Counter Strike : Global Offensive Source Code
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.

3986 lines
100 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #if defined( _WIN32 ) && !defined( _X360 )
  9. #include <windows.h> // for widechartomultibyte and multibytetowidechar
  10. #elif defined(POSIX)
  11. #include <wchar.h> // wcslen()
  12. #define _alloca alloca
  13. #define _wtoi(arg) wcstol(arg, NULL, 10)
  14. #define _wtoi64(arg) wcstoll(arg, NULL, 10)
  15. #endif
  16. #include <keyvalues.h>
  17. #include "filesystem.h"
  18. #include <vstdlib/ikeyvaluessystem.h>
  19. #include <color.h>
  20. #include <stdlib.h>
  21. #include <ctype.h>
  22. #include "tier1/convar.h"
  23. #include "tier0/dbg.h"
  24. #include "tier0/mem.h"
  25. #include "utlvector.h"
  26. #include "utlbuffer.h"
  27. #include "utlhash.h"
  28. #include "tier0/vprof.h"
  29. // memdbgon must be the last include file in a .cpp file!!!
  30. #include <tier0/memdbgon.h>
  31. //////// VPROF? //////////////////
  32. // For an example of how to mark up this file with VPROF nodes, see
  33. // changelist 702984. However, be aware that calls to FindKey and Init
  34. // may occur outside of Vprof's usual hierarchy, which can cause strange
  35. // duplicate KeyValues::FindKey nodes at the root level and other
  36. // confusing effects.
  37. //////////////////////////////////
  38. static char * s_LastFileLoadingFrom = "unknown"; // just needed for error messages
  39. // Statics for the growable string table
  40. int (*KeyValues::s_pfGetSymbolForString)( const char *name, bool bCreate ) = &KeyValues::GetSymbolForStringClassic;
  41. const char *(*KeyValues::s_pfGetStringForSymbol)( int symbol ) = &KeyValues::GetStringForSymbolClassic;
  42. CKeyValuesGrowableStringTable *KeyValues::s_pGrowableStringTable = NULL;
  43. #define KEYVALUES_TOKEN_SIZE (1024 * 32)
  44. #define INTERNALWRITE( pData, len ) InternalWrite( filesystem, f, pBuf, pData, len )
  45. #define MAKE_3_BYTES_FROM_1_AND_2( x1, x2 ) (( (( uint16 )x2) << 8 ) | (uint8)(x1))
  46. #define SPLIT_3_BYTES_INTO_1_AND_2( x1, x2, x3 ) do { x1 = (uint8)(x3); x2 = (uint16)( (x3) >> 8 ); } while( 0 )
  47. CExpressionEvaluator g_ExpressionEvaluator;
  48. // a simple class to keep track of a stack of valid parsed symbols
  49. const int MAX_ERROR_STACK = 64;
  50. class CKeyValuesErrorStack
  51. {
  52. public:
  53. CKeyValuesErrorStack() : m_pFilename("NULL"), m_errorIndex(0), m_maxErrorIndex(0), m_bEncounteredErrors(false) {}
  54. void SetFilename( const char *pFilename )
  55. {
  56. m_pFilename = pFilename;
  57. m_maxErrorIndex = 0;
  58. }
  59. // entering a new keyvalues block, save state for errors
  60. // Not save symbols instead of pointers because the pointers can move!
  61. int Push( int symName )
  62. {
  63. if ( m_errorIndex < MAX_ERROR_STACK )
  64. {
  65. m_errorStack[m_errorIndex] = symName;
  66. }
  67. m_errorIndex++;
  68. m_maxErrorIndex = MAX( m_maxErrorIndex, (m_errorIndex-1) );
  69. return m_errorIndex-1;
  70. }
  71. // exiting block, error isn't in this block, remove.
  72. void Pop()
  73. {
  74. m_errorIndex--;
  75. Assert(m_errorIndex>=0);
  76. }
  77. // Allows you to keep the same stack level, but change the name as you parse peers
  78. void Reset( int stackLevel, int symName )
  79. {
  80. Assert( stackLevel >= 0 && stackLevel < m_errorIndex );
  81. if ( stackLevel < MAX_ERROR_STACK )
  82. m_errorStack[stackLevel] = symName;
  83. }
  84. // Hit an error, report it and the parsing stack for context
  85. void ReportError( const char *pError )
  86. {
  87. Warning( "KeyValues Error: %s in file %s\n", pError, m_pFilename );
  88. for ( int i = 0; i < m_maxErrorIndex; i++ )
  89. {
  90. if ( i < MAX_ERROR_STACK && m_errorStack[i] != INVALID_KEY_SYMBOL )
  91. {
  92. if ( i < m_errorIndex )
  93. {
  94. Warning( "%s, ", KeyValuesSystem()->GetStringForSymbol(m_errorStack[i]) );
  95. }
  96. else
  97. {
  98. Warning( "(*%s*), ", KeyValuesSystem()->GetStringForSymbol(m_errorStack[i]) );
  99. }
  100. }
  101. }
  102. Warning( "\n" );
  103. m_bEncounteredErrors = true;
  104. }
  105. bool EncounteredAnyErrors()
  106. {
  107. return m_bEncounteredErrors;
  108. }
  109. void ClearErrorFlag()
  110. {
  111. m_bEncounteredErrors = false;
  112. }
  113. private:
  114. int m_errorStack[MAX_ERROR_STACK];
  115. const char *m_pFilename;
  116. int m_errorIndex;
  117. int m_maxErrorIndex;
  118. bool m_bEncounteredErrors;
  119. } g_KeyValuesErrorStack;
  120. // This class gets the tokens out of a CUtlBuffer for KeyValues.
  121. // Since KeyValues likes to seek backwards and seeking won't work with a text-mode CUtlStreamBuffer
  122. // (which is what dmserializers uses), this class allows you to seek back one token.
  123. class CKeyValuesTokenReader
  124. {
  125. public:
  126. CKeyValuesTokenReader( KeyValues *pKeyValues, CUtlBuffer &buf );
  127. const char* ReadToken( bool &wasQuoted, bool &wasConditional );
  128. void SeekBackOneToken();
  129. private:
  130. KeyValues *m_pKeyValues;
  131. CUtlBuffer &m_Buffer;
  132. int m_nTokensRead;
  133. bool m_bUsePriorToken;
  134. bool m_bPriorTokenWasQuoted;
  135. bool m_bPriorTokenWasConditional;
  136. static char s_pTokenBuf[KEYVALUES_TOKEN_SIZE];
  137. };
  138. char CKeyValuesTokenReader::s_pTokenBuf[KEYVALUES_TOKEN_SIZE];
  139. CKeyValuesTokenReader::CKeyValuesTokenReader( KeyValues *pKeyValues, CUtlBuffer &buf ) :
  140. m_Buffer( buf )
  141. {
  142. m_pKeyValues = pKeyValues;
  143. m_nTokensRead = 0;
  144. m_bUsePriorToken = false;
  145. }
  146. const char* CKeyValuesTokenReader::ReadToken( bool &wasQuoted, bool &wasConditional )
  147. {
  148. if ( m_bUsePriorToken )
  149. {
  150. m_bUsePriorToken = false;
  151. wasQuoted = m_bPriorTokenWasQuoted;
  152. wasConditional = m_bPriorTokenWasConditional;
  153. return s_pTokenBuf;
  154. }
  155. m_bPriorTokenWasQuoted = wasQuoted = false;
  156. m_bPriorTokenWasConditional = wasConditional = false;
  157. if ( !m_Buffer.IsValid() )
  158. return NULL;
  159. // eating white spaces and remarks loop
  160. while ( true )
  161. {
  162. m_Buffer.EatWhiteSpace();
  163. if ( !m_Buffer.IsValid() )
  164. {
  165. return NULL; // file ends after reading whitespaces
  166. }
  167. // stop if it's not a comment; a new token starts here
  168. if ( !m_Buffer.EatCPPComment() )
  169. break;
  170. }
  171. const char *c = (const char*)m_Buffer.PeekGet( sizeof(char), 0 );
  172. if ( !c )
  173. {
  174. return NULL;
  175. }
  176. // read quoted strings specially
  177. if ( *c == '\"' )
  178. {
  179. m_bPriorTokenWasQuoted = wasQuoted = true;
  180. m_Buffer.GetDelimitedString( m_pKeyValues->m_bHasEscapeSequences ? GetCStringCharConversion() : GetNoEscCharConversion(),
  181. s_pTokenBuf, KEYVALUES_TOKEN_SIZE );
  182. ++m_nTokensRead;
  183. return s_pTokenBuf;
  184. }
  185. if ( *c == '{' || *c == '}' || *c == '=' )
  186. {
  187. // it's a control char, just add this one char and stop reading
  188. s_pTokenBuf[0] = *c;
  189. s_pTokenBuf[1] = 0;
  190. m_Buffer.GetChar();
  191. ++m_nTokensRead;
  192. return s_pTokenBuf;
  193. }
  194. // read in the token until we hit a whitespace or a control character
  195. bool bReportedError = false;
  196. bool bConditionalStart = false;
  197. int nCount = 0;
  198. while ( 1 )
  199. {
  200. c = (const char*)m_Buffer.PeekGet( sizeof(char), 0 );
  201. // end of file
  202. if ( !c || *c == 0 )
  203. break;
  204. // break if any control character appears in non quoted tokens
  205. if ( *c == '"' || *c == '{' || *c == '}' || *c == '=' )
  206. break;
  207. if ( *c == '[' )
  208. bConditionalStart = true;
  209. if ( *c == ']' && bConditionalStart )
  210. {
  211. m_bPriorTokenWasConditional = wasConditional = true;
  212. bConditionalStart = false;
  213. }
  214. // break on whitespace
  215. if ( V_isspace(*c) && !bConditionalStart )
  216. break;
  217. if (nCount < (KEYVALUES_TOKEN_SIZE-1) )
  218. {
  219. s_pTokenBuf[nCount++] = *c; // add char to buffer
  220. }
  221. else if ( !bReportedError )
  222. {
  223. bReportedError = true;
  224. g_KeyValuesErrorStack.ReportError(" ReadToken overflow" );
  225. }
  226. m_Buffer.GetChar();
  227. }
  228. s_pTokenBuf[ nCount ] = 0;
  229. ++m_nTokensRead;
  230. return s_pTokenBuf;
  231. }
  232. void CKeyValuesTokenReader::SeekBackOneToken()
  233. {
  234. if ( m_bUsePriorToken )
  235. Plat_FatalError( "CKeyValuesTokenReader::SeekBackOneToken: It is only possible to seek back one token at a time" );
  236. if ( m_nTokensRead == 0 )
  237. Plat_FatalError( "CkeyValuesTokenReader::SeekBackOneToken: No tokens read yet" );
  238. m_bUsePriorToken = true;
  239. }
  240. // a simple helper that creates stack entries as it goes in & out of scope
  241. class CKeyErrorContext
  242. {
  243. public:
  244. ~CKeyErrorContext()
  245. {
  246. g_KeyValuesErrorStack.Pop();
  247. }
  248. explicit CKeyErrorContext( int symName )
  249. {
  250. Init( symName );
  251. }
  252. void Reset( int symName )
  253. {
  254. g_KeyValuesErrorStack.Reset( m_stackLevel, symName );
  255. }
  256. int GetStackLevel() const
  257. {
  258. return m_stackLevel;
  259. }
  260. private:
  261. void Init( int symName )
  262. {
  263. m_stackLevel = g_KeyValuesErrorStack.Push( symName );
  264. }
  265. int m_stackLevel;
  266. };
  267. // Uncomment this line to hit the ~CLeakTrack assert to see what's looking like it's leaking
  268. // #define LEAKTRACK
  269. #ifdef LEAKTRACK
  270. class CLeakTrack
  271. {
  272. public:
  273. CLeakTrack()
  274. {
  275. }
  276. ~CLeakTrack()
  277. {
  278. if ( keys.Count() != 0 )
  279. {
  280. Assert( 0 );
  281. }
  282. }
  283. struct kve
  284. {
  285. KeyValues *kv;
  286. char name[ 256 ];
  287. };
  288. void AddKv( KeyValues *kv, char const *name )
  289. {
  290. kve k;
  291. V_strncpy( k.name, name ? name : "NULL", sizeof( k.name ) );
  292. k.kv = kv;
  293. keys.AddToTail( k );
  294. }
  295. void RemoveKv( KeyValues *kv )
  296. {
  297. int c = keys.Count();
  298. for ( int i = 0; i < c; i++ )
  299. {
  300. if ( keys[i].kv == kv )
  301. {
  302. keys.Remove( i );
  303. break;
  304. }
  305. }
  306. }
  307. CUtlVector< kve > keys;
  308. };
  309. static CLeakTrack track;
  310. #define TRACK_KV_ADD( ptr, name ) track.AddKv( ptr, name )
  311. #define TRACK_KV_REMOVE( ptr ) track.RemoveKv( ptr )
  312. #else
  313. #define TRACK_KV_ADD( ptr, name )
  314. #define TRACK_KV_REMOVE( ptr )
  315. #endif
  316. //-----------------------------------------------------------------------------
  317. // Purpose: An arbitrarily growable string table for KeyValues key names.
  318. // See the comment in the header for more info.
  319. //-----------------------------------------------------------------------------
  320. class CKeyValuesGrowableStringTable
  321. {
  322. public:
  323. // Constructor
  324. CKeyValuesGrowableStringTable() :
  325. m_vecStrings( 0, 512 * 1024 ),
  326. m_hashLookup( 2048, 0, 0, m_Functor, m_Functor )
  327. {
  328. m_vecStrings.AddToTail( '\0' );
  329. }
  330. // Translates a string to an index
  331. int GetSymbolForString( const char *name, bool bCreate = true )
  332. {
  333. AUTO_LOCK( m_mutex );
  334. // Put the current details into our hash functor
  335. m_Functor.SetCurString( name );
  336. m_Functor.SetCurStringBase( (const char *)m_vecStrings.Base() );
  337. if ( bCreate )
  338. {
  339. bool bInserted = false;
  340. UtlHashHandle_t hElement = m_hashLookup.Insert( -1, &bInserted );
  341. if ( bInserted )
  342. {
  343. int iIndex = m_vecStrings.AddMultipleToTail( V_strlen( name ) + 1, name );
  344. m_hashLookup[ hElement ] = iIndex;
  345. }
  346. return m_hashLookup[ hElement ];
  347. }
  348. else
  349. {
  350. UtlHashHandle_t hElement = m_hashLookup.Find( -1 );
  351. if ( m_hashLookup.IsValidHandle( hElement ) )
  352. return m_hashLookup[ hElement ];
  353. else
  354. return -1;
  355. }
  356. }
  357. // Translates an index back to a string
  358. const char *GetStringForSymbol( int symbol )
  359. {
  360. return (const char *)m_vecStrings.Base() + symbol;
  361. }
  362. private:
  363. // A class plugged into CUtlHash that allows us to change the behavior of the table
  364. // and store only the index in the table.
  365. class CLookupFunctor
  366. {
  367. public:
  368. CLookupFunctor() : m_pchCurString( NULL ), m_pchCurBase( NULL ) {}
  369. // Sets what we are currently inserting or looking for.
  370. void SetCurString( const char *pchCurString ) { m_pchCurString = pchCurString; }
  371. void SetCurStringBase( const char *pchCurBase ) { m_pchCurBase = pchCurBase; }
  372. // The compare function.
  373. bool operator()( int nLhs, int nRhs ) const
  374. {
  375. const char *pchLhs = nLhs > 0 ? m_pchCurBase + nLhs : m_pchCurString;
  376. const char *pchRhs = nRhs > 0 ? m_pchCurBase + nRhs : m_pchCurString;
  377. return ( 0 == V_stricmp( pchLhs, pchRhs ) );
  378. }
  379. // The hash function.
  380. unsigned int operator()( int nItem ) const
  381. {
  382. return HashStringCaseless( m_pchCurString );
  383. }
  384. private:
  385. const char *m_pchCurString;
  386. const char *m_pchCurBase;
  387. };
  388. CThreadFastMutex m_mutex;
  389. CLookupFunctor m_Functor;
  390. CUtlHash<int, CLookupFunctor &, CLookupFunctor &> m_hashLookup;
  391. CUtlVector<char> m_vecStrings;
  392. };
  393. //-----------------------------------------------------------------------------
  394. // Purpose: Sets whether the KeyValues system should use an arbitrarily growable
  395. // string table. See the comment in the header for more info.
  396. //-----------------------------------------------------------------------------
  397. void KeyValues::SetUseGrowableStringTable( bool bUseGrowableTable )
  398. {
  399. if ( bUseGrowableTable )
  400. {
  401. s_pfGetStringForSymbol = &(KeyValues::GetStringForSymbolGrowable);
  402. s_pfGetSymbolForString = &(KeyValues::GetSymbolForStringGrowable);
  403. if ( NULL == s_pGrowableStringTable )
  404. {
  405. s_pGrowableStringTable = new CKeyValuesGrowableStringTable;
  406. }
  407. }
  408. else
  409. {
  410. s_pfGetStringForSymbol = &(KeyValues::GetStringForSymbolClassic);
  411. s_pfGetSymbolForString = &(KeyValues::GetSymbolForStringClassic);
  412. }
  413. }
  414. //-----------------------------------------------------------------------------
  415. // Purpose: Bodys of the function pointers used for interacting with the key
  416. // name string table
  417. //-----------------------------------------------------------------------------
  418. int KeyValues::GetSymbolForStringClassic( const char *name, bool bCreate )
  419. {
  420. return KeyValuesSystem()->GetSymbolForString( name, bCreate );
  421. }
  422. const char *KeyValues::GetStringForSymbolClassic( int symbol )
  423. {
  424. return KeyValuesSystem()->GetStringForSymbol( symbol );
  425. }
  426. int KeyValues::GetSymbolForStringGrowable( const char *name, bool bCreate )
  427. {
  428. return s_pGrowableStringTable->GetSymbolForString( name, bCreate );
  429. }
  430. const char *KeyValues::GetStringForSymbolGrowable( int symbol )
  431. {
  432. return s_pGrowableStringTable->GetStringForSymbol( symbol );
  433. }
  434. //-----------------------------------------------------------------------------
  435. // Purpose: Constructor
  436. //-----------------------------------------------------------------------------
  437. KeyValues::KeyValues( const char *setName )
  438. {
  439. TRACK_KV_ADD( this, setName );
  440. Init();
  441. SetName ( setName );
  442. }
  443. //-----------------------------------------------------------------------------
  444. // Purpose: Constructor
  445. //-----------------------------------------------------------------------------
  446. KeyValues::KeyValues( const char *setName, const char *firstKey, const char *firstValue )
  447. {
  448. TRACK_KV_ADD( this, setName );
  449. Init();
  450. SetName( setName );
  451. SetString( firstKey, firstValue );
  452. }
  453. //-----------------------------------------------------------------------------
  454. // Purpose: Constructor
  455. //-----------------------------------------------------------------------------
  456. KeyValues::KeyValues( const char *setName, const char *firstKey, const wchar_t *firstValue )
  457. {
  458. TRACK_KV_ADD( this, setName );
  459. Init();
  460. SetName( setName );
  461. SetWString( firstKey, firstValue );
  462. }
  463. //-----------------------------------------------------------------------------
  464. // Purpose: Constructor
  465. //-----------------------------------------------------------------------------
  466. KeyValues::KeyValues( const char *setName, const char *firstKey, int firstValue )
  467. {
  468. TRACK_KV_ADD( this, setName );
  469. Init();
  470. SetName( setName );
  471. SetInt( firstKey, firstValue );
  472. }
  473. //-----------------------------------------------------------------------------
  474. // Purpose: Constructor
  475. //-----------------------------------------------------------------------------
  476. KeyValues::KeyValues( const char *setName, const char *firstKey, const char *firstValue, const char *secondKey, const char *secondValue )
  477. {
  478. TRACK_KV_ADD( this, setName );
  479. Init();
  480. SetName( setName );
  481. SetString( firstKey, firstValue );
  482. SetString( secondKey, secondValue );
  483. }
  484. //-----------------------------------------------------------------------------
  485. // Purpose: Constructor
  486. //-----------------------------------------------------------------------------
  487. KeyValues::KeyValues( const char *setName, const char *firstKey, int firstValue, const char *secondKey, int secondValue )
  488. {
  489. TRACK_KV_ADD( this, setName );
  490. Init();
  491. SetName( setName );
  492. SetInt( firstKey, firstValue );
  493. SetInt( secondKey, secondValue );
  494. }
  495. //-----------------------------------------------------------------------------
  496. // Purpose: Initialize member variables
  497. //-----------------------------------------------------------------------------
  498. void KeyValues::Init()
  499. {
  500. m_iKeyName = 0;
  501. m_iKeyNameCaseSensitive1 = 0;
  502. m_iKeyNameCaseSensitive2 = 0;
  503. m_iDataType = TYPE_NONE;
  504. m_pSub = NULL;
  505. m_pPeer = NULL;
  506. m_pChain = NULL;
  507. m_sValue = NULL;
  508. m_wsValue = NULL;
  509. m_pValue = NULL;
  510. m_bHasEscapeSequences = 0;
  511. }
  512. //-----------------------------------------------------------------------------
  513. // Purpose: Destructor
  514. //-----------------------------------------------------------------------------
  515. KeyValues::~KeyValues()
  516. {
  517. TRACK_KV_REMOVE( this );
  518. RemoveEverything();
  519. }
  520. // for backwards compat - we used to need this to force the free to run from the same DLL
  521. // as the alloc
  522. void KeyValues::deleteThis()
  523. {
  524. delete this;
  525. }
  526. //-----------------------------------------------------------------------------
  527. // Purpose: remove everything
  528. //-----------------------------------------------------------------------------
  529. void KeyValues::RemoveEverything()
  530. {
  531. KeyValues *dat;
  532. KeyValues *datNext = NULL;
  533. for ( dat = m_pSub; dat != NULL; dat = datNext )
  534. {
  535. datNext = dat->m_pPeer;
  536. dat->m_pPeer = NULL;
  537. delete dat;
  538. }
  539. for ( dat = m_pPeer; dat && dat != this; dat = datNext )
  540. {
  541. datNext = dat->m_pPeer;
  542. dat->m_pPeer = NULL;
  543. delete dat;
  544. }
  545. delete [] m_sValue;
  546. m_sValue = NULL;
  547. delete [] m_wsValue;
  548. m_wsValue = NULL;
  549. }
  550. //-----------------------------------------------------------------------------
  551. // Purpose:
  552. // Input : *f -
  553. //-----------------------------------------------------------------------------
  554. void KeyValues::RecursiveSaveToFile( CUtlBuffer& buf, int indentLevel )
  555. {
  556. RecursiveSaveToFile( NULL, FILESYSTEM_INVALID_HANDLE, &buf, indentLevel );
  557. }
  558. //-----------------------------------------------------------------------------
  559. // Adds a chain... if we don't find stuff in this keyvalue, we'll look
  560. // in the one we're chained to.
  561. //-----------------------------------------------------------------------------
  562. void KeyValues::ChainKeyValue( KeyValues* pChain )
  563. {
  564. m_pChain = pChain;
  565. }
  566. //-----------------------------------------------------------------------------
  567. // Purpose: Get the name of the current key section
  568. //-----------------------------------------------------------------------------
  569. const char *KeyValues::GetName( void ) const
  570. {
  571. AssertMsg( this, "Member function called on NULL KeyValues" );
  572. return this ? KeyValuesSystem()->GetStringForSymbol( MAKE_3_BYTES_FROM_1_AND_2( m_iKeyNameCaseSensitive1, m_iKeyNameCaseSensitive2 ) ) : "";
  573. }
  574. //-----------------------------------------------------------------------------
  575. // Purpose: Get the symbol name of the current key section
  576. //-----------------------------------------------------------------------------
  577. int KeyValues::GetNameSymbol() const
  578. {
  579. AssertMsg( this, "Member function called on NULL KeyValues" );
  580. return this ? m_iKeyName : INVALID_KEY_SYMBOL;
  581. }
  582. int KeyValues::GetNameSymbolCaseSensitive() const
  583. {
  584. AssertMsg( this, "Member function called on NULL KeyValues" );
  585. return this ? MAKE_3_BYTES_FROM_1_AND_2( m_iKeyNameCaseSensitive1, m_iKeyNameCaseSensitive2 ) : INVALID_KEY_SYMBOL;
  586. }
  587. //-----------------------------------------------------------------------------
  588. // Purpose: if parser should translate escape sequences ( /n, /t etc), set to true
  589. //-----------------------------------------------------------------------------
  590. void KeyValues::UsesEscapeSequences(bool state)
  591. {
  592. m_bHasEscapeSequences = state;
  593. }
  594. //-----------------------------------------------------------------------------
  595. // Purpose: Load keyValues from disk
  596. //-----------------------------------------------------------------------------
  597. bool KeyValues::LoadFromFile( IBaseFileSystem *filesystem, const char *resourceName, const char *pathID, GetSymbolProc_t pfnEvaluateSymbolProc )
  598. {
  599. //TM_ZONE_FILTERED( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s %s", __FUNCTION__, tmDynamicString( TELEMETRY_LEVEL0, resourceName ) );
  600. FileHandle_t f = filesystem->Open(resourceName, "rb", pathID);
  601. if ( !f )
  602. return false;
  603. s_LastFileLoadingFrom = (char*)resourceName;
  604. // load file into a null-terminated buffer
  605. int fileSize = filesystem->Size( f );
  606. unsigned bufSize = ((IFileSystem *)filesystem)->GetOptimalReadSize( f, fileSize + 2 );
  607. char *buffer = (char*)((IFileSystem *)filesystem)->AllocOptimalReadBuffer( f, bufSize );
  608. Assert( buffer );
  609. // read into local buffer
  610. bool bRetOK = ( ((IFileSystem *)filesystem)->ReadEx( buffer, bufSize, fileSize, f ) != 0 );
  611. filesystem->Close( f ); // close file after reading
  612. if ( bRetOK )
  613. {
  614. buffer[fileSize] = 0; // null terminate file as EOF
  615. buffer[fileSize+1] = 0; // double NULL terminating in case this is a unicode file
  616. bRetOK = LoadFromBuffer( resourceName, buffer, filesystem, pathID, pfnEvaluateSymbolProc );
  617. }
  618. ((IFileSystem *)filesystem)->FreeOptimalReadBuffer( buffer );
  619. return bRetOK;
  620. }
  621. //-----------------------------------------------------------------------------
  622. // Purpose: Save the keyvalues to disk
  623. // Creates the path to the file if it doesn't exist
  624. //-----------------------------------------------------------------------------
  625. bool KeyValues::SaveToFile( IBaseFileSystem *filesystem, const char *resourceName, const char *pathID, bool bWriteEmptySubkeys )
  626. {
  627. // create a write file
  628. FileHandle_t f = filesystem->Open(resourceName, "wb", pathID);
  629. if ( f == FILESYSTEM_INVALID_HANDLE )
  630. {
  631. DevMsg( "KeyValues::SaveToFile: couldn't open file \"%s\" in path \"%s\".\n",
  632. resourceName?resourceName:"NULL", pathID?pathID:"NULL" );
  633. return false;
  634. }
  635. RecursiveSaveToFile(filesystem, f, NULL, 0, bWriteEmptySubkeys);
  636. filesystem->Close(f);
  637. return true;
  638. }
  639. //-----------------------------------------------------------------------------
  640. // Purpose: Write out a set of indenting
  641. //-----------------------------------------------------------------------------
  642. void KeyValues::WriteIndents( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel )
  643. {
  644. for ( int i = 0; i < indentLevel; i++ )
  645. {
  646. INTERNALWRITE( "\t", 1 );
  647. }
  648. }
  649. //-----------------------------------------------------------------------------
  650. // Purpose: Write out a string where we convert the double quotes to backslash double quote
  651. //-----------------------------------------------------------------------------
  652. void KeyValues::WriteConvertedString( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, const char *pszString )
  653. {
  654. // handle double quote chars within the string
  655. // the worst possible case is that the whole string is quotes
  656. int len = V_strlen(pszString);
  657. char *convertedString = (char *) alloca ((len + 1) * sizeof(char) * 2);
  658. int j=0;
  659. for (int i=0; i <= len; i++)
  660. {
  661. if (pszString[i] == '\"')
  662. {
  663. convertedString[j] = '\\';
  664. j++;
  665. }
  666. else if ( m_bHasEscapeSequences && pszString[i] == '\\' )
  667. {
  668. convertedString[j] = '\\';
  669. j++;
  670. }
  671. convertedString[j] = pszString[i];
  672. j++;
  673. }
  674. INTERNALWRITE(convertedString, V_strlen(convertedString));
  675. }
  676. void KeyValues::InternalWrite( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, const void *pData, int len )
  677. {
  678. if ( filesystem )
  679. {
  680. filesystem->Write( pData, len, f );
  681. }
  682. if ( pBuf )
  683. {
  684. pBuf->Put( pData, len );
  685. }
  686. }
  687. //-----------------------------------------------------------------------------
  688. // Purpose: Save keyvalues from disk, if subkey values are detected, calls
  689. // itself to save those
  690. //-----------------------------------------------------------------------------
  691. void KeyValues::RecursiveSaveToFile( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel, bool bWriteEmptySubkeys )
  692. {
  693. // write header
  694. WriteIndents( filesystem, f, pBuf, indentLevel );
  695. INTERNALWRITE("\"", 1);
  696. WriteConvertedString(filesystem, f, pBuf, GetName());
  697. INTERNALWRITE("\"\n", 2);
  698. WriteIndents( filesystem, f, pBuf, indentLevel );
  699. INTERNALWRITE("{\n", 2);
  700. // loop through all our keys writing them to disk
  701. for ( KeyValues *dat = m_pSub; dat != NULL; dat = dat->m_pPeer )
  702. {
  703. if ( dat->m_pSub )
  704. {
  705. dat->RecursiveSaveToFile( filesystem, f, pBuf, indentLevel + 1, bWriteEmptySubkeys );
  706. }
  707. else
  708. {
  709. // only write non-empty keys
  710. switch (dat->m_iDataType)
  711. {
  712. case TYPE_NONE:
  713. {
  714. if ( bWriteEmptySubkeys )
  715. {
  716. dat->RecursiveSaveToFile( filesystem, f, pBuf, indentLevel + 1, bWriteEmptySubkeys );
  717. }
  718. break;
  719. }
  720. case TYPE_STRING:
  721. {
  722. if (dat->m_sValue && *(dat->m_sValue))
  723. {
  724. WriteIndents(filesystem, f, pBuf, indentLevel + 1);
  725. INTERNALWRITE("\"", 1);
  726. WriteConvertedString(filesystem, f, pBuf, dat->GetName());
  727. INTERNALWRITE("\"\t\t\"", 4);
  728. WriteConvertedString(filesystem, f, pBuf, dat->m_sValue);
  729. INTERNALWRITE("\"\n", 2);
  730. }
  731. break;
  732. }
  733. case TYPE_WSTRING:
  734. {
  735. if ( dat->m_wsValue )
  736. {
  737. static char buf[KEYVALUES_TOKEN_SIZE];
  738. // make sure we have enough space
  739. int result = V_UnicodeToUTF8( dat->m_wsValue, buf, KEYVALUES_TOKEN_SIZE);
  740. if (result)
  741. {
  742. WriteIndents(filesystem, f, pBuf, indentLevel + 1);
  743. INTERNALWRITE("\"", 1);
  744. INTERNALWRITE(dat->GetName(), V_strlen(dat->GetName()));
  745. INTERNALWRITE("\"\t\t\"", 4);
  746. WriteConvertedString(filesystem, f, pBuf, buf);
  747. INTERNALWRITE("\"\n", 2);
  748. }
  749. }
  750. break;
  751. }
  752. case TYPE_INT:
  753. {
  754. WriteIndents(filesystem, f, pBuf, indentLevel + 1);
  755. INTERNALWRITE("\"", 1);
  756. INTERNALWRITE(dat->GetName(), V_strlen(dat->GetName()));
  757. INTERNALWRITE("\"\t\t\"", 4);
  758. char buf[32];
  759. V_snprintf(buf, sizeof( buf ), "%d", dat->m_iValue);
  760. INTERNALWRITE(buf, V_strlen(buf));
  761. INTERNALWRITE("\"\n", 2);
  762. break;
  763. }
  764. case TYPE_UINT64:
  765. {
  766. WriteIndents(filesystem, f, pBuf, indentLevel + 1);
  767. INTERNALWRITE("\"", 1);
  768. INTERNALWRITE(dat->GetName(), V_strlen(dat->GetName()));
  769. INTERNALWRITE("\"\t\t\"", 4);
  770. char buf[32];
  771. // write "0x" + 16 char 0-padded hex encoded 64 bit value
  772. V_snprintf( buf, sizeof( buf ), "0x%016llX", *( (uint64 *)dat->m_sValue ) );
  773. INTERNALWRITE(buf, V_strlen(buf));
  774. INTERNALWRITE("\"\n", 2);
  775. break;
  776. }
  777. case TYPE_FLOAT:
  778. {
  779. WriteIndents(filesystem, f, pBuf, indentLevel + 1);
  780. INTERNALWRITE("\"", 1);
  781. INTERNALWRITE(dat->GetName(), V_strlen(dat->GetName()));
  782. INTERNALWRITE("\"\t\t\"", 4);
  783. char buf[48];
  784. V_snprintf(buf, sizeof( buf ), "%f", dat->m_flValue);
  785. INTERNALWRITE(buf, V_strlen(buf));
  786. INTERNALWRITE("\"\n", 2);
  787. break;
  788. }
  789. case TYPE_COLOR:
  790. DevMsg( "KeyValues::RecursiveSaveToFile: TODO, missing code for TYPE_COLOR.\n" );
  791. break;
  792. default:
  793. break;
  794. }
  795. }
  796. }
  797. // write tail
  798. WriteIndents(filesystem, f, pBuf, indentLevel);
  799. INTERNALWRITE("}\n", 2);
  800. }
  801. //-----------------------------------------------------------------------------
  802. // Purpose: looks up a key by symbol name
  803. //-----------------------------------------------------------------------------
  804. KeyValues *KeyValues::FindKey(int keySymbol) const
  805. {
  806. AssertMsg( this, "Member function called on NULL KeyValues" );
  807. for (KeyValues *dat = this ? m_pSub : NULL; dat != NULL; dat = dat->m_pPeer)
  808. {
  809. if ( dat->m_iKeyName == (uint32) keySymbol )
  810. return dat;
  811. }
  812. return NULL;
  813. }
  814. //-----------------------------------------------------------------------------
  815. // Purpose: Find a keyValue, create it if it is not found.
  816. // Set bCreate to true to create the key if it doesn't already exist
  817. // (which ensures a valid pointer will be returned)
  818. //-----------------------------------------------------------------------------
  819. KeyValues *KeyValues::FindKey(const char *keyName, bool bCreate)
  820. {
  821. // Validate NULL == this early out
  822. if ( !this )
  823. {
  824. AssertMsg( false, "KeyValues::FindKey called on NULL pointer!" ); // Undefined behavior. Could blow up on a new platform. Don't do it.
  825. Assert( !bCreate );
  826. return NULL;
  827. }
  828. // return the current key if a NULL subkey is asked for
  829. if (!keyName || !keyName[0])
  830. return this;
  831. // look for '/' characters deliminating sub fields
  832. CUtlVector< char > szBuf;
  833. const char *subStr = strchr(keyName, '/');
  834. const char *searchStr = keyName;
  835. // pull out the substring if it exists
  836. if ( subStr )
  837. {
  838. int size = subStr - keyName;
  839. Assert( size >= 0 );
  840. Assert( size < 1024 * 1024 );
  841. szBuf.EnsureCount( size + 1 );
  842. V_memcpy( szBuf.Base(), keyName, size );
  843. szBuf[size] = 0;
  844. if ( V_strlen( keyName ) > 1 )
  845. {
  846. // If the key name is just '/', we don't treat is as a key with subfields, but use the '/' as a key name directly
  847. searchStr = szBuf.Base();
  848. }
  849. }
  850. // lookup the symbol for the search string,
  851. // we do not need the case-sensitive symbol at this time
  852. // because if the key is found, then it will be found by case-insensitive lookup
  853. // if the key is not found and needs to be created we will pass the actual searchStr
  854. // and have the new KeyValues constructor get/create the case-sensitive symbol
  855. HKeySymbol iSearchStr = KeyValuesSystem()->GetSymbolForString( searchStr, bCreate );
  856. if ( iSearchStr == INVALID_KEY_SYMBOL )
  857. {
  858. // not found, couldn't possibly be in key value list
  859. return NULL;
  860. }
  861. KeyValues *lastItem = NULL;
  862. KeyValues *dat;
  863. // find the searchStr in the current peer list
  864. for (dat = m_pSub; dat != NULL; dat = dat->m_pPeer)
  865. {
  866. lastItem = dat; // record the last item looked at (for if we need to append to the end of the list)
  867. // symbol compare
  868. if ( dat->m_iKeyName == ( uint32 ) iSearchStr )
  869. {
  870. break;
  871. }
  872. }
  873. if ( !dat && m_pChain )
  874. {
  875. dat = m_pChain->FindKey(keyName, false);
  876. }
  877. // make sure a key was found
  878. if (!dat)
  879. {
  880. if (bCreate)
  881. {
  882. // we need to create a new key
  883. dat = new KeyValues( searchStr );
  884. // Assert(dat != NULL);
  885. // insert new key at end of list
  886. if (lastItem)
  887. {
  888. lastItem->m_pPeer = dat;
  889. }
  890. else
  891. {
  892. m_pSub = dat;
  893. }
  894. dat->m_pPeer = NULL;
  895. // a key graduates to be a submsg as soon as it's m_pSub is set
  896. // this should be the only place m_pSub is set
  897. m_iDataType = TYPE_NONE;
  898. }
  899. else
  900. {
  901. return NULL;
  902. }
  903. }
  904. // if we've still got a subStr we need to keep looking deeper in the tree
  905. if ( subStr )
  906. {
  907. // recursively chain down through the paths in the string
  908. return dat->FindKey(subStr + 1, bCreate);
  909. }
  910. return dat;
  911. }
  912. //-----------------------------------------------------------------------------
  913. // Purpose: Create a new key, with an autogenerated name.
  914. // Name is guaranteed to be an integer, of value 1 higher than the highest
  915. // other integer key name
  916. //-----------------------------------------------------------------------------
  917. KeyValues *KeyValues::CreateNewKey()
  918. {
  919. int newID = 1;
  920. // search for any key with higher values
  921. KeyValues *pLastChild = NULL;
  922. for (KeyValues *dat = m_pSub; dat != NULL; dat = dat->m_pPeer)
  923. {
  924. // case-insensitive string compare
  925. int val = atoi(dat->GetName());
  926. if (newID <= val)
  927. {
  928. newID = val + 1;
  929. }
  930. pLastChild = dat;
  931. }
  932. char buf[12];
  933. V_snprintf( buf, sizeof(buf), "%d", newID );
  934. return CreateKeyUsingKnownLastChild( buf, pLastChild );
  935. }
  936. //-----------------------------------------------------------------------------
  937. // Create a key
  938. //-----------------------------------------------------------------------------
  939. KeyValues* KeyValues::CreateKey( const char *keyName )
  940. {
  941. KeyValues *pLastChild = FindLastSubKey();
  942. return CreateKeyUsingKnownLastChild( keyName, pLastChild );
  943. }
  944. //-----------------------------------------------------------------------------
  945. // Create a new sibling key
  946. //-----------------------------------------------------------------------------
  947. KeyValues* KeyValues::CreatePeerKey( const char *keyName )
  948. {
  949. KeyValues* dat = new KeyValues( keyName );
  950. //dat->Internal_SetHasEscapeSequences( Internal_HasEscapeSequences() ); // use same format as peer
  951. dat->m_bHasEscapeSequences = m_bHasEscapeSequences;
  952. // insert into peer linked list after self.
  953. dat->m_pPeer = m_pPeer;
  954. m_pPeer = dat;
  955. return dat;
  956. }
  957. //-----------------------------------------------------------------------------
  958. KeyValues* KeyValues::CreateKeyUsingKnownLastChild( const char *keyName, KeyValues *pLastChild )
  959. {
  960. // Create a new key
  961. KeyValues* dat = new KeyValues( keyName );
  962. dat->UsesEscapeSequences( m_bHasEscapeSequences != 0 ); // use same format as parent does
  963. // add into subkey list
  964. AddSubkeyUsingKnownLastChild( dat, pLastChild );
  965. return dat;
  966. }
  967. //-----------------------------------------------------------------------------
  968. void KeyValues::AddSubkeyUsingKnownLastChild( KeyValues *pSubkey, KeyValues *pLastChild )
  969. {
  970. // Make sure the subkey isn't a child of some other keyvalues
  971. Assert( pSubkey != NULL );
  972. Assert( pSubkey->m_pPeer == NULL );
  973. // Empty child list?
  974. if ( pLastChild == NULL )
  975. {
  976. Assert( m_pSub == NULL );
  977. m_pSub = pSubkey;
  978. }
  979. else
  980. {
  981. Assert( m_pSub != NULL );
  982. Assert( pLastChild->m_pPeer == NULL );
  983. pLastChild->SetNextKey( pSubkey );
  984. }
  985. }
  986. //-----------------------------------------------------------------------------
  987. // Adds a subkey. Make sure the subkey isn't a child of some other keyvalues
  988. //-----------------------------------------------------------------------------
  989. void KeyValues::AddSubKey( KeyValues *pSubkey )
  990. {
  991. // Make sure the subkey isn't a child of some other keyvalues
  992. Assert( pSubkey != NULL );
  993. Assert( pSubkey->m_pPeer == NULL );
  994. // add into subkey list
  995. if ( m_pSub == NULL )
  996. {
  997. m_pSub = pSubkey;
  998. }
  999. else
  1000. {
  1001. KeyValues *pTempDat = m_pSub;
  1002. while ( pTempDat->GetNextKey() != NULL )
  1003. {
  1004. pTempDat = pTempDat->GetNextKey();
  1005. }
  1006. pTempDat->SetNextKey( pSubkey );
  1007. }
  1008. }
  1009. //-----------------------------------------------------------------------------
  1010. // Purpose: Remove a subkey from the list
  1011. //-----------------------------------------------------------------------------
  1012. void KeyValues::RemoveSubKey(KeyValues *subKey)
  1013. {
  1014. if (!subKey)
  1015. return;
  1016. // check the list pointer
  1017. if (m_pSub == subKey)
  1018. {
  1019. m_pSub = subKey->m_pPeer;
  1020. }
  1021. else
  1022. {
  1023. // look through the list
  1024. KeyValues *kv = m_pSub;
  1025. while (kv->m_pPeer)
  1026. {
  1027. if (kv->m_pPeer == subKey)
  1028. {
  1029. kv->m_pPeer = subKey->m_pPeer;
  1030. break;
  1031. }
  1032. kv = kv->m_pPeer;
  1033. }
  1034. }
  1035. subKey->m_pPeer = NULL;
  1036. }
  1037. void KeyValues::InsertSubKey( int nIndex, KeyValues *pSubKey )
  1038. {
  1039. // Sub key must be valid and not part of another chain
  1040. Assert( pSubKey && pSubKey->m_pPeer == NULL );
  1041. if ( nIndex == 0 )
  1042. {
  1043. pSubKey->m_pPeer = m_pSub;
  1044. m_pSub = pSubKey;
  1045. return;
  1046. }
  1047. else
  1048. {
  1049. int nCurrentIndex = 0;
  1050. for ( KeyValues *pIter = GetFirstSubKey(); pIter != NULL; pIter = pIter->GetNextKey() )
  1051. {
  1052. ++ nCurrentIndex;
  1053. if ( nCurrentIndex == nIndex)
  1054. {
  1055. pSubKey->m_pPeer = pIter->m_pPeer;
  1056. pIter->m_pPeer = pSubKey;
  1057. return;
  1058. }
  1059. }
  1060. // Index is out of range if we get here
  1061. Assert( 0 );
  1062. return;
  1063. }
  1064. }
  1065. bool KeyValues::ContainsSubKey( KeyValues *pSubKey )
  1066. {
  1067. for ( KeyValues *pIter = GetFirstSubKey(); pIter != NULL; pIter = pIter->GetNextKey() )
  1068. {
  1069. if ( pSubKey == pIter )
  1070. {
  1071. return true;
  1072. }
  1073. }
  1074. return false;
  1075. }
  1076. void KeyValues::SwapSubKey( KeyValues *pExistingSubkey, KeyValues *pNewSubKey )
  1077. {
  1078. Assert( pExistingSubkey != NULL && pNewSubKey != NULL );
  1079. // Make sure the new sub key isn't a child of some other keyvalues
  1080. Assert( pNewSubKey->m_pPeer == NULL );
  1081. // Check the list pointer
  1082. if ( m_pSub == pExistingSubkey )
  1083. {
  1084. pNewSubKey->m_pPeer = pExistingSubkey->m_pPeer;
  1085. pExistingSubkey->m_pPeer = NULL;
  1086. m_pSub = pNewSubKey;
  1087. }
  1088. else
  1089. {
  1090. // Look through the list
  1091. KeyValues *kv = m_pSub;
  1092. while ( kv->m_pPeer )
  1093. {
  1094. if ( kv->m_pPeer == pExistingSubkey )
  1095. {
  1096. pNewSubKey->m_pPeer = pExistingSubkey->m_pPeer;
  1097. pExistingSubkey->m_pPeer = NULL;
  1098. kv->m_pPeer = pNewSubKey;
  1099. break;
  1100. }
  1101. kv = kv->m_pPeer;
  1102. }
  1103. // Existing sub key should always be found, otherwise it's a bug in the calling code.
  1104. Assert( kv->m_pPeer != NULL );
  1105. }
  1106. }
  1107. void KeyValues::ElideSubKey( KeyValues *pSubKey )
  1108. {
  1109. // This pointer's "next" pointer needs to be fixed up when we elide the key
  1110. KeyValues **ppPointerToFix = &m_pSub;
  1111. for ( KeyValues *pKeyIter = m_pSub; pKeyIter != NULL; ppPointerToFix = &pKeyIter->m_pPeer, pKeyIter = pKeyIter->GetNextKey() )
  1112. {
  1113. if ( pKeyIter == pSubKey )
  1114. {
  1115. if ( pSubKey->m_pSub == NULL )
  1116. {
  1117. // No children, simply remove the key
  1118. *ppPointerToFix = pSubKey->m_pPeer;
  1119. delete pSubKey;
  1120. }
  1121. else
  1122. {
  1123. *ppPointerToFix = pSubKey->m_pSub;
  1124. // Attach the remainder of this chain to the last child of pSubKey
  1125. KeyValues *pChildIter = pSubKey->m_pSub;
  1126. while ( pChildIter->m_pPeer != NULL )
  1127. {
  1128. pChildIter = pChildIter->m_pPeer;
  1129. }
  1130. // Now points to the last child of pSubKey
  1131. pChildIter->m_pPeer = pSubKey->m_pPeer;
  1132. // Detach the node to be elided
  1133. pSubKey->m_pSub = NULL;
  1134. pSubKey->m_pPeer = NULL;
  1135. delete pSubKey;
  1136. }
  1137. return;
  1138. }
  1139. }
  1140. // Key not found; that's caller error.
  1141. Assert( 0 );
  1142. }
  1143. //-----------------------------------------------------------------------------
  1144. // Purpose: Locate last child. Returns NULL if we have no children
  1145. //-----------------------------------------------------------------------------
  1146. KeyValues *KeyValues::FindLastSubKey()
  1147. {
  1148. // No children?
  1149. if ( m_pSub == NULL )
  1150. return NULL;
  1151. // Scan for the last one
  1152. KeyValues *pLastChild = m_pSub;
  1153. while ( pLastChild->m_pPeer )
  1154. pLastChild = pLastChild->m_pPeer;
  1155. return pLastChild;
  1156. }
  1157. //-----------------------------------------------------------------------------
  1158. // Purpose: Return the first subkey in the list
  1159. //-----------------------------------------------------------------------------
  1160. KeyValues *KeyValues::GetFirstSubKey() const
  1161. {
  1162. AssertMsg( this, "Member function called on NULL KeyValues" );
  1163. return this ? m_pSub : NULL;
  1164. }
  1165. //-----------------------------------------------------------------------------
  1166. // Purpose: Return the next subkey
  1167. //-----------------------------------------------------------------------------
  1168. KeyValues *KeyValues::GetNextKey() const
  1169. {
  1170. AssertMsg( this, "Member function called on NULL KeyValues" );
  1171. return this ? m_pPeer : NULL;
  1172. }
  1173. //-----------------------------------------------------------------------------
  1174. // Purpose: Sets this key's peer to the KeyValues passed in
  1175. //-----------------------------------------------------------------------------
  1176. void KeyValues::SetNextKey( KeyValues *pDat )
  1177. {
  1178. m_pPeer = pDat;
  1179. }
  1180. KeyValues* KeyValues::GetFirstTrueSubKey()
  1181. {
  1182. AssertMsg( this, "Member function called on NULL KeyValues" );
  1183. KeyValues *pRet = this ? m_pSub : NULL;
  1184. while ( pRet && pRet->m_iDataType != TYPE_NONE )
  1185. pRet = pRet->m_pPeer;
  1186. return pRet;
  1187. }
  1188. KeyValues* KeyValues::GetNextTrueSubKey()
  1189. {
  1190. AssertMsg( this, "Member function called on NULL KeyValues" );
  1191. KeyValues *pRet = this ? m_pPeer : NULL;
  1192. while ( pRet && pRet->m_iDataType != TYPE_NONE )
  1193. pRet = pRet->m_pPeer;
  1194. return pRet;
  1195. }
  1196. KeyValues* KeyValues::GetFirstValue()
  1197. {
  1198. AssertMsg( this, "Member function called on NULL KeyValues" );
  1199. KeyValues *pRet = this ? m_pSub : NULL;
  1200. while ( pRet && pRet->m_iDataType == TYPE_NONE )
  1201. pRet = pRet->m_pPeer;
  1202. return pRet;
  1203. }
  1204. KeyValues* KeyValues::GetNextValue()
  1205. {
  1206. AssertMsg( this, "Member function called on NULL KeyValues" );
  1207. KeyValues *pRet = this ? m_pPeer : NULL;
  1208. while ( pRet && pRet->m_iDataType == TYPE_NONE )
  1209. pRet = pRet->m_pPeer;
  1210. return pRet;
  1211. }
  1212. //-----------------------------------------------------------------------------
  1213. // Purpose: Get the integer value of a keyName. Default value is returned
  1214. // if the keyName can't be found.
  1215. //-----------------------------------------------------------------------------
  1216. int KeyValues::GetInt( const char *keyName, int defaultValue )
  1217. {
  1218. KeyValues *dat = FindKey( keyName, false );
  1219. if ( dat )
  1220. {
  1221. switch ( dat->m_iDataType )
  1222. {
  1223. case TYPE_STRING:
  1224. return atoi(dat->m_sValue);
  1225. case TYPE_WSTRING:
  1226. return _wtoi(dat->m_wsValue);
  1227. case TYPE_FLOAT:
  1228. return (int)dat->m_flValue;
  1229. case TYPE_UINT64:
  1230. // can't convert, since it would lose data
  1231. Assert(0);
  1232. return 0;
  1233. case TYPE_INT:
  1234. case TYPE_PTR:
  1235. default:
  1236. return dat->m_iValue;
  1237. };
  1238. }
  1239. return defaultValue;
  1240. }
  1241. //-----------------------------------------------------------------------------
  1242. // Purpose: Get the integer value of a keyName. Default value is returned
  1243. // if the keyName can't be found.
  1244. //-----------------------------------------------------------------------------
  1245. uint64 KeyValues::GetUint64( const char *keyName, uint64 defaultValue )
  1246. {
  1247. KeyValues *dat = FindKey( keyName, false );
  1248. if ( dat )
  1249. {
  1250. switch ( dat->m_iDataType )
  1251. {
  1252. case TYPE_STRING:
  1253. {
  1254. uint64 uiResult = 0ull;
  1255. sscanf( dat->m_sValue, "%lld", &uiResult );
  1256. return uiResult;
  1257. }
  1258. case TYPE_WSTRING:
  1259. {
  1260. uint64 uiResult = 0ull;
  1261. swscanf( dat->m_wsValue, L"%lld", &uiResult );
  1262. return uiResult;
  1263. }
  1264. case TYPE_FLOAT:
  1265. return (int)dat->m_flValue;
  1266. case TYPE_UINT64:
  1267. return *((uint64 *)dat->m_sValue);
  1268. case TYPE_PTR:
  1269. return (uint64)(uintp)dat->m_pValue;
  1270. case TYPE_INT:
  1271. default:
  1272. return dat->m_iValue;
  1273. };
  1274. }
  1275. return defaultValue;
  1276. }
  1277. //-----------------------------------------------------------------------------
  1278. // Purpose: Get the pointer value of a keyName. Default value is returned
  1279. // if the keyName can't be found.
  1280. //-----------------------------------------------------------------------------
  1281. void *KeyValues::GetPtr( const char *keyName, void *defaultValue )
  1282. {
  1283. KeyValues *dat = FindKey( keyName, false );
  1284. if ( dat )
  1285. {
  1286. switch ( dat->m_iDataType )
  1287. {
  1288. case TYPE_PTR:
  1289. return dat->m_pValue;
  1290. case TYPE_WSTRING:
  1291. case TYPE_STRING:
  1292. case TYPE_FLOAT:
  1293. case TYPE_INT:
  1294. case TYPE_UINT64:
  1295. default:
  1296. return NULL;
  1297. };
  1298. }
  1299. return defaultValue;
  1300. }
  1301. //-----------------------------------------------------------------------------
  1302. // Purpose: Get the float value of a keyName. Default value is returned
  1303. // if the keyName can't be found.
  1304. //-----------------------------------------------------------------------------
  1305. float KeyValues::GetFloat( const char *keyName, float defaultValue )
  1306. {
  1307. KeyValues *dat = FindKey( keyName, false );
  1308. if ( dat )
  1309. {
  1310. switch ( dat->m_iDataType )
  1311. {
  1312. case TYPE_STRING:
  1313. return (float)atof(dat->m_sValue);
  1314. case TYPE_WSTRING:
  1315. #ifdef WIN32
  1316. return (float) _wtof(dat->m_wsValue); // no wtof
  1317. #else
  1318. return (float) wcstof( dat->m_wsValue, (wchar_t **)NULL );
  1319. #endif
  1320. case TYPE_FLOAT:
  1321. return dat->m_flValue;
  1322. case TYPE_INT:
  1323. return (float)dat->m_iValue;
  1324. case TYPE_UINT64:
  1325. return (float)(*((uint64 *)dat->m_sValue));
  1326. case TYPE_PTR:
  1327. default:
  1328. return 0.0f;
  1329. };
  1330. }
  1331. return defaultValue;
  1332. }
  1333. //-----------------------------------------------------------------------------
  1334. // Purpose: Get the string pointer of a keyName. Default value is returned
  1335. // if the keyName can't be found.
  1336. //-----------------------------------------------------------------------------
  1337. const char *KeyValues::GetString( const char *keyName, const char *defaultValue )
  1338. {
  1339. KeyValues *dat = FindKey( keyName, false );
  1340. if ( dat )
  1341. {
  1342. // convert the data to string form then return it
  1343. char buf[64];
  1344. switch ( dat->m_iDataType )
  1345. {
  1346. case TYPE_FLOAT:
  1347. V_snprintf( buf, sizeof( buf ), "%f", dat->m_flValue );
  1348. SetString( keyName, buf );
  1349. break;
  1350. case TYPE_PTR:
  1351. V_snprintf( buf, sizeof( buf ), "%lld", CastPtrToInt64( dat->m_pValue ) );
  1352. SetString( keyName, buf );
  1353. break;
  1354. case TYPE_INT:
  1355. V_snprintf( buf, sizeof( buf ), "%d", dat->m_iValue );
  1356. SetString( keyName, buf );
  1357. break;
  1358. case TYPE_UINT64:
  1359. V_snprintf( buf, sizeof( buf ), "%lld", *((uint64 *)(dat->m_sValue)) );
  1360. SetString( keyName, buf );
  1361. break;
  1362. case TYPE_COLOR:
  1363. V_snprintf( buf, sizeof( buf ), "%d %d %d %d", dat->m_Color[0], dat->m_Color[1], dat->m_Color[2], dat->m_Color[3] );
  1364. SetString( keyName, buf );
  1365. break;
  1366. case TYPE_WSTRING:
  1367. {
  1368. // convert the string to char *, set it for future use, and return it
  1369. char wideBuf[512];
  1370. int result = V_UnicodeToUTF8(dat->m_wsValue, wideBuf, 512);
  1371. if ( result )
  1372. {
  1373. // note: this will copy wideBuf
  1374. SetString( keyName, wideBuf );
  1375. }
  1376. else
  1377. {
  1378. return defaultValue;
  1379. }
  1380. break;
  1381. }
  1382. case TYPE_STRING:
  1383. break;
  1384. default:
  1385. return defaultValue;
  1386. };
  1387. return dat->m_sValue;
  1388. }
  1389. return defaultValue;
  1390. }
  1391. const wchar_t *KeyValues::GetWString( const char *keyName, const wchar_t *defaultValue)
  1392. {
  1393. KeyValues *dat = FindKey( keyName, false );
  1394. if ( dat )
  1395. {
  1396. wchar_t wbuf[64];
  1397. switch ( dat->m_iDataType )
  1398. {
  1399. case TYPE_FLOAT:
  1400. swprintf(wbuf, Q_ARRAYSIZE(wbuf), L"%f", dat->m_flValue);
  1401. SetWString( keyName, wbuf);
  1402. break;
  1403. case TYPE_PTR:
  1404. swprintf( wbuf, Q_ARRAYSIZE(wbuf), L"%lld", (int64)(size_t)dat->m_pValue );
  1405. SetWString( keyName, wbuf );
  1406. break;
  1407. case TYPE_INT:
  1408. swprintf( wbuf, Q_ARRAYSIZE(wbuf), L"%d", dat->m_iValue );
  1409. SetWString( keyName, wbuf );
  1410. break;
  1411. case TYPE_UINT64:
  1412. {
  1413. swprintf( wbuf, Q_ARRAYSIZE(wbuf), L"%lld", *((uint64 *)(dat->m_sValue)) );
  1414. SetWString( keyName, wbuf );
  1415. }
  1416. break;
  1417. case TYPE_COLOR:
  1418. swprintf( wbuf, Q_ARRAYSIZE(wbuf), L"%d %d %d %d", dat->m_Color[0], dat->m_Color[1], dat->m_Color[2], dat->m_Color[3] );
  1419. SetWString( keyName, wbuf );
  1420. break;
  1421. case TYPE_WSTRING:
  1422. break;
  1423. case TYPE_STRING:
  1424. {
  1425. int bufSize = V_strlen(dat->m_sValue) + 1;
  1426. wchar_t *pWBuf = new wchar_t[ bufSize ];
  1427. int result = V_UTF8ToUnicode(dat->m_sValue, pWBuf, bufSize * sizeof( wchar_t ) );
  1428. if ( result >= 0 ) // may be a zero length string
  1429. {
  1430. SetWString( keyName, pWBuf);
  1431. }
  1432. else
  1433. {
  1434. delete [] pWBuf;
  1435. return defaultValue;
  1436. }
  1437. delete [] pWBuf;
  1438. break;
  1439. }
  1440. default:
  1441. return defaultValue;
  1442. };
  1443. return (const wchar_t* )dat->m_wsValue;
  1444. }
  1445. return defaultValue;
  1446. }
  1447. //-----------------------------------------------------------------------------
  1448. // Purpose: Gets a color
  1449. //-----------------------------------------------------------------------------
  1450. Color KeyValues::GetColor( const char *keyName , const Color& defaultColor )
  1451. {
  1452. Color color = defaultColor;
  1453. KeyValues *dat = FindKey( keyName , false );
  1454. if ( dat )
  1455. {
  1456. if ( dat->m_iDataType == TYPE_COLOR )
  1457. {
  1458. color[0] = dat->m_Color[0];
  1459. color[1] = dat->m_Color[1];
  1460. color[2] = dat->m_Color[2];
  1461. color[3] = dat->m_Color[3];
  1462. }
  1463. else if ( dat->m_iDataType == TYPE_FLOAT )
  1464. {
  1465. color[0] = (unsigned char)dat->m_flValue;
  1466. }
  1467. else if ( dat->m_iDataType == TYPE_INT )
  1468. {
  1469. color[0] = (unsigned char)dat->m_iValue;
  1470. }
  1471. else if ( dat->m_iDataType == TYPE_STRING )
  1472. {
  1473. // parse the colors out of the string
  1474. float a = 0, b = 0, c = 0, d = 0;
  1475. sscanf(dat->m_sValue, "%f %f %f %f", &a, &b, &c, &d);
  1476. color[0] = (unsigned char)a;
  1477. color[1] = (unsigned char)b;
  1478. color[2] = (unsigned char)c;
  1479. color[3] = (unsigned char)d;
  1480. }
  1481. }
  1482. return color;
  1483. }
  1484. //-----------------------------------------------------------------------------
  1485. // Purpose: Sets a color
  1486. //-----------------------------------------------------------------------------
  1487. void KeyValues::SetColor( const char *keyName, Color value)
  1488. {
  1489. KeyValues *dat = FindKey( keyName, true );
  1490. if ( dat )
  1491. {
  1492. dat->m_iDataType = TYPE_COLOR;
  1493. dat->m_Color[0] = value[0];
  1494. dat->m_Color[1] = value[1];
  1495. dat->m_Color[2] = value[2];
  1496. dat->m_Color[3] = value[3];
  1497. }
  1498. }
  1499. void KeyValues::SetStringValue( char const *strValue )
  1500. {
  1501. // delete the old value
  1502. delete [] m_sValue;
  1503. // make sure we're not storing the WSTRING - as we're converting over to STRING
  1504. delete [] m_wsValue;
  1505. m_wsValue = NULL;
  1506. if (!strValue)
  1507. {
  1508. // ensure a valid value
  1509. strValue = "";
  1510. }
  1511. // allocate memory for the new value and copy it in
  1512. int len = V_strlen( strValue );
  1513. m_sValue = new char[len + 1];
  1514. V_memcpy( m_sValue, strValue, len+1 );
  1515. m_iDataType = TYPE_STRING;
  1516. }
  1517. //-----------------------------------------------------------------------------
  1518. // Purpose: Set the string value of a keyName.
  1519. //-----------------------------------------------------------------------------
  1520. void KeyValues::SetString( const char *keyName, const char *value )
  1521. {
  1522. if ( KeyValues *dat = FindKey( keyName, true ) )
  1523. {
  1524. dat->SetStringValue( value );
  1525. }
  1526. }
  1527. //-----------------------------------------------------------------------------
  1528. // Purpose: Set the string value of a keyName.
  1529. //-----------------------------------------------------------------------------
  1530. void KeyValues::SetWString( const char *keyName, const wchar_t *value )
  1531. {
  1532. KeyValues *dat = FindKey( keyName, true );
  1533. if ( dat )
  1534. {
  1535. // delete the old value
  1536. delete [] dat->m_wsValue;
  1537. // make sure we're not storing the STRING - as we're converting over to WSTRING
  1538. delete [] dat->m_sValue;
  1539. dat->m_sValue = NULL;
  1540. if (!value)
  1541. {
  1542. // ensure a valid value
  1543. value = L"";
  1544. }
  1545. // allocate memory for the new value and copy it in
  1546. int len = V_wcslen( value );
  1547. dat->m_wsValue = new wchar_t[len + 1];
  1548. V_memcpy( dat->m_wsValue, value, (len+1) * sizeof(wchar_t) );
  1549. dat->m_iDataType = TYPE_WSTRING;
  1550. }
  1551. }
  1552. //-----------------------------------------------------------------------------
  1553. // Purpose: Set the integer value of a keyName.
  1554. //-----------------------------------------------------------------------------
  1555. void KeyValues::SetInt( const char *keyName, int value )
  1556. {
  1557. KeyValues *dat = FindKey( keyName, true );
  1558. if ( dat )
  1559. {
  1560. dat->m_iValue = value;
  1561. dat->m_iDataType = TYPE_INT;
  1562. }
  1563. }
  1564. //-----------------------------------------------------------------------------
  1565. // Purpose: Set the integer value of a keyName.
  1566. //-----------------------------------------------------------------------------
  1567. void KeyValues::SetUint64( const char *keyName, uint64 value )
  1568. {
  1569. KeyValues *dat = FindKey( keyName, true );
  1570. if ( dat )
  1571. {
  1572. // delete the old value
  1573. delete [] dat->m_sValue;
  1574. // make sure we're not storing the WSTRING - as we're converting over to STRING
  1575. delete [] dat->m_wsValue;
  1576. dat->m_wsValue = NULL;
  1577. dat->m_sValue = new char[sizeof(uint64)];
  1578. *((uint64 *)dat->m_sValue) = value;
  1579. dat->m_iDataType = TYPE_UINT64;
  1580. }
  1581. }
  1582. //-----------------------------------------------------------------------------
  1583. // Purpose: Set the float value of a keyName.
  1584. //-----------------------------------------------------------------------------
  1585. void KeyValues::SetFloat( const char *keyName, float value )
  1586. {
  1587. KeyValues *dat = FindKey( keyName, true );
  1588. if ( dat )
  1589. {
  1590. dat->m_flValue = value;
  1591. dat->m_iDataType = TYPE_FLOAT;
  1592. }
  1593. }
  1594. void KeyValues::SetName( const char * setName )
  1595. {
  1596. HKeySymbol hCaseSensitiveKeyName = INVALID_KEY_SYMBOL, hCaseInsensitiveKeyName = INVALID_KEY_SYMBOL;
  1597. hCaseSensitiveKeyName = KeyValuesSystem()->GetSymbolForStringCaseSensitive( hCaseInsensitiveKeyName, setName );
  1598. m_iKeyName = hCaseInsensitiveKeyName;
  1599. SPLIT_3_BYTES_INTO_1_AND_2( m_iKeyNameCaseSensitive1, m_iKeyNameCaseSensitive2, hCaseSensitiveKeyName );
  1600. }
  1601. //-----------------------------------------------------------------------------
  1602. // Purpose: Set the pointer value of a keyName.
  1603. //-----------------------------------------------------------------------------
  1604. void KeyValues::SetPtr( const char *keyName, void *value )
  1605. {
  1606. KeyValues *dat = FindKey( keyName, true );
  1607. if ( dat )
  1608. {
  1609. dat->m_pValue = value;
  1610. dat->m_iDataType = TYPE_PTR;
  1611. }
  1612. }
  1613. void KeyValues::RecursiveCopyKeyValues( KeyValues& src )
  1614. {
  1615. // garymcthack - need to check this code for possible buffer overruns.
  1616. m_iKeyName = src.m_iKeyName;
  1617. m_iKeyNameCaseSensitive1 = src.m_iKeyNameCaseSensitive1;
  1618. m_iKeyNameCaseSensitive2 = src.m_iKeyNameCaseSensitive2;
  1619. if( !src.m_pSub )
  1620. {
  1621. m_iDataType = src.m_iDataType;
  1622. char buf[256];
  1623. switch( src.m_iDataType )
  1624. {
  1625. case TYPE_NONE:
  1626. break;
  1627. case TYPE_STRING:
  1628. if( src.m_sValue )
  1629. {
  1630. int len = V_strlen(src.m_sValue) + 1;
  1631. m_sValue = new char[len];
  1632. V_strncpy( m_sValue, src.m_sValue, len );
  1633. }
  1634. break;
  1635. case TYPE_INT:
  1636. {
  1637. m_iValue = src.m_iValue;
  1638. V_snprintf( buf,sizeof(buf), "%d", m_iValue );
  1639. int len = V_strlen(buf) + 1;
  1640. m_sValue = new char[len];
  1641. V_strncpy( m_sValue, buf, len );
  1642. }
  1643. break;
  1644. case TYPE_FLOAT:
  1645. {
  1646. m_flValue = src.m_flValue;
  1647. V_snprintf( buf,sizeof(buf), "%f", m_flValue );
  1648. int len = V_strlen(buf) + 1;
  1649. m_sValue = new char[len];
  1650. V_strncpy( m_sValue, buf, len );
  1651. }
  1652. break;
  1653. case TYPE_PTR:
  1654. {
  1655. m_pValue = src.m_pValue;
  1656. }
  1657. break;
  1658. case TYPE_UINT64:
  1659. {
  1660. m_sValue = new char[sizeof(uint64)];
  1661. V_memcpy( m_sValue, src.m_sValue, sizeof(uint64) );
  1662. }
  1663. break;
  1664. case TYPE_COLOR:
  1665. {
  1666. m_Color[0] = src.m_Color[0];
  1667. m_Color[1] = src.m_Color[1];
  1668. m_Color[2] = src.m_Color[2];
  1669. m_Color[3] = src.m_Color[3];
  1670. }
  1671. break;
  1672. default:
  1673. {
  1674. // do nothing . .what the heck is this?
  1675. Assert( 0 );
  1676. }
  1677. break;
  1678. }
  1679. }
  1680. #if 0
  1681. KeyValues *pDst = this;
  1682. for ( KeyValues *pSrc = src.m_pSub; pSrc; pSrc = pSrc->m_pPeer )
  1683. {
  1684. if ( pSrc->m_pSub )
  1685. {
  1686. pDst->m_pSub = new KeyValues( pSrc->m_pSub->getName() );
  1687. pDst->m_pSub->RecursiveCopyKeyValues( *pSrc->m_pSub );
  1688. }
  1689. else
  1690. {
  1691. // copy non-empty keys
  1692. if ( pSrc->m_sValue && *(pSrc->m_sValue) )
  1693. {
  1694. pDst->m_pPeer = new KeyValues(
  1695. }
  1696. }
  1697. }
  1698. #endif
  1699. // Handle the immediate child
  1700. if( src.m_pSub )
  1701. {
  1702. m_pSub = new KeyValues( NULL );
  1703. m_pSub->RecursiveCopyKeyValues( *src.m_pSub );
  1704. }
  1705. // Handle the immediate peer
  1706. if( src.m_pPeer )
  1707. {
  1708. m_pPeer = new KeyValues( NULL );
  1709. m_pPeer->RecursiveCopyKeyValues( *src.m_pPeer );
  1710. }
  1711. }
  1712. KeyValues& KeyValues::operator=( KeyValues& src )
  1713. {
  1714. RemoveEverything();
  1715. Init(); // reset all values
  1716. RecursiveCopyKeyValues( src );
  1717. return *this;
  1718. }
  1719. //-----------------------------------------------------------------------------
  1720. // Make a new copy of all subkeys, add them all to the passed-in keyvalues
  1721. //-----------------------------------------------------------------------------
  1722. void KeyValues::CopySubkeys( KeyValues *pParent ) const
  1723. {
  1724. // recursively copy subkeys
  1725. // Also maintain ordering....
  1726. KeyValues *pPrev = NULL;
  1727. for ( KeyValues *sub = m_pSub; sub != NULL; sub = sub->m_pPeer )
  1728. {
  1729. // take a copy of the subkey
  1730. KeyValues *dat = sub->MakeCopy();
  1731. // add into subkey list
  1732. if (pPrev)
  1733. {
  1734. pPrev->m_pPeer = dat;
  1735. }
  1736. else
  1737. {
  1738. pParent->m_pSub = dat;
  1739. }
  1740. dat->m_pPeer = NULL;
  1741. pPrev = dat;
  1742. }
  1743. }
  1744. //-----------------------------------------------------------------------------
  1745. // Purpose: Makes a copy of the whole key-value pair set
  1746. //-----------------------------------------------------------------------------
  1747. KeyValues *KeyValues::MakeCopy( void ) const
  1748. {
  1749. KeyValues *newKeyValue = new KeyValues(GetName());
  1750. // copy data
  1751. newKeyValue->m_iDataType = m_iDataType;
  1752. switch ( m_iDataType )
  1753. {
  1754. case TYPE_STRING:
  1755. {
  1756. if ( m_sValue )
  1757. {
  1758. int len = V_strlen( m_sValue );
  1759. Assert( !newKeyValue->m_sValue );
  1760. newKeyValue->m_sValue = new char[len + 1];
  1761. V_memcpy( newKeyValue->m_sValue, m_sValue, len+1 );
  1762. }
  1763. }
  1764. break;
  1765. case TYPE_WSTRING:
  1766. {
  1767. if ( m_wsValue )
  1768. {
  1769. int len = V_wcslen( m_wsValue );
  1770. newKeyValue->m_wsValue = new wchar_t[len+1];
  1771. V_memcpy( newKeyValue->m_wsValue, m_wsValue, (len+1)*sizeof(wchar_t));
  1772. }
  1773. }
  1774. break;
  1775. case TYPE_INT:
  1776. newKeyValue->m_iValue = m_iValue;
  1777. break;
  1778. case TYPE_FLOAT:
  1779. newKeyValue->m_flValue = m_flValue;
  1780. break;
  1781. case TYPE_PTR:
  1782. newKeyValue->m_pValue = m_pValue;
  1783. break;
  1784. case TYPE_COLOR:
  1785. newKeyValue->m_Color[0] = m_Color[0];
  1786. newKeyValue->m_Color[1] = m_Color[1];
  1787. newKeyValue->m_Color[2] = m_Color[2];
  1788. newKeyValue->m_Color[3] = m_Color[3];
  1789. break;
  1790. case TYPE_UINT64:
  1791. newKeyValue->m_sValue = new char[sizeof(uint64)];
  1792. V_memcpy( newKeyValue->m_sValue, m_sValue, sizeof(uint64) );
  1793. break;
  1794. };
  1795. // recursively copy subkeys
  1796. CopySubkeys( newKeyValue );
  1797. return newKeyValue;
  1798. }
  1799. //-----------------------------------------------------------------------------
  1800. // Purpose: Check if a keyName has no value assigned to it.
  1801. //-----------------------------------------------------------------------------
  1802. bool KeyValues::IsEmpty(const char *keyName)
  1803. {
  1804. KeyValues *dat = FindKey(keyName, false);
  1805. if (!dat)
  1806. return true;
  1807. if (dat->m_iDataType == TYPE_NONE && dat->m_pSub == NULL)
  1808. return true;
  1809. return false;
  1810. }
  1811. //-----------------------------------------------------------------------------
  1812. // Purpose: Clear out all subkeys, and the current value
  1813. //-----------------------------------------------------------------------------
  1814. void KeyValues::Clear( void )
  1815. {
  1816. delete m_pSub;
  1817. m_pSub = NULL;
  1818. m_iDataType = TYPE_NONE;
  1819. }
  1820. //-----------------------------------------------------------------------------
  1821. // Purpose: Get the data type of the value stored in a keyName
  1822. //-----------------------------------------------------------------------------
  1823. KeyValues::types_t KeyValues::GetDataType(const char *keyName)
  1824. {
  1825. KeyValues *dat = FindKey(keyName, false);
  1826. if (dat)
  1827. return (types_t)dat->m_iDataType;
  1828. return TYPE_NONE;
  1829. }
  1830. KeyValues::types_t KeyValues::GetDataType( void ) const
  1831. {
  1832. return (types_t)m_iDataType;
  1833. }
  1834. //-----------------------------------------------------------------------------
  1835. // Purpose:
  1836. // Input : includedKeys -
  1837. //-----------------------------------------------------------------------------
  1838. void KeyValues::AppendIncludedKeys( CUtlVector< KeyValues * >& includedKeys )
  1839. {
  1840. // Append any included keys, too...
  1841. int includeCount = includedKeys.Count();
  1842. int i;
  1843. for ( i = 0; i < includeCount; i++ )
  1844. {
  1845. KeyValues *kv = includedKeys[ i ];
  1846. Assert( kv );
  1847. KeyValues *insertSpot = this;
  1848. while ( insertSpot->GetNextKey() )
  1849. {
  1850. insertSpot = insertSpot->GetNextKey();
  1851. }
  1852. insertSpot->SetNextKey( kv );
  1853. }
  1854. }
  1855. void KeyValues::ParseIncludedKeys( char const *resourceName, const char *filetoinclude,
  1856. IBaseFileSystem* pFileSystem, const char *pPathID, CUtlVector< KeyValues * >& includedKeys, GetSymbolProc_t pfnEvaluateSymbolProc )
  1857. {
  1858. Assert( resourceName );
  1859. Assert( filetoinclude );
  1860. Assert( pFileSystem );
  1861. // Load it...
  1862. if ( !pFileSystem )
  1863. {
  1864. return;
  1865. }
  1866. // Get relative subdirectory
  1867. char fullpath[ 512 ];
  1868. V_strncpy( fullpath, resourceName, sizeof( fullpath ) );
  1869. // Strip off characters back to start or first /
  1870. bool done = false;
  1871. int len = V_strlen( fullpath );
  1872. while ( !done )
  1873. {
  1874. if ( len <= 0 )
  1875. {
  1876. break;
  1877. }
  1878. if ( fullpath[ len - 1 ] == '\\' ||
  1879. fullpath[ len - 1 ] == '/' )
  1880. {
  1881. break;
  1882. }
  1883. // zero it
  1884. fullpath[ len - 1 ] = 0;
  1885. --len;
  1886. }
  1887. // Append included file
  1888. V_strncat( fullpath, filetoinclude, sizeof( fullpath ), COPY_ALL_CHARACTERS );
  1889. KeyValues *newKV = new KeyValues( fullpath );
  1890. // CUtlSymbol save = s_CurrentFileSymbol; // did that had any use ???
  1891. newKV->UsesEscapeSequences( m_bHasEscapeSequences != 0 ); // use same format as parent
  1892. if ( newKV->LoadFromFile( pFileSystem, fullpath, pPathID, pfnEvaluateSymbolProc ) )
  1893. {
  1894. includedKeys.AddToTail( newKV );
  1895. }
  1896. else
  1897. {
  1898. DevMsg( "KeyValues::ParseIncludedKeys: Couldn't load included keyvalue file %s\n", fullpath );
  1899. delete newKV;
  1900. }
  1901. // s_CurrentFileSymbol = save;
  1902. }
  1903. //-----------------------------------------------------------------------------
  1904. // Purpose:
  1905. // Input : baseKeys -
  1906. //-----------------------------------------------------------------------------
  1907. void KeyValues::MergeBaseKeys( CUtlVector< KeyValues * >& baseKeys )
  1908. {
  1909. int includeCount = baseKeys.Count();
  1910. int i;
  1911. for ( i = 0; i < includeCount; i++ )
  1912. {
  1913. KeyValues *kv = baseKeys[ i ];
  1914. Assert( kv );
  1915. RecursiveMergeKeyValues( kv );
  1916. }
  1917. }
  1918. //-----------------------------------------------------------------------------
  1919. // Purpose:
  1920. // Input : baseKV - keyvalues we're basing ourselves on
  1921. //-----------------------------------------------------------------------------
  1922. void KeyValues::RecursiveMergeKeyValues( KeyValues *baseKV )
  1923. {
  1924. // Merge ourselves
  1925. // we always want to keep our value, so nothing to do here
  1926. // Now merge our children
  1927. for ( KeyValues *baseChild = baseKV->m_pSub; baseChild != NULL; baseChild = baseChild->m_pPeer )
  1928. {
  1929. // for each child in base, see if we have a matching kv
  1930. bool bFoundMatch = false;
  1931. // If we have a child by the same name, merge those keys
  1932. for ( KeyValues *newChild = m_pSub; newChild != NULL; newChild = newChild->m_pPeer )
  1933. {
  1934. if ( !V_strcmp( baseChild->GetName(), newChild->GetName() ) )
  1935. {
  1936. newChild->RecursiveMergeKeyValues( baseChild );
  1937. bFoundMatch = true;
  1938. break;
  1939. }
  1940. }
  1941. // If not merged, append this key
  1942. if ( !bFoundMatch )
  1943. {
  1944. KeyValues *dat = baseChild->MakeCopy();
  1945. Assert( dat );
  1946. AddSubKey( dat );
  1947. }
  1948. }
  1949. }
  1950. //-----------------------------------------------------------------------------
  1951. // Returns whether a keyvalues conditional expression string evaluates to true or false
  1952. //-----------------------------------------------------------------------------
  1953. bool KeyValues::EvaluateConditional( const char *pExpressionString, GetSymbolProc_t pfnEvaluateSymbolProc )
  1954. {
  1955. // evaluate the infix expression, calling the symbol proc to resolve each symbol's value
  1956. bool bResult = false;
  1957. bool bValid = g_ExpressionEvaluator.Evaluate( bResult, pExpressionString, pfnEvaluateSymbolProc );
  1958. if ( !bValid )
  1959. {
  1960. g_KeyValuesErrorStack.ReportError( "KV Conditional Evaluation Error" );
  1961. }
  1962. return bResult;
  1963. }
  1964. // prevent two threads from entering this at the same time and trying to share the global error reporting and parse buffers
  1965. static CThreadFastMutex g_KVMutex;
  1966. //-----------------------------------------------------------------------------
  1967. // Read from a buffer...
  1968. //-----------------------------------------------------------------------------
  1969. bool KeyValues::LoadFromBuffer( char const *resourceName, CUtlBuffer &buf, IBaseFileSystem* pFileSystem, const char *pPathID, GetSymbolProc_t pfnEvaluateSymbolProc )
  1970. {
  1971. AUTO_LOCK_FM( g_KVMutex );
  1972. if ( IsGameConsole() )
  1973. {
  1974. // Let's not crash if the buffer is empty
  1975. unsigned char *pData = buf.Size() > 0 ? (unsigned char *)buf.PeekGet() : NULL;
  1976. if ( pData && (unsigned int)pData[0] == KV_BINARY_POOLED_FORMAT )
  1977. {
  1978. // skip past binary marker
  1979. buf.GetUnsignedChar();
  1980. // get the pool identifier, allows the fs to bind the expected string pool
  1981. unsigned int poolKey = buf.GetUnsignedInt();
  1982. RemoveEverything();
  1983. Init();
  1984. return ReadAsBinaryPooledFormat( buf, pFileSystem, poolKey, pfnEvaluateSymbolProc );
  1985. }
  1986. }
  1987. KeyValues *pPreviousKey = NULL;
  1988. KeyValues *pCurrentKey = this;
  1989. CUtlVector< KeyValues * > includedKeys;
  1990. CUtlVector< KeyValues * > baseKeys;
  1991. bool wasQuoted;
  1992. bool wasConditional;
  1993. CKeyValuesTokenReader tokenReader( this, buf );
  1994. g_KeyValuesErrorStack.SetFilename( resourceName );
  1995. do
  1996. {
  1997. bool bAccepted = true;
  1998. // the first thing must be a key
  1999. const char *s = tokenReader.ReadToken( wasQuoted, wasConditional );
  2000. if ( !buf.IsValid() || !s )
  2001. break;
  2002. if ( !wasQuoted && *s == '\0' )
  2003. {
  2004. // non quoted empty strings stop parsing
  2005. // quoted empty strings are allowed to support unnnamed KV sections
  2006. break;
  2007. }
  2008. if ( !V_stricmp( s, "#include" ) ) // special include macro (not a key name)
  2009. {
  2010. s = tokenReader.ReadToken( wasQuoted, wasConditional );
  2011. // Name of subfile to load is now in s
  2012. if ( !s || *s == 0 )
  2013. {
  2014. g_KeyValuesErrorStack.ReportError("#include is NULL " );
  2015. }
  2016. else
  2017. {
  2018. ParseIncludedKeys( resourceName, s, pFileSystem, pPathID, includedKeys, pfnEvaluateSymbolProc );
  2019. }
  2020. continue;
  2021. }
  2022. else if ( !V_stricmp( s, "#base" ) )
  2023. {
  2024. s = tokenReader.ReadToken( wasQuoted, wasConditional );
  2025. // Name of subfile to load is now in s
  2026. if ( !s || *s == 0 )
  2027. {
  2028. g_KeyValuesErrorStack.ReportError("#base is NULL " );
  2029. }
  2030. else
  2031. {
  2032. ParseIncludedKeys( resourceName, s, pFileSystem, pPathID, baseKeys, pfnEvaluateSymbolProc );
  2033. }
  2034. continue;
  2035. }
  2036. if ( !pCurrentKey )
  2037. {
  2038. pCurrentKey = new KeyValues( s );
  2039. Assert( pCurrentKey );
  2040. pCurrentKey->UsesEscapeSequences( m_bHasEscapeSequences != 0 ); // same format has parent use
  2041. if ( pPreviousKey )
  2042. {
  2043. pPreviousKey->SetNextKey( pCurrentKey );
  2044. }
  2045. }
  2046. else
  2047. {
  2048. pCurrentKey->SetName( s );
  2049. }
  2050. // get the '{'
  2051. s = tokenReader.ReadToken( wasQuoted, wasConditional );
  2052. if ( wasConditional )
  2053. {
  2054. bAccepted = EvaluateConditional( s, pfnEvaluateSymbolProc );
  2055. // Now get the '{'
  2056. s = tokenReader.ReadToken( wasQuoted, wasConditional );
  2057. }
  2058. if ( s && *s == '{' && !wasQuoted )
  2059. {
  2060. // header is valid so load the file
  2061. pCurrentKey->RecursiveLoadFromBuffer( resourceName, tokenReader, pfnEvaluateSymbolProc );
  2062. }
  2063. else
  2064. {
  2065. g_KeyValuesErrorStack.ReportError("LoadFromBuffer: missing {" );
  2066. }
  2067. if ( !bAccepted )
  2068. {
  2069. if ( pPreviousKey )
  2070. {
  2071. pPreviousKey->SetNextKey( NULL );
  2072. }
  2073. pCurrentKey->Clear();
  2074. }
  2075. else
  2076. {
  2077. pPreviousKey = pCurrentKey;
  2078. pCurrentKey = NULL;
  2079. }
  2080. } while ( buf.IsValid() );
  2081. AppendIncludedKeys( includedKeys );
  2082. {
  2083. // delete included keys!
  2084. int i;
  2085. for ( i = includedKeys.Count() - 1; i > 0; i-- )
  2086. {
  2087. KeyValues *kv = includedKeys[ i ];
  2088. delete kv;
  2089. }
  2090. }
  2091. MergeBaseKeys( baseKeys );
  2092. {
  2093. // delete base keys!
  2094. int i;
  2095. for ( i = baseKeys.Count() - 1; i >= 0; i-- )
  2096. {
  2097. KeyValues *kv = baseKeys[ i ];
  2098. delete kv;
  2099. }
  2100. }
  2101. bool bErrors = g_KeyValuesErrorStack.EncounteredAnyErrors();
  2102. g_KeyValuesErrorStack.SetFilename( "" );
  2103. g_KeyValuesErrorStack.ClearErrorFlag();
  2104. return !bErrors;
  2105. }
  2106. //-----------------------------------------------------------------------------
  2107. // Read from a buffer...
  2108. //-----------------------------------------------------------------------------
  2109. bool KeyValues::LoadFromBuffer( char const *resourceName, const char *pBuffer, IBaseFileSystem* pFileSystem, const char *pPathID, GetSymbolProc_t pfnEvaluateSymbolProc )
  2110. {
  2111. if ( !pBuffer )
  2112. return true;
  2113. if ( IsGameConsole() && (unsigned int)((unsigned char *)pBuffer)[0] == KV_BINARY_POOLED_FORMAT )
  2114. {
  2115. // bad, got a binary compiled KV file through an unexpected text path
  2116. // not all paths support binary compiled kv, needs to get fixed
  2117. // need to have caller supply buffer length (strlen not valid), this interface change was never plumbed
  2118. Warning( "ERROR! Binary compiled KV '%s' in an unexpected handler\n", resourceName );
  2119. Assert( 0 );
  2120. return false;
  2121. }
  2122. int nLen = V_strlen( pBuffer );
  2123. CUtlBuffer buf( pBuffer, nLen, CUtlBuffer::READ_ONLY | CUtlBuffer::TEXT_BUFFER );
  2124. // Translate Unicode files into UTF-8 before proceeding
  2125. if ( nLen > 2 && (uint8)pBuffer[0] == 0xFF && (uint8)pBuffer[1] == 0xFE )
  2126. {
  2127. int nUTF8Len = V_UnicodeToUTF8( (wchar_t*)(pBuffer+2), NULL, 0 );
  2128. char *pUTF8Buf = new char[nUTF8Len];
  2129. V_UnicodeToUTF8( (wchar_t*)(pBuffer+2), pUTF8Buf, nUTF8Len );
  2130. buf.AssumeMemory( pUTF8Buf, nUTF8Len, nUTF8Len, CUtlBuffer::READ_ONLY | CUtlBuffer::TEXT_BUFFER );
  2131. }
  2132. return LoadFromBuffer( resourceName, buf, pFileSystem, pPathID, pfnEvaluateSymbolProc );
  2133. }
  2134. //-----------------------------------------------------------------------------
  2135. // Purpose:
  2136. //-----------------------------------------------------------------------------
  2137. void KeyValues::RecursiveLoadFromBuffer( char const *resourceName, CKeyValuesTokenReader &tokenReader, GetSymbolProc_t pfnEvaluateSymbolProc )
  2138. {
  2139. CKeyErrorContext errorReport( GetNameSymbolCaseSensitive() );
  2140. bool wasQuoted;
  2141. bool wasConditional;
  2142. if ( errorReport.GetStackLevel() > 100 )
  2143. {
  2144. g_KeyValuesErrorStack.ReportError( "RecursiveLoadFromBuffer: recursion overflow" );
  2145. return;
  2146. }
  2147. // keep this out of the stack until a key is parsed
  2148. CKeyErrorContext errorKey( INVALID_KEY_SYMBOL );
  2149. // Locate the last child. (Almost always, we will not have any children.)
  2150. // We maintain the pointer to the last child here, so we don't have to re-locate
  2151. // it each time we append the next subkey, which causes O(N^2) time
  2152. KeyValues *pLastChild = FindLastSubKey();
  2153. // Keep parsing until we hit the closing brace which terminates this block, or a parse error
  2154. while ( 1 )
  2155. {
  2156. bool bAccepted = true;
  2157. // get the key name
  2158. const char * name = tokenReader.ReadToken( wasQuoted, wasConditional );
  2159. if ( !name ) // EOF stop reading
  2160. {
  2161. g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got EOF instead of keyname" );
  2162. break;
  2163. }
  2164. if ( !*name ) // empty token, maybe "" or EOF
  2165. {
  2166. g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got empty keyname" );
  2167. break;
  2168. }
  2169. if ( *name == '}' && !wasQuoted ) // top level closed, stop reading
  2170. break;
  2171. // Always create the key; note that this could potentially
  2172. // cause some duplication, but that's what we want sometimes
  2173. KeyValues *dat = CreateKeyUsingKnownLastChild( name, pLastChild );
  2174. errorKey.Reset( dat->GetNameSymbolCaseSensitive() );
  2175. // get the value
  2176. const char * value = tokenReader.ReadToken( wasQuoted, wasConditional );
  2177. bool bFoundConditional = wasConditional;
  2178. if ( wasConditional && value )
  2179. {
  2180. bAccepted = EvaluateConditional( value, pfnEvaluateSymbolProc );
  2181. // get the real value
  2182. value = tokenReader.ReadToken( wasQuoted, wasConditional );
  2183. }
  2184. if ( !value )
  2185. {
  2186. g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got NULL key" );
  2187. break;
  2188. }
  2189. // support the '=' as an assignment, makes multiple-keys-on-one-line easier to read in a keyvalues file
  2190. if ( *value == '=' && !wasQuoted )
  2191. {
  2192. // just skip over it
  2193. value = tokenReader.ReadToken( wasQuoted, wasConditional );
  2194. bFoundConditional = wasConditional;
  2195. if ( wasConditional && value )
  2196. {
  2197. bAccepted = EvaluateConditional( value, pfnEvaluateSymbolProc );
  2198. // get the real value
  2199. value = tokenReader.ReadToken( wasQuoted, wasConditional );
  2200. }
  2201. if ( bFoundConditional && bAccepted )
  2202. {
  2203. // if there is a conditional key see if we already have the key defined and blow it away, last one in the list wins
  2204. KeyValues *pExistingKey = this->FindKey( dat->GetNameSymbol() );
  2205. if ( pExistingKey && pExistingKey != dat )
  2206. {
  2207. this->RemoveSubKey( pExistingKey );
  2208. pExistingKey->deleteThis();
  2209. }
  2210. }
  2211. }
  2212. if ( !value )
  2213. {
  2214. g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got NULL key" );
  2215. break;
  2216. }
  2217. if ( *value == '}' && !wasQuoted )
  2218. {
  2219. g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got } in key" );
  2220. break;
  2221. }
  2222. if ( *value == '{' && !wasQuoted )
  2223. {
  2224. // this isn't a key, it's a section
  2225. errorKey.Reset( INVALID_KEY_SYMBOL );
  2226. // sub value list
  2227. dat->RecursiveLoadFromBuffer( resourceName, tokenReader, pfnEvaluateSymbolProc );
  2228. }
  2229. else
  2230. {
  2231. if ( wasConditional )
  2232. {
  2233. g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got conditional between key and value" );
  2234. break;
  2235. }
  2236. if (dat->m_sValue)
  2237. {
  2238. delete[] dat->m_sValue;
  2239. dat->m_sValue = NULL;
  2240. }
  2241. int len = V_strlen( value );
  2242. // Here, let's determine if we got a float or an int....
  2243. char* pIEnd; // pos where int scan ended
  2244. char* pFEnd; // pos where float scan ended
  2245. const char* pSEnd = value + len ; // pos where token ends
  2246. long lval = strtol( value, &pIEnd, 10 );
  2247. float fval = (float)strtod( value, &pFEnd );
  2248. bool bOverflow = ( lval == LONG_MAX || lval == LONG_MIN ) && errno == ERANGE;
  2249. #ifdef POSIX
  2250. // strtod supports hex representation in strings under posix but we DON'T
  2251. // want that support in keyvalues, so undo it here if needed
  2252. if ( len > 1 && tolower(value[1]) == 'x' )
  2253. {
  2254. fval = 0.0f;
  2255. pFEnd = (char *)value;
  2256. }
  2257. #endif
  2258. if ( *value == 0 )
  2259. {
  2260. dat->m_iDataType = TYPE_STRING;
  2261. }
  2262. else if ( ( 18 == len ) && ( value[0] == '0' ) && ( value[1] == 'x' ) )
  2263. {
  2264. // an 18-byte value prefixed with "0x" (followed by 16 hex digits) is an int64 value
  2265. int64 retVal = 0;
  2266. for( int i=2; i < 2 + 16; i++ )
  2267. {
  2268. char digit = value[i];
  2269. if ( digit >= 'a' )
  2270. digit -= 'a' - ( '9' + 1 );
  2271. else
  2272. if ( digit >= 'A' )
  2273. digit -= 'A' - ( '9' + 1 );
  2274. retVal = ( retVal * 16 ) + ( digit - '0' );
  2275. }
  2276. dat->m_sValue = new char[sizeof(uint64)];
  2277. *((uint64 *)dat->m_sValue) = retVal;
  2278. dat->m_iDataType = TYPE_UINT64;
  2279. }
  2280. else if ( (pFEnd > pIEnd) && (pFEnd == pSEnd) )
  2281. {
  2282. dat->m_flValue = fval;
  2283. dat->m_iDataType = TYPE_FLOAT;
  2284. }
  2285. else if (pIEnd == pSEnd && !bOverflow)
  2286. {
  2287. dat->m_iValue = size_cast< int >( lval );
  2288. dat->m_iDataType = TYPE_INT;
  2289. }
  2290. else
  2291. {
  2292. dat->m_iDataType = TYPE_STRING;
  2293. }
  2294. if (dat->m_iDataType == TYPE_STRING)
  2295. {
  2296. // copy in the string information
  2297. dat->m_sValue = new char[len+1];
  2298. V_memcpy( dat->m_sValue, value, len+1 );
  2299. }
  2300. // Look ahead one token for a conditional tag
  2301. const char *peek = tokenReader.ReadToken( wasQuoted, wasConditional );
  2302. if ( wasConditional )
  2303. {
  2304. bAccepted = EvaluateConditional( peek, pfnEvaluateSymbolProc );
  2305. }
  2306. else
  2307. {
  2308. tokenReader.SeekBackOneToken();
  2309. }
  2310. }
  2311. Assert( dat->m_pPeer == NULL );
  2312. if ( bAccepted )
  2313. {
  2314. Assert( pLastChild == NULL || pLastChild->m_pPeer == dat );
  2315. pLastChild = dat;
  2316. }
  2317. else
  2318. {
  2319. //this->RemoveSubKey( dat );
  2320. if ( pLastChild == NULL )
  2321. {
  2322. Assert( this->m_pSub == dat );
  2323. this->m_pSub = NULL;
  2324. }
  2325. else
  2326. {
  2327. Assert( pLastChild->m_pPeer == dat );
  2328. pLastChild->m_pPeer = NULL;
  2329. }
  2330. delete dat;
  2331. dat = NULL;
  2332. }
  2333. }
  2334. }
  2335. // writes KeyValue as binary data to buffer
  2336. bool KeyValues::WriteAsBinary( CUtlBuffer &buffer ) const
  2337. {
  2338. if ( buffer.IsText() ) // must be a binary buffer
  2339. return false;
  2340. if ( !buffer.IsValid() ) // must be valid, no overflows etc
  2341. return false;
  2342. // Write subkeys:
  2343. // loop through all our peers
  2344. for ( const KeyValues *dat = this; dat != NULL; dat = dat->m_pPeer )
  2345. {
  2346. // write type
  2347. buffer.PutUnsignedChar( dat->m_iDataType );
  2348. // write name
  2349. buffer.PutString( dat->GetName() );
  2350. // write type
  2351. switch (dat->m_iDataType)
  2352. {
  2353. case TYPE_NONE:
  2354. {
  2355. dat->m_pSub->WriteAsBinary( buffer );
  2356. break;
  2357. }
  2358. case TYPE_STRING:
  2359. {
  2360. if (dat->m_sValue && *(dat->m_sValue))
  2361. {
  2362. buffer.PutString( dat->m_sValue );
  2363. }
  2364. else
  2365. {
  2366. buffer.PutString( "" );
  2367. }
  2368. break;
  2369. }
  2370. case TYPE_WSTRING:
  2371. {
  2372. int nLength = dat->m_wsValue ? V_wcslen( dat->m_wsValue ) : 0;
  2373. buffer.PutShort( nLength );
  2374. for( int k = 0; k < nLength; ++ k )
  2375. {
  2376. buffer.PutShort( ( unsigned short ) dat->m_wsValue[k] );
  2377. }
  2378. break;
  2379. }
  2380. case TYPE_INT:
  2381. {
  2382. buffer.PutInt( dat->m_iValue );
  2383. break;
  2384. }
  2385. case TYPE_UINT64:
  2386. {
  2387. buffer.PutInt64( *((int64 *)dat->m_sValue) );
  2388. break;
  2389. }
  2390. case TYPE_FLOAT:
  2391. {
  2392. buffer.PutFloat( dat->m_flValue );
  2393. break;
  2394. }
  2395. case TYPE_COLOR:
  2396. {
  2397. buffer.PutUnsignedChar( dat->m_Color[0] );
  2398. buffer.PutUnsignedChar( dat->m_Color[1] );
  2399. buffer.PutUnsignedChar( dat->m_Color[2] );
  2400. buffer.PutUnsignedChar( dat->m_Color[3] );
  2401. break;
  2402. }
  2403. case TYPE_PTR:
  2404. {
  2405. #if defined( PLATFORM_64BITS )
  2406. // We only put an int here, because 32-bit clients do not expect 64 bits. It'll cause them to read the wrong
  2407. // amount of data and then crash. Longer term, we may bump this up in size on all platforms, but short term
  2408. // we don't really have much of a choice other than sticking in something that appears to not be NULL.
  2409. if ( dat->m_pValue != 0 && ( ( (int)(intp)dat->m_pValue ) == 0 ) )
  2410. buffer.PutInt( 31337 ); // Put not 0, but not a valid number. Yuck.
  2411. else
  2412. buffer.PutInt( ( (int)(intp)dat->m_pValue ) );
  2413. #else
  2414. buffer.PutPtr( dat->m_pValue );
  2415. #endif
  2416. break;
  2417. }
  2418. default:
  2419. break;
  2420. }
  2421. }
  2422. // write tail, marks end of peers
  2423. buffer.PutUnsignedChar( TYPE_NUMTYPES );
  2424. return buffer.IsValid();
  2425. }
  2426. // read KeyValues from binary buffer, returns true if parsing was successful
  2427. bool KeyValues::ReadAsBinary( CUtlBuffer &buffer, int nStackDepth )
  2428. {
  2429. if ( buffer.IsText() ) // must be a binary buffer
  2430. return false;
  2431. if ( !buffer.IsValid() ) // must be valid, no overflows etc
  2432. return false;
  2433. RemoveEverything(); // remove current content
  2434. Init(); // reset
  2435. if ( nStackDepth > 100 )
  2436. {
  2437. AssertMsgOnce( false, "KeyValues::ReadAsBinary() stack depth > 100\n" );
  2438. return false;
  2439. }
  2440. KeyValues *dat = this;
  2441. types_t type = (types_t)buffer.GetUnsignedChar();
  2442. // loop through all our peers
  2443. while ( true )
  2444. {
  2445. if ( type == TYPE_NUMTYPES )
  2446. break; // no more peers
  2447. dat->m_iDataType = type;
  2448. {
  2449. char token[ KEYVALUES_TOKEN_SIZE ];
  2450. buffer.GetString( token, KEYVALUES_TOKEN_SIZE - 1 );
  2451. token[ KEYVALUES_TOKEN_SIZE - 1 ] = 0;
  2452. dat->SetName( token );
  2453. }
  2454. switch ( type )
  2455. {
  2456. case TYPE_NONE:
  2457. {
  2458. dat->m_pSub = new KeyValues("");
  2459. dat->m_pSub->ReadAsBinary( buffer, nStackDepth + 1 );
  2460. break;
  2461. }
  2462. case TYPE_STRING:
  2463. {
  2464. char token[ KEYVALUES_TOKEN_SIZE ];
  2465. buffer.GetString( token, KEYVALUES_TOKEN_SIZE-1 );
  2466. token[KEYVALUES_TOKEN_SIZE-1] = 0;
  2467. int len = V_strlen( token );
  2468. dat->m_sValue = new char[len + 1];
  2469. V_memcpy( dat->m_sValue, token, len+1 );
  2470. break;
  2471. }
  2472. case TYPE_WSTRING:
  2473. {
  2474. int nLength = buffer.GetShort();
  2475. dat->m_wsValue = new wchar_t[nLength + 1];
  2476. for( int k = 0; k < nLength; ++ k )
  2477. {
  2478. dat->m_wsValue[k] = buffer.GetShort();
  2479. }
  2480. dat->m_wsValue[ nLength ] = 0;
  2481. break;
  2482. }
  2483. case TYPE_INT:
  2484. {
  2485. dat->m_iValue = buffer.GetInt();
  2486. break;
  2487. }
  2488. case TYPE_UINT64:
  2489. {
  2490. dat->m_sValue = new char[sizeof(uint64)];
  2491. *((uint64 *)dat->m_sValue) = buffer.GetInt64();
  2492. break;
  2493. }
  2494. case TYPE_FLOAT:
  2495. {
  2496. dat->m_flValue = buffer.GetFloat();
  2497. break;
  2498. }
  2499. case TYPE_COLOR:
  2500. {
  2501. dat->m_Color[0] = buffer.GetUnsignedChar();
  2502. dat->m_Color[1] = buffer.GetUnsignedChar();
  2503. dat->m_Color[2] = buffer.GetUnsignedChar();
  2504. dat->m_Color[3] = buffer.GetUnsignedChar();
  2505. break;
  2506. }
  2507. case TYPE_PTR:
  2508. {
  2509. #if defined( PLATFORM_64BITS )
  2510. // We need to ensure we only read 32 bits out of the stream because 32 bit clients only wrote
  2511. // 32 bits of data there. The actual pointer is irrelevant, all that we really care about here
  2512. // contractually is whether the pointer is zero or not zero.
  2513. dat->m_pValue = ( void* )( intp )buffer.GetInt();
  2514. #else
  2515. dat->m_pValue = buffer.GetPtr();
  2516. #endif
  2517. break;
  2518. }
  2519. default:
  2520. break;
  2521. }
  2522. if ( !buffer.IsValid() ) // error occured
  2523. return false;
  2524. type = (types_t)buffer.GetUnsignedChar();
  2525. if ( type == TYPE_NUMTYPES )
  2526. break;
  2527. // new peer follows
  2528. dat->m_pPeer = new KeyValues("");
  2529. dat = dat->m_pPeer;
  2530. }
  2531. return buffer.IsValid();
  2532. }
  2533. // writes KeyValue as binary data to buffer
  2534. // removes empty keys
  2535. bool KeyValues::WriteAsBinaryFiltered( CUtlBuffer &buffer )
  2536. {
  2537. if ( buffer.IsText() ) // must be a binary buffer
  2538. return false;
  2539. if ( !buffer.IsValid() ) // must be valid, no overflows etc
  2540. return false;
  2541. // Write header
  2542. buffer.PutString( GetName() );
  2543. // loop through all our keys writing them to buffer
  2544. for ( KeyValues *dat = m_pSub; dat != NULL; dat = dat->m_pPeer )
  2545. {
  2546. if ( dat->m_pSub )
  2547. {
  2548. buffer.PutUnsignedChar( TYPE_NONE );
  2549. dat->WriteAsBinaryFiltered( buffer );
  2550. }
  2551. else
  2552. {
  2553. if ( dat->m_iDataType == TYPE_NONE )
  2554. {
  2555. continue; // None with no subs will be filtered
  2556. }
  2557. // write type and name
  2558. buffer.PutUnsignedChar( dat->m_iDataType );
  2559. buffer.PutString( dat->GetName() );
  2560. // write type
  2561. switch (dat->m_iDataType)
  2562. {
  2563. case TYPE_STRING:
  2564. if (dat->m_sValue && *(dat->m_sValue))
  2565. {
  2566. buffer.PutString( dat->m_sValue );
  2567. }
  2568. else
  2569. {
  2570. buffer.PutString( "" );
  2571. }
  2572. break;
  2573. case TYPE_WSTRING:
  2574. {
  2575. int nLength = dat->m_wsValue ? Q_wcslen( dat->m_wsValue ) : 0;
  2576. buffer.PutShort( nLength );
  2577. for( int k = 0; k < nLength; ++ k )
  2578. {
  2579. buffer.PutShort( ( unsigned short ) dat->m_wsValue[k] );
  2580. }
  2581. break;
  2582. }
  2583. case TYPE_INT:
  2584. {
  2585. buffer.PutInt( dat->m_iValue );
  2586. break;
  2587. }
  2588. case TYPE_UINT64:
  2589. {
  2590. buffer.PutInt64( *((int64 *)dat->m_sValue) );
  2591. break;
  2592. }
  2593. case TYPE_FLOAT:
  2594. {
  2595. buffer.PutFloat( dat->m_flValue );
  2596. break;
  2597. }
  2598. case TYPE_COLOR:
  2599. {
  2600. buffer.PutUnsignedChar( dat->m_Color[0] );
  2601. buffer.PutUnsignedChar( dat->m_Color[1] );
  2602. buffer.PutUnsignedChar( dat->m_Color[2] );
  2603. buffer.PutUnsignedChar( dat->m_Color[3] );
  2604. break;
  2605. }
  2606. case TYPE_PTR:
  2607. {
  2608. #if defined( PLATFORM_64BITS )
  2609. // We only put an int here, because 32-bit clients do not expect 64 bits. It'll cause them to read the wrong
  2610. // amount of data and then crash. Longer term, we may bump this up in size on all platforms, but short term
  2611. // we don't really have much of a choice other than sticking in something that appears to not be NULL.
  2612. if ( dat->m_pValue != 0 && ( ( (int)(intp)dat->m_pValue ) == 0 ) )
  2613. buffer.PutInt( 31337 ); // Put not 0, but not a valid number. Yuck.
  2614. else
  2615. buffer.PutInt( ( (int)(intp)dat->m_pValue ) );
  2616. #else
  2617. buffer.PutPtr( dat->m_pValue );
  2618. #endif
  2619. break;
  2620. }
  2621. default:
  2622. break;
  2623. }
  2624. }
  2625. }
  2626. // write tail, marks end of peers
  2627. buffer.PutUnsignedChar( TYPE_NUMTYPES );
  2628. return buffer.IsValid();
  2629. }
  2630. // read KeyValues from binary buffer, returns true if parsing was successful
  2631. bool KeyValues::ReadAsBinaryFiltered( CUtlBuffer &buffer, int nStackDepth )
  2632. {
  2633. if ( buffer.IsText() ) // must be a binary buffer
  2634. return false;
  2635. if ( !buffer.IsValid() ) // must be valid, no overflows etc
  2636. return false;
  2637. RemoveEverything(); // remove current content
  2638. Init(); // reset
  2639. if ( nStackDepth > 100 )
  2640. {
  2641. AssertMsgOnce( false, "KeyValues::ReadAsBinaryFiltered() stack depth > 100\n" );
  2642. return false;
  2643. }
  2644. char name[KEYVALUES_TOKEN_SIZE];
  2645. // Read header
  2646. buffer.GetString( name, KEYVALUES_TOKEN_SIZE-1 );
  2647. name[KEYVALUES_TOKEN_SIZE-1] = 0;
  2648. SetName( name );
  2649. // loop through all our peers
  2650. while ( true )
  2651. {
  2652. types_t type = (types_t)buffer.GetUnsignedChar();
  2653. if ( type == TYPE_NUMTYPES )
  2654. break;
  2655. if ( type == TYPE_NONE )
  2656. {
  2657. KeyValues *newKey = CreateKey("");
  2658. newKey->ReadAsBinaryFiltered( buffer, nStackDepth + 1 );
  2659. }
  2660. else
  2661. {
  2662. buffer.GetString( name, KEYVALUES_TOKEN_SIZE-1 );
  2663. name[KEYVALUES_TOKEN_SIZE-1] = 0;
  2664. switch ( type )
  2665. {
  2666. case TYPE_STRING:
  2667. {
  2668. char token[KEYVALUES_TOKEN_SIZE];
  2669. buffer.GetString( token, KEYVALUES_TOKEN_SIZE-1 );
  2670. token[KEYVALUES_TOKEN_SIZE-1] = 0;
  2671. SetString( name, token );
  2672. }
  2673. break;
  2674. case TYPE_WSTRING:
  2675. {
  2676. int nLength = buffer.GetShort();
  2677. wchar_t *wsValue = new wchar_t[nLength + 1];
  2678. for( int k = 0; k < nLength; ++ k )
  2679. {
  2680. wsValue[k] = buffer.GetShort();
  2681. }
  2682. wsValue[ nLength ] = 0;
  2683. SetWString( name, wsValue );
  2684. delete[] wsValue;
  2685. }
  2686. break;
  2687. case TYPE_INT:
  2688. {
  2689. int value = buffer.GetInt();
  2690. SetInt( name, value );
  2691. }
  2692. break;
  2693. case TYPE_UINT64:
  2694. {
  2695. uint64 value = buffer.GetInt64();
  2696. SetUint64( name, value );
  2697. }
  2698. break;
  2699. case TYPE_FLOAT:
  2700. {
  2701. float value = buffer.GetFloat();
  2702. SetFloat( name, value );
  2703. }
  2704. break;
  2705. case TYPE_COLOR:
  2706. {
  2707. unsigned char c0 = buffer.GetUnsignedChar();
  2708. unsigned char c1 = buffer.GetUnsignedChar();
  2709. unsigned char c2 = buffer.GetUnsignedChar();
  2710. unsigned char c3 = buffer.GetUnsignedChar();
  2711. SetColor( name, Color( c0, c1, c2, c3 ) );
  2712. }
  2713. break;
  2714. case TYPE_PTR:
  2715. {
  2716. #if defined( PLATFORM_64BITS )
  2717. // We need to ensure we only read 32 bits out of the stream because 32 bit clients only wrote
  2718. // 32 bits of data there. The actual pointer is irrelevant, all that we really care about here
  2719. // contractually is whether the pointer is zero or not zero.
  2720. void* value = ( void* )( intp )buffer.GetInt();
  2721. #else
  2722. void* value = buffer.GetPtr();
  2723. #endif
  2724. SetPtr( name, value );
  2725. }
  2726. break;
  2727. default:
  2728. break;
  2729. }
  2730. }
  2731. if ( !buffer.IsValid() ) // error occured
  2732. return false;
  2733. }
  2734. return buffer.IsValid();
  2735. }
  2736. //-----------------------------------------------------------------------------
  2737. // Purpose: memory allocator
  2738. //-----------------------------------------------------------------------------
  2739. bool KeyValues::ReadAsBinaryPooledFormat( CUtlBuffer &buffer, IBaseFileSystem *pFileSystem, unsigned int poolKey, GetSymbolProc_t pfnEvaluateSymbolProc )
  2740. {
  2741. // xbox only support
  2742. if ( !IsGameConsole() )
  2743. {
  2744. Assert( 0 );
  2745. return false;
  2746. }
  2747. if ( buffer.IsText() ) // must be a binary buffer
  2748. return false;
  2749. if ( !buffer.IsValid() ) // must be valid, no overflows etc
  2750. return false;
  2751. char token[KEYVALUES_TOKEN_SIZE];
  2752. KeyValues *dat = this;
  2753. types_t type = (types_t)buffer.GetUnsignedChar();
  2754. // loop through all our peers
  2755. while ( true )
  2756. {
  2757. if ( type == TYPE_NUMTYPES )
  2758. break; // no more peers
  2759. dat->m_iDataType = type;
  2760. unsigned int stringKey = buffer.GetUnsignedInt();
  2761. if ( !((IFileSystem*)pFileSystem)->GetStringFromKVPool( poolKey, stringKey, token, sizeof( token ) ) )
  2762. return false;
  2763. dat->SetName( token );
  2764. switch ( type )
  2765. {
  2766. case TYPE_NONE:
  2767. {
  2768. dat->m_pSub = new KeyValues( "" );
  2769. if ( !dat->m_pSub->ReadAsBinaryPooledFormat( buffer, pFileSystem, poolKey, pfnEvaluateSymbolProc ) )
  2770. return false;
  2771. break;
  2772. }
  2773. case TYPE_STRING:
  2774. {
  2775. stringKey = buffer.GetUnsignedInt();
  2776. if ( !((IFileSystem*)pFileSystem)->GetStringFromKVPool( poolKey, stringKey, token, sizeof( token ) ) )
  2777. return false;
  2778. int len = Q_strlen( token );
  2779. dat->m_sValue = new char[len + 1];
  2780. Q_memcpy( dat->m_sValue, token, len+1 );
  2781. break;
  2782. }
  2783. case TYPE_WSTRING:
  2784. {
  2785. int nLength = buffer.GetShort();
  2786. dat->m_wsValue = new wchar_t[nLength + 1];
  2787. for ( int k = 0; k < nLength; ++k )
  2788. {
  2789. dat->m_wsValue[k] = buffer.GetShort();
  2790. }
  2791. dat->m_wsValue[nLength] = 0;
  2792. break;
  2793. }
  2794. case TYPE_INT:
  2795. {
  2796. dat->m_iValue = buffer.GetInt();
  2797. break;
  2798. }
  2799. case TYPE_UINT64:
  2800. {
  2801. dat->m_sValue = new char[sizeof(uint64)];
  2802. *((uint64 *)dat->m_sValue) = buffer.GetInt64();
  2803. break;
  2804. }
  2805. case TYPE_FLOAT:
  2806. {
  2807. dat->m_flValue = buffer.GetFloat();
  2808. break;
  2809. }
  2810. case TYPE_COLOR:
  2811. {
  2812. dat->m_Color[0] = buffer.GetUnsignedChar();
  2813. dat->m_Color[1] = buffer.GetUnsignedChar();
  2814. dat->m_Color[2] = buffer.GetUnsignedChar();
  2815. dat->m_Color[3] = buffer.GetUnsignedChar();
  2816. break;
  2817. }
  2818. case TYPE_PTR:
  2819. {
  2820. #if defined( PLATFORM_64BITS )
  2821. // We need to ensure we only read 32 bits out of the stream because 32 bit clients only wrote
  2822. // 32 bits of data there. The actual pointer is irrelevant, all that we really care about here
  2823. // contractually is whether the pointer is zero or not zero.
  2824. dat->m_pValue = ( void* )( intp )buffer.GetInt();
  2825. #else
  2826. dat->m_pValue = buffer.GetPtr();
  2827. #endif
  2828. break;
  2829. }
  2830. case TYPE_COMPILED_INT_0:
  2831. {
  2832. // only for dense storage purposes, flip back to preferred internal format
  2833. dat->m_iDataType = TYPE_INT;
  2834. dat->m_iValue = 0;
  2835. break;
  2836. }
  2837. case TYPE_COMPILED_INT_1:
  2838. {
  2839. // only for dense storage purposes, flip back to preferred internal format
  2840. dat->m_iDataType = TYPE_INT;
  2841. dat->m_iValue = 1;
  2842. break;
  2843. }
  2844. case TYPE_COMPILED_INT_BYTE:
  2845. {
  2846. // only for dense storage purposes, flip back to preferred internal format
  2847. dat->m_iDataType = TYPE_INT;
  2848. dat->m_iValue = buffer.GetChar();
  2849. break;
  2850. }
  2851. default:
  2852. break;
  2853. }
  2854. if ( !buffer.IsValid() ) // error occured
  2855. return false;
  2856. if ( !buffer.GetBytesRemaining() )
  2857. break;
  2858. type = (types_t)buffer.GetUnsignedChar();
  2859. if ( type == TYPE_NUMTYPES )
  2860. break;
  2861. // new peer follows
  2862. dat->m_pPeer = new KeyValues("");
  2863. dat = dat->m_pPeer;
  2864. }
  2865. return buffer.IsValid();
  2866. }
  2867. #include "tier0/memdbgoff.h"
  2868. void *KeyValues::operator new( size_t iAllocSize )
  2869. {
  2870. MEM_ALLOC_CREDIT();
  2871. return KeyValuesSystem()->AllocKeyValuesMemory(iAllocSize);
  2872. }
  2873. void *KeyValues::operator new( size_t iAllocSize, int nBlockUse, const char *pFileName, int nLine )
  2874. {
  2875. MemAlloc_PushAllocDbgInfo( pFileName, nLine );
  2876. void *p = KeyValuesSystem()->AllocKeyValuesMemory(iAllocSize);
  2877. MemAlloc_PopAllocDbgInfo();
  2878. return p;
  2879. }
  2880. void KeyValues::operator delete( void *pMem )
  2881. {
  2882. KeyValuesSystem()->FreeKeyValuesMemory( (KeyValues *)pMem );
  2883. }
  2884. void KeyValues::operator delete( void *pMem, int nBlockUse, const char *pFileName, int nLine )
  2885. {
  2886. KeyValuesSystem()->FreeKeyValuesMemory( (KeyValues *)pMem );
  2887. }
  2888. #include "tier0/memdbgon.h"
  2889. //-----------------------------------------------------------------------------
  2890. void KeyValues::UnpackIntoStructure( KeyValuesUnpackStructure const *pUnpackTable, void *pDest )
  2891. {
  2892. uint8 *dest = ( uint8 * ) pDest;
  2893. while( pUnpackTable->m_pKeyName )
  2894. {
  2895. uint8 * dest_field = dest + pUnpackTable->m_nFieldOffset;
  2896. KeyValues * find_it = FindKey( pUnpackTable->m_pKeyName );
  2897. switch( pUnpackTable->m_eDataType )
  2898. {
  2899. case UNPACK_TYPE_FLOAT:
  2900. {
  2901. float default_value = ( pUnpackTable->m_pKeyDefault ) ? atof( pUnpackTable->m_pKeyDefault ) : 0.0;
  2902. *( ( float * ) dest_field ) = GetFloat( pUnpackTable->m_pKeyName, default_value );
  2903. break;
  2904. }
  2905. break;
  2906. case UNPACK_TYPE_VECTOR:
  2907. {
  2908. Vector *dest_v = ( Vector * ) dest_field;
  2909. char const *src_string =
  2910. GetString( pUnpackTable->m_pKeyName, pUnpackTable->m_pKeyDefault );
  2911. if ( ( ! src_string ) ||
  2912. ( sscanf(src_string,"%f %f %f",
  2913. & ( dest_v->x ), & ( dest_v->y ), & ( dest_v->z )) != 3 ))
  2914. dest_v->Init( 0, 0, 0 );
  2915. }
  2916. break;
  2917. case UNPACK_TYPE_FOUR_FLOATS:
  2918. {
  2919. float *dest_f = ( float * ) dest_field;
  2920. char const *src_string =
  2921. GetString( pUnpackTable->m_pKeyName, pUnpackTable->m_pKeyDefault );
  2922. if ( ( ! src_string ) ||
  2923. ( sscanf(src_string,"%f %f %f %f",
  2924. dest_f, dest_f + 1, dest_f + 2, dest_f + 3 )) != 4 )
  2925. memset( dest_f, 0, 4 * sizeof( float ) );
  2926. }
  2927. break;
  2928. case UNPACK_TYPE_TWO_FLOATS:
  2929. {
  2930. float *dest_f = ( float * ) dest_field;
  2931. char const *src_string =
  2932. GetString( pUnpackTable->m_pKeyName, pUnpackTable->m_pKeyDefault );
  2933. if ( ( ! src_string ) ||
  2934. ( sscanf(src_string,"%f %f",
  2935. dest_f, dest_f + 1 )) != 2 )
  2936. memset( dest_f, 0, 2 * sizeof( float ) );
  2937. }
  2938. break;
  2939. case UNPACK_TYPE_STRING:
  2940. {
  2941. char *dest_s = ( char * ) dest_field;
  2942. char const *pDefault = "";
  2943. if ( pUnpackTable->m_pKeyDefault )
  2944. {
  2945. pDefault = pUnpackTable->m_pKeyDefault;
  2946. }
  2947. strncpy( dest_s,
  2948. GetString( pUnpackTable->m_pKeyName, pDefault ),
  2949. pUnpackTable->m_nFieldSize );
  2950. }
  2951. break;
  2952. case UNPACK_TYPE_INT:
  2953. {
  2954. int *dest_i = ( int * ) dest_field;
  2955. int default_int = 0;
  2956. if ( pUnpackTable->m_pKeyDefault )
  2957. default_int = atoi( pUnpackTable->m_pKeyDefault );
  2958. *( dest_i ) = GetInt( pUnpackTable->m_pKeyName, default_int );
  2959. }
  2960. break;
  2961. case UNPACK_TYPE_VECTOR_COLOR:
  2962. {
  2963. Vector *dest_v = ( Vector * ) dest_field;
  2964. if ( find_it )
  2965. {
  2966. Color c = GetColor( pUnpackTable->m_pKeyName );
  2967. dest_v->x = c.r();
  2968. dest_v->y = c.g();
  2969. dest_v->z = c.b();
  2970. }
  2971. else
  2972. {
  2973. if ( pUnpackTable->m_pKeyDefault )
  2974. sscanf(pUnpackTable->m_pKeyDefault,"%f %f %f",
  2975. & ( dest_v->x ), & ( dest_v->y ), & ( dest_v->z ));
  2976. else
  2977. dest_v->Init( 0, 0, 0 );
  2978. }
  2979. *( dest_v ) *= ( 1.0 / 255 );
  2980. }
  2981. }
  2982. pUnpackTable++;
  2983. }
  2984. }
  2985. //-----------------------------------------------------------------------------
  2986. // Helper function for processing a keyvalue tree for console resolution support.
  2987. // Alters key/values for easier console video resolution support.
  2988. // If running SD (640x480), the presence of "???_lodef" creates or slams "???".
  2989. // If running HD (1280x720), the presence of "???_hidef" creates or slams "???".
  2990. //-----------------------------------------------------------------------------
  2991. bool KeyValues::ProcessResolutionKeys( const char *pResString )
  2992. {
  2993. if ( !pResString )
  2994. {
  2995. // not for pc, console only
  2996. return false;
  2997. }
  2998. KeyValues *pSubKey = GetFirstSubKey();
  2999. if ( !pSubKey )
  3000. {
  3001. // not a block
  3002. return false;
  3003. }
  3004. for ( ; pSubKey != NULL; pSubKey = pSubKey->GetNextKey() )
  3005. {
  3006. // recursively descend each sub block
  3007. pSubKey->ProcessResolutionKeys( pResString );
  3008. // check to see if our substring is present
  3009. if ( V_stristr( pSubKey->GetName(), pResString ) != NULL )
  3010. {
  3011. char normalKeyName[128];
  3012. V_strncpy( normalKeyName, pSubKey->GetName(), sizeof( normalKeyName ) );
  3013. // substring must match exactly, otherwise keys like "_lodef" and "_lodef_wide" would clash.
  3014. char *pString = V_stristr( normalKeyName, pResString );
  3015. if ( pString && !V_stricmp( pString, pResString ) )
  3016. {
  3017. *pString = '\0';
  3018. // find and delete the original key (if any)
  3019. KeyValues *pKey = FindKey( normalKeyName );
  3020. if ( pKey )
  3021. {
  3022. // remove the key
  3023. RemoveSubKey( pKey );
  3024. delete pKey;
  3025. }
  3026. // rename the marked key
  3027. pSubKey->SetName( normalKeyName );
  3028. }
  3029. }
  3030. }
  3031. return true;
  3032. }
  3033. //
  3034. // KeyValues merge operations
  3035. //
  3036. void KeyValues::MergeFrom( KeyValues *kvMerge, MergeKeyValuesOp_t eOp /* = MERGE_KV_ALL */ )
  3037. {
  3038. if ( !this || !kvMerge )
  3039. return;
  3040. switch ( eOp )
  3041. {
  3042. case MERGE_KV_ALL:
  3043. MergeFrom( kvMerge->FindKey( "update" ), MERGE_KV_UPDATE );
  3044. MergeFrom( kvMerge->FindKey( "delete" ), MERGE_KV_DELETE );
  3045. MergeFrom( kvMerge->FindKey( "borrow" ), MERGE_KV_BORROW );
  3046. return;
  3047. case MERGE_KV_UPDATE:
  3048. {
  3049. for ( KeyValues *sub = kvMerge->GetFirstTrueSubKey(); sub; sub = sub->GetNextTrueSubKey() )
  3050. {
  3051. char const *szName = sub->GetName();
  3052. KeyValues *subStorage = this->FindKey( szName, false );
  3053. if ( !subStorage )
  3054. {
  3055. AddSubKey( sub->MakeCopy() );
  3056. }
  3057. else
  3058. {
  3059. subStorage->MergeFrom( sub, eOp );
  3060. }
  3061. }
  3062. for ( KeyValues *val = kvMerge->GetFirstValue(); val; val = val->GetNextValue() )
  3063. {
  3064. char const *szName = val->GetName();
  3065. if ( KeyValues *valStorage = this->FindKey( szName, false ) )
  3066. {
  3067. this->RemoveSubKey( valStorage );
  3068. delete valStorage;
  3069. }
  3070. this->AddSubKey( val->MakeCopy() );
  3071. }
  3072. }
  3073. return;
  3074. case MERGE_KV_BORROW:
  3075. {
  3076. for ( KeyValues *sub = kvMerge->GetFirstTrueSubKey(); sub; sub = sub->GetNextTrueSubKey() )
  3077. {
  3078. char const *szName = sub->GetName();
  3079. KeyValues *subStorage = this->FindKey( szName, false );
  3080. if ( !subStorage )
  3081. continue;
  3082. subStorage->MergeFrom( sub, eOp );
  3083. }
  3084. for ( KeyValues *val = kvMerge->GetFirstValue(); val; val = val->GetNextValue() )
  3085. {
  3086. char const *szName = val->GetName();
  3087. if ( KeyValues *valStorage = this->FindKey( szName, false ) )
  3088. {
  3089. this->RemoveSubKey( valStorage );
  3090. delete valStorage;
  3091. }
  3092. else
  3093. continue;
  3094. this->AddSubKey( val->MakeCopy() );
  3095. }
  3096. }
  3097. return;
  3098. case MERGE_KV_DELETE:
  3099. {
  3100. for ( KeyValues *sub = kvMerge->GetFirstTrueSubKey(); sub; sub = sub->GetNextTrueSubKey() )
  3101. {
  3102. char const *szName = sub->GetName();
  3103. if ( KeyValues *subStorage = this->FindKey( szName, false ) )
  3104. {
  3105. subStorage->MergeFrom( sub, eOp );
  3106. }
  3107. }
  3108. for ( KeyValues *val = kvMerge->GetFirstValue(); val; val = val->GetNextValue() )
  3109. {
  3110. char const *szName = val->GetName();
  3111. if ( KeyValues *valStorage = this->FindKey( szName, false ) )
  3112. {
  3113. this->RemoveSubKey( valStorage );
  3114. delete valStorage;
  3115. }
  3116. }
  3117. }
  3118. return;
  3119. }
  3120. }
  3121. //
  3122. // KeyValues from string parsing
  3123. //
  3124. static char const * ParseStringToken( char const *szStringVal, char const **ppEndOfParse )
  3125. {
  3126. // Eat whitespace
  3127. while ( V_isspace( *szStringVal ) )
  3128. ++ szStringVal;
  3129. char const *pszResult = szStringVal;
  3130. while ( *szStringVal && !V_isspace( *szStringVal ) )
  3131. ++ szStringVal;
  3132. if ( ppEndOfParse )
  3133. {
  3134. *ppEndOfParse = szStringVal;
  3135. }
  3136. return pszResult;
  3137. }
  3138. KeyValues * KeyValues::FromString( char const *szName, char const *szStringVal, char const **ppEndOfParse )
  3139. {
  3140. if ( !szName )
  3141. szName = "";
  3142. if ( !szStringVal )
  3143. szStringVal = "";
  3144. KeyValues *kv = new KeyValues( szName );
  3145. if ( !kv )
  3146. return NULL;
  3147. char chName[256] = {0};
  3148. char chValue[1024] = {0};
  3149. for ( ; ; )
  3150. {
  3151. char const *szEnd;
  3152. char const *szVarValue = NULL;
  3153. char const *szVarName = ParseStringToken( szStringVal, &szEnd );
  3154. if ( !*szVarName )
  3155. break;
  3156. if ( *szVarName == '}' )
  3157. {
  3158. szStringVal = szVarName + 1;
  3159. break;
  3160. }
  3161. V_strncpy( chName, szVarName, ( int )MIN( sizeof( chName ), szEnd - szVarName + 1 ) );
  3162. szVarName = chName;
  3163. szStringVal = szEnd;
  3164. if ( *szVarName == '{' )
  3165. {
  3166. szVarName = "";
  3167. goto do_sub_key;
  3168. }
  3169. szVarValue = ParseStringToken( szStringVal, &szEnd );
  3170. if ( *szVarValue == '}' )
  3171. {
  3172. szStringVal = szVarValue + 1;
  3173. kv->SetString( szVarName, "" );
  3174. break;
  3175. }
  3176. V_strncpy( chValue, szVarValue, ( int )MIN( sizeof( chValue ), szEnd - szVarValue + 1 ) );
  3177. szVarValue = chValue;
  3178. szStringVal = szEnd;
  3179. if ( *szVarValue == '{' )
  3180. {
  3181. goto do_sub_key;
  3182. }
  3183. // Try to recognize some known types
  3184. if ( char const *szInt = StringAfterPrefix( szVarValue, "#int#" ) )
  3185. {
  3186. kv->SetInt( szVarName, atoi( szInt ) );
  3187. }
  3188. else if ( !V_stricmp( szVarValue, "#empty#" ) )
  3189. {
  3190. kv->SetString( szVarName, "" );
  3191. }
  3192. else
  3193. {
  3194. kv->SetString( szVarName, szVarValue );
  3195. }
  3196. continue;
  3197. do_sub_key:
  3198. {
  3199. KeyValues *pSubKey = KeyValues::FromString( szVarName, szStringVal, &szEnd );
  3200. if ( pSubKey )
  3201. {
  3202. kv->AddSubKey( pSubKey );
  3203. }
  3204. szStringVal = szEnd;
  3205. continue;
  3206. }
  3207. }
  3208. if ( ppEndOfParse )
  3209. {
  3210. *ppEndOfParse = szStringVal;
  3211. }
  3212. return kv;
  3213. }
  3214. //-----------------------------------------------------------------------------
  3215. // Purpose: comparison function for keyvalues
  3216. //-----------------------------------------------------------------------------
  3217. bool KeyValues::IsEqual( KeyValues *pRHS )
  3218. {
  3219. if ( !pRHS )
  3220. return false;
  3221. // check our key
  3222. if ( m_iDataType != pRHS->m_iDataType )
  3223. return false;
  3224. switch ( m_iDataType )
  3225. {
  3226. case TYPE_STRING:
  3227. return V_strcmp( GetString(), pRHS->GetString() ) == 0;
  3228. case TYPE_WSTRING:
  3229. return V_wcscmp( GetWString(), pRHS->GetWString() ) == 0;
  3230. case TYPE_FLOAT:
  3231. return m_flValue == pRHS->m_flValue;
  3232. case TYPE_UINT64:
  3233. return GetUint64() == pRHS->GetUint64();
  3234. case TYPE_NONE:
  3235. {
  3236. // walk through the subkeys - does it in order right now
  3237. KeyValues *pkv = GetFirstSubKey();
  3238. KeyValues *pkvRHS = pRHS->GetFirstSubKey();
  3239. bool bRet = false;
  3240. while ( 1 )
  3241. {
  3242. // ended at the same time, good
  3243. if ( !pkv && !pkvRHS )
  3244. {
  3245. bRet = true;
  3246. break;
  3247. }
  3248. // uneven number of keys, failure
  3249. if ( !pkv || !pkvRHS )
  3250. break;
  3251. // recursively compare
  3252. if ( !pkv->IsEqual( pkvRHS ) )
  3253. break;
  3254. pkv = pkv->GetNextKey();
  3255. pkvRHS = pkvRHS->GetNextKey();
  3256. }
  3257. return bRet;
  3258. }
  3259. case TYPE_INT:
  3260. case TYPE_PTR:
  3261. return m_iValue == pRHS->m_iValue;
  3262. default:
  3263. Assert( false );
  3264. }
  3265. return true;
  3266. }
  3267. //
  3268. // KeyValues dumping implementation
  3269. //
  3270. bool KeyValues::Dump( IKeyValuesDumpContext *pDump, int nIndentLevel /* = 0 */ )
  3271. {
  3272. if ( !pDump->KvBeginKey( this, nIndentLevel ) )
  3273. return false;
  3274. // Dump values
  3275. for ( KeyValues *val = this ? GetFirstValue() : NULL; val; val = val->GetNextValue() )
  3276. {
  3277. if ( !pDump->KvWriteValue( val, nIndentLevel + 1 ) )
  3278. return false;
  3279. }
  3280. // Dump subkeys
  3281. for ( KeyValues *sub = this ? GetFirstTrueSubKey() : NULL; sub; sub = sub->GetNextTrueSubKey() )
  3282. {
  3283. if ( !sub->Dump( pDump, nIndentLevel + 1 ) )
  3284. return false;
  3285. }
  3286. return pDump->KvEndKey( this, nIndentLevel );
  3287. }
  3288. bool IKeyValuesDumpContextAsText::KvBeginKey( KeyValues *pKey, int nIndentLevel )
  3289. {
  3290. if ( pKey )
  3291. {
  3292. return
  3293. KvWriteIndent( nIndentLevel ) &&
  3294. KvWriteText( pKey->GetName() ) &&
  3295. KvWriteText( " {\n" );
  3296. }
  3297. else
  3298. {
  3299. return
  3300. KvWriteIndent( nIndentLevel ) &&
  3301. KvWriteText( "<< NULL >>\n" );
  3302. }
  3303. }
  3304. bool IKeyValuesDumpContextAsText::KvWriteValue( KeyValues *val, int nIndentLevel )
  3305. {
  3306. if ( !val )
  3307. {
  3308. return
  3309. KvWriteIndent( nIndentLevel ) &&
  3310. KvWriteText( "<< NULL >>\n" );
  3311. }
  3312. if ( !KvWriteIndent( nIndentLevel ) )
  3313. return false;
  3314. if ( !KvWriteText( val->GetName() ) )
  3315. return false;
  3316. if ( !KvWriteText( " " ) )
  3317. return false;
  3318. switch ( val->GetDataType() )
  3319. {
  3320. case KeyValues::TYPE_STRING:
  3321. {
  3322. if ( !KvWriteText( val->GetString() ) )
  3323. return false;
  3324. }
  3325. break;
  3326. case KeyValues::TYPE_INT:
  3327. {
  3328. int n = val->GetInt();
  3329. char *chBuffer = ( char * ) stackalloc( 128 );
  3330. V_snprintf( chBuffer, 128, "int( %d = 0x%X )", n, n );
  3331. if ( !KvWriteText( chBuffer ) )
  3332. return false;
  3333. }
  3334. break;
  3335. case KeyValues::TYPE_FLOAT:
  3336. {
  3337. float fl = val->GetFloat();
  3338. char *chBuffer = ( char * ) stackalloc( 128 );
  3339. V_snprintf( chBuffer, 128, "float( %f )", fl );
  3340. if ( !KvWriteText( chBuffer ) )
  3341. return false;
  3342. }
  3343. break;
  3344. case KeyValues::TYPE_PTR:
  3345. {
  3346. void *ptr = val->GetPtr();
  3347. char *chBuffer = ( char * ) stackalloc( 128 );
  3348. V_snprintf( chBuffer, 128, "ptr( 0x%p )", ptr );
  3349. if ( !KvWriteText( chBuffer ) )
  3350. return false;
  3351. }
  3352. break;
  3353. case KeyValues::TYPE_WSTRING:
  3354. {
  3355. wchar_t const *wsz = val->GetWString();
  3356. int nLen = V_wcslen( wsz );
  3357. int numBytes = nLen*2 + 64;
  3358. char *chBuffer = ( char * ) stackalloc( numBytes );
  3359. V_snprintf( chBuffer, numBytes, "%ls [wstring, len = %d]", wsz, nLen );
  3360. if ( !KvWriteText( chBuffer ) )
  3361. return false;
  3362. }
  3363. break;
  3364. case KeyValues::TYPE_UINT64:
  3365. {
  3366. uint64 n = val->GetUint64();
  3367. char *chBuffer = ( char * ) stackalloc( 128 );
  3368. V_snprintf( chBuffer, 128, "u64( %lld = 0x%llX )", n, n );
  3369. if ( !KvWriteText( chBuffer ) )
  3370. return false;
  3371. }
  3372. break;
  3373. default:
  3374. break;
  3375. #if 0 // this code was accidentally stubbed out by a mis-integration in CL722860; it hasn't been tested
  3376. {
  3377. int n = val->GetDataType();
  3378. char *chBuffer = ( char * ) stackalloc( 128 );
  3379. V_snprintf( chBuffer, 128, "??kvtype[%d]", n );
  3380. if ( !KvWriteText( chBuffer ) )
  3381. return false;
  3382. }
  3383. break;
  3384. #endif
  3385. }
  3386. return KvWriteText( "\n" );
  3387. }
  3388. bool IKeyValuesDumpContextAsText::KvEndKey( KeyValues *pKey, int nIndentLevel )
  3389. {
  3390. if ( pKey )
  3391. {
  3392. return
  3393. KvWriteIndent( nIndentLevel ) &&
  3394. KvWriteText( "}\n" );
  3395. }
  3396. else
  3397. {
  3398. return true;
  3399. }
  3400. }
  3401. bool IKeyValuesDumpContextAsText::KvWriteIndent( int nIndentLevel )
  3402. {
  3403. int numIndentBytes = ( nIndentLevel * 2 + 1 );
  3404. char *pchIndent = ( char * ) stackalloc( numIndentBytes );
  3405. memset( pchIndent, ' ', numIndentBytes - 1 );
  3406. pchIndent[ numIndentBytes - 1 ] = 0;
  3407. return KvWriteText( pchIndent );
  3408. }
  3409. bool CKeyValuesDumpContextAsDevMsg::KvBeginKey( KeyValues *pKey, int nIndentLevel )
  3410. {
  3411. static ConVarRef r_developer( "developer" );
  3412. if ( r_developer.IsValid() && r_developer.GetInt() < m_nDeveloperLevel )
  3413. // If "developer" is not the correct level, then avoid evaluating KeyValues tree early
  3414. return false;
  3415. else
  3416. return IKeyValuesDumpContextAsText::KvBeginKey( pKey, nIndentLevel );
  3417. }
  3418. bool CKeyValuesDumpContextAsDevMsg::KvWriteText( char const *szText )
  3419. {
  3420. if ( m_nDeveloperLevel > 0 )
  3421. {
  3422. DevMsg( "%s", szText );
  3423. }
  3424. else
  3425. {
  3426. Msg( "%s", szText );
  3427. }
  3428. return true;
  3429. }