From 29a6c17d6796119f57cfaae32b887cbd253a4c9f Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 29 Aug 2005 18:01:38 +0000 Subject: [PATCH] Allow tor_gzip_uncompress to handle multiple concatenated compressed strings. svn:r4882 --- src/common/torgzip.c | 27 +++++++++++++++++++++++---- src/or/test.c | 12 +++++++++++- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/common/torgzip.c b/src/common/torgzip.c index f502c828b8..65f13b357f 100644 --- a/src/common/torgzip.c +++ b/src/common/torgzip.c @@ -30,6 +30,8 @@ const char torgzip_c_id[] = "$Id$"; static int gzip_is_supported = -1; +/** Return true iff we support gzip-based compression. Otherwise, we need to + * use zlib. */ int is_gzip_supported(void) { @@ -53,6 +55,11 @@ method_bits(compress_method_t method) return method == GZIP_METHOD ? 15+16 : 15; } +/** Given in_len bytes at in, compress them into a newly + * allocated buffer, using the method described in method. Store the + * compressed string in *out, and its length in *out_len. + * Return 0 on success, -1 on failure. + */ int tor_gzip_compress(char **out, size_t *out_len, const char *in, size_t in_len, @@ -138,7 +145,12 @@ tor_gzip_compress(char **out, size_t *out_len, return -1; } -/* DOCDOC -- sets *out to NULL on failure. */ +/** Given or more zlib-compressed or gzip-compressed strings of total length + * in_len bytes at in, uncompress them into a newly allocated + * buffer, using the method described in method. Store the uncompressed + * string in *out, and its length in *out_len. Return 0 on + * success, -1 on failure. + */ int tor_gzip_uncompress(char **out, size_t *out_len, const char *in, size_t in_len, @@ -186,13 +198,20 @@ tor_gzip_uncompress(char **out, size_t *out_len, switch (inflate(stream, Z_FINISH)) { case Z_STREAM_END: - goto done; + if (stream->avail_in == 0) + goto done; + if (inflateInit2(stream, method_bits(method)) != Z_OK) { + log_fn(LOG_WARN, "Error from inflateInit2: %s", + stream->msg?stream->msg:""); + goto err; + } + break; case Z_OK: /* In case zlib doesn't work as I think.... */ if (stream->avail_out >= stream->avail_in+16) break; case Z_BUF_ERROR: - offset = stream->next_out - ((unsigned char*)*out); + offset = stream->next_out - (unsigned char*)*out; out_size *= 2; *out = tor_realloc(*out, out_size); stream->next_out = (unsigned char*)(*out + offset); @@ -205,7 +224,7 @@ tor_gzip_uncompress(char **out, size_t *out_len, } } done: - *out_len = stream->total_out; + *out_len = stream->next_out - (unsigned char*)*out; r = inflateEnd(stream); tor_free(stream); if (r != Z_OK) { diff --git a/src/or/test.c b/src/or/test.c index 067cb9c6c1..3ba9a7fcfa 100644 --- a/src/or/test.c +++ b/src/or/test.c @@ -908,7 +908,7 @@ test_gzip(void) char *buf1, *buf2=NULL, *buf3=NULL; size_t len1, len2; - buf1 = tor_strdup("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + buf1 = tor_strdup("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAAAAAAAAAAAAAAAAZ"); test_eq(detect_compression_method(buf1, strlen(buf1)), 0); if (is_gzip_supported()) { test_assert(!tor_gzip_compress(&buf2, &len1, buf1, strlen(buf1)+1, @@ -935,6 +935,16 @@ test_gzip(void) test_assert(buf3); test_streq(buf1,buf3); + tor_free(buf3); + buf2 = tor_realloc(buf2, len1*2); + memcpy(buf2+len1, buf2, len1); + test_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1*2, ZLIB_METHOD)); + test_eq(len2, (strlen(buf1)+1)*2); + test_memeq(buf3, + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAAAAAAAAAAAAAAAAZ\0" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAAAAAAAAAAAAAAAAZ\0", + (strlen(buf1)+1)*2); + tor_free(buf2); tor_free(buf3); tor_free(buf1);