Home | History | Annotate | Download | only in elf
      1 // Copyright 2015 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package elf
      6 
      7 import (
      8 	"io"
      9 	"os"
     10 )
     11 
     12 // errorReader returns error from all operations.
     13 type errorReader struct {
     14 	error
     15 }
     16 
     17 func (r errorReader) Read(p []byte) (n int, err error) {
     18 	return 0, r.error
     19 }
     20 
     21 func (r errorReader) ReadAt(p []byte, off int64) (n int, err error) {
     22 	return 0, r.error
     23 }
     24 
     25 func (r errorReader) Seek(offset int64, whence int) (int64, error) {
     26 	return 0, r.error
     27 }
     28 
     29 func (r errorReader) Close() error {
     30 	return r.error
     31 }
     32 
     33 // readSeekerFromReader converts an io.Reader into an io.ReadSeeker.
     34 // In general Seek may not be efficient, but it is optimized for
     35 // common cases such as seeking to the end to find the length of the
     36 // data.
     37 type readSeekerFromReader struct {
     38 	reset  func() (io.Reader, error)
     39 	r      io.Reader
     40 	size   int64
     41 	offset int64
     42 }
     43 
     44 func (r *readSeekerFromReader) start() {
     45 	x, err := r.reset()
     46 	if err != nil {
     47 		r.r = errorReader{err}
     48 	} else {
     49 		r.r = x
     50 	}
     51 	r.offset = 0
     52 }
     53 
     54 func (r *readSeekerFromReader) Read(p []byte) (n int, err error) {
     55 	if r.r == nil {
     56 		r.start()
     57 	}
     58 	n, err = r.r.Read(p)
     59 	r.offset += int64(n)
     60 	return n, err
     61 }
     62 
     63 func (r *readSeekerFromReader) Seek(offset int64, whence int) (int64, error) {
     64 	var newOffset int64
     65 	switch whence {
     66 	case seekStart:
     67 		newOffset = offset
     68 	case seekCurrent:
     69 		newOffset = r.offset + offset
     70 	case seekEnd:
     71 		newOffset = r.size + offset
     72 	default:
     73 		return 0, os.ErrInvalid
     74 	}
     75 
     76 	switch {
     77 	case newOffset == r.offset:
     78 		return newOffset, nil
     79 
     80 	case newOffset < 0, newOffset > r.size:
     81 		return 0, os.ErrInvalid
     82 
     83 	case newOffset == 0:
     84 		r.r = nil
     85 
     86 	case newOffset == r.size:
     87 		r.r = errorReader{io.EOF}
     88 
     89 	default:
     90 		if newOffset < r.offset {
     91 			// Restart at the beginning.
     92 			r.start()
     93 		}
     94 		// Read until we reach offset.
     95 		var buf [512]byte
     96 		for r.offset < newOffset {
     97 			b := buf[:]
     98 			if newOffset-r.offset < int64(len(buf)) {
     99 				b = buf[:newOffset-r.offset]
    100 			}
    101 			if _, err := r.Read(b); err != nil {
    102 				return 0, err
    103 			}
    104 		}
    105 	}
    106 	r.offset = newOffset
    107 	return r.offset, nil
    108 }
    109