Handle mailcap's copiousoutput without an external pager.
[elinks.git] / src / encoding / lzma.c
blob3e6abf15ac5c346bd904137b855899cc34f36895
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 #define ELINKS_LZMA_MEMORY_LIMIT (1024 * 1024 * 128)
27 struct lzma_enc_data {
28 lzma_stream flzma_stream;
29 int fdread;
30 int last_read;
31 unsigned char buf[ELINKS_BZ_BUFFER_LENGTH];
34 static int
35 lzma_open(struct stream_encoded *stream, int fd)
37 struct lzma_enc_data *data = mem_alloc(sizeof(*data));
38 int err;
40 stream->data = NULL;
41 if (!data) {
42 return -1;
45 memset(&data->flzma_stream, 0, sizeof(data->flzma_stream));
46 data->fdread = fd;
47 data->last_read = 0;
49 err = lzma_auto_decoder(&data->flzma_stream, ELINKS_LZMA_MEMORY_LIMIT, 0);
50 if (err != LZMA_OK) {
51 mem_free(data);
52 return -1;
55 stream->data = data;
57 return 0;
60 static int
61 lzma_read(struct stream_encoded *stream, unsigned char *buf, int len)
63 struct lzma_enc_data *data = (struct lzma_enc_data *) stream->data;
64 int err = 0;
66 if (!data) return -1;
68 assert(len > 0);
70 if (data->last_read) return 0;
72 data->flzma_stream.avail_out = len;
73 data->flzma_stream.next_out = buf;
75 do {
76 if (data->flzma_stream.avail_in == 0) {
77 int l = safe_read(data->fdread, data->buf,
78 ELINKS_BZ_BUFFER_LENGTH);
80 if (l == -1) {
81 if (errno == EAGAIN)
82 break;
83 else
84 return -1; /* I/O error */
85 } else if (l == 0) {
86 /* EOF. It is error: we wait for more bytes */
87 return -1;
90 data->flzma_stream.next_in = data->buf;
91 data->flzma_stream.avail_in = l;
94 err = lzma_code(&data->flzma_stream, LZMA_RUN);
95 if (err == LZMA_STREAM_END) {
96 data->last_read = 1;
97 break;
98 } else if (err != LZMA_OK) {
99 return -1;
101 } while (data->flzma_stream.avail_out > 0);
103 assert(len - data->flzma_stream.avail_out == data->flzma_stream.next_out - buf);
104 return len - data->flzma_stream.avail_out;
107 static unsigned char *
108 lzma_decode_buffer(unsigned char *data, int len, int *new_len)
110 lzma_stream stream = LZMA_STREAM_INIT;
111 unsigned char *buffer = NULL;
112 int error;
114 *new_len = 0; /* default, left there if an error occurs */
116 stream.next_in = data;
117 stream.avail_in = len;
119 if (lzma_auto_decoder(&stream, ELINKS_LZMA_MEMORY_LIMIT, 0) != LZMA_OK)
120 return NULL;
122 do {
123 unsigned char *new_buffer;
124 size_t size = stream.total_out + MAX_STR_LEN;
126 new_buffer = mem_realloc(buffer, size);
127 if (!new_buffer) {
128 error = LZMA_MEM_ERROR;
129 break;
132 buffer = new_buffer;
133 stream.next_out = buffer + stream.total_out;
134 stream.avail_out = MAX_STR_LEN;
136 error = lzma_code(&stream, LZMA_RUN);
137 if (error == LZMA_STREAM_END) {
138 error = LZMA_OK;
139 break;
141 } while (error == LZMA_OK && stream.avail_in > 0);
143 lzma_end(&stream);
145 if (error == LZMA_OK) {
146 *new_len = stream.total_out;
147 return buffer;
148 } else {
149 if (buffer) mem_free(buffer);
150 return NULL;
154 static void
155 lzma_close(struct stream_encoded *stream)
157 struct lzma_enc_data *data = (struct lzma_enc_data *) stream->data;
159 if (data) {
160 lzma_end(&data->flzma_stream);
161 close(data->fdread);
162 mem_free(data);
163 stream->data = 0;
167 static const unsigned char *const lzma_extensions[] = { ".lzma", ".xz", NULL };
169 const struct decoding_backend lzma_decoding_backend = {
170 "lzma",
171 lzma_extensions,
172 lzma_open,
173 lzma_read,
174 lzma_decode_buffer,
175 lzma_close,