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 if (native->ctx->GetRuntime()->IsPaused())
59 return pContext->ThrowNativeError("Plugin owning this native is currently paused.");
62 CPlugin *pCaller = g_PluginSys.GetPluginByCtx(pContext->GetContext());
64 /* Save any old data on the stack */
65 FakeNative *pSaveNative = s_curnative;
66 IPluginContext *pSaveCaller = s_curcaller;
67 cell_t save_params[SP_MAX_EXEC_PARAMS+1];
68 if (pSaveNative != NULL)
70 /* Copy all old parameters */
71 for (cell_t i=0; i<=s_curparams[0]; i++)
73 save_params[i] = s_curparams[i];
77 /* Save the current parameters */
79 s_curcaller = pContext;
80 for (cell_t i=0; i<=params[0]; i++)
82 s_curparams[i] = params[i];
85 /* Push info and execute. */
87 native->call->PushCell(pCaller->GetMyHandle());
88 native->call->PushCell(params[0]);
90 if ((error=native->call->Execute(&result)) != SP_ERROR_NONE)
92 if (pContext->GetLastNativeError() == SP_ERROR_NONE)
94 pContext->ThrowNativeErrorEx(error, "Error encountered while processing a dynamic native");
98 /* Restore everything from the stack if necessary */
99 s_curnative = pSaveNative;
100 s_curcaller = pSaveCaller;
101 if (pSaveNative != NULL)
103 for (cell_t i=0; i<=save_params[0]; i++)
105 s_curparams[i] = save_params[i];
112 static cell_t CreateNative(IPluginContext *pContext, const cell_t *params)
117 pContext->LocalToString(params[1], &name);
119 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
122 return pContext->ThrowNativeError("Function %x is not a valid function", params[2]);
125 pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
127 if (!pPlugin->AddFakeNative(pFunction, name, FakeNativeRouter))
129 return pContext->ThrowNativeError("Fatal error creating dynamic native!");
135 static cell_t ThrowNativeError(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 g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
146 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
148 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
150 s_curcaller->ThrowNativeError("Error encountered while processing a dynamic native");
152 s_curcaller->ThrowNativeErrorEx(params[1], "%s", buffer);
158 static cell_t GetNativeStringLength(IPluginContext *pContext, const cell_t *params)
160 if (!s_curnative || (s_curnative->ctx != pContext))
162 return pContext->ThrowNativeError("Not called from inside a native function");
165 cell_t param = params[1];
166 if (param < 1 || param > s_curparams[0])
168 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
173 if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE)
179 pContext->LocalToPhysAddr(params[2], &addr);
180 *addr = (cell_t)strlen(str);
182 return SP_ERROR_NONE;
185 static cell_t GetNativeString(IPluginContext *pContext, const cell_t *params)
187 if (!s_curnative || (s_curnative->ctx != pContext))
189 return pContext->ThrowNativeError("Not called from inside a native function");
192 cell_t param = params[1];
193 if (param < 1 || param > s_curparams[0])
195 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
200 if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE)
206 pContext->StringToLocalUTF8(params[2], params[3], str, &bytes);
209 pContext->LocalToPhysAddr(params[4], &addr);
210 *addr = (cell_t)bytes;
212 return SP_ERROR_NONE;
215 static cell_t SetNativeString(IPluginContext *pContext, const cell_t *params)
217 if (!s_curnative || (s_curnative->ctx != pContext))
219 return pContext->ThrowNativeError("Not called from inside a native function");
222 cell_t param = params[1];
223 if (param < 1 || param > s_curparams[0])
225 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
229 pContext->LocalToString(params[2], &str);
235 err = s_curcaller->StringToLocalUTF8(s_curparams[param], params[3], str, &bytes);
237 err = s_curcaller->StringToLocal(s_curparams[param], params[3], str);
240 if (bytes >= (size_t)params[3])
242 bytes = params[3] - 1;
246 if (err != SP_ERROR_NONE)
252 pContext->LocalToPhysAddr(params[5], &addr);
253 *addr = (cell_t)bytes;
255 return SP_ERROR_NONE;
258 static cell_t GetNativeCell(IPluginContext *pContext, const cell_t *params)
260 if (!s_curnative || (s_curnative->ctx != pContext))
262 return pContext->ThrowNativeError("Not called from inside a native function");
265 cell_t param = params[1];
266 if (param < 1 || param > s_curparams[0])
268 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
271 return s_curparams[param];
274 static cell_t GetNativeCellRef(IPluginContext *pContext, const cell_t *params)
276 if (!s_curnative || (s_curnative->ctx != pContext))
278 return pContext->ThrowNativeError("Not called from inside a native function");
281 cell_t param = params[1];
282 if (param < 1 || param > s_curparams[0])
284 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
288 if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE)
290 return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value");
296 static cell_t SetNativeCellRef(IPluginContext *pContext, const cell_t *params)
298 if (!s_curnative || (s_curnative->ctx != pContext))
300 return pContext->ThrowNativeError("Not called from inside a native function");
303 cell_t param = params[1];
304 if (param < 1 || param > s_curparams[0])
306 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
310 if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE)
312 return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value");
320 static cell_t GetNativeArray(IPluginContext *pContext, const cell_t *params)
322 if (!s_curnative || (s_curnative->ctx != pContext))
324 return pContext->ThrowNativeError("Not called from inside a native function");
327 cell_t param = params[1];
328 if (param < 1 || param > s_curparams[0])
330 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
335 if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
341 pContext->LocalToPhysAddr(params[2], &src);
343 memcpy(src, addr, sizeof(cell_t) * params[3]);
345 return SP_ERROR_NONE;
348 static cell_t SetNativeArray(IPluginContext *pContext, const cell_t *params)
350 if (!s_curnative || (s_curnative->ctx != pContext))
352 return pContext->ThrowNativeError("Not called from inside a native function");
355 cell_t param = params[1];
356 if (param < 1 || param > s_curparams[0])
358 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
363 if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
369 pContext->LocalToPhysAddr(params[2], &src);
371 memcpy(addr, src, sizeof(cell_t) * params[3]);
373 return SP_ERROR_NONE;
376 static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params)
378 if (!s_curnative || (s_curnative->ctx != pContext))
380 return pContext->ThrowNativeError("Not called from inside a native function");
383 int out_param = params[1];
384 int fmt_param = params[2];
385 int var_param = params[3];
388 if (out_param && (out_param < 1 || out_param > s_curparams[0]))
390 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", out_param);
392 if (fmt_param && (fmt_param < 1 || fmt_param > s_curparams[0]))
394 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param);
396 if (var_param && (var_param < 1 || var_param > s_curparams[0] + 1))
398 return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param);
401 /* Get buffer information */
408 if ((err=s_curcaller->LocalToString(s_curparams[out_param], &output_buffer)) != SP_ERROR_NONE)
413 pContext->LocalToString(params[6], &output_buffer);
418 if ((err=s_curcaller->LocalToString(s_curparams[fmt_param], &format_buffer)) != SP_ERROR_NONE)
423 pContext->LocalToString(params[7], &format_buffer);
426 /* Get maximum length */
427 size_t maxlen = (size_t)params[4];
430 size_t written = atcprintf(output_buffer, maxlen, format_buffer, s_curcaller, s_curparams, &var_param);
433 pContext->LocalToPhysAddr(params[5], &addr);
434 *addr = (cell_t)written;
436 return s_curcaller->GetLastNativeError();
440 REGISTER_NATIVES(nativeNatives)
442 {"CreateNative", CreateNative},
443 {"GetNativeArray", GetNativeArray},
444 {"GetNativeCell", GetNativeCell},
445 {"GetNativeCellRef", GetNativeCellRef},
446 {"GetNativeString", GetNativeString},
447 {"GetNativeStringLength", GetNativeStringLength},
448 {"FormatNativeString", FormatNativeString},
449 {"ThrowNativeError", ThrowNativeError},
450 {"SetNativeArray", SetNativeArray},
451 {"SetNativeCellRef", SetNativeCellRef},
452 {"SetNativeString", SetNativeString},