mirror of
https://github.com/wader/fq.git
synced 2024-12-26 15:02:28 +03:00
76 lines
1.5 KiB
Go
76 lines
1.5 KiB
Go
package bitio
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
)
|
|
|
|
// IOReader is a io.Reader and io.ByteReader that reads from a bitio.Reader.
|
|
// Unaligned byte at EOF will be zero bit padded.
|
|
type IOReader struct {
|
|
r Reader
|
|
rErr error
|
|
b Buffer
|
|
}
|
|
|
|
// NewIOReader returns a new bitio.IOReader.
|
|
func NewIOReader(r Reader) *IOReader {
|
|
return &IOReader{r: r}
|
|
}
|
|
|
|
func (r *IOReader) Read(p []byte) (n int, err error) {
|
|
var ns int64
|
|
|
|
for {
|
|
// uses p even if returning nothing, io.Reader docs says:
|
|
// "it may use all of p as scratch space during the call"
|
|
if r.rErr == nil {
|
|
var rn int64
|
|
rn, err = r.r.ReadBits(p, int64(len(p))*8)
|
|
r.rErr = err
|
|
ns += rn
|
|
_, err = r.b.WriteBits(p, rn)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
}
|
|
|
|
if r.b.Len() >= 8 {
|
|
// read whole bytes
|
|
rBits := int64(len(p)) * 8
|
|
bBits := r.b.Len()
|
|
aBits := bBits - bBits%8
|
|
if rBits > aBits {
|
|
rBits = aBits
|
|
}
|
|
|
|
rn, rErr := r.b.ReadBits(p, rBits)
|
|
if rErr != nil {
|
|
return int(rn / 8), rErr
|
|
}
|
|
return int(rn / 8), nil
|
|
} else if r.rErr != nil {
|
|
if errors.Is(r.rErr, io.EOF) && r.b.Len() > 0 {
|
|
// TODO: hmm io.Buffer does this
|
|
if len(p) == 0 {
|
|
return 0, nil
|
|
}
|
|
|
|
_, err := r.b.ReadBits(p, r.b.Len())
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return 1, r.rErr
|
|
}
|
|
return 0, r.rErr
|
|
}
|
|
}
|
|
}
|
|
|
|
// required to make some readers like deflate not do their own buffering
|
|
func (r *IOReader) ReadByte() (byte, error) {
|
|
var rb [1]byte
|
|
_, err := r.Read(rb[:])
|
|
return rb[0], err
|
|
}
|