📄 lzsc.c
字号:
register PGPUInt16 i;
PGPUInt32 LZS_FAR * invalidationPtr;
PGPUInt32 invalidationValue;
/*
Body of function:
*/
invalidationValue = INVALID_FOR_1ST_HALF; /* assume first half */
if (context->sr.sc.historyPointer != 0) /* which half ? */
invalidationValue = INVALID_FOR_2ND_HALF; /* second half */
invalidationPtr = context->sp->hashTable; /* for every table entry*/
for (i = 0; i < HASH_TABLE_SIZE; i++, invalidationPtr++)
/* if the entry is old (minus 2 accounts for currentBytePair */
if (context->sr.sc.historyPointer - *invalidationPtr > HISTORY_SIZE - 2)
*invalidationPtr = invalidationValue; /* invalidate old entry */
return;
} /* RefreshOldHashEntries */
/*
+*****************************************************************************
*
* Function Name: PutBits
*
* Function: Outputs bits of compressed data
*
* Arguments: None.
*
* Globals Used: bitPattern
* nextFreeBit
* numberOfBits
* outputByte
* outputDataCount
* outputDataHandle
*
* Return: None.
*
* Globals Altered: destBufferFull
* outputByte
* nextFreeBit
* outputDataHandle
* outputDataCount
* outputByte
* bitPattern
* numberOfBits
*
* Error Handling: The global destBufferFull is set to TRUE if the
* destination buffer count is exhausted. It is set to OK
* otherwise.
*
* Algorithms: Basically input comes from the variables bitPattern and
* numberOfBits. bitPattern contains the right aligned
* compressed bit pattern to output. Number of bits contains
* the nubmer of bits to output from bitPattern. The
* new bit pattern is or'd left justified into outputByte
* starting at nextFreeBit. The values of nextFreeBit range
* from 8 (msb) to 1 (lsb). When the value of nextFreeBit
* reaches 0 outputByte is written to the destination buffer
* and nextFreeBit is reset to 8.
*
* Notes: OutputByte and nextFree bit are globals whose state is
* preserved across calls. After all of the source data
* has been compressed a call to PutEndMark will assure that
* any remaining data held held in output byte is flushed to
* buffer.
*
-****************************************************************************/
static void PutBits(LZSContextRef context)
{
/*
Local Data Declarations:
*/
register PGPInt16 shiftCount;
/*
Body of function:
*/
if (context->sr.sc.outputDataCount == 0) /* watch for full output buffer */
context->sr.sc.destBufferFull = TRUE;/* initialized to OK by LZS_InitHistory */
if ((shiftCount = context->sr.sc.numberOfBits - context->sr.sc.nextFreeBit) > 0)
{
context->sr.sc.outputByte |= (context->sr.sc.bitPattern >> shiftCount);
context->sr.sc.nextFreeBit = 8;
*context->sr.sc.outputDataHandle++ = context->sr.sc.outputByte;
--context->sr.sc.outputDataCount;
context->sr.sc.outputByte = 0;
context->sr.sc.bitPattern &= ((1 << shiftCount) - 1);
context->sr.sc.numberOfBits = shiftCount;
PutBits(context);
}
else if (shiftCount < 0)
{
context->sr.sc.outputByte |= (context->sr.sc.bitPattern << -shiftCount);
context->sr.sc.nextFreeBit -= context->sr.sc.numberOfBits;
}
else /* (shiftCount == 0) */
{
context->sr.sc.outputByte |= context->sr.sc.bitPattern;
context->sr.sc.nextFreeBit = 8;
*context->sr.sc.outputDataHandle++ = context->sr.sc.outputByte;
--context->sr.sc.outputDataCount;
context->sr.sc.outputByte = 0;
}
return;
} /* PutBits */
/*
+*****************************************************************************
*
* Function Name: PutEndMark
*
* Function: Outputs an end of compressed data mark
*
* Arguments: None.
*
* Globals Used: See PutBits.
*
* Return: None.
*
* Globals Altered: See PutBits.
*
* Error Handling: The global destBufferFull is set to TRUE if the
* destination buffer count is exhausted. It is set to OK
* otherwise.
*
* Algorithms:
*
* Notes: Calling this functions forces all data that has been
* compressed to be flushed to the destination buffer.
*
-****************************************************************************/
static void PutEndMark(LZSContextRef context)
{
/*
Local Data Declarations:
*/
/*
Body of function:
*/
/*----------------------------------------*/
/* output the end of compressed data mark */
/*----------------------------------------*/
PutBitsMac(0x180, 9);
/*------------------------------------*/
/* flush any remaining bits to buffer */
/*------------------------------------*/
if (context->sr.sc.nextFreeBit != 8)
{
*context->sr.sc.outputDataHandle++ = context->sr.sc.outputByte;
--context->sr.sc.outputDataCount;
if (context->sr.sc.outputDataCount == 0) /* watch for full output buffer */
{
context->sr.sc.destBufferFull = TRUE; /* initialized to OK by */
} /* LZS_InitHistory */
}
context->sr.sc.nextFreeBit = 8;
context->sr.sc.outputByte = 0;
return;
} /* PutEndMark */
/*
+*****************************************************************************
*
* Function Name: PutCompressedString
*
* Function: Output a compressed string of data
*
* Arguments: rawStringOffset - Offset of compressed string
* rawStringLength - Length of compressed string
* Globals Used: See PutBits.
*
* Return: None.
*
* Globals Altered: stringLength - The current string length is set to 0
* at the end of this routine. This is
* used as the indication that there is
* no current string.
*
* See PutBits for complete list of altered globals.
*
* Error Handling: The global destBufferFull is set to TRUE if the
* destination buffer count is exhausted. It is set to OK
* otherwise.
*
* Algorithms:
*
* Notes: Read note above about stringLength!
*
-****************************************************************************/
static void PutCompressedString(
LZSContextRef context,
PGPUInt16 rawStringOffset,
PGPUInt32 rawStringLength
)
{
/*
Local Data Declarations:
*/
/*
Body of function:
*/
if (context->sr.sc.stringOutputStarted == FALSE)
{
/*----------------*/
/* 7 bit offset ? */
/*----------------*/
if (rawStringOffset < 128)
{
PutBitsMac(0x180 | rawStringOffset, 9);
}
/*-----------------*/
else /* 11 bit offset ? */
/*-----------------*/
{
PutBitsMac(0x1000 | rawStringOffset, 13);
}
}
/*--------------------------------------------------------------*/
/* take care of any run length encoded portion of string length */
/*--------------------------------------------------------------*/
if (rawStringLength >= MIN_RLE_LENGTH)
{
PutBitsMac(RLE_UNIT_LENGTH, BITS_PER_RLE_UNIT);
rawStringLength -= RLE_UNIT_LENGTH;
context->sr.sc.RLE_Length += RLE_UNIT_LENGTH;
context->sr.sc.stringOutputStarted = TRUE;
}
else
{
/*--------------------------------------------*/
/* look up the remainder of the string length */
/*--------------------------------------------*/
PutBitsMac(
lengthTable[(PGPUInt16) rawStringLength].pattern,
lengthTable[(PGPUInt16) rawStringLength].size
);
/*----------------------------*/
/* no current string any more */
/*----------------------------*/
context->sr.sc.stringOutputStarted = FALSE;
context->sr.sc.stringLength = 0;
context->sr.sc.RLE_Length = 0;
context->event = ENDED_STRING;
}
return;
} /* PutCompressedString */
/*
+*****************************************************************************
*
* Function Name: PerformFlush
*
* Function: Flush all compressed data & write EOCD mark
*
* Arguments:
* Globals Used:
* Hardware Inputs:
*
* Return:
* Globals Altered:
* Hardware Outputs:
*
* Error Handling:
*
* Algorithms/Structures:
*
* Notes:
*
-****************************************************************************/
static void PerformFlush(LZSContextRef context, PGPUInt16 flags)
{
/*
Local Data Declarations:
*/
/*
Body of function:
*/
/*--------------------------*/
/* Flush any remaining data */
/*--------------------------*/
if (context->sr.sc.compressedSomeData == TRUE)
{
if (context->sr.sc.stringLength == 0)
{
PutARawByte(context->sr.sc.currentByte);
}
else
PutCompressedString(context, context->sr.sc.matchStringOffset, context->sr.sc.stringLength);
}
PutEndMark(context);
if ((flags & LZS_NO_CLEAR) == FALSE)
{
/*-----------------------------*/
/* Invalidate old hash entries */
/*-----------------------------*/
if (0 - context->sr.sc.historyPointer >= HISTORY_SIZE)
InitHashTable(context->sp->hashTable, INVALID_FOR_1ST_HALF);
else if (0x80000000L - context->sr.sc.historyPointer >= HISTORY_SIZE)
InitHashTable(context->sp->hashTable, INVALID_FOR_2ND_HALF);
context->sr.sc.historyPointer += HISTORY_SIZE;
context->sr.sc.historyPointerMinus1 += HISTORY_SIZE;
InitCompressVars(context);
}
/*---------------------------------------*/
/* Forget old data. Reprime w/ next byte */
/*---------------------------------------*/
context->sr.sc.compressedSomeData = FALSE;
return;
} /* PerformFlush */
/*
+*****************************************************************************
*
* Function Name: LZS_Compress
*
* Function: compress a buffer full of data
*
* Arguments: sourceHandle - pointer to pointer to source buffer
* destHandle - pointer to pointer to destination buffer
* sourceCount - pointer to size in bytes of data in
* source buffer.
* destCount - pointer to size in bytes of destination
* buffer.
*
* Globals Used: compressedSomeData
* currentByte
* currentBytePair
* currentStringIndex
* hashTable
* c_history
* historyPointer
* historyPointerMinus1
* inputDataCount
* inputDataHandle
* matchIndex
* matchStringOffset
* outputDataCount
* outputDataHandle
* searchCount
* stringLength
* stringList
*
*
* Return: None.
*
* Globals Altered: bytePairOffset
* compressedSomeData
* currentByte
* currentBytePair
* currentStringIndex
* firstMatchOffset
* hashAddress
* hashTable
* c_history
* historyPointer
* historyPointerMinus1
* inputDataCount
* inputDataHandle
* matchIndex
* matchStringOffset
* outputDataCount
* outputDataHandle
* rematchOffset
* searchCount
* searchCount
* stringLength
* stringList
*
* Error Handling: Terminates if either source or destination counts are
* exhausted.
*
* Algorithms: Hash incoming byte pairs. Store the current history
* pointer in the hashTable. Store offsets to previous hash
* entries in stringList (hash buckets). Search stringList
* for matches to current byte pair.
*
* Pseudo-code:
*
* BEGIN
* {
* if there is data to compress and room to put it
* {
* initialize data;
* get a byte to prime the pump;
* while still data to compress and room to put it;
* {
* advance history and related vars;
* see if hash table needs to be refreshed;
* get another byte, update history, and string list;
* if offset to last hashed string greater than history size;
* stringList for current byte pair = 0;
* else
* {
* update string list with current byte pair offset;
* if not currently extending a string;
* search string list for current byte pair match;
* }
* update hash table with current byte pair information;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -