diff --git a/lib/linux/tier1_i486.a b/lib/linux/tier1_i486.a index 1063dc15..c21b8435 100644 Binary files a/lib/linux/tier1_i486.a and b/lib/linux/tier1_i486.a differ diff --git a/lib/public/tier1.lib b/lib/public/tier1.lib index 766d064e..21f54421 100644 Binary files a/lib/public/tier1.lib and b/lib/public/tier1.lib differ diff --git a/public/tier1/KeyValues.h b/public/tier1/KeyValues.h index caca26f4..c52bd420 100644 --- a/public/tier1/KeyValues.h +++ b/public/tier1/KeyValues.h @@ -1,4 +1,4 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -12,8 +12,6 @@ #pragma once #endif -// #include - #ifndef NULL #ifdef __cplusplus #define NULL 0 @@ -22,15 +20,33 @@ #endif #endif +#include + #include "utlvector.h" #include "Color.h" -class IKeyValuesSystem; class IBaseFileSystem; class CUtlBuffer; class Color; +class KeyValues; +class IKeyValuesDumpContext; typedef void * FileHandle_t; +// single byte identifies a xbox kv file in binary format +// strings are pooled from a searchpath/zip mounted symbol table +#define KV_BINARY_POOLED_FORMAT 0xAA + + +#define FOR_EACH_SUBKEY( kvRoot, kvSubKey ) \ + for ( KeyValues * kvSubKey = kvRoot->GetFirstSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextKey() ) + +#define FOR_EACH_TRUE_SUBKEY( kvRoot, kvSubKey ) \ + for ( KeyValues * kvSubKey = kvRoot->GetFirstTrueSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextTrueSubKey() ) + +#define FOR_EACH_VALUE( kvRoot, kvValue ) \ + for ( KeyValues * kvValue = kvRoot->GetFirstValue(); kvValue != NULL; kvValue = kvValue->GetNextValue() ) + + //----------------------------------------------------------------------------- // Purpose: Simple recursive data access class // Used in vgui for message parameters and resource files @@ -55,28 +71,44 @@ typedef void * FileHandle_t; class KeyValues { public: - KeyValues( const char *setName ); + KeyValues( const char *setName, IKeyValuesSystem *customSystem = NULL, bool ownsCustomSystem = false ); // // AutoDelete class to automatically free the keyvalues. // Simply construct it with the keyvalues you allocated and it will free them when falls out of scope. // When you decide that keyvalues shouldn't be deleted call Assign(NULL) on it. // If you constructed AutoDelete(NULL) you can later assign the keyvalues to be deleted with Assign(pKeyValues). - // You can also pass temporary KeyValues object as an argument to a function by wrapping it into KeyValues::AutoDelete - // instance: call_my_function( KeyValues::AutoDelete( new KeyValues( "test" ) ) ) // class AutoDelete { public: explicit inline AutoDelete( KeyValues *pKeyValues ) : m_pKeyValues( pKeyValues ) {} + explicit inline AutoDelete( const char *pchKVName ) : m_pKeyValues( new KeyValues( pchKVName ) ) {} inline ~AutoDelete( void ) { if( m_pKeyValues ) m_pKeyValues->deleteThis(); } inline void Assign( KeyValues *pKeyValues ) { m_pKeyValues = pKeyValues; } + KeyValues *operator->() { return m_pKeyValues; } + operator KeyValues *() { return m_pKeyValues; } private: AutoDelete( AutoDelete const &x ); // forbid AutoDelete & operator= ( AutoDelete const &x ); // forbid + protected: KeyValues *m_pKeyValues; }; + // + // AutoDeleteInline is useful when you want to hold your keyvalues object inside + // and delete it right after using. + // You can also pass temporary KeyValues object as an argument to a function by wrapping it into KeyValues::AutoDeleteInline + // instance: call_my_function( KeyValues::AutoDeleteInline( new KeyValues( "test" ) ) ) + // + class AutoDeleteInline : public AutoDelete + { + public: + explicit inline AutoDeleteInline( KeyValues *pKeyValues ) : AutoDelete( pKeyValues ) {} + inline operator KeyValues *() const { return m_pKeyValues; } + inline KeyValues * Get() const { return m_pKeyValues; } + }; + // Quick setup constructors KeyValues( const char *setName, const char *firstKey, const char *firstValue ); KeyValues( const char *setName, const char *firstKey, const wchar_t *firstValue ); @@ -146,16 +178,19 @@ public: const char *GetString( const char *keyName = NULL, const char *defaultValue = "" ); const wchar_t *GetWString( const char *keyName = NULL, const wchar_t *defaultValue = L"" ); void *GetPtr( const char *keyName = NULL, void *defaultValue = (void*)0 ); - Color GetColor( const char *keyName = NULL /* default value is all black */); + Color GetColor( const char *keyName = NULL , const Color &defaultColor = Color( 0, 0, 0, 0 ) ); + bool GetBool( const char *keyName = NULL, bool defaultValue = false ) { return GetInt( keyName, defaultValue ? 1 : 0 ) ? true : false; } bool IsEmpty(const char *keyName = NULL); // Data access int GetInt( int keySymbol, int defaultValue = 0 ); + uint64 GetUint64( int keySymbol, uint64 defaultValue = 0 ); float GetFloat( int keySymbol, float defaultValue = 0.0f ); const char *GetString( int keySymbol, const char *defaultValue = "" ); const wchar_t *GetWString( int keySymbol, const wchar_t *defaultValue = L"" ); void *GetPtr( int keySymbol, void *defaultValue = (void*)0 ); Color GetColor( int keySymbol /* default value is all black */); + bool GetBool( int keySymbol, bool defaultValue = false ) { return GetInt( keySymbol, defaultValue ? 1 : 0 ) ? true : false; } bool IsEmpty( int keySymbol ); // Key writing @@ -166,6 +201,7 @@ public: void SetFloat( const char *keyName, float value ); void SetPtr( const char *keyName, void *value ); void SetColor( const char *keyName, Color value); + void SetBool( const char *keyName, bool value ) { SetInt( keyName, value ? 1 : 0 ); } // Memory allocation (optimized) void *operator new( size_t iAllocSize ); @@ -221,6 +257,22 @@ public: // Process conditional keys for widescreen support. bool ProcessResolutionKeys( const char *pResString ); + + // Dump keyvalues recursively into a dump context + bool Dump( IKeyValuesDumpContext *pDump, int nIndentLevel = 0 ); + + // Merge operations describing how two keyvalues can be combined + enum MergeKeyValuesOp_t + { + MERGE_KV_ALL, + MERGE_KV_UPDATE, // update values are copied into storage, adding new keys to storage or updating existing ones + MERGE_KV_DELETE, // update values specify keys that get deleted from storage + MERGE_KV_BORROW, // update values only update existing keys in storage, keys in update that do not exist in storage are discarded + }; + void MergeFrom( KeyValues *kvMerge, MergeKeyValuesOp_t eOp = MERGE_KV_ALL ); + + // Assign keyvalues from a string + // static KeyValues * FromString( char const *szName, char const *szStringVal, char const **ppEndOfParse = NULL ); private: KeyValues( KeyValues& ); // prevent copy constructor being used @@ -242,7 +294,7 @@ private: void RecursiveLoadFromBuffer( char const *resourceName, CUtlBuffer &buf ); - // For handling #include "filename" + // for handling #include "filename" void AppendIncludedKeys( CUtlVector< KeyValues * >& includedKeys ); void ParseIncludedKeys( char const *resourceName, const char *filetoinclude, IBaseFileSystem* pFileSystem, const char *pPathID, CUtlVector< KeyValues * >& includedKeys ); @@ -255,13 +307,29 @@ private: // If filesystem is null, it'll ignore f. void InternalWrite( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, const void *pData, int len ); - void Init(); + void Init(IKeyValuesSystem *customSystem = NULL, bool ownsCustomSystem = false); const char * ReadToken( CUtlBuffer &buf, bool &wasQuoted, bool &wasConditional ); void WriteIndents( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel ); void FreeAllocatedValue(); void AllocateValueBlock(int size); + bool ReadAsBinaryPooledFormat( CUtlBuffer &buf, IBaseFileSystem *pFileSystem, unsigned int poolKey ); + + bool EvaluateConditional( const char *pExpressionString ); + + inline IKeyValuesSystem *GetKeyValuesSystem() const { + if (m_pKeyValuesSystem) { + return m_pKeyValuesSystem; + } + + return KeyValuesSystem(); + } + + IKeyValuesSystem *KVSystem() const { + return GetKeyValuesSystem(); + } + int m_iKeyName; // keyname is a symbol defined in KeyValuesSystem // These are needed out of the union because the API returns string pointers @@ -280,17 +348,19 @@ private: char m_iDataType; char m_bHasEscapeSequences; // true, if while parsing this KeyValue, Escape Sequences are used (default false) char unused[2]; - + IKeyValuesSystem* m_pKeyValuesSystem; - bool m_bHasCustomKeyvalueSystem; + bool m_bOwnsCustomKeyValuesSystem; KeyValues *m_pPeer; // pointer to next key in list KeyValues *m_pSub; // pointer to Start of a new sub key list KeyValues *m_pChain;// Search here if it's not in our list - + void* m_pExpressionGetSymbolProc; }; +typedef KeyValues::AutoDelete KeyValuesAD; + enum KeyValuesUnpackDestinationTypes_t { UNPACK_TYPE_FLOAT, // dest is a float @@ -324,6 +394,12 @@ inline int KeyValues::GetInt( int keySymbol, int defaultValue ) return dat ? dat->GetInt( (const char *)NULL, defaultValue ) : defaultValue; } +inline uint64 KeyValues::GetUint64( int keySymbol, uint64 defaultValue ) +{ + KeyValues *dat = FindKey( keySymbol ); + return dat ? dat->GetUint64( (const char *)NULL, defaultValue ) : defaultValue; +} + inline float KeyValues::GetFloat( int keySymbol, float defaultValue ) { KeyValues *dat = FindKey( keySymbol ); @@ -361,6 +437,50 @@ inline bool KeyValues::IsEmpty( int keySymbol ) return dat ? dat->IsEmpty( ) : true; } -bool EvaluateConditional( const char *str ); + +// +// KeyValuesDumpContext and generic implementations +// + +// class IKeyValuesDumpContext +// { +// public: +// virtual bool KvBeginKey( KeyValues *pKey, int nIndentLevel ) = 0; +// virtual bool KvWriteValue( KeyValues *pValue, int nIndentLevel ) = 0; +// virtual bool KvEndKey( KeyValues *pKey, int nIndentLevel ) = 0; +// }; + +// class IKeyValuesDumpContextAsText : public IKeyValuesDumpContext +// { +// public: +// virtual bool KvBeginKey( KeyValues *pKey, int nIndentLevel ); +// virtual bool KvWriteValue( KeyValues *pValue, int nIndentLevel ); +// virtual bool KvEndKey( KeyValues *pKey, int nIndentLevel ); + +// public: +// virtual bool KvWriteIndent( int nIndentLevel ); +// virtual bool KvWriteText( char const *szText ) = 0; +// }; + +// class CKeyValuesDumpContextAsDevMsg : public IKeyValuesDumpContextAsText +// { +// public: +// // Overrides developer level to dump in DevMsg, zero to dump as Msg +// CKeyValuesDumpContextAsDevMsg( int nDeveloperLevel = 1 ) : m_nDeveloperLevel( nDeveloperLevel ) {} + +// public: +// virtual bool KvBeginKey( KeyValues *pKey, int nIndentLevel ); +// virtual bool KvWriteText( char const *szText ); + +// protected: +// int m_nDeveloperLevel; +// }; + +// inline bool KeyValuesDumpAsDevMsg( KeyValues *pKeyValues, int nIndentLevel = 0, int nDeveloperLevel = 1 ) +// { +// CKeyValuesDumpContextAsDevMsg ctx( nDeveloperLevel ); +// return pKeyValues->Dump( &ctx, nIndentLevel ); +// } + #endif // KEYVALUES_H diff --git a/tier1/KeyValues.cpp b/tier1/KeyValues.cpp index 4934e73b..4ae87435 100644 --- a/tier1/KeyValues.cpp +++ b/tier1/KeyValues.cpp @@ -1,4 +1,4 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -211,11 +211,11 @@ static CLeakTrack track; //----------------------------------------------------------------------------- // Purpose: Constructor //----------------------------------------------------------------------------- -KeyValues::KeyValues( const char *setName ) +KeyValues::KeyValues( const char *setName, IKeyValuesSystem *customSystem, bool ownsCustomSystem ) { TRACK_KV_ADD( this, setName ); - Init(); + Init( customSystem, ownsCustomSystem ); SetName ( setName ); } @@ -284,7 +284,7 @@ KeyValues::KeyValues( const char *setName, const char *firstKey, int firstValue, //----------------------------------------------------------------------------- // Purpose: Initialize member variables //----------------------------------------------------------------------------- -void KeyValues::Init() +void KeyValues::Init(IKeyValuesSystem *customSystem, bool ownsCustomSystem) { m_iKeyName = INVALID_KEY_SYMBOL; m_iDataType = TYPE_NONE; @@ -301,9 +301,9 @@ void KeyValues::Init() // for future proof memset( unused, 0, sizeof(unused) ); - - m_pKeyValuesSystem = NULL; - m_bHasCustomKeyvalueSystem = false; + + m_pKeyValuesSystem = customSystem; + m_bOwnsCustomKeyValuesSystem = ownsCustomSystem; m_pExpressionGetSymbolProc = NULL; } @@ -315,6 +315,11 @@ KeyValues::~KeyValues() TRACK_KV_REMOVE( this ); RemoveEverything(); + + if (m_pKeyValuesSystem && m_bOwnsCustomKeyValuesSystem) { + delete m_pKeyValuesSystem; + m_pKeyValuesSystem = NULL; + } } //----------------------------------------------------------------------------- @@ -369,7 +374,10 @@ void KeyValues::ChainKeyValue( KeyValues* pChain ) //----------------------------------------------------------------------------- const char *KeyValues::GetName( void ) const { - return KeyValuesSystem()->GetStringForSymbol(m_iKeyName); + if (!this) + return ""; + + return GetKeyValuesSystem()->GetStringForSymbol(m_iKeyName); } //----------------------------------------------------------------------------- @@ -377,6 +385,9 @@ const char *KeyValues::GetName( void ) const //----------------------------------------------------------------------------- int KeyValues::GetNameSymbol() const { + if (!this) + return INVALID_KEY_SYMBOL; + return m_iKeyName; } @@ -691,7 +702,7 @@ void KeyValues::RecursiveSaveToFile( IBaseFileSystem *filesystem, FileHandle_t f char buf[32]; // write "0x" + 16 char 0-padded hex encoded 64 bit value - Q_snprintf( buf, sizeof( buf ), "0x%016I64X", *( (uint64 *)dat->m_sValue ) ); + Q_snprintf( buf, sizeof( buf ), "0x%016llX", *( (uint64 *)dat->m_sValue ) ); INTERNALWRITE(buf, Q_strlen(buf)); INTERNALWRITE("\"\n", 2); @@ -748,6 +759,9 @@ KeyValues *KeyValues::FindKey(int keySymbol) const //----------------------------------------------------------------------------- KeyValues *KeyValues::FindKey(const char *keyName, bool bCreate) { + if (!this) + return NULL; + // return the current key if a NULL subkey is asked for if (!keyName || !keyName[0]) return this; @@ -767,7 +781,7 @@ KeyValues *KeyValues::FindKey(const char *keyName, bool bCreate) } // lookup the symbol for the search string - HKeySymbol iSearchStr = KeyValuesSystem()->GetSymbolForString( searchStr, bCreate ); + HKeySymbol iSearchStr = GetKeyValuesSystem()->GetSymbolForString( searchStr, bCreate ); if ( iSearchStr == INVALID_KEY_SYMBOL ) { // not found, couldn't possibly be in key value list @@ -799,7 +813,7 @@ KeyValues *KeyValues::FindKey(const char *keyName, bool bCreate) if (bCreate) { // we need to create a new key - dat = new KeyValues( searchStr ); + dat = new KeyValues( searchStr, m_pKeyValuesSystem ); // Assert(dat != NULL); // insert new key at end of list @@ -866,7 +880,7 @@ KeyValues *KeyValues::CreateNewKey() KeyValues* KeyValues::CreateKey( const char *keyName ) { // key wasn't found so just create a new one - KeyValues* dat = new KeyValues( keyName ); + KeyValues* dat = new KeyValues( keyName, m_pKeyValuesSystem ); dat->UsesEscapeSequences( m_bHasEscapeSequences != 0 ); // use same format as parent does @@ -943,6 +957,9 @@ void KeyValues::RemoveSubKey(KeyValues *subKey) //----------------------------------------------------------------------------- KeyValues *KeyValues::GetFirstSubKey() { + if (!this) + return NULL; + return m_pSub; } @@ -951,6 +968,9 @@ KeyValues *KeyValues::GetFirstSubKey() //----------------------------------------------------------------------------- KeyValues *KeyValues::GetNextKey() { + if (!this) + return NULL; + return m_pPeer; } @@ -965,6 +985,9 @@ void KeyValues::SetNextKey( KeyValues *pDat ) KeyValues* KeyValues::GetFirstTrueSubKey() { + if (!this) + return NULL; + KeyValues *pRet = m_pSub; while ( pRet && pRet->m_iDataType != TYPE_NONE ) pRet = pRet->m_pPeer; @@ -974,6 +997,9 @@ KeyValues* KeyValues::GetFirstTrueSubKey() KeyValues* KeyValues::GetNextTrueSubKey() { + if (!this) + return NULL; + KeyValues *pRet = m_pPeer; while ( pRet && pRet->m_iDataType != TYPE_NONE ) pRet = pRet->m_pPeer; @@ -983,6 +1009,9 @@ KeyValues* KeyValues::GetNextTrueSubKey() KeyValues* KeyValues::GetFirstValue() { + if (!this) + return NULL; + KeyValues *pRet = m_pSub; while ( pRet && pRet->m_iDataType == TYPE_NONE ) pRet = pRet->m_pPeer; @@ -992,6 +1021,9 @@ KeyValues* KeyValues::GetFirstValue() KeyValues* KeyValues::GetNextValue() { + if (!this) + return NULL; + KeyValues *pRet = m_pPeer; while ( pRet && pRet->m_iDataType == TYPE_NONE ) pRet = pRet->m_pPeer; @@ -1151,7 +1183,7 @@ const char *KeyValues::GetString( const char *keyName, const char *defaultValue SetString( keyName, buf ); break; case TYPE_UINT64: - Q_snprintf( buf, sizeof( buf ), "%I64i", *((uint64 *)(dat->m_sValue)) ); + Q_snprintf( buf, sizeof( buf ), "%lld", *((uint64 *)(dat->m_sValue)) ); SetString( keyName, buf ); break; @@ -1240,9 +1272,9 @@ const wchar_t *KeyValues::GetWString( const char *keyName, const wchar_t *defaul //----------------------------------------------------------------------------- // Purpose: Gets a color //----------------------------------------------------------------------------- -Color KeyValues::GetColor( const char *keyName ) +Color KeyValues::GetColor( const char *keyName, const Color &defaultColor ) { - Color color(0, 0, 0, 0); + Color color = defaultColor; KeyValues *dat = FindKey( keyName, false ); if ( dat ) { @@ -1424,7 +1456,7 @@ void KeyValues::SetFloat( const char *keyName, float value ) void KeyValues::SetName( const char * setName ) { - m_iKeyName = KeyValuesSystem()->GetSymbolForString( setName ); + m_iKeyName = GetKeyValuesSystem()->GetSymbolForString( setName ); } //----------------------------------------------------------------------------- @@ -1533,14 +1565,14 @@ void KeyValues::RecursiveCopyKeyValues( KeyValues& src ) // Handle the immediate child if( src.m_pSub ) { - m_pSub = new KeyValues( NULL ); + m_pSub = new KeyValues( NULL, m_pKeyValuesSystem ); m_pSub->RecursiveCopyKeyValues( *src.m_pSub ); } // Handle the immediate peer if( src.m_pPeer ) { - m_pPeer = new KeyValues( NULL ); + m_pPeer = new KeyValues( NULL, m_pKeyValuesSystem ); m_pPeer->RecursiveCopyKeyValues( *src.m_pPeer ); } } @@ -1756,7 +1788,7 @@ void KeyValues::ParseIncludedKeys( char const *resourceName, const char *filetoi // Append included file Q_strncat( fullpath, filetoinclude, sizeof( fullpath ), COPY_ALL_CHARACTERS ); - KeyValues *newKV = new KeyValues( fullpath ); + KeyValues *newKV = new KeyValues( fullpath, m_pKeyValuesSystem ); // CUtlSymbol save = s_CurrentFileSymbol; // did that had any use ??? @@ -1833,7 +1865,7 @@ void KeyValues::RecursiveMergeKeyValues( KeyValues *baseKV ) // Returns whether a keyvalues conditional evaluates to true or false // Needs more flexibility with conditionals, checking convars would be nice. //----------------------------------------------------------------------------- -bool EvaluateConditional( const char *str ) +bool KeyValues::EvaluateConditional( const char *str ) { bool bResult = false; bool bXboxUI = IsX360(); @@ -1907,7 +1939,7 @@ bool KeyValues::LoadFromBuffer( char const *resourceName, CUtlBuffer &buf, IBase if ( !pCurrentKey ) { - pCurrentKey = new KeyValues( s ); + pCurrentKey = new KeyValues( s, m_pKeyValuesSystem ); Assert( pCurrentKey ); pCurrentKey->UsesEscapeSequences( m_bHasEscapeSequences != 0 ); // same format has parent use @@ -2279,7 +2311,7 @@ bool KeyValues::ReadAsBinary( CUtlBuffer &buffer ) { case TYPE_NONE: { - dat->m_pSub = new KeyValues(""); + dat->m_pSub = new KeyValues("", m_pKeyValuesSystem); dat->m_pSub->ReadAsBinary( buffer ); break; } @@ -2344,7 +2376,7 @@ bool KeyValues::ReadAsBinary( CUtlBuffer &buffer ) break; // new peer follows - dat->m_pPeer = new KeyValues(""); + dat->m_pPeer = new KeyValues("", m_pKeyValuesSystem); dat = dat->m_pPeer; } @@ -2495,6 +2527,11 @@ bool KeyValues::ProcessResolutionKeys( const char *pResString ) return false; } + if ( !this ) + { + return false; + } + KeyValues *pSubKey = GetFirstSubKey(); if ( !pSubKey ) {