Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

486 lines
20 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #ifndef KEYVALUES_H
  8. #define KEYVALUES_H
  9. #ifdef _WIN32
  10. #pragma once
  11. #endif
  12. // #include <vgui/VGUI.h>
  13. #ifndef NULL
  14. #ifdef __cplusplus
  15. #define NULL 0
  16. #else
  17. #define NULL ((void *)0)
  18. #endif
  19. #endif
  20. #include "utlvector.h"
  21. #include "Color.h"
  22. #define FOR_EACH_SUBKEY( kvRoot, kvSubKey ) \
  23. for ( KeyValues * kvSubKey = kvRoot->GetFirstSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextKey() )
  24. #define FOR_EACH_TRUE_SUBKEY( kvRoot, kvSubKey ) \
  25. for ( KeyValues * kvSubKey = kvRoot->GetFirstTrueSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextTrueSubKey() )
  26. #define FOR_EACH_VALUE( kvRoot, kvValue ) \
  27. for ( KeyValues * kvValue = kvRoot->GetFirstValue(); kvValue != NULL; kvValue = kvValue->GetNextValue() )
  28. class IBaseFileSystem;
  29. class CUtlBuffer;
  30. class Color;
  31. typedef void * FileHandle_t;
  32. class CKeyValuesGrowableStringTable;
  33. //-----------------------------------------------------------------------------
  34. // Purpose: Simple recursive data access class
  35. // Used in vgui for message parameters and resource files
  36. // Destructor deletes all child KeyValues nodes
  37. // Data is stored in key (string names) - (string/int/float)value pairs called nodes.
  38. //
  39. // About KeyValues Text File Format:
  40. // It has 3 control characters '{', '}' and '"'. Names and values may be quoted or
  41. // not. The quote '"' character must not be used within name or values, only for
  42. // quoting whole tokens. You may use escape sequences wile parsing and add within a
  43. // quoted token a \" to add quotes within your name or token. When using Escape
  44. // Sequence the parser must now that by setting KeyValues::UsesEscapeSequences( true ),
  45. // which it's off by default. Non-quoted tokens ends with a whitespace, '{', '}' and '"'.
  46. // So you may use '{' and '}' within quoted tokens, but not for non-quoted tokens.
  47. // An open bracket '{' after a key name indicates a list of subkeys which is finished
  48. // with a closing bracket '}'. Subkeys use the same definitions recursively.
  49. // Whitespaces are space, return, newline and tabulator. Allowed Escape sequences
  50. // are \n, \t, \\, \n and \". The number character '#' is used for macro purposes
  51. // (eg #include), don't use it as first character in key names.
  52. //-----------------------------------------------------------------------------
  53. class KeyValues
  54. {
  55. public:
  56. // By default, the KeyValues class uses a string table for the key names that is
  57. // limited to 4MB. The game will exit in error if this space is exhausted. In
  58. // general this is preferable for game code for performance and memory fragmentation
  59. // reasons.
  60. //
  61. // If this is not acceptable, you can use this call to switch to a table that can grow
  62. // arbitrarily. This call must be made before any KeyValues objects are allocated or it
  63. // will result in undefined behavior. If you use the growable string table, you cannot
  64. // share KeyValues pointers directly with any other module. You can serialize them across
  65. // module boundaries. These limitations are acceptable in the Steam backend code
  66. // this option was written for, but may not be in other situations. Make sure to
  67. // understand the implications before using this.
  68. static void SetUseGrowableStringTable( bool bUseGrowableTable );
  69. KeyValues( const char *setName );
  70. //
  71. // AutoDelete class to automatically free the keyvalues.
  72. // Simply construct it with the keyvalues you allocated and it will free them when falls out of scope.
  73. // When you decide that keyvalues shouldn't be deleted call Assign(NULL) on it.
  74. // If you constructed AutoDelete(NULL) you can later assign the keyvalues to be deleted with Assign(pKeyValues).
  75. // You can also pass temporary KeyValues object as an argument to a function by wrapping it into KeyValues::AutoDelete
  76. // instance: call_my_function( KeyValues::AutoDelete( new KeyValues( "test" ) ) )
  77. //
  78. class AutoDelete
  79. {
  80. public:
  81. explicit inline AutoDelete( KeyValues *pKeyValues ) : m_pKeyValues( pKeyValues ) {}
  82. explicit inline AutoDelete( const char *pchKVName ) : m_pKeyValues( new KeyValues( pchKVName ) ) {}
  83. inline ~AutoDelete( void ) { if( m_pKeyValues ) m_pKeyValues->deleteThis(); }
  84. inline void Assign( KeyValues *pKeyValues ) { m_pKeyValues = pKeyValues; }
  85. KeyValues *operator->() { return m_pKeyValues; }
  86. operator KeyValues *() { return m_pKeyValues; }
  87. private:
  88. AutoDelete( AutoDelete const &x ); // forbid
  89. AutoDelete & operator= ( AutoDelete const &x ); // forbid
  90. KeyValues *m_pKeyValues;
  91. };
  92. // Quick setup constructors
  93. KeyValues( const char *setName, const char *firstKey, const char *firstValue );
  94. KeyValues( const char *setName, const char *firstKey, const wchar_t *firstValue );
  95. KeyValues( const char *setName, const char *firstKey, int firstValue );
  96. KeyValues( const char *setName, const char *firstKey, const char *firstValue, const char *secondKey, const char *secondValue );
  97. KeyValues( const char *setName, const char *firstKey, int firstValue, const char *secondKey, int secondValue );
  98. // Section name
  99. const char *GetName() const;
  100. void SetName( const char *setName);
  101. // gets the name as a unique int
  102. int GetNameSymbol() const { return m_iKeyName; }
  103. // File access. Set UsesEscapeSequences true, if resource file/buffer uses Escape Sequences (eg \n, \t)
  104. void UsesEscapeSequences(bool state); // default false
  105. void UsesConditionals(bool state); // default true
  106. bool LoadFromFile( IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL, bool refreshCache = false );
  107. bool SaveToFile( IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL, bool sortKeys = false, bool bAllowEmptyString = false, bool bCacheResult = false );
  108. // Read from a buffer... Note that the buffer must be null terminated
  109. bool LoadFromBuffer( char const *resourceName, const char *pBuffer, IBaseFileSystem* pFileSystem = NULL, const char *pPathID = NULL );
  110. // Read from a utlbuffer...
  111. bool LoadFromBuffer( char const *resourceName, CUtlBuffer &buf, IBaseFileSystem* pFileSystem = NULL, const char *pPathID = NULL );
  112. // Find a keyValue, create it if it is not found.
  113. // Set bCreate to true to create the key if it doesn't already exist (which ensures a valid pointer will be returned)
  114. KeyValues *FindKey(const char *keyName, bool bCreate = false);
  115. KeyValues *FindKey(int keySymbol) const;
  116. KeyValues *CreateNewKey(); // creates a new key, with an autogenerated name. name is guaranteed to be an integer, of value 1 higher than the highest other integer key name
  117. void AddSubKey( KeyValues *pSubkey ); // Adds a subkey. Make sure the subkey isn't a child of some other keyvalues
  118. void RemoveSubKey(KeyValues *subKey); // removes a subkey from the list, DOES NOT DELETE IT
  119. // Key iteration.
  120. //
  121. // NOTE: GetFirstSubKey/GetNextKey will iterate keys AND values. Use the functions
  122. // below if you want to iterate over just the keys or just the values.
  123. //
  124. KeyValues *GetFirstSubKey() { return m_pSub; } // returns the first subkey in the list
  125. KeyValues *GetNextKey() { return m_pPeer; } // returns the next subkey
  126. const KeyValues *GetNextKey() const { return m_pPeer; } // returns the next subkey
  127. void SetNextKey( KeyValues * pDat);
  128. KeyValues *FindLastSubKey(); // returns the LAST subkey in the list. This requires a linked list iteration to find the key. Returns NULL if we don't have any children
  129. //
  130. // These functions can be used to treat it like a true key/values tree instead of
  131. // confusing values with keys.
  132. //
  133. // So if you wanted to iterate all subkeys, then all values, it would look like this:
  134. // for ( KeyValues *pKey = pRoot->GetFirstTrueSubKey(); pKey; pKey = pKey->GetNextTrueSubKey() )
  135. // {
  136. // Msg( "Key name: %s\n", pKey->GetName() );
  137. // }
  138. // for ( KeyValues *pValue = pRoot->GetFirstValue(); pKey; pKey = pKey->GetNextValue() )
  139. // {
  140. // Msg( "Int value: %d\n", pValue->GetInt() ); // Assuming pValue->GetDataType() == TYPE_INT...
  141. // }
  142. KeyValues* GetFirstTrueSubKey();
  143. KeyValues* GetNextTrueSubKey();
  144. KeyValues* GetFirstValue(); // When you get a value back, you can use GetX and pass in NULL to get the value.
  145. KeyValues* GetNextValue();
  146. // Data access
  147. int GetInt( const char *keyName = NULL, int defaultValue = 0 );
  148. uint64 GetUint64( const char *keyName = NULL, uint64 defaultValue = 0 );
  149. float GetFloat( const char *keyName = NULL, float defaultValue = 0.0f );
  150. const char *GetString( const char *keyName = NULL, const char *defaultValue = "" );
  151. const wchar_t *GetWString( const char *keyName = NULL, const wchar_t *defaultValue = L"" );
  152. void *GetPtr( const char *keyName = NULL, void *defaultValue = (void*)0 );
  153. bool GetBool( const char *keyName = NULL, bool defaultValue = false, bool* optGotDefault = NULL );
  154. Color GetColor( const char *keyName = NULL /* default value is all black */);
  155. bool IsEmpty(const char *keyName = NULL);
  156. // Data access
  157. int GetInt( int keySymbol, int defaultValue = 0 );
  158. float GetFloat( int keySymbol, float defaultValue = 0.0f );
  159. const char *GetString( int keySymbol, const char *defaultValue = "" );
  160. const wchar_t *GetWString( int keySymbol, const wchar_t *defaultValue = L"" );
  161. void *GetPtr( int keySymbol, void *defaultValue = (void*)0 );
  162. Color GetColor( int keySymbol /* default value is all black */);
  163. bool IsEmpty( int keySymbol );
  164. // Key writing
  165. void SetWString( const char *keyName, const wchar_t *value );
  166. void SetString( const char *keyName, const char *value );
  167. void SetInt( const char *keyName, int value );
  168. void SetUint64( const char *keyName, uint64 value );
  169. void SetFloat( const char *keyName, float value );
  170. void SetPtr( const char *keyName, void *value );
  171. void SetColor( const char *keyName, Color value);
  172. void SetBool( const char *keyName, bool value ) { SetInt( keyName, value ? 1 : 0 ); }
  173. // Memory allocation (optimized)
  174. void *operator new( size_t iAllocSize );
  175. void *operator new( size_t iAllocSize, int nBlockUse, const char *pFileName, int nLine );
  176. void operator delete( void *pMem );
  177. void operator delete( void *pMem, int nBlockUse, const char *pFileName, int nLine );
  178. KeyValues& operator=( const KeyValues& src );
  179. // Adds a chain... if we don't find stuff in this keyvalue, we'll look
  180. // in the one we're chained to.
  181. void ChainKeyValue( KeyValues* pChain );
  182. void RecursiveSaveToFile( CUtlBuffer& buf, int indentLevel, bool sortKeys = false, bool bAllowEmptyString = false );
  183. bool WriteAsBinary( CUtlBuffer &buffer );
  184. bool ReadAsBinary( CUtlBuffer &buffer, int nStackDepth = 0 );
  185. // Allocate & create a new copy of the keys
  186. KeyValues *MakeCopy( void ) const;
  187. // Allocate & create a new copy of the keys, including the next keys. This is useful for top level files
  188. // that don't use the usual convention of a root key with lots of children (like soundscape files).
  189. KeyValues *MakeCopy( bool copySiblings ) const;
  190. // Make a new copy of all subkeys, add them all to the passed-in keyvalues
  191. void CopySubkeys( KeyValues *pParent ) const;
  192. // Clear out all subkeys, and the current value
  193. void Clear( void );
  194. // Data type
  195. enum types_t
  196. {
  197. TYPE_NONE = 0,
  198. TYPE_STRING,
  199. TYPE_INT,
  200. TYPE_FLOAT,
  201. TYPE_PTR,
  202. TYPE_WSTRING,
  203. TYPE_COLOR,
  204. TYPE_UINT64,
  205. TYPE_NUMTYPES,
  206. };
  207. types_t GetDataType(const char *keyName = NULL);
  208. // Virtual deletion function - ensures that KeyValues object is deleted from correct heap
  209. void deleteThis();
  210. void SetStringValue( char const *strValue );
  211. // unpack a key values list into a structure
  212. void UnpackIntoStructure( struct KeyValuesUnpackStructure const *pUnpackTable, void *pDest, size_t DestSizeInBytes );
  213. // Process conditional keys for widescreen support.
  214. bool ProcessResolutionKeys( const char *pResString );
  215. // Dump keyvalues recursively into a dump context
  216. bool Dump( class IKeyValuesDumpContext *pDump, int nIndentLevel = 0, bool bSorted = false );
  217. // Merge in another KeyValues, keeping "our" settings
  218. void RecursiveMergeKeyValues( KeyValues *baseKV );
  219. void AddSubkeyUsingKnownLastChild( KeyValues *pSubKey, KeyValues *pLastChild );
  220. private:
  221. KeyValues( KeyValues& ); // prevent copy constructor being used
  222. // prevent delete being called except through deleteThis()
  223. ~KeyValues();
  224. KeyValues* CreateKey( const char *keyName );
  225. /// Create a child key, given that we know which child is currently the last child.
  226. /// This avoids the O(N^2) behaviour when adding children in sequence to KV,
  227. /// when CreateKey() wil have to re-locate the end of the list each time. This happens,
  228. /// for example, every time we load any KV file whatsoever.
  229. KeyValues* CreateKeyUsingKnownLastChild( const char *keyName, KeyValues *pLastChild );
  230. void CopyKeyValuesFromRecursive( const KeyValues& src );
  231. void CopyKeyValue( const KeyValues& src, size_t tmpBufferSizeB, char* tmpBuffer );
  232. void RemoveEverything();
  233. // void RecursiveSaveToFile( IBaseFileSystem *filesystem, CUtlBuffer &buffer, int indentLevel );
  234. // void WriteConvertedString( CUtlBuffer &buffer, const char *pszString );
  235. // NOTE: If both filesystem and pBuf are non-null, it'll save to both of them.
  236. // If filesystem is null, it'll ignore f.
  237. void RecursiveSaveToFile( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel, bool sortKeys, bool bAllowEmptyString );
  238. void SaveKeyToFile( KeyValues *dat, IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel, bool sortKeys, bool bAllowEmptyString );
  239. void WriteConvertedString( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, const char *pszString );
  240. void RecursiveLoadFromBuffer( char const *resourceName, CUtlBuffer &buf );
  241. // For handling #include "filename"
  242. void AppendIncludedKeys( CUtlVector< KeyValues * >& includedKeys );
  243. void ParseIncludedKeys( char const *resourceName, const char *filetoinclude,
  244. IBaseFileSystem* pFileSystem, const char *pPathID, CUtlVector< KeyValues * >& includedKeys );
  245. // For handling #base "filename"
  246. void MergeBaseKeys( CUtlVector< KeyValues * >& baseKeys );
  247. // NOTE: If both filesystem and pBuf are non-null, it'll save to both of them.
  248. // If filesystem is null, it'll ignore f.
  249. void InternalWrite( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, const void *pData, int len );
  250. void Init();
  251. const char * ReadToken( CUtlBuffer &buf, bool &wasQuoted, bool &wasConditional );
  252. void WriteIndents( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel );
  253. void FreeAllocatedValue();
  254. void AllocateValueBlock(int size);
  255. int m_iKeyName; // keyname is a symbol defined in KeyValuesSystem
  256. // These are needed out of the union because the API returns string pointers
  257. char *m_sValue;
  258. wchar_t *m_wsValue;
  259. // we don't delete these
  260. union
  261. {
  262. int m_iValue;
  263. float m_flValue;
  264. void *m_pValue;
  265. unsigned char m_Color[4];
  266. };
  267. char m_iDataType;
  268. char m_bHasEscapeSequences; // true, if while parsing this KeyValue, Escape Sequences are used (default false)
  269. char m_bEvaluateConditionals; // true, if while parsing this KeyValue, conditionals blocks are evaluated (default true)
  270. char unused[1];
  271. KeyValues *m_pPeer; // pointer to next key in list
  272. KeyValues *m_pSub; // pointer to Start of a new sub key list
  273. KeyValues *m_pChain;// Search here if it's not in our list
  274. private:
  275. // Statics to implement the optional growable string table
  276. // Function pointers that will determine which mode we are in
  277. static int (*s_pfGetSymbolForString)( const char *name, bool bCreate );
  278. static const char *(*s_pfGetStringForSymbol)( int symbol );
  279. static CKeyValuesGrowableStringTable *s_pGrowableStringTable;
  280. public:
  281. // Functions that invoke the default behavior
  282. static int GetSymbolForStringClassic( const char *name, bool bCreate = true );
  283. static const char *GetStringForSymbolClassic( int symbol );
  284. // Functions that use the growable string table
  285. static int GetSymbolForStringGrowable( const char *name, bool bCreate = true );
  286. static const char *GetStringForSymbolGrowable( int symbol );
  287. // Functions to get external access to whichever of the above functions we're going to call.
  288. static int CallGetSymbolForString( const char *name, bool bCreate = true ) { return s_pfGetSymbolForString( name, bCreate ); }
  289. static const char *CallGetStringForSymbol( int symbol ) { return s_pfGetStringForSymbol( symbol ); }
  290. };
  291. typedef KeyValues::AutoDelete KeyValuesAD;
  292. enum KeyValuesUnpackDestinationTypes_t
  293. {
  294. UNPACK_TYPE_FLOAT, // dest is a float
  295. UNPACK_TYPE_VECTOR, // dest is a Vector
  296. UNPACK_TYPE_VECTOR_COLOR, // dest is a vector, src is a color
  297. UNPACK_TYPE_STRING, // dest is a char *. unpacker will allocate.
  298. UNPACK_TYPE_INT, // dest is an int
  299. UNPACK_TYPE_FOUR_FLOATS, // dest is an array of 4 floats. source is a string like "1 2 3 4"
  300. UNPACK_TYPE_TWO_FLOATS, // dest is an array of 2 floats. source is a string like "1 2"
  301. };
  302. #define UNPACK_FIXED( kname, kdefault, dtype, ofs ) { kname, kdefault, dtype, ofs, 0 }
  303. #define UNPACK_VARIABLE( kname, kdefault, dtype, ofs, sz ) { kname, kdefault, dtype, ofs, sz }
  304. #define UNPACK_END_MARKER { NULL, NULL, UNPACK_TYPE_FLOAT, 0 }
  305. struct KeyValuesUnpackStructure
  306. {
  307. char const *m_pKeyName; // null to terminate tbl
  308. char const *m_pKeyDefault; // null ok
  309. KeyValuesUnpackDestinationTypes_t m_eDataType; // UNPACK_TYPE_INT, ..
  310. size_t m_nFieldOffset; // use offsetof to set
  311. size_t m_nFieldSize; // for strings or other variable length
  312. };
  313. //-----------------------------------------------------------------------------
  314. // inline methods
  315. //-----------------------------------------------------------------------------
  316. inline int KeyValues::GetInt( int keySymbol, int defaultValue )
  317. {
  318. KeyValues *dat = FindKey( keySymbol );
  319. return dat ? dat->GetInt( (const char *)NULL, defaultValue ) : defaultValue;
  320. }
  321. inline float KeyValues::GetFloat( int keySymbol, float defaultValue )
  322. {
  323. KeyValues *dat = FindKey( keySymbol );
  324. return dat ? dat->GetFloat( (const char *)NULL, defaultValue ) : defaultValue;
  325. }
  326. inline const char *KeyValues::GetString( int keySymbol, const char *defaultValue )
  327. {
  328. KeyValues *dat = FindKey( keySymbol );
  329. return dat ? dat->GetString( (const char *)NULL, defaultValue ) : defaultValue;
  330. }
  331. inline const wchar_t *KeyValues::GetWString( int keySymbol, const wchar_t *defaultValue )
  332. {
  333. KeyValues *dat = FindKey( keySymbol );
  334. return dat ? dat->GetWString( (const char *)NULL, defaultValue ) : defaultValue;
  335. }
  336. inline void *KeyValues::GetPtr( int keySymbol, void *defaultValue )
  337. {
  338. KeyValues *dat = FindKey( keySymbol );
  339. return dat ? dat->GetPtr( (const char *)NULL, defaultValue ) : defaultValue;
  340. }
  341. inline Color KeyValues::GetColor( int keySymbol )
  342. {
  343. Color defaultValue( 0, 0, 0, 0 );
  344. KeyValues *dat = FindKey( keySymbol );
  345. return dat ? dat->GetColor( ) : defaultValue;
  346. }
  347. inline bool KeyValues::IsEmpty( int keySymbol )
  348. {
  349. KeyValues *dat = FindKey( keySymbol );
  350. return dat ? dat->IsEmpty( ) : true;
  351. }
  352. bool EvaluateConditional( const char *str );
  353. class CUtlSortVectorKeyValuesByName
  354. {
  355. public:
  356. bool Less( const KeyValues* lhs, const KeyValues* rhs, void * )
  357. {
  358. return Q_stricmp( lhs->GetName(), rhs->GetName() ) < 0;
  359. }
  360. };
  361. //
  362. // KeyValuesDumpContext and generic implementations
  363. //
  364. class IKeyValuesDumpContext
  365. {
  366. public:
  367. virtual bool KvBeginKey( KeyValues *pKey, int nIndentLevel ) = 0;
  368. virtual bool KvWriteValue( KeyValues *pValue, int nIndentLevel ) = 0;
  369. virtual bool KvEndKey( KeyValues *pKey, int nIndentLevel ) = 0;
  370. };
  371. class IKeyValuesDumpContextAsText : public IKeyValuesDumpContext
  372. {
  373. public:
  374. virtual bool KvBeginKey( KeyValues *pKey, int nIndentLevel );
  375. virtual bool KvWriteValue( KeyValues *pValue, int nIndentLevel );
  376. virtual bool KvEndKey( KeyValues *pKey, int nIndentLevel );
  377. public:
  378. virtual bool KvWriteIndent( int nIndentLevel );
  379. virtual bool KvWriteText( char const *szText ) = 0;
  380. };
  381. class CKeyValuesDumpContextAsDevMsg : public IKeyValuesDumpContextAsText
  382. {
  383. public:
  384. // Overrides developer level to dump in DevMsg, zero to dump as Msg
  385. CKeyValuesDumpContextAsDevMsg( int nDeveloperLevel = 1 ) : m_nDeveloperLevel( nDeveloperLevel ) {}
  386. public:
  387. virtual bool KvBeginKey( KeyValues *pKey, int nIndentLevel );
  388. virtual bool KvWriteText( char const *szText );
  389. protected:
  390. int m_nDeveloperLevel;
  391. };
  392. inline bool KeyValuesDumpAsDevMsg( KeyValues *pKeyValues, int nIndentLevel = 0, int nDeveloperLevel = 1 )
  393. {
  394. CKeyValuesDumpContextAsDevMsg ctx( nDeveloperLevel );
  395. return pKeyValues->Dump( &ctx, nIndentLevel );
  396. }
  397. #endif // KEYVALUES_H