Fix unmarshal error in nbt
This commit is contained in:
@ -51,13 +51,10 @@ func (d *Decoder) checkCompressed(head byte) (compress string) {
|
|||||||
var ErrEND = errors.New("unexpected TAG_End")
|
var ErrEND = errors.New("unexpected TAG_End")
|
||||||
|
|
||||||
func (d *Decoder) unmarshal(val reflect.Value, tagType byte, tagName string) error {
|
func (d *Decoder) unmarshal(val reflect.Value, tagType byte, tagName string) error {
|
||||||
if val.CanInterface() {
|
u, val := indirect(val, tagType == TagEnd)
|
||||||
if i, ok := val.Interface().(Unmarshaler); ok {
|
if u != nil {
|
||||||
return i.Unmarshal(tagType, tagName, d.r)
|
return u.Unmarshal(tagType, tagName, d.r)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// TODO: use function like json.indirect() to handle pointer better
|
|
||||||
val = val.Elem()
|
|
||||||
|
|
||||||
switch tagType {
|
switch tagType {
|
||||||
default:
|
default:
|
||||||
@ -358,6 +355,70 @@ func (d *Decoder) unmarshal(val reflect.Value, tagType byte, tagName string) err
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// indirect walks down v allocating pointers as needed,
|
||||||
|
// until it gets to a non-pointer.
|
||||||
|
// If it encounters an Unmarshaler, indirect stops and returns that.
|
||||||
|
// If decodingNull is true, indirect stops at the first settable pointer so it
|
||||||
|
// can be set to nil.
|
||||||
|
//
|
||||||
|
// This function is copied and modified from encoding/json
|
||||||
|
func indirect(v reflect.Value, decodingNull bool) (Unmarshaler, reflect.Value) {
|
||||||
|
v0 := v
|
||||||
|
haveAddr := false
|
||||||
|
|
||||||
|
// If v is a named type and is addressable,
|
||||||
|
// start with its address, so that if the type has pointer methods,
|
||||||
|
// we find them.
|
||||||
|
if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
|
||||||
|
haveAddr = true
|
||||||
|
v = v.Addr()
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
// Load value from interface, but only if the result will be
|
||||||
|
// usefully addressable.
|
||||||
|
if v.Kind() == reflect.Interface && !v.IsNil() {
|
||||||
|
e := v.Elem()
|
||||||
|
if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) {
|
||||||
|
haveAddr = false
|
||||||
|
v = e
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Kind() != reflect.Ptr {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if decodingNull && v.CanSet() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent infinite loop if v is an interface pointing to its own address:
|
||||||
|
// var v interface{}
|
||||||
|
// v = &v
|
||||||
|
if v.Elem().Kind() == reflect.Interface && v.Elem().Elem() == v {
|
||||||
|
v = v.Elem()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if v.IsNil() {
|
||||||
|
v.Set(reflect.New(v.Type().Elem()))
|
||||||
|
}
|
||||||
|
if v.Type().NumMethod() > 0 && v.CanInterface() {
|
||||||
|
if u, ok := v.Interface().(Unmarshaler); ok {
|
||||||
|
return u, reflect.Value{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if haveAddr {
|
||||||
|
v = v0 // restore original value after round-trip Value.Addr().Elem()
|
||||||
|
haveAddr = false
|
||||||
|
} else {
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, v
|
||||||
|
}
|
||||||
|
|
||||||
// rawRead read and discard a value
|
// rawRead read and discard a value
|
||||||
func (d *Decoder) rawRead(tagType byte) error {
|
func (d *Decoder) rawRead(tagType byte) error {
|
||||||
var buf [8]byte
|
var buf [8]byte
|
||||||
|
Reference in New Issue
Block a user