128 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			128 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								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
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 |