module MultiJson::OkJson

def abbrev(s)

def abbrev(s)
  t = s[0, 10]
  p = t["`"]
  t = t[0, p] if p
  t += "..." if t.length < s.length
  "`" + t + "`"
end

def arrenc(a)

def arrenc(a)
  "[" + a.map { |x| valenc(x) }.join(",") + "]"
end

def arrparse(ts)

Returns the parsed value and any trailing tokens.
Parses an "array" in the sense of RFC 4627.
def arrparse(ts)
  ts = eat("[", ts)
  arr = []
  return arr, ts[1..] if ts[0][0] == "]"
  v, ts = valparse(ts)
  arr << v
  return arr, ts[1..] if ts[0][0] == "]"
  loop do
    ts = eat(",", ts)
    v, ts = valparse(ts)
    arr << v
    return arr, ts[1..] if ts[0][0] == "]"
  end
end

def decode(s)

will be UTF-8.
String values in the resulting structure

it first.
a string in some other encoding, convert
String s must be valid UTF-8. If you have
returns the corresponding ruby value.
Decodes a json document in string s and
def decode(s)
  ts = lex(s)
  v, ts = textparse(ts)
  raise Error, "trailing garbage" unless ts.empty?
  v
end

def eat(typ, ts)

def eat(typ, ts)
  raise Error, "expected #{typ} (got #{ts[0].inspect})" if ts[0][0] != typ
  ts[1..]
end

def encode(x)

Strings contained in x must be valid UTF-8.
is not a String.
Nan, Infinity, Symbol, and Proc, or if a Hash key
be raised if x contains any other value, such as
No other value can be encoded, and an error will
X itself must be an Array or a Hash.
(Note, this list excludes Symbol.)
Array, Hash, String, Numeric, true, false, nil.
Encodes x into a json text. It may contain only
def encode(x)
  case x
  when Hash then objenc(x)
  when Array then arrenc(x)
  else
    raise Error, "root value must be an Array or a Hash"
  end
end

def falsetok(s) = (s[0, 5] == "false") ? [:val, "false", false] : []

def falsetok(s) = (s[0, 5] == "false") ? [:val, "false", false] : []

def hexdec4(s)

def hexdec4(s)
  raise Error, "short" if s.length != 4
  (nibble(s[0]) << 12) | (nibble(s[1]) << 8) | (nibble(s[2]) << 4) | nibble(s[3])
end

def keyenc(k)

def keyenc(k)
  case k
  when String then strenc(k)
  else
    raise Error, "Hash key is not a string: #{k.inspect}"
  end
end

def lex(s)

excluding white space (as defined in RFC 4627).
Scans s and returns a list of json tokens,
def lex(s)
  ts = []
  until s.empty?
    typ, lexeme, val = tok(s)
    raise Error, "invalid character at #{s[0, 10].inspect}" if typ.nil?
    ts << [typ, lexeme, val] if typ != :space
    s = s[lexeme.length..]
  end
  ts
end

def nibble(c)

def nibble(c)
  if c >= "0" && c <= "9" then c.ord - "0".ord
  elsif c >= "a" && c <= "z" then c.ord - "a".ord + 10
  elsif c >= "A" && c <= "Z" then c.ord - "A".ord + 10
  else
    raise Error, "invalid hex code #{c}"
  end
end

def nulltok(s) = (s[0, 4] == "null") ? [:val, "null", nil] : []

def nulltok(s) = (s[0, 4] == "null") ? [:val, "null", nil] : []

def numenc(x)

def numenc(x)
  raise Error, "Numeric cannot be represented: #{x}" if (x.nan? || x.infinite? rescue false)
  x.to_s
end

def numtok(s)

def numtok(s)
  m = /(-?(?:[1-9][0-9]+|[0-9]))([.][0-9]+)?([eE][+-]?[0-9]+)?/.match(s)
  if m&.begin(0)&.zero?
    if !m[2] && !m[3]
      [:val, m[0], Integer(m[0])]
    elsif m[2]
      [:val, m[0], Float(m[0])]
    else
      [:val, m[0], Integer(m[1]) * (10**m[3][1..].to_i(10))]
    end
  else
    []
  end
end

def objenc(x)

def objenc(x)
  "{" + x.map { |k, v| keyenc(k) + ":" + valenc(v) }.join(",") + "}"
end

def objparse(ts)

Returns the parsed value and any trailing tokens.
Parses an "object" in the sense of RFC 4627.
def objparse(ts)
  ts = eat("{", ts)
  obj = {}
  return obj, ts[1..] if ts[0][0] == "}"
  k, v, ts = pairparse(ts)
  obj[k] = v
  return obj, ts[1..] if ts[0][0] == "}"
  loop do
    ts = eat(",", ts)
    k, v, ts = pairparse(ts)
    obj[k] = v
    return obj, ts[1..] if ts[0][0] == "}"
  end
end

def pairparse(ts)

