implement old NBT format.
TODO: TAG_Int_Array and TAG_Long_Array
This commit is contained in:
@ -3,6 +3,7 @@ package nbt
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -129,6 +130,18 @@ func TestUnmarshal_bittest(t *testing.T) {
|
|||||||
Value float32 `nbt:"value"`
|
Value float32 `nbt:"value"`
|
||||||
} `nbt:"ham"`
|
} `nbt:"ham"`
|
||||||
} `nbt:"nested compound test"`
|
} `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
|
//test parse
|
||||||
@ -146,11 +159,24 @@ func TestUnmarshal_bittest(t *testing.T) {
|
|||||||
want.NCT.Egg.Value = 0.5
|
want.NCT.Egg.Value = 0.5
|
||||||
want.NCT.Ham.Name = "Hampus"
|
want.NCT.Ham.Name = "Hampus"
|
||||||
want.NCT.Ham.Value = 0.75
|
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)
|
t.Errorf("parse fail, expect %v, get %v", want, value)
|
||||||
} else {
|
|
||||||
t.Log("value:", value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//test skip
|
//test skip
|
||||||
|
127
nbt/read.go
127
nbt/read.go
@ -28,9 +28,52 @@ func (d *Decoder) unmarshal(val reflect.Value, tagType byte, tagName string) err
|
|||||||
switch tagType {
|
switch tagType {
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unknown Tag 0x%02x", tagType)
|
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:
|
case TagFloat:
|
||||||
if vk := val.Kind(); vk != reflect.Float32 {
|
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()
|
vInt, err := d.readInt32()
|
||||||
if err != nil {
|
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))))
|
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:
|
case TagString:
|
||||||
if vk := val.Kind(); vk != reflect.String {
|
if vk := val.Kind(); vk != reflect.String {
|
||||||
return errors.New("cannot parse TagString as " + vk.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
|
return err
|
||||||
}
|
}
|
||||||
val.SetString(s)
|
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:
|
case TagCompound:
|
||||||
if vk := val.Kind(); vk != reflect.Struct {
|
if vk := val.Kind(); vk != reflect.Struct {
|
||||||
return errors.New("cannot parse TagCompound as " + vk.String())
|
return errors.New("cannot parse TagCompound as " + vk.String())
|
||||||
}
|
}
|
||||||
fmt.Println("TagName:", tagName)
|
|
||||||
tinfo := getTypeInfo(val.Type())
|
tinfo := getTypeInfo(val.Type())
|
||||||
for {
|
for {
|
||||||
tt, tn, err := d.readTag()
|
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) {
|
func (d *Decoder) readNByte(n int) (buf []byte, err error) {
|
||||||
buf = make([]byte, n)
|
buf = make([]byte, n)
|
||||||
_, err = d.r.Read(buf) //what happend if (returned n) != (argument 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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,6 +275,14 @@ func (d *Decoder) readInt32() (int32, error) {
|
|||||||
int32(data[2])<<8 | int32(data[3]), err
|
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) {
|
func (d *Decoder) readString() (string, error) {
|
||||||
length, err := d.readInt16()
|
length, err := d.readInt16()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Reference in New Issue
Block a user