snes9xgx/source/ngc/freeze.cpp

359 lines
8.0 KiB
C++
Raw Normal View History

/****************************************************************************
* 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
*
* 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>
#include <gccore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fat.h>
#include <zlib.h>
2009-03-11 18:28:37 +01:00
#include "pngu/pngu.h"
#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 "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"
extern void S9xSRTCPreSaveState ();
extern void NGCFreezeStruct ();
extern bool8 S9xUnfreezeGame (const char *filename);
static int bufoffset;
/****************************************************************************
* GetMem
*
* Return x bytes from memory buffer
***************************************************************************/
int
GetMem (char *buffer, int len)
{
memcpy (buffer, savebuffer + bufoffset, len);
2008-08-12 05:25:16 +02:00
bufoffset += len;
2008-08-12 05:25:16 +02:00
return len;
}
/****************************************************************************
* PutMem
*
* Put some values in memory buffer
***************************************************************************/
static void
PutMem (char *buffer, int len)
{
memcpy (savebuffer + bufoffset, buffer, len);
2008-08-12 05:25:16 +02:00
bufoffset += len;
}
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);
}
/****************************************************************************
* NGCFreezeMembuffer
*
* Copies a snapshot of Snes9x state into memory
***************************************************************************/
static int
NGCFreezeMemBuffer ()
{
int i;
char buffer[1024];
bufoffset = 0;
S9xUpdateRTC ();
S9xSRTCPreSaveState ();
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];
}
sprintf (buffer, "%s:%04d\n", SNAPSHOT_MAGIC, SNAPSHOT_VERSION);
PutMem (buffer, strlen (buffer));
sprintf (buffer, "NAM:%06d:%s%c", (int) strlen (Memory.ROMFilename) + 1,
Memory.ROMFilename, 0);
PutMem (buffer, strlen (buffer) + 1);
NGCFreezeStruct ();
return 0;
}
/****************************************************************************
* NGCFreezeGame
*
* Do freeze game for Nintendo Gamecube
***************************************************************************/
int
2009-03-11 18:28:37 +01:00
NGCFreezeGame (char * filepath, int method, bool silent)
{
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];
if(method == METHOD_AUTO)
method = autoSaveMethod(silent);
2009-03-11 18:28:37 +01:00
if(method == METHOD_AUTO)
2008-11-12 08:50:39 +01:00
return 0;
S9xSetSoundMute (TRUE);
S9xPrepareSoundForSnapshotSave (FALSE);
2008-09-27 09:13:52 +02:00
AllocSaveBuffer ();
// copy freeze mem into savebuffer - bufoffset contains # bytes written
NGCFreezeMemBuffer ();
2008-11-12 08:50:39 +01:00
woffset = bufoffset;
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
{
// set freezecomment
char freezecomment[2][32];
memset(freezecomment, 0, 64);
2009-03-19 17:51:36 +01:00
sprintf (freezecomment[0], "%s Snapshot", APPNAME);
sprintf (freezecomment[1], Memory.ROMName);
SetMCSaveComment(freezecomment);
// Zip and copy in the freeze
uLongf DestBuffSize = (uLongf) SAVEBUFFERSIZE;
int err= compress2((Bytef*)(savebuffer+8), (uLongf*)&DestBuffSize, (const Bytef*)savebuffer, (uLongf)bufoffset, Z_BEST_COMPRESSION);
if(err!=Z_OK)
{
2009-03-16 07:58:50 +01:00
sprintf (msg, "Zip error %s",zError(err));
2009-03-11 18:28:37 +01:00
ErrorPrompt(msg);
goto done;
}
int zippedsize = (int)DestBuffSize;
int decompressedsize = (int)bufoffset;
memcpy (savebuffer, &zippedsize, 4);
memcpy (savebuffer+4, &decompressedsize, 4);
woffset = zippedsize + 8;
}
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(gameScreenTex2 != NULL && method != METHOD_MC_SLOTA && method != METHOD_MC_SLOTB)
2009-03-11 18:28:37 +01:00
{
AllocSaveBuffer ();
IMGCTX pngContext = PNGU_SelectImageFromBuffer(savebuffer);
if (pngContext != NULL)
{
imgSize = PNGU_EncodeFromGXTexture(pngContext, 640, 480, gameScreenTex2, 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;
}
return 0;
}
2009-03-11 18:28:37 +01:00
int
NGCFreezeGameAuto (int method, bool silent)
{
2009-03-16 07:58:50 +01:00
if(method == METHOD_AUTO)
method = autoSaveMethod(silent);
if(method == METHOD_AUTO)
return false;
2009-03-11 18:28:37 +01:00
char filepath[1024];
2009-03-20 09:26:10 +01:00
if(!MakeFilePath(filepath, FILE_SNAPSHOT, method, Memory.ROMFilename, 0))
return false;
2009-03-11 18:28:37 +01:00
return NGCFreezeGame(filepath, method, silent);
}
/****************************************************************************
* NGCUnFreezeBlock
***************************************************************************/
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-12 05:25:16 +02:00
GetMem (buffer, 11);
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)
{
bufoffset -= 11; // go back to where we started
2008-08-12 05:25:16 +02:00
return WRONG_FORMAT;
}
2008-08-12 05:25:16 +02:00
if (len > size)
{
rem = len - size;
len = size;
}
2008-08-12 05:25:16 +02:00
ZeroMemory (block, size);
2008-08-12 05:25:16 +02:00
GetMem ((char *) block, len);
2008-08-12 05:25:16 +02:00
if (rem)
{
bufoffset += rem;
}
2008-08-12 05:25:16 +02:00
return SUCCESS;
}
/****************************************************************************
* NGCUnfreezeGame
***************************************************************************/
int
2009-03-11 18:28:37 +01:00
NGCUnfreezeGame (char * filepath, int method, bool silent)
{
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-12 05:25:16 +02:00
bufoffset = 0;
2009-03-20 09:26:10 +01:00
if(method == METHOD_AUTO)
method = autoSaveMethod(silent); // we use 'Save' because snapshot needs R/W
2009-03-20 09:26:10 +01:00
if(method == METHOD_AUTO)
2009-03-11 18:28:37 +01:00
return 0;
2009-03-20 09:26:10 +01:00
AllocSaveBuffer();
2008-11-12 08:50:39 +01:00
offset = LoadFile(filepath, method, silent);
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)
{
2009-02-07 04:01:10 +01:00
char * zipbuffer = (char *)memalign(32, SAVEBUFFERSIZE);
memset (zipbuffer, 0, SAVEBUFFERSIZE);
uLongf zipsize = 0;
uLongf decompressedsize = 0;
uLongf DestBuffSize = SAVEBUFFERSIZE;
memcpy (&zipsize, savebuffer, 4);
memcpy (&decompressedsize, savebuffer+4, 4);
int err= uncompress((Bytef*)zipbuffer, (uLongf*)&DestBuffSize, (const Bytef*)(savebuffer+8), zipsize);
if ( err!=Z_OK )
{
2009-03-20 09:26:10 +01:00
offset = 0;
2009-03-16 07:58:50 +01:00
sprintf (msg, "Unzip error %s",zError(err));
2009-03-11 18:28:37 +01:00
ErrorPrompt(msg);
}
2008-08-13 07:47:04 +02:00
else if ( DestBuffSize != decompressedsize )
{
2009-03-20 09:26:10 +01:00
offset = 0;
2009-03-11 18:28:37 +01:00
ErrorPrompt("Unzipped size doesn't match expected size!");
}
2008-08-13 07:47:04 +02:00
else
{
2009-03-20 09:26:10 +01:00
offset = decompressedsize;
memset(savebuffer, 0, SAVEBUFFERSIZE);
memcpy (savebuffer, zipbuffer, decompressedsize);
2008-08-13 07:47:04 +02:00
}
free(zipbuffer);
}
}
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
}
2009-03-20 09:26:10 +01:00
FreeSaveBuffer();
2008-09-27 09:13:52 +02:00
return result;
}
2009-03-11 18:28:37 +01:00
int
NGCUnfreezeGameAuto (int method, bool silent)
{
2009-03-16 07:58:50 +01:00
if(method == METHOD_AUTO)
method = autoSaveMethod(silent);
if(method == METHOD_AUTO)
return false;
2009-03-11 18:28:37 +01:00
char filepath[1024];
2009-03-16 07:58:50 +01:00
if(!MakeFilePath(filepath, FILE_SNAPSHOT, method, Memory.ROMFilename, 0))
return false;
2009-03-11 18:28:37 +01:00
return NGCUnfreezeGame(filepath, method, silent);
}