%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2001-2011. 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(asn1rt_check). -include("asn1_records.hrl"). -export([check_bool/2, check_int/3, check_bitstring/3, check_octetstring/2, check_null/2, check_objectidentifier/2, check_objectdescriptor/2, check_real/2, check_enum/3, check_restrictedstring/2]). -export([transform_to_EXTERNAL1990/1, transform_to_EXTERNAL1994/1]). -export([dynamicsort_SET_components/1, dynamicsort_SETOF/1]). check_bool(_Bool,asn1_DEFAULT) -> true; check_bool(Bool,Bool) when Bool == true; Bool == false -> true; check_bool(_Bool1,Bool2) -> throw({error,Bool2}). check_int(_,asn1_DEFAULT,_) -> true; check_int(Value,Value,_) when is_integer(Value) -> true; check_int(DefValue,Value,NNL) when is_atom(Value) -> case lists:keysearch(Value,1,NNL) of {value,{_,DefValue}} -> true; _ -> throw({error,DefValue}) end; check_int(DefaultValue,_Value,_) -> throw({error,DefaultValue}). % check_bitstring([H|T],[H|T],_) when is_integer(H) -> % true; % check_bitstring(V,V,_) when is_integer(V) -> % true; %% Two equal lists or integers check_bitstring(_,asn1_DEFAULT,_) -> true; check_bitstring(V,V,_) -> true; %% Default value as a list of 1 and 0 and user value as an integer check_bitstring(L=[H|T],Int,_) when is_integer(Int),is_integer(H) -> case bit_list_to_int(L,length(T)) of Int -> true; _ -> throw({error,L,Int}) end; %% Default value as an integer, val as list check_bitstring(Int,Val,NBL) when is_integer(Int),is_list(Val) -> BL = int_to_bit_list(Int,[],length(Val)), check_bitstring(BL,Val,NBL); %% Default value and user value as lists of ones and zeros check_bitstring(L1=[H1|_T1],L2=[H2|_T2],NBL=[_H|_T]) when is_integer(H1),is_integer(H2) -> L2new = remove_trailing_zeros(L2), check_bitstring(L1,L2new,NBL); %% Default value as a list of 1 and 0 and user value as a list of atoms check_bitstring(L1=[H1|_T1],L2=[H2|_T2],NBL) when is_integer(H1),is_atom(H2) -> L3 = bit_list_to_nbl(L1,NBL,0,[]), check_bitstring(L3,L2,NBL); %% Both default value and user value as a list of atoms check_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_bitstring(L1=[H1|_T1],L2=[H2|_T2],NBL) when is_atom(H1),is_integer(H2) -> L3 = bit_list_to_nbl(L2,NBL,0,[]), check_bitstring(L1,L3,NBL); %% User value in compact format check_bitstring(DefVal,CBS={_,_},NBL) -> NewVal = cbs_to_bit_list(CBS), check_bitstring(DefVal,NewVal,NBL); check_bitstring(DV,V,_) -> throw({error,DV,V}). bit_list_to_int([0|Bs],ShL)-> bit_list_to_int(Bs,ShL-1) + 0; bit_list_to_int([1|Bs],ShL) -> bit_list_to_int(Bs,ShL-1) + (1 bsl ShL); bit_list_to_int([],_) -> 0. int_to_bit_list(0,Acc,0) -> Acc; int_to_bit_list(Int,Acc,Len) -> 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:keysearch(Pos,2,NBL) of {value,{N,_}} -> bit_list_to_nbl(T,NBL,Pos+1,[N|Acc]); _ -> 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 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 size(Bin) == 1 -> Used = 8-Unused, <<Int:Used,_:Unused>> = Bin, int_to_bit_list(Int,[],Used). 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}) 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) -> true; check_null('NULL','NULL') -> true; check_null(_,V) -> throw({error,V}). check_objectidentifier(_,asn1_DEFAULT) -> true; check_objectidentifier(OI,OI) -> 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}) end; check_objectidentifier1([],[],_) -> 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_objectdescriptor(_,asn1_DEFAULT) -> true; check_objectdescriptor(OD,OD) -> true; check_objectdescriptor(OD,OD) -> throw({error,{not_implemented_yet,check_objectdescriptor}}). check_real(_,asn1_DEFAULT) -> true; check_real(R,R) -> true; 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:keysearch(Atom,1,Enumerations) of {value,{_,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]) -> check_restrictedstring(Rest1,Rest2); check_restrictedstring([V1|Rest1],[V2|Rest2]) -> check_restrictedstring(V1,V2), check_restrictedstring(Rest1,Rest2); %% tuple format of value check_restrictedstring({V1,V2},[V1,V2]) -> true; check_restrictedstring([V1,V2],{V1,V2}) -> true; %% quadruple format of value check_restrictedstring({V1,V2,V3,V4},[V1,V2,V3,V4]) -> true; 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}}). transform_to_EXTERNAL1990(Val) when is_tuple(Val),size(Val) == 4 -> transform_to_EXTERNAL1990(tuple_to_list(Val),[]); transform_to_EXTERNAL1990(Val) when is_tuple(Val) -> %% Data already in ASN1 1990 format Val. transform_to_EXTERNAL1990(['EXTERNAL'|Rest],Acc) -> transform_to_EXTERNAL1990(Rest,['EXTERNAL'|Acc]); transform_to_EXTERNAL1990([{syntax,Syntax}|Rest],Acc) -> transform_to_EXTERNAL1990(Rest,[asn1_NOVALUE,Syntax|Acc]); transform_to_EXTERNAL1990([{'presentation-context-id',PCid}|Rest],Acc) -> transform_to_EXTERNAL1990(Rest,[PCid,asn1_NOVALUE|Acc]); transform_to_EXTERNAL1990([{'context-negotiation',Context_negot}|Rest],Acc) -> {_,Presentation_Cid,Transfer_syntax} = Context_negot, transform_to_EXTERNAL1990(Rest,[Presentation_Cid,Transfer_syntax|Acc]); transform_to_EXTERNAL1990([asn1_NOVALUE|Rest],Acc) -> transform_to_EXTERNAL1990(Rest,[asn1_NOVALUE|Acc]); transform_to_EXTERNAL1990([Data_val_desc,Data_value],Acc) when is_list(Data_value)-> list_to_tuple(lists:reverse([{'octet-aligned',Data_value}, Data_val_desc|Acc])); transform_to_EXTERNAL1990([Data_val_desc,Data_value],Acc) when is_binary(Data_value)-> list_to_tuple(lists:reverse([{'single-ASN1-type',Data_value}, Data_val_desc|Acc])); transform_to_EXTERNAL1990([Data_value],Acc) when is_list(Data_value)-> list_to_tuple(lists:reverse([{'octet-aligned',Data_value}|Acc])). transform_to_EXTERNAL1994(V={'EXTERNAL',DRef,IndRef,Data_v_desc,Encoding}) -> Identification = case {DRef,IndRef} of {DRef,asn1_NOVALUE} -> {syntax,DRef}; {asn1_NOVALUE,IndRef} -> {'presentation-context-id',IndRef}; _ -> {'context-negotiation', {'EXTERNAL_identification_context-negotiation',IndRef,DRef}} end, case Encoding of {_,Val} when is_list(Val);is_binary(Val) -> {'EXTERNAL',Identification,Data_v_desc,Val}; _ -> V end. %% dynamicsort_SET_components(Arg) -> %% Res Arg -> list() %% Res -> list() %% Sorts the elements in Arg according to the encoded tag in %% increasing order. dynamicsort_SET_components(ListOfEncCs) -> BinL = lists:map(fun(X) -> list_to_binary(X) end,ListOfEncCs), TagBinL = lists:map(fun(X) -> {{T,_,TN},_,_} = asn1rt_ber_bin:decode_tag(X), {{T,TN},X} end,BinL), ClassTagNoSorted = lists:keysort(1,TagBinL), lists:map(fun({_,El}) -> El end,ClassTagNoSorted). %% dynamicsort_SETOF(Arg) -> Res %% Arg -> list() %% Res -> list() %% Sorts the elements in Arg in increasing size dynamicsort_SETOF(ListOfEncVal) -> BinL = lists:map(fun(L) when is_list(L) -> list_to_binary(L); (B) -> B end,ListOfEncVal), lists:sort(BinL).