From 92673736e3c8c4b4462e77073b37d96aee522215 Mon Sep 17 00:00:00 2001 From: Thierry Crozat Date: Mon, 11 Dec 2023 23:28:13 +0000 Subject: [PATCH] IOS7: Save state to a separate file when closing ScummVM The state information was saved using ConfMan in the scummvm ini file, but this could cause corruption of that ini file if the application was killed while ConfMan was flushed (see bug #14623). To reduce the risk of losing the config file, we now save the state to a separate file. --- backends/platform/ios7/ios7_osys_main.cpp | 59 +++++++++++++++-------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/backends/platform/ios7/ios7_osys_main.cpp b/backends/platform/ios7/ios7_osys_main.cpp index 0be4d416c9a50..6d089d161f282 100644 --- a/backends/platform/ios7/ios7_osys_main.cpp +++ b/backends/platform/ios7/ios7_osys_main.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -36,6 +37,7 @@ #include "common/fs.h" #include "common/config-manager.h" #include "common/translation.h" +#include "common/formats/ini-file.h" #include "base/main.h" @@ -280,49 +282,64 @@ void OSystem_iOS7::saveState() { if (g_engine && g_engine->hasFeature(Engine::kSupportsSavingDuringRuntime) && g_engine->canSaveAutosaveCurrently()) { Common::String targetName(ConfMan.getActiveDomainName()); int saveSlot = g_engine->getAutosaveSlot(); + if (saveSlot == -1) + return; // Make sure we do not overwrite a user save SaveStateDescriptor desc = g_engine->getMetaEngine()->querySaveMetaInfos(targetName.c_str(), saveSlot); if (desc.getSaveSlot() != -1 && !desc.isAutosave()) return; - // Do the auto-save, and if successful store this it in the config + // Do the auto-save, and if successful store this it in the uset settings if (g_engine->saveGameState(saveSlot, _("Autosave"), true).getCode() == Common::kNoError) { - ConfMan.set("restore_target", targetName, Common::ConfigManager::kApplicationDomain); - ConfMan.setInt("restore_slot", saveSlot, Common::ConfigManager::kApplicationDomain); - ConfMan.flushToDisk(); + Common::INIFile stateFile; + stateFile.addSection("state"); + stateFile.setKey("restore_target", "state", targetName); + stateFile.setKey("restore_slot", "state", Common::String::format("%d", saveSlot)); + stateFile.saveToFile("/scummvm.state"); } } } void OSystem_iOS7::restoreState() { - Common::String target; - int slot = -1; - if (ConfMan.hasKey("restore_target", Common::ConfigManager::kApplicationDomain) && - ConfMan.hasKey("restore_slot", Common::ConfigManager::kApplicationDomain)) { - target = ConfMan.get("restore_target", Common::ConfigManager::kApplicationDomain); - slot = ConfMan.getInt("restore_slot", Common::ConfigManager::kApplicationDomain); + // If the g_engine is still running (i.e. the application was not terminated) we don't need to do anything other than clear the saved state. + if (g_engine) { clearState(); + return; } - // If the g_engine is still running (i.e. the application was not terminated) we don't need to do anything. - if (g_engine) + // Read the state + Common::FSNode node("/scummvm.state"); + Common::File stateFile; + if (!stateFile.open(node)) return; - if (!target.empty() && slot != -1) { - ConfMan.setInt("save_slot", slot, Common::ConfigManager::kTransientDomain); - ConfMan.setActiveDomain(target); + Common::String targetName, slotString; + int saveSlot = -1; + Common::INIFile stateIniFile; + if (stateIniFile.loadFromStream(stateFile) && + stateIniFile.getKey("restore_target", "state", targetName) && + stateIniFile.getKey("restore_slot", "state", slotString) && + !slotString.empty()) { + char *errpos; + saveSlot = (int)strtol(slotString.c_str(), &errpos, 10); + if (slotString.c_str() == errpos) + saveSlot = -1; + } + + clearState(); + + // Reload the state + if (!targetName.empty() && saveSlot != -1) { + ConfMan.setInt("save_slot", saveSlot, Common::ConfigManager::kTransientDomain); + ConfMan.setActiveDomain(targetName); if (GUI::GuiManager::hasInstance()) g_gui.exitLoop(); } } void OSystem_iOS7::clearState() { - if (ConfMan.hasKey("restore_target", Common::ConfigManager::kApplicationDomain) && - ConfMan.hasKey("restore_slot", Common::ConfigManager::kApplicationDomain)) { - ConfMan.removeKey("restore_target", Common::ConfigManager::kApplicationDomain); - ConfMan.removeKey("restore_slot", Common::ConfigManager::kApplicationDomain); - ConfMan.flushToDisk(); - } + Common::String statePath = _chrootBasePath + "/scummvm.state"; + remove(statePath.c_str()); } uint32 OSystem_iOS7::getMillis(bool skipRecord) {