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]);
73 if (native->call->Execute(&result) != SP_ERROR_NONE)
75 if (pContext->GetContext()->n_err == SP_ERROR_NONE)
77 pContext->ThrowNativeError("Error encountered while processing a dynamic native");
81 /* Restore everything from the stack if necessary */
82 s_curnative = pSaveNative;
83 s_curcaller = pSaveCaller;
84 if (pSaveNative != NULL)
86 for (cell_t i=0; i<=save_params[0]; i++)
88 s_curparams[i] = save_params[i];
95 static cell_t CreateNative(IPluginContext *pContext, const cell_t *params)
98 pContext->LocalToString(params[1], &name);
100 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
103 return pContext->ThrowNativeError("Function %x is not a valid function", params[2]);
106 if (!g_PluginSys.AddFakeNative(pFunction, name, FakeNativeRouter))
108 return pContext->ThrowNativeError("Fatal error creating dynamic native!");
114 static cell_t ThrowNativeError(IPluginContext *pContext, const cell_t *params)
116 if (!s_curnative || (s_curnative->ctx != pContext))
118 return pContext->ThrowNativeError("Not called from inside a native function");
123 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
125 if (pContext->GetContext()->n_err != SP_ERROR_NONE)
127 s_curcaller->ThrowNativeError("Error encountered while processing a dynamic native");
129 s_curcaller->ThrowNativeErrorEx(params[1], "%s", buffer);
135 static cell_t GetNativeStringLength(IPluginContext *pContext, const cell_t *params)
137 if (!s_curnative || (s_curnative->ctx != pContext))
139 return pContext->ThrowNativeError("Not called from inside a native function");
142 cell_t param = params[1];
143 if (param < 1 || param > s_curparams[0])
145 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
150 if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE)
156 pContext->LocalToPhysAddr(params[2], &addr);
157 *addr = (cell_t)strlen(str);
159 return SP_ERROR_NONE;
162 static cell_t GetNativeString(IPluginContext *pContext, const cell_t *params)
164 if (!s_curnative || (s_curnative->ctx != pContext))
166 return pContext->ThrowNativeError("Not called from inside a native function");
169 cell_t param = params[1];
170 if (param < 1 || param > s_curparams[0])
172 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
177 if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE)
183 pContext->StringToLocalUTF8(params[2], params[3], str, &bytes);
186 pContext->LocalToPhysAddr(params[4], &addr);
187 *addr = (cell_t)bytes;
189 return SP_ERROR_NONE;
192 static cell_t SetNativeString(IPluginContext *pContext, const cell_t *params)
194 if (!s_curnative || (s_curnative->ctx != pContext))
196 return pContext->ThrowNativeError("Not called from inside a native function");
199 cell_t param = params[1];
200 if (param < 1 || param > s_curparams[0])
202 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
206 pContext->LocalToString(params[2], &str);
212 err = s_curcaller->StringToLocalUTF8(s_curparams[param], params[3], str, &bytes);
214 err = s_curcaller->StringToLocal(s_curparams[param], params[3], str);
217 if (bytes >= (size_t)params[3])
219 bytes = params[3] - 1;
223 if (err != SP_ERROR_NONE)
229 pContext->LocalToPhysAddr(params[5], &addr);
230 *addr = (cell_t)bytes;
232 return SP_ERROR_NONE;
235 static cell_t GetNativeCell(IPluginContext *pContext, const cell_t *params)
237 if (!s_curnative || (s_curnative->ctx != pContext))
239 return pContext->ThrowNativeError("Not called from inside a native function");
242 cell_t param = params[1];
243 if (param < 1 || param > s_curparams[0])
245 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
248 return s_curparams[param];
251 static cell_t GetNativeCellRef(IPluginContext *pContext, const cell_t *params)
253 if (!s_curnative || (s_curnative->ctx != pContext))
255 return pContext->ThrowNativeError("Not called from inside a native function");
258 cell_t param = params[1];
259 if (param < 1 || param > s_curparams[0])
261 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
265 if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE)
267 return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value");
273 static cell_t SetNativeCellRef(IPluginContext *pContext, const cell_t *params)
275 if (!s_curnative || (s_curnative->ctx != pContext))
277 return pContext->ThrowNativeError("Not called from inside a native function");
280 cell_t param = params[1];
281 if (param < 1 || param > s_curparams[0])
283 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
287 if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE)
289 return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value");
297 static cell_t GetNativeArray(IPluginContext *pContext, const cell_t *params)
299 if (!s_curnative || (s_curnative->ctx != pContext))
301 return pContext->ThrowNativeError("Not called from inside a native function");
304 cell_t param = params[1];
305 if (param < 1 || param > s_curparams[0])
307 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
312 if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
318 pContext->LocalToPhysAddr(params[2], &src);
320 memcpy(src, addr, sizeof(cell_t) * params[3]);
322 return SP_ERROR_NONE;
325 static cell_t SetNativeArray(IPluginContext *pContext, const cell_t *params)
327 if (!s_curnative || (s_curnative->ctx != pContext))
329 return pContext->ThrowNativeError("Not called from inside a native function");
332 cell_t param = params[1];
333 if (param < 1 || param > s_curparams[0])
335 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
340 if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
346 pContext->LocalToPhysAddr(params[2], &src);
348 memcpy(addr, src, sizeof(cell_t) * params[3]);
350 return SP_ERROR_NONE;
353 static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params)
355 if (!s_curnative || (s_curnative->ctx != pContext))
357 return pContext->ThrowNativeError("Not called from inside a native function");
360 int out_param = params[1];
361 int fmt_param = params[2];
362 int var_param = params[3];
365 if (out_param && (out_param < 1 || out_param > s_curparams[0]))
367 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", out_param);
369 if (fmt_param && (fmt_param < 1 || fmt_param > s_curparams[0]))
371 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param);
373 if (var_param && (var_param < 1 || var_param > s_curparams[0] + 1))
375 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param);
378 /* Get buffer information */
385 if ((err=s_curcaller->LocalToString(s_curparams[out_param], &output_buffer)) != SP_ERROR_NONE)
390 pContext->LocalToString(params[6], &output_buffer);
395 if ((err=s_curcaller->LocalToString(s_curparams[fmt_param], &format_buffer)) != SP_ERROR_NONE)
400 pContext->LocalToString(params[7], &format_buffer);
403 /* Get maximum length */
404 size_t maxlen = (size_t)params[4];
407 size_t written = atcprintf(output_buffer, maxlen, format_buffer, s_curcaller, s_curparams, &var_param);
410 pContext->LocalToPhysAddr(params[5], &addr);
411 *addr = (cell_t)written;
413 return s_curcaller->GetContext()->n_err;
417 REGISTER_NATIVES(nativeNatives)
419 {"CreateNative", CreateNative},
420 {"GetNativeArray", GetNativeArray},
421 {"GetNativeCell", GetNativeCell},
422 {"GetNativeCellRef", GetNativeCellRef},
423 {"GetNativeString", GetNativeString},
424 {"GetNativeStringLength", GetNativeStringLength},
425 {"FormatNativeString", FormatNativeString},
426 {"ThrowNativeError", ThrowNativeError},
427 {"SetNativeArray", SetNativeArray},
428 {"SetNativeCellRef", SetNativeCellRef},
429 {"SetNativeString", SetNativeString},