mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
Implement a real Seek() method in the slicereader helper (prior to this it had a simplified SeekTo function), so that slicereader's will satisfy the ReadSeeker interface (needed in a subsequent patch). Change-Id: I832e3ec1e34d0f8c6b5edf390470f6f943c6ece0 Reviewed-on: https://go-review.googlesource.com/c/go/+/495438 Run-TryBot: Than McIntosh <thanm@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: David Chase <drchase@google.com>
123 lines
2.5 KiB
Go
123 lines
2.5 KiB
Go
// Copyright 2021 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 slicereader
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
"unsafe"
|
|
)
|
|
|
|
// This file contains the helper "SliceReader", a utility for
|
|
// reading values from a byte slice that may or may not be backed
|
|
// by a read-only mmap'd region.
|
|
|
|
type Reader struct {
|
|
b []byte
|
|
readonly bool
|
|
off int64
|
|
}
|
|
|
|
func NewReader(b []byte, readonly bool) *Reader {
|
|
r := Reader{
|
|
b: b,
|
|
readonly: readonly,
|
|
}
|
|
return &r
|
|
}
|
|
|
|
func (r *Reader) Read(b []byte) (int, error) {
|
|
amt := len(b)
|
|
toread := r.b[r.off:]
|
|
if len(toread) < amt {
|
|
amt = len(toread)
|
|
}
|
|
copy(b, toread)
|
|
r.off += int64(amt)
|
|
return amt, nil
|
|
}
|
|
|
|
func (r *Reader) Seek(offset int64, whence int) (ret int64, err error) {
|
|
switch whence {
|
|
case io.SeekStart:
|
|
if offset < 0 || offset > int64(len(r.b)) {
|
|
return 0, fmt.Errorf("invalid seek: new offset %d (out of range [0 %d]", offset, len(r.b))
|
|
}
|
|
r.off = offset
|
|
return offset, nil
|
|
case io.SeekCurrent:
|
|
newoff := r.off + offset
|
|
if newoff < 0 || newoff > int64(len(r.b)) {
|
|
return 0, fmt.Errorf("invalid seek: new offset %d (out of range [0 %d]", newoff, len(r.b))
|
|
}
|
|
r.off = newoff
|
|
return r.off, nil
|
|
case io.SeekEnd:
|
|
newoff := int64(len(r.b)) + offset
|
|
if newoff < 0 || newoff > int64(len(r.b)) {
|
|
return 0, fmt.Errorf("invalid seek: new offset %d (out of range [0 %d]", newoff, len(r.b))
|
|
}
|
|
r.off = newoff
|
|
return r.off, nil
|
|
}
|
|
// other modes are not supported
|
|
return 0, fmt.Errorf("unsupported seek mode %d", whence)
|
|
}
|
|
|
|
func (r *Reader) Offset() int64 {
|
|
return r.off
|
|
}
|
|
|
|
func (r *Reader) ReadUint8() uint8 {
|
|
rv := uint8(r.b[int(r.off)])
|
|
r.off += 1
|
|
return rv
|
|
}
|
|
|
|
func (r *Reader) ReadUint32() uint32 {
|
|
end := int(r.off) + 4
|
|
rv := binary.LittleEndian.Uint32(r.b[int(r.off):end:end])
|
|
r.off += 4
|
|
return rv
|
|
}
|
|
|
|
func (r *Reader) ReadUint64() uint64 {
|
|
end := int(r.off) + 8
|
|
rv := binary.LittleEndian.Uint64(r.b[int(r.off):end:end])
|
|
r.off += 8
|
|
return rv
|
|
}
|
|
|
|
func (r *Reader) ReadULEB128() (value uint64) {
|
|
var shift uint
|
|
|
|
for {
|
|
b := r.b[r.off]
|
|
r.off++
|
|
value |= (uint64(b&0x7F) << shift)
|
|
if b&0x80 == 0 {
|
|
break
|
|
}
|
|
shift += 7
|
|
}
|
|
return
|
|
}
|
|
|
|
func (r *Reader) ReadString(len int64) string {
|
|
b := r.b[r.off : r.off+len]
|
|
r.off += len
|
|
if r.readonly {
|
|
return toString(b) // backed by RO memory, ok to make unsafe string
|
|
}
|
|
return string(b)
|
|
}
|
|
|
|
func toString(b []byte) string {
|
|
if len(b) == 0 {
|
|
return ""
|
|
}
|
|
return unsafe.String(&b[0], len(b))
|
|
}
|