1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1997-2018. 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_gen_per). 22 23%% Generate erlang module which handles (PER) encode and decode for 24%% all types in an ASN.1 module 25 26-include("asn1_records.hrl"). 27 28-export([gen_dec_imm/2]). 29-export([gen_dec_prim/3,gen_encode_prim_imm/3]). 30-export([gen_obj_code/3,gen_objectset_code/2]). 31-export([gen_decode/2, gen_decode/3]). 32-export([gen_encode/2, gen_encode/3]). 33-export([gen_dec_external/2]). 34-export([extaddgroup2sequence/1]). 35-export([dialyzer_suppressions/1]). 36 37-import(asn1ct_gen, [emit/1]). 38-import(asn1ct_func, [call/3]). 39 40 41%%**************************************** 42%% Generate ENCODING 43%%**************************************** 44 45dialyzer_suppressions(#gen{erule=per,aligned=Aligned}) -> 46 Mod = case Aligned of 47 false -> uper; 48 true -> per 49 end, 50 suppress({Mod,complete,1}), 51 suppress({per_common,to_bitstring,2}), 52 emit([" ok.",nl]). 53 54suppress({M,F,A}=MFA) -> 55 case asn1ct_func:is_used(MFA) of 56 false -> 57 ok; 58 true -> 59 Args = 60 [lists:concat(["element(",I,", Arg)"]) 61 || I <- lists:seq(1, A)], 62 emit([" ",{call,M,F,Args},com,nl]) 63 end. 64 65gen_encode(Erules,Type) when is_record(Type,typedef) -> 66 gen_encode_user(Erules,Type). 67 68gen_encode(Erules,Typename,#'ComponentType'{name=Cname,typespec=Type}) -> 69 NewTypename = [Cname|Typename], 70 gen_encode(Erules,NewTypename,Type); 71 72gen_encode(Erules,Typename,Type) when is_record(Type,type) -> 73 InnerType = asn1ct_gen:get_inner(Type#type.def), 74 ObjFun = 75 case lists:keysearch(objfun,1,Type#type.tablecinf) of 76 {value,{_,_Name}} -> 77 ", ObjFun"; 78 false -> 79 "" 80 end, 81 case asn1ct_gen:type(InnerType) of 82 {constructed,bif} -> 83 Func = enc_func(asn1ct_gen:list2name(Typename)), 84 emit([{asis,Func},"(Val",ObjFun,") ->",nl]), 85 asn1ct_gen:gen_encode_constructed(Erules,Typename,InnerType,Type); 86 _ -> 87 true 88 end. 89 90 91gen_encode_user(Erules,D) when is_record(D,typedef) -> 92 CurrMod = get(currmod), 93 Typename = [D#typedef.name], 94 Def = D#typedef.typespec, 95 InnerType = asn1ct_gen:get_inner(Def#type.def), 96 Func = enc_func(asn1ct_gen:list2name(Typename)), 97 emit([{asis,Func},"(Val) ->",nl]), 98 case asn1ct_gen:type(InnerType) of 99 {primitive,bif} -> 100 gen_encode_prim(Erules, Def), 101 emit([".",nl]); 102 'ASN1_OPEN_TYPE' -> 103 gen_encode_prim(Erules, Def#type{def='ASN1_OPEN_TYPE'}), 104 emit([".",nl]); 105 {constructed,bif} -> 106 asn1ct_gen:gen_encode_constructed(Erules,Typename,InnerType,D); 107 #'Externaltypereference'{module=CurrMod,type=Etype} -> 108 emit([{asis,enc_func(Etype)},"(Val).",nl]); 109 #'Externaltypereference'{module=Emod,type=Etype} -> 110 emit([{asis,Emod},":",{asis,enc_func(Etype)},"(Val).",nl]) 111 end. 112 113 114gen_encode_prim(Erules, D) -> 115 Value = {var,atom_to_list(asn1ct_gen:mk_var(asn1ct_name:curr(val)))}, 116 gen_encode_prim(Erules, D, Value). 117 118gen_encode_prim(#gen{erule=per,aligned=Aligned}, #type{}=D, Value) -> 119 Imm = gen_encode_prim_imm(Value, D, Aligned), 120 asn1ct_imm:enc_cg(Imm, Aligned). 121 122gen_encode_prim_imm(Val, #type{def=Type0,constraint=Constraint}, Aligned) -> 123 case simplify_type(Type0) of 124 k_m_string -> 125 Type = case Type0 of 126 'GeneralizedTime' -> 'VisibleString'; 127 'UTCTime' -> 'VisibleString'; 128 _ -> Type0 129 end, 130 asn1ct_imm:per_enc_k_m_string(Val, Type, Constraint, Aligned); 131 restricted_string -> 132 ToBinary = {erlang,iolist_to_binary}, 133 asn1ct_imm:per_enc_restricted_string(Val, ToBinary, Aligned); 134 {'ENUMERATED',NNL} -> 135 asn1ct_imm:per_enc_enumerated(Val, NNL, Aligned); 136 'INTEGER' -> 137 asn1ct_imm:per_enc_integer(Val, Constraint, Aligned); 138 {'INTEGER',NNL} -> 139 asn1ct_imm:per_enc_integer(Val, NNL, Constraint, Aligned); 140 'REAL' -> 141 ToBinary = {real_common,encode_real}, 142 asn1ct_imm:per_enc_restricted_string(Val, ToBinary, Aligned); 143 {'BIT STRING',NNL} -> 144 case asn1ct:use_legacy_types() of 145 false -> 146 asn1ct_imm:per_enc_bit_string(Val, NNL, 147 Constraint, Aligned); 148 true -> 149 asn1ct_imm:per_enc_legacy_bit_string(Val, NNL, 150 Constraint, Aligned) 151 end; 152 'NULL' -> 153 asn1ct_imm:per_enc_null(Val, Aligned); 154 'OBJECT IDENTIFIER' -> 155 ToBinary = {per_common,encode_oid}, 156 asn1ct_imm:per_enc_restricted_string(Val, ToBinary, Aligned); 157 'RELATIVE-OID' -> 158 ToBinary = {per_common,encode_relative_oid}, 159 asn1ct_imm:per_enc_restricted_string(Val, ToBinary, Aligned); 160 'BOOLEAN' -> 161 asn1ct_imm:per_enc_boolean(Val, Aligned); 162 'OCTET STRING' -> 163 case asn1ct:use_legacy_types() of 164 false -> 165 asn1ct_imm:per_enc_octet_string(Val, Constraint, Aligned); 166 true -> 167 asn1ct_imm:per_enc_legacy_octet_string(Val, Constraint, 168 Aligned) 169 end; 170 'ASN1_OPEN_TYPE' -> 171 case Constraint of 172 [#'Externaltypereference'{type=Tname}] -> 173 EncFunc = enc_func(Tname), 174 Imm = [{apply,{local,EncFunc,[]},[Val]}], 175 asn1ct_imm:per_enc_open_type(Imm, Aligned); 176 [] -> 177 Imm = [{call,erlang,iolist_to_binary,[Val]}], 178 asn1ct_imm:per_enc_open_type(Imm, Aligned) 179 end 180 end. 181 182dec_func(Tname) -> 183 list_to_atom(lists:concat(["dec_",Tname])). 184 185enc_func(Tname) -> 186 list_to_atom(lists:concat(["enc_",Tname])). 187 188simplify_type(Type) -> 189 case Type of 190 'BMPString' -> k_m_string; 191 'IA5String' -> k_m_string; 192 'NumericString' -> k_m_string; 193 'PrintableString' -> k_m_string; 194 'VisibleString' -> k_m_string; 195 'UniversalString' -> k_m_string; 196 'GeneralizedTime' -> k_m_string; 197 'UTCTime' -> k_m_string; 198 'TeletexString' -> restricted_string; 199 'T61String' -> restricted_string; 200 'VideotexString' -> restricted_string; 201 'GraphicString' -> restricted_string; 202 'GeneralString' -> restricted_string; 203 'UTF8String' -> restricted_string; 204 'ObjectDescriptor' -> restricted_string; 205 Other -> Other 206 end. 207 208%% Object code generating for encoding and decoding 209%% ------------------------------------------------ 210 211gen_obj_code(_Erules, _Module, #typedef{}) -> 212 ok. 213 214%% Object Set code generating for encoding and decoding 215%% ---------------------------------------------------- 216gen_objectset_code(_Erules, _ObjSet) -> 217 ok. 218 219%% DECODING ***************************** 220%%*************************************** 221 222gen_decode(Erules, #typedef{}=Type) -> 223 DecFunc = dec_func(Type#typedef.name), 224 emit([nl,nl,{asis,DecFunc},"(Bytes) ->",nl]), 225 gen_decode_user(Erules, Type). 226 227gen_decode(Erules,Tname,#'ComponentType'{name=Cname,typespec=Type}) -> 228 NewTname = [Cname|Tname], 229 gen_decode(Erules,NewTname,Type); 230 231gen_decode(Erules,Typename,Type) when is_record(Type,type) -> 232 InnerType = asn1ct_gen:get_inner(Type#type.def), 233 case asn1ct_gen:type(InnerType) of 234 {constructed,bif} -> 235 ObjFun = 236 case Type#type.tablecinf of 237 [{objfun,_}|_R] -> 238 ", ObjFun"; 239 _ -> 240 "" 241 end, 242 emit([nl, 243 {asis,dec_func(asn1ct_gen:list2name(Typename))}, 244 "(Bytes",ObjFun,") ->",nl]), 245 asn1ct_gen:gen_decode_constructed(Erules,Typename,InnerType,Type); 246 _ -> 247 true 248 end. 249 250gen_decode_user(Erules,D) when is_record(D,typedef) -> 251 Typename = [D#typedef.name], 252 Def = D#typedef.typespec, 253 InnerType = asn1ct_gen:get_inner(Def#type.def), 254 case asn1ct_gen:type(InnerType) of 255 {primitive,bif} -> 256 gen_dec_prim(Erules,Def,"Bytes"), 257 emit([".",nl,nl]); 258 'ASN1_OPEN_TYPE' -> 259 gen_dec_prim(Erules,Def#type{def='ASN1_OPEN_TYPE'},"Bytes"), 260 emit([".",nl,nl]); 261 {constructed,bif} -> 262 asn1ct_gen:gen_decode_constructed(Erules,Typename,InnerType,D); 263 #'Externaltypereference'{}=Etype -> 264 gen_dec_external(Etype, "Bytes"), 265 emit([".",nl,nl]) 266 end. 267 268gen_dec_external(Ext, BytesVar) -> 269 CurrMod = get(currmod), 270 #'Externaltypereference'{module=Mod,type=Type} = Ext, 271 emit([case CurrMod of 272 Mod -> []; 273 _ -> [{asis,Mod},":"] 274 end,{asis,dec_func(Type)},"(",BytesVar,")"]). 275 276gen_dec_imm(#gen{erule=per,aligned=Aligned}, #type{def=Name,constraint=C}) -> 277 gen_dec_imm_1(Name, C, Aligned). 278 279gen_dec_imm_1('ASN1_OPEN_TYPE', Constraint, Aligned) -> 280 imm_decode_open_type(Constraint, Aligned); 281gen_dec_imm_1({'BIT STRING',NNL}, Constr0, Aligned) -> 282 Constr = asn1ct_imm:effective_constraint(bitstring, Constr0), 283 Imm = asn1ct_imm:per_dec_raw_bitstring(Constr, Aligned), 284 case NNL of 285 [] -> 286 case asn1ct:get_bit_string_format() of 287 compact -> 288 gen_dec_bit_string(decode_compact_bit_string, 289 Imm); 290 legacy -> 291 gen_dec_bit_string(decode_legacy_bit_string, 292 Imm); 293 bitstring -> 294 gen_dec_copy_bitstring(Imm) 295 end; 296 [_|_] -> 297 D = fun(V, Buf) -> 298 As = [V,{asis,NNL}], 299 Call = {call,per_common,decode_named_bit_string,As}, 300 emit(["{",Call,com,Buf,"}"]) 301 end, 302 {call,D,Imm} 303 end; 304gen_dec_imm_1('NULL', _Constr, _Aligned) -> 305 {value,'NULL'}; 306gen_dec_imm_1('BOOLEAN', _Constr, _Aligned) -> 307 asn1ct_imm:per_dec_boolean(); 308gen_dec_imm_1({'ENUMERATED',{Base,Ext}}, _Constr, Aligned) -> 309 asn1ct_imm:per_dec_enumerated(Base, Ext, Aligned); 310gen_dec_imm_1({'ENUMERATED',NamedNumberList}, _Constr, Aligned) -> 311 asn1ct_imm:per_dec_enumerated(NamedNumberList, Aligned); 312gen_dec_imm_1('INTEGER', Constr, Aligned) -> 313 asn1ct_imm:per_dec_integer(Constr, Aligned); 314gen_dec_imm_1({'INTEGER',NamedNumberList}, Constraint, Aligned) -> 315 asn1ct_imm:per_dec_named_integer(Constraint, 316 NamedNumberList, 317 Aligned); 318gen_dec_imm_1('BMPString'=Type, Constraint, Aligned) -> 319 gen_dec_k_m_string(Type, Constraint, Aligned); 320gen_dec_imm_1('NumericString'=Type, Constraint, Aligned) -> 321 gen_dec_k_m_string(Type, Constraint, Aligned); 322gen_dec_imm_1('PrintableString'=Type, Constraint, Aligned) -> 323 gen_dec_k_m_string(Type, Constraint, Aligned); 324gen_dec_imm_1('VisibleString'=Type, Constraint, Aligned) -> 325 gen_dec_k_m_string(Type, Constraint, Aligned); 326gen_dec_imm_1('IA5String'=Type, Constraint, Aligned) -> 327 gen_dec_k_m_string(Type, Constraint, Aligned); 328gen_dec_imm_1('UniversalString'=Type, Constraint, Aligned) -> 329 gen_dec_k_m_string(Type, Constraint, Aligned); 330gen_dec_imm_1('UTCTime', Constraint, Aligned) -> 331 gen_dec_k_m_string('VisibleString', Constraint, Aligned); 332gen_dec_imm_1('GeneralizedTime', Constraint, Aligned) -> 333 gen_dec_k_m_string('VisibleString', Constraint, Aligned); 334gen_dec_imm_1('OCTET STRING', Constraint, Aligned) -> 335 SzConstr = asn1ct_imm:effective_constraint(bitstring, Constraint), 336 Imm = asn1ct_imm:per_dec_octet_string(SzConstr, Aligned), 337 case asn1ct:use_legacy_types() of 338 false -> {convert,{binary,copy},Imm}; 339 true -> {convert,binary_to_list,Imm} 340 end; 341gen_dec_imm_1('TeletexString', _Constraint, Aligned) -> 342 gen_dec_restricted_string(Aligned); 343gen_dec_imm_1('T61String', _Constraint, Aligned) -> 344 gen_dec_restricted_string(Aligned); 345gen_dec_imm_1('VideotexString', _Constraint, Aligned) -> 346 gen_dec_restricted_string(Aligned); 347gen_dec_imm_1('GraphicString', _Constraint, Aligned) -> 348 gen_dec_restricted_string(Aligned); 349gen_dec_imm_1('GeneralString', _Constraint, Aligned) -> 350 gen_dec_restricted_string(Aligned); 351gen_dec_imm_1('ObjectDescriptor', _Constraint, Aligned) -> 352 gen_dec_restricted_string(Aligned); 353gen_dec_imm_1('OBJECT IDENTIFIER', _Constraint, Aligned) -> 354 Dec = fun(V, Buf) -> 355 emit(["{",{call,per_common,decode_oid,[V]},com, 356 Buf,"}"]) 357 end, 358 {call,Dec,gen_dec_restricted_string(Aligned)}; 359gen_dec_imm_1('RELATIVE-OID', _Constraint, Aligned) -> 360 Dec = fun(V, Buf) -> 361 emit(["{",{call,per_common,decode_relative_oid,[V]},com, 362 Buf,"}"]) 363 end, 364 {call,Dec,gen_dec_restricted_string(Aligned)}; 365gen_dec_imm_1('UTF8String', _Constraint, Aligned) -> 366 asn1ct_imm:per_dec_restricted_string(Aligned); 367gen_dec_imm_1('REAL', _Constraint, Aligned) -> 368 asn1ct_imm:per_dec_real(Aligned). 369 370gen_dec_bit_string(F, Imm) -> 371 D = fun(V, Buf) -> 372 emit(["{",{call,per_common,F,[V]},com,Buf,"}"]) 373 end, 374 {call,D,Imm}. 375 376gen_dec_copy_bitstring(Imm) -> 377 D = fun(V, Buf) -> 378 emit(["{list_to_bitstring([",V,"]),",Buf,"}"]) 379 end, 380 {call,D,Imm}. 381 382gen_dec_k_m_string(Type, Constraint, Aligned) -> 383 asn1ct_imm:per_dec_k_m_string(Type, Constraint, Aligned). 384 385gen_dec_restricted_string(Aligned) -> 386 Imm = asn1ct_imm:per_dec_restricted_string(Aligned), 387 {convert,binary_to_list,Imm}. 388 389gen_dec_prim(Erule, Type, BytesVar) -> 390 Imm = gen_dec_imm(Erule, Type), 391 asn1ct_imm:dec_code_gen(Imm, BytesVar). 392 393 394%% For PER the ExtensionAdditionGroup notation has significance for 395%% the encoding and decoding. The components within the 396%% ExtensionAdditionGroup is treated in a similar way as if they have 397%% been specified within a SEQUENCE. Therefore we construct a fake 398%% sequence type here so that we can generate code for it. 399extaddgroup2sequence(ExtList) -> 400 extaddgroup2sequence(ExtList,0,[]). 401 402extaddgroup2sequence([{'ExtensionAdditionGroup',Number0}|T],ExtNum,Acc) -> 403 Number = case Number0 of undefined -> 1; _ -> Number0 end, 404 {ExtGroupComps,['ExtensionAdditionGroupEnd'|T2]} = 405 lists:splitwith(fun(Elem) -> is_record(Elem,'ComponentType') end,T), 406 extaddgroup2sequence(T2,ExtNum+1, 407 [#'ComponentType'{ 408 name=list_to_atom("ExtAddGroup"++ 409 integer_to_list(ExtNum+1)), 410 typespec=#type{def=#'SEQUENCE'{ 411 extaddgroup=Number, 412 components=ExtGroupComps}}, 413 prop='OPTIONAL'}|Acc]); 414extaddgroup2sequence([C|T],ExtNum,Acc) -> 415 extaddgroup2sequence(T,ExtNum,[C|Acc]); 416extaddgroup2sequence([],_,Acc) -> 417 lists:reverse(Acc). 418 419imm_decode_open_type([#'Externaltypereference'{type=Tname}], Aligned) -> 420 imm_dec_open_type_1(Tname, Aligned); 421imm_decode_open_type([#type{def=#'Externaltypereference'{type=Tname}}], 422 Aligned) -> 423 imm_dec_open_type_1(Tname, Aligned); 424imm_decode_open_type(_, Aligned) -> 425 asn1ct_imm:per_dec_open_type(Aligned). 426 427imm_dec_open_type_1(Type, Aligned) -> 428 D = fun(OpenType, Buf) -> 429 asn1ct_name:new(tmpval), 430 emit(["begin",nl, 431 "{",{curr,tmpval},",_} = ", 432 {asis,dec_func(Type)},"(",OpenType,"),",nl, 433 "{",{curr,tmpval},com,Buf,"}",nl, 434 "end"]) 435 end, 436 {call,D,asn1ct_imm:per_dec_open_type(Aligned)}. 437