Merge pull request #2611 from TheKoopaKingdom/missing-file-dialogs

Display QMessageBox Dialogs For Errors
This commit is contained in:
bunnei 2017-06-02 22:24:29 -04:00 committed by GitHub
commit 81449f025a
14 changed files with 212 additions and 41 deletions

View file

@ -37,7 +37,10 @@ void EmuThread::run() {
if (!was_active) if (!was_active)
emit DebugModeLeft(); emit DebugModeLeft();
Core::System::GetInstance().RunLoop(); Core::System::ResultStatus result = Core::System::GetInstance().RunLoop();
if (result != Core::System::ResultStatus::Success) {
emit ErrorThrown(result, Core::System::GetInstance().GetStatusDetails());
}
was_active = running || exec_step; was_active = running || exec_step;
if (!was_active && !stop_run) if (!was_active && !stop_run)

View file

@ -10,6 +10,7 @@
#include <QGLWidget> #include <QGLWidget>
#include <QThread> #include <QThread>
#include "common/thread.h" #include "common/thread.h"
#include "core/core.h"
#include "core/frontend/emu_window.h" #include "core/frontend/emu_window.h"
#include "core/frontend/motion_emu.h" #include "core/frontend/motion_emu.h"
@ -97,6 +98,8 @@ signals:
* Qt::BlockingQueuedConnection (additionally block source thread until slot returns) * Qt::BlockingQueuedConnection (additionally block source thread until slot returns)
*/ */
void DebugModeLeft(); void DebugModeLeft();
void ErrorThrown(Core::System::ResultStatus, std::string);
}; };
class GRenderWindow : public QWidget, public EmuWindow { class GRenderWindow : public QWidget, public EmuWindow {

View file

@ -93,6 +93,14 @@ void GMainWindow::InitializeWidgets() {
ui.horizontalLayout->addWidget(game_list); ui.horizontalLayout->addWidget(game_list);
// Create status bar // Create status bar
message_label = new QLabel();
// Configured separately for left alignment
message_label->setVisible(false);
message_label->setFrameStyle(QFrame::NoFrame);
message_label->setContentsMargins(4, 0, 4, 0);
message_label->setAlignment(Qt::AlignLeft);
statusBar()->addPermanentWidget(message_label, 1);
emu_speed_label = new QLabel(); emu_speed_label = new QLabel();
emu_speed_label->setToolTip(tr("Current emulation speed. Values higher or lower than 100% " emu_speed_label->setToolTip(tr("Current emulation speed. Values higher or lower than 100% "
"indicate emulation is running faster or slower than a 3DS.")); "indicate emulation is running faster or slower than a 3DS."));
@ -108,7 +116,7 @@ void GMainWindow::InitializeWidgets() {
label->setVisible(false); label->setVisible(false);
label->setFrameStyle(QFrame::NoFrame); label->setFrameStyle(QFrame::NoFrame);
label->setContentsMargins(4, 0, 4, 0); label->setContentsMargins(4, 0, 4, 0);
statusBar()->addPermanentWidget(label); statusBar()->addPermanentWidget(label, 0);
} }
statusBar()->setVisible(true); statusBar()->setVisible(true);
setStyleSheet("QStatusBar::item{border: none;}"); setStyleSheet("QStatusBar::item{border: none;}");
@ -300,9 +308,8 @@ bool GMainWindow::LoadROM(const QString& filename) {
render_window->MakeCurrent(); render_window->MakeCurrent();
if (!gladLoadGL()) { if (!gladLoadGL()) {
QMessageBox::critical(this, tr("Error while starting Citra!"), QMessageBox::critical(this, tr("Error while initializing OpenGL 3.3 Core!"),
tr("Failed to initialize the video core!\n\n" tr("Your GPU may not support OpenGL 3.3, or you do not"
"Please ensure that your GPU supports OpenGL 3.3 and that you "
"have the latest graphics driver.")); "have the latest graphics driver."));
return false; return false;
} }
@ -327,18 +334,17 @@ bool GMainWindow::LoadROM(const QString& filename) {
break; break;
case Core::System::ResultStatus::ErrorLoader_ErrorEncrypted: { case Core::System::ResultStatus::ErrorLoader_ErrorEncrypted: {
// Build the MessageBox ourselves to have clickable link QMessageBox::critical(
QMessageBox popup_error; this, tr("Error while loading ROM!"),
popup_error.setTextFormat(Qt::RichText);
popup_error.setWindowTitle(tr("Error while loading ROM!"));
popup_error.setText(
tr("The game that you are trying to load must be decrypted before being used with " tr("The game that you are trying to load must be decrypted before being used with "
"Citra.<br/><br/>" "Citra. A real 3DS is required.<br/><br/>"
"For more information on dumping and decrypting games, please see: <a " "For more information on dumping and decrypting games, please see the following "
"href='https://citra-emu.org/wiki/Dumping-Game-Cartridges'>https://" "wiki pages: <ul>"
"citra-emu.org/wiki/Dumping-Game-Cartridges</a>")); "<li><a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>Dumping Game "
popup_error.setIcon(QMessageBox::Critical); "Cartridges</a></li>"
popup_error.exec(); "<li><a href='https://citra-emu.org/wiki/dumping-installed-titles/'>Dumping "
"Installed Titles</a></li>"
"</ul>"));
break; break;
} }
case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat: case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat:
@ -346,8 +352,23 @@ bool GMainWindow::LoadROM(const QString& filename) {
tr("The ROM format is not supported.")); tr("The ROM format is not supported."));
break; break;
case Core::System::ResultStatus::ErrorVideoCore:
QMessageBox::critical(
this, tr("An error occured in the video core."),
tr("Citra has encountered an error while running the video core, please see the "
"log for more details."
"For more information on accessing the log, please see the following page: "
"<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How "
"to "
"Upload the Log File</a>."
"Ensure that you have the latest graphics drivers for your GPU."));
break;
default: default:
QMessageBox::critical(this, tr("Error while loading ROM!"), tr("Unknown error!")); QMessageBox::critical(
this, tr("Error while loading ROM!"),
tr("An unknown error occured. Please see the log for more details."));
break; break;
} }
return false; return false;
@ -424,6 +445,7 @@ void GMainWindow::ShutdownGame() {
// Disable status bar updates // Disable status bar updates
status_bar_update_timer.stop(); status_bar_update_timer.stop();
message_label->setVisible(false);
emu_speed_label->setVisible(false); emu_speed_label->setVisible(false);
game_fps_label->setVisible(false); game_fps_label->setVisible(false);
emu_frametime_label->setVisible(false); emu_frametime_label->setVisible(false);
@ -530,6 +552,10 @@ void GMainWindow::OnMenuRecentFile() {
void GMainWindow::OnStartGame() { void GMainWindow::OnStartGame() {
emu_thread->SetRunning(true); emu_thread->SetRunning(true);
qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus");
qRegisterMetaType<std::string>("std::string");
connect(emu_thread.get(), SIGNAL(ErrorThrown(Core::System::ResultStatus, std::string)), this,
SLOT(OnCoreError(Core::System::ResultStatus, std::string)));
ui.action_Start->setEnabled(false); ui.action_Start->setEnabled(false);
ui.action_Start->setText(tr("Continue")); ui.action_Start->setText(tr("Continue"));
@ -622,11 +648,74 @@ void GMainWindow::UpdateStatusBar() {
emu_frametime_label->setVisible(true); emu_frametime_label->setVisible(true);
} }
void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string details) {
QMessageBox::StandardButton answer;
QString status_message;
const QString common_message =
tr("The game you are trying to load requires additional files from your 3DS to be dumped "
"before playing.<br/><br/>For more information on dumping these files, please see the "
"following wiki page: <a "
"href='https://citra-emu.org/wiki/"
"dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>Dumping System "
"Archives and the Shared Fonts from a 3DS Console</a>.<br/><br/>Would you like to quit "
"back to the game list? Continuing emulation may result in crashes, corrupted save "
"data, or other bugs.");
switch (result) {
case Core::System::ResultStatus::ErrorSystemFiles: {
QString message = "Citra was unable to locate a 3DS system archive";
if (!details.empty()) {
message.append(tr(": %1. ").arg(details.c_str()));
} else {
message.append(". ");
}
message.append(common_message);
answer = QMessageBox::question(this, tr("System Archive Not Found"), message,
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
status_message = "System Archive Missing";
break;
}
case Core::System::ResultStatus::ErrorSharedFont: {
QString message = tr("Citra was unable to locate the 3DS shared fonts. ");
message.append(common_message);
answer = QMessageBox::question(this, tr("Shared Fonts Not Found"), message,
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
status_message = "Shared Font Missing";
break;
}
default:
answer = QMessageBox::question(
this, tr("Fatal Error"),
tr("Citra has encountered a fatal error, please see the log for more details. "
"For more information on accessing the log, please see the following page: "
"<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to "
"Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? "
"Continuing emulation may result in crashes, corrupted save data, or other bugs."),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
status_message = "Fatal Error encountered";
break;
}
if (answer == QMessageBox::Yes) {
if (emu_thread) {
ShutdownGame();
}
} else {
// Only show the message if the game is still running.
if (emu_thread) {
message_label->setText(status_message);
message_label->setVisible(true);
}
}
}
bool GMainWindow::ConfirmClose() { bool GMainWindow::ConfirmClose() {
if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) if (emu_thread == nullptr || !UISettings::values.confirm_before_closing)
return true; return true;
auto answer = QMessageBox::StandardButton answer =
QMessageBox::question(this, tr("Citra"), tr("Are you sure you want to close Citra?"), QMessageBox::question(this, tr("Citra"), tr("Are you sure you want to close Citra?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No); QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
return answer != QMessageBox::No; return answer != QMessageBox::No;

View file

@ -8,6 +8,7 @@
#include <memory> #include <memory>
#include <QMainWindow> #include <QMainWindow>
#include <QTimer> #include <QTimer>
#include "core/core.h"
#include "ui_main.h" #include "ui_main.h"
class Config; class Config;
@ -125,6 +126,7 @@ private slots:
void OnDisplayTitleBars(bool); void OnDisplayTitleBars(bool);
void ToggleWindowMode(); void ToggleWindowMode();
void OnCreateGraphicsSurfaceViewer(); void OnCreateGraphicsSurfaceViewer();
void OnCoreError(Core::System::ResultStatus, std::string);
private: private:
void UpdateStatusBar(); void UpdateStatusBar();
@ -135,6 +137,7 @@ private:
GameList* game_list; GameList* game_list;
// Status bar elements // Status bar elements
QLabel* message_label = nullptr;
QLabel* emu_speed_label = nullptr; QLabel* emu_speed_label = nullptr;
QLabel* game_fps_label = nullptr; QLabel* game_fps_label = nullptr;
QLabel* emu_frametime_label = nullptr; QLabel* emu_frametime_label = nullptr;

View file

@ -3,7 +3,7 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <memory> #include <memory>
#include <utility>
#include "audio_core/audio_core.h" #include "audio_core/audio_core.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/arm/arm_interface.h" #include "core/arm/arm_interface.h"
@ -26,6 +26,7 @@ namespace Core {
/*static*/ System System::s_instance; /*static*/ System System::s_instance;
System::ResultStatus System::RunLoop(int tight_loop) { System::ResultStatus System::RunLoop(int tight_loop) {
status = ResultStatus::Success;
if (!cpu_core) { if (!cpu_core) {
return ResultStatus::ErrorNotInitialized; return ResultStatus::ErrorNotInitialized;
} }
@ -59,7 +60,7 @@ System::ResultStatus System::RunLoop(int tight_loop) {
HW::Update(); HW::Update();
Reschedule(); Reschedule();
return ResultStatus::Success; return status;
} }
System::ResultStatus System::SingleStep() { System::ResultStatus System::SingleStep() {
@ -73,14 +74,25 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
LOG_CRITICAL(Core, "Failed to obtain loader for %s!", filepath.c_str()); LOG_CRITICAL(Core, "Failed to obtain loader for %s!", filepath.c_str());
return ResultStatus::ErrorGetLoader; return ResultStatus::ErrorGetLoader;
} }
std::pair<boost::optional<u32>, Loader::ResultStatus> system_mode =
app_loader->LoadKernelSystemMode();
boost::optional<u32> system_mode{app_loader->LoadKernelSystemMode()}; if (system_mode.second != Loader::ResultStatus::Success) {
if (!system_mode) { LOG_CRITICAL(Core, "Failed to determine system mode (Error %i)!",
LOG_CRITICAL(Core, "Failed to determine system mode!"); static_cast<int>(system_mode.second));
return ResultStatus::ErrorSystemMode; System::Shutdown();
switch (system_mode.second) {
case Loader::ResultStatus::ErrorEncrypted:
return ResultStatus::ErrorLoader_ErrorEncrypted;
case Loader::ResultStatus::ErrorInvalidFormat:
return ResultStatus::ErrorLoader_ErrorInvalidFormat;
default:
return ResultStatus::ErrorSystemMode;
}
} }
ResultStatus init_result{Init(emu_window, system_mode.get())}; ResultStatus init_result{Init(emu_window, system_mode.first.get())};
if (init_result != ResultStatus::Success) { if (init_result != ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to initialize system (Error %i)!", init_result); LOG_CRITICAL(Core, "Failed to initialize system (Error %i)!", init_result);
System::Shutdown(); System::Shutdown();
@ -101,7 +113,8 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
return ResultStatus::ErrorLoader; return ResultStatus::ErrorLoader;
} }
} }
return ResultStatus::Success; status = ResultStatus::Success;
return status;
} }
void System::PrepareReschedule() { void System::PrepareReschedule() {

View file

@ -40,7 +40,10 @@ public:
ErrorLoader_ErrorEncrypted, ///< Error loading the specified application due to encryption ErrorLoader_ErrorEncrypted, ///< Error loading the specified application due to encryption
ErrorLoader_ErrorInvalidFormat, ///< Error loading the specified application due to an ErrorLoader_ErrorInvalidFormat, ///< Error loading the specified application due to an
/// invalid format /// invalid format
ErrorSystemFiles, ///< Error in finding system files
ErrorSharedFont, ///< Error in finding shared font
ErrorVideoCore, ///< Error in the video core ErrorVideoCore, ///< Error in the video core
ErrorUnknown ///< Any other error
}; };
/** /**
@ -105,6 +108,17 @@ public:
PerfStats perf_stats; PerfStats perf_stats;
FrameLimiter frame_limiter; FrameLimiter frame_limiter;
void SetStatus(ResultStatus new_status, const char* details = nullptr) {
status = new_status;
if (details) {
status_details = details;
}
}
const std::string& GetStatusDetails() const {
return status_details;
}
private: private:
/** /**
* Initialize the emulated system. * Initialize the emulated system.
@ -130,6 +144,9 @@ private:
std::unique_ptr<Core::TelemetrySession> telemetry_session; std::unique_ptr<Core::TelemetrySession> telemetry_session;
static System s_instance; static System s_instance;
ResultStatus status = ResultStatus::Success;
std::string status_details = "";
}; };
inline ARM_Interface& CPU() { inline ARM_Interface& CPU() {

View file

@ -9,7 +9,9 @@
#include "common/file_util.h" #include "common/file_util.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "core/core.h"
#include "core/file_sys/archive_ncch.h" #include "core/file_sys/archive_ncch.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/ivfc_archive.h" #include "core/file_sys/ivfc_archive.h"
#include "core/hle/service/fs/archive.h" #include "core/hle/service/fs/archive.h"
@ -33,11 +35,44 @@ ArchiveFactory_NCCH::ArchiveFactory_NCCH(const std::string& nand_directory)
ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_NCCH::Open(const Path& path) { ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_NCCH::Open(const Path& path) {
auto vec = path.AsBinary(); auto vec = path.AsBinary();
const u32* data = reinterpret_cast<u32*>(vec.data()); const u32* data = reinterpret_cast<u32*>(vec.data());
std::string file_path = GetNCCHPath(mount_point, data[1], data[0]); u32 high = data[1];
u32 low = data[0];
std::string file_path = GetNCCHPath(mount_point, high, low);
auto file = std::make_shared<FileUtil::IOFile>(file_path, "rb"); auto file = std::make_shared<FileUtil::IOFile>(file_path, "rb");
if (!file->IsOpen()) { if (!file->IsOpen()) {
return ResultCode(-1); // TODO(Subv): Find the right error code // High Title ID of the archive: The category (https://3dbrew.org/wiki/Title_list).
constexpr u32 shared_data_archive = 0x0004009B;
constexpr u32 system_data_archive = 0x000400DB;
// Low Title IDs.
constexpr u32 mii_data = 0x00010202;
constexpr u32 region_manifest = 0x00010402;
constexpr u32 ng_word_list = 0x00010302;
LOG_DEBUG(Service_FS, "Full Path: %s. Category: 0x%X. Path: 0x%X.", path.DebugStr().c_str(),
high, low);
if (high == shared_data_archive) {
if (low == mii_data) {
LOG_ERROR(Service_FS, "Failed to get a handle for shared data archive: Mii data. ");
Core::System::GetInstance().SetStatus(Core::System::ResultStatus::ErrorSystemFiles,
"Mii data");
} else if (low == region_manifest) {
LOG_ERROR(Service_FS,
"Failed to get a handle for shared data archive: region manifest.");
Core::System::GetInstance().SetStatus(Core::System::ResultStatus::ErrorSystemFiles,
"Region manifest");
}
} else if (high == system_data_archive) {
if (low == ng_word_list) {
LOG_ERROR(Service_FS,
"Failed to get a handle for system data archive: NG bad word list.");
Core::System::GetInstance().SetStatus(Core::System::ResultStatus::ErrorSystemFiles,
"NG bad word list");
}
}
return ERROR_NOT_FOUND;
} }
auto size = file->GetSize(); auto size = file->GetSize();

View file

@ -5,6 +5,7 @@
#include "common/common_paths.h" #include "common/common_paths.h"
#include "common/file_util.h" #include "common/file_util.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/applets/applet.h" #include "core/hle/applets/applet.h"
#include "core/hle/kernel/event.h" #include "core/hle/kernel/event.h"
#include "core/hle/kernel/mutex.h" #include "core/hle/kernel/mutex.h"
@ -74,6 +75,7 @@ void GetSharedFont(Service::Interface* self) {
LOG_ERROR(Service_APT, "shared font file missing - go dump it from your 3ds"); LOG_ERROR(Service_APT, "shared font file missing - go dump it from your 3ds");
rb.Push<u32>(-1); // TODO: Find the right error code rb.Push<u32>(-1); // TODO: Find the right error code
rb.Skip(1 + 2, true); rb.Skip(1 + 2, true);
Core::System::GetInstance().SetStatus(Core::System::ResultStatus::ErrorSharedFont);
return; return;
} }

View file

@ -10,6 +10,7 @@
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/result.h" #include "core/hle/result.h"
#include "core/hle/service/err_f.h" #include "core/hle/service/err_f.h"
@ -172,6 +173,7 @@ static void ThrowFatalError(Interface* self) {
const ErrInfo* errinfo = reinterpret_cast<ErrInfo*>(&cmd_buff[1]); const ErrInfo* errinfo = reinterpret_cast<ErrInfo*>(&cmd_buff[1]);
LOG_CRITICAL(Service_ERR, "Fatal error type: %s", LOG_CRITICAL(Service_ERR, "Fatal error type: %s",
GetErrType(errinfo->errinfo_common.specifier).c_str()); GetErrType(errinfo->errinfo_common.specifier).c_str());
Core::System::GetInstance().SetStatus(Core::System::ResultStatus::ErrorUnknown);
// Generic Info // Generic Info
LogGenericInfo(errinfo->errinfo_common); LogGenericInfo(errinfo->errinfo_common);

View file

@ -258,9 +258,7 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi
auto itr = id_code_map.find(id_code); auto itr = id_code_map.find(id_code);
if (itr == id_code_map.end()) { if (itr == id_code_map.end()) {
// TODO: Verify error against hardware return FileSys::ERROR_NOT_FOUND;
return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, ErrorSummary::NotFound,
ErrorLevel::Permanent);
} }
CASCADE_RESULT(std::unique_ptr<ArchiveBackend> res, itr->second->Open(archive_path)); CASCADE_RESULT(std::unique_ptr<ArchiveBackend> res, itr->second->Open(archive_path));

View file

@ -8,6 +8,7 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/scope_exit.h" #include "common/scope_exit.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "core/core.h"
#include "core/file_sys/errors.h" #include "core/file_sys/errors.h"
#include "core/hle/kernel/client_session.h" #include "core/hle/kernel/client_session.h"
#include "core/hle/result.h" #include "core/hle/result.h"
@ -130,7 +131,7 @@ static void OpenFileDirectly(Service::Interface* self) {
ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id, archive_path); ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id, archive_path);
if (archive_handle.Failed()) { if (archive_handle.Failed()) {
LOG_ERROR(Service_FS, LOG_ERROR(Service_FS,
"failed to get a handle for archive archive_id=0x%08X archive_path=%s", "Failed to get a handle for archive archive_id=0x%08X archive_path=%s",
static_cast<u32>(archive_id), archive_path.DebugStr().c_str()); static_cast<u32>(archive_id), archive_path.DebugStr().c_str());
cmd_buff[1] = archive_handle.Code().raw; cmd_buff[1] = archive_handle.Code().raw;
cmd_buff[3] = 0; cmd_buff[3] = 0;

View file

@ -8,6 +8,7 @@
#include <initializer_list> #include <initializer_list>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility>
#include <vector> #include <vector>
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include "common/common_types.h" #include "common/common_types.h"
@ -100,11 +101,11 @@ public:
* Loads the system mode that this application needs. * Loads the system mode that this application needs.
* This function defaults to 2 (96MB allocated to the application) if it can't read the * This function defaults to 2 (96MB allocated to the application) if it can't read the
* information. * information.
* @returns Optional with the kernel system mode * @returns A pair with the optional system mode, and and the status.
*/ */
virtual boost::optional<u32> LoadKernelSystemMode() { virtual std::pair<boost::optional<u32>, ResultStatus> LoadKernelSystemMode() {
// 96MB allocated to the application. // 96MB allocated to the application.
return 2; return std::make_pair(2, ResultStatus::Success);
} }
/** /**

View file

@ -121,12 +121,16 @@ FileType AppLoader_NCCH::IdentifyType(FileUtil::IOFile& file) {
return FileType::Error; return FileType::Error;
} }
boost::optional<u32> AppLoader_NCCH::LoadKernelSystemMode() { std::pair<boost::optional<u32>, ResultStatus> AppLoader_NCCH::LoadKernelSystemMode() {
if (!is_loaded) { if (!is_loaded) {
if (LoadExeFS() != ResultStatus::Success) ResultStatus res = LoadExeFS();
return boost::none; if (res != ResultStatus::Success) {
return std::make_pair(boost::none, res);
}
} }
return exheader_header.arm11_system_local_caps.system_mode.Value(); // Set the system mode as the one from the exheader.
return std::make_pair(exheader_header.arm11_system_local_caps.system_mode.Value(),
ResultStatus::Success);
} }
ResultStatus AppLoader_NCCH::LoadExec() { ResultStatus AppLoader_NCCH::LoadExec() {

View file

@ -179,9 +179,9 @@ public:
/** /**
* Loads the Exheader and returns the system mode for this application. * Loads the Exheader and returns the system mode for this application.
* @return Optional with the kernel system mode * @returns A pair with the optional system mode, and and the status.
*/ */
boost::optional<u32> LoadKernelSystemMode() override; std::pair<boost::optional<u32>, ResultStatus> LoadKernelSystemMode() override;
ResultStatus ReadCode(std::vector<u8>& buffer) override; ResultStatus ReadCode(std::vector<u8>& buffer) override;