You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
118 lines
3.0 KiB
Go
118 lines
3.0 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
// a bitBuffer is a buffer of raw data that is not necessarily byte-aligned,
|
|
// for performing bitwise reads and manipulation. The bulk of this source is
|
|
// adapted from the bitReader defined in the standard library bzip2 package.
|
|
type bitBuffer struct {
|
|
source []byte // the source data to be read. This slice is never modified
|
|
index int // position of the last byte read out of source
|
|
scratch uint64 // scratch register of bits worthy of manipulation
|
|
bits uint // bit width of the scratch register
|
|
err error // stored error
|
|
}
|
|
|
|
func newBitBuffer(buf []byte) *bitBuffer {
|
|
return &bitBuffer{source: buf}
|
|
}
|
|
|
|
func (b *bitBuffer) readBits(bits uint) uint64 {
|
|
for bits > b.bits {
|
|
if b.index >= len(b.source) {
|
|
b.err = io.ErrUnexpectedEOF
|
|
return 0
|
|
}
|
|
b.scratch <<= 8
|
|
b.scratch |= uint64(b.source[b.index])
|
|
b.index += 1
|
|
b.bits += 8
|
|
}
|
|
|
|
// b.scratch looks like this (assuming that b.bits = 14 and bits = 6):
|
|
// Bit: 111111
|
|
// 5432109876543210
|
|
//
|
|
// (6 bits, the desired output)
|
|
// |-----|
|
|
// V V
|
|
// 0101101101001110
|
|
// ^ ^
|
|
// |------------|
|
|
// b.bits (num valid bits)
|
|
//
|
|
// This the next line right shifts the desired bits into the
|
|
// least-significant places and masks off anything above.
|
|
n := (b.scratch >> (b.bits - bits)) & ((1 << bits) - 1)
|
|
b.bits -= bits
|
|
return n
|
|
}
|
|
|
|
func (b *bitBuffer) readByte() (out byte) {
|
|
if b.bits == 0 {
|
|
if b.index >= len(b.source) {
|
|
b.err = io.ErrUnexpectedEOF
|
|
return
|
|
}
|
|
out = b.source[b.index]
|
|
b.index += 1
|
|
return
|
|
}
|
|
return byte(b.readBits(8))
|
|
}
|
|
|
|
func (b *bitBuffer) readBytes(n int) []byte {
|
|
if b.bits == 0 {
|
|
b.index += n
|
|
if b.index > len(b.source) {
|
|
b.err = io.ErrUnexpectedEOF
|
|
return []byte{}
|
|
}
|
|
return b.source[b.index-n : b.index]
|
|
}
|
|
buf := make([]byte, n)
|
|
for i := 0; i < n; i++ {
|
|
buf[i] = byte(b.readBits(8))
|
|
}
|
|
return buf
|
|
}
|
|
|
|
// readVarUint reads a variable-length uint32, encoded with some scheme that I
|
|
// can't find a standard for. first two bits are a length prefix, followed by a
|
|
// 4, 8, 12, or 32-bit wide uint.
|
|
func (b *bitBuffer) readVarUint() uint32 {
|
|
switch b.readBits(2) {
|
|
case 0:
|
|
return uint32(b.readBits(4))
|
|
case 1:
|
|
return uint32(b.readBits(4) | b.readBits(4)<<4)
|
|
case 2:
|
|
return uint32(b.readBits(4) | b.readBits(8)<<4)
|
|
case 3:
|
|
return uint32(b.readBits(4) | b.readBits(28)<<4)
|
|
default:
|
|
// this switch is already exhaustive, the compiler just can't tell.
|
|
panic(fmt.Sprintf("invalid varuint prefix"))
|
|
}
|
|
}
|
|
|
|
// readVarInt reads a varint-encoded value off of the front of the buffer. This
|
|
// is the varint encoding used in protobuf. That is: each byte utilizes a 7-bit
|
|
// group. the msb of each byte indicates whether there are more bytes to
|
|
// follow.
|
|
func (b *bitBuffer) readVarInt() uint64 {
|
|
var x, n uint64
|
|
for shift := uint(0); shift < 64; shift += 7 {
|
|
n = b.readBits(8)
|
|
if n < 0x80 {
|
|
return x | n<<shift
|
|
}
|
|
x |= n &^ 0x80 << shift
|
|
}
|
|
b.err = fmt.Errorf("readVarInt never saw the end of varint")
|
|
return 0
|
|
}
|