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