mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
The KeyValues class belongs here. Also reimplemented most loading methods for KeyValues, and adjusted the VPK building code to account for it. Pointers to the engine's implementation of KeyValues have been moved to a separate header ('keyvalues_iface.h'), as this allows external tools code to utilize the standalone KeyValues class implementation. Playlist utilities are completely separated from the KeyValues header; these have nothing to do with KeyValues other than manipulating a global KeyValues object for the playlists, and thus have been named as such and moved to rtech/playlists.
194 lines
9.0 KiB
C++
194 lines
9.0 KiB
C++
#pragma once
|
|
#include "mathlib/color.h"
|
|
#include "tier1/utlbuffer.h"
|
|
#include "tier1/exprevaluator.h"
|
|
#include "public/ifilesystem.h"
|
|
|
|
#define KEYVALUES_TOKEN_SIZE (1024 * 32)
|
|
|
|
// single byte identifies a xbox kv file in binary format
|
|
// strings are pooled from a searchpath/zip mounted symbol table
|
|
#define KV_BINARY_POOLED_FORMAT 0xAA
|
|
|
|
//---------------------------------------------------------------------------------
|
|
// Purpose: Forward declarations
|
|
//---------------------------------------------------------------------------------
|
|
class KeyValues;
|
|
class CFileSystem_Stdio;
|
|
class IBaseFileSystem;
|
|
class CKeyValuesTokenReader;
|
|
|
|
enum KeyValuesTypes_t : char
|
|
{
|
|
TYPE_NONE = 0x0,
|
|
TYPE_STRING = 0x1,
|
|
TYPE_INT = 0x2,
|
|
TYPE_FLOAT = 0x3,
|
|
TYPE_PTR = 0x4,
|
|
TYPE_WSTRING = 0x5,
|
|
TYPE_COLOR = 0x6,
|
|
TYPE_UINT64 = 0x7,
|
|
TYPE_COMPILED_INT_BYTE = 0x8,
|
|
TYPE_COMPILED_INT_0 = 0x9,
|
|
TYPE_COMPILED_INT_1 = 0xA,
|
|
TYPE_NUMTYPES = 0xB,
|
|
};
|
|
enum MergeKeyValuesOp_t
|
|
{
|
|
MERGE_KV_ALL,
|
|
MERGE_KV_UPDATE, // update values are copied into storage, adding new keys to storage or updating existing ones
|
|
MERGE_KV_DELETE, // update values specify keys that get deleted from storage
|
|
MERGE_KV_BORROW, // update values only update existing keys in storage, keys in update that do not exist in storage are discarded
|
|
};
|
|
|
|
#define FOR_EACH_SUBKEY( kvRoot, kvSubKey ) \
|
|
for ( KeyValues * kvSubKey = kvRoot->GetFirstSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextKey() )
|
|
|
|
#define FOR_EACH_TRUE_SUBKEY( kvRoot, kvSubKey ) \
|
|
for ( KeyValues * kvSubKey = kvRoot->GetFirstTrueSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextTrueSubKey() )
|
|
|
|
#define FOR_EACH_VALUE( kvRoot, kvValue ) \
|
|
for ( KeyValues * kvValue = kvRoot->GetFirstValue(); kvValue != NULL; kvValue = kvValue->GetNextValue() )
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Simple recursive data access class
|
|
// Used in vgui for message parameters and resource files
|
|
// Destructor deletes all child KeyValues nodes
|
|
// Data is stored in key (string names) - (string/int/float)value pairs called nodes.
|
|
//
|
|
// About KeyValues Text File Format:
|
|
|
|
// It has 3 control characters '{', '}' and '"'. Names and values may be quoted or
|
|
// not. The quote '"' character must not be used within name or values, only for
|
|
// quoting whole tokens. You may use escape sequences wile parsing and add within a
|
|
// quoted token a \" to add quotes within your name or token. When using Escape
|
|
// Sequence the parser must now that by setting KeyValues::UsesEscapeSequences( true ),
|
|
// which it's off by default. Non-quoted tokens ends with a whitespace, '{', '}' and '"'.
|
|
// So you may use '{' and '}' within quoted tokens, but not for non-quoted tokens.
|
|
// An open bracket '{' after a key name indicates a list of subkeys which is finished
|
|
// with a closing bracket '}'. Subkeys use the same definitions recursively.
|
|
// Whitespaces are space, return, newline and tabulator. Allowed Escape sequences
|
|
// are \n, \t, \\, \n and \". The number character '#' is used for macro purposes
|
|
// (eg #include), don't use it as first character in key names.
|
|
//-----------------------------------------------------------------------------
|
|
class KeyValues
|
|
{
|
|
public:
|
|
// Constructors/destructors
|
|
KeyValues(const char* pszSetName);
|
|
KeyValues(const char* pszSetName, const char* pszFirstKey, const char* pszFirstValue);
|
|
KeyValues(const char* pszSetName, const char* pszFirstKey, const wchar_t* pwszFirstValue);
|
|
KeyValues(const char* pszSetName, const char* pszFirstKey, int iFirstValue);
|
|
KeyValues(const char* pszSetName, const char* pszFirstKey, const char* pszFirstValue, const char* pszSecondKey, const char* pszSecondValue);
|
|
KeyValues(const char* pszSetName, const char* pszFirstKey, int iFirstValue, const char* pszSecondKey, int iSecondValue);
|
|
~KeyValues(void);
|
|
|
|
void Init(void);
|
|
void Clear(void);
|
|
void DeleteThis(void);
|
|
void RemoveEverything();
|
|
|
|
KeyValues* FindKey(int keySymbol) const;
|
|
KeyValues* FindKey(const char* pKeyName, bool bCreate = false);
|
|
KeyValues* FindLastSubKey(void) const;
|
|
|
|
void AddSubKey(KeyValues* pSubkey);
|
|
void RemoveSubKey(KeyValues* pSubKey);
|
|
void InsertSubKey(int nIndex, KeyValues* pSubKey);
|
|
bool ContainsSubKey(KeyValues* pSubKey);
|
|
void SwapSubKey(KeyValues* pExistingSubkey, KeyValues* pNewSubKey);
|
|
void ElideSubKey(KeyValues* pSubKey);
|
|
|
|
// Data access
|
|
bool IsEmpty(const char* pszKeyName);
|
|
KeyValues* GetFirstTrueSubKey(void) const;
|
|
KeyValues* GetNextTrueSubKey(void) const;
|
|
KeyValues* GetFirstValue(void) const;
|
|
KeyValues* GetNextValue(void) const;
|
|
KeyValues* GetFirstSubKey() const;
|
|
KeyValues* GetNextKey() const;
|
|
const char* GetName(void) const;
|
|
int GetNameSymbol() const;
|
|
int GetNameSymbolCaseSensitive() const;
|
|
int GetInt(const char* pszKeyName, int iDefaultValue);
|
|
uint64_t GetUint64(const char* pszKeyName, uint64_t nDefaultValue);
|
|
void* GetPtr(const char* pszKeyName, void* pDefaultValue);
|
|
float GetFloat(const char* pszKeyName, float flDefaultValue);
|
|
const char* GetString(const char* pszKeyName = nullptr, const char* pszDefaultValue = "");
|
|
const wchar_t* GetWString(const char* pszKeyName = nullptr, const wchar_t* pwszDefaultValue = L"");
|
|
Color GetColor(const char* pszKeyName, const Color& defaultColor);
|
|
bool GetBool(const char* pszKeyName = nullptr, bool nDefaultValue = false) { return GetInt(pszKeyName, nDefaultValue ? 1 : 0) ? true : false; }
|
|
KeyValuesTypes_t GetDataType(const char* pszKeyName);
|
|
KeyValuesTypes_t GetDataType(void) const;
|
|
|
|
// Key writing
|
|
void SetInt(const char* pszKeyName, int iValue);
|
|
void SetUint64(const char* pszKeyName, uint64_t nValue);
|
|
void SetPtr(const char* pszKeyName, void* pValue);
|
|
void SetNextKey(KeyValues* pDat);
|
|
void SetName(const char* pszName);
|
|
void SetString(const char* pszKeyName, const char* pszValue);
|
|
void SetWString(const char* pszKeyName, const wchar_t* pwszValue);
|
|
void SetStringValue(char const* pszValue);
|
|
void SetColor(const char* pszKeyName, Color color);
|
|
void SetFloat(const char* pszKeyName, float flValue);
|
|
void SetBool(const char* pszKeyName, bool bValue) { SetInt(pszKeyName, bValue ? 1 : 0); }
|
|
void UsesEscapeSequences(bool bState);
|
|
|
|
void RecursiveSaveToFile(CUtlBuffer& buf, int nIndentLevel);
|
|
|
|
bool LoadFromFile(IBaseFileSystem* filesystem, const char* resourceName, const char* pathID, GetSymbolProc_t pfnEvaluateSymbolProc = nullptr);
|
|
|
|
bool LoadFromBuffer(char const* resourceName, CUtlBuffer& buf, IBaseFileSystem* pFileSystem, const char* pPathID, GetSymbolProc_t pfnEvaluateSymbolProc = nullptr);
|
|
bool LoadFromBuffer(char const* resourceName, const char* pBuffer, IBaseFileSystem* pFileSystem, const char* pPathID, GetSymbolProc_t pfnEvaluateSymbolProc = nullptr);
|
|
|
|
// for handling #include "filename"
|
|
void AppendIncludedKeys(CUtlVector< KeyValues* >& includedKeys);
|
|
void ParseIncludedKeys(char const* resourceName, const char* filetoinclude,
|
|
IBaseFileSystem* pFileSystem, const char* pPathID, CUtlVector< KeyValues* >& includedKeys, GetSymbolProc_t pfnEvaluateSymbolProc);
|
|
|
|
// For handling #base "filename"
|
|
void MergeBaseKeys(CUtlVector< KeyValues* >& baseKeys);
|
|
void RecursiveMergeKeyValues(KeyValues* baseKV);
|
|
|
|
void CopySubkeys(KeyValues* pParent) const;
|
|
KeyValues* MakeCopy(void) const;
|
|
|
|
KeyValues* CreateKeyUsingKnownLastChild(const char* keyName, KeyValues* pLastChild);
|
|
void AddSubkeyUsingKnownLastChild(KeyValues* pSubKey, KeyValues* pLastChild);
|
|
|
|
private:
|
|
void RecursiveSaveToFile(IBaseFileSystem* pFileSystem, FileHandle_t pHandle, CUtlBuffer* pBuf, int nIndentLevel);
|
|
void RecursiveLoadFromBuffer(char const* resourceName, CKeyValuesTokenReader& tokenReader, GetSymbolProc_t pfnEvaluateSymbolProc);
|
|
|
|
void RecursiveCopyKeyValues(KeyValues& src);
|
|
|
|
// NOTE: If both filesystem and pBuf are non-null, it'll save to both of them.
|
|
// If filesystem is null, it'll ignore f.
|
|
void InternalWrite(IBaseFileSystem* filesystem, FileHandle_t f, CUtlBuffer* pBuf, const void* pData, ssize_t len);
|
|
void WriteIndents(IBaseFileSystem* filesystem, FileHandle_t f, CUtlBuffer* pBuf, int indentLevel);
|
|
void WriteConvertedString(IBaseFileSystem* pFileSystem, FileHandle_t pHandle, CUtlBuffer* pBuf, const char* pszString);
|
|
|
|
bool EvaluateConditional(const char* pExpressionString, GetSymbolProc_t pfnEvaluateSymbolProc);
|
|
|
|
public:
|
|
uint32_t m_iKeyName : 24;// 0x0000
|
|
uint32_t m_iKeyNameCaseSensitive1 : 8; // 0x0003
|
|
char* m_sValue; // 0x0008
|
|
wchar_t* m_wsValue; // 0x0010
|
|
union // 0x0018
|
|
{
|
|
int m_iValue;
|
|
float m_flValue;
|
|
void* m_pValue;
|
|
unsigned char m_Color[4];
|
|
};
|
|
char m_szShortName[8]; // 0x0020
|
|
char m_iDataType; // 0x0028
|
|
char m_bHasEscapeSequences; // 0x0029
|
|
uint16_t m_iKeyNameCaseSensitive2; // 0x002A
|
|
KeyValues* m_pPeer; // 0x0030
|
|
KeyValues* m_pSub; // 0x0038
|
|
KeyValues* m_pChain; // 0x0040
|
|
};
|