work on bit reader
This commit is contained in:
parent
2581573252
commit
a67b06a511
@ -6,8 +6,8 @@ import (
|
|||||||
|
|
||||||
type BitReader struct {
|
type BitReader struct {
|
||||||
reader io.Reader
|
reader io.Reader
|
||||||
offset int
|
bitOffset int
|
||||||
buffer [1]byte
|
tailByte byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBitReader(reader io.Reader) *BitReader {
|
func NewBitReader(reader io.Reader) *BitReader {
|
||||||
@ -66,31 +66,65 @@ func (r *BitReader) ReadInt64(count int) (int64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *BitReader) ReadUint64(count int) (uint64, error) {
|
func (r *BitReader) ReadUint64(count int) (uint64, error) {
|
||||||
var value uint64
|
buffer, bitOffset, err := r.readBytes(count)
|
||||||
for count > 0 {
|
if err != nil {
|
||||||
bitOffset := r.offset % 8
|
|
||||||
bitsLeft := 8 - bitOffset
|
|
||||||
if bitsLeft == 8 {
|
|
||||||
if _, err := r.reader.Read(r.buffer[:]); err != nil {
|
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var result uint64
|
||||||
|
|
||||||
|
remainder := count
|
||||||
|
for byteOffset := 0; remainder > 0; byteOffset++ {
|
||||||
|
bitsRead := 8 - bitOffset
|
||||||
|
if bitsRead > remainder {
|
||||||
|
bitsRead = remainder
|
||||||
}
|
}
|
||||||
|
|
||||||
bitsRead := count
|
bufferByte := buffer[byteOffset]
|
||||||
if bitsRead > bitsLeft {
|
bufferByte >>= uint(bitOffset)
|
||||||
bitsRead = bitsLeft
|
bufferByte &= ^(0xff << uint(bitsRead))
|
||||||
|
|
||||||
|
result |= (uint64(bufferByte) << uint(count-remainder))
|
||||||
|
|
||||||
|
remainder -= bitsRead
|
||||||
|
bitOffset = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer := r.buffer[0]
|
return result, nil
|
||||||
buffer <<= uint(bitOffset)
|
|
||||||
buffer >>= (uint(bitOffset) + uint(bitsLeft-bitsRead))
|
|
||||||
|
|
||||||
value <<= uint(bitsRead)
|
|
||||||
value |= uint64(buffer)
|
|
||||||
|
|
||||||
r.offset += bitsRead
|
|
||||||
count -= bitsRead
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return value, nil
|
func (r *BitReader) readBytes(count int) ([]byte, int, error) {
|
||||||
|
if count == 0 {
|
||||||
|
return nil, 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
@ -2,40 +2,37 @@ package streaming
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBitReader(t *testing.T) {
|
func TestBitReader(t *testing.T) {
|
||||||
data := []byte{
|
data := []byte{
|
||||||
0x69, // 01101001
|
0x01, // 00000001
|
||||||
0x96, // 10010110
|
0x23, // 00100011
|
||||||
0xf0, // 11110000
|
0x45, // 01000101
|
||||||
0xaa, // 10101010
|
0x67, // 01100111
|
||||||
0x00, // 00000000
|
0x89, // 01100111
|
||||||
0xff, // 11111111
|
0xAB, // 10101011
|
||||||
|
0xCD, // 11001101
|
||||||
|
0xEF, // 11101111
|
||||||
}
|
}
|
||||||
|
|
||||||
r := NewBitReader(bytes.NewReader(data))
|
r := NewBitReader(bytes.NewReader(data))
|
||||||
|
|
||||||
readPass := func(c int, v uint64) {
|
readPass := func(c int, v uint64) {
|
||||||
if value, err := r.ReadUint64(c); value != v || err != nil {
|
if value, err := r.ReadUint64(c); value != v || err != nil {
|
||||||
t.Fail()
|
fmt.Printf("%.16x (expected %.16x)\n", value, v)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
readFail := func(c int) {
|
|
||||||
if value, err := r.ReadUint64(c); value != 0 || err == nil {
|
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readPass(0, 0x00)
|
readPass(0, 0x00)
|
||||||
readPass(2, 0x01)
|
readPass(8, 0x01)
|
||||||
readPass(2, 0x02)
|
readPass(16, 0x4523)
|
||||||
readPass(3, 0x04)
|
readPass(3, 0x67&0x07)
|
||||||
readPass(1, 0x01)
|
readPass(13, 0x8967>>3)
|
||||||
readPass(12, 0x096f)
|
readPass(13, 0xcdab&0x1fff)
|
||||||
readPass(8, 0x000a)
|
readPass(2, (0xcdab>>13)&3)
|
||||||
readPass(20, 0x0a00ff)
|
readPass(9, 0xefcdab>>15)
|
||||||
readFail(1)
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user