forked from mirrors/gotosocial
a156188b3e
* update dependencies, bump Go version to 1.19 * bump test image Go version * update golangci-lint * update gotosocial-drone-build * sign * linting, go fmt * update swagger docs * update swagger docs * whitespace * update contributing.md * fuckin whoopsie doopsie * linterino, linteroni * fix followrequest test not starting processor * fix other api/client tests not starting processor * fix remaining tests where processor not started * bump go-runners version * don't check last-webfingered-at, processor may have updated this * update swagger command * update bun to latest version * fix embed to work the same as before with new bun Signed-off-by: kim <grufwub@gmail.com> Co-authored-by: tsmethurst <tobi.smethurst@protonmail.com>
254 lines
5.3 KiB
Go
254 lines
5.3 KiB
Go
package decoder
|
|
|
|
import (
|
|
"sync"
|
|
"unsafe"
|
|
|
|
"github.com/goccy/go-json/internal/errors"
|
|
)
|
|
|
|
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)))
|
|
}
|
|
|
|
func skipWhiteSpace(buf []byte, cursor int64) int64 {
|
|
for isWhiteSpace[buf[cursor]] {
|
|
cursor++
|
|
}
|
|
return cursor
|
|
}
|
|
|
|
func skipObject(buf []byte, cursor, depth int64) (int64, error) {
|
|
braceCount := 1
|
|
for {
|
|
switch buf[cursor] {
|
|
case '{':
|
|
braceCount++
|
|
depth++
|
|
if depth > maxDecodeNestingDepth {
|
|
return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
|
|
}
|
|
case '}':
|
|
depth--
|
|
braceCount--
|
|
if braceCount == 0 {
|
|
return cursor + 1, nil
|
|
}
|
|
case '[':
|
|
depth++
|
|
if depth > maxDecodeNestingDepth {
|
|
return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
|
|
}
|
|
case ']':
|
|
depth--
|
|
case '"':
|
|
for {
|
|
cursor++
|
|
switch buf[cursor] {
|
|
case '\\':
|
|
cursor++
|
|
if buf[cursor] == nul {
|
|
return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
|
|
}
|
|
case '"':
|
|
goto SWITCH_OUT
|
|
case nul:
|
|
return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
|
|
}
|
|
}
|
|
case nul:
|
|
return 0, errors.ErrUnexpectedEndOfJSON("object of object", cursor)
|
|
}
|
|
SWITCH_OUT:
|
|
cursor++
|
|
}
|
|
}
|
|
|
|
func skipArray(buf []byte, cursor, depth int64) (int64, error) {
|
|
bracketCount := 1
|
|
for {
|
|
switch buf[cursor] {
|
|
case '[':
|
|
bracketCount++
|
|
depth++
|
|
if depth > maxDecodeNestingDepth {
|
|
return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
|
|
}
|
|
case ']':
|
|
bracketCount--
|
|
depth--
|
|
if bracketCount == 0 {
|
|
return cursor + 1, nil
|
|
}
|
|
case '{':
|
|
depth++
|
|
if depth > maxDecodeNestingDepth {
|
|
return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
|
|
}
|
|
case '}':
|
|
depth--
|
|
case '"':
|
|
for {
|
|
cursor++
|
|
switch buf[cursor] {
|
|
case '\\':
|
|
cursor++
|
|
if buf[cursor] == nul {
|
|
return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
|
|
}
|
|
case '"':
|
|
goto SWITCH_OUT
|
|
case nul:
|
|
return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
|
|
}
|
|
}
|
|
case nul:
|
|
return 0, errors.ErrUnexpectedEndOfJSON("array of object", cursor)
|
|
}
|
|
SWITCH_OUT:
|
|
cursor++
|
|
}
|
|
}
|
|
|
|
func skipValue(buf []byte, cursor, depth int64) (int64, error) {
|
|
for {
|
|
switch buf[cursor] {
|
|
case ' ', '\t', '\n', '\r':
|
|
cursor++
|
|
continue
|
|
case '{':
|
|
return skipObject(buf, cursor+1, depth+1)
|
|
case '[':
|
|
return skipArray(buf, cursor+1, depth+1)
|
|
case '"':
|
|
for {
|
|
cursor++
|
|
switch buf[cursor] {
|
|
case '\\':
|
|
cursor++
|
|
if buf[cursor] == nul {
|
|
return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
|
|
}
|
|
case '"':
|
|
return cursor + 1, nil
|
|
case nul:
|
|
return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
|
|
}
|
|
}
|
|
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
|
for {
|
|
cursor++
|
|
if floatTable[buf[cursor]] {
|
|
continue
|
|
}
|
|
break
|
|
}
|
|
return cursor, nil
|
|
case 't':
|
|
if err := validateTrue(buf, cursor); err != nil {
|
|
return 0, err
|
|
}
|
|
cursor += 4
|
|
return cursor, nil
|
|
case 'f':
|
|
if err := validateFalse(buf, cursor); err != nil {
|
|
return 0, err
|
|
}
|
|
cursor += 5
|
|
return cursor, nil
|
|
case 'n':
|
|
if err := validateNull(buf, cursor); err != nil {
|
|
return 0, err
|
|
}
|
|
cursor += 4
|
|
return cursor, nil
|
|
default:
|
|
return cursor, errors.ErrUnexpectedEndOfJSON("null", cursor)
|
|
}
|
|
}
|
|
}
|
|
|
|
func validateTrue(buf []byte, cursor int64) error {
|
|
if cursor+3 >= int64(len(buf)) {
|
|
return errors.ErrUnexpectedEndOfJSON("true", cursor)
|
|
}
|
|
if buf[cursor+1] != 'r' {
|
|
return errors.ErrInvalidCharacter(buf[cursor+1], "true", cursor)
|
|
}
|
|
if buf[cursor+2] != 'u' {
|
|
return errors.ErrInvalidCharacter(buf[cursor+2], "true", cursor)
|
|
}
|
|
if buf[cursor+3] != 'e' {
|
|
return errors.ErrInvalidCharacter(buf[cursor+3], "true", cursor)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateFalse(buf []byte, cursor int64) error {
|
|
if cursor+4 >= int64(len(buf)) {
|
|
return errors.ErrUnexpectedEndOfJSON("false", cursor)
|
|
}
|
|
if buf[cursor+1] != 'a' {
|
|
return errors.ErrInvalidCharacter(buf[cursor+1], "false", cursor)
|
|
}
|
|
if buf[cursor+2] != 'l' {
|
|
return errors.ErrInvalidCharacter(buf[cursor+2], "false", cursor)
|
|
}
|
|
if buf[cursor+3] != 's' {
|
|
return errors.ErrInvalidCharacter(buf[cursor+3], "false", cursor)
|
|
}
|
|
if buf[cursor+4] != 'e' {
|
|
return errors.ErrInvalidCharacter(buf[cursor+4], "false", cursor)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateNull(buf []byte, cursor int64) error {
|
|
if cursor+3 >= int64(len(buf)) {
|
|
return errors.ErrUnexpectedEndOfJSON("null", cursor)
|
|
}
|
|
if buf[cursor+1] != 'u' {
|
|
return errors.ErrInvalidCharacter(buf[cursor+1], "null", cursor)
|
|
}
|
|
if buf[cursor+2] != 'l' {
|
|
return errors.ErrInvalidCharacter(buf[cursor+2], "null", cursor)
|
|
}
|
|
if buf[cursor+3] != 'l' {
|
|
return errors.ErrInvalidCharacter(buf[cursor+3], "null", cursor)
|
|
}
|
|
return nil
|
|
}
|