/*++ Copyright (C) 1997-2001 Microsoft Corporation Module Name: MRCICLASS.CPP Abstract: Implements the Wrapper class for MRCI 1 & MRCI 2 maxcompress and decompress functions History: paulall 1-Jul-97 Created --*/ #include "precomp.h" #include #include #include #include #include "MRCIclass.h" class CMRCICompressionHeaderV1 { public: char cVersion; //Compression file format char compressionLevel; //Is this a level 1 or level 2 compression DWORD dwReadBufferSize; //Buffer size used to read original file FILETIME ftCreateTime; //Time and date file created __int64 dwOriginalSize; //Original file length // ... for each buffer // CMRCICompressionBlockV1 block; // ... until dwNextBufferSize is 0 }; class CMRCICompressionBlockV1 { public: char bCompressed; //Was this block compressed DWORD dwNextBufferSize; //Size of the proceeding buffer DWORD dwUncompressedBufferSize; //Size needed for uncompress buffer //char[dwNextBufferSize]; //next block is the compression part }; CMRCICompression::CMRCICompression() { } CMRCICompression::~CMRCICompression() { } BOOL CMRCICompression::GetCompressedFileInfo(const wchar_t *pchFile, CompressionLevel &compressionLevel, DWORD &dwReadBufferSize, FILETIME &ftCreateTime, __int64 &dwOriginalSize) { BOOL bStatus = FALSE; int hFile = _wopen(pchFile,_O_BINARY | _O_RDONLY, 0); if (hFile != -1) { CMRCICompressionHeaderV1 header; if (_read(hFile, &header, sizeof(CMRCICompressionHeaderV1)) == sizeof(CMRCICompressionHeaderV1)) { compressionLevel = (CompressionLevel)header.cVersion; dwReadBufferSize = header.dwReadBufferSize; ftCreateTime = header.ftCreateTime; dwOriginalSize = header.dwOriginalSize; //If the version is 0xFF, the file is not valid! if (header.cVersion != 0xFF) bStatus = TRUE; } _close(hFile); } return bStatus; } BOOL CMRCICompression::CompressFile(const wchar_t *pchFileFrom, const TCHAR *pchFileTo, DWORD dwBufferSize, CompressionLevel compressionLevel, CMRCIControl *pControlObject) { BOOL bStatus = FALSE; int fileFrom; int fileTo; //Open the files for processing //============================= fileFrom = _wopen(pchFileFrom,_O_BINARY | _O_RDONLY, 0); fileTo = _wopen(pchFileTo, _O_BINARY | _O_TRUNC | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE); //If open sucessful //================= if ((fileFrom != -1) && (fileTo != -1)) { //DO the compression using the latest and greatest version //======================================================== bStatus = CompressFileV1(fileFrom, fileTo, dwBufferSize, compressionLevel, pControlObject); } //Close the files //=============== if (fileFrom != -1) _close(fileFrom); if (fileTo != -1) _close(fileTo); if (pControlObject && pControlObject->AbortRequested()) { //User requested an abort, so we need to delete the compressed file... _wunlink(pchFileTo); bStatus = FALSE; } return bStatus; } BOOL CMRCICompression::CompressFileV1(int hFileFrom, int hFileTo, DWORD dwBufferSize, CompressionLevel compressionLevel, CMRCIControl *pControlObject) { BOOL bStatus = FALSE; unsigned char *pBufferFrom = new unsigned char[dwBufferSize + 4]; unsigned char *pBufferTo = new unsigned char[dwBufferSize + 4]; if (pBufferFrom && pBufferTo) { //Write the header to the new file //================================ CMRCICompressionHeaderV1 header; header.cVersion = char(0xFF); //INVALID. We write the header back when we have //finished! When we read this, we check to see //if this is invalid. We do not uncompress if it is //this value.... header.compressionLevel = compressionLevel; header.dwReadBufferSize = dwBufferSize; SYSTEMTIME sysTime; GetSystemTime(&sysTime); SystemTimeToFileTime(&sysTime, &header.ftCreateTime); header.dwOriginalSize = _filelengthi64(hFileFrom); if (_write(hFileTo, &header, sizeof(CMRCICompressionHeaderV1)) != sizeof(CMRCICompressionHeaderV1)) { delete [] pBufferFrom; delete [] pBufferTo; bStatus = FALSE; return bStatus; } __int64 remainingFileSize = header.dwOriginalSize; unsigned cbChunk; unsigned cbCompressed; bStatus = TRUE; //While we have some file to write... //=================================== while (remainingFileSize) { //See if we need to abort the compression... if (pControlObject && pControlObject->AbortRequested()) { break; } //Calculate the size of this buffer to compress //============================================= if (remainingFileSize > dwBufferSize) { cbChunk = dwBufferSize; } else { cbChunk = (unsigned) remainingFileSize; } //Read from the source file //========================= if (_read(hFileFrom, pBufferFrom, cbChunk) != (int) cbChunk) { bStatus = FALSE; break; } //Calculate what is left to read //============================== remainingFileSize -= cbChunk; //Compress the buffer //=================== cbCompressed = CompressBuffer(pBufferFrom, cbChunk, pBufferTo, dwBufferSize, compressionLevel); //Create the compression block header CMRCICompressionBlockV1 block; unsigned char *pWriteBuffer; unsigned thisBufferSize; if ((cbCompressed == (unsigned) -1) || (cbCompressed >= cbChunk)) { //This means compression failed or there was no compression... block.bCompressed = FALSE; pWriteBuffer = pBufferFrom; thisBufferSize = cbChunk; } else { block.bCompressed = TRUE; pWriteBuffer = pBufferTo; thisBufferSize = cbCompressed; } block.dwNextBufferSize = thisBufferSize; block.dwUncompressedBufferSize = cbChunk; //Write the block header //====================== if (_write(hFileTo, &block, sizeof(CMRCICompressionBlockV1)) != sizeof(CMRCICompressionBlockV1)) { bStatus = FALSE; break; } //Write the compressed block //========================== if (_write(hFileTo, pWriteBuffer, thisBufferSize) != (int)thisBufferSize) { bStatus = FALSE; break; } } if (pControlObject && pControlObject->AbortRequested()) { //User requested an abort... } else { //Write final block header with zero length buffer marker CMRCICompressionBlockV1 block; block.dwNextBufferSize = 0; block.bCompressed = FALSE; if (_write(hFileTo, &block, sizeof(CMRCICompressionBlockV1)) != -1 && _lseek(hFileTo, 0, SEEK_SET) != -1) { //Write a valid block header to the start with a correct version number header.cVersion = 1; //Set this to the correct version bStatus = _write(hFileTo, &header, sizeof(CMRCICompressionHeaderV1)) != -1; } else bStatus = FALSE; } } //Tidy up delete [] pBufferFrom; delete [] pBufferTo; return bStatus; } unsigned CMRCICompression::CompressBuffer(unsigned char *pFromBuffer, DWORD dwFromBufferSize, unsigned char *pToBuffer, DWORD dwToBufferSize, CompressionLevel compressionLevel) { unsigned cbCompressed; if (compressionLevel == level1) { cbCompressed = Mrci1MaxCompress(pFromBuffer, dwFromBufferSize, pToBuffer, dwToBufferSize); } else { cbCompressed = Mrci2MaxCompress(pFromBuffer, dwFromBufferSize, pToBuffer, dwToBufferSize); } return cbCompressed; } BOOL CMRCICompression::UncompressFile(const wchar_t *pchFromFile, const wchar_t *pchToFile) { BOOL bStatus = FALSE; int fileFrom; int fileTo; //Open the files //============== fileFrom = _wopen(pchFromFile,_O_BINARY | _O_RDONLY, 0); fileTo = _wopen(pchToFile, _O_BINARY | _O_TRUNC | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE); if ((fileFrom != -1) && (fileTo != -1)) { //Read the version... //=================== char cVer; if (_read(fileFrom, &cVer, sizeof(char)) == sizeof(char)) { //Reset the file position to the start //==================================== if (_lseek(fileFrom, 0, SEEK_SET) != -1) { //Call the uncompress with the equivelant method which created //the compression //============================================================ switch(cVer) { case 1: bStatus = UncompressFileV1(fileFrom, fileTo); break; case 0xFF: //INVALID FILE! default: //Unsupported version break; } } } } //CLose the files //=============== if (fileFrom != -1) _close(fileFrom); if (fileTo != -1) _close(fileTo); return bStatus; } BOOL CMRCICompression::UncompressFileV1(int hFileFrom, int hFileTo) { BOOL bStatus = FALSE; unsigned char *pBufferFrom = NULL; unsigned char *pBufferTo = NULL; //Read the header //=============== CMRCICompressionHeaderV1 header; if (_read(hFileFrom, &header, sizeof(CMRCICompressionHeaderV1)) != sizeof(CMRCICompressionHeaderV1)) return FALSE; //Allocate buffers. The read buffer is never buffer than the write buffer //cos if it would have been we saved the uncompressed version! pBufferFrom = new unsigned char[header.dwReadBufferSize + 4]; if (pBufferFrom == 0) return FALSE; pBufferTo = new unsigned char[header.dwReadBufferSize + 4]; if (pBufferTo == 0) { delete [] pBufferFrom; return FALSE; } bStatus = TRUE; while (1) { //Read the block header //===================== CMRCICompressionBlockV1 block; if (_read(hFileFrom, &block, sizeof(CMRCICompressionBlockV1)) != sizeof(CMRCICompressionBlockV1)) { bStatus = FALSE; break; } if (block.dwNextBufferSize == 0) { bStatus = TRUE; break; } //Read the block data //=================== if (_read(hFileFrom, pBufferFrom, block.dwNextBufferSize) != (int)block.dwNextBufferSize) { bStatus = FALSE; break; } unsigned char *pWriteBuffer; unsigned cbChunk, cbUncompressed; //If this block was compressed //============================ if (block.bCompressed) { //Uncompress the block //==================== if ((cbUncompressed = UncompressBuffer(pBufferFrom, block.dwNextBufferSize, pBufferTo, block.dwUncompressedBufferSize, (CompressionLevel)header.compressionLevel)) == (unsigned) -1) { bStatus = FALSE; break; } pWriteBuffer = pBufferTo; cbChunk = cbUncompressed; } else { //Otherwise we use the existing block pWriteBuffer = pBufferFrom; cbChunk = block.dwNextBufferSize; } //Write the file data _write(hFileTo, pWriteBuffer, cbChunk); } //Sanity check the file. It should be the same size as the original //compressed file if (_filelengthi64(hFileTo) != header.dwOriginalSize) { bStatus = FALSE; } //Tidy up delete [] pBufferFrom; delete [] pBufferTo; return bStatus; } unsigned CMRCICompression::UncompressBuffer(unsigned char *pFromBuffer, DWORD dwFromBufferSize, unsigned char *pToBuffer, DWORD dwToBufferSize, CompressionLevel compressionLevel) { unsigned cbCompressed; if (compressionLevel == level1) { cbCompressed = Mrci1Decompress(pFromBuffer, dwFromBufferSize, pToBuffer, dwToBufferSize); } else { cbCompressed = Mrci2Decompress(pFromBuffer, dwFromBufferSize, pToBuffer, dwToBufferSize); } return cbCompressed; }