CArchiveExt - Enhanced archiving class with encryption and compression

CArchiveExt is enhanced archiving class derived from CArchive. It have 2 additional features: encryption and compression. CArchiveExt class may be used instead of CArchive class in serialization.

The class uses the zlib source code. The 'zlib' general purpose compression library version 1.1.3, July 9th, 1998. Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler.


To use CArchiveExt, do the following:
  • include CArchiveEx.h in your project
  • link your project with zlib.lib
  • use constructor CArchiveExt instead of CArchive
  • use standart functions of CArchive class for serialization, loading, saving etc.



CArchiveEx.h file:

struct ArcHeader
{
	_TCHAR		chSignature[3];		// "akz" ;-) (it may be replaced anyhow)
	BYTE		uchFlag;		// 0-plane text; 1-compression; 2-encryption; 
						// 3-compression & encryption;
	DWORD		dwOriginalSize;		// decompression size
	ULONG		ulCRC;			// CRC
};

class CArchiveExt : public CArchive
{
	CString 	m_strKey;		// Key for the encryption algorithm. 
	BOOL		m_bCompress;		// If TRUE then compress or de-compress the data
	CFile*		m_pFileTmp; 		// temporary file
	BYTE*		m_pBuf;

public:
	CArchiveExt(CFile* pFile, UINT nMode, int nBufSize = 4096, void* lpBuf = NULL, CString Key = _TEXT(""), BOOL bCompress = FALSE);
	// if Key is not empty then encrypt or decrypt the data
	// if bCompress is TRUE then compress or de-compress the data

	virtual ~CArchiveExt();

	virtual void Close();
	virtual void Abort();

protected:
	virtual bool Crypto(LPSTR lpstrBuffer, ULONG ulLen, CString strKey = _TEXT(""));
	// This function may be overrided with your favourite algorithm
	// lpstrBuffer 	- pointer to data
	// ulLen	- size of buffer
	// strKey	- key of encription algorithm
};

CArchiveEx.cpp file:

CString signature = _TEXT("akz");

// constructor
CArchiveExt::CArchiveExt(CFile* pFile, UINT nMode, int nBufSize, void* lpBuf, CString Key, BOOL bCompress)
			:CArchive(pFile, nMode, nBufSize, lpBuf)
{
	m_strKey = Key;
	m_bCompress = bCompress;
	m_pFileTmp = m_pFile;

// for simplicity, if encrypt is enabled then compress is enabled too
	if(!Key.IsEmpty())
		m_bCompress = TRUE;

	if(m_bCompress)
	{
// if loading exist file
		if(IsLoading())
		{
	 	    	int iComprErr;
			CString Contents, Compress;
			_TCHAR sign[4];
			DWORD dwFileSize = m_pFileTmp -> GetLength();
			LPSTR szContents = Contents.GetBuffer(dwFileSize);
			DWORD dwComprSize;

			m_pBuf = (BYTE *)new char[dwFileSize];
			m_pFile = new CMemFile(m_pBuf, dwFileSize, 1024);

			m_pFileTmp -> SeekToBegin();

// read header
			ArcHeader ahead;
			m_pFileTmp -> Read(&ahead, sizeof(ahead));

			sign[0] = ahead.chSignature[0];
			sign[1] = ahead.chSignature[1];
			sign[2] = ahead.chSignature[2];
			sign[3] = _TEXT('\0');

// if compress and encrypt is enabled, and file contains signature
			if(signature == sign)
			{
				dwFileSize = m_pFileTmp -> ReadHuge(szContents, dwFileSize);

// if file compressed and encryption
				if(ahead.uchFlag == 3)
				{
					ULONG crc = adler32(0L, Z_NULL, 0);
// decription
					Crypto(szContents, dwFileSize, m_strKey);

// compute CRC decripted file
					crc = adler32(crc, (const unsigned char*)szContents, dwFileSize);
					if(crc != ahead.ulCRC)
					{
						AfxMessageBox("Password incorrect!!!");
						Abort();
						AfxThrowUserException();
					}
				}

// size of decompressed file
				dwComprSize = ahead.dwOriginalSize;
				LPSTR szCompress = Compress.GetBuffer(dwComprSize);
				iComprErr = uncompress((LPBYTE)szCompress, &dwComprSize, (LPBYTE)szContents, dwFileSize);
				ASSERT(iComprErr == Z_OK);

				m_pFile -> WriteHuge(szCompress, dwComprSize);
			}
			else
// if compress and encrypt is enabled, but file does not contain signature
			{
				m_pFileTmp -> SeekToBegin();
				dwFileSize = m_pFileTmp -> ReadHuge(szContents, dwFileSize);
				m_pFile -> WriteHuge(szContents, dwFileSize);
			}
			m_pFile -> SeekToBegin();
		}
		else
		{
// if save file
			m_pBuf = (BYTE *)new char[1024];
			m_pFile = new CMemFile(m_pBuf, 1024, 1024);
		}
	}
}

