Genesis-Plus-GX/source/gx/fileio/file_mem.c

650 lines
18 KiB
C
Raw Normal View History

2008-12-11 18:38:29 +01:00
/*
* file_mem.c
2008-08-07 14:26:07 +02:00
*
2008-12-11 18:38:29 +01:00
* FAT and Memory Card SRAM/Savestate files managment
*
* Softdev (2006)
* Eke-Eke (2007,2008,2009)
2008-12-11 18:38:29 +01:00
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2008-08-07 14:26:07 +02:00
*
***************************************************************************/
2008-12-11 18:38:29 +01:00
2008-08-07 14:26:07 +02:00
#include "shared.h"
#include "file_mem.h"
#include "file_fat.h"
#include "dvd.h"
#include "gui.h"
#include "filesel.h"
#include "saveicon.h"
2008-08-07 14:26:07 +02:00
/* Global ROM filename */
char rom_filename[MAXJOLIET];
2008-08-07 14:26:07 +02:00
/* Support for MemCards */
/**
* libOGC System Work Area
*/
static u8 SysArea[CARD_WORKAREA] ATTRIBUTE_ALIGN (32);
static card_dir CardDir;
static card_file CardFile;
static card_stat CardStatus;
/**
* DMA Transfer Area.
* Must be 32-byte aligned.
* 64k SRAM + 2k Icon
*/
static u8 savebuffer[STATE_SIZE] ATTRIBUTE_ALIGN (32);
2008-08-07 14:26:07 +02:00
/****************************************************************************
* SDCARD Access functions
*
* We use the same buffer as for Memory Card manager
* Function returns TRUE on success.
*****************************************************************************/
static int FAT_ManageFile(char *filename, u8 direction, u8 filetype)
2008-08-07 14:26:07 +02:00
{
char fname[MAXPATHLEN];
2008-08-07 14:26:07 +02:00
int done = 0;
int filesize;
/* build complete SDCARD filename */
sprintf (fname, "%s/saves/%s", DEFAULT_PATH, filename);
2008-08-07 14:26:07 +02:00
/* open file */
FILE *fp = fopen(fname, direction ? "rb" : "wb");
2008-08-07 14:26:07 +02:00
if (fp == NULL)
{
GUI_WaitPrompt("Error","Unable to open file !");
2008-08-07 14:26:07 +02:00
return 0;
}
2008-12-10 19:16:30 +01:00
switch (direction)
{
case 0: /* SAVING */
2008-08-07 14:26:07 +02:00
2008-12-10 19:16:30 +01:00
if (filetype) /* SRAM */
{
memcpy(savebuffer, sram.sram, 0x10000);
sram.crc = crc32 (0, sram.sram, 0x10000);
filesize = 0x10000;
2008-12-10 19:16:30 +01:00
}
else filesize = state_save(savebuffer); /* STATE */
2008-08-07 14:26:07 +02:00
/* write buffer (2k blocks) */
while (filesize > FATCHUNK)
{
fwrite(savebuffer + done, FATCHUNK, 1, fp);
filesize -= FATCHUNK;
done += FATCHUNK;
}
done += fwrite(savebuffer + done, filesize, 1, fp);
fclose(fp);
2008-08-07 14:26:07 +02:00
if (done < filesize)
{
GUI_WaitPrompt("Error","Unable to write file !");
2008-08-07 14:26:07 +02:00
return 0;
}
GUI_MsgBoxClose();
2008-08-07 14:26:07 +02:00
return 1;
2008-12-10 19:16:30 +01:00
case 1: /* LOADING */
2008-08-07 14:26:07 +02:00
/* read size */
fseek(fp , 0 , SEEK_END);
filesize = ftell (fp);
fseek(fp, 0, SEEK_SET);
/* read into buffer (2k blocks) */
while (filesize > FATCHUNK)
{
fread(savebuffer + done, FATCHUNK, 1, fp);
filesize -= FATCHUNK;
done += FATCHUNK;
}
done += fread(savebuffer + done, filesize, 1, fp);
fclose(fp);
2008-08-07 14:26:07 +02:00
if (done < filesize)
{
GUI_WaitPrompt("Error","Unable to read file !");
2008-08-07 14:26:07 +02:00
return 0;
}
2008-12-10 19:16:30 +01:00
if (filetype) /* SRAM */
{
memcpy(sram.sram, savebuffer, done);
2008-12-10 19:16:30 +01:00
sram.crc = crc32 (0, sram.sram, 0x10000);
}
else
{
/* STATE */
if (!state_load(savebuffer))
{
GUI_WaitPrompt("Error","File version is not compatible !");
return 0;
}
}
2008-12-10 19:16:30 +01:00
GUI_MsgBoxClose();
2008-12-10 19:16:30 +01:00
return 1;
}
return 0;
2008-08-07 14:26:07 +02:00
}
/****************************************************************************
* MountTheCard
*
* libOGC provides the CARD_Mount function, and it should be all you need.
* However, experience with previous emulators has taught me that you are
* better off doing a little bit more than that!
*
* Function returns TRUE on success.
*****************************************************************************/
static int MountTheCard (u8 slot)
2008-08-07 14:26:07 +02:00
{
2008-12-10 19:16:30 +01:00
int tries = 0;
int CardError;
#if defined(HW_DOL)
*(unsigned long *) (0xCC006800) |= 1 << 13; /*** Disable Encryption ***/
2008-12-10 19:16:30 +01:00
uselessinquiry ();
#elif defined(HW_RVL)
*(unsigned long *) (0xCD006800) |= 1 << 13; /*** Disable Encryption ***/
2008-08-07 14:26:07 +02:00
#endif
while (tries < 10)
{
VIDEO_WaitVSync ();
2008-12-10 19:16:30 +01:00
CardError = CARD_Mount (slot, SysArea, NULL); /*** Don't need or want a callback ***/
if (CardError == 0)
return 1;
else
EXI_ProbeReset ();
2008-12-10 19:16:30 +01:00
tries++;
}
return 0;
2008-08-07 14:26:07 +02:00
}
/****************************************************************************
* CardFileExists
*
* Wrapper to search through the files on the card.
* Returns TRUE if found.
****************************************************************************/
static int CardFileExists (char *filename, u8 slot)
2008-08-07 14:26:07 +02:00
{
2008-12-10 19:16:30 +01:00
int CardError = CARD_FindFirst (slot, &CardDir, TRUE);
while (CardError != CARD_ERROR_NOFILE)
{
CardError = CARD_FindNext (&CardDir);
if (strcmp ((char *) CardDir.filename, filename) == 0)
return 1;
2008-12-10 19:16:30 +01:00
}
return 0;
2008-08-07 14:26:07 +02:00
}
/****************************************************************************
* FILE autoload (SRAM/FreezeState or Config File)
*
*
*****************************************************************************/
void memfile_autoload(s8 autosram, s8 autostate)
{
/* this should be transparent to the user */
SILENT = 1;
/* SRAM */
if (autosram != -1)
ManageSRAM(1,autosram);
/* STATE */
if (autostate != -1)
ManageState(1,autostate);
SILENT = 0;
}
void memfile_autosave(s8 autosram, s8 autostate)
{
int crccheck = crc32 (0, sram.sram, 0x10000);
/* this should be transparent to the user */
SILENT = 1;
/* SRAM */
if ((autosram != -1) && (crccheck != sram.crc))
ManageSRAM(0, autosram);
/* STATE */
if (autostate != -1)
ManageState(0,autostate);
SILENT = 0;
}
2008-08-07 14:26:07 +02:00
/****************************************************************************
* ManageSRAM
*
* Here is the main SRAM Management stuff.
* The output file contains an icon (2K), 64 bytes comment and the SRAM (64k).
* As memcards are allocated in blocks of 8k or more, you have a around
* 6k bytes to save/load any other data you wish without altering any of the
* main save / load code.
*
* direction == 0 save, 1 load.
****************************************************************************/
int ManageSRAM (u8 direction, u8 device)
{
if (!cart.romsize)
return 0;
char filename[MAXJOLIET];
if (direction)
GUI_MsgBoxOpen("Information","Loading SRAM ...",1);
else
GUI_MsgBoxOpen("Information","Saving SRAM ...",1);
/* clean buffer */
memset(savebuffer, 0, STATE_SIZE);
if (device == 0)
{
/* FAT support */
sprintf (filename, "%s.srm", rom_filename);
return FAT_ManageFile(filename,direction,1);
}
/* Memory CARD support */
2008-12-10 19:16:30 +01:00
char action[80];
int CardError;
unsigned int SectorSize = 0;
2008-12-10 19:16:30 +01:00
int blocks;
char comment[2][32] = { {"Genesis Plus 1.2a"}, {"SRAM Save"} };
2008-08-07 14:26:07 +02:00
int outbytes = 0;
2008-12-10 19:16:30 +01:00
int sbo;
unsigned long inzipped,outzipped;
2008-08-07 14:26:07 +02:00
2008-12-10 19:16:30 +01:00
/* First, build a filename */
sprintf (filename, "MD-%04X.srm", realchecksum);
strcpy (comment[1], filename);
2008-08-07 14:26:07 +02:00
/* set MCARD slot nr. */
u8 CARDSLOT = device - 1;
/* Saving */
if (direction == 0)
2008-12-10 19:16:30 +01:00
{
/*** Build the output buffer ***/
memcpy (&savebuffer, &icon, 2048);
memcpy (&savebuffer[2048], &comment[0], 64);
inzipped = 0x10000;
outzipped = 0x12000;
compress2 ((Bytef *) &savebuffer[2112+sizeof(outzipped)], &outzipped, (Bytef *) &sram.sram, inzipped, 9);
memcpy(&savebuffer[2112], &outzipped, sizeof(outzipped));
}
outbytes = 2048 + 64 + outzipped + sizeof(outzipped);
/*** Initialise the CARD system ***/
memset (&SysArea, 0, CARD_WORKAREA);
CARD_Init ("GENP", "00");
/*** Attempt to mount the card ***/
CardError = MountTheCard (CARDSLOT);
if (CardError)
{
/*** Retrieve the sector size ***/
CardError = CARD_GetSectorSize (CARDSLOT, &SectorSize);
if (SectorSize)
2008-12-10 19:16:30 +01:00
{
switch (direction)
{
case 0: /*** Saving ***/
2008-12-10 19:16:30 +01:00
/*** Determine number of blocks on this card ***/
blocks = (outbytes / SectorSize) * SectorSize;
if (outbytes % SectorSize)
blocks += SectorSize;
2008-12-10 19:16:30 +01:00
/*** Check if a previous save exists ***/
if (CardFileExists (filename,CARDSLOT))
2008-12-10 19:16:30 +01:00
{
CardError = CARD_Open (CARDSLOT, filename, &CardFile);
2008-12-10 19:16:30 +01:00
if (CardError)
{
sprintf (action, "Unable to open file (%d)", CardError);
GUI_WaitPrompt("Error",action);
2008-12-10 19:16:30 +01:00
CARD_Unmount (CARDSLOT);
return 0;
}
int size = CardFile.len;
2008-12-10 19:16:30 +01:00
CARD_Close (&CardFile);
if (size < blocks)
{
/* new size is bigger: check if there is enough space left */
CardError = CARD_Create (CARDSLOT, "TEMP", blocks-size, &CardFile);
if (CardError)
{
sprintf (action, "Unable to create temporary file (%d)", CardError);
GUI_WaitPrompt("Error",action);
CARD_Unmount (CARDSLOT);
return 0;
}
CARD_Close (&CardFile);
CARD_Delete(CARDSLOT, "TEMP");
}
/* always delete existing slot */
CARD_Delete(CARDSLOT, filename);
2008-12-10 19:16:30 +01:00
}
/*** Create a new slot ***/
CardError = CARD_Create (CARDSLOT, filename, blocks, &CardFile);
if (CardError)
{
sprintf (action, "Unable to create new file (%d)", CardError);
GUI_WaitPrompt("Error",action);
CARD_Unmount (CARDSLOT);
return 0;
}
2008-12-10 19:16:30 +01:00
/*** Continue and save ***/
CARD_GetStatus (CARDSLOT, CardFile.filenum, &CardStatus);
CardStatus.icon_addr = 0x0;
CardStatus.icon_fmt = 2;
CardStatus.icon_speed = 1;
CardStatus.comment_addr = 2048;
CARD_SetStatus (CARDSLOT, CardFile.filenum, &CardStatus);
/*** And write the blocks out ***/
sbo = 0;
while (outbytes > 0)
{
CardError = CARD_Write (&CardFile, &savebuffer[sbo], SectorSize, sbo);
outbytes -= SectorSize;
sbo += SectorSize;
}
CARD_Close (&CardFile);
2008-12-10 19:16:30 +01:00
CARD_Unmount (CARDSLOT);
sram.crc = crc32 (0, &sram.sram[0], 0x10000);
GUI_MsgBoxClose();
return 1;
2008-12-10 19:16:30 +01:00
default: /*** Loading ***/
2008-12-10 19:16:30 +01:00
if (!CardFileExists (filename,CARDSLOT))
{
GUI_WaitPrompt("Error","File does not exist !");
CARD_Unmount (CARDSLOT);
return 0;
}
2008-12-10 19:16:30 +01:00
memset (&CardFile, 0, sizeof (CardFile));
CardError = CARD_Open (CARDSLOT, filename, &CardFile);
if (CardError)
{
sprintf (action, "Unable to open file (%d)", CardError);
GUI_WaitPrompt("Error",action);
CARD_Unmount (CARDSLOT);
return 0;
}
2008-12-10 19:16:30 +01:00
blocks = CardFile.len;
if (blocks < SectorSize)
blocks = SectorSize;
if (blocks % SectorSize)
blocks++;
2008-12-10 19:16:30 +01:00
/*** Just read the file back in ***/
sbo = 0;
while (blocks > 0)
{
CARD_Read (&CardFile, &savebuffer[sbo], SectorSize, sbo);
sbo += SectorSize;
blocks -= SectorSize;
}
CARD_Close (&CardFile);
CARD_Unmount (CARDSLOT);
/*** update SRAM ***/
memcpy(&inzipped,&savebuffer[2112],sizeof(inzipped));
outzipped = 0x10000;
uncompress ((Bytef *) &sram.sram, &outzipped, (Bytef *) &savebuffer[2112+sizeof(inzipped)], inzipped);
sram.crc = crc32 (0, &sram.sram[0], 0x10000);
GUI_MsgBoxClose();
return 1;
}
2008-12-10 19:16:30 +01:00
}
GUI_WaitPrompt("Error","Invalid sector size");
return 0;
2008-12-10 19:16:30 +01:00
}
GUI_WaitPrompt("Error","Unable to mount memory card");
return 0;
2008-08-07 14:26:07 +02:00
}
/****************************************************************************
* ManageState
*
* Here is the main Freeze File Management stuff.
* The output file contains an icon (2K), 64 bytes comment and the STATE (~128k)
*
* direction == 0 save, 1 load.
****************************************************************************/
int ManageState (u8 direction, u8 device)
{
if (!cart.romsize)
return 0;
char filename[MAXJOLIET];
if (direction)
GUI_MsgBoxOpen("Information","Loading State ...",1);
else
GUI_MsgBoxOpen("Information","Saving State ...",1);
/* clean buffer */
memset(savebuffer, 0, STATE_SIZE);
if (device == 0)
{
/* FAT support */
sprintf (filename, "%s.gpz", rom_filename);
return FAT_ManageFile(filename,direction,0);
}
/* Memory CARD support */
2008-12-10 19:16:30 +01:00
char action[80];
int CardError;
unsigned int SectorSize;
int blocks;
char comment[2][32] = { {"Genesis Plus 1.2a [FRZ]"}, {"Freeze State"} };
int outbytes = 0;
int sbo;
int state_size = 0;
2008-08-07 14:26:07 +02:00
2008-12-10 19:16:30 +01:00
/* First, build a filename */
sprintf (filename, "MD-%04X.gpz", realchecksum);
strcpy (comment[1], filename);
2008-08-07 14:26:07 +02:00
/* set MCARD slot nr. */
u8 CARDSLOT = device - 1;
/* Saving */
if (direction == 0)
2008-12-10 19:16:30 +01:00
{
/* Build the output buffer */
memcpy (&savebuffer, &icon, 2048);
memcpy (&savebuffer[2048], &comment[0], 64);
state_size = state_save(&savebuffer[2112]);
}
outbytes = 2048 + 64 + state_size;
/*** Initialise the CARD system ***/
memset (&SysArea, 0, CARD_WORKAREA);
CARD_Init ("GENP", "00");
/*** Attempt to mount the card ***/
CardError = MountTheCard (CARDSLOT);
if (CardError)
{
/*** Retrieve the sector size ***/
CardError = CARD_GetSectorSize (CARDSLOT, &SectorSize);
if (SectorSize)
2008-12-10 19:16:30 +01:00
{
switch (direction)
{
case 0: /*** Saving ***/
/*** Determine number of blocks on this card ***/
blocks = (outbytes / SectorSize) * SectorSize;
if (outbytes % SectorSize)
blocks += SectorSize;
/*** Check if a previous save exists ***/
if (CardFileExists (filename, CARDSLOT))
2008-12-10 19:16:30 +01:00
{
CardError = CARD_Open (CARDSLOT, filename, &CardFile);
2008-12-10 19:16:30 +01:00
if (CardError)
{
sprintf (action, "Unable to open file (%d)", CardError);
GUI_WaitPrompt("Error",action);
2008-12-10 19:16:30 +01:00
CARD_Unmount (CARDSLOT);
return 0;
}
int size = CardFile.len;
2008-12-10 19:16:30 +01:00
CARD_Close (&CardFile);
if (size < blocks)
{
/* new size is bigger: check if there is enough space left */
CardError = CARD_Create (CARDSLOT, "TEMP", blocks-size, &CardFile);
if (CardError)
{
sprintf (action, "Unable to create temporary file (%d)", CardError);
GUI_WaitPrompt("Error",action);
CARD_Unmount (CARDSLOT);
return 0;
}
CARD_Close (&CardFile);
CARD_Delete(CARDSLOT, "TEMP");
}
/* always delete existing slot */
CARD_Delete(CARDSLOT, filename);
2008-12-10 19:16:30 +01:00
}
/*** Create a new slot ***/
CardError = CARD_Create (CARDSLOT, filename, blocks, &CardFile);
if (CardError)
{
sprintf (action, "Unable to create new file (%d)", CardError);
GUI_WaitPrompt("Error",action);
CARD_Unmount (CARDSLOT);
return 0;
}
/*** Continue and save ***/
CARD_GetStatus (CARDSLOT, CardFile.filenum, &CardStatus);
CardStatus.icon_addr = 0x0;
CardStatus.icon_fmt = 2;
CardStatus.icon_speed = 1;
CardStatus.comment_addr = 2048;
CARD_SetStatus (CARDSLOT, CardFile.filenum, &CardStatus);
/*** And write the blocks out ***/
sbo = 0;
while (outbytes > 0)
{
CardError = CARD_Write (&CardFile, &savebuffer[sbo], SectorSize, sbo);
outbytes -= SectorSize;
sbo += SectorSize;
}
2008-12-10 19:16:30 +01:00
CARD_Close (&CardFile);
2008-12-10 19:16:30 +01:00
CARD_Unmount (CARDSLOT);
GUI_MsgBoxClose();
return 1;
2008-12-10 19:16:30 +01:00
default: /*** Loading ***/
2008-12-10 19:16:30 +01:00
if (!CardFileExists (filename, CARDSLOT))
{
GUI_WaitPrompt("Error","File does not exist !");
CARD_Unmount (CARDSLOT);
return 0;
}
2008-12-10 19:16:30 +01:00
memset (&CardFile, 0, sizeof (CardFile));
CardError = CARD_Open (CARDSLOT, filename, &CardFile);
if (CardError)
{
sprintf (action, "Unable to open file (%d)", CardError);
GUI_WaitPrompt("Error",action);
CARD_Unmount (CARDSLOT);
return 0;
}
2008-12-10 19:16:30 +01:00
blocks = CardFile.len;
if (blocks < SectorSize)
blocks = SectorSize;
if (blocks % SectorSize)
blocks++;
2008-12-10 19:16:30 +01:00
/*** Just read the file back in ***/
sbo = 0;
while (blocks > 0)
{
CARD_Read (&CardFile, &savebuffer[sbo], SectorSize, sbo);
sbo += SectorSize;
blocks -= SectorSize;
}
CARD_Close (&CardFile);
CARD_Unmount (CARDSLOT);
GUI_MsgBoxClose();
2008-12-10 19:16:30 +01:00
/*** Load State ***/
state_load(&savebuffer[2112]);
return 1;
}
2008-12-10 19:16:30 +01:00
}
GUI_WaitPrompt("Error","Invalid sector size");
return 0;
2008-12-10 19:16:30 +01:00
}
GUI_WaitPrompt("Error","Unable to mount memory card !");
return 0;
2008-08-07 14:26:07 +02:00
}