Files
kopia/repo/compression/compressor.go
Jarek Kowalski 38d01d4c4d compression: added 'lz4' and 'deflate' methods (#1077)
* compression: add mapping from HeaderID to Name

* compression: minor refactoring

* compression: added 'lz4' based on 'github.com/pierrec/lz4'

* compression: added 'deflate' support

* cli: 'kopia benchmark compression' improvements
2021-05-16 14:42:56 -07:00

82 lines
1.9 KiB
Go

// Package compression manages compression algorithm implementations.
package compression
import (
"bytes"
"encoding/binary"
"fmt"
"github.com/pkg/errors"
)
const compressionHeaderSize = 4
// Name is the name of the compressor to use.
type Name string
// Compressor implements compression and decompression of a byte slice.
type Compressor interface {
HeaderID() HeaderID
Compress(output *bytes.Buffer, input []byte) error
Decompress(output *bytes.Buffer, input []byte) error
}
// maps of registered compressors by header ID and name.
var (
ByHeaderID = map[HeaderID]Compressor{}
ByName = map[Name]Compressor{}
HeaderIDToName = map[HeaderID]Name{}
)
// RegisterCompressor registers the provided compressor implementation.
func RegisterCompressor(name Name, c Compressor) {
if ByHeaderID[c.HeaderID()] != nil {
panic(fmt.Sprintf("compressor with HeaderID %x already registered", c.HeaderID()))
}
if ByName[name] != nil {
panic(fmt.Sprintf("compressor with name %q already registered", name))
}
ByHeaderID[c.HeaderID()] = c
ByName[name] = c
HeaderIDToName[c.HeaderID()] = name
}
func compressionHeader(id HeaderID) []byte {
b := make([]byte, 4)
binary.BigEndian.PutUint32(b, uint32(id))
return b
}
// IDFromHeader retrieves compression ID from content header.
func IDFromHeader(b []byte) (HeaderID, error) {
if len(b) < compressionHeaderSize {
return 0, errors.Errorf("invalid size: %v", len(b))
}
return HeaderID(binary.BigEndian.Uint32(b[0:compressionHeaderSize])), nil
}
func mustSucceed(err error) {
if err != nil {
panic("unexpected error: " + err.Error())
}
}
func verifyCompressionHeader(got, want []byte) error {
if !bytes.HasPrefix(got, want) {
var gotHeader []byte
if len(got) >= len(want) {
gotHeader = got[0:len(want)]
} else {
gotHeader = got
}
return errors.Errorf("invalid compression header, expected %x but got %x (len %v)", want, gotHeader, len(got))
}
return nil
}