summaryrefslogtreecommitdiffstats
path: root/private/utils/ufat/src/mrcf.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/utils/ufat/src/mrcf.c')
-rw-r--r--private/utils/ufat/src/mrcf.c1726
1 files changed, 1726 insertions, 0 deletions
diff --git a/private/utils/ufat/src/mrcf.c b/private/utils/ufat/src/mrcf.c
new file mode 100644
index 000000000..39816b175
--- /dev/null
+++ b/private/utils/ufat/src/mrcf.c
@@ -0,0 +1,1726 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ Mrcf.c
+
+Abstract:
+
+ This module implements the Compress routines for the Double Space File System
+
+Author:
+
+ Gary Kimura [GaryKi] 26-May-1993
+
+Revision History:
+
+--*/
+
+#include <stdio.h>
+#include <nt.h>
+#include "mrcf.h"
+
+//XXX.mjb:
+#define DbgAssert(x) /* nothing */
+
+//
+// The debug macros
+//
+
+#ifdef MRCFDBG
+
+#define DbgDoit(X) {X;}
+#define ChPrint(b) (isprint(b) ? b : '.')
+#define DbgPrint printf
+
+#else
+
+#define DbgDoit(X) {NOTHING;}
+
+#endif // MRCFDBG
+
+
+//
+// Compress this much before each EOS
+//
+
+#define cbCOMPRESSCHUNK (512)
+
+//
+// Maximum back-pointer value, also used to indicate end of compressed stream!
+//
+
+#define wBACKPOINTERMAX (4415)
+
+//
+// bitsEND_OF_STREAM - bits that mark end of compressed stream (EOS)
+//
+// This pattern is used to indicate the end of a "chunk" in a compressed
+// data stream. The Compress code compresses up to 512 bytes, writes
+// this pattern, and continues.
+//
+// NOTE: This diagram is interpreted right to left.
+//
+// ? ---offset----
+//
+// ?.111-1111-1111-1.1.11
+//
+// \---7F---/ \----FF---/
+//
+// This is a 12-bit "match" code with a maximum offset.
+// NOTE: There is no length component!
+//
+// Define the EOS and also say how many bits it is.
+//
+
+#define bitsEND_OF_STREAM (0x7FFF)
+#define cbitsEND_OF_STREAM (15)
+
+//
+// MDSIGNATURE - Signature at start of each compressed block
+//
+// This 4-byte signature is used as a check to ensure that we
+// are decompressing data we compressed, and also to indicate
+// which compression method was used.
+//
+// NOTE: A compressed block consists of one or more "chunks", separated
+// by the bitsEND_OF_STREAM pattern.
+//
+// Byte Word
+// ----------- ---------
+// 0 1 2 3 0 1 Meaning
+// -- -- -- -- ---- ---- ----------------
+// 44 53 00 01 5344 0100 MaxCompression
+// 44 53 00 02 5344 0200 StandardCompression
+//
+// NOTE: The *WORD* values are listed to be clear about the
+// byte ordering!
+//
+
+typedef struct _MDSIGNATURE {
+
+ //
+ // Must be MD_STAMP
+ //
+
+ USHORT sigStamp;
+
+ //
+ // mdsSTANDARD or mdsMAX
+ //
+
+ USHORT sigType;
+
+} MDSIGNATURE;
+typedef MDSIGNATURE *PMDSIGNATURE;
+
+#define MD_STAMP 0x5344 // Signature stamp at start of compressed blk
+#define mdsSTANDARD 0x0200 // StandardCompressed block
+#define MASK_VALID_mds 0x0300 // All other bits must be zero
+
+
+//
+// Local procedure declarations and macros
+//
+
+#define min(a,b) (a < b ? a : b)
+
+//
+// PFNFINDMATCH - Lookup function type for XxxxCompression routines
+//
+
+typedef ULONG (*PFNFINDMATCH) (
+ ULONG UncompressedIndex,
+ PUCHAR UncompressedBuffer,
+ ULONG UncompressedLength,
+ PULONG MatchedStringIndex,
+ PMRCF_STANDARD_COMPRESS WorkSpace
+ );
+
+//
+// Local procedure prototypes
+//
+
+ULONG
+MrcfDoCompress (
+ PUCHAR CompressedBuffer,
+ ULONG CompressedLength,
+ PUCHAR UncompressedBuffer,
+ ULONG UncompressedLength,
+ PFNFINDMATCH FindMatchFunction,
+ PMRCF_STANDARD_COMPRESS WorkSpace
+ );
+
+ULONG
+MrcfCompressChunk (
+ PUCHAR UncompressedBuffer,
+ ULONG UncompressedIndex,
+ ULONG UncompressedLength,
+ PFNFINDMATCH FindMatchFunction,
+ PMRCF_STANDARD_COMPRESS WorkSpace
+ );
+
+ULONG
+MrcfFindMatchStandard (
+ ULONG UncompressedIndex,
+ PUCHAR UncompressedBuffer,
+ ULONG UncompressedLength,
+ PULONG MatchedStringIndex,
+ PMRCF_STANDARD_COMPRESS WorkSpace
+ );
+
+ULONG
+MrcfGetMatchLength (
+ PUCHAR UncompressedBuffer,
+ ULONG MatchIndex,
+ ULONG CurrentIndex,
+ ULONG UncompressedLength
+ );
+
+BOOLEAN
+MrcfEncodeByte (
+ UCHAR b,
+ PMRCF_BIT_IO BitIo
+ );
+
+BOOLEAN
+MrcfEncodeMatch (
+ ULONG off,
+ ULONG cb,
+ PMRCF_BIT_IO BitIo
+ );
+
+VOID
+MrcfSetBitBuffer (
+ PUCHAR pb,
+ ULONG cb,
+ PMRCF_BIT_IO BitIo
+ );
+
+VOID
+MrcfFillBitBuffer (
+ PMRCF_BIT_IO BitIo
+ );
+
+USHORT
+MrcfReadBit (
+ PMRCF_BIT_IO BitIo
+ );
+
+USHORT
+MrcfReadNBits (
+ LONG cbits,
+ PMRCF_BIT_IO BitIo
+ );
+
+BOOLEAN
+MrcfWriteBit (
+ ULONG bit,
+ PMRCF_BIT_IO BitIo
+ );
+
+BOOLEAN
+MrcfWriteNBits (
+ ULONG abits,
+ LONG cbits,
+ PMRCF_BIT_IO BitIo
+ );
+
+ULONG
+MrcfFlushBitBuffer (
+ PMRCF_BIT_IO BitIo
+ );
+
+//**** unconverted routines ****
+
+VOID
+MrcfDoInterMaxPairs (
+ ULONG ibU,
+ PUCHAR pbU,
+ ULONG cbMatch,
+ PVOID WorkSpace
+ );
+
+ULONG
+MrcfDoMaxPairLookup (
+ ULONG ibU,
+ PUCHAR pbU,
+ PVOID WorkSpace
+ );
+
+ULONG
+MrcfFindMatchMax (
+ ULONG ibU,
+ PUCHAR pbU,
+ ULONG cbU,
+ PULONG piPrev,
+ BOOLEAN fLast,
+ PVOID WorkSpace
+ );
+
+
+ULONG
+MrcfDecompress (
+ PUCHAR UncompressedBuffer,
+ ULONG UncompressedLength,
+ PUCHAR CompressedBuffer,
+ ULONG CompressedLength,
+ PMRCF_DECOMPRESS WorkSpace
+ )
+
+/*++
+
+Routine Description:
+
+ This routine decompresses a buffer of StandardCompressed or MaxCompressed
+ data.
+
+Arguments:
+
+ UncompressedBuffer - buffer to receive uncompressed data
+
+ UncompressedLength - length of UncompressedBuffer
+
+ NOTE: UncompressedLength must be the EXACT length of the uncompressed
+ data, as Decompress uses this information to detect
+ when decompression is complete. If this value is
+ incorrect, Decompress may crash!
+
+ CompressedBuffer - buffer containing compressed data
+
+ CompressedLength - length of CompressedBuffer
+
+ WorkSpace - pointer to a private work area for use by this operation
+
+Return Value:
+
+ ULONG - Returns the size of the decompressed data in bytes. Returns 0 if
+ there was an error in the decompress.
+
+--*/
+
+{
+ ULONG cbMatch; // Length of match string
+ ULONG i; // Index in UncompressedBuffer to receive decoded data
+ ULONG iMatch; // Index in UncompressedBuffer of matched string
+ ULONG k; // Number of bits in length string
+ ULONG off; // Offset from i in UncompressedBuffer of match string
+ USHORT x; // Current bit being examined
+ ULONG y;
+
+ //
+ // verify that compressed data starts with proper signature
+ //
+
+ if (CompressedLength < sizeof(MDSIGNATURE) || // Must have signature
+ ((PMDSIGNATURE)CompressedBuffer)->sigStamp != MD_STAMP || // Stamp must be OK
+ ((PMDSIGNATURE)CompressedBuffer)->sigType & (~MASK_VALID_mds)) { // Type must be OK
+
+ return 0;
+ }
+
+ //
+ // Skip over the valid signature
+ //
+
+ CompressedLength -= sizeof(MDSIGNATURE);
+ CompressedBuffer += sizeof(MDSIGNATURE);
+
+ //
+ // Set up for decompress, start filling UncompressedBuffer at front
+ //
+
+ i = 0;
+
+ //
+ // Set statics to save parm passing
+ //
+
+ MrcfSetBitBuffer(CompressedBuffer,CompressedLength,&WorkSpace->BitIo);
+
+ while (TRUE) {
+
+ DbgDoit( DbgPrint("UncompressedOffset i = %3x ",i) );
+ DbgDoit( DbgPrint("CompressedOffset = (%3x.%2x) ", WorkSpace->BitIo.cbBBInitial - WorkSpace->BitIo.cbBB, 16 - WorkSpace->BitIo.cbitsBB) );
+
+ y = MrcfReadNBits(2,&WorkSpace->BitIo);
+
+ //
+ // Check if next 7 bits are a byte
+ // 1 if 128..255 (0x80..0xff), 2 if 0..127 (0x00..0x7f)
+ //
+
+ if (y == 1 || y == 2) {
+
+ DbgAssert(i<UncompressedLength);
+
+ UncompressedBuffer[i] = (UCHAR)((y == 1 ? 0x80 : 0) | MrcfReadNBits(7,&WorkSpace->BitIo));
+
+ DbgDoit( DbgPrint("byte: %02x = '%c'\n",(USHORT)UncompressedBuffer[i],ChPrint(UncompressedBuffer[i])) );
+
+ i++;
+
+ } else {
+
+ //
+ // Have match sequence
+ //
+
+ DbgDoit( DbgPrint("offset(") );
+
+ //
+ // Get the offset
+ //
+
+ if (y == 0) {
+
+ //
+ // next 6 bits are offset
+ //
+
+ off = MrcfReadNBits(6,&WorkSpace->BitIo);
+
+ DbgDoit( DbgPrint("%x): %x",6,off) );
+
+ DbgAssert(off != 0);
+
+ } else {
+
+ x = MrcfReadBit(&WorkSpace->BitIo);
+
+ if (x == 0) {
+
+ //
+ // next 8 bits are offset-64 (0x40)
+ //
+
+ off = MrcfReadNBits(8, &WorkSpace->BitIo) + 64;
+
+ DbgDoit( DbgPrint("%x): %x",8,off) );
+
+ } else {
+
+ //
+ // next 12 bits are offset-320 (0x140)
+ //
+
+ off = MrcfReadNBits(12, &WorkSpace->BitIo) + 320;
+
+ DbgDoit( DbgPrint("%x): %x",12,off) );
+
+ if (off == wBACKPOINTERMAX) {
+
+ //
+ // EOS marker
+ //
+
+ DbgDoit( DbgPrint("; EOS\n") );
+
+ if (i >= UncompressedLength) {
+
+ //
+ // Done with entire buffer
+ //
+
+ DbgDoit( DbgPrint("Uncompressed Length = %x\n",i) );
+
+ return i;
+
+ } else {
+
+ //
+ // More to do
+ // Done with a 512-byte chunk
+ //
+
+ continue;
+ }
+ }
+ }
+ }
+
+ DbgAssert(i<UncompressedLength);
+ DbgAssert(off <= i);
+
+ //
+ // Get the length - logarithmically encoded
+ //
+
+ for (k=0; (x=MrcfReadBit(&WorkSpace->BitIo)) == 0; k++) { NOTHING; }
+
+ DbgAssert(k <= 8);
+
+ if (k == 0) {
+
+ //
+ // All matches at least 2 chars long
+ //
+
+ cbMatch = 2;
+
+ } else {
+
+ cbMatch = (1 << k) + 1 + MrcfReadNBits(k, &WorkSpace->BitIo);
+ }
+
+ DbgDoit( DbgPrint("; length=%x; '",cbMatch) );
+
+ DbgAssert((i - off + cbMatch - 1) <= UncompressedLength);
+
+ //
+ // Copy the matched string
+ //
+
+ iMatch = i - off;
+
+ while ( (cbMatch > 0) && (i<UncompressedLength) ) {
+
+ DbgDoit( DbgPrint("%c",ChPrint(UncompressedBuffer[iMatch])) );
+
+ UncompressedBuffer[i++] = UncompressedBuffer[iMatch++];
+ cbMatch--;
+ }
+
+ DbgDoit( DbgPrint("'\n") );
+
+ DbgAssert(cbMatch == 0);
+ }
+ }
+}
+
+
+ULONG
+MrcfStandardCompress (
+ PUCHAR CompressedBuffer,
+ ULONG CompressedLength,
+ PUCHAR UncompressedBuffer,
+ ULONG UncompressedLength,
+ PMRCF_STANDARD_COMPRESS WorkSpace
+ )
+
+/*++
+
+Routine Description:
+
+ This routine compresses a buffer using the standard compression algorithm.
+
+Arguments:
+
+ CompressedBuffer - buffer to receive compressed data
+
+ CompressedLength - length of CompressedBuffer
+
+ UncompressedBuffer - buffer containing uncompressed data
+
+ UncompressedLength - length of UncompressedBuffer
+
+ WorkSpace - pointer to a private work area for use by this operation
+
+Return Value:
+
+ ULONG - Returns the size of the compressed data in bytes. Returns 0 if
+ the data is not compressible
+
+--*/
+
+{
+ ULONG i,j;
+
+ //
+ // Fill lookup tables with initial values
+ //
+
+ for (i=0; i<256; i++) {
+
+ for (j = 0; j < cMAXSLOTS; j++) {
+
+ WorkSpace->ltX[i][j] = ltUNUSED; // Mark offset look-up entries unused
+ WorkSpace->abChar[i][j] = bRARE; // Mark match char entries unused
+ }
+
+ WorkSpace->abMRUX[i] = mruUNUSED; // MRU pointer = unused
+ }
+
+ //
+ // Do compression, first set type and then do the compression
+ //
+
+ ((PMDSIGNATURE)CompressedBuffer)->sigType = mdsSTANDARD;
+
+ return MrcfDoCompress( CompressedBuffer,
+ CompressedLength,
+ UncompressedBuffer,
+ UncompressedLength,
+ MrcfFindMatchStandard,
+ WorkSpace );
+}
+
+
+//
+// Internal Support Routine
+//
+
+ULONG
+MrcfDoCompress (
+ PUCHAR CompressedBuffer,
+ ULONG CompressedLength,
+ PUCHAR UncompressedBuffer,
+ ULONG UncompressedLength,
+ PFNFINDMATCH FindMatchFunction,
+ PMRCF_STANDARD_COMPRESS WorkSpace
+ )
+
+/*++
+
+Routine Description:
+
+ This routine compresses a data buffer
+
+Arguments:
+
+ CompressedBuffer - buffer to receive compressed data
+
+ CompressedLength - length of CompressedBuffer
+
+ UncompressedBuffer - buffer containing uncompressed data
+
+ UncompressedLength - length of UncompressedBuffer
+
+ FindMatchFunction - matching function
+
+ WorkSpace - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ ULONG - Returns the size of the compressed data in bytes. Returns 0 if
+ the data is not compressible
+
+--*/
+
+{
+ ULONG cbDone; // Count of uncompressed bytes processed so far
+ ULONG cb; // Count of bytes processed in a chunk
+
+ DbgAssert(CompressedLength >= UncompressedLength);
+
+ //
+ // Treat zero-length request specially as Not compressible
+ //
+
+ if (UncompressedLength == 0) { return 0; }
+
+ //
+ // Write signature to compressed data block
+ //
+
+ ((PMDSIGNATURE)CompressedBuffer)->sigStamp = MD_STAMP;
+
+ CompressedLength -= sizeof(MDSIGNATURE);
+ CompressedBuffer += sizeof(MDSIGNATURE);
+
+ //
+ // Set statics to save parm passing
+ //
+
+ MrcfSetBitBuffer(CompressedBuffer, CompressedLength, &WorkSpace->BitIo);
+
+ //
+ // Start with first chunk
+ // and process entire buffer
+ //
+
+ cbDone = 0;
+
+ while (cbDone < UncompressedLength) {
+
+ //
+ // Compress a chunk
+ //
+
+ cb = MrcfCompressChunk( UncompressedBuffer,
+ cbDone,
+ UncompressedLength,
+ FindMatchFunction,
+ WorkSpace );
+
+ //
+ // Check if we could not compress, i.e., Not compressible
+ //
+
+ if (cb == 0) { return 0; }
+
+ cbDone += cb;
+
+ if (FALSE) { //**** if (WorkSpace->fMaxCmp) {
+
+ //
+ // MAXCMP check
+ //
+
+ if ((cbDone < UncompressedLength) && (WorkSpace->BitIo.cbBB < 586)) { return 0; }
+
+ } else {
+
+ //
+ // RCOMP check
+ //
+
+ //**** if (WorkSpace->BitIo.cbBB <= 586) { return 0; }
+ }
+ }
+
+ DbgAssert(cbDone == UncompressedLength);
+
+ //
+ // Make sure we saved some space
+ //
+
+ cb = sizeof(MDSIGNATURE) + MrcfFlushBitBuffer( &WorkSpace->BitIo );
+
+ if (TRUE) { //**** if (!WorkSpace->fMaxCmp) {
+
+ if (cb+8 >= UncompressedLength) { return 0; }
+ }
+
+ if (cb < UncompressedLength) {
+
+ return cb;
+
+ } else {
+
+ return 0;
+ }
+}
+
+
+//
+// Internal Support Routine
+//
+
+ULONG
+MrcfCompressChunk (
+ PUCHAR UncompressedBuffer,
+ ULONG UncompressedIndex,
+ ULONG UncompressedLength,
+ PFNFINDMATCH FindMatchFunction,
+ PMRCF_STANDARD_COMPRESS WorkSpace
+ )
+
+/*++
+
+Routine Description:
+
+ This routine compresses a chunk of uncompressed data
+
+Arguments:
+
+ UncompressedBuffer - buffer containing uncompressed data
+
+ UncompressedIndex - index in UncompressedBuffer to start compressing (0 => first byte)
+
+ UncompressedLength - length of UncompressedBuffer
+
+ FindMatchFunction - matching function
+
+ WorkSpace - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ ULONG - Returns the non-zero count of uncompressed bytes processed.
+ Returns 0 if the data is not compressible
+
+--*/
+
+{
+ UCHAR b1; // First byte of pair
+ UCHAR b2; // Second byte of pair
+ ULONG cbChunk; // Count of bytes in chunk to compress
+ ULONG cbMatch; // Count of bytes matched
+ ULONG cbUChunk; // Phony buffer length, for compressing this chunk
+ BOOLEAN fLast; // TRUE if this is the last chunk
+ ULONG i; // Index in byte stream being compressed
+ ULONG iPrev; // Previous table entry
+
+ DbgAssert(UncompressedLength > 0);
+ DbgAssert(UncompressedBuffer != 0);
+ DbgAssert(UncompressedIndex < UncompressedLength);
+
+ //
+ // Only compress one chunk
+ //
+
+ cbChunk = min((UncompressedLength-UncompressedIndex),cbCOMPRESSCHUNK);
+
+ //
+ // Limit to chunk length
+ //
+
+ cbUChunk = UncompressedIndex + cbChunk;
+
+ DbgAssert(cbUChunk <= UncompressedLength);
+
+ //
+ // TRUE if last chunk of buffer
+ //
+
+ fLast = (cbUChunk == UncompressedLength);
+
+ //
+ // Limit to chunk length
+ //
+
+ UncompressedLength = cbUChunk;
+
+ //
+ // Scan each pair of bytes
+ //
+
+ //
+ // First byte of input
+ //
+
+ b2 = UncompressedBuffer[UncompressedIndex];
+
+ //
+ // Process all bytes in chunk
+ //
+
+ for (i=UncompressedIndex+1; i<UncompressedLength; ) {
+
+ //
+ // Set Last byte, Next byte, and find a match
+ //
+
+ b1 = b2;
+ b2 = UncompressedBuffer[i];
+
+ cbMatch = (*FindMatchFunction)(i,UncompressedBuffer,UncompressedLength,&iPrev,WorkSpace);
+
+ //
+ // Check if we got match
+ //
+
+ if (cbMatch >= 2) {
+
+ DbgDoit( DbgPrint("<Match>: '%c%c' at offset %x for length %x\n",
+ ChPrint(UncompressedBuffer[i-1]),ChPrint(UncompressedBuffer[i]),i-1, cbMatch) );
+
+ //
+ // Pass offset and length, and check for failure (i.e., data incompressible)
+ //
+
+ if (!MrcfEncodeMatch(i-iPrev,cbMatch,&WorkSpace->BitIo)) {
+
+ return 0;
+ }
+
+ //
+ // Now we have to continue with the first pair of bytes
+ // after the string we matched: mmmmmmm12
+ //
+
+ //
+ // i is index of 2nd byte after match!
+ //
+
+ i += cbMatch;
+
+ //
+ // Check if at least 1 byte still to compress, if so
+ // get 1st byte after match, for loop, otherwise put out EOS
+ //
+
+ if (i <= UncompressedLength) {
+
+ b2 = UncompressedBuffer[i-1];
+
+ } else {
+
+ goto WriteEOS;
+ }
+
+ } else {
+
+ //
+ // No match found, Store one byte and continue, and check
+ // for failure (i.e., data incompressible)
+ //
+
+ if (!MrcfEncodeByte(b1,&WorkSpace->BitIo)) {
+ return 0;
+ }
+
+ //
+ // Advance to next byte
+ //
+
+ i++;
+ }
+ }
+
+ //
+ // Store last byte, and again check for failure
+ //
+
+ if (!MrcfEncodeByte(b2,&WorkSpace->BitIo)) {
+
+ return 0;
+ }
+
+WriteEOS:
+
+ //
+ // write out EOS, and check for failure otherwise return how much
+ // data we processed
+ //
+
+ if (!MrcfWriteNBits( bitsEND_OF_STREAM,
+ cbitsEND_OF_STREAM,
+ &WorkSpace->BitIo )) {
+
+ return 0;
+
+ } else {
+
+ return cbChunk;
+ }
+}
+
+
+//
+// Internal Support Routine
+//
+
+ULONG
+MrcfFindMatchStandard (
+ ULONG UncompressedIndex,
+ PUCHAR UncompressedBuffer,
+ ULONG UncompressedLength,
+ PULONG MatchedStringIndex,
+ PMRCF_STANDARD_COMPRESS WorkSpace
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does a standard compression lookup
+
+Arguments:
+
+ UncompressedIndex - index into UncompressedBuffer[] of *2nd* byte of pair to match
+
+ UncompressedBuffer - buffer containing uncompressed data
+
+ UncompressedLength - length of UncompressedBuffer
+
+ MatchedStringIndex - pointer to int to receive index of start of matched string
+
+ WorkSpace - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ ULONG - Returns length of match. If the return value is >= 2 then
+ *MatchedStringIndex = index of matched string (*2nd* byte in pair).
+ Otherwise the match length is 0 or 1
+
+--*/
+
+{
+ ULONG i;
+ ULONG iMRU;
+ ULONG iChar;
+ ULONG iPrev;
+
+ //
+ // Are there exactly two bytes left? If so then do not check for match.
+ //
+
+ if (UncompressedIndex == (UncompressedLength-1)) { return 0; }
+
+ //
+ // 1st char is index to look-up tables
+ //
+
+ iChar = UncompressedBuffer[UncompressedIndex-1];
+
+ //
+ // Can't match if 1st MRU ent is unused
+ //
+
+ if (WorkSpace->abMRUX[iChar] != mruUNUSED) {
+
+ for (i = 0; i < cMAXSLOTS; i++) {
+
+ if (WorkSpace->abChar[iChar][i] == UncompressedBuffer[UncompressedIndex]) {
+
+ iPrev = WorkSpace->ltX[iChar][i];
+ WorkSpace->ltX[iChar][i] = UncompressedIndex;
+
+ if ((UncompressedIndex - iPrev) >= wBACKPOINTERMAX) { return 0; }
+
+ *MatchedStringIndex = iPrev;
+
+ return MrcfGetMatchLength( UncompressedBuffer,
+ iPrev,
+ UncompressedIndex,
+ UncompressedLength );
+ }
+ }
+ }
+
+ //
+ // Cycle MRU index for char
+ // Update char match table
+ // Location of this char pair
+ //
+
+ iMRU = (WorkSpace->abMRUX[iChar] += 1) & (cMAXSLOTS - 1);
+ WorkSpace->abChar[iChar][iMRU] = UncompressedBuffer[UncompressedIndex];
+ WorkSpace->ltX[iChar][iMRU] = UncompressedIndex;
+
+ return 0;
+}
+
+
+//
+// Internal Support Routine
+//
+
+ULONG
+MrcfGetMatchLength (
+ PUCHAR UncompressedBuffer,
+ ULONG MatchIndex,
+ ULONG CurrentIndex,
+ ULONG UncompressedLength
+ )
+
+/*++
+
+Routine Description:
+
+ Find length of matching strings
+
+Arguments:
+
+ UncompressedBuffer - uncompressed data buffer
+
+ MatchIndex - index of 2nd byte in UncompressedBuffer of match (MatchIndex < CurrentIndex)
+
+ CurrentIndex - index of 2nd byte in UncompressedBuffer that is being compressed
+
+ UncompressedLength - length of UncompressedBuffer
+
+Return Value:
+
+ ULONG - Returns length of matching strings (0, or 2 or greater)
+
+--*/
+
+{
+ ULONG cb;
+
+ DbgAssert(MatchIndex >= 0);
+ DbgAssert(MatchIndex < CurrentIndex);
+ DbgAssert(CurrentIndex < UncompressedLength);
+
+ //
+ // Point back to start of both strings
+ //
+
+ MatchIndex--;
+ CurrentIndex--;
+
+ //
+ // No bytes matched, yet
+ //
+
+ cb = 0;
+
+ //
+ // Scan for end of match, or end of buffer
+ //
+
+ while ((CurrentIndex<UncompressedLength) && (UncompressedBuffer[MatchIndex] == UncompressedBuffer[CurrentIndex])) {
+
+ MatchIndex++;
+ CurrentIndex++;
+ cb++;
+ }
+
+ return cb;
+}
+
+
+//
+// Internal Support Routine
+//
+
+BOOLEAN
+MrcfEncodeByte (
+ UCHAR b,
+ PMRCF_BIT_IO BitIo
+ )
+
+/*++
+
+Routine Description:
+
+ Write one byte to compressed bit stream
+
+Arguments:
+
+ b - byte to write
+
+ BitIo - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ BOOLEAN - TRUE if the bit stream was updated and FALSE if overran buffer
+
+--*/
+
+{
+ ULONG abits;
+
+ DbgDoit( DbgPrint("<MrcfEncodeByte>: byte=%02x '%c'\n",b,ChPrint(b)) );
+
+ abits = ((b & 0x7F) << 2) | ((b < 128) ? 2 : 1);
+
+ //
+ // Write to bitstream
+ //
+
+ return MrcfWriteNBits(abits, 9, BitIo);
+}
+
+
+//
+// Internal Support Routine
+//
+
+BOOLEAN
+MrcfEncodeMatch (
+ ULONG off,
+ ULONG cb,
+ PMRCF_BIT_IO BitIo
+ )
+
+/*++
+
+Routine Description:
+
+ Write a match to compressed bit stream
+
+Arguments:
+
+ off - offset of match (must be greater than 0)
+
+ cb - length of match (must be at least 2)
+
+ BitIo - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ BOOLEAN - TRUE if the compress stream was updated and FALSE if overran buffer
+
+--*/
+
+{
+ ULONG abits;
+ ULONG cbits;
+ ULONG cbSave;
+ ULONG mask;
+
+ DbgAssert(off > 0);
+ DbgAssert(off < wBACKPOINTERMAX);
+ DbgAssert(cb >= 2);
+
+ DbgDoit( DbgPrint("<MrcfEncodeMatch>: off=%x len=%x\n",off,cb) );
+
+ //
+ // Encode the match bits and offset portion
+ //
+
+ if (off < 64) {
+
+ //
+ // Use 6-bit offset encoding
+ //
+
+ abits = (off << 2) | 0x0; // .00 = <offset>+<6-bit>+<match>
+
+ if (!MrcfWriteNBits(abits,6+2,BitIo)) {
+
+ //
+ // Opps overran the compression buffer
+ //
+
+ return FALSE;
+ }
+
+ } else if (off < 320) {
+
+ //
+ // Use 8-bit offset encoding
+ //
+
+ abits = ((off - 64) << 3) | 0x3; // 0.11 = <offset>+<8-bit>+<match>
+
+ if (!MrcfWriteNBits(abits,8+3,BitIo)) {
+
+ //
+ // Opps overran the compression buffer
+ //
+
+ return FALSE;
+ }
+
+ } else { // (off >= 320)
+
+ //
+ // Use 12-bit offset encoding
+ //
+
+ abits = ((off - 320) << 3) | 0x7; // 1.11 = <offset>+<12-bit>+<match>
+
+ if (!MrcfWriteNBits(abits,12+3,BitIo)) {
+
+ //
+ // Opps overran the compression buffer
+ //
+
+ return FALSE;
+ }
+ }
+
+ //
+ // Encode the length logarithmically
+ //
+
+ cb -= 1;
+ cbSave = cb; // Save to get remainder later
+ cbits = 0;
+
+ while (cb > 1) {
+
+ cbits++;
+
+ //
+ // Put out another 0 for the length, and
+ // watch for buffer overflow
+ //
+
+ if (!MrcfWriteBit(0, BitIo)) {
+
+ return FALSE;
+ }
+
+ //
+ // Shift count right (avoid sign bit)
+ //
+
+ ((USHORT)cb) >>= 1;
+ }
+
+ //
+ // Terminate length bit string
+ //
+
+ if (!MrcfWriteBit(1, BitIo)) {
+
+ return FALSE;
+ }
+
+ if (cbits > 0) {
+
+ //
+ // Mask for bits we want, and get remainder
+ //
+
+ mask = (1 << cbits) - 1;
+ abits = cbSave & mask;
+
+ if (!MrcfWriteNBits(abits,cbits,BitIo)) {
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+//
+// Internal Support Routine
+//
+
+VOID
+MrcfSetBitBuffer (
+ PUCHAR pb,
+ ULONG cb,
+ PMRCF_BIT_IO BitIo
+ )
+
+/*++
+
+Routine Description:
+
+ Set statics with coded buffer pointer and length
+
+Arguments:
+
+ pb - pointer to compressed data buffer
+
+ cb - length of compressed data buffer
+
+ BitIo - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ BitIo->pbBB = pb;
+ BitIo->cbBB = cb;
+ BitIo->cbBBInitial = cb;
+ BitIo->cbitsBB = 0;
+ BitIo->abitsBB = 0;
+}
+
+
+//
+// Internal Support Routine
+//
+
+VOID
+MrcfFillBitBuffer (
+ PMRCF_BIT_IO BitIo
+ )
+
+/*++
+
+Routine Description:
+
+ Fill abitsBB from static bit buffer
+
+Arguments:
+
+ BitIo - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DbgAssert((BitIo->cbitsBB) == 0);
+
+ switch (BitIo->cbBB) {
+
+ case 0:
+
+ DbgAssert(FALSE);
+
+ break;
+
+ case 1:
+
+ //
+ // Get last byte and adjust count
+ //
+
+ BitIo->cbitsBB = 8;
+ BitIo->abitsBB = *(BitIo->pbBB)++;
+ BitIo->cbBB--;
+
+ break;
+
+ default:
+
+ //
+ // Get word and adjust count
+ //
+
+ BitIo->cbitsBB = 16;
+ BitIo->abitsBB = *((USHORT *)(BitIo->pbBB))++;
+ BitIo->cbBB -= 2;
+
+ break;
+ }
+}
+
+
+//
+// Internal Support Routine
+//
+
+USHORT
+MrcfReadBit (
+ PMRCF_BIT_IO BitIo
+ )
+
+/*++
+
+Routine Description:
+
+ Get next bit from bit buffer
+
+Arguments:
+
+ BitIo - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ USHORT - Returns next bit (0 or 1)
+
+--*/
+
+{
+ USHORT bit;
+
+ //
+ // Check if no bits available
+ //
+
+ if ((BitIo->cbitsBB) == 0) {
+
+ MrcfFillBitBuffer(BitIo);
+ }
+
+ //
+ // Decrement the bit count
+ // get the bit, remove it, and return the bit
+ //
+
+ (BitIo->cbitsBB)--;
+ bit = (BitIo->abitsBB) & 1;
+ (BitIo->abitsBB) >>= 1;
+
+ return bit;
+}
+
+
+//
+// Internal Support Routine
+//
+
+USHORT
+MrcfReadNBits (
+ LONG cbits,
+ PMRCF_BIT_IO BitIo
+ )
+
+/*++
+
+Routine Description:
+
+ Get next N bits from bit buffer
+
+Arguments:
+
+ cbits - count of bits to get
+
+ BitIo - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ USHORT - Returns next cbits bits.
+
+--*/
+
+{
+ ULONG abits; // Bits to return
+ LONG cbitsPart; // Partial count of bits
+ ULONG cshift; // Shift count
+ ULONG mask; // Mask
+
+ //
+ // Largest number of bits we should read at one time is 12 bits for
+ // a 12-bit offset. The largest length field component that we
+ // read is 8 bits. If this routine were used for some other purpose,
+ // it can support up to 15 (NOT 16) bit reads, due to how the masking
+ // code works.
+ //
+
+ DbgAssert(cbits <= 12);
+
+ //
+ // No shift and no bits yet
+ //
+
+ cshift = 0;
+ abits = 0;
+
+ while (cbits > 0) {
+
+ //
+ // If not bits available get some bits
+ //
+
+ if ((BitIo->cbitsBB) == 0) {
+
+ MrcfFillBitBuffer(BitIo);
+ }
+
+ //
+ // Number of bits we can read
+ //
+
+ cbitsPart = min((BitIo->cbitsBB), cbits);
+
+ //
+ // Mask for bits we want, extract and store them
+ //
+
+ mask = (1 << cbitsPart) - 1;
+ abits |= ((BitIo->abitsBB) & mask) << cshift;
+
+ //
+ // Remember the next chunk of bits
+ //
+
+ cshift = cbitsPart;
+
+ //
+ // Update bit buffer, move remaining bits down and
+ // update count of bits left
+ //
+
+ (BitIo->abitsBB) >>= cbitsPart;
+ (BitIo->cbitsBB) -= cbitsPart;
+
+ //
+ // Update count of bits left to read
+ //
+
+ cbits -= cbitsPart;
+ }
+
+ //
+ // Return requested bits
+ //
+
+ return (USHORT)abits;
+}
+
+
+//
+// Internal Support Routine
+//
+
+BOOLEAN
+MrcfWriteBit (
+ ULONG bit,
+ PMRCF_BIT_IO BitIo
+ )
+
+/*++
+
+Routine Description:
+
+ Write a bit to the bit buffer
+
+Arguments:
+
+ bit - bit to write (0 or 1)
+ BitIo - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ BOOLEAN - returns TRUE if the compresed bit stream was updated and
+ FALSE if overran buffer.
+
+--*/
+
+{
+ DbgAssert((bit == 0) || (bit == 1));
+ DbgAssert((BitIo->cbitsBB) < 16);
+
+ DbgDoit( DbgPrint("<MrcfWriteBit>: bit=%x\n",bit) );
+
+ //
+ // Write one bit
+ //
+
+ (BitIo->abitsBB) |= bit << (BitIo->cbitsBB);
+ (BitIo->cbitsBB)++;
+
+ //
+ // Check if abitsBB is full and write compressed data buffer
+ //
+
+ if ((BitIo->cbitsBB) >= 16) {
+
+ return (MrcfFlushBitBuffer(BitIo) != 0);
+
+ } else {
+
+ return TRUE;
+ }
+}
+
+
+//
+// Internal Support Routine
+//
+
+BOOLEAN
+MrcfWriteNBits (
+ ULONG abits,
+ LONG cbits,
+ PMRCF_BIT_IO BitIo
+ )
+
+/*++
+
+Routine Description:
+
+ Write N bits to the bit buffer
+
+Arguments:
+
+ abits - bits to write
+
+ cbits - count of bits write
+
+ BitIo - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ BOOLEAN - returns TRUE if the compressed bit stream was updated and
+ FALSE if overran buffer
+
+--*/
+
+{
+ LONG cbitsPart;
+ ULONG mask;
+
+ DbgAssert(cbits > 0);
+ DbgAssert(cbits <= 16);
+ DbgAssert((BitIo->cbitsBB) < 16);
+
+ DbgDoit( DbgPrint("<MrcfWriteNBits>: bits=%04x count=%x\n",abits,cbits) );
+
+ while (cbits > 0) {
+
+ //
+ // Number of bits we can write
+ //
+
+ cbitsPart = min(16-(BitIo->cbitsBB), cbits);
+
+ mask = (1 << cbitsPart) - 1;
+
+ //
+ // Move part of bits to buffer
+ //
+
+ (BitIo->abitsBB) |= (abits & mask) << (BitIo->cbitsBB);
+
+ //
+ // Update count of bits written
+ //
+
+ (BitIo->cbitsBB) += cbitsPart;
+
+ //
+ // Check if buffer if full
+ //
+
+ if ((BitIo->cbitsBB) >= 16) {
+
+ //
+ // Write compressed data buffer
+ //
+
+ if (!MrcfFlushBitBuffer(BitIo)) {
+
+ return FALSE;
+ }
+ }
+
+ //
+ // Reduce number of bits left to write and move remaining bits over
+ //
+
+ cbits -= cbitsPart;
+ abits >>= cbitsPart;
+ }
+
+ return TRUE;
+}
+
+
+//
+// Internal Support Routine
+//
+
+ULONG
+MrcfFlushBitBuffer (
+ PMRCF_BIT_IO BitIo
+ )
+
+/*++
+
+Routine Description:
+
+ Write remaining bits to compressed data buffer
+
+Arguments:
+
+ BitIo - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ ULONG - Returns total count of bytes written to the compressed data
+ buffer since the last call to MrcfSetBitBuffer(). Returns 0 if
+ overran buffer
+
+--*/
+
+{
+ DbgAssert((BitIo->cbitsBB) >= 0);
+ DbgAssert((BitIo->cbitsBB) <= 16);
+
+ //
+ // Move bits to the compressed data buffer
+ //
+
+ while ((BitIo->cbitsBB) > 0) {
+
+ //
+ // Process low and high half.
+ // Check if output buffer is out of room
+ //
+
+ if ((BitIo->cbBB) == 0) { return 0; }
+
+ //
+ // Store a byte, adjust the count, get high half, nd adjust
+ // count of bits remaining
+ //
+
+ *(BitIo->pbBB)++ = (UCHAR)((BitIo->abitsBB) & 0xFF);
+ (BitIo->cbBB)--;
+ (BitIo->abitsBB) >>= 8;
+ (BitIo->cbitsBB) -= 8;
+ }
+
+ //
+ // Reset bit buffer, "abitsBB >>= 8" guarantees abitsBB is clear
+ //
+
+ DbgAssert((BitIo->abitsBB) == 0);
+
+ (BitIo->cbitsBB) = 0;
+
+ return (BitIo->cbBBInitial)-(BitIo->cbBB);
+}
+