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 64 ZSTDFixupTags(TIFF* tif) 65 { 66 (void) tif; 67 return 1; 68 } 69 70 static int 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 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 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 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 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 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 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 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 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 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 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