core/smn_fakenatives.cpp
author David Anderson <dvander@alliedmods.net>
Thu Jun 21 23:06:37 2007 +0000 (2007-06-21)
changeset 997 2fc3152c3118
parent 805 cdbcd5af7c6e
child 1011 b413072540fd
permissions -rw-r--r--
bumped menu api again - added feature to get menu end reason
     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 	char buffer[512];
   123 
   124 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
   125 
   126 	if (pContext->GetContext()->n_err != SP_ERROR_NONE)
   127 	{
   128 		s_curcaller->ThrowNativeError("Error encountered while processing a dynamic native");
   129 	} else {
   130 		s_curcaller->ThrowNativeErrorEx(params[1], "%s", buffer);
   131 	}
   132 
   133 	return 0;
   134 }
   135 
   136 static cell_t GetNativeStringLength(IPluginContext *pContext, const cell_t *params)
   137 {
   138 	if (!s_curnative || (s_curnative->ctx != pContext))
   139 	{
   140 		return pContext->ThrowNativeError("Not called from inside a native function");
   141 	}
   142 
   143 	cell_t param = params[1];
   144 	if (param < 1 || param > s_curparams[0])
   145 	{
   146 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
   147 	}
   148 
   149 	int err;
   150 	char *str;
   151 	if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE)
   152 	{
   153 		return err;
   154 	}
   155 
   156 	cell_t *addr;
   157 	pContext->LocalToPhysAddr(params[2], &addr);
   158 	*addr = (cell_t)strlen(str);
   159 
   160 	return SP_ERROR_NONE;
   161 }
   162 
   163 static cell_t GetNativeString(IPluginContext *pContext, const cell_t *params)
   164 {
   165 	if (!s_curnative || (s_curnative->ctx != pContext))
   166 	{
   167 		return pContext->ThrowNativeError("Not called from inside a native function");
   168 	}
   169 
   170 	cell_t param = params[1];
   171 	if (param < 1 || param > s_curparams[0])
   172 	{
   173 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
   174 	}
   175 
   176 	int err;
   177 	char *str;
   178 	if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE)
   179 	{
   180 		return err;
   181 	}
   182 
   183 	size_t bytes = 0;
   184 	pContext->StringToLocalUTF8(params[2], params[3], str, &bytes);
   185 
   186 	cell_t *addr;
   187 	pContext->LocalToPhysAddr(params[4], &addr);
   188 	*addr = (cell_t)bytes;
   189 
   190 	return SP_ERROR_NONE;
   191 }
   192 
   193 static cell_t SetNativeString(IPluginContext *pContext, const cell_t *params)
   194 {
   195 	if (!s_curnative || (s_curnative->ctx != pContext))
   196 	{
   197 		return pContext->ThrowNativeError("Not called from inside a native function");
   198 	}
   199 
   200 	cell_t param = params[1];
   201 	if (param < 1 || param > s_curparams[0])
   202 	{
   203 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
   204 	}
   205 
   206 	char *str;
   207 	pContext->LocalToString(params[2], &str);
   208 
   209 	int err;
   210 	size_t bytes = 0;
   211 	if (params[4])
   212 	{
   213 		err = s_curcaller->StringToLocalUTF8(s_curparams[param], params[3], str, &bytes);
   214 	} else {
   215 		err = s_curcaller->StringToLocal(s_curparams[param], params[3], str);
   216 		/* Eww */
   217 		bytes = strlen(str);
   218 		if (bytes >= (size_t)params[3])
   219 		{
   220 			bytes = params[3] - 1;
   221 		}
   222 	}
   223 
   224 	if (err != SP_ERROR_NONE)
   225 	{
   226 		return err;
   227 	}
   228 
   229 	cell_t *addr;
   230 	pContext->LocalToPhysAddr(params[5], &addr);
   231 	*addr = (cell_t)bytes;
   232 
   233 	return SP_ERROR_NONE;
   234 }
   235 
   236 static cell_t GetNativeCell(IPluginContext *pContext, const cell_t *params)
   237 {
   238 	if (!s_curnative || (s_curnative->ctx != pContext))
   239 	{
   240 		return pContext->ThrowNativeError("Not called from inside a native function");
   241 	}
   242 
   243 	cell_t param = params[1];
   244 	if (param < 1 || param > s_curparams[0])
   245 	{
   246 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
   247 	}
   248 
   249 	return s_curparams[param];
   250 }
   251 
   252 static cell_t GetNativeCellRef(IPluginContext *pContext, const cell_t *params)
   253 {
   254 	if (!s_curnative || (s_curnative->ctx != pContext))
   255 	{
   256 		return pContext->ThrowNativeError("Not called from inside a native function");
   257 	}
   258 
   259 	cell_t param = params[1];
   260 	if (param < 1 || param > s_curparams[0])
   261 	{
   262 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
   263 	}
   264 
   265 	cell_t *addr;
   266 	if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE)
   267 	{
   268 		return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value");
   269 	}
   270 
   271 	return *addr;
   272 }
   273 
   274 static cell_t SetNativeCellRef(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 	*addr = params[2];
   294 
   295 	return 1;
   296 }
   297 
   298 static cell_t GetNativeArray(IPluginContext *pContext, const cell_t *params)
   299 {
   300 	if (!s_curnative || (s_curnative->ctx != pContext))
   301 	{
   302 		return pContext->ThrowNativeError("Not called from inside a native function");
   303 	}
   304 
   305 	cell_t param = params[1];
   306 	if (param < 1 || param > s_curparams[0])
   307 	{
   308 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
   309 	}
   310 
   311 	int err;
   312 	cell_t *addr;
   313 	if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
   314 	{
   315 		return err;
   316 	}
   317 
   318 	cell_t *src;
   319 	pContext->LocalToPhysAddr(params[2], &src);
   320 
   321 	memcpy(src, addr, sizeof(cell_t) * params[3]);
   322 
   323 	return SP_ERROR_NONE;
   324 }
   325 
   326 static cell_t SetNativeArray(IPluginContext *pContext, const cell_t *params)
   327 {
   328 	if (!s_curnative || (s_curnative->ctx != pContext))
   329 	{
   330 		return pContext->ThrowNativeError("Not called from inside a native function");
   331 	}
   332 
   333 	cell_t param = params[1];
   334 	if (param < 1 || param > s_curparams[0])
   335 	{
   336 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
   337 	}
   338 
   339 	int err;
   340 	cell_t *addr;
   341 	if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
   342 	{
   343 		return err;
   344 	}
   345 
   346 	cell_t *src;
   347 	pContext->LocalToPhysAddr(params[2], &src);
   348 
   349 	memcpy(addr, src, sizeof(cell_t) * params[3]);
   350 
   351 	return SP_ERROR_NONE;
   352 }
   353 
   354 static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params)
   355 {
   356 	if (!s_curnative || (s_curnative->ctx != pContext))
   357 	{
   358 		return pContext->ThrowNativeError("Not called from inside a native function");
   359 	}
   360 
   361 	int out_param = params[1];
   362 	int fmt_param = params[2];
   363 	int var_param = params[3];
   364 
   365 	/* Validate input */
   366 	if (out_param && (out_param < 1 || out_param > s_curparams[0]))
   367 	{
   368 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", out_param);
   369 	}
   370 	if (fmt_param && (fmt_param < 1 || fmt_param > s_curparams[0]))
   371 	{
   372 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param);
   373 	}
   374 	if (var_param && (var_param < 1 || var_param > s_curparams[0] + 1))
   375 	{
   376 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param);
   377 	}
   378 
   379 	/* Get buffer information */
   380 	int err;
   381 	char *output_buffer;
   382 	char *format_buffer;
   383 
   384 	if (out_param)
   385 	{
   386 		if ((err=s_curcaller->LocalToString(s_curparams[out_param], &output_buffer)) != SP_ERROR_NONE)
   387 		{
   388 			return err;
   389 		}
   390 	} else {
   391 		pContext->LocalToString(params[6], &output_buffer);
   392 	}
   393 
   394 	if (fmt_param)
   395 	{
   396 		if ((err=s_curcaller->LocalToString(s_curparams[fmt_param], &format_buffer)) != SP_ERROR_NONE)
   397 		{
   398 			return err;
   399 		}
   400 	} else {
   401 		pContext->LocalToString(params[7], &format_buffer);
   402 	}
   403 
   404 	/* Get maximum length */
   405 	size_t maxlen = (size_t)params[4];
   406 
   407 	/* Do the format */
   408 	size_t written = atcprintf(output_buffer, maxlen, format_buffer, s_curcaller, s_curparams, &var_param);
   409 
   410 	cell_t *addr;
   411 	pContext->LocalToPhysAddr(params[5], &addr);
   412 	*addr = (cell_t)written;
   413 
   414 	return s_curcaller->GetContext()->n_err;
   415 }
   416 
   417 //tee hee
   418 REGISTER_NATIVES(nativeNatives)
   419 {
   420 	{"CreateNative",			CreateNative},
   421 	{"GetNativeArray",			GetNativeArray},
   422 	{"GetNativeCell",			GetNativeCell},
   423 	{"GetNativeCellRef",		GetNativeCellRef},
   424 	{"GetNativeString",			GetNativeString},
   425 	{"GetNativeStringLength",	GetNativeStringLength},
   426 	{"FormatNativeString",		FormatNativeString},
   427 	{"ThrowNativeError",		ThrowNativeError},
   428 	{"SetNativeArray",			SetNativeArray},
   429 	{"SetNativeCellRef",		SetNativeCellRef},
   430 	{"SetNativeString",			SetNativeString},
   431 	{NULL,						NULL},
   432 };