Merge pull request #8490 from unknownbrackets/ui-tweaks

Show save state titles in the save state manager
This commit is contained in:
Henrik Rydgård committed 2016-01-24 00:51:04 +01:00
commit 19b0858d5e
6 files changed
+152 -55

No files matched your search

+76 -40
View File
@@ -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;
}
+19 -10
View File
@@ -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);
};
+44 -2
View File
@@ -293,6 +293,48 @@ namespace SaveState
static const char *SCREENSHOT_EXTENSION = "jpg";
// Slot utilities
std::string AppendSlotTitle(const std::string &filename, const std::string &title) {
if (!endsWith(filename, std::string(".") + STATE_EXTENSION)) {
return title + " (" + filename + ")";
}
// Usually these are slots, let's check the slot # after the last '_'.
size_t slotNumPos = filename.find_last_of('_');
if (slotNumPos == filename.npos) {
return title + " (" + filename + ")";
}
const size_t extLength = strlen(STATE_EXTENSION) + 1;
// If we take out the extension, '_', etc. we should be left with only a single digit.
if (slotNumPos + 1 + extLength != filename.length() - 1) {
return title + " (" + filename + ")";
}
std::string slot = filename.substr(slotNumPos + 1, 1);
if (slot[0] < '0' || slot[0] > '8') {
return title + " (" + filename + ")";
}
// Change from zero indexed to human friendly.
slot[0]++;
return title + " (" + slot + ")";
}
std::string GetTitle(const std::string &filename) {
std::string title;
if (CChunkFileReader::GetFileTitle(filename, &title) == CChunkFileReader::ERROR_NONE) {
if (title.empty()) {
return File::GetFilename(filename);
}
return AppendSlotTitle(filename, title);
}
// The file can't be loaded - let's note that.
I18NCategory *sy = GetI18NCategory("System");
return File::GetFilename(filename) + " " + sy->T("(broken)");
}
std::string GenerateSaveSlotFilename(const std::string &gameFilename, int slot, const char *extension)
{
std::string discId = g_paramSFO.GetValueString("DISC_ID");
@@ -541,7 +583,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 +601,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);
+2 -2
View File
@@ -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();
@@ -47,6 +45,8 @@ namespace SaveState
std::string GetSlotDateAsString(const std::string &gameFilename, int slot);
std::string GenerateSaveSlotFilename(const std::string &gameFilename, int slot, const char *extension);
std::string GetTitle(const std::string &filename);
// Load the specified file into the current state (async.)
// Warning: callback will be called on a different thread.
void Load(const std::string &filename, Callback callback = Callback(), void *cbUserData = 0);
+10 -1
View File
@@ -35,6 +35,7 @@
#include "Core/FileSystems/DirectoryFileSystem.h"
#include "Core/FileSystems/VirtualDiscFileSystem.h"
#include "Core/ELF/PBPReader.h"
#include "Core/SaveState.h"
#include "Core/System.h"
#include "Core/Util/GameManager.h"
#include "Core/Config.h"
@@ -287,6 +288,11 @@ std::string GameInfo::GetTitle() {
return title;
}
void GameInfo::SetTitle(const std::string &newTitle) {
lock_guard guard(lock);
title = newTitle;
}
static bool ReadFileToString(IFileSystem *fs, const char *filename, std::string *contents, recursive_mutex *mtx) {
PSPFileInfo info = fs->GetFileInfo(filename);
if (!info.exists) {
@@ -443,9 +449,12 @@ handleELF:
case FILETYPE_PPSSPP_SAVESTATE:
{
info_->SetTitle(SaveState::GetTitle(gamePath_));
lock_guard guard(info_->lock);
// Let's use the screenshot as an icon, too.
std::string screenshotPath = ReplaceAll(gamePath_, ".ppst", ".jpg");
lock_guard guard(info_->lock);
if (File::Exists(screenshotPath)) {
if (readFileToString(false, screenshotPath.c_str(), info_->iconTextureData)) {
info_->iconDataLoaded = true;
+1
View File
@@ -117,6 +117,7 @@ public:
std::vector<std::string> GetSaveDataDirectories();
std::string GetTitle();
void SetTitle(const std::string &newTitle);
// Hold this when reading or writing from the GameInfo.
// Don't need to hold it when just passing around the pointer,