Click here to Skip to main content
15,886,199 members
Articles / Programming Languages / C++

CRC32: Generating a checksum for a file

Rate me:
Please Sign up or sign in to vote.
4.90/5 (69 votes)
17 Dec 20018 min read 1M   18K   161  
How to generate a CRC32 based on a file
#include "stdafx.h"
#include "Crc32Dynamic.h"
#include <fstream.h>

//***********************************************
CCrc32Dynamic::CCrc32Dynamic() : m_pdwCrc32Table(NULL)
{
}

//***********************************************
CCrc32Dynamic::~CCrc32Dynamic()
{
	Free();
}

//***********************************************
void CCrc32Dynamic::Init(void)
{
	// This is the official polynomial used by CRC32 in PKZip.
	// Often times the polynomial shown reversed as 0x04C11DB7.
	DWORD dwPolynomial = 0xEDB88320;
	int i, j;

	Free();
	m_pdwCrc32Table = new DWORD[256];

	DWORD dwCrc;
	for(i = 0; i < 256; i++)
	{
		dwCrc = i;
		for(j = 8; j > 0; j--)
		{
			if(dwCrc & 1)
				dwCrc = (dwCrc >> 1) ^ dwPolynomial;
			else
				dwCrc >>= 1;
		}
		m_pdwCrc32Table[i] = dwCrc;
	}
}

//***********************************************
void CCrc32Dynamic::Free(void)
{
	delete m_pdwCrc32Table;
	m_pdwCrc32Table = NULL;
}

//***********************************************
inline void CCrc32Dynamic::CalcCrc32(const BYTE byte, DWORD &dwCrc32) const
{
	dwCrc32 = ((dwCrc32) >> 8) ^ m_pdwCrc32Table[(byte) ^ ((dwCrc32) & 0x000000FF)];
}

//***********************************************
bool CCrc32Dynamic::GetFileSizeQW(const HANDLE hFile, QWORD &qwSize)
{
	_ASSERTE(hFile != INVALID_HANDLE_VALUE);

	bool bSuccess = true;

	try
	{
		DWORD dwLo = 0, dwHi = 0;
		dwLo = GetFileSize(hFile, &dwHi);

		if(dwLo == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)
		{
			bSuccess = false;
			qwSize = 0;
		}
		else
		{
			qwSize = MAKEQWORD(dwHi, dwLo);
		}
	}
	catch(...)
	{
		bSuccess = false;
	}

	return bSuccess;
}

//***********************************************
DWORD CCrc32Dynamic::StringCrc32(LPCTSTR szString, DWORD &dwCrc32) const
{
	_ASSERTE(szString);

	DWORD dwErrorCode = NO_ERROR;

	dwCrc32 = 0xFFFFFFFF;

	try
	{
		// Is the table initialized?
		if(m_pdwCrc32Table == NULL)
			throw 0;

		while(*szString != _T('\0'))
		{
			CalcCrc32((BYTE)*szString, dwCrc32);
			szString++;
		}
	}
	catch(...)
	{
		// An unknown exception happened, or the table isn't initialized
		dwErrorCode = ERROR_CRC;
	}

	dwCrc32 = ~dwCrc32;

	return dwErrorCode;
}

//***********************************************
DWORD CCrc32Dynamic::FileCrc32Streams(LPCTSTR szFilename, DWORD &dwCrc32) const
{
#if UNICODE || _UNICODE
	return ERROR_NOT_SUPPORTED;
#else
	_ASSERTE(szFilename);
	_ASSERTE(lstrlen(szFilename));

	DWORD dwErrorCode = NO_ERROR;
	ifstream file;

	dwCrc32 = 0xFFFFFFFF;

	try
	{
		// Is the table initialized?
		if(m_pdwCrc32Table == NULL)
			throw 0;

		// Open the file
		file.open(szFilename, ios::in | ios::nocreate | ios::binary, filebuf::sh_read);
		if(!file.is_open())
			dwErrorCode = file.fail();
		else
		{
			char buffer[MAX_BUFFER_SIZE];
			int nLoop, nCount;
			nCount = file.read(buffer, sizeof(buffer)).gcount();
			while(nCount)
			{
				for(nLoop = 0; nLoop < nCount; nLoop++)
					CalcCrc32(buffer[nLoop], dwCrc32);
				nCount = file.read(buffer, sizeof(buffer)).gcount();
			}

			file.close();
		}
	}
	catch(...)
	{
		// An unknown exception happened, or the table isn't initialized
		dwErrorCode = ERROR_CRC;
	}

	if(file.is_open()) file.close();

	dwCrc32 = ~dwCrc32;

	return dwErrorCode;
#endif
}

