You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
468 lines
13 KiB
468 lines
13 KiB
/* File: C:\WACKER\xfer\cmprs1.c (Created: 20-Jan-1994)
|
|
* created from HAWIN source file
|
|
* cmprs1.c -- Routines to implement data compression
|
|
*
|
|
* Copyright 1989,1994 by Hilgraeve Inc. -- Monroe, MI
|
|
* All rights reserved
|
|
*
|
|
* $Revision: 1 $
|
|
* $Date: 10/05/98 1:16p $
|
|
*/
|
|
#include <windows.h>
|
|
|
|
#include <tdll\stdtyp.h>
|
|
|
|
#if !defined(BYTE)
|
|
#define BYTE unsigned char
|
|
#endif
|
|
|
|
#include "cmprs.h"
|
|
#include "cmprs.hh"
|
|
|
|
#if SHOW
|
|
// #include <stdio.h>
|
|
#endif
|
|
|
|
unsigned int usPrefixCode = 0; /* code representing pattern matched so far */
|
|
int mcK; /* character to be appended to prefix for
|
|
next match */
|
|
|
|
int (**ppfCmprsGetfunc)(void *) = NULL;
|
|
/* pointer to the
|
|
pointer to a function used by calling
|
|
routine */
|
|
|
|
int (*pfCmprsGetChar)(void *);
|
|
/* pointer to the function used
|
|
internally to get data to compress */
|
|
void *pPsave;
|
|
|
|
long *plCmprsLoadcnt;
|
|
long lCmprsBegcnt;
|
|
long lCmprsLimitcnt = 1L; // Initializing to one disables compression
|
|
// shut-down unless changed
|
|
struct s_cmprs_node *pstCmprsTbl; /* pointer to compression lookup table */
|
|
|
|
#define NODE_CAST struct s_cmprs_node *
|
|
|
|
int lookup_code(void);
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* compress_start
|
|
*
|
|
* DESCRIPTION
|
|
* This function is called to begin data compression. The calling routine
|
|
* should set up a pointer to a function through which it will make calls
|
|
* to get characters of data. The pointer should be initialized to point
|
|
* to the function that the compression routines should use to get raw
|
|
* data for compression. The pointer is then modified by the compression
|
|
* routines to point to the compressor. After compression is complete or
|
|
* abandoned, the pointer is restored to its original value.
|
|
* Example of calling sequence:
|
|
* int (*xgetc)();
|
|
* int fgetc();
|
|
*
|
|
* xgetc = fgetc;
|
|
* if (compress_start(&xgetc))
|
|
* ;
|
|
* If fPauses is TRUE, the compressor will flush existing data through when
|
|
* the input function returns an EOF but will not shutdown. Whenever the
|
|
* next non-EOF is retrieved, compression will resume where it left off will
|
|
* the pattern table still intact. The fPauses flag must be used by both
|
|
* the compression and decompression routines to work. If fPauses is used,
|
|
* the cmprs_stop() function must be used to shut compression down before
|
|
* compress_disable() is called.
|
|
*
|
|
* RETURN VALUE
|
|
* Returns TRUE if memory is available for table storage and at least one
|
|
* character is available from input; FALSE otherwise.
|
|
*/
|
|
int compress_start(int (**getfunc)(void *),
|
|
void *pP,
|
|
long *loadcnt,
|
|
int fPauses)
|
|
{
|
|
#if FALSE
|
|
#if !defined(LZTEST)
|
|
long x;
|
|
#endif
|
|
#endif
|
|
|
|
if (!compress_enable())
|
|
return(FALSE);
|
|
|
|
fFlushable = fPauses;
|
|
|
|
fxLastBuildGood = FALSE; /* By setting this FALSE, we will cause
|
|
* compression to shut down if the very first
|
|
* table build indicates that compression is
|
|
* not effective. Thereafter, it will take two
|
|
* consecutive bad builds to shut it down.
|
|
*/
|
|
|
|
if ((plCmprsLoadcnt = loadcnt) != NULL && !fFlushable)
|
|
{
|
|
lCmprsBegcnt = *plCmprsLoadcnt;
|
|
/*
|
|
* Compressability of files can be roughly measured by how many input
|
|
* characters must be read before the pattern table fills up. The
|
|
* lower the number, the less efficient compression is. This
|
|
* calculation determines a cutoff point for any combination of
|
|
* machine speed and transfer rate based on experimental trials.
|
|
*
|
|
* Note that this mechanism should not be used when the fPauses
|
|
* parameter is TRUE because the decompressor would misinterpret
|
|
* the data following the STOPCODE after compression shut down
|
|
*/
|
|
#if FALSE
|
|
#if !defined(LZTEST)
|
|
if ((x = (cnfg.bit_rate / cpu_speed())) == 0L)
|
|
lCmprsLimitcnt = 4300L;
|
|
else
|
|
lCmprsLimitcnt = max(x * 774L - 500L, 4300L);
|
|
#else
|
|
lCmprsLimitcnt = 4300L;
|
|
#endif
|
|
#endif
|
|
lCmprsLimitcnt = 4300L;
|
|
}
|
|
pPsave = pP;
|
|
ppfCmprsGetfunc = getfunc;
|
|
pfCmprsGetChar = *ppfCmprsGetfunc;
|
|
if ((mcK = (*pfCmprsGetChar)(pPsave)) != EOF)
|
|
{
|
|
|
|
*ppfCmprsGetfunc = cmprs_getc;
|
|
cmprs_inittbl();
|
|
ulHoldReg = 0L;
|
|
ulHoldReg |= CLEARCODE;
|
|
sBitsLeft = sCodeBits;
|
|
usxCmprsStatus = COMPRESS_ACTIVE;
|
|
|
|
#if SHOW
|
|
printf("C %02X (starting, emit CLEARCODE)\n",
|
|
mcK);
|
|
printf("C -> %03X %08lX,%2d\n", CLEARCODE,
|
|
ulHoldReg, sBitsLeft);
|
|
#endif
|
|
|
|
return(TRUE);
|
|
}
|
|
else
|
|
{
|
|
ppfCmprsGetfunc = NULL;
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* compress_stop
|
|
*
|
|
* DESCRIPTION
|
|
* If compression has been started, it is turned off.
|
|
*/
|
|
void compress_stop(void)
|
|
{
|
|
#if SHOW
|
|
printf("C Compress_stop\n");
|
|
#endif
|
|
|
|
if (ppfCmprsGetfunc != NULL)
|
|
{
|
|
*ppfCmprsGetfunc = pfCmprsGetChar;
|
|
ppfCmprsGetfunc = NULL;
|
|
}
|
|
usxCmprsStatus = COMPRESS_IDLE;
|
|
}
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* cmprs_inittbl
|
|
*
|
|
* DESCRIPTION
|
|
* Used to initialize the lookup table used for compressing data.
|
|
*/
|
|
void cmprs_inittbl(void)
|
|
{
|
|
register INT iCount;
|
|
|
|
sCodeBits = 9;
|
|
usMaxCode = 512;
|
|
usFreeCode = FIRSTFREE;
|
|
|
|
// pstCmprsTbl = (struct s_cmprs_node *)(OFFSETOF(compress_tblspace));
|
|
pstCmprsTbl = (struct s_cmprs_node *)(compress_tblspace);
|
|
|
|
for (iCount = 0; iCount < FIRSTFREE; ++iCount)
|
|
pstCmprsTbl[iCount].first = pstCmprsTbl[iCount].next = NULL;
|
|
}
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* cmprs_shutdown
|
|
*
|
|
* DESCRIPTION
|
|
* This is the function that is installed by cmprs_getc when compression
|
|
* is ending. It is installed after cmprs_getc encounters the end of the input
|
|
* data. This function returns any remaining bytes, then returns EOF and
|
|
* restores the original getc function
|
|
*
|
|
* RETURN VALUE
|
|
* Returns the next code to be sent or EOF.
|
|
*/
|
|
int cmprs_shutdown(void *pX)
|
|
{
|
|
int mcRetCode;
|
|
|
|
// If we haven't sent all the data yet, do so
|
|
if (sBitsLeft > 0)
|
|
{
|
|
mcRetCode = (int)(ulHoldReg & 0x00FF);
|
|
ulHoldReg >>= 8;
|
|
sBitsLeft -= 8;
|
|
|
|
#if SHOW
|
|
printf("C %02X %08lX,%2d Draining ulHoldReg\n",
|
|
mcRetCode, ulHoldReg, sBitsLeft);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// No more data waiting.
|
|
mcRetCode = EOF;
|
|
sBitsLeft = 0;
|
|
|
|
if (!fFlushable)
|
|
{
|
|
// Not flushable, get compression out of the chain
|
|
*ppfCmprsGetfunc = pfCmprsGetChar;
|
|
ppfCmprsGetfunc = NULL;
|
|
#if SHOW
|
|
printf(" !fFlushable, outta here\n");
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// Flushable, see whether we should resume compression
|
|
if ((mcK = (*pfCmprsGetChar)(pPsave)) != EOF)
|
|
{
|
|
#if SHOW
|
|
printf("C %02X fFlushable TRUE, restarting\n",
|
|
mcK);
|
|
#endif
|
|
*ppfCmprsGetfunc = cmprs_getc;
|
|
mcRetCode = cmprs_getc(pPsave);
|
|
}
|
|
}
|
|
}
|
|
return(mcRetCode);
|
|
}
|
|
|
|
|
|
#if !USE_ASM
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* cmprs_getc
|
|
*
|
|
* DESCRIPTION
|
|
* This is the function installed by compress_start to be used by any routine
|
|
* that needs compressed data. It delivers bytes to the calling routine,
|
|
* but may read several characters from the input to do so.
|
|
*
|
|
* RETURN VALUE
|
|
* Returns next 8-bits of compressed data or EOF if no more is available.
|
|
*/
|
|
int cmprs_getc(void *pX)
|
|
{
|
|
int mcRetCode;
|
|
int fBuildGood;
|
|
|
|
if (sBitsLeft < 8)
|
|
{
|
|
usPrefixCode = (unsigned int)mcK;
|
|
do
|
|
{
|
|
if ((mcK = (*pfCmprsGetChar)(pPsave)) == EOF)
|
|
{
|
|
/* at end of file, send last code followed by STOPCODE */
|
|
/* to stop decompression. Note that ulHoldReg may overflow */
|
|
/* if the maximum code size is greater than 12 bits */
|
|
ulHoldReg |= ((unsigned long)usPrefixCode << sBitsLeft);
|
|
sBitsLeft += sCodeBits;
|
|
|
|
#if SHOW
|
|
printf("C -1 Shutdown,"
|
|
" emit prefix and STOPCODE\n");
|
|
printf("C -> %03X %08lX,%2d Codebits=%d\n",
|
|
usPrefixCode, ulHoldReg, sBitsLeft, sCodeBits);
|
|
#endif
|
|
|
|
// If we're poised to switch to the next larger code size,
|
|
// the decompressor will do so after the prior code, so
|
|
// we should switch now too.
|
|
if (usFreeCode >= usMaxCode && sCodeBits < MAXCODEBITS)
|
|
{
|
|
++sCodeBits;
|
|
usMaxCode *= 2;
|
|
#if SHOW
|
|
printf("C "
|
|
"New sCodeBits = %d (anticipating)\n",
|
|
sCodeBits);
|
|
#endif
|
|
}
|
|
|
|
usPrefixCode = STOPCODE;
|
|
*ppfCmprsGetfunc = cmprs_shutdown;
|
|
usxCmprsStatus = COMPRESS_IDLE;
|
|
|
|
break; /* let last code go out */
|
|
}
|
|
} while (lookup_code());
|
|
ulHoldReg |= ((unsigned long)usPrefixCode << sBitsLeft);
|
|
sBitsLeft += sCodeBits;
|
|
#if SHOW
|
|
printf("C -> %03X %08lX,%2d Codebits=%d\n", usPrefixCode,
|
|
ulHoldReg, sBitsLeft, sCodeBits);
|
|
#endif
|
|
}
|
|
mcRetCode = (int)(ulHoldReg & 0x00FF);
|
|
ulHoldReg >>= 8;
|
|
sBitsLeft -= 8;
|
|
|
|
#if SHOW
|
|
printf("C %02X %08lX,%2d\n", mcRetCode, ulHoldReg, sBitsLeft);
|
|
#endif
|
|
|
|
if (usFreeCode > usMaxCode)
|
|
{
|
|
/* We've used up all available codes at the current codesize */
|
|
|
|
if (sCodeBits >= MAXCODEBITS)
|
|
{
|
|
/* We've filled the pattern table, either shut down or clear the
|
|
* table and build a new one.
|
|
*/
|
|
|
|
fBuildGood = TRUE;
|
|
if (plCmprsLoadcnt &&
|
|
(*plCmprsLoadcnt - lCmprsBegcnt) < lCmprsLimitcnt)
|
|
fBuildGood = FALSE;
|
|
|
|
#if SHOW
|
|
printf("C Table full, fBuildGood = %d\n",
|
|
fBuildGood);
|
|
#endif
|
|
/* if two ineffective builds in a row (or if the very first build
|
|
* is ineffective, shut compression down.
|
|
*/
|
|
|
|
if (!fBuildGood && !fxLastBuildGood)
|
|
{
|
|
/* compression is not effective, shut it down */
|
|
|
|
ulHoldReg |= ((unsigned long)STOPCODE << sBitsLeft);
|
|
sBitsLeft += sCodeBits;
|
|
#if SHOW
|
|
printf("C -> %03X %08lX,%2d Ineffective, emitting STOPCODE\n",
|
|
STOPCODE, ulHoldReg, sBitsLeft);
|
|
#endif
|
|
*ppfCmprsGetfunc = cmprs_shutdown;
|
|
usxCmprsStatus = COMPRESS_SHUTDOWN;
|
|
}
|
|
else
|
|
{
|
|
/* clear the table and build a new one in case the nature of
|
|
* the data changes.
|
|
*/
|
|
ulHoldReg |= ((unsigned long)CLEARCODE << sBitsLeft);
|
|
sBitsLeft += sCodeBits;
|
|
#if SHOW
|
|
printf("C -> %03X %08lX,%2d New table, emiting CLEARCODE\n",
|
|
CLEARCODE, ulHoldReg, sBitsLeft);
|
|
#endif
|
|
cmprs_inittbl();
|
|
lCmprsBegcnt = *plCmprsLoadcnt;
|
|
}
|
|
fxLastBuildGood = fBuildGood;
|
|
}
|
|
else
|
|
{
|
|
/* code size hasn't maxed out yet, bump to next larger code size */
|
|
|
|
++sCodeBits;
|
|
usMaxCode *= 2;
|
|
#if SHOW
|
|
printf("C New sCodeBits = %d, usMaxCode = %03X\n",
|
|
sCodeBits, usMaxCode);
|
|
#endif
|
|
}
|
|
}
|
|
return(mcRetCode);
|
|
}
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* lookup_code
|
|
*
|
|
* DESCRIPTION
|
|
* This is a 'C' language version of the table lookup routine. It is used
|
|
* when an internal lookup table is being used. An assembly language version
|
|
* is used if an external lookup table is being used.
|
|
* Given a current usPrefixCode and input character, this function
|
|
* attempts to find a new usPrefixCode for the combined pattern in the table.
|
|
* If so, it updates the usPrefixCode and returns TRUE. If the pattern is
|
|
* not found, it adds the combination to the table and returns FALSE.
|
|
*
|
|
* RETURN VALUE
|
|
* TRUE if usPrefixCode:mcK is found in the table. FALSE if not.
|
|
*/
|
|
int lookup_code(void)
|
|
{
|
|
int firstflag;
|
|
struct s_cmprs_node *tptr = (NODE_CAST)&pstCmprsTbl[usPrefixCode];
|
|
struct s_cmprs_node *newptr;
|
|
|
|
|
|
firstflag = TRUE;
|
|
if (tptr->first != NULL)
|
|
{
|
|
firstflag = FALSE;
|
|
tptr = tptr->first;
|
|
for (;;)
|
|
{
|
|
if (tptr->cchar == (BYTE)mcK)
|
|
{
|
|
usPrefixCode = (unsigned int)(tptr - (NODE_CAST)(&pstCmprsTbl[0]));
|
|
|
|
#if SHOW
|
|
printf("C %02X ->(%03X)\n",
|
|
mcK, usPrefixCode);
|
|
#endif
|
|
|
|
return(TRUE);
|
|
}
|
|
if (tptr->next == NULL)
|
|
break;
|
|
else
|
|
tptr = tptr->next;
|
|
}
|
|
}
|
|
if (usFreeCode < MAXNODES)
|
|
{
|
|
#if SHOW
|
|
printf("C %02X Added %03X = %03X + %02X\n",
|
|
mcK, usFreeCode, usPrefixCode, mcK);
|
|
#endif
|
|
newptr = (NODE_CAST)&pstCmprsTbl[usFreeCode++];
|
|
if (firstflag)
|
|
tptr->first = newptr;
|
|
else
|
|
tptr->next = newptr;
|
|
newptr->first = newptr->next = NULL;
|
|
newptr->cchar = (BYTE)mcK;
|
|
}
|
|
else
|
|
++usFreeCode; /* triggers clearing and rebuilding of table */
|
|
return(FALSE);
|
|
}
|
|
|
|
#endif
|
|
|
|
/* end of cmprs1.c */
|