windows-nt/Source/XPSP1/NT/windows/winstate/cobra/utils/compress/mrcicode.c
2020-09-26 16:20:57 +08:00

1091 lines
33 KiB
C

/*
* Microsoft Confidential
* Copyright (c) 1994 Microsoft Corporation
* All Rights Reserved.
*
* MRCICODE.C
*
* MRCI 1 & MRCI 2 maxcompress and decompress functions
*/
#include "pch.h"
#include "mrcicode.h" /* prototype verification */
#include <assert.h> /* use NDEBUG to inhibit */
#include <setjmp.h> /* fast overflow recovery */
#define LOGCHASH (13) /* Log of max. no. of hash buckets */
#define CHASH (1U << LOGCHASH) /* Reasonably large table */
#define hash(w) ((w) & (CHASH - 1))
/* Simply toss the high-order bits */
#define word(p) ((p)[0] + (((p)[1]) << 8))
/* Return word at location */
#define BITMASK(x) ((1 << x) - 1) /* returns lower 'x' bits set */
#define LOGDISPSMALL (6) /* Number of bits in small disp */
#define LOGDISPMED (8) /* Number of bits in medium disp */
#define LOGDISPBIG (12) /* Number of bits in big displacement */
#define MAXDISPSMALL ((1 << LOGDISPSMALL) - 1)
/* Maximum small displacement */
#define MAXDISPMED ((1 << LOGDISPMED) + MAXDISPSMALL)
/* Maximum medium displacement */
#define MAXDISPBIG ((1 << LOGDISPBIG) + MAXDISPMED)
/* Maximum big displacement */
#define MINDISPSMALL (0) /* Minimum small displacement */
#define MINDISPMED (MAXDISPSMALL + 1)
/* Minimum medium displacement */
#define MINDISPBIG (MAXDISPMED + 1)/* Minimum big displacement */
#define DISPMAX (MAXDISPBIG - 1)/* MAXDISPBIG is our end marker */
#define MINMATCH1 (2) /* Minimum match length for MRCI1 */
#define MINMATCH2 (3) /* Minimum match length for MRCI2 */
#define MAXMATCH (512) /* Maximum match length */
#define EOB (0) /* length used to mean end of block */
#define SECTOR (512) /* blocking factor */
#define SIG_SIZE (4) /* # of block type prefix bytes */
/* local variables */
static unsigned abits; /* Array of bits */
static unsigned cbitsleft; /* Number of bits in abits */
static unsigned char FAR *pCompressed; /* pointer into compressed data */
static unsigned cCompressed; /* # bytes remaining @ pCompressed */
static jmp_buf bailout; /* longjmp if cCompressed exceeded */
static unsigned ahash[CHASH]; /* Hash table */
static unsigned alink[MAXDISPBIG]; /* Links */
/* compression internal functions */
static void inithash(void);
static void charbuf(unsigned c);
static void putbits(unsigned bits,unsigned cbits);
static void outlength(unsigned cb);
static void mrci1outsingle(unsigned ch);
static void mrci1outstring(unsigned disp,unsigned cb);
static void mrci2outsingle(unsigned ch);
static void mrci2outstring(unsigned disp,unsigned cb);
/* decompression internal functions */
static unsigned getbit(void);
static unsigned getbits(unsigned cbits);
static void expandstring(unsigned char FAR **ppchout,unsigned disp,
unsigned cb);
/*
* (compress) Reset the hash tables between blocks.
*/
static void inithash(void)
{
unsigned FAR *entry;
int i;
entry = ahash;
i = CHASH;
do
{
*entry++ = (unsigned) -1; /* Mark all entries as empty */
} while (--i);
}
/*
* (compress) Add a character to compressed output buffer.
*/
static void charbuf(unsigned c)
{
if (cCompressed-- == 0) /* make sure there's room */
{
longjmp(bailout,1); /* Data expanding! */
}
*pCompressed++ = (unsigned char) c; /* Put character into buffer */
}
/*
* (compress) Write n bits to the compressed bitstream.
*/
static void putbits(unsigned ab,unsigned cbits)
{
do /* Loop to emit bits */
{
if (cbits > cbitsleft) /* if not enough space */
{
cbits -= cbitsleft; /* doing partial */
abits |= (ab << (8 - cbitsleft));
/* Put bits in output buffer */
ab >>= cbitsleft; /* clip sent bits */
charbuf(abits); /* Emit the buffer */
cbitsleft = 8; /* Reset buffer count */
abits = 0; /* Reset buffer */
}
else /* can do all in one pass */
{
abits |= ((ab & BITMASK(cbits)) << (8 - cbitsleft));
/* Put bits in output buffer */
cbitsleft -= cbits; /* used up some buffer */
if (cbitsleft == 0) /* If buffer full */
{
charbuf(abits); /* Emit the buffer */
cbitsleft = 8; /* Reset buffer count */
abits = 0; /* Reset buffer */
}
break; /* we've done all cbits */
}
} while (cbits); /* repeat until done */
}
/*
* (compress) Encode a length into the compressed stream.
*/
static void outlength(unsigned cb)
{
unsigned alogbits, clogbits;
unsigned avaluebits, cvaluebits;
assert(cb >= 2); /* Length must be at least two */
assert(cb <= MAXMATCH);
if (cb <= 2)
{
alogbits = 1;
clogbits = 1;
cvaluebits = 0;
}
else if (cb <= 4)
{
alogbits = 1 << 1;
clogbits = 2;
avaluebits = cb - 3;
cvaluebits = 1;
}
else if (cb <= 8)
{
alogbits = 1 << 2;
clogbits = 3;
avaluebits = cb - 5;
cvaluebits = 2;
}
else if (cb <= 16)
{
alogbits = 1 << 3;
clogbits = 4;
avaluebits = cb - 9;
cvaluebits = 3;
}
else if (cb <= 32)
{
alogbits = 1 << 4;
clogbits = 5;
avaluebits = cb - 17;
cvaluebits = 4;
}
else if (cb <= 64)
{
alogbits = 1 << 5;
clogbits = 6;
avaluebits = cb - 33;
cvaluebits = 5;
}
else if (cb <= 128)
{
alogbits = 1 << 6;
clogbits = 7;
avaluebits = cb - 65;
cvaluebits = 6;
}
else if (cb <= 256)
{
alogbits = 1 << 7;
clogbits = 8;
avaluebits = cb - 129;
cvaluebits = 7;
}
else /* (cb <= 512) */
{
alogbits = 1 << 8;
clogbits = 9;
avaluebits = cb - 257;
cvaluebits = 8;
}
putbits(alogbits,clogbits);
if (cvaluebits)
{
putbits(avaluebits,cvaluebits);
}
}
/*
* (MRCI1 compress) Encode a literal into the compressed stream.
*/
static void mrci1outsingle(unsigned ch)
{
ch = (ch << 2) | ((ch & 0x80) ? 1 : 2);
putbits(ch,9);
}
/*
* (MRCI2 compress) Encode a literal into the compressed stream.
*/
static void mrci2outsingle(unsigned ch)
{
if (ch & 0x80)
{
putbits((ch << 2) | 3,9);
}
else
{
putbits(ch << 1,8);
}
}
/*
* (MRCI1 compress) Encode a match into the compressed stream.
*/
static void mrci1outstring(unsigned disp,unsigned cb)
{
assert(((cb >= MINMATCH1) && (disp != 0) && (disp < MAXDISPBIG)) ||
((cb == EOB) && (disp == MAXDISPBIG)));
if (disp <= MAXDISPSMALL)
{
putbits(((disp - MINDISPSMALL) << 2),LOGDISPSMALL + 2);
/* Put small displacement */
}
else if (disp <= MAXDISPMED)
{
putbits(((disp - MINDISPMED) << 3) | 3,LOGDISPMED + 3);
/* Put medium displacement */
}
else
{
putbits(((disp - MINDISPBIG) << 3) | 7,LOGDISPBIG + 3);
/* Put big displacement */
}
if (cb != EOB) /* If not an end marker */
{
outlength(cb); /* Emit the match length */
}
}
/*
* (MRCI2 compress) Encode a match into the compressed stream.
*/
static void mrci2outstring(unsigned disp,unsigned cb)
{
assert(((cb >= MINMATCH2) && (disp != 0) && (disp < MAXDISPBIG)) ||
((cb == EOB) && (disp == MAXDISPBIG)));
if (disp <= MAXDISPSMALL)
{
putbits(((disp - MINDISPSMALL) << 3) | 1,LOGDISPSMALL + 3);
/* Put small displacement */
}
else if (disp <= MAXDISPMED)
{
putbits(((disp - MINDISPMED) << 4) | 5,LOGDISPMED + 4);
/* Put medium displacement */
}
else
{
putbits(((disp - MINDISPBIG) << 4) | 13,LOGDISPBIG + 4);
/* Put big displacement */
}
if (cb != EOB) /* If not an end marker */
{
outlength(cb - 1); /* Emit the match length */
}
}
/*
* (MRCI1) MaxCompress
*/
unsigned Mrci1MaxCompress(unsigned char FAR *pchbase,unsigned cchunc,
unsigned char FAR *pchcmpBase,unsigned cchcmpMax)
{
unsigned cchbest; /* Length of best match */
unsigned cchmatch; /* Length of this match */
unsigned ibest; /* Position of best match */
unsigned icur; /* Current position */
unsigned ihash; /* Hash table index */
unsigned ilink; /* Link index */
unsigned char FAR *pch; /* Char pointer */
unsigned char FAR *pch2; /* Char pointer */
unsigned char FAR *pchend; /* End of input (-> last valid) */
unsigned cch; /* per-pass limit */
cbitsleft = 8; /* Buffer is empty */
abits = 0;
pCompressed = pchcmpBase; /* Initialize pointer */
if (cchunc < cchcmpMax)
{
cCompressed = cchunc; /* limit to source size */
}
else
{
cCompressed = cchcmpMax; /* limit to max size offered */
}
if (cCompressed < SIG_SIZE)
{
return((unsigned) -1);
}
*pCompressed++ = 'D';
*pCompressed++ = 'S';
*pCompressed++ = '\x00';
*pCompressed++ = '\x01';
cCompressed -= SIG_SIZE;
pch = pchbase; /* Initialize */
if (cchunc-- == 0)
{
return(0); /* Do nothing to empty buffer */
}
inithash(); /* Initialize tables */
if (setjmp(bailout) != 0) /* If failure */
{
return((unsigned) -1); /* Data expanded */
}
cchbest = 0; /* no match yet */
icur = 0; /* Initialize */
for (cch = SECTOR - 1; cch <= (cchunc + SECTOR - 1); cch += SECTOR)
{
assert(cchbest == 0); /* must always start with no match */
if (cch > cchunc)
{
cch = cchunc; /* limit to exact req count */
}
pchend = &pchbase[cch]; /* Remember end of buffer */
while (icur < cch) /* While at least two chars left */
{
/* update hash tables for this character */
ihash = hash(word(&pchbase[icur]));
/* Get hash index */
ilink = ahash[ihash]; /* Get link index */
ahash[ihash] = icur; /* Remember position */
alink[icur % MAXDISPBIG] = ilink;
/* Chain on rest of list */
/* walk hash chain looking for matches */
while (ilink < icur && icur - ilink <= DISPMAX)
{ /* While link is valid and in range */
pch = &pchbase[icur]; /* Point at first byte */
pch2 = &pchbase[ilink]; /* Point at first byte */
if (pch[cchbest] == pch2[cchbest] && word(pch) == word(pch2))
{ /* If we have a possible best match */
pch += 2; /* Skip first pair */
pch2 += 2; /* Skip first pair */
while (pch <= pchend) /* Loop to find end of match */
{
if (*pch != *pch2++)
{
break; /* Break if mismatch */
}
pch++; /* Skip matching character */
}
if ((cchmatch = (unsigned)(pch - pchbase) - icur) > cchbest)
{ /* If new best match */
cchbest = cchmatch; /* Remember length */
ibest = ilink; /* Remember position */
assert((pch-1) <= pchend);
if (pch > pchend)
{
break; /* Break if we can't do any better */
}
}
}
assert((alink[ilink % MAXDISPBIG] == (unsigned) -1) ||
(alink[ilink % MAXDISPBIG] < ilink));
ilink = alink[ilink % MAXDISPBIG];
/* Get next link */
} /* until end of hash chain reached */
if (cchbest >= MINMATCH1) /* If we have a string match */
{
mrci1outstring(icur - ibest,cchbest);
/* Describe matching string */
#ifdef VXD
if (icur + cchbest >= cch ) /* If end of sector reached */
#else
if (icur + cchbest >= cchunc) /* If end of buffer reached */
#endif
{
icur += cchbest; /* Advance the index */
cchbest = 0; /* reset for next match */
break; /* Done if buffer exhausted */
}
icur++; /* Skip to first unhashed pair */
#ifdef VXD
/* avoid re-seeding all of a big match */
if (cchbest > MAXDISPSMALL)
{ /* If big match */
icur += cchbest - MAXDISPSMALL - 1;
/* Skip ahead */
cchbest = MAXDISPSMALL + 1;
/* Use shorter length */
}
#endif
/* update hash tables for each add't char in string */
ibest = icur % MAXDISPBIG; /* Get current link table index */
while (--cchbest != 0) /* Loop to reseed link table */
{
ihash = hash(word(&pchbase[icur]));
/* Get hash index */
ilink = ahash[ihash]; /* Get link index */
ahash[ihash] = icur++; /* Remember position */
alink[ibest] = ilink; /* Chain on rest of list */
if (++ibest < MAXDISPBIG)
{
continue; /* Loop if we haven't wrapped yet */
}
ibest = 0; /* Wrap to zero */
}
assert(cchbest == 0); /* Counter must be 0 */
}
else
{
mrci1outsingle(pchbase[icur++]);
/* Else output single character */
cchbest = 0; /* Reset counter */
}
}
assert(icur == cch || icur == cch + 1);
/* Must be at or past last character */
if (icur == cch)
{
#ifndef VXD
ihash = hash(word(&pchbase[icur]));
/* Get hash index */
ilink = ahash[ihash]; /* Get link index */
ahash[ihash] = icur; /* Remember position */
alink[icur % MAXDISPBIG] = ilink;
/* Chain on rest of list */
#endif
mrci1outsingle(pchbase[icur++]); /* Output last character */
}
assert(icur == cch + 1); /* Must be past last character */
mrci1outstring(MAXDISPBIG,EOB); /* Put out an end marker */
}
if (cbitsleft != 8)
{
charbuf(abits); /* Flush bit buffer */
}
if ((unsigned) (pCompressed - pchcmpBase) > cchunc)
{
return((unsigned) -1); /* data expanded or not smaller */
}
return(pCompressed - pchcmpBase); /* Return compressed size */
}
/*
* (MRCI2) MaxCompress
*/
unsigned Mrci2MaxCompress(unsigned char FAR *pchbase,unsigned cchunc,
unsigned char FAR *pchcmpBase,unsigned cchcmpMax)
{
unsigned cchbest; /* Length of best match */
unsigned cchmatch; /* Length of this match */
unsigned ibest; /* Position of best match */
unsigned icur; /* Current position */
unsigned ihash; /* Hash table index */
unsigned ilink; /* Link index */
unsigned char FAR *pch; /* Char pointer */
unsigned char FAR *pch2; /* Char pointer */
unsigned char FAR *pchend; /* End of input (-> last valid) */
unsigned cch; /* per-pass limit */
cbitsleft = 8; /* Buffer is empty */
abits = 0;
pCompressed = pchcmpBase; /* Initialize pointer */
if (cchunc < cchcmpMax)
{
cCompressed = cchunc; /* limit to source size */
}
else
{
cCompressed = cchcmpMax; /* limit to max size offered */
}
if (cCompressed < SIG_SIZE)
{
return((unsigned) -1);
}
*pCompressed++ = 'J';
*pCompressed++ = 'M';
*pCompressed++ = '\x00';
*pCompressed++ = '\x01';
cCompressed -= SIG_SIZE;
pch = pchbase; /* Initialize */
if (cchunc-- == 0)
{
return(0); /* Do nothing to empty buffer */
}
inithash(); /* Initialize tables */
if (setjmp(bailout) != 0) /* If failure */
{
return((unsigned) -1); /* Data expanded */
}
cchbest = 0; /* no match yet */
icur = 0; /* Initialize */
for (cch = SECTOR - 1; cch <= (cchunc + SECTOR - 1); cch += SECTOR)
{
assert(cchbest == 0); /* must always start with no match */
if (cch > cchunc)
{
cch = cchunc; /* limit to exact req count */
}
pchend = &pchbase[cch]; /* Remember end of buffer */
while (icur < cch) /* While at least two chars left */
{
/* update hash tables for this character */
ihash = hash(word(&pchbase[icur]));
/* Get hash index */
ilink = ahash[ihash]; /* Get link index */
ahash[ihash] = icur; /* Remember position */
alink[icur % MAXDISPBIG] = ilink;
/* Chain on rest of list */
/* walk hash chain looking for matches */
while (ilink < icur && icur - ilink <= DISPMAX)
{ /* While link is valid and in range */
pch = &pchbase[icur]; /* Point at first byte */
pch2 = &pchbase[ilink]; /* Point at first byte */
if (pch[cchbest] == pch2[cchbest] && word(pch) == word(pch2))
{ /* If we have a possible best match */
pch += 2; /* Skip first pair */
pch2 += 2; /* Skip first pair */
while (pch <= pchend) /* Loop to find end of match */
{
if (*pch != *pch2++)
{
break; /* Break if mismatch */
}
pch++; /* Skip matching character */
}
if ((cchmatch = (unsigned)(pch - pchbase) - icur) > cchbest)
{ /* If new best match */
cchbest = cchmatch; /* Remember length */
ibest = ilink; /* Remember position */
assert((pch-1) <= pchend);
if (pch > pchend)
{
break; /* Break if we can't do any better */
}
}
}
assert((alink[ilink % MAXDISPBIG] == (unsigned) -1) ||
(alink[ilink % MAXDISPBIG] < ilink));
ilink = alink[ilink % MAXDISPBIG];
/* Get next link */
} /* until end of hash chain reached */
if (cchbest >= MINMATCH2) /* If we have a string match */
{
mrci2outstring(icur - ibest,cchbest);
/* Describe matching string */
#ifdef VXD
if (icur + cchbest >= cch ) /* If end of sector reached */
#else
if (icur + cchbest >= cchunc) /* If end of buffer reached */
#endif
{
icur += cchbest; /* Advance the index */
cchbest = 0; /* reset for next match */
break; /* Done if buffer exhausted */
}
icur++; /* Skip to first unhashed pair */
#ifdef VXD
/* avoid re-seeding all of a big match */
if (cchbest > MAXDISPSMALL)
{ /* If big match */
icur += cchbest - MAXDISPSMALL - 1;
/* Skip ahead */
cchbest = MAXDISPSMALL + 1;
/* Use shorter length */
}
#endif
/* update hash tables for each add't char in string */
ibest = icur % MAXDISPBIG; /* Get current link table index */
while (--cchbest != 0) /* Loop to reseed link table */
{
ihash = hash(word(&pchbase[icur]));
/* Get hash index */
ilink = ahash[ihash]; /* Get link index */
ahash[ihash] = icur++; /* Remember position */
alink[ibest] = ilink; /* Chain on rest of list */
if (++ibest < MAXDISPBIG)
{
continue; /* Loop if we haven't wrapped yet */
}
ibest = 0; /* Wrap to zero */
}
assert(cchbest == 0); /* Counter must be 0 */
}
else
{
mrci2outsingle(pchbase[icur++]);
/* Else output single character */
cchbest = 0; /* Reset counter */
}
}
assert(icur == cch || icur == cch + 1);
/* Must be at or past last character */
if (icur == cch)
{
#ifndef VXD
ihash = hash(word(&pchbase[icur]));
/* Get hash index */
ilink = ahash[ihash]; /* Get link index */
ahash[ihash] = icur; /* Remember position */
alink[icur % MAXDISPBIG] = ilink;
/* Chain on rest of list */
#endif
mrci2outsingle(pchbase[icur++]); /* Output last character */
}
assert(icur == cch + 1); /* Must be past last character */
mrci2outstring(MAXDISPBIG,EOB); /* Put out an end marker */
}
if (cbitsleft != 8)
{
charbuf(abits); /* Flush bit buffer */
}
if ((unsigned) (pCompressed - pchcmpBase) > cchunc)
{
return((unsigned) -1); /* data expanded or not smaller */
}
return(pCompressed - pchcmpBase); /* Return compressed size */
}
/*
* (decompress) Get a single bit from the compressed input stream.
*/
static unsigned getbit(void)
{
unsigned bit; /* Bit */
if (cbitsleft) /* If bits available */
{
cbitsleft--; /* Decrement bit count */
bit = abits & 1; /* Get a bit */
abits >>= 1; /* Remove it */
}
else /* no bits available */
{
if (cCompressed-- == 0) /* If buffer empty */
{
longjmp(bailout,1); /* input overrun */
}
cbitsleft = 7; /* Reset count */
abits = *pCompressed++; /* Get a byte */
bit = abits & 1; /* Get a bit */
abits >>= 1; /* Remove it */
}
return(bit); /* Return the bit */
}
/*
* (decompress) Get multiple bits from the compressed input stream.
*/
static unsigned getbits(unsigned cbits)
{
unsigned bits; /* Bits to return */
unsigned cbitsdone; /* number of bits added so far */
unsigned cbitsneeded; /* number of bits still needed */
if (cbits <= cbitsleft) /* If we have enough bits */
{
bits = abits; /* Get the bits */
cbitsleft -= cbits; /* Decrement bit count */
abits >>= cbits; /* Remove used bits */
}
else /* If we'll need to read more bits */
{
bits = 0; /* No bits set yet */
cbitsdone = 0; /* no bits added yet */
cbitsneeded = cbits; /* bits needed */
do
{
if (cbitsleft == 0) /* If no bits ready */
{
if (cCompressed-- == 0) /* count down used */
{
longjmp(bailout,1); /* if input overrun */
}
cbitsleft = 8; /* Reset count */
abits = *pCompressed++; /* Get 8 new bits */
}
bits |= (abits << cbitsdone); /* copy bits for output */
if (cbitsleft >= cbitsneeded) /* if enough now */
{
cbitsleft -= cbitsneeded; /* reduce bits remaining available */
abits >>= cbitsneeded; /* discard used bits */
break; /* got them */
}
else /* if not enough yet */
{
cbitsneeded -= cbitsleft; /* reduce bits still needed */
cbitsdone += cbitsleft; /* increase shift for future bits */
cbitsleft = 0; /* reduce bits remaining available */
}
} while (cbitsneeded); /* go back if more bits needed */
}
return(bits & BITMASK(cbits)); /* Return the bits */
}
/*
* (decompress) Expand a match.
*
* Note: source overwrite is required (so we can't memcpy or memmove)
*/
static void expandstring(unsigned char FAR **ppchout,unsigned disp,
unsigned cb)
{
unsigned char FAR *source;
unsigned char FAR *target;
assert(cb != 0);
target = *ppchout; /* where the bytes go */
source = target - disp; /* where the bytes come from */
*ppchout += cb; /* Update the output pointer */
while (cb--)
{
*target++ = *source++;
}
}
/*
* (MRCI1) Decompress
*/
unsigned Mrci1Decompress(unsigned char FAR *pchin,unsigned cchin,
unsigned char FAR *pchdecBase,unsigned cchdecMax)
{
unsigned b; /* A byte */
unsigned length; /* Length of match */
unsigned disp; /* Displacement */
unsigned char FAR *pchout; /* Output buffer pointer */
abits = 0; /* Bit buffer is empty */
cbitsleft = 0; /* No bits read yet */
pCompressed = pchin; /* setup source pointer */
cCompressed = cchin; /* setup source counter */
if ((cCompressed <= SIG_SIZE) || /* must have a signature */
(*pCompressed++ != 'D') || (*pCompressed++ != 'S'))
{
return((unsigned) -1); /* Data corrupted */
}
pCompressed += 2; /* ignore flags */
cCompressed -= SIG_SIZE;
pchout = pchdecBase; /* Point at output buffer */
if (setjmp(bailout) != 0) /* If failure */
{
return((unsigned) -1); /* Data corrupted */
}
for (;;)
{
b = getbits(2); /* get two bits */
if (b == 1) /* If single byte 128..255 */
{ /* Get the rest of byte */
*pchout++ = (unsigned char) (getbits(7) | 0x80);
continue; /* Next token */
}
if (b == 2) /* If single byte 0..127 */
{ /* Get the rest of byte */
*pchout++ = (unsigned char) getbits(7);
continue; /* Next token */
}
if (b == 0)
{
disp = getbits(6) + MINDISPSMALL;
}
else /* b == 3 */
{
if (getbit() == 0)
{
disp = getbits(8) + MINDISPMED;
}
else
{
disp = getbits(12) + MINDISPBIG;
}
}
if (disp == MAXDISPBIG)
{
if ((unsigned) (pchout - pchdecBase) >= cchdecMax)
{
break; /* End marker found */
}
else
{
continue; /* End sector found */
}
}
length = 0; /* Initialize */
while (getbit() == 0)
{
length++; /* Count the leading zeroes */
}
assert(b <= 15); /* Cannot be too big */
if (length)
{
length = getbits(length) + (1 << length) + 1;
}
else
{
length = 2;
}
expandstring(&pchout,disp,length); /* Copy the match */
}
return((pchout - pchdecBase)); /* Return decompressed size */
}
/*
* (MRCI2) Decompress
*/
unsigned Mrci2Decompress(unsigned char FAR *pchin,unsigned cchin,
unsigned char FAR *pchdecBase,unsigned cchdecMax)
{
unsigned length; /* Length of match */
unsigned disp; /* Displacement */
unsigned char FAR *pchout; /* Output buffer pointer */
abits = 0; /* Bit buffer is empty */
cbitsleft = 0; /* No bits read yet */
pCompressed = pchin; /* setup source pointer */
cCompressed = cchin; /* setup source counter */
if ((cCompressed <= SIG_SIZE) || /* must have a signature */
(*pCompressed++ != 'J') || (*pCompressed++ != 'M'))
{
return((unsigned) -1); /* Data corrupted */
}
pCompressed += 2; /* ignore flags */
cCompressed -= SIG_SIZE;
pchout = pchdecBase; /* Point at output buffer */
if (setjmp(bailout) != 0) /* If failure */
{
return((unsigned) -1); /* Data corrupted */
}
for (;;)
{
if (getbit() == 0) /* literal 00..7F */
{
*pchout++ = (unsigned char) getbits(7);
continue; /* Next token */
}
if (getbit() == 1) /* literal 80..FF */
{
*pchout++ = (unsigned char)(getbits(7) | 0x80);
continue; /* Next token */
}
if (getbit() == 0)
{
disp = getbits(6) + MINDISPSMALL;
}
else
{
if (getbit() == 0)
{
disp = getbits(8) + MINDISPMED;
}
else
{
disp = getbits(12) + MINDISPBIG;
}
}
if (disp == MAXDISPBIG)
{
if ((unsigned) (pchout - pchdecBase) >= cchdecMax)
{
break; /* End marker found */
}
else
{
continue; /* End sector found */
}
}
length = 0; /* Initialize */
while (getbit() == 0)
{
length++; /* Count the leading zeroes */
}
assert(length <= 15); /* Cannot be too big */
if (length)
{
length = getbits(length) + (1 << length) + 1;
}
else
{
length = 2;
}
expandstring(&pchout,disp,length + 1); /* Copy the match */
}
return((pchout - pchdecBase)); /* Return decompressed size */
}