Commit c6f26b48e47f6c0cd67769418c33efe66e5b5fe8

Edward Thomson 2013-12-13T18:26:46

Refactor zlib for easier deflate streaming

diff --git a/src/compress.c b/src/compress.c
deleted file mode 100644
index 14b7940..0000000
--- a/src/compress.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#include "compress.h"
-
-#include <zlib.h>
-
-#define BUFFER_SIZE (1024 * 1024)
-
-int git__compress(git_buf *buf, const void *buff, size_t len)
-{
-	z_stream zs;
-	char *zb;
-	size_t have;
-
-	memset(&zs, 0, sizeof(zs));
-	if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK)
-		return -1;
-
-	zb = git__malloc(BUFFER_SIZE);
-	GITERR_CHECK_ALLOC(zb);
-
-	zs.next_in = (void *)buff;
-	zs.avail_in = (uInt)len;
-
-	do {
-		zs.next_out = (unsigned char *)zb;
-		zs.avail_out = BUFFER_SIZE;
-
-		if (deflate(&zs, Z_FINISH) == Z_STREAM_ERROR) {
-			git__free(zb);
-			return -1;
-		}
-
-		have = BUFFER_SIZE - (size_t)zs.avail_out;
-
-		if (git_buf_put(buf, zb, have) < 0) {
-			git__free(zb);
-			return -1;
-		}
-
-	} while (zs.avail_out == 0);
-
-	assert(zs.avail_in == 0);
-
-	deflateEnd(&zs);
-	git__free(zb);
-	return 0;
-}
diff --git a/src/compress.h b/src/compress.h
deleted file mode 100644
index 49e6f47..0000000
--- a/src/compress.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-#ifndef INCLUDE_compress_h__
-#define INCLUDE_compress_h__
-
-#include "common.h"
-
-#include "buffer.h"
-
-int git__compress(git_buf *buf, const void *buff, size_t len);
-
-#endif /* INCLUDE_compress_h__ */
diff --git a/src/indexer.c b/src/indexer.c
index 6132571..ccab8fc 100644
--- a/src/indexer.c
+++ b/src/indexer.c
@@ -5,8 +5,6 @@
  * a Linking Exception. For full terms see the included COPYING file.
  */
 
-#include <zlib.h>
-
 #include "git2/indexer.h"
 #include "git2/object.h"
 
@@ -18,7 +16,7 @@
 #include "filebuf.h"
 #include "oid.h"
 #include "oidmap.h"
-#include "compress.h"
+#include "zstream.h"
 
 #define UINT31_MAX (0x7FFFFFFF)
 
@@ -662,7 +660,7 @@ static int inject_object(git_indexer *idx, git_oid *id)
 	idx->pack->mwf.size += hdr_len;
 	entry->crc = crc32(entry->crc, hdr, hdr_len);
 
-	if ((error = git__compress(&buf, data, len)) < 0)
+	if ((error = git_zstream_deflatebuf(&buf, data, len)) < 0)
 		goto cleanup;
 
 	/* And then the compressed object */
diff --git a/src/pack-objects.c b/src/pack-objects.c
index 335944c..0d31d50 100644
--- a/src/pack-objects.c
+++ b/src/pack-objects.c
@@ -7,7 +7,7 @@
 
 #include "pack-objects.h"
 
-#include "compress.h"
+#include "zstream.h"
 #include "delta.h"
 #include "iterator.h"
 #include "netops.h"
@@ -319,7 +319,7 @@ static int write_object(git_buf *buf, git_packbuilder *pb, git_pobject *po)
 	/* Write data */
 	if (po->z_delta_size)
 		size = po->z_delta_size;
-	else if (git__compress(&zbuf, data, size) < 0)
+	else if (git_zstream_deflatebuf(&zbuf, data, size) < 0)
 		goto on_error;
 	else {
 		if (po->delta)
@@ -931,7 +931,7 @@ static int find_deltas(git_packbuilder *pb, git_pobject **list,
 		 * between writes at that moment.
 		 */
 		if (po->delta_data) {
-			if (git__compress(&zbuf, po->delta_data, po->delta_size) < 0)
+			if (git_zstream_deflatebuf(&zbuf, po->delta_data, po->delta_size) < 0)
 				goto on_error;
 
 			git__free(po->delta_data);
diff --git a/src/zstream.c b/src/zstream.c
new file mode 100644
index 0000000..e043dd3
--- /dev/null
+++ b/src/zstream.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include <zlib.h>
+
+#include "zstream.h"
+#include "buffer.h"
+
+#define BUFFER_SIZE (1024 * 1024)
+
+static int zstream_seterr(int zerr, git_zstream *zstream)
+{
+	if (zerr == Z_MEM_ERROR)
+		giterr_set_oom();
+	else if (zstream->msg)
+		giterr_set(GITERR_ZLIB, zstream->msg);
+	else
+		giterr_set(GITERR_ZLIB, "Unknown compression error");
+
+	return -1;
+}
+
+int git_zstream_init(git_zstream *zstream)
+{
+	int zerr;
+
+	if ((zerr = deflateInit(zstream, Z_DEFAULT_COMPRESSION)) != Z_OK)
+		return zstream_seterr(zerr, zstream);
+
+	return 0;
+}
+
+ssize_t git_zstream_deflate(void *out, size_t out_len, git_zstream *zstream, const void *in, size_t in_len)
+{
+	int zerr;
+
+	if ((ssize_t)out_len < 0)
+		out_len = INT_MAX;
+
+	zstream->next_in = (Bytef *)in;
+	zstream->avail_in = in_len;
+	zstream->next_out = out;
+	zstream->avail_out = out_len;
+
+	if ((zerr = deflate(zstream, Z_FINISH)) == Z_STREAM_ERROR)
+		return zstream_seterr(zerr, zstream);
+
+	return (out_len - zstream->avail_out);
+}
+
+void git_zstream_free(git_zstream *zstream)
+{
+	deflateEnd(zstream);
+}
+
+int git_zstream_deflatebuf(git_buf *out, const void *in, size_t in_len)
+{
+	git_zstream zstream = GIT_ZSTREAM_INIT;
+	size_t out_len;
+	ssize_t written;
+	int error = 0;
+
+	if ((error = git_zstream_init(&zstream)) < 0)
+		goto done;
+
+	do {
+		if (out->asize - out->size < BUFFER_SIZE)
+			git_buf_grow(out, out->asize + BUFFER_SIZE);
+
+		out_len = out->asize - out->size;
+
+		if ((written = git_zstream_deflate(out->ptr + out->size, out_len, &zstream, in, in_len)) <= 0)
+			break;
+
+		in = (char *)in + written;
+		in_len -= written;
+		out->size += written;
+	} while (written > 0);
+
+	if (written < 0)
+		error = written;
+
+done:
+	git_zstream_free(&zstream);
+	return error;
+}
diff --git a/src/zstream.h b/src/zstream.h
new file mode 100644
index 0000000..e6c8411
--- /dev/null
+++ b/src/zstream.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_zstream_h__
+#define INCLUDE_zstream_h__
+
+#include <zlib.h>
+
+#include "common.h"
+#include "buffer.h"
+
+#define git_zstream z_stream
+
+#define GIT_ZSTREAM_INIT {0}
+
+int git_zstream_init(git_zstream *zstream);
+ssize_t git_zstream_deflate(void *out, size_t out_len, git_zstream *zstream, const void *in, size_t in_len);
+void git_zstream_free(git_zstream *zstream);
+
+int git_zstream_deflatebuf(git_buf *out, const void *in, size_t in_len);
+
+#endif /* INCLUDE_zstream_h__ */