2023-11-18 22:19:28 +03:00
# include "keyvalues3.h"
// memdbgon must be the last include file in a .cpp file!!!
# include "tier0/memdbgon.h"
2023-12-23 20:03:58 +03:00
// Nasty hack to redefine gcc's offsetof which doesn't like GET_OUTER macro
# ifdef COMPILER_GCC
2023-11-18 22:19:28 +03:00
# undef offsetof
# define offsetof(s,m) (size_t)&(((s *)0)->m)
# endif
KeyValues3 : : KeyValues3 ( KV3TypeEx_t type , KV3SubType_t subtype ) :
2025-01-01 22:36:06 +03:00
KeyValues3 ( - 1 , type , subtype )
2023-11-18 22:19:28 +03:00
{
}
KeyValues3 : : KeyValues3 ( int cluster_elem , KV3TypeEx_t type , KV3SubType_t subtype ) :
2025-01-01 22:36:06 +03:00
m_bExternalStorage ( true ) ,
2023-11-18 22:19:28 +03:00
m_TypeEx ( type ) ,
m_SubType ( subtype ) ,
m_nFlags ( 0 ) ,
2025-01-01 22:36:06 +03:00
m_nClusterElement ( ( uint16 ) - 1 ) ,
m_nNumArrayElements ( 0 ) ,
m_nReserved ( 0 )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
SetClusterElement ( cluster_elem ) ;
2023-11-18 22:19:28 +03:00
ResolveUnspecified ( ) ;
Alloc ( ) ;
}
KeyValues3 : : ~ KeyValues3 ( )
{
Free ( ) ;
} ;
2025-01-01 22:36:06 +03:00
void KeyValues3 : : Alloc ( int initial_size , Data_t data , int preallocated_size , bool should_free )
2023-11-18 22:19:28 +03:00
{
switch ( GetTypeEx ( ) )
{
case KV3_TYPEEX_ARRAY :
{
2025-01-01 22:36:06 +03:00
if ( preallocated_size < = 0 )
{
m_Data . m_pArray = AllocArray ( ) ;
m_bFreeArrayMemory = true ;
}
2023-11-18 22:19:28 +03:00
else
2025-01-01 22:36:06 +03:00
{
AllocArrayInPlace ( initial_size , data , preallocated_size , should_free ) ;
}
2023-11-18 22:19:28 +03:00
break ;
}
case KV3_TYPEEX_TABLE :
{
2025-01-01 22:36:06 +03:00
if ( preallocated_size < = 0 )
{
m_Data . m_pTable = AllocTable ( ) ;
m_bFreeArrayMemory = true ;
}
2023-11-18 22:19:28 +03:00
else
2025-01-01 22:36:06 +03:00
{
AllocTableInPlace ( initial_size , data , preallocated_size , should_free ) ;
}
2023-11-18 22:19:28 +03:00
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 ;
2025-01-01 22:36:06 +03:00
m_Data . m_pMemory = NULL ;
2023-11-18 22:19:28 +03:00
break ;
}
default :
break ;
}
}
2025-01-01 22:36:06 +03:00
void KeyValues3 : : AllocArrayInPlace ( int initial_size , Data_t data , int preallocated_size , bool should_free )
{
int bytes_needed = MAX ( CKeyValues3Array : : TotalSizeOf ( 0 ) , CKeyValues3Array : : TotalSizeOf ( initial_size ) ) ;
if ( bytes_needed > preallocated_size )
{
Plat_FatalErrorFunc ( " KeyValues3: pre-allocated array memory is too small for %u elements (%u bytes available, %u bytes needed) \n " , initial_size , preallocated_size , bytes_needed ) ;
DebuggerBreak ( ) ;
}
Construct ( data . m_pArray , - 1 , initial_size ) ;
m_Data . m_pArray = data . m_pArray ;
m_bFreeArrayMemory = should_free ;
}
void KeyValues3 : : AllocTableInPlace ( int initial_size , Data_t data , int preallocated_size , bool should_free )
{
int bytes_needed = MAX ( CKeyValues3Array : : TotalSizeOf ( 0 ) , CKeyValues3Array : : TotalSizeOf ( initial_size ) ) ;
if ( bytes_needed > preallocated_size )
{
Plat_FatalErrorFunc ( " KeyValues3: pre-allocated table memory is too small for %u members (%u bytes available, %u bytes needed) \n " , initial_size , preallocated_size , bytes_needed ) ;
DebuggerBreak ( ) ;
}
Construct ( data . m_pTable , - 1 , initial_size ) ;
m_Data . m_pTable = data . m_pTable ;
m_bFreeArrayMemory = should_free ;
}
CKeyValues3Array * KeyValues3 : : AllocArray ( int initial_size )
{
auto context = GetContext ( ) ;
if ( context )
{
auto arr = context - > AllocArray ( initial_size ) ;
if ( arr )
return arr ;
}
return AllocateOnHeap < CKeyValues3Array > ( initial_size ) ;
}
CKeyValues3Table * KeyValues3 : : AllocTable ( int initial_size )
{
auto context = GetContext ( ) ;
if ( context )
{
auto table = context - > AllocTable ( initial_size ) ;
if ( table )
return table ;
}
return AllocateOnHeap < CKeyValues3Table > ( initial_size ) ;
}
void KeyValues3 : : FreeArray ( CKeyValues3Array * element , bool clearing_context )
{
if ( ! element )
return ;
element - > PurgeContent ( this , clearing_context ) ;
if ( ! m_bFreeArrayMemory )
{
Destruct ( element ) ;
}
else
{
auto context = GetContext ( ) ;
bool raw_allocated = context & & context - > IsArrayRawAllocated ( element ) ;
if ( ! raw_allocated & & element - > GetClusterElement ( ) < 0 )
{
FreeOnHeap ( element ) ;
}
else if ( ! clearing_context )
{
if ( ! raw_allocated )
context - > FreeArray ( element ) ;
else
Destruct ( element ) ;
}
}
}
void KeyValues3 : : FreeTable ( CKeyValues3Table * element , bool clearing_context )
{
if ( ! element )
return ;
element - > PurgeContent ( this , clearing_context ) ;
if ( ! m_bFreeArrayMemory )
{
Destruct ( element ) ;
}
else
{
auto context = GetContext ( ) ;
bool raw_allocated = context & & context - > IsTableRawAllocated ( element ) ;
if ( ! raw_allocated & & element - > GetClusterElement ( ) < 0 )
{
FreeOnHeap ( element ) ;
}
else if ( ! clearing_context )
{
if ( ! raw_allocated )
context - > FreeTable ( element ) ;
else
Destruct ( element ) ;
}
}
}
KeyValues3 * KeyValues3 : : AllocMember ( KV3TypeEx_t type , KV3SubType_t subtype )
{
auto context = GetContext ( ) ;
if ( context )
return context - > AllocKV ( type , subtype ) ;
else
return new KeyValues3 ( type , subtype ) ;
}
void KeyValues3 : : FreeMember ( KeyValues3 * member )
{
auto context = GetContext ( ) ;
if ( context )
{
auto cluster = member - > GetCluster ( ) ;
cluster - > PurgeMetaData ( cluster - > GetNodeIndex ( member ) ) ;
context - > FreeKV ( member ) ;
}
else
{
delete member ;
}
}
2023-11-18 22:19:28 +03:00
void KeyValues3 : : Free ( bool bClearingContext )
{
switch ( GetTypeEx ( ) )
{
case KV3_TYPEEX_STRING :
{
2025-01-01 22:36:06 +03:00
free ( ( void * ) m_Data . m_pString ) ;
m_Data . m_pString = nullptr ;
2023-11-18 22:19:28 +03:00
break ;
}
case KV3_TYPEEX_BINARY_BLOB :
{
2025-01-01 22:36:06 +03:00
if ( m_Data . m_pBinaryBlob )
free ( m_Data . m_pBinaryBlob ) ;
m_Data . m_pBinaryBlob = nullptr ;
2023-11-18 22:19:28 +03:00
break ;
}
case KV3_TYPEEX_BINARY_BLOB_EXTERN :
{
2025-01-01 22:36:06 +03:00
if ( m_Data . m_pBinaryBlob )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
if ( m_Data . m_pBinaryBlob - > m_bFreeMemory )
free ( ( void * ) m_Data . m_pBinaryBlob - > m_pubData ) ;
free ( m_Data . m_pBinaryBlob ) ;
2023-11-18 22:19:28 +03:00
}
2025-01-01 22:36:06 +03:00
m_Data . m_pBinaryBlob = nullptr ;
2023-11-18 22:19:28 +03:00
break ;
}
case KV3_TYPEEX_ARRAY :
{
2025-01-01 22:36:06 +03:00
FreeArray ( m_Data . m_pArray ) ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
m_bFreeArrayMemory = false ;
m_Data . m_pArray = nullptr ;
2023-11-18 22:19:28 +03:00
break ;
}
case KV3_TYPEEX_TABLE :
{
2025-01-01 22:36:06 +03:00
FreeTable ( m_Data . m_pTable ) ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
m_bFreeArrayMemory = false ;
m_Data . m_pTable = nullptr ;
2023-11-18 22:19:28 +03:00
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 )
2025-01-01 22:36:06 +03:00
free ( m_Data . m_pMemory ) ;
2023-11-18 22:19:28 +03:00
m_bFreeArrayMemory = false ;
m_nNumArrayElements = 0 ;
2025-01-01 22:36:06 +03:00
m_Data . m_nMemory = 0 ;
2023-11-18 22:19:28 +03:00
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 ;
Alloc ( ) ;
}
m_SubType = subtype ;
}
void KeyValues3 : : OnClearContext ( )
{
Free ( true ) ;
m_TypeEx = KV3_TYPEEX_NULL ;
2025-01-01 22:36:06 +03:00
m_Data . m_nMemory = 0 ;
2023-11-18 22:19:28 +03:00
}
CKeyValues3Cluster * KeyValues3 : : GetCluster ( ) const
{
if ( m_bExternalStorage )
return NULL ;
2025-01-01 22:36:06 +03:00
return GET_OUTER ( CKeyValues3Cluster , m_Values [ m_nClusterElement ] ) ;
2023-11-18 22:19:28 +03:00
}
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 :
2025-01-01 22:36:06 +03:00
return m_Data . m_pString ;
2023-11-18 22:19:28 +03:00
case KV3_TYPEEX_STRING_SHORT :
2025-01-01 22:36:06 +03:00
return m_Data . m_szStringShort ;
2023-11-18 22:19:28 +03:00
default :
return defaultValue ;
}
}
void KeyValues3 : : SetString ( const char * pString , KV3SubType_t subtype )
{
if ( ! pString )
pString = " " ;
2025-01-01 22:36:06 +03:00
if ( strlen ( pString ) < sizeof ( m_Data . m_szStringShort ) )
2023-11-18 22:19:28 +03:00
{
PrepareForType ( KV3_TYPEEX_STRING_SHORT , subtype ) ;
2025-01-01 22:36:06 +03:00
V_strncpy ( m_Data . m_szStringShort , pString , sizeof ( m_Data . m_szStringShort ) ) ;
2023-11-18 22:19:28 +03:00
}
else
{
PrepareForType ( KV3_TYPEEX_STRING , subtype ) ;
2025-01-01 22:36:06 +03:00
m_Data . m_pString = strdup ( pString ) ;
2023-11-18 22:19:28 +03:00
}
}
void KeyValues3 : : SetStringExternal ( const char * pString , KV3SubType_t subtype )
{
2025-01-01 22:36:06 +03:00
if ( strlen ( pString ) < sizeof ( m_Data . m_szStringShort ) )
2023-11-18 22:19:28 +03:00
{
PrepareForType ( KV3_TYPEEX_STRING_SHORT , subtype ) ;
2025-01-01 22:36:06 +03:00
V_strncpy ( m_Data . m_szStringShort , pString , sizeof ( m_Data . m_szStringShort ) ) ;
2023-11-18 22:19:28 +03:00
}
else
{
PrepareForType ( KV3_TYPEEX_STRING_EXTERN , subtype ) ;
2025-01-01 22:36:06 +03:00
m_Data . m_pString = pString ;
2023-11-18 22:19:28 +03:00
}
}
const byte * KeyValues3 : : GetBinaryBlob ( ) const
{
switch ( GetTypeEx ( ) )
{
case KV3_TYPEEX_BINARY_BLOB :
2025-01-01 22:36:06 +03:00
return m_Data . m_pBinaryBlob ? m_Data . m_pBinaryBlob - > m_ubData : NULL ;
2023-11-18 22:19:28 +03:00
case KV3_TYPEEX_BINARY_BLOB_EXTERN :
2025-01-01 22:36:06 +03:00
return m_Data . m_pBinaryBlob ? m_Data . m_pBinaryBlob - > m_pubData : NULL ;
2023-11-18 22:19:28 +03:00
default :
return NULL ;
}
}
int KeyValues3 : : GetBinaryBlobSize ( ) const
{
2025-01-01 22:36:06 +03:00
if ( GetType ( ) ! = KV3_TYPE_BINARY_BLOB | | ! m_Data . m_pBinaryBlob )
2023-11-18 22:19:28 +03:00
return 0 ;
2025-01-01 22:36:06 +03:00
return ( int ) m_Data . m_pBinaryBlob - > m_nSize ;
2023-11-18 22:19:28 +03:00
}
void KeyValues3 : : SetToBinaryBlob ( const byte * blob , int size )
{
PrepareForType ( KV3_TYPEEX_BINARY_BLOB , KV3_SUBTYPE_BINARY_BLOB ) ;
if ( size > 0 )
{
2025-01-01 22:36:06 +03:00
m_Data . m_pBinaryBlob = ( KV3BinaryBlob_t * ) malloc ( sizeof ( size_t ) + size ) ;
m_Data . m_pBinaryBlob - > m_nSize = size ;
memcpy ( m_Data . m_pBinaryBlob - > m_ubData , blob , size ) ;
2023-11-18 22:19:28 +03:00
}
else
{
2025-01-01 22:36:06 +03:00
m_Data . m_pBinaryBlob = NULL ;
2023-11-18 22:19:28 +03:00
}
}
void KeyValues3 : : SetToBinaryBlobExternal ( const byte * blob , int size , bool free_mem )
{
PrepareForType ( KV3_TYPEEX_BINARY_BLOB_EXTERN , KV3_SUBTYPE_BINARY_BLOB ) ;
if ( size > 0 )
{
2025-01-01 22:36:06 +03:00
m_Data . m_pBinaryBlob = ( KV3BinaryBlob_t * ) malloc ( sizeof ( KV3BinaryBlob_t ) ) ;
m_Data . m_pBinaryBlob - > m_nSize = size ;
m_Data . m_pBinaryBlob - > m_pubData = blob ;
m_Data . m_pBinaryBlob - > m_bFreeMemory = free_mem ;
2023-11-18 22:19:28 +03:00
}
else
{
2025-01-01 22:36:06 +03:00
m_Data . m_pBinaryBlob = NULL ;
2023-11-18 22:19:28 +03:00
}
}
2023-12-23 20:03:58 +03:00
Color KeyValues3 : : GetColor ( const Color & defaultValue ) const
2023-11-18 22:19:28 +03:00
{
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 )
{
2023-12-23 20:03:58 +03:00
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 ) ;
2023-11-18 22:19:28 +03:00
}
int KeyValues3 : : GetArrayElementCount ( ) const
{
if ( GetType ( ) ! = KV3_TYPE_ARRAY )
return 0 ;
if ( GetTypeEx ( ) = = KV3_TYPEEX_ARRAY )
2025-01-01 22:36:06 +03:00
return m_Data . m_pArray - > Count ( ) ;
2023-11-18 22:19:28 +03:00
else
return m_nNumArrayElements ;
}
KeyValues3 * * KeyValues3 : : GetArrayBase ( )
{
2025-01-01 22:36:06 +03:00
if ( GetTypeEx ( ) ! = KV3_TYPEEX_ARRAY )
2023-11-18 22:19:28 +03:00
return NULL ;
2025-01-01 22:36:06 +03:00
return m_Data . m_pArray - > Base ( ) ;
2023-11-18 22:19:28 +03:00
}
KeyValues3 * KeyValues3 : : GetArrayElement ( int elem )
{
2025-01-01 22:36:06 +03:00
if ( GetTypeEx ( ) ! = KV3_TYPEEX_ARRAY )
2023-11-18 22:19:28 +03:00
return NULL ;
2025-01-01 22:36:06 +03:00
if ( elem < 0 | | elem > = m_Data . m_pArray - > Count ( ) )
2023-11-18 22:19:28 +03:00
return NULL ;
2025-01-01 22:36:06 +03:00
return m_Data . m_pArray - > Element ( elem ) ;
2023-11-18 22:19:28 +03:00
}
KeyValues3 * KeyValues3 : : InsertArrayElementBefore ( int elem )
{
2025-01-01 22:36:06 +03:00
if ( GetTypeEx ( ) ! = KV3_TYPEEX_ARRAY )
2023-11-18 22:19:28 +03:00
return NULL ;
2025-01-01 22:36:06 +03:00
return * m_Data . m_pArray - > InsertMultipleBefore ( this , elem , 1 ) ;
2023-11-18 22:19:28 +03:00
}
KeyValues3 * KeyValues3 : : AddArrayElementToTail ( )
{
2025-01-01 22:36:06 +03:00
if ( GetTypeEx ( ) ! = KV3_TYPEEX_ARRAY )
return NULL ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
return * m_Data . m_pArray - > InsertMultipleBefore ( this , m_Data . m_pArray - > Count ( ) , 1 ) ;
2023-11-18 22:19:28 +03:00
}
void KeyValues3 : : SetArrayElementCount ( int count , KV3TypeEx_t type , KV3SubType_t subtype )
{
2025-01-01 22:36:06 +03:00
if ( GetTypeEx ( ) ! = KV3_TYPEEX_ARRAY )
return ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
m_Data . m_pArray - > SetCount ( this , count , type , subtype ) ;
2023-11-18 22:19:28 +03:00
}
void KeyValues3 : : RemoveArrayElements ( int elem , int num )
{
2025-01-01 22:36:06 +03:00
if ( GetTypeEx ( ) ! = KV3_TYPEEX_ARRAY )
2023-11-18 22:19:28 +03:00
return ;
2025-01-01 22:36:06 +03:00
m_Data . m_pArray - > RemoveMultiple ( this , elem , num ) ;
2023-11-18 22:19:28 +03:00
}
void KeyValues3 : : NormalizeArray ( )
{
switch ( GetTypeEx ( ) )
{
case KV3_TYPEEX_ARRAY_FLOAT32 :
{
2025-01-01 22:36:06 +03:00
NormalizeArray < float32 > ( KV3_TYPEEX_DOUBLE , KV3_SUBTYPE_FLOAT32 , m_nNumArrayElements , m_Data . m_Array . m_f32 , m_bFreeArrayMemory ) ;
2023-11-18 22:19:28 +03:00
break ;
}
case KV3_TYPEEX_ARRAY_FLOAT64 :
{
2025-01-01 22:36:06 +03:00
NormalizeArray < float64 > ( KV3_TYPEEX_DOUBLE , KV3_SUBTYPE_FLOAT64 , m_nNumArrayElements , m_Data . m_Array . m_f64 , m_bFreeArrayMemory ) ;
2023-11-18 22:19:28 +03:00
break ;
}
case KV3_TYPEEX_ARRAY_INT16 :
{
2025-01-01 22:36:06 +03:00
NormalizeArray < int16 > ( KV3_TYPEEX_INT , KV3_SUBTYPE_INT16 , m_nNumArrayElements , m_Data . m_Array . m_i16 , m_bFreeArrayMemory ) ;
2023-11-18 22:19:28 +03:00
break ;
}
case KV3_TYPEEX_ARRAY_INT32 :
{
2025-01-01 22:36:06 +03:00
NormalizeArray < int32 > ( KV3_TYPEEX_INT , KV3_SUBTYPE_INT32 , m_nNumArrayElements , m_Data . m_Array . m_i32 , m_bFreeArrayMemory ) ;
2023-11-18 22:19:28 +03:00
break ;
}
case KV3_TYPEEX_ARRAY_UINT8_SHORT :
{
uint8 u8ArrayShort [ 8 ] ;
2025-01-01 22:36:06 +03:00
memcpy ( u8ArrayShort , m_Data . m_Array . m_u8Short , sizeof ( u8ArrayShort ) ) ;
2023-11-18 22:19:28 +03:00
NormalizeArray < uint8 > ( KV3_TYPEEX_UINT , KV3_SUBTYPE_UINT8 , m_nNumArrayElements , u8ArrayShort , false ) ;
break ;
}
case KV3_TYPEEX_ARRAY_INT16_SHORT :
{
int16 i16ArrayShort [ 4 ] ;
2025-01-01 22:36:06 +03:00
memcpy ( i16ArrayShort , m_Data . m_Array . m_u8Short , sizeof ( i16ArrayShort ) ) ;
2023-11-18 22:19:28 +03:00
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 :
{
2025-01-01 22:36:06 +03:00
src_size = m_Data . m_pArray - > Count ( ) ;
2023-11-18 22:19:28 +03:00
int count = MIN ( src_size , dest_size ) ;
2025-01-01 22:36:06 +03:00
KeyValues3 * * arr = m_Data . m_pArray - > Base ( ) ;
2023-11-18 22:19:28 +03:00
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 )
2025-01-01 22:36:06 +03:00
data [ i ] = ( int32 ) m_Data . m_Array . m_u8Short [ i ] ;
2023-11-18 22:19:28 +03:00
break ;
}
case KV3_TYPEEX_ARRAY_INT32 :
{
src_size = m_nNumArrayElements ;
int count = MIN ( src_size , dest_size ) ;
2025-01-01 22:36:06 +03:00
memcpy ( data , m_Data . m_Array . m_i32 , count * sizeof ( int32 ) ) ;
2023-11-18 22:19:28 +03:00
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 )
2025-01-01 22:36:06 +03:00
data [ i ] = ( int32 ) m_Data . m_Array . m_u8Short [ i ] ;
2023-11-18 22:19:28 +03:00
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 )
2025-01-01 22:36:06 +03:00
data [ i ] = ( int32 ) m_Data . m_Array . m_u8Short [ i ] ;
2023-11-18 22:19:28 +03:00
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 :
{
2025-01-01 22:36:06 +03:00
src_size = m_Data . m_pArray - > Count ( ) ;
2023-11-18 22:19:28 +03:00
int count = MIN ( src_size , dest_size ) ;
2025-01-01 22:36:06 +03:00
KeyValues3 * * arr = m_Data . m_pArray - > Base ( ) ;
2023-11-18 22:19:28 +03:00
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 ) ;
2025-01-01 22:36:06 +03:00
memcpy ( data , m_Data . m_Array . m_f32 , count * sizeof ( float32 ) ) ;
2023-11-18 22:19:28 +03:00
break ;
}
case KV3_TYPEEX_ARRAY_FLOAT64 :
{
src_size = m_nNumArrayElements ;
int count = MIN ( src_size , dest_size ) ;
for ( int i = 0 ; i < count ; + + i )
2025-01-01 22:36:06 +03:00
data [ i ] = ( float32 ) m_Data . m_Array . m_f64 [ i ] ;
2023-11-18 22:19:28 +03:00
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 ;
2025-01-01 22:36:06 +03:00
return m_Data . m_pTable - > GetMemberCount ( ) ;
2023-11-18 22:19:28 +03:00
}
2023-12-23 20:03:58 +03:00
KeyValues3 * KeyValues3 : : GetMember ( KV3MemberId_t id )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
if ( GetType ( ) ! = KV3_TYPE_TABLE | | id < 0 | | id > = m_Data . m_pTable - > GetMemberCount ( ) )
2023-11-18 22:19:28 +03:00
return NULL ;
2025-01-01 22:36:06 +03:00
return m_Data . m_pTable - > GetMember ( id ) ;
2023-11-18 22:19:28 +03:00
}
const char * KeyValues3 : : GetMemberName ( KV3MemberId_t id ) const
{
2025-01-01 22:36:06 +03:00
if ( GetType ( ) ! = KV3_TYPE_TABLE | | id < 0 | | id > = m_Data . m_pTable - > GetMemberCount ( ) )
2023-11-18 22:19:28 +03:00
return NULL ;
2025-01-01 22:36:06 +03:00
return m_Data . m_pTable - > GetMemberName ( id ) ;
2023-11-18 22:19:28 +03:00
}
CKV3MemberName KeyValues3 : : GetMemberNameEx ( KV3MemberId_t id ) const
{
2025-01-01 22:36:06 +03:00
if ( GetType ( ) ! = KV3_TYPE_TABLE | | id < 0 | | id > = m_Data . m_pTable - > GetMemberCount ( ) )
2023-11-18 22:19:28 +03:00
return CKV3MemberName ( ) ;
2025-01-01 22:36:06 +03:00
return CKV3MemberName ( m_Data . m_pTable - > GetMemberHash ( id ) , m_Data . m_pTable - > GetMemberName ( id ) ) ;
2023-11-18 22:19:28 +03:00
}
unsigned int KeyValues3 : : GetMemberHash ( KV3MemberId_t id ) const
{
2025-01-01 22:36:06 +03:00
if ( GetType ( ) ! = KV3_TYPE_TABLE | | id < 0 | | id > = m_Data . m_pTable - > GetMemberCount ( ) )
2023-11-18 22:19:28 +03:00
return 0 ;
2025-01-01 22:36:06 +03:00
return m_Data . m_pTable - > GetMemberHash ( id ) ;
2023-11-18 22:19:28 +03:00
}
2023-12-23 20:03:58 +03:00
KeyValues3 * KeyValues3 : : FindMember ( const CKV3MemberName & name , KeyValues3 * defaultValue )
2023-11-18 22:19:28 +03:00
{
if ( GetType ( ) ! = KV3_TYPE_TABLE )
return defaultValue ;
2025-01-01 22:36:06 +03:00
KV3MemberId_t id = m_Data . m_pTable - > FindMember ( name ) ;
2023-11-18 22:19:28 +03:00
if ( id = = KV3_INVALID_MEMBER )
return defaultValue ;
2025-01-01 22:36:06 +03:00
return m_Data . m_pTable - > GetMember ( id ) ;
2023-11-18 22:19:28 +03:00
}
KeyValues3 * KeyValues3 : : FindOrCreateMember ( const CKV3MemberName & name , bool * pCreated )
{
if ( GetType ( ) ! = KV3_TYPE_TABLE )
PrepareForType ( KV3_TYPEEX_TABLE , KV3_SUBTYPE_TABLE ) ;
2025-01-01 22:36:06 +03:00
KV3MemberId_t id = m_Data . m_pTable - > FindMember ( name ) ;
2023-11-18 22:19:28 +03:00
if ( id = = KV3_INVALID_MEMBER )
{
if ( pCreated )
* pCreated = true ;
2025-01-01 22:36:06 +03:00
id = m_Data . m_pTable - > CreateMember ( this , name ) ;
2023-11-18 22:19:28 +03:00
}
else
{
if ( pCreated )
* pCreated = false ;
}
2025-01-01 22:36:06 +03:00
return m_Data . m_pTable - > GetMember ( id ) ;
2023-12-23 20:03:58 +03:00
}
2023-11-18 22:19:28 +03:00
void KeyValues3 : : SetToEmptyTable ( )
{
PrepareForType ( KV3_TYPEEX_TABLE , KV3_SUBTYPE_TABLE ) ;
2025-01-01 22:36:06 +03:00
m_Data . m_pTable - > RemoveAll ( this ) ;
2023-11-18 22:19:28 +03:00
}
bool KeyValues3 : : RemoveMember ( KV3MemberId_t id )
{
2025-01-01 22:36:06 +03:00
if ( GetType ( ) ! = KV3_TYPE_TABLE | | id < 0 | | id > = m_Data . m_pTable - > GetMemberCount ( ) )
2023-11-18 22:19:28 +03:00
return false ;
2025-01-01 22:36:06 +03:00
m_Data . m_pTable - > RemoveMember ( this , id ) ;
2023-11-18 22:19:28 +03:00
return true ;
}
bool KeyValues3 : : RemoveMember ( const KeyValues3 * kv )
{
if ( GetType ( ) ! = KV3_TYPE_TABLE )
return false ;
2025-01-01 22:36:06 +03:00
KV3MemberId_t id = m_Data . m_pTable - > FindMember ( kv ) ;
2023-11-18 22:19:28 +03:00
if ( id = = KV3_INVALID_MEMBER )
return false ;
2025-01-01 22:36:06 +03:00
m_Data . m_pTable - > RemoveMember ( this , id ) ;
2023-11-18 22:19:28 +03:00
return true ;
}
bool KeyValues3 : : RemoveMember ( const CKV3MemberName & name )
{
if ( GetType ( ) ! = KV3_TYPE_TABLE )
return false ;
2025-01-01 22:36:06 +03:00
KV3MemberId_t id = m_Data . m_pTable - > FindMember ( name ) ;
2023-11-18 22:19:28 +03:00
if ( id = = KV3_INVALID_MEMBER )
return false ;
2025-01-01 22:36:06 +03:00
m_Data . m_pTable - > RemoveMember ( this , id ) ;
2023-11-18 22:19:28 +03:00
return true ;
}
2023-12-23 20:03:58 +03:00
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 " ,
2025-01-01 22:36:06 +03:00
" localize " ,
2023-12-23 20:03:58 +03:00
" 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 :
{
2025-01-01 22:36:06 +03:00
const char * str = m_Data . m_Bool ? " true " : " false " ;
2023-12-23 20:03:58 +03:00
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 :
{
2025-01-01 22:36:06 +03:00
buff . AppendFormat ( " %lld " , m_Data . m_Int ) ;
2023-12-23 20:03:58 +03:00
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 ( ) ;
}
2025-01-01 22:36:06 +03:00
buff . AppendFormat ( " %llu " , m_Data . m_UInt ) ;
2023-12-23 20:03:58 +03:00
return buff . ToGrowable ( ) - > Get ( ) ;
}
case KV3_TYPE_DOUBLE :
{
2025-01-01 22:36:06 +03:00
buff . AppendFormat ( " %g " , m_Data . m_Double ) ;
2023-12-23 20:03:58 +03:00
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 ;
2025-01-01 22:36:06 +03:00
CKeyValues3Array : : Element_t * arr = m_Data . m_pArray - > Base ( ) ;
2023-12-23 20:03:58 +03:00
for ( int i = 0 ; i < elements ; + + i )
{
switch ( arr [ i ] - > GetType ( ) )
{
case KV3_TYPE_INT :
2025-01-01 22:36:06 +03:00
temp . AppendFormat ( " %lld " , arr [ i ] - > m_Data . m_Int ) ;
2023-12-23 20:03:58 +03:00
break ;
case KV3_TYPE_UINT :
if ( arr [ i ] - > GetSubType ( ) = = KV3_SUBTYPE_POINTER )
unprintable = true ;
else
2025-01-01 22:36:06 +03:00
temp . AppendFormat ( " %llu " , arr [ i ] - > m_Data . m_UInt ) ;
2023-12-23 20:03:58 +03:00
break ;
case KV3_TYPE_DOUBLE :
2025-01-01 22:36:06 +03:00
temp . AppendFormat ( " %g " , arr [ i ] - > m_Data . m_Double ) ;
2023-12-23 20:03:58 +03:00
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 )
{
2025-01-01 22:36:06 +03:00
buff . AppendFormat ( " %g " , m_Data . m_Array . m_f32 [ i ] ) ;
2023-12-23 20:03:58 +03:00
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 )
{
2025-01-01 22:36:06 +03:00
buff . AppendFormat ( " %g " , m_Data . m_Array . m_f64 [ i ] ) ;
2023-12-23 20:03:58 +03:00
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 )
{
2025-01-01 22:36:06 +03:00
buff . AppendFormat ( " %d " , m_Data . m_Array . m_i16Short [ i ] ) ;
2023-12-23 20:03:58 +03:00
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 )
{
2025-01-01 22:36:06 +03:00
buff . AppendFormat ( " %d " , m_Data . m_Array . m_i32 [ i ] ) ;
2023-12-23 20:03:58 +03:00
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 )
{
2025-01-01 22:36:06 +03:00
buff . AppendFormat ( " %u " , m_Data . m_Array . m_u8Short [ i ] ) ;
2023-12-23 20:03:58 +03:00
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 )
{
2025-01-01 22:36:06 +03:00
buff . AppendFormat ( " %d " , m_Data . m_Array . m_i16Short [ i ] ) ;
2023-12-23 20:03:58 +03:00
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 ( ) ;
}
}
}
2023-11-18 22:19:28 +03:00
void KeyValues3 : : CopyFrom ( const KeyValues3 * pSrc )
{
2025-01-01 22:36:06 +03:00
if ( this = = pSrc )
return ;
2023-11-18 22:19:28 +03:00
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 :
2025-01-01 22:36:06 +03:00
SetBool ( pSrc - > m_Data . m_Bool ) ;
2023-11-18 22:19:28 +03:00
break ;
case KV3_TYPE_INT :
2025-01-01 22:36:06 +03:00
SetValue < int64 > ( pSrc - > m_Data . m_Int , KV3_TYPEEX_INT , eSrcSubType ) ;
2023-11-18 22:19:28 +03:00
break ;
case KV3_TYPE_UINT :
2025-01-01 22:36:06 +03:00
SetValue < uint64 > ( pSrc - > m_Data . m_UInt , KV3_TYPEEX_UINT , eSrcSubType ) ;
2023-11-18 22:19:28 +03:00
break ;
case KV3_TYPE_DOUBLE :
2025-01-01 22:36:06 +03:00
SetValue < float64 > ( pSrc - > m_Data . m_Double , KV3_TYPEEX_DOUBLE , eSrcSubType ) ;
2023-11-18 22:19:28 +03:00
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 ) ;
2025-01-01 22:36:06 +03:00
m_Data . m_pArray - > CopyFrom ( this , pSrc - > m_Data . m_pArray ) ;
2023-11-18 22:19:28 +03:00
break ;
}
case KV3_TYPEEX_ARRAY_FLOAT32 :
2025-01-01 22:36:06 +03:00
AllocArray < float32 > ( pSrc - > m_nNumArrayElements , pSrc - > m_Data . m_Array . m_f32 , KV3_ARRAY_ALLOC_NORMAL , KV3_TYPEEX_INVALID , KV3_TYPEEX_ARRAY_FLOAT32 , eSrcSubType , KV3_TYPEEX_DOUBLE , KV3_SUBTYPE_FLOAT32 ) ;
2023-11-18 22:19:28 +03:00
break ;
case KV3_TYPEEX_ARRAY_FLOAT64 :
2025-01-01 22:36:06 +03:00
AllocArray < float64 > ( pSrc - > m_nNumArrayElements , pSrc - > m_Data . m_Array . m_f64 , KV3_ARRAY_ALLOC_NORMAL , KV3_TYPEEX_INVALID , KV3_TYPEEX_ARRAY_FLOAT64 , eSrcSubType , KV3_TYPEEX_DOUBLE , KV3_SUBTYPE_FLOAT64 ) ;
2023-11-18 22:19:28 +03:00
break ;
case KV3_TYPEEX_ARRAY_INT16 :
2025-01-01 22:36:06 +03:00
AllocArray < int16 > ( pSrc - > m_nNumArrayElements , pSrc - > m_Data . m_Array . m_i16 , KV3_ARRAY_ALLOC_NORMAL , KV3_TYPEEX_ARRAY_INT16_SHORT , KV3_TYPEEX_ARRAY_INT16 , eSrcSubType , KV3_TYPEEX_INT , KV3_SUBTYPE_INT16 ) ;
2023-11-18 22:19:28 +03:00
break ;
case KV3_TYPEEX_ARRAY_INT32 :
2025-01-01 22:36:06 +03:00
AllocArray < int32 > ( pSrc - > m_nNumArrayElements , pSrc - > m_Data . m_Array . m_i32 , KV3_ARRAY_ALLOC_NORMAL , KV3_TYPEEX_INVALID , KV3_TYPEEX_ARRAY_INT32 , eSrcSubType , KV3_TYPEEX_INT , KV3_SUBTYPE_INT32 ) ;
2023-11-18 22:19:28 +03:00
break ;
case KV3_TYPEEX_ARRAY_UINT8_SHORT :
2025-01-01 22:36:06 +03:00
AllocArray < uint8 > ( pSrc - > m_nNumArrayElements , pSrc - > m_Data . m_Array . m_u8Short , KV3_ARRAY_ALLOC_NORMAL , KV3_TYPEEX_ARRAY_UINT8_SHORT , KV3_TYPEEX_INVALID , eSrcSubType , KV3_TYPEEX_UINT , KV3_SUBTYPE_UINT8 ) ;
2023-11-18 22:19:28 +03:00
break ;
case KV3_TYPEEX_ARRAY_INT16_SHORT :
2025-01-01 22:36:06 +03:00
AllocArray < int16 > ( pSrc - > m_nNumArrayElements , pSrc - > m_Data . m_Array . m_i16Short , KV3_ARRAY_ALLOC_NORMAL , KV3_TYPEEX_ARRAY_INT16_SHORT , KV3_TYPEEX_ARRAY_INT16 , eSrcSubType , KV3_TYPEEX_INT , KV3_SUBTYPE_INT16 ) ;
2023-11-18 22:19:28 +03:00
break ;
default :
break ;
}
break ;
}
case KV3_TYPE_TABLE :
{
2025-01-01 22:36:06 +03:00
SetToEmptyTable ( ) ;
m_Data . m_pTable - > CopyFrom ( this , pSrc - > m_Data . m_pTable ) ;
2023-11-18 22:19:28 +03:00
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 ;
}
2025-01-01 22:36:06 +03:00
CKeyValues3Array : : CKeyValues3Array ( int cluster_elem , int alloc_size ) :
m_nClusterElement ( cluster_elem ) ,
m_nAllocatedChunks ( alloc_size ) ,
m_nCount ( 0 ) ,
m_nInitialSize ( MIN ( alloc_size , 255 ) ) ,
m_bIsDynamicallySized ( false ) ,
m_unk001 ( false ) ,
m_unk002 ( false ) ,
m_pDynamicElements ( nullptr )
2023-12-23 20:03:58 +03:00
{
}
2023-11-18 22:19:28 +03:00
CKeyValues3ArrayCluster * CKeyValues3Array : : GetCluster ( ) const
{
if ( m_nClusterElement = = - 1 )
return NULL ;
2025-01-01 22:36:06 +03:00
return GET_OUTER ( CKeyValues3ArrayCluster , m_Values [ m_nClusterElement ] ) ;
2023-11-18 22:19:28 +03:00
}
CKeyValues3Context * CKeyValues3Array : : GetContext ( ) const
{
CKeyValues3ArrayCluster * cluster = GetCluster ( ) ;
if ( cluster )
return cluster - > GetContext ( ) ;
else
return NULL ;
}
2025-01-01 22:36:06 +03:00
KeyValues3 * CKeyValues3Array : : Element ( int i )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
Assert ( 0 < = i & & i < m_nCount ) ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
return Base ( ) [ i ] ;
}
void CKeyValues3Array : : EnsureElementCapacity ( int count , bool force , bool dont_move )
{
if ( count < = m_nAllocatedChunks )
return ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
if ( count > ALLOC_KV3ARRAY_MAX )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
Plat_FatalErrorFunc ( " %s: element count overflow (%u) \n " , __FUNCTION__ , count ) ;
DebuggerBreak ( ) ;
2023-11-18 22:19:28 +03:00
}
2025-01-01 22:36:06 +03:00
const int new_count = force ? count : KV3Helpers : : CalcNewBufferSize ( m_nAllocatedChunks , count , ALLOC_KV3ARRAY_MIN , ALLOC_KV3ARRAY_MAX ) ;
const int new_byte_size = TotalSizeOfData ( new_count ) ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
Element_t * new_base = nullptr ;
if ( m_bIsDynamicallySized )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
new_base = ( Element_t * ) realloc ( m_pDynamicElements , new_byte_size ) ;
}
else
{
new_base = ( Element_t * ) malloc ( new_byte_size ) ;
if ( m_nCount > 0 & & ! dont_move )
{
memmove ( new_base , Base ( ) , sizeof ( Element_t ) * m_nCount ) ;
}
}
m_pDynamicElements = new_base ;
m_nAllocatedChunks = new_count ;
m_bIsDynamicallySized = true ;
}
void CKeyValues3Array : : SetCount ( KeyValues3 * parent , int count , KV3TypeEx_t type , KV3SubType_t subtype )
{
Element_t * elements_base = Base ( ) ;
for ( int i = count ; i < m_nCount ; i + + )
{
parent - > FreeMember ( elements_base [ i ] ) ;
}
EnsureElementCapacity ( count ) ;
elements_base = Base ( ) ;
for ( int i = m_nCount ; i < count ; i + + )
{
elements_base [ i ] = parent - > AllocMember ( type , subtype ) ;
2023-11-18 22:19:28 +03:00
}
2025-01-01 22:36:06 +03:00
m_nCount = count ;
2023-11-18 22:19:28 +03:00
}
2025-01-01 22:36:06 +03:00
CKeyValues3Array : : Element_t * CKeyValues3Array : : InsertMultipleBefore ( KeyValues3 * parent , int from , int num )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
if ( from < 0 | | from > m_nCount )
{
Plat_FatalErrorFunc ( " %s: invalid insert point %u (current count %u) \n " , __FUNCTION__ , from , m_nCount ) ;
DebuggerBreak ( ) ;
}
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
if ( num > ALLOC_KV3ARRAY_MAX - m_nCount )
{
Plat_FatalErrorFunc ( " %s: max element overflow, cur count %u + %u \n " , __FUNCTION__ , m_nCount , num ) ;
DebuggerBreak ( ) ;
}
int new_size = m_nCount + num ;
EnsureElementCapacity ( new_size ) ;
Element_t * base = Base ( ) ;
if ( from < m_nCount )
{
memmove ( ( void * ) base [ from + num ] , ( void * ) base [ from ] , sizeof ( Element_t ) * ( m_nCount - from ) ) ;
}
2023-11-18 22:19:28 +03:00
for ( int i = 0 ; i < num ; + + i )
{
2025-01-01 22:36:06 +03:00
base [ from + i ] = parent - > AllocMember ( ) ;
2023-11-18 22:19:28 +03:00
}
2025-01-01 22:36:06 +03:00
m_nCount = new_size ;
return base ;
2023-11-18 22:19:28 +03:00
}
2025-01-01 22:36:06 +03:00
void CKeyValues3Array : : CopyFrom ( KeyValues3 * parent , const CKeyValues3Array * pSrc )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
int nNewSize = pSrc - > Count ( ) ;
SetCount ( parent , nNewSize ) ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
Element_t * base = Base ( ) ;
Element_t const * pSrcKV = pSrc - > Base ( ) ;
2023-11-18 22:19:28 +03:00
for ( int i = 0 ; i < nNewSize ; + + i )
2025-01-01 22:36:06 +03:00
* base [ i ] = * pSrcKV [ i ] ;
2023-11-18 22:19:28 +03:00
}
2025-01-01 22:36:06 +03:00
void CKeyValues3Array : : RemoveMultiple ( KeyValues3 * parent , int from , int num )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
Element_t * base = Base ( ) ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
for ( int i = 0 ; i < = num ; + + i )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
parent - > FreeMember ( base [ from + i ] ) ;
2023-11-18 22:19:28 +03:00
}
2025-01-01 22:36:06 +03:00
m_nCount - = num ;
2023-11-18 22:19:28 +03:00
}
2025-01-01 22:36:06 +03:00
void CKeyValues3Array : : PurgeBuffers ( )
{
if ( m_bIsDynamicallySized )
{
free ( m_pDynamicElements ) ;
m_nAllocatedChunks = m_nInitialSize ;
m_bIsDynamicallySized = false ;
}
m_nCount = 0 ;
}
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
void CKeyValues3Array : : PurgeContent ( KeyValues3 * parent , bool clearing_context )
{
if ( ! clearing_context & & parent )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
auto elements_base = Base ( ) ;
for ( int i = 0 ; i < m_nCount ; i + + )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
parent - > FreeMember ( elements_base [ i ] ) ;
2023-11-18 22:19:28 +03:00
}
}
}
2025-01-01 22:36:06 +03:00
CKeyValues3Table : : CKeyValues3Table ( int cluster_elem , int alloc_size ) :
2023-12-23 20:03:58 +03:00
m_nClusterElement ( cluster_elem ) ,
2025-01-01 22:36:06 +03:00
m_nAllocatedChunks ( alloc_size ) ,
m_pFastSearch ( nullptr ) ,
m_nCount ( 0 ) ,
m_nInitialSize ( MIN ( alloc_size , 255 ) ) ,
m_bIsDynamicallySized ( false ) ,
m_unk001 ( false ) ,
m_unk002 ( false ) ,
m_pDynamicBuffer ( nullptr )
2023-12-23 20:03:58 +03:00
{
}
2023-11-18 22:19:28 +03:00
CKeyValues3TableCluster * CKeyValues3Table : : GetCluster ( ) const
{
if ( m_nClusterElement = = - 1 )
return NULL ;
2025-01-01 22:36:06 +03:00
return GET_OUTER ( CKeyValues3TableCluster , m_Values [ m_nClusterElement ] ) ;
2023-11-18 22:19:28 +03:00
}
CKeyValues3Context * CKeyValues3Table : : GetContext ( ) const
{
CKeyValues3TableCluster * cluster = GetCluster ( ) ;
if ( cluster )
return cluster - > GetContext ( ) ;
else
return NULL ;
}
2025-01-01 22:36:06 +03:00
KeyValues3 * CKeyValues3Table : : GetMember ( KV3MemberId_t id )
{
Assert ( 0 < = id & & id < m_nCount ) ;
return MembersBase ( ) [ id ] ;
}
const CKeyValues3Table : : Name_t CKeyValues3Table : : GetMemberName ( KV3MemberId_t id ) const
{
Assert ( 0 < = id & & id < m_nCount ) ;
return NamesBase ( ) [ id ] ;
}
const CKeyValues3Table : : Hash_t CKeyValues3Table : : GetMemberHash ( KV3MemberId_t id ) const
{
Assert ( 0 < = id & & id < m_nCount ) ;
return HashesBase ( ) [ id ] ;
}
2023-11-18 22:19:28 +03:00
void CKeyValues3Table : : EnableFastSearch ( )
{
if ( m_pFastSearch )
m_pFastSearch - > m_member_ids . RemoveAll ( ) ;
else
m_pFastSearch = new kv3tablefastsearch_t ;
2025-01-01 22:36:06 +03:00
const Hash_t * pHashes = HashesBase ( ) ;
for ( int i = 0 ; i < m_nCount ; + + i )
{
m_pFastSearch - > m_member_ids . Insert ( pHashes [ i ] , i ) ;
}
2023-11-18 22:19:28 +03:00
m_pFastSearch - > m_ignore = false ;
m_pFastSearch - > m_ignores_counter = 0 ;
}
2025-01-01 22:36:06 +03:00
void CKeyValues3Table : : EnsureMemberCapacity ( int count , bool force , bool dont_move )
{
if ( count < = m_nAllocatedChunks )
return ;
if ( count > ALLOC_KV3TABLE_MAX )
{
Plat_FatalErrorFunc ( " %s member count overflow (%u) \n " , __FUNCTION__ , count ) ;
DebuggerBreak ( ) ;
}
const int new_count = force ? count : KV3Helpers : : CalcNewBufferSize ( m_nAllocatedChunks , count , ALLOC_KV3TABLE_MIN , ALLOC_KV3TABLE_MAX ) ;
const int new_byte_size = TotalSizeOfData ( new_count ) ;
void * new_base = nullptr ;
if ( m_bIsDynamicallySized )
{
new_base = realloc ( m_pDynamicBuffer , new_byte_size ) ;
memmove ( ( uint8 * ) new_base + OffsetToFlagsBase ( new_count ) , FlagsBase ( ) , m_nCount * sizeof ( Flags_t ) ) ;
memmove ( ( uint8 * ) new_base + OffsetToNamesBase ( new_count ) , NamesBase ( ) , m_nCount * sizeof ( Name_t ) ) ;
memmove ( ( uint8 * ) new_base + OffsetToMembersBase ( new_count ) , MembersBase ( ) , m_nCount * sizeof ( Member_t ) ) ;
}
else
{
new_base = malloc ( new_byte_size ) ;
if ( m_nCount > 0 & & ! dont_move )
{
memmove ( ( uint8 * ) new_base + OffsetToHashesBase ( new_count ) , HashesBase ( ) , m_nCount * sizeof ( Hash_t ) ) ;
memmove ( ( uint8 * ) new_base + OffsetToMembersBase ( new_count ) , MembersBase ( ) , m_nCount * sizeof ( Member_t ) ) ;
memmove ( ( uint8 * ) new_base + OffsetToNamesBase ( new_count ) , NamesBase ( ) , m_nCount * sizeof ( Name_t ) ) ;
memmove ( ( uint8 * ) new_base + OffsetToFlagsBase ( new_count ) , FlagsBase ( ) , m_nCount * sizeof ( Flags_t ) ) ;
}
}
m_pDynamicBuffer = new_base ;
m_nAllocatedChunks = new_count ;
m_bIsDynamicallySized = true ;
}
2023-11-18 22:19:28 +03:00
KV3MemberId_t CKeyValues3Table : : FindMember ( const KeyValues3 * kv ) const
{
2025-01-01 22:36:06 +03:00
const Member_t * pMembers = MembersBase ( ) ;
for ( int i = 0 ; i < m_nCount ; + + i )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
if ( pMembers [ i ] = = kv )
2023-11-18 22:19:28 +03:00
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
{
2025-01-01 22:36:06 +03:00
const Hash_t * pHashes = HashesBase ( ) ;
for ( int i = 0 ; i < m_nCount ; + + i )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
if ( pHashes [ i ] = = name . GetHashCode ( ) )
2023-11-18 22:19:28 +03:00
return i ;
}
}
return KV3_INVALID_MEMBER ;
}
2025-01-01 22:36:06 +03:00
KV3MemberId_t CKeyValues3Table : : CreateMember ( KeyValues3 * parent , const CKV3MemberName & name , bool name_external )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
if ( GetMemberCount ( ) > = 128 & & ! m_pFastSearch )
2023-11-18 22:19:28 +03:00
EnableFastSearch ( ) ;
2025-01-01 22:36:06 +03:00
KV3MemberId_t curr = m_nCount ;
int new_size = m_nCount + 1 ;
EnsureMemberCapacity ( new_size ) ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
Hash_t * hashes_base = HashesBase ( ) ;
Member_t * members_base = MembersBase ( ) ;
Name_t * names_base = NamesBase ( ) ;
Flags_t * flags_base = FlagsBase ( ) ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
members_base [ curr ] = parent - > AllocMember ( ) ;
hashes_base [ curr ] = name . GetHashCode ( ) ;
Flags_t flags = TABLEFL_NONE ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
if ( name_external )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
names_base [ curr ] = name . GetString ( ) ;
flags | = TABLEFL_NAME_EXTERNAL ;
2023-11-18 22:19:28 +03:00
}
else
{
2025-01-01 22:36:06 +03:00
auto context = parent - > GetContext ( ) ;
if ( context )
names_base [ curr ] = context - > AllocString ( name . GetString ( ) ) ;
else
names_base [ curr ] = strdup ( name . GetString ( ) ) ;
2023-11-18 22:19:28 +03:00
}
2025-01-01 22:36:06 +03:00
flags_base [ curr ] = flags ;
2023-11-18 22:19:28 +03:00
if ( m_pFastSearch & & ! m_pFastSearch - > m_ignore )
2025-01-01 22:36:06 +03:00
m_pFastSearch - > m_member_ids . Insert ( name . GetHashCode ( ) , curr ) ;
m_nCount = new_size ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
return curr ;
2023-11-18 22:19:28 +03:00
}
2025-01-01 22:36:06 +03:00
void CKeyValues3Table : : CopyFrom ( KeyValues3 * parent , const CKeyValues3Table * src )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
int new_size = src - > GetMemberCount ( ) ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
RemoveAll ( parent , new_size ) ;
EnsureMemberCapacity ( new_size , true , true ) ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
auto context = parent - > GetContext ( ) ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
Hash_t * hashes_base = HashesBase ( ) ;
Member_t * members_base = MembersBase ( ) ;
Name_t * names_base = NamesBase ( ) ;
Flags_t * flags_base = FlagsBase ( ) ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
const Hash_t * src_hashes_base = src - > HashesBase ( ) ;
const Member_t * src_members_base = src - > MembersBase ( ) ;
const Name_t * src_names_base = src - > NamesBase ( ) ;
const Flags_t * src_flags_base = src - > FlagsBase ( ) ;
memmove ( hashes_base , src_hashes_base , sizeof ( Hash_t ) * new_size ) ;
for ( int i = 0 ; i < new_size ; i + + )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
flags_base [ i ] = src_flags_base [ i ] & ~ TABLEFL_NAME_EXTERNAL ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
if ( context )
names_base [ i ] = context - > AllocString ( src_names_base [ i ] ) ;
2023-11-18 22:19:28 +03:00
else
2025-01-01 22:36:06 +03:00
names_base [ i ] = strdup ( src_names_base [ i ] ) ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
members_base [ i ] = parent - > AllocMember ( ) ;
members_base [ i ] - > CopyFrom ( src_members_base [ i ] ) ;
2023-11-18 22:19:28 +03:00
}
2025-01-01 22:36:06 +03:00
if ( new_size > = 128 )
2023-11-18 22:19:28 +03:00
EnableFastSearch ( ) ;
}
2025-01-01 22:36:06 +03:00
void CKeyValues3Table : : RemoveMember ( KeyValues3 * parent , KV3MemberId_t id )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
m_nCount - - ;
Hash_t * hashes_base = HashesBase ( ) ;
Member_t * members_base = MembersBase ( ) ;
Name_t * names_base = NamesBase ( ) ;
Flags_t * flags_base = FlagsBase ( ) ;
parent - > FreeMember ( members_base [ id ] ) ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
if ( ( flags_base [ id ] & TABLEFL_NAME_EXTERNAL ) = = 0 & & ! parent - > GetContext ( ) & & names_base [ id ] )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
free ( ( void * ) names_base [ id ] ) ;
2023-11-18 22:19:28 +03:00
}
2025-01-01 22:36:06 +03:00
if ( id < m_nCount )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
int shift_size = m_nCount - id ;
int shift_from = id + 1 ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
memmove ( & hashes_base [ id ] , & hashes_base [ shift_from ] , shift_size * sizeof ( Hash_t ) ) ;
memmove ( & members_base [ id ] , & members_base [ shift_from ] , shift_size * sizeof ( Member_t ) ) ;
memmove ( & names_base [ id ] , & names_base [ shift_from ] , shift_size * sizeof ( Name_t ) ) ;
memmove ( & flags_base [ id ] , & flags_base [ shift_from ] , shift_size * sizeof ( Flags_t ) ) ;
}
2023-11-18 22:19:28 +03:00
if ( m_pFastSearch )
{
m_pFastSearch - > m_ignore = true ;
m_pFastSearch - > m_ignores_counter = 1 ;
}
}
2025-01-01 22:36:06 +03:00
void CKeyValues3Table : : RemoveAll ( KeyValues3 * parent , int new_size )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
Member_t * members_base = MembersBase ( ) ;
Name_t * names_base = NamesBase ( ) ;
Flags_t * flags_base = FlagsBase ( ) ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
for ( int i = 0 ; i < m_nCount ; i + + )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
parent - > FreeMember ( members_base [ i ] ) ;
if ( ( flags_base [ i ] & TABLEFL_NAME_EXTERNAL ) = = 0 & & ! parent - > GetContext ( ) & & names_base [ i ] )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
free ( ( void * ) names_base [ i ] ) ;
2023-11-18 22:19:28 +03:00
}
}
2025-01-01 22:36:06 +03:00
m_nCount = 0 ;
if ( new_size > 0 )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
EnsureMemberCapacity ( new_size , true , true ) ;
2023-11-18 22:19:28 +03:00
}
2025-01-01 22:36:06 +03:00
if ( new_size < 128 )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
PurgeFastSearch ( ) ;
2023-11-18 22:19:28 +03:00
}
2025-01-01 22:36:06 +03:00
else
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
EnableFastSearch ( ) ;
m_pFastSearch - > m_member_ids . Reserve ( new_size ) ;
2023-11-18 22:19:28 +03:00
}
2023-12-23 20:03:58 +03:00
}
2025-01-01 22:36:06 +03:00
void CKeyValues3Table : : PurgeFastSearch ( )
2023-12-23 20:03:58 +03:00
{
2025-01-01 22:36:06 +03:00
if ( m_pFastSearch )
delete m_pFastSearch ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
m_pFastSearch = nullptr ;
2023-11-18 22:19:28 +03:00
}
2025-01-01 22:36:06 +03:00
void CKeyValues3Table : : PurgeContent ( KeyValues3 * parent , bool bClearingContext )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
Member_t * members_base = MembersBase ( ) ;
Name_t * names_base = NamesBase ( ) ;
Flags_t * flags_base = FlagsBase ( ) ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
for ( int i = 0 ; i < m_nCount ; + + i )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
if ( ! bClearingContext & & parent )
{
parent - > FreeMember ( members_base [ i ] ) ;
}
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
if ( ( flags_base [ i ] & TABLEFL_NAME_EXTERNAL ) = = 0 & & parent & & ! parent - > GetContext ( ) & & names_base [ i ] )
{
free ( ( void * ) names_base [ i ] ) ;
}
2023-11-18 22:19:28 +03:00
}
2025-01-01 22:36:06 +03:00
m_nCount = 0 ;
2023-11-18 22:19:28 +03:00
2025-01-01 22:36:06 +03:00
PurgeFastSearch ( ) ;
2023-11-18 22:19:28 +03:00
}
2025-01-01 22:36:06 +03:00
void CKeyValues3Table : : PurgeBuffers ( )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
if ( m_bIsDynamicallySized )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
free ( m_pDynamicBuffer ) ;
m_nAllocatedChunks = m_nInitialSize ;
m_bIsDynamicallySized = false ;
2023-11-18 22:19:28 +03:00
}
2025-01-01 22:36:06 +03:00
m_nCount = 0 ;
2023-11-18 22:19:28 +03:00
}
CKeyValues3ContextBase : : CKeyValues3ContextBase ( CKeyValues3Context * context ) :
m_pContext ( context ) ,
m_KV3BaseCluster ( context ) ,
2025-01-01 22:36:06 +03:00
m_bMetaDataEnabled ( false ) ,
m_bFormatConverted ( false ) ,
m_bRootAvailabe ( false ) ,
m_pParsingErrorListener ( nullptr )
2023-11-18 22:19:28 +03:00
{
2025-01-01 22:36:06 +03:00
m_KV3PartialClusters . AddToChain ( & m_KV3BaseCluster ) ;
2023-11-18 22:19:28 +03:00
}
void CKeyValues3ContextBase : : Clear ( )
{
m_BinaryData . Clear ( ) ;
m_KV3BaseCluster . Clear ( ) ;
m_Symbols . RemoveAll ( ) ;
2025-01-01 22:36:06 +03:00
2023-11-18 22:19:28 +03:00
m_bFormatConverted = false ;
}
void CKeyValues3ContextBase : : Purge ( )
{
m_BinaryData . Purge ( ) ;
m_KV3BaseCluster . Purge ( ) ;
m_Symbols . Purge ( ) ;
m_bFormatConverted = false ;
}
2025-01-01 22:36:06 +03:00
CKeyValues3Context : : CKeyValues3Context ( bool bNoRoot ) : BaseClass ( this ) , pad { }
2023-11-18 22:19:28 +03:00
{
if ( bNoRoot )
{
m_bRootAvailabe = false ;
}
else
{
m_bRootAvailabe = true ;
m_KV3BaseCluster . Alloc ( ) ;
}
m_bMetaDataEnabled = false ;
m_bFormatConverted = false ;
}
void CKeyValues3Context : : Clear ( )
{
BaseClass : : Clear ( ) ;
2025-01-01 22:36:06 +03:00
ClearClusterNodeChain ( m_KV3PartialClusters ) ;
ClearClusterNodeChain ( m_KV3FullClusters ) ;
MoveToPartial ( m_KV3FullClusters , m_KV3PartialClusters ) ;
ClearClusterNodeChain ( m_PartialArrayClusters ) ;
ClearClusterNodeChain ( m_FullArrayClusters ) ;
MoveToPartial ( m_FullArrayClusters , m_PartialArrayClusters ) ;
m_RawArrayEntries . Clear ( ) ;
ClearClusterNodeChain ( m_PartialTableClusters ) ;
ClearClusterNodeChain ( m_FullTableClusters ) ;
MoveToPartial ( m_FullTableClusters , m_PartialTableClusters ) ;
m_RawTableEntries . Clear ( ) ;
2023-11-18 22:19:28 +03:00
if ( m_bRootAvailabe )
m_KV3BaseCluster . Alloc ( ) ;
}
void CKeyValues3Context : : Purge ( )
{
BaseClass : : Purge ( ) ;
2025-01-01 22:36:06 +03:00
PurgeClusterNodeChain ( m_KV3PartialClusters ) ;
PurgeClusterNodeChain ( m_KV3FullClusters ) ;
m_KV3PartialClusters . AddToChain ( & m_KV3BaseCluster ) ;
PurgeClusterNodeChain ( m_PartialArrayClusters ) ;
PurgeClusterNodeChain ( m_FullArrayClusters ) ;
m_RawArrayEntries . Purge ( ) ;
PurgeClusterNodeChain ( m_PartialTableClusters ) ;
PurgeClusterNodeChain ( m_FullTableClusters ) ;
m_RawTableEntries . Purge ( ) ;
2023-11-18 22:19:28 +03:00
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 ( ) ;
}
2025-01-01 22:36:06 +03:00
return & m_KV3BaseCluster . Head ( ) - > m_Value ;
2023-11-18 22:19:28 +03:00
}
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 ) ;
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 )
{
2024-04-06 23:49:28 +03:00
pDest - > m_Comments . Insert ( pSrc - > m_Comments . Key ( iter ) , pSrc - > m_Comments . Element ( iter ) ) ;
2023-11-18 22:19:28 +03:00
}
}
KeyValues3 * CKeyValues3Context : : AllocKV ( KV3TypeEx_t type , KV3SubType_t subtype )
{
2025-01-01 22:36:06 +03:00
return Alloc ( m_KV3PartialClusters , m_KV3FullClusters , CKeyValues3Cluster : : CLUSTER_SIZE , type , subtype ) ;
2023-11-18 22:19:28 +03:00
}
void CKeyValues3Context : : FreeKV ( KeyValues3 * kv )
{
2023-12-23 20:03:58 +03:00
CKeyValues3Context * context ;
KV3MetaData_t * metadata = kv - > GetMetaData ( & context ) ;
2023-11-18 22:19:28 +03:00
if ( metadata )
metadata - > Clear ( ) ;
2025-01-01 22:36:06 +03:00
// Free<KeyValues3, CKeyValues3Cluster>( kv, &m_KV3BaseCluster, m_pKV3FreeCluster );
2023-11-18 22:19:28 +03:00
}
2025-01-01 22:36:06 +03:00
# include "tier0/memdbgoff.h"