package fastnbt import ( "encoding/binary" "errors" "fmt" "io" "github.com/Tnze/go-mc/nbt" ) func (v *Value) UnmarshalNBT(tagType byte, r nbt.DecoderReader) error { v.tag = tagType var buf [8]byte switch tagType { case nbt.TagEnd: case nbt.TagByte: n, err := r.ReadByte() if err != nil { return err } v.data = append(v.data[:0], n) case nbt.TagShort: if _, err := r.Read(buf[:2]); err != nil { return err } v.data = append(v.data[:0], buf[:2]...) case nbt.TagInt, nbt.TagFloat: if _, err := r.Read(buf[:4]); err != nil { return err } v.data = append(v.data[:0], buf[:4]...) case nbt.TagLong, nbt.TagDouble: if _, err := r.Read(buf[:]); err != nil { return err } v.data = append(v.data[:0], buf[:]...) case nbt.TagByteArray: n, err := readInt32(r) if err != nil { return err } v.data = append(v.data[:0], make([]byte, 4+n)...) binary.BigEndian.PutUint32(v.data, uint32(n)) _, err = io.ReadFull(r, v.data[4:]) if err != nil { return err } case nbt.TagString: n, err := readInt16(r) if err != nil { return err } v.data = append(v.data[:0], make([]byte, 2+n)...) binary.BigEndian.PutUint16(v.data, uint16(n)) _, err = io.ReadFull(r, v.data[2:]) if err != nil { return err } case nbt.TagList: t, err := r.ReadByte() if err != nil { return err } length, err := readInt32(r) if err != nil { return err } v.list = v.list[:0] for i := int32(0); i < length; i++ { field := new(Value) err = field.UnmarshalNBT(t, r) if err != nil { return err } v.list = append(v.list, field) } case nbt.TagCompound: for { t, name, err := readTag(r) if err != nil { return err } if t == nbt.TagEnd { break } field := new(Value) err = field.UnmarshalNBT(t, r) if err != nil { return decodeErr{name, err} } v.comp.kvs = append(v.comp.kvs, kv{tag: name, v: field}) } case nbt.TagIntArray: n, err := readInt32(r) if err != nil { return err } v.data = append(v.data[:0], make([]byte, 4+n*4)...) binary.BigEndian.PutUint32(v.data, uint32(n)) _, err = io.ReadFull(r, v.data[4:]) if err != nil { return err } case nbt.TagLongArray: n, err := readInt32(r) if err != nil { return err } v.data = append(v.data[:0], make([]byte, 4+n*8)...) binary.BigEndian.PutUint32(v.data, uint32(n)) _, err = io.ReadFull(r, v.data[4:]) if err != nil { return err } } return nil } func readTag(r nbt.DecoderReader) (tagType byte, tagName string, err error) { tagType, err = r.ReadByte() if err != nil { return } switch tagType { // case 0x1f, 0x78: case nbt.TagEnd: default: // Read Tag tagName, err = readString(r) } return } func readInt16(r nbt.DecoderReader) (int16, error) { var data [2]byte _, err := io.ReadFull(r, data[:]) return int16(binary.BigEndian.Uint16(data[:])), err } func readInt32(r nbt.DecoderReader) (int32, error) { var data [4]byte _, err := io.ReadFull(r, data[:]) return int32(binary.BigEndian.Uint32(data[:])), err } func readString(r nbt.DecoderReader) (string, error) { length, err := readInt16(r) if err != nil { return "", err } else if length < 0 { return "", errors.New("string length less than 0") } var str string if length > 0 { buf := make([]byte, length) _, err = io.ReadFull(r, buf) str = string(buf) } return str, err } type decodeErr struct { decoding string err error } func (d decodeErr) Error() string { return fmt.Sprintf("fail to decode tag %q: %v", d.decoding, d.err) }