Skip to content

Commit

Permalink
Merge pull request #50 from DataDog/elijah/fix-empty-0.5
Browse files Browse the repository at this point in the history
backport #42 to 0.5.x (Correctly handle compressing empty slice), handle decompressing empty byte slice
  • Loading branch information
elijahandrews authored Jan 16, 2019
2 parents 2b373cb + 269e708 commit 0013387
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 11 deletions.
32 changes: 23 additions & 9 deletions zstd.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,22 +107,33 @@ func Compress(dst, src []byte) ([]byte, error) {

// CompressLevel is the same as Compress but you can pass a compression level
func CompressLevel(dst, src []byte, level int) ([]byte, error) {
if len(src) == 0 {
return []byte{}, ErrEmptySlice
}
bound := CompressBound(len(src))
if cap(dst) >= bound {
dst = dst[0:bound] // Reuse dst buffer
} else {
dst = make([]byte, bound)
}

cWritten := C.ZSTD_compress(
unsafe.Pointer(&dst[0]),
C.size_t(len(dst)),
unsafe.Pointer(&src[0]),
C.size_t(len(src)),
C.int(level))
var cWritten C.size_t
if len(src) > 0 {
cWritten = C.ZSTD_compress(
unsafe.Pointer(&dst[0]),
C.size_t(len(dst)),
unsafe.Pointer(&src[0]),
C.size_t(len(src)),
C.int(level))
} else {
// Special case for when src is empty.
// If you refactor this, careful not to store unsafe.Pointer(nil) in a
// variable or else you'll hit
// https://github.com/golang/go/issues/28606
cWritten = C.ZSTD_compress(
unsafe.Pointer(&dst[0]),
C.size_t(len(dst)),
unsafe.Pointer(nil),
C.size_t(len(src)),
C.int(level))
}

written := int(cWritten)
// Check if the return is an Error code
Expand All @@ -139,6 +150,9 @@ func CompressLevel(dst, src []byte, level int) ([]byte, error) {
// 3 times before falling back to the slower stream API (ie. if the compression
// ratio is 32).
func Decompress(dst, src []byte) ([]byte, error) {
if len(src) == 0 {
return []byte{}, ErrEmptySlice
}
decompress := func(dst, src []byte) ([]byte, error) {

cWritten := C.ZSTD_decompress(
Expand Down
22 changes: 22 additions & 0 deletions zstd_stream_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package zstd
import (
"bytes"
"io"
"io/ioutil"
"testing"
)

Expand Down Expand Up @@ -125,6 +126,27 @@ func TestStreamRealPayload(t *testing.T) {
testCompressionDecompression(t, nil, raw)
}

func TestStreamEmptyPayload(t *testing.T) {
w := bytes.NewBuffer(nil)
writer := NewWriter(w)
_, err := writer.Write(nil)
failOnError(t, "failed to write empty slice", err)
err = writer.Close()
failOnError(t, "failed to close", err)
compressed := w.Bytes()
t.Logf("compressed buffer: 0x%x", compressed)
// Now recheck that if we decompress, we get empty slice
r := bytes.NewBuffer(compressed)
reader := NewReader(r)
decompressed, err := ioutil.ReadAll(reader)
failOnError(t, "failed to read", err)
err = reader.Close()
failOnError(t, "failed to close", err)
if string(decompressed) != "" {
t.Fatalf("Expected empty slice as decompressed, got %v instead", decompressed)
}
}

func BenchmarkStreamCompression(b *testing.B) {
if raw == nil {
b.Fatal(ErrNoPayloadEnv)
Expand Down
19 changes: 17 additions & 2 deletions zstd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,23 @@ func TestCompressDecompress(t *testing.T) {
}
}

func TestEmptySlice(t *testing.T) {
_, err := Compress(nil, []byte{})
func TestEmptySliceCompress(t *testing.T) {
compressed, err := Compress(nil, []byte{})
if err != nil {
t.Fatalf("Error while compressing: %v", err)
}
t.Logf("Compressing empty slice gives 0x%x", compressed)
decompressed, err := Decompress(nil, compressed)
if err != nil {
t.Fatalf("Error while compressing: %v", err)
}
if string(decompressed) != "" {
t.Fatalf("Expected empty slice as decompressed, got %v instead", decompressed)
}
}

func TestEmptySliceDecompress(t *testing.T) {
_, err := Decompress(nil, []byte{})
if err != ErrEmptySlice {
t.Fatalf("Did not get the correct error: %s", err)
}
Expand Down

0 comments on commit 0013387

Please sign in to comment.