Merge pull request #1268 from unknownbrackets/savestates

Bump savestate version, add better error checking
This commit is contained in:
Henrik Rydgård 2013-04-13 02:09:12 -07:00
commit d92dbf8f6d
9 changed files with 56 additions and 20 deletions

View File

@ -115,16 +115,30 @@ public:
MODE_VERIFY, // compare
};
enum Error {
ERROR_NONE = 0,
ERROR_WARNING = 1,
ERROR_FAILURE = 2,
};
u8 **ptr;
Mode mode;
Error error;
public:
PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_) {}
PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), mode((Mode)mode_) {}
PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_), error(ERROR_NONE) {}
PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), mode((Mode)mode_), error(ERROR_NONE) {}
void SetMode(Mode mode_) {mode = mode_;}
Mode GetMode() const {return mode;}
u8 **GetPPtr() {return ptr;}
void SetError(Error error_)
{
if (error < error_)
error = error_;
if (error != ERROR_NONE)
mode = PointerWrap::MODE_MEASURE;
}
void DoVoid(void *data, int size)
{
@ -556,7 +570,7 @@ public:
if(mode == PointerWrap::MODE_READ && cookie != arbitraryNumber)
{
PanicAlertT("Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...", prevName, cookie, cookie, arbitraryNumber, arbitraryNumber);
mode = PointerWrap::MODE_MEASURE;
SetError(ERROR_FAILURE);
}
}
};
@ -642,7 +656,7 @@ public:
delete[] buf;
INFO_LOG(COMMON, "ChunkReader: Done loading %s" , _rFilename.c_str());
return true;
return p.error != p.ERROR_FAILURE;
}
// Save file template
@ -712,7 +726,7 @@ public:
INFO_LOG(COMMON,"ChunkReader: Done writing %s",
_rFilename.c_str());
return true;
return p.error != p.ERROR_FAILURE;
}
template <class T>

View File

@ -611,6 +611,7 @@ std::vector<PSPFileInfo> DirectoryFileSystem::GetDirListing(std::string path) {
void DirectoryFileSystem::DoState(PointerWrap &p) {
if (!entries.empty()) {
p.SetError(p.ERROR_WARNING);
ERROR_LOG(FILESYS, "FIXME: Open files during savestate, could go badly.");
}
}
@ -761,6 +762,7 @@ std::vector<PSPFileInfo> VFSFileSystem::GetDirListing(std::string path) {
void VFSFileSystem::DoState(PointerWrap &p) {
if (!entries.empty()) {
p.SetError(p.ERROR_WARNING);
ERROR_LOG(FILESYS, "FIXME: Open files during savestate, could go badly.");
}
}

View File

@ -422,6 +422,7 @@ void MetaFileSystem::DoState(PointerWrap &p)
p.Do(n);
if (n != (u32) fileSystems.size())
{
p.SetError(p.ERROR_FAILURE);
ERROR_LOG(FILESYS, "Savestate failure: number of filesystems doesn't match.");
return;
}

View File

@ -15,10 +15,11 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "HLE.h"
#include "../MIPS/MIPS.h"
#include "../MIPS/MIPSCodeUtils.h"
#include "../MIPS/MIPSInt.h"
#include "Core/Config.h"
#include "Core/HLE/HLE.h"
#include "Core/MIPS/MIPS.h"
#include "Core/MIPS/MIPSCodeUtils.h"
#include "Core/MIPS/MIPSInt.h"
#include "Common/LogManager.h"
#include "../FileSystems/FileSystem.h"
@ -161,6 +162,14 @@ void __KernelShutdown()
void __KernelDoState(PointerWrap &p)
{
std::string git_version = PPSSPP_GIT_VERSION;
p.Do(git_version);
if (git_version != PPSSPP_GIT_VERSION)
{
p.SetError(p.ERROR_WARNING);
WARN_LOG(HLE, "Warning: this savestate was generated by a different version of PPSSPP. It may not load properly.");
}
p.Do(kernelRunning);
kernelObjects.DoState(p);
p.DoMarker("KernelObjects");
@ -456,7 +465,11 @@ void KernelObjectPool::DoState(PointerWrap &p)
p.Do(_maxCount);
if (_maxCount != maxCount)
{
p.SetError(p.ERROR_FAILURE);
ERROR_LOG(HLE, "Unable to load state: different kernel object storage.");
return;
}
if (p.mode == p.MODE_READ)
{

View File

@ -227,6 +227,7 @@ void __InterruptsDoState(PointerWrap &p)
p.Do(numInterrupts);
if (numInterrupts != PSP_NUMBER_INTERRUPTS)
{
p.SetError(p.ERROR_FAILURE);
ERROR_LOG(HLE, "Savestate failure: wrong number of interrupts, can't load.");
return;
}

View File

@ -405,7 +405,11 @@ public:
u32 numCallbacks = THREAD_CALLBACK_NUM_TYPES;
p.Do(numCallbacks);
if (numCallbacks != THREAD_CALLBACK_NUM_TYPES)
ERROR_LOG(HLE, "Unable to load state: different kernel object storage.");
{
p.SetError(p.ERROR_FAILURE);
ERROR_LOG(HLE, "Unable to load state: different thread callback storage.");
return;
}
for (size_t i = 0; i < THREAD_CALLBACK_NUM_TYPES; ++i)
{
@ -581,6 +585,7 @@ struct ThreadQueueList
p.Do(numQueues);
if (numQueues != NUM_QUEUES)
{
p.SetError(p.ERROR_FAILURE);
ERROR_LOG(HLE, "Savestate loading error: invalid data");
return;
}

View File

@ -111,6 +111,11 @@ namespace SaveState
Enqueue(Operation(SAVESTATE_SAVE, filename, callback, cbUserData));
}
void Verify(Callback callback, void *cbUserData)
{
Enqueue(Operation(SAVESTATE_VERIFY, std::string(""), callback, cbUserData));
}
// Slot utilities
@ -148,9 +153,10 @@ namespace SaveState
(*callback)(false, cbUserData);
}
void HasSaveInSlot(int slot)
bool HasSaveInSlot(int slot)
{
std::string fn = GenerateSaveSlotFilename(slot);
return File::Exists(fn);
}
bool operator < (const tm &t1, const tm &t2) {
@ -186,11 +192,6 @@ namespace SaveState
}
void Verify(Callback callback, void *cbUserData)
{
Enqueue(Operation(SAVESTATE_VERIFY, std::string(""), callback, cbUserData));
}
std::vector<Operation> Flush()
{
std::lock_guard<std::recursive_mutex> guard(mutex);

View File

@ -24,14 +24,14 @@ namespace SaveState
typedef void (*Callback)(bool status, void *cbUserData);
// TODO: Better place for this?
const int REVISION = 1;
const int REVISION = 2;
const int SAVESTATESLOTS = 4;
void Init();
void SaveSlot(int slot, Callback callback, void *cbUserData = 0);
void LoadSlot(int slot, Callback callback, void *cbUserData = 0);
void HasSaveInSlot(int slot);
bool HasSaveInSlot(int slot);
int GetNewestSlot();
// Load the specified file into the current state (async.)

View File

@ -879,9 +879,8 @@ namespace MainWindow
void SaveStateActionFinished(bool result, void *userdata)
{
// TODO: Improve messaging?
if (!result)
MessageBox(0, "Savestate failure. Please try again later.", "Sorry", MB_OK);
MessageBox(0, "Savestate failure. Using savestates between different PPSSPP versions is not supported.", "Sorry", MB_OK);
SetCursor(LoadCursor(0, IDC_ARROW));
}