Line data Source code
1 : /*
2 : * Copyright (c) 2017, Planet Labs
3 : * Author: <even.rouault at spatialys.com>
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 ZSTD_SUPPORT
27 : /*
28 : * TIFF Library.
29 : *
30 : * ZSTD Compression Support
31 : *
32 : */
33 :
34 : #include "tif_predict.h"
35 : #include "zstd.h"
36 :
37 : #include <stdio.h>
38 :
39 : /*
40 : * State block for each open TIFF file using ZSTD compression/decompression.
41 : */
42 : typedef struct
43 : {
44 : TIFFPredictorState predict;
45 : ZSTD_DStream *dstream;
46 : ZSTD_CStream *cstream;
47 : int compression_level; /* compression level */
48 : ZSTD_outBuffer out_buffer;
49 : int state; /* state flags */
50 : #define LSTATE_INIT_DECODE 0x01
51 : #define LSTATE_INIT_ENCODE 0x02
52 :
53 : TIFFVGetMethod vgetparent; /* super-class method */
54 : TIFFVSetMethod vsetparent; /* super-class method */
55 : } ZSTDState;
56 :
57 : #define GetZSTDState(tif) ((ZSTDState *)(tif)->tif_data)
58 : #define ZSTDDecoderState(tif) GetZSTDState(tif)
59 : #define ZSTDEncoderState(tif) GetZSTDState(tif)
60 :
61 : static int ZSTDEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s);
62 : static int ZSTDDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s);
63 :
64 703 : static int ZSTDFixupTags(TIFF *tif)
65 : {
66 : (void)tif;
67 703 : return 1;
68 : }
69 :
70 153 : static int ZSTDSetupDecode(TIFF *tif)
71 : {
72 153 : ZSTDState *sp = ZSTDDecoderState(tif);
73 :
74 153 : assert(sp != NULL);
75 :
76 : /* if we were last encoding, terminate this mode */
77 153 : if (sp->state & LSTATE_INIT_ENCODE)
78 : {
79 21 : ZSTD_freeCStream(sp->cstream);
80 21 : sp->cstream = NULL;
81 21 : sp->state = 0;
82 : }
83 :
84 153 : sp->state |= LSTATE_INIT_DECODE;
85 153 : return 1;
86 : }
87 :
88 : /*
89 : * Setup state for decoding a strip.
90 : */
91 495 : static int ZSTDPreDecode(TIFF *tif, uint16_t s)
92 : {
93 : static const char module[] = "ZSTDPreDecode";
94 495 : ZSTDState *sp = ZSTDDecoderState(tif);
95 : size_t zstd_ret;
96 :
97 : (void)s;
98 495 : assert(sp != NULL);
99 :
100 495 : if ((sp->state & LSTATE_INIT_DECODE) == 0)
101 21 : tif->tif_setupdecode(tif);
102 :
103 495 : if (sp->dstream == NULL)
104 : {
105 153 : sp->dstream = ZSTD_createDStream();
106 153 : if (sp->dstream == NULL)
107 : {
108 0 : TIFFErrorExtR(tif, module, "Cannot allocate decompression stream");
109 0 : return 0;
110 : }
111 : }
112 :
113 495 : zstd_ret = ZSTD_initDStream(sp->dstream);
114 495 : if (ZSTD_isError(zstd_ret))
115 : {
116 0 : TIFFErrorExtR(tif, module, "Error in ZSTD_initDStream(): %s",
117 : ZSTD_getErrorName(zstd_ret));
118 0 : return 0;
119 : }
120 :
121 495 : return 1;
122 : }
123 :
124 495 : static int ZSTDDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
125 : {
126 : static const char module[] = "ZSTDDecode";
127 495 : ZSTDState *sp = ZSTDDecoderState(tif);
128 : ZSTD_inBuffer in_buffer;
129 : ZSTD_outBuffer out_buffer;
130 : size_t zstd_ret;
131 :
132 : (void)s;
133 495 : assert(sp != NULL);
134 495 : assert(sp->state == LSTATE_INIT_DECODE);
135 :
136 495 : in_buffer.src = tif->tif_rawcp;
137 495 : in_buffer.size = (size_t)tif->tif_rawcc;
138 495 : in_buffer.pos = 0;
139 :
140 495 : out_buffer.dst = op;
141 495 : out_buffer.size = (size_t)occ;
142 495 : out_buffer.pos = 0;
143 :
144 : do
145 : {
146 495 : zstd_ret = ZSTD_decompressStream(sp->dstream, &out_buffer, &in_buffer);
147 495 : if (ZSTD_isError(zstd_ret))
148 : {
149 2 : memset(op + out_buffer.pos, 0, out_buffer.size - out_buffer.pos);
150 2 : TIFFErrorExtR(tif, module, "Error in ZSTD_decompressStream(): %s",
151 : ZSTD_getErrorName(zstd_ret));
152 2 : return 0;
153 : }
154 170 : } while (zstd_ret != 0 && in_buffer.pos < in_buffer.size &&
155 663 : out_buffer.pos < out_buffer.size);
156 :
157 493 : if (out_buffer.pos < (size_t)occ)
158 : {
159 0 : memset(op + out_buffer.pos, 0, out_buffer.size - out_buffer.pos);
160 0 : TIFFErrorExtR(tif, module,
161 : "Not enough data at scanline %lu (short %lu bytes)",
162 0 : (unsigned long)tif->tif_row,
163 0 : (unsigned long)((size_t)occ - out_buffer.pos));
164 0 : return 0;
165 : }
166 :
167 493 : tif->tif_rawcp += in_buffer.pos;
168 493 : tif->tif_rawcc -= in_buffer.pos;
169 :
170 493 : return 1;
171 : }
172 :
173 109 : static int ZSTDSetupEncode(TIFF *tif)
174 : {
175 109 : ZSTDState *sp = ZSTDEncoderState(tif);
176 :
177 109 : assert(sp != NULL);
178 109 : if (sp->state & LSTATE_INIT_DECODE)
179 : {
180 0 : ZSTD_freeDStream(sp->dstream);
181 0 : sp->dstream = NULL;
182 0 : sp->state = 0;
183 : }
184 :
185 109 : sp->state |= LSTATE_INIT_ENCODE;
186 109 : return 1;
187 : }
188 :
189 : /*
190 : * Reset encoding state at the start of a strip.
191 : */
192 282 : static int ZSTDPreEncode(TIFF *tif, uint16_t s)
193 : {
194 : static const char module[] = "ZSTDPreEncode";
195 282 : ZSTDState *sp = ZSTDEncoderState(tif);
196 : size_t zstd_ret;
197 :
198 : (void)s;
199 282 : assert(sp != NULL);
200 282 : if (sp->state != LSTATE_INIT_ENCODE)
201 0 : tif->tif_setupencode(tif);
202 :
203 282 : if (sp->cstream == NULL)
204 : {
205 109 : sp->cstream = ZSTD_createCStream();
206 109 : if (sp->cstream == NULL)
207 : {
208 0 : TIFFErrorExtR(tif, module, "Cannot allocate compression stream");
209 0 : return 0;
210 : }
211 : }
212 :
213 282 : zstd_ret = ZSTD_initCStream(sp->cstream, sp->compression_level);
214 282 : if (ZSTD_isError(zstd_ret))
215 : {
216 0 : TIFFErrorExtR(tif, module, "Error in ZSTD_initCStream(): %s",
217 : ZSTD_getErrorName(zstd_ret));
218 0 : return 0;
219 : }
220 :
221 282 : sp->out_buffer.dst = tif->tif_rawdata;
222 282 : sp->out_buffer.size = (size_t)tif->tif_rawdatasize;
223 282 : sp->out_buffer.pos = 0;
224 :
225 282 : return 1;
226 : }
227 :
228 : /*
229 : * Encode a chunk of pixels.
230 : */
231 282 : static int ZSTDEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s)
232 : {
233 : static const char module[] = "ZSTDEncode";
234 282 : ZSTDState *sp = ZSTDEncoderState(tif);
235 : ZSTD_inBuffer in_buffer;
236 : size_t zstd_ret;
237 :
238 282 : assert(sp != NULL);
239 282 : assert(sp->state == LSTATE_INIT_ENCODE);
240 :
241 : (void)s;
242 :
243 282 : in_buffer.src = bp;
244 282 : in_buffer.size = (size_t)cc;
245 282 : in_buffer.pos = 0;
246 :
247 : do
248 : {
249 : zstd_ret =
250 282 : ZSTD_compressStream(sp->cstream, &sp->out_buffer, &in_buffer);
251 282 : if (ZSTD_isError(zstd_ret))
252 : {
253 0 : TIFFErrorExtR(tif, module, "Error in ZSTD_compressStream(): %s",
254 : ZSTD_getErrorName(zstd_ret));
255 0 : return 0;
256 : }
257 282 : if (sp->out_buffer.pos == sp->out_buffer.size)
258 : {
259 0 : tif->tif_rawcc = tif->tif_rawdatasize;
260 0 : if (!TIFFFlushData1(tif))
261 0 : return 0;
262 0 : sp->out_buffer.dst = tif->tif_rawcp;
263 0 : sp->out_buffer.pos = 0;
264 : }
265 282 : } while (in_buffer.pos < in_buffer.size);
266 :
267 282 : return 1;
268 : }
269 :
270 : /*
271 : * Finish off an encoded strip by flushing it.
272 : */
273 282 : static int ZSTDPostEncode(TIFF *tif)
274 : {
275 : static const char module[] = "ZSTDPostEncode";
276 282 : ZSTDState *sp = ZSTDEncoderState(tif);
277 : size_t zstd_ret;
278 :
279 : do
280 : {
281 282 : zstd_ret = ZSTD_endStream(sp->cstream, &sp->out_buffer);
282 282 : if (ZSTD_isError(zstd_ret))
283 : {
284 0 : TIFFErrorExtR(tif, module, "Error in ZSTD_endStream(): %s",
285 : ZSTD_getErrorName(zstd_ret));
286 0 : return 0;
287 : }
288 282 : if (sp->out_buffer.pos > 0)
289 : {
290 282 : tif->tif_rawcc = sp->out_buffer.pos;
291 282 : if (!TIFFFlushData1(tif))
292 0 : return 0;
293 282 : sp->out_buffer.dst = tif->tif_rawcp;
294 282 : sp->out_buffer.pos = 0;
295 : }
296 282 : } while (zstd_ret != 0);
297 282 : return 1;
298 : }
299 :
300 868 : static void ZSTDCleanup(TIFF *tif)
301 : {
302 868 : ZSTDState *sp = GetZSTDState(tif);
303 :
304 868 : assert(sp != 0);
305 :
306 868 : (void)TIFFPredictorCleanup(tif);
307 :
308 868 : tif->tif_tagmethods.vgetfield = sp->vgetparent;
309 868 : tif->tif_tagmethods.vsetfield = sp->vsetparent;
310 :
311 868 : if (sp->dstream)
312 : {
313 153 : ZSTD_freeDStream(sp->dstream);
314 153 : sp->dstream = NULL;
315 : }
316 868 : if (sp->cstream)
317 : {
318 88 : ZSTD_freeCStream(sp->cstream);
319 88 : sp->cstream = NULL;
320 : }
321 868 : _TIFFfreeExt(tif, sp);
322 868 : tif->tif_data = NULL;
323 :
324 868 : _TIFFSetDefaultCompressionState(tif);
325 868 : }
326 :
327 8233 : static int ZSTDVSetField(TIFF *tif, uint32_t tag, va_list ap)
328 : {
329 : static const char module[] = "ZSTDVSetField";
330 8233 : ZSTDState *sp = GetZSTDState(tif);
331 :
332 8233 : switch (tag)
333 : {
334 26 : case TIFFTAG_ZSTD_LEVEL:
335 26 : sp->compression_level = (int)va_arg(ap, int);
336 52 : if (sp->compression_level <= 0 ||
337 26 : sp->compression_level > ZSTD_maxCLevel())
338 : {
339 0 : TIFFWarningExtR(tif, module,
340 : "ZSTD_LEVEL should be between 1 and %d",
341 : ZSTD_maxCLevel());
342 : }
343 26 : return 1;
344 8207 : default:
345 8207 : return (*sp->vsetparent)(tif, tag, ap);
346 : }
347 : /*NOTREACHED*/
348 : }
349 :
350 8001 : static int ZSTDVGetField(TIFF *tif, uint32_t tag, va_list ap)
351 : {
352 8001 : ZSTDState *sp = GetZSTDState(tif);
353 :
354 8001 : switch (tag)
355 : {
356 0 : case TIFFTAG_ZSTD_LEVEL:
357 0 : *va_arg(ap, int *) = sp->compression_level;
358 0 : break;
359 8001 : default:
360 8001 : return (*sp->vgetparent)(tif, tag, ap);
361 : }
362 0 : return 1;
363 : }
364 :
365 : static const TIFFField ZSTDFields[] = {
366 : {TIFFTAG_ZSTD_LEVEL, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT,
367 : TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "ZSTD compression_level",
368 : NULL},
369 : };
370 :
371 868 : int TIFFInitZSTD(TIFF *tif, int scheme)
372 : {
373 : static const char module[] = "TIFFInitZSTD";
374 : ZSTDState *sp;
375 :
376 : (void)scheme;
377 868 : assert(scheme == COMPRESSION_ZSTD);
378 :
379 : /*
380 : * Merge codec-specific tag information.
381 : */
382 868 : if (!_TIFFMergeFields(tif, ZSTDFields, TIFFArrayCount(ZSTDFields)))
383 : {
384 0 : TIFFErrorExtR(tif, module, "Merging ZSTD codec-specific tags failed");
385 0 : return 0;
386 : }
387 :
388 : /*
389 : * Allocate state block so tag methods have storage to record values.
390 : */
391 868 : tif->tif_data = (uint8_t *)_TIFFmallocExt(tif, sizeof(ZSTDState));
392 868 : if (tif->tif_data == NULL)
393 0 : goto bad;
394 868 : sp = GetZSTDState(tif);
395 :
396 : /*
397 : * Override parent get/set field methods.
398 : */
399 868 : sp->vgetparent = tif->tif_tagmethods.vgetfield;
400 868 : tif->tif_tagmethods.vgetfield = ZSTDVGetField; /* hook for codec tags */
401 868 : sp->vsetparent = tif->tif_tagmethods.vsetfield;
402 868 : tif->tif_tagmethods.vsetfield = ZSTDVSetField; /* hook for codec tags */
403 :
404 : /* Default values for codec-specific fields */
405 868 : sp->compression_level = 9; /* default comp. level */
406 868 : sp->state = 0;
407 868 : sp->dstream = 0;
408 868 : sp->cstream = 0;
409 868 : sp->out_buffer.dst = NULL;
410 868 : sp->out_buffer.size = 0;
411 868 : sp->out_buffer.pos = 0;
412 :
413 : /*
414 : * Install codec methods.
415 : */
416 868 : tif->tif_fixuptags = ZSTDFixupTags;
417 868 : tif->tif_setupdecode = ZSTDSetupDecode;
418 868 : tif->tif_predecode = ZSTDPreDecode;
419 868 : tif->tif_decoderow = ZSTDDecode;
420 868 : tif->tif_decodestrip = ZSTDDecode;
421 868 : tif->tif_decodetile = ZSTDDecode;
422 868 : tif->tif_setupencode = ZSTDSetupEncode;
423 868 : tif->tif_preencode = ZSTDPreEncode;
424 868 : tif->tif_postencode = ZSTDPostEncode;
425 868 : tif->tif_encoderow = ZSTDEncode;
426 868 : tif->tif_encodestrip = ZSTDEncode;
427 868 : tif->tif_encodetile = ZSTDEncode;
428 868 : tif->tif_cleanup = ZSTDCleanup;
429 : /*
430 : * Setup predictor setup.
431 : */
432 868 : (void)TIFFPredictorInit(tif);
433 868 : return 1;
434 0 : bad:
435 0 : TIFFErrorExtR(tif, module, "No space for ZSTD state block");
436 0 : return 0;
437 : }
438 : #endif /* ZSTD_SUPPORT */
|