You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

472 lines
7.4 KiB

package jx
import (
"io"
"github.com/go-faster/errors"
)
// Skip skips a json object and positions to relatively the next json object.
func (d *Decoder) Skip() error {
c, err := d.next()
if err != nil {
return err
}
switch c {
case '"':
if err := d.skipStr(); err != nil {
return errors.Wrap(err, "str")
}
return nil
case 'n':
d.unread()
return d.Null()
case 't', 'f':
d.unread()
_, err := d.Bool()
return err
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
d.unread()
return d.skipNumber()
case '[':
if err := d.skipArr(); err != nil {
return errors.Wrap(err, "array")
}
return nil
case '{':
if err := d.skipObj(); err != nil {
return errors.Wrap(err, "object")
}
return nil
default:
return badToken(c)
}
}
var (
skipNumberSet = [256]byte{
'0': 1,
'1': 1,
'2': 1,
'3': 1,
'4': 1,
'5': 1,
'6': 1,
'7': 1,
'8': 1,
'9': 1,
',': 2,
']': 2,
'}': 2,
' ': 2,
'\t': 2,
'\n': 2,
'\r': 2,
}
)
// skipNumber reads one JSON number.
//
// Assumes d.buf is not empty.
func (d *Decoder) skipNumber() error {
const (
digitTag byte = 1
closerTag byte = 2
)
c := d.buf[d.head]
d.head++
switch c {
case '-':
c, err := d.byte()
if err != nil {
return err
}
// Character after '-' must be a digit.
if skipNumberSet[c] != digitTag {
return badToken(c)
}
if c != '0' {
break
}
fallthrough
case '0':
// If buffer is empty, try to read more.
if d.head == d.tail {
err := d.read()
if err != nil {
// There is no data anymore.
if err == io.EOF {
return nil
}
return err
}
}
c = d.buf[d.head]
if skipNumberSet[c] == closerTag {
return nil
}
switch c {
case '.':
goto stateDot
case 'e', 'E':
goto stateExp
default:
return badToken(c)
}
}
for {
for i, c := range d.buf[d.head:d.tail] {
switch skipNumberSet[c] {
case closerTag:
d.head += i
return nil
case digitTag:
continue
}
switch c {
case '.':
d.head += i
goto stateDot
case 'e', 'E':
d.head += i
goto stateExp
default:
return badToken(c)
}
}
if err := d.read(); err != nil {
// There is no data anymore.
if err == io.EOF {
d.head = d.tail
return nil
}
return err
}
}
stateDot:
d.head++
{
var last byte = '.'
for {
for i, c := range d.buf[d.head:d.tail] {
switch skipNumberSet[c] {
case closerTag:
d.head += i
// Check that dot is not last character.
if last == '.' {
return io.ErrUnexpectedEOF
}
return nil
case digitTag:
last = c
continue
}
switch c {
case 'e', 'E':
if last == '.' {
return badToken(c)
}
d.head += i
goto stateExp
default:
return badToken(c)
}
}
if err := d.read(); err != nil {
// There is no data anymore.
if err == io.EOF {
d.head = d.tail
// Check that dot is not last character.
if last == '.' {
return io.ErrUnexpectedEOF
}
return nil
}
return err
}
}
}
stateExp:
d.head++
// There must be a number or sign after e.
{
numOrSign, err := d.byte()
if err != nil {
return err
}
if skipNumberSet[numOrSign] != digitTag { // If next character is not a digit, check for sign.
if numOrSign == '-' || numOrSign == '+' {
num, err := d.byte()
if err != nil {
return err
}
// There must be a number after sign.
if skipNumberSet[num] != digitTag {
return badToken(num)
}
} else {
return badToken(numOrSign)
}
}
}
for {
for i, c := range d.buf[d.head:d.tail] {
if skipNumberSet[c] == closerTag {
d.head += i
return nil
}
if skipNumberSet[c] == 0 {
return badToken(c)
}
}
if err := d.read(); err != nil {
// There is no data anymore.
if err == io.EOF {
d.head = d.tail
return nil
}
return err
}
}
}
var (
escapedStrSet = [256]byte{
'"': '"',
'\\': '\\',
'/': '/',
'b': '\b',
'f': '\f',
'n': '\n',
'r': '\r',
't': '\t',
'u': 'u',
}
hexSet = [256]byte{
'0': 0x0 + 1, '1': 0x1 + 1, '2': 0x2 + 1, '3': 0x3 + 1,
'4': 0x4 + 1, '5': 0x5 + 1, '6': 0x6 + 1, '7': 0x7 + 1,
'8': 0x8 + 1, '9': 0x9 + 1,
'A': 0xA + 1, 'B': 0xB + 1, 'C': 0xC + 1, 'D': 0xD + 1,
'E': 0xE + 1, 'F': 0xF + 1,
'a': 0xa + 1, 'b': 0xb + 1, 'c': 0xc + 1, 'd': 0xd + 1,
'e': 0xe + 1, 'f': 0xf + 1,
}
)
// skipStr reads one JSON string.
//
// Assumes first quote was consumed.
func (d *Decoder) skipStr() error {
var (
c byte
i int
)
readStr:
for {
i = 0
buf := d.buf[d.head:d.tail]
for len(buf) >= 8 {
c = buf[0]
if safeSet[c] != 0 {
goto readTok
}
i++
c = buf[1]
if safeSet[c] != 0 {
goto readTok
}
i++
c = buf[2]
if safeSet[c] != 0 {
goto readTok
}
i++
c = buf[3]
if safeSet[c] != 0 {
goto readTok
}
i++
c = buf[4]
if safeSet[c] != 0 {
goto readTok
}
i++
c = buf[5]
if safeSet[c] != 0 {
goto readTok
}
i++
c = buf[6]
if safeSet[c] != 0 {
goto readTok
}
i++
c = buf[7]
if safeSet[c] != 0 {
goto readTok
}
i++
buf = buf[8:]
}
var n int
for n, c = range buf {
if safeSet[c] != 0 {
i += n
goto readTok
}
}
if err := d.read(); err != nil {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return err
}
}
readTok:
; // Bug in cover tool, see https://github.com/golang/go/issues/28319.
switch {
case c == '"':
d.head += i + 1
return nil
case c == '\\':
d.head += i + 1
v, err := d.byte()
if err != nil {
return err
}
switch escapedStrSet[v] {
case 'u':
for i := 0; i < 4; i++ {
h, err := d.byte()
if err != nil {
return err
}
if hexSet[h] == 0 {
return badToken(h)
}
}
case 0:
return badToken(v)
}
case c < ' ':
return badToken(c)
}
goto readStr
}
// skipObj reads JSON object.
//
// Assumes first bracket was consumed.
func (d *Decoder) skipObj() error {
if err := d.incDepth(); err != nil {
return errors.Wrap(err, "inc")
}
c, err := d.more()
if err != nil {
return errors.Wrap(err, "next")
}
switch c {
case '}':
return d.decDepth()
case '"':
d.unread()
default:
return badToken(c)
}
for {
if err := d.consume('"'); err != nil {
return err
}
if err := d.skipStr(); err != nil {
return errors.Wrap(err, "read field name")
}
if err := d.consume(':'); err != nil {
return errors.Wrap(err, "field")
}
if err := d.Skip(); err != nil {
return err
}
c, err := d.more()
if err != nil {
return errors.Wrap(err, "read comma")
}
switch c {
case ',':
continue
case '}':
return d.decDepth()
default:
return badToken(c)
}
}
}
// skipArr reads JSON array.
//
// Assumes first bracket was consumed.
func (d *Decoder) skipArr() error {
if err := d.incDepth(); err != nil {
return errors.Wrap(err, "inc")
}
c, err := d.more()
if err != nil {
return errors.Wrap(err, "next")
}
if c == ']' {
return d.decDepth()
}
d.unread()
for {
if err := d.Skip(); err != nil {
return err
}
c, err := d.more()
if err != nil {
return errors.Wrap(err, "read comma")
}
switch c {
case ',':
continue
case ']':
return d.decDepth()
default:
return badToken(c)
}
}
}
// skipSpace skips space characters.
//
// Returns io.ErrUnexpectedEOF if got io.EOF.
func (d *Decoder) skipSpace() error {
// Skip space.
if _, err := d.more(); err != nil {
return err
}
d.unread()
return nil
}