mirror of
https://github.com/SagerNet/sing.git
synced 2025-04-03 20:07:38 +03:00
322 lines
5.3 KiB
Go
322 lines
5.3 KiB
Go
package buf
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"fmt"
|
|
"io"
|
|
"sing/common/list"
|
|
|
|
"sing/common"
|
|
)
|
|
|
|
type Buffer struct {
|
|
data []byte
|
|
start int
|
|
end int
|
|
managed bool
|
|
}
|
|
|
|
func New() *Buffer {
|
|
return &Buffer{
|
|
data: GetBytes(),
|
|
start: ReversedHeader,
|
|
end: ReversedHeader,
|
|
managed: true,
|
|
}
|
|
}
|
|
|
|
func StackNew() Buffer {
|
|
return Buffer{
|
|
data: GetBytes(),
|
|
managed: true,
|
|
}
|
|
}
|
|
|
|
func From(data []byte) *Buffer {
|
|
buffer := New()
|
|
buffer.Write(data)
|
|
return buffer
|
|
}
|
|
|
|
func As(data []byte) *Buffer {
|
|
size := len(data)
|
|
max := cap(data)
|
|
if size != max {
|
|
data = data[:max]
|
|
}
|
|
return &Buffer{
|
|
data: data,
|
|
end: size,
|
|
}
|
|
}
|
|
|
|
func With(data []byte) *Buffer {
|
|
return &Buffer{
|
|
data: data,
|
|
}
|
|
}
|
|
|
|
func (b *Buffer) Byte(index int) byte {
|
|
return b.data[b.start+index]
|
|
}
|
|
|
|
func (b *Buffer) SetByte(index int, value byte) {
|
|
b.data[b.start+index] = value
|
|
}
|
|
|
|
func (b *Buffer) Extend(n int) []byte {
|
|
if b.start == b.end {
|
|
b.start = 0
|
|
b.end = n
|
|
return b.data[:n]
|
|
}
|
|
end := b.end + n
|
|
ext := b.data[b.end:end]
|
|
b.end = end
|
|
return ext
|
|
}
|
|
|
|
func (b *Buffer) Advance(from int) {
|
|
b.start += from
|
|
}
|
|
|
|
func (b *Buffer) Truncate(to int) {
|
|
b.end = b.start + to
|
|
}
|
|
|
|
func (b *Buffer) Write(data []byte) (n int, err error) {
|
|
if b.IsFull() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
n = copy(b.data[b.end:], data)
|
|
b.end += n
|
|
return
|
|
}
|
|
|
|
func (b *Buffer) WriteAtFirst(data []byte) (n int, err error) {
|
|
size := len(data)
|
|
if b.start >= size {
|
|
n = copy(b.data[b.start-size:b.start], data)
|
|
b.start -= n
|
|
return
|
|
}
|
|
|
|
offset := size - b.start
|
|
copy(b.data[offset:], b.data[b.start:b.end])
|
|
n = copy(b.data[:offset], data)
|
|
b.end += offset
|
|
return
|
|
}
|
|
|
|
func (b *Buffer) WriteRandom(size int) {
|
|
common.Must1(io.ReadFull(rand.Reader, b.Extend(size)))
|
|
}
|
|
|
|
func (b *Buffer) WriteByte(byte byte) error {
|
|
if b.IsFull() {
|
|
return io.ErrShortBuffer
|
|
}
|
|
b.data[b.end] = byte
|
|
b.end++
|
|
return nil
|
|
}
|
|
|
|
func (b *Buffer) ReadFrom(r io.Reader) (int64, error) {
|
|
if b.IsFull() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
n, err := r.Read(b.FreeBytes())
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
b.end += n
|
|
return int64(n), nil
|
|
}
|
|
|
|
func (b *Buffer) ReadFullFrom(r io.Reader, size int) (n int, err error) {
|
|
if b.IsFull() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
end := b.end + size
|
|
n, err = io.ReadFull(r, b.data[b.start:end])
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
b.end += n
|
|
return
|
|
}
|
|
|
|
func (b *Buffer) WriteRune(s rune) (int, error) {
|
|
return b.Write([]byte{byte(s)})
|
|
}
|
|
|
|
func (b *Buffer) WriteString(s string) (int, error) {
|
|
return b.Write([]byte(s))
|
|
}
|
|
|
|
func (b *Buffer) WriteSprint(s ...any) (int, error) {
|
|
return b.WriteString(fmt.Sprint(s...))
|
|
}
|
|
|
|
func (b *Buffer) WriteZero() error {
|
|
if b.IsFull() {
|
|
return io.ErrShortBuffer
|
|
}
|
|
b.end++
|
|
b.data[b.end] = 0
|
|
return nil
|
|
}
|
|
|
|
func (b *Buffer) WriteZeroN(n int) error {
|
|
if b.end+n > b.Cap() {
|
|
return io.ErrShortBuffer
|
|
}
|
|
for i := b.end; i <= b.end+n; i++ {
|
|
b.data[i] = 0
|
|
}
|
|
b.end += n
|
|
return nil
|
|
}
|
|
|
|
func (b *Buffer) ReadByte() (byte, error) {
|
|
if b.IsEmpty() {
|
|
return 0, io.EOF
|
|
}
|
|
|
|
nb := b.data[b.start]
|
|
b.start++
|
|
return nb, nil
|
|
}
|
|
|
|
func (b *Buffer) ReadBytes(n int) ([]byte, error) {
|
|
if b.end-b.start < n {
|
|
return nil, io.EOF
|
|
}
|
|
|
|
nb := b.data[b.start : b.start+n]
|
|
b.start += n
|
|
return nb, nil
|
|
}
|
|
|
|
func (b *Buffer) Read(data []byte) (n int, err error) {
|
|
if b.Len() == 0 {
|
|
return 0, io.EOF
|
|
}
|
|
n = copy(data, b.data[b.start:b.end])
|
|
if n == b.Len() {
|
|
b.Reset()
|
|
} else {
|
|
b.start += n
|
|
}
|
|
return n, nil
|
|
}
|
|
|
|
func (b *Buffer) WriteTo(w io.Writer) (int64, error) {
|
|
n, err := w.Write(b.Bytes())
|
|
return int64(n), err
|
|
}
|
|
|
|
func (b *Buffer) Resize(start, end int) {
|
|
b.start = start
|
|
b.end = b.start + end
|
|
}
|
|
|
|
func (b *Buffer) Reset() {
|
|
b.start = ReversedHeader
|
|
b.end = ReversedHeader
|
|
}
|
|
|
|
func (b *Buffer) Release() {
|
|
if b == nil || b.data == nil || !b.managed {
|
|
return
|
|
}
|
|
PutBytes(b.data)
|
|
*b = Buffer{}
|
|
}
|
|
|
|
func (b Buffer) Len() int {
|
|
return b.end - b.start
|
|
}
|
|
|
|
func (b Buffer) Cap() int {
|
|
return cap(b.data)
|
|
}
|
|
|
|
func (b Buffer) Bytes() []byte {
|
|
return b.data[b.start:b.end]
|
|
}
|
|
|
|
func (b Buffer) Slice() []byte {
|
|
return b.data
|
|
}
|
|
|
|
func (b Buffer) From(n int) []byte {
|
|
return b.data[b.start+n : b.end]
|
|
}
|
|
|
|
func (b Buffer) To(n int) []byte {
|
|
return b.data[b.start : b.start+n]
|
|
}
|
|
|
|
func (b Buffer) Index(start int) []byte {
|
|
return b.data[b.start+start : b.start+start]
|
|
}
|
|
|
|
func (b Buffer) FreeLen() int {
|
|
return b.Cap() - b.end
|
|
}
|
|
|
|
func (b Buffer) FreeBytes() []byte {
|
|
return b.data[b.end:b.Cap()]
|
|
}
|
|
|
|
func (b Buffer) IsEmpty() bool {
|
|
return b.end-b.start == 0
|
|
}
|
|
|
|
func (b Buffer) IsFull() bool {
|
|
return b.end == b.Cap()
|
|
}
|
|
|
|
func (b Buffer) ToOwned() *Buffer {
|
|
var buffer *Buffer
|
|
if b.Len() > BufferSize {
|
|
buffer = As(make([]byte, b.Len()))
|
|
copy(buffer.data, b.Bytes())
|
|
} else {
|
|
buffer = New()
|
|
buffer.Write(b.Bytes())
|
|
}
|
|
return buffer
|
|
}
|
|
|
|
func (b Buffer) Copy() []byte {
|
|
buffer := make([]byte, b.Len())
|
|
copy(buffer, b.Bytes())
|
|
return buffer
|
|
}
|
|
|
|
func ReleaseMulti(mb *list.List[*Buffer]) {
|
|
for entry := mb.Front(); entry != nil; entry = entry.Next() {
|
|
// TODO: remove cast
|
|
var buffer *Buffer = entry.Value
|
|
buffer.Release()
|
|
}
|
|
}
|
|
|
|
func ForeachN(b []byte, size int) [][]byte {
|
|
total := len(b)
|
|
var index int
|
|
var retArr [][]byte
|
|
for {
|
|
nextIndex := index + size
|
|
if nextIndex < total {
|
|
retArr = append(retArr, b[index:nextIndex])
|
|
index = nextIndex
|
|
} else {
|
|
retArr = append(retArr, b[index:])
|
|
break
|
|
}
|
|
}
|
|
return retArr
|
|
}
|