From 08ec195e27c2044d5fead6bdf9f7bc253f4247a9 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Sun, 25 Mar 2007 20:20:43 +0000 Subject: [PATCH] initial implementation of KV natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40660 --- core/msvc8/sourcemod_mm.vcproj | 6 +- core/smn_keyvalues.cpp | 639 +++++++++++++++++++++++++++++++++ core/sourcemm_api.cpp | 2 + core/sourcemm_api.h | 2 + plugins/include/keyvalues.inc | 280 +++++++++++++++ 5 files changed, 928 insertions(+), 1 deletion(-) create mode 100644 core/smn_keyvalues.cpp create mode 100644 plugins/include/keyvalues.inc diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 0e4575de..7649f658 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ + + diff --git a/core/smn_keyvalues.cpp b/core/smn_keyvalues.cpp new file mode 100644 index 00000000..745756f1 --- /dev/null +++ b/core/smn_keyvalues.cpp @@ -0,0 +1,639 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include "sourcemod.h" +#include "sourcemm_api.h" +#include "sm_stringutil.h" +#include "HandleSys.h" +#include + +HandleType_t g_KeyValueType; + +struct KeyValueStack +{ + KeyValues *pBase; + CStack pCurRoot; +}; + +class KeyValuekNatives : + 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; + } +}; + +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->LocalToString(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->LocalToString(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->LocalToString(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->LocalToString(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->LocalToString(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_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->LocalToString(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->LocalToString(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->LocalToString(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->LocalToString(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->LocalToString(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_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->pBase->FindKey(name, (params[3]) ? true : false); + if (!pSubKey) + { + return 0; + } + pStk->pCurRoot.push(pSubKey); + + return 1; +} + +static cell_t smn_KvJumpFirstSubKey(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 = pSubKey->GetFirstSubKey(); + if (!pFirstSubKey) + { + return 0; + } + pStk->pCurRoot.push(pFirstSubKey); + + return 1; +} + +static cell_t smn_KvJumpNextSubKey(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 *pNextKey = pSubKey->GetNextKey(); + if (!pNextKey) + { + return 0; + } + pStk->pCurRoot.push(pNextKey); + + 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; + + 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()->LoadFromFile(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 KeyValuekNatives s_KeyValuekNatives; + +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}, + {"KvJumpFirstSubKey", smn_KvJumpFirstSubKey}, + {"KvJumpNextSubKey", smn_KvJumpNextSubKey}, + {"KvGoBack", smn_KvGoBack}, + {"KvRewind", smn_KvRewind}, + {"KvGetSectionName", smn_KvGetSectionName}, + {"KvSetSectionName", smn_KvSetSectionName}, + {"KvGetDataType", smn_KvGetDataType}, + {"KeyValuesToFile", smn_KeyValuesToFile}, + {"FileToKeyValues", smn_FileToKeyValues}, + {"KvSetEscapeSequences", smn_KvSetEscapeSequences}, + {NULL, NULL} +}; diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index 2be581b4..cf687e62 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -29,6 +29,7 @@ IUniformRandomStream *engrandom = NULL; CallClass *enginePatch = NULL; CallClass *gamedllPatch = NULL; IPlayerInfoManager *playerinfo = NULL; +IBaseFileSystem *basefilesystem; PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core); @@ -42,6 +43,7 @@ bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen GET_V_IFACE_CURRENT(engineFactory, icvar, ICvar, VENGINE_CVAR_INTERFACE_VERSION); GET_V_IFACE_CURRENT(engineFactory, gameevents, IGameEventManager2, INTERFACEVERSION_GAMEEVENTSMANAGER2); GET_V_IFACE_CURRENT(engineFactory, engrandom, IUniformRandomStream, VENGINE_SERVER_RANDOM_INTERFACE_VERSION); + GET_V_IFACE_CURRENT(fileSystemFactory, basefilesystem, IBaseFileSystem, BASEFILESYSTEM_INTERFACE_VERSION); /* :TODO: Make this optional and... make it find earlier versions [?] */ GET_V_IFACE_CURRENT(serverFactory, playerinfo, IPlayerInfoManager, INTERFACEVERSION_PLAYERINFOMANAGER); diff --git a/core/sourcemm_api.h b/core/sourcemm_api.h index ade38342..be28c1f1 100644 --- a/core/sourcemm_api.h +++ b/core/sourcemm_api.h @@ -21,6 +21,7 @@ #include #include #include +#include /** * @file Contains wrappers around required Metamod:Source API exports @@ -57,6 +58,7 @@ extern SourceHook::CallClass *enginePatch; extern SourceHook::CallClass *gamedllPatch; extern IUniformRandomStream *engrandom; extern IPlayerInfoManager *playerinfo; +extern IBaseFileSystem *basefilesystem; #define ENGINE_CALL(func) SH_CALL(enginePatch, &IVEngineServer::func) #define SERVER_CALL(func) SH_CALL(gamedllPatch, &IServerGameDLL::func) diff --git a/plugins/include/keyvalues.inc b/plugins/include/keyvalues.inc new file mode 100644 index 00000000..56ac067f --- /dev/null +++ b/plugins/include/keyvalues.inc @@ -0,0 +1,280 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#if defined _keyvalues_included + #endinput +#endif +#define _keyvalues_included + +/** + * KeyValue data value types + */ +enum KvDataTypes +{ + KvData_None = 0, /**< Type could not be identified, or no type */ + KvData_String, /**< String value */ + KvData_Int, /**< Integer value */ + KvData_Float, /**< Floating point value */ + KvData_Ptr, /**< Pointer value (sometimes called "long") */ + KvData_WString, /**< Wide string value */ + KvData_Color, /**< Color value */ + KvData_UInt64, /**< Large integer value */ + /* --- */ + KvData_NUMTYPES, +}; + +/** + * Creates a new KeyValues structure. The Handle must always be closed. + * + * @param name Name of the root section. + * @param firstKey If non-empty, specifies the first key value. + * @param firstValue If firstKey is non-empty, specifies the first key's value. + * @return A Handle to a new KeyValues structure. + */ +native Handle:CreateKeyValues(const String:name[], const String:firstkey[], const String:firstValue[]); + +/** + * Sets a string value of a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @param value String value. + * @noreturn + * @error Invalid Handle. + */ +native KvSetString(Handle:kv, const String:key[], const String:value[]); + +/** + * Sets an integer value of a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @param value Value number. + * @noreturn + * @error Invalid Handle. + */ +native KvSetNum(Handle:kv, const String:key[], value); + +/** + * Sets a large integer value of a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @param value Large integer value (0=High bits, 1=Low bits) + * @noreturn + * @error Invalid Handle. + */ +native KvSetUint64(Handle:kv, const String:key[], const value[2]); + +/** + * Sets a floating point value of a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @param value Floating point value. + * @noreturn + * @error Invalid Handle. + */ +native KvSetFloat(Handle:kv, const String:key[], Float:value); + +/** + * Sets a set of color values of a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @param r Red value. + * @param g Green value. + * @param b Blue value. + * @param a Alpha value. + * @noreturn + * @error Invalid Handle. + */ +native KvSetColor(Handle:kv, const String:key[], r, g, b, a=0); + +/** + * Retrieves a string value from a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @param value Buffer to store key value in. + * @param maxlength Maximum length of the value buffer. + * @param defvalue Optional default value to use if the key is not found. + * @noreturn + * @error Invalid Handle. + */ +native KvGetString(Handle:kv, const String:key[], String:value[], maxlength, const String:defvalue[]=""); + +/** + * Retrieves an integer value from a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @param defvalue Optional default value to use if the key is not found. + * @return Integer value of the key. + * @error Invalid Handle. + */ +native KvGetNum(Handle:kv, const String:key[], defvalue=0); + +/** + * Retrieves a floating point value from a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @param defvalue Optional default value to use if the key is not found. + * @return Floating point value of the key. + * @error Invalid Handle. + */ +native Float:KvGetFloat(Handle:kv, const String:key[], Float:defvalue=0.0); + +/** + * Retrieves a set of color values from a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @param r Red value, set by reference. + * @param g Green value, set by reference. + * @param b Blue value, set by reference. + * @param a Alpha value, set by reference. + * @noreturn + * @error Invalid Handle. + */ +native KvGetColor(Handle:kv, const String:key[], &r, &g, &b, &a); + +/** + * Retrieves a large integer value from a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @param value Array to represent the large integer. + * @param defvalue Optional default value to use if the key is not found. + * @noreturn + * @error Invalid Handle. + */ +native KvGetUint64(Handle:kv, const String:key[], value[2], defvalue[2]={0,0}); + +/** + * Sets the current position in the KeyValues tree to the given key. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @param create If true, and the key does not exist, it will be created. + * @return True if the key exists, false if it does not and was not created. + */ +native bool:KvJumpToKey(Handle:kv, const String:key[], bool:create=false); + +/** + * Sets the current position in the KeyValues tree to the first sub key. + * + * @param kv KeyValues Handle. + * @return True on success, false if there was no first sub key. + * @error Invalid Handle. + */ +native bool:KvJumpFirstSubKey(Handle:kv); + +/** + * Sets the current position in the KeyValues tree to the next sub key. + * + * @param kv KeyValues Handle. + * @return True on success, false if there was no next sub key. + * @error Invalid Handle. + */ +native bool:KvJumpNextSubKey(Handle:kv); + +/** + * Jumps back to the previous position. Returns false if there are no + * previous positions (i.e., at the root node). This should be called + * once for each successful Jump call, in order to return to the top node. + * + * @param kv KeyValues Handle. + * @return True on success, false if there is no higher node. + * @error Invalid Handle. + */ +native bool:KvGoBack(Handle:kv); + +/** + * Sets the position back to the top node, emptying the entire node + * traversal history. This can be used instead of looping KvGoBack() + * if recursive iteration is not important. + * + * @param kv KeyValues Handle. + * @noreturn + * @error Invalid Handle. + */ +native KvRewind(Handle:kv); + +/** + * Retrieves the current section name. + * + * @param kv KeyValues Handle. + * @param section Buffer to store the section name. + * @param maxlength Maximum length of the name buffer. + * @return True on success, false on failure. + * @error Invalid Handle. + */ +native bool:KvGetSectionName(Handle:kv, String:section[], maxlength); + +/** + * Sets the current section name. + * + * @param kv KeyValues Handle. + * @param section Section name. + * @noreturn + * @error Invalid Handle. + */ +native KvSetSectionName(Handle:kv, const String:section[]); + +/** + * Returns the data type at a key. + * + * @param kv KeyValues Handle. + * @param key Key name. + * @return KvDataType value of the key. + * @error Invalid Handle. + */ +native KvDataTypes:KvGetDataType(Handle:kv, const String:key[]); + +/** + * Converts a KeyValues tree to a file. The tree is dumped + * from the current position. + * + * @param kv KeyValues Handle. + * @param file File to dump write to. + * @return True on success, false otherwise. + * @error Invalid Handle. + */ +native bool:KeyValuesToFile(Handle:kv, const String:file[]); + +/** + * Converts a file to a KeyValues tree. The file is read into + * the current position of the tree. + * + * @param kv KeyValues Handle. + * @param file File to read from. + * @return True on success, false otherwise. + * @error Invalid Handle. + */ +native bool:FileToKeyValues(Handle:kv, const String:file[]); + +/** + * Sets whether or not the KeyValues parser will read escape sequences. + * For example, \n would be read as a literal newline. This defaults + * to false for new KeyValues structures. + * + * @param kv KeyValues Handle. + * @param useEscapes Whether or not to read escape sequences. + * @noreturn + * @error Invalid Handle. + */ +native KvSetEscapeSequences(Handle:kv, bool:useEscapes);