Files
go-mc/nbt/read.go

183 lines
3.6 KiB
Go

package nbt
import (
"bytes"
"errors"
"fmt"
"math"
"reflect"
)
func Unmarshal(data []byte, v interface{}) error {
return NewDecoder(bytes.NewReader(data)).Decode(v)
}
func (d *Decoder) Decode(v interface{}) error {
val := reflect.ValueOf(v)
if val.Kind() != reflect.Ptr {
return errors.New("non-pointer passed to Unmarshal")
}
tagType, tagName, err := d.readTag()
if err != nil {
return err
}
return d.unmarshal(val.Elem(), tagType, tagName)
}
func (d *Decoder) unmarshal(val reflect.Value, tagType byte, tagName string) error {
switch tagType {
default:
return fmt.Errorf("unknown Tag 0x%02x", tagType)
case TagFloat:
if vk := val.Kind(); vk != reflect.Float32 {
return errors.New("cannot parse TagString as " + vk.String())
}
vInt, err := d.readInt32()
if err != nil {
return err
}
val.Set(reflect.ValueOf(math.Float32frombits(uint32(vInt))))
case TagString:
if vk := val.Kind(); vk != reflect.String {
return errors.New("cannot parse TagString as " + vk.String())
}
s, err := d.readString()
if err != nil {
return err
}
val.SetString(s)
case TagCompound:
if vk := val.Kind(); vk != reflect.Struct {
return errors.New("cannot parse TagCompound as " + vk.String())
}
fmt.Println("TagName:", tagName)
tinfo := getTypeInfo(val.Type())
for {
tt, tn, err := d.readTag()
if err != nil {
return err
}
if tt == TagEnd {
break
}
field := tinfo.findIndexByName(tn)
if field != -1 {
err = d.unmarshal(val.Field(field), tt, tn)
if err != nil {
return err
}
} else {
if err := d.skip(tt); err != nil {
return err
}
}
}
}
return nil
}
func (d *Decoder) skip(tagType byte) error {
switch tagType {
default:
return fmt.Errorf("unknown to skip 0x%02x", tagType)
case TagByte:
_, err := d.r.ReadByte()
return err
case TagString:
_, err := d.readString()
return err
case TagShort:
_, err := d.readNByte(2)
return err
case TagInt, TagFloat:
_, err := d.readNByte(4)
return err
case TagLong, TagDouble:
_, err := d.readNByte(8)
return err
case TagByteArray:
aryLen, err := d.readInt32()
if err != nil {
return err
}
if _, err = d.readNByte(int(aryLen)); err != nil {
return err
}
case TagList:
listType, err := d.r.ReadByte()
if err != nil {
return err
}
listLen, err := d.readInt32()
if err != nil {
return err
}
for i := 0; i < int(listLen); i++ {
if err := d.skip(listType); err != nil {
return err
}
}
case TagCompound:
for {
tt, _, err := d.readTag()
if err != nil {
return err
}
if tt == TagEnd {
break
}
err = d.skip(tt)
if err != nil {
return err
}
}
}
return nil
}
func (d *Decoder) readTag() (tagType byte, tagName string, err error) {
tagType, err = d.r.ReadByte()
if err != nil {
return
}
if tagType != TagEnd && !d.nameless { //Read Tag
tagName, err = d.readString()
}
return
}
func (d *Decoder) readNByte(n int) (buf []byte, err error) {
buf = make([]byte, n)
_, err = d.r.Read(buf) //what happend if (returned n) != (argument n) ?
// for i := 0; i < n; i++ {
// buf[i], err = d.r.ReadByte()
// if err != nil {
// return
// }
// }
return
}
func (d *Decoder) readInt16() (int16, error) {
data, err := d.readNByte(2)
return int16(data[0])<<8 | int16(data[1]), err
}
func (d *Decoder) readInt32() (int32, error) {
data, err := d.readNByte(4)
return int32(data[0])<<24 | int32(data[1])<<16 |
int32(data[2])<<8 | int32(data[3]), err
}
func (d *Decoder) readString() (string, error) {
length, err := d.readInt16()
if err != nil {
return "", err
}
buf, err := d.readNByte(int(length))
return string(buf), err
}