1 /* deflate/gzip encoding backend */
19 #include "encoding/deflate.h"
20 #include "encoding/encoding.h"
21 #include "util/memory.h"
23 /* How many bytes of compressed data to read before decompressing. */
24 #define ELINKS_DEFLATE_BUFFER_LENGTH 5000
26 struct deflate_enc_data
{
27 z_stream deflate_stream
;
29 /* The file descriptor from which we read. */
32 unsigned int last_read
:1;
34 /* A buffer for data that has been read from the file but not
35 * yet decompressed. z_stream.next_in and z_stream.avail_in
36 * refer to this buffer. */
37 unsigned char buf
[ELINKS_DEFLATE_BUFFER_LENGTH
];
41 deflate_open(int window_size
, struct stream_encoded
*stream
, int fd
)
43 /* A zero-initialized z_stream. The compiler ensures that all
44 * pointer members in it are null. (Can't do this with memset
45 * because C99 does not require all-bits-zero to be a null
47 static const z_stream null_z_stream
= {0};
50 struct deflate_enc_data
*data
= mem_alloc(sizeof(*data
));
57 /* Initialize all members of *data, except data->buf[], which
58 * will be initialized on demand by deflate_read. */
59 copy_struct(&data
->deflate_stream
, &null_z_stream
);
63 err
= inflateInit2(&data
->deflate_stream
, window_size
);
74 deflate_raw_open(struct stream_encoded
*stream
, int fd
)
76 /* raw DEFLATE with neither zlib nor gzip header */
77 return deflate_open(-MAX_WBITS
, stream
, fd
);
81 deflate_gzip_open(struct stream_encoded
*stream
, int fd
)
83 /* detect gzip header, else assume zlib header */
84 return deflate_open(MAX_WBITS
+ 32, stream
, fd
);
88 deflate_read(struct stream_encoded
*stream
, unsigned char *buf
, int len
)
90 struct deflate_enc_data
*data
= (struct deflate_enc_data
*) stream
->data
;
97 if (data
->last_read
) return 0;
99 data
->deflate_stream
.avail_out
= len
;
100 data
->deflate_stream
.next_out
= buf
;
103 if (data
->deflate_stream
.avail_in
== 0) {
104 int l
= safe_read(data
->fdread
, data
->buf
,
105 ELINKS_DEFLATE_BUFFER_LENGTH
);
111 return -1; /* I/O error */
113 /* EOF. It is error: we wait for more bytes */
117 data
->deflate_stream
.next_in
= data
->buf
;
118 data
->deflate_stream
.avail_in
= l
;
120 err
= inflate(&data
->deflate_stream
, Z_SYNC_FLUSH
);
121 if (err
== Z_STREAM_END
) {
124 } else if (err
!= Z_OK
) {
127 } while (data
->deflate_stream
.avail_out
> 0);
129 assert(len
- data
->deflate_stream
.avail_out
== data
->deflate_stream
.next_out
- buf
);
130 return len
- data
->deflate_stream
.avail_out
;
133 static unsigned char *
134 deflate_decode_buffer(int window_size
, unsigned char *data
, int len
, int *new_len
)
137 unsigned char *buffer
= NULL
;
140 *new_len
= 0; /* default, left there if an error occurs */
142 if (!len
) return NULL
;
143 memset(&stream
, 0, sizeof(z_stream
));
144 stream
.next_in
= data
;
145 stream
.avail_in
= len
;
147 if (inflateInit2(&stream
, window_size
) != Z_OK
)
151 unsigned char *new_buffer
;
152 size_t size
= stream
.total_out
+ MAX_STR_LEN
;
154 new_buffer
= mem_realloc(buffer
, size
);
161 stream
.next_out
= buffer
+ stream
.total_out
;
162 stream
.avail_out
= MAX_STR_LEN
;
164 error
= inflate(&stream
, Z_SYNC_FLUSH
);
165 if (error
== Z_STREAM_END
) {
169 } while (error
== Z_OK
&& stream
.avail_in
> 0);
174 *new_len
= stream
.total_out
;
177 if (buffer
) mem_free(buffer
);
182 static unsigned char *
183 deflate_raw_decode_buffer(unsigned char *data
, int len
, int *new_len
)
185 /* raw DEFLATE with neither zlib nor gzip header */
186 return deflate_decode_buffer(-MAX_WBITS
, data
, len
, new_len
);
189 static unsigned char *
190 deflate_gzip_decode_buffer(unsigned char *data
, int len
, int *new_len
)
192 /* detect gzip header, else assume zlib header */
193 return deflate_decode_buffer(MAX_WBITS
+ 32, data
, len
, new_len
);
197 deflate_close(struct stream_encoded
*stream
)
199 struct deflate_enc_data
*data
= (struct deflate_enc_data
*) stream
->data
;
202 inflateEnd(&data
->deflate_stream
);
209 static const unsigned char *const deflate_extensions
[] = { NULL
};
211 const struct decoding_backend deflate_decoding_backend
= {
216 deflate_raw_decode_buffer
,
220 static const unsigned char *const gzip_extensions
[] = { ".gz", ".tgz", NULL
};
222 const struct decoding_backend gzip_decoding_backend
= {
227 deflate_gzip_decode_buffer
,