support unmarshal to interface{} .no TagCompound

This commit is contained in:
Tnze
2019-06-10 16:32:12 +08:00
parent 0a094cf956
commit be1a95c27e
2 changed files with 154 additions and 47 deletions

View File

@ -13,8 +13,8 @@ func TestUnmarshal_string(t *testing.T) {
0x42, 0x61, 0x6e, 0x61, 0x6e, 0x72, 0x61, 0x6d, 0x61, 0x42, 0x61, 0x6e, 0x61, 0x6e, 0x72, 0x61, 0x6d, 0x61,
} }
//Unmarshal to string
var Name string var Name string
if err := Unmarshal(data, &Name); err != nil { if err := Unmarshal(data, &Name); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -22,6 +22,16 @@ func TestUnmarshal_string(t *testing.T) {
if Name != "Bananrama" { if Name != "Bananrama" {
t.Errorf("Unmarshal NBT fail: get %q, want %q", Name, "Bananrama") t.Errorf("Unmarshal NBT fail: get %q, want %q", Name, "Bananrama")
} }
//Unmarshal to interface{}
var infName interface{}
if err := Unmarshal(data, &infName); err != nil {
t.Fatal(err)
}
if infName != "Bananrama" {
t.Errorf("Unmarshal NBT fail: get %q, want %q", Name, "Bananrama")
}
} }
func TestUnmarshal_simple(t *testing.T) { func TestUnmarshal_simple(t *testing.T) {
var data = []byte{ var data = []byte{
@ -188,6 +198,17 @@ func TestUnmarshal_bittest(t *testing.T) {
if err := NewDecoder(r).Decode(&empty); err != nil { if err := NewDecoder(r).Decode(&empty); err != nil {
t.Fatal(err) t.Fatal(err)
} }
//test unmarshal to interface{}
var inf interface{}
r, err = gzip.NewReader(bytes.NewReader(data))
if err != nil {
t.Fatal(err)
}
if err := NewDecoder(r).Decode(&inf); err != nil {
t.Fatal(err)
}
t.Log(inf)
} }
func TestUnmarshal_IntArray(t *testing.T) { func TestUnmarshal_IntArray(t *testing.T) {
@ -234,8 +255,9 @@ func TestUnmarshal_LongArray(t *testing.T) {
0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3,
} }
var ( var (
value []int64 value []int64
want = []int64{1, 2, 3} infValue interface{}
want = []int64{1, 2, 3}
) )
if err := Unmarshal(data, &value); err != nil { if err := Unmarshal(data, &value); err != nil {
@ -244,6 +266,43 @@ func TestUnmarshal_LongArray(t *testing.T) {
if !reflect.DeepEqual(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)
} }
// t.Log(value)
t.Log(value) if err := Unmarshal(data, &infValue); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(infValue, want) {
t.Errorf("parse fail, expect %v, get %v", want, infValue)
}
// t.Log(infValue)
}
func TestUnmarshal_ByteArray(t *testing.T) {
data := []byte{
TagByteArray, 0, 0,
0, 0, 0, 7,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
}
var (
value []byte
infValue interface{}
want = []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}
)
//Unmarshal to []byte
if err := Unmarshal(data, &value); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(value, want) {
t.Errorf("parse fail, expect %v, get %v", want, value)
}
// t.Log(value)
//Unmarshal to interface{}
if err := Unmarshal(data, &infValue); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(infValue, want) {
t.Errorf("parse fail, expect %v, get %v", want, value)
}
// t.Log(infValue)
} }

View File

@ -46,6 +46,8 @@ func (d *Decoder) unmarshal(val reflect.Value, tagType byte, tagName string) err
val.SetInt(int64(value)) val.SetInt(int64(value))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
val.SetUint(uint64(value)) val.SetUint(uint64(value))
case reflect.Interface:
val.Set(reflect.ValueOf(value))
} }
case TagShort: case TagShort:
@ -60,6 +62,8 @@ func (d *Decoder) unmarshal(val reflect.Value, tagType byte, tagName string) err
val.SetInt(int64(value)) val.SetInt(int64(value))
case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64: case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
val.SetUint(uint64(value)) val.SetUint(uint64(value))
case reflect.Interface:
val.Set(reflect.ValueOf(value))
} }
case TagInt: case TagInt:
@ -74,17 +78,24 @@ func (d *Decoder) unmarshal(val reflect.Value, tagType byte, tagName string) err
val.SetInt(int64(value)) val.SetInt(int64(value))
case reflect.Uint, reflect.Uint32, reflect.Uint64: case reflect.Uint, reflect.Uint32, reflect.Uint64:
val.SetUint(uint64(value)) val.SetUint(uint64(value))
case reflect.Interface:
val.Set(reflect.ValueOf(value))
} }
case TagFloat: case TagFloat:
if vk := val.Kind(); vk != reflect.Float32 {
return errors.New("cannot parse TagFloat as " + vk.String())
}
vInt, err := d.readInt32() vInt, err := d.readInt32()
if err != nil { if err != nil {
return err return err
} }
val.Set(reflect.ValueOf(math.Float32frombits(uint32(vInt)))) value := math.Float32frombits(uint32(vInt))
switch vk := val.Kind(); vk {
default:
return errors.New("cannot parse TagFloat as " + vk.String())
case reflect.Float32:
val.Set(reflect.ValueOf(value))
case reflect.Float64:
val.Set(reflect.ValueOf(float64(value)))
}
case TagLong: case TagLong:
value, err := d.readInt64() value, err := d.readInt64()
@ -98,33 +109,42 @@ func (d *Decoder) unmarshal(val reflect.Value, tagType byte, tagName string) err
val.SetInt(int64(value)) val.SetInt(int64(value))
case reflect.Uint, reflect.Uint64: case reflect.Uint, reflect.Uint64:
val.SetUint(uint64(value)) val.SetUint(uint64(value))
case reflect.Interface:
val.Set(reflect.ValueOf(value))
} }
case TagDouble: case TagDouble:
if vk := val.Kind(); vk != reflect.Float64 {
return errors.New("cannot parse TagDouble as " + vk.String())
}
vInt, err := d.readInt64() vInt, err := d.readInt64()
if err != nil { if err != nil {
return err return err
} }
val.Set(reflect.ValueOf(math.Float64frombits(uint64(vInt)))) value := math.Float64frombits(uint64(vInt))
switch vk := val.Kind(); vk {
default:
return errors.New("cannot parse TagDouble as " + vk.String())
case reflect.Float64:
val.Set(reflect.ValueOf(value))
case reflect.Interface:
val.Set(reflect.ValueOf(value))
}
case TagString: case TagString:
if vk := val.Kind(); vk != reflect.String {
return errors.New("cannot parse TagString as " + vk.String())
}
s, err := d.readString() s, err := d.readString()
if err != nil { if err != nil {
return err return err
} }
val.SetString(s) switch vk := val.Kind(); vk {
default:
return errors.New("cannot parse TagString as " + vk.String())
case reflect.String:
val.SetString(s)
case reflect.Interface:
val.Set(reflect.ValueOf(s))
}
case TagByteArray: case TagByteArray:
var ba []byte 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() aryLen, err := d.readInt32()
if err != nil { if err != nil {
return err return err
@ -132,7 +152,15 @@ func (d *Decoder) unmarshal(val reflect.Value, tagType byte, tagName string) err
if ba, err = d.readNByte(int(aryLen)); err != nil { if ba, err = d.readNByte(int(aryLen)); err != nil {
return err return err
} }
val.SetBytes(ba)
switch vt := val.Type(); {
default:
return errors.New("cannot parse TagByteArray to " + vt.String() + ", use []byte in this instance")
case vt == reflect.TypeOf(ba):
val.SetBytes(ba)
case vt.Kind() == reflect.Interface:
val.Set(reflect.ValueOf(ba))
}
case TagIntArray: case TagIntArray:
aryLen, err := d.readInt32() aryLen, err := d.readInt32()
@ -140,20 +168,23 @@ func (d *Decoder) unmarshal(val reflect.Value, tagType byte, tagName string) err
return err return err
} }
vt := val.Type() //reciver must be []int or []int32 vt := val.Type() //reciver must be []int or []int32
if vt.Kind() != reflect.Slice { if vt.Kind() == reflect.Interface {
vt = reflect.TypeOf([]int32{}) // pass
} else if vt.Kind() != reflect.Slice {
return errors.New("cannot parse TagIntArray to " + vt.String() + ", it must be a slice") return errors.New("cannot parse TagIntArray to " + vt.String() + ", it must be a slice")
} else if tk := val.Type().Elem().Kind(); tk != reflect.Int && tk != reflect.Int32 { } else if tk := val.Type().Elem().Kind(); tk != reflect.Int && tk != reflect.Int32 {
return errors.New("cannot parse TagIntArray to " + vt.String()) return errors.New("cannot parse TagIntArray to " + vt.String())
} }
val.Set(reflect.MakeSlice(vt, int(aryLen), int(aryLen))) buf := reflect.MakeSlice(vt, int(aryLen), int(aryLen))
for i := 0; i < int(aryLen); i++ { for i := 0; i < int(aryLen); i++ {
value, err := d.readInt32() value, err := d.readInt32()
if err != nil { if err != nil {
return err return err
} }
val.Index(i).SetInt(int64(value)) buf.Index(i).SetInt(int64(value))
} }
val.Set(buf)
case TagLongArray: case TagLongArray:
aryLen, err := d.readInt32() aryLen, err := d.readInt32()
@ -161,20 +192,23 @@ func (d *Decoder) unmarshal(val reflect.Value, tagType byte, tagName string) err
return err return err
} }
vt := val.Type() //reciver must be []int or []int64 vt := val.Type() //reciver must be []int or []int64
if vt.Kind() != reflect.Slice { if vt.Kind() == reflect.Interface {
vt = reflect.TypeOf([]int64{}) // pass
} else if vt.Kind() != reflect.Slice {
return errors.New("cannot parse TagIntArray to " + vt.String() + ", it must be a slice") return errors.New("cannot parse TagIntArray to " + vt.String() + ", it must be a slice")
} else if val.Type().Elem().Kind() != reflect.Int64 { } else if val.Type().Elem().Kind() != reflect.Int64 {
return errors.New("cannot parse TagIntArray to " + vt.String()) return errors.New("cannot parse TagIntArray to " + vt.String())
} }
val.Set(reflect.MakeSlice(vt, int(aryLen), int(aryLen))) buf := reflect.MakeSlice(vt, int(aryLen), int(aryLen))
for i := 0; i < int(aryLen); i++ { for i := 0; i < int(aryLen); i++ {
value, err := d.readInt64() value, err := d.readInt64()
if err != nil { if err != nil {
return err return err
} }
val.Index(i).SetInt(value) buf.Index(i).SetInt(value)
} }
val.Set(buf)
case TagList: case TagList:
listType, err := d.r.ReadByte() listType, err := d.r.ReadByte()
@ -185,50 +219,64 @@ func (d *Decoder) unmarshal(val reflect.Value, tagType byte, tagName string) err
if err != nil { if err != nil {
return err return err
} }
// If we need parse TAG_List into slice, make a new with right length. // 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. // Otherwise if we need parse into array, we check if len(array) are enough.
switch vk := val.Kind(); vk { var buf reflect.Value
vk := val.Kind()
switch vk {
default: default:
return errors.New("cannot parse TagList as " + vk.String()) return errors.New("cannot parse TagList as " + vk.String())
case reflect.Interface:
fallthrough
case reflect.Slice: case reflect.Slice:
val.Set(reflect.MakeSlice(val.Type(), int(listLen), int(listLen))) buf = reflect.MakeSlice(val.Type(), int(listLen), int(listLen))
case reflect.Array: case reflect.Array:
if vl := val.Len(); vl < int(listLen) { if vl := val.Len(); vl < int(listLen) {
return fmt.Errorf( return fmt.Errorf(
"TagList %s has len %d, but array %v only has len %d", "TagList %s has len %d, but array %v only has len %d",
tagName, listLen, val.Type(), vl) tagName, listLen, val.Type(), vl)
} }
buf = val
} }
for i := 0; i < int(listLen); i++ { for i := 0; i < int(listLen); i++ {
if err := d.unmarshal(val.Index(i), listType, ""); err != nil { if err := d.unmarshal(buf.Index(i), listType, ""); err != nil {
return err return err
} }
} }
case TagCompound: if val.Kind() != reflect.Array {
if vk := val.Kind(); vk != reflect.Struct { val.Set(buf)
return errors.New("cannot parse TagCompound as " + vk.String())
} }
tinfo := getTypeInfo(val.Type())
for { case TagCompound:
tt, tn, err := d.readTag() switch vk := val.Kind(); vk {
if err != nil { default:
return err return errors.New("cannot parse TagCompound as " + vk.String())
} case reflect.Struct:
if tt == TagEnd { tinfo := getTypeInfo(val.Type())
break for {
} tt, tn, err := d.readTag()
field := tinfo.findIndexByName(tn)
if field != -1 {
err = d.unmarshal(val.Field(field), tt, tn)
if err != nil { if err != nil {
return err return err
} }
} else { if tt == TagEnd {
if err := d.skip(tt); err != nil { break
return err }
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
}
} }
} }
case reflect.Interface:
} }
} }