diff --git a/nbt/nbt_test.go b/nbt/nbt_test.go index 3bf754e..6ca232a 100644 --- a/nbt/nbt_test.go +++ b/nbt/nbt_test.go @@ -3,6 +3,7 @@ package nbt import ( "bytes" "compress/gzip" + "reflect" "testing" ) @@ -129,6 +130,18 @@ func TestUnmarshal_bittest(t *testing.T) { Value float32 `nbt:"value"` } `nbt:"ham"` } `nbt:"nested compound test"` + IntTest int `nbt:"intTest"` + ByteTest byte `nbt:"byteTest"` + StringTest string `nbt:"stringTest"` + ListTest []int64 `nbt:"listTest (long)"` + DoubleTest float64 `nbt:"doubleTest"` + LongTest int64 `nbt:"longTest"` + ListTest2 [2]struct { + CreatedOn int64 `nbt:"created-on"` + Name string `nbt:"name"` + } `nbt:"listTest (compound)"` + ByteArrayTest []byte `nbt:"byteArrayTest (the first 1000 values of (n*n*255+n*7)%100, starting with n=0 (0, 62, 34, 16, 8, ...))"` + ShortTest int16 `nbt:"shortTest"` } //test parse @@ -146,11 +159,24 @@ func TestUnmarshal_bittest(t *testing.T) { want.NCT.Egg.Value = 0.5 want.NCT.Ham.Name = "Hampus" want.NCT.Ham.Value = 0.75 + want.IntTest = 2147483647 + want.ByteTest = 127 + want.StringTest = "HELLO WORLD THIS IS A TEST STRING \xc3\x85\xc3\x84\xc3\x96!" + want.ListTest = []int64{11, 12, 13, 14, 15} + want.DoubleTest = 0.49312871321823148 + want.LongTest = 9223372036854775807 + want.ListTest2[0].CreatedOn = 1264099775885 + want.ListTest2[0].Name = "Compound tag #0" + want.ListTest2[1].CreatedOn = 1264099775885 + want.ListTest2[1].Name = "Compound tag #1" + want.ByteArrayTest = make([]byte, 1000) + for n := 0; n < 1000; n++ { + want.ByteArrayTest[n] = byte((n*n*255 + n*7) % 100) + } + want.ShortTest = 32767 - if value != want { + if !reflect.DeepEqual(value, want) { t.Errorf("parse fail, expect %v, get %v", want, value) - } else { - t.Log("value:", value) } //test skip diff --git a/nbt/read.go b/nbt/read.go index 6af691b..f0b4810 100644 --- a/nbt/read.go +++ b/nbt/read.go @@ -28,9 +28,52 @@ func (d *Decoder) unmarshal(val reflect.Value, tagType byte, tagName string) err switch tagType { default: return fmt.Errorf("unknown Tag 0x%02x", tagType) + + case TagByte: + value, err := d.r.ReadByte() + if err != nil { + return err + } + switch vk := val.Kind(); vk { + default: + return errors.New("cannot parse TagByte as " + vk.String()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + val.SetInt(int64(value)) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + val.SetUint(uint64(value)) + } + + case TagShort: + value, err := d.readInt16() + if err != nil { + return err + } + switch vk := val.Kind(); vk { + default: + return errors.New("cannot parse TagShort as " + vk.String()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + val.SetInt(int64(value)) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + val.SetUint(uint64(value)) + } + + case TagInt: + value, err := d.readInt32() + if err != nil { + return err + } + switch vk := val.Kind(); vk { + default: + return errors.New("cannot parse TagInt as " + vk.String()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + val.SetInt(int64(value)) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + val.SetUint(uint64(value)) + } + case TagFloat: if vk := val.Kind(); vk != reflect.Float32 { - return errors.New("cannot parse TagString as " + vk.String()) + return errors.New("cannot parse TagFloat as " + vk.String()) } vInt, err := d.readInt32() if err != nil { @@ -38,6 +81,30 @@ func (d *Decoder) unmarshal(val reflect.Value, tagType byte, tagName string) err } val.Set(reflect.ValueOf(math.Float32frombits(uint32(vInt)))) + case TagLong: + value, err := d.readInt64() + if err != nil { + return err + } + switch vk := val.Kind(); vk { + default: + return errors.New("cannot parse TagLong as " + vk.String()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + val.SetInt(int64(value)) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + val.SetUint(uint64(value)) + } + + case TagDouble: + if vk := val.Kind(); vk != reflect.Float64 { + return errors.New("cannot parse TagDouble as " + vk.String()) + } + vInt, err := d.readInt64() + if err != nil { + return err + } + val.Set(reflect.ValueOf(math.Float64frombits(uint64(vInt)))) + case TagString: if vk := val.Kind(); vk != reflect.String { return errors.New("cannot parse TagString as " + vk.String()) @@ -47,11 +114,53 @@ func (d *Decoder) unmarshal(val reflect.Value, tagType byte, tagName string) err return err } val.SetString(s) + + case TagByteArray: + var ba []byte + if vt := val.Type(); vt != reflect.TypeOf(ba) { + return errors.New("cannot parse TagByteArray to " + vt.String() + ", use []byte in this instance") + } + aryLen, err := d.readInt32() + if err != nil { + return err + } + if ba, err = d.readNByte(int(aryLen)); err != nil { + return err + } + val.SetBytes(ba) + + case TagList: + listType, err := d.r.ReadByte() + if err != nil { + return err + } + listLen, err := d.readInt32() + if err != nil { + return err + } + // If we need parse TAG_List into slice, make a new with right length. + // Otherwise if we need parse into array, we check if len(array) are enough. + switch vk := val.Kind(); vk { + default: + return errors.New("cannot parse TagList as " + vk.String()) + case reflect.Slice: + val.Set(reflect.MakeSlice(val.Type(), int(listLen), int(listLen))) + case reflect.Array: + if vl := val.Len(); vl < int(listLen) { + return fmt.Errorf( + "TagList %s has len %d, but array %v only has len %d", + tagName, listLen, val.Type(), vl) + } + } + for i := 0; i < int(listLen); i++ { + if err := d.unmarshal(val.Index(i), listType, ""); err != nil { + return err + } + } 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() @@ -152,12 +261,6 @@ func (d *Decoder) readTag() (tagType byte, tagName string, err error) { 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 } @@ -172,6 +275,14 @@ func (d *Decoder) readInt32() (int32, error) { int32(data[2])<<8 | int32(data[3]), err } +func (d *Decoder) readInt64() (int64, error) { + data, err := d.readNByte(8) + return int64(data[0])<<56 | int64(data[1])<<48 | + int64(data[2])<<40 | int64(data[3])<<32 | + int64(data[4])<<24 | int64(data[5])<<16 | + int64(data[6])<<8 | int64(data[7]), err +} + func (d *Decoder) readString() (string, error) { length, err := d.readInt16() if err != nil {