CRC_32
一个实现了 CRC-32 循环冗余校验算法的类(支持多线程和进度条)
引言
我最近需要计算一些非常大的文件的 CRC-32 值,并且希望有一个进度条显示计算进度。我能够从 CreateWindow.com 找到该算法,并对其进行了修改以满足我的需求。我编写的类是 CRC_32
类,该类定义在演示项目包含的 CRC_32.h 和 CRC_32.cpp 文件中。
测试
这个类没有用 UNICODE 版本进行测试,也没有在带有 UNC 路径的网络上进行测试。 如果你发现并修复了任何错误,请给我发个邮件到 pja@telus.net,谢谢。
已知问题
如果在单独的线程中运行 CRC-32 计算,并且线程过早终止,则会发生内存泄漏。
CRC-32 算法
计算数据对象(文件或任何内存中的数据缓冲区)的 CRC-32 值的第一个步骤是设置查找表。 该表由 256 个唯一的 32 位值组成,ASCII 表中的每个字符一个(0x00 -> 0xFF)。 该表可以在源代码中声明为静态表,也可以在运行时动态构建。 我选择在 CRC_32 类构造函数中构建该表。
CRC_32::CRC_32() { // This is the official polynomial used by CRC-32 // in PKZip, WinZip and Ethernet. ULONG ulPolynomial = 0x04C11DB7; // 256 values representing ASCII character codes. 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; // Swap bit 0 for bit 7 // bit 1 for bit 6, etc. for (int i = 1; i < (ch + 1); i++) { if (ref & 1) value |= 1 << (ch - i); ref >>= 1; } return value; }
现在已经初始化了查找表,可以通过 Calculate()
函数传递数据来计算某些数据的 CRC-32 值。
void CRC_32::Calculate(const LPBYTE buffer, UINT size, ULONG &CRC) { // calculate the CRC LPBYTE pbyte = buffer; while(size--) CRC = (CRC >> 8) ^ Table[(CRC & 0xFF) ^ *pbyte++]; }
CRC 的初始值设置为 0xFFFFFFFF,然后通过 Calculate()
函数传递,然后将最终值与初始值进行异或运算,以生成数据的 CRC-32 值。
DWORD CRC = 0xFFFFFFFF; Calculate ((LPBYTE)buffer, size, CRC); return CRC ^ 0xFFFFFFFF;
用户函数
CRC_32::CRC32()
构造 CRC_32 类对象
参数
无。
返回值
无。
DWORD CRC_32::CalcCRC(LPVOID buffer, UINT size, HWND ProgressWnd/*= NULL*/)
DWORD CRC_32::CalcCRC(LPCTSTR FileName, HWND ProgressWnd/*= NULL*/)
计算给定缓冲区或文件的 CRC-32 值。
参数
buffer [in]
: 指向数据字节的指针。
size [in]
: 缓冲区的大小。
FileName [in]
: 文件的完整路径。
ProgressWnd [in]
: 进度条的 HWND
。
返回值
- 如果
ProgressWnd
不是窗口,则为缓冲区或文件的 CRC-32 值。 - 如果
ProgressWnd
是窗口,则为创建的线程的HANDLE
。 - 如果发生错误,则为
NULL
。
注意
ProgressWnd
通过 IsWindow()
API 函数传递。 如果 IsWindow()
返回零,CalcCRC()
将直接计算 CRC-32 值。 如果 IsWindow()
返回非零值,CalcCRC()
将启动一个单独的线程。 该线程将向 ProgressWnd
发送 PBM_* 进度条消息。 线程完成后,该线程将向 ProgressWnd
的父窗口(通常是对话框窗口)发送 WM_CRC_THREAD_DONE
消息。
WM_CRC_THREAD_DONE 消息
当线程完成执行时,WM_CRC_THREAD_DONE
消息会发送到传递给 CalcCRC()
函数的进度条窗口的父窗口。
- 线程 =
(HANDLE)wParam
- CRC32 =
(ULONG)lParam
Thread 是发送 WM_CRC_THREAD_DONE
消息的线程的 HANDLE。 CRC32 是传递给线程的数据的 CRC-32 值。 如果 CRC32 为零,则发生错误。