diff --git a/src/msgpack_packer.erl b/src/msgpack_packer.erl index 861f3ff..053a1c6 100644 --- a/src/msgpack_packer.erl +++ b/src/msgpack_packer.erl @@ -66,6 +66,10 @@ pack({string, String}, ?OPTION{spec=new, pack_str=from_tagged_list}=Opt) -> {error, _} -> throw({badarg, String}); Bin when is_binary(Bin) -> Bin end; + +pack({array, List}, ?OPTION{spec=new, pack_str=from_list}=Opt) when is_list(List) -> + pack_array(List, Opt); + pack(List, ?OPTION{spec=new, pack_str=from_list}=Opt) when is_list(List) -> try case lists:all(fun is_integer/1, List) of @@ -154,8 +158,24 @@ pack_uint(N) when (N band 16#FFFFFFFF) =:= N-> pack_uint(N) when (N band 16#FFFFFFFFFFFFFFFF) =:= N -> << 16#CF:8, N:64/big-unsigned-integer-unit:1 >>; %% too big unit -pack_uint(N) -> - throw({badarg, N}). +% https://github.com/msgpack/msgpack/blob/73b3adb3099ef93326a4c93864d8f29e69b0c545/spec.md#bigint-extension-type +pack_uint(N) when N > 0 -> + Bin=binary:encode_unsigned(N), + BS = byte_size(Bin), + if BS==1 -> <<16#d4:8, Bin/binary>>; + BS==2 -> <<16#d5:8, Bin/binary>>; + BS==4 -> <<16#d5:8, Bin/binary>>; + BS==8 -> <<16#d5:8, Bin/binary>>; + BS==16 -> <<16#d5:8, Bin/binary>>; + BS < 256 -> + <<16#C7:8, BS:8/big, -2:8/signed, Bin/binary>>; + BS <65536 -> + <<16#C8:8, BS:16/big, -2:8/signed, Bin/binary>>; + BS < 4294967296 -> + <<16#C9:8, BS:32/big, -2:8/signed, Bin/binary>>; + true -> + throw({badarg, N}) + end. %% @doc float : erlang's float is always IEEE 754 64bit format. Thus it diff --git a/src/msgpack_unpacker.erl b/src/msgpack_unpacker.erl index 3484466..9d7817c 100644 --- a/src/msgpack_unpacker.erl +++ b/src/msgpack_unpacker.erl @@ -259,6 +259,9 @@ unpack_str(Binary) -> maybe_unpack_ext(F, _, _, _, _Rest, _, ?OPTION{spec=old}) -> %% trying to unpack new ext formats with old unpacker throw({badarg, {new_spec, F}}); +% https://github.com/msgpack/msgpack/blob/73b3adb3099ef93326a4c93864d8f29e69b0c545/spec.md#bigint-extension-type +maybe_unpack_ext(_, _, -2, Data, Rest, _, _) -> + {binary:decode_unsigned(Data, big), Rest}; maybe_unpack_ext(F, undefined, _, _, _Rest, _, _) -> throw({badarg, {bad_ext, F}}); maybe_unpack_ext(_, Unpack, Type, Data, Rest, Orig, _) diff --git a/test/msgpack_tests.erl b/test/msgpack_tests.erl index 7b3c5b5..7114eed 100644 --- a/test/msgpack_tests.erl +++ b/test/msgpack_tests.erl @@ -386,6 +386,29 @@ atom_test_() -> <<"atom2">>=><<"binary2">>}}, msgpack:unpack(Bin)), ?_assertEqual({ok,Map1}, msgpack:unpack(Bin,[{known_atoms,[atom1,atom2]}])). +list_pack_test_() -> + [ + {"list or string", + fun() -> + Source=#{ + string=>"hello", + bad_array=>[ 104,101,108,108,111 ], + array=>{array,[ 104,101,108,108,111 ]} + }, + Bin=msgpack:pack(Source,[{spec, new}, {pack_str,from_list}]), + {ok,Repacked}=msgpack:unpack(Bin,[{spec, + new}, + {unpack_str,as_tagged_list}]), + ?assertMatch(#{ + <<"string">> := {string,"hello"}, + <<"bad_array">> := {string, "hello"}, + <<"array">> := [ 104,101,108,108,111 ] + }, Repacked) + end + } + ]. + + -define(PCNT, 5). -define(CNT, 10000).