aboutsummaryrefslogtreecommitdiffstats
path: root/lib/asn1/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/asn1/src')
-rw-r--r--lib/asn1/src/Makefile1
-rw-r--r--lib/asn1/src/asn1.app.src3
-rw-r--r--lib/asn1/src/asn1_records.hrl12
-rw-r--r--lib/asn1/src/asn1ct.erl21
-rw-r--r--lib/asn1/src/asn1ct_check.erl613
-rw-r--r--lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl58
-rw-r--r--lib/asn1/src/asn1ct_constructed_per.erl3
-rw-r--r--lib/asn1/src/asn1ct_func.erl12
-rw-r--r--lib/asn1/src/asn1ct_gen.erl373
-rw-r--r--lib/asn1/src/asn1ct_gen_ber_bin_v2.erl338
-rw-r--r--lib/asn1/src/asn1ct_gen_check.erl271
-rw-r--r--lib/asn1/src/asn1ct_gen_per.erl10
-rw-r--r--lib/asn1/src/asn1ct_imm.erl78
-rw-r--r--lib/asn1/src/asn1ct_parser2.erl23
-rw-r--r--lib/asn1/src/asn1ct_tok.erl2
-rw-r--r--lib/asn1/src/asn1rtt_ber.erl221
-rw-r--r--lib/asn1/src/asn1rtt_check.erl300
-rw-r--r--lib/asn1/src/asn1rtt_per_common.erl13
18 files changed, 1105 insertions, 1247 deletions
diff --git a/lib/asn1/src/Makefile b/lib/asn1/src/Makefile
index 500f4a1358..6798da0072 100644
--- a/lib/asn1/src/Makefile
+++ b/lib/asn1/src/Makefile
@@ -52,6 +52,7 @@ CT_MODULES= \
asn1ct_pretty_format \
asn1ct_func \
asn1ct_gen \
+ asn1ct_gen_check \
asn1ct_gen_per \
asn1ct_name \
asn1ct_constructed_per \
diff --git a/lib/asn1/src/asn1.app.src b/lib/asn1/src/asn1.app.src
index f2ee8deb75..02cbba0f10 100644
--- a/lib/asn1/src/asn1.app.src
+++ b/lib/asn1/src/asn1.app.src
@@ -10,5 +10,6 @@
asn1db
]},
{env, []},
- {applications, [kernel, stdlib]}
+ {applications, [kernel, stdlib]},
+ {runtime_dependencies, ["stdlib-2.0","kernel-3.0","erts-6.0"]}
]}.
diff --git a/lib/asn1/src/asn1_records.hrl b/lib/asn1/src/asn1_records.hrl
index 396ba0fcfa..6c1cf1b12a 100644
--- a/lib/asn1/src/asn1_records.hrl
+++ b/lib/asn1/src/asn1_records.hrl
@@ -37,7 +37,7 @@
-record('ObjectClassFieldType',{classname,class,fieldname,type}).
-record(typedef,{checked=false,pos,name,typespec}).
--record(classdef,{checked=false,pos,name,typespec}).
+-record(classdef, {checked=false,pos,name,module,typespec}).
-record(valuedef,{checked=false,pos,name,type,value,module}).
-record(ptypedef,{checked=false,pos,name,args,typespec}).
-record(pvaluedef,{checked=false,pos,name,args,type,value}).
@@ -45,7 +45,6 @@
-record(pobjectdef,{checked=false,pos,name,args,class,def}).
-record(pobjectsetdef,{checked=false,pos,name,args,class,def}).
--record(identifier,{pos,val}).
-record('Constraint',{'SingleValue'=no,'SizeConstraint'=no,'ValueRange'=no,'PermittedAlphabet'=no,
'ContainedSubtype'=no, 'TypeConstraint'=no,'InnerSubtyping'=no,e=no,'Other'=no}).
-record(simpletableattributes,{objectsetname,c_name,c_index,usedclassfield,
@@ -73,6 +72,15 @@
% Externalvaluereference -> modulename '.' typename
-record('Externalvaluereference',{pos,module,value}).
+%% Used to hold a tag for a field in a SEQUENCE/SET. It can also
+%% be used for identifiers in OBJECT IDENTIFIER values, since the
+%% parser cannot always distinguish a SEQUENCE with one element from
+%% an OBJECT IDENTIFIER.
+-record(seqtag,
+ {pos :: integer(),
+ module :: atom(),
+ val :: atom()}).
+
-record(state,{module,mname,type,tname,value,vname,erule,parameters=[],
inputmodules,abscomppath=[],recordtopname=[],options,
sourcedir}).
diff --git a/lib/asn1/src/asn1ct.erl b/lib/asn1/src/asn1ct.erl
index 9ec43197bf..df341e5aab 100644
--- a/lib/asn1/src/asn1ct.erl
+++ b/lib/asn1/src/asn1ct.erl
@@ -43,7 +43,7 @@
add_tobe_refed_func/1,add_generated_refed_func/1,
maybe_rename_function/3,current_sindex/0,
set_current_sindex/1,maybe_saved_sindex/2,
- parse_and_save/2,verbose/3,warning/3,warning/4,error/3]).
+ parse_and_save/2,verbose/3,warning/3,warning/4,error/3,format_error/1]).
-export([get_bit_string_format/0,use_legacy_types/0]).
-include("asn1_records.hrl").
@@ -143,7 +143,8 @@ parse_and_save_passes() ->
{pass,save,fun save_pass/1}].
common_passes() ->
- [{pass,check,fun check_pass/1},
+ [{iff,parse,{pass,parse_listing,fun parse_listing/1}},
+ {pass,check,fun check_pass/1},
{iff,abs,{pass,abs_listing,fun abs_listing/1}},
{pass,generate,fun generate_pass/1},
{unless,noobj,{pass,compile,fun compile_pass/1}}].
@@ -243,6 +244,16 @@ save_pass(#st{code=M,erule=Erule,dbfile=DbFile}=St) ->
asn1_db:dbsave(DbFile,M#module.name),
{ok,St}.
+parse_listing(#st{code=Code,outfile=OutFile0}=St) ->
+ OutFile = OutFile0 ++ ".parse",
+ case file:write_file(OutFile, io_lib:format("~p\n", [Code])) of
+ ok ->
+ done;
+ {error,Reason} ->
+ Error = {write_error,OutFile,Reason},
+ {error,St#st{error=[{structured_error,{OutFile0,none},?MODULE,Error}]}}
+ end.
+
abs_listing(#st{code={M,_},outfile=OutFile}) ->
pretty2(M#module.name, OutFile++".abs"),
done.
@@ -566,6 +577,8 @@ get_pos_of_def(#pobjectdef{pos=Pos}) ->
Pos;
get_pos_of_def(#pobjectsetdef{pos=Pos}) ->
Pos;
+get_pos_of_def(#'Externaltypereference'{pos=Pos}) ->
+ Pos;
get_pos_of_def(#'Externalvaluereference'{pos=Pos}) ->
Pos;
get_pos_of_def(_) ->
@@ -2428,6 +2441,10 @@ verbose(Format, Args, S) ->
ok
end.
+format_error({write_error,File,Reason}) ->
+ io_lib:format("writing output file ~s failed: ~s",
+ [File,file:format_error(Reason)]).
+
is_error(S) when is_record(S, state) ->
is_error(S#state.options);
is_error(O) ->
diff --git a/lib/asn1/src/asn1ct_check.erl b/lib/asn1/src/asn1ct_check.erl
index b9f2cb876a..240f1cbb16 100644
--- a/lib/asn1/src/asn1ct_check.erl
+++ b/lib/asn1/src/asn1ct_check.erl
@@ -91,7 +91,7 @@ check(S,{Types,Values,ParameterizedTypes,Classes,Objects,ObjectSets}) ->
save_asn1db_uptodate(S,S#state.erule,S#state.mname),
put(top_module,S#state.mname),
- _ = checkp(S, ParameterizedTypes), %must do this before the templates are used
+ ParamError = checkp(S, ParameterizedTypes), %must do this before the templates are used
%% table to save instances of parameterized objects,object sets
asn1ct_table:new(parameterized_objects),
@@ -160,8 +160,10 @@ check(S,{Types,Values,ParameterizedTypes,Classes,Objects,ObjectSets}) ->
Exporterror = check_exports(S,S#state.module),
ImportError = check_imports(S,S#state.module),
- case {Terror3,Verror5,Cerror,Oerror,Exporterror,ImportError} of
- {[],[],[],[],[],[]} ->
+ AllErrors = lists:flatten([ParamError,Terror3,Verror5,Cerror,
+ Oerror,Exporterror,ImportError]),
+ case AllErrors of
+ [] ->
ContextSwitchTs = context_switch_in_spec(),
InstanceOf = instance_of_in_spec(S#state.mname),
NewTypes = lists:subtract(Types,AddClasses) ++ ContextSwitchTs
@@ -175,8 +177,7 @@ check(S,{Types,Values,ParameterizedTypes,Classes,Objects,ObjectSets}) ->
lists:subtract(NewObjects,ExclO)++InlinedObjects,
lists:subtract(NewObjectSets,ExclOS)++ParObjectSetNames}};
_ ->
- {error,lists:flatten([Terror3,Verror5,Cerror,
- Oerror,Exporterror,ImportError])}
+ {error,AllErrors}
end.
context_switch_in_spec() ->
@@ -270,46 +271,30 @@ check_exports(S,Module = #module{}) ->
end
end.
-check_imports(S,Module = #module{ }) ->
- case Module#module.imports of
- {imports,[]} ->
- [];
- {imports,ImportList} when is_list(ImportList) ->
- check_imports2(S,ImportList,[]);
- _ ->
- []
- end.
-check_imports2(_S,[],Acc) ->
+check_imports(S, #module{imports={imports,Imports}}) ->
+ check_imports_1(S, Imports, []).
+
+check_imports_1(_S, [], Acc) ->
Acc;
-check_imports2(S,[#'SymbolsFromModule'{symbols=Imports,module=ModuleRef}|SFMs],Acc) ->
- NameOfDef =
- fun(#'Externaltypereference'{type=N}) -> N;
- (#'Externalvaluereference'{value=N}) -> N
- end,
- Module = NameOfDef(ModuleRef),
- Refs = [{M,R}||{{M,_},R} <- [{catch get_referenced_type(S,Ref),Ref}||Ref <- Imports]],
- {Illegal,Other} = lists:splitwith(fun({error,_}) -> true;(_) -> false end,
- Refs),
- ChainedRefs = [R||{M,R} <- Other, M =/= Module],
- IllegalRefs = [R||{error,R} <- Illegal] ++
- [R||{M,R} <- ChainedRefs,
- ok =/= chained_import(S,Module,M,NameOfDef(R))],
- ReportError =
- fun(Ref) ->
- NewS=S#state{type=Ref,tname=NameOfDef(Ref)},
- error({import,"imported undefined entity",NewS})
- end,
- check_imports2(S,SFMs,[ReportError(Err)||Err <- IllegalRefs]++Acc).
+check_imports_1(S, [#'SymbolsFromModule'{symbols=Imports,module=ModuleRef}|SFMs], Acc0) ->
+ Module = name_of_def(ModuleRef),
+ Refs0 = [{catch get_referenced_type(S, Ref),Ref} || Ref <- Imports],
+ Refs = [{M,R} || {{M,_},R} <- Refs0],
+ {Illegal,Other} = lists:splitwith(fun({error,_}) -> true;
+ (_) -> false
+ end, Refs),
+ ChainedRefs = [R || {M,R} <- Other, M =/= Module],
+ IllegalRefs = [R || {error,R} <- Illegal] ++
+ [R || {M,R} <- ChainedRefs,
+ ok =/= chained_import(S, Module, M, name_of_def(R))],
+ Acc = [return_asn1_error(S, Ref, {undefined_import,name_of_def(Ref),Module}) ||
+ Ref <- IllegalRefs] ++ Acc0,
+ check_imports_1(S, SFMs, Acc).
chained_import(S,ImpMod,DefMod,Name) ->
%% Name is a referenced structure that is not defined in ImpMod,
%% but must be present in the Imports list of ImpMod. The chain of
%% imports of Name must end in DefMod.
- NameOfDef =
- fun(#'Externaltypereference'{type=N}) -> N;
- (#'Externalvaluereference'{value=N}) -> N;
- (Other) -> Other
- end,
GetImports =
fun(_M_) ->
case asn1_db:dbget(_M_,'MODULE') of
@@ -321,9 +306,9 @@ chained_import(S,ImpMod,DefMod,Name) ->
FindNameInImports =
fun([],N,_) -> {no_mod,N};
([#'SymbolsFromModule'{symbols=Imports,module=ModuleRef}|SFMs],N,F) ->
- case [NameOfDef(X)||X <- Imports, NameOfDef(X) =:= N] of
+ case [name_of_def(X) || X <- Imports, name_of_def(X) =:= N] of
[] -> F(SFMs,N,F);
- [N] -> {NameOfDef(ModuleRef),N}
+ [N] -> {name_of_def(ModuleRef),N}
end
end,
case GetImports(ImpMod) of
@@ -565,14 +550,10 @@ check_class(S = #state{mname=M,tname=T},ClassSpec)
#objectclass{fields=Def}; % in case of recursive definitions
Tref = #'Externaltypereference'{type=TName} ->
{MName,RefType} = get_referenced_type(S,Tref),
- case is_class(S,RefType) of
- true ->
- NewState = update_state(S#state{type=RefType,
- tname=TName},MName),
- check_class(NewState,get_class_def(S,RefType));
- _ ->
- error({class,{internal_error,RefType},S})
- end;
+ #classdef{} = CD = get_class_def(S, RefType),
+ NewState = update_state(S#state{type=RefType,
+ tname=TName}, MName),
+ check_class(NewState, CD);
{pt,ClassRef,Params} ->
%% parameterized class
{_,PClassDef} = get_referenced_type(S,ClassRef),
@@ -966,6 +947,8 @@ prepare_objset(ObjDef={object,definedsyntax,_ObjFields}) ->
{set,[ObjDef],false};
prepare_objset({ObjDef=#type{},Ext}) when is_list(Ext) ->
{set,[ObjDef|Ext],true};
+prepare_objset({#type{}=Type,#type{}=Ext}) ->
+ {set,[Type,Ext],true};
prepare_objset(Ret) ->
Ret.
@@ -1293,10 +1276,25 @@ get_fieldname_element(_S,Def,[{_RefType,_FieldName}|_RestFName])
check_fieldname_element(S,{value,{_,Def}}) ->
check_fieldname_element(S,Def);
-check_fieldname_element(S,TDef) when is_record(TDef,typedef) ->
- check_type(S,TDef,TDef#typedef.typespec);
-check_fieldname_element(S,VDef) when is_record(VDef,valuedef) ->
- check_value(S,VDef);
+check_fieldname_element(S, #typedef{typespec=Ts}=TDef) ->
+ case Ts of
+ #'Object'{} ->
+ check_object(S, TDef, Ts);
+ _ ->
+ check_type(S, TDef, Ts)
+ end;
+check_fieldname_element(S, #valuedef{}=VDef) ->
+ try
+ check_value(S, VDef)
+ catch
+ throw:{objectdef} ->
+ #valuedef{checked=C,pos=Pos,name=N,type=Type,
+ value=Def} = VDef,
+ ClassName = Type#type.def,
+ NewSpec = #'Object'{classname=ClassName,def=Def},
+ NewDef = #typedef{checked=C,pos=Pos,name=N,typespec=NewSpec},
+ check_fieldname_element(S, NewDef)
+ end;
check_fieldname_element(S,Eref)
when is_record(Eref,'Externaltypereference');
is_record(Eref,'Externalvaluereference') ->
@@ -1567,13 +1565,13 @@ check_defaultfields(S, Fields, ClassFields) ->
[] ->
ok;
[_|_]=Invalid ->
- throw(asn1_error(S, T, {invalid_fields,Invalid,Obj}))
+ asn1_error(S, T, {invalid_fields,Invalid,Obj})
end,
case ordsets:subtract(Mandatory, Present) of
[] ->
check_defaultfields_1(S, Fields, ClassFields, []);
[_|_]=Missing ->
- throw(asn1_error(S, T, {missing_mandatory_fields,Missing,Obj}))
+ asn1_error(S, T, {missing_mandatory_fields,Missing,Obj})
end.
check_defaultfields_1(_S, [], _ClassFields, Acc) ->
@@ -1819,12 +1817,10 @@ convert_to_defaultfield(S,ObjFieldName,[OFS|RestOFS],CField)->
FieldName);
ValSetting = #valuedef{} ->
ValSetting;
- ValSetting = {'CHOICE',{Alt,_ChVal}} when is_atom(Alt) ->
- #valuedef{type=element(3,CField),
- value=ValSetting,
- module=S#state.mname};
ValSetting ->
- #identifier{val=ValSetting}
+ #valuedef{type=element(3,CField),
+ value=ValSetting,
+ module=S#state.mname}
end,
?dbg("fixedtypevaluefield ValRef: ~p~n",[ValRef]),
case ValRef of
@@ -2152,11 +2148,9 @@ check_valuedef(#state{recordtopname=TopName}=S0, V0) ->
{'INTEGER',NamedNumberList} ->
ok = validate_integer(SVal, Value, NamedNumberList, Constr),
V#valuedef{value=normalize_value(SVal, Vtype, Value, [])};
- #'SEQUENCE'{components=Components} ->
- {ok,SeqVal} = validate_sequence(SVal, Value,
- Components, Constr),
- V#valuedef{value=normalize_value(SVal, Vtype,
- SeqVal, TopName)};
+ #'SEQUENCE'{} ->
+ {ok,SeqVal} = convert_external(SVal, Value),
+ V#valuedef{value=normalize_value(SVal, Vtype, SeqVal, TopName)};
{'SelectionType',SelName,SelT} ->
CheckedT = check_selectiontype(SVal, SelName, SelT),
NewV = V#valuedef{type=CheckedT},
@@ -2308,22 +2302,23 @@ validate_oid(_, S, OID, [Id|Vrest], Acc)
error({value, {"illegal "++to_string(OID),[Id,Vrest],Acc}, S})
end
end;
-validate_oid(_, S, OID, [{Atom,Value}],[])
+validate_oid(_, S, OID, [{#seqtag{module=Mod,val=Atom},Value}], [])
when is_atom(Atom),is_integer(Value) ->
%% this case when an OBJECT IDENTIFIER value has been parsed as a
%% SEQUENCE value
- Rec = #'Externalvaluereference'{module=S#state.mname,
+ Rec = #'Externalvaluereference'{module=Mod,
value=Atom},
validate_objectidentifier1(S, OID, [Rec,Value]);
-validate_oid(_, S, OID, [{Atom,EVRef}],[])
+validate_oid(_, S, OID, [{#seqtag{module=Mod,val=Atom},EVRef}], [])
when is_atom(Atom),is_record(EVRef,'Externalvaluereference') ->
%% this case when an OBJECT IDENTIFIER value has been parsed as a
%% SEQUENCE value OTP-4354
- Rec = #'Externalvaluereference'{module=EVRef#'Externalvaluereference'.module,
+ Rec = #'Externalvaluereference'{module=Mod,
value=Atom},
validate_objectidentifier1(S, OID, [Rec,EVRef]);
-validate_oid(_, S, OID, [Atom|Rest],Acc) when is_atom(Atom) ->
- Rec = #'Externalvaluereference'{module=S#state.mname,
+validate_oid(_, S, OID, [#seqtag{module=Mod,val=Atom}|Rest], Acc)
+ when is_atom(Atom) ->
+ Rec = #'Externalvaluereference'{module=Mod,
value=Atom},
validate_oid(true,S, OID, [Rec|Rest],Acc);
validate_oid(_, S, OID, V, Acc) ->
@@ -2415,13 +2410,13 @@ valid_objectid(o_id,_I,[1]) -> false;
valid_objectid(o_id,_I,[2]) -> true;
valid_objectid(_,_,_) -> true.
-validate_sequence(S=#state{type=Vtype},Value,_Components,_Constr) ->
+convert_external(S=#state{type=Vtype}, Value) ->
case Vtype of
#type{tag=[{tag,'UNIVERSAL',8,'IMPLICIT',32}]} ->
%% this is an 'EXTERNAL' (or INSTANCE OF)
case Value of
- [{identification,_}|_RestVal] ->
- {ok,to_EXTERNAL1990(S,Value)};
+ [{#seqtag{val=identification},_}|_] ->
+ {ok,to_EXTERNAL1990(S, Value)};
_ ->
{ok,Value}
end;
@@ -2429,21 +2424,25 @@ validate_sequence(S=#state{type=Vtype},Value,_Components,_Constr) ->
{ok,Value}
end.
-to_EXTERNAL1990(S,[{identification,{'CHOICE',{syntax,Stx}}}|Rest]) ->
- to_EXTERNAL1990(S,Rest,[{'direct-reference',Stx}]);
-to_EXTERNAL1990(S,[{identification,{'CHOICE',{'presentation-context-id',I}}}|Rest]) ->
- to_EXTERNAL1990(S,Rest,[{'indirect-reference',I}]);
-to_EXTERNAL1990(S,[{identification,{'CHOICE',{'context-negotiation',[{_,PCid},{_,TrStx}]}}}|Rest]) ->
- to_EXTERNAL1990(S,Rest,[{'indirect-reference',PCid},{'direct-reference',TrStx}]);
-to_EXTERNAL1990(S,_) ->
+to_EXTERNAL1990(S, [{#seqtag{val=identification}=T,
+ {'CHOICE',{syntax,Stx}}}|Rest]) ->
+ to_EXTERNAL1990(S, Rest, [{T#seqtag{val='direct-reference'},Stx}]);
+to_EXTERNAL1990(S, [{#seqtag{val=identification}=T,
+ {'CHOICE',{'presentation-context-id',I}}}|Rest]) ->
+ to_EXTERNAL1990(S, Rest, [{T#seqtag{val='indirect-reference'},I}]);
+to_EXTERNAL1990(S, [{#seqtag{val=identification}=T,
+ {'CHOICE',{'context-negotiation',[{_,PCid},{_,TrStx}]}}}|Rest]) ->
+ to_EXTERNAL1990(S, Rest, [{T#seqtag{val='indirect-reference'},PCid},
+ {T#seqtag{val='direct-reference'},TrStx}]);
+to_EXTERNAL1990(S, _) ->
error({value,"illegal value in EXTERNAL type",S}).
-to_EXTERNAL1990(S,[V={'data-value-descriptor',_}|Rest],Acc) ->
- to_EXTERNAL1990(S,Rest,[V|Acc]);
-to_EXTERNAL1990(_S,[{'data-value',Val}],Acc) ->
- Encoding = {encoding,{'CHOICE',{'octet-aligned',Val}}},
+to_EXTERNAL1990(S, [V={#seqtag{val='data-value-descriptor'},_}|Rest], Acc) ->
+ to_EXTERNAL1990(S, Rest, [V|Acc]);
+to_EXTERNAL1990(_S, [{#seqtag{val='data-value'}=T,Val}], Acc) ->
+ Encoding = {T#seqtag{val=encoding},{'CHOICE',{'octet-aligned',Val}}},
lists:reverse([Encoding|Acc]);
-to_EXTERNAL1990(S,_,_) ->
+to_EXTERNAL1990(S, _, _) ->
error({value,"illegal value in EXTERNAL type",S}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -2614,7 +2613,7 @@ normalize_octetstring(S,Value,CType) ->
normalize_octetstring(S,String,CType);
_ ->
Item = S#state.value,
- throw(asn1_error(S, Item, illegal_octet_string_value))
+ asn1_error(S, Item, illegal_octet_string_value)
end.
normalize_objectidentifier(S, Value) ->
@@ -2645,7 +2644,7 @@ lookup_enum_value(S, Id, NNL) when is_atom(Id) ->
{_,_}=Ret ->
Ret;
false ->
- throw(asn1_error(S, S#state.value, {undefined,Id}))
+ asn1_error(S, S#state.value, {undefined,Id})
end.
normalize_choice(S,{'CHOICE',{C,V}},CType,NameList) when is_atom(C) ->
@@ -2705,20 +2704,20 @@ normalize_set(S,Value,Components,NameList) ->
normalized_record('SET',S,SortedVal,Components,NameList)
end.
-sort_value(Components,Value) ->
- ComponentNames = lists:map(fun(#'ComponentType'{name=Cname}) -> Cname end,
- Components),
- sort_value1(ComponentNames,Value,[]).
-sort_value1(_,V=#'Externalvaluereference'{},_) ->
- %% sort later, get the value in normalize_seq_or_set
- V;
-sort_value1([N|Ns],Value,Acc) ->
- case lists:keysearch(N,1,Value) of
- {value,V} ->sort_value1(Ns,Value,[V|Acc]);
- _ -> sort_value1(Ns,Value,Acc)
- end;
-sort_value1([],_,Acc) ->
- lists:reverse(Acc).
+sort_value(Components, Value0) when is_list(Value0) ->
+ {Keys0,_} = lists:mapfoldl(fun(#'ComponentType'{name=N}, I) ->
+ {{N,I},I+1}
+ end, 0, Components),
+ Keys = gb_trees:from_orddict(orddict:from_list(Keys0)),
+ Value1 = [{case gb_trees:lookup(N, Keys) of
+ {value,K} -> K;
+ none -> 'end'
+ end,Pair} || {#seqtag{val=N},_}=Pair <- Value0],
+ Value = lists:sort(Value1),
+ [Pair || {_,Pair} <- Value];
+sort_value(_Components, #'Externalvaluereference'{}=Value) ->
+ %% Sort later.
+ Value.
sort_val_if_set(['SET'|_],Val,Type) ->
sort_value(Type,Val);
@@ -2751,9 +2750,9 @@ is_record_normalized(_S,Name,Value,NumComps) when is_tuple(Value) ->
is_record_normalized(_,_,_,_) ->
false.
-normalize_seq_or_set(SorS,S,[{Cname,V}|Vs],
+normalize_seq_or_set(SorS, S, [{#seqtag{val=Cname},V}|Vs],
[#'ComponentType'{name=Cname,typespec=TS}|Cs],
- NameList,Acc) ->
+ NameList, Acc) ->
NewNameList =
case TS#type.def of
#'Externaltypereference'{type=TName} ->
@@ -2931,8 +2930,7 @@ get_canonic_type(S,Type,NameList) ->
check_ptype(S,Type,Ts) when is_record(Ts,type) ->
- %Tag = Ts#type.tag,
- %Constr = Ts#type.constraint,
+ check_formal_parameters(S, Type#ptypedef.args),
Def = Ts#type.def,
NewDef=
case Def of
@@ -2958,6 +2956,16 @@ check_ptype(S,Type,Ts) when is_record(Ts,type) ->
check_ptype(_S,_PTDef,Ts) when is_record(Ts,objectclass) ->
throw({asn1_param_class,Ts}).
+check_formal_parameters(S, Args) ->
+ _ = [check_formal_parameter(S, A) || A <- Args],
+ ok.
+
+check_formal_parameter(_, {_,_}) ->
+ ok;
+check_formal_parameter(_, #'Externaltypereference'{}) ->
+ ok;
+check_formal_parameter(S, #'Externalvaluereference'{value=Name}=Ref) ->
+ asn1_error(S, Ref, {illegal_typereference,Name}).
% check_type(S,Type,ObjSpec={{objectclassname,_},_}) ->
% check_class(S,ObjSpec);
@@ -3005,9 +3013,9 @@ check_type(S=#state{recordtopname=TopName},Type,Ts) when is_record(Ts,type) ->
{TmpRefMod,TmpRefDef} ->
{TmpRefMod,TmpRefDef,false}
end,
- case is_class(S,RefTypeDef) of
- true -> throw({asn1_class,RefTypeDef});
- _ -> ok
+ case get_class_def(S, RefTypeDef) of
+ none -> ok;
+ #classdef{} -> throw({asn1_class,RefTypeDef})
end,
Ct = TestFun(Ext),
{RefType,ExtRef} =
@@ -3084,7 +3092,7 @@ check_type(S=#state{recordtopname=TopName},Type,Ts) when is_record(Ts,type) ->
merge_tags(Tag,?TAG_PRIMITIVE(?N_INTEGER))};
{'INTEGER',NamedNumberList} ->
- TempNewDef#newt{type={'INTEGER',check_integer(S,NamedNumberList,Constr)},
+ TempNewDef#newt{type={'INTEGER',check_integer(S,NamedNumberList)},
tag=
merge_tags(Tag,?TAG_PRIMITIVE(?N_INTEGER))};
'REAL' ->
@@ -3092,8 +3100,7 @@ check_type(S=#state{recordtopname=TopName},Type,Ts) when is_record(Ts,type) ->
TempNewDef#newt{tag=merge_tags(Tag,?TAG_PRIMITIVE(?N_REAL))};
{'BIT STRING',NamedNumberList} ->
- NewL = check_bitstring(S,NamedNumberList,Constr),
-%% erlang:display({asn1ct_check,NamedNumberList,NewL}),
+ NewL = check_bitstring(S, NamedNumberList),
TempNewDef#newt{type={'BIT STRING',NewL},
tag=
merge_tags(Tag,?TAG_PRIMITIVE(?N_BIT_STRING))};
@@ -3389,23 +3396,17 @@ get_type_from_object(S,Object,TypeField)
ObjSpec = check_object(S,ObjectDef,ObjectDef#typedef.typespec),
get_fieldname_element(S,ObjectDef#typedef{typespec=ObjSpec},TypeField).
-is_class(_S,#classdef{}) ->
- true;
-is_class(S,#typedef{typespec=#type{def=Eref}})
- when is_record(Eref,'Externaltypereference')->
- is_class(S,Eref);
-is_class(S,Eref) when is_record(Eref,'Externaltypereference')->
- {_,NextDef} = get_referenced_type(S,Eref),
- is_class(S,NextDef);
-is_class(_,_) ->
- false.
-
-get_class_def(_S,CD=#classdef{}) ->
+%% get_class_def(S, Type) -> #classdef{} | 'none'.
+get_class_def(S, #typedef{typespec=#type{def=#'Externaltypereference'{}=Eref}}) ->
+ {_,NextDef} = get_referenced_type(S, Eref),
+ get_class_def(S, NextDef);
+get_class_def(S, #'Externaltypereference'{}=Eref) ->
+ {_,NextDef} = get_referenced_type(S, Eref),
+ get_class_def(S, NextDef);
+get_class_def(_S, #classdef{}=CD) ->
CD;
-get_class_def(S,#typedef{typespec=#type{def=Eref}})
- when is_record(Eref,'Externaltypereference') ->
- {_,NextDef} = get_referenced_type(S,Eref),
- get_class_def(S,NextDef).
+get_class_def(_S, _) ->
+ none.
maybe_illicit_implicit_tag(Kind,Tag) ->
case Tag of
@@ -3612,109 +3613,54 @@ match_args(_,_, _, _) ->
%% categorize_arg(S,FormalArg,ActualArg) -> {FormalArg,CatgorizedActualArg}
%%
categorize_arg(S,{Governor,Param},ActArg) ->
- case {governor_category(S,Governor),parameter_name_style(Param,ActArg)} of
-%% {absent,beginning_uppercase} -> %% a type
-%% categorize(S,type,ActArg);
- {type,beginning_lowercase} -> %% a value
- categorize(S,value,Governor,ActArg);
- {type,beginning_uppercase} -> %% a value set
- categorize(S,value_set,ActArg);
-%% {absent,entirely_uppercase} -> %% a class
-%% categorize(S,class,ActArg);
+ case {governor_category(S, Governor),parameter_name_style(Param)} of
+ {type,beginning_lowercase} -> %a value
+ categorize(S, value, Governor, ActArg);
+ {type,beginning_uppercase} -> %a value set
+ categorize(ActArg);
{{class,ClassRef},beginning_lowercase} ->
- categorize(S,object,ActArg,ClassRef);
+ categorize(S, object, ActArg, ClassRef);
{{class,ClassRef},beginning_uppercase} ->
- categorize(S,object_set,ActArg,ClassRef);
- _ ->
- [ActArg]
+ categorize(S, object_set, ActArg, ClassRef)
end;
-categorize_arg(S,FormalArg,ActualArg) ->
- %% governor is absent => a type or a class
- case FormalArg of
- #'Externaltypereference'{type=Name} ->
- case is_class_name(Name) of
- true ->
- categorize(S,class,ActualArg);
- _ ->
- categorize(S,type,ActualArg)
- end;
- FA ->
- throw({error,{unexpected_formal_argument,FA}})
- end.
-
-governor_category(S,#type{def=Eref})
- when is_record(Eref,'Externaltypereference') ->
- governor_category(S,Eref);
-governor_category(_S,#type{}) ->
+categorize_arg(_S, _FormalArg, ActualArg) ->
+ %% Governor is absent -- must be a type or a class. We have already
+ %% checked that the FormalArg begins with an uppercase letter.
+ categorize(ActualArg).
+
+%% governor_category(S, Item) -> type | {class,#'Externaltypereference'{}}
+%% Determine whether Item is a type or a class.
+governor_category(S, #type{def=#'Externaltypereference'{}=Eref}) ->
+ governor_category(S, Eref);
+governor_category(_S, #type{}) ->
type;
-governor_category(S,Ref) when is_record(Ref,'Externaltypereference') ->
- case is_class(S,Ref) of
- true ->
- {class,Ref};
- _ ->
+governor_category(S, #'Externaltypereference'{}=Ref) ->
+ case get_class_def(S, Ref) of
+ #classdef{pos=Pos,module=Mod,name=Name} ->
+ {class,#'Externaltypereference'{pos=Pos,module=Mod,type=Name}};
+ none ->
type
- end;
-governor_category(_,Class)
- when Class == 'TYPE-IDENTIFIER'; Class == 'ABSTRACT-SYNTAX' ->
- class.
-%% governor_category(_,_) ->
-%% absent.
+ end.
%% parameter_name_style(Param,Data) -> Result
%% gets the Parameter and the name of the Data and if it exists tells
%% whether it begins with a lowercase letter or is partly or entirely
%% spelled with uppercase letters. Otherwise returns undefined
%%
-parameter_name_style(_,#'Externaltypereference'{type=Name}) ->
- name_category(Name);
-parameter_name_style(_,#'Externalvaluereference'{value=Name}) ->
- name_category(Name);
-parameter_name_style(_,{valueset,_}) ->
- %% It is a object set or value set
+parameter_name_style(#'Externaltypereference'{}) ->
beginning_uppercase;
-parameter_name_style(#'Externalvaluereference'{},_) ->
- beginning_lowercase;
-parameter_name_style(#'Externaltypereference'{type=Name},_) ->
- name_category(Name);
-parameter_name_style(_,_) ->
- undefined.
-
-name_category(Atom) when is_atom(Atom) ->
- name_category(atom_to_list(Atom));
-name_category([H|T]) ->
- case is_lowercase(H) of
- true ->
- beginning_lowercase;
- _ ->
- case is_class_name(T) of
- true ->
- entirely_uppercase;
- _ ->
- beginning_uppercase
- end
- end;
-name_category(_) ->
- undefined.
+parameter_name_style(#'Externalvaluereference'{}) ->
+ beginning_lowercase.
is_lowercase(X) when X >= $A,X =< $W ->
false;
is_lowercase(_) ->
true.
-
-is_class_name(Name) when is_atom(Name) ->
- is_class_name(atom_to_list(Name));
-is_class_name(Name) ->
- case [X||X <- Name, X >= $a,X =< $w] of
- [] ->
- true;
- _ ->
- false
- end.
-%% categorize(S,Category,Parameter) -> CategorizedParameter
+%% categorize(Parameter) -> CategorizedParameter
%% If Parameter has an abstract syntax of another category than
%% Category, transform it to a known syntax.
-categorize(_S,type,{object,_,Type}) ->
+categorize({object,_,Type}) ->
%% One example of this case is an object with a parameterized type
%% having a locally defined type as parameter.
Def = fun(D = #type{}) ->
@@ -3726,11 +3672,12 @@ categorize(_S,type,{object,_,Type}) ->
D
end,
[Def(X)||X<-Type];
-categorize(_S,type,Def) when is_record(Def,type) ->
+categorize(#type{}=Def) ->
[#typedef{name = new_reference_name("type_argument"),
typespec = Def#type{inlined=yes}}];
-categorize(_,_,Def) ->
+categorize(Def) ->
[Def].
+
categorize(S,object_set,Def,ClassRef) ->
NewObjSetSpec =
check_object(S,Def,#'ObjectSet'{class = ClassRef,
@@ -4563,55 +4510,43 @@ check_reference(S,#'Externaltypereference'{pos=Pos,module=Emod,type=Name}) ->
#'Externaltypereference'{pos=Pos,module=ModName,type=Name}
end.
+get_referenced_type(S, T) ->
+ case do_get_referenced_type(S, T) of
+ {_,#type{def=#'Externaltypereference'{}=ERef}} ->
+ get_referenced_type(S, ERef);
+ {_,#type{def=#'Externalvaluereference'{}=VRef}} ->
+ get_referenced_type(S, VRef);
+ {_,_}=Res ->
+ Res
+ end.
-get_referenced_type(S,Ext) when is_record(Ext,'Externaltypereference') ->
- case match_parameters(S,Ext, S#state.parameters) of
- Ext ->
- #'Externaltypereference'{pos=Pos,module=Emod,type=Etype} = Ext,
- case S#state.mname of
- Emod -> % a local reference in this module
- get_referenced1(S,Emod,Etype,Pos);
- _ ->% always when multi file compiling
- case lists:member(Emod,S#state.inputmodules) of
- true ->
- get_referenced1(S,Emod,Etype,Pos);
- false ->
- get_referenced(S,Emod,Etype,Pos)
- end
- end;
- ERef = #'Externaltypereference'{} ->
- get_referenced_type(S,ERef);
- Other ->
- {undefined,Other}
- end;
-get_referenced_type(S=#state{mname=Emod},
- ERef=#'Externalvaluereference'{pos=P,module=Emod,
- value=Eval}) ->
- case match_parameters(S,ERef,S#state.parameters) of
- ERef ->
- get_referenced1(S,Emod,Eval,P);
- OtherERef when is_record(OtherERef,'Externalvaluereference') ->
- get_referenced_type(S,OtherERef);
- Value ->
- {Emod,Value}
- end;
-get_referenced_type(S,ERef=#'Externalvaluereference'{pos=Pos,module=Emod,
- value=Eval}) ->
- case match_parameters(S,ERef,S#state.parameters) of
- ERef ->
- case lists:member(Emod,S#state.inputmodules) of
- true ->
- get_referenced1(S,Emod,Eval,Pos);
- false ->
- get_referenced(S,Emod,Eval,Pos)
- end;
- OtherERef ->
- get_referenced_type(S,OtherERef)
- end;
-get_referenced_type(S,#identifier{val=Name,pos=Pos}) ->
- get_referenced1(S,undefined,Name,Pos);
-get_referenced_type(_S,Type) ->
- {undefined,Type}.
+do_get_referenced_type(#state{parameters=Ps}=S, T0) ->
+ case match_parameters(S, T0, Ps) of
+ T0 ->
+ do_get_ref_type_1(S, T0);
+ T ->
+ do_get_referenced_type(S, T)
+ end.
+
+do_get_ref_type_1(S, #'Externaltypereference'{pos=P,
+ module=M,
+ type=T}) ->
+ do_get_ref_type_2(S, P, M, T);
+do_get_ref_type_1(S, #'Externalvaluereference'{pos=P,
+ module=M,
+ value=V}) ->
+ do_get_ref_type_2(S, P, M, V);
+do_get_ref_type_1(_, T) ->
+ {undefined,T}.
+
+do_get_ref_type_2(#state{mname=Current,inputmodules=Modules}=S,
+ Pos, M, T) ->
+ case M =:= Current orelse lists:member(M, Modules) of
+ true ->
+ get_referenced1(S, M, T, Pos);
+ false ->
+ get_referenced(S, M, T, Pos)
+ end.
%% get_referenced/3
%% The referenced entity Ename may in case of an imported parameterized
@@ -4910,73 +4845,46 @@ imported1(Name,
end;
imported1(_Name,[]) ->
false.
-
-check_integer(_S,[],_C) ->
+%% Check the named number list for an INTEGER or a BIT STRING.
+check_named_number_list(_S, []) ->
[];
-check_integer(S,NamedNumberList,_C) ->
- case [X || X <- NamedNumberList, tuple_size(X) =:= 2] of
- NamedNumberList ->
- %% An already checked integer with NamedNumberList
- NamedNumberList;
- _ ->
- case check_unique(NamedNumberList,2) of
- [] ->
- check_int(S,NamedNumberList,[]);
- L when is_list(L) ->
- error({type,{duplicates,L},S}),
- unchanged
- end
+check_named_number_list(_S, [{_,_}|_]=NNL) ->
+ %% The named number list has already been checked.
+ NNL;
+check_named_number_list(S, NNL0) ->
+ %% Check that the names are unique.
+ T = S#state.type,
+ case check_unique(NNL0, 2) of
+ [] ->
+ NNL1 = [{Id,resolve_valueref(S, Val)} || {'NamedNumber',Id,Val} <- NNL0],
+ NNL = lists:keysort(2, NNL1),
+ case check_unique(NNL, 2) of
+ [] ->
+ NNL;
+ [Val|_] ->
+ asn1_error(S, T, {value_reused,Val})
+ end;
+ [H|_] ->
+ asn1_error(S, T, {namelist_redefinition,H})
end.
-
-check_int(S,[{'NamedNumber',Id,Num}|T],Acc) when is_integer(Num) ->
- check_int(S,T,[{Id,Num}|Acc]);
-check_int(S,[{'NamedNumber',Id,{identifier,_,Name}}|T],Acc) ->
- Val = dbget_ex(S,S#state.mname,Name),
- check_int(S,[{'NamedNumber',Id,Val#valuedef.value}|T],Acc);
-check_int(S,[{'NamedNumber',Id,{'Externalvaluereference',_,Mod,Name}}|T],Acc) ->
- Val = dbget_ex(S,Mod,Name),
- check_int(S,[{'NamedNumber',Id,Val#valuedef.value}|T],Acc);
-check_int(_S,[],Acc) ->
- lists:keysort(2,Acc).
+resolve_valueref(S, #'Externalvaluereference'{module=Mod,value=Name}) ->
+ dbget_ex(S, Mod, Name);
+resolve_valueref(_, Val) when is_integer(Val) ->
+ Val.
-check_real(_S,_Constr) ->
- ok.
+check_integer(S, NNL) ->
+ check_named_number_list(S, NNL).
-check_bitstring(_S,[],_Constr) ->
- [];
-check_bitstring(S,NamedNumberList,_Constr) ->
- case check_unique(NamedNumberList,2) of
- [] ->
- check_bitstr(S,NamedNumberList,[]);
- L when is_list(L) ->
- error({type,{duplicates,L},S}),
- unchanged
- end.
+check_bitstring(S, NNL0) ->
+ NNL = check_named_number_list(S, NNL0),
+ _ = [asn1_error(S, S#state.type, {invalid_bit_number,Bit}) ||
+ {_,Bit} <- NNL, Bit < 0],
+ NNL.
-check_bitstr(S,[{'NamedNumber',Id,Num}|T],Acc)when is_integer(Num) ->
- check_bitstr(S,T,[{Id,Num}|Acc]);
-check_bitstr(S,[{'NamedNumber',Id,Name}|T],Acc) when is_atom(Name) ->
-%%check_bitstr(S,[{'NamedNumber',Id,{identifier,_,Name}}|T],Acc) ->
-%% io:format("asn1ct_check:check_bitstr/3 hej hop ~w~n",[Name]),
- Val = dbget_ex(S,S#state.mname,Name),
-%% io:format("asn1ct_check:check_bitstr/3: ~w~n",[Val]),
- check_bitstr(S,[{'NamedNumber',Id,Val#valuedef.value}|T],Acc);
-check_bitstr(S,[],Acc) ->
- case check_unique(Acc,2) of
- [] ->
- lists:keysort(2,Acc);
- L when is_list(L) ->
- error({type,{duplicate_values,L},S}),
- unchanged
- end;
-%% When a BIT STRING already is checked, for instance a COMPONENTS OF S
-%% where S is a sequence that has a component that is a checked BS, the
-%% NamedNumber list is a list of {atom(),integer()} elements.
-check_bitstr(S,[El={Id,Num}|Rest],Acc) when is_atom(Id),is_integer(Num) ->
- check_bitstr(S,Rest,[El|Acc]).
-
+check_real(_S,_Constr) ->
+ ok.
%% Check INSTANCE OF
%% check that DefinedObjectClass is of TYPE-IDENTIFIER class
@@ -4987,20 +4895,16 @@ check_instance_of(S,DefinedObjectClass,Constraint) ->
check_type_identifier(S,DefinedObjectClass),
iof_associated_type(S,Constraint).
-
-check_type_identifier(_S,'TYPE-IDENTIFIER') ->
- ok;
-check_type_identifier(S,Eref=#'Externaltypereference'{}) ->
- case get_referenced_type(S,Eref) of
- {_,#classdef{name='TYPE-IDENTIFIER'}} -> ok;
- {_,#classdef{typespec=NextEref}}
- when is_record(NextEref,'Externaltypereference') ->
- check_type_identifier(S,NextEref);
+check_type_identifier(S, Eref=#'Externaltypereference'{type=Class}) ->
+ case get_referenced_type(S, Eref) of
+ {_,#classdef{name='TYPE-IDENTIFIER'}} ->
+ ok;
+ {_,#classdef{typespec=#'Externaltypereference'{}=NextEref}} ->
+ check_type_identifier(S, NextEref);
{_,TD=#typedef{typespec=#type{def=#'Externaltypereference'{}}}} ->
- check_type_identifier(S,(TD#typedef.typespec)#type.def);
- Err ->
- error({type,{"object set in type INSTANCE OF "
- "not of class TYPE-IDENTIFIER",Eref,Err},S})
+ check_type_identifier(S, (TD#typedef.typespec)#type.def);
+ _ ->
+ asn1_error(S, S#state.type, {illegal_instance_of,Class})
end.
iof_associated_type(S,[]) ->
@@ -5130,9 +5034,6 @@ check_enumerated(S,NamedNumberList,_Constr) ->
%% the latter is returned if the ENUMERATION contains EXTENSIONMARK
check_enum(S,[{'NamedNumber',Id,Num}|T],Acc1,Acc2,Root) when is_integer(Num) ->
check_enum(S,T,[{Id,Num}|Acc1],Acc2,Root);
-check_enum(S,[{'NamedNumber',Id,{identifier,_,Name}}|T],Acc1,Acc2,Root) ->
- Val = dbget_ex(S,S#state.mname,Name),
- check_enum(S,[{'NamedNumber',Id,Val#valuedef.value}|T],Acc1,Acc2,Root);
check_enum(S,['EXTENSIONMARK'|T],Acc1,Acc2,_Root) ->
NewAcc2 = lists:keysort(2,Acc1),
NewList = enum_number(lists:reverse(Acc2),NewAcc2,0,[],[]),
@@ -6682,6 +6583,8 @@ merge_tags2([T1= #tag{type='IMPLICIT'}, T2 |Rest], Acc) ->
merge_tags2([T1#tag{type=T2#tag.type, form=T2#tag.form}|Rest],Acc);
merge_tags2([T1= #tag{type={default,'IMPLICIT'}}, T2 |Rest], Acc) ->
merge_tags2([T1#tag{type=T2#tag.type, form=T2#tag.form}|Rest],Acc);
+merge_tags2([T1= #tag{type={default,'AUTOMATIC'}}, T2 |Rest], Acc) ->
+ merge_tags2([T1#tag{type=T2#tag.type, form=T2#tag.form}|Rest],Acc);
merge_tags2([H|T],Acc) ->
merge_tags2(T, [H|Acc]);
merge_tags2([], Acc) ->
@@ -6748,7 +6651,7 @@ storeindb(#state{mname=Module}=S, [H|T], Errors) ->
storeindb(S, T, Errors);
Prev ->
PrevLine = asn1ct:get_pos_of_def(Prev),
- {error,Error} = asn1_error(S, H, {already_defined,Name,PrevLine}),
+ Error = return_asn1_error(S, H, {already_defined,Name,PrevLine}),
storeindb(S, T, [Error|Errors])
end;
storeindb(_, [], []) ->
@@ -6795,22 +6698,39 @@ findtypes_and_values([],Tacc,Vacc,Pacc,Cacc,Oacc,OSacc) ->
{lists:reverse(Tacc),lists:reverse(Vacc),lists:reverse(Pacc),
lists:reverse(Cacc),lists:reverse(Oacc),lists:reverse(OSacc)}.
-asn1_error(#state{mname=Where}, Item, Error) ->
+return_asn1_error(#state{mname=Where}, Item, Error) ->
Pos = asn1ct:get_pos_of_def(Item),
- {error,{structured_error,{Where,Pos},?MODULE,Error}}.
+ {structured_error,{Where,Pos},?MODULE,Error}.
+
+asn1_error(S, Item, Error) ->
+ throw({error,return_asn1_error(S, Item, Error)}).
format_error({already_defined,Name,PrevLine}) ->
io_lib:format("the name ~p has already been defined at line ~p",
[Name,PrevLine]);
+format_error({illegal_instance_of,Class}) ->
+ io_lib:format("using INSTANCE OF on class '~s' is illegal, "
+ "because INSTANCE OF may only be used on the class TYPE-IDENTFIER",
+ [Class]);
format_error(illegal_octet_string_value) ->
"expecting a bstring or an hstring as value for an OCTET STRING";
+format_error({illegal_typereference,Name}) ->
+ io_lib:format("'~p' is used as a typereference, but does not start with an uppercase letter", [Name]);
format_error({invalid_fields,Fields,Obj}) ->
io_lib:format("invalid ~s in ~p", [format_fields(Fields),Obj]);
+format_error({invalid_bit_number,Bit}) ->
+ io_lib:format("the bit number '~p' is invalid", [Bit]);
format_error({missing_mandatory_fields,Fields,Obj}) ->
io_lib:format("missing mandatory ~s in ~p",
[format_fields(Fields),Obj]);
+format_error({namelist_redefinition,Name}) ->
+ io_lib:format("the name '~s' can not be redefined", [Name]);
format_error({undefined,Name}) ->
io_lib:format("'~s' is referenced, but is not defined", [Name]);
+format_error({undefined_import,Ref,Module}) ->
+ io_lib:format("'~s' is not exported from ~s", [Ref,Module]);
+format_error({value_reused,Val}) ->
+ io_lib:format("the value '~p' is used more than once", [Val]);
format_error(Other) ->
io_lib:format("~p", [Other]).
@@ -6826,14 +6746,6 @@ error({export,Msg,#state{mname=Mname,type=Ref,tname=Typename}}) ->
Pos = Ref#'Externaltypereference'.pos,
io:format("asn1error:~p:~p:~p~n~p~n",[Pos,Mname,Typename,Msg]),
{error,{export,Pos,Mname,Typename,Msg}};
-error({import,Msg,#state{mname=Mname,type=Ref,tname=Typename}}) ->
- PosOfDef =
- fun(#'Externaltypereference'{pos=P}) -> P;
- (#'Externalvaluereference'{pos=P}) -> P
- end,
- Pos = PosOfDef(Ref),
- io:format("asn1error:~p:~p:~p~n~p~n",[Pos,Mname,Typename,Msg]),
- {error,{import,Pos,Mname,Typename,Msg}};
% error({type,{Msg1,Msg2},#state{mname=Mname,type=Type,tname=Typename}})
% when is_record(Type,typedef) ->
% io:format("asn1error:~p:~p:~p ~p~n",
@@ -7050,7 +6962,7 @@ include_default_class1(_,[]) ->
include_default_class1(Module,[{Name,TS}|Rest]) ->
case asn1_db:dbget(Module,Name) of
undefined ->
- C = #classdef{checked=true,name=Name,
+ C = #classdef{checked=true,module=Module,name=Name,
typespec=TS},
asn1_db:dbput(Module,Name,C);
_ -> ok
@@ -7134,3 +7046,6 @@ check_fold(S, [H|T], Check) ->
[Error|check_fold(S, T, Check)]
end;
check_fold(_, [], Check) when is_function(Check, 3) -> [].
+
+name_of_def(#'Externaltypereference'{type=N}) -> N;
+name_of_def(#'Externalvaluereference'{value=N}) -> N.
diff --git a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl
index a38da8bcc2..5fadd0495a 100644
--- a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl
+++ b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl
@@ -962,8 +962,7 @@ gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,Assign,EncObj)
WhatKind = asn1ct_gen:type(InnerType),
emit(IndDeep),
emit(Assign),
- gen_optormand_case(OptOrMand,Erules,TopType,Cname,Type,InnerType,WhatKind,
- Element),
+ gen_optormand_case(OptOrMand, Erules, TopType, Cname, Type, Element),
case {Type,asn1ct_gen:get_constraint(Type#type.constraint,
componentrelation)} of
% #type{constraint=[{tableconstraint_info,RefedFieldName}],
@@ -1029,26 +1028,19 @@ gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,Assign,EncObj)
emit([nl,indent(7),"end"])
end.
-gen_optormand_case(mandatory,_Erules,_TopType,_Cname,_Type,_InnerType,_WhatKind,
- _Element) ->
+gen_optormand_case(mandatory, _Erules, _TopType, _Cname, _Type, _Element) ->
ok;
-gen_optormand_case('OPTIONAL',Erules,_TopType,_Cname,_Type,_InnerType,_WhatKind,
- Element) ->
+gen_optormand_case('OPTIONAL', Erules, _TopType, _Cname, _Type, Element) ->
emit([" case ",Element," of",nl]),
emit([indent(9),"asn1_NOVALUE -> {",
empty_lb(Erules),",0};",nl]),
emit([indent(9),"_ ->",nl,indent(12)]);
-gen_optormand_case({'DEFAULT',DefaultValue},Erules,TopType,Cname,Type,
- InnerType,WhatKind,Element) ->
+gen_optormand_case({'DEFAULT',DefaultValue}, Erules, _TopType,
+ _Cname, Type, Element) ->
CurrMod = get(currmod),
case catch lists:member(der,get(encoding_options)) of
true ->
- emit(" case catch "),
- asn1ct_gen:gen_check_call(TopType,Cname,Type,InnerType,
- WhatKind,{asis,DefaultValue},
- Element),
- emit([" of",nl]),
- emit([indent(12),"true -> {[],0};",nl]);
+ asn1ct_gen_check:emit(Type, DefaultValue, Element);
_ ->
emit([" case ",Element," of",nl]),
emit([indent(9),"asn1_DEFAULT -> {",
@@ -1063,10 +1055,9 @@ gen_optormand_case({'DEFAULT',DefaultValue},Erules,TopType,Cname,Type,
emit([indent(9),{asis,
DefaultValue}," -> {",
empty_lb(Erules),",0};",nl])
- end
- end,
- emit([indent(9),"_ ->",nl,indent(12)]).
-
+ end,
+ emit([indent(9),"_ ->",nl,indent(12)])
+ end.
gen_dec_line(Erules,TopType,Cname,CTags,Type,OptOrMand,DecObjInf) ->
@@ -1210,11 +1201,11 @@ gen_dec_call({typefield,_},_,_,Cname,Type,BytesVar,Tag,_,_,_DecObjInf,OptOrMandC
(Type#type.def)#'ObjectClassFieldType'.fieldname,
[{Cname,RefedFieldName,asn1ct_gen:mk_var(asn1ct_name:curr(term)),
asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),Tag,OptOrMandComp}];
-gen_dec_call(InnerType,Erules,TopType,Cname,Type,BytesVar,Tag,PrimOptOrMand,
- OptOrMand,DecObjInf,_) ->
+gen_dec_call(InnerType, _Erules, TopType, Cname, Type, BytesVar,
+ Tag, _PrimOptOrMand, _OptOrMand, DecObjInf,_) ->
WhatKind = asn1ct_gen:type(InnerType),
- gen_dec_call1(WhatKind,InnerType,Erules,TopType,Cname,Type,BytesVar,Tag,
- PrimOptOrMand,OptOrMand),
+ gen_dec_call1(WhatKind, InnerType, TopType, Cname,
+ Type, BytesVar, Tag),
case DecObjInf of
{Cname,{_,OSet,_UniqueFName,ValIndex}} ->
Term = asn1ct_gen:mk_var(asn1ct_name:curr(term)),
@@ -1226,8 +1217,9 @@ gen_dec_call(InnerType,Erules,TopType,Cname,Type,BytesVar,Tag,PrimOptOrMand,
ok
end,
[].
-gen_dec_call1({primitive,bif},InnerType,Erules,TopType,Cname,Type,BytesVar,
- Tag,OptOrMand,_) ->
+
+gen_dec_call1({primitive,bif}, InnerType, TopType, Cname,
+ Type, BytesVar, Tag) ->
case {asn1ct:get_gen_state_field(namelist),InnerType} of
{[{Cname,undecoded}|Rest],_} ->
asn1ct:add_generated_refed_func({[Cname|TopType],undecoded,
@@ -1236,11 +1228,10 @@ gen_dec_call1({primitive,bif},InnerType,Erules,TopType,Cname,Type,BytesVar,
emit(["{'",asn1ct_gen:list2name([Cname|TopType]),"',",
BytesVar,"}"]);
_ ->
- ?ASN1CT_GEN_BER:gen_dec_prim(Erules,Type,BytesVar,Tag,[],
- ?PRIMITIVE,OptOrMand)
+ ?ASN1CT_GEN_BER:gen_dec_prim(Type, BytesVar, Tag)
end;
-gen_dec_call1('ASN1_OPEN_TYPE',_InnerType,Erules,TopType,Cname,Type,BytesVar,
- Tag,OptOrMand,_) ->
+gen_dec_call1('ASN1_OPEN_TYPE', _InnerType, TopType, Cname,
+ Type, BytesVar, Tag) ->
case {asn1ct:get_gen_state_field(namelist),Type#type.def} of
{[{Cname,undecoded}|Rest],_} ->
asn1ct:add_generated_refed_func({[Cname|TopType],undecoded,
@@ -1249,15 +1240,12 @@ gen_dec_call1('ASN1_OPEN_TYPE',_InnerType,Erules,TopType,Cname,Type,BytesVar,
emit(["{'",asn1ct_gen:list2name([Cname|TopType]),"',",
BytesVar,"}"]);
{_,#'ObjectClassFieldType'{type=OpenType}} ->
- ?ASN1CT_GEN_BER:gen_dec_prim(Erules,#type{def=OpenType},
- BytesVar,Tag,[],
- ?PRIMITIVE,OptOrMand);
+ ?ASN1CT_GEN_BER:gen_dec_prim(#type{def=OpenType},
+ BytesVar, Tag);
_ ->
- ?ASN1CT_GEN_BER:gen_dec_prim(Erules,Type,BytesVar,Tag,[],
- ?PRIMITIVE,OptOrMand)
+ ?ASN1CT_GEN_BER:gen_dec_prim(Type, BytesVar, Tag)
end;
-gen_dec_call1(WhatKind,_,_Erules,TopType,Cname,Type,BytesVar,
- Tag,_,_OptOrMand) ->
+gen_dec_call1(WhatKind, _, TopType, Cname, Type, BytesVar, Tag) ->
case asn1ct:get_gen_state_field(namelist) of
[{Cname,undecoded}|Rest] ->
asn1ct:add_generated_refed_func({[Cname|TopType],undecoded,
diff --git a/lib/asn1/src/asn1ct_constructed_per.erl b/lib/asn1/src/asn1ct_constructed_per.erl
index ed3f6f886e..a91404ed54 100644
--- a/lib/asn1/src/asn1ct_constructed_per.erl
+++ b/lib/asn1/src/asn1ct_constructed_per.erl
@@ -426,8 +426,7 @@ gen_dec_open_type(Erule, Val, {Xmod,Xtype}, LeadingAttr,
emit([Term," = ",{asis,F},"(",TmpTerm,", ",Val,")"]).
dec_objset_optional(N, {'DEFAULT',Val}) ->
- dec_objset_optional_1(N, Val),
- dec_objset_optional_1(N, asn1_DEFAULT);
+ dec_objset_optional_1(N, Val);
dec_objset_optional(N, 'OPTIONAL') ->
dec_objset_optional_1(N, asn1_NOVALUE);
dec_objset_optional(_N, mandatory) -> ok.
diff --git a/lib/asn1/src/asn1ct_func.erl b/lib/asn1/src/asn1ct_func.erl
index 33f998722a..fb94f65b32 100644
--- a/lib/asn1/src/asn1ct_func.erl
+++ b/lib/asn1/src/asn1ct_func.erl
@@ -19,7 +19,8 @@
%%
-module(asn1ct_func).
--export([start_link/0,need/1,call/3,call_gen/3,call_gen/4,generate/1]).
+-export([start_link/0,need/1,call/3,call_gen/3,call_gen/4,
+ generate/1,is_used/1]).
-export([init/1,handle_call/3,handle_cast/2,terminate/2]).
start_link() ->
@@ -63,6 +64,10 @@ generate(Fd) ->
Funcs = sofs:to_external(Funcs0),
ok = file:write(Fd, Funcs).
+is_used({_,_,_}=MFA) ->
+ req({is_used,MFA}).
+
+
req(Req) ->
gen_server:call(get(?MODULE), Req, infinity).
@@ -103,7 +108,10 @@ handle_call({gen_func,Prefix,Key,GenFun}, _From, #st{gen=G0,gc=Gc0}=St) ->
{reply,Name,St#st{gen=G,gc=Gc}};
{value,{Name,_}} ->
{reply,Name,St}
- end.
+ end;
+handle_call({is_used,MFA}, _From, #st{used=Used}=St) ->
+ {reply,gb_sets:is_member(MFA, Used),St}.
+
terminate(_, _) ->
ok.
diff --git a/lib/asn1/src/asn1ct_gen.erl b/lib/asn1/src/asn1ct_gen.erl
index 4707e517b4..450d309688 100644
--- a/lib/asn1/src/asn1ct_gen.erl
+++ b/lib/asn1/src/asn1ct_gen.erl
@@ -29,7 +29,6 @@
list2rname/1,
constructed_suffix/2,
unify_if_string/1,
- gen_check_call/7,
get_constraint/2,
insert_once/2,
ct_gen_module/1,
@@ -43,6 +42,8 @@
-export([gen_encode_constructed/4,
gen_decode_constructed/4]).
+-define(SUPPRESSION_FUNC, 'dialyzer-suppressions').
+
%% pgen(Outfile, Erules, Module, TypeOrVal, Options)
%% Generate Erlang module (.erl) and (.hrl) file corresponding to an ASN.1 module
%% .hrl file is only generated if necessary
@@ -85,12 +86,18 @@ pgen_module(OutFile,Erules,Module,
"%%%",nl,
"%%% Run-time functions.",nl,
"%%%",nl]),
+ dialyzer_suppressions(Erules),
Fd = get(gen_file_out),
asn1ct_func:generate(Fd),
close_output_file(),
_ = erase(outfile),
asn1ct:verbose("--~p--~n",[{generated,ErlFile}],Options).
+dialyzer_suppressions(Erules) ->
+ emit([nl,
+ {asis,?SUPPRESSION_FUNC},"(Arg) ->",nl]),
+ Rtmod = ct_gen_module(Erules),
+ Rtmod:dialyzer_suppressions(Erules).
pgen_typeorval(Erules,Module,N2nConvEnums,{Types,Values,_Ptypes,_Classes,Objects,ObjectSets}) ->
Rtmod = ct_gen_module(Erules),
@@ -98,11 +105,6 @@ pgen_typeorval(Erules,Module,N2nConvEnums,{Types,Values,_Ptypes,_Classes,Objects
pgen_values(Erules,Module,Values),
pgen_objects(Rtmod,Erules,Module,Objects),
pgen_objectsets(Rtmod,Erules,Module,ObjectSets),
- case catch lists:member(der,get(encoding_options)) of
- true ->
- pgen_check_defaultval(Erules,Module);
- _ -> ok
- end,
pgen_partial_decode(Rtmod,Erules,Module).
pgen_values(_,_,[]) ->
@@ -178,23 +180,6 @@ pgen_objectsets(Rtmod,Erules,Module,[H|T]) ->
Rtmod:gen_objectset_code(Erules,TypeDef),
pgen_objectsets(Rtmod,Erules,Module,T).
-pgen_check_defaultval(Erules,Module) ->
- CheckObjects = asn1ct_table:to_list(check_functions),
- case get(asndebug) of
- true ->
- FileName = lists:concat([Module,".table"]),
- {ok,IoDevice} = file:open(FileName,[write]),
- Fun =
- fun(X)->
- io:format(IoDevice,"~n~n************~n~n~p~n~n*****"
- "********~n~n",[X])
- end,
- lists:foreach(Fun,CheckObjects),
- ok = file:close(IoDevice);
- _ -> ok
- end,
- gen_check_defaultval(Erules,Module,CheckObjects).
-
pgen_partial_decode(Rtmod,Erule,Module) when Erule == ber ->
pgen_partial_inc_dec(Rtmod,Erule,Module),
pgen_partial_dec(Rtmod,Erule,Module);
@@ -542,8 +527,7 @@ gen_part_decode_funcs({constructed,bif},TypeName,
emit([" 'dec_",TypeName,"'(Data,",{asis,Tag},")"]);
gen_part_decode_funcs({primitive,bif},_TypeName,
{_Name,undecoded,Tag,Type}) ->
- % Argument no 6 is 0, i.e. bit 6 for primitive encoding.
- asn1ct_gen_ber_bin_v2:gen_dec_prim(ber_bin_v2,Type,"Data",Tag,[],0,", mandatory, ");
+ asn1ct_gen_ber_bin_v2:gen_dec_prim(Type, "Data", Tag);
gen_part_decode_funcs(WhatKind,_TypeName,{_,Directive,_,_}) ->
throw({error,{asn1,{"Not implemented yet",WhatKind," partial incomplete directive:",Directive}}}).
@@ -576,131 +560,6 @@ gen_types(Erules,Tname,Type) when is_record(Type,type) ->
asn1ct_name:clear(),
Rtmod:gen_decode(Erules,Tname,Type).
-gen_check_defaultval(Erules,Module,[{Name,Type}|Rest]) ->
- gen_check_func(Name,Type),
- gen_check_defaultval(Erules,Module,Rest);
-gen_check_defaultval(_,_,[]) ->
- ok.
-
-gen_check_func(Name,FType = #type{def=Def}) ->
- EncName = ensure_atom(Name),
- emit({{asis,EncName},"(_V,asn1_DEFAULT) ->",nl," true;",nl}),
- emit({{asis,EncName},"(V,V) ->",nl," true;",nl}),
- emit({{asis,EncName},"(V,{_,V}) ->",nl," true;",nl}),
- case Def of
- {'SEQUENCE OF',Type} ->
- gen_check_sof(Name,'SEQOF',Type);
- {'SET OF',Type} ->
- gen_check_sof(Name,'SETOF',Type);
- #'SEQUENCE'{components=Components} ->
- gen_check_sequence(Name,Components);
- #'SET'{components=Components} ->
- gen_check_sequence(Name,Components);
- {'CHOICE',Components} ->
- gen_check_choice(Name,Components);
- #'Externaltypereference'{type=T} ->
- emit({{asis,EncName},"(DefaultValue,Value) ->",nl}),
- emit({" '",list2name([T,check]),"'(DefaultValue,Value).",nl});
- MaybePrim ->
- InnerType = get_inner(MaybePrim),
- case type(InnerType) of
- {primitive,bif} ->
- emit({{asis,EncName},"(DefaultValue,Value) ->",nl," "}),
- gen_prim_check_call(get_inner(InnerType),"DefaultValue","Value",
- FType),
- emit({".",nl,nl});
- _ ->
- throw({asn1_error,{unknown,type,MaybePrim}})
- end
- end.
-
-gen_check_sof(Name,SOF,Type) ->
- EncName = ensure_atom(Name),
- NewName = ensure_atom(list2name([sorted,Name])),
- emit({{asis,EncName},"(V1,V2) ->",nl}),
- emit({" ",{asis,NewName},"(lists:sort(V1),lists:sort(V2)).",nl,nl}),
- emit({{asis,NewName},"([],[]) ->",nl," true;",nl}),
- emit({{asis,NewName},"([DV|DVs],[V|Vs]) ->",nl," "}),
- InnerType = get_inner(Type#type.def),
- case type(InnerType) of
- {primitive,bif} ->
- gen_prim_check_call(get_inner(InnerType),"DV","V",Type),
- emit({",",nl});
- {constructed,bif} ->
- emit([{asis,ensure_atom(list2name([SOF,Name]))},"(DV, V),",nl]);
- #'Externaltypereference'{type=T} ->
- emit([{asis,ensure_atom(list2name([T,check]))},"(DV,V),",nl]);
- 'ASN1_OPEN_TYPE' ->
- emit(["DV = V,",nl]);
- _ ->
- emit(["DV = V,",nl])
- end,
- emit({" ",{asis,NewName},"(DVs,Vs).",nl,nl}).
-
-gen_check_sequence(Name, []) ->
- emit([{asis,ensure_atom(Name)},"(_,_) ->",nl,
- " throw(badval).",nl,nl]);
-gen_check_sequence(Name,Components) ->
- emit([{asis,ensure_atom(Name)},"(DefaultValue,Value) ->",nl]),
- gen_check_sequence(Name,Components,1).
-
-gen_check_sequence(Name,[#'ComponentType'{name=N,typespec=Type}|Cs],Num) ->
- InnerType = get_inner(Type#type.def),
- NthDefV = ["element(",Num+1,",DefaultValue)"],
- NthV = ["element(",Num+1,",Value)"],
- gen_check_func_call(Name,Type,InnerType,NthDefV,NthV,N),
- case Cs of
- [] ->
- emit({".",nl,nl});
- _ ->
- emit({",",nl}),
- gen_check_sequence(Name,Cs,Num+1)
- end.
-
-gen_check_choice(Name,CList=[#'ComponentType'{}|_Cs]) ->
- emit([{asis,ensure_atom(Name)},"({Id,DefaultValue},{Id,Value}) ->",nl]),
- emit([" case Id of",nl]),
- gen_check_choice_components(Name,CList,1).
-
-gen_check_choice_components(_,[],_)->
- ok;
-gen_check_choice_components(Name,[#'ComponentType'{name=N,typespec=Type}|
- Cs],Num) ->
- Ind6 = " ",
- InnerType = get_inner(Type#type.def),
- emit({Ind6,"'",N,"' ->",nl,Ind6}),
- gen_check_func_call(Name,Type,InnerType,{var,"defaultValue"},
- {var,"value"},N),
- case Cs of
- [] ->
- emit({nl," end.",nl,nl});
- _ ->
- emit({";",nl}),
- gen_check_choice_components(Name,Cs,Num+1)
- end.
-
-gen_check_func_call(Name,Type,InnerType,DefVal,Val,N) ->
- case type(InnerType) of
- {primitive,bif} ->
- emit(" "),
- gen_prim_check_call(get_inner(InnerType),DefVal,Val,Type);
- #'Externaltypereference'{type=T} ->
- emit({" ",{asis,ensure_atom(list2name([T,check]))},"(",DefVal,",",Val,")"});
- 'ASN1_OPEN_TYPE' ->
- emit([" if",nl,
- " ",DefVal," == ",Val," -> true;",nl,
- " true -> throw({error,{asn1_open_type}})",nl,
- " end",nl]);
- {constructed,bif} ->
- emit([" ",{asis,ensure_atom(list2name([N,Name]))},"(",DefVal,",",Val,")"]);
- _ ->
- emit([" if",nl,
- " ",DefVal," == ",Val," -> true;",nl,
- " true -> throw({error,{asn1_open_type}})",nl,
- " end",nl])
- end.
-
-
%% VARIOUS GENERATOR STUFF
%% *************************************************
%%**************************************************
@@ -790,8 +649,9 @@ gen_decode_constructed(Erules,Typename,InnerType,D) when is_record(D,typedef) ->
pgen_exports(Erules,_Module,{Types,Values,_,_,Objects,ObjectSets}) ->
- emit(["-export([encoding_rule/0,bit_string_format/0,"
+ emit(["-export([encoding_rule/0,bit_string_format/0,",nl,
" legacy_erlang_types/0]).",nl]),
+ emit(["-export([",{asis,?SUPPRESSION_FUNC},"/1]).",nl]),
case Types of
[] -> ok;
_ ->
@@ -1077,9 +937,10 @@ gen_partial_inc_dispatcher() ->
ok;
{Data1,Data2} ->
% io:format("partial_incomplete_decode: ~p~ninc_type_pattern: ~p~n",[Data,Data2]),
- gen_partial_inc_dispatcher(Data1,Data2)
+ gen_partial_inc_dispatcher(Data1, Data2, "")
end.
-gen_partial_inc_dispatcher([{FuncName,TopType,_Pattern}|Rest],TypePattern) ->
+
+gen_partial_inc_dispatcher([{FuncName,TopType,_Pattern}|Rest], TypePattern, Sep) ->
TPattern =
case lists:keysearch(FuncName,1,TypePattern) of
{value,{_,TP}} -> TP;
@@ -1093,13 +954,13 @@ gen_partial_inc_dispatcher([{FuncName,TopType,_Pattern}|Rest],TypePattern) ->
_ ->
atom_to_list(TopType)
end,
- emit(["decode_partial_inc_disp('",TopTypeName,"',Data) ->",nl,
+ emit([Sep,
+ "decode_partial_inc_disp('",TopTypeName,"',Data) ->",nl,
" ",{asis,list_to_atom(lists:concat(["dec-inc-",FuncName2]))},
- "(Data);",nl]),
- gen_partial_inc_dispatcher(Rest,TypePattern);
-gen_partial_inc_dispatcher([],_) ->
- emit(["decode_partial_inc_disp(Type,_Data) ->",nl,
- " exit({error,{asn1,{undefined_type,Type}}}).",nl]).
+ "(Data)"]),
+ gen_partial_inc_dispatcher(Rest, TypePattern, ";\n");
+gen_partial_inc_dispatcher([], _, _) ->
+ emit([".",nl]).
gen_dispatcher([F1,F2|T],FuncName,Prefix,ExtraArg) ->
emit([FuncName,"('",F1,"',Data) -> '",Prefix,F1,"'(Data",ExtraArg,")",";",nl]),
@@ -1125,7 +986,22 @@ pgen_info() ->
open_hrl(OutFile,Module) ->
File = lists:concat([OutFile,".hrl"]),
_ = open_output_file(File),
- gen_hrlhead(Module).
+ gen_hrlhead(Module),
+ Protector = hrl_protector(OutFile),
+ emit(["-ifndef(",Protector,").\n",
+ "-define(",Protector,", true).\n"
+ "\n"]).
+
+hrl_protector(OutFile) ->
+ BaseName = filename:basename(OutFile),
+ P = "_" ++ string:to_upper(BaseName) ++ "_HRL_",
+ [if
+ $A =< C, C =< $Z -> C;
+ $a =< C, C =< $a -> C;
+ $0 =< C, C =< $9 -> C;
+ true -> $_
+ end || C <- P].
+
%% EMIT functions ************************
%% ***************************************
@@ -1232,6 +1108,8 @@ pgen_hrl(Erules,Module,TypeOrVal,Options,_Indent) ->
0 ->
0;
Y ->
+ Protector = hrl_protector(get(outfile)),
+ emit(["-endif. %% ",Protector,"\n"]),
close_output_file(),
asn1ct:verbose("--~p--~n",
[{generated,lists:concat([get(outfile),".hrl"])}],
@@ -1448,171 +1326,6 @@ to_textual_order(Cs=[#'ComponentType'{textual_order=undefined}|_]) ->
to_textual_order(Cs) when is_list(Cs) ->
lists:keysort(#'ComponentType'.textual_order,Cs).
-
-gen_check_call(TopType,Cname,Type,InnerType,WhatKind,DefaultValue,Element) ->
- case WhatKind of
- {primitive,bif} ->
- gen_prim_check_call(InnerType,DefaultValue,Element,Type);
- #'Externaltypereference'{module=M,type=T} ->
- %% generate function call
- Name = list2name([T,check]),
- emit({"'",Name,"'(",DefaultValue,", ",Element,")"}),
- %% insert in ets table and do look ahead check
- Typedef = asn1_db:dbget(M,T),
- RefType = Typedef#typedef.typespec,
- InType = asn1ct_gen:get_inner(RefType#type.def),
- case insert_once(check_functions,{Name,RefType}) of
- true ->
- lookahead_innertype([T],InType,RefType);
- _ ->
- ok
- end;
- {constructed,bif} ->
- NameList = [Cname|TopType],
- Name = list2name(NameList ++ [check]),
- emit({"'",Name,"'(",DefaultValue,", ",Element,")"}),
- asn1ct_table:insert(check_functions, {Name, Type}),
- %% Must look for check functions in InnerType,
- %% that may be referenced or internal defined
- %% constructed types not used elsewhere.
- lookahead_innertype(NameList,InnerType,Type);
- _ ->
- %% Generate Dummy function call i.e. anything is accepted
- emit(["fun() -> true end ()"])
- end.
-
-gen_prim_check_call(PrimType, Default, Element, Type) ->
- case unify_if_string(PrimType) of
- 'BOOLEAN' ->
- check_call(check_bool, [Default,Element]);
- 'INTEGER' ->
- NNL = case Type#type.def of
- {_,NamedNumberList} -> NamedNumberList;
- _ -> []
- end,
- check_call(check_int, [Default,Element,{asis,NNL}]);
- 'BIT STRING' ->
- case Type#type.def of
- {_,[]} ->
- check_call(check_bitstring,
- [Default,Element]);
- {_,[_|_]=NBL} ->
- check_call(check_named_bitstring,
- [Default,Element,{asis,NBL}])
- end;
- 'OCTET STRING' ->
- check_call(check_octetstring, [Default,Element]);
- 'NULL' ->
- check_call(check_null, [Default,Element]);
- 'OBJECT IDENTIFIER' ->
- check_call(check_objectidentifier, [Default,Element]);
- 'RELATIVE-OID' ->
- check_call(check_objectidentifier, [Default,Element]);
- 'ObjectDescriptor' ->
- check_call(check_objectdescriptor, [Default,Element]);
- 'REAL' ->
- check_call(check_real, [Default,Element]);
- 'ENUMERATED' ->
- {_,Enumerations} = Type#type.def,
- check_call(check_enum, [Default,Element,{asis,Enumerations}]);
- restrictedstring ->
- check_call(check_restrictedstring, [Default,Element])
- end.
-
-check_call(F, Args) ->
- asn1ct_func:call(check, F, Args).
-
-%% lokahead_innertype/3 traverses Type and checks if check functions
-%% have to be generated, i.e. for all constructed or referenced types.
-lookahead_innertype(Name,'SEQUENCE',Type) ->
- Components = (Type#type.def)#'SEQUENCE'.components,
- lookahead_components(Name,Components);
-lookahead_innertype(Name,'SET',Type) ->
- Components = (Type#type.def)#'SET'.components,
- lookahead_components(Name,Components);
-lookahead_innertype(Name,'CHOICE',Type) ->
- {_,Components} = Type#type.def,
- lookahead_components(Name,Components);
-lookahead_innertype(Name,'SEQUENCE OF',SeqOf) ->
- lookahead_sof(Name,'SEQOF',SeqOf);
-lookahead_innertype(Name,'SET OF',SeqOf) ->
- lookahead_sof(Name,'SETOF',SeqOf);
-lookahead_innertype(_Name,#'Externaltypereference'{module=M,type=T},_) ->
- Typedef = asn1_db:dbget(M,T),
- RefType = Typedef#typedef.typespec,
- insert_once(check_functions,{list2name([T,check]),RefType}),
- InType = asn1ct_gen:get_inner(RefType#type.def),
- case type(InType) of
- {constructed,bif} ->
- lookahead_innertype([T],InType,RefType);
- Ref = #'Externaltypereference'{} ->
- lookahead_reference(Ref);
- _ ->
- ok
- end;
-lookahead_innertype(_,_,_) ->
- ok.
-
-lookahead_components(_,[]) -> ok;
-lookahead_components(Name,[C|Cs]) ->
- #'ComponentType'{name=Cname,typespec=Type} = C,
- InType = asn1ct_gen:get_inner(Type#type.def),
- case asn1ct_gen:type(InType) of
- {constructed,bif} ->
- case insert_once(check_functions,
- {list2name([Cname|Name] ++ [check]),Type}) of
- true ->
- lookahead_innertype([Cname|Name],InType,Type);
- _ ->
- ok
- end;
- #'Externaltypereference'{module=RefMod,type=RefName} ->
- Typedef = asn1_db:dbget(RefMod,RefName),
- RefType = Typedef#typedef.typespec,
- case insert_once(check_functions,{list2name([RefName,check]),
- RefType}) of
- true ->
- lookahead_innertype([RefName],InType,RefType);
- _ ->
- ok
- end;
- _ ->
- ok
- end,
- lookahead_components(Name,Cs).
-
-lookahead_sof(Name,SOF,SOFType) ->
- Type = case SOFType#type.def of
- {_,_Type} -> _Type;
- _Type -> _Type
- end,
- InnerType = asn1ct_gen:get_inner(Type#type.def),
- case asn1ct_gen:type(InnerType) of
- {constructed,bif} ->
- %% this is if a constructed type is defined in
- %% the SEQUENCE OF type
- NameList = [SOF|Name],
- insert_once(check_functions,
- {list2name(NameList ++ [check]),Type}),
- lookahead_innertype(NameList,InnerType,Type);
- Ref = #'Externaltypereference'{} ->
- lookahead_reference(Ref);
- _ ->
- ok
- end.
-
-lookahead_reference(#'Externaltypereference'{module=M,type=T}) ->
- Typedef = asn1_db:dbget(M,T),
- RefType = Typedef#typedef.typespec,
- InType = get_inner(RefType#type.def),
- case insert_once(check_functions,
- {list2name([T,check]),RefType}) of
- true ->
- lookahead_innertype([T],InType,RefType);
- _ ->
- ok
- end.
-
insert_once(Table,Object) ->
case asn1ct_table:lookup(Table, element(1, Object)) of
[] ->
@@ -1666,6 +1379,11 @@ conform_value(#type{def={'BIT STRING',[]}}, Bs) ->
bitstring when is_bitstring(Bs) ->
Bs
end;
+conform_value(#type{def='OCTET STRING'}, String) ->
+ case asn1ct:use_legacy_types() of
+ false -> String;
+ true -> binary_to_list(String)
+ end;
conform_value(_, Value) -> Value.
named_bitstring_value(List, Names) ->
@@ -1884,11 +1602,6 @@ get_constraint(C,Key) ->
{value,Cnstr} ->
Cnstr
end.
-
-ensure_atom(Atom) when is_atom(Atom) ->
- Atom;
-ensure_atom(List) when is_list(List) ->
- list_to_atom(List).
get_record_name_prefix() ->
case lists:keysearch(record_name_prefix,1,get(encoding_options)) of
diff --git a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl
index bea0ec8968..e51b0898be 100644
--- a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl
+++ b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl
@@ -27,11 +27,12 @@
-export([decode_class/1, decode_type/1]).
-export([gen_encode/2,gen_encode/3,gen_decode/2,gen_decode/3]).
-export([gen_encode_prim/4]).
--export([gen_dec_prim/7]).
+-export([gen_dec_prim/3]).
-export([gen_objectset_code/2, gen_obj_code/3]).
-export([encode_tag_val/3]).
-export([gen_inc_decode/2,gen_decode_selected/3]).
-export([extaddgroup2sequence/1]).
+-export([dialyzer_suppressions/1]).
-import(asn1ct_gen, [emit/1,demit/1]).
@@ -65,6 +66,23 @@
%%===============================================================================
%%===============================================================================
+dialyzer_suppressions(_) ->
+ case asn1ct:use_legacy_types() of
+ false -> ok;
+ true -> suppress({ber,encode_bit_string,4})
+ end,
+ suppress({ber,decode_selective,2}),
+ emit([" ok.",nl]).
+
+suppress({M,F,A}=MFA) ->
+ case asn1ct_func:is_used(MFA) of
+ false ->
+ ok;
+ true ->
+ Args = [lists:concat(["element(",I,", Arg)"]) || I <- lists:seq(1, A)],
+ emit([" ",{call,M,F,Args},com,nl])
+ end.
+
%%===============================================================================
%% encode #{typedef, {pos, name, typespec}}
%%===============================================================================
@@ -163,6 +181,12 @@ gen_encode_user(Erules, #typedef{}=D, Wrapper) ->
gen_encode_prim(_Erules, #type{}=D, DoTag, Value) ->
BitStringConstraint = get_size_constraint(D#type.constraint),
+ MaxBitStrSize = case BitStringConstraint of
+ [] -> none;
+ {_,'MAX'} -> none;
+ {_,Max} -> Max;
+ Max when is_integer(Max) -> Max
+ end,
asn1ct_name:new(enumval),
Type = case D#type.def of
'OCTET STRING' -> restricted_string;
@@ -208,11 +232,11 @@ gen_encode_prim(_Erules, #type{}=D, DoTag, Value) ->
"end"]);
{'BIT STRING',[]} ->
case asn1ct:use_legacy_types() of
- false when BitStringConstraint =:= [] ->
+ false when MaxBitStrSize =:= none ->
call(encode_unnamed_bit_string, [Value,DoTag]);
false ->
call(encode_unnamed_bit_string,
- [{asis,BitStringConstraint},Value,DoTag]);
+ [{asis,MaxBitStrSize},Value,DoTag]);
true ->
call(encode_bit_string,
[{asis,BitStringConstraint},Value,
@@ -220,12 +244,12 @@ gen_encode_prim(_Erules, #type{}=D, DoTag, Value) ->
end;
{'BIT STRING',NamedNumberList} ->
case asn1ct:use_legacy_types() of
- false when BitStringConstraint =:= [] ->
+ false when MaxBitStrSize =:= none ->
call(encode_named_bit_string,
[Value,{asis,NamedNumberList},DoTag]);
false ->
call(encode_named_bit_string,
- [{asis,BitStringConstraint},Value,
+ [{asis,MaxBitStrSize},Value,
{asis,NamedNumberList},DoTag]);
true ->
call(encode_bit_string,
@@ -254,14 +278,20 @@ emit_enc_enumerated_cases(L, Tags) ->
emit_enc_enumerated_cases(L, Tags, noext).
emit_enc_enumerated_cases([{EnumName,EnumVal}|T], Tags, Ext) ->
+ Bytes = encode_pos_integer(EnumVal, []),
+ Len = length(Bytes),
emit([{asis,EnumName}," -> ",
- {call,ber,encode_enumerated,[EnumVal,Tags]},";",nl]),
+ {call,ber,encode_tags,[Tags,{asis,Bytes},Len]},";",nl]),
emit_enc_enumerated_cases(T, Tags, Ext);
emit_enc_enumerated_cases([], _Tags, _Ext) ->
%% FIXME: Should extension be handled?
emit([{curr,enumval}," -> exit({error,{asn1, {enumerated_not_in_range,",{curr, enumval},"}}})"]),
emit([nl,"end"]).
+encode_pos_integer(0, [B|_Acc] = L) when B < 128 ->
+ L;
+encode_pos_integer(N, Acc) ->
+ encode_pos_integer(N bsr 8, [N band 255|Acc]).
%%===============================================================================
%%===============================================================================
@@ -339,15 +369,11 @@ gen_decode_selected_type(_Erules,TypeDef) ->
case asn1ct_gen:type(InnerType) of
'ASN1_OPEN_TYPE' ->
asn1ct_name:new(len),
- gen_dec_prim(ber, Def#type{def='ASN1_OPEN_TYPE'},
- BytesVar,Tag, [] ,
- ?PRIMITIVE,"OptOrMand");
-% emit({";",nl});
+ gen_dec_prim(Def#type{def='ASN1_OPEN_TYPE'},
+ BytesVar, Tag);
{primitive,bif} ->
asn1ct_name:new(len),
- gen_dec_prim(ber, Def, BytesVar,Tag,[] ,
- ?PRIMITIVE,"OptOrMand");
-% emit([";",nl]);
+ gen_dec_prim(Def, BytesVar, Tag);
{constructed,bif} ->
TopType = case TypeDef#typedef.name of
A when is_atom(A) -> [A];
@@ -461,14 +487,12 @@ gen_decode_user(Erules,D) when is_record(D,typedef) ->
case asn1ct_gen:type(InnerType) of
'ASN1_OPEN_TYPE' ->
asn1ct_name:new(len),
- gen_dec_prim(ber, Def#type{def='ASN1_OPEN_TYPE'},
- BytesVar,{string,"TagIn"}, [] ,
- ?PRIMITIVE,"OptOrMand"),
+ gen_dec_prim(Def#type{def='ASN1_OPEN_TYPE'},
+ BytesVar, {string,"TagIn"}),
emit({".",nl,nl});
{primitive,bif} ->
asn1ct_name:new(len),
- gen_dec_prim(ber, Def, BytesVar,{string,"TagIn"},[] ,
- ?PRIMITIVE,"OptOrMand"),
+ gen_dec_prim(Def, BytesVar, {string,"TagIn"}),
emit([".",nl,nl]);
{constructed,bif} ->
asn1ct:update_namelist(D#typedef.name),
@@ -481,17 +505,10 @@ gen_decode_user(Erules,D) when is_record(D,typedef) ->
end.
-gen_dec_prim(_Erules, Att, BytesVar, DoTag, _TagIn, _Form, _OptOrMand) ->
+gen_dec_prim(Att, BytesVar, DoTag) ->
Typename = Att#type.def,
-%% Currently not used for BER replaced with [] as place holder
-%% Constraint = Att#type.constraint,
-%% Constraint = [],
Constraint = get_size_constraint(Att#type.constraint),
IntConstr = int_constr(Att#type.constraint),
- AsBin = case get(binary_strings) of
- true -> "_as_bin";
- _ -> ""
- end,
NewTypeName = case Typename of
'NumericString' -> restricted_string;
'TeletexString' -> restricted_string;
@@ -505,107 +522,77 @@ gen_dec_prim(_Erules, Att, BytesVar, DoTag, _TagIn, _Form, _OptOrMand) ->
'ObjectDescriptor'-> restricted_string;
'UTCTime' -> restricted_string;
'GeneralizedTime' -> restricted_string;
+ 'OCTET STRING' ->
+ case asn1ct:use_legacy_types() of
+ true -> restricted_string;
+ false -> Typename
+ end;
_ -> Typename
end,
+ TagStr = case DoTag of
+ {string,Tag1} -> Tag1;
+ _ when is_list(DoTag) -> {asis,DoTag}
+ end,
case NewTypeName of
'BOOLEAN'->
- emit(["decode_boolean(",BytesVar,","]),
- need(decode_boolean, 2);
+ call(decode_boolean, [BytesVar,TagStr]);
'INTEGER' ->
- case IntConstr of
- [] ->
- emit(["decode_integer(",BytesVar,","]),
- need(decode_integer, 2);
- {_,_} ->
- emit(["decode_integer(",BytesVar,",",
- {asis,IntConstr},","]),
- need(decode_integer, 3)
- end;
- {'INTEGER',NamedNumberList} ->
- case IntConstr of
- [] ->
- emit(["decode_named_integer(",BytesVar,",",
- {asis,NamedNumberList},","]),
- need(decode_named_integer, 3);
- {_,_} ->
- emit(["decode_named_integer(",BytesVar,",",
- {asis,IntConstr},",",
- {asis,NamedNumberList},","]),
- need(decode_named_integer, 4)
- end;
- {'ENUMERATED',NamedNumberList} ->
- emit(["decode_enumerated(",BytesVar,",",
- {asis,NamedNumberList},","]),
- need(decode_enumerated, 3);
+ check_constraint(decode_integer, [BytesVar,TagStr],
+ IntConstr,
+ identity,
+ identity);
+ {'INTEGER',NNL} ->
+ check_constraint(decode_integer,
+ [BytesVar,TagStr],
+ IntConstr,
+ identity,
+ fun(Val) ->
+ asn1ct_name:new(val),
+ emit([{curr,val}," = "]),
+ Val(),
+ emit([com,nl,
+ {call,ber,number2name,
+ [{curr,val},{asis,NNL}]}])
+ end);
+ {'ENUMERATED',NNL} ->
+ gen_dec_enumerated(BytesVar, NNL, TagStr);
'REAL' ->
- ok;
- {'BIT STRING',_NamedNumberList} ->
- ok;
+ asn1ct_name:new(tmpbuf),
+ emit(["begin",nl,
+ {curr,tmpbuf}," = ",
+ {call,ber,match_tags,[BytesVar,TagStr]},com,nl,
+ {call,real_common,decode_real,[{curr,tmpbuf}]},nl,
+ "end",nl]);
+ {'BIT STRING',NNL} ->
+ gen_dec_bit_string(BytesVar, Constraint, NNL, TagStr);
'NULL' ->
- emit(["decode_null(",BytesVar,","]),
- need(decode_null, 2);
+ call(decode_null, [BytesVar,TagStr]);
'OBJECT IDENTIFIER' ->
- emit(["decode_object_identifier(",BytesVar,","]),
- need(decode_object_identifier, 2);
+ call(decode_object_identifier, [BytesVar,TagStr]);
'RELATIVE-OID' ->
- emit(["decode_relative_oid(",BytesVar,","]),
- need(decode_relative_oid, 2);
+ call(decode_relative_oid, [BytesVar,TagStr]);
'OCTET STRING' ->
- F = case asn1ct:use_legacy_types() of
- false -> decode_octet_string;
- true -> decode_restricted_string
- end,
- emit([{asis,F},"(",BytesVar,","]),
- case Constraint of
- [] ->
- need(F, 2);
- _ ->
- emit([{asis,Constraint},","]),
- need(F, 3)
- end;
+ check_constraint(decode_octet_string, [BytesVar,TagStr],
+ Constraint, {erlang,byte_size}, identity);
restricted_string ->
- emit(["decode_restricted_string",AsBin,"(",BytesVar,","]),
- case Constraint of
- [] ->
- need(decode_restricted_string, 2);
- _ ->
- emit([{asis,Constraint},","]),
- need(decode_restricted_string, 3)
- end;
+ check_constraint(decode_restricted_string, [BytesVar,TagStr],
+ Constraint,
+ {erlang,byte_size},
+ fun(Val) ->
+ emit("binary_to_list("),
+ Val(),
+ emit(")")
+ end);
'UniversalString' ->
- emit(["decode_universal_string",AsBin,"(",
- BytesVar,",",{asis,Constraint},","]),
- need(decode_universal_string, 3);
+ check_constraint(decode_universal_string, [BytesVar,TagStr],
+ Constraint, {erlang,length}, identity);
'UTF8String' ->
- emit(["decode_UTF8_string",AsBin,"(",
- BytesVar,","]),
- need(decode_UTF8_string, 2);
+ call(decode_UTF8_string, [BytesVar,TagStr]);
'BMPString' ->
- emit(["decode_BMP_string",AsBin,"(",
- BytesVar,",",{asis,Constraint},","]),
- need(decode_BMP_string, 3);
+ check_constraint(decode_BMP_string, [BytesVar,TagStr],
+ Constraint, {erlang,length}, identity);
'ASN1_OPEN_TYPE' ->
- emit(["decode_open_type_as_binary(",
- BytesVar,","]),
- need(decode_open_type_as_binary, 2)
- end,
-
- TagStr = case DoTag of
- {string,Tag1} -> Tag1;
- _ when is_list(DoTag) -> {asis,DoTag}
- end,
- case NewTypeName of
- {'BIT STRING',NNL} ->
- gen_dec_bit_string(BytesVar, Constraint, NNL, TagStr);
- 'REAL' ->
- asn1ct_name:new(tmpbuf),
- emit(["begin",nl,
- {curr,tmpbuf}," = ",
- {call,ber,match_tags,[BytesVar,TagStr]},com,nl,
- {call,real_common,decode_real,[{curr,tmpbuf}]},nl,
- "end",nl]);
- _ ->
- emit([TagStr,")"])
+ call(decode_open_type_as_binary, [BytesVar,TagStr])
end.
%% Simplify an integer constraint so that we can efficiently test it.
@@ -621,7 +608,7 @@ int_constr(C) ->
[{'ValueRange',{_,_}=Range}] ->
Range;
[{'SingleValue',Sv}] ->
- {Sv,Sv};
+ Sv;
[] ->
[]
end.
@@ -632,16 +619,108 @@ gen_dec_bit_string(BytesVar, _Constraint, [_|_]=NNL, TagStr) ->
gen_dec_bit_string(BytesVar, Constraint, [], TagStr) ->
case asn1ct:get_bit_string_format() of
compact ->
- call(decode_compact_bit_string,
- [BytesVar,{asis,Constraint},TagStr]);
+ check_constraint(decode_compact_bit_string,
+ [BytesVar,TagStr],
+ Constraint,
+ {ber,compact_bit_string_size},
+ identity);
legacy ->
- call(decode_legacy_bit_string,
- [BytesVar,{asis,Constraint},TagStr]);
+ check_constraint(decode_native_bit_string,
+ [BytesVar,TagStr],
+ Constraint,
+ {erlang,bit_size},
+ fun(Val) ->
+ asn1ct_name:new(val),
+ emit([{curr,val}," = "]),
+ Val(),
+ emit([com,nl,
+ {call,ber,native_to_legacy_bit_string,
+ [{curr,val}]}])
+ end);
bitstring ->
- call(decode_native_bit_string,
- [BytesVar,{asis,Constraint},TagStr])
+ check_constraint(decode_native_bit_string,
+ [BytesVar,TagStr],
+ Constraint,
+ {erlang,bit_size},
+ identity)
+ end.
+
+check_constraint(F, Args, Constr, PreConstr0, ReturnVal0) ->
+ PreConstr = case PreConstr0 of
+ identity ->
+ fun(V) -> V end;
+ {Mod,Name} ->
+ fun(V) ->
+ asn1ct_name:new(c),
+ emit([{curr,c}," = ",
+ {call,Mod,Name,[V]},com,nl]),
+ {curr,c}
+ end
+ end,
+ ReturnVal = case ReturnVal0 of
+ identity -> fun(Val) -> Val() end;
+ _ -> ReturnVal0
+ end,
+ case Constr of
+ [] when ReturnVal0 =:= identity ->
+ %% No constraint, no complications.
+ call(F, Args);
+ [] ->
+ %% No constraint, but the return value could consist
+ %% of more than one statement.
+ emit(["begin",nl]),
+ ReturnVal(fun() -> call(F, Args) end),
+ emit([nl,
+ "end",nl]);
+ _ ->
+ %% There is a constraint.
+ asn1ct_name:new(val),
+ emit(["begin",nl,
+ {curr,val}," = ",{call,ber,F,Args},com,nl]),
+ PreVal0 = asn1ct_gen:mk_var(asn1ct_name:curr(val)),
+ PreVal = PreConstr(PreVal0),
+ emit("if "),
+ case Constr of
+ {Min,Max} ->
+ emit([{asis,Min}," =< ",PreVal,", ",
+ PreVal," =< ",{asis,Max}]);
+ Sv when is_integer(Sv) ->
+ emit([PreVal," =:= ",{asis,Sv}])
+ end,
+ emit([" ->",nl]),
+ ReturnVal(fun() -> emit(PreVal0) end),
+ emit([";",nl,
+ "true ->",nl,
+ "exit({error,{asn1,bad_range}})",nl,
+ "end",nl,
+ "end"])
end.
+gen_dec_enumerated(BytesVar, NNL0, TagStr) ->
+ asn1ct_name:new(enum),
+ emit(["case ",
+ {call,ber,decode_integer,[BytesVar,TagStr]},
+ " of",nl]),
+ NNL = case NNL0 of
+ {L1,L2} ->
+ L1 ++ L2 ++ [accept];
+ [_|_] ->
+ NNL0 ++ [error]
+ end,
+ gen_dec_enumerated_1(NNL),
+ emit("end").
+
+gen_dec_enumerated_1([accept]) ->
+ asn1ct_name:new(default),
+ emit([{curr,default}," -> {asn1_enum,",{curr,default},"}",nl]);
+gen_dec_enumerated_1([error]) ->
+ asn1ct_name:new(default),
+ emit([{curr,default}," -> exit({error,{asn1,{illegal_enumerated,",
+ {curr,default},"}}})",nl]);
+gen_dec_enumerated_1([{V,K}|T]) ->
+ emit([{asis,K}," -> ",{asis,V},";",nl]),
+ gen_dec_enumerated_1(T).
+
%% Object code generating for encoding and decoding
%% ------------------------------------------------
@@ -986,9 +1065,8 @@ gen_decode_field_call(ObjName,FieldName,Bytes,Type) ->
Tag = [(decode_class(X#tag.class) bsl 10) + X#tag.number ||
X <- OTag],
case Type#typedef.name of
- {primitive,bif} -> %%tag should be the primitive tag
- gen_dec_prim(ber,Def,Bytes,Tag,"TagIn",?PRIMITIVE,
- opt_or_default),
+ {primitive,bif} ->
+ gen_dec_prim(Def, Bytes, Tag),
[];
{constructed,bif} ->
emit({" 'dec_",ObjName,'_',FieldName,
@@ -1016,8 +1094,7 @@ gen_decode_default_call(ClassName,FieldName,Bytes,Type) ->
FieldName])),
typespec=Type}];
{primitive,bif} ->
- gen_dec_prim(ber,Type,Bytes,Tag,"TagIn",
- ?PRIMITIVE,opt_or_default),
+ gen_dec_prim(Type, Bytes, Tag),
[];
#'Externaltypereference'{module=CurrentMod,type=Etype} ->
emit([" 'dec_",Etype,"'(",Bytes, " ,",{asis,Tag},")",nl]),
@@ -1386,7 +1463,7 @@ emit_dec_open_type(I) ->
end,
emit(S).
-emit_inner_of_decfun(#typedef{name={ExtName,Name},typespec=Type},Prop,
+emit_inner_of_decfun(#typedef{name={ExtName,Name},typespec=Type}, _Prop,
InternalDefFunName) ->
OTag = Type#type.tag,
%% Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
@@ -1394,8 +1471,7 @@ emit_inner_of_decfun(#typedef{name={ExtName,Name},typespec=Type},Prop,
case {ExtName,Name} of
{primitive,bif} ->
emit(indent(12)),
- gen_dec_prim(ber,Type,"Bytes",Tag,"TagIn",
- ?PRIMITIVE,Prop),
+ gen_dec_prim(Type, "Bytes", Tag),
0;
{constructed,bif} ->
emit([indent(12),"'dec_",
@@ -1412,7 +1488,7 @@ emit_inner_of_decfun(#typedef{name={ExtName,Name},typespec=Type},Prop,
emit_inner_of_decfun(#typedef{name=Name},_Prop,_) ->
emit([indent(12),"'dec_",Name,"'(Bytes)"]),
0;
-emit_inner_of_decfun(Type,Prop,_) when is_record(Type,type) ->
+emit_inner_of_decfun(#type{}=Type, _Prop, _) ->
OTag = Type#type.tag,
%% Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
Tag = [(decode_class(X#tag.class) bsl 10) + X#tag.number || X <- OTag],
@@ -1423,8 +1499,7 @@ emit_inner_of_decfun(Type,Prop,_) when is_record(Type,type) ->
case WhatKind of
{primitive,bif} ->
emit([indent(9),Def," ->",nl,indent(12)]),
- gen_dec_prim(ber,Type,"Bytes",Tag,"TagIn",
- ?PRIMITIVE,Prop);
+ gen_dec_prim(Type, "Bytes", Tag);
#'Externaltypereference'{module=CurrMod,type=T} ->
emit([indent(9),T," ->",nl,indent(12),"'dec_",T,
% "'(Bytes, ",Prop,")"]);
@@ -1561,6 +1636,3 @@ extaddgroup2sequence(ExtList) when is_list(ExtList) ->
call(F, Args) ->
asn1ct_func:call(ber, F, Args).
-
-need(F, Arity) ->
- asn1ct_func:need({ber,F,Arity}).
diff --git a/lib/asn1/src/asn1ct_gen_check.erl b/lib/asn1/src/asn1ct_gen_check.erl
new file mode 100644
index 0000000000..d80a02dfbf
--- /dev/null
+++ b/lib/asn1/src/asn1ct_gen_check.erl
@@ -0,0 +1,271 @@
+%% vim: tabstop=8:shiftwidth=4
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2014. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+-module(asn1ct_gen_check).
+-export([emit/3]).
+
+-import(asn1ct_gen, [emit/1]).
+-include("asn1_records.hrl").
+
+emit(Type, Default, Value) ->
+ Key = {Type,Default},
+ Gen = fun(Fd, Name) ->
+ file:write(Fd, gen(Name, Type, Default))
+ end,
+ emit(" case "),
+ asn1ct_func:call_gen("is_default_", Key, Gen, [Value]),
+ emit([" of",nl,
+ "true -> {[],0};",nl,
+ "false ->",nl]).
+
+gen(Name, #type{def=T}, Default) ->
+ NameStr = atom_to_list(Name),
+ [NameStr,"(asn1_DEFAULT) ->\n",
+ "true;\n"|case do_gen(T, Default) of
+ {literal,Literal} ->
+ [NameStr,"(",term2str(Literal),") ->\n","true;\n",
+ NameStr,"(_) ->\n","false.\n\n"];
+ {exception,Func,Args} ->
+ [NameStr,"(Value) ->\n",
+ "try ",Func,"(Value",arg2str(Args),") of\n",
+ "_ -> true\n"
+ "catch throw:false -> false\n"
+ "end.\n\n"]
+ end].
+
+do_gen(_, asn1_NOVALUE) ->
+ {literal,asn1_NOVALUE};
+do_gen(#'Externaltypereference'{module=M,type=T}, Default) ->
+ #typedef{typespec=#type{def=Td}} = asn1_db:dbget(M, T),
+ do_gen(Td, Default);
+do_gen('BOOLEAN', Default) ->
+ {literal,Default};
+do_gen({'BIT STRING',[]}, Default) ->
+ true = is_bitstring(Default), %Assertion.
+ case asn1ct:use_legacy_types() of
+ false ->
+ {literal,Default};
+ true ->
+ {exception,need(check_legacy_bitstring, 2),[Default]}
+ end;
+do_gen({'BIT STRING',[_|_]=NBL}, Default) ->
+ do_named_bitstring(NBL, Default);
+do_gen({'ENUMERATED',_}, Default) ->
+ {literal,Default};
+do_gen('INTEGER', Default) ->
+ {literal,Default};
+do_gen({'INTEGER',NNL}, Default) ->
+ {exception,need(check_int, 3),[Default,NNL]};
+do_gen('NULL', Default) ->
+ {literal,Default};
+do_gen('OCTET STRING', Default) ->
+ true = is_binary(Default), %Assertion.
+ case asn1ct:use_legacy_types() of
+ false ->
+ {literal,Default};
+ true ->
+ {exception,need(check_octetstring, 2),[Default]}
+ end;
+do_gen('OBJECT IDENTIFIER', Default0) ->
+ Default = pre_process_oid(Default0),
+ {exception,need(check_objectidentifier, 2),[Default]};
+do_gen({'CHOICE',Cs}, Default) ->
+ {Tag,Value} = Default,
+ [Type] = [Type || #'ComponentType'{name=T,typespec=Type} <- Cs,
+ T =:= Tag],
+ case do_gen(Type#type.def, Value) of
+ {literal,Lit} ->
+ {literal,{Tag,Lit}};
+ {exception,Func0,Args} ->
+ Key = {Tag,Func0,Args},
+ Gen = fun(Fd, Name) ->
+ S = gen_choice(Name, Tag, Func0, Args),
+ ok = file:write(Fd, S)
+ end,
+ Func = asn1ct_func:call_gen("is_default_choice", Key, Gen),
+ {exception,atom_to_list(Func),[]}
+ end;
+do_gen(#'SEQUENCE'{components=Cs}, Default) ->
+ do_seq_set(Cs, Default);
+do_gen({'SEQUENCE OF',Type}, Default) ->
+ do_sof(Type, Default);
+do_gen(#'SET'{components=Cs}, Default) ->
+ do_seq_set(Cs, Default);
+do_gen({'SET OF',Type}, Default) ->
+ do_sof(Type, Default);
+do_gen(Type, Default) ->
+ case asn1ct_gen:unify_if_string(Type) of
+ restrictedstring ->
+ {exception,need(check_restrictedstring, 2),[Default]};
+ _ ->
+ %% Open type. Do our best.
+ {literal,Default}
+ end.
+
+do_named_bitstring(NBL, Default0) when is_list(Default0) ->
+ Default = lists:sort(Default0),
+ Bs = asn1ct_gen:named_bitstring_value(Default, NBL),
+ Func = case asn1ct:use_legacy_types() of
+ false -> check_named_bitstring;
+ true -> check_legacy_named_bitstring
+ end,
+ {exception,need(Func, 4),[Default,Bs,bit_size(Bs)]};
+do_named_bitstring(_, Default) when is_bitstring(Default) ->
+ Func = case asn1ct:use_legacy_types() of
+ false -> check_named_bitstring;
+ true -> check_legacy_named_bitstring
+ end,
+ {exception,need(Func, 3),[Default,bit_size(Default)]}.
+
+do_seq_set(Cs0, Default) ->
+ Tag = element(1, Default),
+ Cs1 = [T || #'ComponentType'{typespec=T} <- Cs0],
+ Cs = components(Cs1, tl(tuple_to_list(Default))),
+ case are_all_literals(Cs) of
+ true ->
+ Literal = list_to_tuple([Tag|[L || {literal,L} <- Cs]]),
+ {literal,Literal};
+ false ->
+ Key = {Cs,Default},
+ Gen = fun(Fd, Name) ->
+ S = gen_components(Name, Tag, Cs),
+ ok = file:write(Fd, S)
+ end,
+ Func = asn1ct_func:call_gen("is_default_cs_", Key, Gen),
+ {exception,atom_to_list(Func),[]}
+ end.
+
+do_sof(Type, Default0) ->
+ Default = lists:sort(Default0),
+ Cs0 = lists:duplicate(length(Default), Type),
+ Cs = components(Cs0, Default),
+ case are_all_literals(Cs) of
+ true ->
+ Literal = [Lit || {literal,Lit} <- Cs],
+ {exception,need(check_literal_sof, 2),[Literal]};
+ false ->
+ Key = Cs,
+ Gen = fun(Fd, Name) ->
+ S = gen_sof(Name, Cs),
+ ok = file:write(Fd, S)
+ end,
+ Func = asn1ct_func:call_gen("is_default_sof", Key, Gen),
+ {exception,atom_to_list(Func),[]}
+ end.
+
+are_all_literals([{literal,_}|T]) ->
+ are_all_literals(T);
+are_all_literals([_|_]) ->
+ false;
+are_all_literals([]) -> true.
+
+gen_components(Name, Tag, Cs) ->
+ [atom_to_list(Name),"(Value) ->\n",
+ "case Value of\n",
+ "{",term2str(Tag)|gen_cs_1(Cs, 1, [])].
+
+gen_cs_1([{literal,Lit}|T], I, Acc) ->
+ [",\n",term2str(Lit)|gen_cs_1(T, I, Acc)];
+gen_cs_1([H|T], I, Acc) ->
+ Var = "E"++integer_to_list(I),
+ [",\n",Var|gen_cs_1(T, I+1, [{Var,H}|Acc])];
+gen_cs_1([], _, Acc) ->
+ ["} ->\n"|gen_cs_2(Acc, "")].
+
+gen_cs_2([{Var,{exception,Func,Args}}|T], Sep) ->
+ [Sep,Func,"(",Var,arg2str(Args),")"|gen_cs_2(T, ",\n")];
+gen_cs_2([], _) ->
+ [";\n",
+ "_ ->\n"
+ "throw(false)\n"
+ "end.\n"].
+
+gen_sof(Name, Cs) ->
+ [atom_to_list(Name),"(Value) ->\n",
+ "case length(Value) of\n",
+ integer_to_list(length(Cs))," -> ok;\n"
+ "_ -> throw(false)\n"
+ "end,\n"
+ "T0 = lists:sort(Value)"|gen_sof_1(Cs, 1)].
+
+gen_sof_1([{exception,Func,Args}|Cs], I) ->
+ NumStr = integer_to_list(I),
+ H = "H" ++ NumStr,
+ T = "T" ++ NumStr,
+ Prev = "T" ++ integer_to_list(I-1),
+ [",\n",
+ "[",H,case Cs of
+ [] -> [];
+ [_|_] -> ["|",T]
+ end,"] = ",Prev,",\n",
+ Func,"(",H,arg2str(Args),")"|gen_sof_1(Cs, I+1)];
+gen_sof_1([], _) ->
+ ".\n".
+
+components([#type{def=Def}|Ts], [V|Vs]) ->
+ [do_gen(Def, V)|components(Ts, Vs)];
+components([], []) -> [].
+
+gen_choice(Name, Tag, Func, Args) ->
+ NameStr = atom_to_list(Name),
+ [NameStr,"({",term2str(Tag),",Value}) ->\n"
+ " ",Func,"(Value",arg2str(Args),");\n",
+ NameStr,"(_) ->\n"
+ " throw(false).\n"].
+
+pre_process_oid(Oid) ->
+ Reserved = reserved_oid(),
+ pre_process_oid(tuple_to_list(Oid), Reserved, []).
+
+pre_process_oid([H|T]=Tail, Res0, Acc) ->
+ case lists:keyfind(H, 2, Res0) of
+ false ->
+ {lists:reverse(Acc),Tail};
+ {Names0,H,Res} ->
+ Names = case is_list(Names0) of
+ false -> [Names0];
+ true -> Names0
+ end,
+ Keys = [H|Names],
+ pre_process_oid(T, Res, [Keys|Acc])
+ end.
+
+reserved_oid() ->
+ [{['itu-t',ccitt],0,
+ [{recommendation,0,[]},
+ {question,1,[]},
+ {administration,2,[]},
+ {'network-operator',3,[]},
+ {'identified-organization',4,[]}]},
+ {iso,1,[{standard,0,[]},
+ {'member-body',2,[]},
+ {'identified-organization',3,[]}]},
+ {['joint-iso-itu-t','joint-iso-ccitt'],2,[]}].
+
+arg2str(Args) ->
+ [", "++term2str(Arg) || Arg <- Args].
+
+term2str(T) ->
+ io_lib:format("~w", [T]).
+
+need(F, A) ->
+ asn1ct_func:need({check,F,A}),
+ atom_to_list(F).
diff --git a/lib/asn1/src/asn1ct_gen_per.erl b/lib/asn1/src/asn1ct_gen_per.erl
index 519ce9f054..39cc0536f8 100644
--- a/lib/asn1/src/asn1ct_gen_per.erl
+++ b/lib/asn1/src/asn1ct_gen_per.erl
@@ -32,6 +32,7 @@
-export([gen_encode/2, gen_encode/3]).
-export([gen_dec_external/2]).
-export([extaddgroup2sequence/1]).
+-export([dialyzer_suppressions/1]).
-import(asn1ct_gen, [emit/1,demit/1]).
-import(asn1ct_func, [call/3]).
@@ -40,6 +41,15 @@
%% Generate ENCODING ******************************
%%****************************************x
+dialyzer_suppressions(Erules) ->
+ case asn1ct_func:is_used({Erules,complete,1}) of
+ false ->
+ ok;
+ true ->
+ emit([" _ = complete(Arg),",nl])
+ end,
+ emit([" ok.",nl]).
+
gen_encode(Erules,Type) when is_record(Type,typedef) ->
gen_encode_user(Erules,Type).
diff --git a/lib/asn1/src/asn1ct_imm.erl b/lib/asn1/src/asn1ct_imm.erl
index fde39c674e..bdd14871d1 100644
--- a/lib/asn1/src/asn1ct_imm.erl
+++ b/lib/asn1/src/asn1ct_imm.erl
@@ -82,15 +82,8 @@ per_dec_enumerated(NamedList0, Aligned) ->
Ub = length(NamedList0) - 1,
Constraint = [{'ValueRange',{0,Ub}}],
Int = per_dec_integer(Constraint, Aligned),
- EnumTail = case matched_range(Int) of
- {0,Ub} ->
- %% The error case can never happen.
- [];
- _ ->
- [enum_error]
- end,
- NamedList = per_dec_enumerated_fix_list(NamedList0, EnumTail, 0),
- {map,Int,NamedList}.
+ NamedList = per_dec_enumerated_fix_list(NamedList0, [enum_error], 0),
+ {map,Int,opt_map(NamedList, Int)}.
per_dec_enumerated(BaseNamedList, NamedListExt0, Aligned) ->
Base = per_dec_enumerated(BaseNamedList, Aligned),
@@ -124,7 +117,7 @@ per_dec_length(no, AllowZero, Aligned) ->
per_dec_named_integer(Constraint, NamedList0, Aligned) ->
Int = per_dec_integer(Constraint, Aligned),
NamedList = [{K,V} || {V,K} <- NamedList0] ++ [integer_default],
- {map,Int,NamedList}.
+ {map,Int,opt_map(NamedList, Int)}.
per_dec_k_m_string(StringType, Constraint, Aligned) ->
SzConstr = effective_constraint(bitstring, Constraint),
@@ -175,6 +168,8 @@ per_enc_bit_string(Val0, NNL0, Constraint0, Aligned) ->
ToBs = case ExtraArgs of
[] ->
{call,per_common,bs_drop_trailing_zeroes,[Val]};
+ [0] ->
+ {call,per_common,bs_drop_trailing_zeroes,[Val]};
[Lower] ->
{call,per_common,adjust_trailing_zeroes,[Val,Lower]}
end,
@@ -203,6 +198,7 @@ per_enc_legacy_bit_string(Val0, NNL0, Constraint0, Aligned) ->
Constraint = effective_constraint(bitstring, Constraint0),
ExtraArgs = case constr_min_size(Constraint) of
no -> [];
+ 0 -> [];
Lb -> [Lb]
end,
B ++ [{'try',
@@ -265,10 +261,6 @@ per_enc_k_m_string(Val0, StringType, Constraint, Aligned) ->
SzConstraint = effective_constraint(bitstring, Constraint),
Unit = string_num_bits(StringType, Constraint, Aligned),
Chars0 = char_tab(Constraint, StringType, Unit),
- Args = case enc_char_tab(Chars0) of
- notab -> [Val,Unit];
- Chars -> [Val,Unit,Chars]
- end,
Enc = case Unit of
16 ->
{call,per_common,encode_chars_16bit,[Val],Bin};
@@ -277,7 +269,15 @@ per_enc_k_m_string(Val0, StringType, Constraint, Aligned) ->
8 ->
{call,erlang,list_to_binary,[Val],Bin};
_ ->
- {call,per_common,encode_chars,Args,Bin}
+ case enc_char_tab(Chars0) of
+ notab ->
+ {call,per_common,encode_chars,[Val,Unit],Bin};
+ {tab,Tab} ->
+ {call,per_common,encode_chars,[Val,Unit,Tab],Bin};
+ {compact_map,Map} ->
+ {call,per_common,encode_chars_compact_map,
+ [Val,Unit,Map],Bin}
+ end
end,
case Unit of
8 ->
@@ -581,14 +581,42 @@ per_num_bits(N) when N =< 64 -> 6;
per_num_bits(N) when N =< 128 -> 7;
per_num_bits(N) when N =< 255 -> 8.
+opt_map(Map, Imm) ->
+ case matched_range(Imm) of
+ unknown -> Map;
+ {Lb,Ub} -> opt_map_1(Map, Lb, Ub)
+ end.
+
+opt_map_1([{I,_}=Pair|T], Lb, Ub) ->
+ if
+ I =:= Lb, I =< Ub ->
+ [Pair|opt_map_1(T, Lb+1, Ub)];
+ Lb < I, I =< Ub ->
+ [Pair|opt_map_1(T, Lb, Ub)];
+ true ->
+ opt_map_1(T, Lb, Ub)
+ end;
+opt_map_1(Map, Lb, Ub) ->
+ if
+ Lb =< Ub ->
+ Map;
+ true ->
+ []
+ end.
+
matched_range({get_bits,Bits0,[U|Flags]}) when is_integer(U) ->
- case lists:member(signed, Flags) of
- false ->
+ case not lists:member(signed, Flags) andalso is_integer(Bits0) of
+ true ->
Bits = U*Bits0,
{0,(1 bsl Bits) - 1};
- true ->
+ false ->
unknown
end;
+matched_range({add,Imm,Add}) ->
+ case matched_range(Imm) of
+ unknown -> unknown;
+ {Lb,Ub} -> {Lb+Add,Ub+Add}
+ end;
matched_range(_Op) -> unknown.
string_num_bits(StringType, Constraint, Aligned) ->
@@ -1289,6 +1317,8 @@ eval_cond_1({eq,[],[]}) ->
true;
eval_cond_1({eq,I,N}) when is_integer(I), is_integer(N) ->
I =:= N;
+eval_cond_1({ge,I,N}) when is_integer(I), is_integer(N) ->
+ I >= N;
eval_cond_1({lt,I,N}) when is_integer(I), is_integer(N) ->
I < N;
eval_cond_1(_) -> maybe.
@@ -1303,9 +1333,15 @@ prepend_to_cond_1([Check|T], Code) ->
enc_char_tab(notab) ->
notab;
enc_char_tab(Tab0) ->
- Tab = tuple_to_list(Tab0),
- First = hd(Tab),
- {First-1,list_to_tuple(enc_char_tab_1(Tab, First, 0))}.
+ Tab1 = tuple_to_list(Tab0),
+ First = hd(Tab1),
+ Tab = enc_char_tab_1(Tab1, First, 0),
+ case lists:member(ill, Tab) of
+ false ->
+ {compact_map,{First,tuple_size(Tab0)}};
+ true ->
+ {tab,{First-1,list_to_tuple(Tab)}}
+ end.
enc_char_tab_1([H|T], H, I) ->
[I|enc_char_tab_1(T, H+1, I+1)];
diff --git a/lib/asn1/src/asn1ct_parser2.erl b/lib/asn1/src/asn1ct_parser2.erl
index 283616b157..3891fce8d3 100644
--- a/lib/asn1/src/asn1ct_parser2.erl
+++ b/lib/asn1/src/asn1ct_parser2.erl
@@ -25,7 +25,8 @@
%% Only used internally within this module.
-record(typereference, {pos,val}).
--record(constraint,{c,e}).
+-record(constraint, {c,e}).
+-record(identifier, {pos,val}).
%% parse all types in module
parse(Tokens) ->
@@ -112,6 +113,9 @@ parse_ModuleDefinition(Tokens) ->
parse_Exports([{'EXPORTS',_L1},{';',_L2}|Rest]) ->
{{exports,[]},Rest};
+parse_Exports([{'EXPORTS',_},{'ALL',_},{';',_}|Rest]) ->
+ %% Same as no exports definition.
+ {{exports,all},Rest};
parse_Exports([{'EXPORTS',_L1}|Rest]) ->
{SymbolList,Rest2} = parse_SymbolList(Rest),
case Rest2 of
@@ -1037,10 +1041,6 @@ parse_DefinedObjectClass([{typereference,_,_ModName},{'.',_},Tr={typereference,_
parse_DefinedObjectClass([Tr={typereference,_,_ObjClName}|Rest]) ->
% {{objectclassname,tref2Exttref(Tr)},Rest};
{tref2Exttref(Tr),Rest};
-parse_DefinedObjectClass([{'TYPE-IDENTIFIER',_}|Rest]) ->
- {'TYPE-IDENTIFIER',Rest};
-parse_DefinedObjectClass([{'ABSTRACT-SYNTAX',_}|Rest]) ->
- {'ABSTRACT-SYNTAX',Rest};
parse_DefinedObjectClass(Tokens) ->
throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
[got,get_token(hd(Tokens)),expected,
@@ -1051,7 +1051,8 @@ parse_DefinedObjectClass(Tokens) ->
parse_ObjectClassAssignment([{typereference,L1,ObjClName},{'::=',_}|Rest]) ->
{Type,Rest2} = parse_ObjectClass(Rest),
- {#classdef{pos=L1,name=ObjClName,typespec=Type},Rest2};
+ {#classdef{pos=L1,name=ObjClName,module=resolve_module(Type),
+ typespec=Type},Rest2};
parse_ObjectClassAssignment(Tokens) ->
throw({asn1_assignment_error,{get_line(hd(Tokens)),get(asn1_module),
[got,get_token(hd(Tokens)),expected,
@@ -2134,8 +2135,7 @@ parse_ParameterizedObjectSetAssignment(Tokens) ->
%% Parameter = {Governor,Reference} | Reference
%% Governor = Type | DefinedObjectClass
%% Type = #type{}
-%% DefinedObjectClass = #'Externaltypereference'{} |
-%% 'ABSTRACT-SYNTAX' | 'TYPE-IDENTIFIER'
+%% DefinedObjectClass = #'Externaltypereference'{}
%% Reference = #'Externaltypereference'{} | #'Externalvaluereference'{}
parse_ParameterList([{'{',_}|Rest]) ->
parse_ParameterList(Rest,[]);
@@ -2863,13 +2863,14 @@ parse_SequenceValue(Tokens) ->
throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
[got,get_token(hd(Tokens)),expected,'{']}}).
-parse_SequenceValue([{identifier,_,IdName}|Rest],Acc) ->
+parse_SequenceValue([{identifier,Pos,IdName}|Rest],Acc) ->
{Value,Rest2} = parse_Value(Rest),
+ SeqTag = #seqtag{pos=Pos,module=get(asn1_module),val=IdName},
case Rest2 of
[{',',_}|Rest3] ->
- parse_SequenceValue(Rest3,[{IdName,Value}|Acc]);
+ parse_SequenceValue(Rest3, [{SeqTag,Value}|Acc]);
[{'}',_}|Rest3] ->
- {lists:reverse([{IdName,Value}|Acc]),Rest3};
+ {lists:reverse(Acc, [{SeqTag,Value}]),Rest3};
_ ->
throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module),
[got,get_token(hd(Rest2)),expected,'}']}})
diff --git a/lib/asn1/src/asn1ct_tok.erl b/lib/asn1/src/asn1ct_tok.erl
index 33f4379173..8687ed955c 100644
--- a/lib/asn1/src/asn1ct_tok.erl
+++ b/lib/asn1/src/asn1ct_tok.erl
@@ -309,7 +309,6 @@ check_hex(_) ->
%% returns rstrtype if A is a reserved word in the group
%% RestrictedCharacterStringType
reserved_word('ABSENT') -> true;
-%reserved_word('ABSTRACT-SYNTAX') -> true; % impl as predef item
reserved_word('ALL') -> true;
reserved_word('ANY') -> true;
reserved_word('APPLICATION') -> true;
@@ -380,7 +379,6 @@ reserved_word('T61String') -> rstrtype;
reserved_word('TAGS') -> true;
reserved_word('TeletexString') -> rstrtype;
reserved_word('TRUE') -> true;
-%% reserved_word('TYPE-IDENTIFIER') -> true; % impl as predef item
reserved_word('UNION') -> true;
reserved_word('UNIQUE') -> true;
reserved_word('UNIVERSAL') -> true;
diff --git a/lib/asn1/src/asn1rtt_ber.erl b/lib/asn1/src/asn1rtt_ber.erl
index 4bd814769f..c4cd872368 100644
--- a/lib/asn1/src/asn1rtt_ber.erl
+++ b/lib/asn1/src/asn1rtt_ber.erl
@@ -26,25 +26,24 @@
skip_ExtensionAdditions/2]).
-export([encode_boolean/2,decode_boolean/2,
encode_integer/2,encode_integer/3,
- decode_integer/2,decode_integer/3,
- decode_named_integer/3,decode_named_integer/4,
- encode_enumerated/2,decode_enumerated/3,
+ decode_integer/2,
+ number2name/2,
encode_unnamed_bit_string/2,encode_unnamed_bit_string/3,
encode_named_bit_string/3,encode_named_bit_string/4,
encode_bit_string/4,
decode_named_bit_string/3,
- decode_compact_bit_string/3,
- decode_legacy_bit_string/3,
- decode_native_bit_string/3,
+ decode_compact_bit_string/2,compact_bit_string_size/1,
+ decode_native_bit_string/2,
+ native_to_legacy_bit_string/1,
encode_null/2,decode_null/2,
encode_relative_oid/2,decode_relative_oid/2,
encode_object_identifier/2,decode_object_identifier/2,
encode_restricted_string/2,
- decode_octet_string/2,decode_octet_string/3,
- decode_restricted_string/2,decode_restricted_string/3,
- encode_universal_string/2,decode_universal_string/3,
+ decode_octet_string/2,
+ decode_restricted_string/2,
+ encode_universal_string/2,decode_universal_string/2,
encode_UTF8_string/2,decode_UTF8_string/2,
- encode_BMP_string/2,decode_BMP_string/3]).
+ encode_BMP_string/2,decode_BMP_string/2]).
-export([encode_open_type/2,decode_open_type/2,
decode_open_type_as_binary/2]).
@@ -591,8 +590,6 @@ encode_tags(TagIn, {BytesSoFar,LenSoFar}) ->
encode_open_type(Val, T) when is_list(Val) ->
encode_open_type(list_to_binary(Val), T);
-encode_open_type(Val, []) ->
- {Val,byte_size(Val)};
encode_open_type(Val, Tag) ->
encode_tags(Tag, Val, byte_size(Val)).
@@ -697,41 +694,14 @@ encode_integer_neg(N, Acc) ->
%%===============================================================================
%% decode integer
-%% (Buffer, Range, HasTag, TotalLen) -> {Integer, Remain, RemovedBytes}
-%% (Buffer, Range, NamedNumberList, HasTag, TotalLen) -> {Integer, Remain, RemovedBytes}
%%===============================================================================
-decode_named_integer(Tlv, NamedNumberList, TagIn) ->
- V = match_tags(Tlv, TagIn),
- Int = decode_integer(V),
- number2name(Int, NamedNumberList).
-
-decode_named_integer(Tlv, Range, NamedNumberList, TagIn) ->
- V = match_tags(Tlv, TagIn),
- Int = range_check_integer(decode_integer(V), Range),
- number2name(Int, NamedNumberList).
-
decode_integer(Tlv, TagIn) ->
- V = match_tags(Tlv, TagIn),
- decode_integer(V).
-
-decode_integer(Tlv, Range, TagIn) ->
- V = match_tags(Tlv, TagIn),
- Int = decode_integer(V),
- range_check_integer(Int, Range).
-
-decode_integer(Bin) ->
+ Bin = match_tags(Tlv, TagIn),
Len = byte_size(Bin),
<<Int:Len/signed-unit:8>> = Bin,
Int.
-range_check_integer(Int, {Lb,Ub}) when Lb =< Int, Int =< Ub ->
- Int;
-range_check_integer(Int, Range) ->
- exit({error,{asn1,{integer_range,Range,Int}}}).
-
-number2name(Int, []) ->
- Int;
number2name(Int, NamedNumberList) ->
case lists:keyfind(Int, 2, NamedNumberList) of
{NamedVal,_} ->
@@ -740,49 +710,6 @@ number2name(Int, NamedNumberList) ->
Int
end.
-
-%%============================================================================
-%% Enumerated value, ITU_T X.690 Chapter 8.4
-
-%% encode enumerated value
-%%============================================================================
-encode_enumerated(Val, TagIn) when is_integer(Val) ->
- encode_tags(TagIn, encode_integer(Val)).
-
-%%============================================================================
-%% decode enumerated value
-%% (Buffer, Range, NamedNumberList, HasTag, TotalLen) -> Value
-%%===========================================================================
-decode_enumerated(Tlv, NamedNumberList, Tags) ->
- Buffer = match_tags(Tlv, Tags),
- decode_enumerated_notag(Buffer, NamedNumberList, Tags).
-
-decode_enumerated_notag(Buffer, {NamedNumberList,ExtList}, _Tags) ->
- IVal = decode_integer(Buffer),
- case decode_enumerated1(IVal, NamedNumberList) of
- {asn1_enum,IVal} ->
- decode_enumerated1(IVal,ExtList);
- EVal ->
- EVal
- end;
-decode_enumerated_notag(Buffer, NNList, _Tags) ->
- IVal = decode_integer(Buffer),
- case decode_enumerated1(IVal, NNList) of
- {asn1_enum,_} ->
- exit({error,{asn1, {illegal_enumerated, IVal}}});
- EVal ->
- EVal
- end.
-
-decode_enumerated1(Val, NamedNumberList) ->
- %% it must be a named integer
- case lists:keyfind(Val, 2, NamedNumberList) of
- {NamedVal, _} ->
- NamedVal;
- _ ->
- {asn1_enum,Val}
- end.
-
%%============================================================================
%% Bitstring value, ITU_T X.690 Chapter 8.6
%%
@@ -794,45 +721,46 @@ encode_unnamed_bit_string(Bits, TagIn) ->
Bin = <<Unused,Bits/bitstring,0:Unused>>,
encode_tags(TagIn, Bin, byte_size(Bin)).
-encode_unnamed_bit_string(C, Bits, TagIn) ->
+encode_unnamed_bit_string(MaxBits, Bits, TagIn) ->
NumBits = bit_size(Bits),
Unused = (8 - (NumBits band 7)) band 7,
Bin = <<Unused,Bits/bitstring,0:Unused>>,
- case C of
- {_Min,Max} ->
- if
- NumBits > Max ->
- exit({error,{asn1,
- {bitstring_length,
- {{was,NumBits},{maximum,Max}}}}});
- true ->
- ok
- end;
- Size ->
- if NumBits =< Size ->
- ok;
- true ->
- exit({error,{asn1,
- {bitstring_length,
- {{was,NumBits},{should_be,Size}}}}})
- end
- end,
- encode_tags(TagIn, Bin, byte_size(Bin)).
+ if
+ NumBits > MaxBits ->
+ exit({error,{asn1,
+ {bitstring_length,
+ {{was,NumBits},{maximum,MaxBits}}}}});
+ true ->
+ encode_tags(TagIn, Bin, byte_size(Bin))
+ end.
encode_named_bit_string([H|_]=Bits, NamedBitList, TagIn) when is_atom(H) ->
- encode_bit_string_named([], Bits, NamedBitList, TagIn);
+ do_encode_named_bit_string(Bits, NamedBitList, TagIn);
encode_named_bit_string([{bit,_}|_]=Bits, NamedBitList, TagIn) ->
- encode_bit_string_named([], Bits, NamedBitList, TagIn);
+ do_encode_named_bit_string(Bits, NamedBitList, TagIn);
encode_named_bit_string(Bits, _NamedBitList, TagIn) when is_bitstring(Bits) ->
encode_unnamed_bit_string(Bits, TagIn).
encode_named_bit_string(C, [H|_]=Bits, NamedBitList, TagIn) when is_atom(H) ->
- encode_bit_string_named(C, Bits, NamedBitList, TagIn);
+ do_encode_named_bit_string(C, Bits, NamedBitList, TagIn);
encode_named_bit_string(C, [{bit,_}|_]=Bits, NamedBitList, TagIn) ->
- encode_bit_string_named(C, Bits, NamedBitList, TagIn);
+ do_encode_named_bit_string(C, Bits, NamedBitList, TagIn);
encode_named_bit_string(C, Bits, _NamedBitList, TagIn) when is_bitstring(Bits) ->
encode_unnamed_bit_string(C, Bits, TagIn).
+do_encode_named_bit_string([FirstVal | RestVal], NamedBitList, TagIn) ->
+ ToSetPos = get_all_bitposes([FirstVal | RestVal], NamedBitList, []),
+ Size = lists:max(ToSetPos) + 1,
+ BitList = make_and_set_list(Size, ToSetPos, 0),
+ {Len,Unused,OctetList} = encode_bitstring(BitList),
+ encode_tags(TagIn, [Unused|OctetList],Len+1).
+
+do_encode_named_bit_string(Size, [FirstVal | RestVal], NamedBitList, TagIn) ->
+ ToSetPos = get_all_bitposes([FirstVal | RestVal], NamedBitList, []),
+ BitList = make_and_set_list(Size, ToSetPos, 0),
+ {Len, Unused, OctetList} = encode_bitstring(BitList),
+ encode_tags(TagIn, [Unused|OctetList], Len+1).
+
%%============================================================================
%% Bitstring value, ITU_T X.690 Chapter 8.6
%%
@@ -932,15 +860,14 @@ remove_unused_then_dotag(TagIn,Unused,BinBits) ->
encode_bit_string_named(C, [FirstVal | RestVal], NamedBitList, TagIn) ->
ToSetPos = get_all_bitposes([FirstVal | RestVal], NamedBitList, []),
- Size =
- case C of
- [] ->
- lists:max(ToSetPos)+1;
- {_Min,Max} ->
- Max;
- TSize ->
- TSize
- end,
+ Size = case C of
+ [] ->
+ lists:max(ToSetPos) + 1;
+ {_Min,Max} ->
+ Max;
+ TSize ->
+ TSize
+ end,
BitList = make_and_set_list(Size, ToSetPos, 0),
{Len, Unused, OctetList} = encode_bitstring(BitList),
encode_tags(TagIn, [Unused|OctetList],Len+1).
@@ -1098,33 +1025,23 @@ unused_bitlist([Bit | Rest], Trail, Ack) ->
%% decode bitstring value
%%============================================================================
-decode_compact_bit_string(Buffer, Range, Tags) ->
+decode_compact_bit_string(Buffer, Tags) ->
case match_and_collect(Buffer, Tags) of
- <<0>> ->
- check_restricted_string({0,<<>>}, 0, Range);
- <<Unused,Bits/binary>> ->
- Val = {Unused,Bits},
- Len = bit_size(Bits) - Unused,
- check_restricted_string(Val, Len, Range)
+ <<0>> -> {0,<<>>};
+ <<Unused,Bits/binary>> -> {Unused,Bits}
end.
-decode_legacy_bit_string(Buffer, Range, Tags) ->
- Val = case match_and_collect(Buffer, Tags) of
- <<0>> ->
- [];
- <<Unused,Bits/binary>> ->
- decode_bitstring2(byte_size(Bits), Unused, Bits)
- end,
- check_restricted_string(Val, length(Val), Range).
+compact_bit_string_size({Unused,Bits}) ->
+ bit_size(Bits) - Unused.
-decode_native_bit_string(Buffer, Range, Tags) ->
+decode_native_bit_string(Buffer, Tags) ->
case match_and_collect(Buffer, Tags) of
<<0>> ->
- check_restricted_string(<<>>, 0, Range);
+ <<>>;
<<Unused,Bits/binary>> ->
Size = bit_size(Bits) - Unused,
<<Val:Size/bitstring,_:Unused/bitstring>> = Bits,
- check_restricted_string(Val, Size, Range)
+ Val
end.
decode_named_bit_string(Buffer, NamedNumberList, Tags) ->
@@ -1147,6 +1064,9 @@ decode_bitstring2(Len, Unused,
[B7,B6,B5,B4,B3,B2,B1,B0|
decode_bitstring2(Len - 1, Unused, Buffer)].
+native_to_legacy_bit_string(Bits) ->
+ [B || <<B:1>> <= Bits].
+
%%----------------------------------------
%% Decode the bitlist to names
%%----------------------------------------
@@ -1310,31 +1230,12 @@ decode_octet_string(Tlv, TagsIn) ->
Bin = match_and_collect(Tlv, TagsIn),
binary:copy(Bin).
-decode_octet_string(Tlv, Range, TagsIn) ->
- Bin0 = match_and_collect(Tlv, TagsIn),
- Bin = binary:copy(Bin0),
- check_restricted_string(Bin, byte_size(Bin), Range).
-
%%============================================================================
%% decode Numeric Printable Teletex Videotex Visible IA5 Graphic General strings
%%============================================================================
decode_restricted_string(Tlv, TagsIn) ->
- Bin = match_and_collect(Tlv, TagsIn),
- binary_to_list(Bin).
-
-decode_restricted_string(Tlv, Range, TagsIn) ->
- Bin = match_and_collect(Tlv, TagsIn),
- check_restricted_string(binary_to_list(Bin), byte_size(Bin), Range).
-
-check_restricted_string(Val, _Len, []) ->
- Val;
-check_restricted_string(Val, Len, {Lb,Ub}) when Lb =< Len, Len =< Ub ->
- Val;
-check_restricted_string(Val, Len, Len) ->
- Val;
-check_restricted_string(Val, _Len, Range) ->
- exit({error,{asn1,{length,Range,Val}}}).
+ match_and_collect(Tlv, TagsIn).
%%============================================================================
%% encode Universal string
@@ -1360,10 +1261,9 @@ mk_uni_list([H|T],List) ->
%% {String, Remain, RemovedBytes}
%%===========================================================================
-decode_universal_string(Buffer, Range, Tags) ->
+decode_universal_string(Buffer, Tags) ->
Bin = match_and_collect(Buffer, Tags),
- Val = mk_universal_string(binary_to_list(Bin)),
- check_restricted_string(Val, length(Val), Range).
+ mk_universal_string(binary_to_list(Bin)).
mk_universal_string(In) ->
mk_universal_string(In, []).
@@ -1423,10 +1323,9 @@ mk_BMP_list([H|T], List) ->
%% (Buffer, Range, StringType, HasTag, TotalLen) ->
%% {String, Remain, RemovedBytes}
%%============================================================================
-decode_BMP_string(Buffer, Range, Tags) ->
+decode_BMP_string(Buffer, Tags) ->
Bin = match_and_collect(Buffer, Tags),
- Val = mk_BMP_string(binary_to_list(Bin)),
- check_restricted_string(Val, length(Val), Range).
+ mk_BMP_string(binary_to_list(Bin)).
mk_BMP_string(In) ->
mk_BMP_string(In,[]).
diff --git a/lib/asn1/src/asn1rtt_check.erl b/lib/asn1/src/asn1rtt_check.erl
index be4f9c8bff..0083867a10 100644
--- a/lib/asn1/src/asn1rtt_check.erl
+++ b/lib/asn1/src/asn1rtt_check.erl
@@ -18,43 +18,41 @@
%%
-module(asn1rtt_check).
--export([check_bool/2,
+-export([check_fail/1,
check_int/3,
- check_bitstring/2,check_named_bitstring/3,
+ check_legacy_bitstring/2,
+ check_legacy_named_bitstring/3,
+ check_legacy_named_bitstring/4,
+ check_named_bitstring/3,
+ check_named_bitstring/4,
+ check_literal_sof/2,
check_octetstring/2,
- check_null/2,
check_objectidentifier/2,
check_objectdescriptor/2,
check_real/2,
- check_enum/3,
check_restrictedstring/2]).
-check_bool(_Bool, asn1_DEFAULT) ->
- true;
-check_bool(Bool, Bool) when is_boolean(Bool) ->
- true;
-check_bool(_Bool1, Bool2) ->
- throw({error,Bool2}).
+check_fail(_) ->
+ throw(false).
-check_int(_, asn1_DEFAULT, _) ->
- true;
check_int(Value, Value, _) when is_integer(Value) ->
true;
-check_int(DefValue, Value, NNL) when is_atom(Value) ->
+check_int(Value, DefValue, NNL) when is_atom(Value) ->
case lists:keyfind(Value, 1, NNL) of
{_,DefValue} ->
true;
_ ->
- throw({error,DefValue})
+ throw(false)
end;
-check_int(DefaultValue, _Value, _) ->
- throw({error,DefaultValue}).
+check_int(_, _, _) ->
+ throw(false).
+
+check_legacy_bitstring(Value, Default) ->
+ check_bitstring(Default, Value).
%% check_bitstring(Default, UserBitstring) -> true|false
%% Default = bitstring()
%% UserBitstring = integeger() | list(0|1) | {Unused,binary()} | bitstring()
-check_bitstring(_, asn1_DEFAULT) ->
- true;
check_bitstring(DefVal, {Unused,Binary}) ->
%% User value in compact format.
Sz = bit_size(Binary) - Unused,
@@ -62,7 +60,7 @@ check_bitstring(DefVal, {Unused,Binary}) ->
check_bitstring(DefVal, Val);
check_bitstring(DefVal, Val) when is_bitstring(Val) ->
case Val =:= DefVal of
- false -> throw(error);
+ false -> throw(false);
true -> true
end;
check_bitstring(Def, Val) when is_list(Val) ->
@@ -75,178 +73,95 @@ check_bitstring_list(<<H:1,T1/bitstring>>, [H|T2]) ->
check_bitstring_list(<<>>, []) ->
true;
check_bitstring_list(_, _) ->
- throw(error).
+ throw(false).
check_bitstring_integer(<<H:1,T1/bitstring>>, Int) when H =:= Int band 1 ->
check_bitstring_integer(T1, Int bsr 1);
check_bitstring_integer(<<>>, 0) ->
true;
check_bitstring_integer(_, _) ->
- throw(error).
-
-check_named_bitstring(_, asn1_DEFAULT, _) ->
- true;
-check_named_bitstring(V, V, _) ->
- true;
-%% Default value and user value as lists of ones and zeros
-check_named_bitstring(L1=[H1|_T1], L2=[H2|_T2], NBL=[_H|_T]) when is_integer(H1), is_integer(H2) ->
- L2new = remove_trailing_zeros(L2),
- check_named_bitstring(L1, L2new, NBL);
-%% Default value as a list of 1 and 0 and user value as a list of atoms
-check_named_bitstring(L1=[H1|_T1], L2=[H2|_T2], NBL) when is_integer(H1), is_atom(H2) ->
- L3 = bit_list_to_nbl(L1, NBL, 0, []),
- check_named_bitstring(L3, L2, NBL);
-%% Both default value and user value as a list of atoms
-check_named_bitstring(L1=[H1|T1], L2=[H2|_T2], _)
- when is_atom(H1), is_atom(H2), length(L1) =:= length(L2) ->
- case lists:member(H1, L2) of
- true ->
- check_bitstring1(T1, L2);
- false -> throw({error,L2})
- end;
-%% Default value as a list of atoms and user value as a list of 1 and 0
-check_named_bitstring(L1=[H1|_T1], L2=[H2|_T2], NBL) when is_atom(H1), is_integer(H2) ->
- L3 = bit_list_to_nbl(L2, NBL, 0, []),
- check_named_bitstring(L1, L3, NBL);
-%% User value in compact format
-check_named_bitstring(DefVal,CBS={_,_}, NBL) ->
- NewVal = cbs_to_bit_list(CBS),
- check_named_bitstring(DefVal, NewVal, NBL);
-%% User value as a binary
-check_named_bitstring(DefVal, CBS, NBL) when is_binary(CBS) ->
- NewVal = cbs_to_bit_list({0,CBS}),
- check_named_bitstring(DefVal, NewVal, NBL);
-%% User value as a bitstring
-check_named_bitstring(DefVal, CBS, NBL) when is_bitstring(CBS) ->
- BitSize = bit_size(CBS),
- Unused = 8 - (BitSize band 7),
- NewVal = cbs_to_bit_list({Unused,<<CBS:BitSize/bits,0:Unused>>}),
- check_named_bitstring(DefVal, NewVal, NBL);
-check_named_bitstring(DV, V, _) ->
- throw({error,DV,V}).
-
-int_to_bit_list(0, Acc, 0) ->
- Acc;
-int_to_bit_list(Int, Acc, Len) when Len > 0 ->
- int_to_bit_list(Int bsr 1, [Int band 1|Acc], Len - 1).
-
-bit_list_to_nbl([0|T], NBL, Pos, Acc) ->
- bit_list_to_nbl(T, NBL, Pos+1, Acc);
-bit_list_to_nbl([1|T], NBL, Pos, Acc) ->
- case lists:keyfind(Pos, 2, NBL) of
- {N,_} ->
- bit_list_to_nbl(T, NBL, Pos+1, [N|Acc]);
+ throw(false).
+
+check_legacy_named_bitstring([Int|_]=Val, Bs, BsSize) when is_integer(Int) ->
+ check_named_bitstring(<< <<B:1>> || B <- Val >>, Bs, BsSize);
+check_legacy_named_bitstring({Unused,Val0}, Bs, BsSize) ->
+ Sz = bit_size(Val0) - Unused,
+ <<Val:Sz/bits,_/bits>> = Val0,
+ check_named_bitstring(Val, Bs, BsSize);
+check_legacy_named_bitstring(Val, Bs, BsSize) when is_integer(Val) ->
+ L = legacy_int_to_bitlist(Val),
+ check_named_bitstring(<< <<B:1>> || B <- L >>, Bs, BsSize);
+check_legacy_named_bitstring(Val, Bs, BsSize) ->
+ check_named_bitstring(Val, Bs, BsSize).
+
+check_legacy_named_bitstring([Int|_]=Val, Names, Bs, BsSize) when is_integer(Int) ->
+ check_named_bitstring(<< <<B:1>> || B <- Val >>, Names, Bs, BsSize);
+check_legacy_named_bitstring({Unused,Val0}, Names, Bs, BsSize) ->
+ Sz = bit_size(Val0) - Unused,
+ <<Val:Sz/bits,_/bits>> = Val0,
+ check_named_bitstring(Val, Names, Bs, BsSize);
+check_legacy_named_bitstring(Val, Names, Bs, BsSize) when is_integer(Val) ->
+ L = legacy_int_to_bitlist(Val),
+ check_named_bitstring(<< <<B:1>> || B <- L >>, Names, Bs, BsSize);
+check_legacy_named_bitstring(Val, Names, Bs, BsSize) ->
+ check_named_bitstring(Val, Names, Bs, BsSize).
+
+legacy_int_to_bitlist(0) ->
+ [];
+legacy_int_to_bitlist(Int) ->
+ [Int band 1|legacy_int_to_bitlist(Int bsr 1)].
+
+check_named_bitstring(Bs, Bs, _) ->
+ true;
+check_named_bitstring(Val, Bs, BsSize) ->
+ Rest = bit_size(Val) - BsSize,
+ case Val of
+ <<Bs:BsSize/bits,0:Rest>> ->
+ true;
_ ->
- throw({error,{no,named,element,at,pos,Pos}})
- end;
-bit_list_to_nbl([], _, _, Acc) ->
- Acc.
-
-remove_trailing_zeros(L2) ->
- remove_trailing_zeros1(lists:reverse(L2)).
-remove_trailing_zeros1(L) ->
- lists:reverse(lists:dropwhile(fun(0)->true;
- (_) ->false
- end,
- L)).
-
-check_bitstring1([H|T], NBL) ->
- case lists:member(H, NBL) of
- true -> check_bitstring1(T, NBL);
- V -> throw({error,V})
- end;
-check_bitstring1([], _) ->
- true.
-
-cbs_to_bit_list({Unused, <<B7:1,B6:1,B5:1,B4:1,B3:1,B2:1,B1:1,B0:1,Rest/binary>>}) when byte_size(Rest) >= 1 ->
- [B7,B6,B5,B4,B3,B2,B1,B0|cbs_to_bit_list({Unused,Rest})];
-cbs_to_bit_list({0,<<B7:1,B6:1,B5:1,B4:1,B3:1,B2:1,B1:1,B0:1>>}) ->
- [B7,B6,B5,B4,B3,B2,B1,B0];
-cbs_to_bit_list({Unused,Bin}) when byte_size(Bin) =:= 1 ->
- Used = 8-Unused,
- <<Int:Used,_:Unused>> = Bin,
- int_to_bit_list(Int, [], Used).
-
+ throw(false)
+ end.
-check_octetstring(_, asn1_DEFAULT) ->
- true;
-check_octetstring(L, L) ->
- true;
-check_octetstring(L, Int) when is_list(L), is_integer(Int) ->
- case integer_to_octetlist(Int) of
- L -> true;
- V -> throw({error,V})
+check_named_bitstring([_|_]=Val, Names, _, _) ->
+ case lists:sort(Val) of
+ Names -> true;
+ _ -> throw(false)
end;
-check_octetstring(_, V) ->
- throw({error,V}).
-
-integer_to_octetlist(Int) ->
- integer_to_octetlist(Int, []).
-integer_to_octetlist(0, Acc) ->
- Acc;
-integer_to_octetlist(Int, Acc) ->
- integer_to_octetlist(Int bsr 8, [(Int band 255)|Acc]).
-
-check_null(_, asn1_DEFAULT) ->
+check_named_bitstring(Bs, _, Bs, _) ->
true;
-check_null('NULL', 'NULL') ->
- true;
-check_null(_, V) ->
- throw({error,V}).
+check_named_bitstring(Val, _, Bs, BsSize) ->
+ Rest = bit_size(Val) - BsSize,
+ case Val of
+ <<Bs:BsSize/bits,0:Rest>> ->
+ true;
+ _ ->
+ throw(false)
+ end.
-check_objectidentifier(_, asn1_DEFAULT) ->
- true;
-check_objectidentifier(OI, OI) ->
+check_octetstring(V, V) ->
true;
-check_objectidentifier(DOI, OI) when is_tuple(DOI), is_tuple(OI) ->
- check_objectidentifier1(tuple_to_list(DOI), tuple_to_list(OI));
-check_objectidentifier(_, OI) ->
- throw({error,OI}).
-
-check_objectidentifier1([V|Rest1], [V|Rest2]) ->
- check_objectidentifier1(Rest1, Rest2, V);
-check_objectidentifier1([V1|Rest1], [V2|Rest2]) ->
- case reserved_objectid(V2, []) of
- V1 ->
- check_objectidentifier1(Rest1, Rest2, [V1]);
- V ->
- throw({error,V})
- end.
-check_objectidentifier1([V|Rest1], [V|Rest2], Above) ->
- check_objectidentifier1(Rest1, Rest2, [V|Above]);
-check_objectidentifier1([V1|Rest1], [V2|Rest2], Above) ->
- case reserved_objectid(V2, Above) of
- V1 ->
- check_objectidentifier1(Rest1, Rest2, [V1|Above]);
- V ->
- throw({error,V})
+check_octetstring(V, Def) when is_list(V) ->
+ case list_to_binary(V) of
+ Def -> true;
+ _ -> throw(false)
+ end;
+check_octetstring(_, _) ->
+ throw(false).
+
+check_objectidentifier(Value, {Prefix,Tail}) when is_tuple(Value) ->
+ check_oid(tuple_to_list(Value), Prefix, Tail);
+check_objectidentifier(_, _) ->
+ throw(false).
+
+check_oid([H|T], [K|Ks], Tail) ->
+ case lists:member(H, K) of
+ false -> throw(false);
+ true -> check_oid(T, Ks, Tail)
end;
-check_objectidentifier1([], [], _) ->
+check_oid(Tail, [], Tail) ->
true;
-check_objectidentifier1(_, V, _) ->
- throw({error,object,identifier,V}).
-
-%% ITU-T Rec. X.680 Annex B - D
-reserved_objectid('itu-t', []) -> 0;
-reserved_objectid('ccitt', []) -> 0;
-%% arcs below "itu-t"
-reserved_objectid('recommendation', [0]) -> 0;
-reserved_objectid('question', [0]) -> 1;
-reserved_objectid('administration', [0]) -> 2;
-reserved_objectid('network-operator', [0]) -> 3;
-reserved_objectid('identified-organization', [0]) -> 4;
-
-reserved_objectid(iso, []) -> 1;
-%% arcs below "iso", note that number 1 is not used
-reserved_objectid('standard', [1]) -> 0;
-reserved_objectid('member-body', [1]) -> 2;
-reserved_objectid('identified-organization', [1]) -> 3;
-
-reserved_objectid('joint-iso-itu-t', []) -> 2;
-reserved_objectid('joint-iso-ccitt', []) -> 2;
-
-reserved_objectid(_, _) -> false.
-
+check_oid(_, _, _) ->
+ throw(false).
check_objectdescriptor(_, asn1_DEFAULT) ->
true;
@@ -262,21 +177,6 @@ check_real(R, R) ->
check_real(_, _) ->
throw({error,{not_implemented_yet,check_real}}).
-check_enum(_, asn1_DEFAULT, _) ->
- true;
-check_enum(Val, Val, _) ->
- true;
-check_enum(Int, Atom, Enumerations) when is_integer(Int), is_atom(Atom) ->
- case lists:keyfind(Atom, 1, Enumerations) of
- {_,Int} -> true;
- _ -> throw({error,{enumerated,Int,Atom}})
- end;
-check_enum(DefVal, Val, _) ->
- throw({error,{enumerated,DefVal,Val}}).
-
-
-check_restrictedstring(_, asn1_DEFAULT) ->
- true;
check_restrictedstring(Val, Val) ->
true;
check_restrictedstring([V|Rest1], [V|Rest2]) ->
@@ -295,7 +195,15 @@ check_restrictedstring({V1,V2,V3,V4}, [V1,V2,V3,V4]) ->
check_restrictedstring([V1,V2,V3,V4], {V1,V2,V3,V4}) ->
true;
%% character string list
-check_restrictedstring(V1, V2) when is_list(V1), is_tuple(V2) ->
- check_restrictedstring(V1, tuple_to_list(V2));
-check_restrictedstring(V1, V2) ->
- throw({error,{restricted,string,V1,V2}}).
+check_restrictedstring(V1, V2) when is_tuple(V1) ->
+ check_restrictedstring(tuple_to_list(V1), V2);
+check_restrictedstring(_, _) ->
+ throw(false).
+
+check_literal_sof(Value, Default) ->
+ case lists:sort(Value) of
+ Default ->
+ true;
+ _ ->
+ throw(false)
+ end.
diff --git a/lib/asn1/src/asn1rtt_per_common.erl b/lib/asn1/src/asn1rtt_per_common.erl
index 71fec411a0..0290c75a28 100644
--- a/lib/asn1/src/asn1rtt_per_common.erl
+++ b/lib/asn1/src/asn1rtt_per_common.erl
@@ -30,6 +30,7 @@
decode_big_chars/2,
decode_oid/1,decode_relative_oid/1,
encode_chars/2,encode_chars/3,
+ encode_chars_compact_map/3,
encode_chars_16bit/1,encode_big_chars/1,
encode_fragmented/2,
encode_oid/1,encode_relative_oid/1,
@@ -108,6 +109,9 @@ encode_chars(Val, NumBits) ->
encode_chars(Val, NumBits, {Lb,Tab}) ->
<< <<(enc_char(C, Lb, Tab)):NumBits>> || C <- Val >>.
+encode_chars_compact_map(Val, NumBits, {Lb,Limit}) ->
+ << <<(enc_char_cm(C, Lb, Limit)):NumBits>> || C <- Val >>.
+
encode_chars_16bit(Val) ->
L = [case C of
{0,0,A,B} -> [A,B];
@@ -383,6 +387,15 @@ enc_char(C0, Lb, Tab) ->
illegal_char_error()
end.
+enc_char_cm(C0, Lb, Limit) ->
+ C = C0 - Lb,
+ if
+ 0 =< C, C < Limit ->
+ C;
+ true ->
+ illegal_char_error()
+ end.
+
illegal_char_error() ->
error({error,{asn1,"value forbidden by FROM constraint"}}).