//***********************************************
DWORD CCrc32Dynamic::FileCrc32Win32(LPCTSTR szFilename, DWORD &dwCrc32) const
{
	_ASSERTE(szFilename);
	_ASSERTE(lstrlen(szFilename));

	DWORD dwErrorCode = NO_ERROR;
	HANDLE hFile = NULL;

	dwCrc32 = 0xFFFFFFFF;

	try
	{
		// Is the table initialized?
		if(m_pdwCrc32Table == NULL)
			throw 0;

		// Open the file
		hFile = CreateFile(szFilename,
			GENERIC_READ,
			FILE_SHARE_READ,
			NULL,
			OPEN_EXISTING,
			FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_SEQUENTIAL_SCAN,
			NULL);
		if(hFile == INVALID_HANDLE_VALUE)
			dwErrorCode = GetLastError();
		else
		{
			BYTE buffer[MAX_BUFFER_SIZE];
			DWORD dwBytesRead, dwLoop;
			BOOL bSuccess = ReadFile(hFile, buffer, sizeof(buffer), &dwBytesRead, NULL);
			while(bSuccess && dwBytesRead)
			{
				for(dwLoop = 0; dwLoop < dwBytesRead; dwLoop++)
					CalcCrc32(buffer[dwLoop], dwCrc32);
				bSuccess = ReadFile(hFile, buffer, sizeof(buffer), &dwBytesRead, NULL);
			}
		}
	}
	catch(...)
	{
		// An unknown exception happened, or the table isn't initialized
		dwErrorCode = ERROR_CRC;
	}

	if(hFile != NULL) CloseHandle(hFile);

	dwCrc32 = ~dwCrc32;

	return dwErrorCode;
}

//***********************************************
DWORD CCrc32Dynamic::FileCrc32Filemap(LPCTSTR szFilename, DWORD &dwCrc32) const
{
	_ASSERTE(szFilename);
	_ASSERTE(lstrlen(szFilename));

	DWORD dwErrorCode = NO_ERROR;
	HANDLE hFile = NULL, hFilemap = NULL;

	dwCrc32 = 0xFFFFFFFF;

	try
	{
		// Is the table initialized?
		if(m_pdwCrc32Table == NULL)
			throw 0;

		// Open the file
		hFile = CreateFile(szFilename,
			GENERIC_READ,
			FILE_SHARE_READ,
			NULL,
			OPEN_EXISTING,
			FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_SEQUENTIAL_SCAN,
			NULL);
		if(hFile == INVALID_HANDLE_VALUE)
			dwErrorCode = GetLastError();
		else
		{
			QWORD qwFileSize = 0, qwFileOffset = 0;
			DWORD dwByteCount, dwViewSize;
			DWORD dwBaseAddress;

			// Get the file size
			if(!GetFileSizeQW(hFile, qwFileSize))
				dwErrorCode = ERROR_BAD_LENGTH;
			else if(qwFileSize != 0)	// We cannot CRC zero byte files
			{
				// Create the file mapping
				hFilemap = CreateFileMapping(hFile,
					NULL,
					PAGE_READONLY,
					0,
					0,
					NULL);
				if(hFilemap == NULL)
					dwErrorCode = GetLastError();
				else
				{
					LPBYTE pByte;

					// Loop while we map a section of the file and CRC it
					while(qwFileSize > 0)
					{
						if(qwFileSize < MAX_VIEW_SIZE)
							dwViewSize = LODWORD(qwFileSize);
						else
							dwViewSize = MAX_VIEW_SIZE;

						dwBaseAddress = (DWORD)MapViewOfFile(hFilemap,
							FILE_MAP_READ,
							HIDWORD(qwFileOffset),
							LODWORD(qwFileOffset),
							dwViewSize);

						dwByteCount = dwViewSize;
						pByte = (LPBYTE)dwBaseAddress;
						while(dwByteCount-- > 0)
						{
							CalcCrc32(*pByte, dwCrc32);
							pByte++;
						}

						UnmapViewOfFile((LPVOID)dwBaseAddress);
						qwFileOffset += dwViewSize;
						qwFileSize -= dwViewSize;
					}
				}
			}
		}
	}
	catch(...)
	{
		// An unknown exception happened, or the table isn't initialized
		dwErrorCode = ERROR_CRC;
	}

	if(hFile != NULL) CloseHandle(hFile);
	if(hFilemap != NULL) CloseHandle(hFilemap);

	dwCrc32 = ~dwCrc32;

	return dwErrorCode;
}

