Initial support for xex patching
This commit is contained in:
parent
88ddfe86db
commit
5a933156c0
|
@ -551,10 +551,10 @@ void EmulatorWindow::UpdateTitle() {
|
||||||
")";
|
")";
|
||||||
}
|
}
|
||||||
|
|
||||||
auto patching_system = emulator()->patching_system();
|
patcher::PatchingSystem* patching_system = emulator()->patching_system();
|
||||||
if (patching_system) {
|
if (patching_system) {
|
||||||
auto title_patched =
|
auto title_patched =
|
||||||
patching_system->isAnyPatchApplied() ? " [Patches Applied]" : "";
|
patching_system->IsAnyPatchApplied() ? " [Patches Applied]" : "";
|
||||||
title += title_patched;
|
title += title_patched;
|
||||||
}
|
}
|
||||||
window_->set_title(title);
|
window_->set_title(title);
|
||||||
|
|
|
@ -767,7 +767,8 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
patching_system_->applyPatchesForTitle(kernel_state()->memory(), module->title_id());
|
patching_system_->ApplyPatchesForTitle(
|
||||||
|
kernel_state()->memory(), module->title_id(), module->hash());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "xenia/base/exception_handler.h"
|
#include "xenia/base/exception_handler.h"
|
||||||
#include "xenia/kernel/kernel_state.h"
|
#include "xenia/kernel/kernel_state.h"
|
||||||
#include "xenia/memory.h"
|
#include "xenia/memory.h"
|
||||||
|
#include "xenia/patcher/patcher.h"
|
||||||
#include "xenia/vfs/virtual_file_system.h"
|
#include "xenia/vfs/virtual_file_system.h"
|
||||||
#include "xenia/patcher/patcher.h"
|
#include "xenia/patcher/patcher.h"
|
||||||
#include "xenia/xbox.h"
|
#include "xenia/xbox.h"
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include "xenia/base/byte_stream.h"
|
#include "xenia/base/byte_stream.h"
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
|
#include "xenia/base/xxhash.h"
|
||||||
#include "xenia/cpu/elf_module.h"
|
#include "xenia/cpu/elf_module.h"
|
||||||
#include "xenia/cpu/processor.h"
|
#include "xenia/cpu/processor.h"
|
||||||
#include "xenia/cpu/xex_module.h"
|
#include "xenia/cpu/xex_module.h"
|
||||||
|
@ -75,6 +76,12 @@ X_STATUS UserModule::LoadFromFile(const std::string_view path) {
|
||||||
|
|
||||||
// Load the module.
|
// Load the module.
|
||||||
result = LoadFromMemory(mmap->data(), mmap->size());
|
result = LoadFromMemory(mmap->data(), mmap->size());
|
||||||
|
if (XSUCCEEDED(result)) {
|
||||||
|
XXH3_state_t hash_state;
|
||||||
|
XXH3_64bits_reset(&hash_state);
|
||||||
|
XXH3_64bits_update(&hash_state, mmap->data(), mmap->size());
|
||||||
|
hash_ = XXH3_64bits_digest(&hash_state);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
std::vector<uint8_t> buffer(fs_entry->size());
|
std::vector<uint8_t> buffer(fs_entry->size());
|
||||||
|
|
||||||
|
@ -96,6 +103,12 @@ X_STATUS UserModule::LoadFromFile(const std::string_view path) {
|
||||||
// Load the module.
|
// Load the module.
|
||||||
result = LoadFromMemory(buffer.data(), bytes_read);
|
result = LoadFromMemory(buffer.data(), bytes_read);
|
||||||
|
|
||||||
|
// Generate xex hash
|
||||||
|
XXH3_state_t hash_state;
|
||||||
|
XXH3_64bits_reset(&hash_state);
|
||||||
|
XXH3_64bits_update(&hash_state, buffer.data(), bytes_read);
|
||||||
|
hash_ = XXH3_64bits_digest(&hash_state);
|
||||||
|
|
||||||
// Close the file.
|
// Close the file.
|
||||||
file->Destroy();
|
file->Destroy();
|
||||||
}
|
}
|
||||||
|
@ -105,6 +118,8 @@ X_STATUS UserModule::LoadFromFile(const std::string_view path) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XELOGI("Module hash: {:08X} for {}", hash_, name_);
|
||||||
|
|
||||||
if (cvars::xex_apply_patches) {
|
if (cvars::xex_apply_patches) {
|
||||||
// Search for xexp patch file
|
// Search for xexp patch file
|
||||||
auto module_path = fs_entry->path();
|
auto module_path = fs_entry->path();
|
||||||
|
|
|
@ -38,6 +38,7 @@ class UserModule : public XModule {
|
||||||
|
|
||||||
const std::string& path() const override { return path_; }
|
const std::string& path() const override { return path_; }
|
||||||
const std::string& name() const override { return name_; }
|
const std::string& name() const override { return name_; }
|
||||||
|
const uint64_t hash() const { return hash_; }
|
||||||
|
|
||||||
enum ModuleFormat {
|
enum ModuleFormat {
|
||||||
kModuleFormatUndefined = 0,
|
kModuleFormatUndefined = 0,
|
||||||
|
@ -100,6 +101,7 @@ class UserModule : public XModule {
|
||||||
|
|
||||||
std::string name_;
|
std::string name_;
|
||||||
std::string path_;
|
std::string path_;
|
||||||
|
uint64_t hash_;
|
||||||
|
|
||||||
uint32_t guest_xex_header_ = 0;
|
uint32_t guest_xex_header_ = 0;
|
||||||
ModuleFormat module_format_ = kModuleFormatUndefined;
|
ModuleFormat module_format_ = kModuleFormatUndefined;
|
||||||
|
|
|
@ -2,12 +2,10 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Copyright 2016 Ben Vanik. All rights reserved. *
|
* Copyright 2021 Ben Vanik. All rights reserved. *
|
||||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
#include <regex>
|
|
||||||
|
|
||||||
#include "xenia/patcher/patcher.h"
|
#include "xenia/patcher/patcher.h"
|
||||||
|
|
||||||
#include "xenia/base/cvar.h"
|
#include "xenia/base/cvar.h"
|
||||||
|
@ -20,24 +18,25 @@ namespace xe {
|
||||||
namespace patcher {
|
namespace patcher {
|
||||||
|
|
||||||
PatchingSystem::PatchingSystem() {
|
PatchingSystem::PatchingSystem() {
|
||||||
isAnyPatchApplied_ = false;
|
is_any_patch_applied_ = false;
|
||||||
loadPatches();
|
LoadPatches();
|
||||||
}
|
}
|
||||||
|
|
||||||
PatchingSystem::~PatchingSystem() {}
|
PatchingSystem::~PatchingSystem() {}
|
||||||
|
|
||||||
void PatchingSystem::loadPatches() {
|
void PatchingSystem::LoadPatches() {
|
||||||
if (!cvars::apply_patches) {
|
if (!cvars::apply_patches) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path patches_directory =
|
const std::filesystem::path patches_directory =
|
||||||
filesystem::GetExecutableFolder() / "patches";
|
filesystem::GetExecutableFolder() / "patches";
|
||||||
|
|
||||||
auto patch_files = filesystem::ListFiles(patches_directory);
|
const std::vector<xe::filesystem::FileInfo>& patch_files =
|
||||||
std::regex file_name_regex_match = std::regex("^[A-Fa-f0-9]{8}\\.patch$");
|
filesystem::ListFiles(patches_directory);
|
||||||
|
std::regex file_name_regex_match = std::regex("^[A-Fa-f0-9]{8}.*\\.patch$");
|
||||||
|
|
||||||
for (const auto patch_file : patch_files) {
|
for (const xe::filesystem::FileInfo& patch_file : patch_files) {
|
||||||
// Skip files that doesn't have only title_id as name and .patch as
|
// Skip files that doesn't have only title_id as name and .patch as
|
||||||
// extension
|
// extension
|
||||||
if (!std::regex_match(patch_file.name.u8string(), file_name_regex_match)) {
|
if (!std::regex_match(patch_file.name.u8string(), file_name_regex_match)) {
|
||||||
|
@ -46,40 +45,44 @@ void PatchingSystem::loadPatches() {
|
||||||
patch_file.name.u8string());
|
patch_file.name.u8string());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Load every patch from directory
|
|
||||||
auto loaded_file_patches = readPatchFile(patch_file.path / patch_file.name);
|
const PatchFileEntry loaded_title_patches =
|
||||||
loaded_patch_files.push_back(loaded_file_patches);
|
ReadPatchFile(patch_file.path / patch_file.name);
|
||||||
|
if (loaded_title_patches.title_id != -1) {
|
||||||
|
loaded_patch_files.push_back(loaded_title_patches);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
XELOGI("Patching System: Loaded patches for {} titles",
|
XELOGI("Patching System: Loaded patches for {} titles",
|
||||||
loaded_patch_files.size());
|
loaded_patch_files.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void PatchingSystem::applyPatchesForTitle(Memory* memory,
|
void PatchingSystem::ApplyPatchesForTitle(Memory* memory,
|
||||||
const uint32_t title_id) {
|
const uint32_t title_id,
|
||||||
for (const auto patchFile : loaded_patch_files) {
|
const uint64_t hash) {
|
||||||
|
for (const PatchFileEntry& patchFile : loaded_patch_files) {
|
||||||
if (patchFile.title_id != title_id) {
|
if (patchFile.title_id != title_id) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (patchFile.hash != 0 && patchFile.hash != hash) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
auto title_patches = patchFile.patch_info;
|
for (const PatchInfoEntry& patchEntry : patchFile.patch_info) {
|
||||||
|
|
||||||
for (const auto patchEntry : title_patches) {
|
|
||||||
if (!patchEntry.is_enabled) {
|
if (!patchEntry.is_enabled) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
XELOGE("Applying patch for: {}({:08X}) - {}", patchFile.title_name,
|
XELOGE("Applying patch for: {}({:08X}) - {}", patchFile.title_name,
|
||||||
patchFile.title_id, patchEntry.patch_name);
|
patchFile.title_id, patchEntry.patch_name);
|
||||||
applyPatch(memory, &patchEntry);
|
ApplyPatch(memory, &patchEntry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PatchingSystem::applyPatch(Memory* memory, const patchInfoEntry* patch) {
|
void PatchingSystem::ApplyPatch(Memory* memory, const PatchInfoEntry* patch) {
|
||||||
for (const auto patch_data_entry : patch->patch_data) {
|
for (const PatchDataEntry& patch_data_entry : patch->patch_data) {
|
||||||
uint32_t old_address_protect = 0;
|
uint32_t old_address_protect = 0;
|
||||||
auto address = memory->TranslateVirtual(patch_data_entry.memory_address_);
|
auto address = memory->TranslateVirtual(patch_data_entry.memory_address_);
|
||||||
auto heap = memory->LookupHeap(patch_data_entry.memory_address_);
|
auto heap = memory->LookupHeap(patch_data_entry.memory_address_);
|
||||||
|
|
||||||
if (!heap) {
|
if (!heap) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -111,35 +114,37 @@ void PatchingSystem::applyPatch(Memory* memory, const patchInfoEntry* patch) {
|
||||||
heap->Protect(patch_data_entry.memory_address_,
|
heap->Protect(patch_data_entry.memory_address_,
|
||||||
patch_data_entry.alloc_size_, old_address_protect);
|
patch_data_entry.alloc_size_, old_address_protect);
|
||||||
|
|
||||||
if (!isAnyPatchApplied_) {
|
if (!is_any_patch_applied_) {
|
||||||
isAnyPatchApplied_ = true;
|
is_any_patch_applied_ = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
patchFileEntry PatchingSystem::readPatchFile(
|
PatchFileEntry PatchingSystem::ReadPatchFile(
|
||||||
const std::filesystem::path& file_path) {
|
const std::filesystem::path& file_path) {
|
||||||
patchFileEntry patchFile;
|
PatchFileEntry patchFile;
|
||||||
|
|
||||||
std::shared_ptr<cpptoml::table> patch_toml_fields;
|
std::shared_ptr<cpptoml::table> patch_toml_fields;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
patch_toml_fields = cpptoml::parse_file(file_path.u8string());
|
patch_toml_fields = cpptoml::parse_file(file_path.u8string());
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
XELOGE("Cannot load patch file: {}", file_path.u8string());
|
XELOGE("Cannot load patch file: {}", file_path.u8string());
|
||||||
|
patchFile.title_id = -1;
|
||||||
return patchFile;
|
return patchFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto title_name = patch_toml_fields->get_as<std::string>("title_name");
|
auto title_name = patch_toml_fields->get_as<std::string>("title_name");
|
||||||
auto title_id = patch_toml_fields->get_as<std::string>("title_id");
|
auto title_id = patch_toml_fields->get_as<std::string>("title_id");
|
||||||
|
auto title_hash = patch_toml_fields->get_as<std::string>("hash");
|
||||||
|
|
||||||
patchFile.title_id = strtol((*title_id).c_str(), NULL, 16);
|
patchFile.title_id = strtoul((*title_id).c_str(), NULL, 16);
|
||||||
|
patchFile.hash = strtoull((*title_hash).c_str(), NULL, 16);
|
||||||
patchFile.title_name = *title_name;
|
patchFile.title_name = *title_name;
|
||||||
|
|
||||||
auto tarr = patch_toml_fields->get_table_array("patch");
|
auto tarr = patch_toml_fields->get_table_array("patch");
|
||||||
|
|
||||||
for (auto table : *tarr) {
|
for (auto table : *tarr) {
|
||||||
patchInfoEntry patch = patchInfoEntry();
|
PatchInfoEntry patch = PatchInfoEntry();
|
||||||
auto patch_name = *table->get_as<std::string>("name");
|
auto patch_name = *table->get_as<std::string>("name");
|
||||||
auto patch_desc = *table->get_as<std::string>("desc");
|
auto patch_desc = *table->get_as<std::string>("desc");
|
||||||
auto patch_author = *table->get_as<std::string>("author");
|
auto patch_author = *table->get_as<std::string>("author");
|
||||||
|
@ -155,9 +160,9 @@ patchFileEntry PatchingSystem::readPatchFile(
|
||||||
|
|
||||||
// Iterate through all available data sizes
|
// Iterate through all available data sizes
|
||||||
for (const std::string& type : data_types) {
|
for (const std::string& type : data_types) {
|
||||||
auto entries = readPatchData(type, table);
|
auto entries = ReadPatchData(type, table);
|
||||||
|
|
||||||
for (const auto entry : *entries) {
|
for (const PatchDataEntry& entry : *entries) {
|
||||||
patch.patch_data.push_back(entry);
|
patch.patch_data.push_back(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,10 +171,10 @@ patchFileEntry PatchingSystem::readPatchFile(
|
||||||
return patchFile;
|
return patchFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<patchDataEntry>* PatchingSystem::readPatchData(
|
std::vector<PatchDataEntry>* PatchingSystem::ReadPatchData(
|
||||||
const std::string size_type,
|
const std::string size_type,
|
||||||
const std::shared_ptr<cpptoml::table>& patch_table) {
|
const std::shared_ptr<cpptoml::table>& patch_table) {
|
||||||
std::vector<patchDataEntry>* patch_data = new std::vector<patchDataEntry>();
|
std::vector<PatchDataEntry>* patch_data = new std::vector<PatchDataEntry>();
|
||||||
auto patch_data_tarr = patch_table->get_table_array(size_type);
|
auto patch_data_tarr = patch_table->get_table_array(size_type);
|
||||||
|
|
||||||
if (!patch_data_tarr) {
|
if (!patch_data_tarr) {
|
||||||
|
@ -181,29 +186,28 @@ std::vector<patchDataEntry>* PatchingSystem::readPatchData(
|
||||||
// Todo: How to handle different sizes
|
// Todo: How to handle different sizes
|
||||||
auto value = patch_data_table->get_as<std::uint64_t>("value");
|
auto value = patch_data_table->get_as<std::uint64_t>("value");
|
||||||
|
|
||||||
patchDataEntry patchData = {getAllocSize(size_type), *address, *value};
|
PatchDataEntry patchData = {GetAllocSize(size_type), *address, *value};
|
||||||
patch_data->push_back(patchData);
|
patch_data->push_back(patchData);
|
||||||
}
|
}
|
||||||
return patch_data;
|
return patch_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(Gliniak): Somehow resolve this mess. Maybe by template?
|
uint8_t PatchingSystem::GetAllocSize(const std::string provided_size) {
|
||||||
uint8_t PatchingSystem::getAllocSize(const std::string provided_size) {
|
|
||||||
uint8_t alloc_size = sizeof(uint32_t);
|
uint8_t alloc_size = sizeof(uint32_t);
|
||||||
|
|
||||||
if (provided_size == "be64") {
|
if (provided_size == "be64") {
|
||||||
alloc_size = sizeof(uint64_t);
|
alloc_size = sizeof(uint64_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (provided_size == "be32") {
|
else if (provided_size == "be32") {
|
||||||
alloc_size = sizeof(uint32_t);
|
alloc_size = sizeof(uint32_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (provided_size == "be16") {
|
else if (provided_size == "be16") {
|
||||||
alloc_size = sizeof(uint16_t);
|
alloc_size = sizeof(uint16_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (provided_size == "be8") {
|
else if (provided_size == "be8") {
|
||||||
alloc_size = sizeof(uint8_t);
|
alloc_size = sizeof(uint8_t);
|
||||||
}
|
}
|
||||||
return alloc_size;
|
return alloc_size;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
* Copyright 2021 Ben Vanik. All rights reserved. *
|
||||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
@ -11,68 +11,69 @@
|
||||||
#define XENIA_PATCHER_H_
|
#define XENIA_PATCHER_H_
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <regex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "third_party/cpptoml/include/cpptoml.h"
|
#include "third_party/cpptoml/include/cpptoml.h"
|
||||||
#include "third_party/xxhash/xxhash.h"
|
|
||||||
|
|
||||||
#include "xenia/memory.h"
|
#include "xenia/memory.h"
|
||||||
|
|
||||||
struct patchDataEntry {
|
namespace xe {
|
||||||
|
namespace patcher {
|
||||||
|
|
||||||
|
struct PatchDataEntry {
|
||||||
const uint8_t alloc_size_;
|
const uint8_t alloc_size_;
|
||||||
const uint32_t memory_address_;
|
const uint32_t memory_address_;
|
||||||
const uint64_t new_value_;
|
const uint64_t new_value_;
|
||||||
|
|
||||||
patchDataEntry(const uint8_t alloc_size, const uint32_t memory_address,
|
PatchDataEntry(const uint8_t alloc_size, const uint32_t memory_address,
|
||||||
const uint64_t new_value)
|
const uint64_t new_value)
|
||||||
: alloc_size_(alloc_size),
|
: alloc_size_(alloc_size),
|
||||||
memory_address_(memory_address),
|
memory_address_(memory_address),
|
||||||
new_value_(new_value){};
|
new_value_(new_value){};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct patchInfoEntry {
|
struct PatchInfoEntry {
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
//XXH64_state_t hash_state; // Unsupported. For now.
|
|
||||||
std::string patch_name;
|
std::string patch_name;
|
||||||
std::string patch_desc;
|
std::string patch_desc;
|
||||||
std::string patch_author;
|
std::string patch_author;
|
||||||
std::vector<patchDataEntry> patch_data;
|
std::vector<PatchDataEntry> patch_data;
|
||||||
bool is_enabled;
|
bool is_enabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct patchFileEntry {
|
struct PatchFileEntry {
|
||||||
uint32_t title_id;
|
uint32_t title_id;
|
||||||
std::string title_name;
|
std::string title_name;
|
||||||
std::vector<patchInfoEntry> patch_info;
|
uint64_t hash;
|
||||||
|
std::vector<PatchInfoEntry> patch_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace xe {
|
|
||||||
namespace patcher {
|
|
||||||
|
|
||||||
class PatchingSystem {
|
class PatchingSystem {
|
||||||
public:
|
public:
|
||||||
PatchingSystem();
|
PatchingSystem();
|
||||||
~PatchingSystem();
|
~PatchingSystem();
|
||||||
|
|
||||||
void loadPatches();
|
void LoadPatches();
|
||||||
void applyPatch(Memory* memory, const patchInfoEntry* patch);
|
void ApplyPatch(Memory* memory, const PatchInfoEntry* patch);
|
||||||
void applyPatchesForTitle(Memory* memory, const uint32_t title_id);
|
void ApplyPatchesForTitle(Memory* memory, const uint32_t title_id,
|
||||||
|
const uint64_t hash);
|
||||||
|
|
||||||
patchFileEntry readPatchFile(const std::filesystem::path& file_path);
|
PatchFileEntry ReadPatchFile(const std::filesystem::path& file_path);
|
||||||
std::vector<patchDataEntry>* readPatchData(
|
std::vector<PatchDataEntry>* ReadPatchData(
|
||||||
const std::string size_type,
|
const std::string size_type,
|
||||||
const std::shared_ptr<cpptoml::table>& patch_table);
|
const std::shared_ptr<cpptoml::table>& patch_table);
|
||||||
|
|
||||||
std::vector<patchFileEntry> getAllPatches() { return loaded_patch_files; }
|
std::vector<PatchFileEntry>& GetAllPatches() { return loaded_patch_files; }
|
||||||
|
|
||||||
bool isAnyPatchApplied() { return isAnyPatchApplied_; }
|
bool IsAnyPatchApplied() { return is_any_patch_applied_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<patchFileEntry> loaded_patch_files;
|
std::vector<PatchFileEntry> loaded_patch_files;
|
||||||
|
|
||||||
bool isAnyPatchApplied_;
|
bool is_any_patch_applied_;
|
||||||
|
|
||||||
uint8_t getAllocSize(const std::string provided_size);
|
uint8_t GetAllocSize(const std::string provided_size);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace patcher
|
} // namespace patcher
|
||||||
|
|
Loading…
Reference in New Issue