zstream: introduce a single chunk reader Introduce `get_output_chunk` that will inflate/deflate all the available input buffer into the output buffer. `get_output` will call `get_output_chunk` in a loop, while other consumers can use it to inflate only a piece of the data.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
diff --git a/src/zstream.c b/src/zstream.c
index 963c9a3..affa556 100644
--- a/src/zstream.c
+++ b/src/zstream.c
@@ -87,9 +87,52 @@ size_t git_zstream_suggest_output_len(git_zstream *zstream)
return ZSTREAM_BUFFER_MIN_EXTRA;
}
+int git_zstream_get_output_chunk(
+ void *out, size_t *out_len, git_zstream *zstream)
+{
+ size_t in_queued, in_used, out_queued;
+
+ /* set up input data */
+ zstream->z.next_in = (Bytef *)zstream->in;
+
+ /* feed as much data to zlib as it can consume, at most UINT_MAX */
+ if (zstream->in_len > UINT_MAX) {
+ zstream->z.avail_in = UINT_MAX;
+ zstream->flush = Z_NO_FLUSH;
+ } else {
+ zstream->z.avail_in = (uInt)zstream->in_len;
+ zstream->flush = Z_FINISH;
+ }
+ in_queued = (size_t)zstream->z.avail_in;
+
+ /* set up output data */
+ zstream->z.next_out = out;
+ zstream->z.avail_out = (uInt)*out_len;
+
+ if ((size_t)zstream->z.avail_out != *out_len)
+ zstream->z.avail_out = UINT_MAX;
+ out_queued = (size_t)zstream->z.avail_out;
+
+ /* compress next chunk */
+ if (zstream->type == GIT_ZSTREAM_INFLATE)
+ zstream->zerr = inflate(&zstream->z, zstream->flush);
+ else
+ zstream->zerr = deflate(&zstream->z, zstream->flush);
+
+ if (zstream_seterr(zstream))
+ return -1;
+
+ in_used = (in_queued - zstream->z.avail_in);
+ zstream->in_len -= in_used;
+ zstream->in += in_used;
+
+ *out_len = (out_queued - zstream->z.avail_out);
+
+ return 0;
+}
+
int git_zstream_get_output(void *out, size_t *out_len, git_zstream *zstream)
{
- int zflush = Z_FINISH;
size_t out_remain = *out_len;
if (zstream->in_len && zstream->zerr == Z_STREAM_END) {
@@ -98,47 +141,17 @@ int git_zstream_get_output(void *out, size_t *out_len, git_zstream *zstream)
}
while (out_remain > 0 && zstream->zerr != Z_STREAM_END) {
- size_t out_queued, in_queued, out_used, in_used;
+ size_t out_written = out_remain;
- /* set up in data */
- zstream->z.next_in = (Bytef *)zstream->in;
- zstream->z.avail_in = (uInt)zstream->in_len;
-
- if ((size_t)zstream->z.avail_in != zstream->in_len) {
- zstream->z.avail_in = UINT_MAX;
- zflush = Z_NO_FLUSH;
- } else {
- zflush = Z_FINISH;
- }
- in_queued = (size_t)zstream->z.avail_in;
-
- /* set up out data */
- zstream->z.next_out = out;
- zstream->z.avail_out = (uInt)out_remain;
- if ((size_t)zstream->z.avail_out != out_remain)
- zstream->z.avail_out = UINT_MAX;
- out_queued = (size_t)zstream->z.avail_out;
-
- /* compress next chunk */
- if (zstream->type == GIT_ZSTREAM_INFLATE)
- zstream->zerr = inflate(&zstream->z, zflush);
- else
- zstream->zerr = deflate(&zstream->z, zflush);
-
- if (zstream_seterr(zstream))
+ if (git_zstream_get_output_chunk(out, &out_written, zstream) < 0)
return -1;
- out_used = (out_queued - zstream->z.avail_out);
- out_remain -= out_used;
- out = ((char *)out) + out_used;
-
- in_used = (in_queued - zstream->z.avail_in);
- zstream->in_len -= in_used;
- zstream->in += in_used;
+ out_remain -= out_written;
+ out = ((char *)out) + out_written;
}
/* either we finished the input or we did not flush the data */
- assert(zstream->in_len > 0 || zflush == Z_FINISH);
+ assert(zstream->in_len > 0 || zstream->flush == Z_FINISH);
/* set out_size to number of bytes actually written to output */
*out_len = *out_len - out_remain;
diff --git a/src/zstream.h b/src/zstream.h
index fcc4a31..cfe2b39 100644
--- a/src/zstream.h
+++ b/src/zstream.h
@@ -23,6 +23,7 @@ typedef struct {
git_zstream_t type;
const char *in;
size_t in_len;
+ int flush;
int zerr;
} git_zstream;
@@ -35,6 +36,11 @@ int git_zstream_set_input(git_zstream *zstream, const void *in, size_t in_len);
size_t git_zstream_suggest_output_len(git_zstream *zstream);
+/* get as much output as is available in the input buffer */
+int git_zstream_get_output_chunk(
+ void *out, size_t *out_len, git_zstream *zstream);
+
+/* get all the output from the entire input buffer */
int git_zstream_get_output(void *out, size_t *out_len, git_zstream *zstream);
bool git_zstream_done(git_zstream *zstream);