1
%% ``The contents of this file are subject to the Erlang Public License,
2
%% Version 1.1, (the "License"); you may not use this file except in
3
%% compliance with the License. You should have received a copy of the
4
%% Erlang Public License along with this software. If not, it can be
5
%% retrieved via the world wide web at http://www.erlang.org/.
7
%% Software distributed under the License is distributed on an "AS IS"
8
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9
%% the License for the specific language governing rights and limitations
12
%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
13
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
14
%% AB. All Rights Reserved.''
16
%% $Id: asn1ct.erl,v 1.1 2008/12/17 09:53:29 mikpe Exp $
20
%% Compile Time functions for ASN.1 (e.g ASN.1 compiler).
22
%%-compile(export_all).
24
-export([compile/1, compile/2]).
25
-export([start/0, start/1, stop/0]).
26
-export([encode/2, encode/3, decode/3]).
27
-export([test/1, test/2, test/3, value/2]).
28
%% Application internal exports
29
-export([compile_asn/3,compile_asn1/3,compile_py/3,compile/3,value/1,vsn/0,
30
create_ets_table/2,get_name_of_def/1,get_pos_of_def/1]).
31
-export([read_config_data/1,get_gen_state_field/1,get_gen_state/0,
32
partial_inc_dec_toptype/1,save_gen_state/1,update_gen_state/2,
33
get_tobe_refed_func/1,reset_gen_state/0,is_function_generated/1,
34
generated_refed_func/1,next_refed_func/0,pop_namelist/0,
35
next_namelist_el/0,update_namelist/1,step_in_constructed/0,
36
add_tobe_refed_func/1,add_generated_refed_func/1]).
38
-include("asn1_records.hrl").
39
-include_lib("stdlib/include/erl_compile.hrl").
41
-import(asn1ct_gen_ber_bin_v2,[encode_tag_val/3,decode_class/1]).
43
-define(unique_names,0).
44
-define(dupl_uniquedefs,1).
45
-define(dupl_equaldefs,2).
46
-define(dupl_eqdefs_uniquedefs,?dupl_equaldefs bor ?dupl_uniquedefs).
48
-define(CONSTRUCTED, 2#00100000).
50
%% macros used for partial decode commands
51
-define(CHOOSEN,choosen).
53
-define(SKIP_OPTIONAL,skip_optional).
55
%% macros used for partial incomplete decode commands
56
-define(MANDATORY,mandatory).
57
-define(DEFAULT,default).
58
-define(OPTIONAL,opt).
60
-define(UNDECODED,undec).
61
-define(ALTERNATIVE,alt).
62
-define(ALTERNATIVE_UNDECODED,alt_undec).
63
-define(ALTERNATIVE_PARTS,alt_parts).
66
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
67
%% This is the interface to the compiler
75
compile(File,Options) when list(Options) ->
77
case {lists:member(optimize,Options),lists:member(ber_bin,Options)} of
79
[ber_bin_v2|Options--[ber_bin]];
82
case (catch input_file_type(File)) of
83
{single_file,PrefixedFile} ->
84
(catch compile1(PrefixedFile,Options1));
85
{multiple_files_file,SetBase,FileName} ->
86
FileList = get_file_list(FileName),
87
(catch compile_set(SetBase,filename:dirname(FileName),
89
Err = {input_file_error,_Reason} ->
94
compile1(File,Options) when list(Options) ->
95
io:format("Erlang ASN.1 version ~p compiling ~p ~n",[?vsn,File]),
96
io:format("Compiler Options: ~p~n",[Options]),
97
Ext = filename:extension(File),
98
Base = filename:basename(File,Ext),
99
OutFile = outfile(Base,"",Options),
100
DbFile = outfile(Base,"asn1db",Options),
101
Includes = [I || {i,I} <- Options],
102
EncodingRule = get_rule(Options),
103
create_ets_table(asn1_functab,[named_table]),
104
Continue1 = scan({true,true},File,Options),
105
Continue2 = parse(Continue1,File,Options),
106
Continue3 = check(Continue2,File,OutFile,Includes,EncodingRule,
108
Continue4 = generate(Continue3,OutFile,EncodingRule,Options),
109
delete_tables([asn1_functab]),
110
compile_erl(Continue4,OutFile,Options).
112
%%****************************************************************************%%
113
%% functions dealing with compiling of several input files to one output file %%
114
%%****************************************************************************%%
115
compile_set(SetBase,DirName,Files,Options) when list(hd(Files)),list(Options) ->
116
%% case when there are several input files in a list
117
io:format("Erlang ASN.1 version ~p compiling ~p ~n",[?vsn,Files]),
118
io:format("Compiler Options: ~p~n",[Options]),
119
OutFile = outfile(SetBase,"",Options),
120
DbFile = outfile(SetBase,"asn1db",Options),
121
Includes = [I || {i,I} <- Options],
122
EncodingRule = get_rule(Options),
123
create_ets_table(asn1_functab,[named_table]),
124
ScanRes = scan_set(DirName,Files,Options),
125
ParseRes = parse_set(ScanRes,Options),
127
case [X||X <- ParseRes,element(1,X)==true] of
128
[] -> %% all were false, time to quit
129
lists:map(fun(X)->element(2,X) end,ParseRes);
130
ParseRes -> %% all were true, continue with check
134
E = filename:extension(F),
135
B = filename:basename(F,E),
137
list(B) -> list_to_atom(B);
142
check_set(ParseRes,SetBase,OutFile,Includes,
143
EncodingRule,DbFile,Options,InputModules);
145
{error,{'unexpected error in scan/parse phase',
146
lists:map(fun(X)->element(3,X) end,Other)}}
148
delete_tables([asn1_functab]),
151
check_set(ParseRes,SetBase,OutFile,Includes,EncRule,DbFile,
152
Options,InputModules) ->
153
lists:foreach(fun({_T,M,File})->
154
cmp(M#module.name,File)
157
MergedModule = merge_modules(ParseRes,SetBase),
158
SetM = MergedModule#module{name=SetBase},
159
Continue1 = check({true,SetM},SetBase,OutFile,Includes,EncRule,DbFile,
160
Options,InputModules),
161
Continue2 = generate(Continue1,OutFile,EncRule,Options),
163
delete_tables([renamed_defs,original_imports,automatic_tags]),
165
compile_erl(Continue2,OutFile,Options).
167
%% merge_modules/2 -> returns a module record where the typeorval lists are merged,
168
%% the exports lists are merged, the imports lists are merged when the
169
%% elements come from other modules than the merge set, the tagdefault
170
%% field gets the shared value if all modules have same tagging scheme,
171
%% otherwise a tagging_error exception is thrown,
172
%% the extensiondefault ...(not handled yet).
173
merge_modules(ParseRes,CommonName) ->
174
ModuleList = lists:map(fun(X)->element(2,X) end,ParseRes),
175
NewModuleList = remove_name_collisions(ModuleList),
176
case ets:info(renamed_defs,size) of
177
0 -> ets:delete(renamed_defs);
180
save_imports(NewModuleList),
181
% io:format("~p~n~p~n~p~n~n",[ets:lookup(original_imports,'M1'),ets:lookup(original_imports,'M2'),ets:tab2list(original_imports)]),
182
TypeOrVal = lists:append(lists:map(fun(X)->X#module.typeorval end,
184
InputMNameList = lists:map(fun(X)->X#module.name end,
186
CExports = common_exports(NewModuleList),
188
ImportsModuleNameList = lists:map(fun(X)->
192
%% ImportsModuleNameList: [{Imports,ModuleName},...]
193
%% Imports is a tuple {imports,[#'SymbolsFromModule'{},...]}
194
CImports = common_imports(ImportsModuleNameList,InputMNameList),
195
TagDefault = check_tagdefault(NewModuleList),
196
#module{name=CommonName,tagdefault=TagDefault,exports=CExports,
197
imports=CImports,typeorval=TypeOrVal}.
199
%% causes an exit if duplicate definition names exist in a module
200
remove_name_collisions(Modules) ->
201
create_ets_table(renamed_defs,[named_table]),
202
%% Name duplicates in the same module is not allowed.
203
lists:foreach(fun exit_if_nameduplicate/1,Modules),
204
%% Then remove duplicates in different modules and return the
205
%% new list of modules.
206
remove_name_collisions2(Modules,[]).
208
%% For each definition in the first module in module list, find
209
%% all definitons with same name and rename both definitions in
210
%% the first module and in rest of modules
211
remove_name_collisions2([M|Ms],Acc) ->
212
TypeOrVal = M#module.typeorval,
213
MName = M#module.name,
214
%% Test each name in TypeOrVal on all modules in Ms
215
{NewM,NewMs} = remove_name_collisions2(MName,TypeOrVal,Ms,[]),
216
remove_name_collisions2(NewMs,[M#module{typeorval=NewM}|Acc]);
217
remove_name_collisions2([],Acc) ->
218
finished_warn_prints(),
221
%% For each definition in list of defs find definitions in (rest of)
222
%% modules that have same name. If duplicate was found rename def.
223
%% Test each name in [T|Ts] on all modules in Ms
224
remove_name_collisions2(ModName,[T|Ts],Ms,Acc) ->
225
Name = get_name_of_def(T),
226
case discover_dupl_in_mods(Name,T,Ms,[],?unique_names) of
227
{_,?unique_names} -> % there was no name collision
228
remove_name_collisions2(ModName,Ts,Ms,[T|Acc]);
229
{NewMs,?dupl_uniquedefs} -> % renamed defs in NewMs
231
NewT = set_name_of_def(ModName,Name,T), %rename def
232
warn_renamed_def(ModName,get_name_of_def(NewT),Name),
233
ets:insert(renamed_defs,{get_name_of_def(NewT),Name,ModName}),
234
remove_name_collisions2(ModName,Ts,NewMs,[NewT|Acc]);
235
{NewMs,?dupl_equaldefs} -> % name duplicates, but identical defs
237
warn_kept_def(ModName,Name),
238
remove_name_collisions2(ModName,Ts,NewMs,[T|Acc]);
239
{NewMs,?dupl_eqdefs_uniquedefs} ->
240
%% keep name of T, renamed defs in NewMs
241
warn_kept_def(ModName,Name),
242
remove_name_collisions2(ModName,Ts,NewMs,[T|Acc])
244
remove_name_collisions2(_,[],Ms,Acc) ->
247
%% Name is the name of a definition. If a definition with the same name
248
%% is found in the modules Ms the definition will be renamed and returned.
249
discover_dupl_in_mods(Name,Def,[M=#module{name=N,typeorval=TorV}|Ms],
251
Fun = fun(T,RenamedOrDupl)->
252
case {get_name_of_def(T),compare_defs(Def,T)} of
255
NewT=set_name_of_def(N,Name,T),
256
warn_renamed_def(N,get_name_of_def(NewT),Name),
257
ets:insert(renamed_defs,{get_name_of_def(NewT),
259
{NewT,?dupl_uniquedefs bor RenamedOrDupl};
262
warn_deleted_def(N,Name),
263
{[],?dupl_equaldefs bor RenamedOrDupl};
268
{NewTorV,NewAnyRenamed} = lists:mapfoldl(Fun,AnyRenamed,TorV),
269
%% have to flatten the NewTorV to remove any empty list elements
270
discover_dupl_in_mods(Name,Def,Ms,
271
[M#module{typeorval=lists:flatten(NewTorV)}|Acc],
273
discover_dupl_in_mods(_,_,[],Acc,AnyRenamed) ->
276
warn_renamed_def(ModName,NewName,OldName) ->
277
maybe_first_warn_print(),
278
io:format("NOTICE: The ASN.1 definition in module ~p with name ~p has been renamed in generated module. New name is ~p.~n",[ModName,OldName,NewName]).
280
warn_deleted_def(ModName,DefName) ->
281
maybe_first_warn_print(),
282
io:format("NOTICE: The ASN.1 definition in module ~p with name ~p has been deleted in generated module.~n",[ModName,DefName]).
284
warn_kept_def(ModName,DefName) ->
285
maybe_first_warn_print(),
286
io:format("NOTICE: The ASN.1 definition in module ~p with name ~p has kept its name due to equal definition as duplicate.~n",[ModName,DefName]).
288
maybe_first_warn_print() ->
289
case get(warn_duplicate_defs) of
291
put(warn_duplicate_defs,true),
292
io:format("~nDue to multiple occurrences of a definition name in "
293
"multi-file compiled files:~n");
297
finished_warn_prints() ->
298
put(warn_duplicate_defs,undefined).
301
exit_if_nameduplicate(#module{typeorval=TorV}) ->
302
exit_if_nameduplicate(TorV);
303
exit_if_nameduplicate([]) ->
305
exit_if_nameduplicate([Def|Rest]) ->
306
Name=get_name_of_def(Def),
307
exit_if_nameduplicate2(Name,Rest),
308
exit_if_nameduplicate(Rest).
310
exit_if_nameduplicate2(Name,Rest) ->
312
case get_name_of_def(Def) of
317
case lists:any(Pred,Rest) of
319
throw({error,{"more than one definition with same name",Name}});
324
compare_defs(D1,D2) ->
325
compare_defs2(unset_pos(D1),unset_pos(D2)).
326
compare_defs2(D,D) ->
328
compare_defs2(_,_) ->
331
unset_pos(Def) when record(Def,typedef) ->
332
Def#typedef{pos=undefined};
333
unset_pos(Def) when record(Def,classdef) ->
334
Def#classdef{pos=undefined};
335
unset_pos(Def) when record(Def,valuedef) ->
336
Def#valuedef{pos=undefined};
337
unset_pos(Def) when record(Def,ptypedef) ->
338
Def#ptypedef{pos=undefined};
339
unset_pos(Def) when record(Def,pvaluedef) ->
340
Def#pvaluedef{pos=undefined};
341
unset_pos(Def) when record(Def,pvaluesetdef) ->
342
Def#pvaluesetdef{pos=undefined};
343
unset_pos(Def) when record(Def,pobjectdef) ->
344
Def#pobjectdef{pos=undefined};
345
unset_pos(Def) when record(Def,pobjectsetdef) ->
346
Def#pobjectsetdef{pos=undefined}.
348
get_pos_of_def(#typedef{pos=Pos}) ->
350
get_pos_of_def(#classdef{pos=Pos}) ->
352
get_pos_of_def(#valuedef{pos=Pos}) ->
354
get_pos_of_def(#ptypedef{pos=Pos}) ->
356
get_pos_of_def(#pvaluedef{pos=Pos}) ->
358
get_pos_of_def(#pvaluesetdef{pos=Pos}) ->
360
get_pos_of_def(#pobjectdef{pos=Pos}) ->
362
get_pos_of_def(#pobjectsetdef{pos=Pos}) ->
366
get_name_of_def(#typedef{name=Name}) ->
368
get_name_of_def(#classdef{name=Name}) ->
370
get_name_of_def(#valuedef{name=Name}) ->
372
get_name_of_def(#ptypedef{name=Name}) ->
374
get_name_of_def(#pvaluedef{name=Name}) ->
376
get_name_of_def(#pvaluesetdef{name=Name}) ->
378
get_name_of_def(#pobjectdef{name=Name}) ->
380
get_name_of_def(#pobjectsetdef{name=Name}) ->
383
set_name_of_def(ModName,Name,OldDef) ->
384
NewName = list_to_atom(lists:concat([Name,ModName])),
386
#typedef{} -> OldDef#typedef{name=NewName};
387
#classdef{} -> OldDef#classdef{name=NewName};
388
#valuedef{} -> OldDef#valuedef{name=NewName};
389
#ptypedef{} -> OldDef#ptypedef{name=NewName};
390
#pvaluedef{} -> OldDef#pvaluedef{name=NewName};
391
#pvaluesetdef{} -> OldDef#pvaluesetdef{name=NewName};
392
#pobjectdef{} -> OldDef#pobjectdef{name=NewName};
393
#pobjectsetdef{} -> OldDef#pobjectsetdef{name=NewName}
396
save_imports(ModuleList)->
398
case M#module.imports of
404
ImportsList = lists:map(Fun,ModuleList),
405
case lists:flatten(ImportsList) of
409
create_ets_table(original_imports,[named_table]),
410
ets:insert(original_imports,ImportsList2)
414
common_exports(ModuleList) ->
415
%% if all modules exports 'all' then export 'all',
416
%% otherwise export each typeorval name
417
case lists:filter(fun(X)->
418
element(2,X#module.exports) /= all
425
lists:append(lists:map(fun(X)->element(2,X#module.exports) end,
427
CExports2 = export_all(lists:subtract(ModuleList,ModsWithExpList)),
428
{exports,CExports1++CExports2}
432
export_all(ModuleList) ->
436
TorVL=M#module.typeorval,
437
MName = M#module.name,
441
T when record(T,typedef)->
442
#'Externaltypereference'{pos=0,
444
type=T#typedef.name};
445
V when record(V,valuedef) ->
446
#'Externalvaluereference'{pos=0,
448
value=V#valuedef.name};
449
C when record(C,classdef) ->
450
#'Externaltypereference'{pos=0,
452
type=C#classdef.name};
453
P when record(P,ptypedef) ->
454
#'Externaltypereference'{pos=0,
456
type=P#ptypedef.name};
457
PV when record(PV,pvaluesetdef) ->
458
#'Externaltypereference'{pos=0,
460
type=PV#pvaluesetdef.name};
461
PO when record(PO,pobjectdef) ->
462
#'Externalvaluereference'{pos=0,
464
value=PO#pobjectdef.name}
470
lists:append(ExpList).
473
%% IList is a list of tuples, {Imports,MName}, where Imports is the imports of
474
%% the module with name MName.
475
%% InputMNameL holds the names of all merged modules.
476
%% Returns an import tuple with a list of imports that are external the merged
478
common_imports(IList,InputMNameL) ->
479
SetExternalImportsList = remove_in_set_imports(IList,InputMNameL,[]),
480
{imports,remove_import_doubles(SetExternalImportsList)}.
482
check_tagdefault(ModList) ->
483
case have_same_tagdefault(ModList) of
484
{true,TagDefault} -> TagDefault;
485
{false,TagDefault} ->
486
create_ets_table(automatic_tags,[named_table]),
487
save_automatic_tagged_types(ModList),
491
have_same_tagdefault([#module{tagdefault=T}|Ms]) ->
492
have_same_tagdefault(Ms,{true,T}).
494
have_same_tagdefault([],TagDefault) ->
496
have_same_tagdefault([#module{tagdefault=T}|Ms],TDefault={_,T}) ->
497
have_same_tagdefault(Ms,TDefault);
498
have_same_tagdefault([#module{tagdefault=T1}|Ms],{_,T2}) ->
499
have_same_tagdefault(Ms,{false,rank_tagdef([T1,T2])}).
502
case lists:member('EXPLICIT',L) of
507
save_automatic_tagged_types([])->
509
save_automatic_tagged_types([#module{tagdefault='AUTOMATIC',
510
typeorval=TorV}|Ms]) ->
513
ets:insert(automatic_tags,{get_name_of_def(T)})
515
lists:foreach(Fun,TorV),
516
save_automatic_tagged_types(Ms);
517
save_automatic_tagged_types([_M|Ms]) ->
518
save_automatic_tagged_types(Ms).
520
%% remove_in_set_imports/3 :
521
%% input: list with tuples of each module's imports and module name
523
%% output: one list with same format but each occured import from a
524
%% module in the input set (IMNameL) is removed.
525
remove_in_set_imports([{{imports,ImpL},_ModName}|Rest],InputMNameL,Acc) ->
526
NewImpL = remove_in_set_imports1(ImpL,InputMNameL,[]),
527
remove_in_set_imports(Rest,InputMNameL,NewImpL++Acc);
528
remove_in_set_imports([],_,Acc) ->
531
remove_in_set_imports1([I|Is],InputMNameL,Acc) ->
532
case I#'SymbolsFromModule'.module of
533
#'Externaltypereference'{type=MName} ->
534
case lists:member(MName,InputMNameL) of
536
remove_in_set_imports1(Is,InputMNameL,Acc);
538
remove_in_set_imports1(Is,InputMNameL,[I|Acc])
541
remove_in_set_imports1(Is,InputMNameL,[I|Acc])
543
remove_in_set_imports1([],_,Acc) ->
546
remove_import_doubles([]) ->
548
%% If several modules in the merge set imports symbols from
549
%% the same external module it might be doubled.
550
%% ImportList has #'SymbolsFromModule' elements
551
remove_import_doubles(ImportList) ->
553
merge_symbols_from_module(ImportList,[]),
554
%% io:format("MergedImportList: ~p~n",[MergedImportList]),
555
delete_double_of_symbol(MergedImportList,[]).
557
merge_symbols_from_module([Imp|Imps],Acc) ->
558
#'Externaltypereference'{type=ModName} = Imp#'SymbolsFromModule'.module,
562
case I#'SymbolsFromModule'.module of
563
#'Externaltypereference'{type=ModName} ->
565
#'Externalvaluereference'{value=ModName} ->
571
NewImps = lists:subtract(Imps,IfromModName),
572
%% io:format("Imp: ~p~nIfromModName: ~p~n",[Imp,IfromModName]),
574
Imp#'SymbolsFromModule'{
575
symbols = lists:append(
577
SL#'SymbolsFromModule'.symbols
578
end,[Imp|IfromModName]))},
579
merge_symbols_from_module(NewImps,[NewImp|Acc]);
580
merge_symbols_from_module([],Acc) ->
583
delete_double_of_symbol([I|Is],Acc) ->
584
SymL=I#'SymbolsFromModule'.symbols,
585
NewSymL = delete_double_of_symbol1(SymL,[]),
586
delete_double_of_symbol(Is,[I#'SymbolsFromModule'{symbols=NewSymL}|Acc]);
587
delete_double_of_symbol([],Acc) ->
590
delete_double_of_symbol1([TRef=#'Externaltypereference'{type=TrefName}|Rest],Acc)->
592
lists:filter(fun(S)->
594
#'Externaltypereference'{type=TrefName}->
600
delete_double_of_symbol1(NewRest,[TRef|Acc]);
601
delete_double_of_symbol1([VRef=#'Externalvaluereference'{value=VName}|Rest],Acc) ->
603
lists:filter(fun(S)->
605
#'Externalvaluereference'{value=VName}->
611
delete_double_of_symbol1(NewRest,[VRef|Acc]);
612
delete_double_of_symbol1([TRef={#'Externaltypereference'{type=MRef},
613
#'Externaltypereference'{type=TRef}}|Rest],
619
{#'Externaltypereference'{type=MRef},
620
#'Externaltypereference'{type=TRef}}->
626
delete_double_of_symbol1(NewRest,[TRef|Acc]);
627
delete_double_of_symbol1([],Acc) ->
631
scan_set(DirName,Files,Options) ->
634
case scan({true,true},filename:join([DirName,F]),Options) of
635
{false,{error,Reason}} ->
636
throw({error,{'scan error in file:',F,Reason}});
643
parse_set(ScanRes,Options) ->
646
case parse({TorF,Toks},F,Options) of
647
{false,{error,Reason}} ->
648
throw({error,{'parse error in file:',F,Reason}});
656
%%***********************************
659
scan({true,_}, File,Options) ->
660
case asn1ct_tok:file(File) of
662
io:format("~p~n",[Reason]),
663
{false,{error,Reason}};
665
case lists:member(ss,Options) of
666
true -> % we terminate after scan
668
false -> % continue with next pass
672
scan({false,Result},_,_) ->
676
parse({true,Tokens},File,Options) ->
677
%Presult = asn1ct_parser2:parse(Tokens),
678
%%case lists:member(p1,Options) of
680
%% asn1ct_parser:parse(Tokens);
682
%% asn1ct_parser2:parse(Tokens)
684
case catch asn1ct_parser2:parse(Tokens) of
685
{error,{{Line,_Mod,Message},_TokTup}} ->
688
BaseName = filename:basename(File),
689
io:format("syntax error at line ~p in module ~s:~n",
692
io:format("syntax error in module ~p:~n",[File])
694
print_error_message(Message),
695
{false,{error,Message}};
696
{error,{Line,_Mod,[Message,Token]}} ->
697
io:format("syntax error: ~p ~p at line ~p~n",
698
[Message,Token,Line]),
699
{false,{error,{Line,[Message,Token]}}};
701
case lists:member(sp,Options) of
702
true -> % terminate after parse
704
false -> % continue with next pass
708
io:format("~p~n",[OtherError])
710
parse({false,Tokens},_,_) ->
713
check({true,M},File,OutFile,Includes,EncodingRule,DbFile,Options,InputMods) ->
714
cmp(M#module.name,File),
715
start(["."|Includes]),
716
case asn1ct_check:storeindb(M) of
718
Module = asn1_db:dbget(M#module.name,'MODULE'),
719
State = #state{mname=Module#module.name,
720
module=Module#module{typeorval=[]},
722
inputmodules=InputMods,
724
Check = asn1ct_check:check(State,Module#module.typeorval),
725
case {Check,lists:member(abs,Options)} of
726
{{error,Reason},_} ->
727
{false,{error,Reason}};
728
{{ok,NewTypeOrVal,_},true} ->
729
NewM = Module#module{typeorval=NewTypeOrVal},
730
asn1_db:dbput(NewM#module.name,'MODULE',NewM),
731
pretty2(M#module.name,lists:concat([OutFile,".abs"])),
733
{{ok,NewTypeOrVal,GenTypeOrVal},_} ->
734
NewM = Module#module{typeorval=NewTypeOrVal},
735
asn1_db:dbput(NewM#module.name,'MODULE',NewM),
736
asn1_db:dbsave(DbFile,M#module.name),
737
io:format("--~p--~n",[{generated,DbFile}]),
738
{true,{M,NewM,GenTypeOrVal}}
741
check({false,M},_,_,_,_,_,_,_) ->
744
generate({true,{M,_Module,GenTOrV}},OutFile,EncodingRule,Options) ->
746
case lists:member(compact_bit_string,Options) of
747
true -> put(compact_bit_string,true);
750
put(encoding_options,Options),
751
create_ets_table(check_functions,[named_table]),
753
%% create decoding function names and taglists for partial decode
754
%% For the time being leave errors unnoticed !!!!!!!!!
755
% io:format("Options: ~p~n",[Options]),
756
case catch specialized_decode_prepare(EncodingRule,M,GenTOrV,Options) of
757
{error, enoent} -> ok;
758
{error, Reason} -> io:format("WARNING: Error in configuration"
759
"file: ~n~p~n",[Reason]);
760
{'EXIT',Reason} -> io:format("WARNING: Internal error when "
761
"analyzing configuration"
762
"file: ~n~p~n",[Reason]);
766
asn1ct_gen:pgen(OutFile,EncodingRule,M#module.name,GenTOrV),
768
put(compact_bit_string,false),
769
erase(encoding_options),
770
erase(tlv_format), % used in ber_bin, optimize
771
erase(class_default_type),% used in ber_bin, optimize
772
ets:delete(check_functions),
773
case lists:member(sg,Options) of
774
true -> % terminate here , with .erl file generated
779
generate({false,M},_,_,_) ->
782
compile_erl({true,_},OutFile,Options) ->
783
erl_compile(OutFile,Options);
784
compile_erl({false,true},_,_) ->
786
compile_erl({false,Result},_,_) ->
789
input_file_type([]) ->
791
input_file_type(File) ->
792
case filename:extension(File) of
794
case file:read_file_info(lists:concat([File,".asn1"])) of
796
{single_file, lists:concat([File,".asn1"])};
798
case file:read_file_info(lists:concat([File,".asn"])) of
800
{single_file, lists:concat([File,".asn"])};
802
{single_file, lists:concat([File,".py"])}
806
case read_config_file(File,asn1_module) of
808
put(asn1_config_file,File),
809
input_file_type(Asn1Module);
814
Base = filename:basename(File,Asn1PFix),
815
case filename:extension(Base) of
818
SetPFix when (SetPFix == ".set") ->
819
{multiple_files_file,
820
filename:basename(Base,SetPFix),
823
throw({input_file_error,{'Bad input file',File}})
827
get_file_list(File) ->
828
case file:open(File, [read]) of
830
{error,{File,file:format_error(Reason)}};
832
get_file_list1(Stream,[])
835
get_file_list1(Stream,Acc) ->
836
Ret = io:get_line(Stream,''),
843
case (catch input_file_type(lists:delete($\n,FileName))) of
844
{empty_name,[]} -> [];
845
{single_file,Name} -> [Name];
846
{multiple_files_file,Name} ->
848
Err = {input_file_error,_Reason} ->
851
get_file_list1(Stream,PrefixedNameList++Acc)
855
case [Rule ||Rule <-[per,ber,ber_bin,ber_bin_v2,per_bin],
866
erl_compile(OutFile,Options) ->
867
% io:format("Options:~n~p~n",[Options]),
868
case lists:member(noobj,Options) of
872
ErlOptions = remove_asn_flags(Options),
873
case c:c(OutFile,ErlOptions) of
877
{error,'no_compilation'}
881
remove_asn_flags(Options) ->
883
X /= get_rule(Options),
885
X /= compact_bit_string,
890
case lists:member(debug,Options) of
896
case lists:member(keyed_list,Options) of
898
put(asn_keyed_list,true);
904
debug_off(_Options) ->
906
erase(asn_keyed_list).
909
outfile(Base, Ext, Opts) when atom(Ext) ->
910
outfile(Base, atom_to_list(Ext), Opts);
911
outfile(Base, Ext, Opts) ->
912
Obase = case lists:keysearch(outdir, 1, Opts) of
913
{value, {outdir, Odir}} -> filename:join(Odir, Base);
914
_NotFound -> Base % Not found or bad format
923
%% compile(AbsFileName, Options)
924
%% Compile entry point for erl_compile.
926
compile_asn(File,OutFile,Options) ->
927
compile(lists:concat([File,".asn"]),OutFile,Options).
929
compile_asn1(File,OutFile,Options) ->
930
compile(lists:concat([File,".asn1"]),OutFile,Options).
932
compile_py(File,OutFile,Options) ->
933
compile(lists:concat([File,".py"]),OutFile,Options).
935
compile(File, _OutFile, Options) ->
936
case catch compile(File, make_erl_options(Options)) of
937
Exit = {'EXIT',_Reason} ->
938
io:format("~p~n~s~n",[Exit,"error"]),
941
%% case occurs due to error in asn1ct_parser2,asn1ct_check
942
%% io:format("~p~n",[_Reason]),
943
%% io:format("~p~n~s~n",[_Reason,"error"]),
948
ParseRes when tuple(ParseRes) ->
949
io:format("~p~n",[ParseRes]),
951
ScanRes when list(ScanRes) ->
952
io:format("~p~n",[ScanRes]),
955
io:format("~p~n~s~n",[Unknown,"error"]),
959
%% Converts generic compiler options to specific options.
961
make_erl_options(Opts) ->
963
%% This way of extracting will work even if the record passed
964
%% has more fields than known during compilation.
966
Includes = Opts#options.includes,
967
Defines = Opts#options.defines,
968
Outdir = Opts#options.outdir,
969
%% Warning = Opts#options.warning,
970
Verbose = Opts#options.verbose,
971
Specific = Opts#options.specific,
972
Optimize = Opts#options.optimize,
973
OutputType = Opts#options.output_type,
974
Cwd = Opts#options.cwd,
983
%%% _ -> [report_warnings]
989
_ -> [{optimize,Optimize}]
992
fun ({Name, Value}) ->
999
undefined -> [ber]; % temporary default (ber when it's ready)
1001
ber_bin -> [ber_bin];
1002
ber_bin_v2 -> [ber_bin_v2];
1004
per_bin -> [per_bin]
1007
Options++[report_errors, {cwd, Cwd}, {outdir, Outdir}|
1008
lists:map(fun(Dir) -> {i, Dir} end, Includes)]++Specific.
1010
pretty2(Module,AbsFile) ->
1012
{ok,F} = file:open(AbsFile, [write]),
1013
M = asn1_db:dbget(Module,'MODULE'),
1014
io:format(F,"%%%%%%%%%%%%%%%%%%% ~p %%%%%%%%%%%%%%%%%%%~n",[Module]),
1015
io:format(F,"~s\n",[asn1ct_pretty_format:term(M#module.defid)]),
1016
io:format(F,"~s\n",[asn1ct_pretty_format:term(M#module.tagdefault)]),
1017
io:format(F,"~s\n",[asn1ct_pretty_format:term(M#module.exports)]),
1018
io:format(F,"~s\n",[asn1ct_pretty_format:term(M#module.imports)]),
1019
io:format(F,"~s\n\n",[asn1ct_pretty_format:term(M#module.extensiondefault)]),
1021
{Types,Values,ParameterizedTypes,Classes,Objects,ObjectSets} = M#module.typeorval,
1022
io:format(F,"%%%%%%%%%%%%%%%%%%% TYPES in ~p %%%%%%%%%%%%%%%%%%%~n",[Module]),
1023
lists:foreach(fun(T)-> io:format(F,"~s\n",
1024
[asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])
1026
io:format(F,"%%%%%%%%%%%%%%%%%%% VALUES in ~p %%%%%%%%%%%%%%%%%%%~n",[Module]),
1027
lists:foreach(fun(T)-> io:format(F,"~s\n",
1028
[asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])
1030
io:format(F,"%%%%%%%%%%%%%%%%%%% Parameterized Types in ~p %%%%%%%%%%%%%%%%%%%~n",[Module]),
1031
lists:foreach(fun(T)-> io:format(F,"~s\n",
1032
[asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])
1033
end,ParameterizedTypes),
1034
io:format(F,"%%%%%%%%%%%%%%%%%%% Classes in ~p %%%%%%%%%%%%%%%%%%%~n",[Module]),
1035
lists:foreach(fun(T)-> io:format(F,"~s\n",
1036
[asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])
1038
io:format(F,"%%%%%%%%%%%%%%%%%%% Objects in ~p %%%%%%%%%%%%%%%%%%%~n",[Module]),
1039
lists:foreach(fun(T)-> io:format(F,"~s\n",
1040
[asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])
1042
io:format(F,"%%%%%%%%%%%%%%%%%%% Object Sets in ~p %%%%%%%%%%%%%%%%%%%~n",[Module]),
1043
lists:foreach(fun(T)-> io:format(F,"~s\n",
1044
[asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])
1051
start(Includes) when list(Includes) ->
1052
asn1_db:dbstart(Includes).
1056
asn1_db:stop_server(ns),
1057
asn1_db:stop_server(rand),
1064
%% asn1_db:dbclear().
1066
encode(Module,Term) ->
1067
asn1rt:encode(Module,Term).
1069
encode(Module,Type,Term) when list(Module) ->
1070
asn1rt:encode(list_to_atom(Module),Type,Term);
1071
encode(Module,Type,Term) ->
1072
asn1rt:encode(Module,Type,Term).
1074
decode(Module,Type,Bytes) when list(Module) ->
1075
asn1rt:decode(list_to_atom(Module),Type,Bytes);
1076
decode(Module,Type,Bytes) ->
1077
asn1rt:decode(Module,Type,Bytes).
1082
M = asn1_db:dbget(Module,'MODULE'),
1083
{Types,_Values,_Ptypes,_Classes,_Objects,_ObjectSets} = M#module.typeorval,
1084
test_each(Module,Types).
1086
test_each(Module,[Type | Rest]) ->
1087
case test(Module,Type) of
1089
test_each(Module,Rest);
1096
test(Module,Type) ->
1097
io:format("~p:~p~n",[Module,Type]),
1098
case (catch value(Module,Type)) of
1100
%% io:format("asn1ct:test/2: ~w~n",[Val]),
1101
test(Module,Type,Val);
1103
{error,{asn1,{value,Reason}}}
1107
test(Module,Type,Value) ->
1108
case catch encode(Module,Type,Value) of
1110
%% io:format("test 1: ~p~n",[{Bytes}]),
1113
list_to_atom(Module);
1118
case M:encoding_rule() of
1120
lists:flatten(Bytes);
1121
ber_bin when binary(Bytes) ->
1124
list_to_binary(Bytes);
1125
ber_bin_v2 when binary(Bytes) ->
1128
list_to_binary(Bytes);
1130
lists:flatten(Bytes);
1131
per_bin when binary(Bytes) ->
1134
list_to_binary(Bytes)
1136
case decode(Module,Type,NewBytes) of
1138
{ok,{Module,Type,Value}};
1140
{error,{asn1,{encode_decode_mismatch,
1141
{{Module,Type,Value},Res}}}};
1143
{error,{asn1,{{decode,
1144
{Module,Type,Value},Error}}}}
1147
{error,{asn1,{encode,{{Module,Type,Value},Error}}}}
1152
M = asn1_db:dbget(Module,'MODULE'),
1153
{Types,_Values,_Ptypes,_Classes,_Objects,_ObjectSets} = M#module.typeorval,
1154
lists:map(fun(A) ->value(Module,A) end,Types).
1156
value(Module,Type) ->
1158
case catch asn1ct_value:get_type(Module,Type,no) of
1167
cmp(Module,InFile) ->
1168
Base = filename:basename(InFile),
1169
Dir = filename:dirname(InFile),
1170
Ext = filename:extension(Base),
1171
Finfo = file:read_file_info(InFile),
1172
Minfo = file:read_file_info(filename:join(Dir,lists:concat([Module,Ext]))),
1177
io:format("asn1error: Modulename and filename must be equal~n",[]),
1184
print_error_message([got,H|T]) when list(H) ->
1186
print_listing(H,"and"),
1187
print_error_message(T);
1188
print_error_message([expected,H|T]) when list(H) ->
1189
io:format(" expected one of:"),
1190
print_listing(H,"or"),
1191
print_error_message(T);
1192
print_error_message([H|T]) ->
1193
io:format(" ~p",[H]),
1194
print_error_message(T);
1195
print_error_message([]) ->
1198
print_listing([H1,H2|[]],AndOr) ->
1199
io:format(" ~p ~s ~p",[H1,AndOr,H2]);
1200
print_listing([H1,H2|T],AndOr) ->
1201
io:format(" ~p,",[H1]),
1202
print_listing([H2|T],AndOr);
1203
print_listing([H],_AndOr) ->
1204
io:format(" ~p",[H]);
1205
print_listing([],_) ->
1209
%% functions to administer ets tables
1211
%% Always creates a new table
1212
create_ets_table(Name,Options) when atom(Name) ->
1213
case ets:info(Name) of
1215
ets:new(Name,Options);
1218
ets:new(Name,Options)
1221
%% Creates a new ets table only if no table exists
1222
create_if_no_table(Name,Options) ->
1223
case ets:info(Name) of
1225
%% create a new table
1226
create_ets_table(Name,Options);
1231
delete_tables([Table|Ts]) ->
1232
case ets:info(Table) of
1234
_ -> ets:delete(Table)
1237
delete_tables([]) ->
1241
specialized_decode_prepare(Erule,M,TsAndVs,Options) ->
1243
% fun([{asn1config,File}|_],_) ->
1249
% case Asn1confMember(Options,Asn1confMember) of
1251
case lists:member(asn1config,Options) of
1253
partial_decode_prepare(Erule,M,TsAndVs,Options);
1257
%% Reads the configuration file if it exists and stores information
1258
%% about partial decode and incomplete decode
1259
partial_decode_prepare(ber_bin_v2,M,TsAndVs,Options) when tuple(TsAndVs) ->
1260
%% read configure file
1261
% Types = element(1,TsAndVs),
1262
CfgList = read_config_file(M#module.name),
1263
SelectedDecode = get_config_info(CfgList,partial_decode),
1264
ExclusiveDecode = get_config_info(CfgList,exclusive_decode),
1266
create_partial_decode_gen_info(M#module.name,SelectedDecode),
1267
% io:format("partial_decode = ~p~n",[CommandList]),
1269
save_config(partial_decode,CommandList),
1271
create_partial_inc_decode_gen_info(M#module.name,ExclusiveDecode),
1272
% io:format("partial_incomplete_decode = ~p~n",[CommandList2]),
1273
Part_inc_tlv_tags = tag_format(ber_bin_v2,Options,CommandList2),
1274
% io:format("partial_incomplete_decode: tlv_tags = ~p~n",[Part_inc_tlv_tags]),
1275
save_config(partial_incomplete_decode,Part_inc_tlv_tags),
1276
save_gen_state(ExclusiveDecode,Part_inc_tlv_tags);
1277
partial_decode_prepare(_,_,_,_) ->
1282
%% create_partial_inc_decode_gen_info/2
1284
%% Creats a list of tags out of the information in TypeNameList that
1285
%% tells which value will be incomplete decoded, i.e. each end
1286
%% component/type in TypeNameList. The significant types/components in
1287
%% the path from the toptype must be specified in the
1288
%% TypeNameList. Significant elements are all constructed types that
1289
%% branches the path to the leaf and the leaf it selfs.
1291
%% Returns a list of elements, where an element may be one of
1292
%% mandatory|[opt,Tag]|[bin,Tag]. mandatory correspond to a mandatory
1293
%% element that shall be decoded as usual. [opt,Tag] matches an
1294
%% OPTIONAL or DEFAULT element that shall be decoded as
1295
%% usual. [bin,Tag] corresponds to an element, mandatory, OPTIONAL or
1296
%% DEFAULT, that shall be left encoded (incomplete decoded).
1297
create_partial_inc_decode_gen_info(ModName,{Mod,[{Name,L}|Ls]}) when list(L) ->
1298
TopTypeName = partial_inc_dec_toptype(L),
1300
create_partial_inc_decode_gen_info1(ModName,TopTypeName,{Mod,L})}|
1301
create_partial_inc_decode_gen_info(ModName,{Mod,Ls})];
1302
create_partial_inc_decode_gen_info(_,{_,[]}) ->
1304
create_partial_inc_decode_gen_info(_,[]) ->
1307
create_partial_inc_decode_gen_info1(ModName,TopTypeName,{ModName,
1308
[_TopType|Rest]}) ->
1309
case asn1_db:dbget(ModName,TopTypeName) of
1310
#typedef{typespec=TS} ->
1311
TagCommand = get_tag_command(TS,?MANDATORY,mandatory),
1312
create_pdec_inc_command(ModName,get_components(TS#type.def),
1315
throw({error,{"wrong type list in asn1 config file",
1318
create_partial_inc_decode_gen_info1(M1,_,{M2,_}) when M1 /= M2 ->
1319
throw({error,{"wrong module name in asn1 config file",
1321
create_partial_inc_decode_gen_info1(_,_,TNL) ->
1322
throw({error,{"wrong type list in asn1 config file",
1326
%% Only when there is a 'ComponentType' the config data C1 may be a
1327
%% list, where the incomplete decode is branched. So, C1 may be a
1328
%% list, a "binary tuple", a "parts tuple" or an atom. The second
1329
%% element of a binary tuple and a parts tuple is an atom.
1330
create_pdec_inc_command(_ModName,_,[],Acc) ->
1332
create_pdec_inc_command(ModName,{Comps1,Comps2},TNL,Acc)
1333
when list(Comps1),list(Comps2) ->
1334
create_pdec_inc_command(ModName,Comps1 ++ Comps2,TNL,Acc);
1335
create_pdec_inc_command(ModN,Clist,[CL|_Rest],Acc) when list(CL) ->
1336
create_pdec_inc_command(ModN,Clist,CL,Acc);
1337
create_pdec_inc_command(ModName,
1338
CList=[#'ComponentType'{name=Name,typespec=TS,
1343
% %% In this case C1 is an atom
1344
% TagCommand = get_tag_command(TS,?MANDATORY,Prop),
1345
% create_pdec_inc_command(ModName,get_components(TS#type.def),Cs,[TagCommand|Acc]);
1347
TagCommand = get_tag_command(TS,?UNDECODED,Prop),
1348
create_pdec_inc_command(ModName,Comps,Cs,[TagCommand|Acc]);
1350
TagCommand = get_tag_command(TS,?PARTS,Prop),
1351
create_pdec_inc_command(ModName,Comps,Cs,[TagCommand|Acc]);
1353
%% This case is only possible as the first element after
1354
%% the top type element, when top type is SEGUENCE or SET.
1355
%% Follow each element in L. Must note every tag on the
1356
%% way until the last command is reached, but it ought to
1357
%% be enough to have a "complete" or "complete optional"
1358
%% command for each component that is not specified in the
1359
%% config file. Then in the TLV decode the components with
1360
%% a "complete" command will be decoded by an ordinary TLV
1362
create_pdec_inc_command(ModName,CList,L,Acc);
1363
{Name,RestPartsList} when list(RestPartsList) ->
1364
%% Same as previous, but this may occur at any place in
1365
%% the structure. The previous is only possible as the
1367
case get_tag_command(TS,?MANDATORY,Prop) of
1370
create_pdec_inc_command(ModName,TS#type.def,
1372
create_pdec_inc_command(ModName,Comps,Cs,
1373
[[?MANDATORY,InnerDirectives]|Acc]);
1374
% create_pdec_inc_command(ModName,Comps,Cs,
1375
% [InnerDirectives,?MANDATORY|Acc]);
1378
create_pdec_inc_command(ModName,TS#type.def,
1380
create_pdec_inc_command(ModName,Comps,Cs,
1381
[[Opt,EncTag,InnerDirectives]|Acc])
1383
% create_pdec_inc_command(ModName,CList,RestPartsList,Acc);
1384
%% create_pdec_inc_command(ModName,TS#type.def,RestPartsList,Acc);
1385
_ -> %% this component may not be in the config list
1386
TagCommand = get_tag_command(TS,?MANDATORY,Prop),
1387
create_pdec_inc_command(ModName,Comps,TNL,[TagCommand|Acc])
1389
create_pdec_inc_command(ModName,
1390
{'CHOICE',[#'ComponentType'{name=C1,
1393
[{C1,Directive}|Rest],Acc) ->
1395
List when list(List) ->
1396
[Command,Tag] = get_tag_command(TS,?ALTERNATIVE,Prop),
1397
CompAcc = create_pdec_inc_command(ModName,TS#type.def,List,[]),
1398
create_pdec_inc_command(ModName,{'CHOICE',Comps},Rest,
1399
[[Command,Tag,CompAcc]|Acc]);
1401
TagCommand = get_tag_command(TS,?ALTERNATIVE_UNDECODED,Prop),
1402
create_pdec_inc_command(ModName,{'CHOICE',Comps},Rest,
1405
TagCommand = get_tag_command(TS,?ALTERNATIVE_PARTS,Prop),
1406
create_pdec_inc_command(ModName,{'CHOICE',Comps},Rest,
1409
create_pdec_inc_command(ModName,
1410
{'CHOICE',[#'ComponentType'{typespec=TS,
1413
TagCommand = get_tag_command(TS,?ALTERNATIVE,Prop),
1414
create_pdec_inc_command(ModName,{'CHOICE',Comps},TNL,[TagCommand|Acc]);
1415
create_pdec_inc_command(M,{'CHOICE',{Cs1,Cs2}},TNL,Acc)
1416
when list(Cs1),list(Cs2) ->
1417
create_pdec_inc_command(M,{'CHOICE',Cs1 ++ Cs2},TNL,Acc);
1418
create_pdec_inc_command(ModName,#'Externaltypereference'{module=M,type=Name},
1420
#type{def=Def} = get_referenced_type(M,Name),
1421
create_pdec_inc_command(ModName,get_components(Def),TNL,Acc);
1422
create_pdec_inc_command(_,_,TNL,_) ->
1423
throw({error,{"unexpected error when creating partial "
1424
"decode command",TNL}}).
1426
partial_inc_dec_toptype([T|_]) when atom(T) ->
1428
partial_inc_dec_toptype([{T,_}|_]) when atom(T) ->
1430
partial_inc_dec_toptype([L|_]) when list(L) ->
1431
partial_inc_dec_toptype(L);
1432
partial_inc_dec_toptype(_) ->
1433
throw({error,{"no top type found for partial incomplete decode"}}).
1436
%% Creats a list of tags out of the information in TypeList and Types
1437
%% that tells which value will be decoded. Each constructed type that
1438
%% is in the TypeList will get a "choosen" command. Only the last
1439
%% type/component in the TypeList may be a primitive type. Components
1440
%% "on the way" to the final element may get the "skip" or the
1441
%% "skip_optional" command.
1442
%% CommandList = [Elements]
1443
%% Elements = {choosen,Tag}|{skip_optional,Tag}|skip
1444
%% Tag is a binary with the tag BER encoded.
1445
create_partial_decode_gen_info(ModName,{{_,ModName},TypeList}) ->
1448
case asn1_db:dbget(ModName,TopType) of
1449
#typedef{typespec=TS} ->
1450
TagCommand = get_tag_command(TS,?CHOOSEN),
1451
create_pdec_command(ModName,get_components(TS#type.def),
1454
throw({error,{"wrong type list in asn1 config file",
1460
create_partial_decode_gen_info(_,[]) ->
1462
create_partial_decode_gen_info(_M1,{{_,M2},_}) ->
1463
throw({error,{"wrong module name in asn1 config file",
1466
%% create_pdec_command/4 for each name (type or component) in the
1467
%% third argument, TypeNameList, a command is created. The command has
1468
%% information whether the component/type shall be skipped, looked
1469
%% into or returned. The list of commands is returned.
1470
create_pdec_command(_ModName,_,[],Acc) ->
1472
create_pdec_command(ModName,[#'ComponentType'{name=C1,typespec=TS}|_Comps],
1474
%% this component is a constructed type or the last in the
1475
%% TypeNameList otherwise the config spec is wrong
1476
TagCommand = get_tag_command(TS,?CHOOSEN),
1477
create_pdec_command(ModName,get_components(TS#type.def),
1478
Cs,[TagCommand|Acc]);
1479
create_pdec_command(ModName,[#'ComponentType'{typespec=TS,
1485
get_tag_command(TS,?SKIP);
1487
get_tag_command(TS,?SKIP_OPTIONAL)
1489
create_pdec_command(ModName,Comps,[C2|Cs],[TagCommand|Acc]);
1490
create_pdec_command(ModName,{'CHOICE',[Comp=#'ComponentType'{name=C1}|_]},TNL=[C1|_Cs],Acc) ->
1491
create_pdec_command(ModName,[Comp],TNL,Acc);
1492
create_pdec_command(ModName,{'CHOICE',[#'ComponentType'{}|Comps]},TNL,Acc) ->
1493
create_pdec_command(ModName,{'CHOICE',Comps},TNL,Acc);
1494
create_pdec_command(ModName,#'Externaltypereference'{module=M,type=C1},
1495
TypeNameList,Acc) ->
1496
case get_referenced_type(M,C1) of
1498
create_pdec_command(ModName,get_components(Def),TypeNameList,
1501
throw({error,{"unexpected result when fetching "
1502
"referenced element",Err}})
1504
create_pdec_command(ModName,TS=#type{def=Def},[C1|Cs],Acc) ->
1505
%% This case when we got the "components" of a SEQUENCE/SET OF
1508
%% A list with an integer is the only valid option in a 'S
1509
%% OF', the other valid option would be an empty
1510
%% TypeNameList saying that the entire 'S OF' will be
1512
TagCommand = get_tag_command(TS,?CHOOSEN),
1513
create_pdec_command(ModName,Def,Cs,[TagCommand|Acc]);
1514
[N] when integer(N) ->
1515
TagCommand = get_tag_command(TS,?SKIP),
1516
create_pdec_command(ModName,Def,[[N-1]|Cs],[TagCommand|Acc]);
1518
throw({error,{"unexpected error when creating partial "
1519
"decode command",Err}})
1521
create_pdec_command(_,_,TNL,_) ->
1522
throw({error,{"unexpected error when creating partial "
1523
"decode command",TNL}}).
1525
% get_components({'CHOICE',Components}) ->
1527
get_components(#'SEQUENCE'{components=Components}) ->
1529
get_components(#'SET'{components=Components}) ->
1531
get_components({'SEQUENCE OF',Components}) ->
1533
get_components({'SET OF',Components}) ->
1535
get_components(Def) ->
1538
%% get_tag_command(Type,Command)
1540
%% Type is the type that has information about the tag Command tells
1541
%% what to do with the encoded value with the tag of Type when
1543
get_tag_command(#type{tag=[]},_) ->
1545
get_tag_command(#type{tag=[_Tag]},?SKIP) ->
1547
get_tag_command(#type{tag=[Tag]},Command) ->
1548
%% encode the tag according to BER
1549
[Command,encode_tag_val(decode_class(Tag#tag.class),Tag#tag.form,
1551
get_tag_command(T=#type{tag=[Tag|Tags]},Command) ->
1552
[get_tag_command(T#type{tag=Tag},Command)|
1553
get_tag_command(T#type{tag=Tags},Command)].
1555
%% get_tag_command/3 used by create_pdec_inc_command
1556
get_tag_command(#type{tag=[]},_,_) ->
1558
get_tag_command(#type{tag=[Tag]},?MANDATORY,Prop) ->
1563
[?DEFAULT,encode_tag_val(decode_class(Tag#tag.class),
1564
Tag#tag.form,Tag#tag.number)];
1565
_ -> [?OPTIONAL,encode_tag_val(decode_class(Tag#tag.class),
1566
Tag#tag.form,Tag#tag.number)]
1568
get_tag_command(#type{tag=[Tag]},Command,_) ->
1569
[Command,encode_tag_val(decode_class(Tag#tag.class),Tag#tag.form,
1573
get_referenced_type(M,Name) ->
1574
case asn1_db:dbget(M,Name) of
1575
#typedef{typespec=TS} ->
1577
#type{def=#'Externaltypereference'{module=M2,type=Name2}} ->
1578
%% The tags have already been taken care of in the
1579
%% first reference where they were gathered in a
1581
get_referenced_type(M2,Name2);
1584
throw({error,{"unexpected element when"
1585
" fetching referenced type",TS}})
1588
throw({error,{"unexpected element when fetching "
1589
"referenced type",T}})
1592
tag_format(EncRule,_Options,CommandList) ->
1595
tlv_tags(CommandList);
1602
tlv_tags([mandatory|Rest]) ->
1603
[mandatory|tlv_tags(Rest)];
1604
tlv_tags([[Command,Tag]|Rest]) when atom(Command),binary(Tag) ->
1605
[[Command,tlv_tag(Tag)]|tlv_tags(Rest)];
1606
tlv_tags([[Command,Directives]|Rest]) when atom(Command),list(Directives) ->
1607
[[Command,tlv_tags(Directives)]|tlv_tags(Rest)];
1608
%% remove all empty lists
1609
tlv_tags([[]|Rest]) ->
1611
tlv_tags([{Name,TopType,L1}|Rest]) when list(L1),atom(TopType) ->
1612
[{Name,TopType,tlv_tags(L1)}|tlv_tags(Rest)];
1613
tlv_tags([[Command,Tag,L1]|Rest]) when list(L1),binary(Tag) ->
1614
[[Command,tlv_tag(Tag),tlv_tags(L1)]|tlv_tags(Rest)];
1615
tlv_tags([L=[L1|_]|Rest]) when list(L1) ->
1616
[tlv_tags(L)|tlv_tags(Rest)].
1618
tlv_tag(<<Cl:2,_:1,TagNo:5>>) when TagNo < 31 ->
1619
(Cl bsl 16) + TagNo;
1620
tlv_tag(<<Cl:2,_:1,31:5,0:1,TagNo:7>>) ->
1621
(Cl bsl 16) + TagNo;
1622
tlv_tag(<<Cl:2,_:1,31:5,Buffer/binary>>) ->
1623
TagNo = tlv_tag1(Buffer,0),
1624
(Cl bsl 16) + TagNo.
1625
tlv_tag1(<<0:1,PartialTag:7>>,Acc) ->
1626
(Acc bsl 7) bor PartialTag;
1627
tlv_tag1(<<1:1,PartialTag:7,Buffer/binary>>,Acc) ->
1628
tlv_tag1(Buffer,(Acc bsl 7) bor PartialTag).
1630
%% reads the content from the configuration file and returns the
1631
%% selected part choosen by InfoType. Assumes that the config file
1632
%% content is an Erlang term.
1633
read_config_file(ModuleName,InfoType) when atom(InfoType) ->
1634
CfgList = read_config_file(ModuleName),
1635
get_config_info(CfgList,InfoType).
1638
read_config_file(ModuleName) ->
1639
case file:consult(lists:concat([ModuleName,'.asn1config'])) of
1640
% case file:consult(ModuleName) of
1644
Options = get(encoding_options),
1645
Includes = [I || {i,I} <- Options],
1646
read_config_file1(ModuleName,Includes);
1648
file:format_error(Reason),
1649
throw({error,{"error reading asn1 config file",Reason}})
1651
read_config_file1(ModuleName,[]) ->
1652
case filename:extension(ModuleName) of
1654
throw({error,enoent});
1656
read_config_file(lists:concat([ModuleName,".asn1config"]))
1658
read_config_file1(ModuleName,[H|T]) ->
1659
% File = filename:join([H,lists:concat([ModuleName,'.asn1config'])]),
1660
File = filename:join([H,ModuleName]),
1661
case file:consult(File) of
1665
read_config_file1(ModuleName,T);
1667
file:format_error(Reason),
1668
throw({error,{"error reading asn1 config file",Reason}})
1671
get_config_info(CfgList,InfoType) ->
1676
case lists:keysearch(InfoType,1,CfgList) of
1677
{value,{InfoType,Value}} ->
1684
%% save_config/2 saves the Info with the key Key
1685
%% Before saving anything check if a table exists
1686
save_config(Key,Info) ->
1687
create_if_no_table(asn1_general,[named_table]),
1688
ets:insert(asn1_general,{{asn1_config,Key},Info}).
1690
read_config_data(Key) ->
1691
case ets:info(asn1_general) of
1692
undefined -> undefined;
1694
case ets:lookup(asn1_general,{asn1_config,Key}) of
1697
io:format("strange data from config file ~w~n",[Err]),
1704
%% Functions to manipulate the gen_state record saved in the
1705
%% asn1_general ets table.
1708
%% saves input data in a new gen_state record
1709
save_gen_state({_,ConfList},PartIncTlvTagList) ->
1710
%ConfList=[{FunctionName,PatternList}|Rest]
1711
StateRec = #gen_state{inc_tag_pattern=PartIncTlvTagList,
1712
inc_type_pattern=ConfList},
1713
save_config(gen_state,StateRec);
1714
save_gen_state(_,_) ->
1716
save_config(gen_state,#gen_state{}).
1718
save_gen_state(GenState) when record(GenState,gen_state) ->
1719
save_config(gen_state,GenState).
1722
%% get_gen_state_field returns undefined if no gen_state exists or if
1723
%% Field is undefined or the data at the field.
1724
get_gen_state_field(Field) ->
1725
case read_config_data(gen_state) of
1729
get_gen_state_field(GenState,Field)
1731
get_gen_state_field(#gen_state{active=Active},active) ->
1733
get_gen_state_field(_,active) ->
1735
get_gen_state_field(GS,prefix) ->
1736
GS#gen_state.prefix;
1737
get_gen_state_field(GS,inc_tag_pattern) ->
1738
GS#gen_state.inc_tag_pattern;
1739
get_gen_state_field(GS,tag_pattern) ->
1740
GS#gen_state.tag_pattern;
1741
get_gen_state_field(GS,inc_type_pattern) ->
1742
GS#gen_state.inc_type_pattern;
1743
get_gen_state_field(GS,type_pattern) ->
1744
GS#gen_state.type_pattern;
1745
get_gen_state_field(GS,func_name) ->
1746
GS#gen_state.func_name;
1747
get_gen_state_field(GS,namelist) ->
1748
GS#gen_state.namelist;
1749
get_gen_state_field(GS,tobe_refed_funcs) ->
1750
GS#gen_state.tobe_refed_funcs;
1751
get_gen_state_field(GS,gen_refed_funcs) ->
1752
GS#gen_state.gen_refed_funcs.
1756
read_config_data(gen_state).
1759
update_gen_state(Field,Data) ->
1760
case get_gen_state() of
1761
State when record(State,gen_state) ->
1762
update_gen_state(Field,State,Data);
1764
exit({error,{asn1,{internal,
1765
"tried to update nonexistent gen_state",Field,Data}}})
1767
update_gen_state(active,State,Data) ->
1768
save_gen_state(State#gen_state{active=Data});
1769
update_gen_state(prefix,State,Data) ->
1770
save_gen_state(State#gen_state{prefix=Data});
1771
update_gen_state(inc_tag_pattern,State,Data) ->
1772
save_gen_state(State#gen_state{inc_tag_pattern=Data});
1773
update_gen_state(tag_pattern,State,Data) ->
1774
save_gen_state(State#gen_state{tag_pattern=Data});
1775
update_gen_state(inc_type_pattern,State,Data) ->
1776
save_gen_state(State#gen_state{inc_type_pattern=Data});
1777
update_gen_state(type_pattern,State,Data) ->
1778
save_gen_state(State#gen_state{type_pattern=Data});
1779
update_gen_state(func_name,State,Data) ->
1780
save_gen_state(State#gen_state{func_name=Data});
1781
update_gen_state(namelist,State,Data) ->
1784
% [D] when list(D) -> D;
1787
save_gen_state(State#gen_state{namelist=Data});
1788
update_gen_state(tobe_refed_funcs,State,Data) ->
1789
save_gen_state(State#gen_state{tobe_refed_funcs=Data});
1790
update_gen_state(gen_refed_funcs,State,Data) ->
1791
save_gen_state(State#gen_state{gen_refed_funcs=Data}).
1793
update_namelist(Name) ->
1794
case get_gen_state_field(namelist) of
1795
[Name,Rest] -> update_gen_state(namelist,Rest);
1796
[Name|Rest] -> update_gen_state(namelist,Rest);
1797
[{Name,List}] when list(List) -> update_gen_state(namelist,List);
1798
[{Name,Atom}|Rest] when atom(Atom) -> update_gen_state(namelist,Rest);
1803
DeepTail = %% removes next element in order
1804
fun([[{_,A}]|T],_Fun) when atom(A) -> T;
1805
([{_N,L}|T],_Fun) when list(L) -> [L|T];
1806
([[]|T],Fun) -> Fun(T,Fun);
1807
([L1|L2],Fun) when list(L1) ->
1808
case lists:flatten(L1) of
1809
[] -> Fun([L2],Fun);
1810
_ -> [Fun(L1,Fun)|L2]
1815
case get_gen_state_field(namelist) of
1818
{next_namelist_el(L),
1819
DeepTail(L,DeepTail)}
1821
update_gen_state(namelist,NewNL),
1824
%% next_namelist_el fetches the next type/component name in turn in
1825
%% the namelist, without changing the namelist.
1826
next_namelist_el() ->
1827
case get_gen_state_field(namelist) of
1828
undefined -> undefined;
1829
L when list(L) -> next_namelist_el(L)
1832
next_namelist_el([]) ->
1834
next_namelist_el([L]) when list(L) ->
1835
next_namelist_el(L);
1836
next_namelist_el([H|_]) when atom(H) ->
1838
next_namelist_el([L|T]) when list(L) ->
1839
case next_namelist_el(L) of
1841
next_namelist_el([T]);
1845
next_namelist_el([H={_,A}|_]) when atom(A) ->
1848
%% removes a bracket from the namelist
1849
step_in_constructed() ->
1850
case get_gen_state_field(namelist) of
1852
update_gen_state(namelist,L);
1856
is_function_generated(Name) ->
1857
case get_gen_state_field(gen_refed_funcs) of
1859
lists:member(Name,L);
1864
get_tobe_refed_func(Name) ->
1865
case get_gen_state_field(tobe_refed_funcs) of
1867
case lists:keysearch(Name,1,L) of
1877
add_tobe_refed_func(Data) ->
1878
L = get_gen_state_field(tobe_refed_funcs),
1879
update_gen_state(tobe_refed_funcs,[Data|L]).
1881
%% moves Name from the to be list to the generated list.
1882
generated_refed_func(Name) ->
1883
L = get_gen_state_field(tobe_refed_funcs),
1884
NewL = lists:keydelete(Name,1,L),
1885
update_gen_state(tobe_refed_funcs,NewL),
1886
L2 = get_gen_state_field(gen_refed_funcs),
1887
update_gen_state(gen_refed_funcs,[Name|L2]).
1889
add_generated_refed_func(Data) ->
1890
L = get_gen_state_field(gen_refed_funcs),
1891
update_gen_state(gen_refed_funcs,[Data|L]).
1894
next_refed_func() ->
1895
case get_gen_state_field(tobe_refed_funcs) of
1899
update_gen_state(tobe_refed_funcs,T),
1903
reset_gen_state() ->
1904
save_gen_state(#gen_state{}).