Skip to content

Commit

Permalink
Add and use asn1rtt_check
Browse files Browse the repository at this point in the history
  • Loading branch information
bjorng committed Jan 22, 2013
1 parent 8cc1f6e commit 14ccfeb
Show file tree
Hide file tree
Showing 3 changed files with 297 additions and 29 deletions.
3 changes: 2 additions & 1 deletion lib/asn1/src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ release_docs_spec:
# Run-time library template files.
#

RT_TEMPLATES = asn1rtt_per_common \
RT_TEMPLATES = asn1rtt_check \
asn1rtt_per_common \
asn1rtt_real_common \
asn1rtt_ber \
asn1rtt_per \
Expand Down
47 changes: 19 additions & 28 deletions lib/asn1/src/asn1ct_gen.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1496,50 +1496,41 @@ gen_check_call(TopType,Cname,Type,InnerType,WhatKind,DefaultValue,Element) ->
emit(["fun() -> true end ()"])
end.

gen_prim_check_call(PrimType,DefaultValue,Element,Type) ->
gen_prim_check_call(PrimType, Default, Element, Type) ->
case unify_if_string(PrimType) of
'BOOLEAN' ->
emit({"asn1rt_check:check_bool(",DefaultValue,", ",
Element,")"});
check_call(check_bool, [Default,Element]);
'INTEGER' ->
NNL =
case Type#type.def of
{_,NamedNumberList} -> NamedNumberList;
_ -> []
end,
emit({"asn1rt_check:check_int(",DefaultValue,", ",
Element,", ",{asis,NNL},")"});
NNL = case Type#type.def of
{_,NamedNumberList} -> NamedNumberList;
_ -> []
end,
check_call(check_int, [Default,Element,{asis,NNL}]);
'BIT STRING' ->
{_,NBL} = Type#type.def,
emit({"asn1rt_check:check_bitstring(",DefaultValue,", ",
Element,", ",{asis,NBL},")"});
check_call(check_bitstring, [Default,Element,{asis,NBL}]);
'OCTET STRING' ->
emit({"asn1rt_check:check_octetstring(",DefaultValue,", ",
Element,")"});
check_call(check_octetstring, [Default,Element]);
'NULL' ->
emit({"asn1rt_check:check_null(",DefaultValue,", ",
Element,")"});
check_call(check_null, [Default,Element]);
'OBJECT IDENTIFIER' ->
emit({"asn1rt_check:check_objectidentifier(",DefaultValue,
", ",Element,")"});
check_call(check_objectidentifier, [Default,Element]);
'RELATIVE-OID' ->
emit({"asn1rt_check:check_objectidentifier(",DefaultValue,
", ",Element,")"});
check_call(check_objectidentifier, [Default,Element]);
'ObjectDescriptor' ->
emit({"asn1rt_check:check_objectdescriptor(",DefaultValue,
", ",Element,")"});
check_call(check_objectdescriptor, [Default,Element]);
'REAL' ->
emit({"asn1rt_check:check_real(",DefaultValue,
", ",Element,")"});
check_call(check_real, [Default,Element]);
'ENUMERATED' ->
{_,Enumerations} = Type#type.def,
emit({"asn1rt_check:check_enum(",DefaultValue,
", ",Element,", ",{asis,Enumerations},")"});
check_call(check_enum, [Default,Element,{asis,Enumerations}]);
restrictedstring ->
emit({"asn1rt_check:check_restrictedstring(",DefaultValue,
", ",Element,")"})
check_call(check_restrictedstring, [Default,Element])
end.

check_call(F, Args) ->
asn1ct_func:call(check, F, Args).

%% lokahead_innertype/3 traverses Type and checks if check functions
%% have to be generated, i.e. for all constructed or referenced types.
lookahead_innertype(Name,'SEQUENCE',Type) ->
Expand Down
276 changes: 276 additions & 0 deletions lib/asn1/src/asn1rtt_check.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2012. 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(asn1rtt_check).

-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]).

check_bool(_Bool, asn1_DEFAULT) ->
true;
check_bool(Bool, Bool) when is_boolean(Bool) ->
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:keyfind(Value, 1, NNL) of
{_,DefValue} ->
true;
_ ->
throw({error,DefValue})
end;
check_int(DefaultValue, _Value, _) ->
throw({error,DefaultValue}).

%% 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:keyfind(Pos, 2, NBL) of
{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 byte_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 byte_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:keyfind(Atom, 1, Enumerations) of
{_,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}}).

0 comments on commit 14ccfeb

Please sign in to comment.