Skip to content

Commit ea68dca

Browse files
authored
Merge pull request #130 from jbowens/decompress-into
add DecompressInto for decompression of payloads with known sizes
2 parents 5f14d6a + 81cb63c commit ea68dca

File tree

2 files changed

+46
-6
lines changed

2 files changed

+46
-6
lines changed

zstd.go

+17-6
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,7 @@ func Decompress(dst, src []byte) ([]byte, error) {
143143
dst = make([]byte, bound)
144144
}
145145

146-
written := int(C.ZSTD_decompress(
147-
unsafe.Pointer(&dst[0]),
148-
C.size_t(len(dst)),
149-
unsafe.Pointer(&src[0]),
150-
C.size_t(len(src))))
151-
err := getError(written)
146+
written, err := DecompressInto(dst, src)
152147
if err == nil {
153148
return dst[:written], nil
154149
}
@@ -161,3 +156,19 @@ func Decompress(dst, src []byte) ([]byte, error) {
161156
defer r.Close()
162157
return ioutil.ReadAll(r)
163158
}
159+
160+
// DecompressInto decompresses src into dst. Unlike Decompress, DecompressInto
161+
// requires that dst be sufficiently large to hold the decompressed payload.
162+
// DecompressInto may be used when the caller knows the size of the decompressed
163+
// payload before attempting decompression.
164+
//
165+
// It returns the number of bytes copied and an error if any is encountered. If
166+
// dst is too small, DecompressInto errors.
167+
func DecompressInto(dst, src []byte) (int, error) {
168+
written := int(C.ZSTD_decompress(
169+
unsafe.Pointer(&dst[0]),
170+
C.size_t(len(dst)),
171+
unsafe.Pointer(&src[0]),
172+
C.size_t(len(src))))
173+
return written, getError(written)
174+
}

zstd_test.go

+29
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,35 @@ func TestCompressDecompress(t *testing.T) {
8787
}
8888
}
8989

90+
func TestCompressDecompressInto(t *testing.T) {
91+
payload := []byte("Hello World!")
92+
compressed, err := Compress(make([]byte, CompressBound(len(payload))), payload)
93+
if err != nil {
94+
t.Fatalf("Error while compressing: %v", err)
95+
}
96+
t.Logf("Compressed: %v", compressed)
97+
98+
// We know the size of the payload; construct a buffer that perfectly fits
99+
// the payload and use DecompressInto.
100+
decompressed := make([]byte, len(payload))
101+
if n, err := DecompressInto(decompressed, compressed); err != nil {
102+
t.Fatalf("error while decompressing into buffer of size %d: %v",
103+
len(decompressed), err)
104+
} else if n != len(decompressed) {
105+
t.Errorf("DecompressedInto = (%d, nil), want (%d, nil)", n, len(decompressed))
106+
}
107+
if !bytes.Equal(payload, decompressed) {
108+
t.Fatalf("DecompressInto(_, Compress(_, %q)) yielded %q, want %q", payload, decompressed, payload)
109+
}
110+
111+
// Ensure that decompressing into a buffer too small errors appropriately.
112+
smallBuffer := make([]byte, len(payload)-1)
113+
if _, err := DecompressInto(smallBuffer, compressed); !IsDstSizeTooSmallError(err) {
114+
t.Fatalf("DecompressInto(<%d-sized buffer>, Compress(_, %q)) = %v, want 'Destination buffer is too small'",
115+
len(smallBuffer), payload, err)
116+
}
117+
}
118+
90119
func TestCompressLevel(t *testing.T) {
91120
inputs := [][]byte{
92121
nil, {}, {0}, []byte("Hello World!"),

0 commit comments

Comments
 (0)