dependabot-hex 0.107.13 → 0.107.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/helpers/deps/jason/.fetch +0 -0
- data/helpers/deps/jason/.hex +2 -0
- data/helpers/deps/jason/CHANGELOG.md +60 -0
- data/helpers/deps/jason/LICENSE +13 -0
- data/helpers/deps/jason/README.md +179 -0
- data/helpers/deps/jason/hex_metadata.config +20 -0
- data/helpers/deps/jason/lib/codegen.ex +158 -0
- data/helpers/deps/jason/lib/decoder.ex +657 -0
- data/helpers/deps/jason/lib/encode.ex +630 -0
- data/helpers/deps/jason/lib/encoder.ex +216 -0
- data/helpers/deps/jason/lib/formatter.ex +253 -0
- data/helpers/deps/jason/lib/fragment.ex +11 -0
- data/helpers/deps/jason/lib/helpers.ex +90 -0
- data/helpers/deps/jason/lib/jason.ex +228 -0
- data/helpers/deps/jason/mix.exs +92 -0
- metadata +18 -3
@@ -0,0 +1,630 @@
|
|
1
|
+
defmodule Jason.EncodeError do
|
2
|
+
defexception [:message]
|
3
|
+
|
4
|
+
@type t :: %__MODULE__{message: String.t}
|
5
|
+
|
6
|
+
def new({:duplicate_key, key}) do
|
7
|
+
%__MODULE__{message: "duplicate key: #{key}"}
|
8
|
+
end
|
9
|
+
def new({:invalid_byte, byte, original}) do
|
10
|
+
%__MODULE__{message: "invalid byte #{inspect byte, base: :hex} in #{inspect original}"}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
defmodule Jason.Encode do
|
15
|
+
@moduledoc """
|
16
|
+
Utilities for encoding elixir values to JSON.
|
17
|
+
"""
|
18
|
+
|
19
|
+
import Bitwise
|
20
|
+
|
21
|
+
alias Jason.{Codegen, EncodeError, Encoder, Fragment}
|
22
|
+
|
23
|
+
@typep escape :: (String.t, String.t, integer -> iodata)
|
24
|
+
@typep encode_map :: (map, escape, encode_map -> iodata)
|
25
|
+
@opaque opts :: {escape, encode_map}
|
26
|
+
|
27
|
+
# @compile :native
|
28
|
+
|
29
|
+
@doc false
|
30
|
+
@spec encode(any, map) :: {:ok, iodata} | {:error, EncodeError.t | Exception.t}
|
31
|
+
def encode(value, opts) do
|
32
|
+
escape = escape_function(opts)
|
33
|
+
encode_map = encode_map_function(opts)
|
34
|
+
try do
|
35
|
+
{:ok, value(value, escape, encode_map)}
|
36
|
+
catch
|
37
|
+
:throw, %EncodeError{} = e ->
|
38
|
+
{:error, e}
|
39
|
+
:error, %Protocol.UndefinedError{protocol: Jason.Encoder} = e ->
|
40
|
+
{:error, e}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
defp encode_map_function(%{maps: maps}) do
|
45
|
+
case maps do
|
46
|
+
:naive -> &map_naive/3
|
47
|
+
:strict -> &map_strict/3
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
defp escape_function(%{escape: escape}) do
|
52
|
+
case escape do
|
53
|
+
:json -> &escape_json/3
|
54
|
+
:html_safe -> &escape_html/3
|
55
|
+
:unicode_safe -> &escape_unicode/3
|
56
|
+
:javascript_safe -> &escape_javascript/3
|
57
|
+
# Keep for compatibility with Poison
|
58
|
+
:javascript -> &escape_javascript/3
|
59
|
+
:unicode -> &escape_unicode/3
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
@doc """
|
64
|
+
Equivalent to calling the `Jason.Encoder.encode/2` protocol function.
|
65
|
+
|
66
|
+
Slightly more efficient for built-in types because of the internal dispatching.
|
67
|
+
"""
|
68
|
+
@spec value(term, opts) :: iodata
|
69
|
+
def value(value, {escape, encode_map}) do
|
70
|
+
value(value, escape, encode_map)
|
71
|
+
end
|
72
|
+
|
73
|
+
@doc false
|
74
|
+
# We use this directly in the helpers and deriving for extra speed
|
75
|
+
def value(value, escape, _encode_map) when is_atom(value) do
|
76
|
+
encode_atom(value, escape)
|
77
|
+
end
|
78
|
+
|
79
|
+
def value(value, escape, _encode_map) when is_binary(value) do
|
80
|
+
encode_string(value, escape)
|
81
|
+
end
|
82
|
+
|
83
|
+
def value(value, _escape, _encode_map) when is_integer(value) do
|
84
|
+
integer(value)
|
85
|
+
end
|
86
|
+
|
87
|
+
def value(value, _escape, _encode_map) when is_float(value) do
|
88
|
+
float(value)
|
89
|
+
end
|
90
|
+
|
91
|
+
def value(value, escape, encode_map) when is_list(value) do
|
92
|
+
list(value, escape, encode_map)
|
93
|
+
end
|
94
|
+
|
95
|
+
def value(%{__struct__: module} = value, escape, encode_map) do
|
96
|
+
struct(value, escape, encode_map, module)
|
97
|
+
end
|
98
|
+
|
99
|
+
def value(value, escape, encode_map) when is_map(value) do
|
100
|
+
encode_map.(value, escape, encode_map)
|
101
|
+
end
|
102
|
+
|
103
|
+
def value(value, escape, encode_map) do
|
104
|
+
Encoder.encode(value, {escape, encode_map})
|
105
|
+
end
|
106
|
+
|
107
|
+
@compile {:inline, integer: 1, float: 1}
|
108
|
+
|
109
|
+
@spec atom(atom, opts) :: iodata
|
110
|
+
def atom(atom, {escape, _encode_map}) do
|
111
|
+
encode_atom(atom, escape)
|
112
|
+
end
|
113
|
+
|
114
|
+
defp encode_atom(nil, _escape), do: "null"
|
115
|
+
defp encode_atom(true, _escape), do: "true"
|
116
|
+
defp encode_atom(false, _escape), do: "false"
|
117
|
+
defp encode_atom(atom, escape),
|
118
|
+
do: encode_string(Atom.to_string(atom), escape)
|
119
|
+
|
120
|
+
@spec integer(integer) :: iodata
|
121
|
+
def integer(integer) do
|
122
|
+
Integer.to_string(integer)
|
123
|
+
end
|
124
|
+
|
125
|
+
@spec float(float) :: iodata
|
126
|
+
def float(float) do
|
127
|
+
:io_lib_format.fwrite_g(float)
|
128
|
+
end
|
129
|
+
|
130
|
+
@spec list(list, opts) :: iodata
|
131
|
+
def list(list, {escape, encode_map}) do
|
132
|
+
list(list, escape, encode_map)
|
133
|
+
end
|
134
|
+
|
135
|
+
defp list([], _escape, _encode_map) do
|
136
|
+
"[]"
|
137
|
+
end
|
138
|
+
|
139
|
+
defp list([head | tail], escape, encode_map) do
|
140
|
+
[?[, value(head, escape, encode_map)
|
141
|
+
| list_loop(tail, escape, encode_map)]
|
142
|
+
end
|
143
|
+
|
144
|
+
defp list_loop([], _escape, _encode_map) do
|
145
|
+
']'
|
146
|
+
end
|
147
|
+
|
148
|
+
defp list_loop([head | tail], escape, encode_map) do
|
149
|
+
[?,, value(head, escape, encode_map)
|
150
|
+
| list_loop(tail, escape, encode_map)]
|
151
|
+
end
|
152
|
+
|
153
|
+
@spec map(map, opts) :: iodata
|
154
|
+
def map(value, {escape, encode_map}) do
|
155
|
+
encode_map.(value, escape, encode_map)
|
156
|
+
end
|
157
|
+
|
158
|
+
defp map_naive(value, escape, encode_map) do
|
159
|
+
case Map.to_list(value) do
|
160
|
+
[] -> "{}"
|
161
|
+
[{key, value} | tail] ->
|
162
|
+
["{\"", key(key, escape), "\":",
|
163
|
+
value(value, escape, encode_map)
|
164
|
+
| map_naive_loop(tail, escape, encode_map)]
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
defp map_naive_loop([], _escape, _encode_map) do
|
169
|
+
'}'
|
170
|
+
end
|
171
|
+
|
172
|
+
defp map_naive_loop([{key, value} | tail], escape, encode_map) do
|
173
|
+
[",\"", key(key, escape), "\":",
|
174
|
+
value(value, escape, encode_map)
|
175
|
+
| map_naive_loop(tail, escape, encode_map)]
|
176
|
+
end
|
177
|
+
|
178
|
+
defp map_strict(value, escape, encode_map) do
|
179
|
+
case Map.to_list(value) do
|
180
|
+
[] -> "{}"
|
181
|
+
[{key, value} | tail] ->
|
182
|
+
key = IO.iodata_to_binary(key(key, escape))
|
183
|
+
visited = %{key => []}
|
184
|
+
["{\"", key, "\":",
|
185
|
+
value(value, escape, encode_map)
|
186
|
+
| map_strict_loop(tail, escape, encode_map, visited)]
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
defp map_strict_loop([], _encode_map, _escape, _visited) do
|
191
|
+
'}'
|
192
|
+
end
|
193
|
+
|
194
|
+
defp map_strict_loop([{key, value} | tail], escape, encode_map, visited) do
|
195
|
+
key = IO.iodata_to_binary(key(key, escape))
|
196
|
+
case visited do
|
197
|
+
%{^key => _} ->
|
198
|
+
error({:duplicate_key, key})
|
199
|
+
_ ->
|
200
|
+
visited = Map.put(visited, key, [])
|
201
|
+
[",\"", key, "\":",
|
202
|
+
value(value, escape, encode_map)
|
203
|
+
| map_strict_loop(tail, escape, encode_map, visited)]
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
@spec struct(struct, opts) :: iodata
|
208
|
+
def struct(%module{} = value, {escape, encode_map}) do
|
209
|
+
struct(value, escape, encode_map, module)
|
210
|
+
end
|
211
|
+
|
212
|
+
# TODO: benchmark the effect of inlining the to_iso8601 functions
|
213
|
+
for module <- [Date, Time, NaiveDateTime, DateTime] do
|
214
|
+
defp struct(value, _escape, _encode_map, unquote(module)) do
|
215
|
+
[?\", unquote(module).to_iso8601(value), ?\"]
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
defp struct(value, _escape, _encode_map, Decimal) do
|
220
|
+
# silence the xref warning
|
221
|
+
decimal = Decimal
|
222
|
+
[?\", decimal.to_string(value, :normal), ?\"]
|
223
|
+
end
|
224
|
+
|
225
|
+
defp struct(value, escape, encode_map, Fragment) do
|
226
|
+
%{encode: encode} = value
|
227
|
+
encode.({escape, encode_map})
|
228
|
+
end
|
229
|
+
|
230
|
+
defp struct(value, escape, encode_map, _module) do
|
231
|
+
Encoder.encode(value, {escape, encode_map})
|
232
|
+
end
|
233
|
+
|
234
|
+
@doc false
|
235
|
+
# This is used in the helpers and deriving implementation
|
236
|
+
def key(string, escape) when is_binary(string) do
|
237
|
+
escape.(string, string, 0)
|
238
|
+
end
|
239
|
+
def key(atom, escape) when is_atom(atom) do
|
240
|
+
string = Atom.to_string(atom)
|
241
|
+
escape.(string, string, 0)
|
242
|
+
end
|
243
|
+
def key(other, escape) do
|
244
|
+
string = String.Chars.to_string(other)
|
245
|
+
escape.(string, string, 0)
|
246
|
+
end
|
247
|
+
|
248
|
+
@spec string(String.t, opts) :: iodata
|
249
|
+
def string(string, {escape, _encode_map}) do
|
250
|
+
encode_string(string, escape)
|
251
|
+
end
|
252
|
+
|
253
|
+
defp encode_string(string, escape) do
|
254
|
+
[?\", escape.(string, string, 0), ?\"]
|
255
|
+
end
|
256
|
+
|
257
|
+
slash_escapes = Enum.zip('\b\t\n\f\r\"\\', 'btnfr"\\')
|
258
|
+
surogate_escapes = Enum.zip([0x2028, 0x2029], ["\\u2028", "\\u2029"])
|
259
|
+
ranges = [{0x00..0x1F, :unicode} | slash_escapes]
|
260
|
+
html_ranges = [{0x00..0x1F, :unicode}, {?/, ?/} | slash_escapes]
|
261
|
+
escape_jt = Codegen.jump_table(html_ranges, :error)
|
262
|
+
|
263
|
+
Enum.each(escape_jt, fn
|
264
|
+
{byte, :unicode} ->
|
265
|
+
sequence = List.to_string(:io_lib.format("\\u~4.16.0B", [byte]))
|
266
|
+
defp escape(unquote(byte)), do: unquote(sequence)
|
267
|
+
{byte, char} when is_integer(char) ->
|
268
|
+
defp escape(unquote(byte)), do: unquote(<<?\\, char>>)
|
269
|
+
{byte, :error} ->
|
270
|
+
defp escape(unquote(byte)), do: throw(:error)
|
271
|
+
end)
|
272
|
+
|
273
|
+
## regular JSON escape
|
274
|
+
|
275
|
+
json_jt = Codegen.jump_table(ranges, :chunk, 0x7F + 1)
|
276
|
+
|
277
|
+
defp escape_json(data, original, skip) do
|
278
|
+
escape_json(data, [], original, skip)
|
279
|
+
end
|
280
|
+
|
281
|
+
Enum.map(json_jt, fn
|
282
|
+
{byte, :chunk} ->
|
283
|
+
defp escape_json(<<byte, rest::bits>>, acc, original, skip)
|
284
|
+
when byte === unquote(byte) do
|
285
|
+
escape_json_chunk(rest, acc, original, skip, 1)
|
286
|
+
end
|
287
|
+
{byte, _escape} ->
|
288
|
+
defp escape_json(<<byte, rest::bits>>, acc, original, skip)
|
289
|
+
when byte === unquote(byte) do
|
290
|
+
acc = [acc | escape(byte)]
|
291
|
+
escape_json(rest, acc, original, skip + 1)
|
292
|
+
end
|
293
|
+
end)
|
294
|
+
defp escape_json(<<char::utf8, rest::bits>>, acc, original, skip)
|
295
|
+
when char <= 0x7FF do
|
296
|
+
escape_json_chunk(rest, acc, original, skip, 2)
|
297
|
+
end
|
298
|
+
defp escape_json(<<char::utf8, rest::bits>>, acc, original, skip)
|
299
|
+
when char <= 0xFFFF do
|
300
|
+
escape_json_chunk(rest, acc, original, skip, 3)
|
301
|
+
end
|
302
|
+
defp escape_json(<<_char::utf8, rest::bits>>, acc, original, skip) do
|
303
|
+
escape_json_chunk(rest, acc, original, skip, 4)
|
304
|
+
end
|
305
|
+
defp escape_json(<<>>, acc, _original, _skip) do
|
306
|
+
acc
|
307
|
+
end
|
308
|
+
defp escape_json(<<byte, _rest::bits>>, _acc, original, _skip) do
|
309
|
+
error({:invalid_byte, byte, original})
|
310
|
+
end
|
311
|
+
|
312
|
+
Enum.map(json_jt, fn
|
313
|
+
{byte, :chunk} ->
|
314
|
+
defp escape_json_chunk(<<byte, rest::bits>>, acc, original, skip, len)
|
315
|
+
when byte === unquote(byte) do
|
316
|
+
escape_json_chunk(rest, acc, original, skip, len + 1)
|
317
|
+
end
|
318
|
+
{byte, _escape} ->
|
319
|
+
defp escape_json_chunk(<<byte, rest::bits>>, acc, original, skip, len)
|
320
|
+
when byte === unquote(byte) do
|
321
|
+
part = binary_part(original, skip, len)
|
322
|
+
acc = [acc, part | escape(byte)]
|
323
|
+
escape_json(rest, acc, original, skip + len + 1)
|
324
|
+
end
|
325
|
+
end)
|
326
|
+
defp escape_json_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
|
327
|
+
when char <= 0x7FF do
|
328
|
+
escape_json_chunk(rest, acc, original, skip, len + 2)
|
329
|
+
end
|
330
|
+
defp escape_json_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
|
331
|
+
when char <= 0xFFFF do
|
332
|
+
escape_json_chunk(rest, acc, original, skip, len + 3)
|
333
|
+
end
|
334
|
+
defp escape_json_chunk(<<_char::utf8, rest::bits>>, acc, original, skip, len) do
|
335
|
+
escape_json_chunk(rest, acc, original, skip, len + 4)
|
336
|
+
end
|
337
|
+
defp escape_json_chunk(<<>>, acc, original, skip, len) do
|
338
|
+
part = binary_part(original, skip, len)
|
339
|
+
[acc | part]
|
340
|
+
end
|
341
|
+
defp escape_json_chunk(<<byte, _rest::bits>>, _acc, original, _skip, _len) do
|
342
|
+
error({:invalid_byte, byte, original})
|
343
|
+
end
|
344
|
+
|
345
|
+
## javascript safe JSON escape
|
346
|
+
|
347
|
+
defp escape_javascript(data, original, skip) do
|
348
|
+
escape_javascript(data, [], original, skip)
|
349
|
+
end
|
350
|
+
|
351
|
+
Enum.map(json_jt, fn
|
352
|
+
{byte, :chunk} ->
|
353
|
+
defp escape_javascript(<<byte, rest::bits>>, acc, original, skip)
|
354
|
+
when byte === unquote(byte) do
|
355
|
+
escape_javascript_chunk(rest, acc, original, skip, 1)
|
356
|
+
end
|
357
|
+
{byte, _escape} ->
|
358
|
+
defp escape_javascript(<<byte, rest::bits>>, acc, original, skip)
|
359
|
+
when byte === unquote(byte) do
|
360
|
+
acc = [acc | escape(byte)]
|
361
|
+
escape_javascript(rest, acc, original, skip + 1)
|
362
|
+
end
|
363
|
+
end)
|
364
|
+
defp escape_javascript(<<char::utf8, rest::bits>>, acc, original, skip)
|
365
|
+
when char <= 0x7FF do
|
366
|
+
escape_javascript_chunk(rest, acc, original, skip, 2)
|
367
|
+
end
|
368
|
+
Enum.map(surogate_escapes, fn {byte, escape} ->
|
369
|
+
defp escape_javascript(<<unquote(byte)::utf8, rest::bits>>, acc, original, skip) do
|
370
|
+
acc = [acc | unquote(escape)]
|
371
|
+
escape_javascript(rest, acc, original, skip + 3)
|
372
|
+
end
|
373
|
+
end)
|
374
|
+
defp escape_javascript(<<char::utf8, rest::bits>>, acc, original, skip)
|
375
|
+
when char <= 0xFFFF do
|
376
|
+
escape_javascript_chunk(rest, acc, original, skip, 3)
|
377
|
+
end
|
378
|
+
defp escape_javascript(<<_char::utf8, rest::bits>>, acc, original, skip) do
|
379
|
+
escape_javascript_chunk(rest, acc, original, skip, 4)
|
380
|
+
end
|
381
|
+
defp escape_javascript(<<>>, acc, _original, _skip) do
|
382
|
+
acc
|
383
|
+
end
|
384
|
+
defp escape_javascript(<<byte, _rest::bits>>, _acc, original, _skip) do
|
385
|
+
error({:invalid_byte, byte, original})
|
386
|
+
end
|
387
|
+
|
388
|
+
Enum.map(json_jt, fn
|
389
|
+
{byte, :chunk} ->
|
390
|
+
defp escape_javascript_chunk(<<byte, rest::bits>>, acc, original, skip, len)
|
391
|
+
when byte === unquote(byte) do
|
392
|
+
escape_javascript_chunk(rest, acc, original, skip, len + 1)
|
393
|
+
end
|
394
|
+
{byte, _escape} ->
|
395
|
+
defp escape_javascript_chunk(<<byte, rest::bits>>, acc, original, skip, len)
|
396
|
+
when byte === unquote(byte) do
|
397
|
+
part = binary_part(original, skip, len)
|
398
|
+
acc = [acc, part | escape(byte)]
|
399
|
+
escape_javascript(rest, acc, original, skip + len + 1)
|
400
|
+
end
|
401
|
+
end)
|
402
|
+
defp escape_javascript_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
|
403
|
+
when char <= 0x7FF do
|
404
|
+
escape_javascript_chunk(rest, acc, original, skip, len + 2)
|
405
|
+
end
|
406
|
+
Enum.map(surogate_escapes, fn {byte, escape} ->
|
407
|
+
defp escape_javascript_chunk(<<unquote(byte)::utf8, rest::bits>>, acc, original, skip, len) do
|
408
|
+
part = binary_part(original, skip, len)
|
409
|
+
acc = [acc, part | unquote(escape)]
|
410
|
+
escape_javascript(rest, acc, original, skip + len + 3)
|
411
|
+
end
|
412
|
+
end)
|
413
|
+
defp escape_javascript_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
|
414
|
+
when char <= 0xFFFF do
|
415
|
+
escape_javascript_chunk(rest, acc, original, skip, len + 3)
|
416
|
+
end
|
417
|
+
defp escape_javascript_chunk(<<_char::utf8, rest::bits>>, acc, original, skip, len) do
|
418
|
+
escape_javascript_chunk(rest, acc, original, skip, len + 4)
|
419
|
+
end
|
420
|
+
defp escape_javascript_chunk(<<>>, acc, original, skip, len) do
|
421
|
+
part = binary_part(original, skip, len)
|
422
|
+
[acc | part]
|
423
|
+
end
|
424
|
+
defp escape_javascript_chunk(<<byte, _rest::bits>>, _acc, original, _skip, _len) do
|
425
|
+
error({:invalid_byte, byte, original})
|
426
|
+
end
|
427
|
+
|
428
|
+
## HTML safe JSON escape
|
429
|
+
|
430
|
+
html_jt = Codegen.jump_table(html_ranges, :chunk, 0x7F + 1)
|
431
|
+
|
432
|
+
defp escape_html(data, original, skip) do
|
433
|
+
escape_html(data, [], original, skip)
|
434
|
+
end
|
435
|
+
|
436
|
+
Enum.map(html_jt, fn
|
437
|
+
{byte, :chunk} ->
|
438
|
+
defp escape_html(<<byte, rest::bits>>, acc, original, skip)
|
439
|
+
when byte === unquote(byte) do
|
440
|
+
escape_html_chunk(rest, acc, original, skip, 1)
|
441
|
+
end
|
442
|
+
{byte, _escape} ->
|
443
|
+
defp escape_html(<<byte, rest::bits>>, acc, original, skip)
|
444
|
+
when byte === unquote(byte) do
|
445
|
+
acc = [acc | escape(byte)]
|
446
|
+
escape_html(rest, acc, original, skip + 1)
|
447
|
+
end
|
448
|
+
end)
|
449
|
+
defp escape_html(<<char::utf8, rest::bits>>, acc, original, skip)
|
450
|
+
when char <= 0x7FF do
|
451
|
+
escape_html_chunk(rest, acc, original, skip, 2)
|
452
|
+
end
|
453
|
+
Enum.map(surogate_escapes, fn {byte, escape} ->
|
454
|
+
defp escape_html(<<unquote(byte)::utf8, rest::bits>>, acc, original, skip) do
|
455
|
+
acc = [acc | unquote(escape)]
|
456
|
+
escape_html(rest, acc, original, skip + 3)
|
457
|
+
end
|
458
|
+
end)
|
459
|
+
defp escape_html(<<char::utf8, rest::bits>>, acc, original, skip)
|
460
|
+
when char <= 0xFFFF do
|
461
|
+
escape_html_chunk(rest, acc, original, skip, 3)
|
462
|
+
end
|
463
|
+
defp escape_html(<<_char::utf8, rest::bits>>, acc, original, skip) do
|
464
|
+
escape_html_chunk(rest, acc, original, skip, 4)
|
465
|
+
end
|
466
|
+
defp escape_html(<<>>, acc, _original, _skip) do
|
467
|
+
acc
|
468
|
+
end
|
469
|
+
defp escape_html(<<byte, _rest::bits>>, _acc, original, _skip) do
|
470
|
+
error({:invalid_byte, byte, original})
|
471
|
+
end
|
472
|
+
|
473
|
+
Enum.map(html_jt, fn
|
474
|
+
{byte, :chunk} ->
|
475
|
+
defp escape_html_chunk(<<byte, rest::bits>>, acc, original, skip, len)
|
476
|
+
when byte === unquote(byte) do
|
477
|
+
escape_html_chunk(rest, acc, original, skip, len + 1)
|
478
|
+
end
|
479
|
+
{byte, _escape} ->
|
480
|
+
defp escape_html_chunk(<<byte, rest::bits>>, acc, original, skip, len)
|
481
|
+
when byte === unquote(byte) do
|
482
|
+
part = binary_part(original, skip, len)
|
483
|
+
acc = [acc, part | escape(byte)]
|
484
|
+
escape_html(rest, acc, original, skip + len + 1)
|
485
|
+
end
|
486
|
+
end)
|
487
|
+
defp escape_html_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
|
488
|
+
when char <= 0x7FF do
|
489
|
+
escape_html_chunk(rest, acc, original, skip, len + 2)
|
490
|
+
end
|
491
|
+
Enum.map(surogate_escapes, fn {byte, escape} ->
|
492
|
+
defp escape_html_chunk(<<unquote(byte)::utf8, rest::bits>>, acc, original, skip, len) do
|
493
|
+
part = binary_part(original, skip, len)
|
494
|
+
acc = [acc, part | unquote(escape)]
|
495
|
+
escape_html(rest, acc, original, skip + len + 3)
|
496
|
+
end
|
497
|
+
end)
|
498
|
+
defp escape_html_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
|
499
|
+
when char <= 0xFFFF do
|
500
|
+
escape_html_chunk(rest, acc, original, skip, len + 3)
|
501
|
+
end
|
502
|
+
defp escape_html_chunk(<<_char::utf8, rest::bits>>, acc, original, skip, len) do
|
503
|
+
escape_html_chunk(rest, acc, original, skip, len + 4)
|
504
|
+
end
|
505
|
+
defp escape_html_chunk(<<>>, acc, original, skip, len) do
|
506
|
+
part = binary_part(original, skip, len)
|
507
|
+
[acc | part]
|
508
|
+
end
|
509
|
+
defp escape_html_chunk(<<byte, _rest::bits>>, _acc, original, _skip, _len) do
|
510
|
+
error({:invalid_byte, byte, original})
|
511
|
+
end
|
512
|
+
|
513
|
+
## unicode escape
|
514
|
+
|
515
|
+
defp escape_unicode(data, original, skip) do
|
516
|
+
escape_unicode(data, [], original, skip)
|
517
|
+
end
|
518
|
+
|
519
|
+
Enum.map(json_jt, fn
|
520
|
+
{byte, :chunk} ->
|
521
|
+
defp escape_unicode(<<byte, rest::bits>>, acc, original, skip)
|
522
|
+
when byte === unquote(byte) do
|
523
|
+
escape_unicode_chunk(rest, acc, original, skip, 1)
|
524
|
+
end
|
525
|
+
{byte, _escape} ->
|
526
|
+
defp escape_unicode(<<byte, rest::bits>>, acc, original, skip)
|
527
|
+
when byte === unquote(byte) do
|
528
|
+
acc = [acc | escape(byte)]
|
529
|
+
escape_unicode(rest, acc, original, skip + 1)
|
530
|
+
end
|
531
|
+
end)
|
532
|
+
defp escape_unicode(<<char::utf8, rest::bits>>, acc, original, skip)
|
533
|
+
when char <= 0xFF do
|
534
|
+
acc = [acc, "\\u00" | Integer.to_string(char, 16)]
|
535
|
+
escape_unicode(rest, acc, original, skip + 2)
|
536
|
+
end
|
537
|
+
defp escape_unicode(<<char::utf8, rest::bits>>, acc, original, skip)
|
538
|
+
when char <= 0x7FF do
|
539
|
+
acc = [acc, "\\u0" | Integer.to_string(char, 16)]
|
540
|
+
escape_unicode(rest, acc, original, skip + 2)
|
541
|
+
end
|
542
|
+
defp escape_unicode(<<char::utf8, rest::bits>>, acc, original, skip)
|
543
|
+
when char <= 0xFFF do
|
544
|
+
acc = [acc, "\\u0" | Integer.to_string(char, 16)]
|
545
|
+
escape_unicode(rest, acc, original, skip + 3)
|
546
|
+
end
|
547
|
+
defp escape_unicode(<<char::utf8, rest::bits>>, acc, original, skip)
|
548
|
+
when char <= 0xFFFF do
|
549
|
+
acc = [acc, "\\u" | Integer.to_string(char, 16)]
|
550
|
+
escape_unicode(rest, acc, original, skip + 3)
|
551
|
+
end
|
552
|
+
defp escape_unicode(<<char::utf8, rest::bits>>, acc, original, skip) do
|
553
|
+
char = char - 0x10000
|
554
|
+
acc =
|
555
|
+
[
|
556
|
+
acc,
|
557
|
+
"\\uD", Integer.to_string(0x800 ||| (char >>> 10), 16),
|
558
|
+
"\\uD" | Integer.to_string(0xC00 ||| (char &&& 0x3FF), 16)
|
559
|
+
]
|
560
|
+
escape_unicode(rest, acc, original, skip + 4)
|
561
|
+
end
|
562
|
+
defp escape_unicode(<<>>, acc, _original, _skip) do
|
563
|
+
acc
|
564
|
+
end
|
565
|
+
defp escape_unicode(<<byte, _rest::bits>>, _acc, original, _skip) do
|
566
|
+
error({:invalid_byte, byte, original})
|
567
|
+
end
|
568
|
+
|
569
|
+
Enum.map(json_jt, fn
|
570
|
+
{byte, :chunk} ->
|
571
|
+
defp escape_unicode_chunk(<<byte, rest::bits>>, acc, original, skip, len)
|
572
|
+
when byte === unquote(byte) do
|
573
|
+
escape_unicode_chunk(rest, acc, original, skip, len + 1)
|
574
|
+
end
|
575
|
+
{byte, _escape} ->
|
576
|
+
defp escape_unicode_chunk(<<byte, rest::bits>>, acc, original, skip, len)
|
577
|
+
when byte === unquote(byte) do
|
578
|
+
part = binary_part(original, skip, len)
|
579
|
+
acc = [acc, part | escape(byte)]
|
580
|
+
escape_unicode(rest, acc, original, skip + len + 1)
|
581
|
+
end
|
582
|
+
end)
|
583
|
+
defp escape_unicode_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
|
584
|
+
when char <= 0xFF do
|
585
|
+
part = binary_part(original, skip, len)
|
586
|
+
acc = [acc, part, "\\u00" | Integer.to_string(char, 16)]
|
587
|
+
escape_unicode(rest, acc, original, skip + len + 2)
|
588
|
+
end
|
589
|
+
defp escape_unicode_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
|
590
|
+
when char <= 0x7FF do
|
591
|
+
part = binary_part(original, skip, len)
|
592
|
+
acc = [acc, part, "\\u0" | Integer.to_string(char, 16)]
|
593
|
+
escape_unicode(rest, acc, original, skip + len + 2)
|
594
|
+
end
|
595
|
+
defp escape_unicode_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
|
596
|
+
when char <= 0xFFF do
|
597
|
+
part = binary_part(original, skip, len)
|
598
|
+
acc = [acc, part, "\\u0" | Integer.to_string(char, 16)]
|
599
|
+
escape_unicode(rest, acc, original, skip + len + 3)
|
600
|
+
end
|
601
|
+
defp escape_unicode_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
|
602
|
+
when char <= 0xFFFF do
|
603
|
+
part = binary_part(original, skip, len)
|
604
|
+
acc = [acc, part, "\\u" | Integer.to_string(char, 16)]
|
605
|
+
escape_unicode(rest, acc, original, skip + len + 3)
|
606
|
+
end
|
607
|
+
defp escape_unicode_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len) do
|
608
|
+
char = char - 0x10000
|
609
|
+
part = binary_part(original, skip, len)
|
610
|
+
acc =
|
611
|
+
[
|
612
|
+
acc, part,
|
613
|
+
"\\uD", Integer.to_string(0x800 ||| (char >>> 10), 16),
|
614
|
+
"\\uD" | Integer.to_string(0xC00 ||| (char &&& 0x3FF), 16)
|
615
|
+
]
|
616
|
+
escape_unicode(rest, acc, original, skip + len + 4)
|
617
|
+
end
|
618
|
+
defp escape_unicode_chunk(<<>>, acc, original, skip, len) do
|
619
|
+
part = binary_part(original, skip, len)
|
620
|
+
[acc | part]
|
621
|
+
end
|
622
|
+
defp escape_unicode_chunk(<<byte, _rest::bits>>, _acc, original, _skip, _len) do
|
623
|
+
error({:invalid_byte, byte, original})
|
624
|
+
end
|
625
|
+
|
626
|
+
@compile {:inline, error: 1}
|
627
|
+
defp error(error) do
|
628
|
+
throw EncodeError.new(error)
|
629
|
+
end
|
630
|
+
end
|