3 * ===============================================================
4 * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
5 * ===============================================================
7 * This file is not open source and may not be copied without explicit
8 * written permission of AlliedModders LLC. This file may not be redistributed
9 * in whole or significant part.
10 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
16 #include <sh_string.h>
18 #include "sm_globals.h"
19 #include "PluginSys.h"
20 #include "sourcemod.h"
21 #include "sm_stringutil.h"
23 using namespace SourceHook;
25 static cell_t s_curparams[SP_MAX_EXEC_PARAMS+1];
26 static FakeNative *s_curnative = NULL;
27 static IPluginContext *s_curcaller = NULL;
29 cell_t FakeNativeRouter(IPluginContext *pContext, const cell_t *params, void *pData)
31 FakeNative *native = (FakeNative *)pData;
33 /* Check if too many parameters were passed */
34 if (params[0] > SP_MAX_EXEC_PARAMS)
36 return pContext->ThrowNativeError("Called native with too many parameters (%d>%d)", params[9], SP_MAX_EXEC_PARAMS);
39 /* Check if the native is paused */
40 sp_context_t *pNativeCtx = native->ctx->GetContext();
41 if ((pNativeCtx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
43 return pContext->ThrowNativeError("Plugin owning this native is currently paused.");
46 CPlugin *pCaller = g_PluginSys.GetPluginByCtx(pContext->GetContext());
48 /* Save any old data on the stack */
49 FakeNative *pSaveNative = s_curnative;
50 IPluginContext *pSaveCaller = s_curcaller;
51 cell_t save_params[SP_MAX_EXEC_PARAMS+1];
52 if (pSaveNative != NULL)
54 /* Copy all old parameters */
55 for (cell_t i=0; i<=s_curparams[0]; i++)
57 save_params[i] = s_curparams[i];
61 /* Save the current parameters */
63 s_curcaller = pContext;
64 for (cell_t i=0; i<=params[0]; i++)
66 s_curparams[i] = params[i];
69 /* Push info and execute. */
71 native->call->PushCell(pCaller->GetMyHandle());
72 native->call->PushCell(params[0]);
74 if ((error=native->call->Execute(&result)) != SP_ERROR_NONE)
76 if (pContext->GetContext()->n_err == SP_ERROR_NONE)
78 pContext->ThrowNativeErrorEx(error, "Error encountered while processing a dynamic native");
82 /* Restore everything from the stack if necessary */
83 s_curnative = pSaveNative;
84 s_curcaller = pSaveCaller;
85 if (pSaveNative != NULL)
87 for (cell_t i=0; i<=save_params[0]; i++)
89 s_curparams[i] = save_params[i];
96 static cell_t CreateNative(IPluginContext *pContext, const cell_t *params)
99 pContext->LocalToString(params[1], &name);
101 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
104 return pContext->ThrowNativeError("Function %x is not a valid function", params[2]);
107 if (!g_PluginSys.AddFakeNative(pFunction, name, FakeNativeRouter))
109 return pContext->ThrowNativeError("Fatal error creating dynamic native!");
115 static cell_t ThrowNativeError(IPluginContext *pContext, const cell_t *params)
117 if (!s_curnative || (s_curnative->ctx != pContext))
119 return pContext->ThrowNativeError("Not called from inside a native function");
122 g_SourceMod.SetGlobalTarget(LANG_SERVER);
126 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
128 if (pContext->GetContext()->n_err != SP_ERROR_NONE)
130 s_curcaller->ThrowNativeError("Error encountered while processing a dynamic native");
132 s_curcaller->ThrowNativeErrorEx(params[1], "%s", buffer);
138 static cell_t GetNativeStringLength(IPluginContext *pContext, const cell_t *params)
140 if (!s_curnative || (s_curnative->ctx != pContext))
142 return pContext->ThrowNativeError("Not called from inside a native function");
145 cell_t param = params[1];
146 if (param < 1 || param > s_curparams[0])
148 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
153 if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE)
159 pContext->LocalToPhysAddr(params[2], &addr);
160 *addr = (cell_t)strlen(str);
162 return SP_ERROR_NONE;
165 static cell_t GetNativeString(IPluginContext *pContext, const cell_t *params)
167 if (!s_curnative || (s_curnative->ctx != pContext))
169 return pContext->ThrowNativeError("Not called from inside a native function");
172 cell_t param = params[1];
173 if (param < 1 || param > s_curparams[0])
175 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
180 if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE)
186 pContext->StringToLocalUTF8(params[2], params[3], str, &bytes);
189 pContext->LocalToPhysAddr(params[4], &addr);
190 *addr = (cell_t)bytes;
192 return SP_ERROR_NONE;
195 static cell_t SetNativeString(IPluginContext *pContext, const cell_t *params)
197 if (!s_curnative || (s_curnative->ctx != pContext))
199 return pContext->ThrowNativeError("Not called from inside a native function");
202 cell_t param = params[1];
203 if (param < 1 || param > s_curparams[0])
205 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
209 pContext->LocalToString(params[2], &str);
215 err = s_curcaller->StringToLocalUTF8(s_curparams[param], params[3], str, &bytes);
217 err = s_curcaller->StringToLocal(s_curparams[param], params[3], str);
220 if (bytes >= (size_t)params[3])
222 bytes = params[3] - 1;
226 if (err != SP_ERROR_NONE)
232 pContext->LocalToPhysAddr(params[5], &addr);
233 *addr = (cell_t)bytes;
235 return SP_ERROR_NONE;
238 static cell_t GetNativeCell(IPluginContext *pContext, const cell_t *params)
240 if (!s_curnative || (s_curnative->ctx != pContext))
242 return pContext->ThrowNativeError("Not called from inside a native function");
245 cell_t param = params[1];
246 if (param < 1 || param > s_curparams[0])
248 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
251 return s_curparams[param];
254 static cell_t GetNativeCellRef(IPluginContext *pContext, const cell_t *params)
256 if (!s_curnative || (s_curnative->ctx != pContext))
258 return pContext->ThrowNativeError("Not called from inside a native function");
261 cell_t param = params[1];
262 if (param < 1 || param > s_curparams[0])
264 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
268 if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE)
270 return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value");
276 static cell_t SetNativeCellRef(IPluginContext *pContext, const cell_t *params)
278 if (!s_curnative || (s_curnative->ctx != pContext))
280 return pContext->ThrowNativeError("Not called from inside a native function");
283 cell_t param = params[1];
284 if (param < 1 || param > s_curparams[0])
286 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
290 if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE)
292 return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value");
300 static cell_t GetNativeArray(IPluginContext *pContext, const cell_t *params)
302 if (!s_curnative || (s_curnative->ctx != pContext))
304 return pContext->ThrowNativeError("Not called from inside a native function");
307 cell_t param = params[1];
308 if (param < 1 || param > s_curparams[0])
310 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
315 if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
321 pContext->LocalToPhysAddr(params[2], &src);
323 memcpy(src, addr, sizeof(cell_t) * params[3]);
325 return SP_ERROR_NONE;
328 static cell_t SetNativeArray(IPluginContext *pContext, const cell_t *params)
330 if (!s_curnative || (s_curnative->ctx != pContext))
332 return pContext->ThrowNativeError("Not called from inside a native function");
335 cell_t param = params[1];
336 if (param < 1 || param > s_curparams[0])
338 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
343 if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
349 pContext->LocalToPhysAddr(params[2], &src);
351 memcpy(addr, src, sizeof(cell_t) * params[3]);
353 return SP_ERROR_NONE;
356 static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params)
358 if (!s_curnative || (s_curnative->ctx != pContext))
360 return pContext->ThrowNativeError("Not called from inside a native function");
363 int out_param = params[1];
364 int fmt_param = params[2];
365 int var_param = params[3];
368 if (out_param && (out_param < 1 || out_param > s_curparams[0]))
370 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", out_param);
372 if (fmt_param && (fmt_param < 1 || fmt_param > s_curparams[0]))
374 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param);
376 if (var_param && (var_param < 1 || var_param > s_curparams[0] + 1))
378 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param);
381 /* Get buffer information */
388 if ((err=s_curcaller->LocalToString(s_curparams[out_param], &output_buffer)) != SP_ERROR_NONE)
393 pContext->LocalToString(params[6], &output_buffer);
398 if ((err=s_curcaller->LocalToString(s_curparams[fmt_param], &format_buffer)) != SP_ERROR_NONE)
403 pContext->LocalToString(params[7], &format_buffer);
406 /* Get maximum length */
407 size_t maxlen = (size_t)params[4];
410 size_t written = atcprintf(output_buffer, maxlen, format_buffer, s_curcaller, s_curparams, &var_param);
413 pContext->LocalToPhysAddr(params[5], &addr);
414 *addr = (cell_t)written;
416 return s_curcaller->GetContext()->n_err;
420 REGISTER_NATIVES(nativeNatives)
422 {"CreateNative", CreateNative},
423 {"GetNativeArray", GetNativeArray},
424 {"GetNativeCell", GetNativeCell},
425 {"GetNativeCellRef", GetNativeCellRef},
426 {"GetNativeString", GetNativeString},
427 {"GetNativeStringLength", GetNativeStringLength},
428 {"FormatNativeString", FormatNativeString},
429 {"ThrowNativeError", ThrowNativeError},
430 {"SetNativeArray", SetNativeArray},
431 {"SetNativeCellRef", SetNativeCellRef},
432 {"SetNativeString", SetNativeString},