Port KeyValues class from Source SDK 2013.

This commit is contained in:
Nicholas Hastings 2015-07-12 15:44:04 -04:00
parent 02af635a89
commit 1c13e12266
8 changed files with 1334 additions and 280 deletions

Binary file not shown.

View File

@ -1,4 +1,4 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// //========= Copyright Valve Corporation, All rights reserved. ============//
// //
// Purpose: This header should never be used directly from leaf code!!! // Purpose: This header should never be used directly from leaf code!!!
// Instead, just add the file memoverride.cpp into your project and all this // Instead, just add the file memoverride.cpp into your project and all this
@ -14,25 +14,31 @@
#pragma once #pragma once
#endif #endif
#if !defined(NO_MALLOC_OVERRIDE) && defined(POSIX) // These memory debugging switches aren't relevant under Linux builds since memoverride.cpp
#define NO_MALLOC_OVERRIDE // isn't built into Linux projects
#endif #ifndef POSIX
// Define this in release to get memory tracking even in release builds // Define this in release to get memory tracking even in release builds
//#define USE_MEM_DEBUG 1 //#define USE_MEM_DEBUG 1
#endif
#if defined( _MEMTEST ) #if defined( _MEMTEST )
#ifdef _WIN32
#define USE_MEM_DEBUG 1 #define USE_MEM_DEBUG 1
#endif #endif
#endif
// Undefine this if using a compiler lacking threadsafe RTTI (like vc6) // Undefine this if using a compiler lacking threadsafe RTTI (like vc6)
#define MEM_DEBUG_CLASSNAME 1 #define MEM_DEBUG_CLASSNAME 1
#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
#include <stddef.h> #include <stddef.h>
#if defined( OSX )
#include <malloc/malloc.h>
#endif
#include "tier0/mem.h" #include "tier0/mem.h"
#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
struct _CrtMemState; struct _CrtMemState;
#define MEMALLOC_VERSION 1 #define MEMALLOC_VERSION 1
@ -107,7 +113,17 @@ public:
#endif #endif
// Returns 0 if no failure, otherwise the size_t of the last requested chunk // Returns 0 if no failure, otherwise the size_t of the last requested chunk
// "I'm sure this is completely thread safe!" Brian Deen 7/19/2012.
virtual size_t MemoryAllocFailed() = 0; virtual size_t MemoryAllocFailed() = 0;
// handles storing allocation info for coroutines
virtual uint32 GetDebugInfoSize() = 0;
virtual void SaveDebugInfo( void *pvDebugInfo ) = 0;
virtual void RestoreDebugInfo( const void *pvDebugInfo ) = 0;
virtual void InitDebugInfo( void *pvDebugInfo, const char *pchRootFileName, int nLine ) = 0;
// Replacement for ::GlobalMemoryStatus which accounts for unused memory in our system
virtual void GlobalMemoryStatus( size_t *pUsedMemory, size_t *pFreeMemory ) = 0;
}; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -117,11 +133,52 @@ MEM_INTERFACE IMemAlloc *g_pMemAlloc;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#ifdef MEMALLOC_REGIONS
#ifndef MEMALLOC_REGION
#define MEMALLOC_REGION 0
#endif
inline void *MemAlloc_Alloc( size_t nSize )
{
return g_pMemAlloc->RegionAlloc( MEMALLOC_REGION, nSize );
}
inline void *MemAlloc_Alloc( size_t nSize, const char *pFileName, int nLine )
{
return g_pMemAlloc->RegionAlloc( MEMALLOC_REGION, nSize, pFileName, nLine );
}
#else
#undef MEMALLOC_REGION
inline void *MemAlloc_Alloc( size_t nSize )
{
return g_pMemAlloc->Alloc( nSize );
}
inline void *MemAlloc_Alloc( size_t nSize, const char *pFileName, int nLine )
{
return g_pMemAlloc->Alloc( nSize, pFileName, nLine );
}
#endif
inline void MemAlloc_Free( void *ptr )
{
g_pMemAlloc->Free( ptr );
}
inline void MemAlloc_Free( void *ptr, const char *pFileName, int nLine )
{
g_pMemAlloc->Free( ptr, pFileName, nLine );
}
//-----------------------------------------------------------------------------
inline bool ValueIsPowerOfTwo( size_t value ) // don't clash with mathlib definition
{
return (value & ( value - 1 )) == 0;
}
inline void *MemAlloc_AllocAligned( size_t size, size_t align ) inline void *MemAlloc_AllocAligned( size_t size, size_t align )
{ {
unsigned char *pAlloc, *pResult; unsigned char *pAlloc, *pResult;
if (!IsPowerOfTwo(uint(align))) if (!IsPowerOfTwo(align))
return NULL; return NULL;
align = (align > sizeof(void *) ? align : sizeof(void *)) - 1; align = (align > sizeof(void *) ? align : sizeof(void *)) - 1;
@ -139,7 +196,7 @@ inline void *MemAlloc_AllocAligned( size_t size, size_t align, const char *pszFi
{ {
unsigned char *pAlloc, *pResult; unsigned char *pAlloc, *pResult;
if (!IsPowerOfTwo(uint(align))) if (!IsPowerOfTwo(align))
return NULL; return NULL;
align = (align > sizeof(void *) ? align : sizeof(void *)) - 1; align = (align > sizeof(void *) ? align : sizeof(void *)) - 1;
@ -153,9 +210,45 @@ inline void *MemAlloc_AllocAligned( size_t size, size_t align, const char *pszFi
return (void *)pResult; return (void *)pResult;
} }
inline void *MemAlloc_AllocAlignedUnattributed( size_t size, size_t align )
{
unsigned char *pAlloc, *pResult;
if (!ValueIsPowerOfTwo(align))
return NULL;
align = (align > sizeof(void *) ? align : sizeof(void *)) - 1;
if ( (pAlloc = (unsigned char*)MemAlloc_Alloc( sizeof(void *) + align + size ) ) == (unsigned char*)NULL)
return NULL;
pResult = (unsigned char*)( (size_t)(pAlloc + sizeof(void *) + align ) & ~align );
((unsigned char**)(pResult))[-1] = pAlloc;
return (void *)pResult;
}
inline void *MemAlloc_AllocAlignedFileLine( size_t size, size_t align, const char *pszFile, int nLine )
{
unsigned char *pAlloc, *pResult;
if (!ValueIsPowerOfTwo(align))
return NULL;
align = (align > sizeof(void *) ? align : sizeof(void *)) - 1;
if ( (pAlloc = (unsigned char*)MemAlloc_Alloc( sizeof(void *) + align + size, pszFile, nLine ) ) == (unsigned char*)NULL)
return NULL;
pResult = (unsigned char*)( (size_t)(pAlloc + sizeof(void *) + align ) & ~align );
((unsigned char**)(pResult))[-1] = pAlloc;
return (void *)pResult;
}
inline void *MemAlloc_ReallocAligned( void *ptr, size_t size, size_t align ) inline void *MemAlloc_ReallocAligned( void *ptr, size_t size, size_t align )
{ {
if ( !IsPowerOfTwo( uint(align) ) ) if ( !IsPowerOfTwo( align ) )
return NULL; return NULL;
// Don't change alignment between allocation + reallocation. // Don't change alignment between allocation + reallocation.
@ -201,6 +294,23 @@ inline void MemAlloc_FreeAligned( void *pMemBlock )
g_pMemAlloc->Free( pAlloc ); g_pMemAlloc->Free( pAlloc );
} }
inline void MemAlloc_FreeAligned( void *pMemBlock, const char *pFileName, int nLine )
{
void *pAlloc;
if ( pMemBlock == NULL )
return;
pAlloc = pMemBlock;
// pAlloc points to the pointer to starting of the memory block
pAlloc = (void *)(((size_t)pAlloc & ~( sizeof(void *) - 1 ) ) - sizeof(void *));
// pAlloc is the pointer to the start of memory block
pAlloc = *( (void **)pAlloc );
g_pMemAlloc->Free( pAlloc, pFileName, nLine );
}
inline size_t MemAlloc_GetSizeAligned( void *pMemBlock ) inline size_t MemAlloc_GetSizeAligned( void *pMemBlock )
{ {
void *pAlloc; void *pAlloc;
@ -234,6 +344,20 @@ inline size_t MemAlloc_GetSizeAligned( void *pMemBlock )
#define MemAlloc_RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0) #define MemAlloc_RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0)
#endif #endif
#define MemAlloc_DumpStats() g_pMemAlloc->DumpStats()
#define MemAlloc_CompactHeap() g_pMemAlloc->CompactHeap()
#define MemAlloc_OutOfMemory() g_pMemAlloc->OutOfMemory()
#define MemAlloc_CompactIncremental() g_pMemAlloc->CompactIncremental()
#define MemAlloc_DumpStatsFileBase( _filename ) g_pMemAlloc->DumpStatsFileBase( _filename )
#define MemAlloc_CrtCheckMemory() g_pMemAlloc->CrtCheckMemory()
#define MemAlloc_GlobalMemoryStatus( _usedMemory, _freeMemory ) g_pMemAlloc->GlobalMemoryStatus( _usedMemory, _freeMemory )
#define MemAlloc_MemoryAllocFailed() g_pMemAlloc->MemoryAllocFailed()
#define MemAlloc_GetDebugInfoSize() g_pMemAlloc->GetDebugInfoSize()
#define MemAlloc_SaveDebugInfo( pvDebugInfo ) g_pMemAlloc->SaveDebugInfo( pvDebugInfo )
#define MemAlloc_RestoreDebugInfo( pvDebugInfo ) g_pMemAlloc->RestoreDebugInfo( pvDebugInfo )
#define MemAlloc_InitDebugInfo( pvDebugInfo, pchRootFileName, nLine ) g_pMemAlloc->InitDebugInfo( pvDebugInfo, pchRootFileName, nLine )
#define MemAlloc_GetSize( x ) g_pMemAlloc->GetSize( x );
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
class CMemAllocAttributeAlloction class CMemAllocAttributeAlloction
@ -339,6 +463,51 @@ struct MemAllocFileLine_t
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#elif defined( POSIX )
#if defined( OSX )
// Mac always aligns allocs, don't need to call posix_memalign which doesn't exist in 10.5.8 which TF2 still needs to run on
//inline void *memalign(size_t alignment, size_t size) {void *pTmp=NULL; posix_memalign(&pTmp, alignment, size); return pTmp;}
inline void *memalign(size_t alignment, size_t size) {void *pTmp=NULL; pTmp = malloc(size); return pTmp;}
#endif
inline void *_aligned_malloc( size_t nSize, size_t align ) { return memalign( align, nSize ); }
inline void _aligned_free( void *ptr ) { free( ptr ); }
inline void *MemAlloc_Alloc( size_t nSize, const char *pFileName = NULL, int nLine = 0 ) { return malloc( nSize ); }
inline void MemAlloc_Free( void *ptr, const char *pFileName = NULL, int nLine = 0 ) { free( ptr ); }
inline void *MemAlloc_AllocAligned( size_t size, size_t align, const char *pszFile = NULL, int nLine = 0 ) { return memalign( align, size ); }
inline void *MemAlloc_AllocAlignedFileLine( size_t size, size_t align, const char *pszFile = NULL, int nLine = 0 ) { return memalign( align, size ); }
inline void MemAlloc_FreeAligned( void *pMemBlock, const char *pszFile = NULL, int nLine = 0 ) { free( pMemBlock ); }
#if defined( OSX )
inline size_t _msize( void *ptr ) { return malloc_size( ptr ); }
#else
inline size_t _msize( void *ptr ) { return malloc_usable_size( ptr ); }
#endif
inline void *MemAlloc_ReallocAligned( void *ptr, size_t size, size_t align )
{
void *ptr_new_aligned = memalign( align, size );
if( ptr_new_aligned )
{
size_t old_size = _msize( ptr );
size_t copy_size = ( size < old_size ) ? size : old_size;
memcpy( ptr_new_aligned, ptr, copy_size );
free( ptr );
}
return ptr_new_aligned;
}
#else
#define MemAlloc_GetDebugInfoSize() g_pMemAlloc->GetDebugInfoSize()
#define MemAlloc_SaveDebugInfo( pvDebugInfo ) g_pMemAlloc->SaveDebugInfo( pvDebugInfo )
#define MemAlloc_RestoreDebugInfo( pvDebugInfo ) g_pMemAlloc->RestoreDebugInfo( pvDebugInfo )
#define MemAlloc_InitDebugInfo( pvDebugInfo, pchRootFileName, nLine ) g_pMemAlloc->InitDebugInfo( pvDebugInfo, pchRootFileName, nLine )
#endif // !STEAM && !NO_MALLOC_OVERRIDE #endif // !STEAM && !NO_MALLOC_OVERRIDE
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -347,12 +516,139 @@ struct MemAllocFileLine_t
#define MEM_ALLOC_CREDIT_(tag) ((void)0) #define MEM_ALLOC_CREDIT_(tag) ((void)0)
#define MEM_ALLOC_CREDIT() MEM_ALLOC_CREDIT_(__FILE__) #define MEM_ALLOC_CREDIT() MEM_ALLOC_CREDIT_(__FILE__)
#define MEM_ALLOC_CREDIT_FUNCTION()
#define MEM_ALLOC_CREDIT_CLASS() #define MEM_ALLOC_CREDIT_CLASS()
#define MEM_ALLOC_CLASSNAME(type) NULL #define MEM_ALLOC_CLASSNAME(type) NULL
#define MEM_ALLOC_CREDIT_FUNCTION()
#define MemAlloc_PushAllocDbgInfo( pszFile, line )
#define MemAlloc_PopAllocDbgInfo()
#define MemAlloc_RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0)
#define MemAlloc_RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0)
#define MemAlloc_DumpStats() ((void)0)
#define MemAlloc_CompactHeap() ((void)0)
#define MemAlloc_OutOfMemory() ((void)0)
#define MemAlloc_CompactIncremental() ((void)0)
#define MemAlloc_DumpStatsFileBase( _filename ) ((void)0)
inline bool MemAlloc_CrtCheckMemory() { return true; }
inline void MemAlloc_GlobalMemoryStatus( size_t *pusedMemory, size_t *pfreeMemory )
{
*pusedMemory = 0;
*pfreeMemory = 0;
}
#define MemAlloc_MemoryAllocFailed() 0
#define MemAlloc_GetDebugInfoSize() 0
#define MemAlloc_SaveDebugInfo( pvDebugInfo ) ((void)0)
#define MemAlloc_RestoreDebugInfo( pvDebugInfo ) ((void)0)
#define MemAlloc_InitDebugInfo( pvDebugInfo, pchRootFileName, nLine ) ((void)0)
#define MEMALLOC_DEFINE_EXTERNAL_TRACKING( tag )
#define MemAlloc_RegisterExternalAllocation( tag, p, size ) ((void)0)
#define MemAlloc_RegisterExternalDeallocation( tag, p, size ) ((void)0)
#endif // !STEAM && NO_MALLOC_OVERRIDE #endif // !STEAM && NO_MALLOC_OVERRIDE
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// linux memory tracking via hooks.
#if defined( POSIX ) && !defined( NO_HOOK_MALLOC )
PLATFORM_INTERFACE void MemoryLogMessage( char const *s ); // throw a message into the memory log
PLATFORM_INTERFACE void EnableMemoryLogging( bool bOnOff );
PLATFORM_INTERFACE void DumpMemoryLog( int nThresh );
PLATFORM_INTERFACE void DumpMemorySummary( void );
PLATFORM_INTERFACE void SetMemoryMark( void );
PLATFORM_INTERFACE void DumpChangedMemory( int nThresh );
#else
FORCEINLINE void MemoryLogMessage( char const *s )
{
}
FORCEINLINE void EnableMemoryLogging( bool bOnOff )
{
}
FORCEINLINE void DumpMemoryLog( int nThresh )
{
}
FORCEINLINE void DumpMemorySummary( void )
{
}
FORCEINLINE void SetMemoryMark( void )
{
}
FORCEINLINE void DumpChangedMemory( int nThresh )
{
}
#endif
#ifdef POSIX
// ApproximateProcessMemoryUsage returns the approximate memory footprint of this process.
PLATFORM_INTERFACE size_t ApproximateProcessMemoryUsage( void );
#else
FORCEINLINE size_t ApproximateProcessMemoryUsage( void )
{
return 0;
}
#endif
struct aligned_tmp_t
{
// empty base class
};
/*
This class used to be required if you wanted an object to be allocated with a specific
alignment. ALIGN16 and ALIGN16_POST are not actually sufficient for this because they
guarantee that the globals, statics, locals, and function parameters are appropriately
aligned they do not affect memory allocation alignment.
However this class is usually not needed because as of 2012 our policy is that our
allocator should take care of this automatically. Any object whose size is a multiple
of 16 will be 16-byte aligned. Existing uses of this class were not changed because
the cost/benefit did not justify it.
*/
// template here to allow adding alignment at levels of hierarchy that aren't the base
template< int bytesAlignment = 16, class T = aligned_tmp_t >
class CAlignedNewDelete : public T
{
public:
/*
Note that this class does not overload operator new[] and delete[] which means that
classes that depend on this for alignment may end up misaligned if an array is
allocated. This problem is now mostly theoretical because this class is mostly
obsolete.
*/
void *operator new( size_t nSize )
{
return MemAlloc_AllocAligned( nSize, bytesAlignment );
}
void* operator new( size_t nSize, int nBlockUse, const char *pFileName, int nLine )
{
return MemAlloc_AllocAlignedFileLine( nSize, bytesAlignment, pFileName, nLine );
}
void operator delete(void *pData)
{
if ( pData )
{
MemAlloc_FreeAligned( pData );
}
}
void operator delete( void* pData, int nBlockUse, const char *pFileName, int nLine )
{
if ( pData )
{
MemAlloc_FreeAligned( pData, pFileName, nLine );
}
}
};
#endif /* TIER0_MEMALLOC_H */ #endif /* TIER0_MEMALLOC_H */

View File

@ -75,27 +75,58 @@
#ifdef _WIN32 #ifdef _WIN32
#define IsLinux() false #define IsLinux() false
#define IsOSX() false
#define IsPosix() false
#ifndef PLATFORM_WINDOWS
#define PLATFORM_WINDOWS 1 // Windows PC or Xbox 360
#endif
#ifndef _X360 #ifndef _X360
#define IsWindows() true
#define IsPC() true #define IsPC() true
#define IsConsole() false #define IsConsole() false
#define IsX360() false #define IsX360() false
#define IsPS3() false #define IsPS3() false
#define IS_WINDOWS_PC #define IS_WINDOWS_PC
#define PLATFORM_WINDOWS_PC 1 // Windows PC
#ifdef _WIN64
#define IsPlatformWindowsPC64() true
#define IsPlatformWindowsPC32() false
#define PLATFORM_WINDOWS_PC64 1
#else #else
#define IsPlatformWindowsPC64() false
#define IsPlatformWindowsPC32() true
#define PLATFORM_WINDOWS_PC32 1
#endif
#else
#define PLATFORM_X360 1
#ifndef _CONSOLE #ifndef _CONSOLE
#define _CONSOLE #define _CONSOLE
#endif #endif
#define IsWindows() false
#define IsPC() false #define IsPC() false
#define IsConsole() true #define IsConsole() true
#define IsX360() true #define IsX360() true
#define IsPS3() false #define IsPS3() false
#endif #endif
#elif defined(_LINUX) || defined(__APPLE__) #elif defined(POSIX)
#define IsPC() true #define IsPC() true
#define IsWindows() false
#define IsConsole() false #define IsConsole() false
#define IsX360() false #define IsX360() false
#define IsPS3() false #define IsPS3() false
#if defined( LINUX )
#define IsLinux() true #define IsLinux() true
#else
#define IsLinux() false
#endif
#if defined( OSX )
#define IsOSX() true
#else
#define IsOSX() false
#endif
#define IsPosix() true
#else #else
#error #error
#endif #endif

View File

@ -1,4 +1,4 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// //========= Copyright Valve Corporation, All rights reserved. ============//
// //
// Purpose: // Purpose:
// //
@ -25,10 +25,20 @@
#include "utlvector.h" #include "utlvector.h"
#include "Color.h" #include "Color.h"
#define FOR_EACH_SUBKEY( kvRoot, kvSubKey ) \
for ( KeyValues * kvSubKey = kvRoot->GetFirstSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextKey() )
#define FOR_EACH_TRUE_SUBKEY( kvRoot, kvSubKey ) \
for ( KeyValues * kvSubKey = kvRoot->GetFirstTrueSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextTrueSubKey() )
#define FOR_EACH_VALUE( kvRoot, kvValue ) \
for ( KeyValues * kvValue = kvRoot->GetFirstValue(); kvValue != NULL; kvValue = kvValue->GetNextValue() )
class IBaseFileSystem; class IBaseFileSystem;
class CUtlBuffer; class CUtlBuffer;
class Color; class Color;
typedef void * FileHandle_t; typedef void * FileHandle_t;
class CKeyValuesGrowableStringTable;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Purpose: Simple recursive data access class // Purpose: Simple recursive data access class
@ -39,7 +49,7 @@ typedef void * FileHandle_t;
// About KeyValues Text File Format: // About KeyValues Text File Format:
// It has 3 control characters '{', '}' and '"'. Names and values may be quoted or // It has 3 control characters '{', '}' and '"'. Names and values may be quoted or
// not. The quote '"' charater must not be used within name or values, only for // not. The quote '"' character must not be used within name or values, only for
// quoting whole tokens. You may use escape sequences wile parsing and add within a // quoting whole tokens. You may use escape sequences wile parsing and add within a
// quoted token a \" to add quotes within your name or token. When using Escape // quoted token a \" to add quotes within your name or token. When using Escape
// Sequence the parser must now that by setting KeyValues::UsesEscapeSequences( true ), // Sequence the parser must now that by setting KeyValues::UsesEscapeSequences( true ),
@ -49,11 +59,25 @@ typedef void * FileHandle_t;
// with a closing bracket '}'. Subkeys use the same definitions recursively. // with a closing bracket '}'. Subkeys use the same definitions recursively.
// Whitespaces are space, return, newline and tabulator. Allowed Escape sequences // Whitespaces are space, return, newline and tabulator. Allowed Escape sequences
// are \n, \t, \\, \n and \". The number character '#' is used for macro purposes // are \n, \t, \\, \n and \". The number character '#' is used for macro purposes
// (eg #include), don't use it as first charater in key names. // (eg #include), don't use it as first character in key names.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
class KeyValues class KeyValues
{ {
public: public:
// By default, the KeyValues class uses a string table for the key names that is
// limited to 4MB. The game will exit in error if this space is exhausted. In
// general this is preferable for game code for performance and memory fragmentation
// reasons.
//
// If this is not acceptable, you can use this call to switch to a table that can grow
// arbitrarily. This call must be made before any KeyValues objects are allocated or it
// will result in undefined behavior. If you use the growable string table, you cannot
// share KeyValues pointers directly with any other module. You can serialize them across
// module boundaries. These limitations are acceptable in the Steam backend code
// this option was written for, but may not be in other situations. Make sure to
// understand the implications before using this.
static void SetUseGrowableStringTable( bool bUseGrowableTable );
KeyValues( const char *setName ); KeyValues( const char *setName );
// //
@ -68,8 +92,11 @@ public:
{ {
public: public:
explicit inline AutoDelete( KeyValues *pKeyValues ) : m_pKeyValues( pKeyValues ) {} 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 ~AutoDelete( void ) { if( m_pKeyValues ) m_pKeyValues->deleteThis(); }
inline void Assign( KeyValues *pKeyValues ) { m_pKeyValues = pKeyValues; } inline void Assign( KeyValues *pKeyValues ) { m_pKeyValues = pKeyValues; }
KeyValues *operator->() { return m_pKeyValues; }
operator KeyValues *() { return m_pKeyValues; }
private: private:
AutoDelete( AutoDelete const &x ); // forbid AutoDelete( AutoDelete const &x ); // forbid
AutoDelete & operator= ( AutoDelete const &x ); // forbid AutoDelete & operator= ( AutoDelete const &x ); // forbid
@ -88,12 +115,13 @@ public:
void SetName( const char *setName); void SetName( const char *setName);
// gets the name as a unique int // gets the name as a unique int
int GetNameSymbol() const; int GetNameSymbol() const { return m_iKeyName; }
// File access. Set UsesEscapeSequences true, if resource file/buffer uses Escape Sequences (eg \n, \t) // File access. Set UsesEscapeSequences true, if resource file/buffer uses Escape Sequences (eg \n, \t)
void UsesEscapeSequences(bool state); // default false void UsesEscapeSequences(bool state); // default false
void UsesConditionals(bool state); // default true
bool LoadFromFile( IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL ); bool LoadFromFile( IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL );
bool SaveToFile( IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL); bool SaveToFile( IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL, bool sortKeys = false, bool bAllowEmptyString = false );
// Read from a buffer... Note that the buffer must be null terminated // Read from a buffer... Note that the buffer must be null terminated
bool LoadFromBuffer( char const *resourceName, const char *pBuffer, IBaseFileSystem* pFileSystem = NULL, const char *pPathID = NULL ); bool LoadFromBuffer( char const *resourceName, const char *pBuffer, IBaseFileSystem* pFileSystem = NULL, const char *pPathID = NULL );
@ -114,9 +142,10 @@ public:
// NOTE: GetFirstSubKey/GetNextKey will iterate keys AND values. Use the functions // NOTE: GetFirstSubKey/GetNextKey will iterate keys AND values. Use the functions
// below if you want to iterate over just the keys or just the values. // below if you want to iterate over just the keys or just the values.
// //
KeyValues *GetFirstSubKey(); // returns the first subkey in the list KeyValues *GetFirstSubKey() { return m_pSub; } // returns the first subkey in the list
KeyValues *GetNextKey(); // returns the next subkey KeyValues *GetNextKey() { return m_pPeer; } // returns the next subkey
void SetNextKey( KeyValues * pDat); void SetNextKey( KeyValues * pDat);
KeyValues *FindLastSubKey(); // returns the LAST subkey in the list. This requires a linked list iteration to find the key. Returns NULL if we don't have any children
// //
// These functions can be used to treat it like a true key/values tree instead of // These functions can be used to treat it like a true key/values tree instead of
@ -145,6 +174,7 @@ public:
const char *GetString( const char *keyName = NULL, const char *defaultValue = "" ); const char *GetString( const char *keyName = NULL, const char *defaultValue = "" );
const wchar_t *GetWString( const char *keyName = NULL, const wchar_t *defaultValue = L"" ); const wchar_t *GetWString( const char *keyName = NULL, const wchar_t *defaultValue = L"" );
void *GetPtr( const char *keyName = NULL, void *defaultValue = (void*)0 ); void *GetPtr( const char *keyName = NULL, void *defaultValue = (void*)0 );
bool GetBool( const char *keyName = NULL, bool defaultValue = false, bool* optGotDefault = NULL );
Color GetColor( const char *keyName = NULL /* default value is all black */); Color GetColor( const char *keyName = NULL /* default value is all black */);
bool IsEmpty(const char *keyName = NULL); bool IsEmpty(const char *keyName = NULL);
@ -165,6 +195,7 @@ public:
void SetFloat( const char *keyName, float value ); void SetFloat( const char *keyName, float value );
void SetPtr( const char *keyName, void *value ); void SetPtr( const char *keyName, void *value );
void SetColor( const char *keyName, Color value); void SetColor( const char *keyName, Color value);
void SetBool( const char *keyName, bool value ) { SetInt( keyName, value ? 1 : 0 ); }
// Memory allocation (optimized) // Memory allocation (optimized)
void *operator new( size_t iAllocSize ); void *operator new( size_t iAllocSize );
@ -178,10 +209,10 @@ public:
// in the one we're chained to. // in the one we're chained to.
void ChainKeyValue( KeyValues* pChain ); void ChainKeyValue( KeyValues* pChain );
void RecursiveSaveToFile( CUtlBuffer& buf, int indentLevel ); void RecursiveSaveToFile( CUtlBuffer& buf, int indentLevel, bool sortKeys = false, bool bAllowEmptyString = false );
bool WriteAsBinary( CUtlBuffer &buffer ); bool WriteAsBinary( CUtlBuffer &buffer );
bool ReadAsBinary( CUtlBuffer &buffer ); bool ReadAsBinary( CUtlBuffer &buffer, int nStackDepth = 0 );
// Allocate & create a new copy of the keys // Allocate & create a new copy of the keys
KeyValues *MakeCopy( void ) const; KeyValues *MakeCopy( void ) const;
@ -213,11 +244,17 @@ public:
void SetStringValue( char const *strValue ); void SetStringValue( char const *strValue );
// unpack a key values list into a structure // unpack a key values list into a structure
void UnpackIntoStructure( struct KeyValuesUnpackStructure const *pUnpackTable, void *pDest ); void UnpackIntoStructure( struct KeyValuesUnpackStructure const *pUnpackTable, void *pDest, size_t DestSizeInBytes );
// Process conditional keys for widescreen support. // Process conditional keys for widescreen support.
bool ProcessResolutionKeys( const char *pResString ); bool ProcessResolutionKeys( const char *pResString );
// Dump keyvalues recursively into a dump context
bool Dump( class IKeyValuesDumpContext *pDump, int nIndentLevel = 0 );
// Merge in another KeyValues, keeping "our" settings
void RecursiveMergeKeyValues( KeyValues *baseKV );
private: private:
KeyValues( KeyValues& ); // prevent copy constructor being used KeyValues( KeyValues& ); // prevent copy constructor being used
@ -226,6 +263,13 @@ private:
KeyValues* CreateKey( const char *keyName ); KeyValues* CreateKey( const char *keyName );
/// Create a child key, given that we know which child is currently the last child.
/// This avoids the O(N^2) behaviour when adding children in sequence to KV,
/// when CreateKey() wil have to re-locate the end of the list each time. This happens,
/// for example, every time we load any KV file whatsoever.
KeyValues* CreateKeyUsingKnownLastChild( const char *keyName, KeyValues *pLastChild );
void AddSubkeyUsingKnownLastChild( KeyValues *pSubKey, KeyValues *pLastChild );
void RecursiveCopyKeyValues( KeyValues& src ); void RecursiveCopyKeyValues( KeyValues& src );
void RemoveEverything(); void RemoveEverything();
// void RecursiveSaveToFile( IBaseFileSystem *filesystem, CUtlBuffer &buffer, int indentLevel ); // void RecursiveSaveToFile( IBaseFileSystem *filesystem, CUtlBuffer &buffer, int indentLevel );
@ -233,7 +277,8 @@ private:
// NOTE: If both filesystem and pBuf are non-null, it'll save to both of them. // NOTE: If both filesystem and pBuf are non-null, it'll save to both of them.
// If filesystem is null, it'll ignore f. // If filesystem is null, it'll ignore f.
void RecursiveSaveToFile( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel ); void RecursiveSaveToFile( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel, bool sortKeys, bool bAllowEmptyString );
void SaveKeyToFile( KeyValues *dat, IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel, bool sortKeys, bool bAllowEmptyString );
void WriteConvertedString( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, const char *pszString ); void WriteConvertedString( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, const char *pszString );
void RecursiveLoadFromBuffer( char const *resourceName, CUtlBuffer &buf ); void RecursiveLoadFromBuffer( char const *resourceName, CUtlBuffer &buf );
@ -245,7 +290,6 @@ private:
// For handling #base "filename" // For handling #base "filename"
void MergeBaseKeys( CUtlVector< KeyValues * >& baseKeys ); void MergeBaseKeys( CUtlVector< KeyValues * >& baseKeys );
void RecursiveMergeKeyValues( KeyValues *baseKV );
// NOTE: If both filesystem and pBuf are non-null, it'll save to both of them. // NOTE: If both filesystem and pBuf are non-null, it'll save to both of them.
// If filesystem is null, it'll ignore f. // If filesystem is null, it'll ignore f.
@ -275,13 +319,36 @@ private:
char m_iDataType; char m_iDataType;
char m_bHasEscapeSequences; // true, if while parsing this KeyValue, Escape Sequences are used (default false) char m_bHasEscapeSequences; // true, if while parsing this KeyValue, Escape Sequences are used (default false)
char unused[2]; char m_bEvaluateConditionals; // true, if while parsing this KeyValue, conditionals blocks are evaluated (default true)
char unused[1];
KeyValues *m_pPeer; // pointer to next key in list KeyValues *m_pPeer; // pointer to next key in list
KeyValues *m_pSub; // pointer to Start of a new sub key 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 KeyValues *m_pChain;// Search here if it's not in our list
private:
// Statics to implement the optional growable string table
// Function pointers that will determine which mode we are in
static int (*s_pfGetSymbolForString)( const char *name, bool bCreate );
static const char *(*s_pfGetStringForSymbol)( int symbol );
static CKeyValuesGrowableStringTable *s_pGrowableStringTable;
public:
// Functions that invoke the default behavior
static int GetSymbolForStringClassic( const char *name, bool bCreate = true );
static const char *GetStringForSymbolClassic( int symbol );
// Functions that use the growable string table
static int GetSymbolForStringGrowable( const char *name, bool bCreate = true );
static const char *GetStringForSymbolGrowable( int symbol );
// Functions to get external access to whichever of the above functions we're going to call.
static int CallGetSymbolForString( const char *name, bool bCreate = true ) { return s_pfGetSymbolForString( name, bCreate ); }
static const char *CallGetStringForSymbol( int symbol ) { return s_pfGetStringForSymbol( symbol ); }
}; };
typedef KeyValues::AutoDelete KeyValuesAD;
enum KeyValuesUnpackDestinationTypes_t enum KeyValuesUnpackDestinationTypes_t
{ {
UNPACK_TYPE_FLOAT, // dest is a float UNPACK_TYPE_FLOAT, // dest is a float
@ -354,4 +421,57 @@ inline bool KeyValues::IsEmpty( int keySymbol )
bool EvaluateConditional( const char *str ); bool EvaluateConditional( const char *str );
class CUtlSortVectorKeyValuesByName
{
public:
bool Less( const KeyValues* lhs, const KeyValues* rhs, void * )
{
return Q_stricmp( lhs->GetName(), rhs->GetName() ) < 0;
}
};
//
// 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 #endif // KEYVALUES_H

View File

@ -110,6 +110,8 @@ int V_strcasecmp (const char *s1, const char *s2);
int V_strncasecmp (const char *s1, const char *s2, int n); int V_strncasecmp (const char *s1, const char *s2, int n);
int V_strnicmp (const char *s1, const char *s2, int n); int V_strnicmp (const char *s1, const char *s2, int n);
int V_atoi (const char *str); int V_atoi (const char *str);
int64 V_atoi64(const char *str);
uint64 V_atoui64(const char *str);
float V_atof (const char *str); float V_atof (const char *str);
char* V_stristr( char* pStr, const char* pSearch ); char* V_stristr( char* pStr, const char* pSearch );
const char* V_stristr( const char* pStr, const char* pSearch ); const char* V_stristr( const char* pStr, const char* pSearch );
@ -409,6 +411,8 @@ bool V_GenerateUniqueName( char *name, int memsize, const char *prefix, const Na
#define Q_strncasecmp V_strncasecmp #define Q_strncasecmp V_strncasecmp
#define Q_strnicmp V_strnicmp #define Q_strnicmp V_strnicmp
#define Q_atoi V_atoi #define Q_atoi V_atoi
#define Q_atoi64 V_atoi64
#define Q_atoui64 V_atoui64
#define Q_atof V_atof #define Q_atof V_atof
#define Q_stristr V_stristr #define Q_stristr V_stristr
#define Q_strnistr V_strnistr #define Q_strnistr V_strnistr

View File

@ -176,6 +176,7 @@ public:
short GetShort( ); short GetShort( );
unsigned short GetUnsignedShort( ); unsigned short GetUnsignedShort( );
int GetInt( ); int GetInt( );
int64 GetInt64( );
int GetIntHex( ); int GetIntHex( );
unsigned int GetUnsignedInt( ); unsigned int GetUnsignedInt( );
float GetFloat( ); float GetFloat( );
@ -249,6 +250,7 @@ public:
void PutShort( short s ); void PutShort( short s );
void PutUnsignedShort( unsigned short us ); void PutUnsignedShort( unsigned short us );
void PutInt( int i ); void PutInt( int i );
void PutInt64( int64 i );
void PutUnsignedInt( unsigned int u ); void PutUnsignedInt( unsigned int u );
void PutFloat( float f ); void PutFloat( float f );
void PutDouble( double d ); void PutDouble( double d );
@ -700,6 +702,13 @@ inline int CUtlBuffer::GetInt( )
return i; return i;
} }
inline int64 CUtlBuffer::GetInt64( )
{
int64 i;
GetType( i, "%lld" );
return i;
}
inline int CUtlBuffer::GetIntHex( ) inline int CUtlBuffer::GetIntHex( )
{ {
int i; int i;
@ -920,6 +929,11 @@ inline void CUtlBuffer::PutInt( int i )
PutType( i, "%d" ); PutType( i, "%d" );
} }
inline void CUtlBuffer::PutInt64( int64 i )
{
PutType( i, "%llu" );
}
inline void CUtlBuffer::PutUnsignedInt( unsigned int u ) inline void CUtlBuffer::PutUnsignedInt( unsigned int u )
{ {
PutType( u, "%u" ); PutType( u, "%u" );

File diff suppressed because it is too large Load Diff

View File

@ -316,13 +316,13 @@ const char *StringAfterPrefixCaseSensitive( const char *str, const char *prefix
} }
int V_atoi (const char *str) int64 V_atoi64( const char *str )
{ {
AssertValidStringPtr( str ); AssertValidStringPtr( str );
int val; int64 val;
int sign; int64 sign;
int c; int64 c;
Assert( str ); Assert( str );
if (*str == '-') if (*str == '-')
@ -377,6 +377,63 @@ int V_atoi (const char *str)
return 0; return 0;
} }
uint64 V_atoui64( const char *str )
{
AssertValidStringPtr( str );
uint64 val;
uint64 c;
Assert( str );
val = 0;
//
// check for hex
//
if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )
{
str += 2;
while (1)
{
c = *str++;
if (c >= '0' && c <= '9')
val = (val<<4) + c - '0';
else if (c >= 'a' && c <= 'f')
val = (val<<4) + c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
val = (val<<4) + c - 'A' + 10;
else
return val;
}
}
//
// check for character
//
if (str[0] == '\'')
{
return str[1];
}
//
// assume decimal
//
while (1)
{
c = *str++;
if (c <'0' || c > '9')
return val;
val = val*10 + c - '0';
}
return 0;
}
int V_atoi( const char *str )
{
return (int)V_atoi64( str );
}
float V_atof (const char *str) float V_atof (const char *str)
{ {