source: trunk/third/tiff/libtiff/tif_zip.c @ 18174

Revision 18174, 9.7 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18173, which included commits to RCS files with non-trunk default branches.
Line 
1/* $Header: /afs/dev.mit.edu/source/repository/third/tiff/libtiff/tif_zip.c,v 1.1.1.1 2002-12-26 02:38:35 ghudson Exp $ */
2
3/*
4 * Copyright (c) 1995-1997 Sam Leffler
5 * Copyright (c) 1995-1997 Silicon Graphics, Inc.
6 *
7 * Permission to use, copy, modify, distribute, and sell this software and
8 * its documentation for any purpose is hereby granted without fee, provided
9 * that (i) the above copyright notices and this permission notice appear in
10 * all copies of the software and related documentation, and (ii) the names of
11 * Sam Leffler and Silicon Graphics may not be used in any advertising or
12 * publicity relating to the software without the specific, prior written
13 * permission of Sam Leffler and Silicon Graphics.
14 *
15 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
17 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 
18 *
19 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
20 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
21 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
22 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
23 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24 * OF THIS SOFTWARE.
25 */
26
27#include "tiffiop.h"
28#ifdef ZIP_SUPPORT
29/*
30 * TIFF Library.
31 *
32 * ZIP (aka Deflate) Compression Support
33 *
34 * This file is simply an interface to the zlib library written by
35 * Jean-loup Gailly and Mark Adler.  You must use version 1.0 or later
36 * of the library: this code assumes the 1.0 API and also depends on
37 * the ability to write the zlib header multiple times (one per strip)
38 * which was not possible with versions prior to 0.95.  Note also that
39 * older versions of this codec avoided this bug by supressing the header
40 * entirely.  This means that files written with the old library cannot
41 * be read; they should be converted to a different compression scheme
42 * and then reconverted.
43 *
44 * The data format used by the zlib library is described in the files
45 * zlib-3.1.doc, deflate-1.1.doc and gzip-4.1.doc, available in the
46 * directory ftp://ftp.uu.net/pub/archiving/zip/doc.  The library was
47 * last found at ftp://ftp.uu.net/pub/archiving/zip/zlib/zlib-0.99.tar.gz.
48 */
49#include "tif_predict.h"
50#include "zlib.h"
51
52#include <stdio.h>
53#include <assert.h>
54
55/*
56 * Sigh, ZLIB_VERSION is defined as a string so there's no
57 * way to do a proper check here.  Instead we guess based
58 * on the presence of #defines that were added between the
59 * 0.95 and 1.0 distributions.
60 */
61#if !defined(Z_NO_COMPRESSION) || !defined(Z_DEFLATED)
62#error "Antiquated ZLIB software; you must use version 1.0 or later"
63#endif
64
65/*
66 * State block for each open TIFF
67 * file using ZIP compression/decompression.
68 */
69typedef struct {
70        TIFFPredictorState predict;
71        z_stream        stream;
72        int             zipquality;             /* compression level */
73        int             state;                  /* state flags */
74#define ZSTATE_INIT     0x1             /* zlib setup successfully */
75
76        TIFFVGetMethod  vgetparent;             /* super-class method */
77        TIFFVSetMethod  vsetparent;             /* super-class method */
78} ZIPState;
79
80#define ZState(tif)             ((ZIPState*) (tif)->tif_data)
81#define DecoderState(tif)       ZState(tif)
82#define EncoderState(tif)       ZState(tif)
83
84static  int ZIPEncode(TIFF*, tidata_t, tsize_t, tsample_t);
85static  int ZIPDecode(TIFF*, tidata_t, tsize_t, tsample_t);
86
87static int
88ZIPSetupDecode(TIFF* tif)
89{
90        ZIPState* sp = DecoderState(tif);
91        static const char module[] = "ZIPSetupDecode";
92
93        assert(sp != NULL);
94        if (inflateInit(&sp->stream) != Z_OK) {
95                TIFFError(module, "%s: %s", tif->tif_name, sp->stream.msg);
96                return (0);
97        } else {
98                sp->state |= ZSTATE_INIT;
99                return (1);
100        }
101}
102
103/*
104 * Setup state for decoding a strip.
105 */
106static int
107ZIPPreDecode(TIFF* tif, tsample_t s)
108{
109        ZIPState* sp = DecoderState(tif);
110
111        (void) s;
112        assert(sp != NULL);
113        sp->stream.next_in = tif->tif_rawdata;
114        sp->stream.avail_in = tif->tif_rawcc;
115        return (inflateReset(&sp->stream) == Z_OK);
116}
117
118static int
119ZIPDecode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s)
120{
121        ZIPState* sp = DecoderState(tif);
122        static const char module[] = "ZIPDecode";
123
124        (void) s;
125        assert(sp != NULL);
126        sp->stream.next_out = op;
127        sp->stream.avail_out = occ;
128        do {
129                int state = inflate(&sp->stream, Z_PARTIAL_FLUSH);
130                if (state == Z_STREAM_END)
131                        break;
132                if (state == Z_DATA_ERROR) {
133                        TIFFError(module,
134                            "%s: Decoding error at scanline %d, %s",
135                            tif->tif_name, tif->tif_row, sp->stream.msg);
136                        if (inflateSync(&sp->stream) != Z_OK)
137                                return (0);
138                        continue;
139                }
140                if (state != Z_OK) {
141                        TIFFError(module, "%s: zlib error: %s",
142                            tif->tif_name, sp->stream.msg);
143                        return (0);
144                }
145        } while (sp->stream.avail_out > 0);
146        if (sp->stream.avail_out != 0) {
147                TIFFError(module,
148                    "%s: Not enough data at scanline %d (short %d bytes)",
149                    tif->tif_name, tif->tif_row, sp->stream.avail_out);
150                return (0);
151        }
152        return (1);
153}
154
155static int
156ZIPSetupEncode(TIFF* tif)
157{
158        ZIPState* sp = EncoderState(tif);
159        static const char module[] = "ZIPSetupEncode";
160
161        assert(sp != NULL);
162        if (deflateInit(&sp->stream, sp->zipquality) != Z_OK) {
163                TIFFError(module, "%s: %s", tif->tif_name, sp->stream.msg);
164                return (0);
165        } else {
166                sp->state |= ZSTATE_INIT;
167                return (1);
168        }
169}
170
171/*
172 * Reset encoding state at the start of a strip.
173 */
174static int
175ZIPPreEncode(TIFF* tif, tsample_t s)
176{
177        ZIPState *sp = EncoderState(tif);
178
179        (void) s;
180        assert(sp != NULL);
181        sp->stream.next_out = tif->tif_rawdata;
182        sp->stream.avail_out = tif->tif_rawdatasize;
183        return (deflateReset(&sp->stream) == Z_OK);
184}
185
186/*
187 * Encode a chunk of pixels.
188 */
189static int
190ZIPEncode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
191{
192        ZIPState *sp = EncoderState(tif);
193        static const char module[] = "ZIPEncode";
194
195        (void) s;
196        sp->stream.next_in = bp;
197        sp->stream.avail_in = cc;
198        do {
199                if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK) {
200                        TIFFError(module, "%s: Encoder error: %s",
201                            tif->tif_name, sp->stream.msg);
202                        return (0);
203                }
204                if (sp->stream.avail_out == 0) {
205                        tif->tif_rawcc = tif->tif_rawdatasize;
206                        TIFFFlushData1(tif);
207                        sp->stream.next_out = tif->tif_rawdata;
208                        sp->stream.avail_out = tif->tif_rawdatasize;
209                }
210        } while (sp->stream.avail_in > 0);
211        return (1);
212}
213
214/*
215 * Finish off an encoded strip by flushing the last
216 * string and tacking on an End Of Information code.
217 */
218static int
219ZIPPostEncode(TIFF* tif)
220{
221        ZIPState *sp = EncoderState(tif);
222        static const char module[] = "ZIPPostEncode";
223        int state;
224
225        sp->stream.avail_in = 0;
226        do {
227                state = deflate(&sp->stream, Z_FINISH);
228                switch (state) {
229                case Z_STREAM_END:
230                case Z_OK:
231                    if (sp->stream.avail_out != tif->tif_rawdatasize) {
232                            tif->tif_rawcc =
233                                tif->tif_rawdatasize - sp->stream.avail_out;
234                            TIFFFlushData1(tif);
235                            sp->stream.next_out = tif->tif_rawdata;
236                            sp->stream.avail_out = tif->tif_rawdatasize;
237                    }
238                    break;
239                default:
240                    TIFFError(module, "%s: zlib error: %s",
241                        tif->tif_name, sp->stream.msg);
242                    return (0);
243                }
244        } while (state != Z_STREAM_END);
245        return (1);
246}
247
248static void
249ZIPCleanup(TIFF* tif)
250{
251        ZIPState* sp = ZState(tif);
252        if (sp) {
253                if (sp->state&ZSTATE_INIT) {
254                        /* NB: avoid problems in the library */
255                        if (tif->tif_mode == O_RDONLY)
256                                inflateEnd(&sp->stream);
257                        else
258                                deflateEnd(&sp->stream);
259                }
260                _TIFFfree(sp);
261                tif->tif_data = NULL;
262        }
263}
264
265static int
266ZIPVSetField(TIFF* tif, ttag_t tag, va_list ap)
267{
268        ZIPState* sp = ZState(tif);
269        static const char module[] = "ZIPVSetField";
270
271        switch (tag) {
272        case TIFFTAG_ZIPQUALITY:
273                sp->zipquality = va_arg(ap, int);
274                if (tif->tif_mode != O_RDONLY && (sp->state&ZSTATE_INIT)) {
275                        if (deflateParams(&sp->stream,
276                            sp->zipquality, Z_DEFAULT_STRATEGY) != Z_OK) {
277                                TIFFError(module, "%s: zlib error: %s",
278                                    tif->tif_name, sp->stream.msg);
279                                return (0);
280                        }
281                }
282                return (1);
283        default:
284                return (*sp->vsetparent)(tif, tag, ap);
285        }
286        /*NOTREACHED*/
287}
288
289static int
290ZIPVGetField(TIFF* tif, ttag_t tag, va_list ap)
291{
292        ZIPState* sp = ZState(tif);
293
294        switch (tag) {
295        case TIFFTAG_ZIPQUALITY:
296                *va_arg(ap, int*) = sp->zipquality;
297                break;
298        default:
299                return (*sp->vgetparent)(tif, tag, ap);
300        }
301        return (1);
302}
303
304static const TIFFFieldInfo zipFieldInfo[] = {
305    { TIFFTAG_ZIPQUALITY,        0, 0,  TIFF_ANY,       FIELD_PSEUDO,
306      TRUE,     FALSE,  "" },
307};
308#define N(a)    (sizeof (a) / sizeof (a[0]))
309
310int
311TIFFInitZIP(TIFF* tif, int scheme)
312{
313        ZIPState* sp;
314
315        assert( (scheme == COMPRESSION_DEFLATE) || (scheme == COMPRESSION_ADOBE_DEFLATE));
316
317        /*
318         * Allocate state block so tag methods have storage to record values.
319         */
320        tif->tif_data = (tidata_t) _TIFFmalloc(sizeof (ZIPState));
321        if (tif->tif_data == NULL)
322                goto bad;
323        sp = ZState(tif);
324        sp->stream.zalloc = NULL;
325        sp->stream.zfree = NULL;
326        sp->stream.opaque = NULL;
327        sp->stream.data_type = Z_BINARY;
328
329        /*
330         * Merge codec-specific tag information and
331         * override parent get/set field methods.
332         */
333        _TIFFMergeFieldInfo(tif, zipFieldInfo, N(zipFieldInfo));
334        sp->vgetparent = tif->tif_vgetfield;
335        tif->tif_vgetfield = ZIPVGetField;      /* hook for codec tags */
336        sp->vsetparent = tif->tif_vsetfield;
337        tif->tif_vsetfield = ZIPVSetField;      /* hook for codec tags */
338
339        /* Default values for codec-specific fields */
340        sp->zipquality = Z_DEFAULT_COMPRESSION; /* default comp. level */
341        sp->state = 0;
342
343        /*
344         * Install codec methods.
345         */
346        tif->tif_setupdecode = ZIPSetupDecode;
347        tif->tif_predecode = ZIPPreDecode;
348        tif->tif_decoderow = ZIPDecode;
349        tif->tif_decodestrip = ZIPDecode;
350        tif->tif_decodetile = ZIPDecode;
351        tif->tif_setupencode = ZIPSetupEncode;
352        tif->tif_preencode = ZIPPreEncode;
353        tif->tif_postencode = ZIPPostEncode;
354        tif->tif_encoderow = ZIPEncode;
355        tif->tif_encodestrip = ZIPEncode;
356        tif->tif_encodetile = ZIPEncode;
357        tif->tif_cleanup = ZIPCleanup;
358        /*
359         * Setup predictor setup.
360         */
361        (void) TIFFPredictorInit(tif);
362        return (1);
363bad:
364        TIFFError("TIFFInitZIP", "No space for ZIP state block");
365        return (0);
366}
367#endif /* ZIP_SUPORT */
Note: See TracBrowser for help on using the repository browser.