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  }