今天工作任务中遇到一个分支任务, 从系统上层传来一个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
使用示例:
// 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