go-json/decode_context.go

217 lines
4.6 KiB
Go
Raw Normal View History

2020-04-23 19:39:20 +03:00
package json
2021-02-15 12:45:22 +03:00
import (
"unsafe"
)
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 {
return 0, 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 {
return 0, 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 {
return 0, 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:
return 0, errUnexpectedEndOfJSON("string of object", cursor)
}
}
case nul:
return 0, errUnexpectedEndOfJSON("object of object", cursor)
}
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 {
return 0, 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 {
return 0, 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 {
return 0, 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:
return 0, errUnexpectedEndOfJSON("string of object", cursor)
2020-05-08 14:22:57 +03:00
}
2021-02-15 12:45:22 +03:00
}
case nul:
return 0, errUnexpectedEndOfJSON("array of object", cursor)
}
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 {
return 0, 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:
return 0, 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-02-15 12:45:22 +03:00
buflen := int64(len(buf))
2020-07-31 14:24:39 +03:00
if cursor+3 >= buflen {
return 0, errUnexpectedEndOfJSON("bool of object", cursor)
}
if buf[cursor+1] != 'r' {
return 0, errUnexpectedEndOfJSON("bool of object", cursor)
}
if buf[cursor+2] != 'u' {
return 0, errUnexpectedEndOfJSON("bool of object", cursor)
}
if buf[cursor+3] != 'e' {
return 0, errUnexpectedEndOfJSON("bool of object", cursor)
}
cursor += 4
2021-02-15 12:45:22 +03:00
return cursor, nil
2020-07-31 14:24:39 +03:00
case 'f':
2021-02-15 12:45:22 +03:00
buflen := int64(len(buf))
2020-07-31 14:24:39 +03:00
if cursor+4 >= buflen {
return 0, errUnexpectedEndOfJSON("bool of object", cursor)
}
if buf[cursor+1] != 'a' {
return 0, errUnexpectedEndOfJSON("bool of object", cursor)
}
if buf[cursor+2] != 'l' {
return 0, errUnexpectedEndOfJSON("bool of object", cursor)
}
if buf[cursor+3] != 's' {
return 0, errUnexpectedEndOfJSON("bool of object", cursor)
}
if buf[cursor+4] != 'e' {
return 0, errUnexpectedEndOfJSON("bool of object", cursor)
}
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:
return cursor, errUnexpectedEndOfJSON("null", cursor)
2020-05-08 14:22:57 +03:00
}
}
}
func validateNull(buf []byte, cursor int64) error {
if cursor+3 >= int64(len(buf)) {
return errUnexpectedEndOfJSON("null", cursor)
}
if buf[cursor+1] != 'u' {
return errInvalidCharacter(buf[cursor+1], "null", cursor)
}
if buf[cursor+2] != 'l' {
return errInvalidCharacter(buf[cursor+2], "null", cursor)
}
if buf[cursor+3] != 'l' {
return errInvalidCharacter(buf[cursor+3], "null", cursor)
}
return nil
}