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_KvJumpFirstSubKey(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 = pSubKey->GetFirstSubKey();
414 pStk->pCurRoot.push(pFirstSubKey);
419 static cell_t smn_KvJumpNextSubKey(IPluginContext *pCtx, const cell_t *params)
421 Handle_t hndl = static_cast<Handle_t>(params[1]);
427 sec.pIdentity = g_pCoreIdent;
429 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
432 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
435 KeyValues *pSubKey = pStk->pCurRoot.front();
436 KeyValues *pNextKey = pSubKey->GetNextKey();
441 pStk->pCurRoot.push(pNextKey);
446 static cell_t smn_KvGoBack(IPluginContext *pCtx, const cell_t *params)
448 Handle_t hndl = static_cast<Handle_t>(params[1]);
454 sec.pIdentity = g_pCoreIdent;
456 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
459 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
462 if (pStk->pCurRoot.size() == 1)
466 pStk->pCurRoot.pop();
471 static cell_t smn_KvRewind(IPluginContext *pCtx, const cell_t *params)
473 Handle_t hndl = static_cast<Handle_t>(params[1]);
479 sec.pIdentity = g_pCoreIdent;
481 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
484 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
487 while (pStk->pCurRoot.size() > 1)
489 pStk->pCurRoot.pop();
495 static cell_t smn_KvGetSectionName(IPluginContext *pCtx, const cell_t *params)
497 Handle_t hndl = static_cast<Handle_t>(params[1]);
503 sec.pIdentity = g_pCoreIdent;
505 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
508 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
511 KeyValues *pSection = pStk->pCurRoot.front();
512 const char *name = pSection->GetName();
517 pCtx->StringToLocalUTF8(params[2], params[3], name, NULL);
522 static cell_t smn_KvSetSectionName(IPluginContext *pCtx, const cell_t *params)
524 Handle_t hndl = static_cast<Handle_t>(params[1]);
531 sec.pIdentity = g_pCoreIdent;
533 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
536 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
539 pCtx->LocalToString(params[2], &name);
541 KeyValues *pSection = pStk->pCurRoot.front();
542 pSection->SetName(name);
547 static cell_t smn_KvGetDataType(IPluginContext *pCtx, const cell_t *params)
549 Handle_t hndl = static_cast<Handle_t>(params[1]);
556 sec.pIdentity = g_pCoreIdent;
558 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
561 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
564 pCtx->LocalToString(params[2], &name);
566 return pStk->pCurRoot.front()->GetDataType(name);
569 static cell_t smn_KeyValuesToFile(IPluginContext *pCtx, const cell_t *params)
571 Handle_t hndl = static_cast<Handle_t>(params[1]);
578 sec.pIdentity = g_pCoreIdent;
580 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
583 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
586 pCtx->LocalToString(params[2], &path);
588 char realpath[PLATFORM_MAX_PATH];
589 g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
591 return pStk->pCurRoot.front()->SaveToFile(basefilesystem, realpath);
594 static cell_t smn_FileToKeyValues(IPluginContext *pCtx, const cell_t *params)
596 Handle_t hndl = static_cast<Handle_t>(params[1]);
603 sec.pIdentity = g_pCoreIdent;
605 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
608 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
611 pCtx->LocalToString(params[2], &path);
613 char realpath[PLATFORM_MAX_PATH];
614 g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
616 return pStk->pCurRoot.front()->LoadFromFile(basefilesystem, realpath);
619 static cell_t smn_KvSetEscapeSequences(IPluginContext *pCtx, const cell_t *params)
621 Handle_t hndl = static_cast<Handle_t>(params[1]);
627 sec.pIdentity = g_pCoreIdent;
629 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
632 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
635 pStk->pCurRoot.front()->UsesEscapeSequences(params[2] ? true : false);
640 static cell_t smn_KvDeleteThis(IPluginContext *pContext, const cell_t *params)
642 Handle_t hndl = static_cast<Handle_t>(params[1]);
648 sec.pIdentity = g_pCoreIdent;
650 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
653 return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
656 if (pStk->pCurRoot.size() < 2)
661 KeyValues *pValues = pStk->pCurRoot.front();
662 pStk->pCurRoot.pop();
663 pStk->pCurRoot.front()->RemoveSubKey(pValues);
664 pValues->deleteThis();
669 static cell_t smn_KvDeleteKey(IPluginContext *pContext, const cell_t *params)
671 Handle_t hndl = static_cast<Handle_t>(params[1]);
677 sec.pIdentity = g_pCoreIdent;
679 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
682 return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
685 if (pStk->pCurRoot.size() < 2)
691 pContext->LocalToString(params[2], &keyName);
693 KeyValues *pRoot = pStk->pCurRoot.front();
694 KeyValues *pValues = pRoot->FindKey(keyName);
700 pRoot->RemoveSubKey(pValues);
701 pValues->deleteThis();
706 static KeyValueNatives s_KeyValueNatives;
708 REGISTER_NATIVES(keyvaluenatives)
710 {"KvSetString", smn_KvSetString},
711 {"KvSetNum", smn_KvSetNum},
712 {"KvSetUint64", smn_KvSetUint64},
713 {"KvSetFloat", smn_KvSetFloat},
714 {"KvSetColor", smn_KvSetColor},
715 {"KvGetString", smn_KvGetString},
716 {"KvGetNum", smn_KvGetNum},
717 {"KvGetFloat", smn_KvGetFloat},
718 {"KvGetColor", smn_KvGetColor},
719 {"KvGetUint64", smn_KvGetUint64},
720 {"CreateKeyValues", smn_CreateKeyValues},
721 {"KvJumpToKey", smn_KvJumpToKey},
722 {"KvJumpFirstSubKey", smn_KvJumpFirstSubKey},
723 {"KvJumpNextSubKey", smn_KvJumpNextSubKey},
724 {"KvGoBack", smn_KvGoBack},
725 {"KvRewind", smn_KvRewind},
726 {"KvGetSectionName", smn_KvGetSectionName},
727 {"KvSetSectionName", smn_KvSetSectionName},
728 {"KvGetDataType", smn_KvGetDataType},
729 {"KeyValuesToFile", smn_KeyValuesToFile},
730 {"FileToKeyValues", smn_FileToKeyValues},
731 {"KvSetEscapeSequences", smn_KvSetEscapeSequences},
732 {"KvDeleteThis", smn_KvDeleteThis},
733 {"KvDeleteKey", smn_KvDeleteKey},