Genesis-Plus-GX/source/gx/fileio/file_slot.c
ekeeke31 62f1204476 ----------------------
Genesis Plus GX 1.6.0 
----------------------

[Core/Sound]
---------------
* added YM2413 emulation in Master System compatibility mode.
* fixed SN76489 noise boost initialization.
* minor YM2612 core optimizations.

[Core/VDP]
---------------
* added accurate emulation of SG-1000, Master System (315-5124, 315-5246) & Game Gear VDP.
* added support for all TMS9918 rendering modes.
* improved Mega Drive VDP timings accuracy in Master System Compatibility mode.
* fixed color palette initialization.
* fixed shifted sprites rendering in Mode 4.
* modified pixel rendering support (pixel depth is now forced at compilation time).

[Core/CPU]
---------------
* optimized 68k core (rewrote 68k interrupt handling, removed multiple CPU types support & unused code) for 5~8% speed improvment

[Core/IO]
---------------
* added accurate emulation of Master System (315-5216, 315-5237, 315-5297) & Game Gear I/O controllers.
* added Terebi Oekaki tablet emulation.
* improved Mouse emulation (fixes mouse support in Cannon Fodder).
* improved Justifier emulation (fixes gun support in Lethal Enforcers 2).
* improved 6-Buttons control pad emulation (fixes Duke Nukem 3D)
* modified lightgun emulation to use common key inputs for all devices.
* 2-buttons controller is now picked by default for Master System games.

[Core/MD]
---------------
* added copy-protection hardware emulation for some new dumped games (Tiny Toon Adventures 3, Mighty Morphin Power Rangers & The Battle of Red Cliffs).
* added Game Toshokan in EEPROM database (verified on real cartridge).
* fixed Micro Machines 2 - Turbo Tournament EEPROM size (verified on real cartridge).
* modified SRAM banswitch hardware emulation to be more compatible with some hacks.

[Core/MS]
---------------
* added Cyborg Z to Korean mapper database.

[Core/GG]
---------------
* added 93C46 EEPROM emulation (Majors Pro Baseball, World Series Baseball & World Series Baseball 95).

