Add sbuf.
This commit is contained in:
144
sbuf/sbuf.go
Normal file
144
sbuf/sbuf.go
Normal file
@@ -0,0 +1,144 @@
|
||||
// Package sbuf implements a byte buffer that can be wiped. The underlying
|
||||
// byte slice is wiped on read before being declaimed, and when the
|
||||
// buffer is closed, its storage is zeroised.
|
||||
package sbuf
|
||||
|
||||
import "io"
|
||||
|
||||
func zero(in []byte, n int) {
|
||||
if in == nil {
|
||||
return
|
||||
}
|
||||
|
||||
stop := n
|
||||
if stop > len(in) || stop == 0 {
|
||||
stop = len(in)
|
||||
}
|
||||
|
||||
for i := 0; i < stop; i++ {
|
||||
in[i] ^= in[i]
|
||||
}
|
||||
}
|
||||
|
||||
// A Buffer is a variable-sized buffer of bytes with Read and Write
|
||||
// methods. The zero value for Buffer is an empty buffer ready to use.
|
||||
type Buffer struct {
|
||||
buf []byte
|
||||
}
|
||||
|
||||
// NewBuffer creates a new buffer with the specified capacity.
|
||||
func NewBuffer(n int) *Buffer {
|
||||
return &Buffer{
|
||||
buf: make([]byte, 0, n),
|
||||
}
|
||||
}
|
||||
|
||||
// NewBufferFrom creates a new buffer from the byte slice passed in. The
|
||||
// original data will be wiped.
|
||||
func NewBufferFrom(p []byte) *Buffer {
|
||||
buf := NewBuffer(len(p))
|
||||
buf.Write(p)
|
||||
zero(p, len(p))
|
||||
return buf
|
||||
}
|
||||
|
||||
// Read reads the next len(p) bytes from the buffer or until the buffer
|
||||
// is drained. The return value n is the number of bytes read. If the
|
||||
// buffer has no data to return, err is io.EOF (unless len(p) is zero);
|
||||
// otherwise it is nil.
|
||||
func (buf *Buffer) Read(p []byte) (int, error) {
|
||||
if len(buf.buf) == 0 {
|
||||
if len(p) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
copyLength := len(p)
|
||||
if copyLength > len(buf.buf) {
|
||||
copyLength = len(buf.buf)
|
||||
}
|
||||
|
||||
copy(p, buf.buf)
|
||||
zero(buf.buf, len(p))
|
||||
buf.buf = buf.buf[copyLength:]
|
||||
return copyLength, nil
|
||||
}
|
||||
|
||||
// ReadByte reads the next byte from the buffer. If the buffer has no
|
||||
// data to return, err is io.EOF; otherwise it is nil.
|
||||
func (buf *Buffer) ReadByte() (byte, error) {
|
||||
if len(buf.buf) == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
c := buf.buf[0]
|
||||
buf.buf[0] = 0
|
||||
buf.buf = buf.buf[1:]
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (buf *Buffer) grow(n int) {
|
||||
tmp := make([]byte, len(buf.buf), len(buf.buf)+n)
|
||||
copy(tmp, buf.buf)
|
||||
zero(buf.buf, len(buf.buf))
|
||||
buf.buf = tmp
|
||||
}
|
||||
|
||||
// Write appends the contents of p to the buffer, growing the buffer
|
||||
// as needed. The return value n is the length of p; err is always nil.
|
||||
func (buf *Buffer) Write(p []byte) (int, error) {
|
||||
r := len(buf.buf) + len(p)
|
||||
if cap(buf.buf) < r {
|
||||
l := r
|
||||
for {
|
||||
if l > r {
|
||||
break
|
||||
}
|
||||
l *= 2
|
||||
}
|
||||
buf.grow(l - cap(buf.buf))
|
||||
}
|
||||
buf.buf = append(buf.buf, p...)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// WriteByte adds the byte c to the buffer, growing the buffer as needed.
|
||||
func (buf *Buffer) WriteByte(c byte) error {
|
||||
r := len(buf.buf) + 1
|
||||
if cap(buf.buf) < r {
|
||||
l := r * 2
|
||||
buf.grow(l - cap(buf.buf))
|
||||
}
|
||||
buf.buf = append(buf.buf, c)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close destroys and zeroises the buffer. The buffer will be re-opened
|
||||
// on the next write.
|
||||
func (buf *Buffer) Close() {
|
||||
zero(buf.buf, len(buf.buf))
|
||||
buf.buf = nil
|
||||
}
|
||||
|
||||
// Len returns the length of the buffer.
|
||||
func (buf *Buffer) Len() int {
|
||||
return len(buf.buf)
|
||||
}
|
||||
|
||||
// Cap returns the capacity of the buffer.
|
||||
func (buf *Buffer) Cap() int {
|
||||
return cap(buf.buf)
|
||||
}
|
||||
|
||||
// Bytes returns the bytes currently in the buffer, and closes itself.
|
||||
func (buf *Buffer) Bytes() []byte {
|
||||
if buf.buf == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
p := make([]byte, buf.Len())
|
||||
buf.Read(p)
|
||||
buf.Close()
|
||||
return p
|
||||
}
|
||||
Reference in New Issue
Block a user