package bitio import ( "errors" "io" ) // IOBitReadSeeker is a bitio.ReadAtSeeker reading from a io.ReadSeeker. type IOBitReadSeeker struct { bitPos int64 rs io.ReadSeeker buf []byte } // NewIOBitReadSeeker returns a new bitio.IOBitReadSeeker func NewIOBitReadSeeker(rs io.ReadSeeker) *IOBitReadSeeker { return &IOBitReadSeeker{ bitPos: 0, rs: rs, } } func (r *IOBitReadSeeker) ReadBitsAt(p []byte, nBits int64, bitOffset int64) (int64, error) { if nBits < 0 { return 0, ErrNegativeNBits } readBytePos := bitOffset / 8 readSkipBits := bitOffset % 8 wantReadBits := readSkipBits + nBits wantReadBytes := int(BitsByteCount(wantReadBits)) if wantReadBytes > len(r.buf) { // TODO: use append somehow? r.buf = make([]byte, wantReadBytes) } _, err := r.rs.Seek(readBytePos, io.SeekStart) if err != nil { return 0, err } // TODO: nBits should be available readBytes, err := io.ReadFull(r.rs, r.buf[0:wantReadBytes]) if err != nil && !errors.Is(err, io.ErrUnexpectedEOF) { return 0, err } else if errors.Is(err, io.ErrUnexpectedEOF) { nBits = int64(readBytes) * 8 err = io.EOF } if readSkipBits == 0 && nBits%8 == 0 { copy(p[0:readBytes], r.buf[0:readBytes]) return nBits, err } nBytes := nBits / 8 restBits := nBits % 8 // TODO: copy smartness if many bytes for i := int64(0); i < nBytes; i++ { p[i] = byte(Read64(r.buf, readSkipBits+i*8, 8)) } if restBits != 0 { p[nBytes] = byte(Read64(r.buf, readSkipBits+nBytes*8, restBits)) << (8 - restBits) } return nBits, err } func (r *IOBitReadSeeker) ReadBits(p []byte, nBits int64) (n int64, err error) { rBits, err := r.ReadBitsAt(p, nBits, r.bitPos) r.bitPos += rBits return rBits, err } func (r *IOBitReadSeeker) SeekBits(bitOff int64, whence int) (int64, error) { seekBytesPos, err := r.rs.Seek(bitOff/8, whence) if err != nil { return 0, err } seekBitPos := seekBytesPos*8 + bitOff%8 r.bitPos = seekBitPos return seekBitPos, nil } func (r *IOBitReadSeeker) CloneReader() (Reader, error) { return r.CloneReaderAtSeeker() } func (r *IOBitReadSeeker) CloneReadSeeker() (ReadSeeker, error) { return r.CloneReaderAtSeeker() } func (r *IOBitReadSeeker) CloneReadAtSeeker() (ReadAtSeeker, error) { return r.CloneReaderAtSeeker() } func (r *IOBitReadSeeker) CloneReaderAtSeeker() (ReaderAtSeeker, error) { return NewIOBitReadSeeker(r.rs), nil }