|
|
/*++
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 <io.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys\stat.h>
#include "MRCIclass.h"
#include <TCHAR.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 TCHAR *pchFile, CompressionLevel &compressionLevel, DWORD &dwReadBufferSize, FILETIME &ftCreateTime, __int64 &dwOriginalSize) { BOOL bStatus = FALSE; int hFile = _topen(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 TCHAR *pchFileFrom, const TCHAR *pchFileTo, DWORD dwBufferSize, CompressionLevel compressionLevel, CMRCIControl *pControlObject) { BOOL bStatus = FALSE; int fileFrom; int fileTo;
//Open the files for processing
//=============================
fileFrom = _topen(pchFileFrom,_O_BINARY | _O_RDONLY, 0); fileTo = _topen(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...
_tunlink(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 TCHAR *pchFromFile, const TCHAR *pchToFile) { BOOL bStatus = FALSE; int fileFrom; int fileTo;
//Open the files
//==============
fileFrom = _topen(pchFromFile,_O_BINARY | _O_RDONLY, 0); fileTo = _topen(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; }
|