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