Skip to content

Commit

Permalink
Update binary reader
Browse files Browse the repository at this point in the history
  • Loading branch information
tdewolff committed May 11, 2024
1 parent 80d8980 commit a1dd1e8
Showing 1 changed file with 193 additions and 20 deletions.
213 changes: 193 additions & 20 deletions binary.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,44 @@ package parse

import (
"encoding/binary"
"fmt"
"io"
"math"
"os"
)

// BinaryReader is a binary big endian file format reader.
type BinaryReader struct {
buf []byte
pos uint32
eof bool
Endianness binary.ByteOrder
buf []byte
pos uint32
eof bool
}

// NewBinaryReader returns a big endian binary file format reader.
func NewBinaryReader(buf []byte) *BinaryReader {
if math.MaxUint32 < uint(len(buf)) {
return &BinaryReader{nil, 0, true}
return &BinaryReader{binary.BigEndian, nil, 0, true}
}
return &BinaryReader{buf, 0, false}
return &BinaryReader{binary.BigEndian, buf, 0, false}
}

// NewBinaryReaderLE returns a little endian binary file format reader.
func NewBinaryReaderLE(buf []byte) *BinaryReader {
r := NewBinaryReader(buf)
r.Endianness = binary.LittleEndian
return r
}

// Seek set the reader position in the buffer.
func (r *BinaryReader) Seek(pos uint32) {
func (r *BinaryReader) Seek(pos uint32) error {
if uint32(len(r.buf)) < pos {
r.eof = true
return
return io.EOF
}
r.pos = pos
r.eof = false
return nil
}

// Pos returns the reader's position.
Expand Down Expand Up @@ -93,7 +104,7 @@ func (r *BinaryReader) ReadUint16() uint16 {
if b == nil {
return 0
}
return binary.BigEndian.Uint16(b)
return r.Endianness.Uint16(b)
}

// ReadUint32 reads a uint32.
Expand All @@ -102,7 +113,7 @@ func (r *BinaryReader) ReadUint32() uint32 {
if b == nil {
return 0
}
return binary.BigEndian.Uint32(b)
return r.Endianness.Uint32(b)
}

// ReadUint64 reads a uint64.
Expand All @@ -111,7 +122,7 @@ func (r *BinaryReader) ReadUint64() uint64 {
if b == nil {
return 0
}
return binary.BigEndian.Uint64(b)
return r.Endianness.Uint64(b)
}

// ReadInt8 reads a int8.
Expand All @@ -134,27 +145,189 @@ func (r *BinaryReader) ReadInt64() int64 {
return int64(r.ReadUint64())
}

// ReadUint16LE reads a uint16 little endian.
func (r *BinaryReader) ReadUint16LE() uint16 {
type BinaryFileReader struct {
f *os.File
size uint64
offset uint64

Endianness binary.ByteOrder
buf []byte
pos int
}

func NewBinaryFileReader(f *os.File, chunk int) (*BinaryFileReader, error) {
var buf []byte
var size uint64
if chunk == 0 {
var err error
if buf, err = io.ReadAll(f); err != nil {
return nil, err
}
} else {
buf = make([]byte, 0, chunk)
}
if info, err := f.Stat(); err != nil {
return nil, err
} else {
size = uint64(info.Size())
}
return &BinaryFileReader{
f: f,
size: size,
Endianness: binary.BigEndian,
buf: buf,
}, nil
}

func (r *BinaryFileReader) buffer(pos, length uint64) error {
if pos < r.offset || r.offset+uint64(len(r.buf)) < pos+length {
if math.MaxInt64 < pos {
return fmt.Errorf("seek position too large")
} else if _, err := r.f.Seek(int64(pos), 0); err != nil {
return err
} else if n, err := r.f.Read(r.buf[:cap(r.buf)]); err != nil {
return err
} else {
r.offset = pos
r.buf = r.buf[:n]
r.pos = 0
}
}
return nil
}

// Seek set the reader position in the buffer.
func (r *BinaryFileReader) Seek(pos uint64) error {
if r.size <= pos {
return io.EOF
} else if err := r.buffer(pos, 0); err != nil {
return err
}
r.pos = int(pos - r.offset)
return nil
}

// Pos returns the reader's position.
func (r *BinaryFileReader) Pos() uint64 {
return r.offset + uint64(r.pos)
}

// Len returns the remaining length of the buffer.
func (r *BinaryFileReader) Len() uint64 {
return r.size - r.Pos()
}

// Offset returns the offset of the buffer.
func (r *BinaryFileReader) Offset() uint64 {
return r.offset
}

// BufferLen returns the length of the buffer.
func (r *BinaryFileReader) BufferLen() int {
return len(r.buf)
}

// Read complies with io.Reader.
func (r *BinaryFileReader) Read(b []byte) (int, error) {
if len(b) <= cap(r.buf) {
if err := r.buffer(r.offset+uint64(r.pos), uint64(len(b))); err != nil {
return 0, err
}
n := copy(b, r.buf[r.pos:])
r.pos += n
return n, nil
}

// read directly from file
if _, err := r.f.Seek(int64(r.offset)+int64(r.pos), 0); err != nil {
return 0, err
}
n, err := r.f.Read(b)
r.offset += uint64(r.pos + n)
r.pos = 0
r.buf = r.buf[:0]
return n, err
}

// ReadBytes reads n bytes.
func (r *BinaryFileReader) ReadBytes(n int) []byte {
if n < len(r.buf)-r.pos {
b := r.buf[r.pos : r.pos+n]
r.pos += n
return b
}

b := make([]byte, n)
if _, err := r.Read(b); err != nil {
return nil
}
return b
}

// ReadString reads a string of length n.
func (r *BinaryFileReader) ReadString(n int) string {
return string(r.ReadBytes(n))
}

// ReadByte reads a single byte.
func (r *BinaryFileReader) ReadByte() byte {
b := r.ReadBytes(1)
if b == nil {
return 0
}
return b[0]
}

// ReadUint8 reads a uint8.
func (r *BinaryFileReader) ReadUint8() uint8 {
return r.ReadByte()
}

// ReadUint16 reads a uint16.
func (r *BinaryFileReader) ReadUint16() uint16 {
b := r.ReadBytes(2)
if b == nil {
return 0
}
return binary.LittleEndian.Uint16(b)
return r.Endianness.Uint16(b)
}

// ReadUint32LE reads a uint32 little endian.
func (r *BinaryReader) ReadUint32LE() uint32 {
// ReadUint32 reads a uint32.
func (r *BinaryFileReader) ReadUint32() uint32 {
b := r.ReadBytes(4)
if b == nil {
return 0
}
return binary.LittleEndian.Uint32(b)
return r.Endianness.Uint32(b)
}

// ReadUint64 reads a uint64.
func (r *BinaryFileReader) ReadUint64() uint64 {
b := r.ReadBytes(8)
if b == nil {
return 0
}
return r.Endianness.Uint64(b)
}

// ReadInt8 reads a int8.
func (r *BinaryFileReader) ReadInt8() int8 {
return int8(r.ReadByte())
}

// ReadInt16 reads a int16.
func (r *BinaryFileReader) ReadInt16() int16 {
return int16(r.ReadUint16())
}

// ReadInt32 reads a int32.
func (r *BinaryFileReader) ReadInt32() int32 {
return int32(r.ReadUint32())
}

// ReadInt16LE reads a int16 little endian.
func (r *BinaryReader) ReadInt16LE() int16 {
return int16(r.ReadUint16LE())
// ReadInt64 reads a int64.
func (r *BinaryFileReader) ReadInt64() int64 {
return int64(r.ReadUint64())
}

// BinaryWriter is a big endian binary file format writer.
Expand Down Expand Up @@ -247,7 +420,7 @@ func (w *BinaryWriter) WriteInt64(v int64) {
// BitmapReader is a binary bitmap reader.
type BitmapReader struct {
buf []byte
pos uint32
pos uint32 // TODO: to uint64
eof bool
}

Expand Down

0 comments on commit a1dd1e8

Please sign in to comment.