65.9K
CodeProject 正在变化。 阅读更多。
Home

CRC_32

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.50/5 (9投票s)

2001年10月10日

CPOL

3分钟阅读

viewsIcon

152133

downloadIcon

5480

一个实现了 CRC-32 循环冗余校验算法的类(支持多线程和进度条)

引言

我最近需要计算一些非常大的文件的 CRC-32 值,并且希望有一个进度条显示计算进度。我能够从 CreateWindow.com 找到该算法,并对其进行了修改以满足我的需求。我编写的类是 CRC_32 类,该类定义在演示项目包含的 CRC_32.hCRC_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 为零,则发生错误。

© . All rights reserved.