From 6a5096e546bfca6e847737eb4fc6c5d0a9b59bf8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 23 Jan 2016 12:53:03 -0800 Subject: [PATCH] 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. --- Common/ChunkFile.cpp | 116 ++++++++++++++++++++++++++++--------------- Common/ChunkFile.h | 29 +++++++---- Core/SaveState.cpp | 4 +- Core/SaveState.h | 2 - 4 files changed, 97 insertions(+), 54 deletions(-) diff --git a/Common/ChunkFile.cpp b/Common/ChunkFile.cpp index a315a98692..985cfe9424 100644 --- a/Common/ChunkFile.cpp +++ b/Common/ChunkFile.cpp @@ -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; } diff --git a/Common/ChunkFile.h b/Common/ChunkFile.h index 56d7d9076b..c3880e9f0d 100644 --- a/Common/ChunkFile.h +++ b/Common/ChunkFile.h @@ -632,28 +632,28 @@ public: // Load file template template - 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 - 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); }; diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index 4317996c17..a407c253a5 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -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); diff --git a/Core/SaveState.h b/Core/SaveState.h index 99eca4cbaf..e23c53278e 100644 --- a/Core/SaveState.h +++ b/Core/SaveState.h @@ -25,8 +25,6 @@ namespace SaveState { typedef std::function Callback; - // TODO: Better place for this? - const int REVISION = 4; const int SAVESTATESLOTS = 5; void Init();