mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-07-28 16:01:05 +00:00
TUN-528: Move cloudflared into a separate repo
This commit is contained in:
334
vendor/zombiezen.com/go/capnproto2/internal/packed/packed.go
generated
vendored
Normal file
334
vendor/zombiezen.com/go/capnproto2/internal/packed/packed.go
generated
vendored
Normal file
@@ -0,0 +1,334 @@
|
||||
// Package packed provides functions to read and write the "packed"
|
||||
// compression scheme described at https://capnproto.org/encoding.html#packing.
|
||||
package packed
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
const wordSize = 8
|
||||
|
||||
// Special case tags.
|
||||
const (
|
||||
zeroTag byte = 0x00
|
||||
unpackedTag byte = 0xff
|
||||
)
|
||||
|
||||
// Pack appends the packed version of src to dst and returns the
|
||||
// resulting slice. len(src) must be a multiple of 8 or Pack panics.
|
||||
func Pack(dst, src []byte) []byte {
|
||||
if len(src)%wordSize != 0 {
|
||||
panic("packed.Pack len(src) must be a multiple of 8")
|
||||
}
|
||||
var buf [wordSize]byte
|
||||
for len(src) > 0 {
|
||||
var hdr byte
|
||||
n := 0
|
||||
for i := uint(0); i < wordSize; i++ {
|
||||
if src[i] != 0 {
|
||||
hdr |= 1 << i
|
||||
buf[n] = src[i]
|
||||
n++
|
||||
}
|
||||
}
|
||||
dst = append(dst, hdr)
|
||||
dst = append(dst, buf[:n]...)
|
||||
src = src[wordSize:]
|
||||
|
||||
switch hdr {
|
||||
case zeroTag:
|
||||
z := min(numZeroWords(src), 0xff)
|
||||
dst = append(dst, byte(z))
|
||||
src = src[z*wordSize:]
|
||||
case unpackedTag:
|
||||
i := 0
|
||||
end := min(len(src), 0xff*wordSize)
|
||||
for i < end {
|
||||
zeros := 0
|
||||
for _, b := range src[i : i+wordSize] {
|
||||
if b == 0 {
|
||||
zeros++
|
||||
}
|
||||
}
|
||||
|
||||
if zeros > 1 {
|
||||
break
|
||||
}
|
||||
i += wordSize
|
||||
}
|
||||
|
||||
rawWords := byte(i / wordSize)
|
||||
dst = append(dst, rawWords)
|
||||
dst = append(dst, src[:i]...)
|
||||
src = src[i:]
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// numZeroWords returns the number of leading zero words in b.
|
||||
func numZeroWords(b []byte) int {
|
||||
for i, bb := range b {
|
||||
if bb != 0 {
|
||||
return i / wordSize
|
||||
}
|
||||
}
|
||||
return len(b) / wordSize
|
||||
}
|
||||
|
||||
// Unpack appends the unpacked version of src to dst and returns the
|
||||
// resulting slice.
|
||||
func Unpack(dst, src []byte) ([]byte, error) {
|
||||
for len(src) > 0 {
|
||||
tag := src[0]
|
||||
src = src[1:]
|
||||
|
||||
pstart := len(dst)
|
||||
dst = allocWords(dst, 1)
|
||||
p := dst[pstart : pstart+wordSize]
|
||||
if len(src) >= wordSize {
|
||||
i := 0
|
||||
nz := tag & 1
|
||||
p[0] = src[i] & -nz
|
||||
i += int(nz)
|
||||
nz = tag >> 1 & 1
|
||||
p[1] = src[i] & -nz
|
||||
i += int(nz)
|
||||
nz = tag >> 2 & 1
|
||||
p[2] = src[i] & -nz
|
||||
i += int(nz)
|
||||
nz = tag >> 3 & 1
|
||||
p[3] = src[i] & -nz
|
||||
i += int(nz)
|
||||
nz = tag >> 4 & 1
|
||||
p[4] = src[i] & -nz
|
||||
i += int(nz)
|
||||
nz = tag >> 5 & 1
|
||||
p[5] = src[i] & -nz
|
||||
i += int(nz)
|
||||
nz = tag >> 6 & 1
|
||||
p[6] = src[i] & -nz
|
||||
i += int(nz)
|
||||
nz = tag >> 7 & 1
|
||||
p[7] = src[i] & -nz
|
||||
i += int(nz)
|
||||
src = src[i:]
|
||||
} else {
|
||||
for i := uint(0); i < wordSize; i++ {
|
||||
if tag&(1<<i) == 0 {
|
||||
continue
|
||||
}
|
||||
if len(src) == 0 {
|
||||
return dst, io.ErrUnexpectedEOF
|
||||
}
|
||||
p[i] = src[0]
|
||||
src = src[1:]
|
||||
}
|
||||
}
|
||||
switch tag {
|
||||
case zeroTag:
|
||||
if len(src) == 0 {
|
||||
return dst, io.ErrUnexpectedEOF
|
||||
}
|
||||
dst = allocWords(dst, int(src[0]))
|
||||
src = src[1:]
|
||||
case unpackedTag:
|
||||
if len(src) == 0 {
|
||||
return dst, io.ErrUnexpectedEOF
|
||||
}
|
||||
start := len(dst)
|
||||
dst = allocWords(dst, int(src[0]))
|
||||
src = src[1:]
|
||||
n := copy(dst[start:], src)
|
||||
src = src[n:]
|
||||
}
|
||||
}
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
func allocWords(p []byte, n int) []byte {
|
||||
target := len(p) + n*wordSize
|
||||
if cap(p) >= target {
|
||||
pp := p[len(p):target]
|
||||
for i := range pp {
|
||||
pp[i] = 0
|
||||
}
|
||||
return p[:target]
|
||||
}
|
||||
newcap := cap(p)
|
||||
doublecap := newcap + newcap
|
||||
if target > doublecap {
|
||||
newcap = target
|
||||
} else {
|
||||
if len(p) < 1024 {
|
||||
newcap = doublecap
|
||||
} else {
|
||||
for newcap < target {
|
||||
newcap += newcap / 4
|
||||
}
|
||||
}
|
||||
}
|
||||
pp := make([]byte, target, newcap)
|
||||
copy(pp, p)
|
||||
return pp
|
||||
}
|
||||
|
||||
// A Reader decompresses a packed byte stream.
|
||||
type Reader struct {
|
||||
// ReadWord state
|
||||
rd *bufio.Reader
|
||||
err error
|
||||
zeroes int
|
||||
literal int
|
||||
|
||||
// Read state
|
||||
word [wordSize]byte
|
||||
wordIdx int
|
||||
}
|
||||
|
||||
// NewReader returns a reader that decompresses a packed stream from r.
|
||||
func NewReader(r *bufio.Reader) *Reader {
|
||||
return &Reader{rd: r, wordIdx: wordSize}
|
||||
}
|
||||
|
||||
func min(a, b int) int {
|
||||
if b < a {
|
||||
return b
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// ReadWord decompresses the next word from the underlying stream.
|
||||
func (r *Reader) ReadWord(p []byte) error {
|
||||
if len(p) < wordSize {
|
||||
return errors.New("packed: read word buffer too small")
|
||||
}
|
||||
r.wordIdx = wordSize // if the caller tries to call ReadWord and Read, don't give them partial words.
|
||||
if r.err != nil {
|
||||
err := r.err
|
||||
r.err = nil
|
||||
return err
|
||||
}
|
||||
p = p[:wordSize]
|
||||
switch {
|
||||
case r.zeroes > 0:
|
||||
r.zeroes--
|
||||
for i := range p {
|
||||
p[i] = 0
|
||||
}
|
||||
return nil
|
||||
case r.literal > 0:
|
||||
r.literal--
|
||||
_, err := io.ReadFull(r.rd, p)
|
||||
return err
|
||||
}
|
||||
|
||||
var tag byte
|
||||
if r.rd.Buffered() < wordSize+1 {
|
||||
var err error
|
||||
tag, err = r.rd.ReadByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i := range p {
|
||||
p[i] = 0
|
||||
}
|
||||
for i := uint(0); i < wordSize; i++ {
|
||||
if tag&(1<<i) != 0 {
|
||||
p[i], err = r.rd.ReadByte()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
p[i] = 0
|
||||
}
|
||||
}
|
||||
} else {
|
||||
b, _ := r.rd.Peek(wordSize + 1)
|
||||
tag = b[0]
|
||||
i := 1
|
||||
nz := tag & 1
|
||||
p[0] = b[i] & -nz
|
||||
i += int(nz)
|
||||
nz = tag >> 1 & 1
|
||||
p[1] = b[i] & -nz
|
||||
i += int(nz)
|
||||
nz = tag >> 2 & 1
|
||||
p[2] = b[i] & -nz
|
||||
i += int(nz)
|
||||
nz = tag >> 3 & 1
|
||||
p[3] = b[i] & -nz
|
||||
i += int(nz)
|
||||
nz = tag >> 4 & 1
|
||||
p[4] = b[i] & -nz
|
||||
i += int(nz)
|
||||
nz = tag >> 5 & 1
|
||||
p[5] = b[i] & -nz
|
||||
i += int(nz)
|
||||
nz = tag >> 6 & 1
|
||||
p[6] = b[i] & -nz
|
||||
i += int(nz)
|
||||
nz = tag >> 7 & 1
|
||||
p[7] = b[i] & -nz
|
||||
i += int(nz)
|
||||
discard(r.rd, i)
|
||||
}
|
||||
switch tag {
|
||||
case zeroTag:
|
||||
z, err := r.rd.ReadByte()
|
||||
if err == io.EOF {
|
||||
r.err = io.ErrUnexpectedEOF
|
||||
return nil
|
||||
} else if err != nil {
|
||||
r.err = err
|
||||
return nil
|
||||
}
|
||||
r.zeroes = int(z)
|
||||
case unpackedTag:
|
||||
l, err := r.rd.ReadByte()
|
||||
if err == io.EOF {
|
||||
r.err = io.ErrUnexpectedEOF
|
||||
return nil
|
||||
} else if err != nil {
|
||||
r.err = err
|
||||
return nil
|
||||
}
|
||||
r.literal = int(l)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read reads up to len(p) bytes into p. This will decompress whole
|
||||
// words at a time, so mixing calls to Read and ReadWord may lead to
|
||||
// bytes missing.
|
||||
func (r *Reader) Read(p []byte) (n int, err error) {
|
||||
if r.wordIdx < wordSize {
|
||||
n = copy(p, r.word[r.wordIdx:])
|
||||
r.wordIdx += n
|
||||
}
|
||||
for n < len(p) {
|
||||
if r.rd.Buffered() < wordSize+1 && n > 0 {
|
||||
return n, nil
|
||||
}
|
||||
if len(p)-n >= wordSize {
|
||||
err := r.ReadWord(p[n:])
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
n += wordSize
|
||||
} else {
|
||||
err := r.ReadWord(r.word[:])
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
r.wordIdx = copy(p[n:], r.word[:])
|
||||
n += r.wordIdx
|
||||
}
|
||||
}
|
||||
return n, nil
|
||||
}
|
Reference in New Issue
Block a user