experiment : convert a string to crc32

今天工作任务中遇到一个分支任务, 从系统上层传来一个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算法不同.


经过多次验证, 发现网上下载的单一CRC16计算工具的算法是 crc16_zmodem,

而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


你可能感兴趣的:(exception,String,table,null,byte,任务)