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