mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-02 14:50:41 -07:00
37218e7fe0
As noted in #567, a filesystem path that contains non-ascii will break a lot if using a clang toolchain. Luckily, fmtlib has a lossy utf8 convert when you use it to print a path (after including `fmt/std.h`). The vast majority of this diff is just removing `.string()` from paths inside loggings calls. There are some callsites I _didn't_ touch, mainly the options, because it would be an ABI break to change those to be wide strings and I cbf looking into settings upgrades. There are also some spots (avs mountpath remapping, for example) where the path is guaranteed to be ascii, so I didn't modify them. ImGui doesn't appear to easily support wide strings (I mean, surely it does, but I'm not gonna look too far into it) so I mostly just left those alone too, with a few spots modified to re-use fmtlib's lossy utf8. Some of the changes are basically never gonna be hit IRL, like who would put a file with a non-ascii _extension_ along with their modules? But the diff is (I hope) pretty easy to validate as OK. Testing has been somewhat minimal, I fired up the GCC build of spice2x in a dodgy folder name, got mojibake (running via wine in linux so take that as you will), ran the unmodified clang spice and crashed the same way the reporter did. After modification, I get the exact same mojibake so I assume if the terminal enjoys utf8 it'll display OK. Claude (only used for review) thinks the commit is fine but is annoyed that I use `fmt::detail` in the appdata censoring, which is part of the private API; personally I don't care because it's pretty stable.
175 lines
5.3 KiB
C++
175 lines
5.3 KiB
C++
#pragma once
|
|
|
|
#include "overlay/window.h"
|
|
#include <map>
|
|
#include <functional>
|
|
#include <filesystem>
|
|
#include <optional>
|
|
#include "external/rapidjson/document.h"
|
|
|
|
namespace overlay::windows {
|
|
|
|
enum class PatchType {
|
|
Unknown,
|
|
Memory,
|
|
Signature,
|
|
Union,
|
|
Integer,
|
|
};
|
|
|
|
enum class PatchStatus {
|
|
Error,
|
|
Disabled,
|
|
Enabled,
|
|
};
|
|
|
|
enum class PatchUrlStatus {
|
|
Valid,
|
|
Invalid,
|
|
Unapplied,
|
|
ValidButNoData,
|
|
Partial,
|
|
};
|
|
|
|
struct MemoryPatch {
|
|
std::string dll_name = "";
|
|
std::shared_ptr<uint8_t[]> data_disabled = nullptr;
|
|
size_t data_disabled_len = 0;
|
|
std::shared_ptr<uint8_t[]> data_enabled = nullptr;
|
|
size_t data_enabled_len = 0;
|
|
uint64_t data_offset = 0;
|
|
uint8_t *data_offset_ptr = nullptr;
|
|
bool fatal_error = false;
|
|
};
|
|
|
|
struct PatchData;
|
|
struct SignaturePatch {
|
|
std::string dll_name = "";
|
|
std::string signature = "", replacement = "";
|
|
uint64_t offset = 0;
|
|
int64_t usage = 0;
|
|
|
|
MemoryPatch to_memory(PatchData *patch);
|
|
};
|
|
|
|
struct UnionPatch {
|
|
std::string name = "";
|
|
std::string dll_name = "";
|
|
std::shared_ptr<uint8_t[]> data = nullptr;
|
|
size_t data_len = 0;
|
|
uint64_t offset = 0;
|
|
uint8_t* data_offset_ptr = nullptr;
|
|
bool fatal_error = false;
|
|
};
|
|
|
|
struct NumberPatch {
|
|
std::string dll_name = "";
|
|
uint64_t data_offset = 0;
|
|
uint8_t* data_offset_ptr = nullptr;
|
|
int32_t min;
|
|
int32_t max;
|
|
int32_t value;
|
|
size_t size_in_bytes;
|
|
bool fatal_error = false;
|
|
};
|
|
|
|
struct PatchData {
|
|
bool enabled;
|
|
std::string game_code;
|
|
int datecode_min = 0;
|
|
int datecode_max = 0;
|
|
std::string name, description, caution;
|
|
std::string name_in_lower_case = "";
|
|
PatchType type;
|
|
bool preset;
|
|
std::vector<MemoryPatch> patches_memory;
|
|
std::vector<UnionPatch> patches_union;
|
|
NumberPatch patch_number;
|
|
PatchStatus last_status;
|
|
std::string hash;
|
|
bool unverified = false;
|
|
std::string peIdentifier;
|
|
std::string error_reason = "";
|
|
|
|
// for union patch only
|
|
std::string selected_union_name = "";
|
|
};
|
|
|
|
extern std::optional<std::string> PATCH_MANAGER_CFG_PATH_OVERRIDE;
|
|
|
|
std::string get_game_identifier(const std::filesystem::path& dll_path, bool print_info=false);
|
|
|
|
class PatchManager : public Window {
|
|
public:
|
|
|
|
PatchManager(SpiceOverlay *overlay, bool apply_patches = false);
|
|
~PatchManager() override;
|
|
|
|
void build_content() override;
|
|
void reload_local_patches(bool apply_patches = false);
|
|
bool import_remote_patches_to_disk();
|
|
bool load_from_patches_json(bool apply_patches);
|
|
bool import_remote_patches_for_dll(const std::string& url, const std::string& dll_name);
|
|
void hard_apply_patches();
|
|
void load_embedded_patches(bool apply_patches);
|
|
|
|
private:
|
|
|
|
// configuration
|
|
static std::filesystem::path config_path;
|
|
static bool config_dirty;
|
|
static bool setting_auto_apply;
|
|
static std::vector<std::string> setting_auto_apply_list;
|
|
static std::vector<std::string> setting_patches_enabled;
|
|
static std::map<std::string, std::string> setting_union_patches_enabled;
|
|
static std::map<std::string, int64_t> setting_int_patches_enabled;
|
|
static std::string patch_url;
|
|
static std::string patch_name_filter;
|
|
|
|
static std::filesystem::path LOCAL_PATCHES_PATH;
|
|
static std::string ACTIVE_JSON_FILE;
|
|
|
|
// patches
|
|
static std::vector<PatchData> patches;
|
|
static bool local_patches_initialized;
|
|
|
|
void config_load();
|
|
void config_save();
|
|
|
|
void append_patches(
|
|
std::string &patches_json,
|
|
bool apply_patches = false,
|
|
std::function<bool(const PatchData&)> filter = std::function<bool(const PatchData&)>(),
|
|
std::string pe_identifier_for_patch = "");
|
|
|
|
void show_patch_tooltip(const PatchData& patch);
|
|
|
|
bool is_game_id_wildcard_matched(const std::string& id_from_config);
|
|
};
|
|
|
|
PatchStatus is_patch_active(PatchData &patch);
|
|
bool apply_patch(PatchData &patch, bool active);
|
|
|
|
int64_t parse_little_endian_int(uint8_t* bytes, size_t size);
|
|
void int_to_little_endian_bytes(int64_t value, uint8_t* bytes, size_t size);
|
|
|
|
std::vector<uint8_t>* find_in_dll_map(
|
|
const std::string& dll_name, size_t offset, size_t size);
|
|
std::vector<uint8_t>* find_in_dll_map_org(
|
|
const std::string& dll_name, size_t offset, size_t size);
|
|
|
|
bool restore_bytes_from_dll_map_org(
|
|
uint8_t* destination, const std::string& dll_name, size_t offset, size_t size);
|
|
|
|
void create_dll_backup(
|
|
std::vector<std::filesystem::path>& written_list, const std::filesystem::path& dll_path);
|
|
std::string fix_up_dll_name(const std::string& dll_name);
|
|
uint8_t* get_dll_offset_for_patch_apply(
|
|
const std::string& dll_name, const uint64_t data_offset, const size_t size_in_bytes);
|
|
|
|
uint64_t parse_json_data_offset(
|
|
const std::string &patch_name, const rapidjson::Value &value);
|
|
|
|
void print_auto_apply_status(PatchData &patch);
|
|
}
|