]>
Commit | Line | Data |
---|---|---|
80ed523f VZ |
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: */ |