lazarus/streaming/bitreader.go

138 lines
2.8 KiB
Go
Raw Normal View History

2019-01-14 03:02:49 +00:00
package streaming
import (
"io"
)
type BitReader struct {
2019-02-10 00:00:49 +00:00
reader io.Reader
bitOffset int
tailByte byte
2019-01-14 03:02:49 +00:00
}
2019-01-23 02:49:23 +00:00
func NewBitReader(reader io.Reader) *BitReader {
2019-01-14 03:02:49 +00:00
return &BitReader{reader: reader}
}
2019-01-24 04:06:32 +00:00
func (r *BitReader) ReadBool() (bool, error) {
value, err := r.ReadUint64(1)
return value == 1, err
}
func (r *BitReader) ReadInt8(count int) (int8, error) {
value, err := r.ReadInt64(count)
return int8(value), err
}
func (r *BitReader) ReadUint8(count int) (uint8, error) {
value, err := r.ReadUint64(count)
return uint8(value), err
}
func (r *BitReader) ReadInt16(count int) (int16, error) {
value, err := r.ReadInt64(count)
return int16(value), err
}
func (r *BitReader) ReadUint16(count int) (uint16, error) {
value, err := r.ReadUint64(count)
return uint16(value), err
}
func (r *BitReader) ReadInt32(count int) (int32, error) {
value, err := r.ReadInt64(count)
return int32(value), err
}
func (r *BitReader) ReadUint32(count int) (uint32, error) {
value, err := r.ReadUint64(count)
return uint32(value), err
}
func (r *BitReader) ReadInt64(count int) (int64, error) {
value, err := r.ReadUint64(count)
2019-01-23 03:06:13 +00:00
if err != nil {
return 0, err
}
return twosComplement(value, count), nil
2019-01-23 03:06:13 +00:00
}
2019-01-24 04:06:32 +00:00
func (r *BitReader) ReadUint64(count int) (uint64, error) {
2019-02-10 00:00:49 +00:00
buffer, bitOffset, err := r.readBytes(count)
if err != nil {
return 0, err
}
return readBits(buffer, bitOffset, count), nil
2019-02-10 00:00:49 +00:00
}
2019-01-16 03:44:02 +00:00
2019-02-10 00:00:49 +00:00
func (r *BitReader) readBytes(count int) ([]byte, int, error) {
if count == 0 {
return nil, 0, nil
2019-01-14 03:02:49 +00:00
}
2019-02-10 00:00:49 +00:00
var (
bitOffsetInByte = r.bitOffset % 8
bitsLeftInByte = 8 - bitOffsetInByte
bytesNeeded = 1
)
if bitsLeftInByte < count {
bitsOverrun := count - bitsLeftInByte
bytesNeeded += bitsOverrun / 8
if bitsOverrun%8 != 0 {
bytesNeeded++
}
}
buffer := make([]byte, bytesNeeded)
bufferToRead := buffer
if bitsLeftInByte < 8 {
buffer[0] = r.tailByte
bufferToRead = buffer[1:]
}
if _, err := io.ReadAtLeast(r.reader, bufferToRead, len(bufferToRead)); err != nil {
return nil, 0, err
}
r.bitOffset += count
r.tailByte = buffer[bytesNeeded-1]
return buffer, bitOffsetInByte, nil
2019-01-14 03:02:49 +00:00
}
func readBits(buffer []byte, bitOffset, count int) uint64 {
var result uint64
remainder := count
for byteOffset := 0; remainder > 0; byteOffset++ {
bitsRead := 8 - bitOffset
if bitsRead > remainder {
bitsRead = remainder
}
bufferByte := buffer[byteOffset]
bufferByte >>= uint(bitOffset)
bufferByte &= ^(0xff << uint(bitsRead))
result |= (uint64(bufferByte) << uint(count-remainder))
remainder -= bitsRead
bitOffset = 0
}
return result
}
func twosComplement(value uint64, bits int) int64 {
signMask := uint64(1 << uint(bits-1))
if value&signMask == 0 {
return int64(value &^ signMask)
} else {
valueMask := ^(^uint64(0) << uint(bits-1))
return -int64(valueMask & (^value + 1))
}
}