175 lines
4.7 KiB
C
175 lines
4.7 KiB
C
|
/*
|
||
|
* LZEXP.C
|
||
|
*
|
||
|
* Routines used in Lempel-Ziv expansion.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include "kernel.h"
|
||
|
|
||
|
#if ROM //--------------------------------------------------------------
|
||
|
|
||
|
|
||
|
#define API _far _pascal _loadds
|
||
|
|
||
|
#define RING_BUF_LEN 4096 // size of ring buffer
|
||
|
#define MAX_RING_BUF_LEN 4224 // size of ring buffer - from LZFile
|
||
|
// struct declaration in lzexpand.h
|
||
|
|
||
|
#define BUF_CLEAR_BYTE ((BYTE) ' ') // rgbyteRingBuf[] initializer
|
||
|
|
||
|
#define MAX_LITERAL_LEN 2 // encode string into position and
|
||
|
// length if match length greater than
|
||
|
// this value (== # of bytes required
|
||
|
// to encode position and length)
|
||
|
|
||
|
#define LZ_MAX_MATCH_LEN (0x10 + MAX_LITERAL_LEN)
|
||
|
// upper limit for match length
|
||
|
// (n.b., assume length field implies
|
||
|
// length += 3)
|
||
|
|
||
|
#define END_OF_INPUT 500 // EOF flag for input file
|
||
|
|
||
|
#define FOREVER for(;;)
|
||
|
|
||
|
#define ReadByte(byte) ((byte = (BYTE)(cbSrc ? *pSrc++ : 0)), \
|
||
|
(cbSrc ? (cbSrc--, TRUE) : END_OF_INPUT))
|
||
|
#define WriteByte(byte) ((*pDst++ = byte), cblOutSize++)
|
||
|
|
||
|
typedef struct COMPHEAD _far * LPCOMPHEAD;
|
||
|
|
||
|
struct COMPHEAD { // Compressed segment/resource header
|
||
|
BYTE Sig; // signature
|
||
|
BYTE Method; // compression method
|
||
|
DWORD cbSize; // # compressed bytes following
|
||
|
};
|
||
|
|
||
|
#define CMP_SIG ('C')
|
||
|
#define CMP_LZ ('L')
|
||
|
|
||
|
|
||
|
/*
|
||
|
* LZDecode
|
||
|
*
|
||
|
* Parameters:
|
||
|
* selDst Selector pointing to destination buffer
|
||
|
* selSrc Selector pointing to compressed data
|
||
|
* lpBuf Pointer to optional ring buffer
|
||
|
*
|
||
|
* Returns:
|
||
|
* count (in bytes) of uncompressed data written to selDst buffer
|
||
|
*
|
||
|
* Note: This routine does not use any static or external data.
|
||
|
* This allows it to be used to uncompress Kernel's own
|
||
|
* data segment.
|
||
|
*/
|
||
|
|
||
|
DWORD FAR API
|
||
|
LZDecode(WORD selDst, WORD selSrc, LPSTR lpBuf) {
|
||
|
|
||
|
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
|
||
|
unsigned uFlags; // LZ decoding description byte
|
||
|
int iCurRingBufPos; // ring buffer offset
|
||
|
int cbMaxMatchLen;
|
||
|
LPSTR rgbyteRingBuf;
|
||
|
HANDLE hRingBuf;
|
||
|
LPCOMPHEAD lpHead;
|
||
|
DWORD cblOutSize, cbSrc;
|
||
|
char _based((_segment)selDst) *pDst = NULL;
|
||
|
char _based((_segment)selSrc) *pSrc = NULL;
|
||
|
struct COMPHEAD _based((_segment)selSrc) *pHead = NULL;
|
||
|
|
||
|
pSrc += sizeof(struct COMPHEAD);
|
||
|
|
||
|
cblOutSize = 0;
|
||
|
cbSrc = pHead->cbSize;
|
||
|
cbMaxMatchLen = LZ_MAX_MATCH_LEN;
|
||
|
|
||
|
// Make sure we know how to expand this object
|
||
|
|
||
|
if (pHead->Sig != CMP_SIG || pHead->Method != CMP_LZ)
|
||
|
return(0);
|
||
|
|
||
|
// Set up a fresh buffer state.
|
||
|
if (lpBuf) {
|
||
|
hRingBuf = NULL;
|
||
|
rgbyteRingBuf = lpBuf;
|
||
|
} else {
|
||
|
if (!(hRingBuf = GlobalAlloc(GMEM_MOVEABLE,MAX_RING_BUF_LEN)))
|
||
|
return(0);
|
||
|
rgbyteRingBuf = GlobalLock(hRingBuf);
|
||
|
}
|
||
|
|
||
|
// Initialize ring buffer.
|
||
|
for (i = 0; i < RING_BUF_LEN - cbMaxMatchLen; i++)
|
||
|
rgbyteRingBuf[i] = BUF_CLEAR_BYTE;
|
||
|
|
||
|
// Initialize decoding globals.
|
||
|
uFlags = 0U;
|
||
|
iCurRingBufPos = RING_BUF_LEN - cbMaxMatchLen;
|
||
|
|
||
|
f = ReadByte(byte1);
|
||
|
|
||
|
// Decode one encoded unit at a time.
|
||
|
FOREVER
|
||
|
{
|
||
|
if (f == END_OF_INPUT) // EOF reached
|
||
|
break;
|
||
|
|
||
|
// High order byte counts the number of bits used in the low order
|
||
|
// byte.
|
||
|
if (((uFlags >>= 1) & 0x100) == 0)
|
||
|
{
|
||
|
// Set bit mask describing the next 8 bytes.
|
||
|
uFlags = ((unsigned)byte1) | 0xff00;
|
||
|
|
||
|
if ((f = ReadByte(byte1)) != TRUE)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (uFlags & 1)
|
||
|
{
|
||
|
// Just store the literal byte in the buffer.
|
||
|
WriteByte(byte1);
|
||
|
|
||
|
rgbyteRingBuf[iCurRingBufPos++] = byte1;
|
||
|
iCurRingBufPos &= RING_BUF_LEN - 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Extract the offset and count to copy from the ring buffer.
|
||
|
if ((f = ReadByte(byte2)) != TRUE)
|
||
|
break;
|
||
|
|
||
|
cb = (int)byte2;
|
||
|
oStart = (cb & 0xf0) << 4 | (int)byte1;
|
||
|
cb = (cb & 0x0f) + MAX_LITERAL_LEN;
|
||
|
|
||
|
for (i = 0; i <= cb; i++)
|
||
|
{
|
||
|
byte1 = rgbyteRingBuf[(oStart + i) & (RING_BUF_LEN - 1)];
|
||
|
|
||
|
WriteByte(byte1);
|
||
|
|
||
|
rgbyteRingBuf[iCurRingBufPos++] = byte1;
|
||
|
iCurRingBufPos &= RING_BUF_LEN - 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
f = ReadByte(byte1);
|
||
|
}
|
||
|
|
||
|
if (hRingBuf) {
|
||
|
GlobalUnlock(hRingBuf);
|
||
|
GlobalFree(hRingBuf);
|
||
|
}
|
||
|
|
||
|
return(cblOutSize);
|
||
|
}
|
||
|
|
||
|
#endif //ROM -------------------------------------------------------
|