mirror of
https://github.com/blacktop/ipsw.git
synced 2026-05-08 12:22:26 +00:00
135 lines
3.6 KiB
Go
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
|
|
}
|