Commit b88f1713d01e5cca5a296d564ae094dd8bc6a1f2

Edward Thomson 2015-06-17T08:07:34

zstream: offer inflating, `git_zstream_inflatebuf` Introduce `git_zstream_inflatebuf` for simple uses.

diff --git a/src/pack-objects.c b/src/pack-objects.c
index 6f86deb..ec15970 100644
--- a/src/pack-objects.c
+++ b/src/pack-objects.c
@@ -144,7 +144,7 @@ int git_packbuilder_new(git_packbuilder **out, git_repository *repo)
 	pb->nr_threads = 1; /* do not spawn any thread by default */
 
 	if (git_hash_ctx_init(&pb->ctx) < 0 ||
-		git_zstream_init(&pb->zstream) < 0 ||
+		git_zstream_init(&pb->zstream, GIT_ZSTREAM_DEFLATE) < 0 ||
 		git_repository_odb(&pb->odb, repo) < 0 ||
 		packbuilder_config(pb) < 0)
 		goto on_error;
diff --git a/src/zstream.c b/src/zstream.c
index 2130bc3..6533449 100644
--- a/src/zstream.c
+++ b/src/zstream.c
@@ -28,20 +28,31 @@ static int zstream_seterr(git_zstream *zs)
 	return -1;
 }
 
-int git_zstream_init(git_zstream *zstream)
+int git_zstream_init(git_zstream *zstream, git_zstream_t type)
 {
-	zstream->zerr = deflateInit(&zstream->z, Z_DEFAULT_COMPRESSION);
+	zstream->type = type;
+
+	if (zstream->type == GIT_ZSTREAM_INFLATE)
+		zstream->zerr = inflateInit(&zstream->z);
+	else
+		zstream->zerr = deflateInit(&zstream->z, Z_DEFAULT_COMPRESSION);
 	return zstream_seterr(zstream);
 }
 
 void git_zstream_free(git_zstream *zstream)
 {
-	deflateEnd(&zstream->z);
+	if (zstream->type == GIT_ZSTREAM_INFLATE)
+		inflateEnd(&zstream->z);
+	else
+		deflateEnd(&zstream->z);
 }
 
 void git_zstream_reset(git_zstream *zstream)
 {
-	deflateReset(&zstream->z);
+	if (zstream->type == GIT_ZSTREAM_INFLATE)
+		inflateReset(&zstream->z);
+	else
+		deflateReset(&zstream->z);
 	zstream->in = NULL;
 	zstream->in_len = 0;
 	zstream->zerr = Z_STREAM_END;
@@ -97,7 +108,10 @@ int git_zstream_get_output(void *out, size_t *out_len, git_zstream *zstream)
 		out_queued = (size_t)zstream->z.avail_out;
 
 		/* compress next chunk */
-		zstream->zerr = deflate(&zstream->z, zflush);
+		if (zstream->type == GIT_ZSTREAM_INFLATE)
+			zstream->zerr = inflate(&zstream->z, zflush);
+		else
+			zstream->zerr = deflate(&zstream->z, zflush);
 
 		if (zstream->zerr == Z_STREAM_ERROR)
 			return zstream_seterr(zstream);
@@ -120,12 +134,12 @@ int git_zstream_get_output(void *out, size_t *out_len, git_zstream *zstream)
 	return 0;
 }
 
-int git_zstream_deflatebuf(git_buf *out, const void *in, size_t in_len)
+static int zstream_buf(git_buf *out, const void *in, size_t in_len, git_zstream_t type)
 {
 	git_zstream zs = GIT_ZSTREAM_INIT;
 	int error = 0;
 
-	if ((error = git_zstream_init(&zs)) < 0)
+	if ((error = git_zstream_init(&zs, type)) < 0)
 		return error;
 
 	if ((error = git_zstream_set_input(&zs, in, in_len)) < 0)
@@ -154,3 +168,13 @@ done:
 	git_zstream_free(&zs);
 	return error;
 }
+
+int git_zstream_deflatebuf(git_buf *out, const void *in, size_t in_len)
+{
+	return zstream_buf(out, in, in_len, GIT_ZSTREAM_DEFLATE);
+}
+
+int git_zstream_inflatebuf(git_buf *out, const void *in, size_t in_len)
+{
+	return zstream_buf(out, in, in_len, GIT_ZSTREAM_INFLATE);
+}
diff --git a/src/zstream.h b/src/zstream.h
index 9b5bf6a..f0006d3 100644
--- a/src/zstream.h
+++ b/src/zstream.h
@@ -12,8 +12,14 @@
 #include "common.h"
 #include "buffer.h"
 
