]> git.saurik.com Git - wxWidgets.git/blame - src/tiff/tif_packbits.c
made wxFFile a bit more safe: don't crash when Tell() and Length() are called on...
[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 *
615a9936 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.
615a9936
DW
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,
615a9936
DW
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 */
615a9936 61static int LINKAGEMODE
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;
112 *op++ = b;
113 n -= 128;
114 goto again;
115 }
116 *op++ = (tidataval_t)(-(n-1));
117 *op++ = b;
118 } else {
119 lastliteral = op;
120 *op++ = 0;
121 *op++ = b;
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;
130 *op++ = b;
131 n -= 128;
132 goto again;
133 }
134 *op++ = (tidataval_t)(-(n-1)); /* encode run */
135 *op++ = b;
136 } else { /* extend literal */
137 if (++(*lastliteral) == 127)
138 state = BASE;
139 *op++ = b;
140 }
141 break;
142 case RUN: /* last object was run */
143 if (n > 1) {
144 if (n > 128) {
145 *op++ = (tidata) -127;
146 *op++ = b;
147 n -= 128;
148 goto again;
149 }
150 *op++ = (tidataval_t)(-(n-1));
151 *op++ = b;
152 } else {
153 lastliteral = op;
154 *op++ = 0;
155 *op++ = b;
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 */
615a9936 188static int LINKAGEMODE
b47c832e
RR
189PackBitsEncodeChunk(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
190{
191 tsize_t rowsize = (tsize_t) tif->tif_data;
192
193 assert(rowsize > 0);
194 while ((long)cc > 0) {
195 if (PackBitsEncode(tif, bp, rowsize, s) < 0)
196 return (-1);
197 bp += rowsize;
198 cc -= rowsize;
199 }
200 return (1);
201}
202
615a9936 203static int LINKAGEMODE
b47c832e
RR
204PackBitsDecode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s)
205{
206 char *bp;
207 tsize_t cc;
208 long n;
209 int b;
210
211 (void) s;
212 bp = (char*) tif->tif_rawcp;
213 cc = tif->tif_rawcc;
214 while (cc > 0 && (long)occ > 0) {
215 n = (long) *bp++, cc--;
216 /*
217 * Watch out for compilers that
218 * don't sign extend chars...
219 */
220 if (n >= 128)
221 n -= 256;
222 if (n < 0) { /* replicate next byte -n+1 times */
223 if (n == -128) /* nop */
224 continue;
225 n = -n + 1;
226 occ -= n;
227 b = *bp++, cc--;
228 while (n-- > 0)
229 *op++ = b;
230 } else { /* copy next n+1 bytes literally */
231 _TIFFmemcpy(op, bp, ++n);
232 op += n; occ -= n;
233 bp += n; cc -= n;
234 }
235 }
236 tif->tif_rawcp = (tidata_t) bp;
237 tif->tif_rawcc = cc;
238 if (occ > 0) {
239 TIFFError(tif->tif_name,
240 "PackBitsDecode: Not enough data for scanline %ld",
241 (long) tif->tif_row);
242 return (0);
243 }
244 /* check for buffer overruns? */
245 return (1);
246}
247
248int
249TIFFInitPackBits(TIFF* tif, int scheme)
250{
251 (void) scheme;
252 tif->tif_decoderow = PackBitsDecode;
253 tif->tif_decodestrip = PackBitsDecode;
254 tif->tif_decodetile = PackBitsDecode;
255 tif->tif_preencode = PackBitsPreEncode;
256 tif->tif_encoderow = PackBitsEncode;
257 tif->tif_encodestrip = PackBitsEncodeChunk;
258 tif->tif_encodetile = PackBitsEncodeChunk;
259 return (1);
260}
261#endif /* PACKBITS_SUPPORT */