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() if c == ']' { return true } this.unreadByte() 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() if c == '}' { return this.decrementDepth() } this.unreadByte() 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 }