diff -r 000000000000 -r b7aa2b626807 core/smn_keyvalues.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/smn_keyvalues.cpp Sun Mar 30 07:00:22 2008 +0000 @@ -0,0 +1,1122 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#include "sourcemod.h" +#include "sourcemm_api.h" +#include "sm_stringutil.h" +#include "HandleSys.h" +#include "HalfLife2.h" +#include +#include "utlbuffer.h" + +HandleType_t g_KeyValueType; + +struct KeyValueStack +{ + KeyValues *pBase; + CStack pCurRoot; +}; + +class KeyValueNatives : + public SMGlobalClass, + public IHandleTypeDispatch +{ +public: + void OnSourceModAllInitialized() + { + g_KeyValueType = g_HandleSys.CreateType("KeyValues", this, 0, NULL, NULL, g_pCoreIdent, NULL); + } + void OnSourceModShutdown() + { + g_HandleSys.RemoveType(g_KeyValueType, g_pCoreIdent); + g_KeyValueType = 0; + } + void OnHandleDestroy(HandleType_t type, void *object) + { + KeyValueStack *pStk = reinterpret_cast(object); + pStk->pBase->deleteThis(); + delete pStk; + } + int CalcKVSizeR(KeyValues *pv) + { + CUtlBuffer buf; + int size; + + pv->RecursiveSaveToFile(buf, 0); + size = buf.TellMaxPut(); + + buf.Purge(); + + return size; + } + bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize) + { + KeyValueStack *pStk = (KeyValueStack *)object; + unsigned int size = sizeof(KeyValueStack) + (pStk->pCurRoot.size() * sizeof(KeyValues *)); + + /* Check how much memory the actual thing takes up */ + size += CalcKVSizeR(pStk->pBase); + + *pSize = size; + + return true; + } +}; + +KeyValues *SourceModBase::ReadKeyValuesHandle(Handle_t hndl, HandleError *err, bool root) +{ + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + if (err) + { + *err = herr; + } + return NULL; + } + + if (err) + { + *err = HandleError_None; + } + + return (root) ? pStk->pBase : pStk->pCurRoot.front(); +} + +static cell_t smn_KvSetString(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + char *key, *value; + pCtx->LocalToStringNULL(params[2], &key); + pCtx->LocalToString(params[3], &value); + + pStk->pCurRoot.front()->SetString(key, value); + + return 1; +} + +static cell_t smn_KvSetNum(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + char *key; + pCtx->LocalToStringNULL(params[2], &key); + + pStk->pCurRoot.front()->SetInt(key, params[3]); + + return 1; +} + +static cell_t smn_KvSetUInt64(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + char *key; + cell_t *addr; + uint64 value; + pCtx->LocalToStringNULL(params[2], &key); + pCtx->LocalToPhysAddr(params[3], &addr); + + value = static_cast(*addr); + pStk->pCurRoot.front()->SetUint64(key, value); + + return 1; +} + +static cell_t smn_KvSetFloat(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + char *key; + pCtx->LocalToStringNULL(params[2], &key); + + pStk->pCurRoot.front()->SetFloat(key, sp_ctof(params[3])); + + return 1; +} + +static cell_t smn_KvSetColor(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + char *key; + pCtx->LocalToStringNULL(params[2], &key); + + Color color(params[3], params[4], params[5], params[6]); + pStk->pCurRoot.front()->SetColor(key, color); + + return 1; +} + +static cell_t smn_KvSetVector(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + char *key; + char buffer[64]; + cell_t *vector; + pCtx->LocalToStringNULL(params[2], &key); + pCtx->LocalToPhysAddr(params[3], &vector); + + UTIL_Format(buffer, sizeof(buffer), "%f %f %f", sp_ctof(vector[0]), sp_ctof(vector[1]), sp_ctof(vector[2])); + + pStk->pCurRoot.front()->SetString(key, buffer); + + return 1; +} + +static cell_t smn_KvGetString(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + const char *value; + char *key, *defvalue; + pCtx->LocalToStringNULL(params[2], &key); + pCtx->LocalToString(params[5], &defvalue); + + value = pStk->pCurRoot.front()->GetString(key, defvalue); + pCtx->StringToLocalUTF8(params[3], params[4], value, NULL); + + return 1; +} + +static cell_t smn_KvGetNum(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + int value; + char *key; + pCtx->LocalToStringNULL(params[2], &key); + + value = pStk->pCurRoot.front()->GetInt(key, params[3]); + + return value; +} + +static cell_t smn_KvGetFloat(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + float value; + char *key; + pCtx->LocalToStringNULL(params[2], &key); + + value = pStk->pCurRoot.front()->GetFloat(key, sp_ctof(params[3])); + + return sp_ftoc(value); +} + +static cell_t smn_KvGetColor(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + Color color; + char *key; + cell_t *r, *g, *b, *a; + pCtx->LocalToStringNULL(params[2], &key); + pCtx->LocalToPhysAddr(params[3], &r); + pCtx->LocalToPhysAddr(params[4], &g); + pCtx->LocalToPhysAddr(params[5], &b); + pCtx->LocalToPhysAddr(params[6], &a); + + color = pStk->pCurRoot.front()->GetColor(key); + *r = color.r(); + *g = color.g(); + *b = color.b(); + *a = color.a(); + + return 1; +} + +static cell_t smn_KvGetUInt64(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + char *key; + cell_t *addr, *defvalue; + uint64 value; + pCtx->LocalToStringNULL(params[2], &key); + pCtx->LocalToPhysAddr(params[3], &addr); + pCtx->LocalToPhysAddr(params[4], &defvalue); + + value = pStk->pCurRoot.front()->GetUint64(key, static_cast(*defvalue)); + *reinterpret_cast(addr) = value; + + return 1; +} + +static cell_t smn_KvGetVector(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + char *key; + const char *value; + cell_t *defvector, *outvector; + char buffer[64]; + pCtx->LocalToStringNULL(params[2], &key); + pCtx->LocalToPhysAddr(params[3], &outvector); + pCtx->LocalToPhysAddr(params[4], &defvector); + + UTIL_Format(buffer, sizeof(buffer), "%f %f %f", sp_ctof(defvector[0]), sp_ctof(defvector[1]), sp_ctof(defvector[2])); + + value = pStk->pCurRoot.front()->GetString(key, buffer); + + float out; + int components = 0; + while (*value && components < 3) + { + while ((*value) && (*value == ' ')) + { + value++; + } + + out = 0.0f; + bool isnegative; + if (*value == '-') + { + isnegative = true; + value++; + } + else + { + isnegative = false; + } + + for (; *value && isdigit(*value); ++value) + { + out *= 10.0f; + out += *value - '0'; + } + + if (*value == '.') + { + value++; + float factor = 0.1f; + for (; *value && isdigit(*value); ++value) + { + out += (*value - '0') * factor; + factor *= 0.1f; + } + } + + out = (isnegative) ? -out : out; + outvector[components++] = sp_ftoc(out); + } + + return 1; +} + +static cell_t smn_CreateKeyValues(IPluginContext *pCtx, const cell_t *params) +{ + KeyValueStack *pStk; + char *name, *firstkey, *firstvalue; + bool is_empty; + + pCtx->LocalToString(params[1], &name); + pCtx->LocalToString(params[2], &firstkey); + pCtx->LocalToString(params[3], &firstvalue); + + is_empty = (firstkey[0] == '\0'); + pStk = new KeyValueStack; + pStk->pBase = new KeyValues(name, is_empty ? NULL : firstkey, (is_empty||(firstvalue[0]=='\0')) ? NULL : firstvalue); + pStk->pCurRoot.push(pStk->pBase); + + return g_HandleSys.CreateHandle(g_KeyValueType, pStk, pCtx->GetIdentity(), g_pCoreIdent, NULL); +} + +static cell_t smn_KvJumpToKey(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + char *name; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + pCtx->LocalToString(params[2], &name); + + KeyValues *pSubKey = pStk->pCurRoot.front(); + pSubKey = pSubKey->FindKey(name, (params[3]) ? true : false); + if (!pSubKey) + { + return 0; + } + pStk->pCurRoot.push(pSubKey); + + return 1; +} + +static cell_t smn_KvJumpToKeySymbol(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + KeyValues *pSubKey = pStk->pCurRoot.front(); + pSubKey = pSubKey->FindKey(params[2]); + if (!pSubKey) + { + return 0; + } + pStk->pCurRoot.push(pSubKey); + + return 1; +} + +static cell_t smn_KvGotoFirstSubKey(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + KeyValues *pSubKey = pStk->pCurRoot.front(); + KeyValues *pFirstSubKey; + if (params[2]) + { + pFirstSubKey = pSubKey->GetFirstTrueSubKey(); + } else { + pFirstSubKey = pSubKey->GetFirstSubKey(); + } + + if (!pFirstSubKey) + { + return 0; + } + pStk->pCurRoot.push(pFirstSubKey); + + return 1; +} + +static cell_t smn_KvGotoNextKey(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + KeyValues *pSubKey = pStk->pCurRoot.front(); + if (params[2]) + { + pSubKey = pSubKey->GetNextTrueSubKey(); + } else { + pSubKey = pSubKey->GetNextKey(); + } + if (!pSubKey) + { + return 0; + } + pStk->pCurRoot.pop(); + pStk->pCurRoot.push(pSubKey); + + return 1; +} + +static cell_t smn_KvGoBack(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + if (pStk->pCurRoot.size() == 1) + { + return 0; + } + pStk->pCurRoot.pop(); + + return 1; +} + +static cell_t smn_KvRewind(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + while (pStk->pCurRoot.size() > 1) + { + pStk->pCurRoot.pop(); + } + + return 1; +} + +static cell_t smn_KvGetSectionName(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + KeyValues *pSection = pStk->pCurRoot.front(); + const char *name = pSection->GetName(); + if (!name) + { + return 0; + } + pCtx->StringToLocalUTF8(params[2], params[3], name, NULL); + + return 1; +} + +static cell_t smn_KvSetSectionName(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + char *name; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + pCtx->LocalToString(params[2], &name); + + KeyValues *pSection = pStk->pCurRoot.front(); + pSection->SetName(name); + + return 1; +} + +static cell_t smn_KvGetDataType(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + char *name; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + pCtx->LocalToString(params[2], &name); + + return pStk->pCurRoot.front()->GetDataType(name); +} + +static cell_t smn_KeyValuesToFile(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + char *path; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + pCtx->LocalToString(params[2], &path); + + char realpath[PLATFORM_MAX_PATH]; + g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path); + + return pStk->pCurRoot.front()->SaveToFile(basefilesystem, realpath); +} + +static cell_t smn_FileToKeyValues(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + char *path; + KeyValueStack *pStk; + KeyValues *kv; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + pCtx->LocalToString(params[2], &path); + + char realpath[PLATFORM_MAX_PATH]; + g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path); + + kv = pStk->pCurRoot.front(); + return g_HL2.KVLoadFromFile(kv, basefilesystem, realpath); +} + +static cell_t smn_KvSetEscapeSequences(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + pStk->pCurRoot.front()->UsesEscapeSequences(params[2] ? true : false); + + return 1; +} + +static cell_t smn_KvNodesInStack(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + return pStk->pCurRoot.size() - 1; +} + +static cell_t smn_KvDeleteThis(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + if (pStk->pCurRoot.size() < 2) + { + return 0; + } + + KeyValues *pValues = pStk->pCurRoot.front(); + pStk->pCurRoot.pop(); + KeyValues *pRoot = pStk->pCurRoot.front(); + + /* We have to manually verify this since Valve sucks + * :TODO: make our own KeyValues.h file and make + * the sub stuff private so we can do this ourselves! + */ + KeyValues *sub = pRoot->GetFirstSubKey(); + while (sub) + { + if (sub == pValues) + { + KeyValues *pNext = pValues->GetNextKey(); + pRoot->RemoveSubKey(pValues); + pValues->deleteThis(); + if (pNext) + { + pStk->pCurRoot.push(pNext); + return 1; + } else { + return -1; + } + } + sub = sub->GetNextKey(); + } + + /* Push this back on :( */ + pStk->pCurRoot.push(pValues); + + return 0; +} + +static cell_t smn_KvDeleteKey(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + if (pStk->pCurRoot.size() < 2) + { + return 0; + } + + char *keyName; + pContext->LocalToString(params[2], &keyName); + + KeyValues *pRoot = pStk->pCurRoot.front(); + KeyValues *pValues = pRoot->FindKey(keyName); + if (!pValues) + { + return 0; + } + + pRoot->RemoveSubKey(pValues); + pValues->deleteThis(); + + return 1; +} + +static cell_t smn_KvSavePosition(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + if (pStk->pCurRoot.size() < 2) + { + return 0; + } + + KeyValues *pValues = pStk->pCurRoot.front(); + pStk->pCurRoot.push(pValues); + + return 1; +} + +static cell_t smn_CopySubkeys(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl_copied = static_cast(params[1]); + Handle_t hndl_parent = static_cast(params[2]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk_copied, *pStk_parent; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl_copied, g_KeyValueType, &sec, (void **)&pStk_copied)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl_copied, herr); + } + if ((herr=g_HandleSys.ReadHandle(hndl_parent, g_KeyValueType, &sec, (void **)&pStk_parent)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl_parent, herr); + } + + pStk_copied->pCurRoot.front()->CopySubkeys(pStk_parent->pCurRoot.front()); + + return 1; +} + +static cell_t smn_GetNameSymbol(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + cell_t *val; + char *key; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + if (pStk->pCurRoot.size() < 2) + { + return 0; + } + + pContext->LocalToString(params[2], &key); + + KeyValues *pKv = pStk->pCurRoot.front()->FindKey(key); + if (!pKv) + { + return 0; + } + pContext->LocalToPhysAddr(params[3], &val); + *val = pKv->GetNameSymbol(); + + return 1; +} + +static cell_t smn_FindKeyById(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + KeyValues *pKv = pStk->pCurRoot.front()->FindKey(params[2]); + if (!pKv) + { + return 0; + } + + pContext->StringToLocalUTF8(params[3], params[4], pKv->GetName(), NULL); + + return 1; +} + +static cell_t smn_KvGetSectionSymbol(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + cell_t *val; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + KeyValues *pSection = pStk->pCurRoot.front(); + + pCtx->LocalToPhysAddr(params[2], &val); + *val = pSection->GetNameSymbol(); + + if (!*val) + { + return 0; + } + + return 1; +} + +static KeyValueNatives s_KeyValueNatives; + +REGISTER_NATIVES(keyvaluenatives) +{ + {"KvSetString", smn_KvSetString}, + {"KvSetNum", smn_KvSetNum}, + {"KvSetUInt64", smn_KvSetUInt64}, + {"KvSetFloat", smn_KvSetFloat}, + {"KvSetColor", smn_KvSetColor}, + {"KvGetString", smn_KvGetString}, + {"KvGetNum", smn_KvGetNum}, + {"KvGetFloat", smn_KvGetFloat}, + {"KvGetColor", smn_KvGetColor}, + {"KvGetUInt64", smn_KvGetUInt64}, + {"CreateKeyValues", smn_CreateKeyValues}, + {"KvJumpToKey", smn_KvJumpToKey}, + {"KvJumpToKeySymbol", smn_KvJumpToKeySymbol}, + {"KvGotoNextKey", smn_KvGotoNextKey}, + {"KvGotoFirstSubKey", smn_KvGotoFirstSubKey}, + {"KvGoBack", smn_KvGoBack}, + {"KvRewind", smn_KvRewind}, + {"KvGetSectionName", smn_KvGetSectionName}, + {"KvSetSectionName", smn_KvSetSectionName}, + {"KvGetDataType", smn_KvGetDataType}, + {"KeyValuesToFile", smn_KeyValuesToFile}, + {"FileToKeyValues", smn_FileToKeyValues}, + {"KvSetEscapeSequences", smn_KvSetEscapeSequences}, + {"KvDeleteThis", smn_KvDeleteThis}, + {"KvDeleteKey", smn_KvDeleteKey}, + {"KvNodesInStack", smn_KvNodesInStack}, + {"KvSavePosition", smn_KvSavePosition}, + {"KvCopySubkeys", smn_CopySubkeys}, + {"KvFindKeyById", smn_FindKeyById}, + {"KvGetNameSymbol", smn_GetNameSymbol}, + {"KvGetSectionSymbol", smn_KvGetSectionSymbol}, + {"KvGetVector", smn_KvGetVector}, + {"KvSetVector", smn_KvSetVector}, + {NULL, NULL} +};