1008: Added upload_progress to the connection.
[elinks.git] / src / encoding / deflate.c
blob4d76ed50e0a851594b95b2e22a0ed9f9b61dd02b
1 /* deflate/gzip encoding backend */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <stdio.h>
8 #include <string.h>
9 #ifdef HAVE_UNISTD_H
10 #include <unistd.h>
11 #endif
12 #ifdef HAVE_ZLIB_H
13 #include <zlib.h>
14 #endif
15 #include <errno.h>
17 #include "elinks.h"
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. */
30 int fdread;
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];
40 static int
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
46 * pointer.) */
47 static const z_stream null_z_stream = {0};
48 int err;
50 struct deflate_enc_data *data = mem_alloc(sizeof(*data));
52 stream->data = NULL;
53 if (!data) {
54 return -1;
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);
60 data->fdread = fd;
61 data->last_read = 0;
63 err = inflateInit2(&data->deflate_stream, window_size);
64 if (err != Z_OK) {
65 mem_free(data);
66 return -1;
68 stream->data = data;
70 return 0;
73 static int
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);
80 static int
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);
87 static int
88 deflate_read(struct stream_encoded *stream, unsigned char *buf, int len)
90 struct deflate_enc_data *data = (struct deflate_enc_data *) stream->data;
91 int err = 0;
93 if (!data) return -1;
95 assert(len > 0);
97 if (data->last_read) return 0;
99 data->deflate_stream.avail_out = len;
100 data->deflate_stream.next_out = buf;
102 do {
103 if (data->deflate_stream.avail_in == 0) {
104 int l = safe_read(data->fdread, data->buf,
105 ELINKS_DEFLATE_BUFFER_LENGTH);
107 if (l == -1) {
108 if (errno == EAGAIN)
109 break;
110 else
111 return -1; /* I/O error */
112 } else if (l == 0) {
113 /* EOF. It is error: we wait for more bytes */
114 return -1;
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) {
122 data->last_read = 1;
123 break;
124 } else if (err != Z_OK) {
125 return -1;
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)
136 z_stream stream;
137 unsigned char *buffer = NULL;
138 int error;
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)
148 return NULL;
150 do {
151 unsigned char *new_buffer;
152 size_t size = stream.total_out + MAX_STR_LEN;
154 new_buffer = mem_realloc(buffer, size);
155 if (!new_buffer) {
156 error = Z_MEM_ERROR;
157 break;
160 buffer = new_buffer;
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) {
166 error = Z_OK;
167 break;
169 } while (error == Z_OK && stream.avail_in > 0);
171 inflateEnd(&stream);
173 if (error == Z_OK) {
174 *new_len = stream.total_out;
175 return buffer;
176 } else {
177 if (buffer) mem_free(buffer);
178 return NULL;
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);
196 static void
197 deflate_close(struct stream_encoded *stream)
199 struct deflate_enc_data *data = (struct deflate_enc_data *) stream->data;
201 if (data) {
202 inflateEnd(&data->deflate_stream);
203 close(data->fdread);
204 mem_free(data);
205 stream->data = 0;
209 static const unsigned char *const deflate_extensions[] = { NULL };
211 const struct decoding_backend deflate_decoding_backend = {
212 "deflate",
213 deflate_extensions,
214 deflate_raw_open,
215 deflate_read,
216 deflate_raw_decode_buffer,
217 deflate_close,
220 static const unsigned char *const gzip_extensions[] = { ".gz", ".tgz", NULL };
222 const struct decoding_backend gzip_decoding_backend = {
223 "gzip",
224 gzip_extensions,
225 deflate_gzip_open,
226 deflate_read,
227 deflate_gzip_decode_buffer,
228 deflate_close,