diff options
Diffstat (limited to 'lib/asn1')
36 files changed, 1594 insertions, 1322 deletions
diff --git a/lib/asn1/c_src/asn1_erl_nif.c b/lib/asn1/c_src/asn1_erl_nif.c index 8a0e4b1cf0..53e3aa1678 100644 --- a/lib/asn1/c_src/asn1_erl_nif.c +++ b/lib/asn1/c_src/asn1_erl_nif.c @@ -941,16 +941,31 @@ static int ber_decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char * int maybe_ret; unsigned int len = 0; unsigned int lenoflen = 0; - int indef = 0; unsigned char *tmp_out_buff; ERL_NIF_TERM term = 0, curr_head = 0; if (((in_buf[*ib_index]) & 0x80) == ASN1_SHORT_DEFINITE_LENGTH) { len = in_buf[*ib_index]; - } else if (in_buf[*ib_index] == ASN1_INDEFINITE_LENGTH - ) - indef = 1; - else /* long definite length */{ + } else if (in_buf[*ib_index] == ASN1_INDEFINITE_LENGTH) { + (*ib_index)++; + curr_head = enif_make_list(env, 0); + if (*ib_index+1 >= in_buf_len) { + return ASN1_INDEF_LEN_ERROR; + } + while (!(in_buf[*ib_index] == 0 && in_buf[*ib_index + 1] == 0)) { + maybe_ret = ber_decode(env, &term, in_buf, ib_index, in_buf_len); + if (maybe_ret <= ASN1_ERROR) { + return maybe_ret; + } + curr_head = enif_make_list_cell(env, term, curr_head); + if (*ib_index+1 >= in_buf_len) { + return ASN1_INDEF_LEN_ERROR; + } + } + enif_make_reverse_list(env, curr_head, value); + (*ib_index) += 2; /* skip the indefinite length end bytes */ + return ASN1_OK; + } else /* long definite length */{ lenoflen = (in_buf[*ib_index] & 0x7f); /*length of length */ if (lenoflen > (in_buf_len - (*ib_index + 1))) return ASN1_LEN_ERROR; @@ -965,23 +980,7 @@ static int ber_decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char * if (len > (in_buf_len - (*ib_index + 1))) return ASN1_VALUE_ERROR; (*ib_index)++; - if (indef == 1) { /* in this case it is desireably to check that indefinite length - end bytes exist in inbuffer */ - curr_head = enif_make_list(env, 0); - while (!(in_buf[*ib_index] == 0 && in_buf[*ib_index + 1] == 0)) { - if (*ib_index >= in_buf_len) - return ASN1_INDEF_LEN_ERROR; - - if ((maybe_ret = ber_decode(env, &term, in_buf, ib_index, in_buf_len)) - <= ASN1_ERROR - ) - return maybe_ret; - curr_head = enif_make_list_cell(env, term, curr_head); - } - enif_make_reverse_list(env, curr_head, value); - (*ib_index) += 2; /* skip the indefinite length end bytes */ - } else if (form == ASN1_CONSTRUCTED) - { + if (form == ASN1_CONSTRUCTED) { int end_index = *ib_index + len; if (end_index > in_buf_len) return ASN1_LEN_ERROR; diff --git a/lib/asn1/doc/src/asn1_ug.xml b/lib/asn1/doc/src/asn1_ug.xml index 020e58c615..8b33497dd3 100644 --- a/lib/asn1/doc/src/asn1_ug.xml +++ b/lib/asn1/doc/src/asn1_ug.xml @@ -1390,7 +1390,7 @@ GENERAL-PROCEDURES GENERAL-PROCEDURE ::= { instance, if a Type is used in a definition with certain purpose, one want the type-name to express the intention. This can be done with parameterization.</p> - <p>When many types (or an other ASN.1 entity) only differs in some + <p>When many types (or another ASN.1 entity) only differs in some minor cases, but the structure of the types are similar, only one general type can be defined and the differences may be supplied through parameters. </p> diff --git a/lib/asn1/doc/src/notes.xml b/lib/asn1/doc/src/notes.xml index cb89bb298b..a7032737bd 100644 --- a/lib/asn1/doc/src/notes.xml +++ b/lib/asn1/doc/src/notes.xml @@ -31,6 +31,47 @@ <p>This document describes the changes made to the asn1 application.</p> +<section><title>Asn1 3.0.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Several problems where the ASN.1 compiler would crash + when attempting to compile correct specifications have + been corrected.</p> + <p> + Own Id: OTP-12125</p> + </item> + <item> + <p> + Robustness when decoding incorrect BER messages has been + improved.</p> + <p> + Own Id: OTP-12145</p> + </item> + </list> + </section> + +</section> + +<section><title>Asn1 3.0.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The ASN.1 compiler now generates code that don't trigger + Dialyzer warnings. Along the way, a few minor bugs were + fixed.</p> + <p> + Own Id: OTP-11372 Aux Id: seq12397 </p> + </item> + </list> + </section> + +</section> + <section><title>Asn1 3.0</title> <section><title>Fixed Bugs and Malfunctions</title> 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_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 8470e5a1b4..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. @@ -2430,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 e788aa5c6c..5d8740b92e 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() -> @@ -549,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), @@ -950,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. @@ -1277,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') -> @@ -1803,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 @@ -2292,22 +2304,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) -> @@ -2689,20 +2702,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); @@ -2735,9 +2748,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} -> @@ -2915,8 +2928,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 @@ -2942,6 +2954,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); @@ -2989,9 +3011,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} = @@ -3372,23 +3394,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 @@ -3595,109 +3611,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{}) -> @@ -3709,11 +3670,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, @@ -4546,55 +4508,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 @@ -6760,6 +6710,8 @@ format_error({illegal_instance_of,Class}) -> [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}) -> @@ -7006,7 +6958,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 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 44b050e59d..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]), @@ -1465,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 [] -> @@ -1683,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) -> @@ -1901,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"}}). diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl index 782217ed2d..888339a4d2 100644 --- a/lib/asn1/test/asn1_SUITE.erl +++ b/lib/asn1/test/asn1_SUITE.erl @@ -50,13 +50,14 @@ all() -> {group, performance}]. groups() -> - [{compile, parallel([]), + Parallel = asn1_test_lib:parallel(), + [{compile, Parallel, [c_syntax, c_string, c_implicit_before_choice, constraint_equivalence]}, - {ber, parallel([]), + {ber, Parallel, [ber_choiceinseq, % Uses 'SOpttest' ber_optional]}, @@ -65,7 +66,7 @@ groups() -> {appup_test, [], [{asn1_appup_test, all}]}, - {parallel, parallel([]), + {parallel, Parallel, [cover, xref, {group, ber}, @@ -133,14 +134,13 @@ groups() -> testChoiceIndefinite, per_open_type, testInfObjectClass, - testParameterizedInfObj, + testParam, testFragmented, testMergeCompile, testobj, testDeepTConstr, testExport, testImport, - testParamBasic, testDER, testDEFAULT, testMvrasn6, @@ -173,13 +173,6 @@ groups() -> testTimer_per, testTimer_uper]}]. -parallel(Options) -> - case erlang:system_info(smp_support) andalso - erlang:system_info(schedulers) > 1 of - true -> [parallel|Options]; - false -> Options - end. - %%------------------------------------------------------------------------------ %% Init/end %%------------------------------------------------------------------------------ @@ -428,14 +421,12 @@ testMultipleLevels(Config, Rule, Opts) -> asn1_test_lib:compile("MultipleLevels", Config, [Rule|Opts]), testMultipleLevels:main(Rule). -testDef(Config) -> test(Config, fun testDef/3). -testDef(Config, Rule, Opts) -> - asn1_test_lib:compile("Def", Config, [Rule|Opts]), - testDef:main(Rule). - testDEFAULT(Config) -> test(Config, fun testDEFAULT/3, [ber,{ber,[der]},per,uper]). testDEFAULT(Config, Rule, Opts) -> + asn1_test_lib:compile_all(["Def","Default"], Config, [Rule|Opts]), + testDef:main(Rule), + testSeqSetDefaultVal:main(Rule, Opts), asn1_test_lib:compile_all(["Def","Default"], Config, [legacy_erlang_types,Rule|Opts]), testDef:main(Rule), @@ -528,12 +519,6 @@ testSetDefault(Config, Rule, Opts) -> asn1_test_lib:compile("SetDefault", Config, [Rule|Opts]), testSetDefault:main(Rule). -testParamBasic(Config) -> - test(Config, fun testParamBasic/3, [ber,{ber,[der]},per,uper]). -testParamBasic(Config, Rule, Opts) -> - asn1_test_lib:compile("ParamBasic", Config, [Rule|Opts]), - testParamBasic:main(Rule). - testSetOptional(Config) -> test(Config, fun testSetOptional/3). testSetOptional(Config, Rule, Opts) -> asn1_test_lib:compile("SetOptional", Config, [Rule|Opts]), @@ -766,11 +751,12 @@ testInfObjectClass(Config, Rule, Opts) -> testInfObjectClass:main(Rule), testInfObj:main(Rule). -testParameterizedInfObj(Config) -> - test(Config, fun testParameterizedInfObj/3). -testParameterizedInfObj(Config, Rule, Opts) -> - Files = ["Param","Param2"], +testParam(Config) -> + test(Config, fun testParam/3, [ber,{ber,[der]},per,uper]). +testParam(Config, Rule, Opts) -> + Files = ["ParamBasic","Param","Param2"], asn1_test_lib:compile_all(Files, Config, [Rule|Opts]), + testParamBasic:main(Rule), testParameterizedInfObj:main(Config, Rule), asn1_test_lib:compile("Param", Config, [legacy_erlang_types,Rule|Opts]), diff --git a/lib/asn1/test/asn1_SUITE_data/Constraints.py b/lib/asn1/test/asn1_SUITE_data/Constraints.py index c3b3aebd6d..3495cd841b 100644 --- a/lib/asn1/test/asn1_SUITE_data/Constraints.py +++ b/lib/asn1/test/asn1_SUITE_data/Constraints.py @@ -16,6 +16,7 @@ SemiConstrained ::= INTEGER (100..MAX) NegSemiConstrained ::= INTEGER (-128..MAX) SemiConstrainedExt ::= INTEGER (42..MAX, ...) NegSemiConstrainedExt ::= INTEGER (-128..MAX, ...) +SemiNamed ::= INTEGER {a(100), b(200)} (100..MAX) -- Extensions -- LongLongExt ::= INTEGER (0..18446744073709551615, ..., -5000..-1) Range256to65536Ext ::= INTEGER (256..65536, ..., 1000000..9000000) @@ -65,10 +66,12 @@ Wednesday ::= Day(wednesday) Thing ::= INTEGER {fred (0),fred2 (1),fred3 (2)} - - AnotherThing ::= Thing (fred | fred2) +OneMoreThing ::= INTEGER {wilma(0), fred(1), betty(3), barney(2)} +OneMoreThing-1 ::= OneMoreThing (wilma | fred) +OneMoreThing-2 ::= OneMoreThing (fred | barney) + I ::= INTEGER (0|15..269) -- OTP-5457 X1 ::= INTEGER (1..4 | 8 | 10 | 20) -- OTP-9946 diff --git a/lib/asn1/test/asn1_SUITE_data/Default.asn b/lib/asn1/test/asn1_SUITE_data/Default.asn index 168ce50bb2..b91660381a 100644 --- a/lib/asn1/test/asn1_SUITE_data/Default.asn +++ b/lib/asn1/test/asn1_SUITE_data/Default.asn @@ -25,6 +25,10 @@ SeqBS ::= SEQUENCE { e BIT STRING DEFAULT '01011010'B } +SeqBS2 ::= SEQUENCE { + bs BIT STRING {a(0), z(25)} DEFAULT '101'B +} + SetBS ::= SET { a BIT STRING DEFAULT '1010110'B, b BIT STRING DEFAULT 'A8A'H, @@ -156,4 +160,23 @@ four INTEGER ::= 4 cr IA5String ::= {0,13} +SeqNamedInts ::= SEQUENCE { + i1 INTEGER {first(0), last(31)} DEFAULT 15, + i2 INTEGER {first(0), last(31)} DEFAULT 31 +} + +S5 ::= SEQUENCE { + s3 S3 DEFAULT {}, + so SEQUENCE OF OBJECT IDENTIFIER DEFAULT { + {itu-t question 999}, + {itu-t question 555} + }, + soe SEQUENCE OF OBJECT IDENTIFIER DEFAULT { } +} + +SOI ::= SEQUENCE { + soi SEQUENCE OF OBJECT IDENTIFIER + DEFAULT { {iso member-body f(250) 9 55}, {iso member-body f(250) 3 4} } +} + END diff --git a/lib/asn1/test/asn1_SUITE_data/InfObj.asn b/lib/asn1/test/asn1_SUITE_data/InfObj.asn index 880e81c3b1..719119f418 100644 --- a/lib/asn1/test/asn1_SUITE_data/InfObj.asn +++ b/lib/asn1/test/asn1_SUITE_data/InfObj.asn @@ -255,6 +255,51 @@ Multiple-Optionals ::= SEQUENCE { t3 [2] MULTIPLE-OPTIONALS.&T3 ({Multiple-Optionals-Set}{@id}) OPTIONAL } +-- Test different ways of constructing object sets. + +OBJECT-SET-TEST ::= CLASS { + &id INTEGER UNIQUE, + &Type +} WITH SYNTAX { + &id IS &Type +} + +ObjectSetTest{OBJECT-SET-TEST:ObjectSet} ::= + SEQUENCE { + id OBJECT-SET-TEST.&id ({ObjectSet}), + type OBJECT-SET-TEST.&Type ({ObjectSet}{@id}) + } + +ost1 OBJECT-SET-TEST ::= { 1 IS BIT STRING } +ost2 OBJECT-SET-TEST ::= { 2 IS OCTET STRING } +ost3 OBJECT-SET-TEST ::= { 3 IS ENUMERATED {donald,scrooge} } +ost4 OBJECT-SET-TEST ::= { 4 IS BOOLEAN } +ost5 OBJECT-SET-TEST ::= { 5 IS INTEGER (0..15) } + +Ost12 OBJECT-SET-TEST ::= { ost1 | ost2 } +Ost123 OBJECT-SET-TEST ::= { ost3 | Ost12 } +Ost1234 OBJECT-SET-TEST ::= { Ost123 | ost4 } +Ost45 OBJECT-SET-TEST ::= { ost4 | ost5 } +Ost12345 OBJECT-SET-TEST ::= { Ost123 | Ost45 } + +OstSeq12 ::= ObjectSetTest{ {Ost12} } +OstSeq123 ::= ObjectSetTest{ {Ost123} } +OstSeq1234 ::= ObjectSetTest{ {Ost1234} } +OstSeq45 ::= ObjectSetTest{ {Ost45} } +OstSeq12345 ::= ObjectSetTest{ {Ost12345} } + +ExOst12 OBJECT-SET-TEST ::= { ost1, ..., ost2 } +ExOst123 OBJECT-SET-TEST ::= { ost3, ..., ExOst12 } +--ExOst1234 OBJECT-SET-TEST ::= { ExOst123, ..., ost4 } +ExOst45 OBJECT-SET-TEST ::= { ost4, ..., ost5 } +ExOst12345 OBJECT-SET-TEST ::= { ExOst123, ..., ExOst45 } + +ExOstSeq12 ::= ObjectSetTest{ {ExOst12} } +ExOstSeq123 ::= ObjectSetTest{ {ExOst123} } +--ExOstSeq1234 ::= ObjectSetTest{ {ExOst1234} } +ExOstSeq45 ::= ObjectSetTest{ {ExOst45} } +ExOstSeq12345 ::= ObjectSetTest{ {ExOst12345} } + END diff --git a/lib/asn1/test/asn1_SUITE_data/ParamBasic.asn1 b/lib/asn1/test/asn1_SUITE_data/ParamBasic.asn1 index 491bdf8956..68fc782f33 100644 --- a/lib/asn1/test/asn1_SUITE_data/ParamBasic.asn1 +++ b/lib/asn1/test/asn1_SUITE_data/ParamBasic.asn1 @@ -20,4 +20,26 @@ T21 ::= General2{PrintableString} T22 ::= General2{BIT STRING} + +-- +-- Test a class parameter that is the governor for another parameter. +-- + +AlgorithmIdentifier{ALGORITHM-TYPE, ALGORITHM-TYPE:AlgorithmSet} ::= + SEQUENCE { + algorithm ALGORITHM-TYPE.&id ({AlgorithmSet}), + type ALGORITHM-TYPE.&Type ({AlgorithmSet}{@algorithm}) + } + +AnAlgorithm ::= AlgorithmIdentifier{ SIGNATURE-ALGORITHM, + { {KEY 1 CONTAINING INTEGER} | + {KEY 2 CONTAINING BOOLEAN} } } + +SIGNATURE-ALGORITHM ::= CLASS { + &id INTEGER UNIQUE, + &Type +} WITH SYNTAX { + KEY &id CONTAINING &Type +} + END diff --git a/lib/asn1/test/asn1_SUITE_data/Set.py b/lib/asn1/test/asn1_SUITE_data/Set.py index 4062f6b804..3928004e6b 100644 --- a/lib/asn1/test/asn1_SUITE_data/Set.py +++ b/lib/asn1/test/asn1_SUITE_data/Set.py @@ -80,8 +80,8 @@ SetOpt3 ::= SET SetIn ::= SET { - boolIn BOOLEAN, - intIn INTEGER + boolIn BOOLEAN OPTIONAL, + intIn INTEGER OPTIONAL } diff --git a/lib/asn1/test/asn1_app_test.erl b/lib/asn1/test/asn1_app_test.erl index 1225e36778..d800846b3f 100644 --- a/lib/asn1/test/asn1_app_test.erl +++ b/lib/asn1/test/asn1_app_test.erl @@ -134,13 +134,13 @@ get_ebin_mods(App) -> check_asn1ct_modules(Extra) -> ASN1CTMods = [asn1ct,asn1ct_check,asn1_db,asn1ct_pretty_format, - asn1ct_gen,asn1ct_gen_per,asn1ct_gen_per_rt2ct, + asn1ct_gen,asn1ct_gen_check,asn1ct_gen_per, asn1ct_name,asn1ct_constructed_per,asn1ct_constructed_ber, asn1ct_gen_ber,asn1ct_constructed_ber_bin_v2, asn1ct_gen_ber_bin_v2,asn1ct_value, asn1ct_tok,asn1ct_parser2,asn1ct_table, asn1ct_imm,asn1ct_func,asn1ct_rtt, - asn1ct_eval_ext,asn1ct_eval_per,asn1ct_eval_uper], + asn1ct_eval_ext], case Extra -- ASN1CTMods of [] -> ok; diff --git a/lib/asn1/test/asn1_test_lib.erl b/lib/asn1/test/asn1_test_lib.erl index 417380159e..da07cd1118 100644 --- a/lib/asn1/test/asn1_test_lib.erl +++ b/lib/asn1/test/asn1_test_lib.erl @@ -21,19 +21,72 @@ -export([compile/3,compile_all/3,compile_erlang/3, hex_to_bin/1, + parallel/0, roundtrip/3,roundtrip/4,roundtrip_enc/3,roundtrip_enc/4]). -include_lib("test_server/include/test_server.hrl"). +run_dialyzer() -> + false. + compile(File, Config, Options) -> compile_all([File], Config, Options). compile_all(Files, Config, Options) -> DataDir = ?config(data_dir, Config), CaseDir = ?config(case_dir, Config), - [compile_file(filename:join(DataDir, F), [{outdir, CaseDir}|Options]) + [compile_file(filename:join(DataDir, F), [{outdir, CaseDir}, + debug_info|Options]) || F <- Files], + dialyze(Files, Options), ok. +parallel() -> + case erlang:system_info(schedulers) > 1 andalso not run_dialyzer() of + true -> [parallel]; + false -> [] + end. + +dialyze(Files, Options) -> + case not run_dialyzer() orelse lists:member(abs, Options) of + true -> ok; + false -> dialyze(Files) + end. + +dialyze(Files) -> + Beams0 = [code:which(module(F)) || F <- Files], + Beams = [code:which(asn1rt_nif)|Beams0], + case dialyzer:run([{files,Beams}, + {warnings,[no_improper_lists]}, + {get_warnings,true}]) of + [] -> + ok; + [_|_]=Ws -> + io:put_chars([[B,$\n] || B <- Beams]), + io:put_chars([dialyzer:format_warning(W) || W <- Ws]), + error(dialyzer_warnings) + end. + +module(F0) -> + F1 = filename:basename(F0), + F2 = case filename:extension(F1) of + ".asn" -> + filename:rootname(F1); + ".asn1" -> + filename:rootname(F1); + ".py" -> + filename:rootname(F1); + "" -> + F1 + end, + F = case filename:extension(F2) of + ".set" -> + filename:rootname(F2); + "" -> + F2 + end, + list_to_atom(F). +%% filename:join(CaseDir, F ++ ".beam"). + compile_file(File, Options) -> try ok = asn1ct:compile(File, [warnings_as_errors|Options]) @@ -59,6 +112,7 @@ roundtrip(Mod, Type, Value) -> roundtrip(Mod, Type, Value, ExpectedValue) -> {ok,Encoded} = Mod:encode(Type, Value), {ok,ExpectedValue} = Mod:decode(Type, Encoded), + test_ber_indefinite(Mod, Type, Encoded, ExpectedValue), ok. roundtrip_enc(Mod, Type, Value) -> @@ -67,6 +121,7 @@ roundtrip_enc(Mod, Type, Value) -> roundtrip_enc(Mod, Type, Value, ExpectedValue) -> {ok,Encoded} = Mod:encode(Type, Value), {ok,ExpectedValue} = Mod:decode(Type, Encoded), + test_ber_indefinite(Mod, Type, Encoded, ExpectedValue), Encoded. %%% @@ -76,3 +131,52 @@ roundtrip_enc(Mod, Type, Value, ExpectedValue) -> hex2num(C) when $0 =< C, C =< $9 -> C - $0; hex2num(C) when $A =< C, C =< $F -> C - $A + 10; hex2num(C) when $a =< C, C =< $f -> C - $a + 10. + +test_ber_indefinite(Mod, Type, Encoded, ExpectedValue) -> + case Mod:encoding_rule() of + ber -> + Indefinite = iolist_to_binary(ber_indefinite(Encoded)), + {ok,ExpectedValue} = Mod:decode(Type, Indefinite); + _ -> + ok + end. + +%% Rewrite all definite lengths for constructed values to an +%% indefinite length. +ber_indefinite(Bin0) -> + case ber_get_tag(Bin0) of + done -> + []; + primitive -> + Bin0; + {constructed,Tag,Bin1} -> + {Len,Bin2} = ber_get_len(Bin1), + <<Val0:Len/binary,Bin/binary>> = Bin2, + Val = iolist_to_binary(ber_indefinite(Val0)), + [<<Tag/binary,16#80,Val/binary,0,0>>|ber_indefinite(Bin)] + end. + +ber_get_tag(<<>>) -> + done; +ber_get_tag(<<_:2,0:1,_:5,_/binary>>) -> + primitive; +ber_get_tag(<<_:2,1:1,_:5,_/binary>>=Bin0) -> + TagLen = ber_tag_length(Bin0), + <<Tag:TagLen/binary,Bin/binary>> = Bin0, + {constructed,Tag,Bin}. + +ber_tag_length(<<_:3,2#11111:5,T/binary>>) -> + ber_tag_length_1(T, 1); +ber_tag_length(_) -> + 1. + +ber_tag_length_1(<<1:1,_:7,T/binary>>, N) -> + ber_tag_length_1(T, N+1); +ber_tag_length_1(<<0:1,_:7,_/binary>>, N) -> + N+1. + +ber_get_len(<<0:1,L:7,T/binary>>) -> + {L,T}; +ber_get_len(<<1:1,Octets:7,T0/binary>>) -> + <<L:Octets/unit:8,T/binary>> = T0, + {L,T}. diff --git a/lib/asn1/test/ber_decode_error.erl b/lib/asn1/test/ber_decode_error.erl index 8be92292ee..6fd2450c62 100644 --- a/lib/asn1/test/ber_decode_error.erl +++ b/lib/asn1/test/ber_decode_error.erl @@ -51,4 +51,18 @@ run([]) -> {error,{asn1,{invalid_value,_}}} = (catch 'Constructed':decode('I', <<8,7>>)), + %% Short indefinite length. Make sure that the decoder doesn't look + %% beyond the end of binary when looking for a 0,0 terminator. + {error,{asn1,{invalid_length,_}}} = + (catch 'Constructed':decode('S', sub(<<8,16#80,0,0>>, 3))), + {error,{asn1,{invalid_length,_}}} = + (catch 'Constructed':decode('S', sub(<<8,16#80,0,0>>, 2))), + {error,{asn1,{invalid_length,_}}} = + (catch 'Constructed':decode('S', sub(<<40,16#80,1,1,255,0,0>>, 6))), + {error,{asn1,{invalid_length,_}}} = + (catch 'Constructed':decode('S', sub(<<40,16#80,1,1,255,0,0>>, 5))), ok. + +sub(Bin, Bytes) -> + <<B:Bytes/binary,_/binary>> = Bin, + B. diff --git a/lib/asn1/test/error_SUITE.erl b/lib/asn1/test/error_SUITE.erl index 8a0414708d..1edd60f7c8 100644 --- a/lib/asn1/test/error_SUITE.erl +++ b/lib/asn1/test/error_SUITE.erl @@ -20,7 +20,8 @@ -module(error_SUITE). -export([suite/0,all/0,groups/0, already_defined/1,bitstrings/1,enumerated/1, - imports/1,instance_of/1,integers/1,objects/1,values/1]). + imports/1,instance_of/1,integers/1,objects/1, + parameterization/1,values/1]). -include_lib("test_server/include/test_server.hrl"). @@ -38,6 +39,7 @@ groups() -> instance_of, integers, objects, + parameterization, values]}]. parallel() -> @@ -219,6 +221,19 @@ objects(Config) -> } = run(P, Config), ok. +parameterization(Config) -> + M = 'Parameterization', + P = {M, + <<"Parameterization DEFINITIONS AUTOMATIC TAGS ::= BEGIN\n" + " NotUppercase{lowercase} ::= INTEGER (lowercase)\n" + "END\n">>}, + {error, + [{structured_error,{'Parameterization',2},asn1ct_check, + {illegal_typereference,lowercase}} + ] + } = run(P, Config), + ok. + values(Config) -> M = 'Values', P = {M, diff --git a/lib/asn1/test/testInfObj.erl b/lib/asn1/test/testInfObj.erl index 311595cfda..37c134b1b9 100644 --- a/lib/asn1/test/testInfObj.erl +++ b/lib/asn1/test/testInfObj.erl @@ -118,7 +118,41 @@ main(_Erule) -> roundtrip('InfObj', 'Multiple-Optionals', {'Multiple-Optionals',1,42,true,asn1_NOVALUE}), roundtrip('InfObj', 'Multiple-Optionals', - {'Multiple-Optionals',1,asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE}). + {'Multiple-Optionals',1,asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE}), + + test_objset('OstSeq12', [1,2]), + test_objset('OstSeq123', [1,2,3]), + test_objset('OstSeq1234', [1,2,3,4]), + test_objset('OstSeq45', [4,5]), + test_objset('OstSeq12345', [1,2,3,4,5]), + + test_objset('ExOstSeq12', [1,2]), + test_objset('ExOstSeq123', [1,2,3]), + %%test_objset('ExOstSeq1234', [1,2,3,4]), + test_objset('ExOstSeq45', [4,5]), + test_objset('ExOstSeq12345', [1,2,3,4,5]), + + ok. + +test_objset(Type, Keys) -> + _ = [test_object(Type, Key) || Key <- Keys], + _ = [(catch test_object(Type, Key)) || + Key <- lists:seq(1, 5) -- Keys], + ok. + +test_object(T, 1) -> + roundtrip('InfObj', T, {T,1,<<42:7>>}); +test_object(T, 2) -> + roundtrip('InfObj', T, {T,2,<<"abc">>}); +test_object(T, 3) -> + roundtrip('InfObj', T, {T,3,donald}), + roundtrip('InfObj', T, {T,3,scrooge}); +test_object(T, 4) -> + roundtrip('InfObj', T, {T,4,true}), + roundtrip('InfObj', T, {T,4,false}); +test_object(T, 5) -> + roundtrip('InfObj', T, {T,5,0}), + roundtrip('InfObj', T, {T,5,15}). roundtrip(M, T, V) -> asn1_test_lib:roundtrip(M, T, V). diff --git a/lib/asn1/test/testNBAPsystem.erl b/lib/asn1/test/testNBAPsystem.erl index 57cb483374..e37e22163a 100644 --- a/lib/asn1/test/testNBAPsystem.erl +++ b/lib/asn1/test/testNBAPsystem.erl @@ -79,13 +79,14 @@ powerRaiseLimit, dLPowerAveragingWindowSize, 'iE-Extensions' = asn1_NOVALUE}). compile(Config, Options) -> - [asn1_test_lib:compile(filename:join([nbapsystem, M]), Config, Options) - || M <- ["NBAP-CommonDataTypes.asn", - "NBAP-IEs.asn", - "NBAP-PDU-Contents.asn", - "NBAP-PDU-Discriptions.asn", - "NBAP-Constants.asn", - "NBAP-Containers.asn"]], + Fs = [filename:join("nbapsystem", M) || + M <- ["NBAP-CommonDataTypes.asn", + "NBAP-IEs.asn", + "NBAP-PDU-Contents.asn", + "NBAP-PDU-Discriptions.asn", + "NBAP-Constants.asn", + "NBAP-Containers.asn"]], + asn1_test_lib:compile_all(Fs, Config, Options), ok. diff --git a/lib/asn1/test/testParamBasic.erl b/lib/asn1/test/testParamBasic.erl index 3db89ca174..39f7947e8d 100644 --- a/lib/asn1/test/testParamBasic.erl +++ b/lib/asn1/test/testParamBasic.erl @@ -43,6 +43,9 @@ main(Rules) -> #'T12'{number=11,string = <<10:4>>}); _ -> ok end, + roundtrip('AnAlgorithm', {'AnAlgorithm',1,42}), + roundtrip('AnAlgorithm', {'AnAlgorithm',2,true}), + roundtrip('AnAlgorithm', {'AnAlgorithm',2,false}), ok. roundtrip(Type, Value) -> diff --git a/lib/asn1/test/testSeqSetDefaultVal.erl b/lib/asn1/test/testSeqSetDefaultVal.erl index 79992a0a94..c3d9ce33b7 100644 --- a/lib/asn1/test/testSeqSetDefaultVal.erl +++ b/lib/asn1/test/testSeqSetDefaultVal.erl @@ -36,6 +36,7 @@ c = asn1_DEFAULT, d = asn1_DEFAULT, e = asn1_DEFAULT}). +-record('SeqBS2',{bs = asn1_DEFAULT}). -record('SetBS',{a = asn1_DEFAULT, b = asn1_DEFAULT, c = asn1_DEFAULT, @@ -93,6 +94,13 @@ b = asn1_DEFAULT}). -record('S4_b',{ba = asn1_DEFAULT, bb = asn1_DEFAULT}). +-record('SeqNamedInts', + {i1 = asn1_DEFAULT, + i2 = asn1_DEFAULT}). +-record('S5',{s3 = asn1_DEFAULT, + so = asn1_DEFAULT, + soe = asn1_DEFAULT}). +-record('SOI', {soi = asn1_DEFAULT}). main(ber, []) -> %% Nothing to test because plain BER will only use @@ -105,7 +113,11 @@ main(Rule, Opts) -> case {Rule,Opts} of {ber,[der]} -> - der(); + der(), + case 'Default':legacy_erlang_types() of + false -> der_new_types(); + true -> der_legacy() + end; {_,_} -> ok end, @@ -118,45 +130,45 @@ main(Rule, Opts) -> {#'SeqBS'{}, [{#'SeqBS'.a, - [asn1_DEFAULT, - 2#0110101, + [asn1_DEFAULT, %Always. + <<1:1,0:1,1:1,0:1,1:1,1:1,0:1>>], + [2#0110101, %Legacy only. [1,0,1,0,1,1,0], - {1,<<16#AC>>}, - <<1:1,0:1,1:1,0:1,1:1,1:1,0:1>>]}, + {1,<<16#AC>>}]}, {#'SeqBS'.b, [asn1_DEFAULT, - 2#10100010101, + <<16#A8:8,16#A:4>>], + [2#10100010101, [1,0,1,0,1,0,0,0,1,0,1,0], - {4,<<16#A8,16#A0>>}, - <<16#A8:8,16#A:4>>]}, + {4,<<16#A8,16#A0>>}]}, {#'SeqBS'.c, [asn1_DEFAULT, [second], - [0,1], - {6,<<0:1,1:1,0:6>>}, - <<1:2>>]}, + <<1:2>>], + [[0,1], + {6,<<0:1,1:1,0:6>>}]}, {#'SeqBS'.c, %Zeroes on the right [asn1_DEFAULT, [second], - [0,1,0,0,0], - {4,<<0:1,1:1,0:6>>}, - <<1:2,0:17>>]}, + <<1:2,0:17>>], + [[0,1,0,0,0], + {4,<<0:1,1:1,0:6>>}]}, {#'SeqBS'.d, [asn1_DEFAULT, - 2#1001, + <<2#1001:4>>], + [2#1001, [1,0,0,1], - {4,<<2#1001:4,0:4>>}, - <<2#1001:4>>]}, + {4,<<2#1001:4,0:4>>}]}, {#'SeqBS'.e, [asn1_DEFAULT, - [0,1,0,1,1,0,1,0], - {0,<<2#01011010:8>>}, - <<2#01011010:8>>]}, + <<2#01011010:8>>], + [[0,1,0,1,1,0,1,0], + {0,<<2#01011010:8>>}]}, %% Not EQUAL to DEFAULT. {#'SeqBS'.b, + [<<6:3>>], [[1,1,0], %Not equal to DEFAULT - {5,<<6:3,0:5>>}, - <<6:3>>]} + {5,<<6:3,0:5>>}]} ]}, {#'SeqOS'{}, @@ -170,15 +182,14 @@ main(Rule, Opts) -> {1,2,14,15}]}, {#'SeqOI'.b, [asn1_DEFAULT, -%% {iso,'member-body',250,3,4}, + %% {iso,'member-body',250,3,4}, {1,2,250,3,4}]}, {#'SeqOI'.c, [asn1_DEFAULT, -%% {iso,standard,8571,2,250,4}, + %% {iso,standard,8571,2,250,4}, {1,0,8571,2,250,4}]}]} ], - io:format("~p\n", [Ts]), - R0 = [[consistency(Rec, Pos, Vs) || {Pos,Vs} <- Fs] || {Rec,Fs} <- Ts], + R0 = [[consistency(Rec, PosVs) || PosVs <- Fs] || {Rec,Fs} <- Ts], case lists:flatten(R0) of [] -> ok; @@ -187,8 +198,20 @@ main(Rule, Opts) -> ?t:fail() end. -consistency(Rec0, Pos, [V|Vs]) -> +legacy_filter({_,_}=Keep) -> + Keep; +legacy_filter({Rec,Standard,Legacy}) -> + case 'Default':legacy_erlang_types() of + false -> + {Rec,Standard}; + true -> + {Rec,Standard++Legacy} + end. + +consistency(Rec0, PosVs) -> + {Pos,[V|Vs]=AllVs} = legacy_filter(PosVs), T = element(1, Rec0), + io:format("~p: ~p\n", [T,AllVs]), Rec = setelement(Pos, Rec0, V), {ok,Enc} = 'Default':encode(T, Rec), {ok,_SmokeTest} = 'Default':decode(T, Enc), @@ -206,7 +229,7 @@ consistency_1([V|Vs], Rec0, Pos, Enc) -> consistency_1([], _, _, _) -> []. der() -> - io:put_chars("Peforming DER-specific tests..."), + io:put_chars("Performing DER-specific tests..."), roundtrip(<<48,0>>, 'SeqInts', #'SeqInts'{a=asn1_DEFAULT,b=asn1_DEFAULT, @@ -227,98 +250,6 @@ der() -> #'SetInts'{a=1,b=-1,c=three,d=1}, #'SetInts'{a=1,b=-1,c=3,d=1}), - - roundtrip(<<48,0>>, - 'SeqBS', - #'SeqBS'{a=2#0110101, - b=2#010100010101, - c=[second], - d=[1,0,0,1]}, - #'SeqBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>, - c=[second], d = <<2#1001:4>>, - e = <<2#01011010:8>>}), - roundtrip(<<48,0>>, - 'SeqBS', - #'SeqBS'{a=[1,0,1,0,1,1,0], - b=[1,0,1,0,1,0,0,0,1,0,1,0], - c={5,<<64>>}, - d=2#1001}, - #'SeqBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>, - c=[second], d = <<2#1001:4>>, - e = <<2#01011010:8>>}), - roundtrip(<<48,3,131,1,0>>, - 'SeqBS', - #'SeqBS'{a=[1,0,1,0,1,1,0], - b=[1,0,1,0,1,0,0,0,1,0,1,0], - c={5,<<64>>}, - d=0}, - #'SeqBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>, - c=[second], d = <<>>, - e = <<2#01011010:8>>}), - roundtrip(<<48,3,131,1,0>>, - 'SeqBS', - #'SeqBS'{a = <<1:1,0:1,1:1,0:1,1:1,1:1,0:1>>, - b = <<1:1,0:1,1:1,0:1,1:1,0:1,0:1,0:1,1:1,0:1,1:1,0:1>>, - c = <<2:3>>, - d=0, - e = <<16#5A:8>>}, - #'SeqBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>, - c=[second], d = <<>>, - e = <<2#01011010:8>>}), - - %% None of the default values are used. - roundtrip(<<48,19,128,2,7,128,129,2,5,64,130,2,5,32,131,1,0,132,2,5,224>>, - 'SeqBS', - #'SeqBS'{a = <<1:1>>, - b = {5,<<64>>}, - c = [third], - d = 0, - e = <<7:3>>}, - #'SeqBS'{a = <<1:1>>, - b = <<2:3>>, - c = [third], - d = <<>>, - e = <<7:3>>}), - - roundtrip(<<49,0>>, - 'SetBS', - #'SetBS'{a=2#0110101, - b=2#010100010101, - c=[second], - d=[1,0,0,1]}, - #'SetBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>, - c=[second], d = <<2#1001:4>>}), - roundtrip(<<49,0>>, - 'SetBS', - #'SetBS'{a=[1,0,1,0,1,1,0], - b=[1,0,1,0,1,0,0,0,1,0,1,0], - c={5,<<64>>}, - d=9}, - #'SetBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>, - c=[second], d = <<2#1001:4>>}), - roundtrip(<<49,3,131,1,0>>, - 'SetBS', - #'SetBS'{a=[1,0,1,0,1,1,0], - b=[1,0,1,0,1,0,0,0,1,0,1,0], - c={5,<<64>>}, - d=0}, - #'SetBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>, - c=[second], d = <<>>}), - roundtrip(<<49,3,131,1,0>>, - 'SetBS', - #'SetBS'{a = <<1:1,0:1,1:1,0:1,1:1,1:1,0:1>>, - b = <<1:1,0:1,1:1,0:1,1:1,0:1,0:1,0:1,1:1,0:1,1:1,0:1>>, - c = <<2:3>>, - d=0}, - #'SetBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>, - c=[second], d = <<>>}), - - roundtrip(<<48,0>>, 'SeqOS', - #'SeqOS'{a = <<172>>,b = <<16#A8,16#A0>>,c='NULL'}), - - roundtrip(<<49,0>>, 'SetOS', - #'SetOS'{a = <<172>>,b = <<16#A8,16#A0>>,c='NULL'}), - roundtrip(<<48,0>>, 'SeqOI', #'SeqOI'{a={1,2,14,15}, @@ -443,6 +374,184 @@ der() -> #'S4'{a=#'S2'{a=1,b=asn1_NOVALUE},b=#'S4_b'{ba=true,bb=0}}, #'S4'{a=#'S2'{a=1,b=asn1_NOVALUE},b=#'S4_b'{ba=true,bb=0}}), + roundtrip(<<48,0>>, + 'SeqBS', + #'SeqBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>, + c=[second], d = <<2#1001:4>>, + e = <<2#01011010:8>>}), + roundtrip(<<49,0>>, + 'SetBS', + #'SetBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>, + c=[second], d = <<2#1001:4>>}), + + %% None of the default values are used. + roundtrip(<<48,19,128,2,7,128,129,2,5,64,130,2,5,32,131,1,0,132,2,5,224>>, + 'SeqBS', + #'SeqBS'{a = <<1:1>>, + b = <<2:3>>, + c = [third], + d = <<>>, + e = <<7:3>>}), + roundtrip(<<49,3,131,1,0>>, + 'SetBS', + #'SetBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>, + c=[second], d = <<>>}), + + %% SeqNamedInts + roundtrip(<<48,0>>, + 'SeqNamedInts', + #'SeqNamedInts'{i1=15,i2=31}), + roundtrip(<<48,0>>, + 'SeqNamedInts', + #'SeqNamedInts'{}, + #'SeqNamedInts'{i1=15,i2=31}), + roundtrip(<<48,0>>, + 'SeqNamedInts', + #'SeqNamedInts'{i2=last}, + #'SeqNamedInts'{i1=15,i2=31}), + roundtrip(<<48,3,128,1,0>>, + 'SeqNamedInts', + #'SeqNamedInts'{i1=first,i2=31}, + #'SeqNamedInts'{i1=first,i2=31}), + + %% S5 + roundtrip(<<48,0>>, + 'S5', + #'S5'{s3=#'S3'{a=[11,12,13], + b=[{a,11},{b,true},{c,13}], + c=[1,2,3,4], + d=[#'S2'{a=20,b=true},#'S2'{a=30,b=false}]}, + so=[{0,1,999},{0,1,555}], + soe=[]}), + roundtrip(<<48,0>>, + 'S5', + #'S5'{}, + #'S5'{s3=#'S3'{a=[11,12,13], + b=[{a,11},{b,true},{c,13}], + c=[1,2,3,4], + d=[#'S2'{a=20,b=true},#'S2'{a=30,b=false}]}, + so=[{0,1,999},{0,1,555}], + soe=[]}), + + %% SOI + roundtrip(<<48,0>>, + 'SOI', + #'SOI'{}, + #'SOI'{soi=[{1,2,250,9,55},{1,2,250,3,4}]}), + + %% SeqBS2 + roundtrip(<<48,0>>, + 'SeqBS2', + #'SeqBS2'{bs= <<16#5:3>>}), + roundtrip(<<48,0>>, + 'SeqBS2', + #'SeqBS2'{bs= <<16#5:3,0:4>>}, + #'SeqBS2'{bs= <<16#5:3>>}), + + ok. + +der_new_types() -> + io:put_chars("Performing DER-specific tests with new types..."), + + roundtrip(<<48,0>>, 'SeqOS', + #'SeqOS'{a = <<172>>,b = <<16#A8,16#A0>>,c='NULL'}), + + roundtrip(<<49,0>>, 'SetOS', + #'SetOS'{a = <<172>>,b = <<16#A8,16#A0>>,c='NULL'}), + ok. + +der_legacy() -> + io:put_chars("Performing DER-specific tests with legacy types..."), + + roundtrip(<<48,0>>, 'SeqOS', + #'SeqOS'{a=[172],b=[16#A8,16#A0],c='NULL'}), + roundtrip(<<49,0>>, 'SetOS', + #'SetOS'{a=[172],b=[16#A8,16#A0],c='NULL'}), + + roundtrip(<<48,0>>, + 'SeqBS', + #'SeqBS'{a=2#0110101, + b=2#010100010101, + c=[second], + d=[1,0,0,1]}, + #'SeqBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>, + c=[second], d = <<2#1001:4>>, + e = <<2#01011010:8>>}), + roundtrip(<<48,0>>, + 'SeqBS', + #'SeqBS'{a=[1,0,1,0,1,1,0], + b=[1,0,1,0,1,0,0,0,1,0,1,0], + c={5,<<64>>}, + d=2#1001}, + #'SeqBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>, + c=[second], d = <<2#1001:4>>, + e = <<2#01011010:8>>}), + roundtrip(<<48,3,131,1,0>>, + 'SeqBS', + #'SeqBS'{a=[1,0,1,0,1,1,0], + b=[1,0,1,0,1,0,0,0,1,0,1,0], + c={5,<<64>>}, + d=0}, + #'SeqBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>, + c=[second], d = <<>>, + e = <<2#01011010:8>>}), + roundtrip(<<48,3,131,1,0>>, + 'SeqBS', + #'SeqBS'{a = <<1:1,0:1,1:1,0:1,1:1,1:1,0:1>>, + b = <<1:1,0:1,1:1,0:1,1:1,0:1,0:1,0:1,1:1,0:1,1:1,0:1>>, + c = <<2:3>>, + d=0, + e = <<16#5A:8>>}, + #'SeqBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>, + c=[second], d = <<>>, + e = <<2#01011010:8>>}), + + %% None of the default values are used. + roundtrip(<<48,19,128,2,7,128,129,2,5,64,130,2,5,32,131,1,0,132,2,5,224>>, + 'SeqBS', + #'SeqBS'{a = <<1:1>>, + b = {5,<<64>>}, + c = [third], + d = 0, + e = <<7:3>>}, + #'SeqBS'{a = <<1:1>>, + b = <<2:3>>, + c = [third], + d = <<>>, + e = <<7:3>>}), + roundtrip(<<49,0>>, + 'SetBS', + #'SetBS'{a=2#0110101, + b=2#010100010101, + c=[second], + d=[1,0,0,1]}, + #'SetBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>, + c=[second], d = <<2#1001:4>>}), + roundtrip(<<49,0>>, + 'SetBS', + #'SetBS'{a=[1,0,1,0,1,1,0], + b=[1,0,1,0,1,0,0,0,1,0,1,0], + c={5,<<64>>}, + d=9}, + #'SetBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>, + c=[second], d = <<2#1001:4>>}), + roundtrip(<<49,3,131,1,0>>, + 'SetBS', + #'SetBS'{a=[1,0,1,0,1,1,0], + b=[1,0,1,0,1,0,0,0,1,0,1,0], + c={5,<<64>>}, + d=0}, + #'SetBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>, + c=[second], d = <<>>}), + roundtrip(<<49,3,131,1,0>>, + 'SetBS', + #'SetBS'{a = <<1:1,0:1,1:1,0:1,1:1,1:1,0:1>>, + b = <<1:1,0:1,1:1,0:1,1:1,0:1,0:1,0:1,1:1,0:1,1:1,0:1>>, + c = <<2:3>>, + d=0}, + #'SetBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>, + c=[second], d = <<>>}), + ok. roundtrip(Encoded, Type, Value) -> diff --git a/lib/asn1/test/testTcapsystem.erl b/lib/asn1/test/testTcapsystem.erl index 4979a385b2..fcc9e084e0 100644 --- a/lib/asn1/test/testTcapsystem.erl +++ b/lib/asn1/test/testTcapsystem.erl @@ -21,44 +21,42 @@ -export([compile/2]). --include_lib("test_server/include/test_server.hrl"). - compile(Config, Options) -> - [asn1_test_lib:compile(filename:join([tcapsystem, M]), Config, Options) - || M <- ["DialoguePDUs.asn", - "MAP-ApplicationContexts.asn", - "MAP-BS-Code.asn", - "MAP-CallHandlingOperations.asn", - "MAP-CH-DataTypes.asn", - "MAP-CommonDataTypes.asn", - "MAP-DialogueInformation.asn", - "MAP-ER-DataTypes.asn", - "MAP-Errors.asn", - "MAP-ExtensionDataTypes.asn", - "MAP-GR-DataTypes.asn", - "MAP-Group-Call-Operations.asn", - "MAP-LCS-DataTypes.asn", - "MAP-LocationServiceOperations.asn", - "MAP-MobileServiceOperations.asn", - "MAP-MS-DataTypes.asn", - "MAP-OM-DataTypes.asn", - "MAP-OperationAndMaintenanceOperations.asn", - "MAP-Protocol.asn", - "MAP-SecureTransportOperations.asn", - "MAP-ShortMessageServiceOperations.asn", - "MAP-SM-DataTypes.asn", - "MAP-SS-Code.asn", - "MAP-SS-DataTypes.asn", - "MAP-ST-DataTypes.asn", - "MAP-SupplementaryServiceOperations.asn", - "MAP-TS-Code.asn", - "MobileDomainDefinitions.asn", - "Remote-Operations-Generic-ROS-PDUs.asn", - "Remote-Operations-Information-Objects.asn", - "Remote-Operations-Useful-Definitions.asn", - "TCAP-Examples.asn", - "TCAPMessages.asn", - "TCAP-Tools.asn", - "TC-Notation-Extensions.asn", - "UnidialoguePDUs.asn"]], - ok. + Fs = [filename:join("tcapsystem", M) || + M <- ["DialoguePDUs.asn", + "MAP-ApplicationContexts.asn", + "MAP-BS-Code.asn", + "MAP-CallHandlingOperations.asn", + "MAP-CH-DataTypes.asn", + "MAP-CommonDataTypes.asn", + "MAP-DialogueInformation.asn", + "MAP-ER-DataTypes.asn", + "MAP-Errors.asn", + "MAP-ExtensionDataTypes.asn", + "MAP-GR-DataTypes.asn", + "MAP-Group-Call-Operations.asn", + "MAP-LCS-DataTypes.asn", + "MAP-LocationServiceOperations.asn", + "MAP-MobileServiceOperations.asn", + "MAP-MS-DataTypes.asn", + "MAP-OM-DataTypes.asn", + "MAP-OperationAndMaintenanceOperations.asn", + "MAP-Protocol.asn", + "MAP-SecureTransportOperations.asn", + "MAP-ShortMessageServiceOperations.asn", + "MAP-SM-DataTypes.asn", + "MAP-SS-Code.asn", + "MAP-SS-DataTypes.asn", + "MAP-ST-DataTypes.asn", + "MAP-SupplementaryServiceOperations.asn", + "MAP-TS-Code.asn", + "MobileDomainDefinitions.asn", + "Remote-Operations-Generic-ROS-PDUs.asn", + "Remote-Operations-Information-Objects.asn", + "Remote-Operations-Useful-Definitions.asn", + "TCAP-Examples.asn", + "TCAPMessages.asn", + "TCAP-Tools.asn", + "TC-Notation-Extensions.asn", + "UnidialoguePDUs.asn"]], + asn1_test_lib:compile_all(Fs, Config, Options). diff --git a/lib/asn1/vsn.mk b/lib/asn1/vsn.mk index 1f16f31f6b..d87c50637d 100644 --- a/lib/asn1/vsn.mk +++ b/lib/asn1/vsn.mk @@ -1,2 +1,2 @@ #next version number to use is 2.0 -ASN1_VSN = 3.0 +ASN1_VSN = 3.0.2 |