aboutsummaryrefslogtreecommitdiffstats
path: root/lib/asn1/src/asn1rtt_per.erl
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2013-09-04 13:20:15 +0200
committerBjörn Gustavsson <[email protected]>2013-09-04 13:20:48 +0200
commit93fe50a6e3f685e77a48921273559b6f03b89fb8 (patch)
tree09e5b7e0deb680ee2347f5a0c96be9c7b00d5e74 /lib/asn1/src/asn1rtt_per.erl
parent053b721841efb06d3339c0376783a6dd09e625b5 (diff)
parenta2792ebf8b46903bd05b05288539482722adfa51 (diff)
downloadotp-93fe50a6e3f685e77a48921273559b6f03b89fb8.tar.gz
otp-93fe50a6e3f685e77a48921273559b6f03b89fb8.tar.bz2
otp-93fe50a6e3f685e77a48921273559b6f03b89fb8.zip
Merge branch 'bjorn/asn1/optimize-per-encoding' into maint
OTP-11300 OTP-11262 * bjorn/asn1/optimize-per-encoding: (25 commits) asn1ct_constucted_per: Directly call asn1ct_gen_per Clean up handling of .asn1db files PER, UPER: Fix encoding/decoding of open types greater than 16K PER, UPER: Optimize table constraints PER, UPER: Optimize encoding using an intermediate format Refactor decoding of components of SEQUENCE OF / SET OF PER,UPER: Get rid of unused 'telltype' argument in decoding functions Optimize the generated encode/2 function UPER: Optimize complete/1 Clean up checking of objects Improve tests of deep table constraints BER: Handle multiple optional SEQUENCE fields with table constraints Test OPTIONAL and DEFAULT for open types PER/UPER: Fix encoding of an object set with multiple inlined constructs Remove broken support for multiple UNIQUE Extend the test for parameterized information objects asn1_SUITE: Remove off-topic (and slow) smp/1 test case SeqOf: Add more tricky SEQUENCE OF tests Clean up handling of extension addition groups Refactor encoding of REAL ...
Diffstat (limited to 'lib/asn1/src/asn1rtt_per.erl')
-rw-r--r--lib/asn1/src/asn1rtt_per.erl876
1 files changed, 58 insertions, 818 deletions
diff --git a/lib/asn1/src/asn1rtt_per.erl b/lib/asn1/src/asn1rtt_per.erl
index 9f4b7500d8..672c84593c 100644
--- a/lib/asn1/src/asn1rtt_per.erl
+++ b/lib/asn1/src/asn1rtt_per.erl
@@ -18,62 +18,7 @@
%%
-module(asn1rtt_per).
--export([setext/1, fixextensions/2,
- skipextensions/3,
- set_choice/3,encode_integer/2,
- encode_small_number/1,
- encode_constrained_number/2,
- encode_length/1,
- encode_length/2,
- encode_bit_string/3,
- encode_object_identifier/1,
- encode_relative_oid/1,
- complete/1,
- encode_open_type/1,
- encode_GeneralString/2,
- encode_GraphicString/2,
- encode_TeletexString/2,
- encode_VideotexString/2,
- encode_ObjectDescriptor/2,
- encode_UTF8String/1,
- encode_octet_string/2,
- encode_known_multiplier_string/4,
- octets_to_complete/2]).
-
--define('16K',16384).
--define('32K',32768).
--define('64K',65536).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% setext(true|false) -> CompleteList
-%%
-
-setext(false) ->
- [0];
-setext(true) ->
- [1].
-
-fixextensions({ext,ExtPos,ExtNum},Val) ->
- case fixextensions(ExtPos,ExtNum+ExtPos,Val,0) of
- 0 -> [];
- ExtBits ->
- [encode_small_length(ExtNum)|pre_complete_bits(ExtNum,ExtBits)]
- end.
-
-fixextensions(Pos,MaxPos,_,Acc) when Pos >= MaxPos ->
- Acc;
-fixextensions(Pos,ExtPos,Val,Acc) ->
- Bit = case catch(element(Pos+1,Val)) of
- asn1_NOVALUE ->
- 0;
- asn1_NOEXTVALUE ->
- 0;
- {'EXIT',_} ->
- 0;
- _ ->
- 1
- end,
- fixextensions(Pos+1,ExtPos,Val,(Acc bsl 1)+Bit).
+-export([skipextensions/3,complete/1]).
skipextensions(Bytes0, Nr, ExtensionBitstr) when is_bitstring(ExtensionBitstr) ->
Prev = Nr - 1,
@@ -95,270 +40,6 @@ align(BitStr) when is_bitstring(BitStr) ->
<<_:AlignBits,Rest/binary>> = BitStr,
Rest.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% set_choice(Alt,Choices,Altnum) -> ListofBitSettings
-%% Alt = atom()
-%% Altnum = integer() | {integer(),integer()}% number of alternatives
-%% Choices = [atom()] | {[atom()],[atom()]}
-%% When Choices is a tuple the first list is the Rootset and the
-%% second is the Extensions and then Altnum must also be a tuple with the
-%% lengths of the 2 lists
-%%
-set_choice(Alt,{L1,L2},{Len1,_Len2}) ->
- case set_choice_tag(Alt,L1) of
- N when is_integer(N), Len1 > 1 ->
- [0, % the value is in the root set
- encode_constrained_number({0,Len1-1},N)];
- N when is_integer(N) ->
- [0]; % no encoding if only 0 or 1 alternative
- false ->
- [1, % extension value
- case set_choice_tag(Alt, L2) of
- N2 when is_integer(N2) ->
- encode_small_number(N2);
- false ->
- unknown_choice_alt
- end]
- end;
-set_choice(Alt, L, Len) ->
- case set_choice_tag(Alt, L) of
- N when is_integer(N), Len > 1 ->
- encode_constrained_number({0,Len-1},N);
- N when is_integer(N) ->
- []; % no encoding if only 0 or 1 alternative
- false ->
- [unknown_choice_alt]
- end.
-
-set_choice_tag(Alt,Choices) ->
- set_choice_tag(Alt,Choices,0).
-
-set_choice_tag(Alt,[Alt|_Rest],Tag) ->
- Tag;
-set_choice_tag(Alt,[_H|Rest],Tag) ->
- set_choice_tag(Alt,Rest,Tag+1);
-set_choice_tag(_Alt,[],_Tag) ->
- false.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% encode_open_type(Constraint, Value) -> CompleteList
-%% Value = list of bytes of an already encoded value (the list must be flat)
-%% | binary
-%% Contraint = not used in this version
-%%
-encode_open_type(Val) ->
- case byte_size(Val) of
- Size when Size > 255 ->
- [encode_length(Size),21,<<Size:16>>,Val]; % octets implies align
- Size ->
- [encode_length(Size),20,Size,Val]
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% encode_integer(Constraint, Value) -> CompleteList
-%%
-encode_integer([{Rc,_Ec}],Val) when is_tuple(Rc) ->
- try
- [0|encode_integer([Rc], Val)]
- catch
- _:{error,{asn1,_}} ->
- [1|encode_unconstrained_number(Val)]
- end;
-encode_integer([], Val) ->
- encode_unconstrained_number(Val);
-%% The constraint is the effective constraint, and in this case is a number
-encode_integer([{'SingleValue',V}], V) ->
- [];
-encode_integer([{'ValueRange',{Lb,Ub}=VR,Range,PreEnc}],Val)
- when Val >= Lb, Ub >= Val ->
- %% this case when NamedNumberList
- encode_constrained_number(VR, Range, PreEnc, Val);
-encode_integer([{'ValueRange',{Lb,'MAX'}}], Val) when Lb =< Val ->
- encode_semi_constrained_number(Lb, Val);
-encode_integer([{'ValueRange',{'MIN',_}}], Val) ->
- encode_unconstrained_number(Val);
-encode_integer([{'ValueRange',VR={_Lb,_Ub}}], Val) ->
- encode_constrained_number(VR, Val);
-encode_integer(_,Val) ->
- exit({error,{asn1,{illegal_value,Val}}}).
-
-
-%% X.691:10.6 Encoding of a normally small non-negative whole number
-%% Use this for encoding of CHOICE index if there is an extension marker in
-%% the CHOICE
-encode_small_number(Val) when Val < 64 ->
- [10,7,Val];
-encode_small_number(Val) ->
- [1|encode_semi_constrained_number(0, Val)].
-
-%% X.691:10.7 Encoding of a semi-constrained whole number
-encode_semi_constrained_number(Lb, Val) ->
- Val2 = Val - Lb,
- Oct = eint_positive(Val2),
- Len = length(Oct),
- if
- Len < 128 ->
- [20,Len+1,Len|Oct];
- Len < 256 ->
- [encode_length(Len),20,Len|Oct];
- true ->
- [encode_length(Len),21,<<Len:16>>|Oct]
- end.
-
-encode_constrained_number({Lb,_Ub},_Range,{bits,N},Val) ->
- Val2 = Val-Lb,
- [10,N,Val2];
-encode_constrained_number({Lb,_Ub},_Range,{octets,N},Val) when N < 256->
- %% N is 8 or 16 (1 or 2 octets)
- Val2 = Val-Lb,
- [20,N,Val2];
-encode_constrained_number({Lb,_Ub},_Range,{octets,N},Val) -> % N>255
- %% N is 8 or 16 (1 or 2 octets)
- Val2 = Val-Lb,
- [21,<<N:16>>,Val2];
-encode_constrained_number({Lb,_Ub},Range,_,Val) ->
- Val2 = Val-Lb,
- if
- Range =< 16#1000000 -> % max 3 octets
- Octs = eint_positive(Val2),
- L = length(Octs),
- [encode_length({1,3},L),[20,L,Octs]];
- Range =< 16#100000000 -> % max 4 octets
- Octs = eint_positive(Val2),
- L = length(Octs),
- [encode_length({1,4},L),[20,L,Octs]];
- Range =< 16#10000000000 -> % max 5 octets
- Octs = eint_positive(Val2),
- L = length(Octs),
- [encode_length({1,5},L),[20,L,Octs]];
- true ->
- exit({not_supported,{integer_range,Range}})
- end.
-
-encode_constrained_number({Lb,Ub}, Val) when Val >= Lb, Ub >= Val ->
- Range = Ub - Lb + 1,
- Val2 = Val - Lb,
- if
- Range == 1 -> [];
- Range == 2 ->
- [Val2];
- Range =< 4 ->
- [10,2,Val2];
- Range =< 8 ->
- [10,3,Val2];
- Range =< 16 ->
- [10,4,Val2];
- Range =< 32 ->
- [10,5,Val2];
- Range =< 64 ->
- [10,6,Val2];
- Range =< 128 ->
- [10,7,Val2];
- Range =< 255 ->
- [10,8,Val2];
- Range =< 256 ->
- [20,1,Val2];
- Range =< 65536 ->
- [20,2,<<Val2:16>>];
- Range =< (1 bsl (255*8)) ->
- Octs = binary:encode_unsigned(Val2),
- RangeOcts = binary:encode_unsigned(Range - 1),
- OctsLen = byte_size(Octs),
- RangeOctsLen = byte_size(RangeOcts),
- LengthBitsNeeded = minimum_bits(RangeOctsLen - 1),
- [10,LengthBitsNeeded,OctsLen-1,20,OctsLen,Octs];
- true ->
- exit({not_supported,{integer_range,Range}})
- end;
-encode_constrained_number({_,_},Val) ->
- exit({error,{asn1,{illegal_value,Val}}}).
-
-%% For some reason the minimum bits needed in the length field in
-%% the encoding of constrained whole numbers must always be at least 2?
-minimum_bits(N) when N < 4 -> 2;
-minimum_bits(N) when N < 8 -> 3;
-minimum_bits(N) when N < 16 -> 4;
-minimum_bits(N) when N < 32 -> 5;
-minimum_bits(N) when N < 64 -> 6;
-minimum_bits(N) when N < 128 -> 7;
-minimum_bits(_N) -> 8.
-
-%% X.691:10.8 Encoding of an unconstrained whole number
-
-encode_unconstrained_number(Val) ->
- Oct = if
- Val >= 0 ->
- eint(Val, []);
- true ->
- enint(Val, [])
- end,
- Len = length(Oct),
- if
- Len < 128 ->
- [20,Len + 1,Len|Oct];
- Len < 256 ->
- [20,Len + 2,<<2:2,Len:14>>|Oct];
- true ->
- [encode_length(Len),21,<<Len:16>>|Oct]
- end.
-
-%% used for positive Values which don't need a sign bit
-%% returns a list
-eint_positive(Val) ->
- case eint(Val,[]) of
- [0,B1|T] ->
- [B1|T];
- T ->
- T
- end.
-
-
-eint(0, [B|Acc]) when B < 128 ->
- [B|Acc];
-eint(N, Acc) ->
- eint(N bsr 8, [N band 16#ff| Acc]).
-
-enint(-1, [B1|T]) when B1 > 127 ->
- [B1|T];
-enint(N, Acc) ->
- enint(N bsr 8, [N band 16#ff|Acc]).
-
-%% X.691:10.9 Encoding of a length determinant
-%%encode_small_length(undefined,Len) -> % null means no UpperBound
-%% encode_small_number(Len).
-
-%% X.691:10.9.3.5
-%% X.691:10.9.3.7
-encode_length(Len) -> % unconstrained
- if
- Len < 128 ->
- [20,1,Len];
- Len < 16384 ->
- <<20,2,2:2,Len:14>>;
- true -> % should be able to endode length >= 16384 i.e. fragmented length
- exit({error,{asn1,{encode_length,{nyi,above_16k}}}})
- end.
-
-encode_length({C,[]}, Len) ->
- case C of
- {Lb,Ub}=Vr when Lb =< Len, Len =< Ub ->
- [0|encode_constrained_number(Vr, Len)];
- _ ->
- [1|encode_length(Len)]
- end;
-encode_length(Len, Len) ->
- [];
-encode_length(Vr, Len) ->
- encode_constrained_number(Vr, Len).
-
-%% X.691 10.9.3.4 (only used for length of bitmap that prefixes extension
-%% additions in a sequence or set
-encode_small_length(Len) when Len =< 64 ->
- [10,7,Len-1];
-encode_small_length(Len) ->
- [1,encode_length(Len)].
-
-
decode_length(Buffer) -> % un-constrained
case align(Buffer) of
<<0:1,Oct:7,Rest/binary>> ->
@@ -370,511 +51,70 @@ decode_length(Buffer) -> % un-constrained
exit({error,{asn1,{decode_length,{nyi,above_16k}}}})
end.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% bitstring NamedBitList
-%% Val can be of:
-%% - [identifiers] where only named identifers are set to one,
-%% the Constraint must then have some information of the
-%% bitlength.
-%% - [list of ones and zeroes] all bits
-%% - integer value representing the bitlist
-%% C is constraint Len, only valid when identifiers
-
-
-%% when the value is a list of {Unused,BinBits}, where
-%% Unused = integer(),
-%% BinBits = binary().
-
-encode_bit_string(C, Bits, NamedBitList) when is_bitstring(Bits) ->
- PadLen = (8 - (bit_size(Bits) band 7)) band 7,
- Compact = {PadLen,<<Bits/bitstring,0:PadLen>>},
- encode_bin_bit_string(C, Compact, NamedBitList);
-encode_bit_string(C, {Unused,BinBits}=Bin, NamedBitList)
- when is_integer(Unused), is_binary(BinBits) ->
- encode_bin_bit_string(C,Bin,NamedBitList);
-
-%% when the value is a list of named bits
-
-encode_bit_string(C, LoNB=[FirstVal | _RestVal], NamedBitList) when is_atom(FirstVal) ->
- ToSetPos = get_all_bitposes(LoNB, NamedBitList, []),
- BitList = make_and_set_list(ToSetPos,0),
- encode_bit_string(C,BitList,NamedBitList);% consider the constraint
-
-encode_bit_string(C, BL=[{bit,_} | _RestVal], NamedBitList) ->
- ToSetPos = get_all_bitposes(BL, NamedBitList, []),
- BitList = make_and_set_list(ToSetPos,0),
- encode_bit_string(C,BitList,NamedBitList);
-
-%% when the value is a list of ones and zeroes
-encode_bit_string(Int, BitListValue, _)
- when is_list(BitListValue),is_integer(Int),Int =< 16 ->
- %% The type is constrained by a single value size constraint
- %% range_check(Int,length(BitListValue)),
- [40,Int,length(BitListValue),BitListValue];
-encode_bit_string(Int, BitListValue, _)
- when is_list(BitListValue),is_integer(Int), Int =< 255 ->
- %% The type is constrained by a single value size constraint
- %% range_check(Int,length(BitListValue)),
- [2,40,Int,length(BitListValue),BitListValue];
-encode_bit_string(Int, BitListValue, _)
- when is_list(BitListValue),is_integer(Int), Int < ?'64K' ->
- {Code,DesiredLength,Length} =
- case length(BitListValue) of
- B1 when B1 > Int ->
- exit({error,{'BIT_STRING_length_greater_than_SIZE',
- Int,BitListValue}});
- B1 when B1 =< 255,Int =< 255 ->
- {40,Int,B1};
- B1 when B1 =< 255 ->
- {42,<<Int:16>>,B1};
- B1 ->
- {43,<<Int:16>>,<<B1:16>>}
- end,
- %% The type is constrained by a single value size constraint
- [2,Code,DesiredLength,Length,BitListValue];
-encode_bit_string(no, BitListValue,[])
- when is_list(BitListValue) ->
- [encode_length(length(BitListValue)),
- 2|BitListValue];
-encode_bit_string({{Fix,Fix},Ext}, BitListValue,[])
- when is_integer(Fix), is_list(Ext) ->
- case length(BitListValue) of
- Len when Len =< Fix ->
- [0|encode_bit_string(Fix, BitListValue, [])];
- _ ->
- [1|encode_bit_string(no, BitListValue, [])]
- end;
-encode_bit_string(C, BitListValue,[])
- when is_list(BitListValue) ->
- [encode_length(C, length(BitListValue)),
- 2|BitListValue];
-encode_bit_string(no, BitListValue,_NamedBitList)
- when is_list(BitListValue) ->
- %% this case with an unconstrained BIT STRING can be made more efficient
- %% if the complete driver can take a special code so the length field
- %% is encoded there.
- NewBitLVal = lists:reverse(lists:dropwhile(fun(0)->true;(1)->false end,
- lists:reverse(BitListValue))),
- [encode_length(length(NewBitLVal)),2|NewBitLVal];
-encode_bit_string({{Fix,Fix},Ext}, BitListValue, NamedBitList)
- when is_integer(Fix), is_list(Ext) ->
- case length(BitListValue) of
- Len when Len =< Fix ->
- [0|encode_bit_string(Fix, BitListValue, NamedBitList)];
- _ ->
- [1|encode_bit_string(no, BitListValue, NamedBitList)]
- end;
-encode_bit_string(C, BitListValue, _NamedBitList)
- when is_list(BitListValue) -> % C = {_,'MAX'}
- NewBitLVal = bit_string_trailing_zeros(BitListValue, C),
- [encode_length(C, length(NewBitLVal)),2|NewBitLVal];
-
-
-%% when the value is an integer
-encode_bit_string(C, IntegerVal, NamedBitList) when is_integer(IntegerVal)->
- BitList = int_to_bitlist(IntegerVal),
- encode_bit_string(C,BitList,NamedBitList).
-
-bit_string_trailing_zeros(BitList,C) when is_integer(C) ->
- bit_string_trailing_zeros1(BitList,C,C);
-bit_string_trailing_zeros(BitList,{Lb,Ub}) when is_integer(Lb) ->
- bit_string_trailing_zeros1(BitList,Lb,Ub);
-bit_string_trailing_zeros(BitList,{{Lb,Ub},_}) when is_integer(Lb) ->
- bit_string_trailing_zeros1(BitList,Lb,Ub);
-bit_string_trailing_zeros(BitList,_) ->
- BitList.
-
-bit_string_trailing_zeros1(BitList,Lb,Ub) ->
- case length(BitList) of
- Lb -> BitList;
- B when B < Lb -> BitList++lists:duplicate(Lb-B, 0);
- D -> F = fun(L,LB,LB,_,_)->lists:reverse(L);
- ([0|R],L1,LB,UB,Fun)->Fun(R,L1-1,LB,UB,Fun);
- (L,L1,_,UB,_)when L1 =< UB -> lists:reverse(L);
- (_,_L1,_,_,_) ->exit({error,{list_length_BIT_STRING,
- BitList}}) end,
- F(lists:reverse(BitList),D,Lb,Ub,F)
- end.
-
-%% encode_bin_bit_string/3, when value is a tuple of Unused and BinBits.
-%% Unused = integer(),i.e. number unused bits in least sign. byte of
-%% BinBits = binary().
-encode_bin_bit_string(C, {Unused,BinBits}, _NamedBitList)
- when is_integer(C),C=<16 ->
- range_check(C, bit_size(BinBits) - Unused),
- [45,C,byte_size(BinBits),BinBits];
-encode_bin_bit_string(C, {Unused,BinBits}, _NamedBitList)
- when is_integer(C), C =< 255 ->
- range_check(C, bit_size(BinBits) - Unused),
- [2,45,C,byte_size(BinBits),BinBits];
-encode_bin_bit_string(C, {Unused,BinBits}, _NamedBitList)
- when is_integer(C), C =< 65535 ->
- range_check(C, bit_size(BinBits) - Unused),
- case byte_size(BinBits) of
- Size when Size =< 255 ->
- [2,46,<<C:16>>,Size,BinBits];
- Size ->
- [2,47,<<C:16>>,<<Size:16>>,BinBits]
- end;
-encode_bin_bit_string(C,UnusedAndBin={_,_},NamedBitList) ->
- {Unused1,Bin1} =
- %% removes all trailing bits if NamedBitList is not empty
- remove_trailing_bin(NamedBitList,UnusedAndBin),
- case C of
- {Lb,Ub} when is_integer(Lb),is_integer(Ub) ->
- Size = byte_size(Bin1),
- [encode_length({Lb,Ub}, Size*8 - Unused1),
- 2,octets_unused_to_complete(Unused1,Size,Bin1)];
- no ->
- Size = byte_size(Bin1),
- [encode_length(Size*8 - Unused1),
- 2|octets_unused_to_complete(Unused1, Size, Bin1)];
- {{Fix,Fix},Ext} when is_integer(Fix),is_list(Ext) ->
- case byte_size(Bin1)*8 - Unused1 of
- Size when Size =< Fix ->
- [0|encode_bin_bit_string(Fix,UnusedAndBin,NamedBitList)];
- _Size ->
- [1|encode_bin_bit_string(no,UnusedAndBin,NamedBitList)]
- end;
- Sc ->
- Size = byte_size(Bin1),
- [encode_length(Sc, Size*8 - Unused1),
- 2|octets_unused_to_complete(Unused1,Size,Bin1)]
- end.
-
-range_check(C,C) when is_integer(C) ->
- ok;
-range_check(C1,C2) when is_integer(C1) ->
- exit({error,{asn1,{bit_string_out_of_range,{C1,C2}}}}).
-
-remove_trailing_bin([], {Unused,Bin}) ->
- {Unused,Bin};
-remove_trailing_bin(_NamedNumberList,{_Unused,<<>>}) ->
- {0,<<>>};
-remove_trailing_bin(NamedNumberList, {_Unused,Bin}) ->
- Size = byte_size(Bin)-1,
- <<Bfront:Size/binary, LastByte:8>> = Bin,
- %% clear the Unused bits to be sure
- Unused1 = trailingZeroesInNibble(LastByte band 15),
- Unused2 =
- case Unused1 of
- 4 ->
- 4 + trailingZeroesInNibble(LastByte bsr 4);
- _ -> Unused1
- end,
- case Unused2 of
- 8 ->
- remove_trailing_bin(NamedNumberList,{0,Bfront});
- _ ->
- {Unused2,Bin}
- end.
-
-
-trailingZeroesInNibble(0) ->
- 4;
-trailingZeroesInNibble(1) ->
- 0;
-trailingZeroesInNibble(2) ->
- 1;
-trailingZeroesInNibble(3) ->
- 0;
-trailingZeroesInNibble(4) ->
- 2;
-trailingZeroesInNibble(5) ->
- 0;
-trailingZeroesInNibble(6) ->
- 1;
-trailingZeroesInNibble(7) ->
- 0;
-trailingZeroesInNibble(8) ->
- 3;
-trailingZeroesInNibble(9) ->
- 0;
-trailingZeroesInNibble(10) ->
- 1;
-trailingZeroesInNibble(11) ->
- 0;
-trailingZeroesInNibble(12) -> %#1100
- 2;
-trailingZeroesInNibble(13) ->
- 0;
-trailingZeroesInNibble(14) ->
- 1;
-trailingZeroesInNibble(15) ->
- 0.
-
-
-%%%%%%%%%%%%%%%
-%%
-
-int_to_bitlist(Int) when is_integer(Int), Int > 0 ->
- [Int band 1 | int_to_bitlist(Int bsr 1)];
-int_to_bitlist(0) ->
- [].
-
-
-%%%%%%%%%%%%%%%%%%
-%% get_all_bitposes([list of named bits to set], named_bit_db, []) ->
-%% [sorted_list_of_bitpositions_to_set]
-
-get_all_bitposes([{bit,ValPos}|Rest], NamedBitList, Ack) ->
- get_all_bitposes(Rest, NamedBitList, [ValPos | Ack ]);
-
-get_all_bitposes([Val | Rest], NamedBitList, Ack) ->
- case lists:keyfind(Val, 1, NamedBitList) of
- {_ValName, ValPos} ->
- get_all_bitposes(Rest, NamedBitList, [ValPos | Ack]);
- false ->
- exit({error,{asn1, {bitstring_namedbit, Val}}})
- end;
-get_all_bitposes([], _NamedBitList, Ack) ->
- lists:sort(Ack).
-
-%%%%%%%%%%%%%%%%%%
-%% make_and_set_list([list of positions to set to 1])->
-%% returns list with all in SetPos set.
-%% in positioning in list the first element is 0, the second 1 etc.., but
-%%
-
-make_and_set_list([XPos|SetPos], XPos) ->
- [1 | make_and_set_list(SetPos, XPos + 1)];
-make_and_set_list([Pos|SetPos], XPos) ->
- [0 | make_and_set_list([Pos | SetPos], XPos + 1)];
-make_and_set_list([], _) ->
- [].
-
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% X.691:16
-%% encode_octet_string(Constraint, Val)
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-encode_octet_string({{Sv,Sv},Ext}=SZ, Val) when is_list(Ext), Sv =< 2 ->
- Len = length(Val),
- try
- case encode_length(SZ, Len) of
- [0|_]=EncLen ->
- [EncLen,45,Sv*8,Sv,Val];
- [_|_]=EncLen ->
- [EncLen|octets_to_complete(Len, Val)]
- end
- catch
- exit:{error,{asn1,{encode_length,_}}} ->
- encode_fragmented_octet_string(Val)
- end;
-encode_octet_string({_,_}=SZ, Val) ->
- Len = length(Val),
- try
- [encode_length(SZ, Len),2|octets_to_complete(Len, Val)]
- catch
- exit:{error,{asn1,{encode_length,_}}} ->
- encode_fragmented_octet_string(Val)
- end;
-encode_octet_string(Sv, Val) when is_integer(Sv) ->
- encode_fragmented_octet_string(Val);
-encode_octet_string(no, Val) ->
- Len = length(Val),
- try
- [encode_length(Len),2|octets_to_complete(Len, Val)]
- catch
- exit:{error,{asn1,{encode_length,_}}} ->
- encode_fragmented_octet_string(Val)
- end.
-
-encode_fragmented_octet_string(Val) ->
- Bin = iolist_to_binary(Val),
- efos_1(Bin).
-
-efos_1(<<B1:16#C000/binary,B2:16#4000/binary,T/binary>>) ->
- [20,1,<<3:2,4:6>>,
- octets_to_complete(16#C000, B1),
- octets_to_complete(16#4000, B2)|efos_1(T)];
-efos_1(<<B:16#C000/binary,T/binary>>) ->
- [20,1,<<3:2,3:6>>,octets_to_complete(16#C000, B)|efos_1(T)];
-efos_1(<<B:16#8000/binary,T/binary>>) ->
- [20,1,<<3:2,2:6>>,octets_to_complete(16#8000, B)|efos_1(T)];
-efos_1(<<B:16#4000/binary,T/binary>>) ->
- [20,1,<<3:2,1:6>>,octets_to_complete(16#4000, B)|efos_1(T)];
-efos_1(<<>>) ->
- [20,1,0];
-efos_1(<<B/bitstring>>) ->
- Len = byte_size(B),
- [encode_length(Len)|octets_to_complete(Len, B)].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Restricted char string types
-%% (NumericString, PrintableString,VisibleString,IA5String,BMPString,UniversalString)
-%% X.691:26 and X.680:34-36
-
-encode_restricted_string(Val) when is_list(Val)->
- Len = length(Val),
- [encode_length(Len)|octets_to_complete(Len, Val)].
-
-encode_known_multiplier_string(SizeC, NumBits, CharOutTab, Val) ->
- Result = chars_encode2(Val, NumBits, CharOutTab),
- case SizeC of
- Ub when is_integer(Ub), Ub*NumBits < 16 ->
- Result;
- Ub when is_integer(Ub) ->
- [2,Result];
- {{_,Ub},Ext}=SZ when is_list(Ext) ->
- Len = length(Val),
- case encode_length(SZ, Len) of
- [0|_]=EncLen when Ub*NumBits < 16 ->
- [EncLen,45,Len*NumBits,Len,Val];
- [_|_]=EncLen ->
- [EncLen,2|Result]
- end;
- {_,Ub}=Range ->
- [encode_length(Range, length(Val))|
- if
- Ub*NumBits < 16 -> Result;
- true -> [2|Result]
- end];
- no ->
- [encode_length(length(Val)),2,Result]
- end.
-
-encode_GeneralString(_C,Val) ->
- encode_restricted_string(Val).
-
-encode_GraphicString(_C,Val) ->
- encode_restricted_string(Val).
-
-encode_ObjectDescriptor(_C,Val) ->
- encode_restricted_string(Val).
-
-encode_TeletexString(_C,Val) -> % equivalent with T61String
- encode_restricted_string(Val).
-
-encode_VideotexString(_C,Val) ->
- encode_restricted_string(Val).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% chars_encode(C,StringType,Value) -> ValueList
-%%
-%% encodes chars according to the per rules taking the constraint
-%% PermittedAlphabet into account.
-%%
-%% This function only encodes the value part and NOT the length.
-
-chars_encode2([H|T],NumBits,T1={Min,Max,notab}) when H =< Max, H >= Min ->
- [pre_complete_bits(NumBits,H-Min)|chars_encode2(T,NumBits,T1)];
-chars_encode2([H|T],NumBits,T1={Min,Max,Tab}) when H =< Max, H >= Min ->
- [pre_complete_bits(NumBits,exit_if_false(H,element(H-Min+1,Tab)))|
- chars_encode2(T,NumBits,T1)];
-chars_encode2([{A,B,C,D}|T],NumBits,T1={Min,_Max,notab}) ->
- %% no value range check here (ought to be, but very expensive)
- [pre_complete_bits(NumBits,
- ((((((A bsl 8)+B) bsl 8)+C) bsl 8)+D)-Min)|
- chars_encode2(T,NumBits,T1)];
-chars_encode2([H={A,B,C,D}|T],NumBits,{Min,Max,Tab}) ->
- %% no value range check here (ought to be, but very expensive)
- [pre_complete_bits(NumBits,exit_if_false(H,element(((((((A bsl 8)+B) bsl 8)+C) bsl 8)+D)-Min,Tab)))|chars_encode2(T,NumBits,{Min,Max,notab})];
-chars_encode2([H|_T],_NumBits,{_Min,_Max,_Tab}) ->
- exit({error,{asn1,{illegal_char_value,H}}});
-chars_encode2([],_,_) ->
- [].
-
-exit_if_false(V,false)->
- exit({error,{asn1,{"illegal value according to Permitted alphabet constraint",V}}});
-exit_if_false(_,V) ->V.
-
-pre_complete_bits(NumBits,Val) when NumBits =< 8 ->
- [10,NumBits,Val];
-pre_complete_bits(NumBits,Val) when NumBits =< 16 ->
- [10,NumBits-8,Val bsr 8,10,8,(Val band 255)];
-pre_complete_bits(NumBits,Val) when NumBits =< 2040 -> % 255 * 8
- Unused = (8 - (NumBits rem 8)) rem 8,
- Len = NumBits + Unused,
- [30,Unused,Len div 8,<<(Val bsl Unused):Len>>].
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% encode_UTF8String(Val) -> CompleteList
-%% Val -> <<utf8encoded binary>>
-%% CompleteList -> [apropriate codes and values for driver complete]
-%%
-encode_UTF8String(Val) when is_binary(Val) ->
- Sz = byte_size(Val),
- [encode_length(Sz),octets_to_complete(Sz, Val)];
-encode_UTF8String(Val) ->
- encode_UTF8String(list_to_binary(Val)).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% encode_object_identifier(Val) -> CompleteList
-%% encode_object_identifier({Name,Val}) -> CompleteList
-%% Val -> {Int1,Int2,...,IntN} % N >= 2
-%% Name -> atom()
-%% Int1 -> integer(0..2)
-%% Int2 -> integer(0..39) when Int1 (0..1) else integer()
-%% Int3-N -> integer()
-%% CompleteList -> [{bits,8,Val}|{octets,Ol}|align|...]
-%%
-encode_object_identifier(Val) ->
- OctetList = e_object_identifier(Val),
- Octets = list_to_binary(OctetList),
- Sz = byte_size(Octets),
- [encode_length(Sz),
- octets_to_complete(Sz, Octets)].
-
-e_object_identifier({'OBJECT IDENTIFIER',V}) ->
- e_object_identifier(V);
-e_object_identifier(V) when is_tuple(V) ->
- e_object_identifier(tuple_to_list(V));
-
-%% E1 = 0|1|2 and (E2 < 40 when E1 = 0|1)
-e_object_identifier([E1,E2|Tail]) when E1 >= 0, E1 < 2, E2 < 40 ; E1==2 ->
- Head = 40*E1 + E2, % weird
- e_object_elements([Head|Tail],[]);
-e_object_identifier(Oid=[_,_|_Tail]) ->
- exit({error,{asn1,{'illegal_value',Oid}}}).
-
-e_object_elements([],Acc) ->
- lists:reverse(Acc);
-e_object_elements([H|T],Acc) ->
- e_object_elements(T,[e_object_element(H)|Acc]).
-
-e_object_element(Num) when Num < 128 ->
- [Num];
-e_object_element(Num) ->
- [e_o_e(Num bsr 7)|[Num band 2#1111111]].
-e_o_e(Num) when Num < 128 ->
- Num bor 2#10000000;
-e_o_e(Num) ->
- [e_o_e(Num bsr 7)|[(Num band 2#1111111) bor 2#10000000]].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% encode_relative_oid(Val) -> CompleteList
-%% encode_relative_oid({Name,Val}) -> CompleteList
-encode_relative_oid(Val) when is_tuple(Val) ->
- encode_relative_oid(tuple_to_list(Val));
-encode_relative_oid(Val) when is_list(Val) ->
- Octets = list_to_binary([e_object_element(X)||X <- Val]),
- Sz = byte_size(Octets),
- [encode_length(Sz)|octets_to_complete(Sz, Octets)].
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% complete(InList) -> ByteList
%% Takes a coded list with bits and bytes and converts it to a list of bytes
%% Should be applied as the last step at encode of a complete ASN.1 type
%%
-complete(L) ->
- case asn1rt_nif:encode_per_complete(L) of
+complete(L0) ->
+ L = complete(L0, []),
+ case list_to_bitstring(L) of
<<>> -> <<0>>;
Bin -> Bin
end.
-octets_to_complete(Len,Val) when Len < 256 ->
- [20,Len,Val];
-octets_to_complete(Len,Val) ->
- [21,<<Len:16>>,Val].
-
-octets_unused_to_complete(Unused,Len,Val) when Len < 256 ->
- [30,Unused,Len,Val];
-octets_unused_to_complete(Unused,Len,Val) ->
- [31,Unused,<<Len:16>>,Val].
+complete([], []) ->
+ [];
+complete([], [H|More]) ->
+ complete(H, More);
+complete([align|T], More) ->
+ complete(T, More);
+complete([[]|T], More) ->
+ complete(T, More);
+complete([[_|_]=H], More) ->
+ complete(H, More);
+complete([[_|_]=H|T], More) ->
+ complete(H, [T|More]);
+complete([H|T], More) when is_integer(H); is_binary(H) ->
+ [H|complete(T, More)];
+complete([H|T], More) ->
+ [H|complete(T, bit_size(H), More)];
+complete(Bin, More) when is_binary(Bin) ->
+ [Bin|complete([], More)];
+complete(Bin, More) ->
+ [Bin|complete([], bit_size(Bin), More)].
+
+complete([], Bits, []) ->
+ case Bits band 7 of
+ 0 -> [];
+ N -> [<<0:(8-N)>>]
+ end;
+complete([], Bits, [H|More]) ->
+ complete(H, Bits, More);
+complete([align|T], Bits, More) ->
+ case Bits band 7 of
+ 0 -> complete(T, More);
+ 1 -> [<<0:7>>|complete(T, More)];
+ 2 -> [<<0:6>>|complete(T, More)];
+ 3 -> [<<0:5>>|complete(T, More)];
+ 4 -> [<<0:4>>|complete(T, More)];
+ 5 -> [<<0:3>>|complete(T, More)];
+ 6 -> [<<0:2>>|complete(T, More)];
+ 7 -> [<<0:1>>|complete(T, More)]
+ end;
+complete([[]|T], Bits, More) ->
+ complete(T, Bits, More);
+complete([[_|_]=H], Bits, More) ->
+ complete(H, Bits, More);
+complete([[_|_]=H|T], Bits, More) ->
+ complete(H, Bits, [T|More]);
+complete([H|T], Bits, More) when is_integer(H);
+ is_binary(H) ->
+ [H|complete(T, Bits, More)];
+complete([H|T], Bits, More) ->
+ [H|complete(T, Bits+bit_size(H), More)];
+complete(Bin, Bits, More) when is_binary(Bin) ->
+ [Bin|complete([], Bits, More)];
+complete(Bin, Bits, More) ->
+ [Bin|complete([], Bits+bit_size(Bin), More)].