mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	qt: Add support for dumping a DLC Data RomFS
This commit is contained in:
		
							parent
							
								
									59044862a9
								
							
						
					
					
						commit
						9d0fb0f815
					
				@ -35,6 +35,10 @@ bool operator==(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs
 | 
				
			|||||||
    return std::tie(lhs.title_id, lhs.type) == std::tie(rhs.title_id, rhs.type);
 | 
					    return std::tie(lhs.title_id, lhs.type) == std::tie(rhs.title_id, rhs.type);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool operator!=(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs) {
 | 
				
			||||||
 | 
					    return !operator==(lhs, rhs);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool FollowsTwoDigitDirFormat(std::string_view name) {
 | 
					static bool FollowsTwoDigitDirFormat(std::string_view name) {
 | 
				
			||||||
    static const std::regex two_digit_regex("000000[0-9A-F]{2}", std::regex_constants::ECMAScript |
 | 
					    static const std::regex two_digit_regex("000000[0-9A-F]{2}", std::regex_constants::ECMAScript |
 | 
				
			||||||
                                                                     std::regex_constants::icase);
 | 
					                                                                     std::regex_constants::icase);
 | 
				
			||||||
 | 
				
			|||||||
@ -52,6 +52,7 @@ bool operator<(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// std unique requires operator== to identify duplicates.
 | 
					// std unique requires operator== to identify duplicates.
 | 
				
			||||||
bool operator==(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs);
 | 
					bool operator==(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs);
 | 
				
			||||||
 | 
					bool operator!=(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * A class that catalogues NCAs in the registered directory structure.
 | 
					 * A class that catalogues NCAs in the registered directory structure.
 | 
				
			||||||
 | 
				
			|||||||
@ -100,6 +100,8 @@ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * "Callouts" are one-time instructional messages shown to the user. In the config settings, there
 | 
					 * "Callouts" are one-time instructional messages shown to the user. In the config settings, there
 | 
				
			||||||
 * is a bitfield "callout_flags" options, used to track if a message has already been shown to the
 | 
					 * is a bitfield "callout_flags" options, used to track if a message has already been shown to the
 | 
				
			||||||
@ -823,14 +825,10 @@ static bool RomFSRawCopy(QProgressDialog& dialog, const FileSys::VirtualDir& src
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path) {
 | 
					void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path) {
 | 
				
			||||||
    const auto path = fmt::format("{}{:016X}/romfs",
 | 
					    const auto failed = [this] {
 | 
				
			||||||
                                  FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), program_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const auto failed = [this, &path] {
 | 
					 | 
				
			||||||
        QMessageBox::warning(this, tr("RomFS Extraction Failed!"),
 | 
					        QMessageBox::warning(this, tr("RomFS Extraction Failed!"),
 | 
				
			||||||
                             tr("There was an error copying the RomFS files or the user "
 | 
					                             tr("There was an error copying the RomFS files or the user "
 | 
				
			||||||
                                "cancelled the operation."));
 | 
					                                "cancelled the operation."));
 | 
				
			||||||
        vfs->DeleteDirectory(path);
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const auto loader = Loader::GetLoader(vfs->OpenFile(game_path, FileSys::Mode::Read));
 | 
					    const auto loader = Loader::GetLoader(vfs->OpenFile(game_path, FileSys::Mode::Read));
 | 
				
			||||||
@ -845,10 +843,24 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const auto romfs =
 | 
					    const auto installed = Service::FileSystem::GetUnionContents();
 | 
				
			||||||
        loader->IsRomFSUpdatable()
 | 
					    auto romfs_title_id = SelectRomFSDumpTarget(*installed, program_id);
 | 
				
			||||||
            ? FileSys::PatchManager(program_id).PatchRomFS(file, loader->ReadRomFSIVFCOffset())
 | 
					
 | 
				
			||||||
            : file;
 | 
					    if (!romfs_title_id) {
 | 
				
			||||||
 | 
					        failed();
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const auto path = fmt::format(
 | 
				
			||||||
 | 
					        "{}{:016X}/romfs", FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), *romfs_title_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FileSys::VirtualFile romfs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (*romfs_title_id == program_id) {
 | 
				
			||||||
 | 
					        romfs = file;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        romfs = installed->GetEntry(*romfs_title_id, FileSys::ContentRecordType::Data)->GetRomFS();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const auto extracted = FileSys::ExtractRomFS(romfs, FileSys::RomFSExtractionType::Full);
 | 
					    const auto extracted = FileSys::ExtractRomFS(romfs, FileSys::RomFSExtractionType::Full);
 | 
				
			||||||
    if (extracted == nullptr) {
 | 
					    if (extracted == nullptr) {
 | 
				
			||||||
@ -860,6 +872,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (out == nullptr) {
 | 
					    if (out == nullptr) {
 | 
				
			||||||
        failed();
 | 
					        failed();
 | 
				
			||||||
 | 
					        vfs->DeleteDirectory(path);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -870,8 +883,11 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
 | 
				
			|||||||
           "files into the new directory while <br>skeleton will only create the directory "
 | 
					           "files into the new directory while <br>skeleton will only create the directory "
 | 
				
			||||||
           "structure."),
 | 
					           "structure."),
 | 
				
			||||||
        {"Full", "Skeleton"}, 0, false, &ok);
 | 
					        {"Full", "Skeleton"}, 0, false, &ok);
 | 
				
			||||||
    if (!ok)
 | 
					    if (!ok) {
 | 
				
			||||||
        failed();
 | 
					        failed();
 | 
				
			||||||
 | 
					        vfs->DeleteDirectory(path);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const auto full = res == "Full";
 | 
					    const auto full = res == "Full";
 | 
				
			||||||
    const auto entry_size = CalculateRomFSEntrySize(extracted, full);
 | 
					    const auto entry_size = CalculateRomFSEntrySize(extracted, full);
 | 
				
			||||||
@ -888,6 +904,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
 | 
				
			|||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        progress.close();
 | 
					        progress.close();
 | 
				
			||||||
        failed();
 | 
					        failed();
 | 
				
			||||||
 | 
					        vfs->DeleteDirectory(path);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1459,6 +1476,42 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					boost::optional<u64> GMainWindow::SelectRomFSDumpTarget(
 | 
				
			||||||
 | 
					    const FileSys::RegisteredCacheUnion& installed, u64 program_id) {
 | 
				
			||||||
 | 
					    const auto dlc_entries =
 | 
				
			||||||
 | 
					        installed.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
 | 
				
			||||||
 | 
					    std::vector<FileSys::RegisteredCacheEntry> 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::RegisteredCacheEntry& entry) {
 | 
				
			||||||
 | 
					                     return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == program_id &&
 | 
				
			||||||
 | 
					                            installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success;
 | 
				
			||||||
 | 
					                 });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::vector<u64> romfs_tids;
 | 
				
			||||||
 | 
					    romfs_tids.push_back(program_id);
 | 
				
			||||||
 | 
					    for (const auto& entry : dlc_match)
 | 
				
			||||||
 | 
					        romfs_tids.push_back(entry.title_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (romfs_tids.size() > 1) {
 | 
				
			||||||
 | 
					        QStringList list{"Base"};
 | 
				
			||||||
 | 
					        for (std::size_t i = 1; i < romfs_tids.size(); ++i)
 | 
				
			||||||
 | 
					            list.push_back(QStringLiteral("DLC %1").arg(romfs_tids[i] & 0x7FF));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bool ok;
 | 
				
			||||||
 | 
					        const auto res = QInputDialog::getItem(
 | 
				
			||||||
 | 
					            this, tr("Select RomFS Dump Target"),
 | 
				
			||||||
 | 
					            tr("Please select which RomFS you would like to dump."), list, 0, false, &ok);
 | 
				
			||||||
 | 
					        if (!ok) {
 | 
				
			||||||
 | 
					            return boost::none;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return romfs_tids[list.indexOf(res)];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return program_id;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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;
 | 
				
			||||||
 | 
				
			|||||||
@ -10,6 +10,7 @@
 | 
				
			|||||||
#include <QMainWindow>
 | 
					#include <QMainWindow>
 | 
				
			||||||
#include <QTimer>
 | 
					#include <QTimer>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <boost/optional.hpp>
 | 
				
			||||||
#include "common/common_types.h"
 | 
					#include "common/common_types.h"
 | 
				
			||||||
#include "core/core.h"
 | 
					#include "core/core.h"
 | 
				
			||||||
#include "ui_main.h"
 | 
					#include "ui_main.h"
 | 
				
			||||||
@ -29,8 +30,9 @@ class WaitTreeWidget;
 | 
				
			|||||||
enum class GameListOpenTarget;
 | 
					enum class GameListOpenTarget;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace FileSys {
 | 
					namespace FileSys {
 | 
				
			||||||
 | 
					class RegisteredCacheUnion;
 | 
				
			||||||
class VfsFilesystem;
 | 
					class VfsFilesystem;
 | 
				
			||||||
}
 | 
					} // namespace FileSys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Tegra {
 | 
					namespace Tegra {
 | 
				
			||||||
class DebugContext;
 | 
					class DebugContext;
 | 
				
			||||||
@ -175,6 +177,8 @@ private slots:
 | 
				
			|||||||
    void OnReinitializeKeys(ReinitializeKeyBehavior behavior);
 | 
					    void OnReinitializeKeys(ReinitializeKeyBehavior behavior);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
 | 
					    boost::optional<u64> SelectRomFSDumpTarget(const FileSys::RegisteredCacheUnion&,
 | 
				
			||||||
 | 
					                                               u64 program_id);
 | 
				
			||||||
    void UpdateStatusBar();
 | 
					    void UpdateStatusBar();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Ui::MainWindow ui;
 | 
					    Ui::MainWindow ui;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user