1 /*
2  * Copyright (c) 1988-1997 Sam Leffler
3  * Copyright (c) 1991-1997 Silicon Graphics, Inc.
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and
6  * its documentation for any purpose is hereby granted without fee, provided
7  * that (i) the above copyright notices and this permission notice appear in
8  * all copies of the software and related documentation, and (ii) the names of
9  * Sam Leffler and Silicon Graphics may not be used in any advertising or
10  * publicity relating to the software without the specific, prior written
11  * permission of Sam Leffler and Silicon Graphics.
12  *
13  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
14  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
15  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
18  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
19  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
21  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22  * OF THIS SOFTWARE.
23  */
24 
25 #include "tiffiop.h"
26 #ifdef PACKBITS_SUPPORT
27 /*
28  * TIFF Library.
29  *
30  * PackBits Compression Algorithm Support
31  */
32 #include <stdio.h>
33 
34 static int
PackBitsPreEncode(TIFF * tif,uint16 s)35 PackBitsPreEncode(TIFF* tif, uint16 s)
36 {
37 	(void) s;
38 
39         tif->tif_data = (uint8*)_TIFFmalloc(sizeof(tmsize_t));
40 	if (tif->tif_data == NULL)
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
PackBitsPostEncode(TIFF * tif)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
PackBitsEncode(TIFF * tif,uint8 * buf,tmsize_t cc,uint16 s)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++;
84 		cc--;
85 		n = 1;
86 		for (; cc > 0 && b == *bp; cc--, bp++)
87 			n++;
88 	again:
89 		if (op + 2 >= ep) {		/* insure space for new data */
90 			/*
91 			 * Be careful about writing the last
92 			 * literal.  Must write up to that point
93 			 * and then copy the remainder to the
94 			 * front of the buffer.
95 			 */
96 			if (state == LITERAL || state == LITERAL_RUN) {
97 				slop = (long)(op - lastliteral);
98 				tif->tif_rawcc += (tmsize_t)(lastliteral - tif->tif_rawcp);
99 				if (!TIFFFlushData1(tif))
100 					return (0);
101 				op = tif->tif_rawcp;
102 				while (slop-- > 0)
103 					*op++ = *lastliteral++;
104 				lastliteral = tif->tif_rawcp;
105 			} else {
106 				tif->tif_rawcc += (tmsize_t)(op - tif->tif_rawcp);
107 				if (!TIFFFlushData1(tif))
108 					return (0);
109 				op = tif->tif_rawcp;
110 			}
111 		}
112 		switch (state) {
113 		case BASE:		/* initial state, set run/literal */
114 			if (n > 1) {
115 				state = RUN;
116 				if (n > 128) {
117 					*op++ = (uint8) -127;
118 					*op++ = (uint8) b;
119 					n -= 128;
120 					goto again;
121 				}
122 				*op++ = (uint8)(-(n-1));
123 				*op++ = (uint8) b;
124 			} else {
125 				lastliteral = op;
126 				*op++ = 0;
127 				*op++ = (uint8) b;
128 				state = LITERAL;
129 			}
130 			break;
131 		case LITERAL:		/* last object was literal string */
132 			if (n > 1) {
133 				state = LITERAL_RUN;
134 				if (n > 128) {
135 					*op++ = (uint8) -127;
136 					*op++ = (uint8) b;
137 					n -= 128;
138 					goto again;
139 				}
140 				*op++ = (uint8)(-(n-1));	/* encode run */
141 				*op++ = (uint8) b;
142 			} else {			/* extend literal */
143 				if (++(*lastliteral) == 127)
144 					state = BASE;
145 				*op++ = (uint8) b;
146 			}
147 			break;
148 		case RUN:		/* last object was run */
149 			if (n > 1) {
150 				if (n > 128) {
151 					*op++ = (uint8) -127;
152 					*op++ = (uint8) b;
153 					n -= 128;
154 					goto again;
155 				}
156 				*op++ = (uint8)(-(n-1));
157 				*op++ = (uint8) b;
158 			} else {
159 				lastliteral = op;
160 				*op++ = 0;
161 				*op++ = (uint8) b;
162 				state = LITERAL;
163 			}
164 			break;
165 		case LITERAL_RUN:	/* literal followed by a run */
166 			/*
167 			 * Check to see if previous run should
168 			 * be converted to a literal, in which
169 			 * case we convert literal-run-literal
170 			 * to a single literal.
171 			 */
172 			if (n == 1 && op[-2] == (uint8) -1 &&
173 			    *lastliteral < 126) {
174 				state = (((*lastliteral) += 2) == 127 ?
175 				    BASE : LITERAL);
176 				op[-2] = op[-1];	/* replicate */
177 			} else
178 				state = RUN;
179 			goto again;
180 		}
181 	}
182 	tif->tif_rawcc += (tmsize_t)(op - tif->tif_rawcp);
183 	tif->tif_rawcp = op;
184 	return (1);
185 }
186 
187 /*
188  * Encode a rectangular chunk of pixels.  We break it up
189  * into row-sized pieces to insure that encoded runs do
190  * not span rows.  Otherwise, there can be problems with
191  * the decoder if data is read, for example, by scanlines
192  * when it was encoded by strips.
193  */
194 static int
PackBitsEncodeChunk(TIFF * tif,uint8 * bp,tmsize_t cc,uint16 s)195 PackBitsEncodeChunk(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
196 {
197 	tmsize_t rowsize = *(tmsize_t*)tif->tif_data;
198 
199 	while (cc > 0) {
200 		tmsize_t chunk = rowsize;
201 
202 		if( cc < chunk )
203 		    chunk = cc;
204 
205 		if (PackBitsEncode(tif, bp, chunk, s) < 0)
206 		    return (-1);
207 		bp += chunk;
208 		cc -= chunk;
209 	}
210 	return (1);
211 }
212 
213 static int
PackBitsDecode(TIFF * tif,uint8 * op,tmsize_t occ,uint16 s)214 PackBitsDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
215 {
216 	static const char module[] = "PackBitsDecode";
217 	char *bp;
218 	tmsize_t cc;
219 	long n;
220 	int b;
221 
222 	(void) s;
223 	bp = (char*) tif->tif_rawcp;
224 	cc = tif->tif_rawcc;
225 	while (cc > 0 && occ > 0) {
226 		n = (long) *bp++;
227 		cc--;
228 		/*
229 		 * Watch out for compilers that
230 		 * don't sign extend chars...
231 		 */
232 		if (n >= 128)
233 			n -= 256;
234 		if (n < 0) {		/* replicate next byte -n+1 times */
235 			if (n == -128)	/* nop */
236 				continue;
237 			n = -n + 1;
238 			if( occ < (tmsize_t)n )
239 			{
240 				TIFFWarningExt(tif->tif_clientdata, module,
241 				    "Discarding %lu bytes to avoid buffer overrun",
242 				    (unsigned long) ((tmsize_t)n - occ));
243 				n = (long)occ;
244 			}
245 			if( cc == 0 )
246 			{
247 				TIFFWarningExt(tif->tif_clientdata, module,
248 					       "Terminating PackBitsDecode due to lack of data.");
249 				break;
250 			}
251 			occ -= n;
252 			b = *bp++;
253 			cc--;
254 			while (n-- > 0)
255 				*op++ = (uint8) b;
256 		} else {		/* copy next n+1 bytes literally */
257 			if (occ < (tmsize_t)(n + 1))
258 			{
259 				TIFFWarningExt(tif->tif_clientdata, module,
260 				    "Discarding %lu bytes to avoid buffer overrun",
261 				    (unsigned long) ((tmsize_t)n - occ + 1));
262 				n = (long)occ - 1;
263 			}
264 			if (cc < (tmsize_t) (n+1))
265 			{
266 				TIFFWarningExt(tif->tif_clientdata, module,
267 					       "Terminating PackBitsDecode due to lack of data.");
268 				break;
269 			}
270 			_TIFFmemcpy(op, bp, ++n);
271 			op += n; occ -= n;
272 			bp += n; cc -= n;
273 		}
274 	}
275 	tif->tif_rawcp = (uint8*) bp;
276 	tif->tif_rawcc = cc;
277 	if (occ > 0) {
278 		TIFFErrorExt(tif->tif_clientdata, module,
279 		    "Not enough data for scanline %lu",
280 		    (unsigned long) tif->tif_row);
281 		return (0);
282 	}
283 	return (1);
284 }
285 
286 int
TIFFInitPackBits(TIFF * tif,int scheme)287 TIFFInitPackBits(TIFF* tif, int scheme)
288 {
289 	(void) scheme;
290 	tif->tif_decoderow = PackBitsDecode;
291 	tif->tif_decodestrip = PackBitsDecode;
292 	tif->tif_decodetile = PackBitsDecode;
293 	tif->tif_preencode = PackBitsPreEncode;
294 	tif->tif_postencode = PackBitsPostEncode;
295 	tif->tif_encoderow = PackBitsEncode;
296 	tif->tif_encodestrip = PackBitsEncodeChunk;
297 	tif->tif_encodetile = PackBitsEncodeChunk;
298 	return (1);
299 }
300 #endif /* PACKBITS_SUPPORT */
301 
302 /* vim: set ts=8 sts=8 sw=8 noet: */
303 /*
304  * Local Variables:
305  * mode: c
306  * c-basic-offset: 8
307  * fill-column: 78
308  * End:
309  */
310