mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-01 15:00:00 +00:00
98 lines
1.7 KiB
Go
98 lines
1.7 KiB
Go
|
package bitio
|
||
|
|
||
|
import "io"
|
||
|
|
||
|
type Reader interface {
|
||
|
io.Reader
|
||
|
|
||
|
// alignment:
|
||
|
// |-1-byte-block-|--------------|--------------|--------------|
|
||
|
// |<-offset->|<-------------------width---------------------->|
|
||
|
ReadBits(width uint) (data []byte, err error)
|
||
|
|
||
|
ReadBit() (bit bool, err error)
|
||
|
}
|
||
|
|
||
|
type ReadSeeker interface {
|
||
|
Reader
|
||
|
io.Seeker
|
||
|
}
|
||
|
|
||
|
type reader struct {
|
||
|
reader io.Reader
|
||
|
octet byte
|
||
|
width uint
|
||
|
}
|
||
|
|
||
|
func NewReader(r io.Reader) Reader {
|
||
|
return &reader{reader: r}
|
||
|
}
|
||
|
|
||
|
func (r *reader) Read(p []byte) (n int, err error) {
|
||
|
if r.width != 0 {
|
||
|
return 0, ErrInvalidAlignment
|
||
|
}
|
||
|
return r.reader.Read(p)
|
||
|
}
|
||
|
|
||
|
func (r *reader) ReadBits(size uint) ([]byte, error) {
|
||
|
bytes := (size + 7) / 8
|
||
|
data := make([]byte, bytes)
|
||
|
offset := (bytes * 8) - (size)
|
||
|
|
||
|
for i := uint(0); i < size; i++ {
|
||
|
bit, err := r.ReadBit()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
byteIdx := (offset + i) / 8
|
||
|
bitIdx := 7 - (offset+i)%8
|
||
|
if bit {
|
||
|
data[byteIdx] |= 0x1 << bitIdx
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return data, nil
|
||
|
}
|
||
|
|
||
|
func (r *reader) ReadBit() (bool, error) {
|
||
|
if r.width == 0 {
|
||
|
buf := make([]byte, 1)
|
||
|
if n, err := r.reader.Read(buf); err != nil {
|
||
|
return false, err
|
||
|
} else if n != 1 {
|
||
|
return false, ErrDiscouragedReader
|
||
|
}
|
||
|
r.octet = buf[0]
|
||
|
r.width = 8
|
||
|
}
|
||
|
|
||
|
r.width--
|
||
|
return (r.octet>>r.width)&0x01 != 0, nil
|
||
|
}
|
||
|
|
||
|
type readSeeker struct {
|
||
|
reader
|
||
|
seeker io.Seeker
|
||
|
}
|
||
|
|
||
|
func NewReadSeeker(r io.ReadSeeker) ReadSeeker {
|
||
|
return &readSeeker{
|
||
|
reader: reader{reader: r},
|
||
|
seeker: r,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (r *readSeeker) Seek(offset int64, whence int) (int64, error) {
|
||
|
if whence == io.SeekCurrent && r.reader.width != 0 {
|
||
|
return 0, ErrInvalidAlignment
|
||
|
}
|
||
|
n, err := r.seeker.Seek(offset, whence)
|
||
|
if err != nil {
|
||
|
return n, err
|
||
|
}
|
||
|
r.reader.width = 0
|
||
|
return n, nil
|
||
|
}
|