#ifndef KEYVALUES_H #define KEYVALUES_H #ifdef _WIN32 #pragma once #endif #ifndef NULL #ifdef __cplusplus #define NULL 0 #else #define NULL ((void *)0) #endif #endif #include "utlvector.h" #include "color.h" #include "exprevaluator.h" #define TRACK_KV_ADD( ptr, name ) track.AddKv( ptr, name ) #define SPLIT_3_BYTES_INTO_1_AND_2( x1, x2, x3 ) do { x1 = (uint8)(x3); x2 = (uint16)( (x3) >> 8 ); } while( 0 ) #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() ) class IBaseFileSystem; class CUtlBuffer; class Color; class CKeyValuesTokenReader; class KeyValues; class IKeyValuesDumpContext; typedef void* FileHandle_t; class CKeyValuesGrowableStringTable; #define KV_BINARY_POOLED_FORMAT 0xAA #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() ) class KeyValues { friend class CKeyValuesTokenReader; public: static void SetUseGrowableStringTable(bool bUseGrowableTable); explicit KeyValues(const char* setName); class AutoDelete { public: explicit inline AutoDelete(KeyValues* pKeyValues) : m_pKeyValues(pKeyValues) {} explicit inline AutoDelete(const char* pchKVName) : m_pKeyValues(new KeyValues(pchKVName)) {} inline ~AutoDelete(void) { delete m_pKeyValues; } inline void Assign(KeyValues* pKeyValues) { m_pKeyValues = pKeyValues; } inline KeyValues* Detach() { KeyValues* retval = m_pKeyValues; Assign(NULL); return retval; } KeyValues* operator->() { return m_pKeyValues; } operator KeyValues* () { return m_pKeyValues; } private: AutoDelete(AutoDelete const& x); AutoDelete& operator= (AutoDelete const& x); protected: KeyValues* m_pKeyValues; }; class AutoDeleteInline : public AutoDelete { public: explicit inline AutoDeleteInline(KeyValues* pKeyValues) : AutoDelete(pKeyValues) {} inline operator KeyValues* () const { return m_pKeyValues; } inline KeyValues* Get() const { return m_pKeyValues; } }; KeyValues(const char* setName, const char* firstKey, const char* firstValue); KeyValues(const char* setName, const char* firstKey, const wchar_t* firstValue); KeyValues(const char* setName, const char* firstKey, int firstValue); KeyValues(const char* setName, const char* firstKey, const char* firstValue, const char* secondKey, const char* secondValue); KeyValues(const char* setName, const char* firstKey, int firstValue, const char* secondKey, int secondValue); ~KeyValues(); const char* GetName() const; void SetName(const char* setName); int GetNameSymbol() const; int GetNameSymbolCaseSensitive() const; void UsesEscapeSequences(bool state); bool LoadFromFile(IBaseFileSystem* filesystem, const char* resourceName, const char* pathID = NULL); bool SaveToFile(IBaseFileSystem* filesystem, const char* resourceName, const char* pathID = NULL, bool bWriteEmptySubkeys = false); bool LoadFromBuffer(char const* resourceName, const char* pBuffer, IBaseFileSystem* pFileSystem = NULL, const char* pPathID = NULL); bool LoadFromBuffer(char const* resourceName, CUtlBuffer& buf, IBaseFileSystem* pFileSystem = NULL, const char* pPathID = NULL); KeyValues* FindKey(const char* keyName, bool bCreate = false); KeyValues* FindKey(int keySymbol) const; KeyValues* CreateNewKey(); void AddSubKey(KeyValues* pSubkey); void RemoveSubKey(KeyValues* subKey); void InsertSubKey(int nIndex, KeyValues* pSubKey); bool ContainsSubKey(KeyValues* pSubKey); void SwapSubKey(KeyValues* pExistingSubKey, KeyValues* pNewSubKey); void ElideSubKey(KeyValues* pSubKey); KeyValues* CreateKey(const char* keyName); KeyValues* CreatePeerKey(const char* keyName); KeyValues* GetFirstSubKey() { return m_pSub; } KeyValues* GetNextKey() { return m_pPeer; } void SetNextKey(KeyValues* pDat); KeyValues* FindLastSubKey(); KeyValues* GetFirstTrueSubKey(); KeyValues* GetNextTrueSubKey(); KeyValues* GetFirstValue(); KeyValues* GetNextValue(); int GetInt(const char* keyName = NULL, int defaultValue = 0); uint64 GetUint64(const char* keyName = NULL, uint64 defaultValue = 0); float GetFloat(const char* keyName = NULL, float defaultValue = 0.0f); const char* GetString(const char* keyName = NULL, const char* defaultValue = ""); const wchar_t* GetWString(const char* keyName = NULL, const wchar_t* defaultValue = L""); void* GetPtr(const char* keyName = NULL, void* defaultValue = (void*)0); Color GetColor(const char* keyName = NULL, const Color& defaultColor = Color(0, 0, 0, 0)); bool GetBool(const char* keyName = NULL, bool defaultValue = false) { return GetInt(keyName, defaultValue ? 1 : 0) ? true : false; } bool IsEmpty(const char* keyName = NULL); int GetInt(int keySymbol, int defaultValue = 0); uint64 GetUint64(int keySymbol, uint64 defaultValue = 0); float GetFloat(int keySymbol, float defaultValue = 0.0f); const char* GetString(int keySymbol, const char* defaultValue = ""); const wchar_t* GetWString(int keySymbol, const wchar_t* defaultValue = L""); void* GetPtr(int keySymbol, void* defaultValue = (void*)0); Color GetColor(int keySymbol ); bool GetBool(int keySymbol, bool defaultValue = false) { return GetInt(keySymbol, defaultValue ? 1 : 0) ? true : false; } bool IsEmpty(int keySymbol); void SetWString(const char* keyName, const wchar_t* value); void SetString(const char* keyName, const char* value); void SetInt(const char* keyName, int value); void SetUint64(const char* keyName, uint64 value); void SetFloat(const char* keyName, float value); void SetPtr(const char* keyName, void* value); void SetColor(const char* keyName, Color value); void SetBool(const char* keyName, bool value) { SetInt(keyName, value ? 1 : 0); } void* operator new(size_t iAllocSize); void* operator new(size_t iAllocSize, int nBlockUse, const char* pFileName, int nLine); void operator delete(void* pMem); void operator delete(void* pMem, int nBlockUse, const char* pFileName, int nLine); KeyValues& operator=(KeyValues& src); bool IsEqual(KeyValues* pRHS); void ChainKeyValue(KeyValues* pChain); void RecursiveSaveToFile(CUtlBuffer& buf, int indentLevel); bool WriteAsBinary(CUtlBuffer& buffer) const; bool ReadAsBinary(CUtlBuffer& buffer, int nStackDepth = 0); bool WriteAsBinaryFiltered(CUtlBuffer& buffer); bool ReadAsBinaryFiltered(CUtlBuffer& buffer, int nStackDepth = 0); KeyValues* MakeCopy(void) const; void CopySubkeys(KeyValues* pParent) const; void Clear(void); enum types_t { TYPE_NONE = 0, TYPE_STRING, TYPE_INT, TYPE_FLOAT, TYPE_PTR, TYPE_WSTRING, TYPE_COLOR, TYPE_UINT64, TYPE_COMPILED_INT_BYTE, TYPE_COMPILED_INT_0, TYPE_COMPILED_INT_1, TYPE_NUMTYPES, }; types_t GetDataType(const char* keyName = NULL); types_t GetDataType() const; void deleteThis(); void SetStringValue(char const* strValue); void UnpackIntoStructure(struct KeyValuesUnpackStructure const* pUnpackTable, void* pDest); bool ProcessResolutionKeys(const char* pResString); bool Dump(IKeyValuesDumpContext* pDump, int nIndentLevel = 0); enum MergeKeyValuesOp_t { MERGE_KV_ALL, MERGE_KV_UPDATE, MERGE_KV_DELETE, MERGE_KV_BORROW, }; void MergeFrom(KeyValues* kvMerge, MergeKeyValuesOp_t eOp = MERGE_KV_ALL); static KeyValues* FromString(char const* szName, char const* szStringVal, char const** ppEndOfParse = NULL); KeyValues* CreateKeyUsingKnownLastChild(const char* keyName, KeyValues* pLastChild); void AddSubkeyUsingKnownLastChild(KeyValues* pSubKey, KeyValues* pLastChild); KeyValues(KeyValues&); void RecursiveCopyKeyValues(KeyValues& src); void RemoveEverything(); void RecursiveSaveToFile(IBaseFileSystem* filesystem, FileHandle_t f, CUtlBuffer* pBuf, int indentLevel, bool bWriteEmptySubkeys = false); void WriteConvertedString(IBaseFileSystem* filesystem, FileHandle_t f, CUtlBuffer* pBuf, const char* pszString); void RecursiveLoadFromBuffer(char const* resourceName, CUtlBuffer& buf); void AppendIncludedKeys(CUtlVector< KeyValues* >& includedKeys); void ParseIncludedKeys(char const* resourceName, const char* filetoinclude, IBaseFileSystem* pFileSystem, const char* pPathID, CUtlVector< KeyValues* >& includedKeys); void MergeBaseKeys(CUtlVector< KeyValues* >& baseKeys); void RecursiveMergeKeyValues(KeyValues* baseKV); void InternalWrite(IBaseFileSystem* filesystem, FileHandle_t f, CUtlBuffer* pBuf, const void* pData, int len); void Init(); const char* ReadToken(CUtlBuffer& buf, bool& wasQuoted, bool& wasConditional); void WriteIndents(IBaseFileSystem* filesystem, FileHandle_t f, CUtlBuffer* pBuf, int indentLevel); void FreeAllocatedValue(); void AllocateValueBlock(int size); bool ReadAsBinaryPooledFormat(CUtlBuffer& buf, IBaseFileSystem* pFileSystem, unsigned int poolKey, GetSymbolProc_t pfnEvaluateSymbolProc); bool EvaluateConditional(const char* str); uint32 m_iKeyName : 24; uint32 m_iKeyNameCaseSensitive1 : 8; char* m_sValue; wchar_t* m_wsValue; union { int m_iValue; float m_flValue; void* m_pValue; unsigned char m_Color[4]; }; char m_iDataType; char m_bHasEscapeSequences; uint16 m_iKeyNameCaseSensitive2; KeyValues* m_pPeer; KeyValues* m_pSub; KeyValues* m_pChain; GetSymbolProc_t m_pExpressionGetSymbolProc; private: static int (*s_pfGetSymbolForString)(const char* name, bool bCreate); static const char* (*s_pfGetStringForSymbol)(int symbol); static CKeyValuesGrowableStringTable* s_pGrowableStringTable; public: static int GetSymbolForStringClassic(const char* name, bool bCreate = true); static const char* GetStringForSymbolClassic(int symbol); static int GetSymbolForStringGrowable(const char* name, bool bCreate = true); static const char* GetStringForSymbolGrowable(int symbol); }; typedef KeyValues::AutoDelete KeyValuesAD; enum KeyValuesUnpackDestinationTypes_t { UNPACK_TYPE_FLOAT, UNPACK_TYPE_VECTOR, UNPACK_TYPE_VECTOR_COLOR, UNPACK_TYPE_STRING, UNPACK_TYPE_INT, UNPACK_TYPE_FOUR_FLOATS, UNPACK_TYPE_TWO_FLOATS, }; #define UNPACK_FIXED( kname, kdefault, dtype, ofs ) { kname, kdefault, dtype, ofs, 0 } #define UNPACK_VARIABLE( kname, kdefault, dtype, ofs, sz ) { kname, kdefault, dtype, ofs, sz } #define UNPACK_END_MARKER { NULL, NULL, UNPACK_TYPE_FLOAT, 0 } struct KeyValuesUnpackStructure { char const* m_pKeyName; char const* m_pKeyDefault; KeyValuesUnpackDestinationTypes_t m_eDataType; size_t m_nFieldOffset; size_t m_nFieldSize; }; inline int KeyValues::GetInt(int keySymbol, int defaultValue) { KeyValues* dat = FindKey(keySymbol); return dat ? dat->GetInt((const char*)NULL, defaultValue) : defaultValue; } inline uint64 KeyValues::GetUint64(int keySymbol, uint64 defaultValue) { KeyValues* dat = FindKey(keySymbol); return dat ? dat->GetUint64((const char*)NULL, defaultValue) : defaultValue; } inline float KeyValues::GetFloat(int keySymbol, float defaultValue) { KeyValues* dat = FindKey(keySymbol); return dat ? dat->GetFloat((const char*)NULL, defaultValue) : defaultValue; } inline const char* KeyValues::GetString(int keySymbol, const char* defaultValue) { KeyValues* dat = FindKey(keySymbol); return dat ? dat->GetString((const char*)NULL, defaultValue) : defaultValue; } inline const wchar_t* KeyValues::GetWString(int keySymbol, const wchar_t* defaultValue) { KeyValues* dat = FindKey(keySymbol); return dat ? dat->GetWString((const char*)NULL, defaultValue) : defaultValue; } inline void* KeyValues::GetPtr(int keySymbol, void* defaultValue) { KeyValues* dat = FindKey(keySymbol); return dat ? dat->GetPtr((const char*)NULL, defaultValue) : defaultValue; } inline Color KeyValues::GetColor(int keySymbol) { Color defaultValue(0, 0, 0, 0); KeyValues* dat = FindKey(keySymbol); return dat ? dat->GetColor() : defaultValue; } inline bool KeyValues::IsEmpty(int keySymbol) { KeyValues* dat = FindKey(keySymbol); return dat ? dat->IsEmpty() : true; } class IKeyValuesDumpContext { public: virtual bool KvBeginKey(KeyValues* pKey, int nIndentLevel) = 0; virtual bool KvWriteValue(KeyValues* pValue, int nIndentLevel) = 0; virtual bool KvEndKey(KeyValues* pKey, int nIndentLevel) = 0; }; class IKeyValuesDumpContextAsText : public IKeyValuesDumpContext { public: virtual bool KvBeginKey(KeyValues* pKey, int nIndentLevel); virtual bool KvWriteValue(KeyValues* pValue, int nIndentLevel); virtual bool KvEndKey(KeyValues* pKey, int nIndentLevel); public: virtual bool KvWriteIndent(int nIndentLevel); virtual bool KvWriteText(char const* szText) = 0; }; class CKeyValuesDumpContextAsDevMsg : public IKeyValuesDumpContextAsText { public: CKeyValuesDumpContextAsDevMsg(int nDeveloperLevel = 1) : m_nDeveloperLevel(nDeveloperLevel) {} public: virtual bool KvBeginKey(KeyValues* pKey, int nIndentLevel); virtual bool KvWriteText(char const* szText); protected: int m_nDeveloperLevel; }; inline bool KeyValuesDumpAsDevMsg(KeyValues* pKeyValues, int nIndentLevel = 0, int nDeveloperLevel = 1) { CKeyValuesDumpContextAsDevMsg ctx(nDeveloperLevel); return pKeyValues->Dump(&ctx, nIndentLevel); } #endif