jedi-outcast/utils/roq2/libim/imlzw.c

2171 lines
30 KiB
C

/**
** $Header: /roq/libim/imlzw.c 1 11/02/99 4:38p Zaphod $
** Copyright (c) 1989-1995 San Diego Supercomputer Center (SDSC)
** a division of General Atomics, San Diego, California, USA
**
** Users and possessors of this source code are hereby granted a
** nonexclusive, royalty-free copyright and design patent license to
** use this code in individual software. License is not granted for
** commercial resale, in whole or in part, without prior written
** permission from SDSC. This source is provided "AS IS" without express
** or implied warranty of any kind.
**
** For further information contact:
** E-Mail: info@sds.sdsc.edu
**
** Surface Mail: Information Center
** San Diego Supercomputer Center
** P.O. Box 85608
** San Diego, CA 92138-5608
** (619) 534-5000
**/
#define HEADER " $Header: /roq/libim/imlzw.c 1 11/02/99 4:38p Zaphod $"
/**
** FILE
** imlzw.c - Do Lempel-Ziv & Welch uncompress/compress
**
** PROJECT
** libim - SDSC image manipulation library
**
** DESCRIPTION
** imlzw.c contains rountines for decoding and encoding byte buffers
** using Lempel-Ziv & Welch uncompress/compress algorithm.
**
** PUBLIC CONTENTS
** d =defined constant
** f =function
** m =defined macro
** t =typedef/struct/union
** v =variable
** ? =other
**
** ImLzwPreDecode f Set up for lzw uncompress
** ImLzwDecode f Do uncompression
** ImLzwPostDecode f Clean up after lzw uncompress
**
** ImLzwPreEncode f Set up for lzw compress
** ImLzwEncode f Do compression
** ImLzwPostEncode f Clean up after lzw compress
**
**
**
** PRIVATE CONTENTS
** NULL d an empty pointer
**
** imLzwGetNextCode f Get the next compression code from buf
** imLzwPutNextCode f Put the next compression code to output
** imLzwWriteData f Write compressed pixels to output
** imLzwClearBlock f Check the compression ration, poss reset
** imLzwClearHash f Reset the compression hash table
** imLzwCleanUp f Clean up storage at the end
**
** HISTORY
** $Log: /roq/libim/imlzw.c $
*
* 1 11/02/99 4:38p Zaphod
** Revision 1.8 1995/06/29 00:28:04 bduggan
** updated copyright year
**
** Revision 1.7 1995/06/29 00:19:56 bduggan
** added some casts
**
** Revision 1.6 1994/10/03 11:29:40 nadeau
** Updated to ANSI C and C++ compatibility.
** Removed all use of register keyword.
** Minimized use of custom SDSC types (e.g., uchar vs. unsigned char)
** Changed all float arguments to double.
** Added forward declarations.
** Added misc. casts to passify SGI and DEC compilers.
** Changed all macros and defined constants to have names
** starting with IM.
** Updated comments.
** Updated indenting on some code.
** Updated copyright message.
**
** Revision 1.6 1994/10/03 11:29:40 nadeau
** Updated to ANSI C and C++ compatibility.
** Removed all use of register keyword.
** Minimized use of custom SDSC types (e.g., uchar vs. unsigned char)
** Changed all float arguments to double.
** Added forward declarations.
** Added misc. casts to passify SGI and DEC compilers.
** Changed all macros and defined constants to have names
** starting with IM.
** Updated comments.
** Updated indenting on some code.
** Updated copyright message.
**
** Revision 1.5 92/08/31 17:27:42 vle
** Updated copyright notice.
**
** Revision 1.4 92/04/09 09:33:46 groening
** To make the compiler happy added extern statements.
**
** Revision 1.3 91/10/03 09:14:06 todd
** Updated to match TIFF 5.0 spec.
**
** Revision 1.2 91/03/15 11:23:47 todd
** added return( 0 ) statements
**
** Revision 1.1 91/01/29 11:09:24 todd
** Initial revision
**
**
**
**/
/*
* Copyright (c) 1988 by Sam Leffler.
* All rights reserved.
*
* This file is provided for unrestricted use provided that this
* legend is included on all tape media and as a part of the
* software program in whole or part. Users may copy, modify or
* distribute this file at will.
*/
/*
* Rev 5.0 Lempel-Ziv & Welch Compression Support
*
* This code is derived from the compress program whose code is
* derived from software contributed to Berkeley by James A. Woods,
* derived from original work by Spencer Thomas and Joseph Orost.
*
* The original Berkeley copyright notice appears below in its entirety.
*/
/*
* Copyright (c) 1985, 1986 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* James A. Woods, derived from original work by Spencer Thomas
* and Joseph Orost.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without imLzwSpecific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#include <stdio.h>
#include "iminternal.h"
#ifdef __STDC__
static int imLzwGetNextCode(unsigned char *buf);
static int imLzwPutNextCode( int ioType, int fd, FILE *fp, int c);
static int imLzwClearBlock( int ioType, int fd, FILE *fp);
static int imLzwWriteData( int ioType, int fd, FILE *fp );
#else
static int imLzwGetNextCode( );
static int imLzwPutNextCode( );
static int imLzwClearBlock( );
static int imLzwWriteData( );
#endif
/*
* MACROS
*
*
* DESCRIPTION
* Decode one scanline of pixels.
* The TIFF imLzwSpec imLzwSpecifies that encoded bit strings range
* from 9 to 12 bits. This is somewhat unfortunate in that
* experience indicates full color RGB pictures often need
* ~14 bits for reasonable compression.
*/
#define IMMAXCODE(n) ((1 << (n)) - 1)
#define IMBITS_MIN 9 /* start with 9 bits */
#define IMBITS_MAX 12 /* max of 12 bit strings */
/*
* predefined codes
*/
#define IMCODE_CLEAR 256 /* code to clear string table */
#define IMCODE_EOI 257 /* end-of-information code */
#define IMCODE_FIRST 258 /* first free code entry */
#define IMCODE_MAX IMMAXCODE(IMBITS_MAX)
#ifdef notdef
#define IMHSIZE 9001 /* 91% occupancy */
#define IMHSHIFT (8-(16-13))
#else
#define IMHSIZE 5003 /* 80% occupancy */
#define IMHSHIFT (8-(16-12))
#endif
/*
* NB: The 5.0 spec describes a different algorithm than Aldus
* implements. Specifically, Aldus does code length transitions
* one code earlier than should be done (for real LZW).
* Earlier versions of this library implemented the correct
* LZW algorithm, but emitted codes in a bit order opposite
* to the TIFF spec. Thus, to maintain compatibility w/ Aldus
* we interpret MSB-LSB ordered codes to be images written w/
* old versions of this library, but otherwise adhere to the
* Aldus "off by one" algorithm.
*
* Future revisions to the TIFF spec are expected to "clarify this issue".
*/
#define IMSETMAXCODE(sp, v) { \
(sp)->lzwMaxcode = (v)-1; \
if ((sp)->lzwFlags & IMLZW_COMPAT) \
(sp)->lzwMaxcode++; \
}
/*
* TYPEDEF & STRUCTURE
*
*
* DESCRIPTION
* Decoding and encoding imLzwSpecific state.
*/
struct decode {
short prefixtab[IMHSIZE]; /* prefix(code) */
unsigned char suffixtab[IMCODE_MAX+1]; /* suffix(code) */
unsigned char stack[IMHSIZE-(IMCODE_MAX+1)];
unsigned char *stackp; /* stack pointer */
int firstchar; /* of string associated w/ last code */
};
/*
* Encoding-imLzwSpecific state.
*/
struct encode {
int checkpoint; /* point at which to clear table */
#define IMCHECK_GAP 10000 /* enc_ratio check interval */
long ratio; /* current compression ratio */
int incount; /* (input) data bytes encoded */
int outcount; /* encoded (output) bytes */
int htab[IMHSIZE]; /* hash table */
short codetab[IMHSIZE]; /* code table */
};
/*
* State block for each open TIFF
* file using Lzw compression.
*/
typedef struct LzwState
{
int lzwOldcode; /* last code encountered */
/*new*/ unsigned char lzwHorDif; /* Undefined in 2.2 */
#define IMLZW_HORDIFF4 0x01 /* hor. diff w/ 4-bit samples */
#define IMLZW_HORDIFF8 0x02 /* hor. diff w/ 8-bit samples */
#define IMLZW_HORDIFF16 0x04 /* hor. diff w/ 16-bit samples */
#define IMLZW_HORDIFF32 0x08 /* hor. diff w/ 32-bit samples */
unsigned short lzwFlags; /* flags */
#define IMLZW_RESTART 0x01 /* restart interrupted decode */
#define IMLZW_COMPAT 0x02 /* read old bit-reversed codes */
unsigned short lzwNbits; /* number of bits/code */
/*new*/ unsigned short lzwStride; /* number of bits/code */
int lzwMaxcode; /* maximum code for lzwNbits */
int lzwBitoff; /* bit offset into data */
int lzwBitsize; /* size of strip in bits */
int lzwFree_ent; /* next free entry in hash tabl */
int lzwRawcc; /* byte count of unread/written */
int lzwBytesWritten; /* byte count of unread/written */
char *lzwRawdata; /* raw data buffer */
union {
struct decode dec;
struct encode enc;
} u;
} LzwState;
/*
* TYPEDEF & STRUCTURE
* dec & enc - shorthand structure field names
*
* DESCRIPTION
* Decoding and encoding imLzwSpecific state.
*/
#define IM_DEC_PREFIX u.dec.prefixtab
#define IM_DEC_SUFFIX u.dec.suffixtab
#define IM_DEC_STACK u.dec.stack
#define IM_DEC_STACKP u.dec.stackp
#define IM_DEC_FIRSTCHAR u.dec.firstchar
#define IM_ENC_CHECKPOINT u.enc.checkpoint
#define IM_ENC_RATIO u.enc.ratio
#define IM_ENC_INCOUNT u.enc.incount
#define IM_ENC_OUTCOUNT u.enc.outcount
#define IM_ENC_HTAB u.enc.htab
#define IM_ENC_CODETAB u.enc.codetab
/*
* TYPEDEF & STRUCTURE
*
*
* DESCRIPTION
* Decoding and encoding imLzwSpecific state.
*/
/*
* masks for extracting/inserting variable length bit codes
*/
static unsigned char rmask[9] =
{ 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
static unsigned char lmask[9] =
{ 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
/*
* Old lmask
static unsigned char lmask[9] =
{ 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00 };
*/
#ifdef __STDC__
static void imLzwClearHash(void);
#else
static void imLzwClearHash();
#endif
/*
* STRUCTURE
* imLzwSp - pointer to the global State info structure
*
* DESCRIPTION
*/
LzwState *imLzwSp=NULL;
/*
* Lzw Decoder.
*/
/*
* FUNCTION
* ImLzwPreDecode - Inititialize structures for encode/decode
*
* DESCRIPTION
* Set up the encode/decode structure
*/
int
#ifdef __STDC__
ImLzwPreDecode( unsigned char *buf, int size )
#else
ImLzwPreDecode( buf, size )
unsigned char *buf; /* Encoded bytes so we can check first 2 bytes */
int size; /* Max number of bytes to be decoded */
#endif
{
int code;
if (imLzwSp == NULL)
{
ImCalloc( imLzwSp, LzwState *, sizeof(LzwState), 1 );
imLzwSp->lzwFlags = 0;
imLzwSp->lzwHorDif = 0;
imLzwSp->lzwStride = 0;
}
else
imLzwSp->lzwFlags &= ~IMLZW_RESTART;
imLzwSp->lzwNbits = IMBITS_MIN;
/*
* Pre-load the table.
*/
for (code = 255; code >= 0; code--)
imLzwSp->IM_DEC_SUFFIX[code] = (unsigned char)code;
imLzwSp->lzwFree_ent = IMCODE_FIRST;
imLzwSp->lzwBitoff = 0;
/*
* Calculate data size in bits
*/
imLzwSp->lzwBitsize = size;
imLzwSp->lzwBitsize = (imLzwSp->lzwBitsize << 3) - (IMBITS_MAX-1);
imLzwSp->IM_DEC_STACKP = imLzwSp->IM_DEC_STACK;
imLzwSp->lzwOldcode = -1;
imLzwSp->IM_DEC_FIRSTCHAR = -1;
imLzwSp->lzwRawcc = size;
imLzwSp->lzwBytesWritten = 0;
imLzwSp->lzwRawdata = NULL;
/*
* Check for old bit-reversed codes. All the flag
* manipulations are to insure only one warning is
* given for a file.
*/
if ((buf[0] == 0) && (buf[1] & 0x1))
{
if ((imLzwSp->lzwFlags & IMLZW_COMPAT) == 0)
ImErrorWarning("Old LZW codes-converting",-1,IMESYNTAX);
imLzwSp->lzwFlags |= IMLZW_COMPAT;
} else
imLzwSp->lzwFlags &= ~IMLZW_COMPAT;
IMSETMAXCODE( imLzwSp, IMMAXCODE(IMBITS_MIN));
return (0);
}
/*
* FUNCTION
* ImLzwDecode - Decode one scanline of pixels.
*
* DESCRIPTION
* Decode one scanline of pixels.
*/
int
#ifdef __STDC__
ImLzwDecode(unsigned char *buf, char *op, int occ)
#else
ImLzwDecode(buf, op, occ)
unsigned char *buf; /* Pixels to be decoded */
char *op; /* Decoded pixels returned */
int occ;
#endif
{
int code; /* A compression code */
int retCnt=0; /* The number of bytes uncompre */
unsigned char *stackp; /* Stack pointer */
int firstchar, oldcode, incode;
stackp = imLzwSp->IM_DEC_STACKP;
/*
* Restart interrupted unstacking operations.
*/
if (imLzwSp->lzwFlags & IMLZW_RESTART)
{
do
{
if (--occ < 0) /* end of scanline */
{
imLzwSp->IM_DEC_STACKP = stackp;
return (1);
}
*op++ = *--stackp;
retCnt++;
} while (stackp > imLzwSp->IM_DEC_STACK);
imLzwSp->lzwFlags &= ~IMLZW_RESTART;
}
oldcode = imLzwSp->lzwOldcode;
firstchar = imLzwSp->IM_DEC_FIRSTCHAR;
while (occ > 0 && (code = imLzwGetNextCode(buf)) != IMCODE_EOI)
{
if (code == IMCODE_CLEAR)
{
memset(imLzwSp->IM_DEC_PREFIX, 0x00, sizeof (imLzwSp->IM_DEC_PREFIX));
imLzwSp->lzwFree_ent = IMCODE_FIRST;
imLzwSp->lzwNbits = IMBITS_MIN;
IMSETMAXCODE( imLzwSp, IMMAXCODE(IMBITS_MIN));
if ((code = imLzwGetNextCode(buf)) == IMCODE_EOI)
break;
*op++ = code, occ--;
retCnt++;
oldcode = firstchar = code;
continue;
}
incode = code;
/*
* When a code is not in the table we use (as shown):
* StringFromCode(oldcode) +
* FirstChar(StringFromCode(oldcode))
*/
if (code >= imLzwSp->lzwFree_ent) /* code not in table */
{
*stackp++ = firstchar;
code = oldcode;
}
/*
* Generate output string (first in reverse).
*/
for (; code >= 256; code = imLzwSp->IM_DEC_PREFIX[code])
*stackp++ = imLzwSp->IM_DEC_SUFFIX[code];
*stackp++ = firstchar = imLzwSp->IM_DEC_SUFFIX[code];
do
{
if (--occ < 0) /* end of scanline */
{
imLzwSp->lzwFlags |= IMLZW_RESTART;
break;
}
*op++ = *--stackp;
retCnt++;
} while (stackp > imLzwSp->IM_DEC_STACK);
/*
* Add the new entry to the code table.
*/
if ((code = imLzwSp->lzwFree_ent) < IMCODE_MAX)
{
imLzwSp->IM_DEC_PREFIX[code] = (unsigned short)oldcode;
imLzwSp->IM_DEC_SUFFIX[code] = firstchar;
imLzwSp->lzwFree_ent++;
/*
* If the next entry is too big for the
* current code size, then increase the
* size up to the maximum possible.
*/
if (imLzwSp->lzwFree_ent > imLzwSp->lzwMaxcode) {
imLzwSp->lzwNbits++;
if (imLzwSp->lzwNbits > IMBITS_MAX)
imLzwSp->lzwNbits = IMBITS_MAX;
IMSETMAXCODE(imLzwSp, IMMAXCODE(imLzwSp->lzwNbits));
}
}
oldcode = incode;
}
imLzwSp->IM_DEC_STACKP = stackp;
imLzwSp->lzwOldcode = oldcode;
imLzwSp->IM_DEC_FIRSTCHAR = firstchar;
/*
* If we were doing prediction we would have to put some
* horizontal differencing code here
*/
if (occ > 0)
ImErrorFatal("Not enough data for scanline", -1, IMENOREAD );
return ( retCnt );
}
/*
* FUNCTION
* ImLzwPostDecode - Clean up after uncompression
*
* DESCRIPTION
*
*/
int
ImLzwPostDecode()
{
return ( 1 );
}
/*
* FUNCTION
* imLzwGetNextCode - Get the next code out of the buffer
*
* DESCRIPTION
* Get the next code from the raw data buffer.
*/
static int
#ifdef __STDC__
imLzwGetNextCode(unsigned char *buf)
#else
imLzwGetNextCode(buf)
unsigned char *buf; /* Undecoded data */
#endif
{
int code, r_off, bits;
unsigned char *bp;
/*
* This check shouldn't be necessary because each
* strip is suppose to be terminated with IMCODE_EOI.
* At worst it's a substitute for the IMCODE_EOI that's
* supposed to be there (see calculation of lzwBitsize
* in LzwPreDecode()).
*/
if (imLzwSp->lzwBitoff > imLzwSp->lzwBitsize)
return (IMCODE_EOI);
r_off = imLzwSp->lzwBitoff;
bits = imLzwSp->lzwNbits;
/*
* Get to the first byte.
*/
bp = (unsigned char *)buf + (r_off >> 3);
r_off &= 7;
if (imLzwSp->lzwFlags & IMLZW_COMPAT)
{
/* Get first part (low order bits) */
code = (*bp++ >> r_off);
r_off = 8 - r_off; /* now, offset into code word */
bits -= r_off;
/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
if (bits >= 8) {
code |= *bp++ << r_off;
r_off += 8;
bits -= 8;
}
/* high order bits. */
code |= (*bp & rmask[bits]) << r_off;
}
else
{
r_off = 8 - r_off; /* convert offset to count */
code = *bp++ & rmask[r_off]; /* high order bits */
bits -= r_off;
if (bits >= 8) {
code = (code<<8) | *bp++;
bits -= 8;
}
/* low order bits */
code = (code << bits) | ((*bp & lmask[bits]) >> (8 - bits));
}
imLzwSp->lzwBitoff += imLzwSp->lzwNbits;
return (code);
}
/*
* Lzw Encoding.
*/
/*
* FUNCTION
* ImLzwPreEncode - initialize data structure
*
* DESCRIPTION
* Allocate memory and initialize values as necessary.
* Reset encoding state at the start of a strip.
*/
int
#ifdef __STDC__
ImLzwPreEncode(int size)
#else
ImLzwPreEncode(size)
int size; /* The number of bytes to be decoded */
#endif
{
if (imLzwSp == NULL)
{
ImCalloc( imLzwSp, LzwState *, sizeof(LzwState), 1 );
imLzwSp->lzwFlags = 0;
imLzwSp->lzwHorDif = 0;
imLzwSp->lzwStride = 0;
}
imLzwSp->IM_ENC_RATIO = 0;
imLzwSp->IM_ENC_CHECKPOINT = IMCHECK_GAP;
IMSETMAXCODE(imLzwSp, IMMAXCODE(imLzwSp->lzwNbits = IMBITS_MIN)+1);
imLzwSp->lzwFree_ent = IMCODE_FIRST;
imLzwSp->lzwBitoff = 0;
imLzwSp->lzwBitsize = (size << 3) - (IMBITS_MAX-1);
imLzwClearHash(); /* clear hash table */
imLzwSp->lzwOldcode = -1; /* generates IMCODE_CLEAR in LzwEncode */
imLzwSp->lzwRawcc = size;
imLzwSp->lzwBytesWritten = 0;
/*
* This is stinky. The lzw code uses a fixed size buffer to store
* the compressed data. Compressed data should be smaller so we
* allocate a buffer twice as big just in case.
*/
if (imLzwSp->lzwRawdata == NULL)
ImCalloc( imLzwSp->lzwRawdata, char *, 1, size*2 );
return( 0 );
}
/*
* FUNCTION
* imLzwEncode - Encode a scanline of pixels
*
* DESCRIPTION
* Uses an open addressing double hashing (no chaining) on the
* prefix code/next character combination. We do a variant of
* Knuth's algorithm D (vol. 3, sec. 6.4) along with G. Knott's
* relatively-prime secondary probe. Here, the modular division
* first probe is gives way to a faster exclusive-or manipulation.
* Also do block compression with an adaptive reset, whereby the
* code table is cleared when the compression ratio decreases,
* but after the table fills. The variable-length output codes
* are re-sized at this point, and a IMCODE_CLEAR is generated
* for the decoder.
*/
int
#ifdef __STDC__
ImLzwEncode(int ioType, int fd, FILE *fp, unsigned char *bp, int cc)
#else
ImLzwEncode(ioType, fd, fp, bp, cc)
int ioType; /* I/O flags */
int fd; /* Input file descriptor */
FILE *fp; /* Input file pointer */
unsigned char *bp; /* Bytes to be encoded */
int cc; /* Count of bytes to be encoded */
#endif
{
long fcode;
int h, c, ent, disp;
if ( imLzwSp == NULL )
{
ImErrorFatal("Null pointer in LZW encode", -1, IMEENCODING );
}
/*
* If we were doing prediction we would have to put some
* horizontal differencing code here
*/
ent = imLzwSp->lzwOldcode;
if (ent == -1 && cc > 0)
{
if (imLzwPutNextCode(ioType, fd, fp, IMCODE_CLEAR) == -1)
return( -1 ); /* ImErrNo already set */
ent = *bp++; cc--; imLzwSp->IM_ENC_INCOUNT++;
}
while (cc > 0)
{
c = *bp++; cc--; imLzwSp->IM_ENC_INCOUNT++;
fcode = ((long)c << IMBITS_MAX) + ent;
h = (c << IMHSHIFT) ^ ent; /* xor hashing */
if (imLzwSp->IM_ENC_HTAB[h] == fcode)
{
ent = imLzwSp->IM_ENC_CODETAB[h];
continue;
}
if (imLzwSp->IM_ENC_HTAB[h] >= 0)
{
/*
* Primary hash failed, check secondary hash.
*/
disp = IMHSIZE - h;
if (h == 0)
disp = 1;
do
{
if ((h -= disp) < 0)
h += IMHSIZE;
if (imLzwSp->IM_ENC_HTAB[h] == fcode)
{
ent = imLzwSp->IM_ENC_CODETAB[h];
goto hit;
}
} while (imLzwSp->IM_ENC_HTAB[h] >= 0);
}
/*
* New entry, add to table.
*/
if (imLzwPutNextCode(ioType, fd, fp, ent) == -1)
return( -1 ); /* ImErrNo already set */
ent = c;
imLzwSp->IM_ENC_CODETAB[h] = imLzwSp->lzwFree_ent++;
imLzwSp->IM_ENC_HTAB[h] = (int) fcode;
if (imLzwSp->lzwFree_ent == IMCODE_MAX-1) /* Table is full */
{
imLzwSp->IM_ENC_RATIO = 0;
imLzwClearHash(); /* clear hash table */
imLzwSp->lzwFree_ent = IMCODE_FIRST;
if (imLzwPutNextCode(ioType, fd, fp, IMCODE_CLEAR) == -1)
return( -1 ); /* ImErrNo already set */
IMSETMAXCODE(imLzwSp,
IMMAXCODE(imLzwSp->lzwNbits = IMBITS_MIN)+1);
}
else /* Table is not full */
{
if (imLzwSp->IM_ENC_INCOUNT >= imLzwSp->IM_ENC_CHECKPOINT)
{
if ( imLzwClearBlock( ioType, fd, fp ) == -1 )
return( -1 ); /* ImErrNo already set */
}
if (imLzwSp->lzwFree_ent > imLzwSp->lzwMaxcode)
{
imLzwSp->lzwNbits++;
if ( ! (imLzwSp->lzwNbits <= IMBITS_MAX))
{
ImErrorFatal("Nbits <= MaxBits", -1,
IMEENCODING );
}
IMSETMAXCODE(imLzwSp,
IMMAXCODE(imLzwSp->lzwNbits)+1);
}
}
hit:
;
}
imLzwSp->lzwOldcode = ent;
return ( 0 );
}
/*
* FUNCTION
* ImLzwPostEncode - Clean up after compression
*
* DESCRIPTION
* Finish off an encoded strip by flushing the last
* string and tacking on an End Of Information code.
* Returns the total number of bytes written out.
*/
int
#ifdef __STDC__
ImLzwPostEncode( int ioType, int fd, FILE *fp )
#else
ImLzwPostEncode( ioType, fd, fp )
int ioType; /* I/O flags */
int fd; /* Input file descriptor */
FILE *fp; /* Input file pointer */
#endif
{
if (imLzwSp->lzwOldcode != -1)
if (imLzwPutNextCode(ioType, fd, fp, imLzwSp->lzwOldcode) == -1)
return( -1 ); /* ImErrNo already set */
if (imLzwPutNextCode( ioType, fd, fp, IMCODE_EOI) == -1)
return( -1 ); /* ImErrNo already set */
if (imLzwWriteData( ioType, fd, fp ) == -1)
return( -1 ); /* ImErrNo already set */
return ( imLzwSp->lzwBytesWritten );
}
/*
* FUNCTION
* imLzwPutNextCode - Put the next code to output
*
* DESCRIPTION
* Put the next code to output
*/
static int
#ifdef __STDC__
imLzwPutNextCode( int ioType, int fd, FILE *fp, int c)
#else
imLzwPutNextCode( ioType, fd, fp, c)
int ioType; /* I/O flags */
int fd; /* Input file descriptor */
FILE *fp; /* Input file pointer */
int c; /* Code */
#endif
{
int r_off, bits, code = c;
char *bp;
r_off = imLzwSp->lzwBitoff;
bits = imLzwSp->lzwNbits;
/*
* Flush buffer if code doesn't fit.
*/
if (r_off + bits > imLzwSp->lzwBitsize)
{
/*
* Calculate the number of full bytes that can be
* written and save anything else for the next write.
*/
if (r_off & 7)
{
imLzwSp->lzwRawcc = r_off >> 3;
bp = imLzwSp->lzwRawdata + imLzwSp->lzwRawcc;
if (imLzwWriteData( ioType, fd, fp ) == -1)
return( -1 ); /* ImErrNo already set */
imLzwSp->lzwRawdata[0] = *bp;
}
else
{
/*
* Otherwise, on a byte boundary (in
* which lzwRawcc is already correct).
*/
if (imLzwWriteData( ioType, fd, fp ) == -1)
return( -1 ); /* ImErrNo already set */
}
bp = imLzwSp->lzwRawdata;
imLzwSp->lzwBitoff = (r_off &= 7);
}
else
{
/*
* Get to the first byte.
*/
bp = imLzwSp->lzwRawdata + (r_off >> 3);
r_off &= 7;
}
/*
* Note that lzw_bitoff is maintained as the bit offset
* into the buffer w/ a right-to-left orientation (i.e.
* lsb-to-msb). The bits, however, go in the file in
* an msb-to-lsb order.
*/
bits -= (8 - r_off);
*bp = (*bp & lmask[r_off]) | (code >> bits);
bp++;
if (bits >= 8) {
bits -= 8;
*bp++ = code >> bits;
}
if (bits)
*bp = (code & rmask[bits]) << (8 - bits);
/*
* IM_ENC_OUTCOUNT is used by the compression analysis machinery
* which resets the compression tables when the compression
* ratio goes up. lzwBitoff is used here (in imLzwPutNextCode) for
* inserting codes into the output buffer. imLzwSp_rawcc must
* be updated for the mainline write code in TIFFWriteScanline()
* so that data is flushed when the end of a strip is reached.
* Note that the latter is rounded up to ensure that a non-zero
* byte count is present.
*/
imLzwSp->IM_ENC_OUTCOUNT += imLzwSp->lzwNbits;
imLzwSp->lzwBitoff += imLzwSp->lzwNbits;
imLzwSp->lzwRawcc = (imLzwSp->lzwBitoff + 7) >> 3;
return( 0 );
}
/*
* FUNCTION
* imLzwWriteData - Write compressed data to output
*
* DESCRIPTION
* Write compressed data to output
*/
static int
#ifdef __STDC__
imLzwWriteData( int ioType, int fd, FILE *fp )
#else
imLzwWriteData( ioType, fd, fp )
int ioType; /* I/O flags */
int fd; /* Input file descriptor */
FILE *fp; /* Input file pointer */
#endif
{
if ( ImBinWrite( ioType, fd, fp,
imLzwSp->lzwRawdata, UCHAR, 1, imLzwSp->lzwRawcc ) == -1 )
ImReturnBinError( );
imLzwSp->lzwBytesWritten += imLzwSp->lzwRawcc;
imLzwSp->lzwRawcc = 0;
return( 0 );
}
/*
* FUNCTION
* imLzwClearBlock - Check compression ratio
*
* DESCRIPTION
* Check compression ratio and, if things seem to
* be slipping, clear the hash table and reset state.
*/
static int
#ifdef __STDC__
imLzwClearBlock( int ioType, int fd, FILE *fp)
#else
imLzwClearBlock( ioType, fd, fp)
int ioType; /* I/O flags */
int fd; /* Input file descriptor */
FILE *fp; /* Input file pointer */
#endif
{
long rat;
imLzwSp->IM_ENC_CHECKPOINT = imLzwSp->IM_ENC_INCOUNT + IMCHECK_GAP;
if (imLzwSp->IM_ENC_INCOUNT > 0x007fffff) /* shift will overflow */
{
rat = imLzwSp->IM_ENC_OUTCOUNT >> 8;
rat = (rat == 0 ? 0x7fffffff : imLzwSp->IM_ENC_INCOUNT / rat);
}
else /* 8 fract bits */
rat = (imLzwSp->IM_ENC_INCOUNT << 8) / imLzwSp->IM_ENC_OUTCOUNT;
if (rat <= imLzwSp->IM_ENC_RATIO)
{
imLzwSp->IM_ENC_RATIO = 0;
imLzwClearHash();
imLzwSp->lzwFree_ent = IMCODE_FIRST;
if (imLzwPutNextCode( ioType, fd, fp, IMCODE_CLEAR) == -1)
return( -1 ); /* ImErrNo already set */
IMSETMAXCODE( imLzwSp, IMMAXCODE(imLzwSp->lzwNbits = IMBITS_MIN)+1);
}
else
imLzwSp->IM_ENC_RATIO = rat;
return( 0 );
}
/*
* FUNCTION
* imClearHash - Get the next code out of the buffer
*
* DESCRIPTION
* Get the next code from the raw data buffer.
*/
/*
* Reset code table.
*/
static void
imLzwClearHash()
{
int *htab_p = imLzwSp->IM_ENC_HTAB+IMHSIZE;
int i, m1 = -1;
i = IMHSIZE - 16;
do {
*(htab_p-16) = m1;
*(htab_p-15) = m1;
*(htab_p-14) = m1;
*(htab_p-13) = m1;
*(htab_p-12) = m1;
*(htab_p-11) = m1;
*(htab_p-10) = m1;
*(htab_p-9) = m1;
*(htab_p-8) = m1;
*(htab_p-7) = m1;
*(htab_p-6) = m1;
*(htab_p-5) = m1;
*(htab_p-4) = m1;
*(htab_p-3) = m1;
*(htab_p-2) = m1;
*(htab_p-1) = m1;
htab_p -= 16;
} while ((i -= 16) >= 0);
for (i += 16; i > 0; i--)
*--htab_p = m1;
}
/*
* FUNCTION
* ImLzwCleanup - free storage
*
* DESCRIPTION
* Release the structure memory used by lzw compression
*/
void
ImLzwCleanup()
{
if (imLzwSp->lzwRawdata)
free(imLzwSp->lzwRawdata);
if (imLzwSp)
free(imLzwSp);
imLzwSp = NULL;
}