From 3e436b886913f02117a8776638dfefe2726a75ab Mon Sep 17 00:00:00 2001 From: Witold Filipczyk Date: Sat, 1 Jul 2017 22:38:06 +0200 Subject: [PATCH] brotli code updated --- configure.in | 2 +- src/encoding/brotli.c | 386 ++++++++++++++++++++++++-------------------------- 2 files changed, 184 insertions(+), 204 deletions(-) rewrite src/encoding/brotli.c (65%) diff --git a/configure.in b/configure.in index c5f73513..3e189c92 100644 --- a/configure.in +++ b/configure.in @@ -486,7 +486,7 @@ EL_CONFIG_OPTIONAL_LIBRARY(CONFIG_GZIP, zlib, zlib.h, z, gzclearerr, EL_CONFIG_OPTIONAL_LIBRARY(CONFIG_BZIP2, bzlib, bzlib.h, bz2, BZ2_bzReadOpen, [ --without-bzlib disable bzlib support]) -EL_CONFIG_OPTIONAL_LIBRARY(CONFIG_BROTLI, brotli, brotli/dec/decode.h, brotlidec, BrotliStateInit, +EL_CONFIG_OPTIONAL_LIBRARY(CONFIG_BROTLI, brotli, brotli/decode.h, brotlidec, BrotliDecoderDecompressStream, [ --with-brotli enable experimental brotli support]) EL_CONFIG_OPTIONAL_LIBRARY(CONFIG_IDN, idn, idna.h, idn, stringprep_check_version, diff --git a/src/encoding/brotli.c b/src/encoding/brotli.c dissimilarity index 65% index 9dc1fe69..65735dee 100644 --- a/src/encoding/brotli.c +++ b/src/encoding/brotli.c @@ -1,203 +1,183 @@ -/* Brotli encoding (ENCODING_BROTLI) backend */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifdef HAVE_BROTLI_DEC_DECODE_H -#include -#endif - -#include - -#include "elinks.h" - -#include "encoding/brotli.h" -#include "encoding/encoding.h" -#include "util/math.h" -#include "util/memory.h" - -struct br_enc_data { - BrotliState br_stream; - - uint8_t *input; - uint8_t *output; - - size_t input_length; - size_t output_length; - size_t output_pos; - size_t input_pos; - - /* The file descriptor from which we read. */ - int fdread; - int after_end:1; - int need_free:1; -}; - -static int -brotli_open(struct stream_encoded *stream, int fd) -{ - struct br_enc_data *data = mem_calloc(1, sizeof(*data)); - - stream->data = NULL; - if (!data) { - return -1; - } - - data->fdread = fd; - BrotliStateInit(&data->br_stream); - stream->data = data; - - return 0; -} - -static int -brotli_read_function_fd(void *data, uint8_t *buf, size_t len) -{ - struct br_enc_data *enc_data = (struct br_enc_data *)data; - - return safe_read(enc_data->fdread, buf, len); -} - -static int -brotli_read_function(void *data, uint8_t *buf, size_t len) -{ - struct br_enc_data *enc_data = (struct br_enc_data *)data; - size_t l = MIN(len, enc_data->input_length - enc_data->input_pos); - - memcpy(buf, enc_data->input + enc_data->input_pos, l); - enc_data->input_pos += l; - return l; -} - -static int -brotli_write_function(void *data, const uint8_t *buf, size_t len) -{ - struct br_enc_data *enc_data = (struct br_enc_data *)data; - - enc_data->output = mem_alloc(len); - if (!enc_data->output) { - return -1; - } - memcpy(enc_data->output, buf, len); - enc_data->output_length = len; - return len; -} - -static int -brotli_read(struct stream_encoded *stream, unsigned char *buf, int len) -{ - struct br_enc_data *enc_data = (struct br_enc_data *) stream->data; - BrotliState *s; - BrotliInput inp; - BrotliOutput outp; - size_t l; - int error; - - if (!enc_data) return -1; - s = &enc_data->br_stream; - - assert(len > 0); - - if (enc_data->after_end) { - l = MIN(len, enc_data->output_length - enc_data->output_pos); - memcpy(buf, enc_data->output + enc_data->output_pos, l); - enc_data->output_pos += l; - return l; - } - - enc_data->input = NULL; - enc_data->input_length = 0; - enc_data->output = NULL; - enc_data->output_length = 0; - enc_data->output_pos = 0; - inp.data_ = enc_data; - outp.data_ = enc_data; - inp.cb_ = brotli_read_function_fd; - outp.cb_ = brotli_write_function; - - error = BrotliDecompressStreaming(inp, outp, 1, s); - switch (error) { - case BROTLI_RESULT_ERROR: - return -1; - case BROTLI_RESULT_SUCCESS: - enc_data->after_end = 1; - case BROTLI_RESULT_NEEDS_MORE_INPUT: - default: - enc_data->need_free = 1; - l = MIN(len, enc_data->output_length - enc_data->output_pos); - memcpy(buf, enc_data->output + enc_data->output_pos, l); - enc_data->output_pos += l; - return l; - } -} - -static unsigned char * -brotli_decode_buffer(struct stream_encoded *st, unsigned char *data, int len, int *new_len) -{ - struct br_enc_data *enc_data = (struct br_enc_data *)st->data; - BrotliInput inp; - BrotliOutput outp; - BrotliState *stream = &enc_data->br_stream; - int error; - int finish = (len == 0); - - *new_len = 0; /* default, left there if an error occurs */ - enc_data->input = data; - enc_data->input_length = len; - enc_data->input_pos = 0; - enc_data->output = NULL; - enc_data->output_length = 0; - enc_data->output_pos = 0; - inp.data_ = enc_data; - outp.data_ = enc_data; - inp.cb_ = brotli_read_function; - outp.cb_ = brotli_write_function; - error = BrotliDecompressStreaming(inp, outp, finish, stream); - - switch (error) { - case BROTLI_RESULT_ERROR: - return NULL; - case BROTLI_RESULT_SUCCESS: - enc_data->after_end = 1; - case BROTLI_RESULT_NEEDS_MORE_INPUT: - default: - *new_len = enc_data->output_length; - return enc_data->output; - } -} - -static void -brotli_close(struct stream_encoded *stream) -{ - struct br_enc_data *data = (struct br_enc_data *) stream->data; - - if (data) { - BrotliStateCleanup(&data->br_stream); - if (data->fdread != -1) { - close(data->fdread); - } - if (data->need_free) { - mem_free_if(data->output); - } - mem_free(data); - stream->data = 0; - } -} - -static const unsigned char *const brotli_extensions[] = { ".br", NULL }; - -const struct decoding_backend brotli_decoding_backend = { - "brotli", - brotli_extensions, - brotli_open, - brotli_read, - brotli_decode_buffer, - brotli_close, -}; +/* Brotli encoding (ENCODING_BROTLI) backend */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#include +#include + +#include "elinks.h" + +#include "encoding/brotli.h" +#include "encoding/encoding.h" +#include "util/math.h" +#include "util/memory.h" + +#define ELINKS_BROTLI_BUFFER_LENGTH 4096 + +struct br_enc_data { + BrotliDecoderState *state; + + const uint8_t *next_in; + uint8_t *next_out; + + size_t avail_in; + size_t avail_out; + size_t total_out; + + /* The file descriptor from which we read. */ + int fdread; + int after_end:1; + int last_read:1; + unsigned char buf[ELINKS_BROTLI_BUFFER_LENGTH]; +}; + +static int +brotli_open(struct stream_encoded *stream, int fd) +{ + struct br_enc_data *data = mem_calloc(1, sizeof(*data)); + + stream->data = NULL; + if (!data) { + return -1; + } + data->state = BrotliDecoderCreateInstance(NULL, NULL, NULL); + + if (!data->state) { + mem_free(data); + return -1; + } + + data->fdread = fd; + stream->data = data; + + return 0; +} + +static int +brotli_read(struct stream_encoded *stream, unsigned char *buf, int len) +{ + struct br_enc_data *data = (struct br_enc_data *) stream->data; + int err = 0; + + if (!data) return -1; + + assert(len > 0); + + if (data->last_read) return 0; + + data->avail_out = len; + data->next_out = buf; + + do { + if (data->avail_in == 0) { + int l = safe_read(data->fdread, data->buf, + ELINKS_BROTLI_BUFFER_LENGTH); + + 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->next_in = data->buf; + data->avail_in = l; + } + + err = BrotliDecoderDecompressStream(data->state, &data->avail_in, &data->next_in, + &data->avail_out, &data->next_out, &data->total_out); + + if (err == BROTLI_DECODER_RESULT_SUCCESS) { + data->last_read = 1; + break; + } else if (err == BROTLI_DECODER_RESULT_ERROR) { + return -1; + } + } while (data->avail_out > 0); + + assert(len - data->avail_out == data->next_out - buf); + return len - data->avail_out; +} + +static unsigned char * +brotli_decode_buffer(struct stream_encoded *st, unsigned char *data, int len, int *new_len) +{ + struct br_enc_data *enc_data = (struct br_enc_data *)st->data; + BrotliDecoderState *state = enc_data->state; + unsigned char *buffer = NULL; + int error; + + *new_len = 0; /* default, left there if an error occurs */ + + if (!len) return NULL; + + enc_data->next_in = data; + enc_data->avail_in = len; + enc_data->total_out = 0; + + do { + unsigned char *new_buffer; + size_t size = enc_data->total_out + ELINKS_BROTLI_BUFFER_LENGTH; + + new_buffer = mem_realloc(buffer, size); + + if (!new_buffer) { + error = BROTLI_DECODER_RESULT_ERROR; + break; + } + + buffer = new_buffer; + enc_data->next_out = buffer + enc_data->total_out; + enc_data->avail_out = ELINKS_BROTLI_BUFFER_LENGTH; + + error = BrotliDecoderDecompressStream(state, &enc_data->avail_in, &enc_data->next_in, + &enc_data->avail_out, &enc_data->next_out, &enc_data->total_out); + + if (error == BROTLI_DECODER_RESULT_SUCCESS) { + *new_len = enc_data->total_out; + enc_data->after_end = 1; + return buffer; + } + + } while (error == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT); + + mem_free_if(buffer); + return NULL; +} + +static void +brotli_close(struct stream_encoded *stream) +{ + struct br_enc_data *data = (struct br_enc_data *) stream->data; + + if (data) { + if (data->state) BrotliDecoderDestroyInstance(data->state); + if (data->fdread != -1) { + close(data->fdread); + } + mem_free(data); + stream->data = 0; + } +} + +static const unsigned char *const brotli_extensions[] = { ".br", NULL }; + +const struct decoding_backend brotli_decoding_backend = { + "brotli", + brotli_extensions, + brotli_open, + brotli_read, + brotli_decode_buffer, + brotli_close, +}; -- 2.11.4.GIT