+typedef enum {
+	GIT_ZSTREAM_INFLATE,
+	GIT_ZSTREAM_DEFLATE,
+} git_zstream_t;
+
 typedef struct {
 	z_stream z;
+	git_zstream_t type;
 	const char *in;
 	size_t in_len;
 	int zerr;
@@ -21,7 +27,7 @@ typedef struct {
 
 #define GIT_ZSTREAM_INIT {{0}}
 
-int git_zstream_init(git_zstream *zstream);
+int git_zstream_init(git_zstream *zstream, git_zstream_t type);
 void git_zstream_free(git_zstream *zstream);
 
 int git_zstream_set_input(git_zstream *zstream, const void *in, size_t in_len);
@@ -35,5 +41,6 @@ bool git_zstream_done(git_zstream *zstream);
 void git_zstream_reset(git_zstream *zstream);
 
 int git_zstream_deflatebuf(git_buf *out, const void *in, size_t in_len);
+int git_zstream_inflatebuf(git_buf *out, const void *in, size_t in_len);
 
 #endif /* INCLUDE_zstream_h__ */
diff --git a/tests/core/zstream.c b/tests/core/zstream.c
index 7ba9424..b13429b 100644
--- a/tests/core/zstream.c
+++ b/tests/core/zstream.c
@@ -48,7 +48,7 @@ void test_core_zstream__basic(void)
 	char out[128];
 	size_t outlen = sizeof(out);
 
-	cl_git_pass(git_zstream_init(&z));
+	cl_git_pass(git_zstream_init(&z, GIT_ZSTREAM_DEFLATE));
 	cl_git_pass(git_zstream_set_input(&z, data, strlen(data) + 1));
 	cl_git_pass(git_zstream_get_output(out, &outlen, &z));
 	cl_assert(git_zstream_done(&z));
@@ -68,9 +68,10 @@ void test_core_zstream__buffer(void)
 
 #define BIG_STRING_PART "Big Data IS Big - Long Data IS Long - We need a buffer larger than 1024 x 1024 to make sure we trigger chunked compression - Big Big Data IS Bigger than Big - Long Long Data IS Longer than Long"
 
-static void compress_input_various_ways(git_buf *input)
+static void compress_and_decompress_input_various_ways(git_buf *input)
 {
 	git_buf out1 = GIT_BUF_INIT, out2 = GIT_BUF_INIT;
+	git_buf inflated = GIT_BUF_INIT;
 	size_t i, fixed_size = max(input->size / 2, 256);
 	char *fixed = git__malloc(fixed_size);
 	cl_assert(fixed);
@@ -93,7 +94,7 @@ static void compress_input_various_ways(git_buf *input)
 		}
 		cl_assert(use_fixed_size <= fixed_size);
 
-		cl_git_pass(git_zstream_init(&zs));
+		cl_git_pass(git_zstream_init(&zs, GIT_ZSTREAM_DEFLATE));
 		cl_git_pass(git_zstream_set_input(&zs, input->ptr, input->size));
 
 		while (!git_zstream_done(&zs)) {
@@ -112,7 +113,12 @@ static void compress_input_various_ways(git_buf *input)
 		git_buf_free(&out2);
 	}
 
+	cl_git_pass(git_zstream_inflatebuf(&inflated, out1.ptr, out1.size));
+	cl_assert_equal_i(input->size, inflated.size);
+	cl_assert(memcmp(input->ptr, inflated.ptr, inflated.size) == 0);
+
 	git_buf_free(&out1);
+	git_buf_free(&inflated);
 	git__free(fixed);
 }
 
@@ -129,14 +135,14 @@ void test_core_zstream__big_data(void)
 			cl_git_pass(
 				git_buf_put(&in, BIG_STRING_PART, strlen(BIG_STRING_PART)));
 
-		compress_input_various_ways(&in);
+		compress_and_decompress_input_various_ways(&in);
 
 		/* make a big string that's hard to compress */
 		srand(0xabad1dea);
 		for (scan = 0; scan < in.size; ++scan)
 			in.ptr[scan] = (char)rand();
 
-		compress_input_various_ways(&in);
+		compress_and_decompress_input_various_ways(&in);
 	}
 
 	git_buf_free(&in);