ziggs/vendor/git.tcp.direct/kayos/common/squish/squish.go

99 lines
2.1 KiB
Go

package squish
import (
"bytes"
"compress/gzip"
"encoding/base64"
"errors"
"io"
"sync"
)
var (
bufPool = &sync.Pool{
New: func() interface{} {
return &bytes.Buffer{}
},
}
gzipPool = &sync.Pool{
New: func() interface{} {
return gzip.NewWriter(nil)
},
}
)
// Gzip compresses as slice of bytes using gzip compression.
func Gzip(data []byte) []byte {
buf := bufPool.Get().(*bytes.Buffer)
gz := gzipPool.Get().(*gzip.Writer)
buf.Reset()
r, w := io.Pipe()
gz.Reset(w)
go func() {
_, _ = gz.Write(data)
_ = gz.Close()
_ = w.Close()
}()
n, _ := buf.ReadFrom(r)
buf.Truncate(int(n))
_ = r.Close()
res, _ := io.ReadAll(buf)
bufPool.Put(buf)
gzipPool.Put(gz)
return res
}
// Gunzip decompresses a gzip compressed slice of bytes.
func Gunzip(data []byte) (out []byte, err error) {
gz, err := gzip.NewReader(bytes.NewReader(data))
if err != nil {
return nil, err
}
buf := bufPool.Get().(*bytes.Buffer)
buf.Reset()
var n int64
n, _ = buf.ReadFrom(gz)
err = gz.Close()
buf.Truncate(int(n))
res, _ := io.ReadAll(buf)
bufPool.Put(buf)
return res, err
}
// B64e encodes the given slice of bytes into base64 standard encoding.
func B64e(in []byte) (out string) {
buf := bufPool.Get().(*bytes.Buffer)
buf.Reset()
buf.Grow(base64.StdEncoding.EncodedLen(len(in)))
b64 := base64.NewEncoder(base64.StdEncoding, buf)
_, _ = b64.Write(in)
_ = b64.Close()
res := buf.Bytes()
bufPool.Put(buf)
return string(res)
}
// B64d decodes the given string into the original slice of bytes.
// Do note that this is for non critical tasks, it has no error handling for purposes of clean code.
func B64d(str string) (data []byte) {
if len(str) == 0 {
return nil
}
data, _ = base64.StdEncoding.DecodeString(str)
return data
}
// UnpackStr UNsafely unpacks (usually banners) that have been base64'd and then gzip'd.
func UnpackStr(encoded string) (string, error) {
one := B64d(encoded)
if len(one) == 0 {
return "", errors.New("0 length base64 decoding result")
}
dcytes, err := Gunzip(one)
if err != nil && !errors.Is(err, io.EOF) {
return "", err
}
return string(dcytes), nil
}