/* * Microsoft Confidential * Copyright (c) 1994 Microsoft Corporation * All Rights Reserved. * * MRCICODE.C * * MRCI 1 & MRCI 2 maxcompress and decompress functions */ #include "mrcicode.h" /* prototype verification */ #include /* use NDEBUG to inhibit */ #include /* 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 (above will work on ALPHA)*/ #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 */ #ifdef BIT16 #define FARBSS _far #else #define FARBSS #endif 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 FARBSS ahash[CHASH]; /* Hash table */ static unsigned FARBSS alink[MAXDISPBIG]; /* Links */ /* compression internal functions */ #ifdef BIT16 #define FAST _near _pascal /* speed up local calls */ #else #define FAST #endif static void FAST inithash(void); static void FAST charbuf(unsigned c); static void FAST putbits(unsigned bits,unsigned cbits); static void FAST outlength(unsigned cb); static void FAST mrci1outsingle(unsigned ch); static void FAST mrci1outstring(unsigned disp,unsigned cb); static void FAST mrci2outsingle(unsigned ch); static void FAST mrci2outstring(unsigned disp,unsigned cb); /* decompression internal functions */ static unsigned FAST getbit(void); static unsigned FAST getbits(unsigned cbits); static void FAST expandstring(unsigned char FAR **ppchout,unsigned disp, unsigned cb); /* * (compress) Reset the hash tables between blocks. */ static void FAST 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 FAST 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 FAST 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 FAST 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 FAST mrci1outsingle(unsigned ch) { ch = (ch << 2) | ((ch & 0x80) ? 1 : 2); putbits(ch,9); } /* * (MRCI2 compress) Encode a literal into the compressed stream. */ static void FAST 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 FAST 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 FAST 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((unsigned int)(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((unsigned int)(pCompressed - pchcmpBase)); /* Return compressed size */ } /* * (decompress) Get a single bit from the compressed input stream. */ static unsigned FAST 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 FAST 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 FAST 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((unsigned int)(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((unsigned int)(pchout - pchdecBase)); /* Return decompressed size */ }