Source file src/debug/elf/reader.go

     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  

View as plain text