2
# Include OkJson as a replacement for the Yaml backend
5
# Copyright 2011, 2012 Keith Rarick
7
# Permission is hereby granted, free of charge, to any person obtaining a copy
8
# of this software and associated documentation files (the "Software"), to deal
9
# in the Software without restriction, including without limitation the rights
10
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
# copies of the Software, and to permit persons to whom the Software is
12
# furnished to do so, subject to the following conditions:
14
# The above copyright notice and this permission notice shall be included in
15
# all copies or substantial portions of the Software.
17
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
# See https://github.com/kr/okjson for updates.
29
# Some parts adapted from
30
# http://golang.org/src/pkg/json/decode.go and
31
# http://golang.org/src/pkg/utf8/utf8.go
33
Upstream = 'LTD7LBKLZWFF7OZK'
37
# Decodes a json document in string s and
38
# returns the corresponding ruby value.
39
# String s must be valid UTF-8. If you have
40
# a string in some other encoding, convert
43
# String values in the resulting structure
49
raise Error, 'trailing garbage'
55
# Parses a "json text" in the sense of RFC 4627.
56
# Returns the parsed value and any trailing tokens.
57
# Note: this is almost the same as valparse,
58
# except that it does not accept atomic values.
66
when '{' then objparse(ts)
67
when '[' then arrparse(ts)
69
raise Error, "unexpected #{val.inspect}"
74
# Parses a "value" in the sense of RFC 4627.
75
# Returns the parsed value and any trailing tokens.
83
when '{' then objparse(ts)
84
when '[' then arrparse(ts)
85
when :val,:str then [val, ts[1..-1]]
87
raise Error, "unexpected #{val.inspect}"
92
# Parses an "object" in the sense of RFC 4627.
93
# Returns the parsed value and any trailing tokens.
102
k, v, ts = pairparse(ts)
106
return obj, ts[1..-1]
112
k, v, ts = pairparse(ts)
116
return obj, ts[1..-1]
122
# Parses a "member" in the sense of RFC 4627.
123
# Returns the parsed values and any trailing tokens.
125
(typ, _, k), ts = ts[0], ts[1..-1]
127
raise Error, "unexpected #{k.inspect}"
135
# Parses an "array" in the sense of RFC 4627.
136
# Returns the parsed value and any trailing tokens.
142
return arr, ts[1..-1]
149
return arr, ts[1..-1]
159
return arr, ts[1..-1]
167
raise Error, "expected #{typ} (got #{ts[0].inspect})"
173
# Scans s and returns a list of json tokens,
174
# excluding white space (as defined in RFC 4627).
178
typ, lexeme, val = tok(s)
180
raise Error, "invalid character at #{s[0,10].inspect}"
183
ts << [typ, lexeme, val]
185
s = s[lexeme.length..-1]
191
# Scans the first token in s and
192
# returns a 3-element list, or nil
193
# if s does not begin with a valid token.
195
# The first list element is one of
196
# '{', '}', ':', ',', '[', ']',
197
# :val, :str, and :space.
199
# The second element is the lexeme.
201
# The third element is the value of the
202
# token for :val and :str, otherwise
206
when ?{ then ['{', s[0,1], s[0,1]]
207
when ?} then ['}', s[0,1], s[0,1]]
208
when ?: then [':', s[0,1], s[0,1]]
209
when ?, then [',', s[0,1], s[0,1]]
210
when ?[ then ['[', s[0,1], s[0,1]]
211
when ?] then [']', s[0,1], s[0,1]]
212
when ?n then nulltok(s)
213
when ?t then truetok(s)
214
when ?f then falsetok(s)
215
when ?" then strtok(s)
216
when Spc then [:space, s[0,1], s[0,1]]
217
when ?\t then [:space, s[0,1], s[0,1]]
218
when ?\n then [:space, s[0,1], s[0,1]]
219
when ?\r then [:space, s[0,1], s[0,1]]
225
def nulltok(s); s[0,4] == 'null' ? [:val, 'null', nil] : [] end
226
def truetok(s); s[0,4] == 'true' ? [:val, 'true', true] : [] end
227
def falsetok(s); s[0,5] == 'false' ? [:val, 'false', false] : [] end
231
m = /-?([1-9][0-9]+|[0-9])([.][0-9]+)?([eE][+-]?[0-9]+)?/.match(s)
232
if m && m.begin(0) == 0
234
[:val, m[0], Integer(m[1])*(10**Integer(m[3][1..-1]))]
236
[:val, m[0], Float(m[0])]
238
[:val, m[0], Integer(m[0])]
247
m = /"([^"\\]|\\["\/\\bfnrt]|\\u[0-9a-fA-F]{4})*"/.match(s)
249
raise Error, "invalid string literal at #{abbrev(s)}"
251
[:str, m[0], unquote(m[0])]
259
t = t + '...' if t.length < s.length
264
# Converts a quoted json string literal q into a UTF-8-encoded string.
265
# The rules are different than for Ruby, so we cannot use eval.
266
# Unquote will raise an error if q contains control characters.
269
a = q.dup # allocate a big enough string
271
# In ruby >= 1.9, a[w] is a codepoint, not a byte.
272
if a.class.method_defined?(:force_encoding)
273
a.force_encoding('UTF-8')
283
raise Error, "string literal ends with a \"\\\": \"#{q}\""
299
rescue RuntimeError => e
300
raise Error, "invalid escape sequence \\u#{q[r,4]}: #{e}"
305
uchar1 = hexdec4(q[r+2,4])
306
uchar = subst(uchar, uchar1)
308
# A valid pair; consume.
317
w += ucharenc(a, w, uchar)
320
raise Error, "invalid escape char #{q[r]} in \"#{q}\""
322
when c == ?", c < Spc
323
raise Error, "invalid character in string literal \"#{q}\""
325
# Copy anything else byte-for-byte.
326
# Valid UTF-8 will remain valid UTF-8.
327
# Invalid UTF-8 will remain invalid UTF-8.
328
# In ruby >= 1.9, c is a codepoint, not a byte,
329
# in which case this is still what we want.
339
# Encodes unicode character u as UTF-8
340
# bytes in string a at position i.
341
# Returns the number of bytes written.
342
def ucharenc(a, i, u)
345
a[i] = (u & 0xff).chr
348
a[i+0] = (Utag2 | ((u>>6)&0xff)).chr
349
a[i+1] = (Utagx | (u&Umaskx)).chr
352
a[i+0] = (Utag3 | ((u>>12)&0xff)).chr
353
a[i+1] = (Utagx | ((u>>6)&Umaskx)).chr
354
a[i+2] = (Utagx | (u&Umaskx)).chr
357
a[i+0] = (Utag4 | ((u>>18)&0xff)).chr
358
a[i+1] = (Utagx | ((u>>12)&Umaskx)).chr
359
a[i+2] = (Utagx | ((u>>6)&Umaskx)).chr
360
a[i+3] = (Utagx | (u&Umaskx)).chr
370
(nibble(s[0])<<12) | (nibble(s[1])<<8) | (nibble(s[2])<<4) | nibble(s[3])
375
if Usurr1 <= u1 && u1 < Usurr2 && Usurr2 <= u2 && u2 < Usurr3
376
return ((u1-Usurr1)<<10) | (u2-Usurr2) + Usurrself
383
Usurr1 <= u && u < Usurr3
389
when ?0 <= c && c <= ?9 then c.ord - ?0.ord
390
when ?a <= c && c <= ?z then c.ord - ?a.ord + 10
391
when ?A <= c && c <= ?Z then c.ord - ?A.ord + 10
393
raise Error, "invalid hex code #{c}"
398
# Encodes x into a json text. It may contain only
399
# Array, Hash, String, Numeric, true, false, nil.
400
# (Note, this list excludes Symbol.)
401
# X itself must be an Array or a Hash.
402
# No other value can be encoded, and an error will
403
# be raised if x contains any other value, such as
404
# Nan, Infinity, Symbol, and Proc, or if a Hash key
406
# Strings contained in x must be valid UTF-8.
409
when Hash then objenc(x)
410
when Array then arrenc(x)
412
raise Error, 'root value must be an Array or a Hash'
419
when Hash then objenc(x)
420
when Array then arrenc(x)
421
when String then strenc(x)
422
when Numeric then numenc(x)
423
when true then "true"
424
when false then "false"
427
raise Error, "cannot encode #{x.class}: #{x.inspect}"
433
'{' + x.map{|k,v| keyenc(k) + ':' + valenc(v)}.join(',') + '}'
438
'[' + a.map{|x| valenc(x)}.join(',') + ']'
444
when String then strenc(k)
446
raise Error, "Hash key is not a string: #{k.inspect}"
456
# In ruby >= 1.9, s[r] is a codepoint, not a byte.
457
rubydoesenc = s.class.method_defined?(:encoding)
461
when ?" then t.print('\\"')
462
when ?\\ then t.print('\\\\')
463
when ?\b then t.print('\\b')
464
when ?\f then t.print('\\f')
465
when ?\n then t.print('\\n')
466
when ?\r then t.print('\\r')
467
when ?\t then t.print('\\t')
473
c.ord # will raise an error if c is invalid UTF-8
478
when Spc <= c && c <= ?~
481
n = ucharcopy(t, s, r) # ensure valid UTF-8 output
482
r += n - 1 # r is incremented below
493
if ((x.nan? || x.infinite?) rescue false)
494
raise Error, "Numeric cannot be represented: #{x}"
500
# Copies the valid UTF-8 bytes of a single character
501
# from string s at position i to I/O object t, and
502
# returns the number of bytes copied.
503
# If no valid UTF-8 char exists at position i,
504
# ucharcopy writes Ustrerr and returns 1.
505
def ucharcopy(t, s, i)
507
raise Utf8Error if n < 1
511
# 1-byte, 7-bit sequence?
517
raise Utf8Error if c0 < Utag2 # unexpected continuation byte?
519
raise Utf8Error if n < 2 # need continuation byte
521
raise Utf8Error if c1 < Utagx || Utag2 <= c1
523
# 2-byte, 11-bit sequence?
525
raise Utf8Error if ((c0&Umask2)<<6 | (c1&Umaskx)) <= Uchar1max
531
# need second continuation byte
532
raise Utf8Error if n < 3
535
raise Utf8Error if c2 < Utagx || Utag2 <= c2
537
# 3-byte, 16-bit sequence?
539
u = (c0&Umask3)<<12 | (c1&Umaskx)<<6 | (c2&Umaskx)
540
raise Utf8Error if u <= Uchar2max
547
# need third continuation byte
548
raise Utf8Error if n < 4
550
raise Utf8Error if c3 < Utagx || Utag2 <= c3
552
# 4-byte, 21-bit sequence?
554
u = (c0&Umask4)<<18 | (c1&Umaskx)<<12 | (c2&Umaskx)<<6 | (c3&Umaskx)
555
raise Utf8Error if u <= Uchar3max
570
class Utf8Error < ::StandardError
574
class Error < ::StandardError
578
Utagx = 0x80 # 1000 0000
579
Utag2 = 0xc0 # 1100 0000
580
Utag3 = 0xe0 # 1110 0000
581
Utag4 = 0xf0 # 1111 0000
582
Utag5 = 0xF8 # 1111 1000
583
Umaskx = 0x3f # 0011 1111
584
Umask2 = 0x1f # 0001 1111
585
Umask3 = 0x0f # 0000 1111
586
Umask4 = 0x07 # 0000 0111
587
Uchar1max = (1<<7) - 1
588
Uchar2max = (1<<11) - 1
589
Uchar3max = (1<<16) - 1
590
Ucharerr = 0xFFFD # unicode "replacement char"
591
Ustrerr = "\xef\xbf\xbd" # unicode "replacement char"
598
Unesc = {?b=>?\b, ?f=>?\f, ?n=>?\n, ?r=>?\r, ?t=>?\t}
604
ParseError = ::ActiveSupport::OkJson::Error
607
# Parses a JSON string or IO and convert it into an object
609
if json.respond_to?(:read)
612
data = ActiveSupport::OkJson.decode(json)
613
if ActiveSupport.parse_json_times
614
convert_dates_from(data)
621
def convert_dates_from(data)
632
data.map! { |d| convert_dates_from(d) }
634
data.each do |key, value|
635
data[key] = convert_dates_from(value)