From d53e94db88d18178ed73a5bc48b8df8e2fa4c992 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sun, 12 Apr 2020 23:12:15 +0100
Subject: [PATCH] Show save/load errors to the user

---
 src/citra_qt/main.cpp  |  3 +++
 src/core/core.cpp      | 20 +++++++++++++----
 src/core/core.h        |  1 +
 src/core/savestate.cpp | 49 ++++++++++++------------------------------
 4 files changed, 34 insertions(+), 39 deletions(-)

diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index f6dc3f2ef..7389b8c23 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -2079,6 +2079,9 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det
 
         title = tr("System Archive Not Found");
         status_message = tr("System Archive Missing");
+    } else if (result == Core::System::ResultStatus::ErrorSavestate) {
+        title = tr("Save/load Error");
+        message = QString::fromStdString(details);
     } else {
         title = tr("Fatal Error");
         message =
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 1421d7f70..14b41207a 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -107,15 +107,27 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
         return ResultStatus::ShutdownRequested;
     case Signal::Load: {
         LOG_INFO(Core, "Begin load");
-        System::LoadState(param);
-        LOG_INFO(Core, "Load completed");
+        try {
+            System::LoadState(param);
+            LOG_INFO(Core, "Load completed");
+        } catch (const std::exception& e) {
+            LOG_ERROR(Core, "Error loading: {}", e.what());
+            status_details = e.what();
+            return ResultStatus::ErrorSavestate;
+        }
         frame_limiter.WaitOnce();
         return ResultStatus::Success;
     }
     case Signal::Save: {
         LOG_INFO(Core, "Begin save");
-        System::SaveState(param);
-        LOG_INFO(Core, "Save completed");
+        try {
+            System::SaveState(param);
+            LOG_INFO(Core, "Save completed");
+        } catch (const std::exception& e) {
+            LOG_ERROR(Core, "Error saving: {}", e.what());
+            status_details = e.what();
+            return ResultStatus::ErrorSavestate;
+        }
         frame_limiter.WaitOnce();
         return ResultStatus::Success;
     }
diff --git a/src/core/core.h b/src/core/core.h
index eb3dc01b3..dca6a6888 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -89,6 +89,7 @@ public:
                                             /// generic drivers installed
         ErrorVideoCore_ErrorBelowGL33,      ///< Error in the video core due to the user not having
                                             /// OpenGL 3.3 or higher
+        ErrorSavestate,                     ///< Error saving or loading
         ShutdownRequested,                  ///< Emulated program requested a system shutdown
         ErrorUnknown                        ///< Any other error
     };
diff --git a/src/core/savestate.cpp b/src/core/savestate.cpp
index 2a6fb92cb..26fc0cbed 100644
--- a/src/core/savestate.cpp
+++ b/src/core/savestate.cpp
@@ -90,26 +90,22 @@ std::vector<SaveStateInfo> ListSaveStates(u64 program_id) {
 
 void System::SaveState(u32 slot) const {
     std::ostringstream sstream{std::ios_base::binary};
-    try {
-        oarchive oa{sstream};
-        oa&* this;
-    } catch (const std::exception& e) {
-        LOG_ERROR(Core, "Error saving: {}", e.what());
-    }
+    // Serialize
+    oarchive oa{sstream};
+    oa&* this;
+
     const std::string& str{sstream.str()};
     auto buffer = Common::Compression::CompressDataZSTDDefault(
         reinterpret_cast<const u8*>(str.data()), str.size());
 
     const auto path = GetSaveStatePath(title_id, slot);
     if (!FileUtil::CreateFullPath(path)) {
-        LOG_ERROR(Core, "Could not create path {}", path);
-        return;
+        throw std::runtime_error("Could not create path " + path);
     }
 
     FileUtil::IOFile file(path, "wb");
     if (!file) {
-        LOG_ERROR(Core, "Could not open file {}", path);
-        return;
+        throw std::runtime_error("Could not open file " + path);
     }
 
     CSTHeader header{};
@@ -123,41 +119,27 @@ void System::SaveState(u32 slot) const {
                       std::chrono::system_clock::now().time_since_epoch())
                       .count();
 
-    if (file.WriteBytes(&header, sizeof(header)) != sizeof(header)) {
-        LOG_ERROR(Core, "Could not write to file {}", path);
-        return;
-    }
-    if (file.WriteBytes(buffer.data(), buffer.size()) != buffer.size()) {
-        LOG_ERROR(Core, "Could not write to file {}", path);
-        return;
+    if (file.WriteBytes(&header, sizeof(header)) != sizeof(header) ||
+        file.WriteBytes(buffer.data(), buffer.size()) != buffer.size()) {
+        throw std::runtime_error("Could not write to file " + path);
     }
 }
 
 void System::LoadState(u32 slot) {
     if (Network::GetRoomMember().lock()->IsConnected()) {
-        LOG_ERROR(Core, "Unable to load while connected to multiplayer");
-        return;
+        throw std::runtime_error("Unable to load while connected to multiplayer");
     }
 
     const auto path = GetSaveStatePath(title_id, slot);
-    if (!FileUtil::Exists(path)) {
-        LOG_ERROR(Core, "File not exist {}", path);
-        return;
-    }
 
     std::vector<u8> decompressed;
     {
         std::vector<u8> buffer(FileUtil::GetSize(path) - sizeof(CSTHeader));
 
         FileUtil::IOFile file(path, "rb");
-        if (!file) {
-            LOG_ERROR(Core, "Could not open file {}", path);
-            return;
-        }
         file.Seek(sizeof(CSTHeader), SEEK_SET); // Skip header
         if (file.ReadBytes(buffer.data(), buffer.size()) != buffer.size()) {
-            LOG_ERROR(Core, "Could not read from file {}", path);
-            return;
+            throw std::runtime_error("Could not read from file at " + path);
         }
         decompressed = Common::Compression::DecompressDataZSTD(buffer);
     }
@@ -166,12 +148,9 @@ void System::LoadState(u32 slot) {
         std::ios_base::binary};
     decompressed.clear();
 
-    try {
-        iarchive ia{sstream};
-        ia&* this;
-    } catch (const std::exception& e) {
-        LOG_ERROR(Core, "Error loading: {}", e.what());
-    }
+    // Deserialize
+    iarchive ia{sstream};
+    ia&* this;
 }
 
 } // namespace Core