]> git.saurik.com Git - wxWidgets.git/blob - src/tiff/libtiff/tif_lzma.c
wxMessageBox off the main thread lost result code.
[wxWidgets.git] / src / tiff / libtiff / tif_lzma.c
1
2 /*
3 * Copyright (c) 2010, Andrey Kiselev <dron@ak4719.spb.edu>
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that (i) the above copyright notices and this permission notice appear in
8 * all copies of the software and related documentation, and (ii) the names of
9 * Sam Leffler and Silicon Graphics may not be used in any advertising or
10 * publicity relating to the software without the specific, prior written
11 * permission of Sam Leffler and Silicon Graphics.
12 *
13 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
14 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
15 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
16 *
17 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
18 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
19 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
21 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22 * OF THIS SOFTWARE.
23 */
24
25 #include "tiffiop.h"
26 #ifdef LZMA_SUPPORT
27 /*
28 * TIFF Library.
29 *
30 * LZMA2 Compression Support
31 *
32 * You need an LZMA2 SDK to link with. See http://tukaani.org/xz/ for details.
33 *
34 * The codec is derived from ZLIB codec (tif_zip.c).
35 */
36
37 #include "tif_predict.h"
38 #include "lzma.h"
39
40 #include <stdio.h>
41
42 /*
43 * State block for each open TIFF file using LZMA2 compression/decompression.
44 */
45 typedef struct {
46 TIFFPredictorState predict;
47 lzma_stream stream;
48 lzma_filter filters[LZMA_FILTERS_MAX + 1];
49 lzma_options_delta opt_delta; /* delta filter options */
50 lzma_options_lzma opt_lzma; /* LZMA2 filter options */
51 int preset; /* compression level */
52 lzma_check check; /* type of the integrity check */
53 int state; /* state flags */
54 #define LSTATE_INIT_DECODE 0x01
55 #define LSTATE_INIT_ENCODE 0x02
56
57 TIFFVGetMethod vgetparent; /* super-class method */
58 TIFFVSetMethod vsetparent; /* super-class method */
59 } LZMAState;
60
61 #define LState(tif) ((LZMAState*) (tif)->tif_data)
62 #define DecoderState(tif) LState(tif)
63 #define EncoderState(tif) LState(tif)
64
65 static int LZMAEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s);
66 static int LZMADecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s);
67
68 static const char *
69 LZMAStrerror(lzma_ret ret)
70 {
71 switch (ret) {
72 case LZMA_OK:
73 return "operation completed successfully";
74 case LZMA_STREAM_END:
75 return "end of stream was reached";
76 case LZMA_NO_CHECK:
77 return "input stream has no integrity check";
78 case LZMA_UNSUPPORTED_CHECK:
79 return "cannot calculate the integrity check";
80 case LZMA_GET_CHECK:
81 return "integrity check type is now available";
82 case LZMA_MEM_ERROR:
83 return "cannot allocate memory";
84 case LZMA_MEMLIMIT_ERROR:
85 return "memory usage limit was reached";
86 case LZMA_FORMAT_ERROR:
87 return "file format not recognized";
88 case LZMA_OPTIONS_ERROR:
89 return "invalid or unsupported options";
90 case LZMA_DATA_ERROR:
91 return "data is corrupt";
92 case LZMA_BUF_ERROR:
93 return "no progress is possible (stream is truncated or corrupt)";
94 case LZMA_PROG_ERROR:
95 return "programming error";
96 default:
97 return "unindentified liblzma error";
98 }
99 }
100
101 static int
102 LZMAFixupTags(TIFF* tif)
103 {
104 (void) tif;
105 return 1;
106 }
107
108 static int
109 LZMASetupDecode(TIFF* tif)
110 {
111 LZMAState* sp = DecoderState(tif);
112
113 assert(sp != NULL);
114
115 /* if we were last encoding, terminate this mode */
116 if (sp->state & LSTATE_INIT_ENCODE) {
117 lzma_end(&sp->stream);
118 sp->state = 0;
119 }
120
121 sp->state |= LSTATE_INIT_DECODE;
122 return 1;
123 }
124
125 /*
126 * Setup state for decoding a strip.
127 */
128 static int
129 LZMAPreDecode(TIFF* tif, uint16 s)
130 {
131 static const char module[] = "LZMAPreDecode";
132 LZMAState* sp = DecoderState(tif);
133 lzma_ret ret;
134
135 (void) s;
136 assert(sp != NULL);
137
138 if( (sp->state & LSTATE_INIT_DECODE) == 0 )
139 tif->tif_setupdecode(tif);
140
141 sp->stream.next_in = tif->tif_rawdata;
142 sp->stream.avail_in = (size_t) tif->tif_rawcc;
143 if ((tmsize_t)sp->stream.avail_in != tif->tif_rawcc) {
144 TIFFErrorExt(tif->tif_clientdata, module,
145 "Liblzma cannot deal with buffers this size");
146 return 0;
147 }
148
149 /*
150 * Disable memory limit when decoding. UINT64_MAX is a flag to disable
151 * the limit, we are passing (uint64_t)-1 which should be the same.
152 */
153 ret = lzma_stream_decoder(&sp->stream, (uint64_t)-1, 0);
154 if (ret != LZMA_OK) {
155 TIFFErrorExt(tif->tif_clientdata, module,
156 "Error initializing the stream decoder, %s",
157 LZMAStrerror(ret));
158 return 0;
159 }
160 return 1;
161 }
162
163 static int
164 LZMADecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
165 {
166 static const char module[] = "LZMADecode";
167 LZMAState* sp = DecoderState(tif);
168
169 (void) s;
170 assert(sp != NULL);
171 assert(sp->state == LSTATE_INIT_DECODE);
172
173 sp->stream.next_in = tif->tif_rawcp;
174 sp->stream.avail_in = (size_t) tif->tif_rawcc;
175
176 sp->stream.next_out = op;
177 sp->stream.avail_out = (size_t) occ;
178 if ((tmsize_t)sp->stream.avail_out != occ) {
179 TIFFErrorExt(tif->tif_clientdata, module,
180 "Liblzma cannot deal with buffers this size");
181 return 0;
182 }
183
184 do {
185 /*
186 * Save the current stream state to properly recover from the
187 * decoding errors later.
188 */
189 const uint8_t *next_in = sp->stream.next_in;
190 size_t avail_in = sp->stream.avail_in;
191
192 lzma_ret ret = lzma_code(&sp->stream, LZMA_RUN);
193 if (ret == LZMA_STREAM_END)
194 break;
195 if (ret == LZMA_MEMLIMIT_ERROR) {
196 lzma_ret r = lzma_stream_decoder(&sp->stream,
197 lzma_memusage(&sp->stream), 0);
198 if (r != LZMA_OK) {
199 TIFFErrorExt(tif->tif_clientdata, module,
200 "Error initializing the stream decoder, %s",
201 LZMAStrerror(r));
202 break;
203 }
204 sp->stream.next_in = next_in;
205 sp->stream.avail_in = avail_in;
206 continue;
207 }
208 if (ret != LZMA_OK) {
209 TIFFErrorExt(tif->tif_clientdata, module,
210 "Decoding error at scanline %lu, %s",
211 (unsigned long) tif->tif_row, LZMAStrerror(ret));
212 break;
213 }
214 } while (sp->stream.avail_out > 0);
215 if (sp->stream.avail_out != 0) {
216 TIFFErrorExt(tif->tif_clientdata, module,
217 "Not enough data at scanline %lu (short %lu bytes)",
218 (unsigned long) tif->tif_row, (unsigned long) sp->stream.avail_out);
219 return 0;
220 }
221
222 tif->tif_rawcp = (uint8 *)sp->stream.next_in; /* cast away const */
223 tif->tif_rawcc = sp->stream.avail_in;
224
225 return 1;
226 }
227
228 static int
229 LZMASetupEncode(TIFF* tif)
230 {
231 LZMAState* sp = EncoderState(tif);
232
233 assert(sp != NULL);
234 if (sp->state & LSTATE_INIT_DECODE) {
235 lzma_end(&sp->stream);
236 sp->state = 0;
237 }
238
239 sp->state |= LSTATE_INIT_ENCODE;
240 return 1;
241 }
242
243 /*
244 * Reset encoding state at the start of a strip.
245 */
246 static int
247 LZMAPreEncode(TIFF* tif, uint16 s)
248 {
249 static const char module[] = "LZMAPreEncode";
250 LZMAState *sp = EncoderState(tif);
251
252 (void) s;
253 assert(sp != NULL);
254 if( sp->state != LSTATE_INIT_ENCODE )
255 tif->tif_setupencode(tif);
256
257 sp->stream.next_out = tif->tif_rawdata;
258 sp->stream.avail_out = (size_t)tif->tif_rawdatasize;
259 if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize) {
260 TIFFErrorExt(tif->tif_clientdata, module,
261 "Liblzma cannot deal with buffers this size");
262 return 0;
263 }
264 return (lzma_stream_encoder(&sp->stream, sp->filters, sp->check) == LZMA_OK);
265 }
266
267 /*
268 * Encode a chunk of pixels.
269 */
270 static int
271 LZMAEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
272 {
273 static const char module[] = "LZMAEncode";
274 LZMAState *sp = EncoderState(tif);
275
276 assert(sp != NULL);
277 assert(sp->state == LSTATE_INIT_ENCODE);
278
279 (void) s;
280 sp->stream.next_in = bp;
281 sp->stream.avail_in = (size_t) cc;
282 if ((tmsize_t)sp->stream.avail_in != cc) {
283 TIFFErrorExt(tif->tif_clientdata, module,
284 "Liblzma cannot deal with buffers this size");
285 return 0;
286 }
287 do {
288 lzma_ret ret = lzma_code(&sp->stream, LZMA_RUN);
289 if (ret != LZMA_OK) {
290 TIFFErrorExt(tif->tif_clientdata, module,
291 "Encoding error at scanline %lu, %s",
292 (unsigned long) tif->tif_row, LZMAStrerror(ret));
293 return 0;
294 }
295 if (sp->stream.avail_out == 0) {
296 tif->tif_rawcc = tif->tif_rawdatasize;
297 TIFFFlushData1(tif);
298 sp->stream.next_out = tif->tif_rawdata;
299 sp->stream.avail_out = (size_t)tif->tif_rawdatasize; /* this is a safe typecast, as check is made already in LZMAPreEncode */
300 }
301 } while (sp->stream.avail_in > 0);
302 return 1;
303 }
304
305 /*
306 * Finish off an encoded strip by flushing the last
307 * string and tacking on an End Of Information code.
308 */
309 static int
310 LZMAPostEncode(TIFF* tif)
311 {
312 static const char module[] = "LZMAPostEncode";
313 LZMAState *sp = EncoderState(tif);
314 lzma_ret ret;
315
316 sp->stream.avail_in = 0;
317 do {
318 ret = lzma_code(&sp->stream, LZMA_FINISH);
319 switch (ret) {
320 case LZMA_STREAM_END:
321 case LZMA_OK:
322 if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize) {
323 tif->tif_rawcc =
324 tif->tif_rawdatasize - sp->stream.avail_out;
325 TIFFFlushData1(tif);
326 sp->stream.next_out = tif->tif_rawdata;
327 sp->stream.avail_out = (size_t)tif->tif_rawdatasize; /* this is a safe typecast, as check is made already in ZIPPreEncode */
328 }
329 break;
330 default:
331 TIFFErrorExt(tif->tif_clientdata, module, "Liblzma error: %s",
332 LZMAStrerror(ret));
333 return 0;
334 }
335 } while (ret != LZMA_STREAM_END);
336 return 1;
337 }
338
339 static void
340 LZMACleanup(TIFF* tif)
341 {
342 LZMAState* sp = LState(tif);
343
344 assert(sp != 0);
345
346 (void)TIFFPredictorCleanup(tif);
347
348 tif->tif_tagmethods.vgetfield = sp->vgetparent;
349 tif->tif_tagmethods.vsetfield = sp->vsetparent;
350
351 if (sp->state) {
352 lzma_end(&sp->stream);
353 sp->state = 0;
354 }
355 _TIFFfree(sp);
356 tif->tif_data = NULL;
357
358 _TIFFSetDefaultCompressionState(tif);
359 }
360
361 static int
362 LZMAVSetField(TIFF* tif, uint32 tag, va_list ap)
363 {
364 static const char module[] = "LZMAVSetField";
365 LZMAState* sp = LState(tif);
366
367 switch (tag) {
368 case TIFFTAG_LZMAPRESET:
369 sp->preset = (int) va_arg(ap, int);
370 lzma_lzma_preset(&sp->opt_lzma, sp->preset);
371 if (sp->state & LSTATE_INIT_ENCODE) {
372 lzma_ret ret = lzma_stream_encoder(&sp->stream,
373 sp->filters,
374 sp->check);
375 if (ret != LZMA_OK) {
376 TIFFErrorExt(tif->tif_clientdata, module,
377 "Liblzma error: %s",
378 LZMAStrerror(ret));
379 }
380 }
381 return 1;
382 default:
383 return (*sp->vsetparent)(tif, tag, ap);
384 }
385 /*NOTREACHED*/
386 }
387
388 static int
389 LZMAVGetField(TIFF* tif, uint32 tag, va_list ap)
390 {
391 LZMAState* sp = LState(tif);
392
393 switch (tag) {
394 case TIFFTAG_LZMAPRESET:
395 *va_arg(ap, int*) = sp->preset;
396 break;
397 default:
398 return (*sp->vgetparent)(tif, tag, ap);
399 }
400 return 1;
401 }
402
403 static const TIFFField lzmaFields[] = {
404 { TIFFTAG_LZMAPRESET, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED,
405 FIELD_PSEUDO, TRUE, FALSE, "LZMA2 Compression Preset", NULL },
406 };
407
408 int
409 TIFFInitLZMA(TIFF* tif, int scheme)
410 {
411 static const char module[] = "TIFFInitLZMA";
412 LZMAState* sp;
413 lzma_stream tmp_stream = LZMA_STREAM_INIT;
414
415 assert( scheme == COMPRESSION_LZMA );
416
417 /*
418 * Merge codec-specific tag information.
419 */
420 if (!_TIFFMergeFields(tif, lzmaFields, TIFFArrayCount(lzmaFields))) {
421 TIFFErrorExt(tif->tif_clientdata, module,
422 "Merging LZMA2 codec-specific tags failed");
423 return 0;
424 }
425
426 /*
427 * Allocate state block so tag methods have storage to record values.
428 */
429 tif->tif_data = (uint8*) _TIFFmalloc(sizeof(LZMAState));
430 if (tif->tif_data == NULL)
431 goto bad;
432 sp = LState(tif);
433 memcpy(&sp->stream, &tmp_stream, sizeof(lzma_stream));
434
435 /*
436 * Override parent get/set field methods.
437 */
438 sp->vgetparent = tif->tif_tagmethods.vgetfield;
439 tif->tif_tagmethods.vgetfield = LZMAVGetField; /* hook for codec tags */
440 sp->vsetparent = tif->tif_tagmethods.vsetfield;
441 tif->tif_tagmethods.vsetfield = LZMAVSetField; /* hook for codec tags */
442
443 /* Default values for codec-specific fields */
444 sp->preset = LZMA_PRESET_DEFAULT; /* default comp. level */
445 sp->check = LZMA_CHECK_NONE;
446 sp->state = 0;
447
448 /* Data filters. So far we are using delta and LZMA2 filters only. */
449 sp->opt_delta.type = LZMA_DELTA_TYPE_BYTE;
450 /*
451 * The sample size in bytes seems to be reasonable distance for delta
452 * filter.
453 */
454 sp->opt_delta.dist = (tif->tif_dir.td_bitspersample % 8) ?
455 1 : tif->tif_dir.td_bitspersample / 8;
456 sp->filters[0].id = LZMA_FILTER_DELTA;
457 sp->filters[0].options = &sp->opt_delta;
458
459 lzma_lzma_preset(&sp->opt_lzma, sp->preset);
460 sp->filters[1].id = LZMA_FILTER_LZMA2;
461 sp->filters[1].options = &sp->opt_lzma;
462
463 sp->filters[2].id = LZMA_VLI_UNKNOWN;
464 sp->filters[2].options = NULL;
465
466 /*
467 * Install codec methods.
468 */
469 tif->tif_fixuptags = LZMAFixupTags;
470 tif->tif_setupdecode = LZMASetupDecode;
471 tif->tif_predecode = LZMAPreDecode;
472 tif->tif_decoderow = LZMADecode;
473 tif->tif_decodestrip = LZMADecode;
474 tif->tif_decodetile = LZMADecode;
475 tif->tif_setupencode = LZMASetupEncode;
476 tif->tif_preencode = LZMAPreEncode;
477 tif->tif_postencode = LZMAPostEncode;
478 tif->tif_encoderow = LZMAEncode;
479 tif->tif_encodestrip = LZMAEncode;
480 tif->tif_encodetile = LZMAEncode;
481 tif->tif_cleanup = LZMACleanup;
482 /*
483 * Setup predictor setup.
484 */
485 (void) TIFFPredictorInit(tif);
486 return 1;
487 bad:
488 TIFFErrorExt(tif->tif_clientdata, module,
489 "No space for LZMA2 state block");
490 return 0;
491 }
492 #endif /* LZMA_SUPORT */
493
494 /* vim: set ts=8 sts=8 sw=8 noet: */