1 /* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
4 * Redistribution and use in source and binary forms,
5 * with or without modification, are permitted provided
6 * that the following conditions are met:
8 * Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the
10 * following disclaimer.
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.
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.
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
38 #include "libssh2_priv.h"
39 #ifdef LIBSSH2_HAVE_ZLIB
47 /* {{{ libssh2_comp_method_none_comp
48 * Minimalist compression: Absolutely none
51 libssh2_comp_method_none_comp(LIBSSH2_SESSION
* session
,
54 unsigned long *dest_len
,
55 unsigned long payload_limit
,
57 const unsigned char *src
,
58 unsigned long src_len
, void **abstract
)
64 *dest
= (unsigned char *) src
;
74 static const LIBSSH2_COMP_METHOD libssh2_comp_method_none
= {
77 libssh2_comp_method_none_comp
,
81 #ifdef LIBSSH2_HAVE_ZLIB
86 /* {{{ Memory management wrappers
87 * Yes, I realize we're doing a callback to a callback,
92 libssh2_comp_method_zlib_alloc(voidpf opaque
, uInt items
, uInt size
)
94 LIBSSH2_SESSION
*session
= (LIBSSH2_SESSION
*) opaque
;
96 return (voidpf
) LIBSSH2_ALLOC(session
, items
* size
);
100 libssh2_comp_method_zlib_free(voidpf opaque
, voidpf address
)
102 LIBSSH2_SESSION
*session
= (LIBSSH2_SESSION
*) opaque
;
104 LIBSSH2_FREE(session
, address
);
109 /* {{{ libssh2_comp_method_zlib_init
110 * All your bandwidth are belong to us (so save some)
113 libssh2_comp_method_zlib_init(LIBSSH2_SESSION
* session
, int compress
,
119 strm
= LIBSSH2_ALLOC(session
, sizeof(z_stream
));
121 libssh2_error(session
, LIBSSH2_ERROR_ALLOC
,
122 "Unable to allocate memory for zlib compression/decompression",
126 memset(strm
, 0, sizeof(z_stream
));
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
;
133 status
= deflateInit(strm
, Z_DEFAULT_COMPRESSION
);
136 status
= inflateInit(strm
);
139 if (status
!= Z_OK
) {
140 LIBSSH2_FREE(session
, strm
);
150 /* {{{ libssh2_comp_method_zlib_comp
151 * zlib, a compression standard for all occasions
154 libssh2_comp_method_zlib_comp(LIBSSH2_SESSION
* session
,
156 unsigned char **dest
,
157 unsigned long *dest_len
,
158 unsigned long payload_limit
,
160 const unsigned char *src
,
161 unsigned long src_len
, void **abstract
)
163 z_stream
*strm
= *abstract
;
164 /* A short-term alloc of a full data chunk is better than a series of
167 int out_maxlen
= compress
? (src_len
+ 4) : (2 * src_len
);
170 /* In practice they never come smaller than this */
171 if (out_maxlen
< 25) {
175 if (out_maxlen
> (int) payload_limit
) {
176 out_maxlen
= payload_limit
;
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",
190 while (strm
->avail_in
) {
194 status
= deflate(strm
, Z_PARTIAL_FLUSH
);
196 status
= inflate(strm
, Z_PARTIAL_FLUSH
);
198 if (status
!= Z_OK
) {
199 libssh2_error(session
, LIBSSH2_ERROR_ZLIB
,
200 "compress/decompression failure", 0);
201 LIBSSH2_FREE(session
, out
);
204 if (strm
->avail_in
) {
205 unsigned long out_ofs
= out_maxlen
- strm
->avail_out
;
209 compress
? (strm
->avail_in
+ 4) : (2 * strm
->avail_in
);
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
);
218 newout
= LIBSSH2_REALLOC(session
, out
, out_maxlen
);
220 libssh2_error(session
, LIBSSH2_ERROR_ALLOC
,
221 "Unable to expand compress/decompression buffer",
223 LIBSSH2_FREE(session
, out
);
227 strm
->next_out
= (unsigned char *) out
+ out_ofs
;
229 compress
? (strm
->avail_in
+ 4) : (2 * strm
->avail_in
);
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
235 int grow_size
= compress
? 8 : 1024;
238 if (out_maxlen
>= (int) payload_limit
) {
239 libssh2_error(session
, LIBSSH2_ERROR_ZLIB
,
240 "Excessive growth in decompression phase",
242 LIBSSH2_FREE(session
, out
);
246 if (grow_size
> (int) (payload_limit
- out_maxlen
)) {
247 grow_size
= payload_limit
- out_maxlen
;
250 out_maxlen
+= grow_size
;
251 strm
->avail_out
= grow_size
;
253 newout
= LIBSSH2_REALLOC(session
, out
, out_maxlen
);
255 libssh2_error(session
, LIBSSH2_ERROR_ALLOC
,
256 "Unable to expand final compress/decompress buffer",
258 LIBSSH2_FREE(session
, out
);
262 strm
->next_out
= (unsigned char *) out
+ out_maxlen
-
266 status
= deflate(strm
, Z_PARTIAL_FLUSH
);
268 status
= inflate(strm
, Z_PARTIAL_FLUSH
);
270 if (status
!= Z_OK
) {
271 libssh2_error(session
, LIBSSH2_ERROR_ZLIB
,
272 "compress/decompression failure", 0);
273 LIBSSH2_FREE(session
, out
);
279 *dest
= (unsigned char *) out
;
280 *dest_len
= out_maxlen
- strm
->avail_out
;
288 /* {{{ libssh2_comp_method_zlib_dtor
289 * All done, no more compression for you
292 libssh2_comp_method_zlib_dtor(LIBSSH2_SESSION
* session
, int compress
,
295 z_stream
*strm
= *abstract
;
306 LIBSSH2_FREE(session
, strm
);
316 static const LIBSSH2_COMP_METHOD libssh2_comp_method_zlib
= {
318 libssh2_comp_method_zlib_init
,
319 libssh2_comp_method_zlib_comp
,
320 libssh2_comp_method_zlib_dtor
,
322 #endif /* LIBSSH2_HAVE_ZLIB */
324 /* ***********************
325 * Compression Methods *
326 *********************** */
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 */
336 const LIBSSH2_COMP_METHOD
**
337 libssh2_comp_methods(void)
339 return _libssh2_comp_methods
;