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
PackBitsPreEncode(TIFF * tif,uint16 s)37 PackBitsPreEncode(TIFF* tif, uint16 s)
38 {
39     (void) s;
40 
41     if (!(tif->tif_data = (uint8*)_TIFFmalloc(sizeof(tmsize_t))))
42         return (0);
43     /*
44      * Calculate the scanline/tile-width size in bytes.
45      */
46     if (isTiled(tif))
47         *(tmsize_t*)tif->tif_data = TIFFTileRowSize(tif);
48     else
49         *(tmsize_t*)tif->tif_data = TIFFScanlineSize(tif);
50     return (1);
51 }
52 
53 static int
PackBitsPostEncode(TIFF * tif)54 PackBitsPostEncode(TIFF* tif)
55 {
56         if (tif->tif_data)
57             _TIFFfree(tif->tif_data);
58     return (1);
59 }
60 
61 /*
62  * Encode a run of pixels.
63  */
64 static int
PackBitsEncode(TIFF * tif,uint8 * buf,tmsize_t cc,uint16 s)65 PackBitsEncode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s)
66 {
67     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     op = tif->tif_rawcp;
77     ep = tif->tif_rawdata + tif->tif_rawdatasize;
78     state = BASE;
79     lastliteral = 0;
80     while (cc > 0) {
81         /*
82          * Find the longest string of identical bytes.
83          */
84         b = *bp++, cc--, n = 1;
85         for (; cc > 0 && b == *bp; cc--, bp++)
86             n++;
87     again:
88         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             if (state == LITERAL || state == LITERAL_RUN) {
96                 slop = (long)(op - lastliteral);
97                 tif->tif_rawcc += (tmsize_t)(lastliteral - tif->tif_rawcp);
98                 if (!TIFFFlushData1(tif))
99                     return (-1);
100                 op = tif->tif_rawcp;
101                 while (slop-- > 0)
102                     *op++ = *lastliteral++;
103                 lastliteral = tif->tif_rawcp;
104             } else {
105                 tif->tif_rawcc += (tmsize_t)(op - tif->tif_rawcp);
106                 if (!TIFFFlushData1(tif))
107                     return (-1);
108                 op = tif->tif_rawcp;
109             }
110         }
111         switch (state) {
112         case BASE:		/* initial state, set run/literal */
113             if (n > 1) {
114                 state = RUN;
115                 if (n > 128) {
116                     *op++ = (uint8) -127;
117                     *op++ = (uint8) b;
118                     n -= 128;
119                     goto again;
120                 }
121                 *op++ = (uint8)(-(n-1));
122                 *op++ = (uint8) b;
123             } else {
124                 lastliteral = op;
125                 *op++ = 0;
126                 *op++ = (uint8) b;
127                 state = LITERAL;
128             }
129             break;
130         case LITERAL:		/* last object was literal string */
131             if (n > 1) {
132                 state = LITERAL_RUN;
133                 if (n > 128) {
134                     *op++ = (uint8) -127;
135                     *op++ = (uint8) b;
136                     n -= 128;
137                     goto again;
138                 }
139                 *op++ = (uint8)(-(n-1));	/* encode run */
140                 *op++ = (uint8) b;
141             } else {			/* extend literal */
142                 if (++(*lastliteral) == 127)
143                     state = BASE;
144                 *op++ = (uint8) b;
145             }
146             break;
147         case RUN:		/* last object was run */
148             if (n > 1) {
149                 if (n > 128) {
150                     *op++ = (uint8) -127;
151                     *op++ = (uint8) b;
152                     n -= 128;
153                     goto again;
154                 }
155                 *op++ = (uint8)(-(n-1));
156                 *op++ = (uint8) b;
157             } else {
158                 lastliteral = op;
159                 *op++ = 0;
160                 *op++ = (uint8) b;
161                 state = LITERAL;
162             }
163             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             if (n == 1 && op[-2] == (uint8) -1 &&
172                 *lastliteral < 126) {
173                 state = (((*lastliteral) += 2) == 127 ?
174                     BASE : LITERAL);
175                 op[-2] = op[-1];	/* replicate */
176             } else
177                 state = RUN;
178             goto again;
179         }
180     }
181     tif->tif_rawcc += (tmsize_t)(op - tif->tif_rawcp);
182     tif->tif_rawcp = op;
183     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
PackBitsEncodeChunk(TIFF * tif,uint8 * bp,tmsize_t cc,uint16 s)194 PackBitsEncodeChunk(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
195 {
196     tmsize_t rowsize = *(tmsize_t*)tif->tif_data;
197 
198     while (cc > 0) {
199         tmsize_t chunk = rowsize;
200 
201         if( cc < chunk )
202             chunk = cc;
203 
204         if (PackBitsEncode(tif, bp, chunk, s) < 0)
205             return (-1);
206         bp += chunk;
207         cc -= chunk;
208     }
209     return (1);
210 }
211 
212 static int
PackBitsDecode(TIFF * tif,uint8 * op,tmsize_t occ,uint16 s)213 PackBitsDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
214 {
215     static const char module[] = "PackBitsDecode";
216     char *bp;
217     tmsize_t cc;
218     long n;
219     int b;
220 
221     (void) s;
222     bp = (char*) tif->tif_rawcp;
223     cc = tif->tif_rawcc;
224     while (cc > 0 && occ > 0) {
225         n = (long) *bp++, cc--;
226         /*
227          * Watch out for compilers that
228          * don't sign extend chars...
229          */
230         if (n >= 128)
231             n -= 256;
232         if (n < 0) {		/* replicate next byte -n+1 times */
233             if (n == -128)	/* nop */
234                 continue;
235             n = -n + 1;
236             if( occ < (tmsize_t)n )
237             {
238                 TIFFWarningExt(tif->tif_clientdata, module,
239                     "Discarding %lu bytes to avoid buffer overrun",
240                     (unsigned long) ((tmsize_t)n - occ));
241                 n = (long)occ;
242             }
243             occ -= n;
244             b = *bp++, cc--;      /* TODO: may be reading past input buffer here when input data is corrupt or ends prematurely */
245             while (n-- > 0)
246                 *op++ = (uint8) b;
247         } else {		/* copy next n+1 bytes literally */
248             if (occ < (tmsize_t)(n + 1))
249             {
250                 TIFFWarningExt(tif->tif_clientdata, module,
251                     "Discarding %lu bytes to avoid buffer overrun",
252                     (unsigned long) ((tmsize_t)n - occ + 1));
253                 n = (long)occ - 1;
254             }
255             _TIFFmemcpy(op, bp, ++n);  /* TODO: may be reading past input buffer here when input data is corrupt or ends prematurely */
256             op += n; occ -= n;
257             bp += n; cc -= n;
258         }
259     }
260     tif->tif_rawcp = (uint8*) bp;
261     tif->tif_rawcc = cc;
262     if (occ > 0) {
263         TIFFErrorExt(tif->tif_clientdata, module,
264             "Not enough data for scanline %lu",
265             (unsigned long) tif->tif_row);
266         return (0);
267     }
268     return (1);
269 }
270 
271 int
TIFFInitPackBits(TIFF * tif,int scheme)272 TIFFInitPackBits(TIFF* tif, int scheme)
273 {
274     (void) scheme;
275     tif->tif_decoderow = PackBitsDecode;
276     tif->tif_decodestrip = PackBitsDecode;
277     tif->tif_decodetile = PackBitsDecode;
278     tif->tif_preencode = PackBitsPreEncode;
279     tif->tif_postencode = PackBitsPostEncode;
280     tif->tif_encoderow = PackBitsEncode;
281     tif->tif_encodestrip = PackBitsEncodeChunk;
282     tif->tif_encodetile = PackBitsEncodeChunk;
283     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  */
295