snes9xgx/source/ngc/filebrowser.cpp

601 lines
15 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
2009-03-11 18:28:37 +01:00
* Tantric 2008-2009
*
2009-03-28 20:03:35 +01:00
* filebrowser.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 HW_RVL
#include <di/di.h>
2008-08-23 05:20:54 +02:00
#endif
#include "snes9x.h"
#include "memmap.h"
2009-03-11 18:28:37 +01:00
#include "filebrowser.h"
2008-09-09 19:36:48 +02:00
#include "snes9xGX.h"
#include "dvd.h"
2009-03-11 18:28:37 +01:00
#include "menu.h"
#include "video.h"
#include "aram.h"
#include "networkop.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 "gcunzip.h"
2009-03-11 18:28:37 +01:00
#include "cheatmgr.h"
#include "patch.h"
#include "freeze.h"
#include "sram.h"
BROWSERINFO browser;
BROWSERENTRY * browserList = NULL; // list of files/folders in browser
2008-08-16 02:02:08 +02:00
char rootdir[10];
static char szpath[MAXPATHLEN];
static bool inSz = false;
2008-09-27 09:57:03 +02:00
unsigned long SNESROMSize = 0;
2008-09-27 09:13:52 +02:00
/****************************************************************************
* autoLoadMethod()
* Auto-determines and sets the load method
* Returns method set
****************************************************************************/
int autoLoadMethod()
{
2008-12-18 19:36:30 +01:00
ShowAction ("Attempting to determine load method...");
2008-08-12 05:25:16 +02:00
2009-03-11 18:28:37 +01:00
int method = METHOD_AUTO;
2008-12-18 19:36:30 +01:00
if(ChangeInterface(METHOD_SD, SILENT))
method = METHOD_SD;
2008-12-18 19:36:30 +01:00
else if(ChangeInterface(METHOD_USB, SILENT))
method = METHOD_USB;
2008-12-18 19:36:30 +01:00
else if(ChangeInterface(METHOD_DVD, SILENT))
method = METHOD_DVD;
2008-12-18 19:36:30 +01:00
else if(ChangeInterface(METHOD_SMB, SILENT))
method = METHOD_SMB;
else
2009-03-11 18:28:37 +01:00
ErrorPrompt("Unable to auto-determine load method!");
if(GCSettings.LoadMethod == METHOD_AUTO)
GCSettings.LoadMethod = method; // save method found for later use
2009-03-11 18:28:37 +01:00
CancelAction();
return method;
}
/****************************************************************************
* autoSaveMethod()
* Auto-determines and sets the save method
* Returns method set
****************************************************************************/
int autoSaveMethod(bool silent)
{
if(!silent)
ShowAction ("Attempting to determine save method...");
2009-03-11 18:28:37 +01:00
int method = METHOD_AUTO;
2008-08-12 05:25:16 +02:00
2008-12-18 19:36:30 +01:00
if(ChangeInterface(METHOD_SD, SILENT))
method = METHOD_SD;
2008-12-18 19:36:30 +01:00
else if(ChangeInterface(METHOD_USB, SILENT))
method = METHOD_USB;
2009-03-11 18:28:37 +01:00
else if(ChangeInterface(METHOD_MC_SLOTA, SILENT))
method = METHOD_MC_SLOTA;
2009-03-11 18:28:37 +01:00
else if(ChangeInterface(METHOD_MC_SLOTB, SILENT))
method = METHOD_MC_SLOTB;
2008-12-18 19:36:30 +01:00
else if(ChangeInterface(METHOD_SMB, SILENT))
method = METHOD_SMB;
else if(!silent)
2009-03-11 18:28:37 +01:00
ErrorPrompt("Unable to auto-determine save method!");
if(GCSettings.SaveMethod == METHOD_AUTO)
GCSettings.SaveMethod = method; // save method found for later use
2009-03-11 18:28:37 +01:00
CancelAction();
return method;
}
/****************************************************************************
* ResetBrowser()
* Clears the file browser memory, and allocates one initial entry
***************************************************************************/
void ResetBrowser()
{
2009-03-11 18:28:37 +01:00
browser.numEntries = 0;
browser.selIndex = 0;
browser.pageIndex = 0;
// Clear any existing values
if(browserList != NULL)
{
free(browserList);
browserList = NULL;
}
// set aside space for 1 entry
browserList = (BROWSERENTRY *)malloc(sizeof(BROWSERENTRY));
memset(browserList, 0, sizeof(BROWSERENTRY));
}
2009-06-12 09:47:42 +02:00
/****************************************************************************
* CleanupPath()
* Cleans up the filepath, removing double // and replacing \ with /
***************************************************************************/
static void CleanupPath(char * path)
{
int pathlen = strlen(path);
int j = 0;
for(int i=0; i < pathlen && i < MAXPATHLEN; i++)
{
if(path[i] == '\\')
path[i] = '/';
if(j == 0 || !(path[j-1] == '/' && path[i] == '/'))
path[j++] = path[i];
}
path[j] = 0;
if(strlen(path) == 0)
sprintf(path, "/");
}
/****************************************************************************
* 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-11-12 08:50:39 +01:00
// update DVD directory
2008-08-16 02:02:08 +02:00
if(method == METHOD_DVD)
SetDVDdirectory(browserList[browser.selIndex].offset, browserList[browser.selIndex].length);
2008-08-16 02:02:08 +02:00
/* current directory doesn't change */
if (strcmp(browserList[browser.selIndex].filename,".") == 0)
{
return 0;
}
/* go up to parent directory */
else if (strcmp(browserList[browser.selIndex].filename,"..") == 0)
{
/* determine last subdirectory namelength */
sprintf(temp,"%s",browser.dir);
test = strtok(temp,"/");
while (test != NULL)
{
size = strlen(test);
test = strtok(NULL,"/");
}
/* remove last subdirectory name */
size = strlen(browser.dir) - size - 1;
browser.dir[size] = 0;
return 1;
}
/* Open a directory */
else
{
/* test new directory namelength */
if ((strlen(browser.dir)+1+strlen(browserList[browser.selIndex].filename)) < MAXPATHLEN)
{
/* update current directory name */
2009-06-12 09:47:42 +02:00
sprintf(browser.dir, "%s%s/",browser.dir, browserList[browser.selIndex].filename);
return 1;
}
else
{
2009-03-11 18:28:37 +01:00
ErrorPrompt("Directory name is too long!");
return -1;
}
}
}
2009-03-16 07:58:50 +01:00
bool MakeFilePath(char filepath[], int type, int method, char * filename, int filenum)
2008-10-14 11:21:34 +02:00
{
2008-11-12 08:50:39 +01:00
char file[512];
char folder[1024];
2009-03-19 17:51:36 +01:00
char ext[4];
2008-10-14 11:21:34 +02:00
char temppath[MAXPATHLEN];
2008-11-12 08:50:39 +01:00
if(type == FILE_ROM)
2008-10-14 11:21:34 +02:00
{
2008-11-12 08:50:39 +01:00
// Check path length
if ((strlen(browser.dir)+1+strlen(browserList[browser.selIndex].filename)) >= MAXPATHLEN)
2008-11-12 08:50:39 +01:00
{
2009-03-11 18:28:37 +01:00
ErrorPrompt("Maximum filepath length reached!");
2008-11-12 08:50:39 +01:00
filepath[0] = 0;
return false;
}
2008-10-14 11:21:34 +02:00
else
2008-11-12 08:50:39 +01:00
{
2009-06-12 09:47:42 +02:00
sprintf(temppath, "%s%s",browser.dir,browserList[browser.selIndex].filename);
2008-11-12 08:50:39 +01:00
}
2008-10-14 11:21:34 +02:00
}
else
{
2008-11-12 08:50:39 +01:00
switch(type)
{
case FILE_SRAM:
case FILE_SNAPSHOT:
sprintf(folder, GCSettings.SaveFolder);
2009-03-16 07:58:50 +01:00
2009-03-19 17:51:36 +01:00
if(type == FILE_SRAM) sprintf(ext, "srm");
else sprintf(ext, "frz");
if(filenum >= -1)
2009-03-16 07:58:50 +01:00
{
if(method == METHOD_MC_SLOTA || method == METHOD_MC_SLOTB)
{
if(filenum > 9)
{
return false;
}
else if(filenum == -1)
{
filename[27] = 0; // truncate filename
sprintf(file, "%s.%s", filename, ext);
}
else
{
filename[26] = 0; // truncate filename
sprintf(file, "%s%i.%s", filename, filenum, ext);
}
2009-03-16 07:58:50 +01:00
}
else
{
if(filenum == -1)
sprintf(file, "%s.%s", filename, ext);
else if(filenum == 0)
2009-03-20 08:30:29 +01:00
sprintf(file, "%s Auto.%s", filename, ext);
2009-03-16 07:58:50 +01:00
else
2009-03-20 08:30:29 +01:00
sprintf(file, "%s %i.%s", filename, filenum, ext);
2009-03-16 07:58:50 +01:00
}
}
else
{
2009-03-17 06:21:25 +01:00
sprintf(file, "%s", filename);
2009-03-16 07:58:50 +01:00
}
2008-11-12 08:50:39 +01:00
break;
case FILE_CHEAT:
sprintf(folder, GCSettings.CheatFolder);
sprintf(file, "%s.cht", Memory.ROMFilename);
break;
case FILE_PREF:
sprintf(folder, appPath);
2008-11-12 08:50:39 +01:00
sprintf(file, "%s", PREF_FILE_NAME);
break;
case FILE_SCREEN:
2009-03-19 17:51:36 +01:00
sprintf(folder, GCSettings.SaveFolder);
sprintf(file, "%s.png", Memory.ROMFilename);
break;
2008-11-12 08:50:39 +01:00
}
switch(method)
{
case METHOD_MC_SLOTA:
case METHOD_MC_SLOTB:
sprintf (temppath, "%s", file);
temppath[31] = 0; // truncate filename
break;
2008-12-18 19:36:30 +01:00
default:
2009-06-12 09:47:42 +02:00
sprintf (temppath, "/%s/%s", folder, file);
2008-12-18 19:36:30 +01:00
break;
2008-11-12 08:50:39 +01:00
}
}
2009-06-12 09:47:42 +02:00
CleanupPath(temppath); // cleanup path
2009-03-16 07:58:50 +01:00
strncpy(filepath, temppath, MAXPATHLEN);
2008-11-12 08:50:39 +01:00
return true;
}
/****************************************************************************
* 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(((BROWSERENTRY *)f1)->filename[0] == '.' || ((BROWSERENTRY *)f2)->filename[0] == '.')
{
if(strcmp(((BROWSERENTRY *)f1)->filename, ".") == 0) { return -1; }
if(strcmp(((BROWSERENTRY *)f2)->filename, ".") == 0) { return 1; }
if(strcmp(((BROWSERENTRY *)f1)->filename, "..") == 0) { return -1; }
if(strcmp(((BROWSERENTRY *)f2)->filename, "..") == 0) { return 1; }
}
/* If one is a file and one is a directory the directory is first. */
if(((BROWSERENTRY *)f1)->isdir && !(((BROWSERENTRY *)f2)->isdir)) return -1;
if(!(((BROWSERENTRY *)f1)->isdir) && ((BROWSERENTRY *)f2)->isdir) return 1;
return stricmp(((BROWSERENTRY *)f1)->filename, ((BROWSERENTRY *)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
***************************************************************************/
2009-03-11 18:28:37 +01:00
static bool IsValidROM(int method)
{
// file size should be between 96K and 8MB
if(browserList[browser.selIndex].length < (1024*96) ||
2009-03-11 18:28:37 +01:00
browserList[browser.selIndex].length > Memory.MAX_ROM_SIZE)
{
2009-03-11 18:28:37 +01:00
ErrorPrompt("Invalid file size!");
return false;
}
if (strlen(browserList[browser.selIndex].filename) > 4)
{
char * p = strrchr(browserList[browser.selIndex].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;
}
}
}
}
2009-03-11 18:28:37 +01:00
ErrorPrompt("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(browserList[browser.selIndex].filename) > 4)
2008-10-14 11:21:34 +02:00
{
char * p = strrchr(browserList[browser.selIndex].filename, '.');
2008-10-14 11:21:34 +02:00
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
strncpy (returnstring, inputstring, MAXJOLIET);
2009-03-11 18:28:37 +01:00
if(inputstring == NULL || strlen(inputstring) < 4)
return;
loc_dot = strrchr(returnstring,'.');
if (loc_dot != NULL)
2008-09-27 10:36:22 +02:00
*loc_dot = 0; // strip file extension
}
2009-03-28 20:03:35 +01:00
/****************************************************************************
* BrowserLoadSz
*
* Opens the selected 7z file, and parses a listing of the files within
***************************************************************************/
2009-03-11 18:28:37 +01:00
int BrowserLoadSz(int method)
{
2009-03-11 18:28:37 +01:00
char filepath[MAXPATHLEN];
memset(filepath, 0, MAXPATHLEN);
2009-03-11 18:28:37 +01:00
// we'll store the 7z filepath for extraction later
if(!MakeFilePath(szpath, FILE_ROM, method))
return 0;
2009-03-11 18:28:37 +01:00
// add device to filepath
2009-04-07 01:03:57 +02:00
if(method != METHOD_DVD)
{
sprintf(filepath, "%s%s", rootdir, szpath);
memcpy(szpath, filepath, MAXPATHLEN);
}
2009-03-11 18:28:37 +01:00
int szfiles = SzParse(szpath, method);
if(szfiles)
{
browser.numEntries = szfiles;
inSz = true;
}
else
ErrorPrompt("Error opening archive!");
2008-10-14 11:21:34 +02:00
2009-03-11 18:28:37 +01:00
return szfiles;
}
2009-03-28 20:03:35 +01:00
/****************************************************************************
* BrowserLoadFile
*
* Loads the selected ROM
***************************************************************************/
2009-03-11 18:28:37 +01:00
int BrowserLoadFile(int method)
{
char filepath[1024];
int loaded = 0;
2008-10-14 11:21:34 +02:00
2009-03-11 18:28:37 +01:00
// check that this is a valid ROM
if(!IsValidROM(method))
goto done;
2009-03-11 18:28:37 +01:00
// store the filename (w/o ext) - used for sram/freeze naming
StripExt(Memory.ROMFilename, browserList[browser.selIndex].filename);
2009-03-11 18:28:37 +01:00
SNESROMSize = 0;
S9xDeleteCheats();
2009-03-11 18:28:37 +01:00
if(!inSz)
{
if(!MakeFilePath(filepath, FILE_ROM, method))
goto done;
SNESROMSize = LoadFile ((char *)Memory.ROM, filepath, browserList[browser.selIndex].length, method, NOTSILENT);
}
else
{
switch (method)
{
2009-03-11 18:28:37 +01:00
case METHOD_DVD:
SNESROMSize = SzExtractFile(browserList[browser.selIndex].offset, (unsigned char *)Memory.ROM);
break;
default:
SNESROMSize = LoadSzFile(szpath, (unsigned char *)Memory.ROM);
break;
}
}
2009-03-11 18:28:37 +01:00
inSz = false;
if (SNESROMSize <= 0)
{
ErrorPrompt("Error loading ROM!");
}
else
{
// load UPS/IPS/PPF patch
LoadPatch(GCSettings.LoadMethod);
Memory.LoadROM ("BLANK.SMC");
Memory.LoadSRAM ("BLANK");
// load SRAM or snapshot
if (GCSettings.AutoLoad == 1)
LoadSRAMAuto(GCSettings.SaveMethod, SILENT);
else if (GCSettings.AutoLoad == 2)
NGCUnfreezeGameAuto(GCSettings.SaveMethod, SILENT);
// setup cheats
if(GCSettings.SaveMethod != METHOD_MC_SLOTA &&
GCSettings.SaveMethod != METHOD_MC_SLOTB)
SetupCheats();
ResetBrowser();
loaded = 1;
}
done:
CancelAction();
return loaded;
}
2009-03-28 20:03:35 +01:00
/****************************************************************************
* BrowserChangeFolder
*
* Update current directory and set new entry list if directory has changed
***************************************************************************/
2009-03-11 18:28:37 +01:00
int BrowserChangeFolder(int method)
{
if(inSz && browser.selIndex == 0) // inside a 7z, requesting to leave
{
if(method == METHOD_DVD)
SetDVDdirectory(browserList[0].offset, browserList[0].length);
inSz = false;
SzClose();
}
if(!UpdateDirName(method))
return -1;
2009-06-12 09:47:42 +02:00
CleanupPath(browser.dir);
strcpy(GCSettings.LoadFolder, browser.dir);
2009-06-12 09:47:42 +02:00
2009-03-11 18:28:37 +01:00
switch (method)
{
case METHOD_DVD:
2009-03-23 06:53:21 +01:00
ParseDVDdirectory();
2009-03-11 18:28:37 +01:00
break;
default:
ParseDirectory(method);
2009-03-11 18:28:37 +01:00
break;
}
if (!browser.numEntries)
{
ErrorPrompt("Error reading directory!");
}
return browser.numEntries;
}
/****************************************************************************
2008-12-18 19:36:30 +01:00
* OpenROM
2009-03-11 18:28:37 +01:00
* Displays a list of ROMS on load device
***************************************************************************/
int
2009-03-11 18:28:37 +01:00
OpenGameList ()
{
2009-03-11 18:28:37 +01:00
int method = GCSettings.LoadMethod;
2008-12-18 19:36:30 +01:00
if(method == METHOD_AUTO)
method = autoLoadMethod();
// change current dir to roms directory
switch(method)
2008-12-18 19:36:30 +01:00
{
case METHOD_DVD:
browser.dir[0] = 0;
2009-03-23 06:53:21 +01:00
if(MountDVD(NOTSILENT))
if(ParseDVDdirectory()) // Parse root directory
SwitchDVDFolder(GCSettings.LoadFolder); // switch to ROM folder
break;
default:
2009-06-12 09:47:42 +02:00
sprintf(browser.dir, "/%s/", GCSettings.LoadFolder);
CleanupPath(browser.dir);
ParseDirectory(method); // Parse root directory
break;
2009-03-11 18:28:37 +01:00
}
return browser.numEntries;
}