1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1997-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_per).
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-include("asn1_records.hrl").
33
34-import(asn1ct_gen, [emit/1,get_record_name_prefix/1]).
35
36-type type_name() :: any().
37
38
39%% ENCODE GENERATOR FOR SEQUENCE TYPE  ** **********
40
41
42-spec gen_encode_set(Gen, TypeName, #type{}) -> 'ok' when
43      Gen :: #gen{},
44      TypeName :: type_name().
45
46gen_encode_set(Gen, TypeName, D) ->
47    gen_encode_constructed(Gen, TypeName, D).
48
49-spec gen_encode_sequence(Gen, TypeName, #type{}) -> 'ok' when
50      Gen :: #gen{},
51      TypeName :: type_name().
52
53gen_encode_sequence(Gen, TypeName, D) ->
54    gen_encode_constructed(Gen, TypeName, D).
55
56gen_encode_constructed(Erule, Typename, #type{}=D) ->
57    asn1ct_name:start(),
58    Imm = gen_encode_constructed_imm(Erule, Typename, D),
59    asn1ct_imm:enc_cg(Imm, is_aligned(Erule)),
60    emit([".",nl]).
61
62gen_encode_constructed_imm(Gen, Typename, #type{}=D) ->
63    {CompList,TableConsInfo} = enc_complist(D),
64    ExternalImm = external_imm(Gen, Typename),
65    Optionals = optionals(to_textual_order(CompList)),
66    ImmOptionals = enc_optionals(Gen, Optionals),
67    Ext = extensible_enc(CompList),
68    Aligned = is_aligned(Gen),
69    ExtImm = case Ext of
70		 {ext,ExtPos,NumExt} when NumExt > 0 ->
71		     gen_encode_extaddgroup(Gen, CompList),
72		     Value = make_var(val),
73                     enc_extensions(Gen, Value, ExtPos, NumExt, Aligned);
74		 _ ->
75		     []
76	     end,
77    MatchImm = enc_map_match(Gen, CompList),
78    {EncObj,ObjSetImm} = enc_table(Gen, TableConsInfo, D),
79    ImmSetExt =
80	case Ext of
81	    {ext,_Pos,NumExt2} when NumExt2 > 0 ->
82		asn1ct_imm:per_enc_extension_bit({var,"Extensions"}, Aligned);
83	    {ext,_Pos,_} ->
84		asn1ct_imm:per_enc_extension_bit([], Aligned);
85	    _ ->
86		[]
87	end,
88    ImmBody = gen_enc_components_call(Gen, Typename, CompList, EncObj, Ext),
89    ExternalImm ++ MatchImm ++ ExtImm ++ ObjSetImm ++
90	asn1ct_imm:enc_append([ImmSetExt] ++ ImmOptionals ++ ImmBody).
91
92external_imm(Gen, ['EXTERNAL']) ->
93    Next = asn1ct_gen:mk_var(asn1ct_name:next(val)),
94    Curr = asn1ct_gen:mk_var(asn1ct_name:curr(val)),
95    asn1ct_name:new(val),
96    F = case Gen of
97            #gen{pack=record} -> transform_to_EXTERNAL1990;
98            #gen{pack=map} -> transform_to_EXTERNAL1990_maps
99        end,
100    [{call,ext,F,[{var,Curr}],{var,Next}}];
101external_imm(_, _) ->
102    [].
103
104enc_extensions(#gen{pack=record}, Value, ExtPos, NumExt, Aligned) ->
105    asn1ct_imm:per_enc_extensions(Value, ExtPos, NumExt, Aligned);
106enc_extensions(#gen{pack=map}, Value, ExtPos, NumExt, Aligned) ->
107    Vars = [{var,lists:concat(["Input@",Pos])} ||
108               Pos <- lists:seq(ExtPos, ExtPos+NumExt-1)],
109    Undefined = atom_to_list(?MISSING_IN_MAP),
110    asn1ct_imm:per_enc_extensions_map(Value, Vars, Undefined, Aligned).
111
112enc_complist(#type{def=Def}) ->
113    case Def of
114        #'SEQUENCE'{tablecinf=TCI,components=CL0,extaddgroup=ExtAddGroup} ->
115            case ExtAddGroup of
116                undefined ->
117                    {CL0,TCI};
118                _ when is_integer(ExtAddGroup) ->
119                    %% This is a fake SEQUENCE representing an
120                    %% ExtensionAdditionGroup.  Renumber the textual
121                    %% order so we get the right index of the
122                    %% components.
123                    CL = add_textual_order(CL0),
124                    {CL,TCI}
125            end;
126        #'SET'{tablecinf=TCI,components=CL} ->
127            {CL,TCI}
128    end.
129
130enc_table(Gen, #simpletableattributes{objectsetname=ObjectSet,
131                                      c_name=AttrN,
132                                      c_index=N,
133                                      usedclassfield=UniqueFieldName,
134                                      uniqueclassfield=UniqueFieldName,
135                                      valueindex=ValueIndex0}, _) ->
136    {Module,ObjSetName} = ObjectSet,
137    #typedef{typespec=#'ObjectSet'{gen=MustGen}} =
138        asn1_db:dbget(Module, ObjSetName),
139    case MustGen of
140        true ->
141            ValueIndex = ValueIndex0 ++ [{N+1,'ASN1_top'}],
142            Val = make_var(val),
143            {ObjSetImm,Dst} = enc_dig_out_value(Gen, ValueIndex, Val),
144            {{AttrN,Dst},ObjSetImm};
145        false ->
146            {false,[]}
147    end;
148enc_table(_Gen, #simpletableattributes{}, _) ->
149    {false,[]};
150enc_table(_Gen, _, #type{tablecinf=TCInf}) ->
151    case TCInf of
152        [{objfun,_}|_] ->
153            %% The simpletableattributes was at an outer
154            %% level and the objfun has been passed through the
155            %% function call.
156            {{"got objfun through args",{var,"ObjFun"}},[]};
157        _ ->
158            {false,[]}
159    end.
160
161enc_optionals(Gen, Optionals) ->
162    Var = make_var(val),
163    enc_optionals_1(Gen, Optionals, Var).
164
165enc_optionals_1(#gen{pack=record}=Gen, [{Pos,DefVals}|T], Var) ->
166    {Imm0,Element} = asn1ct_imm:enc_element(Pos+1, Var),
167    Imm = asn1ct_imm:per_enc_optional(Element, DefVals),
168    [Imm0++Imm|enc_optionals_1(Gen, T, Var)];
169enc_optionals_1(#gen{pack=map}=Gen, [{Pos,DefVals0}|T], V) ->
170    Var = {var,lists:concat(["Input@",Pos])},
171    DefVals = translate_missing_value(Gen, DefVals0),
172    Imm = asn1ct_imm:per_enc_optional(Var, DefVals),
173    [Imm|enc_optionals_1(Gen, T, V)];
174enc_optionals_1(_, [], _) ->
175    [].
176
177enc_map_match(#gen{pack=record}, _Cs) ->
178    [];
179enc_map_match(#gen{pack=map}, Cs0) ->
180    Var0 = "Input",
181    Cs = enc_flatten_components(Cs0),
182    M = [[quote_atom(Name),":=",lists:concat([Var0,"@",Order])] ||
183            #'ComponentType'{prop=mandatory,name=Name,
184                             textual_order=Order} <- Cs],
185    Mand = case M of
186               [] ->
187                   [];
188               [_|_] ->
189                   Patt = {expr,lists:flatten(["#{",lists:join(",", M),"}"])},
190                   [{assign,Patt,{var,asn1ct_name:curr(val)}}]
191           end,
192
193    Os0 = [{Name,Order} ||
194              #'ComponentType'{prop=Prop,name=Name,
195                               textual_order=Order} <- Cs,
196              Prop =/= mandatory],
197    {var,Val} = make_var(val),
198    F = fun({Name,Order}) ->
199                Var = lists:concat([Var0,"@",Order]),
200                P0 = ["case ",Val," of\n"
201                      "  #{",quote_atom(Name),":=",Var,"_0} -> ",
202                      Var,"_0;\n"
203                      "  _ -> ",atom_to_list(?MISSING_IN_MAP),"\n"
204                      "end"],
205                P = lists:flatten(P0),
206                {assign,{var,Var},P}
207        end,
208    Os = [F(O) || O <- Os0],
209    Mand ++ Os.
210
211enc_flatten_components({Root1,Ext0,Root2}=CL) ->
212    {_,Gs} = extgroup_pos_and_length(CL),
213    Ext = wrap_extensionAdditionGroups(Ext0, Gs),
214    Root1 ++ Root2 ++ [mark_optional(C) || C <- Ext];
215enc_flatten_components({Root,Ext}) ->
216    enc_flatten_components({Root,Ext,[]});
217enc_flatten_components(Cs) ->
218    Cs.
219
220gen_encode_extaddgroup(#gen{pack=record}, CompList) ->
221    case extgroup_pos_and_length(CompList) of
222	{extgrouppos,[]} ->
223	    ok;
224	{extgrouppos,ExtGroupPosLenList} ->
225	    _ = [gen_encode_eag_record(G) ||
226                    G <- ExtGroupPosLenList],
227	    ok
228    end;
229gen_encode_extaddgroup(#gen{pack=map}, Cs0) ->
230    Cs = enc_flatten_components(Cs0),
231    gen_encode_eag_map(Cs).
232
233gen_encode_eag_map([#'ComponentType'{name=Group,typespec=Type}|Cs]) ->
234    case Type of
235        #type{def=#'SEQUENCE'{extaddgroup=G,components=GCs0}}
236          when is_integer(G) ->
237            Ns = [N || #'ComponentType'{name=N,prop=mandatory} <- GCs0],
238            test_for_mandatory(Ns, Group),
239            gen_encode_eag_map(Cs);
240        _ ->
241            gen_encode_eag_map(Cs)
242    end;
243gen_encode_eag_map([]) ->
244    ok.
245
246test_for_mandatory([Mand|_], Group) ->
247    emit([{next,val}," = case ",{curr,val}," of",nl,
248	  "#{",quote_atom(Mand),":=_} -> ",
249          {curr,val},"#{",{asis,Group},"=>",{curr,val},"};",nl,
250          "#{} -> ",{curr,val},nl,
251	  "end,",nl]),
252    asn1ct_name:new(val);
253test_for_mandatory([], _) ->
254    ok.
255
256gen_encode_eag_record({ActualPos,VirtualPos,Len}) ->
257    Val = asn1ct_gen:mk_var(asn1ct_name:curr(val)),
258    Elements = get_input_vars(Val, VirtualPos, Len),
259    Expr = any_non_value(Val, VirtualPos, Len),
260    emit([{next,val}," = case ",Expr," of",nl,
261	  "false -> setelement(",{asis,ActualPos+1},", ",
262	  {curr,val},", asn1_NOVALUE);",nl,
263	  "true -> setelement(",{asis,ActualPos+1},", ",
264	  {curr,val},", {extaddgroup,", Elements,"})",nl,
265	  "end,",nl]),
266    asn1ct_name:new(val).
267
268any_non_value(Val, Pos, N) ->
269    L = any_non_value_1(Val, Pos, N),
270    lists:join(" orelse ", L).
271
272any_non_value_1(_, _, 0) ->
273    [];
274any_non_value_1(Val, Pos, N) ->
275    Var = get_input_var(Val, Pos),
276    [Var ++ " =/= asn1_NOVALUE"|any_non_value_1(Val, Pos+1, N-1)].
277
278%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
279%% generate decode function for SEQUENCE and SET
280%%
281gen_decode_set(Erules,Typename,D) ->
282    gen_decode_constructed(Erules,Typename,D).
283
284gen_decode_sequence(Erules,Typename,D) ->
285    gen_decode_constructed(Erules,Typename,D).
286
287gen_decode_constructed(Erule, Typename, #type{}=D) ->
288    Imm0 = gen_dec_constructed_imm(Erule, Typename, #type{}=D),
289    Imm = opt_imm(Imm0),
290    asn1ct_name:start(),
291    emit_gen_dec_imm(Imm),
292    emit([".",nl,nl]).
293
294opt_imm(Imm0) ->
295    {Imm,_} = opt_imm_1(Imm0, unknown, []),
296    Imm.
297
298opt_imm_1([{imm,Imm0,F}|T], Al0, Acc) ->
299    {Imm,Al} = asn1ct_imm:optimize_alignment(Imm0, Al0),
300    opt_imm_1(T, Al, [{imm,Imm,F}|Acc]);
301opt_imm_1([ignore|T], Al, Acc) ->
302    opt_imm_1(T, Al, Acc);
303opt_imm_1([{ignore,_}=H|T], Al, Acc) ->
304    opt_imm_1(T, Al, [H|Acc]);
305opt_imm_1([{safe,ignore}|T], Al, Acc) ->
306    opt_imm_1(T, Al, Acc);
307opt_imm_1([{safe,_}=H|T], Al, Acc) ->
308    opt_imm_1(T, Al, [H|Acc]);
309opt_imm_1([{group,G0}|T], Al0, Acc) ->
310    {G,Al} = opt_imm_1(G0, Al0, []),
311    opt_imm_1(T, Al, [{group,G}|Acc]);
312opt_imm_1([Emit|T], _, Acc) when is_function(Emit, 1) ->
313    opt_imm_1(T, unknown, [Emit|Acc]);
314opt_imm_1([], Al, Acc) ->
315    {lists:reverse(Acc),Al}.
316
317emit_gen_dec_imm(L) ->
318    emit_gen_dec_imm(L, "", []).
319
320emit_gen_dec_imm([{ignore,Fun}|T], Sep, St0) ->
321    St = Fun(St0),
322    emit_gen_dec_imm(T, Sep, St);
323emit_gen_dec_imm([{group,L}|T], Sep, St0) ->
324    emit(Sep),
325    St = emit_gen_dec_imm_group(L, St0),
326    emit_gen_dec_imm(T, [com,nl], St);
327emit_gen_dec_imm([{imm,Imm,Emit}|T], Sep, St0) ->
328    emit(Sep),
329    St = Emit(Imm, St0),
330    emit_gen_dec_imm(T, [com,nl], St);
331emit_gen_dec_imm([{safe,Item}|T], Sep, St) ->
332    emit_gen_dec_imm([Item|T], Sep, St);
333emit_gen_dec_imm([Emit|T], Sep, St0) ->
334    emit(Sep),
335    St = Emit(St0),
336    emit_gen_dec_imm(T, [com,nl], St);
337emit_gen_dec_imm([], _, _) -> ok.
338
339emit_gen_dec_imm_group([H|T], St0) ->
340    St = emit_gen_dec_group_item(H, St0),
341    emit_gen_dec_imm_group(T, St);
342emit_gen_dec_imm_group([], St) -> St.
343
344emit_gen_dec_group_item({ignore,Fun}, St) ->
345    Fun(St);
346emit_gen_dec_group_item({imm,Imm,Fun}, St) ->
347    Fun(Imm, St);
348emit_gen_dec_group_item({safe,Item}, St) ->
349    emit_gen_dec_group_item(Item, St);
350emit_gen_dec_group_item(Emit, St) ->
351    Emit(St).
352
353gen_dec_constructed_imm(Erule, Typename, #type{}=D) ->
354    {CompList,TableConsInfo} =
355	case D#type.def of
356	    #'SEQUENCE'{tablecinf=TCI,components=CL} ->
357		{add_textual_order(CL),TCI};
358	    #'SET'{tablecinf=TCI,components=CL} ->
359		{CL,TCI} % the textual order is already taken care of
360	end,
361    Ext = extensible_dec(CompList),
362    EmitExt = case Ext of
363		  {ext,_Pos,_NumExt} ->
364		      gen_dec_extension_value();
365		  _ -> ignore
366	      end,
367    Optionals = optionals(CompList),
368    EmitOpt = case Optionals of
369		  [] ->
370		      ignore;
371		  [_|_] ->
372		      gen_dec_optionals(Optionals)
373	      end,
374    ObjSetInfo =
375	case TableConsInfo of
376	    #simpletableattributes{objectsetname=ObjectSet,
377				   c_name=AttrN,
378				   usedclassfield=UniqueFieldName,
379				   uniqueclassfield=UniqueFieldName,
380				   valueindex=ValIndex} ->
381		F = fun(#'ComponentType'{typespec=CT})->
382			    case {asn1ct_gen:get_constraint(CT#type.constraint,componentrelation),CT#type.tablecinf} of
383				{no,[{objfun,_}|_R]} -> true;
384				_ -> false
385			    end
386		    end,
387		case lists:any(F,flat_complist(CompList)) of
388		    true -> % when component relation constraint establish
389			%% relation from a component to another components
390			%% subtype component
391			{{AttrN,{deep,ObjectSet,UniqueFieldName,ValIndex}},
392			 UniqueFieldName,ValIndex};
393		    false ->
394			{{AttrN,ObjectSet},UniqueFieldName,ValIndex}
395		end;
396	    _ ->
397		case D#type.tablecinf of
398		    [{objfun,_}|_] ->
399			{{"got objfun through args","ObjFun"},false,false};
400		    _ ->
401			{false,false,false}
402		end
403	end,
404    {DecObjInf,_,_} = ObjSetInfo,
405    EmitComp = gen_dec_components_call(Erule, Typename, CompList,
406				       DecObjInf, Ext, length(Optionals)),
407    EmitObjSets = gen_dec_objsets_fun(Erule, ObjSetInfo),
408    EmitPack = fun(_) ->
409                       gen_dec_pack(Erule, Typename, CompList)
410               end,
411    RestGroup = {group,[{safe,EmitObjSets},{safe,EmitPack}]},
412    [EmitExt,EmitOpt|EmitComp++[RestGroup]].
413
414gen_dec_objsets_fun(Gen, ObjSetInfo) ->
415    fun({AccTerm,AccBytes}) ->
416            {_,_UniqueFName,ValueIndex} = ObjSetInfo,
417            case {AccTerm,AccBytes} of
418                {[],[]} ->
419                    ok;
420                {_,[]} ->
421                    ok;
422                {[{ObjSet,LeadingAttr,Term}],ListOfOpenTypes} ->
423                    ValueMatch = value_match(Gen, ValueIndex, Term),
424                    _ = [begin
425                             gen_dec_open_type(Gen, ValueMatch, ObjSet,
426                                               LeadingAttr, T),
427                             emit([com,nl])
428                         end || T <- ListOfOpenTypes],
429                    ok
430            end
431    end.
432
433gen_dec_pack(Gen, Typename, CompList) ->
434    case Typename of
435	['EXTERNAL'] ->
436            dec_external(Gen, Typename);
437	_ ->
438            asn1ct_name:new(res),
439            gen_dec_do_pack(Gen, Typename, CompList),
440            emit([com,nl,
441                  "{",{curr,res},",",{curr,bytes},"}"])
442    end.
443
444dec_external(#gen{pack=record}=Gen, Typename) ->
445    RecordName = list_to_atom(record_name(Gen, Typename)),
446    All = [{var,Term} || Term <- asn1ct_name:all(term)],
447    Record = [{asis,RecordName}|All],
448    emit(["OldFormat={",lists:join(",", Record),"},",nl,
449          "ASN11994Format =",nl,
450          {call,ext,transform_to_EXTERNAL1994,
451           ["OldFormat"]},com,nl,
452          "{ASN11994Format,",{curr,bytes},"}"]);
453dec_external(#gen{pack=map}, _Typename) ->
454    Vars = asn1ct_name:all(term),
455    Names = ['direct-reference','indirect-reference',
456             'data-value-descriptor',encoding],
457    Zipped = lists:zip(Names, Vars),
458    MapInit = lists:join(",", [["'",N,"'=>",{var,V}] || {N,V} <- Zipped]),
459    emit(["OldFormat = #{",MapInit,"}",com,nl,
460          "ASN11994Format =",nl,
461          {call,ext,transform_to_EXTERNAL1994_maps,
462           ["OldFormat"]},com,nl,
463          "{ASN11994Format,",{curr,bytes},"}"]).
464
465gen_dec_do_pack(#gen{pack=record}=Gen, TypeName, CompList) ->
466    Zipped0 = zip_components(CompList, asn1ct_name:all(term)),
467    Zipped = textual_order(Zipped0),
468    RecordName = ["'",record_name(Gen, TypeName),"'"],
469    L = [RecordName|[{var,Var} || {_,Var} <- Zipped]],
470    emit([{curr,res}," = {",lists:join(",", L),"}"]);
471gen_dec_do_pack(#gen{pack=map}, _, CompList0) ->
472    CompList = enc_flatten_components(CompList0),
473    Zipped0 = zip_components(CompList, asn1ct_name:all(term)),
474    Zipped = textual_order(Zipped0),
475    PF = fun({#'ComponentType'{prop='OPTIONAL'},_}) -> false;
476            ({_,_}) -> true
477         end,
478    {Mandatory,Optional} = lists:partition(PF, Zipped),
479    L = [[{asis,Name},"=>",{var,Var}] ||
480            {#'ComponentType'{name=Name},Var} <- Mandatory],
481    emit([{curr,res}," = #{",lists:join(",", L),"}"]),
482    gen_dec_map_optional(Optional),
483    gen_dec_merge_maps(asn1ct_name:all(map)).
484
485gen_dec_map_optional([{#'ComponentType'{name=Name},Var}|T]) ->
486    asn1ct_name:new(res),
487    emit([com,nl,
488          {curr,res}," = case ",{var,Var}," of",nl,
489          "  asn1_NOVALUE -> ",{prev,res},";",nl,
490          "  _ -> ",{prev,res},"#{",{asis,Name},"=>",{var,Var},"}",nl,
491          "end"]),
492    gen_dec_map_optional(T);
493gen_dec_map_optional([]) ->
494    ok.
495
496gen_dec_merge_maps([M|Ms]) ->
497    asn1ct_name:new(res),
498    emit([com,nl,
499          {curr,res}," = maps:merge(",{prev,res},", ",{var,M},")"]),
500    gen_dec_merge_maps(Ms);
501gen_dec_merge_maps([]) ->
502    ok.
503
504quote_atom(A) when is_atom(A) ->
505    io_lib:format("~p", [A]).
506
507%% record_name([TypeName]) -> RecordNameString
508%%  Construct a record name for the constructed type, ignoring any
509%%  fake sequences that are used to represent an extension addition
510%%  group. Such fake sequences never appear as a top type, and their
511%%  name always start with "ExtAddGroup".
512
513record_name(Gen, Typename0) ->
514    [TopType|Typename1] = lists:reverse(Typename0),
515    Typename = filter_ext_add_groups(Typename1, [TopType]),
516    lists:concat([get_record_name_prefix(Gen),
517		  asn1ct_gen:list2rname(Typename)]).
518
519filter_ext_add_groups([H|T], Acc) when is_atom(H) ->
520    case atom_to_list(H) of
521	"ExtAddGroup"++_ ->
522	    filter_ext_add_groups(T, Acc);
523	_ ->
524	    filter_ext_add_groups(T, [H|Acc])
525    end;
526filter_ext_add_groups([H|T], Acc) ->
527    filter_ext_add_groups(T, [H|Acc]);
528filter_ext_add_groups([], Acc) -> Acc.
529
530zip_components({Root,Ext}, Vars) ->
531    zip_components({Root,Ext,[]}, Vars);
532zip_components({R1,Ext0,R2}, Vars) ->
533    Ext = [mark_optional(C) || C <- Ext0],
534    zip_components(R1++R2++Ext, Vars);
535zip_components(Cs, Vars) when is_list(Cs) ->
536    zip_components_1(Cs, Vars).
537
538zip_components_1([#'ComponentType'{}=C|Cs], [V|Vs]) ->
539    [{C,V}|zip_components_1(Cs, Vs)];
540zip_components_1([_|Cs], Vs) ->
541    zip_components_1(Cs, Vs);
542zip_components_1([], []) ->
543    [].
544
545textual_order([{#'ComponentType'{textual_order=undefined},_}|_]=L) ->
546    L;
547textual_order(L0) ->
548    L = [{Ix,P} || {#'ComponentType'{textual_order=Ix},_}=P <- L0],
549    [C || {_,C} <- lists:sort(L)].
550
551to_textual_order({Root,Ext}) ->
552    {to_textual_order(Root),Ext};
553to_textual_order(Cs) when is_list(Cs) ->
554    case Cs of
555	[#'ComponentType'{textual_order=undefined}|_] ->
556	    Cs;
557	_ ->
558	    lists:keysort(#'ComponentType'.textual_order,Cs)
559    end;
560to_textual_order(Cs) ->
561    Cs.
562
563gen_dec_open_type(Erule, Val, {Xmod,Xtype}, LeadingAttr,
564		  {_,{Name,RestFieldNames},Term,TmpTerm,Prop}) ->
565    #typedef{typespec=ObjSet0} = asn1_db:dbget(Xmod, Xtype),
566    #'ObjectSet'{class=Class,set=ObjSet1} = ObjSet0,
567    #'Externaltypereference'{module=ClMod,type=ClType} = Class,
568    #classdef{typespec=ClassDef} = asn1_db:dbget(ClMod, ClType),
569    #objectclass{fields=ClassFields} = ClassDef,
570    Extensible = lists:member('EXTENSIONMARK', ObjSet1),
571    Typename = [Name,ClType],
572    ObjSet = index_object_set(Erule, ClType, Name,
573			      ObjSet1, ClassFields),
574    Key = erlang:md5(term_to_binary({decode,ObjSet,RestFieldNames,
575				     Prop,Extensible})),
576    Gen = fun(_Fd, N) ->
577		  dec_objset_optional(N, Prop),
578		  dec_objset(Erule, N, ObjSet, RestFieldNames, Typename),
579		  dec_objset_default(N, Name, LeadingAttr, Extensible)
580	  end,
581    Prefix = lists:concat(["dec_os_",Name]),
582    F = asn1ct_func:call_gen(Prefix, Key, Gen),
583    emit([Term," = ",{asis,F},"(",TmpTerm,", ",Val,")"]).
584
585dec_objset_optional(N, {'DEFAULT',Val}) ->
586    dec_objset_optional_1(N, Val);
587dec_objset_optional(N, 'OPTIONAL') ->
588    dec_objset_optional_1(N, asn1_NOVALUE);
589dec_objset_optional(_N, mandatory) -> ok.
590
591dec_objset_optional_1(N, Val) ->
592    emit([{asis,N},"(",{asis,Val},", _Id) ->",nl,
593	  {asis,Val},";",nl]).
594
595dec_objset(_Erule, _N, [], _, _) ->
596    ok;
597dec_objset(Erule, N, [Obj|Objs], RestFields, Cl) ->
598    dec_objset_1(Erule, N, Obj, RestFields, Cl),
599    emit([";",nl]),
600    dec_objset(Erule, N, Objs, RestFields, Cl).
601
602dec_objset_default(N, C, LeadingAttr, false) ->
603    emit([{asis,N},"(Bytes, Id) ->",nl,
604	  "exit({'Type not compatible with table constraint',"
605	  "{{component,",{asis,C},"},"
606	  "{value,Bytes},"
607	  "{unique_name_and_value,",{asis,LeadingAttr},",Id}}}).",nl,nl]);
608dec_objset_default(N, _, _, true) ->
609    emit([{asis,N},"(Bytes, Id) ->",nl|
610	  case asn1ct:use_legacy_types() of
611	      false ->
612		  ["{asn1_OPENTYPE,Bytes}.",nl,nl];
613	      true ->
614		  ["Bytes.",nl,nl]
615	  end]).
616
617dec_objset_1(Erule, N, {Id,Obj}, RestFields, Typename) ->
618    emit([{asis,N},"(Bytes, Id) when Id =:= ",{asis,Id}," ->",nl]),
619    dec_objset_2(Erule, Obj, RestFields, Typename).
620
621dec_objset_2(Erule, Obj, RestFields0, Typename) ->
622    case Obj of
623	#typedef{name={primitive,bif},typespec=Type} ->
624	    Imm = asn1ct_gen_per:gen_dec_imm(Erule, Type),
625	    {Term,_} = asn1ct_imm:dec_slim_cg(Imm, 'Bytes'),
626	    emit([com,nl,Term]);
627	#typedef{name={constructed,bif},typespec=Type}=Def ->
628	    Prefix = "dec_outlined_",
629	    Key = {dec_outlined,Def},
630	    Gen = fun(_Fd, Name) ->
631			  gen_dec_obj(Erule, Name, Typename, Type)
632		  end,
633	    Func = asn1ct_func:call_gen(Prefix, Key, Gen),
634	    emit(["{Term,_} = ",{asis,Func},"(Bytes)",com,nl,
635		  "Term"]);
636	#typedef{name=Type} ->
637	    emit(["{Result,_} = ",{asis,enc_func("dec_", Type)},"(Bytes),",nl,
638		  "Result"]);
639	#'Externaltypereference'{module=Mod,type=Type} ->
640	    emit("{Term,_} = "),
641	    Func = enc_func("dec_", Type),
642	    case get(currmod) of
643		Mod ->
644		    emit([{asis,Func},"(Bytes)"]);
645		_ ->
646		    emit([{asis,Mod},":",{asis,Func},"(Bytes)"])
647	    end,
648	    emit([com,nl,
649		  "Term"]);
650	#'Externalvaluereference'{module=Mod,value=Value} ->
651	    case asn1_db:dbget(Mod, Value) of
652		#typedef{typespec=#'Object'{def=Def}} ->
653		    {object,_,Fields} = Def,
654		    [NextField|RestFields] = RestFields0,
655		    {NextField,Typedef} = lists:keyfind(NextField, 1, Fields),
656		    dec_objset_2(Erule, Typedef, RestFields, Typename)
657	    end
658    end.
659
660gen_dec_obj(Erules, Name, Typename, Type) ->
661    emit([{asis,Name},"(Bytes) ->",nl]),
662    InnerType = asn1ct_gen:get_inner(Type#type.def),
663    asn1ct_gen:gen_decode_constructed(Erules, Typename,
664				      InnerType, Type).
665
666gen_encode_choice(Erule, TopType, D) ->
667    asn1ct_name:start(),
668    Imm = gen_encode_choice_imm(Erule, TopType, D),
669    asn1ct_imm:enc_cg(Imm, is_aligned(Erule)),
670    emit([".",nl]).
671
672gen_encode_choice_imm(Erule, TopType, #type{def={'CHOICE',CompList}}) ->
673    Ext = extensible_enc(CompList),
674    Aligned = is_aligned(Erule),
675    Cs = gen_enc_choice(Erule, TopType, CompList, Ext),
676    [{assign,{expr,"{ChoiceTag,ChoiceVal}"},"Val"}|
677     asn1ct_imm:per_enc_choice({var,"ChoiceTag"}, Cs, Aligned)].
678
679gen_decode_choice(Erules,Typename,D) when is_record(D,type) ->
680    asn1ct_name:start(),
681    asn1ct_name:new(bytes),
682    {'CHOICE',CompList} = D#type.def,
683    Ext = extensible_enc(CompList),
684    gen_dec_choice(Erules,Typename,CompList,Ext),
685    emit([".",nl]).
686
687%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
688%% Encode generator for SEQUENCE OF type
689
690gen_encode_sof(Erule, Typename, SeqOrSetOf, D) ->
691    asn1ct_name:start(),
692    Imm = gen_encode_sof_imm(Erule, Typename, SeqOrSetOf, D),
693    asn1ct_imm:enc_cg(Imm, is_aligned(Erule)),
694    emit([".",nl,nl]).
695
696gen_encode_sof_imm(Erule, Typename, SeqOrSetOf, #type{}=D) ->
697    {_SeqOrSetOf,ComponentType} = D#type.def,
698    Aligned = is_aligned(Erule),
699    CompType = ComponentType#type.def,
700    Constructed_Suffix = asn1ct_gen:constructed_suffix(SeqOrSetOf, CompType),
701    Conttype = asn1ct_gen:get_inner(CompType),
702    Currmod = get(currmod),
703    Imm0 = case asn1ct_gen:type(Conttype) of
704	       {primitive,bif} ->
705		   asn1ct_gen_per:gen_encode_prim_imm({var,"Comp"},
706						      ComponentType, Aligned);
707	       {constructed,bif} ->
708		   TypeName = [Constructed_Suffix|Typename],
709		   Enc = enc_func(asn1ct_gen:list2name(TypeName)),
710		   ObjArg = case D#type.tablecinf of
711				[{objfun,_}|_] -> [{var,"ObjFun"}];
712				_ -> []
713			    end,
714		   [{apply,{local,Enc,CompType},
715		     [{var,"Comp"}|ObjArg]}];
716	       #'Externaltypereference'{module=Currmod,type=Ename} ->
717		   [{apply,{local,enc_func(Ename),CompType},[{var,"Comp"}]}];
718	       #'Externaltypereference'{module=EMod,type=Ename} ->
719		   [{apply,{EMod,enc_func(Ename),CompType},[{var,"Comp"}]}];
720	       'ASN1_OPEN_TYPE' ->
721		   asn1ct_gen_per:gen_encode_prim_imm({var,"Comp"},
722						      #type{def='ASN1_OPEN_TYPE'},
723						      Aligned)
724	   end,
725    asn1ct_imm:per_enc_sof({var,"Val"}, D#type.constraint, 'Comp',
726			   Imm0, Aligned).
727
728gen_decode_sof(Erules, Typename, SeqOrSetOf, #type{}=D) ->
729    asn1ct_name:start(),
730    do_gen_decode_sof(Erules, Typename, SeqOrSetOf, D),
731    emit([".",nl,nl]).
732
733do_gen_decode_sof(Erules, Typename, SeqOrSetOf, D) ->
734    {_SeqOrSetOf,ComponentType} = D#type.def,
735    SizeConstraint = asn1ct_imm:effective_constraint(bitstring,
736						     D#type.constraint),
737    ObjFun =
738	case D#type.tablecinf of
739	    [{objfun,_}|_R] ->
740		", ObjFun";
741	    _ ->
742		""
743	end,
744    {Num,Buf} = gen_decode_length(SizeConstraint, Erules),
745    Key = erlang:md5(term_to_binary({Typename,SeqOrSetOf,ComponentType})),
746    Gen = fun(_Fd, Name) ->
747		  gen_decode_sof_components(Erules, Name,
748					    Typename, SeqOrSetOf,
749					    ComponentType)
750	  end,
751    F = asn1ct_func:call_gen("dec_components", Key, Gen),
752    emit([",",nl,
753	  {asis,F},"(",Num,", ",Buf,ObjFun,", [])"]).
754
755is_aligned(#gen{erule=per,aligned=Aligned}) -> Aligned.
756
757gen_decode_length(Constraint, Erule) ->
758    emit(["%% Length with constraint ",{asis,Constraint},nl]),
759    Imm = asn1ct_imm:per_dec_length(Constraint, true, is_aligned(Erule)),
760    asn1ct_imm:dec_slim_cg(Imm, "Bytes").
761
762gen_decode_sof_components(Erule, Name, Typename, SeqOrSetOf, Cont) ->
763    {ObjFun,ObjFun_Var} =
764	case Cont#type.tablecinf of
765	    [{objfun,_}|_R] ->
766		{", ObjFun",", _"};
767	    _ ->
768		{"",""}
769	end,
770    emit([{asis,Name},"(0, Bytes",ObjFun_Var,", Acc) ->",nl,
771	  "{lists:reverse(Acc),Bytes};",nl]),
772    emit([{asis,Name},"(Num, Bytes",ObjFun,", Acc) ->",nl,
773	  "{Term,Remain} = "]),
774    Constructed_Suffix = asn1ct_gen:constructed_suffix(SeqOrSetOf,
775						       Cont#type.def),
776    Conttype = asn1ct_gen:get_inner(Cont#type.def),
777    case asn1ct_gen:type(Conttype) of
778	{primitive,bif} ->
779	    asn1ct_gen_per:gen_dec_prim(Erule, Cont, "Bytes"),
780	    emit([com,nl]);
781	{constructed,bif} ->
782	    NewTypename = [Constructed_Suffix|Typename],
783	    emit([{asis,dec_func(asn1ct_gen:list2name(NewTypename))},
784		  "(Bytes",ObjFun,"),",nl]);
785	#'Externaltypereference'{}=Etype ->
786	    asn1ct_gen_per:gen_dec_external(Etype, "Bytes"),
787	    emit([com,nl]);
788	'ASN1_OPEN_TYPE' ->
789	    asn1ct_gen_per:gen_dec_prim(Erule, #type{def='ASN1_OPEN_TYPE'},
790					"Bytes"),
791	    emit([com,nl]);
792	_ ->
793	    emit([{asis,dec_func(Conttype)},"(Bytes),",nl])
794    end,
795    emit([{asis,Name},"(Num-1, Remain",ObjFun,", [Term|Acc]).",nl]).
796
797
798%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
799%% General and special help functions (not exported)
800
801extensible_dec(CompList) when is_list(CompList) ->
802    noext;
803extensible_dec({RootList,ExtList}) ->
804    {ext,length(RootList)+1,ext_length(ExtList)};
805extensible_dec({Rl1,Ext,Rl2}) ->
806     {ext,length(Rl1)+length(Rl2)+1,ext_length(Ext)}.
807
808extensible_enc(CompList) when is_list(CompList) ->
809    noext;
810extensible_enc({RootList,ExtList}) ->
811    {ext,length(RootList)+1,ext_length(ExtList)};
812extensible_enc({Rl1,Ext,_Rl2}) ->
813     {ext,length(Rl1)+1,ext_length(Ext)}.
814
815ext_length(ExtList) -> ext_length(ExtList,normal,0).
816ext_length([{'ExtensionAdditionGroup',_Num}|T],_,Acc)->
817    ext_length(T,group,Acc);
818ext_length(['ExtensionAdditionGroupEnd'|T],group,Acc) ->
819    ext_length(T,normal,Acc+1);
820ext_length([#'ComponentType'{}|T],State=group,Acc) ->
821    ext_length(T,State,Acc);
822ext_length([#'ComponentType'{}|T],State=normal,Acc) ->
823    ext_length(T,State,Acc+1);
824ext_length([],_,Acc) ->
825    Acc.
826
827extgroup_pos_and_length(CompList) when is_list(CompList) ->
828    {extgrouppos,[]};
829extgroup_pos_and_length({RootList,ExtList}) ->
830    ActualPos = length(RootList) +1,
831    %% position to get and deliver data in the record to the user
832    VirtualPos = ActualPos,
833    %% position to encode/decode the extaddgroup as an opentype sequence
834    extgrouppos(ExtList,ActualPos,VirtualPos,[]);
835extgroup_pos_and_length({RootList,ExtList,_Rl2}) ->
836    extgroup_pos_and_length({RootList,ExtList}).
837
838extgrouppos([{'ExtensionAdditionGroup',_Num}|T],ActualPos,VirtualPos,Acc) ->
839    extgrouppos(T,ActualPos,VirtualPos,0,Acc);
840extgrouppos([_|T],ActualPos,VirtualPos,Acc) ->
841    extgrouppos(T,ActualPos+1,VirtualPos+1,Acc);
842extgrouppos([],_,_,Acc) ->
843    {extgrouppos,lists:reverse(Acc)}.
844
845extgrouppos(['ExtensionAdditionGroupEnd'|T],ActualPos,VirtualPos,Len,Acc) ->
846    extgrouppos(T,ActualPos+1,VirtualPos+Len,[{ActualPos,VirtualPos,Len}|Acc]);
847extgrouppos([_|T],ActualPos,VirtualPos,Len,Acc) ->
848    extgrouppos(T,ActualPos,VirtualPos,Len+1,Acc).
849
850
851gen_dec_extension_value() ->
852    Imm0 = {get_bits,1,[1]},
853    E = fun(Imm, _) ->
854		emit(["{Ext,",{next,bytes},"} = "]),
855		BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
856		asn1ct_imm:dec_code_gen(Imm, BytesVar),
857		asn1ct_name:new(bytes)
858	end,
859    {imm,Imm0,E}.
860
861gen_dec_optionals(Optionals) ->
862    Imm0 = {get_bits,length(Optionals),[1]},
863    E = fun(Imm, _) ->
864		BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
865		emit(["{Opt,",{next,bytes},"} = "]),
866		asn1ct_imm:dec_code_gen(Imm, BytesVar),
867		asn1ct_name:new(bytes)
868    end,
869    {imm,Imm0,E}.
870
871%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
872
873optionals({Root1,Ext,Root2}) ->
874    Opt1 = optionals(Root1, 1),
875    ExtComps = length([C || C = #'ComponentType'{} <- Ext]),
876    Opt2 = optionals(Root2, 1 + length(Root1) + ExtComps),
877    Opt1 ++ Opt2;
878optionals({L,_Ext}) ->
879    optionals(L, 1);
880optionals(L) ->
881    optionals(L, 1).
882
883optionals([#'ComponentType'{prop='OPTIONAL'}|Rest], Pos) ->
884    [{Pos,[asn1_NOVALUE]}|optionals(Rest, Pos+1)];
885optionals([#'ComponentType'{typespec=T,prop={'DEFAULT',Val}}|Cs], Pos) ->
886    Vals = def_values(T, Val),
887    [{Pos,Vals}|optionals(Cs, Pos+1)];
888optionals([#'ComponentType'{}|Rest], Pos) ->
889    optionals(Rest, Pos+1);
890optionals([], _) ->
891    [].
892
893%%%%%%%%%%%%%%%%%%%%%%
894%% create_optionality_table(Cs=[#'ComponentType'{textual_order=undefined}|_]) ->
895%%     {NewCs,_} = lists:mapfoldl(fun(C,Num) ->
896%% 				       {C#'ComponentType'{textual_order=Num},
897%% 					Num+1}
898%% 			       end,
899%% 			       1,Cs),
900%%     create_optionality_table(NewCs);
901create_optionality_table(Cs) ->
902    IsOptional = fun('OPTIONAL') -> true;
903		    ({'DEFAULT',_}) -> true;
904		    (_) -> false
905		 end,
906    OptionalsElNum = [TO || #'ComponentType'{prop = O,textual_order=TO} <- Cs,
907			   IsOptional(O)],
908    {Table,_} = lists:mapfoldl(fun(X,Num) ->
909				       {{Num,X},Num+1}
910			       end,
911			       1,lists:sort(OptionalsElNum)),
912    Table.
913get_optionality_pos(TextPos,OptTable) ->
914    case lists:keysearch(TextPos,2,OptTable) of
915	{value,{OptNum,_}} ->
916	    OptNum;
917	_ ->
918	    no_num
919    end.
920
921add_textual_order(Cs) when is_list(Cs) ->
922    {NewCs,_} = add_textual_order1(Cs,1),
923    NewCs;
924add_textual_order({Root,Ext}) ->
925    {NewRoot,Num} = add_textual_order1(Root,1),
926    {NewExt,_} = add_textual_order1(Ext,Num),
927    {NewRoot,NewExt};
928add_textual_order({R1,Ext,R2}) ->
929    {NewR1,Num1} = add_textual_order1(R1,1),
930    {NewExt,Num2} = add_textual_order1(Ext,Num1),
931    {NewR2,_} = add_textual_order1(R2,Num2),
932    {NewR1,NewExt,NewR2}.
933
934add_textual_order1(Cs,NumIn) ->
935    lists:mapfoldl(fun(C=#'ComponentType'{},Num) ->
936			   {C#'ComponentType'{textual_order=Num},
937			    Num+1};
938		      (OtherMarker,Num) ->
939			   {OtherMarker,Num}
940		   end,
941		   NumIn,Cs).
942
943gen_enc_components_call(Erule, TopType, {Root,ExtList}, DynamicEnc, Ext) ->
944    gen_enc_components_call(Erule, TopType, {Root,ExtList,[]}, DynamicEnc, Ext);
945gen_enc_components_call(Erule, TopType, {R1,ExtList0,R2}=CL, DynamicEnc, Ext) ->
946    Root = R1 ++ R2,
947    Imm0 = gen_enc_components_call1(Erule, TopType, Root, DynamicEnc, noext),
948    ExtImm = case Ext of
949		 {ext,_,ExtNum} when ExtNum > 0 ->
950		     [{var,"Extensions"}];
951		 _ ->
952		     []
953	     end,
954    {extgrouppos,ExtGroupPosLen}  = extgroup_pos_and_length(CL),
955    ExtList1 = wrap_extensionAdditionGroups(ExtList0, ExtGroupPosLen),
956    ExtList = [mark_optional(C) || C <- ExtList1],
957    Imm1 = gen_enc_components_call1(Erule, TopType, ExtList, DynamicEnc, Ext),
958    Imm0 ++ [ExtImm|Imm1];
959gen_enc_components_call(Erule, TopType, CompList, DynamicEnc, Ext) ->
960    %% No extension marker.
961    gen_enc_components_call1(Erule, TopType, CompList, DynamicEnc, Ext).
962
963mark_optional(#'ComponentType'{prop=Prop0}=C) ->
964    Prop = case Prop0 of
965               mandatory -> 'OPTIONAL';
966               'OPTIONAL'=Keep -> Keep;
967               {'DEFAULT',_}=Keep -> Keep
968           end,
969    C#'ComponentType'{prop=Prop};
970mark_optional(Other) ->
971    Other.
972
973gen_enc_components_call1(Gen, TopType, [C|Rest], DynamicEnc, Ext) ->
974    #'ComponentType'{name=Cname,typespec=Type,
975                     prop=Prop,textual_order=Num} = C,
976    InnerType = asn1ct_gen:get_inner(Type#type.def),
977    CommentString = attribute_comment(InnerType, Num, Cname),
978    ImmComment = asn1ct_imm:enc_comment(CommentString),
979
980    {Imm0,Element} = enc_fetch_field(Gen, Num, Prop),
981    Imm1 = gen_enc_line_imm(Gen, TopType, Cname, Type,
982                            Element, DynamicEnc, Ext),
983    Imm2 = case Prop of
984	       mandatory ->
985		   Imm1;
986	       'OPTIONAL' ->
987		   enc_absent(Gen, Element, [asn1_NOVALUE], Imm1);
988	       {'DEFAULT',Def} when Ext =:= noext ->
989		   DefValues = def_values(Type, Def),
990		   enc_absent(Gen, Element, DefValues, Imm1);
991               {'DEFAULT',_} ->
992		   enc_absent(Gen, Element, [asn1_DEFAULT], Imm1)
993	   end,
994    Imm = case Imm2 of
995	      [] -> [];
996	      _ -> [ImmComment|Imm0 ++ Imm2]
997	  end,
998    [Imm|gen_enc_components_call1(Gen, TopType, Rest, DynamicEnc, Ext)];
999gen_enc_components_call1(_Gen, _TopType, [], _, _) ->
1000    [].
1001
1002enc_absent(Gen, Var, Absent0, Imm) ->
1003    Absent = translate_missing_value(Gen, Absent0),
1004    asn1ct_imm:enc_absent(Var, Absent, Imm).
1005
1006translate_missing_value(#gen{pack=record}, Optionals) ->
1007    Optionals;
1008translate_missing_value(#gen{pack=map}, Optionals) ->
1009    case Optionals of
1010        [asn1_NOVALUE|T] -> [?MISSING_IN_MAP|T];
1011        [asn1_DEFAULT|T] -> [?MISSING_IN_MAP|T];
1012        {call,_,_,_} -> Optionals
1013    end.
1014
1015enc_fetch_field(#gen{pack=record}, Num, _Prop) ->
1016    Val = make_var(val),
1017    asn1ct_imm:enc_element(Num+1, Val);
1018enc_fetch_field(#gen{pack=map}, Num, _) ->
1019    {[],{var,lists:concat(["Input@",Num])}}.
1020
1021def_values(#type{def=#'Externaltypereference'{module=Mod,type=Type}}, Def) ->
1022    #typedef{typespec=T} = asn1_db:dbget(Mod, Type),
1023    def_values(T, Def);
1024def_values(#type{def={'BIT STRING',[]}}, Bs) when is_bitstring(Bs) ->
1025    case asn1ct:use_legacy_types() of
1026	false ->
1027	    [asn1_DEFAULT,Bs];
1028	true ->
1029	    ListBs = [B || <<B:1>> <= Bs],
1030	    IntBs = lists:foldl(fun(B, A) ->
1031					(A bsl 1) bor B
1032				end, 0, lists:reverse(ListBs)),
1033	    Sz = bit_size(Bs),
1034	    Compact = case 8 - Sz rem 8 of
1035			  8 ->
1036			      {0,Bs};
1037			  Unused ->
1038			      {Unused,<<Bs:Sz/bits,0:Unused>>}
1039		      end,
1040	    [asn1_DEFAULT,Bs,Compact,ListBs,IntBs]
1041    end;
1042def_values(#type{def={'BIT STRING',[_|_]=Ns}}, List) when is_list(List) ->
1043    Bs = asn1ct_gen:named_bitstring_value(List, Ns),
1044    As = case asn1ct:use_legacy_types() of
1045	     false ->
1046		 [List,Bs];
1047	     true ->
1048		 ListBs = [B || <<B:1>> <= Bs],
1049		 IntBs = lists:foldl(fun(B, A) ->
1050					     (A bsl 1) bor B
1051				     end, 0, lists:reverse(ListBs)),
1052		 [List,Bs,ListBs,IntBs]
1053	 end,
1054    {call,per_common,is_default_bitstring,As};
1055def_values(#type{def={'INTEGER',Ns}}, Def) ->
1056    [asn1_DEFAULT,Def|case lists:keyfind(Def, 2, Ns) of
1057			  false -> [];
1058			  {Val,Def} -> [Val]
1059		      end];
1060def_values(_, Def) ->
1061    [asn1_DEFAULT,Def].
1062
1063gen_enc_line_imm(Erule, TopType, Cname, Type, Element, DynamicEnc, Ext) ->
1064    Imm0 = gen_enc_line_imm_1(Erule, TopType, Cname, Type,
1065			      Element, DynamicEnc),
1066    Aligned = is_aligned(Erule),
1067    case Ext of
1068	{ext,_Ep2,_} ->
1069	    asn1ct_imm:per_enc_open_type(Imm0, Aligned);
1070	_ ->
1071	    Imm0
1072    end.
1073
1074gen_enc_line_imm_1(Erule, TopType, Cname, Type, Element, DynamicEnc) ->
1075    Atype =
1076	case Type of
1077	    #type{def=#'ObjectClassFieldType'{type=InnerType}} ->
1078		InnerType;
1079	    _  ->
1080		asn1ct_gen:get_inner(Type#type.def)
1081	end,
1082    Aligned = is_aligned(Erule),
1083    case Atype of
1084	{typefield,_} ->
1085	    {_LeadingAttrName,Fun} = DynamicEnc,
1086	    case (Type#type.def)#'ObjectClassFieldType'.fieldname of
1087		{Name,RestFieldNames} when is_atom(Name) ->
1088		    Imm = enc_var_type_call(Erule, Name, RestFieldNames,
1089					    Type, Fun, Element),
1090		    asn1ct_imm:per_enc_open_type(Imm, Aligned)
1091	    end;
1092	_ ->
1093	    CurrMod = get(currmod),
1094	    case asn1ct_gen:type(Atype) of
1095		#'Externaltypereference'{module=CurrMod,type=EType} ->
1096		    [{apply,{local,enc_func(EType),Atype},[Element]}];
1097		#'Externaltypereference'{module=Mod,type=EType} ->
1098		    [{apply,{Mod,enc_func(EType),Atype},[Element]}];
1099		{primitive,bif} ->
1100		    asn1ct_gen_per:gen_encode_prim_imm(Element, Type, Aligned);
1101		'ASN1_OPEN_TYPE' ->
1102		    case Type#type.def of
1103			#'ObjectClassFieldType'{type=OpenType} ->
1104			    asn1ct_gen_per:gen_encode_prim_imm(Element,
1105							       #type{def=OpenType},
1106							       Aligned);
1107			_ ->
1108			    asn1ct_gen_per:gen_encode_prim_imm(Element,
1109							       Type,
1110							       Aligned)
1111		    end;
1112		{constructed,bif} ->
1113		    NewTypename = [Cname|TopType],
1114		    Enc = enc_func(asn1ct_gen:list2name(NewTypename)),
1115		    case {Type#type.tablecinf,DynamicEnc} of
1116			{[{objfun,_}|_R],{_,EncFun}} ->
1117			    [{apply,{local,Enc,Type},[Element,EncFun]}];
1118			_ ->
1119			    [{apply,{local,Enc,Type},[Element]}]
1120		    end
1121	    end
1122    end.
1123
1124enc_func(Type) ->
1125    enc_func("enc_", Type).
1126
1127enc_func(Prefix, Name) ->
1128    list_to_atom(lists:concat([Prefix,Name])).
1129
1130enc_var_type_call(Erule, Name, RestFieldNames,
1131		  #type{tablecinf=TCI}, Fun, Val) ->
1132    [{objfun,#'Externaltypereference'{module=Xmod,type=Xtype}}] = TCI,
1133    #typedef{typespec=ObjSet0} = asn1_db:dbget(Xmod, Xtype),
1134    #'ObjectSet'{class=Class,set=ObjSet1} = ObjSet0,
1135    #'Externaltypereference'{module=ClMod,type=ClType} = Class,
1136    #classdef{typespec=ClassDef} = asn1_db:dbget(ClMod, ClType),
1137    #objectclass{fields=ClassFields} = ClassDef,
1138    Extensible = lists:member('EXTENSIONMARK', ObjSet1),
1139    ObjSet = index_object_set(Erule, ClType, Name,
1140			      ObjSet1, ClassFields),
1141    Key = erlang:md5(term_to_binary({encode,ObjSet,RestFieldNames,Extensible})),
1142    TypeName = [ClType,Name],
1143    Imm = enc_objset_imm(Erule, TypeName, Name, ObjSet,
1144			 RestFieldNames, Extensible),
1145    Lambda = {lambda,[{var,"Val"},{var,"Id"}],Imm},
1146    Gen = fun(_Fd, N) ->
1147		  Aligned = is_aligned(Erule),
1148		  emit([{asis,N},"(Val, Id) ->",nl]),
1149		  asn1ct_imm:enc_cg(Imm, Aligned),
1150		  emit([".",nl])
1151	  end,
1152    Prefix = lists:concat(["enc_os_",Name]),
1153    [{call_gen,Prefix,Key,Gen,Lambda,[Val,Fun]}].
1154
1155index_object_set(_Erules, _ClType, Name, Set0, ClassFields) ->
1156    Set = index_object_set_1(Name, Set0, ClassFields),
1157    lists:sort(Set).
1158
1159index_object_set_1(Name, [{_,Key,Code}|T], ClassFields) ->
1160    case index_object_set_2(Name, Code, ClassFields) of
1161	none ->
1162	    index_object_set_1(Name, T, ClassFields);
1163	Type ->
1164	    [{Key,Type}|index_object_set_1(Name, T, ClassFields)]
1165    end;
1166index_object_set_1(Name, [_|T], ClassFields) ->
1167    index_object_set_1(Name, T, ClassFields);
1168index_object_set_1(_, [], _) ->
1169    [].
1170
1171index_object_set_2(Name, [{Name,Type}|_], _ClassFields) ->
1172    Type;
1173index_object_set_2(Name, [_|T], ClassFields) ->
1174    index_object_set_2(Name, T, ClassFields);
1175index_object_set_2(Name, [], ClassFields) ->
1176    case lists:keyfind(Name, 2, ClassFields) of
1177	{typefield,Name,'OPTIONAL'} ->
1178	    none;
1179	{objectfield,Name,_,_,'OPTIONAL'} ->
1180	    none;
1181	{typefield,Name,{'DEFAULT',#type{}=Type}} ->
1182	    InnerType = asn1ct_gen:get_inner(Type#type.def),
1183	    case asn1ct_gen:type(InnerType) of
1184		{primitive,bif} ->
1185		    #typedef{name={primitive,bif},typespec=Type};
1186		{constructed,bif} ->
1187		    #typedef{name={constructed,bif},typespec=Type}
1188	    end
1189    end.
1190
1191enc_objset_imm(Erule, TypeName, Component, ObjSet,
1192	       RestFieldNames, Extensible) ->
1193    Aligned = is_aligned(Erule),
1194    E = {error,
1195	 fun() ->
1196		 emit(["exit({'Type not compatible with table constraint',"
1197		       "{component,",{asis,Component},"},"
1198		       "{value,Val},"
1199		       "{unique_name_and_value,'_'}})",nl])
1200	 end},
1201    [{'cond',
1202      [[{eq,{var,"Id"},Key}|
1203	enc_obj(Erule, Obj, TypeName, RestFieldNames, Aligned)] ||
1204	  {Key,Obj} <- ObjSet] ++
1205	  [['_',case Extensible of
1206		    false ->
1207			E;
1208		    true ->
1209			case asn1ct:use_legacy_types() of
1210			    false ->
1211				{call,per_common,open_type_to_binary,
1212				 [{var,"Val"}]};
1213			    true ->
1214				{call,per_common,legacy_open_type_to_binary,
1215				 [{var,"Val"}]}
1216			end
1217		end]]}].
1218
1219enc_obj(Erule, Obj, TypeName, RestFieldNames0, Aligned) ->
1220    Val = {var,"Val"},
1221    case Obj of
1222	#typedef{name={constructed,bif},typespec=Type}=Def ->
1223	    Prefix = "enc_outlined_",
1224	    Key = {enc_outlined,Def},
1225	    Gen = fun(_Fd, Name) ->
1226			  gen_enc_obj(Erule, Name, TypeName, Type)
1227		  end,
1228	    [{call_gen,Prefix,Key,Gen,undefined,[Val]}];
1229	#typedef{name={primitive,bif},typespec=Def} ->
1230	    asn1ct_gen_per:gen_encode_prim_imm({var,"Val"}, Def, Aligned);
1231	#typedef{name=Type} ->
1232	    [{apply,{local,enc_func(Type),Type},[{var,"Val"}]}];
1233	#'Externalvaluereference'{module=Mod,value=Value} ->
1234	    case asn1_db:dbget(Mod, Value) of
1235		#typedef{typespec=#'Object'{def=Def}} ->
1236		    {object,_,Fields} = Def,
1237		    [NextField|RestFieldNames] = RestFieldNames0,
1238		    {NextField,Typedef} = lists:keyfind(NextField, 1, Fields),
1239		    enc_obj(Erule, Typedef, TypeName,
1240			    RestFieldNames, Aligned)
1241	    end;
1242	#'Externaltypereference'{module=Mod,type=Type} ->
1243	    Func = enc_func(Type),
1244	    case get(currmod) of
1245		Mod ->
1246		    [{apply,{local,Func,Obj},[{var,"Val"}]}];
1247		_ ->
1248		    [{apply,{Mod,Func,Obj},[{var,"Val"}]}]
1249	    end
1250    end.
1251
1252gen_enc_obj(Erules, Name, Typename, Type) ->
1253    emit([{asis,Name},"(Val) ->",nl]),
1254    InnerType = asn1ct_gen:get_inner(Type#type.def),
1255    asn1ct_gen:gen_encode_constructed(Erules, Typename,
1256				      InnerType, Type).
1257
1258gen_dec_components_call(Erule, TopType, {Root,ExtList},
1259			DecInfObj, Ext, NumberOfOptionals) ->
1260    gen_dec_components_call(Erule,TopType,{Root,ExtList,[]},
1261			    DecInfObj,Ext,NumberOfOptionals);
1262gen_dec_components_call(Gen, TopType, {Root1,ExtList,Root2}=CL,
1263			DecInfObj, Ext, NumberOfOptionals) ->
1264    %% The type has extensionmarker
1265    OptTable = create_optionality_table(Root1++Root2),
1266    Init = {ignore,fun(_) -> {[],[]} end},
1267    {EmitRoot,Tpos} =
1268	gen_dec_comp_calls(Root1++Root2, Gen, TopType, OptTable,
1269			   DecInfObj, noext, NumberOfOptionals,
1270			   1, []),
1271    EmitGetExt = gen_dec_get_extension(Gen),
1272    {extgrouppos,ExtGroupPosLen}  = extgroup_pos_and_length(CL),
1273    NewExtList = wrap_extensionAdditionGroups(ExtList, ExtGroupPosLen),
1274    {EmitExts,_} = gen_dec_comp_calls(NewExtList, Gen, TopType, OptTable,
1275				      DecInfObj, Ext, NumberOfOptionals,
1276				      Tpos, []),
1277    NumExtsToSkip = ext_length(ExtList),
1278    Finish =
1279	fun(St) ->
1280		emit([{next,bytes},"= "]),
1281                Mod = case Gen of
1282                          #gen{erule=per,aligned=false} -> uper;
1283                          #gen{erule=per,aligned=true} -> per
1284                      end,
1285		asn1ct_func:call(Mod, skipextensions,
1286                                 [{curr,bytes},NumExtsToSkip+1,"Extensions"]),
1287		asn1ct_name:new(bytes),
1288		St
1289	end,
1290    [Init] ++ EmitRoot ++ [EmitGetExt|EmitExts] ++ [Finish];
1291gen_dec_components_call(Erule, TopType, CompList, DecInfObj,
1292			Ext, NumberOfOptionals) ->
1293    %% The type has no extensionmarker
1294    OptTable = create_optionality_table(CompList),
1295    Init = {ignore,fun(_) -> {[],[]} end},
1296    {Cs,_} = gen_dec_comp_calls(CompList, Erule, TopType, OptTable,
1297				DecInfObj, Ext, NumberOfOptionals,
1298				1, []),
1299    [Init|Cs].
1300
1301gen_dec_get_extension(Erule) ->
1302    Imm0 = asn1ct_imm:per_dec_extension_map(is_aligned(Erule)),
1303    E = fun(Imm, St) ->
1304		emit([nl,"%% Extensions",
1305		      nl,
1306		      "{Extensions,",{next,bytes},"} = ",
1307		      "case Ext of",nl,
1308		      "0 -> {<<>>,",{curr,bytes},"};",nl,
1309		      "1 ->",nl]),
1310		BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
1311		{Dst,DstBuf} = asn1ct_imm:dec_slim_cg(Imm, BytesVar),
1312		emit([com,nl,
1313		      "{",Dst,",",DstBuf,"}",nl,
1314		      "end"]),
1315		asn1ct_name:new(bytes),
1316		St
1317	end,
1318    {imm,Imm0,E}.
1319
1320gen_dec_comp_calls([C|Cs], Erule, TopType, OptTable, DecInfObj,
1321		   Ext, NumberOfOptionals, Tpos, Acc) ->
1322    L = gen_dec_comp_call(C, Erule, TopType, Tpos, OptTable, DecInfObj,
1323			  Ext, NumberOfOptionals),
1324    gen_dec_comp_calls(Cs, Erule, TopType, OptTable, DecInfObj,
1325		       Ext, NumberOfOptionals, Tpos+1, [L|Acc]);
1326gen_dec_comp_calls([], _, _, _, _, _, _, Tpos, Acc) ->
1327    {lists:append(lists:reverse(Acc)),Tpos}.
1328
1329gen_dec_comp_call(Comp, Gen, TopType, Tpos, OptTable, DecInfObj,
1330		  Ext, NumberOfOptionals) ->
1331    #'ComponentType'{name=Cname,typespec=Type,
1332                     prop=Prop,textual_order=TextPos} = Comp,
1333    Pos = case Ext of
1334	      noext -> Tpos;
1335	      {ext,Epos,_Enum} -> Tpos - Epos + 1
1336	  end,
1337    InnerType = asn1ct_gen:get_inner(Type#type.def),
1338
1339    CommentString = attribute_comment(InnerType, TextPos, Cname),
1340    Comment = fun(St) ->
1341		      emit([nl,"%% ",CommentString,nl]),
1342		      St
1343	      end,
1344
1345    Preamble =
1346	case {InnerType,is_mandatory_predef_tab_c(Ext, Prop, DecInfObj)} of
1347	    {{typefield,_},true}  ->
1348		%% DecInfObj /= {"got objfun through args","ObjFun"} |
1349		%% (DecInfObj == {"got objfun through args","ObjFun"} &
1350		%% Ext == noext & Prop == mandatory)
1351		fun(St) ->
1352			asn1ct_name:new(term),
1353			asn1ct_name:new(tmpterm),
1354			emit(["{",{curr,tmpterm},", ",{next,bytes},"} = "]),
1355			St
1356		end;
1357	_ ->
1358	    case Type of
1359		#type{def=#'SEQUENCE'{
1360                             extaddgroup=GroupNum,
1361                             components=CompList}} when is_integer(GroupNum)->
1362                    dec_match_extadd_fun(Gen, CompList);
1363		_ ->
1364		    fun(St) ->
1365			    asn1ct_name:new(term),
1366			    emit(["{",{curr,term}]),
1367			    emit([",",{next,bytes},"} = "]),
1368			    St
1369		    end
1370	    end
1371	end,
1372    {Pre,Post} = comp_call_pre_post(Gen, Ext, Prop, Pos, Type, TextPos,
1373				    OptTable, NumberOfOptionals, Ext),
1374    Lines = gen_dec_seq_line_imm(Gen, TopType, Comp, Tpos, DecInfObj, Ext),
1375    AdvBuffer = {ignore,fun(St) ->
1376				asn1ct_name:new(bytes),
1377				St
1378			end},
1379    [{group,[{safe,Comment},{safe,Preamble}] ++ Pre ++
1380	  Lines ++ Post ++ [{safe,AdvBuffer}]}].
1381
1382dec_match_extadd_fun(#gen{pack=record}, CompList) ->
1383    fun(St) ->
1384            emit(["{{_,"]),
1385            emit_extaddgroupTerms(term, CompList),
1386            emit(["}"]),
1387            emit([",",{next,bytes},"} = "]),
1388            St
1389    end;
1390dec_match_extadd_fun(#gen{pack=map}, _CompList) ->
1391    fun(St) ->
1392            asn1ct_name:new(map),
1393            emit(["{",{curr,map},",",{next,bytes},"} = "]),
1394            St
1395    end.
1396
1397comp_call_pre_post(_Gen, noext, mandatory, _, _, _, _, _, _) ->
1398    {[],[]};
1399comp_call_pre_post(_Gen, noext, Prop, _, Type, TextPos,
1400		   OptTable, NumOptionals, Ext) ->
1401    %% OPTIONAL or DEFAULT
1402    OptPos = get_optionality_pos(TextPos, OptTable),
1403    Element = case NumOptionals - OptPos of
1404		  0 ->
1405		      "Opt band 1";
1406		  Shift ->
1407		      lists:concat(["(Opt bsr ",Shift,") band 1"])
1408	      end,
1409    {[fun(St) ->
1410	      emit(["case ",Element," of",nl,
1411		    "1 ->",nl]),
1412	      St
1413      end],
1414     [fun(St) ->
1415	      emit([";",nl,
1416		    "0 ->",nl,
1417		    "{"]),
1418	      gen_dec_component_no_val(Ext, Type, Prop),
1419	      emit([",",{curr,bytes},"}",nl,
1420		    "end"]),
1421	      St
1422      end]};
1423comp_call_pre_post(Gen, {ext,_,_}, Prop, Pos, Type, _, _, _, Ext) ->
1424    %% Extension
1425    {[fun(St) ->
1426	      emit(["case Extensions of",nl,
1427		    "  <<_:",Pos-1,",1:1,_/bitstring>> ->",nl]),
1428	      St
1429      end],
1430     [extadd_group_fun(Gen, Prop, Type, Ext)]}.
1431
1432extadd_group_fun(#gen{pack=record}, Prop, Type, Ext) ->
1433    fun(St) ->
1434            emit([";",nl,
1435                  "_  ->",nl,
1436                  "{"]),
1437            case Type of
1438                #type{def=#'SEQUENCE'{
1439                             extaddgroup=Number2,
1440                             components=ExtGroupCompList2}}
1441                  when is_integer(Number2)->
1442                    emit("{extAddGroup,"),
1443                    gen_dec_extaddGroup_no_val(Ext, Type, ExtGroupCompList2),
1444                    emit("}");
1445                _ ->
1446                    gen_dec_component_no_val(Ext, Type, Prop)
1447            end,
1448            emit([",",{curr,bytes},"}",nl,
1449                  "end"]),
1450            St
1451    end;
1452extadd_group_fun(#gen{pack=map}, Prop, Type, Ext) ->
1453    fun(St) ->
1454            emit([";",nl,
1455                  "_  ->",nl,
1456                  "{"]),
1457            case Type of
1458                #type{def=#'SEQUENCE'{
1459                             extaddgroup=Number2,
1460                             components=Comp}}
1461                  when is_integer(Number2)->
1462                    dec_map_extaddgroup_no_val(Ext, Type, Comp);
1463                _ ->
1464                    gen_dec_component_no_val(Ext, Type, Prop)
1465            end,
1466            emit([",",{curr,bytes},"}",nl,
1467                  "end"]),
1468            St
1469    end.
1470
1471is_mandatory_predef_tab_c(noext, mandatory,
1472			  {"got objfun through args","ObjFun"}) ->
1473    true;
1474is_mandatory_predef_tab_c(_, _, {"got objfun through args","ObjFun"}) ->
1475    false;
1476is_mandatory_predef_tab_c(_,_,_) ->
1477    true.
1478
1479gen_dec_extaddGroup_no_val(Ext, Type, [#'ComponentType'{prop=Prop}])->
1480    gen_dec_component_no_val(Ext, Type, Prop),
1481    ok;
1482gen_dec_extaddGroup_no_val(Ext, Type, [#'ComponentType'{prop=Prop}|Rest])->
1483    gen_dec_component_no_val(Ext, Type, Prop),
1484    emit(","),
1485    gen_dec_extaddGroup_no_val(Ext, Type, Rest);
1486gen_dec_extaddGroup_no_val(_, _, []) ->
1487    ok.
1488
1489gen_dec_component_no_val(_, Type, {'DEFAULT',DefVal0}) ->
1490    DefVal = asn1ct_gen:conform_value(Type, DefVal0),
1491    emit([{asis,DefVal}]);
1492gen_dec_component_no_val(_, _, 'OPTIONAL') ->
1493    emit(["asn1_NOVALUE"]);
1494gen_dec_component_no_val({ext,_,_}, _, mandatory) ->
1495    emit(["asn1_NOVALUE"]).
1496
1497dec_map_extaddgroup_no_val(Ext, Type, Comp) ->
1498    L0 = [dec_map_extaddgroup_no_val_1(N, P, Ext, Type) ||
1499             #'ComponentType'{name=N,prop=P} <- Comp],
1500    L = [E || E <- L0, E =/= []],
1501    emit(["#{",lists:join(",", L),"}"]).
1502
1503dec_map_extaddgroup_no_val_1(Name, {'DEFAULT',DefVal0}, _Ext, Type) ->
1504    DefVal = asn1ct_gen:conform_value(Type, DefVal0),
1505    [Name,"=>",{asis,DefVal}];
1506dec_map_extaddgroup_no_val_1(_Name, 'OPTIONAL', _, _) ->
1507    [];
1508dec_map_extaddgroup_no_val_1(_Name, mandatory, {ext,_,_}, _) ->
1509    [].
1510
1511gen_dec_choice_line(Erule, TopType, Comp, Pre) ->
1512    Imm0 = gen_dec_line_imm(Erule, TopType, Comp, false, Pre),
1513    Init = {ignore,fun(_) -> {[],[]} end},
1514    Imm = [{group,[Init|Imm0]}],
1515    emit_gen_dec_imm(Imm).
1516
1517gen_dec_seq_line_imm(Erule, TopType, Comp, Pos, DecInfObj, Ext) ->
1518    Pre = gen_dec_line_open_type(Erule, Ext, Pos),
1519    gen_dec_line_imm(Erule, TopType, Comp, DecInfObj, Pre).
1520
1521gen_dec_line_imm(Erule, TopType, Comp, DecInfObj, Pre) ->
1522    #'ComponentType'{name=Cname,typespec=Type} = Comp,
1523    Atype =
1524	case Type of
1525	    #type{def=#'ObjectClassFieldType'{type=InnerType}} ->
1526		InnerType;
1527	    _  ->
1528		asn1ct_gen:get_inner(Type#type.def)
1529	end,
1530    Decode = gen_dec_line_special(Erule, Atype, TopType, Comp, DecInfObj),
1531    Post =
1532	fun({SaveBytes,Finish}) ->
1533		{AccTerm,AccBytes} = Finish(),
1534		#'ComponentType'{name=Cname} = Comp,
1535		case DecInfObj of
1536		    {Cname,ObjSet} ->
1537			ObjSetRef =
1538			    case ObjSet of
1539				{deep,OSName,_,_} ->
1540				    OSName;
1541				_ -> ObjSet
1542			    end,
1543			{AccTerm++[{ObjSetRef,Cname,
1544				    asn1ct_gen:mk_var(asn1ct_name:curr(term))}],
1545			 AccBytes++SaveBytes};
1546		    _ ->
1547			{AccTerm,AccBytes++SaveBytes}
1548		end
1549	end,
1550    [Pre,Decode,{safe,Post}].
1551
1552gen_dec_line_open_type(Erule, {ext,Ep,_}, Pos) when Pos >= Ep ->
1553    Imm = asn1ct_imm:per_dec_open_type(is_aligned(Erule)),
1554    {safe,fun(St) ->
1555		  emit(["begin",nl]),
1556		  BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
1557		  {Dst,DstBuf} = asn1ct_imm:dec_slim_cg(Imm, BytesVar),
1558		  emit([",",nl,"{TmpValx",Pos,",_} = "]),
1559		  {Dst,
1560		   fun() ->
1561			   emit([",",nl,
1562				 "{TmpValx",Pos,",",DstBuf,"}",nl,
1563				 "end"]),
1564			   St
1565		   end}
1566	  end};
1567gen_dec_line_open_type(_, _, _) ->
1568    {safe,fun(St) ->
1569		  {asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
1570		   fun() -> St end}
1571	  end}.
1572
1573gen_dec_line_special(Erule, {typefield,_}, _TopType, Comp,
1574		     DecInfObj) ->
1575    #'ComponentType'{name=Cname,typespec=Type,prop=Prop} = Comp,
1576    fun({_BytesVar,PrevSt}) ->
1577	    case DecInfObj of
1578		false -> % This is in a choice with typefield components
1579		    {Name,RestFieldNames} =
1580			(Type#type.def)#'ObjectClassFieldType'.fieldname,
1581		    Imm = asn1ct_imm:per_dec_open_type(is_aligned(Erule)),
1582		    BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
1583		    {TmpTerm,TempBuf} = asn1ct_imm:dec_slim_cg(Imm, BytesVar),
1584		    emit([com,nl]),
1585		    #type{tablecinf=[{objfun,
1586				      #'Externaltypereference'{module=Xmod,
1587							       type=Xtype}}]} =
1588			Type,
1589		    gen_dec_open_type(Erule, "ObjFun", {Xmod,Xtype},
1590				      '_', {'_',{Name,RestFieldNames},
1591					    'Result',TmpTerm,mandatory}),
1592		    emit([com,nl,
1593			  "{",{asis,Cname},",{Result,",TempBuf,"}}"]),
1594		    {[],PrevSt};
1595		{"got objfun through args","ObjFun"} ->
1596		    %% this is when the generated code gots the
1597		    %% objfun though arguments on function
1598		    %% invocation.
1599		    if
1600			Prop =:= mandatory ->
1601			    ok;
1602			true ->
1603			    asn1ct_name:new(tmpterm),
1604			    asn1ct_name:new(tmpbytes),
1605			    emit([nl,"    {",{curr,tmpterm},", ",{curr,tmpbytes},"} ="])
1606		    end,
1607		    {Name,RestFieldNames} =
1608			(Type#type.def)#'ObjectClassFieldType'.fieldname,
1609		    Imm = asn1ct_imm:per_dec_open_type(is_aligned(Erule)),
1610		    BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
1611		    asn1ct_imm:dec_code_gen(Imm, BytesVar),
1612		    emit([com,nl]),
1613		    #type{tablecinf=[{objfun,
1614				      #'Externaltypereference'{module=Xmod,
1615							       type=Xtype}}]} =
1616			Type,
1617		    Term = asn1ct_gen:mk_var(asn1ct_name:curr(term)),
1618		    TmpTerm = asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),
1619		    if
1620			Prop =:= mandatory ->
1621			    gen_dec_open_type(Erule, "ObjFun", {Xmod,Xtype},
1622					      '_', {'_',{Name,RestFieldNames},
1623						    Term,TmpTerm,Prop});
1624			true ->
1625			    emit(["     {"]),
1626			    gen_dec_open_type(Erule, "ObjFun", {Xmod,Xtype},
1627					      '_', {'_',{Name,RestFieldNames},
1628						    '_',TmpTerm,Prop}),
1629			    emit([",",nl,{curr,tmpbytes},"}"])
1630		    end,
1631		    {[],PrevSt};
1632		_ ->
1633		    Imm = asn1ct_imm:per_dec_open_type(is_aligned(Erule)),
1634		    BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
1635		    asn1ct_imm:dec_code_gen(Imm, BytesVar),
1636		    RefedFieldName =
1637			(Type#type.def)#'ObjectClassFieldType'.fieldname,
1638
1639		    {[{Cname,RefedFieldName,
1640		       asn1ct_gen:mk_var(asn1ct_name:curr(term)),
1641		       asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),
1642		       Prop}],PrevSt}
1643	    end
1644    end;
1645gen_dec_line_special(Gen, Atype, TopType, Comp, DecInfObj) ->
1646    case gen_dec_line_other(Gen, Atype, TopType, Comp) of
1647	Fun when is_function(Fun, 1) ->
1648	    fun({BytesVar,PrevSt}) ->
1649		    Fun(BytesVar),
1650		    gen_dec_line_dec_inf(Gen,Comp, DecInfObj),
1651		    {[],PrevSt}
1652	    end;
1653	Imm0 ->
1654	    {imm,Imm0,
1655	     fun(Imm, {BytesVar,PrevSt}) ->
1656		     asn1ct_imm:dec_code_gen(Imm, BytesVar),
1657		     gen_dec_line_dec_inf(Gen, Comp, DecInfObj),
1658		     {[],PrevSt}
1659	     end}
1660    end.
1661
1662gen_dec_line_dec_inf(Gen, Comp, DecInfObj) ->
1663    #'ComponentType'{name=Cname} = Comp,
1664    case DecInfObj of
1665	{Cname,{_,_OSet,_UniqueFName,ValIndex}} ->
1666	    Term = asn1ct_gen:mk_var(asn1ct_name:curr(term)),
1667	    ValueMatch = value_match(Gen, ValIndex,Term),
1668	    emit([",",nl,
1669		  "ObjFun = ",ValueMatch]);
1670	_ ->
1671	    ok
1672    end.
1673
1674gen_dec_line_other(Erule, Atype, TopType, Comp) ->
1675    #'ComponentType'{name=Cname,typespec=Type} = Comp,
1676    case asn1ct_gen:type(Atype) of
1677	#'Externaltypereference'{}=Etype ->
1678	    fun(BytesVar) ->
1679		    asn1ct_gen_per:gen_dec_external(Etype, BytesVar)
1680	    end;
1681	{primitive,bif} ->
1682	    asn1ct_gen_per:gen_dec_imm(Erule, Type);
1683	'ASN1_OPEN_TYPE' ->
1684	    case Type#type.def of
1685		#'ObjectClassFieldType'{type=OpenType} ->
1686		    asn1ct_gen_per:gen_dec_imm(Erule, #type{def=OpenType});
1687		_ ->
1688		    asn1ct_gen_per:gen_dec_imm(Erule, Type)
1689	    end;
1690	{constructed,bif} ->
1691	    NewTypename = [Cname|TopType],
1692            DecFunc = dec_func(asn1ct_gen:list2name(NewTypename)),
1693	    case Type#type.tablecinf of
1694		[{objfun,_}|_R] ->
1695		    fun(BytesVar) ->
1696			    emit([{asis,DecFunc},"(",BytesVar,", ObjFun)"])
1697		    end;
1698		_ ->
1699		    fun(BytesVar) ->
1700			    emit([{asis,DecFunc},"(",BytesVar,")"])
1701		    end
1702	    end
1703    end.
1704
1705gen_enc_choice(Erule, TopType, {Root,Exts}, Ext) ->
1706    Constr = choice_constraint(Root),
1707    gen_enc_choices(Root, Erule, TopType, 0, Constr, Ext) ++
1708	gen_enc_choices(Exts, Erule, TopType, 0, ext, Ext);
1709gen_enc_choice(Erule, TopType, {Root,Exts,[]}, Ext) ->
1710    gen_enc_choice(Erule, TopType, {Root,Exts}, Ext);
1711gen_enc_choice(Erule, TopType, Root, Ext) when is_list(Root) ->
1712    Constr = choice_constraint(Root),
1713    gen_enc_choices(Root, Erule, TopType, 0, Constr, Ext).
1714
1715choice_constraint(L) ->
1716    case length(L) of
1717	0 -> [{'SingleValue',0}];
1718	Len -> [{'ValueRange',{0,Len-1}}]
1719    end.
1720
1721gen_enc_choices([H|T], Erule, TopType, Pos, Constr, Ext) ->
1722    #'ComponentType'{name=Cname,typespec=Type} = H,
1723    Aligned = is_aligned(Erule),
1724    EncObj =
1725	case asn1ct_gen:get_constraint(Type#type.constraint,
1726				       componentrelation) of
1727	    no ->
1728		case Type#type.tablecinf of
1729		    [{objfun,_}|_] ->
1730			{"got objfun through args",{var,"ObjFun"}};
1731		    _ ->
1732			false
1733		end;
1734	    _ ->
1735		{no_attr,{var,"ObjFun"}}
1736	end,
1737    DoExt = case Constr of
1738		ext -> Ext;
1739		_ -> noext
1740	    end,
1741    Tag = case {Ext,Constr} of
1742	      {noext,_} ->
1743		  asn1ct_imm:per_enc_integer(Pos, Constr, Aligned);
1744	      {{ext,_,_},ext} ->
1745		  [{put_bits,1,1,[1]}|
1746		   asn1ct_imm:per_enc_small_number(Pos, Aligned)];
1747	      {{ext,_,_},_} ->
1748		  [{put_bits,0,1,[1]}|
1749		   asn1ct_imm:per_enc_integer(Pos, Constr, Aligned)]
1750	  end,
1751    Body = gen_enc_line_imm(Erule, TopType, Cname, Type, {var,"ChoiceVal"},
1752			    EncObj, DoExt),
1753    Imm = Tag ++ Body,
1754    [{Cname,Imm}|gen_enc_choices(T, Erule, TopType, Pos+1, Constr, Ext)];
1755gen_enc_choices([], _, _, _, _, _)  -> [].
1756
1757%% Generate the code for CHOICE. If the CHOICE is extensible,
1758%% the structure of the generated code is as follows:
1759%%
1760%% case Bytes of
1761%%   <<0:1,Bytes1/bitstring>> ->
1762%%      Choice = <Decode INTEGER (0..LastRootChoice) from Bytes1>
1763%%      case Choice of
1764%%        0 -> <Decode>;
1765%%        :
1766%%        LastRootChoice -> <Decode>
1767%%      end;
1768%%   <<1:1,Bytes1/bitstring>> ->
1769%%      Choice = <Decode normally small number from Bytes1>
1770%%      TmpVal = <Decode open type>
1771%%      case Choice of
1772%%        0 -> <Decode TmpVal>;
1773%%        :
1774%%        LastExtension -> <Decode TmpVal>;
1775%%        _ -> <Return TmpVal since the type is unknown>
1776%%       end
1777%% end
1778%%
1779%% The return value from the generated function always looks like:
1780%%    {{ChoiceTag,Value},RemainingBuffer}
1781%% where ChoiceTag will be 'asn1_ExtAlt' for an unknown extension.
1782%%
1783%% If the CHOICE is not extensible, the top-level case is omitted
1784%% and only the code in the first case arm is generated.
1785
1786gen_dec_choice(Erule, TopType, CompList, {ext,_,_}=Ext) ->
1787    {RootList,ExtList} = split_complist(CompList),
1788    emit(["case Bytes of",nl]),
1789    case RootList of
1790	[] ->
1791	    ok;
1792	[_|_] ->
1793	    emit(["<<0:1,Bytes1/bitstring>> ->",nl]),
1794	    asn1ct_name:new(bytes),
1795	    gen_dec_choice1(Erule, TopType, RootList, noext),
1796	    emit([";",nl,nl])
1797    end,
1798    emit(["<<1:1,Bytes1/bitstring>> ->",nl]),
1799    asn1ct_name:clear(),
1800    asn1ct_name:new(bytes),
1801    asn1ct_name:new(bytes),
1802    gen_dec_choice1(Erule, TopType, ExtList, Ext),
1803    emit([nl,"end"]);
1804gen_dec_choice(Erule, TopType, CompList, noext) ->
1805    gen_dec_choice1(Erule, TopType, CompList, noext).
1806
1807split_complist({Root1,Ext,Root2}) ->
1808    {Root1++Root2,Ext};
1809split_complist({_,_}=CompList) ->
1810    CompList.
1811
1812gen_dec_choice1(Erule, TopType, CompList, noext=Ext) ->
1813    emit_getchoice(Erule, CompList, Ext),
1814    emit(["case Choice of",nl]),
1815    Pre = {safe,fun(St) ->
1816			{asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
1817			 fun() -> St end}
1818		end},
1819    gen_dec_choice2(Erule, TopType, CompList, Pre),
1820    emit([nl,"end"]);
1821gen_dec_choice1(Erule, TopType, CompList, {ext,_,_}=Ext) ->
1822    emit_getchoice(Erule, CompList, Ext),
1823    Imm = asn1ct_imm:per_dec_open_type(is_aligned(Erule)),
1824    emit(["begin",nl]),
1825    BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
1826    {Dst,DstBuf} = asn1ct_imm:dec_slim_cg(Imm, BytesVar),
1827    emit([nl,
1828	  "end,",nl,
1829	  "case Choice of",nl]),
1830    Pre = {safe,fun(St) ->
1831			emit(["{TmpVal,_} = "]),
1832			{Dst,
1833			 fun() ->
1834				 emit([",",nl,
1835				       "{TmpVal,",DstBuf,"}"]),
1836				 St
1837			 end}
1838		end},
1839    gen_dec_choice2(Erule, TopType, CompList, Pre),
1840    case CompList of
1841	[] -> ok;
1842	[_|_] -> emit([";",nl])
1843    end,
1844    emit(["_ ->",nl,
1845	  "{{asn1_ExtAlt,",Dst,"},",DstBuf,"}",nl,
1846	  "end"]).
1847
1848emit_getchoice(Erule, CompList, Ext) ->
1849    Al = is_aligned(Erule),
1850    Imm = case {Ext,CompList} of
1851	      {noext,[_]} ->
1852		  {value,0};
1853	      {noext,_} ->
1854		  asn1ct_imm:per_dec_constrained(0, length(CompList)-1, Al);
1855	      {{ext,_,_},_} ->
1856		  asn1ct_imm:per_dec_normally_small_number(Al)
1857	  end,
1858    emit(["{Choice,",{curr,bytes},"} = ",nl]),
1859    BytesVar = asn1ct_gen:mk_var(asn1ct_name:prev(bytes)),
1860    asn1ct_imm:dec_code_gen(Imm, BytesVar),
1861    emit([com,nl]).
1862
1863gen_dec_choice2(Erule,TopType,L,Ext) ->
1864    gen_dec_choice2(Erule, TopType, L, 0, [], Ext).
1865
1866gen_dec_choice2(Erule, TopType, [H0|T], Pos, Sep0, Pre) ->
1867    #'ComponentType'{name=Cname,typespec=Type} = H0,
1868    H = H0#'ComponentType'{prop=mandatory},
1869    emit([Sep0,Pos," ->",nl]),
1870    case Type#type.def of
1871	#'ObjectClassFieldType'{type={typefield,_}} ->
1872	    emit("{Cname,{Val,NewBytes}} = begin\n"),
1873	    gen_dec_choice_line(Erule, TopType, H, Pre),
1874	    emit([nl,
1875		  "end,",nl,
1876		  "{{Cname,Val},NewBytes}"]);
1877	_ ->
1878	    emit("{Val,NewBytes} = begin\n"),
1879	    gen_dec_choice_line(Erule, TopType, H, Pre),
1880	    emit([nl,
1881		  "end,",nl,
1882		  "{{",{asis,Cname},",Val},NewBytes}"])
1883    end,
1884    Sep = [";",nl],
1885    gen_dec_choice2(Erule, TopType, T, Pos+1, Sep, Pre);
1886gen_dec_choice2(_, _, [], _, _, _)  -> ok.
1887
1888get_input_vars(Val, I, N) ->
1889    L = get_input_vars_1(Val, I, N),
1890    lists:join(",", L).
1891
1892get_input_vars_1(_Val, _I, 0) ->
1893    [];
1894get_input_vars_1(Val, I, N) ->
1895    [get_input_var(Val, I)|get_input_vars_1(Val, I+1, N-1)].
1896
1897get_input_var(Val, I) ->
1898    lists:flatten(io_lib:format("element(~w, ~s)", [I+1,Val])).
1899
1900emit_extaddgroupTerms(VarSeries,[_]) ->
1901    asn1ct_name:new(VarSeries),
1902    emit({curr,VarSeries}),
1903    ok;
1904emit_extaddgroupTerms(VarSeries,[_|Rest]) ->
1905    asn1ct_name:new(VarSeries),
1906    emit([{curr,VarSeries},","]),
1907    emit_extaddgroupTerms(VarSeries,Rest);
1908emit_extaddgroupTerms(_,[]) ->
1909    ok.
1910
1911flat_complist({Rl1,El,Rl2}) -> Rl1 ++ El ++ Rl2;
1912flat_complist({Rl,El}) -> Rl ++ El;
1913flat_complist(CompList) -> CompList.
1914
1915%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1916%%  Convert all componentTypes following 'ExtensionAdditionGroup'
1917%%  up to the matching 'ExtensionAdditionGroupEnd' into one componentType
1918%%  of type SEQUENCE with the componentTypes as components.
1919%%
1920wrap_extensionAdditionGroups(ExtCompList, ExtGroupPosLen) ->
1921    wrap_eags(ExtCompList, ExtGroupPosLen, 0, 0).
1922
1923wrap_eags([{'ExtensionAdditionGroup',_Number}|T0],
1924          [{ActualPos,_,_}|Gs], _ExtAddGroupDiff, ExtGroupNum) ->
1925    {ExtGroupCompList,['ExtensionAdditionGroupEnd'|T]} =
1926	lists:splitwith(fun(#'ComponentType'{}) -> true;
1927			   (_) -> false
1928			end, T0),
1929    Name = list_to_atom(lists:concat(["ExtAddGroup",ExtGroupNum+1])),
1930    Seq = #type{def=#'SEQUENCE'{extaddgroup=ExtGroupNum+1,
1931                                components=ExtGroupCompList}},
1932    Comp = #'ComponentType'{name=Name,
1933                            typespec=Seq,
1934                            textual_order=ActualPos,
1935                            prop='OPTIONAL'},
1936    [Comp|wrap_eags(T, Gs, length(ExtGroupCompList)-1, ExtGroupNum+1)];
1937wrap_eags([#'ComponentType'{textual_order=Tord}=H|T],
1938          ExtAddGrpLenPos, ExtAddGroupDiff, ExtGroupNum)
1939  when is_integer(Tord) ->
1940    Comp = H#'ComponentType'{textual_order=Tord - ExtAddGroupDiff},
1941    [Comp|wrap_eags(T, ExtAddGrpLenPos, ExtAddGroupDiff, ExtGroupNum)];
1942wrap_eags([H|T], ExtAddGrpLenPos, ExtAddGroupDiff, ExtGroupNum) ->
1943    [H|wrap_eags(T, ExtAddGrpLenPos, ExtAddGroupDiff, ExtGroupNum)];
1944wrap_eags([], _, _, _) ->
1945    [].
1946
1947value_match(#gen{pack=record}, VIs, Value) ->
1948    value_match_rec(VIs, Value);
1949value_match(#gen{pack=map}, VIs, Value) ->
1950    value_match_map(VIs, Value).
1951
1952value_match_rec([], Value) ->
1953    Value;
1954value_match_rec([{VI,_}|VIs], Value0) ->
1955    Value = value_match_rec(VIs, Value0),
1956    lists:concat(["element(",VI,", ",Value,")"]).
1957
1958value_match_map([], Value) ->
1959    Value;
1960value_match_map([{_,Name}|VIs], Value0) ->
1961    Value = value_match_map(VIs, Value0),
1962    lists:concat(["maps:get(",Name,", ",Value,")"]).
1963
1964enc_dig_out_value(_Gen, [], Value) ->
1965    {[],Value};
1966enc_dig_out_value(#gen{pack=record}=Gen, [{N,_}|T], Value) ->
1967    {Imm0,Dst0} = enc_dig_out_value(Gen, T, Value),
1968    {Imm,Dst} = asn1ct_imm:enc_element(N, Dst0),
1969    {Imm0++Imm,Dst};
1970enc_dig_out_value(#gen{pack=map}, [{N,'ASN1_top'}], _Value) ->
1971    {[],{var,lists:concat(["Input@",N-1])}};
1972enc_dig_out_value(#gen{pack=map}=Gen, [{_,Name}|T], Value) ->
1973    {Imm0,Dst0} = enc_dig_out_value(Gen, T, Value),
1974    {Imm,Dst} = asn1ct_imm:enc_maps_get(Name, Dst0),
1975    {Imm0++Imm,Dst}.
1976
1977make_var(Base) ->
1978    {var,atom_to_list(asn1ct_gen:mk_var(asn1ct_name:curr(Base)))}.
1979
1980attribute_comment(InnerType, TextPos, Cname) ->
1981    DispType = case InnerType of
1982		   #'Externaltypereference'{type=T} -> T;
1983		   IT when is_tuple(IT) -> element(2,IT);
1984		   _ -> InnerType
1985	       end,
1986    Comment = ["attribute ",Cname,"(",TextPos,") with type ",DispType],
1987    lists:concat(Comment).
1988
1989dec_func(Tname) ->
1990    list_to_atom(lists:concat(["dec_",Tname])).
1991