core/smn_adt_array.cpp
author David Anderson <dvander@alliedmods.net>
Tue Sep 11 18:08:49 2007 +0000 (2007-09-11)
changeset 1408 2fd63cc4bd9c
parent 1330 ab94316bb52b
child 1664 e054be79e28a
permissions -rw-r--r--
timelimit function now gets initialized
     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 } s_CellArrayHelpers;
    60 
    61 static cell_t CreateArray(IPluginContext *pContext, const cell_t *params)
    62 {
    63 	if (!params[1])
    64 	{
    65 		return pContext->ThrowNativeError("Invalid block size (must be > 0)");
    66 	}
    67 
    68 	CellArray *array = new CellArray(params[1]);
    69 
    70 	if (params[2])
    71 	{
    72 		array->resize(params[2]);
    73 	}
    74 	
    75 	Handle_t hndl = g_HandleSys.CreateHandle(htCellArray, array, pContext->GetIdentity(), g_pCoreIdent, NULL);
    76 	if (!hndl)
    77 	{
    78 		delete array;
    79 	}
    80 
    81 	return hndl;
    82 }
    83 
    84 static cell_t ClearArray(IPluginContext *pContext, const cell_t *params)
    85 {
    86 	CellArray *array;
    87 	HandleError err;
    88 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
    89 
    90 	if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
    91 		!= HandleError_None)
    92 	{
    93 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
    94 	}
    95 
    96 	array->clear();
    97 	
    98 	return 1;
    99 }
   100 
   101 static cell_t ResizeArray(IPluginContext *pContext, const cell_t *params)
   102 {
   103 	CellArray *array;
   104 	HandleError err;
   105 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   106 
   107 	if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   108 		!= HandleError_None)
   109 	{
   110 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   111 	}
   112 
   113 	if (!array->resize(params[2]))
   114 	{
   115 		return pContext->ThrowNativeError("Unable to resize array to \"%u\"", params[2]);
   116 	}
   117 
   118 	return 1;
   119 }
   120 
   121 static cell_t GetArraySize(IPluginContext *pContext, const cell_t *params)
   122 {
   123 	CellArray *array;
   124 	HandleError err;
   125 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   126 
   127 	if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   128 		!= HandleError_None)
   129 	{
   130 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   131 	}
   132 
   133 	return (cell_t)array->size();
   134 }
   135 
   136 static cell_t PushArrayCell(IPluginContext *pContext, const cell_t *params)
   137 {
   138 	CellArray *array;
   139 	HandleError err;
   140 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   141 
   142 	if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   143 		!= HandleError_None)
   144 	{
   145 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   146 	}
   147 
   148 	cell_t *blk = array->push();
   149 	if (!blk)
   150 	{
   151 		return pContext->ThrowNativeError("Failed to grow array");
   152 	}
   153 
   154 	*blk = params[2];
   155 
   156 	return (cell_t)(array->size() - 1);
   157 }
   158 
   159 static cell_t PushArrayString(IPluginContext *pContext, const cell_t *params)
   160 {
   161 	CellArray *array;
   162 	HandleError err;
   163 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   164 
   165 	if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   166 		!= HandleError_None)
   167 	{
   168 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   169 	}
   170 
   171 	cell_t *blk = array->push();
   172 	if (!blk)
   173 	{
   174 		return pContext->ThrowNativeError("Failed to grow array");
   175 	}
   176 
   177 	char *str;
   178 	pContext->LocalToString(params[2], &str);
   179 
   180 	strncopy((char *)blk, str, array->blocksize() * sizeof(cell_t));
   181 
   182 	return (cell_t)(array->size() - 1);
   183 }
   184 
   185 static cell_t PushArrayArray(IPluginContext *pContext, const cell_t *params)
   186 {
   187 	CellArray *array;
   188 	HandleError err;
   189 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   190 
   191 	if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   192 		!= HandleError_None)
   193 	{
   194 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   195 	}
   196 
   197 	cell_t *blk = array->push();
   198 	if (!blk)
   199 	{
   200 		return pContext->ThrowNativeError("Failed to grow array");
   201 	}
   202 
   203 	cell_t *addr;
   204 	pContext->LocalToPhysAddr(params[2], &addr);
   205 
   206 	size_t indexes = array->blocksize();
   207 	if (params[3] != -1 && (size_t)params[3] <= array->blocksize())
   208 	{
   209 		indexes = params[3];
   210 	}
   211 
   212 	memcpy(blk, addr, sizeof(cell_t) * indexes);
   213 
   214 	return (cell_t)(array->size() - 1);
   215 }
   216 
   217 static cell_t GetArrayCell(IPluginContext *pContext, const cell_t *params)
   218 {
   219 	CellArray *array;
   220 	HandleError err;
   221 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   222 
   223 	if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   224 		!= HandleError_None)
   225 	{
   226 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   227 	}
   228 
   229 	size_t idx = (size_t)params[2];
   230 	if (idx >= array->size())
   231 	{
   232 		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
   233 	}
   234 
   235 	cell_t *blk = array->at(idx);
   236 
   237 	idx = (size_t)params[3];
   238 	if (params[4] == 0)
   239 	{
   240 		if (idx >= array->blocksize())
   241 		{
   242 			return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", idx, array->blocksize());
   243 		}
   244 		return blk[idx];
   245 	} else {
   246 		if (idx >= array->blocksize() * 4)
   247 		{
   248 			return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * 4);
   249 		}
   250 		return (cell_t)*((char *)blk + idx);
   251 	}
   252 
   253 	return 0;
   254 }
   255 
   256 static cell_t GetArrayString(IPluginContext *pContext, const cell_t *params)
   257 {
   258 	CellArray *array;
   259 	HandleError err;
   260 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   261 
   262 	if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   263 		!= HandleError_None)
   264 	{
   265 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   266 	}
   267 
   268 	size_t idx = (size_t)params[2];
   269 	if (idx >= array->size())
   270 	{
   271 		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
   272 	}
   273 
   274 	cell_t *blk = array->at(idx);
   275 	size_t numWritten = 0;
   276 
   277 	pContext->StringToLocalUTF8(params[3], params[4], (char *)blk, &numWritten);
   278 
   279 	return numWritten;
   280 }
   281 
   282 static cell_t GetArrayArray(IPluginContext *pContext, const cell_t *params)
   283 {
   284 	CellArray *array;
   285 	HandleError err;
   286 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   287 
   288 	if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   289 		!= HandleError_None)
   290 	{
   291 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   292 	}
   293 
   294 	size_t idx = (size_t)params[2];
   295 	if (idx >= array->size())
   296 	{
   297 		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
   298 	}
   299 
   300 	cell_t *blk = array->at(idx);
   301 	size_t indexes = array->blocksize();
   302 	if (params[4] != -1 && (size_t)params[4] <= array->blocksize())
   303 	{
   304 		indexes = params[4];
   305 	}
   306 
   307 	cell_t *addr;
   308 	pContext->LocalToPhysAddr(params[3], &addr);
   309 
   310 	memcpy(addr, blk, sizeof(cell_t) * indexes);
   311 
   312 	return indexes;
   313 }
   314 
   315 static cell_t SetArrayCell(IPluginContext *pContext, const cell_t *params)
   316 {
   317 	CellArray *array;
   318 	HandleError err;
   319 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   320 
   321 	if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   322 		!= HandleError_None)
   323 	{
   324 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   325 	}
   326 
   327 	size_t idx = (size_t)params[2];
   328 	if (idx >= array->size())
   329 	{
   330 		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
   331 	}
   332 
   333 	cell_t *blk = array->at(idx);
   334 
   335 	idx = (size_t)params[4];
   336 	if (params[5] == 0)
   337 	{
   338 		if (idx >= array->blocksize())
   339 		{
   340 			return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", idx, array->blocksize());
   341 		}
   342 		blk[idx] = params[3];
   343 	} else {
   344 		if (idx >= array->blocksize() * 4)
   345 		{
   346 			return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * 4);
   347 		}
   348 		*((char *)blk + idx) = (char)params[3];
   349 	}
   350 
   351 	return 1;
   352 }
   353 
   354 static cell_t SetArrayString(IPluginContext *pContext, const cell_t *params)
   355 {
   356 	CellArray *array;
   357 	HandleError err;
   358 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   359 
   360 	if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   361 		!= HandleError_None)
   362 	{
   363 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   364 	}
   365 
   366 	size_t idx = (size_t)params[2];
   367 	if (idx >= array->size())
   368 	{
   369 		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
   370 	}
   371 
   372 	cell_t *blk = array->at(idx);
   373 
   374 	char *str;
   375 	pContext->LocalToString(params[3], &str);
   376 
   377 	return strncopy((char *)blk, str, array->blocksize() * sizeof(cell_t));
   378 }
   379 
   380 static cell_t SetArrayArray(IPluginContext *pContext, const cell_t *params)
   381 {
   382 	CellArray *array;
   383 	HandleError err;
   384 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   385 
   386 	if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   387 		!= HandleError_None)
   388 	{
   389 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   390 	}
   391 
   392 	size_t idx = (size_t)params[2];
   393 	if (idx >= array->size())
   394 	{
   395 		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
   396 	}
   397 
   398 	cell_t *blk = array->at(idx);
   399 	size_t indexes = array->blocksize();
   400 	if (params[4] != -1 && (size_t)params[4] <= array->blocksize())
   401 	{
   402 		indexes = params[4];
   403 	}
   404 
   405 	cell_t *addr;
   406 	pContext->LocalToPhysAddr(params[3], &addr);
   407 
   408 	memcpy(blk, addr, sizeof(cell_t) * indexes);
   409 
   410 	return indexes;
   411 }
   412 
   413 static cell_t ShiftArrayUp(IPluginContext *pContext, const cell_t *params)
   414 {
   415 	CellArray *array;
   416 	HandleError err;
   417 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   418 
   419 	if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   420 		!= HandleError_None)
   421 	{
   422 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   423 	}
   424 
   425 	size_t idx = (size_t)params[2];
   426 	if (idx >= array->size())
   427 	{
   428 		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
   429 	}
   430 
   431 	array->insert_at(idx);
   432 
   433 	return 1;
   434 }
   435 
   436 static cell_t RemoveFromArray(IPluginContext *pContext, const cell_t *params)
   437 {
   438 	CellArray *array;
   439 	HandleError err;
   440 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   441 
   442 	if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   443 		!= HandleError_None)
   444 	{
   445 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   446 	}
   447 
   448 	size_t idx = (size_t)params[2];
   449 	if (idx >= array->size())
   450 	{
   451 		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
   452 	}
   453 
   454 	array->remove(idx);
   455 
   456 	return 1;
   457 }
   458 
   459 static cell_t SwapArrayItems(IPluginContext *pContext, const cell_t *params)
   460 {
   461 	CellArray *array;
   462 	HandleError err;
   463 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   464 
   465 	if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&array)) 
   466 		!= HandleError_None)
   467 	{
   468 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   469 	}
   470 
   471 	size_t idx1 = (size_t)params[2];
   472 	size_t idx2 = (size_t)params[3];
   473 	if (idx1 >= array->size())
   474 	{
   475 		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx1, array->size());
   476 	}
   477 	if (idx2 >= array->size())
   478 	{
   479 		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx2, array->size());
   480 	}
   481 
   482 	array->swap(idx1, idx2);
   483 
   484 	return 1;
   485 }
   486 
   487 REGISTER_NATIVES(cellArrayNatives)
   488 {
   489 	{"ClearArray",					ClearArray},
   490 	{"CreateArray",					CreateArray},
   491 	{"GetArrayArray",				GetArrayArray},
   492 	{"GetArrayCell",				GetArrayCell},
   493 	{"GetArraySize",				GetArraySize},
   494 	{"GetArrayString",				GetArrayString},
   495 	{"ResizeArray",					ResizeArray},
   496 	{"PushArrayArray",				PushArrayArray},
   497 	{"PushArrayCell",				PushArrayCell},
   498 	{"PushArrayString",				PushArrayString},
   499 	{"RemoveFromArray",				RemoveFromArray},
   500 	{"SetArrayCell",				SetArrayCell},
   501 	{"SetArrayString",				SetArrayString},
   502 	{"SetArrayArray",				SetArrayArray},
   503 	{"ShiftArrayUp",				ShiftArrayUp},
   504 	{"SwapArrayItems",				SwapArrayItems},
   505 	{NULL,							NULL},
   506 };