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 KeyValuekNatives :
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->pBase->FindKey(name, (params[3]) ? true : false);
386 pStk->pCurRoot.push(pSubKey);
391 static cell_t smn_KvJumpFirstSubKey(IPluginContext *pCtx, const cell_t *params)
393 Handle_t hndl = static_cast<Handle_t>(params[1]);
399 sec.pIdentity = g_pCoreIdent;
401 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
404 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
407 KeyValues *pSubKey = pStk->pCurRoot.front();
408 KeyValues *pFirstSubKey = pSubKey->GetFirstSubKey();
413 pStk->pCurRoot.push(pFirstSubKey);
418 static cell_t smn_KvJumpNextSubKey(IPluginContext *pCtx, const cell_t *params)
420 Handle_t hndl = static_cast<Handle_t>(params[1]);
426 sec.pIdentity = g_pCoreIdent;
428 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
431 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
434 KeyValues *pSubKey = pStk->pCurRoot.front();
435 KeyValues *pNextKey = pSubKey->GetNextKey();
440 pStk->pCurRoot.push(pNextKey);
445 static cell_t smn_KvGoBack(IPluginContext *pCtx, const cell_t *params)
447 Handle_t hndl = static_cast<Handle_t>(params[1]);
453 sec.pIdentity = g_pCoreIdent;
455 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
458 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
461 if (pStk->pCurRoot.size() == 1)
465 pStk->pCurRoot.pop();
470 static cell_t smn_KvRewind(IPluginContext *pCtx, const cell_t *params)
472 Handle_t hndl = static_cast<Handle_t>(params[1]);
478 sec.pIdentity = g_pCoreIdent;
480 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
483 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
486 while (pStk->pCurRoot.size() > 1)
488 pStk->pCurRoot.pop();
494 static cell_t smn_KvGetSectionName(IPluginContext *pCtx, const cell_t *params)
496 Handle_t hndl = static_cast<Handle_t>(params[1]);
502 sec.pIdentity = g_pCoreIdent;
504 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
507 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
510 KeyValues *pSection = pStk->pCurRoot.front();
511 const char *name = pSection->GetName();
516 pCtx->StringToLocalUTF8(params[2], params[3], name, NULL);
521 static cell_t smn_KvSetSectionName(IPluginContext *pCtx, const cell_t *params)
523 Handle_t hndl = static_cast<Handle_t>(params[1]);
530 sec.pIdentity = g_pCoreIdent;
532 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
535 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
538 pCtx->LocalToString(params[2], &name);
540 KeyValues *pSection = pStk->pCurRoot.front();
541 pSection->SetName(name);
546 static cell_t smn_KvGetDataType(IPluginContext *pCtx, const cell_t *params)
548 Handle_t hndl = static_cast<Handle_t>(params[1]);
555 sec.pIdentity = g_pCoreIdent;
557 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
560 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
563 pCtx->LocalToString(params[2], &name);
565 return pStk->pCurRoot.front()->GetDataType(name);
568 static cell_t smn_KeyValuesToFile(IPluginContext *pCtx, const cell_t *params)
570 Handle_t hndl = static_cast<Handle_t>(params[1]);
577 sec.pIdentity = g_pCoreIdent;
579 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
582 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
585 pCtx->LocalToString(params[2], &path);
587 char realpath[PLATFORM_MAX_PATH];
588 g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
590 return pStk->pCurRoot.front()->SaveToFile(basefilesystem, realpath);
593 static cell_t smn_FileToKeyValues(IPluginContext *pCtx, const cell_t *params)
595 Handle_t hndl = static_cast<Handle_t>(params[1]);
602 sec.pIdentity = g_pCoreIdent;
604 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
607 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
610 pCtx->LocalToString(params[2], &path);
612 char realpath[PLATFORM_MAX_PATH];
613 g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
615 return pStk->pCurRoot.front()->LoadFromFile(basefilesystem, realpath);
618 static cell_t smn_KvSetEscapeSequences(IPluginContext *pCtx, const cell_t *params)
620 Handle_t hndl = static_cast<Handle_t>(params[1]);
626 sec.pIdentity = g_pCoreIdent;
628 if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
631 return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
634 pStk->pCurRoot.front()->UsesEscapeSequences(params[2] ? true : false);
639 static KeyValuekNatives s_KeyValuekNatives;
641 REGISTER_NATIVES(keyvaluenatives)
643 {"KvSetString", smn_KvSetString},
644 {"KvSetNum", smn_KvSetNum},
645 {"KvSetUint64", smn_KvSetUint64},
646 {"KvSetFloat", smn_KvSetFloat},
647 {"KvSetColor", smn_KvSetColor},
648 {"KvGetString", smn_KvGetString},
649 {"KvGetNum", smn_KvGetNum},
650 {"KvGetFloat", smn_KvGetFloat},
651 {"KvGetColor", smn_KvGetColor},
652 {"KvGetUint64", smn_KvGetUint64},
653 {"CreateKeyValues", smn_CreateKeyValues},
654 {"KvJumpToKey", smn_KvJumpToKey},
655 {"KvJumpFirstSubKey", smn_KvJumpFirstSubKey},
656 {"KvJumpNextSubKey", smn_KvJumpNextSubKey},
657 {"KvGoBack", smn_KvGoBack},
658 {"KvRewind", smn_KvRewind},
659 {"KvGetSectionName", smn_KvGetSectionName},
660 {"KvSetSectionName", smn_KvSetSectionName},
661 {"KvGetDataType", smn_KvGetDataType},
662 {"KeyValuesToFile", smn_KeyValuesToFile},
663 {"FileToKeyValues", smn_FileToKeyValues},
664 {"KvSetEscapeSequences", smn_KvSetEscapeSequences},