summaryrefslogtreecommitdiff
path: root/dmxloader/dmxelement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dmxloader/dmxelement.cpp')
-rw-r--r--dmxloader/dmxelement.cpp489
1 files changed, 489 insertions, 0 deletions
diff --git a/dmxloader/dmxelement.cpp b/dmxloader/dmxelement.cpp
new file mode 100644
index 0000000..7537590
--- /dev/null
+++ b/dmxloader/dmxelement.cpp
@@ -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 );
+ }
+ }
+ }
+}