1008: Added upload_progress to the connection.
[elinks.git] / src / encoding / lzma.c
blob0cbbaf32d78f13a63d7053d6ad05a96d6b1d0cca
1 /* lzma encoding (ENCODING_LZMA) backend */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <stdio.h>
8 #include <string.h>
9 #include <sys/stat.h>
10 #ifdef HAVE_UNISTD_H
11 #include <unistd.h>
12 #endif
14 #include <lzma.h>
15 #include <errno.h>
17 #include "elinks.h"
19 #include "encoding/encoding.h"
20 #include "encoding/lzma.h"
21 #include "util/memory.h"
23 #define ELINKS_BZ_BUFFER_LENGTH 5000
25 struct lzma_enc_data {
26 lzma_stream flzma_stream;
27 int fdread;
28 int last_read;
29 unsigned char buf[ELINKS_BZ_BUFFER_LENGTH];
32 static int
33 lzma_open(struct stream_encoded *stream, int fd)
35 struct lzma_enc_data *data = mem_alloc(sizeof(*data));
36 int err;
38 stream->data = NULL;
39 if (!data) {
40 return -1;
43 copy_struct(&data->flzma_stream, &LZMA_STREAM_INIT_VAR);
44 data->fdread = fd;
45 data->last_read = 0;
47 err = lzma_auto_decoder(&data->flzma_stream, NULL, NULL);
48 if (err != LZMA_OK) {
49 mem_free(data);
50 return -1;
53 stream->data = data;
55 return 0;
58 static int
59 lzma_read(struct stream_encoded *stream, unsigned char *buf, int len)
61 struct lzma_enc_data *data = (struct lzma_enc_data *) stream->data;
62 int err = 0;
64 if (!data) return -1;
66 assert(len > 0);
68 if (data->last_read) return 0;
70 data->flzma_stream.avail_out = len;
71 data->flzma_stream.next_out = buf;
73 do {
74 if (data->flzma_stream.avail_in == 0) {
75 int l = safe_read(data->fdread, data->buf,
76 ELINKS_BZ_BUFFER_LENGTH);
78 if (l == -1) {
79 if (errno == EAGAIN)
80 break;
81 else
82 return -1; /* I/O error */
83 } else if (l == 0) {
84 /* EOF. It is error: we wait for more bytes */
85 return -1;
88 data->flzma_stream.next_in = data->buf;
89 data->flzma_stream.avail_in = l;
92 err = lzma_code(&data->flzma_stream, LZMA_RUN);
93 if (err == LZMA_STREAM_END) {
94 data->last_read = 1;
95 break;
96 } else if (err != LZMA_OK) {
97 return -1;
99 } while (data->flzma_stream.avail_out > 0);
101 assert(len - data->flzma_stream.avail_out == data->flzma_stream.next_out - buf);
102 return len - data->flzma_stream.avail_out;
105 static unsigned char *
106 lzma_decode_buffer(unsigned char *data, int len, int *new_len)
108 lzma_stream stream = LZMA_STREAM_INIT;
109 unsigned char *buffer = NULL;
110 int error;
112 *new_len = 0; /* default, left there if an error occurs */
114 stream.next_in = data;
115 stream.avail_in = len;
117 if (lzma_auto_decoder(&stream, NULL, NULL) != LZMA_OK)
118 return NULL;
120 do {
121 unsigned char *new_buffer;
122 size_t size = stream.total_out + MAX_STR_LEN;
124 new_buffer = mem_realloc(buffer, size);
125 if (!new_buffer) {
126 error = LZMA_MEM_ERROR;
127 break;
130 buffer = new_buffer;
131 stream.next_out = buffer + stream.total_out;
132 stream.avail_out = MAX_STR_LEN;
134 error = lzma_code(&stream, LZMA_RUN);
135 if (error == LZMA_STREAM_END) {
136 error = LZMA_OK;
137 break;
139 } while (error == LZMA_OK && stream.avail_in > 0);
141 lzma_end(&stream);
143 if (error == LZMA_OK) {
144 *new_len = stream.total_out;
145 return buffer;
146 } else {
147 if (buffer) mem_free(buffer);
148 return NULL;
152 static void
153 lzma_close(struct stream_encoded *stream)
155 struct lzma_enc_data *data = (struct lzma_enc_data *) stream->data;
157 if (data) {
158 lzma_end(&data->flzma_stream);
159 close(data->fdread);
160 mem_free(data);
161 stream->data = 0;
165 static const unsigned char *const lzma_extensions[] = { ".lzma", NULL };
167 const struct decoding_backend lzma_decoding_backend = {
168 "lzma",
169 lzma_extensions,
170 lzma_open,
171 lzma_read,
172 lzma_decode_buffer,
173 lzma_close,