3 * =============================================================================
5 * Copyright (C) 2004-2008 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)
118 pContext->LocalToString(params[1], &name);
120 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
123 return pContext->ThrowNativeError("Function %x is not a valid function", params[2]);
126 pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
128 if (!pPlugin->AddFakeNative(pFunction, name, FakeNativeRouter))
130 return pContext->ThrowNativeError("Fatal error creating dynamic native!");
136 static cell_t ThrowNativeError(IPluginContext *pContext, const cell_t *params)
138 if (!s_curnative || (s_curnative->ctx != pContext))
140 return pContext->ThrowNativeError("Not called from inside a native function");
143 g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
147 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
149 if (pContext->GetContext()->n_err != SP_ERROR_NONE)
151 s_curcaller->ThrowNativeError("Error encountered while processing a dynamic native");
153 s_curcaller->ThrowNativeErrorEx(params[1], "%s", buffer);
159 static cell_t GetNativeStringLength(IPluginContext *pContext, const cell_t *params)
161 if (!s_curnative || (s_curnative->ctx != pContext))
163 return pContext->ThrowNativeError("Not called from inside a native function");
166 cell_t param = params[1];
167 if (param < 1 || param > s_curparams[0])
169 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
174 if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE)
180 pContext->LocalToPhysAddr(params[2], &addr);
181 *addr = (cell_t)strlen(str);
183 return SP_ERROR_NONE;
186 static cell_t GetNativeString(IPluginContext *pContext, const cell_t *params)
188 if (!s_curnative || (s_curnative->ctx != pContext))
190 return pContext->ThrowNativeError("Not called from inside a native function");
193 cell_t param = params[1];
194 if (param < 1 || param > s_curparams[0])
196 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
201 if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE)
207 pContext->StringToLocalUTF8(params[2], params[3], str, &bytes);
210 pContext->LocalToPhysAddr(params[4], &addr);
211 *addr = (cell_t)bytes;
213 return SP_ERROR_NONE;
216 static cell_t SetNativeString(IPluginContext *pContext, const cell_t *params)
218 if (!s_curnative || (s_curnative->ctx != pContext))
220 return pContext->ThrowNativeError("Not called from inside a native function");
223 cell_t param = params[1];
224 if (param < 1 || param > s_curparams[0])
226 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
230 pContext->LocalToString(params[2], &str);
236 err = s_curcaller->StringToLocalUTF8(s_curparams[param], params[3], str, &bytes);
238 err = s_curcaller->StringToLocal(s_curparams[param], params[3], str);
241 if (bytes >= (size_t)params[3])
243 bytes = params[3] - 1;
247 if (err != SP_ERROR_NONE)
253 pContext->LocalToPhysAddr(params[5], &addr);
254 *addr = (cell_t)bytes;
256 return SP_ERROR_NONE;
259 static cell_t GetNativeCell(IPluginContext *pContext, const cell_t *params)
261 if (!s_curnative || (s_curnative->ctx != pContext))
263 return pContext->ThrowNativeError("Not called from inside a native function");
266 cell_t param = params[1];
267 if (param < 1 || param > s_curparams[0])
269 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
272 return s_curparams[param];
275 static cell_t GetNativeCellRef(IPluginContext *pContext, const cell_t *params)
277 if (!s_curnative || (s_curnative->ctx != pContext))
279 return pContext->ThrowNativeError("Not called from inside a native function");
282 cell_t param = params[1];
283 if (param < 1 || param > s_curparams[0])
285 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
289 if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE)
291 return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value");
297 static cell_t SetNativeCellRef(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);
311 if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE)
313 return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value");
321 static cell_t GetNativeArray(IPluginContext *pContext, const cell_t *params)
323 if (!s_curnative || (s_curnative->ctx != pContext))
325 return pContext->ThrowNativeError("Not called from inside a native function");
328 cell_t param = params[1];
329 if (param < 1 || param > s_curparams[0])
331 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
336 if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
342 pContext->LocalToPhysAddr(params[2], &src);
344 memcpy(src, addr, sizeof(cell_t) * params[3]);
346 return SP_ERROR_NONE;
349 static cell_t SetNativeArray(IPluginContext *pContext, const cell_t *params)
351 if (!s_curnative || (s_curnative->ctx != pContext))
353 return pContext->ThrowNativeError("Not called from inside a native function");
356 cell_t param = params[1];
357 if (param < 1 || param > s_curparams[0])
359 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
364 if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
370 pContext->LocalToPhysAddr(params[2], &src);
372 memcpy(addr, src, sizeof(cell_t) * params[3]);
374 return SP_ERROR_NONE;
377 static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params)
379 if (!s_curnative || (s_curnative->ctx != pContext))
381 return pContext->ThrowNativeError("Not called from inside a native function");
384 int out_param = params[1];
385 int fmt_param = params[2];
386 int var_param = params[3];
389 if (out_param && (out_param < 1 || out_param > s_curparams[0]))
391 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", out_param);
393 if (fmt_param && (fmt_param < 1 || fmt_param > s_curparams[0]))
395 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param);
397 if (var_param && (var_param < 1 || var_param > s_curparams[0] + 1))
399 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param);
402 /* Get buffer information */
409 if ((err=s_curcaller->LocalToString(s_curparams[out_param], &output_buffer)) != SP_ERROR_NONE)
414 pContext->LocalToString(params[6], &output_buffer);
419 if ((err=s_curcaller->LocalToString(s_curparams[fmt_param], &format_buffer)) != SP_ERROR_NONE)
424 pContext->LocalToString(params[7], &format_buffer);
427 /* Get maximum length */
428 size_t maxlen = (size_t)params[4];
431 size_t written = atcprintf(output_buffer, maxlen, format_buffer, s_curcaller, s_curparams, &var_param);
434 pContext->LocalToPhysAddr(params[5], &addr);
435 *addr = (cell_t)written;
437 return s_curcaller->GetContext()->n_err;
441 REGISTER_NATIVES(nativeNatives)
443 {"CreateNative", CreateNative},
444 {"GetNativeArray", GetNativeArray},
445 {"GetNativeCell", GetNativeCell},
446 {"GetNativeCellRef", GetNativeCellRef},
447 {"GetNativeString", GetNativeString},
448 {"GetNativeStringLength", GetNativeStringLength},
449 {"FormatNativeString", FormatNativeString},
450 {"ThrowNativeError", ThrowNativeError},
451 {"SetNativeArray", SetNativeArray},
452 {"SetNativeCellRef", SetNativeCellRef},
453 {"SetNativeString", SetNativeString},