219 lines
5.2 KiB
C++
219 lines
5.2 KiB
C++
#pragma once
|
|
|
|
namespace RE
|
|
{
|
|
namespace msvc
|
|
{
|
|
class type_info;
|
|
}
|
|
|
|
namespace RTTI
|
|
{
|
|
template <class T>
|
|
class RVA
|
|
{
|
|
public:
|
|
using value_type = T;
|
|
using pointer = value_type*;
|
|
using reference = value_type&;
|
|
|
|
constexpr RVA() noexcept = default;
|
|
|
|
constexpr RVA(std::uint32_t a_rva) noexcept :
|
|
_rva(a_rva)
|
|
{}
|
|
|
|
[[nodiscard]] pointer get() const { return is_good() ? REL::Relocation<T*>{ REL::Offset(_rva) }.get() : nullptr; }
|
|
[[nodiscard]] std::uint32_t offset() const noexcept { return _rva; }
|
|
[[nodiscard]] reference operator*() const { return *get(); }
|
|
[[nodiscard]] pointer operator->() const { return get(); }
|
|
[[nodiscard]] explicit constexpr operator bool() const noexcept { return is_good(); }
|
|
|
|
protected:
|
|
[[nodiscard]] constexpr bool is_good() const noexcept { return _rva != 0; }
|
|
|
|
// members
|
|
std::uint32_t _rva{ 0 }; // 00
|
|
};
|
|
static_assert(sizeof(RVA<void*>) == 0x4);
|
|
|
|
using TypeDescriptor = std::type_info;
|
|
|
|
class PMD
|
|
{
|
|
public:
|
|
// members
|
|
std::int32_t mDisp; // 0
|
|
std::int32_t pDisp; // 4
|
|
std::int32_t vDisp; // 8
|
|
};
|
|
static_assert(sizeof(PMD) == 0xC);
|
|
|
|
class BaseClassDescriptor
|
|
{
|
|
public:
|
|
enum class Attribute : std::uint32_t
|
|
{
|
|
kNone = 0,
|
|
kNotVisible = 1 << 0,
|
|
kAmbiguous = 1 << 1,
|
|
kPrivate = 1 << 2,
|
|
kPrivateOrProtectedBase = 1 << 3,
|
|
kVirtual = 1 << 4,
|
|
kNonPolymorphic = 1 << 5,
|
|
kHasHierarchyDescriptor = 1 << 6
|
|
};
|
|
|
|
// members
|
|
RVA<TypeDescriptor> typeDescriptor; // 00
|
|
std::uint32_t numContainedBases; // 04
|
|
PMD pmd; // 08
|
|
REX::TEnumSet<Attribute, std::uint32_t> attributes; // 14
|
|
};
|
|
static_assert(sizeof(BaseClassDescriptor) == 0x18);
|
|
|
|
class ClassHierarchyDescriptor
|
|
{
|
|
public:
|
|
enum class Attribute
|
|
{
|
|
kNoInheritance = 0,
|
|
kMultipleInheritance = 1 << 0,
|
|
kVirtualInheritance = 1 << 1,
|
|
kAmbiguousInheritance = 1 << 2
|
|
};
|
|
|
|
// members
|
|
std::uint32_t signature; // 00
|
|
REX::TEnumSet<Attribute, std::uint32_t> attributes; // 04
|
|
std::uint32_t numBaseClasses; // 08
|
|
RVA<BaseClassDescriptor> baseClassArray; // 0C
|
|
};
|
|
static_assert(sizeof(ClassHierarchyDescriptor) == 0x10);
|
|
|
|
class CompleteObjectLocator
|
|
{
|
|
public:
|
|
enum class Signature
|
|
{
|
|
x86 = 0,
|
|
x64 = 1
|
|
};
|
|
|
|
// members
|
|
REX::TEnumSet<Signature, std::uint32_t> signature; // 00
|
|
std::uint32_t offset; // 04
|
|
std::uint32_t ctorDispOffset; // 08
|
|
RVA<TypeDescriptor> typeDescriptor; // 0C
|
|
RVA<ClassHierarchyDescriptor> classDescriptor; // 10
|
|
};
|
|
static_assert(sizeof(CompleteObjectLocator) == 0x14);
|
|
}
|
|
|
|
inline void* RTDynamicCast(void* a_inptr, std::int32_t a_vfDelta, void* a_srcType, void* a_targetType, std::int32_t a_isReference)
|
|
{
|
|
using func_t = decltype(&RTDynamicCast);
|
|
static REL::Relocation<func_t> func{ ID::RTDynamicCast };
|
|
return func(a_inptr, a_vfDelta, a_srcType, a_targetType, a_isReference);
|
|
}
|
|
|
|
namespace detail
|
|
{
|
|
template <class T>
|
|
using remove_cvpr_t =
|
|
std::remove_cv_t<
|
|
std::remove_pointer_t<
|
|
std::remove_reference_t<T>>>;
|
|
|
|
template <class T>
|
|
struct target_is_valid :
|
|
std::disjunction<
|
|
std::is_polymorphic<
|
|
remove_cvpr_t<T>>,
|
|
std::is_same<
|
|
void*,
|
|
std::remove_cv_t<T>>>
|
|
{};
|
|
|
|
template <class, class>
|
|
struct types_are_compat :
|
|
std::false_type
|
|
{};
|
|
|
|
template <class To, class From>
|
|
struct types_are_compat<To, From*> :
|
|
std::is_pointer<To>
|
|
{};
|
|
|
|
template <class To, class From>
|
|
struct types_are_compat<To, const From*> :
|
|
std::conjunction<
|
|
std::is_pointer<To>,
|
|
std::is_const<
|
|
std::remove_pointer_t<To>>>
|
|
{};
|
|
|
|
template <class To, class From>
|
|
struct types_are_compat<To, volatile From*> :
|
|
std::conjunction<
|
|
std::is_pointer<To>,
|
|
std::is_volatile<
|
|
std::remove_pointer_t<To>>>
|
|
{};
|
|
|
|
template <class To, class From>
|
|
struct types_are_compat<To, const volatile From*> :
|
|
std::conjunction<
|
|
std::is_pointer<To>,
|
|
std::is_const<
|
|
std::remove_pointer_t<To>>,
|
|
std::is_volatile<
|
|
std::remove_pointer_t<To>>>
|
|
{};
|
|
|
|
template <class, class = void>
|
|
struct implements_rtti :
|
|
std::false_type
|
|
{};
|
|
|
|
template <class T>
|
|
struct implements_rtti<
|
|
T,
|
|
std::void_t<
|
|
decltype(remove_cvpr_t<T>::RTTI)>> :
|
|
std::true_type
|
|
{};
|
|
|
|
template <class To, class From>
|
|
struct cast_is_valid :
|
|
std::conjunction<
|
|
types_are_compat<
|
|
To,
|
|
From>,
|
|
target_is_valid<
|
|
To>,
|
|
implements_rtti<To>,
|
|
implements_rtti<From>>
|
|
{};
|
|
|
|
template <class To, class From>
|
|
inline constexpr bool cast_is_valid_v = cast_is_valid<To, From>::value;
|
|
}
|
|
|
|
template <class To, class From>
|
|
To fallout_cast(From* a_from) //
|
|
requires(detail::cast_is_valid_v<To, From*>)
|
|
{
|
|
REL::Relocation<void*> from{ detail::remove_cvpr_t<From>::RTTI };
|
|
REL::Relocation<void*> to{ detail::remove_cvpr_t<To>::RTTI };
|
|
return static_cast<To>(
|
|
RE::RTDynamicCast(
|
|
const_cast<void*>(
|
|
static_cast<const volatile void*>(a_from)),
|
|
0,
|
|
from.get(),
|
|
to.get(),
|
|
false));
|
|
}
|
|
}
|