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.: // // // 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) }