github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/lib/readers/fakeseeker.go (about) 1 package readers 2 3 import ( 4 "errors" 5 "fmt" 6 "io" 7 ) 8 9 // FakeSeeker adapts an io.Seeker into an io.ReadSeeker 10 type FakeSeeker struct { 11 in io.Reader 12 readErr error 13 length int64 14 offset int64 15 read bool 16 } 17 18 // NewFakeSeeker creates a fake io.ReadSeeker from an io.Reader 19 // 20 // This can be seeked before reading to discover the length passed in. 21 func NewFakeSeeker(in io.Reader, length int64) io.ReadSeeker { 22 if rs, ok := in.(io.ReadSeeker); ok { 23 return rs 24 } 25 return &FakeSeeker{ 26 in: in, 27 length: length, 28 } 29 } 30 31 // Seek the stream - possible only before reading 32 func (r *FakeSeeker) Seek(offset int64, whence int) (abs int64, err error) { 33 if r.readErr != nil { 34 return 0, r.readErr 35 } 36 if r.read { 37 return 0, fmt.Errorf("FakeSeeker: can't Seek(%d, %d) after reading", offset, whence) 38 } 39 switch whence { 40 case io.SeekStart: 41 abs = offset 42 case io.SeekCurrent: 43 abs = r.offset + offset 44 case io.SeekEnd: 45 abs = r.length + offset 46 default: 47 return 0, errors.New("FakeSeeker: invalid whence") 48 } 49 if abs < 0 { 50 return 0, errors.New("FakeSeeker: negative position") 51 } 52 r.offset = abs 53 return abs, nil 54 } 55 56 // Read data from the stream. Will give an error if seeked. 57 func (r *FakeSeeker) Read(p []byte) (n int, err error) { 58 if r.readErr != nil { 59 return 0, r.readErr 60 } 61 if !r.read && r.offset != 0 { 62 return 0, errors.New("FakeSeeker: not at start: can't read") 63 } 64 n, err = r.in.Read(p) 65 if n != 0 { 66 r.read = true 67 } 68 if err != nil { 69 r.readErr = err 70 } 71 return n, err 72 }