snes9xgx/source/ngc/filesel.cpp

762 lines
19 KiB
C++
Raw Normal View History

/****************************************************************************
* Snes9x 1.51 Nintendo Wii/Gamecube Port
2008-08-14 00:44:59 +02:00
*
* softdev July 2006
* svpe June 2007
* crunchy2 May-July 2007
2008-09-23 06:54:53 +02:00
* Michniewski 2008
* Tantric August 2008
*
* filesel.cpp
*
* Generic file routines - reading, writing, browsing
***************************************************************************/
#include <gccore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wiiuse/wpad.h>
#include <sys/dir.h>
#include <malloc.h>
#ifdef WII_DVD
2008-08-23 05:20:54 +02:00
extern "C" {
#include <di/di.h>
2008-08-23 05:20:54 +02:00
}
#endif
#include "snes9x.h"
#include "memmap.h"
2008-09-09 19:36:48 +02:00
#include "snes9xGX.h"
#include "dvd.h"
2008-08-07 07:19:17 +02:00
#include "menudraw.h"
#include "video.h"
#include "aram.h"
#include "smbop.h"
2008-08-07 07:33:24 +02:00
#include "fileop.h"
2008-08-12 05:25:16 +02:00
#include "memcardop.h"
#include "input.h"
#include "unzip.h"
int offset;
int selection;
char currentdir[MAXPATHLEN];
2008-10-14 11:21:34 +02:00
char szpath[MAXPATHLEN];
int maxfiles;
extern int screenheight;
unsigned long SNESROMSize = 0;
2008-08-16 02:02:08 +02:00
int havedir = -1;
extern u64 dvddir;
extern int dvddirlength;
2008-08-14 00:44:59 +02:00
// Global file entry table
FILEENTRIES filelist[MAXFILES];
2008-10-14 11:21:34 +02:00
bool inSz = false;
2008-08-14 00:44:59 +02:00
unsigned char *savebuffer = NULL;
2008-08-12 05:25:16 +02:00
/****************************************************************************
2008-09-27 09:13:52 +02:00
* AllocSaveBuffer ()
* Allocate and clear the savebuffer
***************************************************************************/
2008-08-12 05:25:16 +02:00
void
2008-09-27 09:13:52 +02:00
AllocSaveBuffer ()
2008-08-12 05:25:16 +02:00
{
2008-09-27 09:13:52 +02:00
if (savebuffer != NULL)
free(savebuffer);
savebuffer = (unsigned char *) malloc(SAVEBUFFERSIZE);
memset (savebuffer, 0, SAVEBUFFERSIZE);
2008-08-12 05:25:16 +02:00
}
2008-09-27 09:13:52 +02:00
/****************************************************************************
* FreeSaveBuffer ()
* Free the savebuffer memory
***************************************************************************/
void
FreeSaveBuffer ()
{
if (savebuffer != NULL)
free(savebuffer);
2008-09-27 09:57:03 +02:00
savebuffer = NULL;
2008-09-27 09:13:52 +02:00
}
/****************************************************************************
* autoLoadMethod()
* Auto-determines and sets the load method
* Returns method set
****************************************************************************/
int autoLoadMethod()
{
2008-08-12 05:25:16 +02:00
ShowAction ((char*) "Attempting to determine load method...");
if(ChangeFATInterface(METHOD_SD, SILENT))
return METHOD_SD;
2008-08-12 05:25:16 +02:00
else if(ChangeFATInterface(METHOD_USB, SILENT))
return METHOD_USB;
2008-08-16 02:02:08 +02:00
else if(TestDVD())
2008-08-12 05:25:16 +02:00
return METHOD_DVD;
else if(ConnectShare (SILENT))
return METHOD_SMB;
else
{
WaitPrompt((char*) "Unable to auto-determine load method!");
return 0; // no method found
}
}
/****************************************************************************
* autoSaveMethod()
* Auto-determines and sets the save method
* Returns method set
****************************************************************************/
int autoSaveMethod()
{
2008-08-12 05:25:16 +02:00
ShowAction ((char*) "Attempting to determine save method...");
if(ChangeFATInterface(METHOD_SD, SILENT))
return METHOD_SD;
2008-08-12 05:25:16 +02:00
else if(ChangeFATInterface(METHOD_USB, SILENT))
return METHOD_USB;
2008-08-08 10:13:13 +02:00
else if(TestCard(CARD_SLOTA, SILENT))
return METHOD_MC_SLOTA;
2008-08-08 10:13:13 +02:00
else if(TestCard(CARD_SLOTB, SILENT))
return METHOD_MC_SLOTB;
2008-08-12 05:25:16 +02:00
else if(ConnectShare (SILENT))
return METHOD_SMB;
else
{
WaitPrompt((char*) "Unable to auto-determine save method!");
return 0; // no method found
}
}
/****************************************************************************
* UpdateDirName()
* Update curent directory name for file browser
***************************************************************************/
2008-08-16 02:02:08 +02:00
int UpdateDirName(int method)
{
int size=0;
2008-09-27 09:13:52 +02:00
char * test;
char temp[1024];
2008-08-16 02:02:08 +02:00
// update DVD directory (does not utilize 'currentdir')
if(method == METHOD_DVD)
{
dvddir = filelist[selection].offset;
dvddirlength = filelist[selection].length;
return 1;
}
/* current directory doesn't change */
if (strcmp(filelist[selection].filename,".") == 0)
{
return 0;
}
/* go up to parent directory */
else if (strcmp(filelist[selection].filename,"..") == 0)
{
/* determine last subdirectory namelength */
sprintf(temp,"%s",currentdir);
test = strtok(temp,"/");
while (test != NULL)
{
size = strlen(test);
test = strtok(NULL,"/");
}
/* remove last subdirectory name */
size = strlen(currentdir) - size - 1;
currentdir[size] = 0;
return 1;
}
/* Open a directory */
else
{
/* test new directory namelength */
if ((strlen(currentdir)+1+strlen(filelist[selection].filename)) < MAXPATHLEN)
{
/* update current directory name */
sprintf(currentdir, "%s/%s",currentdir, filelist[selection].filename);
return 1;
}
else
{
WaitPrompt((char*)"Directory name is too long !");
return -1;
}
}
}
2008-10-14 11:21:34 +02:00
bool MakeROMPath(char filepath[], int method)
{
char temppath[MAXPATHLEN];
// Check filename length
if ((strlen(currentdir)+1+strlen(filelist[selection].filename)) < MAXPATHLEN)
{
sprintf(temppath, "%s/%s",currentdir,filelist[selection].filename);
if(method == METHOD_SMB)
strcpy(filepath, SMBPath(temppath));
else
strcpy(filepath, temppath);
return true;
}
else
{
filepath[0] = 0;
return false;
}
}
/****************************************************************************
* FileSortCallback
*
* Quick sort callback to sort file entries with the following order:
* .
* ..
* <dirs>
* <files>
***************************************************************************/
int FileSortCallback(const void *f1, const void *f2)
{
/* Special case for implicit directories */
if(((FILEENTRIES *)f1)->filename[0] == '.' || ((FILEENTRIES *)f2)->filename[0] == '.')
{
if(strcmp(((FILEENTRIES *)f1)->filename, ".") == 0) { return -1; }
if(strcmp(((FILEENTRIES *)f2)->filename, ".") == 0) { return 1; }
if(strcmp(((FILEENTRIES *)f1)->filename, "..") == 0) { return -1; }
if(strcmp(((FILEENTRIES *)f2)->filename, "..") == 0) { return 1; }
}
/* If one is a file and one is a directory the directory is first. */
2008-08-17 07:25:33 +02:00
if(((FILEENTRIES *)f1)->flags && !(((FILEENTRIES *)f2)->flags)) return -1;
if(!(((FILEENTRIES *)f1)->flags) && ((FILEENTRIES *)f2)->flags) return 1;
return stricmp(((FILEENTRIES *)f1)->filename, ((FILEENTRIES *)f2)->filename);
}
/****************************************************************************
* IsValidROM
*
* Checks if the specified file is a valid ROM
* For now we will just check the file extension and file size
* If the file is a zip, we will check the file extension / file size of the
* first file inside
***************************************************************************/
bool IsValidROM(int method)
{
// file size should be between 128K and 8MB
if(filelist[selection].length < (1024*128) ||
filelist[selection].length > (1024*1024*8))
{
WaitPrompt((char *)"Invalid file size!");
return false;
}
if (strlen(filelist[selection].filename) > 4)
{
char * p = strrchr(filelist[selection].filename, '.');
if (p != NULL)
{
2008-10-14 11:21:34 +02:00
if(stricmp(p, ".zip") == 0 && !inSz)
{
// we need to check the file extension of the first file in the archive
char * zippedFilename = GetFirstZipFilename (method);
2008-10-14 11:21:34 +02:00
if(zippedFilename == NULL) // we don't want to run strlen on NULL
p = NULL;
else if(strlen(zippedFilename) > 4)
p = strrchr(zippedFilename, '.');
else
p = NULL;
}
if(p != NULL)
{
if (stricmp(p, ".smc") == 0 ||
stricmp(p, ".fig") == 0 ||
2008-10-19 20:07:38 +02:00
stricmp(p, ".sfc") == 0 ||
stricmp(p, ".swc") == 0)
{
return true;
}
}
}
}
WaitPrompt((char *)"Unknown file type!");
return false;
}
2008-10-14 11:21:34 +02:00
/****************************************************************************
* IsSz
*
* Checks if the specified file is a 7z
***************************************************************************/
bool IsSz()
{
if (strlen(filelist[selection].filename) > 4)
{
char * p = strrchr(filelist[selection].filename, '.');
if (p != NULL)
if(stricmp(p, ".7z") == 0)
return true;
}
return false;
}
/****************************************************************************
* StripExt
*
* Strips an extension from a filename
***************************************************************************/
void StripExt(char* returnstring, char * inputstring)
{
char* loc_dot;
2008-08-07 07:19:17 +02:00
strcpy (returnstring, inputstring);
loc_dot = strrchr(returnstring,'.');
if (loc_dot != NULL)
2008-09-27 10:36:22 +02:00
*loc_dot = 0; // strip file extension
}
/****************************************************************************
* FileSelector
*
* Let user select a file from the listing
***************************************************************************/
int FileSelector (int method)
{
u32 p = 0;
u32 wp = 0;
u32 ph = 0;
u32 wh = 0;
signed char gc_ay = 0;
signed char gc_sx = 0;
signed char wm_ay = 0;
signed char wm_sx = 0;
2008-08-20 09:58:55 +02:00
int haverom = 0;
int redraw = 1;
int selectit = 0;
2008-08-20 09:58:55 +02:00
int scroll_delay = 0;
bool move_selection = 0;
#define SCROLL_INITIAL_DELAY 15
#define SCROLL_LOOP_DELAY 2
while (haverom == 0)
{
if (redraw)
2008-08-14 00:44:59 +02:00
ShowFiles (filelist, maxfiles, offset, selection);
redraw = 0;
VIDEO_WaitVSync(); // slow things down a bit so we don't overread the pads
gc_ay = PAD_StickY (0);
gc_sx = PAD_SubStickX (0);
2008-08-20 09:58:55 +02:00
p = PAD_ButtonsDown (0);
ph = PAD_ButtonsHeld (0);
#ifdef HW_RVL
2008-10-03 23:52:57 +02:00
wm_ay = WPAD_Stick (0, 0, 1);
wm_sx = WPAD_Stick (0, 1, 0);
wp = WPAD_ButtonsDown (0);
wh = WPAD_ButtonsHeld (0);
#endif
/*** Check for exit combo ***/
if ( (gc_sx < -70) || (wm_sx < -70) || (wp & WPAD_BUTTON_HOME) || (wp & WPAD_CLASSIC_BUTTON_HOME) )
return 0;
/*** Check buttons, perform actions ***/
2008-08-12 05:25:16 +02:00
if ( (p & PAD_BUTTON_A) || selectit || (wp & (WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A)) )
{
if ( selectit )
selectit = 0;
if (filelist[selection].flags) // This is directory
{
/* update current directory and set new entry list if directory has changed */
2008-10-14 11:21:34 +02:00
int status;
if(inSz && selection == 0) // inside a 7z, requesting to leave
{
if(method == METHOD_DVD)
{
2008-10-15 20:29:01 +02:00
// go to directory the 7z was in
2008-10-14 11:21:34 +02:00
dvddir = filelist[0].offset;
dvddirlength = filelist[0].length;
}
inSz = false;
status = 1;
SzClose();
}
else
{
status = UpdateDirName(method);
}
2008-08-12 05:25:16 +02:00
if (status == 1) // ok, open directory
{
switch (method)
{
case METHOD_SD:
case METHOD_USB:
maxfiles = ParseFATdirectory(method);
break;
case METHOD_DVD:
maxfiles = ParseDVDdirectory();
break;
case METHOD_SMB:
maxfiles = ParseSMBdirectory();
break;
}
if (!maxfiles)
{
2008-10-28 07:52:38 +01:00
WaitPrompt ((char*) "Error reading directory!");
2008-10-14 11:21:34 +02:00
haverom = 1; // quit menu
2008-08-12 05:25:16 +02:00
}
}
else if (status == -1) // directory name too long
{
return 0; // quit menu
2008-08-12 05:25:16 +02:00
}
}
else // this is a file
{
2008-10-28 07:52:38 +01:00
// better do another unmount/remount, just in case
if(method == METHOD_SD || method == METHOD_USB)
if(!ChangeFATInterface(method, NOTSILENT))
return 0;
2008-10-14 11:21:34 +02:00
// 7z file - let's open it up to select a file inside
if(IsSz())
2008-08-12 05:25:16 +02:00
{
2008-10-14 11:21:34 +02:00
// we'll store the 7z filepath for extraction later
if(!MakeROMPath(szpath, method))
{
WaitPrompt((char*) "Maximum filepath length reached!");
2008-10-28 07:52:38 +01:00
return 0;
2008-10-14 11:21:34 +02:00
}
2008-10-15 01:35:19 +02:00
int szfiles = SzParse(szpath, method);
if(szfiles)
{
maxfiles = szfiles;
2008-10-14 11:21:34 +02:00
inSz = true;
2008-10-15 01:35:19 +02:00
}
2008-10-15 08:35:14 +02:00
else
WaitPrompt((char*) "Error opening archive!");
2008-08-12 05:25:16 +02:00
}
else
{
2008-10-14 11:21:34 +02:00
// check that this is a valid ROM
if(!IsValidROM(method))
return 0;
// store the filename (w/o ext) - used for sram/freeze naming
StripExt(Memory.ROMFilename, filelist[selection].filename);
ShowAction ((char *)"Loading...");
SNESROMSize = 0;
switch (method)
{
case METHOD_SD:
case METHOD_USB:
if(inSz)
SNESROMSize = LoadFATSzFile(szpath, (unsigned char *)Memory.ROM);
else
2008-10-15 08:35:14 +02:00
SNESROMSize = LoadFATFile ((char *)Memory.ROM, filelist[selection].length);
2008-10-14 11:21:34 +02:00
break;
case METHOD_DVD:
if(inSz)
SNESROMSize = SzExtractFile(filelist[selection].offset, (unsigned char *)Memory.ROM);
else
2008-10-15 08:35:14 +02:00
SNESROMSize = LoadDVDFile (Memory.ROM, filelist[selection].length);
2008-10-14 11:21:34 +02:00
break;
case METHOD_SMB:
if(inSz)
SNESROMSize = LoadSMBSzFile(szpath, (unsigned char *)Memory.ROM);
else
2008-10-15 08:35:14 +02:00
SNESROMSize = LoadSMBFile ((char *)Memory.ROM, filelist[selection].length);
2008-10-14 11:21:34 +02:00
break;
}
inSz = false;
if (SNESROMSize > 0)
{
Memory.LoadROM ("BLANK.SMC");
Memory.LoadSRAM ("BLANK");
haverom = 1;
return 1;
}
else
{
WaitPrompt((char*) "Error loading ROM!");
}
2008-08-12 05:25:16 +02:00
}
}
redraw = 1;
} // End of A
if ( (p & PAD_BUTTON_B) || (wp & (WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B)) )
{
while ( (PAD_ButtonsDown(0) & PAD_BUTTON_B)
#ifdef HW_RVL
|| (WPAD_ButtonsDown(0) & (WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B))
#endif
)
VIDEO_WaitVSync();
if ( strcmp(filelist[0].filename,"..") == 0 )
{
selection = 0;
selectit = 1;
}
else if ( strcmp(filelist[1].filename,"..") == 0 )
{
selection = selectit = 1;
}
else
{
return 0;
}
} // End of B
if ( ((p | ph) & PAD_BUTTON_DOWN) || ((wp | wh) & (WPAD_BUTTON_DOWN | WPAD_CLASSIC_BUTTON_DOWN)) || (gc_ay < -PADCAL) || (wm_ay < -PADCAL) )
{
if ( (p & PAD_BUTTON_DOWN) || (wp & (WPAD_BUTTON_DOWN | WPAD_CLASSIC_BUTTON_DOWN)) ) { /*** Button just pressed ***/
scroll_delay = SCROLL_INITIAL_DELAY; // reset scroll delay.
move_selection = 1; //continue (move selection)
}
else if (scroll_delay == 0) { /*** Button is held ***/
scroll_delay = SCROLL_LOOP_DELAY;
move_selection = 1; //continue (move selection)
} else {
scroll_delay--; // wait
}
if (move_selection)
{
selection++;
if (selection == maxfiles)
selection = offset = 0;
if ((selection - offset) >= PAGESIZE)
offset += PAGESIZE;
redraw = 1;
move_selection = 0;
}
} // End of down
if ( ((p | ph) & PAD_BUTTON_UP) || ((wp | wh) & (WPAD_BUTTON_UP | WPAD_CLASSIC_BUTTON_UP)) || (gc_ay > PADCAL) || (wm_ay > PADCAL) )
{
if ( (p & PAD_BUTTON_UP) || (wp & (WPAD_BUTTON_UP | WPAD_CLASSIC_BUTTON_UP)) ) { /*** Button just pressed***/
scroll_delay = SCROLL_INITIAL_DELAY; // reset scroll delay.
move_selection = 1; //continue (move selection)
}
else if (scroll_delay == 0) { /*** Button is held ***/
scroll_delay = SCROLL_LOOP_DELAY;
move_selection = 1; //continue (move selection)
} else {
scroll_delay--; // wait
}
if (move_selection)
{
selection--;
if (selection < 0) {
selection = maxfiles - 1;
offset = selection - PAGESIZE + 1;
}
if (selection < offset)
offset -= PAGESIZE;
if (offset < 0)
offset = 0;
redraw = 1;
move_selection = 0;
}
} // End of Up
if ( (p & PAD_BUTTON_LEFT) || (wp & (WPAD_BUTTON_LEFT | WPAD_CLASSIC_BUTTON_LEFT)) )
{
/*** Go back a page ***/
selection -= PAGESIZE;
if (selection < 0)
{
selection = maxfiles - 1;
offset = selection - PAGESIZE + 1;
}
if (selection < offset)
offset -= PAGESIZE;
if (offset < 0)
offset = 0;
redraw = 1;
}
if ( (p & PAD_BUTTON_RIGHT) || (wp & (WPAD_BUTTON_RIGHT | WPAD_CLASSIC_BUTTON_RIGHT)) )
{
/*** Go forward a page ***/
selection += PAGESIZE;
if (selection > maxfiles - 1)
selection = offset = 0;
if ((selection - offset) >= PAGESIZE)
offset += PAGESIZE;
redraw = 1;
}
}
return 0;
}
/****************************************************************************
* OpenDVD
*
* Function to load a DVD directory and display to user.
***************************************************************************/
int
OpenDVD (int method)
{
2008-08-12 05:25:16 +02:00
if (!getpvd())
{
ShowAction((char*) "Loading DVD...");
#ifdef HW_DOL
2008-08-16 02:02:08 +02:00
DVD_Mount(); // mount the DVD unit again
#elif WII_DVD
u32 val;
DI_GetCoverRegister(&val);
if(val & 0x1) // True if no disc inside, use (val & 0x2) for true if disc inside.
{
2008-08-20 09:58:55 +02:00
WaitPrompt((char *)"No disc inserted!");
return 0;
}
DI_Mount();
while(DI_GetStatus() & DVD_INIT);
#endif
2008-08-16 02:02:08 +02:00
2008-08-12 05:25:16 +02:00
if (!getpvd())
{
WaitPrompt ((char *)"Invalid DVD.");
2008-08-16 02:02:08 +02:00
return 0; // not a ISO9660 DVD
}
2008-08-12 05:25:16 +02:00
}
2008-08-16 02:02:08 +02:00
maxfiles = ParseDVDdirectory(); // load root folder
// switch to rom folder
SwitchDVDFolder(GCSettings.LoadFolder);
if (maxfiles > 0)
2008-08-12 05:25:16 +02:00
{
2008-08-16 02:02:08 +02:00
return FileSelector (method);
2008-08-12 05:25:16 +02:00
}
else
2008-08-16 02:02:08 +02:00
{
// no entries found
WaitPrompt ((char *)"No Files Found!");
return 0;
}
}
/****************************************************************************
* OpenSMB
*
* Function to load from an SMB share
***************************************************************************/
int
OpenSMB (int method)
{
// Connect to network share
2008-08-12 05:25:16 +02:00
if(ConnectShare (NOTSILENT))
{
// change current dir to root dir
sprintf(currentdir, "/%s", GCSettings.LoadFolder);
2008-08-12 05:25:16 +02:00
maxfiles = ParseSMBdirectory ();
if (maxfiles > 0)
{
return FileSelector (method);
}
else
{
// no entries found
WaitPrompt ((char *)"No Files Found!");
return 0;
}
}
return 0;
}
/****************************************************************************
* OpenFAT
*
* Function to load from FAT
***************************************************************************/
int
OpenFAT (int method)
{
2008-08-12 05:25:16 +02:00
if(ChangeFATInterface(method, NOTSILENT))
{
// change current dir to snes roms directory
sprintf ( currentdir, "%s/%s", ROOTFATDIR, GCSettings.LoadFolder );
// Parse initial root directory and get entries list
2008-08-12 05:25:16 +02:00
maxfiles = ParseFATdirectory (method);
if (maxfiles > 0)
{
// Select an entry
return FileSelector (method);
}
else
{
// no entries found
WaitPrompt ((char *)"No Files Found!");
return 0;
}
}
return 0;
}
/****************************************************************************
* OpenROM
* Opens device specified by method, displays a list of ROMS
***************************************************************************/
int
OpenROM (int method)
{
int loadROM = 0;
2008-08-07 07:19:17 +02:00
if(method == METHOD_AUTO)
method = autoLoadMethod();
switch (method)
{
case METHOD_SD:
case METHOD_USB:
loadROM = OpenFAT (method);
break;
case METHOD_DVD:
// Load from DVD
loadROM = OpenDVD (method);
break;
case METHOD_SMB:
// Load from Network (SMB)
loadROM = OpenSMB (method);
break;
}
2008-08-07 07:19:17 +02:00
return loadROM;
}