From 302ad9890fbd71ad54cb6a0ae4f5e6cfe198b485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 6 Aug 2013 12:05:21 +0200 Subject: PER, UPER: Fix encoding/decoding of open types greater than 16K --- lib/asn1/src/asn1rt_per_bin.erl | 49 +++++++++++++++++---- lib/asn1/src/asn1rt_per_bin_rt2ct.erl | 61 +++++++++++++++++++++------ lib/asn1/src/asn1rt_uper_bin.erl | 44 ++++++++++++++++--- lib/asn1/test/Makefile | 1 + lib/asn1/test/asn1_SUITE.erl | 7 +++ lib/asn1/test/asn1_SUITE_data/Fragmented.asn1 | 24 +++++++++++ lib/asn1/test/testFragmented.erl | 42 ++++++++++++++++++ 7 files changed, 198 insertions(+), 30 deletions(-) create mode 100644 lib/asn1/test/asn1_SUITE_data/Fragmented.asn1 create mode 100644 lib/asn1/test/testFragmented.erl diff --git a/lib/asn1/src/asn1rt_per_bin.erl b/lib/asn1/src/asn1rt_per_bin.erl index 5772f09bf4..1f8c9729e7 100644 --- a/lib/asn1/src/asn1rt_per_bin.erl +++ b/lib/asn1/src/asn1rt_per_bin.erl @@ -505,12 +505,21 @@ decode_fragmented_octets(<<0:1,Len:7,Bin/binary>>,C,Acc) -> %% | binary %% Contraint = not used in this version %% -encode_open_type(_C, Val) when is_list(Val) -> - Bin = list_to_binary(Val), - [encode_length(undefined,size(Bin)),{octets,Bin}]; % octets implies align -encode_open_type(_C, Val) when is_binary(Val) -> - [encode_length(undefined,size(Val)),{octets,Val}]. % octets implies align -%% the binary_to_list is not optimal but compatible with the current solution +encode_open_type(_Constraint, Val) when is_list(Val) -> + encode_open_type_1(list_to_binary(Val)); +encode_open_type(_Constraint, Val) when is_binary(Val) -> + encode_open_type_1(Val). + +encode_open_type_1(Val0) -> + case byte_size(Val0) of + Size when Size < 16384 -> + [encode_length(undefined, Size),{octets,Val0}]; + Size -> + F = min(Size bsr 14, 4), + SegSz = F * ?'16K', + <> = Val0, + [{octets,<<3:2,F:6>>},{octets,Val}|encode_open_type_1(T)] + end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% decode_open_type(Buffer,Constraint) -> Value @@ -518,9 +527,20 @@ encode_open_type(_C, Val) when is_binary(Val) -> %% Buffer = [byte] with PER encoded data %% Value = [byte] with decoded data (which must be decoded again as some type) %% -decode_open_type(Bytes, _C) -> - {Len,Bytes2} = decode_length(Bytes,undefined), - getoctets_as_bin(Bytes2,Len). +decode_open_type(Bytes, _Constraint) -> + decode_open_type_1(Bytes, []). + +decode_open_type_1(Bytes0, Acc) -> + case decode_length_unlimited(Bytes0) of + {Len,Bytes} when Len < ?'16K', Acc =:= [] -> + getoctets_as_bin(Bytes, Len); + {Len,Bytes1} when Len < ?'16K' -> + {Bin,Bytes} = getoctets_as_bin(Bytes1, Len), + {iolist_to_binary([Acc,Bin]),Bytes}; + {Len,Bytes1} -> + {Bin,Bytes} = getoctets_as_bin(Bytes1, Len), + decode_open_type_1(Bytes, [Acc,Bin]) + end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% encode_integer(Constraint,Value,NamedNumberList) -> CompleteList @@ -884,6 +904,17 @@ decode_small_length(Buffer) -> decode_length(Remain,undefined) end. +decode_length_unlimited(Buffer) -> + case align(Buffer) of + {0,<<0:1,Oct:7,Rest/binary>>} -> + {Oct,{0,Rest}}; + {0,<<1:1,0:1,Val:14,Rest/binary>>} -> + {Val,{0,Rest}}; + {0,<<1:1,1:1,F:6,Rest/binary>>} -> + SegSz = F * ?'16K', + {SegSz,{0,Rest}} + end. + decode_length(Buffer) -> decode_length(Buffer,undefined). diff --git a/lib/asn1/src/asn1rt_per_bin_rt2ct.erl b/lib/asn1/src/asn1rt_per_bin_rt2ct.erl index 1df757a47f..9ce5b086cd 100644 --- a/lib/asn1/src/asn1rt_per_bin_rt2ct.erl +++ b/lib/asn1/src/asn1rt_per_bin_rt2ct.erl @@ -378,21 +378,32 @@ decode_fragmented_octets(<<0:1,Len:7,Bin/binary>>,C,Acc) -> %% Contraint = not used in this version %% encode_open_type(_Constraint, Val) when is_list(Val) -> - Bin = list_to_binary(Val), - case size(Bin) of - Size when Size>255 -> - [encode_length(undefined,Size),[21,<>,Bin]]; - Size -> - [encode_length(undefined,Size),[20,Size,Bin]] - end; + encode_open_type_1(list_to_binary(Val)); encode_open_type(_Constraint, Val) when is_binary(Val) -> - case size(Val) of - Size when Size>255 -> - [encode_length(undefined,size(Val)),[21,<>,Val]]; % octets implies align + encode_open_type_1(Val). + +encode_open_type_1(Val) -> + case byte_size(Val) of + Size when Size < 256 -> + [encode_length(undefined, Size),20,Size,Val]; + Size when Size < 16384 -> + [encode_length(undefined, Size),21,<>,Val]; Size -> - [encode_length(undefined,Size),[20,Size,Val]] + encode_fragmented(Val, Size) + end. + +encode_fragmented(Val0, Size) -> + case Size bsr 14 of + F when F >= 4 -> + <> = Val0, + [20,1,16#C4,<<21,16#8000:16>>,Val1, + <<21,16#8000:16>>,Val2|encode_open_type_1(T)]; + F -> + SegSz = F * ?'16K', + <> = Val0, + [<<20,1,3:2,F:6,21,SegSz:16>>,Val|encode_open_type_1(T)] end. -%% the binary_to_list is not optimal but compatible with the current solution + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% decode_open_type(Buffer,Constraint) -> Value @@ -401,8 +412,19 @@ encode_open_type(_Constraint, Val) when is_binary(Val) -> %% Value = [byte] with decoded data (which must be decoded again as some type) %% decode_open_type(Bytes, _Constraint) -> - {Len,Bytes2} = decode_length(Bytes,undefined), - getoctets_as_bin(Bytes2,Len). + decode_open_type_1(Bytes, []). + +decode_open_type_1(Bytes0, Acc) -> + case decode_length_unlimited(Bytes0) of + {Len,Bytes} when Len < ?'16K', Acc =:= [] -> + getoctets_as_bin(Bytes, Len); + {Len,Bytes1} when Len < ?'16K' -> + {Bin,Bytes} = getoctets_as_bin(Bytes1, Len), + {iolist_to_binary([Acc,Bin]),Bytes}; + {Len,Bytes1} -> + <> = Bytes1, + decode_open_type_1(Bytes, [Acc,Bin]) + end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% encode_integer(Constraint,Value,NamedNumberList) -> CompleteList @@ -788,6 +810,17 @@ decode_small_length(Buffer) -> decode_length(Remain,undefined) end. +decode_length_unlimited(Buffer) -> + case align(Buffer) of + <<0:1,Oct:7,Rest/binary>> -> + {Oct,Rest}; + <<1:1,0:1,Val:14,Rest/binary>> -> + {Val,Rest}; + <<1:1,1:1,F:6,Rest/binary>> -> + SegSz = F * ?'16K', + {SegSz,Rest} + end. + decode_length(Buffer) -> decode_length(Buffer,undefined). diff --git a/lib/asn1/src/asn1rt_uper_bin.erl b/lib/asn1/src/asn1rt_uper_bin.erl index abe178a69e..4e18753a16 100644 --- a/lib/asn1/src/asn1rt_uper_bin.erl +++ b/lib/asn1/src/asn1rt_uper_bin.erl @@ -323,10 +323,21 @@ decode_fragmented_octets(<<0:1,Len:7,BitStr/bitstring>>,C,Acc) -> %% | binary %% Contraint = not used in this version %% -encode_open_type(C, Val) when is_list(Val) -> - encode_open_type(C, list_to_binary(Val)); -encode_open_type(_C, Val) when is_binary(Val) -> - [encode_length(undefined,size(Val)),Val]. +encode_open_type(_Constraint, Val) when is_list(Val) -> + encode_open_type_1(list_to_binary(Val)); +encode_open_type(_Constraint, Val) when is_binary(Val) -> + encode_open_type_1(Val). + +encode_open_type_1(Val0) -> + case byte_size(Val0) of + Size when Size < 16384 -> + [encode_length(undefined, Size),Val0]; + Size -> + F = min(Size bsr 14, 4), + SegSz = F * ?'16K', + <> = Val0, + [<<3:2,F:6>>,Val|encode_open_type_1(T)] + end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -335,9 +346,20 @@ encode_open_type(_C, Val) when is_binary(Val) -> %% Buffer = [byte] with PER encoded data %% Value = [byte] with decoded data (which must be decoded again as some type) %% -decode_open_type(Bytes, _C) -> - {Len,Bytes2} = decode_length(Bytes,undefined), - getoctets_as_bin(Bytes2,Len). +decode_open_type(Bytes, _Constraint) -> + decode_open_type_1(Bytes, []). + +decode_open_type_1(Bytes0, Acc) -> + case decode_length_unlimited(Bytes0) of + {Len,Bytes} when Len < ?'16K', Acc =:= [] -> + getoctets_as_bin(Bytes, Len); + {Len,Bytes1} when Len < ?'16K' -> + {Bin,Bytes} = getoctets_as_bin(Bytes1, Len), + {iolist_to_binary([Acc,Bin]),Bytes}; + {Len,Bytes1} -> + <> = Bytes1, + decode_open_type_1(Bytes, [Acc,Bin]) + end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% encode_integer(Constraint,Value,NamedNumberList) -> CompleteList @@ -632,6 +654,14 @@ decode_small_length(Buffer) -> decode_length(Remain,undefined) end. +decode_length_unlimited(<<0:1,Oct:7,Rest/bitstring>>) -> + {Oct,Rest}; +decode_length_unlimited(<<1:1,0:1,Val:14,Rest/bitstring>>) -> + {Val,Rest}; +decode_length_unlimited(<<1:1,1:1,F:6,Rest/bitstring>>) -> + SegSz = F * ?'16K', + {SegSz,Rest}. + decode_length(Buffer) -> decode_length(Buffer,undefined). diff --git a/lib/asn1/test/Makefile b/lib/asn1/test/Makefile index 6e6374baf1..69b95b40d5 100644 --- a/lib/asn1/test/Makefile +++ b/lib/asn1/test/Makefile @@ -109,6 +109,7 @@ MODULES= \ test_modified_x420 \ testX420 \ test_x691 \ + testFragmented \ asn1_test_lib \ asn1_app_test \ asn1_appup_test \ diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl index be3a6c52c2..b052529ebd 100644 --- a/lib/asn1/test/asn1_SUITE.erl +++ b/lib/asn1/test/asn1_SUITE.erl @@ -168,6 +168,7 @@ groups() -> per_open_type, testInfObjectClass, testParameterizedInfObj, + testFragmented, testMergeCompile, testobj, testDeepTConstr, @@ -816,6 +817,12 @@ testParameterizedInfObj(Config, Rule, Opts) -> asn1_test_lib:compile_all(Files, Config, [Rule|Opts]), testParameterizedInfObj:main(Config, Rule). +testFragmented(Config) -> + test(Config, fun testFragmented/3). +testFragmented(Config, Rule, Opts) -> + asn1_test_lib:compile("Fragmented", Config, [Rule|Opts]), + testFragmented:main(Rule). + testMergeCompile(Config) -> test(Config, fun testMergeCompile/3). testMergeCompile(Config, Rule, Opts) -> Files = ["MS.set.asn", "RANAPSET.set.asn1", "Mvrasn4.set.asn", diff --git a/lib/asn1/test/asn1_SUITE_data/Fragmented.asn1 b/lib/asn1/test/asn1_SUITE_data/Fragmented.asn1 new file mode 100644 index 0000000000..bfc939737f --- /dev/null +++ b/lib/asn1/test/asn1_SUITE_data/Fragmented.asn1 @@ -0,0 +1,24 @@ +Fragmented DEFINITIONS AUTOMATIC TAGS ::= +BEGIN + +FUNCTION ::= CLASS { + &code INTEGER UNIQUE, + &b BOOLEAN, + &ArgumentType +} + +SS ::= SEQUENCE OF OCTET STRING + +val1 FUNCTION ::= { + &code 1, &b FALSE, &ArgumentType SS +} + +ObjSet FUNCTION ::= { val1 } + +PDU ::= SEQUENCE { + code FUNCTION.&code ({ObjSet}), + b FUNCTION.&b ({ObjSet}{@code}), + arg FUNCTION.&ArgumentType ({ObjSet}{@code}) +} + +END diff --git a/lib/asn1/test/testFragmented.erl b/lib/asn1/test/testFragmented.erl new file mode 100644 index 0000000000..17995a05bf --- /dev/null +++ b/lib/asn1/test/testFragmented.erl @@ -0,0 +1,42 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2013. 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(testFragmented). + +-export([main/1]). + +main(_Erule) -> + roundtrip('PDU', {'PDU',1,false,["abc","def"]}), + B256 = lists:seq(0, 255), + K1 = lists:duplicate(4, B256), + K8 = binary_to_list(iolist_to_binary(lists:duplicate(8, K1))), + roundtrip('PDU', {'PDU',1,false,[K8,K8]}), + roundtrip('PDU', {'PDU',1,false,[K8,K8,K8,K8]}), + roundtrip('PDU', {'PDU',1,false,[K8,K8,K8,K8,K8,K8]}), + roundtrip('PDU', {'PDU',1,false,[K8,K8,K8,K8,K8,K8,K8,K8]}), + roundtrip('PDU', {'PDU',1,false,[K8,K8,K8,K8,K8,K8,K8,K8, + K8,K8,K8,K8,K8,K8]}), + roundtrip('PDU', {'PDU',1,false,[K8,K8,K8,K8,K8,K8,K8,K8, + K8,K8,K8,K8,K8,K8,K8,K8]}), + ok. + +roundtrip(T, V) -> + {ok,E} = asn1_wrapper:encode('Fragmented', T, V), + {ok,V} = asn1_wrapper:decode('Fragmented', T, E), + ok. -- cgit v1.2.3