aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2012-12-10 10:56:10 +0100
committerBjörn Gustavsson <[email protected]>2012-12-10 10:56:10 +0100
commit13bf84f59fca26e3fcf644b566db0100b8f01546 (patch)
tree9552867dd790eb5cdcc4f28aa391c21b511f70bc
parentd4b42df28b1d696ce7b2b634be09a7fa5bc0b9cb (diff)
parent5c407a3477e0f35e6e60ff86c664e3de812a8c7a (diff)
downloadotp-13bf84f59fca26e3fcf644b566db0100b8f01546.tar.gz
otp-13bf84f59fca26e3fcf644b566db0100b8f01546.tar.bz2
otp-13bf84f59fca26e3fcf644b566db0100b8f01546.zip
Merge branch 'bjorn/asn1/optimize/OTP-10519'
* bjorn/asn1/optimize/OTP-10519: Remove unused run-time functions Optimize decoding of extensions Do alignment optimization of SEQUENCEs and SETs Refactor code generation for decoding SEQUENCE/SET Teach asn1ct_imm to optimize alignment Optimize decoding of OCTET STRINGs Implement encoding of fragmented OCTET STRINGs Use asn1ct_imm to optimize decoding of per and uper Use asn1ct_imm:effective_constraint/2 Add the asn1ct_imm module Makefile: Add dependencies for header files Eliminate the useless 'telltype' argument in component decoding testPrimString: Increase readability by introducing a roundtrip function asn1_SUITE: Let the per/1 test case also test 'uper' asn1ct_value: Fix type for open type value for uper Optimize encoding/decoding of NULL in the per and uper back-ends Suppress warnings for unused variables using a compiler option
-rw-r--r--lib/asn1/src/Makefile36
-rw-r--r--lib/asn1/src/asn1ct_constructed_per.erl919
-rw-r--r--lib/asn1/src/asn1ct_gen.erl2
-rw-r--r--lib/asn1/src/asn1ct_gen_per.erl193
-rw-r--r--lib/asn1/src/asn1ct_gen_per_rt2ct.erl211
-rw-r--r--lib/asn1/src/asn1ct_imm.erl626
-rw-r--r--lib/asn1/src/asn1ct_value.erl5
-rw-r--r--lib/asn1/src/asn1rt_per_bin_rt2ct.erl307
-rw-r--r--lib/asn1/src/asn1rt_uper_bin.erl270
-rw-r--r--lib/asn1/test/asn1_SUITE.erl2
-rw-r--r--lib/asn1/test/asn1_SUITE_data/PrimStrings.asn113
-rw-r--r--lib/asn1/test/asn1_app_test.erl3
-rw-r--r--lib/asn1/test/testPrimStrings.erl350
13 files changed, 1553 insertions, 1384 deletions
diff --git a/lib/asn1/src/Makefile b/lib/asn1/src/Makefile
index 3d66583745..8d9422144e 100644
--- a/lib/asn1/src/Makefile
+++ b/lib/asn1/src/Makefile
@@ -54,6 +54,7 @@ CT_MODULES= \
asn1ct_constructed_per \
asn1ct_constructed_ber_bin_v2 \
asn1ct_gen_ber_bin_v2 \
+ asn1ct_imm \
asn1ct_value \
asn1ct_tok \
asn1ct_parser2 \
@@ -163,11 +164,32 @@ release_spec: opt
release_docs_spec:
+#
+# Dependencies
+#
-
-
-
-
-
-
-
+$(EBIN)/asn1_app.beam: asn1_app.erl
+$(EBIN)/asn1_db.beam: asn1_db.erl
+$(EBIN)/asn1ct.beam: asn1ct.erl asn1_records.hrl
+$(EBIN)/asn1ct_check.beam: asn1ct_check.erl asn1_records.hrl
+$(EBIN)/asn1ct_constructed_ber_bin_v2.beam: asn1ct_constructed_ber_bin_v2.erl \
+ asn1_records.hrl
+$(EBIN)/asn1ct_constructed_per.beam: asn1ct_constructed_per.erl asn1_records.hrl
+$(EBIN)/asn1ct_gen.beam: asn1ct_gen.erl asn1_records.hrl
+$(EBIN)/asn1ct_gen_ber_bin_v2.beam: asn1ct_gen_ber_bin_v2.erl asn1_records.hrl
+$(EBIN)/asn1ct_gen_per.beam: asn1ct_gen_per.erl asn1_records.hrl
+$(EBIN)/asn1ct_gen_per_rt2ct.beam: asn1ct_gen_per_rt2ct.erl asn1_records.hrl
+$(EBIN)/asn1ct_imm.beam: asn1ct_imm.erl
+$(EBIN)/asn1ct_name.beam: asn1ct_name.erl
+$(EBIN)/asn1ct_parser2.beam: asn1ct_parser2.erl asn1_records.hrl
+$(EBIN)/asn1ct_pretty_format.beam: asn1ct_pretty_format.erl
+$(EBIN)/asn1ct_table.beam: asn1ct_table.erl
+$(EBIN)/asn1ct_tok.beam: asn1ct_tok.erl
+$(EBIN)/asn1ct_value.beam: asn1ct_value.erl asn1_records.hrl
+$(EBIN)/asn1rt.beam: asn1rt.erl
+$(EBIN)/asn1rt_ber_bin.beam: asn1rt_ber_bin.erl asn1_records.hrl
+$(EBIN)/asn1rt_ber_bin_v2.beam: asn1rt_ber_bin_v2.erl
+$(EBIN)/asn1rt_check.beam: asn1rt_check.erl
+$(EBIN)/asn1rt_nif.beam: asn1rt_nif.erl
+$(EBIN)/asn1rt_per_bin_rt2ct.beam: asn1rt_per_bin_rt2ct.erl asn1_records.hrl
+$(EBIN)/asn1rt_uper_bin.beam: asn1rt_uper_bin.erl asn1_records.hrl
diff --git a/lib/asn1/src/asn1ct_constructed_per.erl b/lib/asn1/src/asn1ct_constructed_per.erl
index e4e0e064e8..b29a7b3048 100644
--- a/lib/asn1/src/asn1ct_constructed_per.erl
+++ b/lib/asn1/src/asn1ct_constructed_per.erl
@@ -76,9 +76,7 @@ gen_encode_constructed(Erule,Typename,D) when is_record(D,type) ->
case {Optionals = optionals(to_textual_order(CompList)),CompList,
is_optimized(Erule)} of
{[],EmptyCL,_} when EmptyCL == {[],[],[]};EmptyCL == {[],[]};EmptyCL == [] ->
- emit(["%%Variable setting just to eliminate ",
- "compiler warning for unused vars!",nl,
- "_Val = ",{curr,val},",",nl]);
+ ok;
{[],_,_} ->
emit([{next,val}," = ",{curr,val},",",nl]);
{_,_,true} ->
@@ -219,9 +217,74 @@ gen_decode_set(Erules,Typename,D) ->
gen_decode_sequence(Erules,Typename,D) ->
gen_decode_constructed(Erules,Typename,D).
-gen_decode_constructed(Erules,Typename,D) when is_record(D,type) ->
+gen_decode_constructed(Erule, Typename, #type{}=D) ->
+ Imm0 = gen_dec_constructed_imm(Erule, Typename, #type{}=D),
+ Imm = opt_imm(Imm0),
asn1ct_name:start(),
asn1ct_name:clear(),
+ emit_gen_dec_imm(Imm),
+ emit([".",nl,nl]).
+
+opt_imm(Imm0) ->
+ {Imm,_} = opt_imm_1(Imm0, unknown, []),
+ Imm.
+
+opt_imm_1([{imm,Imm0,F}|T], Al0, Acc) ->
+ {Imm,Al} = asn1ct_imm:optimize_alignment(Imm0, Al0),
+ opt_imm_1(T, Al, [{imm,Imm,F}|Acc]);
+opt_imm_1([ignore|T], Al, Acc) ->
+ opt_imm_1(T, Al, Acc);
+opt_imm_1([{ignore,_}=H|T], Al, Acc) ->
+ opt_imm_1(T, Al, [H|Acc]);
+opt_imm_1([{safe,ignore}|T], Al, Acc) ->
+ opt_imm_1(T, Al, Acc);
+opt_imm_1([{safe,_}=H|T], Al, Acc) ->
+ opt_imm_1(T, Al, [H|Acc]);
+opt_imm_1([{group,G0}|T], Al0, Acc) ->
+ {G,Al} = opt_imm_1(G0, Al0, []),
+ opt_imm_1(T, Al, [{group,G}|Acc]);
+opt_imm_1([Emit|T], _, Acc) when is_function(Emit, 1) ->
+ opt_imm_1(T, unknown, [Emit|Acc]);
+opt_imm_1([], Al, Acc) ->
+ {lists:reverse(Acc),Al}.
+
+emit_gen_dec_imm(L) ->
+ emit_gen_dec_imm(L, "", []).
+
+emit_gen_dec_imm([{ignore,Fun}|T], Sep, St0) ->
+ St = Fun(St0),
+ emit_gen_dec_imm(T, Sep, St);
+emit_gen_dec_imm([{group,L}|T], Sep, St0) ->
+ emit(Sep),
+ St = emit_gen_dec_imm_group(L, St0),
+ emit_gen_dec_imm(T, [com,nl], St);
+emit_gen_dec_imm([{imm,Imm,Emit}|T], Sep, St0) ->
+ emit(Sep),
+ St = Emit(Imm, St0),
+ emit_gen_dec_imm(T, [com,nl], St);
+emit_gen_dec_imm([{safe,Item}|T], Sep, St) ->
+ emit_gen_dec_imm([Item|T], Sep, St);
+emit_gen_dec_imm([Emit|T], Sep, St0) ->
+ emit(Sep),
+ St = Emit(St0),
+ emit_gen_dec_imm(T, [com,nl], St);
+emit_gen_dec_imm([], _, _) -> ok.
+
+emit_gen_dec_imm_group([H|T], St0) ->
+ St = emit_gen_dec_group_item(H, St0),
+ emit_gen_dec_imm_group(T, St);
+emit_gen_dec_imm_group([], St) -> St.
+
+emit_gen_dec_group_item({ignore,Fun}, St) ->
+ Fun(St);
+emit_gen_dec_group_item({imm,Imm,Fun}, St) ->
+ Fun(Imm, St);
+emit_gen_dec_group_item({safe,Item}, St) ->
+ emit_gen_dec_group_item(Item, St);
+emit_gen_dec_group_item(Emit, St) ->
+ Emit(St).
+
+gen_dec_constructed_imm(Erule, Typename, #type{}=D) ->
{CompList,TableConsInfo} =
case D#type.def of
#'SEQUENCE'{tablecinf=TCI,components=CL} ->
@@ -231,27 +294,19 @@ gen_decode_constructed(Erules,Typename,D) when is_record(D,type) ->
{CL,TCI} % the textual order is already taken care of
end,
Ext = extensible_dec(CompList),
- MaybeComma1 = case Ext of
- {ext,_Pos,_NumExt} ->
- gen_dec_extension_value("Bytes"),
- {",",nl};
- _ ->
- ""
- end,
+ EmitExt = case Ext of
+ {ext,_Pos,_NumExt} ->
+ gen_dec_extension_value();
+ _ -> ignore
+ end,
Optionals = optionals(CompList),
- MaybeComma2 = case Optionals of
- [] -> MaybeComma1;
- _ ->
- Bcurr = asn1ct_name:curr(bytes),
- Bnext = asn1ct_name:next(bytes),
- emit(MaybeComma1),
- GetoptCall = "} = ?RT_PER:getoptionals2(",
- emit({"{Opt,",{var,Bnext},GetoptCall,
- {var,Bcurr},",",{asis,length(Optionals)},")"}),
- asn1ct_name:new(bytes),
- ", "
- end,
- {DecObjInf,UniqueFName,ValueIndex} =
+ EmitOpt = case Optionals of
+ [] ->
+ ignore;
+ [_|_] ->
+ gen_dec_optionals(Optionals)
+ end,
+ ObjSetInfo =
case TableConsInfo of
%% {ObjectSet,AttrN,N,UniqueFieldName} ->%% N is index of attribute that determines constraint
#simpletableattributes{objectsetname=ObjectSet,
@@ -283,13 +338,19 @@ gen_decode_constructed(Erules,Typename,D) when is_record(D,type) ->
{false,false,false}
end
end,
-%% NewCompList = wrap_compList(CompList),
- {AccTerm,AccBytes} =
- gen_dec_components_call(Erules,Typename,CompList,MaybeComma2,DecObjInf,Ext,length(Optionals)),
- case asn1ct_name:all(term) of
- [] -> emit(MaybeComma2); % no components at all
- _ -> emit({com,nl})
- end,
+ {DecObjInf,_,_} = ObjSetInfo,
+ EmitComp = gen_dec_components_call(Erule, Typename, CompList,
+ DecObjInf, Ext, length(Optionals)),
+ EmitRest = fun({AccTerm,AccBytes}) ->
+ gen_dec_constructed_imm_2(Typename, CompList,
+ ObjSetInfo,
+ AccTerm, AccBytes)
+ end,
+ [EmitExt,EmitOpt|EmitComp++[{safe,EmitRest}]].
+
+gen_dec_constructed_imm_2(Typename, CompList,
+ ObjSetInfo, AccTerm, AccBytes) ->
+ {_,UniqueFName,ValueIndex} = ObjSetInfo,
case {AccTerm,AccBytes} of
{[],[]} ->
ok;
@@ -331,8 +392,7 @@ gen_decode_constructed(Erules,Typename,D) when is_record(D,type) ->
mkvlist(textual_order(to_encoding_order(CompList),asn1ct_name:all(term))),
emit("},")
end,
- emit({{curr,bytes},"}"}),
- emit({".",nl,nl}).
+ emit({{curr,bytes},"}"}).
textual_order([#'ComponentType'{textual_order=undefined}|_],TermList) ->
TermList;
@@ -514,10 +574,10 @@ gen_decode_sof(Erules,Typename,SeqOrSetOf,D) when is_record(D,type) ->
_ ->
""
end,
- gen_decode_length(SizeConstraint,
- is_optimized(Erules)),
- emit({"'dec_",asn1ct_gen:list2name(Typename),
- "_components'(Num, Bytes1, telltype",ObjFun,", []).",nl}),
+ {Num,Buf} = gen_decode_length(SizeConstraint, Erules),
+ emit([",",nl,
+ "'dec_",asn1ct_gen:list2name(Typename),
+ "_components'(",Num,", ",Buf,ObjFun,", []).",nl,nl]),
NewComponentType =
case ComponentType#type.def of
{'ENUMERATED',_,Component}->
@@ -526,40 +586,13 @@ gen_decode_sof(Erules,Typename,SeqOrSetOf,D) when is_record(D,type) ->
end,
gen_decode_sof_components(Erules,Typename,SeqOrSetOf,NewComponentType).
-%% Logic copied from asn1_per_bin_rt2ct:decode_constrained_number
-gen_decode_length({Lb,Ub},true) when Ub =< 65535, Lb >= 0 ->
- Range = Ub - Lb + 1,
- Call = if
- Range == 1 ->
- "{0,Bytes}";
- Range == 2 ->
- "?RT_PER:getbits(Bytes,1)";
- Range =< 4 ->
- "?RT_PER:getbits(Bytes,2)";
- Range =< 8 ->
- "?RT_PER:getbits(Bytes,3)";
- Range =< 16 ->
- "?RT_PER:getbits(Bytes,4)";
- Range =< 32 ->
- "?RT_PER:getbits(Bytes,5)";
- Range =< 64 ->
- "?RT_PER:getbits(Bytes,6)";
- Range =< 128 ->
- "?RT_PER:getbits(Bytes,7)";
- Range =< 255 ->
- "?RT_PER:getbits(Bytes,8)";
- Range =< 256 ->
- "?RT_PER:getoctets(Bytes,1)";
- Range =< 65536 ->
- "?RT_PER:getoctets(Bytes,2)";
- true ->
- ["exit({not_supported,{integer_range,",Range,"}}"]
- end,
- emit({nl,"{Val,Remain} = ",Call,",",nl}),
- emit({nl,"{Num,Bytes1} = {Val+",Lb,",Remain},",nl});
-gen_decode_length(SizeConstraint,_) ->
- emit({nl,"{Num,Bytes1} = ?RT_PER:decode_length(Bytes,",
- {asis,SizeConstraint},"),",nl}).
+is_aligned(per) -> true;
+is_aligned(uper) -> false.
+
+gen_decode_length(Constraint, Erule) ->
+ emit(["%% Length with constraint ",{asis,Constraint},nl]),
+ Imm = asn1ct_imm:per_dec_length(Constraint, true, is_aligned(Erule)),
+ asn1ct_imm:dec_slim_cg(Imm, "Bytes").
gen_encode_sof_components(Erule,Typename,SeqOrSetOf,Cont) ->
{ObjFun,ObjFun_Var} =
@@ -611,10 +644,10 @@ gen_decode_sof_components(Erule,Typename,SeqOrSetOf,Cont) ->
{"",""}
end,
emit({"'dec_",asn1ct_gen:list2name(Typename),
- "_components'(0, Bytes, _",ObjFun_Var,", Acc) ->",nl,
+ "_components'(0, Bytes",ObjFun_Var,", Acc) ->",nl,
indent(3),"{lists:reverse(Acc), Bytes};",nl}),
emit({"'dec_",asn1ct_gen:list2name(Typename),
- "_components'(Num, Bytes, _",ObjFun,", Acc) ->",nl}),
+ "_components'(Num, Bytes",ObjFun,", Acc) ->",nl}),
emit({indent(3),"{Term,Remain} = "}),
Constructed_Suffix = asn1ct_gen:constructed_suffix(SeqOrSetOf,
Cont#type.def),
@@ -643,7 +676,7 @@ gen_decode_sof_components(Erule,Typename,SeqOrSetOf,Cont) ->
emit({"'dec_",Conttype,"'(Bytes,telltype),",nl})
end,
emit({indent(3),"'dec_",asn1ct_gen:list2name(Typename),
- "_components'(Num-1, Remain, telltype",ObjFun,", [Term|Acc]).",nl}).
+ "_components'(Num-1, Remain",ObjFun,", [Term|Acc]).",nl}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -714,10 +747,25 @@ extgrouppos([_|T],ActualPos,VirtualPos,Len,Acc) ->
extgrouppos(T,ActualPos,VirtualPos,Len+1,Acc).
-
-gen_dec_extension_value(_) ->
- emit({"{Ext,",{next,bytes},"} = ?RT_PER:getext(",{curr,bytes},")"}),
- asn1ct_name:new(bytes).
+gen_dec_extension_value() ->
+ Imm0 = {get_bits,1,[1]},
+ E = fun(Imm, _) ->
+ emit(["{Ext,",{next,bytes},"} = "]),
+ BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
+ asn1ct_imm:dec_code_gen(Imm, BytesVar),
+ asn1ct_name:new(bytes)
+ end,
+ {imm,Imm0,E}.
+
+gen_dec_optionals(Optionals) ->
+ Imm0 = {get_bits,length(Optionals),[1]},
+ E = fun(Imm, _) ->
+ BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
+ emit(["{Opt,",{next,bytes},"} = "]),
+ asn1ct_imm:dec_code_gen(Imm, BytesVar),
+ asn1ct_name:new(bytes)
+ end,
+ {imm,Imm0,E}.
gen_fixoptionals([{Pos,Def}|R]) ->
asn1ct_name:new(fixopt),
@@ -1031,53 +1079,79 @@ gen_enc_line(Erule,TopType,Cname,Type,Element, _Pos,DynamicEnc,Ext) ->
emit("))");
_ -> true
end.
-gen_dec_components_call(Erule,TopType,{Root,ExtList},MaybeComma,
+
+gen_dec_components_call(Erule, TopType, {Root,ExtList},
+ DecInfObj, Ext, NumberOfOptionals) ->
+ gen_dec_components_call(Erule,TopType,{Root,ExtList,[]},
+ DecInfObj,Ext,NumberOfOptionals);
+gen_dec_components_call(Erule,TopType,CL={Root1,ExtList,Root2},
DecInfObj,Ext,NumberOfOptionals) ->
- gen_dec_components_call(Erule,TopType,{Root,ExtList,[]},MaybeComma,DecInfObj,Ext,NumberOfOptionals);
-gen_dec_components_call(Erule,TopType,CL={Root1,ExtList,Root2},MaybeComma,DecInfObj,Ext,NumberOfOptionals) ->
%% The type has extensionmarker
-
OptTable = create_optionality_table(Root1++Root2),
- {Rpos,AccTerm,AccBytes} =
- gen_dec_components_call1(Erule,TopType, Root1++Root2, 1, OptTable,
- MaybeComma,DecInfObj,noext,[],[],
- NumberOfOptionals),
- emit([",",nl,"{Extensions,",{next,bytes},"} = "]),
- emit(["?RT_PER:getextension(Ext,",{curr,bytes},"),",nl]),
- asn1ct_name:new(bytes),
+ Init = {ignore,fun(_) -> {[],[]} end},
+ {EmitRoot,Tpos} =
+ gen_dec_comp_calls(Root1++Root2, Erule, TopType, OptTable,
+ DecInfObj, noext, NumberOfOptionals,
+ 1, []),
+ EmitGetExt = gen_dec_get_extension(Erule),
{extgrouppos,ExtGroupPosLen} = extgroup_pos_and_length(CL),
- NewExtList = wrap_extensionAdditionGroups(ExtList,ExtGroupPosLen),
- {_Epos,AccTermE,AccBytesE} =
- gen_dec_components_call1(Erule,TopType,NewExtList,Rpos, OptTable,
- "",DecInfObj,Ext,[],[],NumberOfOptionals),
- case ExtList of
- [] -> true;
- _ -> emit([",",nl])
- end,
- emit([{next,bytes},"= ?RT_PER:skipextensions(",{curr,bytes},",",
- length(ExtList)+1,",Extensions)",nl]),
- asn1ct_name:new(bytes),
- {AccTerm++AccTermE,AccBytes++AccBytesE};
-
-gen_dec_components_call(Erule,TopType,CompList,MaybeComma,DecInfObj,
- Ext,NumberOfOptionals) ->
+ NewExtList = wrap_extensionAdditionGroups(ExtList, ExtGroupPosLen),
+ {EmitExts,_} = gen_dec_comp_calls(NewExtList, Erule, TopType, OptTable,
+ DecInfObj, Ext, NumberOfOptionals,
+ Tpos, []),
+ Finish =
+ fun(St) ->
+ emit([{next,bytes},"= ?RT_PER:skipextensions(",{curr,bytes},",",
+ length(ExtList)+1,",Extensions)"]),
+ asn1ct_name:new(bytes),
+ St
+ end,
+ [Init] ++ EmitRoot ++ [EmitGetExt|EmitExts] ++ [Finish];
+gen_dec_components_call(Erule, TopType, CompList, DecInfObj,
+ Ext, NumberOfOptionals) ->
%% The type has no extensionmarker
OptTable = create_optionality_table(CompList),
- {_,AccTerm,AccBytes} =
- gen_dec_components_call1(Erule,TopType, CompList, 1, OptTable,
- MaybeComma,DecInfObj,Ext,[],[],
- NumberOfOptionals),
- {AccTerm,AccBytes}.
-
-
-gen_dec_components_call1(Erule,TopType,
- [C=#'ComponentType'{name=Cname,typespec=Type,prop=Prop,textual_order=TextPos}|Rest],
- Tpos,OptTable,MaybeComma,DecInfObj,Ext,AccTerm,AccBytes,NumberOfOptionals) ->
+ Init = {ignore,fun(_) -> {[],[]} end},
+ {Cs,_} = gen_dec_comp_calls(CompList, Erule, TopType, OptTable,
+ DecInfObj, Ext, NumberOfOptionals,
+ 1, []),
+ [Init|Cs].
+
+gen_dec_get_extension(Erule) ->
+ Imm0 = asn1ct_imm:per_dec_extension_map(is_aligned(Erule)),
+ E = fun(Imm, St) ->
+ emit([nl,"%% Extensions",
+ nl,
+ "{Extensions,",{next,bytes},"} = ",
+ "case Ext of",nl,
+ "0 -> {<<>>,",{curr,bytes},"};",nl,
+ "1 ->",nl]),
+ BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
+ {Dst,DstBuf} = asn1ct_imm:dec_slim_cg(Imm, BytesVar),
+ emit([com,nl,
+ "{",Dst,",",DstBuf,"}",nl,
+ "end"]),
+ asn1ct_name:new(bytes),
+ St
+ end,
+ {imm,Imm0,E}.
+
+gen_dec_comp_calls([C|Cs], Erule, TopType, OptTable, DecInfObj,
+ Ext, NumberOfOptionals, Tpos, Acc) ->
+ L = gen_dec_comp_call(C, Erule, TopType, Tpos, OptTable, DecInfObj,
+ Ext, NumberOfOptionals),
+ gen_dec_comp_calls(Cs, Erule, TopType, OptTable, DecInfObj,
+ Ext, NumberOfOptionals, Tpos+1, [L|Acc]);
+gen_dec_comp_calls([], _, _, _, _, _, _, Tpos, Acc) ->
+ {lists:append(lists:reverse(Acc)),Tpos}.
+
+gen_dec_comp_call(Comp, Erule, TopType, Tpos, OptTable, DecInfObj,
+ Ext, NumberOfOptionals) ->
+ #'ComponentType'{typespec=Type,prop=Prop,textual_order=TextPos} = Comp,
Pos = case Ext of
noext -> Tpos;
{ext,Epos,_Enum} -> Tpos - Epos + 1
end,
- emit(MaybeComma),
InnerType =
case Type#type.def of
#'ObjectClassFieldType'{type=InType} ->
@@ -1086,109 +1160,128 @@ gen_dec_components_call1(Erule,TopType,
asn1ct_gen:get_inner(Def)
end,
- case InnerType of
- #'Externaltypereference'{type=T} ->
- emit({nl,"%% attribute number ",TextPos," with type ",
- T,nl});
- IT when is_tuple(IT) ->
- emit({nl,"%% attribute number ",TextPos," with type ",
- element(2,IT),nl});
- _ ->
- emit({nl,"%% attribute number ",TextPos," with type ",
- InnerType,nl})
- end,
-
- IsMandatoryAndPredefinedTableC =
- fun(noext,mandatory,{"got objfun through args","ObjFun"}) ->
- true;
- (_,_,{"got objfun through args","ObjFun"}) ->
- false;
- (_,_,_) ->
- true
- end,
- case {InnerType,IsMandatoryAndPredefinedTableC(Ext,Prop,DecInfObj)} of
-%% {typefield,_} when Ext == noext, Prop == mandatory ->
- {{typefield,_},true} ->
- %% DecInfObj /= {"got objfun through args","ObjFun"} |
- %% (DecInfObj == {"got objfun through args","ObjFun"} &
- %% Ext == noext & Prop == mandatory)
- asn1ct_name:new(term),
- asn1ct_name:new(tmpterm),
- emit({"{",{curr,tmpterm},", ",{next,bytes},"} = "});
+ DispType = case InnerType of
+ #'Externaltypereference'{type=T} -> T;
+ IT when is_tuple(IT) -> element(2,IT);
+ _ -> InnerType
+ end,
+ Comment = fun(St) ->
+ emit([nl,"%% attribute number ",TextPos,
+ " with type ",DispType,nl]),
+ St
+ end,
+
+ Preamble =
+ case {InnerType,is_mandatory_predef_tab_c(Ext, Prop, DecInfObj)} of
+ {{typefield,_},true} ->
+ %% DecInfObj /= {"got objfun through args","ObjFun"} |
+ %% (DecInfObj == {"got objfun through args","ObjFun"} &
+ %% Ext == noext & Prop == mandatory)
+ fun(St) ->
+ asn1ct_name:new(term),
+ asn1ct_name:new(tmpterm),
+ emit(["{",{curr,tmpterm},", ",{next,bytes},"} = "]),
+ St
+ end;
%%{objectfield,_,_} when Ext == noext, Prop == mandatory ->
- {{objectfield,_,_},true} ->
- asn1ct_name:new(term),
- asn1ct_name:new(tmpterm),
- emit({"{",{curr,tmpterm},", ",{next,bytes},"} = "});
+ {{objectfield,_,_},true} ->
+ fun(St) ->
+ asn1ct_name:new(term),
+ asn1ct_name:new(tmpterm),
+ emit(["{",{curr,tmpterm},", ",{next,bytes},"} = "]),
+ St
+ end;
_ ->
case Type of
#type{def=#'SEQUENCE'{
extaddgroup=Number1,
components=ExtGroupCompList1}} when is_integer(Number1)->
- emit({"{{_,"}),
- emit_extaddgroupTerms(term,ExtGroupCompList1),
- emit({"}"});
- _ ->
- asn1ct_name:new(term),
- emit({"{",{curr,term}})
- end,
- emit({",",{next,bytes},"} = "})
- end,
-
- case {Ext,Prop,is_optimized(Erule)} of
- {noext,mandatory,_} -> ok; % generate nothing
- {noext,_,_} -> %% OPTIONAL or DEFAULT
- OptPos = get_optionality_pos(TextPos,OptTable),
- Element = io_lib:format("Opt band (1 bsl ~w)",[NumberOfOptionals - OptPos]),
- emit(["case ",Element," of",nl]),
- emit([" _Opt",TextPos," when _Opt",TextPos," > 0 ->"]);
- {_,_,false} -> %% extension element, not bitstring
- emit(["case Extensions of",nl]),
- emit([" _ when size(Extensions) >= ",Pos,",element(",Pos,",Extensions) == 1 ->",nl]);
- _ ->
- emit(["case Extensions of",nl]),
- emit([" <<_:",Pos-1,",1:1,_/bitstring>> when bit_size(Extensions) >= ",Pos," ->",nl])
- end,
- put(component_type,{true,C}),
- {TermVar,BytesVar} = gen_dec_line(Erule,TopType,Cname,Type,Tpos,DecInfObj,Ext,Prop),
- erase(component_type),
- case {Ext,Prop} of
- {noext,mandatory} -> true; % generate nothing
- {noext,_} ->
- emit([";",nl,"0 ->"]),
- emit(["{"]),
- gen_dec_component_no_val(Ext,Prop),
- emit({",",{curr,bytes},"}",nl}),
- emit([nl,"end"]);
- _ ->
- emit([";",nl,"_ ->",nl]),
- emit(["{"]),
- case Type of
- #type{def=#'SEQUENCE'{
- extaddgroup=Number2,
- components=ExtGroupCompList2}} when is_integer(Number2)->
- emit({"{extAddGroup,"}),
- gen_dec_extaddGroup_no_val(Ext,ExtGroupCompList2),
- emit({"}"});
+ fun(St) ->
+ emit(["{{_,"]),
+ emit_extaddgroupTerms(term,ExtGroupCompList1),
+ emit(["}"]),
+ emit([",",{next,bytes},"} = "]),
+ St
+ end;
_ ->
- gen_dec_component_no_val(Ext,Prop)
- end,
- emit({",",{curr,bytes},"}",nl}),
- emit([nl,"end"])
- end,
- asn1ct_name:new(bytes),
- case Rest of
- [] ->
- {Tpos+1,AccTerm++TermVar,AccBytes++BytesVar};
- _ ->
- emit({com,nl}),
- gen_dec_components_call1(Erule,TopType,Rest,Tpos+1,OptTable,
- "",DecInfObj,Ext, AccTerm++TermVar,
- AccBytes++BytesVar,NumberOfOptionals)
- end;
+ fun(St) ->
+ asn1ct_name:new(term),
+ emit(["{",{curr,term}]),
+ emit([",",{next,bytes},"} = "]),
+ St
+ end
+ end
+ end,
-gen_dec_components_call1(_,_TopType,[],Pos,_OptTable,_,_,_,AccTerm,AccBytes,_NumberOfOptionals) ->
- {Pos,AccTerm,AccBytes}.
+ OptOrDef =
+ case {Ext,Prop} of
+ {noext,mandatory} ->
+ ignore;
+ {noext,_} -> %% OPTIONAL or DEFAULT
+ OptPos = get_optionality_pos(TextPos, OptTable),
+ Element = io_lib:format("Opt band (1 bsl ~w)",
+ [NumberOfOptionals - OptPos]),
+ fun(St) ->
+ emit(["case ",Element," of",nl]),
+ emit([" _Opt",TextPos," when _Opt",TextPos," > 0 ->"]),
+ St
+ end;
+ {{ext,_,_},_} -> %Extension
+ fun(St) ->
+ emit(["case Extensions of",nl,
+ " <<_:",Pos-1,",1:1,_/bitstring>> ->",nl]),
+ St
+ end
+ end,
+ Lines = gen_dec_line_imm(Erule, TopType, Comp, Tpos, DecInfObj, Ext),
+ Postamble =
+ case {Ext,Prop} of
+ {noext,mandatory} ->
+ ignore;
+ {noext,_} ->
+ fun(St) ->
+ emit([";",nl,"0 ->"]),
+ emit(["{"]),
+ gen_dec_component_no_val(Ext,Prop),
+ emit({",",{curr,bytes},"}",nl}),
+ emit([nl,"end"]),
+ St
+ end;
+ _ ->
+ fun(St) ->
+ emit([";",nl,"_ ->",nl]),
+ emit(["{"]),
+ case Type of
+ #type{def=#'SEQUENCE'{
+ extaddgroup=Number2,
+ components=ExtGroupCompList2}}
+ when is_integer(Number2)->
+ emit({"{extAddGroup,"}),
+ gen_dec_extaddGroup_no_val(Ext,ExtGroupCompList2),
+ emit({"}"});
+ _ ->
+ gen_dec_component_no_val(Ext, Prop)
+ end,
+ emit({",",{curr,bytes},"}",nl}),
+ emit([nl,"end"]),
+ St
+ end
+ end,
+ AdvBuffer = {ignore,fun(St) ->
+ asn1ct_name:new(bytes),
+ St
+ end},
+ [{group,[{safe,Comment},{safe,Preamble},
+ {safe,OptOrDef}|Lines]++
+ [{safe,Postamble},{safe,AdvBuffer}]}].
+
+is_mandatory_predef_tab_c(noext, mandatory,
+ {"got objfun through args","ObjFun"}) ->
+ true;
+is_mandatory_predef_tab_c(_, _, {"got objfun through args","ObjFun"}) ->
+ false;
+is_mandatory_predef_tab_c(_,_,_) ->
+ true.
gen_dec_extaddGroup_no_val(Ext,[#'ComponentType'{prop=Prop}])->
gen_dec_component_no_val(Ext,Prop),
@@ -1208,8 +1301,14 @@ gen_dec_component_no_val({ext,_,_},mandatory) ->
emit({"asn1_NOVALUE"}).
-gen_dec_line(Erule,TopType,Cname,Type,Pos,DecInfObj,Ext,Prop) ->
- Ctgenmod = asn1ct_gen:ct_gen_module(Erule),
+gen_dec_line(Erule, TopType, Comp, Pos, DecInfObj, Ext) ->
+ Imm0 = gen_dec_line_imm(Erule, TopType, Comp, Pos, DecInfObj, Ext),
+ Init = {ignore,fun(_) -> {[],[]} end},
+ Imm = [{group,[Init|Imm0]}],
+ emit_gen_dec_imm(Imm).
+
+gen_dec_line_imm(Erule, TopType, Comp, Pos, DecInfObj, Ext) ->
+ #'ComponentType'{name=Cname,typespec=Type} = Comp,
Atype =
case Type of
#type{def=#'ObjectClassFieldType'{type=InnerType}} ->
@@ -1218,175 +1317,235 @@ gen_dec_line(Erule,TopType,Cname,Type,Pos,DecInfObj,Ext,Prop) ->
asn1ct_gen:get_inner(Type#type.def)
end,
- BytesVar0 = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
- BytesVar = case Ext of
- {ext,Ep,_} when Pos >= Ep ->
- emit(["begin",nl,"{TmpVal",Pos,",Trem",Pos,
- "}=?RT_PER:decode_open_type(",
- {curr,bytes},",[]),",nl,
- "{TmpValx",Pos,",_}="]),
- io_lib:format("TmpVal~p",[Pos]);
- _ -> BytesVar0
- end,
- SaveBytes =
- case Atype of
- {typefield,_} ->
+ Pre = gen_dec_line_open_type(Erule, Ext, Pos),
+ Decode = gen_dec_line_special(Erule, Atype, TopType, Comp, DecInfObj, Ext),
+ Post =
+ fun({SaveBytes,Finish}) ->
+ {AccTerm,AccBytes} = Finish(),
+ #'ComponentType'{name=Cname} = Comp,
case DecInfObj of
- false -> % This is in a choice with typefield components
- {Name,RestFieldNames} =
- (Type#type.def)#'ObjectClassFieldType'.fieldname,
-
- asn1ct_name:new(tmpterm),
- asn1ct_name:new(reason),
- emit([indent(2),"{",{curr,tmpterm},", ",{next,bytes},
- "} = ?RT_PER:decode_open_type(",{curr,bytes},
- ", []),",nl]),
- emit([indent(2),"case (catch ObjFun(",
- {asis,Name},",",{curr,tmpterm},",telltype,",
- {asis,RestFieldNames},")) of", nl]),
- emit([indent(4),"{'EXIT',",{curr,reason},"} ->",nl]),
- emit([indent(6),"exit({'Type not ",
- "compatible with table constraint', ",
- {curr,reason},"});",nl]),
- asn1ct_name:new(tmpterm),
- emit([indent(4),"{",{curr,tmpterm},", _} ->",nl]),
- emit([indent(6),"{",{asis,Cname},", {",{curr,tmpterm},", ",
- {next,bytes},"}}",nl]),
- emit([indent(2),"end"]),
- [];
- {"got objfun through args","ObjFun"} ->
- %% this is when the generated code gots the
- %% objfun though arguments on function
- %% invocation.
- if
- Ext == noext andalso Prop == mandatory ->
- ok;
- true ->
- asn1ct_name:new(tmpterm),
- asn1ct_name:new(tmpbytes),
- emit([nl," {",{curr,tmpterm},", ",{curr,tmpbytes},"} ="])
- end,
- {Name,RestFieldNames} =
- (Type#type.def)#'ObjectClassFieldType'.fieldname,
- emit(["?RT_PER:decode_open_type(",{curr,bytes},
- ", []),",nl]),
- if
- Ext == noext andalso Prop == mandatory ->
- emit([{curr,term}," =",nl," "]);
- true ->
- emit([" {"])
- end,
- emit(["case (catch ObjFun(",{asis,Name},",",
- {curr,tmpterm},",telltype,",
- {asis,RestFieldNames},")) of", nl]),
- emit([" {'EXIT',",{curr,reason},"} ->",nl]),
- emit([indent(6),"exit({'Type not ",
- "compatible with table constraint', ",
- {curr,reason},"});",nl]),
- asn1ct_name:new(tmpterm),
- emit([indent(4),"{",{curr,tmpterm},", _} ->",nl]),
- emit([indent(6),{curr,tmpterm},nl]),
- emit([indent(2),"end"]),
- if
- Ext == noext andalso Prop == mandatory ->
- ok;
- true ->
- emit([",",nl,{curr,tmpbytes},"}"])
- end,
- [];
- _ ->
- emit(["?RT_PER:decode_open_type(",{curr,bytes},
- ", [])"]),
- RefedFieldName =
- (Type#type.def)#'ObjectClassFieldType'.fieldname,
-
- [{Cname,RefedFieldName,
- asn1ct_gen:mk_var(asn1ct_name:curr(term)),
- asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),
- get_components_prop()}]
- end;
- {objectfield,PrimFieldName1,PFNList} ->
- emit(["?RT_PER:decode_open_type(",{curr,bytes},", [])"]),
- [{Cname,{PrimFieldName1,PFNList},
- asn1ct_gen:mk_var(asn1ct_name:curr(term)),
- asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),
- get_components_prop()}];
- _ ->
- CurrMod = get(currmod),
- case asn1ct_gen:type(Atype) of
- #'Externaltypereference'{module=CurrMod,type=EType} ->
- emit({"'dec_",EType,"'(",BytesVar,",telltype)"});
- #'Externaltypereference'{module=Mod,type=EType} ->
- emit({"'",Mod,"':'dec_",EType,"'(",BytesVar,
- ",telltype)"});
- {primitive,bif} ->
- case Atype of
- {fixedtypevaluefield,_,Btype} ->
- Ctgenmod:gen_dec_prim(Erule,Btype,
- BytesVar);
- _ ->
- Ctgenmod:gen_dec_prim(Erule,Type,
- BytesVar)
- end;
- 'ASN1_OPEN_TYPE' ->
- case Type#type.def of
- #'ObjectClassFieldType'{type=OpenType} ->
- Ctgenmod:gen_dec_prim(Erule,#type{def=OpenType},
- BytesVar);
- _ ->
- Ctgenmod:gen_dec_prim(Erule,Type,
- BytesVar)
- end;
- #typereference{val=Dname} ->
- emit({"'dec_",Dname,"'(",BytesVar,",telltype)"});
- {notype,_} ->
- emit({"'dec_",Atype,"'(",BytesVar,",telltype)"});
- {constructed,bif} ->
- NewTypename = [Cname|TopType],
- case Type#type.tablecinf of
- [{objfun,_}|_R] ->
- emit({"'dec_",asn1ct_gen:list2name(NewTypename),
- "'(",BytesVar,", telltype, ObjFun)"});
- _ ->
- emit({"'dec_",asn1ct_gen:list2name(NewTypename),
- "'(",BytesVar,", telltype)"})
- end
- end,
- case DecInfObj of
- {Cname,{_,OSet,UniqueFName,ValIndex}} ->
- Term = asn1ct_gen:mk_var(asn1ct_name:curr(term)),
- ValueMatch = value_match(ValIndex,Term),
- {ObjSetMod,ObjSetName} =
- case OSet of
- {M,O} -> {{asis,M},O};
- _ -> {"?MODULE",OSet}
+ {Cname,ObjSet} ->
+ ObjSetRef =
+ case ObjSet of
+ {deep,OSName,_,_} ->
+ OSName;
+ _ -> ObjSet
end,
- emit({",",nl,"ObjFun = ",ObjSetMod,
- ":'getdec_",ObjSetName,"'(",
- {asis,UniqueFName},", ",ValueMatch,")"});
+ {AccTerm++[{ObjSetRef,Cname,
+ asn1ct_gen:mk_var(asn1ct_name:curr(term))}],
+ AccBytes++SaveBytes};
_ ->
- ok
- end,
- []
+ {AccTerm,AccBytes++SaveBytes}
+ end
end,
- case Ext of
- {ext,Ep2,_} when Pos >= Ep2 ->
- emit([", {TmpValx",Pos,",Trem",Pos,"}",nl,"end"]);
- _ -> true
- end,
- %% Prepare return value
+ [Pre,Decode,{safe,Post}].
+
+gen_dec_line_open_type(Erule, {ext,Ep,_}, Pos) when Pos >= Ep ->
+ Imm = asn1ct_imm:per_dec_open_type(is_aligned(Erule)),
+ {safe,fun(St) ->
+ emit(["begin",nl]),
+ BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
+ {Dst,DstBuf} = asn1ct_imm:dec_slim_cg(Imm, BytesVar),
+ emit([",",nl,"{TmpValx",Pos,",_} = "]),
+ {Dst,
+ fun() ->
+ emit([",",nl,
+ "{TmpValx",Pos,",",DstBuf,"}",nl,
+ "end"]),
+ St
+ end}
+ end};
+gen_dec_line_open_type(_, _, _) ->
+ {safe,fun(St) ->
+ {asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
+ fun() -> St end}
+ end}.
+
+gen_dec_line_special(_, {typefield,_}, _TopType, Comp,
+ DecInfObj, Ext) ->
+ #'ComponentType'{name=Cname,typespec=Type,prop=Prop} = Comp,
+ fun({_BytesVar,PrevSt}) ->
+ case DecInfObj of
+ false -> % This is in a choice with typefield components
+ {Name,RestFieldNames} =
+ (Type#type.def)#'ObjectClassFieldType'.fieldname,
+
+ asn1ct_name:new(tmpterm),
+ asn1ct_name:new(reason),
+ emit([indent(2),"{",{curr,tmpterm},", ",{next,bytes},
+ "} = ?RT_PER:decode_open_type(",{curr,bytes},
+ ", []),",nl]),
+ emit([indent(2),"case (catch ObjFun(",
+ {asis,Name},",",{curr,tmpterm},",telltype,",
+ {asis,RestFieldNames},")) of", nl]),
+ emit([indent(4),"{'EXIT',",{curr,reason},"} ->",nl]),
+ emit([indent(6),"exit({'Type not ",
+ "compatible with table constraint', ",
+ {curr,reason},"});",nl]),
+ asn1ct_name:new(tmpterm),
+ emit([indent(4),"{",{curr,tmpterm},", _} ->",nl]),
+ emit([indent(6),"{",{asis,Cname},", {",{curr,tmpterm},", ",
+ {next,bytes},"}}",nl]),
+ emit([indent(2),"end"]),
+ {[],PrevSt};
+ {"got objfun through args","ObjFun"} ->
+ %% this is when the generated code gots the
+ %% objfun though arguments on function
+ %% invocation.
+ if
+ Ext == noext andalso Prop == mandatory ->
+ ok;
+ true ->
+ asn1ct_name:new(tmpterm),
+ asn1ct_name:new(tmpbytes),
+ emit([nl," {",{curr,tmpterm},", ",{curr,tmpbytes},"} ="])
+ end,
+ {Name,RestFieldNames} =
+ (Type#type.def)#'ObjectClassFieldType'.fieldname,
+ emit(["?RT_PER:decode_open_type(",{curr,bytes},
+ ", []),",nl]),
+ if
+ Ext == noext andalso Prop == mandatory ->
+ emit([{curr,term}," =",nl," "]);
+ true ->
+ emit([" {"])
+ end,
+ emit(["case (catch ObjFun(",{asis,Name},",",
+ {curr,tmpterm},",telltype,",
+ {asis,RestFieldNames},")) of", nl]),
+ emit([" {'EXIT',",{curr,reason},"} ->",nl]),
+ emit([indent(6),"exit({'Type not ",
+ "compatible with table constraint', ",
+ {curr,reason},"});",nl]),
+ asn1ct_name:new(tmpterm),
+ emit([indent(4),"{",{curr,tmpterm},", _} ->",nl]),
+ emit([indent(6),{curr,tmpterm},nl]),
+ emit([indent(2),"end"]),
+ if
+ Ext == noext andalso Prop == mandatory ->
+ ok;
+ true ->
+ emit([",",nl,{curr,tmpbytes},"}"])
+ end,
+ {[],PrevSt};
+ _ ->
+ emit(["?RT_PER:decode_open_type(",{curr,bytes},
+ ", [])"]),
+ RefedFieldName =
+ (Type#type.def)#'ObjectClassFieldType'.fieldname,
+
+ {[{Cname,RefedFieldName,
+ asn1ct_gen:mk_var(asn1ct_name:curr(term)),
+ asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),
+ Prop}],PrevSt}
+ end
+ end;
+gen_dec_line_special(_, {objectfield,PrimFieldName1,PFNList}, _TopType,
+ Comp, _DecInfObj, _Ext) ->
+ fun({_BytesVar,PrevSt}) ->
+ emit(["?RT_PER:decode_open_type(",{curr,bytes},", [])"]),
+ #'ComponentType'{name=Cname,prop=Prop} = Comp,
+ SaveBytes = [{Cname,{PrimFieldName1,PFNList},
+ asn1ct_gen:mk_var(asn1ct_name:curr(term)),
+ asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),
+ Prop}],
+ {SaveBytes,PrevSt}
+ end;
+gen_dec_line_special(Erule, Atype, TopType, Comp, DecInfObj, _Ext) ->
+ case gen_dec_line_other(Erule, Atype, TopType, Comp) of
+ Fun when is_function(Fun, 1) ->
+ fun({BytesVar,PrevSt}) ->
+ Fun(BytesVar),
+ gen_dec_line_dec_inf(Comp, DecInfObj),
+ {[],PrevSt}
+ end;
+ Imm0 ->
+ {imm,Imm0,
+ fun(Imm, {BytesVar,PrevSt}) ->
+ asn1ct_imm:dec_code_gen(Imm, BytesVar),
+ gen_dec_line_dec_inf(Comp, DecInfObj),
+ {[],PrevSt}
+ end}
+ end.
+
+gen_dec_line_dec_inf(Comp, DecInfObj) ->
+ #'ComponentType'{name=Cname} = Comp,
case DecInfObj of
- {Cname,ObjSet} ->
- ObjSetRef =
- case ObjSet of
- {deep,OSName,_,_} ->
- OSName;
- _ -> ObjSet
+ {Cname,{_,OSet,UniqueFName,ValIndex}} ->
+ Term = asn1ct_gen:mk_var(asn1ct_name:curr(term)),
+ ValueMatch = value_match(ValIndex,Term),
+ {ObjSetMod,ObjSetName} =
+ case OSet of
+ {M,O} -> {{asis,M},O};
+ _ -> {"?MODULE",OSet}
end,
- {[{ObjSetRef,Cname,asn1ct_gen:mk_var(asn1ct_name:curr(term))}],
- SaveBytes};
+ emit({",",nl,"ObjFun = ",ObjSetMod,
+ ":'getdec_",ObjSetName,"'(",
+ {asis,UniqueFName},", ",ValueMatch,")"});
_ ->
- {[],SaveBytes}
+ ok
+ end.
+
+gen_dec_line_other(Erule, Atype, TopType, Comp) ->
+ #'ComponentType'{name=Cname,typespec=Type} = Comp,
+ CurrMod = get(currmod),
+ Ctgenmod = asn1ct_gen:ct_gen_module(Erule),
+ case asn1ct_gen:type(Atype) of
+ #'Externaltypereference'{module=CurrMod,type=EType} ->
+ fun(BytesVar) ->
+ emit({"'dec_",EType,"'(",BytesVar,",telltype)"})
+ end;
+ #'Externaltypereference'{module=Mod,type=EType} ->
+ fun(BytesVar) ->
+ emit({"'",Mod,"':'dec_",EType,"'(",BytesVar,
+ ",telltype)"})
+ end;
+ {primitive,bif} ->
+ case Atype of
+ {fixedtypevaluefield,_,Btype} ->
+ gen_dec_prim(Ctgenmod, Erule, Btype);
+ _ ->
+ gen_dec_prim(Ctgenmod, Erule, Type)
+ end;
+ 'ASN1_OPEN_TYPE' ->
+ case Type#type.def of
+ #'ObjectClassFieldType'{type=OpenType} ->
+ gen_dec_prim(Ctgenmod, Erule, #type{def=OpenType});
+ _ ->
+ gen_dec_prim(Ctgenmod, Erule, Type)
+ end;
+ #typereference{val=Dname} ->
+ fun(BytesVar) ->
+ emit({"'dec_",Dname,"'(",BytesVar,",telltype)"})
+ end;
+ {notype,_} ->
+ fun(BytesVar) ->
+ emit({"'dec_",Atype,"'(",BytesVar,",telltype)"})
+ end;
+ {constructed,bif} ->
+ NewTypename = [Cname|TopType],
+ case Type#type.tablecinf of
+ [{objfun,_}|_R] ->
+ fun(BytesVar) ->
+ emit({"'dec_",asn1ct_gen:list2name(NewTypename),
+ "'(",BytesVar,", telltype, ObjFun)"})
+ end;
+ _ ->
+ fun(BytesVar) ->
+ emit({"'dec_",asn1ct_gen:list2name(NewTypename),
+ "'(",BytesVar,", telltype)"})
+ end
+ end
+ end.
+
+gen_dec_prim(Ctgenmod, Erule, Type) ->
+ case asn1ct_gen_per:gen_dec_imm(Erule, Type) of
+ no ->
+ fun(BytesVar) ->
+ Ctgenmod:gen_dec_prim(Erule, Type, BytesVar)
+ end;
+ Imm ->
+ Imm
end.
gen_enc_choice(Erule,TopType,CompList,Ext) ->
@@ -1640,18 +1799,12 @@ wrap_extensionAdditionGroups([],_,Acc,_,_) ->
lists:reverse(Acc).
-wrap_gen_dec_line(Erule,C,TopType,Cname,Type,Pos,DIO,Ext) ->
+wrap_gen_dec_line(Erule,C,TopType,_Cname,_Type,Pos,DIO,Ext) ->
put(component_type,{true,C}),
- gen_dec_line(Erule,TopType,Cname,Type,Pos,DIO,Ext,mandatory),
+ gen_dec_line(Erule, TopType, C#'ComponentType'{prop=mandatory},
+ Pos, DIO, Ext),
erase(component_type).
-get_components_prop() ->
- case get(component_type) of
- undefined ->
- mandatory;
- {true,#'ComponentType'{prop=Prop}} -> Prop
- end.
-
value_match(Index,Value) when is_atom(Value) ->
value_match(Index,atom_to_list(Value));
diff --git a/lib/asn1/src/asn1ct_gen.erl b/lib/asn1/src/asn1ct_gen.erl
index b0990e92cf..57b12ce186 100644
--- a/lib/asn1/src/asn1ct_gen.erl
+++ b/lib/asn1/src/asn1ct_gen.erl
@@ -1405,7 +1405,7 @@ gen_head(Erules,Mod,Hrl) ->
emit({"%% Purpose: encoder and decoder to the types in mod ",Mod,nl,nl}),
emit({"-module('",Mod,"').",nl}),
put(currmod,Mod),
- %emit({"-compile(export_all).",nl}),
+ emit({"-compile(nowarn_unused_vars).",nl}),
case {Hrl,lists:member(inline,get(encoding_options))} of
{0,_} -> true;
{_,true} -> true;
diff --git a/lib/asn1/src/asn1ct_gen_per.erl b/lib/asn1/src/asn1ct_gen_per.erl
index 3e100fc833..eb4cfdccc6 100644
--- a/lib/asn1/src/asn1ct_gen_per.erl
+++ b/lib/asn1/src/asn1ct_gen_per.erl
@@ -25,6 +25,7 @@
-include("asn1_records.hrl").
%-compile(export_all).
+-export([gen_dec_imm/2]).
-export([pgen/4,gen_dec_prim/3,gen_encode_prim/4]).
-export([gen_obj_code/3,gen_objectset_code/2]).
-export([gen_decode/2, gen_decode/3]).
@@ -146,10 +147,12 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
case D#type.def of
'INTEGER' ->
emit({"?RT_PER:encode_integer(", %fel
- {asis,effective_constraint(integer,Constraint)},",",Value,")"});
+ {asis,asn1ct_imm:effective_constraint(integer,Constraint)},
+ ",",Value,")"});
{'INTEGER',NamedNumberList} ->
emit({"?RT_PER:encode_integer(",
- {asis,effective_constraint(integer,Constraint)},",",Value,",",
+ {asis,asn1ct_imm:effective_constraint(integer,Constraint)},
+ ",",Value,",",
{asis,NamedNumberList},")"});
{'ENUMERATED',{Nlist1,Nlist2}} ->
NewList = lists:concat([[{0,X}||{X,_} <- Nlist1],['EXT_MARK'],[{1,X}||{X,_} <- Nlist2]]),
@@ -184,7 +187,7 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
{asis,Constraint},",",Value,",",
{asis,NamedNumberList},")"});
'NULL' ->
- emit({"?RT_PER:encode_null(",Value,")"});
+ emit("[]");
'OBJECT IDENTIFIER' ->
emit({"?RT_PER:encode_object_identifier(",Value,")"});
'RELATIVE-OID' ->
@@ -295,107 +298,16 @@ emit_enc_enumerated_case(_Per,C, {0,EnumName}, Count) ->
emit_enc_enumerated_case(_Erule, C, EnumName, Count) ->
emit(["'",EnumName,"' -> ?RT_PER:encode_integer(",{asis,C},", ",Count,")"]).
-%% effective_constraint(Type,C)
-%% Type = atom()
-%% C = [C1,...]
-%% C1 = {'SingleValue',SV} | {'ValueRange',VR} | {atom(),term()}
-%% SV = integer() | [integer(),...]
-%% VR = {Lb,Ub}
-%% Lb = 'MIN' | integer()
-%% Ub = 'MAX' | integer()
-%% Returns a single value if C only has a single value constraint, and no
-%% value range constraints, that constrains to a single value, otherwise
-%% returns a value range that has the lower bound set to the lowest value
-%% of all single values and lower bound values in C and the upper bound to
-%% the greatest value.
-effective_constraint(integer,[C={{_,_},_}|_Rest]) -> % extension
- [C]; %% [C|effective_constraint(integer,Rest)]; XXX what is possible ???
-effective_constraint(integer,C) ->
- SVs = get_constraints(C,'SingleValue'),
- SV = effective_constr('SingleValue',SVs),
- VRs = get_constraints(C,'ValueRange'),
- VR = effective_constr('ValueRange',VRs),
- greatest_common_range(SV,VR).
-
-effective_constr(_,[]) ->
- [];
-effective_constr('SingleValue',List) ->
- SVList = lists:flatten(lists:map(fun(X)->element(2,X)end,List)),
- %% Sort and remove duplicates before generating SingleValue or ValueRange
- %% In case of ValueRange, also check for 'MIN and 'MAX'
- case lists:usort(SVList) of
- [N] ->
- [{'SingleValue',N}];
- L when is_list(L) ->
- [{'ValueRange',{least_Lb(L),greatest_Ub(L)}}]
- end;
-effective_constr('ValueRange',List) ->
- LBs = lists:map(fun({_,{Lb,_}})-> Lb end,List),
- UBs = lists:map(fun({_,{_,Ub}})-> Ub end,List),
- Lb = least_Lb(LBs),
- [{'ValueRange',{Lb,lists:max(UBs)}}].
-
-greatest_common_range([],VR) ->
- VR;
-greatest_common_range(SV,[]) ->
- SV;
-greatest_common_range(SV,VR) ->
- greatest_common_range2(mk_vr(SV),mk_vr(VR)).
-greatest_common_range2({_,Int},{'MIN',Ub}) when is_integer(Int),
- Int > Ub ->
- [{'ValueRange',{'MIN',Int}}];
-greatest_common_range2({_,Int},{Lb,Ub}) when is_integer(Int),
- Int < Lb ->
- [{'ValueRange',{Int,Ub}}];
-greatest_common_range2({_,Int},VR={_Lb,_Ub}) when is_integer(Int) ->
- [{'ValueRange',VR}];
-greatest_common_range2({_,L},{Lb,Ub}) when is_list(L) ->
- Min = least_Lb([Lb|L]),
- Max = greatest_Ub([Ub|L]),
- [{'ValueRange',{Min,Max}}];
-greatest_common_range2({Lb1,Ub1},{Lb2,Ub2}) ->
- Min = least_Lb([Lb1,Lb2]),
- Max = greatest_Ub([Ub1,Ub2]),
- [{'ValueRange',{Min,Max}}].
-
-mk_vr([{Type,I}]) when is_atom(Type), is_integer(I) ->
- {I,I};
-mk_vr([{Type,{Lb,Ub}}]) when is_atom(Type) ->
- {Lb,Ub};
-mk_vr(Other) ->
- Other.
-
-least_Lb(L) ->
- case lists:member('MIN',L) of
- true -> 'MIN';
- _ -> lists:min(L)
- end.
-
-greatest_Ub(L) ->
- case lists:member('MAX',L) of
- true -> 'MAX';
- _ -> lists:max(L)
- end.
-
-
-get_constraints(L=[{Key,_}],Key) ->
- L;
-get_constraints([],_) ->
- [];
-get_constraints(C,Key) ->
- {value,L} = keysearch_allwithkey(Key,1,C,[]),
- L.
-
-keysearch_allwithkey(Key,Ix,C,Acc) ->
- case lists:keysearch(Key,Ix,C) of
- false ->
- {value,Acc};
- {value,T} ->
- RestC = lists:delete(T,C),
- keysearch_allwithkey(Key,Ix,RestC,[T|Acc])
+get_constraint([{Key,V}], Key) ->
+ V;
+get_constraint([], _) ->
+ no;
+get_constraint(C, Key) ->
+ case lists:keyfind(Key, 1, C) of
+ false -> no;
+ {Key,V} -> V
end.
-
%% Object code generating for encoding and decoding
%% ------------------------------------------------
@@ -1228,19 +1140,43 @@ gen_decode_user(Erules,D) when is_record(D,typedef) ->
exit({error,{asn1,{unknown,Other}}})
end.
+gen_dec_imm(Erule, #type{def=Name,constraint=C}) ->
+ Aligned = case Erule of
+ uper -> false;
+ per -> true
+ end,
+ gen_dec_imm_1(Name, C, Aligned).
+
+gen_dec_imm_1('BOOLEAN', _Constr, _Aligned) ->
+ asn1ct_imm:per_dec_boolean();
+gen_dec_imm_1({'ENUMERATED',{Base,Ext}}, _Constr, Aligned) ->
+ asn1ct_imm:per_dec_enumerated(Base, Ext, Aligned);
+gen_dec_imm_1({'ENUMERATED',NamedNumberList}, _Constr, Aligned) ->
+ asn1ct_imm:per_dec_enumerated(NamedNumberList, Aligned);
+gen_dec_imm_1('INTEGER', Constr, Aligned) ->
+ asn1ct_imm:per_dec_integer(Constr, Aligned);
+gen_dec_imm_1({'INTEGER',NamedNumberList}, Constraint, Aligned) ->
+ asn1ct_imm:per_dec_named_integer(Constraint,
+ NamedNumberList,
+ Aligned);
+gen_dec_imm_1('OCTET STRING', Constraint, Aligned) ->
+ SzConstr = get_constraint(Constraint, 'SizeConstraint'),
+ Imm = asn1ct_imm:per_dec_octet_string(SzConstr, Aligned),
+ {convert,binary_to_list,Imm};
+gen_dec_imm_1(_, _, _) -> no.
+
+gen_dec_prim(Erule, Type, BytesVar) ->
+ case gen_dec_imm(Erule, Type) of
+ no ->
+ gen_dec_prim_1(Erule, Type, BytesVar);
+ Imm ->
+ asn1ct_imm:dec_code_gen(Imm, BytesVar)
+ end.
-gen_dec_prim(Erules,Att,BytesVar) ->
- Typename = Att#type.def,
- Constraint = Att#type.constraint,
+gen_dec_prim_1(Erule,
+ #type{def=Typename,constraint=Constraint}=Att,
+ BytesVar) ->
case Typename of
- 'INTEGER' ->
- emit({"?RT_PER:decode_integer(",BytesVar,",",
- {asis,effective_constraint(integer,Constraint)},")"});
- {'INTEGER',NamedNumberList} ->
- emit({"?RT_PER:decode_integer(",BytesVar,",",
- {asis,effective_constraint(integer,Constraint)},",",
- {asis,NamedNumberList},")"});
-
'REAL' ->
emit({"?RT_PER:decode_real(",BytesVar,")"});
@@ -1256,8 +1192,7 @@ gen_dec_prim(Erules,Att,BytesVar) ->
{asis,NamedNumberList},")"})
end;
'NULL' ->
- emit({"?RT_PER:decode_null(",
- BytesVar,")"});
+ emit({"{'NULL',",BytesVar,"}"});
'OBJECT IDENTIFIER' ->
emit({"?RT_PER:decode_object_identifier(",
BytesVar,")"});
@@ -1267,24 +1202,6 @@ gen_dec_prim(Erules,Att,BytesVar) ->
'ObjectDescriptor' ->
emit({"?RT_PER:decode_ObjectDescriptor(",
BytesVar,")"});
- {'ENUMERATED',{NamedNumberList1,NamedNumberList2}} ->
- NewTup = {list_to_tuple([X||{X,_} <- NamedNumberList1]),
- list_to_tuple([X||{X,_} <- NamedNumberList2])},
- NewC = [{'ValueRange',{0,size(element(1,NewTup))-1}}],
- emit({"?RT_PER:decode_enumerated(",BytesVar,",",
- {asis,NewC},",",
- {asis,NewTup},")"});
- {'ENUMERATED',NamedNumberList} ->
- NewTup = list_to_tuple([X||{X,_} <- NamedNumberList]),
- NewC = [{'ValueRange',{0,size(NewTup)-1}}],
- emit({"?RT_PER:decode_enumerated(",BytesVar,",",
- {asis,NewC},",",
- {asis,NewTup},")"});
- 'BOOLEAN'->
- emit({"?RT_PER:decode_boolean(",BytesVar,")"});
- 'OCTET STRING' ->
- emit({"?RT_PER:decode_octet_string(",BytesVar,",",
- {asis,Constraint},")"});
'NumericString' ->
emit({"?RT_PER:decode_NumericString(",BytesVar,",",
{asis,Constraint},")"});
@@ -1323,7 +1240,7 @@ gen_dec_prim(Erules,Att,BytesVar) ->
'UTF8String' ->
emit({"?RT_PER:decode_UTF8String(",BytesVar,")"});
'ANY' ->
- case Erules of
+ case Erule of
per ->
emit(["fun() -> {XTerm,YTermXBytes} = ?RT_PER:decode_open_type(",BytesVar,",",{asis,Constraint}, "), {binary_to_list(XTerm),XBytes} end ()"]);
_ ->
@@ -1345,7 +1262,7 @@ gen_dec_prim(Erules,Att,BytesVar) ->
emit([" {YTerm,_} = dec_",Tname,"(XTerm,mandatory),",nl]),
emit([" {YTerm,XBytes} end(",BytesVar,")"]);
_ ->
- case Erules of
+ case Erule of
per ->
emit(["fun() -> {XTerm,XBytes} = ?RT_PER:decode_open_type(",BytesVar,", []), {binary_to_list(XTerm),XBytes} end()"]);
_ ->
@@ -1353,11 +1270,11 @@ gen_dec_prim(Erules,Att,BytesVar) ->
end
end;
#'ObjectClassFieldType'{} ->
- case asn1ct_gen:get_inner(Att#type.def) of
+ case asn1ct_gen:get_inner(Typename) of
{fixedtypevaluefield,_,InnerType} ->
- gen_dec_prim(Erules,InnerType,BytesVar);
+ gen_dec_prim(Erule, InnerType, BytesVar);
T ->
- gen_dec_prim(Erules,Att#type{def=T},BytesVar)
+ gen_dec_prim(Erule, Att#type{def=T}, BytesVar)
end;
Other ->
exit({'cant decode' ,Other})
diff --git a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl
index 16eec92847..ecd212c3e3 100644
--- a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl
+++ b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl
@@ -176,7 +176,7 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
{asis,NamedNumberList},")"})
end;
'NULL' ->
- emit({"?RT_PER:encode_null(",Value,")"});
+ emit("[]");
'OBJECT IDENTIFIER' ->
emit({"?RT_PER:encode_object_identifier(",Value,")"});
'RELATIVE-OID' ->
@@ -450,17 +450,6 @@ emit_enc_octet_string(_Erules,Constraint,Value) ->
emit({" ?RT_PER:encode_octet_string(",{asis,C},",false,",Value,")",nl})
end.
-emit_dec_octet_string(Constraint,BytesVar) ->
- case get_constraint(Constraint,'SizeConstraint') of
- 0 ->
- emit({" {[],",BytesVar,"}",nl});
- {_,0} ->
- emit({" {[],",BytesVar,"}",nl});
- C ->
- emit({" ?RT_PER:decode_octet_string(",BytesVar,",",
- {asis,C},",false)",nl})
- end.
-
emit_enc_integer_case(Value) ->
case get(component_type) of
{true,#'ComponentType'{prop=Prop}} ->
@@ -624,23 +613,6 @@ get_constraint(C,Key) ->
V
end.
-get_constraints(L=[{Key,_}],Key) ->
- L;
-get_constraints([],_) ->
- [];
-get_constraints(C,Key) ->
- {value,L} = keysearch_allwithkey(Key,1,C,[]),
- L.
-
-keysearch_allwithkey(Key,Ix,C,Acc) ->
- case lists:keysearch(Key,Ix,C) of
- false ->
- {value,Acc};
- {value,T} ->
- RestC = lists:delete(T,C),
- keysearch_allwithkey(Key,Ix,RestC,[T|Acc])
- end.
-
%% effective_constraint(Type,C)
%% Type = atom()
%% C = [C1,...]
@@ -657,69 +629,9 @@ keysearch_allwithkey(Key,Ix,C,Acc) ->
effective_constraint(integer,[C={{_,_},_}|_Rest]) -> % extension
[C]; %% [C|effective_constraint(integer,Rest)]; XXX what is possible ???
effective_constraint(integer,C) ->
- SVs = get_constraints(C,'SingleValue'),
- SV = effective_constr('SingleValue',SVs),
- VRs = get_constraints(C,'ValueRange'),
- VR = effective_constr('ValueRange',VRs),
- CRange = greatest_common_range(SV,VR),
- pre_encode(integer,CRange);
+ pre_encode(integer, asn1ct_imm:effective_constraint(integer, C));
effective_constraint(bitstring,C) ->
- get_constraint(C,'SizeConstraint').
-
-effective_constr(_,[]) ->
- [];
-effective_constr('SingleValue',List) ->
- SVList = lists:flatten(lists:map(fun(X)->element(2,X)end,List)),
- %% Sort and remove duplicates before generating SingleValue or ValueRange
- %% In case of ValueRange, also check for 'MIN and 'MAX'
- case lists:usort(SVList) of
- [N] ->
- [{'SingleValue',N}];
- L when is_list(L) ->
- [{'ValueRange',{least_Lb(L),greatest_Ub(L)}}]
- end;
-effective_constr('ValueRange',List) ->
- LBs = lists:map(fun({_,{Lb,_}})-> Lb end,List),
- UBs = lists:map(fun({_,{_,Ub}})-> Ub end,List),
- Lb = least_Lb(LBs),
- [{'ValueRange',{Lb,lists:max(UBs)}}].
-
-greatest_common_range([],VR) ->
- VR;
-greatest_common_range(SV,[]) ->
- SV;
-greatest_common_range([{_,Int}],[{_,{'MIN',Ub}}]) when is_integer(Int),
- Int > Ub ->
- [{'ValueRange',{'MIN',Int}}];
-greatest_common_range([{_,Int}],[{_,{Lb,Ub}}]) when is_integer(Int),
- Int < Lb ->
- [{'ValueRange',{Int,Ub}}];
-greatest_common_range([{_,Int}],VR=[{_,{_Lb,_Ub}}]) when is_integer(Int) ->
- VR;
-greatest_common_range([{_,L}],[{_,{Lb,Ub}}]) when is_list(L) ->
- Min = least_Lb([Lb|L]),
- Max = greatest_Ub([Ub|L]),
- [{'ValueRange',{Min,Max}}];
-greatest_common_range([{_,{Lb1,Ub1}}],[{_,{Lb2,Ub2}}]) ->
- Min = least_Lb([Lb1,Lb2]),
- Max = greatest_Ub([Ub1,Ub2]),
- [{'ValueRange',{Min,Max}}].
-
-
-least_Lb(L) ->
- case lists:member('MIN',L) of
- true -> 'MIN';
- _ -> lists:min(L)
- end.
-
-greatest_Ub(L) ->
- case lists:member('MAX',L) of
- true -> 'MAX';
- _ -> lists:max(L)
- end.
-
-
-
+ asn1ct_imm:effective_constraint(bitstring, C).
pre_encode(integer,[]) ->
[];
@@ -1586,17 +1498,9 @@ gen_dec_prim(Erules,Att,BytesVar) ->
Constraint = Att#type.constraint,
case Typename of
'INTEGER' ->
- EffectiveConstr = effective_constraint(integer,Constraint),
- emit_dec_integer(EffectiveConstr,BytesVar);
-% emit({"?RT_PER:decode_integer(",BytesVar,",",
-% {asis,EffectiveConstr},")"});
- {'INTEGER',NamedNumberList} ->
- EffectiveConstr = effective_constraint(integer,Constraint),
- emit_dec_integer(EffectiveConstr,BytesVar,NamedNumberList);
-% emit({"?RT_PER:decode_integer(",BytesVar,",",
-% {asis,EffectiveConstr},",",
-% {asis,NamedNumberList},")"});
-
+ asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar);
+ {'INTEGER',_NamedNumberList} ->
+ asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar);
'REAL' ->
emit(["?RT_PER:decode_real(",BytesVar,")"]);
@@ -1612,8 +1516,7 @@ gen_dec_prim(Erules,Att,BytesVar) ->
{asis,NamedNumberList},")"})
end;
'NULL' ->
- emit({"?RT_PER:decode_null(",
- BytesVar,")"});
+ emit({"{'NULL',",BytesVar,"}"});
'OBJECT IDENTIFIER' ->
emit({"?RT_PER:decode_object_identifier(",
BytesVar,")"});
@@ -1623,23 +1526,13 @@ gen_dec_prim(Erules,Att,BytesVar) ->
'ObjectDescriptor' ->
emit({"?RT_PER:decode_ObjectDescriptor(",
BytesVar,")"});
- {'ENUMERATED',{NamedNumberList1,NamedNumberList2}} ->
- NewTup = {list_to_tuple([X||{X,_} <- NamedNumberList1]),
- list_to_tuple([X||{X,_} <- NamedNumberList2])},
- NewC = [{'ValueRange',{0,size(element(1,NewTup))-1}}],
- emit({"?RT_PER:decode_enumerated(",BytesVar,",",
- {asis,NewC},",",
- {asis,NewTup},")"});
- {'ENUMERATED',NamedNumberList} ->
- NewNNL = [X||{X,_} <- NamedNumberList],
- NewC = effective_constraint(integer,
- [{'ValueRange',{0,length(NewNNL)-1}}]),
- emit_dec_enumerated(BytesVar,NewC,NewNNL);
+ {'ENUMERATED',_} ->
+ asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar);
'BOOLEAN'->
- emit({"?RT_PER:decode_boolean(",BytesVar,")"});
+ asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar);
'OCTET STRING' ->
- emit_dec_octet_string(Constraint,BytesVar);
+ asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar);
'NumericString' ->
emit_dec_known_multiplier_string('NumericString',
@@ -1716,88 +1609,6 @@ gen_dec_prim(Erules,Att,BytesVar) ->
exit({'cant decode' ,Other})
end.
-
-emit_dec_integer(C,BytesVar,NNL) ->
- asn1ct_name:new(tmpterm),
- asn1ct_name:new(buffer),
- Tmpterm = asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),
- Buffer = asn1ct_gen:mk_var(asn1ct_name:curr(buffer)),
- emit({" begin {",{curr,tmpterm},",",{curr,buffer},"} = ",nl}),
- emit_dec_integer(C,BytesVar),
- emit({",",nl," case ",Tmpterm," of",nl}),
- lists:map(fun({Name,Int})->emit({" ",Int," -> {",{asis,Name},",",
- Buffer,"};",nl});
- (_)-> exit({error,{asn1,{"error in named number list",NNL}}})
- end,
- NNL),
- emit({" _ -> {",Tmpterm,",",Buffer,"}",nl}),
- emit({" end",nl}), % end of case
- emit(" end"). % end of begin
-
-emit_dec_integer([{'SingleValue',Int}],BytesVar) when is_integer(Int) ->
- emit(["{",Int,",",BytesVar,"}"]);
-emit_dec_integer([{_,{Lb,_Ub},_Range,{BitsOrOctets,N}}],BytesVar) ->
- GetBorO =
- case BitsOrOctets of
- bits -> "getbits";
- _ -> "getoctets"
- end,
- asn1ct_name:new(tmpterm),
- asn1ct_name:new(tmpremain),
- emit({" begin",nl," {",{curr,tmpterm},",",{curr,tmpremain},"}=",
- "?RT_PER:",GetBorO,"(",BytesVar,",",N,"),",nl}),
- emit({" {",{curr,tmpterm},"+",Lb,",",{curr,tmpremain},"}",nl,
- " end"});
-emit_dec_integer([{_,{'MIN',_}}],BytesVar) ->
- emit({"?RT_PER:decode_unconstrained_number(",BytesVar,")"});
-emit_dec_integer([{_,{Lb,'MAX'}}],BytesVar) ->
- emit({"?RT_PER:decode_semi_constrained_number(",BytesVar,",",Lb,")"});
-emit_dec_integer([{'ValueRange',VR={Lb,Ub}}],BytesVar) ->
- Range = Ub-Lb+1,
- emit({"?RT_PER:decode_constrained_number(",BytesVar,",",
- {asis,VR},",",Range,")"});
-emit_dec_integer(C=[{Rc,_}],BytesVar) when is_tuple(Rc) ->
- emit({"?RT_PER:decode_integer(",BytesVar,",",{asis,C},")"});
-emit_dec_integer(_,BytesVar) ->
- emit({"?RT_PER:decode_unconstrained_number(",BytesVar,")"}).
-
-
-emit_dec_enumerated(BytesVar,C,NamedNumberList) ->
- emit_dec_enumerated_begin(),% emits a begin if component
- asn1ct_name:new(tmpterm),
- Tmpterm = asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),
- asn1ct_name:new(tmpremain),
- Tmpremain = asn1ct_gen:mk_var(asn1ct_name:curr(tmpremain)),
- emit({" {",{curr,tmpterm},",",{curr,tmpremain},"} =",nl}),
- emit_dec_integer(C,BytesVar),
- emit({",",nl," case ",Tmpterm," of "}),
-
- Cases=lists:flatten(dec_enumerated_cases(NamedNumberList,Tmpremain,0)),
- emit({Cases++"_->exit({error,{asn1,{decode_enumerated,{",Tmpterm,
- ",",{asis,NamedNumberList},"}}}}) end",nl}),
- emit_dec_enumerated_end().
-
-emit_dec_enumerated_begin() ->
- case get(component_type) of
- {true,_} ->
- emit({" begin",nl});
- _ -> ok
- end.
-
-emit_dec_enumerated_end() ->
- case get(component_type) of
- {true,_} ->
- emit(" end");
- _ -> ok
- end.
-
-
-dec_enumerated_cases([Name|Rest],Tmpremain,No) ->
- io_lib:format("~w->{~w,~s};",[No,Name,Tmpremain])++
- dec_enumerated_cases(Rest,Tmpremain,No+1);
-dec_enumerated_cases([],_,_) ->
- "".
-
%% For PER the ExtensionAdditionGroup notation has significance for the encoding and decoding
%% the components within the ExtensionAdditionGroup is treated in a similar way as if they
%% have been specified within a SEQUENCE, therefore we construct a fake sequence type here
diff --git a/lib/asn1/src/asn1ct_imm.erl b/lib/asn1/src/asn1ct_imm.erl
new file mode 100644
index 0000000000..34bb0b8714
--- /dev/null
+++ b/lib/asn1/src/asn1ct_imm.erl
@@ -0,0 +1,626 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+-module(asn1ct_imm).
+-export([per_dec_boolean/0,per_dec_enumerated/2,per_dec_enumerated/3,
+ per_dec_extension_map/1,
+ per_dec_integer/2,per_dec_length/3,per_dec_named_integer/3,
+ per_dec_octet_string/2,per_dec_open_type/1]).
+-export([optimize_alignment/1,optimize_alignment/2,
+ dec_slim_cg/2,dec_code_gen/2]).
+-export([effective_constraint/2]).
+-import(asn1ct_gen, [emit/1]).
+
+-record(st, {var,
+ base}).
+
+dec_slim_cg(Imm0, BytesVar) ->
+ {Imm,_} = optimize_alignment(Imm0),
+ asn1ct_name:new(v),
+ [H|T] = atom_to_list(asn1ct_name:curr(v)) ++ "@",
+ VarBase = [H-($a-$A)|T],
+ St0 = #st{var=0,base=VarBase},
+ {Res,Pre,_} = flatten(Imm, BytesVar, St0),
+ dcg_list_outside(Pre),
+ Res.
+
+dec_code_gen(Imm, BytesVar) ->
+ emit(["begin",nl]),
+ {Dst,DstBuf} = dec_slim_cg(Imm, BytesVar),
+ emit([",",nl,
+ "{",Dst,",",DstBuf,"}",nl,
+ "end"]),
+ ok.
+
+optimize_alignment(Imm) ->
+ opt_al(Imm, unknown).
+
+optimize_alignment(Imm, Al) ->
+ opt_al(Imm, Al).
+
+
+per_dec_boolean() ->
+ {map,{get_bits,1,[1]},[{0,false},{1,true}]}.
+
+per_dec_enumerated(NamedList0, Aligned) ->
+ Constraint = [{'ValueRange',{0,length(NamedList0)-1}}],
+ NamedList = per_dec_enumerated_fix_list(NamedList0, [enum_error], 0),
+ Int = per_dec_integer(Constraint, Aligned),
+ {map,Int,NamedList}.
+
+per_dec_enumerated(BaseNamedList, NamedListExt0, Aligned) ->
+ Base = per_dec_enumerated(BaseNamedList, Aligned),
+ NamedListExt = per_dec_enumerated_fix_list(NamedListExt0,
+ [enum_default], 0),
+ Ext = {map,per_dec_normally_small_number(Aligned),NamedListExt},
+ bit_case(Base, Ext).
+
+per_dec_extension_map(Aligned) ->
+ Len = {add,per_dec_normally_small_number(Aligned),1},
+ {get_bits,Len,[1,bitstring]}.
+
+per_dec_integer(Constraint0, Aligned) ->
+ Constraint = effective_constraint(integer, Constraint0),
+ per_dec_integer_1(Constraint, Aligned).
+
+per_dec_length(SingleValue, _, _Aligned) when is_integer(SingleValue) ->
+ {value,SingleValue};
+per_dec_length({S,S}, _, _Aligned) when is_integer(S) ->
+ {value,S};
+per_dec_length({{_,_}=Constr,_}, AllowZero, Aligned) ->
+ bit_case(per_dec_length(Constr, AllowZero, Aligned),
+ per_dec_length(undefined, AllowZero, Aligned));
+per_dec_length({Lb,Ub}, _AllowZero, Aligned) when is_integer(Lb),
+ is_integer(Lb),
+ Ub =< 65535 ->
+ per_dec_constrained(Lb, Ub, Aligned);
+per_dec_length({_,_}, AllowZero, Aligned) ->
+ decode_unconstrained_length(AllowZero, Aligned);
+per_dec_length(undefined, AllowZero, Aligned) ->
+ decode_unconstrained_length(AllowZero, Aligned).
+
+per_dec_named_integer(Constraint, NamedList0, Aligned) ->
+ Int = per_dec_integer(Constraint, Aligned),
+ NamedList = [{K,V} || {V,K} <- NamedList0] ++ [integer_default],
+ {map,Int,NamedList}.
+
+per_dec_octet_string(Constraint, Aligned) ->
+ dec_string(Constraint, 8, Aligned).
+
+per_dec_open_type(Aligned) ->
+ {get_bits,decode_unconstrained_length(true, Aligned),
+ [8,binary,{align,Aligned}]}.
+
+
+%%%
+%%% Local functions.
+%%%
+
+dec_string(Sv, U, _Aligned) when is_integer(Sv), U*Sv =< 16 ->
+ {get_bits,Sv,[U,binary]};
+dec_string(Sv, U, Aligned) when is_integer(Sv), Sv < 16#10000 ->
+ {get_bits,Sv,[U,binary,{align,Aligned}]};
+dec_string(C, U, Aligned) when is_list(C) ->
+ dec_string({hd(C),lists:max(C)}, U, Aligned);
+dec_string({Sv,Sv}, U, Aligned) ->
+ dec_string(Sv, U, Aligned);
+dec_string({{_,_}=C,_}, U, Aligned) ->
+ bit_case(dec_string(C, U, Aligned),
+ dec_string(no, U, Aligned));
+dec_string({Lb,Ub}, U, Aligned) when Ub < 16#10000 ->
+ Len = per_dec_constrained(Lb, Ub, Aligned),
+ {get_bits,Len,[U,binary,{align,Aligned}]};
+dec_string(_, U, Aligned) ->
+ Al = [{align,Aligned}],
+ DecRest = fun(V, Buf) ->
+ emit(["?RT_PER:decode_fragmented(",V,", ",
+ Buf,", ",U,")"])
+ end,
+ {'case',[{test,{get_bits,1,[1|Al]},0,
+ {value,{get_bits,
+ {get_bits,7,[1]},
+ [U,binary]}}},
+ {test,{get_bits,1,[1|Al]},1,
+ {test,{get_bits,1,[1]},0,
+ {value,{get_bits,
+ {get_bits,14,[1]},
+ [U,binary]}}}},
+ {test,{get_bits,1,[1|Al]},1,
+ {test,{get_bits,1,[1]},1,
+ {value,{call,DecRest,{get_bits,6,[1]}}}}}]}.
+
+per_dec_enumerated_fix_list([{V,_}|T], Tail, N) ->
+ [{N,V}|per_dec_enumerated_fix_list(T, Tail, N+1)];
+per_dec_enumerated_fix_list([], Tail, _) -> Tail.
+
+per_dec_integer_1([{'SingleValue',Value}], _Aligned) ->
+ {value,Value};
+per_dec_integer_1([{'ValueRange',{Lb,'MAX'}}], Aligned) when is_integer(Lb) ->
+ per_dec_unconstrained(Aligned);
+per_dec_integer_1([{'ValueRange',{Lb,Ub}}], Aligned) when is_integer(Lb),
+ is_integer(Ub) ->
+ per_dec_constrained(Lb, Ub, Aligned);
+per_dec_integer_1([{{_,_}=Constr0,_}], Aligned) ->
+ Constr = effective_constraint(integer, [Constr0]),
+ bit_case(per_dec_integer(Constr, Aligned),
+ per_dec_unconstrained(Aligned));
+per_dec_integer_1([], Aligned) ->
+ per_dec_unconstrained(Aligned).
+
+per_dec_unconstrained(Aligned) ->
+ {get_bits,decode_unconstrained_length(false, Aligned),[8,signed]}.
+
+per_dec_constrained(Lb, Ub, false) ->
+ Range = Ub - Lb + 1,
+ Get = {get_bits,uper_num_bits(Range),[1]},
+ add_lb(Lb, Get);
+per_dec_constrained(Lb, Ub, true) ->
+ Range = Ub - Lb + 1,
+ Get = if
+ Range =< 255 ->
+ {get_bits,per_num_bits(Range),[1,unsigned]};
+ Range == 256 ->
+ {get_bits,1,[8,unsigned,{align,true}]};
+ Range =< 65536 ->
+ {get_bits,2,[8,unsigned,{align,true}]};
+ true ->
+ RangeOctLen = byte_size(binary:encode_unsigned(Range - 1)),
+ {get_bits,per_dec_length({1,RangeOctLen}, false, true),
+ [8,unsigned,{align,true}]}
+ end,
+ add_lb(Lb, Get).
+
+add_lb(0, Get) -> Get;
+add_lb(Lb, Get) -> {add,Get,Lb}.
+
+per_dec_normally_small_number(Aligned) ->
+ Small = {get_bits,6,[1]},
+ Unlimited = per_decode_semi_constrained(0, Aligned),
+ bit_case(Small, Unlimited).
+
+per_decode_semi_constrained(Lb, Aligned) ->
+ add_lb(Lb, {get_bits,decode_unconstrained_length(false, Aligned),[8]}).
+
+bit_case(Base, Ext) ->
+ {'case',[{test,{get_bits,1,[1]},0,Base},
+ {test,{get_bits,1,[1]},1,Ext}]}.
+
+decode_unconstrained_length(AllowZero, Aligned) ->
+ Al = [{align,Aligned}],
+ Zero = case AllowZero of
+ false -> [non_zero];
+ true -> []
+ end,
+ {'case',[{test,{get_bits,1,[1|Al]},0,
+ {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]}}}}]}.
+
+uper_num_bits(N) ->
+ uper_num_bits(N, 1, 0).
+
+uper_num_bits(N, T, B) when N =< T -> B;
+uper_num_bits(N, T, B) -> uper_num_bits(N, T bsl 1, B+1).
+
+per_num_bits(2) -> 1;
+per_num_bits(N) when N =< 4 -> 2;
+per_num_bits(N) when N =< 8 -> 3;
+per_num_bits(N) when N =< 16 -> 4;
+per_num_bits(N) when N =< 32 -> 5;
+per_num_bits(N) when N =< 64 -> 6;
+per_num_bits(N) when N =< 128 -> 7;
+per_num_bits(N) when N =< 255 -> 8.
+
+%%%
+%%% Remove unnecessary aligning to octet boundaries.
+%%%
+
+opt_al({get_bits,E0,Opts0}, A0) ->
+ {E,A1} = opt_al(E0, A0),
+ Opts = opt_al_1(A1, Opts0),
+ A = update_al(A1, E, Opts),
+ {{get_bits,E,Opts},A};
+opt_al({call,Fun,E0}, A0) ->
+ {E,A} = opt_al(E0, A0),
+ {{call,Fun,E},A};
+opt_al({convert,Op,E0}, A0) ->
+ {E,A} = opt_al(E0, A0),
+ {{convert,Op,E},A};
+opt_al({value,E0}, A0) ->
+ {E,A} = opt_al(E0, A0),
+ {{value,E},A};
+opt_al({add,E0,I}, A0) when is_integer(I) ->
+ {E,A} = opt_al(E0, A0),
+ {{add,E,I},A};
+opt_al({test,E0,V,B0}, A0) ->
+ {E,A1} = opt_al(E0, A0),
+ {B,A2} = opt_al(B0, A1),
+ {{test,E,V,B},A2};
+opt_al({'case',Cs0}, A0) ->
+ {Cs,A} = opt_al_cs(Cs0, A0),
+ {{'case',Cs},A};
+opt_al({map,E0,Cs}, A0) ->
+ {E,A} = opt_al(E0, A0),
+ {{map,E,Cs},A};
+opt_al(I, A) when is_integer(I) ->
+ {I,A}.
+
+opt_al_cs([C0|Cs0], A0) ->
+ {C,A1} = opt_al(C0, A0),
+ {Cs,A2} = opt_al_cs(Cs0, A0),
+ {[C|Cs],merge_al(A1, A2)};
+opt_al_cs([], _) -> {[],none}.
+
+merge_al(unknown, _) -> unknown;
+merge_al(Other, none) -> Other;
+merge_al(_, unknown) -> unknown;
+merge_al(I0, I1) ->
+ case {I0 rem 8,I1 rem 8} of
+ {I,I} -> I;
+ {_,_} -> unknown
+ end.
+
+opt_al_1(unknown, Opts) ->
+ Opts;
+opt_al_1(A, Opts0) ->
+ case alignment(Opts0) of
+ none ->
+ Opts0;
+ full ->
+ case A rem 8 of
+ 0 ->
+ %% Already in alignment.
+ proplists:delete(align, Opts0);
+ Bits ->
+ %% Cheaper alignment with a constant padding.
+ Opts1 = proplists:delete(align, Opts0),
+ [{align,8-Bits }|Opts1]
+ end;
+ A -> %Assertion.
+ Opts0
+ end.
+
+update_al(A0, E, Opts) ->
+ A = case alignment(Opts) of
+ none -> A0;
+ full -> 0;
+ Bits when is_integer(A0) ->
+ 0 = (A0 + Bits) rem 8; %Assertion.
+ _ ->
+ 0
+ end,
+ [U] = [U || U <- Opts, is_integer(U)],
+ if
+ U rem 8 =:= 0 -> A;
+ is_integer(A), is_integer(E) -> A + U*E;
+ true -> unknown
+ end.
+
+%%%
+%%% Flatten the intermediate format and assign temporaries.
+%%%
+
+flatten({get_bits,I,U}, Buf0, St0) when is_integer(I) ->
+ {Dst,St} = new_var_pair(St0),
+ Gb = {get_bits,{I,Buf0},U,Dst},
+ flatten_align(Gb, [], St);
+flatten({get_bits,E0,U}, Buf0, St0) ->
+ {E,Pre,St1} = flatten(E0, Buf0, St0),
+ {Dst,St2} = new_var_pair(St1),
+ Gb = {get_bits,E,U,Dst},
+ flatten_align(Gb, Pre, St2);
+flatten({test,{get_bits,I,U},V,E0}, Buf0, St0) when is_integer(I) ->
+ {DstBuf0,St1} = new_var("Buf", St0),
+ Gb = {get_bits,{I,Buf0},U,{V,DstBuf0}},
+ {{_Dst,DstBuf},Pre0,St2} = flatten_align(Gb, [], St1),
+ {E,Pre1,St3} = flatten(E0, DstBuf, St2),
+ {E,Pre0++Pre1,St3};
+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({'case',Cs0}, Buf0, St0) ->
+ {Dst,St1} = new_var_pair(St0),
+ {Cs1,St} = flatten_cs(Cs0, Buf0, St1),
+ {Al,Cs2} = flatten_hoist_align(Cs1),
+ {Dst,Al++[{'case',Buf0,Cs2,Dst}],St};
+flatten({map,E0,Cs0}, Buf0, St0) ->
+ {{E,DstBuf},Pre,St1} = flatten(E0, Buf0, St0),
+ {Dst,St2} = new_var("Int", St1),
+ Cs = flatten_map_cs(Cs0, E),
+ {{Dst,DstBuf},Pre++[{'map',E,Cs,{Dst,DstBuf}}],St2};
+flatten({value,V0}, Buf0, St0) when is_integer(V0) ->
+ {{V0,Buf0},[],St0};
+flatten({value,V0}, Buf0, St0) ->
+ flatten(V0, Buf0, St0);
+flatten({convert,Op,E0}, Buf0, St0) ->
+ {{E,Buf},Pre,St1} = flatten(E0, Buf0, St0),
+ {Dst,St2} = new_var("Conv", St1),
+ {{Dst,Buf},Pre++[{convert,Op,E,Dst}],St2};
+flatten({call,Fun,E0}, Buf0, St0) ->
+ {Src,Pre,St1} = flatten(E0, Buf0, St0),
+ {Dst,St2} = new_var_pair(St1),
+ {Dst,Pre++[{call,Fun,Src,Dst}],St2}.
+
+flatten_cs([C0|Cs0], Buf, St0) ->
+ {C,Pre,St1} = flatten(C0, Buf, St0),
+ {Cs,St2} = flatten_cs(Cs0, Buf, St0),
+ St3 = St2#st{var=max(St1#st.var, St2#st.var)},
+ {[Pre++[{return,C}]|Cs],St3};
+flatten_cs([], _, St) -> {[],St}.
+
+flatten_map_cs(Cs, Var) ->
+ flatten_map_cs_1(Cs, {Var,Cs}).
+
+flatten_map_cs_1([{K,V}|Cs], DefData) ->
+ [{{asis,K},{asis,V}}|flatten_map_cs_1(Cs, DefData)];
+flatten_map_cs_1([integer_default], {Int,_}) ->
+ [{'_',Int}];
+flatten_map_cs_1([enum_default], {Int,_}) ->
+ [{'_',["{asn1_enum,",Int,"}"]}];
+flatten_map_cs_1([enum_error], {Var,Cs}) ->
+ Vs = [V || {_,V} <- Cs],
+ [{'_',["exit({error,{asn1,{decode_enumerated,{",Var,",",
+ {asis,Vs},"}}}})"]}];
+flatten_map_cs_1([], _) -> [].
+
+flatten_hoist_align([[{align_bits,_,_}=Ab|T]|Cs]) ->
+ flatten_hoist_align_1(Cs, Ab, [T]);
+flatten_hoist_align(Cs) -> {[],Cs}.
+
+flatten_hoist_align_1([[Ab|T]|Cs], Ab, Acc) ->
+ flatten_hoist_align_1(Cs, Ab, [T|Acc]);
+flatten_hoist_align_1([], Ab, Acc) ->
+ {[Ab],lists:reverse(Acc)}.
+
+flatten_align({get_bits,{SrcBits,SrcBuf},U,Dst}=Gb0, Pre, St0) ->
+ case alignment(U) of
+ none ->
+ flatten_align_1(U, Dst, Pre++[Gb0], St0);
+ full ->
+ {PadBits,St1} = new_var("Pad", St0),
+ {DstBuf,St2} = new_var("Buf", St1),
+ Ab = {align_bits,SrcBuf,PadBits},
+ Agb = {get_bits,{PadBits,SrcBuf},[1],{'_',DstBuf}},
+ Gb = {get_bits,{SrcBits,DstBuf},U,Dst},
+ flatten_align_1(U, Dst, Pre++[Ab,Agb,Gb], St2);
+ PadBits when is_integer(PadBits), PadBits > 0 ->
+ {DstBuf,St1} = new_var("Buf", St0),
+ Agb = {get_bits,{PadBits,SrcBuf},[1],{'_',DstBuf}},
+ Gb = {get_bits,{SrcBits,DstBuf},U,Dst},
+ flatten_align_1(U, Dst, Pre++[Agb,Gb], St1)
+ end.
+
+flatten_align_1(U, {D,_}=Dst, Pre, St) ->
+ case is_non_zero(U) of
+ false ->
+ {Dst,Pre,St};
+ true ->
+ {Dst,Pre++[{non_zero,D}],St}
+ end.
+
+new_var_pair(St0) ->
+ {Var,St1} = new_var("V", St0),
+ {Buf,St2} = new_var("Buf", St1),
+ {{Var,Buf},St2}.
+
+new_var(Tag, #st{base=VarBase,var=N}=St) ->
+ {VarBase++Tag++integer_to_list(N),St#st{var=N+1}}.
+
+alignment([{align,false}|_]) -> none;
+alignment([{align,true}|_]) -> full;
+alignment([{align,Bits}|_]) -> Bits;
+alignment([_|T]) -> alignment(T);
+alignment([]) -> none.
+
+is_non_zero(Fl) ->
+ lists:member(non_zero, Fl).
+
+%%%
+%%% Generate Erlang code from the flattened intermediate format.
+%%%
+
+dcg_list_outside([{align_bits,Buf,SzVar}|T]) ->
+ emit([SzVar," = bit_size(",Buf,") band 7"]),
+ iter_dcg_list_outside(T);
+dcg_list_outside([{'case',Buf,Cs,Dst}|T]) ->
+ dcg_case(Buf, Cs, Dst),
+ iter_dcg_list_outside(T);
+dcg_list_outside([{'map',Val,Cs,Dst}|T]) ->
+ dcg_map(Val, Cs, Dst),
+ iter_dcg_list_outside(T);
+dcg_list_outside([{add,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);
+dcg_list_outside([{call,Fun,{V,Buf},{Dst,DstBuf}}|T]) ->
+ emit(["{",Dst,",",DstBuf,"} = "]),
+ Fun(V, Buf),
+ iter_dcg_list_outside(T);
+dcg_list_outside([{convert,Op,V,Dst}|T]) ->
+ emit([Dst," = ",Op,"(",V,")"]),
+ iter_dcg_list_outside(T);
+dcg_list_outside([{get_bits,{_,Buf0},_,_}|_]=L0) ->
+ emit("<<"),
+ {L,Buf} = dcg_list_inside(L0, buf),
+ emit([Buf,"/bitstring>> = ",Buf0]),
+ iter_dcg_list_outside(L);
+dcg_list_outside([]) ->
+ emit("ignore"),
+ ok.
+
+iter_dcg_list_outside([_|_]=T) ->
+ emit([",",nl]),
+ dcg_list_outside(T);
+iter_dcg_list_outside([]) -> ok.
+
+dcg_case(Buf, Cs, {Dst,DstBuf}) ->
+ emit(["{",Dst,",",DstBuf,"} = case ",Buf," of",nl]),
+ dcg_case_cs(Cs),
+ emit("end").
+
+dcg_case_cs([C|Cs]) ->
+ emit("<<"),
+ {T0,DstBuf} = dcg_list_inside(C, buf),
+ emit([DstBuf,"/bitstring>>"]),
+ T1 = dcg_guard(T0),
+ dcg_list_outside(T1),
+ case Cs of
+ [] -> emit([nl]);
+ [_|_] -> emit([";",nl])
+ end,
+ dcg_case_cs(Cs);
+dcg_case_cs([]) -> ok.
+
+dcg_guard([{non_zero,Src}|T]) ->
+ emit([" when ",Src," =/= 0 ->",nl]),
+ T;
+dcg_guard(T) ->
+ emit([" ->",nl]),
+ T.
+
+dcg_map(Val, Cs, {Dst,_}) ->
+ emit([Dst," = case ",Val," of",nl]),
+ dcg_map_cs(Cs),
+ emit("end").
+
+dcg_map_cs([{K,V}]) ->
+ emit([K," -> ",V,nl]);
+dcg_map_cs([{K,V}|Cs]) ->
+ emit([K," -> ",V,";",nl]),
+ dcg_map_cs(Cs).
+
+dcg_list_inside([{get_bits,{Sz,_},Fl0,{Dst,DstBuf}}|T], _) ->
+ Fl = bit_flags(Fl0, []),
+ emit([mk_dest(Dst),":",Sz,Fl,","]),
+ dcg_list_inside(T, DstBuf);
+dcg_list_inside(L, Dst) -> {L,Dst}.
+
+bit_flags([1|T], Acc) ->
+ bit_flags(T, Acc);
+bit_flags([{align,_}|T], Acc) ->
+ bit_flags(T, Acc);
+bit_flags([non_zero|T], Acc) ->
+ bit_flags(T, Acc);
+bit_flags([U|T], Acc) when is_integer(U) ->
+ bit_flags(T, ["unit:"++integer_to_list(U)|Acc]);
+bit_flags([H|T], Acc) ->
+ bit_flags(T, [atom_to_list(H)|Acc]);
+bit_flags([], []) ->
+ "";
+bit_flags([], Acc) ->
+ "/" ++ bit_flags_1(Acc, "").
+
+bit_flags_1([H|T], Sep) ->
+ Sep ++ H ++ bit_flags_1(T, "-");
+bit_flags_1([], _) -> [].
+
+mk_dest(I) when is_integer(I) ->
+ integer_to_list(I);
+mk_dest(S) -> S.
+
+%% effective_constraint(Type,C)
+%% Type = atom()
+%% C = [C1,...]
+%% C1 = {'SingleValue',SV} | {'ValueRange',VR} | {atom(),term()}
+%% SV = integer() | [integer(),...]
+%% VR = {Lb,Ub}
+%% Lb = 'MIN' | integer()
+%% Ub = 'MAX' | integer()
+%% Returns a single value if C only has a single value constraint, and no
+%% value range constraints, that constrains to a single value, otherwise
+%% returns a value range that has the lower bound set to the lowest value
+%% of all single values and lower bound values in C and the upper bound to
+%% the greatest value.
+effective_constraint(integer,[C={{_,_},_}|_Rest]) -> % extension
+ [C];
+effective_constraint(integer, C) ->
+ SVs = get_constraints(C, 'SingleValue'),
+ SV = effective_constr('SingleValue', SVs),
+ VRs = get_constraints(C, 'ValueRange'),
+ VR = effective_constr('ValueRange', VRs),
+ greatest_common_range(SV, VR);
+effective_constraint(bitstring, C) ->
+ get_constraint(C, 'SizeConstraint').
+
+effective_constr(_, []) -> [];
+effective_constr('SingleValue', List) ->
+ SVList = lists:flatten(lists:map(fun(X) -> element(2, X) end, List)),
+ %% Sort and remove duplicates before generating SingleValue or ValueRange
+ %% In case of ValueRange, also check for 'MIN and 'MAX'
+ case lists:usort(SVList) of
+ [N] ->
+ [{'SingleValue',N}];
+ [_|_]=L ->
+ [{'ValueRange',{least_Lb(L),greatest_Ub(L)}}]
+ end;
+effective_constr('ValueRange', List) ->
+ LBs = lists:map(fun({_,{Lb,_}}) -> Lb end, List),
+ UBs = lists:map(fun({_,{_,Ub}}) -> Ub end, List),
+ Lb = least_Lb(LBs),
+ [{'ValueRange',{Lb,lists:max(UBs)}}].
+
+greatest_common_range([], VR) ->
+ VR;
+greatest_common_range(SV, []) ->
+ SV;
+greatest_common_range([{_,Int}], [{_,{'MIN',Ub}}])
+ when is_integer(Int), Int > Ub ->
+ [{'ValueRange',{'MIN',Int}}];
+greatest_common_range([{_,Int}],[{_,{Lb,Ub}}])
+ when is_integer(Int), Int < Lb ->
+ [{'ValueRange',{Int,Ub}}];
+greatest_common_range([{_,Int}],VR=[{_,{_Lb,_Ub}}]) when is_integer(Int) ->
+ VR;
+greatest_common_range([{_,L}],[{_,{Lb,Ub}}]) when is_list(L) ->
+ Min = least_Lb([Lb|L]),
+ Max = greatest_Ub([Ub|L]),
+ [{'ValueRange',{Min,Max}}];
+greatest_common_range([{_,{Lb1,Ub1}}], [{_,{Lb2,Ub2}}]) ->
+ Min = least_Lb([Lb1,Lb2]),
+ Max = greatest_Ub([Ub1,Ub2]),
+ [{'ValueRange',{Min,Max}}].
+
+
+least_Lb(L) ->
+ case lists:member('MIN', L) of
+ true -> 'MIN';
+ false -> lists:min(L)
+ end.
+
+greatest_Ub(L) ->
+ case lists:member('MAX', L) of
+ true -> 'MAX';
+ false -> lists:max(L)
+ end.
+
+get_constraint(C, Key) ->
+ case lists:keyfind(Key, 1, C) of
+ false -> no;
+ {_,V} -> V
+ end.
+
+get_constraints([{Key,_}=Pair|T], Key) ->
+ [Pair|get_constraints(T, Key)];
+get_constraints([_|T], Key) ->
+ get_constraints(T, Key);
+get_constraints([], _) -> [].
diff --git a/lib/asn1/src/asn1ct_value.erl b/lib/asn1/src/asn1ct_value.erl
index 6057e27b63..389642c446 100644
--- a/lib/asn1/src/asn1ct_value.erl
+++ b/lib/asn1/src/asn1ct_value.erl
@@ -436,11 +436,8 @@ get_encoding_rule(M) ->
open_type_value(ber) ->
<<4,9,111,112,101,110,95,116,121,112,101>>;
-open_type_value(per) ->
- <<"\n\topen_type">>; %octet string value "open_type"
-% <<10,9,111,112,101,110,95,116,121,112,101>>;
open_type_value(_) ->
- [4,9,111,112,101,110,95,116,121,112,101].
+ <<"\n\topen_type">>. %octet string value "open_type"
to_textual_order({Root,Ext}) ->
{to_textual_order(Root),Ext};
diff --git a/lib/asn1/src/asn1rt_per_bin_rt2ct.erl b/lib/asn1/src/asn1rt_per_bin_rt2ct.erl
index 01e1cb23d7..5997232f13 100644
--- a/lib/asn1/src/asn1rt_per_bin_rt2ct.erl
+++ b/lib/asn1/src/asn1rt_per_bin_rt2ct.erl
@@ -22,25 +22,21 @@
-include("asn1_records.hrl").
--export([dec_fixup/3]).
+-export([decode_fragmented/3]).
-export([setchoiceext/1, setext/1, fixoptionals/3, fixextensions/2,
- getext/1, getextension/2, skipextensions/3, getbit/1, getchoice/3 ]).
--export([getoptionals/2, getoptionals2/2,
- set_choice/3, encode_integer/2, encode_integer/3 ]).
--export([decode_integer/2, decode_integer/3, encode_small_number/1,
- decode_boolean/1, encode_length/2, decode_length/1, decode_length/2,
- encode_small_length/1, decode_small_length/1,
+ skipextensions/3, getbit/1, getchoice/3 ]).
+-export([set_choice/3, encode_integer/2, encode_integer/3 ]).
+-export([encode_small_number/1,
+ encode_length/2,
+ encode_small_length/1,
decode_compact_bit_string/3]).
--export([decode_enumerated/3,
- encode_bit_string/3, decode_bit_string/3 ]).
--export([encode_octet_string/2, decode_octet_string/2,
- encode_null/1, decode_null/1,
+-export([encode_bit_string/3, decode_bit_string/3 ]).
+-export([encode_octet_string/2,
encode_object_identifier/1, decode_object_identifier/1,
encode_real/1, decode_real/1,
encode_relative_oid/1, decode_relative_oid/1,
complete/1]).
-
-export([encode_open_type/2, decode_open_type/2]).
-export([encode_GeneralString/2, decode_GeneralString/2,
@@ -51,19 +47,10 @@
encode_UTF8String/1,decode_UTF8String/1
]).
--export([decode_constrained_number/2,
- decode_constrained_number/3,
- decode_unconstrained_number/1,
- decode_semi_constrained_number/2,
- encode_unconstrained_number/1,
- decode_constrained_number/4,
+-export([encode_unconstrained_number/1,
encode_octet_string/3,
- decode_octet_string/3,
encode_known_multiplier_string/5,
- decode_known_multiplier_string/5,
- getoctets/2, getbits/2
-% start_drv/1,start_drv2/1,init_drv/1
- ]).
+ decode_known_multiplier_string/5]).
-export([eint_positive/1]).
@@ -73,20 +60,6 @@
-define('32K',32768).
-define('64K',65536).
-%%-define(nodriver,true).
-
-dec_fixup(Terms,Cnames,RemBytes) ->
- dec_fixup(Terms,Cnames,RemBytes,[]).
-
-dec_fixup([novalue|T],[_Hc|Tc],RemBytes,Acc) ->
- dec_fixup(T,Tc,RemBytes,Acc);
-dec_fixup([{_Name,novalue}|T],[_Hc|Tc],RemBytes,Acc) ->
- dec_fixup(T,Tc,RemBytes,Acc);
-dec_fixup([H|T],[Hc|Tc],RemBytes,Acc) ->
- dec_fixup(T,Tc,RemBytes,[{Hc,H}|Acc]);
-dec_fixup([],_Cnames,RemBytes,Acc) ->
- {lists:reverse(Acc),RemBytes}.
-
%%--------------------------------------------------------
%% setchoiceext(InRootSet) -> [{bit,X}]
%% X is set to 1 when InRootSet==false
@@ -131,15 +104,6 @@ fixoptionals([Pos|Ot],Val,Acc) ->
end.
-getext(Bytes) when is_bitstring(Bytes) ->
- getbit(Bytes).
-
-getextension(0, Bytes) ->
- {<<>>,Bytes};
-getextension(1, Bytes) ->
- {Len,Bytes2} = decode_small_length(Bytes),
- getbits_as_binary(Len,Bytes2).% {Bin,Bytes3}.
-
fixextensions({ext,ExtPos,ExtNum},Val) ->
case fixextensions(ExtPos,ExtNum+ExtPos,Val,0) of
0 -> [];
@@ -182,14 +146,6 @@ getchoice(Bytes,_,1) ->
getchoice(Bytes,NumChoices,0) ->
decode_constrained_number(Bytes,{0,NumChoices-1}).
-%% old version kept for backward compatibility with generates from R7B01
-getoptionals(Bytes,NumOpt) ->
- getbits_as_binary(NumOpt,Bytes).
-
-%% new version used in generates from r8b_patch/3 and later
-getoptionals2(Bytes,NumOpt) ->
- {_,_} = getbits(Bytes,NumOpt).
-
%% getbits_as_binary(Num,Bytes) -> {Bin,Rest}
%% Num = integer(),
@@ -332,32 +288,6 @@ decode_fragmented_bits(<<0:1,Len:7,Bin/binary>>,C,Acc) ->
exit({error,{asn1,{illegal_value,C,BinBits}}})
end.
-
-decode_fragmented_octets(Bin,C) ->
- decode_fragmented_octets(Bin,C,[]).
-
-decode_fragmented_octets(<<3:2,Len:6,Bin/binary>>,C,Acc) ->
- {Value,Bin2} = split_binary(Bin,Len * ?'16K'),
- decode_fragmented_octets(Bin2,C,[Value|Acc]);
-decode_fragmented_octets(<<0:1,0:7,Bin/binary>>,C,Acc) ->
- Octets = list_to_binary(lists:reverse(Acc)),
- case C of
- Int when is_integer(Int), C == size(Octets) ->
- {Octets,Bin};
- Int when is_integer(Int) ->
- exit({error,{asn1,{illegal_value,C,Octets}}})
- end;
-decode_fragmented_octets(<<0:1,Len:7,Bin/binary>>,C,Acc) ->
- <<Value:Len/binary-unit:8,Bin2/binary>> = Bin,
- BinOctets = list_to_binary(lists:reverse([Value|Acc])),
- case C of
- Int when is_integer(Int),size(BinOctets) == Int ->
- {BinOctets,Bin2};
- Int when is_integer(Int) ->
- exit({error,{asn1,{illegal_value,C,BinOctets}}})
- end.
-
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% encode_open_type(Constraint, Value) -> CompleteList
@@ -442,40 +372,6 @@ encode_integer(_,Val) ->
exit({error,{asn1,{illegal_value,Val}}}).
-
-decode_integer(Buffer,Range,NamedNumberList) ->
- {Val,Buffer2} = decode_integer(Buffer,Range),
- case lists:keysearch(Val,2,NamedNumberList) of
- {value,{NewVal,_}} -> {NewVal,Buffer2};
- _ -> {Val,Buffer2}
- end.
-
-decode_integer(Buffer,[{Rc,_Ec}]) when is_tuple(Rc) ->
- {Ext,Buffer2} = getext(Buffer),
- case Ext of
- 0 -> decode_integer(Buffer2,[Rc]);
- 1 -> decode_unconstrained_number(Buffer2)
- end;
-decode_integer(Buffer,undefined) ->
- decode_unconstrained_number(Buffer);
-decode_integer(Buffer,C) ->
- case get_constraint(C,'SingleValue') of
- V when is_integer(V) ->
- {V,Buffer};
- _ ->
- decode_integer1(Buffer,C)
- end.
-
-decode_integer1(Buffer,C) ->
- case VR = get_constraint(C,'ValueRange') of
- no ->
- decode_unconstrained_number(Buffer);
- {Lb, 'MAX'} ->
- decode_semi_constrained_number(Buffer,Lb);
- {_Lb,_Ub} ->
- decode_constrained_number(Buffer,VR)
- end.
-
%% X.691:10.6 Encoding of a normally small non-negative whole number
%% Use this for encoding of CHOICE index if there is an extension marker in
%% the CHOICE
@@ -495,7 +391,7 @@ decode_small_number(Bytes) ->
0 ->
getbits(Bytes2,6);
1 ->
- decode_semi_constrained_number(Bytes2,0)
+ decode_semi_constrained_number(Bytes2)
end.
%% X.691:10.7 Encoding of a semi-constrained whole number
@@ -518,12 +414,10 @@ encode_semi_constrained_number(Lb,Val) ->
[encode_length(undefined,Len),[21,<<Len:16>>,Oct]]
end.
-decode_semi_constrained_number(Bytes,{Lb,_}) ->
- decode_semi_constrained_number(Bytes,Lb);
-decode_semi_constrained_number(Bytes,Lb) ->
+decode_semi_constrained_number(Bytes) ->
{Len,Bytes2} = decode_length(Bytes,undefined),
{V,Bytes3} = getoctets(Bytes2,Len),
- {V+Lb,Bytes3}.
+ {V,Bytes3}.
encode_constrained_number({Lb,_Ub},_Range,{bits,N},Val) ->
Val2 = Val-Lb,
@@ -609,13 +503,6 @@ decode_constrained_number(Buffer,VR={Lb,Ub}) ->
Range = Ub - Lb + 1,
decode_constrained_number(Buffer,VR,Range).
-decode_constrained_number(Buffer,{Lb,_Ub},_Range,{bits,N}) ->
- {Val,Remain} = getbits(Buffer,N),
- {Val+Lb,Remain};
-decode_constrained_number(Buffer,{Lb,_Ub},_Range,{octets,N}) ->
- {Val,Remain} = getoctets(Buffer,N),
- {Val+Lb,Remain}.
-
decode_constrained_number(Buffer,{Lb,_Ub},Range) ->
% Val2 = Val - Lb,
{Val,Remain} =
@@ -716,23 +603,6 @@ enint(-1, [B1|T]) when B1 > 127 ->
enint(N, Acc) ->
enint(N bsr 8, [N band 16#ff|Acc]).
-decode_unconstrained_number(Bytes) ->
- {Len,Bytes2} = decode_length(Bytes,undefined),
- {Ints,Bytes3} = getoctets_as_bin(Bytes2,Len),
- {dec_integer(Ints),Bytes3}.
-
-dec_integer(Bin = <<0:1,_:7,_/binary>>) ->
- decpint(Bin);
-dec_integer(<<_:1,B:7,BitStr/bitstring>>) ->
- Size = bit_size(BitStr),
- <<I:Size>> = BitStr,
- (-128 + B) bsl bit_size(BitStr) bor I.
-
-decpint(Bin) ->
- Size = bit_size(Bin),
- <<Int:Size>> = Bin,
- Int.
-
%% X.691:10.9 Encoding of a length determinant
%%encode_small_length(undefined,Len) -> % null means no UpperBound
%% encode_small_number(Len).
@@ -777,18 +647,6 @@ encode_small_length(Len) ->
[1,encode_length(undefined,Len)].
-decode_small_length(Buffer) ->
- case getbit(Buffer) of
- {0,Remain} ->
- {Bits,Remain2} = getbits(Remain,6),
- {Bits+1,Remain2};
- {1,Remain} ->
- decode_length(Remain,undefined)
- end.
-
-decode_length(Buffer) ->
- decode_length(Buffer,undefined).
-
decode_length(Buffer,undefined) -> % un-constrained
case align(Buffer) of
<<0:1,Oct:7,Rest/binary>> ->
@@ -831,38 +689,6 @@ decode_length(Buffer,SingleValue) when is_integer(SingleValue) ->
{SingleValue,Buffer}.
- % X.691:11
-decode_boolean(Buffer) -> %when record(Buffer,buffer)
- case getbit(Buffer) of
- {1,Remain} -> {true,Remain};
- {0,Remain} -> {false,Remain}
- end.
-
-
-%% ENUMERATED with extension marker
-decode_enumerated(Buffer,C,{Ntup1,Ntup2}) when is_tuple(Ntup1), is_tuple(Ntup2) ->
- {Ext,Buffer2} = getext(Buffer),
- case Ext of
- 0 -> % not an extension value
- {Val,Buffer3} = decode_integer(Buffer2,C),
- case catch (element(Val+1,Ntup1)) of
- NewVal when is_atom(NewVal) -> {NewVal,Buffer3};
- _Error -> exit({error,{asn1,{decode_enumerated,{Val,[Ntup1,Ntup2]}}}})
- end;
- 1 -> % this an extension value
- {Val,Buffer3} = decode_small_number(Buffer2),
- case catch (element(Val+1,Ntup2)) of
- NewVal when is_atom(NewVal) -> {NewVal,Buffer3};
- _ -> {{asn1_enum,Val},Buffer3}
- end
- end;
-
-decode_enumerated(Buffer,C,NamedNumberTup) when is_tuple(NamedNumberTup) ->
- {Val,Buffer2} = decode_integer(Buffer,C),
- case catch (element(Val+1,NamedNumberTup)) of
- NewVal when is_atom(NewVal) -> {NewVal,Buffer2};
- _Error -> exit({error,{asn1,{decode_enumerated,{Val,NamedNumberTup}}}})
- end.
%%===============================================================================
%%===============================================================================
@@ -1313,49 +1139,74 @@ encode_octet_string(SZ={_,_},false,Val) ->
% [encode_length(SZ,length(Val)),align,
% {octets,Val}];
Len = length(Val),
- [encode_length(SZ,Len),2,
- octets_to_complete(Len,Val)];
+ try
+ [encode_length(SZ,Len),2,
+ octets_to_complete(Len,Val)]
+ catch
+ exit:{error,{asn1,{encode_length,_}}} ->
+ encode_fragmented_octet_string(Val)
+ end;
encode_octet_string(SZ,false,Val) when is_list(SZ) ->
Len = length(Val),
- [encode_length({hd(SZ),lists:max(SZ)},Len),2,
- octets_to_complete(Len,Val)];
+ try
+ [encode_length({hd(SZ),lists:max(SZ)},Len),2,
+ octets_to_complete(Len,Val)]
+ catch
+ exit:{error,{asn1,{encode_length,_}}} ->
+ encode_fragmented_octet_string(Val)
+ end;
+encode_octet_string(Sv,false,Val) when is_integer(Sv) ->
+ encode_fragmented_octet_string(Val);
encode_octet_string(no,false,Val) ->
Len = length(Val),
- [encode_length(undefined,Len),2,
- octets_to_complete(Len,Val)];
+ try
+ [encode_length(undefined,Len),2,
+ octets_to_complete(Len,Val)]
+ catch
+ exit:{error,{asn1,{encode_length,_}}} ->
+ encode_fragmented_octet_string(Val)
+ end;
encode_octet_string(C,_,_) ->
exit({error,{not_implemented,C}}).
-
-decode_octet_string(Bytes,Range) ->
- decode_octet_string(Bytes,Range,false).
-
-decode_octet_string(<<B1,Bytes/bitstring>>,1,false) ->
-%% {B1,Bytes2} = getbits(Bytes,8),
- {[B1],Bytes};
-decode_octet_string(<<B1,B2,Bytes/bitstring>>,2,false) ->
-%% {Bs,Bytes2}= getbits(Bytes,16),
-%% {binary_to_list(<<Bs:16>>),Bytes2};
- {[B1,B2],Bytes};
-decode_octet_string(Bytes,Sv,false) when is_integer(Sv),Sv=<65535 ->
- %% Bytes2 = align(Bytes),
- %% getoctets_as_list aligns buffer before it picks octets
- getoctets_as_list(Bytes,Sv);
-decode_octet_string(Bytes,Sv,false) when is_integer(Sv) ->
- Bytes2 = align(Bytes),
- decode_fragmented_octets(Bytes2,Sv);
-decode_octet_string(Bytes,{Lb,Ub},false) ->
- {Len,Bytes2} = decode_length(Bytes,{Lb,Ub}),
-%% Bytes3 = align(Bytes2),
- getoctets_as_list(Bytes2,Len);
-decode_octet_string(Bytes,Sv,false) when is_list(Sv) ->
- {Len,Bytes2} = decode_length(Bytes,{hd(Sv),lists:max(Sv)}),
-%% Bytes3 = align(Bytes2),
- getoctets_as_list(Bytes2,Len);
-decode_octet_string(Bytes,no,false) ->
- {Len,Bytes2} = decode_length(Bytes,undefined),
-%% Bytes3 = align(Bytes2),
- getoctets_as_list(Bytes2,Len).
+encode_fragmented_octet_string(Val) ->
+ Bin = iolist_to_binary(Val),
+ efos_1(Bin).
+
+efos_1(<<B1:16#C000/binary,B2:16#4000/binary,T/binary>>) ->
+ [20,1,<<3:2,4:6>>,
+ octets_to_complete(16#C000, B1),
+ octets_to_complete(16#4000, B2)|efos_1(T)];
+efos_1(<<B:16#C000/binary,T/binary>>) ->
+ [20,1,<<3:2,3:6>>,octets_to_complete(16#C000, B)|efos_1(T)];
+efos_1(<<B:16#8000/binary,T/binary>>) ->
+ [20,1,<<3:2,2:6>>,octets_to_complete(16#8000, B)|efos_1(T)];
+efos_1(<<B:16#4000/binary,T/binary>>) ->
+ [20,1,<<3:2,1:6>>,octets_to_complete(16#4000, B)|efos_1(T)];
+efos_1(<<>>) ->
+ [20,1,0];
+efos_1(<<B/bitstring>>) ->
+ Len = byte_size(B),
+ [encode_length(undefined, Len),octets_to_complete(Len, B)].
+
+decode_fragmented(SegSz0, Buf0, Unit) ->
+ SegSz = SegSz0 * Unit * ?'16K',
+ <<Res:SegSz/bitstring,Buf/bitstring>> = Buf0,
+ decode_fragmented_1(Buf, Unit, Res).
+
+decode_fragmented_1(<<0:1,N:7,Buf0/bitstring>>, Unit, Res) ->
+ Sz = N*Unit,
+ <<S:Sz/bitstring,Buf/bitstring>> = Buf0,
+ {<<Res/bitstring,S/bitstring>>,Buf};
+decode_fragmented_1(<<1:1,0:1,N:14,Buf0/bitstring>>, Unit, Res) ->
+ Sz = N*Unit,
+ <<S:Sz/bitstring,Buf/bitstring>> = Buf0,
+ {<<Res/bitstring,S/bitstring>>,Buf};
+decode_fragmented_1(<<1:1,1:1,SegSz0:6,Buf0/bitstring>>, Unit, Res0) ->
+ SegSz = SegSz0 * Unit * ?'16K',
+ <<Frag:SegSz/bitstring,Buf/bitstring>> = Buf0,
+ Res = <<Res0/bitstring,Frag/bitstring>>,
+ decode_fragmented_1(Buf, Unit, Res).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1543,16 +1394,6 @@ chars_decode2(Bytes,{Min,Max,CharInTab},NumBits,Len,Acc) ->
chars_decode2(Bytes2,{Min,Max,CharInTab},NumBits,Len -1,[element(Char+1,CharInTab)|Acc]).
- % X.691:17
-encode_null(_Val) -> []. % encodes to nothing
-%encode_null({Name,Val}) when is_atom(Name) ->
-% encode_null(Val).
-
-decode_null(Bytes) ->
- {'NULL',Bytes}.
-
-
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% encode_UTF8String(Val) -> CompleteList
%% Val -> <<utf8encoded binary>>
diff --git a/lib/asn1/src/asn1rt_uper_bin.erl b/lib/asn1/src/asn1rt_uper_bin.erl
index e1f96416a9..9410c3ef90 100644
--- a/lib/asn1/src/asn1rt_uper_bin.erl
+++ b/lib/asn1/src/asn1rt_uper_bin.erl
@@ -25,21 +25,20 @@
%%-compile(export_all).
- -export([setext/1, fixoptionals/3,
+-export([decode_fragmented/3]).
+-export([setext/1, fixoptionals/3,
fixextensions/2,
- getext/1, getextension/2, skipextensions/3, getbit/1, getchoice/3 ]).
- -export([getoptionals2/2, set_choice/3, encode_integer/2, encode_integer/3 ]).
- -export([decode_integer/2, decode_integer/3, encode_small_number/1, encode_boolean/1,
- decode_boolean/1, encode_length/2, decode_length/1, decode_length/2,
- encode_small_length/1, decode_small_length/1,
+ skipextensions/3, getbit/1, getchoice/3 ]).
+-export([set_choice/3, encode_integer/2, encode_integer/3]).
+-export([encode_small_number/1, encode_boolean/1,
+ encode_length/2,
+ encode_small_length/1,
decode_compact_bit_string/3]).
- -export([decode_enumerated/3,
- encode_bit_string/3, decode_bit_string/3 ]).
- -export([encode_octet_string/2, decode_octet_string/2,
- encode_null/1, decode_null/1,
- encode_relative_oid/1, decode_relative_oid/1,
+-export([encode_bit_string/3, decode_bit_string/3 ]).
+-export([encode_octet_string/2,
+ encode_relative_oid/1, decode_relative_oid/1,
encode_object_identifier/1, decode_object_identifier/1,
- encode_real/1, decode_real/1,
+ encode_real/1, decode_real/1,
complete/1, complete_NFP/1]).
@@ -99,16 +98,6 @@ fixoptionals([Pos|Ot],Val,Acc) ->
end.
-getext(Bytes) when is_bitstring(Bytes) ->
- getbit(Bytes).
-
-getextension(0, Bytes) ->
- {{},Bytes};
-getextension(1, Bytes) ->
- {Len,Bytes2} = decode_small_length(Bytes),
- {Blist, Bytes3} = getbits_as_list(Len,Bytes2),
- {list_to_tuple(Blist),Bytes3}.
-
fixextensions({ext,ExtPos,ExtNum},Val) ->
case fixextensions(ExtPos,ExtNum+ExtPos,Val,0) of
0 -> [];
@@ -151,11 +140,6 @@ getchoice(Bytes,NumChoices,0) ->
decode_constrained_number(Bytes,{0,NumChoices-1}).
-%%%%%%%%%%%%%%%
-getoptionals2(Bytes,NumOpt) ->
- getbits(Bytes,NumOpt).
-
-
%% getbits_as_binary(Num,Bytes) -> {{Unused,BinBits},RestBytes},
%% Num = integer(),
%% Bytes = list() | tuple(),
@@ -275,33 +259,6 @@ decode_fragmented_bits(<<0:1,Len:7,BitStr/bitstring>>,C,Acc) ->
exit({error,{asn1,{illegal_value,C,ResBitStr}}})
end.
-
-decode_fragmented_octets({0,Bin},C) ->
- decode_fragmented_octets(Bin,C,[]).
-
-decode_fragmented_octets(<<3:2,Len:6,BitStr/bitstring>>,C,Acc) ->
- FragLen = Len * ?'16K',
- <<Value:FragLen/binary,Rest/bitstring>> = BitStr,
- decode_fragmented_octets(Rest,C,[Value|Acc]);
-decode_fragmented_octets(<<0:1,0:7,Bin/bitstring>>,C,Acc) ->
- Octets = list_to_binary(lists:reverse(Acc)),
- case C of
- Int when is_integer(Int), C == size(Octets) ->
- {Octets,Bin};
- Int when is_integer(Int) ->
- exit({error,{asn1,{illegal_value,C,Octets}}})
- end;
-decode_fragmented_octets(<<0:1,Len:7,BitStr/bitstring>>,C,Acc) ->
- <<Value:Len/binary-unit:8,BitStr2/binary>> = BitStr,
- BinOctets = list_to_binary(lists:reverse([Value|Acc])),
- case C of
- Int when is_integer(Int),size(BinOctets) == Int ->
- {BinOctets,BitStr2};
- Int when is_integer(Int) ->
- exit({error,{asn1,{illegal_value,C,BinOctets}}})
- end.
-
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% encode_open_type(Constraint, Value) -> CompleteList
@@ -384,47 +341,6 @@ encode_integer1(C, Val) ->
exit({error,{asn1,{illegal_value,VR,Val}}})
end.
-decode_integer(Buffer,Range,NamedNumberList) ->
- {Val,Buffer2} = decode_integer(Buffer,Range),
- case lists:keysearch(Val,2,NamedNumberList) of
- {value,{NewVal,_}} -> {NewVal,Buffer2};
- _ -> {Val,Buffer2}
- end.
-
-decode_integer(Buffer,[{Rc,_Ec}]) when is_tuple(Rc) ->
- {Ext,Buffer2} = getext(Buffer),
- case Ext of
- 0 -> decode_integer(Buffer2,[Rc]); %% Value in root of constraint
- 1 -> decode_unconstrained_number(Buffer2)
- end;
-decode_integer(Buffer,undefined) ->
- decode_unconstrained_number(Buffer);
-decode_integer(Buffer,C) ->
- case get_constraint(C,'SingleValue') of
- V when is_integer(V) ->
- {V,Buffer};
- V when is_list(V) ->
- {Val,Buffer2} = decode_integer1(Buffer,C),
- case lists:member(Val,V) of
- true ->
- {Val,Buffer2};
- _ ->
- exit({error,{asn1,{illegal_value,Val}}})
- end;
- _ ->
- decode_integer1(Buffer,C)
- end.
-
-decode_integer1(Buffer,C) ->
- case VR = get_constraint(C,'ValueRange') of
- no ->
- decode_unconstrained_number(Buffer);
- {Lb, 'MAX'} ->
- decode_semi_constrained_number(Buffer,Lb);
- {_,_} ->
- decode_constrained_number(Buffer,VR)
- end.
-
%% X.691:10.6 Encoding of a normally small non-negative whole number
%% Use this for encoding of CHOICE index if there is an extension marker in
%% the CHOICE
@@ -441,7 +357,7 @@ decode_small_number(Bytes) ->
0 ->
getbits(Bytes2,6);
1 ->
- decode_semi_constrained_number(Bytes2,0)
+ decode_semi_constrained_number(Bytes2)
end.
%% X.691:10.7 Encoding of a semi-constrained whole number
@@ -465,12 +381,10 @@ encode_semi_constrained_number(Lb,Val) ->
[encode_length(undefined,Size),Bin]
end.
-decode_semi_constrained_number(Bytes,{Lb,_}) ->
- decode_semi_constrained_number(Bytes,Lb);
-decode_semi_constrained_number(Bytes,Lb) ->
+decode_semi_constrained_number(Bytes) ->
{Len,Bytes2} = decode_length(Bytes,undefined),
{V,Bytes3} = getoctets(Bytes2,Len),
- {V+Lb,Bytes3}.
+ {V,Bytes3}.
encode_constrained_number(Range,{Name,Val}) when is_atom(Name) ->
encode_constrained_number(Range,Val);
@@ -552,23 +466,6 @@ enint(-1, [B1|T]) when B1 > 127 ->
enint(N, Acc) ->
enint(N bsr 8, [N band 16#ff|Acc]).
-decode_unconstrained_number(Bytes) ->
- {Len,Bytes2} = decode_length(Bytes,undefined),
- {Ints,Bytes3} = getoctets_as_bin(Bytes2,Len),
- {dec_integer(Ints),Bytes3}.
-
-dec_integer(Bin = <<0:1,_:7,_/bitstring>>) ->
- decpint(Bin);
-dec_integer(<<_:1,B:7,BitStr/bitstring>>) ->
- Size = bit_size(BitStr),
- <<I:Size>> = BitStr,
- (-128 + B) bsl bit_size(BitStr) bor I.
-
-decpint(Bin) ->
- Size = bit_size(Bin),
- <<Int:Size>> = Bin,
- Int.
-
%% X.691:10.9 Encoding of a length determinant
%%encode_small_length(undefined,Len) -> % null means no UpperBound
@@ -583,7 +480,7 @@ encode_length(undefined,Len) -> % un-constrained
Len < 16384 ->
<<2:2,Len:14>>;
true -> % should be able to endode length >= 16384
- exit({error,{asn1,{encode_length,{nyi,above_16k}}}})
+ error({error,{asn1,{encode_length,{nyi,above_16k}}}})
end;
encode_length({0,'MAX'},Len) ->
@@ -609,18 +506,6 @@ encode_small_length(Len) ->
[<<1:1>>,encode_length(undefined,Len)].
-decode_small_length(Buffer) ->
- case getbit(Buffer) of
- {0,Remain} ->
- {Bits,Remain2} = getbits(Remain,6),
- {Bits+1,Remain2};
- {1,Remain} ->
- decode_length(Remain,undefined)
- end.
-
-decode_length(Buffer) ->
- decode_length(Buffer,undefined).
-
%% un-constrained
decode_length(<<0:1,Oct:7,Rest/bitstring>>,undefined) ->
{Oct,Rest};
@@ -663,38 +548,6 @@ encode_boolean({Name,Val}) when is_atom(Name) ->
encode_boolean(Val) ->
exit({error,{asn1,{encode_boolean,Val}}}).
-decode_boolean(Buffer) -> %when record(Buffer,buffer)
- case getbit(Buffer) of
- {1,Remain} -> {true,Remain};
- {0,Remain} -> {false,Remain}
- end.
-
-
-%% ENUMERATED with extension marker
-decode_enumerated(Buffer,C,{Ntup1,Ntup2}) when is_tuple(Ntup1), is_tuple(Ntup2) ->
- {Ext,Buffer2} = getext(Buffer),
- case Ext of
- 0 -> % not an extension value
- {Val,Buffer3} = decode_integer(Buffer2,C),
- case catch (element(Val+1,Ntup1)) of
- NewVal when is_atom(NewVal) -> {NewVal,Buffer3};
- _Error -> exit({error,{asn1,{decode_enumerated,{Val,[Ntup1,Ntup2]}}}})
- end;
- 1 -> % this an extension value
- {Val,Buffer3} = decode_small_number(Buffer2),
- case catch (element(Val+1,Ntup2)) of
- NewVal when is_atom(NewVal) -> {NewVal,Buffer3};
- _ -> {{asn1_enum,Val},Buffer3}
- end
- end;
-
-decode_enumerated(Buffer,C,NamedNumberTup) when is_tuple(NamedNumberTup) ->
- {Val,Buffer2} = decode_integer(Buffer,C),
- case catch (element(Val+1,NamedNumberTup)) of
- NewVal when is_atom(NewVal) -> {NewVal,Buffer2};
- _Error -> exit({error,{asn1,{decode_enumerated,{Val,NamedNumberTup}}}})
- end.
-
%%============================================================================
%%============================================================================
@@ -1053,36 +906,71 @@ encode_octet_string(C,Val) ->
list_to_binary(Val);
2 ->
list_to_binary(Val);
- Sv when Sv =<65535, Sv == length(Val) -> % fixed length
- list_to_binary(Val);
- VR = {_,_} ->
- [encode_length(VR,length(Val)),list_to_binary(Val)];
+ {_,_}=VR ->
+ try
+ [encode_length(VR, length(Val)),list_to_binary(Val)]
+ catch
+ error:{error,{asn1,{encode_length,_}}} ->
+ encode_fragmented_octet_string(Val)
+ end;
+ Sv when is_integer(Sv), Sv =:= length(Val) -> % fixed length
+ if
+ Sv =< 65535 ->
+ list_to_binary(Val);
+ true ->
+ encode_fragmented_octet_string(Val)
+ end;
Sv when is_list(Sv) ->
- [encode_length({hd(Sv),lists:max(Sv)},length(Val)),list_to_binary(Val)];
+ try
+ [encode_length({hd(Sv),lists:max(Sv)},
+ length(Val)),list_to_binary(Val)]
+ catch
+ error:{error,{asn1,{encode_length,_}}} ->
+ encode_fragmented_octet_string(Val)
+ end;
no ->
- [encode_length(undefined,length(Val)),list_to_binary(Val)]
+ try
+ [encode_length(undefined, length(Val)),list_to_binary(Val)]
+ catch
+ error:{error,{asn1,{encode_length,_}}} ->
+ encode_fragmented_octet_string(Val)
+ end
end.
-decode_octet_string(Bytes,C) ->
- decode_octet_string1(Bytes,get_constraint(C,'SizeConstraint')).
-decode_octet_string1(<<B1,Bytes/bitstring>>,1) ->
- {[B1],Bytes};
-decode_octet_string1(<<B1,B2,Bytes/bitstring>>,2) ->
- {[B1,B2],Bytes};
-decode_octet_string1(Bytes,Sv) when is_integer(Sv),Sv=<65535 ->
- getoctets_as_list(Bytes,Sv);
-decode_octet_string1(Bytes,Sv) when is_integer(Sv) ->
- decode_fragmented_octets(Bytes,Sv);
-decode_octet_string1(Bytes,{Lb,Ub}) ->
- {Len,Bytes2} = decode_length(Bytes,{Lb,Ub}),
- getoctets_as_list(Bytes2,Len);
-decode_octet_string1(Bytes,Sv) when is_list(Sv) ->
- {Len,Bytes2} = decode_length(Bytes,{hd(Sv),lists:max(Sv)}),
- getoctets_as_list(Bytes2,Len);
-decode_octet_string1(Bytes,no) ->
- {Len,Bytes2} = decode_length(Bytes,undefined),
- getoctets_as_list(Bytes2,Len).
-
+encode_fragmented_octet_string(Val) ->
+ Bin = list_to_binary(Val),
+ efos_1(Bin).
+
+efos_1(<<B:16#10000/binary,T/binary>>) ->
+ [<<3:2,4:6>>,B|efos_1(T)];
+efos_1(<<B:16#C000/binary,T/binary>>) ->
+ [<<3:2,3:6>>,B|efos_1(T)];
+efos_1(<<B:16#8000/binary,T/binary>>) ->
+ [<<3:2,2:6>>,B|efos_1(T)];
+efos_1(<<B:16#4000/binary,T/binary>>) ->
+ [<<3:2,1:6>>,B|efos_1(T)];
+efos_1(<<B/bitstring>>) ->
+ Len = byte_size(B),
+ [encode_length(undefined, Len),B].
+
+decode_fragmented(SegSz0, Buf0, Unit) ->
+ SegSz = SegSz0 * Unit * ?'16K',
+ <<Res:SegSz/bitstring,Buf/bitstring>> = Buf0,
+ decode_fragmented_1(Buf, Unit, Res).
+
+decode_fragmented_1(<<0:1,N:7,Buf0/bitstring>>, Unit, Res) ->
+ Sz = N*Unit,
+ <<S:Sz/bitstring,Buf/bitstring>> = Buf0,
+ {<<Res/bitstring,S/bitstring>>,Buf};
+decode_fragmented_1(<<1:1,0:1,N:14,Buf0/bitstring>>, Unit, Res) ->
+ Sz = N*Unit,
+ <<S:Sz/bitstring,Buf/bitstring>> = Buf0,
+ {<<Res/bitstring,S/bitstring>>,Buf};
+decode_fragmented_1(<<1:1,1:1,SegSz0:6,Buf0/bitstring>>, Unit, Res0) ->
+ SegSz = SegSz0 * Unit * ?'16K',
+ <<Frag:SegSz/bitstring,Buf/bitstring>> = Buf0,
+ Res = <<Res0/bitstring,Frag/bitstring>>,
+ decode_fragmented_1(Buf, Unit, Res).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1427,12 +1315,6 @@ decode_UTF8String(Bytes) ->
getoctets_as_bin(Bytes2,Len).
- % X.691:17
-encode_null(_) -> []. % encodes to nothing
-
-decode_null(Bytes) ->
- {'NULL',Bytes}.
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% encode_object_identifier(Val) -> CompleteList
%% encode_object_identifier({Name,Val}) -> CompleteList
diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl
index fd5ea15323..38ec72c473 100644
--- a/lib/asn1/test/asn1_SUITE.erl
+++ b/lib/asn1/test/asn1_SUITE.erl
@@ -631,7 +631,7 @@ parse(Config) ->
[asn1_test_lib:compile(M, Config, [abs]) || M <- test_modules()].
per(Config) ->
- test(Config, fun per/3, [per]).
+ test(Config, fun per/3, [per,uper]).
per(Config, Rule, Opts) ->
[module_test(M, Config, Rule, Opts) || M <- per_modules()].
diff --git a/lib/asn1/test/asn1_SUITE_data/PrimStrings.asn1 b/lib/asn1/test/asn1_SUITE_data/PrimStrings.asn1
index d287840f30..7cb47e9792 100644
--- a/lib/asn1/test/asn1_SUITE_data/PrimStrings.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/PrimStrings.asn1
@@ -55,6 +55,19 @@ BS1024 ::= BIT STRING (SIZE (1024))
OsExpCon ::= [60] EXPLICIT OCTET STRING
OsExpPri ::= [PRIVATE 61] EXPLICIT OCTET STRING
OsExpApp ::= [APPLICATION 62] EXPLICIT OCTET STRING
+ OsFrag ::= OCTET STRING (SIZE (0..100000))
+ FixedOs65536 ::= OCTET STRING (SIZE (65536))
+ FixedOs65537 ::= OCTET STRING (SIZE (65537))
+
+ OsAlignment ::= SEQUENCE {
+ b1 BOOLEAN,
+ s1 Os,
+ b2 BOOLEAN,
+ s2 OsFrag,
+ b3 BOOLEAN,
+ s3 FixedOs65536,
+ i INTEGER (0..63)
+ }
Ns ::= NumericString
NsCon ::= [70] NumericString
diff --git a/lib/asn1/test/asn1_app_test.erl b/lib/asn1/test/asn1_app_test.erl
index 2c31c3259d..9dbe1b50e0 100644
--- a/lib/asn1/test/asn1_app_test.erl
+++ b/lib/asn1/test/asn1_app_test.erl
@@ -138,7 +138,8 @@ check_asn1ct_modules(Extra) ->
asn1ct_name,asn1ct_constructed_per,asn1ct_constructed_ber,
asn1ct_gen_ber,asn1ct_constructed_ber_bin_v2,
asn1ct_gen_ber_bin_v2,asn1ct_value,
- asn1ct_tok,asn1ct_parser2,asn1ct_table],
+ asn1ct_tok,asn1ct_parser2,asn1ct_table,
+ asn1ct_imm],
case Extra -- ASN1CTMods of
[] ->
ok;
diff --git a/lib/asn1/test/testPrimStrings.erl b/lib/asn1/test/testPrimStrings.erl
index b1c5172b95..9a640a2cb1 100644
--- a/lib/asn1/test/testPrimStrings.erl
+++ b/lib/asn1/test/testPrimStrings.erl
@@ -338,69 +338,24 @@ octet_string(Rules) ->
ok
end,
+ roundtrip('Os', [47,23,99,255,1]),
+ roundtrip('OsCon', [47,23,99,255,1]),
+ roundtrip('OsPri', [47,23,99,255,1]),
+ roundtrip('OsApp', [47,23,99,255,1]),
-
- ?line {ok,Bytes4} =
- asn1_wrapper:encode('PrimStrings','Os',[47,23,99,255,1]),
- ?line {ok,[47,23,99,255,1]} = asn1_wrapper:decode('PrimStrings','Os',lists:flatten(Bytes4)),
-
- ?line {ok,Bytes5} =
- asn1_wrapper:encode('PrimStrings','OsCon',[47,23,99,255,1]),
- ?line {ok,[47,23,99,255,1]} = asn1_wrapper:decode('PrimStrings','OsCon',lists:flatten(Bytes5)),
-
- ?line {ok,Bytes6} =
- asn1_wrapper:encode('PrimStrings','OsPri',[47,23,99,255,1]),
- ?line {ok,[47,23,99,255,1]} = asn1_wrapper:decode('PrimStrings','OsPri',lists:flatten(Bytes6)),
-
- ?line {ok,Bytes7} =
- asn1_wrapper:encode('PrimStrings','OsApp',[47,23,99,255,1]),
- ?line {ok,[47,23,99,255,1]} = asn1_wrapper:decode('PrimStrings','OsApp',lists:flatten(Bytes7)),
-
- ?line {ok,Bytes8} =
- asn1_wrapper:encode('PrimStrings','OsExpCon',[47,23,99,255,1]),
- ?line {ok,[47,23,99,255,1]} = asn1_wrapper:decode('PrimStrings','OsExpCon',lists:flatten(Bytes8)),
-
- ?line {ok,Bytes9} =
- asn1_wrapper:encode('PrimStrings','OsExpPri',[47,23,99,255,1]),
- ?line {ok,[47,23,99,255,1]} = asn1_wrapper:decode('PrimStrings','OsExpPri',lists:flatten(Bytes9)),
-
- ?line {ok,Bytes10} =
- asn1_wrapper:encode('PrimStrings','OsExpApp',[47,23,99,255,1]),
- ?line {ok,[47,23,99,255,1]} = asn1_wrapper:decode('PrimStrings','OsExpApp',lists:flatten(Bytes10)),
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('PrimStrings','Os',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','Os',lists:flatten(Bytes11)),
-
- ?line {ok,Bytes12} =
- asn1_wrapper:encode('PrimStrings','OsApp',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','OsApp',lists:flatten(Bytes12)),
-
- ?line {ok,Bytes13} =
- asn1_wrapper:encode('PrimStrings','OsExpApp',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','OsExpApp',lists:flatten(Bytes13)),
-
-
-
-
-
+ roundtrip('OsExpCon', [47,23,99,255,1]),
+ roundtrip('OsExpPri', [47,23,99,255,1]),
+ roundtrip('OsExpApp', [47,23,99,255,1]),
+ roundtrip('Os', []),
+ roundtrip('OsApp', []),
+ roundtrip('OsExpApp',[]),
OsR = "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('PrimStrings','Os',OsR),
- ?line {ok,Os1} = asn1_wrapper:decode('PrimStrings','Os',lists:flatten(Bytes21)),
- ?line Os1 = OsR,
- ?line {ok,Bytes22} =
- asn1_wrapper:encode('PrimStrings','OsCon',OsR),
- ?line {ok,Os2} = asn1_wrapper:decode('PrimStrings','OsCon',lists:flatten(Bytes22)),
- ?line Os2 = OsR,
- ?line {ok,Bytes23} =
- asn1_wrapper:encode('PrimStrings','OsExpApp',OsR),
- ?line {ok,Os3} = asn1_wrapper:decode('PrimStrings','OsExpApp',lists:flatten(Bytes23)),
- ?line Os3 = OsR,
-
+ roundtrip('Os', OsR),
+ roundtrip('OsCon', OsR),
+ roundtrip('OsExpApp', OsR),
?line case asn1_wrapper:erule(Rules) of
@@ -416,21 +371,85 @@ octet_string(Rules) ->
ok
end,
-
+ fragmented_octet_string(Rules),
ok.
+fragmented_octet_string(Erules) ->
+ K16 = 1 bsl 14,
+ K32 = K16 + K16,
+ K48 = K32 + K16,
+ K64 = K48 + K16,
+ Lens = [0,1,14,15,16,17,127,128,
+ K16-1,K16,K16+1,K16+(1 bsl 7)-1,K16+(1 bsl 7),K16+(1 bsl 7)+1,
+ K32-1,K32,K32+1,K32+(1 bsl 7)-1,K32+(1 bsl 7),K32+(1 bsl 7)+1,
+ K48-1,K48,K48+1,K48+(1 bsl 7)-1,K48+(1 bsl 7),K48+(1 bsl 7)+1,
+ K64-1,K64,K64+1,K64+(1 bsl 7)-1,K64+(1 bsl 7),K64+(1 bsl 7)+1,
+ K64+K16-1,K64+K16,K64+K16+1],
+ Types = ['Os','OsFrag'],
+ [fragmented_octet_string(Erules, Types, L) || L <- Lens],
+ fragmented_octet_string(Erules, ['FixedOs65536'], 65536),
+ fragmented_octet_string(Erules, ['FixedOs65537'], 65537),
+
+ %% Make sure that octet alignment works.
+ roundtrip('OsAlignment',
+ {'OsAlignment',false,make_value(70000),true,make_value(66666),
+ false,make_value(65536),42}),
+ roundtrip('OsAlignment',
+ {'OsAlignment',false,make_value(0),true,make_value(0),
+ false,make_value(65536),42}),
+ ok.
+
+fragmented_octet_string(Erules, Types, L) ->
+ Value = make_value(L),
+ [begin
+ Encoded = enc_frag(Erules, Type, Value),
+ {ok,Value} = 'PrimStrings':decode(Type, Encoded)
+ end || Type <- Types],
+ ok.
+enc_frag(Erules, Type, Value) ->
+ {ok,Encoded} = 'PrimStrings':encode(Type, Value),
+ case Erules of
+ ber ->
+ Encoded;
+ _ ->
+ %% Validate encoding with our own encoder.
+ Encoded = enc_frag_1(<<>>, list_to_binary(Value))
+ end.
+
+enc_frag_1(Res, Bin0) ->
+ K16 = 1 bsl 14,
+ Sz = byte_size(Bin0),
+ if
+ Sz >= K16 ->
+ F = min(Sz div K16, 4),
+ FragSize = F * K16,
+ <<Frag:FragSize/binary-unit:8,Bin/binary>> = Bin0,
+ enc_frag_1(<<Res/binary,3:2,F:6,Frag/binary>>, Bin);
+ Sz >= 128 ->
+ <<Res/binary,1:1,0:1,Sz:14,Bin0/binary>>;
+ true ->
+ <<Res/binary,0:1,Sz:7,Bin0/binary>>
+ end.
+
+make_value(L) ->
+ make_value(L, 0, []).
+
+make_value(0, _, Acc) ->
+ Acc;
+make_value(N, Byte, Acc) when Byte =< 255 ->
+ make_value(N-1, Byte+7, [Byte|Acc]);
+make_value(N, Byte, Acc) ->
+ make_value(N, Byte band 16#FF, Acc).
-
numeric_string(Rules) ->
%%==========================================================
%% Ns ::= NumericString
%%==========================================================
- ?line {ok,BytesNs2} = asn1_wrapper:encode('PrimStrings','Ns',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','Ns',lists:flatten(BytesNs2)),
+ roundtrip('Ns', []),
?line case asn1_wrapper:erule(Rules) of
ber ->
@@ -455,10 +474,7 @@ numeric_string(Rules) ->
%% NsCon ::= [70] NumericString
%%==========================================================
- ?line {ok,BytesNs12} = asn1_wrapper:encode('PrimStrings','NsCon',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','NsCon',lists:flatten(BytesNs12)),
-
-
+ roundtrip('NsCon', []),
?line case asn1_wrapper:erule(Rules) of
ber ->
@@ -482,10 +498,7 @@ numeric_string(Rules) ->
%% NsExpCon ::= [71] EXPLICIT NumericString
%%==========================================================
- ?line {ok,BytesNs22} = asn1_wrapper:encode('PrimStrings','NsExpCon',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','NsExpCon',lists:flatten(BytesNs22)),
-
-
+ roundtrip('NsExpCon', []),
?line case asn1_wrapper:erule(Rules) of
ber ->
@@ -507,9 +520,6 @@ numeric_string(Rules) ->
ok.
-
-
-
other_strings(_Rules) ->
@@ -517,49 +527,27 @@ other_strings(_Rules) ->
%% Ps ::= PrintableString
%%==========================================================
- ?line {ok,BytesPs1} = asn1_wrapper:encode('PrimStrings','Ps',[47,23,99,75,47]),
- ?line {ok,[47,23,99,75,47]} =
- asn1_wrapper:decode('PrimStrings','Ps',lists:flatten(BytesPs1)),
-
- ?line {ok,BytesPs2} = asn1_wrapper:encode('PrimStrings','Ps',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','Ps',lists:flatten(BytesPs2)),
-
+ roundtrip('Ps', [47,23,99,75,47]),
+ roundtrip('Ps', []),
%%==========================================================
%% Vis ::= VisibleString
%%==========================================================
- ?line {ok,BytesVis1} = asn1_wrapper:encode('PrimStrings','Vis',[47,23,99,75,47]),
- ?line {ok,[47,23,99,75,47]} =
- asn1_wrapper:decode('PrimStrings','Vis',lists:flatten(BytesVis1)),
-
- ?line {ok,BytesVis2} = asn1_wrapper:encode('PrimStrings','Vis',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','Vis',lists:flatten(BytesVis2)),
-
+ roundtrip('Vis', [47,23,99,75,47]),
+ roundtrip('Vis', []),
%%==========================================================
%% IA5 ::= IA5String
%%==========================================================
- ?line {ok,BytesIA51} = asn1_wrapper:encode('PrimStrings','IA5',[47,23,99,75,47]),
- ?line {ok,[47,23,99,75,47]} =
- asn1_wrapper:decode('PrimStrings','IA5',lists:flatten(BytesIA51)),
-
- ?line {ok,BytesIA52} = asn1_wrapper:encode('PrimStrings','IA5',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','IA5',lists:flatten(BytesIA52)),
+ roundtrip('IA5', [47,23,99,75,47]),
+ roundtrip('IA5', []),
-
IA5_1 = "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
-
- ?line {ok,BytesIA53} = asn1_wrapper:encode('PrimStrings','IA5',IA5_1),
- ?line {ok,IA5_1r} = asn1_wrapper:decode('PrimStrings','IA5',lists:flatten(BytesIA53)),
- ?line IA5_1 = IA5_1r,
-
-
-
-
+ roundtrip('IA5', IA5_1),
ok.
@@ -568,94 +556,60 @@ more_strings(_Rules) ->
%% Ts ::= TeletexString
%%==========================================================
- ?line {ok,BytesTs1} = asn1_wrapper:encode('PrimStrings','Ts',[47,23,99,75,47]),
- ?line {ok,[47,23,99,75,47]} =
- asn1_wrapper:decode('PrimStrings','Ts',lists:flatten(BytesTs1)),
-
- ?line {ok,BytesTs2} = asn1_wrapper:encode('PrimStrings','Ts',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','Ts',lists:flatten(BytesTs2)),
-
+ roundtrip('Ts', [47,23,99,75,47]),
+ roundtrip('Ts', []),
%%==========================================================
%% Vxs ::= VideotexString
%%==========================================================
- ?line {ok,BytesVxs1} = asn1_wrapper:encode('PrimStrings','Vxs',[47,23,99,75,47]),
- ?line {ok,[47,23,99,75,47]} =
- asn1_wrapper:decode('PrimStrings','Vxs',lists:flatten(BytesVxs1)),
-
- ?line {ok,BytesVxs2} = asn1_wrapper:encode('PrimStrings','Vxs',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','Vxs',lists:flatten(BytesVxs2)),
-
+ roundtrip('Vxs', [47,23,99,75,47]),
+ roundtrip('Vxs', []),
%%==========================================================
%% Grs ::= GraphicString
%%==========================================================
- ?line {ok,BytesGrs1} = asn1_wrapper:encode('PrimStrings','Grs',[47,23,99,75,47]),
- ?line {ok,[47,23,99,75,47]} =
- asn1_wrapper:decode('PrimStrings','Grs',lists:flatten(BytesGrs1)),
-
- ?line {ok,BytesGrs2} = asn1_wrapper:encode('PrimStrings','Grs',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','Grs',lists:flatten(BytesGrs2)),
+ roundtrip('Grs',[47,23,99,75,47]),
+ roundtrip('Grs', []),
%%==========================================================
%% ODesc ::= ObjectDescriptor, test case for OTP-4161
%%==========================================================
- ?line {ok,BytesODesc1} = asn1_wrapper:encode('PrimStrings','ODesc',[79,98,106,101,99,116,68,101,115,99,114,105,112,116,111,114]),
- ?line {ok,[79,98,106,101,99,116,68,101,115,99,114,105,112,116,111,114]} =
- asn1_wrapper:decode('PrimStrings','ODesc',lists:flatten(BytesODesc1)),
-
- ?line {ok,BytesODesc2} = asn1_wrapper:encode('PrimStrings','ODesc',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','ODesc',lists:flatten(BytesODesc2)),
+ roundtrip('ODesc', [79,98,106,101,99,116,68,101,115,99,114,
+ 105,112,116,111,114]),
+ roundtrip('ODesc', []),
%%==========================================================
%% Ges ::= GeneralString
%%==========================================================
- ?line {ok,BytesGes1} = asn1_wrapper:encode('PrimStrings','Ges',[47,23,99,75,47]),
- ?line {ok,[47,23,99,75,47]} =
- asn1_wrapper:decode('PrimStrings','Ges',lists:flatten(BytesGes1)),
-
- ?line {ok,BytesGes2} = asn1_wrapper:encode('PrimStrings','Ges',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','Ges',lists:flatten(BytesGes2)),
-
- ok.
+ roundtrip('Ges', [47,23,99,75,47]),
+ roundtrip('Ges', []),
+ ok.
universal_string(Rules) ->
-
%%==========================================================
%% Us ::= UniversalString
%%==========================================================
- ?line {ok,Bytes1} =
- asn1_wrapper:encode('PrimStrings','Us',[{47,23,99,47},{0,0,55,66}]),
- ?line {ok,[{47,23,99,47},{0,0,55,66}]} =
- asn1_wrapper:decode('PrimStrings','Us',lists:flatten(Bytes1)),
+ roundtrip('Us', [{47,23,99,47},{0,0,55,66}]),
?line {ok,Bytes2} =
asn1_wrapper:encode('PrimStrings','Us',[{47,23,99,255},{0,0,0,201}]),
?line {ok,[{47,23,99,255},201]} =
asn1_wrapper:decode('PrimStrings','Us',lists:flatten(Bytes2)),
- ?line {ok,Bytes3} = asn1_wrapper:encode('PrimStrings','Us',"Universal String"),
- ?line {ok,"Universal String"} =
- asn1_wrapper:decode('PrimStrings','Us',lists:flatten(Bytes3)),
-
- ?line {ok,Bytes4} = asn1_wrapper:encode('PrimStrings','Us',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','Us',lists:flatten(Bytes4)),
-
- ?line {ok,Bytes5} = asn1_wrapper:encode('PrimStrings','Us',[{47,23,99,47}]),
- ?line {ok,[{47,23,99,47}]} =
- asn1_wrapper:decode('PrimStrings','Us',lists:flatten(Bytes5)),
-
+ roundtrip('Us', "Universal String"),
+ roundtrip('Us', []),
+ roundtrip('Us', [{47,23,99,47}]),
?line case asn1_wrapper:erule(Rules) of
ber ->
@@ -670,32 +624,22 @@ universal_string(Rules) ->
Us1 = "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
- ?line {ok,Bytes15} = asn1_wrapper:encode('PrimStrings','IA5',Us1),
- ?line {ok,Us1r} = asn1_wrapper:decode('PrimStrings','IA5',lists:flatten(Bytes15)),
- ?line Us1 = Us1r,
-
+ roundtrip('IA5', Us1),
%%==========================================================
%% UsCon ::= [70] UniversalString
%%==========================================================
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('PrimStrings','UsCon',[{47,23,99,255},{0,0,2,201}]),
- ?line {ok,[{47,23,99,255},{0,0,2,201}]} =
- asn1_wrapper:decode('PrimStrings','UsCon',lists:flatten(Bytes11)),
+ roundtrip('UsCon', [{47,23,99,255},{0,0,2,201}]),
?line {ok,Bytes12} =
asn1_wrapper:encode('PrimStrings','UsCon',[{47,23,99,255},{0,0,0,201}]),
?line {ok,[{47,23,99,255},201]} =
asn1_wrapper:decode('PrimStrings','UsCon',lists:flatten(Bytes12)),
- ?line {ok,Bytes13} = asn1_wrapper:encode('PrimStrings','UsCon',"Universal String"),
- ?line {ok,"Universal String"} =
- asn1_wrapper:decode('PrimStrings','UsCon',lists:flatten(Bytes13)),
-
- ?line {ok,Bytes14} = asn1_wrapper:encode('PrimStrings','UsCon',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','UsCon',lists:flatten(Bytes14)),
+ roundtrip('UsCon', "Universal String"),
+ roundtrip('UsCon', []),
?line case asn1_wrapper:erule(Rules) of
ber ->
@@ -712,25 +656,15 @@ universal_string(Rules) ->
%% UsExpCon ::= [71] EXPLICIT UniversalString
%%==========================================================
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('PrimStrings','UsExpCon',[{47,23,99,255},{0,0,2,201}]),
- ?line {ok,[{47,23,99,255},{0,0,2,201}]} =
- asn1_wrapper:decode('PrimStrings','UsExpCon',lists:flatten(Bytes21)),
+ roundtrip('UsExpCon', [{47,23,99,255},{0,0,2,201}]),
?line {ok,Bytes22} =
asn1_wrapper:encode('PrimStrings','UsExpCon',[{47,23,99,255},{0,0,0,201}]),
?line {ok,[{47,23,99,255},201]} =
asn1_wrapper:decode('PrimStrings','UsExpCon',lists:flatten(Bytes22)),
- ?line {ok,Bytes23} =
- asn1_wrapper:encode('PrimStrings','UsExpCon',"Universal String"),
- ?line {ok,"Universal String"} =
- asn1_wrapper:decode('PrimStrings','UsExpCon',lists:flatten(Bytes23)),
-
- ?line {ok,Bytes24} =
- asn1_wrapper:encode('PrimStrings','UsExpCon',[]),
- ?line {ok,[]} =
- asn1_wrapper:decode('PrimStrings','UsExpCon',lists:flatten(Bytes24)),
+ roundtrip('UsExpCon', "Universal String"),
+ roundtrip('UsExpCon', []),
?line case asn1_wrapper:erule(Rules) of
ber ->
@@ -740,12 +674,8 @@ universal_string(Rules) ->
asn1_wrapper:decode('PrimStrings','UsExpCon',lists:flatten([16#BF,16#47,16,60,16#80,28,4,47,23,99,255,28,4,0,0,2,201,0,0]));
_ -> ok
end,
-
-
-ok.
-
-
+ ok.
bmp_string(_Rules) ->
@@ -754,29 +684,18 @@ bmp_string(_Rules) ->
%% BMP ::= BMPString
%%==========================================================
- ?line {ok,Bytes1} =
- asn1_wrapper:encode('PrimStrings','BMP',[{0,0,99,48},{0,0,2,201}]),
- ?line {ok,[{0,0,99,48},{0,0,2,201}]} =
- asn1_wrapper:decode('PrimStrings','BMP',lists:flatten(Bytes1)),
+ roundtrip('BMP', [{0,0,99,48},{0,0,2,201}]),
?line {ok,Bytes2} =
asn1_wrapper:encode('PrimStrings','BMP',[{0,0,0,48},{0,0,2,201}]),
?line {ok,[48,{0,0,2,201}]} =
asn1_wrapper:decode('PrimStrings','BMP',lists:flatten(Bytes2)),
-
- ?line {ok,Bytes3} = asn1_wrapper:encode('PrimStrings','BMP',"BMP String"),
- ?line {ok,"BMP String"} =
- asn1_wrapper:decode('PrimStrings','BMP',lists:flatten(Bytes3)),
-
- ?line {ok,Bytes4} = asn1_wrapper:encode('PrimStrings','BMP',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','BMP',lists:flatten(Bytes4)),
+ roundtrip('BMP', "BMP String"),
+ roundtrip('BMP', []),
BMP1 = "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
- ?line {ok,Bytes5} = asn1_wrapper:encode('PrimStrings','BMP',BMP1),
- ?line {ok,BMP1r} = asn1_wrapper:decode('PrimStrings','BMP',lists:flatten(Bytes5)),
- ?line BMP1 = BMP1r,
-
+ roundtrip('BMP', BMP1),
ok.
@@ -790,35 +709,17 @@ times(_Rules) ->
%% Gt ::= GeneralizedTime
%%==========================================================
- ?line {ok,Bytes1} = asn1_wrapper:encode('PrimStrings','Gt',"19970923110723.2"),
- ?line {ok,"19970923110723.2"} =
- asn1_wrapper:decode('PrimStrings','Gt',lists:flatten(Bytes1)),
+ roundtrip('Gt', "19970923110723.2"),
+ roundtrip('Gt', "19970923110723.2Z"),
+ roundtrip('Gt', "19970923110723.2-0500"),
- ?line {ok,Bytes2} = asn1_wrapper:encode('PrimStrings','Gt',"19970923110723.2Z"),
- ?line {ok,"19970923110723.2Z"} =
- asn1_wrapper:decode('PrimStrings','Gt',lists:flatten(Bytes2)),
-
- ?line {ok,Bytes3} = asn1_wrapper:encode('PrimStrings','Gt',"19970923110723.2-0500"),
- ?line {ok,"19970923110723.2-0500"} =
- asn1_wrapper:decode('PrimStrings','Gt',lists:flatten(Bytes3)),
-
-
-
-
-
-
%%==========================================================
%% UTC ::= UTCTime
%%==========================================================
- ?line {ok,Bytes11} = asn1_wrapper:encode('PrimStrings','UTC',"9709211107Z"),
- ?line {ok,"9709211107Z"} =
- asn1_wrapper:decode('PrimStrings','UTC',lists:flatten(Bytes11)),
-
- ?line {ok,Bytes12} = asn1_wrapper:encode('PrimStrings','UTC',"9709211107-0500"),
- ?line {ok,"9709211107-0500"} =
- asn1_wrapper:decode('PrimStrings','UTC',lists:flatten(Bytes12)),
+ roundtrip('UTC', "9709211107Z"),
+ roundtrip('UTC', "9709211107-0500"),
ok.
@@ -917,3 +818,8 @@ wrapper_utf8_binary_to_list(L) when is_list(L) ->
asn1rt:utf8_binary_to_list(list_to_binary(L));
wrapper_utf8_binary_to_list(B) ->
asn1rt:utf8_binary_to_list(B).
+
+roundtrip(Type, Value) ->
+ {ok,Encoded} = 'PrimStrings':encode(Type, Value),
+ {ok,Value} = 'PrimStrings':decode(Type, Encoded),
+ ok.