88 lines
2.6 KiB
Go
88 lines
2.6 KiB
Go
package compression
|
|
|
|
// BitstreamReader is a utility to read big-endian integer values of arbitrary bit size from a bitstream.
|
|
type BitstreamReader struct {
|
|
source []byte
|
|
nextSourceIndex int
|
|
sourceBitLen uint64
|
|
|
|
currentBitPos uint64
|
|
|
|
buffer uint64
|
|
bitsBuffered uint64
|
|
}
|
|
|
|
// NewBitstreamReader returns a new instance of a bistream reader using the provided byte slice as source.
|
|
func NewBitstreamReader(data []byte) *BitstreamReader {
|
|
return &BitstreamReader{
|
|
source: data,
|
|
sourceBitLen: uint64(len(data)) * 8,
|
|
}
|
|
}
|
|
|
|
func (reader *BitstreamReader) bufferNextByte() {
|
|
reader.buffer = (reader.buffer << 8) | uint64(reader.source[reader.nextSourceIndex])
|
|
reader.bitsBuffered += 8
|
|
reader.nextSourceIndex++
|
|
}
|
|
|
|
// Exhausted returns true if the current position is at or beyond the possible length.
|
|
// Reading an exhausted stream yields only zeroes.
|
|
func (reader *BitstreamReader) Exhausted() bool {
|
|
return reader.currentBitPos >= reader.sourceBitLen
|
|
}
|
|
|
|
// Read returns a value with the requested bit size, right aligned, as a uint32.
|
|
// Reading does not advance the current position. A successful read of a certain size will return the same
|
|
// value when called repeatedly with the same parameter.
|
|
// Reading is possible beyond the available size. For the missing bits, a value of 0 is provided.
|
|
//
|
|
// The function panics when reading more than 32 bits.
|
|
func (reader *BitstreamReader) Read(bits int) (result uint32) {
|
|
if bits > 32 {
|
|
panic("Limit of bit count: 32")
|
|
}
|
|
|
|
available := reader.sourceBitLen - reader.currentBitPos
|
|
toRead := uint64(bits)
|
|
if toRead > available {
|
|
toRead = available
|
|
}
|
|
|
|
for reader.bitsBuffered < toRead {
|
|
reader.bufferNextByte()
|
|
}
|
|
result = uint32(reader.buffer >> (reader.bitsBuffered - toRead) & ^(uint64(0xFFFFFFFFFFFFFFFF) << toRead))
|
|
result <<= uint64(bits) - toRead
|
|
|
|
return
|
|
}
|
|
|
|
// Advance skips the provided amount of bits and puts the current position there.
|
|
// Successive read operations will return values from the new position.
|
|
// It is possible to advance beyond the available length.
|
|
//
|
|
// This function panics when advancing with negative values.
|
|
func (reader *BitstreamReader) Advance(bits int) {
|
|
if bits < 0 {
|
|
panic("Can only advance forward")
|
|
}
|
|
|
|
newIndex := reader.currentBitPos + uint64(bits)
|
|
if newIndex > reader.sourceBitLen {
|
|
newIndex = reader.sourceBitLen
|
|
}
|
|
reader.currentBitPos = newIndex
|
|
if uint64(bits) > reader.bitsBuffered {
|
|
reader.bitsBuffered = 0
|
|
reader.nextSourceIndex = int(reader.currentBitPos / 8)
|
|
remainder := reader.currentBitPos % 8
|
|
if remainder > 0 {
|
|
reader.bufferNextByte()
|
|
reader.bitsBuffered -= remainder
|
|
}
|
|
} else {
|
|
reader.bitsBuffered -= uint64(bits)
|
|
}
|
|
}
|