go_dreamfactory/lego/utils/codec/json/reader.go

827 lines
18 KiB
Go

package json
import (
"fmt"
"io"
"math/big"
"reflect"
"unicode/utf16"
"go_dreamfactory/lego/utils/codec"
"go_dreamfactory/lego/utils/codec/codecore"
"go_dreamfactory/lego/utils/codec/utils"
"github.com/modern-go/reflect2"
)
type JsonReader struct {
buf []byte
head int
tail int
depth int
err error
}
func (this *JsonReader) GetReader(buf []byte) codecore.IReader {
return GetReader(buf)
}
func (this *JsonReader) PutReader(r codecore.IReader) {
PutReader(r)
}
func (this *JsonReader) GetWriter() codecore.IWriter {
return GetWriter()
}
func (this *JsonReader) PutWriter(w codecore.IWriter) {
PutWriter(w)
}
func (this *JsonReader) ReadVal(obj interface{}) {
depth := this.depth
cacheKey := reflect2.RTypeOf(obj)
decoder := codec.GetDecoder(cacheKey)
if decoder == nil {
typ := reflect2.TypeOf(obj)
if typ == nil || typ.Kind() != reflect.Ptr {
this.reportError("ReadVal", "can only unmarshal into pointer")
return
}
decoder = codec.DecoderOf(typ, defconf)
}
ptr := reflect2.PtrOf(obj)
if ptr == nil {
this.reportError("ReadVal", "can not read into nil pointer")
return
}
decoder.Decode(ptr, this)
if this.depth != depth {
this.reportError("ReadVal", "unexpected mismatched nesting")
return
}
}
func (this *JsonReader) WhatIsNext() codecore.ValueType {
valueType := valueTypes[this.nextToken()]
this.unreadByte()
return valueType
}
func (this *JsonReader) Read() interface{} {
valueType := this.WhatIsNext()
switch valueType {
case codecore.StringValue:
return this.ReadString()
case codecore.NumberValue:
return this.ReadFloat64()
case codecore.NilValue:
this.skipFourBytes('n', 'u', 'l', 'l')
return nil
case codecore.BoolValue:
return this.ReadBool()
case codecore.ArrayValue:
arr := []interface{}{}
this.ReadArrayCB(func(extra codecore.IReader) bool {
var elem interface{}
extra.ReadVal(&elem)
arr = append(arr, elem)
return true
})
return arr
case codecore.ObjectValue:
obj := map[string]interface{}{}
this.ReadMapCB(func(extra codecore.IReader, field string) bool {
var elem interface{}
this.ReadVal(&elem)
obj[field] = elem
return true
})
return obj
default:
this.reportError("Read", fmt.Sprintf("unexpected value type: %v", valueType))
return nil
}
}
func (this *JsonReader) ReadNil() (ret bool) {
c := this.nextToken()
if c == 'n' {
this.skipThreeBytes('u', 'l', 'l') // null
return true
}
this.unreadByte()
return false
}
func (this *JsonReader) ReadArrayStart() (ret bool) {
c := this.nextToken()
if c == '[' {
return true
}
this.reportError("ReadArrayStart", `expect [ but found `+string([]byte{c}))
return
}
func (this *JsonReader) CheckNextIsArrayEnd() (ret bool) {
c := this.nextToken()
this.unreadByte()
if c == ']' {
return true
}
return
}
func (this *JsonReader) ReadArrayEnd() (ret bool) {
c := this.nextToken()
if c == ']' {
return true
}
this.reportError("ReadArrayEnd", `expect ] but found `+string([]byte{c}))
return
}
func (this *JsonReader) ReadObjectStart() (ret bool) {
c := this.nextToken()
if c == '{' {
return this.incrementDepth()
}
this.reportError("ReadObjectStart", `expect { but found `+string([]byte{c}))
return
}
func (this *JsonReader) CheckNextIsObjectEnd() (ret bool) {
c := this.nextToken()
this.unreadByte()
if c == '}' {
return true
}
return
}
func (this *JsonReader) ReadObjectEnd() (ret bool) {
c := this.nextToken()
if c == '}' {
return this.decrementDepth()
}
this.reportError("ReadObjectEnd", `expect } but found `+string([]byte{c}))
return
}
func (this *JsonReader) ReadMemberSplit() (ret bool) {
c := this.nextToken()
if c == ',' {
return true
}
this.unreadByte()
return
}
func (this *JsonReader) ReadKVSplit() (ret bool) {
c := this.nextToken()
if c == ':' {
return true
}
this.reportError("ReadKVSplit", `expect : but found `+string([]byte{c}))
return
}
func (this *JsonReader) ReadKeyStart() (ret bool) {
c := this.nextToken()
if c == '"' {
return true
}
this.reportError("ReadKeyStart", `expect " but found `+string([]byte{c}))
return
}
func (this *JsonReader) ReadKeyEnd() (ret bool) {
c := this.nextToken()
if c == '"' {
return true
}
this.reportError("ReadKeyEnd", `expect " but found `+string([]byte{c}))
return
}
func (this *JsonReader) Skip() {
c := this.nextToken()
switch c {
case '"':
this.skipString()
case 'n':
this.skipThreeBytes('u', 'l', 'l') // null
case 't':
this.skipThreeBytes('r', 'u', 'e') // true
case 'f':
this.skipFourBytes('a', 'l', 's', 'e') // false
case '0':
this.unreadByte()
this.ReadFloat32()
case '-', '1', '2', '3', '4', '5', '6', '7', '8', '9':
this.skipNumber()
case '[':
this.skipArray()
case '{':
this.skipObject()
default:
this.reportError("Skip", fmt.Sprintf("do not know how to skip: %v", c))
return
}
}
func (this *JsonReader) ReadBool() (ret bool) {
c := this.nextToken()
if c == 't' {
this.skipThreeBytes('r', 'u', 'e')
return true
}
if c == 'f' {
this.skipFourBytes('a', 'l', 's', 'e')
return false
}
this.reportError("ReadBool", "expect t or f, but found "+string([]byte{c}))
return
}
func (this *JsonReader) ReadInt8() (ret int8) {
var (
n int
err error
)
if ret, n, err = utils.ReadInt8ForString(this.buf[this.head:]); err != nil {
this.reportError("ReadInt8", err.Error())
return
}
this.head += n
return
}
func (this *JsonReader) ReadInt16() (ret int16) {
var (
n int
err error
)
if ret, n, err = utils.ReadInt16ForString(this.buf[this.head:]); err != nil {
this.reportError("ReadInt32", err.Error())
return
}
this.head += n
return
}
func (this *JsonReader) ReadInt32() (ret int32) {
var (
n int
err error
)
if ret, n, err = utils.ReadInt32ForString(this.buf[this.head:]); err != nil {
this.reportError("ReadInt32", err.Error())
return
}
this.head += n
return
}
func (this *JsonReader) ReadInt64() (ret int64) {
var (
n int
err error
)
if ret, n, err = utils.ReadInt64ForString(this.buf[this.head:]); err != nil {
this.reportError("ReadInt64", err.Error())
return
}
this.head += n
return
}
func (this *JsonReader) ReadUint8() (ret uint8) {
var (
n int
err error
)
if ret, n, err = utils.ReadUint8ForString(this.buf[this.head:]); err != nil {
this.reportError("ReadUint8", err.Error())
return
}
this.head += n
return
}
func (this *JsonReader) ReadUint16() (ret uint16) {
var (
n int
err error
)
if ret, n, err = utils.ReadUint16ForString(this.buf[this.head:]); err != nil {
this.reportError("ReadUint16", err.Error())
return
}
this.head += n
return
}
func (this *JsonReader) ReadUint32() (ret uint32) {
var (
n int
err error
)
if ret, n, err = utils.ReadUint32ForString(this.buf[this.head:]); err != nil {
this.reportError("ReadUint32", err.Error())
return
}
this.head += n
return
}
func (this *JsonReader) ReadUint64() (ret uint64) {
var (
n int
err error
)
if ret, n, err = utils.ReadUint64ForString(this.buf[this.head:]); err != nil {
this.reportError("ReadUint64", err.Error())
return
}
this.head += n
return
}
func (this *JsonReader) ReadFloat32() (ret float32) {
var (
n int
err error
)
if ret, n, err = utils.ReadFloat32ForString(this.buf[this.head:]); err != nil {
this.reportError("ReadFloat32", err.Error())
return
}
this.head += n
return
}
func (this *JsonReader) ReadFloat64() (ret float64) {
var (
n int
err error
)
if ret, n, err = utils.ReadFloat64ForString(this.buf[this.head:]); err != nil {
this.reportError("ReadFloat64", err.Error())
return
}
this.head += n
return
}
func (this *JsonReader) ReadString() (ret string) {
c := this.nextToken()
if c == '"' {
for i := this.head; i < this.tail; i++ {
c := this.buf[i]
if c == '"' {
ret = string(this.buf[this.head:i])
this.head = i + 1
return ret
} else if c == '\\' {
break
} else if c < ' ' {
this.reportError("ReadString",
fmt.Sprintf(`invalid control character found: %d`, c))
return
}
}
return this.readStringSlowPath()
} else if c == 'n' {
this.skipThreeBytes('u', 'l', 'l')
return ""
}
this.reportError("ReadString", `expects " or n, but found `+string([]byte{c}))
return
}
func (this *JsonReader) ResetBytes(d []byte) {
this.buf = d
this.head = 0
this.tail = len(d)
}
func (this *JsonReader) Error() error {
return this.err
}
func (this *JsonReader) SetErr(err error) {
this.err = err
}
//-----------------------------------------------------------------------------------------------------------------------------------
func (this *JsonReader) readByte() (ret byte) {
if this.head == this.tail {
return 0
}
ret = this.buf[this.head]
this.head++
return ret
}
func (this *JsonReader) readStringSlowPath() (ret string) {
var str []byte
var c byte
for this.err == nil {
c = this.readByte()
if c == '"' {
return string(str)
}
if c == '\\' {
c = this.readByte()
str = this.readEscapedChar(c, str)
} else {
str = append(str, c)
}
}
this.reportError("readStringSlowPath", "unexpected end of input")
return
}
func (this *JsonReader) readEscapedChar(c byte, str []byte) []byte {
switch c {
case 'u':
r := this.readU4()
if utf16.IsSurrogate(r) {
c = this.readByte()
if this.err != nil {
return nil
}
if c != '\\' {
this.unreadByte()
str = utils.AppendRune(str, r)
return str
}
c = this.readByte()
if this.err != nil {
return nil
}
if c != 'u' {
str = utils.AppendRune(str, r)
return this.readEscapedChar(c, str)
}
r2 := this.readU4()
if this.err != nil {
return nil
}
combined := utf16.DecodeRune(r, r2)
if combined == '\uFFFD' {
str = utils.AppendRune(str, r)
str = utils.AppendRune(str, r2)
} else {
str = utils.AppendRune(str, combined)
}
} else {
str = utils.AppendRune(str, r)
}
case '"':
str = append(str, '"')
case '\\':
str = append(str, '\\')
case '/':
str = append(str, '/')
case 'b':
str = append(str, '\b')
case 'f':
str = append(str, '\f')
case 'n':
str = append(str, '\n')
case 'r':
str = append(str, '\r')
case 't':
str = append(str, '\t')
default:
this.reportError("readEscapedChar",
`invalid escape char after \`)
return nil
}
return str
}
func (this *JsonReader) readU4() (ret rune) {
for i := 0; i < 4; i++ {
c := this.readByte()
if this.err != nil {
return
}
if c >= '0' && c <= '9' {
ret = ret*16 + rune(c-'0')
} else if c >= 'a' && c <= 'f' {
ret = ret*16 + rune(c-'a'+10)
} else if c >= 'A' && c <= 'F' {
ret = ret*16 + rune(c-'A'+10)
} else {
this.reportError("readU4", "expects 0~9 or a~f, but found "+string([]byte{c}))
return
}
}
return ret
}
func (this *JsonReader) nextToken() byte {
for i := this.head; i < this.tail; i++ {
c := this.buf[i]
switch c {
case ' ', '\n', '\t', '\r':
continue
}
this.head = i + 1
return c
}
return 0
}
func (this *JsonReader) unreadByte() {
if this.err != nil {
return
}
this.head--
return
}
func (this *JsonReader) skipNumber() {
if !this.trySkipNumber() {
this.unreadByte()
if this.err != nil && this.err != io.EOF {
return
}
this.ReadFloat64()
if this.err != nil && this.err != io.EOF {
this.err = nil
this.ReadBigFloat()
}
}
}
func (this *JsonReader) ReadBigFloat() (ret *big.Float) {
var (
n int
err error
)
if ret, n, err = utils.ReadBigFloatForString(this.buf[this.head:]); err != nil {
this.reportError("ReadBigFloat", err.Error())
return
}
this.head += n
return
}
func (iter *JsonReader) trySkipNumber() bool {
dotFound := false
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
switch c {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
case '.':
if dotFound {
iter.reportError("validateNumber", `more than one dot found in number`)
return true // already failed
}
if i+1 == iter.tail {
return false
}
c = iter.buf[i+1]
switch c {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
default:
iter.reportError("validateNumber", `missing digit after dot`)
return true // already failed
}
dotFound = true
default:
switch c {
case ',', ']', '}', ' ', '\t', '\n', '\r':
if iter.head == i {
return false // if - without following digits
}
iter.head = i
return true // must be valid
}
return false // may be invalid
}
}
return false
}
func (this *JsonReader) skipString() {
if !this.trySkipString() {
this.unreadByte()
this.ReadString()
}
}
func (this *JsonReader) trySkipString() bool {
for i := this.head; i < this.tail; i++ {
c := this.buf[i]
if c == '"' {
this.head = i + 1
return true // valid
} else if c == '\\' {
return false
} else if c < ' ' {
this.reportError("trySkipString",
fmt.Sprintf(`invalid control character found: %d`, c))
return true // already failed
}
}
return false
}
func (this *JsonReader) skipObject() {
this.unreadByte()
this.ReadObjectCB(func(extra codecore.IReader, field string) bool {
extra.Skip()
return true
})
}
func (this *JsonReader) skipArray() {
this.unreadByte()
this.ReadArrayCB(func(extra codecore.IReader) bool {
extra.Skip()
return true
})
}
func (this *JsonReader) skipThreeBytes(b1, b2, b3 byte) {
if this.readByte() != b1 {
this.reportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3})))
return
}
if this.readByte() != b2 {
this.reportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3})))
return
}
if this.readByte() != b3 {
this.reportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3})))
return
}
}
func (this *JsonReader) skipFourBytes(b1, b2, b3, b4 byte) {
if this.readByte() != b1 {
this.reportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4})))
return
}
if this.readByte() != b2 {
this.reportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4})))
return
}
if this.readByte() != b3 {
this.reportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4})))
return
}
if this.readByte() != b4 {
this.reportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4})))
return
}
}
func (this *JsonReader) reportError(operation string, msg string) {
if this.err != nil {
if this.err != io.EOF {
return
}
}
peekStart := this.head - 10
if peekStart < 0 {
peekStart = 0
}
peekEnd := this.head + 10
if peekEnd > this.tail {
peekEnd = this.tail
}
parsing := string(this.buf[peekStart:peekEnd])
contextStart := this.head - 50
if contextStart < 0 {
contextStart = 0
}
contextEnd := this.head + 50
if contextEnd > this.tail {
contextEnd = this.tail
}
context := string(this.buf[contextStart:contextEnd])
this.err = fmt.Errorf("%s: %s, error found in #%v byte of ...|%s|..., bigger context ...|%s|...",
operation, msg, this.head-peekStart, parsing, context)
}
func (this *JsonReader) incrementDepth() (success bool) {
this.depth++
if this.depth <= maxDepth {
return true
}
this.reportError("incrementDepth", "exceeded max depth")
return false
}
func (this *JsonReader) decrementDepth() (success bool) {
this.depth--
if this.depth >= 0 {
return true
}
this.reportError("decrementDepth", "unexpected negative nesting")
return false
}
func (iter *JsonReader) ReadObjectCB(callback func(codecore.IReader, string) bool) bool {
c := iter.nextToken()
var field string
if c == '{' {
if !iter.incrementDepth() {
return false
}
c = iter.nextToken()
if c == '"' {
iter.unreadByte()
field = iter.ReadString()
c = iter.nextToken()
if c != ':' {
iter.reportError("ReadObject", "expect : after object field, but found "+string([]byte{c}))
}
if !callback(iter, field) {
iter.decrementDepth()
return false
}
c = iter.nextToken()
for c == ',' {
field = iter.ReadString()
c = iter.nextToken()
if c != ':' {
iter.reportError("ReadObject", "expect : after object field, but found "+string([]byte{c}))
}
if !callback(iter, field) {
iter.decrementDepth()
return false
}
c = iter.nextToken()
}
if c != '}' {
iter.reportError("ReadObjectCB", `object not ended with }`)
iter.decrementDepth()
return false
}
return iter.decrementDepth()
}
if c == '}' {
return iter.decrementDepth()
}
iter.reportError("ReadObjectCB", `expect " after {, but found `+string([]byte{c}))
iter.decrementDepth()
return false
}
if c == 'n' {
iter.skipThreeBytes('u', 'l', 'l')
return true // null
}
iter.reportError("ReadObjectCB", `expect { or n, but found `+string([]byte{c}))
return false
}
func (iter *JsonReader) ReadMapCB(callback func(codecore.IReader, string) bool) bool {
c := iter.nextToken()
if c == '{' {
if !iter.incrementDepth() {
return false
}
c = iter.nextToken()
if c == '"' {
iter.unreadByte()
field := iter.ReadString()
if iter.nextToken() != ':' {
iter.reportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c}))
iter.decrementDepth()
return false
}
if !callback(iter, field) {
iter.decrementDepth()
return false
}
c = iter.nextToken()
for c == ',' {
field = iter.ReadString()
if iter.nextToken() != ':' {
iter.reportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c}))
iter.decrementDepth()
return false
}
if !callback(iter, field) {
iter.decrementDepth()
return false
}
c = iter.nextToken()
}
if c != '}' {
iter.reportError("ReadMapCB", `object not ended with }`)
iter.decrementDepth()
return false
}
return iter.decrementDepth()
}
if c == '}' {
return iter.decrementDepth()
}
iter.reportError("ReadMapCB", `expect " after {, but found `+string([]byte{c}))
iter.decrementDepth()
return false
}
if c == 'n' {
iter.skipThreeBytes('u', 'l', 'l')
return true // null
}
iter.reportError("ReadMapCB", `expect { or n, but found `+string([]byte{c}))
return false
}
func (iter *JsonReader) ReadArrayCB(callback func(codecore.IReader) bool) (ret bool) {
c := iter.nextToken()
if c == '[' {
if !iter.incrementDepth() {
return false
}
c = iter.nextToken()
if c != ']' {
iter.unreadByte()
if !callback(iter) {
iter.decrementDepth()
return false
}
c = iter.nextToken()
for c == ',' {
if !callback(iter) {
iter.decrementDepth()
return false
}
c = iter.nextToken()
}
if c != ']' {
iter.reportError("ReadArrayCB", "expect ] in the end, but found "+string([]byte{c}))
iter.decrementDepth()
return false
}
return iter.decrementDepth()
}
return iter.decrementDepth()
}
if c == 'n' {
iter.skipThreeBytes('u', 'l', 'l')
return true // null
}
iter.reportError("ReadArrayCB", "expect [ or n, but found "+string([]byte{c}))
return false
}