1034: Initialize l in deflate_read to shut up GCC
[elinks.git] / src / encoding / deflate.c
blobf4b97f2a1799c5d39aecf5bcc6a37fc3dd25fece
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;
33 unsigned int after_first_read:1;
35 /* A buffer for data that has been read from the file but not
36 * yet decompressed. z_stream.next_in and z_stream.avail_in
37 * refer to this buffer. */
38 unsigned char buf[ELINKS_DEFLATE_BUFFER_LENGTH];
41 static int
42 deflate_open(int window_size, struct stream_encoded *stream, int fd)
44 /* A zero-initialized z_stream. The compiler ensures that all
45 * pointer members in it are null. (Can't do this with memset
46 * because C99 does not require all-bits-zero to be a null
47 * pointer.) */
48 static const z_stream null_z_stream = {0};
49 int err;
51 struct deflate_enc_data *data = mem_alloc(sizeof(*data));
53 stream->data = NULL;
54 if (!data) {
55 return -1;
58 /* Initialize all members of *data, except data->buf[], which
59 * will be initialized on demand by deflate_read. */
60 copy_struct(&data->deflate_stream, &null_z_stream);
61 data->fdread = fd;
62 data->last_read = 0;
63 data->after_first_read = 0;
65 err = inflateInit2(&data->deflate_stream, window_size);
66 if (err != Z_OK) {
67 mem_free(data);
68 return -1;
70 stream->data = data;
72 return 0;
75 #if 0
76 static int
77 deflate_raw_open(struct stream_encoded *stream, int fd)
79 /* raw DEFLATE with neither zlib nor gzip header */
80 return deflate_open(-MAX_WBITS, stream, fd);
82 #endif
84 static int
85 deflate_gzip_open(struct stream_encoded *stream, int fd)
87 /* detect gzip header, else assume zlib header */
88 return deflate_open(MAX_WBITS + 32, stream, fd);
91 static int
92 deflate_read(struct stream_encoded *stream, unsigned char *buf, int len)
94 struct deflate_enc_data *data = (struct deflate_enc_data *) stream->data;
95 int err = 0;
96 int l = 0;
98 if (!data) return -1;
100 assert(len > 0);
102 if (data->last_read) return 0;
104 data->deflate_stream.avail_out = len;
105 data->deflate_stream.next_out = buf;
107 do {
108 if (data->deflate_stream.avail_in == 0) {
109 l = safe_read(data->fdread, data->buf,
110 ELINKS_DEFLATE_BUFFER_LENGTH);
112 if (l == -1) {
113 if (errno == EAGAIN)
114 break;
115 else
116 return -1; /* I/O error */
117 } else if (l == 0) {
118 /* EOF. It is error: we wait for more bytes */
119 return -1;
122 data->deflate_stream.next_in = data->buf;
123 data->deflate_stream.avail_in = l;
125 restart:
126 err = inflate(&data->deflate_stream, Z_SYNC_FLUSH);
127 if (err == Z_DATA_ERROR && !data->after_first_read) {
128 data->after_first_read = 1;
129 inflateEnd(&data->deflate_stream);
130 data->deflate_stream.avail_out = len;
131 data->deflate_stream.next_out = buf;
132 data->deflate_stream.next_in = data->buf;
133 data->deflate_stream.avail_in = l;
134 err = inflateInit2(&data->deflate_stream, -MAX_WBITS);
135 if (err == Z_OK) goto restart;
137 data->after_first_read = 1;
138 if (err == Z_STREAM_END) {
139 data->last_read = 1;
140 break;
141 } else if (err != Z_OK) {
142 return -1;
144 } while (data->deflate_stream.avail_out > 0);
146 assert(len - data->deflate_stream.avail_out == data->deflate_stream.next_out - buf);
147 return len - data->deflate_stream.avail_out;
150 static unsigned char *
151 deflate_decode_buffer(int window_size, unsigned char *data, int len, int *new_len)
153 z_stream stream;
154 unsigned char *buffer = NULL;
155 int error;
157 *new_len = 0; /* default, left there if an error occurs */
159 if (!len) return NULL;
160 memset(&stream, 0, sizeof(z_stream));
161 stream.next_in = data;
162 stream.avail_in = len;
164 if (inflateInit2(&stream, window_size) != Z_OK)
165 return NULL;
167 do {
168 unsigned char *new_buffer;
169 size_t size = stream.total_out + MAX_STR_LEN;
171 new_buffer = mem_realloc(buffer, size);
172 if (!new_buffer) {
173 error = Z_MEM_ERROR;
174 break;
177 buffer = new_buffer;
178 stream.next_out = buffer + stream.total_out;
179 stream.avail_out = MAX_STR_LEN;
181 error = inflate(&stream, Z_SYNC_FLUSH);
182 if (error == Z_STREAM_END) {
183 error = Z_OK;
184 break;
186 } while (error == Z_OK && stream.avail_in > 0);
188 inflateEnd(&stream);
190 if (error == Z_OK) {
191 *new_len = stream.total_out;
192 return buffer;
193 } else {
194 if (buffer) mem_free(buffer);
195 return NULL;
199 static unsigned char *
200 deflate_raw_decode_buffer(unsigned char *data, int len, int *new_len)
202 /* raw DEFLATE with neither zlib nor gzip header */
203 return deflate_decode_buffer(-MAX_WBITS, data, len, new_len);
206 static unsigned char *
207 deflate_gzip_decode_buffer(unsigned char *data, int len, int *new_len)
209 /* detect gzip header, else assume zlib header */
210 return deflate_decode_buffer(MAX_WBITS + 32, data, len, new_len);
213 static void
214 deflate_close(struct stream_encoded *stream)
216 struct deflate_enc_data *data = (struct deflate_enc_data *) stream->data;
218 if (data) {
219 inflateEnd(&data->deflate_stream);
220 close(data->fdread);
221 mem_free(data);
222 stream->data = 0;
226 static const unsigned char *const deflate_extensions[] = { NULL };
228 const struct decoding_backend deflate_decoding_backend = {
229 "deflate",
230 deflate_extensions,
231 deflate_gzip_open,
232 deflate_read,
233 deflate_raw_decode_buffer,
234 deflate_close,
237 static const unsigned char *const gzip_extensions[] = { ".gz", ".tgz", NULL };
239 const struct decoding_backend gzip_decoding_backend = {
240 "gzip",
241 gzip_extensions,
242 deflate_gzip_open,
243 deflate_read,
244 deflate_gzip_decode_buffer,
245 deflate_close,