lazarus/streaming/bitreader.go

150 lines
2.7 KiB
Go
Raw Normal View History

2019-01-14 03:02:49 +00:00
package streaming
import (
2019-02-10 16:55:14 +00:00
"errors"
2019-01-14 03:02:49 +00:00
"io"
)
type BitReader struct {
2019-02-10 00:00:49 +00:00
reader io.Reader
bitOffset int
tailByte byte
2019-02-10 16:55:14 +00:00
err error
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-02-10 16:55:14 +00:00
func (r *BitReader) ReadBool() bool {
return r.ReadUint(1) != 0
2019-01-24 04:06:32 +00:00
}
2019-02-10 16:55:14 +00:00
func (r *BitReader) ReadIntPacked(countPacked int) int64 {
if r.err != nil {
return 0
}
2019-01-24 04:06:32 +00:00
2019-02-10 16:55:14 +00:00
count, err := unpackSize(countPacked)
if err != nil {
r.err = err
return 0
}
2019-01-24 04:06:32 +00:00
2019-02-10 16:55:14 +00:00
return r.ReadInt(count)
2019-01-24 04:06:32 +00:00
}
2019-02-10 16:55:14 +00:00
func (r *BitReader) ReadInt(count int) int64 {
return twosComplement(r.ReadUint(count), count)
2019-01-24 04:06:32 +00:00
}
2019-02-10 16:55:14 +00:00
func (r *BitReader) ReadUintPacked(countPacked int) uint64 {
if r.err != nil {
return 0
}
2019-01-24 04:06:32 +00:00
2019-02-10 16:55:14 +00:00
count, err := unpackSize(countPacked)
2019-01-23 03:06:13 +00:00
if err != nil {
2019-02-10 16:55:14 +00:00
r.err = err
return 0
2019-01-23 03:06:13 +00:00
}
2019-02-10 16:55:14 +00:00
return r.ReadUint(count)
2019-01-23 03:06:13 +00:00
}
2019-02-10 16:55:14 +00:00
func (r *BitReader) ReadUint(count int) uint64 {
if r.err != nil {
return 0
}
2019-02-10 00:00:49 +00:00
buffer, bitOffset, err := r.readBytes(count)
if err != nil {
2019-02-10 16:55:14 +00:00
r.err = err
return 0
2019-02-10 00:00:49 +00:00
}
2019-02-10 16:55:14 +00:00
return readBits(buffer, bitOffset, count)
}
func (r *BitReader) Error() error {
return r.err
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))
}
}
2019-02-10 16:55:14 +00:00
func unpackSize(sizePacked int) (int, error) {
sizes := []int{0, 1, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 26, 28, 30, 32}
if sizePacked >= len(sizes) {
return 0, errors.New("invalid packed size")
}
return sizes[sizePacked], nil
}