15 type multiReadSeeker struct {
16 readers []io.ReadSeeker
18 posIdx map[io.ReadSeeker]int
21 func (r *multiReadSeeker) Seek(offset int64, whence int) (int64, error) {
25 for i, rdr := range r.readers {
26 // get size of the current reader
27 s, err := rdr.Seek(0, os.SEEK_END)
32 if offset > tmpOffset+s {
33 if i == len(r.readers)-1 {
34 rdrOffset := s + (offset - tmpOffset)
35 if _, err := rdr.Seek(rdrOffset, os.SEEK_SET); err != nil {
38 r.pos = &pos{i, rdrOffset}
46 rdrOffset := offset - tmpOffset
49 rdr.Seek(rdrOffset, os.SEEK_SET)
50 // make sure all following readers are at 0
51 for _, rdr := range r.readers[i+1:] {
52 rdr.Seek(0, os.SEEK_SET)
55 if rdrOffset == s && i != len(r.readers)-1 {
59 r.pos = &pos{idx, rdrOffset}
63 for _, rdr := range r.readers {
64 s, err := rdr.Seek(0, os.SEEK_END)
70 r.Seek(tmpOffset+offset, os.SEEK_SET)
71 return tmpOffset + offset, nil
74 return r.Seek(offset, os.SEEK_SET)
76 // Just return the current offset
78 return r.getCurOffset()
81 curOffset, err := r.getCurOffset()
85 rdr, rdrOffset, err := r.getReaderForOffset(curOffset + offset)
90 r.pos = &pos{r.posIdx[rdr], rdrOffset}
91 return curOffset + offset, nil
93 return -1, fmt.Errorf("Invalid whence: %d", whence)
96 return -1, fmt.Errorf("Error seeking for whence: %d, offset: %d", whence, offset)
99 func (r *multiReadSeeker) getReaderForOffset(offset int64) (io.ReadSeeker, int64, error) {
100 var rdr io.ReadSeeker
103 for i, rdr := range r.readers {
104 offsetTo, err := r.getOffsetToReader(rdr)
108 if offsetTo > offset {
110 rdrOffset = offsetTo - offset
114 if rdr == r.readers[len(r.readers)-1] {
115 rdrOffset = offsetTo + offset
120 return rdr, rdrOffset, nil
123 func (r *multiReadSeeker) getCurOffset() (int64, error) {
125 for _, rdr := range r.readers[:r.pos.idx+1] {
126 if r.posIdx[rdr] == r.pos.idx {
127 totalSize += r.pos.offset
131 size, err := getReadSeekerSize(rdr)
133 return -1, fmt.Errorf("error getting seeker size: %v", err)
137 return totalSize, nil
140 func (r *multiReadSeeker) getOffsetToReader(rdr io.ReadSeeker) (int64, error) {
142 for _, r := range r.readers {
147 size, err := getReadSeekerSize(rdr)
156 func (r *multiReadSeeker) Read(b []byte) (int, error) {
161 bCap := int64(cap(b))
162 buf := bytes.NewBuffer(nil)
163 var rdr io.ReadSeeker
165 for _, rdr = range r.readers[r.pos.idx:] {
166 readBytes, err := io.CopyN(buf, rdr, bCap)
167 if err != nil && err != io.EOF {
177 rdrPos, err := rdr.Seek(0, os.SEEK_CUR)
181 r.pos = &pos{r.posIdx[rdr], rdrPos}
185 func getReadSeekerSize(rdr io.ReadSeeker) (int64, error) {
186 // save the current position
187 pos, err := rdr.Seek(0, os.SEEK_CUR)
193 size, err := rdr.Seek(0, os.SEEK_END)
198 // reset the position
199 if _, err := rdr.Seek(pos, os.SEEK_SET); err != nil {
205 // MultiReadSeeker returns a ReadSeeker that's the logical concatenation of the provided
206 // input readseekers. After calling this method the initial position is set to the
207 // beginning of the first ReadSeeker. At the end of a ReadSeeker, Read always advances
208 // to the beginning of the next ReadSeeker and returns EOF at the end of the last ReadSeeker.
209 // Seek can be used over the sum of lengths of all readseekers.
211 // When a MultiReadSeeker is used, no Read and Seek operations should be made on
212 // its ReadSeeker components. Also, users should make no assumption on the state
213 // of individual readseekers while the MultiReadSeeker is used.
214 func MultiReadSeeker(readers ...io.ReadSeeker) io.ReadSeeker {
215 if len(readers) == 1 {
218 idx := make(map[io.ReadSeeker]int)
219 for i, rdr := range readers {
222 return &multiReadSeeker{