diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 9ee7a5ee4b..f2e6c03f0d 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2581,50 +2581,48 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa return; } - FileSys::VirtualFile base_romfs; - if (loader->ReadRomFS(base_romfs) != Loader::ResultStatus::Success) { - failed(); - return; - } + FileSys::VirtualFile packed_update_raw{}; + loader->ReadUpdateRaw(packed_update_raw); const auto& installed = system->GetContentProvider(); - const auto romfs_title_id = SelectRomFSDumpTarget(installed, program_id); - if (!romfs_title_id) { + u64 title_id{}; + u8 raw_type{}; + if (!SelectRomFSDumpTarget(installed, program_id, &title_id, &raw_type)) { failed(); return; } - const auto type = *romfs_title_id == program_id ? FileSys::ContentRecordType::Program - : FileSys::ContentRecordType::Data; - const auto base_nca = installed.GetEntry(*romfs_title_id, type); + const auto type = static_cast(raw_type); + const auto base_nca = installed.GetEntry(title_id, type); if (!base_nca) { failed(); return; } + const FileSys::NCA update_nca{packed_update_raw, nullptr}; + if (type != FileSys::ContentRecordType::Program || + update_nca.GetStatus() != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS || + update_nca.GetTitleId() != FileSys::GetUpdateTitleID(title_id)) { + packed_update_raw = {}; + } + + const auto base_romfs = base_nca->GetRomFS(); + if (!base_romfs) { + failed(); + return; + } + const auto dump_dir = target == DumpRomFSTarget::Normal ? Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir) : Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir) / "atmosphere" / "contents"; - const auto romfs_dir = fmt::format("{:016X}/romfs", *romfs_title_id); + const auto romfs_dir = fmt::format("{:016X}/romfs", title_id); const auto path = Common::FS::PathToUTF8String(dump_dir / romfs_dir); - FileSys::VirtualFile romfs; - - if (*romfs_title_id == program_id) { - const FileSys::PatchManager pm{program_id, system->GetFileSystemController(), installed}; - romfs = pm.PatchRomFS(base_nca.get(), base_romfs, type, nullptr, false); - } else { - romfs = installed.GetEntry(*romfs_title_id, type)->GetRomFS(); - } - - const auto extracted = FileSys::ExtractRomFS(romfs, FileSys::RomFSExtractionType::Full); - if (extracted == nullptr) { - failed(); - return; - } + const FileSys::PatchManager pm{title_id, system->GetFileSystemController(), installed}; + auto romfs = pm.PatchRomFS(base_nca.get(), base_romfs, type, packed_update_raw, false); const auto out = VfsFilesystemCreateDirectoryWrapper(vfs, path, FileSys::Mode::ReadWrite); @@ -2648,6 +2646,12 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa return; } + const auto extracted = FileSys::ExtractRomFS(romfs, FileSys::RomFSExtractionType::Full); + if (extracted == nullptr) { + failed(); + return; + } + const auto full = res == selections.constFirst(); const auto entry_size = CalculateRomFSEntrySize(extracted, full); @@ -4358,28 +4362,41 @@ bool GMainWindow::CheckSystemArchiveDecryption() { return mii_nca->GetRomFS().get() != nullptr; } -std::optional GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installed, - u64 program_id) { - const auto dlc_entries = - installed.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data); - std::vector dlc_match; - dlc_match.reserve(dlc_entries.size()); - std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match), - [&program_id, &installed](const FileSys::ContentProviderEntry& entry) { - return FileSys::GetBaseTitleID(entry.title_id) == program_id && - installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success; - }); +bool GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installed, u64 program_id, + u64* selected_title_id, u8* selected_content_record_type) { + using ContentInfo = std::pair; + boost::container::flat_map available_title_ids; - std::vector romfs_tids; - romfs_tids.push_back(program_id); - for (const auto& entry : dlc_match) { - romfs_tids.push_back(entry.title_id); + const auto RetrieveEntries = [&](FileSys::TitleType title_type, + FileSys::ContentRecordType record_type) { + const auto entries = installed.ListEntriesFilter(title_type, record_type); + for (const auto& entry : entries) { + if (FileSys::GetBaseTitleID(entry.title_id) == program_id && + installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success) { + available_title_ids[entry.title_id] = {title_type, record_type}; + } + } + }; + + RetrieveEntries(FileSys::TitleType::Application, FileSys::ContentRecordType::Program); + RetrieveEntries(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data); + + if (available_title_ids.empty()) { + return false; } - if (romfs_tids.size() > 1) { - QStringList list{QStringLiteral("Base")}; - for (std::size_t i = 1; i < romfs_tids.size(); ++i) { - list.push_back(QStringLiteral("DLC %1").arg(romfs_tids[i] & 0x7FF)); + size_t title_index = 0; + + if (available_title_ids.size() > 1) { + QStringList list; + for (auto& [title_id, content_info] : available_title_ids) { + const auto hex_title_id = QString::fromStdString(fmt::format("{:X}", title_id)); + if (content_info.first == FileSys::TitleType::Application) { + list.push_back(QStringLiteral("Application [%1]").arg(hex_title_id)); + } else { + list.push_back( + QStringLiteral("DLC %1 [%2]").arg(title_id & 0x7FF).arg(hex_title_id)); + } } bool ok; @@ -4387,13 +4404,16 @@ std::optional GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProv this, tr("Select RomFS Dump Target"), tr("Please select which RomFS you would like to dump."), list, 0, false, &ok); if (!ok) { - return {}; + return false; } - return romfs_tids[list.indexOf(res)]; + title_index = list.indexOf(res); } - return program_id; + const auto selected_info = available_title_ids.nth(title_index); + *selected_title_id = selected_info->first; + *selected_content_record_type = static_cast(selected_info->second.second); + return true; } bool GMainWindow::ConfirmClose() { diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 1b7055122b..668dbc3b13 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -375,7 +375,8 @@ private: void RemoveAllTransferableShaderCaches(u64 program_id); void RemoveCustomConfiguration(u64 program_id, const std::string& game_path); void RemoveCacheStorage(u64 program_id); - std::optional SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id); + bool SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id, + u64* selected_title_id, u8* selected_content_record_type); InstallResult InstallNSPXCI(const QString& filename); InstallResult InstallNCA(const QString& filename); void MigrateConfigFiles();