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