/*      
  _____     ___ ____ 
   ____|   |    ____|      PSX2 OpenSource Project
  |     ___|   |____       (c) 2008 jMk0Nm 
------------------------------------------------------------------------
mcboot.c

This program has been made in order to make the Free V@st a reality.
The 2 Authors prefers to remain anonymous.

main code file

*/

#include "mcboot.h"

char version[] = "  Free McBoot v1.5";


char *MG_region[8] = {"A", "E", "U", "J", "M", "O", "R", "C"};
	
#define NUM_INSTALL_FILES   10
#define NUM_OSD_FILES       3
#define FOLDER_EXEC         2
#define EXEC_ICON_SYS       0
#define EXEC_ICON_ICN       1
#define BOOT_ICON_SYS       3
#define BOOT_ICON_ICN       4
#define BOOT_FOLDER         5
#define SYSCONF_FOLDER      6
#define SYSCONF_FILE        7
#define SYSCONF_ICON_SYS    8
#define SYSCONF_ICON_ICN    9


char* install_tab[NUM_INSTALL_FILES]= { 
	"/B?EXEC-SYSTEM/icon.sys",                                           
	"/B?EXEC-SYSTEM/McBoot.icn",                                         
	"/B?EXEC-SYSTEM",             //2 exec folder
	"/BOOT/icon.sys",               
	"/BOOT/BOOT.icn",  
	"/BOOT",  	                  //5 optional boot folder
	"/FMCB-CNF",  	              //6
	"/FMCB-CNF/FREEMCB.CNF",      //7	
	"/FMCB-CNF/icon.sys",         //8	
	"/FMCB-CNF/FMCB.icn",      //9		
	
};      


#define NUM_DUMMIES_FILES   21
#define DUMMIES_UNINSTALL   21

char* dummies_tab[22]= { 
	"/B?EXEC-SYSTEM/osdsys.elf",
	"/B?EXEC-SYSTEM/osd100.elf",
	"/B?EXEC-SYSTEM/osd110.elf",
	"/B?EXEC-SYSTEM/osd120.elf",
	"/B?EXEC-SYSTEM/osd130.elf",
	"/B?EXEC-SYSTEM/osd140.elf",
	"/B?EXEC-SYSTEM/osd150.elf",
	"/B?EXEC-SYSTEM/osd160.elf",
	"/B?EXEC-SYSTEM/osd170.elf",
	"/B?EXEC-SYSTEM/osd180.elf",
	"/B?EXEC-SYSTEM/osd190.elf",
	"/B?EXEC-SYSTEM/osd200.elf",
	"/B?EXEC-SYSTEM/osd210.elf",
	"/B?EXEC-SYSTEM/osd220.elf",
	"/B?EXEC-SYSTEM/osd230.elf",
	"/B?EXEC-SYSTEM/osd240.elf",
	"/B?EXEC-SYSTEM/osd250.elf",
	"/B?EXEC-SYSTEM/osd260.elf",
	"/B?EXEC-SYSTEM/osd270.elf",
	"/B?EXEC-SYSTEM/osd280.elf",
	"/B?EXEC-SYSTEM/osd290.elf",
	"/FMCB-CNF/uninstall.dat"
};      

char dummy[] = "dummy";
int size_dummy = 5;
int install_with_dummies = 0;

char run_path[MAX_PATH];
int filesize;

u8 *hacked_dvdelf;		
u8 romver[16];
	
static int mc_Type, mc_Free, mc_Format;

int pos_x;
int pos_y;


//------------------------------------------------------------------------------------------------------------------------
void list_modules(void)
{
	int c = 0;
	smod_mod_info_t info;
	u8 name[60];

	if (!smod_get_next_mod(0, &info))
		return;
	scr_printf("\n\tList of modules currently in the system:\n\n");
	do {
		smem_read(info.name, name, sizeof name);
		if (!(c & 1)) scr_printf(" ");
		scr_printf("   \t%-21.21s  %2d  %3x%c", name, info.id, info.version, (++c & 1) ? ' ' : '\n');
	} while (smod_get_next_mod(&info, &info) != 0);
}

//------------------------------------------------------------------------------------------------------------------------
void IOP_reset(void)
{
	
	SifInitRpc(0);
	
	while(!SifIopReset("rom0:UDNL rom0:EELOADCNF",0));
	while(!SifIopSync());
	fioExit();
	SifExitIopHeap();
	SifLoadFileExit();
	SifExitRpc();
	SifExitCmd();
	SifInitRpc(0);
  	FlushCache(0);
  	FlushCache(2);
  	//twice, some in-hdloader hack
  	while(!SifIopReset("rom0:UDNL rom0:EELOADCNF",0));
  	while(!SifIopSync());
  	fioExit();
  	SifExitIopHeap();
  	SifLoadFileExit();
  	SifExitRpc();
  	SifExitCmd();

  	SifInitRpc(0);
  	FlushCache(0);
  	FlushCache(2);

  	SifLoadFileInit();

  	sbv_patch_enable_lmb();
  	sbv_patch_disable_prefix_check();

}	

//------------------------------------------------------------------------------------------------------------------------
void delay(int count) {
	
	int i;
	int ret;
	for (i  = 0; i < count; i++) {
	        ret = 0x01000000;
		while(ret--) asm("nop\nnop\nnop\nnop");
	}
}

//------------------------------------------------------------------------------------------------------------------------

int load_basic_modules(void)
{
	int id;
	char launch_path[MAX_PATH];
	char tmp_path[MAX_PATH];
	char *p;
		
	strcpy(launch_path, run_path);
	if	(	((p=strrchr(launch_path, '/'))==NULL)
  		 &&((p=strrchr(launch_path, '\\'))==NULL)
			)	p=strrchr(launch_path, ':');
	if	(p!=NULL)
		*(p+1)=0;
	//The above cuts away the ELF filename from Launch Dir, leaving a pure path
	
	sprintf(tmp_path, "%sXSIO2MAN", launch_path);
    if ((id = SifLoadModule("rom0:XSIO2MAN", 0, NULL)) < 0) {
	    if ((id = SifLoadModule(tmp_path, 0, NULL)) < 0)  {
			scr_printf("\tERROR: cannot load Xsio2man: %d.\n", id);
			return 0;
		}
	}

	sprintf(tmp_path, "%sXMCMAN", launch_path);
	if ((id = SifLoadModule("rom0:XMCMAN", 0, NULL)) < 0) {
	    if ((id = SifLoadModule(tmp_path, 0, NULL)) < 0)  {		
			scr_printf("\tERROR: cannot load Xmcman: %d.\n", id);
			return 0;
		}
	}
	
	sprintf(tmp_path, "%sXMCSERV", launch_path);	
    if ((id = SifLoadModule("rom0:XMCSERV", 0, NULL)) < 0) {
   	    if ((id = SifLoadModule(tmp_path, 0, NULL)) < 0)  {
			scr_printf("\tERROR: cannot load Xmcserv: %d.\n", id);
			return 0;
		}
	}

	sprintf(tmp_path, "%sXPADMAN", launch_path);		
    if ((id = SifLoadModule("rom0:XPADMAN", 0, NULL)) < 0) {
  	    if ((id = SifLoadModule(tmp_path, 0, NULL)) < 0)  {
			scr_printf("\tERROR: cannot load Xpadman: %d.\n", id);
			return 0;
		}
	}

	return 1;		
}

