We now build libssh2 in Xcode and it's a much better UB/10.4 citizen
[printdrop.git] / Vendor / libssh2 / Source / comp.c
1 /* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms,
5 * with or without modification, are permitted provided
6 * that the following conditions are met:
7 *
8 * Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the
10 * following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials
15 * provided with the distribution.
16 *
17 * Neither the name of the copyright holder nor the names
18 * of any other contributors may be used to endorse or
19 * promote products derived from this software without
20 * specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
23 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
34 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
35 * OF SUCH DAMAGE.
36 */
37
38 #include "libssh2_priv.h"
39 #ifdef LIBSSH2_HAVE_ZLIB
40 # include <zlib.h>
41 #endif
42
43 /* ********
44 * none *
45 ******** */
46
47 /* {{{ libssh2_comp_method_none_comp
48 * Minimalist compression: Absolutely none
49 */
50 static int
51 libssh2_comp_method_none_comp(LIBSSH2_SESSION * session,
52 int compress,
53 unsigned char **dest,
54 unsigned long *dest_len,
55 unsigned long payload_limit,
56 int *free_dest,
57 const unsigned char *src,
58 unsigned long src_len, void **abstract)
59 {
60 (void) session;
61 (void) compress;
62 (void) payload_limit;
63 (void) abstract;
64 *dest = (unsigned char *) src;
65 *dest_len = src_len;
66
67 *free_dest = 0;
68
69 return 0;
70 }
71
72 /* }}} */
73
74 static const LIBSSH2_COMP_METHOD libssh2_comp_method_none = {
75 "none",
76 NULL,
77 libssh2_comp_method_none_comp,
78 NULL
79 };
80
81 #ifdef LIBSSH2_HAVE_ZLIB
82 /* ********
83 * zlib *
84 ******** */
85
86 /* {{{ Memory management wrappers
87 * Yes, I realize we're doing a callback to a callback,
88 * Deal...
89 */
90
91 static voidpf
92 libssh2_comp_method_zlib_alloc(voidpf opaque, uInt items, uInt size)
93 {
94 LIBSSH2_SESSION *session = (LIBSSH2_SESSION *) opaque;
95
96 return (voidpf) LIBSSH2_ALLOC(session, items * size);
97 }
98
99 static void
100 libssh2_comp_method_zlib_free(voidpf opaque, voidpf address)
101 {
102 LIBSSH2_SESSION *session = (LIBSSH2_SESSION *) opaque;
103
104 LIBSSH2_FREE(session, address);
105 }
106
107 /* }}} */
108
109 /* {{{ libssh2_comp_method_zlib_init
110 * All your bandwidth are belong to us (so save some)
111 */
112 static int
113 libssh2_comp_method_zlib_init(LIBSSH2_SESSION * session, int compress,
114 void **abstract)
115 {
116 z_stream *strm;
117 int status;
118
119 strm = LIBSSH2_ALLOC(session, sizeof(z_stream));
120 if (!strm) {
121 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
122 "Unable to allocate memory for zlib compression/decompression",
123 0);
124 return -1;
125 }
126 memset(strm, 0, sizeof(z_stream));
127
128 strm->opaque = (voidpf) session;
129 strm->zalloc = (alloc_func) libssh2_comp_method_zlib_alloc;
130 strm->zfree = (free_func) libssh2_comp_method_zlib_free;
131 if (compress) {
132 /* deflate */
133 status = deflateInit(strm, Z_DEFAULT_COMPRESSION);
134 } else {
135 /* inflate */
136 status = inflateInit(strm);
137 }
138
139 if (status != Z_OK) {
140 LIBSSH2_FREE(session, strm);
141 return -1;
142 }
143 *abstract = strm;
144
145 return 0;
146 }
147
148 /* }}} */
149
150 /* {{{ libssh2_comp_method_zlib_comp
151 * zlib, a compression standard for all occasions
152 */
153 static int
154 libssh2_comp_method_zlib_comp(LIBSSH2_SESSION * session,
155 int compress,
156 unsigned char **dest,
157 unsigned long *dest_len,
158 unsigned long payload_limit,
159 int *free_dest,
160 const unsigned char *src,
161 unsigned long src_len, void **abstract)
162 {
163 z_stream *strm = *abstract;
164 /* A short-term alloc of a full data chunk is better than a series of
165 reallocs */
166 char *out;
167 int out_maxlen = compress ? (src_len + 4) : (2 * src_len);
168 int limiter = 0;
169
170 /* In practice they never come smaller than this */
171 if (out_maxlen < 25) {
172 out_maxlen = 25;
173 }
174
175 if (out_maxlen > (int) payload_limit) {
176 out_maxlen = payload_limit;
177 }
178
179 strm->next_in = (unsigned char *) src;
180 strm->avail_in = src_len;
181 strm->next_out = (unsigned char *) LIBSSH2_ALLOC(session, out_maxlen);
182 out = (char *) strm->next_out;
183 strm->avail_out = out_maxlen;
184 if (!strm->next_out) {
185 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
186 "Unable to allocate compression/decompression buffer",
187 0);
188 return -1;
189 }
190 while (strm->avail_in) {
191 int status;
192
193 if (compress) {
194 status = deflate(strm, Z_PARTIAL_FLUSH);
195 } else {
196 status = inflate(strm, Z_PARTIAL_FLUSH);
197 }
198 if (status != Z_OK) {
199 libssh2_error(session, LIBSSH2_ERROR_ZLIB,
200 "compress/decompression failure", 0);
201 LIBSSH2_FREE(session, out);
202 return -1;
203 }
204 if (strm->avail_in) {
205 unsigned long out_ofs = out_maxlen - strm->avail_out;
206 char *newout;
207
208 out_maxlen +=
209 compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
210
211 if ((out_maxlen > (int) payload_limit) && !compress && limiter++) {
212 libssh2_error(session, LIBSSH2_ERROR_ZLIB,
213 "Excessive growth in decompression phase", 0);
214 LIBSSH2_FREE(session, out);
215 return -1;
216 }
217
218 newout = LIBSSH2_REALLOC(session, out, out_maxlen);
219 if (!newout) {
220 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
221 "Unable to expand compress/decompression buffer",
222 0);
223 LIBSSH2_FREE(session, out);
224 return -1;
225 }
226 out = newout;
227 strm->next_out = (unsigned char *) out + out_ofs;
228 strm->avail_out +=
229 compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
230 } else
231 while (!strm->avail_out) {
232 /* Done with input, might be a byte or two in internal buffer during compress
233 * Or potentially many bytes if it's a decompress
234 */
235 int grow_size = compress ? 8 : 1024;
236 char *newout;
237
238 if (out_maxlen >= (int) payload_limit) {
239 libssh2_error(session, LIBSSH2_ERROR_ZLIB,
240 "Excessive growth in decompression phase",
241 0);
242 LIBSSH2_FREE(session, out);
243 return -1;
244 }
245
246 if (grow_size > (int) (payload_limit - out_maxlen)) {
247 grow_size = payload_limit - out_maxlen;
248 }
249
250 out_maxlen += grow_size;
251 strm->avail_out = grow_size;
252
253 newout = LIBSSH2_REALLOC(session, out, out_maxlen);
254 if (!newout) {
255 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
256 "Unable to expand final compress/decompress buffer",
257 0);
258 LIBSSH2_FREE(session, out);
259 return -1;
260 }
261 out = newout;
262 strm->next_out = (unsigned char *) out + out_maxlen -
263 grow_size;
264
265 if (compress) {
266 status = deflate(strm, Z_PARTIAL_FLUSH);
267 } else {
268 status = inflate(strm, Z_PARTIAL_FLUSH);
269 }
270 if (status != Z_OK) {
271 libssh2_error(session, LIBSSH2_ERROR_ZLIB,
272 "compress/decompression failure", 0);
273 LIBSSH2_FREE(session, out);
274 return -1;
275 }
276 }
277 }
278
279 *dest = (unsigned char *) out;
280 *dest_len = out_maxlen - strm->avail_out;
281 *free_dest = 1;
282
283 return 0;
284 }
285
286 /* }}} */
287
288 /* {{{ libssh2_comp_method_zlib_dtor
289 * All done, no more compression for you
290 */
291 static int
292 libssh2_comp_method_zlib_dtor(LIBSSH2_SESSION * session, int compress,
293 void **abstract)
294 {
295 z_stream *strm = *abstract;
296
297 if (strm) {
298 if (compress) {
299 /* deflate */
300 deflateEnd(strm);
301 } else {
302 /* inflate */
303 inflateEnd(strm);
304 }
305
306 LIBSSH2_FREE(session, strm);
307 }
308
309 *abstract = NULL;
310
311 return 0;
312 }
313
314 /* }}} */
315
316 static const LIBSSH2_COMP_METHOD libssh2_comp_method_zlib = {
317 "zlib",
318 libssh2_comp_method_zlib_init,
319 libssh2_comp_method_zlib_comp,
320 libssh2_comp_method_zlib_dtor,
321 };
322 #endif /* LIBSSH2_HAVE_ZLIB */
323
324 /* ***********************
325 * Compression Methods *
326 *********************** */
327
328 static const LIBSSH2_COMP_METHOD *_libssh2_comp_methods[] = {
329 &libssh2_comp_method_none,
330 #ifdef LIBSSH2_HAVE_ZLIB
331 &libssh2_comp_method_zlib,
332 #endif /* LIBSSH2_HAVE_ZLIB */
333 NULL
334 };
335
336 const LIBSSH2_COMP_METHOD **
337 libssh2_comp_methods(void)
338 {
339 return _libssh2_comp_methods;
340 }