1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2002-2017. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20%%
21-module(asn1ct_constructed_ber_bin_v2).
22
23-export([gen_encode_sequence/3]).
24-export([gen_decode_sequence/3]).
25-export([gen_encode_set/3]).
26-export([gen_decode_set/3]).
27-export([gen_encode_sof/4]).
28-export([gen_decode_sof/4]).
29-export([gen_encode_choice/3]).
30-export([gen_decode_choice/3]).
31
32
33-include("asn1_records.hrl").
34
35-import(asn1ct_gen, [emit/1,get_record_name_prefix/1]).
36
37-define(ASN1CT_GEN_BER,asn1ct_gen_ber_bin_v2).
38
39%% the encoding of class of tag bits 8 and 7
40-define(UNIVERSAL,   0).
41-define(APPLICATION, 16#40).
42-define(CONTEXT,     16#80).
43-define(PRIVATE,     16#C0).
44
45%% primitive or constructed encoding % bit 6
46-define(PRIMITIVE,   0).
47-define(CONSTRUCTED, 2#00100000).
48
49
50
51
52%%===============================================================================
53%%===============================================================================
54%%===============================================================================
55%%  Encode/decode SEQUENCE (and SET)
56%%===============================================================================
57%%===============================================================================
58%%===============================================================================
59
60gen_encode_sequence(Gen, Typename, #type{}=D) ->
61    asn1ct_name:start(),
62    asn1ct_name:new(term),
63    asn1ct_name:new(bytes),
64
65    %% if EXTERNAL type the input value must be transformed to
66    %% ASN1 1990 format
67    ValName =
68	case Typename of
69	    ['EXTERNAL'] ->
70                Tr = case Gen of
71                         #gen{pack=record} -> transform_to_EXTERNAL1990;
72                         #gen{pack=map} -> transform_to_EXTERNAL1990_maps
73                     end,
74		emit([indent(4),"NewVal = ",
75		      {call,ext,Tr,["Val"]},
76		      com,nl]),
77		"NewVal";
78	    _ ->
79	    "Val"
80	end,
81
82    {SeqOrSet,TableConsInfo,CompList0} =
83	case D#type.def of
84	    #'SEQUENCE'{tablecinf=TCI,components=CL} ->
85		{'SEQUENCE',TCI,CL};
86	    #'SET'{tablecinf=TCI,components=CL} ->
87		{'SET',TCI,CL}
88	end,
89    %% filter away extensionAdditiongroup markers
90    CompList = filter_complist(CompList0),
91    Ext = extensible(CompList),
92    CompList1 = case CompList of
93		    {Rl1,El,Rl2} -> Rl1 ++ El ++ Rl2;
94		    {Rl,El} -> Rl ++ El;
95		    _ -> CompList
96		end,
97
98    enc_match_input(Gen, ValName, CompList1),
99
100    EncObj =
101	case TableConsInfo of
102	    #simpletableattributes{usedclassfield=Used,
103				   uniqueclassfield=Unique} when Used /= Unique ->
104		false;
105	    %% ObjectSet, name of the object set in constraints
106	    #simpletableattributes{objectsetname=ObjectSetRef,
107				   c_name=AttrN,
108				   c_index=N,
109				   usedclassfield=UniqueFieldName,
110				   uniqueclassfield=UniqueFieldName,
111				   valueindex=ValueIndex} -> %% N is index of attribute that determines constraint
112		{ObjSetMod,ObjSetName} = ObjectSetRef,
113		OSDef = asn1_db:dbget(ObjSetMod, ObjSetName),
114		case (OSDef#typedef.typespec)#'ObjectSet'.gen of
115		    true ->
116			ObjectEncode =
117			    asn1ct_gen:un_hyphen_var(lists:concat(['Obj',
118								   AttrN])),
119			emit([ObjectEncode," = ",nl,
120			      "   ",{asis,ObjSetMod},":'getenc_",ObjSetName,
121			      "'("]),
122			ValueMatch = value_match(Gen, ValueIndex,
123						 lists:concat(["Cindex",N])),
124			emit([indent(35),ValueMatch,"),",nl]),
125			{AttrN,ObjectEncode};
126		    _ ->
127			false
128		end;
129	    _ ->
130		case D#type.tablecinf of
131		    [{objfun,_}|_] ->
132			%% when the simpletableattributes was at an outer
133			%% level and the objfun has been passed through the
134			%% function call
135			{"got objfun through args","ObjFun"};
136		    _ ->
137			false
138		end
139	end,
140
141    gen_enc_sequence_call(Gen, Typename, CompList1, 1, Ext, EncObj),
142
143    emit([nl,"   BytesSoFar = "]),
144    case SeqOrSet of
145	'SET' when (D#type.def)#'SET'.sorted == dynamic ->
146	    asn1ct_func:need({ber,dynamicsort_SET_components,1}),
147	    emit("dynamicsort_SET_components(["),
148	    mkvlist(asn1ct_name:all(encBytes)),
149	    emit(["]),",nl]);
150	_ ->
151	    emit("["),
152	    mkvlist(asn1ct_name:all(encBytes)),
153	    emit(["],",nl])
154    end,
155    emit("LenSoFar = "),
156    case asn1ct_name:all(encLen) of
157	[] -> emit("0");
158	AllLengths ->
159	    mkvplus(AllLengths)
160    end,
161    emit([",",nl]),
162    call(encode_tags, ["TagIn","BytesSoFar","LenSoFar"]),
163    emit([".",nl]).
164
165enc_match_input(#gen{pack=record}, ValName, CompList) ->
166    Len = length(CompList),
167    Vars = [lists:concat(["Cindex",N]) || N <- lists:seq(1, Len)],
168    RecordName = "_",
169    emit(["{",lists:join(",", [RecordName|Vars]),"} = ",ValName,com,nl]);
170enc_match_input(#gen{pack=map}, ValName, CompList) ->
171    Len = length(CompList),
172    Vars = [lists:concat(["Cindex",N]) || N <- lists:seq(1, Len)],
173    Zipped = lists:zip(CompList, Vars),
174    M = [[{asis,Name},":=",Var] ||
175            {#'ComponentType'{prop=mandatory,name=Name},Var} <- Zipped],
176    case M of
177        [] ->
178            ok;
179        [_|_] ->
180            emit(["#{",lists:join(",", M),"} = ",ValName,com,nl])
181    end,
182    Os0 = [{Name,Var} ||
183              {#'ComponentType'{prop=Prop,name=Name},Var} <- Zipped,
184              Prop =/= mandatory],
185    F = fun({Name,Var}) ->
186                [Var," = case ",ValName," of\n"
187                 "  #{",{asis,Name},":=",Var,"_0} -> ",
188                 Var,"_0;\n"
189                 "  _ -> ",atom_to_list(?MISSING_IN_MAP),"\n"
190                 "end"]
191        end,
192    emit(lists:join(",\n", [F(E) || E <- Os0]++[[]])).
193
194gen_decode_sequence(Gen, Typename, #type{}=D) ->
195    asn1ct_name:start(),
196    asn1ct_name:new(tag),
197    #'SEQUENCE'{tablecinf=TableConsInfo,components=CList0} = D#type.def,
198
199    %% filter away extensionAdditiongroup markers
200    CList = filter_complist(CList0),
201    Ext = extensible(CList),
202    {CompList,CompList2} =
203	case CList of
204	    {Rl1,El,Rl2} -> {Rl1 ++ El ++ Rl2, CList};
205	    {Rl,El}  -> {Rl ++ El, Rl ++ El};
206	    _ -> {CList, CList}
207	end,
208
209    emit(["   %%-------------------------------------------------",nl]),
210    emit(["   %% decode tag and length ",nl]),
211    emit(["   %%-------------------------------------------------",nl]),
212
213    asn1ct_name:new(tlv),
214    case CompList of
215	[] -> % empty sequence
216	    true;
217	_ ->
218	    emit([{curr,tlv}," = "])
219    end,
220    call(match_tags, [{prev,tlv},"TagIn"]),
221    emit([com,nl]),
222    asn1ct_name:new(tlv),
223    asn1ct_name:new(v),
224
225    {DecObjInf,ValueIndex} =
226	case TableConsInfo of
227	    #simpletableattributes{objectsetname=ObjectSetRef,
228				   c_name=AttrN,
229				   usedclassfield=UniqueFieldName,
230				   uniqueclassfield=UniqueFieldName,
231				   valueindex=ValIndex} ->
232		F = fun(#'ComponentType'{typespec=CT})->
233			    case {asn1ct_gen:get_constraint(CT#type.constraint,componentrelation),CT#type.tablecinf} of
234				{no,[{objfun,_}|_]} -> true;
235				_ -> false
236			    end
237		    end,
238		case lists:any(F,CompList) of
239		    true -> % when component relation constraint establish
240			%% relation from a component to another components
241			%% subtype component
242			{{AttrN,{deep,ObjectSetRef,UniqueFieldName,ValIndex}},
243			 ValIndex};
244		    false ->
245			{{AttrN,ObjectSetRef},ValIndex}
246		end;
247	    _ ->
248		{false,false}
249	end,
250    RecordName0 = lists:concat([get_record_name_prefix(Gen),
251                                asn1ct_gen:list2rname(Typename)]),
252    RecordName = list_to_atom(RecordName0),
253    case gen_dec_sequence_call(Gen, Typename, CompList2, Ext, DecObjInf) of
254	no_terms ->                           % an empty sequence
255	    asn1ct_name:new(rb),
256            case Gen of
257                #gen{pack=record} ->
258                    emit([nl,nl,
259                          "   {'",RecordName,"'}.",nl,nl]);
260                #gen{pack=map} ->
261                    emit([nl,nl,
262                          "   #{}.",nl,nl])
263            end;
264	{LeadingAttrTerm,PostponedDecArgs} ->
265	    emit([nl]),
266	    case {LeadingAttrTerm,PostponedDecArgs} of
267		{[],[]} ->
268		    ok;
269		{_,[]} ->
270		    ok;
271		{[{ObjSetRef,LeadingAttr,Term}],PostponedDecArgs} ->
272		    DecObj = asn1ct_gen:un_hyphen_var(lists:concat(['DecObj',LeadingAttr,Term])),
273		    ValueMatch = value_match(Gen, ValueIndex,Term),
274		    {ObjSetMod,ObjSetName} = ObjSetRef,
275		    emit([DecObj," =",nl,
276			  "   ",{asis,ObjSetMod},":'getdec_",ObjSetName,"'(",
277			  ValueMatch,"),",nl]),
278		    gen_dec_postponed_decs(DecObj,PostponedDecArgs)
279	    end,
280	    %% return value as record
281	    case Ext of
282		{ext,_,_} ->
283		    emit(["case ",{prev,tlv}," of [] -> true; _ -> true end, % ... extra fields skipped",nl]);
284		_ ->
285                    %% noext | extensible
286		    emit(["case ",{prev,tlv}," of",nl,
287			  "[] -> true;",
288			  "_ -> exit({error,{asn1, {unexpected,",{prev,tlv},
289			  "}}}) % extra fields not allowed",nl,
290			  "end,",nl])
291	    end,
292	    asn1ct_name:new(rb),
293            gen_dec_pack(Gen, RecordName, Typename, CompList),
294            emit([".",nl])
295    end.
296
297gen_dec_pack(Gen, RecordName, Typename, CompList) ->
298    case Typename of
299	['EXTERNAL'] ->
300            dec_external(Gen, RecordName);
301	_ ->
302            asn1ct_name:new(res),
303            gen_dec_do_pack(Gen, RecordName, CompList),
304            emit([com,nl,
305                  {curr,res}])
306    end.
307
308dec_external(#gen{pack=record}, RecordName) ->
309    All = [{var,Term} || Term <- asn1ct_name:all(term)],
310    Record = [{asis,RecordName}|All],
311    emit(["OldFormat={",lists:join(",", Record),"},",nl,
312          {call,ext,transform_to_EXTERNAL1994,
313           ["OldFormat"]}]);
314dec_external(#gen{pack=map}, _RecordName) ->
315    Vars = asn1ct_name:all(term),
316    Names = ['direct-reference','indirect-reference',
317             'data-value-descriptor',encoding],
318    Zipped = lists:zip(Names, Vars),
319    MapInit = lists:join(",", [["'",N,"'=>",{var,V}] || {N,V} <- Zipped]),
320    emit(["OldFormat = #{",MapInit,"}",com,nl,
321          "ASN11994Format =",nl,
322          {call,ext,transform_to_EXTERNAL1994_maps,
323           ["OldFormat"]}]).
324
325gen_dec_do_pack(#gen{pack=record}, RecordName, _CompList) ->
326    All = asn1ct_name:all(term),
327    L = [{asis,RecordName}|[{var,Var} || Var <- All]],
328    emit([{curr,res}," = {",lists:join(",", L),"}"]);
329gen_dec_do_pack(#gen{pack=map}, _, CompList) ->
330    Zipped = lists:zip(CompList, asn1ct_name:all(term)),
331    PF = fun({#'ComponentType'{prop='OPTIONAL'},_}) -> false;
332            ({_,_}) -> true
333         end,
334    {Mandatory,Optional} = lists:partition(PF, Zipped),
335    L = [[{asis,Name},"=>",{var,Var}] ||
336            {#'ComponentType'{name=Name},Var} <- Mandatory],
337    emit([{curr,res}," = #{",lists:join(",", L),"}"]),
338    gen_dec_map_optional(Optional).
339
340gen_dec_map_optional([{#'ComponentType'{name=Name},Var}|T]) ->
341    asn1ct_name:new(res),
342    emit([com,nl,
343          {curr,res}," = case ",{var,Var}," of",nl,
344          "  asn1_NOVALUE -> ",{prev,res},";",nl,
345          "  _ -> ",{prev,res},"#{",{asis,Name},"=>",{var,Var},"}",nl,
346          "end"]),
347    gen_dec_map_optional(T);
348gen_dec_map_optional([]) ->
349    ok.
350
351gen_dec_postponed_decs(_,[]) ->
352    emit(nl);
353gen_dec_postponed_decs(DecObj,[{_Cname,{FirstPFN,PFNList},Term,
354				TmpTerm,_Tag,OptOrMand}|Rest]) ->
355
356    asn1ct_name:new(tmpterm),
357    asn1ct_name:new(reason),
358    asn1ct_name:new(tmptlv),
359
360    emit([Term," = ",nl]),
361    N = case OptOrMand of
362	    mandatory -> 0;
363	    'OPTIONAL' ->
364		emit_opt_or_mand_check(asn1_NOVALUE,TmpTerm),
365		6;
366	    {'DEFAULT',Val} ->
367		emit_opt_or_mand_check(Val,TmpTerm),
368		6
369	end,
370    emit([indent(N+3),"case (catch ",DecObj,"(",{asis,FirstPFN},
371	  ", ",TmpTerm,", ",{asis,PFNList},")) of",nl]),
372    emit([indent(N+6),"{'EXIT', ",{curr,reason},"} ->",nl]),
373    emit([indent(N+9),"exit({'Type not compatible with table constraint',",
374	  {curr,reason},"});",nl]),
375    emit([indent(N+6),{curr,tmpterm}," ->",nl]),
376    emit([indent(N+9),{curr,tmpterm},nl]),
377
378    case OptOrMand of
379	mandatory -> emit([indent(N+3),"end,",nl]);
380	_ ->
381	    emit([indent(N+3),"end",nl,
382		  indent(3),"end,",nl])
383    end,
384    gen_dec_postponed_decs(DecObj,Rest).
385
386emit_opt_or_mand_check(Value,TmpTerm) ->
387    emit([indent(3),"case ",TmpTerm," of",nl,
388	  indent(6),{asis,Value}," ->",{asis,Value},";",nl,
389	  indent(6),"_ ->",nl]).
390
391%%============================================================================
392%%  Encode/decode SET
393%%
394%%============================================================================
395
396gen_encode_set(Erules,Typename,D) when is_record(D,type) ->
397    gen_encode_sequence(Erules,Typename,D).
398
399gen_decode_set(Gen, Typename, #type{}=D) ->
400    asn1ct_name:start(),
401%%    asn1ct_name:new(term),
402    asn1ct_name:new(tag),
403    #'SET'{tablecinf=TableConsInfo,components=TCompList0} = D#type.def,
404    %% filter away extensionAdditiongroup markers
405    TCompList = filter_complist(TCompList0),
406    Ext = extensible(TCompList),
407    ToOptional = fun(mandatory) ->
408			 'OPTIONAL';
409		    (X) -> X
410		 end,
411    CompList = case TCompList of
412		   {Rl1,El,Rl2} -> Rl1 ++ [X#'ComponentType'{prop=ToOptional(Y)}||X = #'ComponentType'{prop=Y}<-El] ++ Rl2;
413		   {Rl,El} -> Rl ++ El;
414		   _ -> TCompList
415	       end,
416
417    %% asn1ct_name:clear(),
418    asn1ct_name:new(tlv),
419    case CompList of
420	[] -> % empty sequence
421	    true;
422	_ ->
423	    emit([{curr,tlv}," = "])
424    end,
425    call(match_tags, [{prev,tlv},"TagIn"]),
426    emit([com,nl]),
427    asn1ct_name:new(v),
428
429
430    {DecObjInf,ValueIndex} =
431	case TableConsInfo of
432	    #simpletableattributes{objectsetname=ObjectSetRef,
433				   c_name=AttrN,
434				   usedclassfield=UniqueFieldName,
435				   uniqueclassfield=UniqueFieldName,
436				   valueindex=ValIndex} ->
437		F = fun(#'ComponentType'{typespec=CT})->
438			    case {asn1ct_gen:get_constraint(CT#type.constraint,
439							    componentrelation),
440				  CT#type.tablecinf} of
441				{no,[{objfun,_}|_]} -> true;
442				_ -> false
443			    end
444		    end,
445		case lists:any(F,CompList) of
446		    true ->
447                        %% when component relation constraint establish
448			%% relation from a component to another components
449			%% subtype component
450			{{AttrN,{deep,ObjectSetRef,UniqueFieldName,ValIndex}},
451			 ValIndex};
452		    false ->
453			{{AttrN,ObjectSetRef},ValIndex}
454		end;
455	    _ ->
456		{false,false}
457	end,
458
459    case CompList of
460	[] -> % empty set
461	    true;
462	_ ->
463	    emit(["SetFun = fun(FunTlv) ->", nl]),
464	    emit(["case FunTlv of ",nl]),
465	    NextNum = gen_dec_set_cases(Gen, Typename, CompList, 1),
466	    emit([indent(6), {curr,else}," -> ",nl,
467		  indent(9),"{",NextNum,", ",{curr,else},"}",nl]),
468	    emit([indent(3),"end",nl]),
469	    emit([indent(3),"end,",nl]),
470
471	    emit(["PositionList = [SetFun(TempTlv)|| TempTlv <- ",{curr,tlv},"],",nl]),
472	    asn1ct_name:new(tlv),
473	    emit([{curr,tlv}," = [Stlv || {_,Stlv} <- lists:sort(PositionList)],",nl]),
474	    asn1ct_name:new(tlv)
475
476    end,
477    RecordName0 = lists:concat([get_record_name_prefix(Gen),
478                                asn1ct_gen:list2rname(Typename)]),
479    RecordName = list_to_atom(RecordName0),
480    case gen_dec_sequence_call(Gen, Typename, CompList, Ext, DecObjInf) of
481	no_terms ->                           % an empty SET
482            case Gen of
483                #gen{pack=record} ->
484                    emit([nl,nl,"   {'",RecordName,"'}.",nl,nl]);
485                #gen{pack=map} ->
486                    emit([nl,nl,"   #{}.",nl,nl])
487            end;
488	{LeadingAttrTerm,PostponedDecArgs} ->
489	    emit([nl]),
490	    case {LeadingAttrTerm,PostponedDecArgs} of
491		{[],[]} ->
492		    ok;
493		{_,[]} ->
494		    ok;
495		{[{ObjSetRef,LeadingAttr,Term}],PostponedDecArgs} ->
496		    DecObj = asn1ct_gen:un_hyphen_var(lists:concat(['DecObj',LeadingAttr,Term])),
497		    ValueMatch = value_match(Gen, ValueIndex, Term),
498		    {ObjSetMod,ObjSetName} = ObjSetRef,
499		    emit([DecObj," =",nl,
500			  "   ",{asis,ObjSetMod},":'getdec_",ObjSetName,"'(",
501			  ValueMatch,"),",nl]),
502		    gen_dec_postponed_decs(DecObj,PostponedDecArgs)
503	    end,
504	    %% return value as record
505	    case Ext of
506		Extnsn when Extnsn =/= noext ->
507		    emit(["case ",{prev,tlv}," of [] -> true; _ -> true end, % ... extra fields skipped",nl]);
508		noext ->
509		    emit(["case ",{prev,tlv}," of",nl,
510			  "[] -> true;",
511			  "_ -> exit({error,{asn1, {unexpected,",{prev,tlv},
512			  "}}}) % extra fields not allowed",nl,
513			  "end,",nl])
514	    end,
515            gen_dec_pack(Gen, RecordName, Typename, CompList),
516	    emit([".",nl])
517    end.
518
519
520%%===============================================================================
521%%===============================================================================
522%%===============================================================================
523%%  Encode/decode SEQUENCE OF and SET OF
524%%===============================================================================
525%%===============================================================================
526%%===============================================================================
527
528gen_encode_sof(Erules,Typename,_InnerTypename,D) when is_record(D,type) ->
529    asn1ct_name:start(),
530    {SeqOrSetOf, Cont} = D#type.def,
531
532    Objfun = case D#type.tablecinf of
533		 [{objfun,_}|_R] ->
534		     ", ObjFun";
535		 _ ->
536		     ""
537	     end,
538
539    emit(["   {EncBytes,EncLen} = 'enc_",asn1ct_gen:list2name(Typename),
540	  "_components'(Val",Objfun,",[],0),",nl]),
541
542    emit(["   ",{call,ber,encode_tags,["TagIn","EncBytes","EncLen"]},
543	  ".",nl,nl]),
544
545    gen_encode_sof_components(Erules,Typename,SeqOrSetOf,Cont).
546
547
548gen_decode_sof(Erules,TypeName,_InnerTypeName,D) when is_record(D,type) ->
549    asn1ct_name:start(),
550    {SeqOrSetOf, _TypeTag, Cont} =
551	case D#type.def of
552	    {'SET OF',_Cont} -> {'SET OF','SET',_Cont};
553	    {'SEQUENCE OF',_Cont} -> {'SEQUENCE OF','SEQUENCE',_Cont}
554	end,
555    TypeNameSuffix = asn1ct_gen:constructed_suffix(SeqOrSetOf,Cont#type.def),
556
557    emit(["   %%-------------------------------------------------",nl]),
558    emit(["   %% decode tag and length ",nl]),
559    emit(["   %%-------------------------------------------------",nl]),
560
561    asn1ct_name:new(tlv),
562    emit([{curr,tlv}," = ",
563	  {call,ber,match_tags,[{prev,tlv},"TagIn"]},com,nl]),
564    asn1ct_name:new(v),
565
566    emit(["["]),
567
568    InnerType = asn1ct_gen:get_inner(Cont#type.def),
569    ContName = case asn1ct_gen:type(InnerType) of
570		   Atom when is_atom(Atom) -> Atom;
571		   _ -> TypeNameSuffix
572	       end,
573    gen_dec_line(Erules,TypeName,ContName,[],Cont,mandatory),
574    emit([" || ",{curr,v}," <- ",{curr,tlv},"].",nl,nl,nl]).
575
576
577gen_encode_sof_components(Gen, Typename, SeqOrSetOf, #type{}=Cont) ->
578    {Objfun,Objfun_novar,EncObj} =
579	case Cont#type.tablecinf of
580	    [{objfun,_}|_R] ->
581		{", ObjFun",", _",{no_attr,"ObjFun"}};
582	    _ ->
583		{"","",false}
584	end,
585    emit(["'enc_",asn1ct_gen:list2name(Typename),
586	  "_components'([]",Objfun_novar,", AccBytes, AccLen) -> ",nl]),
587
588    case {Gen,SeqOrSetOf} of
589        {#gen{der=true},'SET OF'} ->
590	    asn1ct_func:need({ber,dynamicsort_SETOF,1}),
591	    emit([indent(3),
592		  "{dynamicsort_SETOF(AccBytes),AccLen};",nl,nl]);
593	{_,_} ->
594	    emit([indent(3),"{lists:reverse(AccBytes),AccLen};",nl,nl])
595    end,
596    emit(["'enc_",asn1ct_gen:list2name(Typename),
597	  "_components'([H|T]",Objfun,",AccBytes, AccLen) ->",nl]),
598    TypeNameSuffix = asn1ct_gen:constructed_suffix(SeqOrSetOf,Cont#type.def),
599    gen_enc_line(Gen, Typename, TypeNameSuffix, Cont, "H", 3,
600		 mandatory, EncObj),
601    emit([",",nl]),
602    emit([indent(3),"'enc_",asn1ct_gen:list2name(Typename),
603	  "_components'(T",Objfun,","]),
604    emit(["[EncBytes|AccBytes], AccLen + EncLen).",nl,nl]).
605
606%%============================================================================
607%%  Encode/decode CHOICE
608%%
609%%============================================================================
610
611gen_encode_choice(Erules,Typename,D) when is_record(D,type) ->
612    ChoiceTag = D#type.tag,
613    {'CHOICE',CompList} = D#type.def,
614    Ext = extensible(CompList),
615    CompList1 = case CompList of
616		    {Rl1,El,Rl2} -> Rl1 ++ El ++ Rl2;
617		    {Rl,El} -> Rl ++ El;
618		    _ -> CompList
619		end,
620    gen_enc_choice(Erules,Typename,ChoiceTag,CompList1,Ext),
621    emit([nl,nl]).
622
623gen_decode_choice(Erules,Typename,D) when is_record(D,type) ->
624    asn1ct_name:start(),
625    asn1ct_name:new(bytes),
626    ChoiceTag = D#type.tag,
627    {'CHOICE',CompList} = D#type.def,
628    Ext = extensible(CompList),
629    CompList1 = case CompList of
630		    {Rl1,El,Rl2} -> Rl1 ++ El ++ Rl2;
631		    {Rl,El} -> Rl ++ El;
632		    _ -> CompList
633		end,
634    gen_dec_choice(Erules,Typename,ChoiceTag,CompList1,Ext),
635    emit([".",nl]).
636
637
638%%============================================================================
639%%  Encode SEQUENCE
640%%
641%%============================================================================
642
643gen_enc_sequence_call(Erules,TopType,[#'ComponentType'{name=Cname,typespec=Type,prop=Prop,textual_order=Order}|Rest],Pos,Ext,EncObj) ->
644    asn1ct_name:new(encBytes),
645    asn1ct_name:new(encLen),
646    asn1ct_name:new(tmpBytes),
647    asn1ct_name:new(tmpLen),
648    CindexPos =
649	case Order of
650	    undefined ->
651		Pos;
652	    _ -> Order % der
653	end,
654    Element =
655	case TopType of
656	    ['EXTERNAL'] ->
657		io_lib:format("Cindex~w",[CindexPos]);
658	    _ ->
659		io_lib:format("Cindex~w",[CindexPos])
660	end,
661    InnerType = asn1ct_gen:get_inner(Type#type.def),
662    print_attribute_comment(InnerType,Pos,Cname,Prop),
663    gen_enc_line(Erules,TopType,Cname,Type,Element,3,Prop,EncObj),
664    emit([com,nl]),
665    gen_enc_sequence_call(Erules,TopType,Rest,Pos+1,Ext,EncObj);
666
667gen_enc_sequence_call(_Erules,_TopType,[],_Num,_,_) ->
668	true.
669
670%%============================================================================
671%%  Decode SEQUENCE
672%%
673%%============================================================================
674
675gen_dec_sequence_call(Erules,TopType,CompList,Ext,DecObjInf)
676  when is_list(CompList) ->
677    gen_dec_sequence_call1(Erules,TopType, CompList, 1, Ext,DecObjInf,[],[]);
678gen_dec_sequence_call(Erules,TopType,CompList,Ext,DecObjInf) ->
679    gen_dec_sequence_call2(Erules,TopType, CompList, Ext,DecObjInf).
680
681
682gen_dec_sequence_call1(Erules,TopType,[#'ComponentType'{name=Cname,typespec=Type,prop=Prop,tags=Tags}|Rest],Num,Ext,DecObjInf,LeadingAttrAcc,ArgsAcc) ->
683    {LA,PostponedDec} =
684	gen_dec_component(Erules,TopType,Cname,Tags,Type,Num,Prop,
685			  Ext,DecObjInf),
686    emit([com,nl]),
687    case Rest of
688	[] ->
689	    {LA ++ LeadingAttrAcc,PostponedDec ++ ArgsAcc};
690	_ ->
691	    asn1ct_name:new(bytes),
692	    gen_dec_sequence_call1(Erules,TopType,Rest,Num+1,Ext,DecObjInf,
693				   LA++LeadingAttrAcc,PostponedDec++ArgsAcc)
694    end;
695
696gen_dec_sequence_call1(_Erules,_TopType,[],1,_,_,_,_) ->
697    no_terms;
698gen_dec_sequence_call1(_, _, [], _Num, _, _, LA, PostponedDec) ->
699    {LA, PostponedDec}.
700
701gen_dec_sequence_call2(_Erules,_TopType, {[], [], []}, _Ext,_DecObjInf) ->
702    no_terms;
703gen_dec_sequence_call2(Erules,TopType,{Root1,EList,Root2},_Ext,DecObjInf) ->
704    {LA,ArgsAcc} =
705	case gen_dec_sequence_call1(Erules,TopType,Root1++EList,1,
706				    extensible({Root1,EList}),DecObjInf,[],[]) of
707	    no_terms ->
708		{[],[]};
709	    Res -> Res
710	end,
711    %% TagList is the tags of Root2 elements from the first up to and
712    %% including the first mandatory element.
713    TagList = get_root2_taglist(Root2,[]),
714    emit([{curr,tlv}," = ",
715	  {call,ber,skip_ExtensionAdditions,
716	   [{prev,tlv},{asis,TagList}]},com,nl]),
717    asn1ct_name:new(tlv),
718    gen_dec_sequence_call1(Erules,TopType,Root2,
719			   length(Root1)+length(EList),noext,
720			   DecObjInf,LA,ArgsAcc).
721
722%% Returns a list of tags of the elements in the component (second
723%% root) list up to and including the first mandatory tag. See 24.6 in
724%% X.680 (7/2002)
725get_root2_taglist([],Acc) ->
726    lists:reverse(Acc);
727get_root2_taglist([#'ComponentType'{prop=Prop,typespec=Type}|Rest],Acc) ->
728    FirstTag = fun([])->[];
729		  ([H|_T])->(?ASN1CT_GEN_BER:decode_class(H#tag.class) bsl 10)
730				+ H#tag.number
731	       end(Type#type.tag),
732    case Prop of
733	mandatory ->
734	    %% match_tags/ may be used
735	    %% this is the last tag of interest -> return
736	    lists:reverse([FirstTag|Acc]);
737	_ ->
738	    get_root2_taglist(Rest,[FirstTag|Acc])
739    end.
740
741
742
743%%----------------------------
744%%SEQUENCE mandatory
745%%----------------------------
746
747gen_dec_component(Erules,TopType,Cname,CTags,Type,Pos,Prop,Ext,DecObjInf) ->
748    InnerType =
749	case Type#type.def of
750	    #'ObjectClassFieldType'{type=OCFTType} -> OCFTType;
751	    _ -> asn1ct_gen:get_inner(Type#type.def)
752	end,
753
754    Prop1 = case {Prop,Ext} of
755		{mandatory,{ext,Epos,_}} when Pos >= Epos ->
756		    'OPTIONAL';
757		_ ->
758		    Prop
759	    end,
760    print_attribute_comment(InnerType,Pos,Cname,Prop1),
761    asn1ct_name:new(term),
762    emit_term_tlv(Prop1,InnerType,DecObjInf),
763    asn1ct_name:new(rb),
764    PostponedDec =
765	gen_dec_line(Erules,TopType,Cname,CTags,Type,Prop1,DecObjInf),
766    asn1ct_name:new(v),
767    asn1ct_name:new(tlv),
768    asn1ct_name:new(form),
769    PostponedDec.
770
771
772emit_term_tlv({'DEFAULT',_},InnerType,DecObjInf) ->
773    emit_term_tlv(opt_or_def,InnerType,DecObjInf);
774emit_term_tlv('OPTIONAL',InnerType,DecObjInf) ->
775    emit_term_tlv(opt_or_def,InnerType,DecObjInf);
776emit_term_tlv(Prop,{typefield,_},DecObjInf) ->
777    emit_term_tlv(Prop,type_or_object_field,DecObjInf);
778emit_term_tlv(opt_or_def,type_or_object_field,NotFalse)
779  when NotFalse /= false ->
780    asn1ct_name:new(tmpterm),
781    emit(["{",{curr,tmpterm},",",{curr,tlv},"} = "]);
782emit_term_tlv(opt_or_def,_,_) ->
783    emit(["{",{curr,term},",",{curr,tlv},"} = "]);
784emit_term_tlv(_,type_or_object_field,false) ->
785     emit(["[",{curr,v},"|",{curr,tlv},"] = ",{prev,tlv},", ",nl,
786	  {curr,term}," = "]);
787emit_term_tlv(_,type_or_object_field,_) ->
788    asn1ct_name:new(tmpterm),
789    emit(["[",{curr,v},"|",{curr,tlv},"] = ",{prev,tlv},", ",nl]),
790    emit([nl,"  ",{curr,tmpterm}," = "]);
791emit_term_tlv(mandatory,_,_) ->
792    emit(["[",{curr,v},"|",{curr,tlv},"] = ",{prev,tlv},", ",nl,
793	  {curr,term}," = "]).
794
795
796gen_dec_set_cases(_Erules,_TopType,[],Pos) ->
797    Pos;
798gen_dec_set_cases(Erules,TopType,[Comp|RestComps],Pos) ->
799    Name = Comp#'ComponentType'.name,
800    Type = Comp#'ComponentType'.typespec,
801    CTags = Comp#'ComponentType'.tags,
802
803    emit([indent(6),"%",Name,nl]),
804    Tags = case Type#type.tag of
805	       [] -> % this is a choice without explicit tag
806		   [(?ASN1CT_GEN_BER:decode_class(T1class) bsl 10) + T1number||
807		       {T1class,T1number} <- CTags];
808               [FirstTag|_] ->
809		   [(?ASN1CT_GEN_BER:decode_class(FirstTag#tag.class) bsl 10) + FirstTag#tag.number]
810	   end,
811    CaseFun = fun(TagList=[H|T],Fun,N) ->
812		      Semicolon = case TagList of
813				      [_Tag1,_|_] -> [";",nl];
814				      _ -> ""
815				  end,
816		      emit(["TTlv = {",H,",_} ->",nl]),
817		      emit([indent(4),"{",Pos,", TTlv}",Semicolon]),
818		      Fun(T,Fun,N+1);
819		 ([],_,0) ->
820		      true;
821		 ([],_,_) ->
822		      emit([";",nl])
823	      end,
824    CaseFun(Tags,CaseFun,0),
825    gen_dec_set_cases(Erules,TopType,RestComps,Pos+1).
826
827
828
829%%---------------------------------------------
830%%  Encode CHOICE
831%%---------------------------------------------
832%% for BER we currently do care (a little) if the choice has an EXTENSIONMARKER
833
834
835gen_enc_choice(Erules,TopType,Tag,CompList,_Ext) ->
836    gen_enc_choice1(Erules,TopType,Tag,CompList,_Ext).
837
838gen_enc_choice1(Erules,TopType,_Tag,CompList,_Ext) ->
839    asn1ct_name:clear(),
840    emit(["   {EncBytes,EncLen} = case element(1,Val) of",nl]),
841    gen_enc_choice2(Erules,TopType,CompList),
842    emit([nl,"   end,",nl,nl]),
843    call(encode_tags, ["TagIn","EncBytes","EncLen"]),
844    emit([".",nl]).
845
846
847gen_enc_choice2(Erules,TopType,[H1|T]) when is_record(H1,'ComponentType') ->
848    Cname = H1#'ComponentType'.name,
849    Type = H1#'ComponentType'.typespec,
850    emit(["      ",{asis,Cname}," ->",nl]),
851    {Encobj,Assign} =
852	case {Type#type.def,asn1ct_gen:get_constraint(Type#type.constraint,
853						      componentrelation)} of
854	    {#'ObjectClassFieldType'{},{componentrelation,_,_}} ->
855		asn1ct_name:new(tmpBytes),
856		asn1ct_name:new(tmpLen),
857		asn1ct_name:new(encBytes),
858		asn1ct_name:new(encLen),
859		Emit = ["{",{curr,tmpBytes},", _} = "],
860		{{no_attr,"ObjFun"},Emit};
861	    _ ->
862		case Type#type.tablecinf of
863		    [{objfun,_}] -> {{no_attr,"ObjFun"},[]};
864		    _ -> {false,[]}
865		end
866	end,
867    gen_enc_line(Erules,TopType,Cname,Type,"element(2,Val)",9,
868		 mandatory,Assign,Encobj),
869    case {Type#type.def,Encobj} of
870	{#'ObjectClassFieldType'{},{no_attr,"ObjFun"}} ->
871	    emit([",",nl,indent(9),"{",{curr,encBytes},", ",
872		  {curr,encLen},"}"]);
873	_ -> ok
874    end,
875    emit([";",nl]),
876    case T of
877	[] ->
878	    emit([indent(6), "Else -> ",nl,
879		  indent(9),"exit({error,{asn1,{invalid_choice_type,Else}}})"]);
880	_ ->
881	    true
882    end,
883    gen_enc_choice2(Erules,TopType,T);
884
885gen_enc_choice2(_Erules,_TopType,[])  ->
886    true.
887
888
889
890
891%%--------------------------------------------
892%%  Decode CHOICE
893%%--------------------------------------------
894
895gen_dec_choice(Erules,TopType, _ChTag, CompList, Ext) ->
896    asn1ct_name:clear(),
897    asn1ct_name:new(tlv),
898    emit([{curr,tlv}," = ",
899	  {call,ber,match_tags,[{prev,tlv},"TagIn"]},com,nl]),
900    asn1ct_name:new(tlv),
901    asn1ct_name:new(v),
902    emit(["case (case ",{prev,tlv},
903	  " of [Ctemp",{prev,tlv},"] -> Ctemp",{prev,tlv},
904	  "; _ -> ",{prev,tlv}," end)"," of",nl]),
905    asn1ct_name:new(tagList),
906    asn1ct_name:new(choTags),
907    asn1ct_name:new(res),
908    gen_dec_choice_cases(Erules,TopType,CompList),
909    emit([indent(6), {curr,else}," -> ",nl]),
910    case Ext of
911	noext ->
912	    emit([indent(9),"exit({error,{asn1,{invalid_choice_tag,",
913		  {curr,else},"}}})",nl]);
914	_ ->
915	    emit([indent(9),"{asn1_ExtAlt,",
916		  {call,ber,ber_encode,[{curr,else}]},"}",nl])
917    end,
918    emit([indent(3),"end",nl]),
919    asn1ct_name:new(tag),
920    asn1ct_name:new(else).
921
922gen_dec_choice_cases(_Erules,_TopType, []) ->
923    ok;
924gen_dec_choice_cases(Erules,TopType, [H|T]) ->
925    Cname = H#'ComponentType'.name,
926    Type = H#'ComponentType'.typespec,
927    Prop = H#'ComponentType'.prop,
928    Tags = Type#type.tag,
929    Fcases  = fun([{T1class,T1number}|Tail],Fun) ->
930		      emit([indent(4),{curr,v}," = {",
931			    (?ASN1CT_GEN_BER:decode_class(T1class) bsl 10) +
932			    T1number,",_} -> ",nl]),
933		      emit([indent(8),"{",{asis,Cname},", "]),
934		      gen_dec_line(Erules,TopType,Cname,[],Type,Prop),
935		      emit(["};",nl,nl]),
936		      Fun(Tail,Fun);
937		 ([],_) ->
938		      ok
939	      end,
940    emit([nl,"%% '",Cname,"'",nl]),
941    case {Tags,asn1ct:get_gen_state_field(namelist)} of
942	{[],_} -> % choice without explicit tags
943	    Fcases(H#'ComponentType'.tags,Fcases);
944	{[FirstT|_RestT],[{Cname,undecoded}|Names]} ->
945	    DecTag=(?ASN1CT_GEN_BER:decode_class(FirstT#tag.class) bsl 10) +
946		FirstT#tag.number,
947	    asn1ct:add_generated_refed_func({[Cname|TopType],undecoded,
948					     [DecTag],Type}),
949	    asn1ct:update_gen_state(namelist,Names),
950	    emit([indent(4),{curr,res}," = ",
951		  match_tag(FirstT#tag.class, FirstT#tag.number),
952		  " -> ",nl]),
953	    emit([indent(8),"{",{asis,Cname},", {'",
954		  asn1ct_gen:list2name([Cname|TopType]),"',",
955		  {curr,res},"}};",nl,nl]);
956	{[FirstT|RestT],_} ->
957	    emit([indent(4),"{",
958		  (?ASN1CT_GEN_BER:decode_class(FirstT#tag.class) bsl 10) +
959		  FirstT#tag.number,", ",{curr,v},"} -> ",nl]),
960	    emit([indent(8),"{",{asis,Cname},", "]),
961	    gen_dec_line(Erules,TopType,Cname,[],Type#type{tag=RestT},Prop),
962	    emit(["};",nl,nl])
963    end,
964    gen_dec_choice_cases(Erules,TopType, T).
965
966match_tag(Class, TagNo) when is_integer(TagNo) ->
967    match_tag1(asn1ct_gen_ber_bin_v2:decode_class(Class), TagNo).
968
969match_tag1(Class, TagNo) when TagNo =< 30 ->
970    io_lib:format("<<~p:2,_:1,~p:5,_/binary>>", [Class bsr 6,TagNo]);
971match_tag1(Class, TagNo) ->
972    Octets = mk_object_val(TagNo),
973    io_lib:format("<<~p:2,_:1,31:5,~s,_/binary>>", [Class bsr 6,Octets]).
974
975mk_object_val(Val) when Val < 16#80 ->
976    integer_to_list(Val);
977mk_object_val(Val) ->
978    mk_object_val(Val bsr 7, [integer_to_list(Val band 16#7F)]).
979
980mk_object_val(0, Acc) ->
981    Acc;
982mk_object_val(Val, Acc) ->
983    I = integer_to_list((Val band 16#7F) bor 16#80),
984    mk_object_val(Val bsr 7, [I,","|Acc]).
985
986%%---------------------------------------
987%% Generate the encode/decode code
988%%---------------------------------------
989
990gen_enc_line(Erules,TopType,Cname,
991	     Type=#type{constraint=C,
992			def=#'ObjectClassFieldType'{type={typefield,_}}},
993	     Element,Indent,OptOrMand=mandatory,EncObj)
994  when is_list(Element) ->
995    case asn1ct_gen:get_constraint(C,componentrelation) of
996	{componentrelation,_,_} ->
997	    gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,
998			 ["{",{curr,tmpBytes},",_} = "],EncObj);
999	_ ->
1000	    gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,
1001			 ["{",{curr,encBytes},",",{curr,encLen},"} = "],
1002			 EncObj)
1003    end;
1004gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,EncObj)
1005  when is_list(Element) ->
1006    gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,
1007		 ["{",{curr,encBytes},",",{curr,encLen},"} = "],EncObj).
1008
1009gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,Assign,EncObj)
1010  when is_list(Element) ->
1011    IndDeep = indent(Indent),
1012    Tag = lists:reverse([?ASN1CT_GEN_BER:encode_tag_val(
1013			    ?ASN1CT_GEN_BER:decode_class(X#tag.class),
1014			    X#tag.form,
1015			    X#tag.number)
1016			 || X <- Type#type.tag]),
1017    InnerType = asn1ct_gen:get_inner(Type#type.def),
1018    WhatKind = asn1ct_gen:type(InnerType),
1019    emit(IndDeep),
1020    emit(Assign),
1021    gen_optormand_case(OptOrMand, Erules, TopType, Cname, Type, Element),
1022    case {Type,asn1ct_gen:get_constraint(Type#type.constraint,
1023					 componentrelation)} of
1024	{#type{def=#'ObjectClassFieldType'{type={typefield,_},
1025					   fieldname=RefedFieldName}},
1026	 {componentrelation,_,_}} ->
1027	    {_LeadingAttrName,Fun} = EncObj,
1028            {Name,RestFieldNames} = RefedFieldName,
1029            true = is_atom(Name),                %Assertion.
1030            case OptOrMand of
1031                mandatory -> ok;
1032                _ ->
1033                    emit(["{",{curr,tmpBytes},",_ } = "])
1034            end,
1035            emit([Fun,"(",{asis,Name},", ",Element,", ",
1036                  {asis,RestFieldNames},"),",nl]),
1037            emit(IndDeep),
1038            case OptOrMand of
1039                mandatory ->
1040                    emit(["{",{curr,encBytes},",",{curr,encLen},
1041                          "} = ",
1042                          {call,ber,encode_open_type,
1043                           [{curr,tmpBytes},{asis,Tag}]},nl]);
1044                _ ->
1045                    emit([{call,ber,encode_open_type,
1046                           [{curr,tmpBytes},{asis,Tag}]}])
1047            end;
1048	_ ->
1049	    case WhatKind of
1050		{primitive,bif} ->
1051		    ?ASN1CT_GEN_BER:gen_encode_prim(ber, Type, {asis,Tag},
1052						    Element);
1053		'ASN1_OPEN_TYPE' ->
1054		    case Type#type.def of
1055			#'ObjectClassFieldType'{} -> %Open Type
1056			    ?ASN1CT_GEN_BER:gen_encode_prim(ber,#type{def='ASN1_OPEN_TYPE'},{asis,Tag},Element);
1057			_ ->
1058			    ?ASN1CT_GEN_BER:gen_encode_prim(ber,Type,
1059							    {asis,Tag},
1060							    Element)
1061		    end;
1062		_ ->
1063		    {EncFunName, _EncMod, _EncFun} =
1064			mkfuncname(TopType,Cname,WhatKind,"enc_",""),
1065		    case {WhatKind,Type#type.tablecinf,EncObj} of
1066			{{constructed,bif},[{objfun,_}|_R],{_,Fun}} ->
1067			    emit([EncFunName,"(",Element,", ",{asis,Tag},
1068				  ", ",Fun,")"]);
1069			_ ->
1070			    emit([EncFunName,"(",Element,", ",{asis,Tag},")"])
1071		    end
1072	    end
1073    end,
1074    case OptOrMand of
1075	mandatory -> true;
1076	_ ->
1077	    emit([nl,indent(7),"end"])
1078    end.
1079
1080gen_optormand_case(mandatory, _Gen, _TopType, _Cname, _Type, _Element) ->
1081    ok;
1082gen_optormand_case('OPTIONAL', Gen, _TopType, _Cname, _Type, Element) ->
1083    emit([" case ",Element," of",nl]),
1084    Missing = case Gen of
1085                  #gen{pack=record} -> asn1_NOVALUE;
1086                  #gen{pack=map} -> ?MISSING_IN_MAP
1087              end,
1088    emit([indent(9),Missing," -> {",
1089	  empty_lb(Gen),",0};",nl]),
1090    emit([indent(9),"_ ->",nl,indent(12)]);
1091gen_optormand_case({'DEFAULT',DefaultValue}, Gen, _TopType,
1092		   _Cname, Type, Element) ->
1093    CurrMod = get(currmod),
1094    case Gen of
1095        #gen{erule=ber,der=true} ->
1096	    asn1ct_gen_check:emit(Gen, Type, DefaultValue, Element);
1097	#gen{erule=ber,der=false,pack=Pack} ->
1098            Ind9 = indent(9),
1099            DefMarker = case Pack of
1100                            record -> asn1_DEFAULT;
1101                            map -> ?MISSING_IN_MAP
1102                        end,
1103	    emit([" case ",Element," of",nl,
1104                  Ind9,{asis,DefMarker}," ->",nl,
1105                  Ind9,indent(3),"{",empty_lb(Gen),",0};",nl,
1106                  Ind9,"_ when ",Element," =:= "]),
1107	    Dv = case DefaultValue of
1108                     #'Externalvaluereference'{module=CurrMod,
1109                                               value=V} ->
1110                         ["?",{asis,V}];
1111                     _ ->
1112                         [{asis,DefaultValue}]
1113                 end,
1114            emit(Dv++[" ->",nl,
1115                      Ind9,indent(3),"{",empty_lb(Gen),",0};",nl,
1116                      Ind9,"_ ->",nl,
1117                      indent(12)])
1118    end.
1119
1120%% Use for SEQUENCE OF and CHOICE.
1121gen_dec_line(Erules,TopType,Cname,CTags,Type,OptOrMand) ->
1122    %% The matching on the next line is an assertion.
1123    {[],[]} = gen_dec_line(Erules,TopType,Cname,CTags,Type,OptOrMand,false),
1124    ok.
1125
1126%% Use for SEQUENCE.
1127gen_dec_line(Erules,TopType,Cname,CTags,Type,OptOrMand,DecObjInf)  ->
1128    BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(v)),
1129    Tag =
1130	[(?ASN1CT_GEN_BER:decode_class(X#tag.class) bsl 10) + X#tag.number ||
1131	    X <- Type#type.tag],
1132    ChoiceTags =
1133	[(?ASN1CT_GEN_BER:decode_class(Class) bsl 10) + Number||
1134	    {Class,Number} <- CTags],
1135    InnerType =
1136	case Type#type.def of
1137	    #'ObjectClassFieldType'{type=OCFTType} ->
1138		OCFTType;
1139	    _ ->
1140		asn1ct_gen:get_inner(Type#type.def)
1141	end,
1142    PostpDec =
1143	case OptOrMand of
1144	    mandatory ->
1145		gen_dec_call(InnerType,Erules,TopType,Cname,Type,
1146			     BytesVar,Tag,
1147			     mandatory,", mandatory, ",DecObjInf,OptOrMand);
1148	    _ ->
1149                %% optional or default, or a mandatory component after
1150                %% an extension marker
1151		{FirstTag,RestTag} =
1152		    case Tag of
1153			[] ->
1154			    {ChoiceTags,[]};
1155			[Ft|Rt] ->
1156			    {Ft,Rt}
1157		    end,
1158		emit(["case ",{prev,tlv}," of",nl]),
1159		PostponedDec =
1160		    case Tag of
1161			[] when length(ChoiceTags) > 0 -> % a choice without explicit tag
1162			    Fcases =
1163				fun(FirstTag1) ->
1164					emit(["[",{curr,v}," = {",{asis,FirstTag1},
1165					      ",_}|Temp",
1166					      {curr,tlv},
1167					      "] ->",nl]),
1168					emit([indent(4),"{"]),
1169					Pdec=
1170					    gen_dec_call(InnerType,Erules,
1171							 TopType,Cname,Type,
1172							 BytesVar,RestTag,
1173							 mandatory,
1174							 ", mandatory, ",
1175							 DecObjInf,OptOrMand),
1176
1177					emit([", Temp",{curr,tlv},"}"]),
1178					emit([";",nl]),
1179					Pdec
1180				end,
1181			    hd([Fcases(TmpTag)|| TmpTag <- FirstTag]);
1182
1183			[] -> % an open type without explicit tag
1184			    emit(["[",{curr,v},"|Temp",{curr,tlv},"] ->",nl]),
1185			    emit([indent(4),"{"]),
1186			    Pdec=
1187				gen_dec_call(InnerType,Erules,TopType,Cname,
1188					     Type,BytesVar,RestTag,mandatory,
1189					     ", mandatory, ",DecObjInf,
1190					     OptOrMand),
1191
1192			    emit([", Temp",{curr,tlv},"}"]),
1193			    emit([";",nl]),
1194			    Pdec;
1195
1196			_ ->
1197			    emit(["[{",{asis,FirstTag},
1198				  ",",{curr,v},"}|Temp",
1199				  {curr,tlv},
1200				  "] ->",nl]),
1201			    emit([indent(4),"{"]),
1202			    Pdec=
1203				gen_dec_call(InnerType,Erules,TopType,Cname,
1204					     Type,BytesVar,RestTag,mandatory,
1205					     ", mandatory, ",DecObjInf,
1206					     OptOrMand),
1207
1208			    emit([", Temp",{curr,tlv},"}"]),
1209			    emit([";",nl]),
1210			    Pdec
1211		    end,
1212
1213		emit([indent(4),"_ ->",nl]),
1214		case OptOrMand of
1215		    {'DEFAULT', Def0} ->
1216			Def = asn1ct_gen:conform_value(Type, Def0),
1217			emit([indent(8),"{",{asis,Def},",",{prev,tlv},"}",nl]);
1218		    'OPTIONAL' ->
1219			emit([indent(8),"{ asn1_NOVALUE, ",{prev,tlv},"}",nl])
1220		end,
1221		emit(["end"]),
1222		PostponedDec
1223	end,
1224    case DecObjInf of
1225	{Cname,ObjSet} ->
1226            %% This must be the component were an object is chosen
1227	    %% from the object set according to the table constraint.
1228	    ObjSetName = case ObjSet of
1229			     {deep,OSName,_,_} ->
1230				 OSName;
1231			     _ -> ObjSet
1232			 end,
1233	    {[{ObjSetName,Cname,asn1ct_gen:mk_var(asn1ct_name:curr(term))}],
1234	     PostpDec};
1235	_  -> {[],PostpDec}
1236    end.
1237
1238gen_dec_call({typefield,_},_,_,_Cname,Type,BytesVar,Tag,_,_,false,_) ->
1239    %%  this in case of a choice with typefield components
1240    asn1ct_name:new(reason),
1241    asn1ct_name:new(opendec),
1242    asn1ct_name:new(tmpterm),
1243    asn1ct_name:new(tmptlv),
1244
1245    {FirstPFName,RestPFName} =
1246	(Type#type.def)#'ObjectClassFieldType'.fieldname,
1247    emit([nl,indent(6),"begin",nl]),
1248    emit([indent(9),{curr,tmptlv}," = ",
1249	  {call,ber,decode_open_type,
1250	   [BytesVar,{asis,Tag}]},com,nl]),
1251
1252    emit([indent(9),"case (catch ObjFun(",{asis,FirstPFName},
1253	  ", ",{curr,tmptlv},", ",{asis,RestPFName},
1254	  ")) of", nl]),%% ??? What about Tag
1255    emit([indent(12),"{'EXIT',",{curr,reason},"} ->",nl]),
1256    emit([indent(15),"exit({'Type not ",
1257	  "compatible with table constraint', ",{curr,reason},"});",nl]),
1258    emit([indent(12),{curr,tmpterm}," ->",nl]),
1259    emit([indent(15),{curr,tmpterm},nl]),
1260    emit([indent(9),"end",nl,indent(6),"end",nl]),
1261    [];
1262gen_dec_call({typefield,_},_,_,Cname,Type,BytesVar,Tag,_,_,_DecObjInf,OptOrMandComp) ->
1263    call(decode_open_type, [BytesVar,{asis,Tag}]),
1264    RefedFieldName = (Type#type.def)#'ObjectClassFieldType'.fieldname,
1265    [{Cname,RefedFieldName,asn1ct_gen:mk_var(asn1ct_name:curr(term)),
1266      asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),Tag,OptOrMandComp}];
1267gen_dec_call(InnerType, Gen, TopType, Cname, Type, BytesVar,
1268	     Tag, _PrimOptOrMand, _OptOrMand, DecObjInf,_) ->
1269    WhatKind = asn1ct_gen:type(InnerType),
1270    gen_dec_call1(WhatKind, InnerType, TopType, Cname,
1271		  Type, BytesVar, Tag),
1272    case DecObjInf of
1273	{Cname,{_,OSet,_UniqueFName,ValIndex}} ->
1274	    Term = asn1ct_gen:mk_var(asn1ct_name:curr(term)),
1275	    ValueMatch = value_match(Gen, ValIndex, Term),
1276	    {ObjSetMod,ObjSetName} = OSet,
1277	    emit([",",nl,"ObjFun = ",{asis,ObjSetMod},":'getdec_",ObjSetName,
1278		  "'(",ValueMatch,")"]);
1279	_ ->
1280	    ok
1281    end,
1282    [].
1283
1284gen_dec_call1({primitive,bif}, InnerType, TopType, Cname,
1285	      Type, BytesVar, Tag) ->
1286    case {asn1ct:get_gen_state_field(namelist),InnerType} of
1287	{[{Cname,undecoded}|Rest],_} ->
1288	    asn1ct:add_generated_refed_func({[Cname|TopType],undecoded,
1289					     Tag,Type}),
1290	    asn1ct:update_gen_state(namelist,Rest),
1291	    emit(["{'",asn1ct_gen:list2name([Cname|TopType]),"',",
1292		  BytesVar,"}"]);
1293	_ ->
1294	    ?ASN1CT_GEN_BER:gen_dec_prim(Type, BytesVar, Tag)
1295    end;
1296gen_dec_call1('ASN1_OPEN_TYPE', _InnerType, TopType, Cname,
1297	      Type, BytesVar, Tag) ->
1298    case {asn1ct:get_gen_state_field(namelist),Type#type.def} of
1299	{[{Cname,undecoded}|Rest],_} ->
1300	    asn1ct:add_generated_refed_func({[Cname|TopType],undecoded,
1301					     Tag,Type}),
1302	    asn1ct:update_gen_state(namelist,Rest),
1303	    emit(["{'",asn1ct_gen:list2name([Cname|TopType]),"',",
1304		  BytesVar,"}"]);
1305	{_,#'ObjectClassFieldType'{type=OpenType}} ->
1306	    ?ASN1CT_GEN_BER:gen_dec_prim(#type{def=OpenType},
1307					 BytesVar, Tag);
1308	_ ->
1309	    ?ASN1CT_GEN_BER:gen_dec_prim(Type, BytesVar, Tag)
1310    end;
1311gen_dec_call1(WhatKind, _, TopType, Cname, Type, BytesVar, Tag) ->
1312    case asn1ct:get_gen_state_field(namelist) of
1313	[{Cname,undecoded}|Rest] ->
1314	    asn1ct:add_generated_refed_func({[Cname|TopType],undecoded,
1315					     Tag,Type}),
1316	    asn1ct:update_gen_state(namelist,Rest),
1317	    emit(["{'",asn1ct_gen:list2name([Cname|TopType]),"',",
1318		  BytesVar,"}"]);
1319	_ ->
1320	    EmitDecFunCall =
1321		fun(FuncName) ->
1322			case {WhatKind,Type#type.tablecinf} of
1323			    {{constructed,bif},[{objfun,_}|_Rest]} ->
1324				emit([FuncName,"(",BytesVar,", ",{asis,Tag},
1325				      ", ObjFun)"]);
1326			    _ ->
1327				emit([FuncName,"(",BytesVar,", ",{asis,Tag},")"])
1328			end
1329		end,
1330	    case asn1ct:get_gen_state_field(namelist) of
1331		[{Cname,List}|Rest] when is_list(List) ->
1332		    Sindex =
1333			case WhatKind of
1334			    #'Externaltypereference'{} ->
1335				SI = asn1ct:maybe_saved_sindex(WhatKind,List),
1336				Saves = {WhatKind,SI,List},
1337				asn1ct:add_tobe_refed_func(Saves),
1338				SI;
1339			    _ ->
1340				SI = asn1ct:maybe_saved_sindex([Cname|TopType],List),
1341				Saves = {[Cname|TopType],SI,List,Type},
1342				asn1ct:add_tobe_refed_func(Saves),
1343				SI
1344			end,
1345		    asn1ct:update_gen_state(namelist,Rest),
1346		    Prefix=asn1ct:get_gen_state_field(prefix),
1347		    Suffix =
1348			case Sindex of
1349			    I when is_integer(I),I>0 -> lists:concat(["_",I]);
1350			    _ -> ""
1351			end,
1352		    {DecFunName,_,_}=
1353			mkfuncname(TopType,Cname,WhatKind,Prefix,Suffix),
1354		    EmitDecFunCall(DecFunName);
1355		[{Cname,parts}|Rest] ->
1356		    asn1ct:update_gen_state(namelist,Rest),
1357		    asn1ct:get_gen_state_field(prefix),
1358		    %% This is to prepare SEQUENCE OF value in
1359		    %% partial incomplete decode for a later
1360		    %% part-decode, i.e. skip %% the tag.
1361		    asn1ct:add_generated_refed_func({[Cname|TopType],
1362						     parts,
1363						     [],Type}),
1364		    emit(["{'",asn1ct_gen:list2name([Cname|TopType]),"',"]),
1365		    asn1ct_func:need({ber,match_tags,2}),
1366		    EmitDecFunCall("match_tags"),
1367		    emit("}");
1368		_ ->
1369		    {DecFunName,_,_}=
1370			mkfuncname(TopType,Cname,WhatKind,"dec_",""),
1371		    EmitDecFunCall(DecFunName)
1372	    end
1373    end.
1374
1375
1376%%------------------------------------------------------
1377%% General and special help functions (not exported)
1378%%------------------------------------------------------
1379
1380
1381indent(N) ->
1382    lists:duplicate(N,32). % 32 = space
1383
1384mkvlist([H,T1|T], Sep) -> % Sep is a string e.g ", " or "+ "
1385    emit([{var,H},Sep]),
1386    mkvlist([T1|T], Sep);
1387mkvlist([H|T], Sep) ->
1388    emit([{var,H}]),
1389    mkvlist(T, Sep);
1390mkvlist([], _) ->
1391    true.
1392
1393mkvlist(L) ->
1394    mkvlist(L,", ").
1395
1396mkvplus(L) ->
1397    mkvlist(L," + ").
1398
1399extensible(CompList) when is_list(CompList) ->
1400    noext;
1401extensible({RootList,ExtList}) ->
1402    {ext,length(RootList)+1,length(ExtList)};
1403extensible({_Rl1,_Ext,_Rl2}) ->
1404    extensible.
1405%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1406%% filter away ExtensionAdditionGroup start and end marks since these
1407%% have no significance for the BER encoding
1408%%
1409filter_complist(CompList) when is_list(CompList) ->
1410    lists:filter(fun(#'ExtensionAdditionGroup'{}) ->
1411			 false;
1412		    ('ExtensionAdditionGroupEnd') ->
1413			 false;
1414		    (_) ->
1415			 true
1416		 end, CompList);
1417filter_complist({Root,Ext}) ->
1418    {Root,filter_complist(Ext)};
1419filter_complist({Root1,Ext,Root2}) ->
1420    {Root1,filter_complist(Ext),Root2}.
1421
1422
1423print_attribute_comment(InnerType,Pos,Cname,Prop) ->
1424    CommentLine = "%%-------------------------------------------------",
1425    emit([nl,CommentLine]),
1426    case InnerType of
1427	#'Externaltypereference'{module=XModule,type=Name} ->
1428	    emit([nl,"%% attribute ",Cname,"(",Pos,")   External ",XModule,":",Name]);
1429        _ when is_tuple(InnerType) ->
1430	    emit([nl,"%% attribute ",Cname,"(",Pos,") with type "|
1431                  tuple_to_list(InnerType)]);
1432	_ ->
1433	    emit([nl,"%% attribute ",Cname,"(",Pos,") with type ",InnerType])
1434    end,
1435    case Prop of
1436	mandatory ->
1437	    continue;
1438	{'DEFAULT', Def} ->
1439	    emit([" DEFAULT = ",{asis,Def}]);
1440	'OPTIONAL' ->
1441	    emit([" OPTIONAL"])
1442    end,
1443    emit([nl,CommentLine,nl]).
1444
1445
1446
1447mkfuncname(TopType,Cname,WhatKind,Prefix,Suffix) ->
1448    CurrMod = get(currmod),
1449    case WhatKind of
1450	#'Externaltypereference'{module=CurrMod,type=EType} ->
1451	    F = lists:concat(["'",Prefix,EType,Suffix,"'"]),
1452	    {F, "?MODULE", F};
1453	#'Externaltypereference'{module=Mod,type=EType} ->
1454	    {lists:concat(["'",Mod,"':'",Prefix,EType,Suffix,"'"]),Mod,
1455	     lists:concat(["'",Prefix,EType,"'"])};
1456	{constructed,bif} ->
1457	    F = lists:concat(["'",Prefix,
1458			      asn1ct_gen:list2name([Cname|TopType]),
1459			      Suffix,"'"]),
1460	    {F, "?MODULE", F}
1461    end.
1462
1463empty_lb(#gen{erule=ber}) ->
1464    "<<>>".
1465
1466value_match(#gen{pack=record}, VIs, Value) ->
1467    value_match_rec(VIs, Value);
1468value_match(#gen{pack=map}, VIs, Value) ->
1469    value_match_map(VIs, Value).
1470
1471value_match_rec([], Value) ->
1472    Value;
1473value_match_rec([{VI,_}|VIs], Value0) ->
1474    Value = value_match_rec(VIs, Value0),
1475    lists:concat(["element(",VI,", ",Value,")"]).
1476
1477value_match_map([], Value) ->
1478    Value;
1479value_match_map([{_,Name}|VIs], Value0) ->
1480    Value = value_match_map(VIs, Value0),
1481    lists:concat(["maps:get(",Name,", ",Value,")"]).
1482
1483call(F, Args) ->
1484    asn1ct_func:call(ber, F, Args).
1485