mirror of
https://github.com/alliedmodders/hl2sdk.git
synced 2025-01-05 17:13:36 +08:00
1845 lines
39 KiB
C++
1845 lines
39 KiB
C++
#include "keyvalues3.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
// Nasty hack to redefine gcc's offsetof which doesn't like GET_OUTER macro
|
|
#ifdef COMPILER_GCC
|
|
#undef offsetof
|
|
#define offsetof(s,m) (size_t)&(((s *)0)->m)
|
|
#endif
|
|
|
|
KeyValues3::KeyValues3( KV3TypeEx_t type, KV3SubType_t subtype ) :
|
|
m_bExternalStorage( true ),
|
|
m_TypeEx( type ),
|
|
m_SubType( subtype ),
|
|
m_nFlags( 0 ),
|
|
m_nReserved( 0 ),
|
|
m_nData( 0 )
|
|
{
|
|
ResolveUnspecified();
|
|
Alloc();
|
|
}
|
|
|
|
KeyValues3::KeyValues3( int cluster_elem, KV3TypeEx_t type, KV3SubType_t subtype ) :
|
|
m_bExternalStorage( false ),
|
|
m_TypeEx( type ),
|
|
m_SubType( subtype ),
|
|
m_nFlags( 0 ),
|
|
m_nClusterElement( cluster_elem ),
|
|
m_nReserved( 0 ),
|
|
m_nData( 0 )
|
|
{
|
|
ResolveUnspecified();
|
|
Alloc();
|
|
}
|
|
|
|
KeyValues3::~KeyValues3()
|
|
{
|
|
Free();
|
|
};
|
|
|
|
void KeyValues3::Alloc()
|
|
{
|
|
switch ( GetTypeEx() )
|
|
{
|
|
case KV3_TYPEEX_ARRAY:
|
|
{
|
|
CKeyValues3Context* context = GetContext();
|
|
if ( context )
|
|
m_pArray = context->AllocArray();
|
|
else
|
|
m_pArray = new CKeyValues3Array;
|
|
break;
|
|
}
|
|
case KV3_TYPEEX_TABLE:
|
|
{
|
|
CKeyValues3Context* context = GetContext();
|
|
if ( context )
|
|
m_pTable = context->AllocTable();
|
|
else
|
|
m_pTable = new CKeyValues3Table;
|
|
break;
|
|
}
|
|
case KV3_TYPEEX_ARRAY_FLOAT32:
|
|
case KV3_TYPEEX_ARRAY_FLOAT64:
|
|
case KV3_TYPEEX_ARRAY_INT16:
|
|
case KV3_TYPEEX_ARRAY_INT32:
|
|
case KV3_TYPEEX_ARRAY_UINT8_SHORT:
|
|
case KV3_TYPEEX_ARRAY_INT16_SHORT:
|
|
{
|
|
m_bFreeArrayMemory = false;
|
|
m_nNumArrayElements = 0;
|
|
m_nData = 0;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void KeyValues3::Free( bool bClearingContext )
|
|
{
|
|
switch ( GetTypeEx() )
|
|
{
|
|
case KV3_TYPEEX_STRING:
|
|
{
|
|
free( (void*)m_pString );
|
|
m_pString = NULL;
|
|
break;
|
|
}
|
|
case KV3_TYPEEX_BINARY_BLOB:
|
|
{
|
|
if ( m_pBinaryBlob )
|
|
free( m_pBinaryBlob );
|
|
m_pBinaryBlob = NULL;
|
|
break;
|
|
}
|
|
case KV3_TYPEEX_BINARY_BLOB_EXTERN:
|
|
{
|
|
if ( m_pBinaryBlob )
|
|
{
|
|
if ( m_pBinaryBlob->m_bFreeMemory )
|
|
free( (void*)m_pBinaryBlob->m_pubData );
|
|
free( m_pBinaryBlob );
|
|
}
|
|
m_pBinaryBlob = NULL;
|
|
break;
|
|
}
|
|
case KV3_TYPEEX_ARRAY:
|
|
{
|
|
m_pArray->Purge( bClearingContext );
|
|
|
|
CKeyValues3Context* context = GetContext();
|
|
|
|
if ( context )
|
|
{
|
|
if ( !bClearingContext )
|
|
context->FreeArray( m_pArray );
|
|
}
|
|
else
|
|
{
|
|
delete m_pArray;
|
|
}
|
|
|
|
m_pArray = NULL;
|
|
break;
|
|
}
|
|
case KV3_TYPEEX_TABLE:
|
|
{
|
|
m_pTable->Purge( bClearingContext );
|
|
|
|
CKeyValues3Context* context = GetContext();
|
|
|
|
if ( context )
|
|
{
|
|
if ( !bClearingContext )
|
|
context->FreeTable( m_pTable );
|
|
}
|
|
else
|
|
{
|
|
delete m_pTable;
|
|
}
|
|
|
|
m_pTable = NULL;
|
|
break;
|
|
}
|
|
case KV3_TYPEEX_ARRAY_FLOAT32:
|
|
case KV3_TYPEEX_ARRAY_FLOAT64:
|
|
case KV3_TYPEEX_ARRAY_INT16:
|
|
case KV3_TYPEEX_ARRAY_INT32:
|
|
case KV3_TYPEEX_ARRAY_UINT8_SHORT:
|
|
case KV3_TYPEEX_ARRAY_INT16_SHORT:
|
|
{
|
|
if ( m_bFreeArrayMemory )
|
|
free( m_pData );
|
|
m_bFreeArrayMemory = false;
|
|
m_nNumArrayElements = 0;
|
|
m_nData = 0;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void KeyValues3::ResolveUnspecified()
|
|
{
|
|
if ( GetSubType() == KV3_SUBTYPE_UNSPECIFIED )
|
|
{
|
|
switch ( GetType() )
|
|
{
|
|
case KV3_TYPE_NULL:
|
|
m_SubType = KV3_SUBTYPE_NULL;
|
|
break;
|
|
case KV3_TYPE_BOOL:
|
|
m_SubType = KV3_SUBTYPE_BOOL8;
|
|
break;
|
|
case KV3_TYPE_INT:
|
|
m_SubType = KV3_SUBTYPE_INT64;
|
|
break;
|
|
case KV3_TYPE_UINT:
|
|
m_SubType = KV3_SUBTYPE_UINT64;
|
|
break;
|
|
case KV3_TYPE_DOUBLE:
|
|
m_SubType = KV3_SUBTYPE_FLOAT64;
|
|
break;
|
|
case KV3_TYPE_STRING:
|
|
m_SubType = KV3_SUBTYPE_STRING;
|
|
break;
|
|
case KV3_TYPE_BINARY_BLOB:
|
|
m_SubType = KV3_SUBTYPE_BINARY_BLOB;
|
|
break;
|
|
case KV3_TYPE_ARRAY:
|
|
m_SubType = KV3_SUBTYPE_ARRAY;
|
|
break;
|
|
case KV3_TYPE_TABLE:
|
|
m_SubType = KV3_SUBTYPE_TABLE;
|
|
break;
|
|
default:
|
|
m_SubType = KV3_SUBTYPE_INVALID;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void KeyValues3::PrepareForType( KV3TypeEx_t type, KV3SubType_t subtype )
|
|
{
|
|
if ( GetTypeEx() == type )
|
|
{
|
|
switch ( type )
|
|
{
|
|
case KV3_TYPEEX_STRING:
|
|
case KV3_TYPEEX_BINARY_BLOB:
|
|
case KV3_TYPEEX_BINARY_BLOB_EXTERN:
|
|
case KV3_TYPEEX_ARRAY_FLOAT32:
|
|
case KV3_TYPEEX_ARRAY_FLOAT64:
|
|
case KV3_TYPEEX_ARRAY_INT16:
|
|
case KV3_TYPEEX_ARRAY_INT32:
|
|
case KV3_TYPEEX_ARRAY_UINT8_SHORT:
|
|
case KV3_TYPEEX_ARRAY_INT16_SHORT:
|
|
{
|
|
Free();
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Free();
|
|
m_TypeEx = type;
|
|
m_nData = 0;
|
|
Alloc();
|
|
}
|
|
|
|
m_SubType = subtype;
|
|
}
|
|
|
|
void KeyValues3::OnClearContext()
|
|
{
|
|
Free( true );
|
|
m_TypeEx = KV3_TYPEEX_NULL;
|
|
m_nData = 0;
|
|
}
|
|
|
|
CKeyValues3Cluster* KeyValues3::GetCluster() const
|
|
{
|
|
if ( m_bExternalStorage )
|
|
return NULL;
|
|
|
|
return GET_OUTER( CKeyValues3Cluster, m_KeyValues[ m_nClusterElement ] );
|
|
}
|
|
|
|
CKeyValues3Context* KeyValues3::GetContext() const
|
|
{
|
|
CKeyValues3Cluster* cluster = GetCluster();
|
|
|
|
if ( cluster )
|
|
return cluster->GetContext();
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
KV3MetaData_t* KeyValues3::GetMetaData( CKeyValues3Context** ppCtx ) const
|
|
{
|
|
CKeyValues3Cluster* cluster = GetCluster();
|
|
|
|
if ( cluster )
|
|
{
|
|
if ( ppCtx )
|
|
*ppCtx = cluster->GetContext();
|
|
|
|
return cluster->GetMetaData( m_nClusterElement );
|
|
}
|
|
else
|
|
{
|
|
if ( ppCtx )
|
|
*ppCtx = NULL;
|
|
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
const char* KeyValues3::GetString( const char* defaultValue ) const
|
|
{
|
|
switch ( GetTypeEx() )
|
|
{
|
|
case KV3_TYPEEX_STRING:
|
|
case KV3_TYPEEX_STRING_EXTERN:
|
|
return m_pString;
|
|
case KV3_TYPEEX_STRING_SHORT:
|
|
return m_szStringShort;
|
|
default:
|
|
return defaultValue;
|
|
}
|
|
}
|
|
|
|
void KeyValues3::SetString( const char* pString, KV3SubType_t subtype )
|
|
{
|
|
if ( !pString )
|
|
pString = "";
|
|
|
|
if ( strlen( pString ) < sizeof( m_szStringShort ) )
|
|
{
|
|
PrepareForType( KV3_TYPEEX_STRING_SHORT, subtype );
|
|
V_strncpy( m_szStringShort, pString, sizeof( m_szStringShort ) );
|
|
}
|
|
else
|
|
{
|
|
PrepareForType( KV3_TYPEEX_STRING, subtype );
|
|
m_pString = strdup( pString );
|
|
}
|
|
}
|
|
|
|
void KeyValues3::SetStringExternal( const char* pString, KV3SubType_t subtype )
|
|
{
|
|
if ( strlen( pString ) < sizeof( m_szStringShort ) )
|
|
{
|
|
PrepareForType( KV3_TYPEEX_STRING_SHORT, subtype );
|
|
V_strncpy( m_szStringShort, pString, sizeof( m_szStringShort ) );
|
|
}
|
|
else
|
|
{
|
|
PrepareForType( KV3_TYPEEX_STRING_EXTERN, subtype );
|
|
m_pString = pString;
|
|
}
|
|
}
|
|
|
|
const byte* KeyValues3::GetBinaryBlob() const
|
|
{
|
|
switch ( GetTypeEx() )
|
|
{
|
|
case KV3_TYPEEX_BINARY_BLOB:
|
|
return m_pBinaryBlob ? m_pBinaryBlob->m_ubData : NULL;
|
|
case KV3_TYPEEX_BINARY_BLOB_EXTERN:
|
|
return m_pBinaryBlob ? m_pBinaryBlob->m_pubData : NULL;
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
int KeyValues3::GetBinaryBlobSize() const
|
|
{
|
|
if ( GetType() != KV3_TYPE_BINARY_BLOB || !m_pBinaryBlob )
|
|
return 0;
|
|
|
|
return ( int )m_pBinaryBlob->m_nSize;
|
|
}
|
|
|
|
void KeyValues3::SetToBinaryBlob( const byte* blob, int size )
|
|
{
|
|
PrepareForType( KV3_TYPEEX_BINARY_BLOB, KV3_SUBTYPE_BINARY_BLOB );
|
|
|
|
if ( size > 0 )
|
|
{
|
|
m_pBinaryBlob = (KV3BinaryBlob_t*)malloc( sizeof( size_t ) + size );
|
|
m_pBinaryBlob->m_nSize = size;
|
|
memcpy( m_pBinaryBlob->m_ubData, blob, size );
|
|
}
|
|
else
|
|
{
|
|
m_pBinaryBlob = NULL;
|
|
}
|
|
}
|
|
|
|
void KeyValues3::SetToBinaryBlobExternal( const byte* blob, int size, bool free_mem )
|
|
{
|
|
PrepareForType( KV3_TYPEEX_BINARY_BLOB_EXTERN, KV3_SUBTYPE_BINARY_BLOB );
|
|
|
|
if ( size > 0 )
|
|
{
|
|
m_pBinaryBlob = (KV3BinaryBlob_t*)malloc( sizeof( KV3BinaryBlob_t ) );
|
|
m_pBinaryBlob->m_nSize = size;
|
|
m_pBinaryBlob->m_pubData = blob;
|
|
m_pBinaryBlob->m_bFreeMemory = free_mem;
|
|
}
|
|
else
|
|
{
|
|
m_pBinaryBlob = NULL;
|
|
}
|
|
}
|
|
|
|
Color KeyValues3::GetColor( const Color &defaultValue ) const
|
|
{
|
|
int32 color[4];
|
|
if ( ReadArrayInt32( 4, color ) )
|
|
{
|
|
return Color( color[0], color[1], color[2], color[3] );
|
|
}
|
|
else if ( ReadArrayInt32( 3, color ) )
|
|
{
|
|
return Color( color[0], color[1], color[2], 255 );
|
|
}
|
|
else
|
|
{
|
|
return defaultValue;
|
|
}
|
|
}
|
|
|
|
void KeyValues3::SetColor( const Color &color )
|
|
{
|
|
if ( color.a() == 255 )
|
|
AllocArray<uint8>( 3, &color[0], KV3_ARRAY_ALLOC_NORMAL, KV3_TYPEEX_ARRAY_UINT8_SHORT, KV3_TYPEEX_INVALID, KV3_SUBTYPE_COLOR32, KV3_TYPEEX_UINT, KV3_SUBTYPE_UINT8 );
|
|
else
|
|
AllocArray<uint8>( 4, &color[0], KV3_ARRAY_ALLOC_NORMAL, KV3_TYPEEX_ARRAY_UINT8_SHORT, KV3_TYPEEX_INVALID, KV3_SUBTYPE_COLOR32, KV3_TYPEEX_UINT, KV3_SUBTYPE_UINT8 );
|
|
}
|
|
|
|
int KeyValues3::GetArrayElementCount() const
|
|
{
|
|
if ( GetType() != KV3_TYPE_ARRAY )
|
|
return 0;
|
|
|
|
if ( GetTypeEx() == KV3_TYPEEX_ARRAY )
|
|
return m_pArray->Count();
|
|
else
|
|
return m_nNumArrayElements;
|
|
}
|
|
|
|
KeyValues3** KeyValues3::GetArrayBase()
|
|
{
|
|
if ( GetType() != KV3_TYPE_ARRAY )
|
|
return NULL;
|
|
|
|
NormalizeArray();
|
|
|
|
return m_pArray->Base();
|
|
}
|
|
|
|
KeyValues3* KeyValues3::GetArrayElement( int elem )
|
|
{
|
|
if ( GetType() != KV3_TYPE_ARRAY )
|
|
return NULL;
|
|
|
|
NormalizeArray();
|
|
|
|
if ( elem < 0 || elem >= m_pArray->Count() )
|
|
return NULL;
|
|
|
|
return m_pArray->Element( elem );
|
|
}
|
|
|
|
KeyValues3* KeyValues3::InsertArrayElementBefore( int elem )
|
|
{
|
|
if ( GetType() != KV3_TYPE_ARRAY )
|
|
return NULL;
|
|
|
|
NormalizeArray();
|
|
|
|
return *m_pArray->InsertBeforeGetPtr( elem, 1 );
|
|
}
|
|
|
|
KeyValues3* KeyValues3::AddArrayElementToTail()
|
|
{
|
|
if ( GetType() != KV3_TYPE_ARRAY )
|
|
PrepareForType( KV3_TYPEEX_ARRAY, KV3_SUBTYPE_ARRAY );
|
|
else
|
|
NormalizeArray();
|
|
|
|
return *m_pArray->InsertBeforeGetPtr( m_pArray->Count(), 1 );
|
|
}
|
|
|
|
void KeyValues3::SetArrayElementCount( int count, KV3TypeEx_t type, KV3SubType_t subtype )
|
|
{
|
|
if ( GetType() != KV3_TYPE_ARRAY )
|
|
PrepareForType( KV3_TYPEEX_ARRAY, KV3_SUBTYPE_ARRAY );
|
|
else
|
|
NormalizeArray();
|
|
|
|
m_pArray->SetCount( count, type, subtype );
|
|
}
|
|
|
|
void KeyValues3::RemoveArrayElements( int elem, int num )
|
|
{
|
|
if ( GetType() != KV3_TYPE_ARRAY )
|
|
return;
|
|
|
|
NormalizeArray();
|
|
|
|
m_pArray->RemoveMultiple( elem, num );
|
|
}
|
|
|
|
void KeyValues3::NormalizeArray()
|
|
{
|
|
switch ( GetTypeEx() )
|
|
{
|
|
case KV3_TYPEEX_ARRAY_FLOAT32:
|
|
{
|
|
NormalizeArray<float32>( KV3_TYPEEX_DOUBLE, KV3_SUBTYPE_FLOAT32, m_nNumArrayElements, m_f32Array, m_bFreeArrayMemory );
|
|
break;
|
|
}
|
|
case KV3_TYPEEX_ARRAY_FLOAT64:
|
|
{
|
|
NormalizeArray<float64>( KV3_TYPEEX_DOUBLE, KV3_SUBTYPE_FLOAT64, m_nNumArrayElements, m_f64Array, m_bFreeArrayMemory );
|
|
break;
|
|
}
|
|
case KV3_TYPEEX_ARRAY_INT16:
|
|
{
|
|
NormalizeArray<int16>( KV3_TYPEEX_INT, KV3_SUBTYPE_INT16, m_nNumArrayElements, m_i16Array, m_bFreeArrayMemory );
|
|
break;
|
|
}
|
|
case KV3_TYPEEX_ARRAY_INT32:
|
|
{
|
|
NormalizeArray<int32>( KV3_TYPEEX_INT, KV3_SUBTYPE_INT32, m_nNumArrayElements, m_i32Array, m_bFreeArrayMemory );
|
|
break;
|
|
}
|
|
case KV3_TYPEEX_ARRAY_UINT8_SHORT:
|
|
{
|
|
uint8 u8ArrayShort[8];
|
|
memcpy( u8ArrayShort, m_u8ArrayShort, sizeof( u8ArrayShort ) );
|
|
NormalizeArray<uint8>( KV3_TYPEEX_UINT, KV3_SUBTYPE_UINT8, m_nNumArrayElements, u8ArrayShort, false );
|
|
break;
|
|
}
|
|
case KV3_TYPEEX_ARRAY_INT16_SHORT:
|
|
{
|
|
int16 i16ArrayShort[4];
|
|
memcpy( i16ArrayShort, m_i16ArrayShort, sizeof( i16ArrayShort ) );
|
|
NormalizeArray<int16>( KV3_TYPEEX_INT, KV3_SUBTYPE_INT16, m_nNumArrayElements, i16ArrayShort, false );
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool KeyValues3::ReadArrayInt32( int dest_size, int32* data ) const
|
|
{
|
|
int src_size = 0;
|
|
|
|
if ( GetType() == KV3_TYPE_STRING )
|
|
{
|
|
CSplitString values( GetString(), " " );
|
|
src_size = values.Count();
|
|
int count = MIN( src_size, dest_size );
|
|
for ( int i = 0; i < count; ++i )
|
|
data[ i ] = V_StringToInt32( values[ i ], 0, NULL, NULL, PARSING_FLAG_SKIP_ASSERT );
|
|
}
|
|
else
|
|
{
|
|
switch ( GetTypeEx() )
|
|
{
|
|
case KV3_TYPEEX_ARRAY:
|
|
{
|
|
src_size = m_pArray->Count();
|
|
int count = MIN( src_size, dest_size );
|
|
KeyValues3** arr = m_pArray->Base();
|
|
for ( int i = 0; i < count; ++i )
|
|
data[ i ] = arr[ i ]->GetInt();
|
|
break;
|
|
}
|
|
case KV3_TYPEEX_ARRAY_INT16:
|
|
{
|
|
src_size = m_nNumArrayElements;
|
|
int count = MIN( src_size, dest_size );
|
|
for ( int i = 0; i < count; ++i )
|
|
data[ i ] = ( int32 )m_i16Array[ i ];
|
|
break;
|
|
}
|
|
case KV3_TYPEEX_ARRAY_INT32:
|
|
{
|
|
src_size = m_nNumArrayElements;
|
|
int count = MIN( src_size, dest_size );
|
|
memcpy( data, m_i32Array, count * sizeof( int32 ) );
|
|
break;
|
|
}
|
|
case KV3_TYPEEX_ARRAY_UINT8_SHORT:
|
|
{
|
|
src_size = m_nNumArrayElements;
|
|
int count = MIN( src_size, dest_size );
|
|
for ( int i = 0; i < count; ++i )
|
|
data[ i ] = ( int32 )m_u8ArrayShort[ i ];
|
|
break;
|
|
}
|
|
case KV3_TYPEEX_ARRAY_INT16_SHORT:
|
|
{
|
|
src_size = m_nNumArrayElements;
|
|
int count = MIN( src_size, dest_size );
|
|
for ( int i = 0; i < count; ++i )
|
|
data[ i ] = ( int32 )m_i16ArrayShort[ i ];
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( src_size < dest_size )
|
|
memset( &data[ src_size ], 0, ( dest_size - src_size ) * sizeof( int32 ) );
|
|
|
|
return ( src_size == dest_size );
|
|
}
|
|
|
|
bool KeyValues3::ReadArrayFloat32( int dest_size, float32* data ) const
|
|
{
|
|
int src_size = 0;
|
|
|
|
if ( GetType() == KV3_TYPE_STRING )
|
|
{
|
|
CSplitString values( GetString(), " " );
|
|
src_size = values.Count();
|
|
int count = MIN( src_size, dest_size );
|
|
for ( int i = 0; i < count; ++i )
|
|
data[ i ] = ( float32 )V_StringToFloat64( values[ i ], 0, NULL, NULL, PARSING_FLAG_SKIP_ASSERT );
|
|
}
|
|
else
|
|
{
|
|
switch ( GetTypeEx() )
|
|
{
|
|
case KV3_TYPEEX_ARRAY:
|
|
{
|
|
src_size = m_pArray->Count();
|
|
int count = MIN( src_size, dest_size );
|
|
KeyValues3** arr = m_pArray->Base();
|
|
for ( int i = 0; i < count; ++i )
|
|
data[ i ] = arr[ i ]->GetFloat();
|
|
break;
|
|
}
|
|
case KV3_TYPEEX_ARRAY_FLOAT32:
|
|
{
|
|
src_size = m_nNumArrayElements;
|
|
int count = MIN( src_size, dest_size );
|
|
memcpy( data, m_f32Array, count * sizeof( float32 ) );
|
|
break;
|
|
}
|
|
case KV3_TYPEEX_ARRAY_FLOAT64:
|
|
{
|
|
src_size = m_nNumArrayElements;
|
|
int count = MIN( src_size, dest_size );
|
|
for ( int i = 0; i < count; ++i )
|
|
data[ i ] = ( float32 )m_f64Array[ i ];
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( src_size < dest_size )
|
|
memset( &data[ src_size ], 0, ( dest_size - src_size ) * sizeof( float32 ) );
|
|
|
|
return ( src_size == dest_size );
|
|
}
|
|
|
|
int KeyValues3::GetMemberCount() const
|
|
{
|
|
if ( GetType() != KV3_TYPE_TABLE )
|
|
return 0;
|
|
|
|
return m_pTable->GetMemberCount();
|
|
}
|
|
|
|
KeyValues3* KeyValues3::GetMember( KV3MemberId_t id )
|
|
{
|
|
if ( GetType() != KV3_TYPE_TABLE || id < 0 || id >= m_pTable->GetMemberCount() )
|
|
return NULL;
|
|
|
|
return m_pTable->GetMember( id );
|
|
}
|
|
|
|
const char* KeyValues3::GetMemberName( KV3MemberId_t id ) const
|
|
{
|
|
if ( GetType() != KV3_TYPE_TABLE || id < 0 || id >= m_pTable->GetMemberCount() )
|
|
return NULL;
|
|
|
|
return m_pTable->GetMemberName( id );
|
|
}
|
|
|
|
CKV3MemberName KeyValues3::GetMemberNameEx( KV3MemberId_t id ) const
|
|
{
|
|
if ( GetType() != KV3_TYPE_TABLE || id < 0 || id >= m_pTable->GetMemberCount() )
|
|
return CKV3MemberName();
|
|
|
|
return CKV3MemberName( m_pTable->GetMemberHash( id ), m_pTable->GetMemberName( id ) );
|
|
}
|
|
|
|
unsigned int KeyValues3::GetMemberHash( KV3MemberId_t id ) const
|
|
{
|
|
if ( GetType() != KV3_TYPE_TABLE || id < 0 || id >= m_pTable->GetMemberCount() )
|
|
return 0;
|
|
|
|
return m_pTable->GetMemberHash( id );
|
|
}
|
|
|
|
KeyValues3* KeyValues3::FindMember( const CKV3MemberName &name, KeyValues3* defaultValue )
|
|
{
|
|
if ( GetType() != KV3_TYPE_TABLE )
|
|
return defaultValue;
|
|
|
|
KV3MemberId_t id = m_pTable->FindMember( name );
|
|
|
|
if ( id == KV3_INVALID_MEMBER )
|
|
return defaultValue;
|
|
|
|
return m_pTable->GetMember( id );
|
|
}
|
|
|
|
KeyValues3* KeyValues3::FindOrCreateMember( const CKV3MemberName &name, bool *pCreated )
|
|
{
|
|
if ( GetType() != KV3_TYPE_TABLE )
|
|
PrepareForType( KV3_TYPEEX_TABLE, KV3_SUBTYPE_TABLE );
|
|
|
|
KV3MemberId_t id = m_pTable->FindMember( name );
|
|
|
|
if ( id == KV3_INVALID_MEMBER )
|
|
{
|
|
if ( pCreated )
|
|
*pCreated = true;
|
|
|
|
id = m_pTable->CreateMember( name );
|
|
}
|
|
else
|
|
{
|
|
if ( pCreated )
|
|
*pCreated = false;
|
|
}
|
|
|
|
return m_pTable->GetMember( id );
|
|
}
|
|
|
|
bool KeyValues3::TableHasBadNames() const
|
|
{
|
|
if ( GetType() != KV3_TYPE_TABLE )
|
|
return false;
|
|
|
|
return m_pTable->HasBadNames();
|
|
}
|
|
|
|
void KeyValues3::SetTableHasBadNames( bool bHasBadNames )
|
|
{
|
|
if ( GetType() != KV3_TYPE_TABLE )
|
|
return;
|
|
|
|
m_pTable->SetHasBadNames( bHasBadNames );
|
|
}
|
|
|
|
void KeyValues3::SetToEmptyTable()
|
|
{
|
|
PrepareForType( KV3_TYPEEX_TABLE, KV3_SUBTYPE_TABLE );
|
|
m_pTable->RemoveAll();
|
|
}
|
|
|
|
bool KeyValues3::RemoveMember( KV3MemberId_t id )
|
|
{
|
|
if ( GetType() != KV3_TYPE_TABLE || id < 0 || id >= m_pTable->GetMemberCount() )
|
|
return false;
|
|
|
|
m_pTable->RemoveMember( id );
|
|
|
|
return true;
|
|
}
|
|
|
|
bool KeyValues3::RemoveMember( const KeyValues3* kv )
|
|
{
|
|
if ( GetType() != KV3_TYPE_TABLE )
|
|
return false;
|
|
|
|
KV3MemberId_t id = m_pTable->FindMember( kv );
|
|
|
|
if ( id == KV3_INVALID_MEMBER )
|
|
return false;
|
|
|
|
m_pTable->RemoveMember( id );
|
|
|
|
return true;
|
|
}
|
|
|
|
bool KeyValues3::RemoveMember( const CKV3MemberName &name )
|
|
{
|
|
if ( GetType() != KV3_TYPE_TABLE )
|
|
return false;
|
|
|
|
KV3MemberId_t id = m_pTable->FindMember( name );
|
|
|
|
if ( id == KV3_INVALID_MEMBER )
|
|
return false;
|
|
|
|
m_pTable->RemoveMember( id );
|
|
|
|
return true;
|
|
}
|
|
|
|
const char* KeyValues3::GetTypeAsString() const
|
|
{
|
|
static const char* s_Types[] =
|
|
{
|
|
"invalid",
|
|
"null",
|
|
"bool",
|
|
"int",
|
|
"uint",
|
|
"double",
|
|
"string",
|
|
"binary_blob",
|
|
"array",
|
|
"table",
|
|
NULL
|
|
};
|
|
|
|
KV3Type_t type = GetType();
|
|
|
|
if ( type < KV3_TYPE_COUNT )
|
|
return s_Types[type];
|
|
|
|
return "<unknown>";
|
|
}
|
|
|
|
const char* KeyValues3::GetSubTypeAsString() const
|
|
{
|
|
static const char* s_SubTypes[] =
|
|
{
|
|
"invalid",
|
|
"resource",
|
|
"resource_name",
|
|
"panorama",
|
|
"soundevent",
|
|
"subclass",
|
|
"entity_name",
|
|
"unspecified",
|
|
"null",
|
|
"binary_blob",
|
|
"array",
|
|
"table",
|
|
"bool8",
|
|
"char8",
|
|
"uchar32",
|
|
"int8",
|
|
"uint8",
|
|
"int16",
|
|
"uint16",
|
|
"int32",
|
|
"uint32",
|
|
"int64",
|
|
"uint64",
|
|
"float32",
|
|
"float64",
|
|
"string",
|
|
"pointer",
|
|
"color32",
|
|
"vector",
|
|
"vector2d",
|
|
"vector4d",
|
|
"rotation_vector",
|
|
"quaternion",
|
|
"qangle",
|
|
"matrix3x4",
|
|
"transform",
|
|
"string_token",
|
|
"ehandle",
|
|
NULL
|
|
};
|
|
|
|
KV3SubType_t subtype = GetSubType();
|
|
|
|
if ( subtype < KV3_SUBTYPE_COUNT )
|
|
return s_SubTypes[subtype];
|
|
|
|
return "<unknown>";
|
|
}
|
|
|
|
const char* KeyValues3::ToString( CBufferString& buff, uint flags ) const
|
|
{
|
|
if ( ( flags & KV3_TO_STRING_DONT_CLEAR_BUFF ) != 0 )
|
|
flags &= ~KV3_TO_STRING_DONT_APPEND_STRINGS;
|
|
else
|
|
buff.ToGrowable()->Clear();
|
|
|
|
KV3Type_t type = GetType();
|
|
|
|
switch ( type )
|
|
{
|
|
case KV3_TYPE_NULL:
|
|
{
|
|
return buff.ToGrowable()->Get();
|
|
}
|
|
case KV3_TYPE_BOOL:
|
|
{
|
|
const char* str = m_Bool ? "true" : "false";
|
|
|
|
if ( ( flags & KV3_TO_STRING_DONT_APPEND_STRINGS ) != 0 )
|
|
return str;
|
|
|
|
buff.Insert( buff.ToGrowable()->GetTotalNumber(), str );
|
|
return buff.ToGrowable()->Get();
|
|
}
|
|
case KV3_TYPE_INT:
|
|
{
|
|
buff.AppendFormat( "%lld", m_Int );
|
|
return buff.ToGrowable()->Get();
|
|
}
|
|
case KV3_TYPE_UINT:
|
|
{
|
|
if ( GetSubType() == KV3_SUBTYPE_POINTER )
|
|
{
|
|
if ( ( flags & KV3_TO_STRING_APPEND_ONLY_NUMERICS ) == 0 )
|
|
buff.Insert( buff.ToGrowable()->GetTotalNumber(), "<pointer>" );
|
|
|
|
if ( ( flags & KV3_TO_STRING_RETURN_NON_NUMERICS ) == 0 )
|
|
return NULL;
|
|
|
|
return buff.ToGrowable()->Get();
|
|
}
|
|
|
|
buff.AppendFormat( "%llu", m_UInt );
|
|
return buff.ToGrowable()->Get();
|
|
}
|
|
case KV3_TYPE_DOUBLE:
|
|
{
|
|
buff.AppendFormat( "%g", m_Double );
|
|
return buff.ToGrowable()->Get();
|
|
}
|
|
case KV3_TYPE_STRING:
|
|
{
|
|
const char* str = GetString();
|
|
|
|
if ( ( flags & KV3_TO_STRING_DONT_APPEND_STRINGS ) != 0 )
|
|
return str;
|
|
|
|
buff.Insert( buff.ToGrowable()->GetTotalNumber(), str );
|
|
return buff.ToGrowable()->Get();
|
|
}
|
|
case KV3_TYPE_BINARY_BLOB:
|
|
{
|
|
if ( ( flags & KV3_TO_STRING_APPEND_ONLY_NUMERICS ) == 0 )
|
|
buff.AppendFormat( "<binary blob: %u bytes>", GetBinaryBlobSize() );
|
|
|
|
if ( ( flags & KV3_TO_STRING_RETURN_NON_NUMERICS ) == 0 )
|
|
return NULL;
|
|
|
|
return buff.ToGrowable()->Get();
|
|
}
|
|
case KV3_TYPE_ARRAY:
|
|
{
|
|
int elements = GetArrayElementCount();
|
|
|
|
if ( elements > 0 && elements <= 4 )
|
|
{
|
|
switch ( GetTypeEx() )
|
|
{
|
|
case KV3_TYPEEX_ARRAY:
|
|
{
|
|
bool unprintable = false;
|
|
CBufferStringGrowable<128> temp;
|
|
|
|
KeyValues3** arr = m_pArray->Base();
|
|
for ( int i = 0; i < elements; ++i )
|
|
{
|
|
switch ( arr[i]->GetType() )
|
|
{
|
|
case KV3_TYPE_INT:
|
|
temp.AppendFormat( "%lld", arr[i]->m_Int );
|
|
break;
|
|
case KV3_TYPE_UINT:
|
|
if ( arr[i]->GetSubType() == KV3_SUBTYPE_POINTER )
|
|
unprintable = true;
|
|
else
|
|
temp.AppendFormat( "%llu", arr[i]->m_UInt );
|
|
break;
|
|
case KV3_TYPE_DOUBLE:
|
|
temp.AppendFormat( "%g", arr[i]->m_Double );
|
|
break;
|
|
default:
|
|
unprintable = true;
|
|
break;
|
|
}
|
|
|
|
if ( unprintable )
|
|
break;
|
|
|
|
if ( i != elements - 1 ) temp.Insert( temp.ToGrowable()->GetTotalNumber(), " " );
|
|
}
|
|
|
|
if ( unprintable )
|
|
break;
|
|
|
|
buff.Insert( buff.ToGrowable()->GetTotalNumber(), temp.Get() );
|
|
return buff.ToGrowable()->Get();
|
|
}
|
|
case KV3_TYPEEX_ARRAY_FLOAT32:
|
|
{
|
|
for ( int i = 0; i < elements; ++i )
|
|
{
|
|
buff.AppendFormat( "%g", m_f32Array[i] );
|
|
if ( i != elements - 1 ) buff.Insert( buff.ToGrowable()->GetTotalNumber(), " " );
|
|
}
|
|
return buff.ToGrowable()->Get();
|
|
}
|
|
case KV3_TYPEEX_ARRAY_FLOAT64:
|
|
{
|
|
for ( int i = 0; i < elements; ++i )
|
|
{
|
|
buff.AppendFormat( "%g", m_f64Array[i] );
|
|
if ( i != elements - 1 ) buff.Insert( buff.ToGrowable()->GetTotalNumber(), " " );
|
|
}
|
|
return buff.ToGrowable()->Get();
|
|
}
|
|
case KV3_TYPEEX_ARRAY_INT16:
|
|
{
|
|
for ( int i = 0; i < elements; ++i )
|
|
{
|
|
buff.AppendFormat( "%d", m_i16Array[i] );
|
|
if ( i != elements - 1 ) buff.Insert( buff.ToGrowable()->GetTotalNumber(), " " );
|
|
}
|
|
return buff.ToGrowable()->Get();
|
|
}
|
|
case KV3_TYPEEX_ARRAY_INT32:
|
|
{
|
|
for ( int i = 0; i < elements; ++i )
|
|
{
|
|
buff.AppendFormat( "%d", m_i32Array[i] );
|
|
if ( i != elements - 1 ) buff.Insert( buff.ToGrowable()->GetTotalNumber(), " " );
|
|
}
|
|
return buff.ToGrowable()->Get();
|
|
}
|
|
case KV3_TYPEEX_ARRAY_UINT8_SHORT:
|
|
{
|
|
for ( int i = 0; i < elements; ++i )
|
|
{
|
|
buff.AppendFormat( "%u", m_u8ArrayShort[i] );
|
|
if ( i != elements - 1 ) buff.Insert( buff.ToGrowable()->GetTotalNumber(), " " );
|
|
}
|
|
return buff.ToGrowable()->Get();
|
|
}
|
|
case KV3_TYPEEX_ARRAY_INT16_SHORT:
|
|
{
|
|
for ( int i = 0; i < elements; ++i )
|
|
{
|
|
buff.AppendFormat( "%d", m_i16ArrayShort[i] );
|
|
if ( i != elements - 1 ) buff.Insert( buff.ToGrowable()->GetTotalNumber(), " " );
|
|
}
|
|
return buff.ToGrowable()->Get();
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( ( flags & KV3_TO_STRING_APPEND_ONLY_NUMERICS ) == 0 )
|
|
buff.AppendFormat( "<array: %u elements>", elements );
|
|
|
|
if ( ( flags & KV3_TO_STRING_RETURN_NON_NUMERICS ) == 0 )
|
|
return NULL;
|
|
|
|
return buff.ToGrowable()->Get();
|
|
}
|
|
case KV3_TYPE_TABLE:
|
|
{
|
|
if ( ( flags & KV3_TO_STRING_APPEND_ONLY_NUMERICS ) == 0 )
|
|
buff.AppendFormat( "<table: %u members>", GetMemberCount() );
|
|
|
|
if ( ( flags & KV3_TO_STRING_RETURN_NON_NUMERICS ) == 0 )
|
|
return NULL;
|
|
|
|
return buff.ToGrowable()->Get();
|
|
}
|
|
default:
|
|
{
|
|
if ( ( flags & KV3_TO_STRING_APPEND_ONLY_NUMERICS ) == 0 )
|
|
buff.AppendFormat( "<unknown KV3 basic type '%s' (%d)>", GetTypeAsString(), type );
|
|
|
|
if ( ( flags & KV3_TO_STRING_RETURN_NON_NUMERICS ) == 0 )
|
|
return NULL;
|
|
|
|
return buff.ToGrowable()->Get();
|
|
}
|
|
}
|
|
}
|
|
|
|
void KeyValues3::CopyFrom( const KeyValues3* pSrc )
|
|
{
|
|
SetToNull();
|
|
|
|
CKeyValues3Context* context;
|
|
KV3MetaData_t* pDestMetaData = GetMetaData( &context );
|
|
|
|
if ( pDestMetaData )
|
|
{
|
|
KV3MetaData_t* pSrcMetaData = pSrc->GetMetaData();
|
|
|
|
if ( pSrcMetaData )
|
|
context->CopyMetaData( pDestMetaData, pSrcMetaData );
|
|
else
|
|
pDestMetaData->Clear();
|
|
}
|
|
|
|
KV3SubType_t eSrcSubType = pSrc->GetSubType();
|
|
|
|
switch ( pSrc->GetType() )
|
|
{
|
|
case KV3_TYPE_BOOL:
|
|
SetBool( pSrc->m_Bool );
|
|
break;
|
|
case KV3_TYPE_INT:
|
|
SetValue<int64>( pSrc->m_Int, KV3_TYPEEX_INT, eSrcSubType );
|
|
break;
|
|
case KV3_TYPE_UINT:
|
|
SetValue<uint64>( pSrc->m_UInt, KV3_TYPEEX_UINT, eSrcSubType );
|
|
break;
|
|
case KV3_TYPE_DOUBLE:
|
|
SetValue<float64>( pSrc->m_Double, KV3_TYPEEX_DOUBLE, eSrcSubType );
|
|
break;
|
|
case KV3_TYPE_STRING:
|
|
SetString( pSrc->GetString(), eSrcSubType );
|
|
break;
|
|
case KV3_TYPE_BINARY_BLOB:
|
|
SetToBinaryBlob( pSrc->GetBinaryBlob(), pSrc->GetBinaryBlobSize() );
|
|
break;
|
|
case KV3_TYPE_ARRAY:
|
|
{
|
|
switch ( pSrc->GetTypeEx() )
|
|
{
|
|
case KV3_TYPEEX_ARRAY:
|
|
{
|
|
PrepareForType( KV3_TYPEEX_ARRAY, KV3_SUBTYPE_ARRAY );
|
|
m_pArray->CopyFrom( pSrc->m_pArray );
|
|
break;
|
|
}
|
|
case KV3_TYPEEX_ARRAY_FLOAT32:
|
|
AllocArray<float32>( pSrc->m_nNumArrayElements, pSrc->m_f32Array, KV3_ARRAY_ALLOC_NORMAL, KV3_TYPEEX_INVALID, KV3_TYPEEX_ARRAY_FLOAT32, eSrcSubType, KV3_TYPEEX_DOUBLE, KV3_SUBTYPE_FLOAT32 );
|
|
break;
|
|
case KV3_TYPEEX_ARRAY_FLOAT64:
|
|
AllocArray<float64>( pSrc->m_nNumArrayElements, pSrc->m_f64Array, KV3_ARRAY_ALLOC_NORMAL, KV3_TYPEEX_INVALID, KV3_TYPEEX_ARRAY_FLOAT64, eSrcSubType, KV3_TYPEEX_DOUBLE, KV3_SUBTYPE_FLOAT64 );
|
|
break;
|
|
case KV3_TYPEEX_ARRAY_INT16:
|
|
AllocArray<int16>( pSrc->m_nNumArrayElements, pSrc->m_i16Array, KV3_ARRAY_ALLOC_NORMAL, KV3_TYPEEX_ARRAY_INT16_SHORT, KV3_TYPEEX_ARRAY_INT16, eSrcSubType, KV3_TYPEEX_INT, KV3_SUBTYPE_INT16 );
|
|
break;
|
|
case KV3_TYPEEX_ARRAY_INT32:
|
|
AllocArray<int32>( pSrc->m_nNumArrayElements, pSrc->m_i32Array, KV3_ARRAY_ALLOC_NORMAL, KV3_TYPEEX_INVALID, KV3_TYPEEX_ARRAY_INT32, eSrcSubType, KV3_TYPEEX_INT, KV3_SUBTYPE_INT32 );
|
|
break;
|
|
case KV3_TYPEEX_ARRAY_UINT8_SHORT:
|
|
AllocArray<uint8>( pSrc->m_nNumArrayElements, pSrc->m_u8ArrayShort, KV3_ARRAY_ALLOC_NORMAL, KV3_TYPEEX_ARRAY_UINT8_SHORT, KV3_TYPEEX_INVALID, eSrcSubType, KV3_TYPEEX_UINT, KV3_SUBTYPE_UINT8 );
|
|
break;
|
|
case KV3_TYPEEX_ARRAY_INT16_SHORT:
|
|
AllocArray<int16>( pSrc->m_nNumArrayElements, pSrc->m_i16ArrayShort, KV3_ARRAY_ALLOC_NORMAL, KV3_TYPEEX_ARRAY_INT16_SHORT, KV3_TYPEEX_ARRAY_INT16, eSrcSubType, KV3_TYPEEX_INT, KV3_SUBTYPE_INT16 );
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case KV3_TYPE_TABLE:
|
|
{
|
|
PrepareForType( KV3_TYPEEX_TABLE, KV3_SUBTYPE_TABLE );
|
|
m_pTable->CopyFrom( pSrc->m_pTable );
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
m_SubType = eSrcSubType;
|
|
m_nFlags = pSrc->m_nFlags;
|
|
}
|
|
|
|
KeyValues3& KeyValues3::operator=( const KeyValues3& src )
|
|
{
|
|
if ( this == &src )
|
|
return *this;
|
|
|
|
CopyFrom( &src );
|
|
|
|
return *this;
|
|
}
|
|
|
|
CKeyValues3Array::CKeyValues3Array( int cluster_elem ) :
|
|
m_nClusterElement( cluster_elem )
|
|
{
|
|
}
|
|
|
|
CKeyValues3ArrayCluster* CKeyValues3Array::GetCluster() const
|
|
{
|
|
if ( m_nClusterElement == -1 )
|
|
return NULL;
|
|
|
|
return GET_OUTER( CKeyValues3ArrayCluster, m_Elements[ m_nClusterElement ] );
|
|
}
|
|
|
|
CKeyValues3Context* CKeyValues3Array::GetContext() const
|
|
{
|
|
CKeyValues3ArrayCluster* cluster = GetCluster();
|
|
|
|
if ( cluster )
|
|
return cluster->GetContext();
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
void CKeyValues3Array::SetCount( int count, KV3TypeEx_t type, KV3SubType_t subtype )
|
|
{
|
|
int nOldSize = m_Elements.Count();
|
|
|
|
CKeyValues3Context* context = GetContext();
|
|
|
|
for ( int i = count; i < nOldSize; ++i )
|
|
{
|
|
if ( context )
|
|
context->FreeKV( m_Elements[ i ] );
|
|
else
|
|
delete m_Elements[ i ];
|
|
}
|
|
|
|
m_Elements.SetCount( count );
|
|
|
|
for ( int i = nOldSize; i < count; ++i )
|
|
{
|
|
if ( context )
|
|
m_Elements[ i ] = context->AllocKV( type, subtype );
|
|
else
|
|
m_Elements[ i ] = new KeyValues3( type, subtype );
|
|
}
|
|
}
|
|
|
|
KeyValues3** CKeyValues3Array::InsertBeforeGetPtr( int elem, int num )
|
|
{
|
|
KeyValues3** kv = m_Elements.InsertBeforeGetPtr( elem, num );
|
|
|
|
CKeyValues3Context* context = GetContext();
|
|
|
|
for ( int i = 0; i < num; ++i )
|
|
{
|
|
if ( context )
|
|
m_Elements[ elem + i ] = context->AllocKV();
|
|
else
|
|
m_Elements[ elem + i ] = new KeyValues3;
|
|
}
|
|
|
|
return kv;
|
|
}
|
|
|
|
void CKeyValues3Array::CopyFrom( const CKeyValues3Array* pSrc )
|
|
{
|
|
int nNewSize = pSrc->m_Elements.Count();
|
|
|
|
SetCount( nNewSize );
|
|
|
|
for ( int i = 0; i < nNewSize; ++i )
|
|
*m_Elements[i] = *pSrc->m_Elements[i];
|
|
}
|
|
|
|
void CKeyValues3Array::RemoveMultiple( int elem, int num )
|
|
{
|
|
CKeyValues3Context* context = GetContext();
|
|
|
|
for ( int i = 0; i < num; ++i )
|
|
{
|
|
if ( context )
|
|
context->FreeKV( m_Elements[ elem + i ] );
|
|
else
|
|
delete m_Elements[ elem + i ];
|
|
}
|
|
|
|
m_Elements.RemoveMultiple( elem, num );
|
|
}
|
|
|
|
void CKeyValues3Array::Purge( bool bClearingContext )
|
|
{
|
|
CKeyValues3Context* context = GetContext();
|
|
|
|
FOR_EACH_LEANVEC( m_Elements, iter )
|
|
{
|
|
if ( context )
|
|
{
|
|
if ( !bClearingContext )
|
|
context->FreeKV( m_Elements[ iter ] );
|
|
}
|
|
else
|
|
{
|
|
delete m_Elements[ iter ];
|
|
}
|
|
}
|
|
|
|
m_Elements.Purge();
|
|
}
|
|
|
|
CKeyValues3Table::CKeyValues3Table( int cluster_elem ) :
|
|
m_nClusterElement( cluster_elem ),
|
|
m_pFastSearch( NULL ),
|
|
m_bHasBadNames( false )
|
|
{
|
|
}
|
|
|
|
CKeyValues3TableCluster* CKeyValues3Table::GetCluster() const
|
|
{
|
|
if ( m_nClusterElement == -1 )
|
|
return NULL;
|
|
|
|
return GET_OUTER( CKeyValues3TableCluster, m_Elements[ m_nClusterElement ] );
|
|
}
|
|
|
|
CKeyValues3Context* CKeyValues3Table::GetContext() const
|
|
{
|
|
CKeyValues3TableCluster* cluster = GetCluster();
|
|
|
|
if ( cluster )
|
|
return cluster->GetContext();
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
void CKeyValues3Table::EnableFastSearch()
|
|
{
|
|
if ( m_pFastSearch )
|
|
m_pFastSearch->m_member_ids.RemoveAll();
|
|
else
|
|
m_pFastSearch = new kv3tablefastsearch_t;
|
|
|
|
for ( int i = 0; i < m_Hashes.Count(); ++i )
|
|
m_pFastSearch->m_member_ids.Insert( m_Hashes[i], i );
|
|
|
|
m_pFastSearch->m_ignore = false;
|
|
m_pFastSearch->m_ignores_counter = 0;
|
|
}
|
|
|
|
KV3MemberId_t CKeyValues3Table::FindMember( const KeyValues3* kv ) const
|
|
{
|
|
for ( int i = 0; i < m_Hashes.Count(); ++i )
|
|
{
|
|
if ( m_Members[i] == kv )
|
|
return i;
|
|
}
|
|
|
|
return KV3_INVALID_MEMBER;
|
|
}
|
|
|
|
KV3MemberId_t CKeyValues3Table::FindMember( const CKV3MemberName &name )
|
|
{
|
|
bool bFastSearch = false;
|
|
|
|
if ( m_pFastSearch )
|
|
{
|
|
if ( m_pFastSearch->m_ignore )
|
|
{
|
|
if ( ++m_pFastSearch->m_ignores_counter > 4 )
|
|
{
|
|
EnableFastSearch();
|
|
bFastSearch = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bFastSearch = true;
|
|
}
|
|
}
|
|
|
|
if ( bFastSearch )
|
|
{
|
|
UtlHashHandle_t h = m_pFastSearch->m_member_ids.Find( name.GetHashCode() );
|
|
|
|
if ( h != m_pFastSearch->m_member_ids.InvalidHandle() )
|
|
return m_pFastSearch->m_member_ids[ h ];
|
|
}
|
|
else
|
|
{
|
|
for ( int i = 0; i < m_Hashes.Count(); ++i )
|
|
{
|
|
if ( m_Hashes[i] == name.GetHashCode() )
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return KV3_INVALID_MEMBER;
|
|
}
|
|
|
|
KV3MemberId_t CKeyValues3Table::CreateMember( const CKV3MemberName &name )
|
|
{
|
|
if ( m_Hashes.Count() >= 128 && !m_pFastSearch )
|
|
EnableFastSearch();
|
|
|
|
*m_Hashes.AddToTailGetPtr() = name.GetHashCode();
|
|
|
|
KV3MemberId_t memberId = m_Hashes.Count() - 1;
|
|
|
|
CKeyValues3Context* context = GetContext();
|
|
|
|
if ( context )
|
|
{
|
|
*m_Members.AddToTailGetPtr() = context->AllocKV();
|
|
*m_Names.AddToTailGetPtr() = context->AllocString( name.GetString() );
|
|
}
|
|
else
|
|
{
|
|
*m_Members.AddToTailGetPtr() = new KeyValues3;
|
|
*m_Names.AddToTailGetPtr() = strdup( name.GetString() );
|
|
}
|
|
|
|
m_IsExternalName.AddToTail( false );
|
|
|
|
if ( m_pFastSearch && !m_pFastSearch->m_ignore )
|
|
m_pFastSearch->m_member_ids.Insert( name.GetHashCode(), memberId );
|
|
|
|
return memberId;
|
|
}
|
|
|
|
void CKeyValues3Table::CopyFrom( const CKeyValues3Table* pSrc )
|
|
{
|
|
int nNewSize = pSrc->m_Hashes.Count();
|
|
|
|
RemoveAll( nNewSize );
|
|
|
|
m_Hashes.SetCount( nNewSize );
|
|
m_Members.SetCount( nNewSize );
|
|
m_Names.SetCount( nNewSize );
|
|
m_IsExternalName.SetCount( nNewSize );
|
|
|
|
CKeyValues3Context* context = GetContext();
|
|
|
|
for ( int i = 0; i < nNewSize; ++i )
|
|
{
|
|
m_Hashes[i] = pSrc->m_Hashes[i];
|
|
|
|
if ( context )
|
|
{
|
|
m_Members[i] = context->AllocKV();
|
|
m_Names[i] = context->AllocString( pSrc->m_Names[i] );
|
|
}
|
|
else
|
|
{
|
|
m_Members[i] = new KeyValues3;
|
|
m_Names[i] = strdup( pSrc->m_Names[i] );
|
|
}
|
|
|
|
m_IsExternalName[i] = false;
|
|
|
|
*m_Members[i] = *pSrc->m_Members[i];
|
|
}
|
|
|
|
if ( nNewSize >= 128 )
|
|
EnableFastSearch();
|
|
}
|
|
|
|
void CKeyValues3Table::RemoveMember( KV3MemberId_t id )
|
|
{
|
|
CKeyValues3Context* context = GetContext();
|
|
|
|
if ( context )
|
|
{
|
|
context->FreeKV( m_Members[ id ] );
|
|
}
|
|
else
|
|
{
|
|
delete m_Members[ id ];
|
|
free( (void*)m_Names[ id ] );
|
|
}
|
|
|
|
m_Hashes.Remove( id );
|
|
m_Members.Remove( id );
|
|
m_Names.Remove( id );
|
|
m_IsExternalName.Remove( id );
|
|
|
|
if ( m_pFastSearch )
|
|
{
|
|
m_pFastSearch->m_ignore = true;
|
|
m_pFastSearch->m_ignores_counter = 1;
|
|
}
|
|
}
|
|
|
|
void CKeyValues3Table::RemoveAll( int nAllocSize )
|
|
{
|
|
CKeyValues3Context* context = GetContext();
|
|
|
|
for ( int i = 0; i < m_Hashes.Count(); ++i )
|
|
{
|
|
if ( context )
|
|
{
|
|
context->FreeKV( m_Members[i] );
|
|
}
|
|
else
|
|
{
|
|
delete m_Members[i];
|
|
free( (void*)m_Names[i] );
|
|
}
|
|
}
|
|
|
|
m_Hashes.RemoveAll();
|
|
m_Members.RemoveAll();
|
|
m_Names.RemoveAll();
|
|
m_IsExternalName.RemoveAll();
|
|
|
|
if ( nAllocSize > 0 )
|
|
{
|
|
m_Hashes.EnsureCapacity( nAllocSize );
|
|
m_Members.EnsureCapacity( nAllocSize );
|
|
m_Names.EnsureCapacity( nAllocSize );
|
|
m_IsExternalName.EnsureCapacity( nAllocSize );
|
|
}
|
|
|
|
if ( m_pFastSearch )
|
|
{
|
|
if ( nAllocSize >= 128 )
|
|
{
|
|
m_pFastSearch->Clear();
|
|
}
|
|
else
|
|
{
|
|
delete m_pFastSearch;
|
|
m_pFastSearch = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CKeyValues3Table::Purge( bool bClearingContext )
|
|
{
|
|
CKeyValues3Context* context = GetContext();
|
|
|
|
for ( int i = 0; i < m_Hashes.Count(); ++i )
|
|
{
|
|
if ( context )
|
|
{
|
|
if ( !bClearingContext )
|
|
context->FreeKV( m_Members[i] );
|
|
}
|
|
else
|
|
{
|
|
delete m_Members[i];
|
|
free( (void*)m_Names[i] );
|
|
}
|
|
}
|
|
|
|
if ( m_pFastSearch )
|
|
delete m_pFastSearch;
|
|
m_pFastSearch = NULL;
|
|
|
|
m_Hashes.Purge();
|
|
m_Members.Purge();
|
|
m_Names.Purge();
|
|
m_IsExternalName.Purge();
|
|
}
|
|
|
|
CKeyValues3Cluster::CKeyValues3Cluster( CKeyValues3Context* context ) :
|
|
m_pContext( context ),
|
|
m_nAllocatedElements( 0 ),
|
|
m_pMetaData( NULL ),
|
|
m_pNextFree( NULL )
|
|
{
|
|
memset( &m_KeyValues, 0, sizeof( m_KeyValues ) );
|
|
}
|
|
|
|
CKeyValues3Cluster::~CKeyValues3Cluster()
|
|
{
|
|
FreeMetaData();
|
|
}
|
|
|
|
#include "tier0/memdbgoff.h"
|
|
|
|
KeyValues3* CKeyValues3Cluster::Alloc( KV3TypeEx_t type, KV3SubType_t subtype )
|
|
{
|
|
Assert( IsFree() );
|
|
int element = KV3Helpers::BitScanFwd( ~m_nAllocatedElements );
|
|
m_nAllocatedElements |= ( 1ull << element );
|
|
KeyValues3* kv = &m_KeyValues[ element ];
|
|
new( kv ) KeyValues3( element, type, subtype );
|
|
return kv;
|
|
}
|
|
|
|
#include "tier0/memdbgon.h"
|
|
|
|
void CKeyValues3Cluster::Free( int element )
|
|
{
|
|
Assert( element >= 0 && element < KV3_CLUSTER_MAX_ELEMENTS );
|
|
KeyValues3* kv = &m_KeyValues[ element ];
|
|
Destruct( kv );
|
|
memset( (void *)kv, 0, sizeof( KeyValues3 ) );
|
|
m_nAllocatedElements &= ~( 1ull << element );
|
|
}
|
|
|
|
void CKeyValues3Cluster::PurgeElements()
|
|
{
|
|
uint64 mask = 1;
|
|
for ( int i = 0; i < KV3_CLUSTER_MAX_ELEMENTS; ++i )
|
|
{
|
|
if ( ( m_nAllocatedElements & mask ) != 0 )
|
|
m_KeyValues[ i ].OnClearContext();
|
|
mask <<= 1;
|
|
}
|
|
|
|
m_nAllocatedElements = 0;
|
|
}
|
|
|
|
void CKeyValues3Cluster::Purge()
|
|
{
|
|
PurgeElements();
|
|
|
|
if ( m_pMetaData )
|
|
{
|
|
for ( int i = 0; i < KV3_CLUSTER_MAX_ELEMENTS; ++i )
|
|
m_pMetaData->m_elements[ i ].Purge();
|
|
}
|
|
}
|
|
|
|
void CKeyValues3Cluster::Clear()
|
|
{
|
|
PurgeElements();
|
|
|
|
if ( m_pMetaData )
|
|
{
|
|
for ( int i = 0; i < KV3_CLUSTER_MAX_ELEMENTS; ++i )
|
|
m_pMetaData->m_elements[ i ].Clear();
|
|
}
|
|
}
|
|
|
|
void CKeyValues3Cluster::EnableMetaData( bool bEnable )
|
|
{
|
|
if ( bEnable )
|
|
{
|
|
if ( !m_pMetaData )
|
|
m_pMetaData = new kv3metadata_t;
|
|
}
|
|
else
|
|
{
|
|
FreeMetaData();
|
|
}
|
|
}
|
|
|
|
void CKeyValues3Cluster::FreeMetaData()
|
|
{
|
|
if ( m_pMetaData )
|
|
delete m_pMetaData;
|
|
m_pMetaData = NULL;
|
|
}
|
|
|
|
KV3MetaData_t* CKeyValues3Cluster::GetMetaData( int element ) const
|
|
{
|
|
Assert( element >= 0 && element < KV3_CLUSTER_MAX_ELEMENTS );
|
|
|
|
if ( !m_pMetaData )
|
|
return NULL;
|
|
|
|
return &m_pMetaData->m_elements[ element ];
|
|
}
|
|
|
|
CKeyValues3ContextBase::CKeyValues3ContextBase( CKeyValues3Context* context ) :
|
|
m_pContext( context ),
|
|
m_KV3BaseCluster( context ),
|
|
m_pKV3FreeCluster( &m_KV3BaseCluster ),
|
|
m_pArrayFreeCluster( NULL ),
|
|
m_pTableFreeCluster( NULL ),
|
|
m_pParsingErrorListener( NULL )
|
|
{
|
|
}
|
|
|
|
CKeyValues3ContextBase::~CKeyValues3ContextBase()
|
|
{
|
|
Purge();
|
|
}
|
|
|
|
void CKeyValues3ContextBase::Clear()
|
|
{
|
|
m_BinaryData.Clear();
|
|
|
|
m_KV3BaseCluster.Clear();
|
|
m_KV3BaseCluster.SetNextFree( NULL );
|
|
m_pKV3FreeCluster = &m_KV3BaseCluster;
|
|
|
|
FOR_EACH_LEANVEC( m_KV3Clusters, iter )
|
|
{
|
|
m_KV3Clusters[ iter ]->Clear();
|
|
m_KV3Clusters[ iter ]->SetNextFree( m_pKV3FreeCluster );
|
|
m_pKV3FreeCluster = m_KV3Clusters[ iter ];
|
|
}
|
|
|
|
m_pArrayFreeCluster = NULL;
|
|
|
|
FOR_EACH_LEANVEC( m_ArrayClusters, iter )
|
|
{
|
|
m_ArrayClusters[ iter ]->Clear();
|
|
m_ArrayClusters[ iter ]->SetNextFree( m_pArrayFreeCluster );
|
|
m_pArrayFreeCluster = m_ArrayClusters[ iter ];
|
|
}
|
|
|
|
m_pTableFreeCluster = NULL;
|
|
|
|
FOR_EACH_LEANVEC( m_TableClusters, iter )
|
|
{
|
|
m_TableClusters[ iter ]->Clear();
|
|
m_TableClusters[ iter ]->SetNextFree( m_pTableFreeCluster );
|
|
m_pTableFreeCluster = m_TableClusters[ iter ];
|
|
}
|
|
|
|
m_Symbols.RemoveAll();
|
|
|
|
m_bFormatConverted = false;
|
|
}
|
|
|
|
void CKeyValues3ContextBase::Purge()
|
|
{
|
|
m_BinaryData.Purge();
|
|
|
|
m_KV3BaseCluster.Purge();
|
|
m_KV3BaseCluster.SetNextFree( NULL );
|
|
m_pKV3FreeCluster = &m_KV3BaseCluster;
|
|
|
|
FOR_EACH_LEANVEC( m_KV3Clusters, iter )
|
|
{
|
|
m_KV3Clusters[ iter ]->Purge();
|
|
delete m_KV3Clusters[ iter ];
|
|
}
|
|
|
|
m_KV3Clusters.Purge();
|
|
|
|
FOR_EACH_LEANVEC( m_ArrayClusters, iter )
|
|
{
|
|
m_ArrayClusters[ iter ]->Purge();
|
|
delete m_ArrayClusters[ iter ];
|
|
}
|
|
|
|
m_pArrayFreeCluster = NULL;
|
|
m_ArrayClusters.Purge();
|
|
|
|
FOR_EACH_LEANVEC( m_TableClusters, iter )
|
|
{
|
|
m_TableClusters[ iter ]->Purge();
|
|
delete m_TableClusters[ iter ];
|
|
}
|
|
|
|
m_pTableFreeCluster = NULL;
|
|
m_TableClusters.Purge();
|
|
|
|
m_Symbols.Purge();
|
|
|
|
m_bFormatConverted = false;
|
|
}
|
|
|
|
CKeyValues3Context::CKeyValues3Context( bool bNoRoot ) : BaseClass( this )
|
|
{
|
|
if ( bNoRoot )
|
|
{
|
|
m_bRootAvailabe = false;
|
|
}
|
|
else
|
|
{
|
|
m_bRootAvailabe = true;
|
|
m_KV3BaseCluster.Alloc();
|
|
}
|
|
|
|
m_bMetaDataEnabled = false;
|
|
m_bFormatConverted = false;
|
|
}
|
|
|
|
CKeyValues3Context::~CKeyValues3Context()
|
|
{
|
|
}
|
|
|
|
void CKeyValues3Context::Clear()
|
|
{
|
|
BaseClass::Clear();
|
|
|
|
if ( m_bRootAvailabe )
|
|
m_KV3BaseCluster.Alloc();
|
|
}
|
|
|
|
void CKeyValues3Context::Purge()
|
|
{
|
|
BaseClass::Purge();
|
|
|
|
if ( m_bRootAvailabe )
|
|
m_KV3BaseCluster.Alloc();
|
|
}
|
|
|
|
KeyValues3* CKeyValues3Context::Root()
|
|
{
|
|
if ( !m_bRootAvailabe )
|
|
{
|
|
Plat_FatalErrorFunc( "FATAL: %s called on a pool context (no root available)\n", __FUNCTION__ );
|
|
DebuggerBreak();
|
|
}
|
|
|
|
return m_KV3BaseCluster.Head();
|
|
}
|
|
|
|
const char* CKeyValues3Context::AllocString( const char* pString )
|
|
{
|
|
return m_Symbols.AddString( pString ).String();
|
|
}
|
|
|
|
void CKeyValues3Context::EnableMetaData( bool bEnable )
|
|
{
|
|
if ( bEnable != m_bMetaDataEnabled )
|
|
{
|
|
m_KV3BaseCluster.EnableMetaData( bEnable );
|
|
|
|
for ( int i = 0; i < m_KV3Clusters.Count(); ++i )
|
|
m_KV3Clusters[ i ]->EnableMetaData( bEnable );
|
|
|
|
m_bMetaDataEnabled = bEnable;
|
|
}
|
|
}
|
|
|
|
void CKeyValues3Context::CopyMetaData( KV3MetaData_t* pDest, const KV3MetaData_t* pSrc )
|
|
{
|
|
pDest->m_nLine = pSrc->m_nLine;
|
|
pDest->m_nColumn = pSrc->m_nColumn;
|
|
pDest->m_nFlags = pSrc->m_nFlags;
|
|
pDest->m_sName = m_Symbols.AddString( pSrc->m_sName.String() );
|
|
|
|
pDest->m_Comments.Purge();
|
|
pDest->m_Comments.EnsureCapacity( pSrc->m_Comments.Count() );
|
|
|
|
FOR_EACH_MAP_FAST( pSrc->m_Comments, iter )
|
|
{
|
|
CBufferStringGrowable<8> buff;
|
|
buff.Insert( 0, pSrc->m_Comments[ iter ].Get() );
|
|
|
|
pDest->m_Comments.Insert( pSrc->m_Comments.Key( iter ), buff );
|
|
}
|
|
}
|
|
|
|
KeyValues3* CKeyValues3Context::AllocKV( KV3TypeEx_t type, KV3SubType_t subtype )
|
|
{
|
|
KeyValues3* kv;
|
|
|
|
if ( m_pKV3FreeCluster )
|
|
{
|
|
kv = m_pKV3FreeCluster->Alloc( type, subtype );
|
|
|
|
if ( !m_pKV3FreeCluster->IsFree() )
|
|
{
|
|
CKeyValues3Cluster* cluster = m_pKV3FreeCluster->GetNextFree();
|
|
m_pKV3FreeCluster->SetNextFree( NULL );
|
|
m_pKV3FreeCluster = cluster;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CKeyValues3Cluster* cluster = new CKeyValues3Cluster( m_pContext );
|
|
cluster->EnableMetaData( m_bMetaDataEnabled );
|
|
*m_KV3Clusters.AddToTailGetPtr() = cluster;
|
|
m_pKV3FreeCluster = cluster;
|
|
kv = cluster->Alloc( type, subtype );
|
|
}
|
|
|
|
return kv;
|
|
}
|
|
|
|
void CKeyValues3Context::FreeKV( KeyValues3* kv )
|
|
{
|
|
CKeyValues3Context* context;
|
|
KV3MetaData_t* metadata = kv->GetMetaData( &context );
|
|
|
|
Assert( context == m_pContext );
|
|
|
|
if ( metadata )
|
|
metadata->Clear();
|
|
|
|
Free<KeyValues3, CKeyValues3Cluster, KV3ClustersVec_t>( kv, &m_KV3BaseCluster, m_pKV3FreeCluster, m_KV3Clusters );
|
|
}
|