%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1997-2010. 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_constructed_ber).
-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]).
%%%% Application internal exports
-export([match_tag/2]).
-include("asn1_records.hrl").
-import(asn1ct_gen, [emit/1,demit/1,get_record_name_prefix/0]).
% 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
%%===============================================================================
%%===============================================================================
%%===============================================================================
gen_encode_sequence(Erules,Typename,D) when is_record(D,type) ->
asn1ct_name:start(),
asn1ct_name:new(term),
asn1ct_name:new(bytes),
%% if EXTERNAL type the input value must be transformed to
%% ASN1 1990 format
case Typename of
['EXTERNAL'] ->
emit([" NewVal = asn1rt_check:transform_to_EXTERNAL1990(Val),",
nl]);
_ ->
ok
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,
EncObj =
case TableConsInfo of
#simpletableattributes{usedclassfield=Used,
uniqueclassfield=Unique} when Used /= Unique ->
false;
%% ObjectSetRef, name of the object set in constraints
%%
%%{ObjectSetRef,AttrN,N,UniqueFieldName}
#simpletableattributes{objectsetname=ObjectSetRef,
c_name=AttrN,
c_index=N,
usedclassfield=UniqueFieldName,
uniqueclassfield=UniqueFieldName,
valueindex=ValueIndex
} ->
OSDef =
case ObjectSetRef of
{Module,OSName} ->
asn1_db:dbget(Module,OSName);
OSName ->
asn1_db:dbget(get(currmod),OSName)
end,
% io:format("currmod: ~p~nOSName: ~p~nAttrN: ~p~nN: ~p~nUniqueFieldName: ~p~n",
% [get(currmod),OSName,AttrN,N,UniqueFieldName]),
case (OSDef#typedef.typespec)#'ObjectSet'.gen of
true ->
% Val = lists:concat(["?RT_BER:cindex(",
% N+1,",Val,"]),
ObjectEncode =
asn1ct_gen:un_hyphen_var(lists:concat(['Obj',
AttrN])),
emit({ObjectEncode," = ",nl}),
{ObjSetMod,ObjSetName} =
case ObjectSetRef of
{M,O} ->
{{asis,M},O};
O ->
{"?MODULE",O}
end,
emit({" ",ObjSetMod,":'getenc_",ObjSetName,"'(",{asis,UniqueFieldName},
", ",nl}),
% emit({indent(35),"?RT_BER:cindex(",N+1,", Val,",
% {asis,AttrN},")),",nl}),
Length = fun(X,_LFun) when is_atom(X) ->
length(atom_to_list(X));
(X,_LFun) when is_list(X) ->
length(X);
({X1,X2},LFun) ->
LFun(X1,LFun) + LFun(X2,LFun)
end,
emit([indent(10+Length(ObjectSetRef,Length)),
"value_match(",{asis,ValueIndex},",",
"?RT_BER:cindex(",N+1,",Val,",
{asis,AttrN},"))),",nl]),
notice_value_match(),
{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(Erules,Typename,CompList1,1,Ext,EncObj),
MyTag = [X#tag{class=asn1ct_gen_ber:decode_class(X#tag.class)}|| X <- D#type.tag]
++
[#tag{class = asn1ct_gen_ber:decode_class('UNIVERSAL'),
number = asn1ct_gen_ber:decode_type(SeqOrSet),
form = ?CONSTRUCTED,
type = 'IMPLICIT'}],
emit([nl," BytesSoFar = "]),
case SeqOrSet of
'SET' when (D#type.def)#'SET'.sorted == dynamic ->
emit("asn1rt_check: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]),
% emit(["{TagBytes,Len} = ?RT_BER:encode_tags(TagIn ++ ",
emit([" ?RT_BER:encode_tags(TagIn ++ ",
{asis,MyTag},", BytesSoFar, LenSoFar).",nl]).
gen_decode_sequence(Erules,Typename,D) when is_record(D,type) ->
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(rb),
MyTag = [X#tag{class=asn1ct_gen_ber:decode_class(X#tag.class)}|| X <- D#type.tag]
++
[#tag{class = asn1ct_gen_ber:decode_class('UNIVERSAL'),
number = asn1ct_gen_ber:decode_type('SEQUENCE'),
form = ?CONSTRUCTED,
type = 'IMPLICIT'}],
emit([" {{_,",asn1ct_gen_ber:unused_var("Len",D#type.def),"},",{next,bytes},",",{curr,rb},
"} = ?RT_BER:check_tags(TagIn ++ ",{asis,MyTag},", ",
{curr,bytes},", OptOrMand), ",nl]),
asn1ct_name:new(bytes),
asn1ct_name:new(len),
case CompList of
[] -> true;
_ ->
emit({"{",{next,bytes},
",RemBytes} = ?RT_BER:split_list(",
{curr,bytes},
",", {prev,len},"),",nl}),
asn1ct_name:new(bytes)
end,
{DecObjInf,UniqueFName,ValueIndex} =
case TableConsInfo of
#simpletableattributes{objectsetname=ObjectSet,
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
% case {CT#type.constraint,CT#type.tablecinf} of
{no,[{objfun,_}|_R]} -> true;
_ -> false
end
end,
case lists:any(F,CompList) of
%%AttributeName = asn1ct_gen:un_hyphen_var(AttrN),
true -> % when component relation constraint establish
%% relation from a component to another components
%% subtype component
{{AttrN,{deep,ObjectSet,UniqueFieldName,
ValIndex}},
UniqueFieldName,ValIndex};
false ->
{{AttrN,ObjectSet},UniqueFieldName,ValIndex}
end;
_ ->
{false,false,false}
end,
RecordName = lists:concat([get_record_name_prefix(),asn1ct_gen:list2rname(Typename)]),
case gen_dec_sequence_call(Erules,Typename,CompList2,Ext,DecObjInf) of
no_terms -> % an empty sequence
emit([nl,nl]),
demit({"Result = "}), %dbg
%% return value as record
asn1ct_name:new(rb),
emit([" {{'",RecordName,"'}, ",{curr,bytes},",",nl," "]),
asn1ct_gen_ber:add_removed_bytes(),
emit(["}.",nl]);
{LeadingAttrTerm,PostponedDecArgs} ->
emit([com,nl,nl]),
case {LeadingAttrTerm,PostponedDecArgs} of
{[],[]} ->
ok;
{_,[]} ->
ok;
{[{ObjSet,LeadingAttr,Term}],PostponedDecArgs} ->
DecObj = asn1ct_gen:un_hyphen_var(lists:concat(['DecObj',LeadingAttr,Term])),
ValueMatch = value_match(ValueIndex,Term),
{ObjSetMod,ObjSetName} =
case ObjSet of
{M,O} ->
{{asis,M},O};
_ ->
{"?MODULE",ObjSet}
end,
emit([DecObj," =",nl," ",ObjSetMod,":'getdec_",ObjSetName,"'(",
% {asis,UniqueFName},", ",Term,"),",nl}),
{asis,UniqueFName},", ",ValueMatch,"),",nl]),
gen_dec_postponed_decs(DecObj,PostponedDecArgs)
end,
demit({"Result = "}), %dbg
%% return value as record
asn1ct_name:new(rb),
asn1ct_name:new(bytes),
ExtStatus = case Ext of
{ext,_,_} -> ext;
_ -> noext % noext | extensible
end,
emit([" {",{next,bytes},",",{curr,rb},"} = ?RT_BER:restbytes2(RemBytes, ",
{curr,bytes},",",ExtStatus,"),",nl]),
asn1ct_name:new(rb),
case Typename of
['EXTERNAL'] ->
emit([" OldFormat={'",RecordName,
"', "]),
mkvlist(asn1ct_name:all(term)),
emit(["},",nl]),
emit([" ASN11994Format =",nl,
" asn1rt_check:transform_to_EXTERNAL1994",
"(OldFormat),",nl]),
emit([" {ASN11994Format,",{next,bytes},", "]);
_ ->
emit([" {{'",RecordName,"', "]),
mkvlist(asn1ct_name:all(term)),
emit(["}, ",{next,bytes},", "])
end,
asn1ct_gen_ber:add_removed_bytes(),
emit(["}.",nl])
end.
gen_dec_postponed_decs(_,[]) ->
emit(nl);
gen_dec_postponed_decs(DecObj,[{_Cname,{FirstPFN,PFNList},Term,TmpTerm,_Tag,OptOrMand}|Rest]) ->
% asn1ct_name:new(term),
asn1ct_name:new(tmpterm),
asn1ct_name:new(reason),
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,Tag},", ",{asis,PFNList},")) of",nl}),
", ",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,
% emit({indent(3),"end,",nl}),
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(Erules,Typename,D) when is_record(D,type) ->
asn1ct_name:start(),
asn1ct_name:clear(),
asn1ct_name:new(term),
asn1ct_name:new(tag),
#'SET'{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,
emit([" %%-------------------------------------------------",nl]),
emit([" %% decode tag and length ",nl]),
emit([" %%-------------------------------------------------",nl]),
asn1ct_name:new(rb),
MyTag = [X#tag{class=asn1ct_gen_ber:decode_class(X#tag.class)}|| X <- D#type.tag]
++
[#tag{class = asn1ct_gen_ber:decode_class('UNIVERSAL'),
number = asn1ct_gen_ber:decode_type('SET'),
form = ?CONSTRUCTED,
type = 'IMPLICIT'}],
emit([" {{_,Len},",{next,bytes},",",{curr,rb},
"} = ?RT_BER:check_tags(TagIn ++ ",{asis,MyTag},", ",
{curr,bytes},", OptOrMand), ",nl]),
asn1ct_name:new(bytes),
asn1ct_name:new(len),
asn1ct_name:new(rb),
emit([" {SetTerm, SetBytes, ",{curr,rb},"} = ?RT_BER:decode_set(0, Len, ",
{curr,bytes},", OptOrMand, ",
"fun 'dec_",asn1ct_gen:list2name(Typename),"_fun'/2, []),",nl]),
asn1ct_name:new(rb),
{ExtFlatten1,ExtFlatten2} =
case Ext of
noext -> {"",""};
_ -> {"lists:flatten(",")"}
end,
emit([" 'dec_",asn1ct_gen:list2name(Typename),
"__result__'(lists:sort(",ExtFlatten1,"SetTerm",ExtFlatten2,"), SetBytes, "]),
asn1ct_gen_ber:add_removed_bytes(),
emit([").",nl,nl,nl]),
emit({"%%-------------------------------------------------",nl}),
emit({"%% Set loop fun for ",asn1ct_gen:list2name(Typename),nl}),
emit({"%%-------------------------------------------------",nl}),
asn1ct_name:clear(),
asn1ct_name:new(term),
emit(["'dec_",asn1ct_gen:list2name(Typename),"_fun'(",{curr,bytes},
", OptOrMand) ->",nl]),
asn1ct_name:new(bytes),
gen_dec_set(Erules,Typename,CompList,1,Ext),
emit([" %% tag not found, if extensionmark we should skip bytes here",nl]),
emit([indent(6),"_ -> ",nl]),
case Ext of
noext ->
emit([indent(9),"{[], Bytes,0}",nl]);
_ ->
asn1ct_name:new(rbCho),
emit([indent(9),"{RestBytes, ",{curr,rbCho},
"} = ?RT_BER:skipvalue(Bytes),",nl,
indent(9),"{[], RestBytes, ",{curr,rbCho},"}",nl])
end,
emit([indent(3),"end.",nl,nl,nl]),
emit({"%%-------------------------------------------------",nl}),
emit({"%% Result ",asn1ct_gen:list2name(Typename),nl}),
emit({"%%-------------------------------------------------",nl}),
asn1ct_name:clear(),
emit({"'dec_",asn1ct_gen:list2name(Typename),"__result__'(",
asn1ct_gen_ber:unused_var("TermList",D#type.def),", Bytes, Rb) ->",nl}),
RecordName = lists:concat([get_record_name_prefix(),
asn1ct_gen:list2rname(Typename)]),
case gen_dec_set_result(Erules,Typename,CompList) of
no_terms ->
%% return value as record
asn1ct_name:new(rb),
emit({" {{'",RecordName,"'}, Bytes, Rb}.",nl});
_ ->
emit({nl," case ",{curr,termList}," of",nl}),
emit({" [] -> {{'",RecordName,"', "}),
mkvlist(asn1ct_name:all(term)),
emit({"}, Bytes, Rb};",nl}),
emit({" ExtraAtt -> exit({error,{asn1,{too_many_attributes, ExtraAtt}}})",nl}),
emit({" end.",nl}),
emit({nl,nl,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}),
MyTag = [X#tag{class=asn1ct_gen_ber:decode_class(X#tag.class)}|| X <- D#type.tag]
++
[#tag{class = asn1ct_gen_ber:decode_class('UNIVERSAL'),
number = asn1ct_gen_ber:decode_type(SeqOrSetOf),
form = ?CONSTRUCTED,
type = 'IMPLICIT'}],
% gen_encode_tags(Erules,MyTag,"EncLen","EncBytes"),
emit([" ?RT_BER:encode_tags(TagIn ++ ",
{asis,MyTag},", EncBytes, EncLen).",nl,nl]),
gen_encode_sof_components(Erules,Typename,SeqOrSetOf,Cont).
% gen_enc_line(Erules,Typename,TypeNameSuffix,Cont,"H",0,
% mandatory,"{EncBytes,EncLen} = "),
gen_decode_sof(Erules,Typename,_InnerTypename,D) when is_record(D,type) ->
asn1ct_name:start(),
asn1ct_name:clear(),
{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(rb),
MyTag = [X#tag{class=asn1ct_gen_ber:decode_class(X#tag.class)}|| X <- D#type.tag]
++
[#tag{class = asn1ct_gen_ber:decode_class('UNIVERSAL'),
number = asn1ct_gen_ber:decode_type(TypeTag),
form = ?CONSTRUCTED,
type = 'IMPLICIT'}],
emit([" {{_,Len},",{next,bytes},",",{curr,rb},
"} = ?RT_BER:check_tags(TagIn ++ ",{asis,MyTag},", ",
{curr,bytes},", OptOrMand), ",nl]),
emit([" ?RT_BER:decode_components(",{curr,rb}]),
InnerType = asn1ct_gen:get_inner(Cont#type.def),
ContName = case asn1ct_gen:type(InnerType) of
Atom when is_atom(Atom) -> Atom;
_ -> TypeNameSuffix
end,
emit([", Len, ",{next,bytes},", "]),
% NewCont =
% case Cont#type.def of
% {'ENUMERATED',_,Components}->
% Cont#type{def={'ENUMERATED',Components}};
% _ -> Cont
% end,
ObjFun =
case D#type.tablecinf of
[{objfun,_}|_R] ->
", ObjFun";
_ ->
[]
end,
gen_dec_line_sof(Erules,Typename,ContName,Cont,ObjFun),
emit([", []).",nl,nl,nl]).
gen_encode_sof_components(Erules,Typename,SeqOrSetOf,Cont)
when is_record(Cont,type)->
{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 catch lists:member(der,get(encoding_options)) of
true when SeqOrSetOf=='SET OF' ->
emit([indent(3),
"{asn1rt_check: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(Erules,Typename,TypeNameSuffix,Cont,"H",3,
% mandatory,"{EncBytes,EncLen} = ",EncObj),
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),
CindexPos =
case Order of
undefined ->
Pos;
_ -> Order % der
end,
Element =
case TopType of
['EXTERNAL'] ->
io_lib:format("?RT_BER:cindex(~w,NewVal,~w)",[CindexPos+1,Cname]);
_ ->
io_lib:format("?RT_BER:cindex(~w,Val,~w)",[CindexPos+1,Cname])
end,
InnerType = asn1ct_gen:get_inner(Type#type.def),
print_attribute_comment(InnerType,Pos,Prop),
gen_enc_line(Erules,TopType,Cname,Type,Element,3,Prop,EncObj),
case Rest of
[] ->
emit({com,nl});
_ ->
emit({com,nl}),
gen_enc_sequence_call(Erules,TopType,Rest,Pos+1,Ext,EncObj)
end;
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,CList,Ext,DecObjInf) ->
gen_dec_sequence_call2(Erules,TopType,CList,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),
case Rest of
[] ->
{LA ++ LeadingAttrAcc,PostponedDec ++ ArgsAcc};
_ ->
emit({com,nl}),
% asn1ct_name:new(term),
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_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({com,nl}),
asn1ct_name:new(bytes),
emit([" {",{next,bytes},", ",{next,rb},
"} = ?RT_BER:skip_ExtensionAdditions(",
{curr,bytes},", ",{asis,TagList},"),",nl]),
asn1ct_name:new(rb),
asn1ct_name:new(bytes),
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])->H#tag{class=asn1ct_gen_ber:decode_class(H#tag.class)}
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
{_,{ext,Epos,_Root2pos}} when Pos < Epos ->
Prop;
{mandatory,{ext,Epos,_}} when Pos >= Epos ->
'OPTIONAL';
_ ->
Prop
end,
print_attribute_comment(InnerType,Pos,Prop1),
emit(" "),
case {InnerType,DecObjInf} of
{{typefield,_},NotFalse} when NotFalse /= false ->
asn1ct_name:new(term),
asn1ct_name:new(tmpterm),
emit({"{",{curr,tmpterm},", ",{next,bytes},",",{next,rb},"} = "});
{{objectfield,_,_},_} ->
asn1ct_name:new(term),
asn1ct_name:new(tmpterm),
emit({"{",{curr,tmpterm},", ",{next,bytes},",",{next,rb},"} = "});
_ ->
asn1ct_name:new(term),
emit({"{",{curr,term},",",{next,bytes},",",{next,rb},"} = "})
end,
asn1ct_name:new(rb),
PostponedDec =
gen_dec_line(Erules,TopType,Cname,CTags,Type,Prop1,DecObjInf),
asn1ct_name:new(form),
PostponedDec.
%%-------------------------------------
%% Decode SET
%%-------------------------------------
gen_dec_set(Erules,TopType,CompList,Pos,Ext) ->
ExtCatch = case Ext of
noext ->"";
_ -> " catch"
end,
TagList = get_all_choice_tags(CompList),
emit({indent(3),
{curr,tagList}," = ",{asis,TagList},",",nl}),
emit({indent(3),
"case",ExtCatch," ?RT_BER:check_if_valid_tag(Bytes, ",
{curr,tagList},", OptOrMand) of",nl}),
asn1ct_name:new(tagList),
asn1ct_name:new(rbCho),
asn1ct_name:new(choTags),
gen_dec_set_cases(Erules,TopType,CompList,TagList,Pos),
asn1ct_name:new(tag),
asn1ct_name:new(bytes).
gen_dec_set_cases(_,_,[],_,_) ->
ok;
gen_dec_set_cases(Erules,TopType,[H|T],List,Pos) ->
Name = H#'ComponentType'.name,
Type = H#'ComponentType'.typespec,
emit({indent(6),"'",Name,"' ->",nl}),
case Type#type.def of
{'CHOICE',_NewCompList} ->
gen_dec_set_cases_choice(Erules,TopType,H,Pos);
_ ->
gen_dec_set_cases_type(Erules,TopType,H,Pos)
end,
gen_dec_set_cases(Erules,TopType,T,List,Pos+1).
gen_dec_set_cases_choice(_Erules,TopType,H,Pos) ->
Cname = H#'ComponentType'.name,
Tag = [X#tag{class=asn1ct_gen_ber:decode_class(X#tag.class)}
|| X <- (H#'ComponentType'.typespec)#type.tag],
asn1ct_name:new(rbCho),
emit({indent(9),"{Dec, Rest, ",{curr,rbCho},"} = "}),
emit({"'dec_",asn1ct_gen:list2name([Cname|TopType]),
"'(Bytes,OptOrMand,",{asis,Tag},"),",nl}),
emit([" {{",Pos,",Dec}, Rest, ",{curr,rbCho},"}"]),
emit([";",nl,nl]).
gen_dec_set_cases_type(Erules,TopType,H,Pos) ->
Cname = H#'ComponentType'.name,
Type = H#'ComponentType'.typespec,
%% always use Prop = mandatory here Prop = H#'ComponentType'.prop,
asn1ct_name:new(rbCho),
emit({indent(9),"{Dec, Rest, ",{curr,rbCho},"} = "}),
asn1ct_name:delete(bytes),
%% we have already seen the tag so now we must find the value
%% that why we always use 'mandatory' here
gen_dec_line(Erules,TopType,Cname,[],Type,mandatory,decObjInf),
asn1ct_name:new(bytes),
emit([",",nl]),
emit(["{{",Pos,",Dec}, Rest, ",{curr,rbCho},"}"]),
emit([";",nl,nl]).
%%---------------------------------
%% Decode SET result
%%---------------------------------
gen_dec_set_result(Erules,TopType,CompList) ->
gen_dec_set_result1(Erules,TopType, CompList, 1).
gen_dec_set_result1(Erules,TopType,
[#'ComponentType'{name=Cname,
typespec=Type,
prop=Prop}|Rest],Num) ->
gen_dec_set_component(Erules,TopType,Cname,Type,Num,Prop),
case Rest of
[] ->
true;
_ ->
gen_dec_set_result1(Erules,TopType,Rest,Num+1)
end;
gen_dec_set_result1(_Erules,_TopType,[],1) ->
no_terms;
gen_dec_set_result1(_Erules,_TopType,[],_Num) ->
true.
gen_dec_set_component(_Erules,_TopType,_Cname,Type,Pos,Prop) ->
InnerType = asn1ct_gen:get_inner(Type#type.def),
print_attribute_comment(InnerType,Pos,Prop),
emit({" {",{next,term},com,{next,termList},"} =",nl}),
emit({" case ",{curr,termList}," of",nl}),
emit({" [{",Pos,com,{curr,termTmp},"}|",
{curr,rest},"] -> "}),
emit({"{",{curr,termTmp},com,
{curr,rest},"};",nl}),
case Prop of
'OPTIONAL' ->
emit([indent(10),"_ -> {asn1_NOVALUE, ",{curr,termList},"}",nl]);
{'DEFAULT', DefVal} ->
emit([indent(10),
"_ -> {",{asis,DefVal},", ",{curr,termList},"}",nl]);
mandatory ->
emit([indent(10),
"_ -> exit({error,{asn1,{mandatory_attribute_no, ",
Pos,", missing}}})",nl])
end,
emit([indent(6),"end,",nl]),
asn1ct_name:new(rest),
asn1ct_name:new(term),
asn1ct_name:new(termList),
asn1ct_name:new(termTmp).
%%---------------------------------------------
%% 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]),
NewTag = [X#tag{class=asn1ct_gen_ber:decode_class(X#tag.class)}|| X <- Tag],
% gen_encode_tags(Erules,NewTag,"EncLen","EncBytes").
emit(["?RT_BER:encode_tags(TagIn ++",{asis,NewTag},", EncBytes, EncLen).",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 asn1ct_gen:get_constraint(Type#type.constraint,
% tableconstraint_info) of
case {Type#type.def,asn1ct_gen:get_constraint(Type#type.constraint,
componentrelation)} of
{#'ObjectClassFieldType'{},{componentrelation,_,_}} ->
asn1ct_name:new(tmpBytes),
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(_,_,[]) ->
true.
%%--------------------------------------------
%% Decode CHOICE
%%--------------------------------------------
gen_dec_choice(Erules,TopType, ChTag, CompList, Ext) ->
asn1ct_name:delete(bytes),
Tags = [X#tag{class=asn1ct_gen_ber:decode_class(X#tag.class)}|| X <- ChTag],
emit([" {{_,Len},",{next,bytes},
", RbExp} = ?RT_BER:check_tags(TagIn++",
{asis,Tags},", ",
{curr,bytes},", OptOrMand),",nl]),
asn1ct_name:new(bytes),
asn1ct_name:new(len),
gen_dec_choice_indef_funs(Erules),
case Erules of
ber_bin ->
emit([indent(3),"case ",{curr,bytes}," of",nl]);
ber ->
emit([indent(3),
"case (catch ?RT_BER:peek_tag(",{curr,bytes},")) of",nl])
end,
asn1ct_name:new(tagList),
asn1ct_name:new(choTags),
gen_dec_choice_cases(Erules,TopType,CompList),
case Ext of
noext ->
emit([indent(6), {curr,else}," -> ",nl]),
emit([indent(9),"case OptOrMand of",nl,
indent(12),"mandatory ->","exit({error,{asn1,",
"{invalid_choice_tag,",{curr,else},"}}});",nl,
indent(12),"_ ->","exit({error,{asn1,{no_optional_tag,",
{curr,else},"}}})",nl,
indent(9),"end",nl]);
_ ->
emit([indent(6),"_ -> ",nl]),
emit([indent(9),"{{asn1_ExtAlt,",{curr,bytes},"},",
empty_lb(Erules),", RbExp}",nl])
end,
emit([indent(3),"end"]),
asn1ct_name:new(tag),
asn1ct_name:new(else).
gen_dec_choice_indef_funs(Erules) ->
emit({indent(3),"IndefEndBytes = fun(indefinite,",indefend_match(Erules,used_var),
")-> R; (_,B)-> B end,",nl}),
emit({indent(3),"IndefEndRb = fun(indefinite,",indefend_match(Erules,unused_var),
")-> 2; (_,_)-> 0 end,",nl}).
gen_dec_choice_cases(_,_, []) ->
ok;
gen_dec_choice_cases(Erules,TopType, [H|T]) ->
asn1ct_name:push(rbCho),
Name = H#'ComponentType'.name,
emit([nl,"%% '",Name,"'",nl]),
Fcases = fun([T1,T2|Tail],Fun) ->
emit([indent(6),match_tag(Erules,T1)," ->",nl]),
gen_dec_choice_cases_type(Erules,TopType, H),
Fun([T2|Tail],Fun);
([T1],_) ->
emit([indent(6),match_tag(Erules,T1)," ->",nl]),
gen_dec_choice_cases_type(Erules,TopType, H)
end,
Fcases(H#'ComponentType'.tags,Fcases),
asn1ct_name:pop(rbCho),
gen_dec_choice_cases(Erules,TopType, T).
gen_dec_choice_cases_type(Erules,TopType,H) ->
Cname = H#'ComponentType'.name,
Type = H#'ComponentType'.typespec,
Prop = H#'ComponentType'.prop,
emit({indent(9),"{Dec, Rest, ",{curr,rbCho},"} = "}),
gen_dec_line(Erules,TopType,Cname,[],Type,Prop,false),
emit([",",nl,indent(9),"{{",{asis,Cname},
", Dec}, IndefEndBytes(Len,Rest), RbExp + ",
{curr,rbCho}," + IndefEndRb(Len,Rest)};",nl,nl]).
encode_tag_val(Erules,{Class,TagNo}) when is_integer(TagNo) ->
Rtmod = rtmod(Erules),
Rtmod:encode_tag_val({asn1ct_gen_ber:decode_class(Class),
0,TagNo});
encode_tag_val(Erules,{Class,TypeName}) ->
Rtmod = rtmod(Erules),
Rtmod:encode_tag_val({asn1ct_gen_ber:decode_class(Class),
0,asn1ct_gen_ber:decode_type(TypeName)}).
match_tag(ber_bin,Arg) ->
match_tag_with_bitsyntax(Arg);
match_tag(Erules,Arg) ->
io_lib:format("~p",[encode_tag_val(Erules,Arg)]).
match_tag_with_bitsyntax({Class,TagNo}) when is_integer(TagNo) ->
match_tag_with_bitsyntax1({asn1ct_gen_ber:decode_class(Class),
0,TagNo});
match_tag_with_bitsyntax({Class,TypeName}) ->
match_tag_with_bitsyntax1({asn1ct_gen_ber:decode_class(Class),
0,asn1ct_gen_ber:decode_type(TypeName)}).
match_tag_with_bitsyntax1({Class, _Form, TagNo}) when (TagNo =< 30) ->
io_lib:format("<<~p:2,_:1,~p:5,_/binary>>",[Class bsr 6,TagNo]);
match_tag_with_bitsyntax1({Class, _Form, TagNo}) ->
{Octets,Len} = mk_object_val(TagNo),
OctForm = case Len of
1 -> "~p";
2 -> "~p,~p";
3 -> "~p,~p,~p";
4 -> "~p,~p,~p,~p"
end,
io_lib:format("<<~p:2,_:1,31:5," ++ OctForm ++ ",_/binary>>",
[Class bsr 6] ++ Octets).
%%%%%%%%%%%
%% mk_object_val(Value) -> {OctetList, Len}
%% returns a Val as a list of octets, the 8 bit is allways set to one except
%% for the last octet, where its 0
%%
mk_object_val(Val) when Val =< 127 ->
{[255 band Val], 1};
mk_object_val(Val) ->
mk_object_val(Val bsr 7, [Val band 127], 1).
mk_object_val(0, Ack, Len) ->
{Ack, Len};
mk_object_val(Val, Ack, Len) ->
mk_object_val(Val bsr 7, [((Val band 127) bor 128) | Ack], Len + 1).
get_all_choice_tags(ComponentTypeList) ->
get_all_choice_tags(ComponentTypeList,[]).
get_all_choice_tags([],TagList) ->
TagList;
get_all_choice_tags([H|T],TagList) ->
Tags = H#'ComponentType'.tags,
get_all_choice_tags(T, TagList ++ [{H#'ComponentType'.name, Tags}]).
%%---------------------------------------
%% 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,_,_} ->
asn1ct_name:new(tmpBytes),
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 = [X#tag{class=asn1ct_gen_ber:decode_class(X#tag.class)}
|| 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,InnerType,WhatKind,
Element),
case {Type,asn1ct_gen:get_constraint(Type#type.constraint,
componentrelation)} of
{#type{def=#'ObjectClassFieldType'{type={typefield,_},
fieldname=RefedFieldName}},
{componentrelation,_,_}} ->
{_LeadingAttrName,Fun} = EncObj,
case RefedFieldName of
{Name,RestFieldNames} when is_atom(Name),Name =/= notype ->
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},"} = "}),
emit({"?RT_BER:encode_open_type(",{curr,tmpBytes},
",",{asis,Tag},")"});
_ ->
emit({"{",{next,tmpBytes},", ",{curr,tmpLen},
"} = "}),
emit({"?RT_BER:encode_open_type(",{curr,tmpBytes},
",",{asis,Tag},"),",nl}),
emit(IndDeep),
emit({"{",{next,tmpBytes},", ",{curr,tmpLen},"}"})
end;
Err ->
throw({asn1,{'internal error',Err}})
end;
_ ->
case WhatKind of
{primitive,bif} ->
EncType =
case Type#type.def of
#'ObjectClassFieldType'{
type={fixedtypevaluefield,
_,Btype}} ->
Btype;
_ ->
Type
end,
asn1ct_gen_ber:gen_encode_prim(ber,EncType,{asis,Tag},
Element);
'ASN1_OPEN_TYPE' ->
asn1ct_gen_ber:gen_encode_prim(ber,Type#type{def='ASN1_OPEN_TYPE'},{asis,Tag},Element);
_ ->
{EncFunName, _, _} =
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,_,_,_,_,_,_, _) ->
ok;
gen_optormand_case('OPTIONAL',Erules,_,_,_,_,_,Element) ->
emit({" case ",Element," of",nl}),
emit({indent(9),"asn1_NOVALUE -> {",
empty_lb(Erules),",0};",nl}),
emit({indent(9),"_ ->",nl,indent(12)});
gen_optormand_case({'DEFAULT',DefaultValue},Erules,TopType,Cname,Type,
InnerType,WhatKind,Element) ->
CurrMod = get(currmod),
case catch lists:member(der,get(encoding_options)) of
true ->
emit(" case catch "),
asn1ct_gen:gen_check_call(TopType,Cname,Type,InnerType,
WhatKind,{asis,DefaultValue},
Element),
emit({" of",nl}),
emit({indent(12),"true -> {[],0};",nl});
_ ->
emit({" case ",Element," of",nl}),
emit({indent(9),"asn1_DEFAULT -> {",
empty_lb(Erules),
",0};",nl}),
case DefaultValue of
#'Externalvaluereference'{module=CurrMod,
value=V} ->
emit({indent(9),"?",{asis,V}," -> {",
empty_lb(Erules),",0};",nl});
_ ->
emit({indent(9),{asis,
DefaultValue}," -> {",
empty_lb(Erules),",0};",nl})
end
end,
emit({indent(9),"_ ->",nl,indent(12)}).
gen_dec_line_sof(Erules,TopType,Cname,Type,ObjFun) ->
Tag = [X#tag{class=asn1ct_gen_ber:decode_class(X#tag.class)}
|| X <- Type#type.tag],
InnerType = asn1ct_gen:get_inner(Type#type.def),
WhatKind = asn1ct_gen:type(InnerType),
case WhatKind of
{primitive,bif} ->
asn1ct_name:delete(len),
asn1ct_name:new(len),
emit(["fun(FBytes,_,_)->",nl]),
EncType = case Type#type.def of
#'ObjectClassFieldType'{
type={fixedtypevaluefield,
_,Btype}} ->
Btype;
_ ->
Type
end,
asn1ct_gen_ber:gen_dec_prim(ber,EncType,"FBytes",Tag,
[],no_length,?PRIMITIVE,
mandatory),
emit([nl,"end, []"]);
_ ->
case ObjFun of
[] ->
{DecFunName, _, _} =
mkfunname(Erules,TopType,Cname,WhatKind,dec,3),
emit([DecFunName,", ",{asis,Tag}]);
_ ->
{DecFunName, _, _} =
mkfunname(Erules,TopType,Cname,WhatKind,dec,4),
emit([DecFunName,", ",{asis,Tag},", ObjFun"])
end
end.
gen_dec_line(Erules,TopType,Cname,CTags,Type,OptOrMand,DecObjInf) ->
BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
Tag = [X#tag{class=asn1ct_gen_ber:decode_class(X#tag.class)}
|| X <- Type#type.tag],
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
case {CTags,Erules} of
{[CTag],ber_bin} when CTag =/= [] -> % R9C-0.patch-34
emit(["case ",{curr,bytes}," of",nl]),
emit([match_tag(Erules,CTag)," ->",nl]),
PostponedDec =
gen_dec_call(InnerType,Erules,TopType,Cname,Type,
BytesVar,Tag,mandatory,
", opt_or_default, ",DecObjInf,
OptOrMand),
emit([";",nl]),
emit(["_ ->",nl]),
case OptOrMand of
{'DEFAULT', Def} ->
emit(["{",{asis,Def},",",
BytesVar,", 0 }",nl]);
'OPTIONAL' ->
emit(["{ asn1_NOVALUE, ",
BytesVar,", 0 }",nl])
end,
emit("end"),
PostponedDec;
_ ->
emit("case (catch "),
PostponedDec =
gen_dec_call(InnerType,Erules,TopType,Cname,Type,
BytesVar,Tag,OptOrMand,
", opt_or_default, ",DecObjInf,
OptOrMand),
emit([") of",nl]),
case OptOrMand of
{'DEFAULT', Def} ->
emit(["{'EXIT',{error,{asn1,{no_optional_tag,_}}}}",
" -> {",{asis,Def},",",
BytesVar,", 0 };",nl]);
'OPTIONAL' ->
emit(["{'EXIT',{error,{asn1,{no_optional_tag,_}}}}",
" -> { asn1_NOVALUE, ",
BytesVar,", 0 };",nl])
end,
asn1ct_name:new(casetmp),
emit([{curr,casetmp},"-> ",{curr,casetmp},nl,"end"]),
PostponedDec
end
end,
case DecObjInf of
{Cname,ObjSet} -> % this must be the component were an object is
%% choosen 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,_},Erules,_,_,Type,_,Tag,_,_,false,_) ->
%% this in case of a choice with typefield components
asn1ct_name:new(reason),
{FirstPFName,RestPFName} =
% asn1ct_gen:get_constraint(Type#type.constraint,
% tableconstraint_info),
(Type#type.def)#'ObjectClassFieldType'.fieldname,
emit([nl,indent(6),"begin",nl]),
emit([indent(9),"{OpenDec,TmpRest,TmpRbCho} =",nl,indent(12),
"?RT_BER:decode_open_type(",Erules,",",{curr,bytes},",",
{asis,Tag},"),",nl]),
emit([indent(9),"case (catch ObjFun(",{asis,FirstPFName},
", OpenDec, [], ",{asis,RestPFName},
")) of", nl]),%% ??? What about Tag
emit([indent(12),"{'EXIT',",{curr,reason},"} ->",nl]),
%% emit({indent(15),"throw({runtime_error,{'Type not ",
%% "compatible with tableconstraint', OpenDec}});",nl}),
emit([indent(15),"exit({'Type not ",
"compatible with table constraint', ",{curr,reason},"});",nl]),
emit([indent(12),"{TmpDec,_ ,_} ->",nl]),
emit([indent(15),"{TmpDec, TmpRest, TmpRbCho}",nl]),
emit([indent(9),"end",nl,indent(6),"end",nl]),
[];
gen_dec_call({typefield,_},_Erules,_,Cname,Type,_BytesVar,Tag,_,_,
_DecObjInf,OptOrMandComp) ->
emit(["?RT_BER:decode_open_type(",{curr,bytes},",",{asis,Tag},")"]),
RefedFieldName =
(Type#type.def)#'ObjectClassFieldType'.fieldname,
% asn1ct_gen:get_constraint(Type#type.constraint,
% tableconstraint_info),
[{Cname,RefedFieldName,
asn1ct_gen:mk_var(asn1ct_name:curr(term)),
% asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),[],OptOrMandComp}];
asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),Tag,OptOrMandComp}];
gen_dec_call({objectfield,PrimFieldName,PFNList},_Erules,_,Cname,_,_,Tag,_,_,_,
OptOrMandComp) ->
emit(["?RT_BER:decode_open_type(",{curr,bytes},",",{asis,Tag},")"]),
[{Cname,{PrimFieldName,PFNList},
asn1ct_gen:mk_var(asn1ct_name:curr(term)),
% asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),[],OptOrMandComp}];
asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),Tag,OptOrMandComp}];
gen_dec_call(InnerType,Erules,TopType,Cname,Type,BytesVar,Tag,PrimOptOrMand,
OptOrMand,DecObjInf,_) ->
WhatKind = asn1ct_gen:type(InnerType),
gen_dec_call1(WhatKind,InnerType,Erules,TopType,Cname,Type,BytesVar,Tag,
PrimOptOrMand,OptOrMand),
case DecObjInf 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}
end,
emit({",",nl,"ObjFun = ",ObjSetMod,":'getdec_",ObjSetName,"'(",
{asis,UniqueFName},", ",ValueMatch,")"});
_ ->
ok
end,
[].
gen_dec_call1({primitive,bif},InnerType,Erules,_,_,Type,BytesVar,
Tag,OptOrMand,_) ->
case InnerType of
{fixedtypevaluefield,_,Btype} ->
asn1ct_gen_ber:gen_dec_prim(Erules,Btype,BytesVar,Tag,[],no_length,
?PRIMITIVE,OptOrMand);
_ ->
asn1ct_gen_ber:gen_dec_prim(Erules,Type,BytesVar,Tag,[],no_length,
?PRIMITIVE,OptOrMand)
end;
gen_dec_call1('ASN1_OPEN_TYPE',_InnerType,Erules,_,_,Type,BytesVar,
Tag,OptOrMand,_) ->
asn1ct_gen_ber:gen_dec_prim(Erules,Type#type{def='ASN1_OPEN_TYPE'},
BytesVar,Tag,[],no_length,
?PRIMITIVE,OptOrMand);
gen_dec_call1(WhatKind,_,_Erules,TopType,Cname,Type,_,Tag,_,OptOrMand) ->
{DecFunName,_,_} =
mkfuncname(TopType,Cname,WhatKind,dec),
case {WhatKind,Type#type.tablecinf} of
{{constructed,bif},[{objfun,_}|_R]} ->
emit({DecFunName,"(",{curr,bytes},OptOrMand,{asis,Tag},", ObjFun)"});
_ ->
emit({DecFunName,"(",{curr,bytes},OptOrMand,{asis,Tag},")"})
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,_ExtL,_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,Prop) ->
CommentLine = "%%-------------------------------------------------",
emit([nl,CommentLine]),
case InnerType of
{typereference,_,Name} ->
emit([nl,"%% attribute number ",Pos," with type ",Name]);
{'Externaltypereference',_,XModule,Name} ->
emit([nl,"%% attribute number ",Pos," External ",XModule,":",Name]);
_ ->
emit([nl,"%% attribute number ",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,DecOrEnc) ->
CurrMod = get(currmod),
case WhatKind of
#'Externaltypereference'{module=CurrMod,type=EType} ->
F = lists:concat(["'",DecOrEnc,"_",EType,"'"]),
{F, "?MODULE", F};
#'Externaltypereference'{module=Mod,type=EType} ->
{lists:concat(["'",Mod,"':'",DecOrEnc,"_",EType,"'"]),Mod,
lists:concat(["'",DecOrEnc,"_",EType,"'"])};
{constructed,bif} ->
F = lists:concat(["'",DecOrEnc,"_",asn1ct_gen:list2name([Cname|TopType]),"'"]),
{F, "?MODULE", F}
end.
mkfunname(Erule,TopType,Cname,WhatKind,DecOrEnc,Arity) ->
CurrMod = get(currmod),
case WhatKind of
#'Externaltypereference'{module=CurrMod,type=EType} ->
F = lists:concat(["fun '",DecOrEnc,"_",EType,"'/",Arity]),
{F, "?MODULE", F};
#'Externaltypereference'{module=Mod,type=EType} ->
{lists:concat(["fun '",Mod,"':'",DecOrEnc,"_",EType,"'/",Arity]),Mod,
lists:concat(["'",DecOrEnc,"_",EType,"'"])};
{constructed,bif} ->
F =
lists:concat(["fun '",DecOrEnc,"_",
asn1ct_gen:list2name([Cname|TopType]),"'/",
Arity]),
{F, "?MODULE", F};
'ASN1_OPEN_TYPE' ->
case Arity of
3 ->
F = lists:concat(["fun(A,_,C) -> ?RT_BER:decode_open_type(",Erule,",A,C) end"]),
{F, "?MODULE", F};
4 ->
F = lists:concat(["fun(A,_,C,_) -> ?RT_BER:decode_open_type(",Erule,",A,C) end"]),
{F, "?MODULE", F}
end
end.
empty_lb(ber) ->
"[]";
empty_lb(ber_bin) ->
"<<>>".
rtmod(ber) ->
list_to_atom(?RT_BER_BIN);
rtmod(ber_bin) ->
list_to_atom(?RT_BER_BIN).
indefend_match(ber,used_var) ->
"[0,0|R]";
indefend_match(ber,unused_var) ->
"[0,0|_R]";
indefend_match(ber_bin,used_var) ->
"<<0,0,R/binary>>";
indefend_match(ber_bin,unused_var) ->
"<<0,0,_R/binary>>".
notice_value_match() ->
Module = get(currmod),
put(value_match,{true,Module}).
value_match(Index,Value) when is_atom(Value) ->
value_match(Index,atom_to_list(Value));
value_match([],Value) ->
Value;
value_match([{VI,_Cname}|VIs],Value) ->
value_match1(Value,VIs,lists:concat(["element(",VI,","]),1).
value_match1(Value,[],Acc,Depth) ->
Acc ++ Value ++ lists:concat(lists:duplicate(Depth,")"));
value_match1(Value,[{VI,_Cname}|VIs],Acc,Depth) ->
value_match1(Value,VIs,Acc++lists:concat(["element(",VI,","]),Depth+1).