Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

466 lines
14 KiB

/*++
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;
}