Index: ps2launchargs/source/uLaunchELF/LaunchArgs.txt
===================================================================
--- ps2launchargs/source/uLaunchELF/LaunchArgs.txt	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/LaunchArgs.txt	(revision 1101)
@@ -0,0 +1,5 @@
+-noui
+-players 2
+-level testzipline5
+-mission 5
+-model00 bra
Index: ps2launchargs/source/uLaunchELF/Makefile
===================================================================
--- ps2launchargs/source/uLaunchELF/Makefile	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/Makefile	(revision 1101)
@@ -0,0 +1,103 @@
+EE_BIN = BOOT.ELF
+EE_OBJS = main.o pad.o config.o elf.o draw.o loader.o  filer.o cd.o\
+	poweroff.o iomanx.o filexio.o ps2atad.o ps2dev9.o smsutils.o ps2ip.o\
+	ps2smap.o ps2hdd.o ps2fs.o ps2netfs.o usbd.o usbhdfsd.o\
+	cdvd.o ps2ftpd.o ps2host.o vmcfs.o fakehost.o ps2kbd.o\
+	hdd.o hdl_rpc.o hdl_info.o editor.o timer.o jpgviewer.o icon.o lang.o\
+	font_uLE.o makeicon.o chkesr_rpc.o chkesr.o
+
+EE_INCS := -I$(PS2DEV)/gsKit/include -I$(PS2DEV)/libjpg/include\
+	-I$(PS2SDK)/sbv/include -I$(PS2DEV)/libcdvd/ee
+
+EE_LDFLAGS := -L$(PS2DEV)/gsKit/lib -L$(PS2DEV)/libjpg\
+	-L$(PS2SDK)/sbv/lib -L$(PS2DEV)/libcdvd/lib -s
+EE_LIBS = -lpad -lgskit -ldmakit -ljpg -lmc -lhdd -lcdvdfs -lkbd -lmf -lc  -lfileXio -lpatches -lpoweroff  -ldebug -lc
+
+all:	$(EE_BIN)
+
+run: all
+	ps2client -h 192.168.0.10 -t 1 execee host:BOOT.ELF
+reset: clean
+	ps2client -h 192.168.0.10 reset
+
+usbd.s:
+	bin2s $(PS2SDK)/iop/irx/usbd.irx usbd.s usbd_irx
+
+usbhdfsd.s:
+	bin2s $(PS2DEV)/usbhdfsd/bin/usbhdfsd.irx usbhdfsd.s usb_mass_irx
+
+cdvd.s:
+	bin2s $(PS2DEV)/libcdvd/lib/cdvd.irx cdvd.s cdvd_irx
+
+poweroff.s:
+	bin2s $(PS2SDK)/iop/irx/poweroff.irx poweroff.s poweroff_irx
+
+iomanx.s:
+	bin2s $(PS2SDK)/iop/irx/iomanX.irx iomanx.s iomanx_irx
+
+filexio.s:
+	bin2s $(PS2SDK)/iop/irx/fileXio.irx filexio.s filexio_irx
+
+ps2dev9.s:
+	bin2s $(PS2SDK)/iop/irx/ps2dev9.irx ps2dev9.s ps2dev9_irx
+
+ps2ip.s:
+	bin2s $(PS2DEV)/SMS/drv/SMSTCPIP/bin/SMSTCPIP.irx ps2ip.s ps2ip_irx
+
+ps2smap.s:
+	bin2s $(PS2DEV)/SMS/drv/SMSMAP/SMSMAP.irx ps2smap.s ps2smap_irx
+
+smsutils.s:
+	bin2s $(PS2DEV)/SMS/drv/SMSUTILS/SMSUTILS.irx smsutils.s smsutils_irx
+
+ps2ftpd.s:
+	bin2s $(PS2DEV)/ps2ftpd/bin/ps2ftpd.irx ps2ftpd.s ps2ftpd_irx
+
+ps2atad.s:
+	bin2s $(PS2SDK)/iop/irx/ps2atad.irx ps2atad.s ps2atad_irx
+
+ps2hdd.s:
+	bin2s $(PS2SDK)/iop/irx/ps2hdd.irx ps2hdd.s ps2hdd_irx
+
+ps2fs.s:
+	bin2s $(PS2SDK)/iop/irx/ps2fs.irx ps2fs.s ps2fs_irx
+
+ps2netfs.s:
+	bin2s $(PS2SDK)/iop/irx/ps2netfs.irx ps2netfs.s ps2netfs_irx
+
+fakehost.s:
+	bin2s $(PS2SDK)/iop/irx/fakehost.irx fakehost.s fakehost_irx
+
+hdl_info.s:
+	$(MAKE) -C hdl_info
+	bin2s hdl_info/hdl_info.irx hdl_info.s hdl_info_irx
+
+ps2host.s:
+	$(MAKE) -C ps2host
+	bin2s ps2host/ps2host.irx ps2host.s ps2host_irx
+
+vmcfs.s:
+	$(MAKE) -C vmcfs
+	bin2s vmcfs/bin/vmcfs.irx vmcfs.s vmcfs_irx
+
+loader.s:
+	$(MAKE) -C loader
+	bin2s loader/loader.elf loader.s loader_elf
+
+ps2kbd.s:
+	bin2s $(PS2SDK)/iop/irx/ps2kbd.irx ps2kbd.s ps2kbd_irx
+
+chkesr.s:
+	$(MAKE) -C chkesr
+	bin2s chkesr/chkesr.irx chkesr.s chkesr_irx
+
+clean:
+	$(MAKE) -C hdl_info clean
+	$(MAKE) -C ps2host clean
+	$(MAKE) -C loader clean
+	$(MAKE) -C vmcfs clean
+	$(MAKE) -C chkesr clean
+	rm -f *.o *.a *.s BOOT.ELF
+
+include $(PS2SDK)/samples/Makefile.pref
+include $(PS2SDK)/samples/Makefile.eeglobal
Index: ps2launchargs/source/uLaunchELF/cd.c
===================================================================
--- ps2launchargs/source/uLaunchELF/cd.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/cd.c	(revision 1101)
@@ -0,0 +1,174 @@
+//---------------------------------------------------------------------------
+//File name:   cd.c
+//---------------------------------------------------------------------------
+#include "launchelf.h"
+
+#define CD_SERVER_INIT			0x80000592
+#define CD_SERVER_SCMD			0x80000593
+#define CD_SCMD_GETDISCTYPE		0x03
+
+SifRpcClientData_t clientInit __attribute__ ((aligned(64)));
+u32 initMode __attribute__ ((aligned(64)));
+s32 cdThreadId = 0;
+s32 bindSearchFile = -1;
+s32 bindDiskReady = -1;
+s32 bindInit = -1;
+s32 bindNCmd = -1;
+s32 bindSCmd = -1;
+s32 nCmdSemaId = -1;		// n-cmd semaphore id
+s32 sCmdSemaId = -1;		// s-cmd semaphore id
+s32 callbackSemaId = -1;	// callback semaphore id
+s32 cdDebug = 0;
+s32 sCmdNum = 0;
+SifRpcClientData_t clientSCmd __attribute__ ((aligned(64)));
+u8 sCmdRecvBuff[48] __attribute__ ((aligned(64)));
+volatile s32 cbSema = 0;
+ee_thread_t cdThreadParam; // Iritscen: changed "ee_thread_status_t" (used in later ps2sdk versions) to earlier name "ee_thread_t"
+s32 callbackThreadId = 0;
+volatile s32 cdCallbackNum __attribute__ ((aligned(64)));
+
+void cdSemaInit(void);
+s32 cdCheckSCmd(s32 cur_cmd);
+s32 cdSyncS(s32 mode);
+void cdSemaExit(void);
+
+//---------------------------------------------------------------------------
+s32 cdInit(s32 mode)
+{
+	s32 i;
+
+	if (cdSyncS(1))
+		return 0;
+	SifInitRpc(0);
+	cdThreadId = GetThreadId();
+	bindSearchFile = -1;
+	bindNCmd = -1;
+	bindSCmd = -1;
+	bindDiskReady = -1;
+	bindInit = -1;
+
+	while (1) {
+		if (SifBindRpc(&clientInit, CD_SERVER_INIT, 0) >= 0)
+			if (clientInit.server != 0) break;
+		i = 0x10000;
+		while (i--);
+	}
+
+	bindInit = 0;
+	initMode = mode;
+	SifWriteBackDCache(&initMode, 4);
+	if (SifCallRpc(&clientInit, 0, 0, &initMode, 4, 0, 0, 0, 0) < 0)
+		return 0;
+	if (mode == CDVD_INIT_EXIT) {
+		cdSemaExit();
+		nCmdSemaId = -1;
+		sCmdSemaId = -1;
+		callbackSemaId = -1;
+	} else {
+		cdSemaInit();
+	}
+	return 1;
+}
+
+//---------------------------------------------------------------------------
+void cdSemaExit(void)
+{
+	if (callbackThreadId) {
+		cdCallbackNum = -1;
+		SignalSema(callbackSemaId);
+	}
+	DeleteSema(nCmdSemaId);
+	DeleteSema(sCmdSemaId);
+	DeleteSema(callbackSemaId);
+}
+
+//---------------------------------------------------------------------------
+void cdSemaInit(void)
+{
+	struct t_ee_sema semaParam;
+
+	// return if both semaphores are already inited
+	if (nCmdSemaId != -1 && sCmdSemaId != -1)
+		return;
+
+	semaParam.init_count = 1;
+	semaParam.max_count = 1;
+	semaParam.option = 0;
+	nCmdSemaId = CreateSema(&semaParam);
+	sCmdSemaId = CreateSema(&semaParam);
+
+	semaParam.init_count = 0;
+	callbackSemaId = CreateSema(&semaParam);
+
+	cbSema = 0;
+}
+
+//---------------------------------------------------------------------------
+s32 cdCheckSCmd(s32 cur_cmd)
+{
+	s32 i;
+	cdSemaInit();
+	if (PollSema(sCmdSemaId) != sCmdSemaId) {
+		if (cdDebug > 0)
+			printf("Scmd fail sema cur_cmd:%d keep_cmd:%d\n", cur_cmd, sCmdNum);
+		return 0;
+	}
+	sCmdNum = cur_cmd;
+	ReferThreadStatus(cdThreadId, &cdThreadParam);
+	if (cdSyncS(1)) {
+		SignalSema(sCmdSemaId);
+		return 0;
+	}
+
+	SifInitRpc(0);
+	if (bindSCmd >= 0)
+		return 1;
+	while (1) {
+		if (SifBindRpc(&clientSCmd, CD_SERVER_SCMD, 0) < 0) {
+			if (cdDebug > 0)
+				printf("Libcdvd bind err S cmd\n");
+		}
+		if (clientSCmd.server != 0)
+			break;
+
+		i = 0x10000;
+		while (i--)
+			;
+	}
+
+	bindSCmd = 0;
+	return 1;
+}
+
+//---------------------------------------------------------------------------
+s32 cdSyncS(s32 mode)
+{
+	if (mode == 0) {
+		if (cdDebug > 0)
+			printf("S cmd wait\n");
+		while (SifCheckStatRpc(&clientSCmd))
+			;
+		return 0;
+	}
+	return SifCheckStatRpc(&clientSCmd);
+}
+
+//---------------------------------------------------------------------------
+CdvdDiscType_t cdGetDiscType(void)
+{
+	if (cdCheckSCmd(CD_SCMD_GETDISCTYPE) == 0)
+		return 0;
+
+	if (SifCallRpc(&clientSCmd, CD_SCMD_GETDISCTYPE, 0, 0, 0, sCmdRecvBuff, 4, 0, 0) < 0) {
+		SignalSema(sCmdSemaId);
+		return 0;
+	}
+
+	SignalSema(sCmdSemaId);
+	return *(s32 *) UNCACHED_SEG(sCmdRecvBuff);
+}
+//------------------------------
+//endfunc cdGetDiscType
+//---------------------------------------------------------------------------
+//End of file: cd.c
+//---------------------------------------------------------------------------
Index: ps2launchargs/source/uLaunchELF/cd.h
===================================================================
--- ps2launchargs/source/uLaunchELF/cd.h	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/cd.h	(revision 1101)
@@ -0,0 +1,32 @@
+#ifndef CD_H
+#define CD_H
+
+#define CDVD_INIT_INIT		0x00
+#define CDVD_INIT_NOCHECK	0x01
+#define CDVD_INIT_EXIT		0x05
+
+typedef enum {
+	CDVD_TYPE_NODISK =	0x00,		// No Disc inserted
+	CDVD_TYPE_DETECT,			// Detecting disc type
+	CDVD_TYPE_DETECT_CD,
+	CDVD_TYPE_DETECT_DVDSINGLE,
+	CDVD_TYPE_DETECT_DVDDUAL,
+	CDVD_TYPE_UNKNOWN,			// Unknown disc type
+
+	CDVD_TYPE_PS1CD	=	0x10,		// PS1 CD with no CDDA tracks
+	CDVD_TYPE_PS1CDDA,			// PS1 CD with CDDA tracks
+	CDVD_TYPE_PS2CD,			// PS2 CD with no CDDA tracks
+	CDVD_TYPE_PS2CDDA,			// PS2 CD with CDDA tracks
+	CDVD_TYPE_PS2DVD,			// PS2 DVD
+	CDVD_TYPE_ESRDVD_0,		// ESR-patched DVD, as seen without ESR driver active
+	CDVD_TYPE_ESRDVD_1,		// ESR-patched DVD, as seen with ESR driver active
+
+	CDVD_TYPE_CDDA =	0xFD,		// CDDA
+	CDVD_TYPE_DVDVIDEO,			// DVD Video
+	CDVD_TYPE_ILLEGAL,			// Illegal disk type
+} CdvdDiscType_t;
+
+s32 cdInit(s32);
+CdvdDiscType_t cdGetDiscType(void);
+
+#endif
Index: ps2launchargs/source/uLaunchELF/chkesr/Makefile
===================================================================
--- ps2launchargs/source/uLaunchELF/chkesr/Makefile	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/chkesr/Makefile	(revision 1101)
@@ -0,0 +1,47 @@
+#  _____     ___ ____ 
+#   ____|   |    ____|      PS2 Open Source Project
+#  |     ___|   |____       
+#  
+#--------------------------------------------------------------------------
+#
+#    Copyright (C) 2008 - Neme & jimmikaelkael (www.psx-scene.com) 
+#
+#    This program is free software; you can redistribute it and/or modify
+#    it under the terms of the Free McBoot License.
+#    
+#	 This program and any related documentation is provided "as is"
+#	 WITHOUT ANY WARRANTIES, either express or implied, including, but not
+# 	 limited to, implied warranties of fitness for a particular purpose. The
+# 	 entire risk arising out of use or performance of the software remains
+# 	 with you.
+#    In no event shall the author be liable for any damages whatsoever
+# 	 (including, without limitation, damages to your hardware or equipment,
+# 	 environmental damage, loss of health, or any kind of pecuniary loss)
+# 	 arising out of the use of or inability to use this software or
+# 	 documentation, even if the author has been advised of the possibility
+# 	 of such damages.
+#
+#    You should have received a copy of the Free McBoot License along with
+#    this program; if not, please report at psx-scene :
+#    http://psx-scene.com/forums/freevast/
+#
+#--------------------------------------------------------------------------     
+#
+# MakeFile
+#
+# ------------------------------------------------------------------------
+
+IOP_BIN  = chkesr.irx
+IOP_OBJS = chkesr.o imports.o
+
+IOP_CFLAGS  += -Wall -fno-builtin
+IOP_LDFLAGS += -s
+IOP_INCS += -I$(PS2SDK)/iop/include -I$(PS2SDK)/common/include
+
+all: $(IOP_BIN)
+
+clean:
+	-rm -f *.o *.bak *.irx
+	
+include $(PS2SDK)/Defs.make
+include Rules.make
Index: ps2launchargs/source/uLaunchELF/chkesr/Rules.make
===================================================================
--- ps2launchargs/source/uLaunchELF/chkesr/Rules.make	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/chkesr/Rules.make	(revision 1101)
@@ -0,0 +1,54 @@
+# _____     ___ ____     ___ ____
+#  ____|   |    ____|   |        | |____|
+# |     ___|   |____ ___|    ____| |    \    PS2DEV Open Source Project.
+#-----------------------------------------------------------------------
+# Copyright 2001-2004.
+# Licenced under Academic Free License version 2.0
+# Review ps2sdk README & LICENSE files for further details.
+
+
+IOP_CC_VERSION := $(shell $(IOP_CC) -v 2>&1 | sed -n 's/^.*version //p')
+
+ASFLAGS_TARGET = -mcpu=r3000
+
+ifeq ($(IOP_CC_VERSION),3.2.2)
+CFLAGS_TARGET  = -miop
+ASFLAGS_TARGET = -march=r3000
+LDFLAGS_TARGET = -miop
+endif
+
+IOP_INCS := $(IOP_INCS) -I$(PS2SDK)/iop/include -I$(PS2SDK)/common/include 
+
+IOP_CFLAGS  := $(CFLAGS_TARGET) -O2 -G0 -c $(IOP_INCS) $(IOP_CFLAGS)
+IOP_ASFLAGS := $(ASFLAGS_TARGET) -EL -G0 $(IOP_ASFLAGS)
+IOP_LDFLAGS := $(LDFLAGS_TARGET) -nostdlib $(IOP_LDFLAGS)
+
+# Externally defined variables: IOP_BIN, IOP_OBJS, IOP_LIB
+
+%.o : %.c
+	$(IOP_CC) $(IOP_CFLAGS) $< -o $@
+
+%.o : %.s
+	$(IOP_AS) $(IOP_ASFLAGS) $< -o $@
+
+# A rule to build imports.lst.
+%.o : %.lst
+	echo "#include \"irx_imports.h\"" > build-imports.c
+	cat $< >> build-imports.c
+	$(IOP_CC) $(IOP_CFLAGS) build-imports.c -o $@
+	-rm -f build-imports.c
+
+# A rule to build exports.tab.
+%.o : %.tab
+	echo "#include \"irx.h\"" > build-exports.c
+	cat $< >> build-exports.c
+	$(IOP_CC) $(IOP_CFLAGS) build-exports.c -o $@
+	-rm -f build-exports.c
+
+
+$(IOP_BIN) : $(IOP_OBJS)
+	$(IOP_CC) $(IOP_LDFLAGS) -o $(IOP_BIN) $(IOP_OBJS) $(IOP_LIBS)
+
+$(IOP_LIB) : $(IOP_OBJS)
+	$(IOP_AR) cru $(IOP_LIB) $(IOP_OBJS)
+
Index: ps2launchargs/source/uLaunchELF/chkesr/chkesr.c
===================================================================
--- ps2launchargs/source/uLaunchELF/chkesr/chkesr.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/chkesr/chkesr.c	(revision 1101)
@@ -0,0 +1,142 @@
+/*      
+  _____     ___ ____ 
+   ____|   |    ____|      PS2 Open Source Project
+  |     ___|   |____       
+  
+---------------------------------------------------------------------------
+*/
+
+#include <cdvdman.h>
+#include <intrman.h>
+#include <loadcore.h>
+#include <sifcmd.h>
+#include <sysclib.h>
+#include <sysmem.h>
+#include <thbase.h>
+#include <stdio.h> 
+
+#define MODNAME "chkesr"
+IRX_ID(MODNAME, 1, 1);
+
+#define CHKESR_IRX 0x0E0E0E0
+
+int __attribute__((unused)) shutdown() { return 0; }
+
+/* function declaration */
+void rpcMainThread(void* param);
+void *rpcCommandHandler(int command, void *Data, int Size);
+void *Check_ESR_Disc(void *Data);
+void *SysAlloc(u64 size);
+int   SysFree(void *area);
+
+static SifRpcDataQueue_t Rpc_Queue __attribute__((aligned(64)));
+static SifRpcServerData_t Rpc_Server __attribute((aligned(64)));
+static int Rpc_Buffer[1024] __attribute((aligned(64)));
+
+//--------------------------------------------------------------
+/* Description: Module entry point */
+int _start(int argc, char **argv)
+{
+ iop_thread_t param;
+ int id;
+
+ /*create thread*/
+ param.attr      = TH_C;
+ param.thread    = rpcMainThread;
+ param.priority  = 40;
+ param.stacksize = 0x800;
+ param.option    = 0;
+
+ if((id = CreateThread(&param)) <= 0)
+  return MODULE_NO_RESIDENT_END;
+
+ StartThread(id,0);
+
+ return MODULE_RESIDENT_END;
+}
+//--------------------------------------------------------------
+void rpcMainThread(void* param)
+{
+ SifInitRpc(0);
+ SifSetRpcQueue(&Rpc_Queue, GetThreadId());
+ SifRegisterRpc(&Rpc_Server, CHKESR_IRX, (void *) rpcCommandHandler, (u8 *) &Rpc_Buffer, 0, 0, &Rpc_Queue);
+ SifRpcLoop(&Rpc_Queue);
+}
+//--------------------------------------------------------------
+void *rpcCommandHandler(int command, void *Data, int Size)
+{
+	switch(command)
+	{
+		case 1:
+			Data = Check_ESR_Disc(Data);
+			break;
+	}
+
+	return Data;
+}
+//--------------------------------------------------------------
+void *Check_ESR_Disc(void *Data)
+{
+	
+ u32 *ret = Data;
+ cd_read_mode_t s_DVDReadMode;
+ u8 *buf = NULL;
+ int offs = 12;
+ int i; 
+ int r = 0;
+ 
+ //printf("Check_ESR_Disc starting.\n");
+ 
+ *ret = -1;
+
+ buf = (u8*)SysAlloc((2048 + 0xFF) & ~(u32)0xFF);
+ if (buf != NULL) *ret = 0;
+ 
+ if (*ret == 0) {
+ 	s_DVDReadMode.trycount = 5;
+ 	s_DVDReadMode.spindlctrl = CdSpinStm;
+ 	s_DVDReadMode.datapattern = CdSecS2048;
+ 	s_DVDReadMode.pad = 0x00;
+
+ 	for (i=0; i<2048; i++) buf[i] = 0;
+ 	 	
+	//sceCdDiskReady(0);
+	//r = sceCdRead(14, 1, buf, &s_DVDReadMode); // read LBA 14
+	r = sceCdReadDVDV(14, 1, buf, &s_DVDReadMode); // read LBA 14
+	sceCdSync(0);
+	
+ 	if (r <= 0) *ret = -1;
+ 	else if (!strncmp(buf + offs + 25, "+NSR", 4))
+ 	     	*ret = 1;
+
+ 	SysFree(buf); 	
+ }	
+ 
+ //printf("Check_ESR_Disc returning %ld\n", *ret);
+ return Data; 
+}
+//--------------------------------------------------------------
+void *SysAlloc(u64 size)
+{
+ int oldstate;
+ register void *p;
+ 
+ CpuSuspendIntr(&oldstate);
+ p = AllocSysMemory(ALLOC_FIRST, size, NULL);
+ CpuResumeIntr(oldstate);
+
+ return p;
+}
+//--------------------------------------------------------------
+int SysFree(void *area)
+{
+ int oldstate;
+ register int r;
+
+ CpuSuspendIntr(&oldstate);
+ r = FreeSysMemory(area);
+ CpuResumeIntr(oldstate);
+
+ return r;
+}
+//--------------------------------------------------------------
Index: ps2launchargs/source/uLaunchELF/chkesr/imports.lst
===================================================================
--- ps2launchargs/source/uLaunchELF/chkesr/imports.lst	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/chkesr/imports.lst	(revision 1101)
@@ -0,0 +1,48 @@
+//---------------------------------------------------------------------------
+// File name:   imports.lst
+// Description: Used to generate code for IRX function imports
+//---------------------------------------------------------------------------
+
+cdvdman_IMPORTS_start
+//I_sceCdDiskReady
+//I_sceCdGetDiskType
+//I_sceCdRead
+I_sceCdReadDVDV
+//I_sceCdStatus
+I_sceCdSync
+cdvdman_IMPORTS_end
+
+intrman_IMPORTS_start
+I_CpuSuspendIntr
+I_CpuResumeIntr
+intrman_IMPORTS_end
+
+sifcmd_IMPORTS_start
+I_sceSifInitRpc 
+I_sceSifSetRpcQueue 
+I_sceSifRegisterRpc 
+I_sceSifRpcLoop
+sifcmd_IMPORTS_end
+
+sysmem_IMPORTS_start
+I_AllocSysMemory
+I_FreeSysMemory
+sysmem_IMPORTS_end
+
+sysclib_IMPORTS_start
+I_strncmp
+sysclib_IMPORTS_end
+
+stdio_IMPORTS_start
+I_printf
+stdio_IMPORTS_end
+
+thbase_IMPORTS_start
+I_CreateThread
+I_GetThreadId
+I_StartThread
+thbase_IMPORTS_end
+
+//---------------------------------------------------------------------------
+// End of file: imports.lst
+//---------------------------------------------------------------------------
Index: ps2launchargs/source/uLaunchELF/chkesr/irx_imports.h
===================================================================
--- ps2launchargs/source/uLaunchELF/chkesr/irx_imports.h	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/chkesr/irx_imports.h	(revision 1101)
@@ -0,0 +1,22 @@
+/*
+ * irx_imports.h - Defines all IRX imports.
+ *
+ * NB: inapplicable old copyright claim to this material removed, as that
+ * NB: claim would only relate to the old material created by that author
+ */
+
+#ifndef IOP_IRX_IMPORTS_H
+#define IOP_IRX_IMPORTS_H
+
+#include <irx.h>
+
+/* Please keep these in alphabetical order!  */
+#include <cdvdman.h>
+#include <intrman.h>
+#include <sifcmd.h>
+#include <stdio.h>
+#include <sysclib.h>
+#include <sysmem.h>
+#include <thbase.h>
+
+#endif /* IOP_IRX_IMPORTS_H */
Index: ps2launchargs/source/uLaunchELF/chkesr_rpc.c
===================================================================
--- ps2launchargs/source/uLaunchELF/chkesr_rpc.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/chkesr_rpc.c	(revision 1101)
@@ -0,0 +1,83 @@
+/*      
+  _____     ___ ____ 
+   ____|   |    ____|      PS2 Open Source Project
+  |     ___|   |____       
+  
+---------------------------------------------------------------------------
+
+    Copyright (C) 2008 - Neme & jimmikaelkael (www.psx-scene.com) 
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the Free McBoot License.
+    
+	This program and any related documentation is provided "as is"
+	WITHOUT ANY WARRANTIES, either express or implied, including, but not
+ 	limited to, implied warranties of fitness for a particular purpose. The
+ 	entire risk arising out of use or performance of the software remains
+ 	with you.
+   	In no event shall the author be liable for any damages whatsoever
+ 	(including, without limitation, damages to your hardware or equipment,
+ 	environmental damage, loss of health, or any kind of pecuniary loss)
+ 	arising out of the use of or inability to use this software or
+ 	documentation, even if the author has been advised of the possibility of
+ 	such damages.
+
+    You should have received a copy of the Free McBoot License along with
+    this program; if not, please report at psx-scene :
+    http://psx-scene.com/forums/freevast/
+
+---------------------------------------------------------------------------
+*/
+
+#include <tamtypes.h>
+#include <kernel.h>
+#include <sifrpc.h>
+
+// External functions
+int chkesr_rpc_Init(void);
+int Check_ESR_Disc(void);
+
+#define CHKESR_IRX 0x0E0E0E0
+
+static SifRpcClientData_t chkesr    __attribute__((aligned(64)));
+static int Rpc_Buffer[1024] __attribute__((aligned(64)));
+
+typedef struct {
+	u32 ret;
+} Rpc_Packet_Send_Check_ESR_Disc;
+
+int chkesr_Inited  = 0;
+
+//--------------------------------------------------------------
+int chkesrBindRpc(void) {
+	int ret;
+	int retryCount = 0x1000;
+
+	while(retryCount--) {
+	        ret = SifBindRpc( &chkesr, CHKESR_IRX, 0);
+        	if ( ret  < 0) return -1;
+	        if (chkesr.server != 0) break;
+	        // short delay 
+	      	ret = 0x10000;
+	    	while(ret--) asm("nop\nnop\nnop\nnop");
+	}
+	chkesr_Inited = 1;
+	return retryCount;
+}
+//--------------------------------------------------------------
+int chkesr_rpc_Init(void)
+{
+ 	chkesrBindRpc();
+ 	if(!chkesr_Inited) return -1;
+ 	return 1;
+}
+//--------------------------------------------------------------
+int Check_ESR_Disc(void)
+{
+ 	Rpc_Packet_Send_Check_ESR_Disc *Packet = (Rpc_Packet_Send_Check_ESR_Disc *)Rpc_Buffer;
+ 	
+	if(!chkesr_Inited) chkesr_rpc_Init();
+   	if ((SifCallRpc(&chkesr, 1, 0, (void*)Rpc_Buffer, sizeof(Rpc_Packet_Send_Check_ESR_Disc), (void*)Rpc_Buffer, sizeof(int),0,0)) < 0) return -1;
+ 	return Packet->ret;
+}
+//--------------------------------------------------------------
Index: ps2launchargs/source/uLaunchELF/config.c
===================================================================
--- ps2launchargs/source/uLaunchELF/config.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/config.c	(revision 1101)
@@ -0,0 +1,2282 @@
+//---------------------------------------------------------------------------
+// File name:   config.c
+//---------------------------------------------------------------------------
+#include "launchelf.h"
+#include <stdbool.h>
+
+enum
+{
+	DEF_TIMEOUT = 10,
+	DEF_HIDE_PATHS = TRUE,
+	DEF_COLOR1 = GS_SETREG_RGBA(128,128,128,0), //Backgr
+	DEF_COLOR2 = GS_SETREG_RGBA(64,64,64,0),    //Frame
+	DEF_COLOR3 = GS_SETREG_RGBA(96,0,0,0),      //Select
+	DEF_COLOR4 = GS_SETREG_RGBA(0,0,0,0),       //Text
+	DEF_COLOR5 = GS_SETREG_RGBA(96,96,0,0),     //Graph1
+	DEF_COLOR6 = GS_SETREG_RGBA(0,96,0,0),      //Graph2
+	DEF_COLOR7 = GS_SETREG_RGBA(224,224,224,0), //Graph3
+	DEF_COLOR8 = GS_SETREG_RGBA(0,0,0,0),       //Graph4
+	DEF_DISCCONTROL = FALSE,
+	DEF_INTERLACE = TRUE,
+	DEF_MENU_FRAME = TRUE,
+	DEF_MENU = TRUE,
+	DEF_RESETIOP = TRUE,
+	DEF_NUMCNF = 1,
+	DEF_SWAPKEYS = FALSE,
+	DEF_HOSTWRITE = FALSE,
+	DEF_BRIGHT = 50,
+	DEF_POPUP_OPAQUE = FALSE,
+	DEF_INIT_DELAY = 0,
+	DEF_USBKBD_USED = 1,
+	DEF_SHOW_TITLES = 1,
+	DEF_PATHPAD_LOCK = 0,
+	DEF_JPGVIEW_TIMER = 5,
+	DEF_JPGVIEW_TRANS = 2,
+	DEF_JPGVIEW_FULL = 0,
+	DEF_PSU_HUGENAMES = 0,
+	DEF_PSU_DATENAMES = 0,
+	DEF_PSU_NOOVERWRITE = 0,
+	DEF_FB_NOICONS = 0,
+	
+	DEFAULT=0,
+	SHOW_TITLES=12,
+	DISCCONTROL,
+	FILENAME,
+	SCREEN,
+	SETTINGS,
+	NETWORK,
+	OK,
+	CANCEL
+};
+
+char LK_ID[16][10]={
+	"auto",
+	"Circle",
+	"Cross",
+	"Square",
+	"Triangle",
+	"L1",
+	"R1",
+	"L2",
+	"R2",
+	"L3",
+	"R3",
+	"Start",
+	"Select",  //Predefined for "CONFIG"
+	"Left",    //Predefined for "LOAD CONFIG--"
+	"Right",   //Predefined for "LOAD CONFIG++"
+	"ESR"
+};
+char PathPad[30][MAX_PATH];
+char tmp[MAX_PATH];
+SETTING *setting = NULL;
+SETTING *tmpsetting;
+//---------------------------------------------------------------------------
+// End of declarations
+// Start of functions
+//---------------------------------------------------------------------------
+// get_CNF_string is the main CNF parser called for each CNF variable in a
+// CNF file. Input and output data is handled via its pointer parameters.
+// The return value flags 'false' when no variable is found. (normal at EOF)
+//---------------------------------------------------------------------------
+int	get_CNF_string(unsigned char **CNF_p_p,
+                   unsigned char **name_p_p,
+                   unsigned char **value_p_p)
+{
+	unsigned char *np, *vp, *tp = *CNF_p_p;
+
+start_line:
+	while((*tp<=' ') && (*tp>'\0')) tp+=1;  //Skip leading whitespace, if any
+	if(*tp=='\0')	return false;            //but exit at EOF
+	np = tp;                               //Current pos is potential name
+	if(*tp<'A')                            //but may be a comment line
+	{                                      //We must skip a comment line
+		while((*tp!='\r')&&(*tp!='\n')&&(*tp>'\0')) tp+=1;  //Seek line end
+		goto start_line;                     //Go back to try next line
+	}
+
+	while((*tp>='A')||((*tp>='0')&&(*tp<='9'))) tp+=1;  //Seek name end
+	if(*tp=='\0')	return false;            //but exit at EOF
+
+	while((*tp<=' ') && (*tp>'\0'))
+		*tp++ = '\0';                        //zero&skip post-name whitespace
+	if(*tp!='=') return false;             //exit (syntax error) if '=' missing
+	*tp++ = '\0';                          //zero '=' (possibly terminating name)
+
+	while((*tp<=' ') && (*tp>'\0')         //Skip pre-value whitespace, if any
+		&& (*tp!='\r') && (*tp!='\n'))tp+=1; //but do not pass the end of the line
+	if(*tp=='\0')	return false;            //but exit at EOF
+	vp = tp;                               //Current pos is potential value
+
+	while((*tp!='\r')&&(*tp!='\n')&&(*tp!='\0')) tp+=1;  //Seek line end
+	if(*tp!='\0') *tp++ = '\0';            //terminate value (passing if not EOF)
+	while((*tp<=' ') && (*tp>'\0')) tp+=1;  //Skip following whitespace, if any
+
+	*CNF_p_p = tp;                         //return new CNF file position
+	*name_p_p = np;                        //return found variable name
+	*value_p_p = vp;                       //return found variable value
+	return true;                           //return control to caller
+}	//Ends get_CNF_string
+
+//---------------------------------------------------------------------------
+int CheckMC(void)
+{
+	int dummy, ret;
+	
+	mcGetInfo(0, 0, &dummy, &dummy, &dummy);
+	mcSync(0, NULL, &ret);
+
+	if( -1 == ret || 0 == ret) return 0;
+
+	mcGetInfo(1, 0, &dummy, &dummy, &dummy);
+	mcSync(0, NULL, &ret);
+
+	if( -1 == ret || 0 == ret ) return 1;
+
+	return -11;
+}
+//---------------------------------------------------------------------------
+unsigned long hextoul(char *string)
+{
+	unsigned long value;
+	char c;
+
+	value = 0;
+	while( !(((c=*string++)<'0')||(c>'F')||((c>'9')&&(c<'A'))) )
+		value = value*16 + ((c>'9') ? (c-'A'+10) : (c-'0'));
+	return value;
+}
+//---------------------------------------------------------------------------
+//storeSkinCNF will save most cosmetic settings to a RAM area
+//------------------------------
+size_t storeSkinCNF(char *cnf_buf)
+{
+	size_t CNF_size;
+
+	sprintf(cnf_buf,
+		"GUI_Col_1_ABGR = %08lX\r\n"
+		"GUI_Col_2_ABGR = %08lX\r\n"
+		"GUI_Col_3_ABGR = %08lX\r\n"
+		"GUI_Col_4_ABGR = %08lX\r\n"
+		"GUI_Col_5_ABGR = %08lX\r\n"
+		"GUI_Col_6_ABGR = %08lX\r\n"
+		"GUI_Col_7_ABGR = %08lX\r\n"
+		"GUI_Col_8_ABGR = %08lX\r\n"
+		"SKIN_FILE = %s\r\n"
+		"GUI_SKIN_FILE = %s\r\n"
+		"SKIN_Brightness = %d\r\n"
+		"TV_mode = %d\r\n"
+		"Screen_Interlace = %d\r\n"
+		"Screen_X = %d\r\n"
+		"Screen_Y = %d\r\n"
+		"Popup_Opaque = %d\r\n"
+		"Menu_Frame = %d\r\n"
+		"Show_Menu = %d\r\n"
+		"%n",           // %n causes NO output, but only a measurement
+		setting->color[0],   //Col_1
+		setting->color[1],   //Col_2
+		setting->color[2],   //Col_3
+		setting->color[3],   //Col_4
+		setting->color[4],   //Col_5
+		setting->color[5],   //Col_6
+		setting->color[6],   //Col_7
+		setting->color[7],   //Col_8
+		setting->skin,       //SKIN_FILE
+		setting->GUI_skin,   //GUI_SKIN_FILE
+		setting->Brightness, //SKIN_Brightness
+		setting->TV_mode,    //TV_mode
+		setting->interlace,  //Screen_Interlace
+		setting->screen_x,   //Screen_X
+		setting->screen_y,   //Screen_Y
+		setting->Popup_Opaque, //Popup_Opaque
+		setting->Menu_Frame, //Menu_Frame
+		setting->Show_Menu,  //Show_Menu
+		&CNF_size       // This variable measures the size of sprintf data
+  );
+  return CNF_size;
+}
+//------------------------------
+//endfunc storeSkinCNF
+//---------------------------------------------------------------------------
+//saveSkinCNF will save most cosmetic settings to a skin CNF file
+//------------------------------
+int saveSkinCNF(char *CNF)
+{
+	int ret, fd;
+	char tmp[26*MAX_PATH + 30*MAX_PATH];
+	char cnf_path[MAX_PATH];
+	size_t CNF_size;
+
+	CNF_size = storeSkinCNF(tmp);
+
+	ret = genFixPath(CNF, cnf_path);
+	if((ret < 0) || ((fd=genOpen(cnf_path,O_CREAT|O_WRONLY|O_TRUNC)) < 0)){
+		return -1; //Failed open
+	}
+	ret = genWrite(fd,&tmp,CNF_size);
+	if(ret!=CNF_size)
+		ret = -2; //Failed writing
+	genClose(fd);
+
+	return ret;
+}
+//-----------------------------
+//endfunc saveSkinCNF
+//---------------------------------------------------------------------------
+//saveSkinBrowser will save most cosmetic settings to browsed skin CNF file
+//------------------------------
+void saveSkinBrowser(void)
+{
+	int  tst;
+	char path[MAX_PATH];
+	char mess[MAX_PATH];
+	char *p;
+
+	tst = getFilePath(path, SAVE_CNF);
+	if(path[0] == '\0')
+		goto abort;
+	if(!strncmp(path, "cdfs", 4))
+		goto abort;
+
+	drawMsg(LNG(Enter_File_Name));
+
+	tmp[0]=0;
+	if(tst > 0){ //if an existing file was selected, use its name
+		p = strrchr(path, '/'); //find separator between path and name
+		if(p != NULL){
+			strcpy(tmp, p+1);
+			p[1] = '\0';
+		}else //if we got a pathname without separator, something is wrong
+			goto abort;
+	}
+	if((tst >= 0) && (keyboard(tmp, 36)>0))
+		strcat(path, tmp);
+	else{
+abort:
+		tst = -3;
+		goto test;
+	}
+
+	tst = saveSkinCNF(path);
+
+test:
+	switch(tst){
+	case -1:
+		sprintf(mess, "%s \"%s\".", LNG(Failed_To_Save), path);
+		break;
+	case -2:
+		sprintf(mess, "%s \"%s\".", LNG(Failed_writing), path);
+		break;
+	case -3:
+		sprintf(mess, "%s \"%s\".", LNG(Failed_Saving_File), path);
+		break;
+	default:
+		sprintf(mess, "%s \"%s\".", LNG(Saved), path);
+	}
+	drawMsg(mess);
+}
+//-----------------------------
+//endfunc saveSkinBrowser
+//---------------------------------------------------------------------------
+//preloadCNF loads an entire CNF file into RAM it allocates
+//------------------------------
+unsigned char *preloadCNF(char *path)
+{
+	int fd, tst;
+	size_t CNF_size;
+	char cnf_path[MAX_PATH];
+	unsigned char *RAM_p;
+
+	fd=-1;
+	if((tst = genFixPath(path, cnf_path)) >= 0)
+		fd = genOpen(cnf_path, O_RDONLY);
+	if(fd<0){
+failed_load:
+		return NULL;
+	}
+	CNF_size = genLseek(fd, 0, SEEK_END);
+	printf("CNF_size=%d\n", CNF_size);
+	genLseek(fd, 0, SEEK_SET);
+	RAM_p = (char*)malloc(CNF_size);
+	if	(RAM_p==NULL)	{ genClose(fd); goto failed_load; }
+	genRead(fd, RAM_p, CNF_size);  //Read CNF as one long string
+	genClose(fd);
+	RAM_p[CNF_size] = '\0';        //Terminate the CNF string
+	return RAM_p;
+}
+//------------------------------
+//endfunc preloadCNF
+//---------------------------------------------------------------------------
+//scanSkinCNF will check for most cosmetic variables of a CNF
+//------------------------------
+int scanSkinCNF(unsigned char *name, unsigned char *value)
+{
+	if(!strcmp(name,"GUI_Col_1_ABGR")) setting->color[0] = hextoul(value);
+	else if(!strcmp(name,"GUI_Col_2_ABGR")) setting->color[1] = hextoul(value);
+	else if(!strcmp(name,"GUI_Col_3_ABGR")) setting->color[2] = hextoul(value);
+	else if(!strcmp(name,"GUI_Col_4_ABGR")) setting->color[3] = hextoul(value);
+	else if(!strcmp(name,"GUI_Col_5_ABGR")) setting->color[4] = hextoul(value);
+	else if(!strcmp(name,"GUI_Col_6_ABGR")) setting->color[5] = hextoul(value);
+	else if(!strcmp(name,"GUI_Col_7_ABGR")) setting->color[6] = hextoul(value);
+	else if(!strcmp(name,"GUI_Col_8_ABGR")) setting->color[7] = hextoul(value);
+	//----------
+	else if(!strcmp(name,"SKIN_FILE")) strcpy(setting->skin,value);
+	else if(!strcmp(name,"GUI_SKIN_FILE")) strcpy(setting->GUI_skin,value);
+	else if(!strcmp(name,"SKIN_Brightness")) setting->Brightness = atoi(value);
+	//----------
+	else if(!strcmp(name,"TV_mode")) setting->TV_mode = atoi(value);
+	else if(!strcmp(name,"Screen_Interlace")) setting->interlace = atoi(value);
+	else if(!strcmp(name,"Screen_X")) setting->screen_x = atoi(value);
+	else if(!strcmp(name,"Screen_Y")) setting->screen_y = atoi(value);
+	//----------
+	else if(!strcmp(name,"Popup_Opaque")) setting->Popup_Opaque = atoi(value);
+	else if(!strcmp(name,"Menu_Frame")) setting->Menu_Frame = atoi(value);
+	else if(!strcmp(name,"Show_Menu")) setting->Show_Menu = atoi(value);
+	else
+		return 0; //when no skin variable
+	return 1; //when skin variable found
+}
+//------------------------------
+//endfunc scanSkinCNF
+//---------------------------------------------------------------------------
+//loadSkinCNF will load most cosmetic settings from CNF file
+//------------------------------
+int loadSkinCNF(char *path)
+{
+	int dummy, var_cnt;
+	unsigned char *RAM_p, *CNF_p, *name, *value;
+
+	if( !(RAM_p = preloadCNF(path)) )
+		return -1;
+	CNF_p = RAM_p;
+	for(var_cnt = 0; get_CNF_string(&CNF_p, &name, &value); var_cnt++)
+		dummy = scanSkinCNF(name, value);
+	free(RAM_p);
+	updateScreenMode(0);
+	if(setting->skin)
+		loadSkin(BACKGROUND_PIC, 0, 0);
+	return 0;
+}
+//------------------------------
+//endfunc loadSkinCNF
+//---------------------------------------------------------------------------
+//loadSkinBrowser will load most cosmetic settings from browsed skin CNF file
+//------------------------------
+void loadSkinBrowser(void)
+{
+	int tst;
+	char path[MAX_PATH];
+	char mess[MAX_PATH];
+
+	getFilePath(path, TEXT_CNF); // No Filtering, Be Careful.
+	tst = loadSkinCNF(path);
+	if(tst<0)
+		sprintf(mess, "%s \"%s\".", LNG(Failed_To_Load), path);
+	else
+		sprintf(mess, "%s \"%s\".", LNG(Loaded_Config), path);
+
+	drawMsg(mess);
+}
+//------------------------------
+//endfunc loadSkinBrowser
+//---------------------------------------------------------------------------
+// Save LAUNCHELF.CNF (or LAUNCHELFx.CNF with multiple pages)
+// sincro: ADD save USBD_FILE string
+// polo: ADD save SKIN_FILE string
+// suloku: ADD save MAIN_SKIN string //dlanor: changed to GUI_SKIN_FILE
+//---------------------------------------------------------------------------
+void saveConfig(char *mainMsg, char *CNF)
+{
+	int i, ret, fd;
+	char c[MAX_PATH], tmp[26*MAX_PATH + 30*MAX_PATH];
+	char cnf_path[MAX_PATH];
+	size_t CNF_size, CNF_step;
+
+	sprintf(tmp, "CNF_version = 3\r\n%n", &CNF_size); //Start CNF with version header
+
+	for(i=0; i<16; i++){	//Loop to save the ELF paths for launch keys
+		if((i<12) || (setting->LK_Flag[i]!=0)){
+			sprintf(tmp+CNF_size,
+				"LK_%s_E1 = %s\r\n"
+				"%n",           // %n causes NO output, but only a measurement
+				LK_ID[i], setting->LK_Path[i],
+				&CNF_step       // This variable measures the size of sprintf data
+	  	);
+			CNF_size += CNF_step;
+		}
+	}//ends for
+
+	i = strlen(setting->Misc);
+	sprintf(tmp+CNF_size,
+		"Misc = %s\r\n"
+		"Misc_PS2Disc = %s\r\n"
+		"Misc_FileBrowser = %s\r\n"
+		"Misc_PS2Browser = %s\r\n"
+		"Misc_PS2Net = %s\r\n"
+		"Misc_PS2PowerOff = %s\r\n"
+		"Misc_HddManager = %s\r\n"
+		"Misc_TextEditor = %s\r\n"
+		"Misc_JpgViewer = %s\r\n"
+		"Misc_Configure = %s\r\n"
+		"Misc_Load_CNFprev = %s\r\n"
+		"Misc_Load_CNFnext = %s\r\n"
+		"Misc_Set_CNF_Path = %s\r\n"
+		"Misc_Load_CNF = %s\r\n"
+		"Misc_ShowFont = %s\r\n"
+		"Misc_Debug_Info = %s\r\n"
+		"Misc_About_uLE = %s\r\n"
+		"%n",           // %n causes NO output, but only a measurement
+		setting->Misc,
+		setting->Misc_PS2Disc+i,
+		setting->Misc_FileBrowser+i,
+		setting->Misc_PS2Browser+i,
+		setting->Misc_PS2Net+i,
+		setting->Misc_PS2PowerOff+i,
+		setting->Misc_HddManager+i,
+		setting->Misc_TextEditor+i,
+		setting->Misc_JpgViewer+i,
+		setting->Misc_Configure+i,
+		setting->Misc_Load_CNFprev+i,
+		setting->Misc_Load_CNFnext+i,
+		setting->Misc_Set_CNF_Path+i,
+		setting->Misc_Load_CNF+i,
+		setting->Misc_ShowFont+i,
+		setting->Misc_Debug_Info+i,
+		setting->Misc_About_uLE+i,
+		&CNF_step       // This variable measures the size of sprintf data
+  );
+	CNF_size += CNF_step;
+
+	CNF_size += storeSkinCNF(tmp+CNF_size);
+
+	sprintf(tmp+CNF_size,
+		"LK_auto_Timer = %d\r\n"
+		"Menu_Hide_Paths = %d\r\n"
+		"Init_CDVD_Check = %d\r\n"
+		"Init_Reset_IOP = %d\r\n"
+		"Menu_Pages = %d\r\n"
+		"GUI_Swap_Keys = %d\r\n"
+		"USBD_FILE = %s\r\n"
+		"NET_HOSTwrite = %d\r\n"
+		"Menu_Title = %s\r\n"
+		"Init_Delay = %d\r\n"
+		"USBKBD_USED = %d\r\n"
+		"USBKBD_FILE = %s\r\n"
+		"KBDMAP_FILE = %s\r\n"
+		"Menu_Show_Titles = %d\r\n"
+		"PathPad_Lock = %d\r\n"
+		"CNF_Path = %s\r\n"
+		"USBMASS_FILE = %s\r\n"
+		"LANG_FILE = %s\r\n"
+		"FONT_FILE = %s\r\n"
+		"JpgView_Timer = %d\r\n"
+		"JpgView_Trans = %d\r\n"
+		"JpgView_Full = %d\r\n"
+		"PSU_HugeNames = %d\r\n"
+		"PSU_DateNames = %d\r\n"
+		"PSU_NoOverwrite = %d\r\n"
+		"FB_NoIcons = %d\r\n"
+		"%n",           // %n causes NO output, but only a measurement
+		setting->timeout,    //auto_Timer
+		setting->Hide_Paths,   //Menu_Hide_Paths
+		setting->discControl,  //Init_CDVD_Check
+		setting->resetIOP,   //Init_Reset_IOP
+		setting->numCNF,     //Menu_Pages
+		setting->swapKeys,   //GUI_Swap_Keys
+		setting->usbd_file,  //USBD_FILE
+		setting->HOSTwrite,  //NET_HOST_write
+		setting->Menu_Title, //Menu_Title
+		setting->Init_Delay,   //Init_Delay
+		setting->usbkbd_used,  //USBKBD_USED
+		setting->usbkbd_file,  //USBKBD_FILE
+		setting->kbdmap_file,  //KBDMAP_FILE
+		setting->Show_Titles,  //Menu_Show_Titles
+		setting->PathPad_Lock, //PathPad_Lock
+		setting->CNF_Path,     //CNF_Path
+		setting->usbmass_file,  //USBMASS_FILE
+		setting->lang_file,     //LANG_FILE
+		setting->font_file,     //FONT_FILE
+		setting->JpgView_Timer, //JpgView_Timer
+		setting->JpgView_Trans, //JpgView_Trans
+		setting->JpgView_Full,  //JpgView_Full
+		setting->PSU_HugeNames, //PSU_HugeNames
+		setting->PSU_DateNames, //PSU_DateNames
+		setting->PSU_NoOverwrite, //PSU_NoOverwrite
+		setting->FB_NoIcons, //FB_NoIcons
+		&CNF_step       // This variable measures the size of sprintf data
+  );
+	CNF_size += CNF_step;
+
+	for(i=0; i<16; i++){  //Loop to save user defined launch key titles
+		if(setting->LK_Title[i][0]){  //Only save non-empty strings
+			sprintf(tmp+CNF_size,
+				"LK_%s_Title = %s\r\n"
+				"%n",           // %n causes NO output, but only a measurement
+				LK_ID[i], setting->LK_Title[i],
+				&CNF_step       // This variable measures the size of sprintf data
+		  );
+			CNF_size += CNF_step;
+		}//ends if
+	}//ends for
+
+	sprintf(tmp+CNF_size,
+		"PathPad_Lock = %d\r\n"
+		"%n",           // %n causes NO output, but only a measurement
+		setting->PathPad_Lock, //PathPad_Lock
+		&CNF_step       // This variable measures the size of sprintf data
+  );
+	CNF_size += CNF_step;
+
+	for(i=0; i<30; i++){  //Loop to save non-empty PathPad entries
+		if(PathPad[i][0]){  //Only save non-empty strings
+			sprintf(tmp+CNF_size,
+				"PathPad[%02d] = %s\r\n"
+				"%n",           // %n causes NO output, but only a measurement
+				i, PathPad[i],
+				&CNF_step       // This variable measures the size of sprintf data
+		  );
+			CNF_size += CNF_step;
+		}//ends if
+	}//ends for
+
+	strcpy(c, LaunchElfDir);
+	strcat(c, CNF);
+	ret = genFixPath(c, cnf_path);
+	if((ret >= 0) && ((fd=genOpen(cnf_path, O_RDONLY)) >= 0))
+		genClose(fd);
+	else {  //Start of clause for failure to use LaunchElfDir
+		if(setting->CNF_Path[0]==0) { //if NO CNF Path override defined
+			if(!strncmp(LaunchElfDir, "mc", 2))
+				sprintf(c, "mc%d:/SYS-CONF", LaunchElfDir[2]-'0');
+			else
+				sprintf(c, "mc%d:/SYS-CONF", CheckMC());
+	
+			if((fd=fioDopen(c)) >= 0){
+				fioDclose(fd);
+				char strtmp[MAX_PATH] = "/";
+				strcat(c, strcat(strtmp, CNF));
+			}else{
+				strcpy(c, LaunchElfDir);
+				strcat(c, CNF);
+			}
+		}
+	}  //End of clause for failure to use LaunchElfDir
+
+	ret = genFixPath(c, cnf_path);
+	if((ret < 0) || ((fd=genOpen(cnf_path,O_CREAT|O_WRONLY|O_TRUNC)) < 0)){
+		sprintf(c, "mc%d:/SYS-CONF", CheckMC());
+		if((fd=fioDopen(c)) >= 0){
+			fioDclose(fd);
+			char strtmp[MAX_PATH] = "/";
+			strcat(c, strcat(strtmp, CNF));
+		}else{
+			strcpy(c, LaunchElfDir);
+			strcat(c, CNF);
+		}
+		ret = genFixPath(c, cnf_path);
+		if((fd=genOpen(cnf_path,O_CREAT|O_WRONLY|O_TRUNC)) < 0){
+			sprintf(mainMsg, "%s %s", LNG(Failed_To_Save), CNF);
+			return;
+		}
+	}
+	ret = genWrite(fd,&tmp,CNF_size);
+	if(ret==CNF_size)
+		sprintf(mainMsg, "%s (%s)", LNG(Saved_Config), c);
+	else
+		sprintf(mainMsg, "%s (%s)", LNG(Failed_writing), CNF);
+	genClose(fd);
+}
+//---------------------------------------------------------------------------
+void initConfig(void)
+{
+	int i;
+	
+	if(setting!=NULL)
+		free(setting);
+	setting = (SETTING*)malloc(sizeof(SETTING));
+
+	sprintf(setting->Misc, "%s/", LNG_DEF(MISC));
+	sprintf(setting->Misc_PS2Disc, "%s/%s", LNG_DEF(MISC), LNG_DEF(PS2Disc));
+	sprintf(setting->Misc_FileBrowser, "%s/%s", LNG_DEF(MISC), LNG_DEF(FileBrowser));
+	sprintf(setting->Misc_PS2Browser, "%s/%s", LNG_DEF(MISC), LNG_DEF(PS2Browser));
+	sprintf(setting->Misc_PS2Net, "%s/%s", LNG_DEF(MISC), LNG_DEF(PS2Net));
+	sprintf(setting->Misc_PS2PowerOff, "%s/%s", LNG_DEF(MISC), LNG_DEF(PS2PowerOff));
+	sprintf(setting->Misc_HddManager, "%s/%s", LNG_DEF(MISC), LNG_DEF(HddManager));
+	sprintf(setting->Misc_TextEditor, "%s/%s", LNG_DEF(MISC), LNG_DEF(TextEditor));
+	sprintf(setting->Misc_JpgViewer, "%s/%s", LNG_DEF(MISC), LNG_DEF(JpgViewer));
+	sprintf(setting->Misc_Configure, "%s/%s", LNG_DEF(MISC), LNG_DEF(Configure));
+	sprintf(setting->Misc_Load_CNFprev, "%s/%s", LNG_DEF(MISC), LNG_DEF(Load_CNFprev));
+	sprintf(setting->Misc_Load_CNFnext, "%s/%s", LNG_DEF(MISC), LNG_DEF(Load_CNFnext));
+	sprintf(setting->Misc_Set_CNF_Path, "%s/%s", LNG_DEF(MISC), LNG_DEF(Set_CNF_Path));
+	sprintf(setting->Misc_Load_CNF, "%s/%s", LNG_DEF(MISC), LNG_DEF(Load_CNF));
+	sprintf(setting->Misc_ShowFont, "%s/%s", LNG_DEF(MISC), LNG_DEF(ShowFont));
+	sprintf(setting->Misc_Debug_Info, "%s/%s", LNG_DEF(MISC), LNG_DEF(Debug_Info));
+	sprintf(setting->Misc_About_uLE, "%s/%s", LNG_DEF(MISC), LNG_DEF(About_uLE));
+
+	for(i=0; i<16; i++){
+		setting->LK_Path[i][0]  = 0;
+		setting->LK_Title[i][0] = 0;
+		setting->LK_Flag[i]    = 0;
+	}
+	for(i=0; i<30; i++) PathPad[i][0] = 0;
+
+	strcpy(setting->LK_Path[1], setting->Misc_FileBrowser);
+	setting->LK_Flag[1] = 1;
+	strcpy(setting->LK_Path[4], setting->Misc_About_uLE);
+	setting->LK_Flag[4] = 1;
+	setting->usbd_file[0] = '\0';
+	setting->usbmass_file[0] = '\0';
+	setting->usbkbd_file[0] = '\0';
+	setting->kbdmap_file[0] = '\0';
+	setting->skin[0] = '\0';
+	setting->GUI_skin[0] = '\0';
+	setting->Menu_Title[0] = '\0';
+	setting->CNF_Path[0] = '\0';
+	setting->lang_file[0] = '\0';
+	setting->font_file[0] = '\0';
+	setting->timeout = DEF_TIMEOUT;
+	setting->Hide_Paths = DEF_HIDE_PATHS;
+	setting->color[0] = DEF_COLOR1;
+	setting->color[1] = DEF_COLOR2;
+	setting->color[2] = DEF_COLOR3;
+	setting->color[3] = DEF_COLOR4;
+	setting->color[4] = DEF_COLOR5;
+	setting->color[5] = DEF_COLOR6;
+	setting->color[6] = DEF_COLOR7;
+	setting->color[7] = DEF_COLOR8;
+	setting->screen_x = SCREEN_X;
+	setting->screen_y = SCREEN_Y;
+	setting->discControl = DEF_DISCCONTROL;
+	setting->interlace = DEF_INTERLACE;
+	setting->Menu_Frame = DEF_MENU_FRAME;
+	setting->Show_Menu = DEF_MENU;
+	setting->resetIOP = DEF_RESETIOP;
+	setting->numCNF = DEF_NUMCNF;
+	setting->swapKeys = DEF_SWAPKEYS;
+	setting->HOSTwrite = DEF_HOSTWRITE;
+	setting->Brightness = DEF_BRIGHT;
+	setting->TV_mode = TV_mode_AUTO; //0==Console_auto, 1==NTSC, 2==PAL
+	setting->Popup_Opaque = DEF_POPUP_OPAQUE;
+	setting->Init_Delay = DEF_INIT_DELAY;
+	setting->usbkbd_used = DEF_USBKBD_USED;
+	setting->Show_Titles = DEF_SHOW_TITLES;
+	setting->PathPad_Lock = DEF_PATHPAD_LOCK;
+	setting->JpgView_Timer = -1; //only used to detect missing variable
+	setting->JpgView_Trans = -1; //only used to detect missing variable
+	setting->JpgView_Full = DEF_JPGVIEW_FULL;
+	setting->PSU_HugeNames = DEF_PSU_HUGENAMES;
+	setting->PSU_DateNames = DEF_PSU_DATENAMES;
+	setting->PSU_NoOverwrite = DEF_PSU_NOOVERWRITE;
+	setting->FB_NoIcons = DEF_FB_NOICONS;
+}
+//------------------------------
+//endfunc initConfig
+//---------------------------------------------------------------------------
+// Load LAUNCHELF.CNF (or LAUNCHELFx.CNF with multiple pages)
+// sincro: ADD load USBD_FILE string
+// polo: ADD load SKIN_FILE string
+// suloku: ADD load MAIN_SKIN string //dlanor: changed to GUI_SKIN_FILE
+// dlanor: added error flag return value 0==OK, -1==failure
+//---------------------------------------------------------------------------
+int loadConfig(char *mainMsg, char *CNF)
+{
+	int i, fd, tst, len, mcport, var_cnt, CNF_version;
+	char tsts[20];
+	char path[MAX_PATH];
+	char cnf_path[MAX_PATH];
+	unsigned char *RAM_p, *CNF_p, *name, *value;
+
+	initConfig();
+
+	strcpy(path, LaunchElfDir);
+	strcat(path, CNF);
+	if(!strncmp(path, "cdrom", 5)) strcat(path, ";1");
+
+	fd=-1;
+	if((tst = genFixPath(path, cnf_path)) >= 0)
+		fd = genOpen(cnf_path, O_RDONLY);
+	if(fd<0) {
+		char strtmp[MAX_PATH], *p;
+		int  pos;
+
+		p = strrchr(path, '.');  //make p point to extension
+		if(*(p-1)!='F')          //is this an indexed CNF
+			p--;                   //then make p point to index
+		pos = (p-path);
+		strcpy(strtmp, path);
+		strcpy(strtmp+pos-9, "LNCHELF"); //Replace LAUNCHELF with LNCHELF (for CD)
+		strcpy(strtmp+pos-2, path+pos); //Add index+extension too
+		if((tst = genFixPath(strtmp, cnf_path)) >= 0)
+			fd = genOpen(cnf_path, O_RDONLY);
+		if(fd<0) {
+			if(!strncmp(LaunchElfDir, "mc", 2))
+				mcport = LaunchElfDir[2]-'0';
+			else
+				mcport = CheckMC();
+			if(mcport==1 || mcport==0){
+				sprintf(strtmp, "mc%d:/SYS-CONF/", mcport);
+				strcpy(cnf_path, strtmp);
+				strcat(cnf_path, CNF);
+				fd = genOpen(cnf_path, O_RDONLY);
+				if(fd>=0)
+					strcpy(LaunchElfDir, strtmp);
+			}
+		}
+	}
+	if(fd<0) {
+failed_load:
+		sprintf(mainMsg, "%s %s", LNG(Failed_To_Load), CNF);
+		return -1;
+	}
+	// This point is only reached after succefully opening CNF
+	genClose(fd);
+
+	if( (RAM_p = preloadCNF(cnf_path))==NULL )
+		goto failed_load;
+	CNF_p = RAM_p;
+
+//RA NB: in the code below, the 'LK_' variables have been implemented such that
+//       any _Ex suffix will be accepted, with identical results. This will need
+//       to be modified when more execution methods are implemented.
+
+  CNF_version = 0;  // The CNF version is still unidentified
+	for(var_cnt = 0; get_CNF_string(&CNF_p, &name, &value); var_cnt++)
+	{	// A variable was found, now we dispose of its value.
+		if(!strcmp(name,"CNF_version")){
+			CNF_version = atoi(value);
+			continue;
+		} else if(CNF_version == 0)
+			goto failed_load;  // Refuse unidentified CNF
+
+		if( scanSkinCNF(name, value) )
+			continue;
+
+		for(i=0; i<16; i++){
+			sprintf(tsts, "LK_%s_E%n", LK_ID[i], &len);
+			if(!strncmp(name, tsts, len)) {
+				strcpy(setting->LK_Path[i], value);
+				setting->LK_Flag[i] = 1;
+				break;
+			}
+		}
+		if(i<16) continue;
+		//----------
+		//In the next group, the Misc device must be defined before its subprograms
+		//----------
+		else if(!strcmp(name,"Misc")) sprintf(setting->Misc, "%s/", value);
+		else if(!strcmp(name,"Misc_PS2Disc"))
+			sprintf(setting->Misc_PS2Disc, "%s%s", setting->Misc, value);
+		else if(!strcmp(name,"Misc_FileBrowser"))
+			sprintf(setting->Misc_FileBrowser, "%s%s", setting->Misc, value);
+		else if(!strcmp(name,"Misc_PS2Browser"))
+			sprintf(setting->Misc_PS2Browser, "%s%s", setting->Misc, value);
+		else if(!strcmp(name,"Misc_PS2Net"))
+			sprintf(setting->Misc_PS2Net, "%s%s", setting->Misc, value);
+		else if(!strcmp(name,"Misc_PS2PowerOff"))
+			sprintf(setting->Misc_PS2PowerOff, "%s%s", setting->Misc, value);
+		else if(!strcmp(name,"Misc_HddManager"))
+			sprintf(setting->Misc_HddManager, "%s%s", setting->Misc, value);
+		else if(!strcmp(name,"Misc_TextEditor"))
+			sprintf(setting->Misc_TextEditor, "%s%s", setting->Misc, value);
+		else if(!strcmp(name,"Misc_JpgViewer"))
+			sprintf(setting->Misc_JpgViewer, "%s%s", setting->Misc, value);
+		else if(!strcmp(name,"Misc_Configure"))
+			sprintf(setting->Misc_Configure, "%s%s", setting->Misc, value);
+		else if(!strcmp(name,"Misc_Load_CNFprev"))
+			sprintf(setting->Misc_Load_CNFprev, "%s%s", setting->Misc, value);
+		else if(!strcmp(name,"Misc_Load_CNFnext"))
+			sprintf(setting->Misc_Load_CNFnext, "%s%s", setting->Misc, value);
+		else if(!strcmp(name,"Misc_Set_CNF_Path"))
+			sprintf(setting->Misc_Set_CNF_Path, "%s%s", setting->Misc, value);
+		else if(!strcmp(name,"Misc_Load_CNF"))
+			sprintf(setting->Misc_Load_CNF, "%s%s", setting->Misc, value);
+		else if(!strcmp(name,"Misc_ShowFont"))
+			sprintf(setting->Misc_ShowFont, "%s%s", setting->Misc, value);
+		else if(!strcmp(name,"Misc_Debug_Info"))
+			sprintf(setting->Misc_Debug_Info, "%s%s", setting->Misc, value);
+		else if(!strcmp(name,"Misc_About_uLE"))
+			sprintf(setting->Misc_About_uLE, "%s%s", setting->Misc, value);
+		//----------
+		else if(!strcmp(name,"LK_auto_Timer")) setting->timeout = atoi(value);
+		else if(!strcmp(name,"Menu_Hide_Paths")) setting->Hide_Paths = atoi(value);
+		//---------- NB: color settings moved to scanSkinCNF
+		else if(!strcmp(name,"Init_CDVD_Check")) setting->discControl = atoi(value);
+		else if(!strcmp(name,"Init_Reset_IOP")) setting->resetIOP = atoi(value);
+		else if(!strcmp(name,"Menu_Pages")) setting->numCNF = atoi(value);
+		else if(!strcmp(name,"GUI_Swap_Keys")) setting->swapKeys = atoi(value);
+		else if(!strcmp(name,"USBD_FILE")) strcpy(setting->usbd_file,value);
+		else if(!strcmp(name,"NET_HOSTwrite")) setting->HOSTwrite = atoi(value);
+		else if(!strcmp(name,"Menu_Title")){
+			strncpy(setting->Menu_Title, value, MAX_MENU_TITLE);
+			setting->Menu_Title[MAX_MENU_TITLE] = '\0';
+		}
+		else if(!strcmp(name,"Init_Delay")) setting->Init_Delay = atoi(value);
+		else if(!strcmp(name,"USBKBD_USED")) setting->usbkbd_used = atoi(value);
+		else if(!strcmp(name,"USBKBD_FILE")) strcpy(setting->usbkbd_file,value);
+		else if(!strcmp(name,"KBDMAP_FILE")) strcpy(setting->kbdmap_file,value);
+		else if(!strcmp(name,"Menu_Show_Titles")) setting->Show_Titles = atoi(value);
+		else if(!strcmp(name,"PathPad_Lock")) setting->PathPad_Lock = atoi(value);
+		else if(!strcmp(name,"CNF_Path")) strcpy(setting->CNF_Path,value);
+		else if(!strcmp(name,"USBMASS_FILE")) strcpy(setting->usbmass_file,value);
+		else if(!strcmp(name,"LANG_FILE")) strcpy(setting->lang_file,value);
+		else if(!strcmp(name,"FONT_FILE")) strcpy(setting->font_file,value);
+		//----------
+		else if(!strcmp(name,"JpgView_Timer")) setting->JpgView_Timer = atoi(value);
+		else if(!strcmp(name,"JpgView_Trans")) setting->JpgView_Trans = atoi(value);
+		else if(!strcmp(name,"JpgView_Full")) setting->JpgView_Full = atoi(value);
+		//----------
+		else if(!strcmp(name,"PSU_HugeNames")) setting->PSU_HugeNames = atoi(value);
+		else if(!strcmp(name,"PSU_DateNames")) setting->PSU_DateNames = atoi(value);
+		else if(!strcmp(name,"PSU_NoOverwrite")) setting->PSU_NoOverwrite = atoi(value);
+		else if(!strcmp(name,"FB_NoIcons")) setting->FB_NoIcons = atoi(value);
+		//----------
+		else {
+			for(i=0; i<16; i++){
+				sprintf(tsts, "LK_%s_Title", LK_ID[i]);
+				if(!strcmp(name, tsts)) {
+					strncpy(setting->LK_Title[i], value, MAX_ELF_TITLE-1);
+					break;
+				}
+			}
+			if(i<16) continue;
+			else if(!strncmp(name,"PathPad[",8)){
+				i = atoi(name+8);
+				if(i < 30){
+					strncpy(PathPad[i], value, MAX_PATH-1);
+					PathPad[i][MAX_PATH-1] = '\0';
+				}
+			}
+		}
+	} //ends for
+	for(i=0; i<16; i++) setting->LK_Title[i][MAX_ELF_TITLE-1] = 0;
+	free(RAM_p);
+	if(setting->JpgView_Timer < 0)
+		setting->JpgView_Timer = DEF_JPGVIEW_TIMER;
+	if((setting->JpgView_Trans < 1) || (setting->JpgView_Trans > 4))
+		setting->JpgView_Trans = DEF_JPGVIEW_TRANS;
+	sprintf(mainMsg, "%s (%s)", LNG(Loaded_Config), path);
+	return 0;
+}
+//------------------------------
+//endfunc loadConfig
+//---------------------------------------------------------------------------
+// Polo: ADD Skin Menu with Skin preview
+// suloku: ADD Main skin selection
+//---------------------------------------------------------------------------
+void Config_Skin(void)
+{
+	int  s, max_s=7;
+	int  x, y;
+	int event, post_event=0;
+	char c[MAX_PATH];
+	char skinSave[MAX_PATH], GUI_Save[MAX_PATH];
+	int  Brightness = setting->Brightness;
+	int current_preview = 0;
+
+	strcpy(skinSave, setting->skin);
+	strcpy(GUI_Save, setting->GUI_skin);
+
+	loadSkin(PREVIEW_PIC, 0, 0);
+	current_preview = PREVIEW_PIC;
+
+	s=1;
+	event = 1;  //event = initial entry
+	while(1)
+	{
+		//Pad response section
+		waitPadReady(0, 0);
+		if(readpad())
+		{
+			if(new_pad & PAD_UP)
+			{
+				event |= 2;  //event |= valid pad command
+				if(s!=1) s--;
+				else s=max_s;
+			}
+			else if(new_pad & PAD_DOWN)
+			{
+				event |= 2;  //event |= valid pad command
+				if(s!=max_s) s++;
+				else s=1;
+			}
+			else if(new_pad & PAD_LEFT)
+			{
+				event |= 2;  //event |= valid pad command
+				if(s!=1) s=1;
+				else s=max_s;
+			}
+			else if(new_pad & PAD_RIGHT)
+			{
+				event |= 2;  //event |= valid pad command
+				if(s!=max_s) s=max_s;
+				else s=1;
+			}
+			else if((!swapKeys && new_pad & PAD_CROSS) || (swapKeys && new_pad & PAD_CIRCLE) )
+			{
+				event |= 2;  //event |= valid pad command
+				if(s==1) {                      //Command == Cancel Skin Path
+					setting->skin[0] = '\0';
+					loadSkin(PREVIEW_PIC, 0, 0);
+					current_preview = PREVIEW_PIC;
+				} else if(s==3) {               //Command == Decrease Brightness
+					if((Brightness > 0)&&(testsetskin == 1)) {
+						Brightness--;
+					}
+				} else if(s==4) {               //Command == Cancel GUI Skin Path
+					setting->GUI_skin[0] = '\0';
+					loadSkin(PREVIEW_GUI, 0, 0);
+					current_preview = PREVIEW_GUI;
+				}
+			}
+			else if((swapKeys && new_pad & PAD_CROSS) || (!swapKeys && new_pad & PAD_CIRCLE))
+			{
+				event |= 2;  //event |= valid pad command
+				if(s==1) {                      //Command == Set Skin Path
+					getFilePath(setting->skin, SKIN_CNF);
+					loadSkin(PREVIEW_PIC, 0, 0);
+					current_preview = PREVIEW_PIC;
+				} else if(s==2) {               //Command == Apply New Skin
+					GUI_active = 0;
+					loadSkin(BACKGROUND_PIC, 0, 0);
+					setting->Brightness = Brightness;
+					strcpy(skinSave, setting->skin);
+					loadSkin(PREVIEW_PIC, 0, 0);
+					current_preview = PREVIEW_PIC;
+			} else if(s==3) {               //Command == Increase Brightness
+					if((Brightness < 100)&&(testsetskin == 1)) {
+						Brightness++;
+					}
+				} else if(s==4) {               //Command == Set GUI Skin Path
+					getFilePath(setting->GUI_skin, GUI_SKIN_CNF);
+					loadSkin(PREVIEW_GUI, 0, 0);
+					current_preview = PREVIEW_GUI;
+				} else if(s==5) {               //Command == Apply GUI Skin
+					strcpy(GUI_Save, setting->GUI_skin);
+					loadSkin(PREVIEW_GUI, 0, 0);
+					current_preview = PREVIEW_GUI;
+				} else if(s==6) {               //Command == Show GUI Menu
+					setting->Show_Menu = !setting->Show_Menu;
+				} else if(s==7) {               //Command == RETURN
+					setting->skin[0] = '\0';
+					strcpy(setting->skin, skinSave);
+					setting->GUI_skin[0] = '\0';
+					strcpy(setting->GUI_skin, GUI_Save);
+					return;
+				}
+			}
+			else if(new_pad & PAD_TRIANGLE) {
+				setting->skin[0] = '\0';
+				strcpy(setting->skin, skinSave);
+				setting->GUI_skin[0] = '\0';
+				strcpy(setting->GUI_skin, GUI_Save);
+				return;
+			}
+		} //end if(readpad())
+		
+		if(event||post_event){ //NB: We need to update two frame buffers per event
+
+			//Display section
+			clrScr(setting->color[0]);
+
+			if ( testsetskin == 1 ) {
+				setBrightness(Brightness);
+				gsKit_prim_sprite_texture(gsGlobal, &TexPreview,
+				 SCREEN_WIDTH/4, ( SCREEN_HEIGHT/4 )+60, 0, 0,
+				 ( SCREEN_WIDTH/4 )*3, ( ( SCREEN_HEIGHT/4 )*3 )+60, SCREEN_WIDTH, SCREEN_HEIGHT,
+				 0, BrightColor);
+				setBrightness(50);
+			} else {
+				gsKit_prim_sprite(gsGlobal,
+				 SCREEN_WIDTH/4, ( SCREEN_HEIGHT/4 )+60, ( SCREEN_WIDTH/4 )*3, ( ( SCREEN_HEIGHT/4 )*3 )+60,
+				 0, setting->color[0]);
+			}
+			drawFrame( ( SCREEN_WIDTH/4 )-2, ( ( SCREEN_HEIGHT/4 )+60 )-1,
+			 ( ( SCREEN_WIDTH/4 )*3 )+1, ( ( SCREEN_HEIGHT/4 )*3 )+60,
+			  setting->color[1]);
+
+			x = Menu_start_x;
+			y = Menu_start_y;
+		
+			printXY(LNG(SKIN_SETTINGS), x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			if(strlen(setting->skin)==0)
+				sprintf(c, "  %s: %s", LNG(Skin_Path), LNG(NULL));
+			else
+				sprintf(c, "  %s: %s", LNG(Skin_Path), setting->skin);
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			sprintf(c, "  %s", LNG(Apply_New_Skin));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			sprintf(c, "  %s: %d", LNG(Brightness), Brightness);
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			if(strlen(setting->GUI_skin)==0)
+				sprintf(c, "  %s %s: %s", LNG(GUI), LNG(Skin_Path), LNG(NULL));
+			else
+				sprintf(c, "  %s %s: %s", LNG(GUI), LNG(Skin_Path), setting->GUI_skin);
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			sprintf(c, "  %s", LNG(Apply_GUI_Skin));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			if(setting->Show_Menu)
+				sprintf(c, "  %s: %s", LNG(Show_Menu), LNG(ON));
+			else
+				sprintf(c, "  %s: %s", LNG(Show_Menu), LNG(OFF));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			sprintf(c, "  %s", LNG(RETURN));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			if(current_preview == PREVIEW_PIC)
+				sprintf(c, "%s ", LNG(Normal));
+			else
+				sprintf(c, "%s ", LNG(GUI));
+			strcat(c, LNG(Skin_Preview));
+			printXY(c, SCREEN_WIDTH/4, (SCREEN_HEIGHT/4)+78-FONT_HEIGHT, setting->color[3], TRUE, 0);
+
+			//Cursor positioning section
+			y = Menu_start_y + s*(FONT_HEIGHT);
+			drawChar(LEFT_CUR, x, y, setting->color[3]);
+
+			//Tooltip section
+			if ((s == 1)||(s == 4)) {
+				if (swapKeys)
+					sprintf(c, "ÿ1:%s ÿ0:%s", LNG(Edit), LNG(Clear));
+				else
+					sprintf(c, "ÿ0:%s ÿ1:%s", LNG(Edit), LNG(Clear));
+			} else if (s == 3) {  //if cursor at a colour component or a screen offset
+				if (swapKeys)
+					sprintf(c, "ÿ1:%s ÿ0:%s", LNG(Add), LNG(Subtract));
+				else
+					sprintf(c, "ÿ0:%s ÿ1:%s", LNG(Add), LNG(Subtract));
+			} else if (s == 6) {
+				if (swapKeys)
+					sprintf(c, "ÿ1:%s", LNG(Change));
+				else
+					sprintf(c, "ÿ0:%s", LNG(Change));
+			} else {
+				if (swapKeys)
+					sprintf(c, "ÿ1:%s", LNG(OK));
+				else
+					sprintf(c, "ÿ0:%s", LNG(OK));
+			}
+			sprintf(tmp, " ÿ3:%s", LNG(Return));
+			strcat(c, tmp);
+			setScrTmp("", c);
+		}//ends if(event||post_event)
+		drawScr();
+		post_event = event;
+		event = 0;
+
+	}//ends while
+}//ends Config_Skin
+//---------------------------------------------------------------------------
+void Config_Screen(void)
+{
+	int i;
+	int s, max_s=35;		//define cursor index and its max value
+	int x, y;
+	int event, post_event=0;
+	u64 rgb[8][3];
+	char c[MAX_PATH];
+	int space=((SCREEN_WIDTH-SCREEN_MARGIN-4*FONT_WIDTH)-(Menu_start_x+2*FONT_WIDTH))/8;
+	
+	event = 1;	//event = initial entry
+
+	for(i=0; i<8; i++) {
+		rgb[i][0] = setting->color[i] & 0xFF;
+		rgb[i][1] = setting->color[i] >> 8 & 0xFF;
+		rgb[i][2] = setting->color[i] >> 16 & 0xFF;
+	}
+	
+	s=0;
+	while(1)
+	{
+		//Pad response section
+		waitPadReady(0, 0);
+		if(readpad())
+		{
+			if(new_pad & PAD_UP)
+			{
+				event |= 2;  //event |= valid pad command
+				if(s==0)
+					s=max_s;
+				else if(s==24)
+					s=2;
+				else
+					s--;
+			}
+			else if(new_pad & PAD_DOWN)
+			{
+				event |= 2;  //event |= valid pad command
+				if((s<24)&&(s%3==2))
+					s=24;
+				else if(s==max_s)
+					s=0;
+				else
+					s++;
+			}
+			else if(new_pad & PAD_LEFT)
+			{
+				event |= 2;  //event |= valid pad command
+				if(s>=34) s=32;
+				else if(s>=32) s=31;
+				else if(s>=31) s=28;
+				else if(s>=28) s=27;
+				else if(s>=27) s=25;
+				else if(s>=25) s=24; //at or 
+				else if(s>=24) s=21; //if s beyond color settings
+				else if(s>=3) s-=3;  //if s in a color beyond Color1 step to preceding color
+			}
+			else if(new_pad & PAD_RIGHT)
+			{
+				event |= 2;  //event |= valid pad command
+				if(s>=32) s=34;
+				else if(s>=31) s=32;
+				else if(s>=28) s=31;
+				else if(s>=27) s=28;
+				else if(s>=25) s=27;
+				else if(s>=24) s=25;
+				else if(s>=21) s=24; //if s in Color8, move it to ScreenX
+				else s+=3;           //if s in a color before Color8, step to next color
+			}
+			else if((!swapKeys && new_pad & PAD_CROSS) || (swapKeys && new_pad & PAD_CIRCLE) )
+			{ //User pressed CANCEL=>Subtract/Clear
+				event |= 2;  //event |= valid pad command
+				if(s<24) {
+					if(rgb[s/3][s%3] > 0) {
+						rgb[s/3][s%3]--;
+						setting->color[s/3] = 
+							GS_SETREG_RGBA(rgb[s/3][0], rgb[s/3][1], rgb[s/3][2], 0);
+					}
+				} else if(s==25) {
+					if(setting->screen_x > 0) {
+						setting->screen_x--;
+						updateScreenMode(0);
+					}
+				} else if(s==26) {
+					if(setting->screen_y > 0) {
+						setting->screen_y--;
+						updateScreenMode(0);
+					}
+				} else if(s==31) {  //cursor is at Menu_Title
+						setting->Menu_Title[0] = '\0';
+				}
+			}
+			else if((swapKeys && new_pad & PAD_CROSS) || (!swapKeys && new_pad & PAD_CIRCLE))
+			{ //User pressed OK=>Add/Ok/Edit
+				event |= 2;  //event |= valid pad command
+				if(s<24) {
+					if(rgb[s/3][s%3] < 255) {
+						rgb[s/3][s%3]++;
+						setting->color[s/3] = 
+							GS_SETREG_RGBA(rgb[s/3][0], rgb[s/3][1], rgb[s/3][2], 0);
+					}
+				}else if(s==24){
+					setting->TV_mode = (setting->TV_mode+1)%3; //Change between 0,1,2
+					updateScreenMode(1);
+				} else if(s==25) {
+					setting->screen_x++;
+					updateScreenMode(0);
+				} else if(s==26) {
+					setting->screen_y++;
+					updateScreenMode(0);
+				} else if(s==27) {
+					setting->interlace = !setting->interlace;
+					updateScreenMode(1);
+				} else if(s==28) {
+					Config_Skin();
+				} else if(s==29) {
+					loadSkinBrowser();
+				} else if(s==30) {
+					saveSkinBrowser();
+				} else if(s==31) {  //cursor is at Menu_Title
+					char tmp[MAX_MENU_TITLE+1];
+					strcpy(tmp, setting->Menu_Title);
+					if(keyboard(tmp, 36)>=0)
+						strcpy(setting->Menu_Title, tmp);
+				} else if(s==32) {
+					setting->Menu_Frame = !setting->Menu_Frame;
+				} else if(s==33) {
+					setting->Popup_Opaque = !setting->Popup_Opaque;
+				} else if(s==max_s-1) { //Always put 'RETURN' next to last
+					return;
+				} else if(s==max_s) { //Always put 'DEFAULT SCREEN SETTINGS' last
+					setting->skin[0] = '\0';
+					setting->GUI_skin[0] = '\0';
+					loadSkin(BACKGROUND_PIC, 0, 0);
+					setting->color[0] = DEF_COLOR1;
+					setting->color[1] = DEF_COLOR2;
+					setting->color[2] = DEF_COLOR3;
+					setting->color[3] = DEF_COLOR4;
+					setting->color[4] = DEF_COLOR5;
+					setting->color[5] = DEF_COLOR6;
+					setting->color[6] = DEF_COLOR7;
+					setting->color[7] = DEF_COLOR8;
+					setting->TV_mode = TV_mode_AUTO;
+					setting->screen_x = SCREEN_X;
+					setting->screen_y = SCREEN_Y;
+					setting->interlace = DEF_INTERLACE;
+					setting->Menu_Frame = DEF_MENU_FRAME;
+					setting->Show_Menu = DEF_MENU;
+					setting->Brightness = DEF_BRIGHT;
+					setting->Popup_Opaque = DEF_POPUP_OPAQUE;
+					updateScreenMode(0);
+					
+					for(i=0; i<8; i++) {
+						rgb[i][0] = setting->color[i] & 0xFF;
+						rgb[i][1] = setting->color[i] >> 8 & 0xFF;
+						rgb[i][2] = setting->color[i] >> 16 & 0xFF;
+					}
+				}
+			}
+			else if(new_pad & PAD_TRIANGLE)
+				return;
+		}
+
+		if(event||post_event){ //NB: We need to update two frame buffers per event
+
+			//Display section
+			clrScr(setting->color[0]);
+
+			x = Menu_start_x;
+
+			for(i=0; i<8; i++){
+				y = Menu_start_y;
+				sprintf(c, "%s%d", LNG(Color), i+1);
+				printXY(c, x+(space*(i+1))-(printXY(c, 0, 0, 0, FALSE, space-FONT_WIDTH/2)/2), y,
+					setting->color[3], TRUE, space-FONT_WIDTH/2);
+				if(i==0)
+					sprintf(c, "%s", LNG(Backgr));
+				else if(i==1)
+					sprintf(c, "%s", LNG(Frames));
+				else if(i==2)
+					sprintf(c, "%s", LNG(Select));
+				else if(i==3)
+					sprintf(c, "%s", LNG(Normal));
+				else if(i>=4)
+					sprintf(c, "%s%d", LNG(Graph), i-3);
+				printXY(c, x+(space*(i+1))-(printXY(c, 0, 0, 0, FALSE, space-FONT_WIDTH/2)/2), y+FONT_HEIGHT,
+					setting->color[3], TRUE, space-FONT_WIDTH/2);
+				y += FONT_HEIGHT*2;
+				printXY("R:", x, y, setting->color[3], TRUE, 0);
+				sprintf(c, "%02lX", rgb[i][0]);
+				printXY(c, x+(space*(i+1))-FONT_WIDTH, y, setting->color[3], TRUE, 0);
+				y += FONT_HEIGHT;
+				printXY("G:", x, y, setting->color[3], TRUE, 0);
+				sprintf(c, "%02lX", rgb[i][1]);
+				printXY(c, x+(space*(i+1))-FONT_WIDTH, y, setting->color[3], TRUE, 0);
+				y += FONT_HEIGHT;
+				printXY("B:", x, y, setting->color[3], TRUE, 0);
+				sprintf(c, "%02lX", rgb[i][2]);
+				printXY(c, x+(space*(i+1))-FONT_WIDTH, y, setting->color[3], TRUE, 0);
+				y += FONT_HEIGHT;
+				sprintf(c, "ÿ4");
+				printXY(c, x+(space*(i+1))-FONT_WIDTH, y, setting->color[i], TRUE, 0);
+			} //ends loop for colour RGB values
+			y += FONT_HEIGHT*2;
+			sprintf(c, "  %s: ", LNG(TV_mode));
+			if(setting->TV_mode==TV_mode_NTSC)
+				strcat(c, "NTSC");
+			else if(setting->TV_mode==TV_mode_PAL)
+				strcat(c, "PAL");
+			else
+				strcat(c, "AUTO");
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+			y += FONT_HEIGHT / 2;
+
+			sprintf(c, "  %s: %d", LNG(Screen_X_offset), setting->screen_x);
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+			sprintf(c, "  %s: %d", LNG(Screen_Y_offset), setting->screen_y);
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+			y += FONT_HEIGHT / 2;
+
+			if(setting->interlace)
+				sprintf(c, "  %s: %s", LNG(Interlace), LNG(ON));
+			else
+				sprintf(c, "  %s: %s", LNG(Interlace), LNG(OFF));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+			y += FONT_HEIGHT / 2;
+
+			sprintf(c, "  %s...", LNG(Skin_Settings));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+			sprintf(c, "  %s...", LNG(Load_Skin_CNF));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+			sprintf(c, "  %s...", LNG(Save_Skin_CNF));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+			y += FONT_HEIGHT / 2;
+
+			if(setting->Menu_Title[0]=='\0')
+				sprintf(c, "  %s: %s", LNG(Menu_Title), LNG(NULL));
+			else
+				sprintf(c, "  %s: %s", LNG(Menu_Title),setting->Menu_Title);
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+			y += FONT_HEIGHT / 2;
+
+			if(setting->Menu_Frame)
+				sprintf(c, "  %s: %s", LNG(Menu_Frame), LNG(ON));
+			else
+				sprintf(c, "  %s: %s", LNG(Menu_Frame), LNG(OFF));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			if(setting->Popup_Opaque)
+				sprintf(c, "  %s: %s", LNG(Popups_Opaque), LNG(ON));
+			else
+				sprintf(c, "  %s: %s", LNG(Popups_Opaque), LNG(OFF));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+			y += FONT_HEIGHT / 2;
+
+			sprintf(c, "  %s", LNG(RETURN));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+			sprintf(c, "  %s", LNG(Use_Default_Screen_Settings));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			//Cursor positioning section
+			x = Menu_start_x;
+			y = Menu_start_y;
+
+			if(s<24){  //if cursor indicates a colour component
+				int colnum = s/3;
+				int comnum = s-colnum*3;
+				x += (space*(colnum+1))-(FONT_WIDTH*4);
+				y += (2+comnum)*FONT_HEIGHT;
+			} else {  //if cursor indicates anything after colour components
+				y += (s-24+6)*FONT_HEIGHT+FONT_HEIGHT/2;  //adjust y for cursor beyond colours
+				//Here y is almost correct, except for additional group spacing
+				if(s>=24)            //if cursor at or beyond TV mode choice
+					y+=FONT_HEIGHT/2;  //adjust for half-row space below colours
+				if(s>=25)            //if cursor at or beyond screen offsets
+					y+=FONT_HEIGHT/2;  //adjust for half-row space below TV mode choice
+				if(s>=27)            //if cursor at or beyond interlace choice
+					y+=FONT_HEIGHT/2;  //adjust for half-row space below screen offsets
+				if(s>=28)            //if cursor at or beyond 'SKIN SETTINGS'
+					y+=FONT_HEIGHT/2;  //adjust for half-row space below interlace choice
+				if(s>=31)            //if cursor at or beyond 'Menu Title'
+					y+=FONT_HEIGHT/2;  //adjust for half-row space below 'SKIN SETTINGS'
+				if(s>=32)            //if cursor at or beyond 'Menu Frame'
+					y+=FONT_HEIGHT/2;  //adjust for half-row space below 'Menu Title'
+				if(s>=max_s-1)            //if cursor at or beyond 'RETURN'
+					y+=FONT_HEIGHT/2;  //adjust for half-row space below 'Popups Opaque'
+			}
+			drawChar(LEFT_CUR, x, y, setting->color[3]);  //draw cursor
+
+			//Tooltip section
+			if (s<24||s==25||s==26) {  //if cursor at a colour component or a screen offset
+				if (swapKeys)
+					sprintf(c, "ÿ1:%s ÿ0:%s", LNG(Add), LNG(Subtract));
+				else
+					sprintf(c, "ÿ0:%s ÿ1:%s", LNG(Add), LNG(Subtract));
+			} else if(s==24||s==27||s==32||s==33) {
+				//if cursor at 'TV mode', 'INTERLACE', 'Menu Frame' or 'Popups Opaque'
+				if (swapKeys)
+					sprintf(c, "ÿ1:%s", LNG(Change));
+				else
+					sprintf(c, "ÿ0:%s", LNG(Change));
+			} else if(s==28||s==29||s==30){  //if cursor at 'SKIN SETTINGS'
+				if (swapKeys)
+					sprintf(c, "ÿ1:%s", LNG(OK));
+				else
+					sprintf(c, "ÿ0:%s", LNG(OK));
+			} else if(s==31){  //if cursor at Menu_Title
+				if (swapKeys)
+					sprintf(c, "ÿ1:%s ÿ0:%s", LNG(Edit), LNG(Clear));
+				else
+					sprintf(c, "ÿ0:%s ÿ1:%s", LNG(Edit), LNG(Clear));
+			} else {  //if cursor at 'RETURN' or 'DEFAULT' options
+				if (swapKeys)
+					sprintf(c, "ÿ1:%s", LNG(OK));
+				else
+					sprintf(c, "ÿ0:%s", LNG(OK));
+			}
+			sprintf(tmp, " ÿ3:%s", LNG(Return));
+			strcat(c, tmp);
+			setScrTmp("", c);
+		}//ends if(event||post_event)
+		drawScr();
+		post_event = event;
+		event = 0;
+
+	}//ends while
+}//ends Config_Screen
+//---------------------------------------------------------------------------
+// Other settings by EP
+// sincro: ADD USBD SELECTOR MENU
+// dlanor: Add Menu_Title config
+//---------------------------------------------------------------------------
+void Config_Startup(void)
+{
+	int s, max_s=15;		//define cursor index and its max value
+	int x, y;
+	int event, post_event=0;
+	char c[MAX_PATH];
+
+	event = 1;	//event = initial entry
+	s=1;
+	while(1)
+	{
+		//Pad response section
+		waitPadReady(0, 0);
+		if(readpad())
+		{
+			if(new_pad & PAD_UP)
+			{
+				event |= 2;  //event |= valid pad command
+				if(s!=1) s--;
+				else s=max_s;
+			}
+			else if(new_pad & PAD_DOWN)
+			{
+				event |= 2;  //event |= valid pad command
+				if(s!=max_s) s++;
+				else s=1;
+			}
+			else if(new_pad & PAD_LEFT)
+			{
+				event |= 2;  //event |= valid pad command
+				if(s!=max_s) s=max_s;
+				else s=1;
+			}
+			else if(new_pad & PAD_RIGHT)
+			{
+				event |= 2;  //event |= valid pad command
+				if(s!=max_s) s=max_s;
+				else s=1;
+			}
+			else if((!swapKeys && new_pad & PAD_CROSS) || (swapKeys && new_pad & PAD_CIRCLE) )
+			{
+				event |= 2;  //event |= valid pad command
+				if(s==2 && setting->numCNF>1) setting->numCNF--;
+				else if(s==4) setting->usbd_file[0] = '\0';
+				else if(s==5 && setting->Init_Delay>0) setting->Init_Delay--;
+				else if(s==6 && setting->timeout>0) setting->timeout--;
+				else if(s==8) setting->usbkbd_file[0] = '\0';
+				else if(s==9) setting->kbdmap_file[0] = '\0';
+				else if(s==10) setting->CNF_Path[0] = '\0';
+				else if(s==11) setting->usbmass_file[0] = '\0';
+				else if(s==12){
+					setting->lang_file[0] = '\0';
+					Load_External_Language();
+				}
+				else if(s==13){
+					setting->font_file[0] = '\0';
+					loadFont("");
+				}else if(s==14){
+					setting->LK_Path[15][0] = 0;
+					setting->LK_Flag[15] = 0;
+				}
+			}
+			else if((swapKeys && new_pad & PAD_CROSS) || (!swapKeys && new_pad & PAD_CIRCLE))
+			{
+				event |= 2;  //event |= valid pad command
+				if(s==1)
+					setting->resetIOP = !setting->resetIOP;
+				else if(s==2)
+					setting->numCNF++;
+				else if(s==3)
+					setting->swapKeys = !setting->swapKeys;
+				else if(s==4)
+					getFilePath(setting->usbd_file, USBD_IRX_CNF);
+				else if(s==5)
+					setting->Init_Delay++;
+				else if(s==6)
+					setting->timeout++;
+				else if(s==7)
+					setting->usbkbd_used = !setting->usbkbd_used;
+				else if(s==8)
+					getFilePath(setting->usbkbd_file, USBKBD_IRX_CNF);
+				else if(s==9)
+					getFilePath(setting->kbdmap_file, KBDMAP_FILE_CNF);
+				else if(s==10)
+				{	char *tmp;
+
+					getFilePath(setting->CNF_Path, CNF_PATH_CNF);
+					if((tmp = strrchr(setting->CNF_Path, '/')))
+						tmp[1] = '\0';
+				}
+				else if(s==11)
+					getFilePath(setting->usbmass_file, USBMASS_IRX_CNF);
+				else if(s==12){
+					getFilePath(setting->lang_file, LANG_CNF);
+					Load_External_Language();
+				}else if(s==13){
+					getFilePath(setting->font_file, FONT_CNF);
+					if(loadFont(setting->font_file)==0)
+						setting->font_file[0] = '\0';
+				}else if(s==14){
+					getFilePath(setting->LK_Path[15], TRUE);
+					if(!strncmp(setting->LK_Path[15], "mc0", 3) ||
+						!strncmp(setting->LK_Path[15], "mc1", 3)){
+						sprintf(c, "mc%s", &setting->LK_Path[15][3]);
+						strcpy(setting->LK_Path[15], c);
+					}
+					if(setting->LK_Path[15][0])
+						setting->LK_Flag[15] = 1;
+				}else if(s==max_s)
+					return;
+			}
+			else if(new_pad & PAD_TRIANGLE)
+				return;
+		}
+
+		if(event||post_event){ //NB: We need to update two frame buffers per event
+
+			//Display section
+			clrScr(setting->color[0]);
+
+			x = Menu_start_x;
+			y = Menu_start_y;
+
+			printXY(LNG(STARTUP_SETTINGS), x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+			y += FONT_HEIGHT / 2;
+
+			if(setting->resetIOP)
+				sprintf(c, "  %s: %s", LNG(Reset_IOP), LNG(ON));
+			else
+				sprintf(c, "  %s: %s", LNG(Reset_IOP), LNG(OFF));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			sprintf(c, "  %s: %d", LNG(Number_of_CNFs), setting->numCNF);
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			if(setting->swapKeys)
+				sprintf(c, "  %s: ÿ1:%s ÿ0:%s", LNG(Pad_mapping), LNG(OK), LNG(CANCEL));
+			else
+				sprintf(c, "  %s: ÿ0:%s ÿ1:%s", LNG(Pad_mapping), LNG(OK), LNG(CANCEL));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			if(strlen(setting->usbd_file)==0)
+				sprintf(c, "  %s: %s", LNG(USBD_IRX), LNG(DEFAULT));
+			else
+				sprintf(c, "  %s: %s", LNG(USBD_IRX), setting->usbd_file);
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			sprintf(c, "  %s: %d", LNG(Initial_Delay), setting->Init_Delay);
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			sprintf(c, "  %s: %d", LNG(Default_Timeout), setting->timeout);
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			if(setting->usbkbd_used)
+				sprintf(c, "  %s: %s", LNG(USB_Keyboard_Used), LNG(ON));
+			else
+				sprintf(c, "  %s: %s", LNG(USB_Keyboard_Used), LNG(OFF));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			if(strlen(setting->usbkbd_file)==0)
+				sprintf(c, "  %s: %s", LNG(USB_Keyboard_IRX), LNG(DEFAULT));
+			else
+				sprintf(c, "  %s: %s", LNG(USB_Keyboard_IRX), setting->usbkbd_file);
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			if(strlen(setting->kbdmap_file)==0)
+				sprintf(c, "  %s: %s", LNG(USB_Keyboard_Map), LNG(DEFAULT));
+			else
+				sprintf(c, "  %s: %s", LNG(USB_Keyboard_Map), setting->kbdmap_file);
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			if(strlen(setting->CNF_Path)==0)
+				sprintf(c, "  %s: %s", LNG(CNF_Path_override), LNG(NONE));
+			else
+				sprintf(c, "  %s: %s", LNG(CNF_Path_override), setting->CNF_Path);
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			if(strlen(setting->usbmass_file)==0)
+				sprintf(c, "  %s: %s", LNG(USB_Mass_IRX), LNG(DEFAULT));
+			else
+				sprintf(c, "  %s: %s", LNG(USB_Mass_IRX), setting->usbmass_file);
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			if(strlen(setting->lang_file)==0)
+				sprintf(c, "  %s: %s", LNG(Language_File), LNG(DEFAULT));
+			else
+				sprintf(c, "  %s: %s", LNG(Language_File), setting->lang_file);
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			if(strlen(setting->font_file)==0)
+				sprintf(c, "  %s: %s", LNG(Font_File), LNG(DEFAULT));
+			else
+				sprintf(c, "  %s: %s", LNG(Font_File), setting->font_file);
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			if(strlen(setting->LK_Path[15])==0)
+				sprintf(c, "  ESR elf: %s", LNG(DEFAULT));
+			else
+				sprintf(c, "  ESR elf: %s", setting->LK_Path[15]);
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			y += FONT_HEIGHT / 2;
+			sprintf(c, "  %s", LNG(RETURN));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			//Cursor positioning section
+			y = Menu_start_y + s*FONT_HEIGHT + FONT_HEIGHT /2;
+
+			if(s>=max_s) y+=FONT_HEIGHT/2;
+			drawChar(LEFT_CUR, x, y, setting->color[3]);
+
+			//Tooltip section
+			if ((s==1)||(s==3)||(s==7)) { //resetIOP || usbkbd_used
+				if (swapKeys)
+					sprintf(c, "ÿ1:%s", LNG(Change));
+				else
+					sprintf(c, "ÿ0:%s", LNG(Change));
+			} else if ((s==2)||(s==5)||(s==6)) { //numCNF || Init_Delay || timeout
+				if (swapKeys)
+					sprintf(c, "ÿ1:%s ÿ0:%s", LNG(Add), LNG(Subtract));
+				else
+					sprintf(c, "ÿ0:%s ÿ1:%s", LNG(Add), LNG(Subtract));
+			} else if((s==4)||(s==8)||(s==9)||(s==10)
+			||(s==11)||(s==12)||(s==13)||(s==14)) {
+			//usbd_file||usbkbd_file||kbdmap_file||CNF_Path||usbmass_file
+				if (swapKeys)
+					sprintf(c, "ÿ1:%s ÿ0:%s", LNG(Browse), LNG(Clear));
+				else
+					sprintf(c, "ÿ0:%s ÿ1:%s", LNG(Browse), LNG(Clear));
+			} else {
+				if (swapKeys)
+					sprintf(c, "ÿ1:%s", LNG(OK));
+				else
+					sprintf(c, "ÿ0:%s", LNG(OK));
+			}
+			sprintf(tmp, " ÿ3:%s", LNG(Return));
+			strcat(c, tmp);
+			setScrTmp("", c);
+		}//ends if(event||post_event)
+		drawScr();
+		post_event = event;
+		event = 0;
+
+	}//ends while
+}//ends Config_Startup
+//---------------------------------------------------------------------------
+// Network settings GUI by Slam-Tilt
+//---------------------------------------------------------------------------
+void saveNetworkSettings(char *Message)
+{
+	char firstline[50];
+	extern char ip[16];
+	extern char netmask[16];
+	extern char gw[16];
+    int out_fd,in_fd;
+    int ret=0,i=0;
+	int size,sizeleft=0;
+	char *ipconfigfile=0;
+	char path[MAX_PATH];
+
+	// Default message, will get updated if save is sucessfull
+	sprintf(Message,"%s", LNG(Saved_Failed));
+
+	sprintf(firstline,"%s %s %s\n\r",ip,netmask,gw);
+
+
+
+	// This block looks at the existing ipconfig.dat and works out if there is
+	// already any data beyond the first line. If there is it will get appended to the output
+	// to new file later.
+
+	if(uLE_related(path, "uLE:/IPCONFIG.DAT")==1)
+		in_fd = genOpen(path, O_RDONLY);
+	else
+		in_fd=-1;
+
+	if(strncmp(path, "mc",2)){
+		mcSync(0,NULL,NULL);
+		mcMkDir(0, 0, "SYS-CONF");
+		mcSync(0, NULL, &ret);
+	}
+	
+	if (in_fd >= 0) {
+
+		size = genLseek(in_fd, 0, SEEK_END);
+		printf("size of existing file is %ibytes\n\r",size);
+
+		ipconfigfile = (char *)malloc(size);
+
+		genLseek(in_fd, 0, SEEK_SET);
+		genRead(in_fd, ipconfigfile, size);
+
+
+		for (i=0; (ipconfigfile[i] != 0 && i<=size); i++)
+
+		{
+			// printf("%i-%c\n\r",i,ipconfigfile[i]);
+		}
+
+		sizeleft=size-i;
+
+		genClose(in_fd);
+	}else
+		strcpy(path, "mc0:/SYS-CONF/IPCONFIG.DAT");
+
+	// Writing the data out
+
+	out_fd=genOpen(path, O_WRONLY | O_TRUNC | O_CREAT);
+	if(out_fd >=0)
+	{
+		mcSync(0, NULL, &ret);
+		genWrite(out_fd,firstline,strlen(firstline));
+		mcSync(0, NULL, &ret);
+
+		// If we have any extra data, spit that out too.
+		if (sizeleft > 0)
+		{
+			mcSync(0, NULL, &ret);
+			genWrite(out_fd,&ipconfigfile[i],sizeleft);
+			mcSync(0, NULL, &ret);
+		}
+
+		sprintf(Message,"%s %s", LNG(Saved), path);
+
+		genClose(out_fd);
+
+	}
+}
+//---------------------------------------------------------------------------
+// Convert IP string to numbers
+//---------------------------------------------------------------------------
+void ipStringToOctet(char *ip, int ip_octet[4])
+{
+
+	// This takes a string (ip) representing an IP address and converts it
+	// into an array of ints (ip_octet)
+	// Rewritten 22/10/05
+
+	char oct_str[5];
+	int oct_cnt,i;
+
+	oct_cnt = 0;
+	oct_str[0]=0;
+
+	for (i=0; ((i<=strlen(ip)) && (oct_cnt<4)); i++)
+	{
+		if ((ip[i] == '.') | (i==strlen(ip)))
+		{
+			ip_octet[oct_cnt] = atoi(oct_str);
+			oct_cnt++;
+			oct_str[0]=0;
+		} else
+			sprintf(oct_str,"%s%c",oct_str,ip[i]);
+	}
+}
+//---------------------------------------------------------------------------
+data_ip_struct BuildOctets(char *ip, char *nm, char *gw)
+{
+
+	// Populate 3 arrays with the ip address (as ints)
+
+	data_ip_struct iplist;
+
+	ipStringToOctet(ip,iplist.ip);
+	ipStringToOctet(nm,iplist.nm);
+	ipStringToOctet(gw,iplist.gw);
+
+	return(iplist);
+}
+//---------------------------------------------------------------------------
+void Config_Network(void)
+{
+	// Menu System for Network Settings Page.
+
+	int s,l;
+	int x, y;
+	int event, post_event=0;
+	char c[MAX_PATH];
+	extern char ip[16];
+	extern char netmask[16];
+	extern char gw[16];
+	data_ip_struct ipdata;
+	char NetMsg[MAX_PATH] = "";
+	char path[MAX_PATH];
+
+	event = 1;	//event = initial entry
+	s=1;
+	l=1;
+	ipdata = BuildOctets(ip,netmask,gw);
+
+	while(1)
+	{
+		//Pad response section
+		waitPadReady(0, 0);
+		if(readpad())
+		{
+			if(new_pad & PAD_UP)
+			{
+				event |= 2;  //event |= valid pad command
+				if(s!=1) s--;
+				else {s=5; l=1; }
+			}
+			else if(new_pad & PAD_DOWN)
+			{
+				event |= 2;  //event |= valid pad command
+				if(s!=5) s++;
+				else s=1;
+				if(s>3) l=1;
+			}
+			else if(new_pad & PAD_LEFT)
+			{
+				event |= 2;  //event |= valid pad command
+				if(s<4)
+					if(l>1)
+						l--;
+			}
+			else if(new_pad & PAD_RIGHT)
+			{
+				event |= 2;  //event |= valid pad command
+				if(s<4)
+					if(l<5)
+						l++;
+			}
+			else if((!swapKeys && new_pad & PAD_CROSS) || (swapKeys && new_pad & PAD_CIRCLE) )
+			{
+				event |= 2;  //event |= valid pad command
+				if((s<4) && (l>1))
+				{
+					if (s == 1)
+					{
+							if (ipdata.ip[l-2] > 0)
+							{
+								ipdata.ip[l-2]--;
+							}
+					}
+					else if (s == 2)
+					{
+							if (ipdata.nm[l-2] > 0)
+							{
+								ipdata.nm[l-2]--;
+							}
+					}
+					else if (s == 3)
+					{
+							if (ipdata.gw[l-2] > 0)
+							{
+								ipdata.gw[l-2]--;
+							}
+					}
+
+				}
+			}
+			else if((swapKeys && new_pad & PAD_CROSS) || (!swapKeys && new_pad & PAD_CIRCLE))
+			{
+				event |= 2;  //event |= valid pad command
+				if((s<4) && (l>1))
+				{
+					if (s == 1)
+					{
+							if (ipdata.ip[l-2] < 255)
+							{
+								ipdata.ip[l-2]++;
+							}
+					}
+					else if (s == 2)
+					{
+							if (ipdata.nm[l-2] < 255)
+							{
+								ipdata.nm[l-2]++;
+							}
+					}
+					else if (s == 3)
+					{
+							if (ipdata.gw[l-2] < 255)
+							{
+								ipdata.gw[l-2]++;
+							}
+					}
+
+				}
+
+				else if(s==4)
+				{
+					sprintf(ip,"%i.%i.%i.%i",ipdata.ip[0],ipdata.ip[1],ipdata.ip[2],ipdata.ip[3]);
+					sprintf(netmask,"%i.%i.%i.%i",ipdata.nm[0],ipdata.nm[1],ipdata.nm[2],ipdata.nm[3]);
+					sprintf(gw,"%i.%i.%i.%i",ipdata.gw[0],ipdata.gw[1],ipdata.gw[2],ipdata.gw[3]);
+
+					saveNetworkSettings(NetMsg);
+				}
+				else
+					return;
+			}
+			else if(new_pad & PAD_TRIANGLE)
+				return;
+		}
+
+		if(event||post_event){ //NB: We need to update two frame buffers per event
+
+			//Display section
+			clrScr(setting->color[0]);
+
+			x = Menu_start_x;
+			y = Menu_start_y;
+
+			printXY(LNG(NETWORK_SETTINGS), x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			y += FONT_HEIGHT / 2;
+
+			int len = (strlen(LNG(IP_Address))+5>strlen(LNG(Netmask))+5)?
+				strlen(LNG(IP_Address))+5:strlen(LNG(Netmask))+5;
+			len = (len>strlen(LNG(Gateway))+5)? len:strlen(LNG(Gateway))+5;
+			sprintf(c, "%s:", LNG(IP_Address));
+			printXY(c, x+2*FONT_WIDTH, y, setting->color[3], TRUE, 0);
+			sprintf(c, "%.3i . %.3i . %.3i . %.3i", ipdata.ip[0],ipdata.ip[1],ipdata.ip[2],ipdata.ip[3]);
+			printXY(c, x+len*FONT_WIDTH, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			sprintf(c, "%s:", LNG(Netmask));
+			printXY(c, x+2*FONT_WIDTH, y, setting->color[3], TRUE, 0);
+			sprintf(c, "%.3i . %.3i . %.3i . %.3i", ipdata.nm[0],ipdata.nm[1],ipdata.nm[2],ipdata.nm[3]);
+			printXY(c, x+len*FONT_WIDTH, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			sprintf(c, "%s:", LNG(Gateway));
+			printXY(c, x+2*FONT_WIDTH, y, setting->color[3], TRUE, 0);
+			sprintf(c, "%.3i . %.3i . %.3i . %.3i", ipdata.gw[0],ipdata.gw[1],ipdata.gw[2],ipdata.gw[3]);
+			printXY(c, x+len*FONT_WIDTH, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			y += FONT_HEIGHT / 2;
+
+			if(uLE_related(path, "uLE:/IPCONFIG.DAT")!=1)
+				strcpy(path, "mc0:/SYS-CONF/IPCONFIG.DAT");
+			sprintf(c, "  %s \"%s\"", LNG(Save_to), path);
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			y += FONT_HEIGHT / 2;
+			sprintf(c, "  %s", LNG(RETURN));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			//Cursor positioning section
+			y = Menu_start_y + s*FONT_HEIGHT + FONT_HEIGHT/2;
+
+			if(s>=4) y+=FONT_HEIGHT/2;
+			if(s>=5) y+=FONT_HEIGHT/2;
+			if (l > 1)
+				x += (len-1)*FONT_WIDTH-1+(l-2)*6*FONT_WIDTH;
+			drawChar(LEFT_CUR, x, y, setting->color[3]);
+
+			//Tooltip section
+			if ((s <4) && (l==1)) {
+					sprintf(c, "%s", LNG(Right_DPad_to_Edit));
+			} else if (s < 4) {
+				if (swapKeys)
+					sprintf(c, "ÿ1:%s ÿ0:%s", LNG(Add), LNG(Subtract));
+				else
+					sprintf(c, "ÿ0:%s ÿ1:%s", LNG(Add), LNG(Subtract));
+			} else if( s== 4) {
+				if (swapKeys)
+					sprintf(c, "ÿ1:%s", LNG(Save));
+				else
+					sprintf(c, "ÿ0:%s", LNG(Save));
+			} else {
+				if (swapKeys)
+					sprintf(c, "ÿ1:%s", LNG(OK));
+				else
+					sprintf(c, "ÿ0:%s", LNG(OK));
+			}
+			sprintf(tmp, " ÿ3:%s", LNG(Return));
+			strcat(c, tmp);
+			setScrTmp(NetMsg, c);
+		}//ends if(event||post_event)
+		drawScr();
+		post_event = event;
+		event = 0;
+
+	}//ends while
+}//ends Config_Network
+//---------------------------------------------------------------------------
+// Configuration menu
+//---------------------------------------------------------------------------
+void config(char *mainMsg, char *CNF)
+{
+	char c[MAX_PATH];
+	char title_tmp[MAX_ELF_TITLE];
+	char *localMsg;
+	int i;
+	int s;
+	int x, y;
+	int event, post_event=0;
+	
+	tmpsetting = setting;
+	setting = (SETTING*)malloc(sizeof(SETTING));
+	*setting = *tmpsetting;
+	
+	event = 1;	//event = initial entry
+	s=0;
+	while(1)
+	{
+		//Pad response section
+		waitPadReady(0, 0);
+		if(readpad())
+		{
+			if(new_pad & PAD_UP)
+			{
+				event |= 2;  //event |= valid pad command
+				if(s!=0)
+					s--;
+				else
+					s=CANCEL;
+			}
+			else if(new_pad & PAD_DOWN)
+			{
+				event |= 2;  //event |= valid pad command
+				if(s!=CANCEL)
+					s++;
+				else
+					s=0;
+			}
+			else if(new_pad & PAD_LEFT)
+			{
+				event |= 2;  //event |= valid pad command
+				if(s>=OK)
+					s=SHOW_TITLES;
+				else
+					s=DEFAULT;
+			}
+			else if(new_pad & PAD_RIGHT)
+			{
+				event |= 2;  //event |= valid pad command
+				if(s<SHOW_TITLES)
+					s=SHOW_TITLES;
+				else if(s<OK)
+					s=OK;
+			}
+			else if((new_pad & PAD_SQUARE) && (s<SHOW_TITLES)){
+				event |= 2;  //event |= valid pad command
+				strcpy(title_tmp, setting->LK_Title[s]);
+				if(keyboard(title_tmp, MAX_ELF_TITLE)>=0)
+					strcpy(setting->LK_Title[s], title_tmp);
+			}
+			else if((!swapKeys && new_pad & PAD_CROSS) || (swapKeys && new_pad & PAD_CIRCLE) )
+			{
+				event |= 2;  //event |= valid pad command
+				if(s<SHOW_TITLES){
+					setting->LK_Path[s][0]=0;
+					setting->LK_Title[s][0]=0;
+				}
+			}
+			else if((swapKeys && new_pad & PAD_CROSS) || (!swapKeys && new_pad & PAD_CIRCLE))
+			{
+				event |= 2;  //event |= valid pad command
+				if(s<SHOW_TITLES)
+				{
+					getFilePath(setting->LK_Path[s], TRUE);
+					if(!strncmp(setting->LK_Path[s], "mc0", 3) ||
+						!strncmp(setting->LK_Path[s], "mc1", 3)){
+						sprintf(c, "mc%s", &setting->LK_Path[s][3]);
+						strcpy(setting->LK_Path[s], c);
+					}
+				}
+				else if(s==SHOW_TITLES)
+					setting->Show_Titles = !setting->Show_Titles;
+				else if(s==FILENAME)
+					setting->Hide_Paths = !setting->Hide_Paths;
+				else if(s==DISCCONTROL)
+					setting->discControl = !setting->discControl;
+				else if(s==SCREEN)
+					Config_Screen();
+				else if(s==SETTINGS)
+					Config_Startup();
+				else if(s==NETWORK)
+					Config_Network();
+				else if(s==OK)
+				{
+					free(tmpsetting);
+					saveConfig(mainMsg, CNF);
+					if(setting->GUI_skin[0]) {
+						GUI_active = 1;
+						loadSkin(BACKGROUND_PIC, 0, 0);
+					}
+					break;
+				}
+				else if(s==CANCEL)
+					goto cancel_exit;
+			}
+			else if(new_pad & PAD_TRIANGLE) {
+cancel_exit:
+				free(setting);
+				setting = tmpsetting;
+				updateScreenMode(0);
+				if (setting->GUI_skin[0])
+					GUI_active = 1;
+				loadSkin(BACKGROUND_PIC, 0, 0);
+				Load_External_Language();
+				loadFont(setting->font_file);
+				mainMsg[0] = 0;
+				break;
+			}
+		} //end if(readpad())
+		
+		if(event||post_event){ //NB: We need to update two frame buffers per event
+
+			//Display section
+			clrScr(setting->color[0]);
+
+			if(s < SHOW_TITLES) localMsg = setting->LK_Title[s];
+			else                localMsg = "";
+
+			x = Menu_start_x;
+			y = Menu_start_y;
+			printXY(LNG(Button_Settings), x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+			for(i=0; i<12; i++)
+			{
+				switch(i)
+				{
+				case 0:
+					strcpy(c,"  Default: ");
+					break;
+				case 1:
+					strcpy(c,"  ÿ0     : ");
+					break;
+				case 2:
+					strcpy(c,"  ÿ1     : ");
+					break;
+				case 3:
+					strcpy(c,"  ÿ2     : ");
+					break;
+				case 4:
+					strcpy(c,"  ÿ3     : ");
+					break;
+				case 5:
+					strcpy(c,"  L1     : ");
+					break;
+				case 6:
+					strcpy(c,"  R1     : ");
+					break;
+				case 7:
+					strcpy(c,"  L2     : ");
+					break;
+				case 8:
+					strcpy(c,"  R2     : ");
+					break;
+				case 9:
+					strcpy(c,"  L3     : ");
+					break;
+				case 10:
+					strcpy(c,"  R3     : ");
+					break;
+				case 11:
+					strcpy(c,"  START  : ");
+					break;
+				}
+				strcat(c, setting->LK_Path[i]);
+				printXY(c, x, y, setting->color[3], TRUE, 0);
+				y += FONT_HEIGHT;
+			}
+
+			y += FONT_HEIGHT / 2;
+
+			if(setting->Show_Titles)
+				sprintf(c, "  %s: %s", LNG(Show_launch_titles), LNG(ON));
+			else
+				sprintf(c, "  %s: %s", LNG(Show_launch_titles), LNG(OFF));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			if(setting->discControl)
+				sprintf(c, "  %s: %s", LNG(Disc_control), LNG(ON));
+			else
+				sprintf(c, "  %s: %s", LNG(Disc_control), LNG(OFF));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			if(setting->Hide_Paths)
+				sprintf(c, "  %s: %s", LNG(Hide_full_ELF_paths), LNG(ON));
+			else
+				sprintf(c, "  %s: %s", LNG(Hide_full_ELF_paths), LNG(OFF));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			sprintf(c, "  %s...", LNG(Screen_Settings));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+			sprintf(c, "  %s...", LNG(Startup_Settings));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+			sprintf(c, "  %s...", LNG(Network_Settings));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+
+			sprintf(c, "  %s", LNG(OK));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+			y += FONT_HEIGHT;
+			sprintf(c, "  %s", LNG(Cancel));
+			printXY(c, x, y, setting->color[3], TRUE, 0);
+
+			//Cursor positioning section
+			y = Menu_start_y + (s+1)*FONT_HEIGHT;
+			if(s>=SHOW_TITLES)
+				y += FONT_HEIGHT / 2;
+			drawChar(LEFT_CUR, x, y, setting->color[3]);
+
+			//Tooltip section
+			if (s < SHOW_TITLES) {
+				if (swapKeys)
+					sprintf(c, "ÿ1:%s ÿ0:%s ÿ2:%s", LNG(Browse), LNG(Clear), LNG(Edit_Title));
+				else
+					sprintf(c, "ÿ0:%s ÿ1:%s ÿ2:%s", LNG(Browse), LNG(Clear), LNG(Edit_Title));
+			} else if((s==SHOW_TITLES)||(s==FILENAME)||(s==DISCCONTROL)) {
+				if (swapKeys)
+					sprintf(c, "ÿ1:%s", LNG(Change));
+				else
+					sprintf(c, "ÿ0:%s", LNG(Change));
+			} else {
+				if (swapKeys)
+					sprintf(c, "ÿ1:%s", LNG(OK));
+				else
+					sprintf(c, "ÿ0:%s", LNG(OK));
+			}
+			sprintf(tmp, " ÿ3:%s", LNG(Return));
+			strcat(c, tmp);
+			setScrTmp(localMsg, c);
+		}//ends if(event||post_event)
+		drawScr();
+		post_event = event;
+		event = 0;
+
+	}//ends while
+	if(setting->discControl)
+		loadCdModules();
+}//ends config
+//---------------------------------------------------------------------------
+// End of file: config.c
+//---------------------------------------------------------------------------
Index: ps2launchargs/source/uLaunchELF/draw.c
===================================================================
--- ps2launchargs/source/uLaunchELF/draw.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/draw.c	(revision 1101)
@@ -0,0 +1,1286 @@
+//--------------------------------------------------------------
+//File name:   draw.c
+//--------------------------------------------------------------
+#include "launchelf.h"
+
+GSGLOBAL  *gsGlobal;
+GSTEXTURE TexSkin, TexPreview, TexPicture, TexThumb[MAX_ENTRY], TexIcon[2];
+int				testskin, testsetskin, testjpg, testthumb;
+int				SCREEN_WIDTH	= 640;
+int				SCREEN_HEIGHT = 448;
+int				SCREEN_X			= 632;
+int				SCREEN_Y			= 50;
+//dlanor: values shown above are defaults for NTSC mode
+u64       BrightColor;
+
+int updateScr_1;     //dlanor: flags screen updates for drawScr()
+int updateScr_2;     //dlanor: used for anti-flicker delay in drawScr()
+u64 updateScr_t = 0; //dlanor: exit time of last drawScr()
+int  Old_Interlace;
+
+char LastMessage[MAX_TEXT_LINE+2];
+
+int Menu_start_x   = SCREEN_MARGIN + LINE_THICKNESS + FONT_WIDTH;
+int Menu_title_y   = SCREEN_MARGIN;
+int Menu_message_y = SCREEN_MARGIN + FONT_HEIGHT;
+int Frame_start_y  = SCREEN_MARGIN + 2*FONT_HEIGHT + 2;  //First line of menu frame
+int Menu_start_y   = SCREEN_MARGIN + 2*FONT_HEIGHT + LINE_THICKNESS + 5;
+//dlanor: Menu_start_y is the 1st pixel line that may be used for main content of a menu
+//dlanor: values below are only calculated when a rez is activated
+int Menu_end_y;     //Normal menu display should not use pixels at this line or beyond
+int Frame_end_y;    //first line of frame bottom
+int Menu_tooltip_y; //Menus may also use this row for tooltips
+
+
+//The font file ELISA100.FNT is needed to display MC save titles in japanese
+//and the arrays defined here are needed to find correct data in that file
+const u16 font404[] = {
+	0xA2AF, 11,
+	0xA2C2, 8,
+	0xA2D1, 11,
+	0xA2EB, 7,
+	0xA2FA, 4,
+	0xA3A1, 15,
+	0xA3BA, 7,
+	0xA3DB, 6,
+	0xA3FB, 4,
+	0xA4F4, 11,
+	0xA5F7, 8,
+	0xA6B9, 8,
+	0xA6D9, 38,
+	0xA7C2, 15,
+	0xA7F2, 13,
+	0xA8C1, 720,
+	0xCFD4, 43,
+	0xF4A5, 1030,
+	0,0
+};
+
+// ASCIIÆSJISÌÏ·pzñ
+const unsigned char sjis_lookup_81[256] = {
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,  // 0x00
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,  // 0x10
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,  // 0x20
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,  // 0x30
+  ' ', ',', '.', ',', '.', 0xFF,':', ';', '?', '!', 0xFF,0xFF,'´', '`', 0xFF,'^',   // 0x40
+  0xFF,'_', 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,'0', 0xFF,'-', '-', 0xFF,0xFF,  // 0x50
+  0xFF,0xFF,0xFF,0xFF,0xFF,'\'','\'','"', '"', '(', ')', 0xFF,0xFF,'[', ']', '{',   // 0x60
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,'+', '-', 0xFF,'*', 0xFF,  // 0x70
+  '/', '=', 0xFF,'<', '>', 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,'°', 0xFF,0xFF,'°', 0xFF,  // 0x80
+  '$', 0xFF,0xFF,'%', '#', '&', '*', '@', 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,  // 0x90
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,  // 0xA0
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,  // 0xB0
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,'&', '|', '!', 0xFF,0xFF,0xFF,0xFF,0xFF,  // 0xC0
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,  // 0xD0
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,  // 0xE0
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,  // 0xF0
+};
+const unsigned char sjis_lookup_82[256] = {
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,  // 0x00
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,  // 0x10
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,  // 0x20
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,  // 0x30
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,'0',   // 0x40
+  '1', '2', '3', '4', '5', '6', '7', '8', '9', 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,  // 0x50
+  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',   // 0x60
+  'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,  // 0x70
+  0xFF,'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',   // 0x80
+  'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0xFF,0xFF,0xFF,0xFF,0xFF,  // 0x90
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,  // 0xA0
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,  // 0xB0
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,  // 0xC0
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,  // 0xD0
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,  // 0xE0
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,  // 0xF0
+};
+//--------------------------------------------------------------
+int *CreateCoeffInt( int nLen, int nNewLen, int bShrink ) {
+
+ int nSum    = 0;
+ int nSum2   = 0;
+ int *pRes   = (int*) malloc( 2 * nLen * sizeof(int) );
+ int *pCoeff = pRes;
+ int nNorm   = (bShrink) ? (nNewLen << 12) / nLen : 0x1000;
+ int nDenom  = (bShrink) ? nLen : nNewLen;
+ int i;
+
+ memset( pRes, 0, 2 * nLen * sizeof(int) );
+
+ for( i = 0; i < nLen; i++, pCoeff += 2 ) {
+
+  nSum2 = nSum + nNewLen;
+
+  if(nSum2 > nLen) {
+
+   *pCoeff = ((nLen - nSum) << 12) / nDenom;
+   pCoeff[1] = ((nSum2 - nLen) << 12) / nDenom;
+   nSum2 -= nLen;
+
+  } else {
+
+   *pCoeff = nNorm;
+
+   if(nSum2 == nLen) {
+    pCoeff[1] = -1;
+    nSum2 = 0;
+
+   } /* end if */
+
+  } /* end else */
+
+  nSum = nSum2;
+
+ } /* end for */
+
+ return pRes;
+
+} /* CreateCoeffInt */
+
+//--------------------------------------------------------------
+int ShrinkData( u8 *pInBuff, u16 wWidth, u16 wHeight, u8 *pOutBuff, u16 wNewWidth, u16 wNewHeight ) {
+
+ u8 *pLine    = pInBuff, *pPix;
+ u8 *pOutLine = pOutBuff;
+ u32 dwInLn   = ( 3 * wWidth + 3 ) & ~3;
+ u32 dwOutLn  = ( 3 * wNewWidth + 3 ) & ~3;
+
+ int  x, y, i, ii;
+ int  bCrossRow, bCrossCol;
+ int *pRowCoeff = CreateCoeffInt( wWidth, wNewWidth, 1 );
+ int *pColCoeff = CreateCoeffInt( wHeight, wNewHeight, 1 );
+
+ int *pXCoeff, *pYCoeff = pColCoeff;
+ u32  dwBuffLn = 3 * wNewWidth * sizeof( u32 );
+ u32 *pdwBuff = ( u32* ) malloc( 6 * wNewWidth * sizeof( u32 ) );
+ u32 *pdwCurrLn = pdwBuff;  
+ u32 *pdwNextLn = pdwBuff + 3 * wNewWidth;
+ u32 *pdwCurrPix;
+ u32  dwTmp, *pdwNextPix;
+
+ memset( pdwBuff, 0, 2 * dwBuffLn );
+
+ y = 0;
+ 
+ while( y < wNewHeight ) {
+
+  pPix = pLine;
+  pLine += dwInLn;
+
+  pdwCurrPix = pdwCurrLn;
+  pdwNextPix = pdwNextLn;
+
+  x = 0;
+  pXCoeff = pRowCoeff;
+  bCrossRow = pYCoeff[ 1 ] > 0;
+  
+  while( x < wNewWidth ) {
+  
+   dwTmp = *pXCoeff * *pYCoeff;
+   for ( i = 0; i < 3; i++ )
+    pdwCurrPix[ i ] += dwTmp * pPix[i];
+   
+   bCrossCol = pXCoeff[ 1 ] > 0;
+   
+   if ( bCrossCol ) {
+
+    dwTmp = pXCoeff[ 1 ] * *pYCoeff;
+    for ( i = 0, ii = 3; i < 3; i++, ii++ )
+     pdwCurrPix[ ii ] += dwTmp * pPix[ i ];
+
+   } /* end if */
+
+   if ( bCrossRow ) {
+
+    dwTmp = *pXCoeff * pYCoeff[ 1 ];
+    for( i = 0; i < 3; i++ )
+     pdwNextPix[ i ] += dwTmp * pPix[ i ];
+    
+    if ( bCrossCol ) {
+
+     dwTmp = pXCoeff[ 1 ] * pYCoeff[ 1 ];
+     for ( i = 0, ii = 3; i < 3; i++, ii++ )
+      pdwNextPix[ ii ] += dwTmp * pPix[ i ];
+
+    } /* end if */
+
+   } /* end if */
+
+   if ( pXCoeff[ 1 ] ) {
+
+    x++;
+    pdwCurrPix += 3;
+    pdwNextPix += 3;
+
+   } /* end if */
+   
+   pXCoeff += 2;
+   pPix += 3;
+
+  } /* end while */
+  
+  if ( pYCoeff[ 1 ] ) {
+
+   // set result line
+   pdwCurrPix = pdwCurrLn;
+   pPix = pOutLine;
+   
+   for ( i = 3 * wNewWidth; i > 0; i--, pdwCurrPix++, pPix++ )
+    *pPix = ((u8*)pdwCurrPix)[3];
+
+   // prepare line buffers
+   pdwCurrPix = pdwNextLn;
+   pdwNextLn = pdwCurrLn;
+   pdwCurrLn = pdwCurrPix;
+   
+   memset( pdwNextLn, 0, dwBuffLn );
+   
+   y++;
+   pOutLine += dwOutLn;
+
+  } /* end if */
+  
+  pYCoeff += 2;
+
+ } /* end while */
+
+ free( pRowCoeff );
+ free( pColCoeff );
+ free( pdwBuff );
+
+ return 1;
+
+} /* end ShrinkData */
+
+//--------------------------------------------------------------
+int EnlargeData( u8 *pInBuff, u16 wWidth, u16 wHeight, u8 *pOutBuff, u16 wNewWidth, u16 wNewHeight ) {
+
+ u8 *pLine = pInBuff,
+    *pPix  = pLine,
+    *pPixOld,
+    *pUpPix,
+    *pUpPixOld;
+ u8 *pOutLine = pOutBuff, *pOutPix;
+ u32 dwInLn   = ( 3 * wWidth + 3 ) & ~3;
+ u32 dwOutLn  = ( 3 * wNewWidth + 3 ) & ~3;
+
+ int x, y, i;
+ int bCrossRow, bCrossCol;
+ 
+ int *pRowCoeff = CreateCoeffInt( wNewWidth, wWidth, 0 );
+ int *pColCoeff = CreateCoeffInt( wNewHeight, wHeight, 0 );
+ int *pXCoeff, *pYCoeff = pColCoeff;
+ 
+ u32 dwTmp, dwPtTmp[ 3 ];
+ 
+ y = 0;
+ 
+ while( y < wHeight ) {
+ 
+  bCrossRow = pYCoeff[ 1 ] > 0;
+  x         = 0;
+  pXCoeff   = pRowCoeff;
+  pOutPix   = pOutLine;
+  pOutLine += dwOutLn;
+  pUpPix    = pLine;
+  
+  if ( pYCoeff[ 1 ] ) {
+
+   y++;
+   pLine += dwInLn;
+   pPix = pLine;
+
+  } /* end if */
+  
+  while( x < wWidth ) {
+
+   bCrossCol = pXCoeff[ 1 ] > 0;
+   pUpPixOld = pUpPix;
+   pPixOld  = pPix;
+   
+   if( pXCoeff[ 1 ] ) {
+
+    x++;
+    pUpPix += 3;
+    pPix += 3;
+
+   } /* end if */
+   
+   dwTmp = *pXCoeff * *pYCoeff;
+   
+   for ( i = 0; i < 3; i++ )
+    dwPtTmp[ i ] = dwTmp * pUpPixOld[ i ];
+
+   if ( bCrossCol ) {
+
+    dwTmp = pXCoeff[ 1 ] * *pYCoeff;
+    for ( i = 0; i < 3; i++ )
+     dwPtTmp[ i ] += dwTmp * pUpPix[ i ];
+
+   } /* end if */
+
+   if ( bCrossRow ) {
+
+    dwTmp = *pXCoeff * pYCoeff[ 1 ];
+    for ( i = 0; i < 3; i++ )
+     dwPtTmp[ i ] += dwTmp * pPixOld[ i ];
+    
+    if ( bCrossCol ) {
+
+     dwTmp = pXCoeff[ 1 ] * pYCoeff[ 1 ];
+     for(i = 0; i < 3; i++)
+      dwPtTmp[ i ] += dwTmp * pPix[ i ];
+
+    } /* end if */
+
+   } /* end if */
+   
+   for ( i = 0; i < 3; i++, pOutPix++ )
+    *pOutPix = (  ( u8* )( dwPtTmp + i )  )[ 3 ];
+   
+   pXCoeff += 2;
+
+  } /* end while */
+  
+  pYCoeff += 2;
+
+ } /* end while */
+ 
+ free( pRowCoeff );
+ free( pColCoeff );
+
+ return 1;
+
+} /* end EnlargeData */
+
+//--------------------------------------------------------------
+int ScaleBitmap( u8* pInBuff, u16 wWidth, u16 wHeight, u8** pOutBuff, u16 wNewWidth, u16 wNewHeight ) {
+
+ int lRet;
+
+ // check for valid size
+ if( (wWidth  > wNewWidth  && wHeight < wNewHeight) ||
+ 		 (wHeight > wNewHeight && wWidth  < wNewWidth ) ) return 0;
+
+ // allocate memory
+ *pOutBuff = ( u8* ) memalign(   128, (  ( 3 * wNewWidth + 3 ) & ~3  ) * wNewHeight   );
+
+ if( !*pOutBuff )return 0;
+
+ if( wWidth >= wNewWidth && wHeight >= wNewHeight )
+  lRet = ShrinkData( pInBuff, wWidth, wHeight, *pOutBuff, wNewWidth, wNewHeight );
+ else
+  lRet = EnlargeData( pInBuff, wWidth, wHeight, *pOutBuff, wNewWidth, wNewHeight );
+
+ return lRet;
+ 
+} /* end ScaleBitmap */
+
+//--------------------------------------------------------------
+void RotateBitmap(u8* InBuff, u16 Width, u16 Height, u8* OutBuff, int Way) {
+
+	int i, j, k, l;
+	int Byte;
+	u8  pixels[Width][Height][3];
+	u8  newpixels[Height][Width][3];
+	
+	Byte=0;
+	for( i = 0; i < Height; i++ ){
+		for( j = 0; j < Width; j++ ){
+			pixels[j][i][0] = InBuff[Byte];
+			pixels[j][i][1] = InBuff[Byte+1];
+			pixels[j][i][2] = InBuff[Byte+2];
+			Byte+=3;
+		}
+	}
+	if(Way==1){ // +90°
+		for( i = 0, l = 0; i < Width; i++, l++ ){
+			for( j = 0, k = Height-1; j < Height; j++, k-- ){
+				newpixels[j][i][0] = pixels[l][k][0];
+				newpixels[j][i][1] = pixels[l][k][1];
+				newpixels[j][i][2] = pixels[l][k][2];
+			}
+		}
+	}else if(Way==3){ // -90°
+		for( i = 0, l = Width-1; i < Width; i++, l-- ){
+			for( j = 0, k = 0; j < Height; j++, k++ ){
+				newpixels[j][i][0] = pixels[l][k][0];
+				newpixels[j][i][1] = pixels[l][k][1];
+				newpixels[j][i][2] = pixels[l][k][2];
+			}
+		}
+	} /* end if */
+	
+	Byte=0;
+	for( i = 0; i < Width; i++ ){
+		for( j = 0; j < Height; j++ ){
+			OutBuff[Byte]   = newpixels[j][i][0];
+			OutBuff[Byte+1] = newpixels[j][i][1];
+			OutBuff[Byte+2] = newpixels[j][i][2];
+			Byte+=3;
+		}
+	}
+
+ free( pixels );
+ free( newpixels );
+
+} /* end RotateBitmap */
+
+//--------------------------------------------------------------
+void setScrTmp(const char *msg0, const char *msg1)
+{
+	int x, y;
+	char temp_txt[64];
+
+	x = SCREEN_MARGIN;
+	y = Menu_title_y;
+	printXY(setting->Menu_Title, x, y, setting->color[3], TRUE, 0);
+	sprintf(temp_txt, " ÿ4 LaunchELF %s ÿ4", ULE_VERSION);
+	printXY(temp_txt, SCREEN_WIDTH-SCREEN_MARGIN-FONT_WIDTH*strlen(temp_txt), y,
+		setting->color[1], TRUE, 0);
+	
+	strncpy(LastMessage, msg0, MAX_TEXT_LINE);
+	LastMessage[MAX_TEXT_LINE] = '\0';
+	printXY(msg0, x, Menu_message_y, setting->color[2], TRUE, 0);
+
+	if(setting->Menu_Frame)
+		drawFrame(SCREEN_MARGIN, Frame_start_y,
+			SCREEN_WIDTH-SCREEN_MARGIN, Frame_end_y, setting->color[1]);
+	
+	printXY(msg1, x, Menu_tooltip_y, setting->color[2], TRUE, 0);
+}
+//--------------------------------------------------------------
+void drawSprite( u64 color, int x1, int y1, int x2, int y2 ){
+	int	y_off = (setting->interlace) ? 0 : (y1 & 1);
+	y1 -= y_off;
+	y2 -= y_off;
+
+	if ( testskin == 1 ) {
+		setBrightness(setting->Brightness);
+		gsKit_prim_sprite_texture(gsGlobal, &TexSkin, x1, y1, x1, y1, x2, y2, x2, y2, 0, BrightColor);
+		setBrightness(50);
+	} else {
+		gsKit_prim_sprite(gsGlobal, x1, y1, x2, y2, 0, color);
+	}
+}
+//--------------------------------------------------------------
+void drawPopSprite( u64 color, int x1, int y1, int x2, int y2 ){
+	int	y_off = (setting->interlace) ? 0 : (y1 & 1);
+	y1 -= y_off;
+	y2 -= y_off;
+
+	if ( testskin == 1 && !setting->Popup_Opaque) {
+		setBrightness(setting->Brightness);
+		gsKit_prim_sprite_texture(gsGlobal, &TexSkin, x1, y1, x1, y1, x2, y2, x2, y2, 0, BrightColor);
+		setBrightness(50);
+	} else {
+		gsKit_prim_sprite(gsGlobal, x1, y1, x2, y2, 0, color);
+	}
+}
+//--------------------------------------------------------------
+//drawOpSprite exists only to eliminate the use of primitive sprite functions
+//that are specific to the graphics lib used (currently gsKit). So normally
+//it will merely be a 'wrapper' function for one of the lib calls, except
+//that it will also perform any coordinate adjustments (if any)implemented for
+//the functions drawSprite and drawPopSprite, to keep all of them compatible.
+//
+void drawOpSprite( u64 color, int x1, int y1, int x2, int y2 ){
+	int	y_off = (setting->interlace) ? 0 : (y1 & 1);
+	y1 -= y_off;
+	y2 -= y_off;
+
+	gsKit_prim_sprite(gsGlobal, x1, y1, x2, y2, 0, color);
+}
+//--------------------------------------------------------------
+void drawMsg(const char *msg)
+{
+	strncpy(LastMessage, msg, MAX_TEXT_LINE);
+	LastMessage[MAX_TEXT_LINE] = '\0';
+	drawSprite(setting->color[0], 0, Menu_message_y-1,
+		SCREEN_WIDTH, Frame_start_y);
+	printXY(msg, SCREEN_MARGIN, Menu_message_y, setting->color[2], TRUE, 0);
+	drawScr();
+}
+//--------------------------------------------------------------
+void drawLastMsg(void)
+{
+	drawSprite(setting->color[0], 0, Menu_message_y-1,
+		SCREEN_WIDTH, Frame_start_y);
+	printXY(LastMessage, SCREEN_MARGIN, Menu_message_y, setting->color[2], TRUE, 0);
+	drawScr();
+}
+//--------------------------------------------------------------
+void setupGS(int gs_vmode)
+{
+	// GS Init
+	gsGlobal = gsKit_init_global_custom(
+		GS_RENDER_QUEUE_OS_POOLSIZE+GS_RENDER_QUEUE_OS_POOLSIZE/2, //eliminates overflow
+		GS_RENDER_QUEUE_PER_POOLSIZE);
+
+	// GS video mode
+	gsGlobal->Mode = gs_vmode;
+
+	// Screen size and Interlace Init
+	gsGlobal->Width  = SCREEN_WIDTH;
+	if(setting->interlace){
+		gsGlobal->Height = SCREEN_HEIGHT;
+		gsGlobal->Interlace = GS_INTERLACED;
+		gsGlobal->Field     = GS_FIELD;
+		gsGlobal->MagV      = 0;
+	}else{
+		gsGlobal->Height = SCREEN_HEIGHT/2;
+		gsGlobal->Interlace = GS_NONINTERLACED;
+		gsGlobal->Field     = GS_FRAME;
+		gsGlobal->MagV      = 0;
+	}
+	Old_Interlace = setting->interlace;
+
+	// Clear Screen
+	gsKit_clear(gsGlobal, GS_SETREG_RGBAQ(0x00,0x00,0x00,0x00,0x00));
+
+	// Screen Position Init
+	gsGlobal->StartX = setting->screen_x; 
+	gsGlobal->StartY = setting->screen_y;
+
+	// Buffer Init
+	gsGlobal->PrimAAEnable = GS_SETTING_ON;
+	gsGlobal->DoubleBuffering = GS_SETTING_OFF;
+	gsGlobal->ZBuffering      = GS_SETTING_OFF;
+
+	// DMAC Init
+	dmaKit_init(D_CTRL_RELE_OFF,D_CTRL_MFD_OFF, D_CTRL_STS_UNSPEC, D_CTRL_STD_OFF, D_CTRL_RCYC_8, 1 << DMA_CHANNEL_GIF);
+	dmaKit_chan_init(DMA_CHANNEL_GIF);
+	dmaKit_chan_init(DMA_CHANNEL_FROMSPR);
+	dmaKit_chan_init(DMA_CHANNEL_TOSPR);
+
+	// Screen Init
+	gsKit_init_screen(gsGlobal);
+	gsKit_mode_switch(gsGlobal, GS_ONESHOT);
+	gsKit_clear(gsGlobal, GS_SETREG_RGBAQ(0x00,0x00,0x00,0x00,0x00));
+}
+//--------------------------------------------------------------
+void updateScreenMode(int adapt_XY)
+{
+	int setGS_flag = 0;
+	int New_TV_mode = setting->TV_mode;
+
+	if((New_TV_mode!=TV_mode_NTSC)&&(New_TV_mode!=TV_mode_PAL)){ //If no forced request
+		New_TV_mode = uLE_detect_TV_mode();  //Let console region decide TV_mode
+	}
+
+	if(New_TV_mode != TV_mode){
+		setGS_flag = 1;
+		TV_mode = New_TV_mode;
+  
+		if(TV_mode == TV_mode_PAL){ //Use PAL mode if chosen (forced or auto)
+			gsGlobal->Mode = GS_MODE_PAL;
+			SCREEN_WIDTH	 = 640;
+			SCREEN_HEIGHT  = 512;
+			if(adapt_XY){
+				setting->screen_x+=20;
+				if(setting->interlace)
+					setting->screen_y+=22;
+				else
+					setting->screen_y+=11;
+			}
+			Menu_end_y     = Menu_start_y + 26*FONT_HEIGHT;
+		}else{                      //else use NTSC mode (forced or auto)
+			gsGlobal->Mode = GS_MODE_NTSC;
+			SCREEN_WIDTH	 = 640;
+			SCREEN_HEIGHT  = 448;
+			if(adapt_XY){
+				setting->screen_x-=20;
+				if(setting->interlace)
+					setting->screen_y-=22;
+				else
+					setting->screen_y-=11;
+			}
+			Menu_end_y     = Menu_start_y + 22*FONT_HEIGHT;
+		} /* end else */
+		Frame_end_y      = Menu_end_y + 3;
+		Menu_tooltip_y   = Frame_end_y + LINE_THICKNESS + 2;
+  
+	} // end TV_Mode change
+
+	if(setting->interlace != Old_Interlace){
+		setGS_flag = 1;
+		Old_Interlace = setting->interlace;
+
+		// Interlace Init
+		if(setting->interlace){
+			gsGlobal->Interlace = GS_INTERLACED;
+			gsGlobal->Field     = GS_FIELD;
+			if(adapt_XY){
+				setting->screen_y = (setting->screen_y-1)*2;
+			}
+		}else{
+			gsGlobal->Interlace = GS_NONINTERLACED;
+			gsGlobal->Field     = GS_FRAME;
+			if(adapt_XY){
+				setting->screen_y = setting->screen_y/2+1;
+			}
+		}
+	} // end Interlace change
+
+	// Init screen size
+	gsGlobal->Width  = SCREEN_WIDTH;
+	gsGlobal->MagH = 3;
+	if(setting->interlace){
+		gsGlobal->Height = SCREEN_HEIGHT;
+		gsGlobal->MagV = 0;
+	} else {
+		gsGlobal->Height = SCREEN_HEIGHT/2;
+		gsGlobal->MagV = 0;
+	}
+
+	// Init screen position
+	gsGlobal->StartX = setting->screen_x;
+	gsGlobal->StartY = setting->screen_y;
+
+	if(setGS_flag){
+		// Clear screen before setting GS
+		gsKit_clear(gsGlobal, GS_SETREG_RGBAQ(0x00,0x00,0x00,0x00,0x00));
+		// Init screen modes
+		SetGsCrt(gsGlobal->Interlace, gsGlobal->Mode, gsGlobal->Field);
+	}
+
+	GS_SET_DISPLAY1(gsGlobal->StartX,		// X position in the display area (in VCK unit
+			gsGlobal->StartY,		// Y position in the display area (in Raster u
+			gsGlobal->MagH,			// Horizontal Magnification
+			gsGlobal->MagV,			// Vertical Magnification
+			(gsGlobal->Width * 4) -1,	// Display area width
+			(gsGlobal->Height-1));		// Display area height
+
+	GS_SET_DISPLAY2(gsGlobal->StartX,		// X position in the display area (in VCK units)
+			gsGlobal->StartY,		// Y position in the display area (in Raster units)
+			gsGlobal->MagH,			// Horizontal Magnification
+			gsGlobal->MagV,			// Vertical Magnification
+			(gsGlobal->Width * 4) -1,	// Display area width
+			(gsGlobal->Height-1));		// Display area height
+}
+//--------------------------------------------------------------
+void loadSkin(int Picture, char *Path, int ThumbNum)
+{
+	char  tmpPath[MAX_PATH], skinpath[MAX_PATH];
+
+	strcpy(tmpPath, "\0");
+	if( Picture == BACKGROUND_PIC ){
+		if (GUI_active == 1){
+		strcpy(tmpPath, setting->GUI_skin);
+		}
+		else{
+		strcpy(tmpPath, setting->skin);
+		}
+		testskin = 0;
+	}else if( Picture == PREVIEW_PIC ){
+		strcpy(tmpPath, setting->skin);
+		testsetskin = 0;
+	}else if( Picture == JPG_PIC ){
+		strcpy(tmpPath, Path);
+		testjpg = 0;
+	}else if( Picture == THUMB_PIC ){
+		strcpy(tmpPath, Path);
+		testthumb = 0;
+	}else if( Picture == PREVIEW_GUI ){
+		strcpy(tmpPath, setting->GUI_skin);
+		testsetskin = 0;
+	}
+
+	genFixPath(tmpPath, skinpath);
+	FILE *File = fopen(skinpath, "r");
+	
+	PicW=0, PicH=0, PicCoeff=0;
+ 
+	if( File != NULL ) {
+
+		jpgData  *Jpg;
+		u8       *ImgData, *ImgData1, *ImgData2;
+		int      W=0;
+
+		if( ( Jpg = jpgOpenFILE ( File, JPG_WIDTH_FIX ) ) > 0 ){
+			if( (ImgData = malloc( Jpg->width * Jpg->height * ( Jpg->bpp / 8 ) ) ) > 0){
+				if( ( jpgReadImage( Jpg, ImgData ) ) != -1 ){
+				 	if( Picture == BACKGROUND_PIC ){
+				 		if( ( ScaleBitmap ( ImgData, Jpg->width, Jpg->height, (void*)&TexSkin.Mem, SCREEN_WIDTH, SCREEN_HEIGHT ) ) != 0 ){
+				 			TexSkin.PSM = GS_PSM_CT24;
+							TexSkin.VramClut = 0;
+							TexSkin.Clut = NULL;
+							TexSkin.Width =  SCREEN_WIDTH;
+							TexSkin.Height = SCREEN_HEIGHT;
+							TexSkin.Filter = GS_FILTER_NEAREST;
+							gsGlobal->CurrentPointer=0x140000;
+							TexSkin.Vram = gsKit_vram_alloc(gsGlobal,
+							 gsKit_texture_size(TexSkin.Width, TexSkin.Height, TexSkin.PSM),
+							 GSKIT_ALLOC_USERBUFFER);
+							gsKit_texture_upload(gsGlobal, &TexSkin);
+							free(TexSkin.Mem);
+							testskin = 1;
+						} /* end if */
+				 	} else if((Picture==PREVIEW_PIC)||(Picture==PREVIEW_GUI)){
+				 		if( ( ScaleBitmap ( ImgData, Jpg->width, Jpg->height, (void*)&TexPreview.Mem, SCREEN_WIDTH, SCREEN_HEIGHT ) ) != 0 ){
+				 			TexPreview.PSM = GS_PSM_CT24;
+							TexPreview.VramClut = 0;
+							TexPreview.Clut = NULL;
+				 			TexPreview.Width =  SCREEN_WIDTH;
+							TexPreview.Height = SCREEN_HEIGHT;
+							TexPreview.Filter = GS_FILTER_NEAREST;
+							gsGlobal->CurrentPointer=0x280000;
+							TexPreview.Vram = gsKit_vram_alloc(gsGlobal,
+							 gsKit_texture_size(TexPreview.Width, TexPreview.Height, TexPreview.PSM),
+							 GSKIT_ALLOC_USERBUFFER);
+							gsKit_texture_upload(gsGlobal, &TexPreview);
+							free(TexPreview.Mem);
+							testsetskin = 1;
+						} /* end if */
+				 	} else if( Picture == JPG_PIC ){
+				 		PicW=Jpg->width;
+				 		PicH=Jpg->height;
+				 		if(TV_mode == TV_mode_NTSC)
+				 			PicCoeff=(PicW/PicH)+(1.0f/10.5f);
+						else if(TV_mode == TV_mode_PAL)
+				 			PicCoeff=(PicW/PicH)-(1.0f/12.0f);
+				 		if(FullScreen){
+				 			if(Jpg->width > Jpg->height){
+				 				PicWidth=928;
+				 				PicHeight=696;
+				 			}else{
+				 				PicHeight=928;
+				 				PicWidth=696;
+				 			}
+				 		}else{
+				 			if(Jpg->width > Jpg->height){
+				 				PicWidth=640;
+				 				PicHeight=512;
+				 			}else{
+				 				PicHeight=640;
+				 				PicWidth=512;
+				 			}
+				 		}
+				 		if((ScaleBitmap(ImgData, Jpg->width, Jpg->height, &ImgData1, (int)PicWidth, Jpg->height))!=0){
+				 			if((ScaleBitmap(ImgData1, (int)PicWidth, Jpg->height, &ImgData2, (int)PicWidth, (int)PicHeight))!=0){
+						 		if((PicRotate==1) || (PicRotate==3)){ // Rotate picture
+						 			(void*)TexPicture.Mem = malloc(((int)PicWidth * (int)PicHeight * 3) + 1);
+						 			RotateBitmap(ImgData2, (int)PicWidth, (int)PicHeight, (void*)TexPicture.Mem, PicRotate);
+						 			W=PicW;
+						 			PicW=PicH;
+						 			PicH=W;
+							 		if(TV_mode == TV_mode_NTSC)
+							 			PicCoeff=(PicW/PicH)+(1.0f/10.5f);
+									else if(TV_mode == TV_mode_PAL)
+							 			PicCoeff=(PicW/PicH)-(1.0f/12.0f);
+							 		W=PicWidth;
+						 			PicWidth=PicHeight;
+						 			PicHeight=W;
+						 		}else{
+						 			memcpy((void*)&TexPicture.Mem, &ImgData2, sizeof(ImgData2));
+								}
+				 				TexPicture.PSM = GS_PSM_CT24;
+								TexPicture.VramClut = 0;
+								TexPicture.Clut = NULL;
+								TexPicture.Filter = GS_FILTER_NEAREST;
+				 				TexPicture.Width =  PicWidth;
+								TexPicture.Height = PicHeight;
+				 				if(FullScreen)
+									gsGlobal->CurrentPointer=0x140000;
+								else
+									gsGlobal->CurrentPointer=0x288000;
+								TexPicture.Vram = gsKit_vram_alloc(gsGlobal,
+								 gsKit_texture_size(TexPicture.Width, TexPicture.Height, TexPicture.PSM),
+								 GSKIT_ALLOC_USERBUFFER);
+								gsKit_texture_upload(gsGlobal, &TexPicture);
+								free(TexPicture.Mem);
+								testjpg = 1;
+							} /* end if */
+						} /* end if */
+				 	} else if( Picture == THUMB_PIC ){
+				 		if( ( ScaleBitmap ( ImgData, Jpg->width, Jpg->height, (void*)&TexThumb[ThumbNum].Mem, 64, 32 ) ) != 0 ){
+				 			TexThumb[ThumbNum].PSM = GS_PSM_CT24;
+							TexThumb[ThumbNum].VramClut = 0;
+							TexThumb[ThumbNum].Clut = NULL;
+				 			TexThumb[ThumbNum].Width =  64;
+							TexThumb[ThumbNum].Height = 32;
+							TexThumb[ThumbNum].Filter = GS_FILTER_NEAREST;
+							TexThumb[ThumbNum].Vram = gsKit_vram_alloc(gsGlobal,
+							 gsKit_texture_size(TexThumb[ThumbNum].Width,
+							 TexThumb[ThumbNum].Height, TexThumb[ThumbNum].PSM),
+							 GSKIT_ALLOC_USERBUFFER);
+							gsKit_texture_upload(gsGlobal, &TexThumb[ThumbNum]);
+							free(TexThumb[ThumbNum].Mem);
+							testthumb = 1;
+						} /* end if */
+				 	} /* end else */
+					jpgClose( Jpg );//This really should be moved, but jpg funcs may object
+				} /* end if((jpgReadImage(...)) != -1) */
+			free(ImgData);
+			free(ImgData1);
+			free(ImgData2);
+			} /* end if( (ImgData = malloc(...)) > 0 ) */
+		} /* end if( (Jpg=jpgOpenRAW(...)) > 0 ) */
+		fclose( File );
+	} /* end if( File != NULL ) */
+	if(!strncmp(tmpPath, "cdfs", 4)) CDVD_Stop();
+	if(!strncmp(tmpPath, "hdd0:/", 6))
+		unmountParty(0);
+}
+//--------------------------------------------------------------
+void loadIcon(void)
+{
+	TexIcon[0].Width = 16;
+	TexIcon[0].Height = 16;
+	TexIcon[0].PSM = GS_PSM_CT32;
+	TexIcon[0].Mem = (void*)icon_folder;
+	gsGlobal->CurrentPointer=0x280000;
+	TexIcon[0].Vram = gsKit_vram_alloc(gsGlobal, gsKit_texture_size(TexIcon[0].Width, TexIcon[0].Height, TexIcon[0].PSM), GSKIT_ALLOC_USERBUFFER);
+	TexIcon[0].Filter = GS_FILTER_LINEAR;
+	gsKit_texture_upload(gsGlobal, &TexIcon[0]);
+	free(TexIcon[0].Mem);
+
+	TexIcon[1].Width = 16;
+	TexIcon[1].Height = 16;
+	TexIcon[1].PSM = GS_PSM_CT32;
+	TexIcon[1].Mem = (void*)icon_warning;
+	gsGlobal->CurrentPointer=0x284000;
+	TexIcon[1].Vram = gsKit_vram_alloc(gsGlobal, gsKit_texture_size(TexIcon[0].Width, TexIcon[0].Height, TexIcon[0].PSM), GSKIT_ALLOC_USERBUFFER);
+	TexIcon[1].Filter = GS_FILTER_LINEAR;
+	gsKit_texture_upload(gsGlobal, &TexIcon[1]);
+	free(TexIcon[1].Mem);
+}
+//--------------------------------------------------------------
+int loadFont(char *path_arg)
+{
+	int fd;
+
+	if(strlen(path_arg) != 0 ){
+	char FntPath[MAX_PATH];
+	genFixPath(path_arg, FntPath);
+	fd = genOpen( FntPath, O_RDONLY );
+		if(fd < 0){
+			genClose( fd );
+			goto use_default;
+		} // end if failed open file
+		genLseek( fd, 0, SEEK_SET );
+		if(genLseek( fd, 0, SEEK_END ) > 4700){
+			genClose( fd );
+			goto use_default;
+		}
+		genLseek( fd, 0, SEEK_SET );
+		u8 FontHeader[100];
+		genRead( fd, FontHeader, 100 );
+		if((FontHeader[ 0]==0x00) &&
+		   (FontHeader[ 1]==0x02) &&
+		   (FontHeader[70]==0x60) &&
+		   (FontHeader[72]==0x60) &&
+		   (FontHeader[83]==0x90)){
+			genLseek( fd, 1018, SEEK_SET );
+			memset( FontBuffer, 0, 32*16 );
+			genRead( fd, FontBuffer+32*16, 224*16 ); //.fnt files skip 1st 32 chars
+			genClose( fd );
+			return 1;
+		}else{ // end if good fnt file
+			genClose( fd );
+			goto use_default;
+		} // end else bad fnt file
+	}else{ // end if external font file
+use_default:
+		memcpy( FontBuffer, &font_uLE, 4096 );
+	} // end else build-in font
+	return 0;
+}
+//------------------------------
+//endfunc loadFont
+//--------------------------------------------------------------
+// Set Skin Brightness
+void setBrightness(int Brightness)
+{
+	float adjustBright = 128.0F;
+ 
+	if ( Brightness == 50 ) adjustBright = 128.0F;
+	else	adjustBright = (((256.0F/100.0F)*Brightness) + (32.0F*((50.0F-Brightness)/50)));
+
+	if ( adjustBright <=  16.0F ) adjustBright =  16.0F;
+	if ( adjustBright >= 240.0F ) adjustBright = 240.0F;
+
+	BrightColor = GS_SETREG_RGBAQ( adjustBright, adjustBright, adjustBright, 0x80, 0x00 );
+}
+
+//--------------------------------------------------------------
+void clrScr(u64 color)
+{
+	if ( testskin == 1 ) {
+		setBrightness(setting->Brightness);
+		gsKit_clear(gsGlobal, GS_SETREG_RGBAQ(0x00,0x00,0x00,0x00,0x00));
+		gsKit_prim_sprite_texture(gsGlobal,
+		 &TexSkin, 0, 0, 0, 0,
+		 SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT,
+		 0, BrightColor);
+		setBrightness(50);
+	} else {
+		gsKit_prim_sprite(gsGlobal, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, color);
+	} /* end else */
+}
+
+//--------------------------------------------------------------
+void drawScr(void)
+{
+	int sanity_check = 0;
+
+	if(updateScr_2){            //Did we render anything last time
+		while((Timer() < updateScr_t+5) && (sanity_check++ < 10000));
+															//if so, delay to complete rendering
+	}
+	gsKit_sync_flip(gsGlobal);  //Await sync and flip buffers
+	gsKit_queue_exec(gsGlobal); //Start rendering recent transfers for NEXT time
+	updateScr_t = Timer();      //Note the time when the rendering started
+	updateScr_2 = updateScr_1;  //Note if this rendering had expected updates
+	updateScr_1 = 0;            //Note that we've nothing expected for next time
+} //NB: Apparently the GS keeps rendering while we continue with other work
+//--------------------------------------------------------------
+void drawFrame(int x1, int y1, int x2, int y2, u64 color)
+{
+	int	y_off = (setting->interlace) ? 0 : (y1 & 1);
+	y1 -= y_off;
+	y2 -= y_off;
+
+	updateScr_1 = 1;
+
+	//Top horizontal edge
+	gsKit_prim_sprite(gsGlobal, x1, y1, x2, y1+LINE_THICKNESS-1, 1, color);
+
+	//Bottom horizontal
+	gsKit_prim_sprite(gsGlobal, x1, y2-LINE_THICKNESS+1, x2, y2, 1, color);
+
+	//Left vertical edge
+	gsKit_prim_sprite(gsGlobal, x1, y1, x1+LINE_THICKNESS-1, y2, 1, color);
+
+	//Right vertical edge
+	gsKit_prim_sprite(gsGlobal, x2-LINE_THICKNESS+1, y1, x2, y2, 1, color);
+}
+
+//--------------------------------------------------------------
+// draw a char using the system font (16x16)
+void drawChar(unsigned int c, int x, int y, u64 colour)
+{
+	int i, j, pixBase, pixMask;
+	u8  *cm;
+
+	updateScr_1 = 1;
+
+	if(!setting->interlace){
+		y = y & -2;
+	}
+
+	if(c >= FONT_COUNT) c = '_';
+	if(c > 0xFF)              //if char is beyond normal ascii range
+		cm = &font_uLE[c*16];   //  cm points to special char def in default font
+	else                      //else char is inside normal ascii range
+		cm = &FontBuffer[c*16]; //  cm points to normal char def in active font
+
+	pixMask = 0x80;
+	for(i=0; i<8; i++){	//for i == each pixel column
+		pixBase = -1;
+		for(j=0; j<16; j++){ //for j == each pixel row
+			if((pixBase < 0) && (cm[j] & pixMask)){ //if start of sequence
+				pixBase = j;
+			} else if((pixBase > -1) && !(cm[j] & pixMask)){ //if end of sequence
+				gsKit_prim_sprite(gsGlobal, x+i, y+pixBase-1, x+i+1, y+j-1, 1, colour);
+				pixBase = -1;
+			}
+		}//ends for j == each pixel row
+		if(pixBase > -1) //if end of sequence including final row
+			gsKit_prim_sprite(gsGlobal, x+i, y+pixBase-1, x+i+1, y+j-1, 1, colour);
+		pixMask >>= 1;
+	}//ends for i == each pixel column
+}
+//------------------------------
+//endfunc drawChar
+//--------------------------------------------------------------
+// draw a char using the ELISA font (16x16)
+void drawChar2(int n, int x, int y, u64 colour)
+{
+	unsigned int i, j;
+	u8 b;
+	
+	updateScr_1 = 1;
+
+	if(!setting->interlace){
+		y = y & -2;
+	}
+
+	for(i=0; i<8; i++)
+	{
+		b = elisaFnt[n+i];
+		for(j=0; j<8; j++)
+		{
+			if(b & 0x80) {
+				gsKit_prim_sprite(gsGlobal, x+j, y+i*2-2, x+j+1, y+i*2, 1, colour);
+			}
+			b = b << 1;
+		}
+	}
+}
+//------------------------------
+//endfunc drawChar2
+//--------------------------------------------------------------
+// draw a string of characters, without shift-JIS support
+int printXY(const unsigned char *s, int x, int y, u64 colour, int draw, int space)
+{
+	unsigned int c1, c2;
+	int i;
+	int text_spacing=8;
+	
+	if(space>0){
+		while((strlen(s)*text_spacing) > space)
+			if(--text_spacing<=5)
+				break;
+	}else{
+		while((strlen(s)*text_spacing) > SCREEN_WIDTH-SCREEN_MARGIN-FONT_WIDTH*2)
+			if(--text_spacing<=5)
+				break;
+	}
+
+	i=0;
+	while((c1=s[i++])!=0) {
+		if(c1 != 0xFF) { // Normal character
+			if(draw) drawChar(c1, x, y, colour);
+			x += text_spacing;
+			if(x > SCREEN_WIDTH-SCREEN_MARGIN-FONT_WIDTH)
+				break;
+			continue;
+		}  //End if for normal character
+		// Here we got a sequence starting with 0xFF ('ÿ')
+		if((c2=s[i++])==0)
+			break;
+		if((c2 < '0') || (c2 > '='))
+			continue;
+		c1=(c2-'0')*2+0x100;
+		if(draw) {
+			//expand sequence ÿ0=Circle  ÿ1=Cross  ÿ2=Square  ÿ3=Triangle  ÿ4=FilledBox
+			//"ÿ:"=Pad_Right  "ÿ;"=Pad_Down  "ÿ<"=Pad_Left  "ÿ="=Pad_Up
+			drawChar(c1, x, y, colour);
+			x += 8;
+			if(x > SCREEN_WIDTH-SCREEN_MARGIN-FONT_WIDTH)
+				break;
+			drawChar(c1+1, x, y, colour);
+			x += 8;
+			if(x > SCREEN_WIDTH-SCREEN_MARGIN-FONT_WIDTH)
+				break;
+		}
+	}  // ends while(1)
+	return x;
+}
+//------------------------------
+//endfunc printXY
+//--------------------------------------------------------------
+// draw a string of characters, with shift-JIS support (only for gamesave titles)
+int printXY_sjis(const unsigned char *s, int x, int y, u64 colour, int draw)
+{
+	int n;
+	unsigned char ascii;
+	u16 code;
+	int i, j, tmp;
+	
+	i=0;
+	while(s[i]){
+		if((s[i] & 0x80) && s[i+1]) { //we have top bit and some more char ?
+			// SJIS
+			code = s[i++];
+			code = (code<<8) + s[i++];
+			
+			switch(code){
+			// Circle == ""
+			case 0x819B:
+				if(draw){
+					drawChar(0x100, x, y, colour);
+					drawChar(0x101, x+8, y, colour);
+				}
+				x+=16;
+				break;
+			// Cross == "~"
+			case 0x817E:
+				if(draw){
+					drawChar(0x102, x, y, colour);
+					drawChar(0x103, x+8, y, colour);
+				}
+				x+=16;
+				break;
+			// Square == " "
+			case 0x81A0:
+				if(draw){
+					drawChar(0x104, x, y, colour);
+					drawChar(0x105, x+8, y, colour);
+				}
+				x+=16;
+				break;
+			// Triangle == "¢"
+			case 0x81A2:
+				if(draw){
+					drawChar(0x106, x, y, colour);
+					drawChar(0x107, x+8, y, colour);
+				}
+				x+=16;
+				break;
+			// FilledBox == "¡"
+			case 0x81A1:
+				if(draw){
+					drawChar(0x108, x, y, colour);
+					drawChar(0x109, x+8, y, colour);
+				}
+				x+=16;
+				break;
+			default:
+				if(elisaFnt!=NULL){ // elisa font is available ?
+					tmp=y;
+					if(code<=0x829A) tmp++;
+					// SJIS©çEUCÉÏ·
+					if(code >= 0xE000) code-=0x4000;
+					code = ((((code>>8)&0xFF)-0x81)<<9) + (code&0x00FF);
+					if((code & 0x00FF) >= 0x80) code--;
+					if((code & 0x00FF) >= 0x9E) code+=0x62;
+					else code-=0x40;
+					code += 0x2121 + 0x8080;
+					
+					// EUC©çb¹tHgÌÔð¶¬
+					n = (((code>>8)&0xFF)-0xA1)*(0xFF-0xA1)
+						+ (code&0xFF)-0xA1;
+					j=0;
+					while(font404[j]) {
+						if(code >= font404[j]) {
+							if(code <= font404[j]+font404[j+1]-1) {
+								n = -1;
+								break;
+							} else {
+								n-=font404[j+1];
+							}
+						}
+						j+=2;
+					}
+					n*=8;
+					
+					if(n>=0 && n<=55008) {
+						if(draw) drawChar2(n, x, tmp, colour);
+						x+=9;
+					}else{
+						if(draw) drawChar('_', x, y, colour);
+						x+=8;
+					}
+				}else{ //elisa font is not available
+					ascii=0xFF;
+					if(code>>8==0x81)
+						ascii = sjis_lookup_81[code & 0x00FF];
+					else if(code>>8==0x82)
+						ascii = sjis_lookup_82[code & 0x00FF];
+					if(ascii!=0xFF){
+						if(draw) drawChar(ascii, x, y, colour);
+					}else{
+						if(draw) drawChar('_', x, y, colour);
+					}
+					x+=8;
+				}
+				break;
+			}
+		}else{ //First char does not have top bit set or no following char
+			if(draw) drawChar(s[i], x, y, colour);
+			i++;
+			x += 8;
+		}
+		if(x > SCREEN_WIDTH-SCREEN_MARGIN-FONT_WIDTH){
+			//x=16; y=y+8;
+			return x;
+		}
+	}
+	return x;
+}
+//------------------------------
+//endfunc printXY_sjis
+//--------------------------------------------------------------
+//translate a string from shift-JIS to ascii (for gamesave titles)
+u8 *transcpy_sjis(u8 *d, u8 *s)
+{
+	u8 ascii;
+	u16 code1, code2;
+	int i, j;
+
+	for(i=0, j=0; s[i];){
+		code1 = s[i++];
+		if((code1 & 0x80) && s[i]) { //we have top bit and some more char (SJIS) ?
+			// SJIS
+			code2 = s[i++];
+			ascii=0xFF;
+			if(code1==0x81)
+				ascii = sjis_lookup_81[code2];
+			else if(code1==0x82)
+				ascii = sjis_lookup_82[code2];
+			if(ascii!=0xFF){
+				d[j++]=ascii;
+			}else{
+				d[j++]='_';
+			}
+		}else{ //First char lacks top bit set or no following char (non-SJIS)
+			d[j++] = code1;
+		}
+	}//ends for
+	d[j] = '\0'; //terminate result string
+	return d;
+}
+//------------------------------
+//endfunc transcpy_sjis
+//--------------------------------------------------------------
+//WriteFont_C is used to save the current font as C source code
+//Comment it out if not used
+/*
+int	WriteFont_C(char *path_arg)
+{
+	u8  path[MAX_PATH];
+	u8  text[80*2], char_info[80];
+	u8	*p;
+	int ret, tst, i, fd=-1;
+
+	ret=-1; tst=genFixPath(path_arg, path);
+	if(tst < 0) goto finish;
+	ret=-2; tst=genOpen(path,O_CREAT|O_WRONLY|O_TRUNC);
+	if(tst < 0) goto finish;
+	fd = tst;
+	sprintf(text, "unsigned char font_uLE[] = {\r\n");
+	ret=-3; tst = genWrite(fd, text, strlen(text));
+	if(tst != strlen(text)) goto finish;
+	for(i=0x000; i<0x10A; i++){
+		p = font_uLE + i*16;
+		text[0] = '\0';
+		if((i & 0x07) == 0)
+			sprintf(text, "//Font position 0x%03X\r\n", i);
+		if((i < 0x20) || (i>0x80 && i<0xA0))
+			sprintf(char_info, "//char 0x%03X == '_' (free for use)", i);
+		else if(i < 0x100)
+			sprintf(char_info, "//char 0x%03X == '%c'", i, i);
+		else //(i > 0x0FF)
+			sprintf(char_info, "//char 0x%03X == special for uLE", i);
+		sprintf(text+strlen(text),
+			"	0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, %s\r\n"
+			"	0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X"
+			, p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7], char_info
+			, p[8],p[9], p[10],p[11], p[12],p[13], p[14],p[15]
+		);
+		if(i<0x109) strcat(text, ",");
+		strcat(text, "\r\n");
+		ret=-4; tst = genWrite(fd, text, strlen(text));
+		if(tst != strlen(text)) break;
+		ret = 0;
+	} //ends for
+	if(ret == 0){
+		sprintf(text,
+			"//Font position 0x%03X\r\n"
+			"}; //ends font_uLE\r\n", i);
+		ret=-5; tst = genWrite(fd, text, strlen(text));
+		if(tst == strlen(text)) ret = 0;
+	}
+finish:
+	if(fd >= 0) genClose(fd);
+	sprintf(text,"Saving %s => %d\nChoose either option to continue", path, ret);
+	ynDialog(text);
+	return ret;
+}
+*/
+//------------------------------
+//endfunc WriteFont_C
+//--------------------------------------------------------------
+//End of file: draw.c
+//--------------------------------------------------------------
Index: ps2launchargs/source/uLaunchELF/editor.c
===================================================================
--- ps2launchargs/source/uLaunchELF/editor.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/editor.c	(revision 1101)
@@ -0,0 +1,1750 @@
+//--------------------------------------------------------------
+//File name:    editor.c
+//--------------------------------------------------------------
+#include "launchelf.h"
+
+enum
+{
+	COL_NORM_BG    = GS_SETREG_RGBA(160,160,160,0),
+	COL_NORM_TEXT  = GS_SETREG_RGBA(0,0,0,0),
+	COL_MARK_BG    = GS_SETREG_RGBA(0,40,160,0),
+	COL_MARK_TEXT  = GS_SETREG_RGBA(160,160,160,0),
+	COL_CUR_INSERT = GS_SETREG_RGBA(0,160,0,0),
+	COL_CUR_OVERWR = GS_SETREG_RGBA(160,0,0,0),
+	COL_LINE_END   = GS_SETREG_RGBA(160,80,0,0),
+	COL_TAB        = GS_SETREG_RGBA(0,0,160,0),
+	COL_TEXT_END   = GS_SETREG_RGBA(0,160,160,0),
+	COL_dummy
+};
+
+enum
+{
+	NEW,
+	OPEN,
+	CLOSE,
+	SAVE,
+	SAVE_AS,
+	WINDOWS,
+	EXIT,
+	NUM_MENU
+}; // Menu Fonction.
+
+enum
+{
+	MARK_START,
+	MARK_ON,
+	MARK_COPY,
+	MARK_CUT,
+	MARK_IN,
+	MARK_OUT,
+	MARK_TMP,
+	MARK_SIZE,
+	MARK_PRINT,
+	MARK_COLOR,
+	NUM_MARK
+}; // Marking Fonction/State.
+
+enum
+{
+	CREATED,
+	OPENED,
+	SAVED,
+	NUM_STATE
+}; // Windowing State.
+
+#define OTHER 1 // CR/LF Return Text Mode, 'All Normal System'.
+#define UNIX  2 // CR Return Text Mode, Unix.
+#define MAC   3 // LF Return Text Mode, Mac.
+
+#define TMP  10 // Temp Buffer For Add / Remove Char.
+#define EDIT 11 // Edit Buffer For Copy / Cut / Paste.
+
+static u8   *TextBuffer[12]; // Text Buffers, 10 Windows Max + 1 TMP + 1 EDIT. See above.
+static int  Window[10][NUM_STATE], // Windowing System, 10 Windows Max.
+						TextMode[10], // Text Mode, UNIX, MAC, OTHER.
+						TextSize[10], // Text Size, 10 Windows Max.
+						Editor_nRowsWidth[MAX_ENTRY], // Current Window, Char Number For Each Rows. (MAX_ENTRY???)
+						Mark[NUM_MARK], // Marking System,(Mark, Copy, Cut, Paste, Delete),Work From 1 Window To An Other.
+						Active_Window, // Activated Windows Number.
+						Num_Window, // Opened Windows Count.
+						Editor_Cur, // Text Cursor.
+						Tmp_Cur, // Temp Cursor For Rules Calculations.
+						Editor_nChar, // Current Window, Total Char Number.
+						Editor_nRowsNum, // Current Window, Total Rows Number.
+						Editor_nCharRows, // Current Window, Char Number Per Rows Height.
+						Editor_nRowsTop, // Current Window, Rows Number Above Top Screen For Rules Calculations.
+						Rows_Num, // Rows Number Feeting In Screen Height.
+						Rows_Width, // Char Number Feeting In Screen Width.
+						Top_Width,  // Char Number In Rows Above Top Screen.
+						Top_Height, // Current Window Rows Number Above Top Screen.
+						Editor_Insert, // Setting Insert On/Off.
+						Editor_RetMode, // Setting Insert On/Off.
+						Editor_Home, // Goto Line Home.
+						Editor_End, // Goto Line End
+						Editor_PushRows, // Push 1 Row Height Up(+1) Or Down(-1), Use For Page Up/Down Too.
+						Editor_TextEnd, // Set To 1 When '\0' Char Is Found Tell Text End.
+						KeyBoard_Cur, // Virtual KeyBoard Cursor.
+						KeyBoard_Active, // Virtual KeyBoard Activated Or Not.
+						del1, del2, del3, del4, // Deleted Chars Different Cases.
+						ins1, ins2, ins3, ins4, ins5, // Added Chars Different Cases.
+						t; // Text Cursor Timer.
+static char Path[10][MAX_PATH]; // File Path For Each Opened Windows. 10 Max.
+
+static const int WFONTS=20, // Virtual KeyBoard Width.
+								 HFONTS=5; // Virtual KeyBoard Height.
+static char *KEY= "  01ABCDEFGHIJKLM:; "
+									"  23NOPQRSTUVWXYZ., "
+									"  45abcdefghijklm() "
+									"  67nopqrstuvwxyz[] "
+									"  89+-=!#   $%&@_^' "; // Virtual KeyBoard Matrix.
+
+//--------------------------------------------------------------
+int MenuEditor(void)
+{
+	u64 color;
+	char enable[NUM_MENU], tmp[64];
+	int x, y, i, Menu_Sel;
+	int event, post_event=0;
+
+	int menu_len=strlen(LNG(New))>strlen(LNG(Open))?
+		strlen(LNG(New)):strlen(LNG(Open));
+	menu_len=strlen(LNG(Close))>menu_len? strlen(LNG(Close)):menu_len;
+	menu_len=strlen(LNG(Save))>menu_len? strlen(LNG(Save)):menu_len;
+	menu_len=strlen(LNG(Save_As))>menu_len? strlen(LNG(Save_As)):menu_len;
+	menu_len=strlen(LNG(Windows))>menu_len? strlen(LNG(Windows)):menu_len;
+	menu_len=strlen(LNG(Exit))>menu_len? strlen(LNG(Exit)):menu_len;
+
+	int menu_ch_w = menu_len+1;    //Total characters in longest menu string.
+	int menu_ch_h = NUM_MENU;      //Total number of menu lines.
+	int mSprite_Y1 = 64;           //Top edge of sprite.
+	int mSprite_X2 = SCREEN_WIDTH-35;   //Right edge of sprite.
+	int mSprite_X1 = mSprite_X2-(menu_ch_w+3)*FONT_WIDTH;   //Left edge of sprite
+	int mSprite_Y2 = mSprite_Y1+(menu_ch_h+1)*FONT_HEIGHT;  //Bottom edge of sprite
+
+	memset(enable, TRUE, NUM_MENU);
+
+	if(!Window[Active_Window][OPENED]){
+		enable[CLOSE] = FALSE;
+		enable[SAVE] = FALSE;
+		enable[SAVE_AS] = FALSE;
+	}	
+	if(Window[Active_Window][CREATED]){
+		enable[SAVE] = FALSE;
+	}
+	if(!Num_Window)
+		enable[WINDOWS] = FALSE;
+
+	for(Menu_Sel=0; Menu_Sel<NUM_MENU; Menu_Sel++)
+		if(enable[Menu_Sel]==TRUE) break;
+	
+	event = 1;  //event = initial entry.
+	while(1){
+		//Pad response section.
+		waitPadReady(0, 0);
+		if(readpad()){
+			if(new_pad & PAD_UP && Menu_Sel<NUM_MENU){
+				event |= 2;  //event |= valid pad command.
+				do{
+					Menu_Sel--;
+					if(Menu_Sel<0) Menu_Sel=NUM_MENU-1;
+				}while(!enable[Menu_Sel]);
+			}else if(new_pad & PAD_DOWN && Menu_Sel<NUM_MENU){
+				event |= 2;  //event |= valid pad command.
+				do{
+					Menu_Sel++;
+					if(Menu_Sel==NUM_MENU) Menu_Sel=0;
+				}while(!enable[Menu_Sel]);
+			}else if((new_pad & PAD_TRIANGLE)
+						|| (!swapKeys && new_pad & PAD_CROSS)
+			      || (swapKeys && new_pad & PAD_CIRCLE) ){
+				return -1;
+			}else if((swapKeys && new_pad & PAD_CROSS)
+			      || (!swapKeys && new_pad & PAD_CIRCLE) ){
+				event |= 2;  //event |= valid pad command.
+				break;
+			}
+		}
+
+		if(event||post_event){ //NB: We need to update two frame buffers per event.
+
+			//Display section.
+			drawPopSprite(setting->color[0],
+				mSprite_X1, mSprite_Y1,
+				mSprite_X2, mSprite_Y2);
+			drawFrame(mSprite_X1, mSprite_Y1, mSprite_X2, mSprite_Y2, setting->color[1]);
+
+			for(i=0,y=mSprite_Y1+FONT_HEIGHT/2; i<NUM_MENU; i++){
+				if(i==NEW)			strcpy(tmp, LNG(New));
+				else if(i==OPEN)			strcpy(tmp, LNG(Open));
+				else if(i==CLOSE)		strcpy(tmp, LNG(Close));
+				else if(i==SAVE)		strcpy(tmp, LNG(Save));
+				else if(i==SAVE_AS)	strcpy(tmp, LNG(Save_As));
+				else if(i==WINDOWS)	strcpy(tmp, LNG(Windows));
+				else if(i==EXIT)	strcpy(tmp, LNG(Exit));
+
+				if(enable[i])	color = setting->color[3];
+				else			color = setting->color[1];
+
+				printXY(tmp, mSprite_X1+2*FONT_WIDTH, y, color, TRUE, 0);
+				y+=FONT_HEIGHT;
+			}
+			if(Menu_Sel<NUM_MENU)
+				drawChar(LEFT_CUR, mSprite_X1+FONT_WIDTH, mSprite_Y1+(FONT_HEIGHT/2+Menu_Sel*FONT_HEIGHT), setting->color[3]);
+
+			//Tooltip section.
+			x = SCREEN_MARGIN;
+			y = Menu_tooltip_y;
+			drawSprite(setting->color[0],
+				0, y-1,
+				SCREEN_WIDTH, y+16);
+			if (swapKeys)
+				sprintf(tmp, "ÿ1:%s ÿ0:%s ÿ3:%s", LNG(OK), LNG(Cancel), LNG(Back));
+			else
+				sprintf(tmp, "ÿ0:%s ÿ1:%s ÿ3:%s", LNG(OK), LNG(Cancel), LNG(Back));
+			printXY(tmp, x, y, setting->color[2], TRUE, 0);
+		}//ends if(event||post_event).
+		drawScr();
+		post_event = event;
+		event = 0;
+	}//ends while.
+	return Menu_Sel;
+}//ends menu.
+//--------------------------------------------------------------
+void Virt_KeyBoard_Entry(void)
+{
+	int i, Operation;
+
+	Operation=0;
+
+	if(new_pad & PAD_UP){ // Virtual KeyBoard move up.
+		if(!KeyBoard_Cur)
+			KeyBoard_Cur=WFONTS*(HFONTS-1);
+		else if(KeyBoard_Cur==WFONTS-1)
+			KeyBoard_Cur=WFONTS*HFONTS-1;
+		else if(KeyBoard_Cur>0){
+			if((KeyBoard_Cur-=WFONTS)<0)
+				KeyBoard_Cur=0;
+		}
+		//ends Virtual KeyBoard move up.
+	}else if(new_pad & PAD_DOWN){ // Virtual KeyBoard move down.
+		if(KeyBoard_Cur==WFONTS*HFONTS-1)
+			KeyBoard_Cur=WFONTS-1;
+		else if(KeyBoard_Cur==WFONTS*(HFONTS-1))
+			KeyBoard_Cur=0;
+		else if(KeyBoard_Cur<WFONTS*HFONTS-1){
+			if((KeyBoard_Cur+=WFONTS)>WFONTS*HFONTS-1)
+				KeyBoard_Cur=WFONTS*HFONTS-1;
+		}
+		//ends Virtual KeyBoard move down.
+	}else if(new_pad & PAD_LEFT){ // Virtual KeyBoard move left.
+		if(!KeyBoard_Cur)
+			KeyBoard_Cur=WFONTS*HFONTS-1;
+		else
+			KeyBoard_Cur--;
+		//ends Virtual KeyBoard move left.
+	}else if(new_pad & PAD_RIGHT){ // Virtual KeyBoard move right.
+		if(KeyBoard_Cur==WFONTS*HFONTS-1)
+			KeyBoard_Cur=0;
+		else
+			KeyBoard_Cur++;
+		//ends Virtual KeyBoard move right.
+	}else if(new_pad & PAD_L2){ // Text move left.
+		if(Editor_Cur>0)
+			Editor_Cur--;
+	}else if(new_pad & PAD_R2){ // Text move right.
+		if(Editor_Cur<Editor_nChar && TextBuffer[Active_Window][Editor_Cur]!='\0')
+			Editor_Cur++;
+	}else if(new_pad & PAD_SELECT){ // Virtual KeyBoard Exit.
+		Rows_Num += 6;
+		KeyBoard_Active = 0;
+	}else if((!swapKeys && new_pad & PAD_CROSS)
+	      || (swapKeys && new_pad & PAD_CIRCLE) ){ // Virtual KeyBoard Backspace
+		if(Editor_Cur>0){
+			if(		TextMode[Active_Window]==OTHER
+				&&	TextBuffer[Active_Window][Editor_Cur]=='\n'
+				&&	TextBuffer[Active_Window][Editor_Cur-1]=='\r'
+			){
+				Editor_Cur += 1; //Backspace at LF of CRLF must work after LF instead
+			}
+			if(Mark[MARK_ON]){
+				Mark[MARK_OUT]=Editor_Cur;
+				if(Mark[MARK_OUT]<Mark[MARK_IN]){
+					Mark[MARK_TMP]=Mark[MARK_IN];
+					Mark[MARK_IN]=Mark[MARK_OUT];
+					Mark[MARK_OUT]=Mark[MARK_TMP];
+				}else if(Mark[MARK_IN]==Mark[MARK_OUT])
+					goto abort;
+				Mark[MARK_SIZE]=Mark[MARK_OUT]-Mark[MARK_IN];
+				del1= -Mark[MARK_SIZE], del2=0, del3= -Mark[MARK_SIZE], del4= -Mark[MARK_SIZE];
+				Mark[MARK_ON]=0;
+			}else if(TextMode[Active_Window]==OTHER
+				&&	TextBuffer[Active_Window][Editor_Cur-1]=='\n'
+				&&	Editor_Cur>1
+				&&	TextBuffer[Active_Window][Editor_Cur-2]=='\r'){
+				del1=-2, del2=0, del3=-2, del4=-2; //Backspace CRLF
+			}else{
+				del1=-1, del2=0, del3=-1, del4=-1; //Backspace single char
+			}
+			Operation=-1;
+		}
+		//ends Virtual KeyBoard Backspace
+	}else if((swapKeys && new_pad & PAD_CROSS)
+	      || (!swapKeys && new_pad & PAD_CIRCLE) ){ // Virtual KeyBoard Select.
+		if(!KeyBoard_Cur){ // Virtual KeyBoard MARK.
+			Mark[MARK_ON]=!Mark[MARK_ON];
+			if(Mark[MARK_ON]){
+				if(		TextMode[Active_Window]==OTHER
+					&&	TextBuffer[Active_Window][Editor_Cur]=='\n'
+					&&	Editor_Cur>0
+					&&	TextBuffer[Active_Window][Editor_Cur-1]=='\r'
+				){
+					Editor_Cur -= 1; //Marking at LF of CRLF must start at CR instead
+				}
+				if(Mark[MARK_COPY] || Mark[MARK_CUT])
+					free(TextBuffer[EDIT]);
+				Mark[MARK_ON]=1, Mark[MARK_COPY]=0, Mark[MARK_CUT]=0,
+				Mark[MARK_IN]=0, Mark[MARK_OUT]=0, Mark[MARK_TMP]=0,
+				Mark[MARK_SIZE]=0, Mark[MARK_PRINT]=0, Mark[MARK_COLOR]=0;
+				Mark[MARK_IN]=Mark[MARK_OUT]=Editor_Cur;
+			}
+			Mark[MARK_START]=1;
+			//ends Virtual KeyBoard MARK.
+		}else if(KeyBoard_Cur == WFONTS){ // Virtual KeyBoard COPY.
+			if(Mark[MARK_ON]){
+				if(		TextMode[Active_Window]==OTHER
+					&&	TextBuffer[Active_Window][Editor_Cur]=='\n'
+					&&	Editor_Cur>0
+					&&	TextBuffer[Active_Window][Editor_Cur-1]=='\r'
+				){
+					Editor_Cur += 1; //Mark end at LF of CRLF must include LF as well
+				}
+				Mark[MARK_OUT]=Editor_Cur;
+				if(Mark[MARK_OUT]<Mark[MARK_IN]){
+					Mark[MARK_TMP]=Mark[MARK_IN];
+					Mark[MARK_IN]=Mark[MARK_OUT];
+					Mark[MARK_OUT]=Mark[MARK_TMP];
+				}else if(Mark[MARK_IN]==Mark[MARK_OUT])
+					goto abort;
+				if(Mark[MARK_COPY] || Mark[MARK_CUT])
+					free(TextBuffer[EDIT]);
+				Mark[MARK_SIZE]=Mark[MARK_OUT]-Mark[MARK_IN];
+				TextBuffer[EDIT] = malloc(Mark[MARK_SIZE]+256); // 256 To Avoid Crash 256???
+				for(i=0; i<Mark[MARK_SIZE]; i++)
+					TextBuffer[EDIT][i]=TextBuffer[Active_Window][i+Mark[MARK_IN]];
+				Mark[MARK_COPY]=1, Mark[MARK_CUT]=0, Mark[MARK_ON]=0;
+			}
+			//ends Virtual KeyBoard COPY.
+		}else if(KeyBoard_Cur == 2*WFONTS){ // Virtual KeyBoard CUT.
+			if(Mark[MARK_ON]){
+				if(		TextMode[Active_Window]==OTHER
+					&&	TextBuffer[Active_Window][Editor_Cur]=='\n'
+					&&	Editor_Cur>0
+					&&	TextBuffer[Active_Window][Editor_Cur-1]=='\r'
+				){
+					Editor_Cur += 1; //Mark end at LF of CRLF must include LF as well
+				}
+				Mark[MARK_OUT]=Editor_Cur;
+				if(Mark[MARK_OUT]<Mark[MARK_IN]){
+					Mark[MARK_TMP]=Mark[MARK_IN];
+					Mark[MARK_IN]=Mark[MARK_OUT];
+					Mark[MARK_OUT]=Mark[MARK_TMP];
+				}else if(Mark[MARK_IN]==Mark[MARK_OUT])
+					goto abort;
+				if(Mark[MARK_COPY] || Mark[MARK_CUT])
+					free(TextBuffer[EDIT]);
+				Mark[MARK_SIZE]=Mark[MARK_OUT]-Mark[MARK_IN];
+				TextBuffer[EDIT] = malloc(Mark[MARK_SIZE]+256); // 256 To Avoid Crash 256???
+				for(i=0; i<Mark[MARK_SIZE]; i++)
+					TextBuffer[EDIT][i]=TextBuffer[Active_Window][i+Mark[MARK_IN]];
+				del1= -Mark[MARK_SIZE], del2=0, del3= -Mark[MARK_SIZE], del4= -Mark[MARK_SIZE];
+				Mark[MARK_CUT]=1, Mark[MARK_COPY]=0, Mark[MARK_ON]=0;
+				Operation=-1;
+			}
+abort:
+			Mark[MARK_TMP]=0; // just for compiler warning.
+			//ends Virtual KeyBoard CUT.
+		}else if(KeyBoard_Cur == 3*WFONTS){ // Virtual KeyBoard PASTE.
+			if( Mark[MARK_COPY] || Mark[MARK_CUT]){
+				if(TextMode[Active_Window]==OTHER && TextBuffer[Active_Window][Editor_Cur]=='\n'){
+					Editor_Cur-=1;
+					Mark[MARK_SIZE]-=1;
+				}
+				ins1=Mark[MARK_SIZE], ins2=Mark[MARK_SIZE], ins3=Mark[MARK_SIZE], ins4=0, ins5=Mark[MARK_SIZE];
+				Operation=1;
+			}
+			//ends Virtual KeyBoard PASTE.
+		}else if(KeyBoard_Cur == 4*WFONTS){ // Virtual KeyBoard HOME.
+			Editor_Home=1;
+		}else if(KeyBoard_Cur == 1){ // Virtual KeyBoard LINE UP.
+			if(Editor_Cur>0)
+				Editor_PushRows++;
+		}else if(KeyBoard_Cur == WFONTS+1){ // Virtual KeyBoard LINE DOWN.
+			if(Editor_Cur<Editor_nChar)
+				Editor_PushRows--;
+		}else if(KeyBoard_Cur == 2*WFONTS+1){ // Virtual KeyBoard PAGE UP.
+			if(Editor_Cur>0)
+				Editor_PushRows += 1*(Rows_Num-1);
+		}else if(KeyBoard_Cur == 3*WFONTS+1){ // Virtual KeyBoard PAGE DOWN.
+			if(Editor_Cur<Editor_nChar && TextBuffer[Active_Window][Editor_Cur]!='\0')
+				Editor_PushRows -= 1*(Rows_Num-1);
+		}else if(KeyBoard_Cur == 4*WFONTS+1){ // Virtual KeyBoard END.
+			Editor_End=1;
+		}else if(KeyBoard_Cur == WFONTS-1){ // Virtual KeyBoard INSERT.
+			Editor_Insert = !Editor_Insert;
+		}else if(KeyBoard_Cur == 2*WFONTS-1){ // Virtual KeyBoard Return Mode CR/LF, LF, CR.
+			if((Editor_RetMode++)>=4)
+				Editor_RetMode=OTHER;
+		}else if(KeyBoard_Cur == 5*WFONTS-1){ // Virtual KeyBoard RETURN.
+
+			if(		TextMode[Active_Window]==OTHER
+				&&	TextBuffer[Active_Window][Editor_Cur]=='\n'
+				&&	Editor_Cur>0
+				&&	TextBuffer[Active_Window][Editor_Cur-1]=='\r'
+			){
+				Editor_Cur -= 1; //Entry at LF of CRLF must work at CR instead
+			}
+			if(Editor_Insert || TextBuffer[Active_Window][Editor_Cur]=='\0')
+				if(Editor_RetMode==OTHER)
+					ins1=2, ins2=0, ins3=2, ins4=0, ins5=2; //Insert CRLF
+				else
+					ins1=1, ins2=0, ins3=1, ins4=0, ins5=1; //Insert LF/CR
+			else
+				if(		TextMode[Active_Window]==OTHER
+					&&	TextBuffer[Active_Window][Editor_Cur]=='\r'
+					&&	TextBuffer[Active_Window][Editor_Cur+1]=='\n'
+				){ //OWrite Return at CRLF
+					if(Editor_RetMode==OTHER)
+						ins1=0, ins2=0, ins3=2, ins4=2, ins5=2; //OWrite CRLF at CRLF
+					else
+						ins1=0, ins2=0, ins3=1, ins4=2, ins5=1; //OWrite LF/CR at CRLF
+				}else{ //OWrite return at normal char
+					if(Editor_RetMode==OTHER)
+						ins1=1, ins2=0, ins3=2, ins4=1, ins5=2; //OWrite CRLF at char
+					else
+						ins1=0, ins2=0, ins3=1, ins4=1, ins5=1; //OWrite LF/CR at char
+				}
+			Operation=2;
+			//ends Virtual KeyBoard RETURN.
+		}else{  // Virtual KeyBoard Any other char + Space + Tabulation.
+			if(		TextMode[Active_Window]==OTHER
+				&&	TextBuffer[Active_Window][Editor_Cur]=='\n'
+				&&	Editor_Cur>0
+				&&	TextBuffer[Active_Window][Editor_Cur-1]=='\r'
+			){
+				Editor_Cur -= 1; //Entry at LF of CRLF must work at CR instead
+			}
+			if(Editor_Insert || TextBuffer[Active_Window][Editor_Cur]=='\0'){
+				ins1=1, ins2=0, ins3=1, ins4=0, ins5=1; //Insert char normally
+			}else{
+				if(TextMode[Active_Window]==OTHER
+					&&	TextBuffer[Active_Window][Editor_Cur]=='\r'
+					&&	TextBuffer[Active_Window][Editor_Cur+1]=='\n'
+				){ //OWrite char at CRLF
+					ins1=0, ins2= 0, ins3=1, ins4= 2, ins5= 1; //OWrite at CR of CRLF
+				}else{ //OWrite return at normal char
+					ins1=0, ins2= 0, ins3=1, ins4= 1, ins5= 1; //OWrite normal char
+				}
+			}
+			if(KeyBoard_Cur == 3*WFONTS-1) // Tabulation.
+				Operation=3;
+			else if(KeyBoard_Cur == 4*WFONTS-1) // Space.
+				Operation=4;
+			else // Any other char.
+				Operation=5;
+		}
+		//ends Virtual KeyBoard Select.
+	}
+
+	if(Operation>0){ // Perform Add Char / Paste. Can Be Simplify???
+		TextBuffer[TMP] = malloc(TextSize[Active_Window]+ins1+256); // 256 To Avoid Crash 256???
+		strcpy(TextBuffer[TMP], TextBuffer[Active_Window]);
+		//memset(TextBuffer[Active_Window], 0, TextSize[Active_Window]+256); // 256 To Avoid Crash 256???		free(TextBuffer[Active_Window]);
+		TextBuffer[Active_Window] = malloc(TextSize[Active_Window]+ins1+256); // 256 To Avoid Crash 256???
+		strcpy(TextBuffer[Active_Window], TextBuffer[TMP]);
+	}
+
+	switch(Operation){
+	case 0:
+		break;
+	case -1:// Perform Del Char / Cut. Can Be Simplify???
+		TextBuffer[TMP] = malloc(TextSize[Active_Window]+256); // 256 To Avoid Crash 256???
+		strcpy(TextBuffer[TMP], TextBuffer[Active_Window]);
+		TextBuffer[Active_Window][Editor_Cur+del1]='\0';
+		strcat(TextBuffer[Active_Window], TextBuffer[TMP]+(Editor_Cur+del2));
+		strcpy(TextBuffer[TMP], TextBuffer[Active_Window]);
+		//memset(TextBuffer[Active_Window], 0, TextSize[Active_Window]+256); // 256 To Avoid Crash 256???
+		free(TextBuffer[Active_Window]);
+		TextBuffer[Active_Window] = malloc(TextSize[Active_Window]+del3+256); // 256 To Avoid Crash 256???
+		strcpy(TextBuffer[Active_Window], TextBuffer[TMP]);
+		//memset(TextBuffer[TMP], 0, TextSize[Active_Window]+256); // 256 To Avoid Crash 256???
+		free(TextBuffer[TMP]);
+		Editor_Cur+=del3, TextSize[Active_Window]+=del4;
+		t=0;
+		break;
+	case 1:	// Paste.
+		for(i=0; i<ins2; i++)
+			TextBuffer[Active_Window][i+Editor_Cur]=TextBuffer[EDIT][i];
+		goto common;
+	case 2:	// Return.
+		if(Editor_RetMode==OTHER){
+			TextBuffer[Active_Window][Editor_Cur+ins2]='\r';
+			TextBuffer[Active_Window][Editor_Cur+ins2+1]='\n';
+		}else if(Editor_RetMode==UNIX){
+			TextBuffer[Active_Window][Editor_Cur+ins2]='\r';
+		}else if(Editor_RetMode==MAC){
+			TextBuffer[Active_Window][Editor_Cur+ins2]='\n';
+		}
+		goto common;
+	case 3:	// Tabulation.
+		TextBuffer[Active_Window][Editor_Cur+ins2]='\t';
+		goto common;
+	case 4: // Space.
+		TextBuffer[Active_Window][Editor_Cur+ins2]=' ';
+		goto common;
+	case 5:	// Any Char.
+		TextBuffer[Active_Window][Editor_Cur+ins2]=KEY[KeyBoard_Cur];
+		goto common;
+	common:
+		TextBuffer[Active_Window][Editor_Cur+ins3]='\0';
+		strcat(TextBuffer[Active_Window], TextBuffer[TMP]+(Editor_Cur+ins4));
+		//memset(TextBuffer[TMP], 0, TextSize[Active_Window]+256); // 256 To Avoid Crash 256???
+		free(TextBuffer[TMP]);
+		Editor_Cur+=ins5, TextSize[Active_Window]+=ins1;
+		t=0;
+		break;
+	}
+}
+//------------------------------
+//endfunc Virt_KeyBoard_Entry
+//--------------------------------------------------------------
+int KeyBoard_Entry(void)
+{
+	int i, ret=0, Operation;
+	unsigned char KeyPress;
+
+	Operation=0;
+
+	if(PS2KbdRead(&KeyPress)) { //KeyBoard Response Section.
+
+		ret=1;  // Equal To event |= pad command.
+
+		if(KeyPress == PS2KBD_ESCAPE_KEY) {
+			PS2KbdRead(&KeyPress);
+			if(KeyPress)
+				t=0;
+			if(KeyPress == 0x29){ // Key Right.
+				if(Editor_Cur<Editor_nChar && TextBuffer[Active_Window][Editor_Cur]!='\0')
+					Editor_Cur++;
+			}else if(KeyPress == 0x2A){ // Key Left.
+				if(Editor_Cur>0)
+					Editor_Cur--;
+			}else if(KeyPress == 0x2C){ // Key Up.
+				if(Editor_Cur>0)
+					Editor_PushRows++;
+			}else if(KeyPress == 0x2B){ // Key Down.
+				if(Editor_Cur<Editor_nChar && TextBuffer[Active_Window][Editor_Cur]!='\0')
+					Editor_PushRows--;
+			}else if(KeyPress == 0x24) // Key Home.
+				Editor_Home=1;
+			else if(KeyPress == 0x27) // Key End.
+				Editor_End=1;
+			else if(KeyPress == 0x25){ // Key PgUp.
+				if(Editor_Cur>0)
+					Editor_PushRows += 1*(Rows_Num-1);
+			}else if(KeyPress == 0x28){ // Key PgDn.
+				if(Editor_Cur<Editor_nChar && TextBuffer[Active_Window][Editor_Cur]!='\0')
+					Editor_PushRows -= 1*(Rows_Num-1);
+			}else if(KeyPress == 0x23) // Key Insert.
+				Editor_Insert = !Editor_Insert;
+			else if(KeyPress == 0x26){ // Key Delete.
+				if(Editor_Cur<Editor_nChar){
+					if(		TextMode[Active_Window]==OTHER
+						&&	TextBuffer[Active_Window][Editor_Cur]=='\n'
+						&&	Editor_Cur>0
+						&&	TextBuffer[Active_Window][Editor_Cur-1]=='\r'
+					){
+						Editor_Cur -= 1; //Delete at LF of CRLF must work at CR instead
+					}
+					if(Mark[MARK_ON]){
+						Mark[MARK_OUT]=Editor_Cur;
+						if(Mark[MARK_OUT]<Mark[MARK_IN]){
+							Mark[MARK_TMP]=Mark[MARK_IN];
+							Mark[MARK_IN]=Mark[MARK_OUT];
+							Mark[MARK_OUT]=Mark[MARK_TMP];
+						}else if(Mark[MARK_IN]==Mark[MARK_OUT])
+							goto abort;
+						Mark[MARK_SIZE]=Mark[MARK_OUT]-Mark[MARK_IN];
+						del1= -Mark[MARK_SIZE], del2=0, del3= -Mark[MARK_SIZE], del4= -Mark[MARK_SIZE];
+						Mark[MARK_ON]=0;
+					}else if(TextMode[Active_Window]==OTHER
+						&&	TextBuffer[Active_Window][Editor_Cur]=='\r'
+						&&	TextBuffer[Active_Window][Editor_Cur+1]=='\n'
+					){ //Delete at CRLF
+						del1=0, del2=2, del3=0, del4=-2; //delete CRLF
+					}else if(TextMode[Active_Window]==OTHER && TextBuffer[Active_Window][Editor_Cur]=='\n'){
+						del1=-1, del2=1, del3=-1, del4=-2;
+					}else{
+						del1=0, del2=1, del3=0, del4=-1; //delete single char
+					}
+					Operation=-1;
+				}
+			}else if(KeyPress == 0x01){ // Key F1 MENU.
+				ret=2;
+			}else if(KeyPress == 0x1B){ // Key Escape EXIT Editor.
+				ret=3;
+			}
+		}else{
+			if(KeyPress == 0x12){ // Key Ctrl+r Return Mode CR/LF Or LF Or CR.
+				if((Editor_RetMode++)>=4)
+					Editor_RetMode=OTHER;
+			}else if(KeyPress == 0x02){ // Key Ctrl+b MARK.
+				Mark[MARK_ON]=!Mark[MARK_ON];
+				if(Mark[MARK_ON]){
+					if(		TextMode[Active_Window]==OTHER
+						&&	TextBuffer[Active_Window][Editor_Cur]=='\n'
+						&&	Editor_Cur>0
+						&&	TextBuffer[Active_Window][Editor_Cur-1]=='\r'
+					){
+						Editor_Cur -= 1; //Marking at LF of CRLF must start at CR instead
+					}
+					if(Mark[MARK_COPY] || Mark[MARK_CUT])
+						free(TextBuffer[EDIT]);
+					Mark[MARK_ON]=1, Mark[MARK_COPY]=0, Mark[MARK_CUT]=0,
+					Mark[MARK_IN]=0, Mark[MARK_OUT]=0, Mark[MARK_TMP]=0,
+					Mark[MARK_SIZE]=0, Mark[MARK_PRINT]=0, Mark[MARK_COLOR]=0;
+					Mark[MARK_IN]=Mark[MARK_OUT]=Editor_Cur;
+				}
+				Mark[MARK_START]=1;
+				//ends Key Ctrl+b MARK.
+			}else if(KeyPress == 0x03){ // Key Ctrl+c COPY.
+				if(		TextMode[Active_Window]==OTHER
+					&&	TextBuffer[Active_Window][Editor_Cur]=='\n'
+					&&	Editor_Cur>0
+					&&	TextBuffer[Active_Window][Editor_Cur-1]=='\r'
+				){
+					Editor_Cur += 1; //Mark end at LF of CRLF must include LF as well
+				}
+				if(Mark[MARK_ON]){
+					Mark[MARK_OUT]=Editor_Cur;
+					if(Mark[MARK_OUT]<Mark[MARK_IN]){
+						Mark[MARK_TMP]=Mark[MARK_IN];
+						Mark[MARK_IN]=Mark[MARK_OUT];
+						Mark[MARK_OUT]=Mark[MARK_TMP];
+					}else if(Mark[MARK_IN]==Mark[MARK_OUT])
+						goto abort;
+					if(Mark[MARK_COPY] || Mark[MARK_CUT])
+						free(TextBuffer[EDIT]);
+					Mark[MARK_SIZE]=Mark[MARK_OUT]-Mark[MARK_IN];
+					TextBuffer[EDIT] = malloc(Mark[MARK_SIZE]+256); // 256 To Avoid Crash 256???
+					for(i=0; i<Mark[MARK_SIZE]; i++)
+						TextBuffer[EDIT][i]=TextBuffer[Active_Window][i+Mark[MARK_IN]];
+					Mark[MARK_COPY]=1, Mark[MARK_CUT]=0, Mark[MARK_ON]=0, Mark[MARK_TMP]=0;
+				}
+				//ends Key Ctrl+c COPY.
+			}else if(KeyPress == 0x18){ // Key Ctrl+x CUT.
+				if(Mark[MARK_ON]){
+					if(		TextMode[Active_Window]==OTHER
+						&&	TextBuffer[Active_Window][Editor_Cur]=='\n'
+						&&	Editor_Cur>0
+						&&	TextBuffer[Active_Window][Editor_Cur-1]=='\r'
+					){
+						Editor_Cur += 1; //Mark end at LF of CRLF must include LF as well
+					}
+					Mark[MARK_OUT]=Editor_Cur;
+					if(Mark[MARK_OUT]<Mark[MARK_IN]){
+						Mark[MARK_TMP]=Mark[MARK_IN];
+						Mark[MARK_IN]=Mark[MARK_OUT];
+						Mark[MARK_OUT]=Mark[MARK_TMP];
+					}else if(Mark[MARK_IN]==Mark[MARK_OUT])
+						goto abort;
+					if(Mark[MARK_COPY] || Mark[MARK_CUT])
+						free(TextBuffer[EDIT]);
+					Mark[MARK_SIZE]=Mark[MARK_OUT]-Mark[MARK_IN];
+					TextBuffer[EDIT] = malloc(Mark[MARK_SIZE]+256); // 256 To Avoid Crash 256???
+					for(i=0; i<Mark[MARK_SIZE]; i++)
+						TextBuffer[EDIT][i]=TextBuffer[Active_Window][i+Mark[MARK_IN]];
+					del1= -Mark[MARK_SIZE], del2=0, del3= -Mark[MARK_SIZE], del4= -Mark[MARK_SIZE];
+					Mark[MARK_CUT]=1, Mark[MARK_COPY]=0, Mark[MARK_ON]=0, Mark[MARK_TMP]=0;
+					Operation=-2;
+				}
+				//ends Key Ctrl+x CUT.
+			}else if(KeyPress == 0x16){ // Key Ctrl+v PASTE.
+				if( Mark[MARK_COPY] || Mark[MARK_CUT]){
+					if(TextMode[Active_Window]==OTHER && TextBuffer[Active_Window][Editor_Cur]=='\n'){
+						Editor_Cur-=1;
+						Mark[MARK_SIZE]-=1;
+					}
+					ins1=Mark[MARK_SIZE], ins2=Mark[MARK_SIZE], ins3=Mark[MARK_SIZE], ins4=0, ins5=Mark[MARK_SIZE];
+					Operation=1;
+				}
+				//ends Key Ctrl+v PASTE.
+			}else if(KeyPress == 0x07){ // Key BackSpace.
+				if(Editor_Cur>0){
+					if(		TextMode[Active_Window]==OTHER
+						&&	TextBuffer[Active_Window][Editor_Cur]=='\n'
+						&&	TextBuffer[Active_Window][Editor_Cur-1]=='\r'
+					){
+						Editor_Cur += 1; //Backspace at LF of CRLF must work after LF
+					}
+					if(Mark[MARK_ON]){
+						Mark[MARK_OUT]=Editor_Cur;
+						if(Mark[MARK_OUT]<Mark[MARK_IN]){
+							Mark[MARK_TMP]=Mark[MARK_IN];
+							Mark[MARK_IN]=Mark[MARK_OUT];
+							Mark[MARK_OUT]=Mark[MARK_TMP];
+						}else if(Mark[MARK_IN]==Mark[MARK_OUT])
+							goto abort;
+						Mark[MARK_SIZE]=Mark[MARK_OUT]-Mark[MARK_IN];
+						del1= -Mark[MARK_SIZE], del2=0, del3= -Mark[MARK_SIZE], del4= -Mark[MARK_SIZE];
+						Mark[MARK_ON]=0;
+					}else if(TextMode[Active_Window]==OTHER
+						&&	TextBuffer[Active_Window][Editor_Cur-1]=='\n'
+						&&	Editor_Cur>1
+						&&	TextBuffer[Active_Window][Editor_Cur-2]=='\r'){
+						del1=-2, del2=0, del3=-2, del4=-2; //Backspace CRLF
+					}else{
+						del1=-1, del2=0, del3=-1, del4=-1; //Backspace single char
+					}
+					Operation=-3;
+				}
+				//ends Key BackSpace.
+			}else if(KeyPress == 0x0A){ // Key Return.
+
+				if(		TextMode[Active_Window]==OTHER
+					&&	TextBuffer[Active_Window][Editor_Cur]=='\n'
+					&&	Editor_Cur>0
+					&&	TextBuffer[Active_Window][Editor_Cur-1]=='\r'
+				){
+					Editor_Cur -= 1; //Entry at LF of CRLF must work at CR instead
+				}
+				if(Editor_Insert || TextBuffer[Active_Window][Editor_Cur]=='\0')
+					if(Editor_RetMode==OTHER)
+						ins1=2, ins2=0, ins3=2, ins4=0, ins5=2; //Insert CRLF
+					else
+						ins1=1, ins2=0, ins3=1, ins4=0, ins5=1; //Insert LF/CR
+				else
+					if(		TextMode[Active_Window]==OTHER
+						&&	TextBuffer[Active_Window][Editor_Cur]=='\r'
+						&&	TextBuffer[Active_Window][Editor_Cur+1]=='\n'
+					){ //OWrite Return at CRLF
+						if(Editor_RetMode==OTHER)
+							ins1=0, ins2=0, ins3=2, ins4=2, ins5=2; //OWrite CRLF at CRLF
+						else
+							ins1=0, ins2=0, ins3=1, ins4=2, ins5=1; //OWrite LF/CR at CRLF
+					}else{ //OWrite return at normal char
+						if(Editor_RetMode==OTHER)
+							ins1=1, ins2=0, ins3=2, ins4=1, ins5=2; //OWrite CRLF at char
+						else
+							ins1=0, ins2=0, ins3=1, ins4=1, ins5=1; //OWrite LF/CR at char
+					}
+				Operation=2;
+				//ends Key Return.
+			}else{ // All Other Keys.
+				if(		TextMode[Active_Window]==OTHER
+					&&	TextBuffer[Active_Window][Editor_Cur]=='\n'
+					&&	Editor_Cur>0
+					&&	TextBuffer[Active_Window][Editor_Cur-1]=='\r'
+				){
+					Editor_Cur -= 1; //Entry at LF of CRLF must work at CR instead
+				}
+				if(Editor_Insert || TextBuffer[Active_Window][Editor_Cur]=='\0'){
+					ins1=1, ins2=0, ins3=1, ins4=0, ins5=1; //Insert char normally
+				}else{
+					if(TextMode[Active_Window]==OTHER
+						&&	TextBuffer[Active_Window][Editor_Cur]=='\r'
+						&&	TextBuffer[Active_Window][Editor_Cur+1]=='\n'
+					){ //OWrite char at CRLF
+						ins1=0, ins2= 0, ins3=1, ins4= 2, ins5= 1; //OWrite at CR of CRLF
+					}else{ //OWrite return at normal char
+						ins1=0, ins2= 0, ins3=1, ins4= 1, ins5= 1; //OWrite normal char
+					}
+				}
+				Operation=3;
+			}
+		}
+
+		if(Operation>0){ // Perform Add Char / Paste. Can Be Simplify???
+			TextBuffer[TMP] = malloc(TextSize[Active_Window]+ins1+256); // 256 To Avoid Crash 256???
+			strcpy(TextBuffer[TMP], TextBuffer[Active_Window]);
+			//memset(TextBuffer[Active_Window], 0, TextSize[Active_Window]+256); // 256 To Avoid Crash 256???		free(TextBuffer[Active_Window]);
+			TextBuffer[Active_Window] = malloc(TextSize[Active_Window]+ins1+256); // 256 To Avoid Crash 256???
+			strcpy(TextBuffer[Active_Window], TextBuffer[TMP]);
+		}
+
+		switch(Operation){
+		case 0:
+			break;
+		case -1:// Perform Del Char / Cut. Can Be Simplify???
+		case -2:
+		case -3:
+			TextBuffer[TMP] = malloc(TextSize[Active_Window]+256); // 256 To Avoid Crash 256???
+			strcpy(TextBuffer[TMP], TextBuffer[Active_Window]);
+			TextBuffer[Active_Window][Editor_Cur+del1]='\0';
+			strcat(TextBuffer[Active_Window], TextBuffer[TMP]+(Editor_Cur+del2));
+			strcpy(TextBuffer[TMP], TextBuffer[Active_Window]);
+			//memset(TextBuffer[Active_Window], 0, TextSize[Active_Window]+256); // 256 To Avoid Crash 256???
+			free(TextBuffer[Active_Window]);
+			TextBuffer[Active_Window] = malloc(TextSize[Active_Window]+del3+256); // 256 To Avoid Crash 256???
+			strcpy(TextBuffer[Active_Window], TextBuffer[TMP]);
+			//memset(TextBuffer[TMP], 0, TextSize[Active_Window]+256); // 256 To Avoid Crash 256???
+			free(TextBuffer[TMP]);
+			Editor_Cur+=del3, TextSize[Active_Window]+=del4;
+			t=0;
+			break;
+		case 1:	// Paste.
+			for(i=0; i<ins2; i++)
+				TextBuffer[Active_Window][i+Editor_Cur]=TextBuffer[EDIT][i];
+			goto common;
+		case 2:	// Return.
+			if(Editor_RetMode==OTHER){
+				TextBuffer[Active_Window][Editor_Cur+ins2]='\r';
+				TextBuffer[Active_Window][Editor_Cur+ins2+1]='\n';
+			}else if(Editor_RetMode==UNIX){
+				TextBuffer[Active_Window][Editor_Cur+ins2]='\r';
+			}else if(Editor_RetMode==MAC){
+				TextBuffer[Active_Window][Editor_Cur+ins2]='\n';
+			}
+			goto common;
+		case 3:	// Normal characters
+			TextBuffer[Active_Window][Editor_Cur+ins2]=KeyPress;
+		common:
+			TextBuffer[Active_Window][Editor_Cur+ins3]='\0';
+			strcat(TextBuffer[Active_Window], TextBuffer[TMP]+(Editor_Cur+ins4));
+			//memset(TextBuffer[TMP], 0, TextSize[Active_Window]+256); // 256 To Avoid Crash 256???
+			free(TextBuffer[TMP]);
+			Editor_Cur+=ins5, TextSize[Active_Window]+=ins1;
+			t=0;
+			break;
+		}
+
+abort:
+		KeyPress = '\0';
+	} //ends if(PS2KbdRead(&KeyPress)).
+	return ret;
+}
+//------------------------------
+//endfunc KeyBoard_Entry
+//--------------------------------------------------------------
+void Editor_Rules(void)
+{
+	int i;
+
+	Editor_nChar=TextSize[Active_Window]+1;
+
+	Top_Height=0, Top_Width =0;
+	Editor_nRowsNum=0, Editor_nCharRows=1, Editor_nRowsTop=1;
+	for(i=0; i<Editor_nChar; i++) // Rows Number, Width, Top, Calucations.
+	{
+		if((TextMode[Active_Window]==UNIX && TextBuffer[Active_Window][i]=='\r') || // Text Mode UNIX End Line.
+		   TextBuffer[Active_Window][i]=='\n' || // Text Mode MAC Or OTHER End Line.
+		   Editor_nCharRows>=Rows_Width ||       // Line Width > Screen Width.
+		   TextBuffer[Active_Window][i]=='\0'){  // End Text.
+			if(i<Editor_Cur){
+				if((Editor_nRowsTop += 1)>Rows_Num){
+					Top_Width  += Editor_nRowsWidth[Top_Height];
+					Top_Height += 1;
+				}
+			}
+			Editor_nRowsWidth[Editor_nRowsNum]=Editor_nCharRows;
+			Editor_nRowsNum++;
+			Editor_nCharRows=0;
+		}
+		if(TextBuffer[Active_Window][i]=='\0') // End Text Stop Calculations.
+			break;
+		Editor_nCharRows++;
+	}
+
+	if(Editor_Home){
+		Tmp_Cur=0;
+		for(i=0; i<Editor_nRowsNum; i++) // Home Rules.
+		{
+			if((Tmp_Cur += Editor_nRowsWidth[i])>=Editor_Cur+1)
+				break;
+		}
+		Tmp_Cur -= (Editor_nRowsWidth[i]-1);
+		Editor_Cur = Tmp_Cur-1;
+		Editor_Home=0;
+	}
+
+	if(Editor_End){
+		Tmp_Cur=0;
+		for(i=0; i<Editor_nRowsNum; i++) // End Rules.
+		{
+			if((Tmp_Cur += Editor_nRowsWidth[i])>=Editor_Cur+1)
+				break;
+		}
+		Editor_Cur = Tmp_Cur-1;
+		Editor_End=0;
+	}
+
+	if(Editor_PushRows<0){
+		Tmp_Cur=0;
+		for(i=0; i<Editor_nRowsNum; i++) // Line / Page Up Rules.
+		{
+			if((Tmp_Cur += Editor_nRowsWidth[i])>=Editor_Cur+1)
+				break;
+		}
+		Tmp_Cur -= (Editor_nRowsWidth[i]-1);
+		if(Editor_nRowsWidth[i+1]<=((Editor_Cur+1)-(Tmp_Cur-1)))
+			Editor_Cur = Tmp_Cur+Editor_nRowsWidth[i]+Editor_nRowsWidth[i+1]-1-1;
+		else
+			Editor_Cur = Tmp_Cur+Editor_nRowsWidth[i]+((Editor_Cur+1)-Tmp_Cur)-1;
+
+		if(Editor_PushRows++ >= 0)
+			Editor_PushRows=0;
+		
+		if(Editor_Cur+1>=Editor_nChar && TextBuffer[Active_Window][Editor_Cur]!='\0'){
+			Editor_Cur=Editor_nChar-1;
+			Editor_PushRows=0;
+		}
+	}
+
+	if(Editor_PushRows>0){
+		Tmp_Cur=0;
+		for(i=0; i<Editor_nRowsNum; i++) // Line / Page Down Rules.
+		{
+			if((Tmp_Cur += Editor_nRowsWidth[i])>=Editor_Cur+1)
+				break;
+		}
+		Tmp_Cur -= (Editor_nRowsWidth[i]-1);
+
+		if(Editor_nRowsWidth[i-1]<=((Editor_Cur+1)-(Tmp_Cur-1)))
+			Editor_Cur = Tmp_Cur-1-1;
+		else
+			Editor_Cur = Tmp_Cur-Editor_nRowsWidth[i-1]+((Editor_Cur+1)-Tmp_Cur)-1;
+
+		if(Editor_PushRows-- <= 0)
+			Editor_PushRows=0;
+
+		if(Editor_Cur<=0){
+			Editor_Cur=0;
+			Editor_PushRows=0;
+		}
+	}
+
+	if(Editor_Cur >= Editor_nChar) // Max Char Number Rules.
+		Editor_Cur=Editor_nChar-1;
+
+	if(Editor_Cur < 0) // Min Char Number Rules.
+		Editor_Cur=0;
+
+	if(Mark[MARK_ON]){ // Mark Rules.
+		Mark[MARK_SIZE]=Editor_Cur-Mark[MARK_IN];
+		if(Mark[MARK_SIZE]>0){
+			Mark[MARK_PRINT]=Mark[MARK_SIZE];
+			if(Mark[MARK_IN]<Top_Width)
+				Mark[MARK_PRINT]=Editor_Cur-Top_Width;
+		}else if(Mark[MARK_SIZE]<0)
+			Mark[MARK_PRINT]=1;
+		else
+			Mark[MARK_PRINT]=0;
+	}
+
+}
+//--------------------------------------------------------------
+int Windows_Selector(void)
+{
+	u64 color;
+	int x, y, i, Window_Sel=Active_Window;
+	int event, post_event=0;
+
+	int Window_ch_w = 36;           //Total characters in longest Window Name.
+	int Window_ch_h = 10;   //Total number of Window Menu lines.
+	int wSprite_Y1 = 200;           //Top edge of sprite.
+	int wSprite_X2 = SCREEN_WIDTH-35;   //Right edge of sprite.
+	int wSprite_X1 = wSprite_X2-(Window_ch_w+3)*FONT_WIDTH-3;  //Left edge of sprite.
+	int wSprite_Y2 = wSprite_Y1+(Window_ch_h+1)*FONT_HEIGHT+3; //Bottom edge of sprite.
+	
+	char tmp[64];
+
+	event = 1;  //event = initial entry.
+	while(1){
+		//Pad response section.
+		waitPadReady(0, 0);
+		if(readpad()){
+			if(new_pad & PAD_UP){
+				event |= 2;  //event |= valid pad command.
+				if((Window_Sel--)<=0)
+					Window_Sel=9;
+			}else if(new_pad & PAD_DOWN){
+				event |= 2;  //event |= valid pad command.
+				if((Window_Sel++)>=9)
+					Window_Sel=0;
+			}else if((new_pad & PAD_TRIANGLE)
+						|| (!swapKeys && new_pad & PAD_CROSS)
+			      || (swapKeys && new_pad & PAD_CIRCLE) ){
+				return -1;
+			}else if((swapKeys && new_pad & PAD_CROSS)
+			      || (!swapKeys && new_pad & PAD_CIRCLE) ){
+				event |= 2;  //event |= valid pad command.
+				break;
+			}
+		}
+
+		if(event||post_event){ //NB: We need to update two frame buffers per event.
+
+			//Display section.
+			drawPopSprite(setting->color[0],
+				wSprite_X1, wSprite_Y1,
+				wSprite_X2, wSprite_Y2);
+			drawFrame(wSprite_X1, wSprite_Y1, wSprite_X2, wSprite_Y2, setting->color[1]);
+
+			for(i=0,y=wSprite_Y1+FONT_HEIGHT/2; i<10; i++){
+				if(Window_Sel==i)
+					color = setting->color[2];
+				else
+					color = setting->color[3];
+
+				if(!Window[i][OPENED])
+					printXY(LNG(Free_Window), wSprite_X1+2*FONT_WIDTH, y, color, TRUE, 0);
+				else if(Window[i][CREATED])
+					printXY(LNG(Window_Not_Yet_Saved), wSprite_X1+2*FONT_WIDTH, y, color, TRUE, 0);
+				else if(Window[i][OPENED])				
+					printXY(Path[i], wSprite_X1+2*FONT_WIDTH, y, color, TRUE, 0);
+
+				y+=FONT_HEIGHT;
+			}
+
+			if(Window_Sel<=10)
+				drawChar(LEFT_CUR, wSprite_X1+FONT_WIDTH, wSprite_Y1+(FONT_HEIGHT/2+Window_Sel*FONT_HEIGHT), setting->color[3]);
+
+			//Tooltip section.
+			x = SCREEN_MARGIN;
+			y = Menu_tooltip_y;
+			drawSprite(setting->color[0],
+				0, y-1,
+				SCREEN_WIDTH, y+16);
+			if (swapKeys)
+				sprintf(tmp, "ÿ1:%s ÿ0:%s ÿ3:%s", LNG(OK), LNG(Cancel), LNG(Back));
+			else
+				sprintf(tmp, "ÿ0:%s ÿ1:%s ÿ3:%s", LNG(OK), LNG(Cancel), LNG(Back));
+			printXY(tmp, x, y, setting->color[2], TRUE, 0);
+		}//ends if(event||post_event).
+		drawScr();
+		post_event = event;
+		event = 0;
+	}//ends while.
+	return Window_Sel;
+}//ends Window_Selector.
+//--------------------------------------------------------------
+void Init(void)
+{
+	int i;
+
+	for(i=0; i<MAX_ENTRY; i++)
+		Editor_nRowsWidth[i]=0;
+
+	Editor_Cur=0, Tmp_Cur=0,
+	Editor_nChar=0, Editor_nRowsNum=0,
+	Editor_nCharRows=0, Editor_nRowsTop=0,
+	Editor_PushRows=0, Editor_TextEnd=0;
+
+	Top_Width=0, Top_Height=0;
+
+	Rows_Width  = (SCREEN_WIDTH-SCREEN_MARGIN-LINE_THICKNESS-26-Menu_start_x)/FONT_WIDTH;
+	Rows_Num = (Menu_end_y-Menu_start_y)/FONT_HEIGHT;
+
+	KeyBoard_Cur=2, KeyBoard_Active=0,
+	Editor_Insert=1, Editor_RetMode=TextMode[Active_Window];
+	Editor_Home=0, Editor_End=0;
+
+	del1=0, del2=0, del3=0, del4=0;
+	ins1=0, ins2=0, ins3=0, ins4=0, ins5=0;
+
+	if(Mark[MARK_ON]){
+		Mark[MARK_ON]=0, Mark[MARK_IN]=0,
+		Mark[MARK_OUT]=0, Mark[MARK_TMP]=0,
+		Mark[MARK_PRINT]=0, Mark[MARK_COLOR]=0;
+	}
+
+}
+//--------------------------------------------------------------
+int New(int Win)
+{
+	int ret=0;
+
+	TextSize[Win]=1;
+	
+	if( TextSize[Win] ){
+		if( ( TextBuffer[Win] = malloc( TextSize[Win]+256 ) ) > 0 ){
+			TextBuffer[Win][0]='\0';
+			TextMode[Win]=OTHER;
+			Window[Win][CREATED]=1, Window[Win][OPENED]=1, Window[Win][SAVED]=0;
+			Init();
+			ret=1;
+		}
+	}
+
+	if(ret){
+		drawMsg(LNG(File_Created));
+	}else{
+		drawMsg(LNG(Failed_Creating_File));
+	}
+
+	WaitTime=Timer();
+	while(Timer()<WaitTime+1500); // print operation result during 1.5 sec.
+
+	return ret;
+}
+//--------------------------------------------------------------
+int Open(int Win)
+{
+	int fd, i, ret=0;
+	char filePath[MAX_PATH];
+
+	getFilePath(Path[Win], TEXT_CNF); // No Filtering, Be Careful.
+
+	if(Path[Win][0]=='\0')
+		goto abort;
+
+	genFixPath(Path[Win], filePath);
+	fd = genOpen( filePath, O_RDONLY );
+ 
+	if( fd >= 0 ) {
+		TextSize[Win] = genLseek ( fd, 0, SEEK_END );
+		genLseek ( fd, 0, SEEK_SET );
+
+		if( TextSize[Win] && TextSize[Win] <= 512*1024 ){ // Limit Text Size To 512Kb???
+			if( ( TextBuffer[Win] = malloc( TextSize[Win]+256 ) ) > 0 ){ // 256 To Avoid Crash 256???
+				memset(TextBuffer[Win], 0, TextSize[Win]+256); // 256 To Avoid Crash 256???
+				genRead( fd, TextBuffer[Win], TextSize[Win] );
+
+				for(i=0; i<TextSize[Win]; i++){ // Scan For Text Mode.
+					if(TextBuffer[Win][i-1]!='\r' && TextBuffer[Win][i]=='\n'){
+						// Mode MAC Only LF At Line End.
+						TextMode[Win]=MAC;
+						break;
+					}else if(TextBuffer[Win][i]=='\r' && TextBuffer[Win][i+1]=='\n'){
+						// Mode OTHER CR/LF At Line End.
+						TextMode[Win]=OTHER;
+						break;
+					}else if(TextBuffer[Win][i]=='\r' && TextBuffer[Win][i+1]!='\n'){
+						// Mode UNIX Only CR At Line End.
+						TextMode[Win]=UNIX;
+						break;
+					}
+				}
+
+				Window[Win][OPENED]=1, Window[Win][SAVED]=0;
+				Init();
+				ret=1;
+			}
+		}
+	}
+
+	genClose( fd );
+
+	if(ret){
+		drawMsg(LNG(File_Opened));
+	}else{
+abort:
+		TextSize[Win]=0;
+		drawMsg(LNG(Failed_Opening_File));
+	}
+
+	WaitTime=Timer();
+	while(Timer()<WaitTime+1500); // print operation result during 1.5 sec.
+
+	return ret;
+}
+//--------------------------------------------------------------
+void Close(int Win)
+{
+	char msg[MAX_PATH];
+
+	//memset(TextBuffer[Win], 0, TextSize[Win]+256); // 256 To Avoid Crash 256???
+	free(TextBuffer[Win]);
+
+	if(Window[Win][CREATED])
+		strcpy(msg, LNG(File_Not_Yet_Saved_Closed));
+	else
+		sprintf(msg, LNG(File_Closed), Path[Win]);
+
+	Path[Win][0]='\0';
+
+	TextMode[Win]=0, TextSize[Win]=0, Window[Win][CREATED]=0, Window[Win][OPENED]=0, Window[Win][SAVED]=1;
+
+	Init();
+
+	drawMsg(msg);
+
+	WaitTime=Timer();
+	while(Timer()<WaitTime+1500); // print operation result during 1.5 sec.
+}
+//--------------------------------------------------------------
+void Save(int Win)
+{
+	int fd, ret=0;
+
+	char filePath[MAX_PATH];
+
+	if(!strncmp(Path[Win], "cdfs", 4))
+		goto abort;
+	genFixPath(Path[Win], filePath);
+
+	fd = genOpen( filePath, O_CREAT|O_WRONLY|O_TRUNC );
+ 
+	if( fd >= 0 ) {
+		if(TextMode[Win]==OTHER && TextBuffer[Win][TextSize[Win]]=='\n')
+			genWrite(fd, TextBuffer[Win], TextSize[Win]-1);
+		else
+			genWrite(fd, TextBuffer[Win], TextSize[Win]);
+		Window[Win][OPENED]=1, Window[Win][SAVED]=1;
+		ret=1;
+	}
+	
+	genClose( fd );
+	if(!strncmp(filePath, "pfs", 3))
+		unmountParty(filePath[3]-'0');
+
+	if(ret){
+		drawMsg(LNG(File_Saved));
+	}else{
+abort:
+		drawMsg(LNG(Failed_Saving_File));
+	}
+
+	WaitTime=Timer();
+	while(Timer()<WaitTime+1500); // print operation result during 1.5 sec.
+}
+//--------------------------------------------------------------
+void Save_As(int Win)
+{
+	int fd, ret=0;
+	char tmp[MAX_PATH], oldPath[MAX_PATH], filePath[MAX_PATH];
+	char *p;
+
+	tmp[0]='\0', oldPath[0]='\0', filePath[0]='\0';
+
+	if(Path[Win][0]!='\0'){
+		strcpy(oldPath, Path[Win]);
+		Path[Win][0]='\0';
+		p=strrchr(oldPath, '/');
+		if(p)
+			strcpy(tmp, p+1);
+	}
+
+	getFilePath(Path[Win], DIR_CNF);
+	if(Path[Win][0] == '\0')
+		goto abort;
+	if(!strncmp(Path[Win], "cdfs", 4))
+		goto abort;
+
+	drawMsg(LNG(Enter_File_Name));
+
+	if(keyboard(tmp, 36)>0){
+		//strcat(Path[Win], tmp); //This is what we want, but malfunctions for MC!
+		//sprintf(&Path[Win][strlen(Path[Win])], "%s", tmp); //This always works
+		strcpy(&Path[Win][strlen(Path[Win])], tmp); //And this one works too
+		//Note that the strcat call SHOULD have done the same thing, but won't.
+	} else goto abort;
+
+	genFixPath(Path[Win], filePath);
+
+	fd = genOpen( filePath, O_CREAT|O_WRONLY|O_TRUNC );
+ 
+	if( fd >= 0 ) {
+		if(TextMode[Win]==OTHER && TextBuffer[Win][TextSize[Win]]=='\n')
+			genWrite(fd, TextBuffer[Win], TextSize[Win]-1);
+		else
+			genWrite(fd, TextBuffer[Win], TextSize[Win]);
+		Window[Win][CREATED]=0, Window[Win][OPENED]=1, Window[Win][SAVED]=1;
+		ret=1;
+		genClose( fd );
+	}
+
+	if(!strncmp(filePath, "pfs", 3))
+		unmountParty(filePath[3]-'0');
+
+	if(ret){
+		drawMsg(LNG(File_Saved));
+		goto result_delay;
+	}
+
+abort:
+	if(oldPath[0]!='\0')
+		strcpy(Path[Win], oldPath);
+	drawMsg(LNG(Failed_Saving_File));
+
+result_delay:
+	WaitTime=Timer();
+	while(Timer()<WaitTime+1500); // display operation result during 1.5 sec.
+}
+//--------------------------------------------------------------
+void TextEditor(void)
+{
+	char   tmp[MAX_PATH], tmp1[MAX_PATH], tmp2[MAX_PATH];
+	int    ch;
+	int    x, y, y0, y1;
+	int    i=0, j, ret=0;
+	int    tmpLen=0;
+	int    event=1, post_event=0;
+	int    Editor_Start=0;
+	u64 color;
+	const int	KEY_W=350,
+				KEY_H=98,
+				KEY_X=(SCREEN_WIDTH - KEY_W)/2,
+				KEY_Y=(Menu_end_y - KEY_H);
+	int KEY_LEN = strlen(KEY);
+	
+	tmp[0]='\0', tmp1[0]='\0', ch='\0';
+	
+	Active_Window=0, Num_Window=0;
+
+	for(i=0; i<10; i++){
+		Window[i][CREATED]=0;
+		Window[i][OPENED]=0;
+		Window[i][SAVED]=1;
+		TextMode[i]=0;
+		TextSize[i]=0;
+		Path[i][0]='\0';
+	}
+
+	for(i=0; i<NUM_MARK; i++)
+		Mark[i]=0;
+
+	Init();
+	
+	t=0;
+
+	event = 1;  //event = initial entry.
+
+	Rows_Width  = (SCREEN_WIDTH-SCREEN_MARGIN-LINE_THICKNESS-26-Menu_start_x)/FONT_WIDTH;
+	Rows_Num = (Menu_end_y-Menu_start_y)/FONT_HEIGHT;
+
+	x = Menu_start_x;
+	y = Menu_start_y;
+	
+	while(1){
+
+		//Pad response section.
+		waitPadReady(0, 0);
+		if(readpad_no_KB()){
+			if(new_pad){
+				event |= 2;  //event |= pad command.
+			}
+			if(!KeyBoard_Active){ // Pad Response Without KeyBoard.
+				if(new_pad & PAD_UP){ // Text move up.
+					if(Editor_Cur>0)
+						Editor_PushRows++;
+				}else if(new_pad & PAD_DOWN){ // Text move down.
+					if(Editor_Cur<Editor_nChar && TextBuffer[Active_Window][Editor_Cur]!='\0')
+						Editor_PushRows--;
+				}else if(new_pad & PAD_LEFT){ // Text move left.
+					if(Editor_Cur>0)
+						Editor_Cur--;
+				}else if(new_pad & PAD_RIGHT){ // Text move right.
+					if(Editor_Cur<Editor_nChar && TextBuffer[Active_Window][Editor_Cur]!='\0')
+						Editor_Cur++;
+				}else if(new_pad & PAD_L2){ // Text move page up.
+					if(Editor_Cur>0)
+						Editor_PushRows += 1*(Rows_Num-1);
+				}else if(new_pad & PAD_R2){ // Text move page down.
+					if(Editor_Cur<Editor_nChar && TextBuffer[Active_Window][Editor_Cur]!='\0')
+						Editor_PushRows -= 1*(Rows_Num-1);
+				}else if(new_pad & PAD_SELECT && Window[Active_Window][OPENED]){ // Virtual KeyBoard Active Rows_Num -= 7.
+						KeyBoard_Cur=2;
+						Rows_Num -= 6;
+						KeyBoard_Active = 1;
+				}
+			}else{ // Pad Response With Virtual KeyBoard.
+				Virt_KeyBoard_Entry();
+			}
+
+			if(new_pad & PAD_TRIANGLE){ // General Pad Response.
+exit:
+				drawMsg(LNG(Exiting_Editor));
+				for(i=0; i<10; i++){
+					if(!Window[i][SAVED])
+						goto unsave;
+				}
+force:
+				for(i=0; i<10; i++){
+					if(Window[i][OPENED]){
+						Close(i);
+						Path[i][0]='\0';
+					}
+				}
+				if(Mark[MARK_COPY] || Mark[MARK_CUT])
+					free(TextBuffer[EDIT]);
+				Mark[MARK_START]=0, Mark[MARK_ON]=0, Mark[MARK_COPY]=0, Mark[MARK_CUT]=0,
+				Mark[MARK_IN]=0, Mark[MARK_OUT]=0, Mark[MARK_TMP]=0,
+				Mark[MARK_SIZE]=0, Mark[MARK_PRINT]=0, Mark[MARK_COLOR]=0;
+
+				return;
+unsave:
+				if(ynDialog(LNG(Exit_Without_Saving))!=1)
+					goto abort;
+				else
+					goto force;
+			}else if(new_pad & PAD_R1) {
+menu:
+				ret = MenuEditor();
+				if(ret==NEW){
+					Num_Window=0;
+					for(i=0; i<10; i++){
+						if(Window[i][OPENED])
+							Num_Window++;
+					}
+					if(Num_Window<10){
+						for(i=0; i<10; i++){
+							if(!Window[i][OPENED]){
+								Active_Window=i;
+								break;
+							}
+						}
+						ret=New(Active_Window);
+						if(!ret)
+							goto fail;
+						Editor_Cur=0, Editor_PushRows=0;
+					}
+					Num_Window=0;
+					for(i=0; i<10; i++){
+						if(Window[i][OPENED])
+							Num_Window++;
+					}
+				} else if(ret==OPEN){
+					drawMsg(LNG(Select_A_File_For_Editing));
+					drawMsg(LNG(Select_A_File_For_Editing));
+					Num_Window=0;
+					for(i=0; i<10; i++){
+						if(Window[i][OPENED])
+							Num_Window++;
+					}
+					if(Num_Window<10){
+						for(i=0; i<10; i++){
+							if(!Window[i][OPENED]){
+								Active_Window=i;
+								break;
+							}
+						}
+						ret=Open(Active_Window);
+						if(!ret)
+							goto fail;
+						Editor_Cur=0, Editor_PushRows=0;
+					}
+					Num_Window=0;
+					for(i=0; i<10; i++){
+						if(Window[i][OPENED])
+							Num_Window++;
+					}
+				} else if(ret==CLOSE){
+					if(!Window[Active_Window][SAVED]){
+						if(ynDialog(LNG(Close_Without_Saving))!=1)
+							goto abort;
+					}
+					Close(Active_Window);
+fail:
+					for(i=9; i>-1; i--){
+						if(Window[i][OPENED]){
+							Active_Window=i;
+							break;
+						}
+					}
+					Num_Window=0;
+					for(i=0; i<10; i++){
+						if(Window[i][OPENED])
+							Num_Window++;
+					}
+abort:
+					i=0; // just for compiler warning.
+				} else if(ret==SAVE){
+					Save(Active_Window);
+				} else if(ret==SAVE_AS){
+					Save_As(Active_Window);
+				} else if(ret==WINDOWS){
+					ret=Windows_Selector();
+					if(ret>=0){
+						Active_Window=ret;
+						Init();
+					}
+				} else if(ret==EXIT){
+					goto exit;
+				}
+			}
+		}//ends pad response section.
+
+		if(!Num_Window)
+			Editor_Start++;
+		if(Editor_Start==4){
+			Editor_Start=0;
+			event |= 2;
+			goto menu;
+		}
+		
+		if(setting->usbkbd_used){	// Kbd response section.
+			
+			ret = KeyBoard_Entry();
+			if(ret)
+				event |=2;
+			if(ret==2)
+				goto menu;
+			else if(ret==3)
+				goto exit;
+
+		}	// end Kbd response section.
+
+		t++;
+
+		if(t & 0x0F) event |= 4;  //repetitive timer event.
+
+		if(event||post_event){ //NB: We need to update two frame buffers per event.
+
+			//Display section.
+			clrScr(setting->color[0]);
+			
+			if(TextSize[Active_Window]==0)
+				goto end;
+
+			drawOpSprite(COL_NORM_BG,
+				SCREEN_MARGIN, Frame_start_y,
+				SCREEN_WIDTH-SCREEN_MARGIN, Frame_end_y);
+
+			if(KeyBoard_Active){ //Display Virtual KeyBoard Section.
+
+				drawPopSprite(setting->color[0],
+					SCREEN_MARGIN, KEY_Y+6,
+					SCREEN_WIDTH-SCREEN_MARGIN, Frame_end_y);
+				drawOpSprite(setting->color[1],
+					SCREEN_MARGIN, KEY_Y+6,
+					SCREEN_WIDTH-SCREEN_MARGIN, KEY_Y+6+LINE_THICKNESS-1);
+				drawOpSprite(setting->color[1],
+					KEY_X-48, KEY_Y+6,
+					KEY_X-48+LINE_THICKNESS-1, Frame_end_y);
+				drawOpSprite(setting->color[1],
+					KEY_X+32, KEY_Y+6,
+					KEY_X+32+LINE_THICKNESS-1, Frame_end_y);
+				drawOpSprite(setting->color[1],
+					KEY_X+KEY_W+32, KEY_Y+6,
+					KEY_X+KEY_W+32+LINE_THICKNESS-1, Frame_end_y);
+
+				if(Mark[MARK_ON])
+					color=setting->color[2];
+				else
+					color=setting->color[3];
+				printXY(LNG(MARK), KEY_X+2+4-120, KEY_Y+12,
+					color, TRUE, ((KEY_X-48)-SCREEN_MARGIN-3*FONT_WIDTH));
+				printXY(LNG(LINE_UP), KEY_X+2+4-120+10*FONT_WIDTH, KEY_Y+12,
+					setting->color[3], TRUE, ((KEY_X+32)-(KEY_X-48)-3*FONT_WIDTH));
+				if(Mark[MARK_COPY])
+					color=setting->color[2];
+				else
+					color=setting->color[3];
+				printXY(LNG(COPY), KEY_X+2+4-120, KEY_Y+12+FONT_HEIGHT+2,
+					color, TRUE, ((KEY_X-48)-SCREEN_MARGIN-3*FONT_WIDTH));
+				printXY(LNG(LINE_DOWN), KEY_X+2+4-120+10*FONT_WIDTH, KEY_Y+12+FONT_HEIGHT+2,
+					setting->color[3], TRUE, ((KEY_X+32)-(KEY_X-48)-3*FONT_WIDTH));
+				if(Mark[MARK_CUT])
+					color=setting->color[2];
+				else
+					color=setting->color[3];
+				printXY(LNG(CUT), KEY_X+2+4-120, KEY_Y+12+FONT_HEIGHT*2+4,
+					color, TRUE, ((KEY_X-48)-SCREEN_MARGIN-3*FONT_WIDTH));
+				printXY(LNG(PAGE_UP), KEY_X+2+4-120+10*FONT_WIDTH, KEY_Y+12+FONT_HEIGHT*2+4,
+					setting->color[3], TRUE, ((KEY_X+32)-(KEY_X-48)-3*FONT_WIDTH));
+				printXY(LNG(PASTE), KEY_X+2+4-120, KEY_Y+12+FONT_HEIGHT*3+6,
+					setting->color[3], TRUE, ((KEY_X-48)-SCREEN_MARGIN-3*FONT_WIDTH));
+				printXY(LNG(PAGE_DOWN), KEY_X+2+4-120+10*FONT_WIDTH, KEY_Y+12+FONT_HEIGHT*3+6,
+					setting->color[3], TRUE, ((KEY_X+32)-(KEY_X-48)-3*FONT_WIDTH));
+				printXY(LNG(HOME), KEY_X+2+4-120, KEY_Y+12+FONT_HEIGHT*4+8,
+					setting->color[3], TRUE, ((KEY_X-48)-SCREEN_MARGIN-3*FONT_WIDTH));
+				printXY(LNG(END), KEY_X+2+4-120+10*FONT_WIDTH, KEY_Y+12+FONT_HEIGHT*4+8,
+					setting->color[3], TRUE, ((KEY_X+32)-(KEY_X-48)-3*FONT_WIDTH));
+
+				if(Editor_Insert)
+					color=setting->color[2];
+				else
+					color=setting->color[3];
+				printXY(LNG(INSERT), KEY_X+2+4+392, KEY_Y+12,
+					color, TRUE, ((SCREEN_WIDTH-SCREEN_MARGIN)-(KEY_X+KEY_W+32)-3*FONT_WIDTH));
+				tmp[0]='\0';
+				if(Editor_RetMode==OTHER)
+					strcpy(tmp, LNG(RET_CRLF));
+				else if(Editor_RetMode==UNIX)
+					strcpy(tmp, LNG(RET_CR));
+				else if(Editor_RetMode==MAC)
+					strcpy(tmp, LNG(RET_LF));
+				printXY(tmp, KEY_X+2+4 + 392, KEY_Y+12+FONT_HEIGHT+2,
+					setting->color[3], TRUE, ((SCREEN_WIDTH-SCREEN_MARGIN)-(KEY_X+KEY_W+32)-3*FONT_WIDTH));
+				printXY(LNG(TAB), KEY_X+2+4 + 392, KEY_Y+12+FONT_HEIGHT*2+4,
+					setting->color[3], TRUE, ((SCREEN_WIDTH-SCREEN_MARGIN)-(KEY_X+KEY_W+32)-3*FONT_WIDTH));
+				printXY(LNG(SPACE), KEY_X+2+4 + 392, KEY_Y+12+FONT_HEIGHT*3+6,
+					setting->color[3], TRUE, ((SCREEN_WIDTH-SCREEN_MARGIN)-(KEY_X+KEY_W+32)-3*FONT_WIDTH));
+				printXY(LNG(KB_RETURN), KEY_X+2+4 + 392, KEY_Y+12+FONT_HEIGHT*4+8,
+					setting->color[3], TRUE, ((SCREEN_WIDTH-SCREEN_MARGIN)-(KEY_X+KEY_W+32)-3*FONT_WIDTH));
+
+				for(i=0; i<KEY_LEN; i++){
+					drawChar(KEY[i],
+						KEY_X+2+4+14 + (i%WFONTS+1)*20 - 32,
+						KEY_Y+12 + (i/WFONTS)*18,
+						setting->color[3]);
+				}
+
+				//Virtual KeyBoard Cursor positioning section.
+				if(!KeyBoard_Cur || KeyBoard_Cur%WFONTS==0)
+					x = KEY_X+2+4 - 128;
+				else if(KeyBoard_Cur==1 || (KeyBoard_Cur-1)%WFONTS==0)
+					x = KEY_X+2+4 - 48;
+				else if((KeyBoard_Cur+1)%WFONTS==0)
+					x = KEY_X+2+4 + 384;
+				else
+					x = KEY_X+2+4+14 + (KeyBoard_Cur%WFONTS+1)*20 - 40;
+				y = KEY_Y+12 + (KeyBoard_Cur/WFONTS)*18;
+				drawChar(LEFT_CUR, x, y, setting->color[2]);
+			
+			} // end Display Virtual KeyBoard Section.
+
+			x = Menu_start_x;
+			y = Menu_start_y;
+
+			Editor_Rules();
+
+			Editor_TextEnd=0, tmpLen=0;
+
+			for(i=Top_Height; i<Rows_Num+Top_Height; i++)
+			{
+				for(j=0; j<Editor_nRowsWidth[i]; j++)
+				{
+					Mark[MARK_COLOR]=0;
+
+					if(Mark[MARK_ON] && Mark[MARK_PRINT]>0){ //Mark Text.
+						if(Mark[MARK_SIZE]>0){
+							if(Top_Width+tmpLen+j == (Editor_Cur-Mark[MARK_PRINT])){
+								drawOpSprite(COL_MARK_BG, x, y-1, x+FONT_WIDTH, y+FONT_HEIGHT-1);
+								Mark[MARK_COLOR]=1;
+								Mark[MARK_PRINT]--;
+							}
+						}else if(Mark[MARK_SIZE]<0){
+							if(Top_Width+tmpLen+j == (Editor_Cur+Mark[MARK_PRINT]-1)){
+								drawOpSprite(COL_MARK_BG, x, y-1, x+FONT_WIDTH, y+FONT_HEIGHT-1);
+								Mark[MARK_COLOR]=1;
+								if((Mark[MARK_PRINT]++) == (-Mark[MARK_SIZE]))
+									Mark[MARK_PRINT]=0;
+							}
+						}
+					} // end mark.
+
+					if(Top_Width+tmpLen+j == Editor_Cur){ //Text Cursor.
+						if(Editor_Insert)
+							color = COL_CUR_INSERT;
+						else
+							color = COL_CUR_OVERWR;
+						if(((event|post_event)&4) && (t & 0x10))
+							drawChar(TEXT_CUR, x-4, y, color);
+					}
+
+					if(TextBuffer[Active_Window][Top_Width+tmpLen+j]=='\n'){ // Line Feed.
+						ch=DN_ARROW;
+						color = COL_LINE_END;
+					}else if (TextBuffer[Active_Window][Top_Width+tmpLen+j]=='\r'){ // Carriage Return.
+						ch=LT_ARROW;
+						color = COL_LINE_END;
+					}else if (TextBuffer[Active_Window][Top_Width+tmpLen+j]=='\t'){ // Tabulation.
+						ch=RT_ARROW;
+						color = COL_TAB;
+					}else if (TextBuffer[Active_Window][Top_Width+tmpLen+j]=='\0'){ // Text End.
+						ch=BR_SPLIT;
+						color = COL_TEXT_END;
+						Editor_TextEnd=1;
+					}else{
+						ch=TextBuffer[Active_Window][Top_Width+tmpLen+j];
+						if(Mark[MARK_ON] && Mark[MARK_COLOR]) //Text Color Black / White If Mark.
+							color = COL_MARK_TEXT;
+						else
+							color = COL_NORM_TEXT;
+					}
+
+					drawChar(ch, x, y, color);
+
+					if(Editor_TextEnd)
+						goto end;
+					
+					x += FONT_WIDTH;
+				}
+
+				tmpLen += Editor_nRowsWidth[i];
+
+				x = Menu_start_x;
+				y += FONT_HEIGHT;
+
+			} //ends for, so all editor Rows_Num were fixed above.
+end:
+			if(Editor_nRowsNum > Rows_Num) { //if more lines than available Rows_Num, use scrollbar.
+				if(KeyBoard_Active){
+					drawFrame(SCREEN_WIDTH-SCREEN_MARGIN-LINE_THICKNESS*8, Frame_start_y,
+						SCREEN_WIDTH-SCREEN_MARGIN, KEY_Y+6, setting->color[1]);
+					y0=(KEY_Y+6-Menu_start_y+8)*((double)Top_Height/Editor_nRowsNum);
+					y1=(KEY_Y+6-Menu_start_y+8)*((double)(Top_Height+Rows_Num)/Editor_nRowsNum);
+					drawOpSprite(setting->color[1],
+						SCREEN_WIDTH-SCREEN_MARGIN-LINE_THICKNESS*6, (y0+Menu_start_y-2),
+						SCREEN_WIDTH-SCREEN_MARGIN-LINE_THICKNESS*2, (y1+Menu_start_y-10));
+				}else{
+					drawFrame(SCREEN_WIDTH-SCREEN_MARGIN-LINE_THICKNESS*8, Frame_start_y,
+						SCREEN_WIDTH-SCREEN_MARGIN, Frame_end_y, setting->color[1]);
+					y0=(Menu_end_y-Menu_start_y+8)*((double)Top_Height/Editor_nRowsNum);
+					y1=(Menu_end_y-Menu_start_y+8)*((double)(Top_Height+Rows_Num)/Editor_nRowsNum);
+					drawOpSprite(setting->color[1],
+						SCREEN_WIDTH-SCREEN_MARGIN-LINE_THICKNESS*6, (y0+Menu_start_y-2),
+						SCREEN_WIDTH-SCREEN_MARGIN-LINE_THICKNESS*2, (y1+Menu_start_y-6));
+				} //ends clause for scrollbar with KeyBoard.
+			} //ends clause for scrollbar.
+
+			//Tooltip section.
+			tmp[0]='\0', tmp1[0]='\0', tmp2[0]='\0';
+			if(KeyBoard_Active){ //Display Virtual KeyBoard Tooltip.
+				if(swapKeys) 
+					sprintf(tmp1, "R1:%s ÿ3:%s ÿ1:%s ÿ0:%s L2:%s R2:%s Sel:%s",
+						LNG(Menu), LNG(Exit), LNG(Sel), LNG(BackSpace),
+						LNG(Left), LNG(Right), LNG(Close_KB));
+				else
+					sprintf(tmp1, "R1:%s ÿ3:%s ÿ0:%s ÿ1:%s L2:%s R2:%s Sel:%s",
+						LNG(Menu), LNG(Exit), LNG(Sel), LNG(BackSpace),
+						LNG(Left), LNG(Right), LNG(Close_KB));
+			}else if(setting->usbkbd_used){ //Display KeyBoard Tooltip.
+				if(Window[Active_Window][OPENED]){
+					if(Mark[MARK_ON])
+						sprintf(tmp1, "F1/R1:%s Esc/ÿ3:%s Ctrl+ b:%s: %s ",
+							LNG(Menu), LNG(Exit), LNG(Mark), LNG(On));
+					else
+						sprintf(tmp1, "F1/R1:%s Esc/ÿ3:%s Ctrl+ b:%s: %s ",
+							LNG(Menu), LNG(Exit), LNG(Mark), LNG(Off));
+					sprintf(tmp2, "x:%s c:%s v:%s ", LNG(Cut), LNG(Copy), LNG(Paste));
+					strcat(tmp1, tmp2);
+					if(Editor_RetMode==OTHER)
+						sprintf(tmp2, "r:%s ", LNG(CrLf));
+					else if(Editor_RetMode==UNIX)
+						sprintf(tmp2, "r:%s ", LNG(Cr));
+					else if(Editor_RetMode==MAC)
+						sprintf(tmp2, "r:%s ", LNG(Lf));
+					strcat(tmp1, tmp2);
+					if(Editor_Insert)
+						sprintf(tmp2, "%s:%s", LNG(Ins), LNG(On));
+					else
+						sprintf(tmp2, "%s:%s", LNG(Ins), LNG(Off));
+					strcat(tmp1, tmp2);
+				}else
+					sprintf(tmp1, "F1/R1:%s Esc/ÿ3:%s", LNG(Menu), LNG(Exit));
+			}else{ //Display Basic Tooltip.
+				if(Window[Active_Window][OPENED]) 
+					sprintf(tmp1, "R1:%s ÿ3:%s Select:%s", LNG(Menu), LNG(Exit), LNG(Open_KeyBoard));
+				else
+					sprintf(tmp1, "R1:%s ÿ3:%s", LNG(Menu), LNG(Exit));
+			}
+			if(Window[Active_Window][CREATED])
+				sprintf(tmp, "%s : %s", LNG(PS2_TEXT_EDITOR), LNG(File_Not_Yet_Saved));
+			else if(Window[Active_Window][OPENED])
+				sprintf(tmp, "%s : %s", LNG(PS2_TEXT_EDITOR), Path[Active_Window]);
+			else
+				strcpy(tmp, LNG(PS2_TEXT_EDITOR));
+			setScrTmp(tmp, tmp1);
+		}//ends if(event||post_event).
+		drawScr();
+		post_event = event;
+		event = 0;
+	}//ends while.
+	
+	return;
+}
+//--------------------------------------------------------------
+//End of file: editor.c
+//--------------------------------------------------------------
Index: ps2launchargs/source/uLaunchELF/elf.c
===================================================================
--- ps2launchargs/source/uLaunchELF/elf.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/elf.c	(revision 1101)
@@ -0,0 +1,264 @@
+//--------------------------------------------------------------
+//File name:    elf.c
+//--------------------------------------------------------------
+#include "launchelf.h"
+
+unsigned char *elfLoaderLoadFile(char *path); // Iritscen: Modeled this on config.c's loadConfig()
+
+#define MAX_PATH 1025
+
+extern u8 *loader_elf;
+extern int size_loader_elf;
+extern u8 *fakehost_irx;
+extern int size_fakehost_irx;
+extern char LaunchElfDir[MAX_PATH]; // Iritscen: "extern"ed from main.c
+
+// ELF-loading stuff
+#define ELF_MAGIC		0x464c457f
+#define ELF_PT_LOAD		1
+
+//------------------------------
+typedef struct
+{
+	u8	ident[16];			// struct definition for ELF object header
+	u16	type;
+	u16	machine;
+	u32	version;
+	u32	entry;
+	u32	phoff;
+	u32	shoff;
+	u32	flags;
+	u16	ehsize;
+	u16	phentsize;
+	u16	phnum;
+	u16	shentsize;
+	u16	shnum;
+	u16	shstrndx;
+} elf_header_t;
+//------------------------------
+typedef struct
+{
+	u32	type;				// struct definition for ELF program section header
+	u32	offset;
+	void	*vaddr;
+	u32	paddr;
+	u32	filesz;
+	u32	memsz;
+	u32	flags;
+	u32	align;
+} elf_pheader_t;
+//--------------------------------------------------------------
+//End of data declarations
+//--------------------------------------------------------------
+//Start of function code
+//--------------------------------------------------------------
+// checkELFheader Tests for valid ELF file 
+// Modified version of loader from Independence
+//	(C) 2003 Marcus R. Brown <mrbrown@0xd6.org>
+//--------------------------------------------------------------
+int checkELFheader(char *path)
+{
+	elf_header_t elf_head;
+	u8 *boot_elf = (u8 *) &elf_head;
+	elf_header_t *eh = (elf_header_t *) boot_elf;
+	int fd, size=0, ret;
+	char fullpath[MAX_PATH], tmp[MAX_PATH], *p;
+
+	strcpy(fullpath,path);
+	if(	!strncmp(fullpath, "mc", 2)
+		||!strncmp(fullpath, "vmc", 3)
+		||!strncmp(fullpath, "rom", 3)
+		||!strncmp(fullpath, "cdrom", 5)
+		||!strncmp(fullpath, "cdfs", 4)
+		){; //fullpath is already correct
+	}else if(!strncmp(fullpath, "hdd0:", 5)) {
+		p = &path[5];
+		if(*p == '/')
+			p++;
+		sprintf(tmp, "hdd0:%s", p);
+		p = strchr(tmp, '/');
+		sprintf(fullpath, "pfs0:%s", p);
+		*p = 0;
+		if( (ret = mountParty(tmp)) < 0)
+			goto error;
+		fullpath[3] += ret;
+	}else if(!strncmp(fullpath, "mass", 4)){
+		char *pathSep;
+
+		pathSep = strchr(path, '/');
+		if(pathSep && (pathSep-path<7) && pathSep[-1]==':')
+			strcpy(fullpath+(pathSep-path), pathSep+1);
+	}else if(!strncmp(fullpath, "host:", 5)){
+		if(path[5] == '/')
+			strcpy(fullpath+5, path+6);
+	} else {
+		return 0;  //return 0 for unrecognized device
+	}
+	if ((fd = genOpen(fullpath, O_RDONLY)) < 0) 
+		goto error;
+	size = genLseek(fd, 0, SEEK_END);
+	if (!size){
+		genClose(fd);
+		goto error;
+	}
+	genLseek(fd, 0, SEEK_SET);
+	genRead(fd, boot_elf, sizeof(elf_header_t));
+	genClose(fd);
+
+	if ((_lw((u32)&eh->ident) != ELF_MAGIC) || eh->type != 2)
+		goto error;
+	
+	return 1;  //return 1 for successful check
+error:
+	return -1; //return -1 for failed check
+}
+//------------------------------
+//End of func:  int checkELFheader(const char *path)
+//--------------------------------------------------------------
+// RunLoaderElf loads LOADER.ELF from program memory and passes
+// args of selected ELF and partition to it
+// Modified version of loader from Independence
+//	(C) 2003 Marcus R. Brown <mrbrown@0xd6.org>
+//------------------------------
+void RunLoaderElf(char *filename, char *party)
+{
+	u8 *boot_elf;
+	elf_header_t *eh;
+	elf_pheader_t *eph;
+	void *pdata;
+	int ret, i;
+    int argc; // Iritscen: Added to allow add'l args
+    char *argv[16/*MAX_ARGS*/]; // Iritscen: Changed from "2" to allow add'l args
+
+	if((!strncmp(party, "hdd0:", 5)) && (!strncmp(filename, "pfs0:", 5))){
+		char fakepath[128], *p;
+		if(0 > fileXioMount("pfs0:", party, FIO_MT_RDONLY)){
+			//Some error occurred, it could be due to something else having used pfs0
+			unmountParty(0);  //So we try unmounting pfs0, to try again
+			if(0 > fileXioMount("pfs0:", party, FIO_MT_RDONLY))
+				return;  //If it still fails, we have to give up...
+		}
+		strcpy(fakepath,filename);
+		p=strrchr(fakepath,'/');
+		if(p==NULL) strcpy(fakepath,"pfs0:");
+		else
+		{
+			p++;
+			*p='\0';
+		}
+		//printf("Loading fakehost.irx %i bytes\n", size_fakehost_irx);
+		//printf("Faking for path \"%s\" on partition \"%s\"\n", fakepath, party);
+		SifExecModuleBuffer(&fakehost_irx, size_fakehost_irx, strlen(fakepath), fakepath, &ret);
+		
+	}
+
+/* NB: LOADER.ELF is embedded  */
+	boot_elf = (u8 *)&loader_elf;
+	eh = (elf_header_t *)boot_elf;
+	if (_lw((u32)&eh->ident) != ELF_MAGIC)
+		while (1);
+
+	eph = (elf_pheader_t *)(boot_elf + eh->phoff);
+
+/* Scan through the ELF's program headers and copy them into RAM, then
+									zero out any non-loaded regions.  */
+	for (i = 0; i < eh->phnum; i++)
+	{
+		if (eph[i].type != ELF_PT_LOAD)
+		continue;
+
+		pdata = (void *)(boot_elf + eph[i].offset);
+		memcpy(eph[i].vaddr, pdata, eph[i].filesz);
+
+		if (eph[i].memsz > eph[i].filesz)
+			memset(eph[i].vaddr + eph[i].filesz, 0,
+					eph[i].memsz - eph[i].filesz);
+	}
+
+/* Let's go.  */
+	fioExit();
+	SifInitRpc(0);
+	SifExitRpc();
+	FlushCache(0);
+	FlushCache(2);
+
+	argv[0] = filename;
+	argv[1] = party;
+	argc = 2;
+	
+	// Iritscen: Load launch args from file
+	char txtPath[MAX_PATH];
+	strcpy(txtPath, LaunchElfDir); // a path like "host:C:/Users/Home/pcsx2/uLaunchELF/"
+	strcat(txtPath, "LaunchArgs.txt");
+	printf("uLaunchELF: Attempting to open %s...\n", txtPath);
+	unsigned char *argsTxt = elfLoaderLoadFile(txtPath);
+	if (argsTxt != NULL)
+	{
+		int argsRead = 0;
+		unsigned char *lineStart = argsTxt, *scanner = lineStart;
+		while (*lineStart != '\0' && argsRead < 16 /*MAX_ARGS*/)
+		{
+			// Find end of line and copy line to an argv[] element
+			while (*scanner != '\r' && *scanner != '\n' && *scanner != '\0')
+				scanner++;
+			int length = scanner - lineStart;
+			argv[argsRead + 2] = malloc(length + 1);
+			strncpy(argv[argsRead + 2], lineStart, length);
+			argv[argsRead + 2][length] = '\0';
+			printf("Got argument %s.\n", argv[argsRead + 2]);
+			
+			// Advance to next line
+			while (*scanner == '\r' || *scanner == '\n')
+				scanner++;
+			lineStart = scanner;
+			argsRead++;
+		}
+		
+		argc += argsRead;
+		printf("uLaunchELF: Passing %d argument(s) to the loader for the game:\n", argsRead);
+		int a;
+		for (a = 0; a < argsRead; a++)
+			printf("   arg %d: %s\n", a + 1, argv[a + 2]);
+	}
+	else
+		printf("uLaunchELF: Could not load LaunchArgs.txt from disk!\n");
+	
+	ExecPS2((void *)eh->entry, 0, argc, argv);
+}
+//------------------------------
+//End of func:  void RunLoaderElf(char *filename, char *party)
+//--------------------------------------------------------------
+// Iritscen: Modeled this on config.c's loadConfig()
+unsigned char *elfLoaderLoadFile(char *path)
+{
+	int fd = -1, tst;
+	size_t fileSize;
+	char filePath[MAX_PATH];
+	unsigned char *RAM_p;
+
+	if ((tst = genFixPath(path, filePath)) >= 0)
+		fd = genOpen(filePath, O_RDONLY);
+	
+	if (fd < 0)
+	{
+failed_load:
+		return NULL;
+	}
+	fileSize = genLseek(fd, 0, SEEK_END);
+	printf("fileSize=%d\n", fileSize);
+	genLseek(fd, 0, SEEK_SET);
+	RAM_p = (char*)malloc(fileSize);
+	if (RAM_p == NULL)
+	{
+		genClose(fd);
+		goto failed_load;
+	}
+	
+	genRead(fd, RAM_p, fileSize); // read file as one long string
+	genClose(fd);
+	RAM_p[fileSize] = '\0'; // terminate the file contents string
+	return RAM_p;
+}
+//--------------------------------------------------------------
+//End of file:  elf.c
+//--------------------------------------------------------------
Index: ps2launchargs/source/uLaunchELF/filer.c
===================================================================
--- ps2launchargs/source/uLaunchELF/filer.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/filer.c	(revision 1101)
@@ -0,0 +1,4112 @@
+//--------------------------------------------------------------
+//File name:   filer.c
+//--------------------------------------------------------------
+#include "launchelf.h"
+
+typedef struct
+{
+	unsigned char unknown;
+	unsigned char sec;      // date/time (second)
+	unsigned char min;      // date/time (minute)
+	unsigned char hour;     // date/time (hour)
+	unsigned char day;      // date/time (day)
+	unsigned char month;    // date/time (month)
+	unsigned short year;    // date/time (year)
+} PS2TIME __attribute__((aligned (2)));
+
+#define MC_SFI 0xFEED //flag value used for mcSetFileInfo at MC file restoration
+
+#define MC_ATTR_norm_folder 0x8427  //Normal folder on PS2 MC
+#define MC_ATTR_prot_folder 0x842F  //Protected folder on PS2 MC
+#define MC_ATTR_PS1_folder  0x9027  //PS1 save folder on PS2 MC
+#define MC_ATTR_norm_file   0x8497  //file (PS2/PS1) on PS2 MC
+#define MC_ATTR_PS1_file    0x9417  //PS1 save file on PS1 MC
+
+#define IOCTL_RENAME 0xFEEDC0DE  //Ioctl request code for Rename function
+
+enum
+{
+	COPY,
+	CUT,
+	PASTE,
+	MCPASTE,
+	PSUPASTE,
+	DELETE,
+	RENAME,
+	NEWDIR,
+	NEWICON,
+	MOUNTVMC0,
+	MOUNTVMC1,
+	GETSIZE,
+	NUM_MENU
+} R1_menu_enum;
+
+#define PM_NORMAL     0  //PasteMode value for normal copies
+#define PM_MC_BACKUP  1  //PasteMode value for gamesave backup from MC
+#define PM_MC_RESTORE 2  //PasteMode value for gamesave restore to MC
+#define PM_PSU_BACKUP  3 //PasteMode value for gamesave backup from MC to PSU
+#define PM_PSU_RESTORE 4 //PasteMode value for gamesave restore to MC from PSU
+#define PM_RENAME 5      //PasteMode value for normal copies with new names
+#define MAX_RECURSE  16 //Maximum folder recursion for MC Backup/Restore
+
+int PasteProgress_f = 0;  //Flags progress report having been made in Pasting
+int PasteMode;            //Top-level PasteMode flag
+int PM_flag[MAX_RECURSE]; //PasteMode flag for each 'copy' recursion level
+int PM_file[MAX_RECURSE]; //PasteMode attribute file descriptors
+
+char mountedParty[MOUNT_LIMIT][MAX_NAME];
+int	latestMount = -1;
+int vmcMounted[2] = {0, 0}; //flags true for mounted VMC false for unmounted
+int vmc_PartyIndex[2] = {-1, -1};         //PFS index for each VMC, unless -1
+int Party_vmcIndex[MOUNT_LIMIT] = {-1,-1,-1,-1}; //VMC for each PFS, unless -1
+unsigned char *elisaFnt=NULL;
+int elisa_failed = FALSE; //Set at failure to load font, cleared at browser entry
+s64 freeSpace;
+int mcfreeSpace;
+int mctype_PSx;  //dlanor: Needed for proper scaling of mcfreespace
+int vfreeSpace;  //flags validity of freespace value
+int browser_cut;
+int nclipFiles, nmarks, nparties;
+int file_show = 1;  //dlanor: 0==name_only, 1==name+size+time, 2==title+size+time
+int file_sort = 1;  //dlanor: 0==none, 1==name, 2==title, 3==mtime
+int size_valid = 0;
+int time_valid = 0;
+char parties[MAX_PARTITIONS][MAX_NAME];
+char clipPath[MAX_PATH], LastDir[MAX_NAME], marks[MAX_ENTRY];
+FILEINFO clipFiles[MAX_ENTRY];
+int fileMode =  FIO_S_IRUSR | FIO_S_IWUSR | FIO_S_IXUSR | FIO_S_IRGRP | FIO_S_IWGRP | FIO_S_IXGRP | FIO_S_IROTH | FIO_S_IWOTH | FIO_S_IXOTH;
+
+char cnfmode_extU[CNFMODE_CNT][4] = {
+	"*",		// cnfmode FALSE
+	"ELF",	// cnfmode TRUE
+	"IRX",	// cnfmode USBD_IRX_CNF
+	"JPG",	// cnfmode SKIN_CNF
+	"JPG",	// cnfmode GUI_SKIN_CNF
+	"IRX",	// cnfmode USBKBD_IRX_CNF
+	"KBD",	// cnfmode KBDMAP_FILE_CNF
+	"CNF",	// cnfmode CNF_PATH_CNF
+	"*",		// cnfmode TEXT_CNF
+	"",			// cnfmode DIR_CNF
+	"JPG",	// cnfmode JPG_CNF
+	"IRX",	// cnfmode USBMASS_IRX_CNF
+	"LNG",	// cnfmode LANG_CNF
+	"FNT",	// cnfmode FONT_CNF
+	"*"			// cnfmode SAVE_CNF
+};
+
+char cnfmode_extL[CNFMODE_CNT][4] = {
+	"*",		// cnfmode FALSE
+	"elf",	// cnfmode TRUE
+	"irx",	// cnfmode USBD_IRX_CNF
+	"jpg",	// cnfmode SKIN_CNF
+	"jpg",	// cnfmode GUI_SKIN_CNF
+	"irx",	// cnfmode USBKBD_IRX_CNF
+	"kbd",	// cnfmode KBDMAP_FILE_CNF
+	"cnf",	// cnfmode CNF_PATH_CNF
+	"*",		// cnfmode TEXT_CNF
+	"",			// cnfmode DIR_CNF
+	"jpg",	// cnfmode JPG_CNF
+	"irx",	// cnfmode USBMASS_IRX_CNF
+	"lng",	// cnfmode LANG_CNF
+	"fnt",	// cnfmode FONT_CNF
+	"*"			// cnfmode SAVE_CNF
+};
+
+int host_ready   = 0;
+int host_error   = 0;
+int host_elflist = 0;
+int host_use_Bsl = 1;	//By default assume that host paths use backslash
+
+unsigned long written_size; //Used for pasting progress report
+u64 PasteTime;              //Used for pasting progress report
+
+typedef struct {
+	u8	unused;
+	u8	sec;
+	u8	min;
+	u8	hour;
+	u8	day;
+	u8	month;
+	u16	year;
+} ps2time;
+
+typedef struct {                  //Offs:  Example content
+	ps2time cTime;                  //0x00:  8 bytes creation timestamp (struct above)
+	ps2time mTime;                  //0x08:  8 bytes modification timestamp (struct above)
+	u32 size;                       //0x10:  file size
+	u16 attr;                       //0x14:  0x8427  (=normal folder, 8497 for normal file)
+	u16 unknown_1_u16;              //0x16:  2 zero bytes
+	u64 unknown_2_u64;              //0x18:  8 zero bytes
+	u8  name[32];                   //0x20:  32 name bytes, padded with zeroes
+} mcT_header __attribute__((aligned (64)));
+
+typedef struct {                  //Offs:  Example content
+	u16 attr;                       //0x00:  0x8427  (=normal folder, 8497 for normal file)
+	u16 unknown_1_u16;              //0x02:  2 zero bytes
+	u32 size;                       //0x04:  header_count-1, file size, 0 for pseudo
+	ps2time	cTime;                  //0x08:  8 bytes creation timestamp (struct above)
+	u64 EMS_used_u64;               //0x10:  8 zero bytes (but used by EMS)
+	ps2time mTime;                  //0x18:  8 bytes modification timestamp (struct above)
+	u64 unknown_2_u64;              //0x20:  8 bytes from mcTable
+	u8  unknown_3_24_bytes[24];     //0x28:  24 zero bytes
+	u8  name[32];                   //0x40:  32 name bytes, padded with zeroes
+	u8  unknown_4_416_bytes[0x1A0]; //0x60:  zero byte padding to reach 0x200 size
+} psu_header;                     //0x200: End of psu_header struct
+
+int	PSU_content;	//Used to count PSU content headers for the main header
+
+//USB_mass definitions for multiple drive usage
+char	USB_mass_ix[10] = {'0',0,0,0,0,0,0,0,0,0};
+int		USB_mass_max_drives = USB_MASS_MAX_DRIVES;
+u64		USB_mass_scan_time = 0;
+int		USB_mass_scanned = 0;   //0==Not_found_OR_No_Multi 1==found_Multi_mass_once
+int		USB_mass_loaded = 0;    //0==none, 1==internal, 2==external
+
+
+//char debugs[4096]; //For debug display strings. Comment it out when unused
+//--------------------------------------------------------------
+//executable code
+//--------------------------------------------------------------
+void clear_mcTable(mcTable *mcT)
+{
+	memset((void *) mcT, 0, sizeof(mcTable));
+}
+//--------------------------------------------------------------
+void clear_psu_header(psu_header *psu)
+{
+	memset((void *) psu, 0, sizeof(psu_header));
+}
+//--------------------------------------------------------------
+void pad_psu_header(psu_header *psu)
+{
+	memset((void *) psu, 0xFF, sizeof(psu_header));
+}
+//--------------------------------------------------------------
+// getHddParty below takes as input the string path and the struct file
+// and uses these to calculate the output strings party and dir. If the
+// file struct is not passed as NULL, then its file->name entry will be
+// added to the internal copy of the path string (which remains unchanged),
+// and if that file struct entry is for a folder, then a slash is also added.
+// The modified path is then used to calculate the output strings as follows. 
+//-----
+// party = the full path string with "hdd0:" and partition spec, but without
+// the slash character between them, used in user specified full paths. So
+// the first slash in that string will come after the partition name.
+//-----
+// dir = the pfs path string, starting like "pfs0:" (but may use different
+// pfs index), and this is then followed by the path within that partition.
+// Note that despite the name 'dir', this is also used for files.
+//-----
+//NB: From the first slash character those two strings are identical when
+// both are used, but either pointer may be set to NULL in the function call,
+// as an indication that the caller isn't interested in that part.
+//--------------------------------------------------------------
+int getHddParty(const char *path, const FILEINFO *file, char *party, char *dir)
+{
+	char fullpath[MAX_PATH], *p;
+	
+	if(strncmp(path,"hdd",3)) return -1;
+	
+	strcpy(fullpath, path);
+	if(file!=NULL){
+		strcat(fullpath, file->name);
+		if(file->stats.attrFile & MC_ATTR_SUBDIR) strcat(fullpath,"/");
+	}
+	if((p=strchr(&fullpath[6], '/'))==NULL) return -1;
+	if(dir!=NULL) sprintf(dir, "pfs0:%s", p);
+	*p=0;
+	if(party!=NULL) sprintf(party, "hdd0:%s", &fullpath[6]);
+	
+	return 0;
+}
+//--------------------------------------------------------------
+int mountParty(const char *party)
+{
+	int i, j;
+	char pfs_str[6];
+
+	for(i=0; i<MOUNT_LIMIT; i++){ //Here we check already mounted PFS indexes
+		if(!strcmp(party, mountedParty[i]))
+			goto return_i;
+	}
+
+	for(i=0, j=-1; i<MOUNT_LIMIT; i++){ //Here we search for a free PFS index
+		if(mountedParty[i][0] == 0){
+			j=i;
+			break;
+		}
+	}
+
+	if(j == -1){ //Here we search for a suitable PFS index to unmount
+		for(i=0; i<MOUNT_LIMIT; i++){
+			if((i!=latestMount) && (Party_vmcIndex[i]<0)){
+				j=i;
+				break;
+			}
+		}
+		unmountParty(j);
+	}
+	//Here j is the index of a free PFS mountpoint
+	//But 'free' only means that the main uLE program isn't using it
+	//If the ftp server is running, that may have used the mountpoints
+
+	//RA NB: The old code to reclaim FTP partitions was seriously bugged...
+
+	i = j;
+	strcpy(pfs_str, "pfs0:");
+
+	pfs_str[3] = '0'+i;
+	if(fileXioMount(pfs_str, party, FIO_MT_RDWR) < 0){ //if FTP stole it
+		for(i=0; i<=4; i++){ //for loop to kill FTP partition mountpoints
+			if((i!=latestMount) && (Party_vmcIndex[i]<0)){ //if unneeded by uLE
+				unmountParty(i);  //unmount partition mountpoint
+				pfs_str[3] = '0'+i; //prepare to reuse that mountpoint
+				if(fileXioMount(pfs_str, party, FIO_MT_RDWR) >= 0)
+					break; //break from the loop on successful mount
+			} //ends if unneeded by uLE
+		} //ends for loop to kill FTP partition mountpoints
+		//Here i indicates what happened above with the following meanings:
+		//0..4==Success after trying i mountpoints,  5==Failure
+		if(i>4)
+			return -1;
+	} //ends if clause for mountpoints stolen by FTP
+	strcpy(mountedParty[i], party);
+return_i:
+	latestMount = i;
+	return i;
+}
+//--------------------------------------------------------------
+void unmountParty(int party_ix)
+{
+	char pfs_str[6];
+
+	strcpy(pfs_str, "pfs0:");
+	pfs_str[3] += party_ix;
+	if(fileXioUmount(pfs_str) < 0)
+		return; //leave variables unchanged if unmount failed (remember true state)
+	if(party_ix < MOUNT_LIMIT){
+		mountedParty[party_ix][0] = 0;
+	}
+	if(latestMount==party_ix)
+		latestMount=-1;
+}
+//--------------------------------------------------------------
+// unmountAll can unmount all mountpoints from 0 to MOUNT_LIMIT,
+// but unlike the individual unmountParty, it will only do so
+// for mountpoints indicated as used by the matching string in
+// the string array 'mountedParty'.
+// From v4.23 this routine is also used to unmount VMC devices
+//------------------------------
+void unmountAll(void)
+{
+	char pfs_str[6];
+	char vmc_str[6];
+	int i;
+
+	strcpy(vmc_str, "vmc0:");
+	for(i=0; i<2; i++){
+		if(vmcMounted[i]){
+			vmc_str[3] = '0'+i;
+			fileXioUmount(vmc_str);
+			vmcMounted[i] = 0;
+			vmc_PartyIndex[i]=-1;
+		}
+	}
+
+	strcpy(pfs_str, "pfs0:");
+	for(i=0; i<MOUNT_LIMIT; i++){
+		Party_vmcIndex[i]=-1;
+		if(mountedParty[i][0]!=0){
+			pfs_str[3] = '0'+i;
+			fileXioUmount(pfs_str);
+			mountedParty[i][0] = 0;
+		}
+	}
+	latestMount = -1;
+} //ends unmountAll
+//--------------------------------------------------------------
+int ynDialog(const char *message)
+{
+	char msg[512];
+	int dh, dw, dx, dy;
+	int sel=0, a=6, b=4, c=2, n, tw;
+	int i, x, len, ret;
+	int event, post_event=0;
+	
+	strcpy(msg, message);
+	
+	for(i=0,n=1; msg[i]!=0; i++){ //start with one string at pos zero
+		if(msg[i]=='\n'){           //line separator at current pos ?
+			msg[i]=0;                 //split old line to separate string
+			n++;                      //increment string count
+		}
+	}                             //loop back for next character pos
+	for(i=len=tw=0; i<n; i++){    //start with string 0, assume 0 length & width
+		ret = printXY(&msg[len], 0, 0, 0, FALSE, 0);  //get width of current string
+		if(ret>tw) tw=ret;     //tw = largest text width of strings so far
+		len+=strlen(&msg[len])+1;    //len = pos of next string start
+	}
+	if(tw<96) tw=96;
+	
+	dh = FONT_HEIGHT*(n+1)+2*2+a+b+c;
+	dw = 2*2+a*2+tw;
+	dx = (SCREEN_WIDTH-dw)/2;
+	dy = (SCREEN_HEIGHT-dh)/2;
+//	printf("tw=%d\ndh=%d\ndw=%d\ndx=%d\ndy=%d\n", tw,dh,dw,dx,dy);
+	
+	event = 1;  //event = initial entry
+	while(1){
+		//Pad response section
+		waitPadReady(0, 0);
+		if(readpad()){
+			if(new_pad & PAD_LEFT){
+				event |= 2;  //event |= valid pad command
+				sel=0;
+			}else if(new_pad & PAD_RIGHT){
+				event |= 2;  //event |= valid pad command
+				sel=1;
+			}else if((!swapKeys && new_pad & PAD_CROSS)
+			      || (swapKeys && new_pad & PAD_CIRCLE) ){
+				ret=-1;
+				break;
+			}else if((swapKeys && new_pad & PAD_CROSS)
+			      || (!swapKeys && new_pad & PAD_CIRCLE) ){
+				if(sel==0) ret=1;
+				else	   ret=-1;
+				break;
+			}
+		}
+		
+		if(event||post_event){ //NB: We need to update two frame buffers per event
+
+			//Display section
+			drawPopSprite(setting->color[0],
+				dx, dy,
+				dx+dw, (dy+dh));
+			drawFrame(dx, dy, dx+dw, (dy+dh), setting->color[1]);
+			for(i=len=0; i<n; i++){
+				printXY(&msg[len], dx+2+a,(dy+a+2+i*16), setting->color[3],TRUE,0);
+				len+=strlen(&msg[len])+1;
+			}
+
+			//Cursor positioning section
+			x=(tw-96)/4;
+			printXY(LNG(OK), dx+a+x+FONT_WIDTH,
+				(dy+a+b+2+n*FONT_HEIGHT), setting->color[3],TRUE,0);
+			printXY(LNG(CANCEL), dx+dw-x-(strlen(LNG(CANCEL))+1)*FONT_WIDTH,
+				(dy+a+b+2+n*FONT_HEIGHT), setting->color[3],TRUE,0);
+			if(sel==0)
+				drawChar(LEFT_CUR, dx+a+x,(dy+a+b+2+n*FONT_HEIGHT), setting->color[3]);
+			else
+				drawChar(LEFT_CUR,dx+dw-x-(strlen(LNG(CANCEL))+2)*FONT_WIDTH-1,
+					(dy+a+b+2+n*FONT_HEIGHT),setting->color[3]);
+		}//ends if(event||post_event)
+		drawLastMsg();
+		post_event = event;
+		event = 0;
+	}//ends while
+	drawSprite(setting->color[0], dx, dy, dx+dw+1, (dy+dh)+1);
+	drawScr();
+	drawSprite(setting->color[0], dx, dy, dx+dw+1, (dy+dh)+1);
+	drawScr();
+	return ret;
+}
+//------------------------------
+//endfunc ynDialog
+//--------------------------------------------------------------
+void nonDialog(char *message)
+{
+	char msg[80*30]; //More than this can't be shown on screen, even in PAL
+	static int dh, dw, dx, dy;    //These are static, to allow cleanup
+	int a=6, b=4, c=2, n, tw;
+	int i, len, ret;
+
+	if(message==NULL){ //NULL message means cleanup for last nonDialog
+		drawSprite(setting->color[0],
+			dx, dy,
+			dx+dw, (dy+dh));
+		return;
+	}
+
+	strcpy(msg, message);
+
+	for(i=0,n=1; msg[i]!=0; i++){ //start with one string at pos zero
+		if(msg[i]=='\n'){           //line separator at current pos ?
+			msg[i]=0;                 //split old line to separate string
+			n++;                      //increment string count
+		}
+	}                             //loop back for next character pos
+	for(i=len=tw=0; i<n; i++){    //start with string 0, assume 0 length & width
+		ret = printXY(&msg[len], 0, 0, 0, FALSE,0);  //get width of current string
+		if(ret>tw) tw=ret;     //tw = largest text width of strings so far
+		len+=strlen(&msg[len])+1;    //len = pos of next string start
+	}
+	if(tw<96) tw=96;
+
+	dh = 16*n+2*2+a+b+c;
+	dw = 2*2+a*2+tw;
+	dx = (SCREEN_WIDTH-dw)/2;
+	dy = (SCREEN_HEIGHT-dh)/2;
+	//printf("tw=%d\ndh=%d\ndw=%d\ndx=%d\ndy=%d\n", tw,dh,dw,dx,dy);
+
+	drawPopSprite(setting->color[0],
+		dx, dy,
+		dx+dw, (dy+dh));
+	drawFrame(dx, dy, dx+dw, (dy+dh), setting->color[1]);
+	for(i=len=0; i<n; i++){
+		printXY(&msg[len], dx+2+a,(dy+a+2+i*FONT_HEIGHT), setting->color[3],TRUE,0);
+		len+=strlen(&msg[len])+1;
+	}
+}
+//------------------------------
+//endfunc nonDialog
+//--------------------------------------------------------------
+// cmpFile below returns negative if the 'a' entry is 'lower'
+// than the 'b' entry, normally meaning that 'a' should be in
+// a higher/earlier screen position than 'b'. Such negative
+// return value causes the calling sort routine to adjust the
+// entry order, which does not occur for other return values.
+//--------------------------------------------------------------
+int cmpFile(FILEINFO *a, FILEINFO *b)  //Used for directory sort
+{
+	unsigned char *p, ca, cb;
+	int i, n, ret, aElf=FALSE, bElf=FALSE, t=(file_sort==2);
+
+	if(file_sort == 0) return 0; //return 0 for unsorted mode
+
+	if((a->stats.attrFile & MC_ATTR_OBJECT) == (b->stats.attrFile & MC_ATTR_OBJECT)){
+		if(a->stats.attrFile & MC_ATTR_FILE){
+			p = strrchr(a->name, '.');
+			if(p!=NULL && !stricmp(p+1, "ELF")) aElf=TRUE;
+			p = strrchr(b->name, '.');
+			if(p!=NULL && !stricmp(p+1, "ELF")) bElf=TRUE;
+			if(aElf && !bElf)		return -1;
+			else if(!aElf && bElf)	return 1;
+		}
+		if(file_sort == 3){ //Sort by timestamp
+			t=(file_show==2);  //Set secondary sort criterion
+			if(time_valid){
+				u64 time_a = *(u64 *) &a->stats._modify;
+				u64 time_b = *(u64 *) &b->stats._modify;
+				if(time_a > time_b) return -1;  //NB: reversed comparison for falling order
+				if(time_a < time_b) return 1;
+			}
+		}
+		if(t){
+			if(a->title[0]!=0 && b->title[0]==0) return -1;
+			else if(a->title[0]==0 && b->title[0]!=0) return 1;
+			else if(a->title[0]==0 && b->title[0]==0) t=FALSE;
+		}
+		if(t) n=strlen(a->title);
+		else  n=strlen(a->name);
+		for(i=0; i<=n; i++){
+			if(t){
+				ca=a->title[i]; cb=b->title[i];
+			}else{
+				ca=a->name[i]; cb=b->name[i];
+				if(ca>='a' && ca<='z') ca-=0x20;
+				if(cb>='a' && cb<='z') cb-=0x20;
+			}
+			ret = ca-cb;
+			if(ret!=0) return ret;
+		}
+		return 0;
+	}
+	
+	if(a->stats.attrFile & MC_ATTR_SUBDIR)	return -1;
+	else						return 1;
+}
+//--------------------------------------------------------------
+void sort(FILEINFO *a, int left, int right) {
+	FILEINFO tmp, pivot;
+	int i, p;
+	
+	if (left < right) {
+		pivot = a[left];
+		p = left;
+		for (i=left+1; i<=right; i++) {
+			if (cmpFile(&a[i],&pivot)<0){
+				p=p+1;
+				tmp=a[p];
+				a[p]=a[i];
+				a[i]=tmp;
+			}
+		}
+		a[left] = a[p];
+		a[p] = pivot;
+		sort(a, left, p-1);
+		sort(a, p+1, right);
+	}
+}
+//--------------------------------------------------------------
+int readMC(const char *path, FILEINFO *info, int max)
+{
+	static mcTable mcDir[MAX_ENTRY] __attribute__((aligned(64)));
+	char dir[MAX_PATH];
+	int i, j, ret;
+
+	mcSync(0,NULL,NULL);
+
+	mcGetInfo(path[2]-'0', 0, &mctype_PSx, NULL, NULL);
+	mcSync(0, NULL, &ret);
+	if (mctype_PSx == 2) //PS2 MC ?
+		time_valid = 1;
+	size_valid = 1;
+
+	strcpy(dir, &path[4]); strcat(dir, "*");
+	mcGetDir(path[2]-'0', 0, dir, 0, MAX_ENTRY-2, (mcTable *) mcDir);
+	mcSync(0, NULL, &ret);
+	
+	for(i=j=0; i<ret; i++)
+	{
+		if(mcDir[i].attrFile & MC_ATTR_SUBDIR &&
+		(!strcmp(mcDir[i].name,".") || !strcmp(mcDir[i].name,"..")))
+			continue;  //Skip pseudopaths "." and ".."
+		strcpy(info[j].name, mcDir[i].name);
+		info[j].stats = mcDir[i];
+		j++;
+	}
+	
+	return j;
+}
+//------------------------------
+//endfunc readMC
+//--------------------------------------------------------------
+int readCD(const char *path, FILEINFO *info, int max)
+{
+	static struct TocEntry TocEntryList[MAX_ENTRY];
+	char dir[MAX_PATH];
+	int i, j, n;
+	u64 wait_start;
+
+	loadCdModules();
+	if(cdGetDiscType() <= CDVD_TYPE_UNKNOWN){
+		wait_start = Timer();
+		while((Timer() < wait_start+500) && !uLE_cdDiscValid()){
+			if(cdmode == CDVD_TYPE_NODISK)
+				return 0;
+		}
+		if(cdmode == CDVD_TYPE_NODISK)
+			return 0;
+		if((cdmode < CDVD_TYPE_PS1CD) || (cdmode > CDVD_TYPE_PS2DVD)){
+			if(setting->discControl)
+				uLE_cdStop();
+			return 0;
+		}
+	}
+	
+	strcpy(dir, &path[5]);
+	CDVD_FlushCache();
+	n = CDVD_GetDir(dir, NULL, CDVD_GET_FILES_AND_DIRS, TocEntryList, MAX_ENTRY, dir);
+
+	for(i=j=0; i<n; i++)
+	{
+		if(TocEntryList[i].fileProperties & 0x02 &&
+		 (!strcmp(TocEntryList[i].filename,".") ||
+		  !strcmp(TocEntryList[i].filename,"..")))
+			continue;  //Skip pseudopaths "." and ".."
+		strcpy(info[j].name, TocEntryList[i].filename);
+		clear_mcTable(&info[j].stats);
+		if(TocEntryList[i].fileProperties & 0x02){
+			info[j].stats.attrFile = MC_ATTR_norm_folder;
+		}
+		else{
+			info[j].stats.attrFile = MC_ATTR_norm_file;
+			info[j].stats.fileSizeByte = TocEntryList[i].fileSize;
+		}
+		j++;
+	}
+
+	size_valid = 1;
+
+	return j;
+}
+//------------------------------
+//endfunc readCD
+//--------------------------------------------------------------
+void setPartyList(void)
+{
+	iox_dirent_t dirEnt;
+	int hddFd;
+	
+	nparties=0;
+	
+	if((hddFd=fileXioDopen("hdd0:")) < 0)
+		return;
+	while(fileXioDread(hddFd, &dirEnt) > 0)
+	{
+		if(nparties >= MAX_PARTITIONS)
+			break;
+		if((dirEnt.stat.attr != ATTR_MAIN_PARTITION) 
+				|| (dirEnt.stat.mode != FS_TYPE_PFS))
+			continue;
+
+		//Patch this to see if new CB versions use valid PFS format
+		//NB: All CodeBreaker versions up to v9.3 use invalid formats
+		if(!strncmp(dirEnt.name, "PP.",3)){
+			int len = strlen(dirEnt.name);
+			if(!strcmp(dirEnt.name+len-4, ".PCB"))
+				continue;
+		}
+
+		if(!strncmp(dirEnt.name, "__", 2) &&
+			strcmp(dirEnt.name, "__boot") &&
+			strcmp(dirEnt.name, "__net") &&
+			strcmp(dirEnt.name, "__system") &&
+			strcmp(dirEnt.name, "__sysconf") &&
+			strcmp(dirEnt.name, "__common"))
+			continue;
+		
+		strcpy(parties[nparties++], dirEnt.name);
+	}
+	fileXioDclose(hddFd);
+}
+//--------------------------------------------------------------
+// The following group of file handling functions are used to allow
+// the main program to access files without having to deal with the
+// difference between fio and fileXio devices directly in each call.
+// Even so, paths for fileXio are assumed to be already prepared so
+// as to be accepted by fileXio calls (so HDD file access use "pfs")
+// Generic functions for this purpose that have been added so far are:
+// genInit(void), genLimObjName(uLE_path, reserve),
+// genFixPath(uLE_path, gen_path),
+// genOpen(path, mode), genClose(fd), genDopen(path), genDclose(fd),
+// genLseek(fd,where,how), genRead(fd,buf,size), genWrite(fd,buf,size)
+// genRemove(path), genRmdir(path)
+//--------------------------------------------------------------
+int gen_fd[256]; //Allow up to 256 generic file handles
+int gen_io[256]; //For each handle, also memorize io type
+//--------------------------------------------------------------
+void genInit(void)
+{
+	int	i;
+
+	for(i=0; i<256; i++)
+		gen_fd[i] = -1;
+}
+//------------------------------
+//endfunc genInit
+//--------------------------------------------------------------
+void genLimObjName(char *uLE_path, int reserve)
+{
+	char	*p, *q, *r;
+	int	limit = 256; //enforce a generic limit of 256 characters
+	int	folder_flag = (uLE_path[strlen(uLE_path)-1] == '/'); //flag folder object
+	int overflow;
+
+	if(!strncmp(uLE_path, "mc", 2) || !strncmp(uLE_path, "vmc", 3))
+		limit = 32;    //enforce MC limit of 32 characters
+
+	if(folder_flag)                  //if path ends with path separator
+		uLE_path[strlen(uLE_path)-1]=0;  //  remove final path separator (temporarily)
+
+	p = uLE_path;    //initially assume a pure object name (quite insanely :))
+	if((q=strchr(p, ':')) != NULL)   //if a drive separator is present
+		p = q+1;                       //  object name may start after drive separator
+	if((q=strrchr(p, '/')) != NULL)  //If there's any path separator in the string
+		p = q+1;                       //  object name starts after last path separator
+	limit -= reserve;                //lower limit by reserved character space
+	overflow = strlen(p)-limit;      //Calculate length of string to remove (if positive)
+	if((limit<=0)||(overflow<=0))    //if limit invalid, or not exceeded
+		goto limited;                  //  no further limitation is needed
+	if((q=strrchr(p, '.')) == NULL)  //if there's no extension separator
+		goto limit_end;                //limitation must be done at end of full name
+	r = q-overflow;                  //r is the place to recopy file extension
+	if(r > p){                       //if this place is above string start
+		strcpy(r, q);                  //remove overflow from end of prefix part
+		goto limited;                  //which concludes the limitation
+	}//if we fall through here, the prefix part was too short for the limitation needed
+limit_end:
+	p[limit] = 0;                  //  remove overflow from end of full name
+limited:
+
+	if(folder_flag)                  //if original path ended with path separator
+		strcat(uLE_path, "/");         //  reappend final path separator after name
+}
+//------------------------------
+//endfunc genLimObjName
+//--------------------------------------------------------------
+int genFixPath(char *inp_path, char *gen_path)
+{
+	char uLE_path[MAX_PATH], loc_path[MAX_PATH], party[MAX_NAME], *p;
+	char *pathSep;
+	int part_ix;
+
+	part_ix = 99;               //Assume valid non-HDD path
+	if( !uLE_related(uLE_path, inp_path) )
+		part_ix = -99; //Assume invalid uLE_related path
+	strcpy(gen_path, uLE_path); //Assume no path patching needed
+	pathSep = strchr(uLE_path, '/');
+
+	if(!strncmp(uLE_path, "cdfs", 4)){          //if using CD or DVD disc path
+		loadCdModules();
+		CDVD_FlushCache();
+		CDVD_DiskReady(0);
+	//end of clause for using a CD or DVD path
+
+	} else if(!strncmp(uLE_path, "mass", 4)){   //if using USB mass: path
+		loadUsbModules();
+
+		if(pathSep && (pathSep-uLE_path<7) && pathSep[-1]==':')
+			strcpy(gen_path+(pathSep-uLE_path), pathSep+1);
+	//end of clause for using a USB mass: path
+
+	} else if(!strncmp(uLE_path, "hdd0:/", 6)){ //If using HDD path
+		strcpy(loc_path, uLE_path+6);
+		if((p=strchr(loc_path, '/'))!=NULL){
+			sprintf(gen_path,"pfs0:%s", p);
+			*p = 0;
+		} else {
+			strcpy(gen_path, "pfs0:/");
+		}
+		sprintf(party, "hdd0:%s", loc_path);
+		if(nparties==0){
+			loadHddModules();
+			setPartyList();
+		}
+		if((part_ix = mountParty(party)) >= 0)
+		  gen_path[3] = part_ix+'0';
+	//end of clause for using an HDD path
+	}
+	genLimObjName(gen_path, 0);
+	return part_ix;
+	//non-HDD Path => 99, Good HDD Path => 0-3, Bad Path => negative
+}
+//------------------------------
+//endfunc genFixPath
+//--------------------------------------------------------------
+int genRmdir(char *path)
+{
+	int ret;
+
+	genLimObjName(path, 0);
+	if(!strncmp(path, "pfs", 3) || !strncmp(path, "vmc", 3)){
+		ret = fileXioRmdir(path);
+		if(!strncmp(path, "vmc", 3))
+			(void) fileXioDevctl("vmc0:", DEVCTL_VMCFS_CLEAN, NULL, 0, NULL, 0);
+	}else{
+		ret = fioRmdir(path);
+	}
+	return ret;
+}
+//------------------------------
+//endfunc genRmdir
+//--------------------------------------------------------------
+int genRemove(char *path)
+{
+	int ret;
+
+	genLimObjName(path, 0);
+	if(!strncmp(path, "pfs", 3) || !strncmp(path, "vmc", 3)){
+		ret = fileXioRemove(path);
+		if(!strncmp(path, "vmc", 3))
+			(void) fileXioDevctl("vmc0:", DEVCTL_VMCFS_CLEAN, NULL, 0, NULL, 0);
+	}else{
+		ret = fioRemove(path);
+		if(!strncmp("mc", path, 2)) //exception for MCMAN, which has its own fix
+			ret = fioRmdir(path);     //  Remove accidental dir (ancient ioman bug)
+	} //ends if clauses
+	return ret;
+}
+//------------------------------
+//endfunc genRemove
+//--------------------------------------------------------------
+int genOpen(char *path, int mode)
+{
+	int i, fd, io;
+
+	genLimObjName(path, 0);
+	for(i=0; i<256; i++)
+		if(gen_fd[i] < 0)
+			break;
+	if(i > 255)
+		return -1;
+
+	if(!strncmp(path, "pfs", 3) || !strncmp(path, "vmc", 3)){
+		fd = fileXioOpen(path, mode, fileMode);
+		io = 1;
+	}else{
+		fd = fioOpen(path, mode);
+		io = 0;
+	}
+	if(fd < 0)
+		return fd;
+
+	gen_fd[i] = fd;
+	gen_io[i] = io;
+	return i;
+}
+//------------------------------
+//endfunc genOpen
+//--------------------------------------------------------------
+int genDopen(char *path)
+{
+	int i, fd, io;
+
+	for(i=0; i<256; i++)
+		if(gen_fd[i] < 0)
+			break;
+	if(i > 255){
+		//printf("genDopen(\"%s\") => no free descriptors\r\n", path);
+		return -1;
+	}
+
+	if(!strncmp(path, "pfs", 3) || !strncmp(path, "vmc", 3)){
+		char tmp[MAX_PATH];
+
+		strcpy(tmp, path);
+		if(tmp[strlen(tmp)-1] == '/')
+			tmp[strlen(tmp)-1] = '\0';
+		fd = fileXioDopen(tmp);
+		io = 3;
+	}else{
+		fd = fioDopen(path);
+		io = 2;
+	}
+	if(fd < 0){
+		//printf("genDopen(\"%s\") => low error %d\r\n", path, fd);
+		return fd;
+	}
+
+	gen_fd[i] = fd;
+	gen_io[i] = io;
+	//printf("genDopen(\"%s\") =>dd = %d\r\n", path, i);
+	return i;
+}
+//------------------------------
+//endfunc genDopen
+//--------------------------------------------------------------
+int genLseek(int fd, int where, int how)
+{
+	if((fd < 0) || (fd > 255) || (gen_fd[fd] < 0))
+		return -1;
+
+	if(gen_io[fd])
+		return fileXioLseek(gen_fd[fd], where, how);
+	else
+		return fioLseek(gen_fd[fd], where, how);
+}
+//------------------------------
+//endfunc genLseek
+//--------------------------------------------------------------
+int genRead(int fd, void *buf, int size)
+{
+	if((fd < 0) || (fd > 255) || (gen_fd[fd] < 0))
+		return -1;
+
+	if(gen_io[fd])
+		return fileXioRead(gen_fd[fd], buf, size);
+	else
+		return fioRead(gen_fd[fd], buf, size);
+}
+//------------------------------
+//endfunc genRead
+//--------------------------------------------------------------
+int genWrite(int fd, void *buf, int size)
+{
+	if((fd < 0) || (fd > 255) || (gen_fd[fd] < 0))
+		return -1;
+
+	if(gen_io[fd])
+		return fileXioWrite(gen_fd[fd], buf, size);
+	else
+		return fioWrite(gen_fd[fd], buf, size);
+}
+//------------------------------
+//endfunc genWrite
+//--------------------------------------------------------------
+int genClose(int fd)
+{
+	int ret;
+
+	if((fd < 0) || (fd > 255) || (gen_fd[fd] < 0))
+		return -1;
+
+	if(gen_io[fd]==1)
+		ret = fileXioClose(gen_fd[fd]);
+	else if(gen_io[fd]==0)
+		ret = fioClose(gen_fd[fd]);
+	else
+		return -1;
+	gen_fd[fd] = -1;
+	return ret;
+}
+//------------------------------
+//endfunc genClose
+//--------------------------------------------------------------
+int genDclose(int fd)
+{
+	int ret;
+
+	if((fd < 0) || (fd > 255) || (gen_fd[fd] < 0))
+		return -1;
+
+	if(gen_io[fd]==3)
+		ret = fileXioDclose(gen_fd[fd]);
+	else if(gen_io[fd]==2)
+		ret = fioDclose(gen_fd[fd]);
+	else
+		return -1;
+	gen_fd[fd] = -1;
+	return ret;
+}
+//------------------------------
+//endfunc genDclose
+//--------------------------------------------------------------
+int readVMC(const char *path, FILEINFO *info, int max)
+{
+	iox_dirent_t dirbuf;
+	char dir[MAX_PATH];
+	int i=0, fd;
+	
+	strcpy(dir, path);
+	if((fd=fileXioDopen(dir)) < 0) return 0;
+	
+	while(fileXioDread(fd, &dirbuf) > 0){
+//		if(dirbuf.stat.mode & FIO_S_IFDIR &&  //NB: normal usage (non-vmcfs)
+		if(dirbuf.stat.mode & MC_ATTR_SUBDIR &&  //NB: nonstandard usage of vmcfs
+		(!strcmp(dirbuf.name,".") || !strcmp(dirbuf.name,"..")))
+			continue;  //Skip pseudopaths "." and ".."
+		
+		strcpy(info[i].name, dirbuf.name);
+		clear_mcTable(&info[i].stats);
+//		if(dirbuf.stat.mode & FIO_S_IFDIR){  //NB: normal usage (non-vmcfs)
+//			info[i].stats.attrFile = MC_ATTR_norm_folder;
+//		}
+		if(dirbuf.stat.mode & MC_ATTR_SUBDIR){  //NB: vmcfs usage
+			info[i].stats.attrFile = dirbuf.stat.mode;
+		}
+//		else if(dirbuf.stat.mode & FIO_S_IFREG){  //NB: normal usage (non-vmcfs)
+//			info[i].stats.attrFile = MC_ATTR_norm_file;
+//			info[i].stats.fileSizeByte = dirbuf.stat.size;
+//		}
+		else if(dirbuf.stat.mode & MC_ATTR_FILE){  //NB: vmcfs usage
+			info[i].stats.attrFile = dirbuf.stat.mode;
+			info[i].stats.fileSizeByte = dirbuf.stat.size;
+		}
+		else
+			continue; //Skip entry which is neither a file nor a folder
+		strncpy(info[i].stats.name, info[i].name, 32);
+		memcpy((void *) &info[i].stats._create, dirbuf.stat.ctime, 8);
+		memcpy((void *) &info[i].stats._modify, dirbuf.stat.mtime, 8);
+		i++;
+		if(i==max) break;
+	}
+	
+	fileXioDclose(fd);
+
+	size_valid = 1;
+	time_valid = 1;
+
+	return i;
+}
+//------------------------------
+//endfunc readVMC
+//--------------------------------------------------------------
+int readHDD(const char *path, FILEINFO *info, int max)
+{
+	iox_dirent_t dirbuf;
+	char party[MAX_PATH], dir[MAX_PATH];
+	int i=0, fd, ret;
+	
+	if(nparties==0){
+		loadHddModules();
+		setPartyList();
+	}
+	
+	if(!strcmp(path, "hdd0:/")){
+		for(i=0; i<nparties; i++){
+			strcpy(info[i].name, parties[i]);
+			info[i].stats.attrFile = MC_ATTR_norm_folder;
+		}
+		return nparties;
+	}
+	
+	getHddParty(path,NULL,party,dir);
+	ret = mountParty(party);
+	if(ret<0) return 0;
+	dir[3] = ret+'0';
+	
+	if((fd=fileXioDopen(dir)) < 0) return 0;
+	
+	while(fileXioDread(fd, &dirbuf) > 0){
+		if(dirbuf.stat.mode & FIO_S_IFDIR &&
+		(!strcmp(dirbuf.name,".") || !strcmp(dirbuf.name,"..")))
+			continue;  //Skip pseudopaths "." and ".."
+		
+		strcpy(info[i].name, dirbuf.name);
+		clear_mcTable(&info[i].stats);
+		if(dirbuf.stat.mode & FIO_S_IFDIR){
+			info[i].stats.attrFile = MC_ATTR_norm_folder;
+		}
+		else if(dirbuf.stat.mode & FIO_S_IFREG){
+			info[i].stats.attrFile = MC_ATTR_norm_file;
+			info[i].stats.fileSizeByte = dirbuf.stat.size;
+		}
+		else
+			continue; //Skip entry which is neither a file nor a folder
+		strncpy(info[i].stats.name, info[i].name, 32);
+		memcpy((void *) &info[i].stats._create, dirbuf.stat.ctime, 8);
+		memcpy((void *) &info[i].stats._modify, dirbuf.stat.mtime, 8);
+		i++;
+		if(i==max) break;
+	}
+	
+	fileXioDclose(fd);
+
+	size_valid = 1;
+	time_valid = 1;
+
+	return i;
+}
+//------------------------------
+//endfunc readHDD
+//--------------------------------------------------------------
+void scan_USB_mass(void){
+	int i;
+	fio_stat_t chk_stat;
+	char mass_path[8] = "mass0:/";
+
+	if(	(USB_mass_max_drives < 2) //No need for dynamic lists with only one drive
+		||(USB_mass_scanned && ((Timer()-USB_mass_scan_time) < 5000))
+		)
+		return;
+
+	for(i=0; i<USB_mass_max_drives; i++){
+		mass_path[4] = '0'+i;
+		if(fioGetstat(mass_path, &chk_stat) < 0){
+			USB_mass_ix[i] = 0;
+			continue;
+		}
+		USB_mass_ix[i] = '0'+i;
+		USB_mass_scanned =1;
+		USB_mass_scan_time = Timer();
+	}//ends for loop
+}
+//------------------------------
+//endfunc scan_USB_mass
+//--------------------------------------------------------------
+int readMASS(const char *path, FILEINFO *info, int max)
+{
+	fio_dirent_t record;
+	int n=0, dd=-1;
+	
+	loadUsbModules();
+
+	if(!USB_mass_scanned)
+		scan_USB_mass();
+
+	if ((dd = fioDopen(path)) < 0) goto exit;  //exit if error opening directory
+	while(fioDread(dd, &record) > 0){
+		if((FIO_SO_ISDIR(record.stat.mode))
+			&& (!strcmp(record.name,".") || !strcmp(record.name,".."))
+		) continue; //Skip entry if pseudo-folder "." or ".."
+
+		strcpy(info[n].name, record.name);
+		clear_mcTable(&info[n].stats);
+		if(FIO_SO_ISDIR(record.stat.mode)){
+			info[n].stats.attrFile = MC_ATTR_norm_folder;
+		}
+		else if(FIO_SO_ISREG(record.stat.mode)){
+			info[n].stats.attrFile = MC_ATTR_norm_file;
+			info[n].stats.fileSizeByte = record.stat.size;
+		}
+		else
+			continue; //Skip entry which is neither a file nor a folder
+		strncpy(info[n].stats.name, info[n].name, 32);
+		memcpy((void *) &info[n].stats._create, record.stat.ctime, 8);
+		memcpy((void *) &info[n].stats._modify, record.stat.mtime, 8);
+		n++;
+		if(n==max) break;
+	} //ends while
+	size_valid = 1;
+	time_valid = 1;
+
+exit:
+	if(dd >= 0) fioDclose(dd); //Close directory if opened above
+	return n;
+}
+//------------------------------
+//endfunc readMASS
+//--------------------------------------------------------------
+char	*makeHostPath(char *dp, char *sp)
+{
+	int	i;
+	char ch;
+
+	if	(!host_use_Bsl)
+		return strcpy(dp, sp);
+
+	for (i=0; i<MAX_PATH-1; i++)
+	{	ch = sp[i];
+		if	(ch == '/')
+			dp[i] = '\\';
+		else
+			dp[i] = ch;
+		if	(!ch)
+			break;
+	}
+	return dp;
+}
+//--------------------------------------------------------------
+char	*makeFslPath(char *dp, char *sp)
+{
+	int	i;
+	char ch;
+
+	for (i=0; i<MAX_PATH-1; i++)
+	{	ch = sp[i];
+		if	(ch == '\\')
+			dp[i] = '/';
+		else
+			dp[i] = ch;
+		if	(!ch)
+			break;
+	}
+	return dp;
+}
+//--------------------------------------------------------------
+void	initHOST(void)
+{
+	int	fd;
+
+	load_ps2host();
+	host_error = 0;
+	if ((fd = fioOpen("host:elflist.txt", O_RDONLY)) >= 0)
+	{ fioClose(fd);
+		host_elflist = 1;
+	}
+	else
+	{	host_elflist = 0;
+		if ((fd = fioDopen("host:")) >= 0)
+			fioDclose(fd);
+		else
+			host_error = 1;
+	}
+	host_ready = 1;
+}
+//--------------------------------------------------------------
+int	readHOST(const char *path, FILEINFO *info, int max)
+{
+	fio_dirent_t hostcontent;
+	int hfd, rv, size, contentptr, hostcount = 0;
+	char *elflisttxt, elflistchar;
+	char	host_path[MAX_PATH], host_next[MAX_PATH];
+	char	Win_path[MAX_PATH];
+
+	initHOST();
+	snprintf(host_path, MAX_PATH-1, "%s", path);
+	if	(!strncmp(path, "host:/", 6))
+		strcpy(host_path+5, path+6);
+	if	((host_elflist) && !strcmp(host_path, "host:")){
+		if	((hfd = fioOpen("host:elflist.txt", O_RDONLY)) < 0)
+			return 0;
+		if	((size = fioLseek(hfd, 0, SEEK_END)) <= 0)
+		{	fioClose(hfd);
+			return 0;
+		}
+		elflisttxt = (char *)malloc(size);
+		fioLseek(hfd, 0, SEEK_SET);
+		fioRead(hfd, elflisttxt, size);
+		fioClose(hfd);
+		contentptr = 0;
+		for (rv=0;rv<=size;rv++)
+		{	elflistchar = elflisttxt[rv];
+			if	((elflistchar == 0x0a) || (rv == size))
+			{	host_next[contentptr] = 0;
+				snprintf(host_path, MAX_PATH-1, "%s%s", "host:", host_next);
+				clear_mcTable(&info[hostcount].stats);
+				if	((hfd = fioOpen(makeHostPath(Win_path, host_path), O_RDONLY)) >= 0)
+				{	fioClose(hfd);
+					info[hostcount].stats.attrFile = MC_ATTR_norm_file;
+					makeFslPath(info[hostcount++].name, host_next);
+				} else if ((hfd = fioDopen(Win_path)) >= 0)
+				{	fioDclose(hfd);
+					info[hostcount].stats.attrFile = MC_ATTR_norm_folder;
+					makeFslPath(info[hostcount++].name, host_next);
+				}
+				contentptr = 0;
+				if	(hostcount > max)
+					break;
+			}
+			else if	(elflistchar != 0x0d)
+			{	host_next[contentptr]=elflistchar;
+				contentptr++;
+			}
+		}
+		free(elflisttxt);
+		return hostcount-1;
+	}
+	//This point is only reached if elflist.txt is NOT to be used
+
+	if ((hfd = fioDopen(makeHostPath(Win_path, host_path))) < 0)
+		return 0;
+	strcpy(host_path, Win_path);
+	while ((rv = fioDread(hfd, &hostcontent)))
+	{	if (strcmp(hostcontent.name, ".")&&strcmp(hostcontent.name, ".."))
+		{
+			size_valid = 1;
+			time_valid = 1;
+			snprintf(Win_path, MAX_PATH-1, "%s%s", host_path, hostcontent.name);
+			strcpy(info[hostcount].name, hostcontent.name);
+			clear_mcTable(&info[hostcount].stats);
+
+			if(!(hostcontent.stat.mode & FIO_SO_IFDIR)) //if not a directory
+				info[hostcount].stats.attrFile = MC_ATTR_norm_file;
+			else
+				info[hostcount].stats.attrFile = MC_ATTR_norm_folder;
+
+			info[hostcount].stats.fileSizeByte = hostcontent.stat.size;
+			memcpy((void *) &info[hostcount].stats._create, hostcontent.stat.ctime, 8);
+			info[hostcount].stats._create.year += 1900;
+			memcpy((void *) &info[hostcount].stats._modify, hostcontent.stat.mtime, 8);
+			info[hostcount].stats._modify.year += 1900;
+			hostcount++;
+			if (hostcount >= max)
+				break;
+		}
+	}
+	fioDclose(hfd);
+	strcpy (info[hostcount].name, "\0");
+	return hostcount;
+}
+//------------------------------
+//endfunc readHOST
+//--------------------------------------------------------------
+int getDir(const char *path, FILEINFO *info)
+{
+	int max=MAX_ENTRY-2;
+	int n;
+	
+	if(!strncmp(path, "mc", 2))			n=readMC(path, info, max);
+	else if(!strncmp(path, "hdd", 3))	n=readHDD(path, info, max);
+	else if(!strncmp(path, "mass", 4))	n=readMASS(path, info, max);
+	else if(!strncmp(path, "cdfs", 4))	n=readCD(path, info, max);
+	else if(!strncmp(path, "host", 4))	n=readHOST(path, info, max);
+	else if(!strncmp(path, "vmc", 3))	n=readVMC(path, info, max);
+	else return 0;
+	
+	return n;
+}
+//--------------------------------------------------------------
+// getGameTitle below is used to extract the real save title of
+// an MC gamesave folder. Normally this is held in the icon.sys
+// file of a PS2 game save, but that is not the case for saves
+// on a PS1 MC, or similar saves backed up to a PS2 MC. Two new
+// methods need to be used to extract such titles correctly, and
+// these were added in v3.62, by me (dlanor).
+// From v3.91 This routine also extracts titles from PSU files.
+//--------------------------------------------------------------
+int getGameTitle(const char *path, const FILEINFO *file, char *out)
+{
+	char party[MAX_NAME], dir[MAX_PATH], tmpdir[MAX_PATH];
+	int fd=-1, size, hddin=FALSE, ret;
+	psu_header PSU_head;
+	int i, tst, PSU_content, psu_pad_pos;
+	char *cp;
+
+	out[0] = '\0'; //Start by making an empty result string, for failures
+
+	//Avoid title usage in browser root or partition list
+	if(path[0]==0 || !strcmp(path,"hdd0:/")) return -1;
+
+	if(!strncmp(path, "hdd", 3)){
+		ret = getHddParty(path, file, party, dir);
+		if((ret = mountParty(party)<0))
+			return -1;
+		dir[3]=ret+'0';
+		hddin=TRUE;
+	}else{
+		strcpy(dir, path);
+		strcat(dir, file->name);
+		if(file->stats.attrFile & MC_ATTR_SUBDIR) strcat(dir, "/");
+	}
+
+	ret = -1;  //Assume that result will be failure, to simplify aborts
+
+	if((file->stats.attrFile & MC_ATTR_SUBDIR)==0){
+		//Here we know that the object needing a title is a file
+		strcpy(tmpdir, dir);				//Copy the pathname for file access
+		cp = strrchr(tmpdir, '.');  //Find the extension, if any
+		if((cp==NULL) || stricmp(cp, ".psu") ) //If it's anything other than a PSU file
+			goto get_PS1_GameTitle;              //then it may be a PS1 save
+		//Here we know that the object needing a title is a PSU file
+		if((fd=genOpen(tmpdir, O_RDONLY)) < 0) goto finish;  //Abort if open fails
+		tst = genRead(fd, (void *) &PSU_head, sizeof(PSU_head));
+		if(tst != sizeof(PSU_head)) goto finish; //Abort if read fails
+		PSU_content = PSU_head.size;
+		for(i=0; i<PSU_content; i++){
+			tst = genRead(fd, (void *) &PSU_head, sizeof(PSU_head));
+			if(tst != sizeof(PSU_head)) goto finish; //Abort if read fails
+			PSU_head.name[sizeof(PSU_head.name)] = '\0';
+			if(!strcmp(PSU_head.name, "icon.sys")) {
+				genLseek(fd, 0xC0, SEEK_CUR);
+				goto read_title;
+			}
+			if(PSU_head.size){
+				psu_pad_pos = (PSU_head.size + 0x3FF) & -0x400;
+				genLseek(fd, psu_pad_pos, SEEK_CUR);
+			}
+			//Here the PSU file pointer is positioned for reading next header
+		}//ends for
+		//Coming here means that the search for icon.sys failed
+		goto finish;  //So go finish off this function
+	}//ends if clause for files needing a title
+
+	//Here we know that the object needing a title is a folder
+	//First try to find a valid PS2 icon.sys file inside the folder
+	strcpy(tmpdir, dir);
+	strcat(tmpdir, "icon.sys");
+	if((fd=genOpen(tmpdir, O_RDONLY)) >= 0){
+		if((size=genLseek(fd,0,SEEK_END)) <= 0x100) goto finish;
+		genLseek(fd,0xC0,SEEK_SET);
+		goto read_title;
+	}
+	//Next try to find a valid PS1 savefile inside the folder instead
+	strcpy(tmpdir, dir);
+	strcat(tmpdir, file->name);  //PS1 save file should have same name as folder
+
+get_PS1_GameTitle:
+	if((fd=genOpen(tmpdir, O_RDONLY)) < 0) goto finish;  //PS1 gamesave file needed
+	if((size=genLseek(fd,0,SEEK_END)) < 0x2000) goto finish;  //Min size is 8K
+	if(size & 0x1FFF) goto finish;  //Size must be a multiple of 8K
+	genLseek(fd, 0, SEEK_SET);
+	genRead(fd, out, 2);
+	if(strncmp(out, "SC", 2)) goto finish;  //PS1 gamesaves always start with "SC"
+	genLseek(fd, 4, SEEK_SET);
+
+read_title:
+	genRead(fd, out, 32*2);
+	out[32*2] = 0;
+	genClose(fd); fd=-1;
+	ret=0;
+
+finish:
+	if(fd>=0)
+		genClose(fd);
+	return ret;
+}
+//--------------------------------------------------------------
+int menu(const char *path, FILEINFO *file)
+{
+	u64 color;
+	char enable[NUM_MENU], tmp[80];
+	int x, y, i, sel;
+	int event, post_event = 0;
+	int menu_disabled = 0;
+	int write_disabled = 0;
+	
+	int menu_len=strlen(LNG(Copy))>strlen(LNG(Cut))?
+		strlen(LNG(Copy)):strlen(LNG(Cut));
+	menu_len=strlen(LNG(Paste))>menu_len? strlen(LNG(Paste)):menu_len;
+	menu_len=strlen(LNG(Delete))>menu_len? strlen(LNG(Delete)):menu_len;
+	menu_len=strlen(LNG(Rename))>menu_len? strlen(LNG(Rename)):menu_len;
+	menu_len=strlen(LNG(New_Dir))>menu_len? strlen(LNG(New_Dir)):menu_len;
+	menu_len=strlen(LNG(Get_Size))>menu_len? strlen(LNG(Get_Size)):menu_len;
+	menu_len=strlen(LNG(mcPaste))>menu_len? strlen(LNG(mcPaste)):menu_len;
+	menu_len=strlen(LNG(psuPaste))>menu_len? strlen(LNG(psuPaste)):menu_len;
+	menu_len=(strlen(LNG(Mount))+6)>menu_len? (strlen(LNG(Mount))+6):menu_len;
+
+	int menu_ch_w = menu_len+1;    //Total characters in longest menu string
+	int menu_ch_h = NUM_MENU;      //Total number of menu lines
+	int mSprite_Y1 = 64;           //Top edge of sprite
+	int mSprite_X2 = SCREEN_WIDTH-35;   //Right edge of sprite
+	int mSprite_X1 = mSprite_X2-(menu_ch_w+3)*FONT_WIDTH;   //Left edge of sprite
+	int mSprite_Y2 = mSprite_Y1+(menu_ch_h+1)*FONT_HEIGHT;  //Bottom edge of sprite
+
+	memset(enable, TRUE, NUM_MENU); //Assume that all menu items are legal by default
+
+	//identify cases where write access is illegal, and disable menu items accordingly
+	if(	(!strncmp(path,"cdfs",4)) //Writing is always illegal for CDVD drive
+		||(	(!strncmp(path,"host",4)) //host: has special cases
+			&&(	(!setting->HOSTwrite)		//host: Writing is illegal if not enabled in CNF
+				||(host_elflist && !strcmp(path, "host:/")) //it's also illegal in elflist.txt
+		)	)	) write_disabled = 1;
+
+	if(	!strcmp(path,"hdd0:/") || path[0]==0) //No menu cmds in partition/device lists
+		menu_disabled = 1;
+	
+	if(menu_disabled) {
+		enable[COPY] = FALSE;
+		enable[MOUNTVMC0]=FALSE;
+		enable[MOUNTVMC1]=FALSE;
+		enable[GETSIZE] = FALSE;
+	}
+
+	if(write_disabled || menu_disabled){
+		enable[CUT] = FALSE;
+		enable[PASTE] = FALSE;
+		enable[MCPASTE] = FALSE;
+		enable[PSUPASTE] = FALSE;
+		enable[DELETE] = FALSE;
+		enable[RENAME] = FALSE;
+		enable[NEWDIR] = FALSE;
+		enable[NEWICON] = FALSE;
+	}
+
+	if(!strncmp(path, "mass", 4)){
+		enable[RENAME] = FALSE;
+	}
+
+/* commented due to MC modules by jimmikaelkael (allow rename)
+	if(!strncmp(path, "mc", 2)){
+		int test;
+
+		mcGetInfo(path[2]-'0', 0, &mctype_PSx, NULL, NULL);
+		mcSync(0, NULL, &test);
+		if (mctype_PSx == 2) //PS2 MC ?
+			enable[RENAME] = FALSE;
+	}
+*/
+
+	if(nmarks==0){
+		if(!strcmp(file->name, "..")){
+			enable[COPY] = FALSE;
+			enable[CUT] = FALSE;
+			enable[DELETE] = FALSE;
+			enable[RENAME] = FALSE;
+			enable[GETSIZE] = FALSE;
+		}
+	}else{
+		enable[RENAME] = FALSE;
+	}
+
+	if((file->stats.attrFile & MC_ATTR_SUBDIR)
+		|| !strncmp(path, "vmc", 3)
+		|| !strncmp(path, "mc", 2)
+		){
+			enable[MOUNTVMC0]=FALSE; //forbid insane VMC mounting
+			enable[MOUNTVMC1]=FALSE; //forbid insane VMC mounting
+		}
+
+	if(nclipFiles==0){
+		//Nothing in clipboard
+		enable[PASTE] = FALSE;
+		enable[MCPASTE] = FALSE;
+		enable[PSUPASTE] = FALSE;
+	} else {
+		//Something in clipboard
+		if(!strncmp(path, "mc", 2) || !strncmp(path, "vmc", 3)){
+			if(!strncmp(clipPath, "mc", 2) || !strncmp(clipPath, "vmc", 3)){
+				enable[MCPASTE] = FALSE;  //No mcPaste if both src and dest are MC
+				enable[PSUPASTE] = FALSE;
+			}
+		}	else
+			if(strncmp(clipPath, "mc", 2) && strncmp(clipPath, "vmc", 3)){
+				enable[MCPASTE] = FALSE;  //No mcPaste if both src and dest non-MC
+				enable[PSUPASTE] = FALSE;
+			}
+	}
+
+	for(sel=0; sel<NUM_MENU; sel++) //loop to preselect the first enabled menu entry
+		if(enable[sel]==TRUE) break;  //break loop if sel is at an enabled menu entry
+	
+	event = 1;  //event = initial entry
+	while(1){
+		//Pad response section
+		waitPadReady(0, 0);
+		if(readpad()){
+			if(new_pad & PAD_UP && sel<NUM_MENU){
+				event |= 2;  //event |= valid pad command
+				do{
+					sel--;
+					if(sel<0) sel=NUM_MENU-1;
+				}while(!enable[sel]);
+			}else if(new_pad & PAD_DOWN && sel<NUM_MENU){
+				event |= 2;  //event |= valid pad command
+				do{
+					sel++;
+					if(sel==NUM_MENU) sel=0;
+				}while(!enable[sel]);
+			}else if((new_pad & PAD_TRIANGLE)
+						|| (!swapKeys && new_pad & PAD_CROSS)
+			      || (swapKeys && new_pad & PAD_CIRCLE) ){
+				return -1;
+			}else if((swapKeys && new_pad & PAD_CROSS)
+			      || (!swapKeys && new_pad & PAD_CIRCLE) ){
+				event |= 2;  //event |= valid pad command
+				break;
+			}else if(new_pad & PAD_SQUARE && sel==PASTE){
+				event |= 2;  //event |= valid pad command
+				break;
+			}
+		}
+
+		if(event||post_event){ //NB: We need to update two frame buffers per event
+
+			//Display section
+			drawPopSprite(setting->color[0],
+				mSprite_X1, mSprite_Y1,
+				mSprite_X2, mSprite_Y2);
+			drawFrame(mSprite_X1, mSprite_Y1, mSprite_X2, mSprite_Y2, setting->color[1]);
+
+			for(i=0,y=mSprite_Y1+FONT_HEIGHT/2; i<NUM_MENU; i++){
+				if(i==COPY)			strcpy(tmp, LNG(Copy));
+				else if(i==CUT)		strcpy(tmp, LNG(Cut));
+				else if(i==PASTE)	strcpy(tmp, LNG(Paste));
+				else if(i==MCPASTE)	strcpy(tmp, LNG(mcPaste));
+				else if(i==PSUPASTE)	strcpy(tmp, LNG(psuPaste));
+				else if(i==DELETE)	strcpy(tmp, LNG(Delete));
+				else if(i==RENAME)	strcpy(tmp, LNG(Rename));
+				else if(i==NEWDIR)	strcpy(tmp, LNG(New_Dir));
+				else if(i==NEWICON)	strcpy(tmp, LNG(New_Icon));
+				else if(i==MOUNTVMC0) sprintf(tmp, "%s vmc0:", LNG(Mount));
+				else if(i==MOUNTVMC1) sprintf(tmp, "%s vmc1:", LNG(Mount));
+				else if(i==GETSIZE) strcpy(tmp, LNG(Get_Size));
+
+				if(enable[i])	color = setting->color[3];
+				else			color = setting->color[1];
+
+				printXY(tmp, mSprite_X1+2*FONT_WIDTH, y, color, TRUE,0);
+				y+=FONT_HEIGHT;
+			}
+			if(sel<NUM_MENU)
+				drawChar(LEFT_CUR, mSprite_X1+FONT_WIDTH, mSprite_Y1+(FONT_HEIGHT/2+sel*FONT_HEIGHT), setting->color[3]);
+
+			//Tooltip section
+			x = SCREEN_MARGIN;
+			y = Menu_tooltip_y;
+			drawSprite(setting->color[0],
+				0, y-1,
+				SCREEN_WIDTH, y+FONT_HEIGHT);
+			if (swapKeys)
+				sprintf(tmp, "ÿ1:%s ÿ0:%s", LNG(OK), LNG(Cancel));
+			else
+				sprintf(tmp, "ÿ0:%s ÿ1:%s", LNG(OK), LNG(Cancel));
+			if(sel==PASTE)
+				sprintf(tmp+strlen(tmp), " ÿ2:%s", LNG(PasteRename));
+			sprintf(tmp+strlen(tmp), " ÿ3:%s", LNG(Back));
+			printXY(tmp, x, y, setting->color[2], TRUE, 0);
+		}//ends if(event||post_event)
+		drawScr();
+		post_event = event;
+		event = 0;
+	}//ends while
+	return sel;
+}//ends menu
+//--------------------------------------------------------------
+char *PathPad_menu(const char *path)
+{
+	u64 color;
+	int x, y, dx, dy, dw, dh;
+	int a=6, b=4, c=2, tw, th;
+	int i, sel_x, sel_y;
+	int event, post_event=0;
+	char textrow[80], tmp[64];
+
+	th = 10*FONT_HEIGHT; //Height in pixels of text area
+	tw = 68*FONT_WIDTH;  //Width in pixels of max text row
+	dh = th+2*2+a+b+c; //Height in pixels of entire frame
+	dw = tw+2*2+a*2;     //Width in pixels of entire frame
+	dx = (SCREEN_WIDTH-dw)/2;  //X position of frame (centred)
+	dy = (SCREEN_HEIGHT-dh)/2; //Y position of frame (centred)
+	
+	sel_x=0; sel_y=0;
+	event = 1;  //event = initial entry
+	while(1){
+		//Pad response section
+		waitPadReady(0, 0);
+		if(readpad()){
+			if(new_pad){
+				event |= 2;  //event |= valid pad command
+				if(new_pad & PAD_UP){
+					sel_y--;
+					if(sel_y<0)
+						sel_y=9;
+				}else if(new_pad & PAD_DOWN){
+					sel_y++;
+					if(sel_y>9)
+						sel_y=0;
+				}else if(new_pad & PAD_LEFT){
+					sel_y -= 5;
+					if(sel_y<0)
+						sel_y=0;
+				}else if(new_pad & PAD_RIGHT){
+					sel_y += 5;
+					if(sel_y>9)
+						sel_y=9;
+				}else if(new_pad & PAD_L1){
+					sel_x--;
+					if(sel_x<0)
+						sel_x=2;
+				}else if(new_pad & PAD_R1){
+					sel_x++;
+					if(sel_x>2)
+						sel_x=0;
+				}else if(new_pad & PAD_TRIANGLE){ //Pushed 'Back'
+					return NULL;
+				}else if(!setting->PathPad_Lock  //if PathPad changes allowed ?
+				      && ( (!swapKeys && new_pad & PAD_CROSS)
+				         ||(swapKeys && new_pad & PAD_CIRCLE) )) {//Pushed 'Clear'
+					PathPad[sel_x*10+sel_y][0] = '\0';
+				}else if((swapKeys && new_pad & PAD_CROSS)
+				      || (!swapKeys && new_pad & PAD_CIRCLE) ){//Pushed 'Use'
+					return PathPad[sel_x*10+sel_y];
+				}else if(!setting->PathPad_Lock && (new_pad & PAD_SQUARE)){//Pushed 'Set'
+					strncpy(PathPad[sel_x*10+sel_y], path, MAX_PATH-1);
+					PathPad[sel_x*10+sel_y][MAX_PATH-1]='\0';
+				}
+			}//ends 'if(new_pad)'
+		}//ends 'if(readpad())'
+
+		if(event||post_event){ //NB: We need to update two frame buffers per event
+
+			//Display section
+			drawSprite(setting->color[0],
+				0, (Menu_message_y-1),
+				SCREEN_WIDTH, (Frame_start_y));
+			drawPopSprite(setting->color[0],
+				dx, dy,
+				dx+dw, (dy+dh));
+			drawFrame(dx, dy, dx+dw, (dy+dh), setting->color[1]);
+			for(i=0; i<10; i++){
+				if(i==sel_y)
+					color=setting->color[2];
+				else
+					color=setting->color[3];
+				sprintf(textrow, "%02d=", (sel_x*10+i));
+				strncat(textrow, PathPad[sel_x*10+i], 64);
+				textrow[67] = '\0';
+				printXY(textrow, dx+2+a,(dy+a+2+i*FONT_HEIGHT), color,TRUE,0);
+			}
+
+			//Tooltip section
+			x = SCREEN_MARGIN;
+			y = Menu_tooltip_y;
+			drawSprite(setting->color[0], 0, y-1, SCREEN_WIDTH, y+FONT_HEIGHT);
+
+			if(swapKeys) {
+				sprintf(textrow, "ÿ1:%s ", LNG(Use));
+				if(!setting->PathPad_Lock){
+					sprintf(tmp, "ÿ0:%s ÿ2:%s ", LNG(Clear), LNG(Set));
+					strcat(textrow, tmp);
+				}
+			} else {
+				sprintf(textrow, "ÿ0:%s ", LNG(Use));
+				if(!setting->PathPad_Lock){
+					sprintf(tmp, "ÿ1:%s ÿ2:%s ", LNG(Clear), LNG(Set));
+					strcat(textrow, tmp);
+				}
+			}
+			sprintf(tmp, "ÿ3:%s L1/R1:%s", LNG(Back), LNG(Page_leftright));
+			strcat(textrow, tmp);
+			printXY(textrow, x, y, setting->color[2], TRUE, 0);
+		}//ends if(event||post_event)
+		drawScr();
+		post_event = event;
+		event = 0;
+	}//ends while
+}
+//------------------------------
+//endfunc PathPad_menu
+//--------------------------------------------------------------
+s64 getFileSize(const char *path, const FILEINFO *file)
+{
+	s64 size, filesize;
+	FILEINFO files[MAX_ENTRY];
+	char dir[MAX_PATH], party[MAX_NAME];
+	int nfiles, i, ret, fd;
+	
+	if(file->stats.attrFile & MC_ATTR_SUBDIR){ //Folder object to size up
+		sprintf(dir, "%s%s/", path, file->name);
+		nfiles = getDir(dir, files);
+		for(i=size=0; i<nfiles; i++){
+			filesize=getFileSize(dir, &files[i]); //recurse for each object in folder
+			if(filesize < 0) return -1;
+			else		size += filesize;
+		}
+	} else {                                   //File object to size up
+		if(!strncmp(path, "hdd", 3)){
+			getHddParty(path,file,party,dir);
+			ret = mountParty(party);
+			if(ret<0) return 0;
+			dir[3] = ret+'0';
+		}else
+			sprintf(dir, "%s%s", path, file->name);
+		if	(!strncmp(dir, "host:/", 6))
+			makeHostPath(dir+5, dir+6);
+		if(!strncmp(path, "hdd", 3) || !strncmp(path, "vmc", 3)){
+			fd = fileXioOpen(dir, O_RDONLY, fileMode);
+			size = fileXioLseek(fd,0,SEEK_END);
+			fileXioClose(fd);
+		}else{
+			fd = fioOpen(dir, O_RDONLY);
+			size = fioLseek(fd,0,SEEK_END);
+			fioClose(fd);
+		}
+	}
+	return size;
+}
+//------------------------------
+//endfunc getFileSize
+//--------------------------------------------------------------
+int delete(const char *path, const FILEINFO *file)
+{
+	FILEINFO files[MAX_ENTRY];
+	char party[MAX_NAME], dir[MAX_PATH], hdddir[MAX_PATH];
+	int nfiles, i, ret;
+	
+	if(!strncmp(path, "hdd", 3)){
+		getHddParty(path,file,party,hdddir);
+		ret = mountParty(party);
+		if(ret<0) return 0;
+		hdddir[3] = ret+'0';
+	}
+	sprintf(dir, "%s%s", path, file->name);
+	genLimObjName(dir, 0);
+	if	(!strncmp(dir, "host:/", 6))
+		makeHostPath(dir+5, dir+6);
+	
+	if(file->stats.attrFile & MC_ATTR_SUBDIR){ //Is the object to delete a folder ?
+		strcat(dir,"/");
+		nfiles = getDir(dir, files);
+		for(i=0; i<nfiles; i++){
+			ret=delete(dir, &files[i]);            //recursively delete contents of folder
+			if(ret < 0) return -1;
+		}
+		if(!strncmp(dir, "mc", 2)){
+			mcSync(0,NULL,NULL);
+			mcDelete(dir[2]-'0', 0, &dir[4]);
+			mcSync(0, NULL, &ret);
+
+		}else if(!strncmp(path, "hdd", 3)){
+			ret = fileXioRmdir(hdddir);
+
+		}else if(!strncmp(path, "vmc", 3)){
+			ret = fileXioRmdir(dir);
+			(void) fileXioDevctl("vmc0:", DEVCTL_VMCFS_CLEAN, NULL, 0, NULL, 0);
+
+		}else if(!strncmp(path, "mass", 4)){
+			char *pathSep;
+
+			pathSep = strchr(path, '/');
+			strcpy(dir, path);
+			strcat(dir, file->name);
+			ret = fioRmdir(dir);
+			if((ret < 0) && (dir[4] == ':')){
+				sprintf(dir, "mass0:%s%s", &path[5], file->name);
+				ret = fioRmdir(dir);
+			}
+
+		}else if(!strncmp(path, "host", 4)){
+			sprintf(dir, "%s%s", path, file->name);
+			ret = fioRmdir(dir);
+		}
+	} else {                                   //The object to delete is a file
+		if(!strncmp(path, "mc", 2)){
+			mcSync(0,NULL,NULL);
+			mcDelete(dir[2]-'0', 0, &dir[4]);
+			mcSync(0, NULL, &ret);
+		}else if(!strncmp(path, "hdd", 3)){
+			ret = fileXioRemove(hdddir);
+		}else if(!strncmp(path, "vmc", 3)){
+			ret = fileXioRemove(dir);
+			(void) fileXioDevctl("vmc0:", DEVCTL_VMCFS_CLEAN, NULL, 0, NULL, 0);
+		}else if((!strncmp(path, "mass", 4)) || (!strncmp(path, "host", 4))){
+			ret = fioRemove(dir);
+		}
+	}
+	return ret;
+}
+//--------------------------------------------------------------
+int Rename(const char *path, const FILEINFO *file, const char *name)
+{
+	char party[MAX_NAME], oldPath[MAX_PATH], newPath[MAX_PATH];
+	int test, ret=0;
+	
+	if(!strncmp(path, "hdd", 3)){
+		sprintf(party, "hdd0:%s", &path[6]);
+		*strchr(party, '/')=0;
+		sprintf(oldPath, "pfs0:%s", strchr(&path[6], '/')+1);
+		sprintf(newPath, "%s%s", oldPath, name);
+		strcat(oldPath, file->name);
+		
+		ret = mountParty(party);
+		if(ret<0) return -1;
+		oldPath[3] = newPath[3] = ret+'0';
+		
+		ret=fileXioRename(oldPath, newPath);
+	}else if(!strncmp(path, "vmc", 3)){
+		sprintf(oldPath, "%s%s", path, file->name);
+		sprintf(newPath, "%s%s", path, name);
+		ret=fileXioRename(oldPath, newPath);
+	}else if(!strncmp(path, "mc", 2)){
+		sprintf(oldPath, "%s%s", path, file->name);
+		sprintf(newPath, "%s%s", path, name);
+		if((test=fioDopen(newPath))>=0){ //Does folder of same name exist ?
+			fioDclose(test);
+			ret = -17;
+		}else if((test=fioOpen(newPath, O_RDONLY))>=0){ //Does file of same name exist ?
+			fioClose(test);
+			ret = -17;
+		}else{ //No file/folder of the same name exists
+			mcGetInfo(path[2]-'0', 0, &mctype_PSx, NULL, NULL);
+			mcSync(0, NULL, &test);
+			if (mctype_PSx == 2) //PS2 MC ?
+				strncpy((void *)file->stats.name, name, 32);
+				mcSetFileInfo(path[2]-'0', 0, oldPath+4, &file->stats, 0x0010); //Fix file stats
+				mcSync(0, NULL, &test);
+				if(ret == -4)
+					ret = -17;
+			else{               //PS1 MC !
+				strncpy((void *)file->stats.name, name, 32);
+				mcSetFileInfo(path[2]-'0', 0, oldPath+4, &file->stats, 0x0010); //Fix file stats
+				mcSync(0, NULL, &test);
+				if(ret == -4)
+					ret = -17;
+			}
+		}
+	}else if(!strncmp(path, "host", 4)){
+		int temp_fd;
+
+		strcpy(oldPath, path);
+		if(!strncmp(oldPath, "host:/", 6))
+			makeHostPath(oldPath+5, oldPath+6);
+		strcpy(newPath, oldPath+5);
+		strcat(oldPath, file->name);
+		strcat(newPath, name);
+		if(file->stats.attrFile & MC_ATTR_SUBDIR){ //Rename a folder ?
+			ret = (temp_fd = fioDopen(oldPath));
+			if (temp_fd >= 0){
+				ret = fioIoctl(temp_fd, IOCTL_RENAME, (void *) newPath);
+				fioDclose(temp_fd);
+			}
+		} else if(file->stats.attrFile & MC_ATTR_FILE){ //Rename a file ?
+			ret = (temp_fd = fioOpen(oldPath, O_RDONLY));
+			if (temp_fd >= 0){
+				ret = fioIoctl(temp_fd, IOCTL_RENAME, (void *) newPath);
+				fioClose(temp_fd);
+			}
+		} else  //This was neither a folder nor a file !!!
+			return -1;
+	} else  //The device was not recognized
+		return -1;
+		
+	return ret;
+}
+
+//--------------------------------------------------------------
+int newdir(const char *path, const char *name)
+{
+	char party[MAX_NAME], dir[MAX_PATH];
+	int ret=0;
+	
+	if(!strncmp(path, "hdd", 3)){
+		getHddParty(path,NULL,party,dir);
+		ret = mountParty(party);
+		if(ret<0) return -1;
+		dir[3] = ret+'0';
+		//fileXioChdir(dir);
+		strcat(dir, name);
+		genLimObjName(dir, 0);
+		ret = fileXioMkdir(dir, fileMode);
+	}else if(!strncmp(path, "vmc", 3)){
+		strcpy(dir, path);
+		strcat(dir, name);
+		genLimObjName(dir, 0);
+		if((ret = fileXioDopen(dir)) >= 0){
+			fileXioDclose(ret);
+			ret = -17;					//return fileXio error code for pre-existing folder
+		} else {
+			ret = fileXioMkdir(dir, fileMode);
+		}
+	}else if(!strncmp(path, "mc", 2)){
+		sprintf(dir, "%s%s", path+4, name);
+		genLimObjName(dir, 0);
+		mcSync(0,NULL,NULL);
+		mcMkDir(path[2]-'0', 0, dir);
+		mcSync(0, NULL, &ret);
+		if(ret == -4)
+			ret = -17;					//return fileXio error code for pre-existing folder
+	}else if(!strncmp(path, "mass", 4)){
+		strcpy(dir, path);
+		strcat(dir, name);
+		genLimObjName(dir, 0);
+		ret = fioMkdir(dir);
+	}else if(!strncmp(path, "host", 4)){
+		strcpy(dir, path);
+		strcat(dir, name);
+		genLimObjName(dir, 0);
+		if(!strncmp(dir, "host:/", 6))
+			makeHostPath(dir+5, dir+6);
+		if((ret = fioDopen(dir)) >= 0){
+			fioDclose(ret);
+			ret = -17;					//return fileXio error code for pre-existing folder
+		} else {
+			ret = fioMkdir(dir);//Create the new folder
+		}
+	} else {                //Device not recognized
+		ret = -1;
+	}
+	return ret;
+}
+//--------------------------------------------------------------
+//The function 'copy' below is called to copy a single object,
+//indicated by 'file' from 'inPath' to 'outPath', but this may
+//be either a single file or a folder. In the latter case the
+//folder contents should also be copied, recursively.
+//--------------------------------------------------------------
+int copy(char *outPath, const char *inPath, FILEINFO file, int recurses)
+{
+	FILEINFO newfile, files[MAX_ENTRY];
+	fio_stat_t fio_stat;
+	iox_stat_t iox_stat;
+	char out[MAX_PATH], in[MAX_PATH], tmp[MAX_PATH],
+		progress[MAX_PATH*4],
+		*buff=NULL, inParty[MAX_NAME], outParty[MAX_NAME];
+	int hddout=FALSE, hddin=FALSE, nfiles, i;
+	size_t size, outsize;
+	int ret=-1, pfsout=-1, pfsin=-1, in_fd=-1, out_fd=-1, buffSize;
+	int dummy;
+	mcTable stats;
+	int speed=0;
+	int remain_time=0, TimeDiff=0;
+	long old_size=0, SizeDiff=0;
+	u64 OldTime=0LL;
+	psu_header PSU_head;
+	mcT_header *mcT_head_p = (mcT_header *) &file.stats;
+	mcT_header *mcT_files_p = (mcT_header *) &files[0].stats;
+	int psu_pad_size = 0, PSU_restart_f = 0;
+	char *cp, *np;
+
+	PM_flag[recurses+1] = PM_NORMAL;  //assume normal mode for next level
+	PM_file[recurses+1] = -1;         //assume that no special file is needed
+
+restart_copy: //restart point for PM_PSU_RESTORE to reprocess modified arguments
+
+	newfile = file;                   //assume that no renaming is to be done
+
+	if(PasteMode==PM_RENAME && recurses==0){ //if renaming requested and valid
+		if(keyboard(newfile.name, 36)<=0)   //if name entered by user made the result invalid
+			strcpy(newfile.name, file.name);  //  recopy newname from file.name
+	} //ends if clause for renaming name entry
+	//Here the struct 'newfile' is FILEINFO for destination, regardless of renaming
+	//for non-renaming cases this is always identical to the struct 'file'
+
+	if(!strncmp(inPath, "hdd", 3)){
+		hddin = TRUE;
+		getHddParty(inPath, &file, inParty, in);
+		pfsin = mountParty(inParty);
+		in[3]=pfsin+'0';
+	}else
+		sprintf(in, "%s%s", inPath, file.name);
+
+	if(!strncmp(outPath, "hdd", 3)){
+		hddout = TRUE;
+		getHddParty(outPath, &newfile, outParty, out);
+		pfsout = mountParty(outParty);
+		out[3]=pfsout+'0';
+	}else
+		sprintf(out, "%s%s", outPath, newfile.name);
+
+	if(!strcmp(in, out)) return 0;  //if in and out are identical our work is done.
+
+//Here 'in' and 'out' are complete pathnames for the object to copy
+//patched to contain appropriate 'pfs' refs where args used 'hdd'
+//The physical device specifiers remain in 'inPath' and 'outPath'
+
+//Here we have an object to copy, which may be either a file or a folder
+	if(file.stats.attrFile & MC_ATTR_SUBDIR){
+//Here we have a folder to copy, starting with an attempt to create it
+//This is where we must act differently for PSU backup, creating a PSU file instead
+		if(PasteMode==PM_PSU_BACKUP){
+			if(recurses)
+				return -1;  //abort, as subfolders are not copied to PSU backups
+			i = strlen(out)-1;
+			if(out[i]=='/')
+				out[i] = 0;
+			strcpy(tmp, out);
+			np = tmp+strlen(tmp)-strlen(file.name); //np = start of the pure filename
+			cp = tmp+strlen(tmp);                      //cp = end of the pure filename
+			if(!setting->PSU_HugeNames)
+				cp = np;                              //cp = start of the pure filename
+
+			if((file_show==2) || setting->PSU_HugeNames){ //at request, use game title
+				ret = getGameTitle(inPath, &file, file.title);
+				if((ret == 0) && file.title[0] && setting->PSU_HugeNames){
+					*cp++ = '_';
+					*cp = '\0';
+				}
+				transcpy_sjis(cp, file.title);
+			}
+			//Here game title has been used for the name if requested, either alone
+			//or combined with the original folder name (for PSU_HugeNames)
+
+			if(np[0] == 0)						//If name is now empty (bad gamesave title)
+				strcpy(np, file.name);  //revert to normal folder name
+
+			for(i=0; np[i];) {
+				i = strcspn(np, "\"\\/:*?<>|");	//Filter out illegal name characters
+				if(np[i])
+					np[i] = '_';
+			}
+			//Here illegal characters, from either title or original folder name
+			//have been filtered out (replaced by underscore) to ensure compatibility
+
+			cp = tmp+strlen(tmp); //set cp pointing to the end of the filename
+			if(setting->PSU_DateNames){ //at request, append modification timestamp string
+				sprintf(cp, "_%04d-%02d-%02d_%02d-%02d-%02d",
+					mcT_head_p->mTime.year, mcT_head_p->mTime.month, mcT_head_p->mTime.day,
+					mcT_head_p->mTime.hour, mcT_head_p->mTime.min, mcT_head_p->mTime.sec);
+			}
+			//Here a timestamp has been added to the name if requested by PSU_DateNames
+
+			genLimObjName(tmp, 4); //Limit name to leave room for 4 characters more
+			strcat(tmp, ".psu");	//add the PSU file extension
+
+			if(!strncmp(tmp, "host:/", 6))
+				makeHostPath(tmp+5, tmp+6);
+
+			if(setting->PSU_DateNames && setting->PSU_NoOverwrite){
+				if(0 <= (out_fd = genOpen(tmp, O_RDONLY))){ //Name conflict ?
+					genClose(out_fd);
+					out_fd=-1;
+					return 0;
+				}
+			}
+			//here tmp is the name of an existing file, to be removed before making new one
+			genRemove(tmp);
+			if(0 > (out_fd = genOpen(tmp, O_WRONLY | O_TRUNC | O_CREAT)))
+				return -1;	//return error on failure to create PSU file
+
+			PM_file[recurses+1] = out_fd;
+			PM_flag[recurses+1] = PM_PSU_BACKUP; //Set PSU backup mode for next level
+			clear_psu_header(&PSU_head);
+			PSU_content = 2;                //2 content headers minimum, for empty PSU
+			PSU_head.attr = mcT_head_p->attr;
+			PSU_head.size = PSU_content;
+			PSU_head.cTime = mcT_head_p->cTime;
+			PSU_head.mTime = mcT_head_p->mTime;
+			memcpy(PSU_head.name, mcT_head_p->name, sizeof(PSU_head.name));
+			PSU_head.unknown_1_u16 = mcT_head_p->unknown_1_u16;
+			PSU_head.unknown_2_u64 = mcT_head_p->unknown_2_u64;
+			size = genWrite(out_fd, (void *) &PSU_head, sizeof(PSU_head));
+			if(size != sizeof(PSU_head)){
+PSU_error:
+				genClose(PM_file[recurses+1]);
+				return -1;
+			}
+			clear_psu_header(&PSU_head);
+			PSU_head.attr = 0x8427;  //Standard folder attr, for pseudo "." and ".."
+			PSU_head.cTime = mcT_head_p->cTime;
+			PSU_head.mTime = mcT_head_p->mTime;
+			PSU_head.name[0] = '.';  //Set name entry to "."
+			size = genWrite(out_fd, (void *) &PSU_head, sizeof(PSU_head));
+			if(size != sizeof(PSU_head)) goto PSU_error;
+			PSU_head.name[1] = '.';  //Change name entry to ".."
+			size = genWrite(out_fd, (void *) &PSU_head, sizeof(PSU_head));
+			if(size != sizeof(PSU_head)) goto PSU_error;
+		} else {                              //any other PasteMode than PM_PSU_BACKUP
+			ret = newdir(outPath, newfile.name);
+			if(ret == -17){	//NB: 'newdir' must return -17 for ALL pre-existing folder cases
+				ret = getGameTitle(outPath, &newfile, newfile.title);
+				transcpy_sjis(tmp, newfile.title);
+				sprintf(progress,
+					"%s:\n"
+					"%s%s/\n"
+					"\n"
+					"%s:\n",
+					LNG(Name_conflict_for_this_folder), outPath,
+					file.name, LNG(With_gamesave_title));
+				if(tmp[0])
+					strcat(progress, tmp);
+				else
+					strcat(progress, LNG(Undefined_Not_a_gamesave));
+				sprintf(tmp, "\n\n%s ?", LNG(Do_you_wish_to_overwrite_it));
+				strcat(progress, tmp);
+				if(ynDialog(progress)<0) return -1;
+				if(	(PasteMode == PM_MC_BACKUP)
+				||	(PasteMode == PM_MC_RESTORE)
+				||	(PasteMode == PM_PSU_RESTORE)
+				) {
+					ret = delete(outPath, &newfile);  //Attempt recursive delete
+					if(ret < 0) return -1;
+					if(newdir(outPath, newfile.name) < 0) return -1;
+				}
+				drawMsg(LNG(Pasting));
+			} else if(ret < 0){
+				return -1;  //return error for failure to create destination folder
+			}
+		}
+//Here a destination folder, or a PSU file exists, ready to receive files
+		if(PasteMode==PM_MC_BACKUP){         //MC Backup mode folder paste preparation
+			sprintf(tmp, "%s/PS2_MC_Backup_Attributes.BUP.bin", out);
+			genRemove(tmp);
+			out_fd = genOpen(tmp, O_WRONLY | O_CREAT);
+
+			if(out_fd>=0){
+				size = genWrite(out_fd, (void *) &file.stats, 64);
+				if(size == 64){
+					PM_file[recurses+1] = out_fd;
+					PM_flag[recurses+1] = PM_MC_BACKUP;
+				}
+				else
+					genClose(PM_file[recurses+1]);
+			}
+		} else if(PasteMode==PM_MC_RESTORE){ //MC Restore mode folder paste preparation
+			sprintf(tmp, "%s/PS2_MC_Backup_Attributes.BUP.bin", in);
+
+			if(!strncmp(tmp, "host:/", 6))
+				makeHostPath(tmp+5, tmp+6);
+			in_fd = genOpen(tmp, O_RDONLY);
+
+			if(in_fd>=0){
+				size = genRead(in_fd, (void *) &file.stats, 64); //Read stats for the save folder
+				if(size == 64){
+					PM_file[recurses+1] = in_fd;
+					PM_flag[recurses+1] = PM_MC_RESTORE;
+				}
+				else
+					genClose(PM_file[recurses+1]);
+			}
+		}
+		if(PM_flag[recurses+1]==PM_NORMAL){  //Normal mode folder paste preparation
+		}
+		sprintf(in, "%s%s/", inPath, file.name);     //restore phys dev spec to 'in'
+		sprintf(out, "%s%s", outPath, newfile.name); //restore phys dev spec to 'out'
+		genLimObjName(out, 0);                       //Limit dest folder name
+		strcat(out, "/");                            //Separate dest folder name
+
+		if(PasteMode == PM_PSU_RESTORE && PSU_restart_f) {
+			nfiles = PSU_content;
+			for(i=0; i<nfiles; i++) {
+				size = genRead(PM_file[recurses+1], (void *) &PSU_head, sizeof(PSU_head));
+				if(size != sizeof(PSU_head)) { //Break with error on read failure
+					ret = -1;
+					break;
+				}
+				if(	(PSU_head.size == 0)
+				&&	(PSU_head.attr & MC_ATTR_SUBDIR))//Dummy/Pseudo folder entry ?
+					continue;                            //Just ignore dummies
+				if(PSU_head.attr & MC_ATTR_SUBDIR) { //break with error on weird folder in PSU
+					ret = -1;
+					break;
+				}
+				if(PSU_head.size & 0x3FF)		//Check if file is padded in PSU
+					psu_pad_size = 0x400-(PSU_head.size & 0x3FF);
+				else
+					psu_pad_size = 0;
+				//here we need to create a proper FILEINFO struct for PSU-contained file
+				mcT_files_p->attr = PSU_head.attr;
+				mcT_files_p->size = PSU_head.size;
+				mcT_files_p->cTime = PSU_head.cTime;
+				mcT_files_p->mTime = PSU_head.mTime;
+				memcpy(mcT_files_p->name, PSU_head.name, sizeof(PSU_head.name));
+				mcT_files_p->unknown_1_u16 = PSU_head.unknown_1_u16;
+				mcT_files_p->unknown_2_u64 = PSU_head.unknown_2_u64;
+				memcpy(files[0].name, PSU_head.name, sizeof(PSU_head.name));
+				files[0].name[sizeof(PSU_head.name)] = 0;
+				//Finally we can make the recursive call
+				if((ret = copy(out, in, files[0], recurses+1)) < 0)
+					break;
+				//We must also step past any file padding, for next header
+				if(psu_pad_size)
+					genLseek(PM_file[recurses+1], psu_pad_size, SEEK_CUR);
+				//finally, we must adjust attributes of the new file copy, to ensure
+				//correct timestamps and attributes (requires MC-specific functions)
+				strcpy(tmp, out);
+				strncat(tmp, files[0].stats.name, 32);
+				mcGetInfo(tmp[2]-'0', 0, &dummy, &dummy, &dummy);  //Wakeup call
+				mcSync(0, NULL, &dummy);
+				mcSetFileInfo(tmp[2]-'0', 0, &tmp[4], &files[0].stats, MC_SFI); //Fix file stats
+				mcSync(0, NULL, &dummy);
+			} //ends main for loop of valid PM_PSU_RESTORE mode
+			genClose(PM_file[recurses+1]); //Close the PSU file
+			//Finally fix the stats of the containing folder
+			//It has to be done last, as timestamps would change when fixing files
+			//--- This has been moved to a later clause, shared with PM_MC_RESTORE ---
+		} else { //Any other mode than a valid PM_PSU_RESTORE
+			nfiles = getDir(in, files);
+			for(i=0; i<nfiles; i++) {
+				if((ret = copy(out, in, files[i], recurses+1)) < 0)
+					break;
+			} //ends main for loop for all modes other than valid PM_PSU_RESTORE
+		}
+//folder contents are copied by the recursive call above, with error handling below
+		if(ret<0){
+			if(PM_flag[recurses+1]==PM_PSU_BACKUP) goto PSU_error;
+			else return -1;
+		}
+
+//Here folder contents have been copied error-free, but we also need to copy
+//attributes and timestamps, and close the attribute/PSU file if such was used
+//Lots of stuff need to be done here to make PSU operations work properly
+		if(PM_flag[recurses+1]==PM_MC_BACKUP){         //MC Backup mode folder paste closure
+			genClose(PM_file[recurses+1]);
+		} else if(PM_flag[recurses+1]==PM_PSU_BACKUP){ //PSU Backup mode folder paste closure
+			genLseek(PM_file[recurses+1], 0, SEEK_SET);
+			clear_psu_header(&PSU_head);
+			PSU_head.attr = mcT_head_p->attr;
+			PSU_head.size = PSU_content;
+			PSU_head.cTime = mcT_head_p->cTime;
+			PSU_head.mTime = mcT_head_p->mTime;
+			memcpy(PSU_head.name, mcT_head_p->name, sizeof(PSU_head.name));
+			PSU_head.unknown_1_u16 = mcT_head_p->unknown_1_u16;
+			PSU_head.unknown_2_u64 = mcT_head_p->unknown_2_u64;
+			size = genWrite(PM_file[recurses+1], (void *) &PSU_head, sizeof(PSU_head));
+			genLseek(PM_file[recurses+1], 0, SEEK_END);
+			genClose(PM_file[recurses+1]);
+		} else if(PM_flag[recurses+1]==PM_MC_RESTORE){ //MC Restore mode folder paste closure
+			in_fd = PM_file[recurses+1];
+			for(size=64, i=0; size==64;){
+				size = genRead(in_fd, (void *) &stats, 64);
+				if(size == 64){
+					strcpy(tmp, out);
+					strncat(tmp, stats.name, 32);
+					mcGetInfo(tmp[2]-'0', 0, &dummy, &dummy, &dummy);  //Wakeup call
+					mcSync(0, NULL, &dummy);
+					mcSetFileInfo(tmp[2]-'0', 0, &tmp[4], &stats, MC_SFI); //Fix file stats
+					mcSync(0, NULL, &dummy);
+				} else {
+					genClose(in_fd);
+				}
+			}
+			//Finally fix the stats of the containing folder
+			//It has to be done last, as timestamps would change when fixing files
+			//--- This has been moved to a later clause, shared with PM_PSU_RESTORE ---
+		} else if(PM_flag[recurses+1]==PM_NORMAL){     //Normal mode folder paste closure
+			if(!strncmp(out, "mc", 2)){  //Handle folder copied to MC
+				mcGetInfo(out[2]-'0', 0, &dummy, &dummy, &dummy);  //Wakeup call
+				mcSync(0, NULL, &dummy);
+				ret = MC_SFI; //default request for changing entire mcTable
+				if(strncmp(in, "mc", 2)){  //Handle file copied from non-MC to MC
+					file.stats.attrFile = MC_ATTR_norm_folder; //normalize MC folder attribute
+					if(!strncmp(in, "host", 4)){  //Handle folder copied from host: to MC
+						ret = 4;      //request change only of main attribute for host:
+					} //ends host: source clause
+				} //ends non-MC source clause
+				mcSetFileInfo(out[2]-'0', 0, &out[4], &file.stats, ret);
+				mcSync(0, NULL, &dummy);
+			} else {  //Handle folder copied to non-MC
+				if(!strncmp(out, "pfs", 3)){  //for pfs on HDD we use fileXio_ stuff
+					memcpy(iox_stat.ctime, (void *) &file.stats._create, 8);
+					memcpy(iox_stat.mtime, (void *) &file.stats._modify, 8);
+					memcpy(iox_stat.atime, iox_stat.mtime, 8);
+					ret = FIO_CST_CT|FIO_CST_AT|FIO_CST_MT;  //Request timestamp stat change
+					if(!strncmp(in, "host", 4)){  //Handle folder copied from host:
+						ret = 0;                               //Request NO stat change
+					}
+////					dummy = fileXioChStat(out, &iox_stat, ret); //disabled due to bugs
+				} else if(!strncmp(out, "host", 4)) { //for files copied to host: we skip Chstat
+				} else if(!strncmp(out, "mass", 4)) { //for files copied to mass: we skip Chstat
+				} else { //for other devices we use fio_ stuff
+					memcpy(fio_stat.ctime, (void *) &file.stats._create, 8);
+					memcpy(fio_stat.mtime, (void *) &file.stats._modify, 8);
+					memcpy(fio_stat.atime, fio_stat.mtime, 8);
+					ret = FIO_CST_CT|FIO_CST_AT|FIO_CST_MT;  //Request timestamp stat change
+					if(!strncmp(in, "host", 4)){  //Handle folder copied from host:
+						ret = 0;                               //Request NO stat change
+					}
+					dummy = fioChstat(out, &fio_stat, ret); //(no such devices yet)
+				}
+			}
+		}
+		if(	(PM_flag[recurses+1]==PM_MC_RESTORE)
+		||	(PM_flag[recurses+1]==PM_PSU_RESTORE)) {
+			//Finally fix the stats of the containing folder
+			//It has to be done last, as timestamps would change when fixing files
+			mcGetInfo(out[2]-'0', 0, &dummy, &dummy, &dummy);  //Wakeup call
+			mcSync(0, NULL, &dummy);
+			mcSetFileInfo(out[2]-'0', 0, &out[4], &file.stats, MC_SFI); //Fix folder stats
+			mcSync(0, NULL, &dummy);
+		}
+//the return code below is used if there were no errors copying a folder
+		return 0;
+	}
+
+//Here we know that the object to copy is a file, not a folder
+//But in PSU Restore mode we must treat PSU files as special folders, at level 0.
+//and recursively call copy with higher recurse level to process the contents
+	if(PasteMode==PM_PSU_RESTORE && recurses==0){
+		cp = strrchr(in, '.');
+		if((cp==NULL) || stricmp(cp, ".psu") )
+			goto non_PSU_RESTORE_init;  //if not a PSU file, go do normal pasting
+
+		in_fd = genOpen(in, O_RDONLY);
+
+		if(in_fd < 0)
+			return -1;
+		size = genRead(in_fd, (void *) &PSU_head, sizeof(PSU_head));
+		if(size != sizeof(PSU_head)){
+			genClose(in_fd);
+			return -1;
+		}
+		PM_file[recurses+1] = in_fd;           //File descriptor for PSU
+		PM_flag[recurses+1] = PM_PSU_RESTORE;  //Mode flag for recursive entry
+		//Here we need to prep the file struct to appear like a normal MC folder
+		//before 'restarting' this 'copy' to handle creation of destination folder
+		//as well as the copying of files from the PSU into that folder
+		mcT_head_p->attr = PSU_head.attr;
+		PSU_content = PSU_head.size;
+		mcT_head_p->size = 0;
+		mcT_head_p->cTime = PSU_head.cTime;
+		mcT_head_p->mTime = PSU_head.mTime;
+		memcpy(mcT_head_p->name, PSU_head.name, sizeof(PSU_head.name));
+		mcT_head_p->unknown_1_u16 = PSU_head.unknown_1_u16;
+		mcT_head_p->unknown_2_u64 = PSU_head.unknown_2_u64;
+		memcpy(file.name, PSU_head.name, sizeof(PSU_head.name));
+		file.name[sizeof(PSU_head.name)] = 0;
+		PSU_restart_f = 1;
+		goto restart_copy;
+	}
+non_PSU_RESTORE_init:
+//In MC Restore mode we must here avoid copying the attribute file
+	if(PM_flag[recurses]==PM_MC_RESTORE)
+		if(!strcmp(file.name,"PS2_MC_Backup_Attributes.BUP.bin"))
+			return 0;
+
+//It is now time to open the input file, indicated by 'in_fd'
+//But in PSU Restore mode we must use the already open PSU file instead
+	if(PM_flag[recurses]==PM_PSU_RESTORE){
+		in_fd = PM_file[recurses];
+		size = mcT_head_p->size;
+	}
+	else { //Any other mode than PM_PSU_RESTORE
+		if	(!strncmp(in, "host:/", 6))
+			makeHostPath(in+5, in+6);
+		in_fd = genOpen(in, O_RDONLY);
+		if(in_fd<0) goto copy_file_exit;
+		size = genLseek(in_fd,0,SEEK_END);
+		genLseek(in_fd,0,SEEK_SET);
+	}
+
+//Here the input file has been opened, indicated by 'in_fd'
+//It is now time to open the output file, indicated by 'out_fd'
+//except in the case of a PSU backup, when we must add a header to PSU instead
+	if(PM_flag[recurses]==PM_PSU_BACKUP){
+		out_fd = PM_file[recurses];
+		clear_psu_header(&PSU_head);
+		PSU_head.attr = mcT_head_p->attr;
+		PSU_head.size = mcT_head_p->size;
+		PSU_head.cTime = mcT_head_p->cTime;
+		PSU_head.mTime = mcT_head_p->mTime;
+		memcpy(PSU_head.name, mcT_head_p->name, sizeof(PSU_head.name));
+		genWrite(out_fd, (void *) &PSU_head, sizeof(PSU_head));
+		if(PSU_head.size & 0x3FF)
+			psu_pad_size = 0x400-(PSU_head.size & 0x3FF);
+		else
+			psu_pad_size = 0;
+		PSU_content++; //Increase PSU content header count
+	} else { //Any other PasteMode than PM_PSU_BACKUP needs a new output file
+		if	(!strncmp(out, "host:/", 6))
+			makeHostPath(out+5, out+6);
+		genLimObjName(out, 0);                              //Limit dest file name
+		genRemove(out);                                     //Remove old file if present
+		out_fd=genOpen(out, O_WRONLY | O_TRUNC | O_CREAT);  //Create new file
+		if(out_fd<0) goto copy_file_exit;
+	}
+
+//Here the output file has been opened, indicated by 'out_fd'
+
+	buffSize = 0x100000;       //First assume buffer size = 1MB (good for HDD)
+	if(!strncmp(out, "mass", 4) || !strncmp(out, "vmc", 3))
+		buffSize =  50000;       //Use  50000 if writing to USB (Flash RAM writes)
+//VMC contents should use the same size, as VMCs will often be stored on USB
+	else if(!strncmp(out, "mc", 2))
+		buffSize = 125000;       //Use 125000 if writing to MC (pretty slow too)
+	else if(!strncmp(in, "mc",2))
+		buffSize = 200000;       //Use 200000 if reading from MC (still pretty slow)
+	else if(!strncmp(out, "host", 4))
+		buffSize = 350000;       //Use 350000 if writing to HOST (acceptable)
+	else if((!strncmp(in, "mass", 4)) || (!strncmp(in, "host", 4)))
+		buffSize = 500000;       //Use 500000 reading from USB or HOST (acceptable)
+
+	if(size < buffSize)
+		buffSize = size;
+
+	buff = (char*)malloc(buffSize);   //Attempt buffer allocation
+	if(buff==NULL){                   //if allocation fails
+		buffSize = 32768;               //Set buffsize to 32KB
+		buff = (char*)malloc(buffSize); //Allocate 32KB buffer
+	}
+
+	old_size = written_size;  //Note initial progress data pos
+	OldTime = Timer();	      //Note initial progress time
+
+	while(size>0){ // ----- The main copying loop starts here -----
+
+		if(size < buffSize)
+			buffSize = size;		//Adjust effective buffer size to remaining data
+
+		TimeDiff = Timer()-OldTime;
+		OldTime = Timer();
+		SizeDiff = written_size-old_size;
+		old_size = written_size;
+		if(SizeDiff){													//if anything was written this time
+			speed = (SizeDiff * 1000)/TimeDiff;   //calc real speed
+			remain_time = size / speed;           //calc time remaining for that speed
+		}else if(TimeDiff){                   //if nothing written though time passed
+			speed = 0;                            //set speed as zero
+			remain_time = -1;                     //set time remaining as unknown
+		}else{                                //if nothing written and no time passed
+			speed = -1;                           //set speed as unknown
+			remain_time = -1;                     //set time remaining as unknown
+		}
+
+		sprintf(progress, "%s : %s", LNG(Pasting_file), file.name);
+
+		sprintf(tmp, "\n%s : ", LNG(Remain_Size));
+		strcat(progress, tmp);
+		if(size<=1024)
+			sprintf(tmp, "%lu %s", (long)size, LNG(bytes)); // bytes
+		else
+			sprintf(tmp, "%lu %s", (long)size/1024, LNG(Kbytes)); // Kbytes
+		strcat(progress, tmp);
+
+		sprintf(tmp, "\n%s: ", LNG(Current_Speed));
+		strcat(progress, tmp);
+		if(speed==-1)
+			strcpy(tmp, LNG(Unknown));
+		else if(speed<=1024)
+			sprintf(tmp, "%d %s/sec", speed, LNG(bytes)); // bytes/sec
+		else
+			sprintf(tmp, "%d %s/sec", speed/1024, LNG(Kbytes)); //Kbytes/sec
+		strcat(progress, tmp);
+
+		sprintf(tmp, "\n%s : ", LNG(Remain_Time));
+		strcat(progress, tmp);
+		if(remain_time==-1)
+			strcpy(tmp, LNG(Unknown));
+		else if(remain_time<60)
+			sprintf(tmp, "%d sec", remain_time); // sec
+		else if(remain_time<3600)
+			sprintf(tmp, "%d m %d sec", remain_time/60, remain_time%60); // min,sec
+		else
+			sprintf(tmp, "%d h %d m %d sec", remain_time/3600, (remain_time%3600)/60, remain_time%60); // hour,min,sec
+		strcat(progress, tmp);
+
+		sprintf(tmp, "\n\n%s: ", LNG(Written_Total));
+		strcat(progress, tmp);
+		sprintf(tmp, "%ld %s", written_size/1024, LNG(Kbytes)); //Kbytes
+		strcat(progress, tmp);
+
+		sprintf(tmp, "\n%s: ", LNG(Average_Speed));
+		strcat(progress, tmp);
+		TimeDiff = Timer()-PasteTime;
+		if(TimeDiff == 0)
+			strcpy(tmp, LNG(Unknown));
+		else {
+			speed = (written_size * 1000)/TimeDiff;   //calc real speed
+			if(speed<=1024)
+				sprintf(tmp, "%d %s/sec", speed, LNG(bytes)); // bytes/sec
+			else
+				sprintf(tmp, "%d %s/sec", speed/1024, LNG(Kbytes)); //Kbytes/sec
+		}
+		strcat(progress, tmp);
+
+		if(PasteProgress_f)  //if progress report was used earlier in this pasting
+			nonDialog(NULL);     //order cleanup for that screen area
+		nonDialog(progress); //Make new progress report
+		PasteProgress_f = 1; //and note that it was done for next time
+		drawMsg(file.name);
+		if(readpad() && new_pad){
+			if(-1 == ynDialog(LNG(Continue_transfer))) {
+				genClose(out_fd); out_fd=-1;
+				if(PM_flag[recurses]!=PM_PSU_BACKUP)
+					genRemove(out);
+				ret = -1;   // flag generic error
+				goto copy_file_exit;	// go deal with it
+			}
+		}
+		//buffSize = genRead(in_fd, buff, buffSize);
+		genRead(in_fd, buff, buffSize);
+		if(buffSize > 0){
+			outsize = genWrite(out_fd, buff, buffSize);
+		}
+//		if((buffSize <= 0) || (buffSize!=outsize)){
+		if(buffSize <= 0){
+			genClose(out_fd); out_fd=-1;
+			if(PM_flag[recurses]!=PM_PSU_BACKUP)
+				genRemove(out);
+			ret = -1;   // flag generic error
+			goto copy_file_exit;
+		}
+		size -= buffSize;
+		written_size += buffSize;
+	} // ends while(size>0), ----- The main copying loop ends here -----
+	ret=0;
+//Here the file has been copied. without error, as indicated by 'ret' above
+//but we also need to copy attributes and timestamps (as yet only for MC)
+//For PSU backup output padding may be needed, but not output file closure
+	if(PM_flag[recurses]==PM_PSU_BACKUP){
+		if(psu_pad_size){
+			pad_psu_header(&PSU_head);
+			if(psu_pad_size >= sizeof(PSU_head)){
+				genWrite(out_fd, (void *) &PSU_head, sizeof(PSU_head));
+				psu_pad_size -= sizeof(PSU_head);
+			}
+			if(psu_pad_size)
+				genWrite(out_fd, (void *) &PSU_head, psu_pad_size);
+		}
+		out_fd = -1;   //prevent output file closure below
+		goto copy_file_exit;
+	}
+
+	if(PM_flag[recurses]==PM_MC_BACKUP){         //MC Backup mode file paste closure
+		size = genWrite(PM_file[recurses], (void *) &file.stats, 64);
+		if(size != 64) return -1; //Abort if attribute file crashed
+	}
+
+	if(out_fd>=0){
+		genClose(out_fd);
+		out_fd = -1; //prevent dual closure attempt
+	}
+
+	if(!strncmp(out, "mc", 2)){  //Handle file copied to MC
+		mcGetInfo(out[2]-'0', 0, &mctype_PSx, &dummy, &dummy); //Wakeup call & MC type check
+		mcSync(0, NULL, &dummy);
+		ret = MC_SFI; //default request for changing entire mcTable
+		if(strncmp(in, "mc", 2)){  //Handle file copied from non-MC to MC
+			file.stats.attrFile = MC_ATTR_norm_file; //normalize MC file attribute
+			if(!strncmp(in, "host", 4)){  //Handle folder copied from host: to MC
+				ret = 4;      //request change only of main attribute for host:
+			} //ends host: source clause
+		} //ends non-MC source clause
+		if(mctype_PSx == 2){ //if copying to a PS2 MC
+			mcSetFileInfo(out[2]-'0', 0, &out[4], &file.stats, ret);
+			mcSync(0, NULL, &dummy);
+		}
+	} else {  //Handle file copied to non-MC
+		if(!strncmp(out, "pfs", 3)){  //for pfs on HDD we use fileXio_ stuff
+			memcpy(iox_stat.ctime, (void *) &file.stats._create, 8);
+			memcpy(iox_stat.mtime, (void *) &file.stats._modify, 8);
+			memcpy(iox_stat.atime, iox_stat.mtime, 8);
+			ret = FIO_CST_CT|FIO_CST_AT|FIO_CST_MT;  //Request timestamp stat change
+			if(!strncmp(in, "host", 4)){  //Handle file copied from host:
+				ret = 0;                               //Request NO stat change
+			}
+////			dummy = fileXioChStat(out, &iox_stat, ret); //disabled due to bugs
+		} else if(!strncmp(out, "host", 4)) { //for files copied to host: we skip Chstat
+		} else if(!strncmp(out, "mass", 4)) { //for files copied to mass: we skip Chstat
+		} else { //for other devices we use fio_ stuff
+			memcpy(fio_stat.ctime, (void *) &file.stats._create, 8);
+			memcpy(fio_stat.mtime, (void *) &file.stats._modify, 8);
+			memcpy(fio_stat.atime, fio_stat.mtime, 8);
+			ret = FIO_CST_CT|FIO_CST_AT|FIO_CST_MT;  //Request timestamp stat change
+			if(!strncmp(in, "host", 4)){  //Handle file copied from host:
+				ret = 0;                               //Request NO stat change
+			}
+			dummy = fioChstat(out, &fio_stat, ret); //(no such devices yet)
+		}
+	}
+
+//The code below is also used for all errors in copying a file,
+//but those cases are distinguished by a negative value in 'ret'
+copy_file_exit:
+	free(buff);
+	if(PM_flag[recurses]!=PM_PSU_RESTORE){ //Avoid closing PSU file here for PSU Restore
+		if(in_fd>=0){
+			genClose(in_fd);
+		}
+	}
+	if(out_fd>=0){
+		genClose(out_fd);
+	}
+	return ret;
+}
+//------------------------------
+//endfunc copy
+//--------------------------------------------------------------
+//dlanor: For v3.64 the virtual keyboard function is modified to
+//allow entry of empty strings. The function now returns string
+//length, except if you use 'CANCEL' when it returns -1 instead.
+//Routines that require a non-empty string (eg: Rename, Newdir)
+//must test with '>' now, instead of '>=' as used previously.
+//--------------------------------------------------------------
+int keyboard(char *out, int max)
+{
+	int event, post_event=0;
+	const int
+		WFONTS= 13,
+		HFONTS= 7,
+		KEY_W = LINE_THICKNESS+12+(13*FONT_WIDTH+12*12)+12+LINE_THICKNESS,
+		KEY_H = LINE_THICKNESS + 1 + FONT_HEIGHT + 1
+		      + LINE_THICKNESS + 8 + (8*FONT_HEIGHT) + 8 + LINE_THICKNESS,
+		KEY_X = ((SCREEN_WIDTH - KEY_W)/2) & -2,
+		KEY_Y = ((SCREEN_HEIGHT - KEY_H)/2)& -2;
+	char *KEY="ABCDEFGHIJKLM"
+	          "NOPQRSTUVWXYZ"
+	          "abcdefghijklm"
+	          "nopqrstuvwxyz"
+	          "0123456789/|\\"
+	          "<>(){}[].,:;\""
+	          "!@#$%&=+-^*_'";
+	int KEY_LEN;
+	int cur=0, sel=0, i=0, x, y, t=0;
+	char tmp[256], *p;
+	unsigned char KeyPress;
+	
+	p=strrchr(out, '.');
+	if(p==NULL)	cur=strlen(out);
+	else		cur=(int)(p-out);
+	KEY_LEN = strlen(KEY);
+
+	event = 1;  //event = initial entry
+	while(1){
+		//Pad response section
+		waitPadReady(0, 0);
+		if(readpad_no_KB()){
+			if(new_pad)
+				event |= 2;  //event |= pad command
+			if(new_pad & PAD_UP){
+				if(sel<=WFONTS*HFONTS){
+					if(sel>=WFONTS) sel-=WFONTS;
+				}else{
+					sel-=4;
+				}
+			}else if(new_pad & PAD_DOWN){
+				if(sel/WFONTS == HFONTS-1){
+					if(sel%WFONTS < 5)	sel=WFONTS*HFONTS;
+					else				sel=WFONTS*HFONTS+1;
+				}else if(sel/WFONTS <= HFONTS-2)
+					sel+=WFONTS;
+			}else if(new_pad & PAD_LEFT){
+				if(sel>0) sel--;
+			}else if(new_pad & PAD_RIGHT){
+				if(sel<=WFONTS*HFONTS) sel++;
+			}else if(new_pad & PAD_START){
+				sel = WFONTS*HFONTS;
+			}else if(new_pad & PAD_L1){
+				if(cur>0) cur--;
+				t=0;
+			}else if(new_pad & PAD_R1){
+				if(cur<strlen(out)) cur++;
+				t=0;
+			}else if((!swapKeys && new_pad & PAD_CROSS)
+			      || (swapKeys && new_pad & PAD_CIRCLE) ){
+				if(cur>0){
+					strcpy(tmp, out);
+					out[cur-1]=0;
+					strcat(out, &tmp[cur]);
+					cur--;
+					t=0;
+				}
+			}else if(new_pad & PAD_SQUARE){ //Square => space
+				i=strlen(out);
+				if(i<max && i<33){
+					strcpy(tmp, out);
+					out[cur]=' ';
+					out[cur+1]=0;
+					strcat(out, &tmp[cur]);
+					cur++;
+					t=0;
+				}
+			}else if((swapKeys && new_pad & PAD_CROSS)
+			      || (!swapKeys && new_pad & PAD_CIRCLE) ){
+				i=strlen(out);
+				if(sel < WFONTS*HFONTS){  //Any char in matrix selected ?
+					if(i<max && i<33){
+						strcpy(tmp, out);
+						out[cur]=KEY[sel];
+						out[cur+1]=0;
+						strcat(out, &tmp[cur]);
+						cur++;
+						t=0;
+					}
+				}else if(sel == WFONTS*HFONTS){ //'OK' exit-button selected ?
+					break;                        //break out of loop with i==strlen
+				}else  //Must be 'CANCEL' exit-button
+					return -1;
+			}else if(new_pad & PAD_TRIANGLE){
+				return -1;
+			}
+		}
+
+		//Kbd response section
+		if(setting->usbkbd_used && PS2KbdRead(&KeyPress)) {
+
+			event |= 2;  //event |= pad command
+
+			if(KeyPress == PS2KBD_ESCAPE_KEY) {
+				PS2KbdRead(&KeyPress);
+				if(KeyPress == 0x29){ // Key Right;
+					if(cur<strlen(out)) cur++;
+					t=0;
+				}else if(KeyPress == 0x2a){ // Key Left;
+					if(cur>0) cur--;
+					t=0;
+				}else if(KeyPress == 0x24){ // Key Home;
+					cur=0;
+					t=0;
+				}else if(KeyPress == 0x27){ // Key End;
+					cur=strlen(out);
+					t=0;
+				}else if(KeyPress == 0x26){ // Key Delete;
+					if(strlen(out)>cur){
+						strcpy(tmp, out);
+						out[cur]=0;
+						strcat(out, &tmp[cur+1]);
+						t=0;
+					}
+				}else if(KeyPress == 0x1b){ // Key Escape;
+					return -1;
+				}
+			}else{
+				if(KeyPress == 0x07){ // Key BackSpace;
+					if(cur>0){
+						strcpy(tmp, out);
+						out[cur-1]=0;
+						strcat(out, &tmp[cur]);
+						cur--;
+						t=0;
+					}
+				}else if(KeyPress == 0x0a){ // Key Return;
+					break;
+				}else{ // All Other Keys;
+					i=strlen(out);
+					if(i<max && i<33){
+						strcpy(tmp, out);
+						out[cur]=KeyPress;
+						out[cur+1]=0;
+						strcat(out, &tmp[cur]);
+						cur++;
+						t=0;
+					}
+				}
+			}
+			KeyPress = '\0';
+		} //ends if(setting->usbkbd_used && PS2KbdRead(&KeyPress))
+
+		t++;
+
+		if(t & 0x0F) event |= 4;  //repetitive timer event
+
+		if(event||post_event){ //NB: We need to update two frame buffers per event
+
+			//Display section
+			drawPopSprite(setting->color[0],
+				KEY_X, KEY_Y,
+				KEY_X+KEY_W-1, KEY_Y+KEY_H-1);
+			drawFrame(
+				KEY_X, KEY_Y,
+				KEY_X+KEY_W-1, KEY_Y+KEY_H-1, setting->color[1]);
+			drawOpSprite(setting->color[1],
+				KEY_X, KEY_Y+LINE_THICKNESS+1+FONT_HEIGHT+1,
+				KEY_X+KEY_W-1, KEY_Y+LINE_THICKNESS+1+FONT_HEIGHT+1+LINE_THICKNESS-1);
+			printXY(out, KEY_X+LINE_THICKNESS+3, KEY_Y+LINE_THICKNESS+1, setting->color[3], TRUE, 0);
+			if(((event|post_event)&4) && (t & 0x10)){
+				drawOpSprite(setting->color[2],
+					KEY_X + LINE_THICKNESS + 1 + cur*8,
+					KEY_Y + LINE_THICKNESS + 2,
+					KEY_X + LINE_THICKNESS + 1 + cur*8 + LINE_THICKNESS - 1,
+					KEY_Y + LINE_THICKNESS + 2 + (FONT_HEIGHT-2) - 1);
+			}
+			for(i=0; i<KEY_LEN; i++)
+				drawChar(KEY[i],
+					KEY_X + LINE_THICKNESS + 12 + (i%WFONTS)*(FONT_WIDTH+12),
+					KEY_Y + LINE_THICKNESS + 1 + FONT_HEIGHT + 1
+					      + LINE_THICKNESS + 8 + (i/WFONTS)*FONT_HEIGHT, setting->color[3]);
+			printXY(LNG(OK),
+				KEY_X + LINE_THICKNESS + 12,
+				KEY_Y + LINE_THICKNESS + 1 + FONT_HEIGHT + 1
+				      + LINE_THICKNESS + 8 + HFONTS*FONT_HEIGHT, setting->color[3], TRUE, 0);
+			printXY(LNG(CANCEL),
+				KEY_X + KEY_W - 1 - (strlen(LNG(CANCEL))+2)*FONT_WIDTH,
+				KEY_Y + LINE_THICKNESS + 1 + FONT_HEIGHT + 1
+				      + LINE_THICKNESS + 8 + HFONTS*FONT_HEIGHT, setting->color[3], TRUE, 0);
+
+			//Cursor positioning section
+			if(sel<=WFONTS*HFONTS)
+				x = KEY_X + LINE_THICKNESS + 12 + (sel%WFONTS)*(FONT_WIDTH+12) - 8;
+			else
+				x = KEY_X + KEY_W - 2 - (strlen(LNG(CANCEL))+3)*FONT_WIDTH;
+			y = KEY_Y + LINE_THICKNESS + 1 + FONT_HEIGHT + 1
+			          + LINE_THICKNESS + 8 + (sel/WFONTS)*FONT_HEIGHT;
+			drawChar(LEFT_CUR, x, y, setting->color[2]);
+
+			//Tooltip section
+			x = SCREEN_MARGIN;
+			y = Menu_tooltip_y;
+			drawSprite(setting->color[0], 0, y-1, SCREEN_WIDTH, y+FONT_HEIGHT);
+
+			if (swapKeys){
+				sprintf(tmp, "ÿ1:%s ÿ0", LNG(Use));
+			}else{
+				sprintf(tmp, "ÿ0:%s ÿ1", LNG(Use));
+			}
+				sprintf(tmp+strlen(tmp), ":%s ÿ2:%s L1:%s R1:%s START:%s ÿ3:%s",
+				LNG(BackSpace), LNG(SPACE), LNG(Left), LNG(Right), LNG(Enter), LNG(Exit));
+			printXY(tmp, x, y, setting->color[2], TRUE, 0);
+		}//ends if(event||post_event)
+		drawScr();
+		post_event = event;
+		event = 0;
+	}//ends while
+	return strlen(out);
+}
+//------------------------------
+//endfunc keyboard
+//--------------------------------------------------------------
+//keyboard2 below is used for testing output from a USB keyboard
+//it can be commented out when not used by the programmer.
+//When using it for tests, simply replace the call to 'keyboard'
+//somewhere (Rename routine is a good choice) with a call to
+//'keyboard2' instead. It uses the old routines for virtual keys
+//via gamepad, so you can still enter proper strings that way,
+//but each key pressed on the USB keyboard will be expanded to a
+//sequence corresponding to sprintf(somestring," %02X ", key).
+//Thus four characters are added to the output string for each
+//such key, and after character 32 the cursor loops back to the
+//first character again.
+//--------------------------------------------------------------
+/*
+int keyboard2(char *out, int max)
+{
+	int event, post_event=0;
+	const int	KEY_W=276,
+				KEY_H=168,
+				KEY_X=(SCREEN_WIDTH - KEY_W)/2,
+				KEY_Y=((SCREEN_HEIGHT - KEY_H)/2),
+				WFONTS=13,
+				HFONTS=7;
+	char *KEY="ABCDEFGHIJKLM"
+	          "NOPQRSTUVWXYZ"
+	          "abcdefghijklm"
+	          "nopqrstuvwxyz"
+	          "0123456789   "
+	          "()[]!#$%&@;  "
+	          "=+-'^.,_     ";
+	int KEY_LEN;
+	int cur=0, sel=0, i=0, x, y, t=0;
+	char tmp[256], *p;
+	unsigned char KeyPress;
+	
+	p=strrchr(out, '.');
+	if(p==NULL)	cur=strlen(out);
+	else		cur=(int)(p-out);
+	KEY_LEN = strlen(KEY);
+
+	event = 1;  //event = initial entry
+	while(1){
+		//Pad response section
+		waitPadReady(0, 0);
+		if(readpad_no_KB()){
+			if(new_pad)
+				event |= 2;  //event |= pad command
+			if(new_pad & PAD_UP){
+				if(sel<=WFONTS*HFONTS){
+					if(sel>=WFONTS) sel-=WFONTS;
+				}else{
+					sel-=4;
+				}
+			}else if(new_pad & PAD_DOWN){
+				if(sel/WFONTS == HFONTS-1){
+					if(sel%WFONTS < 5)	sel=WFONTS*HFONTS;
+					else				sel=WFONTS*HFONTS+1;
+				}else if(sel/WFONTS <= HFONTS-2)
+					sel+=WFONTS;
+			}else if(new_pad & PAD_LEFT){
+				if(sel>0) sel--;
+			}else if(new_pad & PAD_RIGHT){
+				if(sel<=WFONTS*HFONTS) sel++;
+			}else if(new_pad & PAD_START){
+				sel = WFONTS*HFONTS;
+			}else if(new_pad & PAD_L1){
+				if(cur>0) cur--;
+				t=0;
+			}else if(new_pad & PAD_R1){
+				if(cur<strlen(out)) cur++;
+				t=0;
+			}else if((!swapKeys && new_pad & PAD_CROSS)
+			      || (swapKeys && new_pad & PAD_CIRCLE) ){
+				if(cur>0){
+					strcpy(tmp, out);
+					out[cur-1]=0;
+					strcat(out, &tmp[cur]);
+					cur--;
+					t=0;
+				}
+			}else if((swapKeys && new_pad & PAD_CROSS)
+			      || (!swapKeys && new_pad & PAD_CIRCLE) ){
+				i=strlen(out);
+				if(sel < WFONTS*HFONTS){  //Any char in matrix selected ?
+					if(i<max && i<33){
+						strcpy(tmp, out);
+						out[cur]=KEY[sel];
+						out[cur+1]=0;
+						strcat(out, &tmp[cur]);
+						cur++;
+						t=0;
+					}
+				}else if(sel == WFONTS*HFONTS){ //'OK' exit-button selected ?
+					break;                        //break out of loop with i==strlen
+				}else  //Must be 'CANCEL' exit-button
+					return -1;
+			}
+		}
+
+		//Kbd response section
+		if(PS2KbdRead(&KeyPress)) {
+			strcpy(tmp, out);
+			sprintf(out+cur," %02X %n",KeyPress, &x);
+			if(cur+x < strlen(tmp))
+				strcat(out, tmp+cur+x);
+			cur+=x;
+			if(cur>=31)
+				cur=0;
+			t=0;
+		} //ends if(PS2KbdRead(&KeyPress))
+
+		t++;
+
+		if(t & 0x0F) event |= 4;  //repetitive timer event
+
+		if(event||post_event){ //NB: We need to update two frame buffers per event
+
+			//Display section
+			drawPopSprite(setting->color[0],
+				KEY_X, KEY_Y,
+				KEY_X+KEY_W, KEY_Y+KEY_H);
+			drawFrame(
+				KEY_X, KEY_Y,
+				KEY_X+KEY_W, KEY_Y+KEY_H, setting->color[1]);
+			drawOpSprite(setting->color[1],
+				KEY_X, KEY_Y+20,
+				KEY_X+KEY_W, KEY_Y+20+LINE_THICKNESS);
+			printXY(out, KEY_X+2+3, KEY_Y+3, setting->color[3], TRUE, 0);
+			if(((event|post_event)&4) && (t & 0x10)){
+				printXY("|",
+					KEY_X+cur*8+1, KEY_Y+3, setting->color[3], TRUE, 0);
+			}
+			for(i=0; i<KEY_LEN; i++)
+				drawChar(KEY[i],
+					KEY_X+2+4 + (i%WFONTS+1)*20 - 12,
+					KEY_Y+28 + (i/WFONTS)*16,
+					setting->color[3]);
+			printXY("OK                       CANCEL",
+				KEY_X+2+4 + 20 - 12, KEY_Y+28 + HFONTS*16, setting->color[3], TRUE, 0);
+
+			//Cursor positioning section
+			if(sel<=WFONTS*HFONTS)
+				x = KEY_X+2+4 + (sel%WFONTS+1)*20 - 20;
+			else
+				x = KEY_X+2+4 + 25*8;
+			y = KEY_Y+28 + (sel/WFONTS)*16;
+			drawChar(LEFT_CUR, x, y, setting->color[3]);
+
+			//Tooltip section
+			x = SCREEN_MARGIN;
+			y = Menu_tooltip_y;
+			drawSprite(setting->color[0], 0, y-1, SCREEN_WIDTH, y+FONT_HEIGHT);
+
+			if (swapKeys) 
+				printXY("ÿ1:OK ÿ0:Back L1:Left R1:Right START:Enter",
+					x, y, setting->color[2], TRUE, 0);
+			else
+				printXY("ÿ0:OK ÿ1:Back L1:Left R1:Right START:Enter",
+					x, y, setting->color[2], TRUE, 0);
+		}//ends if(event||post_event)
+		drawScr();
+		post_event = event;
+		event = 0;
+	}//ends while
+	return i;
+}
+*/
+//------------------------------
+//endfunc keyboard2  (commented out except in testing)
+//--------------------------------------------------------------
+int setFileList(const char *path, const char *ext, FILEINFO *files, int cnfmode)
+{
+	char *p;
+	int nfiles, i, j, ret;
+
+	size_valid = 0;
+	time_valid = 0;
+
+	nfiles = 0;
+	if(path[0]==0){
+		//-- Start case for browser root pseudo folder with device links --
+		if(USB_mass_scanned)	//if mass drives were scanned in earlier browsing
+			scan_USB_mass();		//then allow another scan here (timer dependent)
+
+		strcpy(files[nfiles].name, "mc0:");
+		files[nfiles++].stats.attrFile = MC_ATTR_SUBDIR;
+		strcpy(files[nfiles].name, "mc1:");
+		files[nfiles++].stats.attrFile = MC_ATTR_SUBDIR;
+		strcpy(files[nfiles].name, "hdd0:");
+		files[nfiles++].stats.attrFile = MC_ATTR_SUBDIR;
+		strcpy(files[nfiles].name, "cdfs:");
+		files[nfiles++].stats.attrFile = MC_ATTR_SUBDIR;
+		if(	(cnfmode!=USBD_IRX_CNF)
+			&&(cnfmode!=USBKBD_IRX_CNF)
+			&&(cnfmode!=USBMASS_IRX_CNF)) {
+			//The condition above blocks selecting USB drivers from USB devices
+			if(USB_mass_ix[0] || !USB_mass_scanned){
+				strcpy(files[nfiles].name, "mass:");
+				files[nfiles++].stats.attrFile = MC_ATTR_SUBDIR;
+			}
+			for(i=1; i<10; i++){
+				if(USB_mass_ix[i]){
+					strcpy(files[nfiles].name, "mass0:");
+					files[nfiles].name[4] = USB_mass_ix[i];
+					files[nfiles++].stats.attrFile = MC_ATTR_SUBDIR;
+				}
+			}
+		}
+		if	(!cnfmode || (cnfmode==JPG_CNF)) {
+			//This condition blocks selecting any CONFIG items on PC
+			//or in a virtual memory card
+			strcpy(files[nfiles].name, "host:");
+			files[nfiles++].stats.attrFile = MC_ATTR_SUBDIR;
+			if(vmcMounted[0]){
+				strcpy(files[nfiles].name, "vmc0:");
+				files[nfiles++].stats.attrFile = MC_ATTR_SUBDIR;
+			}
+			if(vmcMounted[1]){
+				strcpy(files[nfiles].name, "vmc1:");
+				files[nfiles++].stats.attrFile = MC_ATTR_SUBDIR;
+			}
+		}
+		if(cnfmode<2) {
+			//This condition blocks use of MISC pseudo-device for drivers and skins
+			//And allows this device only for launch keys and for normal browsing
+			strcpy(files[nfiles].name, LNG(MISC));
+			files[nfiles].stats.attrFile = MC_ATTR_SUBDIR;
+			nfiles++;
+		}
+		for(i=0; i<nfiles; i++)
+			files[i].title[0]=0;
+		vfreeSpace=FALSE;
+		//-- End case for browser root pseudo folder with device links --
+	}else if(!strcmp(path, setting->Misc)){
+		//-- Start case for MISC command pseudo folder with function links --
+		nfiles = 0;
+		strcpy(files[nfiles].name, "..");
+		files[nfiles++].stats.attrFile = MC_ATTR_SUBDIR;
+		if(cnfmode) { //Stop recursive FileBrowser entry, only allow it for launch keys
+			strcpy(files[nfiles].name, LNG(FileBrowser));
+			files[nfiles++].stats.attrFile = MC_ATTR_FILE;
+		}
+		strcpy(files[nfiles].name, LNG(PS2Browser));
+		files[nfiles++].stats.attrFile = MC_ATTR_FILE;
+		strcpy(files[nfiles].name, LNG(PS2Disc));
+		files[nfiles++].stats.attrFile = MC_ATTR_FILE;
+		strcpy(files[nfiles].name, LNG(PS2Net));
+		files[nfiles++].stats.attrFile = MC_ATTR_FILE;
+		strcpy(files[nfiles].name, LNG(PS2PowerOff));
+		files[nfiles++].stats.attrFile = MC_ATTR_FILE;
+		strcpy(files[nfiles].name, LNG(HddManager));
+		files[nfiles++].stats.attrFile = MC_ATTR_FILE;
+		strcpy(files[nfiles].name, LNG(TextEditor));
+		files[nfiles++].stats.attrFile = MC_ATTR_FILE;
+		strcpy(files[nfiles].name, LNG(JpgViewer));
+		files[nfiles++].stats.attrFile = MC_ATTR_FILE;
+		strcpy(files[nfiles].name, LNG(Configure));
+		files[nfiles++].stats.attrFile = MC_ATTR_FILE;
+		strcpy(files[nfiles].name, LNG(Load_CNFprev));
+		files[nfiles++].stats.attrFile = MC_ATTR_FILE;
+		strcpy(files[nfiles].name, LNG(Load_CNFnext));
+		files[nfiles++].stats.attrFile = MC_ATTR_FILE;
+		strcpy(files[nfiles].name, LNG(Set_CNF_Path));
+		files[nfiles++].stats.attrFile = MC_ATTR_FILE;
+		strcpy(files[nfiles].name, LNG(Load_CNF));
+		files[nfiles++].stats.attrFile = MC_ATTR_FILE;
+//Next 2 lines add an optional font test routine
+		strcpy(files[nfiles].name, LNG(ShowFont));
+		files[nfiles++].stats.attrFile = MC_ATTR_FILE;
+		strcpy(files[nfiles].name, LNG(Debug_Info));
+		files[nfiles++].stats.attrFile = MC_ATTR_FILE;
+		strcpy(files[nfiles].name, LNG(About_uLE));
+		files[nfiles++].stats.attrFile = MC_ATTR_FILE;
+		for(i=0; i<nfiles; i++)
+			files[i].title[0]=0;
+		//-- End case for MISC command pseudo folder with function links --
+	}else{
+		//-- Start case for normal folder with file/folder links --
+		strcpy(files[0].name, "..");
+		files[0].stats.attrFile = MC_ATTR_SUBDIR;
+		nfiles = getDir(path, &files[1]) + 1;
+		if(strcmp(ext,"*")){
+			for(i=j=1; i<nfiles; i++){
+				if(files[i].stats.attrFile & MC_ATTR_SUBDIR)
+					files[j++] = files[i];
+				else{
+					p = strrchr(files[i].name, '.');
+					if(p!=NULL && !stricmp(ext,p+1))
+						files[j++] = files[i];
+				}
+			}
+			nfiles = j;
+		}
+		if((file_show==2)||(file_sort==2)){
+			for(i=1; i<nfiles; i++){
+				ret = getGameTitle(path, &files[i], files[i].title);
+				if(ret<0) files[i].title[0]=0;
+			}
+		}
+		if(!strcmp(path, "hdd0:/"))
+			vfreeSpace=FALSE;
+		else if(nfiles>1)
+			sort(&files[1], 0, nfiles-2);
+		//-- End case for normal folder with file/folder links --
+	}
+	return nfiles;
+}
+//------------------------------
+//endfunc setFileList
+//--------------------------------------------------------------
+int BrowserModePopup(void)
+{
+	char tmp[80];
+	int x, y, i, test;
+	int event, post_event=0;
+
+	int entry_file_show = file_show;
+	int entry_file_sort = file_sort;
+
+	int Show_len = strlen(LNG(Show_Content_as))+1;
+	int Sort_len = strlen(LNG(Sort_Content_by))+1;
+
+	int menu_len = Show_len;
+	if(menu_len < (i = Sort_len)) menu_len = i;
+	if(menu_len < (i = strlen(LNG(Filename))+strlen(LNG(_plus_Details)))) menu_len = i;
+	if(menu_len < (i = strlen(LNG(Game_Title))+strlen(LNG(_plus_Details)))) menu_len = i;
+	if(menu_len < (i = strlen(LNG(No_Sort)))) menu_len = i;
+	if(menu_len < (i = strlen(LNG(Timestamp)))) menu_len = i;
+	if(menu_len < (i = strlen(LNG(Back_to_Browser)))) menu_len = i;
+	menu_len += 3; //All of the above strings are indented 3 spaces, for tooltips
+
+	int menu_ch_w = menu_len+1;    //Total characters in longest menu string
+	int menu_ch_h = 14;      //Total number of menu lines
+	int mSprite_w = (menu_ch_w + 3) * FONT_WIDTH;
+	int mSprite_h = (menu_ch_h +1) * FONT_HEIGHT;
+	int mSprite_X1 = SCREEN_WIDTH/2 - mSprite_w/2;
+	int mSprite_Y1 = SCREEN_HEIGHT/2 - mSprite_h/2;
+	int mSprite_X2 = mSprite_X1+mSprite_w;
+	int mSprite_Y2 = mSprite_Y1+mSprite_h;
+
+	char minuses_s[81];
+
+	for(i=0; i<80; i++)
+		minuses_s[i] = '-';
+	minuses_s[80] = '\0';
+
+	event = 1;  //event = initial entry
+	while(1){
+		//Pad response section
+		waitPadReady(0, 0);
+		if(readpad()){
+			switch(new_pad){
+			case PAD_RIGHT:
+				file_sort = 0;
+				event |= 2;  //event |= valid pad command
+				break;
+			case PAD_DOWN:
+				file_sort = 1;
+				event |= 2;  //event |= valid pad command
+				break;
+			case PAD_LEFT:
+				file_sort = 2;
+				event |= 2;  //event |= valid pad command
+				break;
+			case PAD_UP:
+				file_sort = 3;
+				event |= 2;  //event |= valid pad command
+				break;
+			case PAD_CIRCLE:
+				file_show = 0;
+				event |= 2;  //event |= valid pad command
+				break;
+			case PAD_CROSS:
+				file_show = 1;
+				event |= 2;  //event |= valid pad command
+				break;
+			case PAD_SQUARE:
+				file_show = 2;
+				event |= 2;  //event |= valid pad command
+				if((file_show==2) && (elisaFnt==NULL) && (elisa_failed==FALSE)){
+					int fd;
+
+					fd = uLE_related(tmp, "uLE:/ELISA100.FNT");
+					if(!strncmp(tmp, "cdrom", 5)) strcat(tmp, ";1");
+					if(fd==1)
+						fd = genOpen(tmp, O_RDONLY);
+					else
+						fd = -1;
+					if(fd>=0){
+						test = genLseek(fd,0,SEEK_END);
+						if(test==55016){
+							elisaFnt = (char*)malloc(test);
+							genLseek(fd,0,SEEK_SET);
+							genRead(fd, elisaFnt, test);
+						}
+						genClose(fd);
+					}else
+						elisa_failed = TRUE;
+				}
+				break;
+			case PAD_TRIANGLE:
+				return (file_show!=entry_file_show)||(file_sort!=entry_file_sort);
+			} //ends switch(new_pad)
+		} //ends if(readpad())
+
+		if(event||post_event){ //NB: We need to update two frame buffers per event
+
+			//Display section
+			drawPopSprite(setting->color[0],
+				mSprite_X1, mSprite_Y1,
+				mSprite_X2, mSprite_Y2);
+			drawFrame(mSprite_X1, mSprite_Y1, mSprite_X2, mSprite_Y2, setting->color[1]);
+
+			for(i=0, y=mSprite_Y1+FONT_HEIGHT/2; i<menu_ch_h; i++){
+				if(i==0) sprintf(tmp, "   %s:", LNG(Show_Content_as));
+				else if(i==1) sprintf(tmp, "   %s", &minuses_s[80-Show_len]);
+				else if(i==2) sprintf(tmp, "ÿ0 %s", LNG(Filename));
+				else if(i==3) sprintf(tmp, "ÿ1 %s%s", LNG(Filename), LNG(_plus_Details));
+				else if(i==4) sprintf(tmp, "ÿ2 %s%s", LNG(Game_Title), LNG(_plus_Details));
+				else if(i==6) sprintf(tmp, "   %s:", LNG(Sort_Content_by));
+				else if(i==7) sprintf(tmp, "   %s", &minuses_s[80-Sort_len]);
+				else if(i==8) sprintf(tmp, "ÿ: %s", LNG(No_Sort));
+				else if(i==9) sprintf(tmp, "ÿ; %s", LNG(Filename));
+				else if(i==10) sprintf(tmp, "ÿ< %s", LNG(Game_Title));
+				else if(i==11) sprintf(tmp, "ÿ= %s", LNG(Timestamp));
+				else if(i==13) sprintf(tmp, "ÿ3 %s", LNG(Back_to_Browser));
+				else tmp[0] = 0;
+
+				printXY(tmp, mSprite_X1+2*FONT_WIDTH, y, setting->color[3], TRUE,0);
+				//Display marker for current modes
+				if((file_show == i-2) || (file_sort == i-8))
+					drawChar(LEFT_CUR, mSprite_X1+FONT_WIDTH/2, y, setting->color[2]);
+				y+=FONT_HEIGHT;
+
+			} //ends for loop handling one text row per loop
+
+			//Tooltip section
+			x = SCREEN_MARGIN;
+			y = Menu_tooltip_y;
+			drawSprite(setting->color[0],
+				0, y-1,
+				SCREEN_WIDTH, y+FONT_HEIGHT);
+		}//ends if(event||post_event)
+		drawScr();
+		post_event = event;
+		event = 0;
+	}//ends while
+}
+//------------------------------
+//endfunc BrowserModePopup
+//--------------------------------------------------------------
+// get_FilePath is the main browser function.
+// It also contains the menu handler for the R1 submenu
+// The static variables declared here are only for the use of
+// this function and the submenu functions that it calls
+//--------------------------------------------------------------
+// sincro: ADD USBD_IRX_CNF mode for found IRX file for USBD.IRX
+// example: getFilePath(setting->usbd_file, USBD_IRX_CNF);
+// polo: ADD SKIN_CNF mode for found jpg file for SKIN
+// example: getFilePath(setting->skin, SKIN_CNF);
+// suloku: ADD GUI_SKIN_CNF mode for found jpg file for MAIN_SKIN
+// example: getFilePath(setting->GUI_skin, GUI_SKIN_CNF);
+// dlanor: ADD USBKBD_IRX_CNF mode for found IRX file for USBKBD.IRX
+// example: getFilePath(setting->usbkbd_file, USBKBD_IRX_CNF);
+// dlanor: ADD USBMASS_IRX_CNF mode for found IRX file for usb_mass
+// example: getFilePath(setting->usbmass_file, USBMASS_IRX_CNF);
+// dlanor: ADD SAVE_CNF mode returning either pure path or pathname
+// dlanor: ADD return value 0=pure path, 1=pathname, negative=error/no_selection
+static int browser_cd, browser_up, browser_repos, browser_pushed;
+static int browser_sel, browser_nfiles;
+static void submenu_func_GetSize(char *mess, char *path, FILEINFO *files);
+static void submenu_func_Paste(char *mess, char *path);
+static void submenu_func_mcPaste(char *mess, char *path);
+static void submenu_func_psuPaste(char *mess, char *path);
+int getFilePath(char *out, int cnfmode)
+{
+	char path[MAX_PATH], cursorEntry[MAX_PATH],
+		msg0[MAX_PATH], msg1[MAX_PATH],
+		tmp[MAX_PATH], tmp1[MAX_PATH], tmp2[MAX_PATH], ext[8], *p;
+	u64 color;
+	FILEINFO files[MAX_ENTRY];
+	int top=0, rows;
+	int x, y, y0, y1;
+	int i, j, ret, rv=-1; //NB: rv is for return value of this function
+	int event, post_event=0;
+	int font_height;
+	int iconbase, iconcolr;
+
+  elisa_failed = FALSE; //set at failure to load font, cleared at each browser entry
+
+	browser_cd=TRUE;
+	browser_up=FALSE;
+	browser_repos=FALSE;
+	browser_pushed=TRUE;
+	browser_sel=0;
+	browser_nfiles=0;
+
+	strcpy(ext, cnfmode_extL[cnfmode]);
+
+	if(	(cnfmode==USBD_IRX_CNF)
+		||(cnfmode==USBKBD_IRX_CNF)
+		||(cnfmode==USBMASS_IRX_CNF)
+		||(	(!strncmp(LastDir,setting->Misc,strlen(setting->Misc))) && (cnfmode>LK_ELF_CNF)))
+		path[0] = '\0';			    //start in main root if recent folder unreasonable
+	else
+		strcpy(path, LastDir);	//If reasonable, start in recent folder
+
+	unmountAll();    //unmount all uLE-used mountpoints
+
+	clipPath[0] = 0;
+	nclipFiles = 0;
+	browser_cut = 0;
+
+	file_show = 1;
+	file_sort = 1;
+
+	font_height = FONT_HEIGHT;
+	if((file_show==2) && (elisaFnt!=NULL))
+		font_height = FONT_HEIGHT+2;
+	rows = (Menu_end_y-Menu_start_y)/font_height;
+
+	event = 1;  //event = initial entry
+	while(1){
+
+		//Pad response section
+		waitPadReady(0, 0);
+		if(readpad()){
+			if(new_pad){
+				browser_pushed=TRUE;
+				event |= 2;  //event |= pad command
+			}
+			if(new_pad & PAD_UP)
+				browser_sel--;
+			else if(new_pad & PAD_DOWN)
+				browser_sel++;
+			else if(new_pad & PAD_LEFT)
+				browser_sel-=rows/2;
+			else if(new_pad & PAD_RIGHT)
+				browser_sel+=rows/2;
+			else if(new_pad & PAD_TRIANGLE)
+				browser_up=TRUE;
+			else if((swapKeys && (new_pad & PAD_CROSS))
+			     || (!swapKeys && (new_pad & PAD_CIRCLE)) ){ //Pushed OK
+				if(files[browser_sel].stats.attrFile & MC_ATTR_SUBDIR){
+					//pushed OK for a folder
+					if(!strcmp(files[browser_sel].name,".."))
+						browser_up=TRUE;
+					else {
+						strcat(path, files[browser_sel].name);
+						strcat(path, "/");
+						browser_cd=TRUE;
+					}
+				}else{
+					//pushed OK for a file
+					sprintf(out, "%s%s", path, files[browser_sel].name);
+					// Must to include a function for check IRX Header 
+					if( ((cnfmode==LK_ELF_CNF) || (cnfmode==NON_CNF))
+						&&(checkELFheader(out)<0)){
+						browser_pushed=FALSE;
+						sprintf(msg0, "%s.", LNG(This_file_isnt_an_ELF));
+						out[0] = 0;
+					}else{
+						strcpy(LastDir, path);
+						rv = 1; //flag pathname selected
+						break;
+					}
+				}
+			}else if(new_pad & PAD_R3){ //New clause for uLE-relative paths
+				if(files[browser_sel].stats.attrFile & MC_ATTR_SUBDIR){
+					//pushed R3 for a folder (navigate to uLE CNF folder)
+					strcpy(path, LaunchElfDir);
+					if( (p = strchr(path, ':')) ){ //device separator ?
+						if( p[1] != '/' ){ //missing path separator ? (mass: & host:)
+							p[1] = '/';      //insert path separator
+							strcpy(p+2, LaunchElfDir+(p-path)+1); //append rest of pathname
+						}
+					}
+					browser_cd=TRUE;
+				}else{
+					//pushed R3 for a file (treat as uLE-related)
+					sprintf(out, "%s%s", path, files[browser_sel].name);
+					// Must to include a function for check IRX Header 
+					if( ((cnfmode==LK_ELF_CNF) || (cnfmode==NON_CNF))
+						&&(checkELFheader(out)<0)){
+						browser_pushed=FALSE;
+						sprintf(msg0, "%s.", LNG(This_file_isnt_an_ELF));
+						out[0] = 0;
+					}else{
+						strcpy(LastDir, path);
+						sprintf(out, "%s%s", "uLE:/", files[browser_sel].name);
+						rv = 1; //flag pathname selected
+						break;
+					}
+				}
+			}else if(new_pad & PAD_R2){
+				char *temp = PathPad_menu(path);
+
+				if(temp != NULL){
+					strcpy(path, temp);
+					browser_cd=TRUE;
+					vfreeSpace=FALSE;
+				}
+			} else if(new_pad & PAD_L1) {
+				browser_cd = BrowserModePopup();
+			}
+			//pad checks above are for commands common to all browser modes
+			//pad checks below are for commands that differ depending on cnfmode
+			if(cnfmode==DIR_CNF){
+				if(new_pad & PAD_START) {
+					strcpy(out, path);
+					strcpy(LastDir, path);
+					rv = 0; //flag pathname selected
+					break;
+				}
+			}else if(cnfmode==SAVE_CNF){ //Generic Save commands
+				if(new_pad & PAD_START) {
+					if(files[browser_sel].stats.attrFile & MC_ATTR_SUBDIR){
+						//no file was highlighted, so prep to save with empty filename
+						strcpy(out, path);
+						rv = 0; //flag pure path selected
+					}else{
+						//a file was highlighted, so prep to save with that filename
+						sprintf(out, "%s%s", path, files[browser_sel].name);
+						rv = 1; //flag pathname selected
+					}
+					strcpy(LastDir, path);
+					break;
+				}
+			}
+			if(cnfmode){ //A file is to be selected, not in normal browser mode
+				if(new_pad & PAD_SQUARE) {
+					if(!strcmp(ext,"*")) strcpy(ext, cnfmode_extL[cnfmode]);
+					else				 strcpy(ext, "*");
+					browser_cd=TRUE;
+				}else if((!swapKeys && (new_pad & PAD_CROSS))
+				      || (swapKeys && (new_pad & PAD_CIRCLE)) ){ //Cancel command ?
+					unmountAll();
+					return rv;
+				}
+			}else{ //cnfmode == FALSE
+				if(new_pad & PAD_R1) {
+					ret = menu(path, &files[browser_sel]);
+					if(ret==COPY || ret==CUT){
+						strcpy(clipPath, path);
+						if(nmarks>0){
+							for(i=nclipFiles=0; i<browser_nfiles; i++)
+								if(marks[i])
+									clipFiles[nclipFiles++]=files[i];
+						}else{
+							clipFiles[0]=files[browser_sel];
+							nclipFiles = 1;
+						}
+						sprintf(msg0, "%s", LNG(Copied_to_the_Clipboard));
+						browser_pushed=FALSE;
+						if(ret==CUT)	browser_cut=TRUE;
+						else			browser_cut=FALSE;
+					} //ends COPY and CUT
+					else if(ret==DELETE){
+						if(nmarks==0){	//dlanor: using title was inappropriate here (filesystem op)
+							sprintf(tmp,"%s",files[browser_sel].name);
+							if(files[browser_sel].stats.attrFile & MC_ATTR_SUBDIR)
+								strcat(tmp,"/");
+							sprintf(tmp1, "\n%s ?", LNG(Delete));
+							strcat(tmp, tmp1);
+							ret = ynDialog(tmp);
+						}else
+							ret = ynDialog(LNG(Mark_Files_Delete));
+						
+						if(ret>0){
+							int first_deleted = 0;
+							if(nmarks==0){
+								strcpy(tmp, files[browser_sel].name);
+								if(files[browser_sel].stats.attrFile & MC_ATTR_SUBDIR) strcat(tmp,"/");
+								sprintf(tmp1, " %s", LNG(deleting));
+								strcat(tmp, tmp1);
+								drawMsg(tmp);
+								ret=delete(path, &files[browser_sel]);
+							}else{
+								for(i=0; i<browser_nfiles; i++){
+									if(marks[i]){
+										if(!first_deleted) //if this is the first mark
+											first_deleted = i; //then memorize it for cursor positioning
+										strcpy(tmp, files[i].name);
+										if(files[i].stats.attrFile & MC_ATTR_SUBDIR) strcat(tmp,"/");
+										sprintf(tmp1, " %s", LNG(deleting));
+										strcat(tmp, tmp1);
+										drawMsg(tmp);
+										ret=delete(path, &files[i]);
+										if(ret<0) break;
+									}
+								}
+							}
+							if(ret>=0) {
+								if(nmarks==0)
+									strcpy(cursorEntry, files[browser_sel-1].name);
+								else
+									strcpy(cursorEntry, files[first_deleted-1].name);
+							} else {
+								strcpy(cursorEntry, files[browser_sel].name);
+								sprintf(msg0, "%s Err=%d", LNG(Delete_Failed), ret);
+								browser_pushed = FALSE;
+							}
+							browser_cd=TRUE;
+							browser_repos=TRUE;
+						}
+					} //ends DELETE
+					else if(ret==RENAME){
+						strcpy(tmp, files[browser_sel].name);
+						if(keyboard(tmp, 36)>0){
+							if(Rename(path, &files[browser_sel], tmp)<0){
+								browser_pushed=FALSE;
+								strcpy(msg0, LNG(Rename_Failed));
+							}else
+								browser_cd=TRUE;
+						}
+					} //ends RENAME
+					else if(ret==PASTE)	submenu_func_Paste(msg0, path);
+					else if(ret==MCPASTE)	submenu_func_mcPaste(msg0, path);
+					else if(ret==PSUPASTE)	submenu_func_psuPaste(msg0, path);
+					else if(ret==NEWDIR){
+						tmp[0]=0;
+						if(keyboard(tmp, 36)>0){
+							ret = newdir(path, tmp);
+							if(ret == -17){
+								strcpy(msg0, LNG(directory_already_exists));
+								browser_pushed=FALSE;
+							}else if(ret < 0){
+								strcpy(msg0, LNG(NewDir_Failed));
+								browser_pushed=FALSE;
+							}else{ //dlanor: modified for similarity to PC browsers
+								sprintf(msg0, "%s: ", LNG(Created_folder));
+								strcat(msg0, tmp);
+								browser_pushed=FALSE;
+								strcpy(cursorEntry, tmp);
+								browser_repos=TRUE;
+								browser_cd=TRUE;
+							}
+						}
+					} //ends NEWDIR
+					else if(ret==NEWICON){
+						strcpy(tmp, LNG(Icon_Title));
+						if(keyboard(tmp, 36) <= 0)
+							goto DoneIcon;
+						genFixPath(path, tmp1); 
+						strcat(tmp1, "icon.sys");
+						if((ret = genOpen(tmp1, O_RDONLY))>=0){ //if old "icon.sys" file exists
+							genClose(ret);
+							sprintf(msg1,
+								"\n\"icon.sys\" %s.\n\n%s ?", LNG(file_alredy_exists),
+								LNG(Do_you_wish_to_overwrite_it));
+							if(ynDialog(msg1) < 0)
+								goto DoneIcon;
+							genRemove(tmp1);
+						}
+						make_iconsys(tmp, "icon.icn", tmp1);
+						browser_cd=TRUE;
+						strcpy(tmp, LNG(IconText));
+						keyboard(tmp, 36);
+						genFixPath(path, tmp1); 
+						strcat(tmp1, "icon.icn");
+						if((ret = genOpen(tmp1, O_RDONLY))>=0){ //if old "icon.icn" file exists
+							genClose(ret);
+							sprintf(msg1,
+								"\n\"icon.icn\" %s.\n\n%s ?", LNG(file_alredy_exists),
+								LNG(Do_you_wish_to_overwrite_it));
+							if(ynDialog(msg1) < 0)
+								goto DoneIcon;
+							genRemove(tmp1);
+						}
+						make_icon(tmp, tmp1);
+					DoneIcon:
+						strcpy(tmp, tmp1); //Dummy code to make 'goto DoneIcon' legal for gcc
+					} //ends NEWICON
+					else if((ret==MOUNTVMC0) || (ret==MOUNTVMC1)){
+						i = ret-MOUNTVMC0;
+						load_vmcfs();
+						sprintf(tmp, "vmc%d:", i);
+						if(vmcMounted[i]){
+							if((j=vmc_PartyIndex[i]) >= 0){
+								vmc_PartyIndex[i] = -1;
+								if(j != vmc_PartyIndex[1^i])
+									Party_vmcIndex[j] = -1;
+							}
+							fileXioUmount(tmp);
+							vmcMounted[i] = 0;
+						}
+						j = genFixPath(path, tmp1);
+						strcpy(tmp2, tmp1);
+						if	(!strncmp(path, "host:", 5)){
+							makeHostPath(tmp2, tmp1);
+						}
+						strcat(tmp2, files[browser_sel].name);
+						if( (x = fileXioMount(tmp, tmp2, FIO_MT_RDWR)) >= 0){
+							if((j>=0) && (j<MOUNT_LIMIT)){
+								vmc_PartyIndex[i] = j;
+								Party_vmcIndex[j] = i;
+							}
+							vmcMounted[i] = 1;
+							sprintf(path, "%s/", tmp);
+							browser_cd = TRUE;
+							cnfmode = NON_CNF;
+							strcpy(ext, cnfmode_extL[cnfmode]);
+						}
+						else{
+							sprintf(msg1, "\n'%s vmc%d:' for \"%s\"\nResult=%d",
+								LNG(Mount), i, tmp2, x);
+							(void) ynDialog(msg1);
+						}
+					} //ends MOUNTVMCx
+					else if(ret==GETSIZE){
+						submenu_func_GetSize(msg0, path, files);
+					} //ends GETSIZE
+					//R1 menu handling is completed above
+				}else if((!swapKeys && new_pad & PAD_CROSS)
+				      || (swapKeys && new_pad & PAD_CIRCLE) ){
+					if(browser_sel!=0 && path[0]!=0 && strcmp(path,"hdd0:/")){
+						if(marks[browser_sel]){
+							marks[browser_sel]=FALSE;
+							nmarks--;
+						}else{
+							marks[browser_sel]=TRUE;
+							nmarks++;
+						}
+					}
+					browser_sel++;
+				} else if(new_pad & PAD_SQUARE) {
+					if(path[0]!=0 && strcmp(path,"hdd0:/")){
+						for(i=1; i<browser_nfiles; i++){
+							if(marks[i]){
+								marks[i]=FALSE;
+								nmarks--;
+							}else{
+								marks[i]=TRUE;
+								nmarks++;
+							}
+						}
+					}
+				} else if(new_pad & PAD_SELECT){  //Leaving the browser ?
+					unmountAll();
+					return rv;
+				}
+			}
+		}//ends pad response section
+
+		//browser path adjustment section
+		if(browser_up){
+			if((p=strrchr(path, '/'))!=NULL)
+				*p = 0;
+			if((p=strrchr(path, '/'))!=NULL){
+				p++;
+				strcpy(cursorEntry, p);
+				*p = 0;
+			}else{
+				strcpy(cursorEntry, path);
+				path[0] = 0;
+			}
+			browser_cd=TRUE;
+			browser_repos=TRUE;
+		}//ends 'if(browser_up)'
+		//----- Process newly entered directory here (incl initial entry)
+		if(browser_cd){
+			browser_nfiles = setFileList(path, ext, files, cnfmode);
+			if(!cnfmode){  //Calculate free space (unless configuring)
+				if(!strncmp(path, "mc", 2)){
+					mcGetInfo(path[2]-'0', 0, &mctype_PSx, &mcfreeSpace, NULL);
+					mcSync(0, NULL, &ret);
+					freeSpace = mcfreeSpace*((mctype_PSx==1) ? 8192 : 1024);
+					vfreeSpace=TRUE;
+				}else if(!strncmp(path,"vmc",3)){
+					strncpy(tmp, path, 5);
+					tmp[5]='\0';
+					freeSpace = fileXioDevctl(tmp, DEVCTL_VMCFS_CKFREE, NULL, 0, NULL, 0);
+					vfreeSpace=TRUE;
+				}else if(!strncmp(path,"hdd",3)&&strcmp(path,"hdd0:/")){
+					s64 ZoneFree, ZoneSize;
+					char pfs_str[6];
+
+					strcpy(pfs_str, "pfs0:");
+					pfs_str[3] += latestMount;
+					ZoneFree = fileXioDevctl(pfs_str, PFSCTL_GET_ZONE_FREE, NULL, 0, NULL, 0);
+					ZoneSize = fileXioDevctl(pfs_str, PFSCTL_GET_ZONE_SIZE, NULL, 0, NULL, 0);
+					//printf("ZoneFree==%d  ZoneSize==%d\r\n", ZoneFree, ZoneSize);
+					freeSpace = ZoneFree*ZoneSize;
+					vfreeSpace=TRUE;
+				}
+			}
+			browser_sel=0;
+			top=0;
+			if(browser_repos){
+				browser_repos = FALSE;
+				for(i=0; i<browser_nfiles; i++) {
+					if(!strcmp(cursorEntry, files[i].name)) {
+						browser_sel=i;
+						top=browser_sel-3;
+						break;
+					}
+				}
+			} //ends if(browser_repos)
+			nmarks = 0;
+			memset(marks, 0, MAX_ENTRY);
+			browser_cd=FALSE;
+			browser_up=FALSE;
+		} //ends if(browser_cd)
+		if(setting->discControl && !strncmp(path,"cdfs",4))
+			uLE_cdStop();
+		if(top > browser_nfiles-rows)	top=browser_nfiles-rows;
+		if(top < 0)				top=0;
+		if(browser_sel >= browser_nfiles)		browser_sel=browser_nfiles-1;
+		if(browser_sel < 0)				browser_sel=0;
+		if(browser_sel >= top+rows)		top=browser_sel-rows+1;
+		if(browser_sel < top)			top=browser_sel;
+		
+		if(event||post_event){ //NB: We need to update two frame buffers per event
+
+			//Display section
+			clrScr(setting->color[0]);
+
+			x = Menu_start_x;
+			y = Menu_start_y;
+			font_height = FONT_HEIGHT;
+			if((file_show==2) && (elisaFnt!=NULL)){
+				y-=2;
+				font_height = FONT_HEIGHT+2;
+			}
+			rows = (Menu_end_y-Menu_start_y)/font_height;
+
+			for(i=0; i<rows; i++) //Repeat loop for each browser text row
+			{
+				int	title_flag = 0; //Assume that normal file/folder names are wanted
+				int name_limit = 0; //Assume that no name length problems exist
+
+				if(top+i >= browser_nfiles) break;
+				if(top+i == browser_sel) color = setting->color[2];  //Highlight cursor line
+				else			 color = setting->color[3];
+				
+				if(!strcmp(files[top+i].name,".."))
+					strcpy(tmp,"..");
+				else if((file_show==2) && files[top+i].title[0]!=0) {
+					strcpy(tmp,files[top+i].title);
+					title_flag = 1;
+				}else{ //Show normal file/folder names
+					strcpy(tmp,files[top+i].name);
+					if(file_show > 0){  //Does display mode include file details ?
+						name_limit = 43*8;
+					} else {  //Filenames are shown without file details
+						name_limit = 71*8;
+					}
+				}
+				if(name_limit){ //Do we need to check name length ?
+					int name_end = name_limit/7; //Max string length for acceptable spacing
+
+					if(files[top+i].stats.attrFile & MC_ATTR_SUBDIR)
+						name_end -= 1;  //For folders, reserve one character for final '/'
+					if(strlen(tmp) > name_end){  //Is name too long for clean display ?
+						tmp[name_end-1] = '~';  //indicate filename abbreviation
+						tmp[name_end] = 0;    //abbreviate name length to make room for details
+					}
+				}
+
+				if(files[top+i].stats.attrFile & MC_ATTR_SUBDIR)
+					strcat(tmp, "/");
+				if(title_flag)
+					printXY_sjis(tmp, x+4, y, color, TRUE);
+				else
+					printXY(tmp, x+4, y, color, TRUE, name_limit);
+				if(file_show > 0){
+					unsigned int size = files[top+i].stats.fileSizeByte;
+					int scale = 0; //0==Bytes, 1==KBytes, 2==MBytes, 3==GB
+					char scale_s[5] = " KMGT";
+					PS2TIME timestamp = *(PS2TIME *) &files[top+i].stats._modify;
+
+					if(!size_valid) size = 0;
+					if(!time_valid) memset((void *) &timestamp, 0, sizeof(timestamp));
+
+					if(!size_valid || !(top+i))
+						strcpy(tmp, "----- B");
+					else {
+						while(size > 99999){
+							scale++;
+							size /= 1024;
+						}
+						sprintf(tmp, "%5u%cB", size, scale_s[scale]);
+					}
+
+					if(!time_valid || !(top+i))
+						strcat(tmp, " ----.--.-- --:--:--");
+					else {
+						sprintf(tmp+strlen(tmp), " %04d.%02d.%02d %02d:%02d:%02d", 
+							((timestamp.year < 2256) ?timestamp.year :(timestamp.year-256)),
+							timestamp.month,
+							timestamp.day,
+							timestamp.hour,
+							timestamp.min,
+							timestamp.sec
+						);
+					}
+
+					printXY(tmp, x+4+44*FONT_WIDTH, y, color, TRUE, 0);
+				}
+				if(setting->FB_NoIcons){ //if FileBrowser should not use icons
+					if(marks[top+i])
+						drawChar('*', x-6, y, setting->color[3]);
+				} else { //if Icons must be used in front of file/folder names
+					if(files[top+i].stats.attrFile & MC_ATTR_SUBDIR){
+						iconbase = ICON_FOLDER;
+						iconcolr = 4;
+					} else {
+						iconbase = ICON_FILE;
+						p = strrchr(files[top+i].name, '.');
+						if(p!=NULL && !stricmp(p+1, "ELF"))
+							iconcolr = 5;
+						else
+							iconcolr = 6;
+					}
+					if(marks[top+i])
+						iconbase += 2;
+					drawChar(iconbase, x-3-FONT_WIDTH, y, setting->color[iconcolr]);
+					drawChar(iconbase+1, x-3, y, setting->color[iconcolr]);
+				}
+				y += font_height;
+			} //ends for, so all browser rows were fixed above
+			if(browser_nfiles > rows) { //if more files than available rows, use scrollbar
+				drawFrame(SCREEN_WIDTH-SCREEN_MARGIN-LINE_THICKNESS*8, Frame_start_y,
+					SCREEN_WIDTH-SCREEN_MARGIN, Frame_end_y, setting->color[1]);
+				y0=(Menu_end_y-Menu_start_y+8) * ((double)top/browser_nfiles);
+				y1=(Menu_end_y-Menu_start_y+8) * ((double)(top+rows)/browser_nfiles);
+				drawOpSprite(setting->color[1],
+					SCREEN_WIDTH-SCREEN_MARGIN-LINE_THICKNESS*6, (y0+Menu_start_y-4),
+					SCREEN_WIDTH-SCREEN_MARGIN-LINE_THICKNESS*2, (y1+Menu_start_y-4));
+			} //ends clause for scrollbar
+			if(nclipFiles) { //if Something in clipboard, emulate LED indicator
+				u64 LED_colour, RIM_colour = GS_SETREG_RGBA(0,0,0,0);
+				int RIM_w=4, LED_w=6, indicator_w = LED_w+2*RIM_w;
+				int x2 = SCREEN_WIDTH-SCREEN_MARGIN-2, x1 = x2-indicator_w;
+				int y1 = Frame_start_y+2, y2 = y1+indicator_w; 
+
+				if(browser_cut) LED_colour = GS_SETREG_RGBA(0xC0,0,0,0); //Red LED == CUT
+				else            LED_colour = GS_SETREG_RGBA(0,0xC0,0,0); //Green LED == COPY
+				drawOpSprite(RIM_colour, x1, y1, x2, y2);
+				drawOpSprite(LED_colour, x1+RIM_w, y1+RIM_w, x2-RIM_w, y2-RIM_w);
+			} //ends clause for clipboard indicator
+			if(browser_pushed)
+				sprintf(msg0, "%s: %s", LNG(Path), path);
+
+			//Tooltip section
+			if(cnfmode) {//cnfmode indicates configurable file selection
+				if (swapKeys)
+					sprintf(msg1, "ÿ1:%s ÿ0:%s ÿ3:%s ÿ2:", LNG(OK), LNG(Cancel), LNG(Up));
+				else
+					sprintf(msg1, "ÿ0:%s ÿ1:%s ÿ3:%s ÿ2:", LNG(OK), LNG(Cancel), LNG(Up));
+				if(ext[0] == '*')
+					strcat(msg1, "*->");
+				strcat(msg1, cnfmode_extU[cnfmode]);
+				if(ext[0] != '*')
+					strcat(msg1, "->*");
+				sprintf(tmp, " R2:%s", LNG(PathPad));
+				strcat(msg1, tmp);
+				if((cnfmode==DIR_CNF)||(cnfmode==SAVE_CNF)) { //modes using Start
+					sprintf(tmp, " Start:%s", LNG(Choose));
+					strcat(msg1, tmp);
+				}
+			}else{ // cnfmode == FALSE
+				if (swapKeys) 
+					sprintf(msg1, "ÿ1:%s ÿ3:%s ÿ0:%s ÿ2:%s L1:%s R1:%s R2:%s Sel:%s",
+						LNG(OK), LNG(Up), LNG(Mark), LNG(RevMark),
+						LNG(Mode), LNG(Menu), LNG(PathPad), LNG(Exit));
+				else
+					sprintf(msg1, "ÿ0:%s ÿ3:%s ÿ1:%s ÿ2:%s L1:%s R1:%s R2:%s Sel:%s",
+						LNG(OK), LNG(Up), LNG(Mark), LNG(RevMark),
+						LNG(Mode), LNG(Menu), LNG(PathPad), LNG(Exit));
+			}
+			setScrTmp(msg0, msg1);
+			if(vfreeSpace){
+				if(freeSpace >= 1024*1024)
+					sprintf(tmp, "[%.1fMB %s]", (double)freeSpace/1024/1024, LNG(free));
+				else if(freeSpace >= 1024)
+					sprintf(tmp, "[%.1fKB %s]", (double)freeSpace/1024, LNG(free));
+				else
+					sprintf(tmp, "[%dB %s]", (int) freeSpace, LNG(free));
+				ret=strlen(tmp);
+				drawSprite(setting->color[0],
+					SCREEN_WIDTH-SCREEN_MARGIN-(ret+1)*FONT_WIDTH, (Menu_message_y-1),
+					SCREEN_WIDTH-SCREEN_MARGIN, (Menu_message_y+FONT_HEIGHT));
+				printXY(tmp,
+					SCREEN_WIDTH-SCREEN_MARGIN-ret*FONT_WIDTH,
+					(Menu_message_y),
+					setting->color[2], TRUE, 0);
+			}
+		}//ends if(event||post_event)
+		drawScr();
+		post_event = event;
+		event = 0;
+	}//ends while
+	
+	//Leaving the browser
+	unmountAll();
+	return rv;
+}
+//------------------------------
+//endfunc getFilePath
+//--------------------------------------------------------------
+void submenu_func_GetSize(char *mess, char *path, FILEINFO *files)
+{
+	s64 size;
+	int	ret, i, text_pos, text_inc, sel=-1;
+	char filepath[MAX_PATH];
+
+/*
+	int test;
+	iox_stat_t stats;
+	PS2TIME *time;
+*/
+
+	drawMsg(LNG(Checking_Size));
+	if(nmarks==0){
+		size = getFileSize(path, &files[browser_sel]);
+		sel = browser_sel; //for stat checking
+	}else{
+		for(i=size=0; i<browser_nfiles; i++){
+			if(marks[i]){
+				size += getFileSize(path, &files[i]);
+				sel = i; //for stat checking
+			}
+			if(size<0) size=-1;
+		}
+	}
+	printf("size result = %ld\r\n", size);
+	if(size<0){
+		strcpy(mess, LNG(Size_test_Failed));
+		text_pos = strlen(mess);
+	}else{
+		text_pos = 0;
+		if(size >= 1024*1024)
+			sprintf(mess, "%s = %.1fMB%n", LNG(SIZE), (double)size/1024/1024, &text_inc);
+		else if(size >= 1024)
+			sprintf(mess, "%s = %.1fKB%n", LNG(SIZE), (double)size/1024, &text_inc);
+		else
+			sprintf(mess, "%s = %ldB%n", LNG(SIZE), size, &text_inc);
+		text_pos += text_inc;
+	}
+
+//----- Comment out this section to skip attributes entirely -----
+	if((nmarks<2) && (sel>=0)){
+		sprintf(filepath, "%s%s", path, files[sel].name);
+//----- Start of section for debug display of attributes -----
+/*
+		printf("path =\"%s\"\r\n", path);
+		printf("file =\"%s\"\r\n", files[sel].name);
+		if	(!strncmp(filepath, "host:/", 6))
+			makeHostPath(filepath+5, filepath+6);
+		if(!strncmp(filepath, "hdd", 3))
+			test = fileXioGetStat(filepath, &stats);
+		else
+			test = fioGetstat(filepath, (fio_stat_t *) &stats);
+		printf("test = %d\r\n", test);
+		printf("mode = %08X\r\n", stats.mode);
+		printf("attr = %08X\r\n", stats.attr);
+		printf("size = %08X\r\n", stats.size);
+		time = (PS2TIME *) stats.ctime;
+		printf("ctime = %04d.%02d.%02d %02d:%02d:%02d.%02d\r\n",
+			time->year,time->month,time->day,
+			time->hour,time->min,time->sec,time->unknown);
+		time = (PS2TIME *) stats.atime;
+		printf("atime = %04d.%02d.%02d %02d:%02d:%02d.%02d\r\n",
+			time->year,time->month,time->day,
+			time->hour,time->min,time->sec,time->unknown);
+		time = (PS2TIME *) stats.mtime;
+		printf("mtime = %04d.%02d.%02d %02d:%02d:%02d.%02d\r\n",
+			time->year,time->month,time->day,
+			time->hour,time->min,time->sec,time->unknown);
+*/
+//----- End of section for debug display of attributes -----
+		sprintf(mess+text_pos, " m=%04X %04d.%02d.%02d %02d:%02d:%02d%n",
+			files[sel].stats.attrFile,
+			files[sel].stats._modify.year,
+			files[sel].stats._modify.month,
+			files[sel].stats._modify.day,
+			files[sel].stats._modify.hour,
+			files[sel].stats._modify.min,
+			files[sel].stats._modify.sec,
+			&text_inc
+		);
+		text_pos += text_inc;
+		if(!strncmp(path, "mc", 2)){
+			mcGetInfo(path[2]-'0', 0, &mctype_PSx, NULL, NULL);
+			mcSync(0, NULL, &ret);
+			sprintf(mess+text_pos, " %s=%d%n", LNG(mctype), mctype_PSx, &text_inc);
+			text_pos += text_inc;
+		}
+		sprintf(mess+text_pos, " mcTsz=%d%n", files[sel].stats.fileSizeByte, &text_inc);
+		text_pos += text_inc;
+	}
+//----- End of sections that show attributes -----
+	browser_pushed = FALSE;
+}
+//------------------------------
+//endfunc submenu_func_GetSize
+//--------------------------------------------------------------
+void subfunc_Paste(char *mess, char *path)
+{
+	char tmp[MAX_PATH], tmp1[MAX_PATH];
+	int i, ret=-1;
+	
+	written_size = 0;
+	PasteTime = Timer();	      //Note initial pasting time
+	drawMsg(LNG(Pasting));
+	if(!strcmp(path,clipPath)) goto finished;
+	
+	for(i=0; i<nclipFiles; i++){
+		strcpy(tmp, clipFiles[i].name);
+		if(clipFiles[i].stats.attrFile & MC_ATTR_SUBDIR) strcat(tmp,"/");
+		sprintf(tmp1, " %s", LNG(pasting));
+		strcat(tmp, tmp1);
+		drawMsg(tmp);
+		PM_flag[0] = PM_NORMAL; //Always use normal mode at top level
+		PM_file[0] = -1;        //Thus no attribute file is used here
+		ret = copy(path, clipPath, clipFiles[i], 0);
+		if(ret < 0) break;
+		if(browser_cut){
+			ret=delete(clipPath, &clipFiles[i]);
+			if(ret<0) break;
+		}
+	}
+
+//	unmountAll(); //disabled to avoid interference with VMC implementation
+
+finished:
+	if(ret < 0){
+		strcpy(mess, LNG(Paste_Failed));
+		browser_pushed = FALSE;
+	}else
+		if(browser_cut) nclipFiles=0;
+	browser_cd=TRUE;
+}
+//------------------------------
+//endfunc subfunc_Paste
+//--------------------------------------------------------------
+void submenu_func_Paste(char *mess, char *path)
+{
+	if(new_pad & PAD_SQUARE)
+		PasteMode = PM_RENAME;
+	else
+		PasteMode = PM_NORMAL;
+	subfunc_Paste(mess, path);
+}
+//------------------------------
+//endfunc submenu_func_Paste
+//--------------------------------------------------------------
+void submenu_func_mcPaste(char *mess, char *path)
+{
+	if(!strncmp(path, "mc", 2)||!strncmp(path, "vmc", 3)){
+		PasteMode = PM_MC_RESTORE;
+	} else {
+		PasteMode = PM_MC_BACKUP;
+	}
+	subfunc_Paste(mess, path);
+}
+//------------------------------
+//endfunc submenu_func_mcPaste
+//--------------------------------------------------------------
+void submenu_func_psuPaste(char *mess, char *path)
+{
+	if(!strncmp(path, "mc", 2)||!strncmp(path, "vmc", 3)){
+		PasteMode = PM_PSU_RESTORE;
+	} else {
+		PasteMode = PM_PSU_BACKUP;
+	}
+	subfunc_Paste(mess, path);
+}
+//------------------------------
+//endfunc submenu_func_psuPaste
+//--------------------------------------------------------------
+//End of file: filer.c
+//--------------------------------------------------------------
Index: ps2launchargs/source/uLaunchELF/font_uLE.c
===================================================================
--- ps2launchargs/source/uLaunchELF/font_uLE.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/font_uLE.c	(revision 1101)
@@ -0,0 +1,645 @@
+//---------------------------------------------------------------------------
+//File name:    font_uLE.c  //Holds FontBuffer and font_uLE (default font)
+//---------------------------------------------------------------------------
+unsigned char FontBuffer[256*16]; //This holds either default or external font
+unsigned char font_uLE[] = {
+//Font position 0x000
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x000 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x001 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x002 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x003 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x004 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x005 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x006 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x007 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+//Font position 0x008
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x008 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x009 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x00A == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x00B == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x00C == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x00D == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x00E == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x00F == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+//Font position 0x010
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x010 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x011 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x012 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x013 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x014 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x015 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x016 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x017 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+//Font position 0x018
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x018 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x019 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x01A == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x01B == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x01C == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x01D == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x01E == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x01F == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+//Font position 0x020
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x020 == ' '
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, //char 0x021 == '!'
+	0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
+	0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, //char 0x022 == '"'
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x66, 0x66, 0xFF, 0xFF, 0x66, 0x66, //char 0x023 == '#'
+	0x66, 0x66, 0xFF, 0xFF, 0x66, 0x66, 0x00, 0x00,
+	0x18, 0x18, 0x3E, 0x3E, 0x60, 0x60, 0x3C, 0x3C, //char 0x024 == '$'
+	0x06, 0x06, 0x7C, 0x7C, 0x18, 0x18, 0x00, 0x00,
+	0x00, 0x00, 0x66, 0x66, 0x6C, 0x6C, 0x18, 0x18, //char 0x025 == '%'
+	0x30, 0x30, 0x66, 0x66, 0x46, 0x46, 0x00, 0x00,
+	0x1C, 0x1C, 0x36, 0x36, 0x1C, 0x1C, 0x38, 0x38, //char 0x026 == '&'
+	0x6F, 0x6F, 0x66, 0x66, 0x3B, 0x3B, 0x00, 0x00,
+	0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, //char 0x027 == '''
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+//Font position 0x028
+	0x00, 0x00, 0x0E, 0x0E, 0x1C, 0x1C, 0x18, 0x18, //char 0x028 == '('
+	0x18, 0x18, 0x1C, 0x1C, 0x0E, 0x0E, 0x00, 0x00,
+	0x00, 0x00, 0x70, 0x70, 0x38, 0x38, 0x18, 0x18, //char 0x029 == ')'
+	0x18, 0x18, 0x38, 0x38, 0x70, 0x70, 0x00, 0x00,
+	0x00, 0x00, 0x66, 0x66, 0x3C, 0x3C, 0xFF, 0xFF, //char 0x02A == '*'
+	0x3C, 0x3C, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, //char 0x02B == '+'
+	0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x02C == ','
+	0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x30, 0x30,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, //char 0x02D == '-'
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x02E == '.'
+	0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+	0x00, 0x00, 0x06, 0x06, 0x0C, 0x0C, 0x18, 0x18, //char 0x02F == '/'
+	0x30, 0x30, 0x60, 0x60, 0x40, 0x40, 0x00, 0x00,
+//Font position 0x030
+	0x00, 0x00, 0x3C, 0x3C, 0x66, 0x66, 0x6E, 0x6E, //char 0x030 == '0'
+	0x76, 0x76, 0x66, 0x66, 0x3C, 0x3C, 0x00, 0x00,
+	0x00, 0x00, 0x18, 0x18, 0x38, 0x38, 0x18, 0x18, //char 0x031 == '1'
+	0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00,
+	0x00, 0x00, 0x3C, 0x3C, 0x66, 0x66, 0x0C, 0x0C, //char 0x032 == '2'
+	0x18, 0x18, 0x30, 0x30, 0x7E, 0x7E, 0x00, 0x00,
+	0x00, 0x00, 0x7E, 0x7E, 0x0C, 0x0C, 0x18, 0x18, //char 0x033 == '3'
+	0x0C, 0x0C, 0x66, 0x66, 0x3C, 0x3C, 0x00, 0x00,
+	0x00, 0x00, 0x0C, 0x0C, 0x1C, 0x1C, 0x3C, 0x3C, //char 0x034 == '4'
+	0x6C, 0x6C, 0x7E, 0x7E, 0x0C, 0x0C, 0x00, 0x00,
+	0x00, 0x00, 0x7E, 0x7E, 0x60, 0x60, 0x7C, 0x7C, //char 0x035 == '5'
+	0x06, 0x06, 0x66, 0x66, 0x3C, 0x3C, 0x00, 0x00,
+	0x00, 0x00, 0x3C, 0x3C, 0x60, 0x60, 0x7C, 0x7C, //char 0x036 == '6'
+	0x66, 0x66, 0x66, 0x66, 0x3C, 0x3C, 0x00, 0x00,
+	0x00, 0x00, 0x7E, 0x7E, 0x06, 0x06, 0x0C, 0x0C, //char 0x037 == '7'
+	0x18, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00,
+//Font position 0x038
+	0x00, 0x00, 0x3C, 0x3C, 0x66, 0x66, 0x3C, 0x3C, //char 0x038 == '8'
+	0x66, 0x66, 0x66, 0x66, 0x3C, 0x3C, 0x00, 0x00,
+	0x00, 0x00, 0x3C, 0x3C, 0x66, 0x66, 0x3E, 0x3E, //char 0x039 == '9'
+	0x06, 0x06, 0x0C, 0x0C, 0x38, 0x38, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, //char 0x03A == ':'
+	0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, //char 0x03B == ';'
+	0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x30, 0x30,
+	0x06, 0x06, 0x0C, 0x0C, 0x18, 0x18, 0x30, 0x30, //char 0x03C == '<'
+	0x18, 0x18, 0x0C, 0x0C, 0x06, 0x06, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x00, 0x00, //char 0x03D == '='
+	0x00, 0x00, 0x7E, 0x7E, 0x00, 0x00, 0x00, 0x00,
+	0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0C, 0x0C, //char 0x03E == '>'
+	0x18, 0x18, 0x30, 0x30, 0x60, 0x60, 0x00, 0x00,
+	0x00, 0x00, 0x3C, 0x3C, 0x66, 0x66, 0x0C, 0x0C, //char 0x03F == '?'
+	0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
+//Font position 0x040
+	0x00, 0x00, 0x3C, 0x3C, 0x66, 0x66, 0x6E, 0x6E, //char 0x040 == '@'
+	0x6E, 0x6E, 0x60, 0x60, 0x3E, 0x3E, 0x00, 0x00,
+	0x00, 0x00, 0x18, 0x3C, 0x66, 0x66, 0x66, 0x66, //char 0x041 == 'A'
+	0x7E, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00,
+	0x00, 0x00, 0x7C, 0x7C, 0x66, 0x66, 0x66, 0x7C, //char 0x042 == 'B'
+	0x7C, 0x66, 0x66, 0x66, 0x7C, 0x7C, 0x00, 0x00,
+	0x00, 0x00, 0x3C, 0x3C, 0x66, 0x66, 0x60, 0x60, //char 0x043 == 'C'
+	0x60, 0x60, 0x66, 0x66, 0x3C, 0x3C, 0x00, 0x00,
+	0x00, 0x00, 0x78, 0x78, 0x6C, 0x6C, 0x66, 0x66, //char 0x044 == 'D'
+	0x66, 0x66, 0x6C, 0x6C, 0x78, 0x78, 0x00, 0x00,
+	0x00, 0x00, 0x7E, 0x7E, 0x60, 0x60, 0x60, 0x7C, //char 0x045 == 'E'
+	0x7C, 0x60, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00,
+	0x00, 0x00, 0x7E, 0x7E, 0x60, 0x60, 0x60, 0x7C, //char 0x046 == 'F'
+	0x7C, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00,
+	0x00, 0x00, 0x3E, 0x3E, 0x60, 0x60, 0x60, 0x60, //char 0x047 == 'G'
+	0x6E, 0x6E, 0x66, 0x66, 0x3E, 0x3E, 0x00, 0x00,
+//Font position 0x048
+	0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, //char 0x048 == 'H'
+	0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00,
+	0x00, 0x00, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, //char 0x049 == 'I'
+	0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00,
+	0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, //char 0x04A == 'J'
+	0x06, 0x06, 0x66, 0x66, 0x3C, 0x3C, 0x00, 0x00,
+	0x00, 0x00, 0x66, 0x66, 0x6C, 0x6C, 0x78, 0x78, //char 0x04B == 'K'
+	0x78, 0x78, 0x6C, 0x6C, 0x66, 0x66, 0x00, 0x00,
+	0x00, 0x00, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, //char 0x04C == 'L'
+	0x60, 0x60, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00,
+	0x00, 0x00, 0x63, 0x63, 0x77, 0x77, 0x7F, 0x7F, //char 0x04D == 'M'
+	0x6B, 0x6B, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00,
+	0x00, 0x00, 0x66, 0x66, 0x76, 0x76, 0x7E, 0x7E, //char 0x04E == 'N'
+	0x7E, 0x7E, 0x6E, 0x6E, 0x66, 0x66, 0x00, 0x00,
+	0x00, 0x00, 0x3C, 0x3C, 0x66, 0x66, 0x66, 0x66, //char 0x04F == 'O'
+	0x66, 0x66, 0x66, 0x66, 0x3C, 0x3C, 0x00, 0x00,
+//Font position 0x050
+	0x00, 0x00, 0x7C, 0x7C, 0x66, 0x66, 0x66, 0x7C, //char 0x050 == 'P'
+	0x7C, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00,
+	0x00, 0x00, 0x3C, 0x3C, 0x66, 0x66, 0x66, 0x66, //char 0x051 == 'Q'
+	0x66, 0x66, 0x6C, 0x6C, 0x36, 0x36, 0x00, 0x00,
+	0x00, 0x00, 0x7C, 0x7E, 0x66, 0x66, 0x66, 0x7E, //char 0x052 == 'R'
+	0x7C, 0x78, 0x68, 0x6C, 0x66, 0x66, 0x00, 0x00,
+	0x00, 0x00, 0x3C, 0x3E, 0x60, 0x60, 0x60, 0x3C, //char 0x053 == 'S'
+	0x3C, 0x06, 0x06, 0x06, 0x7C, 0x3C, 0x00, 0x00,
+	0x00, 0x00, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, //char 0x054 == 'T'
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+	0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, //char 0x055 == 'U'
+	0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+	0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, //char 0x056 == 'V'
+	0x66, 0x66, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x00,
+	0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x6B, 0x6B, //char 0x057 == 'W'
+	0x7F, 0x7F, 0x77, 0x77, 0x63, 0x63, 0x00, 0x00,
+//Font position 0x058
+	0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x3C, //char 0x058 == 'X'
+	0x3C, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00,
+	0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x3C, //char 0x059 == 'Y'
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+	0x00, 0x00, 0x7E, 0x7E, 0x0C, 0x0C, 0x18, 0x18, //char 0x05A == 'Z'
+	0x30, 0x30, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00,
+	0x00, 0x00, 0x1E, 0x1E, 0x18, 0x18, 0x18, 0x18, //char 0x05B == '['
+	0x18, 0x18, 0x18, 0x18, 0x1E, 0x1E, 0x00, 0x00,
+	0x00, 0x00, 0x40, 0x40, 0x60, 0x60, 0x30, 0x30, //char 0x05C == '\'
+	0x18, 0x18, 0x0C, 0x0C, 0x06, 0x06, 0x00, 0x00,
+	0x00, 0x00, 0x78, 0x78, 0x18, 0x18, 0x18, 0x18, //char 0x05D == ']'
+	0x18, 0x18, 0x18, 0x18, 0x78, 0x78, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x08, 0x1C, 0x1C, 0x36, 0x36, //char 0x05E == '^'
+	0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x05F == '_'
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+//Font position 0x060
+	0x00, 0x00, 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, //char 0x060 == '`'
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x3C, 0x3C, 0x06, 0x06, //char 0x061 == 'a'
+	0x3E, 0x3E, 0x66, 0x66, 0x3E, 0x3E, 0x00, 0x00,
+	0x00, 0x00, 0x60, 0x60, 0x60, 0x60, 0x7C, 0x7C, //char 0x062 == 'b'
+	0x66, 0x66, 0x66, 0x66, 0x7C, 0x7C, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x3C, 0x3C, 0x60, 0x60, //char 0x063 == 'c'
+	0x60, 0x60, 0x60, 0x60, 0x3C, 0x3C, 0x00, 0x00,
+	0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x3E, 0x3E, //char 0x064 == 'd'
+	0x66, 0x66, 0x66, 0x66, 0x3E, 0x3E, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x3C, 0x3C, 0x66, 0x66, //char 0x065 == 'e'
+	0x7E, 0x7E, 0x60, 0x60, 0x3C, 0x3C, 0x00, 0x00,
+	0x00, 0x00, 0x0E, 0x0E, 0x18, 0x18, 0x3E, 0x3E, //char 0x066 == 'f'
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x3E, 0x3E, 0x66, 0x66, //char 0x067 == 'g'
+	0x66, 0x66, 0x3E, 0x3E, 0x06, 0x06, 0x7C, 0x7C,
+//Font position 0x068
+	0x00, 0x00, 0x60, 0x60, 0x60, 0x60, 0x7C, 0x7C, //char 0x068 == 'h'
+	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00,
+	0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x38, 0x38, //char 0x069 == 'i'
+	0x18, 0x18, 0x18, 0x18, 0x3C, 0x3C, 0x00, 0x00,
+	0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x06, 0x06, //char 0x06A == 'j'
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x3C, 0x3C,
+	0x00, 0x00, 0x60, 0x60, 0x60, 0x60, 0x6C, 0x6C, //char 0x06B == 'k'
+	0x78, 0x78, 0x6C, 0x6C, 0x66, 0x66, 0x00, 0x00,
+	0x00, 0x00, 0x38, 0x38, 0x18, 0x18, 0x18, 0x18, //char 0x06C == 'l'
+	0x18, 0x18, 0x18, 0x18, 0x3C, 0x3C, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x7F, 0x7F, //char 0x06D == 'm'
+	0x7F, 0x7F, 0x6B, 0x6B, 0x63, 0x63, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x7C, 0x7C, 0x66, 0x66, //char 0x06E == 'n'
+	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x3C, 0x3C, 0x66, 0x66, //char 0x06F == 'o'
+	0x66, 0x66, 0x66, 0x66, 0x3C, 0x3C, 0x00, 0x00,
+//Font position 0x070
+	0x00, 0x00, 0x00, 0x00, 0x7C, 0x7C, 0x66, 0x66, //char 0x070 == 'p'
+	0x66, 0x66, 0x7C, 0x7C, 0x60, 0x60, 0x60, 0x60,
+	0x00, 0x00, 0x00, 0x00, 0x3E, 0x3E, 0x66, 0x66, //char 0x071 == 'q'
+	0x66, 0x66, 0x3E, 0x3E, 0x06, 0x06, 0x06, 0x06,
+	0x00, 0x00, 0x00, 0x00, 0x7C, 0x7C, 0x66, 0x66, //char 0x072 == 'r'
+	0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x3E, 0x3E, 0x60, 0x60, //char 0x073 == 's'
+	0x3C, 0x3C, 0x06, 0x06, 0x7C, 0x7C, 0x00, 0x00,
+	0x00, 0x00, 0x18, 0x18, 0x7E, 0x7E, 0x18, 0x18, //char 0x074 == 't'
+	0x18, 0x18, 0x18, 0x18, 0x0E, 0x0E, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, //char 0x075 == 'u'
+	0x66, 0x66, 0x66, 0x66, 0x3E, 0x3E, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, //char 0x076 == 'v'
+	0x66, 0x66, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x6B, 0x6B, //char 0x077 == 'w'
+	0x7F, 0x7F, 0x3E, 0x3E, 0x36, 0x36, 0x00, 0x00,
+//Font position 0x078
+	0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x3C, 0x3C, //char 0x078 == 'x'
+	0x18, 0x18, 0x3C, 0x3C, 0x66, 0x66, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, //char 0x079 == 'y'
+	0x66, 0x66, 0x3E, 0x3E, 0x0C, 0x0C, 0x78, 0x78,
+	0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x0C, 0x0C, //char 0x07A == 'z'
+	0x18, 0x18, 0x30, 0x30, 0x7E, 0x7E, 0x00, 0x00,
+	0x00, 0x00, 0x06, 0x0E, 0x18, 0x18, 0x18, 0x30, //char 0x07B == '{'
+	0x30, 0x18, 0x18, 0x18, 0x0E, 0x06, 0x00, 0x00,
+	0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, //char 0x07C == '|'
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+	0x00, 0x00, 0x60, 0x70, 0x18, 0x18, 0x18, 0x0C, //char 0x07D == '}'
+	0x0C, 0x18, 0x18, 0x18, 0x70, 0x60, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x70, 0x52, //char 0x07E == '~'
+	0x4A, 0x0E, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, //char 0x07F == ''
+	0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF,
+//Font position 0x080
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x080 == ''
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x081 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x082 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x083 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x084 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x085 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x086 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x087 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+//Font position 0x088
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x088 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x089 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x08A == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x08B == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x08C == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x08D == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x08E == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x08F == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+//Font position 0x090
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x090 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x091 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x092 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x093 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x094 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x095 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x096 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x097 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+//Font position 0x098
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x098 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x099 == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x09A == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x09B == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x09C == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x09D == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x09E == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x09F == '_' (free for use)
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+//Font position 0x0A0
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x0A0 == ' '
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, //char 0x0A1 == '¡'
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+	0x00, 0x00, 0x03, 0x06, 0x7F, 0x7F, 0xCC, 0xD8, //char 0x0A2 == '¢'
+	0xD8, 0xF0, 0x7F, 0x7F, 0x60, 0xC0, 0x00, 0x00,
+	0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x60, 0xFC, //char 0x0A3 == '£'
+	0xFC, 0x60, 0x60, 0x60, 0xFE, 0xFE, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xFF, 0x66, //char 0x0A4 == '¤'
+	0x66, 0xFF, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0xC3, 0xC3, 0x66, 0x66, 0x3C, 0xFF, //char 0x0A5 == '¥'
+	0xFF, 0x18, 0xFF, 0xFF, 0x18, 0x18, 0x00, 0x00,
+	0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, //char 0x0A6 == '¦'
+	0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+	0x00, 0x00, 0x3C, 0x7E, 0x66, 0x60, 0x3C, 0x66, //char 0x0A7 == '§'
+	0x66, 0x3C, 0x06, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+//Font position 0x0A8
+	0x00, 0x00, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, //char 0x0A8 == '¨'
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x7E, 0xFF, 0xC3, 0xDB, 0xDB, 0xD3, //char 0x0A9 == '©'
+	0xD3, 0xDB, 0xDB, 0xC3, 0xFF, 0x7E, 0x00, 0x00,
+	0x00, 0x00, 0x3E, 0x3E, 0x06, 0x3E, 0x36, 0x3E, //char 0x0AA == 'ª'
+	0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x1B, 0x36, 0x6C, 0x6C, 0xD8, //char 0x0AB == '«'
+	0xD8, 0x6C, 0x6C, 0x36, 0x1B, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x06, //char 0x0AC == '¬'
+	0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, //char 0x0AD == '­'
+	0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x7E, 0xFF, 0xC3, 0xDD, 0xD5, 0xDD, //char 0x0AE == '®'
+	0xDD, 0xD5, 0xD5, 0xC3, 0xFF, 0x7E, 0x00, 0x00,
+	0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x0AF == '¯'
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+//Font position 0x0B0
+	0x00, 0x00, 0x08, 0x1C, 0x36, 0x36, 0x1C, 0x08, //char 0x0B0 == '°'
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x18, //char 0x0B1 == '±'
+	0x18, 0x18, 0x00, 0x00, 0x7E, 0x7E, 0x00, 0x00,
+	0x00, 0x00, 0x3E, 0x3E, 0x0E, 0x0C, 0x38, 0x3E, //char 0x0B2 == '²'
+	0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x3E, 0x3E, 0x0E, 0x1C, 0x0C, 0x3E, //char 0x0B3 == '³'
+	0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x0E, 0x1C, 0x38, 0x00, 0x00, 0x00, //char 0x0B4 == '´'
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, //char 0x0B5 == 'µ'
+	0x7E, 0x7E, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00,
+	0x00, 0x00, 0x3F, 0x3F, 0x7F, 0x7F, 0x3B, 0x3B, //char 0x0B6 == '¶'
+	0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, //char 0x0B7 == '·'
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+//Font position 0x0B8
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //char 0x0B8 == '¸'
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x0C, 0x0C, 0x1C, 0x3C, 0x3C, 0x0C, //char 0x0B9 == '¹'
+	0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x7E, //char 0x0BA == 'º'
+	0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0xD8, 0x6C, 0x36, 0x36, 0x1B, //char 0x0BB == '»'
+	0x1B, 0x36, 0x36, 0x6C, 0xD8, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x60, 0xE0, 0xE3, 0x66, 0x6C, 0x18, //char 0x0BC == '¼'
+	0x18, 0x33, 0x67, 0xCF, 0x1F, 0x03, 0x00, 0x00,
+	0x00, 0x00, 0x60, 0xE0, 0xE3, 0x66, 0x6C, 0x18, //char 0x0BD == '½'
+	0x18, 0x37, 0x6F, 0xC7, 0x18, 0x1F, 0x00, 0x00,
+	0x00, 0x00, 0xE0, 0x60, 0xE3, 0x66, 0xEC, 0x18, //char 0x0BE == '¾'
+	0x18, 0x33, 0x67, 0xCF, 0x1F, 0x03, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, //char 0x0BF == '¿'
+	0x18, 0x30, 0x30, 0x36, 0x3E, 0x3E, 0x00, 0x00,
+//Font position 0x0C0
+	0x30, 0x18, 0x0C, 0x18, 0x3C, 0x66, 0x66, 0x66, //char 0x0C0 == 'À'
+	0x7E, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00,
+	0x0C, 0x18, 0x30, 0x18, 0x3C, 0x66, 0x66, 0x66, //char 0x0C1 == 'Á'
+	0x7E, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00,
+	0x18, 0x3C, 0x66, 0x18, 0x3C, 0x66, 0x66, 0x66, //char 0x0C2 == 'Â'
+	0x7E, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00,
+	0x36, 0x7E, 0x6C, 0x00, 0x18, 0x3C, 0x66, 0x66, //char 0x0C3 == 'Ã'
+	0x66, 0x7E, 0x7E, 0x66, 0x66, 0x66, 0x00, 0x00,
+	0x66, 0x66, 0x00, 0x18, 0x3C, 0x66, 0x66, 0x66, //char 0x0C4 == 'Ä'
+	0x7E, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00,
+	0x3C, 0x3C, 0x00, 0x18, 0x3C, 0x66, 0x66, 0x66, //char 0x0C5 == 'Å'
+	0x7E, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x37, 0x7F, 0xCC, 0xCC, 0xCC, //char 0x0C6 == 'Æ'
+	0xFF, 0xFF, 0xCC, 0xCC, 0xCF, 0xCF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x3C, 0x3C, 0x66, 0x66, 0x60, //char 0x0C7 == 'Ç'
+	0x60, 0x66, 0x66, 0x3C, 0x3C, 0x08, 0x38, 0x38,
+//Font position 0x0C8
+	0x30, 0x18, 0x0C, 0x00, 0x7E, 0x7E, 0x60, 0x60, //char 0x0C8 == 'È'
+	0x7C, 0x7C, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00,
+	0x0C, 0x18, 0x30, 0x00, 0x7E, 0x7E, 0x60, 0x60, //char 0x0C9 == 'É'
+	0x7C, 0x7C, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00,
+	0x18, 0x3C, 0x66, 0x00, 0x7E, 0x7E, 0x60, 0x60, //char 0x0CA == 'Ê'
+	0x7C, 0x7C, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00,
+	0x66, 0x66, 0x00, 0x00, 0x7E, 0x7E, 0x60, 0x60, //char 0x0CB == 'Ë'
+	0x7C, 0x7C, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00,
+	0x30, 0x18, 0x0C, 0x00, 0x18, 0x18, 0x18, 0x18, //char 0x0CC == 'Ì'
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+	0x0C, 0x18, 0x30, 0x00, 0x18, 0x18, 0x18, 0x18, //char 0x0CD == 'Í'
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+	0x18, 0x3C, 0x66, 0x00, 0x00, 0x18, 0x18, 0x18, //char 0x0CE == 'Î'
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+	0x66, 0x66, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, //char 0x0CF == 'Ï'
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+//Font position 0x0D0
+	0x00, 0x00, 0x78, 0x7C, 0x66, 0x66, 0x66, 0xF6, //char 0x0D0 == 'Ð'
+	0xF6, 0x66, 0x66, 0x66, 0x7C, 0x78, 0x00, 0x00,
+	0x36, 0x7E, 0x6C, 0x00, 0x66, 0x66, 0x76, 0x76, //char 0x0D1 == 'Ñ'
+	0x7E, 0x7E, 0x6E, 0x6E, 0x66, 0x66, 0x00, 0x00,
+	0x30, 0x18, 0x0C, 0x00, 0x3C, 0x7E, 0x66, 0x66, //char 0x0D2 == 'Ò'
+	0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+	0x0C, 0x18, 0x30, 0x00, 0x3C, 0x7E, 0x66, 0x66, //char 0x0D3 == 'Ó'
+	0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+	0x18, 0x3C, 0x66, 0x00, 0x3C, 0x7E, 0x66, 0x66, //char 0x0D4 == 'Ô'
+	0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+	0x36, 0x7E, 0x6C, 0x00, 0x3C, 0x7E, 0x66, 0x66, //char 0x0D5 == 'Õ'
+	0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+	0x66, 0x66, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, //char 0x0D6 == 'Ö'
+	0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x3C, 0x3C, //char 0x0D7 == '×'
+	0x18, 0x18, 0x3C, 0x66, 0x66, 0x00, 0x00, 0x00,
+//Font position 0x0D8
+	0x00, 0x03, 0x06, 0x3E, 0x7E, 0x6E, 0x6E, 0x7E, //char 0x0D8 == 'Ø'
+	0x7E, 0x7E, 0x76, 0x76, 0x7E, 0xFC, 0xC0, 0x00,
+	0x30, 0x18, 0x0C, 0x00, 0x66, 0x66, 0x66, 0x66, //char 0x0D9 == 'Ù'
+	0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+	0x0C, 0x18, 0x30, 0x00, 0x66, 0x66, 0x66, 0x66, //char 0x0DA == 'Ú'
+	0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+	0x18, 0x3C, 0x66, 0x00, 0x66, 0x66, 0x66, 0x66, //char 0x0DB == 'Û'
+	0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+	0x66, 0x66, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, //char 0x0DC == 'Ü'
+	0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+	0x0E, 0x38, 0x00, 0x00, 0x66, 0x66, 0x66, 0x7E, //char 0x0DD == 'Ý'
+	0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x60, 0x60, 0x7C, 0x7E, 0x63, //char 0x0DE == 'Þ'
+	0x63, 0x63, 0x7E, 0x7C, 0x60, 0x60, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x1C, 0x3E, 0x66, 0x66, 0x6E, //char 0x0DF == 'ß'
+	0x6C, 0x6E, 0x63, 0x63, 0x6E, 0x6C, 0x00, 0x00,
+//Font position 0x0E0
+	0x30, 0x18, 0x0C, 0x00, 0x3C, 0x3E, 0x06, 0x06, //char 0x0E0 == 'à'
+	0x3E, 0x7E, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00,
+	0x0C, 0x18, 0x30, 0x00, 0x3C, 0x3E, 0x06, 0x06, //char 0x0E1 == 'á'
+	0x3E, 0x7E, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00,
+	0x18, 0x3C, 0x66, 0x00, 0x3C, 0x3E, 0x06, 0x06, //char 0x0E2 == 'â'
+	0x3E, 0x7E, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00,
+	0x36, 0x7E, 0x6C, 0x00, 0x3C, 0x3E, 0x06, 0x06, //char 0x0E3 == 'ã'
+	0x3E, 0x7E, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00,
+	0x66, 0x66, 0x00, 0x00, 0x3C, 0x3E, 0x06, 0x06, //char 0x0E4 == 'ä'
+	0x3E, 0x7E, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00,
+	0x3C, 0x3C, 0x00, 0x00, 0x3C, 0x3E, 0x06, 0x06, //char 0x0E5 == 'å'
+	0x3E, 0x7E, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x76, 0xFF, 0x1B, 0x1B, //char 0x0E6 == 'æ'
+	0x7F, 0xFF, 0xD8, 0xD8, 0xFF, 0x6E, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x60, //char 0x0E7 == 'ç'
+	0x60, 0x60, 0x66, 0x7E, 0x3C, 0x18, 0x78, 0x78,
+//Font position 0x0E8
+	0x30, 0x18, 0x0C, 0x00, 0x3C, 0x7E, 0x66, 0x66, //char 0x0E8 == 'è'
+	0x7E, 0x7E, 0x60, 0x60, 0x7E, 0x3C, 0x00, 0x00,
+	0x0C, 0x18, 0x30, 0x00, 0x3C, 0x7E, 0x66, 0x66, //char 0x0E9 == 'é'
+	0x7E, 0x7E, 0x60, 0x60, 0x7E, 0x3C, 0x00, 0x00,
+	0x18, 0x3C, 0x66, 0x00, 0x3C, 0x7E, 0x66, 0x66, //char 0x0EA == 'ê'
+	0x7E, 0x7E, 0x60, 0x60, 0x7E, 0x3C, 0x00, 0x00,
+	0x66, 0x66, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, //char 0x0EB == 'ë'
+	0x7E, 0x7E, 0x60, 0x60, 0x7E, 0x3C, 0x00, 0x00,
+	0x30, 0x18, 0x0C, 0x00, 0x00, 0x18, 0x18, 0x18, //char 0x0EC == 'ì'
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+	0x0C, 0x18, 0x30, 0x00, 0x00, 0x18, 0x18, 0x18, //char 0x0ED == 'í'
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+	0x18, 0x3C, 0x66, 0x00, 0x00, 0x18, 0x18, 0x18, //char 0x0EE == 'î'
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+	0x66, 0x66, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, //char 0x0EF == 'ï'
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+//Font position 0x0F0
+	0x64, 0x38, 0x58, 0x0C, 0x3C, 0x7E, 0x66, 0x66, //char 0x0F0 == 'ð'
+	0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+	0x36, 0x7E, 0x6C, 0x00, 0x60, 0x7E, 0x7E, 0x66, //char 0x0F1 == 'ñ'
+	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00,
+	0x30, 0x18, 0x0C, 0x00, 0x00, 0x3C, 0x7E, 0x66, //char 0x0F2 == 'ò'
+	0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+	0x0C, 0x18, 0x30, 0x00, 0x00, 0x3C, 0x7E, 0x66, //char 0x0F3 == 'ó'
+	0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+	0x18, 0x3C, 0x66, 0x00, 0x00, 0x3C, 0x7E, 0x66, //char 0x0F4 == 'ô'
+	0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+	0x36, 0x7E, 0x6C, 0x00, 0x00, 0x3C, 0x7E, 0x66, //char 0x0F5 == 'õ'
+	0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+	0x66, 0x66, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66, //char 0x0F6 == 'ö'
+	0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x7E, //char 0x0F7 == '÷'
+	0x7E, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+//Font position 0x0F8
+	0x00, 0x00, 0x03, 0x06, 0x3E, 0x7E, 0x6E, 0x6E, //char 0x0F8 == 'ø'
+	0x7E, 0x7E, 0x76, 0x76, 0x7E, 0x7C, 0xC0, 0x00,
+	0x30, 0x18, 0x0C, 0x00, 0x00, 0x66, 0x66, 0x66, //char 0x0F9 == 'ù'
+	0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+	0x0C, 0x18, 0x30, 0x00, 0x00, 0x66, 0x66, 0x66, //char 0x0FA == 'ú'
+	0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+	0x18, 0x3C, 0x66, 0x00, 0x00, 0x66, 0x66, 0x66, //char 0x0FB == 'û'
+	0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+	0x66, 0x66, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, //char 0x0FC == 'ü'
+	0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+	0x0C, 0x18, 0x30, 0x00, 0x66, 0x66, 0x66, 0x66, //char 0x0FD == 'ý'
+	0x7E, 0x3C, 0x18, 0x18, 0x18, 0x70, 0x70, 0x00,
+	0x00, 0x00, 0x60, 0x60, 0x6C, 0x7E, 0x7E, 0x66, //char 0x0FE == 'þ'
+	0x66, 0x7E, 0x7E, 0x6C, 0x60, 0x60, 0x60, 0x00,
+	0x00, 0x66, 0x66, 0x00, 0x66, 0x66, 0x66, 0x66, //char 0x0FF == 'ÿ'
+	0x7E, 0x3C, 0x18, 0x18, 0x18, 0x70, 0x70, 0x00,
+//Font position 0x100
+	0x00, 0x00, 0x03, 0x03, 0x0C, 0x0C, 0x18, 0x18, //char 0x100 == special for uLE
+	0x18, 0x18, 0x0C, 0x0C, 0x03, 0x03, 0x00, 0x00, //Left half of Circle == SJIS 0x819B)
+	0x00, 0x00, 0xC0, 0xC0, 0x30, 0x30, 0x18, 0x18, //char 0x101 == special for uLE
+	0x18, 0x18, 0x30, 0x30, 0xC0, 0xC0, 0x00, 0x00, //Right half of Circle
+	0x00, 0x00, 0x18, 0x18, 0x0E, 0x0E, 0x03, 0x03, //char 0x102 == special for uLE
+	0x03, 0x03, 0x0E, 0x0E, 0x18, 0x18, 0x00, 0x00, //Left half of Cross == SJIS 0x817E)
+	0x00, 0x00, 0x18, 0x18, 0x70, 0x70, 0xC0, 0xC0, //char 0x103 == special for uLE
+	0xC0, 0xC0, 0x70, 0x70, 0x18, 0x18, 0x00, 0x00, //Right half of Cross
+	0x00, 0x00, 0x1F, 0x1F, 0x18, 0x18, 0x18, 0x18, //char 0x104 == special for uLE
+	0x18, 0x18, 0x18, 0x18, 0x1F, 0x1F, 0x00, 0x00, //Left half of Square == SJIS 0x81A0)
+	0x00, 0x00, 0xF8, 0xF8, 0x18, 0x18, 0x18, 0x18, //char 0x105 == special for uLE
+	0x18, 0x18, 0x18, 0x18, 0xF8, 0xF8, 0x00, 0x00, //Right half of Square
+	0x00, 0x00, 0x01, 0x01, 0x03, 0x03, 0x06, 0x06, //char 0x106 == special for uLE
+	0x0C, 0x0C, 0x18, 0x18, 0x1F, 0x1F, 0x00, 0x00, //Left half of Triangle == SJIS 0x81A2)
+	0x00, 0x00, 0x80, 0x80, 0xC0, 0xC0, 0x60, 0x60, //char 0x107 == special for uLE
+	0x30, 0x30, 0x18, 0x18, 0xF8, 0xF8, 0x00, 0x00, //Right half of Triangle
+//Font position 0x108
+	0x00, 0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, //char 0x108 == special for uLE
+	0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x00, //Left half of filledSq == SJIS 0x81A1)
+	0x00, 0x00, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, //char 0x109 == special for uLE
+	0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0x00, 0x00, //Right half of filledSq
+//Font position 0x10A
+	0x08, 0x08, 0x18, 0x18, 0x38, 0x38, 0x78, 0x78, //char 0x10A == Triangle pointing left
+	0x38, 0x38, 0x18, 0x18, 0x08, 0x08, 0x00, 0x00, //--this used to be 0x07E
+	0x10, 0x10, 0x18, 0x18, 0x1C, 0x1C, 0x1E, 0x1E, //char 0x10B == Triangle pointing right
+	0x1C, 0x1C, 0x18, 0x18, 0x10, 0x10, 0x00, 0x00, //--this used to be 0x07F
+	0x00, 0x00, 0x18, 0x18, 0x3C, 0x3C, 0x7E, 0x7E, //char 0x10C == Arrow pointing up
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, //--this used to be 0x09C
+	0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, //char 0x10D == Arrow pointing down
+	0x7E, 0x7E, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x00, //--this used to be 0x09D
+	0x00, 0x00, 0x18, 0x18, 0x30, 0x30, 0x7E, 0x7E, //char 0x10E == Arrow pointing left
+	0x30, 0x30, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, //--this used to be 0x09E
+	0x00, 0x00, 0x18, 0x18, 0x0C, 0x0C, 0x7E, 0x7E, //char 0x10F == Arrow pointing right
+	0x0C, 0x0C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, //--this used to be 0x09F
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, //char 0x110 == Vertical bar
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, //--this used to be 0x07C
+	0x00, 0x00, 0x7E, 0x7E, 0x78, 0x78, 0x7C, 0x7C, //char 0x111 == Arrow pointing up+left
+	0x6E, 0x6E, 0x66, 0x66, 0x06, 0x06, 0x00, 0x00, //--this used to be 0x07D
+	0x01, 0x01, 0x03, 0x03, 0x07, 0x07, 0x0F, 0x0F, //char 0x112 == diagonal split BR-filled
+	0x1F, 0x1F, 0x3F, 0x3F, 0x7F, 0x7F, 0xFF, 0xFF, //--this used to be 0x088
+	0x80, 0x80, 0xC0, 0xC0, 0xE0, 0xE0, 0xF0, 0xF0, //char 0x113 == diagonal split BL-filled
+	0xF8, 0xF8, 0xFC, 0xFC, 0xFE, 0xFE, 0xFF, 0xFF, //--this used to be 0x08A
+//Font position 0x114 == Fat arrow Right
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x30,
+	0x30, 0x30, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x80, 0xC0, 0xE0, 0xB0, 0x98, 0x0C,
+	0x06, 0x0C, 0x98, 0xB0, 0xE0, 0xC0, 0x80, 0x00,
+//Font position 0x116 == Fat arrow Down
+	0x00, 0x00, 0x07, 0x07, 0x06, 0x06, 0x06, 0x06,
+	0x3E, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00, 0x00,
+	0x00, 0x00, 0xF0, 0xF0, 0x30, 0x30, 0x30, 0x30,
+	0x3E, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00,
+//Font position 0x118 == Fat arrow Left
+	0x00, 0x00, 0x00, 0x01, 0x03, 0x06, 0x0C, 0x18,
+	0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00, 0x00,
+	0x00, 0x00, 0x80, 0x80, 0x80, 0xFE, 0xFE, 0x06,
+	0x06, 0x06, 0xFE, 0xFE, 0x80, 0x80, 0x80, 0x00,
+//Font position 0x11A == Fat arrow Up
+	0x00, 0x00, 0x00, 0x01, 0x03, 0x06, 0x0C, 0x18,
+	0x3E, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x00,
+	0x00, 0x00, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C,
+	0x3E, 0x30, 0x30, 0x30, 0x30, 0xF0, 0xF0, 0x00,
+//Font position 0x11C == Folder icon unselected
+	0x00, 0x3C, 0x7E, 0x7F, 0x7F, 0x3F, 0x3F, 0x3F,
+	0x3F, 0x3F, 0x3F, 0x1F, 0x0F, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0xF0, 0xF8, 0xFC, 0xFC, 0xFC,
+	0xFC, 0xFC, 0xFC, 0xF8, 0xF0, 0x00, 0x00, 0x00,
+//Font position 0x11E == Folder icon selected
+	0x00, 0x3C, 0x7E, 0x7F, 0x7F, 0x3E, 0x3C, 0x38,
+	0x38, 0x3C, 0x3E, 0x1F, 0x0F, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0xF0, 0xF8, 0x7C, 0x3C, 0x1C,
+	0x1C, 0x3C, 0x7C, 0xF8, 0xF0, 0x00, 0x00, 0x00,
+//Font position 0x120 == File icon unselected
+	0x00, 0x00, 0x03, 0x07, 0x0F, 0x1F, 0x1F, 0x1F,
+	0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x00,
+	0x00, 0x00, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
+	0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0x00, 0x00,
+//Font position 0x122 == File icon selected
+	0x00, 0x00, 0x03, 0x07, 0x0F, 0x1E, 0x1C, 0x18,
+	0x18, 0x1C, 0x1E, 0x1F, 0x1F, 0x1F, 0x00, 0x00,
+	0x00, 0x00, 0xF8, 0xF8, 0xF8, 0x78, 0x38, 0x18,
+	0x18, 0x38, 0x78, 0xF8, 0xF8, 0xF8, 0x00, 0x00,
+//---------------------------------------------------------------------------
+//dlanor: The old methods of accessing these special characters all relied
+//on using some character that is invisible in Windows, which is a bad idea.
+//so my new routines filter some escape sequences to achieve this, using the
+//visible character 0xFF ('ÿ') as escape flag, and the characters "01234"
+//to select which of the five special characters to expand. Thus we get:
+//"ÿ0"=>Circle  "ÿ1"=>Cross  "ÿ2"=>Square  "ÿ3"=>Triangle  "ÿ4"=>FilledBox
+//An extra benefit of this is that the method can be used regardless of
+//the position in the character set used for these special characters
+}; //ends font_uLE
+//---------------------------------------------------------------------------
+//End of file:  font_uLE.c
+//---------------------------------------------------------------------------
Index: ps2launchargs/source/uLaunchELF/hdd.c
===================================================================
--- ps2launchargs/source/uLaunchELF/hdd.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/hdd.c	(revision 1101)
@@ -0,0 +1,1101 @@
+//--------------------------------------------------------------
+//File name:    hdd.c
+//--------------------------------------------------------------
+#include "launchelf.h"
+
+#define MAX_PARTGB 128                  //Partition MAX in GB
+#define MAX_PARTMB (MAX_PARTGB*1024)   //Partition MAX in MB
+
+typedef struct{
+	char Name[MAX_NAME];
+	s64  RawSize;
+	s64  TotalSize;
+	s64  FreeSize;
+	s64  UsedSize;
+	int  FsGroup;
+	GameInfo Game;  //Intended for HDL game info, implemented through IRX module
+	int  Count;
+	int  Treatment;
+} PARTYINFO;
+
+enum {//For Treatment codes
+	TREAT_PFS = 0,   //PFS partition for normal file access
+	TREAT_HDL_RAW,	 //HDL game partition before reading GameInfo data
+	TREAT_HDL_GAME,  //HDL game partition after reading GameInfo data
+	TREAT_SYSTEM,		 //System partition that must never be modified (__mbr)
+	TREAT_NOACCESS   //Inaccessible partition (but can be deleted)
+};
+
+enum {//For menu commands
+	CREATE = 0,
+	REMOVE,
+	RENAME,
+	EXPAND,
+	FORMAT,
+	NUM_MENU
+};
+
+#define SECTORS_PER_MB 2048  //Divide by this to convert from sector count to MB
+#define MB 1048576
+
+PARTYINFO PartyInfo[MAX_PARTITIONS];
+int  numParty;
+int  hddSize, hddFree, hddFreeSpace, hddUsed;
+int  hddConnected, hddFormated;
+
+char DbgMsg[MAX_TEXT_LINE*30];
+
+//--------------------------------------------------------------
+///*
+void DebugDisp(char *Message)
+{
+	int  done;
+
+	for(done=0; done==0;){
+		nonDialog(Message);
+		drawLastMsg();
+		if(readpad() && new_pad){
+			done=1;
+		}
+	}
+}
+//*/
+//------------------------------
+//endfunc DebugDisp
+//--------------------------------------------------------------
+/*
+void DebugDispStat(iox_dirent_t *p)
+{
+	char buf[MAX_TEXT_LINE*24]="";
+	int  stp, pos, i;
+	unsigned int *ip = &p->stat.private_0;
+	int *cp = (int *) p->stat.ctime;
+	int *ap = (int *) p->stat.atime;
+	int *mp = (int *) p->stat.mtime;
+
+	pos = 0;
+	sprintf(buf+pos,"dirent.name == \"%s\"\n%n", p->name, &stp); pos+=stp;
+	sprintf(buf+pos,"dirent.unknown == %d\n%n", p->unknown, &stp); pos+=stp;
+	sprintf(buf+pos,"  mode == 0x%08X, attr == 0x%08X\n%n",p->stat.mode,p->stat.attr,&stp); pos+=stp;
+	sprintf(buf+pos,"hisize == 0x%08X, size == 0x%08X\n%n",p->stat.hisize,p->stat.size,&stp); pos+=stp;
+	sprintf(buf+pos,"ctime == 0x%08X%08X                      \n%n", cp[1],cp[0], &stp); pos+=stp;
+	sprintf(buf+pos,"atime == 0x%08X%08X\n%n", ap[1],ap[0], &stp); pos+=stp;
+	sprintf(buf+pos,"mtime == 0x%08X%08X\n%n", mp[1],mp[0], &stp); pos+=stp;
+	for(i=0; i<6; i++){
+		sprintf(buf+pos,"private_%d == 0x%08X\n%n", i, ip[i], &stp); pos+=stp;
+	}
+	DebugDisp(buf);
+}
+//*/
+//------------------------------
+//endfunc DebugDispStat
+//--------------------------------------------------------------
+void GetHddInfo(void)
+{
+	iox_dirent_t infoDirEnt;
+	int  rv, hddFd=0, partitionFd, i, Treat;
+	s64  size=0;
+	char tmp[MAX_PATH];
+	char dbgtmp[MAX_PATH];
+	s64  zoneFree, zoneSize;
+	char pfs_str[6];
+
+	strcpy(pfs_str, "pfs0:");
+	hddSize=0, hddFree=0, hddFreeSpace=0, hddUsed=0;
+	hddConnected=0, hddFormated=0;
+	numParty=0;
+	
+	drawMsg(LNG(Reading_HDD_Information));
+
+	if(hddCheckPresent() < 0){
+		hddConnected=0;
+		goto end;
+	}else
+		hddConnected=1;
+
+	if(hddCheckFormatted() < 0){
+		hddFormated=0;
+		goto end;
+	}else
+		hddFormated=1;
+
+	size =((s64) fileXioDevctl("hdd0:", HDDCTL_TOTAL_SECTORS, NULL, 0, NULL, 0))*512;
+	hddSize = (size / MB);
+
+	if((hddFd = fileXioDopen("hdd0:")) < 0) return;
+
+	while(fileXioDread(hddFd, &infoDirEnt) > 0){ //Starts main while loop
+		int	found_size =
+					((((s64) infoDirEnt.stat.hisize)<<32) + infoDirEnt.stat.size) / MB;
+
+		//DebugDispStat(&infoDirEnt);
+
+		if(infoDirEnt.stat.mode == FS_TYPE_EMPTY)
+			continue;
+		hddUsed += found_size;
+		for(i=0; i<numParty; i++) //Check with previous partitions
+			if(!strcmp(infoDirEnt.name,PartyInfo[i].Name))
+				break;
+		if(i<numParty) { //found another reference to an old name
+			PartyInfo[i].RawSize += found_size; //Add new segment to old size
+		} else { //Starts clause for finding brand new name for PartyInfo[numParty]
+			sprintf(dbgtmp, "%s \"%s\"", LNG(Found), infoDirEnt.name);
+			drawMsg(dbgtmp);
+
+			memset(&PartyInfo[numParty], 0, sizeof(PARTYINFO));
+			strcpy(PartyInfo[numParty].Name, infoDirEnt.name);
+			PartyInfo[numParty].RawSize = found_size; //Store found segment size
+			PartyInfo[numParty].Count = numParty;
+
+			if(infoDirEnt.stat.mode == 0x0001)  //New test of partition type by 'mode'
+				Treat = TREAT_SYSTEM;
+			else if(!strncmp(infoDirEnt.name,"PP.HDL.",7))
+				Treat = TREAT_HDL_RAW;
+			else {
+				sprintf(tmp, "hdd0:%s", infoDirEnt.name);
+				partitionFd = fileXioOpen(tmp, O_RDONLY, 0);
+				if(partitionFd < 0){
+					Treat = TREAT_NOACCESS; //needed for Sony-style protected partitions
+				} else {
+					fileXioClose(partitionFd);
+					Treat = TREAT_PFS;
+				}
+			}
+			PartyInfo[numParty].Treatment = Treat; 
+
+			if((PartyInfo[numParty].Name[0] == '_') && (PartyInfo[numParty].Name[1] == '_'))
+				PartyInfo[numParty].FsGroup = FS_GROUP_SYSTEM;
+			else if(PartyInfo[numParty].Name[0] == FS_COMMON_PREFIX)
+				PartyInfo[numParty].FsGroup = FS_GROUP_COMMON;
+			else
+				PartyInfo[numParty].FsGroup = FS_GROUP_APPLICATION;
+
+			if(Treat == TREAT_PFS){ //Starts clause for TREAT_PFS
+				sprintf(tmp, "hdd0:%s", PartyInfo[numParty].Name);
+				partitionFd = fileXioOpen(tmp, O_RDONLY, 0);
+
+				for(i = 0, size = 0; i < infoDirEnt.stat.private_0 + 1; i++)
+				{
+					rv = fileXioIoctl2(partitionFd, HDDIO_GETSIZE, &i, 4, NULL, 0);
+					size += rv * 512 / 1024 / 1024;
+				}
+				PartyInfo[numParty].TotalSize=size;
+	
+				fileXioClose(partitionFd);
+	
+				mountParty(tmp);
+				pfs_str[3] = '0'+latestMount;
+				zoneFree = fileXioDevctl(pfs_str, PFSCTL_GET_ZONE_FREE, NULL,0,NULL,0);
+				zoneSize = fileXioDevctl(pfs_str, PFSCTL_GET_ZONE_SIZE, NULL,0,NULL,0);
+				unmountParty(latestMount);
+
+				PartyInfo[numParty].FreeSize  = zoneFree*zoneSize / MB;
+				PartyInfo[numParty].UsedSize  = PartyInfo[numParty].TotalSize-PartyInfo[numParty].FreeSize;
+		
+			} //Ends clause for TREAT_PFS
+
+			numParty++;
+		} //Ends clause for finding brand new name for PartyInfo[numParty]
+	} //ends main while loop
+	fileXioDclose(hddFd);
+	hddFreeSpace = (hddSize - hddUsed) & 0x7FFFFF80; //free space rounded to useful area
+	hddFree = (hddFreeSpace*100)/hddSize;            //free space percentage
+
+end:
+	drawMsg(LNG(HDD_Information_Read));
+
+	WaitTime=Timer();
+	while(Timer()<WaitTime+1500); // print operation result during 1.5 sec.
+}
+//------------------------------
+//endfunc GetHddInfo
+//--------------------------------------------------------------
+int sizeSelector(int size)
+{
+	int   x, y;
+	int   saveSize=size;
+	float scrollBar;
+	char  c[MAX_PATH];
+	int   event, post_event=0;
+
+	int mSprite_X1 = SCREEN_WIDTH/2-12*FONT_WIDTH;       //Left edge of sprite
+	int mSprite_Y1 = SCREEN_HEIGHT/2-3*FONT_HEIGHT; //Top edge of sprite
+	int mSprite_X2 = SCREEN_WIDTH/2+12*FONT_WIDTH;       //Right edge of sprite
+	int mSprite_Y2 = SCREEN_HEIGHT/2+3*FONT_HEIGHT; //Bottom edge of sprite
+
+	event = 1;  //event = initial entry
+	while(1){
+		//Pad response section
+		waitPadReady(0, 0);
+		if(readpad()){
+			if(new_pad & PAD_RIGHT){
+				event |= 2;  //event |= valid pad command
+				if((size += 128)>MAX_PARTMB)
+					size = MAX_PARTMB;
+			}else if(new_pad & PAD_LEFT){
+				event |= 2;  //event |= valid pad command
+				if((size -= 128)<saveSize)
+					size = saveSize;
+			}else if(new_pad & PAD_R1){
+				event |= 2;  //event |= valid pad command
+				if(size<1024)
+					size=1024;
+				else{
+					if((size += 1024)>MAX_PARTMB)
+						size = MAX_PARTMB;
+				}
+			}else if(new_pad & PAD_L1){
+				event |= 2;  //event |= valid pad command
+				if((size -= 1024)<saveSize)
+					size = saveSize;
+			}else if(new_pad & PAD_R2){
+				event |= 2;  //event |= valid pad command
+				if(size<10240)
+					size=10240;
+				else{
+					if((size += 10240)>MAX_PARTMB)
+						size = MAX_PARTMB;
+				}
+			}else if(new_pad & PAD_L2){
+				event |= 2;  //event |= valid pad command
+				if((size -= 10240)<saveSize)
+					size = saveSize;
+			}else if((new_pad & PAD_TRIANGLE)
+						|| (!swapKeys && new_pad & PAD_CROSS)
+			      || (swapKeys && new_pad & PAD_CIRCLE) ){
+				return -1;
+			}else if((swapKeys && new_pad & PAD_CROSS)
+			      || (!swapKeys && new_pad & PAD_CIRCLE) ){
+				event |= 2;  //event |= valid pad command
+				break;
+			}
+		}
+
+		if(event||post_event){ //NB: We need to update two frame buffers per event
+
+			//Display section
+			drawPopSprite(setting->color[0],
+				mSprite_X1, mSprite_Y1,
+				mSprite_X2, mSprite_Y2);
+			drawFrame(mSprite_X1, mSprite_Y1, mSprite_X2, mSprite_Y2, setting->color[1]);
+
+			sprintf(c, "%d %s", size, LNG(MB));
+			printXY(c, mSprite_X1+12*FONT_WIDTH-(strlen(c)*FONT_WIDTH)/2,
+				mSprite_Y1+FONT_HEIGHT, setting->color[3], TRUE, 0);
+			drawFrame(mSprite_X1+7*FONT_WIDTH, mSprite_Y1+FONT_HEIGHT/2,
+				mSprite_X2-7*FONT_WIDTH, mSprite_Y1+FONT_HEIGHT*2+FONT_HEIGHT/2, setting->color[1]);
+
+			//RA NB: Next line assumes a scrollbar 19 characters wide (see below)
+			sprintf(c, "128%s            %3d%s", LNG(MB), MAX_PARTGB, LNG(GB));
+			printXY(c, mSprite_X1+FONT_WIDTH, mSprite_Y1+FONT_HEIGHT*3, setting->color[3], TRUE, 0);
+
+			drawOpSprite(setting->color[1],
+				mSprite_X1+2*FONT_WIDTH+FONT_WIDTH/2, mSprite_Y1+FONT_HEIGHT*5-LINE_THICKNESS+1,
+				mSprite_X2-2*FONT_WIDTH-FONT_WIDTH/2, mSprite_Y1+FONT_HEIGHT*5);
+
+
+			//RA NB: Next line sets scroll position on a bar 19 chars wide (see above)
+			scrollBar = (size*(19*FONT_WIDTH)/(MAX_PARTMB-128));
+
+			drawOpSprite(setting->color[1],
+				mSprite_X1+2*FONT_WIDTH+FONT_WIDTH/2+(int)scrollBar-LINE_THICKNESS+1,
+				mSprite_Y1+FONT_HEIGHT*5-FONT_HEIGHT/2,
+				mSprite_X1+2*FONT_WIDTH+FONT_WIDTH/2+(int)scrollBar,
+				mSprite_Y1+FONT_HEIGHT*5+FONT_HEIGHT/2);
+
+			//Tooltip section
+			x = SCREEN_MARGIN;
+			y = Menu_tooltip_y;
+			drawSprite(setting->color[0],
+				0, y-1,
+				SCREEN_WIDTH, y+16);
+			if (swapKeys)
+				sprintf(c, "ÿ1:%s ÿ0:%s ÿ3:%s ÿ</ÿ::-/+128%s L1/R1:-/+1%s L2/R2:-/+10%s",
+					LNG(OK), LNG(Cancel), LNG(Back), LNG(MB), LNG(GB), LNG(GB));
+			else
+				sprintf(c, "ÿ0:%s ÿ1:%s ÿ3:%s ÿ</ÿ::-/+128%s L1/R1:-/+1%s L2/R2:-/+10%s",
+					LNG(OK), LNG(Cancel), LNG(Back), LNG(MB), LNG(GB), LNG(GB));
+			printXY(c, x, y, setting->color[2], TRUE, 0);
+		}//ends if(event||post_event)
+		drawScr();
+		post_event = event;
+		event = 0;
+	}//ends while
+	return size;
+}
+//------------------------------
+//endfunc sizeSelector
+//--------------------------------------------------------------
+int MenuParty(PARTYINFO Info)
+{
+	u64 color;
+	char enable[NUM_MENU], tmp[64];
+	int x, y, i, sel;
+	int event, post_event=0;
+	
+	int menu_len=strlen(LNG(Create))>strlen(LNG(Remove))?
+		strlen(LNG(Create)):strlen(LNG(Remove));
+	menu_len=strlen(LNG(Rename))>menu_len? strlen(LNG(Rename)):menu_len;
+	menu_len=strlen(LNG(Expand))>menu_len? strlen(LNG(Expand)):menu_len;
+	menu_len=strlen(LNG(Format))>menu_len? strlen(LNG(Format)):menu_len;
+
+	int menu_ch_w = menu_len+1;    //Total characters in longest menu string
+	int menu_ch_h = NUM_MENU;      //Total number of menu lines
+	int mSprite_Y1 = 64;           //Top edge of sprite
+	int mSprite_X2 = SCREEN_WIDTH-35;   //Right edge of sprite
+	int mSprite_X1 = mSprite_X2-(menu_ch_w+3)*FONT_WIDTH;   //Left edge of sprite
+	int mSprite_Y2 = mSprite_Y1+(menu_ch_h+1)*FONT_HEIGHT;  //Bottom edge of sprite
+
+	unmountAll();    //unmount all uLE-used mountpoints
+	unmountParty(0); //unconditionally unmount primary mountpoint
+	unmountParty(1); //unconditionally unmount secondary mountpoint
+
+	memset(enable, TRUE, NUM_MENU);
+
+	if(Info.FsGroup==FS_GROUP_SYSTEM){
+		enable[REMOVE] = FALSE;
+		enable[RENAME] = FALSE;
+		enable[EXPAND] = FALSE;
+	}
+	if(Info.FsGroup==FS_GROUP_APPLICATION){
+		enable[RENAME] = FALSE;
+	}
+	if(Info.Treatment == TREAT_HDL_RAW){
+		enable[RENAME] = FALSE;
+		enable[EXPAND] = FALSE;
+	}
+	if(Info.Treatment == TREAT_HDL_GAME){
+		enable[RENAME] = TRUE;
+		enable[EXPAND] = FALSE;
+	}
+
+	for(sel=0; sel<NUM_MENU; sel++)
+		if(enable[sel]==TRUE) break;
+	
+	event = 1;  //event = initial entry
+	while(1){
+		//Pad response section
+		waitPadReady(0, 0);
+		if(readpad()){
+			if(new_pad & PAD_UP && sel<NUM_MENU){
+				event |= 2;  //event |= valid pad command
+				do{
+					sel--;
+					if(sel<0) sel=NUM_MENU-1;
+				}while(!enable[sel]);
+			}else if(new_pad & PAD_DOWN && sel<NUM_MENU){
+				event |= 2;  //event |= valid pad command
+				do{
+					sel++;
+					if(sel==NUM_MENU) sel=0;
+				}while(!enable[sel]);
+			}else if((new_pad & PAD_TRIANGLE)
+						|| (!swapKeys && new_pad & PAD_CROSS)
+			      || (swapKeys && new_pad & PAD_CIRCLE) ){
+				return -1;
+			}else if((swapKeys && new_pad & PAD_CROSS)
+			      || (!swapKeys && new_pad & PAD_CIRCLE) ){
+				event |= 2;  //event |= valid pad command
+				break;
+			}
+		}
+
+		if(event||post_event){ //NB: We need to update two frame buffers per event
+
+			//Display section
+			drawPopSprite(setting->color[0],
+				mSprite_X1, mSprite_Y1,
+				mSprite_X2, mSprite_Y2);
+			drawFrame(mSprite_X1, mSprite_Y1, mSprite_X2, mSprite_Y2, setting->color[1]);
+
+			for(i=0,y=mSprite_Y1+FONT_HEIGHT/2; i<NUM_MENU; i++){
+				if(i==CREATE)			strcpy(tmp, LNG(Create));
+				else if(i==REMOVE)		strcpy(tmp, LNG(Remove));
+				else if(i==RENAME)	strcpy(tmp, LNG(Rename));
+				else if(i==EXPAND)	strcpy(tmp, LNG(Expand));
+				else if(i==FORMAT)	strcpy(tmp, LNG(Format));
+
+				if(enable[i])	color = setting->color[3];
+				else			color = setting->color[1];
+
+				printXY(tmp, mSprite_X1+2*FONT_WIDTH, y, color, TRUE, 0);
+				y+=FONT_HEIGHT;
+			}
+			if(sel<NUM_MENU)
+				drawChar(LEFT_CUR, mSprite_X1+FONT_WIDTH, mSprite_Y1+(FONT_HEIGHT/2+sel*FONT_HEIGHT), setting->color[3]);
+
+			//Tooltip section
+			x = SCREEN_MARGIN;
+			y = Menu_tooltip_y;
+			drawSprite(setting->color[0],
+				0, y-1,
+				SCREEN_WIDTH, y+16);
+			if (swapKeys)
+				sprintf(tmp, "ÿ1:%s ÿ0:%s ÿ3:%s", LNG(OK), LNG(Cancel), LNG(Back));
+			else
+				sprintf(tmp, "ÿ0:%s ÿ1:%s ÿ3:%s", LNG(OK), LNG(Cancel), LNG(Back));
+			printXY(tmp, x, y, setting->color[2], TRUE, 0);
+		}//ends if(event||post_event)
+		drawScr();
+		post_event = event;
+		event = 0;
+	}//ends while
+	return sel;
+}
+//------------------------------
+//endfunc MenuParty
+//--------------------------------------------------------------
+int CreateParty(char *party, int size)
+{
+	int  i, num=1, ret=0;
+	int  remSize = size-2048;
+	char tmpName[MAX_ENTRY];	
+	t_hddFilesystem hddFs[MAX_PARTITIONS];
+
+	drawMsg(LNG(Creating_New_Partition));
+
+	tmpName[0]=0;
+	sprintf(tmpName, "+%s", party);
+	for(i=0; i<MAX_PARTITIONS; i++){
+		if(!strcmp(PartyInfo[i].Name, tmpName)){
+			sprintf(tmpName, "+%s%d", party, num);
+			num++;
+		}
+	}
+	strcpy(party, tmpName+1);
+	if(remSize <= 0)
+		ret = hddMakeFilesystem(size, party, FS_GROUP_COMMON);
+	else{
+		ret = hddMakeFilesystem(2048, party, FS_GROUP_COMMON);
+		hddGetFilesystemList(hddFs, MAX_PARTITIONS);
+		for(i=0; i<MAX_PARTITIONS; i++){
+			if(!strcmp(hddFs[i].name, party))
+				ret = hddExpandFilesystem(&hddFs[i], remSize);
+		}
+	}
+
+	if(ret>0){
+		GetHddInfo();
+		drawMsg(LNG(New_Partition_Created));
+	}else{
+		drawMsg(LNG(Failed_Creating_New_Partition));
+	}
+
+	WaitTime=Timer();
+	while(Timer()<WaitTime+1500); // print operation result during 1.5 sec.
+
+	return ret;
+}
+//------------------------------
+//endfunc CreateParty
+//--------------------------------------------------------------
+int RemoveParty(PARTYINFO Info)
+{
+	int  i, ret=0;
+	char tmpName[MAX_ENTRY];	
+	
+	//printf("Remove Partition: %d\n", Info.Count);
+
+	drawMsg(LNG(Removing_Current_Partition));
+
+	sprintf(tmpName, "hdd0:%s", Info.Name);
+	ret = fileXioRemove(tmpName);
+
+	if(ret==0){
+		hddUsed -= Info.TotalSize;
+		hddFreeSpace = (hddSize - hddUsed) & 0x7FFFFF80; //free space rounded to useful area
+		hddFree = (hddFreeSpace*100)/hddSize;            //free space percentage
+		numParty--;
+		if(Info.Count==numParty){
+			memset(&PartyInfo[numParty], 0, sizeof(PARTYINFO));
+		}else{
+			for(i=Info.Count; i<numParty; i++){
+				memset(&PartyInfo[i], 0, sizeof(PARTYINFO));
+				memcpy(&PartyInfo[i], &PartyInfo[i+1], sizeof(PARTYINFO));
+				PartyInfo[i].Count--;
+			}
+			memset(&PartyInfo[numParty], 0, sizeof(PARTYINFO));
+		}
+		drawMsg(LNG(Partition_Removed));
+	}else{
+		drawMsg(LNG(Failed_Removing_Current_Partition));
+	}
+
+	WaitTime=Timer();
+	while(Timer()<WaitTime+1500); // print operation result during 1.5 sec.
+
+	return ret;
+}
+//------------------------------
+//endfunc RemoveParty
+//--------------------------------------------------------------
+int RenameParty(PARTYINFO Info, char *newName)
+{
+	int  i, num=1, ret=0;
+	char in[MAX_ENTRY], out[MAX_ENTRY], tmpName[MAX_ENTRY];
+
+	//printf("Rename Partition: %d  group: %d\n", Info.Count, Info.FsGroup);
+	drawMsg(LNG(Renaming_Partition));
+
+	in[0]=0;
+	out[0]=0;
+	tmpName[0]=0;
+	if(Info.FsGroup==FS_GROUP_APPLICATION){
+		sprintf(tmpName, "%s", newName);
+		if(!strcmp(Info.Name, tmpName))
+			goto end;
+		for(i=0; i<MAX_PARTITIONS; i++){
+			if(!strcmp(PartyInfo[i].Name, tmpName)){
+				sprintf(tmpName, "%s%d", newName, num);
+				num++;
+			}
+		}
+		strcpy(newName, tmpName);
+		sprintf(in, "hdd0:%s", Info.Name);
+		sprintf(out, "hdd0:%s", newName);
+	}else{ // FS_GROUP_COMMON
+		sprintf(tmpName, "+%s", newName);
+		if(!strcmp(Info.Name, tmpName))
+			goto end;
+		for(i=0; i<MAX_PARTITIONS; i++){
+			if(!strcmp(PartyInfo[i].Name, tmpName)){
+				sprintf(tmpName, "+%s%d", newName, num);
+				num++;
+			}
+		}
+		strcpy(newName, tmpName+1);
+		sprintf(in, "hdd0:%s", Info.Name);
+		sprintf(out, "hdd0:+%s", newName);
+	}
+
+	ret = fileXioRename(in, out);
+
+	if(ret==0){
+		if(Info.FsGroup==FS_GROUP_APPLICATION)
+			strcpy(PartyInfo[Info.Count].Name, newName);
+		else // FS_GROUP_COMMON
+			sprintf(PartyInfo[Info.Count].Name, "+%s", newName);
+		drawMsg(LNG(Partition_Renamed));
+	}else{
+		drawMsg(LNG(Failed_Renaming_Partition));
+	}
+
+	WaitTime=Timer();
+	while(Timer()<WaitTime+1500); // print operation result during 1.5 sec.
+
+end:
+	return ret;
+}
+//------------------------------
+//endfunc RenameParty
+//--------------------------------------------------------------
+int RenameGame(PARTYINFO Info, char *newName)
+{
+	//printf("Rename Game: %d\n", Info.Count);
+
+	int  i, fd, num=1, ret=0;
+	char tmpName[MAX_ENTRY];
+
+	drawMsg(LNG(Renaming_Game));
+
+	if(!strcmp(Info.Game.Name, newName))
+		goto end1;
+
+	tmpName[0]=0;
+	strcpy(tmpName, newName);
+	for(i=0; i<MAX_PARTITIONS; i++){
+		if(!strcmp(PartyInfo[i].Game.Name, tmpName)){
+			if(strlen(tmpName)>=32)
+				goto end2; //For this case HDL renaming can't be done
+			sprintf(tmpName, "%s%d", newName, num);
+			num++;
+		}
+	}
+	strcpy(newName, tmpName);
+
+	ret = HdlRenameGame(Info.Game.Name, newName);
+
+	if(ret==0){
+		strcpy(PartyInfo[Info.Count].Game.Name, newName);
+		if(mountParty("hdd0:HDLoader Settings")>=0){
+			if((fd=genOpen("pfs0:/gamelist.log", O_RDONLY)) >= 0){
+				genClose(fd);
+				if(fileXioRemove("pfs0:/gamelist.log")!=0)
+					ret=0;
+			}
+			unmountParty(latestMount);
+		}
+	}else{
+		sprintf(DbgMsg,"HdlRenameGame(\"%s\",\n  \"%s\")\n=> %d",Info.Game.Name, newName,ret);
+		DebugDisp(DbgMsg);
+	}
+
+
+	if(ret!=0){
+		strcpy(PartyInfo[Info.Count].Game.Name, newName);
+		drawMsg(LNG(Game_Renamed));
+	}else{
+end2:
+		drawMsg(LNG(Failed_Renaming_Game));
+	}
+
+	WaitTime=Timer();
+	while(Timer()<WaitTime+1500); // print operation result during 1.5 sec.
+
+end1:
+	return ret;
+}
+//------------------------------
+//endfunc RenameGame
+//--------------------------------------------------------------
+int ExpandParty(PARTYINFO Info, int size)
+{
+	int i, ret=0;
+	char tmpName[MAX_ENTRY];
+	t_hddFilesystem hddFs[MAX_PARTITIONS];
+	
+	drawMsg(LNG(Expanding_Current_Partition));
+	//printf("Expand Partition: %d\n", Info.Count);
+
+	if(Info.FsGroup==FS_GROUP_APPLICATION){
+		strcpy(tmpName, Info.Name);
+	}else{
+		strcpy(tmpName, Info.Name+1);
+	}
+
+	hddGetFilesystemList(hddFs, MAX_PARTITIONS);
+	for(i=0; i<MAX_PARTITIONS; i++){
+		if(!strcmp(hddFs[i].name, tmpName))
+			ret = hddExpandFilesystem(&hddFs[i], size);
+	}
+
+	if(ret>0){
+		hddUsed += size;
+		hddFreeSpace = (hddSize - hddUsed) & 0x7FFFFF80; //free space rounded to useful area
+		hddFree = (hddFreeSpace*100)/hddSize;            //free space percentage
+
+		PartyInfo[Info.Count].TotalSize += size;
+		PartyInfo[Info.Count].FreeSize += size;
+		drawMsg(LNG(Partition_Expanded));
+	}else{
+		drawMsg(LNG(Failed_Expanding_Current_Partition));
+	}
+
+	WaitTime=Timer();
+	while(Timer()<WaitTime+1500); // print operation result during 1.5 sec.
+
+	return ret;
+}
+//------------------------------
+//endfunc ExpandParty
+//--------------------------------------------------------------
+int FormatHdd(void)
+{
+	int ret=0;
+	
+	drawMsg(LNG(Formating_HDD));
+
+	ret = hddFormat();
+
+	if(ret==0){
+		drawMsg(LNG(HDD_Formated));
+	}else{
+		drawMsg(LNG(HDD_Format_Failed));
+	}
+
+	WaitTime=Timer();
+	while(Timer()<WaitTime+1500); // print operation result during 1.5 sec.
+
+	GetHddInfo();
+
+	return ret;
+}
+//------------------------------
+//endfunc FormatHdd
+//--------------------------------------------------------------
+void hddManager(void)
+{
+	char   c[MAX_PATH];
+	int    Angle;
+	int    x, y, y0, y1, x2, y2;
+	float  x3, y3;
+	int    i, ret;
+	int    partySize;
+	int    pfsFree;
+	int    ray=50;
+	u64 Color;
+	char   tmp[MAX_PATH];
+	char	tooltip[MAX_TEXT_LINE];
+	int    top=0, rows;
+	int    event, post_event=0;
+	int    browser_sel=0,	browser_nfiles=0;
+	int    Treat;
+
+	rows = (Menu_end_y-Menu_start_y)/FONT_HEIGHT;
+
+	loadHddModules();
+	GetHddInfo();
+
+	event = 1;  //event = initial entry
+	while(1){
+
+		//Pad response section
+		waitPadReady(0, 0);
+		if(readpad()){
+			if(new_pad){
+				//printf("Selected Partition: %d\n", browser_sel);
+				event |= 2;  //event |= pad command
+			}
+			if(new_pad & PAD_UP)
+				browser_sel--;
+			else if(new_pad & PAD_DOWN)
+				browser_sel++;
+			else if(new_pad & PAD_LEFT)
+				browser_sel-=rows/2;
+			else if(new_pad & PAD_RIGHT)
+				browser_sel+=rows/2;
+			else if((new_pad & PAD_SELECT) || (new_pad & PAD_TRIANGLE)){
+				//Prepare for exit from HddManager
+				unmountAll();    //unmount all uLE-used mountpoints
+				unmountParty(0); //unconditionally unmount primary mountpoint
+				unmountParty(1); //unconditionally unmount secondary mountpoint
+				return;
+			}else if(new_pad & PAD_SQUARE){
+				if(PartyInfo[browser_sel].Treatment == TREAT_HDL_RAW){
+					loadHdlInfoModule();
+					ret=HdlGetGameInfo(PartyInfo[browser_sel].Name, &PartyInfo[browser_sel].Game);
+					if(ret==0)
+						PartyInfo[browser_sel].Treatment = TREAT_HDL_GAME;
+					else{
+						sprintf(DbgMsg, "HdlGetGameInfo(\"%s\",bf)\n=> %d", PartyInfo[browser_sel].Name, ret);
+						DebugDisp(DbgMsg);
+					}
+				}
+			}else if(new_pad & PAD_R1) { //Starts clause for R1 menu
+				ret = MenuParty(PartyInfo[browser_sel]);
+				tmp[0]=0;
+				if(ret==CREATE){
+					drawMsg(LNG(Enter_New_Partition_Name));
+					drawMsg(LNG(Enter_New_Partition_Name));
+					if(keyboard(tmp, 36)>0){
+						partySize=128;
+						drawMsg(LNG(Select_New_Partition_Size_In_MB));
+						drawMsg(LNG(Select_New_Partition_Size_In_MB));
+						if((ret = sizeSelector(partySize))>0){
+							if(ynDialog(LNG(Create_New_Partition))==1){
+								CreateParty(tmp, ret);
+								nparties = 0; //Tell FileBrowser to refresh party list
+							}
+						}
+					}
+				} else if(ret==REMOVE){
+					if(ynDialog(LNG(Remove_Current_Partition))==1) {
+						RemoveParty(PartyInfo[browser_sel]);
+						nparties = 0; //Tell FileBrowser to refresh party list
+					}	
+				} else if(ret==RENAME){
+					drawMsg(LNG(Enter_New_Partition_Name));
+					drawMsg(LNG(Enter_New_Partition_Name));
+					if(PartyInfo[browser_sel].Treatment == TREAT_HDL_GAME){//Rename HDL Game
+						strcpy(tmp, PartyInfo[browser_sel].Game.Name);
+						if(keyboard(tmp, 32)>0){
+							if(ynDialog(LNG(Rename_Current_Game))==1)
+								RenameGame(PartyInfo[browser_sel], tmp);
+						}
+					}else{//starts clause for normal partition RENAME
+						strcpy(tmp, PartyInfo[browser_sel].Name+1);
+						if(keyboard(tmp, 36)>0){
+							if(ynDialog(LNG(Rename_Current_Partition))==1){
+								RenameParty(PartyInfo[browser_sel], tmp);
+								nparties = 0; //Tell FileBrowser to refresh party list
+							}
+						}
+					}//ends clause for normal partition RENAME
+				} else if(ret==EXPAND){
+					drawMsg(LNG(Select_New_Partition_Size_In_MB));
+					drawMsg(LNG(Select_New_Partition_Size_In_MB));
+					partySize=PartyInfo[browser_sel].TotalSize;
+					if((ret=sizeSelector(partySize))>0){
+						if(ynDialog(LNG(Expand_Current_Partition))==1){
+							ret -= partySize;
+							ExpandParty(PartyInfo[browser_sel], ret);
+							nparties = 0; //Tell FileBrowser to refresh party list
+						}
+					}
+				} else if(ret==FORMAT){
+					if(ynDialog(LNG(Format_HDD))==1){
+						FormatHdd();
+						nparties = 0; //Tell FileBrowser to refresh party list
+					}
+				}
+			} //Ends clause for R1 menu
+		}//ends pad response section
+
+		if(event||post_event){ //NB: We need to update two frame buffers per event
+
+			//Display section
+			clrScr(setting->color[0]);
+
+			browser_nfiles=numParty;
+			//printf("Number Of Partition: %d\n", numParty);
+
+			if(top > browser_nfiles-rows)	top=browser_nfiles-rows;
+			if(top < 0)				top=0;
+			if(browser_sel >= browser_nfiles)		browser_sel=browser_nfiles-1;
+			if(browser_sel < 0)				browser_sel=0;
+			if(browser_sel >= top+rows)		top=browser_sel-rows+1;
+			if(browser_sel < top)			top=browser_sel;
+		
+			y = Menu_start_y;
+
+			x = ((((SCREEN_WIDTH/2-25)-Menu_start_x)/2)+Menu_start_x)-(strlen(LNG(HDD_STATUS))*FONT_WIDTH)/2;
+			printXY(LNG(HDD_STATUS), x, y, setting->color[3], TRUE, 0);
+
+			if(TV_mode == TV_mode_NTSC) 
+				y += FONT_HEIGHT+10;
+			else
+				y += FONT_HEIGHT+11;
+
+			drawOpSprite(setting->color[1],
+				SCREEN_MARGIN, y-6,
+				SCREEN_WIDTH/2-20, y-4);
+
+			if(hddConnected==0)
+				sprintf(c, "%s:  %s / %s:  %s",
+				LNG(CONNECTED), LNG(NO), LNG(FORMATED), LNG(NO));
+			else if((hddConnected==1)&&(hddFormated==0))
+				sprintf(c, "%s:  %s / %s:  %s",
+				LNG(CONNECTED), LNG(YES), LNG(FORMATED), LNG(NO));
+			else if(hddFormated==1)
+				sprintf(c, "%s:  %s / %s:  %s",
+				LNG(CONNECTED), LNG(YES), LNG(FORMATED), LNG(YES));
+
+			x = ((((SCREEN_WIDTH/2-25)-Menu_start_x)/2)+Menu_start_x)-(strlen(c)*FONT_WIDTH)/2;
+			printXY(c, x, y, setting->color[3], TRUE, ((SCREEN_WIDTH/2-20)-SCREEN_MARGIN-2*FONT_WIDTH));
+
+			drawOpSprite(setting->color[1],
+				SCREEN_WIDTH/2-21, Frame_start_y,
+				SCREEN_WIDTH/2-19, Frame_end_y);
+
+			if(TV_mode == TV_mode_NTSC) 
+				y += FONT_HEIGHT+11;
+			else
+				y += FONT_HEIGHT+12;
+
+			drawOpSprite(setting->color[1],
+				SCREEN_MARGIN, y-6,
+				SCREEN_WIDTH/2-20, y-4);
+
+			if(hddFormated==1){
+
+				sprintf(c, "%s: %d %s", LNG(HDD_SIZE), hddSize, LNG(MB));
+				x = ((((SCREEN_WIDTH/2-25)-Menu_start_x)/2)+Menu_start_x)-(strlen(c)*FONT_WIDTH)/2;
+				printXY(c, x, y, setting->color[3], TRUE, ((SCREEN_WIDTH/2-20)-SCREEN_MARGIN-2*FONT_WIDTH));
+				y += FONT_HEIGHT;
+				sprintf(c, "%s: %d %s", LNG(HDD_USED), hddUsed, LNG(MB));
+				printXY(c, x, y, setting->color[3], TRUE, ((SCREEN_WIDTH/2-20)-SCREEN_MARGIN-2*FONT_WIDTH));
+				y += FONT_HEIGHT;
+				sprintf(c, "%s: %d %s", LNG(HDD_FREE), hddFreeSpace, LNG(MB));
+				printXY(c, x, y, setting->color[3], TRUE, ((SCREEN_WIDTH/2-20)-SCREEN_MARGIN-2*FONT_WIDTH));
+
+				if(TV_mode == TV_mode_NTSC) 
+					ray = 45;
+				else
+					ray = 55;
+
+				x = ((((SCREEN_WIDTH/2-25)-Menu_start_x)/2)+Menu_start_x);
+				if(TV_mode == TV_mode_NTSC) 
+					y += ray+20;
+				else
+					y += ray+25;
+
+				Angle=0;
+
+				for(i=0; i<360; i++){
+					if((Angle = i-90) >= 360) Angle = i+270;
+					if(((i*100)/360) >= hddFree)
+						Color = setting->color[5];
+					else
+						Color = setting->color[4];
+					x3 = ray*cosdgf(Angle);
+					if(TV_mode == TV_mode_NTSC) 
+						y3 = (ray-5)*sindgf(Angle);
+					else
+						y3 = (ray)*sindgf(Angle);
+					x2 = x+x3;
+					y2 = y+(y3);
+					gsKit_prim_line(gsGlobal, x, y, x2, y2, 1, Color);
+					gsKit_prim_line(gsGlobal, x, y, x2+1, y2, 1, Color);
+					gsKit_prim_line(gsGlobal, x, y, x2, y2+1, 1, Color);
+				}
+
+				sprintf(c, "%d%% %s",hddFree, LNG(FREE));
+				printXY(c, x-FONT_WIDTH*4, y-FONT_HEIGHT/4, setting->color[3], TRUE, 0);
+
+				if(TV_mode == TV_mode_NTSC) 
+					y += ray+15;
+				else
+					y += ray+20;
+
+				drawOpSprite(setting->color[1],
+					SCREEN_MARGIN, y-6,
+					SCREEN_WIDTH/2-20, y-4);
+
+				Treat = PartyInfo[browser_sel].Treatment;
+				if(Treat == TREAT_SYSTEM){
+					sprintf(c, "%s: %d %s", LNG(Raw_SIZE), (int)PartyInfo[browser_sel].RawSize, LNG(MB));
+					x = ((((SCREEN_WIDTH/2-25)-Menu_start_x)/2)+Menu_start_x)-(strlen(c)*FONT_WIDTH)/2;
+					printXY(c, x, y, setting->color[3], TRUE, ((SCREEN_WIDTH/2-20)-SCREEN_MARGIN-2*FONT_WIDTH));
+					y += FONT_HEIGHT;
+					strcpy(c, LNG(Reserved_for_system));
+					x = ((((SCREEN_WIDTH/2-25)-Menu_start_x)/2)+Menu_start_x)-(strlen(c)*FONT_WIDTH)/2;
+					printXY(c, x, y, setting->color[3], TRUE, ((SCREEN_WIDTH/2-20)-SCREEN_MARGIN-2*FONT_WIDTH));
+					y += FONT_HEIGHT;
+					pfsFree = 0;
+				} else if(Treat == TREAT_NOACCESS){
+					sprintf(c, "%s: %d %s", LNG(Raw_SIZE), (int)PartyInfo[browser_sel].RawSize, LNG(MB));
+					x = ((((SCREEN_WIDTH/2-25)-Menu_start_x)/2)+Menu_start_x)-(strlen(c)*FONT_WIDTH)/2;
+					printXY(c, x, y, setting->color[3], TRUE, ((SCREEN_WIDTH/2-20)-SCREEN_MARGIN-2*FONT_WIDTH));
+					y += FONT_HEIGHT;
+					strcpy(c, LNG(Inaccessible));
+					x = ((((SCREEN_WIDTH/2-25)-Menu_start_x)/2)+Menu_start_x)-(strlen(c)*FONT_WIDTH)/2;
+					printXY(c, x, y, setting->color[3], TRUE, ((SCREEN_WIDTH/2-20)-SCREEN_MARGIN-2*FONT_WIDTH));
+					y += FONT_HEIGHT;
+					pfsFree = 0;
+				} else if(Treat == TREAT_HDL_RAW){ //starts clause for HDL without GameInfo
+					//---------- Start of clause for HDL game partitions ----------
+					//dlanor NB: Not properly implemented yet
+					sprintf(c, "%s: %d %s", LNG(HDL_SIZE), (int)PartyInfo[browser_sel].RawSize, LNG(MB));
+					x = ((((SCREEN_WIDTH/2-25)-Menu_start_x)/2)+Menu_start_x)-(strlen(c)*FONT_WIDTH)/2;
+					printXY(c, x, y, setting->color[3], TRUE, ((SCREEN_WIDTH/2-20)-SCREEN_MARGIN-2*FONT_WIDTH));
+					y += FONT_HEIGHT*4;
+					strcpy(c, LNG(Info_not_loaded));
+					x = ((((SCREEN_WIDTH/2-25)-Menu_start_x)/2)+Menu_start_x)-(strlen(c)*FONT_WIDTH)/2;
+					printXY(c, x, y, setting->color[3], TRUE, ((SCREEN_WIDTH/2-20)-SCREEN_MARGIN-2*FONT_WIDTH));
+					pfsFree = -1; //Disable lower pie chart display
+				} else if(Treat == TREAT_HDL_GAME){ //starts clause for HDL with GameInfo
+					y += FONT_HEIGHT/4;
+
+					x = ((((SCREEN_WIDTH/2-25)-Menu_start_x)/2)+Menu_start_x)-
+						(strlen(LNG(GAME_INFORMATION))*FONT_WIDTH)/2;
+					printXY(LNG(GAME_INFORMATION), x, y,
+						setting->color[3], TRUE, ((SCREEN_WIDTH/2-20)-SCREEN_MARGIN-2*FONT_WIDTH));
+
+					x = ((((SCREEN_WIDTH/2-25)-Menu_start_x)/2)+Menu_start_x)
+						-(strlen(PartyInfo[browser_sel].Game.Name)*FONT_WIDTH)/2;
+					y += FONT_HEIGHT*2;
+					printXY(PartyInfo[browser_sel].Game.Name, x, y,
+						setting->color[3], TRUE, ((SCREEN_WIDTH/2-20)-SCREEN_MARGIN-2*FONT_WIDTH));
+
+					y += FONT_HEIGHT+FONT_HEIGHT/2+FONT_HEIGHT/4;
+					sprintf(c, "%s: %s", LNG(STARTUP), PartyInfo[browser_sel].Game.Startup);
+					x = ((((SCREEN_WIDTH/2-25)-Menu_start_x)/2)+Menu_start_x)-(strlen(c)*FONT_WIDTH)/2;
+					printXY(c, x, y, setting->color[3], TRUE, ((SCREEN_WIDTH/2-20)-SCREEN_MARGIN-2*FONT_WIDTH));
+					y += FONT_HEIGHT+FONT_HEIGHT/2;
+					sprintf(c, "%s: %d %s", LNG(SIZE), (int)PartyInfo[browser_sel].RawSize, LNG(MB));
+					x = ((((SCREEN_WIDTH/2-25)-Menu_start_x)/2)+Menu_start_x)-(strlen(c)*FONT_WIDTH)/2;
+					printXY(c, x, y, setting->color[3], TRUE, ((SCREEN_WIDTH/2-20)-SCREEN_MARGIN-2*FONT_WIDTH));
+					y += FONT_HEIGHT+FONT_HEIGHT/2;
+					x = ((((SCREEN_WIDTH/2-25)-Menu_start_x)/2)+Menu_start_x)-
+						(strlen(LNG(TYPE_DVD_GAME))*FONT_WIDTH)/2;
+					if(PartyInfo[browser_sel].Game.Is_Dvd==1)
+						printXY(LNG(TYPE_DVD_GAME), x, y,
+							setting->color[3], TRUE, ((SCREEN_WIDTH/2-20)-SCREEN_MARGIN-2*FONT_WIDTH));
+					else
+						printXY(LNG(TYPE_CD_GAME), x, y,
+							setting->color[3], TRUE, ((SCREEN_WIDTH/2-20)-SCREEN_MARGIN-2*FONT_WIDTH));
+					pfsFree = -1; //Disable lower pie chart display
+					//---------- End of clause for HDL game partitions ----------
+			  }else{ //ends clause for HDL, starts clause for normal partitions
+					//---------- Start of clause for PFS partitions ----------
+
+					sprintf(c, "%s: %d %s", LNG(PFS_SIZE), (int)PartyInfo[browser_sel].TotalSize, LNG(MB));
+					x = ((((SCREEN_WIDTH/2-25)-Menu_start_x)/2)+Menu_start_x)-(strlen(c)*FONT_WIDTH)/2;
+					printXY(c, x, y, setting->color[3], TRUE, ((SCREEN_WIDTH/2-20)-SCREEN_MARGIN-2*FONT_WIDTH));
+					y += FONT_HEIGHT;
+					sprintf(c, "%s: %d %s", LNG(PFS_USED), (int)PartyInfo[browser_sel].UsedSize, LNG(MB));
+					printXY(c, x, y, setting->color[3], TRUE, ((SCREEN_WIDTH/2-20)-SCREEN_MARGIN-2*FONT_WIDTH));
+					y += FONT_HEIGHT;
+					sprintf(c, "%s: %d %s", LNG(PFS_FREE), (int)PartyInfo[browser_sel].FreeSize, LNG(MB));
+					printXY(c, x, y, setting->color[3], TRUE, ((SCREEN_WIDTH/2-20)-SCREEN_MARGIN-2*FONT_WIDTH));
+
+					pfsFree = (PartyInfo[browser_sel].FreeSize * 100) / PartyInfo[browser_sel].TotalSize;
+
+					//---------- End of clause for normal partitions (not HDL games) ----------
+				} //ends clause for normal partitions
+
+				if(pfsFree >= 0){ //Will be negative when skipping this graph
+					x = ((((SCREEN_WIDTH/2-25)-Menu_start_x)/2)+Menu_start_x);
+					if(TV_mode == TV_mode_NTSC) 
+						y += ray+20;
+					else
+						y += ray+25;
+
+					Angle=0;
+
+					for(i=0; i<360; i++){
+						if((Angle = i-90) >= 360) Angle = i+270;
+						if(((i*100)/360) >= pfsFree)
+							Color = setting->color[5];
+						else
+							Color = setting->color[4];
+						x3 = ray*cosdgf(Angle);
+						if(TV_mode == TV_mode_NTSC) 
+							y3 = (ray-5)*sindgf(Angle);
+						else
+							y3 = (ray)*sindgf(Angle);
+						x2 = x+x3;
+						y2 = y+(y3);
+						gsKit_prim_line(gsGlobal, x, y, x2, y2, 1, Color);
+						gsKit_prim_line(gsGlobal, x, y, x2+1, y2, 1, Color);
+						gsKit_prim_line(gsGlobal, x, y, x2, y2+1, 1, Color);
+					}
+
+					sprintf(c, "%d%% %s",pfsFree, LNG(FREE));
+					printXY(c, x-FONT_WIDTH*4, y-FONT_HEIGHT/2, setting->color[3], TRUE, 0);
+				}
+
+				rows = (Menu_end_y-Menu_start_y)/FONT_HEIGHT;
+
+				x = SCREEN_WIDTH/2-FONT_WIDTH;
+				y = Menu_start_y;
+
+				for(i=0; i<rows; i++)
+				{
+					if(top+i >= browser_nfiles) break;
+					if(top+i == browser_sel) Color = setting->color[2];  //Highlight cursor line
+					else			 Color = setting->color[3];
+
+					strcpy(tmp,PartyInfo[top+i].Name);
+					printXY(tmp, x+4, y, Color, TRUE, ((SCREEN_WIDTH-SCREEN_MARGIN)-(SCREEN_WIDTH/2-FONT_WIDTH)));
+					y += FONT_HEIGHT;
+				} //ends for, so all browser rows were fixed above
+				if(browser_nfiles > rows) { //if more files than available rows, use scrollbar
+					drawFrame(SCREEN_WIDTH-SCREEN_MARGIN-LINE_THICKNESS*8, Frame_start_y,
+						SCREEN_WIDTH-SCREEN_MARGIN, Frame_end_y, setting->color[1]);
+					y0=(Menu_end_y-Menu_start_y+8) * ((double)top/browser_nfiles);
+					y1=(Menu_end_y-Menu_start_y+8) * ((double)(top+rows)/browser_nfiles);
+					drawOpSprite(setting->color[1],
+						SCREEN_WIDTH-SCREEN_MARGIN-LINE_THICKNESS*6, (y0+Menu_start_y-4),
+						SCREEN_WIDTH-SCREEN_MARGIN-LINE_THICKNESS*2, (y1+Menu_start_y-4));
+				} //ends clause for scrollbar
+			} //ends hdd formated
+			//Tooltip section
+			sprintf(tooltip, "R1:%s  ÿ3:%s", LNG(MENU), LNG(Exit));
+			if(PartyInfo[browser_sel].Treatment == TREAT_HDL_RAW){
+				sprintf(tmp, " ÿ2:%s", LNG(Load_HDL_Game_Info));
+				strcat(tooltip, tmp);
+			}
+			setScrTmp(LNG(PS2_HDD_MANAGER), tooltip);
+
+		}//ends if(event||post_event)
+		drawScr();
+		post_event = event;
+		event = 0;
+	}//ends while
+	
+	return;
+}
+//------------------------------
+//endfunc hddManager
+//--------------------------------------------------------------
Index: ps2launchargs/source/uLaunchELF/hdl_info/Makefile
===================================================================
--- ps2launchargs/source/uLaunchELF/hdl_info/Makefile	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/hdl_info/Makefile	(revision 1101)
@@ -0,0 +1,40 @@
+IOP_OBJS	= main.o hdd.o apa.o hdl.o imports.o exports.o
+
+IOP_BIN		= hdl_info.irx
+
+IOP_CFLAGS  += -Wall -fno-builtin
+IOP_LDFLAGS += -s
+IOP_INCS += -I$(PS2SDK)/iop/include -I$(PS2SDK)/common/include
+
+all: $(IOP_BIN)
+
+run: all
+	ps2client -h 192.168.0.10 -t 1 execiop host:$(IOP_BIN)
+reset: clean
+	ps2client -h 192.168.0.10 reset
+
+clean:
+	rm -f *.o *.irx
+
+include $(PS2SDK)/samples/Makefile.pref
+include $(PS2SDK)/samples/Makefile.iopglobal
+
+# compiling with iop-gcc 3.2.2 causes weird problems in ps2ftpd
+# temporary solution is to turn off compiler optimization
+
+IOP_CFLAGS = $(CFLAGS_TARGET) -O2 -G0 -c $(IOP_INCS) -Wall -fno-builtin
+# Iritscen: After first 'make' invocation fails (at top level), remove "-c" argument above and call 'make' again (from top level) to complete build
+
+# A rule to build imports.lst.
+%.o : %.lst
+	echo "#include \"irx_imports.h\"" > build-imports.c
+	cat $< >> build-imports.c
+	$(IOP_CC) $(IOP_CFLAGS) build-imports.c -o $@
+	-rm -f build-imports.c
+
+# A rule to build exports.tab.
+%.o : %.tab
+	echo "#include \"irx.h\"" > build-exports.c
+	cat $< >> build-exports.c
+	$(IOP_CC) $(IOP_CFLAGS) build-exports.c -o $@
+	-rm -f build-exports.c
Index: ps2launchargs/source/uLaunchELF/hdl_info/apa.c
===================================================================
--- ps2launchargs/source/uLaunchELF/hdl_info/apa.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/hdl_info/apa.c	(revision 1101)
@@ -0,0 +1,323 @@
+//--------------------------------------------------------------
+//File name:   apa.c
+//--------------------------------------------------------------
+#include <thbase.h>
+#include <sysclib.h>
+#include <cdvdman.h>
+#include <iomanX.h>
+#include <sysmem.h>
+
+#include "ps2_hdd.h"
+#include "hdd.h"
+#include "hdl.h"
+#include "apa.h"
+
+#define AUTO_DELETE_EMPTY
+
+#define _MB * (1024 * 1024) /* really ugly :-) */
+
+typedef struct ps2_partition_run_type
+{
+ unsigned long sector;
+ u_long size_in_mb;
+} ps2_partition_run_t;
+
+//Remove this line, and uncomment the next line, to reactivate 'apa_check'
+//static int apa_check(const apa_partition_table_t *table);
+
+//--------------------------------------------------------------
+u_long apa_partition_checksum(const ps2_partition_header_t *part)
+{
+ const u_long *p = (const u_long*)part;
+ register u_long i;
+ u_long sum = 0;
+ for(i=1; i<256; ++i)
+  sum += get_u32(p + i);
+ return sum;
+}
+//------------------------------
+//endfunc apa_partition_checksum
+//--------------------------------------------------------------
+static apa_partition_table_t* apa_ptable_alloc(void)
+{
+ apa_partition_table_t *table = AllocSysMemory(0, sizeof (apa_partition_table_t), NULL);
+ if(table != NULL)
+  memset(table, 0, sizeof (apa_partition_table_t));
+ return table;
+}
+//------------------------------
+//endfunc apa_ptable_alloc
+//--------------------------------------------------------------
+void apa_ptable_free(apa_partition_table_t *table)
+{
+	if (table != NULL){
+		if (table->chunks_map != NULL)
+			FreeSysMemory(table->chunks_map);
+		if (table->parts != NULL)
+			FreeSysMemory(table->parts);
+		FreeSysMemory(table);
+	}
+}
+//------------------------------
+//endfunc apa_ptable_free
+//--------------------------------------------------------------
+static int apa_part_add (apa_partition_table_t *table, const ps2_partition_header_t *part, int existing, int linked)
+{
+	if (table->part_count == table->part_alloc_){ /* grow buffer */
+		u_long bytes = (table->part_alloc_ + 16) * sizeof (apa_partition_t);
+		apa_partition_t *tmp = AllocSysMemory(0, bytes, NULL);
+		if(tmp != NULL)
+		{
+			memset(tmp, 0, bytes);
+			if (table->parts != NULL) /* copy existing */
+				memcpy(tmp, table->parts, table->part_count * sizeof (apa_partition_t));
+			FreeSysMemory(table->parts);
+			table->parts = tmp;
+			table->part_alloc_ += 16;
+		}
+		else return -2;
+	}
+
+	memcpy(&table->parts[table->part_count].header, part, sizeof (ps2_partition_header_t));
+	table->parts[table->part_count].existing = existing;
+	table->parts[table->part_count].modified = !existing;
+	table->parts[table->part_count].linked = linked;
+	++table->part_count;
+
+	return 0;
+}
+//------------------------------
+//endfunc apa_part_add
+//--------------------------------------------------------------
+/* //Remove this line and a similar one below to reactivate 'apa_setup_statistics'
+static int apa_setup_statistics(apa_partition_table_t *table)
+{
+ u_long i;
+ char *map;
+
+ table->total_chunks = table->device_size_in_mb / 128;
+ map = AllocSysMemory(0, table->total_chunks * sizeof (char), NULL);
+ if(map != NULL)
+ {
+  for(i=0; i<table->total_chunks; ++i)
+   map [i] = MAP_AVAIL;
+
+  // build occupided/available space map
+  table->allocated_chunks = 0;
+  table->free_chunks = table->total_chunks;
+  for(i=0; i<table->part_count; ++i)
+  {
+   const ps2_partition_header_t *part = &table->parts [i].header;
+   u_long part_no = get_u32(&part->start) / ((128 _MB) / 512);
+   u_long num_parts = get_u32(&part->length) / ((128 _MB) / 512);
+
+   // "alloc" num_parts starting at part_no
+   while (num_parts)
+   {
+    if(map[part_no] == MAP_AVAIL)
+     map[part_no] = get_u32(&part->main) == 0 ? MAP_MAIN : MAP_SUB;
+    else
+     map[part_no] = MAP_COLL; // collision
+    ++part_no;
+    --num_parts;
+    ++table->allocated_chunks;
+    --table->free_chunks;
+   }
+  }
+
+  if(table->chunks_map != NULL)
+  FreeSysMemory(table->chunks_map);
+  table->chunks_map = map;
+
+  return 0;
+ }
+ else return -2;
+}
+*/ //Remove this line and a similar one below to reactivate 'apa_setup_statistics'
+//------------------------------
+//endfunc apa_setup_statistics
+//--------------------------------------------------------------
+int apa_ptable_read_ex ( hio_t *hio, apa_partition_table_t **table)
+{
+	u_long size_in_kb;
+	int result = hio->stat(hio, &size_in_kb);
+	if(result == 0){
+		u_long total_sectors;
+		// limit HDD size to 128GB - 1KB; that is: exclude the last 128MB chunk
+		//if (size_in_kb > 128 * 1024 * 1024 - 1)
+		// size_in_kb = 128 * 1024 * 1024 - 1;
+
+		total_sectors = size_in_kb * 2; /* 1KB = 2 sectors of 512 bytes, each */
+
+		*table = apa_ptable_alloc();
+		if(*table != NULL){
+			u_long sector = 0;
+			do {
+				u_long bytes;
+				ps2_partition_header_t part;
+				result = hio->read(hio, sector, sizeof(part) / 512, &part, &bytes);
+				if(result == 0){
+					if(bytes == sizeof(part) &&
+					  get_u32(&part.checksum) == apa_partition_checksum(&part) &&
+					  memcmp(part.magic, PS2_PARTITION_MAGIC, 4) == 0)
+					{
+						if(get_u32(&part.start) < total_sectors &&
+						  get_u32(&part.start) + get_u32(&part.length) < total_sectors)
+						{
+							if((get_u16(&part.flags)==0x0000) && (get_u16(&part.type) ==0x1337))
+								result = apa_part_add(*table, &part, 1, 1);
+							if(result == 0)
+								sector = get_u32(&part.next);
+						} else { /* partition behind end-of-HDD */
+							result = 7; /* data behind end-of-HDD */
+							break;
+						}
+					} else
+						result = 1;
+				}
+				/* TODO: check whether next partition is not loaded already --
+				* do not deadlock; that is a quick-and-dirty hack */
+				if ((*table)->part_count > 10000)
+					result = 7;
+			} while (result == 0 && sector != 0);
+
+			if (result == 0){
+				(*table)->device_size_in_mb = size_in_kb / 1024;
+				//NB: uncommenting the next lines requires changes elsewhere too
+				//result = apa_setup_statistics (*table);
+				//if (result == 0)
+					//result = apa_check (*table);
+			}
+
+			if (result != 0){
+				result = 20000+(*table)->part_count;
+				apa_ptable_free (*table);
+			}
+		}
+		else result = -2;
+	}
+	return result;
+}
+//------------------------------
+//endfunc apa_ptable_read_ex
+//--------------------------------------------------------------
+/* //Remove this line and a similar one below to reactivate 'apa_check'
+static int apa_check (const apa_partition_table_t *table) {
+
+  u_long i, j, k;
+
+  const u_long total_sectors = table->device_size_in_mb * 1024 * 2;
+
+  for (i=0; i<table->part_count; ++i)
+    {
+      const ps2_partition_header_t *part = &table->parts [i].header;
+      if (get_u32 (&part->checksum) != apa_partition_checksum (part))
+ return 7; // bad checksum
+
+      if (get_u32 (&part->start) < total_sectors &&
+   get_u32 (&part->start) + get_u32 (&part->length) <= total_sectors)
+ ;
+      else
+ {
+     return 7; // data behind end-of-HDD
+ }
+
+      if ((get_u32 (&part->length) % ((128 _MB) / 512)) != 0)
+ return 7; // partition size not multiple to 128MB
+
+      if ((get_u32 (&part->start) % get_u32 (&part->length)) != 0)
+ return 7; // partition start not multiple on partition size
+
+      if (get_u32 (&part->main) == 0 &&
+   get_u16 (&part->flags) == 0 &&
+   get_u32 (&part->start) != 0)
+ { // check sub-partitions
+   u_long count = 0;
+   for (j=0; j<table->part_count; ++j)
+     {
+       const ps2_partition_header_t *part2 = &table->parts [j].header;
+       if (get_u32 (&part2->main) == get_u32 (&part->start))
+  { // sub-partition of current main partition
+    int found;
+    if (get_u16 (&part2->flags) != PS2_PART_FLAG_SUB)
+      return 7;
+
+    found = 0;
+    for (k=0; k<get_u32 (&part->nsub); ++k)
+      if (get_u32 (&part->subs [k].start) == get_u32 (&part2->start))
+        { // in list
+   if (get_u32 (&part->subs [k].length) != get_u32 (&part2->length))
+     return 7;
+   found = 1;
+   break;
+        }
+    if (!found)
+      return 7; // not found in the list
+
+    ++count;
+  }
+     }
+   if (count != get_u32 (&part->nsub))
+     return 7; // wrong number of sub-partitions
+ }
+    }
+
+  // verify double-linked list
+  for (i=0; i<table->part_count; ++i)
+    {
+      apa_partition_t *prev = table->parts + (i > 0 ? i - 1 : table->part_count - 1);
+      apa_partition_t *curr = table->parts + i;
+      apa_partition_t *next = table->parts + (i + 1 < table->part_count ? i + 1 : 0);
+      if (get_u32 (&curr->header.prev) != get_u32 (&prev->header.start) ||
+   get_u32 (&curr->header.next) != get_u32 (&next->header.start))
+ return 7; // bad links
+    }
+
+  return 0;
+}
+*/ //Remove this line and a similar one above to reactivate 'apa_check'
+//------------------------------
+//endfunc apa_check
+//--------------------------------------------------------------
+u_long get_u32 (const void *buffer)
+{
+  const u_char *p = buffer;
+  return ((((u_long) p[3]) << 24) |
+          (((u_long) p[2]) << 16) |
+          (((u_long) p[1]) <<  8) |
+          (((u_long) p[0]) <<  0));
+}
+//------------------------------
+//endfunc get_u32
+//--------------------------------------------------------------
+void set_u32 (void *buffer, u_long val)
+{
+  u_char *p = buffer;
+  p [3] = (u_char) (val >> 24);
+  p [2] = (u_char) (val >> 16);
+  p [1] = (u_char) (val >>  8);
+  p [0] = (u_char) (val >>  0);
+}
+//------------------------------
+//endfunc set_u32
+//--------------------------------------------------------------
+u_short get_u16 (const void *buffer)
+{
+  const u_char *p = buffer;
+  return ((((u_short) p[1]) << 8) |
+          (((u_short) p[0]) << 0));
+}
+//------------------------------
+//endfunc get_u16
+//--------------------------------------------------------------
+void set_u16 (void *buffer, u_short val)
+{
+  u_char *p = buffer;
+  p [1] = (u_char) (val >> 8);
+  p [0] = (u_char) (val >> 0);
+}
+//------------------------------
+//endfunc set_u16
+//--------------------------------------------------------------
+//End of file: apa.c
+//--------------------------------------------------------------
Index: ps2launchargs/source/uLaunchELF/hdl_info/apa.h
===================================================================
--- ps2launchargs/source/uLaunchELF/hdl_info/apa.h	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/hdl_info/apa.h	(revision 1101)
@@ -0,0 +1,48 @@
+#ifndef _CDVDAPA_H_
+#define _CDVDAPA_H_
+
+/* chunks_map */
+static const char MAP_AVAIL = '.';
+static const char MAP_MAIN = 'M';
+static const char MAP_SUB = 's';
+static const char MAP_COLL = 'x';
+static const char MAP_ALLOC = '*';
+
+typedef struct apa_partition_type
+{
+  int existing;
+  int modified;
+  int linked;
+  ps2_partition_header_t header;
+} apa_partition_t;
+
+
+typedef struct apa_partition_table_type
+{
+  u_long device_size_in_mb;
+  u_long total_chunks;
+  u_long allocated_chunks;
+  u_long free_chunks;
+
+  char *chunks_map;
+
+  /* existing partitions */
+  u_long part_alloc_;
+  u_long part_count;
+  apa_partition_t *parts;
+} apa_partition_table_t;
+
+void apa_ptable_free(apa_partition_table_t *table);
+
+u_long apa_partition_checksum (const ps2_partition_header_t *part);
+
+int apa_ptable_read_ex (hio_t *hio, apa_partition_table_t **table);
+
+u_long get_u32 (const void *buffer);
+void set_u32 (void *buffer, u_long val);
+
+u_short get_u16 (const void *buffer);
+void set_u16 (void *buffer, u_short val);
+
+
+#endif /* _APA_H_ */
Index: ps2launchargs/source/uLaunchELF/hdl_info/exports.tab
===================================================================
--- ps2launchargs/source/uLaunchELF/hdl_info/exports.tab	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/hdl_info/exports.tab	(revision 1101)
@@ -0,0 +1,11 @@
+DECLARE_EXPORT_TABLE(hdl_srv, 1, 1)
+	DECLARE_EXPORT(_start)
+	DECLARE_EXPORT(_retonly)
+	DECLARE_EXPORT(shutdown)
+	DECLARE_EXPORT(_retonly)
+
+	DECLARE_EXPORT(HdlRenameGame)
+
+END_EXPORT_TABLE
+
+void _retonly() {}
Index: ps2launchargs/source/uLaunchELF/hdl_info/hdd.c
===================================================================
--- ps2launchargs/source/uLaunchELF/hdl_info/hdd.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/hdl_info/hdd.c	(revision 1101)
@@ -0,0 +1,198 @@
+//--------------------------------------------------------------
+//File name:   hdd.c
+//--------------------------------------------------------------
+#include <thbase.h>
+#include <sysclib.h>
+#include <stdio.h>
+#include <sysmem.h>
+#include <dev9.h>
+#include <atad.h>
+
+#include "ps2_hdd.h"
+#include "hdd.h"
+#include "hdl.h"
+#include "apa.h"
+
+static hdl_games_list_t *games = NULL;
+static hio_t *hio = NULL;
+
+//--------------------------------------------------------------
+static int iop_stat(hio_t *hio, u_long *size_in_kb)
+{
+ hio_iop_t *iop = (hio_iop_t*) hio;
+ *size_in_kb = iop->size_in_sectors / 2;
+ return 0;
+}
+//------------------------------
+//endfunc iop_stat
+//--------------------------------------------------------------
+static int iop_read(hio_t *hio, u_long start_sector, u_long num_sectors, void *output, u_long *bytes)
+{
+ hio_iop_t *iop = (hio_iop_t*) hio;
+ int result = ata_device_dma_transfer(iop->unit, output, start_sector, num_sectors, ATA_DIR_READ);
+ if (result == 0)
+ {
+  *bytes = num_sectors * HDD_SECTOR_SIZE;
+  return 0;
+ }
+ else return -1;
+}
+//------------------------------
+//endfunc iop_read
+//--------------------------------------------------------------
+static int iop_write(hio_t *hio, u_long start_sector, u_long num_sectors, const void *input, u_long *bytes)
+{
+ hio_iop_t *iop = (hio_iop_t*) hio;
+ int result = ata_device_dma_transfer(iop->unit, (char*) input, start_sector, num_sectors, ATA_DIR_WRITE);
+ if (result == 0)
+ {
+  *bytes = num_sectors * HDD_SECTOR_SIZE;
+  return 0;
+ }
+ return -1;
+}
+//------------------------------
+//endfunc iop_write
+//--------------------------------------------------------------
+static int iop_flush(hio_t *hio)
+{
+ hio_iop_t *iop = (hio_iop_t*) hio;
+ int result = ata_device_flush_cache(iop->unit);
+ return result;
+}
+//------------------------------
+//endfunc iop_flush
+//--------------------------------------------------------------
+static int iop_close(hio_t *hio)
+{
+  FreeSysMemory (hio);
+  return 0;
+}
+//------------------------------
+//endfunc iop_close
+//--------------------------------------------------------------
+static int iop_poweroff (hio_t *hio)
+{
+ /* dev9 shutdown; borrowed from ps2link */
+ dev9IntrDisable(-1);
+ dev9Shutdown();
+
+ *((unsigned char *) 0xbf402017) = 0x00;
+ *((unsigned char *) 0xbf402016) = 0x0f;
+ return 0;
+}
+//------------------------------
+//endfunc iop_poweroff
+//--------------------------------------------------------------
+static hio_t* iop_alloc (int unit, size_t size_in_sectors)
+{
+ hio_iop_t *iop = AllocSysMemory (0, sizeof (hio_iop_t), NULL);
+ if (iop != NULL)
+   {
+     hio_t *hio = &iop->hio;
+     hio->stat = &iop_stat;
+     hio->read = &iop_read;
+     hio->write = &iop_write;
+     hio->flush = &iop_flush;
+     hio->close = &iop_close;
+     hio->poweroff = &iop_poweroff;
+     iop->unit = unit;
+     iop->size_in_sectors = size_in_sectors;
+   }
+ return ((hio_t*) iop);
+}
+//------------------------------
+//endfunc iop_alloc
+//--------------------------------------------------------------
+int hio_iop_probe (const char *path, hio_t **hio)
+{
+ if (path[0] == 'h' &&
+     path[1] == 'd' &&
+     path[2] == 'd' &&
+     (path[3] >= '0' && path[3] <= '9') &&
+     path[4] == ':' &&
+     path[5] == '\0')
+ {
+  int unit = path [3] - '0';
+  ata_devinfo_t *dev_info = ata_get_devinfo(unit);
+  if (dev_info != NULL && dev_info->exists)
+  {
+   *hio = iop_alloc (unit, dev_info->total_sectors);
+   if (*hio != NULL)
+    return (0);
+   else
+    return -2;
+  }
+ }
+ return 14;
+}
+//------------------------------
+//endfunc hio_iop_probe
+//--------------------------------------------------------------
+int HdlGetGameInfo(char *PartName, GameInfo *GameInf){
+
+	int i, count=0, err;
+
+	hdl_glist_free(games); games = NULL;
+	if (hio != NULL) hio->close(hio); hio = NULL;
+
+	if(hio_iop_probe("hdd0:", &hio) == 0){
+ 		if((err = hdl_glist_read(hio, &games)) == 0){
+			for (i=0; i<games->count; ++i){
+				const hdl_game_info_t *game = &games->games[i];
+
+				if(!strcmp(PartName, game->partition_name)){
+					strcpy(GameInf->Partition_Name, game->partition_name);
+					strcpy(GameInf->Name, game->name);
+					strcpy(GameInf->Startup, game->startup);
+					GameInf->Is_Dvd = game->is_dvd;
+					return 0;  //Return flag for no error
+				}
+				++count;
+			} /* for */
+			return -3;  //Return error flag for 'Game not found'
+		} /* if */
+		return err;  //Return error flag for 'hdl_glist_read failed'
+	} /* if */
+	return -1;  //Return error flag for 'hio_iop_probe failed'
+}
+//------------------------------
+//endfunc HdlGetGameInfo
+//--------------------------------------------------------------
+
+int HdlRenameGame(void *Data){
+
+	int i, count=0, err;
+
+	int *Pointer = Data;
+	Rpc_Packet_Send_Rename *Packet = (Rpc_Packet_Send_Rename *)Pointer;
+
+	hdl_glist_free(games); games = NULL;
+	if (hio != NULL) hio->close(hio); hio = NULL;
+
+	if(hio_iop_probe("hdd0:", &hio) == 0){
+		if((err = hdl_glist_read(hio, &games)) == 0){
+			for (i=0; i<games->count; ++i){
+				hdl_game_info_t *game = &games->games[i];
+  
+				if(!strcmp(Packet->OldName, game->name)){
+					printf("Renaming Game %s To %s.\n", game->name, Packet->NewName);
+					strcpy(game->name, Packet->NewName);
+					if((err = hdl_glist_write(hio, game))==0)
+						return 0;  //Return flag for no error
+					else
+						return err;  //Return error flag for 'hdl_glist_write failed'
+				}
+				++count;
+			} /* for */
+			return -3;  //Return error flag for 'Game not found'
+		} /* if */
+		return err;  //Return error flag for 'hdl_glist_read failed'
+	} /* if */
+	return -1;  //Return error flag for 'hio_iop_probe failed'
+}
+//------------------------------
+//endfunc HdlRenameGame
+//--------------------------------------------------------------
+//End of file: hdd.c
+//--------------------------------------------------------------
Index: ps2launchargs/source/uLaunchELF/hdl_info/hdd.h
===================================================================
--- ps2launchargs/source/uLaunchELF/hdl_info/hdd.h	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/hdl_info/hdd.h	(revision 1101)
@@ -0,0 +1,79 @@
+#ifndef _CDVDHDD_H_
+#define _CDVDHDD_H_
+
+#define HDL_IRX 0xD0D0D0D
+
+#define HDD_SECTOR_SIZE 512    /* HDD sector size in bytes */
+
+/* HD Loader I/O interface */
+
+typedef struct hio_type hio_t;
+
+typedef int (*hio_probe_t) (const char *path,
+			    hio_t **hio);
+
+typedef int (*hio_stat_t) (hio_t *hio,
+			   u_long *size_in_kb);
+
+typedef int (*hio_read_t) (hio_t *hio,
+			   u_long start_sector,
+			   u_long num_sectors,
+			   void *output,
+			   u_long *bytes);
+
+typedef int (*hio_write_t) (hio_t *hio,
+			    u_long start_sector,
+			    u_long num_sectors,
+			    const void *input,
+			    u_long *bytes);
+
+typedef int (*hio_flush_t) (hio_t *hio);
+
+typedef int (*hio_poweroff_t) (hio_t *hio);
+
+typedef int (*hio_close_t) (hio_t *hio);
+
+/* return last error text in a memory buffer, that would be freed by calling hio_dispose_error_t */
+typedef char* (*hio_last_error_t) (hio_t *hio);
+typedef void (*hio_dispose_error_t) (hio_t *hio,
+				     char* error);
+
+struct hio_type
+{
+  hio_stat_t stat;
+  hio_read_t read;
+  hio_write_t write;
+  hio_flush_t flush;
+  hio_close_t close;
+  hio_poweroff_t poweroff;
+  hio_last_error_t last_error;
+  hio_dispose_error_t dispose_error;
+};
+
+typedef struct hio_iop_type
+{
+  hio_t hio;
+  int unit;
+  size_t size_in_sectors;
+} hio_iop_t;
+
+typedef struct {
+  char Partition_Name [32 + 1];
+} Rpc_Packet_Send_GetInfo;
+
+typedef struct {
+	char OldName[64];
+	char NewName[64];
+} Rpc_Packet_Send_Rename;
+
+typedef struct {
+  char Partition_Name [32 + 1];
+  char Name [64 + 1];
+  char Startup [8 + 1 + 3 + 1];
+  int  Is_Dvd;
+} GameInfo;
+
+int HdlGetGameInfo(char *PartName, GameInfo *GameInf);
+int HdlRenameGame(void *Data);
+
+#endif
Index: ps2launchargs/source/uLaunchELF/hdl_info/hdl.c
===================================================================
--- ps2launchargs/source/uLaunchELF/hdl_info/hdl.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/hdl_info/hdl.c	(revision 1101)
@@ -0,0 +1,183 @@
+//--------------------------------------------------------------
+//File name:   hdl.c
+//--------------------------------------------------------------
+#include <thbase.h>
+#include <stdio.h>
+#include <sysclib.h>
+#include <cdvdman.h>
+#include <iomanX.h>
+#include <sysmem.h>
+
+#include "ps2_hdd.h"
+#include "hdd.h"
+#include "hdl.h"
+#include "apa.h"
+
+//--------------------------------------------------------------
+void hdl_glist_free (hdl_games_list_t *glist)
+{
+ if (glist != NULL)
+ {
+  FreeSysMemory  (glist->games);
+  FreeSysMemory  (glist);
+ }
+}
+//------------------------------
+//endfunc hdl_glist_free
+//--------------------------------------------------------------
+static int hdl_ginfo_read (hio_t *hio, const ps2_partition_header_t *part, hdl_game_info_t *ginfo)
+{
+ u_long i, size;
+ /* data we're interested in starts @ 0x101000 and is header
+ * plus information for up to 65 partitions
+ * (1 main + 64 sub) by 12 bytes each */
+ const u_long offset = 0x101000;
+ char buffer [1024];
+ int result;
+ u_long bytes;
+
+ result = hio->read(hio, get_u32 (&part->start) + offset / 512, 2, buffer, &bytes);
+ if (result == 0)
+ {
+  if (bytes == 1024)
+  {
+   /* calculate total size */
+   size = get_u32 (&part->length);
+   for (i=0; i<get_u32 (&part->nsub); ++i)
+    size += get_u32 (&part->subs [i].length);
+
+   memcpy (ginfo->partition_name, part->id, PS2_PART_IDMAX);
+   ginfo->partition_name [PS2_PART_IDMAX] = '\0';
+   strcpy (ginfo->name, buffer + 8);
+   strcpy (ginfo->startup, buffer + 0xac);
+   ginfo->compat_flags = buffer [0xa8];
+   ginfo->is_dvd = buffer [0xec] == 0x14;
+   ginfo->start_sector = get_u32 (&part->start);
+   ginfo->total_size_in_kb = size / 2;
+  }
+  else result = -1;
+ }
+ return (result);
+}
+//------------------------------
+//endfunc hdl_ginfo_read
+//--------------------------------------------------------------
+int hdl_glist_read (hio_t *hio, hdl_games_list_t **glist)
+{
+	apa_partition_table_t *ptable;
+	int result;
+
+	result = apa_ptable_read_ex (hio, &ptable);
+	if (result == 0){
+		u_long i, count = 0;
+		void *tmp;
+		for (i=0; i<ptable->part_count; ++i)
+			count += (get_u16 (&ptable->parts [i].header.flags) == 0x00 &&
+			          get_u16 (&ptable->parts [i].header.type) == 0x1337);
+
+		tmp = AllocSysMemory(0, (sizeof (hdl_game_info_t) * count), NULL);
+		if (tmp != NULL){
+			memset (tmp, 0, sizeof (hdl_game_info_t) * count);
+			*glist = AllocSysMemory(0, sizeof (hdl_games_list_t), NULL);
+			if (*glist != NULL){
+				u_long index = 0;
+				memset (*glist, 0, sizeof (hdl_games_list_t));
+				(*glist)->count = count;
+				(*glist)->games = tmp;
+				(*glist)->total_chunks = ptable->total_chunks;
+				(*glist)->free_chunks = ptable->free_chunks;
+				for (i=0; result==0&&i<ptable->part_count; ++i){
+					const ps2_partition_header_t *part = &ptable->parts [i].header;
+					if (get_u16 (&part->flags) == 0x00 && get_u16 (&part->type) == 0x1337)
+						result = hdl_ginfo_read (hio, part, (*glist)->games + index++);
+				}
+				if (result != 0)
+					FreeSysMemory(*glist);
+			} else
+				result = -2;
+			if (result != 0)
+				FreeSysMemory(tmp);
+		} else result = -2;
+
+		apa_ptable_free (ptable);
+	} else { //apa_ptable_read_ex failed
+	}
+	return result;
+}
+//------------------------------
+//endfunc hdl_glist_read
+//--------------------------------------------------------------
+static int hdl_ginfo_write (hio_t *hio, const ps2_partition_header_t *part, hdl_game_info_t *ginfo)
+{
+ const u_long offset = 0x101000;
+ char buffer [1024];
+ int result;
+ u_long bytes;
+
+ result = hio->read(hio, get_u32(&part->start) + offset / 512, 2, buffer, &bytes);
+
+ memset(buffer + 8, 0, PS2_PART_NAMEMAX);
+ memcpy(buffer + 8, ginfo->name, PS2_PART_NAMEMAX);
+ 
+ result = hio->write(hio, get_u32(&part->start) + offset / 512, 2, buffer, &bytes);
+
+ return result;
+}
+//------------------------------
+//endfunc hdl_ginfo_write
+//--------------------------------------------------------------
+int hdl_glist_write (hio_t *hio, hdl_game_info_t *ginfo)
+{
+ hdl_games_list_t *tmplist;
+ apa_partition_table_t *ptable;
+ int result;
+
+ result = apa_ptable_read_ex (hio, &ptable);
+ if (result == 0)
+ {
+  u_long i, count = 0;
+  void *tmp;
+  for (i=0; i<ptable->part_count; ++i)
+   count += (get_u16 (&ptable->parts [i].header.flags) == 0x00 &&
+            get_u16 (&ptable->parts [i].header.type) == 0x1337);
+
+  tmp = AllocSysMemory(0, (sizeof (hdl_game_info_t) * count), NULL);
+  if (tmp != NULL)
+  {
+   memset (tmp, 0, sizeof (hdl_game_info_t) * count);
+   tmplist = AllocSysMemory(0, sizeof (hdl_games_list_t), NULL);
+   if (tmplist != NULL)
+   {
+    u_long index = 0;
+    memset (tmplist, 0, sizeof (hdl_games_list_t));
+    tmplist->count = count;
+    tmplist->games = tmp;
+    tmplist->total_chunks = ptable->total_chunks;
+    tmplist->free_chunks = ptable->free_chunks;
+    for (i=0; result==0&&i<ptable->part_count; ++i)
+    {
+     const ps2_partition_header_t *part = &ptable->parts [i].header;
+     if (get_u16 (&part->flags) == 0x00 && get_u16 (&part->type) == 0x1337){
+      result = hdl_ginfo_read(hio, part, tmplist->games + index++);
+      if(!strcmp(tmplist->games[index-1].partition_name, ginfo->partition_name)){
+       result = hdl_ginfo_write(hio, part, ginfo);
+       break;
+      }
+     }
+    }
+    FreeSysMemory(tmplist);
+   }
+   else result = -2;
+   if (result != 0) FreeSysMemory(tmp);
+  }
+  else result = -2;
+
+  apa_ptable_free (ptable);
+ }
+ return result;
+}
+//------------------------------
+//endfunc hdl_glist_write
+//--------------------------------------------------------------
+//End of file: hdl.c
+//--------------------------------------------------------------
Index: ps2launchargs/source/uLaunchELF/hdl_info/hdl.h
===================================================================
--- ps2launchargs/source/uLaunchELF/hdl_info/hdl.h	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/hdl_info/hdl.h	(revision 1101)
@@ -0,0 +1,29 @@
+#ifndef _CDVDHDL_H_
+#define _CDVDHDL_H_
+
+#define HDL_GAME_NAME_MAX  64
+
+typedef struct hdl_game_info_type
+{
+  char partition_name [PS2_PART_IDMAX + 1];
+  char name [HDL_GAME_NAME_MAX + 1];
+  char startup [8 + 1 + 3 + 1];
+  u_char compat_flags;
+  int is_dvd;
+  u_long start_sector;
+  u_long total_size_in_kb;
+} hdl_game_info_t;
+
+typedef struct hdl_games_list_type
+{
+  u_long count;
+  hdl_game_info_t *games;
+  u_long total_chunks;
+  u_long free_chunks;
+} hdl_games_list_t;
+
+void hdl_glist_free (hdl_games_list_t *glist);
+int  hdl_glist_read (hio_t *hio, hdl_games_list_t **glist);
+int  hdl_glist_write (hio_t *hio, hdl_game_info_t *ginfo);
+
+#endif /* _CDVDHDL_H_ */
Index: ps2launchargs/source/uLaunchELF/hdl_info/imports.lst
===================================================================
--- ps2launchargs/source/uLaunchELF/hdl_info/imports.lst	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/hdl_info/imports.lst	(revision 1101)
@@ -0,0 +1,26 @@
+dev9_IMPORTS_start
+I_dev9IntrDisable
+I_dev9Shutdown
+dev9_IMPORTS_end
+
+atad_IMPORTS_start
+I_ata_get_devinfo
+I_ata_device_dma_transfer
+I_ata_device_flush_cache
+atad_IMPORTS_end
+
+stdio_IMPORTS_start
+I_printf
+stdio_IMPORTS_end
+
+sysmem_IMPORTS_start
+I_AllocSysMemory
+I_FreeSysMemory
+sysmem_IMPORTS_end
+
+sifcmd_IMPORTS_start
+I_sceSifInitRpc 
+I_sceSifSetRpcQueue 
+I_sceSifRegisterRpc 
+I_sceSifRpcLoop
+sifcmd_IMPORTS_end
Index: ps2launchargs/source/uLaunchELF/hdl_info/irx_imports.h
===================================================================
--- ps2launchargs/source/uLaunchELF/hdl_info/irx_imports.h	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/hdl_info/irx_imports.h	(revision 1101)
@@ -0,0 +1,21 @@
+/*
+ * irx_imports.h - Defines all IRX imports.
+ *
+ * Copyright (c) 2003 Marcus R. Brown <mrbrown@0xd6.org>
+ *
+ * See the file LICENSE included with this distribution for licensing terms.
+ */
+
+#ifndef IOP_IRX_IMPORTS_H
+#define IOP_IRX_IMPORTS_H
+
+#include <irx.h>
+
+/* Please keep these in alphabetical order!  */
+#include <atad.h>
+#include <dev9.h>
+#include <stdio.h>
+#include <sysmem.h>
+#include <sifcmd.h>
+
+#endif /* IOP_IRX_IMPORTS_H */
Index: ps2launchargs/source/uLaunchELF/hdl_info/main.c
===================================================================
--- ps2launchargs/source/uLaunchELF/hdl_info/main.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/hdl_info/main.c	(revision 1101)
@@ -0,0 +1,72 @@
+#include <thbase.h> 
+#include <thevent.h> 
+#include <iomanX.h>
+#include <stdio.h>
+#include <loadcore.h>
+#include <intrman.h>
+#include <sys/stat.h>
+#include <dev9.h>
+#include <sifrpc.h>
+
+#include "ps2_hdd.h"
+#include "hdd.h"
+
+int __attribute__((unused)) shutdown() { return 0; }
+
+/* function declaration */
+void rpcMainThread(void* param);
+void *rpcCommandHandler(int command, void *Data, int Size);
+
+static SifRpcDataQueue_t Rpc_Queue __attribute__((aligned(64)));
+static SifRpcServerData_t Rpc_Server __attribute((aligned(64)));
+static int Rpc_Buffer[1024] __attribute((aligned(64)));
+
+/* Description: Module entry point */
+int _start(int argc, char **argv)
+{
+ iop_thread_t param;
+ int id;
+
+ printf("Hdl Info: PS2 HDLoader Information Module v 0.1\n");
+ printf("Hdl Info: 2006 Polo\n");
+
+ printf("Hdl Info: IOP RPC Initialization.\n"); 
+ /*create thread*/
+ param.attr         = TH_C;
+ param.thread     = rpcMainThread;
+ param.priority = 40;
+ param.stacksize    = 0x800;
+ param.option      = 0;
+
+ id = CreateThread(&param);
+ if (id > 0) {
+  StartThread(id,0);
+  return 0;
+ } else
+  return 1;
+
+ return MODULE_RESIDENT_END;
+}
+
+void rpcMainThread(void* param)
+{
+ SifInitRpc(0);
+ SifSetRpcQueue(&Rpc_Queue, GetThreadId());
+ SifRegisterRpc(&Rpc_Server, HDL_IRX, (void *) rpcCommandHandler, (u8 *) &Rpc_Buffer, 0, 0, &Rpc_Queue);
+ SifRpcLoop(&Rpc_Queue);
+}
+
+void *rpcCommandHandler(int command, void *Data, int Size)
+{
+	switch (command) {
+		case 4: //HDL Get Game Info
+			((int *)Data)[0] = HdlGetGameInfo((char *)Data, (GameInfo *)(Data+4));
+			break;
+  	case 5: //HDL Rename Game
+   		((int *)Data)[0] = HdlRenameGame((char*)Data);
+   		break;
+  	default:
+   		break;
+ }
+ return Data;
+}
Index: ps2launchargs/source/uLaunchELF/hdl_info/ps2_hdd.h
===================================================================
--- ps2launchargs/source/uLaunchELF/hdl_info/ps2_hdd.h	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/hdl_info/ps2_hdd.h	(revision 1101)
@@ -0,0 +1,79 @@
+/*
+ * ps2_hdd.h
+ * $Id: ps2_hdd.h,v 1.5 2005/07/10 21:06:48 bobi Exp $
+ *
+ * borrowed from ps2fdisk
+ */
+
+#ifndef _PS2_HDD_H_
+#define _PS2_HDD_H_
+
+typedef unsigned char  u_char;
+typedef unsigned int   u_int;
+typedef unsigned short u_short;
+typedef unsigned long  u_long;
+
+/* Various PS2 partition constants */
+#define PS2_PARTITION_MAGIC	"APA"	/* "APA\0" */
+#define PS2_PART_IDMAX		32
+#define PS2_PART_NAMEMAX	128
+#define PS2_PART_MAXSUB		64	/* Maximum # of sub-partitions */
+#define PS2_PART_FLAG_SUB	0x0001	/* Is partition a sub-partition? */
+#define PS2_MBR_VERSION		2	/* Current MBR version */
+
+/* Partition types */
+#define PS2_MBR_PARTITION	0x0001
+#define PS2_SWAP_PARTITION	0x0082
+#define PS2_LINUX_PARTITION	0x0083
+#define PS2_GAME_PARTITION	0x0100
+
+/* Date/time descriptor used in on-disk partition header */
+typedef struct ps2fs_datetime_type
+{
+  u_char unused;
+  u_char sec;
+  u_char min;
+  u_char hour;
+  u_char day;
+  u_char month;
+  u_short year;
+} ps2fs_datetime_t;
+
+/* On-disk partition header for a partition */
+typedef struct ps2_partition_header_type
+{
+  u_long checksum;	/* Sum of all 256 words, assuming checksum==0 */
+  u_char magic [4];	/* PS2_PARTITION_MAGIC */
+  u_long next;	/* Sector address of next partition */
+  u_long prev;	/* Sector address of previous partition */
+  char id [PS2_PART_IDMAX];
+  char unknown1 [16];
+  u_long start;	/* Sector address of this partition */
+  u_long length;	/* Sector count */
+  u_short type;
+  u_short flags;	/* PS2_PART_FLAG_* */
+  u_long nsub;	/* No. of sub-partitions (stored in main partition) */
+  ps2fs_datetime_t created;
+  u_long main;	/* For sub-partitions, main partition sector address */
+  u_long number;	/* For sub-partitions, sub-partition number */
+  u_short unknown2;
+  char unknown3 [30];
+  char name [PS2_PART_NAMEMAX];
+  struct
+  {
+    char magic [32];	/* Copyright message in MBR */
+    char unknown_0x02;
+    char unknown1 [7];
+    ps2fs_datetime_t created; /* Same as for the partition, it seems*/
+    u_long data_start;	/* Some sort of MBR data; position in sectors*/
+    u_long data_len;	/* Length also in sectors */
+    char unknown2 [200];
+  } mbr;
+  struct
+  {		/* Sub-partition data */
+    u_long start;/* Sector address */
+    u_long length;/* Sector count */
+  } subs [PS2_PART_MAXSUB];
+} ps2_partition_header_t;
+
+#endif /* _PS2_HDD_H_ */
Index: ps2launchargs/source/uLaunchELF/hdl_rpc.c
===================================================================
--- ps2launchargs/source/uLaunchELF/hdl_rpc.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/hdl_rpc.c	(revision 1101)
@@ -0,0 +1,75 @@
+#include <tamtypes.h>
+#include <kernel.h>
+#include <sifrpc.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "launchelf.h"
+
+static SifRpcClientData_t client __attribute__((aligned(64)));
+static int Rpc_Buffer[1024] __attribute__((aligned(64)));
+
+typedef struct {
+  char Partition_Name [32 + 1];
+} Rpc_Packet_Send_GetInfo;
+
+typedef struct {
+	char OldName[64];
+	char NewName[64];
+} Rpc_Packet_Send_Rename;
+
+int Hdl_Inited = 0;
+
+int Hdl_Info_BindRpc() {                           
+	int ret;
+	int retryCount = 0x1000;
+
+	while(retryCount--) {
+	        ret = SifBindRpc( &client, HDL_IRX, 0);
+        	if ( ret  < 0)  {
+						printf("Hdl Info: EE Bind RPC Error.\n");
+	          return -1;
+	        }
+	        if (client.server != 0){
+	        	printf("Hdl Info: EE Bind RPC Set.\n");
+	        	break;
+	        }
+
+	        // short delay 
+	      	ret = 0x10000;
+	    	while(ret--) asm("nop\nnop\nnop\nnop");
+	}
+
+	Hdl_Inited = 1;
+	return retryCount;
+}
+
+int HdlGetGameInfo(char *PartName, GameInfo *Game){
+
+	Rpc_Packet_Send_GetInfo *Packet = (Rpc_Packet_Send_GetInfo *)Rpc_Buffer;
+
+	if(!Hdl_Inited) return -1;
+
+	strcpy(Packet->Partition_Name, PartName);
+
+	SifCallRpc(&client, HDL_GETINFO, 0, (void*)Rpc_Buffer, sizeof(Rpc_Packet_Send_GetInfo), (void*)Rpc_Buffer, sizeof(GameInfo)+4,0,0);
+
+	memcpy(Game, ((void *)Rpc_Buffer)+4, sizeof(GameInfo));
+
+	return Rpc_Buffer[0];
+}
+
+int HdlRenameGame(char* OldName, char* NewName){
+
+ Rpc_Packet_Send_Rename *Packet = (Rpc_Packet_Send_Rename *)Rpc_Buffer;
+
+ if(!Hdl_Inited) return -1;
+
+ strcpy(Packet->OldName, OldName);
+ strcpy(Packet->NewName, NewName);
+
+ SifCallRpc(&client, HDL_RENAME, 0, (void*)(Rpc_Buffer), sizeof(Rpc_Packet_Send_Rename), (void*)Rpc_Buffer, 4,0,0);
+
+ return Rpc_Buffer[0];
+}
Index: ps2launchargs/source/uLaunchELF/hdl_rpc.h
===================================================================
--- ps2launchargs/source/uLaunchELF/hdl_rpc.h	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/hdl_rpc.h	(revision 1101)
@@ -0,0 +1,28 @@
+#ifndef _HDL_RPC_H
+#define _HDL_RPC_H
+
+#define HDL_IRX 0xD0D0D0D
+
+#define HDL_GETINFO 0x004
+#define HDL_RENAME  0x005
+
+typedef struct {
+  char Partition_Name [32 + 1];
+  char Name [64 + 1];
+  char Startup [8 + 1 + 3 + 1];
+  int  Is_Dvd;
+} GameInfo;
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+int Hdl_Info_BindRpc(void);
+int HdlGetGameInfo(char* PartName, GameInfo *Game);
+int HdlRenameGame(char* OldName, char* NewName);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _HDL_RPC_H */
Index: ps2launchargs/source/uLaunchELF/icon.c
===================================================================
--- ps2launchargs/source/uLaunchELF/icon.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/icon.c	(revision 1101)
@@ -0,0 +1,2055 @@
+
+unsigned char icon_folder[1024] = {
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x1,
+	0x1,
+	0x1,
+	0x2,
+	0x3,
+	0x3,
+	0x2,
+	0x2,
+	0x2,
+	0x2,
+	0x1,
+	0x0,
+	0x1,
+	0x2,
+	0x1,
+	0x0,
+	0x0,
+	0x1,
+	0x1,
+	0x0,
+	0x1,
+	0x2,
+	0x1,
+	0x1,
+	0x2,
+	0x2,
+	0x1,
+	0x2,
+	0x2,
+	0x2,
+	0x1,
+	0x2,
+	0x3,
+	0x3,
+	0x2,
+	0x1,
+	0x2,
+	0x2,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x2,
+	0x0,
+	0x0,
+	0x0,
+	0x3,
+	0x0,
+	0x0,
+	0x0,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x6,
+	0x24,
+	0x4e,
+	0x27,
+	0x25,
+	0x44,
+	0x75,
+	0x3b,
+	0x23,
+	0x42,
+	0x69,
+	0x35,
+	0x0,
+	0xb,
+	0x28,
+	0x14,
+	0x0,
+	0x17,
+	0x4b,
+	0x26,
+	0x0,
+	0x29,
+	0x67,
+	0x34,
+	0x7,
+	0x2a,
+	0x5f,
+	0x30,
+	0x1a,
+	0x35,
+	0x66,
+	0x33,
+	0x29,
+	0x46,
+	0x71,
+	0x39,
+	0x22,
+	0x44,
+	0x69,
+	0x35,
+	0x0,
+	0xa,
+	0x17,
+	0xc,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x38,
+	0x76,
+	0xb7,
+	0x5c,
+	0x9d,
+	0xd7,
+	0xff,
+	0x80,
+	0x96,
+	0xcb,
+	0xff,
+	0x80,
+	0x61,
+	0x93,
+	0xcc,
+	0x66,
+	0x6b,
+	0xa0,
+	0xdd,
+	0x6f,
+	0x7f,
+	0xb8,
+	0xf9,
+	0x7d,
+	0x87,
+	0xc0,
+	0xf7,
+	0x7c,
+	0x96,
+	0xca,
+	0xfd,
+	0x7f,
+	0x9f,
+	0xd8,
+	0xff,
+	0x80,
+	0x6e,
+	0xb4,
+	0xef,
+	0x78,
+	0x1,
+	0x1a,
+	0x36,
+	0x1b,
+	0x1,
+	0x6,
+	0xe,
+	0x7,
+	0x0,
+	0x9,
+	0x17,
+	0xc,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x4b,
+	0x77,
+	0xa7,
+	0x54,
+	0xd3,
+	0xe7,
+	0xf8,
+	0x7c,
+	0xc8,
+	0xdd,
+	0xf8,
+	0x7c,
+	0xcb,
+	0xe9,
+	0xff,
+	0x80,
+	0xc8,
+	0xe5,
+	0xff,
+	0x80,
+	0xc0,
+	0xdf,
+	0xfc,
+	0x7e,
+	0xb7,
+	0xdb,
+	0xfc,
+	0x7e,
+	0xa7,
+	0xd1,
+	0xfa,
+	0x7d,
+	0x99,
+	0xce,
+	0xfb,
+	0x7e,
+	0x65,
+	0xaf,
+	0xe9,
+	0x75,
+	0x8,
+	0x1f,
+	0x3f,
+	0x20,
+	0x0,
+	0x14,
+	0x50,
+	0x28,
+	0x0,
+	0x18,
+	0x40,
+	0x20,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x2d,
+	0x50,
+	0x83,
+	0x42,
+	0xc5,
+	0xde,
+	0xfd,
+	0x7f,
+	0xc0,
+	0xd9,
+	0xf8,
+	0x7c,
+	0xb9,
+	0xd9,
+	0xf9,
+	0x7d,
+	0xb2,
+	0xd6,
+	0xfc,
+	0x7e,
+	0xa3,
+	0xcf,
+	0xfc,
+	0x7e,
+	0x96,
+	0xc9,
+	0xfc,
+	0x7e,
+	0x8b,
+	0xc1,
+	0xfc,
+	0x7e,
+	0x7c,
+	0xbd,
+	0xfe,
+	0x7f,
+	0x5f,
+	0xab,
+	0xef,
+	0x78,
+	0x20,
+	0x65,
+	0xb4,
+	0x5a,
+	0x16,
+	0x63,
+	0xca,
+	0x65,
+	0x6,
+	0x1c,
+	0x3c,
+	0x1e,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x15,
+	0x3c,
+	0x7b,
+	0x3e,
+	0xaa,
+	0xce,
+	0xf9,
+	0x7d,
+	0xbc,
+	0xda,
+	0xfc,
+	0x7e,
+	0x90,
+	0xc5,
+	0xfc,
+	0x7e,
+	0x6d,
+	0xb5,
+	0xfd,
+	0x7f,
+	0x68,
+	0xb2,
+	0xfc,
+	0x7e,
+	0x6b,
+	0xb4,
+	0xfd,
+	0x7f,
+	0x6e,
+	0xb4,
+	0xfd,
+	0x7f,
+	0x6a,
+	0xb4,
+	0xfd,
+	0x7f,
+	0x58,
+	0xa8,
+	0xf5,
+	0x7b,
+	0x2c,
+	0x84,
+	0xdc,
+	0x6e,
+	0x1b,
+	0x65,
+	0xb4,
+	0x5a,
+	0x5,
+	0x10,
+	0x1f,
+	0x10,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0xd,
+	0x23,
+	0x55,
+	0x2b,
+	0x99,
+	0xbc,
+	0xeb,
+	0x76,
+	0x7d,
+	0xb3,
+	0xfd,
+	0x7f,
+	0x20,
+	0x84,
+	0xf8,
+	0x7c,
+	0x2f,
+	0x96,
+	0xfc,
+	0x7e,
+	0x41,
+	0x9e,
+	0xfa,
+	0x7d,
+	0x4e,
+	0xa4,
+	0xfa,
+	0x7d,
+	0x53,
+	0xa5,
+	0xf9,
+	0x7d,
+	0x52,
+	0xa8,
+	0xf9,
+	0x7d,
+	0x42,
+	0x96,
+	0xed,
+	0x77,
+	0x23,
+	0x6c,
+	0xc8,
+	0x64,
+	0xb,
+	0x38,
+	0x6d,
+	0x37,
+	0x0,
+	0x2,
+	0x6,
+	0x3,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x10,
+	0x23,
+	0x5d,
+	0x2f,
+	0x6b,
+	0x99,
+	0xe4,
+	0x72,
+	0x28,
+	0x74,
+	0xf6,
+	0x7b,
+	0x17,
+	0x71,
+	0xf0,
+	0x78,
+	0x30,
+	0x8e,
+	0xf9,
+	0x7d,
+	0x32,
+	0x97,
+	0xfb,
+	0x7e,
+	0x3c,
+	0x9f,
+	0xfe,
+	0x7f,
+	0x3f,
+	0xa4,
+	0xff,
+	0x80,
+	0x37,
+	0x9d,
+	0xff,
+	0x80,
+	0x57,
+	0xa4,
+	0xfa,
+	0x7d,
+	0x4e,
+	0x94,
+	0xe9,
+	0x75,
+	0x1,
+	0x1e,
+	0x46,
+	0x23,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x1,
+	0x2,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x6,
+	0xb,
+	0x1e,
+	0xf,
+	0x2c,
+	0x58,
+	0xaa,
+	0x55,
+	0x20,
+	0x71,
+	0xff,
+	0x80,
+	0x1a,
+	0x6e,
+	0xff,
+	0x80,
+	0x24,
+	0x7f,
+	0xff,
+	0x80,
+	0x29,
+	0x85,
+	0xfb,
+	0x7e,
+	0x28,
+	0x82,
+	0xe8,
+	0x74,
+	0x27,
+	0x7e,
+	0xd8,
+	0x6c,
+	0x1c,
+	0x63,
+	0xbe,
+	0x5f,
+	0x3b,
+	0x6b,
+	0xac,
+	0x56,
+	0x2a,
+	0x53,
+	0x85,
+	0x43,
+	0x0,
+	0x4,
+	0x13,
+	0xa,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x1,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x2,
+	0xe,
+	0x26,
+	0x13,
+	0x11,
+	0x3e,
+	0x95,
+	0x4b,
+	0xc,
+	0x36,
+	0x86,
+	0x43,
+	0xb,
+	0x2e,
+	0x69,
+	0x35,
+	0xb,
+	0x25,
+	0x52,
+	0x29,
+	0x8,
+	0x1b,
+	0x3c,
+	0x1e,
+	0x5,
+	0x13,
+	0x2b,
+	0x16,
+	0x1,
+	0x8,
+	0x18,
+	0xc,
+	0x0,
+	0x0,
+	0x8,
+	0x4,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x1,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x1,
+	0x2,
+	0x0,
+	0x0,
+	0x1,
+	0x2,
+	0x2,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x1,
+	0x1,
+	0x0,
+	0x0,
+	0x1,
+	0x1,
+	0x0,
+	0x0,
+	0x1,
+	0x1,
+	0x0,
+	0x1,
+	0x2,
+	0x1,
+	0x0,
+	0x1,
+	0x3,
+	0x2,
+	0x0,
+	0x1,
+	0x3,
+	0x2,
+	0x0,
+	0x1,
+	0x3,
+	0x2,
+	0x0,
+	0x0,
+	0x2,
+	0x1,
+	0x0,
+	0x0,
+	0x1,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x2,
+	0x1,
+	0x0,
+	0x0,
+	0x1,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+};
+
+
+unsigned char icon_warning[1024] = {
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x1,
+	0x0,
+	0x0,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x2,
+	0x0,
+	0x0,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x1,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x1,
+	0x1,
+	0x0,
+	0x25,
+	0x2f,
+	0x31,
+	0x13,
+	0x0,
+	0x1,
+	0x2,
+	0x0,
+	0x3,
+	0x0,
+	0x0,
+	0x2,
+	0x1,
+	0x1,
+	0x1,
+	0x1,
+	0x3,
+	0x1,
+	0x1,
+	0x2,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x25,
+	0x30,
+	0x30,
+	0x13,
+	0x2,
+	0x6,
+	0x6,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x1,
+	0x0,
+	0x0,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x6,
+	0xc,
+	0xd,
+	0x3,
+	0x5d,
+	0x5c,
+	0x5a,
+	0x2f,
+	0xdb,
+	0xa1,
+	0x8e,
+	0x6e,
+	0x5a,
+	0x40,
+	0x3c,
+	0x2d,
+	0x0,
+	0x3,
+	0x5,
+	0x0,
+	0x7,
+	0x4,
+	0x3,
+	0x4,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x47,
+	0x42,
+	0x41,
+	0x24,
+	0xdb,
+	0x8e,
+	0x86,
+	0x6e,
+	0x6b,
+	0x64,
+	0x61,
+	0x36,
+	0x6,
+	0xa,
+	0xb,
+	0x3,
+	0x2,
+	0x1,
+	0x1,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x42,
+	0x50,
+	0x4f,
+	0x21,
+	0xfc,
+	0x9c,
+	0x8d,
+	0x7e,
+	0xf4,
+	0x19,
+	0xd,
+	0x7a,
+	0xef,
+	0x62,
+	0x47,
+	0x78,
+	0x57,
+	0x4a,
+	0x48,
+	0x2c,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x48,
+	0x47,
+	0x47,
+	0x24,
+	0xd9,
+	0x63,
+	0x57,
+	0x6d,
+	0xd8,
+	0x10,
+	0xc,
+	0x6c,
+	0xe4,
+	0x73,
+	0x69,
+	0x72,
+	0x49,
+	0x51,
+	0x51,
+	0x25,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x3,
+	0x3,
+	0x3,
+	0x2,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x19,
+	0x1b,
+	0x1b,
+	0xd,
+	0x9b,
+	0x60,
+	0x56,
+	0x4e,
+	0xfd,
+	0x3b,
+	0x2c,
+	0x7f,
+	0xec,
+	0x13,
+	0x3,
+	0x76,
+	0xdc,
+	0x52,
+	0x40,
+	0x6e,
+	0x87,
+	0x75,
+	0x72,
+	0x44,
+	0xd0,
+	0x5c,
+	0x4e,
+	0x68,
+	0xd2,
+	0x8,
+	0x4,
+	0x69,
+	0xcf,
+	0x1f,
+	0x18,
+	0x68,
+	0x90,
+	0x4d,
+	0x48,
+	0x48,
+	0x1b,
+	0x1c,
+	0x1c,
+	0xe,
+	0x2,
+	0x0,
+	0x0,
+	0x1,
+	0x1,
+	0x0,
+	0x0,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x4,
+	0x10,
+	0x11,
+	0x2,
+	0x99,
+	0x68,
+	0x5c,
+	0x4d,
+	0xee,
+	0x35,
+	0x24,
+	0x77,
+	0xd6,
+	0x11,
+	0x1,
+	0x6b,
+	0xe6,
+	0x41,
+	0x29,
+	0x73,
+	0xce,
+	0x11,
+	0x2,
+	0x67,
+	0xce,
+	0x1a,
+	0x11,
+	0x67,
+	0x95,
+	0x58,
+	0x54,
+	0x4b,
+	0x8,
+	0xf,
+	0xf,
+	0x4,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x4,
+	0x4,
+	0x4,
+	0x2,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x2,
+	0x14,
+	0x17,
+	0x1,
+	0xa4,
+	0x73,
+	0x69,
+	0x52,
+	0xe4,
+	0x2e,
+	0x1e,
+	0x72,
+	0xbd,
+	0x5,
+	0x0,
+	0x5f,
+	0xce,
+	0x1a,
+	0x8,
+	0x67,
+	0xac,
+	0x6d,
+	0x68,
+	0x56,
+	0x0,
+	0x9,
+	0x9,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x2,
+	0x1,
+	0x1,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x2,
+	0x0,
+	0x0,
+	0x1,
+	0x0,
+	0x1,
+	0x2,
+	0x0,
+	0x44,
+	0x43,
+	0x42,
+	0x22,
+	0xcb,
+	0x5f,
+	0x55,
+	0x66,
+	0xce,
+	0x12,
+	0x3,
+	0x67,
+	0xc9,
+	0x12,
+	0x8,
+	0x65,
+	0xbf,
+	0x9,
+	0x0,
+	0x60,
+	0xbc,
+	0x47,
+	0x43,
+	0x5e,
+	0x48,
+	0x40,
+	0x40,
+	0x24,
+	0x0,
+	0x5,
+	0x5,
+	0x0,
+	0x1,
+	0x0,
+	0x0,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x1,
+	0x4,
+	0x4,
+	0x1,
+	0x40,
+	0x3a,
+	0x39,
+	0x20,
+	0xdd,
+	0x6b,
+	0x5e,
+	0x6f,
+	0xd3,
+	0x4,
+	0x0,
+	0x6a,
+	0xc9,
+	0x1e,
+	0x16,
+	0x65,
+	0xbb,
+	0x62,
+	0x58,
+	0x5e,
+	0xc1,
+	0x25,
+	0x22,
+	0x61,
+	0xb2,
+	0x0,
+	0x0,
+	0x59,
+	0xbf,
+	0x4a,
+	0x48,
+	0x60,
+	0x46,
+	0x3d,
+	0x3c,
+	0x23,
+	0x1,
+	0x2,
+	0x2,
+	0x1,
+	0x1,
+	0x1,
+	0x1,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x3e,
+	0x49,
+	0x48,
+	0x1f,
+	0xe4,
+	0x82,
+	0x7a,
+	0x72,
+	0xc6,
+	0x0,
+	0x0,
+	0x63,
+	0xd5,
+	0x29,
+	0x1e,
+	0x6b,
+	0x8c,
+	0x4d,
+	0x49,
+	0x46,
+	0x20,
+	0x33,
+	0x35,
+	0x10,
+	0x82,
+	0x57,
+	0x55,
+	0x41,
+	0xbd,
+	0x25,
+	0x25,
+	0x5f,
+	0x99,
+	0x0,
+	0x0,
+	0x4d,
+	0xbd,
+	0x58,
+	0x56,
+	0x5f,
+	0x3f,
+	0x46,
+	0x46,
+	0x20,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x3,
+	0x2,
+	0x2,
+	0x2,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x26,
+	0x2b,
+	0x2a,
+	0x13,
+	0xa8,
+	0x7c,
+	0x79,
+	0x54,
+	0xed,
+	0x5f,
+	0x5c,
+	0x77,
+	0x8e,
+	0x4a,
+	0x45,
+	0x47,
+	0xf,
+	0x15,
+	0x16,
+	0x8,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0xc,
+	0x15,
+	0x15,
+	0x6,
+	0x7c,
+	0x53,
+	0x53,
+	0x3e,
+	0xc7,
+	0x54,
+	0x53,
+	0x64,
+	0x98,
+	0x6a,
+	0x69,
+	0x4c,
+	0x27,
+	0x2a,
+	0x2a,
+	0x14,
+	0x2,
+	0x1,
+	0x1,
+	0x1,
+	0x1,
+	0x1,
+	0x1,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x18,
+	0x22,
+	0x22,
+	0xc,
+	0x6a,
+	0x63,
+	0x61,
+	0x35,
+	0xb,
+	0xe,
+	0xe,
+	0x6,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x4,
+	0x3,
+	0x3,
+	0x2,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0xc,
+	0x11,
+	0x11,
+	0x6,
+	0x63,
+	0x5b,
+	0x5b,
+	0x32,
+	0x19,
+	0x22,
+	0x22,
+	0xd,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x1,
+	0x0,
+	0x0,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x1,
+	0x1,
+	0x1,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x1,
+	0x1,
+	0x1,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x1,
+	0x1,
+	0x1,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x1,
+	0x1,
+	0x1,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x1,
+	0x1,
+	0x1,
+	0x1,
+	0x4,
+	0x0,
+	0x0,
+	0x2,
+	0x2,
+	0x0,
+	0x0,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x1,
+	0x1,
+	0x1,
+	0x1,
+	0x3,
+	0x0,
+	0x0,
+	0x2,
+	0x2,
+	0x2,
+	0x2,
+	0x1,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+};
Index: ps2launchargs/source/uLaunchELF/iopmod_name.h
===================================================================
--- ps2launchargs/source/uLaunchELF/iopmod_name.h	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/iopmod_name.h	(revision 1101)
@@ -0,0 +1,69 @@
+//--------------------------------------------------------------
+//File name:   iopmod_name.h           Revision Date: 2005.06.14
+//Created by:  Ronald Andersson        Creation Date: 2005.06.14
+//Purpose:     Define names of PS2 IOP modules and libraries
+//--------------------------------------------------------------
+#ifndef _IOPMOD_NAME_
+#define _IOPMOD_NAME_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//#define IOPMOD_NAME_        ""
+#define	IOPMOD_NAME_ATAD      "atad"
+#define	IOPMOD_NAME_CDVDMAN   "cdvd_driver"
+#define	IOPMOD_NAME_DEV9      "dev9"
+#define	IOPMOD_NAME_FAKEHOST  "fakehost"
+#define	IOPMOD_NAME_FILEIO    "FILEIO_service"
+#define	IOPMOD_NAME_FILEXIO   "IOX/File_Manager_Rpc"
+#define	IOPMOD_NAME_FREESD    "freesd"
+#define	IOPMOD_NAME_HDD       "hdd"
+#define	IOPMOD_NAME_ILINK     "iLINK_Driver"
+#define IOPMOD_NAME_IOMAN     "IO/File_Manager"
+#define IOPMOD_NAME_IOMANX    "IOX/File_Manager"
+#define IOPMOD_NAME_IOPMGR    "IOP_Manager"
+#define	IOPMOD_NAME_LIBSD     "Sound_Device_Library"
+#define IOPMOD_NAME_LOADFILE  "LoadModuleByEE"
+#define	IOPMOD_NAME_MCMAN     "mcman"
+#define	IOPMOD_NAME_MCSERV    "mcserv"
+#define IOPMOD_NAME_MODLOAD   "Moldule_File_loader" //NB: spelling error is in ROM!
+#define	IOPMOD_NAME_PADMAN    "padman"
+#define	IOPMOD_NAME_PFS       "pfs"
+#define	IOPMOD_NAME_POWEROFF  "Poweroff_Handler"
+#define	IOPMOD_NAME_PS2NETFS  "PS2_TcpFileDriver"
+#define	IOPMOD_NAME_PS2ATAD   "atad_driver"
+#define IOPMOD_NAME_PS2DEV9   "dev9_driver"
+#define	IOPMOD_NAME_PS2FS     "pfs_driver"
+#define	IOPMOD_NAME_PS2HDD    "hdd_driver"
+#define	IOPMOD_NAME_PS2IP     "TCP/IP Stack"
+#define	IOPMOD_NAME_SIO2MAN   "sio2man"
+#define	IOPMOD_NAME_SMAP      "INET_SMAP_driver"
+#define IOPMOD_NAME_THREADMAN "Multi_Thread_Manager"
+#define	IOPMOD_NAME_USBD      "USB_driver"
+#define IOPMOD_NAME_XLOADFILE "LoadModuleByEE" //NB: same name as for LOADFILE
+#define IOPMOD_NAME_XMCMAN    "mcman_cex"
+#define IOPMOD_NAME_XMCSERV   "mcserv" //NB: same name as for MCSERV
+
+//NB: some modules exist with conflicting names, and even no name at all...
+//This includes USBD, PS2IP, PS2SMAP, PS2FTPD, PS2HOST, and probably others
+//Some alternate names are defined below
+//#define IOPMOD_NAM2_        ""
+#define	IOPMOD_NAM2_USBD      "usbd"
+
+//Some modules also register as runtime libraries, with library names that
+//are independent of the module name. Libraries for same purpose may often
+//have the same library name even though they have different module names,
+//while some libraries don't even have any module name...
+//#define IOPLIB_NAME_        ""
+#define IOPLIB_NAME_IOPMGR    "iopmgr"
+#define IOPLIB_NAME_MODLOAD   "modload"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _IOPMOD_NAME_
+//--------------------------------------------------------------
+//End of file: iopmod_name.h
+//--------------------------------------------------------------
Index: ps2launchargs/source/uLaunchELF/jpgviewer.c
===================================================================
--- ps2launchargs/source/uLaunchELF/jpgviewer.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/jpgviewer.c	(revision 1101)
@@ -0,0 +1,910 @@
+//--------------------------------------------------------------
+//File name:   jpgviewer.c
+//--------------------------------------------------------------
+#include "launchelf.h"
+
+static char	 msg0[MAX_PATH], msg1[MAX_PATH], jpgpath[MAX_PATH];
+static int   SlideShowTime=5, SlideShowTrans=2, SlideShowBegin, SlideShowStart, SlideShowStop, SlideShowSkip;
+static int	 Brightness, TimeRemain, PrintLen;
+static float PanPosX, PanPosY, PanPosX1, PanPosY1;
+static float PanZoom, PanOffsetX, PanOffsetY;
+float    		 PicW, PicH, PicCoeff;
+float    		 PicWidth, PicHeight;
+int					 PicRotate, FullScreen;
+
+#define OFF        1
+#define ZOOM       2
+#define FADE       3
+#define ZOOM_FADE  4
+
+#define LIST       1
+#define THUMBNAIL  2
+
+#define NOTLOADED -1
+#define BADJPG  	 0
+#define LOADED  	 1
+
+//--------------------------------------------------------------
+static void Command_List( void )
+{
+	int x, y;
+	int event, post_event=0;
+	
+	int command_len=strlen(LNG(Start_StartStop_Slideshow))>strlen(LNG(Start_StartStop_Slideshow))?
+		strlen(LNG(Start_StartStop_Slideshow)):strlen(LNG(Start_StartStop_Slideshow));
+	command_len=strlen(LNG(L1R1_Slideshow_Timer))>command_len?
+		strlen(LNG(L1R1_Slideshow_Timer)):command_len;
+	command_len=strlen(LNG(L2R2_Slideshow_Transition))>command_len?
+		strlen(LNG(L2R2_Slideshow_Transition)):command_len;
+	command_len=strlen(LNG(LeftRight_Pad_PrevNext_Picture))>command_len?
+		strlen(LNG(LeftRight_Pad_PrevNext_Picture)):command_len;
+	command_len=strlen(LNG(UpDown_Pad_Rotate_Picture))>command_len?
+		strlen(LNG(UpDown_Pad_Rotate_Picture)):command_len;
+	command_len=strlen(LNG(Left_Joystick_Panorama))>command_len?
+		strlen(LNG(Left_Joystick_Panorama)):command_len;
+	command_len=strlen(LNG(Right_Joystick_Vertical_Zoom))>command_len?
+		strlen(LNG(Right_Joystick_Vertical_Zoom)):command_len;
+	command_len=strlen(LNG(FullScreen_Mode))+3>command_len?
+		strlen(LNG(FullScreen_Mode))+3:command_len;
+	command_len=strlen(LNG(Exit_To_Jpg_Browser))+3>command_len?
+		strlen(LNG(Exit_To_Jpg_Browser))+3:command_len;
+
+	int Command_ch_w = command_len+1; //Total characters in longest Command Name.
+	int Command_ch_h = 9;             //Total Command lines number.
+	int cSprite_Y1 = SCREEN_HEIGHT/2-((Command_ch_h+1)*FONT_HEIGHT)/2; //Top edge
+	int cSprite_X2 = SCREEN_WIDTH/2+((Command_ch_w+3)*FONT_WIDTH)/2;   //Right edge
+	int cSprite_X1 = cSprite_X2-(Command_ch_w+3)*FONT_WIDTH-4;         //Left edge
+	int cSprite_Y2 = cSprite_Y1+(Command_ch_h+1)*FONT_HEIGHT;          //Bottom edge
+	
+	char tmp[MAX_PATH];
+
+	event = 1;  //event = initial entry.
+	while(1){
+		//Pad response section.
+		waitPadReady(0, 0);
+		if(readpad()){
+			if(new_pad){
+				event |= 2;  //event |= valid pad command.
+				break;
+			}
+		}
+
+		if(event||post_event){ //NB: We need to update two frame buffers per event.
+
+			//Display section.
+			drawOpSprite(setting->color[0], cSprite_X1, cSprite_Y1, cSprite_X2, cSprite_Y2);
+			drawFrame(cSprite_X1, cSprite_Y1, cSprite_X2, cSprite_Y2, setting->color[1]);
+
+			y=cSprite_Y1+FONT_HEIGHT/2;
+			x=cSprite_X1+2*FONT_WIDTH;
+
+			printXY(LNG(Start_StartStop_Slideshow), x, y, setting->color[3], TRUE, 0);
+			y+=FONT_HEIGHT;
+			printXY(LNG(L1R1_Slideshow_Timer), x, y, setting->color[3], TRUE, 0);
+			y+=FONT_HEIGHT;
+			printXY(LNG(L2R2_Slideshow_Transition), x, y, setting->color[3], TRUE, 0);
+			y+=FONT_HEIGHT;
+			printXY(LNG(LeftRight_Pad_PrevNext_Picture), x, y, setting->color[3], TRUE, 0);
+			y+=FONT_HEIGHT;
+			printXY(LNG(UpDown_Pad_Rotate_Picture), x, y, setting->color[3], TRUE, 0);
+			y+=FONT_HEIGHT;
+			printXY(LNG(Left_Joystick_Panorama), x, y, setting->color[3], TRUE, 0);
+			y+=FONT_HEIGHT;
+			printXY(LNG(Right_Joystick_Vertical_Zoom), x, y, setting->color[3], TRUE, 0);
+			y+=FONT_HEIGHT;
+			if (swapKeys)
+				sprintf(tmp, "ÿ1: %s", LNG(FullScreen_Mode));
+			else
+				sprintf(tmp, "ÿ0: %s", LNG(FullScreen_Mode));
+			printXY(tmp, x, y, setting->color[3], TRUE, 0);
+			y+=FONT_HEIGHT;
+			sprintf(tmp, "ÿ3: %s", LNG(Exit_To_Jpg_Browser));
+			printXY(tmp, x, y, setting->color[3], TRUE, 0);
+			y+=FONT_HEIGHT;
+
+		}//ends if(event||post_event).
+		drawScr();
+		post_event = event;
+		event = 0;
+	}//ends while.
+}//ends Command_List.
+//--------------------------------------------------------------
+static void View_Render( void ) {
+
+	char *name, tmp[MAX_PATH];
+
+	float ScreenPosX, ScreenPosX1, ScreenPosY, ScreenPosY1;
+	float ScreenOffsetX, ScreenOffsetY;
+	float TmpPosX, TmpPosY;
+
+	// Init picture position on screen
+	if(FullScreen){
+		ScreenPosX =0.0f;
+		ScreenPosX1=SCREEN_WIDTH;
+		ScreenPosY =0.0f;
+		ScreenPosY1=SCREEN_HEIGHT;
+	}else{
+		ScreenPosX =SCREEN_MARGIN;
+		ScreenPosX1=SCREEN_WIDTH-SCREEN_MARGIN;
+		ScreenPosY =Frame_start_y;
+		ScreenPosY1=Frame_end_y;
+	}
+
+	// Init black bars
+	if((ScreenOffsetX=((ScreenPosX1-ScreenPosX)-((ScreenPosY1-ScreenPosY)*PicCoeff))/2)<=0.0f)
+		ScreenOffsetX=0.0f;
+	if((ScreenOffsetY=((ScreenPosY1-ScreenPosY)-((ScreenPosX1-ScreenPosX)/PicCoeff))/2)<=0.0f)
+		ScreenOffsetY=0.0f;
+
+	// Init panorama
+	PanPosX=0.0f;
+	PanPosY=0.0f;
+	PanPosX1=PicWidth;
+	PanPosY1=PicHeight;
+	if(PanZoom==1.0f){
+		PanOffsetX=0.0f;
+		PanOffsetY=0.0f;
+	}else{
+		PanPosX=TmpPosX=((PicWidth/8)-((1.5f-PanZoom)*(PicWidth/4)));
+		if((PanPosX+=PanOffsetX*TmpPosX)<=0.0f)
+			PanPosX=0.0f;
+		if((PanPosX1=PicWidth-(TmpPosX*2-PanPosX))>=PicWidth)
+			PanPosX1=PicWidth;
+		PanPosY=TmpPosY=((PicHeight/8)-((1.5f-PanZoom)*(PicHeight/4)));
+		if((PanPosY+=PanOffsetY*TmpPosY)<=0.0f)
+			PanPosY=0.0f;
+		if((PanPosY1=PicHeight-(TmpPosY*2-PanPosY))>=PicHeight)
+			PanPosY1=PicHeight;
+	}
+
+	// Clear screen
+	clrScr(setting->color[0]);
+
+	// Draw color8 graph4
+	gsKit_prim_sprite(gsGlobal, ScreenPosX, ScreenPosY, ScreenPosX1, ScreenPosY1, 0, setting->color[7]);
+	// Draw picture
+	if(PicRotate==0 || PicRotate==1 ||PicRotate==3){ // No rotation, rotate +90°, -90°
+	 gsKit_prim_sprite_texture(gsGlobal,
+		 &TexPicture,
+		 ScreenPosX+ScreenOffsetX, ScreenPosY+ScreenOffsetY, PanPosX, PanPosY,
+		 ScreenPosX1-ScreenOffsetX, ScreenPosY1-ScreenOffsetY, PanPosX1, PanPosY1,
+		 0, GS_SETREG_RGBAQ(Brightness*1.28f, Brightness*1.28f, Brightness*1.28f, 0x80, 0x00));
+	}else if(PicRotate==2){ // Rotate 180°
+	 gsKit_prim_sprite_texture(gsGlobal,
+		 &TexPicture,
+		 ScreenPosX+ScreenOffsetX, ScreenPosY+ScreenOffsetY, PanPosX1, PanPosY1,
+		 ScreenPosX1-ScreenOffsetX, ScreenPosY1-ScreenOffsetY, PanPosX, PanPosY,
+		 0, GS_SETREG_RGBAQ(Brightness*1.28f, Brightness*1.28f, Brightness*1.28f, 0x80, 0x00));
+	}
+	setBrightness(50);
+
+	if(!FullScreen){
+		//Tooltip section
+		strcpy(tmp, jpgpath);
+		name=strrchr(tmp, '/');
+		strcpy(name, name+1);
+		msg0[0]='\0';
+		sprintf(msg0, "%s  %s: %s  %s: %d*%d ",
+			LNG(Jpg_Viewer), LNG(Picture), name, LNG(Size), (int)PicW, (int)PicH);
+		msg1[0]='\0';
+		sprintf(msg1, "Select: %s  ", LNG(Command_List));
+		tmp[0]='\0';
+		if(TimeRemain<60)
+			sprintf(tmp, "%s: %d sec  %s: ", LNG(Timer), TimeRemain, LNG(Transition));
+		else
+			sprintf(tmp, "%s: %d m %d sec  %s: ", LNG(Timer), TimeRemain/60, TimeRemain%60, LNG(Transition));
+		strcat(msg1, tmp);
+		if(SlideShowTrans==OFF)
+			strcat(msg1, LNG(Off));
+		else if(SlideShowTrans==ZOOM)
+			strcat(msg1, LNG(Zoom));
+		else if(SlideShowTrans==FADE)
+			strcat(msg1, LNG(Fade));
+		else if(SlideShowTrans==ZOOM_FADE)
+			strcat(msg1, LNG(ZoomFade));
+		setScrTmp(msg0, msg1);
+	} /* end FullScreen */
+	drawScr();
+} /* end View_Render */
+
+//--------------------------------------------------------------
+static void View_Input( void ) {
+
+	int i=0;
+	u64 OldTime=Timer()+1000;
+
+	while(1){
+
+		if(SlideShowStart){
+			if(Timer()>=OldTime){
+				OldTime=Timer()+1000;
+				if(--TimeRemain<=0)
+					break;
+				View_Render();
+			}
+		}else{
+			if(Timer()>=OldTime){
+				OldTime=Timer()+1000;
+				TimeRemain=SlideShowTime;
+				View_Render();
+			}
+		}
+
+		//Pad response section
+		waitPadReady(0, 0);
+		if(readpad()){
+			if(new_pad & PAD_R3_V0){ // PanZoom In
+				if( PanZoom < 2.75f ) {
+					PanZoom += 0.01f*joy_value/32;
+					SlideShowStart=0;
+					View_Render();
+				} /* end if */
+			}else if(new_pad & PAD_R3_V1){ // PanZoom Out
+				if( PanZoom > 1.0f ) {
+					PanZoom -= 0.01f*joy_value/32;
+					SlideShowStart=0;
+					View_Render();
+				} /* end if */
+			}else if(new_pad & PAD_L3_H1){ // Move Right
+				if ( PanOffsetX < 0.95f ) {
+					PanOffsetX += 0.05f/PanZoom*joy_value/32;
+					SlideShowStart=0;
+					View_Render();
+				} /* end if */
+			}else if(new_pad & PAD_L3_H0){ // Move Left
+				if ( PanOffsetX > -0.95f ) {
+					PanOffsetX -= 0.05f/PanZoom*joy_value/32;
+					SlideShowStart=0;
+					View_Render();
+				} /* end if */
+			}else if(new_pad & PAD_L3_V1){ // Move Down
+				if ( PanOffsetY < 0.95f ) {
+					PanOffsetY += 0.05f/PanZoom*joy_value/32;
+					SlideShowStart=0;
+					View_Render();
+				} /* end if */
+			}else if(new_pad & PAD_L3_V0){ // Move Up
+				if ( PanOffsetY > -0.95f ) {
+					PanOffsetY -= 0.05f/PanZoom*joy_value/32;
+					SlideShowStart=0;
+					View_Render();
+				} /* end if */
+			}else if(new_pad & PAD_RIGHT){ // Next Pic
+				SlideShowSkip=1;
+				break;
+			}else if(new_pad & PAD_LEFT){ // Prev Pic
+				SlideShowSkip=-1;
+				break;
+			}else if(new_pad & PAD_UP){ // Rotate Pic +
+		    if(PanZoom!=1.0f){
+		    	for ( i = 0; i < 35; ++i ) {
+						if (  ( PanZoom -= 0.05F ) <= 1.0F  ) PanZoom = 1.0F;
+						View_Render();
+					} /* end for */
+				} /* end if */
+				if(++PicRotate>=4) PicRotate=0;
+				loadSkin( JPG_PIC, jpgpath, 0 );
+				WaitTime=Timer();
+				while(Timer()<WaitTime+500); // Wait To Ensure Switch
+				View_Render();
+				TimeRemain=SlideShowTime;
+			}else if(new_pad & PAD_DOWN){ // Rotate Pic -
+		    if(PanZoom!=1.0f){
+		    	for ( i = 0; i < 35; ++i ) {
+						if (  ( PanZoom -= 0.05F ) <= 1.0F  ) PanZoom = 1.0F;
+						View_Render();
+					} /* end for */
+				} /* end if */
+				if(--PicRotate<=-1) PicRotate=3;
+				loadSkin( JPG_PIC, jpgpath, 0 );
+				WaitTime=Timer();
+				while(Timer()<WaitTime+500); // Wait To Ensure Switch
+				View_Render();
+				TimeRemain=SlideShowTime;
+			}else if(new_pad & PAD_R1){
+				if(++SlideShowTime>=3600) SlideShowTime=3600;
+				WaitTime=Timer();
+				while(Timer()<WaitTime+100); // Wait To Ensure Switch
+				if(++TimeRemain>=3600) TimeRemain=3600;
+				View_Render();
+			}else if(new_pad & PAD_L1){
+				if(--SlideShowTime<=1) SlideShowTime=1;
+				WaitTime=Timer();
+				while(Timer()<WaitTime+100); // Wait To Ensure Switch
+				if(--TimeRemain<=1) TimeRemain=1;
+				View_Render();
+			}else if(new_pad & PAD_R2){
+				if(++SlideShowTrans>4) SlideShowTrans=1;
+				WaitTime=Timer();
+				while(Timer()<WaitTime+500); // Wait To Ensure Switch
+				View_Render();
+			}else if(new_pad & PAD_L2){
+				if(--SlideShowTrans<1) SlideShowTrans=4;
+				WaitTime=Timer();
+				while(Timer()<WaitTime+500); // Wait To Ensure Switch
+				View_Render();
+			}else if(new_pad & PAD_TRIANGLE){ // Stop SlideShow
+				SlideShowStop=1;
+				break;
+			}else if(new_pad & PAD_START){ // Play/Pause SlideShow
+		    if(PanZoom!=1.0f){
+		    	for ( i = 0; i < 35; ++i ) {
+						if (  ( PanZoom -= 0.05F ) <= 1.0F  ) PanZoom = 1.0F;
+						View_Render();
+					} /* end for */
+				} /* end if */
+				SlideShowStart=!SlideShowStart;
+				WaitTime=Timer();
+				while(Timer()<WaitTime+500); // Wait To Ensure Switch
+				TimeRemain=SlideShowTime;
+				View_Render();
+			}else if(new_pad & PAD_SELECT){ // Command List
+				Command_List();
+				View_Render();
+				WaitTime=Timer();
+				while(Timer()<WaitTime+500); // Wait To Ensure Switch
+				OldTime=Timer()+1000;
+			}else if((swapKeys && new_pad & PAD_CROSS)
+			     || (!swapKeys && new_pad & PAD_CIRCLE) ){ // Full Screen
+		    if(PanZoom!=1.0f){
+		    	for ( i = 0; i < 35; ++i ) {
+						if (  ( PanZoom -= 0.05F ) <= 1.0F  ) PanZoom = 1.0F;
+						View_Render();
+					} /* end for */
+				} /* end if */
+				FullScreen=!FullScreen;
+				if(FullScreen){
+					loadSkin( JPG_PIC, jpgpath, 0 );
+				}else{
+					loadSkin(BACKGROUND_PIC, 0, 0);
+					loadSkin( JPG_PIC, jpgpath, 0 );
+				}
+				WaitTime=Timer();
+				while(Timer()<WaitTime+500); // Wait To Ensure Switch
+				View_Render();
+			} /* end else */
+		}//ends pad response section
+	}//ends while
+} /* end View_Input */
+
+//--------------------------------------------------------------
+static void loadPic(void)
+{
+	int i=0;
+
+	loadSkin( JPG_PIC, jpgpath, 0 );
+
+	Brightness = 0;
+	PanZoom    = 3.0f;
+	PanOffsetX = 0.0f;
+	PanOffsetY = 0.0f;
+  
+	if(testjpg){
+		switch ( SlideShowTrans ) {
+			case OFF  : {
+				View_Render();
+			} break;
+			case ZOOM : {
+				Brightness = 100;
+		    for ( i = 0; i < 100; ++i ) {
+					if (  ( PanZoom -= 0.02F ) <= 1.0F  ) PanZoom = 1.0F;
+					View_Render();
+				} /* end for */
+			} break;
+			case FADE : {
+				PanZoom = 1.0f;
+				for ( i = 0; i < 100; ++i ) {
+					++Brightness;
+					View_Render();
+				} /* end for */
+			} break;
+			case ZOOM_FADE : {
+				for ( i = 0; i < 100; ++i ) {
+					if (  ( PanZoom -= 0.02F ) <= 1.0F  ) PanZoom = 1.0F;
+					++Brightness;
+					View_Render();
+				} /* end for */
+			} break;
+		}  /* end switch */
+
+		Brightness = 100;
+		PanZoom    = 1.0f;
+		PanOffsetX = 0.0f;
+		PanOffsetY = 0.0f;
+		TimeRemain = SlideShowTime;
+
+		View_Render();
+		View_Input();
+
+		switch ( SlideShowTrans ) {
+			case OFF  : {
+				View_Render();
+			} break;
+			case ZOOM : {
+		    for ( i = 0; i < 100; ++i ) {
+					if (  ( PanZoom += 0.02F ) >= 3.0F  ) PanZoom = 3.0F;
+					View_Render();
+				} /* end for */
+			} break;
+			case FADE : {
+				for ( i = 0; i < 100; ++i ) {
+					--Brightness;
+					View_Render();
+				} /* end for */
+			} break;
+			case ZOOM_FADE : {
+				for ( i = 0; i < 100; ++i ) {
+					if (  ( PanZoom += 0.02F ) >= 3.0F  ) PanZoom = 3.0F;
+					--Brightness;
+					View_Render();
+				} /* end for */
+			} break;
+		}  /* end switch */
+	} /* end testjpg */
+} /* end loadPic */
+
+//--------------------------------------------------------------
+void JpgViewer( void )
+{
+	char path[MAX_PATH],
+		cursorEntry[MAX_PATH], ext[8],
+		tmp[MAX_PATH], tmp1[MAX_PATH], *p;
+	u64 color;
+	FILEINFO files[MAX_ENTRY];
+	int thumb_test[MAX_ENTRY];
+	int	jpg_browser_cd, jpg_browser_up, jpg_browser_repos, jpg_browser_pushed;
+	int thumb_load;
+	int	jpg_browser_sel, jpg_browser_nfiles, old_jpg_browser_sel;
+	int top=0, test_top=0, rows=0, rows_down=0;
+	int x=0, y=0, y0=0, y1=0;
+	int thumb_num=0, thumb_top=0;
+	int jpg_browser_mode=LIST;
+	int print_name=0;
+	int Len=0;
+	int event, post_event=0;
+	int i, t=0;
+	int CountJpg=0;
+
+	jpg_browser_cd=TRUE;
+	jpg_browser_up=FALSE;
+	jpg_browser_repos=FALSE;
+	jpg_browser_pushed=TRUE;
+	thumb_load=TRUE;
+	jpg_browser_sel=0;
+	jpg_browser_nfiles=0;
+	old_jpg_browser_sel=0;
+
+	SlideShowTime = setting->JpgView_Timer;
+	SlideShowTrans = setting->JpgView_Trans;
+	FullScreen = setting->JpgView_Full;
+	SlideShowBegin=SlideShowStart=SlideShowStop=SlideShowSkip=0;
+	PicRotate=PrintLen=0;
+
+	for(i=0;i<MAX_ENTRY;++i)
+		thumb_test[i]=NOTLOADED;
+
+	strcpy(ext, "jpg");
+
+	mountedParty[0][0]=0;
+	mountedParty[1][0]=0;
+
+	path[0]='\0';
+	jpgpath[0]='\0';
+
+	if(jpg_browser_mode==LIST){
+		rows = (Menu_end_y-Menu_start_y)/FONT_HEIGHT;
+	}else{
+		if(TV_mode == TV_mode_NTSC)
+			rows=4;
+		else if(TV_mode == TV_mode_PAL)
+			rows=5;
+	}
+
+	loadIcon();
+
+	event = 1;  //event = initial entry
+	while(1){
+
+		//Pad response section
+		waitPadReady(0, 0);
+		if(readpad()){
+			if(new_pad){
+				jpg_browser_pushed=TRUE;
+				print_name=0;
+				event |= 2;  //event |= pad command
+				tmp[0]=0;
+				tmp1[0]=0;
+				t=0;
+			}
+			if(new_pad & PAD_UP)
+				jpg_browser_sel--;
+			else if(new_pad & PAD_DOWN)
+				jpg_browser_sel++;
+			else if(new_pad & PAD_LEFT)
+				jpg_browser_sel-=rows-1;
+			else if(new_pad & PAD_RIGHT){
+				rows_down=1;
+				old_jpg_browser_sel=jpg_browser_sel+rows-1;
+				jpg_browser_sel++;
+			}else if(new_pad & PAD_TRIANGLE){
+				jpg_browser_up=TRUE;
+				thumb_load=TRUE;
+			}else if(new_pad & PAD_SQUARE){
+				if(jpg_browser_mode==LIST){
+					jpg_browser_mode=THUMBNAIL;
+					jpg_browser_sel=0;
+					thumb_load=TRUE;
+				}else
+					jpg_browser_mode=LIST;
+			}else if(new_pad & PAD_R1){
+				if(++SlideShowTime>=300) SlideShowTime=300;
+			}else if(new_pad & PAD_L1){
+				if(--SlideShowTime<=1) SlideShowTime=1;
+			}else if(new_pad & PAD_R2){
+				char *temp = PathPad_menu(path);
+
+				if(temp != NULL){
+					strcpy(path, temp);
+					jpg_browser_cd=TRUE;
+					thumb_load=TRUE;
+				}
+			}else if(new_pad & PAD_L2){
+				if(--SlideShowTrans<1) SlideShowTrans=4;
+			}else if((swapKeys && new_pad & PAD_CROSS)
+			     || (!swapKeys && new_pad & PAD_CIRCLE) ){ //Pushed OK
+				if(files[jpg_browser_sel].stats.attrFile & MC_ATTR_SUBDIR){
+					//pushed OK for a folder
+					thumb_load=TRUE;
+					if(!strcmp(files[jpg_browser_sel].name,"..")){
+						jpg_browser_up=TRUE;
+					}else {
+						strcat(path, files[jpg_browser_sel].name);
+						strcat(path, "/");
+						jpg_browser_cd=TRUE;
+					}
+				}else{
+					//pushed OK for a file
+restart:
+					sprintf(jpgpath, "%s%s", path, files[jpg_browser_sel].name);
+
+					SlideShowBegin=1;
+
+					if(!SlideShowStart)
+						goto single;
+repeat:
+					for(i=0;i<jpg_browser_nfiles;++i){
+						if(SlideShowBegin){
+							i=jpg_browser_sel+1;
+							SlideShowBegin=0;
+						}
+						sprintf(jpgpath, "%s%s", path, files[i].name);
+						loadPic();
+						PicRotate=0;
+						if(testjpg) ++CountJpg;
+						if(SlideShowSkip==1)
+							SlideShowSkip=0;
+						else if(SlideShowSkip==-1){
+							i-=2;                      //Loop index back to JPG before previous
+							if(i<=0)
+								i += jpg_browser_nfiles-1; //Loop index back to JPG before final
+							SlideShowSkip=0;
+						}
+						if(SlideShowStop)
+							goto end;
+					} /* end for */
+					goto end;
+single:
+					loadPic();
+					PicRotate=0;
+					if(testjpg) ++CountJpg;
+					if(SlideShowSkip==1 || !testjpg){
+						if(++jpg_browser_sel>jpg_browser_nfiles) jpg_browser_sel=0;
+						SlideShowSkip=0;
+						goto restart;
+					}else if(SlideShowSkip==-1){
+						jpg_browser_sel-=1;
+							if(jpg_browser_sel<=0)
+								jpg_browser_sel += jpg_browser_nfiles-1; //Go back to final JPG
+						SlideShowSkip=0;
+						goto restart;
+					}
+end:
+					if(SlideShowStart && !SlideShowStop && CountJpg>0)
+						goto repeat;
+					if(FullScreen){
+						loadSkin(BACKGROUND_PIC, 0, 0);
+						loadIcon();
+					}
+					SlideShowStart=SlideShowStop=CountJpg=PicRotate=0;
+					thumb_load=TRUE;
+				} /* end else file */
+			} else if(new_pad & PAD_SELECT){
+				if(mountedParty[0][0]!=0){
+					fileXioUmount("pfs0:");
+					mountedParty[0][0]=0;
+				} 
+				if(mountedParty[1][0]!=0){
+					fileXioUmount("pfs1:");
+					mountedParty[1][0]=0;
+				}
+				setting->JpgView_Timer = SlideShowTime;
+				setting->JpgView_Trans = SlideShowTrans;
+				setting->JpgView_Full = FullScreen;
+				return;
+			} else if(new_pad & PAD_START){
+				if(path[0]!=0){
+					SlideShowStart=1;
+					SlideShowBegin=0;
+					goto repeat;
+				}
+			}   
+		}//ends pad response section
+          
+		//Thumb init
+		if(thumb_load){
+			jpg_browser_sel=0;
+			gsGlobal->CurrentPointer=0x288000;
+			for(i=0;i<MAX_ENTRY;++i)
+				thumb_test[i]=NOTLOADED;
+		}
+
+		//browser path adjustment section
+		if(jpg_browser_up){
+			if((p=strrchr(path, '/'))!=NULL)
+				*p = 0;
+			if((p=strrchr(path, '/'))!=NULL){
+				p++;
+				strcpy(cursorEntry, p);
+				*p = 0;
+			}else{
+				strcpy(cursorEntry, path);
+				path[0] = 0;
+			}   
+			jpg_browser_cd=TRUE;
+			jpg_browser_repos=TRUE;
+		}//ends 'if(jpg_browser_up)'
+		//----- Process newly entered directory here (incl initial entry)
+		if(jpg_browser_cd){
+			jpg_browser_nfiles =  setFileList(path, ext, files, JPG_CNF);
+			jpg_browser_sel=0;
+			top=0;
+			if(jpg_browser_repos){
+				jpg_browser_repos = FALSE;
+				for(i=0; i<jpg_browser_nfiles; i++) {
+					if(!strcmp(cursorEntry, files[i].name)) {
+						jpg_browser_sel=i;
+						top=jpg_browser_sel-3;
+						break;
+					}
+				}
+			} //ends if(jpg_browser_repos)
+			jpg_browser_cd=FALSE;
+			jpg_browser_up=FALSE;
+		} //ends if(jpg_browser_cd)
+		if(setting->discControl && !strncmp(path,"cdfs",4))
+			CDVD_Stop();
+		if(top > jpg_browser_nfiles-rows)	top=jpg_browser_nfiles-rows;
+		if(top < 0)				top=0;
+		if(jpg_browser_sel >= jpg_browser_nfiles)		jpg_browser_sel=jpg_browser_nfiles-1;
+		if(jpg_browser_sel < 0)				jpg_browser_sel=0;
+		if(jpg_browser_sel >= top+rows)		top=jpg_browser_sel-rows+1;
+		if(jpg_browser_sel < top)			top=jpg_browser_sel;
+		
+		t++;
+
+		if(t & 0x0F) event |= 4;  //repetitive timer event
+
+		if(event||post_event){ //NB: We need to update two frame buffers per event
+          
+			//Display section
+			clrScr(setting->color[0]);
+          
+			if(jpg_browser_mode==LIST){
+				x = Menu_start_x;
+				y = Menu_start_y;
+				rows = (Menu_end_y-Menu_start_y)/FONT_HEIGHT;
+				if(rows_down==1){
+					jpg_browser_sel=old_jpg_browser_sel;
+					rows_down=0;
+					old_jpg_browser_sel=0;
+				}	/* end if rows_down */
+				goto list;
+			}else{
+				x = Menu_start_x+13;
+				if(TV_mode == TV_mode_NTSC){
+					y = Menu_start_y+15;
+					rows=4;
+				}else if(TV_mode == TV_mode_PAL){
+					y = Menu_start_y+11;
+					rows=5;
+				}
+			}
+
+			if(test_top!=top){
+				if(top>test_top){
+down:
+					thumb_top=thumb_num=0;
+					for(i=0;i<jpg_browser_sel;++i){
+						if(i<top && thumb_test[i]==LOADED)
+							++thumb_top;
+						if(i>=top && thumb_test[i]==LOADED)
+							++thumb_num;
+					} /* end for */
+					if(thumb_test[jpg_browser_sel]==NOTLOADED && !(files[jpg_browser_sel].stats.attrFile & MC_ATTR_SUBDIR)){
+						sprintf(jpgpath, "%s%s", path, files[jpg_browser_sel].name);
+						loadSkin( THUMB_PIC, jpgpath, thumb_top+thumb_num);
+						thumb_test[jpg_browser_sel]=testthumb;
+					} /* end if notloaded */
+					if(rows_down==1){
+						if(++jpg_browser_sel>=old_jpg_browser_sel){
+							rows_down=0;
+							old_jpg_browser_sel=0;
+						}else
+							goto down;
+					} /* end if rows_down */
+				}else{
+					thumb_top=0;
+					for(i=0;i<top;++i){
+						if(thumb_test[i]==LOADED)
+							++thumb_top;
+					} /* end for */
+				} /* end else test_top */
+				test_top=top;
+			}else{
+				if(rows_down==1){
+					jpg_browser_sel=old_jpg_browser_sel;
+					rows_down=0;
+					old_jpg_browser_sel=0;
+				}	/* end if rows_down */
+			}/* end else test_top!=top */
+
+			thumb_num=0;
+
+list:
+			for(i=0; i<rows; i++)
+			{   
+				int name_limit = 0; //Assume that no name length problems exist
+
+				if(top+i >= jpg_browser_nfiles) break;
+				if(top+i == jpg_browser_sel) color = setting->color[2];  //Highlight cursor line
+				else			 color = setting->color[3];
+				
+				if(!strcmp(files[top+i].name,".."))
+					strcpy(tmp,"..");
+				else {
+					strcpy(tmp,files[top+i].name);
+					name_limit = 71*8;
+				}
+
+				if(jpg_browser_mode==LIST){  //List mode
+
+					if(name_limit){ //Do we need to check name length ?
+						int name_end = name_limit/7; //Max string length for acceptable spacing
+
+						if(files[top+i].stats.attrFile & MC_ATTR_SUBDIR)
+							name_end -= 1;  //For folders, reserve one character for final '/'
+						if(strlen(tmp) > name_end){  //Is name too long for clean display ?
+							tmp[name_end-1] = '~';  //indicate filename abbreviation
+							tmp[name_end] = 0;    //abbreviate name length to make room for details
+						}
+					}
+					if(files[top+i].stats.attrFile & MC_ATTR_SUBDIR)
+						strcat(tmp, "/");
+					printXY(tmp, x+4, y, color, TRUE, name_limit);
+					y += FONT_HEIGHT;
+
+				}else{  //Thumbnail mode
+
+					if(files[top+i].stats.attrFile & MC_ATTR_SUBDIR){
+						strcat(tmp, "/");
+						gsGlobal->PrimAlphaEnable = GS_SETTING_ON;
+						gsKit_set_primalpha(gsGlobal, GS_SETREG_ALPHA(0,1,0,1,0), 0);
+						gsKit_set_test(gsGlobal, GS_ATEST_OFF);
+						gsKit_prim_sprite_texture(gsGlobal,
+		 				 &TexIcon[0], x+20, (y+10), 0, 0, x+72-20, (y+55-10), 16, 16,
+		 				 0, GS_SETREG_RGBAQ(0x80,0x80,0x80,0x80,0x00));
+						gsKit_set_test(gsGlobal, GS_ATEST_ON);
+						gsKit_set_primalpha(gsGlobal, GS_BLEND_BACK2FRONT, 0);
+						gsGlobal->PrimAlphaEnable = GS_SETTING_OFF;
+						thumb_test[top+i]=BADJPG;
+						goto frame;
+					}
+
+					if(thumb_load){
+						sprintf(jpgpath, "%s%s", path, files[top+i].name);
+						loadSkin( THUMB_PIC, jpgpath, thumb_num+thumb_top);
+						thumb_test[top+i]=testthumb;
+					}
+
+					if(thumb_test[top+i]==LOADED){
+						gsKit_prim_sprite_texture(gsGlobal,
+		 				 &TexThumb[thumb_num+thumb_top], x, y, 0, 0, x+72, (y+55), 64, 32,
+		 				 0, BrightColor);
+						++thumb_num;
+					}else{ // BADJPG
+						gsGlobal->PrimAlphaEnable = GS_SETTING_ON;
+						gsKit_set_primalpha(gsGlobal, GS_SETREG_ALPHA(0,1,0,1,0), 0);
+						gsKit_set_test(gsGlobal, GS_ATEST_OFF);
+						gsKit_prim_sprite_texture(gsGlobal,
+		 				 &TexIcon[0], x+20, (y+10), 0, 0, x+72-20, (y+55-10), 16, 16,
+		 				 0, GS_SETREG_RGBAQ(0x80,0x80,0x80,0x80,0x00));
+						gsKit_set_test(gsGlobal, GS_ATEST_ON);
+						gsKit_set_primalpha(gsGlobal, GS_BLEND_BACK2FRONT, 0);
+						gsGlobal->PrimAlphaEnable = GS_SETTING_OFF;
+					}
+
+frame:
+					drawFrame(x, y, x+72, (y+55),color);
+
+					Len = printXY(tmp, 0, 0, 0, FALSE, 0);
+					if(Len>72 && top+i==jpg_browser_sel){
+						if(t%0x10==0){
+							strcpy(tmp1,tmp+print_name);
+							tmp1[10]='\0';
+							if(++print_name>(Len/FONT_WIDTH-10))
+								print_name=0;
+						}
+						Len = printXY(tmp1, 0, 0, 0, FALSE, 0);
+						printXY(tmp1, x+72/2-Len/2, (y+58), color, TRUE, 0);
+					}else if(Len>72){
+						tmp[7]='.'; tmp[8]='.'; tmp[9]='.'; tmp[10]='\0';
+						printXY(tmp, x-4, (y+58), color, TRUE, 0);
+					}else
+						printXY(tmp, x+72/2-Len/2, (y+58), color, TRUE, 0);
+
+					if(TV_mode == TV_mode_NTSC)
+						y += 71+15;
+					else if(TV_mode == TV_mode_PAL)
+						y += 71+11;
+
+				}/* end else THUMBNAIL */
+
+			} //ends for, so all browser rows were fixed above
+			thumb_load=FALSE;
+			if(jpg_browser_nfiles > rows) { //if more files than available rows, use scrollbar
+				drawFrame(SCREEN_WIDTH-SCREEN_MARGIN-LINE_THICKNESS*8, Frame_start_y,
+					SCREEN_WIDTH-SCREEN_MARGIN, Frame_end_y, setting->color[1]);
+				y0=(Menu_end_y-Menu_start_y+8) * ((double)top/jpg_browser_nfiles);
+				y1=(Menu_end_y-Menu_start_y+8) * ((double)(top+rows)/jpg_browser_nfiles);
+				drawOpSprite(setting->color[1],
+				 SCREEN_WIDTH-SCREEN_MARGIN-LINE_THICKNESS*6, (y0+Menu_start_y-4),
+				 SCREEN_WIDTH-SCREEN_MARGIN-LINE_THICKNESS*2, (y1+Menu_start_y-4));
+			} //ends clause for scrollbar
+			msg0[0]='\0';
+			if(jpg_browser_pushed)
+				sprintf(msg0, "%s %s: %s", LNG(Jpg_Viewer), LNG(Path), path);
+
+			//Tooltip section
+			msg1[0]='\0';
+			if (swapKeys)
+				sprintf(msg1, "ÿ1:%s", LNG(View));
+			else
+				sprintf(msg1, "ÿ0:%s", LNG(View));
+			if(jpg_browser_mode==LIST)
+				sprintf(tmp, " ÿ3:%s ÿ2:%s", LNG(Up), LNG(Thumb));
+			else
+				sprintf(tmp, " ÿ3:%s ÿ2:%s", LNG(Up), LNG(List));
+			strcat(msg1, tmp);
+			sprintf(tmp, " Sel:%s Start:%s L1/R1:%dsec L2:",
+				LNG(Exit), LNG(SlideShow), SlideShowTime);
+			strcat(msg1, tmp);
+			if(SlideShowTrans==OFF)
+				strcat(msg1, LNG(Off));
+			else if(SlideShowTrans==ZOOM)
+				strcat(msg1, LNG(Zoom));
+			else if(SlideShowTrans==FADE)
+				strcat(msg1, LNG(Fade));
+			else if(SlideShowTrans==ZOOM_FADE)
+				strcat(msg1, LNG(ZoomFade));
+			sprintf(tmp, " R2:%s", LNG(PathPad));
+			strcat(msg1, tmp);
+			setScrTmp(msg0, msg1);
+		}//ends if(event||post_event)
+		drawScr();
+		post_event = event;
+		event = 0;
+	}//ends while
+} /* end JpgViewer */
+//--------------------------------------------------------------
+//End of file: jpgviewer.c
+//--------------------------------------------------------------
Index: ps2launchargs/source/uLaunchELF/lang.c
===================================================================
--- ps2launchargs/source/uLaunchELF/lang.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/lang.c	(revision 1101)
@@ -0,0 +1,329 @@
+//---------------------------------------------------------------------------
+//File name:    lang.c
+//---------------------------------------------------------------------------
+#include "launchelf.h"
+
+#define lang(id, name, value) u8 Str_##name [] = value;
+#include "lang.h"
+#undef lang
+
+Language Lang_Default[]={
+#define lang(id, name, value) {Str_##name},
+#include "lang.h"
+#undef lang
+	{NULL}
+};
+
+Language Lang_String[sizeof(Lang_Default) / sizeof(Lang_Default[0])];
+Language Lang_Extern[sizeof(Lang_Default) / sizeof(Lang_Default[0])];
+
+Language *External_Lang_Buffer = NULL;
+
+//---------------------------------------------------------------------------
+// get_LANG_string is the main parser called for each language dependent
+// string in a language header file. (eg: "Francais.h" or "Francais.lng")
+// Call values for all input arguments should be addresses of string pointers
+// LANG_p_p is for file to be scanned, moved to point beyond scanned data.
+// id_p_p is for a string defining the index value (suitable for 'atoi')
+// value_p_p is for the string value itself (not NUL-terminated)
+// The function returns the length of each string found, but -1 at EOF,
+// and various error codes less than -1 (-2 etc) for various syntax errors,
+// which also applies to EOF occurring where valid macro parts are expected.
+//---------------------------------------------------------------------------
+int	get_LANG_string(u8 **LANG_p_p, u8 **id_p_p, u8 **value_p_p)
+{
+	u8 *cp, *ip, *vp, *tp = *LANG_p_p;
+	int ret, length;
+
+	ip = NULL;
+	vp = NULL;
+	ret = -1;
+
+start_line:
+	while(*tp<=' ' && *tp>'\0') tp+=1;     //Skip leading whitespace, if any
+	if(*tp=='\0')	goto exit;               //but exit at EOF
+	//Current pos is potential "lang(" entry, but we must verify this
+	if(tp[0]=='/' && tp[1]=='/')           //It may be a comment line
+	{                                      //We must skip a comment line
+		while(*tp!='\r' && *tp!='\n' && *tp>'\0') tp+=1;  //Seek line end
+		goto start_line;                     //Go back to try next line
+	}
+	ret = -2;
+	//Here tp points to a non-zero string that is not a comment
+	if(strncmp(tp, "lang", 4)) goto exit;  //Return error if not 'lang' macro
+	tp+=4;                                 //but if it is, step past that name
+	ret = -3;
+	while(*tp<=' ' && *tp!='\r' && *tp!='\n' && *tp>'\0') tp+=1; //skip inline whitespace
+	if(*tp=='\0')	goto exit;               //but exit at EOF
+	ret = -4;
+	//Here tp points to a non-zero string that should be an opening parenthesis
+	if(*tp!='(') goto exit;                //Return error if no opening parenthesis
+	tp+=1;                                 //but if it is, step past this character
+	ret = -5;
+	while(*tp<=' ' && *tp!='\r' && *tp!='\n' && *tp>'\0') tp+=1; //skip inline whitespace
+	if(*tp=='\0')	goto exit;               //but exit at EOF
+	ret = -6;
+	//Here tp points to a non-zero string that should be an index number
+	if(*tp<'0' || *tp>'9') goto exit;      //Return error if it's not a number
+	ip = tp;                               //but if it is, save this pos as id start
+	while(*tp>='0' && *tp<='9') tp+=1;     //skip past the index number
+	ret = -7;
+	while(*tp<=' ' && *tp!='\r' && *tp!='\n' && *tp>'\0') tp+=1; //skip inline whitespace
+	if(*tp=='\0')	goto exit;               //but exit at EOF
+	ret = -8;
+	//Here tp points to a non-zero string that should be a comma
+	if(*tp!=',') goto exit;                //Return error if no comma after index
+	tp+=1;                                 //but if present, step past that comma
+	ret = -9;
+	while(*tp<=' ' && *tp!='\r' && *tp!='\n' && *tp>'\0') tp+=1; //skip inline whitespace
+	if(*tp=='\0')	goto exit;               //but exit at EOF
+	ret = -10;
+	//Here tp points to a non-zero string that should be a symbolic string name
+	//But we don't need to process this for language switch purposes, so we ignore it
+	//This may be changed later, to use the name for generating error messages
+	while(*tp!=',' && *tp!='\r' && *tp!='\n' && *tp>'\0') tp+=1; //seek inline comma
+	if(*tp!=',') goto exit;                //Return error if no comma after string name
+	tp+=1;                                 //but if present, step past that comma
+	ret = -11;
+	while(*tp<=' ' && *tp!='\r' && *tp!='\n' && *tp>'\0') tp+=1; //skip inline whitespace
+	if(*tp=='\0')	goto exit;               //but exit at EOF
+	ret = -12;
+	//Here tp points to a non-zero string that should be the opening quote character
+	if(*tp!='\"') goto exit;               //Return error if no opening quote
+	tp+=1;                                 //but if present, step past that quote
+	ret = -13;
+	vp = tp;                               //save this pos as value start
+close_quote:
+	while(*tp!='\"' && *tp!='\r' && *tp!='\n' && *tp>'\0') tp+=1; //seek inline quote
+	if(*tp!='\"') return -13;              //Return error if no closing quote
+  cp = tp-1;                             //save previous pos as check pointer
+  tp+=1;                                 //step past the quote character
+  if(*cp=='\\') goto close_quote;        //if this was an 'escaped' quote, try again
+  //Here tp points to the character after the closing quote.
+  length = (tp-1) - vp;                  //prepare string length for return value
+	ret = -14;
+	while(*tp<=' ' && *tp!='\r' && *tp!='\n' && *tp>'\0') tp+=1; //skip inline whitespace
+	if(*tp=='\0')	goto exit;               //but exit at EOF
+	ret = -15;
+	//Here tp points to a non-zero string that should be closing parenthesis
+	if(*tp!=')') goto exit;                //Return error if no closing parenthesis
+	tp+=1;                                 //but if present, step past the parenthesis
+	ret = -16;
+	while(*tp<=' ' && *tp!='\r' && *tp!='\n' && *tp>'\0') tp+=1; //skip inline whitespace
+	if(*tp=='\0')	goto exit;              //but exit at EOF
+	//Here tp points to a non-zero string that should be line end or a comment
+	if(tp[0]!='/' || tp[1]!='/') goto finish_line; //if no comment, go handle line end
+	ret = -17;
+	while(*tp!='\r' && *tp!='\n' && *tp>'\0') tp+=1;  //Seek line end
+	if(*tp=='\0')	goto exit;              //but exit at EOF
+finish_line:
+	ret = -18;
+	if(*tp!='\r' && *tp!='\n') goto exit;  //Return error if not valid line end
+	if(tp[0]=='\r' && tp[1]=='\n') tp+=1;  //Step an extra pos for CR+LF
+	tp+=1;                                 //Step past valid line end
+  //Here tp points beyond the line of the processed string, so we're done
+  ret = length;
+
+exit:
+	*LANG_p_p = tp;                        //return new LANG file position
+	*id_p_p = ip;                          //return found index
+	*value_p_p = vp;                       //return found string value
+	return ret;                           //return control to caller
+}
+//Ends get_LANG_string
+//---------------------------------------------------------------------------
+void Init_Default_Language(void)
+{
+	memcpy(Lang_String, Lang_Default, sizeof(Lang_String));
+}
+//Ends Init_Default_Language
+//---------------------------------------------------------------------------
+void Load_External_Language(void)
+{
+	int error_id = -1;
+	int test = 0;
+	u32 index = 0;
+	char filePath[MAX_PATH];
+	u8 *file_bp, *file_tp, *lang_bp, *lang_tp, *oldf_tp=NULL;
+	u8 *id_p, *value_p;
+	int lang_size = 0;
+	int fd;
+
+	if(External_Lang_Buffer!=NULL){  //if an external buffer was allocated before
+		free(External_Lang_Buffer);    //release that buffer before the new attempt
+		External_Lang_Buffer = NULL;
+	}
+
+	Language* Lang = Lang_Default;
+	memcpy(Lang_String, Lang, sizeof(Lang_String));
+
+	if(strlen(setting->lang_file)!=0){ //if language file string set
+
+		error_id = -2;
+		genFixPath(setting->lang_file, filePath);
+		fd = genOpen(filePath, O_RDONLY);
+		if(fd >= 0){                         //if file opened OK
+    	int file_size = genLseek(fd, 0, SEEK_END);
+
+			error_id = -3;
+    	if (file_size > 0) {               //if file size OK
+				error_id = -4;
+ 	 			file_bp = (u8*) malloc(file_size + 1);
+ 	 			if(file_bp == NULL)
+ 	 				goto aborted_1;
+
+				error_id = -5;
+				genLseek(fd, 0, SEEK_SET);
+				if(genRead(fd, file_bp, file_size) != file_size)
+					goto release_1;
+				file_bp[file_size] = '\0'; //enforce termination at buffer end
+
+				error_id = -6;
+				file_tp = file_bp;
+				while(1){
+					oldf_tp = file_tp;
+					test = get_LANG_string(&file_tp, &id_p, &value_p);
+					if(test==-1)                   //if EOF reached without other error
+						break;                         //break from the loop normally
+					if(test<0)                     //At any fatal error result
+						goto release_1;                //go release file buffer
+					index = atoi(id_p);            //get the string index
+					if(index>=LANG_COUNT)          //At any fatal error result
+						goto release_1;                //go release file buffer
+					lang_size += test + 1;         //Include terminator space for total size
+				}
+				//Here lang_size is the space needed for real language buffer,
+
+				error_id = -7;
+ 	 			lang_bp = (u8*) malloc(lang_size + 1); //allocate real language buffer
+ 	 			if(lang_bp == NULL)
+ 	 				goto release_1;
+
+				//We're ready to read language strings, but must first init all pointers
+				//to use default strings, for any indexes left undefined by the file
+				memcpy(Lang_Extern, Lang, sizeof(Lang_Extern));
+
+ 	 			file_tp = file_bp;
+ 	 			lang_tp = lang_bp;
+				while((test = get_LANG_string(&file_tp, &id_p, &value_p)) >= 0){
+					index = atoi(id_p);                  //get the string index
+					Lang_Extern[index].String = lang_tp; //save pointer to this string base
+					strncpy(lang_tp, value_p, test);     //transfer the string
+					lang_tp[test] = '\0';                //transfer a terminator
+					lang_tp += test + 1;                 //move dest pointer past this string
+				}
+				External_Lang_Buffer = (Language*) lang_bp;  //Save base pointer for releases
+				Lang = Lang_Extern;
+				error_id = 0;
+release_1:
+				free(file_bp);
+			}  // end if clause for file size OK
+aborted_1:
+			genClose( fd );
+		}  // end if clause for file opened OK
+	} // end if language file string set
+
+	if(error_id < -1){
+		u8 tmp_s[80*8], t1_s[102], t2_s[102];
+		int pos=0, stp=0;
+		sprintf(tmp_s,
+			"LNG loading failed with error_id==%d and test==%d\n"
+			"The latest string index (possibly invalid) was %d\n"
+			"%n"
+			, error_id, test, index, &stp
+		);
+		pos += stp;
+		if(error_id==-2) {//if file open failure
+			sprintf(tmp_s+pos,
+				"This was a failure to open the file:\n"
+				"\"%s\"\n"
+				, filePath
+			);
+		}
+		if(error_id==-6) {//if parsing error
+			strncpy(t1_s, oldf_tp, 100);
+			t1_s[100] = '\0';
+			strncpy(t2_s, file_tp, 100);
+			t2_s[100] = '\0';
+			sprintf(tmp_s+pos,
+				"This was a parsing error when trying to parse the text:\n"
+				"\"%s\"\n"
+				"That attempt failed somehow, after reaching this point:\n"
+				"\"%s\"\n"
+				, t1_s, t2_s
+			);
+		}
+		strcat(tmp_s, "Use either OK or CANCEL to continue (no diff)");
+		ynDialog(tmp_s);
+	}
+
+	memcpy(Lang_String, Lang, sizeof(Lang_String));
+
+	int i;
+	char *tmp;
+
+	if(strlen(setting->Misc)>0){
+		for(i=0; i<16; i++){	//Loop to rename the ELF paths with new language for launch keys
+			if((i<12) || (setting->LK_Flag[i]!=0)){
+				if(!strncmp(setting->LK_Path[i], setting->Misc, strlen(setting->Misc))){
+					tmp  = strrchr(setting->LK_Path[i], '/');
+					if(!strcmp(tmp+1, setting->Misc_PS2Disc+strlen(setting->Misc)))
+						sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(PS2Disc));
+					else if(!strcmp(tmp+1, setting->Misc_FileBrowser+strlen(setting->Misc)))
+						sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(FileBrowser));
+					else if(!strcmp(tmp+1, setting->Misc_PS2Browser+strlen(setting->Misc)))
+						sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(PS2Browser));
+					else if(!strcmp(tmp+1, setting->Misc_PS2Net+strlen(setting->Misc)))
+						sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(PS2Net));
+					else if(!strcmp(tmp+1, setting->Misc_PS2PowerOff+strlen(setting->Misc)))
+						sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(PS2PowerOff));
+					else if(!strcmp(tmp+1, setting->Misc_HddManager+strlen(setting->Misc)))
+						sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(HddManager));
+					else if(!strcmp(tmp+1, setting->Misc_TextEditor+strlen(setting->Misc)))
+						sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(TextEditor));
+					else if(!strcmp(tmp+1, setting->Misc_JpgViewer+strlen(setting->Misc)))
+						sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(JpgViewer));
+					else if(!strcmp(tmp+1, setting->Misc_Configure+strlen(setting->Misc)))
+						sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(Configure));
+					else if(!strcmp(tmp+1, setting->Misc_Load_CNFprev+strlen(setting->Misc)))
+						sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(Load_CNFprev));
+					else if(!strcmp(tmp+1, setting->Misc_Load_CNFnext+strlen(setting->Misc)))
+						sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(Load_CNFnext));
+					else if(!strcmp(tmp+1, setting->Misc_Set_CNF_Path+strlen(setting->Misc)))
+						sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(Set_CNF_Path));
+					else if(!strcmp(tmp+1, setting->Misc_Load_CNF+strlen(setting->Misc)))
+						sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(Load_CNF));
+					else if(!strcmp(tmp+1, setting->Misc_ShowFont+strlen(setting->Misc)))
+						sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(ShowFont));
+					else if(!strcmp(tmp+1, setting->Misc_Debug_Info+strlen(setting->Misc)))
+						sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(Debug_Info));
+					else if(!strcmp(tmp+1, setting->Misc_About_uLE+strlen(setting->Misc)))
+						sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(About_uLE));
+				} // end if Misc
+			} // end if LK assigned
+		} // end for
+	} // end if Misc Initialized
+
+	sprintf(setting->Misc              , "%s/",   LNG(MISC));
+	sprintf(setting->Misc_PS2Disc      , "%s/%s", LNG(MISC), LNG(PS2Disc));
+	sprintf(setting->Misc_FileBrowser  , "%s/%s", LNG(MISC), LNG(FileBrowser));
+	sprintf(setting->Misc_PS2Browser   , "%s/%s", LNG(MISC), LNG(PS2Browser));
+	sprintf(setting->Misc_PS2Net       , "%s/%s", LNG(MISC), LNG(PS2Net));
+	sprintf(setting->Misc_PS2PowerOff  , "%s/%s", LNG(MISC), LNG(PS2PowerOff));
+	sprintf(setting->Misc_HddManager   , "%s/%s", LNG(MISC), LNG(HddManager));
+	sprintf(setting->Misc_TextEditor   , "%s/%s", LNG(MISC), LNG(TextEditor));
+	sprintf(setting->Misc_JpgViewer    , "%s/%s", LNG(MISC), LNG(JpgViewer));
+	sprintf(setting->Misc_Configure    , "%s/%s", LNG(MISC), LNG(Configure));
+	sprintf(setting->Misc_Load_CNFprev , "%s/%s", LNG(MISC), LNG(Load_CNFprev));
+	sprintf(setting->Misc_Load_CNFnext , "%s/%s", LNG(MISC), LNG(Load_CNFnext));
+	sprintf(setting->Misc_Set_CNF_Path , "%s/%s", LNG(MISC), LNG(Set_CNF_Path));
+	sprintf(setting->Misc_Load_CNF     , "%s/%s", LNG(MISC), LNG(Load_CNF));
+	sprintf(setting->Misc_ShowFont     , "%s/%s", LNG(MISC), LNG(ShowFont));
+	sprintf(setting->Misc_Debug_Info   , "%s/%s", LNG(MISC), LNG(Debug_Info));
+	sprintf(setting->Misc_About_uLE    , "%s/%s", LNG(MISC), LNG(About_uLE));
+
+}
+//Ends Load_External_Language
+//---------------------------------------------------------------------------
+//End of file:  lang.c
+//---------------------------------------------------------------------------
Index: ps2launchargs/source/uLaunchELF/lang.h
===================================================================
--- ps2launchargs/source/uLaunchELF/lang.h	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/lang.h	(revision 1101)
@@ -0,0 +1,371 @@
+//---------------------------------------------------------------------------
+//File name:    lang.h                  Revision Date: 2007.05.10
+//---------------------------------------------------------------------------
+//This file is used both for compiling the uLaunchELF program,
+//with default language definitions, and when loading alternate
+//language definitions at runtime. For the latter case it is the
+//intention that an edited version of this file be used, where
+//each string constant has been replaced by one suitable for the
+//language to be used. Only the quoted strings should be edited
+//for such use, as changing other parts of the lines could cause
+//malfunction. The index number controls where in the program a
+//string gets used, and the 'name' part is an identifying symbol
+//that should remain untranslated even for translated versions,
+//so that we can use them as a common reference independent both
+//of the language used, and of the index number. Those names do
+//not have any effect on loading alternate language definitions.
+//--------------------------------------------------------------
+lang(0, Net_Config,              "Net Config")
+lang(1, Init_Delay,              "Init Delay")
+lang(2, TIMEOUT,                 "TIMEOUT")
+lang(3, Halted,                  "Halted")
+lang(4, LEFT,                    "LEFT")
+lang(5, RIGHT,                   "RIGHT")
+lang(6, PUSH_ANY_BUTTON_or_DPAD, "PUSH ANY BUTTON or D-PAD")
+lang(7, Loading_HDL_Info_Module, "Loading HDL Info Module...")
+lang(8, Loading_HDD_Modules,     "Loading HDD Modules...")
+lang(9, Loading_NetFS_and_FTP_Server_Modules, "Loading NetFS and FTP Server Modules...")
+lang(10, Valid,                  "Valid")
+lang(11, Bogus,                  "Bogus")
+lang(12, CNF_Path,               "CNF Path")
+lang(13, is_Not_Found,           "is Not Found")
+//--------------------------------------------------------------
+lang(14, MISC,         "MISC")
+lang(15, PS2Disc,      "PS2Disc")
+lang(16, FileBrowser,  "FileBrowser")
+lang(17, PS2Browser,   "PS2Browser")
+lang(18, PS2Net,       "PS2Net")
+lang(19, PS2PowerOff,  "PS2PowerOff")
+lang(20, HddManager,   "HddManager")
+lang(21, TextEditor,   "TextEditor")
+lang(22, JpgViewer,    "JpgViewer")
+lang(23, Configure,    "Configure")
+lang(24, Load_CNFprev, "Load CNF--")
+lang(25, Load_CNFnext, "Load CNF++")
+lang(26, Set_CNF_Path, "Set CNF_Path")
+lang(27, Load_CNF,     "Load CNF")
+lang(28, ShowFont,     "ShowFont")
+//--------------------------------------------------------------
+lang(29, Reading_SYSTEMCNF, "Reading SYSTEM.CNF...")
+lang(30, Failed, "Failed")
+lang(31, Powering_Off_Console, "Powering Off Console...")
+lang(32, No_Disc, "No Disc")
+lang(33, Detecting_Disc, "Detecting Disc")
+lang(34, Stop_Disc, "Stop Disc")
+lang(35, auto, "auto")
+lang(36, Circle, "Circle")
+lang(37, Cross, "Cross")
+lang(38, Square, "Square")
+lang(39, Triangle, "Triangle")
+lang(40, Failed_To_Save, "Failed To Save")
+lang(41, Saved_Failed, "Saved Failed")
+lang(42, Saved_Config, "Saved Config")
+lang(43, Saved, "Saved")
+lang(44, Failed_writing, "Failed writing")
+lang(45, Failed_To_Load, "Failed To Load")
+lang(46, Loaded_Config, "Loaded Config")
+//--------------------------------------------------------------
+lang(47, SKIN_SETTINGS, "SKIN SETTINGS")
+lang(48, Skin_Path, "Skin Path")
+lang(49, Apply_New_Skin, "Apply New Skin")
+lang(50, Brightness, "Brightness")
+lang(51, Edit, "Edit")
+lang(52, Clear, "Clear")
+lang(53, Add, "Add")
+lang(54, Subtract, "Subtract")
+lang(55, OK, "OK")
+lang(56, CANCEL, "CANCEL")
+lang(57, Cancel, "Cancel")
+lang(58, Browse, "Browse")
+lang(59, Change, "Change")
+lang(60, Return, "Return")
+lang(61, PasteRename, "Paste+Rename")
+lang(62, Back, "Back")
+lang(63, Use, "Use")
+lang(64, Set, "Set")
+lang(65, Page_leftright, "Page left/right")
+lang(66, Edit_Title, "Edit Title")
+lang(67, Left, "Left")
+lang(68, Right, "Right")
+lang(69, Up, "Up")
+lang(70, Enter, "Enter")
+lang(71, Choose, "Choose")
+lang(72, RevMark, "RevMark")
+lang(73, TitleOFF, "TitleOFF")
+lang(74, TitleON, "TitleON")
+lang(75, Menu, "Menu")
+lang(76, PathPad, "PathPad")
+lang(77, Exit, "Exit")
+lang(78, View, "View")
+lang(79, Thumb, "Thumb")
+lang(80, List, "List")
+lang(81, SlideShow, "SlideShow")
+lang(82, Sel, "Sel")
+lang(83, BackSpace, "BackSpace")
+lang(84, Mark, "Mark")
+lang(85, CrLf, "Cr/Lf")
+lang(86, Cr, "Cr")
+lang(87, Lf, "Lf")
+lang(88, Ins, "Ins")
+lang(89, On, "On")
+lang(90, Off, "Off")
+lang(91, Open_KeyBoard, "Open KeyBoard")
+lang(92, Close_KB, "Close KB")
+lang(93, free, "free")
+lang(94, Color, "Color")
+lang(95, Backgr, "Backgr")
+lang(96, Frames, "Frames")
+lang(97, Select, "Select")
+lang(98, Normal, "Normal")
+lang(99, Graph, "Graph")
+lang(100, TV_mode, "TV mode")
+lang(101, Screen_X_offset, "Screen X offset")
+lang(102, Screen_Y_offset, "Screen Y offset")
+lang(103, Interlace, "Interlace")
+lang(104, ON, "ON")
+lang(105, OFF, "OFF")
+lang(106, Skin_Settings, "Skin Settings")
+lang(107, Menu_Title, "Menu Title")
+lang(108, NULL, "NULL")
+lang(109, NONE, "NONE")
+lang(110, DEFAULT, "DEFAULT")
+lang(111, Menu_Frame, "Menu Frame")
+lang(112, Popups_Opaque, "Popups Opaque")
+lang(113, Use_Default_Screen_Settings, "Use Default Screen Settings")
+//--------------------------------------------------------------
+lang(114, STARTUP_SETTINGS, "STARTUP SETTINGS")
+lang(115, Reset_IOP, "Reset IOP")
+lang(116, Number_of_CNFs, "Number of CNF's")
+lang(117, Pad_mapping, "Pad mapping")
+lang(118, USBD_IRX, "USBD IRX")
+lang(119, Initial_Delay, "Initial Delay")
+lang(120, Default_Timeout, "'Default' Timeout")
+lang(121, USB_Keyboard_Used, "USB Keyboard Used")
+lang(122, USB_Keyboard_IRX, "USB Keyboard IRX")
+lang(123, USB_Keyboard_Map, "USB Keyboard Map")
+lang(124, CNF_Path_override, "CNF Path override")
+lang(125, USB_Mass_IRX, "USB Mass IRX")
+lang(126, Language_File, "Language File")
+//--------------------------------------------------------------
+lang(127, NETWORK_SETTINGS, "NETWORK SETTINGS")
+lang(128, IP_Address, "IP Address")
+lang(129, Netmask, "Netmask")
+lang(130, Gateway, "Gateway")
+lang(131, Save_to, "Save to")
+//--------------------------------------------------------------
+lang(132, Right_DPad_to_Edit, "Right D-Pad to Edit")
+lang(133, Button_Settings, "Button Settings")
+lang(134, Show_launch_titles, "Show launch titles")
+lang(135, Disc_control, "Disc control")
+lang(136, Hide_full_ELF_paths, "Hide full ELF paths")
+lang(137, Screen_Settings, "Screen Settings")
+lang(138, Startup_Settings, "Startup Settings")
+lang(139, Network_Settings, "Network Settings")
+lang(140, Copy, "Copy")
+lang(141, Cut, "Cut")
+lang(142, Paste, "Paste")
+lang(143, Delete, "Delete")
+lang(144, New_Dir, "New Dir")
+lang(145, Get_Size, "Get Size")
+lang(146, mcPaste, "mcPaste")
+lang(147, psuPaste, "psuPaste")
+lang(148, Name_conflict_for_this_folder, "Name conflict for this folder")
+lang(149, With_gamesave_title, "With gamesave title")
+lang(150, Undefined_Not_a_gamesave, "Undefined (Not a gamesave)")
+lang(151, Do_you_wish_to_overwrite_it, "Do you wish to overwrite it")
+lang(152, Pasting_file, "Pasting file")
+lang(153, Remain_Size, "RemainSize")
+lang(154, bytes, "bytes")
+lang(155, Kbytes, "Kbytes")
+lang(156, Current_Speed, "Current Speed")
+lang(157, Unknown, "Unknown")
+lang(158, Remain_Time, "RemainTime")
+lang(159, Written_Total, "Written Total")
+lang(160, Average_Speed, "Average Speed")
+lang(161, Continue_transfer, "Continue transfer ?")
+lang(162, This_file_isnt_an_ELF, "This file isn't an ELF")
+lang(163, Copied_to_the_Clipboard, "Copied to the Clipboard")
+lang(164, Mark_Files_Delete, "Mark Files Delete ?")
+lang(165, deleting, "deleting")
+lang(166, Delete_Failed, "Delete Failed")
+lang(167, Rename_Failed, "Rename Failed")
+lang(168, directory_already_exists, "directory already exists")
+lang(169, NewDir_Failed, "NewDir Failed")
+lang(170, Created_folder, "Created folder")
+lang(171, Path, "Path")
+lang(172, Checking_Size, "Checking Size...")
+lang(173, size_result, "size result")
+lang(174, Size_test_Failed, "Size test Failed")
+lang(175, mctype, "mctype")
+lang(176, Pasting, "Pasting...")
+lang(177, Paste_Failed, "Paste Failed")
+lang(178, pasting, "pasting")
+lang(179, Reading_HDD_Information, "Reading HDD Information...")
+lang(180, Found, "Found")
+lang(181, MB, "MB")
+lang(182, GB, "GB")
+lang(183, HDD_Information_Read, "HDD Information Read")
+lang(184, Create, "Create")
+lang(185, Remove, "Remove")
+lang(186, Rename, "Rename")
+lang(187, Expand, "Expand")
+lang(188, Format, "Format")
+lang(189, Creating_New_Partition, "Creating New Partition...")
+lang(190, New_Partition_Created, "New Partition Created")
+lang(191, Failed_Creating_New_Partition, "Failed Creating New Partition")
+lang(192, Removing_Current_Partition, "Removing Current Partition...")
+lang(193, Partition_Removed, "Partition Removed")
+lang(194, Failed_Removing_Current_Partition, "Failed Removing Current Partition")
+lang(195, Renaming_Partition, "Renaming Partition...")
+lang(196, Partition_Renamed, "Partition Renamed")
+lang(197, Failed_Renaming_Partition, "Failed Renaming Partition")
+lang(198, Renaming_Game, "Renaming Game...")
+lang(199, Game_Renamed, "Game Renamed")
+lang(200, Failed_Renaming_Game, "Failed Renaming Game")
+lang(201, Expanding_Current_Partition, "Expanding Current Partition...")
+lang(202, Partition_Expanded, "Partition Expanded")
+lang(203, Failed_Expanding_Current_Partition, "Failed Expanding Current Partition")
+lang(204, Formating_HDD, "Formating HDD...")
+lang(205, HDD_Formated, "HDD Formated")
+lang(206, HDD_Format_Failed, "HDD Format Failed")
+lang(207, Create_New_Partition, "Create New Partition ?")
+lang(208, Remove_Current_Partition, "Remove Current Partition ?")
+lang(209, Enter_New_Partition_Name, "Enter New Partition Name.")
+lang(210, Rename_Current_Game, "Rename Current Game ?")
+lang(211, Rename_Current_Partition, "Rename Current Partition ?")
+lang(212, Select_New_Partition_Size_In_MB, "Select New Partition Size In MB.")
+lang(213, Expand_Current_Partition, "Expand Current Partition ?")
+lang(214, Format_HDD, "Format entire HDD (destroys all partitions) ?")
+lang(215, HDD_STATUS, "HDD STATUS")
+lang(216, CONNECTED, "CONNECTED")
+lang(217, FORMATED, "FORMATED")
+lang(218, YES, "YES")
+lang(219, NO, "NO")
+lang(220, HDD_SIZE, "HDD SIZE")
+lang(221, HDD_USED, "HDD USED")
+lang(222, HDD_FREE, "HDD FREE")
+lang(223, FREE, "FREE")
+lang(224, Raw_SIZE, "Raw SIZE")
+lang(225, Reserved_for_system, "Reserved for system")
+lang(226, Inaccessible, "Inaccessible")
+lang(227, HDL_SIZE, "HDL SIZE")
+lang(228, Info_not_loaded, "Info not loaded")
+lang(229, GAME_INFORMATION, "GAME INFORMATION")
+lang(230, STARTUP, "STARTUP")
+lang(231, SIZE, "SIZE")
+lang(232, TYPE_DVD_GAME, "TYPE: DVD GAME")
+lang(233, TYPE_CD_GAME, "TYPE: CDGAME")
+lang(234, PFS_SIZE, "PFS SIZE")
+lang(235, PFS_USED, "PFS USED")
+lang(236, PFS_FREE, "PFS FREE")
+lang(237, MENU, "MENU")
+lang(238, Load_HDL_Game_Info, "Load HDL Game Info")
+lang(239, PS2_HDD_MANAGER, "PS2 HDD MANAGER")
+lang(240, New, "New")
+lang(241, Open, "Open")
+lang(242, Close, "Close")
+lang(243, Save, "Save")
+lang(244, Save_As, "Save As")
+lang(245, Windows, "Windows")
+lang(246, Free_Window, "Free Window")
+lang(247, Window_Not_Yet_Saved, "Window Not Yet Saved")
+lang(248, File_Created, "File Created")
+lang(249, Failed_Creating_File, "Failed Creating File")
+lang(250, File_Opened, "File Opened")
+lang(251, Failed_Opening_File, "Failed Opening File")
+lang(252, File_Not_Yet_Saved, "File Not Yet Saved")
+lang(253, File_Not_Yet_Saved_Closed, "File Not Yet Saved Closed")
+lang(254, File_Closed, "File %s Closed")
+lang(255, File_Saved, "File Saved")
+lang(256, Failed_Saving_File, "Failed Saving File")
+lang(257, Enter_File_Name, "Enter File Name.")
+lang(258, Exiting_Editor, "Exiting Editor...")
+lang(259, Exit_Without_Saving, "Exit Without Saving ?")
+lang(260, Select_A_File_For_Editing, "Select A File For Editing")
+lang(261, Close_Without_Saving, "Close Without Saving ?")
+lang(262, MARK, "MARK")
+lang(263, COPY, "COPY")
+lang(264, CUT, "CUT")
+lang(265, PASTE, "PASTE")
+lang(266, LINE_UP, "LINE UP")
+lang(267, LINE_DOWN, "LINE DOWN")
+lang(268, PAGE_UP, "PAGE UP")
+lang(269, PAGE_DOWN, "PAGE DOWN")
+lang(270, HOME, "HOME")
+lang(271, END, "END")
+lang(272, INSERT, "INSERT")
+lang(273, RET_CRLF, "RET CR/LF")
+lang(274, RET_CR, "RET CR")
+lang(275, RET_LF, "RET LF")
+lang(276, TAB, "TAB")
+lang(277, SPACE, "SPACE")
+lang(278, RETURN, "RETURN")
+lang(279, PS2_TEXT_EDITOR, "PS2 TEXT EDITOR")
+lang(280, Start_StartStop_Slideshow, "Start: Start/Stop Slideshow")
+lang(281, L1R1_Slideshow_Timer, "L1/R1: Slideshow Timer")
+lang(282, L2R2_Slideshow_Transition, "L2/R2: Slideshow Transition")
+lang(283, LeftRight_Pad_PrevNext_Picture, "Left/Right Pad: Prev/Next Picture")
+lang(284, UpDown_Pad_Rotate_Picture, "Up/Down Pad: Rotate Picture")
+lang(285, Left_Joystick_Panorama, "Left Joystick: Panorama")
+lang(286, Right_Joystick_Vertical_Zoom, "Right Joystick Vertical: Zoom")
+lang(287, FullScreen_Mode, "FullScreen Mode")
+lang(288, Exit_To_Jpg_Browser, "Exit To Jpg Browser")
+lang(289, Jpg_Viewer, "Jpg Viewer")
+lang(290, Picture, "Picture")
+lang(291, Size, "Size")
+lang(292, Command_List, "Command List")
+lang(293, Timer, "Timer")
+lang(294, Transition, "Transition")
+lang(295, Zoom, "Zoom")
+lang(296, Fade, "Fade")
+lang(297, ZoomFade, "Zoom+Fade")
+//--------------------------------------------------------------
+// Startup Setting Font file Added
+lang(298, Font_File, "Font File")
+//--------------------------------------------------------------
+// New MISC entry for debug info
+// Note that substrings in that info screen should NEVER have
+// any language definitions made for them, as they can and will
+// differ between versions, depending on current debug needs.
+// So only the name of the MISC entry itself should be defined.
+lang(299, Debug_Info, "Debug Info")
+//--------------------------------------------------------------
+// New FileBrowser display modes and sort modes added
+lang(300, Mode, "Mode")
+lang(301, Show_Content_as, "Show Content as")
+lang(302, Filename, "Filename")
+lang(303, Game_Title, "Game Title")
+lang(304, _plus_Details, " + Details")
+lang(305, Sort_Content_by, "Sort Content by")
+lang(306, No_Sort, "No Sort")
+lang(307, Timestamp, "Timestamp")
+lang(308, Back_to_Browser, "Back to Browser")
+//--------------------------------------------------------------
+// New Icon setup command added
+lang(309, New_Icon, "New Icon")
+lang(310, file_alredy_exists, "file already exists")
+lang(311, Icon_Title, "Icon Title")
+lang(312, IconText, "IconText")
+//--------------------------------------------------------------
+lang(313, KB_RETURN, "RETURN")
+//--------------------------------------------------------------
+// New GUI Skin option added
+lang(314, GUI, "GUI")
+lang(315, Apply_GUI_Skin, "Apply GUI Skin")
+lang(316, Skin_Preview, "Skin Preview")
+lang(317, Halt, "Halt") // Alternative Halted text, added for main screen skinning purposes, only appears when main screen skin is active
+lang(318, Delay, "Delay")// Same reason as above
+lang(319, Show_Menu, "Show Menu")
+//---------------------------------------------------------------------------
+// New skin file commands added
+lang(320, Load_Skin_CNF, "Load Skin CNF")
+lang(321, Save_Skin_CNF, "Save Skin CNF")
+//---------------------------------------------------------------------------
+// New FileBrowser command for virtual memory cards
+lang(322, Mount, "Mount")
+//---------------------------------------------------------------------------
+// New MISC entry for "About uLE" screen display
+lang(323, About_uLE, "About uLE")
+//---------------------------------------------------------------------------
+//End of file:  lang.h
+//---------------------------------------------------------------------------
Index: ps2launchargs/source/uLaunchELF/launchelf.h
===================================================================
--- ps2launchargs/source/uLaunchELF/launchelf.h	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/launchelf.h	(revision 1101)
@@ -0,0 +1,402 @@
+#ifndef LAUNCHELF_H
+#define LAUNCHELF_H
+
+#define ULE_VERSION "v4.40h"
+#define ULE_VERDATE "2010.02.12"
+
+#include <stdio.h>
+#include <tamtypes.h>
+#include <sifcmd.h>
+#include <kernel.h>
+#include <sifrpc.h>
+#include <loadfile.h>
+#include <string.h>
+#include <malloc.h>
+#include <libhdd.h>
+#include <libmc.h>
+#include <libpad.h>
+#include <fileio.h>
+#include <sys/stat.h>
+#include <iopheap.h>
+#include <errno.h>
+#include <fileXio_rpc.h>
+#include <iopcontrol.h>
+#include <stdarg.h>
+#include <sbv_patches.h>
+#include <slib.h>
+#include <smem.h>
+#include <smod.h>
+#include <sys/fcntl.h>
+#include <debug.h>
+#include <gsKit.h>
+#include <dmaKit.h>
+#include <cdvd_rpc.h>
+#include "cd.h"
+//#include "mass_rpc.h" //disused in switch to usbhdfsd
+#include "iopmod_name.h"
+#include <libjpg.h>
+#include <libkbd.h>
+#include <floatlib.h>
+#include "hdl_rpc.h"
+
+#define TRUE		1
+#define FALSE		0
+
+enum {  // cnfmode values for getFilePath in browsing for configurable file paths
+	NON_CNF = 0,    	// Normal browser mode, not configuration mode
+	LK_ELF_CNF,     	// Normal ELF choice for launch keys
+	USBD_IRX_CNF,   	// USBD.IRX choice for startup
+	SKIN_CNF,       	// Skin JPG choice
+	GUI_SKIN_CNF,   	// GUI Skin JPG choice
+	USBKBD_IRX_CNF, 	// USB keyboard IRX choice (only PS2SDK)
+  KBDMAP_FILE_CNF,	// USB keyboard mapping table choice
+  CNF_PATH_CNF,   	// CNF Path override choice
+  TEXT_CNF,       	// No restriction choice 
+  DIR_CNF,        	// Directory choice 
+  JPG_CNF,					// Jpg viewer choice
+	USBMASS_IRX_CNF,	// USB_MASS.IRX choice for startup
+	LANG_CNF,					// Language file choice
+	FONT_CNF,					// Font file choice ( .fnt )
+	SAVE_CNF,					// Generic Save choice (with or without selected file)
+  CNFMODE_CNT     	// Total number of cnfmode values defined
+};
+
+enum
+{
+	SCREEN_MARGIN = 16,
+	FONT_WIDTH = 8,
+	FONT_HEIGHT = 16,
+	LINE_THICKNESS = 3,
+	
+	MAX_NAME = 256,
+	MAX_PATH = 1025,
+	MAX_ENTRY = 2048,
+	MAX_PARTITIONS=500,
+	MAX_MENU_TITLE = 40,
+	MAX_ELF_TITLE = 72,
+	MAX_TEXT_LINE = 80
+};
+
+typedef struct
+{
+	char CNF_Path[MAX_PATH];
+	char LK_Path[16][MAX_PATH];
+	char LK_Title[16][MAX_ELF_TITLE];
+	int  LK_Flag[16];
+	char Misc[64];
+	char Misc_PS2Disc[64];
+	char Misc_FileBrowser[64];
+	char Misc_PS2Browser[64];
+	char Misc_PS2Net[64];
+	char Misc_PS2PowerOff[64];
+	char Misc_HddManager[64];
+	char Misc_TextEditor[64];
+	char Misc_JpgViewer[64];
+	char Misc_Configure[64];
+	char Misc_Load_CNFprev[64];
+	char Misc_Load_CNFnext[64];
+	char Misc_Set_CNF_Path[64];
+	char Misc_Load_CNF[64];
+	char Misc_ShowFont[64];
+	char Misc_Debug_Info[64];
+	char Misc_About_uLE[64];
+	char usbd_file[MAX_PATH];
+	char usbkbd_file[MAX_PATH];
+	char usbmass_file[MAX_PATH];
+	char kbdmap_file[MAX_PATH];
+	char skin[MAX_PATH];
+	char GUI_skin[MAX_PATH];
+	char Menu_Title[MAX_MENU_TITLE+1];
+	char lang_file[MAX_PATH];
+	char font_file[MAX_PATH];
+	int  Menu_Frame;
+	int Show_Menu;
+	int timeout;
+	int Hide_Paths;
+	u64 color[8];
+	int screen_x;
+	int screen_y;
+	int discControl;
+	int interlace;
+	int resetIOP;
+	int numCNF;
+	int swapKeys;
+	int HOSTwrite;
+	int Brightness;
+	int TV_mode;
+	int Popup_Opaque;
+	int Init_Delay;
+	int usbkbd_used;
+	int Show_Titles;
+	int PathPad_Lock;
+	int JpgView_Timer;
+	int JpgView_Trans;
+	int JpgView_Full;
+	int PSU_HugeNames;
+	int PSU_DateNames;
+	int PSU_NoOverwrite;
+	int FB_NoIcons;
+} SETTING;
+
+typedef struct
+{
+	int ip[4];
+	int nm[4];
+	int gw[4];
+} data_ip_struct;
+
+extern char LaunchElfDir[MAX_PATH], LastDir[MAX_NAME];
+
+/* main.c */
+extern int TV_mode;
+extern int swapKeys;
+extern int GUI_active;// Skin and Main Skin switch
+extern CdvdDiscType_t cdmode; //Last detected disc type
+
+void load_vmcfs(void);
+void load_ps2host(void);
+void loadCdModules(void);
+void loadUsbModules(void);
+void loadHddModules(void);
+void loadHdlInfoModule(void);
+void setupPowerOff(void);
+int uLE_related(char *pathout, char *pathin);
+int uLE_detect_TV_mode();
+int exists(char *path);
+int uLE_cdDiscValid(void);
+int uLE_cdStop(void);
+
+/* elf.c */
+int checkELFheader(char *filename);
+void RunLoaderElf(char *filename, char *);
+
+/* draw.c */
+#define BACKGROUND_PIC	0
+#define PREVIEW_PIC			1
+#define JPG_PIC					2
+#define THUMB_PIC				3
+#define PREVIEW_GUI			4
+
+#define FOLDER          0
+#define WARNING         1
+
+unsigned char icon_folder[1024];
+unsigned char icon_warning[1024];
+
+extern GSGLOBAL  *gsGlobal;
+extern GSTEXTURE TexSkin, TexPreview, TexPicture, TexThumb[MAX_ENTRY], TexIcon[2];
+extern int      testskin, testsetskin, testjpg, testthumb;
+extern float     PicWidth, PicHeight, PicW, PicH, PicCoeff;
+extern int      SCREEN_WIDTH;
+extern int      SCREEN_HEIGHT;
+extern int      SCREEN_X;
+extern int      SCREEN_Y;
+extern int			Menu_start_x;
+extern int			Menu_title_y;
+extern int			Menu_message_y;
+extern int			Frame_start_y;
+extern int			Menu_start_y;
+extern int			Menu_end_y;
+extern int			Frame_end_y;
+extern int			Menu_tooltip_y;
+extern u64      BrightColor;
+extern int      PicRotate, FullScreen;
+extern u8       FontBuffer[256*16];
+
+void setScrTmp(const char *msg0, const char *msg1);
+void drawSprite( u64 color, int x1, int y1, int x2, int y2 );
+void drawPopSprite( u64 color, int x1, int y1, int x2, int y2 );
+void drawOpSprite( u64 color, int x1, int y1, int x2, int y2 );
+void drawMsg(const char *msg);
+void drawLastMsg(void);
+void setupGS(int gs_vmode);
+void updateScreenMode(int adapt_XY);
+void clrScr(u64 color);
+void setBrightness(int Brightness);
+void loadSkin(int Picture, char *Path, int ThumbNum);
+void drawScr(void);
+void drawFrame(int x1, int y1, int x2, int y2, u64 color);
+void drawChar(unsigned int c, int x, int y, u64 colour);
+int printXY(const unsigned char *s, int x, int y, u64 colour, int draw, int space);
+int printXY_sjis(const unsigned char *s, int x, int y, u64 colour, int);
+u8 *transcpy_sjis(u8 *d, u8 *s);
+void loadIcon(void);
+int loadFont(char *path_arg);
+//Comment out WriteFont_C when not used (also requires patch in draw.c)
+//int	WriteFont_C(char *pathname);
+
+/* pad.c */
+#define PAD_R3_V0 0x010000
+#define PAD_R3_V1 0x020000
+#define PAD_R3_H0 0x040000
+#define PAD_R3_H1 0x080000
+#define PAD_L3_V0 0x100000
+#define PAD_L3_V1 0x200000
+#define PAD_L3_H0 0x400000
+#define PAD_L3_H1 0x800000
+
+extern u32 joy_value;
+extern u32 new_pad;
+int setupPad(void);
+int readpad(void);
+int readpad_no_KB(void);
+int readpad_noRepeat(void);
+void waitPadReady(int port, int slot);
+void waitAnyPadReady(void);
+
+/* config.c */
+#define TV_mode_AUTO 0
+#define TV_mode_NTSC 1
+#define TV_mode_PAL  2
+
+extern char PathPad[30][MAX_PATH];
+extern SETTING *setting;
+void initConfig(void);
+int loadConfig(char *, char *);  //0==OK, -1==load failed
+void config(char *, char *);
+int	get_CNF_string(unsigned char **CNF_p_p,
+                   unsigned char **name_p_p,
+                   unsigned char **value_p_p); //main CNF name,value parser
+unsigned char *preloadCNF(char *path); //loads file into RAM it allocates
+
+/* filer.c */
+typedef struct{
+	char name[MAX_NAME];
+	char title[32*2+1];
+	mcTable stats;
+} FILEINFO;
+
+#define MOUNT_LIMIT 4
+extern char mountedParty[MOUNT_LIMIT][MAX_NAME];
+extern int latestMount;
+extern int vmcMounted[2];
+extern int vmc_PartyIndex[2]; //PFS index for each VMC, unless -1
+extern int Party_vmcIndex[MOUNT_LIMIT]; //VMC index for each PFS, unless -1
+extern int nparties; //Clearing this causes FileBrowser to refresh party list
+extern unsigned char *elisaFnt;
+char *PathPad_menu(const char *path);
+int getFilePath(char *out, const int cnfmode);
+void	initHOST(void);
+char *makeHostPath(char *dp, char*sp);
+int ynDialog(const char *message);
+void nonDialog(char *message);
+int keyboard(char *out, int max);
+void genInit(void);
+void genLimObjName(char *uLE_path, int reserve);
+int genFixPath(char *uLE_path, char *gen_path);
+int genOpen(char *path, int mode);
+int genLseek(int fd, int where, int how);
+int genRead(int fd, void *buf, int size);
+int genWrite(int fd, void *buf, int size);
+int genClose(int fd);
+int genDopen(char *path);
+int genDclose(int fd);
+int genRemove(char *path);
+int genRmdir(char *path);
+int mountParty(const char *party);
+void unmountParty(int party_ix);
+void unmountAll(void);
+int setFileList(const char *path, const char *ext, FILEINFO *files, int cnfmode);
+
+/* hdd.c */
+void DebugDisp(char *Message);
+void hddManager(void);
+
+/* editor.c */
+void TextEditor(void);
+
+/* timer.c */
+extern u64 WaitTime;
+extern u64 CurrTime;
+
+void TimerInit(void);
+u64  Timer(void);
+void TimerEnd(void);
+
+/* jpgviewer.c */
+void JpgViewer(void);
+
+/* lang.c */
+typedef struct Language{
+	u8* String;
+} Language;
+
+enum {
+#define lang(id, name, value) LANG_##name,
+#include "lang.h"
+#undef lang
+	LANG_COUNT
+};
+
+#define LNG(name) Lang_String[LANG_##name].String
+#define LNG_DEF(name) Lang_Default[LANG_##name].String
+
+extern Language Lang_String[];
+extern Language Lang_Default[];
+extern Language *External_Lang_Buffer;
+
+void Init_Default_Language(void);
+void Load_External_Language(void);
+
+/* font_uLE.c */
+
+extern unsigned char font_uLE[];
+enum {
+//0x100-0x109 are 5 double width characters for D-Pad buttons, which are accessed as:
+//"ÿ0"==Circle  "ÿ1"==Cross  "ÿ2"==Square  "ÿ3"==Triangle  "ÿ4"==filled Square
+	RIGHT_CUR = 0x10A, //Triangle pointing left, for use to the right of an item
+	LEFT_CUR  = 0x10B, //Triangle pointing right, for use to the left of an item
+	UP_ARROW  = 0x10C, //Arrow pointing up
+	DN_ARROW  = 0x10D, //Arrow pointing up
+	LT_ARROW  = 0x10E, //Arrow pointing up
+	RT_ARROW  = 0x10F, //Arrow pointing up
+	TEXT_CUR  = 0x110, //Vertical bar, for use between two text characters
+	UL_ARROW  = 0x111, //Arrow pointing up and to the left, from a vertical start.
+	BR_SPLIT  = 0x112, //Splits rectangle from BL to TR with BR portion filled
+	BL_SPLIT  = 0x113, //Splits rectangle from TL to BR with BL portion filled
+//0x114-0x11B are 4 double width characters for D-Pad buttons, which are accessed as:
+//"ÿ:"==Right  "ÿ;"==Down  "ÿ<"==Left  "ÿ="==Up
+//0x11C-0x123 are 4 doubled characters used as normal/marked folder/file icons
+	ICON_FOLDER = 0x11C,
+	ICON_M_FOLDER = 0x11E,
+	ICON_FILE = 0x120,
+	ICON_M_FILE = 0x122,
+	FONT_COUNT= 0x124  //Total number of characters in font
+};
+
+/* makeicon.c */
+int make_icon(char* icontext,char* filename);
+int make_iconsys(char* title,char* iconname, char* filename);
+
+
+//vmcfs definitions
+
+//  The devctl commands: 0x56 == V, 0x4D == M, 0x43 == C, 0x01, 0x02, ... == command number.
+#define DEVCTL_VMCFS_CLEAN   0x564D4301 //  Set as free all fat cluster corresponding to a none existing object. ( Object are just marked as none existing but not removed from fat table when rmdir or remove fonctions are call. This allow to recover a deleted file. )
+#define DEVCTL_VMCFS_CKFREE  0x564D4302 //  Check free space available on vmc. 
+
+//  The ioctl commands: 0x56 == V, 0x4D == M, 0x43 == C, 0x01, 0x02, ... == command number.
+#define IOCTL_VMCFS_RECOVER  0x564D4303 //  Recover an object marked as none existing. ( data must be a valid path to an object in vmc file ) 
+
+//  Vmc format enum
+typedef enum {
+   FORMAT_FULL, 
+   FORMAT_FAST
+} Vmc_Format_Enum;
+
+
+// chkesr_rpc.c
+extern int  chkesr_rpc_Init(void);
+extern int  Check_ESR_Disc(void);
+
+//USB_mass definitions for multiple drive usage
+
+#define USB_MASS_MAX_DRIVES 10
+
+extern	char	USB_mass_ix[10];
+extern	int		USB_mass_max_drives;
+extern	u64		USB_mass_scan_time;
+extern	int		USB_mass_scanned;
+extern	int		USB_mass_loaded;    //0==none, 1==internal, 2==external
+
+#endif
Index: ps2launchargs/source/uLaunchELF/loader/Makefile
===================================================================
--- ps2launchargs/source/uLaunchELF/loader/Makefile	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/loader/Makefile	(revision 1101)
@@ -0,0 +1,43 @@
+ EE_INCS := $(EE_INCS) -I$(PS2SDK)/sbv/include
+
+EE_CFLAGS  := -mips3 -ffreestanding -fno-builtin -G0 \
+		-fshort-double -mlong64 -mhard-float -mno-abicalls -O2 -EL -Wall \
+		$(EE_INCS) $(EE_CFLAGS)
+
+EE_ASFLAGS := -EL -G0 $(EE_ASFLAGS)
+
+###dlanor: adjust these three, for PS2Link compatibility tests
+###dlanor: old LaunchELF used LA=0x90000, SA=0xB0000, SS=0x08000
+###dlanor: The values below were implemented in LaunchELF v3.50
+LOADADDR  = 0x90000
+STACKADDR = 0xA8000
+STACKSIZE = 0x04000
+
+ifeq ($(DEBUG),1)
+LOADADDR  = 0x1700000
+STACKADDR = 0x1720000
+STACKSIZE = 0x08000
+endif
+
+LDPARAMS := -Wl,--defsym -Wl,_stack_size=$(STACKSIZE) -Wl,--defsym -Wl,_stack=$(STACKADDR)
+
+EE_LDFLAGS += -Wl,-Ttext -Wl,$(LOADADDR) -s $(LDPARAMS)
+
+EE_LDFLAGS := $(EE_LDFLAGS) -L$(PS2SDK)/sbv/lib \
+
+EE_BIN = loader.elf
+
+EE_OBJS = loader.o
+
+EE_LIBS = -lfileXio -lpatches
+ifeq ($(DEBUG),1)
+EE_LIBS += -ldebug
+endif
+
+all: $(EE_BIN)
+
+clean:
+	rm -f *.o *.a *.s *.elf
+
+include $(PS2SDK)/samples/Makefile.pref
+include $(PS2SDK)/samples/Makefile.eeglobal
Index: ps2launchargs/source/uLaunchELF/loader/loader.c
===================================================================
--- ps2launchargs/source/uLaunchELF/loader/loader.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/loader/loader.c	(revision 1101)
@@ -0,0 +1,388 @@
+//--------------------------------------------------------------
+//File name:    loader.c
+//--------------------------------------------------------------
+//dlanor: This subprogram has been modified to minimize the code
+//dlanor: size of the resident loader portion. Some of the parts
+//dlanor: that were moved into the main program include loading
+//dlanor: of all IRXs and mounting pfs0: for ELFs on hdd.
+//dlanor: Another change was to skip threading in favor of ExecPS2
+/*==================================================================
+==											==
+==	Copyright(c)2004  Adam Metcalf(gamblore_@hotmail.com)		==
+==	Copyright(c)2004  Thomas Hawcroft(t0mb0la@yahoo.com)		==
+==	This file is subject to terms and conditions shown in the	==
+==	file LICENSE which should be kept in the top folder of	==
+==	this distribution.							==
+==											==
+==	Portions of this code taken from PS2Link:				==
+==				pkoLoadElf						==
+==				wipeUserMemory					==
+==				(C) 2003 Tord Lindstrom (pukko@home.se)	==
+==				(C) 2003 adresd (adresd_ps2dev@yahoo.com)	==
+==	Portions of this code taken from Independence MC exploit	==
+==				tLoadElf						==
+==				LoadAndRunHDDElf					==
+==				(C) 2003 Marcus Brown <mrbrown@0xd6.org>	==
+==											==
+==================================================================*/
+#include "tamtypes.h"
+#include "debug.h"
+#include "kernel.h"
+#include "sifrpc.h"
+#include "loadfile.h"
+#include "fileio.h"
+#include "iopcontrol.h"
+#include "stdarg.h"
+#include "stdio.h" // Iritscen: added this for printf()
+#include "string.h"
+#include "malloc.h"
+#include "libmc.h"
+#include "iopheap.h"
+#include "sys/fcntl.h"
+#include "sys/stat.h"
+#include "sys/ioctl.h"
+#include "fileXio_rpc.h"
+#include "errno.h"
+#include "libhdd.h"
+#include "sbv_patches.h"
+//--------------------------------------------------------------
+//#define DEBUG
+#ifdef DEBUG
+#define dbgprintf(args...) scr_printf(args)
+#define dbginit_scr() init_scr()
+#else
+#define dbgprintf(args...) do { } while(0)
+#define dbginit_scr() do { } while(0)
+#endif
+
+// ELF-header structures and identifiers
+#define ELF_MAGIC	0x464c457f
+#define ELF_PT_LOAD	1
+
+//--------------------------------------------------------------
+typedef struct
+{
+	u8	ident[16];
+	u16	type;
+	u16	machine;
+	u32	version;
+	u32	entry;
+	u32	phoff;
+	u32	shoff;
+	u32	flags;
+	u16	ehsize;
+	u16	phentsize;
+	u16	phnum;
+	u16	shentsize;
+	u16	shnum;
+	u16	shstrndx;
+	} elf_header_t;
+//--------------------------------------------------------------
+typedef struct
+{
+	u32	type;
+	u32	offset;
+	void	*vaddr;
+	u32	paddr;
+	u32	filesz;
+	u32	memsz;
+	u32	flags;
+	u32	align;
+	} elf_pheader_t;
+//--------------------------------------------------------------
+t_ExecData elfdata;
+
+int fileMode =  FIO_S_IRUSR | FIO_S_IWUSR | FIO_S_IXUSR | FIO_S_IRGRP | FIO_S_IWGRP | FIO_S_IXGRP | FIO_S_IROTH | FIO_S_IWOTH | FIO_S_IXOTH;
+char HDDpath[256];
+char partition[128];
+
+static int pkoLoadElf(char *path);
+
+int userThreadID = 0;
+////static char userThreadStack[16*1024] __attribute__((aligned(16)));
+
+#define MAX_ARGS 16
+#define MAX_ARGLEN 256
+
+struct argData
+{
+	int flag;                     // Contains thread id atm
+	int argc;
+	char *argv[MAX_ARGS];
+} __attribute__((packed)) userArgs;
+//--------------------------------------------------------------
+//End of data declarations
+//--------------------------------------------------------------
+//Start of function code:
+//--------------------------------------------------------------
+// Read ELF from hard drive to required location(s) in memory.
+// Modified version of loader from Independence
+//	(C) 2003 Marcus R. Brown <mrbrown@0xd6.org>
+//--------------------------------------------------------------
+static int tLoadElf(char *filename)
+{
+	u8 *boot_elf = (u8 *)0x1800000;
+	elf_header_t *eh = (elf_header_t *)boot_elf;
+	elf_pheader_t *eph;
+
+	int fd, size, i;
+
+//NB: Coming here means pfs0: was mounted correctly earlier
+	if ((fd = fileXioOpen(filename, O_RDONLY, fileMode)) < 0)
+	{
+		dbgprintf("Failed in fileXioOpen %s\n",filename);
+		goto error;
+	}
+	dbgprintf("Opened file %s\n",filename);
+	size = fileXioLseek(fd, 0, SEEK_END);
+	dbgprintf("File size = %i\n",size);
+	if (!size)
+	{
+		dbgprintf("Failed in fileXioLseek\n");
+		fileXioClose(fd);
+		goto error;
+		}
+	fileXioLseek(fd, 0, SEEK_SET);
+	fileXioRead(fd, boot_elf, sizeof(elf_header_t));
+	dbgprintf("Read elf header from file\n");
+	fileXioLseek(fd, eh->phoff, SEEK_SET);
+	eph = (elf_pheader_t *)(boot_elf + eh->phoff);
+	size=eh->phnum*eh->phentsize;
+	size=fileXioRead(fd, (void *)eph, size);
+	dbgprintf("Read %i bytes of program header(s) from file\n",size);
+	for (i = 0; i < eh->phnum; i++)
+	{
+		if (eph[i].type != ELF_PT_LOAD)
+		continue;
+
+		fileXioLseek(fd, eph[i].offset, SEEK_SET);
+		size=eph[i].filesz;
+		size=fileXioRead(fd, eph[i].vaddr, size);
+		dbgprintf("Read %i bytes to %x\n", size, eph[i].vaddr);
+		if (eph[i].memsz > eph[i].filesz)
+			memset(eph[i].vaddr + eph[i].filesz, 0,
+			       eph[i].memsz - eph[i].filesz);
+	}		
+
+	fileXioClose(fd);
+//	fileXioUmount("pfs0:");		We leave the filesystem mounted now for fakehost
+
+	if (_lw((u32)&eh->ident) != ELF_MAGIC)		// this should have already been
+	{                                         // done by menu, but a double-check
+		dbgprintf("Not a recognised ELF.\n");   // doesn't do any harm
+		goto error;
+	}
+	
+	dbgprintf("entry=%x\n",eh->entry);
+	elfdata.epc=eh->entry;
+	return 0;
+error:
+	elfdata.epc=0;
+	return -1;
+}
+//--------------------------------------------------------------
+//End of func:  int tLoadElf(char *filename)
+//--------------------------------------------------------------
+// Load the actual elf, and create a thread for it
+// Return the thread id
+// PS2Link (C) 2003 Tord Lindstrom (pukko@home.se)
+//         (C) 2003 adresd (adresd_ps2dev@yahoo.com)
+//--------------------------------------------------------------
+static int pkoLoadElf(char *path)
+{
+	ee_thread_t th_attr;
+	int ret=0;
+	int pid;
+
+	if(!strncmp(path, "host", 4)) ret = SifLoadElf(path, &elfdata);
+	else if(!strncmp(path, "mc", 2)) ret = SifLoadElf(path, &elfdata);
+	else if(!strncmp(path, "cdrom", 5)) ret = SifLoadElf(path, &elfdata);
+	else if(!strncmp(path, "cdfs", 4)) ret = SifLoadElf(path, &elfdata);
+	else if(!strncmp(path, "pfs0", 4)) ret = tLoadElf(path);
+	else if(!strncmp(path, "vmc", 3)) ret = tLoadElf(path);
+	else ret = SifLoadElf(path, &elfdata);
+
+	FlushCache(0);
+	FlushCache(2);
+
+	dbgprintf("EE: LoadElf returned %d\n", ret);
+
+	dbgprintf("EE: Creating user thread (ent: %x, gp: %x, st: %x)\n", 
+	          elfdata.epc, elfdata.gp, elfdata.sp);
+
+	if (elfdata.epc == 0) {
+		dbgprintf("EE: Could not load file\n");
+		return -1;
+	}
+
+	th_attr.func = (void *)elfdata.epc;
+////	th_attr.stack = userThreadStack;
+////	th_attr.stack_size = sizeof(userThreadStack);
+	th_attr.gp_reg = (void *)elfdata.gp;
+	th_attr.initial_priority = 64;
+
+	pid = 1; ////CreateThread(&th_attr);
+	if (pid < 0) {
+		dbgprintf("EE: Create user thread failed %d\n", pid);
+		return -1;
+	}
+	dbgprintf("EE: Created user thread: %d\n", pid);
+
+	return pid;
+}
+//--------------------------------------------------------------
+//End of func:  static int pkoLoadElf(char *path)
+//--------------------------------------------------------------
+// Clear user memory
+// PS2Link (C) 2003 Tord Lindstrom (pukko@home.se)
+//         (C) 2003 adresd (adresd_ps2dev@yahoo.com)
+//--------------------------------------------------------------
+void wipeUserMem(void)
+{
+	int i;
+	for (i = 0x100000; i < 0x2000000 ; 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) );
+	}
+}
+//--------------------------------------------------------------
+//End of func:  void wipeUserMem(void)
+//--------------------------------------------------------------
+// C standard strrchr func.. returns pointer to the last occurance of a
+// character in a string, or NULL if not found
+// PS2Link (C) 2003 Tord Lindstrom (pukko@home.se)
+//         (C) 2003 adresd (adresd_ps2dev@yahoo.com)
+//--------------------------------------------------------------
+char *strrchr(const char *sp, int i)
+{
+	const char *last = NULL;
+	char c = i;
+
+	while (*sp)
+	{
+		if (*sp == c)
+		{
+			last = sp;
+		}
+		sp++;
+	}
+
+	if (*sp == c)
+	{
+		last = sp;
+	}
+
+	return (char *) last;
+}
+//--------------------------------------------------------------
+//End of func:  char *strrchr(const char *sp, int i)
+//--------------------------------------------------------------
+// *** MAIN ***
+//--------------------------------------------------------------
+int main(int argc, char *argv[])
+{
+	char s[256],fakepart[128], *ptr;
+	int pid=-1;
+
+// Initialize
+	SifInitRpc(0);
+	dbginit_scr();
+	wipeUserMem();
+	dbgprintf("Welcome to Loader of LaunchELF v3.50\nPlease wait...loading.\n");
+
+	strcpy(s,argv[0]);
+	dbgprintf("argv[0] = %s\n",s);
+    /*if (argc==1) // Iritscen: Commented this out and changed "(argc==2)" to "(argc>=2)" below in order to allow add'l args
+	{						// should be two params passed by menu
+		while(1);				// leave this here for adding mc0, host or other
+							// to be added in future
+	}*/
+	if (argc>=2)				// if call came from hddmenu.elf
+	{						// arg1=path to ELF, arg2=partition to mount
+		strcpy(partition,argv[1]);
+		dbgprintf("argv[1] = %s\n", partition);
+		strcpy(HDDpath,s);
+	}
+	dbgprintf("Loading %s\n",HDDpath);
+	pid = pkoLoadElf(HDDpath);
+	dbgprintf("pkoLoadElf returned %i\n",pid);
+////	if (pid < 0)
+////	{
+////		dbgprintf("failed\n");
+////		dbgprintf("Could not execute file %s\n", HDDpath);
+////		return -1;
+////	}
+	if(!strncmp(HDDpath, "pfs0", 4))
+	{
+		strcpy(fakepart,HDDpath);
+		ptr=strrchr(fakepart,'/');
+		if(ptr==NULL) strcpy(fakepart,"pfs0:");
+		else
+		{
+			ptr++;
+			*ptr='\0';
+		}
+		ptr=strrchr(s,'/');
+		if(ptr==NULL) ptr=strrchr(s,':');
+		if(ptr!=NULL)
+		{
+			ptr++;
+			strcpy(HDDpath,"host:");
+			strcat(HDDpath,ptr);
+		}
+	}
+	
+////	FlushCache(0);
+////	FlushCache(2);
+	
+	userThreadID = pid;
+
+	// Iritscen: Copy extra arguments in argv[] to userArgs
+	if (argc > 2)
+	{
+		printf("uLaunchELF loader: Received %d launch argument(s) for the game:\n", argc - 2);
+		userArgs.argc = argc - 1;
+		userArgs.argv[0] = HDDpath;
+		int a;
+		for (a = 0; a < argc - 2; a++)
+		{
+			userArgs.argv[a + 1] = argv[a + 2];
+			printf("   %s\n", argv[a + 2]);
+		}
+	}
+	userArgs.flag = (int)&userThreadID;
+
+////	ret = StartThread(userThreadID, &userArgs);
+////	if (ret < 0)
+////	{
+////		dbgprintf("failed\n");
+////		dbgprintf("EE: Start user thread failed %d\n", ret);
+////		DeleteThread(userThreadID);
+////		return -1;
+////	}
+////	SleepThread();
+	
+	__asm__ __volatile__(
+		".set  noreorder\n\t"
+		"jal     FlushCache\n\t"
+		"li      $a0, 0\n\t"
+		"jal     FlushCache\n\t"
+		"li      $a0, 2\n\t"
+		"lui     $sp, 0x000a\n\t"
+		"nop\n\t"
+		"addiu   $sp, $sp, 0x8000\n\t"
+		"nop\n\t"
+		".set  reorder\n\t"
+	);
+	ExecPS2((void *)elfdata.epc, (void *)elfdata.gp, userArgs.argc, userArgs.argv);
+	return 0;
+}
+//--------------------------------------------------------------
+//End of func:  int main(int argc, char *argv[])
+//--------------------------------------------------------------
+//End of file:  loader.c
+//--------------------------------------------------------------
Index: ps2launchargs/source/uLaunchELF/main.c
===================================================================
--- ps2launchargs/source/uLaunchELF/main.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/main.c	(revision 1101)
@@ -0,0 +1,2237 @@
+//---------------------------------------------------------------------------
+//File name:   main.c
+//---------------------------------------------------------------------------
+#include "launchelf.h"
+
+//dlanor: I'm correcting all these erroneous 'u8 *name' declarations
+//dlanor: They are not pointers at all, but pure block addresses
+//dlanor: Thus they should be declared as 'void name'
+extern void iomanx_irx;
+extern int  size_iomanx_irx;
+extern void filexio_irx;
+extern int  size_filexio_irx;
+extern void ps2dev9_irx;
+extern int  size_ps2dev9_irx;
+extern void ps2ip_irx;
+extern int  size_ps2ip_irx;
+extern void ps2smap_irx;
+extern int  size_ps2smap_irx;
+extern void smsutils_irx;
+extern int  size_smsutils_irx;
+extern void ps2host_irx;
+extern int  size_ps2host_irx;
+extern void vmcfs_irx;
+extern int  size_vmcfs_irx;
+extern void ps2ftpd_irx;
+extern int  size_ps2ftpd_irx;
+extern void ps2atad_irx;
+extern int  size_ps2atad_irx;
+extern void ps2hdd_irx;
+extern int  size_ps2hdd_irx;
+extern void ps2fs_irx;
+extern int  size_ps2fs_irx;
+extern void poweroff_irx;
+extern int  size_poweroff_irx;
+extern void loader_elf;
+extern int  size_loader_elf;
+extern void ps2netfs_irx;
+extern int  size_ps2netfs_irx;
+extern void iopmod_irx;
+extern int  size_iopmod_irx;
+extern void usbd_irx;
+extern int  size_usbd_irx;
+extern void usb_mass_irx;
+extern int  size_usb_mass_irx;
+extern void cdvd_irx;
+extern int  size_cdvd_irx;
+extern void ps2kbd_irx;
+extern int  size_ps2kbd_irx;
+extern void hdl_info_irx;
+extern int  size_hdl_info_irx;
+extern void chkesr_irx;
+extern int size_chkesr_irx;
+//extern void mcman_irx;
+//extern int  size_mcman_irx;
+//extern void mcserv_irx;
+//extern int  size_mcserv_irx;
+
+//#define DEBUG
+#ifdef DEBUG
+#define dbgprintf(args...) scr_printf(args)
+#define dbginit_scr() init_scr()
+#else
+#define dbgprintf(args...) do { } while(0)
+#define dbginit_scr() do { } while(0)
+#endif
+
+enum
+{
+	BUTTON,
+	DPAD
+};
+
+void Reset();
+
+int TV_mode;
+int selected=0;
+int timeout=0, prev_timeout=1;
+int init_delay=0, prev_init_delay=1;
+int poweroff_delay=0; //Set only when calling hddPowerOff
+int mode=BUTTON;
+int user_acted = 0;  /* Set when commands given, to break timeout */
+char LaunchElfDir[MAX_PATH], mainMsg[MAX_PATH];
+char CNF[MAX_NAME];
+int numCNF=0;
+int maxCNF;
+int swapKeys;
+int GUI_active;
+
+u64 WaitTime;
+u64 CurrTime;
+u64 init_delay_start;
+u64 timeout_start;
+u64 poweroff_start;
+
+#define IPCONF_MAX_LEN  (3*16)
+char if_conf[IPCONF_MAX_LEN];
+int if_conf_len;
+
+char ip[16]      = "192.168.0.10";
+char netmask[16] = "255.255.255.0";
+char gw[16]      = "192.168.0.1";
+
+char netConfig[IPCONF_MAX_LEN+64];	//Adjust size as needed
+
+//State of module collections
+int have_NetModules = 0;
+int have_HDD_modules = 0;
+//State of sbv_patches
+int have_sbv_patches = 0;
+//Old State of Checkable Modules (valid header)
+int	old_sio2man  = 0;
+int	old_mcman    = 0;
+int	old_mcserv   = 0;
+int	old_padman   = 0;
+int old_fakehost = 0;
+int old_poweroff = 0;
+int	old_iomanx   = 0;
+int	old_filexio  = 0;
+int	old_ps2dev9  = 0;
+int	old_ps2ip    = 0;
+int	old_ps2atad  = 0;
+int old_ps2hdd   = 0;
+int old_ps2fs    = 0;
+int old_ps2netfs = 0;
+//State of Uncheckable Modules (invalid header)
+int	have_cdvd     = 0;
+int	have_usbd     = 0;
+int	have_usb_mass = 0;
+int	have_ps2smap  = 0;
+int	have_ps2host  = 0;
+int have_vmcfs    = 0; //vmcfs may be checkable. (must ask Polo)
+int	have_ps2ftpd  = 0;
+int	have_ps2kbd   = 0;
+int	have_hdl_info = 0;
+//State of Checkable Modules (valid header)
+int have_urgent   = 0;	//flags presence of urgently needed modules
+int	have_sio2man  = 0;
+int	have_mcman    = 0;
+int	have_mcserv   = 0;
+int	have_padman   = 0;
+int have_fakehost = 0;
+int have_poweroff = 0;
+int	have_iomanx   = 0;
+int	have_filexio  = 0;
+int	have_ps2dev9  = 0;
+int	have_ps2ip    = 0;
+int	have_ps2atad  = 0;
+int have_ps2hdd   = 0;
+int have_ps2fs    = 0;
+int have_ps2netfs = 0;
+
+int have_chkesr   = 0;
+
+int force_IOP = 0; //flags presence of incompatible drivers, so we must reset IOP
+
+int menu_LK[15];  //holds RunElf index for each valid main menu entry
+
+int done_setupPowerOff = 0;
+int ps2kbd_opened = 0;
+
+int boot_argc;
+char *boot_argv[8];
+char boot_path[MAX_PATH];
+
+//Variables for SYSTEM.CNF processing
+int  BootDiscType = 0;
+char SystemCnf_BOOT[MAX_PATH];
+char SystemCnf_BOOT2[MAX_PATH];
+char SystemCnf_VER[10];   //Arbitrary. Real value should always be shorter
+char SystemCnf_VMODE[10]; //Arbitrary, same deal. As yet unused
+
+char default_ESR_path[] = "mc:/BOOT/ESR.ELF";
+
+char ROMVER_data[20]; 	//16 byte file read from rom0:ROMVER at init
+CdvdDiscType_t cdmode;      //Last detected disc type
+CdvdDiscType_t old_cdmode;  //used for disc change detection
+CdvdDiscType_t uLE_cdmode;  //used for smart disc detection
+
+typedef struct{
+	int type;
+	char name[16];
+}	DiscType;
+
+DiscType DiscTypes[] = {
+	{CDVD_TYPE_NODISK,           "!"},
+	{CDVD_TYPE_DETECT,           "??"},
+	{CDVD_TYPE_DETECT_CD,        "CD ?"},
+	{CDVD_TYPE_DETECT_DVDSINGLE, "DVD ?"},
+	{CDVD_TYPE_DETECT_DVDDUAL,   "DVD 2?"},
+	{CDVD_TYPE_UNKNOWN,          "???"},
+	{CDVD_TYPE_PS1CD,            "PS1 CD"},
+	{CDVD_TYPE_PS1CDDA,          "PS1 CDDA"},
+	{CDVD_TYPE_PS2CD,            "PS2 CD"},
+	{CDVD_TYPE_PS2CDDA,          "PS2 CDDA"},
+	{CDVD_TYPE_PS2DVD,           "PS2 DVD"},
+	{CDVD_TYPE_ESRDVD_0,         "ESR DVD (off)"},
+	{CDVD_TYPE_ESRDVD_1,         "ESR DVD (on)"},
+	{CDVD_TYPE_CDDA,             "Audio CD"},
+	{CDVD_TYPE_DVDVIDEO,         "Video DVD"},
+	{CDVD_TYPE_ILLEGAL,          "????"},
+	{0x00,                       ""}//end of list
+}; //ends DiscTypes array
+//---------------------------------------------------------------------------
+//executable code
+//---------------------------------------------------------------------------
+//Function to print a text row to the 'gs' screen
+//------------------------------
+int	PrintRow(int row_f, char *text_p)
+{	static int row;
+	int x = (Menu_start_x + 4);
+	int y;
+
+	if(row_f >= 0) row = row_f;
+	y = (Menu_start_y + FONT_HEIGHT*row++);
+	printXY(text_p, x, y, setting->color[3], TRUE, 0);
+	return row;
+}  
+//------------------------------
+//endfunc PrintRow
+//---------------------------------------------------------------------------
+//Function to print a text row with text positioning
+//------------------------------
+int	PrintPos(int row_f, int column, char *text_p)
+{	static int row;
+	int x = (Menu_start_x + 4 + column*FONT_WIDTH);
+	int y;
+
+	if(row_f >= 0) row = row_f;
+	y = (Menu_start_y + FONT_HEIGHT*row++);
+	printXY(text_p, x, y, setting->color[3], TRUE, 0);
+	return row;
+}  
+//------------------------------
+//endfunc PrintPos
+//---------------------------------------------------------------------------
+//Function to show a screen with debugging info
+//------------------------------
+void ShowDebugInfo(void)
+{	char TextRow[256];
+	int	i, event, post_event=0;
+
+	event = 1;   //event = initial entry
+	//----- Start of event loop -----
+	while(1) {
+		//Pad response section
+		waitAnyPadReady();
+		if(readpad() && new_pad){
+			event |= 2;
+			if (setting->GUI_skin[0]) {
+				GUI_active = 1;
+				loadSkin(BACKGROUND_PIC, 0, 0);
+			}
+			break;
+		}
+
+		//Display section
+		if(event||post_event) { //NB: We need to update two frame buffers per event
+			clrScr(setting->color[0]);
+			PrintRow(0,"Debug Info Screen:");
+			sprintf(TextRow, "rom0:ROMVER == \"%s\"", ROMVER_data);
+			PrintRow(2,TextRow);
+			sprintf(TextRow, "argc == %d", boot_argc);
+			PrintRow(4,TextRow);
+			for(i=0; (i<boot_argc)&&(i<8); i++){
+				sprintf(TextRow, "argv[%d] == \"%s\"", i, boot_argv[i]);
+				PrintRow(-1, TextRow);
+			}
+			sprintf(TextRow, "boot_path == \"%s\"", boot_path);
+			PrintRow(-1, TextRow);
+			sprintf(TextRow, "LaunchElfDir == \"%s\"", LaunchElfDir);
+			PrintRow(-1, TextRow);
+		}//ends if(event||post_event)
+		drawScr();
+		post_event = event;
+		event = 0;
+	} //ends while
+	//----- End of event loop -----
+}
+//------------------------------
+//endfunc ShowDebugInfo
+//---------------------------------------------------------------------------
+//Function to show a screen with program credits ("About uLE")
+//------------------------------
+void Show_About_uLE(void)
+{	char TextRow[256];
+	int	event, post_event=0;
+	int hpos = 16;
+
+	event = 1;   //event = initial entry
+	//----- Start of event loop -----
+	while(1) {
+		//Pad response section
+		waitAnyPadReady();
+		if(readpad() && new_pad){
+			event |= 2;
+			if (setting->GUI_skin[0]) {
+				GUI_active = 1;
+				loadSkin(BACKGROUND_PIC, 0, 0);
+			}
+			break;
+		}
+
+		//Display section
+		if(event||post_event) { //NB: We need to update two frame buffers per event
+			clrScr(setting->color[0]);
+			sprintf(TextRow, "About uLaunchELF %s  %s:", ULE_VERSION, ULE_VERDATE);
+			PrintPos(03,hpos,TextRow);
+			PrintPos(05,hpos,"Project maintainers:");
+			PrintPos(-1,hpos,"  Eric Price       (aka: 'E P')");
+			PrintPos(-1,hpos,"  Ronald Andersson (aka: 'dlanor')");
+			PrintPos(-1,hpos,"");
+			PrintPos(-1,hpos,"Other contributors:");
+			PrintPos(-1,hpos,"  Polo35, radad, Drakonite, sincro");
+			PrintPos(-1,hpos,"  kthu, Slam-Tilt, chip, pixel, Hermes");
+			PrintPos(-1,hpos,"  and others in the PS2Dev community");
+			PrintPos(-1,hpos,"");
+			PrintPos(-1,hpos,"Main release site:");
+			PrintPos(-1,hpos,"  \"http://psx-scene.com/forums/\"");
+			PrintPos(-1,hpos,"");
+			PrintPos(-1,hpos,"Ancestral project: LaunchELF v3.41");
+			PrintPos(-1,hpos,"Created by:        Mirakichi");
+		}//ends if(event||post_event)
+		drawScr();
+		post_event = event;
+		event = 0;
+	} //ends while
+	//----- End of event loop -----
+}
+//------------------------------
+//endfunc Show_About_uLE
+//---------------------------------------------------------------------------
+//Function to check for presence of key modules
+//------------------------------
+void	CheckModules(void)
+{	smod_mod_info_t	mod_t;
+
+	old_sio2man  = (have_sio2man = smod_get_mod_by_name(IOPMOD_NAME_SIO2MAN, &mod_t));
+	old_mcman    = (have_mcman = smod_get_mod_by_name(IOPMOD_NAME_MCMAN, &mod_t));
+	old_mcserv   = (have_mcserv = smod_get_mod_by_name(IOPMOD_NAME_MCSERV, &mod_t));
+	old_padman   = (have_padman = smod_get_mod_by_name(IOPMOD_NAME_PADMAN, &mod_t));
+	old_fakehost = (have_fakehost = smod_get_mod_by_name(IOPMOD_NAME_FAKEHOST, &mod_t));
+	old_poweroff = (have_poweroff = smod_get_mod_by_name(IOPMOD_NAME_POWEROFF, &mod_t));
+	old_iomanx   = (have_iomanx = smod_get_mod_by_name(IOPMOD_NAME_IOMANX, &mod_t));
+	old_filexio  = (have_filexio = smod_get_mod_by_name(IOPMOD_NAME_FILEXIO, &mod_t));
+	old_ps2dev9  = (have_ps2dev9 = smod_get_mod_by_name(IOPMOD_NAME_PS2DEV9, &mod_t));
+	old_ps2ip    = (have_ps2ip = smod_get_mod_by_name(IOPMOD_NAME_PS2IP, &mod_t));
+	old_ps2atad  = (have_ps2atad = smod_get_mod_by_name(IOPMOD_NAME_PS2ATAD, &mod_t));
+	old_ps2hdd   = (have_ps2hdd = smod_get_mod_by_name(IOPMOD_NAME_PS2HDD, &mod_t));
+	old_ps2fs    = (have_ps2fs = smod_get_mod_by_name(IOPMOD_NAME_PS2FS, &mod_t));
+	old_ps2netfs = (have_ps2netfs= smod_get_mod_by_name(IOPMOD_NAME_PS2NETFS, &mod_t));
+}
+//------------------------------
+//endfunc CheckModules
+//---------------------------------------------------------------------------
+// Parse network configuration from IPCONFIG.DAT
+// Now completely rewritten to fix some problems
+//------------------------------
+static void getIpConfig(void)
+{
+	int fd;
+	int i;
+	int len;
+	char c;
+	char buf[IPCONF_MAX_LEN];
+	char path[MAX_PATH];
+
+	if(uLE_related(path, "uLE:/IPCONFIG.DAT")==1)
+		fd = genOpen(path, O_RDONLY);
+	else
+		fd=-1;
+
+	if (fd >= 0) 
+	{	bzero(buf, IPCONF_MAX_LEN);
+		len = genRead(fd, buf, IPCONF_MAX_LEN - 1); //Save a byte for termination
+		genClose(fd);
+	}
+
+	if	((fd >= 0) && (len > 0))
+	{	buf[len] = '\0'; //Ensure string termination, regardless of file content
+		for	(i=0; ((c = buf[i]) != '\0'); i++) //Clear out spaces and any CR/LF
+			if	((c == ' ') || (c == '\r') || (c == '\n'))
+				buf[i] = '\0';
+		strncpy(ip, buf, 15);
+		i = strlen(ip)+1;
+		strncpy(netmask, buf+i, 15);
+		i += strlen(netmask)+1;
+		strncpy(gw, buf+i, 15);
+	}
+
+	bzero(if_conf, IPCONF_MAX_LEN);
+	strncpy(if_conf, ip, 15);
+	i = strlen(ip) + 1;
+	strncpy(if_conf+i, netmask, 15);
+	i += strlen(netmask) + 1;
+	strncpy(if_conf+i, gw, 15);
+	i += strlen(gw) + 1;
+	if_conf_len = i;
+	sprintf(netConfig, "%s:  %-15s %-15s %-15s", LNG(Net_Config), ip, netmask, gw);
+
+}
+//------------------------------
+//endfunc getIpConfig
+//---------------------------------------------------------------------------
+void setLaunchKeys(void)
+{
+	if(!setting->LK_Flag[12])
+		strcpy(setting->LK_Path[12], setting->Misc_Configure);
+	if((maxCNF>1) && !setting->LK_Flag[13])
+		strcpy(setting->LK_Path[13], setting->Misc_Load_CNFprev);
+	if((maxCNF>1) && !setting->LK_Flag[14])
+		strcpy(setting->LK_Path[14], setting->Misc_Load_CNFnext);
+}
+//------------------------------
+//endfunc setLaunchKeys()
+//---------------------------------------------------------------------------
+int drawMainScreen(void)
+{
+	int nElfs=0;
+	int i;
+	int x, y;
+	u64 color;
+	char c[MAX_PATH+8], f[MAX_PATH];
+	char *p;
+
+	setLaunchKeys();
+
+	clrScr(setting->color[0]);
+
+	x = Menu_start_x;
+	y = Menu_start_y;
+	c[0] = 0;
+	if(init_delay)    sprintf(c, "%s: %d", LNG(Init_Delay), init_delay/1000);
+	else if(setting->LK_Path[0][0]){
+		if(!user_acted) sprintf(c, "%s: %d", LNG(TIMEOUT), timeout/1000);
+		else            sprintf(c, "%s: %s", LNG(TIMEOUT), LNG(Halted));
+	}
+	if(c[0]){
+		printXY(c, x, y, setting->color[3], TRUE, 0);
+		y += FONT_HEIGHT*2;
+	}
+	for(i=0; i<15; i++){
+		if((setting->LK_Path[i][0]) && ((i<13) || (maxCNF>1) || setting->LK_Flag[i]))
+		{
+			menu_LK[nElfs] = i; //memorize RunElf index for this menu entry
+			switch(i){
+			case 0:
+				strcpy(c,"Default: ");
+				break;
+			case 1:
+				strcpy(c,"     ÿ0: ");
+				break;
+			case 2:
+				strcpy(c,"     ÿ1: ");
+				break;
+			case 3:
+				strcpy(c,"     ÿ2: ");
+				break;
+			case 4:
+				strcpy(c,"     ÿ3: ");
+				break;
+			case 5:
+				strcpy(c,"     L1: ");
+				break;
+			case 6:
+				strcpy(c,"     R1: ");
+				break;
+			case 7:
+				strcpy(c,"     L2: ");
+				break;
+			case 8:
+				strcpy(c,"     R2: ");
+				break;
+			case 9:
+				strcpy(c,"     L3: ");
+				break;
+			case 10:
+				strcpy(c,"     R3: ");
+				break;
+			case 11:
+				strcpy(c,"  START: ");
+				break;
+			case 12:
+				strcpy(c," SELECT: ");
+				break;
+			case 13:
+				sprintf(c,"%s: ", LNG(LEFT));
+				break;
+			case 14:
+				sprintf(c,"%s: ", LNG(RIGHT));
+				break;
+			} //ends switch
+			if(setting->Show_Titles) //Show Launch Titles ?
+				strcpy(f, setting->LK_Title[i]);
+			else
+				f[0] = '\0';
+			if(!f[0]) {  //No title present, or allowed ?
+				if(setting->Hide_Paths) {  //Hide full path ?
+					if((p=strrchr(setting->LK_Path[i], '/'))) // found delimiter ?
+						strcpy(f, p+1);
+					else // No delimiter !
+						strcpy(f, setting->LK_Path[i]);
+					if((p=strrchr(f, '.')))
+						*p = 0;
+				} else {                  //Show full path !
+					strcpy(f, setting->LK_Path[i]);
+				}
+			} //ends clause for No title
+			if(nElfs++==selected && mode==DPAD)
+				color = setting->color[2];
+			else
+				color = setting->color[3];
+			int len = (strlen(LNG(LEFT))+2>strlen(LNG(RIGHT))+2)?
+				strlen(LNG(LEFT))+2:strlen(LNG(RIGHT))+2;
+			if(i==13){ // LEFT
+				if(strlen(LNG(RIGHT))+2>strlen(LNG(LEFT))+2)
+					printXY(c, x+(strlen(LNG(RIGHT))+2>9?
+						((strlen(LNG(RIGHT))+2)-(strlen(LNG(LEFT))+2))*FONT_WIDTH:
+						(9-(strlen(LNG(LEFT))+2))*FONT_WIDTH), y, color, TRUE, 0);
+				else
+					printXY(c, x+(strlen(LNG(LEFT))+2>9?
+						0:(9-(strlen(LNG(LEFT))+2))*FONT_WIDTH), y, color, TRUE, 0);
+			}else if (i==14){ // RIGHT
+				if(strlen(LNG(LEFT))+2>strlen(LNG(RIGHT))+2)
+					printXY(c, x+(strlen(LNG(LEFT))+2>9?
+						((strlen(LNG(LEFT))+2)-(strlen(LNG(RIGHT))+2))*FONT_WIDTH:
+						(9-(strlen(LNG(RIGHT))+2))*FONT_WIDTH), y, color, TRUE, 0);
+				else
+					printXY(c, x+(strlen(LNG(RIGHT))+2>9?
+						0:(9-(strlen(LNG(RIGHT))+2))*FONT_WIDTH), y, color, TRUE, 0);
+			}else
+				printXY(c, x+(len>9? (len-9)*FONT_WIDTH:0), y, color, TRUE, 0);
+			printXY(f, x+(len>9? len*FONT_WIDTH:9*FONT_WIDTH), y, color, TRUE, 0);
+			y += FONT_HEIGHT;
+		} //ends clause for defined LK_Path[i] valid for menu
+	} //ends for
+
+	if(mode==BUTTON)	sprintf(c, "%s!", LNG(PUSH_ANY_BUTTON_or_DPAD));
+	else{
+		if(swapKeys) 
+			sprintf(c, "ÿ1:%s ÿ0:%s", LNG(OK), LNG(Cancel));
+		else
+			sprintf(c, "ÿ0:%s ÿ1:%s", LNG(OK), LNG(Cancel));
+	}
+	
+	setScrTmp(mainMsg, c);
+	
+	return nElfs;
+}
+//------------------------------
+//endfunc drawMainScreen
+//---------------------------------------------------------------------------
+int drawMainScreen2(int TV_mode)
+{
+	int nElfs=0;
+	int i;
+	int x, y, xo_config=0, yo_config=0, yo_first=0, yo_step=0;
+	u64 color;
+	char c[MAX_PATH+8], f[MAX_PATH];
+	char *p;
+
+	setLaunchKeys();
+
+	clrScr(setting->color[0]);
+
+	x = Menu_start_x;
+	y = Menu_start_y;
+
+	if(init_delay)    sprintf(c, "%s:       %d", LNG(Delay), init_delay/1000);
+	else if(setting->LK_Path[0][0]){
+		if(!user_acted) sprintf(c, "%s:     %d", LNG(TIMEOUT), timeout/1000);
+		else            sprintf(c, "%s:    %s", LNG(TIMEOUT), LNG(Halt));
+	}
+
+	if(TV_mode == TV_mode_PAL){
+		printXY(c, x+448, y+FONT_HEIGHT+6, setting->color[3], TRUE, 0);
+		y += FONT_HEIGHT+5;
+		yo_first = 5;
+		yo_step = FONT_HEIGHT*2;
+		yo_config = -92;
+		xo_config = 370;
+	}else if(TV_mode == TV_mode_NTSC){
+		printXY(c, x+448, y+FONT_HEIGHT-5, setting->color[3], TRUE, 0);
+		y += FONT_HEIGHT-3;
+		yo_first = 3;
+		yo_step = FONT_HEIGHT*2-4;
+		yo_config = -80;
+		xo_config = 360;
+	}
+
+	for(i=0; i<15; i++){
+		if((setting->LK_Path[i][0]) && ((i<13)||(maxCNF>1)||setting->LK_Flag[i]))
+		{
+			menu_LK[nElfs] = i; //memorize RunElf index for this menu entry
+			if(setting->Show_Titles) //Show Launch Titles ?
+				strcpy(f, setting->LK_Title[i]);
+			else
+				f[0] = '\0';
+			if(!f[0]) {  //No title present, or allowed ?
+				if(setting->Hide_Paths) {  //Hide full path ?
+					if((p=strrchr(setting->LK_Path[i], '/'))) // found delimiter ?
+						strcpy(f, p+1);
+					else // No delimiter !
+						strcpy(f, setting->LK_Path[i]);
+					if((p=strrchr(f, '.')))
+						*p = 0;
+				} else {                  //Show full path !
+					strcpy(f, setting->LK_Path[i]);
+				}
+			} //ends clause for No title
+			if(setting->LK_Path[i][0] && nElfs++==selected && mode==DPAD)
+				color = setting->color[2];
+			else
+				color = setting->color[3];
+			int len = (strlen(LNG(LEFT))+2>strlen(LNG(RIGHT))+2)?
+				strlen(LNG(LEFT))+2:strlen(LNG(RIGHT))+2;
+			if (i==0)
+				printXY(f, x+(len>9? len*FONT_WIDTH:9*FONT_WIDTH)+20, y, color, TRUE, 0);
+			else if (i==12)
+				printXY(f, x+(len>9? len*FONT_WIDTH:9*FONT_WIDTH)+xo_config, y, color, TRUE, 0);
+			else if (i==13)
+				printXY(f, x+(len>9? len*FONT_WIDTH:9*FONT_WIDTH)+xo_config, y, color, TRUE, 0);
+			else if (i==14)
+				printXY(f, x+(len>9? len*FONT_WIDTH:9*FONT_WIDTH)+xo_config, y, color, TRUE, 0);
+			else
+				printXY(f, x+(len>9? len*FONT_WIDTH:9*FONT_WIDTH)+10, y, color, TRUE, 0);
+		} //ends clause for defined LK_Path[i] valid for menu
+		y += yo_step;
+		if (i==0)
+			y+=yo_first;
+		else if (i==11)
+			y+=yo_config;
+	} //ends for
+
+	c[0] = '\0';           //dummy tooltip string (Tooltip unused for GUI menu)
+	setScrTmp(mainMsg, c);
+	
+	return nElfs;
+}
+//------------------------------
+//endfunc drawMainScreen2
+//---------------------------------------------------------------------------
+void delay(int count)
+{
+	int i;
+	int ret;
+	for (i  = 0; i < count; i++) {
+	        ret = 0x01000000;
+		while(ret--) asm("nop\nnop\nnop\nnop");
+	}
+}
+//------------------------------
+//endfunc delay
+//---------------------------------------------------------------------------
+void initsbv_patches(void)
+{
+	if(!have_sbv_patches)
+	{	dbgprintf("Init MrBrown sbv_patches\n");
+		sbv_patch_enable_lmb();
+		sbv_patch_disable_prefix_check();
+		have_sbv_patches = 1;
+	}
+}
+//------------------------------
+//endfunc initsbv_patches
+//---------------------------------------------------------------------------
+void	load_iomanx(void)
+{
+	int ret;
+
+	if	(!have_iomanx)
+	{	SifExecModuleBuffer(&iomanx_irx, size_iomanx_irx, 0, NULL, &ret);
+		have_iomanx = 1;
+	}
+}
+//------------------------------
+//endfunc load_iomanx
+//---------------------------------------------------------------------------
+void	load_filexio(void)
+{
+	int ret;
+
+	if	(!have_filexio)
+	{	SifExecModuleBuffer(&filexio_irx, size_filexio_irx, 0, NULL, &ret);
+		have_filexio = 1;
+	}
+}
+//------------------------------
+//endfunc load_filexio
+//---------------------------------------------------------------------------
+void	load_ps2dev9(void)
+{
+	int ret;
+
+	load_iomanx();
+	if	(!have_ps2dev9)
+	{	SifExecModuleBuffer(&ps2dev9_irx, size_ps2dev9_irx, 0, NULL, &ret);
+		have_ps2dev9 = 1;
+	}
+}
+//------------------------------
+//endfunc load_ps2dev9
+//---------------------------------------------------------------------------
+void	load_ps2ip(void)
+{
+	int ret;
+
+	load_ps2dev9();
+	if	(!have_ps2ip){
+		SifExecModuleBuffer(&smsutils_irx, size_smsutils_irx, 0, NULL, &ret);
+		SifExecModuleBuffer(&ps2ip_irx, size_ps2ip_irx, 0, NULL, &ret);
+		have_ps2ip = 1;
+	}
+	if	(!have_ps2smap){
+		SifExecModuleBuffer(&ps2smap_irx, size_ps2smap_irx,
+		                    if_conf_len, &if_conf[0], &ret);
+		have_ps2smap = 1;
+	}
+}
+//------------------------------
+//endfunc load_ps2ip
+//---------------------------------------------------------------------------
+void	load_ps2atad(void)
+{
+	int ret;
+	static char hddarg[] = "-o" "\0" "4" "\0" "-n" "\0" "20";
+	static char pfsarg[] = "-m" "\0" "4" "\0" "-o" "\0" "10" "\0" "-n" "\0" "40";
+
+	load_ps2dev9();
+	if	(!have_ps2atad)
+	{	SifExecModuleBuffer(&ps2atad_irx, size_ps2atad_irx, 0, NULL, &ret);
+		have_ps2atad = 1;
+	}
+	if	(!have_ps2hdd)
+	{	SifExecModuleBuffer(&ps2hdd_irx, size_ps2hdd_irx, sizeof(hddarg), hddarg, &ret);
+		have_ps2hdd = 1;
+	}
+	if	(!have_ps2fs)
+	{	SifExecModuleBuffer(&ps2fs_irx, size_ps2fs_irx, sizeof(pfsarg), pfsarg, &ret);
+		have_ps2fs = 1;
+	}
+}
+//------------------------------
+//endfunc load_ps2atad
+//---------------------------------------------------------------------------
+void	load_ps2host(void)
+{
+	int ret;
+
+	setupPowerOff(); //resolves the stall out when opening host: from LaunchELF's FileBrowser
+	load_ps2ip();
+	if	(!have_ps2host)
+	{	SifExecModuleBuffer(&ps2host_irx, size_ps2host_irx, 0, NULL, &ret);
+		have_ps2host = 1;
+	}
+}
+//------------------------------
+//endfunc load_ps2host
+//---------------------------------------------------------------------------
+void	load_vmcfs(void)
+{
+	int ret;
+
+	load_iomanx();
+	load_filexio();
+	if	(!have_vmcfs)
+	{	SifExecModuleBuffer(&vmcfs_irx, size_vmcfs_irx, 0, NULL, &ret);
+		have_vmcfs = 1;
+	}
+}
+//------------------------------
+//endfunc load_vmcfs
+//---------------------------------------------------------------------------
+void	load_ps2ftpd(void)
+{
+	int 	ret;
+	int		arglen;
+	char* arg_p;
+
+	arg_p = "-anonymous";
+	arglen = strlen(arg_p);
+
+	load_ps2ip();
+	if	(!have_ps2ftpd)
+	{	SifExecModuleBuffer(&ps2ftpd_irx, size_ps2ftpd_irx, arglen, arg_p, &ret);
+		have_ps2ftpd = 1;
+	}
+}
+//------------------------------
+//endfunc load_ps2ftpd
+//---------------------------------------------------------------------------
+void	load_ps2netfs(void)
+{
+	int ret;
+
+	load_ps2ip();
+	if	(!have_ps2netfs)
+	{	SifExecModuleBuffer(&ps2netfs_irx, size_ps2netfs_irx, 0, NULL, &ret);
+		have_ps2netfs = 1;
+	}
+}
+//------------------------------
+//endfunc load_ps2netfs
+//---------------------------------------------------------------------------
+void loadBasicModules(void)
+{
+	int ret;
+
+	if	(!have_sio2man) {
+		SifLoadModule("rom0:SIO2MAN", 0, NULL);
+		have_sio2man = 1;
+	}
+	if	(!have_mcman) {
+		//SifExecModuleBuffer(&mcman_irx, size_mcman_irx, 0, NULL, &ret); //Home
+		SifLoadModule("rom0:MCMAN", 0, NULL); //Sony
+		have_mcman = 1;
+	}
+	if	(!have_mcserv) {
+		//SifExecModuleBuffer(&mcserv_irx, size_mcserv_irx, 0, NULL, &ret); //Home
+		SifLoadModule("rom0:MCSERV", 0, NULL); //Sony
+		have_mcserv = 1;
+	}
+	if	(!have_padman) {
+		SifLoadModule("rom0:PADMAN", 0, NULL);
+		have_padman = 1;
+	}
+}
+//------------------------------
+//endfunc loadBasicModules
+//---------------------------------------------------------------------------
+void loadCdModules(void)
+{
+	int ret;
+	
+	if	(!have_cdvd) {
+		SifExecModuleBuffer(&cdvd_irx, size_cdvd_irx, 0, NULL, &ret);
+		cdInit(CDVD_INIT_INIT);
+		CDVD_Init();
+		have_cdvd = 1;
+	}
+}
+//------------------------------
+//endfunc loadCdModules
+//---------------------------------------------------------------------------
+void load_chkesr_module(void)
+{
+	// load chkesr and other modules (EROMDRV) needed to read DVDV
+	
+	int ret;
+
+	if(have_chkesr)
+		return;
+
+	SifExecModuleBuffer(&chkesr_irx, size_chkesr_irx, 0, NULL, &ret);
+	chkesr_rpc_Init();
+	have_chkesr = 1;
+}
+//------------------------------
+//endfunc load_chkesr_module
+//---------------------------------------------------------------------------
+int uLE_cdDiscValid(void) //returns 1 if disc valid, else returns 0
+{
+	if (!have_cdvd) {
+		loadCdModules();
+	}
+
+	cdmode = cdGetDiscType();
+
+	switch(cdmode){
+	case CDVD_TYPE_PS1CD:
+	case CDVD_TYPE_PS1CDDA:
+	case CDVD_TYPE_PS2CD:
+	case CDVD_TYPE_PS2CDDA:
+	case CDVD_TYPE_PS2DVD:
+//	case CDVD_TYPE_ESRDVD_0:
+//	case CDVD_TYPE_ESRDVD_1:
+	case CDVD_TYPE_CDDA:
+	case CDVD_TYPE_DVDVIDEO:
+		return 1;
+	case CDVD_TYPE_NODISK:
+	case CDVD_TYPE_DETECT:
+	case CDVD_TYPE_DETECT_CD:
+	case CDVD_TYPE_DETECT_DVDSINGLE:
+	case CDVD_TYPE_DETECT_DVDDUAL:
+	case CDVD_TYPE_UNKNOWN:
+	case CDVD_TYPE_ILLEGAL:
+	default:
+		return 0;
+	}
+}
+//------------------------------
+//endfunc uLE_cdDiscValid
+//---------------------------------------------------------------------------
+int uLE_cdStop(void)
+{
+	int	test;
+
+	old_cdmode = cdmode;
+	test = uLE_cdDiscValid();
+	uLE_cdmode = cdmode;
+	if (test){ //if stable detection of a real disc is achieved
+		if((cdmode !=old_cdmode) //if this was a new detection
+		&& ((cdmode == CDVD_TYPE_DVDVIDEO) || (cdmode == CDVD_TYPE_PS2DVD))){
+			load_chkesr_module(); //prepare to check for ESR disc
+			test = Check_ESR_Disc();
+			printf("Check_ESR_Disc => %d\n", test);
+			if(test > 0){	//ESR Disc ?
+				uLE_cdmode = (cdmode == CDVD_TYPE_PS2DVD)
+					? CDVD_TYPE_ESRDVD_1 : CDVD_TYPE_ESRDVD_0 ;
+			}
+		}
+		CDVD_Stop();
+	}
+	return uLE_cdmode;
+}
+//------------------------------
+//endfunc uLE_cdStop
+//---------------------------------------------------------------------------
+// loadExternalFile below will use the given path, and read the
+// indicated file into a buffer it allocates for that purpose.
+// The buffer address and size are returned via pointer variables,
+// and the size is also returned as function value. Both those
+// instances of size will be forced to Zero if any error occurs,
+// and in such cases the buffer pointer returned will be NULL.
+// NB: Release of the allocated memory block, if/when it is not
+// needed anymore, is entirely the responsibility of the caller,
+// though, of course, none is allocated if the file is not found.
+//---------------------------------------------------------------------------
+int	loadExternalFile(char *argPath, void **fileBaseP, int *fileSizeP)
+{ //The first three variables are local variants similar to the arguments
+	char filePath[MAX_PATH];
+	char *pathSep;
+	void *fileBase;
+	int fileSize;
+	FILE*	File;
+
+	fileBase = NULL;
+	fileSize = 0;
+
+	pathSep = strchr(argPath, '/');
+
+	if(!strncmp(argPath, "mass", 4)){
+		//Loading some module from USB mass:
+		//NB: This won't be for USB drivers, due to protection elsewhere
+		loadUsbModules();
+		strcpy(filePath, argPath);
+		if(pathSep && (pathSep-argPath<7) && pathSep[-1]==':')
+			strcpy(filePath+(pathSep-argPath), pathSep+1);
+
+	}else if(!strncmp(argPath, "hdd0:/", 6)){
+		//Loading some module from HDD
+		char party[MAX_PATH];
+		char *p;
+
+		loadHddModules();
+		sprintf(party, "hdd0:%s", argPath+6);
+		p = strchr(party, '/');
+		sprintf(filePath, "pfs0:%s", p);
+		*p = 0;
+		fileXioMount("pfs0:", party, FIO_MT_RDONLY);
+
+	}else if(!strncmp(argPath, "cdfs", 4)){
+		loadCdModules();
+		strcpy(filePath, argPath);
+		CDVD_FlushCache();
+		CDVD_DiskReady(0);
+	}else{
+		(void) uLE_related(filePath, argPath);
+	}
+	//Here 'filePath' is a valid path for fio or fileXio operations
+	//Which means we can now use generic file I/O
+	File = fopen( filePath, "r" );
+ 	if( File != NULL ) {
+		fseek(File, 0, SEEK_END);
+		fileSize = ftell(File);
+		fseek(File, 0, SEEK_SET);
+		if(fileSize) {
+			if((fileBase = malloc(fileSize)) > 0 ) {
+				fread(fileBase, 1, fileSize, File );
+			} else
+				fileSize =0;
+		}
+		fclose(File);
+	}
+	*fileBaseP = fileBase;
+	*fileSizeP = fileSize;
+	return fileSize;
+}
+//------------------------------
+//endfunc loadExternalFile
+//---------------------------------------------------------------------------
+// loadExternalModule below will use the given path and attempt
+// to load the indicated file into a temporary buffer, and from
+// that buffer send it on to the IOP as a driver module, after
+// which the temporary buffer will be freed. If the file is not
+// found, or some error occurs in its reading or buffer allocation
+// then the default internal module specified by the 2nd and 3rd
+// arguments will be used, except if the base is NULL or the size
+// is zero, in which case a value of 0 is returned. A value of
+// 0 is also returned if loading of default module fails. But
+// normally the value returned will be 1 for an internal default
+// module, but 2 for an external module..
+//---------------------------------------------------------------------------
+int loadExternalModule(char *modPath, void *defBase, int defSize)
+{
+	void *extBase;
+	int extSize;
+	int external;       //Flags loading of external file into buffer
+	int ext_OK, def_OK; //Flags success for external and default module
+	int	dummy;
+
+	ext_OK = (def_OK = 0);
+	if( (!(external = loadExternalFile(modPath, &extBase, &extSize)))
+		||((ext_OK = SifExecModuleBuffer(extBase, extSize, 0, NULL, &dummy)) < 0) ) {
+		if(defBase && defSize) {
+			def_OK = SifExecModuleBuffer(defBase, defSize, 0, NULL, &dummy);
+		}
+	}
+	if(external) free(extBase);
+	if(ext_OK) return 2;
+	if(def_OK) return 1;
+	return 0;
+}
+//------------------------------
+//endfunc loadExternalModule
+//---------------------------------------------------------------------------
+void loadUsbDModule(void)
+{
+	if( (!have_usbd)
+		&&(loadExternalModule(setting->usbd_file, &usbd_irx, size_usbd_irx))
+	) have_usbd = 1;
+}
+//------------------------------
+//endfunc loadUsbDModule
+//---------------------------------------------------------------------------
+void loadUsbModules(void)
+{
+	//int ret;
+
+	loadUsbDModule();
+	if(	have_usbd
+	&&	!have_usb_mass
+	&&	(USB_mass_loaded = loadExternalModule(setting->usbmass_file, &usb_mass_irx, size_usb_mass_irx))){
+		delay(3);
+		//ret = usb_mass_bindRpc(); //dlanor: disused in switching to usbhdfsd
+		have_usb_mass = 1;
+	}
+	if(USB_mass_loaded == 1) //if using the internal mass driver
+		USB_mass_max_drives = USB_MASS_MAX_DRIVES; //allow multiple drives
+	else
+		USB_mass_max_drives = 1; //else allow only one mass drive
+}
+//------------------------------
+//endfunc loadUsbModules
+//---------------------------------------------------------------------------
+void loadKbdModules(void)
+{
+	loadUsbDModule();
+	if( (have_usbd && !have_ps2kbd)
+		&&(loadExternalModule(setting->usbkbd_file, &ps2kbd_irx, size_ps2kbd_irx))
+	)	have_ps2kbd = 1;
+}
+//------------------------------
+//endfunc loadKbdModules
+//---------------------------------------------------------------------------
+void loadHdlInfoModule(void)
+{
+	int ret;
+
+	if(!have_hdl_info){
+		drawMsg(LNG(Loading_HDL_Info_Module));
+		SifExecModuleBuffer(&hdl_info_irx, size_hdl_info_irx, 0, NULL, &ret);
+		ret = Hdl_Info_BindRpc();
+		have_hdl_info = 1;
+	}
+}
+//------------------------------
+//endfunc loadHdlInfoModule
+//---------------------------------------------------------------------------
+void poweroffHandler(int i)
+{
+	//hddPowerOff(); //deprecated
+	poweroffShutdown();
+}
+//------------------------------
+//endfunc poweroffHandler
+//---------------------------------------------------------------------------
+void setupPowerOff(void) {
+	int ret;
+
+	if(!done_setupPowerOff) {
+		//hddPreparePoweroff(); //deprecated
+		//hddSetUserPoweroffCallback((void *)poweroffHandler, NULL); //deprecated
+		if	(!have_poweroff) {
+			SifExecModuleBuffer(&poweroff_irx, size_poweroff_irx, 0, NULL, &ret);
+			have_poweroff = 1;
+		}
+		poweroffInit();
+		poweroffSetCallback((void *)poweroffHandler, NULL);
+		load_iomanx();
+		load_filexio();
+		load_ps2dev9();
+		done_setupPowerOff = 1;
+	}
+}
+//------------------------------
+//endfunc setupPowerOff
+//---------------------------------------------------------------------------
+void loadHddModules(void)
+{
+	if(!have_HDD_modules) {
+		drawMsg(LNG(Loading_HDD_Modules));
+		setupPowerOff();
+		load_ps2atad(); //also loads ps2hdd & ps2fs
+		have_HDD_modules = TRUE;
+	}
+}
+//------------------------------
+//endfunc loadHddModules
+//---------------------------------------------------------------------------
+// Load Network modules by EP (modified by RA)
+//------------------------------
+void loadNetModules(void)
+{
+	if(!have_NetModules){
+		loadHddModules();
+		loadUsbModules();
+		drawMsg(LNG(Loading_NetFS_and_FTP_Server_Modules));
+		
+		getIpConfig(); //RA NB: I always get that info, early in init
+		//             //But sometimes it is useful to do it again (HDD)
+		// Also, my module checking makes some other tests redundant
+		load_ps2netfs(); // loads ps2netfs from internal buffer
+		load_ps2ftpd();  // loads ps2dftpd from internal buffer
+		have_NetModules = 1;
+	}
+	strcpy(mainMsg, netConfig);
+	if (setting->GUI_skin[0]) {
+		GUI_active = 1;
+		loadSkin(BACKGROUND_PIC, 0, 0);
+	}
+}
+//------------------------------
+//endfunc loadNetModules
+//---------------------------------------------------------------------------
+void startKbd(void)
+{
+	int kbd_fd;
+	void *mapBase;
+	int   mapSize;
+
+	printf("Entering startKbd()\r\n");
+	if(setting->usbkbd_used) {
+		loadKbdModules();
+		PS2KbdInit();
+		ps2kbd_opened = 1;
+		if(setting->kbdmap_file[0]) {
+			if((kbd_fd = fioOpen(PS2KBD_DEVFILE, O_RDONLY)) >= 0) {
+				printf("kbd_fd=%d; Loading Kbd map file \"%s\"\r\n",kbd_fd,setting->kbdmap_file);
+				if(loadExternalFile(setting->kbdmap_file, &mapBase, &mapSize)) {
+					if(mapSize == 0x600) {
+						fioIoctl(kbd_fd, PS2KBD_IOCTL_SETKEYMAP, mapBase);
+						fioIoctl(kbd_fd, PS2KBD_IOCTL_SETSPECIALMAP, mapBase+0x300);
+						fioIoctl(kbd_fd, PS2KBD_IOCTL_SETCTRLMAP, mapBase+0x400);
+						fioIoctl(kbd_fd, PS2KBD_IOCTL_SETALTMAP, mapBase+0x500);
+					}
+					printf("Freeing buffer after setting Kbd maps\r\n");
+					free(mapBase);
+				}
+				fioClose(kbd_fd);
+			}
+		}
+	}
+}
+//------------------------------
+//endfunc startKbd
+//---------------------------------------------------------------------------
+//scanSystemCnf will check for a standard variable of a SYSTEM.CNF file
+//------------------------------
+int scanSystemCnf(unsigned char *name, unsigned char *value)
+{
+	if(!strcmp(name,"BOOT")) strncat(SystemCnf_BOOT, value, MAX_PATH-1);
+	else if(!strcmp(name,"BOOT2")) strncat(SystemCnf_BOOT2, value, MAX_PATH-1);
+	else if(!strcmp(name,"VER")) strncat(SystemCnf_VER, value, 9);
+	else if(!strcmp(name,"VMODE")) strncat(SystemCnf_VMODE, value, 9);
+	else
+		return 0; //when no matching variable
+	return 1; //when matching variable found
+}
+//------------------------------
+//endfunc scanSystemCnf
+//---------------------------------------------------------------------------
+//readSystemCnf will read standard settings from a SYSTEM.CNF file
+//------------------------------
+int readSystemCnf(void)
+{
+	int dummy, var_cnt;
+	unsigned char *RAM_p, *CNF_p, *name, *value;
+
+	BootDiscType = 0;
+	SystemCnf_BOOT[0]  = '\0';
+	SystemCnf_BOOT2[0] = '\0';
+	SystemCnf_VER[0]   = '\0';
+	SystemCnf_VMODE[0] = '\0';
+
+	if( (RAM_p = preloadCNF("cdrom0:\\SYSTEM.CNF;1")) != NULL){
+		CNF_p = RAM_p;
+		for(var_cnt = 0; get_CNF_string(&CNF_p, &name, &value); var_cnt++)
+			dummy = scanSystemCnf(name, value);
+		free(RAM_p);
+	}
+
+	if(SystemCnf_BOOT2[0]) BootDiscType = 2;
+	else if(SystemCnf_BOOT[0]) BootDiscType = 1;
+
+	if(!SystemCnf_BOOT[0]) strcpy(SystemCnf_BOOT, "???");
+	if(!SystemCnf_VER[0]) strcpy(SystemCnf_VER, "???");
+
+	if(RAM_p == NULL){ //if SYSTEM.CNF was not found test for PS1 special cases
+		if(exists("cdrom0:\\PSXMYST\\MYST.CCS;1")){
+			strcpy(SystemCnf_BOOT, "SLPS_000.24");
+			BootDiscType = 1;
+		}else if(exists("cdrom0:\\CDROM\\LASTPHOT\\ALL_C.NBN;1")){
+			strcpy(SystemCnf_BOOT, "SLPS_000.65");
+			BootDiscType = 1;
+		}else if(exists("cdrom0:\\PSX.EXE;1")){
+			BootDiscType = 1;
+		}
+	}
+
+	return BootDiscType; //0==none, 1==PS1, 2==PS2
+}
+//------------------------------
+//endfunc readSystemCnf
+//---------------------------------------------------------------------------
+void	ShowFont(void)
+{
+	int test_type=0;
+	int test_types=2;  //Patch test_types for number of test loops
+	int	i, j, event, post_event=0;
+	char Hex[18] = "0123456789ABCDEF";
+	int ch_x_stp = 1+FONT_WIDTH+1+LINE_THICKNESS;
+	int ch_y_stp = 2+FONT_HEIGHT+1+LINE_THICKNESS;
+	int	mat_w = LINE_THICKNESS+17*ch_x_stp;
+	int mat_h = LINE_THICKNESS+17*ch_y_stp;
+	int mat_x = (((SCREEN_WIDTH-mat_w)/2) & -2);
+	int mat_y = (((SCREEN_HEIGHT-mat_h)/2) & -2);
+	int ch_x  = mat_x+LINE_THICKNESS+1;
+//	int	ch_y  = mat_y+LINE_THICKNESS+2;
+	int px, ly, cy;
+	u64 col_0=setting->color[0], col_1=setting->color[1], col_3=setting->color[3];
+
+//The next line is a patch to save font, if/when needed (needs patch in draw.c too)
+//	WriteFont_C("mc0:/SYS-CONF/font_uLE.c");
+
+	event = 1;   //event = initial entry
+	//----- Start of event loop -----
+	while(1) {
+		//Display section
+		if(event||post_event) { //NB: We need to update two frame buffers per event
+			drawOpSprite(col_0, mat_x, mat_y, mat_x+mat_w-1, mat_y+mat_h-1);
+			//Here the background rectangle has been prepared
+/* //Start of commented out section //Move this line as needed for tests
+			//Start of gsKit test section
+			if(test_type > 1) goto done_test;
+			gsKit_prim_point(gsGlobal, mat_x+16, mat_y+16, 1, col_3);
+			gsKit_prim_point(gsGlobal, mat_x+33, mat_y+16, 1, col_3);
+			gsKit_prim_point(gsGlobal, mat_x+33, mat_y+33, 1, col_3);
+			gsKit_prim_point(gsGlobal, mat_x+16, mat_y+33, 1, col_3);
+			gsKit_prim_line(gsGlobal, mat_x+48, mat_y+48, mat_x+65, mat_y+48, 1, col_3);
+			gsKit_prim_line(gsGlobal, mat_x+65, mat_y+48, mat_x+65, mat_y+65, 1, col_3);
+			gsKit_prim_line(gsGlobal, mat_x+65, mat_y+65, mat_x+48, mat_y+65, 1, col_3);
+			gsKit_prim_line(gsGlobal, mat_x+48, mat_y+65, mat_x+48, mat_y+48, 1, col_3);
+			gsKit_prim_sprite(gsGlobal, mat_x+80, mat_y+80, mat_x+97, mat_y+81, 1, col_3);
+			gsKit_prim_sprite(gsGlobal, mat_x+97, mat_y+80, mat_x+96, mat_y+97, 1, col_3);
+			gsKit_prim_sprite(gsGlobal, mat_x+97, mat_y+97, mat_x+80, mat_y+96, 1, col_3);
+			gsKit_prim_sprite(gsGlobal, mat_x+80, mat_y+97, mat_x+81, mat_y+80, 1, col_3);
+			gsKit_prim_line(gsGlobal, mat_x+80, mat_y+16, mat_x+81, mat_y+16, 1, col_3);
+			gsKit_prim_line(gsGlobal, mat_x+97, mat_y+16, mat_x+97, mat_y+17, 1, col_3);
+			gsKit_prim_line(gsGlobal, mat_x+97, mat_y+33, mat_x+96, mat_y+33, 1, col_3);
+			gsKit_prim_line(gsGlobal, mat_x+80, mat_y+33, mat_x+80, mat_y+32, 1, col_3);
+			gsKit_prim_sprite(gsGlobal, mat_x+16, mat_y+80, mat_x+17, mat_y+81, 1, col_3);
+			gsKit_prim_sprite(gsGlobal, mat_x+33, mat_y+80, mat_x+32, mat_y+81, 1, col_3);
+			gsKit_prim_sprite(gsGlobal, mat_x+33, mat_y+97, mat_x+32, mat_y+96, 1, col_3);
+			gsKit_prim_sprite(gsGlobal, mat_x+16, mat_y+97, mat_x+17, mat_y+96, 1, col_3);
+			goto end_display;
+done_test:
+			//End of gsKit test section
+*/ //End of commented out section  //Move this line as needed for tests
+			//Start of font display section
+			//Now we start to draw all vertical frame lines
+			px=mat_x;
+			drawOpSprite(col_1, px, mat_y, px+LINE_THICKNESS-1, mat_y+mat_h-1);
+			for(j=0; j<17; j++) { //for each font column, plus the row_index column
+				px += ch_x_stp;
+				drawOpSprite(col_1, px, mat_y, px+LINE_THICKNESS-1, mat_y+mat_h-1);
+			} //ends for each font column, plus the row_index column
+			//Here all the vertical frame lines have been drawn
+			//Next we draw the top horizontal line
+			drawOpSprite(col_1, mat_x, mat_y, mat_x+mat_w-1, mat_y+LINE_THICKNESS-1);
+			cy = mat_y+LINE_THICKNESS+2;
+			ly = mat_y;
+			for(i=0; i<17; i++) { //for each font row
+				px=ch_x;
+				if(!i) { //if top row (which holds the column indexes)
+					drawChar('\\', px, cy, col_3);     //Display '\' at index crosspoint
+				} else { //else a real font row
+					drawChar(Hex[i-1], px, cy, col_3); //Display row index
+				}
+				for(j=0; j<16; j++) { //for each font column
+					px += ch_x_stp;
+					if(!i) { //if top row (which holds the column indexes)
+						drawChar(Hex[j], px, cy, col_3); //Display Column index
+					} else {
+						drawChar((i-1)*16+j, px, cy, col_3); //Display font character
+					}
+				} //ends for each font column
+				ly += ch_y_stp;
+				drawOpSprite(col_1, mat_x, ly, mat_x+mat_w-1, ly+LINE_THICKNESS-1);
+				cy += ch_y_stp;
+			} //ends for each font row
+			//End of font display section
+		} //ends if(event||post_event)
+//end_display:
+		drawScr();
+		post_event = event;
+		event = 0;
+
+		//Pad response section
+		waitAnyPadReady();
+		if(readpad() && new_pad){
+			event |= 2;
+			if((++test_type) < test_types){
+				mat_y++;
+				continue;
+			}
+			if (setting->GUI_skin[0]) {
+				GUI_active = 1;
+				loadSkin(BACKGROUND_PIC, 0, 0);
+			}
+			break;
+		}
+	} //ends while
+	//----- End of event loop -----
+}
+//------------------------------
+//endfunc ShowFont
+//---------------------------------------------------------------------------
+void triggerPowerOff(void)
+{
+	char filepath[MAX_PATH] = "xyz:/imaginary/hypothetical/doesn't.exist";
+	FILE *File;
+
+	File = fopen( filepath, "r" );
+//	sprintf(mainMsg, "%s => %08X.", filepath, File);
+//	drawMsg(mainMsg);
+	if( File != NULL ) {
+		fclose( File );
+	} // end if( File != NULL )
+}
+//------------------------------
+//endfunc triggerPowerOff
+//---------------------------------------------------------------------------
+void Validate_CNF_Path(void)
+{
+	char cnf_path[MAX_PATH];
+
+	if(setting->CNF_Path[0] != '\0') {
+		if(genFixPath(setting->CNF_Path, cnf_path) >= 0)
+			strcpy(LaunchElfDir, setting->CNF_Path);
+	}
+}
+//------------------------------
+//endfunc Validate_CNF_Path
+//---------------------------------------------------------------------------
+void Set_CNF_Path(void)
+{
+	char	*tmp;
+
+	getFilePath(setting->CNF_Path, CNF_PATH_CNF);
+	if((tmp = strrchr(setting->CNF_Path, '/')))
+	tmp[1] = '\0';
+	Validate_CNF_Path();
+
+	if(!strcmp(setting->CNF_Path, LaunchElfDir))
+		sprintf(mainMsg, "%s ", LNG(Valid));
+	else
+		sprintf(mainMsg, "%s ", LNG(Bogus));
+	sprintf(mainMsg+6, "%s = \"%s\"", LNG(CNF_Path), setting->CNF_Path);
+
+}
+//------------------------------
+//endfunc Set_CNF_Path
+//---------------------------------------------------------------------------
+//Reload CNF, possibly after a path change
+int reloadConfig()
+{
+	char tmp[MAX_PATH];
+	int CNF_error = -1;
+
+	if (numCNF == 0)
+		strcpy(CNF, "LAUNCHELF.CNF");
+	else
+		sprintf(CNF, "LAUNCHELF%i.CNF", numCNF);
+
+	CNF_error = loadConfig(mainMsg, CNF);
+	Validate_CNF_Path();
+	updateScreenMode(0);
+	if (setting->GUI_skin[0]) GUI_active = 1;
+	else GUI_active= 0;
+	loadSkin(BACKGROUND_PIC, 0, 0);
+
+	if(CNF_error<0)
+		strcpy(tmp, mainMsg+strlen(LNG(Failed_To_Load)));
+	else
+		strcpy(tmp, mainMsg+strlen(LNG(Loaded_Config)));
+
+	Load_External_Language();
+	loadFont(setting->font_file);
+
+	if(CNF_error<0)
+		sprintf(mainMsg, "%s%s", LNG(Failed_To_Load), tmp);
+	else
+		sprintf(mainMsg, "%s%s", LNG(Loaded_Config), tmp);
+
+	timeout = (setting->timeout+1)*1000;
+	timeout_start = Timer();
+	if(setting->discControl)
+		loadCdModules();
+
+	return CNF_error;
+}
+//------------------------------
+//endfunc reloadConfig
+//---------------------------------------------------------------------------
+// Config Cycle Left  (--) by EP
+void decConfig()
+{
+	if (numCNF > 0)
+		numCNF--;
+	else
+		numCNF = maxCNF-1;
+	
+	reloadConfig();
+}
+//------------------------------
+//endfunc decConfig
+//---------------------------------------------------------------------------
+// Config Cycle Right (++) by EP
+void incConfig()
+{
+	if (numCNF < maxCNF-1)
+		numCNF++;
+	else
+		numCNF = 0;
+	
+	reloadConfig();
+}
+//------------------------------
+//endfunc incConfig
+//---------------------------------------------------------------------------
+//exists.  Tests if a file exists or not
+//------------------------------
+int exists(char *path)
+{
+	int fd;
+
+	fd = genOpen(path, O_RDONLY);
+	if( fd < 0 )
+		return 0;
+	genClose(fd);
+	return 1;
+}
+//------------------------------
+//endfunc exists
+//---------------------------------------------------------------------------
+//uLE_related.  Tests if an uLE_related file exists or not
+// Returns:
+//  1 == uLE related path with file present
+//  0 == uLE related path with file missing
+// -1 == Not uLE related path
+//------------------------------
+int uLE_related(char *pathout, char *pathin)
+{
+	int ret;
+
+	if(!strncmp(pathin, "uLE:/", 5)){
+		sprintf(pathout, "%s%s", LaunchElfDir, pathin+5);
+		if( exists(pathout) )
+			return 1;
+		sprintf(pathout, "%s%s", "mc0:/SYS-CONF/", pathin+5);
+		if( !strncmp(LaunchElfDir, "mc1", 3) )
+			pathout[2] = '1';
+		if( exists(pathout) )
+			return 1;
+		pathout[2] ^= 1;  //switch between mc0 and mc1
+		if( exists(pathout) )
+			return 1;
+		ret = 0;
+	} else
+		ret = -1;
+	strcpy(pathout, pathin);
+	return ret;
+}
+//------------------------------
+//endfunc uLE_related
+//---------------------------------------------------------------------------
+//CleanUp releases uLE stuff preparatory to launching some other application
+//------------------------------
+void	CleanUp(void)
+{
+	clrScr(GS_SETREG_RGBA(0x00, 0x00, 0x00, 0));
+	drawScr();
+	clrScr(GS_SETREG_RGBA(0x00, 0x00, 0x00, 0));
+	drawScr();
+	free(setting);
+	free(elisaFnt);
+	free(External_Lang_Buffer);
+	padPortClose(1,0);
+	padPortClose(0,0);
+	if(ps2kbd_opened) PS2KbdClose();
+	TimerEnd();
+}
+//------------------------------
+//endfunc CleanUp
+//---------------------------------------------------------------------------
+// Run ELF. The generic ELF launcher.
+//------------------------------
+void RunElf(char *pathin)
+{
+	char tmp[MAX_PATH];
+	static char path[MAX_PATH];
+	static char fullpath[MAX_PATH];
+	static char party[40];
+	char *pathSep;
+	char *p;
+	int x, t=0;
+	char dvdpl_path[] = "mc0:/BREXEC-DVDPLAYER/dvdplayer.elf";
+	int dvdpl_update;
+
+	if(pathin[0]==0) return;
+	
+	if( !uLE_related(path, pathin) ) //1==uLE_rel 0==missing, -1==other dev
+		return;
+
+Recurse_for_ESR:          //Recurse here for PS2Disc command with ESR disc
+
+	pathSep = strchr(path, '/');
+
+	if(!strncmp(path, "mc", 2)){
+		party[0] = 0;
+		if(path[2]!=':')
+			goto CheckELF_path;
+		strcpy(fullpath, "mc0:");
+		strcat(fullpath, path+3);
+		if(checkELFheader(fullpath)>0)
+			goto ELFchecked;
+		fullpath[2]='1';
+		goto CheckELF_fullpath;
+
+	}else if(!strncmp(path, "vmc", 3)){
+		x = path[3] - '0';
+		if((x<0)||(x>1)||!vmcMounted[x])
+			goto ELFnotFound;
+		goto CheckELF_path;
+	}else if(!strncmp(path, "hdd0:/", 6)){
+		loadHddModules();
+		if((t=checkELFheader(path))<=0)
+			goto ELFnotFound;
+		//coming here means the ELF is fine
+		sprintf(party, "hdd0:%s", path+6);
+		p = strchr(party, '/');
+		sprintf(fullpath, "pfs0:%s", p);
+		*p = 0;
+		goto ELFchecked;
+
+	}else if(!strncmp(path, "mass", 4)){
+		loadUsbModules();
+		if((t=checkELFheader(path))<=0)
+			goto ELFnotFound;
+		//coming here means the ELF is fine
+		party[0] = 0;
+
+		strcpy(fullpath, path);
+		if(pathSep && (pathSep-path<7) && pathSep[-1]==':')
+			strcpy(fullpath+(pathSep-path), pathSep+1);
+		goto ELFchecked;
+
+	}else if(!strncmp(path, "host:", 5)){
+		initHOST();
+		party[0] = 0;
+		strcpy(fullpath, "host:");
+		if(path[5] == '/')
+			strcat(fullpath, path+6);
+		else
+			strcat(fullpath, path+5);
+		makeHostPath(fullpath, fullpath);
+		goto CheckELF_fullpath;
+
+	}else if(!stricmp(path, setting->Misc_PS2Disc)){
+		drawMsg(LNG(Reading_SYSTEMCNF));
+		party[0]=0;
+		readSystemCnf();
+		if(BootDiscType==2){ //Boot a PS2 disc
+			strcpy(fullpath, SystemCnf_BOOT2);
+			goto CheckELF_fullpath;
+		}
+		if(BootDiscType==1){ //Boot a PS1 disc
+			char *args[2] = {SystemCnf_BOOT, SystemCnf_VER};
+			CleanUp();
+			LoadExecPS2("rom0:PS1DRV", 2, args);
+			sprintf(mainMsg, "PS1DRV %s", LNG(Failed));
+			goto Done_PS2Disc;
+		}
+		if(uLE_cdDiscValid()){
+			if(cdmode == CDVD_TYPE_DVDVIDEO){
+				load_chkesr_module(); //prepare to check for ESR disc
+				x = Check_ESR_Disc();
+				printf("Check_ESR_Disc => %d\n", x);
+				if(x > 0){	//ESR Disc, so launch ESR
+					if(setting->LK_Flag[15] && setting->LK_Path[15][0])
+						strcpy(path, setting->LK_Path[15]);
+					else
+						strcpy(path, default_ESR_path);
+
+					goto Recurse_for_ESR;
+				}
+
+				//DVD Video Disc, so launch DVD player
+				char arg0[20], arg1[20], arg2[20], arg3[40];
+				char *args[4] = {arg0, arg1, arg2, arg3};
+				char kelf_loader[40];
+				char MG_region[10];
+				int i, pos, tst, argc;
+
+				if ((tst = SifLoadModule("rom0:ADDDRV", 0, NULL)) < 0)
+					goto Fail_DVD_Video;
+
+				strcpy(arg0, "-k rom1:EROMDRVA");
+				strcpy(arg1, "-m erom0:UDFIO");
+				strcpy(arg2, "-x erom0:DVDPLA");
+				argc = 3;
+				strcpy(kelf_loader, "moduleload2 rom1:UDNL rom1:DVDCNF");
+
+				strcpy(MG_region, "ACEJMORU");
+				pos = strlen(arg0)-1;
+				for(i=0; i<9 ; i++){ //NB: MG_region[8] is a string terminator
+					arg0[pos] = MG_region[i];
+					tst = SifLoadModuleEncrypted(arg0+3, 0, NULL);
+					if(tst >= 0)
+						break;
+				}
+
+				pos = strlen(arg2);
+				if(i == 8)
+					strcpy(&arg2[pos-3], "ELF");
+				else
+					arg2[pos-1] = MG_region[i];
+				//At this point all args are ready to use internal DVD player
+
+				//We must check for an updated player on MC
+				dvdpl_path[6] = ROMVER_data[4];
+				dvdpl_update = 0;
+				for(i=0; i<2; i++){
+					dvdpl_path[2] = '0'+i;
+					if(exists(dvdpl_path)){
+						dvdpl_update = 1;
+						break;
+					}
+				}
+
+				if((tst < 0) && (dvdpl_update == 0))
+						goto Fail_PS2Disc; //We must abort if no working kelf found
+
+				if(dvdpl_update){	// Launch DVD player from memory card
+					strcpy(arg0, "-m rom0:SIO2MAN");
+					strcpy(arg1, "-m rom0:MCMAN");
+					strcpy(arg2, "-m rom0:MCSERV");
+					sprintf(arg3, "-x %s", dvdpl_path); // -x :elf is encrypted for mc
+					argc = 4;
+					strcpy(kelf_loader, "moduleload");
+				}
+
+				CleanUp();
+				LoadExecPS2(kelf_loader, argc, args);
+
+Fail_DVD_Video:
+				sprintf(mainMsg, "DVD-Video %s", LNG(Failed));
+				goto Done_PS2Disc;
+			}
+			if(cdmode == CDVD_TYPE_CDDA){
+//Fail_CDDA:
+				sprintf(mainMsg, "CDDA %s", LNG(Failed));
+				goto Done_PS2Disc;
+			}
+		}
+Fail_PS2Disc:
+		sprintf(mainMsg, "%s => %s CDVD 0x%02X", LNG(PS2Disc), LNG(Failed), cdmode);
+Done_PS2Disc:
+		x = x;
+	}else if(!stricmp(path, setting->Misc_FileBrowser)){
+		if (setting->GUI_skin[0]) {
+			GUI_active = 0;
+			loadSkin(BACKGROUND_PIC, 0, 0);
+		}
+		mainMsg[0] = 0;
+		tmp[0] = 0;
+		LastDir[0] = 0;
+		getFilePath(tmp, FALSE);
+		if(tmp[0])
+			RunElf(tmp);
+		return;
+	}else if(!stricmp(path, setting->Misc_PS2Browser)){
+		__asm__ __volatile__(
+			"	li $3, 0x04;"
+			"	syscall;"
+			"	nop;"
+		);
+		//There has been a major change in the code for calling PS2Browser
+		//The method above is borrowed from PS2MP3. It's independent of ELF loader
+		//The method below was used earlier, but causes reset with new ELF loader
+		//party[0]=0;
+		//strcpy(fullpath,"rom0:OSDSYS");
+	}else if(!stricmp(path, setting->Misc_PS2Net)){
+		mainMsg[0] = 0;
+		loadNetModules();
+		return;
+	}else if(!stricmp(path, setting->Misc_PS2PowerOff)){
+		mainMsg[0] = 0;
+		drawMsg(LNG(Powering_Off_Console));
+		setupPowerOff();
+		//hddPowerOff(); //deprecated
+		poweroffShutdown();
+		poweroff_delay = 250; //trigger delay for those without net adapter
+		poweroff_start = Timer();
+		return;
+	}else if(!stricmp(path, setting->Misc_HddManager)){
+		if (setting->GUI_skin[0]) {
+			GUI_active = 0;
+			loadSkin(BACKGROUND_PIC, 0, 0);
+		}
+		hddManager();
+		return;
+	}else if(!stricmp(path, setting->Misc_TextEditor)){
+		if (setting->GUI_skin[0]) {
+			GUI_active = 0;
+			loadSkin(BACKGROUND_PIC, 0, 0);
+		}
+		TextEditor();
+		return;
+	}else if(!stricmp(path, setting->Misc_JpgViewer)){
+		if (setting->GUI_skin[0]) {
+			GUI_active = 0;
+			loadSkin(BACKGROUND_PIC, 0, 0);
+		}
+		JpgViewer();
+		return;
+	}else if(!stricmp(path, setting->Misc_Configure)){
+		if (setting->GUI_skin[0]) {
+			GUI_active = 0;
+			loadSkin(BACKGROUND_PIC, 0, 0);
+			Load_External_Language();
+			loadFont(setting->font_file);
+		}
+		config(mainMsg, CNF);
+		return;
+	}else if(!stricmp(path, setting->Misc_Load_CNFprev)){
+		decConfig();
+		return;
+	}else if(!stricmp(path, setting->Misc_Load_CNFnext)){
+		incConfig();
+		return;
+	}else if(!stricmp(path, setting->Misc_Set_CNF_Path)){
+		Set_CNF_Path();
+		return;
+	}else if(!stricmp(path, setting->Misc_Load_CNF)){
+		reloadConfig();
+		return;
+//Next clause is for an optional font test routine
+	}else if(!stricmp(path, setting->Misc_ShowFont)){
+		ShowFont();
+		return;
+	}else if(!stricmp(path, setting->Misc_Debug_Info)){
+		if (setting->GUI_skin[0]) {
+			GUI_active = 0;
+			loadSkin(BACKGROUND_PIC, 0, 0);
+		}
+		ShowDebugInfo();
+		return;
+	}else if(!stricmp(path, setting->Misc_About_uLE)){
+		if (setting->GUI_skin[0]) {
+			GUI_active = 0;
+			loadSkin(BACKGROUND_PIC, 0, 0);
+		}
+		Show_About_uLE();
+		return;
+	}else if(!strncmp(path, "cdfs", 4)){
+		loadCdModules();
+		CDVD_FlushCache();
+		CDVD_DiskReady(0);
+		party[0] = 0;
+		goto CheckELF_path;
+	}else if(!strncmp(path, "rom", 3)){
+		party[0] = 0;
+CheckELF_path:
+		strcpy(fullpath, path);
+CheckELF_fullpath:
+		if((t=checkELFheader(fullpath))<=0)
+			goto ELFnotFound;
+ELFchecked:
+		CleanUp();
+		RunLoaderElf(fullpath, party);
+	}else{ //Invalid path
+		t = 0;
+ELFnotFound:
+		if(t==0)
+			sprintf(mainMsg, "%s %s.", fullpath, LNG(is_Not_Found));
+		else
+			sprintf(mainMsg, "%s: %s.", LNG(This_file_isnt_an_ELF), fullpath);
+		return;
+	}
+}
+//------------------------------
+//endfunc RunElf
+//---------------------------------------------------------------------------
+// reboot IOP (original source by Hermes in BOOT.c - cogswaploader)
+// dlanor: but changed now, as the original was badly bugged
+void Reset()
+{
+	SifIopReset("rom0:UDNL rom0:EELOADCNF",0);
+	while(!SifIopSync());
+	fioExit();
+	SifExitIopHeap();
+	SifLoadFileExit();
+	SifExitRpc();
+	SifExitCmd();
+
+	SifInitRpc(0);
+	FlushCache(0);
+	FlushCache(2);
+
+	have_cdvd     = 0;
+	have_usbd     = 0;
+	have_usb_mass = 0;
+	have_ps2smap  = 0;
+	have_ps2host  = 0;
+	have_ps2ftpd  = 0;
+	have_ps2kbd   = 0;
+	have_NetModules = 0;
+	have_HDD_modules = 0;
+	have_sbv_patches = 0;
+
+	CheckModules();
+	loadBasicModules();
+	mcReset();
+	mcInit(MC_TYPE_MC);
+//	padReset();
+//	setupPad();
+}
+//------------------------------
+//endfunc Reset
+//---------------------------------------------------------------------------
+int uLE_detect_TV_mode()
+{
+	int ROMVER_fd;
+
+	ROMVER_fd = genOpen("rom0:ROMVER", O_RDONLY);
+	if(ROMVER_fd < 0)
+		return TV_mode_NTSC; //NTSC is default mode for unidentified console
+	genRead(ROMVER_fd, ROMVER_data, 16);
+	genClose(ROMVER_fd);
+	ROMVER_data[16] = 0;
+
+	if(ROMVER_data[4] == 'E')
+		return TV_mode_PAL; //PAL mode is identified by 'E' for Europe
+	return TV_mode_NTSC;  //All other cases need NTSC
+}
+//------------------------------
+//endfunc uLE_detect_TV_mode
+//---------------------------------------------------------------------------
+int main(int argc, char *argv[])
+{
+	char *p, CNF_pathname[MAX_PATH];
+	int event, post_event=0;
+	char RunPath[MAX_PATH];
+	int RunELF_index, nElfs=0;
+	int hdd_booted = 0;
+	int host_or_hdd_booted = 0;
+	int mass_booted = 0; //flags boot made with compatible mass drivers
+	int mass_needed = 0; //flags need to load compatible mass drivers
+	int mc_booted = 0;
+	int cdvd_booted = 0;
+	int	host_booted = 0;
+	int gs_vmode;
+	int CNF_error = -1; //assume error until CNF correctly loaded
+	int i;
+
+	boot_argc = argc;
+	for(i=0; (i<argc)&&(i<8); i++)
+		boot_argv[i] = argv[i];
+
+	SifInitRpc(0);
+	CheckModules();
+	loadBasicModules();
+	mcInit(MC_TYPE_MC);
+	genInit();
+	Init_Default_Language();
+
+	force_IOP = 0;
+	LaunchElfDir[0] = 0;
+	if	((argc > 0) && argv[0]){
+		strcpy(LaunchElfDir, argv[0]);
+		if	(!strncmp(argv[0], "mass", 4)){
+			if(!strncmp(argv[0], "mass0:\\", 7)){  //SwapMagic boot path for usb_mass
+				//Transform the boot path to homebrew standards
+				LaunchElfDir[4]=':';
+				strcpy(&LaunchElfDir[5], &LaunchElfDir[7]);
+				for(i=0; LaunchElfDir[i]!=0; i++){
+					if(LaunchElfDir[i] == '\\')
+						LaunchElfDir[i] = '/';
+				}
+				force_IOP = 1;   //Note incompatible drivers present (as yet ignored)
+				mass_needed = 1; //Note need to load compatible mass: drivers
+			} else {  //else we booted with normal homebrew mass: drivers
+				mass_booted = 1; //Note presence of compatible mass: drivers
+			}
+		}
+		else if	(!strncmp(argv[0], "mc", 2))
+			mc_booted = 1;
+		else if	(!strncmp(argv[0], "cd", 2))
+			cdvd_booted = 1;
+		else if	((!strncmp(argv[0], "hdd", 3)) || (!strncmp(argv[0], "pfs", 3)))
+			hdd_booted = 1;  //Modify this section later to cover Dev2 needs !!!
+	}
+	strcpy(boot_path, LaunchElfDir);
+
+	if(!strncmp(LaunchElfDir, "host",4)) {
+		host_or_hdd_booted = 1;
+		if	(have_fakehost)
+			hdd_booted = 1;
+		else
+			host_booted = 1;
+	}
+
+	if	(host_booted)	//Fix untestable modules for host booting
+	{	have_ps2smap = 1;
+		have_ps2host	= 1;
+	}
+
+	if	(mass_booted)	//Fix untestable module for USB_mass booting
+	{	have_usbd = 1;
+		have_usb_mass = 1;
+	}
+
+	if	(	((p=strrchr(LaunchElfDir, '/'))==NULL)
+			&&((p=strrchr(LaunchElfDir, '\\'))==NULL)
+			)	p=strrchr(LaunchElfDir, ':');
+	if	(p!=NULL)
+		*(p+1)=0;
+	//The above cuts away the ELF filename from LaunchElfDir, leaving a pure path
+
+	if(hdd_booted && !strncmp(LaunchElfDir, "hdd", 3)){;
+		//Patch DMS4 Dev2 booting here, when we learn more about how it works
+		//Trying to mount that partition for loading CNF simply crashes.
+		//We may need a new IOP reset method for this.
+	}
+
+	LastDir[0] = 0;
+
+	if(uLE_detect_TV_mode() == TV_mode_PAL) {  //Test console TV mode
+		SCREEN_X			= 652;
+		SCREEN_Y			= 72;
+	} else {
+		SCREEN_X			= 632;
+		SCREEN_Y			= 50;
+	}
+
+	//RA NB: loadConfig needs  SCREEN_X and SCREEN_Y to be defaults matching TV mode
+	CNF_error = loadConfig(mainMsg, strcpy(CNF, "LAUNCHELF.CNF"));
+	if(CNF_error<0)
+		strcpy(CNF_pathname, mainMsg+strlen(LNG(Failed_To_Load)));
+	else
+		strcpy(CNF_pathname, mainMsg+strlen(LNG(Loaded_Config)));
+
+	TV_mode = setting->TV_mode;
+	if((TV_mode!=TV_mode_NTSC)&&(TV_mode!=TV_mode_PAL)){ //If no forced request
+		TV_mode = uLE_detect_TV_mode();  //Let console region decide TV_mode
+	}
+
+	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;
+		Menu_end_y			= Menu_start_y + 26*FONT_HEIGHT;
+	}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;
+		Menu_end_y		 = Menu_start_y + 22*FONT_HEIGHT;
+	} /* end else */
+	Frame_end_y			= Menu_end_y + 4;
+	Menu_tooltip_y	= Frame_end_y + LINE_THICKNESS + 2;
+
+	maxCNF = setting->numCNF;
+	swapKeys = setting->swapKeys;
+	if(setting->resetIOP)
+	{	Reset();
+		if(!strncmp(LaunchElfDir, "mass", 4))
+		{	initsbv_patches();
+			loadUsbModules();
+		}
+		else if(!strncmp(LaunchElfDir, "host:", 5))
+		{	getIpConfig();
+			initsbv_patches();
+			initHOST();
+		}
+	}
+	//Here IOP reset (if done) has been completed, so it's time to load and init drivers
+	getIpConfig();
+	initsbv_patches();
+
+	if(setting->discControl)
+		loadCdModules();
+
+	TimerInit();
+	WaitTime=Timer();
+	setupPad(); //Comment out this line when using early setupPad above
+	startKbd();
+	TimerInit();
+	WaitTime=Timer();
+
+	init_delay = setting->Init_Delay*1000;
+	init_delay_start = Timer();
+	timeout = (setting->timeout+1)*1000;
+	timeout_start = Timer();
+
+//Last chance to look at bootup screen, so allow braking here
+/*
+	if(readpad() && (new_pad && PAD_UP))
+	{ scr_printf("________ Boot paused. Press 'Circle' to continue.\n");
+		while(1)
+		{	if(new_pad & PAD_CIRCLE)
+				break;
+			while(!readpad());
+		}
+	}
+*/
+	setupGS(gs_vmode);
+	updateScreenMode(0); //resolves screen position issue with newer gsKit
+	gsKit_clear(gsGlobal, GS_SETREG_RGBAQ(0x00,0x00,0x00,0x00,0x00));
+
+	loadFont("");  //Some font must be loaded before loading some device modules
+	Load_External_Language();
+	loadFont(setting->font_file);
+	if (setting->GUI_skin[0]) {GUI_active = 1;}
+	loadSkin(BACKGROUND_PIC, 0, 0);
+
+	gsKit_clear(gsGlobal, GS_SETREG_RGBAQ(0x00,0x00,0x00,0x00,0x00));
+
+	if(CNF_error<0)
+		sprintf(mainMsg, "%s%s", LNG(Failed_To_Load), CNF_pathname);
+	else
+		sprintf(mainMsg, "%s%s", LNG(Loaded_Config), CNF_pathname);
+
+	//Here nearly everything is ready for the main menu event loop
+	//But before we start that, we need to validate CNF_Path
+	Validate_CNF_Path();
+
+	RunPath[0] = 0; //Nothing to run yet
+	cdmode = -1; //flag unchecked cdmode state
+	event = 1;   //event = initial entry
+	//----- Start of main menu event loop -----
+	while(1){
+		int DiscType_ix;
+
+		//Background event section
+		if(!setting->discControl)
+			goto done_discControl;
+	
+		uLE_cdStop(); //Test disc state and if needed stop disc (updates cdmode)
+		if(cdmode == old_cdmode) //if disc detection did not change state
+			goto done_discControl;
+
+		event |= 4;  //event |= disc change detection
+		if(cdmode<=0)
+			sprintf(mainMsg, "%s ", LNG(No_Disc));
+		else if(cdmode>=1 && cdmode<=4)
+			sprintf(mainMsg, "%s == ", LNG(Detecting_Disc));
+		else //if(cdmode>=5)
+			sprintf(mainMsg, "%s == ", LNG(Stop_Disc));
+
+		DiscType_ix = 0;
+		for(i=0; DiscTypes[i].name[0]; i++)
+			if(DiscTypes[i].type == uLE_cdmode)
+				DiscType_ix = i;
+
+		sprintf(mainMsg+strlen(mainMsg), DiscTypes[DiscType_ix].name);
+		//Comment out the debug output below when not needed
+		/*
+		sprintf(mainMsg+strlen(mainMsg),
+			"  cdmode==%d  uLE_cdmode==%d  type_ix==%d",
+			cdmode, uLE_cdmode, DiscType_ix);
+		//*/
+done_discControl:
+		if(poweroff_delay) {
+			CurrTime = Timer();
+			if(CurrTime > (poweroff_start + poweroff_delay)){
+				poweroff_delay = 0;
+				triggerPowerOff();
+			}
+		}
+
+		if(init_delay){
+			prev_init_delay = init_delay;
+			CurrTime = Timer();
+			if(CurrTime > (init_delay_start + init_delay)){
+				init_delay = 0;
+				timeout_start = CurrTime;
+			}else{
+				init_delay = init_delay_start + init_delay - CurrTime;
+				init_delay_start = CurrTime;
+			}
+			if((init_delay/1000) != (prev_init_delay/1000))
+				event |= 8;  //event |= visible delay change
+		}else if(timeout && !user_acted){
+			prev_timeout = timeout;
+			CurrTime = Timer();
+			if(CurrTime > (timeout_start + timeout)){
+				timeout = 0;
+			}else{
+				timeout = timeout_start + timeout - CurrTime;
+				timeout_start = CurrTime;
+			}
+			if((timeout/1000) != (prev_timeout/1000))
+				event |= 8;  //event |= visible timeout change
+		}
+
+		//Display section
+		if(event||post_event){  //NB: We need to update two frame buffers per event
+			if (!(setting->GUI_skin[0]))
+				nElfs = drawMainScreen(); //Display pure text GUI on generic background
+			else if (!setting->Show_Menu) { //Display only GUI jpg
+				setLaunchKeys();
+				clrScr(setting->color[0]);
+			}
+			else //Display launch filenames/titles on GUI jpg
+				nElfs = drawMainScreen2(TV_mode);
+		}
+		drawScr();
+		post_event = event;
+		event = 0;
+
+		//Pad response section
+		if(!init_delay && (waitAnyPadReady(), readpad())){
+			if(new_pad){
+				event |= 2;  //event |= pad command
+			}
+			RunELF_index = -1;
+			switch(mode){
+			case BUTTON:
+				if(new_pad & PAD_CIRCLE)        RunELF_index = 1;
+				else if(new_pad & PAD_CROSS)    RunELF_index = 2;
+				else if(new_pad & PAD_SQUARE)   RunELF_index = 3;
+				else if(new_pad & PAD_TRIANGLE) RunELF_index = 4;
+				else if(new_pad & PAD_L1)       RunELF_index = 5;
+				else if(new_pad & PAD_R1)       RunELF_index = 6;
+				else if(new_pad & PAD_L2)       RunELF_index = 7;
+				else if(new_pad & PAD_R2)       RunELF_index = 8;
+				else if(new_pad & PAD_L3)       RunELF_index = 9;
+				else if(new_pad & PAD_R3)       RunELF_index = 10;
+				else if(new_pad & PAD_START)    RunELF_index = 11;
+				else if(new_pad & PAD_SELECT)   RunELF_index = 12;
+				else if((new_pad & PAD_LEFT) && (maxCNF > 1 || setting->LK_Flag[13]))
+					RunELF_index = 13;
+				else if((new_pad & PAD_RIGHT) && (maxCNF > 1 || setting->LK_Flag[14]))
+					RunELF_index = 14;
+				else if(new_pad & PAD_UP || new_pad & PAD_DOWN){
+					user_acted = 1;
+					if (!setting->Show_Menu && setting->GUI_skin[0]){} //GUI Menu: disabled when there's no text on menu screen
+					else{
+						selected=0;
+						mode=DPAD;
+					}
+				}
+				if(RunELF_index >= 0 && setting->LK_Path[RunELF_index][0])
+					strcpy(RunPath, setting->LK_Path[RunELF_index]);
+				break;
+			
+			case DPAD:
+				if(new_pad & PAD_UP){
+					selected--;
+					if(selected<0)
+						selected=nElfs-1;
+				}else if(new_pad & PAD_DOWN){
+					selected++;
+					if(selected>=nElfs)
+						selected=0;
+				}else if((!swapKeys && new_pad & PAD_CROSS)
+				      || (swapKeys && new_pad & PAD_CIRCLE) ){
+					mode=BUTTON;
+				}else if((swapKeys && new_pad & PAD_CROSS)
+				      || (!swapKeys && new_pad & PAD_CIRCLE) ){
+					if(setting->LK_Path[menu_LK[selected]][0])
+						strcpy(RunPath, setting->LK_Path[menu_LK[selected]]);
+				}
+				break;
+			}//ends switch(mode)
+		}//ends Pad response section
+
+		if(!user_acted && ((timeout/1000)==0) && setting->LK_Path[0][0] && mode==BUTTON){
+			event |= 8;  //event |= visible timeout change
+			strcpy(RunPath, setting->LK_Path[0]);
+		}
+
+		if(RunPath[0]){
+			user_acted = 1;
+			mode=BUTTON;
+			RunElf(RunPath);
+			RunPath[0] = 0;
+			if (setting->GUI_skin[0]){
+				GUI_active = 1;
+				loadSkin(BACKGROUND_PIC, 0, 0);
+				//Load_External_Language();
+				//loadFont(setting->font_file);
+			}
+		}
+	}//ends while(1)
+	//----- End of main menu event loop -----
+}
+//------------------------------
+//endfunc main
+//---------------------------------------------------------------------------
+//End of file: main.c
+//---------------------------------------------------------------------------
Index: ps2launchargs/source/uLaunchELF/makeicon.c
===================================================================
--- ps2launchargs/source/uLaunchELF/makeicon.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/makeicon.c	(revision 1101)
@@ -0,0 +1,360 @@
+//--------------------------------------------------------------
+//File name:   makeicon.c
+//--------------------------------------------------------------
+#include "launchelf.h"
+#include "libmc.h"
+#include "math.h"
+extern u8 font_uLE[];
+
+u16* tex_buffer;
+
+#define ICON_WIDTH 	128
+#define ICON_HEIGHT 128
+#define ICON_MARGIN 0
+#define FONT_WIDTH 	8
+#define FONT_HEIGHT 16
+
+//f16 = s16/4096
+#define f16 s16
+#define f32 float
+//--------------------------------------------------------------
+struct icon_header
+{
+	u32 icon_id;		  // PS2 icon id = 0x010000
+	u32 anim_shapes;	// number of animation shapes
+	u32 texture_type;	// 0x07=uncompressed
+	u32 UNKNOWN;		  // always 0x3F800000
+	u32 num_vertices;	// always multiple of 3
+};
+//--------------------------------------------------------------
+struct icon_vertex
+{
+	f16 xyz[3];
+	u16 w;		//no idea what this is //RA: but it is required, though it may be zeroed
+};
+//--------------------------------------------------------------
+struct icon_texturedata
+{
+	f16	uv[2];
+	u8  rgba[4];
+};
+//--------------------------------------------------------------
+struct icon_animheader
+{
+	u32 id;			//always 0x01
+	u32 frame_length;
+	f32 anim_speed;
+	u32 play_offset;
+	u32 num_frames;
+};
+//--------------------------------------------------------------
+struct icon_framedata
+{
+	u32 shapeid;
+	u32 num_keys;
+	u32 time;
+	u32 value;
+};
+//--------------------------------------------------------------
+// A few cheap defines for assigning vector and texture coordinates to vertices
+//Set vector coordinate value of a vertex
+#define set_vv(coord,x,y,z)\
+		coord.xyz[0]=4096*x;\
+		coord.xyz[1]=4096*y;\
+		coord.xyz[2]=4096*z;\
+		coord.w     = 0;
+//--------------------------------------------------------------
+// Set texture coordinate value of a vertex
+#define set_tv(uv,u,v)\
+		uv[0]=u*4096;\
+		uv[1]=v*4096;
+//--------------------------------------------------------------
+// draw a char using the system font (16x16)
+void tex_drawChar(unsigned int c, int x, int y, u16 colour)
+{
+	int i, j, k, pixBase, pixMask;
+	u8  *cm;
+
+	u16 temp_image[16][32];
+	// blank out the memory(was causing issues before)
+	for (i=0;i<16;i++)
+		for(j=0;j<32;j++)
+			temp_image[i][j]=0x0000;
+	
+	if(c >= 0x11A) c = '_';
+	cm = &font_uLE[c*16]; //cm points to the character definition in the font
+	
+	pixMask = 0x80;
+	for(i=0; i<8; i++){	//for i == each pixel column
+		pixBase = -1;
+		for(j=0; j<16; j++){ //for j == each pixel row
+			if((pixBase < 0) && (cm[j] & pixMask)){ //if start of sequence
+				pixBase = j;
+			} else if((pixBase > -1) && !(cm[j] & pixMask)){ //if end of sequence
+				for(k=pixBase;k<j;k++)
+					temp_image[i*2][k*2]=0xFFFF;//every other pixel is blank
+				pixBase = -1;
+			}
+		}//ends for j == each pixel row
+		if(pixBase > -1) //if end of sequence including final row
+		{
+			for(k=pixBase;k<j;k++)
+				temp_image[i*2][k*2]=0xFFFF;
+		}
+		pixMask >>= 1;
+	}//ends for i == each pixel column
+	
+	// OR's with the previous bit in the row to fill in the blank space
+	for (i=1;i<16;i+=2)
+		for(j=0;j<32;j++)
+			temp_image[i][j]=temp_image[i-1][j]|temp_image[i][j];
+	
+	// OR's with the previous bit in the column to fill in the blank space
+	for(j=1;j<32;j+=2)
+		for (i=0;i<16;i++)
+			temp_image[i][j]=temp_image[i][j-1]|temp_image[i][j];
+	
+	//store the temp image buffer into the real image buffer
+	for (i=0;i<16;i++)
+		for (j=0;j<32;j++)
+			tex_buffer[x+i + (y+j)*128]=temp_image[i][j];
+}
+//--------------------------------------------------------------
+// draw a string of characters to an icon texture, without shift-JIS support
+// NOTE: I added in the ability for \n to be part of the string, don't know if its
+// necessary though, although there are some cases where it doesnt work
+
+int tex_printXY(const unsigned char *s, int x, int y, u16 colour)
+{
+	unsigned int c1, c2;
+	int i;
+	int text_spacing=16;//we magnified font
+	int x_orig = x;
+	int x_max = x;
+	i=0;
+	while((c1=s[i++])!=0) {
+		if (c1 == '\t'){			//'Horizontal Tab' code ?
+			x += FONT_WIDTH;		//use HT to step half a char space, for centering odd chars
+			continue;		//loop back to try next character
+		}
+		if (c1 == '\v')				//'Vertical Tab' code ?
+			goto force_halfrow;	//use VT to step half a row down, for centering odd rows
+		if (c1 == '\r'){			//'Carriage Return' code ?
+force_newrow:							//use CR to step a full row down, and restart a row
+			y += FONT_HEIGHT;
+force_halfrow:				//This label is used to allow centering of odd rows
+			y += FONT_HEIGHT;
+			if(x > x_max)
+				x_max = x;
+			x = x_orig;
+			continue;		//loop back to try next character
+		}
+		if(y > ICON_HEIGHT - 2*FONT_HEIGHT) //if insufficient room for current row
+			break;                 //then cut the string rendering here
+		if(x > ICON_WIDTH-ICON_MARGIN-2*FONT_WIDTH){	//if out of room on current row
+			i--;                                     		//back index to retry on next loop
+			goto force_newrow;                       		//and cut this row here.
+		}
+		//Here we know there is room for at least one char on current row
+		if(c1 != 0xFF) { // Normal character
+norm_char:
+			tex_drawChar(c1, x, y, colour);
+			x += text_spacing;
+			continue;
+		}  //End if for normal character
+		// Here we got a sequence starting with 0xFF ('ÿ')
+		if((c2=s[i++])==0){	//if that was the final character
+			i--;              //back index to retry on next loop
+			goto norm_char;		//and go display 'ÿ' as any other character
+		}
+		//Here we deal with any sequence prefixed by 'ÿ'
+		if((c2 < '0') || (c2 > '='))	//if the sequence is illegal
+			continue;                   //then just ignore it
+		c1=(c2-'0')*2+0x100;            //generate adjusted char code > 0xFF
+		tex_drawChar(c1, x, y, colour); //render this base character to texture
+		x += text_spacing;
+		if((c2 > '4') && (c2 < ':'))	//if this is a normal-width character
+			continue;										//continue with the next loop
+		//compound sequence 'ÿ0'=Circle 'ÿ1'=Cross 'ÿ2'=Square 'ÿ3'=Triangle
+		//'ÿ4'=FilledBox 'ÿ:'=Pad_Rt 'ÿ;'=Pad_Dn 'ÿ<'=Pad_Lt 'ÿ='=Pad_Up 
+		if(x > ICON_WIDTH-ICON_MARGIN-2*FONT_WIDTH) //if out of room for compound character ?
+			goto force_newrow;                     		//then cut this row here.
+		tex_drawChar(c1+1, x, y, colour);	//render 2nd half of compound character
+		x += text_spacing;
+	}  // ends while(1)
+	if(x > x_max)
+		x_max = x;
+	return x_max;	//Return max X position reached (not needed for anything though)
+}
+
+//--------------------------------------------------------------
+//This is a quick and dirty RLE compression algorithm that assumes
+//everything is part of a run, and treats everything as a run,
+//regardless as to how long that run is.  It could be slightly
+//optimized, but the gains would be rather insignifigant.
+//NB: With the text magnification used, the assumption of each
+//sequence being a run longer than one pixel is always true.
+//--------------------------------------------------------------
+u32 tex_compresRLE() 
+{
+	u16* new_tex=(u16*)malloc(128*128*2);
+	u16 outbufferpos=0, runcounter=0, currentposition=0;
+	while(currentposition<128*128)
+	{
+		runcounter = 1;
+		// 16384 is size of the uncompressed texture/2
+		while (currentposition+runcounter<16384 && tex_buffer[currentposition] == tex_buffer[currentposition+runcounter]) 
+			runcounter++;
+		new_tex[outbufferpos++] = runcounter;
+		new_tex[outbufferpos++] = tex_buffer[currentposition];
+		currentposition += runcounter;
+	}
+
+	u32 size = outbufferpos*2; 
+	free(tex_buffer); 
+	tex_buffer = (u16*)malloc(size); 
+	memcpy(tex_buffer, new_tex, size);
+	free(new_tex);
+	return size;
+}
+//--------------------------------------------------------------
+//These defines multiplied like '4096*+xs' yield a standard sized flat icon
+#define xs 5/2
+#define ys 5/2
+#define zs 0
+//--------------------------------------------------------------
+/*
+ * Create an icon with the text 'icontext', and store in 'filename'
+ * returns 0 on success, -1 on failure
+ * 
+ * The position of the text is hard coded in on line 260
+ */
+//--------------------------------------------------------------
+int make_icon(char* icontext,char* filename)
+{
+	int i;
+	struct icon_header icn_head;
+	icn_head.icon_id		= 0x010000;
+	icn_head.anim_shapes	= 0x01;
+	icn_head.texture_type	= 0x0E;	//uncompressed=0x07
+	icn_head.UNKNOWN		= 0x3F800000;
+	icn_head.num_vertices	= 12;
+
+	struct icon_vertex icn_vertices[12];
+	struct icon_texturedata texdata[12];
+	struct icon_vertex normals[4];			//numvertices/3, as 3 vertices share one normal
+	//Back face				//Triangle Vertices   //Texture coordinates of vertices
+	set_vv(normals[0], 0, 0, 1);
+	set_vv(icn_vertices[ 0],-xs, -ys,  zs);	set_tv(texdata[ 0].uv,1,0);
+	set_vv(icn_vertices[ 1], xs, -ys,  zs);	set_tv(texdata[ 1].uv,0,0);
+	set_vv(icn_vertices[ 2], xs,  ys,  zs);	set_tv(texdata[ 2].uv,0,1);
+	set_vv(normals[1], 0, 0, 1);
+	set_vv(icn_vertices[ 3], xs,  ys,  zs);	set_tv(texdata[ 3].uv,0,1);
+	set_vv(icn_vertices[ 4],-xs,  ys,  zs);	set_tv(texdata[ 4].uv,1,1);
+	set_vv(icn_vertices[ 5],-xs, -ys,  zs);	set_tv(texdata[ 5].uv,1,0);
+	//Front face
+	set_vv(normals[2], 0, 0,-1);
+	set_vv(icn_vertices[ 6], xs, -ys, -zs);	set_tv(texdata[ 6].uv,1,0);
+	set_vv(icn_vertices[ 7],-xs, -ys, -zs);	set_tv(texdata[ 7].uv,0,0);
+	set_vv(icn_vertices[ 8],-xs,  ys, -zs);	set_tv(texdata[ 8].uv,0,1);
+	set_vv(normals[3], 0, 0,-1);
+	set_vv(icn_vertices[ 9],-xs,  ys, -zs);	set_tv(texdata[ 9].uv,0,1);
+	set_vv(icn_vertices[10], xs,  ys, -zs);	set_tv(texdata[10].uv,1,1);
+	set_vv(icn_vertices[11], xs, -ys, -zs);	set_tv(texdata[11].uv,1,0);
+	
+	for (i=0;i<icn_head.num_vertices;i++)
+	{
+		//the y values are generally too small, make them larger	
+		icn_vertices[i].xyz[1]-=ys*4096;//subtract increases?
+		texdata[i].rgba[0]=0x80;
+		texdata[i].rgba[1]=0x80;
+		texdata[i].rgba[2]=0x80;
+		texdata[i].rgba[3]=0x80;
+	}
+
+	struct icon_animheader icn_anim_head;
+	icn_anim_head.id=0x01;
+	icn_anim_head.frame_length=1;
+	icn_anim_head.anim_speed=1;
+	icn_anim_head.play_offset=0;
+	icn_anim_head.num_frames=1;
+
+	struct icon_framedata framedata;
+	framedata.shapeid=0;
+	framedata.num_keys=1;
+	framedata.time=1;
+	framedata.value=1;
+
+	// allocates room for the texture and sets the background to black
+	tex_buffer=malloc(128*128*2);		// the entire 128x128 pixel image(16bpp)
+	memset(tex_buffer,0x00,128*128*2);	// black background
+	tex_printXY(icontext,0,0,0xFFFF);	// (string,xpos,ypos,color)
+	u32 tex_size=tex_compresRLE();		// compress the texture, overwrites tex_buffer
+
+	int f=fioOpen(filename,O_WRONLY | O_CREAT);//open/create the file
+	if (f<0)return -1;
+	fioWrite(f,&icn_head,				sizeof(icn_head));
+	for (i=0;i<icn_head.num_vertices;i++)
+	{
+		fioWrite(f,&icn_vertices[i],	sizeof(icn_vertices[i]));
+		fioWrite(f,&normals[i/3],		sizeof(normals[i/3]));
+		fioWrite(f,&texdata[i],			sizeof(texdata[i]));
+	}
+	fioWrite(f,&icn_anim_head,			sizeof(icn_anim_head));
+	fioWrite(f,&framedata,				sizeof(framedata));
+	fioWrite(f,&tex_size,4);
+	fioWrite(f,tex_buffer,tex_size);
+	fioClose(f);
+	return 0;
+}
+//--------------------------------------------------------------
+/*
+ * This makes the icon.sys file that goes along with the icon itself
+ * text is the text that the browser shows (max of 32 characters)
+ * iconname is the icon file that it refers to(usually icon.icn/or icon.ico)
+ * filename is where to store the icon.sys file(eg: mc0:/FOLDER/icon.sys)
+ */
+//--------------------------------------------------------------
+int make_iconsys(char* title,char* iconname, char* filename)
+{
+	// mcIcon is defined as part of libmc
+	mcIcon icon_sys;
+
+	memset(((void *) &icon_sys), 0, sizeof(icon_sys));
+
+	strcpy(icon_sys.head,"PS2D");
+	icon_sys.nlOffset=0;//0=automagically wordwrap, otherwise newline position(multiple of 2)
+	strcpy_sjis((short *)&icon_sys.title, title);
+	
+	icon_sys.trans=0x40;
+	// default values from mcIconSysGen
+	iconIVECTOR bgcolor[4]={{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}};
+	iconFVECTOR ambientlight = {1,1,1,0};
+	iconFVECTOR lightdirection[3] = {
+		{ 0.5, 0.5, 0.5, 0.0 },
+		{ 0.0, 0.4,-0.1, 0.0 },
+		{-0.5,-0.5, 0.5, 0.0 },
+	};
+	iconFVECTOR lightcolors[3] = {
+		{ 0.5, 0.5, 0.5, 0.00 },
+		{ 0.7, 0.7, 0.7, 0.00 },
+		{ 0.5, 0.5, 0.5, 0.00 },
+	};
+	memcpy(icon_sys.bgCol, 	      bgcolor, 			sizeof(bgcolor));
+	memcpy(icon_sys.lightDir,     lightdirection, 	sizeof(lightdirection));
+	memcpy(icon_sys.lightCol, 	  lightcolors, 		sizeof(lightcolors));
+	memcpy(icon_sys.lightAmbient, ambientlight,		sizeof(ambientlight));
+	strcpy(icon_sys.view, 	iconname);
+	strcpy(icon_sys.copy, 	iconname);
+	strcpy(icon_sys.del, 	iconname);
+	
+	int f=fioOpen(filename,O_WRONLY | O_CREAT);// open/create the file
+	if(f<0)return -1;
+	fioWrite(f,&icon_sys,sizeof(icon_sys));
+	fioClose(f);
+
+	return 0;
+}
+//--------------------------------------------------------------
+//End of file: makeicon.c
+//--------------------------------------------------------------
Index: ps2launchargs/source/uLaunchELF/pad.c
===================================================================
--- ps2launchargs/source/uLaunchELF/pad.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/pad.c	(revision 1101)
@@ -0,0 +1,355 @@
+//---------------------------------------------------------------------------
+// File name:   pad.c
+//---------------------------------------------------------------------------
+#include "launchelf.h"
+
+static char padBuf_t[2][256] __attribute__((aligned(64)));
+struct padButtonStatus buttons_t[2];
+u32 padtype_t[2];
+u32 paddata, paddata_t[2];
+u32 old_pad = 0, old_pad_t[2] = {0, 0};
+u32 new_pad, new_pad_t[2];
+u32 joy_value = 0;
+static int test_joy = 0;
+
+//---------------------------------------------------------------------------
+// read PAD, without KB, and allow no auto-repeat. This is needed in code
+// that is used regardless of VSync cycles, and where KB is not wanted.
+//---------------------------------------------------------------------------
+int readpad_noKBnoRepeat(void)
+{
+	int port, state, ret[2];
+
+	for(port=0; port<2; port++){
+		if((state=padGetState(port, 0))==PAD_STATE_STABLE
+			||(state == PAD_STATE_FINDCTP1)){
+			//Deal with cases where pad state is valid for padRead
+			ret[port] = padRead(port, 0, &buttons_t[port]);
+			if (ret[port] != 0){
+				paddata_t[port] = 0xffff ^ buttons_t[port].btns;
+				new_pad_t[port] = paddata_t[port] & ~old_pad_t[port];
+				old_pad_t[port] = paddata_t[port];
+			}
+		}else{
+			//Deal with cases where pad state is not valid for padRead
+			new_pad_t[port]=0;
+		}  //ends 'if' testing for state valid for padRead
+	}  //ends for
+	new_pad = new_pad_t[0]|new_pad_t[1]; //This has only new button bits
+	paddata = paddata_t[0]|paddata_t[1]; //This has all pressed button bits
+	return (ret[0]|ret[1]);
+}
+//------------------------------
+//endfunc readpad_noKBnoRepeat
+//---------------------------------------------------------------------------
+// read PAD, but ignore KB. This is needed in code with own KB handlers,
+// such as the virtual keyboard input routines for 'Rename' and 'New Dir'
+//---------------------------------------------------------------------------
+int readpad_no_KB(void)
+{
+	static u64 rpt_time[2]={0,0};
+	static int rpt_count[2];
+	int port, state, ret[2];
+
+	for(port=0; port<2; port++){
+		if((state=padGetState(port, 0))==PAD_STATE_STABLE
+			||(state == PAD_STATE_FINDCTP1)){
+			//Deal with cases where pad state is valid for padRead
+			ret[port] = padRead(port, 0, &buttons_t[port]);
+			if (ret[port] != 0){
+				paddata_t[port] = 0xffff ^ buttons_t[port].btns;
+				if((padtype_t[port] == 2) && (1 & (test_joy++))){//DualShock && time for joy scan
+					joy_value=0;
+					if(buttons_t[port].rjoy_h >= 0xbf){
+						paddata_t[port]=PAD_R3_H1;
+						joy_value=buttons_t[port].rjoy_h-0xbf;
+					}else if(buttons_t[port].rjoy_h <= 0x40){
+						paddata_t[port]=PAD_R3_H0;
+						joy_value=-(buttons_t[port].rjoy_h-0x40);
+					}else if(buttons_t[port].rjoy_v <= 0x40){
+						paddata_t[port]=PAD_R3_V0;
+						joy_value=-(buttons_t[port].rjoy_v-0x40);
+					}else if(buttons_t[port].rjoy_v >= 0xbf){
+						paddata_t[port]=PAD_R3_V1;
+						joy_value=buttons_t[port].rjoy_v-0xbf;
+					}else if(buttons_t[port].ljoy_h >= 0xbf){
+						paddata_t[port]=PAD_L3_H1;
+						joy_value=buttons_t[port].ljoy_h-0xbf;
+					}else if(buttons_t[port].ljoy_h <= 0x40){
+						paddata_t[port]=PAD_L3_H0;
+						joy_value=-(buttons_t[port].ljoy_h-0x40);
+					}else if(buttons_t[port].ljoy_v <= 0x40){
+						paddata_t[port]=PAD_L3_V0;
+						joy_value=-(buttons_t[port].ljoy_v-0x40);
+					}else if(buttons_t[port].ljoy_v >= 0xbf){
+						paddata_t[port]=PAD_L3_V1;
+						joy_value=buttons_t[port].ljoy_v-0xbf;
+					}
+				}
+				new_pad_t[port] = paddata_t[port] & ~old_pad_t[port];
+				if(old_pad_t[port] == paddata_t[port]){
+					//no change of pad data
+					if(Timer() > rpt_time[port]){
+						new_pad_t[port]=paddata_t[port]; //Accept repeated buttons as new
+						rpt_time[port] = Timer() + 40; //Min delay = 40ms => 25Hz repeat
+						if(rpt_count[port]++ < 20)
+							rpt_time[port] += 43; //Early delays = 83ms => 12Hz repeat
+					}
+				}else{
+					//pad data has changed !
+					rpt_count[port] = 0;
+					rpt_time[port] = Timer()+400; //Init delay = 400ms
+					old_pad_t[port] = paddata_t[port];
+				}
+			}
+		}else{
+			//Deal with cases where pad state is not valid for padRead
+			//NB: This should NOT clear KB repeat test variables
+			new_pad_t[port]=0;
+			//old_pad_t[port]=0; //Clearing this could cause hasty repeats
+		}  //ends 'if' testing for state valid for padRead
+	}  //ends for
+	new_pad = new_pad_t[0]|new_pad_t[1];
+	paddata = paddata_t[0]|paddata_t[1]; //This has all pressed button bits
+	return (ret[0]|ret[1]);
+}
+//------------------------------
+//endfunc readpad_no_KB
+//---------------------------------------------------------------------------
+// simPadKB attempts reading data from a USB keyboard, and map this as a
+// virtual gamepad. (Very improvised and sloppy, but it should work fine.)
+//---------------------------------------------------------------------------
+int simPadKB(void)
+{
+	int	ret, command;
+	unsigned char KeyPress;
+
+	if((!setting->usbkbd_used)||(!PS2KbdRead(&KeyPress)))
+		return 0;
+	if(KeyPress != PS2KBD_ESCAPE_KEY)
+		command = KeyPress;
+	else {
+		PS2KbdRead(&KeyPress);
+		command = 0x100+KeyPress;
+	}
+	ret = 1;  //Assume that the entered key is a valid command
+	switch(command) {
+		case 0x11B:                 //Escape == Triangle
+			new_pad = PAD_TRIANGLE;
+			break;
+		case 0x00A:                 //Enter == OK
+		  if(!swapKeys)
+		  	new_pad = PAD_CIRCLE;
+		  else
+		  	new_pad = PAD_CROSS;
+		  break;
+		case 0x020:                 //Space == Cancel/Mark
+		  if(!swapKeys)
+		  	new_pad = PAD_CROSS;
+		  else
+		  	new_pad = PAD_CIRCLE;
+		  break;
+		case 0x031:                 //'1' == L1
+			new_pad = PAD_L1;
+			break;
+		case 0x032:                 //'2' == L2
+			new_pad = PAD_L2;
+			break;
+		case 0x033:                 //'3' == L3
+			new_pad = PAD_L3;
+			break;
+		case 0x077:                 //'w' == Up
+			new_pad = PAD_UP;
+			break;
+		case 0x061:                 //'a' == Left
+			new_pad = PAD_LEFT;
+			break;
+		case 0x073:                 //'s' == Right
+			new_pad = PAD_RIGHT;
+			break;
+		case 0x07A:                 //'z' == Down
+			new_pad = PAD_DOWN;
+			break;
+		case 0x030:                 //'0' == R1
+			new_pad = PAD_R1;
+			break;
+		case 0x039:                 //'9' == R2
+			new_pad = PAD_R2;
+			break;
+		case 0x038:                 //'8' == R3
+			new_pad = PAD_R3;
+			break;
+		case 0x069:                 //'i' == Triangle
+			new_pad = PAD_TRIANGLE;
+			break;
+		case 0x06A:                 //'j' == Square
+			new_pad = PAD_SQUARE;
+			break;
+		case 0x06B:                 //'k' == Circle
+			new_pad = PAD_CIRCLE;
+			break;
+		case 0x06D:                 //'m' == Cross
+			new_pad = PAD_CROSS;
+			break;
+		case 0x101:                 //F1 == L1
+			new_pad = PAD_L1;
+			break;
+		case 0x102:                 //F2 == L2
+			new_pad = PAD_L2;
+			break;
+		case 0x103:                 //F3 == L3
+			new_pad = PAD_L3;
+			break;
+		case 0x12C:                 //Up == Up
+			new_pad = PAD_UP;
+			break;
+		case 0x12A:                 //Left == Left
+			new_pad = PAD_LEFT;
+			break;
+		case 0x129:                 //Right == Right
+			new_pad = PAD_RIGHT;
+			break;
+		case 0x12B:                 //Down == Down
+			new_pad = PAD_DOWN;
+			break;
+		case 0x123:                 //Insert == Select
+			new_pad = PAD_SELECT;
+			break;
+		case 0x10C:                 //F12 == R1
+			new_pad = PAD_R1;
+			break;
+		case 0x10B:                 //F11 == R2
+			new_pad = PAD_R2;
+			break;
+		case 0x10A:                 //F10 == R3
+			new_pad = PAD_R3;
+			break;
+		case 0x124:                 //Home == Triangle
+			new_pad = PAD_TRIANGLE;
+			break;
+		case 0x127:                 //End == Square
+			new_pad = PAD_SQUARE;
+			break;
+		case 0x125:                 //PgUp == Circle
+			new_pad = PAD_CIRCLE;
+			break;
+		case 0x128:                 //PgDn == Cross
+			new_pad = PAD_CROSS;
+			break;
+		case 0x126:                 //Delete == Start
+			new_pad = PAD_START;
+			break;
+		default:                    //Unrecognized key => no pad button
+			ret = 0;
+			break;
+	}
+	return ret;
+}
+//------------------------------
+//endfunc simPadKB
+//---------------------------------------------------------------------------
+// readpad will call readpad_no_KB, and if no new pad buttons are found, it
+// will also attempt reading data from a USB keyboard, and map this as a
+// virtual gamepad. (Very improvised and sloppy, but it should work fine.)
+//---------------------------------------------------------------------------
+int readpad(void)
+{
+	int	ret;
+
+	if((ret=readpad_no_KB()) && new_pad)
+		return ret;
+
+	return simPadKB();
+}
+//------------------------------
+//endfunc readpad
+//---------------------------------------------------------------------------
+// readpad_noRepeat calls readpad_noKBnoRepeat, and if no new pad buttons are
+// found, it also attempts reading data from a USB keyboard, and map this as
+// a virtual gamepad. (Very improvised and sloppy, but it should work fine.)
+//---------------------------------------------------------------------------
+int readpad_noRepeat(void)
+{
+	int	ret;
+
+	if((ret=readpad_noKBnoRepeat()) && new_pad)
+		return ret;
+
+	return simPadKB();
+}
+//------------------------------
+//endfunc readpad_noRepeat
+//---------------------------------------------------------------------------
+// Wait for specific PAD, but also accept disconnected state
+void waitPadReady(int port, int slot)
+{
+	int state, lastState;
+	char stateString[16];
+
+	state = padGetState(port, slot);
+	lastState = -1;
+	while((state != PAD_STATE_DISCONN)
+		&& (state != PAD_STATE_STABLE)
+		&& (state != PAD_STATE_FINDCTP1)){
+		if (state != lastState)
+			padStateInt2String(state, stateString);
+		lastState = state;
+		state=padGetState(port, slot);
+	}
+}
+//---------------------------------------------------------------------------
+// Wait for any PAD, but also accept disconnected states
+void waitAnyPadReady(void)
+{
+	int state_1, state_2;
+
+	state_1 = padGetState(0, 0);
+	state_2 = padGetState(1, 0);
+	while((state_1 != PAD_STATE_DISCONN) && (state_2 != PAD_STATE_DISCONN)
+		&& (state_1 != PAD_STATE_STABLE) && (state_2 != PAD_STATE_STABLE)
+		&& (state_1 != PAD_STATE_FINDCTP1) && (state_2 != PAD_STATE_FINDCTP1)){
+		state_1 = padGetState(0, 0);
+		state_2 = padGetState(1, 0);
+	}
+}
+//---------------------------------------------------------------------------
+// setup PAD
+int setupPad(void)
+{
+	int ret, i, port, state, modes;
+
+	padInit(0);
+
+	for(port=0; port<2; port++){
+		padtype_t[port] = 0;  //Assume that we don't have a proper PS2 controller
+		if((ret = padPortOpen(port, 0, &padBuf_t[port][0])) == 0)
+			return 0;
+		waitPadReady(port, 0);
+		state = padGetState(port, 0);
+		if(state != PAD_STATE_DISCONN){ //if anything connected to this port
+			modes = padInfoMode(port, 0, PAD_MODETABLE, -1);
+			if (modes != 0){ //modes != 0, so it may be a dualshock type
+				for(i=0; i<modes; i++){
+					if (padInfoMode(port, 0, PAD_MODETABLE, i) == PAD_TYPE_DUALSHOCK){
+						padtype_t[port] = 2; //flag normal PS2 controller
+						break;
+					}
+				} //ends for (modes)
+			} else { //modes == 0, so this is a digital controller
+				padtype_t[port] = 1; //flag digital controller
+			}
+			if(padtype_t[port] == 2)                                        //if DualShock
+				padSetMainMode(port, 0, PAD_MMODE_DUALSHOCK, PAD_MMODE_LOCK);   //Set DualShock
+			else                                                            //else
+				padSetMainMode(port, 0, PAD_MMODE_DIGITAL, PAD_MMODE_UNLOCK);   //Set Digital
+			waitPadReady(port, 0);                                          //Await completion
+		} else {                                          //Nothing is connected to this port
+				padSetMainMode(port, 0, PAD_MMODE_DUALSHOCK, PAD_MMODE_LOCK); //Fake DualShock
+				waitPadReady(port, 0);                                        //Await completion
+		}
+	} //ends for (port)
+	return 1;
+}
+//---------------------------------------------------------------------------
+// End of file: pad.c
+//---------------------------------------------------------------------------
Index: ps2launchargs/source/uLaunchELF/ps2host/Makefile
===================================================================
--- ps2launchargs/source/uLaunchELF/ps2host/Makefile	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/ps2host/Makefile	(revision 1101)
@@ -0,0 +1,16 @@
+
+IOP_BIN  = ps2host.irx
+IOP_OBJS = net_fsys.o net_fio.o ps2host.o imports.o
+
+IOP_INCS += -I../include
+IOP_LIBS += 
+IOP_LDFLAGS += 
+IOP_CFLAGS += -Wall
+
+all: $(IOP_BIN)
+
+clean:
+	-rm -f $(IOP_OBJS) $(IOP_BIN)
+
+include $(PS2SDK)/Defs.make
+include Rules.make
Index: ps2launchargs/source/uLaunchELF/ps2host/Rules.make
===================================================================
--- ps2launchargs/source/uLaunchELF/ps2host/Rules.make	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/ps2host/Rules.make	(revision 1101)
@@ -0,0 +1,54 @@
+# _____     ___ ____     ___ ____
+#  ____|   |    ____|   |        | |____|
+# |     ___|   |____ ___|    ____| |    \    PS2DEV Open Source Project.
+#-----------------------------------------------------------------------
+# Copyright 2001-2004.
+# Licenced under Academic Free License version 2.0
+# Review ps2sdk README & LICENSE files for further details.
+
+
+IOP_CC_VERSION := $(shell $(IOP_CC) -v 2>&1 | sed -n 's/^.*version //p')
+
+ASFLAGS_TARGET = -mcpu=r3000
+
+ifeq ($(IOP_CC_VERSION),3.2.2)
+CFLAGS_TARGET  = -miop
+ASFLAGS_TARGET = -march=r3000
+LDFLAGS_TARGET = -miop
+endif
+
+IOP_INCS := $(IOP_INCS) -I$(PS2SDK)/iop/include -I$(PS2SDK)/common/include 
+
+IOP_CFLAGS  := $(CFLAGS_TARGET) -O2 -G0 -c $(IOP_INCS) $(IOP_CFLAGS)
+IOP_ASFLAGS := $(ASFLAGS_TARGET) -EL -G0 $(IOP_ASFLAGS)
+IOP_LDFLAGS := $(LDFLAGS_TARGET) -nostdlib $(IOP_LDFLAGS)
+
+# Externally defined variables: IOP_BIN, IOP_OBJS, IOP_LIB
+
+%.o : %.c
+	$(IOP_CC) $(IOP_CFLAGS) $< -o $@
+
+%.o : %.s
+	$(IOP_AS) $(IOP_ASFLAGS) $< -o $@
+
+# A rule to build imports.lst.
+%.o : %.lst
+	echo "#include \"irx_imports.h\"" > build-imports.c
+	cat $< >> build-imports.c
+	$(IOP_CC) $(IOP_CFLAGS) build-imports.c -o $@
+	-rm -f build-imports.c
+
+# A rule to build exports.tab.
+%.o : %.tab
+	echo "#include \"irx.h\"" > build-exports.c
+	cat $< >> build-exports.c
+	$(IOP_CC) $(IOP_CFLAGS) build-exports.c -o $@
+	-rm -f build-exports.c
+
+
+$(IOP_BIN) : $(IOP_OBJS)
+	$(IOP_CC) $(IOP_LDFLAGS) -o $(IOP_BIN) $(IOP_OBJS) $(IOP_LIBS)
+
+$(IOP_LIB) : $(IOP_OBJS)
+	$(IOP_AR) cru $(IOP_LIB) $(IOP_OBJS)
+
Index: ps2launchargs/source/uLaunchELF/ps2host/hostlink.h
===================================================================
--- ps2launchargs/source/uLaunchELF/ps2host/hostlink.h	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/ps2host/hostlink.h	(revision 1101)
@@ -0,0 +1,272 @@
+/*********************************************************************
+ * Copyright (C) 2003 Tord Lindstrom (pukko@home.se)
+ * This file is subject to the terms and conditions of the PS2Link License.
+ * See the file LICENSE in the main directory of this distribution for more
+ * details.
+ */
+
+#define PKO_PORT        0x4711
+#define PKO_CMD_PORT	0x4712
+#define PKO_PRINTF_PORT	0x4712
+
+#define PKO_OPEN_CMD     0xbabe0111
+#define PKO_OPEN_RLY     0xbabe0112
+#define PKO_CLOSE_CMD    0xbabe0121
+#define PKO_CLOSE_RLY    0xbabe0122
+#define PKO_READ_CMD     0xbabe0131
+#define PKO_READ_RLY     0xbabe0132
+#define PKO_WRITE_CMD    0xbabe0141
+#define PKO_WRITE_RLY    0xbabe0142
+#define PKO_LSEEK_CMD    0xbabe0151
+#define PKO_LSEEK_RLY    0xbabe0152
+#define PKO_OPENDIR_CMD  0xbabe0161
+#define PKO_OPENDIR_RLY  0xbabe0162
+#define PKO_CLOSEDIR_CMD 0xbabe0171
+#define PKO_CLOSEDIR_RLY 0xbabe0172
+#define PKO_READDIR_CMD  0xbabe0181
+#define PKO_READDIR_RLY  0xbabe0182
+
+#define PKO_REMOVE_CMD   0xbabe0191
+#define PKO_REMOVE_RLY   0xbabe0192
+#define PKO_MKDIR_CMD    0xbabe01A1
+#define PKO_MKDIR_RLY    0xbabe01A2
+#define PKO_RMDIR_CMD    0xbabe01B1
+#define PKO_RMDIR_RLY    0xbabe01B2
+
+#define PKO_IOCTL_CMD    0xbabe01C1  //dlanor: Added for Rename capability
+#define PKO_IOCTL_RLY    0xbabe01C2  //dlanor: Added for Rename capability
+
+#define PKO_RESET_CMD    0xbabe0201
+#define PKO_EXECIOP_CMD  0xbabe0202
+#define PKO_EXECEE_CMD   0xbabe0203
+#define PKO_POWEROFF_CMD 0xbabe0204
+#define PKO_SCRDUMP_CMD  0xbabe0205
+#define PKO_NETDUMP_CMD  0xbabe0206
+
+#define PKO_DUMP_MEM     0xbabe0207
+#define PKO_START_VU     0xbabe0208
+#define PKO_STOP_VU      0xbabe0209
+#define PKO_DUMP_REG 		 0xbabe020a
+#define PKO_GSEXEC_CMD   0xbabe020b
+#define PKO_WRITE_MEM    0xbabe020c
+#define PKO_IOPEXCEP_CMD 0xbabe020d
+
+#define PKO_RPC_RESET   1
+#define PKO_RPC_EXECEE  2
+#define PKO_RPC_DUMMY   3
+#define PKO_RPC_SCRDUMP 4
+#define PKO_RPC_NETDUMP 5
+#define PKO_RPC_STARTVU 6
+#define PKO_RPC_STOPVU  7
+#define PKO_RPC_DUMPMEM 8
+#define PKO_RPC_DUMPREG 9
+#define PKO_RPC_GSEXEC  10
+
+#define PKO_MAX_PATH   256
+
+#define REGDMA		0
+#define REGINTC		1
+#define REGTIMER	2
+#define REGGS     3
+#define REGSIF		4
+#define REGFIFO		5
+#define REGGIF		6
+#define REGVIF0		7
+#define REGVIF1		8
+#define REGIPU		9
+#define REGALL		10
+#define REGVU0		11
+#define REGVU1		12
+
+typedef struct
+{
+    unsigned int cmd;
+    unsigned short len;
+} __attribute__((packed)) pko_pkt_hdr;
+
+typedef struct
+{
+    unsigned int cmd;
+    unsigned short len;
+    unsigned int retval;
+} __attribute__((packed)) pko_pkt_file_rly;
+
+typedef struct
+{
+    unsigned int cmd;
+    unsigned short len;
+    int flags;
+    char path[PKO_MAX_PATH];
+} __attribute__((packed)) pko_pkt_open_req;
+
+typedef struct
+{
+    unsigned int cmd;
+    unsigned short len;
+    int fd;
+} __attribute__((packed)) pko_pkt_close_req;
+
+typedef struct
+{
+    unsigned int cmd;
+    unsigned short len;
+    int fd;
+    int nbytes;
+} __attribute__((packed)) pko_pkt_read_req;
+
+typedef struct
+{
+    unsigned int cmd;
+    unsigned short len;
+    int retval;
+    int nbytes;
+} __attribute__((packed)) pko_pkt_read_rly;
+
+typedef struct
+{
+    unsigned int cmd;
+    unsigned short len;
+    int fd;
+    int nbytes;
+} __attribute__((packed)) pko_pkt_write_req;
+
+typedef struct
+{
+    unsigned int cmd;
+    unsigned short len;
+    int fd;
+    int offset;
+    int whence;
+} __attribute__((packed)) pko_pkt_lseek_req;
+
+typedef struct
+{
+    unsigned int cmd;
+    unsigned short len;
+    char name[PKO_MAX_PATH];
+} __attribute__((packed)) pko_pkt_remove_req;
+
+typedef struct
+{
+    unsigned int cmd;
+    unsigned short len;
+    int fd;
+    int request;
+    char data[256];
+} __attribute__((packed)) pko_pkt_ioctl_req;
+
+typedef struct
+{
+    unsigned int cmd;
+    unsigned short len;
+    int mode;
+    char name[PKO_MAX_PATH];
+} __attribute__((packed)) pko_pkt_mkdir_req;
+
+typedef struct
+{
+    unsigned int cmd;
+    unsigned short len;
+    char name[PKO_MAX_PATH];
+} __attribute__((packed)) pko_pkt_rmdir_req;
+
+typedef struct
+{
+    unsigned int cmd;
+    unsigned short len;
+    int fd;
+} __attribute__((packed)) pko_pkt_dread_req;
+
+typedef struct
+{
+    unsigned int cmd;
+    unsigned short len;
+    int retval;
+/* from io_common.h (fio_dirent_t) in ps2lib */
+    unsigned int mode;
+    unsigned int attr;
+    unsigned int size;
+    unsigned char ctime[8];
+    unsigned char atime[8];
+    unsigned char mtime[8];
+    unsigned int hisize;
+    char name[256];
+} __attribute__((packed)) pko_pkt_dread_rly;
+
+////
+
+typedef struct
+{
+    unsigned int cmd;
+    unsigned short len;
+} __attribute__((packed)) pko_pkt_reset_req;
+
+typedef struct
+{
+    unsigned int cmd;
+    unsigned short len;
+    int  argc;
+    char argv[PKO_MAX_PATH];
+} __attribute__((packed)) pko_pkt_execee_req;
+
+typedef struct
+{
+    unsigned int cmd;
+    unsigned short len;
+    int  argc;
+    char argv[PKO_MAX_PATH];
+} __attribute__((packed)) pko_pkt_execiop_req;
+
+typedef struct
+{
+	unsigned int cmd;
+	unsigned short len;
+	unsigned short size;
+	unsigned char file[PKO_MAX_PATH];
+} __attribute__((packed)) pko_pkt_gsexec_req;
+
+typedef struct
+{
+    unsigned int cmd;
+    unsigned short len;
+} __attribute__((packed)) pko_pkt_poweroff_req;
+
+typedef struct
+{
+    unsigned int cmd;
+    unsigned short len;
+    int vpu;
+} __attribute__((packed)) pko_pkt_start_vu;
+
+typedef struct
+{
+    unsigned int cmd;
+    unsigned short len;
+    int vpu;
+} __attribute__((packed)) pko_pkt_stop_vu;
+
+typedef struct
+{
+    unsigned int cmd;
+    unsigned short len;
+    unsigned int offset;
+    unsigned int size;
+    char argv[PKO_MAX_PATH];
+} __attribute__((packed)) pko_pkt_mem_io;
+
+typedef struct {
+    unsigned int cmd;
+    unsigned short len;
+    int regs;
+    char argv[PKO_MAX_PATH];
+} __attribute__((packed)) pko_pkt_dump_regs;
+
+typedef struct {
+	unsigned int cmd;
+	unsigned short len;
+	unsigned int regs[79];
+} __attribute__((packed)) pko_pkt_send_regs;
+
+
+#define PKO_MAX_WRITE_SEGMENT (1460 - sizeof(pko_pkt_write_req))
+#define PKO_MAX_READ_SEGMENT  (1460 - sizeof(pko_pkt_read_rly))
Index: ps2launchargs/source/uLaunchELF/ps2host/imports.lst
===================================================================
--- ps2launchargs/source/uLaunchELF/ps2host/imports.lst	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/ps2host/imports.lst	(revision 1101)
@@ -0,0 +1,56 @@
+
+stdio_IMPORTS_start
+I_printf
+stdio_IMPORTS_end
+
+sysclib_IMPORTS_start
+I_memset
+I_memcpy
+I_strncpy
+sysclib_IMPORTS_end
+
+thsemap_IMPORTS_start
+I_CreateSema
+I_SignalSema
+I_WaitSema
+I_DeleteSema
+thsemap_IMPORTS_end
+
+thbase_IMPORTS_start
+I_CreateThread
+I_StartThread 
+I_ExitDeleteThread
+thbase_IMPORTS_end
+
+ioman_IMPORTS_start
+I_AddDrv
+I_DelDrv
+ioman_IMPORTS_end
+
+ps2ip_IMPORTS_start
+I_lwip_send
+I_lwip_socket
+I_lwip_listen
+I_lwip_recv
+I_lwip_close
+I_lwip_bind
+I_lwip_accept
+ps2ip_IMPORTS_end
+
+sifcmd_IMPORTS_start
+I_sceSifInitRpc
+sifcmd_IMPORTS_end
+
+intrman_IMPORTS_start
+I_CpuEnableIntr
+intrman_IMPORTS_end
+
+loadcore_IMPORTS_start
+I_FlushDcache
+loadcore_IMPORTS_end
+#if 0  /* EEUG: WHY ? */
+cdvdman_IMPORTS_start
+I_sceCdInit
+I_sceCdStop
+cdvdman_IMPORTS_end
+#endif
Index: ps2launchargs/source/uLaunchELF/ps2host/irx_imports.h
===================================================================
--- ps2launchargs/source/uLaunchELF/ps2host/irx_imports.h	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/ps2host/irx_imports.h	(revision 1101)
@@ -0,0 +1,29 @@
+/*
+ * irx_imports.h - Defines all IRX imports.
+ *
+ * Copyright (c) 2003 Marcus R. Brown <mrbrown@0xd6.org>
+ *
+ * See the file LICENSE included with this distribution for licensing terms.
+ */
+
+#ifndef IOP_IRX_IMPORTS_H
+#define IOP_IRX_IMPORTS_H
+
+#include "irx.h"
+
+
+/* Please keep these in alphabetical order!  */
+#if 0  /* EEUG: WHY ? */
+#include "cdvdman.h"
+#endif
+#include "intrman.h"
+#include "ioman.h"
+#include "loadcore.h"
+#include "ps2ip.h"
+#include "sifcmd.h"
+#include "stdio.h"
+#include "sysclib.h"
+#include "thbase.h"
+#include "thsemap.h"
+
+#endif /* IOP_IRX_IMPORTS_H */
Index: ps2launchargs/source/uLaunchELF/ps2host/net_fio.c
===================================================================
--- ps2launchargs/source/uLaunchELF/ps2host/net_fio.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/ps2host/net_fio.c	(revision 1101)
@@ -0,0 +1,774 @@
+/*********************************************************************
+ * Copyright (C) 2003 Tord Lindstrom (pukko@home.se)
+ * Copyright (C) 2004 adresd (adresd_ps2dev@yahoo.com)
+ * This file is subject to the terms and conditions of the PS2Link License.
+ * See the file LICENSE in the main directory of this distribution for more
+ * details.
+ */
+
+// Fu*k knows why net_fio & net_fsys are separated..
+
+#include <types.h>
+#include <ioman.h>
+#include <sysclib.h>
+#include <stdio.h>
+#include <thbase.h>
+
+#include <io_common.h>
+
+#include "ps2ip.h"
+#include "net_fio.h"
+#include "hostlink.h"
+
+#define ntohl(x) htonl(x)
+#define ntohs(x) htons(x)
+
+unsigned int remote_pc_addr = 0xffffffff;
+
+#define PACKET_MAXSIZE 4096
+
+static char send_packet[PACKET_MAXSIZE] __attribute__((aligned(16)));
+static char recv_packet[PACKET_MAXSIZE] __attribute__((aligned(16)));
+
+static int pko_fileio_sock = -1;
+static int pko_fileio_active = 0;
+
+#ifdef DEBUG
+#define dbgprintf(args...) printf(args)
+#else
+#define dbgprintf(args...) do { } while(0)
+#endif
+
+//---------------------------------------------------------------------- 
+//
+void 
+pko_close_socket(void)
+{
+    int ret;
+
+    ret = disconnect(pko_fileio_sock);
+    if (ret < 0) {
+        printf("pko_file: disconnect returned error %d\n", ret);
+    }
+    pko_fileio_sock = -1;
+}
+
+//---------------------------------------------------------------------- 
+//
+void
+pko_close_fsys(void)
+{
+    if (pko_fileio_sock > 0) {
+        disconnect(pko_fileio_sock);
+    }
+    pko_fileio_active = 0;
+    return;
+}
+
+//---------------------------------------------------------------------- 
+// XXX: Hm, this func should behave sorta like pko_recv_bytes imho..
+// i.e. check if it was able to send just a part of the packet etc..
+static inline int 
+pko_lwip_send(int sock, void *buf, int len, int flag)
+{
+    int ret;
+    ret = send(sock, buf, len, flag);
+    if (ret < 0) {
+        dbgprintf("pko_file: lwip_send() error %d\n", ret);
+        pko_close_socket();
+        return -1;
+    }
+    else {
+        return ret;
+    }
+}
+
+
+//---------------------------------------------------------------------- 
+// Do repetetive recv() calles until 'bytes' bytes are received
+// or error returned
+int pko_recv_bytes(int sock, char *buf, int bytes)
+{
+    int left;
+    int len;
+
+    left = bytes;
+
+    while (left > 0) {
+        len = recv(sock, &buf[bytes - left], left, 0);
+        if (len < 0) {
+            dbgprintf("pko_file: pko_recv_bytes error!!\n");
+            return -1;
+        }
+        left -= len;
+    }
+    return bytes;
+}
+
+
+//---------------------------------------------------------------------- 
+// Receive a 'packet' of the expected type 'pkt_type', and lenght 'len'
+int pko_accept_pkt(int sock, char *buf, int len, int pkt_type)
+{
+    int length;
+    pko_pkt_hdr *hdr;
+    unsigned int hcmd;
+    unsigned short hlen;
+
+
+    length = pko_recv_bytes(sock, buf, sizeof(pko_pkt_hdr));
+    if (length < 0) {
+        dbgprintf("pko_file: accept_pkt recv error\n");
+        return -1;
+    }
+
+    if (length < sizeof(pko_pkt_hdr)) {
+        dbgprintf("pko_file: XXX: did not receive a full header!!!! "
+                  "Fix this! (%d)\n", length);
+    }
+    
+    hdr = (pko_pkt_hdr *)buf;
+    hcmd = ntohl(hdr->cmd);
+    hlen = ntohs(hdr->len);
+
+    if (hcmd != pkt_type) {
+        dbgprintf("pko_file: pko_accept_pkt: Expected %x, got %x\n", 
+                  pkt_type, hcmd);
+        return 0;
+    }
+
+    if (hlen > len) {
+        dbgprintf("pko_file: pko_accept_pkt: hdr->len is too large!! "
+               "(%d, can only receive %d)\n", hlen, len);
+        return 0;
+    }
+
+    // get the actual packet data
+    length = pko_recv_bytes(sock, buf + sizeof(pko_pkt_hdr), 
+                            hlen - sizeof(pko_pkt_hdr));
+
+    if (length < 0) {
+        dbgprintf("pko_file: accept recv2 error!!\n");
+        return 0;
+    }
+
+    if (length < (hlen - sizeof(pko_pkt_hdr))) {
+        dbgprintf("pko_accept_pkt: Did not receive full packet!!! "
+                  "Fix this! (%d)\n", length);
+    }
+
+    return 1;
+}
+
+//----------------------------------------------------------------------
+//
+int pko_open_file(char *path, int flags)
+{
+    pko_pkt_open_req *openreq;
+    pko_pkt_file_rly *openrly;
+
+    if (pko_fileio_sock < 0) {
+        return -1;
+    }
+
+    dbgprintf("pko_file: file open req (%s, %x)\n", path, flags);
+
+    openreq = (pko_pkt_open_req *)&send_packet[0];
+
+    // Build packet
+    openreq->cmd = htonl(PKO_OPEN_CMD);
+    openreq->len = htons((unsigned short)sizeof(pko_pkt_open_req));
+    openreq->flags = htonl(flags);
+    strncpy(openreq->path, path, PKO_MAX_PATH);
+    openreq->path[PKO_MAX_PATH - 1] = 0; // Make sure it's null-terminated
+
+    if (pko_lwip_send(pko_fileio_sock, openreq, sizeof(pko_pkt_open_req), 0) < 0) {
+        return -1;
+    }
+
+    if (!pko_accept_pkt(pko_fileio_sock, recv_packet, 
+                        sizeof(pko_pkt_file_rly), PKO_OPEN_RLY)) {
+        dbgprintf("pko_file: pko_open_file: did not receive OPEN_RLY\n");
+        return -1;
+    }
+
+    openrly = (pko_pkt_file_rly *)recv_packet;
+    
+    dbgprintf("pko_file: file open reply received (ret %d)\n", ntohl(openrly->retval));
+
+    return ntohl(openrly->retval);
+}
+
+
+//----------------------------------------------------------------------
+//
+int pko_close_file(int fd)
+{
+    pko_pkt_close_req *closereq;
+    pko_pkt_file_rly *closerly;
+
+
+    if (pko_fileio_sock < 0) {
+        return -1;
+    }
+
+    dbgprintf("pko_file: file close req (fd: %d)\n", fd);
+
+    closereq = (pko_pkt_close_req *)&send_packet[0];
+    closerly = (pko_pkt_file_rly *)&recv_packet[0];
+
+    closereq->cmd = htonl(PKO_CLOSE_CMD);
+    closereq->len = htons((unsigned short)sizeof(pko_pkt_close_req));
+    closereq->fd = htonl(fd);
+
+    if (pko_lwip_send(pko_fileio_sock, closereq, sizeof(pko_pkt_close_req), 0) < 0) {
+        return -1;
+    }
+
+    if(!pko_accept_pkt(pko_fileio_sock, (char *)closerly, 
+                       sizeof(pko_pkt_file_rly), PKO_CLOSE_RLY)) {
+        dbgprintf("pko_file: pko_close_file: did not receive PKO_CLOSE_RLY\n");
+        return -1;
+    }
+
+    dbgprintf("pko_file: pko_close_file: close reply received (ret %d)\n", 
+              ntohl(closerly->retval));
+
+    return ntohl(closerly->retval);
+}
+
+//----------------------------------------------------------------------
+//
+int pko_lseek_file(int fd, unsigned int offset, int whence)
+{
+    pko_pkt_lseek_req *lseekreq;
+    pko_pkt_file_rly *lseekrly;
+
+
+    if (pko_fileio_sock < 0) {
+        return -1;
+    }
+
+    dbgprintf("pko_file: file lseek req (fd: %d)\n", fd);
+
+    lseekreq = (pko_pkt_lseek_req *)&send_packet[0];
+    lseekrly = (pko_pkt_file_rly *)&recv_packet[0];
+
+    lseekreq->cmd = htonl(PKO_LSEEK_CMD);
+    lseekreq->len = htons((unsigned short)sizeof(pko_pkt_lseek_req));
+    lseekreq->fd = htonl(fd);
+    lseekreq->offset = htonl(offset);
+    lseekreq->whence = htonl(whence);
+
+    if(pko_lwip_send(pko_fileio_sock, lseekreq, sizeof(pko_pkt_lseek_req), 0) < 0) {
+        return -1;
+    }
+
+    if(!pko_accept_pkt(pko_fileio_sock, (char *)lseekrly, 
+                       sizeof(pko_pkt_file_rly), PKO_LSEEK_RLY)) {
+        dbgprintf("pko_file: pko_lseek_file: did not receive PKO_LSEEK_RLY\n");
+        return -1;
+    }
+
+    dbgprintf("pko_file: pko_lseek_file: lseek reply received (ret %d)\n", 
+              ntohl(lseekrly->retval));
+
+    return ntohl(lseekrly->retval);
+
+}
+
+
+//----------------------------------------------------------------------
+//
+int pko_write_file(int fd, char *buf, int length)
+{
+    pko_pkt_write_req *writecmd;
+    pko_pkt_file_rly *writerly;
+    int hlen;
+    int writtenbytes;
+    int nbytes;
+    int retval;
+
+    if (pko_fileio_sock < 0) {
+        return -1;
+    }
+
+    dbgprintf("pko_file: file write req (fd: %d)\n", fd);
+
+    writecmd = (pko_pkt_write_req *)&send_packet[0];
+    writerly = (pko_pkt_file_rly *)&recv_packet[0];
+
+    hlen = (unsigned short)sizeof(pko_pkt_write_req);
+    writecmd->cmd = htonl(PKO_WRITE_CMD);
+    writecmd->len = htons(hlen);
+    writecmd->fd = htonl(fd);
+
+    // Divide the write request
+    writtenbytes = 0;
+    while (writtenbytes < length) {
+
+        if ((length - writtenbytes) > PKO_MAX_WRITE_SEGMENT) {
+            // Need to split in several read reqs
+            nbytes = PKO_MAX_READ_SEGMENT;
+        }
+        else {
+            nbytes = length - writtenbytes;
+        }
+
+        writecmd->nbytes = htonl(nbytes);
+#ifdef ZEROCOPY
+        /* Send the packet header.  */
+	if (pko_lwip_send(pko_fileio_sock, writecmd, hlen, 0) < 0)
+		return -1;
+	/* Send the write() data.  */
+        if (pko_lwip_send(pko_fileio_sock, &buf[writtenbytes], nbytes, 0) < 0)
+		return -1;
+#else
+        // Copy data to the acutal packet
+        memcpy(&send_packet[sizeof(pko_pkt_write_req)], &buf[writtenbytes],
+               nbytes);
+
+	if (pko_lwip_send(pko_fileio_sock, writecmd, hlen + nbytes, 0) < 0)
+		return -1;
+#endif
+
+
+        // Get reply
+        if(!pko_accept_pkt(pko_fileio_sock, (char *)writerly, 
+                           sizeof(pko_pkt_file_rly), PKO_WRITE_RLY)) {
+            dbgprintf("pko_file: pko_write_file: "
+                      "did not receive PKO_WRITE_RLY\n");
+            return -1;
+        }
+        retval = ntohl(writerly->retval);
+
+        dbgprintf("pko_file: wrote %d bytes (asked for %d)\n", 
+                  retval, nbytes);
+
+        if (retval < 0) {
+            // Error
+            dbgprintf("pko_file: pko_write_file: received error on write req (%d)\n",
+                      retval);
+            return retval;
+        }
+
+        writtenbytes += retval;
+        if (retval < nbytes) {
+            // EOF?
+            break;
+        }
+    }
+    return writtenbytes;
+}
+
+//----------------------------------------------------------------------
+//
+int pko_read_file(int fd, char *buf, int length)
+{
+    int readbytes;
+    int nbytes;
+    int i;
+    pko_pkt_read_req *readcmd;
+    pko_pkt_read_rly *readrly;
+
+
+    if (pko_fileio_sock < 0) {
+        return -1;
+    }
+
+    readcmd = (pko_pkt_read_req *)&send_packet[0];
+    readrly = (pko_pkt_read_rly *)&recv_packet[0];
+    readbytes = 0;
+
+    readcmd->cmd = htonl(PKO_READ_CMD);
+    readcmd->len = htons((unsigned short)sizeof(pko_pkt_read_req));
+    readcmd->fd = htonl(fd);
+
+    readbytes = 0;
+
+    if (length < 0) {
+        dbgprintf("pko_read_file: illegal req!! (whish to read < 0 bytes!)\n");
+        return -1;
+    }
+
+    readcmd->nbytes = htonl(length);
+
+    i = send(pko_fileio_sock, readcmd, sizeof(pko_pkt_read_req), 0);
+    if (i<0)
+    {
+        dbgprintf("pko_file: pko_read_file: send failed (%d)\n", i);
+        return -1;
+    }
+
+    if(!pko_accept_pkt(pko_fileio_sock, (char *)readrly, 
+                       sizeof(pko_pkt_read_rly), PKO_READ_RLY)) {
+        dbgprintf("pko_file: pko_read_file: "
+                  "did not receive PKO_READ_RLY\n");
+        return -1;
+    }
+
+    nbytes = ntohl(readrly->nbytes);
+    dbgprintf("pko_file: pko_read_file: Reply said there's %d bytes to read "
+              "(wanted %d)\n", nbytes, length);
+
+    // Now read the actual file data
+    i = pko_recv_bytes(pko_fileio_sock, &buf[0], nbytes);
+    if (i < 0) {
+        dbgprintf("pko_file: pko_read_file: data read error\n");
+        return -1;
+    }
+    return nbytes;
+    return readbytes;
+}
+
+//----------------------------------------------------------------------
+//
+int pko_ioctl(int fd,  unsigned long request, void *data)
+{
+    pko_pkt_ioctl_req *ioctlreq;
+    pko_pkt_file_rly *ioctlrly;
+
+    if (pko_fileio_sock < 0) {
+        return -1;
+    }
+
+    dbgprintf("pko_file: ioctl req (%x)\n", request);
+
+    ioctlreq = (pko_pkt_ioctl_req *)&send_packet[0];
+
+    // Build packet
+    ioctlreq->cmd = htonl(PKO_IOCTL_CMD);
+    ioctlreq->len = htons((unsigned short)sizeof(pko_pkt_ioctl_req));
+    ioctlreq->fd = htonl(fd);
+    ioctlreq->request = htonl(request);
+    memcpy(ioctlreq->data, data, 256);
+
+    if (pko_lwip_send(pko_fileio_sock, ioctlreq, sizeof(pko_pkt_ioctl_req), 0) < 0) {
+        return -1;
+    }
+
+    if (!pko_accept_pkt(pko_fileio_sock, recv_packet, 
+                        sizeof(pko_pkt_file_rly), PKO_IOCTL_RLY)) {
+        dbgprintf("pko_file: pko_ioctl: did not receive IOCTL_RLY\n");
+        return -1;
+    }
+
+    ioctlrly = (pko_pkt_file_rly *)recv_packet;
+    dbgprintf("pko_file: ioctl reply received (ret %d)\n", ntohl(ioctlrly->retval));
+    return ntohl(ioctlrly->retval);
+}
+
+//----------------------------------------------------------------------
+//
+int pko_remove(char *name)
+{
+    pko_pkt_remove_req *removereq;
+    pko_pkt_file_rly *removerly;
+
+    if (pko_fileio_sock < 0) {
+        return -1;
+    }
+
+    dbgprintf("pko_file: file remove req (%s)\n", name);
+
+    removereq = (pko_pkt_remove_req *)&send_packet[0];
+
+    // Build packet
+    removereq->cmd = htonl(PKO_REMOVE_CMD);
+    removereq->len = htons((unsigned short)sizeof(pko_pkt_remove_req));
+    strncpy(removereq->name, name, PKO_MAX_PATH);
+    removereq->name[PKO_MAX_PATH - 1] = 0; // Make sure it's null-terminated
+
+    if (pko_lwip_send(pko_fileio_sock, removereq, sizeof(pko_pkt_remove_req), 0) < 0) {
+        return -1;
+    }
+
+    if (!pko_accept_pkt(pko_fileio_sock, recv_packet, 
+                        sizeof(pko_pkt_file_rly), PKO_REMOVE_RLY)) {
+        dbgprintf("pko_file: pko_remove: did not receive REMOVE_RLY\n");
+        return -1;
+    }
+
+    removerly = (pko_pkt_file_rly *)recv_packet;
+    dbgprintf("pko_file: file remove reply received (ret %d)\n", ntohl(removerly->retval));
+    return ntohl(removerly->retval);
+}
+
+//----------------------------------------------------------------------
+//
+int pko_mkdir(char *name, int mode)
+{
+    pko_pkt_mkdir_req *mkdirreq;
+    pko_pkt_file_rly *mkdirrly;
+
+    if (pko_fileio_sock < 0) {
+        return -1;
+    }
+
+    dbgprintf("pko_file: make dir req (%s)\n", name);
+
+    mkdirreq = (pko_pkt_mkdir_req *)&send_packet[0];
+
+    // Build packet
+    mkdirreq->cmd = htonl(PKO_MKDIR_CMD);
+    mkdirreq->len = htons((unsigned short)sizeof(pko_pkt_mkdir_req));
+    mkdirreq->mode = mode;
+    strncpy(mkdirreq->name, name, PKO_MAX_PATH);
+    mkdirreq->name[PKO_MAX_PATH - 1] = 0; // Make sure it's null-terminated
+
+    if (pko_lwip_send(pko_fileio_sock, mkdirreq, sizeof(pko_pkt_mkdir_req), 0) < 0) {
+        return -1;
+    }
+
+    if (!pko_accept_pkt(pko_fileio_sock, recv_packet, 
+                        sizeof(pko_pkt_file_rly), PKO_MKDIR_RLY)) {
+        dbgprintf("pko_file: pko_mkdir: did not receive MKDIR_RLY\n");
+        return -1;
+    }
+
+    mkdirrly = (pko_pkt_file_rly *)recv_packet;
+    dbgprintf("pko_file: make dir reply received (ret %d)\n", ntohl(mkdirrly->retval));
+    return ntohl(mkdirrly->retval);
+}
+
+//----------------------------------------------------------------------
+//
+int pko_rmdir(char *name)
+{
+    pko_pkt_rmdir_req *rmdirreq;
+    pko_pkt_file_rly *rmdirrly;
+
+    if (pko_fileio_sock < 0) {
+        return -1;
+    }
+
+    dbgprintf("pko_file: remove dir req (%s)\n", name);
+
+    rmdirreq = (pko_pkt_rmdir_req *)&send_packet[0];
+
+    // Build packet
+    rmdirreq->cmd = htonl(PKO_RMDIR_CMD);
+    rmdirreq->len = htons((unsigned short)sizeof(pko_pkt_rmdir_req));
+    strncpy(rmdirreq->name, name, PKO_MAX_PATH);
+    rmdirreq->name[PKO_MAX_PATH - 1] = 0; // Make sure it's null-terminated
+
+    if (pko_lwip_send(pko_fileio_sock, rmdirreq, sizeof(pko_pkt_rmdir_req), 0) < 0) {
+        return -1;
+    }
+
+    if (!pko_accept_pkt(pko_fileio_sock, recv_packet, 
+                        sizeof(pko_pkt_file_rly), PKO_RMDIR_RLY)) {
+        dbgprintf("pko_file: pko_rmdir: did not receive RMDIR_RLY\n");
+        return -1;
+    }
+
+    rmdirrly = (pko_pkt_file_rly *)recv_packet;
+    dbgprintf("pko_file: remove dir reply received (ret %d)\n", ntohl(rmdirrly->retval));
+    return ntohl(rmdirrly->retval);
+}
+
+//----------------------------------------------------------------------
+//
+int pko_open_dir(char *path)
+{
+    pko_pkt_open_req *openreq;
+    pko_pkt_file_rly *openrly;
+
+    if (pko_fileio_sock < 0) {
+        return -1;
+    }
+
+    dbgprintf("pko_file: dir open req (%s)\n", path);
+
+    openreq = (pko_pkt_open_req *)&send_packet[0];
+
+    // Build packet
+    openreq->cmd = htonl(PKO_OPENDIR_CMD);
+    openreq->len = htons((unsigned short)sizeof(pko_pkt_open_req));
+    openreq->flags = htonl(0);
+    strncpy(openreq->path, path, PKO_MAX_PATH);
+    openreq->path[PKO_MAX_PATH - 1] = 0; // Make sure it's null-terminated
+
+    if (pko_lwip_send(pko_fileio_sock, openreq, sizeof(pko_pkt_open_req), 0) < 0) {
+        return -1;
+    }
+
+    if (!pko_accept_pkt(pko_fileio_sock, recv_packet, 
+                        sizeof(pko_pkt_file_rly), PKO_OPENDIR_RLY)) {
+        dbgprintf("pko_file: pko_open_dir: did not receive OPENDIR_RLY\n");
+        return -1;
+    }
+
+    openrly = (pko_pkt_file_rly *)recv_packet;
+    
+    dbgprintf("pko_file: dir open reply received (ret %d)\n", ntohl(openrly->retval));
+
+    return ntohl(openrly->retval);
+}
+
+//----------------------------------------------------------------------
+//
+int pko_read_dir(int fd, void *buf)
+{
+    pko_pkt_dread_req *dirreq;
+    pko_pkt_dread_rly *dirrly;
+    fio_dirent_t *dirent;
+
+    if (pko_fileio_sock < 0) {
+        return -1;
+    }
+
+    dbgprintf("pko_file: dir read req (%x)\n", fd);
+
+    dirreq = (pko_pkt_dread_req *)&send_packet[0];
+
+    // Build packet
+    dirreq->cmd = htonl(PKO_READDIR_CMD);
+    dirreq->len = htons((unsigned short)sizeof(pko_pkt_dread_req));
+    dirreq->fd = htonl(fd);
+
+    if (pko_lwip_send(pko_fileio_sock, dirreq, sizeof(pko_pkt_dread_req), 0) < 0) {
+        return -1;
+    }
+
+    if (!pko_accept_pkt(pko_fileio_sock, recv_packet, 
+                        sizeof(pko_pkt_dread_rly), PKO_READDIR_RLY)) {
+        dbgprintf("pko_file: pko_open_file: did not receive OPENDIR_RLY\n");
+        return -1;
+    }
+
+    dirrly = (pko_pkt_dread_rly *)recv_packet;
+    
+    dbgprintf("pko_file: dir read reply received (ret %d)\n", ntohl(dirrly->retval));
+
+    dirent = (fio_dirent_t *) buf;
+    // now handle the return buffer translation, to build reply bit
+    dirent->stat.mode    = ntohl(dirrly->mode);
+    dirent->stat.attr    = ntohl(dirrly->attr);
+    dirent->stat.size    = ntohl(dirrly->size);
+    dirent->stat.hisize  = ntohl(dirrly->hisize);
+    memcpy(dirent->stat.ctime,dirrly->ctime,8*3);
+    strncpy(dirent->name,dirrly->name,256);
+    dirent->unknown = 0;
+
+    return ntohl(dirrly->retval);
+}
+
+
+//----------------------------------------------------------------------
+//
+int pko_close_dir(int fd)
+{
+    pko_pkt_close_req *closereq;
+    pko_pkt_file_rly *closerly;
+
+
+    if (pko_fileio_sock < 0) {
+        return -1;
+    }
+
+    dbgprintf("pko_file: dir close req (fd: %d)\n", fd);
+
+    closereq = (pko_pkt_close_req *)&send_packet[0];
+    closerly = (pko_pkt_file_rly *)&recv_packet[0];
+
+    closereq->cmd = htonl(PKO_CLOSEDIR_CMD);
+    closereq->len = htons((unsigned short)sizeof(pko_pkt_close_req));
+    closereq->fd = htonl(fd);
+
+    if (pko_lwip_send(pko_fileio_sock, closereq, sizeof(pko_pkt_close_req), 0) < 0) {
+        return -1;
+    }
+
+    if(!pko_accept_pkt(pko_fileio_sock, (char *)closerly, 
+                       sizeof(pko_pkt_file_rly), PKO_CLOSEDIR_RLY)) {
+        dbgprintf("pko_file: pko_close_dir: did not receive PKO_CLOSEDIR_RLY\n");
+        return -1;
+    }
+
+    dbgprintf("pko_file: dir close reply received (ret %d)\n", 
+              ntohl(closerly->retval));
+
+    return ntohl(closerly->retval);
+}
+
+//----------------------------------------------------------------------
+// Thread that waits for a PC to connect/disconnect/reconnect blah..
+int
+pko_file_serv(void *argv)
+{
+    struct sockaddr_in server_addr;
+    struct sockaddr_in client_addr;
+    int sock;
+    int client_sock;
+    int client_len;
+    int ret;
+
+    dbgprintf(" - PS2 Side application -\n");
+
+    memset((void *)&server_addr, 0, sizeof(server_addr));
+    // Should perhaps specify PC side ip..
+    server_addr.sin_family = AF_INET;
+    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+    server_addr.sin_port = htons(PKO_PORT);
+
+    while ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+        dbgprintf("pko_file: socket creation error (%d)\n", sock);
+        return -1;
+    }
+
+    ret = bind(sock, (struct sockaddr *)&server_addr, 
+                    sizeof(server_addr));
+    if (ret < 0) {
+        dbgprintf("pko_file: bind error (%d)\n", ret);
+        disconnect(sock);
+        return -1;
+    }
+
+    ret = listen(sock, 5);
+
+    if (ret < 0) {
+        dbgprintf("pko_file: listen error (%d)\n", ret);
+        disconnect(sock);
+        return -1;
+    }
+
+    // Active flag kinda sux, cause it wont be checked until a new client has
+    // connected.. But it's better than nothing and good for now at least
+    pko_fileio_active = 1;
+
+    // Connection loop
+    while(pko_fileio_active)
+    {
+        dbgprintf("Waiting for connection\n");
+
+        client_len = sizeof(client_addr);
+        client_sock = accept(sock, (struct sockaddr *)&client_addr, 
+                             &client_len);
+        if (client_sock < 0) {
+            dbgprintf("pko_file: accept error (%d)", client_sock);
+            continue;
+        }
+
+        dbgprintf("Client connected from %x\n", 
+               client_addr.sin_addr.s_addr);
+
+		remote_pc_addr = client_addr.sin_addr.s_addr;
+
+        if (pko_fileio_sock > 0) {
+            dbgprintf("Client reconnected\n");
+            ret = disconnect(pko_fileio_sock);
+            dbgprintf("close ret %d\n", ret);
+        }
+        pko_fileio_sock = client_sock;
+    }
+
+    if (pko_fileio_sock > 0) {
+        disconnect(pko_fileio_sock);
+    }
+
+    disconnect(sock);
+
+    ExitDeleteThread();
+    return 0;
+}
Index: ps2launchargs/source/uLaunchELF/ps2host/net_fio.h
===================================================================
--- ps2launchargs/source/uLaunchELF/ps2host/net_fio.h	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/ps2host/net_fio.h	(revision 1101)
@@ -0,0 +1,36 @@
+/*********************************************************************
+ * Copyright (C) 2003 Tord Lindstrom (pukko@home.se)
+ * Copyright (C) 2004 adresd (adresd_ps2dev@yahoo.com)
+ * This file is subject to the terms and conditions of the PS2Link License.
+ * See the file LICENSE in the main directory of this distribution for more
+ * details.
+ */
+
+#ifndef _NETFIO_H_
+#define _NETFIO_H_
+
+int pko_file_serv(void *arg);
+int pko_recv_bytes(int fd, char *buf, int bytes);
+int pko_accept_pkt(int fd, char *buf, int len, int pkt_type);
+int pko_open_file(char *path, int flags);
+int pko_close_file(int fd);
+int pko_read_file(int fd, char *buf, int length);
+int pko_write_file(int fd, char *buf, int length);
+int pko_lseek_file(int fd, unsigned int offset, int whence);
+void pko_close_socket(void);
+void pko_close_fsys(void);
+int pko_open_dir(char *path);
+int pko_read_dir(int fd, void *buf);
+int pko_close_dir(int fd);
+int pko_make_dir(char *path);
+int pko_ioctl(int fd,  unsigned long request, void *data);
+int pko_remove(char *name);
+int pko_mkdir(char *name, int mode);
+int pko_rmdir(char *name);
+/*
+ * Don't want printfs to broadcast in case more than 1 ps2 on the same network, so at
+ * connect time, the remote PC's IP is stored here and used as destination for printfs.
+ */
+extern unsigned int remote_pc_addr;
+
+#endif
Index: ps2launchargs/source/uLaunchELF/ps2host/net_fsys.c
===================================================================
--- ps2launchargs/source/uLaunchELF/ps2host/net_fsys.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/ps2host/net_fsys.c	(revision 1101)
@@ -0,0 +1,432 @@
+/*********************************************************************
+ * Copyright (C) 2003 Tord Lindstrom (pukko@home.se)
+ * Copyright (C) 2004 adresd (adresd_ps2dev@yahoo.com)
+ * This file is subject to the terms and conditions of the PS2Link License.
+ * See the file LICENSE in the main directory of this distribution for more
+ * details.
+ */
+
+#include <types.h>
+#include <thbase.h>
+#include <ioman.h>
+#include <sysclib.h>
+#include <stdio.h>
+#include <intrman.h>
+#include <loadcore.h>
+#include <thsemap.h>
+
+#include "net_fio.h"
+
+#define IOCTL_RENAME     0xFEEDC0DE  //dlanor: Used for the Ioctl request code => Rename
+
+#ifdef DEBUG
+#define dbgprintf(args...) printf(args)
+#else
+#define dbgprintf(args...) do { } while(0)
+#endif
+
+static char fsname[] = "host";
+
+//----------------------------------------------------------------------------
+
+/* File desc struct is probably larger than this, but we only
+ * need to access the word @ offset 0x0C (in which we put our identifier)
+ */
+struct filedesc_info
+{
+    int unkn0;
+    int unkn4;
+    int device_id;   // the X in hostX
+    int own_fd;
+};
+//dlanor: In fact this struct is declared elsewhere as iop_file_t, with
+//dlanor: well known fields. The one declared as "int own_fd;" above is
+//dlanor: there declared as "void	*privdata;" but it doesn't matter, as
+//dlanor: it is up to each driver how to use that field. So using it as
+//dlanor: a simple "int" instead of a pointer will work fine.
+
+
+//----------------------------------------------------------------------------
+/* We need(?) to protect the net access, so the server doesn't get
+ * confused if two processes calls a fsys func at the same time
+ */
+static int fsys_sema;
+static int fsys_pid = 0;
+
+//----------------------------------------------------------------------------
+//dlanor: We need variables to remember a file/folder descriptor used
+//dlanor: with the Ioctl Rename function, so that we can avoid passing
+//dlanor: the following fioClose call to PC, where it's already closed.
+//dlanor: We also need a flag to note when we must ignore an Mkdir call
+//dlanor: because it is caused by the bug IOMAN.IRX has for fioRemove.
+//
+int lastopen_fd;   //descriptor of the most recently opened file/folder
+int	renamed_fd;    //descriptor of renamed file/folder awaiting closure
+int remove_flag=0; //Set in fsysRemove, cleared by all other fsysXXXXX
+int remove_result; //Set in fsysRemove, so fsysMkdir can use it for bug
+
+typedef void (*th_func_p)(void *); //dlanor: added to suppress warnings
+
+//----------------------------------------------------------------------------
+static void fsysInit(iop_device_t *driver)
+{
+    struct _iop_thread mythread;
+    int pid;
+    int i;
+
+    dbgprintf("initializing %s\n", driver->name);
+
+		remove_flag = 0;
+
+    // Start socket server thread
+
+    mythread.attr = 0x02000000; // attr
+    mythread.option = 0; // option
+    mythread.thread = (th_func_p) pko_file_serv; // entry
+    mythread.stacksize = 0x800;
+    mythread.priority = 0x45; // We really should choose prio w more effort
+
+    pid = CreateThread(&mythread);
+
+    if (pid > 0) {
+        if ((i=StartThread(pid, NULL)) < 0) {
+            printf("StartThread failed (%d)\n", i);
+        }
+    } 
+    else {
+        printf("CreateThread failed (%d)\n", pid);
+    }
+    
+    fsys_pid = pid;
+    dbgprintf("Thread id: %x\n", pid);
+}
+//----------------------------------------------------------------------------
+static int fsysDestroy(void)
+{
+		remove_flag = 0;
+
+    WaitSema(fsys_sema);
+    pko_close_fsys();
+    //    ExitDeleteThread(fsys_pid);
+    SignalSema(fsys_sema);
+    DeleteSema(fsys_sema);
+    return 0;
+}
+
+
+//----------------------------------------------------------------------------
+static int dummyFormat()
+{
+		remove_flag = 0;
+
+    printf("dummy Format function called\n");
+    return -5;
+}
+//----------------------------------------------------------------------------
+static int fsysOpen( int fd, char *name, int mode)
+{
+    struct filedesc_info *fd_info;
+    int fsys_fd;
+    
+    dbgprintf("fsysOpen..\n");
+    dbgprintf("  fd: %x, name: %s, mode: %d\n\n", fd, name, mode);
+
+		remove_flag = 0;
+
+    fd_info = (struct filedesc_info *)fd;
+
+    WaitSema(fsys_sema);
+    fsys_fd = pko_open_file(name, mode);
+    SignalSema(fsys_sema);
+    fd_info->own_fd = fsys_fd;
+    renamed_fd = -1;
+    lastopen_fd = fsys_fd;
+
+    return fsys_fd;
+}
+//----------------------------------------------------------------------------
+static int fsysClose( int fd)
+{
+    int remote_fd = ((struct filedesc_info *)fd)->own_fd;
+    int ret;
+    
+    dbgprintf("fsys_close..\n"
+           "  fd: %x\n\n", fd);
+
+		remove_flag = 0;
+
+    if (remote_fd != renamed_fd){
+      WaitSema(fsys_sema);
+      ret = pko_close_file(remote_fd);    
+      SignalSema(fsys_sema);
+    } else  ret = 0;
+    renamed_fd = -1;
+
+    return ret;
+}
+//----------------------------------------------------------------------------
+static int fsysRead( int fd, char *buf, int size)
+{
+    struct filedesc_info *fd_info;
+    int ret;
+
+    fd_info = (struct filedesc_info *)fd;
+
+    dbgprintf("fsysRead..."
+           "  fd: %x\n"
+           "  bf: %x\n"
+           "  sz: %d\n"
+           "  ow: %d\n\n", fd, (int)buf, size, fd_info->own_fd);
+
+		remove_flag = 0;
+
+    WaitSema(fsys_sema);
+    ret = pko_read_file(fd_info->own_fd, buf, size);
+    SignalSema(fsys_sema);
+
+    return ret;
+}
+//----------------------------------------------------------------------------
+static int fsysWrite( int fd, char *buf, int size)
+{
+    struct filedesc_info *fd_info;
+    int ret;
+    
+    dbgprintf("fsysWrite..."
+           "  fd: %x\n", fd);
+
+		remove_flag = 0;
+
+    fd_info = (struct filedesc_info *)fd;
+    WaitSema(fsys_sema);
+    ret = pko_write_file(fd_info->own_fd, buf, size);
+    SignalSema(fsys_sema);
+    return ret;
+}
+//----------------------------------------------------------------------------
+static int fsysLseek( int fd, unsigned int offset, int whence)
+{
+    struct filedesc_info *fd_info;
+    int ret;
+
+    dbgprintf("fsysLseek..\n"
+           "  fd: %x\n"
+           "  of: %x\n"
+           "  wh: %x\n\n", fd, offset, whence);
+
+		remove_flag = 0;
+
+    fd_info = (struct filedesc_info *)fd;
+    WaitSema(fsys_sema);
+    ret = pko_lseek_file(fd_info->own_fd, offset, whence);
+    SignalSema(fsys_sema);
+    return ret;
+}
+//----------------------------------------------------------------------------
+static int fsysIoctl(iop_file_t* file, unsigned long request, void *data)
+{
+    int remote_fd = ((struct filedesc_info *) file)->own_fd;
+    int ret;
+    dbgprintf("fsysioctl..\n");
+    dbgprintf("  fd: %x\n"
+              "  rq: %x\n"
+              "  dp: %x\n\n", );
+
+		remove_flag = 0;
+
+		if (request == IOCTL_RENAME){
+		  if (lastopen_fd == remote_fd){
+        WaitSema(fsys_sema);
+        ret = pko_ioctl(remote_fd, request, data);
+        SignalSema(fsys_sema);
+        if ((ret == 0) || (ret == -6))
+        	renamed_fd = remote_fd;
+      } else {
+        printf("Ioctl Rename function used incorrectly.\n");
+        ret = -5;
+
+    	}
+    } else {
+      printf("Ioctl function called with invalid request code\n");
+      ret = -5;
+    }
+    return ret;
+}
+//----------------------------------------------------------------------------
+static int fsysRemove(iop_file_t* file, char *name)
+{
+    int ret;
+    dbgprintf("fsysRemove..\n");
+    dbgprintf("  name: %s\n\n", name);
+
+		remove_flag = 1;
+
+    WaitSema(fsys_sema);
+    ret = pko_remove(name);
+    SignalSema(fsys_sema);
+
+		remove_result = ret;
+    return ret;
+}
+//----------------------------------------------------------------------------
+static int fsysMkdir(iop_file_t* file, char *name, int mode)
+{
+    int ret;
+    dbgprintf("fsysMkdir..\n");
+    dbgprintf("  name: '%s'\n\n", name);
+
+		if (remove_flag == 0){
+    	WaitSema(fsys_sema);
+    	ret = pko_mkdir(name, mode);
+    	SignalSema(fsys_sema);
+    } else {
+    	remove_flag = 0;
+    	ret = remove_result;
+    }
+
+    return ret;
+}
+//----------------------------------------------------------------------------
+static int fsysRmdir(iop_file_t* file, char *name)
+{
+    int ret;
+    dbgprintf("fsysRmdir..\n");
+    dbgprintf("  name: %s\n\n", name);
+
+		remove_flag = 0;
+
+    WaitSema(fsys_sema);
+    ret = pko_rmdir(name);
+    SignalSema(fsys_sema);
+
+    return ret;
+}
+//----------------------------------------------------------------------------
+static int fsysDopen(int fd, char *name)
+{
+    struct filedesc_info *fd_info;
+    int fsys_fd;
+    
+    dbgprintf("fsysDopen..\n");
+    dbgprintf("  fd: %x, name: %s\n\n", fd, name);
+
+    fd_info = (struct filedesc_info *)fd;
+
+		remove_flag = 0;
+
+    WaitSema(fsys_sema);
+    fsys_fd = pko_open_dir(name);
+    SignalSema(fsys_sema);
+    fd_info->own_fd = fsys_fd;
+    renamed_fd = -1;
+    lastopen_fd = fsys_fd;
+
+    return fsys_fd;
+}
+//----------------------------------------------------------------------------
+static int fsysDclose(int fd)
+{
+    int remote_fd = ((struct filedesc_info *)fd)->own_fd;
+    int ret;
+    
+    dbgprintf("fsys_dclose..\n"
+           "  fd: %x\n\n", fd);
+    
+		remove_flag = 0;
+
+    if (remote_fd != renamed_fd){
+      WaitSema(fsys_sema);
+      ret = pko_close_dir(remote_fd);    
+      SignalSema(fsys_sema);
+    } else  ret = 0;
+    renamed_fd = -1;
+
+    return ret;
+}
+//----------------------------------------------------------------------------
+static int fsysDread(int fd, void *buf)
+{
+    struct filedesc_info *fd_info;
+    int ret;
+
+    fd_info = (struct filedesc_info *)fd;
+
+    dbgprintf("fsysDread..."
+           "  fd: %x\n"
+           "  bf: %x\n"
+           "  ow: %d\n\n", fd, (int)buf, fd_info->own_fd);
+
+		remove_flag = 0;
+
+    WaitSema(fsys_sema);
+    ret = pko_read_dir(fd_info->own_fd, buf);
+    SignalSema(fsys_sema);
+
+    return ret;
+
+}
+//----------------------------------------------------------------------------
+static int dummyGetstat()
+{
+		remove_flag = 0;
+
+    printf("dummy Getstat function called\n");
+    return -5;
+}
+//----------------------------------------------------------------------------
+static int dummyChstat()
+{
+		remove_flag = 0;
+
+    printf("dummy Chstat function called\n");
+    return -5;
+}
+//----------------------------------------------------------------------------
+iop_device_ops_t fsys_functarray =
+{	(void *)fsysInit,
+	(void *)fsysDestroy,
+	(void *)dummyFormat,   //init, deinit, format
+	(void *)fsysOpen,
+	(void *)fsysClose,
+	(void *)fsysRead,      //open, close, read,
+	(void *)fsysWrite,
+	(void *)fsysLseek,
+	(void *)fsysIoctl,     //write, lseek, ioctl
+	(void *)fsysRemove,
+	(void *)fsysMkdir,
+	(void *)fsysRmdir,     //remove, mkdir, rmdir
+	(void *)fsysDopen,
+	(void *)fsysDclose,
+	(void *)fsysDread,     //dopen, dclose, dread
+	(void *)dummyGetstat,
+	(void *)dummyChstat }; //getstat, chstat
+
+iop_device_t fsys_driver = { fsname, 16, 1, "fsys driver", 
+							&fsys_functarray };
+//----------------------------------------------------------------------------
+// Entry point for mounting the file system
+int fsysMount(void)
+{
+    iop_sema_t sema_info;
+
+    sema_info.attr = 1;
+    sema_info.option = 0;
+    sema_info.initial = 1;
+    sema_info.max = 1;
+    fsys_sema = CreateSema(&sema_info);
+
+    DelDrv(fsname);
+    AddDrv(&fsys_driver);
+
+    return 0;
+}
+
+//----------------------------------------------------------------------------
+int fsysUnmount(void)
+{
+    DelDrv(fsname);
+    return 0;
+}
+//----------------------------------------------------------------------------
+//End of file:  net_fsys.c
+//----------------------------------------------------------------------------
Index: ps2launchargs/source/uLaunchELF/ps2host/ps2host.c
===================================================================
--- ps2launchargs/source/uLaunchELF/ps2host/ps2host.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/ps2host/ps2host.c	(revision 1101)
@@ -0,0 +1,37 @@
+/*********************************************************************
+ * Copyright (C) 2003 Tord Lindstrom (pukko@home.se)
+ * This file is subject to the terms and conditions of the PS2Link License.
+ * See the file LICENSE in the main directory of this distribution for more
+ * details.
+ */
+
+#include <stdio.h>
+#include <sysclib.h>
+#include <loadcore.h>
+#include <intrman.h>
+#include <types.h>
+#include <sifrpc.h>
+#if 0 /* EEUG: WHY ? */
+#include <cdvdman.h>
+#endif
+
+// Entry points
+extern int fsysMount(void);
+////////////////////////////////////////////////////////////////////////
+// main
+//   start threads & init rpc & filesys
+int
+_start( int argc, char **argv)
+{
+    FlushDcache();
+    CpuEnableIntr(0);
+#if 0  /* EEUG: what the hell these two are doing here ? */
+    sceCdInit(1);
+    sceCdStop();
+#endif
+    SifInitRpc(0);
+
+    fsysMount();
+    return 0;
+}
+
Index: ps2launchargs/source/uLaunchELF/timer.c
===================================================================
--- ps2launchargs/source/uLaunchELF/timer.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/timer.c	(revision 1101)
@@ -0,0 +1,43 @@
+#include "launchelf.h"
+
+// Timer Define
+#define T0_COUNT ((volatile unsigned long*)0x10000000) 
+#define T0_MODE  ((volatile unsigned long*)0x10000010) 
+
+static int TimerInterruptID = -1;
+static u64 TimerInterruptCount = 0;
+
+// Timer Interrupt
+int TimerInterrupt(int a)
+{
+	TimerInterruptCount++;
+	*T0_MODE |= (1 << 11);
+	return -1;
+}
+// Timer Init
+void TimerInit(void)
+{
+	*T0_MODE = 0x0000;
+	TimerInterruptID = AddIntcHandler(9, TimerInterrupt, 0);
+	EnableIntc(9);
+	*T0_COUNT = 0;
+	*T0_MODE = ( 2 << 0 )+( 1 << 7 )+( 1 << 9 );
+	TimerInterruptCount = 0;
+}
+// Timer Count
+u64 Timer(void)
+{
+	u64 ticks = (*T0_COUNT + (TimerInterruptCount << 16)) * (1000.0F / ( 147456000.0F / 256.0F ));
+	return ticks;
+}
+// Timer End
+void TimerEnd(void)
+{
+	*T0_MODE = 0x0000;
+	if (TimerInterruptID >= 0){
+		DisableIntc(9);
+		RemoveIntcHandler(9, TimerInterruptID);
+		TimerInterruptID = -1;
+	}
+	TimerInterruptCount = 0;
+}
Index: ps2launchargs/source/uLaunchELF/vmcfs/Makefile
===================================================================
--- ps2launchargs/source/uLaunchELF/vmcfs/Makefile	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/vmcfs/Makefile	(revision 1101)
@@ -0,0 +1,18 @@
+IOP_OBJS_DIR = obj/
+IOP_BIN_DIR = bin/
+IOP_SRC_DIR = src/
+
+IOP_BIN  = bin/vmcfs.irx
+IOP_OBJS = obj/vmc_fs.o obj/vmc_io.o obj/vmc_misc.o obj/vmc_fat.o obj/vmc_ps2.o obj/imports.o
+
+IOP_CFLAGS  += -Wall -fno-builtin
+IOP_LDFLAGS += -s
+
+all: $(IOP_OBJS_DIR) $(IOP_BIN_DIR) $(IOP_BIN)
+
+clean:
+	rm -f -r $(IOP_OBJS_DIR) $(IOP_BIN_DIR)
+
+include $(PS2SDKSRC)/Defs.make
+include $(PS2SDKSRC)/iop/Rules.make
+include $(PS2SDKSRC)/iop/Rules.release
Index: ps2launchargs/source/uLaunchELF/vmcfs/src/imports.lst
===================================================================
--- ps2launchargs/source/uLaunchELF/vmcfs/src/imports.lst	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/vmcfs/src/imports.lst	(revision 1101)
@@ -0,0 +1,32 @@
+cdvdman_IMPORTS_start
+I_sceCdReadClock
+cdvdman_IMPORTS_end
+
+sysclib_IMPORTS_start
+I_strlen
+I_strcpy
+I_memset
+I_strrchr
+I_sprintf
+I_memcpy
+I_memcmp
+sysclib_IMPORTS_end
+
+stdio_IMPORTS_start
+I_printf
+stdio_IMPORTS_end
+
+iomanX_IMPORTS_start
+I_open
+I_close
+I_read
+I_write
+I_lseek
+I_AddDrv
+I_DelDrv
+iomanX_IMPORTS_end
+
+sysmem_IMPORTS_start
+I_AllocSysMemory
+I_FreeSysMemory
+sysmem_IMPORTS_end
Index: ps2launchargs/source/uLaunchELF/vmcfs/src/irx_imports.h
===================================================================
--- ps2launchargs/source/uLaunchELF/vmcfs/src/irx_imports.h	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/vmcfs/src/irx_imports.h	(revision 1101)
@@ -0,0 +1,26 @@
+/*
+# _____     ___ ____     ___ ____
+#  ____|   |    ____|   |        | |____|
+# |     ___|   |____ ___|    ____| |    \    PS2DEV Open Source Project.
+#-----------------------------------------------------------------------
+# Copyright (c) 2003 Marcus R. Brown <mrbrown@0xd6.org>
+# Licenced under Academic Free License version 2.0
+# Review ps2sdk README & LICENSE files for further details.
+#
+# $Id: irx_imports.h 377 2004-10-25 15:59:28Z tentacle $
+# Defines all IRX imports.
+*/
+
+#ifndef IOP_IRX_IMPORTS_H
+#define IOP_IRX_IMPORTS_H
+
+#include "irx.h"
+
+/* Please keep these in alphabetical order!  */
+#include "cdvdman.h"
+#include "iomanX.h"
+#include "stdio.h"
+#include "sysclib.h"
+#include "sysmem.h"
+
+#endif /* IOP_IRX_IMPORTS_H */
Index: ps2launchargs/source/uLaunchELF/vmcfs/src/vmc.h
===================================================================
--- ps2launchargs/source/uLaunchELF/vmcfs/src/vmc.h	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/vmcfs/src/vmc.h	(revision 1101)
@@ -0,0 +1,301 @@
+#include <types.h> 
+#include <irx.h> 
+#include <stdio.h> 
+#include <sysclib.h> 
+#include <sysmem.h> 
+#include <iomanX.h>
+#include <sys/fcntl.h>
+#include <cdvdman.h>
+
+
+//  Define this to enable debugging, will later support debugging levels, so only messages greater then a certain level will be displayed
+//#define DEBUG 8
+//For release versions of uLE, DEBUG should not be defined
+//To avoid slowdown and size bloat
+
+//  Define this to enable some basic profiling support, each function will display the time it took to run.
+//  #define PROFILING
+
+
+//  Misc defintions
+#define malloc( a ) AllocSysMemory( 0, ( a ), NULL ) 
+#define free( a )   FreeSysMemory(  ( a )  ) 
+
+#define TRUE	1
+#define FALSE	0
+
+#define MAX_NAME   32
+#define MAX_PATH 1024
+
+
+//  Vmcfs error definitions
+#define VMCFS_ERR_NO            0
+#define VMCFS_ERR_INITIALIZED  -1
+#define VMCFS_ERR_VMC_OPEN     -2
+#define VMCFS_ERR_VMC_READ     -3
+#define VMCFS_ERR_CARD_TYPE    -4
+#define VMCFS_ERR_NOT_FORMATED -5
+#define VMCFS_ERR_VMC_SIZE     -6
+#define VMCFS_ERR_NOT_MOUNT    -7
+#define VMCFS_ERR_MOUNT_BUSY   -8
+#define VMCFS_ERR_IMPLEMENTED  -9
+
+
+//  The devctl commands: 0x56 == V, 0x4D == M, 0x43 == C, 0x01, 0x02, ... == command number.
+#define DEVCTL_VMCFS_CLEAN   0x564D4301 //  Set as free all fat cluster corresponding to a none existing object. ( Object are just marked as none existing but not removed from fat table when rmdir or remove fonctions are call. This allow to recover a deleted file. )
+#define DEVCTL_VMCFS_CKFREE  0x564D4302 //  Check free space available on vmc. 
+
+//  The ioctl commands: 0x56 == V, 0x4D == M, 0x43 == C, 0x01, 0x02, ... == command number.
+#define IOCTL_VMCFS_RECOVER  0x564D4303 //  Recover an object marked as none existing. ( data must be a valid path to an object in vmc file ) 
+
+
+//  Vmc format enum
+typedef enum {
+   FORMAT_FULL, 
+   FORMAT_FAST
+} Vmc_Format_Enum;
+
+
+//  Memorycard type definitions
+#define PSX_MEMORYCARD	 0x1
+#define PS2_MEMORYCARD	 0x2
+#define PDA_MEMORYCARD	 0x3
+
+//  Directory Entry Mode Flags
+#define DF_READ          0x0001  //     Read permission. 
+#define DF_WRITE         0x0002  //     Write permission. 
+#define DF_EXECUTE       0x0004  //     Execute permission. 
+#define DF_PROTECTED     0x0008  //     Directory is copy protected. 
+#define DF_FILE          0x0010  //     Regular file. 
+#define DF_DIRECTORY     0x0020  //     Directory. 
+#define DF_040           0x0040  //     Used internally to create directories. 
+#define DF_080           0x0080  //     Copied? 
+#define DF_0100          0x0100  //     - 
+#define O_CREAT          0x0200  //     Used to create files. 
+#define DF_0400          0x0400  //     Set when files and directories are created, otherwise ignored.
+#define DF_POCKETSTN     0x0800  //     PocketStation application save file. 
+#define DF_PSX           0x1000  //     PlayStation save file. 
+#define DF_HIDDEN        0x2000  //     File is hidden. 
+#define DF_04000         0x4000  //     - 
+#define DF_EXISTS        0x8000  //     This entry is in use. If this flag is clear, then the file or directory has been deleted. 
+
+
+//  Cluster definitions
+#define MAX_CLUSTER_SIZE 0x400
+
+#define ROOT_CLUSTER     0x00000000
+#define FREE_CLUSTER     0x7FFFFFFF
+#define EOF_CLUSTER      0xFFFFFFFF
+#define ERROR_CLUSTER    0xFFFFFFFF
+#define NOFOUND_CLUSTER  0xFFFFFFFF
+#define MASK_CLUSTER     0x80000000
+
+
+// The debugging functions, very very handy
+#ifdef DEBUG
+#define DEBUGPRINT( level, args... ) \
+	if( DEBUG >= level ) printf( args )
+#else
+	#define DEBUGPRINT( args... )
+#endif
+
+
+// Used for timing functions, use this to optimize stuff
+#ifdef PROFILING
+	void profilerStart( iop_sys_clock_t *iopclock );
+	void profilerEnd( const char *function, const char* name, iop_sys_clock_t *iopclock1 );
+	//This creates 2 variables with the names name1/name2, and starts the profiler
+	#define PROF_START( name ) \
+		iop_sys_clock_t name;\
+		profilerStart( &name );
+	//this takes the 2 variable names and ends the profiler, printing the time taken
+	#define PROF_END( name ) \
+		profilerEnd( __func__, #name, &name );
+#else
+	//define away the profiler functions
+	#define PROF_START( args )	;
+	#define PROF_END( args )		;
+#endif
+
+
+//  Global Structures Defintions
+
+//  General data struct shared by both files  /  folders that we have opened
+struct gen_privdata
+{
+	int fd;
+	unsigned int indir_fat_clusters[ 32 ];
+	unsigned int first_allocatable;
+	unsigned int last_allocatable;
+	unsigned char dirent_page;
+};
+
+//  the structure used by files that we have opened
+struct file_privdata
+{
+	struct gen_privdata gendata;
+	unsigned int file_startcluster;
+	unsigned int file_length;
+	unsigned int file_position;
+	unsigned int file_cluster;
+	unsigned int cluster_offset;
+	unsigned int file_dirpage;
+};
+
+//  the structure used by directories that we have opened
+struct dir_privdata
+{
+	struct gen_privdata gendata;
+	unsigned int dir_number;      //  first or second entry in the cluster?
+	unsigned int dir_cluster;     //  what cluster we are currently reading directory entries from
+	unsigned int dir_length;      //  the length of the directory
+};
+
+//  date  /  time descriptor
+typedef struct {
+	unsigned char  unused0;
+	unsigned char  sec;
+	unsigned char  min;
+	unsigned char  hour;
+	unsigned char  day;
+	unsigned char  month;
+	unsigned short year;
+} vmc_datetime;
+
+//  the structure of a directory entry
+struct direntry
+{
+	unsigned short mode;            //  See directory mode definitions.
+	unsigned char  unused0[ 2 ];    //  - 
+	unsigned int   length;          //  Length in bytes if a file, or entries if a directory.
+	vmc_datetime   created;         //  created time.
+	unsigned int   cluster;         //  First cluster of the file, or 0xFFFFFFFF for an empty file. In "." entries it's the first cluster of the parent directory relative to first_allocatable.
+	unsigned int   dir_entry;       //  Only in "." entries. Entry of this directory in its parent's directory.
+	vmc_datetime   modified;        //  Modification time.
+	unsigned int   attr;            //  User defined attribute.
+	unsigned char  unused1[ 28 ];   //  - 
+	unsigned char  name[ 32 ];      //  Zero terminated name for this directory entry.
+	unsigned char  unused2[ 416 ];  //  - 
+};
+
+//  A structure containing all of the information about the superblock on a memory card.
+struct superblock
+{
+	unsigned char  magic[ 40 ];
+	unsigned short page_size;
+	unsigned short pages_per_cluster;
+	unsigned short pages_per_block;
+	unsigned short unused0;		               //  always 0xFF00
+	unsigned int   clusters_per_card;
+	unsigned int   first_allocatable;
+	unsigned int   last_allocatable;
+	unsigned int   root_cluster;	           //  must be 0
+	unsigned int   backup_block1;	           //  1023
+	unsigned int   backup_block2;	           //  1024
+	unsigned char  unused1[ 8 ];		         //  unused  /  who knows what it is
+	unsigned int   indir_fat_clusters[ 32 ];
+	unsigned int   bad_block_list[ 32 ];
+	unsigned char  mc_type;
+	unsigned char  mc_flag;
+  unsigned short unused2;                  //  zero
+  unsigned int   cluster_size;             //  1024 always, 0x400
+  unsigned int   unused3;                  //  0x100
+  unsigned int   size_in_megs;             //  size in megabytes
+  unsigned int   unused4;                  //  0xffffffff
+  unsigned char  unused5[ 12 ];            //  zero
+  unsigned int   max_used;                 //  97%of total clusters
+  unsigned char  unused6[ 8 ];             //  zero
+  unsigned int   unused7;                  //  0xffffffff
+};
+
+//  General vmc image structure                                   
+struct global_vmc
+{
+	int               fd;                                    //  global descriptor
+	struct superblock header;                                //  superblock header
+	int               formated;                              //  card is formated
+	int               ecc_flag;                              //  ecc data found in vmc file
+	unsigned int      card_size;                             //  vmc file size
+	unsigned int      total_pages;                           //  total number of pages in the vmc file
+	unsigned int      cluster_size;                          //  size in byte of a cluster
+	unsigned short    erase_byte;                            //  erased blocks have all bits set to 0x0 or 0xFF
+	unsigned int      last_idc;                              //  last indirect cluster
+	unsigned int      last_cluster;                          //  last cluster
+	unsigned int      indirect_cluster[ MAX_CLUSTER_SIZE ];  //  indirect fat cluster
+	unsigned int      fat_cluster[ MAX_CLUSTER_SIZE ];       //  fat cluster
+	unsigned int      last_free_cluster;                     //  adress of the last free cluster found when getting free cluster
+};
+
+
+extern struct global_vmc g_Vmc_Image[ 2 ];
+extern int               g_Vmc_Format_Mode;
+extern int               g_Vmc_Remove_Flag;
+extern int               g_Vmc_Initialized;
+
+
+//  vmc_fs.c
+int          Vmc_Initialize ( iop_device_t * driver );
+int          Vmc_Deinitialize ( iop_device_t * driver );
+
+// vmc_io.c
+int          Vmc_Format    ( iop_file_t *, const char *dev, const char *blockdev, void *arg, size_t arglen );
+int          Vmc_Open      ( iop_file_t *f, const char *name, int flags, int mode );
+int          Vmc_Close     ( iop_file_t* f );
+int          Vmc_Read      ( iop_file_t* f, void* buffer, int size );
+int          Vmc_Write     ( iop_file_t* f, void* buffer, int size );
+int          Vmc_Lseek     ( iop_file_t* f, unsigned long offset, int whence );
+int          Vmc_Ioctl     ( iop_file_t* f, unsigned long request, void* data );
+int          Vmc_Remove    ( iop_file_t* f, const char* path );
+int          Vmc_Mkdir     ( iop_file_t* f, const char* path1, int mode );
+int          Vmc_Rmdir     ( iop_file_t* f, const char* path1 );
+int          Vmc_Dopen     ( iop_file_t* f, const char* path );
+int          Vmc_Dclose    ( iop_file_t* f );
+int          Vmc_Dread     ( iop_file_t* f, iox_dirent_t *buf );
+int          Vmc_Getstat   ( iop_file_t* f, const char* path, iox_stat_t * stat );
+int          Vmc_Chstat    ( iop_file_t* f, const char* path, iox_stat_t * stat, unsigned int unknown );
+int          Vmc_Rename    ( iop_file_t* f, const char* path, const char* new_name );
+int          Vmc_Chdir     ( iop_file_t* f, const char* path );
+int          Vmc_Sync      ( iop_file_t* f, const char* device, int flag );
+int          Vmc_Mount     ( iop_file_t* f, const char* fsname, const char* devname, int flag, void *arg, unsigned int arg_len );
+int          Vmc_Umount    ( iop_file_t* f, const char* fsname );
+int          Vmc_Lseek64   ( iop_file_t* f, long long offset, int whence );
+int          Vmc_Devctl    ( iop_file_t* f, const char* path, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen );
+int          Vmc_Symlink   ( iop_file_t* f, const char* old, const char* new );
+int          Vmc_Readlink  ( iop_file_t* f, const char* path, char* buf, unsigned int buf_len );
+int          Vmc_Ioctl2    ( iop_file_t* f, int cmd, void *arg, unsigned int arglen,	void *buf, unsigned int buflen );
+int          Vmc_Recover   ( int unit, const char* path1 );
+unsigned int Vmc_Checkfree ( int unit );
+int          Vmc_Clean     ( int unit );
+
+//  mcfat.c
+typedef enum {
+   FAT_VALUE,
+   FAT_MASK
+} GetFat_Mode;
+
+typedef enum {
+   FAT_RESET,
+   FAT_SET
+} SetFat_Mode;
+
+unsigned int getFatEntry ( int fd, unsigned int cluster, unsigned int* indir_fat_clusters, GetFat_Mode Mode );
+unsigned int setFatEntry ( int fd, unsigned int cluster, unsigned int value, unsigned int* indir_fat_clusters, SetFat_Mode Mode );
+
+
+//  ps2.c
+int          eraseBlock ( int fd, unsigned int block );
+int          writePage ( int fd, unsigned char* page, unsigned int pagenum );
+int          writeCluster ( int fd, unsigned char* cluster, unsigned int clusternum );
+int          writeClusterPart ( int fd, unsigned char* cluster, unsigned int clusternum, int cluster_offset, int size );
+int          readPage ( int fd, unsigned char* page, unsigned int pagenum );
+int          readCluster ( int fd, unsigned char* cluster, unsigned int clusternum );
+
+
+//  misc.c
+unsigned int getDirentryFromPath ( struct direntry* retval, const char* path, struct gen_privdata* gendata, int unit );
+unsigned int addObject ( struct gen_privdata* gendata, unsigned int parentcluster, struct direntry* parent, struct direntry* dirent, int unit );
+void         removeObject ( struct gen_privdata* gendata, unsigned int dirent_cluster, struct direntry* dirent, int unit );
+unsigned int getFreeCluster ( struct gen_privdata* gendata, int unit );
+int          getPs2Time ( vmc_datetime* tm );
+int          setDefaultSpec ( int unit );
+int          buildECC ( int unit, char* Page_Data, char* ECC_Data );
Index: ps2launchargs/source/uLaunchELF/vmcfs/src/vmc_fat.c
===================================================================
--- ps2launchargs/source/uLaunchELF/vmcfs/src/vmc_fat.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/vmcfs/src/vmc_fat.c	(revision 1101)
@@ -0,0 +1,139 @@
+#include "vmc.h"
+
+
+// Fat table functions
+
+unsigned int getFatEntry ( int fd, unsigned int cluster, unsigned int* indir_fat_clusters, GetFat_Mode Mode ) 
+{
+
+	int unit = ( fd == g_Vmc_Image[ 0 ].fd ) ? 0 : 1;
+
+	// The fat index, aka which cluster we want to know about
+	unsigned int fat_index = cluster;
+
+	// The offset in the fat cluster where we can find information about the sector
+	unsigned int fat_offset = fat_index % ( g_Vmc_Image[ unit ].cluster_size / 4 );
+
+	// Which fat cluster that the information would be in
+	unsigned int indirect_index = fat_index / ( g_Vmc_Image[ unit ].cluster_size / 4 );
+
+	// The offset in the indirect fat cluster that points to the fat table we are interested in
+	unsigned int indirect_offset = indirect_index % ( g_Vmc_Image[ unit ].cluster_size / 4 );
+
+	// This gives the location of the fat_offset inside of the indirect fat cluster list.  Each indirect fat cluster can point to
+	// 256 regular fat clusters, and each fat cluster holds information on 256 sectors.
+	unsigned int dbl_indirect_index = fat_index / (  ( g_Vmc_Image[ unit ].cluster_size / 4 ) * ( g_Vmc_Image[ unit ].cluster_size / 4 )  );
+
+	// Cache indirect file table? ( Generally we will be accessing the first part of it for most virtual memory cards ) 
+	// Get the data for the indirect fat cluster ( as indicated by dbl_indirect_index ) 
+	unsigned int indirect_cluster_num	 = indir_fat_clusters[ dbl_indirect_index ];
+
+	if ( g_Vmc_Image[ unit ].last_idc != indirect_cluster_num ) 
+		readCluster ( fd, ( unsigned char* ) g_Vmc_Image[ unit ].indirect_cluster, indirect_cluster_num );
+
+	g_Vmc_Image[ unit ].last_idc = indirect_cluster_num;
+
+	// Get the data from the fat cluster ( pointed to by the indirect fat cluster ) 
+	unsigned int fat_cluster_num = g_Vmc_Image[ unit ].indirect_cluster[ indirect_offset ];
+
+	if ( g_Vmc_Image[ unit ].last_cluster != fat_cluster_num ) 
+		readCluster ( fd, ( unsigned char* ) g_Vmc_Image[ unit ].fat_cluster, fat_cluster_num );
+
+	g_Vmc_Image[ unit ].last_cluster = fat_cluster_num;
+
+	// Check if the entry in the fat table corresponds to a free cluster or a eof cluster
+	if ( g_Vmc_Image[ unit ].fat_cluster[ fat_offset ] == FREE_CLUSTER || g_Vmc_Image[ unit ].fat_cluster[ fat_offset ] == EOF_CLUSTER ) 
+		return g_Vmc_Image[ unit ].fat_cluster[ fat_offset ];
+
+	if ( Mode == FAT_MASK )
+	{
+
+		if ( g_Vmc_Image[ unit ].fat_cluster[ fat_offset ] & MASK_CLUSTER )
+		{
+
+			return MASK_CLUSTER;
+
+		}
+		else
+		{
+
+			return 0;
+
+		}
+		
+	}
+
+	// Return the fat entry, but remove the most significant bit.
+	return g_Vmc_Image[ unit ].fat_cluster[ fat_offset ] & FREE_CLUSTER;
+
+}
+
+unsigned int setFatEntry ( int fd, unsigned int cluster, unsigned int value, unsigned int* indir_fat_clusters, SetFat_Mode Mode ) 
+{
+
+	int unit = ( fd == g_Vmc_Image[ 0 ].fd ) ? 0 : 1;
+
+	// The fat index, aka which cluster we want to know about
+	unsigned int fat_index = cluster;
+
+	// The offset in the fat cluster where we can find information about the sector
+	unsigned int fat_offset = fat_index % ( g_Vmc_Image[ unit ].cluster_size / 4 );
+
+	// Which fat cluster that the information would be in
+	unsigned int indirect_index = fat_index / ( g_Vmc_Image[ unit ].cluster_size / 4 );
+
+	// The offset in the indirect fat cluster that points to the fat table we are interested in
+	unsigned int indirect_offset = indirect_index % ( g_Vmc_Image[ unit ].cluster_size / 4 );
+
+	// This gives the location of the fat_offset inside of the indirect fat cluster list.  Each indirect fat cluster can point to
+	// 256 regular fat clusters, and each fat cluster holds information on 256 sectors.
+	unsigned int dbl_indirect_index = fat_index / (  ( g_Vmc_Image[ unit ].cluster_size / 4 ) * ( g_Vmc_Image[ unit ].cluster_size / 4 )  );
+
+	// Cache indirect file table? ( Generally we will be accessing the first part of it for most virtual memory cards
+	// Get the data for the indirect fat cluster ( as indicated by dbl_indirect_index ) 
+	unsigned int indirect_cluster_num	 = indir_fat_clusters[ dbl_indirect_index ];
+
+	if ( g_Vmc_Image[ unit ].last_idc != indirect_cluster_num ) 
+		readCluster ( fd, ( unsigned char* ) g_Vmc_Image[ unit ].indirect_cluster, indirect_cluster_num );
+
+	g_Vmc_Image[ unit ].last_idc = indirect_cluster_num;
+
+	// Get the data from the fat cluster ( pointed to by the indirect fat cluster ) 
+	unsigned int fat_cluster_num = g_Vmc_Image[ unit ].indirect_cluster[ indirect_offset ];
+
+	if ( g_Vmc_Image[ unit ].last_cluster != fat_cluster_num ) 
+		readCluster ( fd, ( unsigned char* ) g_Vmc_Image[ unit ].fat_cluster, fat_cluster_num );
+
+	g_Vmc_Image[ unit ].last_cluster = fat_cluster_num;
+
+	if ( value == FREE_CLUSTER || value == EOF_CLUSTER || Mode == FAT_RESET )
+	{
+
+		g_Vmc_Image[ unit ].fat_cluster[ fat_offset ] = value;
+
+	}
+	else
+	{
+
+		g_Vmc_Image[ unit ].fat_cluster[ fat_offset ] = value | MASK_CLUSTER;
+
+	}
+
+	writeCluster ( fd, ( unsigned char* ) g_Vmc_Image[ unit ].fat_cluster, fat_cluster_num );
+	
+	// Update last free cluster
+	if ( ( value == FREE_CLUSTER && Mode == FAT_SET ) || ( Mode == FAT_RESET ) )
+	{
+
+		if ( cluster < g_Vmc_Image[ unit ].last_free_cluster )
+		{
+
+			g_Vmc_Image[ unit ].last_free_cluster = cluster;
+
+		}
+
+	}
+
+	return 0;
+
+}
Index: ps2launchargs/source/uLaunchELF/vmcfs/src/vmc_fs.c
===================================================================
--- ps2launchargs/source/uLaunchELF/vmcfs/src/vmc_fs.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/vmcfs/src/vmc_fs.c	(revision 1101)
@@ -0,0 +1,128 @@
+#include "vmc.h"
+
+
+ //  Driver fonctions
+
+#define MODNAME "vmc_fs"
+IRX_ID ( MODNAME, 1, 2 );
+
+
+// Static variables.
+static iop_device_t     s_Vmc_Driver;
+static iop_device_ops_t s_Vmc_Functions;
+
+// Global variables.
+struct global_vmc          g_Vmc_Image[ 2 ];
+int                        g_Vmc_Remove_Flag;
+int                        g_Vmc_Initialized;
+
+//----------------------------------------------------------------------------
+// Initialize vmc driver
+//----------------------------------------------------------------------------
+int Vmc_Initialize ( iop_device_t * driver ) 
+{
+
+	if ( g_Vmc_Initialized ) 
+		return VMCFS_ERR_NO;
+
+	g_Vmc_Initialized = TRUE;
+
+	//  init the global file descriptor to something negative ( ubergeek like 42, and polo like 35 so - 4235 ) 
+	g_Vmc_Image[ 0 ].fd = -4235;
+	g_Vmc_Image[ 1 ].fd = -4235;
+
+	DEBUGPRINT ( 1, "vmcfs: Filesystem Driver Initialized\n" );
+
+	return VMCFS_ERR_NO;
+}
+
+
+//----------------------------------------------------------------------------
+// Deinitialize vmc driver
+//----------------------------------------------------------------------------
+int Vmc_Deinitialize ( iop_device_t * driver ) 
+{
+
+	int i = 0;
+	
+	if ( !g_Vmc_Initialized ) 
+		return VMCFS_ERR_INITIALIZED;
+
+	g_Vmc_Initialized = FALSE;
+	
+	for ( i = 0; i < 2; i++ )
+	{
+	
+		if( g_Vmc_Image[ i ].fd >=0 )
+		{
+			
+			close ( g_Vmc_Image[ i ].fd );
+			
+		}
+		
+	}
+
+	DEBUGPRINT ( 1, "vmcfs: Filesystem Driver Deinitialized\n" );
+
+	return VMCFS_ERR_NO;
+
+}
+
+// Entry point of the driver.
+int _start ( int argc, char*  * argv ) 
+{
+
+	printf ( "vmcfs: Created by ubergeek42\n" );
+	printf ( "vmcfs: ... Improved by Polo35.\n" );
+	printf ( "vmcfs: Version 1.2\n" );
+
+	g_Vmc_Initialized = FALSE;
+	g_Vmc_Remove_Flag = FALSE;
+
+	s_Vmc_Driver.type    = (IOP_DT_FS | IOP_DT_FSEXT);
+	s_Vmc_Driver.version = 1;
+	s_Vmc_Driver.name    = "vmc"; //  the name used to access this device ( eg: vmc0:  /  ) 
+	s_Vmc_Driver.desc    = "Virtual Memory Card s_Vmc_Driver";
+	s_Vmc_Driver.ops     = &s_Vmc_Functions;
+
+	//  Typecasting to ( void* ) eliminates a bunch of warnings.
+	s_Vmc_Functions.init	   = Vmc_Initialize;
+	s_Vmc_Functions.deinit	 = Vmc_Deinitialize;
+	s_Vmc_Functions.format	 = Vmc_Format;
+	s_Vmc_Functions.open	   = Vmc_Open;
+	s_Vmc_Functions.close	   = Vmc_Close;
+	s_Vmc_Functions.read	   = Vmc_Read;
+	s_Vmc_Functions.write	   = Vmc_Write;
+	s_Vmc_Functions.lseek	   = Vmc_Lseek;
+	s_Vmc_Functions.ioctl	   = Vmc_Ioctl;
+	s_Vmc_Functions.remove	 = Vmc_Remove;
+	s_Vmc_Functions.mkdir	   = Vmc_Mkdir;
+	s_Vmc_Functions.rmdir	   = Vmc_Rmdir;
+	s_Vmc_Functions.dopen	   = Vmc_Dopen;
+	s_Vmc_Functions.dclose	 = Vmc_Dclose;
+	s_Vmc_Functions.dread	   = Vmc_Dread;
+	s_Vmc_Functions.getstat  = Vmc_Getstat;
+	s_Vmc_Functions.chstat	 = Vmc_Chstat;
+	/* Extended ops start here. */
+	s_Vmc_Functions.rename   = Vmc_Rename;
+	s_Vmc_Functions.chdir    = Vmc_Chdir;
+	s_Vmc_Functions.sync     = Vmc_Sync;
+	s_Vmc_Functions.mount    = Vmc_Mount;
+	s_Vmc_Functions.umount   = Vmc_Umount;
+	s_Vmc_Functions.lseek64  = Vmc_Lseek64;
+	s_Vmc_Functions.devctl   = Vmc_Devctl;
+	s_Vmc_Functions.symlink  = Vmc_Symlink;
+	s_Vmc_Functions.readlink = Vmc_Readlink;
+	s_Vmc_Functions.ioctl2   = Vmc_Ioctl2;
+
+
+	//  Add the Driver using the ioman export
+	DelDrv ( s_Vmc_Driver.name );
+	AddDrv ( &s_Vmc_Driver );
+
+	//  And we are done!
+	DEBUGPRINT ( 1, "vmcfs: Filesystem Driver %s added!\n", s_Vmc_Driver.name );
+
+	return 0;
+
+}
Index: ps2launchargs/source/uLaunchELF/vmcfs/src/vmc_io.c
===================================================================
--- ps2launchargs/source/uLaunchELF/vmcfs/src/vmc_io.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/vmcfs/src/vmc_io.c	(revision 1101)
@@ -0,0 +1,2544 @@
+#include "vmc.h"
+
+
+//  IO fonctions
+
+
+//----------------------------------------------------------------------------
+// Format a vmc file previously mounted with fileXioMount(.
+// mode can be FORMAT_FULL which mean erase all pages before formatting.
+// or FORMAT_FAST which skip erasing all pages before formatting.
+//----------------------------------------------------------------------------
+int Vmc_Format ( iop_file_t *f, const char *dev, const char *blockdev, void *arg, size_t arglen ) 
+{
+
+	if ( !g_Vmc_Initialized ) 
+		return VMCFS_ERR_INITIALIZED;
+
+	DEBUGPRINT ( 1, "vmcfs: format %d\n", f->unit );
+
+	int mode = FORMAT_FULL;
+
+	struct direntry dirent;
+	int             all_sector;
+	char           *mcbuffer, *mcbuffer2;
+	unsigned int    i, j, k, x, y, last_blk_sector, Page_Num, Page_Num2;
+
+	Page_Num = 0;
+	Page_Num2 = 0;
+
+	if ( g_Vmc_Image[ f->unit ].fd < 0 ) 
+		return VMCFS_ERR_NOT_MOUNT;
+
+	PROF_START ( vmc_formatProf ) 
+
+	if ( mode == FORMAT_FULL ) 
+	{
+
+		for ( i = 0; i < g_Vmc_Image[ f->unit ].total_pages  /  g_Vmc_Image[ f->unit ].header.pages_per_block; i++ ) 
+		{
+
+			DEBUGPRINT ( 7, "vmcfs: format erasing block %d / %d\r", i, g_Vmc_Image[ f->unit ].total_pages  /  g_Vmc_Image[ f->unit ].header.pages_per_block );
+			eraseBlock ( g_Vmc_Image[ f->unit ].fd, i );
+
+		}
+
+	}
+
+	mcbuffer  = ( char* )malloc (  ( g_Vmc_Image[ f->unit ].header.page_size + 0xFF ) & ~( unsigned int )0xFF );
+	mcbuffer2 = ( char* )malloc (  ( g_Vmc_Image[ f->unit ].header.page_size + 0xFF ) & ~( unsigned int )0xFF );
+
+	DEBUGPRINT ( 3, "vmcfs: format start\n" );
+
+	memset ( mcbuffer, g_Vmc_Image[ f->unit ].erase_byte, g_Vmc_Image[ f->unit ].header.page_size );
+	memcpy ( mcbuffer, &g_Vmc_Image[ f->unit ].header, sizeof ( struct superblock )  );
+
+	//  Write header page
+	writePage ( g_Vmc_Image[ f->unit ].fd, mcbuffer, Page_Num );
+
+	Page_Num++;
+
+	DEBUGPRINT ( 3, "vmcfs: format indirect fat cluster\n" );
+
+	//  goto fat table
+	for ( i = 1; i < ( g_Vmc_Image[ f->unit ].header.indir_fat_clusters[ 0 ]* g_Vmc_Image[ f->unit ].header.pages_per_cluster ); i++, Page_Num++ ) { }
+
+	all_sector      = 0;
+	last_blk_sector = g_Vmc_Image[ f->unit ].header.indir_fat_clusters[ 0 ];
+
+	DEBUGPRINT ( 3, "vmcfs: format fat table\n" );
+
+	//  Write fat table pages
+	for ( x = 0; g_Vmc_Image[ f->unit ].header.indir_fat_clusters[ x ]!= 0; x++ ) 
+	{
+
+		last_blk_sector = g_Vmc_Image[ f->unit ].header.indir_fat_clusters[ 0 ]+ x;
+		Page_Num        = last_blk_sector * g_Vmc_Image[ f->unit ].header.pages_per_cluster;
+
+		for ( i = x * g_Vmc_Image[ f->unit ].header.pages_per_cluster; ( i < (  ( x + 1 ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster )  ) && ( i <= (  ( g_Vmc_Image[ f->unit ].total_pages - 1 )  /  65536 )  ); i++, Page_Num++ ) 
+		{
+
+			memset ( mcbuffer, g_Vmc_Image[ f->unit ].erase_byte, g_Vmc_Image[ f->unit ].header.page_size );
+
+			for ( j = i * (  ( g_Vmc_Image[ f->unit ].header.page_size  /  2 )  /  g_Vmc_Image[ f->unit ].header.pages_per_cluster ), k = 0; ( j < i * (  ( g_Vmc_Image[ f->unit ].header.page_size  /  2 )  /  g_Vmc_Image[ f->unit ].header.pages_per_cluster ) + (  ( g_Vmc_Image[ f->unit ].header.page_size  /  2 )  /  g_Vmc_Image[ f->unit ].header.pages_per_cluster )  ) && ( j < (  ( g_Vmc_Image[ f->unit ].header.last_allocatable  /  ( g_Vmc_Image[ f->unit ].header.page_size  /  2 )  ) + 1 )  ); j++, k++ ) 
+			{
+
+				 (  ( unsigned int* ) mcbuffer )[ k ]= (  ( g_Vmc_Image[ f->unit ].total_pages - 1 )  /  65536 ) + last_blk_sector + 1 + j;
+					
+				memset ( mcbuffer2, g_Vmc_Image[ f->unit ].erase_byte, g_Vmc_Image[ f->unit ].header.page_size );
+				Page_Num2 = (  ( unsigned int* ) mcbuffer )[ k ]* g_Vmc_Image[ f->unit ].header.pages_per_cluster;
+
+				for ( y = 0; ( y < (  ( g_Vmc_Image[ f->unit ].header.page_size  /  2 )  /  g_Vmc_Image[ f->unit ].header.pages_per_cluster )  ) && ( all_sector < g_Vmc_Image[ f->unit ].header.last_allocatable ); y++, all_sector++ ) 
+				{
+
+					if ( y == 0 && j == 0 && i == 0 ) 
+					{
+
+						 (  ( unsigned int* ) mcbuffer2 )[ y ]= EOF_CLUSTER;
+
+					}
+					else
+					{
+
+						 (  ( unsigned int* ) mcbuffer2 )[ y ]= FREE_CLUSTER;
+
+					}
+
+				}
+
+				writePage ( g_Vmc_Image[ f->unit ].fd, mcbuffer2, Page_Num2 );
+
+				Page_Num2++;
+				memset ( mcbuffer2, g_Vmc_Image[ f->unit ].erase_byte, g_Vmc_Image[ f->unit ].header.page_size );
+
+				for ( y = 0; ( y < (  ( g_Vmc_Image[ f->unit ].header.page_size  /  2 )  /  g_Vmc_Image[ f->unit ].header.pages_per_cluster )  ) && ( all_sector < g_Vmc_Image[ f->unit ].header.last_allocatable ); y++, all_sector++ ) 
+				{
+
+					 (  ( unsigned int* ) mcbuffer2 )[ y ]= FREE_CLUSTER;
+
+				}
+
+				writePage ( g_Vmc_Image[ f->unit ].fd, mcbuffer2, Page_Num2 );
+
+			}
+
+			writePage ( g_Vmc_Image[ f->unit ].fd, mcbuffer, Page_Num );
+
+		}
+
+	}
+
+	DEBUGPRINT ( 3, "vmcfs: format root directory\n" );
+
+	Page_Num = g_Vmc_Image[ f->unit ].header.first_allocatable * g_Vmc_Image[ f->unit ].header.pages_per_cluster;
+	
+	memset ( &dirent, 0, sizeof ( dirent )  );
+
+	dirent.mode      = DF_EXISTS | DF_0400 | DF_DIRECTORY | DF_READ | DF_WRITE | DF_EXECUTE; // 0x8427
+	dirent.length    = 2;
+	dirent.name[ 0 ] = '.';
+	getPs2Time ( &dirent.created  );
+	getPs2Time ( &dirent.modified );
+
+	writePage ( g_Vmc_Image[ f->unit ].fd, ( unsigned char* ) &dirent, Page_Num );
+	Page_Num++;
+
+	memset ( &dirent, 0, sizeof ( dirent )  );
+
+	dirent.mode      = DF_EXISTS | DF_HIDDEN | DF_0400 | DF_DIRECTORY | DF_WRITE | DF_EXECUTE; // 0xa426;
+	dirent.length    = 0;
+	dirent.name[ 0 ] = '.';
+	dirent.name[ 1 ] = '.';
+	getPs2Time ( &dirent.created  );
+	getPs2Time ( &dirent.modified );
+
+	writePage ( g_Vmc_Image[ f->unit ].fd, ( unsigned char* ) &dirent, Page_Num );
+
+	free ( mcbuffer  );
+	free ( mcbuffer2 );
+
+	DEBUGPRINT ( 3, "vmcfs: format finished\n" );
+
+	PROF_END ( vmc_formatProf ) 
+
+	return VMCFS_ERR_NO;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Open a file from vmc image. fileXioOpen("vmc...
+//----------------------------------------------------------------------------
+int Vmc_Open ( iop_file_t *f, const char *path1, int flags, int mode ) 
+{
+
+	if ( !g_Vmc_Initialized ) 
+		return VMCFS_ERR_INITIALIZED;
+
+	DEBUGPRINT ( 1, "vmcfs: Open %i %s\n", f->unit, path1 );
+
+	if ( g_Vmc_Image[ f->unit ].fd < 0 ) 
+		return VMCFS_ERR_NOT_MOUNT;
+
+	if ( g_Vmc_Image[ f->unit ].formated == FALSE ) 
+		return VMCFS_ERR_NOT_FORMATED;
+
+	PROF_START ( vmc_openProf ) 
+
+	struct direntry       dirent;
+	struct file_privdata* fprivdata = malloc ( sizeof ( struct file_privdata ) );
+
+	if ( fprivdata == NULL )
+		return -1;
+
+	f->privdata = fprivdata;
+
+	fprivdata->gendata.fd                = g_Vmc_Image[ f->unit ].fd;
+	fprivdata->gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
+	fprivdata->gendata.last_allocatable  = g_Vmc_Image[ f->unit ].header.last_allocatable;
+
+	memcpy ( fprivdata->gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
+
+	unsigned int dirent_cluster = getDirentryFromPath ( &dirent, path1, &( fprivdata->gendata ), f->unit );
+
+	if ( dirent_cluster == ROOT_CLUSTER )
+	{
+
+		free ( fprivdata ); //  Release the allocated memory
+
+		PROF_END ( vmc_openProf ) 
+
+		return -1;	//  File not found, could not be opened.
+
+	}
+	else if ( dirent_cluster == NOFOUND_CLUSTER )
+	{
+
+		if ( flags & O_CREAT ) 
+		{
+
+			DEBUGPRINT ( 2, "vmcfs: Open with O_CREAT.\n");
+
+			struct direntry parent;
+			unsigned int    parent_cluster = 0;
+
+			char* path = malloc ( strlen ( path1 ) + 1 ); //  + 1 for null terminator
+			memcpy ( path, path1, strlen ( path1 ) + 1 ); //  create a local copy to work with
+
+			char* filename = strrchr ( path, '/' ); //  last occurance of  / , which should split the file name from the folders
+
+			//  essentially splits path into 2 strings
+			filename[ 0 ]= '\0';
+			filename++;
+
+			DEBUGPRINT ( 2, "vmcfs: Creating file %s in parent folder %s\n", filename, path );
+
+			memset ( &dirent, 0, sizeof ( dirent )  );
+
+			// fill direntry file information
+			strcpy ( dirent.name, filename );
+			dirent.length  = 0;
+			dirent.cluster = EOF_CLUSTER;
+			dirent.mode    = DF_EXISTS | DF_0400 | DF_FILE | DF_READ | DF_WRITE | DF_EXECUTE; //  0x8417
+			getPs2Time ( &dirent.created  );
+			getPs2Time ( &dirent.modified );
+
+			//  we need to know this directories entry in its parent...
+			if ( path[ 0 ] == '\0' ) 
+			{
+
+				//  get the root directories entry
+				parent_cluster = getDirentryFromPath ( &parent, ".", &( fprivdata->gendata ), f->unit );
+
+			}
+			else
+			{
+
+				//  get the folder entry for the parent
+				parent_cluster = getDirentryFromPath ( &parent, path, &( fprivdata->gendata ), f->unit );
+
+			}
+
+			if ( parent_cluster == NOFOUND_CLUSTER )
+			{
+
+				DEBUGPRINT ( 3, "vmcfs: Unable to find parent directory.\n" );
+
+				free ( path );
+				free ( fprivdata ); //  Release the allocated memory
+
+				PROF_END ( vmc_openProf ) 
+
+				return -1;
+
+			}
+
+			dirent_cluster = addObject ( &( fprivdata->gendata ), parent_cluster, &parent, &dirent, f->unit );
+
+			if ( dirent_cluster == ERROR_CLUSTER )
+			{
+
+				DEBUGPRINT ( 2, "vmcfs: open failed on %s\n", path1 );
+
+				free ( path );
+				free ( fprivdata ); //  Release the allocated memory
+
+				PROF_END ( vmc_openProf ) 
+
+				return -1;	//  File not found, could not be opened.
+
+			}
+
+			free ( path );
+
+		}
+		else
+		{
+
+			free ( fprivdata ); //  Release the allocated memory
+
+			PROF_END ( vmc_openProf ) 
+
+			return -1;	//  File not found, could not be opened.
+
+		}
+
+	}
+
+	if ( ( ! ( dirent.mode & DF_EXISTS ) ) || ( flags & O_TRUNC ) ) // File found but is hidden, or trunc the file
+	{
+
+		if ( flags & O_TRUNC )
+			DEBUGPRINT ( 3, "vmcfs: Open with O_TRUNC.\n");
+
+		int          first_cluster   = 1;
+		unsigned int current_cluster = 0;
+		unsigned int last_cluster    = dirent.cluster;
+
+		DEBUGPRINT ( 4, "vmcfs: Searching last cluster of file ...\n" );
+
+		while ( 1 ) 
+		{
+
+			current_cluster = getFatEntry ( fprivdata->gendata.fd, last_cluster, fprivdata->gendata.indir_fat_clusters, FAT_VALUE );
+
+			if ( current_cluster == FREE_CLUSTER ) 
+			{
+
+				// FREE_CLUSTER mean last cluster of the hidden file is found
+				DEBUGPRINT ( 8, "vmcfs: Last cluster of file at %u\n", last_cluster );
+			
+				break;
+
+			}
+			else if ( current_cluster == EOF_CLUSTER ) 
+			{
+
+				// EOF_CLUSTER mean last cluster of the file is found
+				DEBUGPRINT ( 8, "vmcfs: EOF_CLUSTER found.\n" );
+
+				setFatEntry ( fprivdata->gendata.fd, last_cluster, FREE_CLUSTER, fprivdata->gendata.indir_fat_clusters, FAT_SET );
+
+				break;
+
+			}
+			else
+			{
+
+				DEBUGPRINT ( 8, "vmcfs: Testing cluster %u ... value is %u\n", last_cluster, current_cluster );
+
+				// Otherwise set first cluster as eof and remaining clusters as free
+				if ( first_cluster == 1 )
+				{
+
+					setFatEntry ( fprivdata->gendata.fd, last_cluster, EOF_CLUSTER, fprivdata->gendata.indir_fat_clusters, FAT_SET );
+
+					dirent.length  = 0;
+					dirent.cluster = EOF_CLUSTER;
+					dirent.mode    = DF_EXISTS | DF_0400 | DF_FILE | DF_READ | DF_WRITE | DF_EXECUTE; //  0x8417
+					getPs2Time ( &dirent.created  );
+					getPs2Time ( &dirent.modified );
+					writePage ( fprivdata->gendata.fd, ( unsigned char* ) &dirent, ( dirent_cluster + fprivdata->gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster + fprivdata->gendata.dirent_page );
+
+					first_cluster = 0;
+
+				}
+				else
+				{
+
+					setFatEntry ( fprivdata->gendata.fd, last_cluster, FREE_CLUSTER, fprivdata->gendata.indir_fat_clusters, FAT_SET );
+
+				}
+
+			}
+
+			last_cluster = current_cluster;
+
+		}
+
+	}
+
+	// fill opened file informations
+	fprivdata->file_position     = 0;
+	fprivdata->file_dirpage      = ( dirent_cluster + fprivdata->gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster + fprivdata->gendata.dirent_page;
+	fprivdata->file_cluster      = dirent.cluster;
+	fprivdata->cluster_offset    = 0;
+	fprivdata->file_startcluster = dirent.cluster;
+	fprivdata->file_length       = dirent.length; //  set the length to what it should be, and go from there
+
+	DEBUGPRINT ( 2, "vmcfs: File %s opened with length %u\n", path1, fprivdata->file_length );
+
+	PROF_END ( vmc_openProf ) 
+
+	return 1;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Close a file previously open with fileXioOpen("vmc...
+//----------------------------------------------------------------------------
+int Vmc_Close (  iop_file_t* f ) 
+{
+
+	if ( !g_Vmc_Initialized ) 
+		return VMCFS_ERR_INITIALIZED;
+
+	DEBUGPRINT ( 1, "vmcfs: Close %i\n", f->unit );
+
+	if ( g_Vmc_Image[ f->unit ].fd < 0 ) 
+		return VMCFS_ERR_NOT_MOUNT;
+
+	if ( g_Vmc_Image[ f->unit ].formated == FALSE ) 
+		return VMCFS_ERR_NOT_FORMATED;
+
+	PROF_START ( vmc_closeProf ) 
+
+	struct file_privdata* fprivdata = f->privdata;
+
+	free ( fprivdata );
+
+	PROF_END ( vmc_closeProf ) 
+
+	return 0;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Read a file previously open with fileXioOpen("vmc...
+//----------------------------------------------------------------------------
+int Vmc_Read (  iop_file_t* f, void* buffer, int size ) 
+{
+
+	if ( !g_Vmc_Initialized ) 
+		return VMCFS_ERR_INITIALIZED;
+
+	DEBUGPRINT ( 1, "vmcfs: Read %d bytes\n", size );
+
+	if ( g_Vmc_Image[ f->unit ].fd < 0 ) 
+		return VMCFS_ERR_NOT_MOUNT;
+
+	if ( g_Vmc_Image[ f->unit ].formated == FALSE ) 
+		return VMCFS_ERR_NOT_FORMATED;
+
+	PROF_START ( vmc_readProf ) 
+
+	if ( ! ( f->mode & O_RDONLY )  ) 
+	{
+
+		PROF_END ( vmc_readProf ) 
+
+		return -1; //  if the file isn't opened for reading, return -1. No return eroor code from errno
+
+	}
+
+	struct file_privdata* fprivdata = f->privdata;
+
+	fprivdata->gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
+	fprivdata->gendata.last_allocatable  = g_Vmc_Image[ f->unit ].header.last_allocatable;
+
+	memcpy ( fprivdata->gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
+
+	//  we are at eof
+	if (  ( fprivdata->file_length - fprivdata->file_position ) == 0 ) 
+	{
+
+		PROF_END ( vmc_readProf ) 
+
+		return 0;
+
+	}
+
+	DEBUGPRINT ( 3, "vmcfs: Reading in %i bytes\n", size );
+
+	//  we need to read in size, unless size is larger then length
+	if ( size > fprivdata->file_length - fprivdata->file_position ) 
+	{
+
+		DEBUGPRINT ( 3, "vmcfs: Adjusting size to read in to be %u\n", fprivdata->file_length - fprivdata->file_position );
+
+		size = fprivdata->file_length - fprivdata->file_position;
+
+	}
+
+	//  Ok so we have been requested to read size bytes from the open file, which starts with fprivdata->file_cluster
+	//  and our current position in the cluster is cluster_offset, while our overall position is file_position.
+	//  We can determine what cluster in the link we should be in, by taking our overall position and dividing by 1024
+	//  the size of a cluster.
+
+	int data_read = 0;  //  How much data we have read in so far
+	char* cluster_data; //  Temporary storage for a cluster of data
+
+	cluster_data  = ( char* )malloc ( ( g_Vmc_Image[ f->unit ].cluster_size + 0xFF ) & ~( unsigned int )0xFF );	
+	memset ( cluster_data, 0, g_Vmc_Image[ f->unit ].cluster_size );
+
+	//  While we still have data to read in
+	while ( data_read < size ) 
+	{
+
+		//  Read in the file_cluster
+		readCluster ( fprivdata->gendata.fd, cluster_data, fprivdata->file_cluster + fprivdata->gendata.first_allocatable );
+
+		//  We have 1024 bytes in cluster_data now, but we already read in cluster_offset bytes
+		//  So we now need to copy whats left into the buffer that was passed to us
+
+		DEBUGPRINT ( 3, "vmcfs: There are %i bytes remaining\n", size - data_read );
+ 		DEBUGPRINT ( 3, "vmcfs: There are %i bytes left in cluster %u\n", ( fprivdata->cluster_offset == 0 ) ? 0 : g_Vmc_Image[ f->unit ].cluster_size - fprivdata->cluster_offset, fprivdata->file_cluster + fprivdata->gendata.first_allocatable );
+
+		//  If the data remaining in a cluster is larger then the buffer passed to us, we can only read in size data
+		if ( size - data_read < g_Vmc_Image[ f->unit ].cluster_size - fprivdata->cluster_offset ) 
+		{
+
+			DEBUGPRINT ( 3, "vmcfs: Read in %i bytes\n", size );
+
+			memcpy ( buffer + data_read, cluster_data + fprivdata->cluster_offset, size - data_read );
+			fprivdata->cluster_offset += ( size - data_read );
+			data_read                 += ( size - data_read );
+
+		}
+		else	//  We can copy in the rest of the cluster, since there is space in the buffer passed to us
+		{
+
+			DEBUGPRINT ( 3, "vmcfs: Read in %i bytes\n", g_Vmc_Image[ f->unit ].cluster_size - fprivdata->cluster_offset );
+
+			memcpy ( buffer + data_read, cluster_data + fprivdata->cluster_offset, g_Vmc_Image[ f->unit ].cluster_size - fprivdata->cluster_offset );
+			data_read                 += ( g_Vmc_Image[ f->unit ].cluster_size - fprivdata->cluster_offset );
+			fprivdata->cluster_offset += ( g_Vmc_Image[ f->unit ].cluster_size - fprivdata->cluster_offset );
+
+		}
+		
+		//  If we have used up all of the data in a cluster, we need to tell it that the current cluster is the next one in the list
+		if ( fprivdata->cluster_offset == g_Vmc_Image[ f->unit ].cluster_size ) 
+		{
+
+			DEBUGPRINT ( 6, "vmcfs: Moving onto next cluster\n" );
+
+			fprivdata->file_cluster   = getFatEntry ( fprivdata->gendata.fd, fprivdata->file_cluster, fprivdata->gendata.indir_fat_clusters, FAT_VALUE );
+			fprivdata->cluster_offset = 0;
+
+		}
+
+	}
+
+	free( cluster_data );
+
+	//  Increase the file position by read
+	fprivdata->file_position += data_read;
+
+	PROF_END ( vmc_readProf ) 
+
+	//  Return the amount read in.
+	return data_read;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Write a file previously open with fileXioOpen("vmc...
+//----------------------------------------------------------------------------
+int Vmc_Write (  iop_file_t* f, void* buffer, int size ) 
+{
+
+	if ( !g_Vmc_Initialized ) 
+		return VMCFS_ERR_INITIALIZED;
+
+	DEBUGPRINT ( 1, "vmcfs: Write %i bytes\n", size );
+
+	if ( g_Vmc_Image[ f->unit ].fd < 0 ) 
+		return VMCFS_ERR_NOT_MOUNT;
+
+	if ( g_Vmc_Image[ f->unit ].formated == FALSE ) 
+		return VMCFS_ERR_NOT_FORMATED;
+
+	PROF_START ( vmc_writeProf ) 
+
+	if ( ! ( f->mode & O_WRONLY )  ) 
+	{
+
+		PROF_END ( vmc_writeProf ) 
+
+		return -1; //  if the file isn't opened for writing, return -1
+
+	}
+
+	struct file_privdata* fprivdata = f->privdata;
+
+	fprivdata->gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
+	fprivdata->gendata.last_allocatable  = g_Vmc_Image[ f->unit ].header.last_allocatable;
+
+	memcpy ( fprivdata->gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
+
+	if ( f->mode & O_APPEND ) {
+
+		DEBUGPRINT ( 8, "vmcfs: Write with O_APPEND.\n");
+
+		fprivdata->file_position = fprivdata->file_length;
+
+	}
+
+	unsigned int current_cluster;
+
+	//  if we are going to go past the eof with this write
+	//  we need to allocate some more free cluster space
+	int num_clusters = fprivdata->file_length  /  g_Vmc_Image[ f->unit ].cluster_size;
+
+	if (  ( fprivdata->file_length %g_Vmc_Image[ f->unit ].cluster_size ) > 0 ) 
+		num_clusters++;
+
+	DEBUGPRINT ( 5, "vmcfs: File lenght in cluster before this write: %u\n", num_clusters );
+
+	int num_clusters_required = ( fprivdata->file_position + size )  /  g_Vmc_Image[ f->unit ].cluster_size;
+
+	if (  (  ( fprivdata->file_position + size ) %g_Vmc_Image[ f->unit ].cluster_size ) > 0 ) 
+		num_clusters_required++;
+
+	DEBUGPRINT ( 5, "vmcfs: File lenght in cluster after this write : %u\n", num_clusters_required );
+
+	if ( num_clusters_required > num_clusters ) 
+	{
+
+		fprivdata->file_length = fprivdata->file_position + size;
+
+		DEBUGPRINT ( 3, "vmcfs: File position:  %u\n", fprivdata->file_position );
+		DEBUGPRINT ( 3, "vmcfs: Size to write:  %u\n", size );
+		DEBUGPRINT ( 3, "vmcfs: File length  :  %u\n", fprivdata->file_length );
+
+		//  now determine how many clusters we need forthis write
+		unsigned int clusters_needed = num_clusters_required - num_clusters;
+
+		DEBUGPRINT ( 3, "vmcfs: We need to allocate %u more clusters for storage\n", clusters_needed );
+
+		int i                     = 0;
+		unsigned int free_cluster = 0;
+		unsigned int last_cluster = 0;
+
+		if ( fprivdata->file_startcluster == EOF_CLUSTER ) 
+		{
+
+			free_cluster = getFreeCluster ( &( fprivdata->gendata ), f->unit );
+
+			if ( free_cluster == ERROR_CLUSTER )
+			{
+
+				DEBUGPRINT ( 2, "Not enough free space to add initial cluster.  Aborting.\n" );
+
+				PROF_END ( vmc_writeProf ) 
+
+				return -1;
+
+			}
+
+			DEBUGPRINT ( 3, "vmcfs: Initial cluster at %u\n", free_cluster );
+
+			//  mark the free cluster as eof
+			setFatEntry ( fprivdata->gendata.fd, free_cluster, EOF_CLUSTER, fprivdata->gendata.indir_fat_clusters, FAT_SET );
+
+			struct direntry dirent;
+
+			readPage ( fprivdata->gendata.fd, ( unsigned char* ) &dirent, fprivdata->file_dirpage );
+			dirent.cluster = free_cluster;
+			writePage ( fprivdata->gendata.fd, ( unsigned char* ) &dirent, fprivdata->file_dirpage );
+
+			fprivdata->file_startcluster = free_cluster;
+			fprivdata->file_cluster      = free_cluster;
+
+		}
+		else
+		{
+
+			//  loop to find the last cluster of the file.
+			last_cluster = fprivdata->file_startcluster;
+
+			DEBUGPRINT ( 3, "vmcfs: Searching last cluster of file\n" );
+
+			while ( 1 ) 
+			{
+
+				current_cluster = getFatEntry ( fprivdata->gendata.fd, last_cluster, fprivdata->gendata.indir_fat_clusters, FAT_VALUE );
+
+				if ( current_cluster == FREE_CLUSTER ) 
+				{
+
+					DEBUGPRINT ( 10, "vmcfs: Testing cluster %d ... value is FREE_CLUSTER\n", last_cluster );
+
+				}
+				else if ( current_cluster == EOF_CLUSTER ) 
+				{
+
+					DEBUGPRINT ( 10, "vmcfs: Testing cluster %d ... value is EOF_CLUSTER\n", i );
+					break;
+
+				}
+				else
+				{
+
+					DEBUGPRINT ( 10, "vmcfs: Testing cluster %d ... value is %d\n", last_cluster, current_cluster );
+
+				}
+
+				last_cluster = current_cluster;
+				i++;
+
+			}
+
+			DEBUGPRINT ( 3, "vmcfs: Last cluster of file at %u\n", last_cluster );
+
+			free_cluster = getFreeCluster ( &( fprivdata->gendata ), f->unit );
+
+			if ( free_cluster == ERROR_CLUSTER )
+			{
+
+				DEBUGPRINT ( 2, "Not enough free space to add restart cluster.  Aborting.\n" );
+
+				PROF_END ( vmc_writeProf ) 
+
+				return -1;
+
+			}
+			
+			DEBUGPRINT ( 3, "vmcfs: Restart cluster for the file at %u\n", free_cluster );
+
+			//  mark the last cluster as restart of our file
+			setFatEntry ( fprivdata->gendata.fd, last_cluster, free_cluster, fprivdata->gendata.indir_fat_clusters, FAT_SET );
+
+			//  mark the free cluster as eof
+			setFatEntry ( fprivdata->gendata.fd, free_cluster, EOF_CLUSTER, fprivdata->gendata.indir_fat_clusters, FAT_SET );
+
+			fprivdata->file_cluster = free_cluster;
+
+		}
+
+		clusters_needed--;
+		last_cluster = free_cluster;
+
+		//  allocate free clusters for the space required.
+		for ( i = 0; i < clusters_needed; i++ ) 
+		{
+
+			free_cluster = getFreeCluster ( &( fprivdata->gendata ), f->unit );
+
+			if ( free_cluster == ERROR_CLUSTER )
+			{
+
+				DEBUGPRINT ( 2, "Not enough free space to add cluster to the chain.  Aborting.\n" );
+
+				PROF_END ( vmc_writeProf ) 
+
+				return -1;
+
+			}
+			
+			DEBUGPRINT ( 3, "vmcfs: Adding cluster %u to the chain for the file\n", free_cluster );
+
+			setFatEntry ( fprivdata->gendata.fd, last_cluster, free_cluster, fprivdata->gendata.indir_fat_clusters, FAT_SET );
+			last_cluster = free_cluster;
+
+			//  mark the last cluster as eof
+			setFatEntry ( fprivdata->gendata.fd, last_cluster, EOF_CLUSTER, fprivdata->gendata.indir_fat_clusters, FAT_SET );
+
+		}
+
+	}
+
+	//  ok space is definitly ready for us to write to...
+	current_cluster = fprivdata->file_cluster;
+
+	unsigned int data_written = 0;
+
+	while ( data_written < size ) 
+	{
+
+		//  if we have more then a clusters worth of data to write...
+		int sizewritten = 0;
+
+		if (  ( size - data_written ) >= ( g_Vmc_Image[ f->unit ].cluster_size - fprivdata->cluster_offset )  ) 
+		{
+
+			if ( fprivdata->cluster_offset == 0 ) 
+			{
+
+				DEBUGPRINT ( 4, "vmcfs: Writing to cluster %u\n", current_cluster );
+
+				writeCluster ( fprivdata->gendata.fd, (  ( unsigned char* ) buffer ) + data_written, current_cluster + fprivdata->gendata.first_allocatable );
+				sizewritten = g_Vmc_Image[ f->unit ].cluster_size;
+
+			}
+			else
+			{
+
+				DEBUGPRINT ( 4, "vmcfs: Writing to cluster %u at offset %u for length %u\n", current_cluster, fprivdata->cluster_offset, g_Vmc_Image[ f->unit ].cluster_size - fprivdata->cluster_offset );
+
+				writeClusterPart ( fprivdata->gendata.fd, (  ( unsigned char* ) buffer ) + data_written, current_cluster + fprivdata->gendata.first_allocatable, fprivdata->cluster_offset, g_Vmc_Image[ f->unit ].cluster_size - fprivdata->cluster_offset );
+				sizewritten = g_Vmc_Image[ f->unit ].cluster_size - fprivdata->cluster_offset;
+
+			}
+
+		}
+		else
+		{
+
+			DEBUGPRINT ( 4, "vmcfs: Writing to cluster %u at offset %u for length %u\n", current_cluster, fprivdata->cluster_offset, size - data_written );
+
+			writeClusterPart ( fprivdata->gendata.fd, (  ( unsigned char* ) buffer ) + data_written, current_cluster + fprivdata->gendata.first_allocatable, fprivdata->cluster_offset, size - data_written );
+			sizewritten = size - data_written;
+
+		}
+
+		DEBUGPRINT ( 5, "vmcfs: Wrote %i bytes\n", sizewritten );
+
+		data_written              += sizewritten;
+		fprivdata->file_position  += sizewritten;
+		fprivdata->cluster_offset += sizewritten;
+
+		if ( fprivdata->cluster_offset == g_Vmc_Image[ f->unit ].cluster_size ) 
+		{
+
+			DEBUGPRINT ( 7, "vmcfs: Moving onto next cluster\n" );
+
+			current_cluster = getFatEntry ( fprivdata->gendata.fd, current_cluster, fprivdata->gendata.indir_fat_clusters, FAT_VALUE );
+			fprivdata->cluster_offset = 0;
+
+		}
+
+	}
+
+	struct direntry dirent;
+
+	if ( f->mode & O_TRUNC || f->mode & O_APPEND )
+	{
+
+		DEBUGPRINT ( 8, "vmcfs: Write with O_TRUNC.\n");
+
+		fprivdata->file_length = fprivdata->file_position;
+
+	}
+
+	readPage ( fprivdata->gendata.fd, ( unsigned char* ) &dirent, fprivdata->file_dirpage );
+
+	// Update file length
+	dirent.length = fprivdata->file_length;
+
+	// Update timestamp
+	getPs2Time ( &dirent.modified );
+
+	// Write this changes
+	writePage ( fprivdata->gendata.fd, ( unsigned char* ) &dirent, fprivdata->file_dirpage );
+
+	fprivdata->file_cluster = current_cluster;
+
+	PROF_END ( vmc_writeProf ) 
+
+	return data_written;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Seek a file previously open with fileXioOpen("vmc...
+//----------------------------------------------------------------------------
+int Vmc_Lseek ( iop_file_t* f, unsigned long offset, int whence ) 
+{
+
+	if ( !g_Vmc_Initialized ) 
+		return VMCFS_ERR_INITIALIZED;
+
+	DEBUGPRINT ( 1, "vmcfs: Seek\n" );
+
+	if ( g_Vmc_Image[ f->unit ].fd < 0 ) 
+		return VMCFS_ERR_NOT_MOUNT;
+
+	if ( g_Vmc_Image[ f->unit ].formated == FALSE ) 
+		return VMCFS_ERR_NOT_FORMATED;
+
+	PROF_START ( vmc_lseekProf ) 
+
+	struct file_privdata* fprivdata = f->privdata;
+
+	switch ( whence ) {
+
+		case SEEK_SET:
+			fprivdata->file_position = offset;
+			break;
+
+		case SEEK_CUR:
+			fprivdata->file_position += offset;
+			break;
+
+		case SEEK_END:
+			fprivdata->file_position = fprivdata->file_length + offset;
+			break;
+
+		default:
+			return -1;
+
+	}
+
+	//  Return an error if we are past the end of the file
+	if ( fprivdata->file_position > fprivdata->file_length ) 
+		return -1;
+
+	//  Now we need to position cluster offsets to be correct
+	fprivdata->file_cluster = fprivdata->file_startcluster;
+
+	int i = 0;
+	int chainclusternum = fprivdata->file_position  /  g_Vmc_Image[ f->unit ].cluster_size;
+
+	for ( i = 0; i < chainclusternum; i++ ) 
+		fprivdata->file_cluster = getFatEntry ( fprivdata->gendata.fd, fprivdata->file_cluster, fprivdata->gendata.indir_fat_clusters, FAT_VALUE );
+
+	fprivdata->cluster_offset = fprivdata->file_position %g_Vmc_Image[ f->unit ].cluster_size;
+
+	PROF_END ( vmc_lseekProf ) 
+
+	return fprivdata->file_position;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Control command.
+// IOCTL_VMCFS_RECOVER :  Recover an object marked as none existing. ( data must be a valid path to an object in vmc file ) 
+//----------------------------------------------------------------------------
+int Vmc_Ioctl ( iop_file_t* f, unsigned long request, void* data ) 
+{
+
+	if ( !g_Vmc_Initialized ) 
+		return VMCFS_ERR_INITIALIZED;
+
+	switch ( request ) 
+	{
+
+		case IOCTL_VMCFS_RECOVER:
+			{
+
+				Vmc_Recover ( f->unit, ( char* ) data );
+
+			}
+			break;
+
+		default:
+
+			DEBUGPRINT ( 1, "vmcfs: Unrecognized ioctl command %ld\n", request );
+			break;
+
+	}
+
+	return VMCFS_ERR_NO;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Remove an object from vmc image. Object can be a file or a folder.
+//----------------------------------------------------------------------------
+int Vmc_Remove ( iop_file_t* f, const char* path ) 
+{
+
+	if ( !g_Vmc_Initialized ) 
+		return VMCFS_ERR_INITIALIZED;
+
+	DEBUGPRINT ( 1, "vmcfs: remove %s\n", path );
+
+	if ( g_Vmc_Image[ f->unit ].fd < 0 ) 
+		return VMCFS_ERR_NOT_MOUNT;
+
+	if ( g_Vmc_Image[ f->unit ].formated == FALSE ) 
+		return VMCFS_ERR_NOT_FORMATED;
+
+	PROF_START ( vmc_removeProf ) 
+
+	struct direntry     dirent;
+	struct gen_privdata gendata;
+
+	gendata.fd                = g_Vmc_Image[ f->unit ].fd;
+	gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
+	gendata.last_allocatable  = g_Vmc_Image[ f->unit ].header.last_allocatable;
+
+	memcpy ( gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
+
+	unsigned int dirent_cluster = getDirentryFromPath ( &dirent, path, &gendata, f->unit );
+
+	if ( dirent_cluster == ROOT_CLUSTER )
+	{
+
+		DEBUGPRINT ( 2, "vmcfs: remove failed. Root directory is protected.\n" );
+
+		PROF_END ( vmc_removeProf ) 
+
+		return -1;
+
+	}
+	else if ( dirent_cluster == NOFOUND_CLUSTER )
+	{
+
+		DEBUGPRINT ( 2, "vmcfs: remove failed. %s not found.\n", path );
+
+		PROF_END ( vmc_removeProf ) 
+
+		return -1;
+
+	}
+
+	if ( dirent.mode & DF_FILE ) 
+	{
+
+		removeObject ( &gendata, dirent_cluster, &dirent, f->unit );
+
+		DEBUGPRINT ( 2, "vmcfs: file %s removed.\n", path );
+
+	}
+	else
+	{
+
+		DEBUGPRINT ( 2, "vmcfs: remove failed. %s is not a valid file.\n", path );
+
+		PROF_END ( vmc_removeProf ) 
+
+		return -1;
+
+	}
+
+	//  ioman Bug Fix. mkdir is call after remove fonction
+	g_Vmc_Remove_Flag = TRUE;
+	
+	PROF_END ( vmc_removeProf ) 
+
+	return 0;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Create a new folder into vmc image.
+//----------------------------------------------------------------------------
+int Vmc_Mkdir ( iop_file_t* f, const char* path1, int mode ) 
+{
+
+	if ( !g_Vmc_Initialized ) 
+		return VMCFS_ERR_INITIALIZED;
+
+	//  ioman bug fix. mkdir is call after remove fonction
+	if ( g_Vmc_Remove_Flag == TRUE ) 
+	{
+
+		g_Vmc_Remove_Flag = FALSE;
+		printf ( "vmcfs: mkdir stopped. Ioman bug fix.\n" );
+		return 0;
+
+	} 
+
+	DEBUGPRINT ( 1, "vmcfs: mkdir %s\n", path1 );
+
+	if ( g_Vmc_Image[ f->unit ].fd < 0 ) 
+		return VMCFS_ERR_NOT_MOUNT;
+
+	if ( g_Vmc_Image[ f->unit ].formated == FALSE ) 
+		return VMCFS_ERR_NOT_FORMATED;
+
+	PROF_START ( vmc_mkdirProf ) 
+
+	struct direntry     dirent;
+	struct gen_privdata gendata;
+
+	gendata.fd                = g_Vmc_Image[ f->unit ].fd;
+	gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
+	gendata.last_allocatable  = g_Vmc_Image[ f->unit ].header.last_allocatable;
+
+	memcpy ( gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
+
+	memset ( &dirent, 0, sizeof ( dirent )  );
+
+	// Make a local copy of path.
+	char* path = malloc ( strlen ( path1 ) + 1 );
+	memcpy ( path, path1, strlen ( path1 ) + 1 ); 
+
+	if ( path[ strlen ( path ) - 1 ] == '/' ) 
+		path[ strlen ( path ) - 1 ]= '\0';
+
+	unsigned int dirent_cluster = getDirentryFromPath ( &dirent, path, &gendata, f->unit );
+
+	if ( dirent_cluster == ROOT_CLUSTER )
+	{
+
+		DEBUGPRINT ( 2, "vmcfs: mkdir failed. Root directory is protected.\n" );
+			
+		free( path );
+
+		PROF_END ( vmc_mkdirProf ) 
+
+		return -1;	//  File not found, could not be opened.
+
+	}
+	else if ( dirent_cluster == NOFOUND_CLUSTER )
+	{
+
+		struct direntry     new_dirent;
+		unsigned int        new_dirent_cluster = 0;
+		struct direntry     parent_dirent;
+		unsigned int        parent_cluster = 0;
+		struct gen_privdata parent_gendata;
+
+		parent_gendata.fd                = g_Vmc_Image[ f->unit ].fd;
+		parent_gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
+		parent_gendata.last_allocatable  = g_Vmc_Image[ f->unit ].header.last_allocatable;
+
+		memcpy ( parent_gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
+
+		// Find name of directory, and name of parent
+		char* newdir = strrchr ( path, '/' );
+
+		newdir[ 0 ] = '\0';
+		newdir++;
+
+		DEBUGPRINT ( 2, "vmcfs: Creating folder %s in parent folder %s\n", newdir, (path[0] == '\0') ? "Root" : path );
+
+		memset ( &new_dirent, 0, sizeof ( new_dirent )  );
+
+		//  fill new direntry
+		new_dirent.mode = DF_EXISTS | DF_0400 | DF_DIRECTORY | DF_READ | DF_WRITE | DF_EXECUTE; //  0x8427
+		strcpy ( new_dirent.name, newdir );
+		getPs2Time ( &new_dirent.created );
+		getPs2Time ( &new_dirent.modified );
+
+		if ( path[ 0 ] == '\0' ) 
+		{
+
+			//  get the root directories entry
+			parent_cluster = getDirentryFromPath ( &parent_dirent, ".", &parent_gendata, f->unit );
+
+		}
+		else
+		{
+
+			//  get the folder entry for the parent
+			parent_cluster = getDirentryFromPath ( &parent_dirent, path, &parent_gendata, f->unit );
+
+		}
+
+		if ( parent_cluster == NOFOUND_CLUSTER )
+		{
+
+			DEBUGPRINT ( 3, "vmcfs: Unable to find parent directory\n" );
+
+			free ( path );
+
+			PROF_END ( vmc_mkdirProf ) 
+
+			return -1;
+
+		}
+
+		DEBUGPRINT ( 3, "vmcfs: Parent Information.\n" );
+		DEBUGPRINT ( 3, "vmcfs: parent_cluster  = %u\n", parent_cluster );
+		DEBUGPRINT ( 3, "vmcfs: dir_cluster    = %u\n", parent_dirent.cluster );
+		DEBUGPRINT ( 3, "vmcfs: dirent.name    = %s\n", parent_dirent.name );
+		DEBUGPRINT ( 3, "vmcfs: dirent.length  = %u\n", parent_dirent.length );
+		DEBUGPRINT ( 3, "vmcfs: dirent.mode    = %X\n", parent_dirent.mode );
+		DEBUGPRINT ( 3, "vmcfs: dirent_page    = %i\n", parent_gendata.dirent_page );
+
+		new_dirent_cluster = addObject ( &parent_gendata, parent_cluster, &parent_dirent, &new_dirent, f->unit );
+
+		if ( new_dirent_cluster == ERROR_CLUSTER )
+		{
+
+			DEBUGPRINT ( 2, "vmcfs: mkdir failed on %s\n", path );
+
+			free ( path );
+
+			PROF_END ( vmc_mkdirProf ) 
+
+			return -1;
+
+		}
+
+	}
+	else // directory allready exist, so test DF_EXISTS flag
+	{
+
+		if ( dirent.mode & DF_EXISTS ) 
+		{
+
+			DEBUGPRINT ( 2, "vmcfs: mkdir failed on %s. Directory allready exist.\n", path1 );
+
+			free( path );
+
+			PROF_END ( vmc_mkdirProf ) 
+
+			return -1;
+
+		}
+		else
+		{
+
+			DEBUGPRINT ( 8, "vmcfs: mkdir directory %s allready exist but is hidden. Changing attributs.\n", path1 );
+
+			DEBUGPRINT ( 8, "vmcfs: Following fat table cluster %u\n", dirent.cluster );
+
+			unsigned int pseudo_entry_cluster = getFatEntry ( gendata.fd, dirent.cluster, gendata.indir_fat_clusters, FAT_VALUE );
+
+			DEBUGPRINT ( 8, "vmcfs: Changing cluster mask of fat table cluster %u.\n", pseudo_entry_cluster );
+
+			// change cluster mask of the direntry
+			setFatEntry ( gendata.fd, dirent.cluster, pseudo_entry_cluster, gendata.indir_fat_clusters, FAT_SET );
+
+			DEBUGPRINT ( 8, "vmcfs: Changing direntry %s attributs.\n", path1 );
+
+			//  Update time stamp, and set dirent.mode to exist flag
+			dirent.mode	= dirent.mode | DF_EXISTS;
+			getPs2Time ( &dirent.created );
+			getPs2Time ( &dirent.modified );
+			writePage ( gendata.fd, ( unsigned char* ) &dirent, ( dirent_cluster + gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster + gendata.dirent_page );
+
+			DEBUGPRINT ( 8, "vmcfs: Restoring EOF cluster at %u.\n", pseudo_entry_cluster );
+
+			setFatEntry ( gendata.fd, pseudo_entry_cluster, EOF_CLUSTER, gendata.indir_fat_clusters, FAT_SET );
+
+			struct direntry pseudo_entries;
+
+			DEBUGPRINT ( 8, "vmcfs: Updating pseudo entries time stamps at cluster %u / page %u.\n", dirent.cluster + gendata.first_allocatable, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster );
+
+			//  Update time stamp of '.' entry
+			readPage ( gendata.fd, ( unsigned char* ) &pseudo_entries, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster );
+			getPs2Time ( &pseudo_entries.created );
+			getPs2Time ( &pseudo_entries.modified );
+			writePage ( gendata.fd, ( unsigned char* ) &pseudo_entries, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster );
+
+			DEBUGPRINT ( 8, "vmcfs: Updating pseudo entries time stamps at cluster %u / page %u.\n", dirent.cluster + gendata.first_allocatable, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster + 1 );
+
+			//  Update time stamp of '..' entry
+			readPage ( gendata.fd, ( unsigned char* ) &pseudo_entries, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster + 1 );
+			getPs2Time ( &pseudo_entries.created );
+			getPs2Time ( &pseudo_entries.modified );
+			writePage ( gendata.fd, ( unsigned char* ) &pseudo_entries, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster + 1 );
+
+			free( path );
+
+		}
+
+	}
+	
+	DEBUGPRINT ( 3, "vmcfs: Directory %s created.\n", path1 );
+
+	PROF_END ( vmc_mkdirProf ) 
+
+	return 0;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Remove a folder from vmc image.
+//----------------------------------------------------------------------------
+int Vmc_Rmdir ( iop_file_t* f, const char* path1 ) 
+{
+
+	if ( !g_Vmc_Initialized ) 
+		return VMCFS_ERR_INITIALIZED;
+
+	DEBUGPRINT ( 1, "vmcfs: rmdir %s\n", path1 );
+
+	if ( g_Vmc_Image[ f->unit ].fd < 0 ) 
+		return VMCFS_ERR_NOT_MOUNT;
+
+	if ( g_Vmc_Image[ f->unit ].formated == FALSE ) 
+		return VMCFS_ERR_NOT_FORMATED;
+
+	PROF_START ( vmc_rmdirProf ) 
+
+	struct direntry     dirent;
+	struct gen_privdata folder_gendata;
+
+	folder_gendata.fd                = g_Vmc_Image[ f->unit ].fd;
+	folder_gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
+	folder_gendata.last_allocatable  = g_Vmc_Image[ f->unit ].header.last_allocatable;
+
+	memcpy ( folder_gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
+
+	// Make a local copy of path
+	char* path = malloc ( strlen ( path1 ) + 1 );
+	memcpy ( path, path1, strlen ( path1 ) + 1 );
+
+	if ( path[ strlen ( path ) - 1 ] == '/' ) 
+		path[ strlen ( path ) - 1 ]= '\0';
+
+	unsigned int dirent_cluster = getDirentryFromPath ( &dirent, path, &folder_gendata, f->unit );
+
+	if ( dirent_cluster == ROOT_CLUSTER )
+	{
+
+		DEBUGPRINT ( 2, "vmcfs: rmdir failed. Root directory is protected.\n" );
+
+		free( path );
+
+		PROF_END ( vmc_rmdirProf ) 
+
+		return -1;
+
+	}
+	else if ( dirent_cluster == NOFOUND_CLUSTER )
+	{
+
+		DEBUGPRINT ( 2, "vmcfs: rmdir failed. %s not found.\n", path1 );
+
+		free( path );
+
+		PROF_END ( vmc_rmdirProf ) 
+
+		return -1;
+
+	}
+
+	if ( ! ( dirent.mode & DF_EXISTS ) )
+	{
+
+		DEBUGPRINT ( 2, "vmcfs: rmdir failed. %s is allready removed.\n", path1 );
+
+		free( path );
+
+		PROF_END ( vmc_rmdirProf ) 
+
+		return -1;
+
+
+	}
+
+	if ( dirent.mode & DF_DIRECTORY ) 
+	{
+
+		// Find name of directory, and name of parent
+		char* foldername = strrchr ( path, '/' );
+
+		foldername[ 0 ]= '\0';
+		foldername++;
+
+		struct direntry     child;
+		unsigned int        child_cluster;
+		struct gen_privdata child_gendata;
+		char*               child_path;
+		
+		child_path = ( char* )malloc ( MAX_PATH );
+		memset ( child_path, 0, MAX_PATH );
+
+		int                 i              = 0;
+		int                 dir_number     = 0;
+		unsigned int        search_cluster = dirent.cluster;
+
+		child_gendata.fd                = g_Vmc_Image[ f->unit ].fd;
+		child_gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
+		child_gendata.last_allocatable  = g_Vmc_Image[ f->unit ].header.last_allocatable;
+
+		memcpy ( child_gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
+
+		// remove file contained into the directory
+		for ( i = 0; i < dirent.length; i++ )
+		{
+
+			// read in the next directory entry
+			readPage ( folder_gendata.fd, ( unsigned char* ) &child, ( search_cluster + folder_gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster + dir_number );
+			
+			// if child exist, remove it. But don't touch to pseudo entries.
+			if ( child.mode & DF_EXISTS && i >= 2 )
+			{
+
+				sprintf( child_path, "%s/%s/%s", path, dirent.name, child.name );
+
+				child_cluster = getDirentryFromPath ( &child, child_path, &child_gendata, f->unit );
+
+				if ( child_cluster != NOFOUND_CLUSTER )
+				{
+
+					removeObject ( &child_gendata, child_cluster, &child, f->unit );
+
+				}
+
+			}
+
+			if ( dir_number == 1 ) 
+			{
+
+				dir_number  = 0;
+				search_cluster = getFatEntry ( folder_gendata.fd, search_cluster, folder_gendata.indir_fat_clusters, FAT_VALUE );
+
+			}
+			else
+			{
+
+				dir_number = 1;
+
+			}
+
+		}
+
+		// finaly, remove directory
+		removeObject ( &folder_gendata, dirent_cluster, &dirent, f->unit );
+
+		free( path );
+		free( child_path );
+
+	}
+	else
+	{
+
+		DEBUGPRINT ( 2, "vmcfs: rmdir failed. %s is not a valid directory.\n", path1 );
+
+		free( path );
+
+		PROF_END ( vmc_rmdirProf ) 
+
+		return -1;
+
+	}
+
+	DEBUGPRINT ( 3, "vmcfs: Directory %s removed.\n", path1 );
+
+	//  ioman Bug Fix. mkdir is call after remove fonction
+	g_Vmc_Remove_Flag = TRUE;
+	
+	PROF_END ( vmc_removeProf ) 
+
+	return 0;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Open a folder in vmc image.
+//----------------------------------------------------------------------------
+int Vmc_Dopen (  iop_file_t* f, const char* path ) 
+{
+
+	if ( !g_Vmc_Initialized ) 
+		return VMCFS_ERR_INITIALIZED;
+
+	DEBUGPRINT ( 1, "vmcfs: dopen %i %s\n", f->unit, path );
+
+	if ( g_Vmc_Image[ f->unit ].fd < 0 ) 
+		return VMCFS_ERR_NOT_MOUNT;
+
+	if ( g_Vmc_Image[ f->unit ].formated == FALSE ) 
+		return VMCFS_ERR_NOT_FORMATED;
+
+	PROF_START ( vmc_dopenProf ) 
+
+	struct direntry      dirent;
+	struct dir_privdata* fprivdata = malloc ( sizeof ( struct dir_privdata ) );
+
+	if ( fprivdata == NULL )
+		return -1;
+
+	f->privdata = fprivdata;
+
+	fprivdata->gendata.fd                = g_Vmc_Image[ f->unit ].fd;
+	fprivdata->gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
+
+	memcpy ( fprivdata->gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
+
+	unsigned int dirent_cluster = getDirentryFromPath ( &dirent, path, &( fprivdata->gendata ), f->unit );
+
+	if ( dirent_cluster == NOFOUND_CLUSTER )
+	{
+
+		DEBUGPRINT ( 2, "vmcfs: dopen failed. %s not found.\n", path );
+
+		free ( fprivdata ); //  Release the allocated memory
+
+		PROF_END ( vmc_dopenProf ) 
+
+		return -1; //  Folder not found, could not be opened.
+
+	}
+
+	if ( ! ( dirent.mode & DF_EXISTS ) )
+	{
+
+		DEBUGPRINT ( 2, "vmcfs: dopen failed. %s is hidden.\n", path );
+
+		free ( fprivdata ); //  Release the allocated memory
+
+		PROF_END ( vmc_dopenProf ) 
+
+		return -1; //  Folder not found, could not be opened.
+
+	}
+
+	fprivdata->dir_cluster = dirent.cluster;
+	fprivdata->dir_length  = dirent.length;
+	fprivdata->dir_number  = 0;
+
+	DEBUGPRINT ( 2, "vmcfs: Directory %s opened with length %u\n", path, fprivdata->dir_length );
+
+	PROF_END ( vmc_dopenProf ) 
+
+	return 1;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Close a folder in vmc image.
+//----------------------------------------------------------------------------
+int Vmc_Dclose (  iop_file_t* f ) 
+{
+
+	if ( !g_Vmc_Initialized ) 
+		return VMCFS_ERR_INITIALIZED;
+
+	DEBUGPRINT ( 1, "vmcfs: dclose %i\n", f->unit );
+
+	if (  ( f->unit == 2 ) || ( f->unit == 3 )  ) 
+		return 0; //  Close our fake device used only for ioctl commands
+
+	PROF_START ( vmc_dcloseProf ) 
+
+	struct dir_privdata * fprivdata = f->privdata;
+
+	free ( fprivdata );
+
+	PROF_END ( vmc_dcloseProf ) 
+
+	return 0;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Read the content of a folder in vmc image.
+//----------------------------------------------------------------------------
+int Vmc_Dread (  iop_file_t* f, iox_dirent_t *buffer ) 
+{
+
+	if ( !g_Vmc_Initialized ) 
+		return VMCFS_ERR_INITIALIZED;
+
+	DEBUGPRINT ( 1, "vmcfs: dread %i\n", f->unit );
+
+	if ( g_Vmc_Image[ f->unit ].fd < 0 ) 
+		return VMCFS_ERR_NOT_MOUNT;
+
+	if ( g_Vmc_Image[ f->unit ].formated == FALSE ) 
+		return VMCFS_ERR_NOT_FORMATED;
+
+	PROF_START ( vmc_dreadProf ) 
+
+	int                  next;
+	vmc_datetime         access_time;
+	struct direntry      dirent;
+	struct dir_privdata * fprivdata = f->privdata;
+	iox_dirent_t        * buf       = buffer;
+
+	memset ( buf, 0, sizeof ( iox_dirent_t )  );
+
+next_entry:
+
+	next = 0;
+
+	if ( fprivdata->dir_length == 0 ) 
+		return -1;
+
+	//  read in the next directory entry
+	readPage ( fprivdata->gendata.fd, ( unsigned char* ) &dirent, ( fprivdata->dir_cluster + fprivdata->gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster + fprivdata->dir_number );
+
+	DEBUGPRINT ( 4, "vmcfs: name: %s; cluster %u; length %u; mode 0x%02x\n", dirent.name, dirent.cluster, dirent.length, dirent.mode );
+
+	if ( dirent.mode & DF_EXISTS ) 
+	{
+	
+		buf->stat.mode = dirent.mode;
+		buf->stat.attr = dirent.attr;
+		buf->stat.size = dirent.length;
+
+		//  File created Time  /  Date
+		memcpy ( buf->stat.ctime, &dirent.created, sizeof ( vmc_datetime )  );
+
+		//  File Modification Time  /  Date
+		memcpy ( buf->stat.mtime, &dirent.modified, sizeof ( vmc_datetime )  );
+
+		//  Last File Access Time : now
+		getPs2Time ( &access_time );
+		memcpy ( buf->stat.atime, &access_time, sizeof ( vmc_datetime )  );
+
+		buf->stat.hisize = 0; //  No idea what hisize is?
+
+		strcpy ( buf->name, dirent.name );
+
+	}
+	else
+	{
+
+		next = 1;
+
+	}
+
+	fprivdata->dir_length--;
+	//  return 1 if there are more entries to read, otherwise return -1
+
+	if ( fprivdata->dir_number ) 
+	{
+
+		fprivdata->dir_number  = 0;
+		fprivdata->dir_cluster = getFatEntry ( fprivdata->gendata.fd, fprivdata->dir_cluster, fprivdata->gendata.indir_fat_clusters, FAT_VALUE );
+
+	}
+	else
+	{
+
+		fprivdata->dir_number = 1;
+
+	}
+	
+	if ( next == 1 ) 
+		goto next_entry;
+
+	PROF_END ( vmc_dreadProf ) 
+
+	return 1;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Get stats from an object in vmc image.
+//----------------------------------------------------------------------------
+int Vmc_Getstat ( iop_file_t* f, const char* path, iox_stat_t * stat ) 
+{
+
+	if ( !g_Vmc_Initialized ) 
+		return VMCFS_ERR_INITIALIZED;
+
+	DEBUGPRINT ( 1, "vmcfs: getstat %i %s\n", f->unit, path );
+
+	if ( g_Vmc_Image[ f->unit ].fd < 0 ) 
+		return VMCFS_ERR_NOT_MOUNT;
+
+	if ( g_Vmc_Image[ f->unit ].formated == FALSE ) 
+		return VMCFS_ERR_NOT_FORMATED;
+
+	PROF_START ( vmc_getstatProf ) 
+
+	struct direntry     dirent;
+	struct gen_privdata gendata;      
+	vmc_datetime        access_time;
+
+	gendata.fd                = g_Vmc_Image[ f->unit ].fd;
+	gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
+	gendata.last_allocatable  = g_Vmc_Image[ f->unit ].header.last_allocatable;
+
+	memcpy ( gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
+
+	unsigned int dirent_cluster = getDirentryFromPath ( &dirent, path, &gendata, f->unit );
+
+	if ( dirent_cluster == NOFOUND_CLUSTER )
+	{
+
+		DEBUGPRINT ( 2, "vmcfs: getstat failed. %s not found.\n", path );
+
+		PROF_END ( vmc_getstatProf ) 
+
+		return -1;
+
+	}
+
+	stat->mode = dirent.mode;
+	stat->attr = dirent.attr;
+	stat->size = dirent.length;
+
+	//  File created Time  /  Date
+	memcpy ( stat->ctime, &dirent.created, sizeof ( vmc_datetime )  );
+
+	//  File Modification Time  /  Date
+	memcpy ( stat->mtime, &dirent.modified, sizeof ( vmc_datetime )  );
+
+	//  Last File Access Time : now
+	getPs2Time ( &access_time );
+	memcpy ( stat->atime, &access_time, sizeof ( vmc_datetime )  );
+
+	stat->hisize = 0; //  No idea what hisize is?
+
+	PROF_END ( vmc_getstatProf ) 
+
+	return 0;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Put stats to an object in vmc image.
+//----------------------------------------------------------------------------
+int Vmc_Chstat ( iop_file_t* f, const char* path, iox_stat_t * stat, unsigned int unknown ) 
+{
+
+	if ( !g_Vmc_Initialized ) 
+		return VMCFS_ERR_INITIALIZED;
+
+	DEBUGPRINT ( 1, "vmcfs: chstat %i %s\n", f->unit, path );
+
+	if ( g_Vmc_Image[ f->unit ].fd < 0 ) 
+		return VMCFS_ERR_NOT_MOUNT;
+
+	if ( g_Vmc_Image[ f->unit ].formated == FALSE ) 
+		return VMCFS_ERR_NOT_FORMATED;
+
+	PROF_START ( vmc_chstatProf ) 
+
+	struct direntry     dirent;
+	struct gen_privdata gendata;
+
+	gendata.fd                = g_Vmc_Image[ f->unit ].fd;
+	gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
+	gendata.last_allocatable  = g_Vmc_Image[ f->unit ].header.last_allocatable;
+
+	memcpy ( gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
+
+	unsigned int dirent_cluster = getDirentryFromPath ( &dirent, path, &gendata, f->unit );
+
+	if ( dirent_cluster == NOFOUND_CLUSTER )
+	{
+
+		DEBUGPRINT ( 2, "vmcfs: chstat failed. %s not found.\n", path );
+
+		PROF_END ( vmc_chstatProf ) 
+
+		return -1;
+
+	}
+
+	dirent.mode	  = stat->mode;
+	dirent.attr	  = stat->attr;
+	dirent.length	 = stat->size;
+
+	//  File created Time  /  Date
+	memcpy ( &dirent.created, stat->ctime, sizeof ( vmc_datetime )  );
+
+	//  File Modification Time  /  Date
+	memcpy ( &dirent.created, stat->mtime, sizeof ( vmc_datetime )  );
+
+	//  Write this change
+	writePage ( gendata.fd, ( unsigned char* ) &dirent, ( dirent_cluster + gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster + gendata.dirent_page );
+
+	PROF_END ( vmc_chstatProf ) 
+
+	return 0;
+
+}
+
+
+// Start of extended io fonctions.
+
+
+//----------------------------------------------------------------------------
+// Rename an object into a vmc file.
+//----------------------------------------------------------------------------
+int Vmc_Rename ( iop_file_t* f, const char* path, const char* new_name )
+{
+	
+	if ( !g_Vmc_Initialized ) 
+		return VMCFS_ERR_INITIALIZED;
+
+	DEBUGPRINT ( 1, "vmcfs: rename %s\n", path );
+
+	if ( g_Vmc_Image[ f->unit ].fd < 0 ) 
+		return VMCFS_ERR_NOT_MOUNT;
+
+	if ( g_Vmc_Image[ f->unit ].formated == FALSE ) 
+		return VMCFS_ERR_NOT_FORMATED;
+
+	PROF_START ( vmc_renameProf ) 
+
+	struct direntry     dirent;
+	struct gen_privdata gendata;
+
+	gendata.fd                = g_Vmc_Image[ f->unit ].fd;
+	gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
+	gendata.last_allocatable  = g_Vmc_Image[ f->unit ].header.last_allocatable;
+
+	memcpy ( gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
+
+	unsigned int dirent_cluster = getDirentryFromPath ( &dirent, path, &gendata, f->unit );
+
+	if ( dirent_cluster == ROOT_CLUSTER )
+	{
+
+		DEBUGPRINT ( 2, "vmcfs: rename failed. Root directory is protected.\n" );
+
+		PROF_END ( vmc_renameProf ) 
+
+		return -1;
+
+	}
+	else if ( dirent_cluster == NOFOUND_CLUSTER )
+	{
+
+		DEBUGPRINT ( 2, "vmcfs: rename failed. %s not found.\n", path );
+
+		PROF_END ( vmc_renameProf ) 
+
+		return -1;
+
+	}
+
+	//  Change the name of the object
+	strcpy ( dirent.name, new_name );
+
+	// Update timestamp
+	getPs2Time ( &dirent.modified );
+
+	//  Write this change
+	writePage ( gendata.fd, ( unsigned char* ) &dirent, ( dirent_cluster * g_Vmc_Image[ f->unit ].header.pages_per_cluster ) + gendata.dirent_page );
+
+	DEBUGPRINT ( 2, "vmcfs: Object %s renamed to %s\n", path, new_name );
+
+	PROF_END ( vmc_renameProf ) 
+
+	return 0;
+	
+}
+
+
+//----------------------------------------------------------------------------
+// Not Implemented for the moment.
+//----------------------------------------------------------------------------
+int Vmc_Chdir ( iop_file_t* f, const char* path )
+{
+	
+	return VMCFS_ERR_IMPLEMENTED;
+	
+}
+
+
+//----------------------------------------------------------------------------
+// Not Implemented for the moment.
+//----------------------------------------------------------------------------
+int Vmc_Sync ( iop_file_t* f, const char* device, int flag )
+{
+	
+	return VMCFS_ERR_IMPLEMENTED;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Mount a vmc file with fileXioMount(... call.
+//----------------------------------------------------------------------------
+int Vmc_Mount ( iop_file_t* f, const char* fsname, const char* devname, int flag, void *arg, unsigned int arg_len )
+{
+	int errcode;
+
+	DEBUGPRINT ( 2, "vmcfs: Mount %s at mount point: %d\n", devname, f->unit );
+
+	if ( g_Vmc_Image[ f->unit ].fd >= 0 )
+		return VMCFS_ERR_MOUNT_BUSY;
+
+	g_Vmc_Image[ f->unit ].fd = open ( devname, O_RDWR, 0x666 );
+
+	if ( g_Vmc_Image[ f->unit ].fd < 0 )
+	{
+			DEBUGPRINT ( 1, "vmcfs: Error opening vmc file %s\n", devname );
+			DEBUGPRINT ( 1, "vmcfs: open error code: %d\n", g_Vmc_Image[ f->unit ].fd );
+
+			return VMCFS_ERR_VMC_OPEN;
+	}
+
+	//  read informations from the superblock
+	int r = read ( g_Vmc_Image[ f->unit ].fd, &g_Vmc_Image[ f->unit ].header, sizeof ( struct superblock )  );
+
+	if ( r != sizeof ( struct superblock )  )
+	{
+		DEBUGPRINT ( 1, "vmcfs: Error reading vmc file %s\n", devname );
+		DEBUGPRINT ( 1, "vmcfs: fd: %d, error code:%d\n", g_Vmc_Image[ f->unit ].fd, r );
+
+		errcode = VMCFS_ERR_VMC_READ;
+
+mountAbort:
+		close ( g_Vmc_Image[ f->unit ].fd );
+		g_Vmc_Image[ f->unit ].fd = VMCFS_ERR_NOT_MOUNT;
+		return errcode;
+	}
+
+	g_Vmc_Image[ f->unit ].card_size = lseek ( g_Vmc_Image[ f->unit ].fd, 0, SEEK_END );
+	lseek ( g_Vmc_Image[ f->unit ].fd, 0, SEEK_SET );
+
+	if(		g_Vmc_Image[ f->unit ].header.magic[  0 ] != 'S'
+		||	g_Vmc_Image[ f->unit ].header.magic[  1 ] != 'o'
+		||	g_Vmc_Image[ f->unit ].header.magic[  2 ] != 'n'
+		||	g_Vmc_Image[ f->unit ].header.magic[  3 ] != 'y'
+		||	g_Vmc_Image[ f->unit ].header.magic[  4 ] != ' '
+		||	g_Vmc_Image[ f->unit ].header.magic[  5 ] != 'P'
+		||	g_Vmc_Image[ f->unit ].header.magic[  6 ] != 'S'
+		||	g_Vmc_Image[ f->unit ].header.magic[  7 ] != '2'
+		||	g_Vmc_Image[ f->unit ].header.magic[  8 ] != ' '
+		||	g_Vmc_Image[ f->unit ].header.magic[  9 ] != 'M'
+		||	g_Vmc_Image[ f->unit ].header.magic[ 10 ] != 'e'
+		||	g_Vmc_Image[ f->unit ].header.magic[ 11 ] != 'm'
+		||	g_Vmc_Image[ f->unit ].header.magic[ 12 ] != 'o'
+		||	g_Vmc_Image[ f->unit ].header.magic[ 13 ] != 'r'
+		||	g_Vmc_Image[ f->unit ].header.magic[ 14 ] != 'y'
+		||	g_Vmc_Image[ f->unit ].header.magic[ 15 ] != ' '
+		||	g_Vmc_Image[ f->unit ].header.magic[ 16 ] != 'C'
+		||	g_Vmc_Image[ f->unit ].header.magic[ 17 ] != 'a'
+		||	g_Vmc_Image[ f->unit ].header.magic[ 18 ] != 'r'
+		||	g_Vmc_Image[ f->unit ].header.magic[ 19 ] != 'd'
+		||	g_Vmc_Image[ f->unit ].header.magic[ 20 ] != ' '
+		||	g_Vmc_Image[ f->unit ].header.magic[ 21 ] != 'F'
+		||	g_Vmc_Image[ f->unit ].header.magic[ 22 ] != 'o'
+		||	g_Vmc_Image[ f->unit ].header.magic[ 23 ] != 'r'
+		||	g_Vmc_Image[ f->unit ].header.magic[ 24 ] != 'm'
+		||	g_Vmc_Image[ f->unit ].header.magic[ 25 ] != 'a'
+		||	g_Vmc_Image[ f->unit ].header.magic[ 26 ] != 't'
+		)
+	{
+		//  Card is not formated
+		DEBUGPRINT ( 1, "vmcfs: Warning vmc file %s is not formated\n", devname );
+		if ( !setDefaultSpec ( f->unit )  ) 
+		{
+			//  Card size error
+			DEBUGPRINT ( 1, "vmcfs: Error size of vmc file %s is incompatible\n", devname );
+
+			errcode = VMCFS_ERR_VMC_SIZE;
+			goto mountAbort;
+		}
+		g_Vmc_Image[ f->unit ].formated = FALSE;
+	}else{
+		g_Vmc_Image[ f->unit ].formated = TRUE;
+
+		DEBUGPRINT ( 4, "vmcfs: SuperBlock readed from vmc file %s.\n", devname );
+
+		DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: magic[40]             : %s\n"   , g_Vmc_Image[ f->unit ].header.magic                  );
+		DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: page_size             : 0x%02x\n", g_Vmc_Image[ f->unit ].header.page_size              );
+		DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: pages_per_cluster     : 0x%02x\n", g_Vmc_Image[ f->unit ].header.pages_per_cluster      );
+		DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: pages_per_block       : 0x%02x\n", g_Vmc_Image[ f->unit ].header.pages_per_block        );
+		DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: clusters_per_card     : 0x%02x\n", g_Vmc_Image[ f->unit ].header.clusters_per_card      );
+		DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: first_allocatable     : 0x%02x\n", g_Vmc_Image[ f->unit ].header.first_allocatable      );
+		DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: last_allocatable      : 0x%02x\n", g_Vmc_Image[ f->unit ].header.last_allocatable       );
+		DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: root_cluster          : 0x%02x\n", g_Vmc_Image[ f->unit ].header.root_cluster           );
+		DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: backup_block1         : 0x%02x\n", g_Vmc_Image[ f->unit ].header.backup_block1          );
+		DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: backup_block2         : 0x%02x\n", g_Vmc_Image[ f->unit ].header.backup_block2          );
+		for ( r = 0; g_Vmc_Image[ f->unit ].header.indir_fat_clusters[ r ]!= 0; r++ ) 
+			DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: indir_fat_clusters[%d] : 0x%02x\n", r, g_Vmc_Image[ f->unit ].header.indir_fat_clusters[ r ]);
+		DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: mc_type               : 0x%02x\n", g_Vmc_Image[ f->unit ].header.mc_type                );
+		DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: mc_flag               : 0x%02x\n", g_Vmc_Image[ f->unit ].header.mc_flag                );
+
+		if ( g_Vmc_Image[ f->unit ].header.mc_type != PS2_MEMORYCARD )
+		{
+			//  Card is not a PS2 one
+			DEBUGPRINT ( 1, "vmcfs: Error vmc file %s is not a valid PS2 image\n", devname );
+
+			errcode = VMCFS_ERR_CARD_TYPE;
+			goto mountAbort;
+		}
+
+		//Reaching this point means we have a valid PS2 image
+		DEBUGPRINT ( 4, "vmcfs: Image file Info: Vmc card type         : %s MemoryCard.\n", ( g_Vmc_Image[ f->unit ].header.mc_type == PSX_MEMORYCARD ? "PSX" : ( g_Vmc_Image[ f->unit ].header.mc_type == PS2_MEMORYCARD ? "PS2" : "PDA" )  )  );
+
+		g_Vmc_Image[ f->unit ].total_pages       = g_Vmc_Image[ f->unit ].header.pages_per_cluster * g_Vmc_Image[ f->unit ].header.clusters_per_card;
+		g_Vmc_Image[ f->unit ].cluster_size      = g_Vmc_Image[ f->unit ].header.page_size * g_Vmc_Image[ f->unit ].header.pages_per_cluster;
+		g_Vmc_Image[ f->unit ].erase_byte        = ( g_Vmc_Image[ f->unit ].header.mc_flag & 0x10 ) ? 0x0 : 0xFF;
+		g_Vmc_Image[ f->unit ].last_idc          = EOF_CLUSTER;
+		g_Vmc_Image[ f->unit ].last_cluster      = EOF_CLUSTER;
+		g_Vmc_Image[ f->unit ].last_free_cluster = g_Vmc_Image[ f->unit ].header.first_allocatable;
+
+		memset ( &g_Vmc_Image[ f->unit ].indirect_cluster, g_Vmc_Image[ f->unit ].erase_byte, MAX_CLUSTER_SIZE );
+		memset ( &g_Vmc_Image[ f->unit ].fat_cluster, g_Vmc_Image[ f->unit ].erase_byte, MAX_CLUSTER_SIZE );
+
+		if ( g_Vmc_Image[ f->unit ].card_size == (  ( g_Vmc_Image[ f->unit ].header.page_size + 0x10 ) * g_Vmc_Image[ f->unit ].total_pages )  ) 
+		{
+			g_Vmc_Image[ f->unit ].ecc_flag = TRUE;
+		}
+		else if ( g_Vmc_Image[ f->unit ].card_size == ( g_Vmc_Image[ f->unit ].header.page_size * g_Vmc_Image[ f->unit ].total_pages )  ) 
+		{
+			g_Vmc_Image[ f->unit ].ecc_flag = FALSE;
+		}
+		else
+		{
+			//  Card size error
+			DEBUGPRINT ( 1, "vmcfs: Error size of vmc file %s is incompatible\n", devname );
+			errcode = VMCFS_ERR_VMC_SIZE;
+			goto mountAbort;
+		}
+
+		DEBUGPRINT ( 4, "vmcfs: Image file Info: Number of pages       : %d\n", g_Vmc_Image[ f->unit ].total_pages );
+		DEBUGPRINT ( 4, "vmcfs: Image file Info: Size of a cluster     : %d bytes\n", g_Vmc_Image[ f->unit ].cluster_size );
+		DEBUGPRINT ( 4, "vmcfs: Image file Info: ECC shunk found       : %s\n", g_Vmc_Image[ f->unit ].ecc_flag ? "YES" : "NO" );
+	}
+
+	if ( g_Vmc_Image[ f->unit ].formated == FALSE ){
+		errcode = VMCFS_ERR_NOT_FORMATED;
+		goto mountAbort;
+	}
+
+	return 0;
+}
+
+//----------------------------------------------------------------------------
+// Unmount a vmc file previously mounted with fileXioMount(
+//----------------------------------------------------------------------------
+int Vmc_Umount ( iop_file_t* f, const char* fsname )
+{
+
+	DEBUGPRINT ( 2, "vmcfs: UnMount %s at mount point: %d\n", fsname, f->unit );
+
+	close ( g_Vmc_Image[ f->unit ].fd );
+	g_Vmc_Image[ f->unit ].fd = VMCFS_ERR_NOT_MOUNT;
+
+	return 0;
+
+}
+
+//----------------------------------------------------------------------------
+// Not Implemented for the moment.
+//----------------------------------------------------------------------------
+int Vmc_Lseek64 ( iop_file_t* f, long long offset, int whence )
+{
+	
+	return VMCFS_ERR_IMPLEMENTED;
+	
+}
+
+
+//----------------------------------------------------------------------------
+// Control command.
+// DEVCTL_VMCFS_CLEAN   :  Set as free all fat cluster corresponding to a none existing object. ( Object are just marked as none existing but not removed from fat table when rmdir or remove fonctions are call. This allow to recover a deleted file. )
+// DEVCTL_VMCFS_CKFREE  :  Check free space available on vmc file. 
+//----------------------------------------------------------------------------
+int Vmc_Devctl ( iop_file_t* f, const char* path, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen )
+{
+
+	if ( !g_Vmc_Initialized ) 
+		return VMCFS_ERR_INITIALIZED;
+
+	switch ( cmd ) 
+	{
+
+		case DEVCTL_VMCFS_CLEAN:
+			{
+
+				Vmc_Clean ( f->unit );
+
+			}
+			break;
+
+		case DEVCTL_VMCFS_CKFREE:
+			{
+
+				unsigned int free_space = Vmc_Checkfree ( f->unit );
+
+				return free_space;
+
+			}
+			break;
+
+		default:
+
+			DEBUGPRINT ( 1, "vmcfs: Unrecognized devctl command %d\n", cmd );
+			break;
+
+	}
+
+	return VMCFS_ERR_NO;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Not Implemented for the moment.
+//----------------------------------------------------------------------------
+int Vmc_Symlink ( iop_file_t* f, const char* old, const char* new )
+{
+	
+	return VMCFS_ERR_IMPLEMENTED;
+	
+}
+
+
+//----------------------------------------------------------------------------
+// Not Implemented for the moment.
+//----------------------------------------------------------------------------
+int Vmc_Readlink ( iop_file_t* f, const char* path, char* buf, unsigned int buf_len )
+{
+	
+	return VMCFS_ERR_IMPLEMENTED;
+	
+}
+
+
+//----------------------------------------------------------------------------
+// Not Implemented for the moment.
+//----------------------------------------------------------------------------
+int Vmc_Ioctl2 ( iop_file_t* f, int cmd, void *arg, unsigned int arglen,	void *buf, unsigned int buflen )
+{
+	
+	return VMCFS_ERR_IMPLEMENTED;
+	
+}
+
+
+// Extanded ioctl fonctions.
+
+
+//----------------------------------------------------------------------------
+// Recover an object in vmc image after removing it.
+// Not working properly when object have been overwrited
+//----------------------------------------------------------------------------
+int Vmc_Recover ( int unit, const char* path1 ) 
+{
+
+	if ( !g_Vmc_Initialized ) 
+		return VMCFS_ERR_INITIALIZED;
+
+	DEBUGPRINT ( 1, "vmcfs: recover %s\n", path1 );
+
+	if ( g_Vmc_Image[ unit ].fd < 0 ) 
+		return VMCFS_ERR_NOT_MOUNT;
+
+	if ( g_Vmc_Image[ unit ].formated == FALSE ) 
+		return VMCFS_ERR_NOT_FORMATED;
+
+	PROF_START ( vmc_recoverProf ) 
+
+	struct direntry     dirent;
+	struct gen_privdata gendata;
+
+	gendata.fd                = g_Vmc_Image[ unit ].fd;
+	gendata.first_allocatable = g_Vmc_Image[ unit ].header.first_allocatable;
+	gendata.last_allocatable  = g_Vmc_Image[ unit ].header.last_allocatable;
+
+	memcpy ( gendata.indir_fat_clusters, g_Vmc_Image[ unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
+
+	// Make a local copy of path.
+	char* path = malloc ( strlen ( path1 ) - strlen ( "vmc0:" ) + 1 );
+	memcpy ( path, path1 + strlen ( "vmc0:" ), strlen ( path1 ) - strlen ( "vmc0:" ) + 1 ); 
+
+	if ( path[ strlen ( path ) - 1 ] == '/' ) 
+		path[ strlen ( path ) - 1 ]= '\0';
+
+	unsigned int dirent_cluster = getDirentryFromPath ( &dirent, path, &gendata, unit );
+
+	if ( dirent_cluster == ROOT_CLUSTER )
+	{
+
+		DEBUGPRINT ( 2, "vmcfs: recover failed. Root directory is protected.\n" );
+
+		free( path );
+
+		PROF_END ( vmc_recoverProf ) 
+
+		return -1;
+
+	}
+	else if ( dirent_cluster == NOFOUND_CLUSTER )
+	{
+
+		DEBUGPRINT ( 2, "vmcfs: recover failed. %s not found.\n", path1 );
+
+		free( path );
+
+		PROF_END ( vmc_recoverProf ) 
+
+		return -1;
+
+	}
+
+	struct direntry     parent;
+	struct gen_privdata parent_gendata;
+	unsigned int        parent_cluster = 0;
+
+	parent_gendata.fd                = g_Vmc_Image[ unit ].fd;
+	parent_gendata.first_allocatable = g_Vmc_Image[ unit ].header.first_allocatable;
+	parent_gendata.last_allocatable  = g_Vmc_Image[ unit ].header.last_allocatable;
+
+	memcpy ( parent_gendata.indir_fat_clusters, g_Vmc_Image[ unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
+
+	// Find name of file, and name of parent
+	char* filename = strrchr ( path, '/' );
+
+	filename[ 0 ] = '\0';
+	filename++;
+
+	DEBUGPRINT ( 4, "vmcfs: Checking attributs parent directory %s\n", path );
+
+	if ( path[ 0 ] == '\0' ) 
+	{
+
+		//  get the root directories entry
+		parent_cluster = getDirentryFromPath ( &parent, ".", &parent_gendata, unit );
+
+	}
+	else
+	{
+
+		//  get the folder entry for the parent
+		parent_cluster = getDirentryFromPath ( &parent, path, &parent_gendata, unit );
+
+	}
+
+	if ( parent_cluster == NOFOUND_CLUSTER )
+	{
+
+		DEBUGPRINT ( 3, "vmcfs: Unable to recover %s. Parent directory not found.\n", path1 );
+
+		free ( path );
+
+		PROF_END ( vmc_recoverProf ) 
+
+		return -1;
+
+	}
+
+	DEBUGPRINT ( 6, "vmcfs: Parent Information.\n" );
+	DEBUGPRINT ( 6, "vmcfs: parent_cluster  = %u\n", parent_cluster );
+	DEBUGPRINT ( 6, "vmcfs: dir_cluster    = %u\n", parent.cluster );
+	DEBUGPRINT ( 6, "vmcfs: dirent.name    = %s\n", parent.name );
+	DEBUGPRINT ( 6, "vmcfs: dirent.length  = %u\n", parent.length );
+	DEBUGPRINT ( 6, "vmcfs: dirent.mode    = %X\n", parent.mode );
+	DEBUGPRINT ( 6, "vmcfs: dirent_page    = %i\n", parent_gendata.dirent_page );
+
+	if ( ! ( parent.mode & DF_EXISTS ) )
+	{
+
+		DEBUGPRINT ( 3, "vmcfs: Unable to restore %s. Parent directory %s is hidden.\n", path1, path );
+
+		free ( path );
+
+		PROF_END ( vmc_recoverProf ) 
+
+		return -1;
+
+	}
+
+	if ( dirent.mode & DF_DIRECTORY ) // directory case
+	{
+
+		if ( dirent.mode & DF_EXISTS ) 
+		{
+
+			DEBUGPRINT ( 2, "vmcfs: recover failed on %s. Directory allready exist.\n", path1 );
+
+			free( path );
+
+			PROF_END ( vmc_recoverProf ) 
+
+			return -1;
+
+		}
+		else
+		{
+
+			DEBUGPRINT ( 8, "vmcfs: recover directory %s allready exist but is hidden. Changing attributs.\n", path1 );
+
+			DEBUGPRINT ( 8, "vmcfs: Following fat table cluster %u\n", dirent.cluster );
+
+			unsigned int pseudo_entry_cluster = getFatEntry ( gendata.fd, dirent.cluster, gendata.indir_fat_clusters, FAT_VALUE );
+
+			DEBUGPRINT ( 8, "vmcfs: Changing cluster mask of fat table cluster %u.\n", pseudo_entry_cluster );
+
+			// change cluster mask of the direntry
+			setFatEntry ( gendata.fd, dirent.cluster, pseudo_entry_cluster, gendata.indir_fat_clusters, FAT_SET );
+
+			DEBUGPRINT ( 8, "vmcfs: Changing direntry %s attributs.\n", path1 );
+
+			//  Update time stamp, and set dirent.mode to exist flag
+			dirent.mode	= dirent.mode | DF_EXISTS;
+			getPs2Time ( &dirent.created );
+			getPs2Time ( &dirent.modified );
+			writePage ( gendata.fd, ( unsigned char* ) &dirent, ( dirent_cluster + gendata.first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + gendata.dirent_page );
+
+			DEBUGPRINT ( 8, "vmcfs: Restoring EOF cluster at %u.\n", pseudo_entry_cluster );
+
+			setFatEntry ( gendata.fd, pseudo_entry_cluster, EOF_CLUSTER, gendata.indir_fat_clusters, FAT_SET );
+
+			struct direntry pseudo_entries;
+
+			DEBUGPRINT ( 8, "vmcfs: Updating pseudo entries time stamps at cluster %u / page %u.\n", dirent.cluster + gendata.first_allocatable, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster );
+
+			//  Update time stamp of '.' entry
+			readPage ( gendata.fd, ( unsigned char* ) &pseudo_entries, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster );
+			getPs2Time ( &pseudo_entries.created );
+			getPs2Time ( &pseudo_entries.modified );
+			writePage ( gendata.fd, ( unsigned char* ) &pseudo_entries, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster );
+
+			DEBUGPRINT ( 8, "vmcfs: Updating pseudo entries time stamps at cluster %u / page %u.\n", dirent.cluster + gendata.first_allocatable, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + 1 );
+
+			//  Update time stamp of '..' entry
+			readPage ( gendata.fd, ( unsigned char* ) &pseudo_entries, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + 1 );
+			getPs2Time ( &pseudo_entries.created );
+			getPs2Time ( &pseudo_entries.modified );
+			writePage ( gendata.fd, ( unsigned char* ) &pseudo_entries, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + 1 );
+
+			DEBUGPRINT ( 2, "vmcfs: Directory %s recovered.\n", path1 );
+
+			free( path );
+
+			goto end;	
+
+		}
+		
+	}
+	else // file case
+	{
+
+		if ( dirent.mode & DF_EXISTS ) 
+		{
+
+			DEBUGPRINT ( 2, "vmcfs: recover failed on %s. File allready exist.\n", path );
+
+			free( path );
+
+			PROF_END ( vmc_recoverProf ) 
+
+			return -1;
+
+		}
+		else
+		{
+
+			unsigned int current_cluster = 0;
+			unsigned int last_cluster    = dirent.cluster;
+
+			DEBUGPRINT ( 8, "vmcfs: Restoring fat table clusters of file %s\n", filename );
+
+			while ( 1 ) 
+			{
+
+				current_cluster = getFatEntry ( gendata.fd, last_cluster, gendata.indir_fat_clusters, FAT_VALUE );
+
+				if ( current_cluster == FREE_CLUSTER ) 
+				{
+
+					// FREE_CLUSTER mean last cluster of the direntry is found
+					DEBUGPRINT ( 8, "vmcfs: Last cluster of file at %u\n", last_cluster );
+			
+					DEBUGPRINT ( 8, "vmcfs: Restoring End Of File at fat table cluster %u\n", last_cluster );
+
+					setFatEntry ( gendata.fd, last_cluster, EOF_CLUSTER, gendata.indir_fat_clusters, FAT_SET );
+
+					break;
+
+				}
+				else if ( current_cluster == EOF_CLUSTER ) 
+				{
+
+					// EOF_CLUSTER mean nothing to create or error, so goto end
+					DEBUGPRINT ( 3, "vmcfs: Error. EOF_CLUSTER found !!!\n" );
+
+					free( path );
+
+					goto end;
+
+				}
+				else
+				{
+
+					// Otherwise set cluster as free
+					DEBUGPRINT ( 10, "vmcfs: Testing cluster %u ... value is %u\n", last_cluster, current_cluster );
+
+					DEBUGPRINT ( 8, "vmcfs: Restoring cluster mask at fat table cluster %u\n", last_cluster );
+
+					setFatEntry ( gendata.fd, last_cluster, current_cluster, gendata.indir_fat_clusters, FAT_SET );
+
+				}
+
+				last_cluster = current_cluster;
+
+			}
+
+			DEBUGPRINT ( 8, "vmcfs: Restoring direntry at cluster %u / page %u\n", dirent_cluster + gendata.first_allocatable, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + gendata.dirent_page );
+
+			dirent.mode = dirent.mode | DF_EXISTS;
+			getPs2Time ( &dirent.created  );
+			getPs2Time ( &dirent.modified );
+			writePage ( gendata.fd, ( unsigned char* ) &dirent, ( dirent_cluster + gendata.first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + gendata.dirent_page );
+
+			free( path );
+
+			DEBUGPRINT ( 3, "vmcfs: File %s restored.\n", path1 );
+
+		}
+
+	}
+
+end:
+
+	PROF_END ( vmc_recoverProf ) 
+
+	return 0;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Check actual free space of the vmc file.
+//----------------------------------------------------------------------------
+unsigned int Vmc_Checkfree ( int unit ) 
+{
+
+	if ( !g_Vmc_Initialized ) 
+		return VMCFS_ERR_INITIALIZED;
+
+	DEBUGPRINT ( 1, "vmcfs: check free %d\n", unit );
+
+	if ( g_Vmc_Image[ unit ].fd < 0 ) 
+		return VMCFS_ERR_NOT_MOUNT;
+
+	if ( g_Vmc_Image[ unit ].formated == FALSE ) 
+		return VMCFS_ERR_NOT_FORMATED;
+
+	PROF_START ( vmc_checkfreeProf ) 
+
+	int                 i                = 0;
+	unsigned int        cluster_value    = 0;
+	unsigned int        cluster_mask     = 0;
+	unsigned int        free_space       = 0;
+	unsigned int        free_cluster_num = 0;
+	struct gen_privdata gendata;
+
+	gendata.fd                = g_Vmc_Image[ unit ].fd;
+	gendata.first_allocatable = g_Vmc_Image[ unit ].header.first_allocatable;
+	gendata.last_allocatable  = g_Vmc_Image[ unit ].header.last_allocatable;
+
+	memcpy ( gendata.indir_fat_clusters, g_Vmc_Image[ unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
+
+	for ( i = gendata.first_allocatable; i < gendata.last_allocatable; i++ ) 
+	{
+
+		cluster_value = getFatEntry ( gendata.fd, i - gendata.first_allocatable, gendata.indir_fat_clusters, FAT_VALUE );
+
+		if ( cluster_value == FREE_CLUSTER ) 
+		{
+
+			DEBUGPRINT ( 10, "vmcfs: Testing cluster %d ... value is FREE_CLUSTER\n", i );
+
+			DEBUGPRINT ( 6, "vmcfs: Free cluster found at %d\n", i );
+
+			free_cluster_num++;
+
+		}
+		else if ( cluster_value == EOF_CLUSTER ) 
+		{
+
+			DEBUGPRINT ( 10, "vmcfs: Testing cluster %d ... value is EOF_CLUSTER\n", i );
+
+		}
+		else
+		{
+
+			DEBUGPRINT ( 10, "vmcfs: Testing cluster %d ... value is %u\n", i, cluster_value );
+			
+			cluster_mask = getFatEntry ( gendata.fd, i - gendata.first_allocatable, gendata.indir_fat_clusters, FAT_MASK );
+			
+			if ( cluster_mask != MASK_CLUSTER )
+			{
+
+				DEBUGPRINT ( 6, "vmcfs: Free cluster found at %d\n", i );
+
+				free_cluster_num++;
+
+			}
+
+		}
+
+	}
+	
+	free_space = free_cluster_num * g_Vmc_Image[ unit ].cluster_size;
+
+	PROF_END ( vmc_checkfreeProf ) 
+
+	DEBUGPRINT ( 3, "vmcfs: Total free space: %u\n", free_space );
+
+	return free_space;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Clean unused cluster of the vmc file.
+//----------------------------------------------------------------------------
+int Vmc_Clean ( int unit )
+{
+
+	if ( !g_Vmc_Initialized ) 
+		return VMCFS_ERR_INITIALIZED;
+
+	DEBUGPRINT ( 1, "vmcfs: clean %d\n", unit );
+
+	if ( g_Vmc_Image[ unit ].fd < 0 ) 
+		return VMCFS_ERR_NOT_MOUNT;
+
+	if ( g_Vmc_Image[ unit ].formated == FALSE ) 
+		return VMCFS_ERR_NOT_FORMATED;
+
+	PROF_START ( vmc_cleanProf ) 
+
+	int                 i             = 0;
+	unsigned int        cluster_value = 0;
+	unsigned int        cluster_mask  = 0;
+	int                 object_remove = FALSE;
+	struct gen_privdata gendata;
+
+	gendata.fd                = g_Vmc_Image[ unit ].fd;
+	gendata.first_allocatable = g_Vmc_Image[ unit ].header.first_allocatable;
+	gendata.last_allocatable  = g_Vmc_Image[ unit ].header.last_allocatable;
+
+	memcpy ( gendata.indir_fat_clusters, g_Vmc_Image[ unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
+
+	for ( i = gendata.first_allocatable; i < gendata.last_allocatable; i++ ) 
+	{
+
+		cluster_value = getFatEntry ( gendata.fd, i - gendata.first_allocatable, gendata.indir_fat_clusters, FAT_VALUE );
+
+		if ( cluster_value == FREE_CLUSTER ) 
+		{
+
+			DEBUGPRINT ( 10, "vmcfs: Testing cluster %d ... value is FREE_CLUSTER\n", i );
+
+		}
+		else if ( cluster_value == EOF_CLUSTER ) 
+		{
+
+			DEBUGPRINT ( 10, "vmcfs: Testing cluster %d ... value is EOF_CLUSTER\n", i );
+
+		}
+		else
+		{
+
+			DEBUGPRINT ( 10, "vmcfs: Testing cluster %d ... value is %u\n", i, cluster_value );
+			
+			cluster_mask = getFatEntry ( gendata.fd, i - gendata.first_allocatable, gendata.indir_fat_clusters, FAT_MASK );
+			
+			if ( cluster_mask != MASK_CLUSTER )
+			{
+
+				DEBUGPRINT ( 6, "vmcfs: Setting cluster %d as free cluster.\n", i );
+
+				setFatEntry ( gendata.fd, i - gendata.first_allocatable, FREE_CLUSTER, gendata.indir_fat_clusters, FAT_SET );
+				
+				object_remove = TRUE;
+
+			}
+
+		}
+
+	}
+
+	return 0;
+
+}
Index: ps2launchargs/source/uLaunchELF/vmcfs/src/vmc_misc.c
===================================================================
--- ps2launchargs/source/uLaunchELF/vmcfs/src/vmc_misc.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/vmcfs/src/vmc_misc.c	(revision 1101)
@@ -0,0 +1,729 @@
+#include "vmc.h"
+
+
+// Misc fonctions 
+
+//----------------------------------------------------------------------------
+// Search a direntry corresponding to a path
+//----------------------------------------------------------------------------
+unsigned int getDirentryFromPath ( struct direntry* retval, const char* path, struct gen_privdata* gendata, int unit ) 
+{
+
+	PROF_START ( getDirentryFromPathProf );
+
+	DEBUGPRINT ( 6, "vmcfs: Searching Direntry corresponding to path: %s\n", path );
+
+	// Skip past the first slash if they opened a file such as
+	// vmc0: / file.txt ( which means the path passed here will be / file.txt, we
+	// want to skip that first slash, to ease comparisons.
+	int pathoffset = 0;
+
+	if ( path[ 0 ] ==  '/' ) 
+		pathoffset = 1;
+
+	if ( ( path[ 0 ] ==  '/' || path[ 0 ] == '.' ) && path[ 1 ] == '\0' ) // rootdirectory
+	{
+
+		gendata->dirent_page = 0;
+		readPage ( gendata->fd, ( unsigned char* ) retval, gendata->first_allocatable * g_Vmc_Image[ unit ].header.pages_per_cluster );
+
+		PROF_END ( getDirentryFromPathProf );
+
+		return ROOT_CLUSTER;
+
+	}
+
+	struct direntry dirent;		        // Our temporary directory entry
+
+	int status                   = 0; // The status of our search, if 0 at the end, we didn't find path
+	unsigned int current_cluster = 0;	// The cluster we are currently scanning for directory entries
+	int length                   = 1;	// The number of items in the current directory
+	int i                        = 0;
+
+	// Our main loop that goes through files / folder searching for the right one
+	for ( i = 0; i < length; i++ ) 
+	{
+
+		gendata->dirent_page = i % g_Vmc_Image[ unit ].header.pages_per_cluster;
+
+		DEBUGPRINT ( 6, "vmcfs: Reading in allocatable cluster %u / page %u\n", ( current_cluster + gendata->first_allocatable ), ( current_cluster + gendata->first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + gendata->dirent_page );
+
+		// Reads either the first or second page of a cluster, depending
+		// on the value currently stored in i
+		readPage ( gendata->fd, ( unsigned char* ) &dirent, ( current_cluster + gendata->first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + gendata->dirent_page );
+
+		// Check if this was the first entry ( aka the rootdirectory ) 
+		if ( i == 0 && current_cluster == 0 ) 
+			length = dirent.length;
+
+		DEBUGPRINT ( 5, "vmcfs: Direntry Informations\n" );
+		DEBUGPRINT ( 5, "vmcfs: Object Type    : %s\n", ( dirent.mode & DF_DIRECTORY ) ?"Folder":"File" );
+		DEBUGPRINT ( 5, "vmcfs: Object Name    : %s\n", dirent.name );
+		DEBUGPRINT ( 5, "vmcfs: Object Exists  : %s\n", ( dirent.mode & DF_EXISTS ) ?"Yes":"No" );
+		DEBUGPRINT ( 5, "vmcfs: Object Length  : %u\n", dirent.length );
+		DEBUGPRINT ( 5, "vmcfs: Object Cluster : %u\n", dirent.cluster );
+
+		// Now that we have a pages worth of data, check if it is the
+		// Directory we are searching for.
+
+		if ( memcmp ( dirent.name, path + pathoffset, strlen ( dirent.name )  ) == 0 ) 
+		{
+
+			// Increase the path offset by the length of the directory
+			pathoffset += strlen ( dirent.name );
+
+			// If the next item in the pathname is the null terminator, 
+			// we must be at the end of the path string, and that means
+			// we found the correct entry, so we can break.
+			if ( path[ pathoffset ] == '\0' || ( path[ pathoffset ] == '/' && path[ pathoffset + 1 ] == '\0' )  ) 
+			{
+
+				DEBUGPRINT ( 6, "vmcfs: Breaking from function\n" );
+				DEBUGPRINT ( 6, "vmcfs: dir_cluster = %u\n", dirent.cluster );
+				DEBUGPRINT ( 6, "vmcfs: dirent.name = %s\n", dirent.name );
+				DEBUGPRINT ( 6, "vmcfs: dirent.length = %u\n", dirent.length );
+
+				status = 1;
+
+				break;
+
+			}
+			// Otherwise we found the subfolder, but not the
+			// requested entry, keep going
+			else
+			{
+
+				DEBUGPRINT ( 6, "vmcfs: Recursing into subfolder\n" );
+				DEBUGPRINT ( 6, "vmcfs: dir_cluster = %u\n", dirent.cluster );
+				DEBUGPRINT ( 6, "vmcfs: dirent.name = %s\n", dirent.name );
+				DEBUGPRINT ( 6, "vmcfs: dirent.length = %u\n", dirent.length );
+
+				i               = -1;             // will be 0 when we continue, essentially starting the loop over again
+				current_cluster = dirent.cluster; // dirent.cluster refer to fat table and current_cluster to allocatable place
+				length          = dirent.length;  // set length to current directory length
+				pathoffset++;                     // add one to skip past the / in the folder name
+
+				continue;
+
+			}
+
+		}
+
+		// If we just read the second half of a cluster, we need to set
+		// current_cluster to the next cluster in the chain.
+		if ( i % g_Vmc_Image[ unit ].header.pages_per_cluster ) 
+		{
+
+			current_cluster = getFatEntry ( gendata->fd, current_cluster, gendata->indir_fat_clusters, FAT_VALUE );
+
+		}
+
+	}
+
+	// When we get here, that means one of two things:
+	// 1 ) We found the requested folder / file
+	// 2 ) We searched through all files / folders, and could not find it.
+	// To determine which one it was, check the status variable.
+	if ( status == 0 ) 
+	{
+
+		PROF_END ( getDirentryFromPathProf ) 
+
+		return NOFOUND_CLUSTER;
+
+	}
+
+	// Copy the last directory entry's contents into 'retval'
+	memcpy ( retval, &dirent, sizeof ( dirent )  );
+
+	PROF_END ( getDirentryFromPathProf ) 
+
+	// Return the cluster where the desired directory entry can be found
+	return current_cluster;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Add 2 pseudo entries for a new directory
+//----------------------------------------------------------------------------
+unsigned int addPseudoEntries ( struct gen_privdata* gendata, struct direntry* parent, int unit )
+{
+
+	// Get a free cluster we can use to store the entries '.' and '..'
+	unsigned int pseudo_entries_cluster = getFreeCluster ( gendata, unit );
+
+	if ( pseudo_entries_cluster == ERROR_CLUSTER ) 
+	{
+
+		DEBUGPRINT ( 2, "vmcfs: Not enough free space to add pseudo entries.  Aborting.\n" );
+
+		return ERROR_CLUSTER;
+
+	}
+
+	// Create the first 2 psuedo entries for the folder, and write them
+	DEBUGPRINT ( 5, "vmcfs: Adding pseudo entries into fat table cluster %u\n", pseudo_entries_cluster );
+
+	struct direntry pseudo_entries;
+
+	memset ( &pseudo_entries, 0, sizeof ( pseudo_entries )  );
+
+	// fill pseudo entries
+	strcpy ( pseudo_entries.name, "." );
+	pseudo_entries.dir_entry = parent->length;
+	pseudo_entries.length    = 0;
+	pseudo_entries.cluster   = parent->cluster;
+	pseudo_entries.mode      = DF_EXISTS | DF_0400 | DF_DIRECTORY | DF_READ | DF_WRITE | DF_EXECUTE; // 0x8427
+
+	getPs2Time ( &pseudo_entries.created  );
+	getPs2Time ( &pseudo_entries.modified );
+
+	// write first pseudo entry
+	writePage ( gendata->fd, ( unsigned char* ) &pseudo_entries, ( pseudo_entries_cluster + gendata->first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster );
+
+	strcpy ( pseudo_entries.name, ".." );
+	pseudo_entries.dir_entry = 0;
+	pseudo_entries.cluster   = 0;
+
+	// write second pseudo entry
+	writePage ( gendata->fd, ( unsigned char* ) &pseudo_entries, ( pseudo_entries_cluster + gendata->first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + 1 );
+
+	// set cluster as EOF
+	setFatEntry ( gendata->fd, pseudo_entries_cluster, EOF_CLUSTER, gendata->indir_fat_clusters, FAT_SET );
+
+	return pseudo_entries_cluster;
+	
+}
+
+
+//----------------------------------------------------------------------------
+// Add an object into vmc image.
+// This fonction get a free cluster where it can insert the object, insert it and return the cluster number.
+// Object can be a file or a folder.
+//----------------------------------------------------------------------------
+unsigned int addObject ( struct gen_privdata* gendata, unsigned int parent_cluster, struct direntry* parent, struct direntry* dirent, int unit ) 
+{
+
+	int          i                = 0;
+	unsigned int retval           = ERROR_CLUSTER;
+	unsigned int current_cluster  = parent->cluster;
+
+	// Find to the last cluster in the list of files / folder to add our new object after it
+	for ( i = 0; i < parent->length; i += g_Vmc_Image[ unit ].header.pages_per_cluster ) 
+	{
+
+		DEBUGPRINT ( 6, "vmcfs: Following fat table cluster: %u\n", current_cluster );
+
+		if ( getFatEntry ( gendata->fd, current_cluster, gendata->indir_fat_clusters, FAT_VALUE ) == EOF_CLUSTER ) 
+		{
+
+			DEBUGPRINT ( 6, "vmcfs: Last used cluster in fat table %u\n", current_cluster );
+			break;
+
+		}
+
+		current_cluster = getFatEntry ( gendata->fd, current_cluster, gendata->indir_fat_clusters, FAT_VALUE );
+
+	}
+
+	// Check if we need a new cluster or if we can add our object at the end of an allocatable cluster
+	if ( parent->length % g_Vmc_Image[ unit ].header.pages_per_cluster == 0 ) 	// if its even, we need a new cluster for our file
+	{
+
+		// Get a free cluster because our object require an additional cluster
+		unsigned int nextfree_cluster = getFreeCluster ( gendata, unit );
+
+		if ( nextfree_cluster == ERROR_CLUSTER ) 
+		{
+
+			DEBUGPRINT ( 2, "vmcfs: Not enough free space.  Aborting.\n" );
+
+			return ERROR_CLUSTER;
+
+		}
+
+		DEBUGPRINT ( 6, "vmcfs: Added new object in fat table cluster %u ( Page %u ) \n", current_cluster, current_cluster * g_Vmc_Image[ unit ].header.pages_per_cluster );
+
+		setFatEntry ( gendata->fd, current_cluster, nextfree_cluster, gendata->indir_fat_clusters, FAT_SET ); // update the last cluster in the directory entry list to point to our new cluster
+		setFatEntry ( gendata->fd, nextfree_cluster, EOF_CLUSTER, gendata->indir_fat_clusters, FAT_SET );     // set the free cluster we just found to be EOF
+
+		// If the object is a folder, we have to add 2 psuedoentries
+		if ( dirent->mode & DF_DIRECTORY ) 
+		{
+
+			// Link the new folder to the entries we just created
+			dirent->cluster = addPseudoEntries( gendata, parent, unit );
+			
+			if ( dirent->cluster == ERROR_CLUSTER )
+				return ERROR_CLUSTER;
+
+			// Set the length of the directory to 2, for the 2 psuedoentries we just added
+			dirent->length  = 2;
+
+		}
+
+		// write the page containing our direntry object information
+		writePage ( gendata->fd, ( unsigned char* ) dirent, ( nextfree_cluster + gendata->first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster );
+
+		// now we need to update the length of the parent directory
+		parent->length++;
+		writePage ( gendata->fd, ( unsigned char* ) parent, ( parent_cluster + gendata->first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + gendata->dirent_page );
+
+		gendata->dirent_page = 0;
+		retval               = nextfree_cluster;
+
+	}
+	else	// otherwise we can just add the directory entry to the end of the last cluster
+	{
+
+		DEBUGPRINT ( 5, "vmcfs: Added new object in fat table cluster %u ( Page %u ) \n", current_cluster, current_cluster * g_Vmc_Image[ unit ].header.pages_per_cluster + 1 );
+
+		// If the object is a folder, we have to add 2 psuedoentries
+		if ( dirent->mode & DF_DIRECTORY ) 
+		{
+
+			// Link the new folder to the entries we just created
+			dirent->cluster = addPseudoEntries( gendata, parent, unit );
+			
+			if ( dirent->cluster == ERROR_CLUSTER )
+				return ERROR_CLUSTER;
+
+			// Set the length of the directory to 2, for the 2 psuedoentries we just added
+			dirent->length  = 2;
+
+		}
+
+		// write the page containing our direntry object information
+		writePage ( gendata->fd, ( unsigned char* ) dirent, ( current_cluster + gendata->first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + 1 );// write the page containing our directory information ( + 1 because we are writing the second page in the cluster ) 
+
+		// now we need to update the length of the parent directory
+		parent->length++;
+		writePage ( gendata->fd, ( unsigned char* ) parent, ( parent_cluster + gendata->first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + gendata->dirent_page );
+
+		gendata->dirent_page = 1;
+		retval               = current_cluster;
+
+	}
+
+	return retval;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Remove an object from vmc image.
+// Object can be a file or a directory.
+// Follow fat table to find the last cluster of the direntry chain cluster. ( EOF_CLUSTER )
+// Change bit mask of tested cluster if it's not EOF. ( only for files )
+// Set as free the last cluster of the direntry.
+// Finaly, set deleted flag of the direntry. ( DF_EXISTS flag )
+//----------------------------------------------------------------------------
+void removeObject ( struct gen_privdata* gendata, unsigned int dirent_cluster, struct direntry* dirent, int unit )
+{
+
+	unsigned int current_cluster = 0;
+	unsigned int last_cluster    = dirent->cluster;
+
+	DEBUGPRINT ( 3, "vmcfs: Searching last cluster of direntry\n" );
+
+	while ( 1 ) 
+	{
+
+		current_cluster = getFatEntry ( gendata->fd, last_cluster, gendata->indir_fat_clusters, FAT_VALUE );
+
+		if ( current_cluster == FREE_CLUSTER ) 
+		{
+
+			// FREE_CLUSTER mean nothing to remove or error, so return
+			DEBUGPRINT ( 10, "vmcfs: Testing cluster %u ... value is FREE_CLUSTER\n", last_cluster );
+			
+			return;
+
+		}
+		else if ( current_cluster == EOF_CLUSTER ) 
+		{
+
+			// EOF_CLUSTER mean last cluster of the direntry is found
+			DEBUGPRINT ( 3, "vmcfs: Last cluster of direntry at %u\n", last_cluster );
+
+			break;
+
+		}
+		else
+		{
+
+			// Otherwise change bit mask of tested cluster
+			DEBUGPRINT ( 10, "vmcfs: Testing cluster %u ... value is %u\n", last_cluster, current_cluster );
+
+			setFatEntry ( gendata->fd, last_cluster, current_cluster, gendata->indir_fat_clusters, FAT_RESET );
+
+		}
+
+		last_cluster = current_cluster;
+
+	}
+
+	// Set last cluster of direntry as free.
+	setFatEntry ( gendata->fd, last_cluster, FREE_CLUSTER, gendata->indir_fat_clusters, FAT_RESET ); // set the last cluster of the file as free
+
+	// Set object as deleted. ( Remove DF_EXISTS flag )
+	dirent->mode = dirent->mode ^ DF_EXISTS;
+	writePage ( gendata->fd, ( unsigned char* ) dirent, ( dirent_cluster + gendata->first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + gendata->dirent_page );
+
+}
+
+
+//----------------------------------------------------------------------------
+// Return a free cluster.
+//----------------------------------------------------------------------------
+unsigned int getFreeCluster ( struct gen_privdata* gendata, int unit ) 
+{
+
+	unsigned int i            = 0;
+	unsigned int value        = 0;
+	unsigned int cluster_mask = MASK_CLUSTER;
+
+	for ( i = g_Vmc_Image[ unit ].last_free_cluster; i < gendata->last_allocatable; i++ ) 
+	{
+
+		value = getFatEntry ( gendata->fd, i - gendata->first_allocatable, gendata->indir_fat_clusters, FAT_VALUE );
+
+		if ( value == FREE_CLUSTER ) 
+		{
+
+			DEBUGPRINT ( 10, "vmcfs: Testing fat table cluster %d ... value is FREE_CLUSTER\n", i - gendata->first_allocatable );
+
+			DEBUGPRINT ( 6, "vmcfs: Free cluster found at %d in fat table\n", i - gendata->first_allocatable );
+			g_Vmc_Image[ unit ].last_free_cluster = i;
+
+			return ( i - gendata->first_allocatable );
+
+		}
+		else if ( value == EOF_CLUSTER ) 
+		{
+
+			DEBUGPRINT ( 10, "vmcfs: Testing fat table cluster %d ... value is EOF_CLUSTER\n", i - gendata->first_allocatable );
+
+		}
+		else
+		{
+
+			DEBUGPRINT ( 10, "vmcfs: Testing fat table cluster %d ... value is %d\n", i - gendata->first_allocatable, value );
+
+			cluster_mask = getFatEntry ( gendata->fd, i - gendata->first_allocatable, gendata->indir_fat_clusters, FAT_MASK );
+			
+			if ( cluster_mask != MASK_CLUSTER )
+			{
+
+				DEBUGPRINT ( 6, "vmcfs: Free cluster found at %d in fat table\n", i - gendata->first_allocatable );
+				g_Vmc_Image[ unit ].last_free_cluster = i;
+
+				return ( i - gendata->first_allocatable );
+
+			}
+
+		}
+
+	}
+
+	return ERROR_CLUSTER;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Set default specification to superblock header when card is not formated
+//----------------------------------------------------------------------------
+int setDefaultSpec ( int unit ) 
+{
+
+	DEBUGPRINT ( 4, "vmcfs: SuperBlock set by default\n" );
+
+	memset ( &g_Vmc_Image[ unit ].header, g_Vmc_Image[ unit ].erase_byte, sizeof ( struct superblock )  );
+	
+	strcpy ( g_Vmc_Image[ unit ].header.magic, "Sony PS2 Memory Card Format 1.2.0.0" );
+
+	DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: magic[40]             : %s\n"   , g_Vmc_Image[ unit ].header.magic                  );
+
+	g_Vmc_Image[ unit ].header.page_size = 0x200;
+	g_Vmc_Image[ unit ].header.pages_per_cluster = 0x2;
+	g_Vmc_Image[ unit ].header.pages_per_block = 0x10;
+	g_Vmc_Image[ unit ].header.unused0 = 0xFF00;
+
+	g_Vmc_Image[ unit ].cluster_size = g_Vmc_Image[ unit ].header.page_size * g_Vmc_Image[ unit ].header.pages_per_cluster;
+	g_Vmc_Image[ unit ].erase_byte   = 0xFF;
+	g_Vmc_Image[ unit ].last_idc     = EOF_CLUSTER;
+	g_Vmc_Image[ unit ].last_cluster = EOF_CLUSTER;
+
+	if ( g_Vmc_Image[ unit ].card_size %( g_Vmc_Image[ unit ].header.page_size + 0x10 ) == 0 ) 
+	{
+
+		g_Vmc_Image[ unit ].ecc_flag = TRUE;
+		g_Vmc_Image[ unit ].total_pages = g_Vmc_Image[ unit ].card_size / ( g_Vmc_Image[ unit ].header.page_size + 0x10 );
+		g_Vmc_Image[ unit ].header.clusters_per_card = g_Vmc_Image[ unit ].card_size / (  ( g_Vmc_Image[ unit ].header.page_size + 0x10 ) * g_Vmc_Image[ unit ].header.pages_per_cluster );
+
+	}
+	else if ( g_Vmc_Image[ unit ].card_size %g_Vmc_Image[ unit ].header.page_size == 0 ) 
+	{
+
+		g_Vmc_Image[ unit ].ecc_flag = FALSE;
+		g_Vmc_Image[ unit ].total_pages = g_Vmc_Image[ unit ].card_size / g_Vmc_Image[ unit ].header.page_size;
+		g_Vmc_Image[ unit ].header.clusters_per_card = g_Vmc_Image[ unit ].card_size / ( g_Vmc_Image[ unit ].header.page_size * g_Vmc_Image[ unit ].header.pages_per_cluster );
+
+	}
+	else
+	{
+
+		// Size error
+		return 0;
+
+	}
+
+	g_Vmc_Image[ unit ].header.mc_type = 0x2;
+	g_Vmc_Image[ unit ].header.mc_flag = 0x2B;
+
+	DEBUGPRINT ( 4, "vmcfs: Image file Info: Number of pages       : %d\n", g_Vmc_Image[ unit ].total_pages );
+	DEBUGPRINT ( 4, "vmcfs: Image file Info: Size of a cluster     : %d bytes\n", g_Vmc_Image[ unit ].cluster_size );
+	DEBUGPRINT ( 4, "vmcfs: Image file Info: ECC shunk found       : %s\n", g_Vmc_Image[ unit ].ecc_flag ? "YES" : "NO" );
+	DEBUGPRINT ( 3, "vmcfs: Image file Info: Vmc card type         : %s MemoryCard.\n", ( g_Vmc_Image[ unit ].header.mc_type == PSX_MEMORYCARD ? "PSX" : ( g_Vmc_Image[ unit ].header.mc_type == PS2_MEMORYCARD ? "PS2" : "PDA" )  )  );
+	DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: page_size             : 0x%02x\n", g_Vmc_Image[ unit ].header.page_size              );
+	DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: pages_per_cluster     : 0x%02x\n", g_Vmc_Image[ unit ].header.pages_per_cluster      );
+	DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: pages_per_block       : 0x%02x\n", g_Vmc_Image[ unit ].header.pages_per_block        );
+	DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: clusters_per_card     : 0x%02x\n", g_Vmc_Image[ unit ].header.clusters_per_card      );
+
+	g_Vmc_Image[ unit ].header.first_allocatable = (  (  (  ( g_Vmc_Image[ unit ].total_pages - 1 ) * ( g_Vmc_Image[ unit ].cluster_size / g_Vmc_Image[ unit ].header.page_size )  ) / g_Vmc_Image[ unit ].cluster_size ) + 1 ) + 8 + (  ( g_Vmc_Image[ unit ].total_pages - 1 ) / ( g_Vmc_Image[ unit ].total_pages * g_Vmc_Image[ unit ].header.pages_per_cluster * ( g_Vmc_Image[ unit ].cluster_size / g_Vmc_Image[ unit ].header.page_size )  )  ) + 1;
+	g_Vmc_Image[ unit ].header.last_allocatable = ( g_Vmc_Image[ unit ].header.clusters_per_card - g_Vmc_Image[ unit ].header.first_allocatable ) - (  ( g_Vmc_Image[ unit ].header.pages_per_block / g_Vmc_Image[ unit ].header.pages_per_cluster ) * g_Vmc_Image[ unit ].header.pages_per_cluster );
+	g_Vmc_Image[ unit ].header.root_cluster = 0;
+	
+	g_Vmc_Image[ unit ].header.backup_block1 = ( g_Vmc_Image[ unit ].total_pages / g_Vmc_Image[ unit ].header.pages_per_block ) - 1;
+	g_Vmc_Image[ unit ].header.backup_block2 = g_Vmc_Image[ unit ].header.backup_block1 - 1;
+	memset ( g_Vmc_Image[ unit ].header.unused1, g_Vmc_Image[ unit ].erase_byte, 8 );
+
+	DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: first_allocatable     : 0x%02x\n", g_Vmc_Image[ unit ].header.first_allocatable      );
+	DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: last_allocatable      : 0x%02x\n", g_Vmc_Image[ unit ].header.last_allocatable       );
+	DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: root_cluster          : 0x%02x\n", g_Vmc_Image[ unit ].header.root_cluster           );
+	DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: backup_block1         : 0x%02x\n", g_Vmc_Image[ unit ].header.backup_block1          );
+	DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: backup_block2         : 0x%02x\n", g_Vmc_Image[ unit ].header.backup_block2          );
+
+	unsigned int last_blk_sector = 8;
+	int i = 0;
+
+	for ( i = 0; i <= (  ( g_Vmc_Image[ unit ].total_pages - 1 ) / 65536 ); i++ ) 
+	{
+		if (  (  (  ( last_blk_sector + i ) * ( g_Vmc_Image[ unit ].cluster_size / g_Vmc_Image[ unit ].header.page_size )  ) %g_Vmc_Image[ unit ].header.pages_per_block ) == 0 ) 
+		{
+			last_blk_sector = last_blk_sector + i;
+		}
+		g_Vmc_Image[ unit ].header.indir_fat_clusters[ i ]= last_blk_sector + i;
+	}
+
+	for ( i = 0; g_Vmc_Image[ unit ].header.indir_fat_clusters[ i ]!= 0; i++ ) 
+		DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: indir_fat_clusters[%d] : 0x%02x\n", i, g_Vmc_Image[ unit ].header.indir_fat_clusters[ i ]);
+
+	memset ( g_Vmc_Image[ unit ].header.bad_block_list, g_Vmc_Image[ unit ].erase_byte, sizeof ( unsigned int ) * 32 );
+
+	g_Vmc_Image[ unit ].header.unused2 = 0;
+	g_Vmc_Image[ unit ].header.unused3 = 0x100;
+	g_Vmc_Image[ unit ].header.size_in_megs = ( g_Vmc_Image[ unit ].total_pages * g_Vmc_Image[ unit ].header.page_size ) / ( g_Vmc_Image[ unit ].cluster_size * g_Vmc_Image[ unit ].cluster_size );
+	g_Vmc_Image[ unit ].header.unused4 = 0xFFFFFFFF;
+	memset ( g_Vmc_Image[ unit ].header.unused5, g_Vmc_Image[ unit ].erase_byte, 12 );
+	g_Vmc_Image[ unit ].header.max_used = ( 97 * g_Vmc_Image[ unit ].header.clusters_per_card ) / 100;
+	memset ( g_Vmc_Image[ unit ].header.unused6, g_Vmc_Image[ unit ].erase_byte, 8 );
+	g_Vmc_Image[ unit ].header.unused7 = 0xFFFFFFFF;
+
+	DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: mc_type               : 0x%02x\n", g_Vmc_Image[ unit ].header.mc_type                );
+	DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: mc_flag               : 0x%02x\n", g_Vmc_Image[ unit ].header.mc_flag                );
+
+	g_Vmc_Image[ unit ].last_free_cluster = g_Vmc_Image[ unit ].header.first_allocatable;
+
+	return 1;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Used for timing functions, use this to optimize stuff
+//----------------------------------------------------------------------------
+#ifdef PROFILING
+
+	iop_sys_clock_t iop_clock_finished;	// Global clock finished data
+
+	void profilerStart ( iop_sys_clock_t* iopclock ) 
+	{
+
+		GetSystemTime ( iopclock );
+
+	}
+
+	void profilerEnd ( const char* function, const char* name, iop_sys_clock_t* iopclock1 ) 
+	{
+
+		// Make this the first item, so we don't add time that need not be added
+		GetSystemTime ( &iop_clock_finished );
+
+		unsigned int sec1, usec1;
+		unsigned int sec2, usec2;
+
+		SysClock2USec ( &iop_clock_finished, &sec2, &usec2 );
+		SysClock2USec ( iopclock1, &sec1, &usec1 );
+
+		printf ( "vmcfs: Profiler[ %s ]: %s %ld. %ld seconds\n", function, name, sec2 - sec1, ( usec2 - usec1 ) / 1000 );
+
+	}
+
+#endif
+
+
+//----------------------------------------------------------------------------
+// Get date and time from cdvd fonction and put them into a "vmc_datetime" struct pointer.
+//----------------------------------------------------------------------------
+int getPs2Time ( vmc_datetime* tm ) 
+{
+
+	cd_clock_t	cdtime;
+	s32         tmp;
+
+	static vmc_datetime timeBuf = {
+		0, 0x00, 0x00, 0x0A, 0x01, 0x01, 2008	// used if can not get time... 
+	};
+
+	if ( CdReadClock ( &cdtime ) != 0 && cdtime.stat == 0 ) 
+	{
+
+		tmp = cdtime.second >> 4;
+		timeBuf.sec = ( unsigned int ) (  (  ( tmp << 2 ) + tmp ) << 1 ) + ( cdtime.second & 0x0F );
+		tmp = cdtime.minute >> 4;
+		timeBuf.min = (  (  ( tmp << 2 ) + tmp ) << 1 ) + ( cdtime.minute & 0x0F );
+		tmp = cdtime.hour >> 4;
+		timeBuf.hour = (  (  ( tmp << 2 ) + tmp ) << 1 ) + ( cdtime.hour & 0x0F );
+// 		timeBuf.hour = ( timeBuf.hour + 4 ) %24;// TEMP FIX ( need to deal with timezones? ) ... aparently not!
+		tmp = cdtime.day >> 4;
+		timeBuf.day = (  (  ( tmp << 2 ) + tmp ) << 1 ) + ( cdtime.day & 0x0F );
+		tmp = cdtime.month >> 4;
+		timeBuf.month = (  (  ( tmp << 2 ) + tmp ) << 1 ) + ( cdtime.month & 0x0F );
+		tmp = cdtime.year >> 4;
+		timeBuf.year = (  (  ( tmp << 2 ) + tmp ) << 1 ) + ( cdtime.year & 0xF ) + 2000;
+
+	}
+
+	memcpy ( tm, &timeBuf, sizeof ( vmc_datetime )  );
+
+	return 0;
+
+}
+
+
+//----------------------------------------------------------------------------
+// XOR table use for Error Correcting Code ( ECC ) calculation.
+//----------------------------------------------------------------------------
+const unsigned char ECC_XOR_Table[ 256 ]= {
+0x00, 0x87, 0x96, 0x11, 0xA5, 0x22, 0x33, 0xB4, 
+0xB4, 0x33, 0x22, 0xA5, 0x11, 0x96, 0x87, 0x00, 
+0xC3, 0x44, 0x55, 0xD2, 0x66, 0xE1, 0xF0, 0x77, 
+0x77, 0xF0, 0xE1, 0x66, 0xD2, 0x55, 0x44, 0xC3, 
+0xD2, 0x55, 0x44, 0xC3, 0x77, 0xF0, 0xE1, 0x66, 
+0x66, 0xE1, 0xF0, 0x77, 0xC3, 0x44, 0x55, 0xD2, 
+0x11, 0x96, 0x87, 0x00, 0xB4, 0x33, 0x22, 0xA5, 
+0xA5, 0x22, 0x33, 0xB4, 0x00, 0x87, 0x96, 0x11, 
+0xE1, 0x66, 0x77, 0xF0, 0x44, 0xC3, 0xD2, 0x55, 
+0x55, 0xD2, 0xC3, 0x44, 0xF0, 0x77, 0x66, 0xE1, 
+0x22, 0xA5, 0xB4, 0x33, 0x87, 0x00, 0x11, 0x96, 
+0x96, 0x11, 0x00, 0x87, 0x33, 0xB4, 0xA5, 0x22, 
+0x33, 0xB4, 0xA5, 0x22, 0x96, 0x11, 0x00, 0x87, 
+0x87, 0x00, 0x11, 0x96, 0x22, 0xA5, 0xB4, 0x33, 
+0xF0, 0x77, 0x66, 0xE1, 0x55, 0xD2, 0xC3, 0x44, 
+0x44, 0xC3, 0xD2, 0x55, 0xE1, 0x66, 0x77, 0xF0, 
+0xF0, 0x77, 0x66, 0xE1, 0x55, 0xD2, 0xC3, 0x44, 
+0x44, 0xC3, 0xD2, 0x55, 0xE1, 0x66, 0x77, 0xF0, 
+0x33, 0xB4, 0xA5, 0x22, 0x96, 0x11, 0x00, 0x87, 
+0x87, 0x00, 0x11, 0x96, 0x22, 0xA5, 0xB4, 0x33, 
+0x22, 0xA5, 0xB4, 0x33, 0x87, 0x00, 0x11, 0x96, 
+0x96, 0x11, 0x00, 0x87, 0x33, 0xB4, 0xA5, 0x22, 
+0xE1, 0x66, 0x77, 0xF0, 0x44, 0xC3, 0xD2, 0x55, 
+0x55, 0xD2, 0xC3, 0x44, 0xF0, 0x77, 0x66, 0xE1, 
+0x11, 0x96, 0x87, 0x00, 0xB4, 0x33, 0x22, 0xA5, 
+0xA5, 0x22, 0x33, 0xB4, 0x00, 0x87, 0x96, 0x11, 
+0xD2, 0x55, 0x44, 0xC3, 0x77, 0xF0, 0xE1, 0x66, 
+0x66, 0xE1, 0xF0, 0x77, 0xC3, 0x44, 0x55, 0xD2, 
+0xC3, 0x44, 0x55, 0xD2, 0x66, 0xE1, 0xF0, 0x77, 
+0x77, 0xF0, 0xE1, 0x66, 0xD2, 0x55, 0x44, 0xC3, 
+0x00, 0x87, 0x96, 0x11, 0xA5, 0x22, 0x33, 0xB4, 
+0xB4, 0x33, 0x22, 0xA5, 0x11, 0x96, 0x87, 0x00, 
+};
+
+
+//----------------------------------------------------------------------------
+// Calculate ECC for a 128 bytes chunk of data
+//----------------------------------------------------------------------------
+int calculateECC ( char* ECC_Chunk, const unsigned char* Data_Chunk ) 
+{
+	int i, c;
+
+	ECC_Chunk[ 0 ]= ECC_Chunk[ 1 ]= ECC_Chunk[ 2 ]= 0;
+
+	for ( i = 0; i < 0x80; i++ ) 
+	{
+
+		c = ECC_XOR_Table[ Data_Chunk[ i ] ];
+
+		ECC_Chunk[ 0 ] ^= c;
+
+		if ( c & 0x80 ) 
+		{
+
+			ECC_Chunk[ 1 ] ^= ~i;
+			ECC_Chunk[ 2 ] ^= i;
+
+		}
+
+	}
+
+	ECC_Chunk[ 0 ] = ~ECC_Chunk[ 0 ];
+	ECC_Chunk[ 0 ] &= 0x77;
+	ECC_Chunk[ 1 ] = ~ECC_Chunk[ 1 ];
+	ECC_Chunk[ 1 ] &= 0x7f;
+	ECC_Chunk[ 2 ] = ~ECC_Chunk[ 2 ];
+	ECC_Chunk[ 2 ] &= 0x7f;
+
+	return 1;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Build ECC from a complet page of data
+//----------------------------------------------------------------------------
+int buildECC ( int unit, char* Page_Data, char* ECC_Data ) 
+{
+
+	char Data_Chunk[ 4 ][ 128 ];
+	char ECC_Chunk[ 4 ][ 3 ];
+	char ECC_Pad[ 4 ];
+
+	// This is to divide the page in 128 bytes chunks
+	memcpy ( Data_Chunk[ 0 ], Page_Data +   0, 128 );
+	memcpy ( Data_Chunk[ 1 ], Page_Data + 128, 128 );
+	memcpy ( Data_Chunk[ 2 ], Page_Data + 256, 128 );
+	memcpy ( Data_Chunk[ 3 ], Page_Data + 384, 128 );
+
+	// Ask for 128 bytes chunk ECC calculation, it returns 3 bytes per chunk
+	calculateECC ( ECC_Chunk[ 0 ], Data_Chunk[ 0 ]);
+	calculateECC ( ECC_Chunk[ 1 ], Data_Chunk[ 1 ]);
+	calculateECC ( ECC_Chunk[ 2 ], Data_Chunk[ 2 ]);
+	calculateECC ( ECC_Chunk[ 3 ], Data_Chunk[ 3 ]);
+
+	// Prepare Padding as ECC took only 12 bytes and stand on 16 bytes
+	memset ( ECC_Pad, g_Vmc_Image[ unit ].erase_byte, sizeof ( ECC_Pad )  );
+
+	// "MemCopy" our four 3 bytes ECC chunks into our 16 bytes ECC data buffer
+	// Finaly "MemCopy" our 4 bytes PAD chunks into last 4 bytes of our ECC data buffer
+	memcpy ( ECC_Data + 0, ECC_Chunk[ 0 ], 3 );
+	memcpy ( ECC_Data + 3, ECC_Chunk[ 1 ], 3 );
+	memcpy ( ECC_Data + 6, ECC_Chunk[ 2 ], 3 );
+	memcpy ( ECC_Data + 9, ECC_Chunk[ 3 ], 3 );
+	memcpy ( ECC_Data + 12, ECC_Pad      , 4 );
+
+	return 1;
+
+}
Index: ps2launchargs/source/uLaunchELF/vmcfs/src/vmc_ps2.c
===================================================================
--- ps2launchargs/source/uLaunchELF/vmcfs/src/vmc_ps2.c	(revision 1101)
+++ ps2launchargs/source/uLaunchELF/vmcfs/src/vmc_ps2.c	(revision 1101)
@@ -0,0 +1,220 @@
+#include "vmc.h"
+
+
+// Functions specific to the ps2
+
+int readPage ( int fd, unsigned char* page, unsigned int pagenum ) 
+{
+
+	int unit;
+	unsigned int position;
+
+	unit = ( fd == g_Vmc_Image[ 0 ].fd ) ? 0 : 1;
+
+	if ( g_Vmc_Image[ unit ].ecc_flag ) 
+	{
+
+		position = pagenum * ( g_Vmc_Image[ unit ].header.page_size + 0x10 );
+
+	}
+	else
+	{
+
+		position = pagenum * g_Vmc_Image[ unit ].header.page_size;
+
+	}
+
+	lseek ( fd, position, SEEK_SET );
+	read ( fd, page, g_Vmc_Image[ unit ].header.page_size );
+
+	return 0;
+
+}
+
+int readCluster ( int fd, unsigned char* cluster, unsigned int clusternum ) 
+{
+
+	int          i, unit;
+	char*        Page_Data;
+	unsigned int Page_Num;
+
+	unit = ( fd == g_Vmc_Image[ 0 ].fd ) ? 0 : 1;
+
+	Page_Num = clusternum * g_Vmc_Image[ unit ].header.pages_per_cluster;
+
+	Page_Data  = ( char* )malloc ( ( g_Vmc_Image[ unit ].header.page_size + 0xFF ) & ~( unsigned int )0xFF );
+
+	for ( i = 0; i < g_Vmc_Image[ unit ].header.pages_per_cluster; i++ ) 
+	{
+
+		memset ( Page_Data, g_Vmc_Image[ unit ].erase_byte, g_Vmc_Image[ unit ].header.page_size );
+
+		readPage ( fd, Page_Data, Page_Num + i );
+
+		memcpy ( cluster + ( i * g_Vmc_Image[ unit ].header.page_size ), Page_Data, g_Vmc_Image[ unit ].header.page_size );
+
+	}
+	
+	free( Page_Data );
+
+	return 0;
+
+}
+
+int writePage ( int fd, unsigned char* page, unsigned int pagenum ) 
+{
+
+	int unit;
+	unsigned int position;
+
+	unit = ( fd == g_Vmc_Image[ 0 ].fd ) ? 0 : 1;
+
+	if ( g_Vmc_Image[ unit ].ecc_flag ) 
+	{
+
+		position = pagenum * ( g_Vmc_Image[ unit ].header.page_size + 0x10 );
+
+	}
+	else
+	{
+
+		position = pagenum * g_Vmc_Image[ unit ].header.page_size;
+
+	}
+
+	lseek ( fd, position, SEEK_SET );
+	write ( fd, page, g_Vmc_Image[ unit ].header.page_size );
+
+	if ( g_Vmc_Image[ unit ].ecc_flag ) 
+	{
+
+		char* ECC_Data;
+
+		ECC_Data  = ( char* )malloc ( ( 0x10 + 0xFF ) & ~( unsigned int )0xFF );
+
+		buildECC ( unit, page, ECC_Data );
+		write ( fd, ECC_Data, 0x10 );
+		
+		free( ECC_Data );
+
+	}
+
+	return 0;
+
+}
+
+int writeCluster ( int fd, unsigned char* cluster, unsigned int clusternum ) 
+{
+
+	int          i, unit;
+	char*        Page_Data;
+	unsigned int Page_Num;
+
+	unit = ( fd == g_Vmc_Image[ 0 ].fd ) ? 0 : 1;
+
+	Page_Num = clusternum * g_Vmc_Image[ unit ].header.pages_per_cluster;
+
+	Page_Data  = ( char* )malloc ( ( g_Vmc_Image[ unit ].header.page_size + 0xFF ) & ~( unsigned int )0xFF );
+
+	for ( i = 0; i < g_Vmc_Image[ unit ].header.pages_per_cluster; i++ ) 
+	{
+
+		memset ( Page_Data, g_Vmc_Image[ unit ].erase_byte, g_Vmc_Image[ unit ].header.page_size );
+		memcpy ( Page_Data, cluster + ( i * g_Vmc_Image[ unit ].header.page_size ), g_Vmc_Image[ unit ].header.page_size );
+
+		writePage ( fd, Page_Data, Page_Num + i );
+
+	}
+	
+	free( Page_Data );
+
+	return 0;
+
+}
+
+int writeClusterPart ( int fd, unsigned char* cluster, unsigned int clusternum, int cluster_offset, int size ) 
+{
+
+	int          i, unit;
+	char*        Page_Data;
+	unsigned int Page_Num, Page_offset;
+
+	unit = ( fd == g_Vmc_Image[ 0 ].fd ) ? 0 : 1;
+
+	Page_Num = clusternum * g_Vmc_Image[ unit ].header.pages_per_cluster;
+	Page_offset = cluster_offset;
+
+	Page_Data  = ( char* )malloc ( ( g_Vmc_Image[ unit ].header.page_size + 0xFF ) & ~( unsigned int )0xFF );
+
+	for ( i = 0; i < g_Vmc_Image[ unit ].header.pages_per_cluster; i++ ) 
+	{
+
+		if (  ( cluster_offset >= ( g_Vmc_Image[ unit ].header.page_size * i )  ) && ( cluster_offset < ( g_Vmc_Image[ unit ].header.page_size * ( i + 1 )  )  )  ) 
+		{
+			
+			Page_Num += i;
+			Page_offset = cluster_offset - g_Vmc_Image[ unit ].header.page_size * i;
+
+			memset ( Page_Data, g_Vmc_Image[ unit ].erase_byte, g_Vmc_Image[ unit ].header.page_size );
+			readPage ( fd, Page_Data, Page_Num );
+
+			if ( size > g_Vmc_Image[ unit ].header.page_size - Page_offset ) 
+			{
+				
+				memcpy ( Page_Data + Page_offset, cluster, g_Vmc_Image[ unit ].header.page_size - Page_offset );
+				writePage ( fd, Page_Data, Page_Num );
+
+				Page_Num++;
+
+				memset ( Page_Data, g_Vmc_Image[ unit ].erase_byte, g_Vmc_Image[ unit ].header.page_size );
+				readPage ( fd, Page_Data, Page_Num );
+
+				memcpy ( Page_Data, cluster + ( g_Vmc_Image[ unit ].header.page_size - Page_offset ), size - ( g_Vmc_Image[ unit ].header.page_size - Page_offset )  );
+				writePage ( fd, Page_Data, Page_Num );
+				
+			}
+			else
+			{
+
+				memcpy ( Page_Data + Page_offset, cluster, size );
+				writePage ( fd, Page_Data, Page_Num );
+			
+			}
+				
+		}
+
+	}
+	
+	free( Page_Data );
+
+	return 0;
+
+}
+
+int eraseBlock ( int fd, unsigned int block ) 
+{
+
+	int          i, unit;
+	char*        Page_Data;
+	unsigned int Page_Num;
+
+	unit = ( fd == g_Vmc_Image[ 0 ].fd ) ? 0 : 1;
+
+	Page_Data  = ( char* )malloc ( ( g_Vmc_Image[ unit ].header.page_size + 0xFF ) & ~( unsigned int )0xFF );
+
+	Page_Num = block * g_Vmc_Image[ unit ].header.pages_per_block;
+
+	memset ( Page_Data, g_Vmc_Image[ unit ].erase_byte, g_Vmc_Image[ unit ].header.page_size );
+
+	for ( i = 0; i < g_Vmc_Image[ unit ].header.pages_per_block; i++ ) 
+	{ 
+
+		writePage ( fd, Page_Data, Page_Num + i );
+
+	}
+	
+	free( Page_Data );
+
+	return 0;
+
+}
