core/smn_keyvalues.cpp
author David Anderson <dvander@alliedmods.net>
Wed Sep 26 14:38:40 2007 +0000 (2007-09-26)
changeset 1488 5562086c65c8
parent 1401 e3b761515c0a
child 1707 05af94444cc8
child 1715 f9ecab642e25
permissions -rw-r--r--
initial import of UNTESTED, UNFINISHED topmenus extension
     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_KvGetString(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 	const char *value;
   238 	char *key, *defvalue;
   239 	pCtx->LocalToStringNULL(params[2], &key);
   240 	pCtx->LocalToString(params[5], &defvalue);
   241 
   242 	value = pStk->pCurRoot.front()->GetString(key, defvalue);
   243 	pCtx->StringToLocalUTF8(params[3], params[4], value, NULL);
   244 
   245 	return 1;
   246 }
   247 
   248 static cell_t smn_KvGetNum(IPluginContext *pCtx, const cell_t *params)
   249 {
   250 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   251 	HandleError herr;
   252 	HandleSecurity sec;
   253 	KeyValueStack *pStk;
   254 
   255 	sec.pOwner = NULL;
   256 	sec.pIdentity = g_pCoreIdent;
   257 
   258 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   259 		!= HandleError_None)
   260 	{
   261 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   262 	}
   263 
   264 	int value;
   265 	char *key;
   266 	pCtx->LocalToStringNULL(params[2], &key);
   267 
   268 	value = pStk->pCurRoot.front()->GetInt(key, params[3]);
   269 
   270 	return value;
   271 }
   272 
   273 static cell_t smn_KvGetFloat(IPluginContext *pCtx, const cell_t *params)
   274 {
   275 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   276 	HandleError herr;
   277 	HandleSecurity sec;
   278 	KeyValueStack *pStk;
   279 
   280 	sec.pOwner = NULL;
   281 	sec.pIdentity = g_pCoreIdent;
   282 
   283 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   284 		!= HandleError_None)
   285 	{
   286 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   287 	}
   288 
   289 	float value;
   290 	char *key;
   291 	pCtx->LocalToStringNULL(params[2], &key);
   292 
   293 	value = pStk->pCurRoot.front()->GetFloat(key, sp_ctof(params[3]));
   294 
   295 	return sp_ftoc(value);
   296 }
   297 
   298 static cell_t smn_KvGetColor(IPluginContext *pCtx, const cell_t *params)
   299 {
   300 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   301 	HandleError herr;
   302 	HandleSecurity sec;
   303 	KeyValueStack *pStk;
   304 
   305 	sec.pOwner = NULL;
   306 	sec.pIdentity = g_pCoreIdent;
   307 
   308 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   309 		!= HandleError_None)
   310 	{
   311 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   312 	}
   313 
   314 	Color color;
   315 	char *key;
   316 	cell_t *r, *g, *b, *a;
   317 	pCtx->LocalToStringNULL(params[2], &key);
   318 	pCtx->LocalToPhysAddr(params[3], &r);
   319 	pCtx->LocalToPhysAddr(params[4], &g);
   320 	pCtx->LocalToPhysAddr(params[5], &b);
   321 	pCtx->LocalToPhysAddr(params[6], &a);
   322 
   323 	color = pStk->pCurRoot.front()->GetColor(key);
   324 	*r = color.r();
   325 	*g = color.g();
   326 	*b = color.b();
   327 	*a = color.a();
   328 
   329 	return 1;
   330 }
   331 
   332 static cell_t smn_KvGetUInt64(IPluginContext *pCtx, const cell_t *params)
   333 {
   334 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   335 	HandleError herr;
   336 	HandleSecurity sec;
   337 	KeyValueStack *pStk;
   338 
   339 	sec.pOwner = NULL;
   340 	sec.pIdentity = g_pCoreIdent;
   341 
   342 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   343 		!= HandleError_None)
   344 	{
   345 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   346 	}
   347 
   348 	char *key;
   349 	cell_t *addr, *defvalue;
   350 	uint64 value;
   351 	pCtx->LocalToStringNULL(params[2], &key);
   352 	pCtx->LocalToPhysAddr(params[3], &addr);
   353 	pCtx->LocalToPhysAddr(params[4], &defvalue);
   354 
   355 	value = pStk->pCurRoot.front()->GetUint64(key, static_cast<uint64>(*defvalue));
   356 	*reinterpret_cast<uint64 *>(addr) = value;
   357 
   358 	return 1;
   359 }
   360 
   361 static cell_t smn_CreateKeyValues(IPluginContext *pCtx, const cell_t *params)
   362 {
   363 	KeyValueStack *pStk;
   364 	char *name, *firstkey, *firstvalue;
   365 	bool is_empty;
   366 
   367 	pCtx->LocalToString(params[1], &name);
   368 	pCtx->LocalToString(params[2], &firstkey);
   369 	pCtx->LocalToString(params[3], &firstvalue);
   370 
   371 	is_empty = (firstkey[0] == '\0');
   372 	pStk = new KeyValueStack;
   373 	pStk->pBase = new KeyValues(name, is_empty ? NULL : firstkey, (is_empty||(firstvalue[0]=='\0')) ? NULL : firstvalue);
   374 	pStk->pCurRoot.push(pStk->pBase);
   375 
   376 	return g_HandleSys.CreateHandle(g_KeyValueType, pStk, pCtx->GetIdentity(), g_pCoreIdent, NULL);
   377 }
   378 
   379 static cell_t smn_KvJumpToKey(IPluginContext *pCtx, const cell_t *params)
   380 {
   381 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   382 	HandleError herr;
   383 	HandleSecurity sec;
   384 	char *name;	
   385 	KeyValueStack *pStk;
   386 
   387 	sec.pOwner = NULL;
   388 	sec.pIdentity = g_pCoreIdent;
   389 
   390 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   391 		!= HandleError_None)
   392 	{
   393 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   394 	}
   395 
   396 	pCtx->LocalToString(params[2], &name);
   397 
   398 	KeyValues *pSubKey = pStk->pCurRoot.front();
   399 	pSubKey = pSubKey->FindKey(name, (params[3]) ? true : false);
   400 	if (!pSubKey)
   401 	{
   402 		return 0;
   403 	}
   404 	pStk->pCurRoot.push(pSubKey);
   405 
   406 	return 1;
   407 }
   408 
   409 static cell_t smn_KvGotoFirstSubKey(IPluginContext *pCtx, const cell_t *params)
   410 {
   411 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   412 	HandleError herr;
   413 	HandleSecurity sec;
   414 	KeyValueStack *pStk;
   415 
   416 	sec.pOwner = NULL;
   417 	sec.pIdentity = g_pCoreIdent;
   418 
   419 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   420 		!= HandleError_None)
   421 	{
   422 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   423 	}
   424 
   425 	KeyValues *pSubKey = pStk->pCurRoot.front();
   426 	KeyValues *pFirstSubKey;
   427 	if (params[2])
   428 	{
   429 		pFirstSubKey = pSubKey->GetFirstTrueSubKey();
   430 	} else {
   431 		pFirstSubKey = pSubKey->GetFirstSubKey();
   432 	}
   433 
   434 	if (!pFirstSubKey)
   435 	{
   436 		return 0;
   437 	}
   438 	pStk->pCurRoot.push(pFirstSubKey);
   439 
   440 	return 1;
   441 }
   442 
   443 static cell_t smn_KvGotoNextKey(IPluginContext *pCtx, const cell_t *params)
   444 {
   445 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   446 	HandleError herr;
   447 	HandleSecurity sec;
   448 	KeyValueStack *pStk;
   449 
   450 	sec.pOwner = NULL;
   451 	sec.pIdentity = g_pCoreIdent;
   452 
   453 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   454 		!= HandleError_None)
   455 	{
   456 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   457 	}
   458 
   459 	KeyValues *pSubKey = pStk->pCurRoot.front();
   460 	if (params[2])
   461 	{
   462 		pSubKey = pSubKey->GetNextTrueSubKey();
   463 	} else {
   464 		pSubKey = pSubKey->GetNextKey();
   465 	}
   466 	if (!pSubKey)
   467 	{
   468 		return 0;
   469 	}
   470 	pStk->pCurRoot.pop();
   471 	pStk->pCurRoot.push(pSubKey);
   472 
   473 	return 1;	
   474 }
   475 
   476 static cell_t smn_KvJumpNextSubKey(IPluginContext *pCtx, const cell_t *params)
   477 {
   478 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   479 	HandleError herr;
   480 	HandleSecurity sec;
   481 	KeyValueStack *pStk;
   482 
   483 	sec.pOwner = NULL;
   484 	sec.pIdentity = g_pCoreIdent;
   485 
   486 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   487 		!= HandleError_None)
   488 	{
   489 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   490 	}
   491 
   492 	KeyValues *pSubKey = pStk->pCurRoot.front();
   493 	KeyValues *pNextKey = pSubKey->GetNextKey();
   494 	if (!pNextKey)
   495 	{
   496 		return 0;
   497 	}
   498 	pStk->pCurRoot.push(pNextKey);
   499 
   500 	return 1;	
   501 }
   502 
   503 static cell_t smn_KvGoBack(IPluginContext *pCtx, const cell_t *params)
   504 {
   505 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   506 	HandleError herr;
   507 	HandleSecurity sec;
   508 	KeyValueStack *pStk;
   509 
   510 	sec.pOwner = NULL;
   511 	sec.pIdentity = g_pCoreIdent;
   512 
   513 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   514 		!= HandleError_None)
   515 	{
   516 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   517 	}
   518 
   519 	if (pStk->pCurRoot.size() == 1)
   520 	{
   521 		return 0;
   522 	}
   523 	pStk->pCurRoot.pop();
   524 
   525 	return 1;
   526 }
   527 
   528 static cell_t smn_KvRewind(IPluginContext *pCtx, const cell_t *params)
   529 {
   530 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   531 	HandleError herr;
   532 	HandleSecurity sec;
   533 	KeyValueStack *pStk;
   534 
   535 	sec.pOwner = NULL;
   536 	sec.pIdentity = g_pCoreIdent;
   537 
   538 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   539 		!= HandleError_None)
   540 	{
   541 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   542 	}
   543 
   544 	while (pStk->pCurRoot.size() > 1)
   545 	{
   546 		pStk->pCurRoot.pop();
   547 	}
   548 
   549 	return 1;
   550 }
   551 
   552 static cell_t smn_KvGetSectionName(IPluginContext *pCtx, const cell_t *params)
   553 {
   554 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   555 	HandleError herr;
   556 	HandleSecurity sec;
   557 	KeyValueStack *pStk;
   558 
   559 	sec.pOwner = NULL;
   560 	sec.pIdentity = g_pCoreIdent;
   561 
   562 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   563 		!= HandleError_None)
   564 	{
   565 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   566 	}
   567 
   568 	KeyValues *pSection = pStk->pCurRoot.front();
   569 	const char *name = pSection->GetName();
   570 	if (!name)
   571 	{
   572 		return 0;
   573 	}
   574 	pCtx->StringToLocalUTF8(params[2], params[3], name, NULL);
   575 
   576 	return 1;
   577 }
   578 
   579 static cell_t smn_KvSetSectionName(IPluginContext *pCtx, const cell_t *params)
   580 {
   581 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   582 	HandleError herr;
   583 	HandleSecurity sec;
   584 	char *name;
   585 	KeyValueStack *pStk;
   586 
   587 	sec.pOwner = NULL;
   588 	sec.pIdentity = g_pCoreIdent;
   589 
   590 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   591 		!= HandleError_None)
   592 	{
   593 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   594 	}
   595 
   596 	pCtx->LocalToString(params[2], &name);
   597 
   598 	KeyValues *pSection = pStk->pCurRoot.front();
   599 	pSection->SetName(name);
   600 
   601 	return 1;
   602 }
   603 
   604 static cell_t smn_KvGetDataType(IPluginContext *pCtx, const cell_t *params)
   605 {
   606 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   607 	HandleError herr;
   608 	HandleSecurity sec;
   609 	char *name;
   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 	pCtx->LocalToString(params[2], &name);
   622 
   623 	return pStk->pCurRoot.front()->GetDataType(name);
   624 }
   625 
   626 static cell_t smn_KeyValuesToFile(IPluginContext *pCtx, const cell_t *params)
   627 {
   628 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   629 	HandleError herr;
   630 	HandleSecurity sec;
   631 	char *path;
   632 	KeyValueStack *pStk;
   633 
   634 	sec.pOwner = NULL;
   635 	sec.pIdentity = g_pCoreIdent;
   636 
   637 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   638 		!= HandleError_None)
   639 	{
   640 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   641 	}
   642 
   643 	pCtx->LocalToString(params[2], &path);
   644 
   645 	char realpath[PLATFORM_MAX_PATH];
   646 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
   647 
   648 	return pStk->pCurRoot.front()->SaveToFile(basefilesystem, realpath);
   649 }
   650 
   651 static cell_t smn_FileToKeyValues(IPluginContext *pCtx, const cell_t *params)
   652 {
   653 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   654 	HandleError herr;
   655 	HandleSecurity sec;
   656 	char *path;
   657 	KeyValueStack *pStk;
   658 
   659 	sec.pOwner = NULL;
   660 	sec.pIdentity = g_pCoreIdent;
   661 
   662 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   663 		!= HandleError_None)
   664 	{
   665 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   666 	}
   667 
   668 	pCtx->LocalToString(params[2], &path);
   669 
   670 	char realpath[PLATFORM_MAX_PATH];
   671 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
   672 
   673 	return pStk->pCurRoot.front()->LoadFromFile(basefilesystem, realpath);
   674 }
   675 
   676 static cell_t smn_KvSetEscapeSequences(IPluginContext *pCtx, const cell_t *params)
   677 {
   678 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   679 	HandleError herr;
   680 	HandleSecurity sec;
   681 	KeyValueStack *pStk;
   682 
   683 	sec.pOwner = NULL;
   684 	sec.pIdentity = g_pCoreIdent;
   685 
   686 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   687 		!= HandleError_None)
   688 	{
   689 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   690 	}
   691 
   692 	pStk->pCurRoot.front()->UsesEscapeSequences(params[2] ? true : false);
   693 
   694 	return 1;
   695 }
   696 
   697 static cell_t smn_KvNodesInStack(IPluginContext *pCtx, const cell_t *params)
   698 {
   699 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   700 	HandleError herr;
   701 	HandleSecurity sec;
   702 	KeyValueStack *pStk;
   703 
   704 	sec.pOwner = NULL;
   705 	sec.pIdentity = g_pCoreIdent;
   706 
   707 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   708 		!= HandleError_None)
   709 	{
   710 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   711 	}
   712 
   713 	return pStk->pCurRoot.size() - 1;
   714 }
   715 
   716 static cell_t smn_KvDeleteThis(IPluginContext *pContext, const cell_t *params)
   717 {
   718 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   719 	HandleError herr;
   720 	HandleSecurity sec;
   721 	KeyValueStack *pStk;
   722 
   723 	sec.pOwner = NULL;
   724 	sec.pIdentity = g_pCoreIdent;
   725 
   726 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   727 		!= HandleError_None)
   728 	{
   729 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   730 	}
   731 
   732 	if (pStk->pCurRoot.size() < 2)
   733 	{
   734 		return 0;
   735 	}
   736 
   737 	KeyValues *pValues = pStk->pCurRoot.front();
   738 	pStk->pCurRoot.pop();
   739 	KeyValues *pRoot = pStk->pCurRoot.front();
   740 
   741 	/* We have to manually verify this since Valve sucks
   742 	 * :TODO: make our own KeyValues.h file and make
   743 	 * the sub stuff private so we can do this ourselves!
   744  	 */
   745 	KeyValues *sub = pRoot->GetFirstSubKey();
   746 	while (sub)
   747 	{
   748 		if (sub == pValues)
   749 		{
   750 			KeyValues *pNext = pValues->GetNextKey();
   751 			pRoot->RemoveSubKey(pValues);
   752 			pValues->deleteThis();
   753 			if (pNext)
   754 			{
   755 				pStk->pCurRoot.push(pNext);
   756 				return 1;
   757 			} else {
   758 				return -1;
   759 			}
   760 		}
   761 		sub = sub->GetNextKey();
   762 	}
   763 
   764 	/* Push this back on :( */
   765 	pStk->pCurRoot.push(pValues);
   766 
   767 	return 0;
   768 }
   769 
   770 static cell_t smn_KvDeleteKey(IPluginContext *pContext, const cell_t *params)
   771 {
   772 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   773 	HandleError herr;
   774 	HandleSecurity sec;
   775 	KeyValueStack *pStk;
   776 
   777 	sec.pOwner = NULL;
   778 	sec.pIdentity = g_pCoreIdent;
   779 
   780 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   781 		!= HandleError_None)
   782 	{
   783 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   784 	}
   785 
   786 	if (pStk->pCurRoot.size() < 2)
   787 	{
   788 		return 0;
   789 	}
   790 
   791 	char *keyName;
   792 	pContext->LocalToString(params[2], &keyName);
   793 
   794 	KeyValues *pRoot = pStk->pCurRoot.front();
   795 	KeyValues *pValues = pRoot->FindKey(keyName);
   796 	if (!pValues)
   797 	{
   798 		return 0;
   799 	}
   800 
   801 	pRoot->RemoveSubKey(pValues);
   802 	pValues->deleteThis();
   803 
   804 	return 1;
   805 }
   806 
   807 static cell_t smn_KvSavePosition(IPluginContext *pContext, const cell_t *params)
   808 {
   809 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   810 	HandleError herr;
   811 	HandleSecurity sec;
   812 	KeyValueStack *pStk;
   813 
   814 	sec.pOwner = NULL;
   815 	sec.pIdentity = g_pCoreIdent;
   816 
   817 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   818 		!= HandleError_None)
   819 	{
   820 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   821 	}
   822 
   823 	if (pStk->pCurRoot.size() < 2)
   824 	{
   825 		return 0;
   826 	}
   827 
   828 	KeyValues *pValues = pStk->pCurRoot.front();
   829 	pStk->pCurRoot.push(pValues);
   830 
   831 	return 1;
   832 }
   833 
   834 static cell_t smn_CopySubkeys(IPluginContext *pContext, const cell_t *params)
   835 {
   836 	Handle_t hndl_copied = static_cast<Handle_t>(params[1]);
   837 	Handle_t hndl_parent = static_cast<Handle_t>(params[2]);
   838 	HandleError herr;
   839 	HandleSecurity sec;
   840 	KeyValueStack *pStk_copied, *pStk_parent;
   841 
   842 	sec.pOwner = NULL;
   843 	sec.pIdentity = g_pCoreIdent;
   844 
   845 	if ((herr=g_HandleSys.ReadHandle(hndl_copied, g_KeyValueType, &sec, (void **)&pStk_copied))
   846 		!= HandleError_None)
   847 	{
   848 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl_copied, herr);
   849 	}
   850 	if ((herr=g_HandleSys.ReadHandle(hndl_parent, g_KeyValueType, &sec, (void **)&pStk_parent))
   851 		!= HandleError_None)
   852 	{
   853 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl_parent, herr);
   854 	}
   855 
   856 	pStk_copied->pCurRoot.front()->CopySubkeys(pStk_parent->pCurRoot.front());
   857 
   858 	return 1;
   859 }
   860 
   861 static cell_t smn_GetNameSymbol(IPluginContext *pContext, const cell_t *params)
   862 {
   863 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   864 	HandleError herr;
   865 	HandleSecurity sec;
   866 	KeyValueStack *pStk;
   867 	cell_t *val;
   868 	char *key;
   869 
   870 	sec.pOwner = NULL;
   871 	sec.pIdentity = g_pCoreIdent;
   872 
   873 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   874 		!= HandleError_None)
   875 	{
   876 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   877 	}
   878 
   879 	if (pStk->pCurRoot.size() < 2)
   880 	{
   881 		return 0;
   882 	}
   883 
   884 	pContext->LocalToString(params[2], &key);
   885 
   886 	KeyValues *pKv = pStk->pCurRoot.front()->FindKey(key);
   887 	if (!pKv)
   888 	{
   889 		return 0;
   890 	}
   891 	pContext->LocalToPhysAddr(params[3], &val);
   892 	*val = pKv->GetNameSymbol();
   893 
   894 	return 1;
   895 }
   896 
   897 static cell_t smn_FindKeyById(IPluginContext *pContext, const cell_t *params)
   898 {
   899 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   900 	HandleError herr;
   901 	HandleSecurity sec;
   902 	KeyValueStack *pStk;
   903 
   904 	sec.pOwner = NULL;
   905 	sec.pIdentity = g_pCoreIdent;
   906 
   907 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   908 		!= HandleError_None)
   909 	{
   910 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   911 	}
   912 
   913 	KeyValues *pKv = pStk->pCurRoot.front()->FindKey(params[2]);
   914 	if (!pKv)
   915 	{
   916 		return 0;
   917 	}
   918 
   919 	pContext->StringToLocalUTF8(params[3], params[4], pKv->GetName(), NULL);
   920 
   921 	return 1;
   922 }
   923 
   924 static KeyValueNatives s_KeyValueNatives;
   925 
   926 REGISTER_NATIVES(keyvaluenatives)
   927 {
   928 	{"KvSetString",				smn_KvSetString},
   929 	{"KvSetNum",				smn_KvSetNum},
   930 	{"KvSetUInt64",				smn_KvSetUInt64},
   931 	{"KvSetFloat",				smn_KvSetFloat},
   932 	{"KvSetColor",				smn_KvSetColor},
   933 	{"KvGetString",				smn_KvGetString},
   934 	{"KvGetNum",				smn_KvGetNum},
   935 	{"KvGetFloat",				smn_KvGetFloat},
   936 	{"KvGetColor",				smn_KvGetColor},
   937 	{"KvGetUInt64",				smn_KvGetUInt64},
   938 	{"CreateKeyValues",			smn_CreateKeyValues},
   939 	{"KvJumpToKey",				smn_KvJumpToKey},
   940 	{"KvGotoNextKey",			smn_KvGotoNextKey},
   941 	{"KvJumpFirstSubKey",		smn_KvGotoFirstSubKey},		/* BACKWARDS COMPAT SHIM */
   942 	{"KvGotoFirstSubKey",		smn_KvGotoFirstSubKey},
   943 	{"KvJumpNextSubKey",		smn_KvJumpNextSubKey},		/* BACKWARDS COMPAT SHIM */
   944 	{"KvGoBack",				smn_KvGoBack},
   945 	{"KvRewind",				smn_KvRewind},
   946 	{"KvGetSectionName",		smn_KvGetSectionName},
   947 	{"KvSetSectionName",		smn_KvSetSectionName},
   948 	{"KvGetDataType",			smn_KvGetDataType},
   949 	{"KeyValuesToFile",			smn_KeyValuesToFile},
   950 	{"FileToKeyValues",			smn_FileToKeyValues},
   951 	{"KvSetEscapeSequences",	smn_KvSetEscapeSequences},
   952 	{"KvDeleteThis",			smn_KvDeleteThis},
   953 	{"KvDeleteKey",				smn_KvDeleteKey},
   954 	{"KvNodesInStack",			smn_KvNodesInStack},
   955 	{"KvSavePosition",			smn_KvSavePosition},
   956 	{"KvCopySubkeys",			smn_CopySubkeys},
   957 	{"KvFindKeyById",			smn_FindKeyById},
   958 	{"KvGetNameSymbol",			smn_GetNameSymbol},
   959 	{NULL,						NULL}
   960 };