infer compress type before decode NBT fail

This commit is contained in:
Tnze
2019-07-31 17:31:16 +08:00
parent 697e09fc5e
commit 5fbc95d4a0
19 changed files with 100 additions and 2 deletions

View File

@ -26,7 +26,7 @@ const (
type Decoder struct {
r interface {
io.ByteReader
io.ByteScanner
io.Reader
}
}
@ -34,7 +34,7 @@ type Decoder struct {
func NewDecoder(r io.Reader) *Decoder {
d := new(Decoder)
if br, ok := r.(interface {
io.ByteReader
io.ByteScanner
io.Reader
}); ok {
d.r = br

View File

@ -18,6 +18,17 @@ func (d *Decoder) Decode(v interface{}) error {
if val.Kind() != reflect.Ptr {
return errors.New("non-pointer passed to Unmarshal")
}
// check the head
compress, err := d.checkCompressed()
if err != nil {
return fmt.Errorf("check compressed fail: %v", err)
}
if compress != "" {
return fmt.Errorf("data may compressed with %s", compress)
}
//start read NBT
tagType, tagName, err := d.readTag()
if err != nil {
return err
@ -25,6 +36,29 @@ func (d *Decoder) Decode(v interface{}) error {
return d.unmarshal(val.Elem(), tagType, tagName)
}
// check the first byte and return if it use compress
func (d *Decoder) checkCompressed() (compress string, err error) {
var head byte
head, err = d.r.ReadByte()
if err != nil {
return
}
if head <= 12 { //NBT
compress = ""
} else if head == 0x1f { //gzip
compress = "gzip"
} else if head == 0x78 { //zlib
compress = "zlib"
} else {
compress = "unknown"
}
err = d.r.UnreadByte()
return
}
// ErrEND error will be returned when reading a NBT with only Tag_End
var ErrEND = errors.New("unexpected TAG_End")

4
save/level.go Normal file
View File

@ -0,0 +1,4 @@
package save
type Level struct {
}

16
save/playerdata.go Normal file
View File

@ -0,0 +1,16 @@
package save
import (
"github.com/Tnze/go-mc/nbt"
"io"
)
type PlayerData struct {
Pos [3]float64
Motion [3]float64
}
func ReadPlayerData(r io.Reader) (data PlayerData, err error) {
err = nbt.NewDecoder(r).Decode(&data)
return
}

33
save/playerdata_test.go Normal file
View File

@ -0,0 +1,33 @@
package save
import (
"compress/gzip"
"os"
"testing"
)
func TestPlayerData(t *testing.T) {
f, err := os.Open("testdata/playerdata/58f6356e-b30c-4811-8bfc-d72a9ee99e73.dat")
if err != nil {
t.Fatal(err)
}
r, err := gzip.NewReader(f)
if err != nil {
t.Fatal(err)
}
data, err := ReadPlayerData(r)
if err != nil {
t.Fatal(err)
}
want := PlayerData{
Pos: [3]float64{-41.5, 65, -89.5},
Motion: [3]float64{0, -0.0784000015258789, 0},
}
if data != want {
t.Errorf("player data parse error: get %v, want %v", data, want)
}
}

1
save/save.go Normal file
View File

@ -0,0 +1 @@
package save

Binary file not shown.

BIN
save/testdata/DIM1/data/raids_end.dat vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,9 @@
{
"minecraft:adventure/adventuring_time": {
"criteria": {
"minecraft:plains": "2019-07-31 15:56:59 +0800"
},
"done": false
},
"DataVersion": 1976
}

BIN
save/testdata/data/raids.dat vendored Normal file

Binary file not shown.

BIN
save/testdata/level.dat vendored Normal file

Binary file not shown.

BIN
save/testdata/level.dat_old vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
save/testdata/region/r.-1.-1.mca vendored Normal file

Binary file not shown.

BIN
save/testdata/region/r.-1.0.mca vendored Normal file

Binary file not shown.

BIN
save/testdata/region/r.0.-1.mca vendored Normal file

Binary file not shown.

BIN
save/testdata/region/r.0.0.mca vendored Normal file

Binary file not shown.

BIN
save/testdata/session.lock vendored Normal file

Binary file not shown.

View File

@ -0,0 +1 @@
{"stats":{"minecraft:custom":{"minecraft:time_since_rest":6,"minecraft:play_one_minute":6,"minecraft:leave_game":1,"minecraft:time_since_death":6}},"DataVersion":1976}