/*
**	Command & Conquer Generals Zero Hour(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program is free software: you can redistribute it and/or modify
**	it under the terms of the GNU General Public License as published by
**	the Free Software Foundation, either version 3 of the License, or
**	(at your option) any later version.
**
**	This program is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**	GNU General Public License for more details.
**
**	You should have received a copy of the GNU General Public License
**	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/


#include <iostream>
#include <signal.h>
#ifdef _WINDOWS
#include <process.h> // *MUST* be included before ANY Wnet/Wlib headers if _REENTRANT is defined
#endif

#include "crc.h"

#include "configfile.h"
#include "threadfac.h"

#include "endian.h"

#include "xtime.h"
#include <filed.h>
#include <wstring.h>
#include <wdebug.h>
#include <udp.h>




/***************************************************************************
 * Add_CRC -- Adds a value to a CRC                                        *
 *                                                                         *
 * INPUT:                                                                  *
 *    crc      ptr to crc                                                  *
 *    val      value to add                                                *
 *                                                                         *
 * OUTPUT:                                                                 *
 *    none                                                                 *
 *                                                                         *
 * WARNINGS:                                                               *
 *    none                                                                 *
 *                                                                         *
 * HISTORY:                                                                *
 *   05/09/1995 BRR : Created.                                             *
 *=========================================================================*/
void Add_CRC(unsigned long *crc, unsigned char val)
{
	int hibit;

	//cout << "\t\t" << hex << val;
//	val = htonl(val);
	//cout << " / " << hex << val <<endl;

	if ((*crc) & 0x80000000) {
		hibit = 1;
	} else {
		hibit = 0;
	}

	(*crc) <<= 1;
	(*crc) += val;
	(*crc) += hibit;

	//cout << hex << (*crc) <<endl;
}


void Build_Packet_CRC(unsigned char *buf, int len)
{
	if (len < 5)
	{
		DBGMSG("Ack!  Constructing a packet too small to hold a CRC!");
		return;
	}
	if (!buf)
	{
		DBGMSG("Ack!  Constructing a CRC for a void *");
		return;
	}

	*((unsigned long *)buf) = 0;

	unsigned long *crc_ptr = (unsigned long *)buf;
	unsigned char *packetptr = (unsigned char*) (buf+4);

	len -= 4; // look past CRC

	for (int i=0 ; i<len ; i++) {
		Add_CRC (crc_ptr, *packetptr++);
	}
/*
	int leftover = len & 3;
	if (leftover) {
		unsigned long val = 0;
		unsigned char *c = (unsigned char *)packetptr;
		for (int i=0; i<leftover; i++)
		{
			val += (c[i] << (i*8));
		}
		val = htonl(val);
		Add_CRC (crc_ptr, val);
	}
*/
	*crc_ptr = htonl(*crc_ptr);
}


/***********************************************************************************************
 * Passes_CRC_Check -- Checks the CRC for a packet                                             *
 *                                                                                             *
 *                                                                                             *
 *                                                                                             *
 * INPUT:    ptr to packet                                                                     *
 *                                                                                             *
 * OUTPUT:   true if packet passes CRC check                                                   *
 *                                                                                             *
 * WARNINGS: None                                                                              *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   10/5/99  1:26PM ST : Created                                                              *
 *   1/9/2001 2:21PM MDC: Ripped from RA2 (WinsockInterfaceClass in wsproto.cpp/queue.cpp)     *
 *  1/31/2001 4:30PM MDC: Converted to network-byte-order so Sparc boxes can talk with Intels. *
 *   2/1/2001 4:07PM MDC: Converted back to Intel order to avoid messing with C&C packets      *
 *=============================================================================================*/
bool Passes_CRC_Check(unsigned char *buf, int len)
{
	if (len < 5)
	{
		DBGMSG("Recieved packet too small to contain a CRC");
		return false;
	}
	if (!buf)
	{
		DBGMSG("Ack!  Checking a CRC for a void *");
		return false;
	}

	unsigned long crc = 0;

	unsigned long *crc_ptr = &crc;
	unsigned char *packetptr = (unsigned char*) (buf+4);

	len -= 4; // remove the CRC from packet size - just look at payload

	for (int i=0 ; i<len ; i++) {
		Add_CRC (crc_ptr, *packetptr++);
	}
/*
	int leftover = len & 3;
	if (leftover) {
		unsigned long val = 0;
		unsigned char *c = (unsigned char *)packetptr;
		for (int i=0; i<leftover; i++)
		{
			val += (c[i] << (i*8));
		}
		val = htonl(val);
		Add_CRC (crc_ptr, val);
	}
*/
	crc = htonl(crc);

	if (crc == *((unsigned long *)buf)) {
		return (true);
	}

	DBGMSG("Invalid packet CRC");
	return (false);
}
