/***************************************************************************
 *
 * fixcart.c
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/

/*
 * includes
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
 * defines
 */

#define 	MAX_SECTIONS	20

/*
 * typedefs
 */

/*
 * structures
 */

typedef struct _section
{
	char		*name;
	int		group;
	unsigned long	start;
	unsigned long	len;
	unsigned long	obj;
} section;

/*
 * globals
 */

unsigned long	codeScrambleStart,codeScrambleEnd;

unsigned long	filesysLen;

unsigned char	*data,*ptr;
unsigned long	entryPoint=0;
unsigned long	headerSize=0;
unsigned long	romPtrAddr=0;
unsigned long	bssStart=0;
int		numSections;
section		sections[MAX_SECTIONS];

#define		GROUP_HDR	0
#define		GROUP_TEXT	1
#define		GROUP_BSS	2


char	*groupNames[]=
{
	"hdr","text","bss",NULL
};

char	tmp[256];
char	tmp2[256];

char	iMsg[]="Hey! What are you doing looking at this binary when you should be looking after my shed???! Please don't copy this game... that would be rude. ";
char	tmp3[256];

/*
 * function prototypes
 */

/*
 * code
 */


/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/

void main(int argc, char **argv)
{
	FILE	*stream;
	int	i,j,k,l;
	FILE	*in;
	FILE	*out;
	int	iptr;

	/*
	 * open .MAP file
	 */

	stream=fopen("excite.map","rb");
	if(!stream)
	{
		printf("can't open excite.map\n");
		exit(1);
	}

	/*
	 * open .BIN file
	 */

	in=fopen("excite2.bin","rb");
	if(!in)
	{
		printf("can't open bb.bin\n");
		exit(1);
	}

	/*
	 * find values
	 */

	fgets(tmp,256,stream);
	fgets(tmp,256,stream);

	numSections=0;

	while(1)
	{
		fgets(tmp,256,stream);
		if(feof(stream)) break;

		i=sscanf(tmp,"%x %x %x %x %s %s",
			 &sections[numSections].start,
			 &j,
			 &sections[numSections].len,
			 &sections[numSections].obj,
			 &tmp2,&tmp3);
		if(i!=6) break;

		for(j=0;groupNames[j];j++)
		{
			if(!stricmp(groupNames[j],tmp2))
			{
				sections[numSections].group=j;
				break;
			}
		}
		if(!groupNames[j])
		{
			printf("unrecognised section : %s\n",tmp2);
			exit(1);
		}

		if(j==GROUP_HDR) headerSize+=sections[numSections].len;
		if(j==GROUP_BSS && !bssStart) bssStart=sections[numSections].start;

		sections[numSections].name=strdup(tmp3);
		numSections++;
	}

	/*
	 * find rom ptr offset
	 */

	codeScrambleStart=codeScrambleEnd=-1;

	while(1)
	{
		fgets(tmp,256,stream);
		if(feof(stream)) break;

		i=sscanf(tmp,"%x %s",&j,tmp2);
		if(i!=2) continue;
		if(!stricmp(tmp2,"romFileOffset"))
		{
			romPtrAddr=j & 0x0FFFFFFF;
		}
		if(!strcmp(tmp2,"AnimCacheCreate"))
		{
			codeScrambleStart=j & 0x0FFFFFFF;
		}
		if(!strcmp(tmp2,"WaveRender"))
		{
			codeScrambleEnd=j & 0x0FFFFFFF;
		}
	}
	if(romPtrAddr==-1)
	{
		printf("can't locate romFileOffset variable\n");
		exit(1);
	}
//	if(codeScrambleStart==-1 || codeScrambleEnd==-1)
//	{
//		printf("can't find scramble section\n");
//		exit(1);
//	}

	fclose(stream);

	/*
	 * get program entry point
	 */

	fseek(in,8,SEEK_SET);
	entryPoint =fgetc(in) << 24;
	entryPoint+=fgetc(in) << 16;
	entryPoint+=fgetc(in) << 8;
	entryPoint+=fgetc(in) << 0;
	entryPoint &= 0x0FFFFFFF;

	printf("program entry point: %08x\n",entryPoint);
	if(!headerSize)
	{
		printf("couldn't find header size!\n");
		exit(1);
	}
	printf("header size        : %08x\n",headerSize);

	/*
	 * check its validity!
	 */

	printf("romFileOffset addr : %08x [RAM]\n",romPtrAddr);

	romPtrAddr=(romPtrAddr-entryPoint+headerSize) & 0x0FFFFFFF;
	printf("romFileOffset addr : %08x [ROM]\n");

	fseek(in,romPtrAddr,SEEK_SET);
	i =fgetc(in) << 24;
	i+=fgetc(in) << 16;
	i+=fgetc(in) << 8;
	i+=fgetc(in) << 0;

	printf("romFileOffset val  : %08x\n",i);
	if(i!=0xb0200000)
	{
		printf("Invalid romFileOffset variable\n");
		exit(1);
	}

	/*
	 * get BSS start addr in cart
	 */

	bssStart &= 0x0FFFFFFF;
	printf("BSS start          : %08x\n",bssStart);

	/*
	 * copy hdr, text and data to destination file
	 */

	out=fopen("excite3.bin","wb");
	if(!out)
	{
		printf("can't open excite2.bin for output\n");
		exit(1);
	}

	/*
	 * malloc for image - BSS
	 */

	data=(unsigned char *)malloc(bssStart);
	if(!data)
	{
		printf("insufficient memory!\n");
		exit(1);
	}

	/*
	 * read image
	 */

	rewind(in);
	fread(data,1,bssStart,in);

	/*
	 * clear header, and write entry point...
	 */

//	memset(data,0,4096);
	data[8] =((entryPoint>>24) & 0xFF) | 0x80;
	data[9] =(entryPoint>>16) & 0xFF;
	data[10]=(entryPoint>> 8) & 0xFF;
	data[11]=(entryPoint>> 0) & 0xFF;

	ptr=&data[romPtrAddr];
	*(ptr++)=(bssStart >> 24) & 0xFF;
	*(ptr++)=(bssStart >> 16) & 0xFF;
	*(ptr++)=(bssStart >>  8) & 0xFF;
	*(ptr++)=(bssStart >>  0) & 0xFF;

	/*
	 * scramble data...
	 */

//	printf("scrambling... "); fflush(stdout);
//	for(i=codeScrambleStart+1;i<codeScrambleEnd;i++)
//	{
//		data[i-entryPoint+headerSize]^=data[i-entryPoint+headerSize-1];
//	}
//	printf("scrambled\n");

	/*
	 * write image
	 */

	fwrite(data,1,bssStart,out);
	fclose(in);
	free(data);

	/*
	 * write filesystem
	 */

	in=fopen("fs\\filesys.bin","rb");
	if(!in)
	{
		printf("can't open filesys.bin\n");
		exit(1);
	}

	fseek(in,0,SEEK_END);
	filesysLen=ftell(in);
	fseek(in,0,SEEK_SET);

	printf("filesystem [%08x] + preBSS [%08x] = [%08x]\n",
	       filesysLen,bssStart,filesysLen+bssStart);

	while(1)
	{
		k=fread(tmp,1,256,in);
		if(k) fwrite(tmp,1,k,out);
		if(k!=256) break;
	}
	fclose(in);

	/*
	 * pad up to 12Mb
	 */

	iptr=0;
	for(i=bssStart+filesysLen;i<12*1024*1024;i++)
	{
		fputc(iMsg[iptr++],out);
		if(!iMsg[iptr]) iptr=0;
	}

	fclose(out);

//	sprintf(tmp,"setcsum excite3.bin %08x",entryPoint | 0x80000000);
//	printf("%s\n",tmp);
//	system(tmp);

	sprintf(tmp,"make6103 excite3.bin");
//	sprintf(tmp,"makemask excite3.bin");
	printf("%s\n",tmp);
	system(tmp);

	sprintf(tmp,"nrdc -b -t\"EXCITEBIKE64\" -v0 excite3.bin");
	printf("%s\n",tmp);
	system(tmp);

	printf("excite3.bin is ready for hot N64 action!\n");
}


/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/


/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/


/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/


/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/


/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/



/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/

