aboutsummaryrefslogtreecommitdiff
path: root/src/yuzu/main.cpp
diff options
context:
space:
mode:
authorcrueter <crueter@eden-emu.dev>2025-07-14 01:29:57 +0200
committercrueter <crueter@eden-emu.dev>2025-07-14 01:29:57 +0200
commitf99488fe3e4c0eb783b5fa8aeff42f753c38a0e9 (patch)
tree687b2c2a118c5b2b290ed05653e417893fcbb612 /src/yuzu/main.cpp
parent7b23cd0df4c2ecb13c3b032906950495b187c940 (diff)
[desktop] feat: install firmware from ZIP (#52)
Closes #12 Adds a menu option to install firmware from a packed ZIP. This PR additionally lays the groundwork to add data import/export via ZIP. In the future, a qt_common subproject should be added to handle common Qt tasks such as this. Furthermore, to decrease dependency complexity, this also introduces CPM, a wrapper around FetchContent. In theory, this should also lay the groundwork for #8 as well. Signed-off-by: crueter <crueter@eden-emu.dev> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/52
Diffstat (limited to 'src/yuzu/main.cpp')
-rw-r--r--src/yuzu/main.cpp128
1 files changed, 103 insertions, 25 deletions
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 081f08cf52..634c11bdce 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -12,6 +12,8 @@
#include "core/tools/renderdoc.h"
#include "frontend_common/firmware_manager.h"
+#include <JlCompress.h>
+
#ifdef __APPLE__
#include <unistd.h> // for chdir
#endif
@@ -1683,7 +1685,8 @@ void GMainWindow::ConnectMenuEvents() {
connect_menu(ui->action_Discord, &GMainWindow::OnOpenDiscord);
connect_menu(ui->action_Verify_installed_contents, &GMainWindow::OnVerifyInstalledContents);
- connect_menu(ui->action_Install_Firmware, &GMainWindow::OnInstallFirmware);
+ connect_menu(ui->action_Firmware_From_Folder, &GMainWindow::OnInstallFirmware);
+ connect_menu(ui->action_Firmware_From_ZIP, &GMainWindow::OnInstallFirmwareFromZIP);
connect_menu(ui->action_Install_Keys, &GMainWindow::OnInstallDecryptionKeys);
connect_menu(ui->action_About, &GMainWindow::OnAbout);
}
@@ -1714,7 +1717,8 @@ void GMainWindow::UpdateMenuState() {
action->setEnabled(emulation_running);
}
- ui->action_Install_Firmware->setEnabled(!emulation_running);
+ ui->action_Firmware_From_Folder->setEnabled(!emulation_running);
+ ui->action_Firmware_From_ZIP->setEnabled(!emulation_running);
ui->action_Install_Keys->setEnabled(!emulation_running);
for (QAction* action : applet_actions) {
@@ -4239,26 +4243,8 @@ void GMainWindow::OnVerifyInstalledContents() {
}
}
-void GMainWindow::OnInstallFirmware() {
- // Don't do this while emulation is running, that'd probably be a bad idea.
- if (emu_thread != nullptr && emu_thread->IsRunning()) {
- return;
- }
-
- // Check for installed keys, error out, suggest restart?
- if (!ContentManager::AreKeysPresent()) {
- QMessageBox::information(
- this, tr("Keys not installed"),
- tr("Install decryption keys and restart eden before attempting to install firmware."));
- return;
- }
-
- const QString firmware_source_location = QFileDialog::getExistingDirectory(
- this, tr("Select Dumped Firmware Source Location"), {}, QFileDialog::ShowDirsOnly);
- if (firmware_source_location.isEmpty()) {
- return;
- }
-
+void GMainWindow::InstallFirmware(const QString &location, bool recursive)
+{
QProgressDialog progress(tr("Installing Firmware..."), tr("Cancel"), 0, 100, this);
progress.setWindowModality(Qt::WindowModal);
progress.setMinimumDuration(100);
@@ -4272,11 +4258,11 @@ void GMainWindow::OnInstallFirmware() {
return progress.wasCanceled();
};
- LOG_INFO(Frontend, "Installing firmware from {}", firmware_source_location.toStdString());
+ LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString());
// Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in
// there.)
- std::filesystem::path firmware_source_path = firmware_source_location.toStdString();
+ std::filesystem::path firmware_source_path = location.toStdString();
if (!Common::FS::IsDir(firmware_source_path)) {
progress.close();
return;
@@ -4294,7 +4280,12 @@ void GMainWindow::OnInstallFirmware() {
QtProgressCallback(100, 10);
- Common::FS::IterateDirEntries(firmware_source_path, callback, Common::FS::DirEntryFilter::File);
+ if (recursive) {
+ Common::FS::IterateDirEntriesRecursively(firmware_source_path, callback, Common::FS::DirEntryFilter::File);
+ } else {
+ Common::FS::IterateDirEntries(firmware_source_path, callback, Common::FS::DirEntryFilter::File);
+ }
+
if (out.size() <= 0) {
progress.close();
QMessageBox::warning(this, tr("Firmware install failed"),
@@ -4377,6 +4368,93 @@ void GMainWindow::OnInstallFirmware() {
OnCheckFirmware();
}
+void GMainWindow::OnInstallFirmware() {
+ // Don't do this while emulation is running, that'd probably be a bad idea.
+ if (emu_thread != nullptr && emu_thread->IsRunning()) {
+ return;
+ }
+
+ // Check for installed keys, error out, suggest restart?
+ if (!ContentManager::AreKeysPresent()) {
+ QMessageBox::information(
+ this, tr("Keys not installed"),
+ tr("Install decryption keys and restart Eden before attempting to install firmware."));
+ return;
+ }
+
+ const QString firmware_source_location = QFileDialog::getExistingDirectory(
+ this, tr("Select Dumped Firmware Source Location"), {}, QFileDialog::ShowDirsOnly);
+ if (firmware_source_location.isEmpty()) {
+ return;
+ }
+
+ InstallFirmware(firmware_source_location);
+}
+
+void GMainWindow::OnInstallFirmwareFromZIP()
+{
+ // Don't do this while emulation is running, that'd probably be a bad idea.
+ if (emu_thread != nullptr && emu_thread->IsRunning()) {
+ return;
+ }
+
+ // Check for installed keys, error out, suggest restart?
+ if (!ContentManager::AreKeysPresent()) {
+ QMessageBox::information(
+ this, tr("Keys not installed"),
+ tr("Install decryption keys and restart Eden before attempting to install firmware."));
+ return;
+ }
+
+ const QString firmware_zip_location = QFileDialog::getOpenFileName(
+ this, tr("Select Dumped Firmware ZIP"), {}, tr("Zipped Archives (*.zip)"));
+ if (firmware_zip_location.isEmpty()) {
+ return;
+ }
+
+ namespace fs = std::filesystem;
+ fs::path tmp{std::filesystem::temp_directory_path()};
+
+ if (!std::filesystem::create_directories(tmp / "eden" / "firmware")) {
+ goto unzipFailed;
+ }
+
+ {
+ tmp /= "eden";
+ tmp /= "firmware";
+
+ QString qCacheDir = QString::fromStdString(tmp.string());
+
+ QFile zip(firmware_zip_location);
+
+ QStringList result = JlCompress::extractDir(&zip, qCacheDir);
+ if (result.isEmpty()) {
+ goto unzipFailed;
+ }
+
+ // In this case, it has to be done recursively, since sometimes people
+ // will pack it into a subdirectory after dumping
+ InstallFirmware(qCacheDir, true);
+
+ std::error_code ec;
+ std::filesystem::remove_all(tmp, ec);
+
+ if (ec) {
+ QMessageBox::warning(this, tr("Firmware cleanup failed"),
+ tr("Failed to clean up extracted firmware cache.\n"
+ "Check write permissions in the system temp directory and try again.\nOS reported error: %1")
+ .arg(ec.message()));
+ }
+
+ return;
+ }
+unzipFailed:
+ QMessageBox::critical(this, tr("Firmware unzip failed"),
+ tr("Check write permissions in the system temp directory and try again."));
+ return;
+
+}
+
void GMainWindow::OnInstallDecryptionKeys() {
// Don't do this while emulation is running.
if (emu_thread != nullptr && emu_thread->IsRunning()) {