/*
 * crc.c -- Cyclic redundancy checksum utilities
 *
 * Copyright (C) 1997 Pretty Good Privacy, Inc.
 *
 * Written by Mark H. Weaver
 *
 * $Id: crc.c,v 1.4 1997/07/05 21:04:33 mhw Exp $
 */

#include "crc.h"

/* CRC-32: 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 */
#define CRC32_POLY	0xedb88320

/* CRC-CCITT: X^16 + X^12 + X^5 + 1 */
#define CRC16_POLY	0x8408

/*
 * Templated Optimized CRC functions
 */

#define DECLARE_CRC_TABLE(wordXX, crcXXTable)								\
	wordXX	crcXXTable[0x100];

#define DEFINE_INIT_CRC_TABLE_FUNC(InitCRCXXTable, CRCXX_POLY,				\
								   wordXX, crcXXTable)						\
	void InitCRCXXTable(void)												\
	{																		\
		int		i, oneBit;													\
		wordXX	crc = 1;													\
																			\
		for (oneBit = 0x80; oneBit > 0; oneBit >>= 1) {						\
			crc = (crc >> 1) ^ ((crc & 1) ? (CRCXX_POLY) : 0);				\
			for (i = 0; i < 0x100; i += 2 * oneBit)							\
				(crcXXTable)[i + oneBit] = (crcXXTable)[i] ^ crc;			\
		}																	\
	}

#define DEFINE_CALC_CRC_FUNC(CalculateCRCXX, wordXX, crcXXTable)			\
	wordXX CalculateCRCXX(wordXX crc, byte const *buffer, size_t length)	\
	{																		\
		while (length--)													\
			crc = (crc >> 8) ^ (crcXXTable)[(crc & 0xFF) ^ (*buffer++)];	\
		return crc;															\
	}

#define DEFINE_REV_CRC_FUNC(ReverseCRCXX, CRCXX_POLY, wordXX, highBitXX)	\
	wordXX ReverseCRCXX(wordXX crc, byte b)									\
	{																		\
		int i;																\
																			\
		for (i = 0; i < 8; i++) {											\
			if (crc & (highBitXX))		/* highBitXX is 2^XX - 1 */			\
				crc = ((crc ^ CRCXX_POLY) << 1) ^ 1;						\
			else															\
				crc <<= 1;													\
		}																	\
		return crc ^ b;														\
	}

DECLARE_CRC_TABLE(word32, crc32Table)
DEFINE_INIT_CRC_TABLE_FUNC(InitCRC32Table, CRC32_POLY, word32, crc32Table)
DEFINE_CALC_CRC_FUNC(CalculateCRC32, word32, crc32Table)
DEFINE_REV_CRC_FUNC(ReverseCRC32, CRC32_POLY, word32, 0x80000000)

DECLARE_CRC_TABLE(word16, crc16Table)
DEFINE_INIT_CRC_TABLE_FUNC(InitCRC16Table, CRC16_POLY, word16, crc16Table)
DEFINE_CALC_CRC_FUNC(CalculateCRC16, word16, crc16Table)
DEFINE_REV_CRC_FUNC(ReverseCRC16, CRC16_POLY, word16, 0x8000)

void InitCRC(void)
{
	InitCRC16Table();
	InitCRC32Table();
}

/*
 * Local Variables:
 * tab-width: 4
 * End:
 * vi: ts=4 sw=4
 * vim: si
 */
