2008-08-06 03:09:59 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Snes9x 1.50
|
|
|
|
*
|
|
|
|
* Nintendo Gamecube Port
|
|
|
|
* softdev July 2006
|
|
|
|
* crunchy2 May 2007
|
|
|
|
*
|
2008-08-07 07:19:17 +02:00
|
|
|
* fileop.cpp
|
2008-08-06 03:09:59 +02:00
|
|
|
*
|
2008-08-07 07:19:17 +02:00
|
|
|
* File operations
|
2008-08-06 03:09:59 +02:00
|
|
|
****************************************************************************/
|
|
|
|
#include <gccore.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ogcsys.h>
|
2008-08-07 07:19:17 +02:00
|
|
|
#include "fileop.h"
|
2008-08-06 03:55:59 +02:00
|
|
|
#include "unzip.h"
|
2008-08-06 03:09:59 +02:00
|
|
|
#include "memmap.h"
|
|
|
|
#include "video.h"
|
2008-08-07 07:19:17 +02:00
|
|
|
#include "menudraw.h"
|
2008-08-06 03:09:59 +02:00
|
|
|
#include "dvd.h"
|
|
|
|
#include "filesel.h"
|
|
|
|
#include "sram.h"
|
|
|
|
#include "preferences.h"
|
2008-08-07 05:25:02 +02:00
|
|
|
#include "snes9xGx.h"
|
2008-08-06 03:09:59 +02:00
|
|
|
|
|
|
|
#include <zlib.h>
|
|
|
|
extern unsigned char savebuffer[];
|
|
|
|
extern char output[16384];
|
2008-08-06 03:39:43 +02:00
|
|
|
FILE * filehandle;
|
2008-08-06 03:55:59 +02:00
|
|
|
|
2008-08-07 05:25:02 +02:00
|
|
|
char currFATdir[MAXPATHLEN];
|
2008-08-06 03:09:59 +02:00
|
|
|
extern int offset;
|
|
|
|
extern int selection;
|
|
|
|
|
2008-08-06 03:39:43 +02:00
|
|
|
extern FILEENTRIES filelist[MAXFILES];
|
2008-08-06 03:09:59 +02:00
|
|
|
|
2008-08-07 05:25:02 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* fat_is_mounted
|
|
|
|
* to check whether FAT media are detected.
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
bool fat_is_mounted(PARTITION_INTERFACE partition) {
|
|
|
|
char prefix[] = "fatX:/";
|
|
|
|
prefix[3] = partition + '0';
|
|
|
|
DIR_ITER *dir = diropen(prefix);
|
|
|
|
if (dir) {
|
|
|
|
dirclose(dir);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-08-08 09:57:01 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* changeFATInterface
|
|
|
|
* Checks if the device (method) specified is available, and
|
|
|
|
* sets libfat to use the device
|
|
|
|
****************************************************************************/
|
|
|
|
bool changeFATInterface(int method)
|
|
|
|
{
|
|
|
|
bool devFound = false;
|
|
|
|
|
|
|
|
if(method == METHOD_SD)
|
|
|
|
{
|
|
|
|
// check which SD device is loaded
|
|
|
|
|
|
|
|
#ifdef HW_RVL
|
|
|
|
if (fat_is_mounted(PI_INTERNAL_SD))
|
|
|
|
{
|
|
|
|
devFound = true;
|
|
|
|
fatSetDefaultInterface(PI_INTERNAL_SD);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!devFound && fat_is_mounted(PI_SDGECKO_A))
|
|
|
|
{
|
|
|
|
devFound = true;
|
|
|
|
fatSetDefaultInterface(PI_SDGECKO_A);
|
|
|
|
}
|
|
|
|
if(!devFound && fat_is_mounted(PI_SDGECKO_B))
|
|
|
|
{
|
|
|
|
devFound = true;
|
|
|
|
fatSetDefaultInterface(PI_SDGECKO_B);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(method == METHOD_USB)
|
|
|
|
{
|
|
|
|
#ifdef HW_RVL
|
|
|
|
if(fat_is_mounted(PI_USBSTORAGE))
|
|
|
|
{
|
|
|
|
devFound = true;
|
|
|
|
fatSetDefaultInterface(PI_USBSTORAGE);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
return devFound;
|
|
|
|
}
|
|
|
|
|
2008-08-07 05:25:02 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* fat_enable_readahead_all
|
|
|
|
****************************************************************************/
|
2008-08-07 07:19:17 +02:00
|
|
|
|
2008-08-07 05:25:02 +02:00
|
|
|
void fat_enable_readahead_all() {
|
|
|
|
int i;
|
|
|
|
for (i=1; i <= 4; ++i) {
|
|
|
|
if (fat_is_mounted((PARTITION_INTERFACE)i)) fatEnableReadAhead((PARTITION_INTERFACE)i, 64, 128);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* fat_remount
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
bool fat_remount(PARTITION_INTERFACE partition) {
|
|
|
|
//ShowAction("remounting...");
|
|
|
|
/* // removed to make usb work...
|
|
|
|
if (fat_is_mounted(partition))
|
|
|
|
{
|
|
|
|
fatUnmount(partition);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
fatMountNormalInterface(partition, 8);
|
|
|
|
fatSetDefaultInterface(partition);
|
|
|
|
//fatEnableReadAhead(partition, 64, 128);
|
|
|
|
|
|
|
|
if (fat_is_mounted(partition))
|
|
|
|
{
|
|
|
|
//ShowAction("remount successful.");
|
|
|
|
sleep(1);
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
ShowAction("FAT mount failed.");
|
|
|
|
sleep(1);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-06 03:55:59 +02:00
|
|
|
/***************************************************************************
|
|
|
|
* FileSortCallback
|
|
|
|
*
|
|
|
|
* Quick sort callback to sort file entries with the following order:
|
|
|
|
* .
|
|
|
|
* ..
|
|
|
|
* <dirs>
|
|
|
|
* <files>
|
2008-08-07 05:25:02 +02:00
|
|
|
***************************************************************************/
|
2008-08-06 03:55:59 +02:00
|
|
|
static 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; }
|
|
|
|
}
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:55:59 +02:00
|
|
|
/* If one is a file and one is a directory the directory is first. */
|
|
|
|
if(((FILEENTRIES *)f1)->flags == 1 && ((FILEENTRIES *)f2)->flags == 0) return -1;
|
|
|
|
if(((FILEENTRIES *)f1)->flags == 0 && ((FILEENTRIES *)f2)->flags == 1) return 1;
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:55:59 +02:00
|
|
|
return stricmp(((FILEENTRIES *)f1)->filename, ((FILEENTRIES *)f2)->filename);
|
|
|
|
}
|
|
|
|
|
2008-08-06 03:09:59 +02:00
|
|
|
/***************************************************************************
|
2008-08-07 05:25:02 +02:00
|
|
|
* Update FATCARD curent directory name
|
|
|
|
***************************************************************************/
|
|
|
|
int updateFATdirname(int method)
|
2008-08-06 03:09:59 +02:00
|
|
|
{
|
2008-08-07 05:25:02 +02:00
|
|
|
int size=0;
|
|
|
|
char *test;
|
|
|
|
char temp[1024];
|
|
|
|
|
|
|
|
/* 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",currFATdir);
|
|
|
|
test = strtok(temp,"/");
|
|
|
|
while (test != NULL)
|
|
|
|
{
|
|
|
|
size = strlen(test);
|
|
|
|
test = strtok(NULL,"/");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remove last subdirectory name */
|
|
|
|
size = strlen(currFATdir) - size - 1;
|
|
|
|
currFATdir[size] = 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
/* Open a directory */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* test new directory namelength */
|
|
|
|
if ((strlen(currFATdir)+1+strlen(filelist[selection].filename)) < MAXPATHLEN)
|
2008-08-06 03:39:43 +02:00
|
|
|
{
|
|
|
|
/* handles root name */
|
2008-08-07 05:25:02 +02:00
|
|
|
sprintf(temp, "/%s/..", GCSettings.LoadFolder);
|
|
|
|
if (strcmp(currFATdir, temp) == 0)
|
|
|
|
{
|
2008-08-08 09:57:01 +02:00
|
|
|
sprintf(currFATdir,"%s",ROOTFATDIR);
|
2008-08-07 05:25:02 +02:00
|
|
|
}
|
|
|
|
|
2008-08-06 03:39:43 +02:00
|
|
|
/* update current directory name */
|
2008-08-07 05:25:02 +02:00
|
|
|
sprintf(currFATdir, "%s/%s",currFATdir, filelist[selection].filename);
|
2008-08-06 03:39:43 +02:00
|
|
|
return 1;
|
2008-08-07 05:25:02 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
WaitPrompt((char*)"Dirname is too long !");
|
2008-08-06 03:39:43 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2008-08-07 05:25:02 +02:00
|
|
|
}
|
2008-08-06 03:09:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
2008-08-07 05:25:02 +02:00
|
|
|
* Browse FAT subdirectories
|
|
|
|
***************************************************************************/
|
2008-08-07 07:19:17 +02:00
|
|
|
int parseFATdirectory(int method)
|
2008-08-07 05:25:02 +02:00
|
|
|
{
|
2008-08-06 03:39:43 +02:00
|
|
|
int nbfiles = 0;
|
2008-08-07 05:25:02 +02:00
|
|
|
DIR_ITER *fatdir;
|
2008-08-06 03:39:43 +02:00
|
|
|
char filename[MAXPATHLEN];
|
|
|
|
struct stat filestat;
|
|
|
|
char msg[128];
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:39:43 +02:00
|
|
|
/* initialize selection */
|
|
|
|
selection = offset = 0;
|
|
|
|
|
2008-08-07 05:25:02 +02:00
|
|
|
/* open the directory */
|
|
|
|
fatdir = diropen(currFATdir);
|
|
|
|
if (fatdir == NULL)
|
|
|
|
{
|
|
|
|
sprintf(msg, "Error opening %s", currFATdir);
|
2008-08-06 03:39:43 +02:00
|
|
|
WaitPrompt(msg);
|
2008-08-07 07:19:17 +02:00
|
|
|
|
2008-08-07 05:25:02 +02:00
|
|
|
// if we can't open the previous dir, open root dir
|
2008-08-08 09:57:01 +02:00
|
|
|
sprintf(currFATdir,"%s",ROOTFATDIR);
|
2008-08-07 07:19:17 +02:00
|
|
|
|
2008-08-07 05:25:02 +02:00
|
|
|
fatdir = diropen(currFATdir);
|
2008-08-07 07:19:17 +02:00
|
|
|
|
|
|
|
if (fatdir == NULL)
|
2008-08-07 05:25:02 +02:00
|
|
|
{
|
|
|
|
sprintf(msg, "Error opening %s", currFATdir);
|
2008-08-06 03:39:43 +02:00
|
|
|
WaitPrompt(msg);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2008-08-07 05:25:02 +02:00
|
|
|
|
|
|
|
/* Move to DVD structure - this is required for the file selector */
|
|
|
|
while(dirnext(fatdir,filename,&filestat) == 0) {
|
2008-08-06 03:39:43 +02:00
|
|
|
if(strcmp(filename,".") != 0) {
|
|
|
|
memset(&filelist[nbfiles], 0, sizeof(FILEENTRIES));
|
|
|
|
strncpy(filelist[nbfiles].filename, filename, MAXPATHLEN);
|
|
|
|
strncpy(filelist[nbfiles].displayname, filename, MAXDISPLAY+1); // crop name for display
|
|
|
|
filelist[nbfiles].length = filestat.st_size;
|
|
|
|
filelist[nbfiles].flags = (filestat.st_mode & _IFDIR) == 0 ? 0 : 1;
|
|
|
|
nbfiles++;
|
|
|
|
}
|
|
|
|
}
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:39:43 +02:00
|
|
|
/*** close directory ***/
|
2008-08-07 05:25:02 +02:00
|
|
|
dirclose(fatdir);
|
|
|
|
|
2008-08-06 03:55:59 +02:00
|
|
|
/* Sort the file list */
|
|
|
|
qsort(filelist, nbfiles, sizeof(FILEENTRIES), FileSortCallback);
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:39:43 +02:00
|
|
|
return nbfiles;
|
2008-08-06 03:09:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
2008-08-07 05:25:02 +02:00
|
|
|
* LoadFATFile
|
2008-08-06 03:09:59 +02:00
|
|
|
****************************************************************************/
|
2008-08-07 05:25:02 +02:00
|
|
|
extern int haveFATdir;
|
2008-08-06 03:09:59 +02:00
|
|
|
int
|
2008-08-07 05:25:02 +02:00
|
|
|
LoadFATFile (char *filename, int length)
|
2008-08-06 03:09:59 +02:00
|
|
|
{
|
|
|
|
char zipbuffer[2048];
|
2008-08-06 03:39:43 +02:00
|
|
|
char filepath[MAXPATHLEN];
|
|
|
|
FILE *handle;
|
2008-08-06 03:55:59 +02:00
|
|
|
unsigned char *rbuffer;
|
|
|
|
u32 size;
|
2008-08-06 03:09:59 +02:00
|
|
|
|
2008-08-06 03:55:59 +02:00
|
|
|
rbuffer = (unsigned char *) Memory.ROM;
|
2008-08-06 03:09:59 +02:00
|
|
|
|
|
|
|
/* Check filename length */
|
2008-08-07 05:25:02 +02:00
|
|
|
if ((strlen(currFATdir)+1+strlen(filelist[selection].filename)) < MAXPATHLEN)
|
|
|
|
sprintf(filepath, "%s/%s",currFATdir,filelist[selection].filename);
|
2008-08-06 03:09:59 +02:00
|
|
|
else
|
|
|
|
{
|
2008-08-07 05:25:02 +02:00
|
|
|
WaitPrompt((char*) "Maximum Filename Length reached !");
|
|
|
|
haveFATdir = 0; // reset everything before next access
|
2008-08-06 03:09:59 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:39:43 +02:00
|
|
|
handle = fopen (filepath, "rb");
|
2008-08-06 03:09:59 +02:00
|
|
|
if (handle > 0)
|
|
|
|
{
|
2008-08-06 03:39:43 +02:00
|
|
|
fread (zipbuffer, 1, 2048, handle);
|
2008-08-06 03:09:59 +02:00
|
|
|
|
2008-08-06 03:39:43 +02:00
|
|
|
if (IsZipFile (zipbuffer))
|
|
|
|
{
|
2008-08-06 03:55:59 +02:00
|
|
|
/*** Unzip the ROM ***/
|
2008-08-07 05:25:02 +02:00
|
|
|
size = UnZipBuffer (rbuffer, 0, 0, handle); // unzip from FAT
|
2008-08-06 03:39:43 +02:00
|
|
|
|
|
|
|
fclose (handle);
|
2008-08-06 03:55:59 +02:00
|
|
|
return size;
|
2008-08-06 03:39:43 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*** Just load the file up ***/
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:39:43 +02:00
|
|
|
fseek(handle, 0, SEEK_END);
|
|
|
|
length = ftell(handle); // get filesize
|
|
|
|
fseek(handle, 2048, SEEK_SET); // seek back to point where we left off
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:39:43 +02:00
|
|
|
sprintf (filepath, "Loading %d bytes", length);
|
|
|
|
ShowAction (filepath);
|
|
|
|
memcpy (rbuffer, zipbuffer, 2048); // copy what we already read
|
|
|
|
fread (rbuffer + 2048, 1, length - 2048, handle);
|
|
|
|
fclose (handle);
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:39:43 +02:00
|
|
|
return length;
|
|
|
|
}
|
2008-08-06 03:09:59 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-08-06 03:39:43 +02:00
|
|
|
WaitPrompt((char*) "Error opening file");
|
2008-08-06 03:09:59 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
2008-08-07 05:25:02 +02:00
|
|
|
* Load savebuffer from FAT file
|
2008-08-06 03:09:59 +02:00
|
|
|
****************************************************************************/
|
|
|
|
int
|
2008-08-07 05:25:02 +02:00
|
|
|
LoadBufferFromFAT (char *filepath, bool silent)
|
2008-08-06 03:09:59 +02:00
|
|
|
{
|
2008-08-07 05:25:02 +02:00
|
|
|
FILE *handle;
|
2008-08-06 03:09:59 +02:00
|
|
|
int offset = 0;
|
|
|
|
int read = 0;
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:39:43 +02:00
|
|
|
handle = fopen (filepath, "rb");
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:09:59 +02:00
|
|
|
if (handle <= 0)
|
|
|
|
{
|
|
|
|
if ( !silent )
|
|
|
|
{
|
|
|
|
char msg[100];
|
|
|
|
sprintf(msg, "Couldn't open %s", filepath);
|
|
|
|
WaitPrompt (msg);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:09:59 +02:00
|
|
|
memset (savebuffer, 0, 0x22000);
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:09:59 +02:00
|
|
|
/*** This is really nice, just load the file and decode it ***/
|
2008-08-06 03:39:43 +02:00
|
|
|
while ((read = fread (savebuffer + offset, 1, 1024, handle)) > 0)
|
2008-08-06 03:09:59 +02:00
|
|
|
{
|
|
|
|
offset += read;
|
|
|
|
}
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:39:43 +02:00
|
|
|
fclose (handle);
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:09:59 +02:00
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
2008-08-07 05:25:02 +02:00
|
|
|
* Write savebuffer to FAT card file
|
2008-08-06 03:09:59 +02:00
|
|
|
****************************************************************************/
|
|
|
|
int
|
2008-08-07 05:25:02 +02:00
|
|
|
SaveBufferToFAT (char *filepath, int datasize, bool silent)
|
2008-08-06 03:09:59 +02:00
|
|
|
{
|
2008-08-07 05:25:02 +02:00
|
|
|
FILE *handle;
|
|
|
|
|
2008-08-06 03:09:59 +02:00
|
|
|
if (datasize)
|
|
|
|
{
|
2008-08-06 03:39:43 +02:00
|
|
|
handle = fopen (filepath, "wb");
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:09:59 +02:00
|
|
|
if (handle <= 0)
|
|
|
|
{
|
|
|
|
char msg[100];
|
|
|
|
sprintf(msg, "Couldn't save %s", filepath);
|
|
|
|
WaitPrompt (msg);
|
|
|
|
return 0;
|
|
|
|
}
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:39:43 +02:00
|
|
|
fwrite (savebuffer, 1, datasize, handle);
|
|
|
|
fclose (handle);
|
2008-08-06 03:09:59 +02:00
|
|
|
}
|
|
|
|
|
2008-08-07 05:25:02 +02:00
|
|
|
return datasize;
|
2008-08-06 03:09:59 +02:00
|
|
|
}
|