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