Skip to content

Commit

Permalink
Merge branch 'maint'
Browse files Browse the repository at this point in the history
* maint:
  Fix broken handling of default values for BIT STRINGs
  • Loading branch information
bjorng committed Oct 18, 2013
2 parents 0aae26d + 666b46a commit 5a69967
Show file tree
Hide file tree
Showing 13 changed files with 487 additions and 177 deletions.
105 changes: 35 additions & 70 deletions lib/asn1/src/asn1ct_check.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2534,89 +2534,54 @@ normalize_integer(S,Int=#'Externalvaluereference'{value=Name},Type) ->
normalize_integer(_,Int,_) ->
exit({'Unknown INTEGER value',Int}).

normalize_bitstring(S,Value,Type)->
%% There are four different Erlang formats of BIT STRING:
%% 1 - a list of ones and zeros.
%% 2 - a list of atoms.
%% 3 - as an integer, for instance in hexadecimal form.
%% 4 - as a tuple {Unused, Binary} where Unused is an integer
%% and tells how many bits of Binary are unused.
%%
%% normalize_bitstring/3 transforms Value according to:
%% A to 3,
%% B to 1,
%% C to 1 or 3
%% D to 2,
%% Value can be on format:
%% A - {hstring, String}, where String is a hexadecimal string.
%% B - {bstring, String}, where String is a string on bit format
%% C - #'Externalvaluereference'{value=V}, where V is a defined value
%% D - list of #'Externalvaluereference', where each value component
%% is an identifier corresponing to NamedBits in Type.
%% E - list of ones and zeros, if Value already is normalized.
%% normalize_bitstring(S, Value, Type) -> bitstring()
%% Convert a literal value for a BIT STRING to an Erlang bit string.
%%
normalize_bitstring(S, Value, Type)->
case Value of
{hstring,String} when is_list(String) ->
hstring_to_int(String);
hstring_to_bitstring(String);
{bstring,String} when is_list(String) ->
bstring_to_bitlist(String);
Rec when is_record(Rec,'Externalvaluereference') ->
get_normalized_value(S,Value,Type,
fun normalize_bitstring/3,[]);
bstring_to_bitstring(String);
#'Externalvaluereference'{} ->
get_normalized_value(S, Value, Type,
fun normalize_bitstring/3, []);
RecList when is_list(RecList) ->
case Type of
NBL when is_list(NBL) ->
F = fun(#'Externalvaluereference'{value=Name}) ->
case lists:keysearch(Name,1,NBL) of
{value,{Name,_}} ->
Name;
Other ->
throw({error,Other})
end;
(I) when I =:= 1; I =:= 0 ->
I;
(Other) ->
throw({error,Other})
end,
case catch lists:map(F,RecList) of
{error,Reason} ->
asn1ct:warning("default value not "
"compatible with type definition ~p~n",
[Reason],S,
"default value not "
"compatible with type definition"),
Value;
NewList ->
NewList
end;
_ ->
F = fun(#'Externalvaluereference'{value=Name}) ->
case lists:keymember(Name, 1, Type) of
true -> Name;
false -> throw({error,false})
end;
(Name) when is_atom(Name) ->
%% Already normalized.
Name;
(Other) ->
throw({error,Other})
end,
try
lists:map(F, RecList)
catch
throw:{error,Reason} ->
asn1ct:warning("default value not "
"compatible with type definition ~p~n",
[RecList],S,
[Reason],S,
"default value not "
"compatible with type definition"),
Value
end;
{Name,String} when is_atom(Name) ->
normalize_bitstring(S,String,Type);
Other ->
asn1ct:warning("illegal default value ~p~n",[Other],S,
"illegal default value"),
Value
Bs when is_bitstring(Bs) ->
%% Already normalized.
Bs
end.

hstring_to_int(L) when is_list(L) ->
hstring_to_int(L,0).
hstring_to_int([H|T],Acc) when H >= $A, H =< $F ->
hstring_to_int(T,(Acc bsl 4) + (H - $A + 10) ) ;
hstring_to_int([H|T],Acc) when H >= $0, H =< $9 ->
hstring_to_int(T,(Acc bsl 4) + (H - $0));
hstring_to_int([],Acc) ->
Acc.
hstring_to_bitstring(L) ->
<< <<(hex_to_int(D)):4>> || D <- L >>.

bstring_to_bitlist([H|T]) when H == $0; H == $1 ->
[H - $0 | bstring_to_bitlist(T)];
bstring_to_bitlist([]) ->
[].
bstring_to_bitstring(L) ->
<< <<(D-$0):1>> || D <- L >>.

hex_to_int(D) when $0 =< D, D =< $9 -> D - $0;
hex_to_int(D) when $A =< D, D =< $F -> D - ($A - 10).

%% normalize_octetstring/1 changes representation of input Value to a
%% list of octets.
Expand Down
3 changes: 2 additions & 1 deletion lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1155,7 +1155,8 @@ gen_dec_line(Erules,TopType,Cname,CTags,Type,OptOrMand,DecObjInf) ->

emit([indent(4),"_ ->",nl]),
case OptOrMand of
{'DEFAULT', Def} ->
{'DEFAULT', Def0} ->
Def = asn1ct_gen:conform_value(Type, Def0),
emit([indent(8),"{",{asis,Def},",",{prev,tlv},"}",nl]);
'OPTIONAL' ->
emit([indent(8),"{ asn1_NOVALUE, ",{prev,tlv},"}",nl])
Expand Down
71 changes: 54 additions & 17 deletions lib/asn1/src/asn1ct_constructed_per.erl
Original file line number Diff line number Diff line change
Expand Up @@ -770,8 +770,10 @@ optionals(L) -> optionals(L,[],2).

optionals([#'ComponentType'{prop='OPTIONAL'}|Rest], Acc, Pos) ->
optionals(Rest, [Pos|Acc], Pos+1);
optionals([#'ComponentType'{prop={'DEFAULT',Val}}|Rest], Acc, Pos) ->
optionals(Rest, [{Pos,Val}|Acc], Pos+1);
optionals([#'ComponentType'{typespec=T,prop={'DEFAULT',Val}}|Rest],
Acc, Pos) ->
Vals = def_values(T, Val),
optionals(Rest, [{Pos,Vals}|Acc], Pos+1);
optionals([#'ComponentType'{}|Rest], Acc, Pos) ->
optionals(Rest, Acc, Pos+1);
optionals([], Acc, _) ->
Expand Down Expand Up @@ -888,7 +890,8 @@ gen_enc_components_call1(Erule,TopType,
optional ->
asn1ct_imm:enc_absent(Element, [asn1_NOVALUE], Imm1);
{default,Def} ->
asn1ct_imm:enc_absent(Element, [asn1_DEFAULT,Def], Imm1)
DefValues = def_values(Type, Def),
asn1ct_imm:enc_absent(Element, DefValues, Imm1)
end,
Imm = case Imm2 of
[] -> [];
Expand All @@ -899,6 +902,38 @@ gen_enc_components_call1(_Erule,_TopType,[],Pos,_,_, Acc) ->
ImmList = lists:reverse(Acc),
{ImmList,Pos}.

def_values(#type{def=#'Externaltypereference'{module=Mod,type=Type}}, Def) ->
#typedef{typespec=T} = asn1_db:dbget(Mod, Type),
def_values(T, Def);
def_values(#type{def={'BIT STRING',[]}}, Bs) when is_bitstring(Bs) ->
ListBs = [B || <<B:1>> <= Bs],
IntBs = lists:foldl(fun(B, A) ->
(A bsl 1) bor B
end, 0, lists:reverse(ListBs)),
Sz = bit_size(Bs),
Compact = case 8 - Sz rem 8 of
8 ->
{0,Bs};
Unused ->
{Unused,<<Bs:Sz/bits,0:Unused>>}
end,
[asn1_DEFAULT,Bs,Compact,ListBs,IntBs];
def_values(#type{def={'BIT STRING',[_|_]=Ns}}, List) when is_list(List) ->
Bs = asn1ct_gen:named_bitstring_value(List, Ns),
ListBs = [B || <<B:1>> <= Bs],
IntBs = lists:foldl(fun(B, A) ->
(A bsl 1) bor B
end, 0, lists:reverse(ListBs)),
Args = [List,Bs,ListBs,IntBs],
{call,per_common,is_default_bitstring,Args};
def_values(#type{def={'INTEGER',Ns}}, Def) ->
[asn1_DEFAULT,Def|case lists:keyfind(Def, 2, Ns) of
false -> [];
{Val,Def} -> [Val]
end];
def_values(_, Def) ->
[asn1_DEFAULT,Def].

gen_enc_line_imm(Erule, TopType, Cname, Type, Element, DynamicEnc, Ext) ->
Imm0 = gen_enc_line_imm_1(Erule, TopType, Cname, Type,
Element, DynamicEnc),
Expand Down Expand Up @@ -1207,7 +1242,8 @@ gen_dec_comp_call(Comp, Erule, TopType, Tpos, OptTable, DecInfObj,

comp_call_pre_post(noext, mandatory, _, _, _, _, _, _) ->
{[],[]};
comp_call_pre_post(noext, Prop, _, _, TextPos, OptTable, NumOptionals, Ext) ->
comp_call_pre_post(noext, Prop, _, Type, TextPos,
OptTable, NumOptionals, Ext) ->
%% OPTIONAL or DEFAULT
OptPos = get_optionality_pos(TextPos, OptTable),
Element = case NumOptionals - OptPos of
Expand All @@ -1225,7 +1261,7 @@ comp_call_pre_post(noext, Prop, _, _, TextPos, OptTable, NumOptionals, Ext) ->
emit([";",nl,
"0 ->",nl,
"{"]),
gen_dec_component_no_val(Ext, Prop),
gen_dec_component_no_val(Ext, Type, Prop),
emit([",",{curr,bytes},"}",nl,
"end"]),
St
Expand All @@ -1247,10 +1283,10 @@ comp_call_pre_post({ext,_,_}, Prop, Pos, Type, _, _, _, Ext) ->
components=ExtGroupCompList2}}
when is_integer(Number2)->
emit("{extAddGroup,"),
gen_dec_extaddGroup_no_val(Ext, ExtGroupCompList2),
gen_dec_extaddGroup_no_val(Ext, Type, ExtGroupCompList2),
emit("}");
_ ->
gen_dec_component_no_val(Ext, Prop)
gen_dec_component_no_val(Ext, Type, Prop)
end,
emit([",",{curr,bytes},"}",nl,
"end"]),
Expand All @@ -1265,21 +1301,22 @@ is_mandatory_predef_tab_c(_, _, {"got objfun through args","ObjFun"}) ->
is_mandatory_predef_tab_c(_,_,_) ->
true.

gen_dec_extaddGroup_no_val(Ext,[#'ComponentType'{prop=Prop}])->
gen_dec_component_no_val(Ext,Prop),
gen_dec_extaddGroup_no_val(Ext, Type, [#'ComponentType'{prop=Prop}])->
gen_dec_component_no_val(Ext, Type, Prop),
ok;
gen_dec_extaddGroup_no_val(Ext,[#'ComponentType'{prop=Prop}|Rest])->
gen_dec_component_no_val(Ext,Prop),
emit({","}),
gen_dec_extaddGroup_no_val(Ext,Rest);
gen_dec_extaddGroup_no_val(_, []) ->
gen_dec_extaddGroup_no_val(Ext, Type, [#'ComponentType'{prop=Prop}|Rest])->
gen_dec_component_no_val(Ext, Type, Prop),
emit(","),
gen_dec_extaddGroup_no_val(Ext, Type, Rest);
gen_dec_extaddGroup_no_val(_, _, []) ->
ok.

gen_dec_component_no_val(_,{'DEFAULT',DefVal}) ->
gen_dec_component_no_val(_, Type, {'DEFAULT',DefVal0}) ->
DefVal = asn1ct_gen:conform_value(Type, DefVal0),
emit([{asis,DefVal}]);
gen_dec_component_no_val(_,'OPTIONAL') ->
gen_dec_component_no_val(_, _, 'OPTIONAL') ->
emit({"asn1_NOVALUE"});
gen_dec_component_no_val({ext,_,_},mandatory) ->
gen_dec_component_no_val({ext,_,_}, _, mandatory) ->
emit({"asn1_NOVALUE"}).


Expand Down
44 changes: 38 additions & 6 deletions lib/asn1/src/asn1ct_gen.erl
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@
insert_once/2,
ct_gen_module/1,
index2suffix/1,
get_record_name_prefix/0]).
get_record_name_prefix/0,
conform_value/2,
named_bitstring_value/2]).
-export([pgen/5,
mk_var/1,
un_hyphen_var/1]).
Expand Down Expand Up @@ -1485,8 +1487,14 @@ gen_prim_check_call(PrimType, Default, Element, Type) ->
end,
check_call(check_int, [Default,Element,{asis,NNL}]);
'BIT STRING' ->
{_,NBL} = Type#type.def,
check_call(check_bitstring, [Default,Element,{asis,NBL}]);
case Type#type.def of
{_,[]} ->
check_call(check_bitstring,
[Default,Element]);
{_,[_|_]=NBL} ->
check_call(check_named_bitstring,
[Default,Element,{asis,NBL}])
end;
'OCTET STRING' ->
check_call(check_octetstring, [Default,Element]);
'NULL' ->
Expand Down Expand Up @@ -1640,9 +1648,33 @@ unify_if_string(PrimType) ->
Other -> Other
end.




conform_value(#type{def={'BIT STRING',[]}}, Bs) ->
case asn1ct:get_bit_string_format() of
compact when is_binary(Bs) ->
{0,Bs};
compact when is_bitstring(Bs) ->
Sz = bit_size(Bs),
Unused = 8 - bit_size(Bs),
{Unused,<<Bs:Sz/bits,0:Unused>>};
legacy ->
[B || <<B:1>> <= Bs];
bitstring when is_bitstring(Bs) ->
Bs
end;
conform_value(_, Value) -> Value.

named_bitstring_value(List, Names) ->
Int = lists:foldl(fun(N, A) ->
{N,Pos} = lists:keyfind(N, 1, Names),
A bor (1 bsl Pos)
end, 0, List),
named_bitstring_value_1(<<>>, Int).

named_bitstring_value_1(Bs, 0) ->
Bs;
named_bitstring_value_1(Bs, Int) ->
B = Int band 1,
named_bitstring_value_1(<<Bs/bitstring,B:1>>, Int bsr 1).

get_inner(A) when is_atom(A) -> A;
get_inner(Ext) when is_record(Ext,'Externaltypereference') -> Ext;
Expand Down
23 changes: 18 additions & 5 deletions lib/asn1/src/asn1ct_imm.erl
Original file line number Diff line number Diff line change
Expand Up @@ -319,14 +319,22 @@ per_enc_extensions(Val0, Pos0, NumBits, Aligned) when NumBits > 0 ->
{'cond',[[{eq,Bitmap,0}],
['_'|Length ++ PutBits]],{var,"Extensions"}}].

per_enc_optional(Val0, {Pos,Def}, _Aligned) when is_integer(Pos) ->
per_enc_optional(Val0, {Pos,DefVals}, _Aligned) when is_integer(Pos),
is_list(DefVals) ->
Val1 = lists:concat(["element(",Pos,", ",Val0,")"]),
{B,[Val]} = mk_vars(Val1, []),
Zero = {put_bits,0,1,[1]},
One = {put_bits,1,1,[1]},
B++[{'cond',[[{eq,Val,asn1_DEFAULT},Zero],
[{eq,Val,Def},Zero],
['_',One]]}];
B++[{'cond',
[[{eq,Val,DefVal},Zero] || DefVal <- DefVals] ++ [['_',One]]}];
per_enc_optional(Val0, {Pos,{call,M,F,A}}, _Aligned) when is_integer(Pos) ->
Val1 = lists:concat(["element(",Pos,", ",Val0,")"]),
{B,[Val,Tmp]} = mk_vars(Val1, [tmp]),
Zero = {put_bits,0,1,[1]},
One = {put_bits,1,1,[1]},
B++[{call,M,F,[Val|A],Tmp},
{'cond',
[[{eq,Tmp,true},Zero],['_',One]]}];
per_enc_optional(Val0, Pos, _Aligned) when is_integer(Pos) ->
Val1 = lists:concat(["element(",Pos,", ",Val0,")"]),
{B,[Val]} = mk_vars(Val1, []),
Expand All @@ -352,7 +360,12 @@ per_enc_sof(Val0, Constraint, ElementVar, ElementImm, Aligned) ->
PreBlock ++ EncLen ++ Lc
end.

enc_absent(Val0, AbsVals, Body) ->
enc_absent(Val0, {call,M,F,A}, Body) ->
{B,[Var,Tmp]} = mk_vars(Val0, [tmp]),
B++[{call,M,F,[Var|A],Tmp},
{'cond',
[[{eq,Tmp,true}],['_'|Body]]}];
enc_absent(Val0, AbsVals, Body) when is_list(AbsVals) ->
{B,[Var]} = mk_vars(Val0, []),
Cs = [[{eq,Var,Aval}] || Aval <- AbsVals] ++ [['_'|Body]],
B++build_cond(Cs).
Expand Down
Loading

0 comments on commit 5a69967

Please sign in to comment.