core/logic/smn_adt_array.cpp
author David Anderson <dvander@alliedmods.net>
Mon Oct 26 23:51:39 2009 -0700 (2009-10-26)
changeset 2832 bf5d37088b6d
parent 2726 c96f3fab8211
permissions -rw-r--r--
Don't pass unconnected clients into OnClientCommand (bug 3732, 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 <stdlib.h>
    33 #include "common_logic.h"
    34 #include "CellArray.h"
    35 
    36 HandleType_t htCellArray;
    37 
    38 class CellArrayHelpers : 
    39 	public SMGlobalClass,
    40 	public IHandleTypeDispatch
    41 {
    42 public: //SMGlobalClass
    43 	void OnSourceModAllInitialized()
    44 	{
    45 		htCellArray = handlesys->CreateType("CellArray", this, 0, NULL, NULL, g_pCoreIdent, NULL);
    46 	}
    47 	void OnSourceModShutdown()
    48 	{
    49 		handlesys->RemoveType(htCellArray, g_pCoreIdent);
    50 	}
    51 public: //IHandleTypeDispatch
    52 	void OnHandleDestroy(HandleType_t type, void *object)
    53 	{
    54 		CellArray *array = (CellArray *)object;
    55 		delete array;
    56 	}
    57 	bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
    58 	{
    59 		CellArray *pArray = (CellArray *)object;
    60 		*pSize = sizeof(CellArray) + pArray->mem_usage();
    61 		return true;
    62 	}
    63 } s_CellArrayHelpers;
    64 
    65 static cell_t CreateArray(IPluginContext *pContext, const cell_t *params)
    66 {
    67 	if (!params[1])
    68 	{
    69 		return pContext->ThrowNativeError("Invalid block size (must be > 0)");
    70 	}
    71 
    72 	CellArray *array = new CellArray(params[1]);
    73 
    74 	if (params[2])
    75 	{
    76 		array->resize(params[2]);
    77 	}
    78 	
    79 	Handle_t hndl = handlesys->CreateHandle(htCellArray, array, pContext->GetIdentity(), g_pCoreIdent, NULL);
    80 	if (!hndl)
    81 	{
    82 		delete array;
    83 	}
    84 
    85 	return hndl;
    86 }
    87 
    88 static cell_t ClearArray(IPluginContext *pContext, const cell_t *params)
    89 {
    90 	CellArray *array;
    91 	HandleError err;
    92 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
    93 
    94 	if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
    95 		!= HandleError_None)
    96 	{
    97 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
    98 	}
    99 
   100 	array->clear();
   101 	
   102 	return 1;
   103 }
   104 
   105 static cell_t ResizeArray(IPluginContext *pContext, const cell_t *params)
   106 {
   107 	CellArray *array;
   108 	HandleError err;
   109 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   110 
   111 	if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   112 		!= HandleError_None)
   113 	{
   114 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   115 	}
   116 
   117 	if (!array->resize(params[2]))
   118 	{
   119 		return pContext->ThrowNativeError("Unable to resize array to \"%u\"", params[2]);
   120 	}
   121 
   122 	return 1;
   123 }
   124 
   125 static cell_t GetArraySize(IPluginContext *pContext, const cell_t *params)
   126 {
   127 	CellArray *array;
   128 	HandleError err;
   129 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   130 
   131 	if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   132 		!= HandleError_None)
   133 	{
   134 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   135 	}
   136 
   137 	return (cell_t)array->size();
   138 }
   139 
   140 static cell_t PushArrayCell(IPluginContext *pContext, const cell_t *params)
   141 {
   142 	CellArray *array;
   143 	HandleError err;
   144 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   145 
   146 	if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   147 		!= HandleError_None)
   148 	{
   149 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   150 	}
   151 
   152 	cell_t *blk = array->push();
   153 	if (!blk)
   154 	{
   155 		return pContext->ThrowNativeError("Failed to grow array");
   156 	}
   157 
   158 	*blk = params[2];
   159 
   160 	return (cell_t)(array->size() - 1);
   161 }
   162 
   163 static cell_t PushArrayString(IPluginContext *pContext, const cell_t *params)
   164 {
   165 	CellArray *array;
   166 	HandleError err;
   167 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   168 
   169 	if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   170 		!= HandleError_None)
   171 	{
   172 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   173 	}
   174 
   175 	cell_t *blk = array->push();
   176 	if (!blk)
   177 	{
   178 		return pContext->ThrowNativeError("Failed to grow array");
   179 	}
   180 
   181 	char *str;
   182 	pContext->LocalToString(params[2], &str);
   183 
   184 	smcore.strncopy((char *)blk, str, array->blocksize() * sizeof(cell_t));
   185 
   186 	return (cell_t)(array->size() - 1);
   187 }
   188 
   189 static cell_t PushArrayArray(IPluginContext *pContext, const cell_t *params)
   190 {
   191 	CellArray *array;
   192 	HandleError err;
   193 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   194 
   195 	if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   196 		!= HandleError_None)
   197 	{
   198 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   199 	}
   200 
   201 	cell_t *blk = array->push();
   202 	if (!blk)
   203 	{
   204 		return pContext->ThrowNativeError("Failed to grow array");
   205 	}
   206 
   207 	cell_t *addr;
   208 	pContext->LocalToPhysAddr(params[2], &addr);
   209 
   210 	size_t indexes = array->blocksize();
   211 	if (params[3] != -1 && (size_t)params[3] <= array->blocksize())
   212 	{
   213 		indexes = params[3];
   214 	}
   215 
   216 	memcpy(blk, addr, sizeof(cell_t) * indexes);
   217 
   218 	return (cell_t)(array->size() - 1);
   219 }
   220 
   221 static cell_t GetArrayCell(IPluginContext *pContext, const cell_t *params)
   222 {
   223 	CellArray *array;
   224 	HandleError err;
   225 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   226 
   227 	if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   228 		!= HandleError_None)
   229 	{
   230 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   231 	}
   232 
   233 	size_t idx = (size_t)params[2];
   234 	if (idx >= array->size())
   235 	{
   236 		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
   237 	}
   238 
   239 	cell_t *blk = array->at(idx);
   240 
   241 	idx = (size_t)params[3];
   242 	if (params[4] == 0)
   243 	{
   244 		if (idx >= array->blocksize())
   245 		{
   246 			return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", idx, array->blocksize());
   247 		}
   248 		return blk[idx];
   249 	} else {
   250 		if (idx >= array->blocksize() * 4)
   251 		{
   252 			return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * 4);
   253 		}
   254 		return (cell_t)*((char *)blk + idx);
   255 	}
   256 
   257 	return 0;
   258 }
   259 
   260 static cell_t GetArrayString(IPluginContext *pContext, const cell_t *params)
   261 {
   262 	CellArray *array;
   263 	HandleError err;
   264 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   265 
   266 	if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   267 		!= HandleError_None)
   268 	{
   269 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   270 	}
   271 
   272 	size_t idx = (size_t)params[2];
   273 	if (idx >= array->size())
   274 	{
   275 		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
   276 	}
   277 
   278 	cell_t *blk = array->at(idx);
   279 	size_t numWritten = 0;
   280 
   281 	pContext->StringToLocalUTF8(params[3], params[4], (char *)blk, &numWritten);
   282 
   283 	return numWritten;
   284 }
   285 
   286 static cell_t GetArrayArray(IPluginContext *pContext, const cell_t *params)
   287 {
   288 	CellArray *array;
   289 	HandleError err;
   290 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   291 
   292 	if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   293 		!= HandleError_None)
   294 	{
   295 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   296 	}
   297 
   298 	size_t idx = (size_t)params[2];
   299 	if (idx >= array->size())
   300 	{
   301 		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
   302 	}
   303 
   304 	cell_t *blk = array->at(idx);
   305 	size_t indexes = array->blocksize();
   306 	if (params[4] != -1 && (size_t)params[4] <= array->blocksize())
   307 	{
   308 		indexes = params[4];
   309 	}
   310 
   311 	cell_t *addr;
   312 	pContext->LocalToPhysAddr(params[3], &addr);
   313 
   314 	memcpy(addr, blk, sizeof(cell_t) * indexes);
   315 
   316 	return indexes;
   317 }
   318 
   319 static cell_t SetArrayCell(IPluginContext *pContext, const cell_t *params)
   320 {
   321 	CellArray *array;
   322 	HandleError err;
   323 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   324 
   325 	if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   326 		!= HandleError_None)
   327 	{
   328 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   329 	}
   330 
   331 	size_t idx = (size_t)params[2];
   332 	if (idx >= array->size())
   333 	{
   334 		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
   335 	}
   336 
   337 	cell_t *blk = array->at(idx);
   338 
   339 	idx = (size_t)params[4];
   340 	if (params[5] == 0)
   341 	{
   342 		if (idx >= array->blocksize())
   343 		{
   344 			return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", idx, array->blocksize());
   345 		}
   346 		blk[idx] = params[3];
   347 	} else {
   348 		if (idx >= array->blocksize() * 4)
   349 		{
   350 			return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * 4);
   351 		}
   352 		*((char *)blk + idx) = (char)params[3];
   353 	}
   354 
   355 	return 1;
   356 }
   357 
   358 static cell_t SetArrayString(IPluginContext *pContext, const cell_t *params)
   359 {
   360 	CellArray *array;
   361 	HandleError err;
   362 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   363 
   364 	if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   365 		!= HandleError_None)
   366 	{
   367 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   368 	}
   369 
   370 	size_t idx = (size_t)params[2];
   371 	if (idx >= array->size())
   372 	{
   373 		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
   374 	}
   375 
   376 	cell_t *blk = array->at(idx);
   377 
   378 	char *str;
   379 	pContext->LocalToString(params[3], &str);
   380 
   381 	return smcore.strncopy((char *)blk, str, array->blocksize() * sizeof(cell_t));
   382 }
   383 
   384 static cell_t SetArrayArray(IPluginContext *pContext, const cell_t *params)
   385 {
   386 	CellArray *array;
   387 	HandleError err;
   388 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   389 
   390 	if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   391 		!= HandleError_None)
   392 	{
   393 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   394 	}
   395 
   396 	size_t idx = (size_t)params[2];
   397 	if (idx >= array->size())
   398 	{
   399 		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
   400 	}
   401 
   402 	cell_t *blk = array->at(idx);
   403 	size_t indexes = array->blocksize();
   404 	if (params[4] != -1 && (size_t)params[4] <= array->blocksize())
   405 	{
   406 		indexes = params[4];
   407 	}
   408 
   409 	cell_t *addr;
   410 	pContext->LocalToPhysAddr(params[3], &addr);
   411 
   412 	memcpy(blk, addr, sizeof(cell_t) * indexes);
   413 
   414 	return indexes;
   415 }
   416 
   417 static cell_t ShiftArrayUp(IPluginContext *pContext, const cell_t *params)
   418 {
   419 	CellArray *array;
   420 	HandleError err;
   421 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   422 
   423 	if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   424 		!= HandleError_None)
   425 	{
   426 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   427 	}
   428 
   429 	size_t idx = (size_t)params[2];
   430 	if (idx >= array->size())
   431 	{
   432 		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
   433 	}
   434 
   435 	array->insert_at(idx);
   436 
   437 	return 1;
   438 }
   439 
   440 static cell_t RemoveFromArray(IPluginContext *pContext, const cell_t *params)
   441 {
   442 	CellArray *array;
   443 	HandleError err;
   444 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   445 
   446 	if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   447 		!= HandleError_None)
   448 	{
   449 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   450 	}
   451 
   452 	size_t idx = (size_t)params[2];
   453 	if (idx >= array->size())
   454 	{
   455 		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
   456 	}
   457 
   458 	array->remove(idx);
   459 
   460 	return 1;
   461 }
   462 
   463 static cell_t SwapArrayItems(IPluginContext *pContext, const cell_t *params)
   464 {
   465 	CellArray *array;
   466 	HandleError err;
   467 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   468 
   469 	if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   470 		!= HandleError_None)
   471 	{
   472 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   473 	}
   474 
   475 	size_t idx1 = (size_t)params[2];
   476 	size_t idx2 = (size_t)params[3];
   477 	if (idx1 >= array->size())
   478 	{
   479 		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx1, array->size());
   480 	}
   481 	if (idx2 >= array->size())
   482 	{
   483 		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx2, array->size());
   484 	}
   485 
   486 	array->swap(idx1, idx2);
   487 
   488 	return 1;
   489 }
   490 
   491 static cell_t CloneArray(IPluginContext *pContext, const cell_t *params)
   492 {
   493 	CellArray *oldArray;
   494 	HandleError err;
   495 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   496 
   497 	if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&oldArray)) 
   498 		!= HandleError_None)
   499 	{
   500 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   501 	}
   502 
   503 	CellArray *array = oldArray->clone();
   504 	
   505 	Handle_t hndl = handlesys->CreateHandle(htCellArray, array, pContext->GetIdentity(), g_pCoreIdent, NULL);
   506 	if (!hndl)
   507 	{
   508 		delete array;
   509 	}
   510 
   511 	return hndl;
   512 }
   513 
   514 static cell_t FindStringInArray(IPluginContext *pContext, const cell_t *params)
   515 {
   516 	CellArray *array;
   517 	HandleError err;
   518 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   519 
   520 	if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   521 		!= HandleError_None)
   522 	{
   523 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   524 	}
   525 
   526 	char *str;
   527 	pContext->LocalToString(params[2], &str);
   528 
   529 	for (unsigned int i = 0; i < array->size(); i++)
   530 	{
   531 		const char *array_str = (const char *)array->at(i);
   532 		if (strcmp(str, array_str) == 0)
   533 		{
   534 			return (cell_t) i;
   535 		}
   536 	}
   537 
   538 	return -1;
   539 }
   540 
   541 static cell_t FindValueInArray(IPluginContext *pContext, const cell_t *params)
   542 {
   543 	CellArray *array;
   544 	HandleError err;
   545 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   546 
   547 	if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   548 		!= HandleError_None)
   549 	{
   550 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   551 	}
   552 
   553 	for (unsigned int i = 0; i < array->size(); i++)
   554 	{
   555 		if (params[2] == *array->at(i))
   556 		{
   557 			return (cell_t) i;
   558 		}
   559 	}
   560 
   561 	return -1;
   562 }
   563 
   564 REGISTER_NATIVES(cellArrayNatives)
   565 {
   566 	{"ClearArray",					ClearArray},
   567 	{"CreateArray",					CreateArray},
   568 	{"GetArrayArray",				GetArrayArray},
   569 	{"GetArrayCell",				GetArrayCell},
   570 	{"GetArraySize",				GetArraySize},
   571 	{"GetArrayString",				GetArrayString},
   572 	{"ResizeArray",					ResizeArray},
   573 	{"PushArrayArray",				PushArrayArray},
   574 	{"PushArrayCell",				PushArrayCell},
   575 	{"PushArrayString",				PushArrayString},
   576 	{"RemoveFromArray",				RemoveFromArray},
   577 	{"SetArrayCell",				SetArrayCell},
   578 	{"SetArrayString",				SetArrayString},
   579 	{"SetArrayArray",				SetArrayArray},
   580 	{"ShiftArrayUp",				ShiftArrayUp},
   581 	{"SwapArrayItems",				SwapArrayItems},
   582 	{"CloneArray",					CloneArray},
   583 	{"FindStringInArray",			FindStringInArray},
   584 	{"FindValueInArray",			FindValueInArray},
   585 	{NULL,							NULL},
   586 };