use std::ffi::{CStr, c_char, c_int, c_uint, c_void};
use std::mem::{align_of, offset_of, size_of};
pub type HookManagerPubFunc =
unsafe extern "C" fn(store: bool, info: *mut IHookManagerInfo) -> c_int;
pub type Plugin = c_int;
const _: () = {
const SLOT: usize = size_of::<*const ()>();
macro_rules! assert_slot {
($ty:ty, $field:ident, $slot:expr) => {
assert!(offset_of!($ty, $field) == $slot * SLOT);
};
}
assert!(size_of::<MetaRes>() == size_of::<c_int>());
assert!(size_of::<AddHookMode>() == size_of::<c_int>());
assert!(offset_of!(PassInfo, size) == 0);
assert!(offset_of!(PassInfo, kind) == 8);
assert!(offset_of!(PassInfo, flags) == 12);
assert!(size_of::<PassInfo>() == 16);
assert_slot!(PassInfoV2, normal_ctor, 0);
assert_slot!(PassInfoV2, copy_ctor, 1);
assert_slot!(PassInfoV2, dtor, 2);
assert_slot!(PassInfoV2, assign_operator, 3);
assert!(size_of::<PassInfoV2>() == 4 * SLOT);
assert!(offset_of!(ProtoInfo, num_of_params) == 0);
assert!(offset_of!(ProtoInfo, ret_pass_info) == 8);
assert!(offset_of!(ProtoInfo, params_pass_info) == 24);
assert!(offset_of!(ProtoInfo, convention) == 32);
assert!(offset_of!(ProtoInfo, ret_pass_info2) == 40);
assert!(offset_of!(ProtoInfo, params_pass_info2) == 72);
assert!(size_of::<ProtoInfo>() == 80);
assert!(align_of::<ProtoInfo>() == SLOT);
assert_slot!(ISourceHookVtable, get_iface_version, 0);
assert_slot!(ISourceHookVtable, get_impl_version, 1);
assert_slot!(ISourceHookVtable, add_hook, 2);
assert_slot!(ISourceHookVtable, remove_hook, 3);
assert_slot!(ISourceHookVtable, remove_hook_by_id, 4);
assert_slot!(ISourceHookVtable, pause_hook_by_id, 5);
assert_slot!(ISourceHookVtable, unpause_hook_by_id, 6);
assert_slot!(ISourceHookVtable, set_res, 7);
assert_slot!(ISourceHookVtable, get_prev_res, 8);
assert_slot!(ISourceHookVtable, get_status, 9);
assert_slot!(ISourceHookVtable, get_orig_ret, 10);
assert_slot!(ISourceHookVtable, get_override_ret, 11);
assert_slot!(ISourceHookVtable, get_iface_ptr, 12);
assert_slot!(ISourceHookVtable, get_override_ret_ptr, 13);
assert_slot!(ISourceHookVtable, remove_hook_manager, 14);
assert_slot!(ISourceHookVtable, set_ignore_hooks, 15);
assert_slot!(ISourceHookVtable, reset_ignore_hooks, 16);
assert_slot!(ISourceHookVtable, get_orig_vfn_ptr_entry, 17);
assert_slot!(ISourceHookVtable, do_recall, 18);
assert_slot!(ISourceHookVtable, setup_hook_loop, 19);
assert_slot!(ISourceHookVtable, end_context, 20);
assert_slot!(ISourceHookVtable, log_debug, 21);
assert!(size_of::<ISourceHookVtable>() == 22 * SLOT);
assert_slot!(IHookContextVtable, get_next, 0);
assert_slot!(IHookContextVtable, get_override_ret_ptr, 1);
assert_slot!(IHookContextVtable, get_orig_ret_ptr, 2);
assert_slot!(IHookContextVtable, should_call_orig, 3);
assert!(size_of::<IHookContextVtable>() == 4 * SLOT);
assert_slot!(IShDelegateVtable, is_equal, 0);
assert_slot!(IShDelegateVtable, delete_this, 1);
assert!(size_of::<IShDelegateVtable>() == SH_DELEGATE_CALL_SLOT * SLOT);
assert_slot!(IHookManagerInfoVtable, set_info, 0);
assert!(size_of::<IHookManagerInfoVtable>() == SLOT);
assert!(size_of::<ISourceHook>() == SLOT);
assert!(size_of::<IHookContext>() == SLOT);
assert!(size_of::<IShDelegate>() == SLOT);
assert!(size_of::<IHookManagerInfo>() == SLOT);
};
pub const MMIFACE_SOURCEHOOK: &CStr = c"ISourceHook";
pub const SH_DELEGATE_CALL_SLOT: usize = 2;
pub const SH_HOOKMAN_VERSION: c_int = 1;
pub const SH_IFACE_VERSION: c_int = 5;
pub const SH_IMPL_VERSION: c_int = 5;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct AddHookMode(pub c_int);
impl AddHookMode {
pub const DVP: Self = Self(2);
pub const NORMAL: Self = Self(0);
pub const VP: Self = Self(1);
}
#[repr(C)]
pub struct IHookContext {
pub vtable: *const IHookContextVtable,
}
#[repr(C)]
pub struct IHookContextVtable {
pub get_next: unsafe extern "C" fn(*mut IHookContext) -> *mut IShDelegate,
pub get_override_ret_ptr: unsafe extern "C" fn(*mut IHookContext) -> *mut c_void,
pub get_orig_ret_ptr: unsafe extern "C" fn(*mut IHookContext) -> *const c_void,
pub should_call_orig: unsafe extern "C" fn(*mut IHookContext) -> bool,
}
#[repr(C)]
pub struct IHookManagerInfo {
pub vtable: *const IHookManagerInfoVtable,
}
#[repr(C)]
pub struct IHookManagerInfoVtable {
pub set_info: unsafe extern "C" fn(
*mut IHookManagerInfo,
hook_manager_version: c_int,
vtbl_offs: c_int,
vtbl_idx: c_int,
proto: *mut ProtoInfo,
hook_function: *mut c_void,
),
}
#[repr(C)]
pub struct IShDelegate {
pub vtable: *const IShDelegateVtable,
}
#[repr(C)]
pub struct IShDelegateVtable {
pub is_equal: unsafe extern "C" fn(*mut IShDelegate, other: *mut IShDelegate) -> bool,
pub delete_this: unsafe extern "C" fn(*mut IShDelegate),
}
#[repr(C)]
pub struct ISourceHook {
pub vtable: *const ISourceHookVtable,
}
#[repr(C)]
pub struct ISourceHookVtable {
pub get_iface_version: unsafe extern "C" fn(*mut ISourceHook) -> c_int,
pub get_impl_version: unsafe extern "C" fn(*mut ISourceHook) -> c_int,
pub add_hook: unsafe extern "C" fn(
*mut ISourceHook,
plugin: Plugin,
mode: AddHookMode,
iface: *mut c_void,
thisptr_offs: c_int,
hook_manager: HookManagerPubFunc,
handler: *mut IShDelegate,
post: bool,
) -> c_int,
pub remove_hook: unsafe extern "C" fn(
*mut ISourceHook,
plugin: Plugin,
iface: *mut c_void,
thisptr_offs: c_int,
hook_manager: HookManagerPubFunc,
handler: *mut IShDelegate,
post: bool,
) -> bool,
pub remove_hook_by_id: unsafe extern "C" fn(*mut ISourceHook, hook_id: c_int) -> bool,
pub pause_hook_by_id: unsafe extern "C" fn(*mut ISourceHook, hook_id: c_int) -> bool,
pub unpause_hook_by_id: unsafe extern "C" fn(*mut ISourceHook, hook_id: c_int) -> bool,
pub set_res: unsafe extern "C" fn(*mut ISourceHook, res: MetaRes),
pub get_prev_res: unsafe extern "C" fn(*mut ISourceHook) -> MetaRes,
pub get_status: unsafe extern "C" fn(*mut ISourceHook) -> MetaRes,
pub get_orig_ret: unsafe extern "C" fn(*mut ISourceHook) -> *const c_void,
pub get_override_ret: unsafe extern "C" fn(*mut ISourceHook) -> *const c_void,
pub get_iface_ptr: unsafe extern "C" fn(*mut ISourceHook) -> *mut c_void,
pub get_override_ret_ptr: unsafe extern "C" fn(*mut ISourceHook) -> *mut c_void,
pub remove_hook_manager:
unsafe extern "C" fn(*mut ISourceHook, plugin: Plugin, hook_manager: HookManagerPubFunc),
pub set_ignore_hooks: unsafe extern "C" fn(*mut ISourceHook, vfnptr: *mut c_void),
pub reset_ignore_hooks: unsafe extern "C" fn(*mut ISourceHook, vfnptr: *mut c_void),
pub get_orig_vfn_ptr_entry:
unsafe extern "C" fn(*mut ISourceHook, vfnptr: *mut c_void) -> *mut c_void,
pub do_recall: unsafe extern "C" fn(*mut ISourceHook),
pub setup_hook_loop: unsafe extern "C" fn(
*mut ISourceHook,
info: *mut IHookManagerInfo,
vfnptr: *mut c_void,
thisptr: *mut c_void,
orig_call_addr: *mut *mut c_void,
status: *mut MetaRes,
prev_res: *mut MetaRes,
cur_res: *mut MetaRes,
orig_ret: *const c_void,
override_ret: *mut c_void,
) -> *mut IHookContext,
pub end_context: unsafe extern "C" fn(*mut ISourceHook, context: *mut IHookContext),
pub log_debug: unsafe extern "C" fn(*mut ISourceHook, format: *const c_char, ...),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct MetaRes(pub c_int);
impl MetaRes {
pub const HANDLED: Self = Self(1);
pub const IGNORED: Self = Self(0);
pub const OVERRIDE: Self = Self(2);
pub const SUPERCEDE: Self = Self(3);
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub struct PassInfo {
pub size: usize,
pub kind: c_int,
pub flags: c_uint,
}
impl PassInfo {
pub const PASS_FLAG_ASSIGN_OP: c_uint = 1 << 4;
pub const PASS_FLAG_BY_REF: c_uint = 1 << 1;
pub const PASS_FLAG_BY_VAL: c_uint = 1 << 0;
pub const PASS_FLAG_C_CTOR: c_uint = 1 << 5;
pub const PASS_FLAG_O_CTOR: c_uint = 1 << 3;
pub const PASS_FLAG_O_DTOR: c_uint = 1 << 2;
pub const PASS_FLAG_RET_MEM: c_uint = 1 << 6;
pub const PASS_FLAG_RET_REG: c_uint = 1 << 7;
pub const PASS_TYPE_BASIC: c_int = 1;
pub const PASS_TYPE_FLOAT: c_int = 2;
pub const PASS_TYPE_OBJECT: c_int = 3;
pub const PASS_TYPE_UNKNOWN: c_int = 0;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub struct PassInfoV2 {
pub normal_ctor: *mut c_void,
pub copy_ctor: *mut c_void,
pub dtor: *mut c_void,
pub assign_operator: *mut c_void,
}
impl PassInfoV2 {
pub const TRIVIAL: Self = Self {
normal_ctor: std::ptr::null_mut(),
copy_ctor: std::ptr::null_mut(),
dtor: std::ptr::null_mut(),
assign_operator: std::ptr::null_mut(),
};
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct ProtoInfo {
pub num_of_params: c_int,
pub ret_pass_info: PassInfo,
pub params_pass_info: *const PassInfo,
pub convention: c_int,
pub ret_pass_info2: PassInfoV2,
pub params_pass_info2: *const PassInfoV2,
}
impl ProtoInfo {
pub const CALL_CONV_CDECL: c_int = 2;
pub const CALL_CONV_HAS_VAFMT: c_int = Self::CALL_CONV_HAS_VAR_ARGS | (1 << 17);
pub const CALL_CONV_HAS_VAR_ARGS: c_int = 1 << 16;
pub const CALL_CONV_STD_CALL: c_int = 3;
pub const CALL_CONV_THIS_CALL: c_int = 1;
pub const CALL_CONV_UNKNOWN: c_int = 0;
}