| // Copyright 2015 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package elf | |
| import ( | |
| "io" | |
| "os" | |
| ) | |
| // errorReader returns error from all operations. | |
| type errorReader struct { | |
| error error | |
| } | |
| func (r errorReader) Read(p []byte) (n int, err error) { | |
| return 0, r.error | |
| } | |
| func (r errorReader) ReadAt(p []byte, off int64) (n int, err error) { | |
| return 0, r.error | |
| } | |
| func (r errorReader) Seek(offset int64, whence int) (int64, error) { | |
| return 0, r.error | |
| } | |
| func (r errorReader) Close() error { | |
| return r.error | |
| } | |
| // readSeekerFromReader converts an io.Reader into an io.ReadSeeker. | |
| // In general Seek may not be efficient, but it is optimized for | |
| // common cases such as seeking to the end to find the length of the | |
| // data. | |
| type readSeekerFromReader struct { | |
| reset func() (io.Reader, error) | |
| r io.Reader | |
| size int64 | |
| offset int64 | |
| } | |
| func (r *readSeekerFromReader) start() { | |
| x, err := r.reset() | |
| if err != nil { | |
| r.r = errorReader{err} | |
| } else { | |
| r.r = x | |
| } | |
| r.offset = 0 | |
| } | |
| func (r *readSeekerFromReader) Read(p []byte) (n int, err error) { | |
| if r.r == nil { | |
| r.start() | |
| } | |
| n, err = r.r.Read(p) | |
| r.offset += int64(n) | |
| return n, err | |
| } | |
| func (r *readSeekerFromReader) Seek(offset int64, whence int) (int64, error) { | |
| var newOffset int64 | |
| switch whence { | |
| case io.SeekStart: | |
| newOffset = offset | |
| case io.SeekCurrent: | |
| newOffset = r.offset + offset | |
| case io.SeekEnd: | |
| newOffset = r.size + offset | |
| default: | |
| return 0, os.ErrInvalid | |
| } | |
| switch { | |
| case newOffset == r.offset: | |
| return newOffset, nil | |
| case newOffset < 0, newOffset > r.size: | |
| return 0, os.ErrInvalid | |
| case newOffset == 0: | |
| r.r = nil | |
| case newOffset == r.size: | |
| r.r = errorReader{io.EOF} | |
| default: | |
| if newOffset < r.offset { | |
| // Restart at the beginning. | |
| r.start() | |
| } | |
| // Read until we reach offset. | |
| var buf [512]byte | |
| for r.offset < newOffset { | |
| b := buf[:] | |
| if newOffset-r.offset < int64(len(buf)) { | |
| b = buf[:newOffset-r.offset] | |
| } | |
| if _, err := r.Read(b); err != nil { | |
| return 0, err | |
| } | |
| } | |
| } | |
| r.offset = newOffset | |
| return r.offset, nil | |
| } |