-
Notifications
You must be signed in to change notification settings - Fork 7
/
BitstreamReader.go
86 lines (74 loc) · 2.63 KB
/
BitstreamReader.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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)
}
}