brotli code updated
[elinks.git] / src / encoding / brotli.c
blob65735dee313e2e7c6e8ffa5a940a7905b9db0e81
1 /* Brotli encoding (ENCODING_BROTLI) 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
13 #include <brotli/decode.h>
14 #include <errno.h>
16 #include "elinks.h"
18 #include "encoding/brotli.h"
19 #include "encoding/encoding.h"
20 #include "util/math.h"
21 #include "util/memory.h"
23 #define ELINKS_BROTLI_BUFFER_LENGTH 4096
25 struct br_enc_data {
26 BrotliDecoderState *state;
28 const uint8_t *next_in;
29 uint8_t *next_out;
31 size_t avail_in;
32 size_t avail_out;
33 size_t total_out;
35 /* The file descriptor from which we read. */
36 int fdread;
37 int after_end:1;
38 int last_read:1;
39 unsigned char buf[ELINKS_BROTLI_BUFFER_LENGTH];
42 static int
43 brotli_open(struct stream_encoded *stream, int fd)
45 struct br_enc_data *data = mem_calloc(1, sizeof(*data));
47 stream->data = NULL;
48 if (!data) {
49 return -1;
51 data->state = BrotliDecoderCreateInstance(NULL, NULL, NULL);
53 if (!data->state) {
54 mem_free(data);
55 return -1;
58 data->fdread = fd;
59 stream->data = data;
61 return 0;
64 static int
65 brotli_read(struct stream_encoded *stream, unsigned char *buf, int len)
67 struct br_enc_data *data = (struct br_enc_data *) stream->data;
68 int err = 0;
70 if (!data) return -1;
72 assert(len > 0);
74 if (data->last_read) return 0;
76 data->avail_out = len;
77 data->next_out = buf;
79 do {
80 if (data->avail_in == 0) {
81 int l = safe_read(data->fdread, data->buf,
82 ELINKS_BROTLI_BUFFER_LENGTH);
84 if (l == -1) {
85 if (errno == EAGAIN)
86 break;
87 else
88 return -1; /* I/O error */
89 } else if (l == 0) {
90 /* EOF. It is error: we wait for more bytes */
91 return -1;
94 data->next_in = data->buf;
95 data->avail_in = l;
98 err = BrotliDecoderDecompressStream(data->state, &data->avail_in, &data->next_in,
99 &data->avail_out, &data->next_out, &data->total_out);
101 if (err == BROTLI_DECODER_RESULT_SUCCESS) {
102 data->last_read = 1;
103 break;
104 } else if (err == BROTLI_DECODER_RESULT_ERROR) {
105 return -1;
107 } while (data->avail_out > 0);
109 assert(len - data->avail_out == data->next_out - buf);
110 return len - data->avail_out;
113 static unsigned char *
114 brotli_decode_buffer(struct stream_encoded *st, unsigned char *data, int len, int *new_len)
116 struct br_enc_data *enc_data = (struct br_enc_data *)st->data;
117 BrotliDecoderState *state = enc_data->state;
118 unsigned char *buffer = NULL;
119 int error;
121 *new_len = 0; /* default, left there if an error occurs */
123 if (!len) return NULL;
125 enc_data->next_in = data;
126 enc_data->avail_in = len;
127 enc_data->total_out = 0;
129 do {
130 unsigned char *new_buffer;
131 size_t size = enc_data->total_out + ELINKS_BROTLI_BUFFER_LENGTH;
133 new_buffer = mem_realloc(buffer, size);
135 if (!new_buffer) {
136 error = BROTLI_DECODER_RESULT_ERROR;
137 break;
140 buffer = new_buffer;
141 enc_data->next_out = buffer + enc_data->total_out;
142 enc_data->avail_out = ELINKS_BROTLI_BUFFER_LENGTH;
144 error = BrotliDecoderDecompressStream(state, &enc_data->avail_in, &enc_data->next_in,
145 &enc_data->avail_out, &enc_data->next_out, &enc_data->total_out);
147 if (error == BROTLI_DECODER_RESULT_SUCCESS) {
148 *new_len = enc_data->total_out;
149 enc_data->after_end = 1;
150 return buffer;
153 } while (error == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT);
155 mem_free_if(buffer);
156 return NULL;
159 static void
160 brotli_close(struct stream_encoded *stream)
162 struct br_enc_data *data = (struct br_enc_data *) stream->data;
164 if (data) {
165 if (data->state) BrotliDecoderDestroyInstance(data->state);
166 if (data->fdread != -1) {
167 close(data->fdread);
169 mem_free(data);
170 stream->data = 0;
174 static const unsigned char *const brotli_extensions[] = { ".br", NULL };
176 const struct decoding_backend brotli_decoding_backend = {
177 "brotli",
178 brotli_extensions,
179 brotli_open,
180 brotli_read,
181 brotli_decode_buffer,
182 brotli_close,