170 lines
4.5 KiB
C
170 lines
4.5 KiB
C
/*
|
|
** lzexp.c - Routines used in Lempel-Ziv (from their 1977 article) expansion.
|
|
**
|
|
** Author: DavidDi
|
|
*/
|
|
|
|
|
|
// Headers
|
|
///////////
|
|
|
|
#ifndef LZA_DLL
|
|
#include <io.h>
|
|
#endif
|
|
|
|
#include "lz_common.h"
|
|
#include "lz_buffers.h"
|
|
#include "lz_header.h"
|
|
#include "lzcommon.h"
|
|
|
|
|
|
/*
|
|
** int LZDecode(int doshSource, int doshDest, long cblExpandedLength,
|
|
** BOOL bRestartDecoding, BOOL bFirstAlg);
|
|
**
|
|
** Expand input file to output file.
|
|
**
|
|
** Arguments: doshSource - DOS file handle of open input file
|
|
** doshDest - DOS file handle of open output file
|
|
** cblExpandedLength - amount of output file to expand
|
|
** bRestartDecoding - flag indicating whether or not to start
|
|
** decoding from scratch
|
|
** bFirstAlg - flag indicating whether to use ALG_FIRST
|
|
** or ALG_LZ
|
|
**
|
|
** Returns: int - TRUE if expansion was successful. One of the LZERROR_
|
|
** codes if the expansion failed.
|
|
**
|
|
** Globals:
|
|
**
|
|
** The number of bytes actually expanded will be >= cblExpandedLength. The
|
|
** number of bytes actually expanded may be calculated as
|
|
** (pbyteOutBuf - rgbyteOutBuf). The expansion will overrun the
|
|
** cblExpandedLength request by at most (cbMaxMatchLen - 1) bytes.
|
|
*/
|
|
INT LZDecode(
|
|
INT doshSource,
|
|
INT doshDest,
|
|
LONG cblExpandedLength,
|
|
BOOL bRestartDecoding,
|
|
BOOL bFirstAlg,
|
|
PLZINFO pLZI)
|
|
{
|
|
INT i,
|
|
cb, // number of bytes to unpack
|
|
f; // holds ReadByte() return values
|
|
INT oStart; // buffer offset for unpacking
|
|
BYTE byte1, byte2; // input byte holders
|
|
|
|
|
|
// !!! Assumes parm pLZI is always valid
|
|
|
|
#if 0
|
|
if (bFirstAlg == TRUE)
|
|
pLZI->cbMaxMatchLen = FIRST_MAX_MATCH_LEN;
|
|
else
|
|
pLZI->cbMaxMatchLen = LZ_MAX_MATCH_LEN;
|
|
#else
|
|
pLZI->cbMaxMatchLen = FIRST_MAX_MATCH_LEN;
|
|
#endif
|
|
|
|
// Start decoding from scratch?
|
|
if (bRestartDecoding == TRUE)
|
|
{
|
|
// Rewind the compressed input file to just after the compressed file
|
|
// header.
|
|
if (FSEEK(doshSource, (LONG)HEADER_LEN, SEEK_SET) != (LONG)HEADER_LEN) {
|
|
return(LZERROR_BADINHANDLE);
|
|
}
|
|
|
|
// Rewind output file.
|
|
if (doshDest != NO_DOSH &&
|
|
FSEEK(doshDest, 0L, SEEK_SET) != 0L) {
|
|
return(LZERROR_BADOUTHANDLE);
|
|
}
|
|
|
|
// Set up a fresh buffer state.
|
|
ResetBuffers();
|
|
|
|
// Initialize ring buffer.
|
|
for (i = 0; i < RING_BUF_LEN - pLZI->cbMaxMatchLen; i++)
|
|
pLZI->rgbyteRingBuf[i] = BUF_CLEAR_BYTE;
|
|
|
|
// Initialize decoding globals.
|
|
pLZI->uFlags = 0U;
|
|
pLZI->iCurRingBufPos = RING_BUF_LEN - pLZI->cbMaxMatchLen;
|
|
}
|
|
|
|
if ((f = ReadByte(byte1)) != TRUE && f != END_OF_INPUT) {
|
|
return(f);
|
|
}
|
|
|
|
// Decode one encoded unit at a time.
|
|
FOREVER
|
|
{
|
|
if (f == END_OF_INPUT) // EOF reached
|
|
break;
|
|
|
|
// Have we expanded enough data yet?
|
|
if (pLZI->cblOutSize > cblExpandedLength) // Might want to make this >=.
|
|
{
|
|
UnreadByte();
|
|
return(TRUE);
|
|
}
|
|
|
|
// High order byte counts the number of bits used in the low order
|
|
// byte.
|
|
if (((pLZI->uFlags >>= 1) & 0x100) == 0)
|
|
{
|
|
// Set bit mask describing the next 8 bytes.
|
|
pLZI->uFlags = ((DWORD)byte1) | 0xff00;
|
|
|
|
if ((f = ReadByte(byte1)) != TRUE) {
|
|
return(LZERROR_READ);
|
|
}
|
|
}
|
|
|
|
if (pLZI->uFlags & 1)
|
|
{
|
|
// Just store the literal byte in the buffer.
|
|
if ((f = WriteByte(byte1)) != TRUE) {
|
|
return(f);
|
|
}
|
|
|
|
pLZI->rgbyteRingBuf[pLZI->iCurRingBufPos++] = byte1;
|
|
pLZI->iCurRingBufPos &= RING_BUF_LEN - 1;
|
|
}
|
|
else
|
|
{
|
|
// Extract the offset and count to copy from the ring buffer.
|
|
if ((f = ReadByte(byte2)) != TRUE) {
|
|
return(LZERROR_READ);
|
|
}
|
|
|
|
cb = (INT)byte2;
|
|
oStart = (cb & 0xf0) << 4 | (INT)byte1;
|
|
cb = (cb & 0x0f) + MAX_LITERAL_LEN;
|
|
|
|
for (i = 0; i <= cb; i++)
|
|
{
|
|
byte1 = pLZI->rgbyteRingBuf[(oStart + i) & (RING_BUF_LEN - 1)];
|
|
|
|
if ((f = WriteByte(byte1)) != TRUE) {
|
|
return( f );
|
|
}
|
|
|
|
pLZI->rgbyteRingBuf[pLZI->iCurRingBufPos++] = byte1;
|
|
pLZI->iCurRingBufPos &= RING_BUF_LEN - 1;
|
|
}
|
|
}
|
|
|
|
if ((f = ReadByte(byte1)) != TRUE && f != END_OF_INPUT) {
|
|
return(f);
|
|
}
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|