diff --git a/src/jsx_utils.erl b/src/jsx_utils.erl index eb6fb0f..bfe1900 100644 --- a/src/jsx_utils.erl +++ b/src/jsx_utils.erl @@ -25,13 +25,12 @@ -export([parse_opts/1]). -export([extract_opts/1]). --export([json_escape/2, json_escape_sequence/1]). +-export([json_escape_sequence/1]). -include("jsx_opts.hrl"). %% parsing of jsx opts - parse_opts(Opts) -> parse_opts(Opts, #opts{}). @@ -97,227 +96,6 @@ extract_parser_opts([K|Rest], Acc) -> end. -%% json string escaping, for utf8 binaries. escape the json control sequences to -%% their json equivalent, escape other control characters to \uXXXX sequences, -%% everything else should be a legal json string component - -json_escape(String, Opts) when is_binary(String) -> - case Opts#opts.dirty_strings of - true -> String - ; false -> json_escape(String, Opts, 0, size(String)) - end. - - --define(control_character(X), - <> -> - json_escape( - <>, - Opts, - L + 6, - Len + 5 - ) -). - -json_escape(Str, Opts, L, Len) when L < Len -> - case Str of - ?control_character(0); - ?control_character(1); - ?control_character(2); - ?control_character(3); - ?control_character(4); - ?control_character(5); - ?control_character(6); - ?control_character(7); - <> -> json_escape(<>, Opts, L + 2, Len + 1); - <> -> json_escape(<>, Opts, L + 2, Len + 1); - <> -> json_escape(<>, Opts, L + 2, Len + 1); - ?control_character(11); - <> -> json_escape(<>, Opts, L + 2, Len + 1); - <> -> json_escape(<>, Opts, L + 2, Len + 1); - ?control_character(14); - ?control_character(15); - ?control_character(16); - ?control_character(17); - ?control_character(18); - ?control_character(19); - ?control_character(20); - ?control_character(21); - ?control_character(22); - ?control_character(23); - ?control_character(24); - ?control_character(25); - ?control_character(26); - ?control_character(27); - ?control_character(28); - ?control_character(29); - ?control_character(30); - ?control_character(31); - <<_:L/binary, 32, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 33, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <> -> json_escape(<>, Opts, L + 2, Len + 1); - <<_:L/binary, 35, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 36, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 37, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 38, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 39, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 40, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 41, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 42, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 43, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 44, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 45, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 46, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <> -> - case Opts#opts.escape_forward_slash of - true -> - json_escape(<>, Opts, L + 2, Len + 1); - false -> - json_escape(<>, Opts, L + 1, Len) - end; - <<_:L/binary, 48, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 49, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 50, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 51, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 52, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 53, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 54, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 55, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 56, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 57, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 58, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 59, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 60, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 61, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 62, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 63, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 64, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 65, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 66, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 67, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 68, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 69, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 70, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 71, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 72, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 73, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 74, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 75, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 76, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 77, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 78, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 79, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 80, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 81, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 82, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 83, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 84, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 85, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 86, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 87, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 88, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 89, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 90, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 91, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <> -> json_escape(<>, Opts, L + 2, Len + 1); - <<_:L/binary, 93, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 94, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 95, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 96, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 97, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 98, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 99, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 100, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 101, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 102, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 103, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 104, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 105, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 106, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 107, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 108, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 109, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 110, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 111, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 112, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 113, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 114, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 115, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 116, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 117, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 118, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 119, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 120, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 121, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 122, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 123, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 124, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 125, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 126, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, 127, _/binary>> -> json_escape(Str, Opts, L + 1, Len); - <> -> - case Opts#opts.no_jsonp_escapes of - true -> - json_escape(<>, Opts, L + 3, Len); - false -> - B = unicode:characters_to_binary(json_escape_sequence(16#2028)), - json_escape(<>, Opts, L + 6, Len + 3) - end; - <> -> - case Opts#opts.no_jsonp_escapes of - true -> - json_escape(<>, Opts, L + 3, Len); - false -> - B = unicode:characters_to_binary(json_escape_sequence(16#2029)), - json_escape(<>, Opts, L + 6, Len + 3) - end; - <<_:L/binary, X/utf8, _/binary>> when X < 16#0080 -> - json_escape(Str, Opts, L + 1, Len); - <<_:L/binary, X/utf8, _/binary>> when X < 16#0800 -> - json_escape(Str, Opts, L + 2, Len); - <<_:L/binary, X/utf8, _/binary>> when X < 16#dcff -> - json_escape(Str, Opts, L + 3, Len); - <<_:L/binary, X/utf8, _/binary>> when X > 16#dfff, X < 16#fdd0 -> - json_escape(Str, Opts, L + 3, Len); - <<_:L/binary, X/utf8, _/binary>> when X > 16#fdef, X < 16#fffe -> - json_escape(Str, Opts, L + 3, Len); - <<_:L/binary, X/utf8, _/binary>> when X >= 16#10000, X < 16#1fffe -> - json_escape(Str, Opts, L + 4, Len); - <<_:L/binary, X/utf8, _/binary>> when X >= 16#20000, X < 16#2fffe -> - json_escape(Str, Opts, L + 4, Len); - <<_:L/binary, X/utf8, _/binary>> when X >= 16#30000, X < 16#3fffe -> - json_escape(Str, Opts, L + 4, Len); - <<_:L/binary, X/utf8, _/binary>> when X >= 16#40000, X < 16#4fffe -> - json_escape(Str, Opts, L + 4, Len); - <<_:L/binary, X/utf8, _/binary>> when X >= 16#50000, X < 16#5fffe -> - json_escape(Str, Opts, L + 4, Len); - <<_:L/binary, X/utf8, _/binary>> when X >= 16#60000, X < 16#6fffe -> - json_escape(Str, Opts, L + 4, Len); - <<_:L/binary, X/utf8, _/binary>> when X >= 16#70000, X < 16#7fffe -> - json_escape(Str, Opts, L + 4, Len); - <<_:L/binary, X/utf8, _/binary>> when X >= 16#80000, X < 16#8fffe -> - json_escape(Str, Opts, L + 4, Len); - <<_:L/binary, X/utf8, _/binary>> when X >= 16#90000, X < 16#9fffe -> - json_escape(Str, Opts, L + 4, Len); - <<_:L/binary, X/utf8, _/binary>> when X >= 16#a0000, X < 16#afffe -> - json_escape(Str, Opts, L + 4, Len); - <<_:L/binary, X/utf8, _/binary>> when X >= 16#b0000, X < 16#bfffe -> - json_escape(Str, Opts, L + 4, Len); - <<_:L/binary, X/utf8, _/binary>> when X >= 16#c0000, X < 16#cfffe -> - json_escape(Str, Opts, L + 4, Len); - <<_:L/binary, X/utf8, _/binary>> when X >= 16#d0000, X < 16#dfffe -> - json_escape(Str, Opts, L + 4, Len); - <<_:L/binary, X/utf8, _/binary>> when X >= 16#e0000, X < 16#efffe -> - json_escape(Str, Opts, L + 4, Len); - <<_:L/binary, X/utf8, _/binary>> when X >= 16#f0000, X < 16#ffffe -> - json_escape(Str, Opts, L + 4, Len); - <<_:L/binary, X/utf8, _/binary>> when X >= 16#100000, X < 16#10fffe -> - json_escape(Str, Opts, L + 4, Len); - _ -> erlang:error(badarg, [Str, Opts]) - end; -json_escape(Str, _, L, Len) when L =:= Len -> - Str. - - %% convert a codepoint to it's \uXXXX equiv. json_escape_sequence(X) -> <> = <>, @@ -338,47 +116,13 @@ to_hex(X) -> X + 48. %% ascii "1" is [49], "2" is [50], etc... -include_lib("eunit/include/eunit.hrl"). -binary_escape_test_() -> +json_escape_sequence_test_() -> [ - {"json string escaping", - ?_assertEqual( - json_escape(<<"\"\\\b\f\n\r\t">>, #opts{}), - <<"\\\"\\\\\\b\\f\\n\\r\\t">> - ) - }, - {"json string hex escape", - ?_assertEqual( - json_escape(<<0, 1, 2, 3, 11, 26, 30, 31>>, #opts{}), - <<"\\u0000\\u0001\\u0002\\u0003\\u000b\\u001a\\u001e\\u001f">> - ) - }, - {"jsonp protection", - ?_assertEqual( - json_escape(<<226, 128, 168, 226, 128, 169>>, #opts{}), - <<"\\u2028\\u2029">> - ) - }, - {"no jsonp escapes", - ?_assertEqual( - json_escape(<<226, 128, 168, 226, 128, 169>>, #opts{no_jsonp_escapes=true}), - <<226, 128, 168, 226, 128, 169>> - ) - }, - {"microsoft i hate your date format", - ?_assertEqual( - json_escape(<<"/Date(1303502009425)/">>, #opts{escape_forward_slash=true}), - <<"\\/Date(1303502009425)\\/">> - ) - }, - {"dirty strings", - ?_assertEqual( - json_escape(<<"\\x25\\uffff">>, #opts{dirty_strings=true}), - <<"\\x25\\uffff">> - ) - } + {"json escape sequence test - 16#0000", ?_assertEqual(json_escape_sequence(16#0000), "\\u0000")}, + {"json escape sequence test - 16#abc", ?_assertEqual(json_escape_sequence(16#abc), "\\u0abc")}, + {"json escape sequence test - 16#def", ?_assertEqual(json_escape_sequence(16#def), "\\u0def")} ]. - opts_test_() -> [ {"all flags",