//------------------------------------------------------------------------------------------------------------------------

int load_modules(void)
{
	int id;
	
    if ((id = SifLoadModule("rom0:SIO2MAN", 0, NULL)) < 0) {
		scr_printf("\tERROR: cannot load sio2man: %d.\n", id);
		return 0;
	}

	if ((id = SifLoadModule("rom0:MCMAN", 0, NULL)) < 0) {
		scr_printf("\tERROR: cannot load mcman: %d.\n", id);
		return 0;
	}
	
    if ((id = SifLoadModule("rom0:MCSERV", 0, NULL)) < 0) {
		scr_printf("\tERROR: cannot load mcserv: %d.\n", id);
		return 0;
	}

    if ((id = SifLoadModule("rom0:PADMAN", 0, NULL)) < 0) {
		scr_printf("\tERROR: cannot load padman: %d.\n", id);
		return 0;
	}

	return 1;		
}

//------------------------------------------------------------------------------------------------------------------------
int load_IOX_modules(void)
{
	int ret, id;	

	if ((id = SifExecModuleBuffer(&mod_iomanx, size_mod_iomanx, 0, NULL, &ret)) < 0) {
		scr_printf("\tERROR: cannot load iomanX.\n");
		return 0;
	}

	if ((id = SifExecModuleBuffer(&mod_filexio, size_mod_filexio, 0, NULL, &ret)) < 0) {
		scr_printf("\tERROR: cannot load fileXio.\n");
		return 0;
	}

	return 1;	
}	

//------------------------------------------------------------------------------------------------------------------------
int load_USB_modules(void)
{
	int ret, id;	

	if ((id = SifExecModuleBuffer(&mod_usbd, size_mod_usbd, 0, NULL, &ret)) < 0) {
		scr_printf("\tERROR: cannot load usbd.\n");
		return 0;
	}

	if ((id = SifExecModuleBuffer(&mod_usb_mass, size_mod_usb_mass, 0, NULL, &ret)) < 0) {
		scr_printf("\tERROR: cannot load usbhdfsd.\n");
		return 0;
	}

	delay(1);
	
	return 1;	
}	

//------------------------------------------------------------------------------------------------------------------------

int load_mcsio2_module(void)
{
	int ret, id;	

	if ((id = SifExecModuleBuffer(&mod_mcsio2, size_mod_mcsio2, 0, NULL, &ret)) < 0) {
		scr_printf("\tERROR: cannot load mcsio2.\n");
		return 0;
	}
		
	return 1;		
}

//------------------------------------------------------------------------------------------------------------------------

int load_mcsp_module(void)
{
	int ret, id;	

	if ((id = SifExecModuleBuffer(&mod_mcsp, size_mod_mcsp, 0, NULL, &ret)) < 0) {
		scr_printf("\tERROR: cannot load mcsp.\n");
		return 0;
	}

	return 1;	
}	

//------------------------------------------------------------------------------------------------------------------------

void setupPowerOff(void) 
{
	int ret;

	SifExecModuleBuffer(&mod_poweroff, size_mod_poweroff, 0, NULL, &ret);
	hddPreparePoweroff();
		
}

//------------------------------------------------------------------------------------------------------------------------

int Create_File (char *filepath, u8 *buf, int size)
{
	int fd;
	char filepath2[0x40];

	sprintf(filepath2, "mc0:%s", filepath);
	fd = fioOpen(filepath2, O_WRONLY | O_CREAT);
	if(fd < 0) return 0;		
	if (fioWrite(fd, buf, size) < 0) return 0;
	fioClose(fd);
	
	return 1;
	
}

//------------------------------------------------------------------------------------------------------------------------

int File_Exist (char *filepath)
{
	int fd;
	fd = fioOpen(filepath, O_RDONLY);
	if(fd < 0) return 0;		
	fioClose(fd);	
	
	return 1;
	
}

//------------------------------------------------------------------------------------------------------------------------

int Format_MC(void)
{
	int ret;
	
	ret = mcFormat(0, 0);
	mcSync(0, NULL, &ret);
	
	if (ret < 0) return 0;
	else return 1;
}
//------------------------------------------------------------------------------------------------------------------------

