Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:23
erlang
6091-asn1-Support-SEQUENCE-OF-with-16384-or-mor...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 6091-asn1-Support-SEQUENCE-OF-with-16384-or-more-items.patch of Package erlang
From 8b0548f1f31704651145d9847e8b4df591d65a9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org> Date: Mon, 12 Sep 2022 05:50:38 +0200 Subject: [PATCH] asn1: Support SEQUENCE OF with 16384 or more items Implement support for the `per` and `uper` ASN.1 encoding to handle encoding and decoding of SEQUENCE OF/SET OF with 16384 or more items. --- lib/asn1/src/asn1ct_constructed_per.erl | 87 +++++++++++++----- lib/asn1/src/asn1ct_imm.erl | 91 +++++++++++++++---- lib/asn1/src/asn1rtt_per.erl | 30 +++++- lib/asn1/src/asn1rtt_uper.erl | 29 ++++++ lib/asn1/test/asn1_SUITE_data/Fragmented.asn1 | 9 ++ lib/asn1/test/testFragmented.erl | 30 ++++++ 6 files changed, 232 insertions(+), 44 deletions(-) diff --git a/lib/asn1/src/asn1ct_constructed_per.erl b/lib/asn1/src/asn1ct_constructed_per.erl index aff383479b..ec5894b458 100644 --- a/lib/asn1/src/asn1ct_constructed_per.erl +++ b/lib/asn1/src/asn1ct_constructed_per.erl @@ -730,23 +730,55 @@ gen_decode_sof(Erules, Typename, SeqOrSetOf, #type{}=D) -> do_gen_decode_sof(Erules, Typename, SeqOrSetOf, D), emit([".",nl,nl]). -do_gen_decode_sof(Erules, Typename, SeqOrSetOf, D) -> +do_gen_decode_sof(Erules, TypeName, SeqOrSetOf, D) -> + case asn1ct_imm:effective_constraint(bitstring, D#type.constraint) of + no -> + %% Could be fragmented. + do_gen_decode_fragmented(Erules, TypeName, SeqOrSetOf, D); + SizeConstraint -> + do_gen_decode_sof_plain(Erules, TypeName, SeqOrSetOf, D, SizeConstraint) + end. + +do_gen_decode_fragmented(Erules, TypeName, SeqOrSetOf, D) -> {_SeqOrSetOf,ComponentType} = D#type.def, - SizeConstraint = asn1ct_imm:effective_constraint(bitstring, - D#type.constraint), - ObjFun = - case D#type.tablecinf of - [{objfun,_}|_R] -> - ", ObjFun"; - _ -> - "" - end, + ObjFun = obj_fun_arg(D), + Key = erlang:md5(term_to_binary({fragmented,TypeName,SeqOrSetOf,ComponentType})), + Gen = fun(_Fd, Name) -> + do_gen_dec_fragmented_1(Erules, Name, TypeName, + SeqOrSetOf, ComponentType, D) + end, + F = asn1ct_func:call_gen("dec_components", Key, Gen), + emit([{asis,F}, "(Bytes", ObjFun,", [])"]). + +do_gen_dec_fragmented_1(Erules, Name, TypeName, SeqOrSetOf, ComponentType, D) -> + ObjFun = obj_fun_arg(D), + emit([{asis,Name}, "(Bytes", ObjFun, ", Acc) ->", nl]), + {Num,Buf} = gen_decode_length(no, Erules), + Key = erlang:md5(term_to_binary({TypeName,SeqOrSetOf,ComponentType})), + Gen = fun(_Fd, Name2) -> + gen_decode_sof_components(Erules, Name2, + TypeName, SeqOrSetOf, + ComponentType, false) + end, + F = asn1ct_func:call_gen("dec_fragment", Key, Gen), + emit([",",nl, + "{Acc1,Buf1} = ", + {asis,F}, "(", Num, ", ", Buf, ObjFun, ", Acc),",nl]), + emit(["if ",Num," >= 16384 ->",nl, + {asis,Name},"(Buf1", ObjFun, ", Acc1);",nl, + "true ->",nl, + "{lists:reverse(Acc1),Buf1}",nl, + "end.",nl]). + +do_gen_decode_sof_plain(Erules, TypeName, SeqOrSetOf, D, SizeConstraint) -> + {_SeqOrSetOf,ComponentType} = D#type.def, + ObjFun = obj_fun_arg(D), {Num,Buf} = gen_decode_length(SizeConstraint, Erules), - Key = erlang:md5(term_to_binary({Typename,SeqOrSetOf,ComponentType})), + Key = erlang:md5(term_to_binary({TypeName,SeqOrSetOf,ComponentType})), Gen = fun(_Fd, Name) -> gen_decode_sof_components(Erules, Name, - Typename, SeqOrSetOf, - ComponentType) + TypeName, SeqOrSetOf, + ComponentType, true) end, F = asn1ct_func:call_gen("dec_components", Key, Gen), emit([",",nl, @@ -759,16 +791,16 @@ gen_decode_length(Constraint, Erule) -> Imm = asn1ct_imm:per_dec_length(Constraint, true, is_aligned(Erule)), asn1ct_imm:dec_slim_cg(Imm, "Bytes"). -gen_decode_sof_components(Erule, Name, Typename, SeqOrSetOf, Cont) -> - {ObjFun,ObjFun_Var} = - case Cont#type.tablecinf of - [{objfun,_}|_R] -> - {", ObjFun",", _"}; - _ -> - {"",""} - end, - emit([{asis,Name},"(0, Bytes",ObjFun_Var,", Acc) ->",nl, - "{lists:reverse(Acc),Bytes};",nl]), +gen_decode_sof_components(Erule, Name, Typename, SeqOrSetOf, Cont, Reverse) -> + ObjFun = obj_fun_arg(Cont), + ObjFunPat = obj_fun_pat(Cont), + emit([{asis,Name},"(0, Bytes",ObjFunPat,", Acc) ->",nl]), + case Reverse of + true -> + emit(["{lists:reverse(Acc),Bytes};",nl]); + false -> + emit(["{Acc,Bytes};",nl]) + end, emit([{asis,Name},"(Num, Bytes",ObjFun,", Acc) ->",nl, "{Term,Remain} = "]), Constructed_Suffix = asn1ct_gen:constructed_suffix(SeqOrSetOf, @@ -794,6 +826,15 @@ gen_decode_sof_components(Erule, Name, Typename, SeqOrSetOf, Cont) -> end, emit([{asis,Name},"(Num-1, Remain",ObjFun,", [Term|Acc]).",nl]). +obj_fun_arg(#type{tablecinf=[{objfun,_}|_]}) -> + ", ObjFun"; +obj_fun_arg(#type{}) -> + "". + +obj_fun_pat(#type{tablecinf=[{objfun,_}|_]}) -> + ", _"; +obj_fun_pat(#type{}) -> + "". %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% General and special help functions (not exported) diff --git a/lib/asn1/src/asn1ct_imm.erl b/lib/asn1/src/asn1ct_imm.erl index 231048694a..e70a91ed9e 100644 --- a/lib/asn1/src/asn1ct_imm.erl +++ b/lib/asn1/src/asn1ct_imm.erl @@ -381,22 +381,44 @@ per_enc_optional(Val, {call,M,F,A}) -> [[{eq,Tmp,true},Zero],['_',One]]}]. per_enc_sof(Val0, Constraint, ElementVar, ElementImm, Aligned) -> - {B,[Val,Len]} = mk_vars(Val0, [len]), - SzConstraint = effective_constraint(bitstring, Constraint), - LenImm = enc_length(Len, SzConstraint, Aligned), - Lc0 = [{lc,ElementImm,{var,atom_to_list(ElementVar)},Val}], - Lc = opt_lc(Lc0, LenImm), - PreBlock = B ++ [{call,erlang,length,[Val],Len}], - case LenImm of - [{'cond',[[C|Action]]}] -> - PreBlock ++ [{'cond',[[C|Action++Lc]]}]; - [{sub,_,_,_}=Sub,{'cond',[[C|Action]]}] -> - PreBlock ++ - [Sub,{'cond',[[C|Action++Lc]]}]; - EncLen -> - PreBlock ++ EncLen ++ Lc + case effective_constraint(bitstring, Constraint) of + no -> + per_enc_sof_fragmented(Val0, ElementVar, ElementImm, Aligned); + SzConstraint -> + {B,[Val,Len]} = mk_vars(Val0, [len]), + LenImm = enc_sof_length(Len, SzConstraint, Aligned), + Lc0 = [{lc,ElementImm,{var,atom_to_list(ElementVar)},Val}], + Lc = opt_lc(Lc0, LenImm), + PreBlock = B ++ [{call,erlang,length,[Val],Len}], + case LenImm of + [{'cond',[[C|Action]]}] -> + PreBlock ++ [{'cond',[[C|Action++Lc]]}]; + [{sub,_,_,_}=Sub,{'cond',[[C|Action]]}] -> + PreBlock ++ + [Sub,{'cond',[[C|Action++Lc]]}]; + EncLen -> + PreBlock ++ EncLen ++ Lc + end end. +per_enc_sof_fragmented(Val0, ElementVar, ElementImm, Aligned) -> + {B,[Val,Len,Fun]} = mk_vars(Val0, [len,fn]), + Lc = [{lc,ElementImm,{var,atom_to_list(ElementVar)},Val}], + PreBlock = B ++ [{call,erlang,length,[Val],Len}], + U = unit(1, Aligned), + EncFragmented = + [{'fun', + [{var,atom_to_list(ElementVar)}], + ElementImm, + Fun}, + {call,enc_mod(Aligned),encode_fragmented_sof,[Fun,Val,Len]}], + CondImm = build_cond([[{lt,Len,128}, + {put_bits,Len,8,U}|Lc], + [{lt,Len,16384}, + {put_bits,2,2,U},{put_bits,Len,14,[1]}|Lc], + ['_'|EncFragmented]]), + PreBlock ++ CondImm. + enc_absent(Val0, {call,M,F,A}, Body) -> {B,[Var,Tmp]} = mk_vars(Val0, [tmp]), B++[{call,M,F,[Var|A],Tmp}, @@ -586,7 +608,10 @@ decode_unconstrained_length(AllowZero, Aligned) -> {value,{get_bits,7,[1|Zero]}}}, {test,{get_bits,1,[1|Al]},1, {test,{get_bits,1,[1]},0, - {value,{get_bits,14,[1|Zero]}}}}]}. + {value,{get_bits,14,[1|Zero]}}}}, + {test,{get_bits,1,[1|Al]},1, + {test,{get_bits,1,[1]},1, + {value,{mul,{get_bits,6,[1|Zero]},16384}}}}]}. uper_num_bits(N) -> uper_num_bits(N, 1, 0). @@ -751,6 +776,9 @@ opt_al({value,E0}, A0) -> opt_al({add,E0,I}, A0) when is_integer(I) -> {E,A} = opt_al(E0, A0), {{add,E,I},A}; +opt_al({mul,E0,I}, A0) when is_integer(I) -> + {E,A} = opt_al(E0, A0), + {{mul,E,I},A}; opt_al({test,E0,V,B0}, A0) -> {E,A1} = opt_al(E0, A0), {B,A2} = opt_al(B0, A1), @@ -838,6 +866,10 @@ flatten({add,E0,I}, Buf0, St0) -> {{Src,Buf},Pre,St1} = flatten(E0, Buf0, St0), {Dst,St} = new_var("Add", St1), {{Dst,Buf},Pre++[{add,Src,I,Dst}],St}; +flatten({mul,E0,I}, Buf0, St0) -> + {{Src,Buf},Pre,St1} = flatten(E0, Buf0, St0), + {Dst,St} = new_var("Mul", St1), + {{Dst,Buf},Pre++[{mul,Src,I,Dst}],St}; flatten({'case',Cs0}, Buf0, St0) -> {Dst,St1} = new_var_pair(St0), {Cs1,St} = flatten_cs(Cs0, Buf0, St1), @@ -951,6 +983,9 @@ dcg_list_outside([{'map',Val,Cs,Dst}|T]) -> dcg_list_outside([{add,S1,S2,Dst}|T]) -> emit([Dst," = ",S1," + ",S2]), iter_dcg_list_outside(T); +dcg_list_outside([{mul,S1,S2,Dst}|T]) -> + emit([Dst," = ",S1," * ",S2]), + iter_dcg_list_outside(T); dcg_list_outside([{return,{V,Buf}}|T]) -> emit(["{",V,",",Buf,"}"]), iter_dcg_list_outside(T); @@ -1055,6 +1090,7 @@ split_off_nonbuilding(Imm) -> is_nonbuilding({assign,_,_}) -> true; is_nonbuilding({call,_,_,_,_}) -> true; is_nonbuilding({comment,_}) -> true; +is_nonbuilding({'fun',_,_,_}) -> true; is_nonbuilding({lc,_,_,_,_}) -> true; is_nonbuilding({set,_,_}) -> true; is_nonbuilding({list,_,_}) -> true; @@ -1239,23 +1275,23 @@ per_enc_length(Bin, Unit0, Len, Sv, Aligned, Type) when is_integer(Sv) -> Pb = {put_bits,Bin,binary,U}, [{'cond',[[{eq,Len,Sv},Pb]]}]. -enc_length(Len, no, Aligned) -> +enc_sof_length(Len, no, Aligned) -> U = unit(1, Aligned), build_cond([[{lt,Len,128}, {put_bits,Len,8,U}], [{lt,Len,16384}, {put_bits,2,2,U},{put_bits,Len,14,[1]}]]); -enc_length(Len, {{Lb,Ub},[]}, Aligned) -> +enc_sof_length(Len, {{Lb,Ub},[]}, Aligned) -> {Prefix,Check,PutLen} = per_enc_constrained(Len, Lb, Ub, Aligned), NoExt = {put_bits,0,1,[1]}, - [{'cond',ExtConds0}] = enc_length(Len, no, Aligned), + [{'cond',ExtConds0}] = enc_sof_length(Len, no, Aligned), Ext = {put_bits,1,1,[1]}, ExtConds = prepend_to_cond(ExtConds0, Ext), build_length_cond(Prefix, [[Check,NoExt|PutLen]|ExtConds]); -enc_length(Len, {Lb,Ub}, Aligned) when is_integer(Lb) -> +enc_sof_length(Len, {Lb,Ub}, Aligned) when is_integer(Lb) -> {Prefix,Check,PutLen} = per_enc_constrained(Len, Lb, Ub, Aligned), build_length_cond(Prefix, [[Check|PutLen]]); -enc_length(Len, Sv, _Aligned) when is_integer(Sv) -> +enc_sof_length(Len, Sv, _Aligned) when is_integer(Sv) -> [{'cond',[[{eq,Len,Sv}]]}]. extensions_bitmap(Vs, Undefined) -> @@ -1730,6 +1766,9 @@ enc_make_cons({integer,Int}, {cons,{binary,H},T}) -> enc_make_cons(H, T) -> {cons,H,T}. +enc_pre_cg_nonbuilding({'fun',Args,B0,Dst}, StL) -> + B = enc_pre_cg_1(B0, StL, outside_seq), + {'fun',Args,B,Dst}; enc_pre_cg_nonbuilding({lc,B0,Var,List,Dst}, StL) -> B = enc_pre_cg_1(B0, StL, outside_seq), {lc,B,Var,List,Dst}; @@ -1943,6 +1982,9 @@ enc_opt({cons,H0,T0}, St0) -> {{cons,H,T},St#ost{t=t_cons(TypeH, TypeT)}}; enc_opt({error,_}=Imm, St) -> {Imm,St#ost{t=t_any()}}; +enc_opt({'fun',_,_,Dst}=Imm, St0) -> + St = set_type(Dst, t_any(), St0), + {Imm,St}; enc_opt({integer,V}, St) -> {{integer,subst(V, St)},St#ost{t=t_integer()}}; enc_opt({lc,E0,B,C}, St) -> @@ -2365,6 +2407,13 @@ enc_cg({error,Error}) when is_function(Error, 0) -> enc_cg({error,{Tag,Var0}}) -> Var = mk_val(Var0), emit(["exit({error,{asn1,{",Tag,",",Var,"}}})"]); +enc_cg({'fun',Args,Body,Dst0}) -> + Dst = mk_val(Dst0), + emit([Dst," = fun("]), + _ = [emit(mk_val(A)) || A <- Args], + emit(") -> "), + enc_cg(Body), + emit(" end"); enc_cg({integer,Int}) -> emit(mk_val(Int)); enc_cg({lc,Body,Var,List}) -> @@ -2738,6 +2787,8 @@ per_fixup([{call_gen,_,_,_,_,_}=H|T]) -> [H|per_fixup(T)]; per_fixup([{error,_}=H|T]) -> [H|per_fixup(T)]; +per_fixup([{'fun',Args,Body,Dst}|T]) -> + [{'fun',Args,per_fixup(Body),Dst}|per_fixup(T)]; per_fixup([{lc,B,V,L}|T]) -> [{lc,per_fixup(B),V,L}|per_fixup(T)]; per_fixup([{lc,B,V,L,Dst}|T]) -> diff --git a/lib/asn1/src/asn1rtt_per.erl b/lib/asn1/src/asn1rtt_per.erl index 753a38aa6e..70b1880693 100644 --- a/lib/asn1/src/asn1rtt_per.erl +++ b/lib/asn1/src/asn1rtt_per.erl @@ -19,7 +19,7 @@ %% -module(asn1rtt_per). --export([skipextensions/3,complete/1]). +-export([skipextensions/3,complete/1,encode_fragmented_sof/3]). skipextensions(Bytes0, Nr, ExtensionBitstr) when is_bitstring(ExtensionBitstr) -> Prev = Nr - 1, @@ -119,3 +119,31 @@ complete(Bin, Bits, More) when is_binary(Bin) -> [Bin|complete([], Bits, More)]; complete(Bin, Bits, More) -> [Bin|complete([], Bits+bit_size(Bin), More)]. + +-define('16K',16384). + +encode_fragmented_sof(Fun, Comps, Len) -> + encode_fragmented_sof_1(Fun, Comps, Len, 4). + +encode_fragmented_sof_1(Encoder, Comps0, Len0, N) -> + SegSz = N * ?'16K', + if + Len0 >= SegSz -> + {Comps,B} = encode_components(Comps0, Encoder, SegSz, []), + Len = Len0 - SegSz, + [align,<<3:2,N:6>>,B|encode_fragmented_sof_1(Encoder, Comps, Len, N)]; + N > 1 -> + encode_fragmented_sof_1(Encoder, Comps0, Len0, N - 1); + Len0 < 128 -> + {[],B} = encode_components(Comps0, Encoder, Len0, []), + [align,Len0|B]; + Len0 < ?'16K' -> + {[],B} = encode_components(Comps0, Encoder, Len0, []), + [align,<<2:2,Len0:14>>|B] + end. + +encode_components(Cs, _Encoder, 0, Acc) -> + {Cs,lists:reverse(Acc)}; +encode_components([C|Cs], Encoder, Size, Acc) -> + B = Encoder(C), + encode_components(Cs, Encoder, Size - 1, [B|Acc]). diff --git a/lib/asn1/src/asn1rtt_uper.erl b/lib/asn1/src/asn1rtt_uper.erl index 0ab8fab141..f51cb979b7 100644 --- a/lib/asn1/src/asn1rtt_uper.erl +++ b/lib/asn1/src/asn1rtt_uper.erl @@ -22,6 +22,7 @@ -export([skipextensions/3]). -export([complete/1, complete_NFP/1]). +-export([encode_fragmented_sof/3]). skipextensions(Bytes0, Nr, ExtensionBitstr) when is_bitstring(ExtensionBitstr) -> Prev = Nr - 1, @@ -75,3 +76,31 @@ complete_NFP(InList) when is_list(InList) -> list_to_bitstring(InList); complete_NFP(InList) when is_bitstring(InList) -> InList. + +-define('16K',16384). + +encode_fragmented_sof(Fun, Comps, Len) -> + encode_fragmented_sof_1(Fun, Comps, Len, 4). + +encode_fragmented_sof_1(Encoder, Comps0, Len0, N) -> + SegSz = N * ?'16K', + if + Len0 >= SegSz -> + {Comps,B} = encode_components(Comps0, Encoder, SegSz, []), + Len = Len0 - SegSz, + [<<3:2,N:6>>,B|encode_fragmented_sof_1(Encoder, Comps, Len, N)]; + N > 1 -> + encode_fragmented_sof_1(Encoder, Comps0, Len0, N - 1); + Len0 < 128 -> + {[],B} = encode_components(Comps0, Encoder, Len0, []), + [Len0|B]; + Len0 < ?'16K' -> + {[],B} = encode_components(Comps0, Encoder, Len0, []), + [<<2:2,Len0:14>>|B] + end. + +encode_components(Cs, _Encoder, 0, Acc) -> + {Cs,lists:reverse(Acc)}; +encode_components([C|Cs], Encoder, Size, Acc) -> + B = Encoder(C), + encode_components(Cs, Encoder, Size - 1, [B|Acc]). diff --git a/lib/asn1/test/asn1_SUITE_data/Fragmented.asn1 b/lib/asn1/test/asn1_SUITE_data/Fragmented.asn1 index bfc939737f..e784feff8c 100644 --- a/lib/asn1/test/asn1_SUITE_data/Fragmented.asn1 +++ b/lib/asn1/test/asn1_SUITE_data/Fragmented.asn1 @@ -21,4 +21,13 @@ PDU ::= SEQUENCE { arg FUNCTION.&ArgumentType ({ObjSet}{@code}) } +IntBoolSeqs ::= SEQUENCE (SIZE (1..65536)) OF IntBoolSeq + +IntBoolSeqsU ::= SEQUENCE OF IntBoolSeq + +IntBoolSeq ::= SEQUENCE { + a INTEGER, + b BOOLEAN +} + END diff --git a/lib/asn1/test/testFragmented.erl b/lib/asn1/test/testFragmented.erl index bd63bd83fc..fe23b13d3a 100644 --- a/lib/asn1/test/testFragmented.erl +++ b/lib/asn1/test/testFragmented.erl @@ -36,7 +36,37 @@ main(_Erule) -> K8,K8,K8,K8,K8,K8]}), roundtrip('PDU', {'PDU',1,false,[K8,K8,K8,K8,K8,K8,K8,K8, K8,K8,K8,K8,K8,K8,K8,K8]}), + + K16 = 16384, + K64 = 4 * K16, + K144 = 2 * K64 + K16, + roundtrips([1, 2, 3, 17, + K16-1, K16, K16+1, + 2*K16-1, 2*K16, 2*K16+1, + 3*K16-1, 3*K16, 3*K16+1, + K64-1, K64, K64+1, + K64+K16, + K144-1, K144, K144+1]), + ok. + +roundtrips([Size|Sizes]) -> + L = make_seq(Size, []), + io:format("~p: ~P\n", [Size,L,6]), + roundtrip('IntBoolSeqsU', L), + if + Size =< 65536 -> + roundtrip('IntBoolSeqs', L); + true -> + ok + end, + roundtrips(Sizes); +roundtrips([]) -> ok. roundtrip(T, V) -> asn1_test_lib:roundtrip('Fragmented', T, V). + +make_seq(0, Acc) -> + Acc; +make_seq(N, Acc) -> + make_seq(N - 1, [{'IntBoolSeq',N,N rem 7 =:= 0}|Acc]). -- 2.35.3
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor