]>
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.
13 #define ZSTREAM_BUFFER_SIZE (1024 * 1024)
14 #define ZSTREAM_BUFFER_MIN_EXTRA 8
16 static int zstream_seterr(git_zstream
*zs
)
18 if (zs
->zerr
== Z_OK
|| zs
->zerr
== Z_STREAM_END
)
21 if (zs
->zerr
== Z_MEM_ERROR
)
24 giterr_set(GITERR_ZLIB
, zs
->z
.msg
);
26 giterr_set(GITERR_ZLIB
, "Unknown compression error");
31 int git_zstream_init(git_zstream
*zstream
, git_zstream_t type
)
35 if (zstream
->type
== GIT_ZSTREAM_INFLATE
)
36 zstream
->zerr
= inflateInit(&zstream
->z
);
38 zstream
->zerr
= deflateInit(&zstream
->z
, Z_DEFAULT_COMPRESSION
);
39 return zstream_seterr(zstream
);
42 void git_zstream_free(git_zstream
*zstream
)
44 if (zstream
->type
== GIT_ZSTREAM_INFLATE
)
45 inflateEnd(&zstream
->z
);
47 deflateEnd(&zstream
->z
);
50 void git_zstream_reset(git_zstream
*zstream
)
52 if (zstream
->type
== GIT_ZSTREAM_INFLATE
)
53 inflateReset(&zstream
->z
);
55 deflateReset(&zstream
->z
);
58 zstream
->zerr
= Z_STREAM_END
;
61 int git_zstream_set_input(git_zstream
*zstream
, const void *in
, size_t in_len
)
64 zstream
->in_len
= in_len
;
69 bool git_zstream_done(git_zstream
*zstream
)
71 return (!zstream
->in_len
&& zstream
->zerr
== Z_STREAM_END
);
74 size_t git_zstream_suggest_output_len(git_zstream
*zstream
)
76 if (zstream
->in_len
> ZSTREAM_BUFFER_SIZE
)
77 return ZSTREAM_BUFFER_SIZE
;
78 else if (zstream
->in_len
> ZSTREAM_BUFFER_MIN_EXTRA
)
79 return zstream
->in_len
;
81 return ZSTREAM_BUFFER_MIN_EXTRA
;
84 int git_zstream_get_output(void *out
, size_t *out_len
, git_zstream
*zstream
)
86 int zflush
= Z_FINISH
;
87 size_t out_remain
= *out_len
;
89 if (zstream
->in_len
&& zstream
->zerr
== Z_STREAM_END
) {
90 giterr_set(GITERR_ZLIB
, "zlib input had trailing garbage");
94 while (out_remain
> 0 && zstream
->zerr
!= Z_STREAM_END
) {
95 size_t out_queued
, in_queued
, out_used
, in_used
;
98 zstream
->z
.next_in
= (Bytef
*)zstream
->in
;
99 zstream
->z
.avail_in
= (uInt
)zstream
->in_len
;
100 if ((size_t)zstream
->z
.avail_in
!= zstream
->in_len
) {
101 zstream
->z
.avail_in
= INT_MAX
;
106 in_queued
= (size_t)zstream
->z
.avail_in
;
108 /* set up out data */
109 zstream
->z
.next_out
= out
;
110 zstream
->z
.avail_out
= (uInt
)out_remain
;
111 if ((size_t)zstream
->z
.avail_out
!= out_remain
)
112 zstream
->z
.avail_out
= INT_MAX
;
113 out_queued
= (size_t)zstream
->z
.avail_out
;
115 /* compress next chunk */
116 if (zstream
->type
== GIT_ZSTREAM_INFLATE
)
117 zstream
->zerr
= inflate(&zstream
->z
, zflush
);
119 zstream
->zerr
= deflate(&zstream
->z
, zflush
);
121 if (zstream
->zerr
== Z_STREAM_ERROR
)
122 return zstream_seterr(zstream
);
124 out_used
= (out_queued
- zstream
->z
.avail_out
);
125 out_remain
-= out_used
;
126 out
= ((char *)out
) + out_used
;
128 in_used
= (in_queued
- zstream
->z
.avail_in
);
129 zstream
->in_len
-= in_used
;
130 zstream
->in
+= in_used
;
133 /* either we finished the input or we did not flush the data */
134 assert(zstream
->in_len
> 0 || zflush
== Z_FINISH
);
136 /* set out_size to number of bytes actually written to output */
137 *out_len
= *out_len
- out_remain
;
142 static int zstream_buf(git_buf
*out
, const void *in
, size_t in_len
, git_zstream_t type
)
144 git_zstream zs
= GIT_ZSTREAM_INIT
;
147 if ((error
= git_zstream_init(&zs
, type
)) < 0)
150 if ((error
= git_zstream_set_input(&zs
, in
, in_len
)) < 0)
153 while (!git_zstream_done(&zs
)) {
154 size_t step
= git_zstream_suggest_output_len(&zs
), written
;
156 if ((error
= git_buf_grow_by(out
, step
)) < 0)
159 written
= out
->asize
- out
->size
;
161 if ((error
= git_zstream_get_output(
162 out
->ptr
+ out
->size
, &written
, &zs
)) < 0)
165 out
->size
+= written
;
168 /* NULL terminate for consistency if possible */
169 if (out
->size
< out
->asize
)
170 out
->ptr
[out
->size
] = '\0';
173 git_zstream_free(&zs
);
177 int git_zstream_deflatebuf(git_buf
*out
, const void *in
, size_t in_len
)
179 return zstream_buf(out
, in
, in_len
, GIT_ZSTREAM_DEFLATE
);
182 int git_zstream_inflatebuf(git_buf
*out
, const void *in
, size_t in_len
)
184 return zstream_buf(out
, in
, in_len
, GIT_ZSTREAM_INFLATE
);