
#ifndef DKUTIL_SIGNATURE_CRC32_HPP
#define DKUTIL_SIGNATURE_CRC32_HPP


#include <dkutil/signature/interface.hpp>

/*! x^{32}+x^{26}+x^{23}+x^{22}+x^{16}+x^{12}+x^{11]+
	   x^{10}+x^8+x^7+x^5+x^4+x^2+x^1+1 */
#define DKUTIL_CRC32POLY1 0x04C11DB7UL
	///DKUTIL_CRC32POLY1の 左右逆転 
#define DKUTIL_CRC32POLY2 0xEDB88320UL 

namespace dkutil{
namespace detail{

class crc32_left{

	static unsigned long crctable[UCHAR_MAX + 1];
	
	
	static void makecrctable(void)
	{
		static bool inited = false;
		unsigned int i, j;
		unsigned long r;
		if(inited){
			return;
		}

		for (i = 0; i <= UCHAR_MAX; i++) {
			r = (unsigned long)i << (32 - CHAR_BIT);
			for (j = 0; j < CHAR_BIT; j++)
				if (r & 0x80000000UL) r = (r << 1) ^ DKUTIL_CRC32POLY1;
				else                  r <<= 1;
			crctable[i] = r & 0xFFFFFFFFUL;
		}
		inited = true;
		
	}

	unsigned long mR;
	unsigned long mResult;
public:
	crc32_left(){
		makecrctable();
		Init();
	}


	static unsigned long signature(const BYTE c[],int n)
	{
		unsigned long r;
		makecrctable();

		r = 0xFFFFFFFFUL;
		while (--n >= 0)
			r = (r << CHAR_BIT) ^ crctable[(unsigned char)(r >> (32 - CHAR_BIT)) ^ *c++];
		return ~r & 0xFFFFFFFFUL;
	}
		///初期化する
	void Init(){
		mR = 0xFFFFFFFFUL;
		mResult = 0;
	}
	///データをぶち込む
	void Load(const BYTE c[], int n){
		while (--n >= 0)
			mR = (mR << CHAR_BIT) ^ crctable[(unsigned char)(mR >> (32 - CHAR_BIT)) ^ *c++];
	}
	/*!
	@note
	Finalを二回呼び出すと不正な値になる。
	*/
	///最後に計算する。@return GetDigestと同じ
	ULONG Final(void){
		mResult  = ~mR & 0xFFFFFFFFUL;
		return mResult;
	}
	///@return 求めた値を返す。
	ULONG GetDigest()const{
		return mResult;
	}
};


struct crc32_right{
	static unsigned long crctable[UCHAR_MAX + 1];
	static void makecrctable(void)
	{
		static bool inited = false;
		unsigned int i, j;
		unsigned long r;
		if(inited){
			return;
		}

		for (i = 0; i <= UCHAR_MAX; i++) {
			r = i;
			for (j = 0; j < CHAR_BIT; j++)
				if (r & 1) r = (r >> 1) ^ DKUTIL_CRC32POLY2;
				else       r >>= 1;
			crctable[i] = r;
		}
		inited = true;
	}
	unsigned long mR;
	unsigned long mResult;

public:
	crc32_right(){
		makecrctable();
		Init();
	}


	static unsigned long signature(const BYTE c[],int n)
	{
		unsigned long r;
		makecrctable();

		r = 0xFFFFFFFFUL;
		while (--n >= 0)
			r = (r >> CHAR_BIT) ^ crctable[(unsigned char)r ^ *c++];
		return r ^ 0xFFFFFFFFUL;
	}
	///初期化する
	void Init(){
		mR = 0xFFFFFFFFUL;
		mResult = 0;
	}
	///データをぶち込む
	void Load(const BYTE c[], int n){
		while (--n >= 0)
			mR = (mR >> CHAR_BIT) ^ crctable[(unsigned char)mR ^ *c++];
	}
	/*!
	@note
	Finalを二回呼び出すと不正な値になる。
	*/
	///最後に計算する。@return GetDigestと同じ
	ULONG Final(void){
		mResult  = mR ^ 0xFFFFFFFFUL;
		return mResult;
	}
	///@return 求めた値を返す。
	ULONG GetDigest()const{
		return mResult;
	}
};

}//end of detail
}//end of dkutil
	
#if defined(DKUTIL_NOT_USE_SELF_LIBRARY) && !defined( DKUTIL_SIGNATURE_CRC_CPP )
#include <dkutil/signature/crc.cpp>
#endif



#endif