2019-09-16 09:18:13 +00:00
|
|
|
package io
|
2019-02-25 22:44:14 +00:00
|
|
|
|
|
|
|
import (
|
2019-09-15 11:58:19 +00:00
|
|
|
"bytes"
|
2019-02-25 22:44:14 +00:00
|
|
|
"encoding/binary"
|
|
|
|
"io"
|
|
|
|
)
|
|
|
|
|
2019-03-17 18:26:35 +00:00
|
|
|
//BinReader is a convenient wrapper around a io.Reader and err object
|
|
|
|
// Used to simplify error handling when reading into a struct with many fields
|
2019-02-25 22:44:14 +00:00
|
|
|
type BinReader struct {
|
2019-09-15 11:58:19 +00:00
|
|
|
r io.Reader
|
2019-02-25 22:44:14 +00:00
|
|
|
Err error
|
|
|
|
}
|
|
|
|
|
2019-09-15 11:58:19 +00:00
|
|
|
// NewBinReaderFromIO makes a BinReader from io.Reader.
|
|
|
|
func NewBinReaderFromIO(ior io.Reader) *BinReader {
|
|
|
|
return &BinReader{r: ior}
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewBinReaderFromBuf makes a BinReader from byte buffer.
|
|
|
|
func NewBinReaderFromBuf(b []byte) *BinReader {
|
|
|
|
r := bytes.NewReader(b)
|
|
|
|
return NewBinReaderFromIO(r)
|
|
|
|
}
|
|
|
|
|
2019-08-28 10:24:06 +00:00
|
|
|
// ReadLE reads from the underlying io.Reader
|
|
|
|
// into the interface v in little-endian format
|
|
|
|
func (r *BinReader) ReadLE(v interface{}) {
|
2019-02-25 22:44:14 +00:00
|
|
|
if r.Err != nil {
|
|
|
|
return
|
|
|
|
}
|
2019-09-15 11:58:19 +00:00
|
|
|
r.Err = binary.Read(r.r, binary.LittleEndian, v)
|
2019-02-25 22:44:14 +00:00
|
|
|
}
|
2019-03-17 18:26:35 +00:00
|
|
|
|
2019-08-28 10:24:06 +00:00
|
|
|
// ReadBE reads from the underlying io.Reader
|
|
|
|
// into the interface v in big-endian format
|
|
|
|
func (r *BinReader) ReadBE(v interface{}) {
|
2019-02-25 22:44:14 +00:00
|
|
|
if r.Err != nil {
|
|
|
|
return
|
|
|
|
}
|
2019-09-15 11:58:19 +00:00
|
|
|
r.Err = binary.Read(r.r, binary.BigEndian, v)
|
2019-02-25 22:44:14 +00:00
|
|
|
}
|
|
|
|
|
2019-08-28 10:24:06 +00:00
|
|
|
// ReadVarUint reads a variable-length-encoded integer from the
|
2019-03-17 18:26:35 +00:00
|
|
|
// underlying reader
|
2019-08-28 10:24:06 +00:00
|
|
|
func (r *BinReader) ReadVarUint() uint64 {
|
2019-08-29 10:24:03 +00:00
|
|
|
if r.Err != nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2019-02-25 22:44:14 +00:00
|
|
|
var b uint8
|
2019-09-15 11:58:19 +00:00
|
|
|
r.Err = binary.Read(r.r, binary.LittleEndian, &b)
|
2019-02-25 22:44:14 +00:00
|
|
|
|
|
|
|
if b == 0xfd {
|
|
|
|
var v uint16
|
2019-09-15 11:58:19 +00:00
|
|
|
r.Err = binary.Read(r.r, binary.LittleEndian, &v)
|
2019-02-25 22:44:14 +00:00
|
|
|
return uint64(v)
|
|
|
|
}
|
|
|
|
if b == 0xfe {
|
|
|
|
var v uint32
|
2019-09-15 11:58:19 +00:00
|
|
|
r.Err = binary.Read(r.r, binary.LittleEndian, &v)
|
2019-02-25 22:44:14 +00:00
|
|
|
return uint64(v)
|
|
|
|
}
|
|
|
|
if b == 0xff {
|
|
|
|
var v uint64
|
2019-09-15 11:58:19 +00:00
|
|
|
r.Err = binary.Read(r.r, binary.LittleEndian, &v)
|
2019-02-25 22:44:14 +00:00
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
return uint64(b)
|
|
|
|
}
|
|
|
|
|
2019-08-28 10:24:06 +00:00
|
|
|
// ReadBytes reads the next set of bytes from the underlying reader.
|
|
|
|
// ReadVarUInt() is used to determine how large that slice is
|
|
|
|
func (r *BinReader) ReadBytes() []byte {
|
|
|
|
n := r.ReadVarUint()
|
2019-02-25 22:44:14 +00:00
|
|
|
b := make([]byte, n)
|
2019-08-28 10:24:06 +00:00
|
|
|
r.ReadLE(b)
|
2019-02-25 22:44:14 +00:00
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
2019-08-28 10:24:06 +00:00
|
|
|
// ReadString calls ReadBytes and casts the results as a string
|
|
|
|
func (r *BinReader) ReadString() string {
|
|
|
|
b := r.ReadBytes()
|
2019-02-25 22:44:14 +00:00
|
|
|
return string(b)
|
|
|
|
}
|