ReactOS 0.4.15-dev-8339-g4028de8
tif_zstd.c
Go to the documentation of this file.
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*/
42typedef struct {
43 TIFFPredictorState predict;
44 ZSTD_DStream* dstream;
45 ZSTD_CStream* cstream;
46 int compression_level; /* compression level */
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
60static int ZSTDEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s);
61static int ZSTDDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s);
62
63static int
64ZSTDFixupTags(TIFF* tif)
65{
66 (void) tif;
67 return 1;
68}
69
70static int
71ZSTDSetupDecode(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*/
91static int
92ZSTDPreDecode(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 ) {
113 "Cannot allocate decompression stream");
114 return 0;
115 }
116 zstd_ret = ZSTD_initDStream(sp->dstream);
117 if( ZSTD_isError(zstd_ret) ) {
119 "Error in ZSTD_initDStream(): %s",
120 ZSTD_getErrorName(zstd_ret));
121 return 0;
122 }
123
124 return 1;
125}
126
127static int
128ZSTDDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
129{
130 static const char module[] = "ZSTDDecode";
131 ZSTDState* sp = DecoderState(tif);
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) ) {
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) {
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
175static int
176ZSTDSetupEncode(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*/
194static int
195ZSTDPreEncode(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 ) {
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) ) {
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*/
235static int
236ZSTDEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
237{
238 static const char module[] = "ZSTDEncode";
239 ZSTDState *sp = EncoderState(tif);
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) ) {
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*/
275static int
276ZSTDPostEncode(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) ) {
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
300static void
301ZSTDCleanup(TIFF* tif)
302{
303 ZSTDState* sp = LState(tif);
304
305 assert(sp != 0);
306
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
324}
325
326static int
327ZSTDVSetField(TIFF* tif, uint32 tag, va_list ap)
328{
329 static const char module[] = "ZSTDVSetField";
330 ZSTDState* sp = LState(tif);
331
332 switch (tag) {
334 sp->compression_level = (int) va_arg(ap, int);
335 if( sp->compression_level <= 0 ||
336 sp->compression_level > ZSTD_maxCLevel() )
337 {
339 "ZSTD_LEVEL should be between 1 and %d",
341 }
342 return 1;
343 default:
344 return (*sp->vsetparent)(tif, tag, ap);
345 }
346 /*NOTREACHED*/
347}
348
349static int
350ZSTDVGetField(TIFF* tif, uint32 tag, va_list ap)
351{
352 ZSTDState* sp = LState(tif);
353
354 switch (tag) {
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
364static const TIFFField ZSTDFields[] = {
367 FIELD_PSEUDO, TRUE, FALSE, "ZSTD compression_level", NULL },
368};
369
370int
371TIFFInitZSTD(TIFF* tif, int scheme)
372{
373 static const char module[] = "TIFFInitZSTD";
374 ZSTDState* sp;
375
377
378 /*
379 * Merge codec-specific tag information.
380 */
381 if (!_TIFFMergeFields(tif, ZSTDFields, TIFFArrayCount(ZSTDFields))) {
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;
433bad:
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: */
char * va_list
Definition: acmsvcex.h:78
#define va_arg(ap, T)
Definition: acmsvcex.h:89
static int state
Definition: maze.c:121
unsigned short uint16
Definition: types.h:30
unsigned int uint32
Definition: types.h:32
unsigned char uint8
Definition: types.h:28
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
UINT op
Definition: effect.c:236
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
#define assert(x)
Definition: debug.h:53
__kernel_size_t size_t
Definition: linux.h:237
GLdouble s
Definition: gl.h:2039
static unsigned char * in_buffer
Definition: iccvid.c:87
uint32_t cc
Definition: isohybrid.c:75
static const WCHAR sp[]
Definition: suminfo.c:287
static HANDLE PIO_APC_ROUTINE PVOID PIO_STATUS_BLOCK ULONG PVOID ULONG PVOID out_buffer
Definition: file.c:100
DWORD scheme
TIFFVGetMethod vgetfield
Definition: tiffio.h:334
TIFFVSetMethod vsetfield
Definition: tiffio.h:333
Definition: ecma_167.h:138
Definition: tiffiop.h:115
TIFFCodeMethod tif_encodestrip
Definition: tiffiop.h:183
TIFFCodeMethod tif_encodetile
Definition: tiffiop.h:185
TIFFTagMethods tif_tagmethods
Definition: tiffiop.h:219
TIFFPreMethod tif_preencode
Definition: tiffiop.h:178
TIFFBoolMethod tif_fixuptags
Definition: tiffiop.h:173
tmsize_t tif_rawcc
Definition: tiffiop.h:200
TIFFPreMethod tif_predecode
Definition: tiffiop.h:175
TIFFCodeMethod tif_decodestrip
Definition: tiffiop.h:182
thandle_t tif_clientdata
Definition: tiffiop.h:207
TIFFCodeMethod tif_decoderow
Definition: tiffiop.h:180
TIFFBoolMethod tif_setupencode
Definition: tiffiop.h:176
TIFFBoolMethod tif_postencode
Definition: tiffiop.h:179
uint8 * tif_data
Definition: tiffiop.h:191
TIFFCodeMethod tif_encoderow
Definition: tiffiop.h:181
TIFFVoidMethod tif_cleanup
Definition: tiffiop.h:188
uint32 tif_row
Definition: tiffiop.h:159
TIFFBoolMethod tif_setupdecode
Definition: tiffiop.h:174
tmsize_t tif_rawdatasize
Definition: tiffiop.h:196
uint8 * tif_rawcp
Definition: tiffiop.h:199
TIFFCodeMethod tif_decodetile
Definition: tiffiop.h:184
uint8 * tif_rawdata
Definition: tiffiop.h:195
#define TIFFInitZSTD
Definition: tif_codec.c:75
void _TIFFSetDefaultCompressionState(TIFF *tif)
Definition: tif_compress.c:135
#define FIELD_PSEUDO
Definition: tif_dir.h:190
@ TIFF_SETGET_UNDEFINED
Definition: tif_dir.h:204
@ TIFF_SETGET_INT
Definition: tif_dir.h:217
int _TIFFMergeFields(TIFF *tif, const TIFFField info[], uint32 n)
Definition: tif_dirinfo.c:369
void TIFFErrorExt(thandle_t fd, const char *module, const char *fmt,...)
Definition: tif_error.c:65
int TIFFPredictorCleanup(TIFF *tif)
Definition: tif_predict.c:857
int TIFFPredictorInit(TIFF *tif)
Definition: tif_predict.c:816
void _TIFFfree(void *p)
Definition: tif_unix.c:326
void * _TIFFmalloc(tmsize_t s)
Definition: tif_unix.c:309
void TIFFWarningExt(thandle_t fd, const char *module, const char *fmt,...)
Definition: tif_warning.c:65
int TIFFFlushData1(TIFF *tif)
Definition: tif_write.c:803
#define COMPRESSION_ZSTD
Definition: tiff.h:192
#define TIFFTAG_ZSTD_LEVEL
Definition: tiff.h:569
TIFF_SSIZE_T tmsize_t
Definition: tiffio.h:65
int(* TIFFVGetMethod)(TIFF *, uint32, va_list)
Definition: tiffio.h:329
#define TIFF_ANY
Definition: tiffio.h:307
int(* TIFFVSetMethod)(TIFF *, uint32, va_list)
Definition: tiffio.h:328
#define TIFFArrayCount(a)
Definition: tiffiop.h:283
void int int ULONGLONG int va_list * ap
Definition: winesup.h:36
ZSTDLIB_API size_t ZSTD_initCStream(ZSTD_CStream *zcs, int compressionLevel)
ZSTDLIB_API size_t ZSTD_initDStream(ZSTD_DStream *zds)
ZSTDLIB_API size_t ZSTD_compressStream(ZSTD_CStream *zcs, ZSTD_outBuffer *output, ZSTD_inBuffer *input)
ZSTDLIB_API size_t ZSTD_freeCStream(ZSTD_CStream *zcs)
ZSTDLIB_API size_t ZSTD_decompressStream(ZSTD_DStream *zds, ZSTD_outBuffer *output, ZSTD_inBuffer *input)
ZSTDLIB_API const char * ZSTD_getErrorName(size_t code)
Definition: zstd_common.c:41
ZSTDLIB_API ZSTD_DStream * ZSTD_createDStream(void)
ZSTDLIB_API ZSTD_CStream * ZSTD_createCStream(void)
ZSTDLIB_API size_t ZSTD_endStream(ZSTD_CStream *zcs, ZSTD_outBuffer *output)
ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream *zds)
ZSTDLIB_API int ZSTD_maxCLevel(void)
#define ZSTD_isError
Definition: zstd_internal.h:46