From 78b9c64f67aa0c6c52f7da31a59e4d5512a83c8f Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 29 Mar 2017 02:54:05 +0300 Subject: [PATCH] Simple patch engine --- Utilities/bin_patch.cpp | 105 ++++++++++++++++++++++++++++++++++ Utilities/bin_patch.h | 37 ++++++++++++ rpcs3/Emu/System.cpp | 8 +++ rpcs3/emucore.vcxproj | 4 ++ rpcs3/emucore.vcxproj.filters | 6 ++ 5 files changed, 160 insertions(+) create mode 100644 Utilities/bin_patch.cpp create mode 100644 Utilities/bin_patch.h diff --git a/Utilities/bin_patch.cpp b/Utilities/bin_patch.cpp new file mode 100644 index 0000000000..60d0a05c8a --- /dev/null +++ b/Utilities/bin_patch.cpp @@ -0,0 +1,105 @@ +#include "bin_patch.h" +#include "yaml-cpp/yaml.h" +#include "File.h" +#include "Config.h" + +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + format_enum(out, arg, [](patch_type value) + { + switch (value) + { + case patch_type::byte: return "byte"; + case patch_type::le16: return "le16"; + case patch_type::le32: return "le32"; + case patch_type::le64: return "le64"; + case patch_type::be16: return "be16"; + case patch_type::be32: return "be32"; + case patch_type::be64: return "be64"; + } + + return unknown; + }); +} + +void patch_engine::append(const std::string& patch) +{ + if (fs::file f{patch}) + { + auto root = YAML::Load(f.to_string()); + + for (auto pair : root) + { + auto& name = pair.first.Scalar(); + auto& data = m_map[name]; + + for (auto patch : pair.second) + { + u64 type64 = 0; + cfg::try_to_enum_value(&type64, &fmt_class_string::format, patch[0].Scalar()); + + struct patch info; + info.type = static_cast(type64); + info.offset = patch[1].as(); + info.value = patch[2].as(); + data.emplace_back(info); + } + } + } +} + +void patch_engine::apply(const std::string& name, u8* dst) const +{ + const auto found = m_map.find(name); + + if (found == m_map.cend()) + { + return; + } + + // Apply modifications sequentially + for (const auto& p : found->second) + { + auto ptr = dst + p.offset; + + switch (p.type) + { + case patch_type::byte: + { + *ptr = static_cast(p.value); + break; + } + case patch_type::le16: + { + *reinterpret_cast*>(ptr) = static_cast(p.value); + break; + } + case patch_type::le32: + { + *reinterpret_cast*>(ptr) = static_cast(p.value); + break; + } + case patch_type::le64: + { + *reinterpret_cast*>(ptr) = static_cast(p.value); + break; + } + case patch_type::be16: + { + *reinterpret_cast*>(ptr) = static_cast(p.value); + break; + } + case patch_type::be32: + { + *reinterpret_cast*>(ptr) = static_cast(p.value); + break; + } + case patch_type::be64: + { + *reinterpret_cast*>(ptr) = static_cast(p.value); + break; + } + } + } +} diff --git a/Utilities/bin_patch.h b/Utilities/bin_patch.h new file mode 100644 index 0000000000..56704e5d52 --- /dev/null +++ b/Utilities/bin_patch.h @@ -0,0 +1,37 @@ +#pragma once + +#include "BEType.h" +#include +#include +#include + +enum class patch_type +{ + byte, + le16, + le32, + le64, + be16, + be32, + be64, +}; + +class patch_engine +{ + struct patch + { + patch_type type; + u32 offset; + u64 value; + }; + + // Database + std::unordered_map> m_map; + +public: + // Load from file + void append(const std::string& path); + + // Apply patch + void apply(const std::string& name, u8* dst) const; +}; diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 7bbb3e07fa..99390def52 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -2,6 +2,7 @@ #include "Utilities/Config.h" #include "Utilities/AutoPause.h" #include "Utilities/event.h" +#include "Utilities/bin_patch.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" @@ -99,6 +100,9 @@ void Emulator::Init() fs::create_dir(dev_hdd1 + "game/"); fs::create_path(dev_hdd1); fs::create_path(dev_usb); + + // Initialize patch engine + fxm::make_always()->append(fs::get_config_dir() + "/patch.yml"); } void Emulator::SetPath(const std::string& path, const std::string& elf_path) @@ -215,6 +219,10 @@ void Emulator::Load() LOG_NOTICE(LOADER, "Used configuration:\n%s\n", cfg::root.to_string()); + // Load patches from different locations + fxm::check_unlocked()->append(fs::get_config_dir() + "data/" + m_title_id + "/patch.yml"); + fxm::check_unlocked()->append(m_cache_path + "/patch.yml"); + // Mount all devices const std::string emu_dir_ = g_cfg_vfs_emulator_dir; const std::string emu_dir = emu_dir_.empty() ? fs::get_config_dir() : emu_dir_; diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index bbe6a7943e..8d720c1a64 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -73,6 +73,9 @@ NotUsing + + NotUsing + NotUsing @@ -396,6 +399,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 840db6c849..2e4bb036e3 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -908,6 +908,9 @@ Loader + + Utilities + @@ -1738,5 +1741,8 @@ Loader + + Utilities + \ No newline at end of file