1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20%%
21-module(asn1ct_value).
22
23%%  Generate Erlang values for ASN.1 types.
24%%  The value is randomized within it's constraints
25
26-include("asn1_records.hrl").
27
28-export([from_type/2]).
29
30%%****************************************
31%% Generate examples of values
32%%****************************************
33
34
35from_type(M,Typename) ->
36    case asn1_db:dbload(M) of
37	error ->
38	    {error,{not_found,{M,Typename}}};
39	ok ->
40	    #typedef{typespec=Type} = asn1_db:dbget(M, Typename),
41	    from_type(M,[Typename],Type);
42    Vdef when is_record(Vdef,valuedef) ->
43        from_value(Vdef);
44	Err ->
45	    {error,{other,Err}}
46    end.
47
48from_type(M,Typename,Type) when is_record(Type,type) ->
49    InnerType = get_inner(Type#type.def),
50    case asn1ct_gen:type(InnerType) of
51	#'Externaltypereference'{module=Emod,type=Etype} ->
52	    from_type(Emod,Etype);
53	{_,user} ->
54		from_type(M,InnerType);
55	{primitive,bif} ->
56	    from_type_prim(M, Type);
57	'ASN1_OPEN_TYPE' ->
58	    case  Type#type.constraint of
59		[#'Externaltypereference'{type=TrefConstraint}] ->
60		    from_type(M,TrefConstraint);
61		_ ->
62		    ERule = get_encoding_rule(M),
63		    open_type_value(ERule)
64	    end;
65	{constructed,bif} when Typename == ['EXTERNAL'] ->
66	    Val=from_type_constructed(M,Typename,InnerType,Type),
67            T = case M:maps() of
68                    false -> transform_to_EXTERNAL1994;
69                    true -> transform_to_EXTERNAL1994_maps
70                end,
71            asn1ct_eval_ext:T(Val);
72	{constructed,bif} ->
73	    from_type_constructed(M,Typename,InnerType,Type)
74    end;
75from_type(M,Typename,#'ComponentType'{name = Name,typespec = Type})  ->
76    from_type(M,[Name|Typename],Type);
77from_type(_,_,_) -> % 'EXTENSIONMARK'
78    undefined.
79
80from_value(#valuedef{type = #type{def = 'INTEGER'}, value = Val}) ->
81    Val.
82
83get_inner(A) when is_atom(A) -> A;
84get_inner(Ext) when is_record(Ext,'Externaltypereference') -> Ext;
85get_inner({typereference,_Pos,Name}) -> Name;
86get_inner(T) when is_tuple(T) ->
87    case asn1ct_gen:get_inner(T) of
88	{fixedtypevaluefield,_,Type} ->
89	    Type#type.def;
90	{typefield,_FieldName} ->
91	    'ASN1_OPEN_TYPE';
92	Other ->
93	    Other
94    end.
95
96from_type_constructed(M,Typename,InnerType,D) when is_record(D,type) ->
97    case InnerType of
98	'SET' ->
99	    get_sequence(M,Typename,D);
100	'SEQUENCE' ->
101	    get_sequence(M,Typename,D);
102	'CHOICE' ->
103	    get_choice(M,Typename,D);
104	'SEQUENCE OF' ->
105	    {_,Type} = D#type.def,
106	    NameSuffix = asn1ct_gen:constructed_suffix(InnerType,Type#type.def),
107	    get_sequence_of(M,Typename,D,NameSuffix);
108	'SET OF' ->
109	    {_,Type} = D#type.def,
110	    NameSuffix = asn1ct_gen:constructed_suffix(InnerType,Type#type.def),
111	    get_sequence_of(M,Typename,D,NameSuffix)
112    end.
113
114get_sequence(M,Typename,Type) ->
115    {_SEQorSET,CompList} =
116	case Type#type.def of
117	    #'SEQUENCE'{components=Cl} -> {'SEQUENCE',Cl};
118	    #'SET'{components=Cl} -> {'SET',to_textual_order(Cl)}
119	end,
120    Cs = get_components(M, Typename, CompList),
121    case M:maps() of
122        false ->
123            RecordTag = list_to_atom(asn1ct_gen:list2rname(Typename)),
124            list_to_tuple([RecordTag|[Val || {_,Val} <- Cs]]);
125        true ->
126            maps:from_list(Cs)
127    end.
128
129get_components(M,Typename,{Root,Ext}) ->
130    get_components2(M,Typename,filter_complist(Root++Ext));
131get_components(M,Typename,{Rl1,El,Rl2}) ->
132    get_components2(M,Typename,filter_complist(Rl1++El++Rl2));
133get_components(M,Typename,CompList) ->
134    get_components2(M,Typename,CompList).
135
136%% Should enhance this *** HERE *** with proper handling of extensions
137
138get_components2(M, Typename, [H|T]) ->
139    #'ComponentType'{name=Name} = H,
140    [{Name,from_type(M, Typename, H)}|get_components(M, Typename, T)];
141get_components2(_,_,[]) ->
142    [].
143
144filter_complist(CompList) when is_list(CompList) ->
145    lists:filter(fun(#'ExtensionAdditionGroup'{}) ->
146			 false;
147		    ('ExtensionAdditionGroupEnd') ->
148			 false;
149		    (_) ->
150			 true
151		 end, CompList).
152
153get_choice(M,Typename,Type) ->
154    {'CHOICE',TCompList} = Type#type.def,
155    case TCompList of
156	[] ->
157	    {asn1_EMPTY,asn1_EMPTY};
158	{CompList,ExtList} ->
159            %% should be enhanced to handle extensions too.
160	    CList = CompList ++ ExtList,
161	    C = lists:nth(random(length(CList)),CList),
162	    {C#'ComponentType'.name,from_type(M,Typename,C)};
163	CompList when is_list(CompList) ->
164	    C = lists:nth(random(length(CompList)),CompList),
165	    {C#'ComponentType'.name,from_type(M,Typename,C)}
166    end.
167
168get_sequence_of(M,Typename,Type,TypeSuffix) ->
169    %% should generate length according to constraints later
170    {_,Oftype} = Type#type.def,
171    C = Type#type.constraint,
172    S = size_random(C),
173    NewTypeName = [TypeSuffix|Typename],
174    gen_list(M,NewTypeName,Oftype,S).
175
176gen_list(_,_,_,0) ->
177    [];
178gen_list(M,Typename,Oftype,N) ->
179    [from_type(M,Typename,Oftype)|gen_list(M,Typename,Oftype,N-1)].
180
181from_type_prim(M, D) ->
182    C = D#type.constraint,
183    case D#type.def of
184	'INTEGER' ->
185	    i_random(C);
186	{'INTEGER',[_|_]=NNL} ->
187	    case C of
188		[] ->
189		    {N,_} = lists:nth(random(length(NNL)), NNL),
190		    N;
191		_ ->
192		    V = i_random(C),
193		    case lists:keyfind(V, 2, NNL) of
194			false -> V;
195			{N,V} -> N
196		    end
197	    end;
198	Enum when is_tuple(Enum),element(1,Enum)=='ENUMERATED' ->
199	    NamedNumberList =
200		case Enum of
201		    {_,_,NNL} -> NNL;
202		    {_,NNL} -> NNL
203		end,
204	    NNew=
205		case NamedNumberList of
206		    {N1,N2} ->
207			N1 ++ N2;
208		    _->
209			NamedNumberList
210		end,
211	    NN = [X||{X,_} <- NNew],
212	    case NN of
213		[] ->
214            io:format(user, "Enum = ~p~n", [Enum]),
215		    asn1_EMPTY;
216		_ ->
217		    case C of
218			[] ->
219			    lists:nth(random(length(NN)),NN);
220			_ ->
221			    lists:nth((fun(0)->1;(X)->X end(i_random(C))),NN)
222		    end
223	    end;
224	{'BIT STRING',NamedNumberList} ->
225	    NN = [X||{X,_} <- NamedNumberList],
226	    case NN of
227		[] ->
228		    random_unnamed_bit_string(M, C);
229		_ ->
230		    [lists:nth(random(length(NN)),NN)]
231	    end;
232	'NULL' ->
233	    'NULL';
234	'OBJECT IDENTIFIER' ->
235	    Len = random(3),
236	    Olist = [(random(1000)-1)||_X <-lists:seq(1,Len)],
237	    list_to_tuple([random(3)-1,random(40)-1|Olist]);
238	'RELATIVE-OID' ->
239	    Len = random(5),
240	    Olist = [(random(16#ffff)-1)||_X <-lists:seq(1,Len)],
241	    list_to_tuple(Olist);
242	'ObjectDescriptor' ->
243	    "Dummy ObjectDescriptor";
244	'REAL' ->
245	    %% Base is 2 or 10, format is string (base 10) or tuple
246	    %% (base 2 or 10)
247	    %% Tuple: {Mantissa, Base, Exponent}
248	    case random(3) of
249		1 ->
250		    %% base 2
251		    case random(3) of
252			3 ->
253			    {129,2,10};
254			2 ->
255			    {1,2,1};
256			_ ->
257			    {2#11111111,2,2}
258		    end;
259		_ ->
260		    %% base 10 string format, NR3 format
261		    case random(2) of
262			2 ->
263			    "123.E10";
264			_ ->
265			    "-123.E-10"
266		    end
267	    end;
268	'BOOLEAN' ->
269	    true;
270	'OCTET STRING' ->
271	    S0 = adjust_list(size_random(C), c_string(C, "OCTET STRING")),
272	    case M:legacy_erlang_types() of
273		false -> list_to_binary(S0);
274		true -> S0
275	    end;
276	'NumericString' ->
277	    adjust_list(size_random(C),c_string(C,"0123456789"));
278	'TeletexString' ->
279	    adjust_list(size_random(C),c_string(C,"TeletexString"));
280	'T61String' ->
281	    adjust_list(size_random(C),c_string(C,"T61String"));
282	'VideotexString' ->
283	    adjust_list(size_random(C),c_string(C,"VideotexString"));
284	'UTCTime' ->
285	    "97100211-0500";
286	'GeneralizedTime' ->
287	    "19971002103130.5";
288	'GraphicString' ->
289	    adjust_list(size_random(C),c_string(C,"GraphicString"));
290	'VisibleString' ->
291	    adjust_list(size_random(C),c_string(C,"VisibleString"));
292	'GeneralString' ->
293	    adjust_list(size_random(C),c_string(C,"GeneralString"));
294	'PrintableString' ->
295	    adjust_list(size_random(C),c_string(C,"PrintableString"));
296	'IA5String' ->
297	    adjust_list(size_random(C),c_string(C,"IA5String"));
298	'BMPString' ->
299	    adjust_list(size_random(C),c_string(C,"BMPString"));
300	'UTF8String' ->
301            L = adjust_list(random(50),
302                            [$U,$T,$F,$8,$S,$t,$r,$i,$n,$g,
303                             16#ffff,16#ffee,16#10ffff,16#ffff,16#fff]),
304	    unicode:characters_to_binary(L);
305	'UniversalString' ->
306	    adjust_list(size_random(C),c_string(C,"UniversalString"))
307    end.
308
309c_string(C,Default) ->
310    case get_constraint(C,'PermittedAlphabet') of
311	{'SingleValue',Sv} when is_list(Sv) ->
312	    Sv;
313	{'SingleValue',V} when is_integer(V) ->
314	    [V];
315	no ->
316	    Default
317    end.
318
319random_unnamed_bit_string(M, C) ->
320    Bl1 = lists:reverse(adjust_list(size_random(C), [1,0,1,1])),
321    Bl2 = lists:reverse(lists:dropwhile(fun(0)-> true;
322					   (1) -> false
323					end,Bl1)),
324    Val = case {length(Bl2),get_constraint(C, 'SizeConstraint')} of
325	      {Len,Len} ->
326		  Bl2;
327	      {_Len,Int} when is_integer(Int) ->
328		  Bl1;
329	      {Len,{Min,_}} when Min > Len ->
330		  Bl1;
331	      _ ->
332		  Bl2
333	  end,
334    case M:bit_string_format() of
335	legacy ->
336	    Val;
337	bitstring ->
338	    << <<B:1>> || B <- Val >>;
339	compact ->
340	    BitString = << <<B:1>> || B <- Val >>,
341	    PadLen = (8 - (bit_size(BitString) band 7)) band 7,
342	    {PadLen,<<BitString/bitstring,0:PadLen>>}
343    end.
344
345random(Upper) ->
346    rand:uniform(Upper).
347
348size_random(C) ->
349    case get_constraint(C,'SizeConstraint') of
350	no ->
351	    c_random({0,5},no);
352	{{Lb,Ub},_} when is_integer(Lb),is_integer(Ub) ->
353	    if
354		Ub-Lb =< 4 ->
355		    c_random({Lb,Ub},no);
356		true ->
357		    c_random({Lb,Lb+4},no)
358	    end;
359	{Lb,Ub} when Ub-Lb =< 4 ->
360	    c_random({Lb,Ub},no);
361	{Lb,_}  ->
362	    c_random({Lb,Lb+4},no);
363	Sv ->
364	    c_random(no,Sv)
365    end.
366
367i_random(C) ->
368    c_random(get_constraint(C,'ValueRange'),get_constraint(C,'SingleValue')).
369
370%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
371%% c_random(Range,SingleValue)
372%% only called from other X_random functions
373
374c_random(VRange,Single) ->
375    case {VRange,Single} of
376	{no,no} ->
377	    random(16#fffffff) - (16#fffffff bsr 1);
378	{R,no} ->
379	    case R of
380		{Lb,Ub} when is_integer(Lb),is_integer(Ub) ->
381		    Range = Ub - Lb +1,
382		    Lb + (random(Range)-1);
383		{Lb,'MAX'} ->
384		    Lb + random(16#fffffff)-1;
385		{'MIN',Ub} ->
386		    Ub - random(16#fffffff)-1;
387		{A,{'ASN1_OK',B}} ->
388		    Range = B - A +1,
389		    A + (random(Range)-1)
390	    end;
391	{_,S} when is_integer(S) ->
392	    S;
393	{_,S} when is_list(S) ->
394	    lists:nth(random(length(S)),S)
395    end.
396
397adjust_list(Len,Orig) ->
398    adjust_list1(Len,Orig,Orig,[]).
399
400adjust_list1(0,_Orig,[_Oh|_Ot],Acc) ->
401    lists:reverse(Acc);
402adjust_list1(Len,Orig,[],Acc) ->
403    adjust_list1(Len,Orig,Orig,Acc);
404adjust_list1(Len,Orig,[Oh|Ot],Acc) ->
405    adjust_list1(Len-1,Orig,Ot,[Oh|Acc]).
406
407
408get_constraint(C, Key) ->
409    case lists:keyfind(Key, 1, C) of
410        false                    -> no;
411        {'ValueRange', {Lb, Ub}} -> {check_external(Lb), check_external(Ub)};
412        {'SizeConstraint', N}    -> N;
413        {Key, Value}             -> Value
414    end.
415
416check_external(ExtRef) when is_record(ExtRef, 'Externalvaluereference') ->
417    #'Externalvaluereference'{module = Emod, value = Evalue} = ExtRef,
418    from_type(Emod, Evalue);
419check_external(Value) ->
420    Value.
421
422get_encoding_rule(M) ->
423    Mod =
424	if is_list(M) ->
425		list_to_atom(M);
426	   true ->M
427	end,
428    case (catch Mod:encoding_rule()) of
429	A when is_atom(A) ->
430	    A;
431	_ -> unknown
432    end.
433
434open_type_value(ber) ->
435    <<4,9,111,112,101,110,95,116,121,112,101>>;
436open_type_value(_) ->
437    <<"\n\topen_type">>.	       %octet string value "open_type"
438
439to_textual_order({Root,Ext}) ->
440    {to_textual_order(Root),Ext};
441to_textual_order(Cs) when is_list(Cs) ->
442    case Cs of
443	[#'ComponentType'{textual_order=undefined}|_] ->
444	    Cs;
445	_ ->
446	    lists:keysort(#'ComponentType'.textual_order,Cs)
447    end.
448