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

3209 lines
82 KiB

  1. //========= Copyright 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 "tier0/icommandline.h"
  20. #include "tier0/vprof_telemetry.h"
  21. #include <Color.h>
  22. #include <stdlib.h>
  23. #include "tier0/dbg.h"
  24. #include "tier0/mem.h"
  25. #include "utlbuffer.h"
  26. #include "utlhash.h"
  27. #include "utlvector.h"
  28. #include "utlqueue.h"
  29. #include "UtlSortVector.h"
  30. #include "convar.h"
  31. // memdbgon must be the last include file in a .cpp file!!!
  32. #include <tier0/memdbgon.h>
  33. static const char * s_LastFileLoadingFrom = "unknown"; // just needed for error messages
  34. // Statics for the growable string table
  35. int (*KeyValues::s_pfGetSymbolForString)( const char *name, bool bCreate ) = &KeyValues::GetSymbolForStringClassic;
  36. const char *(*KeyValues::s_pfGetStringForSymbol)( int symbol ) = &KeyValues::GetStringForSymbolClassic;
  37. CKeyValuesGrowableStringTable *KeyValues::s_pGrowableStringTable = NULL;
  38. #define KEYVALUES_TOKEN_SIZE 4096
  39. static char s_pTokenBuf[KEYVALUES_TOKEN_SIZE];
  40. #define INTERNALWRITE( pData, len ) InternalWrite( filesystem, f, pBuf, pData, len )
  41. // a simple class to keep track of a stack of valid parsed symbols
  42. const int MAX_ERROR_STACK = 64;
  43. class CKeyValuesErrorStack
  44. {
  45. public:
  46. CKeyValuesErrorStack() : m_pFilename("NULL"), m_errorIndex(0), m_maxErrorIndex(0) {}
  47. void SetFilename( const char *pFilename )
  48. {
  49. m_pFilename = pFilename;
  50. m_maxErrorIndex = 0;
  51. }
  52. // entering a new keyvalues block, save state for errors
  53. // Not save symbols instead of pointers because the pointers can move!
  54. int Push( int symName )
  55. {
  56. if ( m_errorIndex < MAX_ERROR_STACK )
  57. {
  58. m_errorStack[m_errorIndex] = symName;
  59. }
  60. m_errorIndex++;
  61. m_maxErrorIndex = max( m_maxErrorIndex, (m_errorIndex-1) );
  62. return m_errorIndex-1;
  63. }
  64. // exiting block, error isn't in this block, remove.
  65. void Pop()
  66. {
  67. m_errorIndex--;
  68. Assert(m_errorIndex>=0);
  69. }
  70. // Allows you to keep the same stack level, but change the name as you parse peers
  71. void Reset( int stackLevel, int symName )
  72. {
  73. Assert( stackLevel >= 0 );
  74. Assert( stackLevel < m_errorIndex );
  75. if ( stackLevel < MAX_ERROR_STACK )
  76. m_errorStack[stackLevel] = symName;
  77. }
  78. // Hit an error, report it and the parsing stack for context
  79. void ReportError( const char *pError )
  80. {
  81. bool bSpewCR = false;
  82. Warning( "KeyValues Error: %s in file %s\n", pError, m_pFilename );
  83. for ( int i = 0; i < m_maxErrorIndex; i++ )
  84. {
  85. if ( i < MAX_ERROR_STACK && m_errorStack[i] != INVALID_KEY_SYMBOL )
  86. {
  87. if ( i < m_errorIndex )
  88. {
  89. Warning( "%s, ", KeyValues::CallGetStringForSymbol(m_errorStack[i]) );
  90. }
  91. else
  92. {
  93. Warning( "(*%s*), ", KeyValues::CallGetStringForSymbol(m_errorStack[i]) );
  94. }
  95. bSpewCR = true;
  96. }
  97. }
  98. if ( bSpewCR )
  99. Warning( "\n" );
  100. }
  101. private:
  102. int m_errorStack[MAX_ERROR_STACK];
  103. const char *m_pFilename;
  104. int m_errorIndex;
  105. int m_maxErrorIndex;
  106. } g_KeyValuesErrorStack;
  107. // a simple helper that creates stack entries as it goes in & out of scope
  108. class CKeyErrorContext
  109. {
  110. public:
  111. CKeyErrorContext( KeyValues *pKv )
  112. {
  113. Init( pKv->GetNameSymbol() );
  114. }
  115. ~CKeyErrorContext()
  116. {
  117. g_KeyValuesErrorStack.Pop();
  118. }
  119. CKeyErrorContext( int symName )
  120. {
  121. Init( symName );
  122. }
  123. void Reset( int symName )
  124. {
  125. g_KeyValuesErrorStack.Reset( m_stackLevel, symName );
  126. }
  127. int GetStackLevel() const
  128. {
  129. return m_stackLevel;
  130. }
  131. private:
  132. void Init( int symName )
  133. {
  134. m_stackLevel = g_KeyValuesErrorStack.Push( symName );
  135. }
  136. int m_stackLevel;
  137. };
  138. // Uncomment this line to hit the ~CLeakTrack assert to see what's looking like it's leaking
  139. // #define LEAKTRACK
  140. #ifdef LEAKTRACK
  141. class CLeakTrack
  142. {
  143. public:
  144. CLeakTrack()
  145. {
  146. }
  147. ~CLeakTrack()
  148. {
  149. if ( keys.Count() != 0 )
  150. {
  151. Assert( 0 );
  152. }
  153. }
  154. struct kve
  155. {
  156. KeyValues *kv;
  157. char name[ 256 ];
  158. };
  159. void AddKv( KeyValues *kv, char const *name )
  160. {
  161. kve k;
  162. Q_strncpy( k.name, name ? name : "NULL", sizeof( k.name ) );
  163. k.kv = kv;
  164. keys.AddToTail( k );
  165. }
  166. void RemoveKv( KeyValues *kv )
  167. {
  168. int c = keys.Count();
  169. for ( int i = 0; i < c; i++ )
  170. {
  171. if ( keys[i].kv == kv )
  172. {
  173. keys.Remove( i );
  174. break;
  175. }
  176. }
  177. }
  178. CUtlVector< kve > keys;
  179. };
  180. static CLeakTrack track;
  181. #define TRACK_KV_ADD( ptr, name ) track.AddKv( ptr, name )
  182. #define TRACK_KV_REMOVE( ptr ) track.RemoveKv( ptr )
  183. #else
  184. #define TRACK_KV_ADD( ptr, name )
  185. #define TRACK_KV_REMOVE( ptr )
  186. #endif
  187. //-----------------------------------------------------------------------------
  188. // Purpose: An arbitrarily growable string table for KeyValues key names.
  189. // See the comment in the header for more info.
  190. //-----------------------------------------------------------------------------
  191. class CKeyValuesGrowableStringTable
  192. {
  193. public:
  194. // Constructor
  195. CKeyValuesGrowableStringTable() :
  196. #ifdef PLATFORM_64BITS
  197. m_vecStrings( 0, 4 * 512 * 1024 )
  198. #else
  199. m_vecStrings( 0, 512 * 1024 )
  200. #endif
  201. , m_hashLookup( 2048, 0, 0, m_Functor, m_Functor )
  202. {
  203. m_vecStrings.AddToTail( '\0' );
  204. }
  205. // Translates a string to an index
  206. int GetSymbolForString( const char *name, bool bCreate = true )
  207. {
  208. AUTO_LOCK( m_mutex );
  209. // Put the current details into our hash functor
  210. m_Functor.SetCurString( name );
  211. m_Functor.SetCurStringBase( (const char *)m_vecStrings.Base() );
  212. if ( bCreate )
  213. {
  214. bool bInserted = false;
  215. UtlHashHandle_t hElement = m_hashLookup.Insert( -1, &bInserted );
  216. if ( bInserted )
  217. {
  218. int iIndex = m_vecStrings.AddMultipleToTail( V_strlen( name ) + 1, name );
  219. m_hashLookup[ hElement ] = iIndex;
  220. }
  221. return m_hashLookup[ hElement ];
  222. }
  223. else
  224. {
  225. UtlHashHandle_t hElement = m_hashLookup.Find( -1 );
  226. if ( m_hashLookup.IsValidHandle( hElement ) )
  227. return m_hashLookup[ hElement ];
  228. else
  229. return -1;
  230. }
  231. }
  232. // Translates an index back to a string
  233. const char *GetStringForSymbol( int symbol )
  234. {
  235. return (const char *)m_vecStrings.Base() + symbol;
  236. }
  237. private:
  238. // A class plugged into CUtlHash that allows us to change the behavior of the table
  239. // and store only the index in the table.
  240. class CLookupFunctor
  241. {
  242. public:
  243. CLookupFunctor() : m_pchCurString( NULL ), m_pchCurBase( NULL ) {}
  244. // Sets what we are currently inserting or looking for.
  245. void SetCurString( const char *pchCurString ) { m_pchCurString = pchCurString; }
  246. void SetCurStringBase( const char *pchCurBase ) { m_pchCurBase = pchCurBase; }
  247. // The compare function.
  248. bool operator()( int nLhs, int nRhs ) const
  249. {
  250. const char *pchLhs = nLhs > 0 ? m_pchCurBase + nLhs : m_pchCurString;
  251. const char *pchRhs = nRhs > 0 ? m_pchCurBase + nRhs : m_pchCurString;
  252. return ( 0 == V_stricmp( pchLhs, pchRhs ) );
  253. }
  254. // The hash function.
  255. unsigned int operator()( int nItem ) const
  256. {
  257. return HashStringCaseless( m_pchCurString );
  258. }
  259. private:
  260. const char *m_pchCurString;
  261. const char *m_pchCurBase;
  262. };
  263. CThreadFastMutex m_mutex;
  264. CLookupFunctor m_Functor;
  265. CUtlHash<int, CLookupFunctor &, CLookupFunctor &> m_hashLookup;
  266. CUtlVector<char> m_vecStrings;
  267. };
  268. //-----------------------------------------------------------------------------
  269. // Purpose: Sets whether the KeyValues system should use an arbitrarily growable
  270. // string table. See the comment in the header for more info.
  271. //-----------------------------------------------------------------------------
  272. void KeyValues::SetUseGrowableStringTable( bool bUseGrowableTable )
  273. {
  274. if ( bUseGrowableTable )
  275. {
  276. s_pfGetStringForSymbol = &(KeyValues::GetStringForSymbolGrowable);
  277. s_pfGetSymbolForString = &(KeyValues::GetSymbolForStringGrowable);
  278. if ( NULL == s_pGrowableStringTable )
  279. {
  280. s_pGrowableStringTable = new CKeyValuesGrowableStringTable;
  281. }
  282. }
  283. else
  284. {
  285. s_pfGetStringForSymbol = &(KeyValues::GetStringForSymbolClassic);
  286. s_pfGetSymbolForString = &(KeyValues::GetSymbolForStringClassic);
  287. delete s_pGrowableStringTable;
  288. s_pGrowableStringTable = NULL;
  289. }
  290. }
  291. //-----------------------------------------------------------------------------
  292. // Purpose: Bodys of the function pointers used for interacting with the key
  293. // name string table
  294. //-----------------------------------------------------------------------------
  295. int KeyValues::GetSymbolForStringClassic( const char *name, bool bCreate )
  296. {
  297. return KeyValuesSystem()->GetSymbolForString( name, bCreate );
  298. }
  299. const char *KeyValues::GetStringForSymbolClassic( int symbol )
  300. {
  301. return KeyValuesSystem()->GetStringForSymbol( symbol );
  302. }
  303. int KeyValues::GetSymbolForStringGrowable( const char *name, bool bCreate )
  304. {
  305. return s_pGrowableStringTable->GetSymbolForString( name, bCreate );
  306. }
  307. const char *KeyValues::GetStringForSymbolGrowable( int symbol )
  308. {
  309. return s_pGrowableStringTable->GetStringForSymbol( symbol );
  310. }
  311. //-----------------------------------------------------------------------------
  312. // Purpose: Constructor
  313. //-----------------------------------------------------------------------------
  314. KeyValues::KeyValues( const char *setName )
  315. {
  316. TRACK_KV_ADD( this, setName );
  317. Init();
  318. SetName ( setName );
  319. }
  320. //-----------------------------------------------------------------------------
  321. // Purpose: Constructor
  322. //-----------------------------------------------------------------------------
  323. KeyValues::KeyValues( const char *setName, const char *firstKey, const char *firstValue )
  324. {
  325. TRACK_KV_ADD( this, setName );
  326. Init();
  327. SetName( setName );
  328. SetString( firstKey, firstValue );
  329. }
  330. //-----------------------------------------------------------------------------
  331. // Purpose: Constructor
  332. //-----------------------------------------------------------------------------
  333. KeyValues::KeyValues( const char *setName, const char *firstKey, const wchar_t *firstValue )
  334. {
  335. TRACK_KV_ADD( this, setName );
  336. Init();
  337. SetName( setName );
  338. SetWString( firstKey, firstValue );
  339. }
  340. //-----------------------------------------------------------------------------
  341. // Purpose: Constructor
  342. //-----------------------------------------------------------------------------
  343. KeyValues::KeyValues( const char *setName, const char *firstKey, int firstValue )
  344. {
  345. TRACK_KV_ADD( this, setName );
  346. Init();
  347. SetName( setName );
  348. SetInt( firstKey, firstValue );
  349. }
  350. //-----------------------------------------------------------------------------
  351. // Purpose: Constructor
  352. //-----------------------------------------------------------------------------
  353. KeyValues::KeyValues( const char *setName, const char *firstKey, const char *firstValue, const char *secondKey, const char *secondValue )
  354. {
  355. TRACK_KV_ADD( this, setName );
  356. Init();
  357. SetName( setName );
  358. SetString( firstKey, firstValue );
  359. SetString( secondKey, secondValue );
  360. }
  361. //-----------------------------------------------------------------------------
  362. // Purpose: Constructor
  363. //-----------------------------------------------------------------------------
  364. KeyValues::KeyValues( const char *setName, const char *firstKey, int firstValue, const char *secondKey, int secondValue )
  365. {
  366. TRACK_KV_ADD( this, setName );
  367. Init();
  368. SetName( setName );
  369. SetInt( firstKey, firstValue );
  370. SetInt( secondKey, secondValue );
  371. }
  372. //-----------------------------------------------------------------------------
  373. // Purpose: Initialize member variables
  374. //-----------------------------------------------------------------------------
  375. void KeyValues::Init()
  376. {
  377. m_iKeyName = INVALID_KEY_SYMBOL;
  378. m_iDataType = TYPE_NONE;
  379. m_pSub = NULL;
  380. m_pPeer = NULL;
  381. m_pChain = NULL;
  382. m_sValue = NULL;
  383. m_wsValue = NULL;
  384. m_pValue = NULL;
  385. m_bHasEscapeSequences = false;
  386. m_bEvaluateConditionals = true;
  387. // for future proof
  388. memset( unused, 0, sizeof(unused) );
  389. }
  390. //-----------------------------------------------------------------------------
  391. // Purpose: Destructor
  392. //-----------------------------------------------------------------------------
  393. KeyValues::~KeyValues()
  394. {
  395. TRACK_KV_REMOVE( this );
  396. RemoveEverything();
  397. }
  398. //-----------------------------------------------------------------------------
  399. // Purpose: remove everything
  400. //-----------------------------------------------------------------------------
  401. void KeyValues::RemoveEverything()
  402. {
  403. KeyValues *dat;
  404. KeyValues *datNext = NULL;
  405. for ( dat = m_pSub; dat != NULL; dat = datNext )
  406. {
  407. datNext = dat->m_pPeer;
  408. dat->m_pPeer = NULL;
  409. delete dat;
  410. }
  411. for ( dat = m_pPeer; dat && dat != this; dat = datNext )
  412. {
  413. datNext = dat->m_pPeer;
  414. dat->m_pPeer = NULL;
  415. delete dat;
  416. }
  417. delete [] m_sValue;
  418. m_sValue = NULL;
  419. delete [] m_wsValue;
  420. m_wsValue = NULL;
  421. }
  422. //-----------------------------------------------------------------------------
  423. // Purpose:
  424. // Input : *f -
  425. //-----------------------------------------------------------------------------
  426. void KeyValues::RecursiveSaveToFile( CUtlBuffer& buf, int indentLevel, bool sortKeys /*= false*/, bool bAllowEmptyString /*= false*/ )
  427. {
  428. RecursiveSaveToFile( NULL, FILESYSTEM_INVALID_HANDLE, &buf, indentLevel, sortKeys, bAllowEmptyString );
  429. }
  430. //-----------------------------------------------------------------------------
  431. // Adds a chain... if we don't find stuff in this keyvalue, we'll look
  432. // in the one we're chained to.
  433. //-----------------------------------------------------------------------------
  434. void KeyValues::ChainKeyValue( KeyValues* pChain )
  435. {
  436. m_pChain = pChain;
  437. }
  438. //-----------------------------------------------------------------------------
  439. // Purpose: Get the name of the current key section
  440. //-----------------------------------------------------------------------------
  441. const char *KeyValues::GetName( void ) const
  442. {
  443. return s_pfGetStringForSymbol( m_iKeyName );
  444. }
  445. //-----------------------------------------------------------------------------
  446. // Purpose: Read a single token from buffer (0 terminated)
  447. //-----------------------------------------------------------------------------
  448. #pragma warning (disable:4706)
  449. const char *KeyValues::ReadToken( CUtlBuffer &buf, bool &wasQuoted, bool &wasConditional )
  450. {
  451. wasQuoted = false;
  452. wasConditional = false;
  453. if ( !buf.IsValid() )
  454. return NULL;
  455. // eating white spaces and remarks loop
  456. while ( true )
  457. {
  458. buf.EatWhiteSpace();
  459. if ( !buf.IsValid() )
  460. return NULL; // file ends after reading whitespaces
  461. // stop if it's not a comment; a new token starts here
  462. if ( !buf.EatCPPComment() )
  463. break;
  464. }
  465. const char *c = (const char*)buf.PeekGet( sizeof(char), 0 );
  466. if ( !c )
  467. return NULL;
  468. // read quoted strings specially
  469. if ( *c == '\"' )
  470. {
  471. wasQuoted = true;
  472. buf.GetDelimitedString( m_bHasEscapeSequences ? GetCStringCharConversion() : GetNoEscCharConversion(),
  473. s_pTokenBuf, KEYVALUES_TOKEN_SIZE );
  474. return s_pTokenBuf;
  475. }
  476. if ( *c == '{' || *c == '}' )
  477. {
  478. // it's a control char, just add this one char and stop reading
  479. s_pTokenBuf[0] = *c;
  480. s_pTokenBuf[1] = 0;
  481. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 1 );
  482. return s_pTokenBuf;
  483. }
  484. // read in the token until we hit a whitespace or a control character
  485. bool bReportedError = false;
  486. bool bConditionalStart = false;
  487. int nCount = 0;
  488. while ( ( c = (const char*)buf.PeekGet( sizeof(char), 0 ) ) )
  489. {
  490. // end of file
  491. if ( *c == 0 )
  492. break;
  493. // break if any control character appears in non quoted tokens
  494. if ( *c == '"' || *c == '{' || *c == '}' )
  495. break;
  496. if ( *c == '[' )
  497. bConditionalStart = true;
  498. if ( *c == ']' && bConditionalStart )
  499. {
  500. wasConditional = true;
  501. }
  502. // break on whitespace
  503. if ( isspace(*c) )
  504. break;
  505. if (nCount < (KEYVALUES_TOKEN_SIZE-1) )
  506. {
  507. s_pTokenBuf[nCount++] = *c; // add char to buffer
  508. }
  509. else if ( !bReportedError )
  510. {
  511. bReportedError = true;
  512. g_KeyValuesErrorStack.ReportError(" ReadToken overflow" );
  513. }
  514. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 1 );
  515. }
  516. s_pTokenBuf[ nCount ] = 0;
  517. return s_pTokenBuf;
  518. }
  519. #pragma warning (default:4706)
  520. //-----------------------------------------------------------------------------
  521. // Purpose: if parser should translate escape sequences ( /n, /t etc), set to true
  522. //-----------------------------------------------------------------------------
  523. void KeyValues::UsesEscapeSequences(bool state)
  524. {
  525. m_bHasEscapeSequences = state;
  526. }
  527. //-----------------------------------------------------------------------------
  528. // Purpose: if parser should evaluate conditional blocks ( [$WINDOWS] etc. )
  529. //-----------------------------------------------------------------------------
  530. void KeyValues::UsesConditionals(bool state)
  531. {
  532. m_bEvaluateConditionals = state;
  533. }
  534. //-----------------------------------------------------------------------------
  535. // Purpose: Load keyValues from disk
  536. //-----------------------------------------------------------------------------
  537. bool KeyValues::LoadFromFile( IBaseFileSystem *filesystem, const char *resourceName, const char *pathID, bool refreshCache )
  538. {
  539. TM_ZONE_DEFAULT( TELEMETRY_LEVEL0 );
  540. TM_ZONE_DEFAULT_PARAM( TELEMETRY_LEVEL0, resourceName );
  541. Assert(filesystem);
  542. #ifdef WIN32
  543. Assert( IsX360() || ( IsPC() && _heapchk() == _HEAPOK ) );
  544. #endif
  545. #ifdef STAGING_ONLY
  546. static bool s_bCacheEnabled = !!CommandLine()->FindParm( "-enable_keyvalues_cache" );
  547. const bool bUseCache = s_bCacheEnabled && ( s_pfGetSymbolForString == KeyValues::GetSymbolForStringClassic );
  548. #else
  549. /*
  550. People are cheating with the keyvalue cache enabled by doing the below, so disable it.
  551. For example if one is to allow a blue demoman texture on sv_pure they
  552. change it to this, "$basetexture" "temp/demoman_blue". Remember to move the
  553. demoman texture to the temp folder in the materials folder. It will likely
  554. not be there so make a new folder for it. Once the directory in the
  555. demoman_blue vmt is changed to the temp folder and the vtf texture is in
  556. the temp folder itself you are finally done.
  557. I packed my mods into a vpk but I don't think it's required. Once in game
  558. you must create a server via the create server button and select the map
  559. that will load the custom texture before you join a valve server. I suggest
  560. you only do this with player textures and such as they are always loaded.
  561. After you load the map you join the valve server and the textures should
  562. appear and work on valve servers.
  563. This can be done on any sv_pure 1 server but it depends on what is type of
  564. files are allowed. All valve servers allow temp files so that is the
  565. example I used here."
  566. So all vmt's files can bypass sv_pure 1. And I believe this mod is mostly
  567. made of vmt files, so valve's sv_pure 1 bull is pretty redundant.
  568. */
  569. const bool bUseCache = false;
  570. #endif
  571. // If pathID is null, we cannot cache the result because that has a weird iterate-through-a-bunch-of-locations behavior.
  572. const bool bUseCacheForRead = bUseCache && !refreshCache && pathID != NULL;
  573. const bool bUseCacheForWrite = bUseCache && pathID != NULL;
  574. COM_TimestampedLog( "KeyValues::LoadFromFile(%s%s%s): Begin", pathID ? pathID : "", pathID && resourceName ? "/" : "", resourceName ? resourceName : "" );
  575. // Keep a cache of keyvalues, try to load it here.
  576. if ( bUseCacheForRead && KeyValuesSystem()->LoadFileKeyValuesFromCache( this, resourceName, pathID, filesystem ) ) {
  577. COM_TimestampedLog( "KeyValues::LoadFromFile(%s%s%s): End / CacheHit", pathID ? pathID : "", pathID && resourceName ? "/" : "", resourceName ? resourceName : "" );
  578. return true;
  579. }
  580. FileHandle_t f = filesystem->Open(resourceName, "rb", pathID);
  581. if ( !f )
  582. {
  583. COM_TimestampedLog("KeyValues::LoadFromFile(%s%s%s): End / FileNotFound", pathID ? pathID : "", pathID && resourceName ? "/" : "", resourceName ? resourceName : "");
  584. return false;
  585. }
  586. s_LastFileLoadingFrom = (char*)resourceName;
  587. // load file into a null-terminated buffer
  588. int fileSize = filesystem->Size( f );
  589. unsigned bufSize = ((IFileSystem *)filesystem)->GetOptimalReadSize( f, fileSize + 2 );
  590. char *buffer = (char*)((IFileSystem *)filesystem)->AllocOptimalReadBuffer( f, bufSize );
  591. Assert( buffer );
  592. // read into local buffer
  593. bool bRetOK = ( ((IFileSystem *)filesystem)->ReadEx( buffer, bufSize, fileSize, f ) != 0 );
  594. filesystem->Close( f ); // close file after reading
  595. if ( bRetOK )
  596. {
  597. buffer[fileSize] = 0; // null terminate file as EOF
  598. buffer[fileSize+1] = 0; // double NULL terminating in case this is a unicode file
  599. bRetOK = LoadFromBuffer( resourceName, buffer, filesystem );
  600. }
  601. // The cache relies on the KeyValuesSystem string table, which will only be valid if we're
  602. // using classic mode.
  603. if ( bUseCacheForWrite && bRetOK )
  604. {
  605. KeyValuesSystem()->AddFileKeyValuesToCache( this, resourceName, pathID );
  606. }
  607. ( (IFileSystem *)filesystem )->FreeOptimalReadBuffer( buffer );
  608. COM_TimestampedLog("KeyValues::LoadFromFile(%s%s%s): End / Success", pathID ? pathID : "", pathID && resourceName ? "/" : "", resourceName ? resourceName : "");
  609. return bRetOK;
  610. }
  611. //-----------------------------------------------------------------------------
  612. // Purpose: Save the keyvalues to disk
  613. // Creates the path to the file if it doesn't exist
  614. //-----------------------------------------------------------------------------
  615. bool KeyValues::SaveToFile( IBaseFileSystem *filesystem, const char *resourceName, const char *pathID, bool sortKeys /*= false*/, bool bAllowEmptyString /*= false*/, bool bCacheResult /*= false*/ )
  616. {
  617. // create a write file
  618. FileHandle_t f = filesystem->Open(resourceName, "wb", pathID);
  619. if ( f == FILESYSTEM_INVALID_HANDLE )
  620. {
  621. DevMsg(1, "KeyValues::SaveToFile: couldn't open file \"%s\" in path \"%s\".\n",
  622. resourceName?resourceName:"NULL", pathID?pathID:"NULL" );
  623. return false;
  624. }
  625. KeyValuesSystem()->InvalidateCacheForFile( resourceName, pathID );
  626. if ( bCacheResult ) {
  627. KeyValuesSystem()->AddFileKeyValuesToCache( this, resourceName, pathID );
  628. }
  629. RecursiveSaveToFile(filesystem, f, NULL, 0, sortKeys, bAllowEmptyString );
  630. filesystem->Close(f);
  631. return true;
  632. }
  633. //-----------------------------------------------------------------------------
  634. // Purpose: Write out a set of indenting
  635. //-----------------------------------------------------------------------------
  636. void KeyValues::WriteIndents( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel )
  637. {
  638. for ( int i = 0; i < indentLevel; i++ )
  639. {
  640. INTERNALWRITE( "\t", 1 );
  641. }
  642. }
  643. //-----------------------------------------------------------------------------
  644. // Purpose: Write out a string where we convert the double quotes to backslash double quote
  645. //-----------------------------------------------------------------------------
  646. void KeyValues::WriteConvertedString( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, const char *pszString )
  647. {
  648. // handle double quote chars within the string
  649. // the worst possible case is that the whole string is quotes
  650. int len = Q_strlen(pszString);
  651. char *convertedString = (char *) _alloca ((len + 1) * sizeof(char) * 2);
  652. int j=0;
  653. for (int i=0; i <= len; i++)
  654. {
  655. if (pszString[i] == '\"')
  656. {
  657. convertedString[j] = '\\';
  658. j++;
  659. }
  660. else if ( m_bHasEscapeSequences && pszString[i] == '\\' )
  661. {
  662. convertedString[j] = '\\';
  663. j++;
  664. }
  665. convertedString[j] = pszString[i];
  666. j++;
  667. }
  668. INTERNALWRITE(convertedString, Q_strlen(convertedString));
  669. }
  670. void KeyValues::InternalWrite( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, const void *pData, int len )
  671. {
  672. if ( filesystem )
  673. {
  674. filesystem->Write( pData, len, f );
  675. }
  676. if ( pBuf )
  677. {
  678. pBuf->Put( pData, len );
  679. }
  680. }
  681. //-----------------------------------------------------------------------------
  682. // Purpose: Save keyvalues from disk, if subkey values are detected, calls
  683. // itself to save those
  684. //-----------------------------------------------------------------------------
  685. void KeyValues::RecursiveSaveToFile( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel, bool sortKeys, bool bAllowEmptyString )
  686. {
  687. // write header
  688. WriteIndents( filesystem, f, pBuf, indentLevel );
  689. INTERNALWRITE("\"", 1);
  690. WriteConvertedString(filesystem, f, pBuf, GetName());
  691. INTERNALWRITE("\"\n", 2);
  692. WriteIndents( filesystem, f, pBuf, indentLevel );
  693. INTERNALWRITE("{\n", 2);
  694. // loop through all our keys writing them to disk
  695. if ( sortKeys )
  696. {
  697. CUtlSortVector< KeyValues*, CUtlSortVectorKeyValuesByName > vecSortedKeys;
  698. for ( KeyValues *dat = m_pSub; dat != NULL; dat = dat->m_pPeer )
  699. {
  700. vecSortedKeys.InsertNoSort(dat);
  701. }
  702. vecSortedKeys.RedoSort();
  703. FOR_EACH_VEC( vecSortedKeys, i )
  704. {
  705. SaveKeyToFile( vecSortedKeys[i], filesystem, f, pBuf, indentLevel, sortKeys, bAllowEmptyString );
  706. }
  707. }
  708. else
  709. {
  710. for ( KeyValues *dat = m_pSub; dat != NULL; dat = dat->m_pPeer )
  711. SaveKeyToFile( dat, filesystem, f, pBuf, indentLevel, sortKeys, bAllowEmptyString );
  712. }
  713. // write tail
  714. WriteIndents(filesystem, f, pBuf, indentLevel);
  715. INTERNALWRITE("}\n", 2);
  716. }
  717. void KeyValues::SaveKeyToFile( KeyValues *dat, IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel, bool sortKeys, bool bAllowEmptyString )
  718. {
  719. if ( dat->m_pSub )
  720. {
  721. dat->RecursiveSaveToFile( filesystem, f, pBuf, indentLevel + 1, sortKeys, bAllowEmptyString );
  722. }
  723. else
  724. {
  725. // only write non-empty keys
  726. switch (dat->m_iDataType)
  727. {
  728. case TYPE_STRING:
  729. {
  730. if ( dat->m_sValue && ( bAllowEmptyString || *(dat->m_sValue) ) )
  731. {
  732. WriteIndents(filesystem, f, pBuf, indentLevel + 1);
  733. INTERNALWRITE("\"", 1);
  734. WriteConvertedString(filesystem, f, pBuf, dat->GetName());
  735. INTERNALWRITE("\"\t\t\"", 4);
  736. WriteConvertedString(filesystem, f, pBuf, dat->m_sValue);
  737. INTERNALWRITE("\"\n", 2);
  738. }
  739. break;
  740. }
  741. case TYPE_WSTRING:
  742. {
  743. if ( dat->m_wsValue )
  744. {
  745. static char buf[KEYVALUES_TOKEN_SIZE];
  746. // make sure we have enough space
  747. int result = Q_UnicodeToUTF8( dat->m_wsValue, buf, KEYVALUES_TOKEN_SIZE);
  748. if (result)
  749. {
  750. WriteIndents(filesystem, f, pBuf, indentLevel + 1);
  751. INTERNALWRITE("\"", 1);
  752. INTERNALWRITE(dat->GetName(), Q_strlen(dat->GetName()));
  753. INTERNALWRITE("\"\t\t\"", 4);
  754. WriteConvertedString(filesystem, f, pBuf, buf);
  755. INTERNALWRITE("\"\n", 2);
  756. }
  757. }
  758. break;
  759. }
  760. case TYPE_INT:
  761. {
  762. WriteIndents(filesystem, f, pBuf, indentLevel + 1);
  763. INTERNALWRITE("\"", 1);
  764. INTERNALWRITE(dat->GetName(), Q_strlen(dat->GetName()));
  765. INTERNALWRITE("\"\t\t\"", 4);
  766. char buf[32];
  767. Q_snprintf(buf, sizeof( buf ), "%d", dat->m_iValue);
  768. INTERNALWRITE(buf, Q_strlen(buf));
  769. INTERNALWRITE("\"\n", 2);
  770. break;
  771. }
  772. case TYPE_UINT64:
  773. {
  774. WriteIndents(filesystem, f, pBuf, indentLevel + 1);
  775. INTERNALWRITE("\"", 1);
  776. INTERNALWRITE(dat->GetName(), Q_strlen(dat->GetName()));
  777. INTERNALWRITE("\"\t\t\"", 4);
  778. char buf[32];
  779. // write "0x" + 16 char 0-padded hex encoded 64 bit value
  780. #ifdef WIN32
  781. Q_snprintf( buf, sizeof( buf ), "0x%016I64X", *( (uint64 *)dat->m_sValue ) );
  782. #else
  783. Q_snprintf( buf, sizeof( buf ), "0x%016llX", *( (uint64 *)dat->m_sValue ) );
  784. #endif
  785. INTERNALWRITE(buf, Q_strlen(buf));
  786. INTERNALWRITE("\"\n", 2);
  787. break;
  788. }
  789. case TYPE_FLOAT:
  790. {
  791. WriteIndents(filesystem, f, pBuf, indentLevel + 1);
  792. INTERNALWRITE("\"", 1);
  793. INTERNALWRITE(dat->GetName(), Q_strlen(dat->GetName()));
  794. INTERNALWRITE("\"\t\t\"", 4);
  795. char buf[48];
  796. Q_snprintf(buf, sizeof( buf ), "%f", dat->m_flValue);
  797. INTERNALWRITE(buf, Q_strlen(buf));
  798. INTERNALWRITE("\"\n", 2);
  799. break;
  800. }
  801. case TYPE_COLOR:
  802. DevMsg(1, "KeyValues::RecursiveSaveToFile: TODO, missing code for TYPE_COLOR.\n");
  803. break;
  804. default:
  805. break;
  806. }
  807. }
  808. }
  809. //-----------------------------------------------------------------------------
  810. // Purpose: looks up a key by symbol name
  811. //-----------------------------------------------------------------------------
  812. KeyValues *KeyValues::FindKey(int keySymbol) const
  813. {
  814. for (KeyValues *dat = m_pSub; dat != NULL; dat = dat->m_pPeer)
  815. {
  816. if (dat->m_iKeyName == keySymbol)
  817. return dat;
  818. }
  819. return NULL;
  820. }
  821. //-----------------------------------------------------------------------------
  822. // Purpose: Find a keyValue, create it if it is not found.
  823. // Set bCreate to true to create the key if it doesn't already exist
  824. // (which ensures a valid pointer will be returned)
  825. //-----------------------------------------------------------------------------
  826. KeyValues *KeyValues::FindKey(const char *keyName, bool bCreate)
  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. char szBuf[256];
  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. Q_memcpy( szBuf, keyName, size );
  840. szBuf[size] = 0;
  841. searchStr = szBuf;
  842. }
  843. // lookup the symbol for the search string
  844. HKeySymbol iSearchStr = s_pfGetSymbolForString( searchStr, bCreate );
  845. if ( iSearchStr == INVALID_KEY_SYMBOL )
  846. {
  847. // not found, couldn't possibly be in key value list
  848. return NULL;
  849. }
  850. KeyValues *lastItem = NULL;
  851. KeyValues *dat;
  852. // find the searchStr in the current peer list
  853. for (dat = m_pSub; dat != NULL; dat = dat->m_pPeer)
  854. {
  855. lastItem = dat; // record the last item looked at (for if we need to append to the end of the list)
  856. // symbol compare
  857. if (dat->m_iKeyName == iSearchStr)
  858. {
  859. break;
  860. }
  861. }
  862. if ( !dat && m_pChain )
  863. {
  864. dat = m_pChain->FindKey(keyName, false);
  865. }
  866. // make sure a key was found
  867. if (!dat)
  868. {
  869. if (bCreate)
  870. {
  871. // we need to create a new key
  872. dat = new KeyValues( searchStr );
  873. // Assert(dat != NULL);
  874. dat->UsesEscapeSequences( m_bHasEscapeSequences != 0 ); // use same format as parent
  875. dat->UsesConditionals( m_bEvaluateConditionals != 0 );
  876. // insert new key at end of list
  877. if (lastItem)
  878. {
  879. lastItem->m_pPeer = dat;
  880. }
  881. else
  882. {
  883. m_pSub = dat;
  884. }
  885. dat->m_pPeer = NULL;
  886. // a key graduates to be a submsg as soon as it's m_pSub is set
  887. // this should be the only place m_pSub is set
  888. m_iDataType = TYPE_NONE;
  889. }
  890. else
  891. {
  892. return NULL;
  893. }
  894. }
  895. // if we've still got a subStr we need to keep looking deeper in the tree
  896. if ( subStr )
  897. {
  898. // recursively chain down through the paths in the string
  899. return dat->FindKey(subStr + 1, bCreate);
  900. }
  901. return dat;
  902. }
  903. //-----------------------------------------------------------------------------
  904. // Purpose: Create a new key, with an autogenerated name.
  905. // Name is guaranteed to be an integer, of value 1 higher than the highest
  906. // other integer key name
  907. //-----------------------------------------------------------------------------
  908. KeyValues *KeyValues::CreateNewKey()
  909. {
  910. int newID = 1;
  911. // search for any key with higher values
  912. KeyValues *pLastChild = NULL;
  913. for (KeyValues *dat = m_pSub; dat != NULL; dat = dat->m_pPeer)
  914. {
  915. // case-insensitive string compare
  916. int val = atoi(dat->GetName());
  917. if (newID <= val)
  918. {
  919. newID = val + 1;
  920. }
  921. pLastChild = dat;
  922. }
  923. char buf[12];
  924. Q_snprintf( buf, sizeof(buf), "%d", newID );
  925. return CreateKeyUsingKnownLastChild( buf, pLastChild );
  926. }
  927. //-----------------------------------------------------------------------------
  928. // Create a key
  929. //-----------------------------------------------------------------------------
  930. KeyValues* KeyValues::CreateKey( const char *keyName )
  931. {
  932. KeyValues *pLastChild = FindLastSubKey();
  933. return CreateKeyUsingKnownLastChild( keyName, pLastChild );
  934. }
  935. //-----------------------------------------------------------------------------
  936. KeyValues* KeyValues::CreateKeyUsingKnownLastChild( const char *keyName, KeyValues *pLastChild )
  937. {
  938. // Create a new key
  939. KeyValues* dat = new KeyValues( keyName );
  940. dat->UsesEscapeSequences( m_bHasEscapeSequences != 0 ); // use same format as parent does
  941. dat->UsesConditionals( m_bEvaluateConditionals != 0 );
  942. // add into subkey list
  943. AddSubkeyUsingKnownLastChild( dat, pLastChild );
  944. return dat;
  945. }
  946. //-----------------------------------------------------------------------------
  947. void KeyValues::AddSubkeyUsingKnownLastChild( KeyValues *pSubkey, KeyValues *pLastChild )
  948. {
  949. // Make sure the subkey isn't a child of some other keyvalues
  950. Assert( pSubkey != NULL );
  951. Assert( pSubkey->m_pPeer == NULL );
  952. // Empty child list?
  953. if ( pLastChild == NULL )
  954. {
  955. Assert( m_pSub == NULL );
  956. m_pSub = pSubkey;
  957. }
  958. else
  959. {
  960. Assert( m_pSub != NULL );
  961. Assert( pLastChild->m_pPeer == NULL );
  962. // // In debug, make sure that they really do know which child is the last one
  963. // #ifdef _DEBUG
  964. // KeyValues *pTempDat = m_pSub;
  965. // while ( pTempDat->GetNextKey() != NULL )
  966. // {
  967. // pTempDat = pTempDat->GetNextKey();
  968. // }
  969. // Assert( pTempDat == pLastChild );
  970. // #endif
  971. pLastChild->SetNextKey( pSubkey );
  972. }
  973. }
  974. //-----------------------------------------------------------------------------
  975. // Adds a subkey. Make sure the subkey isn't a child of some other keyvalues
  976. //-----------------------------------------------------------------------------
  977. void KeyValues::AddSubKey( KeyValues *pSubkey )
  978. {
  979. // Make sure the subkey isn't a child of some other keyvalues
  980. Assert( pSubkey != NULL );
  981. Assert( pSubkey->m_pPeer == NULL );
  982. // add into subkey list
  983. if ( m_pSub == NULL )
  984. {
  985. m_pSub = pSubkey;
  986. }
  987. else
  988. {
  989. KeyValues *pTempDat = m_pSub;
  990. while ( pTempDat->GetNextKey() != NULL )
  991. {
  992. pTempDat = pTempDat->GetNextKey();
  993. }
  994. pTempDat->SetNextKey( pSubkey );
  995. }
  996. }
  997. //-----------------------------------------------------------------------------
  998. // Purpose: Remove a subkey from the list
  999. //-----------------------------------------------------------------------------
  1000. void KeyValues::RemoveSubKey(KeyValues *subKey)
  1001. {
  1002. if (!subKey)
  1003. return;
  1004. // check the list pointer
  1005. if (m_pSub == subKey)
  1006. {
  1007. m_pSub = subKey->m_pPeer;
  1008. }
  1009. else
  1010. {
  1011. // look through the list
  1012. KeyValues *kv = m_pSub;
  1013. while (kv->m_pPeer)
  1014. {
  1015. if (kv->m_pPeer == subKey)
  1016. {
  1017. kv->m_pPeer = subKey->m_pPeer;
  1018. break;
  1019. }
  1020. kv = kv->m_pPeer;
  1021. }
  1022. }
  1023. subKey->m_pPeer = NULL;
  1024. }
  1025. //-----------------------------------------------------------------------------
  1026. // Purpose: Locate last child. Returns NULL if we have no children
  1027. //-----------------------------------------------------------------------------
  1028. KeyValues *KeyValues::FindLastSubKey()
  1029. {
  1030. // No children?
  1031. if ( m_pSub == NULL )
  1032. return NULL;
  1033. // Scan for the last one
  1034. KeyValues *pLastChild = m_pSub;
  1035. while ( pLastChild->m_pPeer )
  1036. pLastChild = pLastChild->m_pPeer;
  1037. return pLastChild;
  1038. }
  1039. //-----------------------------------------------------------------------------
  1040. // Purpose: Sets this key's peer to the KeyValues passed in
  1041. //-----------------------------------------------------------------------------
  1042. void KeyValues::SetNextKey( KeyValues *pDat )
  1043. {
  1044. m_pPeer = pDat;
  1045. }
  1046. KeyValues* KeyValues::GetFirstTrueSubKey()
  1047. {
  1048. KeyValues *pRet = m_pSub;
  1049. while ( pRet && pRet->m_iDataType != TYPE_NONE )
  1050. pRet = pRet->m_pPeer;
  1051. return pRet;
  1052. }
  1053. KeyValues* KeyValues::GetNextTrueSubKey()
  1054. {
  1055. KeyValues *pRet = m_pPeer;
  1056. while ( pRet && pRet->m_iDataType != TYPE_NONE )
  1057. pRet = pRet->m_pPeer;
  1058. return pRet;
  1059. }
  1060. KeyValues* KeyValues::GetFirstValue()
  1061. {
  1062. KeyValues *pRet = m_pSub;
  1063. while ( pRet && pRet->m_iDataType == TYPE_NONE )
  1064. pRet = pRet->m_pPeer;
  1065. return pRet;
  1066. }
  1067. KeyValues* KeyValues::GetNextValue()
  1068. {
  1069. KeyValues *pRet = m_pPeer;
  1070. while ( pRet && pRet->m_iDataType == TYPE_NONE )
  1071. pRet = pRet->m_pPeer;
  1072. return pRet;
  1073. }
  1074. //-----------------------------------------------------------------------------
  1075. // Purpose: Get the integer value of a keyName. Default value is returned
  1076. // if the keyName can't be found.
  1077. //-----------------------------------------------------------------------------
  1078. int KeyValues::GetInt( const char *keyName, int defaultValue )
  1079. {
  1080. KeyValues *dat = FindKey( keyName, false );
  1081. if ( dat )
  1082. {
  1083. switch ( dat->m_iDataType )
  1084. {
  1085. case TYPE_STRING:
  1086. return atoi(dat->m_sValue);
  1087. case TYPE_WSTRING:
  1088. return _wtoi(dat->m_wsValue);
  1089. case TYPE_FLOAT:
  1090. return (int)dat->m_flValue;
  1091. case TYPE_UINT64:
  1092. // can't convert, since it would lose data
  1093. Assert(0);
  1094. return 0;
  1095. case TYPE_INT:
  1096. case TYPE_PTR:
  1097. default:
  1098. return dat->m_iValue;
  1099. };
  1100. }
  1101. return defaultValue;
  1102. }
  1103. //-----------------------------------------------------------------------------
  1104. // Purpose: Get the integer value of a keyName. Default value is returned
  1105. // if the keyName can't be found.
  1106. //-----------------------------------------------------------------------------
  1107. uint64 KeyValues::GetUint64( const char *keyName, uint64 defaultValue )
  1108. {
  1109. KeyValues *dat = FindKey( keyName, false );
  1110. if ( dat )
  1111. {
  1112. switch ( dat->m_iDataType )
  1113. {
  1114. case TYPE_STRING:
  1115. return (uint64)Q_atoi64(dat->m_sValue);
  1116. case TYPE_WSTRING:
  1117. return _wtoi64(dat->m_wsValue);
  1118. case TYPE_FLOAT:
  1119. return (int)dat->m_flValue;
  1120. case TYPE_UINT64:
  1121. return *((uint64 *)dat->m_sValue);
  1122. case TYPE_INT:
  1123. case TYPE_PTR:
  1124. default:
  1125. return dat->m_iValue;
  1126. };
  1127. }
  1128. return defaultValue;
  1129. }
  1130. //-----------------------------------------------------------------------------
  1131. // Purpose: Get the pointer value of a keyName. Default value is returned
  1132. // if the keyName can't be found.
  1133. //-----------------------------------------------------------------------------
  1134. void *KeyValues::GetPtr( const char *keyName, void *defaultValue )
  1135. {
  1136. KeyValues *dat = FindKey( keyName, false );
  1137. if ( dat )
  1138. {
  1139. switch ( dat->m_iDataType )
  1140. {
  1141. case TYPE_PTR:
  1142. return dat->m_pValue;
  1143. case TYPE_WSTRING:
  1144. case TYPE_STRING:
  1145. case TYPE_FLOAT:
  1146. case TYPE_INT:
  1147. case TYPE_UINT64:
  1148. default:
  1149. return NULL;
  1150. };
  1151. }
  1152. return defaultValue;
  1153. }
  1154. //-----------------------------------------------------------------------------
  1155. // Purpose: Get the float value of a keyName. Default value is returned
  1156. // if the keyName can't be found.
  1157. //-----------------------------------------------------------------------------
  1158. float KeyValues::GetFloat( const char *keyName, float defaultValue )
  1159. {
  1160. KeyValues *dat = FindKey( keyName, false );
  1161. if ( dat )
  1162. {
  1163. switch ( dat->m_iDataType )
  1164. {
  1165. case TYPE_STRING:
  1166. return (float)atof(dat->m_sValue);
  1167. case TYPE_WSTRING:
  1168. #ifdef WIN32
  1169. return (float) _wtof(dat->m_wsValue); // no wtof
  1170. #else
  1171. Assert( !"impl me" );
  1172. return 0.0;
  1173. #endif
  1174. case TYPE_FLOAT:
  1175. return dat->m_flValue;
  1176. case TYPE_INT:
  1177. return (float)dat->m_iValue;
  1178. case TYPE_UINT64:
  1179. return (float)(*((uint64 *)dat->m_sValue));
  1180. case TYPE_PTR:
  1181. default:
  1182. return 0.0f;
  1183. };
  1184. }
  1185. return defaultValue;
  1186. }
  1187. //-----------------------------------------------------------------------------
  1188. // Purpose: Get the string pointer of a keyName. Default value is returned
  1189. // if the keyName can't be found.
  1190. //-----------------------------------------------------------------------------
  1191. const char *KeyValues::GetString( const char *keyName, const char *defaultValue )
  1192. {
  1193. KeyValues *dat = FindKey( keyName, false );
  1194. if ( dat )
  1195. {
  1196. // convert the data to string form then return it
  1197. char buf[64];
  1198. switch ( dat->m_iDataType )
  1199. {
  1200. case TYPE_FLOAT:
  1201. Q_snprintf( buf, sizeof( buf ), "%f", dat->m_flValue );
  1202. SetString( keyName, buf );
  1203. break;
  1204. case TYPE_PTR:
  1205. Q_snprintf( buf, sizeof( buf ), "%lld", (int64)(size_t)dat->m_pValue );
  1206. SetString( keyName, buf );
  1207. break;
  1208. case TYPE_INT:
  1209. Q_snprintf( buf, sizeof( buf ), "%d", dat->m_iValue );
  1210. SetString( keyName, buf );
  1211. break;
  1212. case TYPE_UINT64:
  1213. Q_snprintf( buf, sizeof( buf ), "%lld", *((uint64 *)(dat->m_sValue)) );
  1214. SetString( keyName, buf );
  1215. break;
  1216. case TYPE_WSTRING:
  1217. {
  1218. // convert the string to char *, set it for future use, and return it
  1219. char wideBuf[512];
  1220. int result = Q_UnicodeToUTF8(dat->m_wsValue, wideBuf, 512);
  1221. if ( result )
  1222. {
  1223. // note: this will copy wideBuf
  1224. SetString( keyName, wideBuf );
  1225. }
  1226. else
  1227. {
  1228. return defaultValue;
  1229. }
  1230. break;
  1231. }
  1232. case TYPE_STRING:
  1233. break;
  1234. default:
  1235. return defaultValue;
  1236. };
  1237. return dat->m_sValue;
  1238. }
  1239. return defaultValue;
  1240. }
  1241. const wchar_t *KeyValues::GetWString( const char *keyName, const wchar_t *defaultValue)
  1242. {
  1243. KeyValues *dat = FindKey( keyName, false );
  1244. if ( dat )
  1245. {
  1246. wchar_t wbuf[64];
  1247. switch ( dat->m_iDataType )
  1248. {
  1249. case TYPE_FLOAT:
  1250. swprintf(wbuf, Q_ARRAYSIZE(wbuf), L"%f", dat->m_flValue);
  1251. SetWString( keyName, wbuf);
  1252. break;
  1253. case TYPE_PTR:
  1254. swprintf( wbuf, Q_ARRAYSIZE(wbuf), L"%lld", (int64)(size_t)dat->m_pValue );
  1255. SetWString( keyName, wbuf );
  1256. break;
  1257. case TYPE_INT:
  1258. swprintf( wbuf, Q_ARRAYSIZE(wbuf), L"%d", dat->m_iValue );
  1259. SetWString( keyName, wbuf );
  1260. break;
  1261. case TYPE_UINT64:
  1262. {
  1263. swprintf( wbuf, Q_ARRAYSIZE(wbuf), L"%lld", *((uint64 *)(dat->m_sValue)) );
  1264. SetWString( keyName, wbuf );
  1265. }
  1266. break;
  1267. case TYPE_WSTRING:
  1268. break;
  1269. case TYPE_STRING:
  1270. {
  1271. int bufSize = Q_strlen(dat->m_sValue) + 1;
  1272. wchar_t *pWBuf = new wchar_t[ bufSize ];
  1273. int result = Q_UTF8ToUnicode(dat->m_sValue, pWBuf, bufSize * sizeof( wchar_t ) );
  1274. if ( result >= 0 ) // may be a zero length string
  1275. {
  1276. SetWString( keyName, pWBuf);
  1277. }
  1278. else
  1279. {
  1280. delete [] pWBuf;
  1281. return defaultValue;
  1282. }
  1283. delete [] pWBuf;
  1284. break;
  1285. }
  1286. default:
  1287. return defaultValue;
  1288. };
  1289. return (const wchar_t* )dat->m_wsValue;
  1290. }
  1291. return defaultValue;
  1292. }
  1293. //-----------------------------------------------------------------------------
  1294. // Purpose: Get a bool interpretation of the key.
  1295. //-----------------------------------------------------------------------------
  1296. bool KeyValues::GetBool( const char *keyName, bool defaultValue, bool* optGotDefault )
  1297. {
  1298. if ( FindKey( keyName ) )
  1299. {
  1300. if ( optGotDefault )
  1301. (*optGotDefault) = false;
  1302. return 0 != GetInt( keyName, 0 );
  1303. }
  1304. if ( optGotDefault )
  1305. (*optGotDefault) = true;
  1306. return defaultValue;
  1307. }
  1308. //-----------------------------------------------------------------------------
  1309. // Purpose: Gets a color
  1310. //-----------------------------------------------------------------------------
  1311. Color KeyValues::GetColor( const char *keyName )
  1312. {
  1313. Color color(0, 0, 0, 0);
  1314. KeyValues *dat = FindKey( keyName, false );
  1315. if ( dat )
  1316. {
  1317. if ( dat->m_iDataType == TYPE_COLOR )
  1318. {
  1319. color[0] = dat->m_Color[0];
  1320. color[1] = dat->m_Color[1];
  1321. color[2] = dat->m_Color[2];
  1322. color[3] = dat->m_Color[3];
  1323. }
  1324. else if ( dat->m_iDataType == TYPE_FLOAT )
  1325. {
  1326. color[0] = dat->m_flValue;
  1327. }
  1328. else if ( dat->m_iDataType == TYPE_INT )
  1329. {
  1330. color[0] = dat->m_iValue;
  1331. }
  1332. else if ( dat->m_iDataType == TYPE_STRING )
  1333. {
  1334. // parse the colors out of the string
  1335. float a = 0.0f, b = 0.0f, c = 0.0f, d = 0.0f;
  1336. sscanf(dat->m_sValue, "%f %f %f %f", &a, &b, &c, &d);
  1337. color[0] = (unsigned char)a;
  1338. color[1] = (unsigned char)b;
  1339. color[2] = (unsigned char)c;
  1340. color[3] = (unsigned char)d;
  1341. }
  1342. }
  1343. return color;
  1344. }
  1345. //-----------------------------------------------------------------------------
  1346. // Purpose: Sets a color
  1347. //-----------------------------------------------------------------------------
  1348. void KeyValues::SetColor( const char *keyName, Color value)
  1349. {
  1350. KeyValues *dat = FindKey( keyName, true );
  1351. if ( dat )
  1352. {
  1353. dat->m_iDataType = TYPE_COLOR;
  1354. dat->m_Color[0] = value[0];
  1355. dat->m_Color[1] = value[1];
  1356. dat->m_Color[2] = value[2];
  1357. dat->m_Color[3] = value[3];
  1358. }
  1359. }
  1360. void KeyValues::SetStringValue( char const *strValue )
  1361. {
  1362. // delete the old value
  1363. delete [] m_sValue;
  1364. // make sure we're not storing the WSTRING - as we're converting over to STRING
  1365. delete [] m_wsValue;
  1366. m_wsValue = NULL;
  1367. if (!strValue)
  1368. {
  1369. // ensure a valid value
  1370. strValue = "";
  1371. }
  1372. // allocate memory for the new value and copy it in
  1373. int len = Q_strlen( strValue );
  1374. m_sValue = new char[len + 1];
  1375. Q_memcpy( m_sValue, strValue, len+1 );
  1376. m_iDataType = TYPE_STRING;
  1377. }
  1378. //-----------------------------------------------------------------------------
  1379. // Purpose: Set the string value of a keyName.
  1380. //-----------------------------------------------------------------------------
  1381. void KeyValues::SetString( const char *keyName, const char *value )
  1382. {
  1383. KeyValues *dat = FindKey( keyName, true );
  1384. if ( dat )
  1385. {
  1386. if ( dat->m_iDataType == TYPE_STRING && dat->m_sValue == value )
  1387. {
  1388. return;
  1389. }
  1390. // delete the old value
  1391. delete [] dat->m_sValue;
  1392. // make sure we're not storing the WSTRING - as we're converting over to STRING
  1393. delete [] dat->m_wsValue;
  1394. dat->m_wsValue = NULL;
  1395. if (!value)
  1396. {
  1397. // ensure a valid value
  1398. value = "";
  1399. }
  1400. // allocate memory for the new value and copy it in
  1401. int len = Q_strlen( value );
  1402. dat->m_sValue = new char[len + 1];
  1403. Q_memcpy( dat->m_sValue, value, len+1 );
  1404. dat->m_iDataType = TYPE_STRING;
  1405. }
  1406. }
  1407. //-----------------------------------------------------------------------------
  1408. // Purpose: Set the string value of a keyName.
  1409. //-----------------------------------------------------------------------------
  1410. void KeyValues::SetWString( const char *keyName, const wchar_t *value )
  1411. {
  1412. KeyValues *dat = FindKey( keyName, true );
  1413. if ( dat )
  1414. {
  1415. // delete the old value
  1416. delete [] dat->m_wsValue;
  1417. // make sure we're not storing the STRING - as we're converting over to WSTRING
  1418. delete [] dat->m_sValue;
  1419. dat->m_sValue = NULL;
  1420. if (!value)
  1421. {
  1422. // ensure a valid value
  1423. value = L"";
  1424. }
  1425. // allocate memory for the new value and copy it in
  1426. int len = Q_wcslen( value );
  1427. dat->m_wsValue = new wchar_t[len + 1];
  1428. Q_memcpy( dat->m_wsValue, value, (len+1) * sizeof(wchar_t) );
  1429. dat->m_iDataType = TYPE_WSTRING;
  1430. }
  1431. }
  1432. //-----------------------------------------------------------------------------
  1433. // Purpose: Set the integer value of a keyName.
  1434. //-----------------------------------------------------------------------------
  1435. void KeyValues::SetInt( const char *keyName, int value )
  1436. {
  1437. KeyValues *dat = FindKey( keyName, true );
  1438. if ( dat )
  1439. {
  1440. dat->m_iValue = value;
  1441. dat->m_iDataType = TYPE_INT;
  1442. }
  1443. }
  1444. //-----------------------------------------------------------------------------
  1445. // Purpose: Set the integer value of a keyName.
  1446. //-----------------------------------------------------------------------------
  1447. void KeyValues::SetUint64( const char *keyName, uint64 value )
  1448. {
  1449. KeyValues *dat = FindKey( keyName, true );
  1450. if ( dat )
  1451. {
  1452. // delete the old value
  1453. delete [] dat->m_sValue;
  1454. // make sure we're not storing the WSTRING - as we're converting over to STRING
  1455. delete [] dat->m_wsValue;
  1456. dat->m_wsValue = NULL;
  1457. dat->m_sValue = new char[sizeof(uint64)];
  1458. *((uint64 *)dat->m_sValue) = value;
  1459. dat->m_iDataType = TYPE_UINT64;
  1460. }
  1461. }
  1462. //-----------------------------------------------------------------------------
  1463. // Purpose: Set the float value of a keyName.
  1464. //-----------------------------------------------------------------------------
  1465. void KeyValues::SetFloat( const char *keyName, float value )
  1466. {
  1467. KeyValues *dat = FindKey( keyName, true );
  1468. if ( dat )
  1469. {
  1470. dat->m_flValue = value;
  1471. dat->m_iDataType = TYPE_FLOAT;
  1472. }
  1473. }
  1474. void KeyValues::SetName( const char * setName )
  1475. {
  1476. m_iKeyName = s_pfGetSymbolForString( setName, true );
  1477. }
  1478. //-----------------------------------------------------------------------------
  1479. // Purpose: Set the pointer value of a keyName.
  1480. //-----------------------------------------------------------------------------
  1481. void KeyValues::SetPtr( const char *keyName, void *value )
  1482. {
  1483. KeyValues *dat = FindKey( keyName, true );
  1484. if ( dat )
  1485. {
  1486. dat->m_pValue = value;
  1487. dat->m_iDataType = TYPE_PTR;
  1488. }
  1489. }
  1490. //-----------------------------------------------------------------------------
  1491. // Purpose: Copies the tree from the other KeyValues into this one, recursively
  1492. // beginning with the root specified by rootSrc.
  1493. //-----------------------------------------------------------------------------
  1494. void KeyValues::CopyKeyValuesFromRecursive( const KeyValues& rootSrc )
  1495. {
  1496. // This code used to be recursive, which was more elegant. Unfortunately, it also blew the stack for large
  1497. // KeyValues. So now we have the iterative version which is uglier but doesn't blow the stack.
  1498. // This uses breadth-first traversal.
  1499. struct CopyStruct
  1500. {
  1501. KeyValues* dst;
  1502. const KeyValues* src;
  1503. };
  1504. char tmp[256];
  1505. KeyValues* localDst = NULL;
  1506. CUtlQueue<CopyStruct> nodeQ;
  1507. nodeQ.Insert({ this, &rootSrc });
  1508. while ( nodeQ.Count() > 0 )
  1509. {
  1510. CopyStruct cs = nodeQ.RemoveAtHead();
  1511. // Process all the siblings of the current node. If anyone has a child, add it to the queue.
  1512. while (cs.src)
  1513. {
  1514. Assert( (cs.src != NULL) == (cs.dst != NULL) );
  1515. // Copy the node contents
  1516. cs.dst->CopyKeyValue( *cs.src, sizeof(tmp), tmp );
  1517. // Add children to the queue to process later.
  1518. if (cs.src->m_pSub) {
  1519. cs.dst->m_pSub = localDst = new KeyValues( NULL );
  1520. nodeQ.Insert({ localDst, cs.src->m_pSub });
  1521. }
  1522. // Process siblings until we hit the end of the line.
  1523. if (cs.src->m_pPeer) {
  1524. cs.dst->m_pPeer = new KeyValues( NULL );
  1525. }
  1526. else {
  1527. cs.dst->m_pPeer = NULL;
  1528. }
  1529. // Advance to the next peer.
  1530. cs.src = cs.src->m_pPeer;
  1531. cs.dst = cs.dst->m_pPeer;
  1532. }
  1533. }
  1534. }
  1535. //-----------------------------------------------------------------------------
  1536. // Purpose: Copies a single KeyValue from src to this, using the provided temporary
  1537. // buffer if the keytype requires it. Does NOT recurse.
  1538. //-----------------------------------------------------------------------------
  1539. void KeyValues::CopyKeyValue( const KeyValues& src, size_t tmpBufferSizeB, char* tmpBuffer )
  1540. {
  1541. m_iKeyName = src.GetNameSymbol();
  1542. if ( src.m_pSub )
  1543. return;
  1544. m_iDataType = src.m_iDataType;
  1545. switch( src.m_iDataType )
  1546. {
  1547. case TYPE_NONE:
  1548. break;
  1549. case TYPE_STRING:
  1550. if( src.m_sValue )
  1551. {
  1552. int len = Q_strlen(src.m_sValue) + 1;
  1553. m_sValue = new char[len];
  1554. Q_strncpy( m_sValue, src.m_sValue, len );
  1555. }
  1556. break;
  1557. case TYPE_INT:
  1558. {
  1559. m_iValue = src.m_iValue;
  1560. Q_snprintf( tmpBuffer, tmpBufferSizeB, "%d", m_iValue );
  1561. int len = Q_strlen(tmpBuffer) + 1;
  1562. m_sValue = new char[len];
  1563. Q_strncpy( m_sValue, tmpBuffer, len );
  1564. }
  1565. break;
  1566. case TYPE_FLOAT:
  1567. {
  1568. m_flValue = src.m_flValue;
  1569. Q_snprintf( tmpBuffer, tmpBufferSizeB, "%f", m_flValue );
  1570. int len = Q_strlen(tmpBuffer) + 1;
  1571. m_sValue = new char[len];
  1572. Q_strncpy( m_sValue, tmpBuffer, len );
  1573. }
  1574. break;
  1575. case TYPE_PTR:
  1576. {
  1577. m_pValue = src.m_pValue;
  1578. }
  1579. break;
  1580. case TYPE_UINT64:
  1581. {
  1582. m_sValue = new char[sizeof(uint64)];
  1583. Q_memcpy( m_sValue, src.m_sValue, sizeof(uint64) );
  1584. }
  1585. break;
  1586. case TYPE_COLOR:
  1587. {
  1588. m_Color[0] = src.m_Color[0];
  1589. m_Color[1] = src.m_Color[1];
  1590. m_Color[2] = src.m_Color[2];
  1591. m_Color[3] = src.m_Color[3];
  1592. }
  1593. break;
  1594. default:
  1595. {
  1596. // do nothing . .what the heck is this?
  1597. Assert( 0 );
  1598. }
  1599. break;
  1600. }
  1601. }
  1602. KeyValues& KeyValues::operator=( const KeyValues& src )
  1603. {
  1604. RemoveEverything();
  1605. Init(); // reset all values
  1606. CopyKeyValuesFromRecursive( src );
  1607. return *this;
  1608. }
  1609. //-----------------------------------------------------------------------------
  1610. // Make a new copy of all subkeys, add them all to the passed-in keyvalues
  1611. //-----------------------------------------------------------------------------
  1612. void KeyValues::CopySubkeys( KeyValues *pParent ) const
  1613. {
  1614. // recursively copy subkeys
  1615. // Also maintain ordering....
  1616. KeyValues *pPrev = NULL;
  1617. for ( KeyValues *sub = m_pSub; sub != NULL; sub = sub->m_pPeer )
  1618. {
  1619. // take a copy of the subkey
  1620. KeyValues *dat = sub->MakeCopy();
  1621. // add into subkey list
  1622. if (pPrev)
  1623. {
  1624. pPrev->m_pPeer = dat;
  1625. }
  1626. else
  1627. {
  1628. pParent->m_pSub = dat;
  1629. }
  1630. dat->m_pPeer = NULL;
  1631. pPrev = dat;
  1632. }
  1633. }
  1634. //-----------------------------------------------------------------------------
  1635. // Purpose: Makes a copy of the whole key-value pair set
  1636. //-----------------------------------------------------------------------------
  1637. KeyValues *KeyValues::MakeCopy( void ) const
  1638. {
  1639. KeyValues *newKeyValue = new KeyValues(GetName());
  1640. newKeyValue->UsesEscapeSequences( m_bHasEscapeSequences != 0 );
  1641. newKeyValue->UsesConditionals( m_bEvaluateConditionals != 0 );
  1642. // copy data
  1643. newKeyValue->m_iDataType = m_iDataType;
  1644. switch ( m_iDataType )
  1645. {
  1646. case TYPE_STRING:
  1647. {
  1648. if ( m_sValue )
  1649. {
  1650. int len = Q_strlen( m_sValue );
  1651. Assert( !newKeyValue->m_sValue );
  1652. newKeyValue->m_sValue = new char[len + 1];
  1653. Q_memcpy( newKeyValue->m_sValue, m_sValue, len+1 );
  1654. }
  1655. }
  1656. break;
  1657. case TYPE_WSTRING:
  1658. {
  1659. if ( m_wsValue )
  1660. {
  1661. int len = Q_wcslen( m_wsValue );
  1662. newKeyValue->m_wsValue = new wchar_t[len+1];
  1663. Q_memcpy( newKeyValue->m_wsValue, m_wsValue, (len+1)*sizeof(wchar_t));
  1664. }
  1665. }
  1666. break;
  1667. case TYPE_INT:
  1668. newKeyValue->m_iValue = m_iValue;
  1669. break;
  1670. case TYPE_FLOAT:
  1671. newKeyValue->m_flValue = m_flValue;
  1672. break;
  1673. case TYPE_PTR:
  1674. newKeyValue->m_pValue = m_pValue;
  1675. break;
  1676. case TYPE_COLOR:
  1677. newKeyValue->m_Color[0] = m_Color[0];
  1678. newKeyValue->m_Color[1] = m_Color[1];
  1679. newKeyValue->m_Color[2] = m_Color[2];
  1680. newKeyValue->m_Color[3] = m_Color[3];
  1681. break;
  1682. case TYPE_UINT64:
  1683. newKeyValue->m_sValue = new char[sizeof(uint64)];
  1684. Q_memcpy( newKeyValue->m_sValue, m_sValue, sizeof(uint64) );
  1685. break;
  1686. };
  1687. // recursively copy subkeys
  1688. CopySubkeys( newKeyValue );
  1689. return newKeyValue;
  1690. }
  1691. //-----------------------------------------------------------------------------
  1692. // Purpose:
  1693. //-----------------------------------------------------------------------------
  1694. KeyValues *KeyValues::MakeCopy( bool copySiblings ) const
  1695. {
  1696. KeyValues* rootDest = MakeCopy();
  1697. if ( !copySiblings )
  1698. return rootDest;
  1699. const KeyValues* curSrc = GetNextKey();
  1700. KeyValues* curDest = rootDest;
  1701. while (curSrc) {
  1702. curDest->SetNextKey( curSrc->MakeCopy() );
  1703. curDest = curDest->GetNextKey();
  1704. curSrc = curSrc->GetNextKey();
  1705. }
  1706. return rootDest;
  1707. }
  1708. //-----------------------------------------------------------------------------
  1709. // Purpose: Check if a keyName has no value assigned to it.
  1710. //-----------------------------------------------------------------------------
  1711. bool KeyValues::IsEmpty(const char *keyName)
  1712. {
  1713. KeyValues *dat = FindKey(keyName, false);
  1714. if (!dat)
  1715. return true;
  1716. if (dat->m_iDataType == TYPE_NONE && dat->m_pSub == NULL)
  1717. return true;
  1718. return false;
  1719. }
  1720. //-----------------------------------------------------------------------------
  1721. // Purpose: Clear out all subkeys, and the current value
  1722. //-----------------------------------------------------------------------------
  1723. void KeyValues::Clear( void )
  1724. {
  1725. delete m_pSub;
  1726. m_pSub = NULL;
  1727. m_iDataType = TYPE_NONE;
  1728. }
  1729. //-----------------------------------------------------------------------------
  1730. // Purpose: Get the data type of the value stored in a keyName
  1731. //-----------------------------------------------------------------------------
  1732. KeyValues::types_t KeyValues::GetDataType(const char *keyName)
  1733. {
  1734. KeyValues *dat = FindKey(keyName, false);
  1735. if (dat)
  1736. return (types_t)dat->m_iDataType;
  1737. return TYPE_NONE;
  1738. }
  1739. //-----------------------------------------------------------------------------
  1740. // Purpose: Deletion, ensures object gets deleted from correct heap
  1741. //-----------------------------------------------------------------------------
  1742. void KeyValues::deleteThis()
  1743. {
  1744. delete this;
  1745. }
  1746. //-----------------------------------------------------------------------------
  1747. // Purpose:
  1748. // Input : includedKeys -
  1749. //-----------------------------------------------------------------------------
  1750. void KeyValues::AppendIncludedKeys( CUtlVector< KeyValues * >& includedKeys )
  1751. {
  1752. // Append any included keys, too...
  1753. KeyValues *insertSpot = this;
  1754. int includeCount = includedKeys.Count();
  1755. for ( int i = 0; i < includeCount; i++ )
  1756. {
  1757. KeyValues *kv = includedKeys[ i ];
  1758. Assert( kv );
  1759. while ( insertSpot->GetNextKey() )
  1760. {
  1761. insertSpot = insertSpot->GetNextKey();
  1762. }
  1763. insertSpot->SetNextKey( kv );
  1764. }
  1765. }
  1766. void KeyValues::ParseIncludedKeys( char const *resourceName, const char *filetoinclude,
  1767. IBaseFileSystem* pFileSystem, const char *pPathID, CUtlVector< KeyValues * >& includedKeys )
  1768. {
  1769. Assert( resourceName );
  1770. Assert( filetoinclude );
  1771. Assert( pFileSystem );
  1772. // Load it...
  1773. if ( !pFileSystem )
  1774. {
  1775. return;
  1776. }
  1777. // Get relative subdirectory
  1778. char fullpath[ 512 ];
  1779. Q_strncpy( fullpath, resourceName, sizeof( fullpath ) );
  1780. // Strip off characters back to start or first /
  1781. int len = Q_strlen( fullpath );
  1782. for (;;)
  1783. {
  1784. if ( len <= 0 )
  1785. {
  1786. break;
  1787. }
  1788. if ( fullpath[ len - 1 ] == '\\' ||
  1789. fullpath[ len - 1 ] == '/' )
  1790. {
  1791. break;
  1792. }
  1793. // zero it
  1794. fullpath[ len - 1 ] = 0;
  1795. --len;
  1796. }
  1797. // Append included file
  1798. Q_strncat( fullpath, filetoinclude, sizeof( fullpath ), COPY_ALL_CHARACTERS );
  1799. KeyValues *newKV = new KeyValues( fullpath );
  1800. // CUtlSymbol save = s_CurrentFileSymbol; // did that had any use ???
  1801. newKV->UsesEscapeSequences( m_bHasEscapeSequences != 0 ); // use same format as parent
  1802. newKV->UsesConditionals( m_bEvaluateConditionals != 0 );
  1803. if ( newKV->LoadFromFile( pFileSystem, fullpath, pPathID ) )
  1804. {
  1805. includedKeys.AddToTail( newKV );
  1806. }
  1807. else
  1808. {
  1809. DevMsg( "KeyValues::ParseIncludedKeys: Couldn't load included keyvalue file %s\n", fullpath );
  1810. newKV->deleteThis();
  1811. }
  1812. // s_CurrentFileSymbol = save;
  1813. }
  1814. //-----------------------------------------------------------------------------
  1815. // Purpose:
  1816. // Input : baseKeys -
  1817. //-----------------------------------------------------------------------------
  1818. void KeyValues::MergeBaseKeys( CUtlVector< KeyValues * >& baseKeys )
  1819. {
  1820. int includeCount = baseKeys.Count();
  1821. int i;
  1822. for ( i = 0; i < includeCount; i++ )
  1823. {
  1824. KeyValues *kv = baseKeys[ i ];
  1825. Assert( kv );
  1826. RecursiveMergeKeyValues( kv );
  1827. }
  1828. }
  1829. //-----------------------------------------------------------------------------
  1830. // Purpose:
  1831. // Input : baseKV - keyvalues we're basing ourselves on
  1832. //-----------------------------------------------------------------------------
  1833. void KeyValues::RecursiveMergeKeyValues( KeyValues *baseKV )
  1834. {
  1835. // Merge ourselves
  1836. // we always want to keep our value, so nothing to do here
  1837. // Now merge our children
  1838. for ( KeyValues *baseChild = baseKV->m_pSub; baseChild != NULL; baseChild = baseChild->m_pPeer )
  1839. {
  1840. // for each child in base, see if we have a matching kv
  1841. bool bFoundMatch = false;
  1842. // If we have a child by the same name, merge those keys
  1843. for ( KeyValues *newChild = m_pSub; newChild != NULL; newChild = newChild->m_pPeer )
  1844. {
  1845. if ( !Q_strcmp( baseChild->GetName(), newChild->GetName() ) )
  1846. {
  1847. newChild->RecursiveMergeKeyValues( baseChild );
  1848. bFoundMatch = true;
  1849. break;
  1850. }
  1851. }
  1852. // If not merged, append this key
  1853. if ( !bFoundMatch )
  1854. {
  1855. KeyValues *dat = baseChild->MakeCopy();
  1856. Assert( dat );
  1857. AddSubKey( dat );
  1858. }
  1859. }
  1860. }
  1861. //-----------------------------------------------------------------------------
  1862. // Returns whether a keyvalues conditional evaluates to true or false
  1863. // Needs more flexibility with conditionals, checking convars would be nice.
  1864. //-----------------------------------------------------------------------------
  1865. bool EvaluateConditional( const char *str )
  1866. {
  1867. if ( !str )
  1868. return false;
  1869. if ( *str == '[' )
  1870. str++;
  1871. bool bNot = false; // should we negate this command?
  1872. if ( *str == '!' )
  1873. bNot = true;
  1874. if ( Q_stristr( str, "$X360" ) )
  1875. return IsX360() ^ bNot;
  1876. if ( Q_stristr( str, "$WIN32" ) )
  1877. return IsPC() ^ bNot; // hack hack - for now WIN32 really means IsPC
  1878. if ( Q_stristr( str, "$WINDOWS" ) )
  1879. return IsWindows() ^ bNot;
  1880. if ( Q_stristr( str, "$OSX" ) )
  1881. return IsOSX() ^ bNot;
  1882. if ( Q_stristr( str, "$LINUX" ) )
  1883. return IsLinux() ^ bNot;
  1884. if ( Q_stristr( str, "$POSIX" ) )
  1885. return IsPosix() ^ bNot;
  1886. return false;
  1887. }
  1888. //-----------------------------------------------------------------------------
  1889. // Read from a buffer...
  1890. //-----------------------------------------------------------------------------
  1891. bool KeyValues::LoadFromBuffer( char const *resourceName, CUtlBuffer &buf, IBaseFileSystem* pFileSystem, const char *pPathID )
  1892. {
  1893. KeyValues *pPreviousKey = NULL;
  1894. KeyValues *pCurrentKey = this;
  1895. CUtlVector< KeyValues * > includedKeys;
  1896. CUtlVector< KeyValues * > baseKeys;
  1897. bool wasQuoted;
  1898. bool wasConditional;
  1899. g_KeyValuesErrorStack.SetFilename( resourceName );
  1900. do
  1901. {
  1902. bool bAccepted = true;
  1903. // the first thing must be a key
  1904. const char *s = ReadToken( buf, wasQuoted, wasConditional );
  1905. if ( !buf.IsValid() || !s || *s == 0 )
  1906. break;
  1907. if ( !Q_stricmp( s, "#include" ) ) // special include macro (not a key name)
  1908. {
  1909. s = ReadToken( buf, wasQuoted, wasConditional );
  1910. // Name of subfile to load is now in s
  1911. if ( !s || *s == 0 )
  1912. {
  1913. g_KeyValuesErrorStack.ReportError("#include is NULL " );
  1914. }
  1915. else
  1916. {
  1917. ParseIncludedKeys( resourceName, s, pFileSystem, pPathID, includedKeys );
  1918. }
  1919. continue;
  1920. }
  1921. else if ( !Q_stricmp( s, "#base" ) )
  1922. {
  1923. s = ReadToken( buf, wasQuoted, wasConditional );
  1924. // Name of subfile to load is now in s
  1925. if ( !s || *s == 0 )
  1926. {
  1927. g_KeyValuesErrorStack.ReportError("#base is NULL " );
  1928. }
  1929. else
  1930. {
  1931. ParseIncludedKeys( resourceName, s, pFileSystem, pPathID, baseKeys );
  1932. }
  1933. continue;
  1934. }
  1935. if ( !pCurrentKey )
  1936. {
  1937. pCurrentKey = new KeyValues( s );
  1938. Assert( pCurrentKey );
  1939. pCurrentKey->UsesEscapeSequences( m_bHasEscapeSequences != 0 ); // same format has parent use
  1940. pCurrentKey->UsesConditionals( m_bEvaluateConditionals != 0 );
  1941. if ( pPreviousKey )
  1942. {
  1943. pPreviousKey->SetNextKey( pCurrentKey );
  1944. }
  1945. }
  1946. else
  1947. {
  1948. pCurrentKey->SetName( s );
  1949. }
  1950. // get the '{'
  1951. s = ReadToken( buf, wasQuoted, wasConditional );
  1952. if ( wasConditional )
  1953. {
  1954. bAccepted = !m_bEvaluateConditionals || EvaluateConditional( s );
  1955. // Now get the '{'
  1956. s = ReadToken( buf, wasQuoted, wasConditional );
  1957. }
  1958. if ( s && *s == '{' && !wasQuoted )
  1959. {
  1960. // header is valid so load the file
  1961. pCurrentKey->RecursiveLoadFromBuffer( resourceName, buf );
  1962. }
  1963. else
  1964. {
  1965. g_KeyValuesErrorStack.ReportError("LoadFromBuffer: missing {" );
  1966. }
  1967. if ( !bAccepted )
  1968. {
  1969. if ( pPreviousKey )
  1970. {
  1971. pPreviousKey->SetNextKey( NULL );
  1972. }
  1973. pCurrentKey->Clear();
  1974. }
  1975. else
  1976. {
  1977. pPreviousKey = pCurrentKey;
  1978. pCurrentKey = NULL;
  1979. }
  1980. } while ( buf.IsValid() );
  1981. AppendIncludedKeys( includedKeys );
  1982. {
  1983. // delete included keys!
  1984. int i;
  1985. for ( i = includedKeys.Count() - 1; i > 0; i-- )
  1986. {
  1987. KeyValues *kv = includedKeys[ i ];
  1988. kv->deleteThis();
  1989. }
  1990. }
  1991. MergeBaseKeys( baseKeys );
  1992. {
  1993. // delete base keys!
  1994. int i;
  1995. for ( i = baseKeys.Count() - 1; i >= 0; i-- )
  1996. {
  1997. KeyValues *kv = baseKeys[ i ];
  1998. kv->deleteThis();
  1999. }
  2000. }
  2001. g_KeyValuesErrorStack.SetFilename( "" );
  2002. return true;
  2003. }
  2004. //-----------------------------------------------------------------------------
  2005. // Read from a buffer...
  2006. //-----------------------------------------------------------------------------
  2007. bool KeyValues::LoadFromBuffer( char const *resourceName, const char *pBuffer, IBaseFileSystem* pFileSystem, const char *pPathID )
  2008. {
  2009. if ( !pBuffer )
  2010. return true;
  2011. COM_TimestampedLog("KeyValues::LoadFromBuffer(%s%s%s): Begin", pPathID ? pPathID : "", pPathID && resourceName ? "/" : "", resourceName ? resourceName : "");
  2012. int nLen = Q_strlen( pBuffer );
  2013. CUtlBuffer buf( pBuffer, nLen, CUtlBuffer::READ_ONLY | CUtlBuffer::TEXT_BUFFER );
  2014. // Translate Unicode files into UTF-8 before proceeding
  2015. if ( nLen > 2 && (uint8)pBuffer[0] == 0xFF && (uint8)pBuffer[1] == 0xFE )
  2016. {
  2017. int nUTF8Len = V_UnicodeToUTF8( (wchar_t*)(pBuffer+2), NULL, 0 );
  2018. char *pUTF8Buf = new char[nUTF8Len];
  2019. V_UnicodeToUTF8( (wchar_t*)(pBuffer+2), pUTF8Buf, nUTF8Len );
  2020. buf.AssumeMemory( pUTF8Buf, nUTF8Len, nUTF8Len, CUtlBuffer::READ_ONLY | CUtlBuffer::TEXT_BUFFER );
  2021. }
  2022. bool retVal = LoadFromBuffer( resourceName, buf, pFileSystem, pPathID );
  2023. COM_TimestampedLog("KeyValues::LoadFromBuffer(%s%s%s): End", pPathID ? pPathID : "", pPathID && resourceName ? "/" : "", resourceName ? resourceName : "");
  2024. return retVal;
  2025. }
  2026. //-----------------------------------------------------------------------------
  2027. // Purpose:
  2028. //-----------------------------------------------------------------------------
  2029. void KeyValues::RecursiveLoadFromBuffer( char const *resourceName, CUtlBuffer &buf )
  2030. {
  2031. CKeyErrorContext errorReport(this);
  2032. bool wasQuoted;
  2033. bool wasConditional;
  2034. if ( errorReport.GetStackLevel() > 100 )
  2035. {
  2036. g_KeyValuesErrorStack.ReportError( "RecursiveLoadFromBuffer: recursion overflow" );
  2037. return;
  2038. }
  2039. // keep this out of the stack until a key is parsed
  2040. CKeyErrorContext errorKey( INVALID_KEY_SYMBOL );
  2041. // Locate the last child. (Almost always, we will not have any children.)
  2042. // We maintain the pointer to the last child here, so we don't have to re-locate
  2043. // it each time we append the next subkey, which causes O(N^2) time
  2044. KeyValues *pLastChild = FindLastSubKey();;
  2045. // Keep parsing until we hit the closing brace which terminates this block, or a parse error
  2046. while ( 1 )
  2047. {
  2048. bool bAccepted = true;
  2049. // get the key name
  2050. const char * name = ReadToken( buf, wasQuoted, wasConditional );
  2051. if ( !name ) // EOF stop reading
  2052. {
  2053. g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got EOF instead of keyname" );
  2054. break;
  2055. }
  2056. if ( !*name ) // empty token, maybe "" or EOF
  2057. {
  2058. g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got empty keyname" );
  2059. break;
  2060. }
  2061. if ( *name == '}' && !wasQuoted ) // top level closed, stop reading
  2062. break;
  2063. // Always create the key; note that this could potentially
  2064. // cause some duplication, but that's what we want sometimes
  2065. KeyValues *dat = CreateKeyUsingKnownLastChild( name, pLastChild );
  2066. errorKey.Reset( dat->GetNameSymbol() );
  2067. // get the value
  2068. const char * value = ReadToken( buf, wasQuoted, wasConditional );
  2069. if ( wasConditional && value )
  2070. {
  2071. bAccepted = !m_bEvaluateConditionals || EvaluateConditional( value );
  2072. // get the real value
  2073. value = ReadToken( buf, wasQuoted, wasConditional );
  2074. }
  2075. if ( !value )
  2076. {
  2077. g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got NULL key" );
  2078. break;
  2079. }
  2080. if ( *value == '}' && !wasQuoted )
  2081. {
  2082. g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got } in key" );
  2083. break;
  2084. }
  2085. if ( *value == '{' && !wasQuoted )
  2086. {
  2087. // this isn't a key, it's a section
  2088. errorKey.Reset( INVALID_KEY_SYMBOL );
  2089. // sub value list
  2090. dat->RecursiveLoadFromBuffer( resourceName, buf );
  2091. }
  2092. else
  2093. {
  2094. if ( wasConditional )
  2095. {
  2096. g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got conditional between key and value" );
  2097. break;
  2098. }
  2099. if (dat->m_sValue)
  2100. {
  2101. delete[] dat->m_sValue;
  2102. dat->m_sValue = NULL;
  2103. }
  2104. int len = Q_strlen( value );
  2105. // Here, let's determine if we got a float or an int....
  2106. char* pIEnd; // pos where int scan ended
  2107. char* pFEnd; // pos where float scan ended
  2108. const char* pSEnd = value + len ; // pos where token ends
  2109. int ival = strtol( value, &pIEnd, 10 );
  2110. float fval = (float)strtod( value, &pFEnd );
  2111. bool bOverflow = ( ival == LONG_MAX || ival == LONG_MIN ) && errno == ERANGE;
  2112. #ifdef POSIX
  2113. // strtod supports hex representation in strings under posix but we DON'T
  2114. // want that support in keyvalues, so undo it here if needed
  2115. if ( len > 1 && tolower(value[1]) == 'x' )
  2116. {
  2117. fval = 0.0f;
  2118. pFEnd = (char *)value;
  2119. }
  2120. #endif
  2121. if ( *value == 0 )
  2122. {
  2123. dat->m_iDataType = TYPE_STRING;
  2124. }
  2125. else if ( ( 18 == len ) && ( value[0] == '0' ) && ( value[1] == 'x' ) )
  2126. {
  2127. // an 18-byte value prefixed with "0x" (followed by 16 hex digits) is an int64 value
  2128. int64 retVal = 0;
  2129. for( int i=2; i < 2 + 16; i++ )
  2130. {
  2131. char digit = value[i];
  2132. if ( digit >= 'a' )
  2133. digit -= 'a' - ( '9' + 1 );
  2134. else
  2135. if ( digit >= 'A' )
  2136. digit -= 'A' - ( '9' + 1 );
  2137. retVal = ( retVal * 16 ) + ( digit - '0' );
  2138. }
  2139. dat->m_sValue = new char[sizeof(uint64)];
  2140. *((uint64 *)dat->m_sValue) = retVal;
  2141. dat->m_iDataType = TYPE_UINT64;
  2142. }
  2143. else if ( (pFEnd > pIEnd) && (pFEnd == pSEnd) )
  2144. {
  2145. dat->m_flValue = fval;
  2146. dat->m_iDataType = TYPE_FLOAT;
  2147. }
  2148. else if (pIEnd == pSEnd && !bOverflow)
  2149. {
  2150. dat->m_iValue = ival;
  2151. dat->m_iDataType = TYPE_INT;
  2152. }
  2153. else
  2154. {
  2155. dat->m_iDataType = TYPE_STRING;
  2156. }
  2157. if (dat->m_iDataType == TYPE_STRING)
  2158. {
  2159. // copy in the string information
  2160. dat->m_sValue = new char[len+1];
  2161. Q_memcpy( dat->m_sValue, value, len+1 );
  2162. }
  2163. // Look ahead one token for a conditional tag
  2164. int prevPos = buf.TellGet();
  2165. const char *peek = ReadToken( buf, wasQuoted, wasConditional );
  2166. if ( wasConditional )
  2167. {
  2168. bAccepted = !m_bEvaluateConditionals || EvaluateConditional( peek );
  2169. }
  2170. else
  2171. {
  2172. buf.SeekGet( CUtlBuffer::SEEK_HEAD, prevPos );
  2173. }
  2174. }
  2175. Assert( dat->m_pPeer == NULL );
  2176. if ( bAccepted )
  2177. {
  2178. Assert( pLastChild == NULL || pLastChild->m_pPeer == dat );
  2179. pLastChild = dat;
  2180. }
  2181. else
  2182. {
  2183. //this->RemoveSubKey( dat );
  2184. if ( pLastChild == NULL )
  2185. {
  2186. Assert( m_pSub == dat );
  2187. m_pSub = NULL;
  2188. }
  2189. else
  2190. {
  2191. Assert( pLastChild->m_pPeer == dat );
  2192. pLastChild->m_pPeer = NULL;
  2193. }
  2194. dat->deleteThis();
  2195. dat = NULL;
  2196. }
  2197. }
  2198. }
  2199. // writes KeyValue as binary data to buffer
  2200. bool KeyValues::WriteAsBinary( CUtlBuffer &buffer )
  2201. {
  2202. if ( buffer.IsText() ) // must be a binary buffer
  2203. return false;
  2204. if ( !buffer.IsValid() ) // must be valid, no overflows etc
  2205. return false;
  2206. // Write subkeys:
  2207. // loop through all our peers
  2208. for ( KeyValues *dat = this; dat != NULL; dat = dat->m_pPeer )
  2209. {
  2210. // write type
  2211. buffer.PutUnsignedChar( dat->m_iDataType );
  2212. // write name
  2213. buffer.PutString( dat->GetName() );
  2214. // write type
  2215. switch (dat->m_iDataType)
  2216. {
  2217. case TYPE_NONE:
  2218. {
  2219. dat->m_pSub->WriteAsBinary( buffer );
  2220. break;
  2221. }
  2222. case TYPE_STRING:
  2223. {
  2224. if (dat->m_sValue && *(dat->m_sValue))
  2225. {
  2226. buffer.PutString( dat->m_sValue );
  2227. }
  2228. else
  2229. {
  2230. buffer.PutString( "" );
  2231. }
  2232. break;
  2233. }
  2234. case TYPE_WSTRING:
  2235. {
  2236. Assert( !"TYPE_WSTRING" );
  2237. break;
  2238. }
  2239. case TYPE_INT:
  2240. {
  2241. buffer.PutInt( dat->m_iValue );
  2242. break;
  2243. }
  2244. case TYPE_UINT64:
  2245. {
  2246. buffer.PutDouble( *((double *)dat->m_sValue) );
  2247. break;
  2248. }
  2249. case TYPE_FLOAT:
  2250. {
  2251. buffer.PutFloat( dat->m_flValue );
  2252. break;
  2253. }
  2254. case TYPE_COLOR:
  2255. {
  2256. buffer.PutUnsignedChar( dat->m_Color[0] );
  2257. buffer.PutUnsignedChar( dat->m_Color[1] );
  2258. buffer.PutUnsignedChar( dat->m_Color[2] );
  2259. buffer.PutUnsignedChar( dat->m_Color[3] );
  2260. break;
  2261. }
  2262. case TYPE_PTR:
  2263. {
  2264. buffer.PutUnsignedInt( (int)dat->m_pValue );
  2265. }
  2266. default:
  2267. break;
  2268. }
  2269. }
  2270. // write tail, marks end of peers
  2271. buffer.PutUnsignedChar( TYPE_NUMTYPES );
  2272. return buffer.IsValid();
  2273. }
  2274. // read KeyValues from binary buffer, returns true if parsing was successful
  2275. bool KeyValues::ReadAsBinary( CUtlBuffer &buffer, int nStackDepth )
  2276. {
  2277. if ( buffer.IsText() ) // must be a binary buffer
  2278. return false;
  2279. if ( !buffer.IsValid() ) // must be valid, no overflows etc
  2280. return false;
  2281. RemoveEverything(); // remove current content
  2282. Init(); // reset
  2283. if ( nStackDepth > 100 )
  2284. {
  2285. AssertMsgOnce( false, "KeyValues::ReadAsBinary() stack depth > 100\n" );
  2286. return false;
  2287. }
  2288. KeyValues *dat = this;
  2289. types_t type = (types_t)buffer.GetUnsignedChar();
  2290. // loop through all our peers
  2291. while ( true )
  2292. {
  2293. if ( type == TYPE_NUMTYPES )
  2294. break; // no more peers
  2295. dat->m_iDataType = type;
  2296. {
  2297. char token[KEYVALUES_TOKEN_SIZE];
  2298. buffer.GetString( token );
  2299. token[KEYVALUES_TOKEN_SIZE-1] = 0;
  2300. dat->SetName( token );
  2301. }
  2302. switch ( type )
  2303. {
  2304. case TYPE_NONE:
  2305. {
  2306. dat->m_pSub = new KeyValues("");
  2307. dat->m_pSub->ReadAsBinary( buffer, nStackDepth + 1 );
  2308. break;
  2309. }
  2310. case TYPE_STRING:
  2311. {
  2312. char token[KEYVALUES_TOKEN_SIZE];
  2313. buffer.GetString( token );
  2314. token[KEYVALUES_TOKEN_SIZE-1] = 0;
  2315. int len = Q_strlen( token );
  2316. dat->m_sValue = new char[len + 1];
  2317. Q_memcpy( dat->m_sValue, token, len+1 );
  2318. break;
  2319. }
  2320. case TYPE_WSTRING:
  2321. {
  2322. Assert( !"TYPE_WSTRING" );
  2323. break;
  2324. }
  2325. case TYPE_INT:
  2326. {
  2327. dat->m_iValue = buffer.GetInt();
  2328. break;
  2329. }
  2330. case TYPE_UINT64:
  2331. {
  2332. dat->m_sValue = new char[sizeof(uint64)];
  2333. *((uint64 *)dat->m_sValue) = buffer.GetInt64();
  2334. break;
  2335. }
  2336. case TYPE_FLOAT:
  2337. {
  2338. dat->m_flValue = buffer.GetFloat();
  2339. break;
  2340. }
  2341. case TYPE_COLOR:
  2342. {
  2343. dat->m_Color[0] = buffer.GetUnsignedChar();
  2344. dat->m_Color[1] = buffer.GetUnsignedChar();
  2345. dat->m_Color[2] = buffer.GetUnsignedChar();
  2346. dat->m_Color[3] = buffer.GetUnsignedChar();
  2347. break;
  2348. }
  2349. case TYPE_PTR:
  2350. {
  2351. dat->m_pValue = (void*)buffer.GetUnsignedInt();
  2352. }
  2353. default:
  2354. break;
  2355. }
  2356. if ( !buffer.IsValid() ) // error occured
  2357. return false;
  2358. type = (types_t)buffer.GetUnsignedChar();
  2359. if ( type == TYPE_NUMTYPES )
  2360. break;
  2361. // new peer follows
  2362. dat->m_pPeer = new KeyValues("");
  2363. dat = dat->m_pPeer;
  2364. }
  2365. return buffer.IsValid();
  2366. }
  2367. #include "tier0/memdbgoff.h"
  2368. //-----------------------------------------------------------------------------
  2369. // Purpose: memory allocator
  2370. //-----------------------------------------------------------------------------
  2371. void *KeyValues::operator new( size_t iAllocSize )
  2372. {
  2373. MEM_ALLOC_CREDIT();
  2374. return KeyValuesSystem()->AllocKeyValuesMemory( (int)iAllocSize );
  2375. }
  2376. void *KeyValues::operator new( size_t iAllocSize, int nBlockUse, const char *pFileName, int nLine )
  2377. {
  2378. MemAlloc_PushAllocDbgInfo( pFileName, nLine );
  2379. void *p = KeyValuesSystem()->AllocKeyValuesMemory( (int)iAllocSize );
  2380. MemAlloc_PopAllocDbgInfo();
  2381. return p;
  2382. }
  2383. //-----------------------------------------------------------------------------
  2384. // Purpose: deallocator
  2385. //-----------------------------------------------------------------------------
  2386. void KeyValues::operator delete( void *pMem )
  2387. {
  2388. KeyValuesSystem()->FreeKeyValuesMemory(pMem);
  2389. }
  2390. void KeyValues::operator delete( void *pMem, int nBlockUse, const char *pFileName, int nLine )
  2391. {
  2392. KeyValuesSystem()->FreeKeyValuesMemory(pMem);
  2393. }
  2394. void KeyValues::UnpackIntoStructure( KeyValuesUnpackStructure const *pUnpackTable, void *pDest, size_t DestSizeInBytes )
  2395. {
  2396. #ifdef DBGFLAG_ASSERT
  2397. void *pDestEnd = ( char * )pDest + DestSizeInBytes + 1;
  2398. #endif
  2399. uint8 *dest=(uint8 *) pDest;
  2400. while( pUnpackTable->m_pKeyName )
  2401. {
  2402. uint8 *dest_field=dest+pUnpackTable->m_nFieldOffset;
  2403. KeyValues *find_it=FindKey( pUnpackTable->m_pKeyName );
  2404. switch( pUnpackTable->m_eDataType )
  2405. {
  2406. case UNPACK_TYPE_FLOAT:
  2407. {
  2408. Assert( dest_field + sizeof( float ) < pDestEnd );
  2409. float default_value=(pUnpackTable->m_pKeyDefault)?atof(pUnpackTable->m_pKeyDefault):0.0;
  2410. *( ( float *) dest_field)=GetFloat( pUnpackTable->m_pKeyName, default_value );
  2411. break;
  2412. }
  2413. break;
  2414. case UNPACK_TYPE_VECTOR:
  2415. {
  2416. Assert( dest_field + sizeof( Vector ) < pDestEnd );
  2417. Vector *dest_v=(Vector *) dest_field;
  2418. char const *src_string=
  2419. GetString( pUnpackTable->m_pKeyName, pUnpackTable->m_pKeyDefault );
  2420. if ( (!src_string) ||
  2421. ( sscanf(src_string,"%f %f %f",
  2422. &(dest_v->x), &(dest_v->y), &(dest_v->z)) != 3))
  2423. dest_v->Init( 0, 0, 0 );
  2424. }
  2425. break;
  2426. case UNPACK_TYPE_FOUR_FLOATS:
  2427. {
  2428. Assert( dest_field + sizeof( float ) * 4 < pDestEnd );
  2429. float *dest_f=(float *) dest_field;
  2430. char const *src_string=
  2431. GetString( pUnpackTable->m_pKeyName, pUnpackTable->m_pKeyDefault );
  2432. if ( (!src_string) ||
  2433. ( sscanf(src_string,"%f %f %f %f",
  2434. dest_f,dest_f+1,dest_f+2,dest_f+3)) != 4)
  2435. memset( dest_f, 0, 4*sizeof(float) );
  2436. }
  2437. break;
  2438. case UNPACK_TYPE_TWO_FLOATS:
  2439. {
  2440. Assert( dest_field + sizeof( float ) * 2 < pDestEnd );
  2441. float *dest_f=(float *) dest_field;
  2442. char const *src_string=
  2443. GetString( pUnpackTable->m_pKeyName, pUnpackTable->m_pKeyDefault );
  2444. if ( (!src_string) ||
  2445. ( sscanf(src_string,"%f %f",
  2446. dest_f,dest_f+1)) != 2)
  2447. memset( dest_f, 0, 2*sizeof(float) );
  2448. }
  2449. break;
  2450. case UNPACK_TYPE_STRING:
  2451. {
  2452. Assert( dest_field + pUnpackTable->m_nFieldSize < pDestEnd );
  2453. char *dest_s=(char *) dest_field;
  2454. strncpy( dest_s, GetString( pUnpackTable->m_pKeyName,
  2455. pUnpackTable->m_pKeyDefault ),
  2456. pUnpackTable->m_nFieldSize );
  2457. }
  2458. break;
  2459. case UNPACK_TYPE_INT:
  2460. {
  2461. Assert( dest_field + sizeof( int ) < pDestEnd );
  2462. int *dest_i=(int *) dest_field;
  2463. int default_int=0;
  2464. if ( pUnpackTable->m_pKeyDefault)
  2465. default_int = atoi( pUnpackTable->m_pKeyDefault );
  2466. *(dest_i)=GetInt( pUnpackTable->m_pKeyName, default_int );
  2467. }
  2468. break;
  2469. case UNPACK_TYPE_VECTOR_COLOR:
  2470. {
  2471. Assert( dest_field + sizeof( Vector ) < pDestEnd );
  2472. Vector *dest_v=(Vector *) dest_field;
  2473. if (find_it)
  2474. {
  2475. Color c=GetColor( pUnpackTable->m_pKeyName );
  2476. dest_v->x = c.r();
  2477. dest_v->y = c.g();
  2478. dest_v->z = c.b();
  2479. }
  2480. else
  2481. {
  2482. if ( pUnpackTable->m_pKeyDefault )
  2483. sscanf(pUnpackTable->m_pKeyDefault,"%f %f %f",
  2484. &(dest_v->x), &(dest_v->y), &(dest_v->z));
  2485. else
  2486. dest_v->Init( 0, 0, 0 );
  2487. }
  2488. *(dest_v) *= (1.0/255);
  2489. }
  2490. }
  2491. pUnpackTable++;
  2492. }
  2493. }
  2494. //-----------------------------------------------------------------------------
  2495. // Helper function for processing a keyvalue tree for console resolution support.
  2496. // Alters key/values for easier console video resolution support.
  2497. // If running SD (640x480), the presence of "???_lodef" creates or slams "???".
  2498. // If running HD (1280x720), the presence of "???_hidef" creates or slams "???".
  2499. //-----------------------------------------------------------------------------
  2500. bool KeyValues::ProcessResolutionKeys( const char *pResString )
  2501. {
  2502. if ( !pResString )
  2503. {
  2504. // not for pc, console only
  2505. return false;
  2506. }
  2507. KeyValues *pSubKey = GetFirstSubKey();
  2508. if ( !pSubKey )
  2509. {
  2510. // not a block
  2511. return false;
  2512. }
  2513. for ( ; pSubKey != NULL; pSubKey = pSubKey->GetNextKey() )
  2514. {
  2515. // recursively descend each sub block
  2516. pSubKey->ProcessResolutionKeys( pResString );
  2517. // check to see if our substring is present
  2518. if ( Q_stristr( pSubKey->GetName(), pResString ) != NULL )
  2519. {
  2520. char normalKeyName[128];
  2521. V_strncpy( normalKeyName, pSubKey->GetName(), sizeof( normalKeyName ) );
  2522. // substring must match exactly, otherwise keys like "_lodef" and "_lodef_wide" would clash.
  2523. char *pString = Q_stristr( normalKeyName, pResString );
  2524. if ( pString && !Q_stricmp( pString, pResString ) )
  2525. {
  2526. *pString = '\0';
  2527. // find and delete the original key (if any)
  2528. KeyValues *pKey = FindKey( normalKeyName );
  2529. if ( pKey )
  2530. {
  2531. // remove the key
  2532. RemoveSubKey( pKey );
  2533. }
  2534. // rename the marked key
  2535. pSubKey->SetName( normalKeyName );
  2536. }
  2537. }
  2538. }
  2539. return true;
  2540. }
  2541. //
  2542. // KeyValues dumping implementation
  2543. //
  2544. bool KeyValues::Dump( IKeyValuesDumpContext *pDump, int nIndentLevel /* = 0 */, bool bSorted /*= false*/ )
  2545. {
  2546. if ( !pDump->KvBeginKey( this, nIndentLevel ) )
  2547. return false;
  2548. if ( bSorted )
  2549. {
  2550. CUtlSortVector< KeyValues*, CUtlSortVectorKeyValuesByName > vecSortedKeys;
  2551. // Dump values
  2552. for ( KeyValues *val = this ? GetFirstValue() : NULL; val; val = val->GetNextValue() )
  2553. {
  2554. vecSortedKeys.InsertNoSort( val );
  2555. }
  2556. vecSortedKeys.RedoSort();
  2557. FOR_EACH_VEC( vecSortedKeys, i )
  2558. {
  2559. if ( !pDump->KvWriteValue( vecSortedKeys[i], nIndentLevel + 1 ) )
  2560. return false;
  2561. }
  2562. vecSortedKeys.Purge();
  2563. // Dump subkeys
  2564. for ( KeyValues *sub = this ? GetFirstTrueSubKey() : NULL; sub; sub = sub->GetNextTrueSubKey() )
  2565. {
  2566. vecSortedKeys.InsertNoSort( sub );
  2567. }
  2568. vecSortedKeys.RedoSort();
  2569. FOR_EACH_VEC( vecSortedKeys, i )
  2570. {
  2571. if ( !vecSortedKeys[i]->Dump( pDump, nIndentLevel + 1, bSorted ) )
  2572. return false;
  2573. }
  2574. }
  2575. else
  2576. {
  2577. // Dump values
  2578. for ( KeyValues *val = this ? GetFirstValue() : NULL; val; val = val->GetNextValue() )
  2579. {
  2580. if ( !pDump->KvWriteValue( val, nIndentLevel + 1 ) )
  2581. return false;
  2582. }
  2583. // Dump subkeys
  2584. for ( KeyValues *sub = this ? GetFirstTrueSubKey() : NULL; sub; sub = sub->GetNextTrueSubKey() )
  2585. {
  2586. if ( !sub->Dump( pDump, nIndentLevel + 1 ) )
  2587. return false;
  2588. }
  2589. }
  2590. return pDump->KvEndKey( this, nIndentLevel );
  2591. }
  2592. bool IKeyValuesDumpContextAsText::KvBeginKey( KeyValues *pKey, int nIndentLevel )
  2593. {
  2594. if ( pKey )
  2595. {
  2596. return
  2597. KvWriteIndent( nIndentLevel ) &&
  2598. KvWriteText( pKey->GetName() ) &&
  2599. KvWriteText( "\n" ) &&
  2600. KvWriteIndent( nIndentLevel ) &&
  2601. KvWriteText( "{\n" );
  2602. }
  2603. else
  2604. {
  2605. return
  2606. KvWriteIndent( nIndentLevel ) &&
  2607. KvWriteText( "<< NULL >>\n" );
  2608. }
  2609. }
  2610. bool IKeyValuesDumpContextAsText::KvWriteValue( KeyValues *val, int nIndentLevel )
  2611. {
  2612. if ( !val )
  2613. {
  2614. return
  2615. KvWriteIndent( nIndentLevel ) &&
  2616. KvWriteText( "<< NULL >>\n" );
  2617. }
  2618. if ( !KvWriteIndent( nIndentLevel ) )
  2619. return false;
  2620. if ( !KvWriteText( val->GetName() ) )
  2621. return false;
  2622. if ( !KvWriteText( " " ) )
  2623. return false;
  2624. switch ( val->GetDataType() )
  2625. {
  2626. case KeyValues::TYPE_STRING:
  2627. {
  2628. if ( !KvWriteText( val->GetString() ) )
  2629. return false;
  2630. }
  2631. break;
  2632. case KeyValues::TYPE_INT:
  2633. {
  2634. int n = val->GetInt();
  2635. char *chBuffer = ( char * ) stackalloc( 128 );
  2636. V_snprintf( chBuffer, 128, "int( %d = 0x%X )", n, n );
  2637. if ( !KvWriteText( chBuffer ) )
  2638. return false;
  2639. }
  2640. break;
  2641. case KeyValues::TYPE_FLOAT:
  2642. {
  2643. float fl = val->GetFloat();
  2644. char *chBuffer = ( char * ) stackalloc( 128 );
  2645. V_snprintf( chBuffer, 128, "float( %f )", fl );
  2646. if ( !KvWriteText( chBuffer ) )
  2647. return false;
  2648. }
  2649. break;
  2650. case KeyValues::TYPE_PTR:
  2651. {
  2652. void *ptr = val->GetPtr();
  2653. char *chBuffer = ( char * ) stackalloc( 128 );
  2654. V_snprintf( chBuffer, 128, "ptr( 0x%p )", ptr );
  2655. if ( !KvWriteText( chBuffer ) )
  2656. return false;
  2657. }
  2658. break;
  2659. case KeyValues::TYPE_WSTRING:
  2660. {
  2661. wchar_t const *wsz = val->GetWString();
  2662. int nLen = V_wcslen( wsz );
  2663. int numBytes = nLen*2 + 64;
  2664. char *chBuffer = ( char * ) stackalloc( numBytes );
  2665. V_snprintf( chBuffer, numBytes, "%ls [wstring, len = %d]", wsz, nLen );
  2666. if ( !KvWriteText( chBuffer ) )
  2667. return false;
  2668. }
  2669. break;
  2670. case KeyValues::TYPE_UINT64:
  2671. {
  2672. uint64 n = val->GetUint64();
  2673. char *chBuffer = ( char * ) stackalloc( 128 );
  2674. V_snprintf( chBuffer, 128, "u64( %lld = 0x%llX )", n, n );
  2675. if ( !KvWriteText( chBuffer ) )
  2676. return false;
  2677. }
  2678. break;
  2679. default:
  2680. break;
  2681. {
  2682. int n = val->GetDataType();
  2683. char *chBuffer = ( char * ) stackalloc( 128 );
  2684. V_snprintf( chBuffer, 128, "??kvtype[%d]", n );
  2685. if ( !KvWriteText( chBuffer ) )
  2686. return false;
  2687. }
  2688. break;
  2689. }
  2690. return KvWriteText( "\n" );
  2691. }
  2692. bool IKeyValuesDumpContextAsText::KvEndKey( KeyValues *pKey, int nIndentLevel )
  2693. {
  2694. if ( pKey )
  2695. {
  2696. return
  2697. KvWriteIndent( nIndentLevel ) &&
  2698. KvWriteText( "}\n" );
  2699. }
  2700. else
  2701. {
  2702. return true;
  2703. }
  2704. }
  2705. bool IKeyValuesDumpContextAsText::KvWriteIndent( int nIndentLevel )
  2706. {
  2707. int numIndentBytes = ( nIndentLevel * 2 + 1 );
  2708. char *pchIndent = ( char * ) stackalloc( numIndentBytes );
  2709. memset( pchIndent, ' ', numIndentBytes - 1 );
  2710. pchIndent[ numIndentBytes - 1 ] = 0;
  2711. return KvWriteText( pchIndent );
  2712. }
  2713. bool CKeyValuesDumpContextAsDevMsg::KvBeginKey( KeyValues *pKey, int nIndentLevel )
  2714. {
  2715. static ConVarRef r_developer( "developer" );
  2716. if ( r_developer.IsValid() && r_developer.GetInt() < m_nDeveloperLevel )
  2717. // If "developer" is not the correct level, then avoid evaluating KeyValues tree early
  2718. return false;
  2719. else
  2720. return IKeyValuesDumpContextAsText::KvBeginKey( pKey, nIndentLevel );
  2721. }
  2722. bool CKeyValuesDumpContextAsDevMsg::KvWriteText( char const *szText )
  2723. {
  2724. if ( m_nDeveloperLevel > 0 )
  2725. {
  2726. DevMsg( m_nDeveloperLevel, "%s", szText );
  2727. }
  2728. else
  2729. {
  2730. Msg( "%s", szText );
  2731. }
  2732. return true;
  2733. }