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 
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--;
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 			if (cc < (tmsize_t) (n+1))
256 			{
257 				TIFFWarningExt(tif->tif_clientdata, module,
258 					       "Terminating PackBitsDecode due to lack of data.");
259 				break;
260 			}
261 			_TIFFmemcpy(op, bp, ++n);
262 			op += n; occ -= n;
263 			bp += n; cc -= n;
264 		}
265 	}
266 	tif->tif_rawcp = (uint8*) bp;
267 	tif->tif_rawcc = cc;
268 	if (occ > 0) {
269 		TIFFErrorExt(tif->tif_clientdata, module,
270 		    "Not enough data for scanline %lu",
271 		    (unsigned long) tif->tif_row);
272 		return (0);
273 	}
274 	return (1);
275 }
276 
277 int
TIFFInitPackBits(TIFF * tif,int scheme)278 TIFFInitPackBits(TIFF* tif, int scheme)
279 {
280 	(void) scheme;
281 	tif->tif_decoderow = PackBitsDecode;
282 	tif->tif_decodestrip = PackBitsDecode;
283 	tif->tif_decodetile = PackBitsDecode;
284 	tif->tif_preencode = PackBitsPreEncode;
285 	tif->tif_postencode = PackBitsPostEncode;
286 	tif->tif_encoderow = PackBitsEncode;
287 	tif->tif_encodestrip = PackBitsEncodeChunk;
288 	tif->tif_encodetile = PackBitsEncodeChunk;
289 	return (1);
290 }
291 #endif /* PACKBITS_SUPPORT */
292 
293 /* vim: set ts=8 sts=8 sw=8 noet: */
294 /*
295  * Local Variables:
296  * mode: c
297  * c-basic-offset: 8
298  * fill-column: 78
299  * End:
300  */
301