make tagType witten early
This commit is contained in:
@ -2,6 +2,7 @@ package nbt
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -28,48 +29,43 @@ func writeValue(e *Encoder, d *decodeState, tagName string) error {
|
|||||||
default:
|
default:
|
||||||
panic(phasePanicMsg)
|
panic(phasePanicMsg)
|
||||||
case scanBeginLiteral:
|
case scanBeginLiteral:
|
||||||
return writeLiteral(e, d, tagName)
|
start := d.readIndex()
|
||||||
|
d.scanWhile(scanContinue)
|
||||||
|
literal := d.data[start:d.readIndex()]
|
||||||
|
tagType, litVal := parseLiteral(literal)
|
||||||
|
e.writeTag(tagType, tagName)
|
||||||
|
return writeLiteralPayload(e, litVal)
|
||||||
case scanBeginCompound:
|
case scanBeginCompound:
|
||||||
return writeCompound(e, d, tagName)
|
e.writeTag(TagCompound, tagName)
|
||||||
|
return writeCompoundPayload(e, d)
|
||||||
case scanBeginList:
|
case scanBeginList:
|
||||||
return writeListOrArray(e, d, tagName)
|
return writeListOrArray(e, d, tagName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeLiteral(e *Encoder, d *decodeState, tagName string) error {
|
func writeLiteralPayload(e *Encoder, v interface{}) error {
|
||||||
start := d.readIndex()
|
switch v.(type) {
|
||||||
d.scanWhile(scanContinue)
|
|
||||||
literal := d.data[start:d.readIndex()]
|
|
||||||
switch v := parseLiteral(literal); v.(type) {
|
|
||||||
case string:
|
case string:
|
||||||
str := v.(string)
|
str := v.(string)
|
||||||
e.writeTag(TagString, tagName)
|
|
||||||
e.writeInt16(int16(len(str)))
|
e.writeInt16(int16(len(str)))
|
||||||
e.w.Write([]byte(str))
|
e.w.Write([]byte(str))
|
||||||
case int8:
|
case int8:
|
||||||
e.writeTag(TagByte, tagName)
|
|
||||||
e.w.Write([]byte{byte(v.(int8))})
|
e.w.Write([]byte{byte(v.(int8))})
|
||||||
case int16:
|
case int16:
|
||||||
e.writeTag(TagShort, tagName)
|
|
||||||
e.writeInt16(v.(int16))
|
e.writeInt16(v.(int16))
|
||||||
case int32:
|
case int32:
|
||||||
e.writeTag(TagInt, tagName)
|
|
||||||
e.writeInt32(v.(int32))
|
e.writeInt32(v.(int32))
|
||||||
case int64:
|
case int64:
|
||||||
e.writeTag(TagLong, tagName)
|
|
||||||
e.writeInt64(v.(int64))
|
e.writeInt64(v.(int64))
|
||||||
case float32:
|
case float32:
|
||||||
e.writeTag(TagFloat, tagName)
|
|
||||||
e.writeInt32(int32(math.Float32bits(v.(float32))))
|
e.writeInt32(int32(math.Float32bits(v.(float32))))
|
||||||
case float64:
|
case float64:
|
||||||
e.writeTag(TagDouble, tagName)
|
|
||||||
e.writeInt64(int64(math.Float64bits(v.(float64))))
|
e.writeInt64(int64(math.Float64bits(v.(float64))))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeCompound(e *Encoder, d *decodeState, tagName string) error {
|
func writeCompoundPayload(e *Encoder, d *decodeState) error {
|
||||||
e.writeTag(TagCompound, tagName)
|
|
||||||
for {
|
for {
|
||||||
d.scanWhile(scanSkipSpace)
|
d.scanWhile(scanSkipSpace)
|
||||||
if d.opcode == scanEndValue {
|
if d.opcode == scanEndValue {
|
||||||
@ -114,6 +110,11 @@ func writeListOrArray(e *Encoder, d *decodeState, tagName string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We don't know the length of the List,
|
||||||
|
// so we read them into a buffer and count.
|
||||||
|
var buf bytes.Buffer
|
||||||
|
var count int
|
||||||
|
e2 := NewEncoder(&buf)
|
||||||
start := d.readIndex()
|
start := d.readIndex()
|
||||||
|
|
||||||
switch d.opcode {
|
switch d.opcode {
|
||||||
@ -127,27 +128,36 @@ func writeListOrArray(e *Encoder, d *decodeState, tagName string) error {
|
|||||||
if d.opcode != scanListValue { // TAG_List<TAG_String>
|
if d.opcode != scanListValue { // TAG_List<TAG_String>
|
||||||
panic(phasePanicMsg)
|
panic(phasePanicMsg)
|
||||||
}
|
}
|
||||||
// TODO
|
var tagType byte
|
||||||
parseLiteral(literal)
|
|
||||||
fallthrough
|
|
||||||
case scanBeginList: // TAG_List<TAG_List>
|
|
||||||
// We don't know the length of the List,
|
|
||||||
// so we read them into a buffer and count.
|
|
||||||
var buf bytes.Buffer
|
|
||||||
e2 := NewEncoder(&buf)
|
|
||||||
var count int
|
|
||||||
for {
|
for {
|
||||||
|
t, v := parseLiteral(literal)
|
||||||
|
if tagType == 0 {
|
||||||
|
tagType = t
|
||||||
|
}
|
||||||
|
if t != tagType {
|
||||||
|
return errors.New("different TagType in List")
|
||||||
|
}
|
||||||
|
writeLiteralPayload(e2, v)
|
||||||
|
count++
|
||||||
|
|
||||||
|
// read ',' or ']'
|
||||||
|
if d.opcode == scanSkipSpace {
|
||||||
d.scanWhile(scanSkipSpace)
|
d.scanWhile(scanSkipSpace)
|
||||||
|
}
|
||||||
if d.opcode == scanEndValue {
|
if d.opcode == scanEndValue {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if d.opcode == scanListValue {
|
if d.opcode != scanListValue {
|
||||||
// TODO
|
panic(phasePanicMsg)
|
||||||
e2.writeInt32(0)
|
|
||||||
}
|
}
|
||||||
|
start = d.readIndex()
|
||||||
|
d.scanNext()
|
||||||
|
d.scanWhile(scanContinue)
|
||||||
|
literal = d.data[start:d.readIndex()]
|
||||||
}
|
}
|
||||||
e.writeListHeader(TagList, tagName, count)
|
e.writeListHeader(tagType, tagName, count)
|
||||||
e.w.Write(buf.Bytes())
|
e.w.Write(buf.Bytes())
|
||||||
|
case scanBeginList: // TAG_List<TAG_List>
|
||||||
case scanBeginCompound: // TAG_List<TAG_Compound>
|
case scanBeginCompound: // TAG_List<TAG_Compound>
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -190,7 +200,7 @@ func (d *decodeState) scanWhile(op int) {
|
|||||||
// parseLiteral parse an SNBT literal, might be
|
// parseLiteral parse an SNBT literal, might be
|
||||||
// TAG_String, TAG_Int, TAG_Float, ... etc.
|
// TAG_String, TAG_Int, TAG_Float, ... etc.
|
||||||
// so returned value is one of string, int32, float32 ...
|
// so returned value is one of string, int32, float32 ...
|
||||||
func parseLiteral(literal []byte) interface{} {
|
func parseLiteral(literal []byte) (byte, interface{}) {
|
||||||
switch literal[0] {
|
switch literal[0] {
|
||||||
case '"', '\'': // Quoted String
|
case '"', '\'': // Quoted String
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
@ -199,7 +209,7 @@ func parseLiteral(literal []byte) interface{} {
|
|||||||
c := literal[i]
|
c := literal[i]
|
||||||
switch c {
|
switch c {
|
||||||
case literal[0]:
|
case literal[0]:
|
||||||
return sb.String()
|
return TagString, sb.String()
|
||||||
case '\\':
|
case '\\':
|
||||||
i++
|
i++
|
||||||
c = literal[i]
|
c = literal[i]
|
||||||
@ -243,17 +253,17 @@ func parseLiteral(literal []byte) interface{} {
|
|||||||
}
|
}
|
||||||
switch numberType {
|
switch numberType {
|
||||||
case 'B', 'b':
|
case 'B', 'b':
|
||||||
return int8(num)
|
return TagByte, int8(num)
|
||||||
case 'S', 's':
|
case 'S', 's':
|
||||||
return int16(num)
|
return TagShort, int16(num)
|
||||||
default:
|
default:
|
||||||
return int32(num)
|
return TagInt, int32(num)
|
||||||
case 'L', 'l':
|
case 'L', 'l':
|
||||||
return num
|
return TagLong, num
|
||||||
case 'F', 'f':
|
case 'F', 'f':
|
||||||
return float32(num)
|
return TagFloat, float32(num)
|
||||||
case 'D', 'd':
|
case 'D', 'd':
|
||||||
return float64(num)
|
return TagDouble, float64(num)
|
||||||
}
|
}
|
||||||
} else if number {
|
} else if number {
|
||||||
num, err := strconv.ParseFloat(string(literal[:strlen-1]), 64)
|
num, err := strconv.ParseFloat(string(literal[:strlen-1]), 64)
|
||||||
@ -262,14 +272,14 @@ func parseLiteral(literal []byte) interface{} {
|
|||||||
}
|
}
|
||||||
switch numberType {
|
switch numberType {
|
||||||
case 'F', 'f':
|
case 'F', 'f':
|
||||||
return float32(num)
|
return TagFloat, float32(num)
|
||||||
case 'D', 'd':
|
case 'D', 'd':
|
||||||
fallthrough
|
fallthrough
|
||||||
default:
|
default:
|
||||||
return num
|
return TagDouble, num
|
||||||
}
|
}
|
||||||
} else if unqstr {
|
} else if unqstr {
|
||||||
return string(literal)
|
return TagString, string(literal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic(phasePanicMsg)
|
panic(phasePanicMsg)
|
||||||
|
@ -8,9 +8,42 @@ import (
|
|||||||
func TestEncoder_WriteSNBT(t *testing.T) {
|
func TestEncoder_WriteSNBT(t *testing.T) {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
e := NewEncoder(&buf)
|
e := NewEncoder(&buf)
|
||||||
if err := e.WriteSNBT(`[1,2,3]`); err != nil {
|
testCases := []struct {
|
||||||
t.Fatal(err)
|
snbt string
|
||||||
}
|
nbt []byte
|
||||||
t.Log(buf.Bytes())
|
}{
|
||||||
|
{`10b`, []byte{1, 0, 0, 10}},
|
||||||
|
{`12S`, []byte{2, 0, 0, 0, 12}},
|
||||||
|
{`0`, []byte{3, 0, 0, 0, 0, 0, 0}},
|
||||||
|
{`12L`, []byte{4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12}},
|
||||||
|
|
||||||
|
{`""`, []byte{8, 0, 0, 0, 0}},
|
||||||
|
{`'""' `, []byte{8, 0, 0, 0, 2, '"', '"'}},
|
||||||
|
{`"ab\"c\""`, []byte{8, 0, 0, 0, 5, 'a', 'b', '"', 'c', '"'}},
|
||||||
|
{` "1\\23"`, []byte{8, 0, 0, 0, 4, '1', '\\', '2', '3'}},
|
||||||
|
|
||||||
|
{`{}`, []byte{10, 0, 0, 0}},
|
||||||
|
{`{a:1b}`, []byte{10, 0, 0, 1, 0, 1, 'a', 1, 0}},
|
||||||
|
{`{ a : 1b }`, []byte{10, 0, 0, 1, 0, 1, 'a', 1, 0}},
|
||||||
|
{`{a:1,2:c}`, []byte{10, 0, 0, 3, 0, 1, 'a', 0, 0, 0, 1, 8, 0, 1, '2', 0, 1, 'c', 0}},
|
||||||
|
{`{a:{b:{}}}`, []byte{10, 0, 0, 10, 0, 1, 'a', 10, 0, 1, 'b', 0, 0, 0}},
|
||||||
|
|
||||||
|
{`[]`, []byte{9, 0, 0, 0, 0, 0, 0, 0}},
|
||||||
|
{`[1b,2b,3b]`, []byte{9, 0, 0, 1, 0, 0, 0, 3, 1, 2, 3}},
|
||||||
|
{`[a,"b",'c']`, []byte{9, 0, 0, 8, 0, 0, 0, 3, 0, 1, 'a', 0, 1, 'b', 0, 1, 'c'}},
|
||||||
|
{`[{},{a:1b},{}]`, []byte{9, 0, 0, 10, 0, 0, 0, 3, 0, 1, 0, 1, 'a', 1, 0, 0}},
|
||||||
|
{`[[],[]]`, []byte{9, 0, 0, 9, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0}},
|
||||||
|
}
|
||||||
|
for i := range testCases {
|
||||||
|
buf.Reset()
|
||||||
|
if err := e.WriteSNBT(testCases[i].snbt); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
want := testCases[i].nbt
|
||||||
|
got := buf.Bytes()
|
||||||
|
if !bytes.Equal(want, got) {
|
||||||
|
t.Errorf("Convert SNBT %q wrong:\nwant: % 02X\ngot: % 02X", testCases[i].snbt, want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user