mirror of
https://github.com/rclone/rclone.git
synced 2024-11-29 20:04:52 +01:00
73 lines
1.5 KiB
Go
73 lines
1.5 KiB
Go
|
package readers
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
)
|
||
|
|
||
|
// FakeSeeker adapts an io.Seeker into an io.ReadSeeker
|
||
|
type FakeSeeker struct {
|
||
|
in io.Reader
|
||
|
readErr error
|
||
|
length int64
|
||
|
offset int64
|
||
|
read bool
|
||
|
}
|
||
|
|
||
|
// NewFakeSeeker creates a fake io.ReadSeeker from an io.Reader
|
||
|
//
|
||
|
// This can be seeked before reading to discover the length passed in.
|
||
|
func NewFakeSeeker(in io.Reader, length int64) io.ReadSeeker {
|
||
|
if rs, ok := in.(io.ReadSeeker); ok {
|
||
|
return rs
|
||
|
}
|
||
|
return &FakeSeeker{
|
||
|
in: in,
|
||
|
length: length,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Seek the stream - possible only before reading
|
||
|
func (r *FakeSeeker) Seek(offset int64, whence int) (abs int64, err error) {
|
||
|
if r.readErr != nil {
|
||
|
return 0, r.readErr
|
||
|
}
|
||
|
if r.read {
|
||
|
return 0, fmt.Errorf("FakeSeeker: can't Seek(%d, %d) after reading", offset, whence)
|
||
|
}
|
||
|
switch whence {
|
||
|
case io.SeekStart:
|
||
|
abs = offset
|
||
|
case io.SeekCurrent:
|
||
|
abs = r.offset + offset
|
||
|
case io.SeekEnd:
|
||
|
abs = r.length + offset
|
||
|
default:
|
||
|
return 0, errors.New("FakeSeeker: invalid whence")
|
||
|
}
|
||
|
if abs < 0 {
|
||
|
return 0, errors.New("FakeSeeker: negative position")
|
||
|
}
|
||
|
r.offset = abs
|
||
|
return abs, nil
|
||
|
}
|
||
|
|
||
|
// Read data from the stream. Will give an error if seeked.
|
||
|
func (r *FakeSeeker) Read(p []byte) (n int, err error) {
|
||
|
if r.readErr != nil {
|
||
|
return 0, r.readErr
|
||
|
}
|
||
|
if !r.read && r.offset != 0 {
|
||
|
return 0, errors.New("FakeSeeker: not at start: can't read")
|
||
|
}
|
||
|
n, err = r.in.Read(p)
|
||
|
if n != 0 {
|
||
|
r.read = true
|
||
|
}
|
||
|
if err != nil {
|
||
|
r.readErr = err
|
||
|
}
|
||
|
return n, err
|
||
|
}
|