Source file src/internal/coverage/slicereader/slicereader.go

     1  // Copyright 2021 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 slicereader
     6  
     7  import (
     8  	"encoding/binary"
     9  	"fmt"
    10  	"io"
    11  	"unsafe"
    12  )
    13  
    14  // This file contains the helper "SliceReader", a utility for
    15  // reading values from a byte slice that may or may not be backed
    16  // by a read-only mmap'd region.
    17  
    18  type Reader struct {
    19  	b        []byte
    20  	readonly bool
    21  	off      int64
    22  }
    23  
    24  func NewReader(b []byte, readonly bool) *Reader {
    25  	r := Reader{
    26  		b:        b,
    27  		readonly: readonly,
    28  	}
    29  	return &r
    30  }
    31  
    32  func (r *Reader) Read(b []byte) (int, error) {
    33  	amt := len(b)
    34  	toread := r.b[r.off:]
    35  	if len(toread) < amt {
    36  		amt = len(toread)
    37  	}
    38  	copy(b, toread)
    39  	r.off += int64(amt)
    40  	return amt, nil
    41  }
    42  
    43  func (r *Reader) Seek(offset int64, whence int) (ret int64, err error) {
    44  	switch whence {
    45  	case io.SeekStart:
    46  		if offset < 0 || offset > int64(len(r.b)) {
    47  			return 0, fmt.Errorf("invalid seek: new offset %d (out of range [0 %d]", offset, len(r.b))
    48  		}
    49  		r.off = offset
    50  		return offset, nil
    51  	case io.SeekCurrent:
    52  		newoff := r.off + offset
    53  		if newoff < 0 || newoff > int64(len(r.b)) {
    54  			return 0, fmt.Errorf("invalid seek: new offset %d (out of range [0 %d]", newoff, len(r.b))
    55  		}
    56  		r.off = newoff
    57  		return r.off, nil
    58  	case io.SeekEnd:
    59  		newoff := int64(len(r.b)) + offset
    60  		if newoff < 0 || newoff > int64(len(r.b)) {
    61  			return 0, fmt.Errorf("invalid seek: new offset %d (out of range [0 %d]", newoff, len(r.b))
    62  		}
    63  		r.off = newoff
    64  		return r.off, nil
    65  	}
    66  	// other modes are not supported
    67  	return 0, fmt.Errorf("unsupported seek mode %d", whence)
    68  }
    69  
    70  func (r *Reader) Offset() int64 {
    71  	return r.off
    72  }
    73  
    74  func (r *Reader) ReadUint8() uint8 {
    75  	rv := uint8(r.b[int(r.off)])
    76  	r.off += 1
    77  	return rv
    78  }
    79  
    80  func (r *Reader) ReadUint32() uint32 {
    81  	end := int(r.off) + 4
    82  	rv := binary.LittleEndian.Uint32(r.b[int(r.off):end:end])
    83  	r.off += 4
    84  	return rv
    85  }
    86  
    87  func (r *Reader) ReadUint64() uint64 {
    88  	end := int(r.off) + 8
    89  	rv := binary.LittleEndian.Uint64(r.b[int(r.off):end:end])
    90  	r.off += 8
    91  	return rv
    92  }
    93  
    94  func (r *Reader) ReadULEB128() (value uint64) {
    95  	var shift uint
    96  
    97  	for {
    98  		b := r.b[r.off]
    99  		r.off++
   100  		value |= (uint64(b&0x7F) << shift)
   101  		if b&0x80 == 0 {
   102  			break
   103  		}
   104  		shift += 7
   105  	}
   106  	return
   107  }
   108  
   109  func (r *Reader) ReadString(len int64) string {
   110  	b := r.b[r.off : r.off+len]
   111  	r.off += len
   112  	if r.readonly {
   113  		return toString(b) // backed by RO memory, ok to make unsafe string
   114  	}
   115  	return string(b)
   116  }
   117  
   118  func toString(b []byte) string {
   119  	if len(b) == 0 {
   120  		return ""
   121  	}
   122  	return unsafe.String(&b[0], len(b))
   123  }
   124  

View as plain text