今天工作任务中遇到一个分支任务, 从系统上层传来一个GUID样子的系统内唯一标识用的字符串, 传到驱动后, 只接受一个DWORD值. 想想需要将这个字符串变成DWORD, 那CRC32好了.
从CodeProject上找了一个类CCrc32Dynamic, http://www.codeproject.com/Articles/1671/CRC32-Generating-a-checksum-for-a-file
但是原版Demo是操作文件的, 算一个文件的CRC32. 改了一下CCrc32Dynamic, 添加了一个接口BufferCrc32, 来计算字符串或Buffer的CRC32值.
使用起来很方便.
使用示例:
// string2crc32.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include <tchar.h>
#include <string>
#include <vector>
#include <time.h>
#include "crc/Crc32Dynamic.h"
VOID fnTest();
int _tmain(int argc, _TCHAR* argv[])
{
size_t nCnt = 0;
for(nCnt = 0; nCnt < 6; nCnt++)
{
fnTest();
}
/// run results
/**
0xfcc50d33
0xfcc50d33
0xfcc50d33
0xfcc50d33
0xfcc50d33
0xfcc50d33
*/
getchar();
return 0;
}
VOID fnTest()
{
DWORD dwCrc32 = 0;
TCHAR szMsg[_MAX_PATH];
::ZeroMemory(szMsg, sizeof(szMsg));
_tcscpy(szMsg, _T("12345"));
/// BufferCrc32 这个接口使用起来很舒服
BufferCrc32((BYTE *)szMsg, _tcslen(szMsg) * sizeof(TCHAR), dwCrc32);
_tprintf(_T("0x%2x\n"), dwCrc32);
}
改版的头文件
#ifndef _CRC32DYNAMIC_H_
#define _CRC32DYNAMIC_H_
/// original url form : http://www.codeproject.com/Articles/1671/CRC32-Generating-a-checksum-for-a-file
/// modify by LostSpeed
class CCrc32Dynamic
{
public:
CCrc32Dynamic();
virtual ~CCrc32Dynamic();
void Init(void);
void Free(void);
DWORD BufferCrc32(BYTE * lpcBuffer, size_t nLenBuffer, DWORD &dwCrc32);
protected:
inline void CalcCrc32(const BYTE byte, DWORD &dwCrc32) const;
DWORD *m_pdwCrc32Table;
};
BOOL BufferCrc32(BYTE * lpcBuffer, size_t nLenBuffer, DWORD &dwCrc32);
#endif
改版的实现文件
#include "stdafx.h"
#include <windows.h>
#include <tchar.h>
#include <string>
#include "Crc32Dynamic.h"
//***********************************************
CCrc32Dynamic::CCrc32Dynamic() : m_pdwCrc32Table(NULL)
{
Init();
}
//***********************************************
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)
{
if(NULL != m_pdwCrc32Table)
{
delete m_pdwCrc32Table;
m_pdwCrc32Table = NULL;
}
}
//***********************************************
inline void CCrc32Dynamic::CalcCrc32(const BYTE byte, DWORD &dwCrc32) const
{
dwCrc32 = ((dwCrc32) >> 8) ^ m_pdwCrc32Table[(byte) ^ ((dwCrc32) & 0x000000FF)];
}
DWORD CCrc32Dynamic::BufferCrc32(BYTE * lpcBuffer, size_t nLenBuffer, DWORD &dwCrc32)
{
_ASSERTE(lpcBuffer);
DWORD dwErrorCode = NO_ERROR;
size_t nCrcPos = 0;
dwCrc32 = 0xFFFFFFFF;
try
{
// Is the table initialized?
if(NULL == m_pdwCrc32Table)
throw 0;
while(nCrcPos < nLenBuffer)
{
CalcCrc32(*(lpcBuffer + nCrcPos++), dwCrc32);
}
}
catch(...)
{
// An unknown exception happened, or the table isn't initialized
dwErrorCode = ERROR_CRC;
}
dwCrc32 = ~dwCrc32;
return dwErrorCode;
}
BOOL BufferCrc32(BYTE * lpcBuffer, size_t nLenBuffer, DWORD &dwCrc32)
{
DWORD dwRc = 0;
CCrc32Dynamic crc32;
dwRc = crc32.BufferCrc32(lpcBuffer, nLenBuffer, dwCrc32);
if(ERROR_CRC == dwRc)
{
dwCrc32 = -1;
}
return (ERROR_CRC == dwRc) ? FALSE : TRUE;
}
<2012_0812>
从网上下了一个CRC32的计算器, 看到同一个串计算出的CRC32和我做的这个实验不同.
而且我JAVA同事算出的CRC32和网上下的工具算出的相同...
有空查一下.
<2012_0825>
查到原因了, CRC32初始表和正确的CRC32初始表不一样.
正确的CRC32初始表参考 http://www.codeproject.com/Articles/1444/CRC_32, 初始化表的操作差很多.
还存在编码问题, 在Vs2008工程(我默认的工程设置是Unicode)中输入固定的字符, 比如: _T("1"), 在文件中, 读出来是0x31, 数量是1. 但是在工程中, 读出来是0x31, 0x00, 数量是2.
需要再查一下.
<2012_0826>
在CRC32之前, 将宽字符转成Ansi格式, 算出的CRC32值和网上找到的程序算出的CRC32值相同.
http://www.codeproject.com/Tips/128870/Useful-function-for-conversion-between-MBCS-and-WC
现在看看CRC16怎么算. 也想写个工具来算CRC16和CRC32, 支持文件方式和手工输入字符串.
CodeProject上有个计算各种HASH的Demo, 是计算文件HASH.
http://www.codeproject.com/Articles/3945/ReHash-A-console-based-hash-calculator
这个Demo中的算法以前用过, 只是单独搬了SHA1或MD5.
如果将这个Demo中的HASH类改改, 应该可以做一个带UI的通用HASH计算工具. 比网上找到的现有HASH工具要强大.
CHashManager算出的CRC32和网上下载的CRC32计算器结果相同.
先验证CRC16的结果正确性, 从网上找了2个CRC16计算器, 算出的结果和这个CHashManager算出的结果都不同, 倒...
sourceforge上有个开源工程, http://sourceforge.net/projects/fsumfe/, 支持96种HASH算法, 强大~
从这个工程可以得知, CRC16和CRC32都有多种算法.
CRC16包括: crc16, crc16_ccitt, crc16_ibm, crc16_x25, crc16_xmodem, crc16_zmodem
CRC32包括:crc32, crc32_bzip2, crc32_jamcrc, crc32_mpeg2
但是CHashManager算出的CRC16和fsumfe都不同...
看了algo目录中的crc16*.d文件, 看到不同的CRC16算法的不同, 初步看是CRC参考表不同, CRC算法不同.
而CHashManager算出的啥也不是~~, CRC初始表是fsumfe中定义的crc16, 但是CRC初值不同.
*uCrc16 = (*uCrc16 >> 8) ^ crc16tab[(*uCrc16 ^ *pBuffer++) & 0xFF]; ///<CHashManager
tmp = (tmp >>> 8 ) ^ crctab[(tmp ^ input[i]) & 0xFF];///< fsumfe
CRC16算法差不多, 不过, 改过来, CHashManager算出的结果也不对. 对CHashManager彻底失去兴趣...
现在可以考虑将fsumfe中的HASH算法移植成C++实现, 封装一些HASH算法组件.
这样, 在算HASH校验和时, 就可以选择MD5, SHA1, 累加和,异或和之外的多种HASH算法.
fsumfe是用D语言写的么??, 还好, 看起来和C差不多, 基本能看懂.
.d文件的资料: Source code written in the D programming language; similar to C++, but also influenced by C#, Java, and Eiffel; can be opened and edited in a text editor, but requires a D compiler to be compiled into an executable program..d