1 /* Copyright 2004 Roger Dingledine */
2 /* Copyright 2004-2005 Roger Dingledine, Nick Mathewson */
3 /* See LICENSE for licensing information */
5 const char torgzip_c_id
[] = "$Id$";
10 * \brief Simple in-memory gzip implementation.
19 #include "..\..\contrib\zlib\zlib.h"
24 #ifdef HAVE_NETINET_IN_H
25 #include <netinet/in.h>
32 static int gzip_is_supported
= -1;
35 is_gzip_supported(void)
37 if (gzip_is_supported
>= 0)
38 return gzip_is_supported
;
40 if (!strcmpstart(ZLIB_VERSION
, "0.") ||
41 !strcmpstart(ZLIB_VERSION
, "1.0") ||
42 !strcmpstart(ZLIB_VERSION
, "1.1"))
43 gzip_is_supported
= 0;
45 gzip_is_supported
= 1;
47 return gzip_is_supported
;
51 method_bits(compress_method_t method
)
53 /* Bits+16 means "use gzip" in zlib >= 1.2 */
54 return method
== GZIP_METHOD
? 15+16 : 15;
58 tor_gzip_compress(char **out
, size_t *out_len
,
59 const char *in
, size_t in_len
,
60 compress_method_t method
)
62 struct z_stream_s
*stream
= NULL
;
70 if (method
== GZIP_METHOD
&& !is_gzip_supported()) {
71 /* Old zlib version don't support gzip in deflateInit2 */
72 log_fn(LOG_WARN
, "Gzip not supported with zlib %s", ZLIB_VERSION
);
78 stream
= tor_malloc_zero(sizeof(struct z_stream_s
));
79 stream
->zalloc
= Z_NULL
;
80 stream
->zfree
= Z_NULL
;
81 stream
->opaque
= NULL
;
82 stream
->next_in
= (unsigned char*) in
;
83 stream
->avail_in
= in_len
;
85 if (deflateInit2(stream
, Z_BEST_COMPRESSION
, Z_DEFLATED
,
87 8, Z_DEFAULT_STRATEGY
) != Z_OK
) {
88 log_fn(LOG_WARN
, "Error from deflateInit2: %s",
89 stream
->msg
?stream
->msg
:"<no message>");
93 /* Guess 50% compression. */
94 out_size
= in_len
/ 2;
95 if (out_size
< 1024) out_size
= 1024;
96 *out
= tor_malloc(out_size
);
97 stream
->next_out
= *out
;
98 stream
->avail_out
= out_size
;
101 switch (deflate(stream
, Z_FINISH
))
106 /* In case zlib doesn't work as I think .... */
107 if (stream
->avail_out
>= stream
->avail_in
+16)
110 offset
= stream
->next_out
- ((unsigned char*)*out
);
112 *out
= tor_realloc(*out
, out_size
);
113 stream
->next_out
= *out
+ offset
;
114 stream
->avail_out
= out_size
- offset
;
117 log_fn(LOG_WARN
, "Gzip compression didn't finish: %s",
118 stream
->msg
? stream
->msg
: "<no message>");
123 *out_len
= stream
->total_out
;
124 if (deflateEnd(stream
)!=Z_OK
) {
125 log_fn(LOG_WARN
, "Error freeing gzip structures");
142 /* DOCDOC -- sets *out to NULL on failure. */
144 tor_gzip_uncompress(char **out
, size_t *out_len
,
145 const char *in
, size_t in_len
,
146 compress_method_t method
)
148 struct z_stream_s
*stream
= NULL
;
156 if (method
== GZIP_METHOD
&& !is_gzip_supported()) {
157 /* Old zlib version don't support gzip in inflateInit2 */
158 log_fn(LOG_WARN
, "Gzip not supported with zlib %s", ZLIB_VERSION
);
164 stream
= tor_malloc_zero(sizeof(struct z_stream_s
));
165 stream
->zalloc
= Z_NULL
;
166 stream
->zfree
= Z_NULL
;
167 stream
->opaque
= NULL
;
168 stream
->next_in
= (unsigned char*) in
;
169 stream
->avail_in
= in_len
;
171 if (inflateInit2(stream
,
172 method_bits(method
)) != Z_OK
) {
173 log_fn(LOG_WARN
, "Error from inflateInit2: %s",
174 stream
->msg
?stream
->msg
:"<no message>");
178 out_size
= in_len
* 2; /* guess 50% compression. */
179 if (out_size
< 1024) out_size
= 1024;
181 *out
= tor_malloc(out_size
);
182 stream
->next_out
= *out
;
183 stream
->avail_out
= out_size
;
186 switch (inflate(stream
, Z_FINISH
))
191 /* In case zlib doesn't work as I think.... */
192 if (stream
->avail_out
>= stream
->avail_in
+16)
195 offset
= stream
->next_out
- ((unsigned char*)*out
);
197 *out
= tor_realloc(*out
, out_size
);
198 stream
->next_out
= *out
+ offset
;
199 stream
->avail_out
= out_size
- offset
;
202 log_fn(LOG_WARN
, "Gzip decompression returned an error: %s",
203 stream
->msg
? stream
->msg
: "<no message>");
209 *out_len
= stream
->total_out
;
210 if (inflateEnd(stream
)!=Z_OK
) {
211 log_fn(LOG_WARN
, "Error freeing gzip structures");
216 /* NUL-terminate output. */
217 if (out_size
== *out_len
)
218 *out
= tor_realloc(*out
, out_size
+ 1);
219 (*out
)[*out_len
] = '\0';
233 /** Try to tell whether the <b>in_len</b>-byte string in <b>in</b> is likely
234 * to be compressed or not. If it is, return the likeliest compression method.
235 * Otherwise, return 0.
237 int detect_compression_method(const char *in
, size_t in_len
)
239 if (in_len
> 2 && !memcmp(in
, "\x1f\x8b", 2)) {
241 } else if (in_len
> 2 && (in
[0] & 0x0f) == 8 &&
242 (ntohs(get_uint16(in
)) % 31) == 0) {