1 /* mz_strm_lzma.c -- Stream for lzma inflate/deflate
2 Version 2.8.1, December 1, 2018
3 part of the MiniZip project
4
5 Copyright (C) 2010-2018 Nathan Moinvaziri
6 https://github.com/nmoinvaz/minizip
7
8 This program is distributed under the terms of the same license as lzma.
9 See the accompanying LICENSE file for the full text of the license.
10 */
11
12
13 #include "mz.h"
14 #include "mz_strm.h"
15 #include "mz_strm_lzma.h"
16
17 #include "lzma.h"
18
19 /***************************************************************************/
20
21 #define MZ_LZMA_HEADER_SIZE (4)
22
23 /***************************************************************************/
24
25 static mz_stream_vtbl mz_stream_lzma_vtbl = {
26 mz_stream_lzma_open,
27 mz_stream_lzma_is_open,
28 mz_stream_lzma_read,
29 mz_stream_lzma_write,
30 mz_stream_lzma_tell,
31 mz_stream_lzma_seek,
32 mz_stream_lzma_close,
33 mz_stream_lzma_error,
34 mz_stream_lzma_create,
35 mz_stream_lzma_delete,
36 mz_stream_lzma_get_prop_int64,
37 mz_stream_lzma_set_prop_int64
38 };
39
40 /***************************************************************************/
41
42 typedef struct mz_stream_lzma_s {
43 mz_stream stream;
44 lzma_stream lstream;
45 int32_t mode;
46 int32_t error;
47 uint8_t buffer[INT16_MAX];
48 int32_t buffer_len;
49 int64_t total_in;
50 int64_t total_out;
51 int64_t max_total_in;
52 int64_t max_total_out;
53 int8_t initialized;
54 uint32_t preset;
55 } mz_stream_lzma;
56
57 /***************************************************************************/
58
mz_stream_lzma_open(void * stream,const char * path,int32_t mode)59 int32_t mz_stream_lzma_open(void *stream, const char *path, int32_t mode)
60 {
61 mz_stream_lzma *lzma = (mz_stream_lzma *)stream;
62 lzma_filter filters[LZMA_FILTERS_MAX + 1];
63 lzma_options_lzma opt_lzma;
64 uint32_t size = 0;
65 uint8_t major = 0;
66 uint8_t minor = 0;
67
68 MZ_UNUSED(path);
69
70 memset(&opt_lzma, 0, sizeof(opt_lzma));
71
72 lzma->lstream.total_in = 0;
73 lzma->lstream.total_out = 0;
74
75 lzma->total_in = 0;
76 lzma->total_out = 0;
77
78 if (mode & MZ_OPEN_MODE_WRITE)
79 {
80 #ifdef MZ_ZIP_NO_COMPRESSION
81 MZ_UNUSED(filters);
82 MZ_UNUSED(major);
83 MZ_UNUSED(minor);
84 return MZ_SUPPORT_ERROR;
85 #else
86 lzma->lstream.next_out = lzma->buffer;
87 lzma->lstream.avail_out = sizeof(lzma->buffer);
88
89 if (lzma_lzma_preset(&opt_lzma, lzma->preset))
90 return MZ_OPEN_ERROR;
91
92 memset(&filters, 0, sizeof(filters));
93
94 filters[0].id = LZMA_FILTER_LZMA1;
95 filters[0].options = &opt_lzma;
96 filters[1].id = LZMA_VLI_UNKNOWN;
97
98 lzma_properties_size(&size, (lzma_filter *)&filters);
99
100 mz_stream_write_uint8(lzma->stream.base, LZMA_VERSION_MAJOR);
101 mz_stream_write_uint8(lzma->stream.base, LZMA_VERSION_MINOR);
102 mz_stream_write_uint16(lzma->stream.base, (uint16_t)size);
103
104 lzma->total_out += MZ_LZMA_HEADER_SIZE;
105
106 lzma->error = lzma_alone_encoder(&lzma->lstream, &opt_lzma);
107 #endif
108 }
109 else if (mode & MZ_OPEN_MODE_READ)
110 {
111 #ifdef MZ_ZIP_NO_DECOMPRESSION
112 MZ_UNUSED(filters);
113 MZ_UNUSED(major);
114 MZ_UNUSED(minor);
115 return MZ_SUPPORT_ERROR;
116 #else
117 lzma->lstream.next_in = lzma->buffer;
118 lzma->lstream.avail_in = 0;
119
120 mz_stream_read_uint8(lzma->stream.base, &major);
121 mz_stream_read_uint8(lzma->stream.base, &minor);
122 mz_stream_read_uint16(lzma->stream.base, (uint16_t *)&size);
123
124 lzma->total_in += MZ_LZMA_HEADER_SIZE;
125
126 lzma->error = lzma_alone_decoder(&lzma->lstream, UINT64_MAX);
127 #endif
128 }
129
130 if (lzma->error != LZMA_OK)
131 return MZ_OPEN_ERROR;
132
133 lzma->initialized = 1;
134 lzma->mode = mode;
135 return MZ_OK;
136 }
137
mz_stream_lzma_is_open(void * stream)138 int32_t mz_stream_lzma_is_open(void *stream)
139 {
140 mz_stream_lzma *lzma = (mz_stream_lzma *)stream;
141 if (lzma->initialized != 1)
142 return MZ_OPEN_ERROR;
143 return MZ_OK;
144 }
145
mz_stream_lzma_read(void * stream,void * buf,int32_t size)146 int32_t mz_stream_lzma_read(void *stream, void *buf, int32_t size)
147 {
148 #ifdef MZ_ZIP_NO_DECOMPRESSION
149 MZ_UNUSED(stream);
150 MZ_UNUSED(buf);
151 MZ_UNUSED(size);
152 return MZ_SUPPORT_ERROR;
153 #else
154 mz_stream_lzma *lzma = (mz_stream_lzma *)stream;
155 uint64_t total_in_before = 0;
156 uint64_t total_out_before = 0;
157 uint64_t total_in_after = 0;
158 uint64_t total_out_after = 0;
159 int32_t total_in = 0;
160 int32_t total_out = 0;
161 int32_t in_bytes = 0;
162 int32_t out_bytes = 0;
163 int32_t bytes_to_read = 0;
164 int32_t read = 0;
165 int32_t err = LZMA_OK;
166
167
168 lzma->lstream.next_out = (uint8_t*)buf;
169 lzma->lstream.avail_out = (size_t)size;
170
171 do
172 {
173 if (lzma->lstream.avail_in == 0)
174 {
175 bytes_to_read = sizeof(lzma->buffer);
176 if (lzma->max_total_in > 0)
177 {
178 if ((int64_t)bytes_to_read > (lzma->max_total_in - lzma->total_in))
179 bytes_to_read = (int32_t)(lzma->max_total_in - lzma->total_in);
180 }
181
182 read = mz_stream_read(lzma->stream.base, lzma->buffer, bytes_to_read);
183
184 if (read < 0)
185 return read;
186 if (read == 0)
187 break;
188
189 lzma->lstream.next_in = lzma->buffer;
190 lzma->lstream.avail_in = (size_t)read;
191 }
192
193 total_in_before = lzma->lstream.avail_in;
194 total_out_before = lzma->lstream.total_out;
195
196 err = lzma_code(&lzma->lstream, LZMA_RUN);
197
198 total_in_after = lzma->lstream.avail_in;
199 total_out_after = lzma->lstream.total_out;
200 if ((lzma->max_total_out != -1) && (int64_t)total_out_after > lzma->max_total_out)
201 total_out_after = (uint64_t)lzma->max_total_out;
202
203 in_bytes = (int32_t)(total_in_before - total_in_after);
204 out_bytes = (int32_t)(total_out_after - total_out_before);
205
206 total_in += in_bytes;
207 total_out += out_bytes;
208
209 lzma->total_in += in_bytes;
210 lzma->total_out += out_bytes;
211
212 if (err == LZMA_STREAM_END)
213 break;
214 if (err != LZMA_OK)
215 {
216 lzma->error = err;
217 break;
218 }
219 }
220 while (lzma->lstream.avail_out > 0);
221
222 if (lzma->error != 0)
223 return MZ_DATA_ERROR;
224
225 return total_out;
226 #endif
227 }
228
229 #ifndef MZ_ZIP_NO_COMPRESSION
mz_stream_lzma_flush(void * stream)230 static int32_t mz_stream_lzma_flush(void *stream)
231 {
232 mz_stream_lzma *lzma = (mz_stream_lzma *)stream;
233 if (mz_stream_write(lzma->stream.base, lzma->buffer, lzma->buffer_len) != lzma->buffer_len)
234 return MZ_WRITE_ERROR;
235 return MZ_OK;
236 }
237
mz_stream_lzma_code(void * stream,int32_t flush)238 static int32_t mz_stream_lzma_code(void *stream, int32_t flush)
239 {
240 mz_stream_lzma *lzma = (mz_stream_lzma *)stream;
241 uint64_t total_out_before = 0;
242 uint64_t total_out_after = 0;
243 uint32_t out_bytes = 0;
244 int32_t err = LZMA_OK;
245
246
247 do
248 {
249 if (lzma->lstream.avail_out == 0)
250 {
251 err = mz_stream_lzma_flush(lzma);
252 if (err != MZ_OK)
253 return err;
254
255 lzma->lstream.avail_out = sizeof(lzma->buffer);
256 lzma->lstream.next_out = lzma->buffer;
257
258 lzma->buffer_len = 0;
259 }
260
261 total_out_before = lzma->lstream.total_out;
262 err = lzma_code(&lzma->lstream, (lzma_action)flush);
263 total_out_after = lzma->lstream.total_out;
264
265 out_bytes = (uint32_t)(total_out_after - total_out_before);
266
267 if (err != LZMA_OK && err != LZMA_STREAM_END)
268 {
269 lzma->error = err;
270 return MZ_DATA_ERROR;
271 }
272
273 lzma->buffer_len += out_bytes;
274 lzma->total_out += out_bytes;
275 }
276 while ((lzma->lstream.avail_in > 0) || (flush == LZMA_FINISH && err == LZMA_OK));
277
278 return MZ_OK;
279 }
280 #endif
281
mz_stream_lzma_write(void * stream,const void * buf,int32_t size)282 int32_t mz_stream_lzma_write(void *stream, const void *buf, int32_t size)
283 {
284 mz_stream_lzma *lzma = (mz_stream_lzma *)stream;
285 int32_t err = size;
286
287 #ifdef MZ_ZIP_NO_COMPRESSION
288 MZ_UNUSED(lzma);
289 MZ_UNUSED(buf);
290 err = MZ_SUPPORT_ERROR;
291 #else
292 lzma->lstream.next_in = (uint8_t*)(intptr_t)buf;
293 lzma->lstream.avail_in = (size_t)size;
294
295 mz_stream_lzma_code(stream, LZMA_RUN);
296
297 lzma->total_in += size;
298 #endif
299 return err;
300 }
301
mz_stream_lzma_tell(void * stream)302 int64_t mz_stream_lzma_tell(void *stream)
303 {
304 MZ_UNUSED(stream);
305
306 return MZ_TELL_ERROR;
307 }
308
mz_stream_lzma_seek(void * stream,int64_t offset,int32_t origin)309 int32_t mz_stream_lzma_seek(void *stream, int64_t offset, int32_t origin)
310 {
311 MZ_UNUSED(stream);
312 MZ_UNUSED(offset);
313 MZ_UNUSED(origin);
314
315 return MZ_SEEK_ERROR;
316 }
317
mz_stream_lzma_close(void * stream)318 int32_t mz_stream_lzma_close(void *stream)
319 {
320 mz_stream_lzma *lzma = (mz_stream_lzma *)stream;
321
322 if (lzma->mode & MZ_OPEN_MODE_WRITE)
323 {
324 #ifdef MZ_ZIP_NO_COMPRESSION
325 return MZ_SUPPORT_ERROR;
326 #else
327 mz_stream_lzma_code(stream, LZMA_FINISH);
328 mz_stream_lzma_flush(stream);
329
330 lzma_end(&lzma->lstream);
331 #endif
332 }
333 else if (lzma->mode & MZ_OPEN_MODE_READ)
334 {
335 #ifdef MZ_ZIP_NO_DECOMPRESSION
336 return MZ_SUPPORT_ERROR;
337 #else
338 lzma_end(&lzma->lstream);
339 #endif
340 }
341
342 lzma->initialized = 0;
343
344 if (lzma->error != LZMA_OK)
345 return MZ_CLOSE_ERROR;
346 return MZ_OK;
347 }
348
mz_stream_lzma_error(void * stream)349 int32_t mz_stream_lzma_error(void *stream)
350 {
351 mz_stream_lzma *lzma = (mz_stream_lzma *)stream;
352 return lzma->error;
353 }
354
mz_stream_lzma_get_prop_int64(void * stream,int32_t prop,int64_t * value)355 int32_t mz_stream_lzma_get_prop_int64(void *stream, int32_t prop, int64_t *value)
356 {
357 mz_stream_lzma *lzma = (mz_stream_lzma *)stream;
358 switch (prop)
359 {
360 case MZ_STREAM_PROP_TOTAL_IN:
361 *value = lzma->total_in;
362 break;
363 case MZ_STREAM_PROP_TOTAL_IN_MAX:
364 *value = lzma->max_total_in;
365 break;
366 case MZ_STREAM_PROP_TOTAL_OUT:
367 *value = lzma->total_out;
368 break;
369 case MZ_STREAM_PROP_TOTAL_OUT_MAX:
370 *value = lzma->max_total_out;
371 break;
372 case MZ_STREAM_PROP_HEADER_SIZE:
373 *value = MZ_LZMA_HEADER_SIZE;
374 break;
375 default:
376 return MZ_EXIST_ERROR;
377 }
378 return MZ_OK;
379 }
380
mz_stream_lzma_set_prop_int64(void * stream,int32_t prop,int64_t value)381 int32_t mz_stream_lzma_set_prop_int64(void *stream, int32_t prop, int64_t value)
382 {
383 mz_stream_lzma *lzma = (mz_stream_lzma *)stream;
384 switch (prop)
385 {
386 case MZ_STREAM_PROP_COMPRESS_LEVEL:
387 if (value >= 9)
388 lzma->preset = LZMA_PRESET_EXTREME;
389 else
390 lzma->preset = LZMA_PRESET_DEFAULT;
391 break;
392 case MZ_STREAM_PROP_TOTAL_IN_MAX:
393 lzma->max_total_in = value;
394 break;
395 case MZ_STREAM_PROP_TOTAL_OUT_MAX:
396 if (value < -1)
397 return MZ_PARAM_ERROR;
398 lzma->max_total_out = value;
399 break;
400 default:
401 return MZ_EXIST_ERROR;
402 }
403 return MZ_OK;
404 }
405
mz_stream_lzma_create(void ** stream)406 void *mz_stream_lzma_create(void **stream)
407 {
408 mz_stream_lzma *lzma = NULL;
409
410 lzma = (mz_stream_lzma *)MZ_ALLOC(sizeof(mz_stream_lzma));
411 if (lzma != NULL)
412 {
413 memset(lzma, 0, sizeof(mz_stream_lzma));
414 lzma->stream.vtbl = &mz_stream_lzma_vtbl;
415 lzma->preset = LZMA_PRESET_DEFAULT;
416 lzma->max_total_out = -1;
417 }
418 if (stream != NULL)
419 *stream = lzma;
420
421 return lzma;
422 }
423
mz_stream_lzma_delete(void ** stream)424 void mz_stream_lzma_delete(void **stream)
425 {
426 mz_stream_lzma *lzma = NULL;
427 if (stream == NULL)
428 return;
429 lzma = (mz_stream_lzma *)*stream;
430 if (lzma != NULL)
431 MZ_FREE(lzma);
432 *stream = NULL;
433 }
434
mz_stream_lzma_get_interface(void)435 void *mz_stream_lzma_get_interface(void)
436 {
437 return (void *)&mz_stream_lzma_vtbl;
438 }
439