Marshal without test and TagList
This commit is contained in:
39
nbt/example_test.go
Normal file
39
nbt/example_test.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package nbt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleUnmarshal() {
|
||||||
|
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 {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(Name)
|
||||||
|
|
||||||
|
// Output: Bananrama
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleMarshal() {
|
||||||
|
var value = struct {
|
||||||
|
Name string `nbt:"name"`
|
||||||
|
}{"Tnze"}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := Marshal(&buf, value); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("% 02x ", buf.Bytes())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0a 00 00 08 00 00 00 04 54 6e 7a 65 00
|
||||||
|
}
|
184
nbt/marshal.go
Normal file
184
nbt/marshal.go
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
package nbt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Marshal(w io.Writer, v interface{}) error {
|
||||||
|
return NewEncoder(w).Encode(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Encoder struct {
|
||||||
|
w io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEncoder(w io.Writer) *Encoder {
|
||||||
|
return &Encoder{w: w}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) Encode(v interface{}) error {
|
||||||
|
val := reflect.ValueOf(v)
|
||||||
|
return e.marshal(val, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) marshal(val reflect.Value, tagName string) error {
|
||||||
|
switch vk := val.Kind(); vk {
|
||||||
|
default:
|
||||||
|
return errors.New("unknown type " + vk.String())
|
||||||
|
|
||||||
|
case reflect.Uint8:
|
||||||
|
if err := e.writeTag(TagByte, tagName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err := e.w.Write([]byte{byte(val.Uint())})
|
||||||
|
return err
|
||||||
|
|
||||||
|
case reflect.Int16, reflect.Uint16:
|
||||||
|
if err := e.writeTag(TagShort, tagName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return e.writeInt16(int16(val.Int()))
|
||||||
|
|
||||||
|
case reflect.Int32, reflect.Uint32:
|
||||||
|
if err := e.writeTag(TagInt, tagName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return e.writeInt32(int32(val.Int()))
|
||||||
|
|
||||||
|
case reflect.Float32:
|
||||||
|
if err := e.writeTag(TagFloat, tagName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return e.writeInt32(int32(math.Float32bits(float32(val.Float()))))
|
||||||
|
|
||||||
|
case reflect.Int64, reflect.Uint64:
|
||||||
|
if err := e.writeTag(TagLong, tagName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return e.writeInt64(int64(val.Int()))
|
||||||
|
|
||||||
|
case reflect.Float64:
|
||||||
|
if err := e.writeTag(TagDouble, tagName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return e.writeInt64(int64(math.Float64bits(val.Float())))
|
||||||
|
|
||||||
|
case reflect.Array, reflect.Slice:
|
||||||
|
switch val.Type().Elem().Kind() {
|
||||||
|
case reflect.Uint8: // []byte
|
||||||
|
if err := e.writeTag(TagByteArray, tagName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := e.writeInt32(int32(val.Len())); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err := e.w.Write(val.Bytes())
|
||||||
|
return err
|
||||||
|
|
||||||
|
case reflect.Int32:
|
||||||
|
if err := e.writeTag(TagIntArray, tagName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
n := val.Len()
|
||||||
|
if err := e.writeInt32(int32(n)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
if err := e.writeInt32(int32(val.Index(i).Int())); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Int64:
|
||||||
|
if err := e.writeTag(TagLongArray, tagName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
n := val.Len()
|
||||||
|
if err := e.writeInt32(int32(n)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
if err := e.writeInt64(val.Index(i).Int()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return errors.New("unknow type " + val.Type().String() + " slice")
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.String:
|
||||||
|
if err := e.writeTag(TagString, tagName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := e.writeInt16(int16(val.Len())); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err := e.w.Write([]byte(val.String()))
|
||||||
|
return err
|
||||||
|
|
||||||
|
case reflect.Struct:
|
||||||
|
if err := e.writeTag(TagCompound, ""); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
n := val.NumField()
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
f := val.Type().Field(i)
|
||||||
|
tag := f.Tag.Get("nbt")
|
||||||
|
if (f.PkgPath != "" && !f.Anonymous) || tag == "-" {
|
||||||
|
continue // Private field
|
||||||
|
}
|
||||||
|
|
||||||
|
tagName := f.Name
|
||||||
|
if tag != "" {
|
||||||
|
tagName = tag
|
||||||
|
}
|
||||||
|
|
||||||
|
err := e.marshal(val.Field(i), tagName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, err := e.w.Write([]byte{TagEnd})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) writeTag(tagType byte, tagName string) error {
|
||||||
|
if _, err := e.w.Write([]byte{tagType}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
bName := []byte(tagName)
|
||||||
|
if err := e.writeInt16(int16(len(bName))); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err := e.w.Write(bName)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) writeNamelessTag(tagType byte, tagName string) error {
|
||||||
|
_, err := e.w.Write([]byte{tagType})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) writeInt16(n int16) error {
|
||||||
|
e.w.Write([]byte{byte(n >> 8), byte(n)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) writeInt32(n int32) error {
|
||||||
|
e.w.Write([]byte{byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) writeInt64(n int64) error {
|
||||||
|
e.w.Write([]byte{
|
||||||
|
byte(n >> 56), byte(n >> 48), byte(n >> 40), byte(n >> 32),
|
||||||
|
byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n)})
|
||||||
|
return nil
|
||||||
|
}
|
35
nbt/marshal_test.go
Normal file
35
nbt/marshal_test.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package nbt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMarshal(t *testing.T) {
|
||||||
|
var (
|
||||||
|
want = []byte{
|
||||||
|
0x0A, 0, 0,
|
||||||
|
0x08, 0, 4, 0x4e, 0x61, 0x6d, 0x65, 0, 4, 0x54, 0x6e, 0x7a, 0x65,
|
||||||
|
0x01, 0x00, 0x08, 0x42, 0x79, 0x74, 0x65, 0x54, 0x65, 0x73, 0x74, 0xFF,
|
||||||
|
|
||||||
|
0,
|
||||||
|
}
|
||||||
|
value struct {
|
||||||
|
Name string
|
||||||
|
ByteTest byte
|
||||||
|
}
|
||||||
|
)
|
||||||
|
value.Name = "Tnze"
|
||||||
|
value.ByteTest = 0xFF
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := Marshal(&buf, value); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
gets := buf.Bytes()
|
||||||
|
if !reflect.DeepEqual(gets, want) {
|
||||||
|
t.Errorf("marshal wrong: get [% 02x], want [% 02x]", gets, want)
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
// Package nbt implement the Named Binary Tag format of Minecraft.
|
||||||
|
// It provides api like encoding/xml package.
|
||||||
package nbt
|
package nbt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
Reference in New Issue
Block a user