package bufreader import ( "errors" "io" ) const ( maxReadAttempts = 5 defaultBufSize = 1024 ) var ( // ErrReadOverflow shows 100% bug in the source reader ErrReadOverflow = errors.New("bufreader: reader returned 'n' > bufsize") // ErrNegativeReadCount shows 100% bug in the source reader ErrNegativeReadCount = errors.New("bufreader: reader returned negative 'n'") ) type BufferedReader struct { r io.Reader buf []byte idx int end int totalRead int } func New(r io.Reader, bufsize int) *BufferedReader { if bufsize == 0 { bufsize = defaultBufSize } return &BufferedReader{ r: r, buf: make([]byte, bufsize), } } func (s *BufferedReader) safeRead(buf []byte) (n int, err error) { readAttempts := 0 for readAttempts < maxReadAttempts { n, err = s.r.Read(buf) if n > 0 { if n > len(buf) { return 0, ErrReadOverflow } if err == io.EOF { err = nil } return } if n < 0 { return 0, ErrNegativeReadCount } // n == 0 if err != nil { return } readAttempts++ } return 0, io.ErrNoProgress } func (s *BufferedReader) fill() error { n, err := s.safeRead(s.buf) s.idx = 0 s.end = n return err } func (s *BufferedReader) ReadByte() (b byte, err error) { if s.idx == s.end { if err = s.fill(); err != nil { return } } b = s.buf[s.idx] s.idx++ s.totalRead++ return } func (s *BufferedReader) Read(buf []byte) (int, error) { size := len(buf) buffered := s.end - s.idx if size <= buffered { for i, b := range s.buf[s.idx : s.idx+size] { buf[i] = b } s.idx += size s.totalRead += len(buf) return size, nil } for i, b := range s.buf[s.idx:s.end] { buf[i] = b } s.idx = 0 s.end = 0 n := buffered rbuf := buf[buffered:] var ( q int err error ) for n < size { q, err = s.safeRead(rbuf) n += q rbuf = rbuf[q:] if err != nil { if err == io.EOF && n == size { s.totalRead += len(buf) return n, nil } break } } s.totalRead += len(buf[:n]) return n, err } func (s *BufferedReader) ReadN(size int) ([]byte, error) { buf := make([]byte, size) _, err := s.Read(buf) if err != nil { return nil, err } return buf, nil } func (s *BufferedReader) TotalRead() int { return s.totalRead }