3 * ===============================================================
4 * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
5 * ===============================================================
7 * This file is not open source and may not be copied without explicit
8 * written permission of AlliedModders LLC. This file may not be redistributed
9 * in whole or significant part.
10 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
15 #include "sourcemod.h"
16 #include "sourcemm_api.h"
17 #include "sm_stringutil.h"
18 #include "HandleSys.h"
19 #include <KeyValues.h>
21 HandleType_t g_KeyValueType;
26 CStack<KeyValues *> pCurRoot;
29 class KeyValueNatives :
31 public IHandleTypeDispatch
34 void OnSourceModAllInitialized()
36 g_KeyValueType = g_HandleSys.CreateType("KeyValues", this, 0, NULL, NULL, g_pCoreIdent, NULL);
38 void OnSourceModShutdown()
40 g_HandleSys.RemoveType(g_KeyValueType, g_pCoreIdent);
43 void OnHandleDestroy(HandleType_t type, void *object)
45 KeyValueStack *pStk = reinterpret_cast<KeyValueStack *>(object);
46 pStk->pBase->deleteThis();
51 KeyValues *SourceModBase::ReadKeyValuesHandle(Handle_t hndl, HandleError *err, bool root)
58 sec.pIdentity = g_pCoreIdent;
60 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
72 *err = HandleError_None;
75 return (root) ? pStk->pBase : pStk->pCurRoot.front();
78 static cell_t smn_KvSetString(IPluginContext *pCtx, const cell_t *params)
80 Handle_t hndl = static_cast<Handle_t>(params[1]);
86 sec.pIdentity = g_pCoreIdent;
88 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
91 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
95 pCtx->LocalToString(params[2], &key);
96 pCtx->LocalToString(params[3], &value);
98 pStk->pCurRoot.front()->SetString(key, value);
103 static cell_t smn_KvSetNum(IPluginContext *pCtx, const cell_t *params)
105 Handle_t hndl = static_cast<Handle_t>(params[1]);
111 sec.pIdentity = g_pCoreIdent;
113 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
116 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
120 pCtx->LocalToString(params[2], &key);
122 pStk->pCurRoot.front()->SetInt(key, params[3]);
127 static cell_t smn_KvSetUInt64(IPluginContext *pCtx, const cell_t *params)
129 Handle_t hndl = static_cast<Handle_t>(params[1]);
135 sec.pIdentity = g_pCoreIdent;
137 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
140 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
146 pCtx->LocalToString(params[2], &key);
147 pCtx->LocalToPhysAddr(params[3], &addr);
149 value = static_cast<uint64>(*addr);
150 pStk->pCurRoot.front()->SetUint64(key, value);
155 static cell_t smn_KvSetFloat(IPluginContext *pCtx, const cell_t *params)
157 Handle_t hndl = static_cast<Handle_t>(params[1]);
163 sec.pIdentity = g_pCoreIdent;
165 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
168 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
172 pCtx->LocalToString(params[2], &key);
174 pStk->pCurRoot.front()->SetFloat(key, sp_ctof(params[3]));
179 static cell_t smn_KvSetColor(IPluginContext *pCtx, const cell_t *params)
181 Handle_t hndl = static_cast<Handle_t>(params[1]);
187 sec.pIdentity = g_pCoreIdent;
189 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
192 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
196 pCtx->LocalToString(params[2], &key);
198 Color color(params[3], params[4], params[5], params[6]);
199 pStk->pCurRoot.front()->SetColor(key, color);
204 static cell_t smn_KvGetString(IPluginContext *pCtx, const cell_t *params)
206 Handle_t hndl = static_cast<Handle_t>(params[1]);
212 sec.pIdentity = g_pCoreIdent;
214 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
217 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
221 char *key, *defvalue;
222 pCtx->LocalToString(params[2], &key);
223 pCtx->LocalToString(params[5], &defvalue);
225 value = pStk->pCurRoot.front()->GetString(key, defvalue);
226 pCtx->StringToLocalUTF8(params[3], params[4], value, NULL);
231 static cell_t smn_KvGetNum(IPluginContext *pCtx, const cell_t *params)
233 Handle_t hndl = static_cast<Handle_t>(params[1]);
239 sec.pIdentity = g_pCoreIdent;
241 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
244 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
249 pCtx->LocalToString(params[2], &key);
251 value = pStk->pCurRoot.front()->GetInt(key, params[3]);
256 static cell_t smn_KvGetFloat(IPluginContext *pCtx, const cell_t *params)
258 Handle_t hndl = static_cast<Handle_t>(params[1]);
264 sec.pIdentity = g_pCoreIdent;
266 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
269 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
274 pCtx->LocalToString(params[2], &key);
276 value = pStk->pCurRoot.front()->GetFloat(key, sp_ctof(params[3]));
278 return sp_ftoc(value);
281 static cell_t smn_KvGetColor(IPluginContext *pCtx, const cell_t *params)
283 Handle_t hndl = static_cast<Handle_t>(params[1]);
289 sec.pIdentity = g_pCoreIdent;
291 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
294 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
299 cell_t *r, *g, *b, *a;
300 pCtx->LocalToString(params[2], &key);
301 pCtx->LocalToPhysAddr(params[3], &r);
302 pCtx->LocalToPhysAddr(params[4], &g);
303 pCtx->LocalToPhysAddr(params[5], &b);
304 pCtx->LocalToPhysAddr(params[6], &a);
306 color = pStk->pCurRoot.front()->GetColor(key);
315 static cell_t smn_KvGetUInt64(IPluginContext *pCtx, const cell_t *params)
317 Handle_t hndl = static_cast<Handle_t>(params[1]);
323 sec.pIdentity = g_pCoreIdent;
325 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
328 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
332 cell_t *addr, *defvalue;
334 pCtx->LocalToString(params[2], &key);
335 pCtx->LocalToPhysAddr(params[3], &addr);
336 pCtx->LocalToPhysAddr(params[4], &defvalue);
338 value = pStk->pCurRoot.front()->GetUint64(key, static_cast<uint64>(*defvalue));
339 *reinterpret_cast<uint64 *>(addr) = value;
344 static cell_t smn_CreateKeyValues(IPluginContext *pCtx, const cell_t *params)
347 char *name, *firstkey, *firstvalue;
350 pCtx->LocalToString(params[1], &name);
351 pCtx->LocalToString(params[2], &firstkey);
352 pCtx->LocalToString(params[3], &firstvalue);
354 is_empty = (firstkey[0] == '\0');
355 pStk = new KeyValueStack;
356 pStk->pBase = new KeyValues(name, is_empty ? NULL : firstkey, (is_empty||(firstvalue[0]=='\0')) ? NULL : firstvalue);
357 pStk->pCurRoot.push(pStk->pBase);
359 return g_HandleSys.CreateHandle(g_KeyValueType, pStk, pCtx->GetIdentity(), g_pCoreIdent, NULL);
362 static cell_t smn_KvJumpToKey(IPluginContext *pCtx, const cell_t *params)
364 Handle_t hndl = static_cast<Handle_t>(params[1]);
371 sec.pIdentity = g_pCoreIdent;
373 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
376 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
379 pCtx->LocalToString(params[2], &name);
381 KeyValues *pSubKey = pStk->pCurRoot.front();
382 pSubKey = pSubKey->FindKey(name, (params[3]) ? true : false);
387 pStk->pCurRoot.push(pSubKey);
392 static cell_t smn_KvGotoFirstSubKey(IPluginContext *pCtx, const cell_t *params)
394 Handle_t hndl = static_cast<Handle_t>(params[1]);
400 sec.pIdentity = g_pCoreIdent;
402 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
405 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
408 KeyValues *pSubKey = pStk->pCurRoot.front();
409 KeyValues *pFirstSubKey;
412 pFirstSubKey = pSubKey->GetFirstTrueSubKey();
414 pFirstSubKey = pSubKey->GetFirstSubKey();
421 pStk->pCurRoot.push(pFirstSubKey);
426 static cell_t smn_KvGotoNextKey(IPluginContext *pCtx, const cell_t *params)
428 Handle_t hndl = static_cast<Handle_t>(params[1]);
434 sec.pIdentity = g_pCoreIdent;
436 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
439 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
442 KeyValues *pSubKey = pStk->pCurRoot.front();
445 pSubKey = pSubKey->GetNextKey();
447 pSubKey = pSubKey->GetNextTrueSubKey();
453 pStk->pCurRoot.pop();
454 pStk->pCurRoot.push(pSubKey);
459 static cell_t smn_KvJumpNextSubKey(IPluginContext *pCtx, const cell_t *params)
461 Handle_t hndl = static_cast<Handle_t>(params[1]);
467 sec.pIdentity = g_pCoreIdent;
469 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
472 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
475 KeyValues *pSubKey = pStk->pCurRoot.front();
476 KeyValues *pNextKey = pSubKey->GetNextKey();
481 pStk->pCurRoot.push(pNextKey);
486 static cell_t smn_KvGoBack(IPluginContext *pCtx, const cell_t *params)
488 Handle_t hndl = static_cast<Handle_t>(params[1]);
494 sec.pIdentity = g_pCoreIdent;
496 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
499 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
502 if (pStk->pCurRoot.size() == 1)
506 pStk->pCurRoot.pop();
511 static cell_t smn_KvRewind(IPluginContext *pCtx, const cell_t *params)
513 Handle_t hndl = static_cast<Handle_t>(params[1]);
519 sec.pIdentity = g_pCoreIdent;
521 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
524 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
527 while (pStk->pCurRoot.size() > 1)
529 pStk->pCurRoot.pop();
535 static cell_t smn_KvGetSectionName(IPluginContext *pCtx, const cell_t *params)
537 Handle_t hndl = static_cast<Handle_t>(params[1]);
543 sec.pIdentity = g_pCoreIdent;
545 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
548 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
551 KeyValues *pSection = pStk->pCurRoot.front();
552 const char *name = pSection->GetName();
557 pCtx->StringToLocalUTF8(params[2], params[3], name, NULL);
562 static cell_t smn_KvSetSectionName(IPluginContext *pCtx, const cell_t *params)
564 Handle_t hndl = static_cast<Handle_t>(params[1]);
571 sec.pIdentity = g_pCoreIdent;
573 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
576 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
579 pCtx->LocalToString(params[2], &name);
581 KeyValues *pSection = pStk->pCurRoot.front();
582 pSection->SetName(name);
587 static cell_t smn_KvGetDataType(IPluginContext *pCtx, const cell_t *params)
589 Handle_t hndl = static_cast<Handle_t>(params[1]);
596 sec.pIdentity = g_pCoreIdent;
598 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
601 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
604 pCtx->LocalToString(params[2], &name);
606 return pStk->pCurRoot.front()->GetDataType(name);
609 static cell_t smn_KeyValuesToFile(IPluginContext *pCtx, const cell_t *params)
611 Handle_t hndl = static_cast<Handle_t>(params[1]);
618 sec.pIdentity = g_pCoreIdent;
620 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
623 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
626 pCtx->LocalToString(params[2], &path);
628 char realpath[PLATFORM_MAX_PATH];
629 g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
631 return pStk->pCurRoot.front()->SaveToFile(basefilesystem, realpath);
634 static cell_t smn_FileToKeyValues(IPluginContext *pCtx, const cell_t *params)
636 Handle_t hndl = static_cast<Handle_t>(params[1]);
643 sec.pIdentity = g_pCoreIdent;
645 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
648 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
651 pCtx->LocalToString(params[2], &path);
653 char realpath[PLATFORM_MAX_PATH];
654 g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
656 return pStk->pCurRoot.front()->LoadFromFile(basefilesystem, realpath);
659 static cell_t smn_KvSetEscapeSequences(IPluginContext *pCtx, const cell_t *params)
661 Handle_t hndl = static_cast<Handle_t>(params[1]);
667 sec.pIdentity = g_pCoreIdent;
669 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
672 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
675 pStk->pCurRoot.front()->UsesEscapeSequences(params[2] ? true : false);
680 static cell_t smn_KvNodesInStack(IPluginContext *pCtx, const cell_t *params)
682 Handle_t hndl = static_cast<Handle_t>(params[1]);
688 sec.pIdentity = g_pCoreIdent;
690 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
693 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
696 return pStk->pCurRoot.size() - 1;
699 static cell_t smn_KvDeleteThis(IPluginContext *pContext, const cell_t *params)
701 Handle_t hndl = static_cast<Handle_t>(params[1]);
707 sec.pIdentity = g_pCoreIdent;
709 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
712 return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
715 if (pStk->pCurRoot.size() < 2)
720 KeyValues *pValues = pStk->pCurRoot.front();
721 pStk->pCurRoot.pop();
722 KeyValues *pRoot = pStk->pCurRoot.front();
724 /* We have to manually verify this since Valve sucks
725 * :TODO: make our own KeyValues.h file and make
726 * the sub stuff private so we can do this ourselves!
728 KeyValues *sub = pRoot->GetFirstSubKey();
733 KeyValues *pNext = pValues->GetNextKey();
734 pRoot->RemoveSubKey(pValues);
735 pValues->deleteThis();
738 pStk->pCurRoot.push(pNext);
744 sub = sub->GetNextKey();
747 /* Push this back on :( */
748 pStk->pCurRoot.push(pValues);
753 static cell_t smn_KvDeleteKey(IPluginContext *pContext, const cell_t *params)
755 Handle_t hndl = static_cast<Handle_t>(params[1]);
761 sec.pIdentity = g_pCoreIdent;
763 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
766 return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
769 if (pStk->pCurRoot.size() < 2)
775 pContext->LocalToString(params[2], &keyName);
777 KeyValues *pRoot = pStk->pCurRoot.front();
778 KeyValues *pValues = pRoot->FindKey(keyName);
784 pRoot->RemoveSubKey(pValues);
785 pValues->deleteThis();
790 static cell_t smn_KvSavePosition(IPluginContext *pContext, const cell_t *params)
792 Handle_t hndl = static_cast<Handle_t>(params[1]);
798 sec.pIdentity = g_pCoreIdent;
800 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
803 return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
806 if (pStk->pCurRoot.size() < 2)
811 KeyValues *pValues = pStk->pCurRoot.front();
812 pStk->pCurRoot.push(pValues);
817 static KeyValueNatives s_KeyValueNatives;
819 REGISTER_NATIVES(keyvaluenatives)
821 {"KvSetString", smn_KvSetString},
822 {"KvSetNum", smn_KvSetNum},
823 {"KvSetUInt64", smn_KvSetUInt64},
824 {"KvSetFloat", smn_KvSetFloat},
825 {"KvSetColor", smn_KvSetColor},
826 {"KvGetString", smn_KvGetString},
827 {"KvGetNum", smn_KvGetNum},
828 {"KvGetFloat", smn_KvGetFloat},
829 {"KvGetColor", smn_KvGetColor},
830 {"KvGetUInt64", smn_KvGetUInt64},
831 {"CreateKeyValues", smn_CreateKeyValues},
832 {"KvJumpToKey", smn_KvJumpToKey},
833 {"KvGotoNextKey", smn_KvGotoNextKey},
834 {"KvJumpFirstSubKey", smn_KvGotoFirstSubKey}, /* BACKWARDS COMPAT SHIM */
835 {"KvGotoFirstSubKey", smn_KvGotoFirstSubKey},
836 {"KvJumpNextSubKey", smn_KvJumpNextSubKey}, /* BACKWARDS COMPAT SHIM */
837 {"KvGoBack", smn_KvGoBack},
838 {"KvRewind", smn_KvRewind},
839 {"KvGetSectionName", smn_KvGetSectionName},
840 {"KvSetSectionName", smn_KvSetSectionName},
841 {"KvGetDataType", smn_KvGetDataType},
842 {"KeyValuesToFile", smn_KeyValuesToFile},
843 {"FileToKeyValues", smn_FileToKeyValues},
844 {"KvSetEscapeSequences", smn_KvSetEscapeSequences},
845 {"KvDeleteThis", smn_KvDeleteThis},
846 {"KvDeleteKey", smn_KvDeleteKey},
847 {"KvNodesInStack", smn_KvNodesInStack},
848 {"KvSavePosition", smn_KvSavePosition},