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