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