diff --git a/bit/reader.go b/bit/reader.go index 78771ed..3e39f99 100644 --- a/bit/reader.go +++ b/bit/reader.go @@ -49,4 +49,25 @@ func (r *Reader) ReadBits(bits uint) (n uint64) { return } +// ReadByte reads a single byte, regardless of alignment. +func (r *Reader) ReadByte() (byte, error) { + b := byte(r.ReadBits(8)) + if err := r.Err(); err != nil { + return 0, err + } + return b, nil +} + +// Read reads like an io.Reader, taking care of alignment internally. +func (r *Reader) Read(buf []byte) (int, error) { + for i := 0; i < len(buf); i++ { + b, err := r.ReadByte() + if err != nil { + return 0, err + } + buf[i] = b + } + return len(buf), nil +} + func (r *Reader) Err() error { return r.err } diff --git a/bit/reader_test.go b/bit/reader_test.go index 4460c61..31398db 100644 --- a/bit/reader_test.go +++ b/bit/reader_test.go @@ -11,7 +11,8 @@ var ( badFood = []byte{0x8b, 0xad, 0xf0, 0x0d} ) -func TestRead(t *testing.T) { +// test the bit-level reads +func TestReadBits(t *testing.T) { assert := assert.New(t) var r *Reader @@ -50,3 +51,22 @@ func TestRead(t *testing.T) { // ^----------^ assert.Equal(uint64(0xd), r.ReadBits(10)) } + +// test the Read calls, satisfying io.Reader +func TestRead(t *testing.T) { + assert := assert.New(t) + var r *Reader + + r = NewBytesReader(badFood) + // 1000 1011 1010 1101 1111 0000 0000 1101 + r.ReadBits(1) + // 0001 0111 0101 1011 1110 0000 0001 101 + buf := make([]byte, 3) + + n, err := r.Read(buf) + assert.NoError(err) + assert.Equal(3, n) + + expected := []byte{0x17, 0x5b, 0xe0} + assert.Equal(expected, buf) +}