core/smn_keyvalues.cpp
author David Anderson <dvander@alliedmods.net>
Wed Feb 27 13:49:57 2008 +0000 (2008-02-27)
changeset 1900 457329ae65bd
parent 1766 d30c252089be
child 1936 89d6e5038933
permissions -rw-r--r--
fixed amb1483 - GetEntPropString() rejected FIELD_MODELNAME/FIELD_SOUNDNAME
     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 "sourcemod.h"
    33 #include "sourcemm_api.h"
    34 #include "sm_stringutil.h"
    35 #include "HandleSys.h"
    36 #include <KeyValues.h>
    37 #include "utlbuffer.h"
    38 
    39 HandleType_t g_KeyValueType;
    40 
    41 struct KeyValueStack 
    42 {
    43 	KeyValues *pBase;
    44 	CStack<KeyValues *> pCurRoot;
    45 };
    46 
    47 class KeyValueNatives : 
    48 	public SMGlobalClass,
    49 	public IHandleTypeDispatch
    50 {
    51 public:
    52 	void OnSourceModAllInitialized()
    53 	{
    54 		g_KeyValueType = g_HandleSys.CreateType("KeyValues", this, 0, NULL, NULL, g_pCoreIdent, NULL);
    55 	}
    56 	void OnSourceModShutdown()
    57 	{
    58 		g_HandleSys.RemoveType(g_KeyValueType, g_pCoreIdent);
    59 		g_KeyValueType = 0;
    60 	}
    61 	void OnHandleDestroy(HandleType_t type, void *object)
    62 	{
    63 		KeyValueStack *pStk = reinterpret_cast<KeyValueStack *>(object);
    64 		pStk->pBase->deleteThis();
    65 		delete pStk;
    66 	}
    67 	int CalcKVSizeR(KeyValues *pv)
    68 	{
    69 		CUtlBuffer buf;
    70 		int size;
    71 
    72 		pv->RecursiveSaveToFile(buf, 0);
    73 		size = buf.TellMaxPut();
    74 
    75 		buf.Purge();
    76 
    77 		return size;
    78 	}
    79 	bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
    80 	{
    81 		KeyValueStack *pStk = (KeyValueStack *)object;
    82 		unsigned int size = sizeof(KeyValueStack) + (pStk->pCurRoot.size() * sizeof(KeyValues *));
    83 
    84 		/* Check how much memory the actual thing takes up */		
    85 		size += CalcKVSizeR(pStk->pBase);
    86 
    87 		*pSize = size;
    88 
    89 		return true;
    90 	}
    91 };
    92 
    93 KeyValues *SourceModBase::ReadKeyValuesHandle(Handle_t hndl, HandleError *err, bool root)
    94 {
    95 	HandleError herr;
    96 	HandleSecurity sec;
    97 	KeyValueStack *pStk;
    98 
    99 	sec.pOwner = NULL;
   100 	sec.pIdentity = g_pCoreIdent;
   101 
   102 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   103 		!= HandleError_None)
   104 	{
   105 		if (err)
   106 		{
   107 			*err = herr;
   108 		}
   109 		return NULL;
   110 	}
   111 
   112 	if (err)
   113 	{
   114 		*err = HandleError_None;
   115 	}
   116 
   117 	return (root) ? pStk->pBase : pStk->pCurRoot.front();
   118 }
   119 
   120 static cell_t smn_KvSetString(IPluginContext *pCtx, const cell_t *params)
   121 {
   122 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   123 	HandleError herr;
   124 	HandleSecurity sec;
   125 	KeyValueStack *pStk;
   126 
   127 	sec.pOwner = NULL;
   128 	sec.pIdentity = g_pCoreIdent;
   129 
   130 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   131 		!= HandleError_None)
   132 	{
   133 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   134 	}
   135 
   136 	char *key, *value;
   137 	pCtx->LocalToStringNULL(params[2], &key);
   138 	pCtx->LocalToString(params[3], &value);
   139 
   140 	pStk->pCurRoot.front()->SetString(key, value);
   141 
   142 	return 1;
   143 }
   144 
   145 static cell_t smn_KvSetNum(IPluginContext *pCtx, const cell_t *params)
   146 {
   147 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   148 	HandleError herr;
   149 	HandleSecurity sec;
   150 	KeyValueStack *pStk;
   151 
   152 	sec.pOwner = NULL;
   153 	sec.pIdentity = g_pCoreIdent;
   154 
   155 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   156 		!= HandleError_None)
   157 	{
   158 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   159 	}
   160 
   161 	char *key;
   162 	pCtx->LocalToStringNULL(params[2], &key);
   163 
   164 	pStk->pCurRoot.front()->SetInt(key, params[3]);
   165 
   166 	return 1;
   167 }
   168 
   169 static cell_t smn_KvSetUInt64(IPluginContext *pCtx, const cell_t *params)
   170 {
   171 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   172 	HandleError herr;
   173 	HandleSecurity sec;
   174 	KeyValueStack *pStk;
   175 
   176 	sec.pOwner = NULL;
   177 	sec.pIdentity = g_pCoreIdent;
   178 
   179 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   180 		!= HandleError_None)
   181 	{
   182 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   183 	}
   184 
   185 	char *key;
   186 	cell_t *addr;
   187 	uint64 value;
   188 	pCtx->LocalToStringNULL(params[2], &key);
   189 	pCtx->LocalToPhysAddr(params[3], &addr);
   190 
   191 	value = static_cast<uint64>(*addr);
   192 	pStk->pCurRoot.front()->SetUint64(key, value);
   193 
   194 	return 1;
   195 }
   196 
   197 static cell_t smn_KvSetFloat(IPluginContext *pCtx, const cell_t *params)
   198 {
   199 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   200 	HandleError herr;
   201 	HandleSecurity sec;
   202 	KeyValueStack *pStk;
   203 
   204 	sec.pOwner = NULL;
   205 	sec.pIdentity = g_pCoreIdent;
   206 
   207 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   208 		!= HandleError_None)
   209 	{
   210 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   211 	}
   212 
   213 	char *key;
   214 	pCtx->LocalToStringNULL(params[2], &key);
   215 
   216 	pStk->pCurRoot.front()->SetFloat(key, sp_ctof(params[3]));
   217 
   218 	return 1;
   219 }
   220 
   221 static cell_t smn_KvSetColor(IPluginContext *pCtx, const cell_t *params)
   222 {
   223 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   224 	HandleError herr;
   225 	HandleSecurity sec;
   226 	KeyValueStack *pStk;
   227 
   228 	sec.pOwner = NULL;
   229 	sec.pIdentity = g_pCoreIdent;
   230 
   231 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   232 		!= HandleError_None)
   233 	{
   234 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   235 	}
   236 
   237 	char *key;
   238 	pCtx->LocalToStringNULL(params[2], &key);
   239 
   240 	Color color(params[3], params[4], params[5], params[6]);
   241 	pStk->pCurRoot.front()->SetColor(key, color);
   242 
   243 	return 1;
   244 }
   245 
   246 static cell_t smn_KvSetVector(IPluginContext *pCtx, const cell_t *params)
   247 {
   248 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   249 	HandleError herr;
   250 	HandleSecurity sec;
   251 	KeyValueStack *pStk;
   252 
   253 	sec.pOwner = NULL;
   254 	sec.pIdentity = g_pCoreIdent;
   255 
   256 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   257 		!= HandleError_None)
   258 	{
   259 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   260 	}
   261 
   262 	char *key;
   263 	char buffer[64];
   264 	cell_t *vector;
   265 	pCtx->LocalToStringNULL(params[2], &key);
   266 	pCtx->LocalToPhysAddr(params[3], &vector);
   267 
   268 	UTIL_Format(buffer, sizeof(buffer), "%f %f %f", sp_ctof(vector[0]), sp_ctof(vector[1]), sp_ctof(vector[2]));
   269 
   270 	pStk->pCurRoot.front()->SetString(key, buffer);
   271 
   272 	return 1;
   273 }
   274 
   275 static cell_t smn_KvGetString(IPluginContext *pCtx, const cell_t *params)
   276 {
   277 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   278 	HandleError herr;
   279 	HandleSecurity sec;
   280 	KeyValueStack *pStk;
   281 
   282 	sec.pOwner = NULL;
   283 	sec.pIdentity = g_pCoreIdent;
   284 
   285 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   286 		!= HandleError_None)
   287 	{
   288 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   289 	}
   290 
   291 	const char *value;
   292 	char *key, *defvalue;
   293 	pCtx->LocalToStringNULL(params[2], &key);
   294 	pCtx->LocalToString(params[5], &defvalue);
   295 
   296 	value = pStk->pCurRoot.front()->GetString(key, defvalue);
   297 	pCtx->StringToLocalUTF8(params[3], params[4], value, NULL);
   298 
   299 	return 1;
   300 }
   301 
   302 static cell_t smn_KvGetNum(IPluginContext *pCtx, const cell_t *params)
   303 {
   304 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   305 	HandleError herr;
   306 	HandleSecurity sec;
   307 	KeyValueStack *pStk;
   308 
   309 	sec.pOwner = NULL;
   310 	sec.pIdentity = g_pCoreIdent;
   311 
   312 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   313 		!= HandleError_None)
   314 	{
   315 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   316 	}
   317 
   318 	int value;
   319 	char *key;
   320 	pCtx->LocalToStringNULL(params[2], &key);
   321 
   322 	value = pStk->pCurRoot.front()->GetInt(key, params[3]);
   323 
   324 	return value;
   325 }
   326 
   327 static cell_t smn_KvGetFloat(IPluginContext *pCtx, const cell_t *params)
   328 {
   329 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   330 	HandleError herr;
   331 	HandleSecurity sec;
   332 	KeyValueStack *pStk;
   333 
   334 	sec.pOwner = NULL;
   335 	sec.pIdentity = g_pCoreIdent;
   336 
   337 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   338 		!= HandleError_None)
   339 	{
   340 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   341 	}
   342 
   343 	float value;
   344 	char *key;
   345 	pCtx->LocalToStringNULL(params[2], &key);
   346 
   347 	value = pStk->pCurRoot.front()->GetFloat(key, sp_ctof(params[3]));
   348 
   349 	return sp_ftoc(value);
   350 }
   351 
   352 static cell_t smn_KvGetColor(IPluginContext *pCtx, const cell_t *params)
   353 {
   354 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   355 	HandleError herr;
   356 	HandleSecurity sec;
   357 	KeyValueStack *pStk;
   358 
   359 	sec.pOwner = NULL;
   360 	sec.pIdentity = g_pCoreIdent;
   361 
   362 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   363 		!= HandleError_None)
   364 	{
   365 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   366 	}
   367 
   368 	Color color;
   369 	char *key;
   370 	cell_t *r, *g, *b, *a;
   371 	pCtx->LocalToStringNULL(params[2], &key);
   372 	pCtx->LocalToPhysAddr(params[3], &r);
   373 	pCtx->LocalToPhysAddr(params[4], &g);
   374 	pCtx->LocalToPhysAddr(params[5], &b);
   375 	pCtx->LocalToPhysAddr(params[6], &a);
   376 
   377 	color = pStk->pCurRoot.front()->GetColor(key);
   378 	*r = color.r();
   379 	*g = color.g();
   380 	*b = color.b();
   381 	*a = color.a();
   382 
   383 	return 1;
   384 }
   385 
   386 static cell_t smn_KvGetUInt64(IPluginContext *pCtx, const cell_t *params)
   387 {
   388 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   389 	HandleError herr;
   390 	HandleSecurity sec;
   391 	KeyValueStack *pStk;
   392 
   393 	sec.pOwner = NULL;
   394 	sec.pIdentity = g_pCoreIdent;
   395 
   396 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   397 		!= HandleError_None)
   398 	{
   399 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   400 	}
   401 
   402 	char *key;
   403 	cell_t *addr, *defvalue;
   404 	uint64 value;
   405 	pCtx->LocalToStringNULL(params[2], &key);
   406 	pCtx->LocalToPhysAddr(params[3], &addr);
   407 	pCtx->LocalToPhysAddr(params[4], &defvalue);
   408 
   409 	value = pStk->pCurRoot.front()->GetUint64(key, static_cast<uint64>(*defvalue));
   410 	*reinterpret_cast<uint64 *>(addr) = value;
   411 
   412 	return 1;
   413 }
   414 
   415 static cell_t smn_KvGetVector(IPluginContext *pCtx, const cell_t *params)
   416 {
   417 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   418 	HandleError herr;
   419 	HandleSecurity sec;
   420 	KeyValueStack *pStk;
   421 
   422 	sec.pOwner = NULL;
   423 	sec.pIdentity = g_pCoreIdent;
   424 
   425 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   426 		!= HandleError_None)
   427 	{
   428 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   429 	}
   430 
   431 	char *key;
   432 	const char *value;
   433 	cell_t *defvector, *outvector;
   434 	char buffer[64];
   435 	pCtx->LocalToStringNULL(params[2], &key);
   436 	pCtx->LocalToPhysAddr(params[3], &outvector);
   437 	pCtx->LocalToPhysAddr(params[4], &defvector);
   438 
   439 	UTIL_Format(buffer, sizeof(buffer), "%f %f %f", sp_ctof(defvector[0]), sp_ctof(defvector[1]), sp_ctof(defvector[2]));
   440 
   441 	value = pStk->pCurRoot.front()->GetString(key, buffer);
   442 
   443 	float out;
   444 	int components = 0;
   445 	while (*value && components < 3)
   446 	{
   447 		while ((*value) && (*value == ' '))
   448 		{
   449 			value++;
   450 		}
   451 
   452 		out = 0.0f;
   453 		bool isnegative;
   454 		if (*value == '-')
   455 		{
   456 			isnegative = true;
   457 			value++;
   458 		}
   459 		else
   460 		{
   461 			isnegative = false;
   462 		}
   463 
   464 		for (; *value && isdigit(*value); ++value)
   465 		{
   466 			out *= 10.0f;
   467 			out += *value - '0';
   468 		}
   469 
   470 		if (*value == '.')
   471 		{
   472 			value++;
   473 			float factor = 0.1f;
   474 			for (; *value && isdigit(*value); ++value)
   475 			{
   476 				out += (*value - '0') * factor;
   477 				factor *= 0.1f;
   478 			}
   479 		}
   480 
   481 		out = (isnegative) ? -out : out;
   482 		outvector[components++] = sp_ftoc(out);
   483 	}
   484 
   485 	return 1;
   486 }
   487 
   488 static cell_t smn_CreateKeyValues(IPluginContext *pCtx, const cell_t *params)
   489 {
   490 	KeyValueStack *pStk;
   491 	char *name, *firstkey, *firstvalue;
   492 	bool is_empty;
   493 
   494 	pCtx->LocalToString(params[1], &name);
   495 	pCtx->LocalToString(params[2], &firstkey);
   496 	pCtx->LocalToString(params[3], &firstvalue);
   497 
   498 	is_empty = (firstkey[0] == '\0');
   499 	pStk = new KeyValueStack;
   500 	pStk->pBase = new KeyValues(name, is_empty ? NULL : firstkey, (is_empty||(firstvalue[0]=='\0')) ? NULL : firstvalue);
   501 	pStk->pCurRoot.push(pStk->pBase);
   502 
   503 	return g_HandleSys.CreateHandle(g_KeyValueType, pStk, pCtx->GetIdentity(), g_pCoreIdent, NULL);
   504 }
   505 
   506 static cell_t smn_KvJumpToKey(IPluginContext *pCtx, const cell_t *params)
   507 {
   508 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   509 	HandleError herr;
   510 	HandleSecurity sec;
   511 	char *name;	
   512 	KeyValueStack *pStk;
   513 
   514 	sec.pOwner = NULL;
   515 	sec.pIdentity = g_pCoreIdent;
   516 
   517 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   518 		!= HandleError_None)
   519 	{
   520 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   521 	}
   522 
   523 	pCtx->LocalToString(params[2], &name);
   524 
   525 	KeyValues *pSubKey = pStk->pCurRoot.front();
   526 	pSubKey = pSubKey->FindKey(name, (params[3]) ? true : false);
   527 	if (!pSubKey)
   528 	{
   529 		return 0;
   530 	}
   531 	pStk->pCurRoot.push(pSubKey);
   532 
   533 	return 1;
   534 }
   535 
   536 static cell_t smn_KvJumpToKeySymbol(IPluginContext *pCtx, const cell_t *params)
   537 {
   538 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   539 	HandleError herr;
   540 	HandleSecurity sec;
   541 	KeyValueStack *pStk;
   542 
   543 	sec.pOwner = NULL;
   544 	sec.pIdentity = g_pCoreIdent;
   545 
   546 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   547 		!= HandleError_None)
   548 	{
   549 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   550 	}
   551 
   552 	KeyValues *pSubKey = pStk->pCurRoot.front();
   553 	pSubKey = pSubKey->FindKey(params[2]);
   554 	if (!pSubKey)
   555 	{
   556 		return 0;
   557 	}
   558 	pStk->pCurRoot.push(pSubKey);
   559 
   560 	return 1;
   561 }
   562 
   563 static cell_t smn_KvGotoFirstSubKey(IPluginContext *pCtx, const cell_t *params)
   564 {
   565 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   566 	HandleError herr;
   567 	HandleSecurity sec;
   568 	KeyValueStack *pStk;
   569 
   570 	sec.pOwner = NULL;
   571 	sec.pIdentity = g_pCoreIdent;
   572 
   573 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   574 		!= HandleError_None)
   575 	{
   576 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   577 	}
   578 
   579 	KeyValues *pSubKey = pStk->pCurRoot.front();
   580 	KeyValues *pFirstSubKey;
   581 	if (params[2])
   582 	{
   583 		pFirstSubKey = pSubKey->GetFirstTrueSubKey();
   584 	} else {
   585 		pFirstSubKey = pSubKey->GetFirstSubKey();
   586 	}
   587 
   588 	if (!pFirstSubKey)
   589 	{
   590 		return 0;
   591 	}
   592 	pStk->pCurRoot.push(pFirstSubKey);
   593 
   594 	return 1;
   595 }
   596 
   597 static cell_t smn_KvGotoNextKey(IPluginContext *pCtx, const cell_t *params)
   598 {
   599 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   600 	HandleError herr;
   601 	HandleSecurity sec;
   602 	KeyValueStack *pStk;
   603 
   604 	sec.pOwner = NULL;
   605 	sec.pIdentity = g_pCoreIdent;
   606 
   607 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   608 		!= HandleError_None)
   609 	{
   610 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   611 	}
   612 
   613 	KeyValues *pSubKey = pStk->pCurRoot.front();
   614 	if (params[2])
   615 	{
   616 		pSubKey = pSubKey->GetNextTrueSubKey();
   617 	} else {
   618 		pSubKey = pSubKey->GetNextKey();
   619 	}
   620 	if (!pSubKey)
   621 	{
   622 		return 0;
   623 	}
   624 	pStk->pCurRoot.pop();
   625 	pStk->pCurRoot.push(pSubKey);
   626 
   627 	return 1;	
   628 }
   629 
   630 static cell_t smn_KvJumpNextSubKey(IPluginContext *pCtx, const cell_t *params)
   631 {
   632 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   633 	HandleError herr;
   634 	HandleSecurity sec;
   635 	KeyValueStack *pStk;
   636 
   637 	sec.pOwner = NULL;
   638 	sec.pIdentity = g_pCoreIdent;
   639 
   640 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   641 		!= HandleError_None)
   642 	{
   643 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   644 	}
   645 
   646 	KeyValues *pSubKey = pStk->pCurRoot.front();
   647 	KeyValues *pNextKey = pSubKey->GetNextKey();
   648 	if (!pNextKey)
   649 	{
   650 		return 0;
   651 	}
   652 	pStk->pCurRoot.push(pNextKey);
   653 
   654 	return 1;	
   655 }
   656 
   657 static cell_t smn_KvGoBack(IPluginContext *pCtx, const cell_t *params)
   658 {
   659 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   660 	HandleError herr;
   661 	HandleSecurity sec;
   662 	KeyValueStack *pStk;
   663 
   664 	sec.pOwner = NULL;
   665 	sec.pIdentity = g_pCoreIdent;
   666 
   667 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   668 		!= HandleError_None)
   669 	{
   670 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   671 	}
   672 
   673 	if (pStk->pCurRoot.size() == 1)
   674 	{
   675 		return 0;
   676 	}
   677 	pStk->pCurRoot.pop();
   678 
   679 	return 1;
   680 }
   681 
   682 static cell_t smn_KvRewind(IPluginContext *pCtx, const cell_t *params)
   683 {
   684 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   685 	HandleError herr;
   686 	HandleSecurity sec;
   687 	KeyValueStack *pStk;
   688 
   689 	sec.pOwner = NULL;
   690 	sec.pIdentity = g_pCoreIdent;
   691 
   692 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   693 		!= HandleError_None)
   694 	{
   695 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   696 	}
   697 
   698 	while (pStk->pCurRoot.size() > 1)
   699 	{
   700 		pStk->pCurRoot.pop();
   701 	}
   702 
   703 	return 1;
   704 }
   705 
   706 static cell_t smn_KvGetSectionName(IPluginContext *pCtx, const cell_t *params)
   707 {
   708 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   709 	HandleError herr;
   710 	HandleSecurity sec;
   711 	KeyValueStack *pStk;
   712 
   713 	sec.pOwner = NULL;
   714 	sec.pIdentity = g_pCoreIdent;
   715 
   716 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   717 		!= HandleError_None)
   718 	{
   719 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   720 	}
   721 
   722 	KeyValues *pSection = pStk->pCurRoot.front();
   723 	const char *name = pSection->GetName();
   724 	if (!name)
   725 	{
   726 		return 0;
   727 	}
   728 	pCtx->StringToLocalUTF8(params[2], params[3], name, NULL);
   729 
   730 	return 1;
   731 }
   732 
   733 static cell_t smn_KvSetSectionName(IPluginContext *pCtx, const cell_t *params)
   734 {
   735 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   736 	HandleError herr;
   737 	HandleSecurity sec;
   738 	char *name;
   739 	KeyValueStack *pStk;
   740 
   741 	sec.pOwner = NULL;
   742 	sec.pIdentity = g_pCoreIdent;
   743 
   744 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   745 		!= HandleError_None)
   746 	{
   747 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   748 	}
   749 
   750 	pCtx->LocalToString(params[2], &name);
   751 
   752 	KeyValues *pSection = pStk->pCurRoot.front();
   753 	pSection->SetName(name);
   754 
   755 	return 1;
   756 }
   757 
   758 static cell_t smn_KvGetDataType(IPluginContext *pCtx, const cell_t *params)
   759 {
   760 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   761 	HandleError herr;
   762 	HandleSecurity sec;
   763 	char *name;
   764 	KeyValueStack *pStk;
   765 
   766 	sec.pOwner = NULL;
   767 	sec.pIdentity = g_pCoreIdent;
   768 
   769 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   770 		!= HandleError_None)
   771 	{
   772 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   773 	}
   774 
   775 	pCtx->LocalToString(params[2], &name);
   776 
   777 	return pStk->pCurRoot.front()->GetDataType(name);
   778 }
   779 
   780 static cell_t smn_KeyValuesToFile(IPluginContext *pCtx, const cell_t *params)
   781 {
   782 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   783 	HandleError herr;
   784 	HandleSecurity sec;
   785 	char *path;
   786 	KeyValueStack *pStk;
   787 
   788 	sec.pOwner = NULL;
   789 	sec.pIdentity = g_pCoreIdent;
   790 
   791 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   792 		!= HandleError_None)
   793 	{
   794 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   795 	}
   796 
   797 	pCtx->LocalToString(params[2], &path);
   798 
   799 	char realpath[PLATFORM_MAX_PATH];
   800 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
   801 
   802 	return pStk->pCurRoot.front()->SaveToFile(basefilesystem, realpath);
   803 }
   804 
   805 static cell_t smn_FileToKeyValues(IPluginContext *pCtx, const cell_t *params)
   806 {
   807 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   808 	HandleError herr;
   809 	HandleSecurity sec;
   810 	char *path;
   811 	KeyValueStack *pStk;
   812 
   813 	sec.pOwner = NULL;
   814 	sec.pIdentity = g_pCoreIdent;
   815 
   816 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   817 		!= HandleError_None)
   818 	{
   819 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   820 	}
   821 
   822 	pCtx->LocalToString(params[2], &path);
   823 
   824 	char realpath[PLATFORM_MAX_PATH];
   825 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
   826 
   827 	return pStk->pCurRoot.front()->LoadFromFile(basefilesystem, realpath);
   828 }
   829 
   830 static cell_t smn_KvSetEscapeSequences(IPluginContext *pCtx, const cell_t *params)
   831 {
   832 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   833 	HandleError herr;
   834 	HandleSecurity sec;
   835 	KeyValueStack *pStk;
   836 
   837 	sec.pOwner = NULL;
   838 	sec.pIdentity = g_pCoreIdent;
   839 
   840 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   841 		!= HandleError_None)
   842 	{
   843 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   844 	}
   845 
   846 	pStk->pCurRoot.front()->UsesEscapeSequences(params[2] ? true : false);
   847 
   848 	return 1;
   849 }
   850 
   851 static cell_t smn_KvNodesInStack(IPluginContext *pCtx, const cell_t *params)
   852 {
   853 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   854 	HandleError herr;
   855 	HandleSecurity sec;
   856 	KeyValueStack *pStk;
   857 
   858 	sec.pOwner = NULL;
   859 	sec.pIdentity = g_pCoreIdent;
   860 
   861 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   862 		!= HandleError_None)
   863 	{
   864 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   865 	}
   866 
   867 	return pStk->pCurRoot.size() - 1;
   868 }
   869 
   870 static cell_t smn_KvDeleteThis(IPluginContext *pContext, const cell_t *params)
   871 {
   872 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   873 	HandleError herr;
   874 	HandleSecurity sec;
   875 	KeyValueStack *pStk;
   876 
   877 	sec.pOwner = NULL;
   878 	sec.pIdentity = g_pCoreIdent;
   879 
   880 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   881 		!= HandleError_None)
   882 	{
   883 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   884 	}
   885 
   886 	if (pStk->pCurRoot.size() < 2)
   887 	{
   888 		return 0;
   889 	}
   890 
   891 	KeyValues *pValues = pStk->pCurRoot.front();
   892 	pStk->pCurRoot.pop();
   893 	KeyValues *pRoot = pStk->pCurRoot.front();
   894 
   895 	/* We have to manually verify this since Valve sucks
   896 	 * :TODO: make our own KeyValues.h file and make
   897 	 * the sub stuff private so we can do this ourselves!
   898  	 */
   899 	KeyValues *sub = pRoot->GetFirstSubKey();
   900 	while (sub)
   901 	{
   902 		if (sub == pValues)
   903 		{
   904 			KeyValues *pNext = pValues->GetNextKey();
   905 			pRoot->RemoveSubKey(pValues);
   906 			pValues->deleteThis();
   907 			if (pNext)
   908 			{
   909 				pStk->pCurRoot.push(pNext);
   910 				return 1;
   911 			} else {
   912 				return -1;
   913 			}
   914 		}
   915 		sub = sub->GetNextKey();
   916 	}
   917 
   918 	/* Push this back on :( */
   919 	pStk->pCurRoot.push(pValues);
   920 
   921 	return 0;
   922 }
   923 
   924 static cell_t smn_KvDeleteKey(IPluginContext *pContext, const cell_t *params)
   925 {
   926 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   927 	HandleError herr;
   928 	HandleSecurity sec;
   929 	KeyValueStack *pStk;
   930 
   931 	sec.pOwner = NULL;
   932 	sec.pIdentity = g_pCoreIdent;
   933 
   934 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   935 		!= HandleError_None)
   936 	{
   937 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   938 	}
   939 
   940 	if (pStk->pCurRoot.size() < 2)
   941 	{
   942 		return 0;
   943 	}
   944 
   945 	char *keyName;
   946 	pContext->LocalToString(params[2], &keyName);
   947 
   948 	KeyValues *pRoot = pStk->pCurRoot.front();
   949 	KeyValues *pValues = pRoot->FindKey(keyName);
   950 	if (!pValues)
   951 	{
   952 		return 0;
   953 	}
   954 
   955 	pRoot->RemoveSubKey(pValues);
   956 	pValues->deleteThis();
   957 
   958 	return 1;
   959 }
   960 
   961 static cell_t smn_KvSavePosition(IPluginContext *pContext, const cell_t *params)
   962 {
   963 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   964 	HandleError herr;
   965 	HandleSecurity sec;
   966 	KeyValueStack *pStk;
   967 
   968 	sec.pOwner = NULL;
   969 	sec.pIdentity = g_pCoreIdent;
   970 
   971 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   972 		!= HandleError_None)
   973 	{
   974 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   975 	}
   976 
   977 	if (pStk->pCurRoot.size() < 2)
   978 	{
   979 		return 0;
   980 	}
   981 
   982 	KeyValues *pValues = pStk->pCurRoot.front();
   983 	pStk->pCurRoot.push(pValues);
   984 
   985 	return 1;
   986 }
   987 
   988 static cell_t smn_CopySubkeys(IPluginContext *pContext, const cell_t *params)
   989 {
   990 	Handle_t hndl_copied = static_cast<Handle_t>(params[1]);
   991 	Handle_t hndl_parent = static_cast<Handle_t>(params[2]);
   992 	HandleError herr;
   993 	HandleSecurity sec;
   994 	KeyValueStack *pStk_copied, *pStk_parent;
   995 
   996 	sec.pOwner = NULL;
   997 	sec.pIdentity = g_pCoreIdent;
   998 
   999 	if ((herr=g_HandleSys.ReadHandle(hndl_copied, g_KeyValueType, &sec, (void **)&pStk_copied))
  1000 		!= HandleError_None)
  1001 	{
  1002 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl_copied, herr);
  1003 	}
  1004 	if ((herr=g_HandleSys.ReadHandle(hndl_parent, g_KeyValueType, &sec, (void **)&pStk_parent))
  1005 		!= HandleError_None)
  1006 	{
  1007 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl_parent, herr);
  1008 	}
  1009 
  1010 	pStk_copied->pCurRoot.front()->CopySubkeys(pStk_parent->pCurRoot.front());
  1011 
  1012 	return 1;
  1013 }
  1014 
  1015 static cell_t smn_GetNameSymbol(IPluginContext *pContext, const cell_t *params)
  1016 {
  1017 	Handle_t hndl = static_cast<Handle_t>(params[1]);
  1018 	HandleError herr;
  1019 	HandleSecurity sec;
  1020 	KeyValueStack *pStk;
  1021 	cell_t *val;
  1022 	char *key;
  1023 
  1024 	sec.pOwner = NULL;
  1025 	sec.pIdentity = g_pCoreIdent;
  1026 
  1027 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
  1028 		!= HandleError_None)
  1029 	{
  1030 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
  1031 	}
  1032 
  1033 	if (pStk->pCurRoot.size() < 2)
  1034 	{
  1035 		return 0;
  1036 	}
  1037 
  1038 	pContext->LocalToString(params[2], &key);
  1039 
  1040 	KeyValues *pKv = pStk->pCurRoot.front()->FindKey(key);
  1041 	if (!pKv)
  1042 	{
  1043 		return 0;
  1044 	}
  1045 	pContext->LocalToPhysAddr(params[3], &val);
  1046 	*val = pKv->GetNameSymbol();
  1047 
  1048 	return 1;
  1049 }
  1050 
  1051 static cell_t smn_FindKeyById(IPluginContext *pContext, const cell_t *params)
  1052 {
  1053 	Handle_t hndl = static_cast<Handle_t>(params[1]);
  1054 	HandleError herr;
  1055 	HandleSecurity sec;
  1056 	KeyValueStack *pStk;
  1057 
  1058 	sec.pOwner = NULL;
  1059 	sec.pIdentity = g_pCoreIdent;
  1060 
  1061 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
  1062 		!= HandleError_None)
  1063 	{
  1064 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
  1065 	}
  1066 
  1067 	KeyValues *pKv = pStk->pCurRoot.front()->FindKey(params[2]);
  1068 	if (!pKv)
  1069 	{
  1070 		return 0;
  1071 	}
  1072 
  1073 	pContext->StringToLocalUTF8(params[3], params[4], pKv->GetName(), NULL);
  1074 
  1075 	return 1;
  1076 }
  1077 
  1078 static cell_t smn_KvGetSectionSymbol(IPluginContext *pCtx, const cell_t *params)
  1079 {
  1080 	Handle_t hndl = static_cast<Handle_t>(params[1]);
  1081 	HandleError herr;
  1082 	HandleSecurity sec;
  1083 	KeyValueStack *pStk;
  1084 	cell_t *val;
  1085 
  1086 	sec.pOwner = NULL;
  1087 	sec.pIdentity = g_pCoreIdent;
  1088 
  1089 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
  1090 		!= HandleError_None)
  1091 	{
  1092 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
  1093 	}
  1094 
  1095 	KeyValues *pSection = pStk->pCurRoot.front();
  1096 
  1097 	pCtx->LocalToPhysAddr(params[2], &val);
  1098 	*val = pSection->GetNameSymbol();
  1099 
  1100 	if (!*val)
  1101 	{
  1102 		return 0;
  1103 	}
  1104 
  1105 	return 1;
  1106 }
  1107 
  1108 static KeyValueNatives s_KeyValueNatives;
  1109 
  1110 REGISTER_NATIVES(keyvaluenatives)
  1111 {
  1112 	{"KvSetString",				smn_KvSetString},
  1113 	{"KvSetNum",				smn_KvSetNum},
  1114 	{"KvSetUInt64",				smn_KvSetUInt64},
  1115 	{"KvSetFloat",				smn_KvSetFloat},
  1116 	{"KvSetColor",				smn_KvSetColor},
  1117 	{"KvGetString",				smn_KvGetString},
  1118 	{"KvGetNum",				smn_KvGetNum},
  1119 	{"KvGetFloat",				smn_KvGetFloat},
  1120 	{"KvGetColor",				smn_KvGetColor},
  1121 	{"KvGetUInt64",				smn_KvGetUInt64},
  1122 	{"CreateKeyValues",			smn_CreateKeyValues},
  1123 	{"KvJumpToKey",				smn_KvJumpToKey},
  1124 	{"KvJumpToKeySymbol",		smn_KvJumpToKeySymbol},
  1125 	{"KvGotoNextKey",			smn_KvGotoNextKey},
  1126 	{"KvJumpFirstSubKey",		smn_KvGotoFirstSubKey},		/* BACKWARDS COMPAT SHIM */
  1127 	{"KvGotoFirstSubKey",		smn_KvGotoFirstSubKey},
  1128 	{"KvJumpNextSubKey",		smn_KvJumpNextSubKey},		/* BACKWARDS COMPAT SHIM */
  1129 	{"KvGoBack",				smn_KvGoBack},
  1130 	{"KvRewind",				smn_KvRewind},
  1131 	{"KvGetSectionName",		smn_KvGetSectionName},
  1132 	{"KvSetSectionName",		smn_KvSetSectionName},
  1133 	{"KvGetDataType",			smn_KvGetDataType},
  1134 	{"KeyValuesToFile",			smn_KeyValuesToFile},
  1135 	{"FileToKeyValues",			smn_FileToKeyValues},
  1136 	{"KvSetEscapeSequences",	smn_KvSetEscapeSequences},
  1137 	{"KvDeleteThis",			smn_KvDeleteThis},
  1138 	{"KvDeleteKey",				smn_KvDeleteKey},
  1139 	{"KvNodesInStack",			smn_KvNodesInStack},
  1140 	{"KvSavePosition",			smn_KvSavePosition},
  1141 	{"KvCopySubkeys",			smn_CopySubkeys},
  1142 	{"KvFindKeyById",			smn_FindKeyById},
  1143 	{"KvGetNameSymbol",			smn_GetNameSymbol},
  1144 	{"KvGetSectionSymbol",		smn_KvGetSectionSymbol},
  1145 	{"KvGetVector",				smn_KvGetVector},
  1146 	{"KvSetVector",				smn_KvSetVector},
  1147 	{NULL,						NULL}
  1148 };