[Core/General]
---------------
* added support for .mdx ROM format.
* added Game Gear & SG-1000 ROM support.
* added accurate emulation of SG-1000, Master System (I, II) & Game Gear hardware models for 100% compatibility.
* updated to new Genesis Plus license (see http://cgfm2.emuviews.com/)
* removed DOS port
* various code cleanup.

[Gamecube/Wii]
---------------
* IMPORTANT: cheats, screenshots & save files are now stored in console-specific directories (ex: /snaps/md, /cheats/ms, /saves/gg, ...)
* added 8-bit Action Replay & Game Genie codes support (for Master System & Game Gear games).
* improved audio/video synchronization for PAL games in 50Hz TV modes (now use VSYNC like NTSC games in 60hz modes).
* improved gun cursor positioning accuracy.
* improved horizontal scaling & screenshots rendering in H32 mode.
* fixed a bug with ROM file extension handling that would affect cheats, snapshots, sram & savestate files.
* removed ARAM/injected ROM support (unused).
* removed WPAD_ and PAD_ update from VSYNC callback.
* increased GCC inlining limits for some speed improvment.
* compiled with devkitPPC r24 & libogc 1.8.7.
2011-08-07 17:49:46 +00:00

594 lines
15 KiB
C

/*
* file_slot.c
*
* FAT and Memory Card SRAM/State slots managment
*
* Copyright Eke-Eke (2008-2011), based on original code from Softdev (2006)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
*
* - Redistributions may not be sold, nor may they be used in a commercial
* product or activity.
*
* - Redistributions that are modified from the original source must include the
* complete source code, including the source code for all components used by a
* binary built from the modified sources. However, as a special exception, the
* source code distributed need not include anything that is normally distributed
* (in either source or binary form) with the major components (compiler, kernel,
* and so on) of the operating system on which the executable runs, unless that
* component itself accompanies the executable.
*
* - Redistributions must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************************/
#include "shared.h"
#include "file_slot.h"
#include "file_load.h"
#include "gui.h"
#include "filesel.h"
#include "saveicon.h"
/**
* libOGC CARD System Work Area
*/
static u8 SysArea[CARD_WORKAREA] ATTRIBUTE_ALIGN (32);
/****************************************************************************
* CardMount
*
* 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!
*
*****************************************************************************/
static int CardMount(int slot)
{
int tries = 0;
#if defined(HW_DOL)
*(unsigned long *) (0xCC006800) |= 1 << 13; /*** Disable Encryption ***/
#elif defined(HW_RVL)
*(unsigned long *) (0xCD006800) |= 1 << 13; /*** Disable Encryption ***/
#endif
while (tries < 10)
{
VIDEO_WaitVSync ();
if (CARD_Mount(slot, SysArea, NULL) == CARD_ERROR_READY)
return 1;
else
EXI_ProbeReset ();
tries++;
}
return 0;
}
/****************************************************************************
* Slot Management
*
*
****************************************************************************/
void slot_autoload(int slot, int device)
{
if (!strlen(rom_filename))
return;
SILENT = 1;
slot_load(slot, device);
SILENT = 0;
}
void slot_autosave(int slot, int device)
{
if (!strlen(rom_filename))
return;
/* only save if SRAM changed */
if (!slot && (crc32(0, &sram.sram[0], 0x10000) == sram.crc))
return;
SILENT = 1;
slot_save(slot, device);
SILENT = 0;
}
void slot_autodetect(int slot, int device, t_slot *ptr)
{
if (!ptr)
return;
char filename[MAXPATHLEN];
memset(ptr,0,sizeof(t_slot));
if (!device)
{
/* FAT support */
if (slot > 0)
sprintf (filename,"%s/saves/%s.gp%d", DEFAULT_PATH, rom_filename, slot - 1);
else
sprintf (filename,"%s/saves/%s.srm", DEFAULT_PATH, rom_filename);
/* Open file */
FILE *fp = fopen(filename, "rb");
if (fp)
{
/* Retrieve date & close */
struct stat filestat;
stat(filename, &filestat);
struct tm *timeinfo = localtime(&filestat.st_mtime);
ptr->year = 1900 + timeinfo->tm_year;
ptr->month = timeinfo->tm_mon;
ptr->day = timeinfo->tm_mday;
ptr->hour = timeinfo->tm_hour;
ptr->min = timeinfo->tm_min;
fclose(fp);
ptr->valid = 1;
}
}
else
{
/* Memory Card support */
if (slot > 0)
sprintf(filename,"MD-%04X.gp%d", rominfo.realchecksum, slot - 1);
else
sprintf(filename,"MD-%04X.srm", rominfo.realchecksum);
/* Initialise the CARD system */
memset(&SysArea, 0, CARD_WORKAREA);
CARD_Init("GENP", "00");
/* CARD slot */
device--;
/* Mount CARD */
if (CardMount(device))
{
/* Open file */
card_file CardFile;
if (CARD_Open(device, filename, &CardFile) == CARD_ERROR_READY)
{
/* Retrieve date & close */
card_stat CardStatus;
CARD_GetStatus(device, CardFile.filenum, &CardStatus);
time_t rawtime = CardStatus.time;
struct tm *timeinfo = localtime(&rawtime);
ptr->year = 1900 + timeinfo->tm_year;
ptr->month = timeinfo->tm_mon;
ptr->day = timeinfo->tm_mday;
ptr->hour = timeinfo->tm_hour;
ptr->min = timeinfo->tm_min;
CARD_Close(&CardFile);
ptr->valid = 1;
}
CARD_Unmount(device);
}
}
}
int slot_delete(int slot, int device)
{
char filename[MAXPATHLEN];
int ret = 0;
if (!device)
{
/* FAT support */
if (slot > 0)
{
/* remove screenshot */
sprintf(filename,"%s/saves/%s__%d.png", DEFAULT_PATH, rom_filename, slot - 1);
remove(filename);
sprintf (filename,"%s/saves/%s.gp%d", DEFAULT_PATH, rom_filename, slot - 1);
}
else
{
sprintf (filename,"%s/saves/%s.srm", DEFAULT_PATH, rom_filename);
}
/* Delete file */
ret = remove(filename);
}
else
{
/* Memory Card support */
if (slot > 0)
sprintf(filename,"MD-%04X.gp%d", rominfo.realchecksum, slot - 1);
else
sprintf(filename,"MD-%04X.srm", rominfo.realchecksum);
/* Initialise the CARD system */
memset(&SysArea, 0, CARD_WORKAREA);
CARD_Init("GENP", "00");
/* CARD slot */
device--;
/* Mount CARD */
if (CardMount(device))
{
/* Delete file */
ret = CARD_Delete(device,filename);
CARD_Unmount(device);
}
}
return ret;
}
int slot_load(int slot, int device)
{
char filename[MAXPATHLEN];
int filesize, done = 0;
int offset = 0;
u8 *savebuffer;
if (slot > 0)
{
GUI_MsgBoxOpen("Information","Loading State ...",1);
}
else
{
if (!sram.on)
{
GUI_WaitPrompt("Error","SRAM is disabled !");
return 0;
}
GUI_MsgBoxOpen("Information","Loading SRAM ...",1);
}
if (!device)
{
/* FAT support */
if (slot > 0)
sprintf (filename,"%s/saves/%s.gp%d", DEFAULT_PATH, rom_filename, slot - 1);
else
sprintf (filename,"%s/saves/%s.srm", DEFAULT_PATH, rom_filename);
/* Open file */
FILE *fp = fopen(filename, "rb");
if (!fp)
{
GUI_WaitPrompt("Error","Unable to open file !");
return 0;
}
/* Read size */
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);
fseek(fp, 0, SEEK_SET);
/* allocate buffer */
savebuffer = (u8 *)memalign(32,filesize);
if (!savebuffer)
{
GUI_WaitPrompt("Error","Unable to allocate memory !");
fclose(fp);
return 0;
}
/* Read into buffer (2k blocks) */
while (filesize > CHUNKSIZE)
{
fread(savebuffer + done, CHUNKSIZE, 1, fp);
done += CHUNKSIZE;
filesize -= CHUNKSIZE;
}
/* Read remaining bytes */
fread(savebuffer + done, filesize, 1, fp);
done += filesize;
fclose(fp);
}
else
{
/* Memory Card support */
if (slot > 0)
sprintf(filename, "MD-%04X.gp%d", rominfo.realchecksum, slot - 1);
else
sprintf(filename, "MD-%04X.srm", rominfo.realchecksum);
/* Initialise the CARD system */
char action[64];
memset(&SysArea, 0, CARD_WORKAREA);
CARD_Init("GENP", "00");
/* CARD slot */
device--;
/* Attempt to mount the card */
if (!CardMount(device))
{
GUI_WaitPrompt("Error","Unable to mount memory card");
return 0;
}
/* Retrieve the sector size */
u32 SectorSize = 0;
int CardError = CARD_GetSectorSize(device, &SectorSize);
if (!SectorSize)
{
sprintf(action, "Invalid sector size (%d)", CardError);
GUI_WaitPrompt("Error",action);
CARD_Unmount(device);
return 0;
}
/* Open file */
card_file CardFile;
CardError = CARD_Open(device, filename, &CardFile);
if (CardError)
{
sprintf(action, "Unable to open file (%d)", CardError);
GUI_WaitPrompt("Error",action);
CARD_Unmount(device);
return 0;
}
/* Retrieve file size */
filesize = CardFile.len;
if (filesize % SectorSize)
filesize = ((filesize / SectorSize) + 1) * SectorSize;
/* Allocate buffer */
savebuffer = (u8 *)memalign(32,filesize);
if (!savebuffer)
{
GUI_WaitPrompt("Error","Unable to allocate memory !");
CARD_Close(&CardFile);
CARD_Unmount(device);
return 0;
}
/* Read file sectors */
while (filesize > 0)
{
CARD_Read(&CardFile, &savebuffer[done], SectorSize, done);
done += SectorSize;
filesize -= SectorSize;
}
CARD_Close(&CardFile);
CARD_Unmount(device);
offset = 2112;
}
if (slot > 0)
{
/* Load state */
if (state_load(&savebuffer[offset]) <= 0)
{
free(savebuffer);
GUI_WaitPrompt("Error","Invalid state file !");
return 0;
}
}
else
{
/* Load SRAM & update CRC */
memcpy(sram.sram, &savebuffer[offset], 0x10000);
sram.crc = crc32(0, sram.sram, 0x10000);
}
free(savebuffer);
GUI_MsgBoxClose();
return 1;
}
int slot_save(int slot, int device)
{
char filename[MAXPATHLEN];
int filesize, done = 0;
int offset = device ? 2112 : 0;
u8 *savebuffer;
if (slot > 0)
{
/* allocate buffer */
savebuffer = (u8 *)memalign(32,STATE_SIZE);
if (!savebuffer)
{
GUI_WaitPrompt("Error","Unable to allocate memory !");
return 0;
}
GUI_MsgBoxOpen("Information","Saving State ...",1);
filesize = state_save(&savebuffer[offset]);
}
else
{
if (!sram.on)
{
GUI_WaitPrompt("Error","SRAM is disabled !");
return 0;
}
/* allocate buffer */
savebuffer = (u8 *)memalign(32,0x10000+offset);
if (!savebuffer)
{
GUI_WaitPrompt("Error","Unable to allocate memory !");
return 0;
}
GUI_MsgBoxOpen("Information","Saving SRAM ...",1);
memcpy(&savebuffer[offset], sram.sram, 0x10000);
sram.crc = crc32(0, sram.sram, 0x10000);
filesize = 0x10000;
}
if (!device)
{
/* FAT support */
if (slot > 0)
sprintf(filename, "%s/saves/%s.gp%d", DEFAULT_PATH, rom_filename, slot - 1);
else
sprintf(filename, "%s/saves/%s.srm", DEFAULT_PATH, rom_filename);
/* Open file */
FILE *fp = fopen(filename, "wb");
if (!fp)
{
GUI_WaitPrompt("Error","Unable to open file !");
free(savebuffer);
return 0;
}
/* Write from buffer (2k blocks) */
while (filesize > CHUNKSIZE)
{
fwrite(savebuffer + done, CHUNKSIZE, 1, fp);
done += CHUNKSIZE;
filesize -= CHUNKSIZE;
}
/* Write remaining bytes */
fwrite(savebuffer + done, filesize, 1, fp);
done += filesize;
fclose(fp);
}
else
{
/* Memory Card support */
if (slot > 0)
sprintf(filename, "MD-%04X.gp%d", rominfo.realchecksum, slot - 1);
else
sprintf(filename, "MD-%04X.srm", rominfo.realchecksum);
/* Initialise the CARD system */
char action[64];
memset(&SysArea, 0, CARD_WORKAREA);
CARD_Init("GENP", "00");
/* CARD slot */
device--;
/* Attempt to mount the card */
if (!CardMount(device))
{
GUI_WaitPrompt("Error","Unable to mount memory card");
free(savebuffer);
return 0;
}
/* Retrieve the sector size */
u32 SectorSize = 0;
int CardError = CARD_GetSectorSize(device, &SectorSize);
if (!SectorSize)
{
sprintf(action, "Invalid sector size (%d)", CardError);
GUI_WaitPrompt("Error",action);
CARD_Unmount(device);
free(savebuffer);
return 0;
}
/* Build the output buffer */
char comment[2][32] = { {"Genesis Plus GX"}, {"SRAM Save"} };
strcpy (comment[1], filename);
memcpy (&savebuffer[0], &icon, 2048);
memcpy (&savebuffer[2048], &comment[0], 64);
/* Adjust file size */
filesize += 2112;
if (filesize % SectorSize)
filesize = ((filesize / SectorSize) + 1) * SectorSize;
/* Check if file already exists */
card_file CardFile;
if (CARD_Open(device, filename, &CardFile) == CARD_ERROR_READY)
{
int size = filesize - CardFile.len;
CARD_Close(&CardFile);
memset(&CardFile,0,sizeof(CardFile));
/* Check file new size */
if (size > 0)
{
CardError = CARD_Create(device, "TEMP", size, &CardFile);
if (CardError)
{
sprintf(action, "Unable to increase file size (%d)", CardError);
GUI_WaitPrompt("Error",action);
CARD_Unmount(device);
free(savebuffer);
return 0;
}
/* delete temporary file */
CARD_Close(&CardFile);
memset(&CardFile,0,sizeof(CardFile));
CARD_Delete(device, "TEMP");
}
/* delete previously existing file */
CARD_Delete(device, filename);
}
/* Create a new file */
CardError = CARD_Create(device, filename, filesize, &CardFile);
if (CardError)
{
sprintf(action, "Unable to create file (%d)", CardError);
GUI_WaitPrompt("Error",action);
CARD_Unmount(device);
free(savebuffer);
return 0;
}
/* Update file informations */
time_t rawtime;
time(&rawtime);
card_stat CardStatus;
CARD_GetStatus(device, CardFile.filenum, &CardStatus);
CardStatus.icon_addr = 0x0;
CardStatus.icon_fmt = 2;
CardStatus.icon_speed = 1;
CardStatus.comment_addr = 2048;
CardStatus.time = rawtime;
CARD_SetStatus(device, CardFile.filenum, &CardStatus);
/* Write file sectors */
while (filesize > 0)
{
CARD_Write(&CardFile, &savebuffer[done], SectorSize, done);
filesize -= SectorSize;
done += SectorSize;
}
/* Close file */
CARD_Close(&CardFile);
CARD_Unmount(device);
}
GUI_MsgBoxClose();
free(savebuffer);
/* Save screenshot */
if (slot && !device)
{
sprintf(filename,"%s/saves/%s__%d.png", DEFAULT_PATH, rom_filename, slot - 1);
gxSaveScreenshot(filename);
}
return 1;
}