#include<stdio.h>
#include"bhole.h"
#include"loaders.h"
#include"mm.h"

unsigned char header_top[0x20];

#define GET_HEADER_SHORT(offset) \
( *((unsigned short*)(header_top + (offset))) )

unsigned long imgsize; /* should this really be global? */

int load_file(FILE *f)
	/* routine: load_file
	 * purpose: loads an executable (EXE or COM or IMG) to memory,
	 *          and sets registers as needed
	 * params : FILE *f - file
	 * notice : this routine is in fact a front-end to
	 *          load_exe and load_com
	 * returns: 0 on failure, non-0 in success
	 */
{
	int load_com(FILE *f);
	int load_exe(FILE *f);
	int load_img(FILE *f);
	if (assume_com_file) 
		return load_com(f);
	else if (assume_img_file)
		return load_img(f);
	else
		return load_exe(f);             
			
}

int load_img(FILE *f)
	/* routine: load_img
	 * purpose/params/returns: same as load_exe but for .IMG files
	 * notice: .IMG files are files containing bootable images
	 */
{
	cs = 0x0000;
	ip = 0x7C00;
	/* TODO: direct reading to memory is idiotic and wrong */
	if (fread(__memory__ + ip,512,1,f) < 1)
	{
		puts("BHole: cannot read boot sector, image file too small?");
		return 0;
	}
	return 1;
}

int load_com(FILE *f)
	/* routine: load_com
	 * purpose/params/returns: same as load_exe but for .COM files
	 * notice: load_exe handles EXE files
	 */
{
	int dummy;
	
	ax = 0x0; /* TODO: is this value right? */
	cs = ds = es = ss = PSPSEG;
	sp = 0xFFFE; /* TODO: is this value right? */
	ip = 0x100;	
	fread(__memory__ + RESERVED,1,65536 - 0x100,f);
	if (fread(&dummy,1,1,f) == 1)
	{
		puts("BHole: ALERT!!!: .COM file is too big");
	}
	return 1;
}


int load_exe(FILE *f)
	/* routine: load_exe
	 * purpose: loads an EXE file to memory, and sets registers as needed
	 * params : FILE *f - file
	 * notice : load_com handles COM files
	 *          EXEs are files which are multi-segment and have relocation tables
	 * returns: 0 - failure, non-0 - success
	 */
{
	unsigned short relocs;
	unsigned short offset,seg;
	unsigned int   sizeval;

	fseek(f,0,SEEK_END);
	sizeval = ftell(f) - 0x200;
	bx = sizeval >> 16;
	cx = sizeval & 0xFFFF;
	rewind(f);
	fread(header_top,0x20,1,f);
	if (header_top[0] != 'M' || header_top[1] != 'Z')
	{
		puts("BHole: bad EXE signature (try rename to .com)");
		return 0;
	}
	/* load our ugly code into memory */
	fseek(f,*((unsigned short*)(header_top + 8))<<4,SEEK_SET);
	/* mark the memory allocation in the first MCB */
	imgsize = *((unsigned short*)(header_top + 2)) + 
	          (*((unsigned short*)(header_top + 4))-1) * 512;
	resize_first_mblk(FIRSTMEMB_SIZE + (imgsize >> 4));
	

	/* TODO: i'm doing direct memory access here, this is idiotic
	 *       but i think it won't cause any shits
	 */

	if (fread(__memory__ + RESERVED,1,
	             imgsize,
	             f) != imgsize)
	{
		fprintf(report_file,"BHole: program size is %x(?)\n",*((unsigned short*)(header_top + 2)) +
	             (*((unsigned short*)(header_top + 4))-1) * 512);
	}

	fprintf(report_file,"BHole: imgsize is %x\n",imgsize);

	/* initialize cs:ip and his friends... */
	cs = RESERVED >> 4; /* leave room for interrupt vector and friends (?) */

	cs+= *((unsigned short*)(header_top + 0x16));
	ip+= *((unsigned short*)(header_top + 0x14));
	es = ds = cs - 0x10; /* why??? */
	ss = cs + GET_HEADER_SHORT(0x0E);
	sp = GET_HEADER_SHORT(0x10);
	/* bx and cx are initialized in the beginning */
	fprintf(report_file,"BHole: sp set to %x\n",sp);
	/* perform relocations */
	relocs = GET_HEADER_SHORT(0x0006);
	fseek(f,GET_HEADER_SHORT(0x18),SEEK_SET);
	fputs("BHole: handling relocation table\n",report_file);

	while(relocs)
	{
		fread(&offset,1,2,f);
		fread(&seg,1,2,f);
		/* this is the relocation, i think the logic
		 * is to allow inter segment communication or
		 * something like that, but i'm not sure,
		 * i'm just doing what i hope the standard sepcifies
		 */
		/* TODO: direct access to __memory__ is idiotic */
		*((unsigned short*)(__memory__ + RESERVED + (offset + (seg << 4)) ))+=cs;
		relocs--;
	}
	

	
	fputs("BHole: relocation complete...\n",report_file);
	return 1;
}


