capricorn 2.0.8 → 2.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/erlang/lib/capricorn/ebin/capricorn.app +2 -1
- data/erlang/lib/capricorn/include/capricorn.hrl +1 -0
- data/erlang/lib/capricorn/src/cap_cluster_gems.erl +6 -1
- data/erlang/lib/capricorn/src/cap_console_dispatcher.erl +214 -0
- data/erlang/lib/capricorn/src/cap_machine_apps.erl +25 -1
- data/erlang/lib/capricorn/src/cap_sup.erl +14 -0
- data/erlang/lib/ejson/Makefile +24 -0
- data/erlang/lib/ejson/ebin/ejson.app +9 -0
- data/erlang/lib/ejson/include/ejson.hrl +40 -0
- data/erlang/lib/ejson/rebar.config +3 -0
- data/erlang/lib/ejson/src/ejson.erl +22 -0
- data/erlang/lib/ejson/src/ejson_decode.erl +337 -0
- data/erlang/lib/ejson/src/ejson_encode.erl +124 -0
- data/erlang/lib/ejson/test/arrays.escript +47 -0
- data/erlang/lib/ejson/test/compound.escript +56 -0
- data/erlang/lib/ejson/test/literals.escript +30 -0
- data/erlang/lib/ejson/test/numbers.escript +70 -0
- data/erlang/lib/ejson/test/objects.escript +51 -0
- data/erlang/lib/ejson/test/strings.escript +49 -0
- data/erlang/lib/ejson/test/timing.escript +43 -0
- data/erlang/lib/ejson/test/timing.json +382 -0
- data/erlang/lib/ejson/vendor/mochijson2.erl +621 -0
- data/erlang/lib/ejson/vendor/rfc4627.erl +625 -0
- data/erlang/lib/misultin/LICENSE.txt +41 -0
- data/erlang/lib/misultin/Makefile +26 -0
- data/erlang/lib/misultin/README.txt +120 -0
- data/erlang/lib/misultin/ebin/misultin.app +9 -0
- data/erlang/lib/misultin/examples/misultin_compress.erl +43 -0
- data/erlang/lib/misultin/examples/misultin_echo.erl +58 -0
- data/erlang/lib/misultin/examples/misultin_file.erl +43 -0
- data/erlang/lib/misultin/examples/misultin_gen_server.erl +158 -0
- data/erlang/lib/misultin/examples/misultin_get_variable.erl +55 -0
- data/erlang/lib/misultin/examples/misultin_hello_world.erl +43 -0
- data/erlang/lib/misultin/examples/misultin_rest.erl +68 -0
- data/erlang/lib/misultin/examples/misultin_ssl.erl +51 -0
- data/erlang/lib/misultin/examples/misultin_stream.erl +55 -0
- data/erlang/lib/misultin/examples/misultin_websocket_event_example.erl +103 -0
- data/erlang/lib/misultin/examples/misultin_websocket_example.erl +95 -0
- data/erlang/lib/misultin/include/misultin.hrl +95 -0
- data/erlang/lib/misultin/make.bat +55 -0
- data/erlang/lib/misultin/priv/README.txt +12 -0
- data/erlang/lib/misultin/priv/test_certificate.pem +21 -0
- data/erlang/lib/misultin/priv/test_privkey.pem +18 -0
- data/erlang/lib/misultin/rebar.config +3 -0
- data/erlang/lib/misultin/src/misultin.app.src +9 -0
- data/erlang/lib/misultin/src/misultin.erl +338 -0
- data/erlang/lib/misultin/src/misultin_http.erl +488 -0
- data/erlang/lib/misultin/src/misultin_req.erl +280 -0
- data/erlang/lib/misultin/src/misultin_socket.erl +193 -0
- data/erlang/lib/misultin/src/misultin_utility.erl +357 -0
- data/erlang/lib/misultin/src/misultin_websocket.erl +252 -0
- data/erlang/lib/misultin/src/misultin_ws.erl +78 -0
- data/erlang/rebar.config +2 -0
- data/erlang/rel/overlay/etc/capricorn/app.config +4 -0
- data/erlang/rel/reltool.config +5 -0
- data/lib/capricorn/recipes/apache-debian.rb +1 -1
- data/lib/capricorn/recipes/centos-plesk.rb +1 -1
- data/lib/capricorn/recipes/debian-plesk95.rb +1 -2
- data/lib/capricorn/recipes/macports.rb +1 -1
- data/lib/capricorn/version.rb +1 -1
- metadata +51 -4
@@ -0,0 +1,337 @@
|
|
1
|
+
|
2
|
+
-module(ejson_decode).
|
3
|
+
|
4
|
+
-export([value/1]).
|
5
|
+
|
6
|
+
-include("ejson.hrl").
|
7
|
+
|
8
|
+
value(Bin) ->
|
9
|
+
case strip(Bin) of
|
10
|
+
<<?LC:8/integer, Rest/binary>> ->
|
11
|
+
object(strip(Rest), []);
|
12
|
+
<<?LB:8/integer, Rest/binary>> ->
|
13
|
+
array(strip(Rest), []);
|
14
|
+
<<?DQ:8/integer, Rest/binary>> ->
|
15
|
+
string(Rest, []);
|
16
|
+
<<"false", Rest/binary>> ->
|
17
|
+
{Rest, false};
|
18
|
+
<<"true", Rest/binary>> ->
|
19
|
+
{Rest, true};
|
20
|
+
<<"null", Rest/binary>> ->
|
21
|
+
{Rest, null};
|
22
|
+
<<First:8/integer, Rest/binary>> ->
|
23
|
+
case First of
|
24
|
+
?HY ->
|
25
|
+
neg_number(Rest, [First]);
|
26
|
+
?ZR ->
|
27
|
+
flt_number(Rest, [First]);
|
28
|
+
_ when First > ?ZR andalso First =< ?NI ->
|
29
|
+
number(Rest, [First]);
|
30
|
+
?PL ->
|
31
|
+
?EXIT({invalid_number, plus_prefix_is_invalid});
|
32
|
+
?PR ->
|
33
|
+
?EXIT({invalid_number, decimals_require_a_zero});
|
34
|
+
_ ->
|
35
|
+
?EXIT({invalid_value, no_decodable_value})
|
36
|
+
end;
|
37
|
+
<<>> ->
|
38
|
+
?EXIT({invalid_value, no_more_data})
|
39
|
+
end.
|
40
|
+
|
41
|
+
object(Bin, Acc) ->
|
42
|
+
case pair(Bin) of
|
43
|
+
{Rest, close_obj} when length(Acc) == 0 ->
|
44
|
+
{Rest, {[]}};
|
45
|
+
{_, close_obj} ->
|
46
|
+
?EXIT({invalid_object, no_key_after_comma});
|
47
|
+
{Rest, KVPair} ->
|
48
|
+
case strip(Rest) of
|
49
|
+
<<?RC:8/integer, Rest2/binary>> ->
|
50
|
+
{strip(Rest2), {lists:reverse([KVPair | Acc])}};
|
51
|
+
<<?CM:8/integer, Rest2/binary>> ->
|
52
|
+
object(strip(Rest2), [KVPair | Acc]);
|
53
|
+
<<>> ->
|
54
|
+
?EXIT({invalid_object, no_more_data});
|
55
|
+
_ ->
|
56
|
+
?EXIT({invalid_object, no_comma_or_close})
|
57
|
+
end
|
58
|
+
end.
|
59
|
+
|
60
|
+
pair(Bin) ->
|
61
|
+
case strip(Bin) of
|
62
|
+
<<?RC:8/integer, Rest/binary>> ->
|
63
|
+
{Rest, close_obj};
|
64
|
+
<<?DQ:8/integer, Rest/binary>> ->
|
65
|
+
{Rest2, Key} = string(Rest, []),
|
66
|
+
case strip(Rest2) of
|
67
|
+
<<?CL:8/integer, Rest3/binary>> ->
|
68
|
+
{Rest4, Val} = value(Rest3),
|
69
|
+
{Rest4, {Key, Val}};
|
70
|
+
<<>> ->
|
71
|
+
?EXIT({invalid_object, no_more_data});
|
72
|
+
_ ->
|
73
|
+
?EXIT({invalid_object, no_colon_after_key})
|
74
|
+
end;
|
75
|
+
<<>> ->
|
76
|
+
?EXIT({invalid_object, no_more_data});
|
77
|
+
_ ->
|
78
|
+
?EXIT({invalid_object, no_key_or_close})
|
79
|
+
end.
|
80
|
+
|
81
|
+
array(<<>>, _) ->
|
82
|
+
?EXIT({invalid_array, no_more_data});
|
83
|
+
array(<<?CM:8/integer, Rest/binary>>, Acc) when length(Acc) > 0 ->
|
84
|
+
{Rest2, Value} = value(Rest),
|
85
|
+
array(strip(Rest2), [Value | Acc]);
|
86
|
+
array(<<?RB:8/integer, Rest/binary>>, Acc) ->
|
87
|
+
{Rest, lists:reverse(Acc)};
|
88
|
+
array(Bin, Acc) when length(Acc) == 0 ->
|
89
|
+
{Rest, Value} = value(Bin),
|
90
|
+
array(strip(Rest), [Value | Acc]);
|
91
|
+
array(_, _) ->
|
92
|
+
?EXIT({invalid_array, trailing_data}).
|
93
|
+
|
94
|
+
string(Bin, Acc) ->
|
95
|
+
case Bin of
|
96
|
+
<<?DQ:8/integer, Rest/binary>> ->
|
97
|
+
{Rest, list_to_binary(lists:reverse(Acc))};
|
98
|
+
<<?ESDQ:16/integer, Rest/binary>> ->
|
99
|
+
string(Rest, [<<?DQ:8/integer>> | Acc]);
|
100
|
+
<<?ESRS:16/integer, Rest/binary>> ->
|
101
|
+
string(Rest, [<<?RS:8/integer>> | Acc]);
|
102
|
+
<<?ESFS:16/integer, Rest/binary>> ->
|
103
|
+
string(Rest, [<<?FS:8/integer>> | Acc]);
|
104
|
+
<<?ESBS:16/integer, Rest/binary>> ->
|
105
|
+
string(Rest, [<<?BS:8/integer>> | Acc]);
|
106
|
+
<<?ESFF:16/integer, Rest/binary>> ->
|
107
|
+
string(Rest, [<<?FF:8/integer>> | Acc]);
|
108
|
+
<<?ESNL:16/integer, Rest/binary>> ->
|
109
|
+
string(Rest, [<<?NL:8/integer>> | Acc]);
|
110
|
+
<<?ESCR:16/integer, Rest/binary>> ->
|
111
|
+
string(Rest, [<<?CR:8/integer>> | Acc]);
|
112
|
+
<<?ESTB:16/integer, Rest/binary>> ->
|
113
|
+
string(Rest, [<<?TB:8/integer>> | Acc]);
|
114
|
+
<<?ESUE:16/integer, Rest/binary>> ->
|
115
|
+
{Rest2, Unescaped} = unicode_escape(Rest),
|
116
|
+
string(Rest2, [Unescaped | Acc]);
|
117
|
+
<<>> ->
|
118
|
+
?EXIT({invalid_string, no_more_data});
|
119
|
+
_ ->
|
120
|
+
case fast_string(Bin, 0) of
|
121
|
+
Pos when Pos > 0 ->
|
122
|
+
<<Fast:Pos/binary, Rest/binary>> = Bin,
|
123
|
+
string(Rest, [Fast | Acc]);
|
124
|
+
_ ->
|
125
|
+
?EXIT({invalid_string, unknown_escape})
|
126
|
+
end
|
127
|
+
end.
|
128
|
+
|
129
|
+
unicode_escape(Bin) ->
|
130
|
+
case Bin of
|
131
|
+
<<C1, C2, C3, C4, ?RS:8/integer, "u", D1, D2, D3, D4, Rest/binary>> ->
|
132
|
+
C = erlang:list_to_integer([C1, C2, C3, C4], 16),
|
133
|
+
D = erlang:list_to_integer([D1, D2, D3, D4], 16),
|
134
|
+
BinCodePoint = <<C:16/unsigned-integer, D:16/unsigned-integer>>,
|
135
|
+
case (catch xmerl_ucs:from_utf16be(BinCodePoint)) of
|
136
|
+
[CodePoint] ->
|
137
|
+
{Rest, list_to_binary(xmerl_ucs:to_utf8(CodePoint))};
|
138
|
+
_Else ->
|
139
|
+
Rest2 = <<?RS:8/integer, "u", D1, D2, D3, D4, Rest/binary>>,
|
140
|
+
{Rest2, crap_point(C)}
|
141
|
+
end;
|
142
|
+
<<C1, C2, C3, C4, Rest/binary>> ->
|
143
|
+
C = erlang:list_to_integer([C1, C2, C3, C4], 16),
|
144
|
+
case (catch xmerl_ucs:to_utf8(C)) of
|
145
|
+
CodePoint when is_list(CodePoint) ->
|
146
|
+
{Rest, list_to_binary(CodePoint)};
|
147
|
+
_Else ->
|
148
|
+
{Rest, crap_point(C)}
|
149
|
+
end;
|
150
|
+
_ ->
|
151
|
+
?EXIT({invalid_unicode_escape, no_more_data})
|
152
|
+
end.
|
153
|
+
|
154
|
+
% http://en.wikipedia.org/wiki/UTF-8#Description
|
155
|
+
crap_point(C) when C =< 16#7F ->
|
156
|
+
<<C:16/integer>>;
|
157
|
+
crap_point(C) when C =< 16#7FF ->
|
158
|
+
<<0:5/bits, C1:5/bits, C2:6/bits>> = <<C:16/integer>>,
|
159
|
+
<<6:3/integer, C1:5/bits, 2:2/integer, C2:6/bits>>;
|
160
|
+
crap_point(C) when C =< 16#FFFF ->
|
161
|
+
<<C1:4/bits, C2:6/bits, C3:6/bits>> = <<C:16/integer>>,
|
162
|
+
<<14:4/integer, C1:4/bits, 2:2/integer, C2:6/bits, 2:2/integer, C3:6/bits>>;
|
163
|
+
crap_point(C) when C =< 16#1FFFFF ->
|
164
|
+
C0 = <<C:32/integer>>,
|
165
|
+
<<0:11/bits, C1:3/bits, C2:6/bits, C3:6/bits, C4:6/bits>> = C0,
|
166
|
+
<<30:5/integer, C1:3/bits, 2:2/integer, C2:6/bits,
|
167
|
+
2:2/integer, C3:6/bits, 2:2/integer, C4:6/bits>>;
|
168
|
+
crap_point(_) ->
|
169
|
+
?EXIT({invalid_rfc, email_douglas_crockford_to_complain}).
|
170
|
+
|
171
|
+
fast_string(<<>>, _) ->
|
172
|
+
?EXIT({invalid_string, no_more_data});
|
173
|
+
fast_string(<<?DQ:8/integer, _/binary>>, Pos) ->
|
174
|
+
Pos;
|
175
|
+
fast_string(<<?RS:8/integer, _/binary>>, Pos) ->
|
176
|
+
Pos;
|
177
|
+
|
178
|
+
% Checking UTF-8
|
179
|
+
fast_string(Bin, Pos) ->
|
180
|
+
case Bin of
|
181
|
+
<<C1, Rest/binary>> when
|
182
|
+
C1 >= 16#20, C1 =< 16#7F ->
|
183
|
+
fast_string(Rest, Pos+1);
|
184
|
+
<<C1, C2, Rest/binary>> when
|
185
|
+
C1 >= 16#C2, C1 =< 16#DF,
|
186
|
+
C2 >= 16#7F, C2 =< 16#BF ->
|
187
|
+
fast_string(Rest, Pos+2);
|
188
|
+
<<C1, C2, C3, Rest/binary>> when
|
189
|
+
C1 >= 16#E0, C1 =< 16#EF,
|
190
|
+
C2 >= 16#7F, C2 =< 16#BF,
|
191
|
+
C3 >= 16#7F, C3 =< 16#BF ->
|
192
|
+
fast_string(Rest, Pos+3);
|
193
|
+
<<C1, C2, C3, C4, Rest/binary>> when
|
194
|
+
C1 >= 16#F0, C1 =< 16#F4,
|
195
|
+
C2 >= 16#7F, C2 =< 16#BF,
|
196
|
+
C3 >= 16#7F, C3 =< 16#BF,
|
197
|
+
C4 >= 16#7F, C4 =< 16#BF ->
|
198
|
+
fast_string(Rest, Pos+4);
|
199
|
+
_ ->
|
200
|
+
?EXIT({invalid_string, invalid_utf_8})
|
201
|
+
end.
|
202
|
+
|
203
|
+
|
204
|
+
number(<<>>, Acc) ->
|
205
|
+
{<<>>, list_to_integer(lists:reverse(Acc))};
|
206
|
+
number(<<First:8/integer, Rest/binary>>, Acc) ->
|
207
|
+
case First of
|
208
|
+
?PR ->
|
209
|
+
flt_number(<<First:8/integer, Rest/binary>>, Acc);
|
210
|
+
_ when First >= ?ZR andalso First =< ?NI ->
|
211
|
+
number(Rest, [First | Acc]);
|
212
|
+
_ when First =:= ?UE orelse First =:= ?LE ->
|
213
|
+
exp_sign(Rest, [First, ?ZR, ?PR | Acc]);
|
214
|
+
_ ->
|
215
|
+
case lists:member(First, [?TB, ?NL, ?CR, ?SP, ?CM, ?RB, ?RC]) of
|
216
|
+
true ->
|
217
|
+
Value = list_to_integer(lists:reverse(Acc)),
|
218
|
+
{<<First:8/integer, Rest/binary>>, Value};
|
219
|
+
_ ->
|
220
|
+
?EXIT({invalid_number, invalid_digit})
|
221
|
+
end
|
222
|
+
end.
|
223
|
+
|
224
|
+
neg_number(<<>>, [?HY]) ->
|
225
|
+
?EXIT({invalid_number, lonely_hyphen});
|
226
|
+
neg_number(<<>>, Acc) ->
|
227
|
+
{<<>>, list_to_integer(lists:reverse(Acc))};
|
228
|
+
neg_number(<<?ZR:8/integer, Rest/binary>>, Acc) ->
|
229
|
+
flt_number(Rest, [?ZR | Acc]);
|
230
|
+
neg_number(<<First:8/integer, Rest/binary>>, Acc) ->
|
231
|
+
case First of
|
232
|
+
?PR ->
|
233
|
+
flt_number(<<First:8/integer, Rest/binary>>, Acc);
|
234
|
+
_ when First > ?ZR andalso First =< ?NI ->
|
235
|
+
number(Rest, [First | Acc]);
|
236
|
+
_ when First =:= ?UE orelse First =:= ?LE ->
|
237
|
+
exp_sign(Rest, [First, ?ZR, ?PR | Acc]);
|
238
|
+
_ ->
|
239
|
+
case lists:member(First, [?TB, ?NL, ?CR, ?SP, ?CM, ?RB, ?RC]) of
|
240
|
+
true ->
|
241
|
+
Value = list_to_integer(lists:reverse(Acc)),
|
242
|
+
{<<First:8/integer, Rest/binary>>, Value};
|
243
|
+
_ ->
|
244
|
+
?EXIT({invalid_number, leading_zero})
|
245
|
+
end
|
246
|
+
end.
|
247
|
+
|
248
|
+
% Special cases for <<"0">>, <<"0E3">>, etc.
|
249
|
+
flt_number(<<>>, [?ZR]) ->
|
250
|
+
{<<>>, 0};
|
251
|
+
flt_number(<<?UE:8/integer, Rest/binary>>, [?ZR]) ->
|
252
|
+
exp_sign(Rest, [?UE, ?ZR, ?PR, ?ZR]);
|
253
|
+
flt_number(<<?LE:8/integer, Rest/binary>>, [?ZR]) ->
|
254
|
+
exp_sign(Rest, [?LE, ?ZR, ?PR, ?ZR]);
|
255
|
+
flt_number(<<?PR:8/integer, First:8/integer, Rest/binary>>, [?ZR]) ->
|
256
|
+
case First of
|
257
|
+
_ when First >= ?ZR andalso First =< ?NI ->
|
258
|
+
frac_number(Rest, [First, ?PR, ?ZR]);
|
259
|
+
_ ->
|
260
|
+
?EXIT({invalid_number, not_digit_after_decimal})
|
261
|
+
end;
|
262
|
+
flt_number(<<First:8/integer, Rest/binary>>, [?ZR]) ->
|
263
|
+
case lists:member(First, [?TB, ?NL, ?CR, ?SP, ?CM, ?RB, ?RC]) of
|
264
|
+
true ->
|
265
|
+
{<<First:8/integer, Rest/binary>>, 0};
|
266
|
+
_ ->
|
267
|
+
?EXIT({invalid_number, leading_zero})
|
268
|
+
end;
|
269
|
+
|
270
|
+
flt_number(<<>>, _Acc) ->
|
271
|
+
?EXIT({invalid_number, no_more_data});
|
272
|
+
flt_number(<<?PR:8/integer>>, _) ->
|
273
|
+
?EXIT({invalid_number, missing_fraction});
|
274
|
+
flt_number(<<?PR:8/integer, First:8/integer, Rest/binary>>, Acc) ->
|
275
|
+
case First of
|
276
|
+
_ when First >= ?ZR andalso First =< ?NI ->
|
277
|
+
frac_number(Rest, [First, ?PR | Acc]);
|
278
|
+
_ ->
|
279
|
+
?EXIT({invalid_number, not_digit_after_decimal})
|
280
|
+
end;
|
281
|
+
flt_number(<<First:8/integer, _/binary>>, Acc) ->
|
282
|
+
?EXIT({invalid_number, lists:reverse([First | Acc])}).
|
283
|
+
|
284
|
+
frac_number(<<>>, Acc) ->
|
285
|
+
{<<>>, list_to_float(lists:reverse(Acc))};
|
286
|
+
frac_number(<<First:8/integer, Rest/binary>>=Bin, Acc) ->
|
287
|
+
case First of
|
288
|
+
_ when First >= ?ZR andalso First =< ?NI ->
|
289
|
+
frac_number(Rest, [First | Acc]);
|
290
|
+
_ when First =:= ?UE orelse First =:= ?LE ->
|
291
|
+
exp_sign(Rest, [First | Acc]);
|
292
|
+
_ ->
|
293
|
+
{Bin, list_to_float(lists:reverse(Acc))}
|
294
|
+
end.
|
295
|
+
|
296
|
+
exp_sign(<<>>, _) ->
|
297
|
+
?EXIT({invalid_number, invalid_exponent});
|
298
|
+
exp_sign(<<?PL:8/integer, Rest/binary>>, Acc) ->
|
299
|
+
exp_number(Rest, Acc);
|
300
|
+
exp_sign(<<?HY:8/integer, Rest/binary>>, Acc) ->
|
301
|
+
exp_number(Rest, [?HY | Acc]);
|
302
|
+
exp_sign(Bin, Acc) ->
|
303
|
+
exp_number(Bin, Acc).
|
304
|
+
|
305
|
+
exp_number(<<>>, Acc) ->
|
306
|
+
{<<>>, list_to_float(lists:reverse(Acc))};
|
307
|
+
exp_number(<<First:8/integer, Rest/binary>>, Acc) ->
|
308
|
+
case First of
|
309
|
+
_ when First >= ?ZR andalso First =< ?NI ->
|
310
|
+
exp_number(Rest, [First | Acc]);
|
311
|
+
_ ->
|
312
|
+
case lists:member(First, [?TB, ?NL, ?CR, ?SP, ?CM, ?RB, ?RC]) of
|
313
|
+
true ->
|
314
|
+
case Acc of
|
315
|
+
[?UE|_] ->
|
316
|
+
?EXIT({invalid_number, no_exponent_after_e});
|
317
|
+
[?LE|_] ->
|
318
|
+
?EXIT({invalid_number, no_exponent_after_e});
|
319
|
+
_ ->
|
320
|
+
Value = erlang:list_to_float(lists:reverse(Acc)),
|
321
|
+
{<<First:8/integer, Rest/binary>>, Value}
|
322
|
+
end;
|
323
|
+
_ ->
|
324
|
+
?EXIT({invalid_number, invalid_digit_in_exponent})
|
325
|
+
end
|
326
|
+
end.
|
327
|
+
|
328
|
+
strip(<<?TB:8/integer, Rest/binary>>) ->
|
329
|
+
strip(Rest);
|
330
|
+
strip(<<?NL:8/integer, Rest/binary>>) ->
|
331
|
+
strip(Rest);
|
332
|
+
strip(<<?CR:8/integer, Rest/binary>>) ->
|
333
|
+
strip(Rest);
|
334
|
+
strip(<<?SP:8/integer, Rest/binary>>) ->
|
335
|
+
strip(Rest);
|
336
|
+
strip(Bin) ->
|
337
|
+
Bin.
|
@@ -0,0 +1,124 @@
|
|
1
|
+
|
2
|
+
-module(ejson_encode).
|
3
|
+
|
4
|
+
-export([value/1]).
|
5
|
+
|
6
|
+
-include("ejson.hrl").
|
7
|
+
|
8
|
+
value({O}) when is_list(O) ->
|
9
|
+
object(O, [<<?LC:8/integer>>]);
|
10
|
+
value(L) when is_list(L) ->
|
11
|
+
array(L, [<<?LB:8/integer>>]);
|
12
|
+
value(true) ->
|
13
|
+
<<"true">>;
|
14
|
+
value(false) ->
|
15
|
+
<<"false">>;
|
16
|
+
value(null) ->
|
17
|
+
<<"null">>;
|
18
|
+
value(S) when is_atom(S); is_binary(S) ->
|
19
|
+
string(S);
|
20
|
+
value(I) when is_integer(I) ->
|
21
|
+
list_to_binary(integer_to_list(I));
|
22
|
+
value(F) when is_float(F) ->
|
23
|
+
list_to_binary(io_lib:format("~p", [F]));
|
24
|
+
value(B) ->
|
25
|
+
throw({invalid_json, {badarg, B}}).
|
26
|
+
|
27
|
+
object([], Acc) ->
|
28
|
+
list_to_binary(lists:reverse([<<?RC:8/integer>> | Acc]));
|
29
|
+
object([{K, V} | Rest], Acc) when length(Acc) =:= 1 ->
|
30
|
+
Acc2 = [value(V), <<?CL:8/integer>>, string(K) | Acc],
|
31
|
+
object(Rest, Acc2);
|
32
|
+
object([{K, V} | Rest], Acc) ->
|
33
|
+
Acc2 = [value(V), <<?CL:8/integer>>, string(K), <<?CM:8/integer>> | Acc],
|
34
|
+
object(Rest, Acc2).
|
35
|
+
|
36
|
+
array([], Acc) ->
|
37
|
+
list_to_binary(lists:reverse([<<?RB:8/integer>> | Acc]));
|
38
|
+
array([V | Rest], Acc) when length(Acc) =:= 1 ->
|
39
|
+
array(Rest, [value(V) | Acc]);
|
40
|
+
array([V | Rest], Acc) ->
|
41
|
+
array(Rest, [value(V), <<?CM:8/integer>> | Acc]).
|
42
|
+
|
43
|
+
string(A) when is_atom(A) ->
|
44
|
+
string(list_to_binary(atom_to_list(A)), [<<?DQ:8/integer>>]);
|
45
|
+
string(B) when is_binary(B) ->
|
46
|
+
string(B, [<<?DQ:8/integer>>]);
|
47
|
+
string(Bad) ->
|
48
|
+
?EXIT({invalid_string, {bad_term, Bad}}).
|
49
|
+
|
50
|
+
string(Bin, Acc) ->
|
51
|
+
case Bin of
|
52
|
+
<<>> ->
|
53
|
+
list_to_binary(lists:reverse([<<?DQ:8/integer>> | Acc]));
|
54
|
+
<<?DQ:8/integer, Rest/binary>> ->
|
55
|
+
string(Rest, [<<?ESDQ:16/integer>> | Acc]);
|
56
|
+
<<?RS:8/integer, Rest/binary>> ->
|
57
|
+
string(Rest, [<<?ESRS:16/integer>> | Acc]);
|
58
|
+
<<?FS:8/integer, Rest/binary>> ->
|
59
|
+
string(Rest, [<<?ESFS:16/integer>> | Acc]);
|
60
|
+
<<?BS:8/integer, Rest/binary>> ->
|
61
|
+
string(Rest, [<<?ESBS:16/integer>> | Acc]);
|
62
|
+
<<?FF:8/integer, Rest/binary>> ->
|
63
|
+
string(Rest, [<<?ESFF:16/integer>> | Acc]);
|
64
|
+
<<?NL:8/integer, Rest/binary>> ->
|
65
|
+
string(Rest, [<<?ESNL:16/integer>> | Acc]);
|
66
|
+
<<?CR:8/integer, Rest/binary>> ->
|
67
|
+
string(Rest, [<<?ESCR:16/integer>> | Acc]);
|
68
|
+
<<?TB:8/integer, Rest/binary>> ->
|
69
|
+
string(Rest, [<<?ESTB:16/integer>> | Acc]);
|
70
|
+
_ ->
|
71
|
+
case fast_string(Bin, 0) of
|
72
|
+
Pos when Pos > 0 ->
|
73
|
+
<<Fast:Pos/binary, Rest/binary>> = Bin,
|
74
|
+
string(Rest, [Fast | Acc]);
|
75
|
+
_ ->
|
76
|
+
{Rest, Escaped} = unicode_escape(Bin),
|
77
|
+
string(Rest, [Escaped | Acc])
|
78
|
+
end
|
79
|
+
end.
|
80
|
+
|
81
|
+
fast_string(<<>>, Pos) ->
|
82
|
+
Pos;
|
83
|
+
fast_string(<<C:8/integer, _/binary>>, Pos) when
|
84
|
+
C == ?DQ; C == ?RS; C == ?FS; C == ?BS;
|
85
|
+
C == ?FF; C == ?NL; C == ?CR; C == ?TB ->
|
86
|
+
Pos;
|
87
|
+
fast_string(<<C, Rest/binary>>, Pos) when C >= ?SP, C < 16#7F ->
|
88
|
+
fast_string(Rest, Pos+1);
|
89
|
+
fast_string(_, Pos) ->
|
90
|
+
Pos.
|
91
|
+
|
92
|
+
unicode_escape(Bin) ->
|
93
|
+
case Bin of
|
94
|
+
<<D:8/integer, Rest/binary>> when D =< ?SP ->
|
95
|
+
{Rest, hex_escape(D)};
|
96
|
+
<<6:3/integer, C1:5/bits, 2:2/integer, C2:6/bits, Rest/binary>> ->
|
97
|
+
<<C:16/integer>> = <<0:5/integer, C1:5/bits, C2:6/bits>>,
|
98
|
+
{Rest, hex_escape(C)};
|
99
|
+
<<14:4/integer, C1:4/bits, 2:2/integer, C2:6/bits,
|
100
|
+
2:2/integer, C3:6/bits, Rest/binary>> ->
|
101
|
+
<<C:16/integer>> = <<C1:4/bits, C2:6/bits, C3:6/bits>>,
|
102
|
+
{Rest, hex_escape(C)};
|
103
|
+
<<30:5/integer, C1:3/bits, 2:2/integer, C2:6/bits, 2:2/integer,
|
104
|
+
C3:6/bits, 2:2/integer, C4:6/bits, Rest/binary>> ->
|
105
|
+
<<C:32/integer>> =
|
106
|
+
<<0:11/integer, C1:3/bits, C2:6/bits, C3:6/bits, C4:6/bits>>,
|
107
|
+
{Rest, hex_escape(C)};
|
108
|
+
_ ->
|
109
|
+
?EXIT(invalid_utf8)
|
110
|
+
end.
|
111
|
+
|
112
|
+
hex_escape(C) when C =< 16#FFFF ->
|
113
|
+
<<C1:4, C2:4, C3:4, C4:4>> = <<C:16>>,
|
114
|
+
["\\u"] ++ [hex_digit(C0) || C0 <- [C1, C2, C3, C4]];
|
115
|
+
hex_escape(C) ->
|
116
|
+
BinCodePoint = list_to_binary(xmerl_ucs:to_utf16be(C)),
|
117
|
+
<<D:16/unsigned-integer, E:16/unsigned-integer>> = BinCodePoint,
|
118
|
+
[hex_escape(D), hex_escape(E)].
|
119
|
+
|
120
|
+
hex_digit(D) when D >= 0, D =< 9 ->
|
121
|
+
$0 + D;
|
122
|
+
hex_digit(D) when D >= 10, D =< 15 ->
|
123
|
+
$A + (D - 10).
|
124
|
+
|