core/smn_fakenatives.cpp
author David Anderson <dvander@alliedmods.net>
Mon Apr 16 16:53:48 2007 +0000 (2007-04-16)
changeset 699 46c97376db0e
parent 653 ef60870067ff
child 805 cdbcd5af7c6e
permissions -rw-r--r--
fixed a re-entrancy bug
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5  * ===============================================================
     6  *
     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
    11  *
    12  * Version: $Id$
    13  */
    14 
    15 #include <sh_list.h>
    16 #include <sh_string.h>
    17 #include "sm_trie.h"
    18 #include "sm_globals.h"
    19 #include "PluginSys.h"
    20 #include "sourcemod.h"
    21 #include "sm_stringutil.h"
    22 
    23 using namespace SourceHook;
    24 
    25 static cell_t s_curparams[SP_MAX_EXEC_PARAMS+1];
    26 static FakeNative *s_curnative = NULL;
    27 static IPluginContext *s_curcaller = NULL;
    28 
    29 cell_t FakeNativeRouter(IPluginContext *pContext, const cell_t *params, void *pData)
    30 {
    31 	FakeNative *native = (FakeNative *)pData;
    32 
    33 	/* Check if too many parameters were passed */
    34 	if (params[0] > SP_MAX_EXEC_PARAMS)
    35 	{
    36 		return pContext->ThrowNativeError("Called native with too many parameters (%d>%d)", params[9], SP_MAX_EXEC_PARAMS);
    37 	}
    38 
    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)
    42 	{
    43 		return pContext->ThrowNativeError("Plugin owning this native is currently paused.");
    44 	}
    45 
    46 	CPlugin *pCaller = g_PluginSys.GetPluginByCtx(pContext->GetContext());
    47 
    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)
    53 	{
    54 		/* Copy all old parameters */
    55 		for (cell_t i=0; i<=s_curparams[0]; i++)
    56 		{
    57 			save_params[i] = s_curparams[i];
    58 		}
    59 	}
    60 
    61 	/* Save the current parameters */
    62 	s_curnative = native;
    63 	s_curcaller = pContext;
    64 	for (cell_t i=0; i<=params[0]; i++)
    65 	{
    66 		s_curparams[i] = params[i];
    67 	}
    68 
    69 	/* Push info and execute. */
    70 	cell_t result = 0;
    71 	native->call->PushCell(pCaller->GetMyHandle());
    72 	native->call->PushCell(params[0]);
    73 	if (native->call->Execute(&result) != SP_ERROR_NONE)
    74 	{
    75 		if (pContext->GetContext()->n_err == SP_ERROR_NONE)
    76 		{
    77 			pContext->ThrowNativeError("Error encountered while processing a dynamic native");
    78 		}
    79 	}
    80 
    81 	/* Restore everything from the stack if necessary */
    82 	s_curnative = pSaveNative;
    83 	s_curcaller = pSaveCaller;
    84 	if (pSaveNative != NULL)
    85 	{
    86 		for (cell_t i=0; i<=save_params[0]; i++)
    87 		{
    88 			s_curparams[i] = save_params[i];
    89 		}
    90 	}
    91 
    92 	return result;
    93 }
    94 
    95 static cell_t CreateNative(IPluginContext *pContext, const cell_t *params)
    96 {
    97 	char *name;
    98 	pContext->LocalToString(params[1], &name);
    99 
   100 	IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
   101 	if (!pFunction)
   102 	{
   103 		return pContext->ThrowNativeError("Function %x is not a valid function", params[2]);
   104 	}
   105 
   106 	if (!g_PluginSys.AddFakeNative(pFunction, name, FakeNativeRouter))
   107 	{
   108 		return pContext->ThrowNativeError("Fatal error creating dynamic native!");
   109 	}
   110 
   111 	return 1;
   112 }
   113 
   114 static cell_t ThrowNativeError(IPluginContext *pContext, const cell_t *params)
   115 {
   116 	if (!s_curnative || (s_curnative->ctx != pContext))
   117 	{
   118 		return pContext->ThrowNativeError("Not called from inside a native function");
   119 	}
   120 
   121 	char buffer[512];
   122 
   123 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
   124 
   125 	if (pContext->GetContext()->n_err != SP_ERROR_NONE)
   126 	{
   127 		s_curcaller->ThrowNativeError("Error encountered while processing a dynamic native");
   128 	} else {
   129 		s_curcaller->ThrowNativeErrorEx(params[1], "%s", buffer);
   130 	}
   131 
   132 	return 0;
   133 }
   134 
   135 static cell_t GetNativeStringLength(IPluginContext *pContext, const cell_t *params)
   136 {
   137 	if (!s_curnative || (s_curnative->ctx != pContext))
   138 	{
   139 		return pContext->ThrowNativeError("Not called from inside a native function");
   140 	}
   141 
   142 	cell_t param = params[1];
   143 	if (param < 1 || param > s_curparams[0])
   144 	{
   145 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
   146 	}
   147 
   148 	int err;
   149 	char *str;
   150 	if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE)
   151 	{
   152 		return err;
   153 	}
   154 
   155 	cell_t *addr;
   156 	pContext->LocalToPhysAddr(params[2], &addr);
   157 	*addr = (cell_t)strlen(str);
   158 
   159 	return SP_ERROR_NONE;
   160 }
   161 
   162 static cell_t GetNativeString(IPluginContext *pContext, const cell_t *params)
   163 {
   164 	if (!s_curnative || (s_curnative->ctx != pContext))
   165 	{
   166 		return pContext->ThrowNativeError("Not called from inside a native function");
   167 	}
   168 
   169 	cell_t param = params[1];
   170 	if (param < 1 || param > s_curparams[0])
   171 	{
   172 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
   173 	}
   174 
   175 	int err;
   176 	char *str;
   177 	if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE)
   178 	{
   179 		return err;
   180 	}
   181 
   182 	size_t bytes = 0;
   183 	pContext->StringToLocalUTF8(params[2], params[3], str, &bytes);
   184 
   185 	cell_t *addr;
   186 	pContext->LocalToPhysAddr(params[4], &addr);
   187 	*addr = (cell_t)bytes;
   188 
   189 	return SP_ERROR_NONE;
   190 }
   191 
   192 static cell_t SetNativeString(IPluginContext *pContext, const cell_t *params)
   193 {
   194 	if (!s_curnative || (s_curnative->ctx != pContext))
   195 	{
   196 		return pContext->ThrowNativeError("Not called from inside a native function");
   197 	}
   198 
   199 	cell_t param = params[1];
   200 	if (param < 1 || param > s_curparams[0])
   201 	{
   202 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
   203 	}
   204 
   205 	char *str;
   206 	pContext->LocalToString(params[2], &str);
   207 
   208 	int err;
   209 	size_t bytes = 0;
   210 	if (params[4])
   211 	{
   212 		err = s_curcaller->StringToLocalUTF8(s_curparams[param], params[3], str, &bytes);
   213 	} else {
   214 		err = s_curcaller->StringToLocal(s_curparams[param], params[3], str);
   215 		/* Eww */
   216 		bytes = strlen(str);
   217 		if (bytes >= (size_t)params[3])
   218 		{
   219 			bytes = params[3] - 1;
   220 		}
   221 	}
   222 
   223 	if (err != SP_ERROR_NONE)
   224 	{
   225 		return err;
   226 	}
   227 
   228 	cell_t *addr;
   229 	pContext->LocalToPhysAddr(params[5], &addr);
   230 	*addr = (cell_t)bytes;
   231 
   232 	return SP_ERROR_NONE;
   233 }
   234 
   235 static cell_t GetNativeCell(IPluginContext *pContext, const cell_t *params)
   236 {
   237 	if (!s_curnative || (s_curnative->ctx != pContext))
   238 	{
   239 		return pContext->ThrowNativeError("Not called from inside a native function");
   240 	}
   241 
   242 	cell_t param = params[1];
   243 	if (param < 1 || param > s_curparams[0])
   244 	{
   245 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
   246 	}
   247 
   248 	return s_curparams[param];
   249 }
   250 
   251 static cell_t GetNativeCellRef(IPluginContext *pContext, const cell_t *params)
   252 {
   253 	if (!s_curnative || (s_curnative->ctx != pContext))
   254 	{
   255 		return pContext->ThrowNativeError("Not called from inside a native function");
   256 	}
   257 
   258 	cell_t param = params[1];
   259 	if (param < 1 || param > s_curparams[0])
   260 	{
   261 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
   262 	}
   263 
   264 	cell_t *addr;
   265 	if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE)
   266 	{
   267 		return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value");
   268 	}
   269 
   270 	return *addr;
   271 }
   272 
   273 static cell_t SetNativeCellRef(IPluginContext *pContext, const cell_t *params)
   274 {
   275 	if (!s_curnative || (s_curnative->ctx != pContext))
   276 	{
   277 		return pContext->ThrowNativeError("Not called from inside a native function");
   278 	}
   279 
   280 	cell_t param = params[1];
   281 	if (param < 1 || param > s_curparams[0])
   282 	{
   283 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
   284 	}
   285 
   286 	cell_t *addr;
   287 	if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE)
   288 	{
   289 		return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value");
   290 	}
   291 
   292 	*addr = params[2];
   293 
   294 	return 1;
   295 }
   296 
   297 static cell_t GetNativeArray(IPluginContext *pContext, const cell_t *params)
   298 {
   299 	if (!s_curnative || (s_curnative->ctx != pContext))
   300 	{
   301 		return pContext->ThrowNativeError("Not called from inside a native function");
   302 	}
   303 
   304 	cell_t param = params[1];
   305 	if (param < 1 || param > s_curparams[0])
   306 	{
   307 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
   308 	}
   309 
   310 	int err;
   311 	cell_t *addr;
   312 	if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
   313 	{
   314 		return err;
   315 	}
   316 
   317 	cell_t *src;
   318 	pContext->LocalToPhysAddr(params[2], &src);
   319 
   320 	memcpy(src, addr, sizeof(cell_t) * params[3]);
   321 
   322 	return SP_ERROR_NONE;
   323 }
   324 
   325 static cell_t SetNativeArray(IPluginContext *pContext, const cell_t *params)
   326 {
   327 	if (!s_curnative || (s_curnative->ctx != pContext))
   328 	{
   329 		return pContext->ThrowNativeError("Not called from inside a native function");
   330 	}
   331 
   332 	cell_t param = params[1];
   333 	if (param < 1 || param > s_curparams[0])
   334 	{
   335 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
   336 	}
   337 
   338 	int err;
   339 	cell_t *addr;
   340 	if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
   341 	{
   342 		return err;
   343 	}
   344 
   345 	cell_t *src;
   346 	pContext->LocalToPhysAddr(params[2], &src);
   347 
   348 	memcpy(addr, src, sizeof(cell_t) * params[3]);
   349 
   350 	return SP_ERROR_NONE;
   351 }
   352 
   353 static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params)
   354 {
   355 	if (!s_curnative || (s_curnative->ctx != pContext))
   356 	{
   357 		return pContext->ThrowNativeError("Not called from inside a native function");
   358 	}
   359 
   360 	int out_param = params[1];
   361 	int fmt_param = params[2];
   362 	int var_param = params[3];
   363 
   364 	/* Validate input */
   365 	if (out_param && (out_param < 1 || out_param > s_curparams[0]))
   366 	{
   367 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", out_param);
   368 	}
   369 	if (fmt_param && (fmt_param < 1 || fmt_param > s_curparams[0]))
   370 	{
   371 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param);
   372 	}
   373 	if (var_param && (var_param < 1 || var_param > s_curparams[0] + 1))
   374 	{
   375 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param);
   376 	}
   377 
   378 	/* Get buffer information */
   379 	int err;
   380 	char *output_buffer;
   381 	char *format_buffer;
   382 
   383 	if (out_param)
   384 	{
   385 		if ((err=s_curcaller->LocalToString(s_curparams[out_param], &output_buffer)) != SP_ERROR_NONE)
   386 		{
   387 			return err;
   388 		}
   389 	} else {
   390 		pContext->LocalToString(params[6], &output_buffer);
   391 	}
   392 
   393 	if (fmt_param)
   394 	{
   395 		if ((err=s_curcaller->LocalToString(s_curparams[fmt_param], &format_buffer)) != SP_ERROR_NONE)
   396 		{
   397 			return err;
   398 		}
   399 	} else {
   400 		pContext->LocalToString(params[7], &format_buffer);
   401 	}
   402 
   403 	/* Get maximum length */
   404 	size_t maxlen = (size_t)params[4];
   405 
   406 	/* Do the format */
   407 	size_t written = atcprintf(output_buffer, maxlen, format_buffer, s_curcaller, s_curparams, &var_param);
   408 
   409 	cell_t *addr;
   410 	pContext->LocalToPhysAddr(params[5], &addr);
   411 	*addr = (cell_t)written;
   412 
   413 	return s_curcaller->GetContext()->n_err;
   414 }
   415 
   416 //tee hee
   417 REGISTER_NATIVES(nativeNatives)
   418 {
   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},
   430 	{NULL,						NULL},
   431 };