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