diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..34cc011 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,39 @@ +name: build + +on: + push: + branches: [ main ] + paths: + - ".github/workflows/build.yml" + - "include/**" + - "src/**" + - "xmake.lua" + pull_request: + branches: [ main ] + workflow_dispatch: + +jobs: + xmake: + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + mode: + - debug + - release + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Setup XMake + uses: xmake-io/github-action-setup-xmake@v1 + with: + xmake-version: "latest" + + - name: Configure + run: xmake config -y --mode=${{ matrix.mode }} + + - name: Build + run: xmake build -y -vD diff --git a/include/REL/FHook.h b/include/REL/FHook.h new file mode 100644 index 0000000..7c92906 --- /dev/null +++ b/include/REL/FHook.h @@ -0,0 +1,43 @@ +#pragma once + +#include "REX/BASE.h" + +#include "REL/IHook.h" + +namespace REL +{ + class FHook : + public IHook + { + public: + FHook(const std::uintptr_t a_address); + FHook(const std::uintptr_t a_address, const char* a_name); + FHook(const std::uintptr_t a_address, const EHookType a_type); + FHook(const std::uintptr_t a_address, const EHookType a_type, const EHookStep a_step); + FHook(const std::uintptr_t a_address, const EHookStep a_step); + FHook(const std::uintptr_t a_address, const char* a_name, const EHookStep a_step); + FHook(const std::uintptr_t a_address, const char* a_name, const EHookType a_type); + FHook(const std::uintptr_t a_address, const char* a_name, const EHookType a_type, const EHookStep a_step); + + ~FHook(); + + virtual bool Init() override; + virtual FHookHandle GetHandle() const override; + virtual const char* GetName() const override; + virtual EHookType GetType() const override; + virtual EHookStep GetStep() const override; + virtual std::size_t GetSize() const override; + virtual std::size_t GetSizeTrampoline() const override; + virtual bool GetEnabled() const override; + + protected: + std::uintptr_t m_address{ 0 }; + std::string m_name; + FHookHandle m_handle; + EHookType m_type{ EHookType::None }; + EHookStep m_step{ EHookStep::Load }; + std::size_t m_size{ 8 }; + std::size_t m_sizeTrampoline{ 0 }; + bool m_enabled{ false }; + }; +} diff --git a/include/REL/FHookStore.h b/include/REL/FHookStore.h new file mode 100644 index 0000000..5089515 --- /dev/null +++ b/include/REL/FHookStore.h @@ -0,0 +1,34 @@ +#pragma once + +#include "REL/IHook.h" +#include "REX/BASE.h" +#include "REX/TSingleton.h" + +namespace REL +{ + class FHookStore : + public REX::TSingleton + { + public: + FHookHandle Add(IHook* a_hook); + void Remove(const FHookHandle a_handle); + + void Init(); + + void Enable(); + void Enable(const FHookHandle a_handle); + void Enable(const EHookType a_type); + void Enable(const EHookStep a_step); + + void Disable(); + void Disable(const FHookHandle a_handle); + void Disable(const EHookType a_type); + + std::size_t GetSizeTrampoline(); + + private: + std::map m_hooks; + std::queue m_hookQueue; + std::uint32_t m_handleCount{ 0 }; + }; +} diff --git a/include/REL/HookObject.h b/include/REL/HookObject.h deleted file mode 100644 index 5a22a2a..0000000 --- a/include/REL/HookObject.h +++ /dev/null @@ -1,134 +0,0 @@ -#pragma once - -#include "REX/BASE.h" - -namespace REL -{ - using HOOK_HANDLE = std::uint32_t; - - enum class HOOK_TYPE : std::uint32_t - { - NONE = 0, - CALL5 = 2, - CALL6 = 3, - JMP5 = 4, - JMP6 = 5, - VFT = 6, - }; - - enum class HOOK_STEP : std::uint32_t - { - NONE = 0, - PRELOAD = 1, - LOAD = 2, - }; - - class HookObject - { - public: - HookObject(const std::uintptr_t a_address); - HookObject(const std::uintptr_t a_address, const char* a_name); - HookObject(const std::uintptr_t a_address, const HOOK_TYPE a_type); - HookObject(const std::uintptr_t a_address, const HOOK_TYPE a_type, const HOOK_STEP a_step); - HookObject(const std::uintptr_t a_address, const HOOK_STEP a_step); - HookObject(const std::uintptr_t a_address, const char* a_name, const HOOK_STEP a_step); - HookObject(const std::uintptr_t a_address, const char* a_name, const HOOK_TYPE a_type); - HookObject(const std::uintptr_t a_address, const char* a_name, const HOOK_TYPE a_type, const HOOK_STEP a_step); - - virtual ~HookObject(); - - virtual bool Init(); - virtual HOOK_HANDLE GetHandle() const; - virtual const char* GetName() const; - virtual HOOK_TYPE GetType() const; - virtual HOOK_STEP GetStep() const; - virtual std::size_t GetSize() const; - virtual std::size_t GetSizeTrampoline() const; - virtual bool GetEnabled() const; - virtual bool Enable() = 0; - virtual bool Disable() = 0; - - protected: - std::uintptr_t m_address{ 0 }; - std::string m_name; - HOOK_HANDLE m_handle; - HOOK_TYPE m_type{ HOOK_TYPE::NONE }; - HOOK_STEP m_step{ HOOK_STEP::LOAD }; - std::size_t m_size{ 8 }; - std::size_t m_sizeTrampoline{ 0 }; - bool m_enabled{ false }; - }; -} - -template - requires(std::is_base_of_v) -struct std::formatter -{ - template - constexpr auto parse(ParseContext& a_ctx) - { - return a_ctx.begin(); - } - - template - constexpr auto format(const T& a_hook, FormatContext& a_ctx) const - { - return format_to(a_ctx.out(), "Hook [{}]", a_hook.GetName()); - } -}; - -template <> -struct std::formatter -{ - template - constexpr auto parse(ParseContext& a_ctx) - { - return a_ctx.begin(); - } - - template - constexpr auto format(const REL::HOOK_TYPE& a_type, FormatContext& a_ctx) const - { - switch (a_type) { - case REL::HOOK_TYPE::NONE: - return format_to(a_ctx.out(), "NONE"); - case REL::HOOK_TYPE::CALL5: - return format_to(a_ctx.out(), "CALL5"); - case REL::HOOK_TYPE::CALL6: - return format_to(a_ctx.out(), "CALL6"); - case REL::HOOK_TYPE::JMP5: - return format_to(a_ctx.out(), "JMP5"); - case REL::HOOK_TYPE::JMP6: - return format_to(a_ctx.out(), "JMP6"); - case REL::HOOK_TYPE::VFT: - return format_to(a_ctx.out(), "VFT"); - } - - return format_to(a_ctx.out(), "UNKNOWN"); - } -}; - -template <> -struct std::formatter -{ - template - constexpr auto parse(ParseContext& a_ctx) - { - return a_ctx.begin(); - } - - template - constexpr auto format(const REL::HOOK_STEP& a_step, FormatContext& a_ctx) const - { - switch (a_step) { - case REL::HOOK_STEP::NONE: - return format_to(a_ctx.out(), "NONE"); - case REL::HOOK_STEP::PRELOAD: - return format_to(a_ctx.out(), "PRELOAD"); - case REL::HOOK_STEP::LOAD: - return format_to(a_ctx.out(), "LOAD"); - } - - return format_to(a_ctx.out(), "UNKNOWN"); - } -}; diff --git a/include/REL/HookStore.h b/include/REL/HookStore.h deleted file mode 100644 index cc941a3..0000000 --- a/include/REL/HookStore.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include "REL/HookObject.h" -#include "REX/BASE.h" - -#include "REX/REX/Singleton.h" - -namespace REL -{ - class HookStore : - public REX::Singleton - { - public: - HOOK_HANDLE Add(HookObject* a_hook); - void Remove(const HOOK_HANDLE a_handle); - - void Init(); - - void Enable(); - void Enable(const HOOK_HANDLE a_handle); - void Enable(const HOOK_TYPE a_type); - void Enable(const HOOK_STEP a_step); - - void Disable(); - void Disable(const HOOK_HANDLE a_handle); - void Disable(const HOOK_TYPE a_type); - - std::size_t GetSizeTrampoline(); - - private: - std::map m_hooks; - std::queue m_hookQueue; - std::uint32_t m_handleCount{ 0 }; - }; -} diff --git a/include/REL/IAT.h b/include/REL/IAT.h index 530fdb2..61307d6 100644 --- a/include/REL/IAT.h +++ b/include/REL/IAT.h @@ -2,34 +2,34 @@ #include "REX/BASE.h" -#include "REX/REX/CAST.h" +#include "REX/CAST.h" #include "REX/W32/BASE.h" namespace REL { - [[nodiscard]] std::uintptr_t GetIATAddr(std::string_view a_dll, std::string_view a_function); - [[nodiscard]] std::uintptr_t GetIATAddr(REX::W32::HMODULE a_module, std::string_view a_dll, std::string_view a_function); + [[nodiscard, deprecated("Use 'REX::FModule' instead")]] std::uintptr_t GetIATAddr(std::string_view a_dll, std::string_view a_function); + [[nodiscard, deprecated("Use 'REX::FModule' instead")]] std::uintptr_t GetIATAddr(REX::W32::HMODULE a_module, std::string_view a_dll, std::string_view a_function); - [[nodiscard]] void* GetIATPtr(std::string_view a_dll, std::string_view a_function); + [[nodiscard, deprecated("Use 'REX::FModule' instead")]] void* GetIATPtr(std::string_view a_dll, std::string_view a_function); template - [[nodiscard]] T* GetIATPtr(std::string_view a_dll, std::string_view a_function) + [[nodiscard, deprecated("Use 'REX::FModule' instead")]] T* GetIATPtr(std::string_view a_dll, std::string_view a_function) { return static_cast(GetIATPtr(std::move(a_dll), std::move(a_function))); } - [[nodiscard]] void* GetIATPtr(REX::W32::HMODULE a_module, std::string_view a_dll, std::string_view a_function); + [[nodiscard, deprecated("Use 'REX::FModule' instead")]] void* GetIATPtr(REX::W32::HMODULE a_module, std::string_view a_dll, std::string_view a_function); template - [[nodiscard]] T* GetIATPtr(REX::W32::HMODULE a_module, std::string_view a_dll, std::string_view a_function) + [[nodiscard, deprecated("Use 'REX::FModule' instead")]] T* GetIATPtr(REX::W32::HMODULE a_module, std::string_view a_dll, std::string_view a_function) { return static_cast(GetIATPtr(a_module, std::move(a_dll), std::move(a_function))); } - std::uintptr_t PatchIAT(std::uintptr_t a_newFunc, std::string_view a_dll, std::string_view a_function); + [[deprecated("Use 'REX::FModule' instead")]] std::uintptr_t PatchIAT(std::uintptr_t a_newFunc, std::string_view a_dll, std::string_view a_function); template - std::uintptr_t PatchIAT(F a_newFunc, std::string_view a_dll, std::string_view a_function) + [[deprecated("Use 'REX::FModule' instead")]] std::uintptr_t PatchIAT(F a_newFunc, std::string_view a_dll, std::string_view a_function) { return PatchIAT(REX::UNRESTRICTED_CAST(a_newFunc), a_dll, a_function); } diff --git a/include/REL/ID.h b/include/REL/ID.h index ff53ef5..7b8c882 100644 --- a/include/REL/ID.h +++ b/include/REL/ID.h @@ -1,9 +1,8 @@ #pragma once -#include "REX/BASE.h" +#include "REX/FModule.h" #include "REL/IDDB.h" -#include "REL/Module.h" namespace REL { @@ -24,8 +23,8 @@ namespace REL [[nodiscard]] std::uintptr_t address() const { - const auto mod = Module::GetSingleton(); - return mod->base() + offset(); + const auto mod = REX::FModule::GetExecutingModule(); + return mod.GetBaseAddress() + offset(); } [[nodiscard]] constexpr std::uint64_t id() const noexcept diff --git a/include/REL/IDDB.h b/include/REL/IDDB.h index 703d30a..42d4763 100644 --- a/include/REL/IDDB.h +++ b/include/REL/IDDB.h @@ -2,13 +2,13 @@ #include "REX/BASE.h" -#include "REX/REX/MemoryMap.h" -#include "REX/REX/Singleton.h" +#include "REX/FMemoryMap.h" +#include "REX/TSingleton.h" namespace REL { class IDDB : - public REX::Singleton + public REX::TSingleton { public: enum class Loader : std::uint32_t @@ -63,7 +63,7 @@ namespace REL std::filesystem::path m_path; Loader m_loader{ Loader::None }; Format m_format{ Format::None }; - REX::MemoryMap m_mmap; + REX::FMemoryMap m_mmap; std::span m_v0; std::span m_v5; }; diff --git a/include/REL/IHook.h b/include/REL/IHook.h new file mode 100644 index 0000000..fb73ba1 --- /dev/null +++ b/include/REL/IHook.h @@ -0,0 +1,110 @@ +#pragma once + +namespace REL +{ + using FHookHandle = std::uint32_t; + + enum class EHookType : std::uint32_t + { + None = 0, + CALL5 = 2, + CALL6 = 3, + JMP5 = 4, + JMP6 = 5, + VFT = 6, + }; + + enum class EHookStep : std::uint32_t + { + None = 0, + PreLoad = 1, + Load = 2, + }; + + struct IHook + { + virtual bool Init() = 0; + virtual FHookHandle GetHandle() const = 0; + virtual const char* GetName() const = 0; + virtual EHookType GetType() const = 0; + virtual EHookStep GetStep() const = 0; + virtual std::size_t GetSize() const = 0; + virtual std::size_t GetSizeTrampoline() const = 0; + virtual bool GetEnabled() const = 0; + virtual bool Enable() = 0; + virtual bool Disable() = 0; + }; +} + +template + requires(std::is_base_of_v) +struct std::formatter +{ + template + constexpr auto parse(ParseContext& a_ctx) + { + return a_ctx.begin(); + } + + template + constexpr auto format(const T& a_hook, FormatContext& a_ctx) const + { + return format_to(a_ctx.out(), "Hook [{}]", a_hook.GetName()); + } +}; + +template <> +struct std::formatter +{ + template + constexpr auto parse(ParseContext& a_ctx) + { + return a_ctx.begin(); + } + + template + constexpr auto format(const REL::EHookType& a_type, FormatContext& a_ctx) const + { + switch (a_type) { + case REL::EHookType::None: + return format_to(a_ctx.out(), "None"); + case REL::EHookType::CALL5: + return format_to(a_ctx.out(), "CALL5"); + case REL::EHookType::CALL6: + return format_to(a_ctx.out(), "CALL6"); + case REL::EHookType::JMP5: + return format_to(a_ctx.out(), "JMP5"); + case REL::EHookType::JMP6: + return format_to(a_ctx.out(), "JMP6"); + case REL::EHookType::VFT: + return format_to(a_ctx.out(), "VFT"); + } + + return format_to(a_ctx.out(), ""); + } +}; + +template <> +struct std::formatter +{ + template + constexpr auto parse(ParseContext& a_ctx) + { + return a_ctx.begin(); + } + + template + constexpr auto format(const REL::EHookStep& a_step, FormatContext& a_ctx) const + { + switch (a_step) { + case REL::EHookStep::None: + return format_to(a_ctx.out(), "None"); + case REL::EHookStep::PreLoad: + return format_to(a_ctx.out(), "PreLoad"); + case REL::EHookStep::Load: + return format_to(a_ctx.out(), "Load"); + } + + return format_to(a_ctx.out(), ""); + } +}; diff --git a/include/REL/Module.h b/include/REL/Module.h deleted file mode 100644 index fd6ef18..0000000 --- a/include/REL/Module.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include "REX/BASE.h" - -#include "REL/Segment.h" -#include "REL/Version.h" - -#include "REX/REX/Singleton.h" - -namespace REL -{ - class Module : - public REX::Singleton - { - public: - Module(); - - [[nodiscard]] constexpr std::uintptr_t base() const noexcept { return _base; } - [[nodiscard]] std::wstring_view filename() const noexcept { return _filename; } - [[nodiscard]] constexpr Segment segment(Segment::Name a_segment) const noexcept { return _segments[a_segment]; } - - [[nodiscard]] constexpr Version version() const noexcept - { - return _version; - } - - constexpr void version(Version a_version) noexcept - { - _version = a_version; - } - - [[nodiscard]] void* pointer() const noexcept { return reinterpret_cast(base()); } - - template - [[nodiscard]] T* pointer() const noexcept - { - return static_cast(pointer()); - } - - private: - void load_segments(); - - static constexpr std::array SEGMENTS{ - ".text"sv, - ".interpr"sv, - ".idata"sv, - ".rdata"sv, - ".data"sv, - ".pdata"sv, - ".tls"sv - }; - - static inline std::uintptr_t _natvis{ 0 }; - - std::wstring _filename; - std::array _segments; - Version _version; - std::uintptr_t _base{ 0 }; - }; -} diff --git a/include/REL/Offset.h b/include/REL/Offset.h index e114026..10eb7b2 100644 --- a/include/REL/Offset.h +++ b/include/REL/Offset.h @@ -1,8 +1,6 @@ #pragma once -#include "REX/BASE.h" - -#include "REL/Module.h" +#include "REX/FModule.h" namespace REL { @@ -12,27 +10,27 @@ namespace REL constexpr Offset() noexcept = default; explicit constexpr Offset(std::size_t a_offset) noexcept : - _offset(a_offset) + m_offset(a_offset) {} constexpr Offset& operator=(std::size_t a_offset) noexcept { - _offset = a_offset; + m_offset = a_offset; return *this; } [[nodiscard]] std::uintptr_t address() const { - const auto mod = Module::GetSingleton(); - return mod->base() + offset(); + const auto mod = REX::FModule::GetExecutingModule(); + return mod.GetBaseAddress() + offset(); } [[nodiscard]] constexpr std::size_t offset() const noexcept { - return _offset; + return m_offset; } private: - std::size_t _offset{ 0 }; + std::size_t m_offset{ 0 }; }; } diff --git a/include/REL/Offset2ID.h b/include/REL/Offset2ID.h index 3bacc5b..4773eb6 100644 --- a/include/REL/Offset2ID.h +++ b/include/REL/Offset2ID.h @@ -1,13 +1,13 @@ #pragma once -#include "REX/BASE.h" - #include "REL/IDDB.h" +#include "REX/BASE.h" + namespace REL { class Offset2ID : - public REX::Singleton + public REX::TSingleton { public: using value_type = IDDB::MAPPING; diff --git a/include/REL/Pattern.h b/include/REL/Pattern.h index da056f8..aa54880 100644 --- a/include/REL/Pattern.h +++ b/include/REL/Pattern.h @@ -2,10 +2,9 @@ #include "REX/BASE.h" -#include "REL/Module.h" - -#include "REX/REX/LOG.h" -#include "REX/REX/StaticString.h" +#include "REX/FModule.h" +#include "REX/LOG.h" +#include "REX/TStaticString.h" namespace REL { @@ -144,15 +143,15 @@ namespace REL const noexcept { if (!this->match(a_address)) { - const auto mod = Module::GetSingleton(); - const auto version = mod->version(); - REX::IMPL::FAIL( + const auto mod = REX::FModule::GetExecutingModule(); + const auto modVersion = mod.GetFileVersion(); + REX::FAIL( a_loc, "A pattern has failed to match.\n" "This means the plugin is incompatible with either the " "current version of the game ({}), or another " "installed mod.", - version.string()); + modVersion.string()); } } }; diff --git a/include/REL/REL.h b/include/REL/REL.h index 5f8fddc..46ba3ae 100644 --- a/include/REL/REL.h +++ b/include/REL/REL.h @@ -1,18 +1,17 @@ #pragma once #include "REL/ASM.h" -#include "REL/Hook.h" -#include "REL/HookObject.h" -#include "REL/HookStore.h" +#include "REL/FHook.h" +#include "REL/FHookStore.h" #include "REL/IAT.h" #include "REL/ID.h" #include "REL/IDDB.h" -#include "REL/Module.h" +#include "REL/IHook.h" #include "REL/Offset.h" #include "REL/Offset2ID.h" #include "REL/Pattern.h" #include "REL/Relocation.h" -#include "REL/Segment.h" +#include "REL/THook.h" #include "REL/Trampoline.h" #include "REL/Utility.h" #include "REL/Version.h" diff --git a/include/REL/Relocation.h b/include/REL/Relocation.h index 2a73e53..afc6882 100644 --- a/include/REL/Relocation.h +++ b/include/REL/Relocation.h @@ -4,12 +4,12 @@ #include "REL/ASM.h" #include "REL/ID.h" -#include "REL/Module.h" #include "REL/Offset.h" #include "REL/Trampoline.h" #include "REL/Utility.h" -#include "REX/REX/CAST.h" +#include "REX/CAST.h" +#include "REX/FModule.h" #define REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER_IMPL(a_nopropQual, a_propQual, ...) \ template < \ @@ -374,7 +374,11 @@ namespace REL private: // clang-format off - [[nodiscard]] static std::uintptr_t base() { return Module::GetSingleton()->base(); } + [[nodiscard]] static std::uintptr_t base() + { + const auto mod = REX::FModule::GetExecutingModule(); + return mod.GetBaseAddress(); + } // clang-format on std::uintptr_t _impl{ 0 }; diff --git a/include/REL/Segment.h b/include/REL/Segment.h deleted file mode 100644 index 1be50e1..0000000 --- a/include/REL/Segment.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include "REX/BASE.h" - -namespace REL -{ - class Segment - { - public: - enum Name : std::size_t - { - text, - interpr, - idata, - rdata, - data, - pdata, - tls, - total - }; - - constexpr Segment() noexcept = default; - - constexpr Segment(std::uintptr_t a_proxyBase, std::uintptr_t a_address, std::uintptr_t a_size) noexcept : - _proxyBase(a_proxyBase), - _address(a_address), - _size(a_size) - {} - - [[nodiscard]] constexpr std::uintptr_t address() const noexcept { return _address; } - [[nodiscard]] constexpr std::size_t offset() const noexcept { return address() - _proxyBase; } - [[nodiscard]] constexpr std::size_t size() const noexcept { return _size; } - - [[nodiscard]] void* pointer() const noexcept { return reinterpret_cast(address()); } - - template - [[nodiscard]] T* pointer() const noexcept - { - return static_cast(pointer()); - } - - private: - std::uintptr_t _proxyBase{ 0 }; - std::uintptr_t _address{ 0 }; - std::size_t _size{ 0 }; - }; -} diff --git a/include/REL/Hook.h b/include/REL/THook.h similarity index 55% rename from include/REL/Hook.h rename to include/REL/THook.h index 065b154..661b446 100644 --- a/include/REL/Hook.h +++ b/include/REL/THook.h @@ -3,75 +3,75 @@ #include "REX/BASE.h" #include "REL/ASM.h" -#include "REL/HookObject.h" +#include "REL/FHook.h" #include "REL/ID.h" #include "REL/Offset.h" #include "REL/Trampoline.h" #include "REL/Utility.h" -#include "REX/REX/LOG.h" +#include "REX/LOG.h" namespace REL { template - class Hook; + class THook; template - class Hook : - public HookObject + class THook : + public FHook { public: - explicit Hook(const ID a_id, const std::ptrdiff_t a_diff, R (*a_function)(T...)) : - HookObject(a_id.address() + a_diff) + explicit THook(const ID a_id, const std::ptrdiff_t a_diff, R (*a_function)(T...)) : + FHook(a_id.address() + a_diff) { m_function = reinterpret_cast(a_function); Detect(); } - explicit Hook(const Offset a_offset, const std::ptrdiff_t a_diff, R (*a_function)(T...)) : - HookObject(a_offset.address() + a_diff) + explicit THook(const Offset a_offset, const std::ptrdiff_t a_diff, R (*a_function)(T...)) : + FHook(a_offset.address() + a_diff) { m_function = reinterpret_cast(a_function); Detect(); } - explicit Hook(const HOOK_STEP a_step, const ID a_id, const std::ptrdiff_t a_diff, R (*a_function)(T...)) : - HookObject(a_id.address() + a_diff, a_step) + explicit THook(const EHookStep a_step, const ID a_id, const std::ptrdiff_t a_diff, R (*a_function)(T...)) : + FHook(a_id.address() + a_diff, a_step) { m_function = reinterpret_cast(a_function); Detect(); } - explicit Hook(const HOOK_STEP a_step, const Offset a_offset, const std::ptrdiff_t a_diff, R (*a_function)(T...)) : - HookObject(a_offset.address() + a_diff, a_step) + explicit THook(const EHookStep a_step, const Offset a_offset, const std::ptrdiff_t a_diff, R (*a_function)(T...)) : + FHook(a_offset.address() + a_diff, a_step) { m_function = reinterpret_cast(a_function); Detect(); } - explicit Hook(const char* a_name, const ID a_id, const std::ptrdiff_t a_diff, R (*a_function)(T...)) : - HookObject(a_id.address() + a_diff, a_name) + explicit THook(const char* a_name, const ID a_id, const std::ptrdiff_t a_diff, R (*a_function)(T...)) : + FHook(a_id.address() + a_diff, a_name) { m_function = reinterpret_cast(a_function); Detect(); } - explicit Hook(const char* a_name, const Offset a_offset, const std::ptrdiff_t a_diff, R (*a_function)(T...)) : - HookObject(a_offset.address() + a_diff, a_name) + explicit THook(const char* a_name, const Offset a_offset, const std::ptrdiff_t a_diff, R (*a_function)(T...)) : + FHook(a_offset.address() + a_diff, a_name) { m_function = reinterpret_cast(a_function); Detect(); } - explicit Hook(const char* a_name, const HOOK_STEP a_step, const ID a_id, const std::ptrdiff_t a_diff, R (*a_function)(T...)) : - HookObject(a_id.address() + a_diff, a_name, a_step) + explicit THook(const char* a_name, const EHookStep a_step, const ID a_id, const std::ptrdiff_t a_diff, R (*a_function)(T...)) : + FHook(a_id.address() + a_diff, a_name, a_step) { m_function = reinterpret_cast(a_function); Detect(); } - explicit Hook(const char* a_name, const HOOK_STEP a_step, const Offset a_offset, const std::ptrdiff_t a_diff, R (*a_function)(T...)) : - HookObject(a_offset.address() + a_diff, a_name, a_step) + explicit THook(const char* a_name, const EHookStep a_step, const Offset a_offset, const std::ptrdiff_t a_diff, R (*a_function)(T...)) : + FHook(a_offset.address() + a_diff, a_name, a_step) { m_function = reinterpret_cast(a_function); Detect(); @@ -79,7 +79,7 @@ namespace REL virtual bool Init() override { - if (m_type == HOOK_TYPE::NONE) { + if (m_type == EHookType::None) { REX::ERROR("{}: could not determine hook type", *this); return false; } @@ -87,19 +87,19 @@ namespace REL REL::Write(std::span{ m_bytesOld }, m_address); switch (m_type) { - case HOOK_TYPE::CALL5: { + case EHookType::CALL5: { ASM::CALL5 assembly(m_address, GetTrampoline().allocate_branch5(m_function)); REL::WriteData(std::span{ m_bytes }, assembly); } break; - case HOOK_TYPE::CALL6: { + case EHookType::CALL6: { ASM::CALL6 assembly(m_address, GetTrampoline().allocate_branch6(m_function)); REL::WriteData(std::span{ m_bytes }, assembly); } break; - case HOOK_TYPE::JMP5: { + case EHookType::JMP5: { ASM::JMP5 assembly(m_address, GetTrampoline().allocate_branch5(m_function)); REL::WriteData(std::span{ m_bytes }, assembly); } break; - case HOOK_TYPE::JMP6: { + case EHookType::JMP6: { ASM::JMP6 assembly(m_address, GetTrampoline().allocate_branch6(m_function)); REL::WriteData(std::span{ m_bytes }, assembly); } break; @@ -112,7 +112,7 @@ namespace REL virtual bool Enable() override { - if (m_type == HOOK_TYPE::NONE) { + if (m_type == EHookType::None) { REX::ERROR("{}: hook type is none", *this); return false; } @@ -128,7 +128,7 @@ namespace REL virtual bool Disable() override { - if (m_type == HOOK_TYPE::NONE) { + if (m_type == EHookType::None) { REX::ERROR("{}: hook type is none", *this); return false; } @@ -154,13 +154,13 @@ namespace REL const auto op = reinterpret_cast(m_address); switch (*op) { case 0xE8: { - m_type = HOOK_TYPE::CALL5; + m_type = EHookType::CALL5; m_size = sizeof(ASM::CALL5); m_sizeTrampoline = sizeof(ASM::JMP14); m_functionOld = ASM::CALL5::TARGET(m_address); } break; case 0xE9: { - m_type = HOOK_TYPE::JMP5; + m_type = EHookType::JMP5; m_size = sizeof(ASM::JMP5); m_sizeTrampoline = sizeof(ASM::JMP14); m_functionOld = ASM::JMP5::TARGET(m_address); @@ -168,13 +168,13 @@ namespace REL case 0xFF: { switch (*(op + 1)) { case 0x15: { - m_type = HOOK_TYPE::CALL6; + m_type = EHookType::CALL6; m_size = sizeof(ASM::CALL6); m_sizeTrampoline = sizeof(std::uintptr_t); m_functionOld = ASM::CALL6::TARGET(m_address); } break; case 0x25: { - m_type = HOOK_TYPE::JMP6; + m_type = EHookType::JMP6; m_size = sizeof(ASM::JMP6); m_sizeTrampoline = sizeof(std::uintptr_t); m_functionOld = ASM::JMP6::TARGET(m_address); @@ -196,91 +196,94 @@ namespace REL }; template - Hook(const ID, const std::uint64_t, R (*)(T...)) -> Hook; + THook(const ID, const std::uint64_t, R (*)(T...)) -> THook; template - Hook(const Offset, const std::uint64_t, R (*)(T...)) -> Hook; + THook(const Offset, const std::uint64_t, R (*)(T...)) -> THook; template - Hook(const HOOK_STEP, const ID, const std::uint64_t, R (*)(T...)) -> Hook; + THook(const EHookStep, const ID, const std::uint64_t, R (*)(T...)) -> THook; template - Hook(const HOOK_STEP, const Offset, const std::uint64_t, R (*)(T...)) -> Hook; + THook(const EHookStep, const Offset, const std::uint64_t, R (*)(T...)) -> THook; template - Hook(const char*, const ID, const std::uint64_t, R (*)(T...)) -> Hook; + THook(const char*, const ID, const std::uint64_t, R (*)(T...)) -> THook; template - Hook(const char*, const Offset, const std::uint64_t, R (*)(T...)) -> Hook; + THook(const char*, const Offset, const std::uint64_t, R (*)(T...)) -> THook; template - Hook(const char*, const HOOK_STEP, const ID, const std::uint64_t, R (*)(T...)) -> Hook; + THook(const char*, const EHookStep, const ID, const std::uint64_t, R (*)(T...)) -> THook; template - Hook(const char*, const HOOK_STEP, const Offset, const std::uint64_t, R (*)(T...)) -> Hook; + THook(const char*, const EHookStep, const Offset, const std::uint64_t, R (*)(T...)) -> THook; + + template + using Hook [[deprecated("Renamed to 'REL::THook'")]] = THook; } namespace REL { template - class HookVFT; + class THookVFT; template - class HookVFT : - public HookObject + class THookVFT : + public FHook { public: - explicit HookVFT(const ID a_id, const std::size_t a_idx, R (*a_function)(T...)) : - HookObject(a_id.address() + (sizeof(void*) * a_idx), HOOK_TYPE::VFT) + explicit THookVFT(const ID a_id, const std::size_t a_idx, R (*a_function)(T...)) : + FHook(a_id.address() + (sizeof(void*) * a_idx), EHookType::VFT) { m_function = reinterpret_cast(a_function); m_functionOld = *reinterpret_cast(m_address); } - explicit HookVFT(const Offset a_offset, const std::size_t a_idx, R (*a_function)(T...)) : - HookObject(a_offset.address() + (sizeof(void*) * a_idx), HOOK_TYPE::VFT) + explicit THookVFT(const Offset a_offset, const std::size_t a_idx, R (*a_function)(T...)) : + FHook(a_offset.address() + (sizeof(void*) * a_idx), EHookType::VFT) { m_function = reinterpret_cast(a_function); m_functionOld = *reinterpret_cast(m_address); } - explicit HookVFT(const HOOK_STEP a_step, const ID a_id, const std::size_t a_idx, R (*a_function)(T...)) : - HookObject(a_id.address() + (sizeof(void*) * a_idx), HOOK_TYPE::VFT, a_step) + explicit THookVFT(const EHookStep a_step, const ID a_id, const std::size_t a_idx, R (*a_function)(T...)) : + FHook(a_id.address() + (sizeof(void*) * a_idx), EHookType::VFT, a_step) { m_function = reinterpret_cast(a_function); m_functionOld = *reinterpret_cast(m_address); } - explicit HookVFT(const HOOK_STEP a_step, const Offset a_offset, const std::size_t a_idx, R (*a_function)(T...)) : - HookObject(a_offset.address() + (sizeof(void*) * a_idx), HOOK_TYPE::VFT, a_step) + explicit THookVFT(const EHookStep a_step, const Offset a_offset, const std::size_t a_idx, R (*a_function)(T...)) : + FHook(a_offset.address() + (sizeof(void*) * a_idx), EHookType::VFT, a_step) { m_function = reinterpret_cast(a_function); m_functionOld = *reinterpret_cast(m_address); } - explicit HookVFT(const char* a_name, const ID a_id, const std::size_t a_idx, R (*a_function)(T...)) : - HookObject(a_id.address() + (sizeof(void*) * a_idx), a_name, HOOK_TYPE::VFT) + explicit THookVFT(const char* a_name, const ID a_id, const std::size_t a_idx, R (*a_function)(T...)) : + FHook(a_id.address() + (sizeof(void*) * a_idx), a_name, EHookType::VFT) { m_function = reinterpret_cast(a_function); m_functionOld = *reinterpret_cast(m_address); } - explicit HookVFT(const char* a_name, const Offset a_offset, const std::size_t a_idx, R (*a_function)(T...)) : - HookObject(a_offset.address() + (sizeof(void*) * a_idx), a_name, HOOK_TYPE::VFT) + explicit THookVFT(const char* a_name, const Offset a_offset, const std::size_t a_idx, R (*a_function)(T...)) : + FHook(a_offset.address() + (sizeof(void*) * a_idx), a_name, EHookType::VFT) { m_function = reinterpret_cast(a_function); m_functionOld = *reinterpret_cast(m_address); } - explicit HookVFT(const char* a_name, const HOOK_STEP a_step, const ID a_id, const std::size_t a_idx, R (*a_function)(T...)) : - HookObject(a_id.address() + (sizeof(void*) * a_idx), a_name, HOOK_TYPE::VFT, a_step) + explicit THookVFT(const char* a_name, const EHookStep a_step, const ID a_id, const std::size_t a_idx, R (*a_function)(T...)) : + FHook(a_id.address() + (sizeof(void*) * a_idx), a_name, EHookType::VFT, a_step) { m_function = reinterpret_cast(a_function); m_functionOld = *reinterpret_cast(m_address); } - explicit HookVFT(const char* a_name, const HOOK_STEP a_step, const Offset a_offset, const std::size_t a_idx, R (*a_function)(T...)) : - HookObject(a_offset.address() + (sizeof(void*) * a_idx), a_name, HOOK_TYPE::VFT, a_step) + explicit THookVFT(const char* a_name, const EHookStep a_step, const Offset a_offset, const std::size_t a_idx, R (*a_function)(T...)) : + FHook(a_offset.address() + (sizeof(void*) * a_idx), a_name, EHookType::VFT, a_step) { m_function = reinterpret_cast(a_function); m_functionOld = *reinterpret_cast(m_address); @@ -330,26 +333,29 @@ namespace REL }; template - HookVFT(const ID, const std::size_t, R (*)(T...)) -> HookVFT; + THookVFT(const ID, const std::size_t, R (*)(T...)) -> THookVFT; template - HookVFT(const Offset, const std::size_t, R (*)(T...)) -> HookVFT; + THookVFT(const Offset, const std::size_t, R (*)(T...)) -> THookVFT; template - HookVFT(const HOOK_STEP, const ID, const std::size_t, R (*)(T...)) -> HookVFT; + THookVFT(const EHookStep, const ID, const std::size_t, R (*)(T...)) -> THookVFT; template - HookVFT(const HOOK_STEP, const Offset, const std::size_t, R (*)(T...)) -> HookVFT; + THookVFT(const EHookStep, const Offset, const std::size_t, R (*)(T...)) -> THookVFT; template - HookVFT(const char*, const ID, const std::size_t, R (*)(T...)) -> HookVFT; + THookVFT(const char*, const ID, const std::size_t, R (*)(T...)) -> THookVFT; template - HookVFT(const char*, const Offset, const std::size_t, R (*)(T...)) -> HookVFT; + THookVFT(const char*, const Offset, const std::size_t, R (*)(T...)) -> THookVFT; template - HookVFT(const char*, const HOOK_STEP, const ID, const std::size_t, R (*)(T...)) -> HookVFT; + THookVFT(const char*, const EHookStep, const ID, const std::size_t, R (*)(T...)) -> THookVFT; template - HookVFT(const char*, const HOOK_STEP, const Offset, const std::size_t, R (*)(T...)) -> HookVFT; + THookVFT(const char*, const EHookStep, const Offset, const std::size_t, R (*)(T...)) -> THookVFT; + + template + using HookVFT [[deprecated("Renamed to 'REL::THookVFT'")]] = THookVFT; } diff --git a/include/REL/Trampoline.h b/include/REL/Trampoline.h index 087c1d2..2bc457f 100644 --- a/include/REL/Trampoline.h +++ b/include/REL/Trampoline.h @@ -1,7 +1,7 @@ #pragma once #include "REX/BASE.h" -#include "REX/REX/CAST.h" +#include "REX/CAST.h" #ifdef COMMONLIB_OPTION_XBYAK namespace Xbyak diff --git a/include/REX/CAST.h b/include/REX/CAST.h new file mode 100644 index 0000000..e72c96a --- /dev/null +++ b/include/REX/CAST.h @@ -0,0 +1,72 @@ +#pragma once + +#include "REX/BASE.h" + +namespace REX +{ + template + [[nodiscard]] auto ADJUST_POINTER(U* a_ptr, std::ptrdiff_t a_adjust) noexcept + { + auto addr = a_ptr ? reinterpret_cast(a_ptr) + a_adjust : 0; + if constexpr (std::is_const_v && std::is_volatile_v) { + return reinterpret_cast*>(addr); + } else if constexpr (std::is_const_v) { + return reinterpret_cast*>(addr); + } else if constexpr (std::is_volatile_v) { + return reinterpret_cast*>(addr); + } else { + return reinterpret_cast(addr); + } + } + + template + void EMPLACE_VTABLE(T* a_ptr) + { + reinterpret_cast(a_ptr)[0] = T::VTABLE[0].address(); + } + + template + void MEM_WRITE_ZERO(volatile T* a_ptr, std::size_t a_size = sizeof(T)) + { + std::fill_n(reinterpret_cast(a_ptr), a_size, '\0'); + } + + template + [[nodiscard]] T1 UNRESTRICTED_CAST(T2 a_from) + { + if constexpr (std::is_same_v< + std::remove_cv_t, + std::remove_cv_t>) { + return T1{ a_from }; + + // From != To + } else if constexpr (std::is_reference_v) { + return unrestricted_cast(std::addressof(a_from)); + + // From: NOT reference + } else if constexpr (std::is_reference_v) { + return *unrestricted_cast< + std::add_pointer_t< + std::remove_reference_t>>(a_from); + + // To: NOT reference + } else if constexpr (std::is_pointer_v && + std::is_pointer_v) { + return static_cast( + const_cast( + static_cast(a_from))); + } else if constexpr ((std::is_pointer_v && std::is_integral_v) || + (std::is_integral_v && std::is_pointer_v)) { + return reinterpret_cast(a_from); + } else { + union + { + std::remove_cv_t> from; + std::remove_cv_t> to; + }; + + from = std::forward(a_from); + return to; + } + } +} diff --git a/include/REX/CONVERT.h b/include/REX/CONVERT.h new file mode 100644 index 0000000..7cdc414 --- /dev/null +++ b/include/REX/CONVERT.h @@ -0,0 +1,80 @@ +#pragma once + +#include "REX/BASE.h" +#include "REX/W32/KERNEL32.h" + +namespace REX +{ + template + U BITS_TO_VALUE(T... a_args) + requires(std::same_as, bool> && ...) + { + constexpr auto ARGC = sizeof...(T); + + std::bitset bits; + std::size_t i = 0; + ((bits[i++] = a_args), ...); + + if constexpr (ARGC <= std::numeric_limits::digits) { + return static_cast(bits.to_ulong()); + } else if constexpr (ARGC <= std::numeric_limits::digits) { + return static_cast(bits.to_ullong()); + } else { + static_assert(false && sizeof...(T)); + } + } + + inline bool UTF8_TO_UTF16(const std::string_view a_in, std::wstring& a_out) noexcept + { + const auto cvt = [&](wchar_t* a_dst, std::size_t a_length) { + return REX::W32::MultiByteToWideChar( + REX::W32::CP_UTF8, + 0, + a_in.data(), + static_cast(a_in.length()), + a_dst, + static_cast(a_length)); + }; + + const auto len = cvt(nullptr, 0); + if (len == 0) { + return false; + } + + std::wstring out(len, '\0'); + if (cvt(out.data(), out.length()) == 0) { + return false; + } + + a_out = out; + return true; + } + + inline bool UTF16_TO_UTF8(const std::wstring_view a_in, std::string& a_out) noexcept + { + const auto cvt = [&](char* a_dst, std::size_t a_length) { + return REX::W32::WideCharToMultiByte( + REX::W32::CP_UTF8, + 0, + a_in.data(), + static_cast(a_in.length()), + a_dst, + static_cast(a_length), + nullptr, + nullptr); + }; + + const auto len = cvt(nullptr, 0); + if (len == 0) { + return false; + } + + std::string out(len, '\0'); + if (cvt(out.data(), out.length()) == 0) { + return false; + } + + a_out = out; + return true; + } +} diff --git a/include/REX/FIniSettingStore.h b/include/REX/FIniSettingStore.h new file mode 100644 index 0000000..be99f46 --- /dev/null +++ b/include/REX/FIniSettingStore.h @@ -0,0 +1,23 @@ +#pragma once + +#ifdef COMMONLIB_OPTION_INI + +# include "REX/TSettingStore.h" + +namespace REX +{ + class FIniSettingStore : + public TSettingStore + { + public: + virtual void Load() override; + virtual void Save() override; + }; +} + +namespace REX::INI +{ + using SettingStore [[deprecated("Renamed to 'REX::FIniSettingStore'")]] = FIniSettingStore; +} + +#endif diff --git a/include/REX/FJsonSettingStore.h b/include/REX/FJsonSettingStore.h new file mode 100644 index 0000000..8599bca --- /dev/null +++ b/include/REX/FJsonSettingStore.h @@ -0,0 +1,23 @@ +#pragma once + +#ifdef COMMONLIB_OPTION_JSON + +# include "REX/TSettingStore.h" + +namespace REX +{ + class FJsonSettingStore : + public TSettingStore + { + public: + virtual void Load() override; + virtual void Save() override; + }; +} + +namespace REX::JSON +{ + using SettingStore [[deprecated("Renamed to 'REX::FJsonSettingStore")]] = FJsonSettingStore; +} + +#endif diff --git a/include/REX/FMemoryMap.h b/include/REX/FMemoryMap.h new file mode 100644 index 0000000..eacad7a --- /dev/null +++ b/include/REX/FMemoryMap.h @@ -0,0 +1,134 @@ +#pragma once + +#include "REX/W32/KERNEL32.h" + +namespace REX +{ + class FMemoryMap + { + static constexpr auto DYNAMIC_SIZE{ static_cast(-1) }; + + public: + FMemoryMap() = default; + ~FMemoryMap() { close(); } + + public: + void close() + { + if (m_mapView) { + REX::W32::UnmapViewOfFile(m_mapView); + m_mapView = nullptr; + } + + if (m_map) { + REX::W32::CloseHandle(m_map); + m_map = nullptr; + } + + if (m_file != REX::W32::INVALID_HANDLE_VALUE) { + REX::W32::CloseHandle(m_file); + m_file = nullptr; + } + + m_size = 0; + m_owner = false; + } + + std::byte* data() const noexcept + { + return static_cast(m_mapView); + } + + std::size_t size() const noexcept + { + return m_size; + } + + bool is_open() const + { + return m_mapView; + } + + bool is_owner() const + { + return m_owner; + } + + bool is_file() const + { + return m_file != REX::W32::INVALID_HANDLE_VALUE; + } + + bool create(bool a_write, const std::string_view a_name, std::size_t a_size) + { + close(); + + if (create_impl(a_write, a_name, a_size)) + return true; + + close(); + return false; + } + + bool create(bool a_write, std::filesystem::path a_path, const std::string_view a_name, std::size_t a_size = DYNAMIC_SIZE) + { + close(); + + const auto access = a_write ? REX::W32::GENERIC_READ | REX::W32::GENERIC_WRITE : REX::W32::GENERIC_READ; + const auto share = a_write ? REX::W32::FILE_SHARE_READ | REX::W32::FILE_SHARE_WRITE : REX::W32::FILE_SHARE_READ; + m_file = REX::W32::CreateFileW(a_path.c_str(), access, share, nullptr, REX::W32::OPEN_EXISTING, REX::W32::FILE_ATTRIBUTE_READONLY, nullptr); + if (m_file == REX::W32::INVALID_HANDLE_VALUE) + return false; + + if (create_impl(a_write, a_name, a_size)) + return true; + + close(); + return false; + } + + private: + bool create_impl(bool a_write, const std::string_view a_name, std::size_t a_size) + { + REX::W32::LARGE_INTEGER size; + if (a_size == DYNAMIC_SIZE) { + if (m_file == REX::W32::INVALID_HANDLE_VALUE) + return false; + + if (REX::W32::GetFileSizeEx(m_file, &size) == 0) + return false; + + } else { + size.value = a_size; + } + + const auto access = a_write ? REX::W32::FILE_MAP_READ | REX::W32::FILE_MAP_WRITE : REX::W32::FILE_MAP_READ; + m_map = REX::W32::OpenFileMappingA(access, false, a_name.data()); + if (!m_map) { + const auto protect = a_write ? REX::W32::PAGE_READWRITE : REX::W32::PAGE_READONLY; + m_map = REX::W32::CreateFileMappingA(m_file, nullptr, protect, size.hi, size.lo, a_name.data()); + if (!m_map) + return false; + + m_owner = true; + } + + m_mapView = REX::W32::MapViewOfFile(m_map, access, 0, 0, size.value); + if (!m_mapView) + return false; + + m_size = static_cast(size.value); + + return true; + } + + private: + void* m_file{ REX::W32::INVALID_HANDLE_VALUE }; + void* m_map{ nullptr }; + void* m_mapView{ nullptr }; + std::size_t m_size{ 0 }; + bool m_owner{ false }; + }; + + using MemoryMap [[deprecated("Renamed to 'REX::FMemoryMap'")]] = FMemoryMap; +} diff --git a/include/REX/FModule.h b/include/REX/FModule.h new file mode 100644 index 0000000..f4fe9c2 --- /dev/null +++ b/include/REX/FModule.h @@ -0,0 +1,59 @@ +#pragma once + +#include "REX/BASE.h" + +#include "REL/Version.h" +#include "REX/FModuleSection.h" +#include "REX/W32/BASE.h" + +namespace REX +{ + class FModule + { + public: + constexpr FModule() = default; + + explicit FModule(W32::HMODULE a_module) : + m_base(reinterpret_cast(a_module)) + {} + + static FModule GetCurrentModule(); + static FModule GetExecutingModule(); + static FModule GetLoadedModule(std::string_view a_name); + + [[nodiscard]] std::string GetFileName() const noexcept; + + [[nodiscard]] REL::Version GetFileVersion() const noexcept; + + [[nodiscard]] void* GetExportFunctionPointer(std::string_view a_function) const; + + [[nodiscard]] std::uintptr_t GetExportFunctionAddress(std::string_view a_function) const + { + return reinterpret_cast(GetExportFunctionPointer(a_function)); + } + + [[nodiscard]] void* GetImportFunctionPointer(std::string_view a_function, std::string_view a_library) const; + + [[nodiscard]] std::uintptr_t GetImportFunctionAddress(std::string_view a_function, std::string_view a_library) const + { + return reinterpret_cast(GetImportFunctionPointer(a_function, a_library)); + } + + void* SetImportFunctionPointer(std::string_view a_function, std::string_view a_library, void* a_pointer) const; + + std::uintptr_t SetImportFunctionAddress(std::string_view a_function, std::string_view a_library, std::uintptr_t a_address) const + { + return reinterpret_cast(SetImportFunctionPointer(a_function, a_library, reinterpret_cast(a_address))); + } + + [[nodiscard]] FModuleSection GetSection(std::string_view a_section) const; + + [[nodiscard]] constexpr std::uintptr_t GetBaseAddress() const noexcept + { + return m_base; + } + + private: + std::uintptr_t m_base{ 0 }; + }; +} diff --git a/include/REX/FModuleSection.h b/include/REX/FModuleSection.h new file mode 100644 index 0000000..04b3bee --- /dev/null +++ b/include/REX/FModuleSection.h @@ -0,0 +1,44 @@ +#pragma once + +#include "REX/BASE.h" + +namespace REX +{ + class FModuleSection + { + public: + constexpr FModuleSection() noexcept = default; + + constexpr FModuleSection(std::uintptr_t a_base, std::uintptr_t a_address, std::uintptr_t a_size) noexcept : + m_base(a_base), + m_address(a_address), + m_size(a_size) + {} + + [[nodiscard]] constexpr std::uintptr_t GetAddress() const noexcept + { + return m_address; + } + + [[nodiscard]] constexpr std::ptrdiff_t GetOffset() const noexcept + { + return GetAddress() - m_base; + } + + [[nodiscard]] constexpr std::size_t GetSize() const noexcept + { + return m_size; + } + + template + [[nodiscard]] T* GetPointer() const noexcept + { + return reinterpret_cast(GetAddress()); + } + + private: + std::uintptr_t m_base{ 0 }; + std::uintptr_t m_address{ 0 }; + std::size_t m_size{ 0 }; + }; +} diff --git a/include/REX/FTomlSettingStore.h b/include/REX/FTomlSettingStore.h new file mode 100644 index 0000000..30baf7d --- /dev/null +++ b/include/REX/FTomlSettingStore.h @@ -0,0 +1,23 @@ +#pragma once + +#ifdef COMMONLIB_OPTION_TOML + +# include "REX/TSettingStore.h" + +namespace REX +{ + class FTomlSettingStore : + public TSettingStore + { + public: + virtual void Load() override; + virtual void Save() override; + }; +} + +namespace REX::TOML +{ + using SettingStore [[deprecated("Renamed to 'REX::FTomlSettingStore")]] = FTomlSettingStore; +} + +#endif diff --git a/include/REX/HASH.h b/include/REX/HASH.h new file mode 100644 index 0000000..61479da --- /dev/null +++ b/include/REX/HASH.h @@ -0,0 +1,49 @@ +#pragma once + +#include "REX/BASE.h" +#include "REX/TScopeExit.h" +#include "REX/W32/BCRYPT.h" + +namespace REX +{ + inline std::optional SHA512(std::span a_data) + { + REX::W32::BCRYPT_ALG_HANDLE algorithm; + if (!REX::W32::NT_SUCCESS(REX::W32::BCryptOpenAlgorithmProvider(&algorithm, REX::W32::BCRYPT_SHA512_ALGORITHM))) + return std::nullopt; + + const TScopeExit cleanup_algo([&]() { + [[maybe_unused]] const auto success = REX::W32::NT_SUCCESS(REX::W32::BCryptCloseAlgorithmProvider(algorithm)); + assert(success); + }); + + REX::W32::BCRYPT_HASH_HANDLE hash; + if (!REX::W32::NT_SUCCESS(REX::W32::BCryptCreateHash(algorithm, &hash))) + return std::nullopt; + + const TScopeExit cleanup_hash([&]() { + [[maybe_unused]] const auto success = REX::W32::NT_SUCCESS(REX::W32::BCryptDestroyHash(hash)); + assert(success); + }); + + if (!REX::W32::NT_SUCCESS(REX::W32::BCryptHashData(hash, reinterpret_cast(const_cast(a_data.data())), static_cast(a_data.size())))) + return std::nullopt; + + std::uint32_t length{ 0 }; + std::uint32_t output{ 0 }; + if (!REX::W32::NT_SUCCESS(REX::W32::BCryptGetProperty(hash, REX::W32::BCRYPT_HASH_LENGTH, reinterpret_cast(&length), sizeof(length), &output))) + return std::nullopt; + + std::vector buffer(static_cast(length)); + if (!REX::W32::NT_SUCCESS(REX::W32::BCryptFinishHash(hash, buffer.data(), static_cast(buffer.size())))) + return std::nullopt; + + std::string result; + result.reserve(buffer.size() * 2); + for (const auto byte : buffer) { + result += std::format("{:02X}", byte); + } + + return { std::move(result) }; + } +} diff --git a/include/REX/ISetting.h b/include/REX/ISetting.h new file mode 100644 index 0000000..548ad40 --- /dev/null +++ b/include/REX/ISetting.h @@ -0,0 +1,10 @@ +#pragma once + +namespace REX +{ + struct ISetting + { + virtual void Load(void* a_data, bool a_isBase) = 0; + virtual void Save(void* a_data) = 0; + }; +} diff --git a/include/REX/ISettingStore.h b/include/REX/ISettingStore.h new file mode 100644 index 0000000..7100602 --- /dev/null +++ b/include/REX/ISettingStore.h @@ -0,0 +1,14 @@ +#pragma once + +namespace REX +{ + struct ISetting; + + struct ISettingStore + { + virtual void Init(const char* a_file, const char* a_fileCustom) = 0; + virtual void Load() = 0; + virtual void Save() = 0; + virtual void Register(ISetting* a_setting) = 0; + }; +} diff --git a/include/REX/LOG.h b/include/REX/LOG.h new file mode 100644 index 0000000..0e4a636 --- /dev/null +++ b/include/REX/LOG.h @@ -0,0 +1,352 @@ +#pragma once + +#include "REX/BASE.h" + +namespace REX +{ + enum class ELogLevel + { + Trace = 0, + Debug = 1, + Info = 2, + Warning = 3, + Error = 4, + Critical = 5, + }; +} + +namespace REX::Impl +{ + void Log(const std::source_location a_loc, const ELogLevel a_level, const std::string_view a_fmt); + + void Log(const std::source_location a_loc, const ELogLevel a_level, const std::wstring_view a_fmt); + + template + void Log(const std::source_location a_loc, const ELogLevel a_level, const std::format_string a_fmt, T&&... a_args) + { + Log(a_loc, a_level, std::vformat(a_fmt.get(), std::make_format_args(a_args...))); + } + + template + void Log(const std::source_location a_loc, const ELogLevel a_level, const std::wformat_string a_fmt, T&&... a_args) + { + Log(a_loc, a_level, std::vformat(a_fmt.get(), std::make_wformat_args(a_args...))); + } +} + +namespace REX +{ + template + struct TRACE + { + TRACE() = delete; + + explicit TRACE(const std::format_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Trace, a_fmt, std::forward(a_args)...); + } + + explicit TRACE(const std::wformat_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Trace, a_fmt, std::forward(a_args)...); + } + }; + + template <> + struct TRACE + { + TRACE() = delete; + + explicit TRACE(const std::string_view a_fmt, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Trace, a_fmt); + } + + explicit TRACE(const std::wstring_view a_fmt, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Trace, a_fmt); + } + }; + + template + struct DEBUG + { + DEBUG() = delete; + + explicit DEBUG(const std::format_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Debug, a_fmt, std::forward(a_args)...); + } + + explicit DEBUG(const std::wformat_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Debug, a_fmt, std::forward(a_args)...); + } + }; + + template <> + struct DEBUG + { + DEBUG() = delete; + + explicit DEBUG(const std::string_view a_fmt, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Debug, a_fmt); + } + + explicit DEBUG(const std::wstring_view a_fmt, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Debug, a_fmt); + } + }; + + template + struct INFO + { + INFO() = delete; + + explicit INFO(const std::format_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Info, a_fmt, std::forward(a_args)...); + } + + explicit INFO(const std::wformat_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Info, a_fmt, std::forward(a_args)...); + } + }; + + template <> + struct INFO + { + INFO() = delete; + + explicit INFO(const std::string_view a_fmt, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Info, a_fmt); + } + + explicit INFO(const std::wstring_view a_fmt, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Info, a_fmt); + } + }; + + template + struct WARN + { + WARN() = delete; + + explicit WARN(const std::format_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Warning, a_fmt, std::forward(a_args)...); + } + + explicit WARN(const std::wformat_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Warning, a_fmt, std::forward(a_args)...); + } + }; + + template <> + struct WARN + { + WARN() = delete; + + explicit WARN(const std::string_view a_fmt, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Warning, a_fmt); + } + + explicit WARN(const std::wstring_view a_fmt, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Warning, a_fmt); + } + }; + + template + struct ERROR + { + ERROR() = delete; + + explicit ERROR(const std::format_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Error, a_fmt, std::forward(a_args)...); + } + + explicit ERROR(const std::wformat_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Error, a_fmt, std::forward(a_args)...); + } + }; + + template <> + struct ERROR + { + ERROR() = delete; + + explicit ERROR(const std::string_view a_fmt, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Error, a_fmt); + } + + explicit ERROR(const std::wstring_view a_fmt, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Error, a_fmt); + } + }; + + template + struct CRITICAL + { + CRITICAL() = delete; + + explicit CRITICAL(const std::format_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Critical, a_fmt, std::forward(a_args)...); + } + + explicit CRITICAL(const std::wformat_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Critical, a_fmt, std::forward(a_args)...); + } + }; + + template <> + struct CRITICAL + { + CRITICAL() = delete; + + explicit CRITICAL(const std::string_view a_fmt, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Critical, a_fmt); + } + + explicit CRITICAL(const std::wstring_view a_fmt, const std::source_location a_loc = std::source_location::current()) + { + Impl::Log(a_loc, ELogLevel::Critical, a_fmt); + } + }; + + template + TRACE(const std::format_string, T&&...) -> TRACE; + template + TRACE(const std::wformat_string, T&&...) -> TRACE; + TRACE(const std::string_view) -> TRACE; + TRACE(const std::wstring_view) -> TRACE; + + template + DEBUG(const std::format_string, T&&...) -> DEBUG; + template + DEBUG(const std::wformat_string, T&&...) -> DEBUG; + DEBUG(const std::string_view) -> DEBUG; + DEBUG(const std::wstring_view) -> DEBUG; + + template + INFO(const std::format_string, T&&...) -> INFO; + template + INFO(const std::wformat_string, T&&...) -> INFO; + INFO(const std::string_view) -> INFO; + INFO(const std::wstring_view) -> INFO; + + template + WARN(const std::format_string, T&&...) -> WARN; + template + WARN(const std::wformat_string, T&&...) -> WARN; + WARN(const std::string_view) -> WARN; + WARN(const std::wstring_view) -> WARN; + + template + ERROR(const std::format_string, T&&...) -> ERROR; + template + ERROR(const std::wformat_string, T&&...) -> ERROR; + ERROR(const std::string_view) -> ERROR; + ERROR(const std::wstring_view) -> ERROR; + + template + CRITICAL(const std::format_string, T&&...) -> CRITICAL; + template + CRITICAL(const std::wformat_string, T&&...) -> CRITICAL; + CRITICAL(const std::string_view) -> CRITICAL; + CRITICAL(const std::wstring_view) -> CRITICAL; +} + +namespace REX +{ + namespace Impl + { + void Fail(const std::source_location a_loc, const std::string_view a_fmt); + void Fail(const std::source_location a_loc, const std::wstring_view a_fmt); + + template + void Fail(const std::source_location a_loc, const std::format_string a_fmt, T&&... a_args) + { + Fail(a_loc, std::vformat(a_fmt.get(), std::make_format_args(a_args...))); + } + + template + void Fail(const std::source_location a_loc, const std::wformat_string a_fmt, T&&... a_args) + { + Fail(a_loc, std::vformat(a_fmt.get(), std::make_wformat_args(a_args...))); + } + } + + template + struct FAIL + { + FAIL() = delete; + + explicit FAIL(const std::format_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) + { + Impl::Fail(a_loc, a_fmt, std::forward(a_args)...); + } + + explicit FAIL(const std::wformat_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) + { + Impl::Fail(a_loc, a_fmt, std::forward(a_args)...); + } + + explicit FAIL(const std::source_location a_loc, const std::format_string a_fmt, T&&... a_args) + { + Impl::Fail(a_loc, a_fmt, std::forward(a_args)...); + } + + explicit FAIL(const std::source_location a_loc, const std::wformat_string a_fmt, T&&... a_args) + { + Impl::Fail(a_loc, a_fmt, std::forward(a_args)...); + } + }; + + template <> + struct FAIL + { + FAIL() = delete; + + explicit FAIL(const std::string_view a_fmt, const std::source_location a_loc = std::source_location::current()) + { + Impl::Fail(a_loc, a_fmt); + } + + explicit FAIL(const std::wstring_view a_fmt, const std::source_location a_loc = std::source_location::current()) + { + Impl::Fail(a_loc, a_fmt); + } + + explicit FAIL(const std::source_location a_loc, const std::string_view a_fmt) + { + Impl::Fail(a_loc, a_fmt); + } + + explicit FAIL(const std::source_location a_loc, const std::wstring_view a_fmt) + { + Impl::Fail(a_loc, a_fmt); + } + }; + + template + FAIL(const std::format_string, T&&...) -> FAIL; + template + FAIL(const std::wformat_string, T&&...) -> FAIL; + FAIL(const std::string_view) -> FAIL; + FAIL(const std::wstring_view) -> FAIL; +} diff --git a/include/REX/REX.h b/include/REX/REX.h index e033b80..192bb5f 100644 --- a/include/REX/REX.h +++ b/include/REX/REX.h @@ -1,17 +1,25 @@ #pragma once -#include "REX/REX/AtomicRef.h" -#include "REX/REX/CAST.h" -#include "REX/REX/CONVERT.h" -#include "REX/REX/Enum.h" -#include "REX/REX/EnumSet.h" -#include "REX/REX/HASH.h" -#include "REX/REX/INI.h" -#include "REX/REX/JSON.h" -#include "REX/REX/LOG.h" -#include "REX/REX/MemoryMap.h" -#include "REX/REX/ScopeExit.h" -#include "REX/REX/Setting.h" -#include "REX/REX/Singleton.h" -#include "REX/REX/StaticString.h" -#include "REX/REX/TOML.h" +#include "REX/CAST.h" +#include "REX/CONVERT.h" +#include "REX/FIniSettingStore.h" +#include "REX/FJsonSettingStore.h" +#include "REX/FMemoryMap.h" +#include "REX/FModule.h" +#include "REX/FModuleSection.h" +#include "REX/FTomlSettingStore.h" +#include "REX/HASH.h" +#include "REX/ISetting.h" +#include "REX/ISettingStore.h" +#include "REX/LOG.h" +#include "REX/TAtomicRef.h" +#include "REX/TEnum.h" +#include "REX/TEnumSet.h" +#include "REX/TIniSetting.h" +#include "REX/TJsonSetting.h" +#include "REX/TScopeExit.h" +#include "REX/TSetting.h" +#include "REX/TSettingStore.h" +#include "REX/TSingleton.h" +#include "REX/TStaticString.h" +#include "REX/TTomlSetting.h" diff --git a/include/REX/REX/AtomicRef.h b/include/REX/REX/AtomicRef.h index afa00c5..0c776a6 100644 --- a/include/REX/REX/AtomicRef.h +++ b/include/REX/REX/AtomicRef.h @@ -1,45 +1,5 @@ #pragma once -#include "REX/BASE.h" +#pragma message("The header 'REX/REX/AtomicRef.h' is deprecated, please include 'REX/TAtomicRef.h'") -namespace REX -{ - template - class TAtomicRef : - public std::atomic_ref - { - private: - using super = std::atomic_ref; - - public: - using value_type = typename super::value_type; - - explicit TAtomicRef(volatile T& a_obj) noexcept(std::is_nothrow_constructible_v) : - super(const_cast(a_obj)) - {} - - using super::super; - using super::operator=; - }; - - template - TAtomicRef(volatile T&) -> TAtomicRef; - - template class TAtomicRef; - template class TAtomicRef; - template class TAtomicRef; - template class TAtomicRef; - template class TAtomicRef; - template class TAtomicRef; - template class TAtomicRef; - template class TAtomicRef; - - static_assert(TAtomicRef::is_always_lock_free); - static_assert(TAtomicRef::is_always_lock_free); - static_assert(TAtomicRef::is_always_lock_free); - static_assert(TAtomicRef::is_always_lock_free); - static_assert(TAtomicRef::is_always_lock_free); - static_assert(TAtomicRef::is_always_lock_free); - static_assert(TAtomicRef::is_always_lock_free); - static_assert(TAtomicRef::is_always_lock_free); -} +#include "REX/TAtomicRef.h" diff --git a/include/REX/REX/CAST.h b/include/REX/REX/CAST.h index 7faa598..4644830 100644 --- a/include/REX/REX/CAST.h +++ b/include/REX/REX/CAST.h @@ -1,72 +1,5 @@ #pragma once -#include "REX/BASE.h" +#pragma message("The header 'REX/REX/CAST.h' is deprecated, please include 'REX/CAST.h'") -namespace REX -{ - template - [[nodiscard]] auto ADJUST_POINTER(U* a_ptr, std::ptrdiff_t a_adjust) noexcept - { - auto addr = a_ptr ? reinterpret_cast(a_ptr) + a_adjust : 0; - if constexpr (std::is_const_v && std::is_volatile_v) { - return reinterpret_cast*>(addr); - } else if constexpr (std::is_const_v) { - return reinterpret_cast*>(addr); - } else if constexpr (std::is_volatile_v) { - return reinterpret_cast*>(addr); - } else { - return reinterpret_cast(addr); - } - } - - template - void EMPLACE_VTABLE(T* a_ptr) - { - reinterpret_cast(a_ptr)[0] = T::VTABLE[0].address(); - } - - template - void MEM_WRITE_ZERO(volatile T* a_ptr, std::size_t a_size = sizeof(T)) - { - std::fill_n(reinterpret_cast(a_ptr), a_size, '\0'); - } - - template - [[nodiscard]] T1 UNRESTRICTED_CAST(T2 a_from) - { - if constexpr (std::is_same_v< - std::remove_cv_t, - std::remove_cv_t>) { - return T1{ a_from }; - - // From != To - } else if constexpr (std::is_reference_v) { - return unrestricted_cast(std::addressof(a_from)); - - // From: NOT reference - } else if constexpr (std::is_reference_v) { - return *unrestricted_cast< - std::add_pointer_t< - std::remove_reference_t>>(a_from); - - // To: NOT reference - } else if constexpr (std::is_pointer_v && - std::is_pointer_v) { - return static_cast( - const_cast( - static_cast(a_from))); - } else if constexpr ((std::is_pointer_v && std::is_integral_v) || - (std::is_integral_v && std::is_pointer_v)) { - return reinterpret_cast(a_from); - } else { - union - { - std::remove_cv_t> from; - std::remove_cv_t> to; - }; - - from = std::forward(a_from); - return to; - } - } -} \ No newline at end of file +#include "REX/CAST.h" diff --git a/include/REX/REX/CONVERT.h b/include/REX/REX/CONVERT.h index 7cdc414..8aa9684 100644 --- a/include/REX/REX/CONVERT.h +++ b/include/REX/REX/CONVERT.h @@ -1,80 +1,5 @@ #pragma once -#include "REX/BASE.h" -#include "REX/W32/KERNEL32.h" +#pragma message("The header 'REX/REX/CONVERT.h' is deprecated, please include 'REX/CONVERT.h'") -namespace REX -{ - template - U BITS_TO_VALUE(T... a_args) - requires(std::same_as, bool> && ...) - { - constexpr auto ARGC = sizeof...(T); - - std::bitset bits; - std::size_t i = 0; - ((bits[i++] = a_args), ...); - - if constexpr (ARGC <= std::numeric_limits::digits) { - return static_cast(bits.to_ulong()); - } else if constexpr (ARGC <= std::numeric_limits::digits) { - return static_cast(bits.to_ullong()); - } else { - static_assert(false && sizeof...(T)); - } - } - - inline bool UTF8_TO_UTF16(const std::string_view a_in, std::wstring& a_out) noexcept - { - const auto cvt = [&](wchar_t* a_dst, std::size_t a_length) { - return REX::W32::MultiByteToWideChar( - REX::W32::CP_UTF8, - 0, - a_in.data(), - static_cast(a_in.length()), - a_dst, - static_cast(a_length)); - }; - - const auto len = cvt(nullptr, 0); - if (len == 0) { - return false; - } - - std::wstring out(len, '\0'); - if (cvt(out.data(), out.length()) == 0) { - return false; - } - - a_out = out; - return true; - } - - inline bool UTF16_TO_UTF8(const std::wstring_view a_in, std::string& a_out) noexcept - { - const auto cvt = [&](char* a_dst, std::size_t a_length) { - return REX::W32::WideCharToMultiByte( - REX::W32::CP_UTF8, - 0, - a_in.data(), - static_cast(a_in.length()), - a_dst, - static_cast(a_length), - nullptr, - nullptr); - }; - - const auto len = cvt(nullptr, 0); - if (len == 0) { - return false; - } - - std::string out(len, '\0'); - if (cvt(out.data(), out.length()) == 0) { - return false; - } - - a_out = out; - return true; - } -} +#include "REX/CONVERT.h" diff --git a/include/REX/REX/Enum.h b/include/REX/REX/Enum.h index ca49214..32d1cdf 100644 --- a/include/REX/REX/Enum.h +++ b/include/REX/REX/Enum.h @@ -1,70 +1,5 @@ #pragma once -#include "REX/BASE.h" +#pragma message("The header 'REX/REX/Enum.h' is deprecated, please include 'REX/TEnum.h'") -namespace REX -{ - template < - class E, - class U = std::underlying_type_t> - class Enum - { - public: - using enum_type = E; - using underlying_type = U; - - static_assert(std::is_enum_v, "Enum must be an enum"); - static_assert(std::is_integral_v, "Enum<..., U> must be an integral"); - - constexpr Enum() noexcept = default; - constexpr Enum(const Enum&) noexcept = default; - constexpr Enum(Enum&&) noexcept = default; - - template // NOLINTNEXTLINE(google-explicit-constructor) - constexpr Enum(Enum a_rhs) noexcept : - _impl(static_cast(a_rhs.get())) - {} - - constexpr Enum(E a_value) noexcept : - _impl(static_cast(a_value)) - {} - - ~Enum() noexcept = default; - - constexpr Enum& operator=(const Enum&) noexcept = default; - constexpr Enum& operator=(Enum&&) noexcept = default; - - template - constexpr Enum& operator=(Enum a_rhs) noexcept - { - _impl = static_cast(a_rhs.get()); - } - - constexpr Enum& operator=(E a_value) noexcept - { - _impl = static_cast(a_value); - return *this; - } - - public: - [[nodiscard]] explicit constexpr operator bool() const noexcept { return _impl != static_cast(0); } - - [[nodiscard]] constexpr E operator*() const noexcept { return get(); } - [[nodiscard]] constexpr E get() const noexcept { return static_cast(_impl); } - [[nodiscard]] constexpr U underlying() const noexcept { return _impl; } - - public: - friend constexpr bool operator==(Enum a_lhs, Enum a_rhs) noexcept { return a_lhs.underlying() == a_rhs.underlying(); } - friend constexpr bool operator==(Enum a_lhs, E a_rhs) noexcept { return a_lhs.underlying() == static_cast(a_rhs); } - friend constexpr bool operator==(E a_lhs, Enum a_rhs) noexcept { return static_cast(a_lhs) == a_rhs.underlying(); } - - private: - U _impl{ 0 }; - }; - - template - Enum(Args...) -> Enum< - std::common_type_t, - std::underlying_type_t< - std::common_type_t>>; -} +#include "REX/TEnum.h" diff --git a/include/REX/REX/EnumSet.h b/include/REX/REX/EnumSet.h index 83d5dde..f07c621 100644 --- a/include/REX/REX/EnumSet.h +++ b/include/REX/REX/EnumSet.h @@ -1,195 +1,5 @@ #pragma once -#include "REX/BASE.h" +#pragma message("The header 'REX/REX/EnumSet.h' is deprecated, please include 'REX/TEnumSet.h'") -namespace REX -{ - template < - class E, - class U = std::underlying_type_t> - class EnumSet - { - public: - using enum_type = E; - using underlying_type = U; - - static_assert(std::is_enum_v, "EnumSet must be an enum"); - static_assert(std::is_integral_v, "EnumSet<..., U> must be an integral"); - - constexpr EnumSet() noexcept = default; - constexpr EnumSet(const EnumSet&) noexcept = default; - constexpr EnumSet(EnumSet&&) noexcept = default; - - template // NOLINTNEXTLINE(google-explicit-constructor) - constexpr EnumSet(EnumSet a_rhs) noexcept : - _impl(static_cast(a_rhs.get())) - {} - - template - constexpr EnumSet(Args... a_values) noexcept - requires(std::same_as && ...) - : - _impl((static_cast(a_values) | ...)) - {} - - ~EnumSet() noexcept = default; - - constexpr EnumSet& operator=(const EnumSet&) noexcept = default; - constexpr EnumSet& operator=(EnumSet&&) noexcept = default; - - template - constexpr EnumSet& operator=(EnumSet a_rhs) noexcept - { - _impl = static_cast(a_rhs.get()); - return *this; - } - - constexpr EnumSet& operator=(E a_value) noexcept - { - _impl = static_cast(a_value); - return *this; - } - - public: - [[nodiscard]] explicit constexpr operator bool() const noexcept { return _impl != static_cast(0); } - - [[nodiscard]] constexpr E operator*() const noexcept { return get(); } - [[nodiscard]] constexpr E get() const noexcept { return static_cast(_impl); } - [[nodiscard]] constexpr U underlying() const noexcept { return _impl; } - - public: - template - constexpr EnumSet& set(Args... a_args) noexcept - requires(std::same_as && ...) - { - _impl |= (static_cast(a_args) | ...); - return *this; - } - - template - constexpr EnumSet& set(bool a_set, Args... a_args) noexcept - requires(std::same_as && ...) - { - if (a_set) - _impl |= (static_cast(a_args) | ...); - else - _impl &= ~(static_cast(a_args) | ...); - - return *this; - } - - template - constexpr EnumSet& reset(Args... a_args) noexcept - requires(std::same_as && ...) - { - _impl &= ~(static_cast(a_args) | ...); - return *this; - } - - constexpr EnumSet& reset() noexcept - { - _impl = 0; - return *this; - } - - template - [[nodiscard]] constexpr bool any(Args... a_args) const noexcept - requires(std::same_as && ...) - { - return (_impl & (static_cast(a_args) | ...)) != static_cast(0); - } - - template - [[nodiscard]] constexpr bool all(Args... a_args) const noexcept - requires(std::same_as && ...) - { - return (_impl & (static_cast(a_args) | ...)) == (static_cast(a_args) | ...); - } - - template - [[nodiscard]] constexpr bool none(Args... a_args) const noexcept - requires(std::same_as && ...) - { - return (_impl & (static_cast(a_args) | ...)) == static_cast(0); - } - - public: - friend constexpr bool operator==(EnumSet a_lhs, EnumSet a_rhs) noexcept { return a_lhs.underlying() == a_rhs.underlying(); } - friend constexpr bool operator==(EnumSet a_lhs, E a_rhs) noexcept { return a_lhs.underlying() == static_cast(a_rhs); } - friend constexpr bool operator==(E a_lhs, EnumSet a_rhs) noexcept { return static_cast(a_lhs) == a_rhs.underlying(); } - - friend constexpr std::strong_ordering operator<=>(EnumSet a_lhs, EnumSet a_rhs) noexcept { return a_lhs.underlying() <=> a_rhs.underlying(); } - friend constexpr std::strong_ordering operator<=>(EnumSet a_lhs, E a_rhs) noexcept { return a_lhs.underlying() <=> static_cast(a_rhs); } - friend constexpr std::strong_ordering operator<=>(E a_lhs, EnumSet a_rhs) noexcept { return static_cast(a_lhs) <=> a_rhs.underlying(); } - - friend constexpr EnumSet operator&(EnumSet a_lhs, EnumSet a_rhs) noexcept { return static_cast(a_lhs.underlying() & a_rhs.underlying()); } - friend constexpr EnumSet operator&(EnumSet a_lhs, E a_rhs) noexcept { return static_cast(a_lhs.underlying() & static_cast(a_rhs)); } - friend constexpr EnumSet operator&(E a_lhs, EnumSet a_rhs) noexcept { return static_cast(static_cast(a_lhs) & a_rhs.underlying()); } - - friend constexpr EnumSet& operator&=(EnumSet& a_lhs, EnumSet a_rhs) noexcept { return a_lhs = a_lhs & a_rhs; } - friend constexpr EnumSet& operator&=(EnumSet& a_lhs, E a_rhs) noexcept { return a_lhs = a_lhs & a_rhs; } - - friend constexpr EnumSet operator|(EnumSet a_lhs, EnumSet a_rhs) noexcept { return static_cast(a_lhs.underlying() | a_rhs.underlying()); } - friend constexpr EnumSet operator|(EnumSet a_lhs, E a_rhs) noexcept { return static_cast(a_lhs.underlying() | static_cast(a_rhs)); } - friend constexpr EnumSet operator|(E a_lhs, EnumSet a_rhs) noexcept { return static_cast(static_cast(a_lhs) | a_rhs.underlying()); } - - friend constexpr EnumSet& operator|=(EnumSet& a_lhs, EnumSet a_rhs) noexcept { return a_lhs = a_lhs | a_rhs; } - friend constexpr EnumSet& operator|=(EnumSet& a_lhs, E a_rhs) noexcept { return a_lhs = a_lhs | a_rhs; } - - friend constexpr EnumSet operator^(EnumSet a_lhs, EnumSet a_rhs) noexcept { return static_cast(a_lhs.underlying() ^ a_rhs.underlying()); } - friend constexpr EnumSet operator^(EnumSet a_lhs, E a_rhs) noexcept { return static_cast(a_lhs.underlying() ^ static_cast(a_rhs)); } - friend constexpr EnumSet operator^(E a_lhs, EnumSet a_rhs) noexcept { return static_cast(static_cast(a_lhs) ^ a_rhs.underlying()); } - - friend constexpr EnumSet& operator^=(EnumSet& a_lhs, EnumSet a_rhs) noexcept { return a_lhs = a_lhs ^ a_rhs; } - friend constexpr EnumSet& operator^=(EnumSet& a_lhs, E a_rhs) noexcept { return a_lhs = a_lhs ^ a_rhs; } - - friend constexpr EnumSet operator+(EnumSet a_lhs, EnumSet a_rhs) noexcept { return static_cast(a_lhs.underlying() + a_rhs.underlying()); } - friend constexpr EnumSet operator+(EnumSet a_lhs, E a_rhs) noexcept { return static_cast(a_lhs.underlying() + static_cast(a_rhs)); } - friend constexpr EnumSet operator+(E a_lhs, EnumSet a_rhs) noexcept { return static_cast(static_cast(a_lhs) + a_rhs.underlying()); } - - friend constexpr EnumSet& operator+=(EnumSet& a_lhs, EnumSet a_rhs) noexcept { return a_lhs = a_lhs + a_rhs; } - friend constexpr EnumSet& operator+=(EnumSet& a_lhs, E a_rhs) noexcept { return a_lhs = a_lhs + a_rhs; } - - friend constexpr EnumSet operator-(EnumSet a_lhs, EnumSet a_rhs) noexcept { return static_cast(a_lhs.underlying() - a_rhs.underlying()); } - friend constexpr EnumSet operator-(EnumSet a_lhs, E a_rhs) noexcept { return static_cast(a_lhs.underlying() - static_cast(a_rhs)); } - friend constexpr EnumSet operator-(E a_lhs, EnumSet a_rhs) noexcept { return static_cast(static_cast(a_lhs) - a_rhs.underlying()); } - - friend constexpr EnumSet& operator-=(EnumSet& a_lhs, EnumSet a_rhs) noexcept { return a_lhs = a_lhs - a_rhs; } - friend constexpr EnumSet& operator-=(EnumSet& a_lhs, E a_rhs) noexcept { return a_lhs = a_lhs - a_rhs; } - - friend constexpr EnumSet operator<<(EnumSet a_lhs, EnumSet a_rhs) noexcept { return static_cast(a_lhs.underlying() << a_rhs.underlying()); } - friend constexpr EnumSet operator<<(EnumSet a_lhs, E a_rhs) noexcept { return static_cast(a_lhs.underlying() << static_cast(a_rhs)); } - friend constexpr EnumSet operator<<(E a_lhs, EnumSet a_rhs) noexcept { return static_cast(static_cast(a_lhs) << a_rhs.underlying()); } - - friend constexpr EnumSet& operator<<=(EnumSet& a_lhs, EnumSet a_rhs) noexcept { return a_lhs = a_lhs << a_rhs; } - friend constexpr EnumSet& operator<<=(EnumSet& a_lhs, E a_rhs) noexcept { return a_lhs = a_lhs << a_rhs; } - - friend constexpr EnumSet operator>>(EnumSet a_lhs, EnumSet a_rhs) noexcept { return static_cast(a_lhs.underlying() >> a_rhs.underlying()); } - friend constexpr EnumSet operator>>(EnumSet a_lhs, E a_rhs) noexcept { return static_cast(a_lhs.underlying() >> static_cast(a_rhs)); } - friend constexpr EnumSet operator>>(E a_lhs, EnumSet a_rhs) noexcept { return static_cast(static_cast(a_lhs) >> a_rhs.underlying()); } - - friend constexpr EnumSet& operator>>=(EnumSet& a_lhs, EnumSet a_rhs) noexcept { return a_lhs = a_lhs >> a_rhs; } - friend constexpr EnumSet& operator>>=(EnumSet& a_lhs, E a_rhs) noexcept { return a_lhs = a_lhs >> a_rhs; } - - friend constexpr EnumSet& operator~(EnumSet& a_lhs) noexcept { return a_lhs = ~a_lhs.underlying(); } - - private: - U _impl{ 0 }; - }; - - template - EnumSet(Args...) -> EnumSet< - std::common_type_t, - std::underlying_type_t< - std::common_type_t>>; -} - -#define REX_DEFINE_ENUM_CLASS_FLAGS(E) \ - inline constexpr E& operator|=(E& a_lhs, E a_rhs) { return a_lhs = (E)((__underlying_type(E))a_lhs | (__underlying_type(E))a_rhs); } \ - inline constexpr E& operator&=(E& a_lhs, E a_rhs) { return a_lhs = (E)((__underlying_type(E))a_lhs & (__underlying_type(E))a_rhs); } \ - inline constexpr E& operator^=(E& a_lhs, E a_rhs) { return a_lhs = (E)((__underlying_type(E))a_lhs ^ (__underlying_type(E))a_rhs); } \ - inline constexpr E operator|(E a_lhs, E a_rhs) { return (E)((__underlying_type(E))a_lhs | (__underlying_type(E))a_rhs); } \ - inline constexpr E operator&(E a_lhs, E a_rhs) { return (E)((__underlying_type(E))a_lhs & (__underlying_type(E))a_rhs); } \ - inline constexpr E operator^(E a_lhs, E a_rhs) { return (E)((__underlying_type(E))a_lhs ^ (__underlying_type(E))a_rhs); } \ - inline constexpr bool operator!(E a_lhs) { return !(__underlying_type(E))a_lhs; } \ - inline constexpr E operator~(E a_lhs) { return (E) ~(__underlying_type(E))a_lhs; } +#include "REX/TEnumSet.h" diff --git a/include/REX/REX/HASH.h b/include/REX/REX/HASH.h index 85725e4..83a32e7 100644 --- a/include/REX/REX/HASH.h +++ b/include/REX/REX/HASH.h @@ -1,49 +1,5 @@ #pragma once -#include "REX/BASE.h" -#include "REX/REX/ScopeExit.h" -#include "REX/W32/BCRYPT.h" +#pragma message("The header 'REX/REX/HASH.h' is deprecated, please include 'REX/HASH.h'") -namespace REX -{ - inline std::optional SHA512(std::span a_data) - { - REX::W32::BCRYPT_ALG_HANDLE algorithm; - if (!REX::W32::NT_SUCCESS(REX::W32::BCryptOpenAlgorithmProvider(&algorithm, REX::W32::BCRYPT_SHA512_ALGORITHM))) - return std::nullopt; - - const TScopeExit cleanup_algo([&]() { - [[maybe_unused]] const auto success = REX::W32::NT_SUCCESS(REX::W32::BCryptCloseAlgorithmProvider(algorithm)); - assert(success); - }); - - REX::W32::BCRYPT_HASH_HANDLE hash; - if (!REX::W32::NT_SUCCESS(REX::W32::BCryptCreateHash(algorithm, &hash))) - return std::nullopt; - - const TScopeExit cleanup_hash([&]() { - [[maybe_unused]] const auto success = REX::W32::NT_SUCCESS(REX::W32::BCryptDestroyHash(hash)); - assert(success); - }); - - if (!REX::W32::NT_SUCCESS(REX::W32::BCryptHashData(hash, reinterpret_cast(const_cast(a_data.data())), static_cast(a_data.size())))) - return std::nullopt; - - std::uint32_t length{ 0 }; - std::uint32_t output{ 0 }; - if (!REX::W32::NT_SUCCESS(REX::W32::BCryptGetProperty(hash, REX::W32::BCRYPT_HASH_LENGTH, reinterpret_cast(&length), sizeof(length), &output))) - return std::nullopt; - - std::vector buffer(static_cast(length)); - if (!REX::W32::NT_SUCCESS(REX::W32::BCryptFinishHash(hash, buffer.data(), static_cast(buffer.size())))) - return std::nullopt; - - std::string result; - result.reserve(buffer.size() * 2); - for (const auto byte : buffer) { - result += std::format("{:02X}", byte); - } - - return { std::move(result) }; - } -} +#include "REX/HASH.h" diff --git a/include/REX/REX/INI.h b/include/REX/REX/INI.h index aa0eaa8..1f1e82b 100644 --- a/include/REX/REX/INI.h +++ b/include/REX/REX/INI.h @@ -1,100 +1,6 @@ #pragma once -#include "REX/REX/Setting.h" +#pragma message("The header 'REX/REX/INI.h' is deprecated, please include 'REX/TIniSetting.h' or 'REX/FIniSettingStore.h'") -#ifdef COMMONLIB_OPTION_INI -namespace REX::INI -{ - using sec_t = std::string_view; - using key_t = std::string_view; - - namespace Impl - { - template - void SettingLoad(void* a_file, sec_t a_section, key_t a_key, T& a_value, T& a_valueDefault); - - template - void SettingSave(void* a_file, sec_t a_section, key_t a_key, T& a_value); - } - - class SettingStore : - public TSettingStore - { - public: - virtual void Load() override; - virtual void Save() override; - }; - - template - class Setting : - public TSetting - { - public: - Setting(sec_t a_section, key_t a_key, T a_default) : - TSetting(a_default), - m_section(a_section), - m_key(a_key) - {} - - public: - virtual void Load(void* a_data, bool a_isBase) override - { - if (a_isBase) { - Impl::SettingLoad(a_data, m_section, m_key, this->m_valueDefault, this->m_valueDefault); - this->SetValue(this->m_valueDefault); - } else { - Impl::SettingLoad(a_data, m_section, m_key, this->m_value, this->m_valueDefault); - } - } - - virtual void Save(void* a_data) override - { - Impl::SettingSave(a_data, m_section, m_key, this->m_value); - } - - private: - sec_t m_section; - key_t m_key; - }; - - template - using Bool = Setting; - - template - using F32 = Setting; - - template - using F64 = Setting; - - template - using I8 = Setting; - - template - using I16 = Setting; - - template - using I32 = Setting; - - template - using U8 = Setting; - - template - using U16 = Setting; - - template - using U32 = Setting; - - template - using Str = Setting; -} - -template -struct std::formatter, CharT> : std::formatter -{ - template - auto format(const REX::INI::Setting& a_setting, FormatContext& a_ctx) const - { - return std::formatter::format(a_setting.GetValue(), a_ctx); - } -}; -#endif +#include "REX/FIniSettingStore.h" +#include "REX/TIniSetting.h" diff --git a/include/REX/REX/JSON.h b/include/REX/REX/JSON.h index 3f85dce..3ed707d 100644 --- a/include/REX/REX/JSON.h +++ b/include/REX/REX/JSON.h @@ -1,130 +1,6 @@ #pragma once -#include "REX/REX/Setting.h" +#pragma message("The header 'REX/REX/JSON.h' is deprecated, please include 'REX/TJsonSetting.h' or 'REX/FJsonSettingStore.h'") -#ifdef COMMONLIB_OPTION_JSON -namespace REX::JSON -{ - using path_t = std::string_view; - - namespace Impl - { - template - void SettingLoad(void* a_file, path_t a_path, T& a_value, T& a_valueDefault); - - template - void SettingSave(void* a_file, path_t a_path, T& a_value); - } - - class SettingStore : - public TSettingStore - { - public: - virtual void Load() override; - virtual void Save() override; - }; - - template - class Setting : - public TSetting - { - public: - Setting(path_t a_path, T a_default) : - TSetting(a_default), - m_path(a_path) - {} - - public: - virtual void Load(void* a_data, bool a_isBase) override - { - if (a_isBase) { - Impl::SettingLoad(a_data, m_path, this->m_valueDefault, this->m_valueDefault); - this->SetValue(this->m_valueDefault); - } else { - Impl::SettingLoad(a_data, m_path, this->m_value, this->m_valueDefault); - } - } - - virtual void Save(void* a_data) override - { - Impl::SettingSave(a_data, m_path, this->m_value); - } - - private: - path_t m_path; - }; - - template - using Bool = Setting; - - template - using F32 = Setting; - - template - using F64 = Setting; - - template - using I8 = Setting; - - template - using I16 = Setting; - - template - using I32 = Setting; - - template - using U8 = Setting; - - template - using U16 = Setting; - - template - using U32 = Setting; - - template - using Str = Setting; - - template - using SettingA = Setting, Store>; - - template - using BoolA = SettingA; - - template - using F32A = SettingA; - - template - using F64A = SettingA; - - template - using I8A = SettingA; - - template - using I16A = SettingA; - - template - using I32A = SettingA; - - template - using U8A = SettingA; - - template - using U16A = SettingA; - - template - using U32A = SettingA; - - template - using StrA = SettingA; -} - -template -struct std::formatter, CharT> : std::formatter -{ - template - auto format(const REX::JSON::Setting& a_setting, FormatContext& a_ctx) const - { - return std::formatter::format(a_setting.GetValue(), a_ctx); - } -}; -#endif +#include "REX/FJsonSettingStore.h" +#include "REX/TJsonSetting.h" diff --git a/include/REX/REX/LOG.h b/include/REX/REX/LOG.h index 40e748e..ea05b13 100644 --- a/include/REX/REX/LOG.h +++ b/include/REX/REX/LOG.h @@ -1,326 +1,5 @@ #pragma once -#include "REX/BASE.h" +#pragma message("The header 'REX/REX/LOG.h' is deprecated, please include 'REX/LOG.h'") -namespace REX -{ - enum class LOG_LEVEL - { - TRACE = 0, - DEBUG = 1, - INFO = 2, - WARN = 3, - ERROR = 4, - CRITICAL = 5, - }; - - void LOG(const std::source_location a_loc, const LOG_LEVEL a_level, const std::string_view a_fmt); - - void LOG(const std::source_location a_loc, const LOG_LEVEL a_level, const std::wstring_view a_fmt); - - template - void LOG(const std::source_location a_loc, const LOG_LEVEL a_level, const std::format_string a_fmt, T&&... a_args) - { - LOG(a_loc, a_level, std::vformat(a_fmt.get(), std::make_format_args(a_args...))); - } - - template - void LOG(const std::source_location a_loc, const LOG_LEVEL a_level, const std::wformat_string a_fmt, T&&... a_args) - { - LOG(a_loc, a_level, std::vformat(a_fmt.get(), std::make_wformat_args(a_args...))); - } - - template - struct TRACE - { - TRACE() = delete; - - explicit TRACE(const std::format_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::TRACE, a_fmt, std::forward(a_args)...); - } - - explicit TRACE(const std::wformat_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::TRACE, a_fmt, std::forward(a_args)...); - } - }; - - template <> - struct TRACE - { - TRACE() = delete; - - explicit TRACE(const std::string_view a_fmt, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::TRACE, a_fmt); - } - - explicit TRACE(const std::wstring_view a_fmt, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::TRACE, a_fmt); - } - }; - - template - struct DEBUG - { - DEBUG() = delete; - - explicit DEBUG(const std::format_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::DEBUG, a_fmt, std::forward(a_args)...); - } - - explicit DEBUG(const std::wformat_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::DEBUG, a_fmt, std::forward(a_args)...); - } - }; - - template <> - struct DEBUG - { - DEBUG() = delete; - - explicit DEBUG(const std::string_view a_fmt, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::DEBUG, a_fmt); - } - - explicit DEBUG(const std::wstring_view a_fmt, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::DEBUG, a_fmt); - } - }; - - template - struct INFO - { - INFO() = delete; - - explicit INFO(const std::format_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::INFO, a_fmt, std::forward(a_args)...); - } - - explicit INFO(const std::wformat_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::INFO, a_fmt, std::forward(a_args)...); - } - }; - - template <> - struct INFO - { - INFO() = delete; - - explicit INFO(const std::string_view a_fmt, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::INFO, a_fmt); - } - - explicit INFO(const std::wstring_view a_fmt, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::INFO, a_fmt); - } - }; - - template - struct WARN - { - WARN() = delete; - - explicit WARN(const std::format_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::WARN, a_fmt, std::forward(a_args)...); - } - - explicit WARN(const std::wformat_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::WARN, a_fmt, std::forward(a_args)...); - } - }; - - template <> - struct WARN - { - WARN() = delete; - - explicit WARN(const std::string_view a_fmt, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::WARN, a_fmt); - } - - explicit WARN(const std::wstring_view a_fmt, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::WARN, a_fmt); - } - }; - - template - struct ERROR - { - ERROR() = delete; - - explicit ERROR(const std::format_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::ERROR, a_fmt, std::forward(a_args)...); - } - - explicit ERROR(const std::wformat_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::ERROR, a_fmt, std::forward(a_args)...); - } - }; - - template <> - struct ERROR - { - ERROR() = delete; - - explicit ERROR(const std::string_view a_fmt, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::ERROR, a_fmt); - } - - explicit ERROR(const std::wstring_view a_fmt, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::ERROR, a_fmt); - } - }; - - template - struct CRITICAL - { - CRITICAL() = delete; - - explicit CRITICAL(const std::format_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::CRITICAL, a_fmt, std::forward(a_args)...); - } - - explicit CRITICAL(const std::wformat_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::CRITICAL, a_fmt, std::forward(a_args)...); - } - }; - - template <> - struct CRITICAL - { - CRITICAL() = delete; - - explicit CRITICAL(const std::string_view a_fmt, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::CRITICAL, a_fmt); - } - - explicit CRITICAL(const std::wstring_view a_fmt, const std::source_location a_loc = std::source_location::current()) - { - LOG(a_loc, LOG_LEVEL::CRITICAL, a_fmt); - } - }; - - template - TRACE(const std::format_string, T&&...) -> TRACE; - template - TRACE(const std::wformat_string, T&&...) -> TRACE; - TRACE(const std::string_view) -> TRACE; - TRACE(const std::wstring_view) -> TRACE; - - template - DEBUG(const std::format_string, T&&...) -> DEBUG; - template - DEBUG(const std::wformat_string, T&&...) -> DEBUG; - DEBUG(const std::string_view) -> DEBUG; - DEBUG(const std::wstring_view) -> DEBUG; - - template - INFO(const std::format_string, T&&...) -> INFO; - template - INFO(const std::wformat_string, T&&...) -> INFO; - INFO(const std::string_view) -> INFO; - INFO(const std::wstring_view) -> INFO; - - template - WARN(const std::format_string, T&&...) -> WARN; - template - WARN(const std::wformat_string, T&&...) -> WARN; - WARN(const std::string_view) -> WARN; - WARN(const std::wstring_view) -> WARN; - - template - ERROR(const std::format_string, T&&...) -> ERROR; - template - ERROR(const std::wformat_string, T&&...) -> ERROR; - ERROR(const std::string_view) -> ERROR; - ERROR(const std::wstring_view) -> ERROR; - - template - CRITICAL(const std::format_string, T&&...) -> CRITICAL; - template - CRITICAL(const std::wformat_string, T&&...) -> CRITICAL; - CRITICAL(const std::string_view) -> CRITICAL; - CRITICAL(const std::wstring_view) -> CRITICAL; -} - -namespace REX -{ - namespace IMPL - { - void FAIL(const std::source_location a_loc, const std::string_view a_fmt); - void FAIL(const std::source_location a_loc, const std::wstring_view a_fmt); - - template - void FAIL(const std::source_location a_loc, const std::format_string a_fmt, T&&... a_args) - { - FAIL(a_loc, std::vformat(a_fmt.get(), std::make_format_args(a_args...))); - } - - template - void FAIL(const std::source_location a_loc, const std::wformat_string a_fmt, T&&... a_args) - { - FAIL(a_loc, std::vformat(a_fmt.get(), std::make_wformat_args(a_args...))); - } - } - - template - struct FAIL - { - FAIL() = delete; - - explicit FAIL(const std::format_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) - { - IMPL::FAIL(a_loc, a_fmt, std::forward(a_args)...); - } - - explicit FAIL(const std::wformat_string a_fmt, T&&... a_args, const std::source_location a_loc = std::source_location::current()) - { - IMPL::FAIL(a_loc, a_fmt, std::forward(a_args)...); - } - }; - - template <> - struct FAIL - { - FAIL() = delete; - - explicit FAIL(const std::string_view a_fmt, const std::source_location a_loc = std::source_location::current()) - { - IMPL::FAIL(a_loc, a_fmt); - } - - explicit FAIL(const std::wstring_view a_fmt, const std::source_location a_loc = std::source_location::current()) - { - IMPL::FAIL(a_loc, a_fmt); - } - }; - - template - FAIL(const std::format_string, T&&...) -> FAIL; - template - FAIL(const std::wformat_string, T&&...) -> FAIL; - FAIL(const std::string_view) -> FAIL; - FAIL(const std::wstring_view) -> FAIL; -} +#include "REX/LOG.h" diff --git a/include/REX/REX/MemoryMap.h b/include/REX/REX/MemoryMap.h index a8f164f..9fb2322 100644 --- a/include/REX/REX/MemoryMap.h +++ b/include/REX/REX/MemoryMap.h @@ -1,132 +1,5 @@ #pragma once -#include "REX/W32/KERNEL32.h" +#pragma message("The header 'REX/REX/MemoryMap.h' is deprecated, please include 'REX/FMemoryMap.h'") -namespace REX -{ - class MemoryMap - { - static constexpr auto DYNAMIC_SIZE{ static_cast(-1) }; - - public: - MemoryMap() = default; - ~MemoryMap() { close(); } - - public: - void close() - { - if (m_mapView) { - REX::W32::UnmapViewOfFile(m_mapView); - m_mapView = nullptr; - } - - if (m_map) { - REX::W32::CloseHandle(m_map); - m_map = nullptr; - } - - if (m_file != REX::W32::INVALID_HANDLE_VALUE) { - REX::W32::CloseHandle(m_file); - m_file = nullptr; - } - - m_size = 0; - m_owner = false; - } - - std::byte* data() const noexcept - { - return static_cast(m_mapView); - } - - std::size_t size() const noexcept - { - return m_size; - } - - bool is_open() const - { - return m_mapView; - } - - bool is_owner() const - { - return m_owner; - } - - bool is_file() const - { - return m_file != REX::W32::INVALID_HANDLE_VALUE; - } - - bool create(bool a_write, const std::string_view a_name, std::size_t a_size) - { - close(); - - if (create_impl(a_write, a_name, a_size)) - return true; - - close(); - return false; - } - - bool create(bool a_write, std::filesystem::path a_path, const std::string_view a_name, std::size_t a_size = DYNAMIC_SIZE) - { - close(); - - const auto access = a_write ? REX::W32::GENERIC_READ | REX::W32::GENERIC_WRITE : REX::W32::GENERIC_READ; - const auto share = a_write ? REX::W32::FILE_SHARE_READ | REX::W32::FILE_SHARE_WRITE : REX::W32::FILE_SHARE_READ; - m_file = REX::W32::CreateFileW(a_path.c_str(), access, share, nullptr, REX::W32::OPEN_EXISTING, REX::W32::FILE_ATTRIBUTE_READONLY, nullptr); - if (m_file == REX::W32::INVALID_HANDLE_VALUE) - return false; - - if (create_impl(a_write, a_name, a_size)) - return true; - - close(); - return false; - } - - private: - bool create_impl(bool a_write, const std::string_view a_name, std::size_t a_size) - { - REX::W32::LARGE_INTEGER size; - if (a_size == DYNAMIC_SIZE) { - if (m_file == REX::W32::INVALID_HANDLE_VALUE) - return false; - - if (REX::W32::GetFileSizeEx(m_file, &size) == 0) - return false; - - } else { - size.value = a_size; - } - - const auto access = a_write ? REX::W32::FILE_MAP_READ | REX::W32::FILE_MAP_WRITE : REX::W32::FILE_MAP_READ; - m_map = REX::W32::OpenFileMappingA(access, false, a_name.data()); - if (!m_map) { - const auto protect = a_write ? REX::W32::PAGE_READWRITE : REX::W32::PAGE_READONLY; - m_map = REX::W32::CreateFileMappingA(m_file, nullptr, protect, size.hi, size.lo, a_name.data()); - if (!m_map) - return false; - - m_owner = true; - } - - m_mapView = REX::W32::MapViewOfFile(m_map, access, 0, 0, size.value); - if (!m_mapView) - return false; - - m_size = static_cast(size.value); - - return true; - } - - private: - void* m_file{ REX::W32::INVALID_HANDLE_VALUE }; - void* m_map{ nullptr }; - void* m_mapView{ nullptr }; - std::size_t m_size{ 0 }; - bool m_owner{ false }; - }; -} +#include "REX/FMemoryMap.h" diff --git a/include/REX/REX/ScopeExit.h b/include/REX/REX/ScopeExit.h index b1adb21..0be43be 100644 --- a/include/REX/REX/ScopeExit.h +++ b/include/REX/REX/ScopeExit.h @@ -1,65 +1,5 @@ #pragma once -#include "REX/BASE.h" +#pragma message("The header 'REX/REX/ScopeExit.h' is deprecated, please include 'REX/TScopeExit.h'") -namespace REX -{ - template - requires(std::invocable>) - class TScopeExit - { - public: - template - explicit TScopeExit(Fn&& a_fn) noexcept(std::is_nothrow_constructible_v || - std::is_nothrow_constructible_v) - requires(!std::is_same_v, TScopeExit> && - std::is_constructible_v) - { - static_assert(std::invocable); - - if constexpr (!std::is_lvalue_reference_v && - std::is_nothrow_constructible_v) { - _fn.emplace(std::forward(a_fn)); - } else { - _fn.emplace(a_fn); - } - } - - TScopeExit(TScopeExit&& a_rhs) noexcept(std::is_nothrow_move_constructible_v || - std::is_nothrow_copy_constructible_v) - requires(std::is_nothrow_move_constructible_v || - std::is_copy_constructible_v) - { - static_assert(!(std::is_nothrow_move_constructible_v && !std::is_move_constructible_v)); - static_assert(!(!std::is_nothrow_move_constructible_v && !std::is_copy_constructible_v)); - - if (a_rhs.active()) { - if constexpr (std::is_nothrow_move_constructible_v) { - _fn.emplace(std::forward(*a_rhs._fn)); - } else { - _fn.emplace(a_rhs._fn); - } - a_rhs.release(); - } - } - - TScopeExit(const TScopeExit&) = delete; - - ~TScopeExit() noexcept - { - if (_fn.has_value()) { - (*_fn)(); - } - } - - void release() noexcept { _fn.reset(); } - - private: - [[nodiscard]] bool active() const noexcept { return _fn.has_value(); } - - std::optional> _fn; - }; - - template - TScopeExit(EF) -> TScopeExit; -} +#include "REX/TScopeExit.h" diff --git a/include/REX/REX/Setting.h b/include/REX/REX/Setting.h deleted file mode 100644 index fcf63f1..0000000 --- a/include/REX/REX/Setting.h +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once - -#include "REX/REX/Singleton.h" - -namespace REX -{ - class ISetting - { - public: - virtual void Load(void* a_data, bool a_isBase) = 0; - virtual void Save(void* a_data) = 0; - }; - - class ISettingStore - { - public: - virtual void Init(const char* a_file, const char* a_fileCustom) = 0; - virtual void Load() = 0; - virtual void Save() = 0; - virtual void Register(ISetting* a_setting) = 0; - }; - - template - class TSetting : - public ISetting - { - public: - TSetting() = delete; - - TSetting(T a_default) : - m_value(a_default), - m_valueDefault(a_default) - { - Store::GetSingleton()->Register(this); - } - - public: - T GetValue() const { return m_value; } - - T GetValueDefault() const { return m_valueDefault; } - - void SetValue(T a_value) { m_value = a_value; } - - public: - operator T&() { return m_value; } - operator const T&() const { return m_value; } - - protected: - T m_value; - T m_valueDefault; - }; - - template - class TSettingStore : - public ISettingStore, - public Singleton - { - public: - virtual void Init(const char* a_fileBase, const char* a_fileUser) override - { - m_fileBase = a_fileBase; - m_fileUser = a_fileUser; - } - - virtual void Register(ISetting* a_setting) override - { - m_settings.emplace_back(a_setting); - } - - protected: - std::string_view m_fileBase; - std::string_view m_fileUser; - std::vector m_settings; - }; -} diff --git a/include/REX/REX/Singleton.h b/include/REX/REX/Singleton.h index 59e62e2..2074ca1 100644 --- a/include/REX/REX/Singleton.h +++ b/include/REX/REX/Singleton.h @@ -1,30 +1,5 @@ #pragma once -#include "REX/BASE.h" +#pragma message("The header 'REX/REX/Singleton.h' is deprecated, please include 'REX/TSingleton.h'") -namespace REX -{ - template - class TSingleton - { - public: - static T* GetSingleton() - { - static T singleton; - return std::addressof(singleton); - } - - protected: - TSingleton() = default; - ~TSingleton() = default; - - TSingleton(const TSingleton&) = delete; - TSingleton(TSingleton&&) = delete; - - TSingleton& operator=(const TSingleton&) = delete; - TSingleton& operator=(TSingleton&&) = delete; - }; - - template - using Singleton = TSingleton; -} +#include "REX/TSingleton.h" diff --git a/include/REX/REX/StaticString.h b/include/REX/REX/StaticString.h index 7420e21..796f235 100644 --- a/include/REX/REX/StaticString.h +++ b/include/REX/REX/StaticString.h @@ -1,56 +1,5 @@ #pragma once -#include "REX/BASE.h" +#pragma message("The header 'REX/REX/StaticString.h' is deprecated, please include 'REX/TStaticString.h'") -namespace REX -{ - template - struct TStaticString - { - using char_type = T; - using pointer = char_type*; - using const_pointer = const char_type*; - using reference = char_type&; - using const_reference = const char_type&; - using size_type = std::size_t; - - static constexpr auto NPOS = static_cast(-1); - - consteval TStaticString(const_pointer a_string) noexcept - { - for (size_type i = 0; i < N; ++i) { - c[i] = a_string[i]; - } - } - - [[nodiscard]] consteval const_reference operator[](size_type a_pos) const noexcept - { - assert(a_pos < N); - return c[a_pos]; - } - - [[nodiscard]] consteval char_type value_at(size_type a_pos) const noexcept - { - assert(a_pos < N); - return c[a_pos]; - } - - [[nodiscard]] consteval const_reference back() const noexcept { return (*this)[size() - 1]; } - [[nodiscard]] consteval const_pointer data() const noexcept { return c; } - [[nodiscard]] consteval bool empty() const noexcept { return this->size() == 0; } - [[nodiscard]] consteval const_reference front() const noexcept { return (*this)[0]; } - [[nodiscard]] consteval size_type length() const noexcept { return N; } - [[nodiscard]] consteval size_type size() const noexcept { return length(); } - - template - consteval auto substr() const noexcept - { - return TStaticString < T, COUNT != NPOS ? COUNT : N - POS > (this->data() + POS); - } - - char_type c[N] = {}; - }; - - template - TStaticString(const T (&)[N]) -> TStaticString; -} +#include "REX/TStaticString.h" diff --git a/include/REX/REX/TOML.h b/include/REX/REX/TOML.h index b2ecd78..46d887a 100644 --- a/include/REX/REX/TOML.h +++ b/include/REX/REX/TOML.h @@ -1,116 +1,6 @@ #pragma once -#include "REX/REX/Setting.h" +#pragma message("The header 'REX/REX/TOML.h' is deprecated, please include 'REX/TTomlSetting.h' or 'REX/FTomlSettingStore.h'") -#ifdef COMMONLIB_OPTION_TOML -namespace REX::TOML -{ - using sec_t = std::vector; - using key_t = std::string_view; - - namespace Impl - { - template - void SettingLoad(void* a_file, sec_t a_section, key_t a_key, T& a_value, T& a_valueDefault); - - template - void SettingSave(void* a_file, sec_t a_section, key_t a_key, T& a_value); - } - - class SettingStore : - public TSettingStore - { - public: - virtual void Load() override; - virtual void Save() override; - }; - - template - class Setting : - public TSetting - { - public: - Setting(key_t a_key, T a_default) : - TSetting(a_default), - m_section(), - m_key(a_key) - {} - - Setting(std::string_view a_section, key_t a_key, T a_default) : - TSetting(a_default), - m_section(), - m_key(a_key) - { - for (const auto token : std::ranges::split_view{ a_section, std::string_view{ "." } }) { - m_section.emplace_back(token.data(), token.size()); - } - } - - Setting(std::initializer_list a_section, key_t a_key, T a_default) : - TSetting(a_default), - m_section(a_section), - m_key(a_key) - {} - - public: - virtual void Load(void* a_data, bool a_isBase) override - { - if (a_isBase) { - Impl::SettingLoad(a_data, m_section, m_key, this->m_valueDefault, this->m_valueDefault); - this->SetValue(this->m_valueDefault); - } else { - Impl::SettingLoad(a_data, m_section, m_key, this->m_value, this->m_valueDefault); - } - } - - virtual void Save(void* a_data) override - { - Impl::SettingSave(a_data, m_section, m_key, this->m_value); - } - - private: - sec_t m_section; - key_t m_key; - }; - - template - using Bool = Setting; - - template - using F32 = Setting; - - template - using F64 = Setting; - - template - using I8 = Setting; - - template - using I16 = Setting; - - template - using I32 = Setting; - - template - using U8 = Setting; - - template - using U16 = Setting; - - template - using U32 = Setting; - - template - using Str = Setting; -} - -template -struct std::formatter, CharT> : std::formatter -{ - template - auto format(const REX::TOML::Setting& a_setting, FormatContext& a_ctx) const - { - return std::formatter::format(a_setting.GetValue(), a_ctx); - } -}; -#endif +#include "REX/FTomlSettingStore.h" +#include "REX/TTomlSetting.h" diff --git a/include/REX/TAtomicRef.h b/include/REX/TAtomicRef.h new file mode 100644 index 0000000..afa00c5 --- /dev/null +++ b/include/REX/TAtomicRef.h @@ -0,0 +1,45 @@ +#pragma once + +#include "REX/BASE.h" + +namespace REX +{ + template + class TAtomicRef : + public std::atomic_ref + { + private: + using super = std::atomic_ref; + + public: + using value_type = typename super::value_type; + + explicit TAtomicRef(volatile T& a_obj) noexcept(std::is_nothrow_constructible_v) : + super(const_cast(a_obj)) + {} + + using super::super; + using super::operator=; + }; + + template + TAtomicRef(volatile T&) -> TAtomicRef; + + template class TAtomicRef; + template class TAtomicRef; + template class TAtomicRef; + template class TAtomicRef; + template class TAtomicRef; + template class TAtomicRef; + template class TAtomicRef; + template class TAtomicRef; + + static_assert(TAtomicRef::is_always_lock_free); + static_assert(TAtomicRef::is_always_lock_free); + static_assert(TAtomicRef::is_always_lock_free); + static_assert(TAtomicRef::is_always_lock_free); + static_assert(TAtomicRef::is_always_lock_free); + static_assert(TAtomicRef::is_always_lock_free); + static_assert(TAtomicRef::is_always_lock_free); + static_assert(TAtomicRef::is_always_lock_free); +} diff --git a/include/REX/TEnum.h b/include/REX/TEnum.h new file mode 100644 index 0000000..3356048 --- /dev/null +++ b/include/REX/TEnum.h @@ -0,0 +1,96 @@ +#pragma once + +#include "REX/BASE.h" + +namespace REX +{ + template < + class E, + class U = std::underlying_type_t> + class TEnum + { + public: + using enum_type = E; + using underlying_type = U; + + static_assert(std::is_enum_v, "TEnum must be an enum"); + static_assert(std::is_integral_v, "TEnum<..., U> must be an integral"); + + constexpr TEnum() noexcept = default; + constexpr TEnum(const TEnum&) noexcept = default; + constexpr TEnum(TEnum&&) noexcept = default; + + template // NOLINTNEXTLINE(google-explicit-constructor) + constexpr TEnum(TEnum a_rhs) noexcept : + _impl(static_cast(a_rhs.get())) + {} + + constexpr TEnum(E a_value) noexcept : + _impl(static_cast(a_value)) + {} + + ~TEnum() noexcept = default; + + constexpr TEnum& operator=(const TEnum&) noexcept = default; + constexpr TEnum& operator=(TEnum&&) noexcept = default; + + template + constexpr TEnum& operator=(TEnum a_rhs) noexcept + { + _impl = static_cast(a_rhs.get()); + } + + constexpr TEnum& operator=(E a_value) noexcept + { + _impl = static_cast(a_value); + return *this; + } + + public: + [[nodiscard]] explicit constexpr operator bool() const noexcept { return _impl != static_cast(0); } + + [[nodiscard]] constexpr E operator*() const noexcept { return get(); } + [[nodiscard]] constexpr E get() const noexcept { return static_cast(_impl); } + [[nodiscard]] constexpr U underlying() const noexcept { return _impl; } + + public: + friend constexpr bool operator==(TEnum a_lhs, TEnum a_rhs) noexcept { return a_lhs.underlying() == a_rhs.underlying(); } + friend constexpr bool operator==(TEnum a_lhs, E a_rhs) noexcept { return a_lhs.underlying() == static_cast(a_rhs); } + friend constexpr bool operator==(E a_lhs, TEnum a_rhs) noexcept { return static_cast(a_lhs) == a_rhs.underlying(); } + + private: + U _impl{ 0 }; + }; + + template + TEnum(Args...) -> TEnum< + std::common_type_t, + std::underlying_type_t< + std::common_type_t>>; +} + +namespace REX +{ + template < + class E, + class U = std::underlying_type_t> + class [[deprecated("Renamed to 'REX::TEnum'")]] Enum : + public TEnum + { + using super = TEnum; + + public: + using enum_type = E; + using underlying_type = U; + + using super::super; + using super::operator=; + using super::operator*; + }; + + template + Enum(Args...) -> Enum< + std::common_type_t, + std::underlying_type_t< + std::common_type_t>>; +} diff --git a/include/REX/TEnumSet.h b/include/REX/TEnumSet.h new file mode 100644 index 0000000..87870b4 --- /dev/null +++ b/include/REX/TEnumSet.h @@ -0,0 +1,221 @@ +#pragma once + +#include "REX/BASE.h" + +namespace REX +{ + template < + class E, + class U = std::underlying_type_t> + class TEnumSet + { + public: + using enum_type = E; + using underlying_type = U; + + static_assert(std::is_enum_v, "TEnumSet must be an enum"); + static_assert(std::is_integral_v, "TEnumSet<..., U> must be an integral"); + + constexpr TEnumSet() noexcept = default; + constexpr TEnumSet(const TEnumSet&) noexcept = default; + constexpr TEnumSet(TEnumSet&&) noexcept = default; + + template // NOLINTNEXTLINE(google-explicit-constructor) + constexpr TEnumSet(TEnumSet a_rhs) noexcept : + _impl(static_cast(a_rhs.get())) + {} + + template + constexpr TEnumSet(Args... a_values) noexcept + requires(std::same_as && ...) + : + _impl((static_cast(a_values) | ...)) + {} + + ~TEnumSet() noexcept = default; + + constexpr TEnumSet& operator=(const TEnumSet&) noexcept = default; + constexpr TEnumSet& operator=(TEnumSet&&) noexcept = default; + + template + constexpr TEnumSet& operator=(TEnumSet a_rhs) noexcept + { + _impl = static_cast(a_rhs.get()); + return *this; + } + + constexpr TEnumSet& operator=(E a_value) noexcept + { + _impl = static_cast(a_value); + return *this; + } + + public: + [[nodiscard]] explicit constexpr operator bool() const noexcept { return _impl != static_cast(0); } + + [[nodiscard]] constexpr E operator*() const noexcept { return get(); } + [[nodiscard]] constexpr E get() const noexcept { return static_cast(_impl); } + [[nodiscard]] constexpr U underlying() const noexcept { return _impl; } + + public: + template + constexpr TEnumSet& set(Args... a_args) noexcept + requires(std::same_as && ...) + { + _impl |= (static_cast(a_args) | ...); + return *this; + } + + template + constexpr TEnumSet& set(bool a_set, Args... a_args) noexcept + requires(std::same_as && ...) + { + if (a_set) + _impl |= (static_cast(a_args) | ...); + else + _impl &= ~(static_cast(a_args) | ...); + + return *this; + } + + template + constexpr TEnumSet& reset(Args... a_args) noexcept + requires(std::same_as && ...) + { + _impl &= ~(static_cast(a_args) | ...); + return *this; + } + + constexpr TEnumSet& reset() noexcept + { + _impl = 0; + return *this; + } + + template + [[nodiscard]] constexpr bool any(Args... a_args) const noexcept + requires(std::same_as && ...) + { + return (_impl & (static_cast(a_args) | ...)) != static_cast(0); + } + + template + [[nodiscard]] constexpr bool all(Args... a_args) const noexcept + requires(std::same_as && ...) + { + return (_impl & (static_cast(a_args) | ...)) == (static_cast(a_args) | ...); + } + + template + [[nodiscard]] constexpr bool none(Args... a_args) const noexcept + requires(std::same_as && ...) + { + return (_impl & (static_cast(a_args) | ...)) == static_cast(0); + } + + public: + friend constexpr bool operator==(TEnumSet a_lhs, TEnumSet a_rhs) noexcept { return a_lhs.underlying() == a_rhs.underlying(); } + friend constexpr bool operator==(TEnumSet a_lhs, E a_rhs) noexcept { return a_lhs.underlying() == static_cast(a_rhs); } + friend constexpr bool operator==(E a_lhs, TEnumSet a_rhs) noexcept { return static_cast(a_lhs) == a_rhs.underlying(); } + + friend constexpr std::strong_ordering operator<=>(TEnumSet a_lhs, TEnumSet a_rhs) noexcept { return a_lhs.underlying() <=> a_rhs.underlying(); } + friend constexpr std::strong_ordering operator<=>(TEnumSet a_lhs, E a_rhs) noexcept { return a_lhs.underlying() <=> static_cast(a_rhs); } + friend constexpr std::strong_ordering operator<=>(E a_lhs, TEnumSet a_rhs) noexcept { return static_cast(a_lhs) <=> a_rhs.underlying(); } + + friend constexpr TEnumSet operator&(TEnumSet a_lhs, TEnumSet a_rhs) noexcept { return static_cast(a_lhs.underlying() & a_rhs.underlying()); } + friend constexpr TEnumSet operator&(TEnumSet a_lhs, E a_rhs) noexcept { return static_cast(a_lhs.underlying() & static_cast(a_rhs)); } + friend constexpr TEnumSet operator&(E a_lhs, TEnumSet a_rhs) noexcept { return static_cast(static_cast(a_lhs) & a_rhs.underlying()); } + + friend constexpr TEnumSet& operator&=(TEnumSet& a_lhs, TEnumSet a_rhs) noexcept { return a_lhs = a_lhs & a_rhs; } + friend constexpr TEnumSet& operator&=(TEnumSet& a_lhs, E a_rhs) noexcept { return a_lhs = a_lhs & a_rhs; } + + friend constexpr TEnumSet operator|(TEnumSet a_lhs, TEnumSet a_rhs) noexcept { return static_cast(a_lhs.underlying() | a_rhs.underlying()); } + friend constexpr TEnumSet operator|(TEnumSet a_lhs, E a_rhs) noexcept { return static_cast(a_lhs.underlying() | static_cast(a_rhs)); } + friend constexpr TEnumSet operator|(E a_lhs, TEnumSet a_rhs) noexcept { return static_cast(static_cast(a_lhs) | a_rhs.underlying()); } + + friend constexpr TEnumSet& operator|=(TEnumSet& a_lhs, TEnumSet a_rhs) noexcept { return a_lhs = a_lhs | a_rhs; } + friend constexpr TEnumSet& operator|=(TEnumSet& a_lhs, E a_rhs) noexcept { return a_lhs = a_lhs | a_rhs; } + + friend constexpr TEnumSet operator^(TEnumSet a_lhs, TEnumSet a_rhs) noexcept { return static_cast(a_lhs.underlying() ^ a_rhs.underlying()); } + friend constexpr TEnumSet operator^(TEnumSet a_lhs, E a_rhs) noexcept { return static_cast(a_lhs.underlying() ^ static_cast(a_rhs)); } + friend constexpr TEnumSet operator^(E a_lhs, TEnumSet a_rhs) noexcept { return static_cast(static_cast(a_lhs) ^ a_rhs.underlying()); } + + friend constexpr TEnumSet& operator^=(TEnumSet& a_lhs, TEnumSet a_rhs) noexcept { return a_lhs = a_lhs ^ a_rhs; } + friend constexpr TEnumSet& operator^=(TEnumSet& a_lhs, E a_rhs) noexcept { return a_lhs = a_lhs ^ a_rhs; } + + friend constexpr TEnumSet operator+(TEnumSet a_lhs, TEnumSet a_rhs) noexcept { return static_cast(a_lhs.underlying() + a_rhs.underlying()); } + friend constexpr TEnumSet operator+(TEnumSet a_lhs, E a_rhs) noexcept { return static_cast(a_lhs.underlying() + static_cast(a_rhs)); } + friend constexpr TEnumSet operator+(E a_lhs, TEnumSet a_rhs) noexcept { return static_cast(static_cast(a_lhs) + a_rhs.underlying()); } + + friend constexpr TEnumSet& operator+=(TEnumSet& a_lhs, TEnumSet a_rhs) noexcept { return a_lhs = a_lhs + a_rhs; } + friend constexpr TEnumSet& operator+=(TEnumSet& a_lhs, E a_rhs) noexcept { return a_lhs = a_lhs + a_rhs; } + + friend constexpr TEnumSet operator-(TEnumSet a_lhs, TEnumSet a_rhs) noexcept { return static_cast(a_lhs.underlying() - a_rhs.underlying()); } + friend constexpr TEnumSet operator-(TEnumSet a_lhs, E a_rhs) noexcept { return static_cast(a_lhs.underlying() - static_cast(a_rhs)); } + friend constexpr TEnumSet operator-(E a_lhs, TEnumSet a_rhs) noexcept { return static_cast(static_cast(a_lhs) - a_rhs.underlying()); } + + friend constexpr TEnumSet& operator-=(TEnumSet& a_lhs, TEnumSet a_rhs) noexcept { return a_lhs = a_lhs - a_rhs; } + friend constexpr TEnumSet& operator-=(TEnumSet& a_lhs, E a_rhs) noexcept { return a_lhs = a_lhs - a_rhs; } + + friend constexpr TEnumSet operator<<(TEnumSet a_lhs, TEnumSet a_rhs) noexcept { return static_cast(a_lhs.underlying() << a_rhs.underlying()); } + friend constexpr TEnumSet operator<<(TEnumSet a_lhs, E a_rhs) noexcept { return static_cast(a_lhs.underlying() << static_cast(a_rhs)); } + friend constexpr TEnumSet operator<<(E a_lhs, TEnumSet a_rhs) noexcept { return static_cast(static_cast(a_lhs) << a_rhs.underlying()); } + + friend constexpr TEnumSet& operator<<=(TEnumSet& a_lhs, TEnumSet a_rhs) noexcept { return a_lhs = a_lhs << a_rhs; } + friend constexpr TEnumSet& operator<<=(TEnumSet& a_lhs, E a_rhs) noexcept { return a_lhs = a_lhs << a_rhs; } + + friend constexpr TEnumSet operator>>(TEnumSet a_lhs, TEnumSet a_rhs) noexcept { return static_cast(a_lhs.underlying() >> a_rhs.underlying()); } + friend constexpr TEnumSet operator>>(TEnumSet a_lhs, E a_rhs) noexcept { return static_cast(a_lhs.underlying() >> static_cast(a_rhs)); } + friend constexpr TEnumSet operator>>(E a_lhs, TEnumSet a_rhs) noexcept { return static_cast(static_cast(a_lhs) >> a_rhs.underlying()); } + + friend constexpr TEnumSet& operator>>=(TEnumSet& a_lhs, TEnumSet a_rhs) noexcept { return a_lhs = a_lhs >> a_rhs; } + friend constexpr TEnumSet& operator>>=(TEnumSet& a_lhs, E a_rhs) noexcept { return a_lhs = a_lhs >> a_rhs; } + + friend constexpr TEnumSet& operator~(TEnumSet& a_lhs) noexcept { return a_lhs = ~a_lhs.underlying(); } + + private: + U _impl{ 0 }; + }; + + template + TEnumSet(Args...) -> TEnumSet< + std::common_type_t, + std::underlying_type_t< + std::common_type_t>>; +} + +namespace REX +{ + template < + class E, + class U = std::underlying_type_t> + class [[deprecated("Renamed to 'REX::TEnumSet'")]] EnumSet : + public TEnumSet + { + using super = TEnumSet; + + public: + using enum_type = E; + using underlying_type = U; + + using super::super; + using super::operator=; + using super::operator*; + }; + + template + EnumSet(Args...) -> EnumSet< + std::common_type_t, + std::underlying_type_t< + std::common_type_t>>; +} + +#define REX_DEFINE_ENUM_CLASS_FLAGS(E) \ + inline constexpr E& operator|=(E& a_lhs, E a_rhs) { return a_lhs = (E)((__underlying_type(E))a_lhs | (__underlying_type(E))a_rhs); } \ + inline constexpr E& operator&=(E& a_lhs, E a_rhs) { return a_lhs = (E)((__underlying_type(E))a_lhs & (__underlying_type(E))a_rhs); } \ + inline constexpr E& operator^=(E& a_lhs, E a_rhs) { return a_lhs = (E)((__underlying_type(E))a_lhs ^ (__underlying_type(E))a_rhs); } \ + inline constexpr E operator|(E a_lhs, E a_rhs) { return (E)((__underlying_type(E))a_lhs | (__underlying_type(E))a_rhs); } \ + inline constexpr E operator&(E a_lhs, E a_rhs) { return (E)((__underlying_type(E))a_lhs & (__underlying_type(E))a_rhs); } \ + inline constexpr E operator^(E a_lhs, E a_rhs) { return (E)((__underlying_type(E))a_lhs ^ (__underlying_type(E))a_rhs); } \ + inline constexpr bool operator!(E a_lhs) { return !(__underlying_type(E))a_lhs; } \ + inline constexpr E operator~(E a_lhs) { return (E) ~(__underlying_type(E))a_lhs; } diff --git a/include/REX/TIniSetting.h b/include/REX/TIniSetting.h new file mode 100644 index 0000000..20ea503 --- /dev/null +++ b/include/REX/TIniSetting.h @@ -0,0 +1,89 @@ +#pragma once + +#ifdef COMMONLIB_OPTION_INI + +# include "REX/FIniSettingStore.h" +# include "REX/TSetting.h" + +namespace REX::Impl +{ + template + void IniSettingLoad(void* a_file, std::string_view a_section, std::string_view a_key, T& a_value, T& a_valueDefault); + + template + void IniSettingSave(void* a_file, std::string_view a_section, std::string_view a_key, T& a_value); +} + +namespace REX +{ + template + class TIniSetting : + public TSetting + { + public: + TIniSetting(std::string_view a_section, std::string_view a_key, T a_default) : + TSetting(a_default), + m_section(a_section), + m_key(a_key) + {} + + public: + virtual void Load(void* a_data, bool a_isBase) override + { + if (a_isBase) { + Impl::IniSettingLoad(a_data, m_section, m_key, this->m_valueDefault, this->m_valueDefault); + this->SetValue(this->m_valueDefault); + } else { + Impl::IniSettingLoad(a_data, m_section, m_key, this->m_value, this->m_valueDefault); + } + } + + virtual void Save(void* a_data) override + { + Impl::IniSettingSave(a_data, m_section, m_key, this->m_value); + } + + private: + std::string_view m_section; + std::string_view m_key; + }; +} + +// DEPRECATED +namespace REX::INI +{ + template + using Setting [[deprecated("Renamed to 'REX::TIniSetting'")]] = TIniSetting; + + template + using Bool = TIniSetting; + + template + using F32 = TIniSetting; + + template + using F64 = TIniSetting; + + template + using I8 = TIniSetting; + + template + using I16 = TIniSetting; + + template + using I32 = TIniSetting; + + template + using U8 = TIniSetting; + + template + using U16 = TIniSetting; + + template + using U32 = TIniSetting; + + template + using Str = TIniSetting; +} + +#endif diff --git a/include/REX/TJsonSetting.h b/include/REX/TJsonSetting.h new file mode 100644 index 0000000..e810297 --- /dev/null +++ b/include/REX/TJsonSetting.h @@ -0,0 +1,120 @@ +#pragma once + +#ifdef COMMONLIB_OPTION_JSON + +# include "REX/FJsonSettingStore.h" +# include "REX/TSetting.h" + +namespace REX::Impl +{ + template + void JsonSettingLoad(void* a_file, std::string_view a_path, T& a_value, T& a_valueDefault); + + template + void JsonSettingSave(void* a_file, std::string_view a_path, T& a_value); +} + +namespace REX +{ + template + class TJsonSetting : + public TSetting + { + public: + TJsonSetting(std::string_view a_path, T a_default) : + TSetting(a_default), + m_path(a_path) + {} + + public: + virtual void Load(void* a_data, bool a_isBase) override + { + if (a_isBase) { + Impl::JsonSettingLoad(a_data, m_path, this->m_valueDefault, this->m_valueDefault); + this->SetValue(this->m_valueDefault); + } else { + Impl::JsonSettingLoad(a_data, m_path, this->m_value, this->m_valueDefault); + } + } + + virtual void Save(void* a_data) override + { + Impl::JsonSettingSave(a_data, m_path, this->m_value); + } + + private: + std::string_view m_path; + }; +} + +// DEPRECATED +namespace REX::JSON +{ + template + using Setting [[deprecated("Renamed to 'REX::TJsonSetting")]] = TJsonSetting; + + template + using Bool = TJsonSetting; + + //template + //using F32 = TJsonSetting; + + template + using F64 = TJsonSetting; + + template + using I8 = TJsonSetting; + + template + using I16 = TJsonSetting; + + template + using I32 = TJsonSetting; + + template + using U8 = TJsonSetting; + + template + using U16 = TJsonSetting; + + template + using U32 = TJsonSetting; + + template + using Str = TJsonSetting; + + template + using SettingA = TJsonSetting, S>; + + template + using BoolA = SettingA; + + //template + //using F32A = SettingA; + + template + using F64A = SettingA; + + template + using I8A = SettingA; + + template + using I16A = SettingA; + + template + using I32A = SettingA; + + template + using U8A = SettingA; + + template + using U16A = SettingA; + + template + using U32A = SettingA; + + template + using StrA = SettingA; +} + +#endif diff --git a/include/REX/TScopeExit.h b/include/REX/TScopeExit.h new file mode 100644 index 0000000..b1adb21 --- /dev/null +++ b/include/REX/TScopeExit.h @@ -0,0 +1,65 @@ +#pragma once + +#include "REX/BASE.h" + +namespace REX +{ + template + requires(std::invocable>) + class TScopeExit + { + public: + template + explicit TScopeExit(Fn&& a_fn) noexcept(std::is_nothrow_constructible_v || + std::is_nothrow_constructible_v) + requires(!std::is_same_v, TScopeExit> && + std::is_constructible_v) + { + static_assert(std::invocable); + + if constexpr (!std::is_lvalue_reference_v && + std::is_nothrow_constructible_v) { + _fn.emplace(std::forward(a_fn)); + } else { + _fn.emplace(a_fn); + } + } + + TScopeExit(TScopeExit&& a_rhs) noexcept(std::is_nothrow_move_constructible_v || + std::is_nothrow_copy_constructible_v) + requires(std::is_nothrow_move_constructible_v || + std::is_copy_constructible_v) + { + static_assert(!(std::is_nothrow_move_constructible_v && !std::is_move_constructible_v)); + static_assert(!(!std::is_nothrow_move_constructible_v && !std::is_copy_constructible_v)); + + if (a_rhs.active()) { + if constexpr (std::is_nothrow_move_constructible_v) { + _fn.emplace(std::forward(*a_rhs._fn)); + } else { + _fn.emplace(a_rhs._fn); + } + a_rhs.release(); + } + } + + TScopeExit(const TScopeExit&) = delete; + + ~TScopeExit() noexcept + { + if (_fn.has_value()) { + (*_fn)(); + } + } + + void release() noexcept { _fn.reset(); } + + private: + [[nodiscard]] bool active() const noexcept { return _fn.has_value(); } + + std::optional> _fn; + }; + + template + TScopeExit(EF) -> TScopeExit; +} diff --git a/include/REX/TSetting.h b/include/REX/TSetting.h new file mode 100644 index 0000000..f799cc9 --- /dev/null +++ b/include/REX/TSetting.h @@ -0,0 +1,36 @@ +#pragma once + +#include "REX/ISetting.h" + +namespace REX +{ + template + class TSetting : + public ISetting + { + public: + TSetting() = delete; + + TSetting(T a_default) : + m_value(a_default), + m_valueDefault(a_default) + { + Store::GetSingleton()->Register(this); + } + + public: + T GetValue() const { return m_value; } + + T GetValueDefault() const { return m_valueDefault; } + + void SetValue(T a_value) { m_value = a_value; } + + public: + operator T&() { return m_value; } + operator const T&() const { return m_value; } + + protected: + T m_value; + T m_valueDefault; + }; +} diff --git a/include/REX/TSettingStore.h b/include/REX/TSettingStore.h new file mode 100644 index 0000000..56565e1 --- /dev/null +++ b/include/REX/TSettingStore.h @@ -0,0 +1,30 @@ +#pragma once + +#include "REX/ISettingStore.h" +#include "REX/TSingleton.h" + +namespace REX +{ + template + class TSettingStore : + public ISettingStore, + public TSingleton + { + public: + virtual void Init(const char* a_fileBase, const char* a_fileUser) override + { + m_fileBase = a_fileBase; + m_fileUser = a_fileUser; + } + + virtual void Register(ISetting* a_setting) override + { + m_settings.emplace_back(a_setting); + } + + protected: + std::string_view m_fileBase; + std::string_view m_fileUser; + std::vector m_settings; + }; +} diff --git a/include/REX/TSingleton.h b/include/REX/TSingleton.h new file mode 100644 index 0000000..a9e6625 --- /dev/null +++ b/include/REX/TSingleton.h @@ -0,0 +1,30 @@ +#pragma once + +#include "REX/BASE.h" + +namespace REX +{ + template + class TSingleton + { + public: + static T* GetSingleton() + { + static T singleton; + return std::addressof(singleton); + } + + protected: + TSingleton() = default; + ~TSingleton() = default; + + TSingleton(const TSingleton&) = delete; + TSingleton(TSingleton&&) = delete; + + TSingleton& operator=(const TSingleton&) = delete; + TSingleton& operator=(TSingleton&&) = delete; + }; + + template + using Singleton [[deprecated("Renamed to 'REX::TSingleton'")]] = TSingleton; +} diff --git a/include/REX/TStaticString.h b/include/REX/TStaticString.h new file mode 100644 index 0000000..7420e21 --- /dev/null +++ b/include/REX/TStaticString.h @@ -0,0 +1,56 @@ +#pragma once + +#include "REX/BASE.h" + +namespace REX +{ + template + struct TStaticString + { + using char_type = T; + using pointer = char_type*; + using const_pointer = const char_type*; + using reference = char_type&; + using const_reference = const char_type&; + using size_type = std::size_t; + + static constexpr auto NPOS = static_cast(-1); + + consteval TStaticString(const_pointer a_string) noexcept + { + for (size_type i = 0; i < N; ++i) { + c[i] = a_string[i]; + } + } + + [[nodiscard]] consteval const_reference operator[](size_type a_pos) const noexcept + { + assert(a_pos < N); + return c[a_pos]; + } + + [[nodiscard]] consteval char_type value_at(size_type a_pos) const noexcept + { + assert(a_pos < N); + return c[a_pos]; + } + + [[nodiscard]] consteval const_reference back() const noexcept { return (*this)[size() - 1]; } + [[nodiscard]] consteval const_pointer data() const noexcept { return c; } + [[nodiscard]] consteval bool empty() const noexcept { return this->size() == 0; } + [[nodiscard]] consteval const_reference front() const noexcept { return (*this)[0]; } + [[nodiscard]] consteval size_type length() const noexcept { return N; } + [[nodiscard]] consteval size_type size() const noexcept { return length(); } + + template + consteval auto substr() const noexcept + { + return TStaticString < T, COUNT != NPOS ? COUNT : N - POS > (this->data() + POS); + } + + char_type c[N] = {}; + }; + + template + TStaticString(const T (&)[N]) -> TStaticString; +} diff --git a/include/REX/TTomlSetting.h b/include/REX/TTomlSetting.h new file mode 100644 index 0000000..9fc5269 --- /dev/null +++ b/include/REX/TTomlSetting.h @@ -0,0 +1,105 @@ +#pragma once + +#ifdef COMMONLIB_OPTION_TOML + +# include "REX/FTomlSettingStore.h" +# include "REX/TSetting.h" + +namespace REX::Impl +{ + template + void TomlSettingLoad(void* a_file, std::vector a_section, std::string_view a_key, T& a_value, T& a_valueDefault); + + template + void TomlSettingSave(void* a_file, std::vector a_section, std::string_view a_key, T& a_value); +} + +namespace REX +{ + template + class TTomlSetting : + public TSetting + { + public: + TTomlSetting(std::string_view a_key, T a_default) : + TSetting(a_default), + m_section(), + m_key(a_key) + {} + + TTomlSetting(std::string_view a_section, std::string_view a_key, T a_default) : + TSetting(a_default), + m_section(), + m_key(a_key) + { + for (const auto token : std::ranges::split_view{ a_section, std::string_view{ "." } }) { + m_section.emplace_back(token.data(), token.size()); + } + } + + TTomlSetting(std::initializer_list a_section, std::string_view a_key, T a_default) : + TSetting(a_default), + m_section(a_section), + m_key(a_key) + {} + + public: + virtual void Load(void* a_data, bool a_isBase) override + { + if (a_isBase) { + Impl::TomlSettingLoad(a_data, m_section, m_key, this->m_valueDefault, this->m_valueDefault); + this->SetValue(this->m_valueDefault); + } else { + Impl::TomlSettingLoad(a_data, m_section, m_key, this->m_value, this->m_valueDefault); + } + } + + virtual void Save(void* a_data) override + { + Impl::TomlSettingSave(a_data, m_section, m_key, this->m_value); + } + + private: + std::vector m_section; + std::string_view m_key; + }; +} + +// DEPRECATED +namespace REX::TOML +{ + template + using Setting [[deprecated("Renamed to 'REX::TTomlSetting")]] = TTomlSetting; + + template + using Bool = TTomlSetting; + + template + using F32 = TTomlSetting; + + template + using F64 = TTomlSetting; + + template + using I8 = TTomlSetting; + + template + using I16 = TTomlSetting; + + template + using I32 = TTomlSetting; + + template + using U8 = TTomlSetting; + + template + using U16 = TTomlSetting; + + template + using U32 = TTomlSetting; + + template + using Str = TTomlSetting; +} + +#endif diff --git a/src/REL/FHook.cpp b/src/REL/FHook.cpp new file mode 100644 index 0000000..1806b96 --- /dev/null +++ b/src/REL/FHook.cpp @@ -0,0 +1,107 @@ +#include "REL/FHook.h" + +#include "REL/FHookStore.h" + +#include "REX/LOG.h" + +namespace REL +{ + FHook::FHook(const std::uintptr_t a_address) : + m_address(a_address) + { + m_handle = FHookStore::GetSingleton()->Add(this); + m_name = std::to_string(m_handle); + } + + FHook::FHook(const std::uintptr_t a_address, const char* a_name) : + m_address(a_address), m_name(a_name) + { + m_handle = FHookStore::GetSingleton()->Add(this); + } + + FHook::FHook(const std::uintptr_t a_address, const EHookType a_type) : + m_address(a_address), m_type(a_type) + { + m_handle = FHookStore::GetSingleton()->Add(this); + m_name = std::to_string(m_handle); + } + + FHook::FHook(const std::uintptr_t a_address, const EHookType a_type, const EHookStep a_step) : + m_address(a_address), m_type(a_type), m_step(a_step) + { + m_handle = FHookStore::GetSingleton()->Add(this); + m_name = std::to_string(m_handle); + } + + FHook::FHook(const std::uintptr_t a_address, const EHookStep a_step) : + m_address(a_address), m_step(a_step) + { + m_handle = FHookStore::GetSingleton()->Add(this); + m_name = std::to_string(m_handle); + } + + FHook::FHook(const std::uintptr_t a_address, const char* a_name, const EHookStep a_step) : + m_address(a_address), m_name(a_name), m_step(a_step) + { + m_handle = FHookStore::GetSingleton()->Add(this); + } + + FHook::FHook(const std::uintptr_t a_address, const char* a_name, const EHookType a_type) : + m_address(a_address), m_name(a_name), m_type(a_type) + { + m_handle = FHookStore::GetSingleton()->Add(this); + } + + FHook::FHook(const std::uintptr_t a_address, const char* a_name, const EHookType a_type, const EHookStep a_step) : + m_address(a_address), m_name(a_name), m_type(a_type), m_step(a_step) + { + m_handle = FHookStore::GetSingleton()->Add(this); + } + + FHook::~FHook() + { + FHookStore::GetSingleton()->Remove(m_handle); + } + + bool FHook::Init() + { + REX::TRACE("{}: Init", *this); + + return true; + } + + FHookHandle FHook::GetHandle() const + { + return m_handle; + } + + const char* FHook::GetName() const + { + return m_name.c_str(); + } + + EHookType FHook::GetType() const + { + return m_type; + } + + EHookStep FHook::GetStep() const + { + return m_step; + } + + std::size_t FHook::GetSize() const + { + return m_size; + } + + std::size_t FHook::GetSizeTrampoline() const + { + return m_sizeTrampoline; + } + + bool FHook::GetEnabled() const + { + return m_enabled; + } +} diff --git a/src/REL/HookStore.cpp b/src/REL/FHookStore.cpp similarity index 65% rename from src/REL/HookStore.cpp rename to src/REL/FHookStore.cpp index ba3999e..c350c8f 100644 --- a/src/REL/HookStore.cpp +++ b/src/REL/FHookStore.cpp @@ -1,10 +1,12 @@ -#include "REL/HookStore.h" +#include "REL/FHookStore.h" -#include "REL/Hook.h" +#include "REL/IHook.h" + +#include "REX/LOG.h" namespace REL { - HOOK_HANDLE HookStore::Add(HookObject* a_hook) + FHookHandle FHookStore::Add(IHook* a_hook) { if (a_hook && a_hook->GetHandle() == 0) { m_hooks.insert({ ++m_handleCount, a_hook }); @@ -15,12 +17,12 @@ namespace REL return 0; } - void HookStore::Remove(const HOOK_HANDLE a_handle) + void FHookStore::Remove(const FHookHandle a_handle) { m_hooks.erase(a_handle); } - void HookStore::Init() + void FHookStore::Init() { std::size_t count{ 0 }; while (!m_hookQueue.empty()) { @@ -30,10 +32,10 @@ namespace REL m_hookQueue.pop(); } - REX::DEBUG("HookStore: Init {} queued hooks", count); + REX::DEBUG("FHookStore: Init {} queued hooks", count); } - void HookStore::Enable() + void FHookStore::Enable() { std::size_t count{ 0 }; for (auto& [name, hook] : m_hooks) { @@ -43,10 +45,10 @@ namespace REL } } - REX::DEBUG("HookStore: Enabled {} hooks", count); + REX::DEBUG("FHookStore: Enabled {} hooks", count); } - void HookStore::Enable(const HOOK_HANDLE a_handle) + void FHookStore::Enable(const FHookHandle a_handle) { if (const auto it = m_hooks.find(a_handle); it != m_hooks.end()) { if (it->second) { @@ -55,7 +57,7 @@ namespace REL } } - void HookStore::Enable(const HOOK_TYPE a_type) + void FHookStore::Enable(const EHookType a_type) { for (auto& [name, hook] : m_hooks) { if (hook && hook->GetType() == a_type) { @@ -64,7 +66,7 @@ namespace REL } } - void HookStore::Enable(const HOOK_STEP a_step) + void FHookStore::Enable(const EHookStep a_step) { std::size_t count{ 0 }; for (auto& [name, hook] : m_hooks) { @@ -74,10 +76,10 @@ namespace REL } } - REX::DEBUG("HookStore: Enabled {} {} hooks", count, a_step); + REX::DEBUG("FHookStore: Enabled {} {} hooks", count, a_step); } - void HookStore::Disable() + void FHookStore::Disable() { std::size_t count{ 0 }; for (auto& [name, hook] : m_hooks) { @@ -87,10 +89,10 @@ namespace REL } } - REX::DEBUG("HookStore: Disabled {} hooks", count); + REX::DEBUG("FHookStore: Disabled {} hooks", count); } - void HookStore::Disable(const HOOK_HANDLE a_handle) + void FHookStore::Disable(const FHookHandle a_handle) { for (auto& [name, hook] : m_hooks) { if (hook && hook->GetHandle() == a_handle) { @@ -99,7 +101,7 @@ namespace REL } } - void HookStore::Disable(const HOOK_TYPE a_type) + void FHookStore::Disable(const EHookType a_type) { for (auto& [name, hook] : m_hooks) { if (hook && hook->GetType() == a_type) { @@ -108,7 +110,7 @@ namespace REL } } - std::size_t HookStore::GetSizeTrampoline() + std::size_t FHookStore::GetSizeTrampoline() { std::size_t size{ 0 }; for (auto& [name, hook] : m_hooks) { diff --git a/src/REL/HookObject.cpp b/src/REL/HookObject.cpp deleted file mode 100644 index 0388f87..0000000 --- a/src/REL/HookObject.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "REL/HookObject.h" -#include "REL/HookStore.h" - -#include "REX/REX/LOG.h" - -namespace REL -{ - HookObject::HookObject(const std::uintptr_t a_address) : - m_address(a_address) - { - m_handle = HookStore::GetSingleton()->Add(this); - m_name = std::to_string(m_handle); - } - - HookObject::HookObject(const std::uintptr_t a_address, const char* a_name) : - m_address(a_address), m_name(a_name) - { - m_handle = HookStore::GetSingleton()->Add(this); - } - - HookObject::HookObject(const std::uintptr_t a_address, const HOOK_TYPE a_type) : - m_address(a_address), m_type(a_type) - { - m_handle = HookStore::GetSingleton()->Add(this); - m_name = std::to_string(m_handle); - } - - HookObject::HookObject(const std::uintptr_t a_address, const HOOK_TYPE a_type, const HOOK_STEP a_step) : - m_address(a_address), m_type(a_type), m_step(a_step) - { - m_handle = HookStore::GetSingleton()->Add(this); - m_name = std::to_string(m_handle); - } - - HookObject::HookObject(const std::uintptr_t a_address, const HOOK_STEP a_step) : - m_address(a_address), m_step(a_step) - { - m_handle = HookStore::GetSingleton()->Add(this); - m_name = std::to_string(m_handle); - } - - HookObject::HookObject(const std::uintptr_t a_address, const char* a_name, const HOOK_STEP a_step) : - m_address(a_address), m_name(a_name), m_step(a_step) - { - m_handle = HookStore::GetSingleton()->Add(this); - } - - HookObject::HookObject(const std::uintptr_t a_address, const char* a_name, const HOOK_TYPE a_type) : - m_address(a_address), m_name(a_name), m_type(a_type) - { - m_handle = HookStore::GetSingleton()->Add(this); - } - - HookObject::HookObject(const std::uintptr_t a_address, const char* a_name, const HOOK_TYPE a_type, const HOOK_STEP a_step) : - m_address(a_address), m_name(a_name), m_type(a_type), m_step(a_step) - { - m_handle = HookStore::GetSingleton()->Add(this); - } - - HookObject::~HookObject() - { - HookStore::GetSingleton()->Remove(m_handle); - } - - bool HookObject::Init() - { - REX::TRACE("{}: Init", *this); - - return true; - } - - HOOK_HANDLE HookObject::GetHandle() const - { - return m_handle; - } - - const char* HookObject::GetName() const - { - return m_name.c_str(); - } - - HOOK_TYPE HookObject::GetType() const - { - return m_type; - } - - HOOK_STEP HookObject::GetStep() const - { - return m_step; - } - - std::size_t HookObject::GetSize() const - { - return m_size; - } - - std::size_t HookObject::GetSizeTrampoline() const - { - return m_sizeTrampoline; - } - - bool HookObject::GetEnabled() const - { - return m_enabled; - } -} diff --git a/src/REL/IAT.cpp b/src/REL/IAT.cpp index 2e3d777..60e6500 100644 --- a/src/REL/IAT.cpp +++ b/src/REL/IAT.cpp @@ -1,79 +1,36 @@ #include "REL/IAT.h" -#include "REL/Module.h" -#include "REL/Utility.h" -#include "REX/REX/LOG.h" -#include "REX/W32/KERNEL32.h" +#include "REX/FModule.h" namespace REL { std::uintptr_t GetIATAddr(std::string_view a_dll, std::string_view a_function) { - return reinterpret_cast(GetIATPtr(std::move(a_dll), std::move(a_function))); + const auto mod = REX::FModule::GetExecutingModule(); + return mod.GetImportFunctionAddress(a_function, a_dll); } std::uintptr_t GetIATAddr(REX::W32::HMODULE a_module, std::string_view a_dll, std::string_view a_function) { - return reinterpret_cast(GetIATPtr(a_module, std::move(a_dll), std::move(a_function))); + const auto mod = REX::FModule(a_module); + return mod.GetImportFunctionAddress(a_function, a_dll); } void* GetIATPtr(std::string_view a_dll, std::string_view a_function) { - const auto mod = Module::GetSingleton(); - const auto ptr = static_cast(mod->pointer()); - return GetIATPtr(ptr, std::move(a_dll), std::move(a_function)); + const auto mod = REX::FModule::GetExecutingModule(); + return mod.GetImportFunctionPointer(a_function, a_dll); } - // https://guidedhacking.com/attachments/pe_imptbl_headers-jpg.2241/ void* GetIATPtr(REX::W32::HMODULE a_module, std::string_view a_dll, std::string_view a_function) { - assert(a_module); - const auto dosHeader = reinterpret_cast(a_module); - if (dosHeader->magic != REX::W32::IMAGE_DOS_SIGNATURE) { - REX::ERROR("Invalid DOS header"); - return nullptr; - } - - const auto ntHeader = REX::ADJUST_POINTER(dosHeader, dosHeader->lfanew); - const auto& dataDir = ntHeader->optionalHeader.dataDirectory[REX::W32::IMAGE_DIRECTORY_ENTRY_IMPORT]; - const auto importDesc = REX::ADJUST_POINTER(dosHeader, dataDir.virtualAddress); - - for (auto import = importDesc; import->characteristics != 0; ++import) { - auto name = REX::ADJUST_POINTER(dosHeader, import->name); - if (a_dll.size() == strlen(name) && _strnicmp(a_dll.data(), name, a_dll.size()) != 0) { - continue; - } - - const auto thunk = REX::ADJUST_POINTER(dosHeader, import->firstThunkOriginal); - for (std::size_t i = 0; thunk[i].ordinal; ++i) { - if (REX::W32::IMAGE_SNAP_BY_ORDINAL64(thunk[i].ordinal)) { - continue; - } - - const auto importByName = REX::ADJUST_POINTER(dosHeader, thunk[i].address); - if (a_function.size() == strlen(importByName->name) && - _strnicmp(a_function.data(), importByName->name, a_function.size()) == 0) { - return REX::ADJUST_POINTER(dosHeader, import->firstThunk) + i; - } - } - } - - REX::ERROR("Failed to find {} ({})", a_dll, a_function); - return nullptr; + const auto mod = REX::FModule(a_module); + return mod.GetImportFunctionPointer(a_function, a_dll); } std::uintptr_t PatchIAT(std::uintptr_t a_newFunc, std::string_view a_dll, std::string_view a_function) { - std::uintptr_t origAddr = 0; - - const auto oldFunc = GetIATAddr(a_dll, a_function); - if (oldFunc) { - origAddr = *reinterpret_cast(oldFunc); - REL::WriteSafeData(oldFunc, a_newFunc); - } else { - REX::ERROR("Failed to patch {} ({})", a_dll, a_function); - } - - return origAddr; + const auto mod = REX::FModule::GetExecutingModule(); + return mod.SetImportFunctionAddress(a_function, a_dll, a_newFunc); } } diff --git a/src/REL/IDDB.cpp b/src/REL/IDDB.cpp index 94b109e..ae777c3 100644 --- a/src/REL/IDDB.cpp +++ b/src/REL/IDDB.cpp @@ -1,9 +1,10 @@ #include "REL/IDDB.h" -#include "REL/Module.h" + #include "REL/Version.h" -#include "REX/REX/HASH.h" -#include "REX/REX/LOG.h" +#include "REX/FModule.h" +#include "REX/HASH.h" +#include "REX/LOG.h" #include "REX/W32/KERNEL32.h" namespace REL @@ -125,18 +126,18 @@ namespace REL { IDDB::IDDB() { - std::unordered_map> g_rootMap{ - { IDDB::Loader::SKSE, { L"versionlib", L"version" } }, - { IDDB::Loader::F4SE, { L"version" } }, - { IDDB::Loader::SFSE, { L"versionlib" } }, - { IDDB::Loader::OBSE, { L"versionlib" } }, + std::unordered_map> g_rootMap{ + { Loader::SKSE, { L"versionlib", L"version" } }, + { Loader::F4SE, { L"version" } }, + { Loader::SFSE, { L"versionlib" } }, + { Loader::OBSE, { L"versionlib" } }, }; - std::unordered_map> g_loaderMap{ - { IDDB::Loader::SKSE, { "SKSE", L"SKSE" } }, - { IDDB::Loader::F4SE, { "F4SE", L"F4SE" } }, - { IDDB::Loader::SFSE, { "SFSE", L"SFSE" } }, - { IDDB::Loader::OBSE, { "OBSE", L"OBSE" } }, + std::unordered_map> g_loaderMap{ + { Loader::SKSE, { "SKSE", L"SKSE" } }, + { Loader::F4SE, { "F4SE", L"F4SE" } }, + { Loader::SFSE, { "SFSE", L"SFSE" } }, + { Loader::OBSE, { "OBSE", L"OBSE" } }, }; wchar_t buffer[REX::W32::MAX_PATH]; @@ -155,8 +156,8 @@ namespace REL if (m_loader == Loader::None) REX::FAIL("Failed to determine Address Library loader!"); - const auto mod = Module::GetSingleton(); - const auto version = mod->version().wstring(L"-"); + const auto mod = REX::FModule::GetExecutingModule(); + const auto version = mod.GetFileVersion().wstring(L"-"); for (const auto& root : g_rootMap[m_loader]) { const auto name = std::format(L"{}-{}.bin", root, version); const auto path = plugin.parent_path() / name; @@ -192,8 +193,8 @@ namespace REL void IDDB::load_v0() { - const auto mod = Module::GetSingleton(); - const auto mapName = std::format("COMMONLIB_IDDB_OFFSETS_{}", mod->version().string("_")); + const auto mod = REX::FModule::GetExecutingModule(); + const auto mapName = std::format("COMMONLIB_IDDB_OFFSETS_{}", mod.GetFileVersion().string("_")); if (!m_mmap.create(false, m_path, mapName)) REX::FAIL(L"Failed to create Address Library MemoryMap!\nError: {}\nPath: {}", REX::W32::GetLastError(), m_path.wstring()); @@ -210,16 +211,17 @@ namespace REL try { HEADER_V2 header(a_stream); - const auto mod = Module::GetSingleton(); - if (header.game_version() != mod->version()) { + const auto mod = REX::FModule::GetExecutingModule(); + const auto modVersion = mod.GetFileVersion(); + if (header.game_version() != modVersion) { REX::FAIL( "Address Library version mismatch!\n" "Expected Version: {}\n" "Actual Version: {}", - mod->version().string(), header.game_version().string()); + modVersion.string(), header.game_version().string()); } - const auto mapName = std::format("COMMONLIB_IDDB_OFFSETS_{}", mod->version().string("_")); + const auto mapName = std::format("COMMONLIB_IDDB_OFFSETS_{}", modVersion.string("_")); const auto byteSize = static_cast(header.address_count()) * sizeof(MAPPING); if (!m_mmap.create(true, mapName, byteSize)) REX::FAIL("Failed to create Address Library MemoryMap!\nError: {}", REX::W32::GetLastError()); @@ -247,16 +249,17 @@ namespace REL try { HEADER_V5 header(a_stream); - const auto mod = Module::GetSingleton(); - if (header.game_version() != mod->version()) { + const auto mod = REX::FModule::GetExecutingModule(); + const auto modVersion = mod.GetFileVersion(); + if (header.game_version() != modVersion) { REX::FAIL( "Address Library version mismatch!\n" "Expected Version: {}\n" "Actual Version: {}", - mod->version().string(), header.game_version().string()); + modVersion.string(), header.game_version().string()); } - const auto mapName = std::format("COMMONLIB_IDDB_OFFSETS_{}", mod->version().string("_")); + const auto mapName = std::format("COMMONLIB_IDDB_OFFSETS_{}", modVersion.string("_")); if (!m_mmap.create(false, m_path, mapName)) REX::FAIL(L"Failed to create Address Library MemoryMap!\nError: {}\nPath: {}", REX::W32::GetLastError(), m_path.wstring()); @@ -355,33 +358,33 @@ namespace REL void IDDB::validate_file() { // clang-format off - std::unordered_map>> g_blacklistMap{ - { IDDB::Loader::SKSE, {} }, - { IDDB::Loader::F4SE, { + std::unordered_map>> g_blacklistMap{ + { Loader::SKSE, {} }, + { Loader::F4SE, { { REL::Version{ 1, 10, 980 }, "2AD60B95388F1B6E77A6F86F17BEB51D043CF95A341E91ECB2E911A393E45FE8156D585D2562F7B14434483D6E6652E2373B91589013507CABAE596C26A343F1"sv }, { REL::Version{ 1, 11, 159 }, "686D40387F638ED75AD43BB76CA14170576F1A30E91144F280987D13A3012B1CA6A4E04E6BE7A5B99E46C50332C49BE40C3D9448038E17D3D31C40E72A90AE26"sv } } }, - { IDDB::Loader::SFSE, {} }, - { IDDB::Loader::OBSE, {} }, + { Loader::SFSE, {} }, + { Loader::OBSE, {} }, }; // clang-format on - const auto mod = Module::GetSingleton(); - const auto version = mod->version(); + const auto mod = REX::FModule::GetExecutingModule(); + const auto modVersion = mod.GetFileVersion(); for (auto& check : g_blacklistMap[m_loader]) { - if (version == check.first) { + if (modVersion == check.first) { auto sha = REX::SHA512({ m_mmap.data(), m_mmap.size() }); if (!sha) REX::FAIL("Failed to hash Address Library file!\nPath: {}", m_path.string()); if (*sha == check.second) - REX::FAIL("Invalid Address Library loaded!\n\nRedownload Address Library for your game version.\nGame Version: {}", version.string()); + REX::FAIL("Invalid Address Library loaded!\n\nRedownload Address Library for your game version.\nGame Version: {}", modVersion.string()); } } } std::uint64_t IDDB::offset(std::uint64_t a_id) const { - const auto mod = Module::GetSingleton(); + const auto mod = REX::FModule::GetExecutingModule(); if (std::to_underlying(m_format) < 5) { if (m_v0.empty()) REX::FAIL("No Address Library has been loaded!"); @@ -400,7 +403,7 @@ namespace REL "Failed to find offset for Address Library ID!\n" "Invalid ID: {}\n" "Game Version: {}", - a_id, mod->version().string()); + a_id, mod.GetFileVersion().string()); } return static_cast(it->offset); @@ -415,7 +418,7 @@ namespace REL "Failed to find offset for Address Library ID!\n" "Invalid ID: {}\n" "Game Version: {}", - a_id, mod->version().string()); + a_id, mod.GetFileVersion().string()); } return offset; diff --git a/src/REL/Module.cpp b/src/REL/Module.cpp deleted file mode 100644 index 8a6e393..0000000 --- a/src/REL/Module.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "REL/Module.h" - -#include "REX/REX/CAST.h" -#include "REX/REX/LOG.h" -#include "REX/W32/KERNEL32.h" - -namespace REL -{ - Module::Module() : - _base(reinterpret_cast(REX::W32::GetModuleHandleA(nullptr))) - { - _natvis = _base; - - char path[REX::W32::MAX_PATH]; - if (!REX::W32::GetModuleFileNameA(reinterpret_cast(_base), path, REX::W32::MAX_PATH)) - REX::FAIL("failed to obtain file name"); - - _filename = std::filesystem::path(path).wstring(); - - if (const auto version = GetFileVersion(_filename)) { - _version = *version; - } else { - REX::FAIL("failed to obtain file version"); - } - - load_segments(); - } - - void Module::load_segments() - { - const auto dosHeader = reinterpret_cast(_base); - const auto ntHeader = REX::ADJUST_POINTER(dosHeader, dosHeader->lfanew); - const auto sections = REX::W32::IMAGE_FIRST_SECTION(ntHeader); - const auto size = std::min(ntHeader->fileHeader.sectionCount, _segments.size()); - for (std::size_t i = 0; i < size; ++i) { - const auto& section = sections[i]; - const auto it = std::find_if(SEGMENTS.begin(), SEGMENTS.end(), [&](auto&& a_elem) { - constexpr auto size = std::extent_v; - const auto len = std::min(a_elem.size(), size); - return std::memcmp(a_elem.data(), section.name, len) == 0; - }); - if (it != SEGMENTS.end()) { - const auto idx = static_cast(std::distance(SEGMENTS.begin(), it)); - _segments[idx] = Segment{ _base, _base + section.virtualAddress, section.virtualSize }; - } - } - } -} diff --git a/src/REL/Offset2ID.cpp b/src/REL/Offset2ID.cpp index d0736c3..27f0c10 100644 --- a/src/REL/Offset2ID.cpp +++ b/src/REL/Offset2ID.cpp @@ -1,7 +1,7 @@ #include "REL/Offset2ID.h" -#include "REL/Module.h" -#include "REX/REX/LOG.h" +#include "REX/FModule.h" +#include "REX/LOG.h" namespace REL { @@ -47,8 +47,8 @@ namespace REL return a_lhs.offset < a_rhs.offset; }); if (it == _offset2id.end()) { - const auto mod = Module::GetSingleton(); - const auto version = mod->version(); + const auto mod = REX::FModule::GetExecutingModule(); + const auto version = mod.GetFileVersion(); REX::FAIL( "Failed to find Address Library ID for offset!\n" "Invalid offset: 0x{:08X}\n" diff --git a/src/REL/Trampoline.cpp b/src/REL/Trampoline.cpp index da7b52d..6e784d1 100644 --- a/src/REL/Trampoline.cpp +++ b/src/REL/Trampoline.cpp @@ -4,7 +4,8 @@ #include "REL/Relocation.h" #include "REL/Utility.h" -#include "REX/REX/LOG.h" +#include "REX/FModule.h" +#include "REX/LOG.h" #include "REX/W32/KERNEL32.h" // xbyak brings in @@ -102,9 +103,9 @@ namespace REL } if (!a_module) { - const auto mod = Module::GetSingleton(); - const auto text = mod->segment(REL::Segment::text); - a_module = text.pointer() + text.size(); + const auto mod = REX::FModule::GetExecutingModule(); + const auto text = mod.GetSection(".text"); + a_module = text.GetPointer() + text.GetSize(); } auto mem = Impl::AllocTrampoline(a_size, reinterpret_cast(a_module)); diff --git a/src/REX/FIniSettingStore.cpp b/src/REX/FIniSettingStore.cpp new file mode 100644 index 0000000..07b2c32 --- /dev/null +++ b/src/REX/FIniSettingStore.cpp @@ -0,0 +1,46 @@ +#ifdef COMMONLIB_OPTION_INI + +# include "REX/FIniSettingStore.h" +# include "REX/ISetting.h" + +# include +# undef ERROR + +namespace REX +{ + void FIniSettingStore::Load() + { + CSimpleIniA file; + file.SetUnicode(true); + file.SetQuotes(true); + + if (std::filesystem::exists(m_fileBase)) { + file.LoadFile(m_fileBase.data()); + for (auto& setting : m_settings) { + setting->Load(&file, true); + } + } + + if (std::filesystem::exists(m_fileUser)) { + file.LoadFile(m_fileUser.data()); + for (auto& setting : m_settings) { + setting->Load(&file, false); + } + } + } + + void FIniSettingStore::Save() + { + CSimpleIniA file; + file.SetUnicode(true); + file.SetQuotes(true); + + file.LoadFile(m_fileBase.data()); + for (auto& setting : m_settings) { + setting->Save(&file); + } + + file.SaveFile(m_fileBase.data()); + } +} +#endif diff --git a/src/REX/FJsonSettingStore.cpp b/src/REX/FJsonSettingStore.cpp new file mode 100644 index 0000000..91c2d4e --- /dev/null +++ b/src/REX/FJsonSettingStore.cpp @@ -0,0 +1,52 @@ +#ifdef COMMONLIB_OPTION_JSON + +# include "REX/FJsonSettingStore.h" +# include "REX/ISetting.h" + +# include + +namespace REX +{ + void FJsonSettingStore::Load() + { + if (std::filesystem::exists(m_fileBase)) { + glz::generic result{}; + if (!glz::read_file_json(result, m_fileBase, std::string{})) { + for (auto setting : m_settings) { + setting->Load(&result, true); + } + } + } + + if (std::filesystem::exists(m_fileUser)) { + glz::generic result{}; + if (!glz::read_file_json(result, m_fileUser, std::string{})) { + for (auto setting : m_settings) { + setting->Load(&result, false); + } + } + } + } + + struct save_opts : glz::opts + { + static constexpr bool prettify = true; + std::uint8_t indentation_width = 4; + }; + + void FJsonSettingStore::Save() + { + glz::generic output{}; + if (std::filesystem::exists(m_fileBase)) { + (void)glz::read_file_json(output, m_fileBase, std::string{}); + } + + for (auto& setting : m_settings) { + setting->Save(&output); + } + + (void)glz::write_file_json(output, m_fileBase, std::string{}); + } +} + +#endif diff --git a/src/REX/FModule.cpp b/src/REX/FModule.cpp new file mode 100644 index 0000000..82054d7 --- /dev/null +++ b/src/REX/FModule.cpp @@ -0,0 +1,115 @@ +#include "REX/FModule.h" + +#include "REL/Utility.h" +#include "REX/CAST.h" +#include "REX/LOG.h" +#include "REX/W32/KERNEL32.h" + +namespace REX +{ + FModule FModule::GetCurrentModule() + { + return FModule{ W32::GetCurrentModule() }; + } + + FModule FModule::GetExecutingModule() + { + return FModule{ W32::GetModuleHandleA(nullptr) }; + } + + FModule FModule::GetLoadedModule(std::string_view a_name) + { + return FModule{ W32::GetModuleHandleA(a_name.data()) }; + } + + std::string FModule::GetFileName() const noexcept + { + char path[W32::MAX_PATH]; + if (!W32::GetModuleFileNameA(reinterpret_cast(m_base), path, W32::MAX_PATH)) { + REX::FAIL("failed to obtain module file name"); + } + + return std::filesystem::path(path).string(); + } + + REL::Version FModule::GetFileVersion() const noexcept + { + return *REL::GetFileVersion(GetFileName()); + } + + void* FModule::GetExportFunctionPointer(std::string_view a_function) const + { + if (m_base) { + return W32::GetProcAddress(reinterpret_cast(m_base), a_function.data()); + } + + return nullptr; + } + + void* FModule::GetImportFunctionPointer(std::string_view a_function, std::string_view a_library) const + { + const auto dosHeader = reinterpret_cast(m_base); + if (dosHeader->magic != W32::IMAGE_DOS_SIGNATURE) { + REX::ERROR("Invalid IMAGE_DOS_HEADER"); + return nullptr; + } + + const auto ntHeader = ADJUST_POINTER(dosHeader, dosHeader->lfanew); + const auto& dataDir = ntHeader->optionalHeader.dataDirectory[REX::W32::IMAGE_DIRECTORY_ENTRY_IMPORT]; + const auto importDesc = ADJUST_POINTER(dosHeader, dataDir.virtualAddress); + + for (auto import = importDesc; import->characteristics != 0; ++import) { + auto name = ADJUST_POINTER(dosHeader, import->name); + if (a_library.size() == strlen(name) && _strnicmp(a_library.data(), name, a_library.size()) != 0) { + continue; + } + + const auto thunk = ADJUST_POINTER(dosHeader, import->firstThunkOriginal); + for (std::size_t i = 0; thunk[i].ordinal; ++i) { + if (W32::IMAGE_SNAP_BY_ORDINAL64(thunk[i].ordinal)) { + continue; + } + + const auto importByName = ADJUST_POINTER(dosHeader, thunk[i].address); + if (a_function.size() == strlen(importByName->name) && + _strnicmp(a_function.data(), importByName->name, a_function.size()) == 0) { + return ADJUST_POINTER(dosHeader, import->firstThunk) + i; + } + } + } + + REX::ERROR("Failed to get {} ({})", a_function, a_library); + + return nullptr; + } + + void* FModule::SetImportFunctionPointer(std::string_view a_function, std::string_view a_library, void* a_pointer) const + { + auto original = GetImportFunctionPointer(a_function, a_library); + if (original) { + REL::WriteSafeData(original, a_pointer); + } else { + REX::ERROR("Failed to set {} ({})", a_function, a_library); + } + + return original; + } + + FModuleSection FModule::GetSection(std::string_view a_section) const + { + const auto dosHeader = reinterpret_cast(m_base); + const auto ntHeader = ADJUST_POINTER(dosHeader, dosHeader->lfanew); + const auto sections = W32::IMAGE_FIRST_SECTION(ntHeader); + for (std::size_t i = 0; i < ntHeader->fileHeader.sectionCount; ++i) { + const auto& section = sections[i]; + constexpr auto size = std::extent_v; + const auto len = std::min(a_section.size(), size); + + if (std::memcmp(a_section.data(), section.name, len) == 0) { + return FModuleSection{ m_base, m_base + section.virtualAddress, section.virtualSize }; + } + } + + return {}; + } +} diff --git a/src/REX/FTomlSettingStore.cpp b/src/REX/FTomlSettingStore.cpp new file mode 100644 index 0000000..7a512d1 --- /dev/null +++ b/src/REX/FTomlSettingStore.cpp @@ -0,0 +1,57 @@ +#ifdef COMMONLIB_OPTION_TOML + +# include "REX/FTomlSettingStore.h" +# include "REX/ISetting.h" + +# include + +bool toml_recurse_mark_implicit(toml::value& a_value) +{ + for (auto& kv : a_value.as_table()) { + if (kv.second.is_table()) { + if (!toml_recurse_mark_implicit(kv.second)) { + continue; + } + kv.second.as_table_fmt().fmt = toml::table_format::implicit; + } else { + return false; + } + } + return true; +} + +namespace REX +{ + void FTomlSettingStore::Load() + { + if (auto result = toml::try_parse(m_fileBase.data()); result.is_ok()) { + for (auto& setting : m_settings) { + setting->Load(&result.unwrap(), true); + } + } + + if (auto result = toml::try_parse(m_fileUser.data()); result.is_ok()) { + for (auto& setting : m_settings) { + setting->Load(&result.unwrap(), false); + } + } + } + + void FTomlSettingStore::Save() + { + toml::value output{}; + if (auto result = toml::try_parse(m_fileBase.data()); result.is_ok()) { + output = result.unwrap(); + } + + for (auto setting : m_settings) { + setting->Save(&output); + } + + toml_recurse_mark_implicit(output); + std::ofstream file{ m_fileBase.data(), std::ios::trunc }; + file << toml::format(output); + } +} + +#endif diff --git a/src/REX/REX/LOG.cpp b/src/REX/LOG.cpp similarity index 86% rename from src/REX/REX/LOG.cpp rename to src/REX/LOG.cpp index bd16981..04a107a 100644 --- a/src/REX/REX/LOG.cpp +++ b/src/REX/LOG.cpp @@ -1,66 +1,66 @@ -#include "REX/REX/LOG.h" +#include "REX/LOG.h" #include "REX/W32/KERNEL32.h" #include "REX/W32/USER32.h" #include -namespace REX +namespace REX::Impl { - void LOG(const std::source_location a_loc, const LOG_LEVEL a_level, const std::string_view a_fmt) + void Log(const std::source_location a_loc, const ELogLevel a_level, const std::string_view a_fmt) { const auto loc = spdlog::source_loc{ a_loc.file_name(), static_cast(a_loc.line()), a_loc.function_name() }; switch (a_level) { - case LOG_LEVEL::TRACE: + case ELogLevel::Trace: spdlog::default_logger_raw()->log(loc, spdlog::level::trace, a_fmt); break; - case LOG_LEVEL::DEBUG: + case ELogLevel::Debug: spdlog::default_logger_raw()->log(loc, spdlog::level::debug, a_fmt); break; - case LOG_LEVEL::INFO: + case ELogLevel::Info: spdlog::default_logger_raw()->log(loc, spdlog::level::info, a_fmt); break; - case LOG_LEVEL::WARN: + case ELogLevel::Warning: spdlog::default_logger_raw()->log(loc, spdlog::level::warn, a_fmt); break; - case LOG_LEVEL::ERROR: + case ELogLevel::Error: spdlog::default_logger_raw()->log(loc, spdlog::level::err, a_fmt); break; - case LOG_LEVEL::CRITICAL: + case ELogLevel::Critical: spdlog::default_logger_raw()->log(loc, spdlog::level::critical, a_fmt); break; } } - void LOG(const std::source_location a_loc, const LOG_LEVEL a_level, const std::wstring_view a_fmt) + void Log(const std::source_location a_loc, const ELogLevel a_level, const std::wstring_view a_fmt) { const auto loc = spdlog::source_loc{ a_loc.file_name(), static_cast(a_loc.line()), a_loc.function_name() }; switch (a_level) { - case LOG_LEVEL::TRACE: + case ELogLevel::Trace: spdlog::default_logger_raw()->log(loc, spdlog::level::trace, a_fmt); break; - case LOG_LEVEL::DEBUG: + case ELogLevel::Debug: spdlog::default_logger_raw()->log(loc, spdlog::level::debug, a_fmt); break; - case LOG_LEVEL::INFO: + case ELogLevel::Info: spdlog::default_logger_raw()->log(loc, spdlog::level::info, a_fmt); break; - case LOG_LEVEL::WARN: + case ELogLevel::Warning: spdlog::default_logger_raw()->log(loc, spdlog::level::warn, a_fmt); break; - case LOG_LEVEL::ERROR: + case ELogLevel::Error: spdlog::default_logger_raw()->log(loc, spdlog::level::err, a_fmt); break; - case LOG_LEVEL::CRITICAL: + case ELogLevel::Critical: spdlog::default_logger_raw()->log(loc, spdlog::level::critical, a_fmt); break; } } } -namespace REX::IMPL +namespace REX::Impl { - void FAIL(const std::source_location a_loc, const std::string_view a_fmt) + void Fail(const std::source_location a_loc, const std::string_view a_fmt) { const auto body = [&]() { constexpr std::array directories{ @@ -111,12 +111,12 @@ namespace REX::IMPL } }(); - LOG(a_loc, LOG_LEVEL::CRITICAL, a_fmt); + Log(a_loc, ELogLevel::Critical, a_fmt); REX::W32::MessageBoxA(nullptr, body.c_str(), (caption.empty() ? nullptr : caption.c_str()), 0); REX::W32::TerminateProcess(REX::W32::GetCurrentProcess(), 1); } - void FAIL(const std::source_location a_loc, const std::wstring_view a_fmt) + void Fail(const std::source_location a_loc, const std::wstring_view a_fmt) { const auto body = [&]() { constexpr std::array directories{ @@ -167,7 +167,7 @@ namespace REX::IMPL } }(); - LOG(a_loc, LOG_LEVEL::CRITICAL, a_fmt); + Log(a_loc, ELogLevel::Critical, a_fmt); REX::W32::MessageBoxW(nullptr, body.c_str(), (caption.empty() ? nullptr : caption.c_str()), 0); REX::W32::TerminateProcess(REX::W32::GetCurrentProcess(), 1); } diff --git a/src/REX/REX/INI.cpp b/src/REX/REX/INI.cpp deleted file mode 100644 index be080bc..0000000 --- a/src/REX/REX/INI.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include "REX/REX/INI.h" - -#ifdef COMMONLIB_OPTION_INI -# include -# undef ERROR - -namespace REX::INI -{ - namespace Impl - { - template - constexpr bool is_long_integral_v = std::_Is_any_of_v, std::uint8_t, std::uint16_t, std::uint32_t, std::int8_t, std::int16_t, std::int32_t>; - - template - void SettingLoad( - void* a_data, - sec_t a_section, - key_t a_key, - T& a_value, - T& a_valueDefault) - { - const auto file = static_cast(a_data); - if constexpr (std::is_same_v) { - a_value = file->GetBoolValue(a_section.data(), a_key.data(), a_valueDefault); - } else if constexpr (std::is_floating_point_v) { - a_value = static_cast(file->GetDoubleValue(a_section.data(), a_key.data(), a_valueDefault)); - } else if constexpr (is_long_integral_v) { - a_value = static_cast(file->GetLongValue(a_section.data(), a_key.data(), a_valueDefault)); - } else if constexpr (std::is_same_v) { - a_value = file->GetValue(a_section.data(), a_key.data(), a_valueDefault.c_str()); - } - } - - template void SettingLoad(void*, sec_t, key_t, bool&, bool&); - template void SettingLoad(void*, sec_t, key_t, float&, float&); - template void SettingLoad(void*, sec_t, key_t, double&, double&); - template void SettingLoad(void*, sec_t, key_t, std::uint8_t&, std::uint8_t&); - template void SettingLoad(void*, sec_t, key_t, std::uint16_t&, std::uint16_t&); - template void SettingLoad(void*, sec_t, key_t, std::uint32_t&, std::uint32_t&); - template void SettingLoad(void*, sec_t, key_t, std::int8_t&, std::int8_t&); - template void SettingLoad(void*, sec_t, key_t, std::int16_t&, std::int16_t&); - template void SettingLoad(void*, sec_t, key_t, std::int32_t&, std::int32_t&); - template void SettingLoad(void*, sec_t, key_t, std::string&, std::string&); - - template - void SettingSave( - void* a_data, - sec_t a_section, - key_t a_key, - T& a_value) - { - auto& file = *static_cast(a_data); - if constexpr (std::is_same_v) { - file.SetBoolValue(a_section.data(), a_key.data(), a_value); - } else if constexpr (std::is_floating_point_v) { - file.SetDoubleValue(a_section.data(), a_key.data(), a_value); - } else if constexpr (is_long_integral_v) { - file.SetLongValue(a_section.data(), a_key.data(), a_value); - } else if constexpr (std::is_same_v) { - file.SetValue(a_section.data(), a_key.data(), a_value.c_str()); - } - } - - template void SettingSave(void*, sec_t, key_t, bool&); - template void SettingSave(void*, sec_t, key_t, float&); - template void SettingSave(void*, sec_t, key_t, double&); - template void SettingSave(void*, sec_t, key_t, std::uint8_t&); - template void SettingSave(void*, sec_t, key_t, std::uint16_t&); - template void SettingSave(void*, sec_t, key_t, std::uint32_t&); - template void SettingSave(void*, sec_t, key_t, std::int8_t&); - template void SettingSave(void*, sec_t, key_t, std::int16_t&); - template void SettingSave(void*, sec_t, key_t, std::int32_t&); - template void SettingSave(void*, sec_t, key_t, std::string&); - } - - void SettingStore::Load() - { - CSimpleIniA file; - file.SetUnicode(true); - file.SetQuotes(true); - - if (std::filesystem::exists(m_fileBase)) { - file.LoadFile(m_fileBase.data()); - for (auto& setting : m_settings) { - setting->Load(&file, true); - } - } - - if (std::filesystem::exists(m_fileUser)) { - file.LoadFile(m_fileUser.data()); - for (auto& setting : m_settings) { - setting->Load(&file, false); - } - } - } - - void SettingStore::Save() - { - CSimpleIniA file; - file.SetUnicode(true); - file.SetQuotes(true); - - file.LoadFile(m_fileBase.data()); - for (auto& setting : m_settings) { - setting->Save(&file); - } - - file.SaveFile(m_fileBase.data()); - } -} -#endif diff --git a/src/REX/REX/JSON.cpp b/src/REX/REX/JSON.cpp deleted file mode 100644 index 13f5daa..0000000 --- a/src/REX/REX/JSON.cpp +++ /dev/null @@ -1,125 +0,0 @@ -#include "REX/REX/JSON.h" - -#ifdef COMMONLIB_OPTION_JSON -# include - -namespace REX::JSON -{ - namespace Impl - { - template - void SettingLoad( - void* a_data, - path_t a_path, - T& a_value, - T& a_valueDefault) - { - const auto& json = *static_cast(a_data); - if (a_path[0] != '/') { - const auto path = std::format("/{}"sv, a_path); - a_value = glz::get(json, path).value_or(a_valueDefault); - } else { - a_value = glz::get(json, a_path).value_or(a_valueDefault); - } - } - - template void SettingLoad(void*, path_t, bool&, bool&); - template void SettingLoad(void*, path_t, float&, float&); - template void SettingLoad(void*, path_t, double&, double&); - template void SettingLoad(void*, path_t, std::uint8_t&, std::uint8_t&); - template void SettingLoad(void*, path_t, std::uint16_t&, std::uint16_t&); - template void SettingLoad(void*, path_t, std::uint32_t&, std::uint32_t&); - template void SettingLoad(void*, path_t, std::int8_t&, std::int8_t&); - template void SettingLoad(void*, path_t, std::int16_t&, std::int16_t&); - template void SettingLoad(void*, path_t, std::int32_t&, std::int32_t&); - template void SettingLoad(void*, path_t, std::string&, std::string&); - template void SettingLoad>(void*, path_t, std::vector&, std::vector&); - template void SettingLoad>(void*, path_t, std::vector&, std::vector&); - template void SettingLoad>(void*, path_t, std::vector&, std::vector&); - template void SettingLoad>(void*, path_t, std::vector&, std::vector&); - template void SettingLoad>(void*, path_t, std::vector&, std::vector&); - template void SettingLoad>(void*, path_t, std::vector&, std::vector&); - template void SettingLoad>(void*, path_t, std::vector&, std::vector&); - template void SettingLoad>(void*, path_t, std::vector&, std::vector&); - template void SettingLoad>(void*, path_t, std::vector&, std::vector&); - template void SettingLoad>(void*, path_t, std::vector&, std::vector&); - - template - void SettingSave( - void* a_data, - path_t a_path, - T& a_value) - { - auto& json = *static_cast(a_data); - if (a_path[0] != '/') { - const auto path = std::format("/{}"sv, a_path); - glz::set(json, path, a_value); - } else { - glz::set(json, a_path, a_value); - } - } - - template void SettingSave(void*, path_t, bool&); - template void SettingSave(void*, path_t, float&); - template void SettingSave(void*, path_t, double&); - template void SettingSave(void*, path_t, std::uint8_t&); - template void SettingSave(void*, path_t, std::uint16_t&); - template void SettingSave(void*, path_t, std::uint32_t&); - template void SettingSave(void*, path_t, std::int8_t&); - template void SettingSave(void*, path_t, std::int16_t&); - template void SettingSave(void*, path_t, std::int32_t&); - template void SettingSave(void*, path_t, std::string&); - template void SettingSave>(void*, path_t, std::vector&); - template void SettingSave>(void*, path_t, std::vector&); - template void SettingSave>(void*, path_t, std::vector&); - template void SettingSave>(void*, path_t, std::vector&); - template void SettingSave>(void*, path_t, std::vector&); - template void SettingSave>(void*, path_t, std::vector&); - template void SettingSave>(void*, path_t, std::vector&); - template void SettingSave>(void*, path_t, std::vector&); - template void SettingSave>(void*, path_t, std::vector&); - template void SettingSave>(void*, path_t, std::vector&); - } - - void SettingStore::Load() - { - if (std::filesystem::exists(m_fileBase)) { - glz::generic result{}; - if (!glz::read_file_json(result, m_fileBase, std::string{})) { - for (auto setting : m_settings) { - setting->Load(&result, true); - } - } - } - - if (std::filesystem::exists(m_fileUser)) { - glz::generic result{}; - if (!glz::read_file_json(result, m_fileUser, std::string{})) { - for (auto setting : m_settings) { - setting->Load(&result, false); - } - } - } - } - - struct save_opts : glz::opts - { - static constexpr bool prettify = true; - std::uint8_t indentation_width = 4; - }; - - void SettingStore::Save() - { - glz::generic output{}; - if (std::filesystem::exists(m_fileBase)) { - (void)glz::read_file_json(output, m_fileBase, std::string{}); - } - - for (auto& setting : m_settings) { - setting->Save(&output); - } - - (void)glz::write_file_json(output, m_fileBase, std::string{}); - } -} -#endif diff --git a/src/REX/REX/TOML.cpp b/src/REX/REX/TOML.cpp deleted file mode 100644 index bdfca3b..0000000 --- a/src/REX/REX/TOML.cpp +++ /dev/null @@ -1,158 +0,0 @@ -#include "REX/REX/TOML.h" - -#ifdef COMMONLIB_OPTION_TOML -# include - -namespace REX::TOML -{ - namespace Impl - { - static toml::value* recurse_table(toml::value* a_result, toml::value& a_value, const std::string& a_section, bool a_create) - { - if (a_result && a_result->is_table()) { - for (auto& value : a_result->as_table()) { - if (value.first == a_section) { - return std::addressof(value.second); - } - } - if (a_create) { - (*a_result)[a_section] = toml::table{}; - return std::addressof((*a_result)[a_section]); - } - } else if (a_value.is_table()) { - for (auto& value : a_value.as_table()) { - if (value.first == a_section) { - return std::addressof(value.second); - } - } - if (a_create) { - a_value[a_section] = toml::table{}; - return std::addressof(a_value[a_section]); - } - } - return a_result; - } - - static bool recurse_mark_implicit(toml::value& a_value) - { - for (auto& kv : a_value.as_table()) { - if (kv.second.is_table()) { - if (!recurse_mark_implicit(kv.second)) { - continue; - } - kv.second.as_table_fmt().fmt = toml::table_format::implicit; - } else { - return false; - } - } - return true; - } - - template - void SettingLoad( - void* a_data, - sec_t a_section, - key_t a_key, - T& a_value, - T& a_valueDefault) - { - const auto& data = static_cast(a_data); - if (a_section.empty()) { - auto& path = (*data); - a_value = toml::find_or(path, a_key.data(), a_valueDefault); - return; - } else if (a_section.size() == 1) { - auto& path = (*data)[a_section.front()]; - a_value = toml::find_or(path, a_key.data(), a_valueDefault); - return; - } else { - toml::value* path{ nullptr }; - for (auto& section : a_section) { - path = recurse_table(path, *data, section, false); - } - if (path) { - a_value = toml::find_or(*path, a_key.data(), a_valueDefault); - return; - } - } - a_value = a_valueDefault; - } - - template void SettingLoad(void*, sec_t, key_t, bool&, bool&); - template void SettingLoad(void*, sec_t, key_t, float&, float&); - template void SettingLoad(void*, sec_t, key_t, double&, double&); - template void SettingLoad(void*, sec_t, key_t, std::uint8_t&, std::uint8_t&); - template void SettingLoad(void*, sec_t, key_t, std::uint16_t&, std::uint16_t&); - template void SettingLoad(void*, sec_t, key_t, std::uint32_t&, std::uint32_t&); - template void SettingLoad(void*, sec_t, key_t, std::int8_t&, std::int8_t&); - template void SettingLoad(void*, sec_t, key_t, std::int16_t&, std::int16_t&); - template void SettingLoad(void*, sec_t, key_t, std::int32_t&, std::int32_t&); - template void SettingLoad(void*, sec_t, key_t, std::string&, std::string&); - - template - void SettingSave( - void* a_data, - sec_t a_section, - key_t a_key, - T& a_value) - { - auto& data = *static_cast(a_data); - if (a_section.empty()) { - data[a_key.data()] = a_value; - } else if (a_section.size() == 1) { - data[a_section.front()][a_key.data()] = a_value; - } else { - toml::value* path{ nullptr }; - for (auto& section : a_section) { - path = recurse_table(path, data, section, true); - } - if (path) { - (*path)[a_key.data()] = a_value; - } - } - } - - template void SettingSave(void*, sec_t, key_t, bool&); - template void SettingSave(void*, sec_t, key_t, float&); - template void SettingSave(void*, sec_t, key_t, double&); - template void SettingSave(void*, sec_t, key_t, std::uint8_t&); - template void SettingSave(void*, sec_t, key_t, std::uint16_t&); - template void SettingSave(void*, sec_t, key_t, std::uint32_t&); - template void SettingSave(void*, sec_t, key_t, std::int8_t&); - template void SettingSave(void*, sec_t, key_t, std::int16_t&); - template void SettingSave(void*, sec_t, key_t, std::int32_t&); - template void SettingSave(void*, sec_t, key_t, std::string&); - } - - void SettingStore::Load() - { - if (auto result = toml::try_parse(m_fileBase.data()); result.is_ok()) { - for (auto& setting : m_settings) { - setting->Load(&result.unwrap(), true); - } - } - - if (auto result = toml::try_parse(m_fileUser.data()); result.is_ok()) { - for (auto& setting : m_settings) { - setting->Load(&result.unwrap(), false); - } - } - } - - void SettingStore::Save() - { - toml::value output{}; - if (auto result = toml::try_parse(m_fileBase.data()); result.is_ok()) { - output = result.unwrap(); - } - - for (auto setting : m_settings) { - setting->Save(&output); - } - - Impl::recurse_mark_implicit(output); - std::ofstream file{ m_fileBase.data(), std::ios::trunc }; - file << toml::format(output); - } -} -#endif diff --git a/src/REX/TIniSetting.cpp b/src/REX/TIniSetting.cpp new file mode 100644 index 0000000..4f68412 --- /dev/null +++ b/src/REX/TIniSetting.cpp @@ -0,0 +1,74 @@ +#ifdef COMMONLIB_OPTION_INI + +# include "REX/TIniSetting.h" + +# include +# undef ERROR + +namespace REX::Impl +{ + template + constexpr bool is_long_integral_v = std::_Is_any_of_v, std::uint8_t, std::uint16_t, std::uint32_t, std::int8_t, std::int16_t, std::int32_t>; + + template + void IniSettingLoad( + void* a_data, + std::string_view a_section, + std::string_view a_key, + T& a_value, + T& a_valueDefault) + { + const auto file = static_cast(a_data); + if constexpr (std::is_same_v) { + a_value = file->GetBoolValue(a_section.data(), a_key.data(), a_valueDefault); + } else if constexpr (std::is_floating_point_v) { + a_value = static_cast(file->GetDoubleValue(a_section.data(), a_key.data(), a_valueDefault)); + } else if constexpr (is_long_integral_v) { + a_value = static_cast(file->GetLongValue(a_section.data(), a_key.data(), a_valueDefault)); + } else if constexpr (std::is_same_v) { + a_value = file->GetValue(a_section.data(), a_key.data(), a_valueDefault.c_str()); + } + } + + template void IniSettingLoad(void*, std::string_view, std::string_view, bool&, bool&); + template void IniSettingLoad(void*, std::string_view, std::string_view, float&, float&); + template void IniSettingLoad(void*, std::string_view, std::string_view, double&, double&); + template void IniSettingLoad(void*, std::string_view, std::string_view, std::uint8_t&, std::uint8_t&); + template void IniSettingLoad(void*, std::string_view, std::string_view, std::uint16_t&, std::uint16_t&); + template void IniSettingLoad(void*, std::string_view, std::string_view, std::uint32_t&, std::uint32_t&); + template void IniSettingLoad(void*, std::string_view, std::string_view, std::int8_t&, std::int8_t&); + template void IniSettingLoad(void*, std::string_view, std::string_view, std::int16_t&, std::int16_t&); + template void IniSettingLoad(void*, std::string_view, std::string_view, std::int32_t&, std::int32_t&); + template void IniSettingLoad(void*, std::string_view, std::string_view, std::string&, std::string&); + + template + void IniSettingSave( + void* a_data, + std::string_view a_section, + std::string_view a_key, + T& a_value) + { + auto& file = *static_cast(a_data); + if constexpr (std::is_same_v) { + file.SetBoolValue(a_section.data(), a_key.data(), a_value); + } else if constexpr (std::is_floating_point_v) { + file.SetDoubleValue(a_section.data(), a_key.data(), a_value); + } else if constexpr (is_long_integral_v) { + file.SetLongValue(a_section.data(), a_key.data(), a_value); + } else if constexpr (std::is_same_v) { + file.SetValue(a_section.data(), a_key.data(), a_value.c_str()); + } + } + + template void IniSettingSave(void*, std::string_view, std::string_view, bool&); + template void IniSettingSave(void*, std::string_view, std::string_view, float&); + template void IniSettingSave(void*, std::string_view, std::string_view, double&); + template void IniSettingSave(void*, std::string_view, std::string_view, std::uint8_t&); + template void IniSettingSave(void*, std::string_view, std::string_view, std::uint16_t&); + template void IniSettingSave(void*, std::string_view, std::string_view, std::uint32_t&); + template void IniSettingSave(void*, std::string_view, std::string_view, std::int8_t&); + template void IniSettingSave(void*, std::string_view, std::string_view, std::int16_t&); + template void IniSettingSave(void*, std::string_view, std::string_view, std::int32_t&); + template void IniSettingSave(void*, std::string_view, std::string_view, std::string&); +} +#endif diff --git a/src/REX/TJsonSetting.cpp b/src/REX/TJsonSetting.cpp new file mode 100644 index 0000000..6ed603f --- /dev/null +++ b/src/REX/TJsonSetting.cpp @@ -0,0 +1,83 @@ +#ifdef COMMONLIB_OPTION_JSON + +# include "REX/TJsonSetting.h" + +# include + +namespace REX::Impl +{ + template + void JsonSettingLoad( + void* a_data, + std::string_view a_path, + T& a_value, + T& a_valueDefault) + { + const auto& json = *static_cast(a_data); + if (a_path[0] != '/') { + const auto path = std::format("/{}"sv, a_path); + a_value = glz::get(json, path).value_or(a_valueDefault); + } else { + a_value = glz::get(json, a_path).value_or(a_valueDefault); + } + } + + template void JsonSettingLoad(void*, std::string_view, bool&, bool&); + //template void JsonSettingLoad(void*, std::string_view, float&, float&); + template void JsonSettingLoad(void*, std::string_view, double&, double&); + template void JsonSettingLoad(void*, std::string_view, std::uint8_t&, std::uint8_t&); + template void JsonSettingLoad(void*, std::string_view, std::uint16_t&, std::uint16_t&); + template void JsonSettingLoad(void*, std::string_view, std::uint32_t&, std::uint32_t&); + template void JsonSettingLoad(void*, std::string_view, std::int8_t&, std::int8_t&); + template void JsonSettingLoad(void*, std::string_view, std::int16_t&, std::int16_t&); + template void JsonSettingLoad(void*, std::string_view, std::int32_t&, std::int32_t&); + template void JsonSettingLoad(void*, std::string_view, std::string&, std::string&); + template void JsonSettingLoad>(void*, std::string_view, std::vector&, std::vector&); + //template void JsonSettingLoad>(void*, std::string_view, std::vector&, std::vector&); + template void JsonSettingLoad>(void*, std::string_view, std::vector&, std::vector&); + template void JsonSettingLoad>(void*, std::string_view, std::vector&, std::vector&); + template void JsonSettingLoad>(void*, std::string_view, std::vector&, std::vector&); + template void JsonSettingLoad>(void*, std::string_view, std::vector&, std::vector&); + template void JsonSettingLoad>(void*, std::string_view, std::vector&, std::vector&); + template void JsonSettingLoad>(void*, std::string_view, std::vector&, std::vector&); + template void JsonSettingLoad>(void*, std::string_view, std::vector&, std::vector&); + template void JsonSettingLoad>(void*, std::string_view, std::vector&, std::vector&); + + template + void JsonSettingSave( + void* a_data, + std::string_view a_path, + T& a_value) + { + auto& json = *static_cast(a_data); + if (a_path[0] != '/') { + const auto path = std::format("/{}"sv, a_path); + glz::set(json, path, a_value); + } else { + glz::set(json, a_path, a_value); + } + } + + template void JsonSettingSave(void*, std::string_view, bool&); + //template void JsonSettingSave(void*, std::string_view, float&); + template void JsonSettingSave(void*, std::string_view, double&); + template void JsonSettingSave(void*, std::string_view, std::uint8_t&); + template void JsonSettingSave(void*, std::string_view, std::uint16_t&); + template void JsonSettingSave(void*, std::string_view, std::uint32_t&); + template void JsonSettingSave(void*, std::string_view, std::int8_t&); + template void JsonSettingSave(void*, std::string_view, std::int16_t&); + template void JsonSettingSave(void*, std::string_view, std::int32_t&); + template void JsonSettingSave(void*, std::string_view, std::string&); + template void JsonSettingSave>(void*, std::string_view, std::vector&); + //template void JsonSettingSave>(void*, std::string_view, std::vector&); + template void JsonSettingSave>(void*, std::string_view, std::vector&); + template void JsonSettingSave>(void*, std::string_view, std::vector&); + template void JsonSettingSave>(void*, std::string_view, std::vector&); + template void JsonSettingSave>(void*, std::string_view, std::vector&); + template void JsonSettingSave>(void*, std::string_view, std::vector&); + template void JsonSettingSave>(void*, std::string_view, std::vector&); + template void JsonSettingSave>(void*, std::string_view, std::vector&); + template void JsonSettingSave>(void*, std::string_view, std::vector&); +} + +#endif diff --git a/src/REX/TTomlSetting.cpp b/src/REX/TTomlSetting.cpp new file mode 100644 index 0000000..adfeebe --- /dev/null +++ b/src/REX/TTomlSetting.cpp @@ -0,0 +1,110 @@ +#ifdef COMMONLIB_OPTION_TOML + +# include "REX/TTomlSetting.h" + +# include + +toml::value* toml_recurse_table(toml::value* a_result, toml::value& a_value, const std::string& a_section, bool a_create) +{ + if (a_result && a_result->is_table()) { + for (auto& value : a_result->as_table()) { + if (value.first == a_section) { + return std::addressof(value.second); + } + } + if (a_create) { + (*a_result)[a_section] = toml::table{}; + return std::addressof((*a_result)[a_section]); + } + } else if (a_value.is_table()) { + for (auto& value : a_value.as_table()) { + if (value.first == a_section) { + return std::addressof(value.second); + } + } + if (a_create) { + a_value[a_section] = toml::table{}; + return std::addressof(a_value[a_section]); + } + } + return a_result; +} + +namespace REX::Impl +{ + template + void TomlSettingLoad( + void* a_data, + std::vector a_section, + std::string_view a_key, + T& a_value, + T& a_valueDefault) + { + const auto& data = static_cast(a_data); + if (a_section.empty()) { + auto& path = (*data); + a_value = toml::find_or(path, a_key.data(), a_valueDefault); + return; + } else if (a_section.size() == 1) { + auto& path = (*data)[a_section.front()]; + a_value = toml::find_or(path, a_key.data(), a_valueDefault); + return; + } else { + toml::value* path{ nullptr }; + for (auto& section : a_section) { + path = toml_recurse_table(path, *data, section, false); + } + if (path) { + a_value = toml::find_or(*path, a_key.data(), a_valueDefault); + return; + } + } + a_value = a_valueDefault; + } + + template void TomlSettingLoad(void*, std::vector, std::string_view, bool&, bool&); + template void TomlSettingLoad(void*, std::vector, std::string_view, float&, float&); + template void TomlSettingLoad(void*, std::vector, std::string_view, double&, double&); + template void TomlSettingLoad(void*, std::vector, std::string_view, std::uint8_t&, std::uint8_t&); + template void TomlSettingLoad(void*, std::vector, std::string_view, std::uint16_t&, std::uint16_t&); + template void TomlSettingLoad(void*, std::vector, std::string_view, std::uint32_t&, std::uint32_t&); + template void TomlSettingLoad(void*, std::vector, std::string_view, std::int8_t&, std::int8_t&); + template void TomlSettingLoad(void*, std::vector, std::string_view, std::int16_t&, std::int16_t&); + template void TomlSettingLoad(void*, std::vector, std::string_view, std::int32_t&, std::int32_t&); + template void TomlSettingLoad(void*, std::vector, std::string_view, std::string&, std::string&); + + template + void TomlSettingSave( + void* a_data, + std::vector a_section, + std::string_view a_key, + T& a_value) + { + auto& data = *static_cast(a_data); + if (a_section.empty()) { + data[a_key.data()] = a_value; + } else if (a_section.size() == 1) { + data[a_section.front()][a_key.data()] = a_value; + } else { + toml::value* path{ nullptr }; + for (auto& section : a_section) { + path = toml_recurse_table(path, data, section, true); + } + if (path) { + (*path)[a_key.data()] = a_value; + } + } + } + + template void TomlSettingSave(void*, std::vector, std::string_view, bool&); + template void TomlSettingSave(void*, std::vector, std::string_view, float&); + template void TomlSettingSave(void*, std::vector, std::string_view, double&); + template void TomlSettingSave(void*, std::vector, std::string_view, std::uint8_t&); + template void TomlSettingSave(void*, std::vector, std::string_view, std::uint16_t&); + template void TomlSettingSave(void*, std::vector, std::string_view, std::uint32_t&); + template void TomlSettingSave(void*, std::vector, std::string_view, std::int8_t&); + template void TomlSettingSave(void*, std::vector, std::string_view, std::int16_t&); + template void TomlSettingSave(void*, std::vector, std::string_view, std::int32_t&); + template void TomlSettingSave(void*, std::vector, std::string_view, std::string&); +} +#endif