]>
git.proxmox.com Git - libgit2.git/blob - src/zstream.c
2 * Copyright (C) the libgit2 contributors. All rights reserved.
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.
14 #define ZSTREAM_BUFFER_SIZE (1024 * 1024)
15 #define ZSTREAM_BUFFER_MIN_EXTRA 8
17 GIT_INLINE(int) zstream_seterr(git_zstream
*zs
)
22 case Z_BUF_ERROR
: /* not fatal; we retry with a larger buffer */
29 git_error_set_str(GIT_ERROR_ZLIB
, zs
->z
.msg
);
31 git_error_set(GIT_ERROR_ZLIB
, "unknown compression error");
37 int git_zstream_init(git_zstream
*zstream
, git_zstream_t type
)
41 if (zstream
->type
== GIT_ZSTREAM_INFLATE
)
42 zstream
->zerr
= inflateInit(&zstream
->z
);
44 zstream
->zerr
= deflateInit(&zstream
->z
, Z_DEFAULT_COMPRESSION
);
45 return zstream_seterr(zstream
);
48 void git_zstream_free(git_zstream
*zstream
)
50 if (zstream
->type
== GIT_ZSTREAM_INFLATE
)
51 inflateEnd(&zstream
->z
);
53 deflateEnd(&zstream
->z
);
56 void git_zstream_reset(git_zstream
*zstream
)
58 if (zstream
->type
== GIT_ZSTREAM_INFLATE
)
59 inflateReset(&zstream
->z
);
61 deflateReset(&zstream
->z
);
64 zstream
->zerr
= Z_STREAM_END
;
67 int git_zstream_set_input(git_zstream
*zstream
, const void *in
, size_t in_len
)
70 zstream
->in_len
= in_len
;
75 bool git_zstream_done(git_zstream
*zstream
)
77 return (!zstream
->in_len
&& zstream
->zerr
== Z_STREAM_END
);
80 bool git_zstream_eos(git_zstream
*zstream
)
82 return zstream
->zerr
== Z_STREAM_END
;
85 size_t git_zstream_suggest_output_len(git_zstream
*zstream
)
87 if (zstream
->in_len
> ZSTREAM_BUFFER_SIZE
)
88 return ZSTREAM_BUFFER_SIZE
;
89 else if (zstream
->in_len
> ZSTREAM_BUFFER_MIN_EXTRA
)
90 return zstream
->in_len
;
92 return ZSTREAM_BUFFER_MIN_EXTRA
;
95 int git_zstream_get_output_chunk(
96 void *out
, size_t *out_len
, git_zstream
*zstream
)
98 size_t in_queued
, in_used
, out_queued
;
100 /* set up input data */
101 zstream
->z
.next_in
= (Bytef
*)zstream
->in
;
103 /* feed as much data to zlib as it can consume, at most UINT_MAX */
104 if (zstream
->in_len
> UINT_MAX
) {
105 zstream
->z
.avail_in
= UINT_MAX
;
106 zstream
->flush
= Z_NO_FLUSH
;
108 zstream
->z
.avail_in
= (uInt
)zstream
->in_len
;
109 zstream
->flush
= Z_FINISH
;
111 in_queued
= (size_t)zstream
->z
.avail_in
;
113 /* set up output data */
114 zstream
->z
.next_out
= out
;
115 zstream
->z
.avail_out
= (uInt
)*out_len
;
117 if ((size_t)zstream
->z
.avail_out
!= *out_len
)
118 zstream
->z
.avail_out
= UINT_MAX
;
119 out_queued
= (size_t)zstream
->z
.avail_out
;
121 /* compress next chunk */
122 if (zstream
->type
== GIT_ZSTREAM_INFLATE
)
123 zstream
->zerr
= inflate(&zstream
->z
, zstream
->flush
);
125 zstream
->zerr
= deflate(&zstream
->z
, zstream
->flush
);
127 if (zstream_seterr(zstream
))
130 in_used
= (in_queued
- zstream
->z
.avail_in
);
131 zstream
->in_len
-= in_used
;
132 zstream
->in
+= in_used
;
134 *out_len
= (out_queued
- zstream
->z
.avail_out
);
139 int git_zstream_get_output(void *out
, size_t *out_len
, git_zstream
*zstream
)
141 size_t out_remain
= *out_len
;
143 if (zstream
->in_len
&& zstream
->zerr
== Z_STREAM_END
) {
144 git_error_set(GIT_ERROR_ZLIB
, "zlib input had trailing garbage");
148 while (out_remain
> 0 && zstream
->zerr
!= Z_STREAM_END
) {
149 size_t out_written
= out_remain
;
151 if (git_zstream_get_output_chunk(out
, &out_written
, zstream
) < 0)
154 out_remain
-= out_written
;
155 out
= ((char *)out
) + out_written
;
158 /* either we finished the input or we did not flush the data */
159 GIT_ASSERT(zstream
->in_len
> 0 || zstream
->flush
== Z_FINISH
);
161 /* set out_size to number of bytes actually written to output */
162 *out_len
= *out_len
- out_remain
;
167 static int zstream_buf(git_buf
*out
, const void *in
, size_t in_len
, git_zstream_t type
)
169 git_zstream zs
= GIT_ZSTREAM_INIT
;
172 if ((error
= git_zstream_init(&zs
, type
)) < 0)
175 if ((error
= git_zstream_set_input(&zs
, in
, in_len
)) < 0)
178 while (!git_zstream_done(&zs
)) {
179 size_t step
= git_zstream_suggest_output_len(&zs
), written
;
181 if ((error
= git_buf_grow_by(out
, step
)) < 0)
184 written
= out
->asize
- out
->size
;
186 if ((error
= git_zstream_get_output(
187 out
->ptr
+ out
->size
, &written
, &zs
)) < 0)
190 out
->size
+= written
;
193 /* NULL terminate for consistency if possible */
194 if (out
->size
< out
->asize
)
195 out
->ptr
[out
->size
] = '\0';
198 git_zstream_free(&zs
);
202 int git_zstream_deflatebuf(git_buf
*out
, const void *in
, size_t in_len
)
204 return zstream_buf(out
, in
, in_len
, GIT_ZSTREAM_DEFLATE
);
207 int git_zstream_inflatebuf(git_buf
*out
, const void *in
, size_t in_len
)
209 return zstream_buf(out
, in
, in_len
, GIT_ZSTREAM_INFLATE
);