diff options
-rw-r--r-- | lib/asn1/src/asn1ct_constructed_per.erl | 160 | ||||
-rw-r--r-- | lib/asn1/src/asn1ct_imm.erl | 1 | ||||
-rw-r--r-- | lib/asn1/src/asn1rtt_per.erl | 100 | ||||
-rw-r--r-- | lib/asn1/src/asn1rtt_uper.erl | 46 | ||||
-rw-r--r-- | lib/asn1/test/asn1_SUITE_data/ChoExtension.asn1 | 6 | ||||
-rw-r--r-- | lib/asn1/test/testChoExtension.erl | 5 |
6 files changed, 130 insertions, 188 deletions
diff --git a/lib/asn1/src/asn1ct_constructed_per.erl b/lib/asn1/src/asn1ct_constructed_per.erl index 7fc904ec16..c3067e53be 100644 --- a/lib/asn1/src/asn1ct_constructed_per.erl +++ b/lib/asn1/src/asn1ct_constructed_per.erl @@ -1322,8 +1322,7 @@ gen_dec_component_no_val({ext,_,_},mandatory) -> emit({"asn1_NOVALUE"}). -gen_dec_choice_line(Erule, TopType, Comp, Pos, Ext) -> - Pre = gen_dec_line_open_type(Erule, Ext, Pos), +gen_dec_choice_line(Erule, TopType, Comp, Pre) -> Imm0 = gen_dec_line_imm(Erule, TopType, Comp, false, Pre), Init = {ignore,fun(_) -> {[],[]} end}, Imm = [{group,[Init|Imm0]}], @@ -1638,62 +1637,135 @@ gen_enc_choice2(Erule, TopType, [H|T], Pos, Sep0, Ext) -> gen_enc_choice2(Erule, TopType, T, Pos+1, Sep, Ext); gen_enc_choice2(_, _, [], _, _, _) -> ok. -gen_dec_choice(Erule,TopType,CompList,{ext,Pos,NumExt}) -> - emit(["{Ext,",{curr,bytes},"} = ", - {call,Erule,getbit,["Bytes"]},com,nl]), +%% Generate the code for CHOICE. If the CHOICE is extensible, +%% the structure of the generated code is as follows: +%% +%% case Bytes of +%% <<0:1,Bytes1/bitstring>> -> +%% Choice = <Decode INTEGER (0..LastRootChoice) from Bytes1> +%% case Choice of +%% 0 -> <Decode>; +%% : +%% LastRootChoice -> <Decode> +%% end; +%% <<1:1,Bytes1/bitstring>> -> +%% Choice = <Decode normally small number from Bytes1> +%% TmpVal = <Decode open type> +%% case Choice of +%% 0 -> <Decode TmpVal>; +%% : +%% LastExtension -> <Decode TmpVal>; +%% _ -> <Return TmpVal since the type is unknown> +%% end +%% end +%% +%% The return value from the generated function always looks like: +%% {{ChoiceTag,Value},RemainingBuffer} +%% where ChoiceTag will be 'asn1_ExtAlt' for an unknown extension. +%% +%% If the CHOICE is not extensible, the top-level case is omitted +%% and only the code in the first case arm is generated. + +gen_dec_choice(Erule, TopType, CompList, {ext,_,_}=Ext) -> + {RootList,ExtList} = split_complist(CompList), + emit(["case Bytes of",nl]), + case RootList of + [] -> + ok; + [_|_] -> + emit(["<<0:1,Bytes1/bitstring>> ->",nl]), + asn1ct_name:new(bytes), + gen_dec_choice1(Erule, TopType, RootList, noext), + emit([";",nl,nl]) + end, + emit(["<<1:1,Bytes1/bitstring>> ->",nl]), + asn1ct_name:clear(), + asn1ct_name:new(bytes), asn1ct_name:new(bytes), - gen_dec_choice1(Erule,TopType,CompList,{ext,Pos,NumExt}); -gen_dec_choice(Erule,TopType,CompList,noext) -> - gen_dec_choice1(Erule,TopType,CompList,noext). - -gen_dec_choice1(Erule,TopType,CompList,noext) -> - emit(["{Choice,",{curr,bytes}, - "} = ",{call,Erule,getchoice, - [{prev,bytes},length(CompList),"0"]},com,nl, - "{Cname,{Val,NewBytes}} = case Choice of",nl]), - gen_dec_choice2(Erule,TopType,CompList,noext), - emit({nl,"end,",nl}), - emit({nl,"{{Cname,Val},NewBytes}"}); -gen_dec_choice1(Erule,TopType,{RootList,ExtList},Ext) -> - NewList = RootList ++ ExtList, - gen_dec_choice1(Erule,TopType, NewList, Ext); -gen_dec_choice1(Erule,TopType,{RootList,ExtList,RootList2},Ext) -> - NewList = RootList ++ RootList2 ++ ExtList, - gen_dec_choice1(Erule,TopType, NewList, Ext); -gen_dec_choice1(Erule,TopType,CompList,{ext,ExtPos,ExtNum}) -> - emit(["{Choice,",{curr,bytes},"} = ", - {call,Erule,getchoice, - [{prev,bytes},length(CompList)-ExtNum,"Ext"]},com,nl]), - emit({"{Cname,{Val,NewBytes}} = case Choice + Ext*",ExtPos-1," of",nl}), - gen_dec_choice2(Erule,TopType,CompList,{ext,ExtPos,ExtNum}), + gen_dec_choice1(Erule, TopType, ExtList, Ext), + emit([nl,"end"]); +gen_dec_choice(Erule, TopType, CompList, noext) -> + gen_dec_choice1(Erule, TopType, CompList, noext). + +split_complist({Root1,Ext,Root2}) -> + {Root1++Root2,Ext}; +split_complist({_,_}=CompList) -> + CompList. + +gen_dec_choice1(Erule, TopType, CompList, noext=Ext) -> + emit_getchoice(Erule, CompList, Ext), + emit(["case Choice of",nl]), + Pre = {safe,fun(St) -> + {asn1ct_gen:mk_var(asn1ct_name:curr(bytes)), + fun() -> St end} + end}, + gen_dec_choice2(Erule, TopType, CompList, Pre), + emit([nl,"end"]); +gen_dec_choice1(Erule, TopType, CompList, {ext,_,_}=Ext) -> + emit_getchoice(Erule, CompList, Ext), Imm = asn1ct_imm:per_dec_open_type(is_aligned(Erule)), + emit(["begin",nl]), BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)), - emit([";",nl, - "_ ->",nl]), - {TmpTerm,TmpBuf} = asn1ct_imm:dec_slim_cg(Imm, BytesVar), - emit([com,nl, - "{asn1_ExtAlt,{",TmpTerm,com,TmpBuf,"}}",nl, - "end,",nl,nl, - "{{Cname,Val},NewBytes}"]). - + {Dst,DstBuf} = asn1ct_imm:dec_slim_cg(Imm, BytesVar), + emit([nl, + "end,",nl, + "case Choice of",nl]), + Pre = {safe,fun(St) -> + emit(["{TmpVal,_} = "]), + {Dst, + fun() -> + emit([",",nl, + "{TmpVal,",DstBuf,"}"]), + St + end} + end}, + gen_dec_choice2(Erule, TopType, CompList, Pre), + case CompList of + [] -> ok; + [_|_] -> emit([";",nl]) + end, + emit(["_ ->",nl, + "{{asn1_ExtAlt,",Dst,"},",DstBuf,"}",nl, + "end"]). + +emit_getchoice(Erule, CompList, Ext) -> + Al = is_aligned(Erule), + Imm = case {Ext,CompList} of + {noext,[_]} -> + {value,0}; + {noext,_} -> + asn1ct_imm:per_dec_constrained(0, length(CompList)-1, Al); + {{ext,_,_},_} -> + asn1ct_imm:per_dec_normally_small_number(Al) + end, + emit(["{Choice,",{curr,bytes},"} = ",nl]), + BytesVar = asn1ct_gen:mk_var(asn1ct_name:prev(bytes)), + asn1ct_imm:dec_code_gen(Imm, BytesVar), + emit([com,nl]). gen_dec_choice2(Erule,TopType,L,Ext) -> gen_dec_choice2(Erule, TopType, L, 0, [], Ext). -gen_dec_choice2(Erule, TopType, [H0|T], Pos, Sep0, Ext) -> +gen_dec_choice2(Erule, TopType, [H0|T], Pos, Sep0, Pre) -> #'ComponentType'{name=Cname,typespec=Type} = H0, H = H0#'ComponentType'{prop=mandatory}, + emit([Sep0,Pos," ->",nl]), case Type#type.def of #'ObjectClassFieldType'{type={typefield,_}} -> - emit([Sep0,Pos," ->",nl]), - gen_dec_choice_line(Erule, TopType, H, Pos+1, Ext); + emit("{Cname,{Val,NewBytes}} = begin\n"), + gen_dec_choice_line(Erule, TopType, H, Pre), + emit([nl, + "end,",nl, + "{{Cname,Val},NewBytes}"]); _ -> - emit([Sep0,Pos," -> {",{asis,Cname},",",nl]), - gen_dec_choice_line(Erule, TopType, H, Pos+1, Ext), - emit("}") + emit("{Val,NewBytes} = begin\n"), + gen_dec_choice_line(Erule, TopType, H, Pre), + emit([nl, + "end,",nl, + "{{",{asis,Cname},",Val},NewBytes}"]) end, Sep = [";",nl], - gen_dec_choice2(Erule, TopType, T, Pos+1, Sep, Ext); + gen_dec_choice2(Erule, TopType, T, Pos+1, Sep, Pre); gen_dec_choice2(_, _, [], _, _, _) -> ok. indent(N) -> diff --git a/lib/asn1/src/asn1ct_imm.erl b/lib/asn1/src/asn1ct_imm.erl index 4b2c3b1b65..2c5620d5c8 100644 --- a/lib/asn1/src/asn1ct_imm.erl +++ b/lib/asn1/src/asn1ct_imm.erl @@ -25,6 +25,7 @@ per_dec_length/3,per_dec_named_integer/3, per_dec_octet_string/2,per_dec_open_type/1,per_dec_real/1, per_dec_restricted_string/1]). +-export([per_dec_constrained/3,per_dec_normally_small_number/1]). -export([optimize_alignment/1,optimize_alignment/2, dec_slim_cg/2,dec_code_gen/2]). -export([effective_constraint/2]). diff --git a/lib/asn1/src/asn1rtt_per.erl b/lib/asn1/src/asn1rtt_per.erl index aa6cf4da0a..1023be8ce1 100644 --- a/lib/asn1/src/asn1rtt_per.erl +++ b/lib/asn1/src/asn1rtt_per.erl @@ -19,7 +19,7 @@ -module(asn1rtt_per). -export([setext/1, fixextensions/2, - skipextensions/3, getbit/1, getchoice/3, + skipextensions/3, set_choice/3,encode_integer/2, encode_small_number/1, encode_constrained_number/2, @@ -88,23 +88,6 @@ skipextensions(Bytes0, Nr, ExtensionBitstr) when is_bitstring(ExtensionBitstr) - Bytes0 end. - -getchoice(Bytes, 1, 0) -> % only 1 alternative is not encoded - {0,Bytes}; -getchoice(Bytes, _, 1) -> - decode_small_number(Bytes); -getchoice(Bytes, NumChoices, 0) -> - decode_constrained_number(Bytes, {0,NumChoices-1}). - - -getbit(Buffer) -> - <<B:1,Rest/bitstring>> = Buffer, - {B,Rest}. - -getbits(Buffer, Num) when is_bitstring(Buffer) -> - <<Bs:Num,Rest/bitstring>> = Buffer, - {Bs,Rest}. - align(Bin) when is_binary(Bin) -> Bin; align(BitStr) when is_bitstring(BitStr) -> @@ -112,28 +95,6 @@ align(BitStr) when is_bitstring(BitStr) -> <<_:AlignBits,Rest/binary>> = BitStr, Rest. - -%% First align buffer, then pick the first Num octets. -%% Returns octets as an integer with bit significance as in buffer. -getoctets(Buffer, Num) when is_binary(Buffer) -> - <<Val:Num/integer-unit:8,RestBin/binary>> = Buffer, - {Val,RestBin}; -getoctets(Buffer, Num) when is_bitstring(Buffer) -> - AlignBits = bit_size(Buffer) rem 8, - <<_:AlignBits,Val:Num/integer-unit:8,RestBin/binary>> = Buffer, - {Val,RestBin}. - - -%% First align buffer, then pick the first Num octets. -%% Returns octets as a binary -getoctets_as_bin(Bin,Num) when is_binary(Bin) -> - <<Octets:Num/binary,RestBin/binary>> = Bin, - {Octets,RestBin}; -getoctets_as_bin(Bin,Num) when is_bitstring(Bin) -> - AlignBits = bit_size(Bin) rem 8, - <<_:AlignBits,Val:Num/binary,RestBin/binary>> = Bin, - {Val,RestBin}. - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% set_choice(Alt,Choices,Altnum) -> ListofBitSettings %% Alt = atom() @@ -238,15 +199,6 @@ encode_small_number(Val) when Val < 64 -> encode_small_number(Val) -> [1|encode_semi_constrained_number(0, Val)]. -decode_small_number(Bytes) -> - {Bit,Bytes2} = getbit(Bytes), - case Bit of - 0 -> - getbits(Bytes2, 6); - 1 -> - decode_semi_constrained_number(Bytes2) - end. - %% X.691:10.7 Encoding of a semi-constrained whole number encode_semi_constrained_number(Lb, Val) -> Val2 = Val - Lb, @@ -261,10 +213,6 @@ encode_semi_constrained_number(Lb, Val) -> [encode_length(Len),21,<<Len:16>>|Oct] end. -decode_semi_constrained_number(Bytes) -> - {Len,Bytes2} = decode_length(Bytes), - getoctets(Bytes2, Len). - encode_constrained_number({Lb,_Ub},_Range,{bits,N},Val) -> Val2 = Val-Lb, [10,N,Val2]; @@ -333,47 +281,6 @@ encode_constrained_number({Lb,Ub}, Val) when Val >= Lb, Ub >= Val -> encode_constrained_number({_,_},Val) -> exit({error,{asn1,{illegal_value,Val}}}). -decode_constrained_number(Buffer,VR={Lb,Ub}) -> - Range = Ub - Lb + 1, - decode_constrained_number(Buffer,VR,Range). - -decode_constrained_number(Buffer,{Lb,_Ub},Range) -> - % Val2 = Val - Lb, - {Val,Remain} = - if - Range == 1 -> - {0,Buffer}; - Range == 2 -> - getbits(Buffer,1); - Range =< 4 -> - getbits(Buffer,2); - Range =< 8 -> - getbits(Buffer,3); - Range =< 16 -> - getbits(Buffer,4); - Range =< 32 -> - getbits(Buffer,5); - Range =< 64 -> - getbits(Buffer,6); - Range =< 128 -> - getbits(Buffer,7); - Range =< 255 -> - getbits(Buffer,8); - Range =< 256 -> - getoctets(Buffer,1); - Range =< 65536 -> - getoctets(Buffer,2); - Range =< (1 bsl (255*8)) -> - OList = binary:bin_to_list(binary:encode_unsigned(Range - 1)), - RangeOctLen = length(OList), - {Len, Bytes} = decode_length(Buffer, {1, RangeOctLen}), - {Octs, RestBytes} = getoctets_as_bin(Bytes, Len), - {binary:decode_unsigned(Octs), RestBytes}; - true -> - exit({not_supported,{integer_range,Range}}) - end, - {Val+Lb,Remain}. - %% For some reason the minimum bits needed in the length field in %% the encoding of constrained whole numbers must always be at least 2? minimum_bits(N) when N < 4 -> 2; @@ -476,11 +383,6 @@ decode_length(Buffer) -> % un-constrained exit({error,{asn1,{decode_length,{nyi,above_16k}}}}) end. -decode_length(Buffer, {Lb,Ub}) when Ub =< 65535, Lb >= 0 -> % constrained - decode_constrained_number(Buffer, {Lb,Ub}); -decode_length(Buffer, {Lb,_Ub}) when is_integer(Lb), Lb >= 0 -> % Ub > 65535 - decode_length(Buffer). - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% bitstring NamedBitList %% Val can be of: diff --git a/lib/asn1/src/asn1rtt_uper.erl b/lib/asn1/src/asn1rtt_uper.erl index 8efe9a7b0f..e55535860f 100644 --- a/lib/asn1/src/asn1rtt_uper.erl +++ b/lib/asn1/src/asn1rtt_uper.erl @@ -21,7 +21,7 @@ -export([setext/1, fixoptionals/3, fixextensions/2, - skipextensions/3, getbit/1, getchoice/3 ]). + skipextensions/3]). -export([set_choice/3, encode_integer/2, encode_integer/3]). -export([encode_small_number/1, encode_constrained_number/2, encode_boolean/1, @@ -123,29 +123,6 @@ skipextensions(Bytes0, Nr, ExtensionBitstr) when is_bitstring(ExtensionBitstr) - end. -getchoice(Bytes,1,0) -> % only 1 alternative is not encoded - {0,Bytes}; -getchoice(Bytes,_,1) -> - decode_small_number(Bytes); -getchoice(Bytes,NumChoices,0) -> - decode_constrained_number(Bytes,{0,NumChoices-1}). - - -getbit(Buffer) -> - <<B:1,Rest/bitstring>> = Buffer, - {B,Rest}. - -getbits(Buffer, Num) when is_bitstring(Buffer) -> - <<Bs:Num,Rest/bitstring>> = Buffer, - {Bs,Rest}. - - -%% Pick the first Num octets. -%% Returns octets as an integer with bit significance as in buffer. -getoctets(Buffer, Num) when is_bitstring(Buffer) -> - <<Val:Num/integer-unit:8,RestBitStr/bitstring>> = Buffer, - {Val,RestBitStr}. - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% set_choice(Alt,Choices,Altnum) -> ListofBitSettings %% Alt = atom() @@ -265,15 +242,6 @@ encode_small_number(Val) when Val < 64 -> encode_small_number(Val) -> [<<1:1>>|encode_semi_constrained_number(0, Val)]. -decode_small_number(Bytes) -> - {Bit,Bytes2} = getbit(Bytes), - case Bit of - 0 -> - getbits(Bytes2,6); - 1 -> - decode_semi_constrained_number(Bytes2) - end. - %% X.691:10.7 Encoding of a semi-constrained whole number encode_semi_constrained_number(Lb, Val) -> %% encoding in minimum number of octets preceeded by a length @@ -289,11 +257,6 @@ encode_semi_constrained_number(Lb, Val) -> [encode_length(Size),Bin] end. -decode_semi_constrained_number(Bytes) -> - {Len,Bytes2} = decode_length(Bytes), - {V,Bytes3} = getoctets(Bytes2,Len), - {V,Bytes3}. - encode_constrained_number({Lb,Ub}, Val) when Val >= Lb, Ub >= Val -> Range = Ub - Lb + 1, Val2 = Val - Lb, @@ -302,13 +265,6 @@ encode_constrained_number({Lb,Ub}, Val) when Val >= Lb, Ub >= Val -> encode_constrained_number(Range,Val) -> exit({error,{asn1,{integer_range,Range,value,Val}}}). - -decode_constrained_number(Buffer, {Lb,Ub}) -> - Range = Ub - Lb + 1, - NumBits = num_bits(Range), - {Val,Remain} = getbits(Buffer,NumBits), - {Val+Lb,Remain}. - %% X.691:10.8 Encoding of an unconstrained whole number encode_unconstrained_number(Val) when Val >= 0 -> diff --git a/lib/asn1/test/asn1_SUITE_data/ChoExtension.asn1 b/lib/asn1/test/asn1_SUITE_data/ChoExtension.asn1 index 18473bae30..f6fe18be10 100644 --- a/lib/asn1/test/asn1_SUITE_data/ChoExtension.asn1 +++ b/lib/asn1/test/asn1_SUITE_data/ChoExtension.asn1 @@ -41,4 +41,10 @@ ChoExt4 ::= CHOICE str OCTET STRING } +ChoEmptyRoot ::= CHOICE { + ..., + bool BOOLEAN, + int INTEGER (0..7) +} + END diff --git a/lib/asn1/test/testChoExtension.erl b/lib/asn1/test/testChoExtension.erl index 067d4d2bf7..5c67ff62ce 100644 --- a/lib/asn1/test/testChoExtension.erl +++ b/lib/asn1/test/testChoExtension.erl @@ -42,6 +42,11 @@ extension(_Rules) -> roundtrip('ChoExt3', {int,33}), roundtrip('ChoExt4', {str,"abc"}), + roundtrip('ChoEmptyRoot', {bool,false}), + roundtrip('ChoEmptyRoot', {bool,true}), + roundtrip('ChoEmptyRoot', {int,0}), + roundtrip('ChoEmptyRoot', {int,7}), + ok. |