package zos import ( "bytes" "io" "os" ) func min(a int, b int) int { if a < b { return a } return b } type FReader struct { io io.Reader buf []byte r, w int err error } func NewReader(io io.Reader) *FReader { return &FReader{ io: io, buf: make([]byte, 4096), r: 0, w: 0, } } func (b *FReader) Read(data []byte) (int, error) { n, rn := len(data), 0 for rn < n { d := min(b.w-b.r, n-rn) if d > 0 { copy(data[rn:rn+d], b.buf[b.r:b.r+d]) b.r += d rn += d if rn >= n { break } } err := b.fill() if err != nil { return rn, err } } return rn, nil } func (b *FReader) ReadLine() ([]byte, error) { line, err := b.ReadSlice('\n') i := len(line) - 1 if i >= 0 && line[i] == '\r' { return line[:i], err } return line, err } func (b *FReader) ReadLineFast() ([]byte, error) { line, err := b.ReadSliceFast('\n') i := len(line) - 1 if i >= 0 && line[i] == '\r' { return line[:i], err } return line, err } func (b *FReader) ReadSlice(delim byte) ([]byte, error) { var lines []byte for { line, err := b.ReadSliceFast(delim) if err == nil || err != ErrBufferFull { return line, err } lines = append(lines, line...) } return lines, nil } func (b *FReader) ReadSliceFast(delim byte) ([]byte, error) { for { // Search buffer. if i := bytes.IndexByte(b.buf[b.r+0:b.w], delim); i >= 0 { i += 1 b.r += i return b.buf[b.r-i : b.r-1], nil } err := b.fill() if err != nil { return b.buf[b.r:], err } } } func (b *FReader) fill() error { d := b.w - b.r if d >= len(b.buf) { b.r = 0 b.w = 0 return ErrBufferFull } // Slide existing data to beginning. if b.r > 0 { copy(b.buf, b.buf[b.r:b.w]) b.w -= b.r b.r = 0 } // Read new data: try a limited number of times. n, err := b.io.Read(b.buf[b.w:]) b.w += n return err } func (b *FReader) Clear() { b.r = 0 b.w = 0 } func (b *FReader) Seek(pos, offset int) { r := b.r + offset if r >= 0 && r <= b.w { b.r = r return } f, ok := b.io.(*os.File) if ok { f.Seek(int64(pos), 0) b.r = 0 b.w = 0 } }