diff --git a/common/bigendianreader.go b/common/bigendianreader.go new file mode 100644 index 0000000..3a998db --- /dev/null +++ b/common/bigendianreader.go @@ -0,0 +1,80 @@ +// Copyright 2024 by Sascha L. Teichmann +// Use of this source code is governed by the MIT license +// that can be found in the LICENSE file. + +package common + +import ( + "encoding/binary" + "io" +) + +type bigEndianReader struct { + parent io.Reader + buf [4]byte + err error +} + +func (ber *bigEndianReader) u8() (uint8, error) { + if ber.err != nil { + return 0, ber.err + } + _, err := io.ReadFull(ber.parent, ber.buf[:1]) + if err != nil { + ber.err = err + return 0, err + } + return ber.buf[0], nil +} + +func (ber *bigEndianReader) u16() (uint16, error) { + if ber.err != nil { + return 0, ber.err + } + two := ber.buf[:2] + _, err := io.ReadFull(ber.parent, two) + if err != nil { + ber.err = err + return 0, err + } + return binary.BigEndian.Uint16(two), nil +} + +func (ber *bigEndianReader) u32() (uint32, error) { + if ber.err != nil { + return 0, ber.err + } + four := ber.buf[:2] + _, err := io.ReadFull(ber.parent, four) + if err != nil { + ber.err = err + return 0, err + } + return binary.BigEndian.Uint32(four), nil +} + +func (ber *bigEndianReader) str(n int) (string, error) { + if ber.err != nil { + return "", ber.err + } + buf := make([]byte, n) + _, err := io.ReadFull(ber.parent, buf) + if err != nil { + ber.err = err + return "", err + } + return string(buf), nil +} + +func (ber *bigEndianReader) full(n int) ([]byte, error) { + if ber.err != nil { + return nil, ber.err + } + buf := make([]byte, n) + _, err := io.ReadFull(ber.parent, buf) + if err != nil { + ber.err = err + return nil, err + } + return buf, nil +} diff --git a/common/block.go b/common/block.go index f81bb6c..8da2d55 100644 --- a/common/block.go +++ b/common/block.go @@ -92,101 +92,38 @@ type posBuf struct { Pos int } -type bigEndian struct { - data []byte - err error -} - -func (be *bigEndian) Err() error { - return be.err -} - -func (be *bigEndian) u8() uint8 { - if be.err != nil { - return 0 - } - if len(be.data) >= 1 { - x := be.data[0] - be.data = be.data[1:] - return x - } - be.err = ErrBlockTruncated - return 0 -} - -func (be *bigEndian) u16() uint16 { - if be.err != nil { - return 0 - } - if len(be.data) >= 2 { - x := binary.BigEndian.Uint16(be.data) - be.data = be.data[2:] - return x - } - be.err = ErrBlockTruncated - return 0 -} - -func (be *bigEndian) u32() uint32 { - if be.err != nil { - return 0 - } - if len(be.data) >= 4 { - x := binary.BigEndian.Uint32(be.data) - be.data = be.data[4:] - return x - } - be.err = ErrBlockTruncated - return 0 -} - -func (be *bigEndian) str(l int) string { - if be.err != nil { - return "" - } - if len(be.data) >= l { - s := string(be.data[:l]) - be.data = be.data[l:] - return s - } - be.err = ErrBlockTruncated - return "" -} - func decode29(data []byte, colors *Colors) (*DecodedBlock, error) { - dec, err := zstd.NewReader(nil) + dec, err := zstd.NewReader(bytes.NewReader(data)) if err != nil { return nil, err } - content, err := dec.DecodeAll(data[1:], nil) - if err != nil { - return nil, err - } + be := bigEndianReader{parent: dec} - be := bigEndian{data: content} - - _ = be.u8() // flags - _ = be.u16() // lightning_complete - _ = be.u32() // timestamp - _ = be.u8() // name_id_mapping_version + be.u8() // flags + be.u16() // lightning_complete + be.u32() // timestamp + be.u8() // name_id_mapping_version airID, ignoreID := int32(-1), int32(-1) indexMap := make(map[int32]int32) transparent := false - numNameIDMappings := be.u16() + numNameIDMappings, _ := be.u16() for i := uint16(0); i < numNameIDMappings; i++ { - id := int32(be.u16()) - name := be.str(int(be.u16())) + var ( + id, _ = be.u16() + nlen, _ = be.u16() + name, _ = be.str(int(nlen)) + ) switch name { case "air": - airID = id + airID = int32(id) case "ignore": - ignoreID = id + ignoreID = int32(id) default: if index, found := colors.NameIndex[name]; found { - indexMap[id] = index + indexMap[int32(id)] = index if !transparent && colors.IsTransparent(index) { transparent = true } @@ -195,18 +132,13 @@ func decode29(data []byte, colors *Colors) (*DecodedBlock, error) { } } } - _ = be.u8() // content_width - _ = be.u8() // params_width + be.u8() // content_width + be.u8() // params_width - if err := be.Err(); err != nil { - return nil, err - } - - mapContent := make([]byte, 2*4096) - if len(be.data) < len(mapContent) { + mapContent, err := be.full(2 * 4096) + if err != nil { return nil, ErrBlockTruncated } - copy(mapContent, be.data) return &DecodedBlock{ Version: data[0],