/* * This file is part of the CitizenFX project - http://citizen.re/ * * See LICENSE and MENTIONS in the root of the source tree for information * regarding licensing. */ #pragma once #include #include #include #pragma warning(push) #pragma warning(disable:4201) namespace hook { class pattern_match { private: void* m_pointer; public: inline pattern_match(void* pointer) : m_pointer(pointer) { } template T* get(ptrdiff_t offset = 0) const { char* ptr = reinterpret_cast(m_pointer); return reinterpret_cast(ptr + offset); } }; class pattern { private: std::basic_string m_bytes; std::basic_string m_mask; #if PATTERNS_USE_HINTS uint64_t m_hash; #endif std::vector m_matches; bool m_matched = false; uintptr_t m_rangeStart; uintptr_t m_rangeEnd; private: static ptrdiff_t get_process_base(); void Initialize(std::string_view pattern); bool ConsiderHint(uintptr_t offset); void EnsureMatches(uint32_t maxCount); inline pattern_match _get_internal(size_t index) const { return m_matches[index]; } inline pattern(uintptr_t module) : pattern( module, 0 ) { } inline pattern(uintptr_t begin, uintptr_t end) : m_rangeStart(begin), m_rangeEnd(end) { } public: pattern(std::string_view pattern) : pattern(get_process_base()) { Initialize(std::move(pattern)); } inline pattern(void* module, std::string_view pattern) : pattern(reinterpret_cast(module)) { Initialize(std::move(pattern)); } inline pattern(uintptr_t begin, uintptr_t end, std::string_view pattern) : m_rangeStart(begin), m_rangeEnd(end) { Initialize(std::move(pattern)); } inline pattern&& count(uint32_t expected) { EnsureMatches(expected); assert(m_matches.size() == expected); return std::forward(*this); } inline pattern&& count_hint(uint32_t expected) { EnsureMatches(expected); return std::forward(*this); } inline pattern&& clear() { m_matches.clear(); m_matched = false; return std::forward(*this); } inline size_t size() { EnsureMatches(UINT32_MAX); return m_matches.size(); } inline bool empty() { return size() == 0; } inline pattern_match get(size_t index) { EnsureMatches(UINT32_MAX); return _get_internal(index); } inline pattern_match get_one() { return std::forward(*this).count(1)._get_internal(0); } template inline auto get_first(ptrdiff_t offset = 0) { return get_one().get(offset); } template inline Pred for_each_result(Pred&& pred) { EnsureMatches(UINT32_MAX); for ( auto it : m_matches ) { std::forward(pred)(it); } return std::forward(pred); } public: #if PATTERNS_USE_HINTS && PATTERNS_CAN_SERIALIZE_HINTS // define a hint static void hint(uint64_t hash, uintptr_t address); #endif }; inline pattern make_module_pattern(void* module, std::string_view bytes) { return pattern(module, std::move(bytes)); } inline pattern make_range_pattern(uintptr_t begin, uintptr_t end, std::string_view bytes) { return pattern(begin, end, std::move(bytes)); } template inline auto get_pattern(std::string_view pattern_string, ptrdiff_t offset = 0) { return pattern(std::move(pattern_string)).get_first(offset); } } #pragma warning(pop)