reader.mx raw

   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 io.SeekStart:
  67  		newOffset = offset
  68  	case io.SeekCurrent:
  69  		newOffset = r.offset + offset
  70  	case io.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