diff --git a/nbt/nbt.go b/nbt/nbt.go new file mode 100644 index 0000000..8dec487 --- /dev/null +++ b/nbt/nbt.go @@ -0,0 +1,44 @@ +package nbt + +import ( + "bufio" + "io" +) + +//Tag type IDs +const ( + TagEnd byte = iota + TagByte + TagShort + TagInt + TagLong + TagFloat + TagDouble + TagByteArray + TagString + TagList + TagCompound + TagIntArray + TagLongArray +) + +type Decoder struct { + r interface { + io.ByteReader + io.Reader + } + nameless bool +} + +func NewDecoder(r io.Reader) *Decoder { + d := new(Decoder) + if br, ok := r.(interface { + io.ByteReader + io.Reader + }); ok { + d.r = br + } else { + d.r = bufio.NewReader(r) + } + return d +} diff --git a/nbt/nbt_test.go b/nbt/nbt_test.go new file mode 100644 index 0000000..36982b8 --- /dev/null +++ b/nbt/nbt_test.go @@ -0,0 +1,42 @@ +package nbt + +import "testing" + +func TestUnmarshal_simple(t *testing.T) { + var data = []byte{ + 0x0a, 0x00, 0x0b, 0x68, 0x65, 0x6c, 0x6c, 0x6f, + 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x08, 0x00, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x00, 0x09, 0x42, + 0x61, 0x6e, 0x61, 0x6e, 0x72, 0x61, 0x6d, 0x61, + 0x00, + } + + var value struct { + Name string `nbt:"name"` + } + + if err := Unmarshal(data, &value); err != nil { + t.Fatal(err) + } + + if value.Name != "Bananrama" { + t.Errorf("Unmarshal NBT fail: get %q, want %q", value.Name, "Bananrama") + } +} + +func TestUnmarshal_string(t *testing.T) { + var data = []byte{ + 0x08, 0x00, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x00, 0x09, + 0x42, 0x61, 0x6e, 0x61, 0x6e, 0x72, 0x61, 0x6d, 0x61, + } + + var Name string + + if err := Unmarshal(data, &Name); err != nil { + t.Fatal(err) + } + + if Name != "Bananrama" { + t.Errorf("Unmarshal NBT fail: get %q, want %q", Name, "Bananrama") + } +} diff --git a/nbt/read.go b/nbt/read.go new file mode 100644 index 0000000..051dcf4 --- /dev/null +++ b/nbt/read.go @@ -0,0 +1,81 @@ +package nbt + +import ( + "bytes" + "errors" + "fmt" + "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") + } + return d.unmarshal(val.Elem()) +} + +// func (d *Decoder) unmarshalInt(val reflect.Value) error { + +// } + +func (d *Decoder) unmarshal(val reflect.Value) error { + tagType, err := d.r.ReadByte() + if err != nil { + return err + } + + var tagName string + if !d.nameless { //Read Tag + if tagName, err = d.readString(); err != nil { + return err + } + } + + switch tagType { + default: + return fmt.Errorf("unknown tag 0x%2x", tagType) + case TagString: + if val.Kind() != reflect.String { + return errors.New("cannot unmarshal TAG_String into " + val.Kind().String()) + } + + s, err := d.readString() + if err != nil { + return err + } + + val.SetString(s) + case TagCompound: + if val.Kind() != reflect.Struct { + return errors.New("cannot unmarshal TAG_Compound into " + val.Kind().String()) + } + fmt.Println("TagName:", tagName) + } + + return nil +} + +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) ? + return +} + +func (d *Decoder) readInt16() (int16, error) { + data, err := d.readNByte(2) + return int16(data[0])<<4 | int16(data[1]), 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 +} diff --git a/nbt/typeinfo.go b/nbt/typeinfo.go new file mode 100644 index 0000000..23885bf --- /dev/null +++ b/nbt/typeinfo.go @@ -0,0 +1,22 @@ +package nbt + +import ( + "reflect" +) + +type typeInfo struct { +} + +func getTypeInfo(typ reflect.Type) (*typeInfo, error) { + tinfo := new(typeInfo) + if typ.Kind() == reflect.Struct { + n := typ.NumField() + for i := 0; i < n; i++ { + f := typ.Field(i) + if (f.PkgPath != "" && !f.Anonymous) || f.Tag.Get("nbt") == "-" { + continue // Private field + } + } + } + return tinfo, nil +}