home/vendor/github.com/valyala/fastjson/parser.go

977 lines
22 KiB
Go

package fastjson
import (
"fmt"
"github.com/valyala/fastjson/fastfloat"
"strconv"
"strings"
"unicode/utf16"
)
// Parser parses JSON.
//
// Parser may be re-used for subsequent parsing.
//
// Parser cannot be used from concurrent goroutines.
// Use per-goroutine parsers or ParserPool instead.
type Parser struct {
// b contains working copy of the string to be parsed.
b []byte
// c is a cache for json values.
c cache
}
// Parse parses s containing JSON.
//
// The returned value is valid until the next call to Parse*.
//
// Use Scanner if a stream of JSON values must be parsed.
func (p *Parser) Parse(s string) (*Value, error) {
s = skipWS(s)
p.b = append(p.b[:0], s...)
p.c.reset()
v, tail, err := parseValue(b2s(p.b), &p.c, 0)
if err != nil {
return nil, fmt.Errorf("cannot parse JSON: %s; unparsed tail: %q", err, startEndString(tail))
}
tail = skipWS(tail)
if len(tail) > 0 {
return nil, fmt.Errorf("unexpected tail: %q", startEndString(tail))
}
return v, nil
}
// ParseBytes parses b containing JSON.
//
// The returned Value is valid until the next call to Parse*.
//
// Use Scanner if a stream of JSON values must be parsed.
func (p *Parser) ParseBytes(b []byte) (*Value, error) {
return p.Parse(b2s(b))
}
type cache struct {
vs []Value
}
func (c *cache) reset() {
c.vs = c.vs[:0]
}
func (c *cache) getValue() *Value {
if cap(c.vs) > len(c.vs) {
c.vs = c.vs[:len(c.vs)+1]
} else {
c.vs = append(c.vs, Value{})
}
// Do not reset the value, since the caller must properly init it.
return &c.vs[len(c.vs)-1]
}
func skipWS(s string) string {
if len(s) == 0 || s[0] > 0x20 {
// Fast path.
return s
}
return skipWSSlow(s)
}
func skipWSSlow(s string) string {
if len(s) == 0 || s[0] != 0x20 && s[0] != 0x0A && s[0] != 0x09 && s[0] != 0x0D {
return s
}
for i := 1; i < len(s); i++ {
if s[i] != 0x20 && s[i] != 0x0A && s[i] != 0x09 && s[i] != 0x0D {
return s[i:]
}
}
return ""
}
type kv struct {
k string
v *Value
}
// MaxDepth is the maximum depth for nested JSON.
const MaxDepth = 300
func parseValue(s string, c *cache, depth int) (*Value, string, error) {
if len(s) == 0 {
return nil, s, fmt.Errorf("cannot parse empty string")
}
depth++
if depth > MaxDepth {
return nil, s, fmt.Errorf("too big depth for the nested JSON; it exceeds %d", MaxDepth)
}
if s[0] == '{' {
v, tail, err := parseObject(s[1:], c, depth)
if err != nil {
return nil, tail, fmt.Errorf("cannot parse object: %s", err)
}
return v, tail, nil
}
if s[0] == '[' {
v, tail, err := parseArray(s[1:], c, depth)
if err != nil {
return nil, tail, fmt.Errorf("cannot parse array: %s", err)
}
return v, tail, nil
}
if s[0] == '"' {
ss, tail, err := parseRawString(s[1:])
if err != nil {
return nil, tail, fmt.Errorf("cannot parse string: %s", err)
}
v := c.getValue()
v.t = typeRawString
v.s = ss
return v, tail, nil
}
if s[0] == 't' {
if len(s) < len("true") || s[:len("true")] != "true" {
return nil, s, fmt.Errorf("unexpected value found: %q", s)
}
return valueTrue, s[len("true"):], nil
}
if s[0] == 'f' {
if len(s) < len("false") || s[:len("false")] != "false" {
return nil, s, fmt.Errorf("unexpected value found: %q", s)
}
return valueFalse, s[len("false"):], nil
}
if s[0] == 'n' {
if len(s) < len("null") || s[:len("null")] != "null" {
// Try parsing NaN
if len(s) >= 3 && strings.EqualFold(s[:3], "nan") {
v := c.getValue()
v.t = TypeNumber
v.s = s[:3]
return v, s[3:], nil
}
return nil, s, fmt.Errorf("unexpected value found: %q", s)
}
return valueNull, s[len("null"):], nil
}
ns, tail, err := parseRawNumber(s)
if err != nil {
return nil, tail, fmt.Errorf("cannot parse number: %s", err)
}
v := c.getValue()
v.t = TypeNumber
v.s = ns
return v, tail, nil
}
func parseArray(s string, c *cache, depth int) (*Value, string, error) {
s = skipWS(s)
if len(s) == 0 {
return nil, s, fmt.Errorf("missing ']'")
}
if s[0] == ']' {
v := c.getValue()
v.t = TypeArray
v.a = v.a[:0]
return v, s[1:], nil
}
a := c.getValue()
a.t = TypeArray
a.a = a.a[:0]
for {
var v *Value
var err error
s = skipWS(s)
v, s, err = parseValue(s, c, depth)
if err != nil {
return nil, s, fmt.Errorf("cannot parse array value: %s", err)
}
a.a = append(a.a, v)
s = skipWS(s)
if len(s) == 0 {
return nil, s, fmt.Errorf("unexpected end of array")
}
if s[0] == ',' {
s = s[1:]
continue
}
if s[0] == ']' {
s = s[1:]
return a, s, nil
}
return nil, s, fmt.Errorf("missing ',' after array value")
}
}
func parseObject(s string, c *cache, depth int) (*Value, string, error) {
s = skipWS(s)
if len(s) == 0 {
return nil, s, fmt.Errorf("missing '}'")
}
if s[0] == '}' {
v := c.getValue()
v.t = TypeObject
v.o.reset()
return v, s[1:], nil
}
o := c.getValue()
o.t = TypeObject
o.o.reset()
for {
var err error
kv := o.o.getKV()
// Parse key.
s = skipWS(s)
if len(s) == 0 || s[0] != '"' {
return nil, s, fmt.Errorf(`cannot find opening '"" for object key`)
}
kv.k, s, err = parseRawKey(s[1:])
if err != nil {
return nil, s, fmt.Errorf("cannot parse object key: %s", err)
}
s = skipWS(s)
if len(s) == 0 || s[0] != ':' {
return nil, s, fmt.Errorf("missing ':' after object key")
}
s = s[1:]
// Parse value
s = skipWS(s)
kv.v, s, err = parseValue(s, c, depth)
if err != nil {
return nil, s, fmt.Errorf("cannot parse object value: %s", err)
}
s = skipWS(s)
if len(s) == 0 {
return nil, s, fmt.Errorf("unexpected end of object")
}
if s[0] == ',' {
s = s[1:]
continue
}
if s[0] == '}' {
return o, s[1:], nil
}
return nil, s, fmt.Errorf("missing ',' after object value")
}
}
func escapeString(dst []byte, s string) []byte {
if !hasSpecialChars(s) {
// Fast path - nothing to escape.
dst = append(dst, '"')
dst = append(dst, s...)
dst = append(dst, '"')
return dst
}
// Slow path.
return strconv.AppendQuote(dst, s)
}
func hasSpecialChars(s string) bool {
if strings.IndexByte(s, '"') >= 0 || strings.IndexByte(s, '\\') >= 0 {
return true
}
for i := 0; i < len(s); i++ {
if s[i] < 0x20 {
return true
}
}
return false
}
func unescapeStringBestEffort(s string) string {
n := strings.IndexByte(s, '\\')
if n < 0 {
// Fast path - nothing to unescape.
return s
}
// Slow path - unescape string.
b := s2b(s) // It is safe to do, since s points to a byte slice in Parser.b.
b = b[:n]
s = s[n+1:]
for len(s) > 0 {
ch := s[0]
s = s[1:]
switch ch {
case '"':
b = append(b, '"')
case '\\':
b = append(b, '\\')
case '/':
b = append(b, '/')
case 'b':
b = append(b, '\b')
case 'f':
b = append(b, '\f')
case 'n':
b = append(b, '\n')
case 'r':
b = append(b, '\r')
case 't':
b = append(b, '\t')
case 'u':
if len(s) < 4 {
// Too short escape sequence. Just store it unchanged.
b = append(b, "\\u"...)
break
}
xs := s[:4]
x, err := strconv.ParseUint(xs, 16, 16)
if err != nil {
// Invalid escape sequence. Just store it unchanged.
b = append(b, "\\u"...)
break
}
s = s[4:]
if !utf16.IsSurrogate(rune(x)) {
b = append(b, string(rune(x))...)
break
}
// Surrogate.
// See https://en.wikipedia.org/wiki/Universal_Character_Set_characters#Surrogates
if len(s) < 6 || s[0] != '\\' || s[1] != 'u' {
b = append(b, "\\u"...)
b = append(b, xs...)
break
}
x1, err := strconv.ParseUint(s[2:6], 16, 16)
if err != nil {
b = append(b, "\\u"...)
b = append(b, xs...)
break
}
r := utf16.DecodeRune(rune(x), rune(x1))
b = append(b, string(r)...)
s = s[6:]
default:
// Unknown escape sequence. Just store it unchanged.
b = append(b, '\\', ch)
}
n = strings.IndexByte(s, '\\')
if n < 0 {
b = append(b, s...)
break
}
b = append(b, s[:n]...)
s = s[n+1:]
}
return b2s(b)
}
// parseRawKey is similar to parseRawString, but is optimized
// for small-sized keys without escape sequences.
func parseRawKey(s string) (string, string, error) {
for i := 0; i < len(s); i++ {
if s[i] == '"' {
// Fast path.
return s[:i], s[i+1:], nil
}
if s[i] == '\\' {
// Slow path.
return parseRawString(s)
}
}
return s, "", fmt.Errorf(`missing closing '"'`)
}
func parseRawString(s string) (string, string, error) {
n := strings.IndexByte(s, '"')
if n < 0 {
return s, "", fmt.Errorf(`missing closing '"'`)
}
if n == 0 || s[n-1] != '\\' {
// Fast path. No escaped ".
return s[:n], s[n+1:], nil
}
// Slow path - possible escaped " found.
ss := s
for {
i := n - 1
for i > 0 && s[i-1] == '\\' {
i--
}
if uint(n-i)%2 == 0 {
return ss[:len(ss)-len(s)+n], s[n+1:], nil
}
s = s[n+1:]
n = strings.IndexByte(s, '"')
if n < 0 {
return ss, "", fmt.Errorf(`missing closing '"'`)
}
if n == 0 || s[n-1] != '\\' {
return ss[:len(ss)-len(s)+n], s[n+1:], nil
}
}
}
func parseRawNumber(s string) (string, string, error) {
// The caller must ensure len(s) > 0
// Find the end of the number.
for i := 0; i < len(s); i++ {
ch := s[i]
if (ch >= '0' && ch <= '9') || ch == '.' || ch == '-' || ch == 'e' || ch == 'E' || ch == '+' {
continue
}
if i == 0 || i == 1 && (s[0] == '-' || s[0] == '+') {
if len(s[i:]) >= 3 {
xs := s[i : i+3]
if strings.EqualFold(xs, "inf") || strings.EqualFold(xs, "nan") {
return s[:i+3], s[i+3:], nil
}
}
return "", s, fmt.Errorf("unexpected char: %q", s[:1])
}
ns := s[:i]
s = s[i:]
return ns, s, nil
}
return s, "", nil
}
// Object represents JSON object.
//
// Object cannot be used from concurrent goroutines.
// Use per-goroutine parsers or ParserPool instead.
type Object struct {
kvs []kv
keysUnescaped bool
}
func (o *Object) reset() {
o.kvs = o.kvs[:0]
o.keysUnescaped = false
}
// MarshalTo appends marshaled o to dst and returns the result.
func (o *Object) MarshalTo(dst []byte) []byte {
dst = append(dst, '{')
for i, kv := range o.kvs {
if o.keysUnescaped {
dst = escapeString(dst, kv.k)
} else {
dst = append(dst, '"')
dst = append(dst, kv.k...)
dst = append(dst, '"')
}
dst = append(dst, ':')
dst = kv.v.MarshalTo(dst)
if i != len(o.kvs)-1 {
dst = append(dst, ',')
}
}
dst = append(dst, '}')
return dst
}
// String returns string representation for the o.
//
// This function is for debugging purposes only. It isn't optimized for speed.
// See MarshalTo instead.
func (o *Object) String() string {
b := o.MarshalTo(nil)
// It is safe converting b to string without allocation, since b is no longer
// reachable after this line.
return b2s(b)
}
func (o *Object) getKV() *kv {
if cap(o.kvs) > len(o.kvs) {
o.kvs = o.kvs[:len(o.kvs)+1]
} else {
o.kvs = append(o.kvs, kv{})
}
return &o.kvs[len(o.kvs)-1]
}
func (o *Object) unescapeKeys() {
if o.keysUnescaped {
return
}
kvs := o.kvs
for i := range kvs {
kv := &kvs[i]
kv.k = unescapeStringBestEffort(kv.k)
}
o.keysUnescaped = true
}
// Len returns the number of items in the o.
func (o *Object) Len() int {
return len(o.kvs)
}
// Get returns the value for the given key in the o.
//
// Returns nil if the value for the given key isn't found.
//
// The returned value is valid until Parse is called on the Parser returned o.
func (o *Object) Get(key string) *Value {
if !o.keysUnescaped && strings.IndexByte(key, '\\') < 0 {
// Fast path - try searching for the key without object keys unescaping.
for _, kv := range o.kvs {
if kv.k == key {
return kv.v
}
}
}
// Slow path - unescape object keys.
o.unescapeKeys()
for _, kv := range o.kvs {
if kv.k == key {
return kv.v
}
}
return nil
}
// Visit calls f for each item in the o in the original order
// of the parsed JSON.
//
// f cannot hold key and/or v after returning.
func (o *Object) Visit(f func(key []byte, v *Value)) {
if o == nil {
return
}
o.unescapeKeys()
for _, kv := range o.kvs {
f(s2b(kv.k), kv.v)
}
}
// Value represents any JSON value.
//
// Call Type in order to determine the actual type of the JSON value.
//
// Value cannot be used from concurrent goroutines.
// Use per-goroutine parsers or ParserPool instead.
type Value struct {
o Object
a []*Value
s string
t Type
}
// MarshalTo appends marshaled v to dst and returns the result.
func (v *Value) MarshalTo(dst []byte) []byte {
switch v.t {
case typeRawString:
dst = append(dst, '"')
dst = append(dst, v.s...)
dst = append(dst, '"')
return dst
case TypeObject:
return v.o.MarshalTo(dst)
case TypeArray:
dst = append(dst, '[')
for i, vv := range v.a {
dst = vv.MarshalTo(dst)
if i != len(v.a)-1 {
dst = append(dst, ',')
}
}
dst = append(dst, ']')
return dst
case TypeString:
return escapeString(dst, v.s)
case TypeNumber:
return append(dst, v.s...)
case TypeTrue:
return append(dst, "true"...)
case TypeFalse:
return append(dst, "false"...)
case TypeNull:
return append(dst, "null"...)
default:
panic(fmt.Errorf("BUG: unexpected Value type: %d", v.t))
}
}
// String returns string representation of the v.
//
// The function is for debugging purposes only. It isn't optimized for speed.
// See MarshalTo instead.
//
// Don't confuse this function with StringBytes, which must be called
// for obtaining the underlying JSON string for the v.
func (v *Value) String() string {
b := v.MarshalTo(nil)
// It is safe converting b to string without allocation, since b is no longer
// reachable after this line.
return b2s(b)
}
// Type represents JSON type.
type Type int
const (
// TypeNull is JSON null.
TypeNull Type = 0
// TypeObject is JSON object type.
TypeObject Type = 1
// TypeArray is JSON array type.
TypeArray Type = 2
// TypeString is JSON string type.
TypeString Type = 3
// TypeNumber is JSON number type.
TypeNumber Type = 4
// TypeTrue is JSON true.
TypeTrue Type = 5
// TypeFalse is JSON false.
TypeFalse Type = 6
typeRawString Type = 7
)
// String returns string representation of t.
func (t Type) String() string {
switch t {
case TypeObject:
return "object"
case TypeArray:
return "array"
case TypeString:
return "string"
case TypeNumber:
return "number"
case TypeTrue:
return "true"
case TypeFalse:
return "false"
case TypeNull:
return "null"
// typeRawString is skipped intentionally,
// since it shouldn't be visible to user.
default:
panic(fmt.Errorf("BUG: unknown Value type: %d", t))
}
}
// Type returns the type of the v.
func (v *Value) Type() Type {
if v.t == typeRawString {
v.s = unescapeStringBestEffort(v.s)
v.t = TypeString
}
return v.t
}
// Exists returns true if the field exists for the given keys path.
//
// Array indexes may be represented as decimal numbers in keys.
func (v *Value) Exists(keys ...string) bool {
v = v.Get(keys...)
return v != nil
}
// Get returns value by the given keys path.
//
// Array indexes may be represented as decimal numbers in keys.
//
// nil is returned for non-existing keys path.
//
// The returned value is valid until Parse is called on the Parser returned v.
func (v *Value) Get(keys ...string) *Value {
if v == nil {
return nil
}
for _, key := range keys {
if v.t == TypeObject {
v = v.o.Get(key)
if v == nil {
return nil
}
} else if v.t == TypeArray {
n, err := strconv.Atoi(key)
if err != nil || n < 0 || n >= len(v.a) {
return nil
}
v = v.a[n]
} else {
return nil
}
}
return v
}
// GetObject returns object value by the given keys path.
//
// Array indexes may be represented as decimal numbers in keys.
//
// nil is returned for non-existing keys path or for invalid value type.
//
// The returned object is valid until Parse is called on the Parser returned v.
func (v *Value) GetObject(keys ...string) *Object {
v = v.Get(keys...)
if v == nil || v.t != TypeObject {
return nil
}
return &v.o
}
// GetArray returns array value by the given keys path.
//
// Array indexes may be represented as decimal numbers in keys.
//
// nil is returned for non-existing keys path or for invalid value type.
//
// The returned array is valid until Parse is called on the Parser returned v.
func (v *Value) GetArray(keys ...string) []*Value {
v = v.Get(keys...)
if v == nil || v.t != TypeArray {
return nil
}
return v.a
}
// GetFloat64 returns float64 value by the given keys path.
//
// Array indexes may be represented as decimal numbers in keys.
//
// 0 is returned for non-existing keys path or for invalid value type.
func (v *Value) GetFloat64(keys ...string) float64 {
v = v.Get(keys...)
if v == nil || v.Type() != TypeNumber {
return 0
}
return fastfloat.ParseBestEffort(v.s)
}
// GetInt returns int value by the given keys path.
//
// Array indexes may be represented as decimal numbers in keys.
//
// 0 is returned for non-existing keys path or for invalid value type.
func (v *Value) GetInt(keys ...string) int {
v = v.Get(keys...)
if v == nil || v.Type() != TypeNumber {
return 0
}
n := fastfloat.ParseInt64BestEffort(v.s)
nn := int(n)
if int64(nn) != n {
return 0
}
return nn
}
// GetUint returns uint value by the given keys path.
//
// Array indexes may be represented as decimal numbers in keys.
//
// 0 is returned for non-existing keys path or for invalid value type.
func (v *Value) GetUint(keys ...string) uint {
v = v.Get(keys...)
if v == nil || v.Type() != TypeNumber {
return 0
}
n := fastfloat.ParseUint64BestEffort(v.s)
nn := uint(n)
if uint64(nn) != n {
return 0
}
return nn
}
// GetInt64 returns int64 value by the given keys path.
//
// Array indexes may be represented as decimal numbers in keys.
//
// 0 is returned for non-existing keys path or for invalid value type.
func (v *Value) GetInt64(keys ...string) int64 {
v = v.Get(keys...)
if v == nil || v.Type() != TypeNumber {
return 0
}
return fastfloat.ParseInt64BestEffort(v.s)
}
// GetUint64 returns uint64 value by the given keys path.
//
// Array indexes may be represented as decimal numbers in keys.
//
// 0 is returned for non-existing keys path or for invalid value type.
func (v *Value) GetUint64(keys ...string) uint64 {
v = v.Get(keys...)
if v == nil || v.Type() != TypeNumber {
return 0
}
return fastfloat.ParseUint64BestEffort(v.s)
}
// GetStringBytes returns string value by the given keys path.
//
// Array indexes may be represented as decimal numbers in keys.
//
// nil is returned for non-existing keys path or for invalid value type.
//
// The returned string is valid until Parse is called on the Parser returned v.
func (v *Value) GetStringBytes(keys ...string) []byte {
v = v.Get(keys...)
if v == nil || v.Type() != TypeString {
return nil
}
return s2b(v.s)
}
// GetBool returns bool value by the given keys path.
//
// Array indexes may be represented as decimal numbers in keys.
//
// false is returned for non-existing keys path or for invalid value type.
func (v *Value) GetBool(keys ...string) bool {
v = v.Get(keys...)
if v != nil && v.t == TypeTrue {
return true
}
return false
}
// Object returns the underlying JSON object for the v.
//
// The returned object is valid until Parse is called on the Parser returned v.
//
// Use GetObject if you don't need error handling.
func (v *Value) Object() (*Object, error) {
if v.t != TypeObject {
return nil, fmt.Errorf("value doesn't contain object; it contains %s", v.Type())
}
return &v.o, nil
}
// Array returns the underlying JSON array for the v.
//
// The returned array is valid until Parse is called on the Parser returned v.
//
// Use GetArray if you don't need error handling.
func (v *Value) Array() ([]*Value, error) {
if v.t != TypeArray {
return nil, fmt.Errorf("value doesn't contain array; it contains %s", v.Type())
}
return v.a, nil
}
// StringBytes returns the underlying JSON string for the v.
//
// The returned string is valid until Parse is called on the Parser returned v.
//
// Use GetStringBytes if you don't need error handling.
func (v *Value) StringBytes() ([]byte, error) {
if v.Type() != TypeString {
return nil, fmt.Errorf("value doesn't contain string; it contains %s", v.Type())
}
return s2b(v.s), nil
}
// Float64 returns the underlying JSON number for the v.
//
// Use GetFloat64 if you don't need error handling.
func (v *Value) Float64() (float64, error) {
if v.Type() != TypeNumber {
return 0, fmt.Errorf("value doesn't contain number; it contains %s", v.Type())
}
return fastfloat.Parse(v.s)
}
// Int returns the underlying JSON int for the v.
//
// Use GetInt if you don't need error handling.
func (v *Value) Int() (int, error) {
if v.Type() != TypeNumber {
return 0, fmt.Errorf("value doesn't contain number; it contains %s", v.Type())
}
n, err := fastfloat.ParseInt64(v.s)
if err != nil {
return 0, err
}
nn := int(n)
if int64(nn) != n {
return 0, fmt.Errorf("number %q doesn't fit int", v.s)
}
return nn, nil
}
// Uint returns the underlying JSON uint for the v.
//
// Use GetInt if you don't need error handling.
func (v *Value) Uint() (uint, error) {
if v.Type() != TypeNumber {
return 0, fmt.Errorf("value doesn't contain number; it contains %s", v.Type())
}
n, err := fastfloat.ParseUint64(v.s)
if err != nil {
return 0, err
}
nn := uint(n)
if uint64(nn) != n {
return 0, fmt.Errorf("number %q doesn't fit uint", v.s)
}
return nn, nil
}
// Int64 returns the underlying JSON int64 for the v.
//
// Use GetInt64 if you don't need error handling.
func (v *Value) Int64() (int64, error) {
if v.Type() != TypeNumber {
return 0, fmt.Errorf("value doesn't contain number; it contains %s", v.Type())
}
return fastfloat.ParseInt64(v.s)
}
// Uint64 returns the underlying JSON uint64 for the v.
//
// Use GetInt64 if you don't need error handling.
func (v *Value) Uint64() (uint64, error) {
if v.Type() != TypeNumber {
return 0, fmt.Errorf("value doesn't contain number; it contains %s", v.Type())
}
return fastfloat.ParseUint64(v.s)
}
// Bool returns the underlying JSON bool for the v.
//
// Use GetBool if you don't need error handling.
func (v *Value) Bool() (bool, error) {
if v.t == TypeTrue {
return true, nil
}
if v.t == TypeFalse {
return false, nil
}
return false, fmt.Errorf("value doesn't contain bool; it contains %s", v.Type())
}
var (
valueTrue = &Value{t: TypeTrue}
valueFalse = &Value{t: TypeFalse}
valueNull = &Value{t: TypeNull}
)