1
0
mirror of https://github.com/alliedmodders/metamod-source.git synced 2025-02-20 13:54:14 +01:00

Untested reentrancy support; TODO: Test sh_stack and reentrancy extensively!

--HG--
extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/trunk%40129
This commit is contained in:
Pavol Marko 2005-10-12 20:25:15 +00:00
parent 03ba0a371e
commit 17aa1b4c3f
10 changed files with 393 additions and 199 deletions

View File

@ -20,10 +20,10 @@
// 1 - Initial revision
// 2 - Changed to virtual functions for iterators and all queries
// 3 - Added "hook loop status variable"
// Future: Thread safe interface?
// 4 - Reentrant
#define SH_IFACE_VERSION 3
#define SH_IMPL_VERSION 2
#define SH_IFACE_VERSION 4
#define SH_IMPL_VERSION 3
#ifndef SH_GLOB_SHPTR
#define SH_GLOB_SHPTR g_SHPtr
@ -273,15 +273,6 @@ namespace SourceHook
typedef CallClass<void> GenericCallClass;
/**
* @brief SH informs the loop in the hook manager about its status through this
*/
enum HookLoopStatus
{
HLS_Continue=0,
HLS_Stop
};
/**
* @brief The main SourceHook interface
*/
@ -360,14 +351,15 @@ namespace SourceHook
virtual void *GetIfacePtr() = 0; //!< Gets the interface pointer
//////////////////////////////////////////////////////////////////////////
// For hook managers
virtual META_RES &GetCurResRef() = 0; //!< Gets the reference to the current meta result
virtual META_RES &GetPrevResRef() = 0; //!< Gets the reference to the previous meta result
virtual META_RES &GetStatusRef() = 0; //!< Gets the reference to the status variable
virtual void* &GetIfacePtrRef() = 0; //!< Gets the reference to the interface this pointer
virtual void SetOrigRet(const void *ptr) = 0; //!< Sets the original return pointer
virtual void SetOverrideRet(const void *ptr) = 0; //!< Sets the override result pointer
virtual HookLoopStatus &GetStatusVarRef(IIface *pIface) = 0; //!< gets the reference to the hook status loop variable
virtual void HookLoopDone() = 0;
virtual void HookLoopBegin(IIface *pIface) = 0; //!< Should be called when a hook loop begins
virtual void HookLoopEnd() = 0; //!< Should be called when a hook loop exits
virtual void SetCurResPtr(META_RES *mres) = 0; //!< Sets pointer to the current meta result
virtual void SetPrevResPtr(META_RES *mres) = 0; //!< Sets pointer to previous meta result
virtual void SetStatusPtr(META_RES *mres) = 0; //!< Sets pointer to the status variable
virtual void SetIfacePtrPtr(void **pp) = 0; //!< Sets pointer to the interface this pointer
virtual void SetOrigRetPtr(const void *ptr) = 0; //!< Sets the original return pointer
virtual void SetOverrideRetPtr(const void *ptr) = 0; //!< Sets the override result pointer
virtual bool ShouldContinue() = 0; //!< Returns false if the hook loop should exit
};
}
@ -543,30 +535,31 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
return (reinterpret_cast<EmptyClass*>(this)->*mfp)params; \
} \
/* 2) Declare some vars and set it up */ \
SH_GLOB_SHPTR->HookLoopBegin(ifinfo); \
IHookList *prelist = ifinfo->GetPreHooks(); \
IHookList *postlist = ifinfo->GetPostHooks(); \
HookLoopStatus &hls = SH_GLOB_SHPTR->GetStatusVarRef(ifinfo); \
hls = HLS_Continue; \
META_RES status = MRES_IGNORED; \
META_RES prev_res; \
META_RES cur_res; \
SH_GLOB_SHPTR->SetStatusPtr(&status); \
SH_GLOB_SHPTR->SetPrevResPtr(&prev_res); \
SH_GLOB_SHPTR->SetCurResPtr(&cur_res); \
rettype orig_ret; \
rettype override_ret; \
rettype plugin_ret; \
META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
void* &ifptr = SH_GLOB_SHPTR->GetIfacePtrRef(); \
status = MRES_IGNORED; \
SH_GLOB_SHPTR->SetOrigRet(reinterpret_cast<void*>(&orig_ret)); \
SH_GLOB_SHPTR->SetOverrideRet(NULL);
void* ifptr; \
SH_GLOB_SHPTR->SetIfacePtrPtr(&ifptr); \
SH_GLOB_SHPTR->SetOrigRetPtr(reinterpret_cast<void*>(&orig_ret)); \
SH_GLOB_SHPTR->SetOverrideRetPtr(NULL);
#define SH_CALL_HOOKS(post, params) \
if (hls == HLS_Continue) \
if (SH_GLOB_SHPTR->ShouldContinue()) \
{ \
prev_res = MRES_IGNORED; \
for (AutoHookIter iter(post##list); !iter.End(); iter.Next()) \
{ \
cur_res = MRES_IGNORED; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - iter.ThisPtrOffs()); \
hls = HLS_Continue; \
plugin_ret = reinterpret_cast<CSHDelegate<FD>*>(iter.Handler())->GetDeleg() params; \
prev_res = cur_res; \
if (cur_res > status) \
@ -574,9 +567,9 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
if (cur_res >= MRES_OVERRIDE) \
{ \
override_ret = plugin_ret; \
SH_GLOB_SHPTR->SetOverrideRet(&override_ret); \
SH_GLOB_SHPTR->SetOverrideRetPtr(&override_ret); \
} \
if (hls == HLS_Stop) \
if (!SH_GLOB_SHPTR->ShouldContinue()) \
{ \
iter.SetToZero(); \
break; \
@ -595,6 +588,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
orig_ret = override_ret;
#define SH_RETURN() \
SH_GLOB_SHPTR->HookLoopEnd(); \
return status >= MRES_OVERRIDE ? override_ret : orig_ret;
#define SH_HANDLEFUNC(ifacetype, ifacefunc, paramtypes, params, rettype) \
@ -625,32 +619,33 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
return; \
} \
/* 2) Declare some vars and set it up */ \
SH_GLOB_SHPTR->HookLoopBegin(ifinfo); \
IHookList *prelist = ifinfo->GetPreHooks(); \
IHookList *postlist = ifinfo->GetPostHooks(); \
META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
HookLoopStatus &hls = SH_GLOB_SHPTR->GetStatusVarRef(ifinfo); \
hls = HLS_Continue; \
META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
void* &ifptr = SH_GLOB_SHPTR->GetIfacePtrRef(); \
status = MRES_IGNORED; \
SH_GLOB_SHPTR->SetOverrideRet(NULL); \
SH_GLOB_SHPTR->SetOrigRet(NULL);
META_RES status = MRES_IGNORED; \
META_RES prev_res; \
META_RES cur_res; \
SH_GLOB_SHPTR->SetStatusPtr(&status); \
SH_GLOB_SHPTR->SetPrevResPtr(&prev_res); \
SH_GLOB_SHPTR->SetCurResPtr(&cur_res); \
void* ifptr; \
SH_GLOB_SHPTR->SetIfacePtrPtr(&ifptr); \
SH_GLOB_SHPTR->SetOverrideRetPtr(NULL); \
SH_GLOB_SHPTR->SetOrigRetPtr(NULL);
#define SH_CALL_HOOKS_void(post, params) \
if (hls == HLS_Continue) \
if (SH_GLOB_SHPTR->ShouldContinue()) \
{ \
prev_res = MRES_IGNORED; \
for (AutoHookIter iter(post##list); !iter.End(); iter.Next()) \
{ \
cur_res = MRES_IGNORED; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - iter.ThisPtrOffs()); \
hls = HLS_Continue; \
reinterpret_cast<CSHDelegate<FD>*>(iter.Handler())->GetDeleg() params; \
prev_res = cur_res; \
if (cur_res > status) \
status = cur_res; \
if (hls == HLS_Stop) \
if (!SH_GLOB_SHPTR->ShouldContinue()) \
{ \
iter.SetToZero(); \
break; \
@ -666,7 +661,8 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
(reinterpret_cast<EmptyClass*>(this)->*mfp)params; \
}
#define SH_RETURN_void()
#define SH_RETURN_void() \
SH_GLOB_SHPTR->HookLoopEnd();
#define SH_HANDLEFUNC_void(ifacetype, ifacefunc, paramtypes, params) \
SH_SETUPCALLS_void(paramtypes, params) \

View File

@ -20,10 +20,10 @@
// 1 - Initial revision
// 2 - Changed to virtual functions for iterators and all queries
// 3 - Added "hook loop status variable"
// Future: Thread safe interface?
// 4 - Reentrant
#define SH_IFACE_VERSION 3
#define SH_IMPL_VERSION 2
#define SH_IFACE_VERSION 4
#define SH_IMPL_VERSION 3
#ifndef SH_GLOB_SHPTR
#define SH_GLOB_SHPTR g_SHPtr
@ -273,15 +273,6 @@ namespace SourceHook
typedef CallClass<void> GenericCallClass;
/**
* @brief SH informs the loop in the hook manager about its status through this
*/
enum HookLoopStatus
{
HLS_Continue=0,
HLS_Stop
};
/**
* @brief The main SourceHook interface
*/
@ -360,14 +351,15 @@ namespace SourceHook
virtual void *GetIfacePtr() = 0; //!< Gets the interface pointer
//////////////////////////////////////////////////////////////////////////
// For hook managers
virtual META_RES &GetCurResRef() = 0; //!< Gets the reference to the current meta result
virtual META_RES &GetPrevResRef() = 0; //!< Gets the reference to the previous meta result
virtual META_RES &GetStatusRef() = 0; //!< Gets the reference to the status variable
virtual void* &GetIfacePtrRef() = 0; //!< Gets the reference to the interface this pointer
virtual void SetOrigRet(const void *ptr) = 0; //!< Sets the original return pointer
virtual void SetOverrideRet(const void *ptr) = 0; //!< Sets the override result pointer
virtual HookLoopStatus &GetStatusVarRef(IIface *pIface) = 0; //!< gets the reference to the hook status loop variable
virtual void HookLoopDone() = 0;
virtual void HookLoopBegin(IIface *pIface) = 0; //!< Should be called when a hook loop begins
virtual void HookLoopEnd() = 0; //!< Should be called when a hook loop exits
virtual void SetCurResPtr(META_RES *mres) = 0; //!< Sets pointer to the current meta result
virtual void SetPrevResPtr(META_RES *mres) = 0; //!< Sets pointer to previous meta result
virtual void SetStatusPtr(META_RES *mres) = 0; //!< Sets pointer to the status variable
virtual void SetIfacePtrPtr(void **pp) = 0; //!< Sets pointer to the interface this pointer
virtual void SetOrigRetPtr(const void *ptr) = 0; //!< Sets the original return pointer
virtual void SetOverrideRetPtr(const void *ptr) = 0; //!< Sets the override result pointer
virtual bool ShouldContinue() = 0; //!< Returns false if the hook loop should exit
};
}
@ -543,30 +535,31 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
return (reinterpret_cast<EmptyClass*>(this)->*mfp)params; \
} \
/* 2) Declare some vars and set it up */ \
SH_GLOB_SHPTR->HookLoopBegin(ifinfo); \
IHookList *prelist = ifinfo->GetPreHooks(); \
IHookList *postlist = ifinfo->GetPostHooks(); \
HookLoopStatus &hls = SH_GLOB_SHPTR->GetStatusVarRef(ifinfo); \
hls = HLS_Continue; \
META_RES status = MRES_IGNORED; \
META_RES prev_res; \
META_RES cur_res; \
SH_GLOB_SHPTR->SetStatusPtr(&status); \
SH_GLOB_SHPTR->SetPrevResPtr(&prev_res); \
SH_GLOB_SHPTR->SetCurResPtr(&cur_res); \
rettype orig_ret; \
rettype override_ret; \
rettype plugin_ret; \
META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
void* &ifptr = SH_GLOB_SHPTR->GetIfacePtrRef(); \
status = MRES_IGNORED; \
SH_GLOB_SHPTR->SetOrigRet(reinterpret_cast<void*>(&orig_ret)); \
SH_GLOB_SHPTR->SetOverrideRet(NULL);
void* ifptr; \
SH_GLOB_SHPTR->SetIfacePtrPtr(&ifptr); \
SH_GLOB_SHPTR->SetOrigRetPtr(reinterpret_cast<void*>(&orig_ret)); \
SH_GLOB_SHPTR->SetOverrideRetPtr(NULL);
#define SH_CALL_HOOKS(post, params) \
if (hls == HLS_Continue) \
if (SH_GLOB_SHPTR->ShouldContinue()) \
{ \
prev_res = MRES_IGNORED; \
for (AutoHookIter iter(post##list); !iter.End(); iter.Next()) \
{ \
cur_res = MRES_IGNORED; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - iter.ThisPtrOffs()); \
hls = HLS_Continue; \
plugin_ret = reinterpret_cast<CSHDelegate<FD>*>(iter.Handler())->GetDeleg() params; \
prev_res = cur_res; \
if (cur_res > status) \
@ -574,9 +567,9 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
if (cur_res >= MRES_OVERRIDE) \
{ \
override_ret = plugin_ret; \
SH_GLOB_SHPTR->SetOverrideRet(&override_ret); \
SH_GLOB_SHPTR->SetOverrideRetPtr(&override_ret); \
} \
if (hls == HLS_Stop) \
if (!SH_GLOB_SHPTR->ShouldContinue()) \
{ \
iter.SetToZero(); \
break; \
@ -595,6 +588,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
orig_ret = override_ret;
#define SH_RETURN() \
SH_GLOB_SHPTR->HookLoopEnd(); \
return status >= MRES_OVERRIDE ? override_ret : orig_ret;
#define SH_HANDLEFUNC(ifacetype, ifacefunc, paramtypes, params, rettype) \
@ -625,32 +619,33 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
return; \
} \
/* 2) Declare some vars and set it up */ \
SH_GLOB_SHPTR->HookLoopBegin(ifinfo); \
IHookList *prelist = ifinfo->GetPreHooks(); \
IHookList *postlist = ifinfo->GetPostHooks(); \
META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
HookLoopStatus &hls = SH_GLOB_SHPTR->GetStatusVarRef(ifinfo); \
hls = HLS_Continue; \
META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
void* &ifptr = SH_GLOB_SHPTR->GetIfacePtrRef(); \
status = MRES_IGNORED; \
SH_GLOB_SHPTR->SetOverrideRet(NULL); \
SH_GLOB_SHPTR->SetOrigRet(NULL);
META_RES status = MRES_IGNORED; \
META_RES prev_res; \
META_RES cur_res; \
SH_GLOB_SHPTR->SetStatusPtr(&status); \
SH_GLOB_SHPTR->SetPrevResPtr(&prev_res); \
SH_GLOB_SHPTR->SetCurResPtr(&cur_res); \
void* ifptr; \
SH_GLOB_SHPTR->SetIfacePtrPtr(&ifptr); \
SH_GLOB_SHPTR->SetOverrideRetPtr(NULL); \
SH_GLOB_SHPTR->SetOrigRetPtr(NULL);
#define SH_CALL_HOOKS_void(post, params) \
if (hls == HLS_Continue) \
if (SH_GLOB_SHPTR->ShouldContinue()) \
{ \
prev_res = MRES_IGNORED; \
for (AutoHookIter iter(post##list); !iter.End(); iter.Next()) \
{ \
cur_res = MRES_IGNORED; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - iter.ThisPtrOffs()); \
hls = HLS_Continue; \
reinterpret_cast<CSHDelegate<FD>*>(iter.Handler())->GetDeleg() params; \
prev_res = cur_res; \
if (cur_res > status) \
status = cur_res; \
if (hls == HLS_Stop) \
if (!SH_GLOB_SHPTR->ShouldContinue()) \
{ \
iter.SetToZero(); \
break; \
@ -666,7 +661,8 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
(reinterpret_cast<EmptyClass*>(this)->*mfp)params; \
}
#define SH_RETURN_void()
#define SH_RETURN_void() \
SH_GLOB_SHPTR->HookLoopEnd();
#define SH_HANDLEFUNC_void(ifacetype, ifacefunc, paramtypes, params) \
SH_SETUPCALLS_void(paramtypes, params) \

165
sourcehook/sh_stack.h Normal file
View File

@ -0,0 +1,165 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2005 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): Pavol "PM OnoTo" Marko
* ============================
*/
#ifndef __SH_STACK_H__
#define __SH_STACK_H__
#define SH_STACK_DEFAULT_SIZE 4
#include <assert.h>
namespace SourceHook
{
// Vector
template <class T> class CStack
{
T *m_Elements;
size_t m_AllocatedSize;
size_t m_UsedSize;
public:
friend class iterator;
class iterator
{
CStack<T> *m_pParent;
size_t m_Index;
public:
iterator(CStack<T> *pParent, size_t id) : m_pParent(pParent), m_Index(id)
{
}
iterator(CStack<T> *pParent) : m_pParent(pParent), m_Index(0)
{
}
iterator() : m_pParent(NULL), m_Index(0)
{
}
T &operator *()
{
return m_pParent->m_Elements[m_Index];
}
const T &operator *() const
{
return m_pParent->m_Elements[m_Index];
}
T * operator->()
{
return m_pParent->m_Elements + m_Index;
}
const T * operator->() const
{
return m_pParent->m_Elements + m_Index;
}
iterator & operator++() // preincrement
{
++m_Index;
return (*this);
}
iterator operator++(int) // postincrement
{
iterator tmp = *this;
++m_Ptr;
return tmp;
}
iterator & operator--() // predecrement
{
--m_Index;
return (*this);
}
iterator operator--(int) // postdecrememnt
{
iterator tmp = *this;
--m_Ptr;
return tmp;
}
bool operator==(const iterator & right) const
{
return (m_pParent == right.m_pParent && m_Index == right.m_Index);
}
bool operator!=(const iterator & right) const
{
return !(*this == right);
}
};
CStack() : m_Elements(new T[SH_STACK_DEFAULT_SIZE]),
m_AllocatedSize(SH_STACK_DEFAULT_SIZE),
m_UsedSize(0)
{
assert(m_Elements);
}
CStack(size_t size) : m_Elements(new T[size]),
m_AllocatedSize(size),
m_UsedSize(0)
{
assert(m_Elements);
}
~CStack()
{
if (m_Elements)
delete [] m_Elements;
}
bool push(const T &val)
{
if (m_UsedSize + 1 == m_AllocatedSize)
{
// zOHNOES! REALLOCATE!
m_AllocatedSize *= 2;
T *newElements = new T[m_AllocatedSize];
if (!newElements)
{
m_AllocatedSize /= 2;
return false;
}
for (size_t i = 0; i < m_UsedSize; ++i)
newElements[i] = m_Elements[i];
delete [] m_Elements;
m_Elements = newElements;
}
m_Elements[m_UsedSize++] = val;
return true;
}
void pop()
{
--m_UsedSize;
}
T &front()
{
return m_Elements[m_UsedSize - 1];
}
const T &front() const
{
return m_Elements[m_UsedSize - 1];
}
iterator begin()
{
return iterator(this, 0);
}
iterator end()
{
return iterator(this, m_UsedSize);
}
};
}; //namespace SourceHook
#endif

View File

@ -365,8 +365,12 @@ namespace SourceHook
if (iface_iter->m_PostHooks.m_List.empty() && iface_iter->m_PreHooks.m_List.empty())
{
// There are no hooks on this iface anymore...
if (m_CurIface == static_cast<IIface*>(&(*iface_iter)))
m_HLS = HLS_Stop;
for (HookLoopInfoStack::iterator hli_iter = m_HLIStack.begin();
hli_iter != m_HLIStack.end(); ++hli_iter)
{
if (hli_iter->pCurIface == static_cast<IIface*>(&(*iface_iter)))
hli_iter->shouldContinue = false;
}
iface_iter = vfnptr_iter->m_Ifaces.erase(iface_iter);
if (vfnptr_iter->m_Ifaces.empty())
@ -519,74 +523,80 @@ namespace SourceHook
SetPluginPaused(plug, false);
}
void CSourceHookImpl::HookLoopBegin(IIface *pIface)
{
HookLoopInfo hli;
hli.pCurIface = pIface;
hli.shouldContinue = true;
m_HLIStack.push(hli);
}
void CSourceHookImpl::HookLoopEnd()
{
m_HLIStack.pop();
}
void CSourceHookImpl::SetRes(META_RES res)
{
m_CurRes = res;
*m_HLIStack.front().pCurRes = res;
}
META_RES CSourceHookImpl::GetPrevRes()
{
return m_PrevRes;
return *m_HLIStack.front().pPrevRes;
}
META_RES CSourceHookImpl::GetStatus()
{
return m_Status;
return *m_HLIStack.front().pStatus;
}
const void *CSourceHookImpl::GetOrigRet()
{
return m_OrigRet;
return m_HLIStack.front().pOrigRet;
}
const void *CSourceHookImpl::GetOverrideRet()
{
return m_OverrideRet;
}
META_RES &CSourceHookImpl::GetCurResRef()
{
return m_CurRes;
}
META_RES &CSourceHookImpl::GetPrevResRef()
{
return m_PrevRes;
}
META_RES &CSourceHookImpl::GetStatusRef()
{
return m_Status;
}
void * &CSourceHookImpl::GetIfacePtrRef()
{
return m_IfacePtr;
}
void CSourceHookImpl::SetOrigRet(const void *ptr)
{
m_OrigRet = ptr;
}
void CSourceHookImpl::SetOverrideRet(const void *ptr)
{
m_OverrideRet = ptr;
return m_HLIStack.front().pOverrideRet;
}
void *CSourceHookImpl::GetIfacePtr()
{
return m_IfacePtr;
return *m_HLIStack.front().pIfacePtrPtr;
}
HookLoopStatus &CSourceHookImpl::GetStatusVarRef(IIface *pIface)
void CSourceHookImpl::SetCurResPtr(META_RES *mres)
{
m_CurIface = pIface;
return m_HLS;
m_HLIStack.front().pCurRes = mres;
}
void CSourceHookImpl::HookLoopDone()
void CSourceHookImpl::SetPrevResPtr(META_RES *mres)
{
m_CurIface = NULL;
m_HLIStack.front().pPrevRes = mres;
}
void CSourceHookImpl::SetStatusPtr(META_RES *mres)
{
m_HLIStack.front().pStatus = mres;
}
void CSourceHookImpl::SetIfacePtrPtr(void **pp)
{
m_HLIStack.front().pIfacePtrPtr = pp;
}
void CSourceHookImpl::SetOrigRetPtr(const void *ptr)
{
m_HLIStack.front().pOrigRet = ptr;
}
void CSourceHookImpl::SetOverrideRetPtr(const void *ptr)
{
m_HLIStack.front().pOverrideRet = ptr;
}
bool CSourceHookImpl::ShouldContinue()
{
return m_HLIStack.front().shouldContinue;
}
////////////////////////////

View File

@ -20,10 +20,10 @@
// 1 - Initial revision
// 2 - Changed to virtual functions for iterators and all queries
// 3 - Added "hook loop status variable"
// Future: Thread safe interface?
// 4 - Reentrant
#define SH_IFACE_VERSION 3
#define SH_IMPL_VERSION 2
#define SH_IFACE_VERSION 4
#define SH_IMPL_VERSION 3
#ifndef SH_GLOB_SHPTR
#define SH_GLOB_SHPTR g_SHPtr
@ -273,15 +273,6 @@ namespace SourceHook
typedef CallClass<void> GenericCallClass;
/**
* @brief SH informs the loop in the hook manager about its status through this
*/
enum HookLoopStatus
{
HLS_Continue=0,
HLS_Stop
};
/**
* @brief The main SourceHook interface
*/
@ -360,14 +351,15 @@ namespace SourceHook
virtual void *GetIfacePtr() = 0; //!< Gets the interface pointer
//////////////////////////////////////////////////////////////////////////
// For hook managers
virtual META_RES &GetCurResRef() = 0; //!< Gets the reference to the current meta result
virtual META_RES &GetPrevResRef() = 0; //!< Gets the reference to the previous meta result
virtual META_RES &GetStatusRef() = 0; //!< Gets the reference to the status variable
virtual void* &GetIfacePtrRef() = 0; //!< Gets the reference to the interface this pointer
virtual void SetOrigRet(const void *ptr) = 0; //!< Sets the original return pointer
virtual void SetOverrideRet(const void *ptr) = 0; //!< Sets the override result pointer
virtual HookLoopStatus &GetStatusVarRef(IIface *pIface) = 0; //!< gets the reference to the hook status loop variable
virtual void HookLoopDone() = 0;
virtual void HookLoopBegin(IIface *pIface) = 0; //!< Should be called when a hook loop begins
virtual void HookLoopEnd() = 0; //!< Should be called when a hook loop exits
virtual void SetCurResPtr(META_RES *mres) = 0; //!< Sets pointer to the current meta result
virtual void SetPrevResPtr(META_RES *mres) = 0; //!< Sets pointer to previous meta result
virtual void SetStatusPtr(META_RES *mres) = 0; //!< Sets pointer to the status variable
virtual void SetIfacePtrPtr(void **pp) = 0; //!< Sets pointer to the interface this pointer
virtual void SetOrigRetPtr(const void *ptr) = 0; //!< Sets the original return pointer
virtual void SetOverrideRetPtr(const void *ptr) = 0; //!< Sets the override result pointer
virtual bool ShouldContinue() = 0; //!< Returns false if the hook loop should exit
};
}
@ -543,30 +535,31 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
return (reinterpret_cast<EmptyClass*>(this)->*mfp)params; \
} \
/* 2) Declare some vars and set it up */ \
SH_GLOB_SHPTR->HookLoopBegin(ifinfo); \
IHookList *prelist = ifinfo->GetPreHooks(); \
IHookList *postlist = ifinfo->GetPostHooks(); \
HookLoopStatus &hls = SH_GLOB_SHPTR->GetStatusVarRef(ifinfo); \
hls = HLS_Continue; \
META_RES status = MRES_IGNORED; \
META_RES prev_res; \
META_RES cur_res; \
SH_GLOB_SHPTR->SetStatusPtr(&status); \
SH_GLOB_SHPTR->SetPrevResPtr(&prev_res); \
SH_GLOB_SHPTR->SetCurResPtr(&cur_res); \
rettype orig_ret; \
rettype override_ret; \
rettype plugin_ret; \
META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
void* &ifptr = SH_GLOB_SHPTR->GetIfacePtrRef(); \
status = MRES_IGNORED; \
SH_GLOB_SHPTR->SetOrigRet(reinterpret_cast<void*>(&orig_ret)); \
SH_GLOB_SHPTR->SetOverrideRet(NULL);
void* ifptr; \
SH_GLOB_SHPTR->SetIfacePtrPtr(&ifptr); \
SH_GLOB_SHPTR->SetOrigRetPtr(reinterpret_cast<void*>(&orig_ret)); \
SH_GLOB_SHPTR->SetOverrideRetPtr(NULL);
#define SH_CALL_HOOKS(post, params) \
if (hls == HLS_Continue) \
if (SH_GLOB_SHPTR->ShouldContinue()) \
{ \
prev_res = MRES_IGNORED; \
for (AutoHookIter iter(post##list); !iter.End(); iter.Next()) \
{ \
cur_res = MRES_IGNORED; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - iter.ThisPtrOffs()); \
hls = HLS_Continue; \
plugin_ret = reinterpret_cast<CSHDelegate<FD>*>(iter.Handler())->GetDeleg() params; \
prev_res = cur_res; \
if (cur_res > status) \
@ -574,9 +567,9 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
if (cur_res >= MRES_OVERRIDE) \
{ \
override_ret = plugin_ret; \
SH_GLOB_SHPTR->SetOverrideRet(&override_ret); \
SH_GLOB_SHPTR->SetOverrideRetPtr(&override_ret); \
} \
if (hls == HLS_Stop) \
if (!SH_GLOB_SHPTR->ShouldContinue()) \
{ \
iter.SetToZero(); \
break; \
@ -595,6 +588,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
orig_ret = override_ret;
#define SH_RETURN() \
SH_GLOB_SHPTR->HookLoopEnd(); \
return status >= MRES_OVERRIDE ? override_ret : orig_ret;
#define SH_HANDLEFUNC(ifacetype, ifacefunc, paramtypes, params, rettype) \
@ -625,32 +619,33 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
return; \
} \
/* 2) Declare some vars and set it up */ \
SH_GLOB_SHPTR->HookLoopBegin(ifinfo); \
IHookList *prelist = ifinfo->GetPreHooks(); \
IHookList *postlist = ifinfo->GetPostHooks(); \
META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
HookLoopStatus &hls = SH_GLOB_SHPTR->GetStatusVarRef(ifinfo); \
hls = HLS_Continue; \
META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
void* &ifptr = SH_GLOB_SHPTR->GetIfacePtrRef(); \
status = MRES_IGNORED; \
SH_GLOB_SHPTR->SetOverrideRet(NULL); \
SH_GLOB_SHPTR->SetOrigRet(NULL);
META_RES status = MRES_IGNORED; \
META_RES prev_res; \
META_RES cur_res; \
SH_GLOB_SHPTR->SetStatusPtr(&status); \
SH_GLOB_SHPTR->SetPrevResPtr(&prev_res); \
SH_GLOB_SHPTR->SetCurResPtr(&cur_res); \
void* ifptr; \
SH_GLOB_SHPTR->SetIfacePtrPtr(&ifptr); \
SH_GLOB_SHPTR->SetOverrideRetPtr(NULL); \
SH_GLOB_SHPTR->SetOrigRetPtr(NULL);
#define SH_CALL_HOOKS_void(post, params) \
if (hls == HLS_Continue) \
if (SH_GLOB_SHPTR->ShouldContinue()) \
{ \
prev_res = MRES_IGNORED; \
for (AutoHookIter iter(post##list); !iter.End(); iter.Next()) \
{ \
cur_res = MRES_IGNORED; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - iter.ThisPtrOffs()); \
hls = HLS_Continue; \
reinterpret_cast<CSHDelegate<FD>*>(iter.Handler())->GetDeleg() params; \
prev_res = cur_res; \
if (cur_res > status) \
status = cur_res; \
if (hls == HLS_Stop) \
if (!SH_GLOB_SHPTR->ShouldContinue()) \
{ \
iter.SetToZero(); \
break; \
@ -666,7 +661,8 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
(reinterpret_cast<EmptyClass*>(this)->*mfp)params; \
}
#define SH_RETURN_void()
#define SH_RETURN_void() \
SH_GLOB_SHPTR->HookLoopEnd();
#define SH_HANDLEFUNC_void(ifacetype, ifacefunc, paramtypes, params) \
SH_SETUPCALLS_void(paramtypes, params) \

View File

@ -15,6 +15,7 @@
#include "sh_list.h"
#include "sh_vector.h"
#include "sh_tinyhash.h"
#include "sh_stack.h"
// Set this to 1 to enable runtime code generation (faster)
// (unused at the moment, but may come back, so I'm leaving it in here!)
@ -217,6 +218,21 @@ namespace SourceHook
Impl_CallClassList m_CallClasses; //!< A list of already generated callclasses
HookManInfoList m_HookMans; //!< A list of hook managers
struct HookLoopInfo
{
META_RES *pStatus;
META_RES *pPrevRes;
META_RES *pCurRes;
bool shouldContinue;
IIface *pCurIface;
const void *pOrigRet;
const void *pOverrideRet;
void **pIfacePtrPtr;
};
typedef CStack<HookLoopInfo> HookLoopInfoStack;
/**
* @brief Finds a hook manager for a function based on a text-prototype, a vtable offset and a vtable index
*/
@ -229,12 +245,7 @@ namespace SourceHook
void SetPluginPaused(Plugin plug, bool paused);
META_RES m_Status, m_PrevRes, m_CurRes;
HookLoopStatus m_HLS;
IIface *m_CurIface;
const void *m_OrigRet;
const void *m_OverrideRet;
void *m_IfacePtr;
HookLoopInfoStack m_HLIStack;
public:
CSourceHookImpl();
virtual ~CSourceHookImpl();
@ -341,14 +352,15 @@ namespace SourceHook
//////////////////////////////////////////////////////////////////////////
// For hook managers
virtual META_RES &GetCurResRef(); //!< Gets the reference to the current meta result
virtual META_RES &GetPrevResRef(); //!< Gets the reference to the previous meta result
virtual META_RES &GetStatusRef(); //!< Gets the reference to the status variable
virtual void* &GetIfacePtrRef(); //!< Gets the reference to the iface ptr
virtual void SetOrigRet(const void *ptr); //!< Sets the original return pointer
virtual void SetOverrideRet(const void *ptr); //!< Sets the override result pointer
HookLoopStatus &GetStatusVarRef(IIface *pIface);
void HookLoopDone();
void HookLoopBegin(IIface *pIface); //!< Should be called when a hook loop begins
void HookLoopEnd(); //!< Should be called when a hook loop exits
void SetCurResPtr(META_RES *mres); //!< Sets pointer to the current meta result
void SetPrevResPtr(META_RES *mres); //!< Sets pointer to previous meta result
void SetStatusPtr(META_RES *mres); //!< Sets pointer to the status variable
void SetIfacePtrPtr(void **pp); //!< Sets pointer to the interface this pointer
void SetOrigRetPtr(const void *ptr); //!< Sets the original return pointer
void SetOverrideRetPtr(const void *ptr); //!< Sets the override result pointer
bool ShouldContinue(); //!< Returns false if the hook loop should exit
};
}

View File

@ -275,6 +275,9 @@
<File
RelativePath="..\sh_list.h">
</File>
<File
RelativePath="..\sh_stack.h">
</File>
<File
RelativePath="..\sh_string.h">
</File>

View File

@ -17,13 +17,11 @@ namespace
SH_DECL_HOOK0_void(zomg_lolz, zomg, SH_NOATTRIB, 0);
void Handler()
{
printf("H1\n");
SH_REMOVE_HOOK_STATICFUNC(zomg_lolz, zomg, reinterpret_cast<zomg_lolz*>(META_IFACEPTR),
Handler, false);
}
void Handler2()
{
printf("H2\n");
}
}

View File

@ -134,5 +134,23 @@ namespace
virtual void Dump() { \
std::cout << " " << #name << "; Param1=" << m_Param1 << "; Param2=" << m_Param2 << std::endl; } \
}
#define MAKE_STATE_3(name, p1_type, p2_type, p3_type) struct name : State { \
p1_type m_Param1; \
p2_type m_Param2; \
p3_type m_Param3; \
name(p1_type param1, p2_type param2, p3_type param3) : m_Param1(param1), m_Param2(param2), m_Param3(param3) {} \
virtual bool IsEqual(State *other) { \
name *other2 = dynamic_cast<name*>(other); \
if (!other2) \
return false; \
return other2->m_Param1 == m_Param1 && other2->m_Param2 == m_Param2 && other2->m_Param3 == m_Param3;\
} \
virtual void Dump() { \
std::cout << " " << #name << "; Param1=" << m_Param1 << "; Param2=" << m_Param2 << "; Param3=" << m_Param3 << std::endl; } \
}
#define CHECK_COND(c, err) if (!(c)) { error = err; return false; }
#endif

View File

@ -1,13 +1,13 @@
#include <string>
#include "sh_list.h"
#include "sh_tinyhash.h"
#include "testevents.h"
// TEST LIST
// Tests sh_list, sh_tinyhash, sh_vector
// :TODO: vector test
#define CHECK_COND(c, err) if (!(c)) { error = err; return false; }
// :TODO: stack test
namespace
{