roentgen b75cab
/* $Id: tif_packbits.c,v 1.22 2012-06-20 05:25:33 fwarmerdam Exp $ */
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Copyright (c) 1988-1997 Sam Leffler
roentgen b75cab
 * Copyright (c) 1991-1997 Silicon Graphics, Inc.
roentgen b75cab
 *
roentgen b75cab
 * Permission to use, copy, modify, distribute, and sell this software and 
roentgen b75cab
 * its documentation for any purpose is hereby granted without fee, provided
roentgen b75cab
 * that (i) the above copyright notices and this permission notice appear in
roentgen b75cab
 * all copies of the software and related documentation, and (ii) the names of
roentgen b75cab
 * Sam Leffler and Silicon Graphics may not be used in any advertising or
roentgen b75cab
 * publicity relating to the software without the specific, prior written
roentgen b75cab
 * permission of Sam Leffler and Silicon Graphics.
roentgen b75cab
 * 
roentgen b75cab
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
roentgen b75cab
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
roentgen b75cab
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
roentgen b75cab
 * 
roentgen b75cab
 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
roentgen b75cab
 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
roentgen b75cab
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
roentgen b75cab
 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
roentgen b75cab
 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
roentgen b75cab
 * OF THIS SOFTWARE.
roentgen b75cab
 */
roentgen b75cab
roentgen b75cab
#include "tiffiop.h"
roentgen b75cab
#ifdef PACKBITS_SUPPORT
roentgen b75cab
/*
roentgen b75cab
 * TIFF Library.
roentgen b75cab
 *
roentgen b75cab
 * PackBits Compression Algorithm Support
roentgen b75cab
 */
