1 /* Copyright 2004 Roger Dingledine */
2 /* See LICENSE for licensing information */
4 const char torgzip_c_id
[] = "$Id$";
9 * \brief Simple in-memory gzip implementation.
18 #include "..\..\contrib\zlib\zlib.h"
23 #ifdef HAVE_NETINET_IN_H
24 #include <netinet/in.h>
31 static int gzip_is_supported
= -1;
34 is_gzip_supported(void)
36 if (gzip_is_supported
>= 0)
37 return gzip_is_supported
;
39 if (!strcmpstart(ZLIB_VERSION
, "0.") ||
40 !strcmpstart(ZLIB_VERSION
, "1.0") ||
41 !strcmpstart(ZLIB_VERSION
, "1.1"))
42 gzip_is_supported
= 0;
44 gzip_is_supported
= 1;
46 return gzip_is_supported
;
50 method_bits(compress_method_t method
)
52 /* Bits+16 means "use gzip" in zlib >= 1.2 */
53 return method
== GZIP_METHOD
? 15+16 : 15;
57 tor_gzip_compress(char **out
, size_t *out_len
,
58 const char *in
, size_t in_len
,
59 compress_method_t method
)
61 struct z_stream_s
*stream
= NULL
;
69 if (method
== GZIP_METHOD
&& !is_gzip_supported()) {
70 /* Old zlib version don't support gzip in deflateInit2 */
71 log_fn(LOG_WARN
, "Gzip not supported with zlib %s", ZLIB_VERSION
);
77 stream
= tor_malloc_zero(sizeof(struct z_stream_s
));
78 stream
->zalloc
= Z_NULL
;
79 stream
->zfree
= Z_NULL
;
80 stream
->opaque
= NULL
;
81 stream
->next_in
= (unsigned char*) in
;
82 stream
->avail_in
= in_len
;
84 if (deflateInit2(stream
, Z_BEST_COMPRESSION
, Z_DEFLATED
,
86 8, Z_DEFAULT_STRATEGY
) != Z_OK
) {
87 log_fn(LOG_WARN
, "Error from deflateInit2: %s",
88 stream
->msg
?stream
->msg
:"<no message>");
92 /* Guess 50% compression. */
93 out_size
= in_len
/ 2;
94 if (out_size
< 1024) out_size
= 1024;
95 *out
= tor_malloc(out_size
);
96 stream
->next_out
= *out
;
97 stream
->avail_out
= out_size
;
100 switch (deflate(stream
, Z_FINISH
))
105 /* In case zlib doesn't work as I think .... */
106 if (stream
->avail_out
>= stream
->avail_in
+16)
109 offset
= stream
->next_out
- ((unsigned char*)*out
);
111 *out
= tor_realloc(*out
, out_size
);
112 stream
->next_out
= *out
+ offset
;
113 stream
->avail_out
= out_size
- offset
;
116 log_fn(LOG_WARN
, "Gzip compression didn't finish: %s",
117 stream
->msg
? stream
->msg
: "<no message>");
122 *out_len
= stream
->total_out
;
123 if (deflateEnd(stream
)!=Z_OK
) {
124 log_fn(LOG_WARN
, "Error freeing gzip structures");
141 /* DOCDOC -- sets *out to NULL on failure. */
143 tor_gzip_uncompress(char **out
, size_t *out_len
,
144 const char *in
, size_t in_len
,
145 compress_method_t method
)
147 struct z_stream_s
*stream
= NULL
;
155 if (method
== GZIP_METHOD
&& !is_gzip_supported()) {
156 /* Old zlib version don't support gzip in inflateInit2 */
157 log_fn(LOG_WARN
, "Gzip not supported with zlib %s", ZLIB_VERSION
);
163 stream
= tor_malloc_zero(sizeof(struct z_stream_s
));
164 stream
->zalloc
= Z_NULL
;
165 stream
->zfree
= Z_NULL
;
166 stream
->opaque
= NULL
;
167 stream
->next_in
= (unsigned char*) in
;
168 stream
->avail_in
= in_len
;
170 if (inflateInit2(stream
,
171 method_bits(method
)) != Z_OK
) {
172 log_fn(LOG_WARN
, "Error from inflateInit2: %s",
173 stream
->msg
?stream
->msg
:"<no message>");
177 out_size
= in_len
* 2; /* guess 50% compression. */
178 if (out_size
< 1024) out_size
= 1024;
180 *out
= tor_malloc(out_size
);
181 stream
->next_out
= *out
;
182 stream
->avail_out
= out_size
;
185 switch (inflate(stream
, Z_FINISH
))
190 /* In case zlib doesn't work as I think.... */
191 if (stream
->avail_out
>= stream
->avail_in
+16)
194 offset
= stream
->next_out
- ((unsigned char*)*out
);
196 *out
= tor_realloc(*out
, out_size
);
197 stream
->next_out
= *out
+ offset
;
198 stream
->avail_out
= out_size
- offset
;
201 log_fn(LOG_WARN
, "Gzip decompression returned an error: %s",
202 stream
->msg
? stream
->msg
: "<no message>");
208 *out_len
= stream
->total_out
;
209 if (inflateEnd(stream
)!=Z_OK
) {
210 log_fn(LOG_WARN
, "Error freeing gzip structures");
215 /* NUL-terminate output. */
216 if (out_size
== *out_len
)
217 *out
= tor_realloc(*out
, out_size
+ 1);
218 (*out
)[*out_len
] = '\0';
232 /** Try to tell whether the <b>in_len</b>-byte string in <b>in</b> is likely
233 * to be compressed or not. If it is, return the likeliest compression method.
234 * Otherwise, return 0.
236 int detect_compression_method(const char *in
, size_t in_len
)
238 if (in_len
> 2 && !memcmp(in
, "\x1f\x8b", 2)) {
240 } else if (in_len
> 2 && (in
[0] & 0x0f) == 8 &&
241 (ntohs(get_uint16(in
)) % 31) == 0) {