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