%% ``Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
%% AB. All Rights Reserved.''
%%
%% $Id: asn1ct_value.erl,v 1.1 2008/12/17 09:53:30 mikpe Exp $
-module(asn1ct_value).
%% Generate Erlang values for ASN.1 types.
%% The value is randomized within it's constraints
-include("asn1_records.hrl").
%-compile(export_all).
-export([get_type/3]).
%% Generate examples of values ******************************
%%****************************************x
get_type(M,Typename,Tellname) ->
case asn1_db:dbget(M,Typename) of
undefined ->
{asn1_error,{not_found,{M,Typename}}};
Tdef when record(Tdef,typedef) ->
Type = Tdef#typedef.typespec,
get_type(M,[Typename],Type,Tellname);
Err ->
{asn1_error,{other,Err}}
end.
get_type(M,Typename,Type,Tellname) when record(Type,type) ->
InnerType = get_inner(Type#type.def),
case asn1ct_gen:type(InnerType) of
#'Externaltypereference'{module=Emod,type=Etype} ->
get_type(Emod,Etype,Tellname);
{_,user} ->
case Tellname of
yes -> {Typename,get_type(M,InnerType,no)};
no -> get_type(M,InnerType,no)
end;
{notype,_} ->
true;
{primitive,bif} ->
get_type_prim(Type);
'ASN1_OPEN_TYPE' ->
case Type#type.constraint of
[#'Externaltypereference'{type=TrefConstraint}] ->
get_type(M,TrefConstraint,no);
_ ->
"open_type"
end;
{constructed,bif} ->
get_type_constructed(M,Typename,InnerType,Type)
end;
get_type(M,Typename,#'ComponentType'{name = Name,typespec = Type},_) ->
get_type(M,[Name|Typename],Type,no);
get_type(_,_,_,_) -> % 'EXTENSIONMARK'
undefined.
get_inner(A) when atom(A) -> A;
get_inner(Ext) when record(Ext,'Externaltypereference') -> Ext;
get_inner({typereference,_Pos,Name}) -> Name;
get_inner(T) when tuple(T) ->
case asn1ct_gen:get_inner(T) of
{fixedtypevaluefield,_,Type} ->
Type#type.def;
{typefield,_FieldName} ->
'ASN1_OPEN_TYPE';
Other ->
Other
end.
%%get_inner(T) when tuple(T) -> element(1,T).
get_type_constructed(M,Typename,InnerType,D) when record(D,type) ->
case InnerType of
'SET' ->
get_sequence(M,Typename,D);
'SEQUENCE' ->
get_sequence(M,Typename,D);
'CHOICE' ->
get_choice(M,Typename,D);
'SEQUENCE OF' ->
{_,Type} = D#type.def,
NameSuffix = asn1ct_gen:constructed_suffix(InnerType,Type#type.def),
get_sequence_of(M,Typename,D,NameSuffix);
'SET OF' ->
{_,Type} = D#type.def,
NameSuffix = asn1ct_gen:constructed_suffix(InnerType,Type#type.def),
get_sequence_of(M,Typename,D,NameSuffix);
_ ->
exit({nyi,InnerType})
end.
get_sequence(M,Typename,Type) ->
{_SEQorSET,CompList} =
case Type#type.def of
#'SEQUENCE'{components=Cl} -> {'SEQUENCE',Cl};
#'SET'{components=Cl} -> {'SET',Cl}
end,
case get_components(M,Typename,CompList) of
[] ->
{list_to_atom(asn1ct_gen:list2rname(Typename))};
C ->
list_to_tuple([list_to_atom(asn1ct_gen:list2rname(Typename))|C])
end.
get_components(M,Typename,{Root,Ext}) ->
get_components(M,Typename,Root++Ext);
%% Should enhance this *** HERE *** with proper handling of extensions
get_components(M,Typename,[H|T]) ->
[get_type(M,Typename,H,no)|
get_components(M,Typename,T)];
get_components(_,_,[]) ->
[].
get_choice(M,Typename,Type) ->
{'CHOICE',TCompList} = Type#type.def,
case TCompList of
[] ->
{asn1_EMPTY,asn1_EMPTY};
{CompList,ExtList} -> % Should be enhanced to handle extensions too
CList = CompList ++ ExtList,
C = lists:nth(random(length(CList)),CList),
{C#'ComponentType'.name,get_type(M,Typename,C,no)};
CompList when list(CompList) ->
C = lists:nth(random(length(CompList)),CompList),
{C#'ComponentType'.name,get_type(M,Typename,C,no)}
end.
get_sequence_of(M,Typename,Type,TypeSuffix) ->
%% should generate length according to constraints later
{_,Oftype} = Type#type.def,
C = Type#type.constraint,
S = size_random(C),
NewTypeName = [TypeSuffix|Typename],
gen_list(M,NewTypeName,Oftype,no,S).
gen_list(_,_,_,_,0) ->
[];
gen_list(M,Typename,Oftype,Tellname,N) ->
[get_type(M,Typename,Oftype,no)|gen_list(M,Typename,Oftype,Tellname,N-1)].
get_type_prim(D) ->
C = D#type.constraint,
case D#type.def of
'INTEGER' ->
i_random(C);
{'INTEGER',NamedNumberList} ->
NN = [X||{X,_} <- NamedNumberList],
case NN of
[] ->
i_random(C);
_ ->
lists:nth(random(length(NN)),NN)
end;
Enum when tuple(Enum),element(1,Enum)=='ENUMERATED' ->
NamedNumberList =
case Enum of
{_,_,NNL} -> NNL;
{_,NNL} -> NNL
end,
NNew=
case NamedNumberList of
{N1,N2} ->
N1 ++ N2;
_->
NamedNumberList
end,
NN = [X||{X,_} <- NNew],
case NN of
[] ->
asn1_EMPTY;
_ ->
lists:nth(random(length(NN)),NN)
end;
{'BIT STRING',NamedNumberList} ->
%% io:format("get_type_prim 1: ~w~n",[NamedNumberList]),
NN = [X||{X,_} <- NamedNumberList],
case NN of
[] ->
Bl1 =lists:reverse(adjust_list(size_random(C),[1,0,1,1])),
lists:reverse(lists:dropwhile(fun(0)->true;(1)->false end,Bl1));
_ ->
%% io:format("get_type_prim 2: ~w~n",[NN]),
[lists:nth(random(length(NN)),NN)]
end;
'ANY' ->
exit({asn1_error,nyi,'ANY'});
'NULL' ->
'NULL';
'OBJECT IDENTIFIER' ->
Len = random(3),
Olist = [(random(1000)-1)||_X <-lists:seq(1,Len)],
list_to_tuple([random(3)-1,random(40)-1|Olist]);
'ObjectDescriptor' ->
object_descriptor_nyi;
'BOOLEAN' ->
true;
'OCTET STRING' ->
adjust_list(size_random(C),c_string(C,"OCTET STRING"));
'NumericString' ->
adjust_list(size_random(C),c_string(C,"0123456789"));
'TeletexString' ->
adjust_list(size_random(C),c_string(C,"TeletexString"));
'VideotexString' ->
adjust_list(size_random(C),c_string(C,"VideotexString"));
'UTCTime' ->
"97100211-0500";
'GeneralizedTime' ->
"19971002103130.5";
'GraphicString' ->
adjust_list(size_random(C),c_string(C,"GraphicString"));
'VisibleString' ->
adjust_list(size_random(C),c_string(C,"VisibleString"));
'GeneralString' ->
adjust_list(size_random(C),c_string(C,"GeneralString"));
'PrintableString' ->
adjust_list(size_random(C),c_string(C,"PrintableString"));
'IA5String' ->
adjust_list(size_random(C),c_string(C,"IA5String"));
'BMPString' ->
adjust_list(size_random(C),c_string(C,"BMPString"));
'UniversalString' ->
adjust_list(size_random(C),c_string(C,"UniversalString"));
XX ->
exit({asn1_error,nyi,XX})
end.
c_string(undefined,Default) ->
Default;
c_string(C,Default) ->
case get_constraint(C,'PermittedAlphabet') of
{'SingleValue',Sv} when list(Sv) ->
Sv;
{'SingleValue',V} when integer(V) ->
[V];
no ->
Default
end.
random(Upper) ->
{A1,A2,A3} = erlang:now(),
random:seed(A1,A2,A3),
random:uniform(Upper).
size_random(C) ->
case get_constraint(C,'SizeConstraint') of
no ->
c_random({0,5},no);
{Lb,Ub} when Ub-Lb =< 4 ->
c_random({Lb,Ub},no);
{Lb,_} ->
c_random({Lb,Lb+4},no);
Sv ->
c_random(no,Sv)
end.
i_random(C) ->
c_random(get_constraint(C,'ValueRange'),get_constraint(C,'SingleValue')).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% c_random(Range,SingleValue)
%% only called from other X_random functions
c_random(VRange,Single) ->
case {VRange,Single} of
{no,no} ->
random(16#fffffff) - (16#fffffff bsr 1);
{R,no} ->
case R of
{Lb,Ub} when integer(Lb),integer(Ub) ->
Range = Ub - Lb +1,
Lb + (random(Range)-1);
{Lb,'MAX'} ->
Lb + random(16#fffffff)-1;
{'MIN',Ub} ->
Ub - random(16#fffffff)-1;
{A,{'ASN1_OK',B}} ->
Range = B - A +1,
A + (random(Range)-1)
end;
{_,S} when integer(S) ->
S;
{_,S} when list(S) ->
lists:nth(random(length(S)),S)
%% {S1,S2} ->
%% io:format("asn1ct_value: hejsan hoppsan~n");
%% _ ->
%% io:format("asn1ct_value: hejsan hoppsan 2~n")
%% io:format("asn1ct_value: c_random/2: S1 = ~w~n"
%% "S2 = ~w,~n",[S1,S2])
%% exit(self(),goodbye)
end.
adjust_list(Len,Orig) ->
adjust_list1(Len,Orig,Orig,[]).
adjust_list1(0,_Orig,[_Oh|_Ot],Acc) ->
lists:reverse(Acc);
adjust_list1(Len,Orig,[],Acc) ->
adjust_list1(Len,Orig,Orig,Acc);
adjust_list1(Len,Orig,[Oh|Ot],Acc) ->
adjust_list1(Len-1,Orig,Ot,[Oh|Acc]).
get_constraint(C,Key) ->
case lists:keysearch(Key,1,C) of
false ->
no;
{value,{_,V}} ->
V
end.