diff -r 000000000000 -r c24a6fa957db core/smn_fakenatives.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/smn_fakenatives.cpp Sun Jul 06 04:49:55 2008 +0000 @@ -0,0 +1,455 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#include +#include +#include "sm_trie.h" +#include "sm_globals.h" +#include "PluginSys.h" +#include "sourcemod.h" +#include "sm_stringutil.h" + +using namespace SourceHook; + +static cell_t s_curparams[SP_MAX_EXEC_PARAMS+1]; +static FakeNative *s_curnative = NULL; +static IPluginContext *s_curcaller = NULL; + +cell_t FakeNativeRouter(IPluginContext *pContext, const cell_t *params, void *pData) +{ + FakeNative *native = (FakeNative *)pData; + + /* Check if too many parameters were passed */ + if (params[0] > SP_MAX_EXEC_PARAMS) + { + return pContext->ThrowNativeError("Called native with too many parameters (%d>%d)", params[9], SP_MAX_EXEC_PARAMS); + } + + /* Check if the native is paused */ + sp_context_t *pNativeCtx = native->ctx->GetContext(); + if ((pNativeCtx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED) + { + return pContext->ThrowNativeError("Plugin owning this native is currently paused."); + } + + CPlugin *pCaller = g_PluginSys.GetPluginByCtx(pContext->GetContext()); + + /* Save any old data on the stack */ + FakeNative *pSaveNative = s_curnative; + IPluginContext *pSaveCaller = s_curcaller; + cell_t save_params[SP_MAX_EXEC_PARAMS+1]; + if (pSaveNative != NULL) + { + /* Copy all old parameters */ + for (cell_t i=0; i<=s_curparams[0]; i++) + { + save_params[i] = s_curparams[i]; + } + } + + /* Save the current parameters */ + s_curnative = native; + s_curcaller = pContext; + for (cell_t i=0; i<=params[0]; i++) + { + s_curparams[i] = params[i]; + } + + /* Push info and execute. */ + cell_t result = 0; + native->call->PushCell(pCaller->GetMyHandle()); + native->call->PushCell(params[0]); + int error; + if ((error=native->call->Execute(&result)) != SP_ERROR_NONE) + { + if (pContext->GetContext()->n_err == SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(error, "Error encountered while processing a dynamic native"); + } + } + + /* Restore everything from the stack if necessary */ + s_curnative = pSaveNative; + s_curcaller = pSaveCaller; + if (pSaveNative != NULL) + { + for (cell_t i=0; i<=save_params[0]; i++) + { + s_curparams[i] = save_params[i]; + } + } + + return result; +} + +static cell_t CreateNative(IPluginContext *pContext, const cell_t *params) +{ + char *name; + CPlugin *pPlugin; + + pContext->LocalToString(params[1], &name); + + IPluginFunction *pFunction = pContext->GetFunctionById(params[2]); + if (!pFunction) + { + return pContext->ThrowNativeError("Function %x is not a valid function", params[2]); + } + + pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext()); + + if (!pPlugin->AddFakeNative(pFunction, name, FakeNativeRouter)) + { + return pContext->ThrowNativeError("Fatal error creating dynamic native!"); + } + + return 1; +} + +static cell_t ThrowNativeError(IPluginContext *pContext, const cell_t *params) +{ + if (!s_curnative || (s_curnative->ctx != pContext)) + { + return pContext->ThrowNativeError("Not called from inside a native function"); + } + + g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE); + + char buffer[512]; + + g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2); + + if (pContext->GetContext()->n_err != SP_ERROR_NONE) + { + s_curcaller->ThrowNativeError("Error encountered while processing a dynamic native"); + } else { + s_curcaller->ThrowNativeErrorEx(params[1], "%s", buffer); + } + + return 0; +} + +static cell_t GetNativeStringLength(IPluginContext *pContext, const cell_t *params) +{ + if (!s_curnative || (s_curnative->ctx != pContext)) + { + return pContext->ThrowNativeError("Not called from inside a native function"); + } + + cell_t param = params[1]; + if (param < 1 || param > s_curparams[0]) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param); + } + + int err; + char *str; + if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE) + { + return err; + } + + cell_t *addr; + pContext->LocalToPhysAddr(params[2], &addr); + *addr = (cell_t)strlen(str); + + return SP_ERROR_NONE; +} + +static cell_t GetNativeString(IPluginContext *pContext, const cell_t *params) +{ + if (!s_curnative || (s_curnative->ctx != pContext)) + { + return pContext->ThrowNativeError("Not called from inside a native function"); + } + + cell_t param = params[1]; + if (param < 1 || param > s_curparams[0]) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param); + } + + int err; + char *str; + if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE) + { + return err; + } + + size_t bytes = 0; + pContext->StringToLocalUTF8(params[2], params[3], str, &bytes); + + cell_t *addr; + pContext->LocalToPhysAddr(params[4], &addr); + *addr = (cell_t)bytes; + + return SP_ERROR_NONE; +} + +static cell_t SetNativeString(IPluginContext *pContext, const cell_t *params) +{ + if (!s_curnative || (s_curnative->ctx != pContext)) + { + return pContext->ThrowNativeError("Not called from inside a native function"); + } + + cell_t param = params[1]; + if (param < 1 || param > s_curparams[0]) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param); + } + + char *str; + pContext->LocalToString(params[2], &str); + + int err; + size_t bytes = 0; + if (params[4]) + { + err = s_curcaller->StringToLocalUTF8(s_curparams[param], params[3], str, &bytes); + } else { + err = s_curcaller->StringToLocal(s_curparams[param], params[3], str); + /* Eww */ + bytes = strlen(str); + if (bytes >= (size_t)params[3]) + { + bytes = params[3] - 1; + } + } + + if (err != SP_ERROR_NONE) + { + return err; + } + + cell_t *addr; + pContext->LocalToPhysAddr(params[5], &addr); + *addr = (cell_t)bytes; + + return SP_ERROR_NONE; +} + +static cell_t GetNativeCell(IPluginContext *pContext, const cell_t *params) +{ + if (!s_curnative || (s_curnative->ctx != pContext)) + { + return pContext->ThrowNativeError("Not called from inside a native function"); + } + + cell_t param = params[1]; + if (param < 1 || param > s_curparams[0]) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param); + } + + return s_curparams[param]; +} + +static cell_t GetNativeCellRef(IPluginContext *pContext, const cell_t *params) +{ + if (!s_curnative || (s_curnative->ctx != pContext)) + { + return pContext->ThrowNativeError("Not called from inside a native function"); + } + + cell_t param = params[1]; + if (param < 1 || param > s_curparams[0]) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param); + } + + cell_t *addr; + if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE) + { + return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value"); + } + + return *addr; +} + +static cell_t SetNativeCellRef(IPluginContext *pContext, const cell_t *params) +{ + if (!s_curnative || (s_curnative->ctx != pContext)) + { + return pContext->ThrowNativeError("Not called from inside a native function"); + } + + cell_t param = params[1]; + if (param < 1 || param > s_curparams[0]) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param); + } + + cell_t *addr; + if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE) + { + return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value"); + } + + *addr = params[2]; + + return 1; +} + +static cell_t GetNativeArray(IPluginContext *pContext, const cell_t *params) +{ + if (!s_curnative || (s_curnative->ctx != pContext)) + { + return pContext->ThrowNativeError("Not called from inside a native function"); + } + + cell_t param = params[1]; + if (param < 1 || param > s_curparams[0]) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param); + } + + int err; + cell_t *addr; + if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE) + { + return err; + } + + cell_t *src; + pContext->LocalToPhysAddr(params[2], &src); + + memcpy(src, addr, sizeof(cell_t) * params[3]); + + return SP_ERROR_NONE; +} + +static cell_t SetNativeArray(IPluginContext *pContext, const cell_t *params) +{ + if (!s_curnative || (s_curnative->ctx != pContext)) + { + return pContext->ThrowNativeError("Not called from inside a native function"); + } + + cell_t param = params[1]; + if (param < 1 || param > s_curparams[0]) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param); + } + + int err; + cell_t *addr; + if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE) + { + return err; + } + + cell_t *src; + pContext->LocalToPhysAddr(params[2], &src); + + memcpy(addr, src, sizeof(cell_t) * params[3]); + + return SP_ERROR_NONE; +} + +static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params) +{ + if (!s_curnative || (s_curnative->ctx != pContext)) + { + return pContext->ThrowNativeError("Not called from inside a native function"); + } + + int out_param = params[1]; + int fmt_param = params[2]; + int var_param = params[3]; + + /* Validate input */ + if (out_param && (out_param < 1 || out_param > s_curparams[0])) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", out_param); + } + if (fmt_param && (fmt_param < 1 || fmt_param > s_curparams[0])) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param); + } + if (var_param && (var_param < 1 || var_param > s_curparams[0] + 1)) + { + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param); + } + + /* Get buffer information */ + int err; + char *output_buffer; + char *format_buffer; + + if (out_param) + { + if ((err=s_curcaller->LocalToString(s_curparams[out_param], &output_buffer)) != SP_ERROR_NONE) + { + return err; + } + } else { + pContext->LocalToString(params[6], &output_buffer); + } + + if (fmt_param) + { + if ((err=s_curcaller->LocalToString(s_curparams[fmt_param], &format_buffer)) != SP_ERROR_NONE) + { + return err; + } + } else { + pContext->LocalToString(params[7], &format_buffer); + } + + /* Get maximum length */ + size_t maxlen = (size_t)params[4]; + + /* Do the format */ + size_t written = atcprintf(output_buffer, maxlen, format_buffer, s_curcaller, s_curparams, &var_param); + + cell_t *addr; + pContext->LocalToPhysAddr(params[5], &addr); + *addr = (cell_t)written; + + return s_curcaller->GetContext()->n_err; +} + +//tee hee +REGISTER_NATIVES(nativeNatives) +{ + {"CreateNative", CreateNative}, + {"GetNativeArray", GetNativeArray}, + {"GetNativeCell", GetNativeCell}, + {"GetNativeCellRef", GetNativeCellRef}, + {"GetNativeString", GetNativeString}, + {"GetNativeStringLength", GetNativeStringLength}, + {"FormatNativeString", FormatNativeString}, + {"ThrowNativeError", ThrowNativeError}, + {"SetNativeArray", SetNativeArray}, + {"SetNativeCellRef", SetNativeCellRef}, + {"SetNativeString", SetNativeString}, + {NULL, NULL}, +};