int unpatch_dummies()
{
	int r, fd, i;	
	returnentry uninstall_entry[42];
	char filepath[MAX_PATH];
	u8 romver[16];
 	int num_entries;
 	int ret;
 	int linked_filesize;
 	int linked_cluster;
 	
	sprintf(filepath, "mc0:%s", dummies_tab[DUMMIES_UNINSTALL]);
	//printf("%s\n", filepath);

	fd = fioOpen(filepath, O_RDONLY);
	if (fd < 0) return 0;
 	r = fioRead(fd, romver, sizeof(romver)); 
	if (r < 0) return 0; 	
 	r = fioRead(fd, (int *)&linked_filesize, sizeof(int)); 
	if (r < 0) return 0; 	
 	r = fioRead(fd, (int *)&linked_cluster, sizeof(int)); 
	if (r < 0) return 0; 	
	
	switch (romver[4])
	{
		case 'J':
            for (i = 0; i < NUM_OSD_FILES; i++) memset(install_tab[i] + 2, 0x49, 1); 						
            for (i = 0; i < NUM_DUMMIES_FILES; i++) memset(dummies_tab[i] + 2, 0x49, 1); 	
			break;
		case 'U':
            for (i = 0; i < NUM_OSD_FILES; i++) memset(install_tab[i] + 2, 0x41, 1); 						
            for (i = 0; i < NUM_DUMMIES_FILES; i++) memset(dummies_tab[i] + 2, 0x41, 1); 	
			break;
		case 'C':
            for (i = 0; i < NUM_OSD_FILES; i++) memset(install_tab[i] + 2, 0x41, 1); 						
            for (i = 0; i < NUM_DUMMIES_FILES; i++) memset(dummies_tab[i] + 2, 0x41, 1); 	
			break;
		case 'E':
            for (i = 0; i < NUM_OSD_FILES; i++) memset(install_tab[i] + 2, 0x45, 1); 						
            for (i = 0; i < NUM_DUMMIES_FILES; i++) memset(dummies_tab[i] + 2, 0x45, 1); 	
			break;
		default:	
			for (i = 0; i < NUM_OSD_FILES; i++) memset(install_tab[i] + 2, romver[4], 1); 			
			for (i = 0; i < NUM_DUMMIES_FILES; i++) memset(dummies_tab[i] + 2, romver[4], 1); 	
			break;			
	}

	 	
	r = fioRead(fd, (int *)&num_entries, sizeof(int));	 		
	if (r < 0) return 0; 	
	for (i = 0; i < num_entries; i++)
	{
		//printf ("entry:%d attr:%04x size:%d cluster:%d\n", i, return_entry[i].attr, return_entry[i].size, return_entry[i].entry_cluster);
		//sprintf (buf, "%02x%04x%02x%s", return_entry[i].attr, return_entry[i].size, return_entry[i].entry_cluster, dummies_tab[i]);
		r = fioRead(fd, (u16 *)&uninstall_entry[i].attr, sizeof(u16));	
		if (r < 0) return 0; 	
		r = fioRead(fd, (u32 *)&uninstall_entry[i].size, sizeof(u32));	
		if (r < 0) return 0; 	
		r = fioRead(fd, (u16 *)&uninstall_entry[i].entry_cluster, sizeof(u16));	
		if (r < 0) return 0; 			
		r = fioRead(fd, uninstall_entry[i].name, sizeof(uninstall_entry[i].name));	
		if (r < 0) return 0; 	
	    //printf ("%s attr:%04x size:%d cluster:%d\n", uninstall_entry[i].name, uninstall_entry[i].attr, uninstall_entry[i].size, uninstall_entry[i].entry_cluster);		
	}
		
	fioClose(fd);
 		
	Print_XY("UnPatching dummies", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);					    		
	Draw_Screen();
	if (!(MC_Dummies_UnPatch(0, 0, (void *)uninstall_entry, num_entries, linked_filesize, linked_cluster)))
	{
		Print_XY("Error", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);
		pos_y += FONT_HEIGHT;
		Draw_Screen();	
		return 0;		
	}
	
	Print_XY("Done", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					    	
	pos_y += FONT_HEIGHT;		
	Draw_Screen();
	

	Print_XY("Deleting dummies", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);					    		
	Draw_Screen();
	for (i = 0; i < num_entries; i++)
	{
		mcDelete(0, 0, dummies_tab[i]);
		mcSync(0, NULL, &ret);
	}
	
	//sprintf(filepath, "%s/osdmain.elf", install_tab[FOLDER_EXEC]);
	//mcDelete(0, 0, filepath);
	//mcSync(0, NULL, &ret);
		
	mcDelete(0, 0, dummies_tab[DUMMIES_UNINSTALL]);
	mcSync(0, NULL, &ret);
	
	Print_XY("Done", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					    	
	pos_y += FONT_HEIGHT;		
	Draw_Screen();
		
	
	return 1; 		
	
}

//------------------------------------------------------------------------------------------------------------------------

int Install_Hack(void)
{
	
	int ret, i;
    u8 *OSDname;	
    char OSD_Path[MAX_PATH];
    char path[MAX_PATH];
    char launch_path[MAX_PATH];
	u8 *cnf_file, *boot_file;
	int cnf_filesize, boot_filesize;	
	int custom_cnf = 0;
	int fd, fd2, r, r2;
	char *p;
    
	  	
  	
	switch (((mg_ELF_region_t *) hacked_dvdelf)->mg_region)
	{
		case 'J':
            for (i = 0; i < NUM_OSD_FILES; i++) memset(install_tab[i] + 2, 0x49, 1); 						
            for (i = 0; i < NUM_DUMMIES_FILES; i++) memset(dummies_tab[i] + 2, 0x49, 1); 	
			break;
		case 'U':
            for (i = 0; i < NUM_OSD_FILES; i++) memset(install_tab[i] + 2, 0x41, 1); 						
            for (i = 0; i < NUM_DUMMIES_FILES; i++) memset(dummies_tab[i] + 2, 0x41, 1); 	
			break;
		case 'C':
            for (i = 0; i < NUM_OSD_FILES; i++) memset(install_tab[i] + 2, 0x41, 1); 						
            for (i = 0; i < NUM_DUMMIES_FILES; i++) memset(dummies_tab[i] + 2, 0x41, 1); 	
			break;
		case 'E':
            for (i = 0; i < NUM_OSD_FILES; i++) memset(install_tab[i] + 2, 0x45, 1); 						
            for (i = 0; i < NUM_DUMMIES_FILES; i++) memset(dummies_tab[i] + 2, 0x45, 1); 	
			break;
			
		default:	
			for (i = 0; i < NUM_OSD_FILES; i++) memset(install_tab[i] + 2, romver[4], 1); 			
			for (i = 0; i < NUM_DUMMIES_FILES; i++) memset(dummies_tab[i] + 2, romver[4], 1); 	
			break;			
	}
	
	if (unpatch_dummies()) {
		sprintf(path, "%s/osdmain.elf", install_tab[FOLDER_EXEC]);
		mcDelete(0, 0, path);
		mcSync(0, NULL, &ret);
	}		
	
	if (!install_with_dummies)
	{
  		OSDname = Get_OSD_Name();
  		if (!OSDname) OSDname = "osdmain.elf";	// if not found default to 'osdmain.elf'
  		sprintf(OSD_Path, "%s/%s", install_tab[FOLDER_EXEC], OSDname);
	}
	else sprintf(OSD_Path, "%s/osdmain.elf", install_tab[FOLDER_EXEC]);

  	
	mcMkDir(0, 0, install_tab[FOLDER_EXEC]);
	mcSync(0, NULL, &ret);

	
	//scr_printf("\tWriting osd file ");
	Print_XY("Writing osd file", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);					    	
	Draw_Screen();
	if (!(Create_File(OSD_Path, hacked_dvdelf, filesize)))
	{
		//scr_printf("error creating osd file\n");	
		Print_XY("Error", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					    	
		pos_y += FONT_HEIGHT;		
		Draw_Screen();
		return 0;		
	}
	//scr_printf("Done\n");	
	Print_XY("Done", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					    	
	pos_y += FONT_HEIGHT;		
	Draw_Screen();
	

	if (install_with_dummies)
	{
		Print_XY("Writing dummies", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);					    		
		Draw_Screen();
		for (i = 0; i < NUM_DUMMIES_FILES; i++) 
		{
			if (!(Create_File(dummies_tab[i], dummy, size_dummy))) 
			{
				Print_XY("Error", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);
				pos_y += FONT_HEIGHT;
				Draw_Screen();	
				return 0;		
			}
		}
		Print_XY("Done", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					    	
		pos_y += FONT_HEIGHT;		
		Draw_Screen();
	}	
	
		
	//scr_printf("\tWriting icons ");
	Print_XY("Writing icons", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);					    			    
	Draw_Screen();
    if (!(Create_File(install_tab[EXEC_ICON_SYS], &icon_sys, size_icon_sys)))
	{
		//scr_printf("error creating %s\n", install_tab[EXEC_ICON_SYS]);	
		Print_XY("Error", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					    	
		pos_y += FONT_HEIGHT;		
		Draw_Screen();
		return 0;		
	}	
	if (!(Create_File(install_tab[EXEC_ICON_ICN], &icon_icn, size_icon_icn)))
	{
		//scr_printf("error creating %s\n", install_tab[EXEC_ICON_ICN]);	
		Print_XY("Error", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					    	
		pos_y += FONT_HEIGHT;		
		Draw_Screen();
		return 0;		
	}
	
	mcMkDir(0, 0, install_tab[BOOT_FOLDER]);
	mcSync(0, NULL, &ret);
    if (!(Create_File(install_tab[BOOT_ICON_SYS], &boot_icon_sys, size_boot_icon_sys)))
	{
		Print_XY("Error", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					    	
		pos_y += FONT_HEIGHT;		
		Draw_Screen();
		return 0;		
	}	
	if (!(Create_File(install_tab[BOOT_ICON_ICN], &boot_icon_icn, size_boot_icon_icn)))
	{
		Print_XY("Error", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					    	
		pos_y += FONT_HEIGHT;		
		Draw_Screen();
		return 0;		
	}
	//scr_printf("Done\n");		
	Print_XY("Done", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					    	
	pos_y += FONT_HEIGHT;		
	Draw_Screen();

	sprintf(path, "mc0:%s", install_tab[SYSCONF_FILE]);
	if (!(File_Exist(path)))	
	{		
		strcpy(launch_path, run_path);
		if	(	((p=strrchr(launch_path, '/'))==NULL)
  		 	&&((p=strrchr(launch_path, '\\'))==NULL)
				)	p=strrchr(launch_path, ':');
		if	(p!=NULL)
			*(p+1)=0;
		//The above cuts away the ELF filename from Launch Dir, leaving a pure path
		strcat (launch_path, "FREEMCB.CNF");

		fd = fioOpen(launch_path, O_RDONLY);
		if (fd >= 0) {
			cnf_filesize = fioLseek(fd, 0, SEEK_END);		
			cnf_file = malloc(cnf_filesize);
			r = fioLseek(fd, 0, SEEK_SET);		
			r = fioRead(fd, cnf_file, cnf_filesize);			
			fioClose(fd);		
			custom_cnf = 1;
		}
		else
		{
			cnf_filesize = size_freemcb_cnf;		
			cnf_file = &freemcb_cnf;
		}	
	
		mcMkDir(0, 0, install_tab[SYSCONF_FOLDER]);
		mcSync(0, NULL, &ret);
		if (custom_cnf) Print_XY("Writing your own config", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);					    			    
		else Print_XY("Writing config", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);					    			    
		Draw_Screen();
    	if (!(Create_File(install_tab[SYSCONF_FILE], cnf_file, cnf_filesize)))
		{
			Print_XY("Error", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					    	
			pos_y += FONT_HEIGHT;		
			Draw_Screen();
			return 0;		
		}
    	if (!(Create_File(install_tab[SYSCONF_ICON_SYS], &cnf_icon_sys, size_cnf_icon_sys)))
		{
			Print_XY("Error", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					    	
			pos_y += FONT_HEIGHT;		
			Draw_Screen();
			return 0;		
		}	
		if (!(Create_File(install_tab[SYSCONF_ICON_ICN], &cnf_icon_icn, size_cnf_icon_icn)))
		{
			Print_XY("Error", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					    	
			pos_y += FONT_HEIGHT;		
			Draw_Screen();
			return 0;		
		}
		//scr_printf("Done\n");		
		Print_XY("Done", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					    	
		pos_y += FONT_HEIGHT;		
		Draw_Screen();
	}
	
	
	strcpy(launch_path, run_path);
	if	(	((p=strrchr(launch_path, '/'))==NULL)
	 	&&((p=strrchr(launch_path, '\\'))==NULL)
			)	p=strrchr(launch_path, ':');
	if	(p!=NULL)
		*(p+1)=0;
	//The above cuts away the ELF filename from Launch Dir, leaving a pure path
	strcat (launch_path, "BOOT.ELF");
	sprintf(path, "mc0:%s/BOOT.ELF", install_tab[BOOT_FOLDER]);
	
	if ((File_Exist(launch_path)) && (!(File_Exist(path))))
	{
		Print_XY("Writing your own BOOT.ELF", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);					    			 
		Draw_Screen();   

		fd = fioOpen(launch_path, O_RDONLY);
		fd2 = fioOpen(path, O_WRONLY | O_CREAT);
		if ((fd >= 0) && (fd2 >= 0)) {
			boot_filesize = fioLseek(fd, 0, SEEK_END);		
			boot_file = malloc(boot_filesize);
			if (boot_file == NULL) Print_XY("Error", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					    	
			else {
				r = fioLseek(fd, 0, SEEK_SET);		
				r = fioRead(fd, boot_file, boot_filesize);			
				r2 = fioWrite(fd2, boot_file, boot_filesize);			
				if ((r < 0) || (r2 < 0)) Print_XY("Error", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					 
				else Print_XY("Done", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					    	
				fioClose(fd);		
				fioClose(fd2);
			}	
		}
		else Print_XY("Error", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					    	
		pos_y += FONT_HEIGHT;		
		Draw_Screen();
	}
	
		
	if (install_with_dummies)
	{
		Print_XY("Scanning MC for osd FAT", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);					    		
		Draw_Screen();
		int linking_cluster = MC_OSD_Scan(0, 0, "osdmain.elf", sizeof("osdmain.elf"));
		if (linking_cluster == 0)
		{
			Print_XY("Error", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);
			pos_y += FONT_HEIGHT;
			return 0;		
		}
		Print_XY("Done", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					    	
		pos_y += FONT_HEIGHT;		
		Draw_Screen();
	
	
		fileentry file_entry[42];	
		returnentry return_entry[42];
		for (i = 0; i < NUM_DUMMIES_FILES; i++) 
		{
			memcpy(file_entry[i].name, dummies_tab[i] + 15, sizeof("osdxxx.elf"));	
			file_entry[i].size_name = sizeof("osdxxx.elf");		
		}	
	
		Print_XY("Patching dummies", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);					    		
		Draw_Screen();
		if (!(MC_Dummies_Patch(0, 0, (void *)file_entry, NUM_DUMMIES_FILES, linking_cluster, filesize, (void *)return_entry)))
		{
			Print_XY("Error", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);
			pos_y += FONT_HEIGHT;
			Draw_Screen();	
			return 0;		
		}
				
 		char filepath[MAX_PATH];

 		sprintf(filepath, "mc0:%s", dummies_tab[DUMMIES_UNINSTALL]);
 		fd = fioOpen(filepath, O_WRONLY | O_CREAT);
 		if(fd < 0)
 		{
			//printf("Unable to create file\n");				
			return 0;
 		}	
 		r = fioWrite(fd, romver, sizeof(romver)); 
		r = fioWrite(fd, (int *)&filesize, sizeof(int));	 				 		
		r = fioWrite(fd, (int *)&linking_cluster, sizeof(int));	 		
 		int num_entries = NUM_DUMMIES_FILES;
		r = fioWrite(fd, (int *)&num_entries, sizeof(int));	 		
		for (i = 0; i < NUM_DUMMIES_FILES; i++)
		{
			//printf ("entry:%d attr:%04x size:%d cluster:%d\n", i, return_entry[i].attr, return_entry[i].size, return_entry[i].entry_cluster);
			r = fioWrite(fd, (u16 *)&return_entry[i].attr, sizeof(u16));	
			r = fioWrite(fd, (u32 *)&return_entry[i].size, sizeof(u32));	
			r = fioWrite(fd, (u16 *)&return_entry[i].entry_cluster, sizeof(u16));	
			r = fioWrite(fd, dummies_tab[i] + 15, sizeof(return_entry[i].name));	
		}
 		fioClose(fd);

		Print_XY("Done", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					    	
		pos_y += FONT_HEIGHT;		
		Draw_Screen();
 				
	}
		
	return 1;
}

//------------------------------------------------------------------------------------------------------------------------
void print_title(void)
{
	gsFont->FontM_Align = GSKIT_FALIGN_LEFT;
	Print_XY(version, 30, 14, MainTextColor, 0.7f, 0.7f);
	
	pos_x = 40;
	pos_y = 100;
	
}
//------------------------------------------------------------------------------------------------------------------------

int Card_Format(void)
{
	int ret;	
	
	Print_XY("Detecting MC", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);
	Draw_Screen();
	
	mcGetInfo(0, 0, &mc_Type, &mc_Free, &mc_Format); 
	mcSync(0, NULL, &ret);

	// Assuming that the same memory card is connected, this should return 0
	mcGetInfo(0,0,&mc_Type,&mc_Free,&mc_Format);
	mcSync(0, NULL, &ret);
	do
	{
		if (ret != 0)
		{
			Print_XY("Insert MC in Slot 1", pos_x + 200, pos_y, MainTextColor, 0.5f, 0.7f);
			Draw_Screen();
		}
		mcGetInfo(0,0,&mc_Type,&mc_Free,&mc_Format);
		mcSync(0, NULL, &ret);
	}
	while (ret != 0);
	
	pos_y += FONT_HEIGHT;	

			
	if (mc_Type != 2) 
	{ 	
		//scr_printf("\tYour Memory Card doesn't seems to be PS2 compatible.\n");						
		Print_XY("Your MC isn't to PS2 format", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);
		pos_y += FONT_HEIGHT;			
		Draw_Screen();
		return 0;	
	}

	Clear_Screen();
	print_title();
	Draw_Screen();
	
	//pos_y += FONT_HEIGHT;
	Print_XY("WARNING : This will delete all MC content !", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);
	pos_y += FONT_HEIGHT;			
	Print_XY("Press TRIANGLE to confirm  CROSS to abort", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);
	pos_y += FONT_HEIGHT;			
	Draw_Screen();
		
	while(1)
	{
		Wait_Pad_Ready();
		if(Read_Pad())
		{
			if(Button & PAD_TRIANGLE)
			{
				pos_y += FONT_HEIGHT;
				Print_XY("Detecting MC", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);
				Draw_Screen();

				mcGetInfo(0,0,&mc_Type,&mc_Free,&mc_Format);
				mcSync(0, NULL, &ret);
				
				// Assuming that the same memory card is connected, this should return 0
				mcGetInfo(0,0,&mc_Type,&mc_Free,&mc_Format);
				mcSync(0, NULL, &ret);
				do
				{
					if (ret != 0)
					{
						Print_XY("Insert MC in Slot 1", pos_x + 200, pos_y, MainTextColor, 0.5f, 0.7f);
						Draw_Screen();
					}
					mcGetInfo(0,0,&mc_Type,&mc_Free,&mc_Format);
					mcSync(0, NULL, &ret);
				}
				while (ret != 0);
				pos_y += FONT_HEIGHT;	
				
				if (mc_Type != 2) 
				{ 	
					//scr_printf("\tYour Memory Card doesn't seems to be PS2 compatible.\n");						
					Print_XY("Your MC isn't to PS2 format", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);
					pos_y += FONT_HEIGHT;			
					Draw_Screen();
					return 0;	
				}
								
				Clear_Screen();
				print_title();
				Draw_Screen();

				Print_XY("Formatting Memory Card", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);
				Draw_Screen();				
				if (!(Format_MC()))
				{
					Print_XY("Error", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					
					pos_y += FONT_HEIGHT;			
					Draw_Screen();				
					return 0;
				}
				Print_XY("Done", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					
				pos_y += FONT_HEIGHT;			
				Draw_Screen();				
				return 1;
				
			}
			else if(Button & PAD_CROSS)
			{
				Print_XY("MC Format canceled !", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);					
				pos_y += FONT_HEIGHT;			
				Draw_Screen();				
				return 1;
			}
		}
	}
	
	return 1;	
	
}

//------------------------------------------------------------------------------------------------------------------------

int Card_Valid(void)
{
	int ret;	
	
	Print_XY("Detecting MC", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);
	Draw_Screen();

	mcGetInfo(0, 0, &mc_Type, &mc_Free, &mc_Format); 
	mcSync(0, NULL, &ret);

	// Assuming that the same memory card is connected, this should return 0
	mcGetInfo(0,0,&mc_Type,&mc_Free,&mc_Format);
	mcSync(0, NULL, &ret);
	do
	{   
		if (ret != 0)
		{
			Print_XY("Insert MC in Slot 1", pos_x + 200, pos_y, MainTextColor, 0.5f, 0.7f);
			Draw_Screen();
		}
		mcGetInfo(0,0,&mc_Type,&mc_Free,&mc_Format);
		mcSync(0, NULL, &ret);
	}
	while (ret != 0);
	
	pos_y += FONT_HEIGHT;	
	
	if (mc_Type != 2) 
	{ 	
		//scr_printf("\tYour Memory Card doesn't seems to be PS2 compatible.\n");						
		Print_XY("Your MC isn't to PS2 format", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);
		pos_y += FONT_HEIGHT;			
		Print_XY("Free McBoot installer exit", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);
		pos_y += FONT_HEIGHT;
		Draw_Screen();
		return 0;	
	}

	if (mc_Free < ((filesize/1024)+200)) {
		//scr_printf("\tYour Memory Card has not enough Free space.\n");	 
		Print_XY("Your MC has not enough Free space", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);
		pos_y += FONT_HEIGHT;
		//scr_printf("\n\tFree McBoot installer exit\n");
		Print_XY("Free McBoot installer exit", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);
		pos_y += FONT_HEIGHT;
		Draw_Screen();
		return 0;	
	}		

	return 1;	
	
}

//------------------------------------------------------------------------------------------------------------------------

int Run_Hack(void)
{
	int fd, r, ret, i;
	
	u8 *original_dvdelf;
	u8 *decrypted_dvdelf;
	u8 *injected_dvdelf;	
	char eromdrvpath[MAX_PATH];
	char dvdplpath[MAX_PATH];	
	char launch_path[MAX_PATH];	
	char *p;
	u8 *bootelf = NULL;
	int bootfilesize = 0;
	u8 MG_REGION[1];
	int custom_boot_elf = 0;

		
	if (!(Card_Valid())) return 0;
	
	Clear_Screen();
	print_title();
	Draw_Screen();
	
			
	Print_XY("Free McBoot installer start !", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);
	pos_y += FONT_HEIGHT;
	Draw_Screen();
	

	if ((ret = SifLoadModule("rom0:ADDDRV", 0, NULL)) < 0) 
	{
		//scr_printf("\tFailed to load rom0:ADDDRV\n");		
		Print_XY("Failed to load rom0:ADDDRV", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);
		pos_y += FONT_HEIGHT;
		Draw_Screen();
		//goto err_out;
	}
	
				
	if ((ret = SifLoadModuleEncrypted("rom1:EROMDRV", 0, NULL)) < 0)
	{
		for (i = 0; i < 8; i++)
		{
			sprintf (eromdrvpath, "%s%c", "rom1:EROMDRV", MG_region[i][0]);
			ret = SifLoadModuleEncrypted(eromdrvpath, 0, NULL);
			if (ret >= 0) 
			{
				MG_REGION[0] = MG_region[i][0];
				break;
 			}
		}	
		/* Donesn't matter if it fails, we continue for those who wants to use their own DVDELF.BIN
		if (ret < 0)
		{
			Print_XY("Failed to load encrypted rom1:EROMDRVx", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);
			pos_y += FONT_HEIGHT;
			Draw_Screen();
			goto err_out;
		}*/
	}
	
	
	strcpy(launch_path, run_path);
	if	(	((p=strrchr(launch_path, '/'))==NULL)
  		 &&((p=strrchr(launch_path, '\\'))==NULL)
			)	p=strrchr(launch_path, ':');
	if	(p!=NULL)
		*(p+1)=0;
	//The above cuts away the ELF filename from Launch Dir, leaving a pure path
	strcat (launch_path, "DVDELF.BIN");

		
	if (File_Exist(launch_path))	
	{			
		Print_XY("Reading your own DVDELF.BIN", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);
		Draw_Screen();
		fd = fioOpen(launch_path, O_RDONLY);
	}	
	else
	{
		fd = fioOpen("erom0:DVDELF", O_RDONLY);
		if (fd < 0) 
		{
	 		sprintf (dvdplpath, "%s%c", "erom0:DVDPL", MG_REGION[0]);
			fd = fioOpen(dvdplpath, O_RDONLY);	
	 		sprintf (dvdplpath, "Reading %s%c", "erom0:DVDPL", MG_REGION[0]);
			Print_XY(dvdplpath, pos_x, pos_y, MainTextColor, 0.5f, 0.7f);
			Draw_Screen();
		}
		else
		{
			Print_XY("Reading erom0:DVDELF", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);
			Draw_Screen();
		}	
	}
    
	if (fd < 0)
	{
		//scr_printf("\tFailed to open erom0:DVDELF\n");		
		Print_XY("Failed to open DVDELF", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);
		pos_y += FONT_HEIGHT;					
		Draw_Screen();
		goto err_out;
	}
	filesize = fioLseek(fd, 0, SEEK_END);		
	original_dvdelf = malloc(filesize);
	if (original_dvdelf == NULL) 
	{
		//scr_printf("\tFailed to allocate memory for original DVDELF\n");		
		Print_XY("Failed to allocate memory", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);		
		pos_y += FONT_HEIGHT;					
		Draw_Screen();
		goto err_out;
	}
	r = fioLseek(fd, 0, SEEK_SET);		
	r = fioRead(fd, original_dvdelf, filesize);			
	fioClose(fd);
	//scr_printf ("Done\n");	
	Print_XY("Done", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);			
	pos_y += FONT_HEIGHT;		
	Draw_Screen();
	
	

	decrypted_dvdelf = malloc(filesize);	
	if (decrypted_dvdelf == NULL)
	{
		//scr_printf("\tFailed to allocate memory for decrypted DVDELF\n");		
		Print_XY("Failed to allocate memory for decrypted DVDELF", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);			
		pos_y += FONT_HEIGHT;		
		Draw_Screen();
		free(original_dvdelf);
		goto err_out;
	}
	memcpy(decrypted_dvdelf, original_dvdelf, filesize);
	
				
	//scr_printf ("\tDecrypting DVDELF ");
	Print_XY("Decrypting DVDELF", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);			
	Draw_Screen();	
    if (Decrypt_Disk_File(decrypted_dvdelf) == NULL) 
    {
		//scr_printf("Failed\n");						    
		Print_XY("Failed", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					
		pos_y += FONT_HEIGHT;					
		Draw_Screen();
		free(original_dvdelf);		
		free(decrypted_dvdelf);				
    	goto err_out;
	}
	//scr_printf ("Done\n");			
	Print_XY("Done", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);				
	pos_y += FONT_HEIGHT;			
	Draw_Screen();
	
    if (Card_Auth() < 0)
    {
		//scr_printf("\n\tUnable to authentificate the Memory Card\n");						    
		Print_XY("Unable to authentificate the Memory Card", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);				
		pos_y += FONT_HEIGHT;			
		Draw_Screen();
		free(original_dvdelf);		
		free(decrypted_dvdelf);				
    	goto err_out;
    }
    
	//scr_printf ("\tPreparing OSD for Memory Card ");    
	Print_XY("Preparing OSD for MC", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);				
	Draw_Screen();
    if (Encrypt_Disk_File(original_dvdelf) == NULL) {
		//scr_printf("\n\tUnable to generate valid kbit and kc\n");						    
		Print_XY("Unable to generate valid kbit and kc", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					
		pos_y += FONT_HEIGHT;				
		Draw_Screen();
		free(original_dvdelf);		
		free(decrypted_dvdelf);				
    	goto err_out;
	}
	//scr_printf ("Done\n");				
	Print_XY("Done", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					
	pos_y += FONT_HEIGHT;				
	Draw_Screen();
	
	

	strcpy(launch_path, run_path);
	if	(	((p=strrchr(launch_path, '/'))==NULL)
  		 &&((p=strrchr(launch_path, '\\'))==NULL)
			)	p=strrchr(launch_path, ':');
	if	(p!=NULL)
		*(p+1)=0;
	//The above cuts away the ELF filename from Launch Dir, leaving a pure path
	strcat (launch_path, "EMBED.ELF");

	if (File_Exist(launch_path))	
	{		
		custom_boot_elf = 1;
		//scr_printf("\tBoot ELF file found in \"%s\"", filepath);		
		Print_XY("EMBED.ELF file found for inject", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);					
		pos_y += FONT_HEIGHT;							
		Draw_Screen();				
				
		fd = fioOpen(launch_path, O_RDONLY);
		if (fd < 0)
		{
			//scr_printf("\tFailed to open erom0:DVDELF\n");		
			Print_XY("Failed to open file", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);
			pos_y += FONT_HEIGHT;					
			Draw_Screen();
			free(original_dvdelf);		
			free(decrypted_dvdelf);				
			goto err_out;
		}
		bootfilesize = fioLseek(fd, 0, SEEK_END);		
		bootelf = malloc(bootfilesize);
		if (bootelf == NULL) 
		{
			//scr_printf("\tFailed to allocate memory for original DVDELF\n");		
			Print_XY("Failed to allocate memory", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);		
			pos_y += FONT_HEIGHT;					
			Draw_Screen();
			free(original_dvdelf);		
			free(decrypted_dvdelf);				
			goto err_out;
		}
		r = fioLseek(fd, 0, SEEK_SET);		
		r = fioRead(fd, bootelf, bootfilesize);			
		fioClose(fd);
	}


	//scr_printf ("\tInjecting ELF ");		
	Print_XY("Injecting DVDELF", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);				
	Draw_Screen();
	injected_dvdelf = malloc(filesize);	
	if (injected_dvdelf == NULL)
	{
		//scr_printf("\tFailed to allocate memory for injected DVDELF\n");		
		Print_XY("Failed to allocate memory", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);				
		pos_y += FONT_HEIGHT;						
		Draw_Screen();
		free(original_dvdelf);		
		free(decrypted_dvdelf);				
		if (custom_boot_elf) free(bootelf);
		goto err_out;
	}
	
	if (custom_boot_elf) 
	{
		if (filesize < 153600) r = embed(decrypted_dvdelf, NULL, 0, bootelf, bootfilesize, injected_dvdelf);
		else r = embed(decrypted_dvdelf, bootelf, bootfilesize, &launcher2, size_launcher2, injected_dvdelf);		
	}
	else
	{
		if (filesize < 153600) r = embed(decrypted_dvdelf, NULL, 0, &launcher2, size_launcher2, injected_dvdelf);
		else {
			bootelf = malloc(size_launcher2);
			if (bootelf == NULL) 
			{
				//scr_printf("\tFailed to allocate memory for original DVDELF\n");		
				Print_XY("Failed to allocate memory", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);		
				pos_y += FONT_HEIGHT;					
				Draw_Screen();
				free(original_dvdelf);		
				free(decrypted_dvdelf);				
				goto err_out;
			}
			memcpy(bootelf, &launcher2, size_launcher2); 		
			bootfilesize = size_launcher2;
			r = embed(decrypted_dvdelf, bootelf, bootfilesize, &launcher2, size_launcher2, injected_dvdelf);
		}
	}
		
	if (!r)
	{
		//scr_printf ("Failed\n");		
		Print_XY("Failed", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);						
		pos_y += FONT_HEIGHT;						
		Draw_Screen();
		free(original_dvdelf);		
		free(decrypted_dvdelf);				
		free(injected_dvdelf);						
		free(bootelf);
		goto err_out;					
	}	
	//scr_printf ("Done\n");
	Print_XY("Done", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					
	pos_y += FONT_HEIGHT;				
	Draw_Screen();
	
	free(bootelf);

	//scr_printf ("\tVerifying blocks ");				
	Print_XY("Verifying blocks", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);					
	Draw_Screen();
	if (!(verify_blocks(decrypted_dvdelf, injected_dvdelf)))
	{
		//scr_printf ("Error\n");		
		Print_XY("Error", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					
		pos_y += FONT_HEIGHT;						
		Draw_Screen();
		free(original_dvdelf);		
		free(injected_dvdelf);						
		free(decrypted_dvdelf);	
		goto err_out;					
	}	
	//scr_printf ("Done\n");
	Print_XY("Done", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					
	pos_y += FONT_HEIGHT;				
	Draw_Screen();		
	
	free(decrypted_dvdelf);	
	
	
	//scr_printf ("\tBuilding osd ");				
	Print_XY("Building osd", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);						
	Draw_Screen();
	hacked_dvdelf = malloc(filesize);	
	if (hacked_dvdelf == NULL)
	{
		//scr_printf("\tFailed to allocate memory for hacked osd\n");		
		Print_XY("Failed to allocate memory", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					
		pos_y += FONT_HEIGHT;						
		Draw_Screen();
		free(original_dvdelf);    		
		free(injected_dvdelf);	
		goto err_out;
	}
	if (!(build_OSD(original_dvdelf, injected_dvdelf, hacked_dvdelf)))
	{
		//scr_printf ("Failed\n");		
		Print_XY("Failed", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					
		pos_y += FONT_HEIGHT;						
		Draw_Screen();
		free(original_dvdelf);    		
		free(injected_dvdelf);	
		free(hacked_dvdelf);		
		goto err_out;					
	}	
	//scr_printf ("Done\n");
	Print_XY("Done", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					
	pos_y += FONT_HEIGHT;						
	Draw_Screen();
	
	free(injected_dvdelf);	


	
	//scr_printf ("\tChecking osd validity ");	
	Print_XY("Checking osd validity", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);						
	Draw_Screen();
    if (Decrypt_Card_File(original_dvdelf) == NULL) {
		Print_XY("Unvalid", pos_x + 250, pos_y, TextRed, 0.5f, 0.7f);					
		pos_y += FONT_HEIGHT;						
		Draw_Screen();
		return 0;					
	}
	Print_XY("Valid", pos_x + 250, pos_y, TextGreen, 0.5f, 0.7f);					
	pos_y += FONT_HEIGHT;						
	Draw_Screen();
	
	free(original_dvdelf);    			
	
    
      	
	if (!(Install_Hack()))
	{   
		free(hacked_dvdelf);		
		goto err_out;
	}
	free(hacked_dvdelf);		
		
	
	//scr_printf("\n\tFree McBoot installed successfully !\n");
	Print_XY("Free McBoot installed successfully !", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);					
	pos_y += FONT_HEIGHT;						
	Draw_Screen();
	
	
	return 1;	
	
	      		
	
		
err_out:	
	//scr_printf("\n\tFree McBoot installer error\n");
	Print_XY("Free McBoot installer error", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);					
	pos_y += FONT_HEIGHT;	
	Draw_Screen();
	
	
	return 0;
	
}

//------------------------------------------------------------------------------------------------------------------------

void GUI_Init(void)
{

	int TV_mode;
	int  gs_vmode;
		
	if(gsKit_detect_signal()==GS_MODE_PAL) //Let console decide
		TV_mode = TV_mode_PAL;
	else
		TV_mode = TV_mode_NTSC;

	//TV_mode = TV_mode_NTSC;
		
	if(TV_mode == TV_mode_PAL){ //Use PAL mode if chosen (forced or auto)
		gs_vmode = GS_MODE_PAL;
		SCREEN_WIDTH	= 640;
		SCREEN_HEIGHT = 512;
		SCREEN_X			= 652;
		SCREEN_Y			= 72;
	}else{                      //else use NTSC mode (forced or auto)
		gs_vmode = GS_MODE_NTSC;
		SCREEN_WIDTH	= 640;
		SCREEN_HEIGHT = 448;
		SCREEN_X			= 632;
		SCREEN_Y			= 50;
	} /* end else */
	
	Setup_GS(gs_vmode);
	gsKit_clear(gsGlobal, ColorBlack);

	TimerInit();
		
	Load_Skin();
	
	Clear_Screen();	
	Draw_Screen();
		
}
//------------------------------------------------------------------------------------------------------------------------

int Menu(void)
{
	
	int cross = 0;
	int square = 0;
	int circle = 0;
	int triangle = 0;
	int start = 0;
	int select = 0;
	int  event = 1;

				
	while(1)
	{
		Wait_Pad_Ready();
		if(Read_Pad())
		{
			if(Button & PAD_TRIANGLE)
			{
				event = 1;
				triangle = 1;
				Clear_Screen();
			}
			else if(Button & PAD_SQUARE)
			{
				event = 1;
				square = 1;
				Clear_Screen();
			}
			else if(Button & PAD_CIRCLE)
			{
				event = 1;
				circle = 1;
				Clear_Screen();
			}
			else if(Button & PAD_CROSS)
			{
				event = 1;
				cross = 1;
				Clear_Screen();
			}
			else if(Button & PAD_START)
			{
				event = 1;
				start = 1;
				Clear_Screen();
			}
			else if(Button & PAD_SELECT)
			{
				event = 1;
				select = 1;
				Clear_Screen();
			}
			
			
		}
	 	if(event)
	 	{			
			print_title();

		 	if (cross) return BUTTON_CROSS;
		 	if (square) return BUTTON_SQUARE;
		 	if (circle) return BUTTON_CIRCLE;		 			 	
		 	if (triangle) return BUTTON_TRIANGLE;
		 	if (start) return BUTTON_START;		 	
		 	if (select) return BUTTON_SELECT;		 			 	
				
 		}	 
 		Draw_Screen();
		event = 0; 					    
		
	}
	return 0;
} 

//------------------------------------------------------------------------------------------------------------------------
void clear_Mem(void)
{
	int i;
	for (i = 0x100000; i < 0x200000 ; i += 64) {
		asm (
			"\tsq $0, 0(%0) \n"
			"\tsq $0, 16(%0) \n"
			"\tsq $0, 32(%0) \n"
			"\tsq $0, 48(%0) \n"
			:: "r" (i) );
	}
}
//------------------------------------------------------------------------------------------------------------------------

void execute_boot_elf(void)
{
	u8 *execPathPoint;
	t_ExecData exd;
	char *argv[1];	
	int no_boot_file = 0;
	int r, fd;
	char mass_boot[] = "mass:/BOOT/BOOT.ELF";
	char mc_boot[] = "mc0:/BOOT/BOOT.ELF";
	char mc_boot_b[] = "mc0:/B?DATA-SYSTEM/BOOT.ELF";
	char msg[MAX_PATH];

	
	fd = fioOpen("rom0:ROMVER", O_RDONLY);
	r = fioRead(fd, romver, sizeof(romver));	
	fioClose(fd);
	
  	mc_boot_b[6] = (romver[4] == 'E' ? 'E' :
        (romver[4] == 'J' ? 'I' : 
        	 (romver[4] == 'U' ? 'A' : romver[4])));
	
	//clearing mem, so better not to have anything valuable on stack		
	Print_XY("Clearing memory", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);
	Draw_Screen();
	
	clear_Mem();
	
	Print_XY("Done", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					
	pos_y += FONT_HEIGHT;				
	Draw_Screen();		

	Print_XY("Resetting IOP", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);	
	Draw_Screen();
	
	IOP_reset();
	
	
	Print_XY("Done", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					
	pos_y += FONT_HEIGHT;				
	Draw_Screen();		

	load_USB_modules();
	load_basic_modules();	
	load_IOX_modules();	
	
  	SifLoadFileExit();
  
	execPathPoint = mass_boot;
	if (!(File_Exist(execPathPoint)))
	{
		execPathPoint = mc_boot;
		if (!(File_Exist(execPathPoint)))
		{
			mc_boot[2]++;
			execPathPoint = mc_boot;
			if (!(File_Exist(execPathPoint)))
			{
   				execPathPoint = mc_boot_b;
   				if (!(File_Exist(execPathPoint)))
   				{
   					mc_boot_b[2]++;
   					execPathPoint = mc_boot_b;
   					if (!(File_Exist(execPathPoint)))
   					{
    					no_boot_file = 1;
   					}
   				}
			}
		}
  	}
  	
  	if (!no_boot_file)
	{
		sprintf(msg, "Executing %s", execPathPoint);
        Print_XY(msg, pos_x, pos_y, MainTextColor, 0.5f, 0.7f);
		pos_y += FONT_HEIGHT;
		Draw_Screen();
		
  		exd.epc = 0;
		exd.gp = 0;
		exd.sp = 0;
 
		r = SifLoadElf(execPathPoint, &exd);
		if ((!r) && (exd.epc))
		{
			fioExit();
			SifExitRpc(); //some programs need it to be here
			FlushCache(0);
			FlushCache(2);
			argv[0] = execPathPoint;

			ExecPS2((void*)exd.epc, (void*)exd.gp, 1, argv);

		}
	}
	
}
//------------------------------------------------------------------------------------------------------------------------

int main(int argc, char *argv[])
{

	int ret, r, fd;
	int poweroff_delay = 0; //Set only when calling hddPowerOff
 	char OSD_Path[MAX_PATH];
 	u8 *OSDname;
 	int file_error;	
 	int osd_filesize = 0;
 	u8 *osd_elf = NULL;
	
	
    strcpy(run_path, argv[0]);				
	
    		
   	init_scr();
   	scr_printf("\n\tLOADING...");				  

   			
   	/* Resets IOP with EELOADCNF and loads needed modules */   	
	IOP_reset();   		   	
	if (!load_USB_modules()) goto err_out;	
	if (!load_basic_modules()) goto err_out; 
	if (!load_IOX_modules()) goto err_out;   	 
	if (!load_mcsio2_module()) goto err_out;  	 	
	if (!load_mcsp_module()) goto err_out;  	 		
	if (!mcsio2_rpc_Init()) goto err_out;				
	if (!mcsp_rpc_Init()) goto err_out;					
		
	mcReset();
	mcInit(MC_TYPE_XMC);
	
	padReset();
	Setup_Pad();
	
		
	fd = fioOpen("rom0:ROMVER", O_RDONLY);
	r = fioRead(fd, romver, sizeof(romver));	
	fioClose(fd);
	
	
	
	/* last chance to see boot-screen is here */
	
	GUI_Init();
		
gui:
	
	ret = Menu();
	
	switch(ret)
	{
		case BUTTON_CROSS:
			install_with_dummies = 0;
			r = Run_Hack();
			break;
		case BUTTON_SQUARE:
			install_with_dummies = 1;
			r = Run_Hack();
			break;
		case BUTTON_START:
			r = unpatch_dummies();
			if (r)
			{
				Print_XY("Modifying osd file", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);					    	
				Draw_Screen();
				
				file_error = 0;
				sprintf(OSD_Path, "mc0:%s/osdmain.elf", install_tab[FOLDER_EXEC]);				
				fd = fioOpen(OSD_Path, O_RDONLY);
				if (fd < 0) file_error = 1;
				else {
					osd_filesize = fioLseek(fd, 0, SEEK_END);		
					osd_elf = malloc(osd_filesize);
					if (osd_elf == NULL) file_error = 1;
					r = fioLseek(fd, 0, SEEK_SET);		
					if (r < 0) file_error = 1;
					r = fioRead(fd, osd_elf, osd_filesize);			
					if (r < 0) file_error = 1;
					fioClose(fd);
				}	

				sprintf(OSD_Path, "%s/osdmain.elf", install_tab[FOLDER_EXEC]);
				mcDelete(0, 0, OSD_Path);
				mcSync(0, NULL, &ret);
								
				OSDname = Get_OSD_Name();
				if (!OSDname) OSDname = "osdmain.elf";	// if not found default to 'osdmain.elf'
				sprintf(OSD_Path, "%s/%s", install_tab[FOLDER_EXEC], OSDname);
				if (!(Create_File(OSD_Path, osd_elf, osd_filesize)))
				{
					//scr_printf("error creating osd file\n");	
					Print_XY("Error", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					    	
					pos_y += FONT_HEIGHT;		
					Draw_Screen();
				}
				//scr_printf("Done\n");	
				
				free(osd_elf);				

				if (file_error)
				{
					Print_XY("Error", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					    	
					pos_y += FONT_HEIGHT;		
					Draw_Screen();
					Print_XY("Free McBoot multi-version uninstall error !", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);					
					pos_y += FONT_HEIGHT;						
					Draw_Screen();
				}
				else
				{
					Print_XY("Done", pos_x + 250, pos_y, MainTextColor, 0.5f, 0.7f);					    	
					pos_y += FONT_HEIGHT;		
					Draw_Screen();
					Print_XY("Free McBoot reverted back to normal install !", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);					
					pos_y += FONT_HEIGHT;						
					Draw_Screen();
				}	
				

				
			}	
			else
			{
				Print_XY("Free McBoot multi-version uninstall error !", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);					
				pos_y += FONT_HEIGHT;						
				Draw_Screen();
			}
			break;
		case BUTTON_TRIANGLE:
			Print_XY("Power Off in 3 seconds", pos_x, pos_y, MainTextColor, 0.5f, 0.7f);
			Draw_Screen();
			WaitTime = Timer();
			while(Timer() < (WaitTime + 3000)); // wait 3 sec.			
			setupPowerOff();
			hddPowerOff();
			poweroff_delay = SCANRATE/4; //trigger delay for those without net adapter				
			SleepThread();
			break;
		case BUTTON_SELECT:
			r = Card_Format();
			break;		
		case BUTTON_CIRCLE:	
			execute_boot_elf();
			break;		
	}
	
	goto gui;
	

		
	
err_out:	
	scr_printf("\n\tFree McBoot Init failed\n");
	SleepThread();
		
	return 0;
}
//------------------------------------------------------------------------------------------------------------------------


