From bfb945c2431ca1ccf1c5c43d4e3c7eaedf0bed31 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 9 Aug 2018 21:33:13 -0400 Subject: qt: Add 'Install to NAND' option to menu Prompts for title type on NCA files. --- src/yuzu/main.cpp | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) (limited to 'src/yuzu/main.cpp') diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 94fb8ae6a..c48191486 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -24,6 +24,7 @@ #include "common/string_util.h" #include "core/core.h" #include "core/crypto/key_manager.h" +#include "core/file_sys/card_image.h" #include "core/file_sys/vfs_real.h" #include "core/gdbstub/gdbstub.h" #include "core/loader/loader.h" @@ -114,6 +115,9 @@ GMainWindow::GMainWindow() .arg(Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc)); show(); + // Necessary to load titles from nand in gamelist. + Service::FileSystem::RegisterBIS(std::make_unique(vfs->OpenDirectory( + FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), FileSys::Mode::ReadWrite))); game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan); // Show one-time "callout" messages to the user @@ -309,6 +313,8 @@ void GMainWindow::ConnectMenuEvents() { // File connect(ui.action_Load_File, &QAction::triggered, this, &GMainWindow::OnMenuLoadFile); connect(ui.action_Load_Folder, &QAction::triggered, this, &GMainWindow::OnMenuLoadFolder); + connect(ui.action_Install_File_NAND, &QAction::triggered, this, + &GMainWindow::OnMenuInstallToNAND); connect(ui.action_Select_Game_List_Root, &QAction::triggered, this, &GMainWindow::OnMenuSelectGameListRoot); connect(ui.action_Exit, &QAction::triggered, this, &QMainWindow::close); @@ -612,6 +618,89 @@ void GMainWindow::OnMenuLoadFolder() { } } +void GMainWindow::OnMenuInstallToNAND() { + const static QString file_filter = + tr("Installable Switch File (*.nca *.xci);;Nintendo Content Archive (*.nca);;NX Cartridge " + "Image (*.xci)"); + QString filename = QFileDialog::getOpenFileName(this, tr("Install File"), + UISettings::values.roms_path, file_filter); + if (!filename.isEmpty()) { + if (filename.endsWith("xci", Qt::CaseInsensitive)) { + const auto xci = std::make_shared( + vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); + if (xci->GetStatus() != Loader::ResultStatus::Success) { + QMessageBox::critical( + this, tr("Failed to Install XCI"), + tr("The XCI file you provided is invalid. Please double-check your encryption " + "keys and the file and try again.")); + return; + } + if (!Service::FileSystem::GetUserNANDContents()->InstallEntry(xci)) { + QMessageBox::critical( + this, tr("Failed to Install XCI"), + tr("There was an error while attempting to install the provided XCI file. It " + "could have an incorrect format or be missing a metadata entry. Please " + "double-check your file and try again.")); + } else { + QMessageBox::information(this, tr("Successfully Installed XCI"), + tr("The file was successfully installed.")); + game_list->PopulateAsync(UISettings::values.gamedir, + UISettings::values.gamedir_deepscan); + } + } else { + const auto nca = std::make_shared( + vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); + if (nca->GetStatus() != Loader::ResultStatus::Success) { + QMessageBox::critical( + this, tr("Failed to Install NCA"), + tr("The NCA file you provided is invalid. Please double-check your encryption " + "keys and the file and try again.")); + return; + } + + const static QStringList tt_options{"System Application", + "System Archive", + "System Application Update", + "Firmware Package (Type A)", + "Firmware Package (Type B)", + "Game", + "Game Update", + "Game DLC", + "Delta Title"}; + bool ok; + const auto item = QInputDialog::getItem( + this, tr("Select NCA Install Type..."), + tr("Please select the type of title you would like to install this NCA as:\n(In " + "most instances, the default 'Game' is fine.)"), + tt_options, 5, false, &ok); + + auto index = tt_options.indexOf(item); + if (!ok || index == -1) { + QMessageBox::critical(this, tr("Failed to Install NCA"), + tr("The title type you selected for the NCA is invalid.")); + return; + } + + if (index >= 5) + index += 0x80; + + if (!Service::FileSystem::GetUserNANDContents()->InstallEntry( + nca, static_cast(index))) { + QMessageBox::critical(this, tr("Failed to Install NCA"), + tr("There was an error while attempting to install the " + "provided NCA file. An error might have occured creating " + "the metadata file or parsing the NCA. Please " + "double-check your file and try again.")); + } else { + QMessageBox::information(this, tr("Successfully Installed NCA"), + tr("The file was successfully installed.")); + game_list->PopulateAsync(UISettings::values.gamedir, + UISettings::values.gamedir_deepscan); + } + } + } +} + void GMainWindow::OnMenuSelectGameListRoot() { QString dir_path = QFileDialog::getExistingDirectory(this, tr("Select Directory")); if (!dir_path.isEmpty()) { -- cgit v1.2.3 From 167bfddafadb843236c0fa683cf97eaffaa5ea1a Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 9 Aug 2018 23:10:32 -0400 Subject: file_sys: Comply to style guidelines --- src/yuzu/main.cpp | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'src/yuzu/main.cpp') diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index c48191486..fd237df43 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -619,7 +619,7 @@ void GMainWindow::OnMenuLoadFolder() { } void GMainWindow::OnMenuInstallToNAND() { - const static QString file_filter = + const QString file_filter = tr("Installable Switch File (*.nca *.xci);;Nintendo Content Archive (*.nca);;NX Cartridge " "Image (*.xci)"); QString filename = QFileDialog::getOpenFileName(this, tr("Install File"), @@ -629,36 +629,36 @@ void GMainWindow::OnMenuInstallToNAND() { const auto xci = std::make_shared( vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); if (xci->GetStatus() != Loader::ResultStatus::Success) { - QMessageBox::critical( + QMessageBox::warning( this, tr("Failed to Install XCI"), tr("The XCI file you provided is invalid. Please double-check your encryption " "keys and the file and try again.")); return; } - if (!Service::FileSystem::GetUserNANDContents()->InstallEntry(xci)) { - QMessageBox::critical( - this, tr("Failed to Install XCI"), - tr("There was an error while attempting to install the provided XCI file. It " - "could have an incorrect format or be missing a metadata entry. Please " - "double-check your file and try again.")); - } else { + if (Service::FileSystem::GetUserNANDContents()->InstallEntry(xci)) { QMessageBox::information(this, tr("Successfully Installed XCI"), tr("The file was successfully installed.")); game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan); + } else { + QMessageBox::warning( + this, tr("Failed to Install XCI"), + tr("There was an error while attempting to install the provided XCI file. It " + "could have an incorrect format or be missing a metadata entry. Please " + "double-check your file and try again.")); } } else { const auto nca = std::make_shared( vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); if (nca->GetStatus() != Loader::ResultStatus::Success) { - QMessageBox::critical( + QMessageBox::warning( this, tr("Failed to Install NCA"), tr("The NCA file you provided is invalid. Please double-check your encryption " "keys and the file and try again.")); return; } - const static QStringList tt_options{"System Application", + static const QStringList tt_options{"System Application", "System Archive", "System Application Update", "Firmware Package (Type A)", @@ -676,26 +676,26 @@ void GMainWindow::OnMenuInstallToNAND() { auto index = tt_options.indexOf(item); if (!ok || index == -1) { - QMessageBox::critical(this, tr("Failed to Install NCA"), - tr("The title type you selected for the NCA is invalid.")); + QMessageBox::warning(this, tr("Failed to Install NCA"), + tr("The title type you selected for the NCA is invalid.")); return; } if (index >= 5) index += 0x80; - if (!Service::FileSystem::GetUserNANDContents()->InstallEntry( + if (Service::FileSystem::GetUserNANDContents()->InstallEntry( nca, static_cast(index))) { - QMessageBox::critical(this, tr("Failed to Install NCA"), - tr("There was an error while attempting to install the " - "provided NCA file. An error might have occured creating " - "the metadata file or parsing the NCA. Please " - "double-check your file and try again.")); - } else { QMessageBox::information(this, tr("Successfully Installed NCA"), tr("The file was successfully installed.")); game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan); + } else { + QMessageBox::warning(this, tr("Failed to Install NCA"), + tr("There was an error while attempting to install the " + "provided NCA file. An error might have occured creating " + "the metadata file or parsing the NCA. Please " + "double-check your file and try again.")); } } } -- cgit v1.2.3 From 10812f8407e18d129664e837614d6124ef9bf1bc Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 10 Aug 2018 11:11:33 -0400 Subject: game_list: Populate control data from installed NAND --- src/yuzu/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/yuzu/main.cpp') diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index fd237df43..1f5a9bb02 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -682,7 +682,7 @@ void GMainWindow::OnMenuInstallToNAND() { } if (index >= 5) - index += 0x80; + index += 0x7B; if (Service::FileSystem::GetUserNANDContents()->InstallEntry( nca, static_cast(index))) { -- cgit v1.2.3 From f78a6e752f70150f930eb66fe735723f3ffe5654 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 10 Aug 2018 15:07:06 -0400 Subject: qt: Use custom RawCopy with progress bar for installs --- src/yuzu/main.cpp | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'src/yuzu/main.cpp') diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 1f5a9bb02..e8254c30f 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -624,6 +624,32 @@ void GMainWindow::OnMenuInstallToNAND() { "Image (*.xci)"); QString filename = QFileDialog::getOpenFileName(this, tr("Install File"), UISettings::values.roms_path, file_filter); + + const auto qt_raw_copy = [this](FileSys::VirtualFile src, FileSys::VirtualFile dest) { + if (src == nullptr || dest == nullptr) + return false; + if (!dest->Resize(src->GetSize())) + return false; + + QProgressDialog progress(fmt::format("Installing file \"{}\"...", src->GetName()).c_str(), + "Cancel", 0, src->GetSize() / 0x1000, this); + progress.setWindowModality(Qt::WindowModal); + + std::array buffer{}; + for (size_t i = 0; i < src->GetSize(); i += 0x1000) { + if (progress.wasCanceled()) { + dest->Resize(0); + return false; + } + + progress.setValue(i / 0x1000); + const auto read = src->Read(buffer.data(), buffer.size(), i); + dest->Write(buffer.data(), read, i); + } + + return true; + }; + if (!filename.isEmpty()) { if (filename.endsWith("xci", Qt::CaseInsensitive)) { const auto xci = std::make_shared( @@ -635,7 +661,7 @@ void GMainWindow::OnMenuInstallToNAND() { "keys and the file and try again.")); return; } - if (Service::FileSystem::GetUserNANDContents()->InstallEntry(xci)) { + if (Service::FileSystem::GetUserNANDContents()->InstallEntry(xci, qt_raw_copy)) { QMessageBox::information(this, tr("Successfully Installed XCI"), tr("The file was successfully installed.")); game_list->PopulateAsync(UISettings::values.gamedir, @@ -685,7 +711,7 @@ void GMainWindow::OnMenuInstallToNAND() { index += 0x7B; if (Service::FileSystem::GetUserNANDContents()->InstallEntry( - nca, static_cast(index))) { + nca, static_cast(index), qt_raw_copy)) { QMessageBox::information(this, tr("Successfully Installed NCA"), tr("The file was successfully installed.")); game_list->PopulateAsync(UISettings::values.gamedir, -- cgit v1.2.3 From 6b76b774007020befdaa8d7475a9a4edd6d0a0a4 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sat, 11 Aug 2018 23:01:38 -0400 Subject: registration: Add support for force overwrite of installed --- src/yuzu/main.cpp | 88 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 30 deletions(-) (limited to 'src/yuzu/main.cpp') diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index e8254c30f..b5f97f332 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -650,37 +650,59 @@ void GMainWindow::OnMenuInstallToNAND() { return true; }; + const auto success = [this]() { + QMessageBox::information(this, tr("Successfully Installed"), + tr("The file was successfully installed.")); + game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan); + }; + + const auto failed = [this]() { + QMessageBox::warning( + this, tr("Failed to Install"), + tr("There was an error while attempting to install the provided file. It " + "could have an incorrect format or be missing metadata. Please " + "double-check your file and try again.")); + }; + + const auto overwrite = [this]() { + return QMessageBox::question(this, "Failed to Install", + "The file you are attempting to install already exists " + "in the cache. Would you like to overwrite it?") == + QMessageBox::Yes; + }; + if (!filename.isEmpty()) { if (filename.endsWith("xci", Qt::CaseInsensitive)) { const auto xci = std::make_shared( vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); if (xci->GetStatus() != Loader::ResultStatus::Success) { - QMessageBox::warning( - this, tr("Failed to Install XCI"), - tr("The XCI file you provided is invalid. Please double-check your encryption " - "keys and the file and try again.")); + failed(); return; } - if (Service::FileSystem::GetUserNANDContents()->InstallEntry(xci, qt_raw_copy)) { - QMessageBox::information(this, tr("Successfully Installed XCI"), - tr("The file was successfully installed.")); - game_list->PopulateAsync(UISettings::values.gamedir, - UISettings::values.gamedir_deepscan); + const auto res = + Service::FileSystem::GetUserNANDContents()->InstallEntry(xci, false, qt_raw_copy); + if (res == FileSys::InstallResult::Success) { + success(); } else { - QMessageBox::warning( - this, tr("Failed to Install XCI"), - tr("There was an error while attempting to install the provided XCI file. It " - "could have an incorrect format or be missing a metadata entry. Please " - "double-check your file and try again.")); + if (res == FileSys::InstallResult::ErrorAlreadyExists) { + if (overwrite()) { + const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry( + xci, true, qt_raw_copy); + if (res2 == FileSys::InstallResult::Success) { + success(); + } else { + failed(); + } + } + } else { + failed(); + } } } else { const auto nca = std::make_shared( vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); if (nca->GetStatus() != Loader::ResultStatus::Success) { - QMessageBox::warning( - this, tr("Failed to Install NCA"), - tr("The NCA file you provided is invalid. Please double-check your encryption " - "keys and the file and try again.")); + failed(); return; } @@ -702,7 +724,7 @@ void GMainWindow::OnMenuInstallToNAND() { auto index = tt_options.indexOf(item); if (!ok || index == -1) { - QMessageBox::warning(this, tr("Failed to Install NCA"), + QMessageBox::warning(this, tr("Failed to Install"), tr("The title type you selected for the NCA is invalid.")); return; } @@ -710,18 +732,24 @@ void GMainWindow::OnMenuInstallToNAND() { if (index >= 5) index += 0x7B; - if (Service::FileSystem::GetUserNANDContents()->InstallEntry( - nca, static_cast(index), qt_raw_copy)) { - QMessageBox::information(this, tr("Successfully Installed NCA"), - tr("The file was successfully installed.")); - game_list->PopulateAsync(UISettings::values.gamedir, - UISettings::values.gamedir_deepscan); + const auto res = Service::FileSystem::GetUserNANDContents()->InstallEntry( + nca, static_cast(index), false, qt_raw_copy); + if (res == FileSys::InstallResult::Success) { + success(); } else { - QMessageBox::warning(this, tr("Failed to Install NCA"), - tr("There was an error while attempting to install the " - "provided NCA file. An error might have occured creating " - "the metadata file or parsing the NCA. Please " - "double-check your file and try again.")); + if (res == FileSys::InstallResult::ErrorAlreadyExists) { + if (overwrite()) { + const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry( + nca, static_cast(index), true, qt_raw_copy); + if (res2 == FileSys::InstallResult::Success) { + success(); + } else { + failed(); + } + } + } else { + failed(); + } } } } -- cgit v1.2.3