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