File Coverage

deps/libgit2/src/util/zstream.c
Criterion Covered Total %
statement 83 104 79.8
branch 36 50 72.0
condition n/a
subroutine n/a
pod n/a
total 119 154 77.2


line stmt bran cond sub pod time code
1             /*
2             * Copyright (C) the libgit2 contributors. All rights reserved.
3             *
4             * This file is part of libgit2, distributed under the GNU GPL v2 with
5             * a Linking Exception. For full terms see the included COPYING file.
6             */
7              
8             #include "zstream.h"
9              
10             #include
11              
12             #include "str.h"
13              
14             #define ZSTREAM_BUFFER_SIZE (1024 * 1024)
15             #define ZSTREAM_BUFFER_MIN_EXTRA 8
16              
17 2878           GIT_INLINE(int) zstream_seterr(git_zstream *zs)
18             {
19 2878           switch (zs->zerr) {
20             case Z_OK:
21             case Z_STREAM_END:
22             case Z_BUF_ERROR: /* not fatal; we retry with a larger buffer */
23 2878           return 0;
24             case Z_MEM_ERROR:
25 0           git_error_set_oom();
26 0           break;
27             default:
28 0 0         if (zs->z.msg)
29 0           git_error_set_str(GIT_ERROR_ZLIB, zs->z.msg);
30             else
31 0           git_error_set(GIT_ERROR_ZLIB, "unknown compression error");
32             }
33              
34 0           return -1;
35             }
36              
37 1192           int git_zstream_init(git_zstream *zstream, git_zstream_t type)
38             {
39 1192           zstream->type = type;
40              
41 1192 100         if (zstream->type == GIT_ZSTREAM_INFLATE)
42 1178           zstream->zerr = inflateInit(&zstream->z);
43             else
44 14           zstream->zerr = deflateInit(&zstream->z, Z_DEFAULT_COMPRESSION);
45 1192           return zstream_seterr(zstream);
46             }
47              
48 1192           void git_zstream_free(git_zstream *zstream)
49             {
50 1192 100         if (zstream->type == GIT_ZSTREAM_INFLATE)
51 1178           inflateEnd(&zstream->z);
52             else
53 14           deflateEnd(&zstream->z);
54 1192           }
55              
56 50           void git_zstream_reset(git_zstream *zstream)
57             {
58 50 50         if (zstream->type == GIT_ZSTREAM_INFLATE)
59 0           inflateReset(&zstream->z);
60             else
61 50           deflateReset(&zstream->z);
62 50           zstream->in = NULL;
63 50           zstream->in_len = 0;
64 50           zstream->zerr = Z_STREAM_END;
65 50           }
66              
67 1235           int git_zstream_set_input(git_zstream *zstream, const void *in, size_t in_len)
68             {
69 1235           zstream->in = in;
70 1235           zstream->in_len = in_len;
71 1235           zstream->zerr = Z_OK;
72 1235           return 0;
73             }
74              
75 876           bool git_zstream_done(git_zstream *zstream)
76             {
77 876 100         return (!zstream->in_len && zstream->zerr == Z_STREAM_END);
    100          
78             }
79              
80 55           bool git_zstream_eos(git_zstream *zstream)
81             {
82 55           return zstream->zerr == Z_STREAM_END;
83             }
84              
85 12           size_t git_zstream_suggest_output_len(git_zstream *zstream)
86             {
87 12 50         if (zstream->in_len > ZSTREAM_BUFFER_SIZE)
88 0           return ZSTREAM_BUFFER_SIZE;
89 12 100         else if (zstream->in_len > ZSTREAM_BUFFER_MIN_EXTRA)
90 3           return zstream->in_len;
91             else
92 9           return ZSTREAM_BUFFER_MIN_EXTRA;
93             }
94              
95 1686           int git_zstream_get_output_chunk(
96             void *out, size_t *out_len, git_zstream *zstream)
97             {
98             size_t in_queued, in_used, out_queued;
99              
100             /* set up input data */
101 1686           zstream->z.next_in = (Bytef *)zstream->in;
102              
103             /* feed as much data to zlib as it can consume, at most UINT_MAX */
104 1686 50         if (zstream->in_len > UINT_MAX) {
105 0           zstream->z.avail_in = UINT_MAX;
106 0           zstream->flush = Z_NO_FLUSH;
107             } else {
108 1686           zstream->z.avail_in = (uInt)zstream->in_len;
109 1686           zstream->flush = Z_FINISH;
110             }
111 1686           in_queued = (size_t)zstream->z.avail_in;
112              
113             /* set up output data */
114 1686           zstream->z.next_out = out;
115 1686           zstream->z.avail_out = (uInt)*out_len;
116              
117 1686 50         if ((size_t)zstream->z.avail_out != *out_len)
118 0           zstream->z.avail_out = UINT_MAX;
119 1686           out_queued = (size_t)zstream->z.avail_out;
120              
121             /* compress next chunk */
122 1686 100         if (zstream->type == GIT_ZSTREAM_INFLATE)
123 1624           zstream->zerr = inflate(&zstream->z, zstream->flush);
124             else
125 62           zstream->zerr = deflate(&zstream->z, zstream->flush);
126              
127 1686 50         if (zstream_seterr(zstream))
128 0           return -1;
129              
130 1686           in_used = (in_queued - zstream->z.avail_in);
131 1686           zstream->in_len -= in_used;
132 1686           zstream->in += in_used;
133              
134 1686           *out_len = (out_queued - zstream->z.avail_out);
135              
136 1686           return 0;
137             }
138              
139 1576           int git_zstream_get_output(void *out, size_t *out_len, git_zstream *zstream)
140             {
141 1576           size_t out_remain = *out_len;
142              
143 1576 100         if (zstream->in_len && zstream->zerr == Z_STREAM_END) {
    50          
144 0           git_error_set(GIT_ERROR_ZLIB, "zlib input had trailing garbage");
145 0           return -1;
146             }
147              
148 2841 100         while (out_remain > 0 && zstream->zerr != Z_STREAM_END) {
    100          
149 1265           size_t out_written = out_remain;
150              
151 1265 50         if (git_zstream_get_output_chunk(out, &out_written, zstream) < 0)
152 0           return -1;
153              
154 1265           out_remain -= out_written;
155 1265           out = ((char *)out) + out_written;
156             }
157              
158             /* either we finished the input or we did not flush the data */
159 1576 100         GIT_ASSERT(zstream->in_len > 0 || zstream->flush == Z_FINISH);
    50          
160              
161             /* set out_size to number of bytes actually written to output */
162 1576           *out_len = *out_len - out_remain;
163              
164 1576           return 0;
165             }
166              
167 7           static int zstream_buf(git_str *out, const void *in, size_t in_len, git_zstream_t type)
168             {
169 7           git_zstream zs = GIT_ZSTREAM_INIT;
170 7           int error = 0;
171              
172 7 50         if ((error = git_zstream_init(&zs, type)) < 0)
173 0           return error;
174              
175 7 50         if ((error = git_zstream_set_input(&zs, in, in_len)) < 0)
176 0           goto done;
177              
178 19 100         while (!git_zstream_done(&zs)) {
179 12           size_t step = git_zstream_suggest_output_len(&zs), written;
180              
181 12 50         if ((error = git_str_grow_by(out, step)) < 0)
182 0           goto done;
183              
184 12           written = out->asize - out->size;
185              
186 12 50         if ((error = git_zstream_get_output(
187 12           out->ptr + out->size, &written, &zs)) < 0)
188 0           goto done;
189              
190 12           out->size += written;
191             }
192              
193             /* NULL terminate for consistency if possible */
194 7 100         if (out->size < out->asize)
195 3           out->ptr[out->size] = '\0';
196              
197             done:
198 7           git_zstream_free(&zs);
199 7           return error;
200             }
201              
202 7           int git_zstream_deflatebuf(git_str *out, const void *in, size_t in_len)
203             {
204 7           return zstream_buf(out, in, in_len, GIT_ZSTREAM_DEFLATE);
205             }
206              
207 0           int git_zstream_inflatebuf(git_str *out, const void *in, size_t in_len)
208             {
209 0           return zstream_buf(out, in, in_len, GIT_ZSTREAM_INFLATE);
210             }