Files
ipsw/internal/buffer/buffer.go
2020-02-19 21:18:41 -05:00

135 lines
3.6 KiB
Go

package buffer
import (
"errors"
"io"
)
// ReadWriteBuffer is a simple type that implements io.WriterAt on an in-memory buffer.
// The zero value of this type is an empty buffer ready to use.
type ReadWriteBuffer struct {
d []byte
i int64 // current reading index
m int
}
// NewReadWriteBuffer creates and returns a new ReadWriteBuffer with the given initial size and
// maximum. If maximum is <= 0 it is unlimited.
func NewReadWriteBuffer(size, max int) *ReadWriteBuffer {
if max < size && max >= 0 {
max = size
}
return &ReadWriteBuffer{make([]byte, size), 0, max}
}
// Reset resets the Reader to be reading from b.
func (rw *ReadWriteBuffer) Reset(b []byte) {
*rw = ReadWriteBuffer{b, 0, rw.m}
}
// Len returns the number of bytes of the unread portion of the
// slice.
func (rw *ReadWriteBuffer) Len() int {
if rw.i >= int64(len(rw.d)) {
return 0
}
return int(int64(len(rw.d)) - rw.i)
}
// Size returns the original length of the underlying byte slice.
// Size is the number of bytes available for reading via ReadAt.
// The returned value is always the same and is not affected by calls
// to any other method.
func (rw *ReadWriteBuffer) Size() int64 { return int64(len(rw.d)) }
// SetMax sets the maximum capacity of the ReadWriteBuffer. If the provided maximum is lower
// than the current capacity but greater than 0 it is set to the current capacity, if
// less than or equal to zero it is unlimited..
func (rw *ReadWriteBuffer) SetMax(max int) {
if max < len(rw.d) && max >= 0 {
max = len(rw.d)
}
rw.m = max
}
// Bytes returns the ReadWriteBuffer's underlying data. This value will remain valid so long
// as no other methods are called on the ReadWriteBuffer.
func (rw *ReadWriteBuffer) Bytes() []byte {
return rw.d
}
// Shape returns the current ReadWriteBuffer size and its maximum if one was provided.
func (rw *ReadWriteBuffer) Shape() (int, int) {
return len(rw.d), rw.m
}
// WriteAt implements the io.WriterAt interface.
func (rw *ReadWriteBuffer) WriteAt(dat []byte, off int64) (int, error) {
if int(off) < 0 {
return 0, errors.New("buffer.ReadWriteBuffer.ReadAt: negative offset")
}
if int(off)+len(dat) >= rw.m && rw.m > 0 {
return 0, errors.New("buffer.ReadWriteBuffer.ReadAt: offset out of range")
}
// Check fast path extension
if int(off) == len(rw.d) {
rw.d = append(rw.d, dat...)
return len(dat), nil
}
// Check slower path extension
if int(off)+len(dat) >= len(rw.d) {
nd := make([]byte, int(off)+len(dat))
copy(nd, rw.d)
rw.d = nd
}
// Once no extension is needed just copy bytes into place.
copy(rw.d[int(off):], dat)
return len(dat), nil
}
// Read implements the io.Reader interface.
func (rw *ReadWriteBuffer) Read(b []byte) (n int, err error) {
if rw.i >= int64(len(rw.d)) {
return 0, io.EOF
}
n = copy(b, rw.d[rw.i:])
rw.i += int64(n)
return
}
// ReadAt implements the io.ReaderAt interface.
func (rw *ReadWriteBuffer) ReadAt(b []byte, off int64) (n int, err error) {
// cannot modify state - see io.ReaderAt
if off < 0 {
return 0, errors.New("buffer.ReadWriteBuffer.ReadAt: negative offset")
}
if off >= int64(len(rw.d)) {
return 0, io.EOF
}
n = copy(b, rw.d[off:])
if n < len(b) {
err = io.EOF
}
return
}
// Seek implements the io.Seeker interface.
func (rw *ReadWriteBuffer) Seek(offset int64, whence int) (int64, error) {
var abs int64
switch whence {
case io.SeekStart:
abs = offset
case io.SeekCurrent:
abs = rw.i + offset
case io.SeekEnd:
abs = int64(len(rw.d)) + offset
default:
return 0, errors.New("buffer.ReadWriteBuffer.Seek: invalid whence")
}
if abs < 0 {
return 0, errors.New("buffer.ReadWriteBuffer.Seek: negative position")
}
rw.i = abs
return abs, nil
}