mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Save the game title in savestates, if available.
So that the UI can show them. Old savestates still load fine, just don't have the title.
This commit is contained in:
parent
8d41664bb1
commit
6a5096e546
4 changed files with 97 additions and 54 deletions
|
@ -161,53 +161,81 @@ PointerWrapSection::~PointerWrapSection() {
|
|||
}
|
||||
}
|
||||
|
||||
CChunkFileReader::Error CChunkFileReader::LoadFile(const std::string& _rFilename, int _Revision, const char *_VersionString, u8 *&_buffer, size_t &sz, std::string *_failureReason) {
|
||||
if (!File::Exists(_rFilename)) {
|
||||
*_failureReason = "LoadStateDoesntExist";
|
||||
ERROR_LOG(COMMON, "ChunkReader: File doesn't exist");
|
||||
return ERROR_BAD_FILE;
|
||||
}
|
||||
|
||||
// Check file size
|
||||
const u64 fileSize = File::GetFileSize(_rFilename);
|
||||
static const u64 headerSize = sizeof(SChunkHeader);
|
||||
if (fileSize < headerSize)
|
||||
{
|
||||
ERROR_LOG(COMMON, "ChunkReader: File too small");
|
||||
return ERROR_BAD_FILE;
|
||||
}
|
||||
|
||||
File::IOFile pFile(_rFilename, "rb");
|
||||
if (!pFile)
|
||||
{
|
||||
CChunkFileReader::Error CChunkFileReader::LoadFileHeader(File::IOFile &pFile, SChunkHeader &header, std::string *title) {
|
||||
if (!pFile) {
|
||||
ERROR_LOG(COMMON, "ChunkReader: Can't open file for reading");
|
||||
return ERROR_BAD_FILE;
|
||||
}
|
||||
|
||||
// read the header
|
||||
SChunkHeader header;
|
||||
if (!pFile.ReadArray(&header, 1))
|
||||
{
|
||||
const u64 fileSize = pFile.GetSize();
|
||||
u64 headerSize = sizeof(SChunkHeader);
|
||||
if (fileSize < headerSize) {
|
||||
ERROR_LOG(COMMON, "ChunkReader: File too small");
|
||||
return ERROR_BAD_FILE;
|
||||
}
|
||||
|
||||
if (!pFile.ReadArray(&header, 1)) {
|
||||
ERROR_LOG(COMMON, "ChunkReader: Bad header size");
|
||||
return ERROR_BAD_FILE;
|
||||
}
|
||||
|
||||
// Check revision
|
||||
if (header.Revision != _Revision)
|
||||
{
|
||||
ERROR_LOG(COMMON, "ChunkReader: Wrong file revision, got %d expected %d", header.Revision, _Revision);
|
||||
if (header.Revision < REVISION_MIN) {
|
||||
ERROR_LOG(COMMON, "ChunkReader: Wrong file revision, got %d expected >= %d", header.Revision, REVISION_MIN);
|
||||
return ERROR_BAD_FILE;
|
||||
}
|
||||
|
||||
// get size
|
||||
sz = (int)(fileSize - headerSize);
|
||||
if (header.ExpectedSize != sz)
|
||||
{
|
||||
ERROR_LOG(COMMON, "ChunkReader: Bad file size, got %u expected %u", (u32)sz, header.ExpectedSize);
|
||||
if (header.Revision >= REVISION_TITLE) {
|
||||
char titleFixed[128];
|
||||
if (!pFile.ReadArray(titleFixed, sizeof(titleFixed))) {
|
||||
ERROR_LOG(COMMON, "ChunkReader: Unable to read title");
|
||||
return ERROR_BAD_FILE;
|
||||
}
|
||||
|
||||
if (title) {
|
||||
*title = titleFixed;
|
||||
}
|
||||
|
||||
headerSize += 128;
|
||||
} else if (title) {
|
||||
title->clear();
|
||||
}
|
||||
|
||||
u32 sz = (u32)(fileSize - headerSize);
|
||||
if (header.ExpectedSize != sz) {
|
||||
ERROR_LOG(COMMON, "ChunkReader: Bad file size, got %u expected %u", sz, header.ExpectedSize);
|
||||
return ERROR_BAD_FILE;
|
||||
}
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
CChunkFileReader::Error CChunkFileReader::GetFileTitle(const std::string &filename, std::string *title) {
|
||||
if (!File::Exists(filename)) {
|
||||
ERROR_LOG(COMMON, "ChunkReader: File doesn't exist");
|
||||
return ERROR_BAD_FILE;
|
||||
}
|
||||
|
||||
File::IOFile pFile(filename, "rb");
|
||||
SChunkHeader header;
|
||||
return LoadFileHeader(pFile, header, title);
|
||||
}
|
||||
|
||||
CChunkFileReader::Error CChunkFileReader::LoadFile(const std::string &filename, const char *gitVersion, u8 *&_buffer, size_t &sz, std::string *failureReason) {
|
||||
if (!File::Exists(filename)) {
|
||||
*failureReason = "LoadStateDoesntExist";
|
||||
ERROR_LOG(COMMON, "ChunkReader: File doesn't exist");
|
||||
return ERROR_BAD_FILE;
|
||||
}
|
||||
|
||||
File::IOFile pFile(filename, "rb");
|
||||
SChunkHeader header;
|
||||
Error err = LoadFileHeader(pFile, header, nullptr);
|
||||
if (err != ERROR_NONE) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// read the state
|
||||
sz = header.ExpectedSize;
|
||||
u8 *buffer = new u8[sz];
|
||||
if (!pFile.ReadBytes(buffer, sz))
|
||||
{
|
||||
|
@ -235,10 +263,10 @@ CChunkFileReader::Error CChunkFileReader::LoadFile(const std::string& _rFilename
|
|||
}
|
||||
|
||||
// Takes ownership of buffer.
|
||||
CChunkFileReader::Error CChunkFileReader::SaveFile(const std::string& _rFilename, int _Revision, const char *_VersionString, u8 *buffer, size_t sz) {
|
||||
INFO_LOG(COMMON, "ChunkReader: Writing %s" , _rFilename.c_str());
|
||||
CChunkFileReader::Error CChunkFileReader::SaveFile(const std::string &filename, const std::string &title, const char *gitVersion, u8 *buffer, size_t sz) {
|
||||
INFO_LOG(COMMON, "ChunkReader: Writing %s", filename.c_str());
|
||||
|
||||
File::IOFile pFile(_rFilename, "wb");
|
||||
File::IOFile pFile(filename, "wb");
|
||||
if (!pFile)
|
||||
{
|
||||
ERROR_LOG(COMMON, "ChunkReader: Error opening file for write");
|
||||
|
@ -251,12 +279,17 @@ CChunkFileReader::Error CChunkFileReader::SaveFile(const std::string& _rFilename
|
|||
// Create header
|
||||
SChunkHeader header;
|
||||
header.Compress = compress ? 1 : 0;
|
||||
header.Revision = _Revision;
|
||||
header.Revision = REVISION_CURRENT;
|
||||
header.ExpectedSize = (u32)sz;
|
||||
header.UncompressedSize = (u32)sz;
|
||||
strncpy(header.GitVersion, _VersionString, 32);
|
||||
strncpy(header.GitVersion, gitVersion, 32);
|
||||
header.GitVersion[31] = '\0';
|
||||
|
||||
// Setup the fixed-length title.
|
||||
char titleFixed[128];
|
||||
strncpy(titleFixed, title.c_str(), sizeof(titleFixed));
|
||||
titleFixed[sizeof(titleFixed) - 1] = '\0';
|
||||
|
||||
// Write to file
|
||||
if (compress) {
|
||||
size_t comp_len = snappy_max_compressed_length(sz);
|
||||
|
@ -264,11 +297,14 @@ CChunkFileReader::Error CChunkFileReader::SaveFile(const std::string& _rFilename
|
|||
snappy_compress((const char *)buffer, sz, (char *)compressed_buffer, &comp_len);
|
||||
delete [] buffer;
|
||||
header.ExpectedSize = (u32)comp_len;
|
||||
if (!pFile.WriteArray(&header, 1))
|
||||
{
|
||||
if (!pFile.WriteArray(&header, 1)) {
|
||||
ERROR_LOG(COMMON, "ChunkReader: Failed writing header");
|
||||
return ERROR_BAD_FILE;
|
||||
}
|
||||
if (!pFile.WriteArray(titleFixed, sizeof(titleFixed))) {
|
||||
ERROR_LOG(COMMON, "ChunkReader: Failed writing title");
|
||||
return ERROR_BAD_FILE;
|
||||
}
|
||||
if (!pFile.WriteBytes(&compressed_buffer[0], comp_len)) {
|
||||
ERROR_LOG(COMMON, "ChunkReader: Failed writing compressed data");
|
||||
return ERROR_BAD_FILE;
|
||||
|
@ -292,6 +328,6 @@ CChunkFileReader::Error CChunkFileReader::SaveFile(const std::string& _rFilename
|
|||
delete [] buffer;
|
||||
}
|
||||
|
||||
INFO_LOG(COMMON, "ChunkReader: Done writing %s", _rFilename.c_str());
|
||||
INFO_LOG(COMMON, "ChunkReader: Done writing %s", filename.c_str());
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
|
|
@ -632,28 +632,28 @@ public:
|
|||
|
||||
// Load file template
|
||||
template<class T>
|
||||
static Error Load(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class, std::string* _failureReason)
|
||||
static Error Load(const std::string &filename, const char *gitVersion, T& _class, std::string *failureReason)
|
||||
{
|
||||
*_failureReason = "LoadStateWrongVersion";
|
||||
*failureReason = "LoadStateWrongVersion";
|
||||
|
||||
u8 *ptr = nullptr;
|
||||
size_t sz;
|
||||
Error error = LoadFile(_rFilename, _Revision, _VersionString, ptr, sz, _failureReason);
|
||||
Error error = LoadFile(filename, gitVersion, ptr, sz, failureReason);
|
||||
if (error == ERROR_NONE) {
|
||||
error = LoadPtr(ptr, _class);
|
||||
delete [] ptr;
|
||||
}
|
||||
|
||||
INFO_LOG(COMMON, "ChunkReader: Done loading %s" , _rFilename.c_str());
|
||||
INFO_LOG(COMMON, "ChunkReader: Done loading %s", filename.c_str());
|
||||
if (error == ERROR_NONE) {
|
||||
_failureReason->clear();
|
||||
failureReason->clear();
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
// Save file template
|
||||
template<class T>
|
||||
static Error Save(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class)
|
||||
static Error Save(const std::string &filename, const std::string &title, const char *gitVersion, T& _class)
|
||||
{
|
||||
// Get data
|
||||
size_t const sz = MeasurePtr(_class);
|
||||
|
@ -662,7 +662,7 @@ public:
|
|||
|
||||
// SaveFile takes ownership of buffer
|
||||
if (error == ERROR_NONE)
|
||||
error = SaveFile(_rFilename, _Revision, _VersionString, buffer, sz);
|
||||
error = SaveFile(filename, title, gitVersion, buffer, sz);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -690,10 +690,9 @@ public:
|
|||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
private:
|
||||
static CChunkFileReader::Error LoadFile(const std::string& _rFilename, int _Revision, const char *_VersionString, u8 *&buffer, size_t &sz, std::string *_failureReason);
|
||||
static CChunkFileReader::Error SaveFile(const std::string& _rFilename, int _Revision, const char *_VersionString, u8 *buffer, size_t sz);
|
||||
static Error GetFileTitle(const std::string &filename, std::string *title);
|
||||
|
||||
private:
|
||||
struct SChunkHeader
|
||||
{
|
||||
int Revision;
|
||||
|
@ -702,4 +701,14 @@ private:
|
|||
u32 UncompressedSize;
|
||||
char GitVersion[32];
|
||||
};
|
||||
|
||||
enum {
|
||||
REVISION_MIN = 4,
|
||||
REVISION_TITLE = 5,
|
||||
REVISION_CURRENT = REVISION_TITLE,
|
||||
};
|
||||
|
||||
static Error LoadFile(const std::string &filename, const char *gitVersion, u8 *&buffer, size_t &sz, std::string *failureReason);
|
||||
static Error SaveFile(const std::string &filename, const std::string &title, const char *gitVersion, u8 *buffer, size_t sz);
|
||||
static Error LoadFileHeader(File::IOFile &pFile, SChunkHeader &header, std::string *title);
|
||||
};
|
||||
|
|
|
@ -541,7 +541,7 @@ namespace SaveState
|
|||
{
|
||||
case SAVESTATE_LOAD:
|
||||
INFO_LOG(COMMON, "Loading state from %s", op.filename.c_str());
|
||||
result = CChunkFileReader::Load(op.filename, REVISION, PPSSPP_GIT_VERSION, state, &reason);
|
||||
result = CChunkFileReader::Load(op.filename, PPSSPP_GIT_VERSION, state, &reason);
|
||||
if (result == CChunkFileReader::ERROR_NONE) {
|
||||
osm.Show(sc->T("Loaded State"), 2.0);
|
||||
callbackResult = true;
|
||||
|
@ -559,7 +559,7 @@ namespace SaveState
|
|||
|
||||
case SAVESTATE_SAVE:
|
||||
INFO_LOG(COMMON, "Saving state to %s", op.filename.c_str());
|
||||
result = CChunkFileReader::Save(op.filename, REVISION, PPSSPP_GIT_VERSION, state);
|
||||
result = CChunkFileReader::Save(op.filename, g_paramSFO.GetValueString("TITLE"), PPSSPP_GIT_VERSION, state);
|
||||
if (result == CChunkFileReader::ERROR_NONE) {
|
||||
|
||||
osm.Show(sc->T("Saved State"), 2.0);
|
||||
|
|
|
@ -25,8 +25,6 @@ namespace SaveState
|
|||
{
|
||||
typedef std::function<void(bool status, void *cbUserData)> Callback;
|
||||
|
||||
// TODO: Better place for this?
|
||||
const int REVISION = 4;
|
||||
const int SAVESTATESLOTS = 5;
|
||||
|
||||
void Init();
|
||||
|
|
Loading…
Add table
Reference in a new issue