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