// FnR.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// The one and only application object

CWinApp theApp;

using namespace std;

FILE *orig, *olk, *rplc;
BYTE *newData, *oldData, *olkData;
__int64 olkOffset, dataSize, olkSize;

void FindAndReplace()
{
	__int64 lastOffset = 0;

	olkOffset = 0;

	fseek(orig, 0, SEEK_END);
	dataSize = ftell(orig) - 128;
	fseek(orig, 128, SEEK_SET);
	fseek(rplc, 128, SEEK_SET);

	newData = (BYTE*) new BYTE[dataSize];
	oldData = (BYTE*) new BYTE[dataSize];
	olkData = (BYTE*) new BYTE[dataSize];

	fread(oldData, sizeof(BYTE), dataSize, orig);
	fread(newData, sizeof(BYTE), dataSize, rplc);

	__int64 test1, test2, test3, test4, test5;
	BYTE val1, val2, val3, val4, val5;

	test1 = 0;
	test2 = dataSize / 4;
	test3 = 2 * dataSize / 4;
	test4 = 3 * dataSize / 4;
	test5 = dataSize - 1;

	int gpercent = 0;
	int tpercent = 0;

	while ((olkOffset + dataSize) <= olkSize)
	{
		fseek(olk, olkOffset + test1, SEEK_SET);
		fread(&val1, sizeof(BYTE), 1, olk);
		fseek(olk, olkOffset + test2, SEEK_SET);
		fread(&val2, sizeof(BYTE), 1, olk);
		fseek(olk, olkOffset + test3, SEEK_SET);
		fread(&val3, sizeof(BYTE), 1, olk);
		fseek(olk, olkOffset + test4, SEEK_SET);
		fread(&val4, sizeof(BYTE), 1, olk);
		fseek(olk, olkOffset + test5, SEEK_SET);
		fread(&val5, sizeof(BYTE), 1, olk);

		if ((val1 == oldData[test1]) && (val2 == oldData[test2]) && (val3 == oldData[test3]) &&
			(val4 == oldData[test4]) && (val5 == oldData[test5]))
		{
			fseek(olk, olkOffset, SEEK_SET);
			fread(olkData, sizeof(BYTE), dataSize, olk);

			if (memcmp(olkData, oldData, dataSize) == 0)
			{
				printf("Found a match at offset: %d\n", olkOffset);
				fseek(olk, olkOffset, SEEK_SET);
				fwrite(newData, sizeof(BYTE), dataSize, olk);
			}
		}

		tpercent = 100.0f * (float)olkOffset / (float)olkSize;
		if (tpercent > (gpercent + 4))
		{
			gpercent = tpercent;
			printf("%d%%\r", gpercent);
		}

		olkOffset++;
	}

	delete newData;
	delete oldData;
	delete olkData;
}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	int nRetCode = 0;

	// initialize MFC and print and error on failure
	if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
	{
		// TODO: change error code to suit your needs
		_tprintf(_T("Fatal Error: MFC initialization failed\n"));
		nRetCode = 1;
	}
	else if (argc == 5)
	{
		CString olkArg = CString(argv[2]);
		CString dds1Arg = CString(argv[3]);
		CString offset = CString(argv[4]);

		olk = fopen(olkArg, "r+b");
		rplc = fopen(dds1Arg, "rb");

		fseek(rplc, 0, SEEK_END);
		dataSize = ftell(rplc) - 128;
		fseek(rplc, 128, SEEK_SET);

		fseek(olk, 0, SEEK_END);
		olkSize = ftell(olk);
		fseek(olk, 0, SEEK_SET);

		olkOffset = strtol(offset, NULL, 0);

		if (olkOffset >= olkSize)
		{
			printf("\n\nERROR:  Offset excedes bounds of file.\n\n");
		}
		else if ((olkOffset + dataSize) >= olkSize)
		{
			printf("\n\nERROR:  Inserting data would excede bounds.\n\n");
		}
		else
		{
			newData = (BYTE*) new BYTE[dataSize];
			fread(newData, sizeof(BYTE), dataSize, rplc);

			printf("\n\nReplacing data at offset %d.\n\n", olkOffset);

			fseek(olk, olkOffset, SEEK_SET);
			fwrite(newData, sizeof(BYTE), dataSize, olk);

			delete newData;
		}

		fclose(rplc);
		fclose(olk);

		nRetCode = 0;
	}
	else if (argc == 4)
	{
		CString olkArg = CString(argv[1]);
		CString dds1Arg = CString(argv[2]);
		CString dds2Arg = CString(argv[3]);

		olk = fopen(olkArg, "r+b");
		orig = fopen(dds1Arg, "rb");
		rplc = fopen(dds2Arg, "rb");

		fseek(olk, 0, SEEK_END);
		olkSize = ftell(olk);
		fseek(olk, 0, SEEK_SET);

		FindAndReplace();

		fclose(orig);
		fclose(rplc);
		fclose(olk);

		nRetCode = 0;
	}
	else
	{
		printf("\n\nERROR:    Incorrect command line parameters.");
		printf("\n\nUSAGE 1:  FNR [binary file] [original DDS] [modified DDS]");
		printf("\n\nUSAGE 2:  FNR O [binary file] [modified DDS] [offset]");
		printf("\n\nEx 1:     FNR Root.OLK File1-10.DDS NewTexture.DDS");
		printf("\nEx 2:     FNR O Root.OLK NewTexture.DDS 693248");
		printf("\nEx 3:     FNR O Root.OLK NewTexture.DDS 0xA9400\n\n");
		nRetCode = 2;
	}

	return nRetCode;
}
