1 /* $Id: tif_packbits.c,v 1.13 2006/02/07 11:03:29 dron 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,tsample_t s)37 PackBitsPreEncode(TIFF* tif, tsample_t s)
38 {
39 	(void) s;
40 
41         if (!(tif->tif_data = (tidata_t)_TIFFmalloc(sizeof(tsize_t))))
42 		return (0);
43 	/*
44 	 * Calculate the scanline/tile-width size in bytes.
45 	 */
46 	if (isTiled(tif))
47 		*(tsize_t*)tif->tif_data = TIFFTileRowSize(tif);
48 	else
49 		*(tsize_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  * NB: tidata is the type representing *(tidata_t);
63  *     if tidata_t is made signed then this type must
64  *     be adjusted accordingly.
65  */
66 typedef unsigned char tidata;
67 
68 /*
69  * Encode a run of pixels.
70  */
71 static int
PackBitsEncode(TIFF * tif,tidata_t buf,tsize_t cc,tsample_t s)72 PackBitsEncode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s)
73 {
74 	unsigned char* bp = (unsigned char*) buf;
75 	tidata_t op, ep, lastliteral;
76 	long n, slop;
77 	int b;
78 	enum { BASE, LITERAL, RUN, LITERAL_RUN } state;
79 
80 	(void) s;
81 	op = tif->tif_rawcp;
82 	ep = tif->tif_rawdata + tif->tif_rawdatasize;
83 	state = BASE;
84 	lastliteral = 0;
85 	while (cc > 0) {
86 		/*
87 		 * Find the longest string of identical bytes.
88 		 */
89 		b = *bp++, cc--, n = 1;
90 		for (; cc > 0 && b == *bp; cc--, bp++)
91 			n++;
92 	again:
93 		if (op + 2 >= ep) {		/* insure space for new data */
94 			/*
95 			 * Be careful about writing the last
96 			 * literal.  Must write up to that point
97 			 * and then copy the remainder to the
98 			 * front of the buffer.
99 			 */
100 			if (state == LITERAL || state == LITERAL_RUN) {
101 				slop = op - lastliteral;
102 				tif->tif_rawcc += lastliteral - tif->tif_rawcp;
103 				if (!TIFFFlushData1(tif))
104 					return (-1);
105 				op = tif->tif_rawcp;
106 				while (slop-- > 0)
107 					*op++ = *lastliteral++;
108 				lastliteral = tif->tif_rawcp;
109 			} else {
110 				tif->tif_rawcc += op - tif->tif_rawcp;
111 				if (!TIFFFlushData1(tif))
112 					return (-1);
113 				op = tif->tif_rawcp;
114 			}
115 		}
116 		switch (state) {
117 		case BASE:		/* initial state, set run/literal */
118 			if (n > 1) {
119 				state = RUN;
120 				if (n > 128) {
121 					*op++ = (tidata) -127;
122 					*op++ = (tidataval_t) b;
123 					n -= 128;
124 					goto again;
125 				}
126 				*op++ = (tidataval_t)(-(n-1));
127 				*op++ = (tidataval_t) b;
128 			} else {
129 				lastliteral = op;
130 				*op++ = 0;
131 				*op++ = (tidataval_t) b;
132 				state = LITERAL;
133 			}
134 			break;
135 		case LITERAL:		/* last object was literal string */
136 			if (n > 1) {
137 				state = LITERAL_RUN;
138 				if (n > 128) {
139 					*op++ = (tidata) -127;
140 					*op++ = (tidataval_t) b;
141 					n -= 128;
142 					goto again;
143 				}
144 				*op++ = (tidataval_t)(-(n-1));	/* encode run */
145 				*op++ = (tidataval_t) b;
146 			} else {			/* extend literal */
147 				if (++(*lastliteral) == 127)
148 					state = BASE;
149 				*op++ = (tidataval_t) b;
150 			}
151 			break;
152 		case RUN:		/* last object was run */
153 			if (n > 1) {
154 				if (n > 128) {
155 					*op++ = (tidata) -127;
156 					*op++ = (tidataval_t) b;
157 					n -= 128;
158 					goto again;
159 				}
160 				*op++ = (tidataval_t)(-(n-1));
161 				*op++ = (tidataval_t) b;
162 			} else {
163 				lastliteral = op;
164 				*op++ = 0;
165 				*op++ = (tidataval_t) b;
166 				state = LITERAL;
167 			}
168 			break;
169 		case LITERAL_RUN:	/* literal followed by a run */
170 			/*
171 			 * Check to see if previous run should
172 			 * be converted to a literal, in which
173 			 * case we convert literal-run-literal
174 			 * to a single literal.
175 			 */
176 			if (n == 1 && op[-2] == (tidata) -1 &&
177 			    *lastliteral < 126) {
178 				state = (((*lastliteral) += 2) == 127 ?
179 				    BASE : LITERAL);
180 				op[-2] = op[-1];	/* replicate */
181 			} else
182 				state = RUN;
183 			goto again;
184 		}
185 	}
186 	tif->tif_rawcc += op - tif->tif_rawcp;
187 	tif->tif_rawcp = op;
188 	return (1);
189 }
190 
191 /*
192  * Encode a rectangular chunk of pixels.  We break it up
193  * into row-sized pieces to insure that encoded runs do
194  * not span rows.  Otherwise, there can be problems with
195  * the decoder if data is read, for example, by scanlines
196  * when it was encoded by strips.
197  */
198 static int
PackBitsEncodeChunk(TIFF * tif,tidata_t bp,tsize_t cc,tsample_t s)199 PackBitsEncodeChunk(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
200 {
201 	tsize_t rowsize = *(tsize_t*)tif->tif_data;
202 
203 	while ((long)cc > 0) {
204 		int	chunk = rowsize;
205 
206 		if( cc < chunk )
207 		    chunk = cc;
208 
209 		if (PackBitsEncode(tif, bp, chunk, s) < 0)
210 		    return (-1);
211 		bp += chunk;
212 		cc -= chunk;
213 	}
214 	return (1);
215 }
216 
217 static int
PackBitsDecode(TIFF * tif,tidata_t op,tsize_t occ,tsample_t s)218 PackBitsDecode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s)
219 {
220 	char *bp;
221 	tsize_t cc;
222 	long n;
223 	int b;
224 
225 	(void) s;
226 	bp = (char*) tif->tif_rawcp;
227 	cc = tif->tif_rawcc;
228 	while (cc > 0 && (long)occ > 0) {
229 		n = (long) *bp++, cc--;
230 		/*
231 		 * Watch out for compilers that
232 		 * don't sign extend chars...
233 		 */
234 		if (n >= 128)
235 			n -= 256;
236 		if (n < 0) {		/* replicate next byte -n+1 times */
237 			if (n == -128)	/* nop */
238 				continue;
239                         n = -n + 1;
240                         if( occ < n )
241                         {
242 							TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
243                                         "PackBitsDecode: discarding %d bytes "
244                                         "to avoid buffer overrun",
245                                         n - occ);
246                             n = occ;
247                         }
248 			occ -= n;
249 			b = *bp++, cc--;
250 			while (n-- > 0)
251 				*op++ = (tidataval_t) b;
252 		} else {		/* copy next n+1 bytes literally */
253 			if (occ < n + 1)
254                         {
255                             TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
256                                         "PackBitsDecode: discarding %d bytes "
257                                         "to avoid buffer overrun",
258                                         n - occ + 1);
259                             n = occ - 1;
260                         }
261                         _TIFFmemcpy(op, bp, ++n);
262 			op += n; occ -= n;
263 			bp += n; cc -= n;
264 		}
265 	}
266 	tif->tif_rawcp = (tidata_t) bp;
267 	tif->tif_rawcc = cc;
268 	if (occ > 0) {
269 		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
270 		    "PackBitsDecode: Not enough data for scanline %ld",
271 		    (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