Introduction
I recently needed the ability to calculate a CRC-32 value for
some very large files, and I wanted to have a progress bar
showing the progress of the calculation. I was able to find the
algorithm at CreateWindow.com
that I modified to suit my needs. The class I came up with is the CRC_32
class which is defined in the
CRC_32.h and CRC_32.cpp files included in the demo project.
Testing
This class was not tested with UNICODE builds, nor was it
tested on a network with UNC paths. If you find and fix any bugs,
dropping me a note at pja@telus.net
would be nice.
Known Problem
If the CRC-32 calculations are run in a separate thread, and
the thread is terminated prematurely, a memory leak occurs.
The CRC-32 Algorithm
The first step in calculating the CRC-32 value for a data
object (a file or any in memory data buffer) is to set up the
lookup table. The table consists of 256 unique 32 bit values, one
for each character in the ASCII table (0x00 -> 0xFF). The
table can be declared as a static table in the source code, or it
can be built dynamically at run time. I chose to build the table in
the CRC_32 class constructor
CRC_32::CRC_32()
{
ULONG ulPolynomial = 0x04C11DB7;
for(int i = 0; i <= 0xFF; i++)
{
Table[i] = Reflect(i, 8) << 24;
for (int j = 0; j < 8; j++)
Table[i] = (Table[i] << 1) ^ (Table[i] & (1 << 31) ? ulPolynomial : 0);
Table[i] = Reflect(Table[i], 32);
}
}
ULONG CRC_32::Reflect(ULONG ref, char ch)
{
ULONG value = 0;
for (int i = 1; i < (ch + 1); i++)
{
if (ref & 1)
value |= 1 << (ch - i);
ref >>= 1;
} return value;
}
Now that the lookup table has been initialized, it can be used
to calculate the CRC-32 value of some data by passing the data
through the Calculate()
function.
void CRC_32::Calculate(const LPBYTE buffer, UINT size, ULONG &CRC)
{
LPBYTE pbyte = buffer;
while(size--)
CRC = (CRC >> 8) ^ Table[(CRC & 0xFF) ^ *pbyte++];
}
The initial value of the CRC is set to 0xFFFFFFFF, then it is
passed through the Calculate()
function, and then
the final value is XORed with the initial value to generate the
CRC-32 value for the data
DWORD CRC = 0xFFFFFFFF;
Calculate ((LPBYTE)buffer, size, CRC);
return CRC ^ 0xFFFFFFFF;
User Functions
CRC_32::CRC32()
Constructs the CRC_32 class object
Parameters :
None.
Returns :
Nothing.
DWORD CRC_32::CalcCRC(LPVOID buffer, UINT size, HWND
ProgressWnd/*= NULL*/)
DWORD CRC_32::CalcCRC(LPCTSTR FileName, HWND ProgressWnd/*=
NULL*/)
Calculates the CRC-32 value for the given buffer or file.
Parameters :
buffer [in]
: a pointer to the data bytes.
size [in]
: the size of the buffer.
FileName [in]
: the complete path to the file.
ProgressWnd [in]
: the HWND
of the progress bar.
Returns :
- The CRC-32 value of the buffer or file if the
ProgressWnd
is
not a window.
- The
HANDLE
of the created thread if the ProgressWnd
is a
window.
NULL
if an error occurs.
Note :
ProgressWnd
is passed through the IsWindow()
API
function. If IsWindow()
returns zero, CalcCRC()
will calculate the CRC-32 value directly. If IsWindow()
returns nonzero, CalcCRC()
will start a separate
thread. The thread will send PBM_* progress bar messages to the
ProgressWnd
. When the thread is finished, the thread will send a
WM_CRC_THREAD_DONE
message to the parent window of the
ProgressWnd
(usually a dialog window).
WM_CRC_THREAD_DONE Message
The WM_CRC_THREAD_DONE
message is sent to the parent
window of the Progress bar window passed to the CalcCRC()
function when the thread has finished executing.
- Thread =
(HANDLE)wParam
- CRC32 =
(ULONG)lParam
Thread is the HANDLE of the thread that sent the
WM_CRC_THREAD_DONE
message. CRC32 is the CRC-32 value of the data passed into the
thread. If CRC32 is zero, an error occurred.