core/smn_core.cpp
author Ruben Gonzalez <drifter01620@gmail.com>
Thu Feb 13 12:12:36 2014 -0500 (2014-02-13)
changeset 4251 9290c598d3cb
parent 4139 de7d1cd00703
child 4296 e0ea8dfa24b1
permissions -rw-r--r--
Update CSSDM gdc patch bytes (NPOTB)
     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 <time.h>
    33 #include <string.h>
    34 #include <stdlib.h>
    35 #include "sm_stringutil.h"
    36 #include "sm_globals.h"
    37 #include "sourcemod.h"
    38 #include "LibrarySys.h"
    39 #include "TimerSys.h"
    40 #include "Logger.h"
    41 #include <sh_memory.h>
    42 #include "logic_bridge.h"
    43 
    44 #if defined PLATFORM_WINDOWS
    45 #include <windows.h>
    46 #elif defined PLATFORM_POSIX
    47 #include <limits.h>
    48 #include <unistd.h>
    49 #include <sys/times.h>
    50 #endif
    51 
    52 HandleType_t g_PlIter;
    53 ConVar sm_datetime_format("sm_datetime_format", "%m/%d/%Y - %H:%M:%S", 0, "Default formatting time rules");
    54 IForward *g_OnLogAction = NULL;
    55 
    56 class CoreNativeHelpers : 
    57 	public SMGlobalClass,
    58 	public IHandleTypeDispatch
    59 {
    60 public:
    61 	void OnSourceModAllInitialized()
    62 	{
    63 		HandleAccess hacc;
    64 		handlesys->InitAccessDefaults(NULL,  &hacc);
    65 		hacc.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER;
    66 
    67 		g_PlIter = handlesys->CreateType("PluginIterator", this, 0, NULL, NULL, g_pCoreIdent, NULL);
    68 
    69 		g_OnLogAction = forwardsys->CreateForward("OnLogAction", 
    70 			ET_Hook, 
    71 			5, 
    72 			NULL,
    73 			Param_Cell,
    74 			Param_Cell,
    75 			Param_Cell,
    76 			Param_Cell,
    77 			Param_String);
    78 	}
    79 	void OnHandleDestroy(HandleType_t type, void *object)
    80 	{
    81 		IPluginIterator *iter = (IPluginIterator *)object;
    82 		iter->Release();
    83 	}
    84 	void OnSourceModShutdown()
    85 	{
    86 		forwardsys->ReleaseForward(g_OnLogAction);
    87 		handlesys->RemoveType(g_PlIter, g_pCoreIdent);
    88 	}
    89 } g_CoreNativeHelpers;
    90 
    91 void LogAction(Handle_t hndl, int type, int client, int target, const char *message)
    92 {
    93 	if (g_OnLogAction->GetFunctionCount())
    94 	{
    95 		cell_t result = 0;
    96 		g_OnLogAction->PushCell(hndl);
    97 		g_OnLogAction->PushCell(type);
    98 		g_OnLogAction->PushCell(client);
    99 		g_OnLogAction->PushCell(target);
   100 		g_OnLogAction->PushString(message);
   101 		g_OnLogAction->Execute(&result);
   102 
   103 		if (result >= (ResultType)Pl_Handled)
   104 		{
   105 			return;
   106 		}
   107 	}
   108 
   109 	const char *logtag = "SM";
   110 	if (type == 2)
   111 	{
   112 		HandleError err;
   113 		IPlugin *pPlugin = scripts->FindPluginByHandle(hndl, &err);
   114 		if (pPlugin)
   115 		{
   116 			logtag = pPlugin->GetFilename();
   117 		}
   118 	}
   119 
   120 	g_Logger.LogMessage("[%s] %s", logtag, message);
   121 }
   122 
   123 static cell_t ThrowError(IPluginContext *pContext, const cell_t *params)
   124 {
   125 	char buffer[512];
   126 
   127 	g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
   128 
   129 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
   130 
   131 	if (pContext->GetLastNativeError() == SP_ERROR_NONE)
   132 	{
   133 		pContext->ThrowNativeErrorEx(SP_ERROR_ABORTED, "%s", buffer);
   134 	}
   135 
   136 	return 0;
   137 }
   138 
   139 static cell_t GetTime(IPluginContext *pContext, const cell_t *params)
   140 {
   141 	time_t t = GetAdjustedTime();
   142 	cell_t *addr;
   143 	pContext->LocalToPhysAddr(params[1], &addr);
   144 
   145 	*(time_t *)addr = t;
   146 
   147 	return static_cast<cell_t>(t);
   148 }
   149 
   150 #if defined SUBPLATFORM_SECURECRT
   151 void _ignore_invalid_parameter(
   152 						const wchar_t * expression,
   153 						const wchar_t * function, 
   154 						const wchar_t * file, 
   155 						unsigned int line,
   156 						uintptr_t pReserved
   157 						)
   158 {
   159 	/* Wow we don't care, thanks Microsoft. */
   160 }
   161 #endif
   162 
   163 static cell_t FormatTime(IPluginContext *pContext, const cell_t *params)
   164 {
   165 	char *format, *buffer;
   166 	pContext->LocalToString(params[1], &buffer);
   167 	pContext->LocalToStringNULL(params[3], &format);
   168 
   169 	if (format == NULL)
   170 	{
   171 		format = const_cast<char *>(sm_datetime_format.GetString());
   172 	}
   173 
   174 #if defined SUBPLATFORM_SECURECRT
   175 	_invalid_parameter_handler handler = _set_invalid_parameter_handler(_ignore_invalid_parameter);
   176 #endif
   177 
   178 	time_t t = (params[4] == -1) ? GetAdjustedTime() : (time_t)params[4];
   179 	size_t written = strftime(buffer, params[2], format, localtime(&t));
   180 
   181 #if defined SUBPLATFORM_SECURECRT
   182 	_set_invalid_parameter_handler(handler);
   183 #endif
   184 
   185 	if (params[2] && format[0] != '\0' && !written)
   186 	{
   187 		pContext->ThrowNativeError("Invalid time format or buffer too small");
   188 		return 0;
   189 	}
   190 
   191 	return 1;
   192 }
   193 
   194 static cell_t GetPluginIterator(IPluginContext *pContext, const cell_t *params)
   195 {
   196 	IPluginIterator *iter = scripts->GetPluginIterator();
   197 
   198 	Handle_t hndl = handlesys->CreateHandle(g_PlIter, iter, pContext->GetIdentity(), g_pCoreIdent, NULL);
   199 
   200 	if (hndl == BAD_HANDLE)
   201 	{
   202 		iter->Release();
   203 	}
   204 
   205 	return hndl;
   206 }
   207 
   208 static cell_t MorePlugins(IPluginContext *pContext, const cell_t *params)
   209 {
   210 	Handle_t hndl = (Handle_t)params[1];
   211 	HandleError err;
   212 	IPluginIterator *pIter;
   213 
   214 	HandleSecurity sec;
   215 	sec.pIdentity = g_pCoreIdent;
   216 	sec.pOwner = pContext->GetIdentity();
   217 
   218 	if ((err=handlesys->ReadHandle(hndl, g_PlIter, &sec, (void **)&pIter)) != HandleError_None)
   219 	{
   220 		return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
   221 	}
   222 
   223 	return pIter->MorePlugins() ? 1 : 0;
   224 }
   225 
   226 static cell_t ReadPlugin(IPluginContext *pContext, const cell_t *params)
   227 {
   228 	Handle_t hndl = (Handle_t)params[1];
   229 	HandleError err;
   230 	IPluginIterator *pIter;
   231 
   232 	HandleSecurity sec;
   233 	sec.pIdentity = g_pCoreIdent;
   234 	sec.pOwner = pContext->GetIdentity();
   235 
   236 	if ((err=handlesys->ReadHandle(hndl, g_PlIter, &sec, (void **)&pIter)) != HandleError_None)
   237 	{
   238 		return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
   239 	}
   240 
   241 	IPlugin *pPlugin = pIter->GetPlugin();
   242 	if (!pPlugin)
   243 	{
   244 		return BAD_HANDLE;
   245 	}
   246 
   247 	pIter->NextPlugin();
   248 
   249 	return pPlugin->GetMyHandle();
   250 }
   251 
   252 IPlugin *GetPluginFromHandle(IPluginContext *pContext, Handle_t hndl)
   253 {
   254 	if (hndl == BAD_HANDLE)
   255 	{
   256 		return scripts->FindPluginByContext(pContext->GetContext());
   257 	} else {
   258 		HandleError err;
   259 		IPlugin *pPlugin = scripts->FindPluginByHandle(hndl, &err);
   260 		if (!pPlugin)
   261 		{
   262 			pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
   263 		}
   264 		return pPlugin;
   265 	}
   266 }
   267 
   268 static cell_t GetPluginStatus(IPluginContext *pContext, const cell_t *params)
   269 {
   270 	IPlugin *pPlugin = GetPluginFromHandle(pContext, params[1]);
   271 	if (!pPlugin)
   272 	{
   273 		return 0;
   274 	}
   275 
   276 	return pPlugin->GetStatus();
   277 }
   278 
   279 static cell_t GetPluginFilename(IPluginContext *pContext, const cell_t *params)
   280 {
   281 	IPlugin *pPlugin = GetPluginFromHandle(pContext, params[1]);
   282 	if (!pPlugin)
   283 	{
   284 		return 0;
   285 	}
   286 
   287 	pContext->StringToLocalUTF8(params[2], params[3], pPlugin->GetFilename(), NULL);
   288 
   289 	return 1;
   290 }
   291 
   292 static cell_t IsPluginDebugging(IPluginContext *pContext, const cell_t *params)
   293 {
   294 	IPlugin *pPlugin = GetPluginFromHandle(pContext, params[1]);
   295 	if (!pPlugin)
   296 	{
   297 		return 0;
   298 	}
   299 
   300 	return pPlugin->IsDebugging() ? 1 : 0;
   301 }
   302 
   303 /* Local to plugins only */
   304 enum PluginInfo
   305 {
   306 	PlInfo_Name,			/**< Plugin name */
   307 	PlInfo_Author,			/**< Plugin author */
   308 	PlInfo_Description,		/**< Plugin description */
   309 	PlInfo_Version,			/**< Plugin verison */
   310 	PlInfo_URL,				/**< Plugin URL */
   311 };
   312 
   313 static cell_t GetPluginInfo(IPluginContext *pContext, const cell_t *params)
   314 {
   315 	IPlugin *pPlugin = GetPluginFromHandle(pContext, params[1]);
   316 	if (!pPlugin)
   317 	{
   318 		return 0;
   319 	}
   320 
   321 	const sm_plugininfo_t *info = pPlugin->GetPublicInfo();
   322 
   323 	if (!info)
   324 	{
   325 		return 0;
   326 	}
   327 
   328 	const char *str = NULL;
   329 
   330 	switch ((PluginInfo)params[2])
   331 	{
   332 	case PlInfo_Name:
   333 		{
   334 			str = info->name;
   335 			break;
   336 		}
   337 	case PlInfo_Author:
   338 		{
   339 			str = info->author;
   340 			break;
   341 		}
   342 	case PlInfo_Description:
   343 		{
   344 			str = info->description;
   345 			break;
   346 		}
   347 	case PlInfo_Version:
   348 		{
   349 			str = info->version;
   350 			break;
   351 		}
   352 	case PlInfo_URL:
   353 		{
   354 			str = info->url;
   355 			break;
   356 		}
   357 	}
   358 
   359 	if (!str || str[0] == '\0')
   360 	{
   361 		return 0;
   362 	}
   363 
   364 	pContext->StringToLocalUTF8(params[3], params[4], str, NULL);
   365 
   366 	return 1;
   367 }
   368 
   369 static cell_t SetFailState(IPluginContext *pContext, const cell_t *params)
   370 {
   371 	char *str;
   372 	SMPlugin *pPlugin;
   373 
   374 	pContext->LocalToString(params[1], &str);
   375 	pPlugin = scripts->FindPluginByContext(pContext->GetContext());
   376 
   377 	if (params[0] == 1)
   378 	{
   379 		pPlugin->SetErrorState(Plugin_Error, "%s", str);
   380 
   381 		return pContext->ThrowNativeErrorEx(SP_ERROR_ABORTED, "%s", str);
   382 	}
   383 	else
   384 	{
   385 		char buffer[2048];
   386 
   387 		g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
   388 		if (pContext->GetLastNativeError() != SP_ERROR_NONE)
   389 		{
   390 			pPlugin->SetErrorState(Plugin_Error, "%s", str);
   391 			return pContext->ThrowNativeErrorEx(SP_ERROR_ABORTED, "Formatting error (%s)", str);
   392 		}
   393 		else
   394 		{
   395 			pPlugin->SetErrorState(Plugin_Error, "%s", buffer);
   396 			return pContext->ThrowNativeErrorEx(SP_ERROR_ABORTED, "%s", buffer);
   397 		}
   398 	}
   399 
   400 	return 0;
   401 }
   402 
   403 static cell_t GetSysTickCount(IPluginContext *pContext, const cell_t *params)
   404 {
   405 #if defined PLATFORM_WINDOWS
   406 	return (cell_t)GetTickCount();
   407 #elif defined PLATFORM_POSIX
   408 	tms tm;
   409 	clock_t ticks = times(&tm);
   410 	long ticks_per_sec = sysconf(_SC_CLK_TCK);
   411 	double fticks = (double)ticks / (double)ticks_per_sec;
   412 	fticks *= 1000.0f;
   413 	if (fticks > INT_MAX)
   414 	{
   415 		double r = (int)(fticks / INT_MAX) * (double)INT_MAX;
   416 		fticks -= r;
   417 	}
   418 	return (cell_t)fticks;
   419 #endif
   420 }
   421 
   422 static cell_t AutoExecConfig(IPluginContext *pContext, const cell_t *params)
   423 {
   424 	SMPlugin *plugin = scripts->FindPluginByContext(pContext->GetContext());
   425 
   426 	char *cfg, *folder;
   427 	pContext->LocalToString(params[2], &cfg);
   428 	pContext->LocalToString(params[3], &folder);
   429 
   430 	if (cfg[0] == '\0')
   431 	{
   432 		static char temp_str[255];
   433 		static char temp_file[PLATFORM_MAX_PATH];
   434 		char *ptr;
   435 
   436 		g_LibSys.GetFileFromPath(temp_str, sizeof(temp_str), plugin->GetFilename());
   437 		if ((ptr = strstr(temp_str, ".smx")) != NULL)
   438 		{
   439 			*ptr = '\0';
   440 		}
   441 
   442 		/* We have the raw filename! */
   443 		UTIL_Format(temp_file, sizeof(temp_file), "plugin.%s", temp_str);
   444 		cfg = temp_file;
   445 	}
   446 
   447 	plugin->AddConfig(params[1] ? true : false, cfg, folder);
   448 
   449 	return 1;
   450 }
   451 
   452 static cell_t MarkNativeAsOptional(IPluginContext *pContext, const cell_t *params)
   453 {
   454 	char *name;
   455 	uint32_t idx;
   456 	sp_native_t *native;
   457 
   458 	pContext->LocalToString(params[1], &name);
   459 	if (pContext->FindNativeByName(name, &idx) != SP_ERROR_NONE)
   460 	{
   461 		/* Oops! This HAS to silently fail! */
   462 		return 0;
   463 	}
   464 
   465 	pContext->GetNativeByIndex(idx, &native);
   466 
   467 	native->flags |= SP_NTVFLAG_OPTIONAL;
   468 
   469 	return 1;
   470 }
   471 
   472 static cell_t RegPluginLibrary(IPluginContext *pContext, const cell_t *params)
   473 {
   474 	char *name;
   475 	SMPlugin *pl = scripts->FindPluginByContext(pContext->GetContext());
   476 
   477 	pContext->LocalToString(params[1], &name);
   478 
   479 	pl->AddLibrary(name);
   480 	return 1;
   481 }
   482 
   483 static cell_t LibraryExists(IPluginContext *pContext, const cell_t *params)
   484 {
   485 	char *str;
   486 	pContext->LocalToString(params[1], &str);
   487 
   488 	if (strcmp(str, "__CanTestFeatures__") == 0)
   489 	{
   490 		return 1;
   491 	}
   492 
   493 	if (scripts->LibraryExists(str))
   494 	{
   495 		return 1;
   496 	}
   497 
   498 	if (extsys->LibraryExists(str))
   499 	{
   500 		return 1;
   501 	}
   502 
   503 	return 0;
   504 }
   505 
   506 static cell_t sm_LogAction(IPluginContext *pContext, const cell_t *params)
   507 {
   508 	char buffer[2048];
   509 	g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
   510 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 3);
   511 
   512 	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
   513 	{
   514 		return 0;
   515 	}
   516 
   517 	IPlugin *pPlugin = scripts->FindPluginByContext(pContext->GetContext());
   518 
   519 	LogAction(pPlugin->GetMyHandle(), 2, params[1], params[2], buffer);
   520 
   521 	return 1;
   522 }
   523 
   524 static cell_t LogToFile(IPluginContext *pContext, const cell_t *params)
   525 {
   526 	char *file;
   527 	pContext->LocalToString(params[1], &file);
   528 
   529 	char path[PLATFORM_MAX_PATH];
   530 	g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "%s", file);
   531 
   532 	FILE *fp = fopen(path, "at");
   533 	if (!fp)
   534 	{
   535 		return pContext->ThrowNativeError("Could not open file \"%s\"", path);
   536 	}
   537 
   538 	char buffer[2048];
   539 	g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
   540 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
   541 
   542 	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
   543 	{
   544 		fclose(fp);
   545 		return 0;
   546 	}
   547 
   548 	IPlugin *pPlugin = scripts->FindPluginByContext(pContext->GetContext());
   549 
   550 	g_Logger.LogToOpenFile(fp, "[%s] %s", pPlugin->GetFilename(), buffer);
   551 
   552 	fclose(fp);
   553 
   554 	return 1;
   555 }
   556 
   557 static cell_t LogToFileEx(IPluginContext *pContext, const cell_t *params)
   558 {
   559 	char *file;
   560 	pContext->LocalToString(params[1], &file);
   561 
   562 	char path[PLATFORM_MAX_PATH];
   563 	g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "%s", file);
   564 
   565 	FILE *fp = fopen(path, "at");
   566 	if (!fp)
   567 	{
   568 		return pContext->ThrowNativeError("Could not open file \"%s\"", path);
   569 	}
   570 
   571 	char buffer[2048];
   572 	g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
   573 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
   574 
   575 	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
   576 	{
   577 		fclose(fp);
   578 		return 0;
   579 	}
   580 
   581 	g_Logger.LogToOpenFile(fp, "%s", buffer);
   582 
   583 	fclose(fp);
   584 
   585 	return 1;
   586 }
   587 
   588 static cell_t GetExtensionFileStatus(IPluginContext *pContext, const cell_t *params)
   589 {
   590 	char *str;
   591 	pContext->LocalToString(params[1], &str);
   592 
   593 	IExtension *pExtension = extsys->FindExtensionByFile(str);
   594 	
   595 	if (!pExtension)
   596 	{
   597 		return -2;
   598 	}
   599 	
   600 	if (!pExtension->IsLoaded())
   601 	{
   602 		return -1;
   603 	}
   604 
   605 	char *error;
   606 	pContext->LocalToString(params[2], &error);
   607 	if (!pExtension->IsRunning(error, params[3]))
   608 	{
   609 		return 0;
   610 	}
   611 
   612 	return 1;
   613 }
   614 
   615 static cell_t FindPluginByNumber(IPluginContext *pContext, const cell_t *params)
   616 {
   617 	IPlugin *pPlugin = scripts->FindPluginByOrder(params[1]);
   618 	
   619 	if (pPlugin == NULL)
   620 	{
   621 		return BAD_HANDLE;
   622 	}
   623 
   624 	return pPlugin->GetMyHandle();
   625 }
   626 
   627 static cell_t VerifyCoreVersion(IPluginContext *pContext, const cell_t *params)
   628 {
   629 	return 4;
   630 }
   631 
   632 static cell_t GetFeatureStatus(IPluginContext *pContext, const cell_t *params)
   633 {
   634 	FeatureType type = (FeatureType)params[1];
   635 	char *name;
   636 
   637 	pContext->LocalToString(params[2], &name);
   638 
   639 	return sharesys->TestFeature(pContext->GetRuntime(), type, name);
   640 }
   641 
   642 static cell_t RequireFeature(IPluginContext *pContext, const cell_t *params)
   643 {
   644 	FeatureType type = (FeatureType)params[1];
   645 	char *name;
   646 
   647 	pContext->LocalToString(params[2], &name);
   648 
   649 	if (sharesys->TestFeature(pContext->GetRuntime(), type, name) != FeatureStatus_Available)
   650 	{
   651 		char buffer[255];
   652 		char *msg = buffer;
   653 		char default_message[255];
   654 		SMPlugin *pPlugin = scripts->FindPluginByContext(pContext->GetContext());
   655 
   656 		g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 3);
   657 		if (pContext->GetLastNativeError() != SP_ERROR_NONE || buffer[0] == '\0')
   658 		{
   659 			UTIL_Format(default_message, sizeof(default_message), "Feature \"%s\" not available", name);
   660 			msg = default_message;
   661 		}
   662 		pPlugin->SetErrorState(Plugin_Error, "%s", msg);
   663 		return pContext->ThrowNativeErrorEx(SP_ERROR_ABORTED, "%s", msg);
   664 	}
   665 
   666 	return 1;
   667 }
   668 
   669 enum NumberType
   670 {
   671 	NumberType_Int8,
   672 	NumberType_Int16,
   673 	NumberType_Int32
   674 };
   675 
   676 //memory addresses below 0x10000 are automatically considered invalid for dereferencing
   677 #define VALID_MINIMUM_MEMORY_ADDRESS 0x10000
   678 
   679 static cell_t LoadFromAddress(IPluginContext *pContext, const cell_t *params)
   680 {
   681 	void *addr = reinterpret_cast<void*>(params[1]);
   682 
   683 	if (addr == NULL)
   684 	{
   685 		pContext->ThrowNativeError("Address cannot be null");
   686 	}
   687 	else if (reinterpret_cast<uintptr_t>(addr) < VALID_MINIMUM_MEMORY_ADDRESS)
   688 	{
   689 		pContext->ThrowNativeError("Invalid address 0x%x is pointing to reserved memory.", addr);
   690 	}
   691 	NumberType size = static_cast<NumberType>(params[2]);
   692 
   693 	switch(size)
   694 	{
   695 	case NumberType_Int8:
   696 		return *reinterpret_cast<uint8_t*>(addr);
   697 	case NumberType_Int16:
   698 		return *reinterpret_cast<uint16_t*>(addr);
   699 	case NumberType_Int32:
   700 		return *reinterpret_cast<uint32_t*>(addr);
   701 	default:
   702 		pContext->ThrowNativeError("Invalid number types %d", size);
   703 	}
   704 
   705 	return 1;
   706 }
   707 
   708 
   709 static cell_t StoreToAddress(IPluginContext *pContext, const cell_t *params)
   710 {
   711 	void *addr = reinterpret_cast<void*>(params[1]);
   712 
   713 	if (addr == NULL)
   714 	{
   715 		pContext->ThrowNativeError("Address cannot be null");
   716 	}
   717 	else if (reinterpret_cast<uintptr_t>(addr) < VALID_MINIMUM_MEMORY_ADDRESS)
   718 	{
   719 		pContext->ThrowNativeError("Invalid address 0x%x is pointing to reserved memory.", addr);
   720 	}
   721 	cell_t data = params[2];
   722 
   723 	NumberType size = static_cast<NumberType>(params[3]);
   724 
   725 	switch(size)
   726 	{
   727 	case NumberType_Int8:
   728 		SourceHook::SetMemAccess(addr, sizeof(uint8_t), SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC);
   729 		*reinterpret_cast<uint8_t*>(addr) = data;
   730 		break;
   731 	case NumberType_Int16:
   732 		SourceHook::SetMemAccess(addr, sizeof(uint16_t), SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC);
   733 		*reinterpret_cast<uint16_t*>(addr) = data;
   734 		break;
   735 	case NumberType_Int32:
   736 		SourceHook::SetMemAccess(addr, sizeof(uint32_t), SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC);
   737 		*reinterpret_cast<uint32_t*>(addr) = data;
   738 		break;
   739 	default:
   740 		pContext->ThrowNativeError("Invalid number types %d", size);
   741 	}
   742 
   743 	return 1;
   744 }
   745 
   746 REGISTER_NATIVES(coreNatives)
   747 {
   748 	{"AutoExecConfig",			AutoExecConfig},
   749 	{"GetPluginFilename",		GetPluginFilename},
   750 	{"GetPluginInfo",			GetPluginInfo},
   751 	{"GetPluginIterator",		GetPluginIterator},
   752 	{"GetPluginStatus",			GetPluginStatus},
   753 	{"GetSysTickCount",			GetSysTickCount},
   754 	{"GetTime",					GetTime},
   755 	{"IsPluginDebugging",		IsPluginDebugging},
   756 	{"MorePlugins",				MorePlugins},
   757 	{"ReadPlugin",				ReadPlugin},
   758 	{"ThrowError",				ThrowError},
   759 	{"SetFailState",			SetFailState},
   760 	{"FormatTime",				FormatTime},
   761 	{"MarkNativeAsOptional",	MarkNativeAsOptional},
   762 	{"RegPluginLibrary",		RegPluginLibrary},
   763 	{"LibraryExists",			LibraryExists},
   764 	{"LogAction",				sm_LogAction},
   765 	{"LogToFile",				LogToFile},
   766 	{"LogToFileEx",				LogToFileEx},
   767 	{"GetExtensionFileStatus",	GetExtensionFileStatus},
   768 	{"FindPluginByNumber",		FindPluginByNumber},
   769 	{"VerifyCoreVersion",		VerifyCoreVersion},
   770 	{"GetFeatureStatus",        GetFeatureStatus},
   771 	{"RequireFeature",          RequireFeature},
   772 	{"LoadFromAddress",         LoadFromAddress},
   773 	{"StoreToAddress",          StoreToAddress},
   774 	{NULL,						NULL},
   775 };
   776