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