Now we can Decode/Encode StringifiedMessage
This commit is contained in:
201
nbt/snbt.go
201
nbt/snbt.go
@ -1,11 +1,17 @@
|
||||
package nbt
|
||||
|
||||
import "io"
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type StringifiedNBT string
|
||||
type StringifiedMessage string
|
||||
|
||||
func (n StringifiedNBT) TagType() (tagType byte) {
|
||||
d := decodeState{data: []byte(n)}
|
||||
func (m StringifiedMessage) TagType() (tagType byte) {
|
||||
d := decodeState{data: []byte(m)}
|
||||
d.scan.reset()
|
||||
d.scanWhile(scanSkipSpace)
|
||||
switch d.opcode {
|
||||
@ -48,11 +54,188 @@ func (n StringifiedNBT) TagType() (tagType byte) {
|
||||
return
|
||||
}
|
||||
|
||||
func (n StringifiedNBT) Encode(w io.Writer) error {
|
||||
d := decodeState{data: []byte(n)}
|
||||
func (m StringifiedMessage) Encode(w io.Writer) error {
|
||||
d := decodeState{data: []byte(m)}
|
||||
d.scan.reset()
|
||||
return writeValue(NewEncoder(w), &d, "")
|
||||
return writeValue(NewEncoder(w), &d, false, "")
|
||||
}
|
||||
|
||||
//func (n *StringifiedNBT) Decode(tagType byte, r DecoderReader) error {
|
||||
//}
|
||||
func (m *StringifiedMessage) Decode(tagType byte, r DecoderReader) error {
|
||||
if tagType == TagEnd {
|
||||
return ErrEND
|
||||
}
|
||||
var sb strings.Builder
|
||||
d := NewDecoder(r)
|
||||
err := m.encode(d, &sb, tagType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*m = StringifiedMessage(sb.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *StringifiedMessage) encode(d *Decoder, sb *strings.Builder, tagType byte) error {
|
||||
switch tagType {
|
||||
default:
|
||||
return fmt.Errorf("unknown to read 0x%02x", tagType)
|
||||
case TagByte:
|
||||
b, err := d.r.ReadByte()
|
||||
sb.WriteString(strconv.FormatInt(int64(b), 10) + "B")
|
||||
return err
|
||||
case TagString:
|
||||
str, err := d.readString()
|
||||
writeEscapeStr(sb, str)
|
||||
return err
|
||||
case TagShort:
|
||||
s, err := d.readInt16()
|
||||
sb.WriteString(strconv.FormatInt(int64(s), 10) + "S")
|
||||
return err
|
||||
case TagInt:
|
||||
i, err := d.readInt32()
|
||||
sb.WriteString(strconv.FormatInt(int64(i), 10) + "I")
|
||||
return err
|
||||
case TagFloat:
|
||||
i, err := d.readInt32()
|
||||
f := float64(math.Float32frombits(uint32(i)))
|
||||
sb.WriteString(strconv.FormatFloat(f, 'f', 10, 32) + "F")
|
||||
return err
|
||||
case TagLong:
|
||||
i, err := d.readInt64()
|
||||
sb.WriteString(strconv.FormatInt(i, 10) + "L")
|
||||
return err
|
||||
case TagDouble:
|
||||
i, err := d.readInt64()
|
||||
f := math.Float64frombits(uint64(i))
|
||||
sb.WriteString(strconv.FormatFloat(f, 'f', 10, 64) + "D")
|
||||
return err
|
||||
case TagByteArray:
|
||||
aryLen, err := d.readInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
first := true
|
||||
sb.WriteString("[B;")
|
||||
for i := int32(0); i < aryLen; i++ {
|
||||
b, err := d.r.ReadByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if first {
|
||||
first = false
|
||||
} else {
|
||||
sb.WriteString(",")
|
||||
}
|
||||
sb.WriteString(strconv.FormatInt(int64(b), 10) + "B")
|
||||
}
|
||||
sb.WriteString("]")
|
||||
case TagIntArray:
|
||||
aryLen, err := d.readInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sb.WriteString("[I;")
|
||||
first := true
|
||||
for i := 0; i < int(aryLen); i++ {
|
||||
v, err := d.readInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if first {
|
||||
first = false
|
||||
} else {
|
||||
sb.WriteString(",")
|
||||
}
|
||||
sb.WriteString(strconv.FormatInt(int64(v), 10) + "I")
|
||||
}
|
||||
sb.WriteString("]")
|
||||
case TagLongArray:
|
||||
aryLen, err := d.readInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
first := true
|
||||
sb.WriteString("[L;")
|
||||
for i := 0; i < int(aryLen); i++ {
|
||||
v, err := d.readInt64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if first {
|
||||
first = false
|
||||
} else {
|
||||
sb.WriteString(",")
|
||||
}
|
||||
sb.WriteString(strconv.FormatInt(v, 10) + "L")
|
||||
}
|
||||
sb.WriteString("]")
|
||||
case TagList:
|
||||
listType, err := d.r.ReadByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
listLen, err := d.readInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
first := true
|
||||
sb.WriteString("[")
|
||||
for i := 0; i < int(listLen); i++ {
|
||||
if first {
|
||||
first = false
|
||||
} else {
|
||||
sb.WriteString(",")
|
||||
}
|
||||
if err := m.encode(d, sb, listType); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
sb.WriteString("]")
|
||||
case TagCompound:
|
||||
first := true
|
||||
for {
|
||||
tt, tn, err := d.readTag()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if first {
|
||||
sb.WriteString("{")
|
||||
first = false
|
||||
} else if tt != TagEnd {
|
||||
sb.WriteString(",")
|
||||
}
|
||||
if tt == TagEnd {
|
||||
sb.WriteString("}")
|
||||
break
|
||||
}
|
||||
|
||||
writeEscapeStr(sb, tn)
|
||||
sb.WriteString(":")
|
||||
err = m.encode(d, sb, tt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeEscapeStr(sb *strings.Builder, str string) {
|
||||
for _, v := range []byte(str) {
|
||||
if !isAllowedInUnquotedString(v) {
|
||||
// need quote
|
||||
dc := strings.Count(str, `"`)
|
||||
sc := strings.Count(str, `'`)
|
||||
if dc > sc {
|
||||
sb.WriteString("'")
|
||||
strings.NewReplacer(`'`, `\'`, `\`, `\\`).WriteString(sb, str)
|
||||
sb.WriteString("'")
|
||||
} else {
|
||||
sb.WriteString(`"`)
|
||||
strings.NewReplacer(`"`, `\"`, `\`, `\\`).WriteString(sb, str)
|
||||
sb.WriteString(`"`)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
sb.WriteString(str)
|
||||
}
|
||||
|
Reference in New Issue
Block a user