#include #include #include #include #include #include "lztest.h" // // To decompress/compress a block of data the user needs to // provide a work space as an extra parameter to all the exported // procedures. That way the routines will not need to use excessive // stack space and will still be multithread safe // // // Variables for reading and writing bits // typedef struct _MRCF_BIT_IO { USHORT abitsBB; // 16-bit buffer being read LONG cbitsBB; // Number of bits left in abitsBB PUCHAR pbBB; // Pointer to byte stream being read ULONG cbBB; // Number of bytes left in pbBB ULONG cbBBInitial; // Initial size of pbBB } MRCF_BIT_IO; typedef MRCF_BIT_IO *PMRCF_BIT_IO; // // Decompression only needs the bit i/o structure // typedef struct _MRCF_DECOMPRESS { MRCF_BIT_IO BitIo; } MRCF_DECOMPRESS; typedef MRCF_DECOMPRESS *PMRCF_DECOMPRESS; // // Standard compression uses a few more field to contain // the lookup table // #define cMAXSLOTS (8) // The maximum number of slots used in the algorithm #define ltUNUSED (0xE000) // Value of unused ltX table entry #define mruUNUSED (0xFF) // Value of unused MRU table entry #define bRARE (0xD5) // Rarely occuring character value typedef struct _MRCF_STANDARD_COMPRESS { MRCF_BIT_IO BitIo; ULONG ltX[256][cMAXSLOTS]; // Source text pointer look-up table UCHAR abChar[256][cMAXSLOTS]; // Character look-up table UCHAR abMRUX[256]; // Most Recently Used ltX/abChar entry } MRCF_STANDARD_COMPRESS; typedef MRCF_STANDARD_COMPRESS *PMRCF_STANDARD_COMPRESS; ULONG MrcfStandardCompress ( PUCHAR CompressedBuffer, ULONG CompressedLength, PUCHAR UncompressedBuffer, ULONG UncompressedLength, PMRCF_STANDARD_COMPRESS WorkSpace ); ULONG MrcfDecompress ( PUCHAR UncompressedBuffer, ULONG UncompressedLength, PUCHAR CompressedBuffer, ULONG CompressedLength, PMRCF_DECOMPRESS WorkSpace ); MRCF_STANDARD_COMPRESS CompressWorkSpace; MRCF_DECOMPRESS DecompressWorkSpace; ULONG CompressMRCF ( IN PUCHAR UncompressedBuffer, IN ULONG UncompressedBufferSize, OUT PUCHAR CompressedBuffer, IN ULONG CompressedBufferSize ) { ULONG FinalCompressedSize; FinalCompressedSize = MrcfStandardCompress( CompressedBuffer, CompressedBufferSize, UncompressedBuffer, UncompressedBufferSize, &CompressWorkSpace ); if (FinalCompressedSize == 0) { strncpy( CompressedBuffer, UncompressedBuffer, UncompressedBufferSize ); return UncompressedBufferSize; } return FinalCompressedSize; } ULONG DecompressMRCF ( OUT PUCHAR UncompressedBuffer, IN ULONG UncompressedBufferSize, IN PUCHAR CompressedBuffer, IN ULONG CompressedBufferSize ) { ULONG FinalUncompressedSize; if (CompressedBufferSize == UncompressedBufferSize) { strncpy( UncompressedBuffer, CompressedBuffer, UncompressedBufferSize ); return UncompressedBufferSize; } FinalUncompressedSize = MrcfDecompress( UncompressedBuffer, UncompressedBufferSize, CompressedBuffer, CompressedBufferSize, &DecompressWorkSpace ); return FinalUncompressedSize; } VOID ResetStatisticsMRCF ( ) { return; } VOID StatisticsMRCF ( ) { return; } ULONG MatchTable[4500][32]; VOID ResetStatisticsMRCFOPT ( ) { memset( MatchTable, 0, sizeof(MatchTable)); return; } VOID StatisticsMRCFOPT ( ) { ULONG i; ULONG j; ULONG k; CHAR s[512]; CHAR t[32]; BOOLEAN BlankLine; ULONG SkipCount; printf("Number of Literal copies = %d\n\n", MatchTable[0][0]); printf("Disp - "); for (i = 1; i < 32; i += 1) { printf("%3d",i); } printf("\n\n"); for (i = 1; i < 4500; i += 1) { strcpy(s," "); BlankLine = TRUE; SkipCount = 0; for (j = 1; j < 32; j += 1) { if (MatchTable[i][j] == 0) { SkipCount += 1; } else { while (SkipCount > 0) { SkipCount -= 1; sprintf(t," "); strcat(s,t); } if (MatchTable[i][j] <= 99) { sprintf(t,"%3d",MatchTable[i][j]); } else if (MatchTable[i][j] <= 1000) { sprintf(t," *"); } else if (MatchTable[i][j] <= 10000) { sprintf(t," **"); } else if (MatchTable[i][j] <= 100000) { sprintf(t,"***"); } else { sprintf(t,"$$$"); } strcat(s,t); BlankLine = FALSE; } } if (!BlankLine) { printf("%4d -%s\n", i,s); } } for (j = 0, i = 1; i < 128; i += 1) { j += MatchTable[i][2]; } printf("\n"); printf("Sum of 2 byte matches between 1 and 128 offset = %d\n", j); k = 0; for (i = 2048; i < 4500; i += 1) { for (j = 2; j < 32; j+= 1) { k += MatchTable[i][j]; } } printf("Sum of matches of length > 3 beyond 2048 offset = %d\n", k); return; } // // 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 minimum(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 // 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 ); 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 MrcfFindOptimalMatch ( 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 ); 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) { 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) { ASSERTMSG("Don't exceed expected length ", iBitIo)); i++; } else { // // Have match sequence // // // Get the offset // if (y == 0) { // // next 6 bits are offset // off = MrcfReadNBits(6,&WorkSpace->BitIo); ASSERTMSG("offset 0 is invalid ", off != 0); } else { x = MrcfReadBit(&WorkSpace->BitIo); if (x == 0) { // // next 8 bits are offset-64 (0x40) // off = MrcfReadNBits(8, &WorkSpace->BitIo) + 64; } else { // // next 12 bits are offset-320 (0x140) // off = MrcfReadNBits(12, &WorkSpace->BitIo) + 320; if (off == wBACKPOINTERMAX) { // // EOS marker // if (i >= UncompressedLength) { // // Done with entire buffer // return i; } else { // // More to do // Done with a 512-byte chunk // continue; } } } } ASSERTMSG("Don't exceed expected length ", iBitIo)) == 0; k++) { NOTHING; } ASSERT(k <= 8); if (k == 0) { // // All matches at least 2 chars long // cbMatch = 2; } else { cbMatch = (1 << k) + 1 + MrcfReadNBits(k, &WorkSpace->BitIo); } ASSERTMSG("Don't exceed buffer size ", (i - off + cbMatch - 1) <= UncompressedLength); // // Copy the matched string // iMatch = i - off; while ( (cbMatch > 0) && (ipbBB = pb; BitIo->cbBB = cb; BitIo->cbBBInitial = cb; BitIo->cbitsBB = 0; BitIo->abitsBB = 0; } // // 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. // ASSERT(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 = minimum((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 // 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. --*/ { ASSERT((BitIo->cbitsBB) == 0); switch (BitIo->cbBB) { case 0: ASSERTMSG("no bits left in coded buffer!", 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; } } 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, (PFNFINDMATCH)MatchFunction, // 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 ASSERT(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; } } } ASSERT(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 ASSERT(UncompressedLength > 0); ASSERT(UncompressedBuffer != 0); ASSERT(UncompressedIndex < UncompressedLength); // // Only compress one chunk // cbChunk = minimum((UncompressedLength-UncompressedIndex),cbCOMPRESSCHUNK); // // Limit to chunk length // cbUChunk = UncompressedIndex + cbChunk; ASSERT(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= 2) { // // 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 MrcfFindOptimalMatch ( 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 j; ULONG BestMatchedLength; // // Are there exactly two bytes left? If so then do not check for match. // if (UncompressedIndex == (UncompressedLength-1)) { return 0; } BestMatchedLength = 0; for (i = UncompressedIndex - 1; (i > 0) && ((UncompressedIndex - i) < wBACKPOINTERMAX); i -= 1) { j = MrcfGetMatchLength( UncompressedBuffer, i, UncompressedIndex, UncompressedLength ); if (j > BestMatchedLength) { BestMatchedLength = j; *MatchedStringIndex = i; } } if (BestMatchedLength == 0) { MatchTable[0][0] += 1; } else { if (BestMatchedLength < 32) { MatchTable[UncompressedIndex - *MatchedStringIndex][BestMatchedLength] += 1; } else { MatchTable[UncompressedIndex - *MatchedStringIndex][127] += 1; } } return BestMatchedLength; } // // 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; ASSERT(MatchIndex >= 0); ASSERT(MatchIndex < CurrentIndex); ASSERT(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 0); ASSERT(off < wBACKPOINTERMAX); ASSERT(cb >= 2); // // Encode the match bits and offset portion // if (off < 64) { // // Use 6-bit offset encoding // abits = (off << 2) | 0x0; // .00 = +<6-bit>+ 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 = +<8-bit>+ 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 = +<12-bit>+ 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 // 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. --*/ { ASSERT((bit == 0) || (bit == 1)); ASSERTMSG("Must be room for at least one bit ", (BitIo->cbitsBB) < 16); // // 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; ASSERT(cbits > 0); ASSERT(cbits <= 16); ASSERTMSG("Must be room for at least one bit ", (BitIo->cbitsBB) < 16); while (cbits > 0) { // // Number of bits we can write // cbitsPart = minimum(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 --*/ { ASSERT((BitIo->cbitsBB) >= 0); ASSERT((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 // ASSERT((BitIo->abitsBB) == 0); (BitIo->cbitsBB) = 0; return (BitIo->cbBBInitial)-(BitIo->cbBB); }