diff --git a/src/encoding/bzip2.c b/src/encoding/bzip2.c index 0291a3916..eb6f90cb4 100644 --- a/src/encoding/bzip2.c +++ b/src/encoding/bzip2.c @@ -19,13 +19,22 @@ #include "encoding/encoding.h" #include "util/memory.h" - struct bz2_enc_data { FILE *file; BZFILE *bzfile; int last_read; /* If err after last bzRead() was BZ_STREAM_END.. */ }; +struct bzFile { + FILE *handle; + char buf[BZ_MAX_UNUSED]; + int bufN; + unsigned char writing; + bz_stream strm; + int lastErr; + unsigned char initialisedOk; +}; + /* TODO: When it'll be official, use bzdopen() from Yoshioka Tsuneo. --pasky */ static int @@ -52,16 +61,112 @@ bzip2_open(struct stream_encoded *stream, int fd) return 0; } +static unsigned char +myfeof(FILE *f) +{ + int c = fgetc (f); + + if (c == EOF) return 1; + ungetc(c, f); + return 0; +} + +#define BZ_SETERR(eee) \ +{ \ + if (bzerror != NULL) *bzerror = eee; \ + if (bzf != NULL) bzf->lastErr = eee; \ +} + +static int +BZ2_bzRead2(int *bzerror, BZFILE *b, void *buf, int len) +{ + int n, ret, pi = 0; + struct bzFile *bzf = (struct bzFile *)b; + + BZ_SETERR(BZ_OK); + + if (bzf == NULL || buf == NULL || len < 0) { + BZ_SETERR(BZ_PARAM_ERROR); + return 0; + } + + if (bzf->writing) { + BZ_SETERR(BZ_SEQUENCE_ERROR); + return 0; + } + + if (len == 0) { + BZ_SETERR(BZ_OK); + return 0; + } + + bzf->strm.avail_out = len; + bzf->strm.next_out = buf; + + while (1) { + if (ferror(bzf->handle)) { + BZ_SETERR(BZ_IO_ERROR); + return 0; + } + + if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) { + n = fread(bzf->buf, 1, BZ_MAX_UNUSED, bzf->handle); + if (ferror(bzf->handle)) { + if (n < 0) { + BZ_SETERR(BZ_IO_ERROR); + return 0; + } else { + BZ_SETERR(BZ_OK); + pi = 1; + } + } + bzf->bufN = n; + bzf->strm.avail_in = bzf->bufN; + bzf->strm.next_in = bzf->buf; + } + + ret = BZ2_bzDecompress ( &(bzf->strm) ); + if (ret != BZ_OK && ret != BZ_STREAM_END) { + BZ_SETERR(ret); + return 0; + } + + if (ret == BZ_OK && myfeof(bzf->handle) && + bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0) { + if (!pi) { + BZ_SETERR(BZ_UNEXPECTED_EOF); + return 0; + } else { + return len - bzf->strm.avail_out; + } + } + + if (ret == BZ_STREAM_END) { + BZ_SETERR(BZ_STREAM_END); + return len - bzf->strm.avail_out; + } + + if (bzf->strm.avail_out == 0) { + BZ_SETERR(BZ_OK); + return len; + } + } + return 0; /*not reached*/ +} +#undef BZ_STRERR + static int bzip2_read(struct stream_encoded *stream, unsigned char *buf, int len) { struct bz2_enc_data *data = (struct bz2_enc_data *) stream->data; int err = 0; + struct bzFile *bzf = (struct bzFile *)data->bzfile; if (data->last_read) return 0; - len = BZ2_bzRead(&err, data->bzfile, buf, len); + clearerr(bzf->handle); + len = BZ2_bzRead2(&err, data->bzfile, buf, len); if (err == BZ_STREAM_END) data->last_read = 1; diff --git a/src/protocol/http/http.c b/src/protocol/http/http.c index 3c52195c0..7d9896c33 100644 --- a/src/protocol/http/http.c +++ b/src/protocol/http/http.c @@ -723,18 +723,14 @@ http_send_header(struct socket *socket) #if defined(CONFIG_GZIP) || defined(CONFIG_BZIP2) add_to_string(&header, "Accept-Encoding: "); -#ifdef BUG_517 #ifdef CONFIG_BZIP2 add_to_string(&header, "bzip2"); #endif -#endif #ifdef CONFIG_GZIP -#ifdef BUG_517 #ifdef CONFIG_BZIP2 add_to_string(&header, ", "); -#endif #endif add_to_string(&header, "gzip"); @@ -1820,13 +1816,13 @@ again: && (!strcasecmp(d, "gzip") || !strcasecmp(d, "x-gzip"))) conn->content_encoding = ENCODING_GZIP; #endif -#ifdef BUG_517 + #ifdef CONFIG_BZIP2 if (file_encoding != ENCODING_BZIP2 && (!strcasecmp(d, "bzip2") || !strcasecmp(d, "x-bzip2"))) conn->content_encoding = ENCODING_BZIP2; #endif -#endif + mem_free(d); }