Home | History | Annotate | Download | only in libtiff
      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
     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
     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
     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
    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
    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
    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