Returns the parsed values and any trailing tokens.
Parses a "member" in the sense of RFC 4627.
def pairparse(ts)
  (typ, _, k) = ts[0]
  ts = ts[1..]
  raise Error, "unexpected #{k.inspect}" if typ != :str
  ts = eat(":", ts)
  v, ts = valparse(ts)
  [k, v, ts]
end

def rubydoesenc?

def rubydoesenc?
  ::String.method_defined?(:force_encoding)
end

def strenc(s)

def strenc(s)
  t = StringIO.new(String.new(encoding: Encoding::UTF_8))
  t.putc('"')
  r = 0
  while r < s.length
    case s[r]
    when '"' then t.print('\\"')
    when "\\" then t.print("\\\\")
    when "\b" then t.print('\\b')
    when "\f" then t.print('\\f')
    when "\n" then t.print('\\n')
    when "\r" then t.print('\\r')
    when "\t" then t.print('\\t')
    else
      c = s[r]
      # In ruby >= 1.9, s[r] is a codepoint, not a byte.
      if rubydoesenc?
        begin
          # c.ord will raise an error if c is invalid UTF-8
          c = "\\u%04x" % [c.ord] if c.ord < Spc.ord
          t.write(c)
        rescue
          t.write(Ustrerr)
        end
      elsif c < Spc
        t.write("\\u%04x" % c)
      elsif c >= Spc && c <= "~"
        t.putc(c)
      else
        n = ucharcopy(t, s, r) # ensure valid UTF-8 output
        r += n - 1 # r is incremented below
      end
    end
    r += 1
  end
  t.putc('"')
  t.string
end

def strtok(s)

def strtok(s)
  m = %r{"([^"\\]|\\["/\\bfnrt]|\\u[0-9a-fA-F]{4})*"}.match(s)
  raise Error, "invalid string literal at #{abbrev(s)}" unless m
  [:str, m[0], unquote(m[0])]
end

def subst(u1, u2)

def subst(u1, u2)
  return ((u1 - Usurr1) << 10) | ((u2 - Usurr2) + Usurrself) if u1 >= Usurr1 && u1 < Usurr2 && u2 >= Usurr2 && u2 < Usurr3
  Ucharerr
end

def surrogate?(u)

def surrogate?(u)
  u >= Usurr1 && u < Usurr3
end

def textparse(ts)

except that it does not accept atomic values.
Note: this is almost the same as valparse,
Returns the parsed value and any trailing tokens.
Parses a "json text" in the sense of RFC 4627.
def textparse(ts)
  raise Error, "empty" if ts.length <= 0
  typ, _, val = ts[0]
  case typ
  when "{" then objparse(ts)
  when "[" then arrparse(ts)
  else
    raise Error, "unexpected #{val.inspect}"
  end
end

def tok(s)

it is the lexeme.
token for :val and :str, otherwise
The third element is the value of the

The second element is the lexeme.

:val, :str, and :space.
'{', '}', ':', ',', '[', ']',
The first list element is one of

if s does not begin with a valid token.
returns a 3-element list, or nil
Scans the first token in s and
def tok(s)
  case s[0]
  when "{" then ["{", s[0, 1], s[0, 1]]
  when "}" then ["}", s[0, 1], s[0, 1]]
  when ":" then [":", s[0, 1], s[0, 1]]
  when "," then [",", s[0, 1], s[0, 1]]
  when "[" then ["[", s[0, 1], s[0, 1]]
  when "]" then ["]", s[0, 1], s[0, 1]]
  when "n" then nulltok(s)
  when "t" then truetok(s)
  when "f" then falsetok(s)
  when '"' then strtok(s)
  when Spc, "\t", "\n", "\r" then [:space, s[0, 1], s[0, 1]]
  else
    numtok(s)
  end
end

def truetok(s) = (s[0, 4] == "true") ? [:val, "true", true] : []

def truetok(s) = (s[0, 4] == "true") ? [:val, "true", true] : []

def ucharcopy(t, s, i)

ucharcopy writes Ustrerr and returns 1.
If no valid UTF-8 char exists at position i,
returns the number of bytes copied.
from string s at position i to I/O object t, and
Copies the valid UTF-8 bytes of a single character
def ucharcopy(t, s, i)
  n = s.length - i
  raise Utf8Error if n < 1
  c0 = s[i].ord
  # 1-byte, 7-bit sequence?
  if c0 < Utagx
    t.putc(c0)
    return 1
  end
  raise Utf8Error if c0 < Utag2 # unexpected continuation byte?
  raise Utf8Error if n < 2 # need continuation byte
  c1 = s[i + 1].ord
  raise Utf8Error if c1 < Utagx || c1 >= Utag2
  # 2-byte, 11-bit sequence?
  if c0 < Utag3
    raise Utf8Error if (((c0 & Umask2) << 6) | (c1 & Umaskx)) <= Uchar1max
    t.putc(c0)
    t.putc(c1)
    return 2
  end
  # need second continuation byte
  raise Utf8Error if n < 3
  c2 = s[i + 2].ord
  raise Utf8Error if c2 < Utagx || c2 >= Utag2
  # 3-byte, 16-bit sequence?
  if c0 < Utag4
    u = ((c0 & Umask3) << 12) | ((c1 & Umaskx) << 6) | (c2 & Umaskx)
    raise Utf8Error if u <= Uchar2max
    t.putc(c0)
    t.putc(c1)
    t.putc(c2)
    return 3
  end
  # need third continuation byte
  raise Utf8Error if n < 4
  c3 = s[i + 3].ord
  raise Utf8Error if c3 < Utagx || c3 >= Utag2
  # 4-byte, 21-bit sequence?
  if c0 < Utag5
    u = ((c0 & Umask4) << 18) | ((c1 & Umaskx) << 12) | ((c2 & Umaskx) << 6) | (c3 & Umaskx)
    raise Utf8Error if u <= Uchar3max
    t.putc(c0)
    t.putc(c1)
    t.putc(c2)
    t.putc(c3)
    return 4
  end
  raise Utf8Error
