/*++ Copyright (c) 1989 Microsoft Corporation Module Name: mrcf.c Abstract: This module implements the Mrcf compression engine. Author: Gary Kimura [GaryKi] 21-Jan-1994 Revision History: --*/ #include "ntrtlp.h" #include // 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; // Maximum back-pointer value, also used to indicate end of compressed stream! #define wBACKPOINTERMAX (4415) // 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 MASK_VALID_mds 0x0300 // All other bits must be zero // Local procedure declarations and macros #define minimum(a,b) (a < b ? a : b) // 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 ); NTSTATUS RtlDecompressBufferMrcf ( OUT PUCHAR UncompressedBuffer, IN ULONG UncompressedBufferSize, IN PUCHAR CompressedBuffer, IN ULONG CompressedBufferSize, OUT PULONG FinalUncompressedSize ) /*++ Routine Description: This routine decompresses a buffer of StandardCompressed or MaxCompressed data. Arguments: UncompressedBuffer - buffer to receive uncompressed data UncompressedBufferSize - length of UncompressedBuffer NOTE: UncompressedBufferSize 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 CompressedBufferSize - 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. --*/ { MRCF_BIT_IO WorkSpace; 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 (CompressedBufferSize < sizeof(MDSIGNATURE) || // Must have signature ((PMDSIGNATURE)CompressedBuffer)->sigStamp != MD_STAMP || // Stamp must be OK ((PMDSIGNATURE)CompressedBuffer)->sigType & (~MASK_VALID_mds)) { // Type must be OK *FinalUncompressedSize = 0; return STATUS_BAD_COMPRESSION_BUFFER; } // Skip over the valid signature CompressedBufferSize -= sizeof(MDSIGNATURE); CompressedBuffer += sizeof(MDSIGNATURE); // Set up for decompress, start filling UncompressedBuffer at front i = 0; // Set statics to save parm passing MrcfSetBitBuffer(CompressedBuffer,CompressedBufferSize,&WorkSpace); while (TRUE) { y = MrcfReadNBits(2,&WorkSpace); // 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 ", i= UncompressedBufferSize) { // Done with entire buffer *FinalUncompressedSize = i; return STATUS_SUCCESS; } else { // More to do // Done with a 512-byte chunk continue; } } } } ASSERTMSG("Don't exceed expected length ", i 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; } }