1%% ``Licensed under the Apache License, Version 2.0 (the "License");
2%% you may not use this file except in compliance with the License.
3%% You may obtain a copy of the License at
4%%
5%%     http://www.apache.org/licenses/LICENSE-2.0
6%%
7%% Unless required by applicable law or agreed to in writing, software
8%% distributed under the License is distributed on an "AS IS" BASIS,
9%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10%% See the License for the specific language governing permissions and
11%% limitations under the License.
12%%
13%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
14%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
15%% AB. All Rights Reserved.''
16%%
17%%     $Id: asn1rt_check.erl,v 1.1 2008/12/17 09:53:30 mikpe Exp $
18-module(asn1rt_check).
19
20-include("asn1_records.hrl").
21
22-export([check_bool/2,
23	 check_int/3,
24	 check_bitstring/3,
25	 check_octetstring/2,
26	 check_null/2,
27	 check_objectidentifier/2,
28	 check_objectdescriptor/2,
29	 check_real/2,
30	 check_enum/3,
31	 check_restrictedstring/2]).
32
33-export([transform_to_EXTERNAL1990/1,
34	 transform_to_EXTERNAL1994/1]).
35
36
37check_bool(_Bool,asn1_DEFAULT) ->
38    true;
39check_bool(Bool,Bool) when Bool == true; Bool == false ->
40    true;
41check_bool(_Bool1,Bool2) ->
42    throw({error,Bool2}).
43
44check_int(_,asn1_DEFAULT,_) ->
45    true;
46check_int(Value,Value,_) when integer(Value) ->
47    true;
48check_int(DefValue,Value,NNL) when atom(Value) ->
49    case lists:keysearch(Value,1,NNL) of
50	{value,{_,DefValue}} ->
51	    true;
52	_ ->
53	    throw({error,DefValue})
54    end;
55check_int(DefaultValue,_Value,_) ->
56    throw({error,DefaultValue}).
57
58% check_bitstring([H|T],[H|T],_) when integer(H) ->
59%     true;
60% check_bitstring(V,V,_) when integer(V) ->
61%     true;
62%% Two equal lists or integers
63check_bitstring(_,asn1_DEFAULT,_) ->
64    true;
65check_bitstring(V,V,_) ->
66    true;
67%% Default value as a list of 1 and 0 and user value as an integer
68check_bitstring(L=[H|T],Int,_) when integer(Int),integer(H) ->
69    case bit_list_to_int(L,length(T)) of
70	Int -> true;
71	_ -> throw({error,L,Int})
72    end;
73%% Default value as an integer, val as list
74check_bitstring(Int,Val,NBL) when integer(Int),list(Val) ->
75    BL = int_to_bit_list(Int,[],length(Val)),
76    check_bitstring(BL,Val,NBL);
77%% Default value and user value as lists of ones and zeros
78check_bitstring(L1=[H1|_T1],L2=[H2|_T2],NBL=[_H|_T]) when integer(H1),integer(H2) ->
79    L2new = remove_trailing_zeros(L2),
80    check_bitstring(L1,L2new,NBL);
81%% Default value as a list of 1 and 0 and user value as a list of atoms
82check_bitstring(L1=[H1|_T1],L2=[H2|_T2],NBL) when integer(H1),atom(H2) ->
83    case bit_list_to_nbl(L1,NBL,0,[]) of
84	L3 -> check_bitstring(L3,L2,NBL);
85	_ -> throw({error,L2})
86    end;
87%% Both default value and user value as a list of atoms
88check_bitstring(L1=[H1|T1],L2=[H2|_T2],_) when atom(H1),atom(H2) ->
89    length(L1) == length(L2),
90    case lists:member(H1,L2) of
91	true ->
92	    check_bitstring1(T1,L2);
93	false -> throw({error,L2})
94    end;
95%% Default value as a list of atoms and user value as a list of 1 and 0
96check_bitstring(L1=[H1|_T1],L2=[H2|_T2],NBL) when atom(H1),integer(H2) ->
97    case bit_list_to_nbl(L2,NBL,0,[]) of
98	L3 ->
99	    check_bitstring(L1,L3,NBL);
100	_ -> throw({error,L2})
101    end;
102%% User value in compact format
103check_bitstring(DefVal,CBS={_,_},NBL) ->
104    NewVal = cbs_to_bit_list(CBS),
105    check_bitstring(DefVal,NewVal,NBL);
106check_bitstring(DV,V,_) ->
107    throw({error,DV,V}).
108
109
110bit_list_to_int([0|Bs],ShL)->
111    bit_list_to_int(Bs,ShL-1) + 0;
112bit_list_to_int([1|Bs],ShL) ->
113    bit_list_to_int(Bs,ShL-1) + (1 bsl ShL);
114bit_list_to_int([],_) ->
115    0.
116
117int_to_bit_list(0,Acc,0) ->
118    Acc;
119int_to_bit_list(Int,Acc,Len) ->
120    int_to_bit_list(Int bsr 1,[Int band 1|Acc],Len - 1).
121
122bit_list_to_nbl([0|T],NBL,Pos,Acc) ->
123    bit_list_to_nbl(T,NBL,Pos+1,Acc);
124bit_list_to_nbl([1|T],NBL,Pos,Acc) ->
125    case lists:keysearch(Pos,2,NBL) of
126	{value,{N,_}} ->
127	    bit_list_to_nbl(T,NBL,Pos+1,[N|Acc]);
128	_ ->
129	    throw({error,{no,named,element,at,pos,Pos}})
130    end;
131bit_list_to_nbl([],_,_,Acc) ->
132    Acc.
133
134remove_trailing_zeros(L2) ->
135    remove_trailing_zeros1(lists:reverse(L2)).
136remove_trailing_zeros1(L) ->
137    lists:reverse(lists:dropwhile(fun(0)->true;
138				     (_) ->false
139				  end,
140				  L)).
141
142check_bitstring1([H|T],NBL) ->
143    case lists:member(H,NBL) of
144	true ->
145	    check_bitstring1(T,NBL);
146	V -> throw({error,V})
147    end;
148check_bitstring1([],_) ->
149    true.
150
151cbs_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 ->
152    [B7,B6,B5,B4,B3,B2,B1,B0|cbs_to_bit_list({Unused,Rest})];
153cbs_to_bit_list({0,<<B7:1,B6:1,B5:1,B4:1,B3:1,B2:1,B1:1,B0:1>>}) ->
154    [B7,B6,B5,B4,B3,B2,B1,B0];
155cbs_to_bit_list({Unused,Bin}) when size(Bin) == 1 ->
156    Used = 8-Unused,
157    <<Int:Used,_:Unused>> = Bin,
158    int_to_bit_list(Int,[],Used).
159
160
161check_octetstring(_,asn1_DEFAULT) ->
162    true;
163check_octetstring(L,L) ->
164    true;
165check_octetstring(L,Int) when list(L),integer(Int) ->
166    case integer_to_octetlist(Int) of
167	L -> true;
168	V -> throw({error,V})
169    end;
170check_octetstring(_,V) ->
171    throw({error,V}).
172
173integer_to_octetlist(Int) ->
174    integer_to_octetlist(Int,[]).
175integer_to_octetlist(0,Acc) ->
176    Acc;
177integer_to_octetlist(Int,Acc) ->
178    integer_to_octetlist(Int bsr 8,[(Int band 255)|Acc]).
179
180check_null(_,asn1_DEFAULT) ->
181    true;
182check_null('NULL','NULL') ->
183    true;
184check_null(_,V) ->
185    throw({error,V}).
186
187check_objectidentifier(_,asn1_DEFAULT) ->
188    true;
189check_objectidentifier(OI,OI) ->
190    true;
191check_objectidentifier(DOI,OI) when tuple(DOI),tuple(OI) ->
192    check_objectidentifier1(tuple_to_list(DOI),tuple_to_list(OI));
193check_objectidentifier(_,OI) ->
194    throw({error,OI}).
195
196check_objectidentifier1([V|Rest1],[V|Rest2]) ->
197    check_objectidentifier1(Rest1,Rest2,V);
198check_objectidentifier1([V1|Rest1],[V2|Rest2]) ->
199    case reserved_objectid(V2,[]) of
200	V1 ->
201	    check_objectidentifier1(Rest1,Rest2,[V1]);
202	V ->
203	    throw({error,V})
204    end.
205check_objectidentifier1([V|Rest1],[V|Rest2],Above) ->
206    check_objectidentifier1(Rest1,Rest2,[V|Above]);
207check_objectidentifier1([V1|Rest1],[V2|Rest2],Above) ->
208    case reserved_objectid(V2,Above) of
209	V1 ->
210	    check_objectidentifier1(Rest1,Rest2,[V1|Above]);
211	V ->
212	    throw({error,V})
213    end;
214check_objectidentifier1([],[],_) ->
215    true;
216check_objectidentifier1(_,V,_) ->
217    throw({error,object,identifier,V}).
218
219%% ITU-T Rec. X.680 Annex B - D
220reserved_objectid('itu-t',[]) -> 0;
221reserved_objectid('ccitt',[]) -> 0;
222%% arcs below "itu-t"
223reserved_objectid('recommendation',[0]) -> 0;
224reserved_objectid('question',[0]) -> 1;
225reserved_objectid('administration',[0]) -> 2;
226reserved_objectid('network-operator',[0]) -> 3;
227reserved_objectid('identified-organization',[0]) -> 4;
228
229reserved_objectid(iso,[]) -> 1;
230%% arcs below "iso", note that number 1 is not used
231reserved_objectid('standard',[1]) -> 0;
232reserved_objectid('member-body',[1]) -> 2;
233reserved_objectid('identified-organization',[1]) -> 3;
234
235reserved_objectid('joint-iso-itu-t',[]) -> 2;
236reserved_objectid('joint-iso-ccitt',[]) -> 2;
237
238reserved_objectid(_,_) -> false.
239
240
241check_objectdescriptor(_,asn1_DEFAULT) ->
242    true;
243check_objectdescriptor(OD,OD) ->
244    true;
245check_objectdescriptor(OD,OD) ->
246    throw({error,{not_implemented_yet,check_objectdescriptor}}).
247
248check_real(_,asn1_DEFAULT) ->
249    true;
250check_real(R,R) ->
251    true;
252check_real(_,_) ->
253    throw({error,{not_implemented_yet,check_real}}).
254
255check_enum(_,asn1_DEFAULT,_) ->
256    true;
257check_enum(Val,Val,_) ->
258    true;
259check_enum(Int,Atom,Enumerations) when integer(Int),atom(Atom) ->
260    case lists:keysearch(Atom,1,Enumerations) of
261	{value,{_,Int}} -> true;
262	_ -> throw({error,{enumerated,Int,Atom}})
263    end;
264check_enum(DefVal,Val,_) ->
265    throw({error,{enumerated,DefVal,Val}}).
266
267
268check_restrictedstring(_,asn1_DEFAULT) ->
269    true;
270check_restrictedstring(Val,Val) ->
271    true;
272check_restrictedstring([V|Rest1],[V|Rest2]) ->
273    check_restrictedstring(Rest1,Rest2);
274check_restrictedstring([V1|Rest1],[V2|Rest2]) ->
275    check_restrictedstring(V1,V2),
276    check_restrictedstring(Rest1,Rest2);
277%% tuple format of value
278check_restrictedstring({V1,V2},[V1,V2]) ->
279    true;
280check_restrictedstring([V1,V2],{V1,V2}) ->
281    true;
282%% quadruple format of value
283check_restrictedstring({V1,V2,V3,V4},[V1,V2,V3,V4]) ->
284    true;
285check_restrictedstring([V1,V2,V3,V4],{V1,V2,V3,V4}) ->
286    true;
287%% character string list
288check_restrictedstring(V1,V2) when list(V1),tuple(V2) ->
289    check_restrictedstring(V1,tuple_to_list(V2));
290check_restrictedstring(V1,V2) ->
291    throw({error,{restricted,string,V1,V2}}).
292
293transform_to_EXTERNAL1990(Val) when tuple(Val),size(Val) == 4 ->
294    transform_to_EXTERNAL1990(tuple_to_list(Val),[]);
295transform_to_EXTERNAL1990(Val) when tuple(Val) ->
296    %% Data already in ASN1 1990 format
297    Val.
298
299transform_to_EXTERNAL1990(['EXTERNAL'|Rest],Acc) ->
300    transform_to_EXTERNAL1990(Rest,['EXTERNAL'|Acc]);
301transform_to_EXTERNAL1990([{syntax,Syntax}|Rest],Acc) ->
302    transform_to_EXTERNAL1990(Rest,[asn1_NOVALUE,Syntax|Acc]);
303transform_to_EXTERNAL1990([{'presentation-context-id',PCid}|Rest],Acc) ->
304    transform_to_EXTERNAL1990(Rest,[PCid,asn1_NOVALUE|Acc]);
305transform_to_EXTERNAL1990([{'context-negotiation',Context_negot}|Rest],Acc) ->
306    {_,Presentation_Cid,Transfer_syntax} = Context_negot,
307    transform_to_EXTERNAL1990(Rest,[Transfer_syntax,Presentation_Cid|Acc]);
308transform_to_EXTERNAL1990([asn1_NOVALUE|Rest],Acc) ->
309    transform_to_EXTERNAL1990(Rest,[asn1_NOVALUE|Acc]);
310transform_to_EXTERNAL1990([Data_val_desc,Data_value],Acc) when list(Data_value)->
311    list_to_tuple(lists:reverse([{'octet-aligned',Data_value},
312				 Data_val_desc|Acc]));
313transform_to_EXTERNAL1990([Data_value],Acc) when list(Data_value)->
314    list_to_tuple(lists:reverse([{'octet-aligned',Data_value}|Acc])).
315
316
317transform_to_EXTERNAL1994(V={'EXTERNAL',DRef,IndRef,Data_v_desc,Encoding}) ->
318    Identification =
319	case {DRef,IndRef} of
320	    {DRef,asn1_NOVALUE} ->
321		{syntax,DRef};
322	    {asn1_NOVALUE,IndRef} ->
323		{'presentation-context-id',IndRef};
324	     _ ->
325		{'context-negotiation',
326		 {'EXTERNAL_identification_context-negotiation',IndRef,DRef}}
327	end,
328    case Encoding of
329	{_,Val} when list(Val) ->
330	    {'EXTERNAL',Identification,Data_v_desc,Val};
331	_  ->
332	    V
333    end.
334