capricorn 2.0.8 → 2.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/erlang/lib/capricorn/ebin/capricorn.app +2 -1
  2. data/erlang/lib/capricorn/include/capricorn.hrl +1 -0
  3. data/erlang/lib/capricorn/src/cap_cluster_gems.erl +6 -1
  4. data/erlang/lib/capricorn/src/cap_console_dispatcher.erl +214 -0
  5. data/erlang/lib/capricorn/src/cap_machine_apps.erl +25 -1
  6. data/erlang/lib/capricorn/src/cap_sup.erl +14 -0
  7. data/erlang/lib/ejson/Makefile +24 -0
  8. data/erlang/lib/ejson/ebin/ejson.app +9 -0
  9. data/erlang/lib/ejson/include/ejson.hrl +40 -0
  10. data/erlang/lib/ejson/rebar.config +3 -0
  11. data/erlang/lib/ejson/src/ejson.erl +22 -0
  12. data/erlang/lib/ejson/src/ejson_decode.erl +337 -0
  13. data/erlang/lib/ejson/src/ejson_encode.erl +124 -0
  14. data/erlang/lib/ejson/test/arrays.escript +47 -0
  15. data/erlang/lib/ejson/test/compound.escript +56 -0
  16. data/erlang/lib/ejson/test/literals.escript +30 -0
  17. data/erlang/lib/ejson/test/numbers.escript +70 -0
  18. data/erlang/lib/ejson/test/objects.escript +51 -0
  19. data/erlang/lib/ejson/test/strings.escript +49 -0
  20. data/erlang/lib/ejson/test/timing.escript +43 -0
  21. data/erlang/lib/ejson/test/timing.json +382 -0
  22. data/erlang/lib/ejson/vendor/mochijson2.erl +621 -0
  23. data/erlang/lib/ejson/vendor/rfc4627.erl +625 -0
  24. data/erlang/lib/misultin/LICENSE.txt +41 -0
  25. data/erlang/lib/misultin/Makefile +26 -0
  26. data/erlang/lib/misultin/README.txt +120 -0
  27. data/erlang/lib/misultin/ebin/misultin.app +9 -0
  28. data/erlang/lib/misultin/examples/misultin_compress.erl +43 -0
  29. data/erlang/lib/misultin/examples/misultin_echo.erl +58 -0
  30. data/erlang/lib/misultin/examples/misultin_file.erl +43 -0
  31. data/erlang/lib/misultin/examples/misultin_gen_server.erl +158 -0
  32. data/erlang/lib/misultin/examples/misultin_get_variable.erl +55 -0
  33. data/erlang/lib/misultin/examples/misultin_hello_world.erl +43 -0
  34. data/erlang/lib/misultin/examples/misultin_rest.erl +68 -0
  35. data/erlang/lib/misultin/examples/misultin_ssl.erl +51 -0
  36. data/erlang/lib/misultin/examples/misultin_stream.erl +55 -0
  37. data/erlang/lib/misultin/examples/misultin_websocket_event_example.erl +103 -0
  38. data/erlang/lib/misultin/examples/misultin_websocket_example.erl +95 -0
  39. data/erlang/lib/misultin/include/misultin.hrl +95 -0
  40. data/erlang/lib/misultin/make.bat +55 -0
  41. data/erlang/lib/misultin/priv/README.txt +12 -0
  42. data/erlang/lib/misultin/priv/test_certificate.pem +21 -0
  43. data/erlang/lib/misultin/priv/test_privkey.pem +18 -0
  44. data/erlang/lib/misultin/rebar.config +3 -0
  45. data/erlang/lib/misultin/src/misultin.app.src +9 -0
  46. data/erlang/lib/misultin/src/misultin.erl +338 -0
  47. data/erlang/lib/misultin/src/misultin_http.erl +488 -0
  48. data/erlang/lib/misultin/src/misultin_req.erl +280 -0
  49. data/erlang/lib/misultin/src/misultin_socket.erl +193 -0
  50. data/erlang/lib/misultin/src/misultin_utility.erl +357 -0
  51. data/erlang/lib/misultin/src/misultin_websocket.erl +252 -0
  52. data/erlang/lib/misultin/src/misultin_ws.erl +78 -0
  53. data/erlang/rebar.config +2 -0
  54. data/erlang/rel/overlay/etc/capricorn/app.config +4 -0
  55. data/erlang/rel/reltool.config +5 -0
  56. data/lib/capricorn/recipes/apache-debian.rb +1 -1
  57. data/lib/capricorn/recipes/centos-plesk.rb +1 -1
  58. data/lib/capricorn/recipes/debian-plesk95.rb +1 -2
  59. data/lib/capricorn/recipes/macports.rb +1 -1
  60. data/lib/capricorn/version.rb +1 -1
  61. 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
+