Merge pull request #672 from peace-maker/null_natives_fixed
Add natives to check for NULL_VECTOR and NULL_STRING
This commit is contained in:
commit
4bab834716
@ -269,21 +269,9 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
|
||||
if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
|
||||
{
|
||||
/* If we're byref or we're vararg, we always push everything by ref.
|
||||
* Even if they're byval, we must push them byref.
|
||||
*/
|
||||
if (type == Param_String)
|
||||
{
|
||||
err = func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
|
||||
}
|
||||
else if (type == Param_Float || type == Param_Cell)
|
||||
{
|
||||
err = func->PushCellByRef(¶m->val);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags);
|
||||
assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
|
||||
}
|
||||
* Even if they're byval, we must push them byref.
|
||||
*/
|
||||
err = _ExecutePushRef(func, type, param);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -382,6 +370,58 @@ done:
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int CForward::_ExecutePushRef(IPluginFunction *func, ParamType type, FwdParamInfo *param)
|
||||
{
|
||||
/* If we're byref or we're vararg, we always push everything by ref.
|
||||
* Even if they're byval, we must push them byref.
|
||||
*/
|
||||
int err;
|
||||
IPluginRuntime *runtime = func->GetParentRuntime();
|
||||
switch (type)
|
||||
{
|
||||
case Param_String:
|
||||
// Normal string was pushed.
|
||||
if (!param->isnull)
|
||||
return func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
|
||||
|
||||
// If NULL_STRING was pushed, push the reference to the pubvar of the callee instead.
|
||||
uint32_t null_string_idx;
|
||||
err = runtime->FindPubvarByName("NULL_STRING", &null_string_idx);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
cell_t null_string;
|
||||
err = runtime->GetPubvarAddrs(null_string_idx, &null_string, nullptr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return func->PushCell(null_string);
|
||||
|
||||
case Param_Float:
|
||||
case Param_Cell:
|
||||
return func->PushCellByRef(¶m->val);
|
||||
|
||||
default:
|
||||
assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
|
||||
// No NULL_VECTOR was pushed.
|
||||
if (type != Param_Array || !param->isnull)
|
||||
return func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags);
|
||||
|
||||
// If NULL_VECTOR was pushed, push the reference to the pubvar of the callee instead.
|
||||
uint32_t null_vector_idx;
|
||||
err = runtime->FindPubvarByName("NULL_VECTOR", &null_vector_idx);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
cell_t null_vector;
|
||||
err = runtime->GetPubvarAddrs(null_vector_idx, &null_vector, nullptr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return func->PushCell(null_vector);
|
||||
}
|
||||
}
|
||||
|
||||
int CForward::PushCell(cell_t cell)
|
||||
{
|
||||
if (m_curparam < m_numparams)
|
||||
@ -400,6 +440,7 @@ int CForward::PushCell(cell_t cell)
|
||||
m_params[m_curparam].pushedas = Param_Cell;
|
||||
}
|
||||
|
||||
m_params[m_curparam].isnull = false;
|
||||
m_params[m_curparam++].val = cell;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
@ -423,6 +464,7 @@ int CForward::PushFloat(float number)
|
||||
m_params[m_curparam].pushedas = Param_Float;
|
||||
}
|
||||
|
||||
m_params[m_curparam].isnull = false;
|
||||
m_params[m_curparam++].val = *(cell_t *)&number;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
@ -481,14 +523,22 @@ void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
|
||||
m_params[m_curparam].byref.cells = cells;
|
||||
m_params[m_curparam].byref.flags = flags;
|
||||
m_params[m_curparam].byref.orig_addr = inarray;
|
||||
m_params[m_curparam].isnull = false;
|
||||
}
|
||||
|
||||
int CForward::PushArray(cell_t *inarray, unsigned int cells, int flags)
|
||||
{
|
||||
/* We don't allow this here */
|
||||
/* Push a reference to the NULL_VECTOR pubvar if NULL was passed. */
|
||||
if (!inarray)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAM);
|
||||
/* Make sure this was intentional. */
|
||||
if (cells == 3)
|
||||
{
|
||||
return PushNullVector();
|
||||
} else {
|
||||
/* We don't allow this here */
|
||||
return SetError(SP_ERROR_PARAM);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_curparam < m_numparams)
|
||||
@ -520,10 +570,17 @@ void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags
|
||||
m_params[m_curparam].byref.flags = cp_flags;
|
||||
m_params[m_curparam].byref.orig_addr = inarray;
|
||||
m_params[m_curparam].byref.sz_flags = sz_flags;
|
||||
m_params[m_curparam].isnull = false;
|
||||
}
|
||||
|
||||
int CForward::PushString(const char *string)
|
||||
{
|
||||
/* Push a reference to the NULL_STRING pubvar if NULL was passed. */
|
||||
if (!string)
|
||||
{
|
||||
return PushNullString();
|
||||
}
|
||||
|
||||
if (m_curparam < m_numparams)
|
||||
{
|
||||
if (m_types[m_curparam] == Param_Any)
|
||||
@ -570,6 +627,52 @@ int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_fla
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int CForward::PushNullString()
|
||||
{
|
||||
if (m_curparam < m_numparams)
|
||||
{
|
||||
if (m_types[m_curparam] == Param_Any)
|
||||
{
|
||||
m_params[m_curparam].pushedas = Param_String;
|
||||
} else if (m_types[m_curparam] != Param_String) {
|
||||
return SetError(SP_ERROR_PARAM);
|
||||
}
|
||||
} else {
|
||||
if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
m_params[m_curparam].pushedas = Param_String;
|
||||
}
|
||||
|
||||
m_params[m_curparam++].isnull = true;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int CForward::PushNullVector()
|
||||
{
|
||||
if (m_curparam < m_numparams)
|
||||
{
|
||||
if (m_types[m_curparam] == Param_Any)
|
||||
{
|
||||
m_params[m_curparam].pushedas = Param_Array;
|
||||
} else if (m_types[m_curparam] != Param_Array) {
|
||||
return SetError(SP_ERROR_PARAM);
|
||||
}
|
||||
} else {
|
||||
if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
m_params[m_curparam].pushedas = Param_Array;
|
||||
}
|
||||
|
||||
m_params[m_curparam++].isnull = true;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
void CForward::Cancel()
|
||||
{
|
||||
if (!m_curparam)
|
||||
|
@ -72,6 +72,9 @@ private:
|
||||
CForward(ExecType et, const char *name,
|
||||
const ParamType *types, unsigned num_params);
|
||||
|
||||
int PushNullString();
|
||||
int PushNullVector();
|
||||
int _ExecutePushRef(IPluginFunction *func, ParamType type, FwdParamInfo *param);
|
||||
void _Int_PushArray(cell_t *inarray, unsigned int cells, int flags);
|
||||
void _Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags);
|
||||
inline int SetError(int err)
|
||||
|
@ -759,6 +759,27 @@ static cell_t StoreToAddress(IPluginContext *pContext, const cell_t *params)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cell_t IsNullVector(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
cell_t *pNullVec = pContext->GetNullRef(SP_NULL_VECTOR);
|
||||
if (!pNullVec)
|
||||
return 0;
|
||||
|
||||
cell_t *addr;
|
||||
pContext->LocalToPhysAddr(params[1], &addr);
|
||||
|
||||
return addr == pNullVec;
|
||||
}
|
||||
|
||||
static cell_t IsNullString(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
char *str;
|
||||
if (pContext->LocalToStringNULL(params[1], &str) != SP_ERROR_NONE)
|
||||
return 0;
|
||||
|
||||
return str == nullptr;
|
||||
}
|
||||
|
||||
REGISTER_NATIVES(coreNatives)
|
||||
{
|
||||
{"ThrowError", ThrowError},
|
||||
@ -787,5 +808,7 @@ REGISTER_NATIVES(coreNatives)
|
||||
{"RequireFeature", RequireFeature},
|
||||
{"LoadFromAddress", LoadFromAddress},
|
||||
{"StoreToAddress", StoreToAddress},
|
||||
{"IsNullVector", IsNullVector},
|
||||
{"IsNullString", IsNullString},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
@ -424,6 +424,58 @@ static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params)
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
static cell_t IsNativeParamNullVector(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
if (!s_curnative || (s_curnative->ctx != pContext))
|
||||
{
|
||||
return pContext->ThrowNativeError("Not called from inside a native function");
|
||||
}
|
||||
|
||||
cell_t param = params[1];
|
||||
if (param < 1 || param > s_curparams[0])
|
||||
{
|
||||
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
|
||||
}
|
||||
|
||||
int err;
|
||||
cell_t *addr;
|
||||
if ((err = s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
cell_t *pNullVec = s_curcaller->GetNullRef(SP_NULL_VECTOR);
|
||||
if (!pNullVec)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return addr == pNullVec ? 1 : 0;
|
||||
}
|
||||
|
||||
static cell_t IsNativeParamNullString(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
if (!s_curnative || (s_curnative->ctx != pContext))
|
||||
{
|
||||
return pContext->ThrowNativeError("Not called from inside a native function");
|
||||
}
|
||||
|
||||
cell_t param = params[1];
|
||||
if (param < 1 || param > s_curparams[0])
|
||||
{
|
||||
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
|
||||
}
|
||||
|
||||
int err;
|
||||
char *str;
|
||||
if ((err = s_curcaller->LocalToStringNULL(s_curparams[param], &str)) != SP_ERROR_NONE)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
return str == nullptr ? 1 : 0;
|
||||
}
|
||||
|
||||
//tee hee
|
||||
REGISTER_NATIVES(nativeNatives)
|
||||
{
|
||||
@ -439,5 +491,7 @@ REGISTER_NATIVES(nativeNatives)
|
||||
{"SetNativeArray", SetNativeArray},
|
||||
{"SetNativeCellRef", SetNativeCellRef},
|
||||
{"SetNativeString", SetNativeString},
|
||||
{"IsNativeParamNullVector", IsNativeParamNullVector},
|
||||
{"IsNativeParamNullString", IsNativeParamNullString},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
@ -552,6 +552,88 @@ static cell_t sm_CallPushStringEx(IPluginContext *pContext, const cell_t *params
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t sm_CallPushNullVector(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
int err = SP_ERROR_NOT_FOUND;
|
||||
|
||||
if (!s_CallStarted)
|
||||
{
|
||||
return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
|
||||
}
|
||||
|
||||
if (s_pFunction)
|
||||
{
|
||||
// Find the NULL_VECTOR pubvar in the target plugin and push the local address.
|
||||
IPluginRuntime *runtime = s_pFunction->GetParentRuntime();
|
||||
uint32_t null_vector_idx;
|
||||
err = runtime->FindPubvarByName("NULL_VECTOR", &null_vector_idx);
|
||||
if (err)
|
||||
{
|
||||
return pContext->ThrowNativeErrorEx(err, "Target plugin has no NULL_VECTOR.");
|
||||
}
|
||||
|
||||
cell_t null_vector;
|
||||
err = runtime->GetPubvarAddrs(null_vector_idx, &null_vector, nullptr);
|
||||
|
||||
if (!err)
|
||||
err = s_pCallable->PushCell(null_vector);
|
||||
}
|
||||
else if (s_pForward)
|
||||
{
|
||||
err = s_pForward->PushArray(NULL, 3);
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
s_pCallable->Cancel();
|
||||
ResetCall();
|
||||
return pContext->ThrowNativeErrorEx(err, NULL);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t sm_CallPushNullString(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
int err = SP_ERROR_NOT_FOUND;
|
||||
|
||||
if (!s_CallStarted)
|
||||
{
|
||||
return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
|
||||
}
|
||||
|
||||
if (s_pFunction)
|
||||
{
|
||||
// Find the NULL_STRING pubvar in the target plugin and push the local address.
|
||||
IPluginRuntime *runtime = s_pFunction->GetParentRuntime();
|
||||
uint32_t null_string_idx;
|
||||
err = runtime->FindPubvarByName("NULL_STRING", &null_string_idx);
|
||||
if (err)
|
||||
{
|
||||
return pContext->ThrowNativeErrorEx(err, "Target plugin has no NULL_STRING.");
|
||||
}
|
||||
|
||||
cell_t null_string;
|
||||
err = runtime->GetPubvarAddrs(null_string_idx, &null_string, nullptr);
|
||||
|
||||
if (!err)
|
||||
err = s_pCallable->PushCell(null_string);
|
||||
}
|
||||
else if (s_pForward)
|
||||
{
|
||||
err = s_pForward->PushString(NULL);
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
s_pCallable->Cancel();
|
||||
ResetCall();
|
||||
return pContext->ThrowNativeErrorEx(err, NULL);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t sm_CallFinish(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
int err = SP_ERROR_NOT_RUNNABLE;
|
||||
@ -668,6 +750,8 @@ REGISTER_NATIVES(functionNatives)
|
||||
{"Call_PushArrayEx", sm_CallPushArrayEx},
|
||||
{"Call_PushString", sm_CallPushString},
|
||||
{"Call_PushStringEx", sm_CallPushStringEx},
|
||||
{"Call_PushNullVector", sm_CallPushNullVector},
|
||||
{"Call_PushNullString", sm_CallPushNullString},
|
||||
{"Call_Finish", sm_CallFinish},
|
||||
{"Call_Cancel", sm_CallCancel},
|
||||
{"RequestFrame", sm_AddFrameAction},
|
||||
|
@ -143,6 +143,22 @@ struct SharedPlugin
|
||||
public float NULL_VECTOR[3]; /**< Pass this into certain functions to act as a C++ NULL */
|
||||
public const char NULL_STRING[1]; /**< pass this into certain functions to act as a C++ NULL */
|
||||
|
||||
/**
|
||||
* Check if the given vector is the NULL_VECTOR.
|
||||
*
|
||||
* @param vec The vector to test.
|
||||
* @return True if NULL_VECTOR, false otherwise.
|
||||
*/
|
||||
native bool IsNullVector(const float vec[3]);
|
||||
|
||||
/**
|
||||
* Check if the given string is the NULL_STRING.
|
||||
*
|
||||
* @param str The string to test.
|
||||
* @return True if NULL_STRING, false otherwise.
|
||||
*/
|
||||
native bool IsNullString(const char[] str);
|
||||
|
||||
/**
|
||||
* Horrible compatibility shim.
|
||||
*/
|
||||
|
@ -290,6 +290,16 @@ native void Call_PushArray(const any[] value, int size);
|
||||
*/
|
||||
native void Call_PushArrayEx(any[] value, int size, int cpflags);
|
||||
|
||||
/**
|
||||
* Pushes the NULL_VECTOR onto the current call.
|
||||
* @see IsNullVector
|
||||
*
|
||||
* @note Cannot be used before a call has been started.
|
||||
*
|
||||
* @error Called before a call has been started.
|
||||
*/
|
||||
native void Call_PushNullVector();
|
||||
|
||||
/**
|
||||
* Pushes a string onto the current call.
|
||||
*
|
||||
@ -317,6 +327,16 @@ native void Call_PushString(const char[] value);
|
||||
*/
|
||||
native void Call_PushStringEx(char[] value, int length, int szflags, int cpflags);
|
||||
|
||||
/**
|
||||
* Pushes the NULL_STRING onto the current call.
|
||||
* @see IsNullString
|
||||
*
|
||||
* @note Cannot be used before a call has been started.
|
||||
*
|
||||
* @error Called before a call has been started.
|
||||
*/
|
||||
native void Call_PushNullString();
|
||||
|
||||
/**
|
||||
* Completes a call to a function or forward's call list.
|
||||
*
|
||||
@ -465,6 +485,22 @@ native int GetNativeArray(int param, any[] local, int size);
|
||||
*/
|
||||
native int SetNativeArray(int param, const any[] local, int size);
|
||||
|
||||
/**
|
||||
* Check if the native parameter is the NULL_VECTOR.
|
||||
*
|
||||
* @param param Parameter number, starting from 1.
|
||||
* @return True if NULL_VECTOR, false otherwise.
|
||||
*/
|
||||
native bool IsNativeParamNullVector(int param);
|
||||
|
||||
/**
|
||||
* Check if the native parameter is the NULL_STRING.
|
||||
*
|
||||
* @param param Parameter number, starting from 1.
|
||||
* @return True if NULL_STRING, false otherwise.
|
||||
*/
|
||||
native bool IsNativeParamNullString(int param);
|
||||
|
||||
/**
|
||||
* Formats a string using parameters from a native.
|
||||
*
|
||||
|
@ -50,7 +50,7 @@
|
||||
using namespace SourcePawn;
|
||||
|
||||
#define SMINTERFACE_FORWARDMANAGER_NAME "IForwardManager"
|
||||
#define SMINTERFACE_FORWARDMANAGER_VERSION 3
|
||||
#define SMINTERFACE_FORWARDMANAGER_VERSION 4
|
||||
|
||||
/*
|
||||
* There is some very important documentation at the bottom of this file.
|
||||
@ -118,6 +118,7 @@ namespace SourceMod
|
||||
cell_t val;
|
||||
ByrefInfo byref;
|
||||
ParamType pushedas;
|
||||
bool isnull;
|
||||
};
|
||||
|
||||
class IForwardFilter
|
||||
@ -177,12 +178,21 @@ namespace SourceMod
|
||||
* @brief Pushes an array of cells onto the current call. Different rules than ICallable.
|
||||
* NOTE: On Execute, the pointer passed will be modified according to the copyback rule.
|
||||
*
|
||||
* @param inarray Array to copy. Cannot be NULL, unlike ICallable's version.
|
||||
* @param inarray Array to copy. If NULL and cells is 3 pushes a reference to the NULL_VECTOR pubvar to each callee.
|
||||
* Pushing other number of cells is not allowed, unlike ICallable's version.
|
||||
* @param cells Number of cells to allocate and optionally read from the input array.
|
||||
* @param flags Whether or not changes should be copied back to the input array.
|
||||
* @return Error code, if any.
|
||||
*/
|
||||
virtual int PushArray(cell_t *inarray, unsigned int cells, int flags=0) =0;
|
||||
|
||||
/**
|
||||
* @brief Pushes a string onto the current call.
|
||||
*
|
||||
* @param string String to push. If NULL pushes a reference to the NULL_STRING pubvar to each callee.
|
||||
* @return Error code, if any.
|
||||
*/
|
||||
virtual int PushString(const char *string) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user