%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 1997-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %% %CopyrightEnd% %% %% -module(testPrimStrings). -export([bit_string/2]). -export([octet_string/1]). -export([numeric_string/1]). -export([other_strings/1]). -export([more_strings/1]). -export([universal_string/1]). -export([bmp_string/1]). -export([times/1]). -export([utf8_string/1]). -export([fragmented/1]). -include_lib("common_test/include/ct.hrl"). fragmented(Rules) -> Lens = fragmented_lengths(), case 'PrimStrings':legacy_erlang_types() of false -> fragmented_octet_string(Rules, Lens); true -> ok end, fragmented_strings(Lens). fragmented_strings(Lens) -> Types = ['Ns','Ps','Ps11','Vis','IA5'], [fragmented_strings(Len, Types) || Len <- Lens], ok. fragmented_strings(Len, Types) -> Str = make_ns_value(Len), [roundtrip(Type, Str) || Type <- Types], ok. make_ns_value(0) -> []; make_ns_value(N) -> [($0 - 1) + rand:uniform(10)|make_ns_value(N-1)]. fragmented_lengths() -> K16 = 1 bsl 14, K32 = K16 + K16, K48 = K32 + K16, K64 = K48 + K16, [0,1,14,15,16,17,127,128, K16-1,K16,K16+1,K16+(1 bsl 7)-1,K16+(1 bsl 7),K16+(1 bsl 7)+1, K32-1,K32,K32+1,K32+(1 bsl 7)-1,K32+(1 bsl 7),K32+(1 bsl 7)+1, K48-1,K48,K48+1,K48+(1 bsl 7)-1,K48+(1 bsl 7),K48+(1 bsl 7)+1, K64-1,K64,K64+1,K64+(1 bsl 7)-1,K64+(1 bsl 7),K64+(1 bsl 7)+1, K64+K16-1,K64+K16,K64+K16+1]. bit_string(Rules, Opts) -> %%========================================================== %% Bs1 ::= BIT STRING %%========================================================== bs_roundtrip('Bs1', <<>>), bs_roundtrip('Bs1', <<1:3>>), bs_roundtrip('Bs1', <<15:4>>), bs_roundtrip('Bs1', <<2#010010:6>>), bs_roundtrip('Bs1', <<2#11111111:8>>), bs_roundtrip('Bs1', <<2#100000000:9>>), bs_roundtrip('Bs1', <<2#100000001:9>>), bs_roundtrip('Bs1', <<2#001111011:9>>), bs_roundtrip('Bs1', <<2#0100101111100010011:19>>), case 'PrimStrings':legacy_erlang_types() of false -> ok; true -> {ok,Enc1} = 'PrimStrings':encode('Bs1', 12345678901234567890), {ok,_} = 'PrimStrings':decode('Bs1', Enc1) end, case {Rules,Opts} of {ber,[legacy_erlang_types]} -> bs_decode('Bs1', <<35,8,3,2,0,73,3,2,4,32>>, [0,1,0,0,1,0,0,1,0,0,1,0]), bs_decode('Bs1', <<35,9,3,2,0,234,3,3,7,156,0>>, [1,1,1,0,1,0,1,0,1,0,0,1,1,1,0,0,0]), bs_decode('Bs1', <<35,128,3,2,0,234,3,3,7,156,0,0,0>>, [1,1,1,0,1,0,1,0,1,0,0,1,1,1,0,0,0]); {ber,[]} -> %% XXX ok; {_,_} -> %% DER, PER, UPER consistent_def_enc('BsDef1', [2#111101, [1,0,1,1,1,1], {2,<<2#101111:6,0:2>>}, <<2#101111:6>>]), consistent_def_enc('BsDef2', [[1,1,0,1, 1,1,1,0, 1,0,1,0, 1,1,0,1, 1,0,1,1, 1,1,1,0, 1,1,1,0, 1,1,1,1], {0,<<16#DEADBEEF:4/unit:8>>}, <<16#DEADBEEF:4/unit:8>>]) end, %%========================================================== %% Bs2 ::= BIT STRING {su(0), mo(1), tu(2), we(3), th(4), fr(5), sa(6) } (SIZE (7)) %%========================================================== roundtrip('Bs2', []), roundtrip('Bs2', [mo,tu,fr]), bs_roundtrip('Bs2', <<2#0110010:7>>, [mo,tu,fr]), bs_roundtrip('Bs2', <<2#0110011:7>>, [mo,tu,fr,sa]), %%========================================================== %% Bs3 ::= BIT STRING {su(0), mo(1), tu(2), we(3), th(4), fr(5), sa(6) } (SIZE (1..7)) %%========================================================== roundtrip('Bs3', []), roundtrip('Bs3', [mo,tu,fr]), bs_roundtrip('Bs3', <<2#0110010:7>>, [mo,tu,fr]), bs_roundtrip('Bs3', <<2#0110010:7>>, [mo,tu,fr]), bs_roundtrip('Bs2', <<2#0110011:7>>, [mo,tu,fr,sa]), bs_roundtrip('Bs3', <<2#011001:6>>, [mo,tu,fr]), bs_roundtrip('Bs3', <<2#11:2>>, [su,mo]), %%========================================================== %% Bs4 ::= BIT STRING {su(0), mo(1), tu(2), we(3), th(4), fr(5), sa(6) } %%========================================================== roundtrip('Bs4', []), roundtrip('Bs4', [mo,tu,fr,sa]), %%========================================================== %% Bs7 ::= BIT STRING (SIZE (24)) %%========================================================== bs_roundtrip('Bs7', <<23563:24>>), case 'PrimStrings':legacy_erlang_types() of false -> %% {error,_} = 'PrimStrings':encode('Bs7', <<2#1010:4>>); ok; true -> ok end, %%========================================================== %% BsPri ::= [PRIVATE 61] BIT STRING %%========================================================== bs_roundtrip('BsPri', <<2#101101:6>>), bs_roundtrip('BsPri', <<2#11001011:8>>), case Rules of ber -> bs_decode('BsPri', <<223,61,4,5,75,226,96>>, [0,1,0,0,1,0,1,1,1,1,1,0,0,0,1,0,0,1,1]), bs_decode('BsPri', <<255,61,128,3,4,5,75,226,96,0,0>>, [0,1,0,0,1,0,1,1,1,1,1,0,0,0,1,0,0,1,1]), bs_decode('BsPri', <<255,61,9,3,2,0,75,3,3,5,226,96>>, [0,1,0,0,1,0,1,1,1,1,1,0,0,0,1,0,0,1,1]), bs_decode('BsPri', <<255,61,128,3,2,0,75,3,3,5,226,96,0,0>>, [0,1,0,0,1,0,1,1,1,1,1,0,0,0,1,0,0,1,1]); _ -> ok end, %%========================================================== %% BsExpPri ::= [PRIVATE 61] EXPLICIT BIT STRING %%========================================================== bs_roundtrip('BsExpPri', <<2#101101:6>>), bs_roundtrip('BsExpPri', <<2#11001011:8>>), case Rules of ber -> bs_decode('BsExpPri', <<255,61,6,3,4,5,75,226,96>>, [0,1,0,0,1,0,1,1,1,1,1,0,0,0,1,0,0,1,1]); _ -> ok end, %%========================================================== %% TestS ::= BIT STRING {a(0),b(1)} (SIZE (3..8)), test case for OTP-4353 %%========================================================== roundtrip('TestS', [a]), %%========================================================== %% PersonalStatus ::= BIT STRING {married(0),employed(1), %% veteran(2), collegeGraduate(3)}, test case for OTP-5710 %%========================================================== {ok,Bytes54} = 'BitStr':encode('PersonalStatus', <<>>), {ok,[]} = 'BitStr':decode('PersonalStatus', Bytes54), %%========================================================== %% BS5932 ::= BIT STRING (SIZE (5..MAX)) %% test case for OTP-5932 %%========================================================== bs_roundtrip('BSMAX', <<2#10101:5>>), case Rules of ber -> {error,_} = 'PrimStrings':encode('BSMAX', [1,0,1]); _ -> ok end, %%========================================================== %% BS255 ::= BIT STRING (SIZE (255)) %% BS256 ::= BIT STRING (SIZE (256)) %% BS1024 ::= BIT STRING (SIZE (1024)) %% test case for OTP-7602 %%========================================================== bs_roundtrip('BS255', random_bits(255)), bs_roundtrip('BS256', random_bits(256)), bs_roundtrip('BS1024', random_bits(1024)), bs_roundtrip('TransportLayerAddress', <<2#0110:4>>), case Rules of ber -> ok; _ -> per_bs_strings() end. random_bits(N) -> Seed0 = {erlang:monotonic_time(),erlang:unique_integer()}, Seed = integer_to_list(erlang:phash2(Seed0)), random_bits(<<>>, N, Seed). random_bits(Bin, N, Seed) -> RandomBits = erlang:md5(Seed), Bits = bit_size(RandomBits), if Bits < N -> random_bits(<<Bin/bitstring,RandomBits/bitstring>>, N-Bits, RandomBits); true -> <<LastBits:N/bitstring,_/bitstring>> = RandomBits, <<Bin/bitstring,LastBits/bitstring>> end. consistent_def_enc(Type, Vs0) -> M = 'PrimStrings', {ok,Enc} = M:encode(Type, {Type,asn1_DEFAULT}), {ok,Val} = M:decode(Type, Enc), %% Ensure that the value has the correct format. case {M:bit_string_format(),Val} of {bitstring,{_,Bs}} when is_bitstring(Bs) -> ok; {compact,{_,{Unused,Bin}}} when is_integer(Unused), is_binary(Bin) -> ok; {legacy,{_,Bs}} when is_list(Bs) -> ok end, %% If this is not the legacy format, only bitstrings are %% allowed. Vs = case M:legacy_erlang_types() of false -> [V || V <- Vs0, is_bitstring(V)]; true -> Vs0 end, %% All values should be recognized and encoded as the %% the default value (i.e. not encoded at all). _ = [{ok,Enc} = M:encode(Type, {Type,V}) || V <- Vs], ok. %% The PER encoding rules requires that a BIT STRING with %% named positions should never have any trailing zeroes %% (except to reach the minimum number of bits as given by %% a SIZE constraint). per_bs_strings() -> bs_roundtrip('Bs3', <<2#0010000:7>>, [tu]), bs_roundtrip('Bs4', <<2#0110010:7>>, [mo,tu,fr]), bs_roundtrip('Bs4', <<2#011:3,0:32>>, [mo,tu]), [per_trailing_zeroes(B) || B <- lists:seq(0, 255)], ok. %% Trailing zeroes should be removed from BIT STRINGs with named %% bit positions. per_trailing_zeroes(Byte) -> L = lists:reverse(make_bit_list(Byte+16#10000)), L = make_bit_list(Byte+16#10000, []), Pos = positions(L, 0), ExpectedSz = case lists:last(Pos) of su -> 1; {bit,LastBitPos} -> LastBitPos+1 end, %% Bitstrings. Bs = << <<B:1>> || B <- L >>, Sz = bit_size(Bs), named_roundtrip(Bs, Pos, ExpectedSz), Bin = <<Bs:Sz/bits,0:16,0:7>>, named_roundtrip(Bin, Pos, ExpectedSz), case 'PrimStrings':legacy_erlang_types() of false -> ok; true -> %% List of zeroes and ones. named_roundtrip(L, Pos, ExpectedSz), named_roundtrip(L++[0,0,0,0,0], Pos, ExpectedSz), %% Compact bitstring. named_roundtrip({7,Bin}, Pos, ExpectedSz), %% Integer bitstring (obsolete). IntBs = intlist_to_integer(L, 0, 0), named_roundtrip(IntBs, Pos, ExpectedSz), ok end. make_bit_list(0) -> []; make_bit_list(B) -> [B band 1|make_bit_list(B bsr 1)]. make_bit_list(0, Acc) -> Acc; make_bit_list(B, Acc) -> make_bit_list(B bsr 1, [B band 1|Acc]). positions([1|T], 0) -> [su|positions(T, 1)]; positions([1|T], Pos) -> [{bit,Pos}|positions(T, Pos+1)]; positions([0|T], Pos) -> positions(T, Pos+1); positions([], _) -> []. intlist_to_integer([B|T], Shift, Acc) -> intlist_to_integer(T, Shift+1, (B bsl Shift) + Acc); intlist_to_integer([], _, Acc) -> Acc. named_roundtrip(Value, Expected, ExpectedSz) -> M = 'PrimStrings', Type = 'Bs4', {ok,Encoded} = M:encode(Type, Value), {ok,Encoded} = M:encode(Type, Expected), {ok,Expected} = M:decode(Type, Encoded), %% Verify the size in the first byte. <<ExpectedSz:8,_/bits>> = Encoded, ok. octet_string(Rules) -> %%========================================================== %% Os ::= OCTET STRING %%========================================================== Legacy = 'PrimStrings':legacy_erlang_types(), case Rules of ber when not Legacy -> {ok,<<"Jones">>} = 'PrimStrings':decode('Os', <<4,5,16#4A,16#6F,16#6E,16#65,16#73>>), {ok,<<"Jones">>} = 'PrimStrings':decode('Os', <<36,9,4,3,16#4A,16#6F,16#6E,4,2,16#65,16#73>>), {ok,<<"Jones">>} = 'PrimStrings':decode('Os', <<36,128,4,3,16#4A,16#6F,16#6E,4,2,16#65,16#73,0,0>>), ok; _ -> ok end, os_roundtrip('Os', <<47,23,99,255,1>>), os_roundtrip('OsCon', <<47,23,99,255,1>>), os_roundtrip('OsPri', <<47,23,99,255,1>>), os_roundtrip('OsApp', <<47,23,99,255,1>>), os_roundtrip('OsExpCon', <<47,23,99,255,1>>), os_roundtrip('OsExpPri', <<47,23,99,255,1>>), os_roundtrip('OsExpApp', <<47,23,99,255,1>>), os_roundtrip('Os', <<>>), os_roundtrip('OsApp', <<>>), os_roundtrip('OsExpApp', <<>>), OsR = <<"12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890">>, os_roundtrip('Os', OsR), os_roundtrip('OsCon', OsR), os_roundtrip('OsExpApp', OsR), case Rules of ber when not Legacy -> {ok,<<"Jones">>} = 'PrimStrings':decode('OsExpApp', <<127,62,7,4,5,16#4A,16#6F,16#6E,16#65,16#73>>), {ok,<<"Jones">>} = 'PrimStrings':decode('OsExpApp', <<127,62,11,36,9,4,3,16#4A,16#6F,16#6E,4,2,16#65,16#73>>), {ok,<<"Jones">>} = 'PrimStrings':decode('OsExpApp', <<127,62,13,36,128,4,3,16#4A,16#6F,16#6E,4,2,16#65,16#73,0,0>>), {ok,<<"Jones">>} = 'PrimStrings':decode('OsExpApp', <<127,62,128,36,128,4,3,16#4A,16#6F,16#6E,4,2,16#65,16#73,0,0,0,0>>), {ok,<<"JonesJones">>} = 'PrimStrings':decode('OsExpApp', <<127,62,128,36,128,4,3,16#4A,16#6F,16#6E,4,2,16#65,16#73,0,0,36,128,4,3,16#4A,16#6F,16#6E,4,2,16#65,16#73,0,0,0,0>>), ok; _ -> ok end, S255 = lists:seq(1, 255), Strings = {type,true,<<"">>,<<"1">>,<<"12">>,<<"345">>,true, list_to_binary(S255),list_to_binary([$a|S255]), list_to_binary([$a,$b|S255]),397}, p_os_roundtrip('OsFixedStrings', Strings), p_os_roundtrip('OsFixedStringsExt', Strings), p_os_roundtrip('OsVarStringsExt', Strings), ShortenedStrings = shorten_by_two(Strings), p_os_roundtrip('OsFixedStringsExt', ShortenedStrings), p_os_roundtrip('OsVarStringsExt', ShortenedStrings), ok. fragmented_octet_string(Erules, Lens) -> Types = ['Os','OsFrag','OsFragExt'], [fragmented_octet_string(Erules, Types, L) || L <- Lens], fragmented_octet_string(Erules, ['FixedOs65536'], 65536), fragmented_octet_string(Erules, ['FixedOs65537'], 65537), fragmented_octet_string(Erules, ['FixedOs65536Ext'], 65536), fragmented_octet_string(Erules, ['FixedOs65537Ext'], 65537), %% Make sure that octet alignment works. roundtrip('OsAlignment', {'OsAlignment',false,make_value(70000),true,make_value(66666), false,make_value(65536),42}), roundtrip('OsAlignment', {'OsAlignment',false,make_value(0),true,make_value(0), false,make_value(65536),42}), ok. fragmented_octet_string(Erules, Types, L) -> Value = make_value(L), [begin Encoded = enc_frag(Erules, Type, Value), {ok,Value} = 'PrimStrings':decode(Type, Encoded) end || Type <- Types], ok. enc_frag(Erules, Type, Value) -> M = 'PrimStrings', {ok,Encoded} = M:encode(Type, Value), case Erules of ber -> Encoded; _ -> %% Validate encoding with our own encoder. Encoded = enc_frag_1(<<>>, Value) end. enc_frag_1(Res, Bin0) -> K16 = 1 bsl 14, Sz = byte_size(Bin0), if Sz >= K16 -> F = min(Sz div K16, 4), FragSize = F * K16, <<Frag:FragSize/binary-unit:8,Bin/binary>> = Bin0, enc_frag_1(<<Res/binary,3:2,F:6,Frag/binary>>, Bin); Sz >= 128 -> <<Res/binary,1:1,0:1,Sz:14,Bin0/binary>>; true -> <<Res/binary,0:1,Sz:7,Bin0/binary>> end. make_value(L) -> make_value(L, 0, <<>>). make_value(0, _, Acc) -> Acc; make_value(N, Byte, Acc) when Byte =< 255 -> make_value(N-1, Byte+7, <<Acc/binary,Byte:8>>); make_value(N, Byte, Acc) -> make_value(N, Byte band 16#FF, Acc). numeric_string(Rules) -> %%========================================================== %% Ns ::= NumericString %%========================================================== roundtrip('Ns', []), roundtrip('Ns', "01 34"), case Rules of ber -> {ok,"Jones"} = 'PrimStrings':decode('Ns', <<16#12,5,16#4A,16#6F, 16#6E,16#65,16#73>>), {ok,"Jones"} = 'PrimStrings':decode('Ns', <<16#32,9,18,3,16#4A,16#6F, 16#6E,18,2,16#65,16#73>>), {ok,"Jones"} = 'PrimStrings':decode('Ns', <<16#32,128,18,3,16#4A,16#6F, 16#6E,18,2,16#65,16#73,0,0>>), ok; _ -> ok end, %%========================================================== %% NsCon ::= [70] NumericString %%========================================================== roundtrip('NsCon', []), roundtrip('NsCon', "01 34"), case Rules of ber -> {ok,"Jones"} = 'PrimStrings':decode('NsCon', <<16#9F,16#46,5,16#4A,16#6F,16#6E,16#65,16#73>>), {ok,"Jones"} = 'PrimStrings':decode('NsCon', <<16#BF,16#46,9,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73>>), {ok,"Jones"} = 'PrimStrings':decode('NsCon', <<16#BF,16#46,128,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73,0,0>>), ok; _ -> ok end, %%========================================================== %% NsExpCon ::= [71] EXPLICIT NumericString %%========================================================== roundtrip('NsExpCon', []), roundtrip('NsExpCon', "01 34"), case Rules of ber -> {ok,"Jones"} = 'PrimStrings':decode('NsExpCon', <<16#BF,16#47,16#07,16#12,16#05,16#4A,16#6F,16#6E,16#65,16#73>>), {ok,"Jones"} = 'PrimStrings':decode('NsExpCon', <<16#BF,16#47,11,16#32,9,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73>>), {ok,"Jones"} = 'PrimStrings':decode('NsExpCon', <<16#BF,16#47,128,16#32,128,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73,0,0,0,0>>), {ok,"JonesJones"} = 'PrimStrings':decode('NsExpCon', <<16#BF,16#47,26,16#32,128,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73,0,0,16#32,128,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73,0,0>>), {ok,"JonesJones"} = 'PrimStrings':decode('NsExpCon', <<16#BF,16#47,128,16#32,128,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73,0,0,16#32,128,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73,0,0,0,0>>), ok; _ -> ok end. other_strings(_Rules) -> %%========================================================== %% Ps ::= PrintableString %%========================================================== roundtrip('Ps', [47,23,99,75,47]), roundtrip('Ps', []), roundtrip('Ps11', "*0123456789*"), %%========================================================== %% Vis ::= VisibleString %%========================================================== roundtrip('Vis', [47,23,99,75,47]), roundtrip('Vis', []), roundtrip('Vis8', "7654321001234567"), roundtrip('Vis8', []), %%========================================================== %% IA5 ::= IA5String %%========================================================== roundtrip('IA5', [47,23,99,75,47]), roundtrip('IA5', []), IA5_1 = "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", roundtrip('IA5', IA5_1), roundtrip('IA5Visible', lists:seq($\s, $~)), S255 = lists:seq(0, 127) ++ lists:seq(1, 127), Strings = {type,true,"","1","12","345",true,"6789",true, S255,[$a|S255],[$a,$b|S255],397}, p_roundtrip('IA5FixedStrings', Strings), p_roundtrip('IA5FixedStringsExt', Strings), p_roundtrip('IA5VarStringsExt', Strings), ShortenedStrings = shorten_by_two(Strings), p_roundtrip('IA5VarStringsExt', ShortenedStrings), ok. more_strings(_Rules) -> %%========================================================== %% Ts ::= TeletexString %%========================================================== roundtrip('Ts', [47,23,99,75,47]), roundtrip('Ts', []), %%========================================================== %% Vxs ::= VideotexString %%========================================================== roundtrip('Vxs', [47,23,99,75,47]), roundtrip('Vxs', []), %%========================================================== %% Grs ::= GraphicString %%========================================================== roundtrip('Grs',[47,23,99,75,47]), roundtrip('Grs', []), %%========================================================== %% ODesc ::= ObjectDescriptor, test case for OTP-4161 %%========================================================== roundtrip('ODesc', [79,98,106,101,99,116,68,101,115,99,114, 105,112,116,111,114]), roundtrip('ODesc', []), %%========================================================== %% Ges ::= GeneralString %%========================================================== roundtrip('Ges', [47,23,99,75,47]), roundtrip('Ges', []), ok. universal_string(Rules) -> %%========================================================== %% Us ::= UniversalString %%========================================================== roundtrip('Us', [{47,23,99,47},{0,0,55,66}]), roundtrip('Us', [{47,23,99,255},{0,0,0,201}], [{47,23,99,255},201]), roundtrip('Us', "Universal String"), roundtrip('Us', []), roundtrip('Us', [{47,23,99,47}]), case Rules of ber -> {ok,[{47,23,99,255},{0,0,2,201}]} = 'PrimStrings':decode('Us', <<16#3C,12,28,4,47,23,99,255,28,4,0,0,2,201>>), {ok,[{47,23,99,255},{0,0,2,201}]} = 'PrimStrings':decode('Us', <<16#3C,16#80,28,4,47,23,99,255,28,4,0,0,2,201,0,0>>); _ -> ok end, Us1 = "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", roundtrip('IA5', Us1), %%========================================================== %% UsCon ::= [70] UniversalString %%========================================================== roundtrip('UsCon', [{47,23,99,255},{0,0,2,201}]), roundtrip('UsCon', [{47,23,99,255},{0,0,0,201}], [{47,23,99,255},201]), roundtrip('UsCon', "Universal String"), roundtrip('UsCon', []), case Rules of ber -> {ok,[{47,23,99,255},{0,0,2,201}]} = 'PrimStrings':decode('UsCon', <<16#BF,16#46,12,28,4,47,23,99,255,28,4,0,0,2,201>>), {ok,[{47,23,99,255},{0,0,2,201}]} = 'PrimStrings':decode('UsCon', <<16#BF,16#46,16#80,28,4,47,23,99,255,28,4,0,0,2,201,0,0>>); _ -> ok end, %%========================================================== %% UsExpCon ::= [71] EXPLICIT UniversalString %%========================================================== roundtrip('UsExpCon', [{47,23,99,255},{0,0,2,201}]), roundtrip('UsExpCon', [{47,23,99,255},{0,0,0,201}], [{47,23,99,255},201]), roundtrip('UsExpCon', "Universal String"), roundtrip('UsExpCon', []), case Rules of ber -> {ok,[{47,23,99,255},{0,0,2,201}]} = 'PrimStrings':decode('UsExpCon', <<16#BF,16#47,14,60,12,28,4,47,23,99,255,28,4,0,0,2,201>>), {ok,[{47,23,99,255},{0,0,2,201}]} = 'PrimStrings':decode('UsExpCon', <<16#BF,16#47,16,60,16#80,28,4,47,23,99,255,28,4,0,0,2,201,0,0>>); _ -> ok end. bmp_string(_Rules) -> %%========================================================== %% BMP ::= BMPString %%========================================================== roundtrip('BMP', [{0,0,99,48},{0,0,2,201}]), roundtrip('BMP', [{0,0,0,48},{0,0,2,201}], [48,{0,0,2,201}]), roundtrip('BMP', "BMP String"), roundtrip('BMP', []), BMP1 = "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", roundtrip('BMP', BMP1), ok. times(_Rules) -> %%========================================================== %% Gt ::= GeneralizedTime %%========================================================== roundtrip('Gt', "19970923110723.2"), roundtrip('Gt', "19970923110723.2Z"), roundtrip('Gt', "19970923110723.2-0500"), %%========================================================== %% UTC ::= UTCTime %%========================================================== roundtrip('UTC', "9709211107Z"), roundtrip('UTC', "9709211107-0500"), ok. utf8_string(_Rules) -> %%========================================================== %% UTF ::= UTF8String %%========================================================== AllRanges = [16#00, 16#7f, 16#80, 16#7ff, 16#800, 16#ffff, 16#10000, 16#1ffff, 16#20000, 16#2ffff, 16#e0000, 16#effff, 16#F0000, 16#10ffff], [begin UTF8 = unicode:characters_to_binary([Char]), [Char] = unicode:characters_to_list([UTF8]), roundtrip('UTF', UTF8) end || Char <- AllRanges], UTF8 = unicode:characters_to_binary(AllRanges), AllRanges = unicode:characters_to_list(UTF8), roundtrip('UTF', UTF8), ok. shorten_by_two(Tuple) -> L = [case E of [_,_|T] -> T; <<_:16,T/binary>> -> T; _ -> E end || E <- tuple_to_list(Tuple)], list_to_tuple(L). p_os_roundtrip(Type, Value0) -> Value = setelement(1, Value0, Type), p_os_roundtrip_1(Type, Value). p_os_roundtrip_1(Type, Value) -> M = 'PrimStrings', case M:legacy_erlang_types() of false -> asn1_test_lib:roundtrip(M, Type, Value); true -> {ok,Encoded} = M:encode(Type, Value), Es0 = tuple_to_list(Value), Es1 = [if is_binary(E) -> binary_to_list(E); true -> E end || E <- Es0], ListValue = list_to_tuple(Es1), {ok,Encoded} = M:encode(Type, ListValue), {ok,ListValue} = M:decode(Type, Encoded) end. p_roundtrip(Type, Value0) -> Value = setelement(1, Value0, Type), roundtrip(Type, Value). roundtrip(Type, Value) -> roundtrip(Type, Value, Value). roundtrip(Type, Value, Expected) -> asn1_test_lib:roundtrip('PrimStrings', Type, Value, Expected). bs_roundtrip(Type, Value) -> bs_roundtrip(Type, Value, Value). os_roundtrip(Type, Bin) when is_binary(Bin) -> M = 'PrimStrings', case M:legacy_erlang_types() of false -> asn1_test_lib:roundtrip(M, Type, Bin); true -> {ok,Encoded} = M:encode(Type, Bin), List = binary_to_list(Bin), {ok,Encoded} = M:encode(Type, List), {ok,List} = M:decode(Type, Encoded) end. bs_roundtrip(Type, Value, Expected) when is_bitstring(Value) -> M = 'PrimStrings', case M:legacy_erlang_types() of false -> asn1_test_lib:roundtrip(M, Type, Value, Expected); true -> {ok,Encoded} = M:encode(Type, Value), BitList = [B || <<B:1>> <= Value], {ok,Encoded} = M:encode(Type, BitList), case BitList of [] -> {ok,Encoded} = M:encode(Type, 0); [_|_] -> case lists:last(BitList) of 1 -> Int = lists:foldr(fun(B, A) -> (A bsl 1) bor B end, 0, BitList), {ok,Encoded} = M:encode(Type, Int); 0 -> %% This BIT STRING cannot be represented %% as an integer. ok end end, Compact = case bit_size(Value) of Bits when Bits rem 8 =:= 0 -> {0,Value}; Bits -> Unused = 8 - Bits rem 8, {Unused,<<Value:Bits/bitstring,0:Unused>>} end, {ok,Encoded} = M:encode(Type, Compact), case M:decode(Type, Encoded) of {ok,Expected} -> ok; {ok,Other} -> Expected = convert(Other, Expected) end end. bs_decode(Type, Encoded, Expected) -> M = 'PrimStrings', case M:decode(Type, Encoded) of {ok,Expected} -> ok; {ok,Other} -> Expected = convert(Other, Expected) end. convert(Val, E) when is_bitstring(Val) -> convert_1(Val, E); convert({Unused,Bin}, E) -> Sz = bit_size(Bin) - Unused, <<Val:Sz/bitstring,_:Unused>> = Bin, convert_1(Val, E); convert(List, E) when is_list(List) -> Val = << <<B:1>> || B <- List >>, convert_1(Val, E). convert_1(Val, E) when is_list(E) -> [B || <<B:1>> <= Val]; convert_1(Val, E) when is_bitstring(E) -> Val.