mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-08 01:39:36 +00:00
1
This commit is contained in:
@@ -0,0 +1,489 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "dmxloader/dmxelement.h"
|
||||
#include "dmxloader/dmxattribute.h"
|
||||
#include "tier1/utlbuffer.h"
|
||||
#include "mathlib/ssemath.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// globals
|
||||
//-----------------------------------------------------------------------------
|
||||
CUtlSymbolTableMT CDmxElement::s_TypeSymbols;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates a dmx element
|
||||
//-----------------------------------------------------------------------------
|
||||
CDmxElement* CreateDmxElement( const char *pType )
|
||||
{
|
||||
return new CDmxElement( pType );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructor, destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CDmxElement::CDmxElement( const char *pType )
|
||||
{
|
||||
m_Type = s_TypeSymbols.AddString( pType );
|
||||
m_nLockCount = 0;
|
||||
m_bResortNeeded = false;
|
||||
m_bIsMarkedForDeletion = false;
|
||||
CreateUniqueId( &m_Id );
|
||||
}
|
||||
|
||||
CDmxElement::~CDmxElement()
|
||||
{
|
||||
CDmxElementModifyScope modify( this );
|
||||
RemoveAllAttributes();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Utility method for getting at the type
|
||||
//-----------------------------------------------------------------------------
|
||||
CUtlSymbol CDmxElement::GetType() const
|
||||
{
|
||||
return m_Type;
|
||||
}
|
||||
|
||||
const char* CDmxElement::GetTypeString() const
|
||||
{
|
||||
return s_TypeSymbols.String( m_Type );
|
||||
}
|
||||
|
||||
const char* CDmxElement::GetName() const
|
||||
{
|
||||
return GetValue< CUtlString >( "name" );
|
||||
}
|
||||
|
||||
const DmObjectId_t &CDmxElement::GetId() const
|
||||
{
|
||||
return m_Id;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sets the object id
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDmxElement::SetId( const DmObjectId_t &id )
|
||||
{
|
||||
CopyUniqueId( id, &m_Id );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sorts the vector when a change has occurred
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDmxElement::Resort( ) const
|
||||
{
|
||||
if ( m_bResortNeeded )
|
||||
{
|
||||
AttributeList_t *pAttributes = const_cast< AttributeList_t *>( &m_Attributes );
|
||||
pAttributes->RedoSort();
|
||||
m_bResortNeeded = false;
|
||||
|
||||
// NOTE: This checks for duplicate attribute names
|
||||
int nCount = m_Attributes.Count();
|
||||
for ( int i = nCount; --i >= 1; )
|
||||
{
|
||||
if ( m_Attributes[i]->GetNameSymbol() == m_Attributes[i-1]->GetNameSymbol() )
|
||||
{
|
||||
Warning( "Duplicate attribute name %s encountered!\n", m_Attributes[i]->GetName() );
|
||||
pAttributes->Remove(i);
|
||||
Assert( 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Enables modification of the DmxElement
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDmxElement::LockForChanges( bool bLock )
|
||||
{
|
||||
if ( bLock )
|
||||
{
|
||||
++m_nLockCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( --m_nLockCount == 0 )
|
||||
{
|
||||
Resort();
|
||||
}
|
||||
Assert( m_nLockCount >= 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Adds, removes attributes
|
||||
//-----------------------------------------------------------------------------
|
||||
CDmxAttribute *CDmxElement::AddAttribute( const char *pAttributeName )
|
||||
{
|
||||
int nIndex = FindAttribute( pAttributeName );
|
||||
if ( nIndex >= 0 )
|
||||
return m_Attributes[nIndex];
|
||||
|
||||
CDmxElementModifyScope modify( this );
|
||||
m_bResortNeeded = true;
|
||||
CDmxAttribute *pAttribute = new CDmxAttribute( pAttributeName );
|
||||
m_Attributes.InsertNoSort( pAttribute );
|
||||
return pAttribute;
|
||||
}
|
||||
|
||||
void CDmxElement::RemoveAttribute( const char *pAttributeName )
|
||||
{
|
||||
CDmxElementModifyScope modify( this );
|
||||
int idx = FindAttribute( pAttributeName );
|
||||
if ( idx >= 0 )
|
||||
{
|
||||
delete m_Attributes[idx];
|
||||
m_Attributes.Remove( idx );
|
||||
}
|
||||
}
|
||||
|
||||
void CDmxElement::RemoveAttributeByPtr( CDmxAttribute *pAttribute )
|
||||
{
|
||||
CDmxElementModifyScope modify( this );
|
||||
int nCount = m_Attributes.Count();
|
||||
for ( int i = 0; i < nCount; ++i )
|
||||
{
|
||||
if ( m_Attributes[i] != pAttribute )
|
||||
continue;
|
||||
|
||||
delete pAttribute;
|
||||
m_Attributes.Remove( i );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CDmxElement::RemoveAllAttributes()
|
||||
{
|
||||
int nCount = m_Attributes.Count();
|
||||
for ( int i = 0; i < nCount; ++i )
|
||||
{
|
||||
delete m_Attributes[i];
|
||||
}
|
||||
m_Attributes.RemoveAll();
|
||||
m_bResortNeeded = false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Rename an attribute
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDmxElement::RenameAttribute( const char *pAttributeName, const char *pNewName )
|
||||
{
|
||||
CDmxElementModifyScope modify( this );
|
||||
|
||||
// No change...
|
||||
if ( !Q_stricmp( pAttributeName, pNewName ) )
|
||||
return;
|
||||
|
||||
int idx = FindAttribute( pAttributeName );
|
||||
if ( idx < 0 )
|
||||
return;
|
||||
|
||||
if ( HasAttribute( pNewName ) )
|
||||
{
|
||||
Warning( "Tried to rename from \"%s\" to \"%s\", but \"%s\" already exists!\n",
|
||||
pAttributeName, pNewName, pNewName );
|
||||
return;
|
||||
}
|
||||
|
||||
m_bResortNeeded = true;
|
||||
m_Attributes[ idx ]->SetName( pNewName );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Find an attribute by name-based lookup
|
||||
//-----------------------------------------------------------------------------
|
||||
int CDmxElement::FindAttribute( const char *pAttributeName ) const
|
||||
{
|
||||
// FIXME: The cost here is O(log M) + O(log N)
|
||||
// where log N is the binary search for the symbol match
|
||||
// and log M is the binary search for the attribute name->symbol
|
||||
// We can eliminate log M by using a hash table in the symbol lookup
|
||||
Resort();
|
||||
CDmxAttribute search( pAttributeName );
|
||||
return m_Attributes.Find( &search );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Find an attribute by name-based lookup
|
||||
//-----------------------------------------------------------------------------
|
||||
int CDmxElement::FindAttribute( CUtlSymbol attributeName ) const
|
||||
{
|
||||
Resort();
|
||||
CDmxAttribute search( attributeName );
|
||||
return m_Attributes.Find( &search );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Attribute finding
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CDmxElement::HasAttribute( const char *pAttributeName ) const
|
||||
{
|
||||
int idx = FindAttribute( pAttributeName );
|
||||
return ( idx >= 0 );
|
||||
}
|
||||
|
||||
CDmxAttribute *CDmxElement::GetAttribute( const char *pAttributeName )
|
||||
{
|
||||
int idx = FindAttribute( pAttributeName );
|
||||
if ( idx >= 0 )
|
||||
return m_Attributes[ idx ];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const CDmxAttribute *CDmxElement::GetAttribute( const char *pAttributeName ) const
|
||||
{
|
||||
int idx = FindAttribute( pAttributeName );
|
||||
if ( idx >= 0 )
|
||||
return m_Attributes[ idx ];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Attribute interation
|
||||
//-----------------------------------------------------------------------------
|
||||
int CDmxElement::AttributeCount() const
|
||||
{
|
||||
return m_Attributes.Count();
|
||||
}
|
||||
|
||||
CDmxAttribute *CDmxElement::GetAttribute( int nIndex )
|
||||
{
|
||||
return m_Attributes[ nIndex ];
|
||||
}
|
||||
|
||||
const CDmxAttribute *CDmxElement::GetAttribute( int nIndex ) const
|
||||
{
|
||||
return m_Attributes[ nIndex ];
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Removes all elements recursively
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDmxElement::AddElementsToDelete( CUtlVector< CDmxElement * >& elementsToDelete )
|
||||
{
|
||||
if ( m_bIsMarkedForDeletion )
|
||||
return;
|
||||
|
||||
m_bIsMarkedForDeletion = true;
|
||||
elementsToDelete.AddToTail( this );
|
||||
|
||||
int nCount = AttributeCount();
|
||||
for ( int i = 0; i < nCount; ++i )
|
||||
{
|
||||
CDmxAttribute *pAttribute = GetAttribute(i);
|
||||
if ( pAttribute->GetType() == AT_ELEMENT )
|
||||
{
|
||||
CDmxElement *pElement = pAttribute->GetValue< CDmxElement* >();
|
||||
if ( pElement )
|
||||
{
|
||||
pElement->AddElementsToDelete( elementsToDelete );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( pAttribute->GetType() == AT_ELEMENT_ARRAY )
|
||||
{
|
||||
const CUtlVector< CDmxElement * > &elements = pAttribute->GetArray< CDmxElement* >();
|
||||
int nElementCount = elements.Count();
|
||||
for ( int j = 0; j < nElementCount; ++j )
|
||||
{
|
||||
if ( elements[j] )
|
||||
{
|
||||
elements[j]->AddElementsToDelete( elementsToDelete );
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Removes all elements recursively
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDmxElement::RemoveAllElementsRecursive()
|
||||
{
|
||||
CUtlVector< CDmxElement * > elementsToDelete;
|
||||
AddElementsToDelete( elementsToDelete );
|
||||
int nCount = elementsToDelete.Count();
|
||||
for ( int i = 0; i < nCount; ++i )
|
||||
{
|
||||
delete elementsToDelete[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Method to unpack data into a structure
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDmxElement::UnpackIntoStructure( void *pData, size_t DestSizeInBytes, const DmxElementUnpackStructure_t *pUnpack ) const
|
||||
{
|
||||
void *pDataEnd = ( char * )pData + DestSizeInBytes;
|
||||
|
||||
for ( ; pUnpack->m_AttributeType != AT_UNKNOWN; ++pUnpack )
|
||||
{
|
||||
char *pDest = (char*)pData + pUnpack->m_nOffset;
|
||||
|
||||
// NOTE: This does not work with array data at the moment
|
||||
if ( IsArrayType( pUnpack->m_AttributeType ) )
|
||||
{
|
||||
AssertMsg( 0, ( "CDmxElement::UnpackIntoStructure: Array attribute types not currently supported!\n" ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( pUnpack->m_AttributeType == AT_VOID )
|
||||
{
|
||||
AssertMsg( 0, ( "CDmxElement::UnpackIntoStructure: Binary blob attribute types not currently supported!\n" ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
CDmxAttribute temp( NULL );
|
||||
const CDmxAttribute *pAttribute = GetAttribute( pUnpack->m_pAttributeName );
|
||||
if ( !pAttribute )
|
||||
{
|
||||
if ( !pUnpack->m_pDefaultString )
|
||||
continue;
|
||||
|
||||
// Convert the default string into the target
|
||||
int nLen = Q_strlen( pUnpack->m_pDefaultString );
|
||||
if ( nLen > 0 )
|
||||
{
|
||||
CUtlBuffer buf( pUnpack->m_pDefaultString, nLen, CUtlBuffer::READ_ONLY | CUtlBuffer::TEXT_BUFFER );
|
||||
temp.Unserialize( pUnpack->m_AttributeType, buf );
|
||||
}
|
||||
else
|
||||
{
|
||||
CUtlBuffer buf;
|
||||
temp.Unserialize( pUnpack->m_AttributeType, buf );
|
||||
}
|
||||
pAttribute = &temp;
|
||||
}
|
||||
|
||||
if ( pUnpack->m_AttributeType != pAttribute->GetType() )
|
||||
{
|
||||
Warning( "CDmxElement::UnpackIntoStructure: Mismatched attribute type in attribute \"%s\"!\n", pUnpack->m_pAttributeName );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( pAttribute->GetType() == AT_STRING )
|
||||
{
|
||||
if ( pDest + pUnpack->m_nSize > pDataEnd )
|
||||
{
|
||||
Warning( "ERROR Memory corruption: CDmxElement::UnpackIntoStructure string buffer overrun!\n" );
|
||||
continue;
|
||||
}
|
||||
|
||||
// Strings get special treatment: they are stored as in-line arrays of chars
|
||||
Q_strncpy( pDest, pAttribute->GetValueString(), pUnpack->m_nSize );
|
||||
continue;
|
||||
}
|
||||
|
||||
// special case - if data type is float, but dest size == 16, we are unpacking into simd by
|
||||
// replication
|
||||
if ( ( pAttribute->GetType() == AT_FLOAT ) && ( pUnpack->m_nSize == sizeof( fltx4 ) ) )
|
||||
{
|
||||
if ( pDest + 4 * sizeof( float ) > pDataEnd )
|
||||
{
|
||||
Warning( "ERROR Memory corruption: CDmxElement::UnpackIntoStructure float buffer overrun!\n" );
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy( pDest + 0 * sizeof( float ) , pAttribute->m_pData, sizeof( float ) );
|
||||
memcpy( pDest + 1 * sizeof( float ) , pAttribute->m_pData, sizeof( float ) );
|
||||
memcpy( pDest + 2 * sizeof( float ) , pAttribute->m_pData, sizeof( float ) );
|
||||
memcpy( pDest + 3 * sizeof( float ) , pAttribute->m_pData, sizeof( float ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( pDest + pUnpack->m_nSize > pDataEnd )
|
||||
{
|
||||
Warning( "ERROR Memory corruption: CDmxElement::UnpackIntoStructure memcpy buffer overrun!\n" );
|
||||
continue;
|
||||
}
|
||||
|
||||
AssertMsg( pUnpack->m_nSize == CDmxAttribute::AttributeDataSize( pAttribute->GetType() ),
|
||||
"CDmxElement::UnpackIntoStructure: Incorrect size to unpack data into in attribute \"%s\"!\n", pUnpack->m_pAttributeName );
|
||||
memcpy( pDest, pAttribute->m_pData, pUnpack->m_nSize );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates attributes based on the unpack structure
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDmxElement::AddAttributesFromStructure_Internal( const void *pData, size_t byteCount, const DmxElementUnpackStructure_t *pUnpack )
|
||||
{
|
||||
for ( ; pUnpack->m_AttributeType != AT_UNKNOWN; ++pUnpack )
|
||||
{
|
||||
const char *pSrc = (const char*)pData + pUnpack->m_nOffset;
|
||||
|
||||
// NOTE: This does not work with array data at the moment
|
||||
if ( IsArrayType( pUnpack->m_AttributeType ) )
|
||||
{
|
||||
AssertMsg( 0, "CDmxElement::AddAttributesFromStructure: Array attribute types not currently supported!\n" );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( pUnpack->m_AttributeType == AT_VOID )
|
||||
{
|
||||
AssertMsg( 0, "CDmxElement::AddAttributesFromStructure: Binary blob attribute types not currently supported!\n" );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( HasAttribute( pUnpack->m_pAttributeName ) )
|
||||
{
|
||||
AssertMsg( 0, "CDmxElement::AddAttributesFromStructure: Attribute %s already exists!\n", pUnpack->m_pAttributeName );
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
if ( (size_t)(pUnpack->m_nOffset + pUnpack->m_nSize) > byteCount )
|
||||
{
|
||||
Msg( "Buffer underread! Mismatched type/type-descriptor.\n" );
|
||||
}
|
||||
CDmxElementModifyScope modify( this );
|
||||
CDmxAttribute *pAttribute = AddAttribute( pUnpack->m_pAttributeName );
|
||||
if ( pUnpack->m_AttributeType == AT_STRING )
|
||||
{
|
||||
pAttribute->SetValue( pSrc );
|
||||
}
|
||||
else
|
||||
{
|
||||
int nSize = pUnpack->m_nSize;
|
||||
|
||||
// handle float attrs stored as replicated fltx4's
|
||||
if ( ( pUnpack->m_AttributeType == AT_FLOAT ) && ( nSize == sizeof( fltx4 ) ) )
|
||||
{
|
||||
nSize = sizeof( float );
|
||||
}
|
||||
|
||||
AssertMsg( nSize == CDmxAttribute::AttributeDataSize( pUnpack->m_AttributeType ),
|
||||
"CDmxElement::UnpackIntoStructure: Incorrect size to unpack data into in attribute \"%s\"!\n", pUnpack->m_pAttributeName );
|
||||
pAttribute->SetValue( pUnpack->m_AttributeType, pSrc, nSize );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user