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