roentgen b75cab
#include <stdio.h></stdio.h>
roentgen b75cab
roentgen b75cab
static int
roentgen b75cab
PackBitsPreEncode(TIFF* tif, uint16 s)
roentgen b75cab
{
roentgen b75cab
	(void) s;
roentgen b75cab
roentgen b75cab
	if (!(tif->tif_data = (uint8*)_TIFFmalloc(sizeof(tmsize_t))))
roentgen b75cab
		return (0);
roentgen b75cab
	/*
roentgen b75cab
	 * Calculate the scanline/tile-width size in bytes.
roentgen b75cab
	 */
roentgen b75cab
	if (isTiled(tif))
roentgen b75cab
		*(tmsize_t*)tif->tif_data = TIFFTileRowSize(tif);
roentgen b75cab
	else
roentgen b75cab
		*(tmsize_t*)tif->tif_data = TIFFScanlineSize(tif);
roentgen b75cab
	return (1);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
static int
roentgen b75cab
PackBitsPostEncode(TIFF* tif)
roentgen b75cab
{
roentgen b75cab
        if (tif->tif_data)
roentgen b75cab
            _TIFFfree(tif->tif_data);
roentgen b75cab
	return (1);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Encode a run of pixels.
roentgen b75cab
 */
roentgen b75cab
static int
roentgen b75cab
PackBitsEncode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s)
roentgen b75cab
{
roentgen b75cab
	unsigned char* bp = (unsigned char*) buf;
roentgen b75cab
	uint8* op;
roentgen b75cab
	uint8* ep;
roentgen b75cab
	uint8* lastliteral;
roentgen b75cab
	long n, slop;
roentgen b75cab
	int b;
roentgen b75cab
	enum { BASE, LITERAL, RUN, LITERAL_RUN } state;
roentgen b75cab
roentgen b75cab
	(void) s;
roentgen b75cab
	op = tif->tif_rawcp;
roentgen b75cab
	ep = tif->tif_rawdata + tif->tif_rawdatasize;
roentgen b75cab
	state = BASE;
roentgen b75cab
	lastliteral = 0;
roentgen b75cab
	while (cc > 0) {
roentgen b75cab
		/*
roentgen b75cab
		 * Find the longest string of identical bytes.
roentgen b75cab
		 */
roentgen b75cab
		b = *bp++, cc--, n = 1;
roentgen b75cab
		for (; cc > 0 && b == *bp; cc--, bp++)
roentgen b75cab
			n++;
roentgen b75cab
	again:
roentgen b75cab
		if (op + 2 >= ep) {		/* insure space for new data */
roentgen b75cab
			/*
roentgen b75cab
			 * Be careful about writing the last
roentgen b75cab
			 * literal.  Must write up to that point
roentgen b75cab
			 * and then copy the remainder to the
roentgen b75cab
			 * front of the buffer.
roentgen b75cab
			 */
roentgen b75cab
			if (state == LITERAL || state == LITERAL_RUN) {
roentgen b75cab
				slop = (long)(op - lastliteral);
roentgen b75cab
				tif->tif_rawcc += (tmsize_t)(lastliteral - tif->tif_rawcp);
roentgen b75cab
				if (!TIFFFlushData1(tif))
roentgen b75cab
					return (-1);
roentgen b75cab
				op = tif->tif_rawcp;
roentgen b75cab
				while (slop-- > 0)
roentgen b75cab
					*op++ = *lastliteral++;
roentgen b75cab
				lastliteral = tif->tif_rawcp;
roentgen b75cab
			} else {
roentgen b75cab
				tif->tif_rawcc += (tmsize_t)(op - tif->tif_rawcp);
roentgen b75cab
				if (!TIFFFlushData1(tif))
roentgen b75cab
					return (-1);
roentgen b75cab
				op = tif->tif_rawcp;
roentgen b75cab
			}
roentgen b75cab
		}
roentgen b75cab
		switch (state) {
roentgen b75cab
		case BASE:		/* initial state, set run/literal */
roentgen b75cab
			if (n > 1) {
roentgen b75cab
				state = RUN;
roentgen b75cab
				if (n > 128) {
roentgen b75cab
					*op++ = (uint8) -127;
roentgen b75cab
					*op++ = (uint8) b;
roentgen b75cab
					n -= 128;
roentgen b75cab
					goto again;
roentgen b75cab
				}
roentgen b75cab
				*op++ = (uint8)(-(n-1));
roentgen b75cab
				*op++ = (uint8) b;
roentgen b75cab
			} else {
roentgen b75cab
				lastliteral = op;
roentgen b75cab
				*op++ = 0;
roentgen b75cab
				*op++ = (uint8) b;
roentgen b75cab
				state = LITERAL;
roentgen b75cab
			}
roentgen b75cab
			break;
roentgen b75cab
		case LITERAL:		/* last object was literal string */
roentgen b75cab
			if (n > 1) {
roentgen b75cab
				state = LITERAL_RUN;
roentgen b75cab
				if (n > 128) {
roentgen b75cab
					*op++ = (uint8) -127;
roentgen b75cab
					*op++ = (uint8) b;
roentgen b75cab
					n -= 128;
roentgen b75cab
					goto again;
roentgen b75cab
				}
roentgen b75cab
				*op++ = (uint8)(-(n-1));	/* encode run */
roentgen b75cab
				*op++ = (uint8) b;
roentgen b75cab
			} else {			/* extend literal */
roentgen b75cab
				if (++(*lastliteral) == 127)
roentgen b75cab
					state = BASE;
roentgen b75cab
				*op++ = (uint8) b;
roentgen b75cab
			}
roentgen b75cab
			break;
roentgen b75cab
		case RUN:		/* last object was run */
roentgen b75cab
			if (n > 1) {
roentgen b75cab
				if (n > 128) {
roentgen b75cab
					*op++ = (uint8) -127;
roentgen b75cab
					*op++ = (uint8) b;
roentgen b75cab
					n -= 128;
roentgen b75cab
					goto again;
roentgen b75cab
				}
roentgen b75cab
				*op++ = (uint8)(-(n-1));
roentgen b75cab
				*op++ = (uint8) b;
roentgen b75cab
			} else {
roentgen b75cab
				lastliteral = op;
roentgen b75cab
				*op++ = 0;
roentgen b75cab
				*op++ = (uint8) b;
roentgen b75cab
				state = LITERAL;
roentgen b75cab
			}
roentgen b75cab
			break;
roentgen b75cab
		case LITERAL_RUN:	/* literal followed by a run */
roentgen b75cab
			/*
roentgen b75cab
			 * Check to see if previous run should
roentgen b75cab
			 * be converted to a literal, in which
roentgen b75cab
			 * case we convert literal-run-literal
roentgen b75cab
			 * to a single literal.
roentgen b75cab
			 */
roentgen b75cab
			if (n == 1 && op[-2] == (uint8) -1 &&
roentgen b75cab
			    *lastliteral < 126) {
roentgen b75cab
				state = (((*lastliteral) += 2) == 127 ?
roentgen b75cab
				    BASE : LITERAL);
roentgen b75cab
				op[-2] = op[-1];	/* replicate */
roentgen b75cab
			} else
roentgen b75cab
				state = RUN;
roentgen b75cab
			goto again;
roentgen b75cab
		}
roentgen b75cab
	}
roentgen b75cab
	tif->tif_rawcc += (tmsize_t)(op - tif->tif_rawcp);
roentgen b75cab
	tif->tif_rawcp = op;
roentgen b75cab
	return (1);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Encode a rectangular chunk of pixels.  We break it up
roentgen b75cab
 * into row-sized pieces to insure that encoded runs do
roentgen b75cab
 * not span rows.  Otherwise, there can be problems with
roentgen b75cab
 * the decoder if data is read, for example, by scanlines
roentgen b75cab
 * when it was encoded by strips.
roentgen b75cab
 */
roentgen b75cab
static int
roentgen b75cab
PackBitsEncodeChunk(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
roentgen b75cab
{
roentgen b75cab
	tmsize_t rowsize = *(tmsize_t*)tif->tif_data;
roentgen b75cab
roentgen b75cab
	while (cc > 0) {
roentgen b75cab
		tmsize_t chunk = rowsize;
roentgen b75cab
		
roentgen b75cab
		if( cc < chunk )
roentgen b75cab
		    chunk = cc;
roentgen b75cab
roentgen b75cab
		if (PackBitsEncode(tif, bp, chunk, s) < 0)
roentgen b75cab
		    return (-1);
roentgen b75cab
		bp += chunk;
roentgen b75cab
		cc -= chunk;
roentgen b75cab
	}
roentgen b75cab
	return (1);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
static int
roentgen b75cab
PackBitsDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
roentgen b75cab
{
roentgen b75cab
	static const char module[] = "PackBitsDecode";
roentgen b75cab
	char *bp;
roentgen b75cab
	tmsize_t cc;
roentgen b75cab
	long n;
roentgen b75cab
	int b;
roentgen b75cab
roentgen b75cab
	(void) s;
roentgen b75cab
	bp = (char*) tif->tif_rawcp;
roentgen b75cab
	cc = tif->tif_rawcc;
roentgen b75cab
	while (cc > 0 && occ > 0) {
roentgen b75cab
		n = (long) *bp++, cc--;
roentgen b75cab
		/*
roentgen b75cab
		 * Watch out for compilers that
roentgen b75cab
		 * don't sign extend chars...
roentgen b75cab
		 */
roentgen b75cab
		if (n >= 128)
roentgen b75cab
			n -= 256;
roentgen b75cab
		if (n < 0) {		/* replicate next byte -n+1 times */
roentgen b75cab
			if (n == -128)	/* nop */
roentgen b75cab
				continue;
roentgen b75cab
			n = -n + 1;
roentgen b75cab
			if( occ < (tmsize_t)n )
roentgen b75cab
			{
roentgen b75cab
				TIFFWarningExt(tif->tif_clientdata, module,
roentgen b75cab
				    "Discarding %lu bytes to avoid buffer overrun",
roentgen b75cab
				    (unsigned long) ((tmsize_t)n - occ));
roentgen b75cab
				n = (long)occ;
roentgen b75cab
			}
roentgen b75cab
			occ -= n;
roentgen b75cab
			b = *bp++, cc--;
roentgen b75cab
			while (n-- > 0)
roentgen b75cab
				*op++ = (uint8) b;
roentgen b75cab
		} else {		/* copy next n+1 bytes literally */
roentgen b75cab
			if (occ < (tmsize_t)(n + 1))
roentgen b75cab
			{
roentgen b75cab
				TIFFWarningExt(tif->tif_clientdata, module,
roentgen b75cab
				    "Discarding %lu bytes to avoid buffer overrun",
roentgen b75cab
				    (unsigned long) ((tmsize_t)n - occ + 1));
roentgen b75cab
				n = (long)occ - 1;
roentgen b75cab
			}
roentgen b75cab
			if (cc < (tmsize_t) (n+1)) 
roentgen b75cab
			{
roentgen b75cab
				TIFFWarningExt(tif->tif_clientdata, module,
roentgen b75cab
					       "Terminating PackBitsDecode due to lack of data.");
roentgen b75cab
				break;
roentgen b75cab
			}
roentgen b75cab
			_TIFFmemcpy(op, bp, ++n);
roentgen b75cab
			op += n; occ -= n;
roentgen b75cab
			bp += n; cc -= n;
roentgen b75cab
		}
roentgen b75cab
	}
roentgen b75cab
	tif->tif_rawcp = (uint8*) bp;
roentgen b75cab
	tif->tif_rawcc = cc;
roentgen b75cab
	if (occ > 0) {
roentgen b75cab
		TIFFErrorExt(tif->tif_clientdata, module,
roentgen b75cab
		    "Not enough data for scanline %lu",
roentgen b75cab
		    (unsigned long) tif->tif_row);
roentgen b75cab
		return (0);
roentgen b75cab
	}
roentgen b75cab
	return (1);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
int
roentgen b75cab
TIFFInitPackBits(TIFF* tif, int scheme)
roentgen b75cab
{
roentgen b75cab
	(void) scheme;
roentgen b75cab
	tif->tif_decoderow = PackBitsDecode;
roentgen b75cab
	tif->tif_decodestrip = PackBitsDecode;
roentgen b75cab
	tif->tif_decodetile = PackBitsDecode;
roentgen b75cab
	tif->tif_preencode = PackBitsPreEncode;
roentgen b75cab
	tif->tif_postencode = PackBitsPostEncode;
roentgen b75cab
	tif->tif_encoderow = PackBitsEncode;
roentgen b75cab
	tif->tif_encodestrip = PackBitsEncodeChunk;
roentgen b75cab
	tif->tif_encodetile = PackBitsEncodeChunk;
roentgen b75cab
	return (1);
roentgen b75cab
}
roentgen b75cab
#endif /* PACKBITS_SUPPORT */
roentgen b75cab
roentgen b75cab
/* vim: set ts=8 sts=8 sw=8 noet: */
roentgen b75cab
/*
roentgen b75cab
 * Local Variables:
roentgen b75cab
 * mode: c
roentgen b75cab
 * c-basic-offset: 8
roentgen b75cab
 * fill-column: 78
roentgen b75cab
 * End:
roentgen b75cab
 */