rescue Utf8Error
  t.write(Ustrerr)
  1
end

def ucharenc(a, i, u)

Returns the number of bytes written.
bytes in string a at position i.
Encodes unicode character u as UTF-8
def ucharenc(a, i, u)
  if u <= Uchar1max
    a[i] = (u & 0xff).chr
    1
  elsif u <= Uchar2max
    a[i + 0] = (Utag2 | ((u >> 6) & 0xff)).chr
    a[i + 1] = (Utagx | (u & Umaskx)).chr
    2
  elsif u <= Uchar3max
    a[i + 0] = (Utag3 | ((u >> 12) & 0xff)).chr
    a[i + 1] = (Utagx | ((u >> 6) & Umaskx)).chr
    a[i + 2] = (Utagx | (u & Umaskx)).chr
    3
  else
    a[i + 0] = (Utag4 | ((u >> 18) & 0xff)).chr
    a[i + 1] = (Utagx | ((u >> 12) & Umaskx)).chr
    a[i + 2] = (Utagx | ((u >> 6) & Umaskx)).chr
    a[i + 3] = (Utagx | (u & Umaskx)).chr
    4
  end
end

def unquote(q)

Unquote will raise an error if q contains control characters.
The rules are different than for Ruby, so we cannot use eval.
Converts a quoted json string literal q into a UTF-8-encoded string.
def unquote(q)
  q = q[1...-1]
  a = q.dup # allocate a big enough string
  # In ruby >= 1.9, a[w] is a codepoint, not a byte.
  a.force_encoding("UTF-8") if rubydoesenc?
  r = 0
  w = 0
  while r < q.length
    c = q[r]
    if c == "\\"
      r += 1
      raise Error, "string literal ends with a \"\\\": \"#{q}\"" if r >= q.length
      case q[r]
      when '"', "\\", "/", "'"
        a[w] = q[r]
        r += 1
        w += 1
      when "b", "f", "n", "r", "t"
        a[w] = Unesc[q[r]]
        r += 1
        w += 1
      when "u"
        r += 1
        uchar = begin
          hexdec4(q[r, 4])
        rescue RuntimeError => e
          raise Error, "invalid escape sequence \\u#{q[r, 4]}: #{e}"
        end
        r += 4
        if surrogate?(uchar) && (q.length >= r + 6)
          uchar1 = hexdec4(q[r + 2, 4])
          uchar = subst(uchar, uchar1)
          if uchar != Ucharerr
            # A valid pair; consume.
            r += 6
          end
        end
        if rubydoesenc?
          a[w] = "" << uchar
          w += 1
        else
          w += ucharenc(a, w, uchar)
        end
      else
        raise Error, "invalid escape char #{q[r]} in \"#{q}\""
      end
    elsif c == '"' || c < Spc
      raise Error, "invalid character in string literal \"#{q}\""
    else
      # Copy anything else byte-for-byte.
      # Valid UTF-8 will remain valid UTF-8.
      # Invalid UTF-8 will remain invalid UTF-8.
      # In ruby >= 1.9, c is a codepoint, not a byte,
      # in which case this is still what we want.
      a[w] = c
      r += 1
      w += 1
    end
  end
  a[0, w]
end

def valenc(x)

def valenc(x)
  case x
  when Hash then objenc(x)
  when Array then arrenc(x)
  when String then strenc(x)
  when Numeric then numenc(x)
  when true then "true"
  when false then "false"
  when nil then "null"
  else
    raise Error, "cannot encode #{x.class}: #{x.inspect}" unless x.respond_to?(:to_json)
    x.to_json
  end
end

def valparse(ts)

Returns the parsed value and any trailing tokens.
Parses a "value" in the sense of RFC 4627.
def valparse(ts)
  raise Error, "empty" if ts.length <= 0
  typ, _, val = ts[0]
  case typ
  when "{" then objparse(ts)
  when "[" then arrparse(ts)
  when :val, :str then [val, ts[1..]]
  else
    raise Error, "unexpected #{val.inspect}"
  end
end