2008-08-06 03:09:59 +02:00
|
|
|
/****************************************************************************
|
2008-09-12 07:28:40 +02:00
|
|
|
* Snes9x 1.51 Nintendo Wii/Gamecube Port
|
2008-08-14 00:44:59 +02:00
|
|
|
*
|
|
|
|
* softdev July 2006
|
|
|
|
* crunchy2 May 2007-July 2007
|
2008-11-12 08:50:39 +01:00
|
|
|
* Michniewski 2008
|
2009-03-11 18:28:37 +01:00
|
|
|
* Tantric 2008-2009
|
2008-08-14 00:44:59 +02:00
|
|
|
*
|
|
|
|
* freeze.cpp
|
|
|
|
*
|
|
|
|
* Snapshots Memory File System
|
2008-08-06 03:09:59 +02:00
|
|
|
*
|
2008-09-12 07:28:40 +02:00
|
|
|
* This is a single global memory file controller.
|
|
|
|
* Don't even think of opening two at the same time!
|
|
|
|
***************************************************************************/
|
|
|
|
|
2009-02-07 04:01:10 +01:00
|
|
|
#include <malloc.h>
|
2008-08-06 03:09:59 +02:00
|
|
|
#include <gccore.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2008-08-06 03:39:43 +02:00
|
|
|
#include <fat.h>
|
2008-08-06 03:09:59 +02:00
|
|
|
#include <zlib.h>
|
|
|
|
|
2009-03-11 18:28:37 +01:00
|
|
|
#include "pngu/pngu.h"
|
|
|
|
|
2008-08-06 03:09:59 +02:00
|
|
|
#include "snes9x.h"
|
|
|
|
#include "memmap.h"
|
|
|
|
#include "soundux.h"
|
|
|
|
#include "snapshot.h"
|
|
|
|
#include "srtc.h"
|
|
|
|
|
2008-10-03 07:26:01 +02:00
|
|
|
#include "snes9xGX.h"
|
2008-08-12 05:25:16 +02:00
|
|
|
#include "images/saveicon.h"
|
|
|
|
#include "freeze.h"
|
2008-12-18 19:36:30 +01:00
|
|
|
#include "fileop.h"
|
2009-03-11 18:28:37 +01:00
|
|
|
#include "filebrowser.h"
|
|
|
|
#include "menu.h"
|
|
|
|
#include "video.h"
|
2008-08-06 03:09:59 +02:00
|
|
|
|
|
|
|
extern void S9xSRTCPreSaveState ();
|
|
|
|
extern void NGCFreezeStruct ();
|
|
|
|
extern bool8 S9xUnfreezeGame (const char *filename);
|
|
|
|
|
|
|
|
static int bufoffset;
|
|
|
|
|
2008-09-12 07:28:40 +02:00
|
|
|
/****************************************************************************
|
2008-08-06 03:09:59 +02:00
|
|
|
* GetMem
|
|
|
|
*
|
|
|
|
* Return x bytes from memory buffer
|
2008-09-12 07:28:40 +02:00
|
|
|
***************************************************************************/
|
2008-08-06 03:09:59 +02:00
|
|
|
int
|
|
|
|
GetMem (char *buffer, int len)
|
|
|
|
{
|
2008-09-04 09:30:04 +02:00
|
|
|
memcpy (buffer, savebuffer + bufoffset, len);
|
2008-08-12 05:25:16 +02:00
|
|
|
bufoffset += len;
|
2008-08-06 03:09:59 +02:00
|
|
|
|
2008-08-12 05:25:16 +02:00
|
|
|
return len;
|
2008-08-06 03:09:59 +02:00
|
|
|
}
|
|
|
|
|
2008-09-12 07:28:40 +02:00
|
|
|
/****************************************************************************
|
2008-08-06 03:09:59 +02:00
|
|
|
* PutMem
|
|
|
|
*
|
|
|
|
* Put some values in memory buffer
|
2008-09-12 07:28:40 +02:00
|
|
|
***************************************************************************/
|
2008-08-06 03:09:59 +02:00
|
|
|
static void
|
|
|
|
PutMem (char *buffer, int len)
|
|
|
|
{
|
2008-09-04 09:30:04 +02:00
|
|
|
memcpy (savebuffer + bufoffset, buffer, len);
|
2008-08-12 05:25:16 +02:00
|
|
|
bufoffset += len;
|
2008-08-06 03:09:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
NGCFreezeBlock (char *name, uint8 * block, int size)
|
|
|
|
{
|
2008-08-12 05:25:16 +02:00
|
|
|
char buffer[512];
|
|
|
|
sprintf (buffer, "%s:%06d:", name, size);
|
|
|
|
PutMem (buffer, strlen (buffer));
|
|
|
|
PutMem ((char *) block, size);
|
2008-08-06 03:09:59 +02:00
|
|
|
}
|
|
|
|
|
2008-09-12 07:28:40 +02:00
|
|
|
/****************************************************************************
|
2008-08-06 03:09:59 +02:00
|
|
|
* NGCFreezeMembuffer
|
2008-09-12 07:28:40 +02:00
|
|
|
*
|
|
|
|
* Copies a snapshot of Snes9x state into memory
|
|
|
|
***************************************************************************/
|
2008-08-06 03:09:59 +02:00
|
|
|
static int
|
|
|
|
NGCFreezeMemBuffer ()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char buffer[1024];
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:09:59 +02:00
|
|
|
bufoffset = 0;
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:09:59 +02:00
|
|
|
S9xUpdateRTC ();
|
|
|
|
S9xSRTCPreSaveState ();
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:09:59 +02:00
|
|
|
for (i = 0; i < 8; i++)
|
|
|
|
{
|
|
|
|
SoundData.channels[i].previous16[0] =
|
|
|
|
(int16) SoundData.channels[i].previous[0];
|
|
|
|
SoundData.channels[i].previous16[1] =
|
|
|
|
(int16) SoundData.channels[i].previous[1];
|
|
|
|
}
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:09:59 +02:00
|
|
|
sprintf (buffer, "%s:%04d\n", SNAPSHOT_MAGIC, SNAPSHOT_VERSION);
|
|
|
|
PutMem (buffer, strlen (buffer));
|
2008-09-12 07:28:40 +02:00
|
|
|
sprintf (buffer, "NAM:%06d:%s%c", (int) strlen (Memory.ROMFilename) + 1,
|
2008-08-06 03:09:59 +02:00
|
|
|
Memory.ROMFilename, 0);
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:09:59 +02:00
|
|
|
PutMem (buffer, strlen (buffer) + 1);
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:09:59 +02:00
|
|
|
NGCFreezeStruct ();
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:09:59 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-09-12 07:28:40 +02:00
|
|
|
/****************************************************************************
|
2008-08-06 03:09:59 +02:00
|
|
|
* NGCFreezeGame
|
|
|
|
*
|
|
|
|
* Do freeze game for Nintendo Gamecube
|
2008-09-12 07:28:40 +02:00
|
|
|
***************************************************************************/
|
2008-08-06 03:09:59 +02:00
|
|
|
int
|
2009-03-11 18:28:37 +01:00
|
|
|
NGCFreezeGame (char * filepath, int method, bool silent)
|
2008-08-06 03:09:59 +02:00
|
|
|
{
|
2008-11-12 08:50:39 +01:00
|
|
|
int offset = 0; // bytes written (actual)
|
|
|
|
int woffset = 0; // bytes written (expected)
|
2009-03-12 08:07:52 +01:00
|
|
|
int imgSize = 0; // image screenshot bytes written
|
2008-11-12 08:50:39 +01:00
|
|
|
char msg[100];
|
|
|
|
|
2008-08-07 05:25:02 +02:00
|
|
|
if(method == METHOD_AUTO)
|
2008-12-22 10:20:35 +01:00
|
|
|
method = autoSaveMethod(silent);
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2009-03-11 18:28:37 +01:00
|
|
|
if(method == METHOD_AUTO)
|
2008-11-12 08:50:39 +01:00
|
|
|
return 0;
|
2008-08-07 05:25:02 +02:00
|
|
|
|
|
|
|
S9xSetSoundMute (TRUE);
|
|
|
|
S9xPrepareSoundForSnapshotSave (FALSE);
|
|
|
|
|
2008-09-27 09:13:52 +02:00
|
|
|
AllocSaveBuffer ();
|
2008-09-04 09:30:04 +02:00
|
|
|
NGCFreezeMemBuffer (); // copy freeze mem into savebuffer
|
2008-11-12 08:50:39 +01:00
|
|
|
woffset = bufoffset;
|
2008-08-07 05:25:02 +02:00
|
|
|
|
|
|
|
S9xPrepareSoundForSnapshotSave (TRUE);
|
|
|
|
S9xSetSoundMute (FALSE);
|
|
|
|
|
2008-11-12 08:50:39 +01:00
|
|
|
if(method == METHOD_MC_SLOTA || method == METHOD_MC_SLOTB) // MC Slot A or B
|
2008-08-07 05:25:02 +02:00
|
|
|
{
|
2008-09-30 07:31:46 +02:00
|
|
|
// Copy in save icon
|
2008-11-12 08:50:39 +01:00
|
|
|
woffset = sizeof (saveicon);
|
2008-08-13 07:47:04 +02:00
|
|
|
memcpy (savebuffer, saveicon, woffset);
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-09-30 07:31:46 +02:00
|
|
|
// And the freezecomment
|
2009-01-05 23:23:41 +01:00
|
|
|
char freezecomment[2][32];
|
2008-12-22 10:20:35 +01:00
|
|
|
memset(freezecomment, 0, 64);
|
|
|
|
|
2008-12-24 09:02:04 +01:00
|
|
|
sprintf (freezecomment[0], "%s Freeze", APPVERSION);
|
2008-08-22 04:47:08 +02:00
|
|
|
sprintf (freezecomment[1], Memory.ROMName);
|
2008-08-13 07:47:04 +02:00
|
|
|
memcpy (savebuffer + woffset, freezecomment, 64);
|
|
|
|
woffset += 64;
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-09-30 07:31:46 +02:00
|
|
|
// Zip and copy in the freeze
|
2008-08-07 05:25:02 +02:00
|
|
|
uLongf DestBuffSize = (uLongf) SAVEBUFFERSIZE;
|
2008-09-04 09:30:04 +02:00
|
|
|
int err= compress2((Bytef*)(savebuffer+woffset+8), (uLongf*)&DestBuffSize, (const Bytef*)savebuffer, (uLongf)bufoffset, Z_BEST_COMPRESSION);
|
2008-08-07 05:25:02 +02:00
|
|
|
|
|
|
|
if(err!=Z_OK)
|
|
|
|
{
|
|
|
|
sprintf (msg, "zip error %s ",zError(err));
|
2009-03-11 18:28:37 +01:00
|
|
|
ErrorPrompt(msg);
|
|
|
|
goto done;
|
2008-08-07 05:25:02 +02:00
|
|
|
}
|
2008-08-06 03:09:59 +02:00
|
|
|
|
|
|
|
int zippedsize = (int)DestBuffSize;
|
2008-08-13 07:47:04 +02:00
|
|
|
memcpy (savebuffer + woffset, &zippedsize, 4);
|
|
|
|
woffset += 4;
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-06 03:09:59 +02:00
|
|
|
int decompressedsize = (int)bufoffset;
|
2008-08-13 07:47:04 +02:00
|
|
|
memcpy (savebuffer + woffset, &decompressedsize, 4);
|
|
|
|
woffset += 4;
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-13 07:47:04 +02:00
|
|
|
woffset += zippedsize;
|
2008-08-07 05:25:02 +02:00
|
|
|
}
|
|
|
|
|
2008-11-12 08:50:39 +01:00
|
|
|
offset = SaveFile(filepath, woffset, method, silent);
|
|
|
|
|
2009-03-11 18:28:37 +01:00
|
|
|
done:
|
|
|
|
|
2008-09-27 09:13:52 +02:00
|
|
|
FreeSaveBuffer ();
|
|
|
|
|
2009-03-11 18:28:37 +01:00
|
|
|
// save screenshot - I would prefer to do this from gameScreenTex
|
|
|
|
if(gameScreenTex != NULL && method != METHOD_MC_SLOTA && method != METHOD_MC_SLOTB)
|
|
|
|
{
|
|
|
|
AllocSaveBuffer ();
|
|
|
|
|
|
|
|
IMGCTX pngContext = PNGU_SelectImageFromBuffer(savebuffer);
|
|
|
|
|
|
|
|
if (pngContext != NULL)
|
|
|
|
{
|
2009-03-12 08:07:52 +01:00
|
|
|
imgSize = PNGU_EncodeFromGXTexture(pngContext, 640, 480, gameScreenTex, 0);
|
2009-03-11 18:28:37 +01:00
|
|
|
PNGU_ReleaseImageContext(pngContext);
|
|
|
|
}
|
|
|
|
|
2009-03-12 08:07:52 +01:00
|
|
|
if(imgSize > 0)
|
2009-03-11 18:28:37 +01:00
|
|
|
{
|
|
|
|
char screenpath[1024];
|
|
|
|
filepath[strlen(filepath)-4] = 0;
|
|
|
|
sprintf(screenpath, "%s.png", filepath);
|
2009-03-12 08:07:52 +01:00
|
|
|
SaveFile(screenpath, imgSize, method, silent);
|
2009-03-11 18:28:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
FreeSaveBuffer ();
|
|
|
|
}
|
|
|
|
|
2008-08-12 05:25:16 +02:00
|
|
|
if(offset > 0) // save successful!
|
|
|
|
{
|
|
|
|
if(!silent)
|
2009-03-11 18:28:37 +01:00
|
|
|
InfoPrompt("Save successful");
|
2008-08-12 05:25:16 +02:00
|
|
|
return 1;
|
2008-08-07 05:25:02 +02:00
|
|
|
}
|
2008-08-06 03:09:59 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-03-11 18:28:37 +01:00
|
|
|
int
|
|
|
|
NGCFreezeGameAuto (int method, bool silent)
|
|
|
|
{
|
|
|
|
char filepath[1024];
|
|
|
|
|
|
|
|
if(method == METHOD_MC_SLOTA || method == METHOD_MC_SLOTB)
|
|
|
|
sprintf(filepath, "%s Auto.frz", Memory.ROMFilename);
|
|
|
|
else
|
|
|
|
sprintf(filepath, "%s/%s Auto.frz", GCSettings.SaveFolder, Memory.ROMFilename);
|
|
|
|
return NGCFreezeGame(filepath, method, silent);
|
|
|
|
}
|
|
|
|
|
2008-09-12 07:28:40 +02:00
|
|
|
/****************************************************************************
|
2008-08-06 03:09:59 +02:00
|
|
|
* NGCUnFreezeBlock
|
2008-09-12 07:28:40 +02:00
|
|
|
***************************************************************************/
|
2008-08-06 03:09:59 +02:00
|
|
|
int
|
|
|
|
NGCUnFreezeBlock (char *name, uint8 * block, int size)
|
|
|
|
{
|
2008-08-12 05:25:16 +02:00
|
|
|
char buffer[20], *e;
|
|
|
|
int len = 0;
|
|
|
|
int rem = 0;
|
2008-08-06 03:09:59 +02:00
|
|
|
|
2008-08-12 05:25:16 +02:00
|
|
|
GetMem (buffer, 11);
|
2008-08-06 03:09:59 +02:00
|
|
|
|
2008-08-12 05:25:16 +02:00
|
|
|
if (strncmp (buffer, name, 3) != 0 || buffer[3] != ':' ||
|
|
|
|
buffer[10] != ':' || (len = strtol (&buffer[4], &e, 10)) == 0 ||
|
|
|
|
e != buffer + 10)
|
|
|
|
{
|
2008-10-17 09:43:37 +02:00
|
|
|
bufoffset -= 11; // go back to where we started
|
2008-08-12 05:25:16 +02:00
|
|
|
return WRONG_FORMAT;
|
|
|
|
}
|
2008-08-06 03:09:59 +02:00
|
|
|
|
2008-08-12 05:25:16 +02:00
|
|
|
if (len > size)
|
|
|
|
{
|
|
|
|
rem = len - size;
|
|
|
|
len = size;
|
|
|
|
}
|
2008-08-06 03:09:59 +02:00
|
|
|
|
2008-08-12 05:25:16 +02:00
|
|
|
ZeroMemory (block, size);
|
2008-08-06 03:09:59 +02:00
|
|
|
|
2008-08-12 05:25:16 +02:00
|
|
|
GetMem ((char *) block, len);
|
2008-08-06 03:09:59 +02:00
|
|
|
|
2008-08-12 05:25:16 +02:00
|
|
|
if (rem)
|
|
|
|
{
|
|
|
|
bufoffset += rem;
|
|
|
|
}
|
2008-08-06 03:09:59 +02:00
|
|
|
|
2008-08-12 05:25:16 +02:00
|
|
|
return SUCCESS;
|
2008-08-06 03:09:59 +02:00
|
|
|
}
|
|
|
|
|
2008-09-12 07:28:40 +02:00
|
|
|
/****************************************************************************
|
2008-08-06 03:09:59 +02:00
|
|
|
* NGCUnfreezeGame
|
2008-09-12 07:28:40 +02:00
|
|
|
***************************************************************************/
|
2008-08-06 03:09:59 +02:00
|
|
|
int
|
2009-03-11 18:28:37 +01:00
|
|
|
NGCUnfreezeGame (char * filepath, int method, bool silent)
|
2008-08-06 03:09:59 +02:00
|
|
|
{
|
2008-08-12 05:25:16 +02:00
|
|
|
int offset = 0;
|
2008-11-12 08:50:39 +01:00
|
|
|
int result = 0;
|
2008-08-12 05:25:16 +02:00
|
|
|
char msg[80];
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-12 05:25:16 +02:00
|
|
|
bufoffset = 0;
|
2008-08-07 05:25:02 +02:00
|
|
|
|
|
|
|
if(method == METHOD_AUTO)
|
2008-12-22 10:20:35 +01:00
|
|
|
method = autoSaveMethod(silent); // we use 'Save' because snapshot needs R/W
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2009-03-11 18:28:37 +01:00
|
|
|
if(method == METHOD_AUTO)
|
|
|
|
return 0;
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-11-12 08:50:39 +01:00
|
|
|
AllocSaveBuffer ();
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-11-12 08:50:39 +01:00
|
|
|
offset = LoadFile(filepath, method, silent);
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-11-12 08:50:39 +01:00
|
|
|
if(method == METHOD_MC_SLOTA || method == METHOD_MC_SLOTB) // MC in slot A or slot B
|
|
|
|
{
|
|
|
|
if (offset)
|
2008-08-07 05:25:02 +02:00
|
|
|
{
|
2009-02-07 04:01:10 +01:00
|
|
|
char * zipbuffer = (char *)memalign(32, SAVEBUFFERSIZE);
|
2008-09-30 07:31:46 +02:00
|
|
|
memset (zipbuffer, 0, SAVEBUFFERSIZE);
|
2008-08-13 07:47:04 +02:00
|
|
|
|
2008-08-07 05:25:02 +02:00
|
|
|
// skip the saveicon and comment
|
|
|
|
offset = (sizeof(saveicon) + 64);
|
|
|
|
uLongf zipsize = 0;
|
|
|
|
uLongf decompressedsize = 0;
|
|
|
|
|
|
|
|
memcpy (&zipsize, savebuffer+offset, 4);
|
|
|
|
offset += 4;
|
|
|
|
|
|
|
|
memcpy (&decompressedsize, savebuffer+offset, 4);
|
|
|
|
offset += 4;
|
|
|
|
|
2008-09-04 09:30:04 +02:00
|
|
|
uLongf DestBuffSize = SAVEBUFFERSIZE;
|
2008-08-13 07:47:04 +02:00
|
|
|
int err= uncompress((Bytef*)zipbuffer, (uLongf*)&DestBuffSize, (const Bytef*)(savebuffer + offset), zipsize);
|
2008-08-07 05:25:02 +02:00
|
|
|
|
|
|
|
if ( err!=Z_OK )
|
|
|
|
{
|
2008-08-12 05:25:16 +02:00
|
|
|
sprintf (msg, "Unzip error %s ",zError(err));
|
2009-03-11 18:28:37 +01:00
|
|
|
ErrorPrompt(msg);
|
2008-08-07 05:25:02 +02:00
|
|
|
}
|
2008-08-13 07:47:04 +02:00
|
|
|
else if ( DestBuffSize != decompressedsize )
|
2008-08-07 05:25:02 +02:00
|
|
|
{
|
2009-03-11 18:28:37 +01:00
|
|
|
ErrorPrompt("Unzipped size doesn't match expected size!");
|
2008-08-07 05:25:02 +02:00
|
|
|
}
|
2008-08-13 07:47:04 +02:00
|
|
|
else
|
|
|
|
{
|
2008-09-04 09:30:04 +02:00
|
|
|
offset = SAVEBUFFERSIZE;
|
|
|
|
memcpy (savebuffer, zipbuffer, SAVEBUFFERSIZE);
|
2008-08-13 07:47:04 +02:00
|
|
|
}
|
2008-09-30 07:31:46 +02:00
|
|
|
free(zipbuffer);
|
2008-08-07 05:25:02 +02:00
|
|
|
}
|
2008-08-06 03:09:59 +02:00
|
|
|
}
|
2008-08-07 05:25:02 +02:00
|
|
|
|
2008-08-12 05:25:16 +02:00
|
|
|
if(offset > 0)
|
|
|
|
{
|
|
|
|
if (S9xUnfreezeGame ("AGAME") == SUCCESS)
|
2008-09-27 09:13:52 +02:00
|
|
|
result = 1;
|
2008-08-12 05:25:16 +02:00
|
|
|
else
|
2009-03-11 18:28:37 +01:00
|
|
|
ErrorPrompt("Error thawing");
|
2008-08-12 05:25:16 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(!silent)
|
2009-03-11 18:28:37 +01:00
|
|
|
ErrorPrompt("Freeze file not found");
|
2008-08-12 05:25:16 +02:00
|
|
|
}
|
2008-09-27 09:13:52 +02:00
|
|
|
FreeSaveBuffer ();
|
|
|
|
return result;
|
2008-08-06 03:09:59 +02:00
|
|
|
}
|
2009-03-11 18:28:37 +01:00
|
|
|
|
|
|
|
int
|
|
|
|
NGCUnfreezeGameAuto (int method, bool silent)
|
|
|
|
{
|
|
|
|
char filepath[1024];
|
|
|
|
|
|
|
|
if(method == METHOD_MC_SLOTA || method == METHOD_MC_SLOTB)
|
|
|
|
sprintf(filepath, "%s Auto.frz", Memory.ROMFilename);
|
|
|
|
else
|
|
|
|
sprintf(filepath, "%s/%s Auto.frz", GCSettings.SaveFolder, Memory.ROMFilename);
|
|
|
|
|
|
|
|
return NGCUnfreezeGame(filepath, method, silent);
|
|
|
|
}
|