open-vault/helper/compressutil/compress.go

75 lines
1.9 KiB
Go
Raw Normal View History

package compressutil
import (
"bytes"
"compress/lzw"
"fmt"
"io"
"log"
)
const (
CompressionCanaryJSON byte = 'Z'
)
func Compress(data []byte, canary byte) ([]byte, error) {
// Create a buffer and place the canary as its first byte
var buf bytes.Buffer
buf.Write([]byte{canary})
// Create writer to compress the JSON encoded bytes
writer := lzw.NewWriter(&buf, lzw.LSB, 8)
// Compress the JSON bytes
if _, err := writer.Write(data); err != nil {
return nil, fmt.Errorf("failed to compress JSON string; err: %v", err)
}
// Close the io.WriteCloser
if err := writer.Close(); err != nil {
return nil, err
}
log.Printf("compressutil.Compress: len(compressedBytes): %d\n", len(buf.Bytes()))
// Return the compressed bytes with canary byte at the start
return buf.Bytes(), nil
}
func Decompress(data []byte, canary byte) ([]byte, bool, error) {
if data == nil || len(data) < 2 {
return nil, false, fmt.Errorf("'data' being decompressed is invalid")
}
// Read the first byte
bytesReader := bytes.NewReader(data)
firstByte, err := bytesReader.ReadByte()
if err != nil {
return nil, false, fmt.Errorf("failed to read the first byte from the input")
}
// If the first byte doesn't match the canaryByte, it means that the
// content was not compressed in the first place. Try JSON decoding it.
if canary != firstByte {
return nil, true, nil
} else {
// If the first byte matches the canaryByte, remove the canary
// byte and try to decompress the data before JSON decoding it.
data = data[1:]
}
// Create a reader to read the compressed data
reader := lzw.NewReader(bytes.NewReader(data), lzw.LSB, 8)
// Close the io.ReadCloser
defer reader.Close()
// Read all the compressed data into a buffer
var jsonBuf bytes.Buffer
if _, err := io.Copy(&jsonBuf, reader); err != nil {
return nil, false, err
}
return jsonBuf.Bytes(), false, nil
}