Initial revision
This commit is contained in:
249
src/comp.c
Normal file
249
src/comp.c
Normal file
@@ -0,0 +1,249 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* Neither the name of the copyright holder nor the names
|
||||
* of any other contributors may be used to endorse or
|
||||
* promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include <zlib.h>
|
||||
|
||||
/* ********
|
||||
* none *
|
||||
******** */
|
||||
|
||||
/* {{{ libssh2_comp_method_none_comp
|
||||
* Minimalist compression: Absolutely none
|
||||
*/
|
||||
static int libssh2_comp_method_none_comp(LIBSSH2_SESSION *session, int compress,
|
||||
unsigned char **dest, unsigned long *dest_len, unsigned long payload_limit, int *free_dest,
|
||||
const unsigned char *src, unsigned long src_len, void **abstract)
|
||||
{
|
||||
*dest = (unsigned char *)src;
|
||||
*dest_len = src_len;
|
||||
|
||||
*free_dest = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static LIBSSH2_COMP_METHOD libssh2_comp_method_none = {
|
||||
"none",
|
||||
NULL,
|
||||
libssh2_comp_method_none_comp,
|
||||
NULL
|
||||
};
|
||||
|
||||
#ifdef LIBSSH2_HAVE_ZLIB
|
||||
/* ********
|
||||
* zlib *
|
||||
******** */
|
||||
|
||||
/* {{{ Memory management wrappers
|
||||
* Yes, I realize we're doing a callback to a callback,
|
||||
* Deal...
|
||||
*/
|
||||
|
||||
static voidpf libssh2_comp_method_zlib_alloc(voidpf opaque, uInt items, uInt size)
|
||||
{
|
||||
LIBSSH2_SESSION *session = (LIBSSH2_SESSION*)opaque;
|
||||
|
||||
return (voidpf)LIBSSH2_ALLOC(session, items * size);
|
||||
}
|
||||
|
||||
static void libssh2_comp_method_zlib_free(voidpf opaque, voidpf address)
|
||||
{
|
||||
LIBSSH2_SESSION *session = (LIBSSH2_SESSION*)opaque;
|
||||
|
||||
LIBSSH2_FREE(session, address);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_comp_method_zlib_init
|
||||
* All your bandwidth are belong to us (so save some)
|
||||
*/
|
||||
static int libssh2_comp_method_zlib_init(LIBSSH2_SESSION *session, int compress, void **abstract)
|
||||
{
|
||||
z_stream *strm;
|
||||
int status;
|
||||
|
||||
strm = LIBSSH2_ALLOC(session, sizeof(z_stream));
|
||||
if (!strm) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for zlib compression/decompression", 0);
|
||||
return -1;
|
||||
}
|
||||
memset(strm, 0, sizeof(z_stream));
|
||||
|
||||
strm->opaque = (voidpf)session;
|
||||
strm->zalloc = (alloc_func)libssh2_comp_method_zlib_alloc;
|
||||
strm->zfree = (free_func)libssh2_comp_method_zlib_free;
|
||||
if (compress) {
|
||||
/* deflate */
|
||||
status = deflateInit(strm, Z_DEFAULT_COMPRESSION);
|
||||
} else {
|
||||
/* inflate */
|
||||
status = inflateInit(strm);
|
||||
}
|
||||
|
||||
if (status != Z_OK) {
|
||||
LIBSSH2_FREE(session, strm);
|
||||
return -1;
|
||||
}
|
||||
*abstract = strm;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_comp_method_zlib_comp
|
||||
* zlib, a compression standard for all occasions
|
||||
*/
|
||||
static int libssh2_comp_method_zlib_comp(LIBSSH2_SESSION *session, int compress,
|
||||
unsigned char **dest, unsigned long *dest_len, unsigned long payload_limit, int *free_dest,
|
||||
const unsigned char *src, unsigned long src_len, void **abstract)
|
||||
{
|
||||
z_stream *strm = *abstract;
|
||||
/* A short-term alloc of a full data chunk is better than a series of reallocs */
|
||||
char *out;
|
||||
int out_maxlen = compress ? src_len : (2 * src_len);
|
||||
int limiter = 0;
|
||||
|
||||
/* In practice they never come smaller than this */
|
||||
if (out_maxlen < 21) {
|
||||
out_maxlen = 21;
|
||||
}
|
||||
|
||||
if (out_maxlen > payload_limit) {
|
||||
out_maxlen = payload_limit;
|
||||
}
|
||||
|
||||
strm->next_in = (char *)src;
|
||||
strm->avail_in = src_len;
|
||||
out = strm->next_out = LIBSSH2_ALLOC(session, out_maxlen);
|
||||
strm->avail_out = out_maxlen;
|
||||
if (!strm->next_out) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate compression/decompression buffer", 0);
|
||||
return -1;
|
||||
}
|
||||
while (strm->avail_in) {
|
||||
int status;
|
||||
|
||||
if (compress) {
|
||||
status = deflate(strm, Z_PARTIAL_FLUSH);
|
||||
} else {
|
||||
status = inflate(strm, Z_PARTIAL_FLUSH);
|
||||
}
|
||||
if (status != Z_OK) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ZLIB, "compress/decompression failure", 0);
|
||||
LIBSSH2_FREE(session, strm->next_out);
|
||||
return -1;
|
||||
}
|
||||
if (strm->avail_in) {
|
||||
unsigned long out_ofs = out_maxlen - strm->avail_out;
|
||||
|
||||
out_maxlen += compress ? strm->avail_in : (2 * strm->avail_in);
|
||||
|
||||
if ((out_maxlen > payload_limit) && !compress && limiter++) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ZLIB, "Excessive growth in decompression phase", 0);
|
||||
LIBSSH2_FREE(session, strm->next_out);
|
||||
return -1;
|
||||
}
|
||||
|
||||
out = LIBSSH2_REALLOC(session, out, out_maxlen);
|
||||
if (!out) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to expand compress/decompression buffer", 0);
|
||||
return -1;
|
||||
}
|
||||
strm->next_out = out + out_ofs;
|
||||
strm->avail_out += compress ? strm->avail_in : (2 * strm->avail_in);
|
||||
}
|
||||
}
|
||||
|
||||
*dest = out;
|
||||
*dest_len = out_maxlen - strm->avail_out;
|
||||
*free_dest = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_comp_method_zlib_dtor
|
||||
* All done, no more compression for you
|
||||
*/
|
||||
static int libssh2_comp_method_zlib_dtor(LIBSSH2_SESSION *session, int compress, void **abstract)
|
||||
{
|
||||
z_stream *strm = *abstract;
|
||||
|
||||
if (strm) {
|
||||
if (compress) {
|
||||
/* deflate */
|
||||
deflateEnd(strm);
|
||||
} else {
|
||||
/* inflate */
|
||||
inflateEnd(strm);
|
||||
}
|
||||
|
||||
LIBSSH2_FREE(session, strm);
|
||||
}
|
||||
|
||||
*abstract = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static LIBSSH2_COMP_METHOD libssh2_comp_method_zlib = {
|
||||
"zlib",
|
||||
libssh2_comp_method_zlib_init,
|
||||
libssh2_comp_method_zlib_comp,
|
||||
libssh2_comp_method_zlib_dtor,
|
||||
};
|
||||
#endif /* LIBSSH2_HAVE_ZLIB */
|
||||
|
||||
/* ***********************
|
||||
* Compression Methods *
|
||||
*********************** */
|
||||
|
||||
static LIBSSH2_COMP_METHOD *_libssh2_comp_methods[] = {
|
||||
#ifdef LIBSSH2_HAVE_ZLIB
|
||||
&libssh2_comp_method_zlib,
|
||||
#endif /* LIBSSH2_HAVE_ZLIB */
|
||||
&libssh2_comp_method_none,
|
||||
NULL
|
||||
};
|
||||
|
||||
LIBSSH2_COMP_METHOD **libssh2_comp_methods(void) {
|
||||
return _libssh2_comp_methods;
|
||||
}
|
||||
|
Reference in New Issue
Block a user