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