diff --git a/nbt/decode.go b/nbt/decode.go index 4e33ecd..dd30411 100644 --- a/nbt/decode.go +++ b/nbt/decode.go @@ -18,7 +18,6 @@ func (d *Decoder) Decode(v interface{}) error { if val.Kind() != reflect.Ptr { return errors.New("nbt: non-pointer passed to Unmarshal") } - //start read NBT tagType, tagName, err := d.readTag() if err != nil { @@ -29,7 +28,9 @@ func (d *Decoder) Decode(v interface{}) error { return fmt.Errorf("nbt: unknown Tag, maybe need %s", c) } - err = d.unmarshal(val.Elem(), tagType, tagName) + // We decode val not val.Elem because the Unmarshaler interface + // test must be applied at the top level of the value. + err = d.unmarshal(val, tagType, tagName) if err != nil { return fmt.Errorf("nbt: fail to decode tag %q: %w", tagName, err) } @@ -55,6 +56,8 @@ func (d *Decoder) unmarshal(val reflect.Value, tagType byte, tagName string) err return i.Unmarshal(tagType, tagName, d.r) } } + // TODO: use function like json.indirect() to handle pointer better + val = val.Elem() switch tagType { default: @@ -355,6 +358,7 @@ func (d *Decoder) unmarshal(val reflect.Value, tagType byte, tagName string) err return nil } +// rawRead read and discard a value func (d *Decoder) rawRead(tagType byte) error { var buf [8]byte switch tagType { diff --git a/nbt/raw.go b/nbt/raw.go new file mode 100644 index 0000000..f599038 --- /dev/null +++ b/nbt/raw.go @@ -0,0 +1,23 @@ +package nbt + +import ( + "bytes" + "io" +) + +type RawMessage []byte + +func (m *RawMessage) Unmarshal(tagType byte, _ string, r DecoderReader) error { + if tagType == TagEnd { + return ErrEND + } + + buf := bytes.NewBuffer((*m)[:0]) + tee := io.TeeReader(r, buf) + err := NewDecoder(tee).rawRead(tagType) + if err != nil { + return err + } + *m = buf.Bytes() + return nil +}