From 8886f2e55ef7a1acc5dab613c42cce8022fae996 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sun, 30 Sep 2018 18:13:38 -0400 Subject: patch_manager: Add support for IPSwitch format patches --- src/core/file_sys/patch_manager.cpp | 78 ++++++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 22 deletions(-) (limited to 'src/core/file_sys/patch_manager.cpp') diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index 539698f6e..f148e7719 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp @@ -73,27 +73,38 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { return exefs; } -static std::vector CollectIPSPatches(const std::vector& patch_dirs, - const std::string& build_id) { - std::vector ips; +static std::vector CollectPatches(const std::vector& patch_dirs, + const std::string& build_id) { + std::vector out; ips.reserve(patch_dirs.size()); for (const auto& subdir : patch_dirs) { auto exefs_dir = subdir->GetSubdirectory("exefs"); if (exefs_dir != nullptr) { for (const auto& file : exefs_dir->GetFiles()) { - if (file->GetExtension() != "ips") - continue; - auto name = file->GetName(); - const auto p1 = name.substr(0, name.find('.')); - const auto this_build_id = p1.substr(0, p1.find_last_not_of('0') + 1); - - if (build_id == this_build_id) - ips.push_back(file); + if (file->GetExtension() == "ips") { + auto name = file->GetName(); + const auto p1 = name.substr(0, name.find('.')); + const auto this_build_id = p1.substr(0, p1.find_last_not_of('0') + 1); + + if (build_id == this_build_id) + out.push_back(file); + } else if (file->GetExtension() == "pchtxt") { + IPSwitchCompiler compiler{file}; + if (!compiler.IsValid()) + continue; + + auto this_build_id = Common::HexArrayToString(compiler.GetBuildID()); + this_build_id = + this_build_id.substr(0, this_build_id.find_last_not_of('0') + 1); + + if (build_id == this_build_id) + out.push_back(file); + } } } } - return ips; + return out; } std::vector PatchManager::PatchNSO(const std::vector& nso) const { @@ -115,15 +126,24 @@ std::vector PatchManager::PatchNSO(const std::vector& nso) const { auto patch_dirs = load_dir->GetSubdirectories(); std::sort(patch_dirs.begin(), patch_dirs.end(), [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); }); - const auto ips = CollectIPSPatches(patch_dirs, build_id); + const auto patches = CollectPatches(patch_dirs, build_id); auto out = nso; - for (const auto& ips_file : ips) { - LOG_INFO(Loader, " - Appling IPS patch from mod \"{}\"", - ips_file->GetContainingDirectory()->GetParentDirectory()->GetName()); - const auto patched = PatchIPS(std::make_shared(out), ips_file); - if (patched != nullptr) - out = patched->ReadAllBytes(); + for (const auto& patch_file : patches) { + if (patch_file->GetExtension() == "ips") { + LOG_INFO(Loader, " - Applying IPS patch from mod \"{}\"", + patch_file->GetContainingDirectory()->GetParentDirectory()->GetName()); + const auto patched = PatchIPS(std::make_shared(out), patch_file); + if (patched != nullptr) + out = patched->ReadAllBytes(); + } else if (patch_file->GetExtension() == "pchtxt") { + LOG_INFO(Loader, " - Applying IPSwitch patch from mod \"{}\"", + patch_file->GetContainingDirectory()->GetParentDirectory()->GetName()); + const IPSwitchCompiler compiler{patch_file}; + const auto patched = compiler.Apply(std::make_shared(out)); + if (patched != nullptr) + out = patched->ReadAllBytes(); + } } if (out.size() < 0x100) @@ -143,7 +163,7 @@ bool PatchManager::HasNSOPatch(const std::array& build_id_) const { std::sort(patch_dirs.begin(), patch_dirs.end(), [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); }); - return !CollectIPSPatches(patch_dirs, build_id).empty(); + return !CollectPatches(patch_dirs, build_id).empty(); } static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) { @@ -253,8 +273,22 @@ std::map> PatchManager::GetPatchVersionNam if (mod_dir != nullptr && mod_dir->GetSize() > 0) { for (const auto& mod : mod_dir->GetSubdirectories()) { std::string types; - if (IsDirValidAndNonEmpty(mod->GetSubdirectory("exefs"))) - AppendCommaIfNotEmpty(types, "IPS"); + if (IsDirValidAndNonEmpty(mod->GetSubdirectory("exefs"))) { + bool ips = false; + bool ipswitch = false; + + for (const auto& file : mod->GetSubdirectory("exefs")->GetFiles()) { + if (file->GetExtension() == "ips") + ips = true; + else if (file->GetExtension() == "pchtxt") + ipswitch = true; + } + + if (ips) + AppendCommaIfNotEmpty(types, "IPS"); + if (ipswitch) + AppendCommaIfNotEmpty(types, "IPSwitch"); + } if (IsDirValidAndNonEmpty(mod->GetSubdirectory("romfs"))) AppendCommaIfNotEmpty(types, "LayeredFS"); -- cgit v1.2.3 From 70bd2bb1d3aec23fc052c9612f9e530c1a2de72d Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Mon, 1 Oct 2018 17:17:08 -0400 Subject: ips_layer: Deduplicate resource usage --- src/core/file_sys/patch_manager.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/core/file_sys/patch_manager.cpp') diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index f148e7719..03df24906 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp @@ -273,11 +273,13 @@ std::map> PatchManager::GetPatchVersionNam if (mod_dir != nullptr && mod_dir->GetSize() > 0) { for (const auto& mod : mod_dir->GetSubdirectories()) { std::string types; - if (IsDirValidAndNonEmpty(mod->GetSubdirectory("exefs"))) { + + const auto exefs_dir = mod->GetSubdirectory("exefs"); + if (IsDirValidAndNonEmpty(exefs_dir)) { bool ips = false; bool ipswitch = false; - for (const auto& file : mod->GetSubdirectory("exefs")->GetFiles()) { + for (const auto& file : exefs_dir->GetFiles()) { if (file->GetExtension() == "ips") ips = true; else if (file->GetExtension() == "pchtxt") -- cgit v1.2.3 From 110d5784702282c594fe57f84f8d6bda21a82d50 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 4 Oct 2018 12:23:18 -0400 Subject: ips_layer: Fix inaccuracies with comments and flags Specifically bugs/crashes that arise when putting them in positions that are legal but not typical, such as midline, between patch data, or between patch records. --- src/core/file_sys/patch_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/file_sys/patch_manager.cpp') diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index 03df24906..ab2e5e43d 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp @@ -76,7 +76,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { static std::vector CollectPatches(const std::vector& patch_dirs, const std::string& build_id) { std::vector out; - ips.reserve(patch_dirs.size()); + out.reserve(patch_dirs.size()); for (const auto& subdir : patch_dirs) { auto exefs_dir = subdir->GetSubdirectory("exefs"); if (exefs_dir != nullptr) { -- cgit v1.2.3