1
0
mirror of https://github.com/alliedmodders/metamod-source.git synced 2024-11-29 11:24:19 +01:00
HLMetaModOfficial/sourcehook/sourcehook_impl.h

393 lines
10 KiB
C++

/* ======== SourceHook ========
* Copyright (C) 2004-2005 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): Pavol "PM OnoTo" Marko
* ============================
*/
#ifndef __SOURCEHOOK_IMPL_H__
#define __SOURCEHOOK_IMPL_H__
#include "sourcehook.h"
#include "sh_list.h"
#include "sh_vector.h"
#include "sh_tinyhash.h"
#include "sh_stack.h"
namespace SourceHook
{
/**
* @brief The SourceHook implementation class
*/
class CSourceHookImpl : public ISourceHook
{
private:
/**
* @brief A hook can be removed if you have this information
*/
struct RemoveHookInfo
{
RemoveHookInfo(Plugin pplug, void *piface, int tpo, HookManagerPubFunc phookman,
ISHDelegate *phandler, bool ppost)
: plug(pplug), iface(piface), thisptr_offs(tpo),
hookman(phookman), handler(phandler), post(ppost)
{
}
Plugin plug;
void *iface;
int thisptr_offs;
HookManagerPubFunc hookman;
ISHDelegate *handler;
bool post;
};
struct HookInfo
{
ISHDelegate *handler; //!< Pointer to the handler
bool paused; //!< If true, the hook should not be executed
Plugin plug; //!< The owner plugin
int thisptr_offs; //!< This pointer offset
};
class CHookList : public IHookList
{
public:
List<HookInfo> m_List;
friend class CIter;
class CIter : public IHookList::IIter
{
friend class CHookList;
CHookList *m_pList;
void SkipPaused();
public:
List<HookInfo>::iterator m_Iter;
CIter(CHookList *pList);
virtual ~CIter();
void GoToBegin();
void Set(CIter *pOther);
bool End();
void Next();
ISHDelegate *Handler();
int ThisPtrOffs();
void Clear();
CIter *m_pNext; // When stored in m_FreeIters and m_UsedIters
CIter *m_pPrev; // Only used when stored in m_UsedIters
};
CIter *m_FreeIters;
CIter *m_UsedIters; // The last returned and not-yet-released iter is always m_UsedIters
// For recalls
bool m_Recall;
void SetRecallState(); // Sets the list into a state where the next returned
// iterator (from GetIter) will be a copy of the last
// returned iterator, incremented by one. This is used in Recalls.
// The hook resets this state automatically on:
// GetIter, ReleaseIter
CHookList();
CHookList(const CHookList &other);
virtual ~CHookList();
void operator=(const CHookList &other);
IIter *GetIter();
void ReleaseIter(IIter *pIter);
};
// I know, data hiding... But I'm a lazy bastard!
class CIface : public IIface
{
public:
void *m_Ptr;
CHookList m_PreHooks;
CHookList m_PostHooks;
public:
CIface(void *ptr);
virtual ~CIface();
void *GetPtr();
IHookList *GetPreHooks();
IHookList *GetPostHooks();
bool operator==(void *ptr)
{
return m_Ptr == ptr;
}
};
class CVfnPtr : public IVfnPtr
{
public:
typedef List<CIface> IfaceList;
typedef IfaceList::iterator IfaceListIter;
void *m_Ptr;
void *m_OrigEntry;
IfaceList m_Ifaces;
public:
CVfnPtr(void *ptr);
virtual ~CVfnPtr();
void *GetVfnPtr();
void *GetOrigEntry();
virtual IIface *FindIface(void *ptr);
bool operator==(void *ptr)
{
return m_Ptr == ptr;
}
};
class CHookManagerInfo : public IHookManagerInfo
{
public:
typedef List<CVfnPtr> VfnPtrList;
typedef VfnPtrList::iterator VfnPtrListIter;
Plugin m_Plug;
HookManagerPubFunc m_Func;
int m_VtblOffs;
int m_VtblIdx;
const char *m_Proto;
void *m_HookfuncVfnptr;
VfnPtrList m_VfnPtrs;
int m_HookFuncVersion;
public:
virtual ~CHookManagerInfo();
IVfnPtr *FindVfnPtr(void *vfnptr);
void SetInfo(int vtbl_offs, int vtbl_idx, const char *proto);
void SetHookfuncVfnptr(void *hookfunc_vfnptr);
};
/**
* @brief A list of CHookManagerInfo classes
*/
typedef List<CHookManagerInfo> HookManInfoList;
class CCallClassImpl : public GenericCallClass
{
public:
typedef SourceHook::CVector<void*> OrigFuncs;
typedef SourceHook::THash<int, OrigFuncs> OrigVTables;
void *m_Ptr; //!< Pointer to the actual object
size_t m_ObjSize; //!< Size of the instance
OrigVTables m_VT; //!< Info about vtables & functions
int m_RefCounter;
CCallClassImpl(void *ptr, size_t size);
virtual ~CCallClassImpl();
bool operator==(void *other)
{
return m_Ptr == other;
}
void *GetThisPtr();
void *GetOrigFunc(int vtbloffs, int vtblidx);
void ApplyCallClassPatch(int vtbl_offs, int vtbl_idx, void *orig_entry);
void RemoveCallClassPatch(int vtbl_offs, int vtbl_idx);
};
/**
* @brief A list of CallClass structures
*/
typedef List<CCallClassImpl> Impl_CallClassList;
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;
bool recall; //!< True if we're in a recall, eh.
IIface *pCurIface;
const void *pOrigRet;
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
*/
HookManInfoList::iterator FindHookMan(HookManInfoList::iterator begin, HookManInfoList::iterator end,
const char *proto, int vtblofs, int vtblidx);
void ApplyCallClassPatches(CCallClassImpl &cc);
void ApplyCallClassPatches(void *ifaceptr, int vtbl_offs, int vtbl_idx, void *orig_entry);
void RemoveCallClassPatches(void *ifaceptr, int vtbl_offs, int vtbl_idx);
void SetPluginPaused(Plugin plug, bool paused);
bool ProtosEquiv(const char *p1, const char *p2);
HookLoopInfoStack m_HLIStack;
public:
CSourceHookImpl();
virtual ~CSourceHookImpl();
/**
* @brief Returns the interface version
*/
int GetIfaceVersion();
/**
* @brief Returns the implemnetation version
*/
int GetImplVersion();
/**
* @brief Make sure that a plugin is not used by any other plugins anymore, and unregister all its hook managers
*/
void UnloadPlugin(Plugin plug);
/**
* @brief Shut down the whole system, unregister all hook managers
*/
void CompleteShutdown();
/**
* @brief Add a hook.
*
* @return True if the function succeeded, false otherwise
*
* @param plug The unique identifier of the plugin that calls this function
* @param iface The interface pointer
* @param ifacesize The size of the class iface points to
* @param myHookMan A hook manager function that should be capable of handling the function
* @param handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post handler
*/
bool AddHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post);
/**
* @brief Removes a hook.
*
* @return True if the function succeeded, false otherwise
*
* @param plug The unique identifier of the plugin that calls this function
* @param iface The interface pointer
* @param thisptr_offs This pointer adjuster
* @param myHookMan A hook manager function that should be capable of handling the function
* @param handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post handler
*/
bool RemoveHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post);
/**
* @brief Removes a hook.
*
* @ return True if the function succeeded, false otherwise
*
* @param info A RemoveHookInfo structure, describing the hook
*/
bool RemoveHook(RemoveHookInfo info);
/**
* @brief Checks whether a plugin has (a) hook manager(s) that is/are currently used by other plugins
*
* @param plug The unique identifier of the plugin in question
*/
bool IsPluginInUse(Plugin plug);
/**
* @brief Pauses all hooks of a plugin
*
* @param plug The unique identifier of the plugin
*/
void PausePlugin(Plugin plug);
/**
* @brief Unpauses all hooks of a plugin
*
* @param plug The unique identifier of the plugin
*/
void UnpausePlugin(Plugin plug);
/**
* @brief Return a pointer to a callclass. Generate a new one if required.
*
* @param iface The interface pointer
* @param size Size of the class instance
*/
GenericCallClass *GetCallClass(void *iface, size_t size);
/**
* @brief Release a callclass
*
* @param ptr Pointer to the callclass
*/
virtual void ReleaseCallClass(GenericCallClass *ptr);
virtual void SetRes(META_RES res); //!< Sets the meta result
virtual META_RES GetPrevRes(); //!< Gets the meta result of the previously called handler
virtual META_RES GetStatus(); //!< Gets the highest meta result
virtual const void *GetOrigRet(); //!< Gets the original result. If not in post function, undefined
virtual const void *GetOverrideRet(); //!< Gets the override result. If none is specified, NULL
virtual void *GetIfacePtr(); //!< Gets the interface pointer
//////////////////////////////////////////////////////////////////////////
// For hook managers
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(void *ptr); //!< Sets the override result pointer
bool ShouldContinue(); //!< Returns false if the hook loop should exit
/**
* @brief Remove a hook manager. Auto-removes all hooks attached to it from plugin plug.
*
* @param plug The owner of the hook manager
* @param pubFunc The hook manager's info function
*/
virtual void RemoveHookManager(Plugin plug, HookManagerPubFunc pubFunc);
virtual void DoRecall(); //!< Initiates a recall sequence
virtual void *GetOverrideRetPtr(); //!< Returns the pointer set by SetOverrideRetPtr
virtual void *SetupHookLoop(META_RES *statusPtr, META_RES *prevResPtr, META_RES *curResPtr,
void **ifacePtrPtr, const void *origRetPtr, void *overrideRetPtr);
};
}
#endif