//***********************************************
DWORD CCrc32Dynamic::FileCrc32Assembly(LPCTSTR szFilename, DWORD &dwCrc32) const
{
	_ASSERTE(szFilename);
	_ASSERTE(lstrlen(szFilename));

	DWORD dwErrorCode = NO_ERROR;
	HANDLE hFile = NULL;

	dwCrc32 = 0xFFFFFFFF;

	try
	{
		// Is the table initialized?
		if(m_pdwCrc32Table == NULL)
			throw 0;

		// Open the file
		hFile = CreateFile(szFilename,
			GENERIC_READ,
			FILE_SHARE_READ,
			NULL,
			OPEN_EXISTING,
			FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_SEQUENTIAL_SCAN,
			NULL);
		if(hFile == INVALID_HANDLE_VALUE)
			dwErrorCode = GetLastError();
		else
		{
			BYTE buffer[MAX_BUFFER_SIZE];
			DWORD dwBytesRead;
			BOOL bSuccess = ReadFile(hFile, buffer, sizeof(buffer), &dwBytesRead, NULL);
			while(bSuccess && dwBytesRead)
			{
				// Register use:
				//		eax - CRC32 value
				//		ebx - a lot of things
				//		ecx - CRC32 value
				//		edx - address of end of buffer
				//		esi - address of start of buffer
				//		edi - CRC32 table
				__asm
				{
					// Save the esi and edi registers
					push esi
					push edi

					mov eax, dwCrc32			// Load the pointer to dwCrc32
					mov ecx, [eax]				// Dereference the pointer to load dwCrc32

					mov ebx, this				// Load the CRC32 table
					mov edi, [ebx]CCrc32Dynamic.m_pdwCrc32Table

					lea esi, buffer				// Load buffer
					mov ebx, dwBytesRead		// Load dwBytesRead
					lea edx, [esi + ebx]		// Calculate the end of the buffer

				crc32loop:
					xor eax, eax				// Clear the eax register
					mov bl, byte ptr [esi]		// Load the current source byte
					
					mov al, cl					// Copy crc value into eax
					inc esi						// Advance the source pointer

					xor al, bl					// Create the index into the CRC32 table
					shr ecx, 8

					mov ebx, [edi + eax * 4]	// Get the value out of the table
					xor ecx, ebx				// xor with the current byte

					cmp edx, esi				// Have we reached the end of the buffer?
					jne crc32loop

					// Restore the edi and esi registers
					pop edi
					pop esi

					mov eax, dwCrc32			// Load the pointer to dwCrc32
					mov [eax], ecx				// Write the result
				}
				bSuccess = ReadFile(hFile, buffer, sizeof(buffer), &dwBytesRead, NULL);
			}
		}
	}
	catch(...)
	{
		// An unknown exception happened, or the table isn't initialized
		dwErrorCode = ERROR_CRC;
	}

	if(hFile != NULL) CloseHandle(hFile);

	dwCrc32 = ~dwCrc32;

	return dwErrorCode;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions