#include <all_far.h>

#include "fstdlib.h"

/*******************************************************************
   Crc32

   Generate 32bit CRC for buffer.

   Algorithm got from sources of ZLib.
 *******************************************************************/

static int crc_table_empty = 1;
static DWORD crc_table[256];

static void make_crc_table(void)
{
	DWORD c, n;
	int k;
	DWORD poly; /* polynomial exclusive-or pattern */
	/* terms of polynomial defining this crc (except x^32): */
	static const BYTE p[] = {0, 1, 2, 4, 5, 7, 8, 10, 11, 12, 16, 22, 23, 26};
	/* make exclusive-or pattern from polynomial (0xedb88320L) */
	poly = 0L;

	for (n = 0; n < sizeof(p) / sizeof(BYTE); n++)
		poly|= 1L << (31 - p[n]);

	for (n = 0; n < 256; n++) {
		c = n;

		for (k = 0; k < 8; k++)
			c = c & 1 ? poly ^ (c >> 1) : c >> 1;

		crc_table[n] = c;
	}

	crc_table_empty = 0;
}

/* ========================================================================= */
#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
#define DO2(buf)                                                                                               \
	DO1(buf);                                                                                                  \
	DO1(buf);
#define DO4(buf)                                                                                               \
	DO2(buf);                                                                                                  \
	DO2(buf);
#define DO8(buf)                                                                                               \
	DO4(buf);                                                                                                  \
	DO4(buf);

DWORD WINAPI Crc32(DWORD crc, const BYTE *buf, DWORD len)
{
	if (buf == NULL)
		return 0L;

	if (crc_table_empty)
		make_crc_table();

	crc = crc ^ 0xffffffffL;

	while (len >= 8) {
		DO8(buf);
		len-= 8;
	}

	if (len)
		do {
			DO1(buf);
		} while (--len);

	return crc ^ 0xffffffffL;
}
