jsone_encode.erl 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. %%% @doc JSON encoding module
  2. %%% @private
  3. %%% @end
  4. %%%
  5. %%% Copyright (c) 2013-2014, Takeru Ohta <phjgt308@gmail.com>
  6. %%%
  7. %%% The MIT License
  8. %%%
  9. %%% Permission is hereby granted, free of charge, to any person obtaining a copy
  10. %%% of this software and associated documentation files (the "Software"), to deal
  11. %%% in the Software without restriction, including without limitation the rights
  12. %%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. %%% copies of the Software, and to permit persons to whom the Software is
  14. %%% furnished to do so, subject to the following conditions:
  15. %%%
  16. %%% The above copyright notice and this permission notice shall be included in
  17. %%% all copies or substantial portions of the Software.
  18. %%%
  19. %%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. %%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. %%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. %%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. %%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. %%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. %%% THE SOFTWARE.
  26. %%%
  27. %%%---------------------------------------------------------------------------------------
  28. -module(jsone_encode).
  29. -compile([native, {hipe, [o3]}]).
  30. %%--------------------------------------------------------------------------------
  31. %% Exported API
  32. %%--------------------------------------------------------------------------------
  33. -export([encode/1]).
  34. %%--------------------------------------------------------------------------------
  35. %% Macros
  36. %%--------------------------------------------------------------------------------
  37. -define(ERROR(Function, Args), {error, {badarg, [{?MODULE, Function, Args, [{line, ?LINE}]}]}}).
  38. -define(IS_REDUNDANT_UTF8(B1, B2, FirstBitN), (B1 =:= 0 andalso B2 < (1 bsl (FirstBitN + 1)))).
  39. -define(HEX(N, I), (binary:at(<<"0123456789abcdef">>, (N bsr (I * 4)) band 2#1111))).
  40. -define(UNICODE_TO_HEX(Code), ?HEX(Code, 3), ?HEX(Code, 2), ?HEX(Code, 1), ?HEX(Code, 0)).
  41. %%--------------------------------------------------------------------------------
  42. %% Exported Functions
  43. %%--------------------------------------------------------------------------------
  44. %% @doc JSON値をバイナリ形式にエンコードする.
  45. % -spec encode(jsone:json_value()) -> binary().
  46. encode(Value) ->
  47. value(Value, [], <<"">>).
  48. %%--------------------------------------------------------------------------------
  49. %% Internal Functions
  50. %%--------------------------------------------------------------------------------
  51. next([], Buf) -> {ok, Buf};
  52. next([Next | Nexts], Buf) ->
  53. case Next of
  54. {array_values, Values} ->
  55. case Values of
  56. [] -> array_values(Values, Nexts, Buf);
  57. _ -> array_values(Values, Nexts, <<Buf/binary, $,>>)
  58. end;
  59. {object_value, Value, Members} ->
  60. object_value(Value, Members, Nexts, Buf);
  61. {object_members, Members} ->
  62. case Members of
  63. [] -> object_members(Members, Nexts, Buf);
  64. _ -> object_members(Members, Nexts, <<Buf/binary, $,>>)
  65. end
  66. end.
  67. % -spec value(jsone:json_value(), binary()) -> binary().
  68. value(null, Nexts, Buf) -> next(Nexts, <<Buf/binary, "null">>);
  69. value(false, Nexts, Buf) -> next(Nexts, <<Buf/binary, "false">>);
  70. value(true, Nexts, Buf) -> next(Nexts, <<Buf/binary, "true">>);
  71. value(Value, Nexts, Buf) when is_integer(Value) -> next(Nexts, <<Buf/binary, (integer_to_binary(Value))/binary>>);
  72. value(Value, Nexts, Buf) when is_float(Value) -> next(Nexts, <<Buf/binary, (float_to_binary(Value))/binary>>);
  73. value(Value, Nexts, Buf) when is_binary(Value) -> string(Value, Nexts, Buf);
  74. value(Value, Nexts, Buf) when is_list(Value) -> array(Value, Nexts, Buf);
  75. value({_} = Value, Nexts, Buf) -> object(Value, Nexts, Buf);
  76. value(Value, Nexts, Buf) -> ?ERROR(value, [Value, Nexts, Buf]).
  77. % -spec string(jsone:json_string(), binary()) -> binary().
  78. string(<<Str/binary>>, Nexts, Buf) ->
  79. escape_string(Str, Nexts, <<Buf/binary, $">>).
  80. % -spec escape_string(binary(), binary()) -> binary().
  81. escape_string(<<"">>, Nexts, Buf) -> next(Nexts, <<Buf/binary, $">>);
  82. escape_string(<<$", Str/binary>>, Nexts, Buf) -> escape_string(Str, Nexts, <<Buf/binary, $\\, $">>);
  83. escape_string(<<$\/, Str/binary>>, Nexts, Buf) -> escape_string(Str, Nexts, <<Buf/binary, $\\, $\/>>);
  84. escape_string(<<$\\, Str/binary>>, Nexts, Buf) -> escape_string(Str, Nexts, <<Buf/binary, $\\, $\\>>);
  85. escape_string(<<$\b, Str/binary>>, Nexts, Buf) -> escape_string(Str, Nexts, <<Buf/binary, $\\, $b>>);
  86. escape_string(<<$\f, Str/binary>>, Nexts, Buf) -> escape_string(Str, Nexts, <<Buf/binary, $\\, $f>>);
  87. escape_string(<<$\n, Str/binary>>, Nexts, Buf) -> escape_string(Str, Nexts, <<Buf/binary, $\\, $n>>);
  88. escape_string(<<$\r, Str/binary>>, Nexts, Buf) -> escape_string(Str, Nexts, <<Buf/binary, $\\, $r>>);
  89. escape_string(<<$\t, Str/binary>>, Nexts, Buf) -> escape_string(Str, Nexts, <<Buf/binary, $\\, $t>>);
  90. escape_string(<<0:1, C:7, Str/binary>>, Nexts, Buf) -> escape_string(Str, Nexts, <<Buf/binary, C>>);
  91. escape_string(<<2#110:3, B1:5, 2#10:2, B2:6, Str/binary>>, Nexts, Buf) when not ?IS_REDUNDANT_UTF8(B1, B2, 5) ->
  92. Unicode = (B1 bsl 6) + B2,
  93. escape_unicode_char(Str, Unicode, Nexts, Buf);
  94. escape_string(<<2#1110:4, B1:4, 2#10:2, B2:6, 2#10:2, B3:6, Str/binary>>, Nexts, Buf) when not ?IS_REDUNDANT_UTF8(B1, B2, 4) ->
  95. Unicode = (B1 bsl 12) + (B2 bsl 6) + B3,
  96. escape_unicode_char(Str, Unicode, Nexts, Buf);
  97. escape_string(<<2#11110:5, B1:3, 2#10:2, B2:6, 2#10:2, B3:6, 2#10:2, B4:6, Str/binary>>, Nexts, Buf) when not ?IS_REDUNDANT_UTF8(B1, B2, 3) ->
  98. Unicode = (B1 bsl 18) + (B2 bsl 12) + (B3 bsl 6) + B4,
  99. escape_unicode_char(Str, Unicode, Nexts, Buf);
  100. escape_string(Str, Nexts, Buf) ->
  101. ?ERROR(escape_string, [Str, Nexts, Buf]).
  102. % -spec escape_unicode_char(binary(), char(), binary()) -> binary().
  103. escape_unicode_char(<<Str/binary>>, Unicode, Nexts, Buf) when Unicode =< 16#FFFF ->
  104. escape_string(Str, Nexts, <<Buf/binary, $\\, $u, ?UNICODE_TO_HEX(Unicode)>>);
  105. escape_unicode_char(<<Str/binary>>, Unicode, Nexts, Buf) ->
  106. %% サロゲートペア
  107. <<High:10, Low:10>> = <<(Unicode - 16#10000):20>>, % 非効率
  108. escape_string(Str, Nexts, <<Buf/binary, $\\, $u, ?UNICODE_TO_HEX(High + 16#D800), $\\, $u, ?UNICODE_TO_HEX(Low + 16#DC00)>>).
  109. % -spec array(jsone:json_array(), binary()) -> binary().
  110. array(List, Nexts, Buf) ->
  111. array_values(List, Nexts, <<Buf/binary, $[>>).
  112. % -spec array_values(jsone:json_array(), binary()) -> binary().
  113. array_values([], Nexts, Buf) -> next(Nexts, <<Buf/binary, $]>>);
  114. array_values([X | Xs], Nexts, Buf) -> value(X, [{array_values, Xs} | Nexts], Buf).
  115. % -spec object(jsone:json_object(), binary()) -> binary().
  116. object({Members}, Nexts, Buf) ->
  117. object_members(Members, Nexts, <<Buf/binary, ${>>).
  118. % -spec object_members(jsone:json_object_members(), binary()) -> binary().
  119. object_members([], Nexts, Buf) -> next(Nexts, <<Buf/binary, $}>>);
  120. object_members([{<<Key/binary>>, Value} | Xs], Nexts, Buf) -> string(Key, [{object_value, Value, Xs} | Nexts], Buf);
  121. object_members(Arg, Nexts, Buf) -> ?ERROR(object_members, [Arg, Nexts, Buf]).
  122. object_value(Value, Members, Nexts, Buf) ->
  123. value(Value, [{object_members, Members} | Nexts], <<Buf/binary, $:>>).