go-json/internal/decoder/context.go

255 lines
5.3 KiB
Go
Raw Permalink Normal View History

2021-06-03 12:49:01 +03:00
package decoder
2020-04-23 19:39:20 +03:00
2021-02-15 12:45:22 +03:00
import (
2021-06-04 19:08:27 +03:00
"sync"
2021-02-15 12:45:22 +03:00
"unsafe"
2021-06-03 12:49:01 +03:00
"github.com/goccy/go-json/internal/errors"
2021-02-15 12:45:22 +03:00
)
2021-06-04 19:08:27 +03:00
type RuntimeContext struct {
Buf []byte
Option *Option
}
var (
runtimeContextPool = sync.Pool{
New: func() interface{} {
return &RuntimeContext{
Option: &Option{},
}
},
}
)
func TakeRuntimeContext() *RuntimeContext {
return runtimeContextPool.Get().(*RuntimeContext)
}
func ReleaseRuntimeContext(ctx *RuntimeContext) {
runtimeContextPool.Put(ctx)
}
var (
isWhiteSpace = [256]bool{}
)
func init() {
isWhiteSpace[' '] = true
isWhiteSpace['\n'] = true
isWhiteSpace['\t'] = true
isWhiteSpace['\r'] = true
}
func char(ptr unsafe.Pointer, offset int64) byte {
return *(*byte)(unsafe.Pointer(uintptr(ptr) + uintptr(offset)))
}
2020-05-23 06:51:09 +03:00
func skipWhiteSpace(buf []byte, cursor int64) int64 {
2021-05-03 13:44:44 +03:00
for isWhiteSpace[buf[cursor]] {
2020-05-07 07:44:41 +03:00
cursor++
2020-04-23 19:39:20 +03:00
}
2020-05-07 07:44:41 +03:00
return cursor
2020-04-23 19:39:20 +03:00
}
2020-05-08 14:22:57 +03:00
func skipObject(buf []byte, cursor, depth int64) (int64, error) {
2021-02-15 12:45:22 +03:00
braceCount := 1
2020-05-08 14:22:57 +03:00
for {
switch buf[cursor] {
case '{':
braceCount++
depth++
if depth > maxDecodeNestingDepth {
2021-06-03 12:49:01 +03:00
return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
}
2020-05-08 14:22:57 +03:00
case '}':
depth--
2020-05-08 14:22:57 +03:00
braceCount--
2021-02-15 12:45:22 +03:00
if braceCount == 0 {
return cursor + 1, nil
2020-05-08 14:22:57 +03:00
}
case '[':
depth++
if depth > maxDecodeNestingDepth {
2021-06-03 12:49:01 +03:00
return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
}
case ']':
depth--
2021-02-15 12:45:22 +03:00
case '"':
for {
cursor++
switch buf[cursor] {
case '\\':
cursor++
if buf[cursor] == nul {
2021-06-03 12:49:01 +03:00
return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
2021-02-15 12:45:22 +03:00
}
case '"':
2021-02-15 12:45:22 +03:00
goto SWITCH_OUT
case nul:
2021-06-03 12:49:01 +03:00
return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
2021-02-15 12:45:22 +03:00
}
}
case nul:
2021-06-03 12:49:01 +03:00
return 0, errors.ErrUnexpectedEndOfJSON("object of object", cursor)
2021-02-15 12:45:22 +03:00
}
SWITCH_OUT:
cursor++
}
}
func skipArray(buf []byte, cursor, depth int64) (int64, error) {
2021-02-15 12:45:22 +03:00
bracketCount := 1
for {
switch buf[cursor] {
case '[':
bracketCount++
depth++
if depth > maxDecodeNestingDepth {
2021-06-03 12:49:01 +03:00
return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
}
2020-05-08 14:22:57 +03:00
case ']':
bracketCount--
depth--
2021-02-15 12:45:22 +03:00
if bracketCount == 0 {
return cursor + 1, nil
2020-05-08 14:22:57 +03:00
}
case '{':
depth++
if depth > maxDecodeNestingDepth {
2021-06-03 12:49:01 +03:00
return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
}
case '}':
depth--
2020-05-08 14:22:57 +03:00
case '"':
2021-02-15 12:45:22 +03:00
for {
cursor++
switch buf[cursor] {
case '\\':
cursor++
if buf[cursor] == nul {
2021-06-03 12:49:01 +03:00
return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
2021-02-15 12:45:22 +03:00
}
case '"':
2021-02-15 12:45:22 +03:00
goto SWITCH_OUT
case nul:
2021-06-03 12:49:01 +03:00
return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
2020-05-08 14:22:57 +03:00
}
2021-02-15 12:45:22 +03:00
}
case nul:
2021-06-03 12:49:01 +03:00
return 0, errors.ErrUnexpectedEndOfJSON("array of object", cursor)
2021-02-15 12:45:22 +03:00
}
SWITCH_OUT:
cursor++
}
}
func skipValue(buf []byte, cursor, depth int64) (int64, error) {
2021-02-15 12:45:22 +03:00
for {
switch buf[cursor] {
case ' ', '\t', '\n', '\r':
cursor++
continue
case '{':
return skipObject(buf, cursor+1, depth+1)
2021-02-15 12:45:22 +03:00
case '[':
return skipArray(buf, cursor+1, depth+1)
2021-02-15 12:45:22 +03:00
case '"':
for {
cursor++
switch buf[cursor] {
case '\\':
cursor++
if buf[cursor] == nul {
2021-06-03 12:49:01 +03:00
return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
2021-02-15 12:45:22 +03:00
}
case '"':
2020-05-08 14:22:57 +03:00
return cursor + 1, nil
2021-02-15 12:45:22 +03:00
case nul:
2021-06-03 12:49:01 +03:00
return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
2020-05-08 14:22:57 +03:00
}
}
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
2021-02-15 12:45:22 +03:00
for {
cursor++
if floatTable[buf[cursor]] {
2020-05-08 14:22:57 +03:00
continue
}
break
}
2021-02-15 12:45:22 +03:00
return cursor, nil
2020-07-31 14:24:39 +03:00
case 't':
2021-05-08 21:05:36 +03:00
if err := validateTrue(buf, cursor); err != nil {
return 0, err
2020-07-31 14:24:39 +03:00
}
cursor += 4
2021-02-15 12:45:22 +03:00
return cursor, nil
2020-07-31 14:24:39 +03:00
case 'f':
2021-05-08 21:05:36 +03:00
if err := validateFalse(buf, cursor); err != nil {
return 0, err
2020-07-31 14:24:39 +03:00
}
cursor += 5
2021-02-15 12:45:22 +03:00
return cursor, nil
2020-07-31 14:24:39 +03:00
case 'n':
if err := validateNull(buf, cursor); err != nil {
return 0, err
2020-07-31 14:24:39 +03:00
}
cursor += 4
2021-02-15 12:45:22 +03:00
return cursor, nil
default:
2021-06-03 12:49:01 +03:00
return cursor, errors.ErrUnexpectedEndOfJSON("null", cursor)
2020-05-08 14:22:57 +03:00
}
}
}
2021-05-08 21:05:36 +03:00
func validateTrue(buf []byte, cursor int64) error {
if cursor+3 >= int64(len(buf)) {
2021-06-03 12:49:01 +03:00
return errors.ErrUnexpectedEndOfJSON("true", cursor)
2021-05-08 21:05:36 +03:00
}
if buf[cursor+1] != 'r' {
2021-06-03 12:49:01 +03:00
return errors.ErrInvalidCharacter(buf[cursor+1], "true", cursor)
2021-05-08 21:05:36 +03:00
}
if buf[cursor+2] != 'u' {
2021-06-03 12:49:01 +03:00
return errors.ErrInvalidCharacter(buf[cursor+2], "true", cursor)
2021-05-08 21:05:36 +03:00
}
if buf[cursor+3] != 'e' {
2021-06-03 12:49:01 +03:00
return errors.ErrInvalidCharacter(buf[cursor+3], "true", cursor)
2021-05-08 21:05:36 +03:00
}
return nil
}
func validateFalse(buf []byte, cursor int64) error {
if cursor+4 >= int64(len(buf)) {
2021-06-03 12:49:01 +03:00
return errors.ErrUnexpectedEndOfJSON("false", cursor)
2021-05-08 21:05:36 +03:00
}
if buf[cursor+1] != 'a' {
2021-06-03 12:49:01 +03:00
return errors.ErrInvalidCharacter(buf[cursor+1], "false", cursor)
2021-05-08 21:05:36 +03:00
}
if buf[cursor+2] != 'l' {
2021-06-03 12:49:01 +03:00
return errors.ErrInvalidCharacter(buf[cursor+2], "false", cursor)
2021-05-08 21:05:36 +03:00
}
if buf[cursor+3] != 's' {
2021-06-03 12:49:01 +03:00
return errors.ErrInvalidCharacter(buf[cursor+3], "false", cursor)
2021-05-08 21:05:36 +03:00
}
if buf[cursor+4] != 'e' {
2021-06-03 12:49:01 +03:00
return errors.ErrInvalidCharacter(buf[cursor+4], "false", cursor)
2021-05-08 21:05:36 +03:00
}
return nil
}
func validateNull(buf []byte, cursor int64) error {
if cursor+3 >= int64(len(buf)) {
2021-06-03 12:49:01 +03:00
return errors.ErrUnexpectedEndOfJSON("null", cursor)
}
if buf[cursor+1] != 'u' {
2021-06-03 12:49:01 +03:00
return errors.ErrInvalidCharacter(buf[cursor+1], "null", cursor)
}
if buf[cursor+2] != 'l' {
2021-06-03 12:49:01 +03:00
return errors.ErrInvalidCharacter(buf[cursor+2], "null", cursor)
}
if buf[cursor+3] != 'l' {
2021-06-03 12:49:01 +03:00
return errors.ErrInvalidCharacter(buf[cursor+3], "null", cursor)
}
return nil
}