diff options
Diffstat (limited to 'vendor/github.com/tdewolff/parse/v2/binary.go')
-rw-r--r-- | vendor/github.com/tdewolff/parse/v2/binary.go | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/vendor/github.com/tdewolff/parse/v2/binary.go b/vendor/github.com/tdewolff/parse/v2/binary.go index 83c08d742..6d1f9ef26 100644 --- a/vendor/github.com/tdewolff/parse/v2/binary.go +++ b/vendor/github.com/tdewolff/parse/v2/binary.go @@ -2,12 +2,15 @@ package parse import ( "encoding/binary" + "errors" "fmt" "io" "math" "os" ) +const PageSize = 4096 + // BinaryReader is a binary big endian file format reader. type BinaryReader struct { Endianness binary.ByteOrder @@ -330,6 +333,320 @@ func (r *BinaryFileReader) ReadInt64() int64 { return int64(r.ReadUint64()) } +type IBinaryReader interface { + Close() error + Len() int + Bytes(int, int64) ([]byte, error) +} + +type binaryReaderFile struct { + f *os.File + size int64 +} + +func newBinaryReaderFile(filename string) (*binaryReaderFile, error) { + f, err := os.Open(filename) + if err != nil { + return nil, err + } + fi, err := f.Stat() + if err != nil { + f.Close() + return nil, err + } + return &binaryReaderFile{f, fi.Size()}, nil +} + +// Close closes the reader. +func (r *binaryReaderFile) Close() error { + return r.f.Close() +} + +// Len returns the length of the underlying memory-mapped file. +func (r *binaryReaderFile) Len() int { + return int(r.size) +} + +func (r *binaryReaderFile) Bytes(n int, off int64) ([]byte, error) { + if _, err := r.f.Seek(off, 0); err != nil { + return nil, err + } + + b := make([]byte, n) + m, err := r.f.Read(b) + if err != nil { + return nil, err + } else if m != n { + return nil, errors.New("file: could not read all bytes") + } + return b, nil +} + +type binaryReaderBytes struct { + data []byte +} + +func newBinaryReaderBytes(data []byte) (*binaryReaderBytes, error) { + return &binaryReaderBytes{data}, nil +} + +// Close closes the reader. +func (r *binaryReaderBytes) Close() error { + return nil +} + +// Len returns the length of the underlying memory-mapped file. +func (r *binaryReaderBytes) Len() int { + return len(r.data) +} + +func (r *binaryReaderBytes) Bytes(n int, off int64) ([]byte, error) { + if off < 0 || int64(len(r.data)) < off { + return nil, fmt.Errorf("bytes: invalid offset %d", off) + } + return r.data[off : off+int64(n) : off+int64(n)], nil +} + +type binaryReaderReader struct { + r io.Reader + n int64 + readerAt bool + seeker bool +} + +func newBinaryReaderReader(r io.Reader, n int64) (*binaryReaderReader, error) { + _, readerAt := r.(io.ReaderAt) + _, seeker := r.(io.Seeker) + return &binaryReaderReader{r, n, readerAt, seeker}, nil +} + +// Close closes the reader. +func (r *binaryReaderReader) Close() error { + if closer, ok := r.r.(io.Closer); ok { + return closer.Close() + } + return nil +} + +// Len returns the length of the underlying memory-mapped file. +func (r *binaryReaderReader) Len() int { + return int(r.n) +} + +func (r *binaryReaderReader) Bytes(n int, off int64) ([]byte, error) { + // seeker seems faster than readerAt by 10% + if r.seeker { + if _, err := r.r.(io.Seeker).Seek(off, 0); err != nil { + return nil, err + } + + b := make([]byte, n) + m, err := r.r.Read(b) + if err != nil { + return nil, err + } else if m != n { + return nil, errors.New("file: could not read all bytes") + } + return b, nil + } else if r.readerAt { + b := make([]byte, n) + m, err := r.r.(io.ReaderAt).ReadAt(b, off) + if err != nil { + return nil, err + } else if m != n { + return nil, errors.New("file: could not read all bytes") + } + return b, nil + } + return nil, errors.New("io.Seeker and io.ReaderAt not implemented") +} + +type BinaryReader2 struct { + f IBinaryReader + pos int64 + err error + + Endian binary.ByteOrder +} + +func NewBinaryReader2(f IBinaryReader) *BinaryReader2 { + return &BinaryReader2{ + f: f, + Endian: binary.BigEndian, + } +} + +func NewBinaryReader2Reader(r io.Reader, n int64) (*BinaryReader2, error) { + _, isReaderAt := r.(io.ReaderAt) + _, isSeeker := r.(io.Seeker) + + var f IBinaryReader + if isReaderAt || isSeeker { + var err error + f, err = newBinaryReaderReader(r, n) + if err != nil { + return nil, err + } + } else { + b := make([]byte, n) + if _, err := io.ReadFull(r, b); err != nil { + return nil, err + } + f, _ = newBinaryReaderBytes(b) + } + return NewBinaryReader2(f), nil +} + +func NewBinaryReader2Bytes(data []byte) (*BinaryReader2, error) { + f, _ := newBinaryReaderBytes(data) + return NewBinaryReader2(f), nil +} + +func NewBinaryReader2File(filename string) (*BinaryReader2, error) { + f, err := newBinaryReaderFile(filename) + if err != nil { + return nil, err + } + return NewBinaryReader2(f), nil +} + +func NewBinaryReader2Mmap(filename string) (*BinaryReader2, error) { + f, err := newBinaryReaderMmap(filename) + if err != nil { + return nil, err + } + return NewBinaryReader2(f), nil +} + +func (r *BinaryReader2) Err() error { + return r.err +} + +func (r *BinaryReader2) Close() error { + if err := r.f.Close(); err != nil { + return err + } + return r.err +} + +// InPageCache returns true if the range is already in the page cache (for mmap). +func (r *BinaryReader2) InPageCache(start, end int64) bool { + index := int64(r.Pos()) / PageSize + return start/PageSize == index && end/PageSize == index +} + +// Free frees all previously read bytes, you cannot seek from before this position (for reader). +func (r *BinaryReader2) Free() { +} + +// Pos returns the reader's position. +func (r *BinaryReader2) Pos() int64 { + return r.pos +} + +// Len returns the remaining length of the buffer. +func (r *BinaryReader2) Len() int { + return int(int64(r.f.Len()) - int64(r.pos)) +} + +func (r *BinaryReader2) Seek(pos int64) { + r.pos = pos +} + +// Read complies with io.Reader. +func (r *BinaryReader2) Read(b []byte) (int, error) { + data, err := r.f.Bytes(len(b), r.pos) + if err != nil && err != io.EOF { + return 0, err + } + n := copy(b, data) + r.pos += int64(len(b)) + return n, err +} + +// ReadBytes reads n bytes. +func (r *BinaryReader2) ReadBytes(n int) []byte { + data, err := r.f.Bytes(n, r.pos) + if err != nil { + r.err = err + return nil + } + r.pos += int64(n) + return data +} + +// ReadString reads a string of length n. +func (r *BinaryReader2) ReadString(n int) string { + return string(r.ReadBytes(n)) +} + +// ReadByte reads a single byte. +func (r *BinaryReader2) ReadByte() byte { + data := r.ReadBytes(1) + if data == nil { + return 0 + } + return data[0] +} + +// ReadUint8 reads a uint8. +func (r *BinaryReader2) ReadUint8() uint8 { + return r.ReadByte() +} + +// ReadUint16 reads a uint16. +func (r *BinaryReader2) ReadUint16() uint16 { + data := r.ReadBytes(2) + if data == nil { + return 0 + } else if r.Endian == binary.LittleEndian { + return uint16(data[1])<<8 | uint16(data[0]) + } + return uint16(data[0])<<8 | uint16(data[1]) +} + +// ReadUint32 reads a uint32. +func (r *BinaryReader2) ReadUint32() uint32 { + data := r.ReadBytes(4) + if data == nil { + return 0 + } else if r.Endian == binary.LittleEndian { + return uint32(data[3])<<24 | uint32(data[2])<<16 | uint32(data[1])<<8 | uint32(data[0]) + } + return uint32(data[0])<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) +} + +// ReadUint64 reads a uint64. +func (r *BinaryReader2) ReadUint64() uint64 { + data := r.ReadBytes(8) + if data == nil { + return 0 + } else if r.Endian == binary.LittleEndian { + return uint64(data[7])<<56 | uint64(data[6])<<48 | uint64(data[5])<<40 | uint64(data[4])<<32 | uint64(data[3])<<24 | uint64(data[2])<<16 | uint64(data[1])<<8 | uint64(data[0]) + } + return uint64(data[0])<<56 | uint64(data[1])<<48 | uint64(data[2])<<40 | uint64(data[3])<<32 | uint64(data[4])<<24 | uint64(data[5])<<16 | uint64(data[6])<<8 | uint64(data[7]) +} + +// ReadInt8 reads a int8. +func (r *BinaryReader2) ReadInt8() int8 { + return int8(r.ReadByte()) +} + +// ReadInt16 reads a int16. +func (r *BinaryReader2) ReadInt16() int16 { + return int16(r.ReadUint16()) +} + +// ReadInt32 reads a int32. +func (r *BinaryReader2) ReadInt32() int32 { + return int32(r.ReadUint32()) +} + +// ReadInt64 reads a int64. +func (r *BinaryReader2) ReadInt64() int64 { + return int64(r.ReadUint64()) +} + // BinaryWriter is a big endian binary file format writer. type BinaryWriter struct { buf []byte |