2 * http_contentdecoder.c
4 * Copyright (c) 2012 project bchan
6 * This software is provided 'as-is', without any express or implied
7 * warranty. In no event will the authors be held liable for any damages
8 * arising from the use of this software.
10 * Permission is granted to anyone to use this software for any purpose,
11 * including commercial applications, and to alter it and redistribute it
12 * freely, subject to the following restrictions:
14 * 1. The origin of this software must not be misrepresented; you must not
15 * claim that you wrote the original software. If you use this software
16 * in a product, an acknowledgment in the product documentation would be
17 * appreciated but is not required.
19 * 2. Altered source versions must be plainly marked as such, and must not be
20 * misrepresented as being the original software.
22 * 3. This notice may not be removed or altered from any source
27 #include "http_contentdecoder.h"
31 #include <util/zlib.h>
33 #ifdef BCHAN_CONFIG_DEBUG
34 # define DP(arg) printf arg
35 # define DP_ER(msg, err) printf("%s (%d/%x)\n", msg, err>>16, err)
38 # define DP_ER(msg, err) /**/
42 # define DP_STATE(state) printf("%s\n", state)
44 # define DP_STATE(state) /**/
47 LOCAL W http_contentdecoderidentity_inputentitybody(http_contentdecoderidentity_t *decoder, UB *data, W data_len)
49 decoder->state = HTTP_CONTENTDECODERIDENTITY_STATE_DATA;
51 decoder->data_len = data_len;
55 LOCAL W http_contentdecoderidentity_inputendofdata(http_contentdecoderidentity_t *decoder)
57 decoder->state = HTTP_CONTENTDECODERIDENTITY_STATE_END;
61 LOCAL W http_contentdecoderidentity_outputdata(http_contentdecoderidentity_t *decoder, http_contentdecoder_result **result, W *result_len, Bool *need_next)
63 switch (decoder->state) {
64 case HTTP_CONTENTDECODERIDENTITY_STATE_DATA:
65 decoder->result.type = HTTP_CONTENTDECODER_RESULTTYPE_DATA;
66 decoder->result.data = decoder->data;
67 decoder->result.len = decoder->data_len;
68 *result = &decoder->result;
72 case HTTP_CONTENTDECODERIDENTITY_STATE_END:
73 decoder->result.type = HTTP_CONTENTDECODER_RESULTTYPE_END;
74 decoder->result.data = NULL;
75 decoder->result.len = 0;
76 *result = &decoder->result;
85 LOCAL W http_contentdecoderidentity_initialize(http_contentdecoderidentity_t *decoder)
87 decoder->state = HTTP_CONTENTDECODERIDENTITY_STATE_DATA;
89 decoder->data_len = 0;
93 LOCAL VOID http_contentdecoderidentity_finalize(http_contentdecoderidentity_t *decoder)
99 LOCAL W gzip_headerskip_inputchar(gzip_headerskip_t *gzip, UB ch, Bool *is_end)
103 switch (gzip->state) {
104 case GZIP_HEADERSKIP_STATE_MAGIC_NUMBER_FIRST:
106 return -1; /* TODO: format error */
108 gzip->state = GZIP_HEADERSKIP_STATE_MAGIC_NUMBER_SECOND;
110 case GZIP_HEADERSKIP_STATE_MAGIC_NUMBER_SECOND:
112 return -1; /* TODO: format error */
114 gzip->state = GZIP_HEADERSKIP_STATE_METHOD;
116 case GZIP_HEADERSKIP_STATE_METHOD:
117 if (ch != Z_DEFLATED) {
118 return -1; /* TODO: format error */
120 gzip->state = GZIP_HEADERSKIP_STATE_FLAGS;
122 case GZIP_HEADERSKIP_STATE_FLAGS:
124 gzip->state = GZIP_HEADERSKIP_STATE_SKIP_UNUSED_FIELD;
126 case GZIP_HEADERSKIP_STATE_SKIP_UNUSED_FIELD:
128 if (gzip->unused != 0) {
131 if (gzip->flags & 0x04) {
132 gzip->state = GZIP_HEADERSKIP_STATE_EXTRA_FIELD_LEN_FIRST;
133 } else if (gzip->flags & 0x08) {
134 gzip->state = GZIP_HEADERSKIP_STATE_SKIP_FILE_NAME;
135 } else if (gzip->flags & 0x10) {
136 gzip->state = GZIP_HEADERSKIP_STATE_SKIP_FILE_COMMENT;
137 } else if (gzip->flags & 0x02) {
138 gzip->state = GZIP_HEADERSKIP_STATE_SKIP_HEADER_CRC_FIRST;
143 case GZIP_HEADERSKIP_STATE_EXTRA_FIELD_LEN_FIRST:
144 gzip->extra_len = (W)ch;
145 gzip->state = GZIP_HEADERSKIP_STATE_EXTRA_FIELD_LEN_SECOND;
147 case GZIP_HEADERSKIP_STATE_EXTRA_FIELD_LEN_SECOND:
148 gzip->extra_len += (W)ch << 8;
149 gzip->state = GZIP_HEADERSKIP_STATE_SKIP_EXTRA_FIELD;
151 case GZIP_HEADERSKIP_STATE_SKIP_EXTRA_FIELD:
153 if (gzip->extra_len != 0) {
156 if (gzip->flags & 0x08) {
157 gzip->state = GZIP_HEADERSKIP_STATE_SKIP_FILE_NAME;
158 } else if (gzip->flags & 0x10) {
159 gzip->state = GZIP_HEADERSKIP_STATE_SKIP_FILE_COMMENT;
160 } else if (gzip->flags & 0x02) {
161 gzip->state = GZIP_HEADERSKIP_STATE_SKIP_HEADER_CRC_FIRST;
166 case GZIP_HEADERSKIP_STATE_SKIP_FILE_NAME:
170 if (gzip->flags & 0x10) {
171 gzip->state = GZIP_HEADERSKIP_STATE_SKIP_FILE_COMMENT;
172 } else if (gzip->flags & 0x02) {
173 gzip->state = GZIP_HEADERSKIP_STATE_SKIP_HEADER_CRC_FIRST;
178 case GZIP_HEADERSKIP_STATE_SKIP_FILE_COMMENT:
182 if (gzip->flags & 0x02) {
183 gzip->state = GZIP_HEADERSKIP_STATE_SKIP_HEADER_CRC_FIRST;
188 case GZIP_HEADERSKIP_STATE_SKIP_HEADER_CRC_FIRST:
189 gzip->state = GZIP_HEADERSKIP_STATE_SKIP_HEADER_CRC_SECOND;
191 case GZIP_HEADERSKIP_STATE_SKIP_HEADER_CRC_SECOND:
198 LOCAL VOID gzip_headerskip_initialize(gzip_headerskip_t *gzip)
200 gzip->state = GZIP_HEADERSKIP_STATE_MAGIC_NUMBER_FIRST;
206 LOCAL VOID gzip_headerskip_finalize(gzip_headerskip_t *gzip)
212 LOCAL W http_contentdecodergzip_inputentitybody(http_contentdecodergzip_t *decoder, UB *data, W data_len)
217 switch (decoder->state) {
218 case HTTP_CONTENTDECODERGZIP_STATE_SKIP_HEADER:
219 DP_STATE("HTTP_CONTENTDECODERGZIP_STATE_SKIP_HEADER");
220 for (i = 0; i < data_len; i++) {
221 err = gzip_headerskip_inputchar(&decoder->gzipheader, data[i], &is_end);
225 if (is_end != False) {
226 decoder->state = HTTP_CONTENTDECODERGZIP_STATE_DECODE;
227 decoder->z.next_in = data + i + 1;
228 decoder->z.avail_in = data_len - (i + 1);
233 case HTTP_CONTENTDECODERGZIP_STATE_DECODE:
234 DP_STATE("HTTP_CONTENTDECODERGZIP_STATE_DECODE");
235 decoder->z.next_in = data;
236 decoder->z.avail_in = data_len;
238 case HTTP_CONTENTDECODERGZIP_STATE_END_OF_DATA:
239 DP_STATE("HTTP_CONTENTDECODERGZIP_STATE_END_OF_DATA");
240 return -1; /* TODO */
246 LOCAL W http_contentdecodergzip_inputendofdata(http_contentdecodergzip_t *decoder)
248 decoder->state = HTTP_CONTENTDECODERGZIP_STATE_END_OF_DATA;
252 LOCAL W http_contentdecodergzip_outputdata(http_contentdecodergzip_t *decoder, http_contentdecoder_result **result, W *result_len, Bool *need_input)
256 switch (decoder->state) {
257 case HTTP_CONTENTDECODERGZIP_STATE_SKIP_HEADER:
262 case HTTP_CONTENTDECODERGZIP_STATE_DECODE:
263 if (decoder->z.avail_in == 0) {
271 *result = decoder->result;
273 err = inflate(&(decoder->z), Z_NO_FLUSH);
274 if (err == Z_STREAM_END) {
275 decoder->result[0].type = HTTP_CONTENTDECODER_RESULTTYPE_DATA;
276 decoder->result[0].data = decoder->buffer;
277 decoder->result[0].len = HTTP_CONTENTDECODERGZIP_BUFLEN - decoder->z.avail_out;
279 decoder->state = HTTP_CONTENTDECODERGZIP_STATE_END_OF_DATA;
283 DP_ER("inflate error:", err);
286 if (decoder->z.avail_out == 0) {
287 decoder->result[0].type = HTTP_CONTENTDECODER_RESULTTYPE_DATA;
288 decoder->result[0].data = decoder->buffer;
289 decoder->result[0].len = HTTP_CONTENTDECODERGZIP_BUFLEN;
291 decoder->z.next_out = decoder->buffer;
292 decoder->z.avail_out = HTTP_CONTENTDECODERGZIP_BUFLEN;
299 case HTTP_CONTENTDECODERGZIP_STATE_END_OF_DATA:
300 decoder->result[0].type = HTTP_CONTENTDECODER_RESULTTYPE_END;
301 decoder->result[0].data = NULL;
302 decoder->result[0].len = 0;
311 LOCAL W http_contentdecodergzip_initialize(http_contentdecodergzip_t *decoder)
315 decoder->z.zalloc = Z_NULL;
316 decoder->z.zfree = Z_NULL;
317 decoder->z.opaque = Z_NULL;
318 decoder->z.next_in = Z_NULL;
319 decoder->z.avail_in = 0;
320 err = inflateInit2(&(decoder->z), -MAX_WBITS);
322 DP_ER("inflateInit2 error:", err);
325 decoder->z.next_out = decoder->buffer;
326 decoder->z.avail_out = HTTP_CONTENTDECODERGZIP_BUFLEN;
328 gzip_headerskip_initialize(&decoder->gzipheader);
329 decoder->state = HTTP_CONTENTDECODERGZIP_STATE_SKIP_HEADER;
334 LOCAL VOID http_contentdecodergzip_finalize(http_contentdecodergzip_t *decoder)
336 gzip_headerskip_finalize(&decoder->gzipheader);
337 inflateEnd(&(decoder->z));
342 EXPORT W http_contentdecoder_inputentitybody(http_contentdecoder_t *decoder, UB *data, W data_len)
344 switch (decoder->type) {
345 case HTTP_CONTENTCODING_VALUE_IDENTITY:
346 return http_contentdecoderidentity_inputentitybody(&decoder->d.identity, data, data_len);
347 case HTTP_CONTENTCODING_VALUE_GZIP:
348 return http_contentdecodergzip_inputentitybody(&decoder->d.gzip, data, data_len);
349 case HTTP_CONTENTCODING_VALUE_COMPRESS: /* unsupported yet */
350 case HTTP_CONTENTCODING_VALUE_DEFLATE: /* unsupported yet */
355 EXPORT W http_contentdecoder_inputendofdata(http_contentdecoder_t *decoder)
357 switch (decoder->type) {
358 case HTTP_CONTENTCODING_VALUE_IDENTITY:
359 return http_contentdecoderidentity_inputendofdata(&decoder->d.identity);
360 case HTTP_CONTENTCODING_VALUE_GZIP:
361 return http_contentdecodergzip_inputendofdata(&decoder->d.gzip);
362 case HTTP_CONTENTCODING_VALUE_COMPRESS: /* unsupported yet */
363 case HTTP_CONTENTCODING_VALUE_DEFLATE: /* unsupported yet */
368 EXPORT W http_contentdecoder_outputdata(http_contentdecoder_t *decoder, http_contentdecoder_result **result, W *result_len, Bool *need_input)
370 switch (decoder->type) {
371 case HTTP_CONTENTCODING_VALUE_IDENTITY:
372 return http_contentdecoderidentity_outputdata(&decoder->d.identity, result, result_len, need_input);
373 case HTTP_CONTENTCODING_VALUE_GZIP:
374 return http_contentdecodergzip_outputdata(&decoder->d.gzip, result, result_len, need_input);
375 case HTTP_CONTENTCODING_VALUE_COMPRESS: /* unsupported yet */
376 case HTTP_CONTENTCODING_VALUE_DEFLATE: /* unsupported yet */
381 EXPORT W http_contentdecoder_initialize(http_contentdecoder_t *decoder, HTTP_CONTENTCODING_VALUE type)
383 decoder->type = type;
385 case HTTP_CONTENTCODING_VALUE_IDENTITY:
386 return http_contentdecoderidentity_initialize(&decoder->d.identity);
387 case HTTP_CONTENTCODING_VALUE_GZIP:
388 return http_contentdecodergzip_initialize(&decoder->d.gzip);
389 case HTTP_CONTENTCODING_VALUE_COMPRESS: /* unsupported yet */
390 case HTTP_CONTENTCODING_VALUE_DEFLATE: /* unsupported yet */
395 EXPORT VOID http_contentdecoder_finalize(http_contentdecoder_t *decoder)
397 switch (decoder->type) {
398 case HTTP_CONTENTCODING_VALUE_IDENTITY:
399 http_contentdecoderidentity_finalize(&decoder->d.identity);
401 case HTTP_CONTENTCODING_VALUE_GZIP:
402 http_contentdecodergzip_finalize(&decoder->d.gzip);
404 case HTTP_CONTENTCODING_VALUE_COMPRESS: /* unsupported yet */
405 case HTTP_CONTENTCODING_VALUE_DEFLATE: /* unsupported yet */