]> git.saurik.com Git - wxWidgets.git/blame - src/tiff/tif_packbits.c
Committing in .
[wxWidgets.git] / src / tiff / tif_packbits.c
CommitLineData
b47c832e
RR
1/* $Header$ */
2
3/*
4 * Copyright (c) 1988-1997 Sam Leffler
5 * Copyright (c) 1991-1997 Silicon Graphics, Inc.
6 *
00cb87b4 7 * Permission to use, copy, modify, distribute, and sell this software and
b47c832e
RR
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.
00cb87b4
VZ
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 *
b47c832e
RR
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,
00cb87b4
VZ
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
b47c832e
RR
24 * OF THIS SOFTWARE.
25 */
26
27#include "tiffiop.h"
28#ifdef PACKBITS_SUPPORT
29/*
30 * TIFF Library.
31 *
32 * PackBits Compression Algorithm Support
33 */
34#include <assert.h>
35#include <stdio.h>
36
37static int
38PackBitsPreEncode(TIFF* tif, tsample_t s)
39{
40 (void) s;
41 /*
42 * Calculate the scanline/tile-width size in bytes.
43 */
44 if (isTiled(tif))
45 tif->tif_data = (tidata_t) TIFFTileRowSize(tif);
46 else
47 tif->tif_data = (tidata_t) TIFFScanlineSize(tif);
48 return (1);
49}
50
51/*
52 * NB: tidata is the type representing *(tidata_t);
53 * if tidata_t is made signed then this type must
54 * be adjusted accordingly.
55 */
56typedef unsigned char tidata;
57
58/*
59 * Encode a run of pixels.
60 */
00cb87b4 61static int
b47c832e
RR
62PackBitsEncode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s)
63{
64 u_char* bp = (u_char*) buf;
65 tidata_t op, ep, lastliteral;
66 long n, slop;
67 int b;
68 enum { BASE, LITERAL, RUN, LITERAL_RUN } state;
69
70 (void) s;
71 op = tif->tif_rawcp;
72 ep = tif->tif_rawdata + tif->tif_rawdatasize;
73 state = BASE;
74 lastliteral = 0;
75 while (cc > 0) {
76 /*
77 * Find the longest string of identical bytes.
78 */
79 b = *bp++, cc--, n = 1;
80 for (; cc > 0 && b == *bp; cc--, bp++)
81 n++;
82 again:
83 if (op + 2 >= ep) { /* insure space for new data */
84 /*
85 * Be careful about writing the last
86 * literal. Must write up to that point
87 * and then copy the remainder to the
88 * front of the buffer.
89 */
90 if (state == LITERAL || state == LITERAL_RUN) {
91 slop = op - lastliteral;
92 tif->tif_rawcc += lastliteral - tif->tif_rawcp;
93 if (!TIFFFlushData1(tif))
94 return (-1);
95 op = tif->tif_rawcp;
96 while (slop-- > 0)
97 *op++ = *lastliteral++;
98 lastliteral = tif->tif_rawcp;
99 } else {
100 tif->tif_rawcc += op - tif->tif_rawcp;
101 if (!TIFFFlushData1(tif))
102 return (-1);
103 op = tif->tif_rawcp;
104 }
105 }
106 switch (state) {
107 case BASE: /* initial state, set run/literal */
108 if (n > 1) {
109 state = RUN;
110 if (n > 128) {
111 *op++ = (tidata) -127;
00cb87b4 112 *op++ = (tidataval_t) b;
b47c832e
RR
113 n -= 128;
114 goto again;
115 }
116 *op++ = (tidataval_t)(-(n-1));
00cb87b4 117 *op++ = (tidataval_t) b;
b47c832e
RR
118 } else {
119 lastliteral = op;
120 *op++ = 0;
00cb87b4 121 *op++ = (tidataval_t) b;
b47c832e
RR
122 state = LITERAL;
123 }
124 break;
125 case LITERAL: /* last object was literal string */
126 if (n > 1) {
127 state = LITERAL_RUN;
128 if (n > 128) {
129 *op++ = (tidata) -127;
00cb87b4 130 *op++ = (tidataval_t) b;
b47c832e
RR
131 n -= 128;
132 goto again;
133 }
134 *op++ = (tidataval_t)(-(n-1)); /* encode run */
00cb87b4 135 *op++ = (tidataval_t) b;
b47c832e
RR
136 } else { /* extend literal */
137 if (++(*lastliteral) == 127)
138 state = BASE;
00cb87b4 139 *op++ = (tidataval_t) b;
b47c832e
RR
140 }
141 break;
142 case RUN: /* last object was run */
143 if (n > 1) {
144 if (n > 128) {
145 *op++ = (tidata) -127;
00cb87b4 146 *op++ = (tidataval_t) b;
b47c832e
RR
147 n -= 128;
148 goto again;
149 }
150 *op++ = (tidataval_t)(-(n-1));
00cb87b4 151 *op++ = (tidataval_t) b;
b47c832e
RR
152 } else {
153 lastliteral = op;
154 *op++ = 0;
00cb87b4 155 *op++ = (tidataval_t) b;
b47c832e
RR
156 state = LITERAL;
157 }
158 break;
159 case LITERAL_RUN: /* literal followed by a run */
160 /*
161 * Check to see if previous run should
162 * be converted to a literal, in which
163 * case we convert literal-run-literal
164 * to a single literal.
165 */
166 if (n == 1 && op[-2] == (tidata) -1 &&
167 *lastliteral < 126) {
168 state = (((*lastliteral) += 2) == 127 ?
169 BASE : LITERAL);
170 op[-2] = op[-1]; /* replicate */
171 } else
172 state = RUN;
173 goto again;
174 }
175 }
176 tif->tif_rawcc += op - tif->tif_rawcp;
177 tif->tif_rawcp = op;
178 return (1);
179}
180
181/*
182 * Encode a rectangular chunk of pixels. We break it up
183 * into row-sized pieces to insure that encoded runs do
184 * not span rows. Otherwise, there can be problems with
185 * the decoder if data is read, for example, by scanlines
186 * when it was encoded by strips.
187 */
00cb87b4 188static int
b47c832e
RR
189PackBitsEncodeChunk(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
190{
00cb87b4
VZ
191#if defined(__hpux) && defined(__LP64__)
192 tsize_t rowsize = (tsize_t)(unsigned long) tif->tif_data;
193#else
b47c832e 194 tsize_t rowsize = (tsize_t) tif->tif_data;
00cb87b4 195#endif
b47c832e
RR
196
197 assert(rowsize > 0);
00cb87b4
VZ
198
199#ifdef YCBCR_SUPPORT
200 /*
201 * YCBCR data isn't really separable into rows, so we
202 * might as well encode the whole tile/strip as one chunk.
203 */
204 if( tif->tif_dir.td_photometric == PHOTOMETRIC_YCBCR ) {
205#if defined(__hpux) && defined(__LP64__)
206 rowsize = (tsize_t)(unsigned long) tif->tif_data;
207#else
208 rowsize = (tsize_t) tif->tif_data;
209#endif
210 }
211#endif
212
b47c832e 213 while ((long)cc > 0) {
00cb87b4
VZ
214 int chunk = rowsize;
215
216 if( cc < chunk )
217 chunk = cc;
218
219 if (PackBitsEncode(tif, bp, chunk, s) < 0)
220 return (-1);
221 bp += chunk;
222 cc -= chunk;
b47c832e
RR
223 }
224 return (1);
225}
226
00cb87b4 227static int
b47c832e
RR
228PackBitsDecode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s)
229{
230 char *bp;
231 tsize_t cc;
232 long n;
233 int b;
234
235 (void) s;
236 bp = (char*) tif->tif_rawcp;
237 cc = tif->tif_rawcc;
238 while (cc > 0 && (long)occ > 0) {
239 n = (long) *bp++, cc--;
240 /*
241 * Watch out for compilers that
242 * don't sign extend chars...
243 */
244 if (n >= 128)
245 n -= 256;
246 if (n < 0) { /* replicate next byte -n+1 times */
247 if (n == -128) /* nop */
248 continue;
00cb87b4
VZ
249 n = -n + 1;
250 if( occ < n )
251 {
252 TIFFWarning(tif->tif_name,
253 "PackBitsDecode: discarding %d bytes "
254 "to avoid buffer overrun",
255 n - occ);
256 n = occ;
257 }
b47c832e
RR
258 occ -= n;
259 b = *bp++, cc--;
260 while (n-- > 0)
00cb87b4 261 *op++ = (tidataval_t) b;
b47c832e 262 } else { /* copy next n+1 bytes literally */
00cb87b4
VZ
263 if (occ < n + 1)
264 {
265 TIFFWarning(tif->tif_name,
266 "PackBitsDecode: discarding %d bytes "
267 "to avoid buffer overrun",
268 n - occ + 1);
269 n = occ - 1;
270 }
271 _TIFFmemcpy(op, bp, ++n);
b47c832e
RR
272 op += n; occ -= n;
273 bp += n; cc -= n;
274 }
275 }
276 tif->tif_rawcp = (tidata_t) bp;
277 tif->tif_rawcc = cc;
278 if (occ > 0) {
279 TIFFError(tif->tif_name,
280 "PackBitsDecode: Not enough data for scanline %ld",
281 (long) tif->tif_row);
282 return (0);
283 }
b47c832e
RR
284 return (1);
285}
286
287int
288TIFFInitPackBits(TIFF* tif, int scheme)
289{
290 (void) scheme;
291 tif->tif_decoderow = PackBitsDecode;
292 tif->tif_decodestrip = PackBitsDecode;
293 tif->tif_decodetile = PackBitsDecode;
294 tif->tif_preencode = PackBitsPreEncode;
295 tif->tif_encoderow = PackBitsEncode;
296 tif->tif_encodestrip = PackBitsEncodeChunk;
297 tif->tif_encodetile = PackBitsEncodeChunk;
298 return (1);
299}
300#endif /* PACKBITS_SUPPORT */