summaryrefslogtreecommitdiff
path: root/decode.go
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@datawire.io>2022-08-14 20:52:06 -0600
committerLuke Shumaker <lukeshu@datawire.io>2022-08-16 00:05:24 -0600
commit54bbd1e59317a6e9658eb8098657078cc8e81979 (patch)
tree0d7033a0644945dedfe0fca158e0c40864f759f6 /decode.go
parent2ae2ebe2a5ac712db6f9221cb1ad8cfa76aad180 (diff)
wip: Reduce test differences [ci-skip]
- Handle UTF-16 surrogate pairs - Handle cycles in values - Handle cycles in types - Better errors - Handle case-folding of struct field names - Allow []byteTypeWithMethods - Fix struct field-order - Fix handling of interfaces storing pointers - Enforce a maximum decode depth - Validate struct tags
Diffstat (limited to 'decode.go')
-rw-r--r--decode.go342
1 files changed, 231 insertions, 111 deletions
diff --git a/decode.go b/decode.go
index 8426526..e4fdd77 100644
--- a/decode.go
+++ b/decode.go
@@ -14,6 +14,8 @@ import (
"reflect"
"strconv"
"strings"
+ "unicode/utf16"
+ "unicode/utf8"
)
type Decodable interface {
@@ -26,6 +28,11 @@ type runeBuffer interface {
Reset()
}
+type decodeStackItem struct {
+ par reflect.Type
+ idx any
+}
+
type Decoder struct {
io runeTypeScanner
@@ -35,7 +42,7 @@ type Decoder struct {
// state
err error
- stack []any
+ stack []decodeStackItem
}
func NewDecoder(r io.Reader) *Decoder {
@@ -63,8 +70,18 @@ func (dec *Decoder) More() bool {
return e == nil && t != RuneTypeEOF
}
-func (dec *Decoder) stackPush(idx any) {
- dec.stack = append(dec.stack, idx)
+const maxNestingDepth = 10000
+
+func (dec *Decoder) stackPush(par reflect.Type, idx any) {
+ dec.stack = append(dec.stack, decodeStackItem{par, idx})
+ if len(dec.stack) > maxNestingDepth {
+ panic(decodeError{
+ Field: dec.stackStr(),
+ FieldParent: dec.stackParent(),
+ FieldName: dec.stackName(),
+ Err: ErrDecodeExceededMaxDepth,
+ })
+ }
}
func (dec *Decoder) stackPop() {
dec.stack = dec.stack[:len(dec.stack)-1]
@@ -73,11 +90,30 @@ func (dec *Decoder) stackStr() string {
var buf strings.Builder
buf.WriteString("v")
for _, item := range dec.stack {
- fmt.Fprintf(&buf, "[%#v]", item)
+ fmt.Fprintf(&buf, "[%#v]", item.idx)
}
return buf.String()
}
+func (dec *Decoder) stackParent() string {
+ if len(dec.stack) > 0 && dec.stack[len(dec.stack)-1].par.Kind() == reflect.Struct {
+ return dec.stack[len(dec.stack)-1].par.Name()
+ }
+ return ""
+}
+
+func (dec *Decoder) stackName() string {
+ var fields []string
+ for i := len(dec.stack) - 1; i >= 0 && dec.stack[i].par.Kind() == reflect.Struct; i-- {
+ fields = append(fields, dec.stack[i].idx.(string))
+ }
+ for i := 0; i < len(fields)/2; i++ {
+ j := (len(fields) - 1) - i
+ fields[i], fields[j] = fields[j], fields[i]
+ }
+ return strings.Join(fields, ".")
+}
+
func Decode(r io.Reader, ptr any) error {
return NewDecoder(r).Decode(ptr)
}
@@ -85,7 +121,7 @@ func Decode(r io.Reader, ptr any) error {
func (dec *Decoder) Decode(ptr any) (err error) {
ptrVal := reflect.ValueOf(ptr)
if ptrVal.Kind() != reflect.Pointer || ptrVal.IsNil() || !ptrVal.Elem().CanSet() {
- return &json.InvalidUnmarshalError{
+ return &DecodeArgumentError{
// don't use ptrVal.Type() because ptrVal might be invalid if ptr==nil
Type: reflect.TypeOf(ptr),
}
@@ -99,7 +135,8 @@ func (dec *Decoder) Decode(ptr any) (err error) {
defer func() {
if r := recover(); r != nil {
if de, ok := r.(decodeError); ok {
- dec.err = de.Err
+ pub := DecodeError(de)
+ dec.err = &pub
err = dec.err
} else {
panic(r)
@@ -112,19 +149,31 @@ func (dec *Decoder) Decode(ptr any) (err error) {
// io helpers //////////////////////////////////////////////////////////////////////////////////////
-type decodeError struct {
- Err error
-}
-
-func (dec *Decoder) panicType(typ reflect.Type, err error) {
- panic(decodeError{fmt.Errorf("json: type mismatch error at input byte %v: %s: type %v: %w",
- dec.InputOffset(), dec.stackStr(), typ, err)})
+type decodeError DecodeError
+
+func (dec *Decoder) panicType(jTyp string, gTyp reflect.Type, err error) {
+ panic(decodeError{
+ Field: dec.stackStr(),
+ FieldParent: dec.stackParent(),
+ FieldName: dec.stackName(),
+ Err: &DecodeTypeError{
+ GoType: gTyp,
+ JSONType: jTyp,
+ Err: err,
+ Offset: dec.InputOffset(),
+ },
+ })
}
func (dec *Decoder) readRune() (rune, RuneType) {
c, _, t, e := dec.io.ReadRuneType()
if e != nil {
- panic(decodeError{e})
+ panic(decodeError{
+ Field: dec.stackStr(),
+ FieldParent: dec.stackParent(),
+ FieldName: dec.stackName(),
+ Err: e,
+ })
}
return c, t
}
@@ -150,10 +199,10 @@ func (dec *Decoder) expectRune(ec rune, et RuneType) {
}
}
-func (dec *Decoder) expectRuneType(ec rune, et RuneType) {
+func (dec *Decoder) expectRuneType(ec rune, et RuneType, gt reflect.Type) {
ac, at := dec.readRune()
if ac != ec || at != et {
- dec.panicType(nil, fmt.Errorf("TODO error message"))
+ dec.panicType(at.jsonType(), gt, nil)
}
}
@@ -164,7 +213,12 @@ type decRuneTypeScanner struct {
func (sc *decRuneTypeScanner) ReadRuneType() (rune, int, RuneType, error) {
c, s, t, e := sc.dec.io.ReadRuneType()
if e != nil {
- panic(decodeError{e})
+ panic(decodeError{
+ Field: sc.dec.stackStr(),
+ FieldParent: sc.dec.stackParent(),
+ FieldName: sc.dec.stackName(),
+ Err: e,
+ })
}
return c, s, t, nil
}
@@ -223,22 +277,25 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
typ := val.Type()
switch {
case val.CanAddr() && reflect.PointerTo(typ) == rawMessagePtrType:
+ t := dec.peekRuneType()
var buf bytes.Buffer
dec.scan(&buf)
if err := val.Addr().Interface().(*json.RawMessage).UnmarshalJSON(buf.Bytes()); err != nil {
- dec.panicType(typ, err)
+ dec.panicType(t.jsonType(), typ, err)
}
case val.CanAddr() && reflect.PointerTo(typ).Implements(decodableType):
+ t := dec.peekRuneType()
obj := val.Addr().Interface().(Decodable)
if err := obj.DecodeJSON(dec.limitingScanner()); err != nil {
- dec.panicType(typ, err)
+ dec.panicType(t.jsonType(), typ, err)
}
case val.CanAddr() && reflect.PointerTo(typ).Implements(jsonUnmarshalerType):
+ t := dec.peekRuneType()
var buf bytes.Buffer
dec.scan(&buf)
obj := val.Addr().Interface().(json.Unmarshaler)
if err := obj.UnmarshalJSON(buf.Bytes()); err != nil {
- dec.panicType(typ, err)
+ dec.panicType(t.jsonType(), typ, err)
}
case val.CanAddr() && reflect.PointerTo(typ).Implements(textUnmarshalerType):
if nullOK && dec.peekRuneType() == RuneTypeNullN {
@@ -246,30 +303,29 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
return
}
var buf bytes.Buffer
- dec.decodeString(&buf)
+ dec.decodeString(typ, &buf)
obj := val.Addr().Interface().(encoding.TextUnmarshaler)
if err := obj.UnmarshalText(buf.Bytes()); err != nil {
- dec.panicType(typ, err)
+ dec.panicType("string", typ, err)
}
default:
- kind := typ.Kind()
- switch kind {
+ switch kind := typ.Kind(); kind {
case reflect.Bool:
if nullOK && dec.peekRuneType() == RuneTypeNullN {
dec.decodeNull()
return
}
- val.SetBool(dec.decodeBool())
+ val.SetBool(dec.decodeBool(typ))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if nullOK && dec.peekRuneType() == RuneTypeNullN {
dec.decodeNull()
return
}
var buf strings.Builder
- dec.scanNumber(&buf)
+ dec.scanNumber(typ, &buf)
n, err := strconv.ParseInt(buf.String(), 10, kind2bits[kind])
if err != nil {
- dec.panicType(typ, err)
+ dec.panicType("number "+buf.String(), typ, err)
}
val.SetInt(n)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
@@ -278,10 +334,10 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
return
}
var buf strings.Builder
- dec.scanNumber(&buf)
+ dec.scanNumber(typ, &buf)
n, err := strconv.ParseUint(buf.String(), 10, kind2bits[kind])
if err != nil {
- dec.panicType(typ, err)
+ dec.panicType("number "+buf.String(), typ, err)
}
val.SetUint(n)
case reflect.Float32, reflect.Float64:
@@ -290,10 +346,10 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
return
}
var buf strings.Builder
- dec.scanNumber(&buf)
+ dec.scanNumber(typ, &buf)
n, err := strconv.ParseFloat(buf.String(), kind2bits[kind])
if err != nil {
- dec.panicType(typ, err)
+ dec.panicType("number "+buf.String(), typ, err)
}
val.SetFloat(n)
case reflect.String:
@@ -303,32 +359,44 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
}
var buf strings.Builder
if typ == numberType {
- dec.scanNumber(&buf)
+ dec.scanNumber(typ, &buf)
val.SetString(buf.String())
} else {
- dec.decodeString(&buf)
+ dec.decodeString(typ, &buf)
val.SetString(buf.String())
}
case reflect.Interface:
if typ.NumMethod() > 0 {
- dec.panicType(typ, fmt.Errorf("cannot decode in to non-empty interface"))
+ dec.panicType("", typ, fmt.Errorf("cannot decode in to non-empty interface"))
+ }
+ // If the interface stores a pointer, try to use the type information of the pointer.
+ if !val.IsNil() && val.Elem().Kind() == reflect.Pointer {
+ // Follow a chain of pointers until we find the first settable
+ // pointer (if any).
+ ptr := val.Elem()
+ for ptr.Kind() == reflect.Pointer {
+ if ptr.CanSet() {
+ break
+ }
+ if ptr.IsNil() {
+ break
+ }
+ ptr = ptr.Elem()
+ }
+ // We only neet to be able to set the pointer itself if we're
+ // decoding "null", so add a "||" clause.
+ if ptr.Kind() == reflect.Pointer && (ptr.CanSet() || dec.peekRuneType() != RuneTypeNullN) {
+ dec.decode(ptr, false)
+ break
+ }
}
+ // Couldn't get type information from a pointer; fall back to untyped mode.
switch dec.peekRuneType() {
case RuneTypeNullN:
- if !val.IsNil() && val.Elem().Kind() == reflect.Pointer && val.Elem().Elem().Kind() == reflect.Pointer {
- // XXX: I can't justify this case, other than "it's what encoding/json does, but
- // I don't understand their rationale".
- dec.decode(val.Elem(), false)
- } else {
- dec.decodeNull()
- val.Set(reflect.Zero(typ))
- }
+ dec.decodeNull()
+ val.Set(reflect.Zero(typ))
default:
- if !val.IsNil() && val.Elem().Kind() == reflect.Pointer {
- dec.decode(val.Elem(), false)
- } else {
- val.Set(reflect.ValueOf(dec.decodeAny()))
- }
+ val.Set(reflect.ValueOf(dec.decodeAny()))
}
case reflect.Struct:
if nullOK && dec.peekRuneType() == RuneTypeNullN {
@@ -337,14 +405,23 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
}
index := indexStruct(typ)
var nameBuf strings.Builder
- dec.decodeObject(&nameBuf, func() {
+ dec.decodeObject(typ, &nameBuf, func() {
name := nameBuf.String()
- dec.stackPush(name)
+ dec.stackPush(typ, name)
defer dec.stackPop()
idx, ok := index.byName[name]
if !ok {
+ for oname, oidx := range index.byName {
+ if strings.EqualFold(name, oname) {
+ idx = oidx
+ ok = true
+ break
+ }
+ }
+ }
+ if !ok {
if dec.disallowUnknownFields {
- dec.panicType(typ, fmt.Errorf("unknown field %q", name))
+ dec.panicType("", typ, fmt.Errorf("json: unknown field %q", name))
}
dec.scan(io.Discard)
return
@@ -353,18 +430,20 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
fVal := val
for _, idx := range field.Path {
if fVal.Kind() == reflect.Pointer {
- if fVal.IsNil() {
- if !fVal.CanSet() { // https://golang.org/issue/21357
- dec.panicType(fVal.Type().Elem(), fmt.Errorf("cannot set embedded pointer to unexported type"))
+ if fVal.IsNil() && !fVal.CanSet() { // https://golang.org/issue/21357
+ dec.panicType("", fVal.Type().Elem(), fmt.Errorf("cannot set embedded pointer to unexported type"))
+ }
+ if dec.peekRuneType() != RuneTypeNullN {
+ if fVal.IsNil() {
+ fVal.Set(reflect.New(fVal.Type().Elem()))
}
- fVal.Set(reflect.New(fVal.Type().Elem()))
+ fVal = fVal.Elem()
}
- fVal = fVal.Elem()
}
fVal = fVal.Field(idx)
}
if field.Quote {
- switch dec.peekRuneType() {
+ switch t := dec.peekRuneType(); t {
case RuneTypeNullN:
dec.decodeNull()
switch fVal.Kind() {
@@ -378,18 +457,25 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
case RuneTypeStringBeg:
// TODO: Figure out how to do this without buffering, have correct offsets.
var buf bytes.Buffer
- dec.decodeString(&buf)
- subD := NewDecoder(&buf)
- subD.decode(fVal, false)
+ dec.decodeString(nil, &buf)
+ if err := Decode(bytes.NewReader(buf.Bytes()), fVal.Addr().Interface()); err != nil {
+ if str := buf.String(); str != "null" {
+ dec.panicType("", fVal.Type(),
+ fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v",
+ str, fVal.Type()))
+ }
+ }
default:
- dec.panicType(typ, fmt.Errorf(",string field TODO ERROR MESSAGE"))
+ dec.panicType(t.jsonType(), fVal.Type(),
+ fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v",
+ fVal.Type()))
}
} else {
dec.decode(fVal, true)
}
})
case reflect.Map:
- switch dec.peekRuneType() {
+ switch t := dec.peekRuneType(); t {
case RuneTypeNullN:
dec.decodeNull()
val.Set(reflect.Zero(typ))
@@ -398,14 +484,14 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
val.Set(reflect.MakeMap(typ))
}
var nameBuf bytes.Buffer
- dec.decodeObject(&nameBuf, func() {
+ dec.decodeObject(typ, &nameBuf, func() {
nameValTyp := typ.Key()
nameValPtr := reflect.New(nameValTyp)
switch {
case reflect.PointerTo(nameValTyp).Implements(textUnmarshalerType):
obj := nameValPtr.Interface().(encoding.TextUnmarshaler)
if err := obj.UnmarshalText(nameBuf.Bytes()); err != nil {
- dec.panicType(nameValTyp, err)
+ dec.panicType("string", nameValTyp, err)
}
default:
switch nameValTyp.Kind() {
@@ -414,20 +500,20 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
n, err := strconv.ParseInt(nameBuf.String(), 10, kind2bits[nameValTyp.Kind()])
if err != nil {
- dec.panicType(nameValTyp, err)
+ dec.panicType("number "+nameBuf.String(), nameValTyp, err)
}
nameValPtr.Elem().SetInt(n)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
n, err := strconv.ParseUint(nameBuf.String(), 10, kind2bits[nameValTyp.Kind()])
if err != nil {
- dec.panicType(nameValTyp, err)
+ dec.panicType("number "+nameBuf.String(), nameValTyp, err)
}
nameValPtr.Elem().SetUint(n)
default:
- dec.panicType(typ, fmt.Errorf("invalid map key type: %v", nameValTyp))
+ dec.panicType("object", typ, &DecodeArgumentError{nameValTyp})
}
}
- dec.stackPush(nameValPtr.Elem())
+ dec.stackPush(typ, nameValPtr.Elem())
defer dec.stackPop()
fValPtr := reflect.New(typ.Elem())
@@ -436,33 +522,39 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
val.SetMapIndex(nameValPtr.Elem(), fValPtr.Elem())
})
default:
- dec.panicType(typ, fmt.Errorf("map: TODO"))
+ dec.panicType(t.jsonType(), typ, nil)
}
case reflect.Slice:
switch {
- case typ.Elem().Kind() == reflect.Uint8:
- switch dec.peekRuneType() {
+ case typ.Elem().Kind() == reflect.Uint8 && !(dec.peekRuneType() == RuneTypeArrayBeg && (false ||
+ reflect.PointerTo(typ.Elem()).Implements(decodableType) ||
+ reflect.PointerTo(typ.Elem()).Implements(jsonUnmarshalerType) ||
+ reflect.PointerTo(typ.Elem()).Implements(textUnmarshalerType))):
+ switch t := dec.peekRuneType(); t {
case RuneTypeNullN:
dec.decodeNull()
val.Set(reflect.Zero(typ))
case RuneTypeStringBeg:
- var buf bytes.Buffer
- dec.decodeString(newBase64Decoder(&buf))
if typ.Elem() == byteType {
+ var buf bytes.Buffer
+ dec.decodeString(typ, newBase64Decoder(&buf))
val.Set(reflect.ValueOf(buf.Bytes()))
} else {
+ // TODO: Surely there's a better way. At the very least, we should
+ // avoid buffering.
+ var buf bytes.Buffer
+ dec.decodeString(typ, newBase64Decoder(&buf))
bs := buf.Bytes()
- // TODO: Surely there's a better way.
val.Set(reflect.MakeSlice(typ, len(bs), len(bs)))
for i := 0; i < len(bs); i++ {
val.Index(i).Set(reflect.ValueOf(bs[i]).Convert(typ.Elem()))
}
}
default:
- dec.panicType(typ, fmt.Errorf("byte slice: TODO"))
+ dec.panicType(t.jsonType(), typ, nil)
}
default:
- switch dec.peekRuneType() {
+ switch t := dec.peekRuneType(); t {
case RuneTypeNullN:
dec.decodeNull()
val.Set(reflect.Zero(typ))
@@ -474,8 +566,8 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
val.Set(val.Slice(0, 0))
}
i := 0
- dec.decodeArray(func() {
- dec.stackPush(i)
+ dec.decodeArray(typ, func() {
+ dec.stackPush(typ, i)
defer dec.stackPop()
mValPtr := reflect.New(typ.Elem())
dec.decode(mValPtr.Elem(), false)
@@ -483,7 +575,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
i++
})
default:
- dec.panicType(typ, fmt.Errorf("slice: TODO"))
+ dec.panicType(t.jsonType(), typ, nil)
}
}
case reflect.Array:
@@ -493,8 +585,8 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
}
i := 0
n := val.Len()
- dec.decodeArray(func() {
- dec.stackPush(i)
+ dec.decodeArray(typ, func() {
+ dec.stackPush(typ, i)
defer dec.stackPop()
if i < n {
mValPtr := reflect.New(typ.Elem())
@@ -512,15 +604,6 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
switch dec.peekRuneType() {
case RuneTypeNullN:
dec.decodeNull()
- /*
- for typ.Elem().Kind() == reflect.Pointer {
- if val.IsNil() || !val.Elem().CanSet() {
- val.Set(reflect.New(typ.Elem()))
- }
- val = val.Elem()
- typ = val.Type()
- }
- */
val.Set(reflect.Zero(typ))
default:
if val.IsNil() {
@@ -529,7 +612,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
dec.decode(val.Elem(), false)
}
default:
- dec.panicType(typ, fmt.Errorf("unsupported type (kind=%v)", typ.Kind()))
+ dec.panicType("", typ, fmt.Errorf("unsupported type (kind=%v)", typ.Kind()))
}
}
}
@@ -545,9 +628,9 @@ func (dec *Decoder) scan(out io.Writer) {
}
}
-func (dec *Decoder) scanNumber(out io.Writer) {
- if !dec.peekRuneType().IsNumber() {
- dec.panicType(numberType, fmt.Errorf("number: not a number"))
+func (dec *Decoder) scanNumber(gTyp reflect.Type, out io.Writer) {
+ if t := dec.peekRuneType(); !t.IsNumber() {
+ dec.panicType(t.jsonType(), gTyp, nil)
}
dec.scan(out)
}
@@ -558,25 +641,27 @@ func (dec *Decoder) decodeAny() any {
switch c {
case '{':
ret := make(map[string]any)
+ typ := reflect.TypeOf(ret)
var nameBuf strings.Builder
- dec.decodeObject(&nameBuf, func() {
+ dec.decodeObject(typ, &nameBuf, func() {
name := nameBuf.String()
- dec.stackPush(name)
+ dec.stackPush(typ, name)
defer dec.stackPop()
ret[name] = dec.decodeAny()
})
return ret
case '[':
ret := []any{}
- dec.decodeArray(func() {
- dec.stackPush(len(ret))
+ typ := reflect.TypeOf(ret)
+ dec.decodeArray(typ, func() {
+ dec.stackPush(typ, len(ret))
defer dec.stackPop()
ret = append(ret, dec.decodeAny())
})
return ret
case '"':
var buf strings.Builder
- dec.decodeString(&buf)
+ dec.decodeString(nil, &buf)
return buf.String()
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
var buf strings.Builder
@@ -591,7 +676,7 @@ func (dec *Decoder) decodeAny() any {
}
return f64
case 't', 'f':
- return dec.decodeBool()
+ return dec.decodeBool(nil)
case 'n':
dec.decodeNull()
return nil
@@ -600,8 +685,8 @@ func (dec *Decoder) decodeAny() any {
}
}
-func (dec *Decoder) decodeObject(nameBuf runeBuffer, decodeKVal func()) {
- dec.expectRuneType('{', RuneTypeObjectBeg)
+func (dec *Decoder) decodeObject(gTyp reflect.Type, nameBuf runeBuffer, decodeKVal func()) {
+ dec.expectRuneType('{', RuneTypeObjectBeg, gTyp)
_, t := dec.readRune()
switch t {
case RuneTypeObjectEnd:
@@ -610,7 +695,7 @@ func (dec *Decoder) decodeObject(nameBuf runeBuffer, decodeKVal func()) {
decodeMember:
dec.unreadRune()
nameBuf.Reset()
- dec.decodeString(nameBuf)
+ dec.decodeString(nil, nameBuf)
dec.expectRune(':', RuneTypeObjectColon)
decodeKVal()
_, t := dec.readRune()
@@ -628,8 +713,8 @@ func (dec *Decoder) decodeObject(nameBuf runeBuffer, decodeKVal func()) {
}
}
-func (dec *Decoder) decodeArray(decodeMember func()) {
- dec.expectRuneType('[', RuneTypeArrayBeg)
+func (dec *Decoder) decodeArray(gTyp reflect.Type, decodeMember func()) {
+ dec.expectRuneType('[', RuneTypeArrayBeg, gTyp)
_, t := dec.readRune()
switch t {
case RuneTypeArrayEnd:
@@ -650,8 +735,8 @@ func (dec *Decoder) decodeArray(decodeMember func()) {
}
}
-func (dec *Decoder) decodeString(out io.Writer) {
- dec.expectRuneType('"', RuneTypeStringBeg)
+func (dec *Decoder) decodeString(gTyp reflect.Type, out io.Writer) {
+ dec.expectRuneType('"', RuneTypeStringBeg, gTyp)
var uhex [4]byte
for {
c, t := dec.readRune()
@@ -694,7 +779,42 @@ func (dec *Decoder) decodeString(out io.Writer) {
rune(uhex[1])<<8 |
rune(uhex[2])<<4 |
rune(uhex[3])<<0
- _, _ = writeRune(out, c)
+ handleUnicode:
+ if utf16.IsSurrogate(c) {
+ if dec.peekRuneType() != RuneTypeStringEsc {
+ _, _ = writeRune(out, utf8.RuneError)
+ break
+ }
+ dec.expectRune('\\', RuneTypeStringEsc)
+ if dec.peekRuneType() != RuneTypeStringEscU {
+ _, _ = writeRune(out, utf8.RuneError)
+ break
+ }
+ dec.expectRune('u', RuneTypeStringEscU)
+
+ b, _ := dec.readRune()
+ uhex[0], _ = hex2int(b)
+ b, _ = dec.readRune()
+ uhex[1], _ = hex2int(b)
+ b, _ = dec.readRune()
+ uhex[2], _ = hex2int(b)
+ b, _ = dec.readRune()
+ uhex[3], _ = hex2int(b)
+ c2 := 0 |
+ rune(uhex[0])<<12 |
+ rune(uhex[1])<<8 |
+ rune(uhex[2])<<4 |
+ rune(uhex[3])<<0
+ d := utf16.DecodeRune(c, c2)
+ if d == utf8.RuneError {
+ _, _ = writeRune(out, utf8.RuneError)
+ c = c2
+ goto handleUnicode
+ }
+ _, _ = writeRune(out, d)
+ } else {
+ _, _ = writeRune(out, c)
+ }
case RuneTypeStringEnd:
return
default:
@@ -703,8 +823,8 @@ func (dec *Decoder) decodeString(out io.Writer) {
}
}
-func (dec *Decoder) decodeBool() bool {
- c, _ := dec.readRune()
+func (dec *Decoder) decodeBool(gTyp reflect.Type) bool {
+ c, t := dec.readRune()
switch c {
case 't':
dec.expectRune('r', RuneTypeTrueR)
@@ -718,13 +838,13 @@ func (dec *Decoder) decodeBool() bool {
dec.expectRune('e', RuneTypeFalseE)
return false
default:
- dec.panicType(boolType, fmt.Errorf("bool: expected %q or %q but got %q", 't', 'f', c))
+ dec.panicType(t.jsonType(), gTyp, nil)
panic("not reached")
}
}
func (dec *Decoder) decodeNull() {
- dec.expectRuneType('n', RuneTypeNullN)
+ dec.expectRune('n', RuneTypeNullN)
dec.expectRune('u', RuneTypeNullU)
dec.expectRune('l', RuneTypeNullL1)
dec.expectRune('l', RuneTypeNullL2)