diff --git a/AUTHORS b/AUTHORS index f65085d..b08ec55 100644 --- a/AUTHORS +++ b/AUTHORS @@ -215,6 +215,9 @@ Hugo Haas Minor random hacking debian/watch file + + bzip2 decoding fix and rewrite + Ingo Blechschmidt German translation updates diff --git a/src/encoding/bzip2.c b/src/encoding/bzip2.c index 0291a39..c33b88e 100644 --- a/src/encoding/bzip2.c +++ b/src/encoding/bzip2.c @@ -12,6 +12,7 @@ #endif #ifdef HAVE_BZLIB_H #include /* Everything needs this after stdio.h */ #endif +#include #include "elinks.h" @@ -20,29 +21,32 @@ #include "encoding/encoding.h" #include "util/memory.h" +#define ELINKS_BZ_BUFFER_LENGTH BZ_MAX_UNUSED + struct bz2_enc_data { - FILE *file; - BZFILE *bzfile; - int last_read; /* If err after last bzRead() was BZ_STREAM_END.. */ + int fdread; + bz_stream fbz_stream; + int last_read; /* If err after last bzDecompress was BZ_STREAM_END.. */ + unsigned char buf[ELINKS_BZ_BUFFER_LENGTH]; }; -/* TODO: When it'll be official, use bzdopen() from Yoshioka Tsuneo. --pasky */ - static int bzip2_open(struct stream_encoded *stream, int fd) { struct bz2_enc_data *data = mem_alloc(sizeof(*data)); int err; + stream->data = 0; if (!data) { return -1; } - data->last_read = 0; - - data->file = fdopen(fd, "rb"); + memset(data, 0, sizeof(struct bz2_enc_data) - ELINKS_BZ_BUFFER_LENGTH); - data->bzfile = BZ2_bzReadOpen(&err, data->file, 0, 0, NULL, 0); - if (!data->bzfile) { + data->last_read = 0; + data->fdread = fd; + + err = BZ2_bzDecompressInit(&data->fbz_stream, 0, 0); + if (err != BZ_OK) { mem_free(data); return -1; } @@ -58,17 +62,44 @@ bzip2_read(struct stream_encoded *stream struct bz2_enc_data *data = (struct bz2_enc_data *) stream->data; int err = 0; - if (data->last_read) - return 0; + if (!data) return -1; - len = BZ2_bzRead(&err, data->bzfile, buf, len); + assert(len > 0); - if (err == BZ_STREAM_END) - data->last_read = 1; - else if (err) - return -1; + if (data->last_read) return 0; + + data->fbz_stream.avail_out = len; + data->fbz_stream.next_out = buf; + + do { + if (data->fbz_stream.avail_in == 0) { + int l = safe_read(data->fdread, data->buf, + ELINKS_BZ_BUFFER_LENGTH); - return len; + if (l == -1) { + if (errno == EAGAIN) + break; + else + return -1; /* I/O error */ + } else if (l == 0) { + /* EOF. It is error: we wait for more bytes */ + return -1; + } + + data->fbz_stream.next_in = data->buf; + data->fbz_stream.avail_in = l; + } + + err = BZ2_bzDecompress(&data->fbz_stream); + if (err == BZ_STREAM_END) { + data->last_read = 1; + break; + } else if (err != BZ_OK) { + return -1; + } + } while (data->fbz_stream.avail_out > 0); + + return len - data->fbz_stream.avail_out; } static unsigned char * @@ -148,11 +179,13 @@ static void bzip2_close(struct stream_encoded *stream) { struct bz2_enc_data *data = (struct bz2_enc_data *) stream->data; - int err; - BZ2_bzReadClose(&err, data->bzfile); - fclose(data->file); - mem_free(data); + if (data) { + BZ2_bzDecompressEnd(&data->fbz_stream); + close(data->fdread); + mem_free(data); + stream->data = 0; + } } static unsigned char *bzip2_extensions[] = { ".bz2", ".tbz", NULL }; diff --git a/src/protocol/http/http.c b/src/protocol/http/http.c index 87d468d..6f7469f 100644 --- a/src/protocol/http/http.c +++ b/src/protocol/http/http.c @@ -720,20 +720,13 @@ 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"); #endif add_crlf_to_string(&header); @@ -1810,13 +1803,11 @@ #ifdef CONFIG_GZIP && (!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); }