%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2002-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
%%
-module(asn1ct_constructed_ber_bin_v2).
-export([gen_encode_sequence/3]).
-export([gen_decode_sequence/3]).
-export([gen_encode_set/3]).
-export([gen_decode_set/3]).
-export([gen_encode_sof/4]).
-export([gen_decode_sof/4]).
-export([gen_encode_choice/3]).
-export([gen_decode_choice/3]).
-include("asn1_records.hrl").
-import(asn1ct_gen, [emit/1,get_record_name_prefix/1]).
-define(ASN1CT_GEN_BER,asn1ct_gen_ber_bin_v2).
%% the encoding of class of tag bits 8 and 7
-define(UNIVERSAL, 0).
-define(APPLICATION, 16#40).
-define(CONTEXT, 16#80).
-define(PRIVATE, 16#C0).
%% primitive or constructed encoding % bit 6
-define(PRIMITIVE, 0).
-define(CONSTRUCTED, 2#00100000).
%%===============================================================================
%%===============================================================================
%%===============================================================================
%% Encode/decode SEQUENCE (and SET)
%%===============================================================================
%%===============================================================================
%%===============================================================================
gen_encode_sequence(Gen, Typename, #type{}=D) ->
asn1ct_name:start(),
asn1ct_name:new(term),
asn1ct_name:new(bytes),
%% if EXTERNAL type the input value must be transformed to
%% ASN1 1990 format
ValName =
case Typename of
['EXTERNAL'] ->
Tr = case Gen of
#gen{pack=record} -> transform_to_EXTERNAL1990;
#gen{pack=map} -> transform_to_EXTERNAL1990_maps
end,
emit([indent(4),"NewVal = ",
{call,ext,Tr,["Val"]},
com,nl]),
"NewVal";
_ ->
"Val"
end,
{SeqOrSet,TableConsInfo,CompList0} =
case D#type.def of
#'SEQUENCE'{tablecinf=TCI,components=CL} ->
{'SEQUENCE',TCI,CL};
#'SET'{tablecinf=TCI,components=CL} ->
{'SET',TCI,CL}
end,
%% filter away extensionAdditiongroup markers
CompList = filter_complist(CompList0),
Ext = extensible(CompList),
CompList1 = case CompList of
{Rl1,El,Rl2} -> Rl1 ++ El ++ Rl2;
{Rl,El} -> Rl ++ El;
_ -> CompList
end,
enc_match_input(Gen, ValName, CompList1),
EncObj =
case TableConsInfo of
#simpletableattributes{usedclassfield=Used,
uniqueclassfield=Unique} when Used /= Unique ->
false;
%% ObjectSet, name of the object set in constraints
#simpletableattributes{objectsetname=ObjectSetRef,
c_name=AttrN,
c_index=N,
usedclassfield=UniqueFieldName,
uniqueclassfield=UniqueFieldName,
valueindex=ValueIndex} -> %% N is index of attribute that determines constraint
{ObjSetMod,ObjSetName} = ObjectSetRef,
OSDef = asn1_db:dbget(ObjSetMod, ObjSetName),
case (OSDef#typedef.typespec)#'ObjectSet'.gen of
true ->
ObjectEncode =
asn1ct_gen:un_hyphen_var(lists:concat(['Obj',
AttrN])),
emit([ObjectEncode," = ",nl,
" ",{asis,ObjSetMod},":'getenc_",ObjSetName,
"'("]),
ValueMatch = value_match(Gen, ValueIndex,
lists:concat(["Cindex",N])),
emit([indent(35),ValueMatch,"),",nl]),
{AttrN,ObjectEncode};
_ ->
false
end;
_ ->
case D#type.tablecinf of
[{objfun,_}|_] ->
%% when the simpletableattributes was at an outer
%% level and the objfun has been passed through the
%% function call
{"got objfun through args","ObjFun"};
_ ->
false
end
end,
gen_enc_sequence_call(Gen, Typename, CompList1, 1, Ext, EncObj),
emit([nl," BytesSoFar = "]),
case SeqOrSet of
'SET' when (D#type.def)#'SET'.sorted == dynamic ->
asn1ct_func:need({ber,dynamicsort_SET_components,1}),
emit("dynamicsort_SET_components(["),
mkvlist(asn1ct_name:all(encBytes)),
emit(["]),",nl]);
_ ->
emit("["),
mkvlist(asn1ct_name:all(encBytes)),
emit(["],",nl])
end,
emit("LenSoFar = "),
case asn1ct_name:all(encLen) of
[] -> emit("0");
AllLengths ->
mkvplus(AllLengths)
end,
emit([",",nl]),
call(encode_tags, ["TagIn","BytesSoFar","LenSoFar"]),
emit([".",nl]).
enc_match_input(#gen{pack=record}, ValName, CompList) ->
Len = length(CompList),
Vars = [lists:concat(["Cindex",N]) || N <- lists:seq(1, Len)],
RecordName = "_",
emit(["{",lists:join(",", [RecordName|Vars]),"} = ",ValName,com,nl]);
enc_match_input(#gen{pack=map}, ValName, CompList) ->
Len = length(CompList),
Vars = [lists:concat(["Cindex",N]) || N <- lists:seq(1, Len)],
Zipped = lists:zip(CompList, Vars),
M = [[{asis,Name},":=",Var] ||
{#'ComponentType'{prop=mandatory,name=Name},Var} <- Zipped],
case M of
[] ->
ok;
[_|_] ->
emit(["#{",lists:join(",", M),"} = ",ValName,com,nl])
end,
Os0 = [{Name,Var} ||
{#'ComponentType'{prop=Prop,name=Name},Var} <- Zipped,
Prop =/= mandatory],
F = fun({Name,Var}) ->
[Var," = case ",ValName," of\n"
" #{",{asis,Name},":=",Var,"_0} -> ",
Var,"_0;\n"
" _ -> ",atom_to_list(?MISSING_IN_MAP),"\n"
"end"]
end,
emit(lists:join(",\n", [F(E) || E <- Os0]++[[]])).
gen_decode_sequence(Gen, Typename, #type{}=D) ->
asn1ct_name:start(),
asn1ct_name:new(tag),
#'SEQUENCE'{tablecinf=TableConsInfo,components=CList0} = D#type.def,
%% filter away extensionAdditiongroup markers
CList = filter_complist(CList0),
Ext = extensible(CList),
{CompList,CompList2} =
case CList of
{Rl1,El,Rl2} -> {Rl1 ++ El ++ Rl2, CList};
{Rl,El} -> {Rl ++ El, Rl ++ El};
_ -> {CList, CList}
end,
emit([" %%-------------------------------------------------",nl]),
emit([" %% decode tag and length ",nl]),
emit([" %%-------------------------------------------------",nl]),
asn1ct_name:new(tlv),
case CompList of
[] -> % empty sequence
true;
_ ->
emit([{curr,tlv}," = "])
end,
call(match_tags, [{prev,tlv},"TagIn"]),
emit([com,nl]),
asn1ct_name:new(tlv),
asn1ct_name:new(v),
{DecObjInf,ValueIndex} =
case TableConsInfo of
#simpletableattributes{objectsetname=ObjectSetRef,
c_name=AttrN,
usedclassfield=UniqueFieldName,
uniqueclassfield=UniqueFieldName,
valueindex=ValIndex} ->
F = fun(#'ComponentType'{typespec=CT})->
case {asn1ct_gen:get_constraint(CT#type.constraint,componentrelation),CT#type.tablecinf} of
{no,[{objfun,_}|_]} -> true;
_ -> false
end
end,
case lists:any(F,CompList) of
true -> % when component relation constraint establish
%% relation from a component to another components
%% subtype component
{{AttrN,{deep,ObjectSetRef,UniqueFieldName,ValIndex}},
ValIndex};
false ->
{{AttrN,ObjectSetRef},ValIndex}
end;
_ ->
{false,false}
end,
RecordName0 = lists:concat([get_record_name_prefix(Gen),
asn1ct_gen:list2rname(Typename)]),
RecordName = list_to_atom(RecordName0),
case gen_dec_sequence_call(Gen, Typename, CompList2, Ext, DecObjInf) of
no_terms -> % an empty sequence
asn1ct_name:new(rb),
case Gen of
#gen{pack=record} ->
emit([nl,nl,
" {'",RecordName,"'}.",nl,nl]);
#gen{pack=map} ->
emit([nl,nl,
" #{}.",nl,nl])
end;
{LeadingAttrTerm,PostponedDecArgs} ->
emit([nl]),
case {LeadingAttrTerm,PostponedDecArgs} of
{[],[]} ->
ok;
{_,[]} ->
ok;
{[{ObjSetRef,LeadingAttr,Term}],PostponedDecArgs} ->
DecObj = asn1ct_gen:un_hyphen_var(lists:concat(['DecObj',LeadingAttr,Term])),
ValueMatch = value_match(Gen, ValueIndex,Term),
{ObjSetMod,ObjSetName} = ObjSetRef,
emit([DecObj," =",nl,
" ",{asis,ObjSetMod},":'getdec_",ObjSetName,"'(",
ValueMatch,"),",nl]),
gen_dec_postponed_decs(DecObj,PostponedDecArgs)
end,
%% return value as record
case Ext of
{ext,_,_} ->
emit(["case ",{prev,tlv}," of [] -> true; _ -> true end, % ... extra fields skipped",nl]);
_ ->
%% noext | extensible
emit(["case ",{prev,tlv}," of",nl,
"[] -> true;",
"_ -> exit({error,{asn1, {unexpected,",{prev,tlv},
"}}}) % extra fields not allowed",nl,
"end,",nl])
end,
asn1ct_name:new(rb),
gen_dec_pack(Gen, RecordName, Typename, CompList),
emit([".",nl])
end.
gen_dec_pack(Gen, RecordName, Typename, CompList) ->
case Typename of
['EXTERNAL'] ->
dec_external(Gen, RecordName);
_ ->
asn1ct_name:new(res),
gen_dec_do_pack(Gen, RecordName, CompList),
emit([com,nl,
{curr,res}])
end.
dec_external(#gen{pack=record}, RecordName) ->
All = [{var,Term} || Term <- asn1ct_name:all(term)],
Record = [{asis,RecordName}|All],
emit(["OldFormat={",lists:join(",", Record),"},",nl,
{call,ext,transform_to_EXTERNAL1994,
["OldFormat"]}]);
dec_external(#gen{pack=map}, _RecordName) ->
Vars = asn1ct_name:all(term),
Names = ['direct-reference','indirect-reference',
'data-value-descriptor',encoding],
Zipped = lists:zip(Names, Vars),
MapInit = lists:join(",", [["'",N,"'=>",{var,V}] || {N,V} <- Zipped]),
emit(["OldFormat = #{",MapInit,"}",com,nl,
"ASN11994Format =",nl,
{call,ext,transform_to_EXTERNAL1994_maps,
["OldFormat"]}]).
gen_dec_do_pack(#gen{pack=record}, RecordName, _CompList) ->
All = asn1ct_name:all(term),
L = [{asis,RecordName}|[{var,Var} || Var <- All]],
emit([{curr,res}," = {",lists:join(",", L),"}"]);
gen_dec_do_pack(#gen{pack=map}, _, CompList) ->
Zipped = lists:zip(CompList, asn1ct_name:all(term)),
PF = fun({#'ComponentType'{prop='OPTIONAL'},_}) -> false;
({_,_}) -> true
end,
{Mandatory,Optional} = lists:partition(PF, Zipped),
L = [[{asis,Name},"=>",{var,Var}] ||
{#'ComponentType'{name=Name},Var} <- Mandatory],
emit([{curr,res}," = #{",lists:join(",", L),"}"]),
gen_dec_map_optional(Optional).
gen_dec_map_optional([{#'ComponentType'{name=Name},Var}|T]) ->
asn1ct_name:new(res),
emit([com,nl,
{curr,res}," = case ",{var,Var}," of",nl,
" asn1_NOVALUE -> ",{prev,res},";",nl,
" _ -> ",{prev,res},"#{",{asis,Name},"=>",{var,Var},"}",nl,
"end"]),
gen_dec_map_optional(T);
gen_dec_map_optional([]) ->
ok.
gen_dec_postponed_decs(_,[]) ->
emit(nl);
gen_dec_postponed_decs(DecObj,[{_Cname,{FirstPFN,PFNList},Term,
TmpTerm,_Tag,OptOrMand}|Rest]) ->
asn1ct_name:new(tmpterm),
asn1ct_name:new(reason),
asn1ct_name:new(tmptlv),
emit([Term," = ",nl]),
N = case OptOrMand of
mandatory -> 0;
'OPTIONAL' ->
emit_opt_or_mand_check(asn1_NOVALUE,TmpTerm),
6;
{'DEFAULT',Val} ->
emit_opt_or_mand_check(Val,TmpTerm),
6
end,
emit([indent(N+3),"case (catch ",DecObj,"(",{asis,FirstPFN},
", ",TmpTerm,", ",{asis,PFNList},")) of",nl]),
emit([indent(N+6),"{'EXIT', ",{curr,reason},"} ->",nl]),
emit([indent(N+9),"exit({'Type not compatible with table constraint',",
{curr,reason},"});",nl]),
emit([indent(N+6),{curr,tmpterm}," ->",nl]),
emit([indent(N+9),{curr,tmpterm},nl]),
case OptOrMand of
mandatory -> emit([indent(N+3),"end,",nl]);
_ ->
emit([indent(N+3),"end",nl,
indent(3),"end,",nl])
end,
gen_dec_postponed_decs(DecObj,Rest).
emit_opt_or_mand_check(Value,TmpTerm) ->
emit([indent(3),"case ",TmpTerm," of",nl,
indent(6),{asis,Value}," ->",{asis,Value},";",nl,
indent(6),"_ ->",nl]).
%%============================================================================
%% Encode/decode SET
%%
%%============================================================================
gen_encode_set(Erules,Typename,D) when is_record(D,type) ->
gen_encode_sequence(Erules,Typename,D).
gen_decode_set(Gen, Typename, #type{}=D) ->
asn1ct_name:start(),
%% asn1ct_name:new(term),
asn1ct_name:new(tag),
#'SET'{tablecinf=TableConsInfo,components=TCompList0} = D#type.def,
%% filter away extensionAdditiongroup markers
TCompList = filter_complist(TCompList0),
Ext = extensible(TCompList),
ToOptional = fun(mandatory) ->
'OPTIONAL';
(X) -> X
end,
CompList = case TCompList of
{Rl1,El,Rl2} -> Rl1 ++ [X#'ComponentType'{prop=ToOptional(Y)}||X = #'ComponentType'{prop=Y}<-El] ++ Rl2;
{Rl,El} -> Rl ++ El;
_ -> TCompList
end,
%% asn1ct_name:clear(),
asn1ct_name:new(tlv),
case CompList of
[] -> % empty sequence
true;
_ ->
emit([{curr,tlv}," = "])
end,
call(match_tags, [{prev,tlv},"TagIn"]),
emit([com,nl]),
asn1ct_name:new(v),
{DecObjInf,ValueIndex} =
case TableConsInfo of
#simpletableattributes{objectsetname=ObjectSetRef,
c_name=AttrN,
usedclassfield=UniqueFieldName,
uniqueclassfield=UniqueFieldName,
valueindex=ValIndex} ->
F = fun(#'ComponentType'{typespec=CT})->
case {asn1ct_gen:get_constraint(CT#type.constraint,
componentrelation),
CT#type.tablecinf} of
{no,[{objfun,_}|_]} -> true;
_ -> false
end
end,
case lists:any(F,CompList) of
true ->
%% when component relation constraint establish
%% relation from a component to another components
%% subtype component
{{AttrN,{deep,ObjectSetRef,UniqueFieldName,ValIndex}},
ValIndex};
false ->
{{AttrN,ObjectSetRef},ValIndex}
end;
_ ->
{false,false}
end,
case CompList of
[] -> % empty set
true;
_ ->
emit(["SetFun = fun(FunTlv) ->", nl]),
emit(["case FunTlv of ",nl]),
NextNum = gen_dec_set_cases(Gen, Typename, CompList, 1),
emit([indent(6), {curr,else}," -> ",nl,
indent(9),"{",NextNum,", ",{curr,else},"}",nl]),
emit([indent(3),"end",nl]),
emit([indent(3),"end,",nl]),
emit(["PositionList = [SetFun(TempTlv)|| TempTlv <- ",{curr,tlv},"],",nl]),
asn1ct_name:new(tlv),
emit([{curr,tlv}," = [Stlv || {_,Stlv} <- lists:sort(PositionList)],",nl]),
asn1ct_name:new(tlv)
end,
RecordName0 = lists:concat([get_record_name_prefix(Gen),
asn1ct_gen:list2rname(Typename)]),
RecordName = list_to_atom(RecordName0),
case gen_dec_sequence_call(Gen, Typename, CompList, Ext, DecObjInf) of
no_terms -> % an empty SET
case Gen of
#gen{pack=record} ->
emit([nl,nl," {'",RecordName,"'}.",nl,nl]);
#gen{pack=map} ->
emit([nl,nl," #{}.",nl,nl])
end;
{LeadingAttrTerm,PostponedDecArgs} ->
emit([nl]),
case {LeadingAttrTerm,PostponedDecArgs} of
{[],[]} ->
ok;
{_,[]} ->
ok;
{[{ObjSetRef,LeadingAttr,Term}],PostponedDecArgs} ->
DecObj = asn1ct_gen:un_hyphen_var(lists:concat(['DecObj',LeadingAttr,Term])),
ValueMatch = value_match(Gen, ValueIndex, Term),
{ObjSetMod,ObjSetName} = ObjSetRef,
emit([DecObj," =",nl,
" ",{asis,ObjSetMod},":'getdec_",ObjSetName,"'(",
ValueMatch,"),",nl]),
gen_dec_postponed_decs(DecObj,PostponedDecArgs)
end,
%% return value as record
case Ext of
Extnsn when Extnsn =/= noext ->
emit(["case ",{prev,tlv}," of [] -> true; _ -> true end, % ... extra fields skipped",nl]);
noext ->
emit(["case ",{prev,tlv}," of",nl,
"[] -> true;",
"_ -> exit({error,{asn1, {unexpected,",{prev,tlv},
"}}}) % extra fields not allowed",nl,
"end,",nl])
end,
gen_dec_pack(Gen, RecordName, Typename, CompList),
emit([".",nl])
end.
%%===============================================================================
%%===============================================================================
%%===============================================================================
%% Encode/decode SEQUENCE OF and SET OF
%%===============================================================================
%%===============================================================================
%%===============================================================================
gen_encode_sof(Erules,Typename,_InnerTypename,D) when is_record(D,type) ->
asn1ct_name:start(),
{SeqOrSetOf, Cont} = D#type.def,
Objfun = case D#type.tablecinf of
[{objfun,_}|_R] ->
", ObjFun";
_ ->
""
end,
emit([" {EncBytes,EncLen} = 'enc_",asn1ct_gen:list2name(Typename),
"_components'(Val",Objfun,",[],0),",nl]),
emit([" ",{call,ber,encode_tags,["TagIn","EncBytes","EncLen"]},
".",nl,nl]),
gen_encode_sof_components(Erules,Typename,SeqOrSetOf,Cont).
gen_decode_sof(Erules,TypeName,_InnerTypeName,D) when is_record(D,type) ->
asn1ct_name:start(),
{SeqOrSetOf, _TypeTag, Cont} =
case D#type.def of
{'SET OF',_Cont} -> {'SET OF','SET',_Cont};
{'SEQUENCE OF',_Cont} -> {'SEQUENCE OF','SEQUENCE',_Cont}
end,
TypeNameSuffix = asn1ct_gen:constructed_suffix(SeqOrSetOf,Cont#type.def),
emit([" %%-------------------------------------------------",nl]),
emit([" %% decode tag and length ",nl]),
emit([" %%-------------------------------------------------",nl]),
asn1ct_name:new(tlv),
emit([{curr,tlv}," = ",
{call,ber,match_tags,[{prev,tlv},"TagIn"]},com,nl]),
asn1ct_name:new(v),
emit(["["]),
InnerType = asn1ct_gen:get_inner(Cont#type.def),
ContName = case asn1ct_gen:type(InnerType) of
Atom when is_atom(Atom) -> Atom;
_ -> TypeNameSuffix
end,
gen_dec_line(Erules,TypeName,ContName,[],Cont,mandatory),
emit([" || ",{curr,v}," <- ",{curr,tlv},"].",nl,nl,nl]).
gen_encode_sof_components(Gen, Typename, SeqOrSetOf, #type{}=Cont) ->
{Objfun,Objfun_novar,EncObj} =
case Cont#type.tablecinf of
[{objfun,_}|_R] ->
{", ObjFun",", _",{no_attr,"ObjFun"}};
_ ->
{"","",false}
end,
emit(["'enc_",asn1ct_gen:list2name(Typename),
"_components'([]",Objfun_novar,", AccBytes, AccLen) -> ",nl]),
case {Gen,SeqOrSetOf} of
{#gen{der=true},'SET OF'} ->
asn1ct_func:need({ber,dynamicsort_SETOF,1}),
emit([indent(3),
"{dynamicsort_SETOF(AccBytes),AccLen};",nl,nl]);
{_,_} ->
emit([indent(3),"{lists:reverse(AccBytes),AccLen};",nl,nl])
end,
emit(["'enc_",asn1ct_gen:list2name(Typename),
"_components'([H|T]",Objfun,",AccBytes, AccLen) ->",nl]),
TypeNameSuffix = asn1ct_gen:constructed_suffix(SeqOrSetOf,Cont#type.def),
gen_enc_line(Gen, Typename, TypeNameSuffix, Cont, "H", 3,
mandatory, EncObj),
emit([",",nl]),
emit([indent(3),"'enc_",asn1ct_gen:list2name(Typename),
"_components'(T",Objfun,","]),
emit(["[EncBytes|AccBytes], AccLen + EncLen).",nl,nl]).
%%============================================================================
%% Encode/decode CHOICE
%%
%%============================================================================
gen_encode_choice(Erules,Typename,D) when is_record(D,type) ->
ChoiceTag = D#type.tag,
{'CHOICE',CompList} = D#type.def,
Ext = extensible(CompList),
CompList1 = case CompList of
{Rl1,El,Rl2} -> Rl1 ++ El ++ Rl2;
{Rl,El} -> Rl ++ El;
_ -> CompList
end,
gen_enc_choice(Erules,Typename,ChoiceTag,CompList1,Ext),
emit([nl,nl]).
gen_decode_choice(Erules,Typename,D) when is_record(D,type) ->
asn1ct_name:start(),
asn1ct_name:new(bytes),
ChoiceTag = D#type.tag,
{'CHOICE',CompList} = D#type.def,
Ext = extensible(CompList),
CompList1 = case CompList of
{Rl1,El,Rl2} -> Rl1 ++ El ++ Rl2;
{Rl,El} -> Rl ++ El;
_ -> CompList
end,
gen_dec_choice(Erules,Typename,ChoiceTag,CompList1,Ext),
emit([".",nl]).
%%============================================================================
%% Encode SEQUENCE
%%
%%============================================================================
gen_enc_sequence_call(Erules,TopType,[#'ComponentType'{name=Cname,typespec=Type,prop=Prop,textual_order=Order}|Rest],Pos,Ext,EncObj) ->
asn1ct_name:new(encBytes),
asn1ct_name:new(encLen),
asn1ct_name:new(tmpBytes),
asn1ct_name:new(tmpLen),
CindexPos =
case Order of
undefined ->
Pos;
_ -> Order % der
end,
Element =
case TopType of
['EXTERNAL'] ->
io_lib:format("Cindex~w",[CindexPos]);
_ ->
io_lib:format("Cindex~w",[CindexPos])
end,
InnerType = asn1ct_gen:get_inner(Type#type.def),
print_attribute_comment(InnerType,Pos,Cname,Prop),
gen_enc_line(Erules,TopType,Cname,Type,Element,3,Prop,EncObj),
emit([com,nl]),
gen_enc_sequence_call(Erules,TopType,Rest,Pos+1,Ext,EncObj);
gen_enc_sequence_call(_Erules,_TopType,[],_Num,_,_) ->
true.
%%============================================================================
%% Decode SEQUENCE
%%
%%============================================================================
gen_dec_sequence_call(Erules,TopType,CompList,Ext,DecObjInf)
when is_list(CompList) ->
gen_dec_sequence_call1(Erules,TopType, CompList, 1, Ext,DecObjInf,[],[]);
gen_dec_sequence_call(Erules,TopType,CompList,Ext,DecObjInf) ->
gen_dec_sequence_call2(Erules,TopType, CompList, Ext,DecObjInf).
gen_dec_sequence_call1(Erules,TopType,[#'ComponentType'{name=Cname,typespec=Type,prop=Prop,tags=Tags}|Rest],Num,Ext,DecObjInf,LeadingAttrAcc,ArgsAcc) ->
{LA,PostponedDec} =
gen_dec_component(Erules,TopType,Cname,Tags,Type,Num,Prop,
Ext,DecObjInf),
emit([com,nl]),
case Rest of
[] ->
{LA ++ LeadingAttrAcc,PostponedDec ++ ArgsAcc};
_ ->
asn1ct_name:new(bytes),
gen_dec_sequence_call1(Erules,TopType,Rest,Num+1,Ext,DecObjInf,
LA++LeadingAttrAcc,PostponedDec++ArgsAcc)
end;
gen_dec_sequence_call1(_Erules,_TopType,[],1,_,_,_,_) ->
no_terms;
gen_dec_sequence_call1(_, _, [], _Num, _, _, LA, PostponedDec) ->
{LA, PostponedDec}.
gen_dec_sequence_call2(_Erules,_TopType, {[], [], []}, _Ext,_DecObjInf) ->
no_terms;
gen_dec_sequence_call2(Erules,TopType,{Root1,EList,Root2},_Ext,DecObjInf) ->
{LA,ArgsAcc} =
case gen_dec_sequence_call1(Erules,TopType,Root1++EList,1,
extensible({Root1,EList}),DecObjInf,[],[]) of
no_terms ->
{[],[]};
Res -> Res
end,
%% TagList is the tags of Root2 elements from the first up to and
%% including the first mandatory element.
TagList = get_root2_taglist(Root2,[]),
emit([{curr,tlv}," = ",
{call,ber,skip_ExtensionAdditions,
[{prev,tlv},{asis,TagList}]},com,nl]),
asn1ct_name:new(tlv),
gen_dec_sequence_call1(Erules,TopType,Root2,
length(Root1)+length(EList),noext,
DecObjInf,LA,ArgsAcc).
%% Returns a list of tags of the elements in the component (second
%% root) list up to and including the first mandatory tag. See 24.6 in
%% X.680 (7/2002)
get_root2_taglist([],Acc) ->
lists:reverse(Acc);
get_root2_taglist([#'ComponentType'{prop=Prop,typespec=Type}|Rest],Acc) ->
FirstTag = fun([])->[];
([H|_T])->(?ASN1CT_GEN_BER:decode_class(H#tag.class) bsl 10)
+ H#tag.number
end(Type#type.tag),
case Prop of
mandatory ->
%% match_tags/ may be used
%% this is the last tag of interest -> return
lists:reverse([FirstTag|Acc]);
_ ->
get_root2_taglist(Rest,[FirstTag|Acc])
end.
%%----------------------------
%%SEQUENCE mandatory
%%----------------------------
gen_dec_component(Erules,TopType,Cname,CTags,Type,Pos,Prop,Ext,DecObjInf) ->
InnerType =
case Type#type.def of
#'ObjectClassFieldType'{type=OCFTType} -> OCFTType;
_ -> asn1ct_gen:get_inner(Type#type.def)
end,
Prop1 = case {Prop,Ext} of
{mandatory,{ext,Epos,_}} when Pos >= Epos ->
'OPTIONAL';
_ ->
Prop
end,
print_attribute_comment(InnerType,Pos,Cname,Prop1),
asn1ct_name:new(term),
emit_term_tlv(Prop1,InnerType,DecObjInf),
asn1ct_name:new(rb),
PostponedDec =
gen_dec_line(Erules,TopType,Cname,CTags,Type,Prop1,DecObjInf),
asn1ct_name:new(v),
asn1ct_name:new(tlv),
asn1ct_name:new(form),
PostponedDec.
emit_term_tlv({'DEFAULT',_},InnerType,DecObjInf) ->
emit_term_tlv(opt_or_def,InnerType,DecObjInf);
emit_term_tlv('OPTIONAL',InnerType,DecObjInf) ->
emit_term_tlv(opt_or_def,InnerType,DecObjInf);
emit_term_tlv(Prop,{typefield,_},DecObjInf) ->
emit_term_tlv(Prop,type_or_object_field,DecObjInf);
emit_term_tlv(opt_or_def,type_or_object_field,NotFalse)
when NotFalse /= false ->
asn1ct_name:new(tmpterm),
emit(["{",{curr,tmpterm},",",{curr,tlv},"} = "]);
emit_term_tlv(opt_or_def,_,_) ->
emit(["{",{curr,term},",",{curr,tlv},"} = "]);
emit_term_tlv(_,type_or_object_field,false) ->
emit(["[",{curr,v},"|",{curr,tlv},"] = ",{prev,tlv},", ",nl,
{curr,term}," = "]);
emit_term_tlv(_,type_or_object_field,_) ->
asn1ct_name:new(tmpterm),
emit(["[",{curr,v},"|",{curr,tlv},"] = ",{prev,tlv},", ",nl]),
emit([nl," ",{curr,tmpterm}," = "]);
emit_term_tlv(mandatory,_,_) ->
emit(["[",{curr,v},"|",{curr,tlv},"] = ",{prev,tlv},", ",nl,
{curr,term}," = "]).
gen_dec_set_cases(_Erules,_TopType,[],Pos) ->
Pos;
gen_dec_set_cases(Erules,TopType,[Comp|RestComps],Pos) ->
Name = Comp#'ComponentType'.name,
Type = Comp#'ComponentType'.typespec,
CTags = Comp#'ComponentType'.tags,
emit([indent(6),"%",Name,nl]),
Tags = case Type#type.tag of
[] -> % this is a choice without explicit tag
[(?ASN1CT_GEN_BER:decode_class(T1class) bsl 10) + T1number||
{T1class,T1number} <- CTags];
[FirstTag|_] ->
[(?ASN1CT_GEN_BER:decode_class(FirstTag#tag.class) bsl 10) + FirstTag#tag.number]
end,
CaseFun = fun(TagList=[H|T],Fun,N) ->
Semicolon = case TagList of
[_Tag1,_|_] -> [";",nl];
_ -> ""
end,
emit(["TTlv = {",H,",_} ->",nl]),
emit([indent(4),"{",Pos,", TTlv}",Semicolon]),
Fun(T,Fun,N+1);
([],_,0) ->
true;
([],_,_) ->
emit([";",nl])
end,
CaseFun(Tags,CaseFun,0),
gen_dec_set_cases(Erules,TopType,RestComps,Pos+1).
%%---------------------------------------------
%% Encode CHOICE
%%---------------------------------------------
%% for BER we currently do care (a little) if the choice has an EXTENSIONMARKER
gen_enc_choice(Erules,TopType,Tag,CompList,_Ext) ->
gen_enc_choice1(Erules,TopType,Tag,CompList,_Ext).
gen_enc_choice1(Erules,TopType,_Tag,CompList,_Ext) ->
asn1ct_name:clear(),
emit([" {EncBytes,EncLen} = case element(1,Val) of",nl]),
gen_enc_choice2(Erules,TopType,CompList),
emit([nl," end,",nl,nl]),
call(encode_tags, ["TagIn","EncBytes","EncLen"]),
emit([".",nl]).
gen_enc_choice2(Erules,TopType,[H1|T]) when is_record(H1,'ComponentType') ->
Cname = H1#'ComponentType'.name,
Type = H1#'ComponentType'.typespec,
emit([" ",{asis,Cname}," ->",nl]),
{Encobj,Assign} =
case {Type#type.def,asn1ct_gen:get_constraint(Type#type.constraint,
componentrelation)} of
{#'ObjectClassFieldType'{},{componentrelation,_,_}} ->
asn1ct_name:new(tmpBytes),
asn1ct_name:new(tmpLen),
asn1ct_name:new(encBytes),
asn1ct_name:new(encLen),
Emit = ["{",{curr,tmpBytes},", _} = "],
{{no_attr,"ObjFun"},Emit};
_ ->
case Type#type.tablecinf of
[{objfun,_}] -> {{no_attr,"ObjFun"},[]};
_ -> {false,[]}
end
end,
gen_enc_line(Erules,TopType,Cname,Type,"element(2,Val)",9,
mandatory,Assign,Encobj),
case {Type#type.def,Encobj} of
{#'ObjectClassFieldType'{},{no_attr,"ObjFun"}} ->
emit([",",nl,indent(9),"{",{curr,encBytes},", ",
{curr,encLen},"}"]);
_ -> ok
end,
emit([";",nl]),
case T of
[] ->
emit([indent(6), "Else -> ",nl,
indent(9),"exit({error,{asn1,{invalid_choice_type,Else}}})"]);
_ ->
true
end,
gen_enc_choice2(Erules,TopType,T);
gen_enc_choice2(_Erules,_TopType,[]) ->
true.
%%--------------------------------------------
%% Decode CHOICE
%%--------------------------------------------
gen_dec_choice(Erules,TopType, _ChTag, CompList, Ext) ->
asn1ct_name:clear(),
asn1ct_name:new(tlv),
emit([{curr,tlv}," = ",
{call,ber,match_tags,[{prev,tlv},"TagIn"]},com,nl]),
asn1ct_name:new(tlv),
asn1ct_name:new(v),
emit(["case (case ",{prev,tlv},
" of [Ctemp",{prev,tlv},"] -> Ctemp",{prev,tlv},
"; _ -> ",{prev,tlv}," end)"," of",nl]),
asn1ct_name:new(tagList),
asn1ct_name:new(choTags),
asn1ct_name:new(res),
gen_dec_choice_cases(Erules,TopType,CompList),
emit([indent(6), {curr,else}," -> ",nl]),
case Ext of
noext ->
emit([indent(9),"exit({error,{asn1,{invalid_choice_tag,",
{curr,else},"}}})",nl]);
_ ->
emit([indent(9),"{asn1_ExtAlt,",
{call,ber,ber_encode,[{curr,else}]},"}",nl])
end,
emit([indent(3),"end",nl]),
asn1ct_name:new(tag),
asn1ct_name:new(else).
gen_dec_choice_cases(_Erules,_TopType, []) ->
ok;
gen_dec_choice_cases(Erules,TopType, [H|T]) ->
Cname = H#'ComponentType'.name,
Type = H#'ComponentType'.typespec,
Prop = H#'ComponentType'.prop,
Tags = Type#type.tag,
Fcases = fun([{T1class,T1number}|Tail],Fun) ->
emit([indent(4),{curr,v}," = {",
(?ASN1CT_GEN_BER:decode_class(T1class) bsl 10) +
T1number,",_} -> ",nl]),
emit([indent(8),"{",{asis,Cname},", "]),
gen_dec_line(Erules,TopType,Cname,[],Type,Prop),
emit(["};",nl,nl]),
Fun(Tail,Fun);
([],_) ->
ok
end,
emit([nl,"%% '",Cname,"'",nl]),
case {Tags,asn1ct:get_gen_state_field(namelist)} of
{[],_} -> % choice without explicit tags
Fcases(H#'ComponentType'.tags,Fcases);
{[FirstT|_RestT],[{Cname,undecoded}|Names]} ->
DecTag=(?ASN1CT_GEN_BER:decode_class(FirstT#tag.class) bsl 10) +
FirstT#tag.number,
asn1ct:add_generated_refed_func({[Cname|TopType],undecoded,
[DecTag],Type}),
asn1ct:update_gen_state(namelist,Names),
emit([indent(4),{curr,res}," = ",
match_tag(FirstT#tag.class, FirstT#tag.number),
" -> ",nl]),
emit([indent(8),"{",{asis,Cname},", {'",
asn1ct_gen:list2name([Cname|TopType]),"',",
{curr,res},"}};",nl,nl]);
{[FirstT|RestT],_} ->
emit([indent(4),"{",
(?ASN1CT_GEN_BER:decode_class(FirstT#tag.class) bsl 10) +
FirstT#tag.number,", ",{curr,v},"} -> ",nl]),
emit([indent(8),"{",{asis,Cname},", "]),
gen_dec_line(Erules,TopType,Cname,[],Type#type{tag=RestT},Prop),
emit(["};",nl,nl])
end,
gen_dec_choice_cases(Erules,TopType, T).
match_tag(Class, TagNo) when is_integer(TagNo) ->
match_tag1(asn1ct_gen_ber_bin_v2:decode_class(Class), TagNo).
match_tag1(Class, TagNo) when TagNo =< 30 ->
io_lib:format("<<~p:2,_:1,~p:5,_/binary>>", [Class bsr 6,TagNo]);
match_tag1(Class, TagNo) ->
Octets = mk_object_val(TagNo),
io_lib:format("<<~p:2,_:1,31:5,~s,_/binary>>", [Class bsr 6,Octets]).
mk_object_val(Val) when Val < 16#80 ->
integer_to_list(Val);
mk_object_val(Val) ->
mk_object_val(Val bsr 7, [integer_to_list(Val band 16#7F)]).
mk_object_val(0, Acc) ->
Acc;
mk_object_val(Val, Acc) ->
I = integer_to_list((Val band 16#7F) bor 16#80),
mk_object_val(Val bsr 7, [I,","|Acc]).
%%---------------------------------------
%% Generate the encode/decode code
%%---------------------------------------
gen_enc_line(Erules,TopType,Cname,
Type=#type{constraint=C,
def=#'ObjectClassFieldType'{type={typefield,_}}},
Element,Indent,OptOrMand=mandatory,EncObj)
when is_list(Element) ->
case asn1ct_gen:get_constraint(C,componentrelation) of
{componentrelation,_,_} ->
gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,
["{",{curr,tmpBytes},",_} = "],EncObj);
_ ->
gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,
["{",{curr,encBytes},",",{curr,encLen},"} = "],
EncObj)
end;
gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,EncObj)
when is_list(Element) ->
gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,
["{",{curr,encBytes},",",{curr,encLen},"} = "],EncObj).
gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,Assign,EncObj)
when is_list(Element) ->
IndDeep = indent(Indent),
Tag = lists:reverse([?ASN1CT_GEN_BER:encode_tag_val(
?ASN1CT_GEN_BER:decode_class(X#tag.class),
X#tag.form,
X#tag.number)
|| X <- Type#type.tag]),
InnerType = asn1ct_gen:get_inner(Type#type.def),
WhatKind = asn1ct_gen:type(InnerType),
emit(IndDeep),
emit(Assign),
gen_optormand_case(OptOrMand, Erules, TopType, Cname, Type, Element),
case {Type,asn1ct_gen:get_constraint(Type#type.constraint,
componentrelation)} of
{#type{def=#'ObjectClassFieldType'{type={typefield,_},
fieldname=RefedFieldName}},
{componentrelation,_,_}} ->
{_LeadingAttrName,Fun} = EncObj,
{Name,RestFieldNames} = RefedFieldName,
true = is_atom(Name), %Assertion.
case OptOrMand of
mandatory -> ok;
_ ->
emit(["{",{curr,tmpBytes},",_ } = "])
end,
emit([Fun,"(",{asis,Name},", ",Element,", ",
{asis,RestFieldNames},"),",nl]),
emit(IndDeep),
case OptOrMand of
mandatory ->
emit(["{",{curr,encBytes},",",{curr,encLen},
"} = ",
{call,ber,encode_open_type,
[{curr,tmpBytes},{asis,Tag}]},nl]);
_ ->
emit([{call,ber,encode_open_type,
[{curr,tmpBytes},{asis,Tag}]}])
end;
_ ->
case WhatKind of
{primitive,bif} ->
?ASN1CT_GEN_BER:gen_encode_prim(ber, Type, {asis,Tag},
Element);
'ASN1_OPEN_TYPE' ->
case Type#type.def of
#'ObjectClassFieldType'{} -> %Open Type
?ASN1CT_GEN_BER:gen_encode_prim(ber,#type{def='ASN1_OPEN_TYPE'},{asis,Tag},Element);
_ ->
?ASN1CT_GEN_BER:gen_encode_prim(ber,Type,
{asis,Tag},
Element)
end;
_ ->
{EncFunName, _EncMod, _EncFun} =
mkfuncname(TopType,Cname,WhatKind,"enc_",""),
case {WhatKind,Type#type.tablecinf,EncObj} of
{{constructed,bif},[{objfun,_}|_R],{_,Fun}} ->
emit([EncFunName,"(",Element,", ",{asis,Tag},
", ",Fun,")"]);
_ ->
emit([EncFunName,"(",Element,", ",{asis,Tag},")"])
end
end
end,
case OptOrMand of
mandatory -> true;
_ ->
emit([nl,indent(7),"end"])
end.
gen_optormand_case(mandatory, _Gen, _TopType, _Cname, _Type, _Element) ->
ok;
gen_optormand_case('OPTIONAL', Gen, _TopType, _Cname, _Type, Element) ->
emit([" case ",Element," of",nl]),
Missing = case Gen of
#gen{pack=record} -> asn1_NOVALUE;
#gen{pack=map} -> ?MISSING_IN_MAP
end,
emit([indent(9),Missing," -> {",
empty_lb(Gen),",0};",nl]),
emit([indent(9),"_ ->",nl,indent(12)]);
gen_optormand_case({'DEFAULT',DefaultValue}, Gen, _TopType,
_Cname, Type, Element) ->
CurrMod = get(currmod),
case Gen of
#gen{erule=ber,der=true} ->
asn1ct_gen_check:emit(Gen, Type, DefaultValue, Element);
#gen{erule=ber,der=false,pack=Pack} ->
Ind9 = indent(9),
DefMarker = case Pack of
record -> asn1_DEFAULT;
map -> ?MISSING_IN_MAP
end,
emit([" case ",Element," of",nl,
Ind9,{asis,DefMarker}," ->",nl,
Ind9,indent(3),"{",empty_lb(Gen),",0};",nl,
Ind9,"_ when ",Element," =:= "]),
Dv = case DefaultValue of
#'Externalvaluereference'{module=CurrMod,
value=V} ->
["?",{asis,V}];
_ ->
[{asis,DefaultValue}]
end,
emit(Dv++[" ->",nl,
Ind9,indent(3),"{",empty_lb(Gen),",0};",nl,
Ind9,"_ ->",nl,
indent(12)])
end.
%% Use for SEQUENCE OF and CHOICE.
gen_dec_line(Erules,TopType,Cname,CTags,Type,OptOrMand) ->
%% The matching on the next line is an assertion.
{[],[]} = gen_dec_line(Erules,TopType,Cname,CTags,Type,OptOrMand,false),
ok.
%% Use for SEQUENCE.
gen_dec_line(Erules,TopType,Cname,CTags,Type,OptOrMand,DecObjInf) ->
BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(v)),
Tag =
[(?ASN1CT_GEN_BER:decode_class(X#tag.class) bsl 10) + X#tag.number ||
X <- Type#type.tag],
ChoiceTags =
[(?ASN1CT_GEN_BER:decode_class(Class) bsl 10) + Number||
{Class,Number} <- CTags],
InnerType =
case Type#type.def of
#'ObjectClassFieldType'{type=OCFTType} ->
OCFTType;
_ ->
asn1ct_gen:get_inner(Type#type.def)
end,
PostpDec =
case OptOrMand of
mandatory ->
gen_dec_call(InnerType,Erules,TopType,Cname,Type,
BytesVar,Tag,
mandatory,", mandatory, ",DecObjInf,OptOrMand);
_ ->
%% optional or default, or a mandatory component after
%% an extension marker
{FirstTag,RestTag} =
case Tag of
[] ->
{ChoiceTags,[]};
[Ft|Rt] ->
{Ft,Rt}
end,
emit(["case ",{prev,tlv}," of",nl]),
PostponedDec =
case Tag of
[] when length(ChoiceTags) > 0 -> % a choice without explicit tag
Fcases =
fun(FirstTag1) ->
emit(["[",{curr,v}," = {",{asis,FirstTag1},
",_}|Temp",
{curr,tlv},
"] ->",nl]),
emit([indent(4),"{"]),
Pdec=
gen_dec_call(InnerType,Erules,
TopType,Cname,Type,
BytesVar,RestTag,
mandatory,
", mandatory, ",
DecObjInf,OptOrMand),
emit([", Temp",{curr,tlv},"}"]),
emit([";",nl]),
Pdec
end,
hd([Fcases(TmpTag)|| TmpTag <- FirstTag]);
[] -> % an open type without explicit tag
emit(["[",{curr,v},"|Temp",{curr,tlv},"] ->",nl]),
emit([indent(4),"{"]),
Pdec=
gen_dec_call(InnerType,Erules,TopType,Cname,
Type,BytesVar,RestTag,mandatory,
", mandatory, ",DecObjInf,
OptOrMand),
emit([", Temp",{curr,tlv},"}"]),
emit([";",nl]),
Pdec;
_ ->
emit(["[{",{asis,FirstTag},
",",{curr,v},"}|Temp",
{curr,tlv},
"] ->",nl]),
emit([indent(4),"{"]),
Pdec=
gen_dec_call(InnerType,Erules,TopType,Cname,
Type,BytesVar,RestTag,mandatory,
", mandatory, ",DecObjInf,
OptOrMand),
emit([", Temp",{curr,tlv},"}"]),
emit([";",nl]),
Pdec
end,
emit([indent(4),"_ ->",nl]),
case OptOrMand of
{'DEFAULT', Def0} ->
Def = asn1ct_gen:conform_value(Type, Def0),
emit([indent(8),"{",{asis,Def},",",{prev,tlv},"}",nl]);
'OPTIONAL' ->
emit([indent(8),"{ asn1_NOVALUE, ",{prev,tlv},"}",nl])
end,
emit(["end"]),
PostponedDec
end,
case DecObjInf of
{Cname,ObjSet} ->
%% This must be the component were an object is chosen
%% from the object set according to the table constraint.
ObjSetName = case ObjSet of
{deep,OSName,_,_} ->
OSName;
_ -> ObjSet
end,
{[{ObjSetName,Cname,asn1ct_gen:mk_var(asn1ct_name:curr(term))}],
PostpDec};
_ -> {[],PostpDec}
end.
gen_dec_call({typefield,_},_,_,_Cname,Type,BytesVar,Tag,_,_,false,_) ->
%% this in case of a choice with typefield components
asn1ct_name:new(reason),
asn1ct_name:new(opendec),
asn1ct_name:new(tmpterm),
asn1ct_name:new(tmptlv),
{FirstPFName,RestPFName} =
(Type#type.def)#'ObjectClassFieldType'.fieldname,
emit([nl,indent(6),"begin",nl]),
emit([indent(9),{curr,tmptlv}," = ",
{call,ber,decode_open_type,
[BytesVar,{asis,Tag}]},com,nl]),
emit([indent(9),"case (catch ObjFun(",{asis,FirstPFName},
", ",{curr,tmptlv},", ",{asis,RestPFName},
")) of", nl]),%% ??? What about Tag
emit([indent(12),"{'EXIT',",{curr,reason},"} ->",nl]),
emit([indent(15),"exit({'Type not ",
"compatible with table constraint', ",{curr,reason},"});",nl]),
emit([indent(12),{curr,tmpterm}," ->",nl]),
emit([indent(15),{curr,tmpterm},nl]),
emit([indent(9),"end",nl,indent(6),"end",nl]),
[];
gen_dec_call({typefield,_},_,_,Cname,Type,BytesVar,Tag,_,_,_DecObjInf,OptOrMandComp) ->
call(decode_open_type, [BytesVar,{asis,Tag}]),
RefedFieldName = (Type#type.def)#'ObjectClassFieldType'.fieldname,
[{Cname,RefedFieldName,asn1ct_gen:mk_var(asn1ct_name:curr(term)),
asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),Tag,OptOrMandComp}];
gen_dec_call(InnerType, Gen, TopType, Cname, Type, BytesVar,
Tag, _PrimOptOrMand, _OptOrMand, DecObjInf,_) ->
WhatKind = asn1ct_gen:type(InnerType),
gen_dec_call1(WhatKind, InnerType, TopType, Cname,
Type, BytesVar, Tag),
case DecObjInf of
{Cname,{_,OSet,_UniqueFName,ValIndex}} ->
Term = asn1ct_gen:mk_var(asn1ct_name:curr(term)),
ValueMatch = value_match(Gen, ValIndex, Term),
{ObjSetMod,ObjSetName} = OSet,
emit([",",nl,"ObjFun = ",{asis,ObjSetMod},":'getdec_",ObjSetName,
"'(",ValueMatch,")"]);
_ ->
ok
end,
[].
gen_dec_call1({primitive,bif}, InnerType, TopType, Cname,
Type, BytesVar, Tag) ->
case {asn1ct:get_gen_state_field(namelist),InnerType} of
{[{Cname,undecoded}|Rest],_} ->
asn1ct:add_generated_refed_func({[Cname|TopType],undecoded,
Tag,Type}),
asn1ct:update_gen_state(namelist,Rest),
emit(["{'",asn1ct_gen:list2name([Cname|TopType]),"',",
BytesVar,"}"]);
_ ->
?ASN1CT_GEN_BER:gen_dec_prim(Type, BytesVar, Tag)
end;
gen_dec_call1('ASN1_OPEN_TYPE', _InnerType, TopType, Cname,
Type, BytesVar, Tag) ->
case {asn1ct:get_gen_state_field(namelist),Type#type.def} of
{[{Cname,undecoded}|Rest],_} ->
asn1ct:add_generated_refed_func({[Cname|TopType],undecoded,
Tag,Type}),
asn1ct:update_gen_state(namelist,Rest),
emit(["{'",asn1ct_gen:list2name([Cname|TopType]),"',",
BytesVar,"}"]);
{_,#'ObjectClassFieldType'{type=OpenType}} ->
?ASN1CT_GEN_BER:gen_dec_prim(#type{def=OpenType},
BytesVar, Tag);
_ ->
?ASN1CT_GEN_BER:gen_dec_prim(Type, BytesVar, Tag)
end;
gen_dec_call1(WhatKind, _, TopType, Cname, Type, BytesVar, Tag) ->
case asn1ct:get_gen_state_field(namelist) of
[{Cname,undecoded}|Rest] ->
asn1ct:add_generated_refed_func({[Cname|TopType],undecoded,
Tag,Type}),
asn1ct:update_gen_state(namelist,Rest),
emit(["{'",asn1ct_gen:list2name([Cname|TopType]),"',",
BytesVar,"}"]);
_ ->
EmitDecFunCall =
fun(FuncName) ->
case {WhatKind,Type#type.tablecinf} of
{{constructed,bif},[{objfun,_}|_Rest]} ->
emit([FuncName,"(",BytesVar,", ",{asis,Tag},
", ObjFun)"]);
_ ->
emit([FuncName,"(",BytesVar,", ",{asis,Tag},")"])
end
end,
case asn1ct:get_gen_state_field(namelist) of
[{Cname,List}|Rest] when is_list(List) ->
Sindex =
case WhatKind of
#'Externaltypereference'{} ->
SI = asn1ct:maybe_saved_sindex(WhatKind,List),
Saves = {WhatKind,SI,List},
asn1ct:add_tobe_refed_func(Saves),
SI;
_ ->
SI = asn1ct:maybe_saved_sindex([Cname|TopType],List),
Saves = {[Cname|TopType],SI,List,Type},
asn1ct:add_tobe_refed_func(Saves),
SI
end,
asn1ct:update_gen_state(namelist,Rest),
Prefix=asn1ct:get_gen_state_field(prefix),
Suffix =
case Sindex of
I when is_integer(I),I>0 -> lists:concat(["_",I]);
_ -> ""
end,
{DecFunName,_,_}=
mkfuncname(TopType,Cname,WhatKind,Prefix,Suffix),
EmitDecFunCall(DecFunName);
[{Cname,parts}|Rest] ->
asn1ct:update_gen_state(namelist,Rest),
asn1ct:get_gen_state_field(prefix),
%% This is to prepare SEQUENCE OF value in
%% partial incomplete decode for a later
%% part-decode, i.e. skip %% the tag.
asn1ct:add_generated_refed_func({[Cname|TopType],
parts,
[],Type}),
emit(["{'",asn1ct_gen:list2name([Cname|TopType]),"',"]),
asn1ct_func:need({ber,match_tags,2}),
EmitDecFunCall("match_tags"),
emit("}");
_ ->
{DecFunName,_,_}=
mkfuncname(TopType,Cname,WhatKind,"dec_",""),
EmitDecFunCall(DecFunName)
end
end.
%%------------------------------------------------------
%% General and special help functions (not exported)
%%------------------------------------------------------
indent(N) ->
lists:duplicate(N,32). % 32 = space
mkvlist([H,T1|T], Sep) -> % Sep is a string e.g ", " or "+ "
emit([{var,H},Sep]),
mkvlist([T1|T], Sep);
mkvlist([H|T], Sep) ->
emit([{var,H}]),
mkvlist(T, Sep);
mkvlist([], _) ->
true.
mkvlist(L) ->
mkvlist(L,", ").
mkvplus(L) ->
mkvlist(L," + ").
extensible(CompList) when is_list(CompList) ->
noext;
extensible({RootList,ExtList}) ->
{ext,length(RootList)+1,length(ExtList)};
extensible({_Rl1,_Ext,_Rl2}) ->
extensible.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% filter away ExtensionAdditionGroup start and end marks since these
%% have no significance for the BER encoding
%%
filter_complist(CompList) when is_list(CompList) ->
lists:filter(fun(#'ExtensionAdditionGroup'{}) ->
false;
('ExtensionAdditionGroupEnd') ->
false;
(_) ->
true
end, CompList);
filter_complist({Root,Ext}) ->
{Root,filter_complist(Ext)};
filter_complist({Root1,Ext,Root2}) ->
{Root1,filter_complist(Ext),Root2}.
print_attribute_comment(InnerType,Pos,Cname,Prop) ->
CommentLine = "%%-------------------------------------------------",
emit([nl,CommentLine]),
case InnerType of
#'Externaltypereference'{module=XModule,type=Name} ->
emit([nl,"%% attribute ",Cname,"(",Pos,") External ",XModule,":",Name]);
_ when is_tuple(InnerType) ->
emit([nl,"%% attribute ",Cname,"(",Pos,") with type "|
tuple_to_list(InnerType)]);
_ ->
emit([nl,"%% attribute ",Cname,"(",Pos,") with type ",InnerType])
end,
case Prop of
mandatory ->
continue;
{'DEFAULT', Def} ->
emit([" DEFAULT = ",{asis,Def}]);
'OPTIONAL' ->
emit([" OPTIONAL"])
end,
emit([nl,CommentLine,nl]).
mkfuncname(TopType,Cname,WhatKind,Prefix,Suffix) ->
CurrMod = get(currmod),
case WhatKind of
#'Externaltypereference'{module=CurrMod,type=EType} ->
F = lists:concat(["'",Prefix,EType,Suffix,"'"]),
{F, "?MODULE", F};
#'Externaltypereference'{module=Mod,type=EType} ->
{lists:concat(["'",Mod,"':'",Prefix,EType,Suffix,"'"]),Mod,
lists:concat(["'",Prefix,EType,"'"])};
{constructed,bif} ->
F = lists:concat(["'",Prefix,
asn1ct_gen:list2name([Cname|TopType]),
Suffix,"'"]),
{F, "?MODULE", F}
end.
empty_lb(#gen{erule=ber}) ->
"<<>>".
value_match(#gen{pack=record}, VIs, Value) ->
value_match_rec(VIs, Value);
value_match(#gen{pack=map}, VIs, Value) ->
value_match_map(VIs, Value).
value_match_rec([], Value) ->
Value;
value_match_rec([{VI,_}|VIs], Value0) ->
Value = value_match_rec(VIs, Value0),
lists:concat(["element(",VI,", ",Value,")"]).
value_match_map([], Value) ->
Value;
value_match_map([{_,Name}|VIs], Value0) ->
Value = value_match_map(VIs, Value0),
lists:concat(["maps:get(",Name,", ",Value,")"]).
call(F, Args) ->
asn1ct_func:call(ber, F, Args).