tbotd/vendor/src/github.com/Sereal/Sereal/Go/sereal/zlib.go

70 lines
1.6 KiB
Go

package sereal
import (
"compress/zlib"
"math"
)
// ZlibCompressor compresses a Sereal document using the zlib format.
type ZlibCompressor struct {
Level int // compression level, set to ZlibDefaultCompression by default
}
// Zlib constants
const (
ZlibBestSpeed = zlib.BestSpeed
ZlibBestCompression = zlib.BestCompression
ZlibDefaultCompression = zlib.DefaultCompression
)
func (c ZlibCompressor) compress(buf []byte) ([]byte, error) {
// Prepend a compressed block with its length, i.e.:
//
// <Varint><Varint><Zlib Blob>
// 1st varint indicates the length of the uncompressed document,
// 2nd varint indicates the length of the compressed document.
//
// XXX It's the naive implementation, better to rework as described in the spec:
// https://github.com/Sereal/Sereal/blob/master/sereal_spec.pod#encoding-the-length-of-compressed-documents
if c.Level == 0 {
c.Level = ZlibDefaultCompression
}
tail, err := zlibEncode(buf, c.Level)
if err != nil {
return nil, err
}
var head []byte
head = varint(head, uint(len(buf)))
head = varint(head, uint(len(tail)))
return append(head, tail...), nil
}
func (c ZlibCompressor) decompress(buf []byte) ([]byte, error) {
// Read the claimed length of the uncompressed document
uln, usz, err := varintdecode(buf)
if err != nil {
return nil, err
}
buf = buf[usz:]
// Read the claimed length of the compressed document
cln, csz, err := varintdecode(buf)
if err != nil {
return nil, err
}
if cln < 0 || cln > math.MaxInt32 || csz+cln > len(buf) {
return nil, ErrCorrupt{errBadOffset}
}
buf = buf[csz : csz+cln]
// XXX Perhaps check if len(buf) == cln
return zlibDecode(uln, buf)
}