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