CArchiveExt::~CArchiveExt()
{
	if (m_pFile != NULL && !(m_nMode & bNoFlushOnDelete))
		Close();

	Abort();    // abort completely shuts down the archive
}

void CArchiveExt::Abort()
{
	if(m_bCompress && m_pFile != NULL)
	{
		m_pBuf = (BYTE *)(((CMemFile*)m_pFile)->Detach());
		delete m_pBuf;
		m_pFile -> Close();
		delete m_pFile;
	}

	CArchive::Abort();
}

void CArchiveExt::Close()
{
	ASSERT_VALID(m_pFile);
	Flush();

	if(m_bCompress)
	{
// if save file
		if(IsStoring())
		{
			int iComprErr;
			CString Compress;
			DWORD dwFileSize = m_pFile -> GetLength();
			DWORD dwComprSize;

			m_pBuf = (BYTE *)(((CMemFile*)m_pFile)->Detach());
			dwComprSize = (DWORD)(dwFileSize * 1.1) + 12;
			LPSTR szCompress = Compress.GetBuffer(dwComprSize);
			iComprErr = compress((LPBYTE)szCompress, &dwComprSize, m_pBuf, dwFileSize);
			ASSERT(iComprErr == Z_OK);

			ULONG crc = adler32(0L, Z_NULL, 0);
			crc = adler32(crc, (const unsigned char*)szCompress, dwComprSize);
			Crypto(szCompress, dwComprSize, m_strKey);

			ArcHeader ahead;
			ahead.chSignature[0] = _TEXT('a');
			ahead.chSignature[1] = _TEXT('k');
			ahead.chSignature[2] = _TEXT('z');
			ahead.dwOriginalSize = dwFileSize;
			ahead.uchFlag = m_strKey.IsEmpty()?1:3;
			ahead.ulCRC = crc;

			m_pFileTmp -> Write(&ahead, sizeof(ahead));
			m_pFileTmp -> WriteHuge(szCompress, dwComprSize);
		}
		else
		{
			m_pBuf = (BYTE *)(((CMemFile*)m_pFile)->Detach());
		}
		delete m_pBuf;
		m_pFile -> Close();
		delete m_pFile;
	}
	m_pFile = NULL;
}

bool CArchiveExt::Crypto(LPSTR lpstrBuffer, ULONG ulLen, CString strKey)
{
	if(strKey.IsEmpty())
		return FALSE;
	
	int nLenKey = strKey.GetLength();

	for(ULONG ii=0; ii<ulLen; ii++)
	{
		for(int jj=0; jj<nLenKey; jj++)
		{
			lpstrBuffer[ii] ^= strKey[jj];
		}
	}
	return TRUE;
}

Download demo project - 86 KB

Download source - 40 KB

Date Last Updated: May 7, 1999


Comments

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: September 10, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild". This loop of continuous delivery and continuous feedback is …

  • Java developers know that testing code changes can be a huge pain, and waiting for an application to redeploy after a code fix can take an eternity. Wouldn't it be great if you could see your code changes immediately, fine-tune, debug, explore and deploy code without waiting for ages? In this white paper, find out how that's possible with a Java plugin that drastically changes the way you develop, test and run Java applications. Discover the advantages of this plugin, and the changes you can expect to see …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds