3 * =============================================================================
5 * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
33 #include <sh_string.h>
35 #include "sm_globals.h"
36 #include "PluginSys.h"
37 #include "sourcemod.h"
38 #include "sm_stringutil.h"
40 using namespace SourceHook;
42 static cell_t s_curparams[SP_MAX_EXEC_PARAMS+1];
43 static FakeNative *s_curnative = NULL;
44 static IPluginContext *s_curcaller = NULL;
46 cell_t FakeNativeRouter(IPluginContext *pContext, const cell_t *params, void *pData)
48 FakeNative *native = (FakeNative *)pData;
50 /* Check if too many parameters were passed */
51 if (params[0] > SP_MAX_EXEC_PARAMS)
53 return pContext->ThrowNativeError("Called native with too many parameters (%d>%d)", params[9], SP_MAX_EXEC_PARAMS);
56 /* Check if the native is paused */
57 sp_context_t *pNativeCtx = native->ctx->GetContext();
58 if ((pNativeCtx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
60 return pContext->ThrowNativeError("Plugin owning this native is currently paused.");
63 CPlugin *pCaller = g_PluginSys.GetPluginByCtx(pContext->GetContext());
65 /* Save any old data on the stack */
66 FakeNative *pSaveNative = s_curnative;
67 IPluginContext *pSaveCaller = s_curcaller;
68 cell_t save_params[SP_MAX_EXEC_PARAMS+1];
69 if (pSaveNative != NULL)
71 /* Copy all old parameters */
72 for (cell_t i=0; i<=s_curparams[0]; i++)
74 save_params[i] = s_curparams[i];
78 /* Save the current parameters */
80 s_curcaller = pContext;
81 for (cell_t i=0; i<=params[0]; i++)
83 s_curparams[i] = params[i];
86 /* Push info and execute. */
88 native->call->PushCell(pCaller->GetMyHandle());
89 native->call->PushCell(params[0]);
91 if ((error=native->call->Execute(&result)) != SP_ERROR_NONE)
93 if (pContext->GetContext()->n_err == SP_ERROR_NONE)
95 pContext->ThrowNativeErrorEx(error, "Error encountered while processing a dynamic native");
99 /* Restore everything from the stack if necessary */
100 s_curnative = pSaveNative;
101 s_curcaller = pSaveCaller;
102 if (pSaveNative != NULL)
104 for (cell_t i=0; i<=save_params[0]; i++)
106 s_curparams[i] = save_params[i];
113 static cell_t CreateNative(IPluginContext *pContext, const cell_t *params)
116 pContext->LocalToString(params[1], &name);
118 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
121 return pContext->ThrowNativeError("Function %x is not a valid function", params[2]);
124 if (!g_PluginSys.AddFakeNative(pFunction, name, FakeNativeRouter))
126 return pContext->ThrowNativeError("Fatal error creating dynamic native!");
132 static cell_t ThrowNativeError(IPluginContext *pContext, const cell_t *params)
134 if (!s_curnative || (s_curnative->ctx != pContext))
136 return pContext->ThrowNativeError("Not called from inside a native function");
139 g_SourceMod.SetGlobalTarget(LANG_SERVER);
143 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
145 if (pContext->GetContext()->n_err != SP_ERROR_NONE)
147 s_curcaller->ThrowNativeError("Error encountered while processing a dynamic native");
149 s_curcaller->ThrowNativeErrorEx(params[1], "%s", buffer);
155 static cell_t GetNativeStringLength(IPluginContext *pContext, const cell_t *params)
157 if (!s_curnative || (s_curnative->ctx != pContext))
159 return pContext->ThrowNativeError("Not called from inside a native function");
162 cell_t param = params[1];
163 if (param < 1 || param > s_curparams[0])
165 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
170 if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE)
176 pContext->LocalToPhysAddr(params[2], &addr);
177 *addr = (cell_t)strlen(str);
179 return SP_ERROR_NONE;
182 static cell_t GetNativeString(IPluginContext *pContext, const cell_t *params)
184 if (!s_curnative || (s_curnative->ctx != pContext))
186 return pContext->ThrowNativeError("Not called from inside a native function");
189 cell_t param = params[1];
190 if (param < 1 || param > s_curparams[0])
192 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
197 if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE)
203 pContext->StringToLocalUTF8(params[2], params[3], str, &bytes);
206 pContext->LocalToPhysAddr(params[4], &addr);
207 *addr = (cell_t)bytes;
209 return SP_ERROR_NONE;
212 static cell_t SetNativeString(IPluginContext *pContext, const cell_t *params)
214 if (!s_curnative || (s_curnative->ctx != pContext))
216 return pContext->ThrowNativeError("Not called from inside a native function");
219 cell_t param = params[1];
220 if (param < 1 || param > s_curparams[0])
222 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
226 pContext->LocalToString(params[2], &str);
232 err = s_curcaller->StringToLocalUTF8(s_curparams[param], params[3], str, &bytes);
234 err = s_curcaller->StringToLocal(s_curparams[param], params[3], str);
237 if (bytes >= (size_t)params[3])
239 bytes = params[3] - 1;
243 if (err != SP_ERROR_NONE)
249 pContext->LocalToPhysAddr(params[5], &addr);
250 *addr = (cell_t)bytes;
252 return SP_ERROR_NONE;
255 static cell_t GetNativeCell(IPluginContext *pContext, const cell_t *params)
257 if (!s_curnative || (s_curnative->ctx != pContext))
259 return pContext->ThrowNativeError("Not called from inside a native function");
262 cell_t param = params[1];
263 if (param < 1 || param > s_curparams[0])
265 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
268 return s_curparams[param];
271 static cell_t GetNativeCellRef(IPluginContext *pContext, const cell_t *params)
273 if (!s_curnative || (s_curnative->ctx != pContext))
275 return pContext->ThrowNativeError("Not called from inside a native function");
278 cell_t param = params[1];
279 if (param < 1 || param > s_curparams[0])
281 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
285 if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE)
287 return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value");
293 static cell_t SetNativeCellRef(IPluginContext *pContext, const cell_t *params)
295 if (!s_curnative || (s_curnative->ctx != pContext))
297 return pContext->ThrowNativeError("Not called from inside a native function");
300 cell_t param = params[1];
301 if (param < 1 || param > s_curparams[0])
303 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
307 if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE)
309 return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value");
317 static cell_t GetNativeArray(IPluginContext *pContext, const cell_t *params)
319 if (!s_curnative || (s_curnative->ctx != pContext))
321 return pContext->ThrowNativeError("Not called from inside a native function");
324 cell_t param = params[1];
325 if (param < 1 || param > s_curparams[0])
327 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
332 if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
338 pContext->LocalToPhysAddr(params[2], &src);
340 memcpy(src, addr, sizeof(cell_t) * params[3]);
342 return SP_ERROR_NONE;
345 static cell_t SetNativeArray(IPluginContext *pContext, const cell_t *params)
347 if (!s_curnative || (s_curnative->ctx != pContext))
349 return pContext->ThrowNativeError("Not called from inside a native function");
352 cell_t param = params[1];
353 if (param < 1 || param > s_curparams[0])
355 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
360 if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
366 pContext->LocalToPhysAddr(params[2], &src);
368 memcpy(addr, src, sizeof(cell_t) * params[3]);
370 return SP_ERROR_NONE;
373 static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params)
375 if (!s_curnative || (s_curnative->ctx != pContext))
377 return pContext->ThrowNativeError("Not called from inside a native function");
380 int out_param = params[1];
381 int fmt_param = params[2];
382 int var_param = params[3];
385 if (out_param && (out_param < 1 || out_param > s_curparams[0]))
387 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", out_param);
389 if (fmt_param && (fmt_param < 1 || fmt_param > s_curparams[0]))
391 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param);
393 if (var_param && (var_param < 1 || var_param > s_curparams[0] + 1))
395 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param);
398 /* Get buffer information */
405 if ((err=s_curcaller->LocalToString(s_curparams[out_param], &output_buffer)) != SP_ERROR_NONE)
410 pContext->LocalToString(params[6], &output_buffer);
415 if ((err=s_curcaller->LocalToString(s_curparams[fmt_param], &format_buffer)) != SP_ERROR_NONE)
420 pContext->LocalToString(params[7], &format_buffer);
423 /* Get maximum length */
424 size_t maxlen = (size_t)params[4];
427 size_t written = atcprintf(output_buffer, maxlen, format_buffer, s_curcaller, s_curparams, &var_param);
430 pContext->LocalToPhysAddr(params[5], &addr);
431 *addr = (cell_t)written;
433 return s_curcaller->GetContext()->n_err;
437 REGISTER_NATIVES(nativeNatives)
439 {"CreateNative", CreateNative},
440 {"GetNativeArray", GetNativeArray},
441 {"GetNativeCell", GetNativeCell},
442 {"GetNativeCellRef", GetNativeCellRef},
443 {"GetNativeString", GetNativeString},
444 {"GetNativeStringLength", GetNativeStringLength},
445 {"FormatNativeString", FormatNativeString},
446 {"ThrowNativeError", ThrowNativeError},
447 {"SetNativeArray", SetNativeArray},
448 {"SetNativeCellRef", SetNativeCellRef},
449 {"SetNativeString", SetNativeString},