From 23a16c1720ee522f6ac7d1f426a2d4a918ce41c9 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Mon, 3 Sep 2018 18:57:52 -0400 Subject: [PATCH] patch_manager: Centralize Control-type NCA parsing --- src/core/file_sys/patch_manager.cpp | 73 +++++++++++++++++++++-------- src/core/file_sys/patch_manager.h | 13 ++++- src/core/loader/nsp.cpp | 20 ++------ src/core/loader/xci.cpp | 21 ++------- src/yuzu/game_list.cpp | 28 ++--------- src/yuzu/main.cpp | 12 ++++- 6 files changed, 88 insertions(+), 79 deletions(-) diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index b6e25f7eb1..fa2fbe5e1f 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "core/file_sys/control_metadata.h" #include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" #include "core/hle/service/filesystem/filesystem.h" @@ -87,29 +88,63 @@ std::map PatchManager::GetPatchVersionNames() const { const auto installed = Service::FileSystem::GetUnionContents(); const auto update_tid = GetUpdateTitleID(title_id); - const auto update_control = installed->GetEntry(title_id, ContentRecordType::Control); - if (update_control != nullptr) { - do { - const auto romfs = - PatchRomFS(update_control->GetRomFS(), update_control->GetBaseIVFCOffset(), - FileSys::ContentRecordType::Control); - if (romfs == nullptr) - break; + PatchManager update{update_tid}; + auto [nacp, discard_icon_file] = update.GetControlMetadata(); - const auto control_dir = FileSys::ExtractRomFS(romfs); - if (control_dir == nullptr) - break; - - const auto nacp_file = control_dir->GetFile("control.nacp"); - if (nacp_file == nullptr) - break; - - FileSys::NACP nacp(nacp_file); - out[PatchType::Update] = nacp.GetVersionString(); - } while (false); + if (nacp != nullptr) { + out[PatchType::Update] = nacp->GetVersionString(); + } else { + if (installed->HasEntry(update_tid, ContentRecordType::Program)) { + const auto meta_ver = installed->GetEntryVersion(update_tid); + if (meta_ver == boost::none || meta_ver.get() == 0) { + out[PatchType::Update] = ""; + } else { + out[PatchType::Update] = + FormatTitleVersion(meta_ver.get(), TitleVersionFormat::ThreeElements); + } + } } return out; } +std::pair, VirtualFile> PatchManager::GetControlMetadata() const { + const auto& installed{Service::FileSystem::GetUnionContents()}; + + const auto base_control_nca = installed->GetEntry(title_id, ContentRecordType::Control); + if (base_control_nca == nullptr) + return {}; + + return ParseControlNCA(base_control_nca); +} + +std::pair, VirtualFile> PatchManager::ParseControlNCA( + const std::shared_ptr& nca) const { + const auto base_romfs = nca->GetRomFS(); + if (base_romfs == nullptr) + return {}; + + const auto romfs = PatchRomFS(base_romfs, nca->GetBaseIVFCOffset(), ContentRecordType::Control); + if (romfs == nullptr) + return {}; + + const auto extracted = ExtractRomFS(romfs); + if (extracted == nullptr) + return {}; + + auto nacp_file = extracted->GetFile("control.nacp"); + if (nacp_file == nullptr) + nacp_file = extracted->GetFile("Control.nacp"); + + const auto nacp = nacp_file == nullptr ? nullptr : std::make_shared(nacp_file); + + VirtualFile icon_file; + for (const auto& language : FileSys::LANGUAGE_NAMES) { + icon_file = extracted->GetFile("icon_" + std::string(language) + ".dat"); + if (icon_file != nullptr) + break; + } + + return {nacp, icon_file}; +} } // namespace FileSys diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h index b6bf86222b..c2626bc6cc 100644 --- a/src/core/file_sys/patch_manager.h +++ b/src/core/file_sys/patch_manager.h @@ -7,13 +7,14 @@ #include #include #include "common/common_types.h" +#include "core/file_sys/nca_metadata.h" +#include "core/file_sys/romfs_factory.h" #include "core/file_sys/vfs.h" -#include "nca_metadata.h" -#include "romfs_factory.h" namespace FileSys { class NCA; +class NACP; enum class TitleVersionFormat : u8 { ThreeElements, ///< vX.Y.Z @@ -47,6 +48,14 @@ public: // i.e. Update v80 will return {Update, 80} std::map GetPatchVersionNames() const; + // Given title_id of the program, attempts to get the control data of the update and parse it, + // falling back to the base control data. + std::pair, VirtualFile> GetControlMetadata() const; + + // Version of GetControlMetadata that takes an arbitrary NCA + std::pair, VirtualFile> ParseControlNCA( + const std::shared_ptr& nca) const; + private: u64 title_id; }; diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp index 7c06239f28..291a9876da 100644 --- a/src/core/loader/nsp.cpp +++ b/src/core/loader/nsp.cpp @@ -9,6 +9,8 @@ #include "core/file_sys/content_archive.h" #include "core/file_sys/control_metadata.h" #include "core/file_sys/nca_metadata.h" +#include "core/file_sys/patch_manager.h" +#include "core/file_sys/registered_cache.h" #include "core/file_sys/romfs.h" #include "core/file_sys/submission_package.h" #include "core/hle/kernel/process.h" @@ -28,24 +30,12 @@ AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file) return; const auto control_nca = - nsp->GetNCA(nsp->GetFirstTitleID(), FileSys::ContentRecordType::Control); + nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Control); if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) return; - const auto romfs = FileSys::ExtractRomFS(control_nca->GetRomFS()); - if (romfs == nullptr) - return; - - for (const auto& language : FileSys::LANGUAGE_NAMES) { - icon_file = romfs->GetFile("icon_" + std::string(language) + ".dat"); - if (icon_file != nullptr) - break; - } - - const auto nacp_raw = romfs->GetFile("control.nacp"); - if (nacp_raw == nullptr) - return; - nacp_file = std::make_shared(nacp_raw); + std::tie(nacp_file, icon_file) = + FileSys::PatchManager(nsp->GetProgramTitleID()).ParseControlNCA(control_nca); } AppLoader_NSP::~AppLoader_NSP() = default; diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index b01d51abb7..16509229f5 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp @@ -10,6 +10,7 @@ #include "core/file_sys/control_metadata.h" #include "core/file_sys/patch_manager.h" #include "core/file_sys/romfs.h" +#include "core/file_sys/submission_package.h" #include "core/hle/kernel/process.h" #include "core/loader/nca.h" #include "core/loader/xci.h" @@ -23,27 +24,11 @@ AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file) return; const auto control_nca = xci->GetNCAByType(FileSys::NCAContentType::Control); - if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) return; - auto romfs_raw = control_nca->GetRomFS(); - FileSys::PatchManager patch{xci->GetNCAByType(FileSys::NCAContentType::Program)->GetTitleId()}; - romfs_raw = patch.PatchRomFS(romfs_raw, control_nca->GetBaseIVFCOffset(), - FileSys::ContentRecordType::Control); - - const auto romfs = FileSys::ExtractRomFS(romfs_raw); - if (romfs == nullptr) - return; - for (const auto& language : FileSys::LANGUAGE_NAMES) { - icon_file = romfs->GetFile("icon_" + std::string(language) + ".dat"); - if (icon_file != nullptr) - break; - } - const auto nacp_raw = romfs->GetFile("control.nacp"); - if (nacp_raw == nullptr) - return; - nacp_file = std::make_shared(nacp_raw); + std::tie(nacp_file, icon_file) = + FileSys::PatchManager(xci->GetProgramTitleID()).ParseControlNCA(control_nca); } AppLoader_XCI::~AppLoader_XCI() = default; diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 38c5071e3a..a3b8416843 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -486,29 +486,11 @@ void GameList::RefreshGameDirectory() { static void GetMetadataFromControlNCA(const FileSys::PatchManager& patch_manager, const std::shared_ptr& nca, std::vector& icon, std::string& name) { - const auto romfs = patch_manager.PatchRomFS(nca->GetRomFS(), nca->GetBaseIVFCOffset(), - FileSys::ContentRecordType::Control); - if (romfs == nullptr) - return; - - const auto control_dir = FileSys::ExtractRomFS(romfs); - if (control_dir == nullptr) - return; - - const auto nacp_file = control_dir->GetFile("control.nacp"); - if (nacp_file == nullptr) - return; - FileSys::NACP nacp(nacp_file); - name = nacp.GetApplicationName(); - - FileSys::VirtualFile icon_file = nullptr; - for (const auto& language : FileSys::LANGUAGE_NAMES) { - icon_file = control_dir->GetFile("icon_" + std::string(language) + ".dat"); - if (icon_file != nullptr) { - icon = icon_file->ReadAllBytes(); - break; - } - } + auto [nacp, icon_file] = patch_manager.ParseControlNCA(nca); + if (icon_file != nullptr) + icon = icon_file->ReadAllBytes(); + if (nacp != nullptr) + name = nacp->GetApplicationName(); } GameListWorker::GameListWorker( diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index b7ce0248b0..80a2845133 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -592,8 +592,16 @@ void GMainWindow::BootGame(const QString& filename) { std::string title_name; const auto res = Core::System::GetInstance().GetGameName(title_name); - if (res != Loader::ResultStatus::Success) - title_name = FileUtil::GetFilename(filename.toStdString()); + if (res != Loader::ResultStatus::Success) { + const u64 program_id = Core::System::GetInstance().CurrentProcess()->program_id; + + const auto [nacp, icon_file] = FileSys::PatchManager(program_id).GetControlMetadata(); + if (nacp != nullptr) + title_name = nacp->GetApplicationName(); + + if (title_name.empty()) + title_name = FileUtil::GetFilename(filename.toStdString()); + } setWindowTitle(QString("yuzu %1| %4 | %2-%3") .arg(Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc,