Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

703 lines
21 KiB

  1. //====== Copyright 1996-2004, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "dmxloader/dmxelement.h"
  7. #include "dmxloader/dmxattribute.h"
  8. #include "tier1/utlbuffer.h"
  9. #include "mathlib/ssemath.h"
  10. #include "tier1/utlbufferutil.h"
  11. // memdbgon must be the last include file in a .cpp file!!!
  12. #include "tier0/memdbgon.h"
  13. #ifdef OSX
  14. #pragma GCC diagnostic ignored "-Wtautological-compare"
  15. #endif
  16. //-----------------------------------------------------------------------------
  17. // globals
  18. //-----------------------------------------------------------------------------
  19. CUtlSymbolTableLargeMT CDmxElement::s_TypeSymbols;
  20. //-----------------------------------------------------------------------------
  21. // Creates a dmx element
  22. //-----------------------------------------------------------------------------
  23. CDmxElement* CreateDmxElement( const char *pType )
  24. {
  25. return new CDmxElement( pType );
  26. }
  27. //-----------------------------------------------------------------------------
  28. // Constructor, destructor
  29. //-----------------------------------------------------------------------------
  30. CDmxElement::CDmxElement( const char *pType )
  31. {
  32. m_Type = s_TypeSymbols.AddString( pType );
  33. m_nLockCount = 0;
  34. m_bResortNeeded = false;
  35. m_bIsMarkedForDeletion = false;
  36. CreateUniqueId( &m_Id );
  37. }
  38. CDmxElement::~CDmxElement()
  39. {
  40. CDmxElementModifyScope modify( this );
  41. RemoveAllAttributes();
  42. }
  43. //-----------------------------------------------------------------------------
  44. // Utility method for getting at the type
  45. //-----------------------------------------------------------------------------
  46. CUtlSymbolLarge CDmxElement::GetType() const
  47. {
  48. return m_Type;
  49. }
  50. const char* CDmxElement::GetTypeString() const
  51. {
  52. return m_Type.String();
  53. }
  54. const char* CDmxElement::GetName() const
  55. {
  56. return GetValue< CUtlString >( "name" );
  57. }
  58. const DmObjectId_t &CDmxElement::GetId() const
  59. {
  60. return m_Id;
  61. }
  62. //-----------------------------------------------------------------------------
  63. // Sets the object id, name
  64. //-----------------------------------------------------------------------------
  65. void CDmxElement::SetId( const DmObjectId_t &id )
  66. {
  67. CopyUniqueId( id, &m_Id );
  68. }
  69. void CDmxElement::SetName( const char *pName )
  70. {
  71. SetValue< CUtlString >( "name", pName );
  72. }
  73. //-----------------------------------------------------------------------------
  74. // Sorts the vector when a change has occurred
  75. //-----------------------------------------------------------------------------
  76. void CDmxElement::Resort( ) const
  77. {
  78. if ( m_bResortNeeded )
  79. {
  80. AttributeList_t *pAttributes = const_cast< AttributeList_t *>( &m_Attributes );
  81. pAttributes->RedoSort();
  82. m_bResortNeeded = false;
  83. // NOTE: This checks for duplicate attribute names
  84. int nCount = m_Attributes.Count();
  85. for ( int i = nCount; --i >= 1; )
  86. {
  87. if ( m_Attributes[i] == NULL || m_Attributes[i-1] == NULL )
  88. {
  89. continue;
  90. }
  91. if ( m_Attributes[i]->GetNameSymbol() == m_Attributes[i-1]->GetNameSymbol() )
  92. {
  93. Warning( "Duplicate attribute name %s encountered!\n", m_Attributes[i]->GetName() );
  94. pAttributes->Remove(i);
  95. Assert( 0 );
  96. }
  97. }
  98. }
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Enables modification of the DmxElement
  102. //-----------------------------------------------------------------------------
  103. void CDmxElement::LockForChanges( bool bLock )
  104. {
  105. if ( bLock )
  106. {
  107. ++m_nLockCount;
  108. }
  109. else
  110. {
  111. if ( --m_nLockCount == 0 )
  112. {
  113. Resort();
  114. }
  115. Assert( m_nLockCount >= 0 );
  116. }
  117. }
  118. //-----------------------------------------------------------------------------
  119. // Adds, removes attributes
  120. //-----------------------------------------------------------------------------
  121. CDmxAttribute *CDmxElement::AddAttribute( const char *pAttributeName )
  122. {
  123. int nIndex = FindAttribute( pAttributeName );
  124. if ( nIndex >= 0 )
  125. return m_Attributes[nIndex];
  126. CDmxElementModifyScope modify( this );
  127. m_bResortNeeded = true;
  128. CDmxAttribute *pAttribute = new CDmxAttribute( pAttributeName );
  129. m_Attributes.InsertNoSort( pAttribute );
  130. return pAttribute;
  131. }
  132. void CDmxElement::RemoveAttribute( const char *pAttributeName )
  133. {
  134. CDmxElementModifyScope modify( this );
  135. int idx = FindAttribute( pAttributeName );
  136. if ( idx >= 0 )
  137. {
  138. delete m_Attributes[idx];
  139. m_Attributes.Remove( idx );
  140. }
  141. }
  142. void CDmxElement::RemoveAttributeByPtr( CDmxAttribute *pAttribute )
  143. {
  144. CDmxElementModifyScope modify( this );
  145. int nCount = m_Attributes.Count();
  146. for ( int i = 0; i < nCount; ++i )
  147. {
  148. if ( m_Attributes[i] != pAttribute )
  149. continue;
  150. delete pAttribute;
  151. m_Attributes.Remove( i );
  152. break;
  153. }
  154. }
  155. void CDmxElement::RemoveAllAttributes()
  156. {
  157. int nCount = m_Attributes.Count();
  158. for ( int i = 0; i < nCount; ++i )
  159. {
  160. delete m_Attributes[i];
  161. }
  162. m_Attributes.RemoveAll();
  163. m_bResortNeeded = false;
  164. }
  165. //-----------------------------------------------------------------------------
  166. // Rename an attribute
  167. //-----------------------------------------------------------------------------
  168. void CDmxElement::RenameAttribute( const char *pAttributeName, const char *pNewName )
  169. {
  170. CDmxElementModifyScope modify( this );
  171. // No change...
  172. if ( !Q_stricmp( pAttributeName, pNewName ) )
  173. return;
  174. int idx = FindAttribute( pAttributeName );
  175. if ( idx < 0 )
  176. return;
  177. if ( HasAttribute( pNewName ) )
  178. {
  179. Warning( "Tried to rename from \"%s\" to \"%s\", but \"%s\" already exists!\n",
  180. pAttributeName, pNewName, pNewName );
  181. return;
  182. }
  183. m_bResortNeeded = true;
  184. m_Attributes[ idx ]->SetName( pNewName );
  185. }
  186. //-----------------------------------------------------------------------------
  187. // Find an attribute by name-based lookup
  188. //-----------------------------------------------------------------------------
  189. int CDmxElement::FindAttribute( const char *pAttributeName ) const
  190. {
  191. // FIXME: The cost here is O(log M) + O(log N)
  192. // where log N is the binary search for the symbol match
  193. // and log M is the binary search for the attribute name->symbol
  194. // We can eliminate log M by using a hash table in the symbol lookup
  195. Resort();
  196. CDmxAttribute search( pAttributeName );
  197. return m_Attributes.Find( &search );
  198. }
  199. //-----------------------------------------------------------------------------
  200. // Find an attribute by name-based lookup
  201. //-----------------------------------------------------------------------------
  202. int CDmxElement::FindAttribute( CUtlSymbolLarge attributeName ) const
  203. {
  204. Resort();
  205. CDmxAttribute search( attributeName );
  206. return m_Attributes.Find( &search );
  207. }
  208. //-----------------------------------------------------------------------------
  209. // Attribute finding
  210. //-----------------------------------------------------------------------------
  211. bool CDmxElement::HasAttribute( const char *pAttributeName ) const
  212. {
  213. int idx = FindAttribute( pAttributeName );
  214. return ( idx >= 0 );
  215. }
  216. CDmxAttribute *CDmxElement::GetAttribute( const char *pAttributeName )
  217. {
  218. int idx = FindAttribute( pAttributeName );
  219. if ( idx >= 0 )
  220. return m_Attributes[ idx ];
  221. return NULL;
  222. }
  223. const CDmxAttribute *CDmxElement::GetAttribute( const char *pAttributeName ) const
  224. {
  225. int idx = FindAttribute( pAttributeName );
  226. if ( idx >= 0 )
  227. return m_Attributes[ idx ];
  228. return NULL;
  229. }
  230. //-----------------------------------------------------------------------------
  231. // Attribute interation
  232. //-----------------------------------------------------------------------------
  233. int CDmxElement::AttributeCount() const
  234. {
  235. return m_Attributes.Count();
  236. }
  237. CDmxAttribute *CDmxElement::GetAttribute( int nIndex )
  238. {
  239. return m_Attributes[ nIndex ];
  240. }
  241. const CDmxAttribute *CDmxElement::GetAttribute( int nIndex ) const
  242. {
  243. return m_Attributes[ nIndex ];
  244. }
  245. //-----------------------------------------------------------------------------
  246. // Removes all elements recursively
  247. //-----------------------------------------------------------------------------
  248. void CDmxElement::AddElementsToDelete( CUtlVector< CDmxElement * >& elementsToDelete )
  249. {
  250. if ( m_bIsMarkedForDeletion )
  251. return;
  252. m_bIsMarkedForDeletion = true;
  253. elementsToDelete.AddToTail( this );
  254. int nCount = AttributeCount();
  255. for ( int i = 0; i < nCount; ++i )
  256. {
  257. CDmxAttribute *pAttribute = GetAttribute(i);
  258. if ( pAttribute->GetType() == AT_ELEMENT )
  259. {
  260. CDmxElement *pElement = pAttribute->GetValue< CDmxElement* >();
  261. if ( pElement )
  262. {
  263. pElement->AddElementsToDelete( elementsToDelete );
  264. }
  265. continue;
  266. }
  267. if ( pAttribute->GetType() == AT_ELEMENT_ARRAY )
  268. {
  269. const CUtlVector< CDmxElement * > &elements = pAttribute->GetArray< CDmxElement* >();
  270. int nElementCount = elements.Count();
  271. for ( int j = 0; j < nElementCount; ++j )
  272. {
  273. if ( elements[j] )
  274. {
  275. elements[j]->AddElementsToDelete( elementsToDelete );
  276. }
  277. }
  278. continue;
  279. }
  280. }
  281. }
  282. //-----------------------------------------------------------------------------
  283. // Removes all elements recursively
  284. //-----------------------------------------------------------------------------
  285. void CDmxElement::RemoveAllElementsRecursive()
  286. {
  287. CUtlVector< CDmxElement * > elementsToDelete;
  288. AddElementsToDelete( elementsToDelete );
  289. int nCount = elementsToDelete.Count();
  290. for ( int i = 0; i < nCount; ++i )
  291. {
  292. delete elementsToDelete[i];
  293. }
  294. }
  295. //-----------------------------------------------------------------------------
  296. // Template for unpacking a bitfield inside of an unpack structure.
  297. // pUnpack->m_nSize is the number of bits in the bitfield
  298. // pUnpack->m_nBitOffset is the number of bits to offset from pDest
  299. //-----------------------------------------------------------------------------
  300. template <typename T>
  301. void CDmxElement::UnpackBitfield( T *pDest, const DmxElementUnpackStructure_t *pUnpack, const CDmxAttribute *pAttribute ) const
  302. {
  303. // Determine if T is a signed type
  304. const bool bIsSigned = ( 0 > (T)(-1) );
  305. if ( bIsSigned )
  306. {
  307. // signed types need to be larger than 1 in size or else you get sign extension problems
  308. Assert( pUnpack->m_nSize > 1 );
  309. }
  310. // Right now the max size bitfield we handle is 32.
  311. Assert( pUnpack->m_nSize <= 32 );
  312. Assert( pUnpack->m_nSize <= 8*sizeof(T) );
  313. Assert( pUnpack->m_nBitOffset + pUnpack->m_nSize <= 8*sizeof(T) );
  314. // Create a mask that covers the bitfield.
  315. T mask;
  316. T maskBeforeShift;
  317. if ( pUnpack->m_nSize == 8*sizeof(T) )
  318. {
  319. maskBeforeShift = (T)~0;
  320. mask = maskBeforeShift;
  321. }
  322. else
  323. {
  324. maskBeforeShift = ( 1 << pUnpack->m_nSize ) - 1;
  325. mask = maskBeforeShift << pUnpack->m_nBitOffset;
  326. }
  327. mask = ~mask;
  328. T value = ( *(T *)pAttribute->m_pData );
  329. // Determine if value is in the range that this variable can hold.
  330. T signedMaskBeforeShift = bIsSigned ? ( 1 << (pUnpack->m_nSize-1) ) - 1 : maskBeforeShift;
  331. if ( !bIsSigned || ( value >= 0 ) )
  332. {
  333. if ( ( value & ~signedMaskBeforeShift ) != 0 )
  334. {
  335. Warning( "Value %s exeeds size of datatype. \n", pUnpack->m_pAttributeName );
  336. value = 0; // Clear value
  337. }
  338. }
  339. else
  340. {
  341. if ( !bIsSigned || ( ( value & ~signedMaskBeforeShift ) != ~signedMaskBeforeShift ) )
  342. {
  343. Warning( "Value %s exeeds size of datatype. \n", pUnpack->m_pAttributeName );
  344. value = 0; // Clear value
  345. }
  346. }
  347. // Mask value to the correct number of bits (important if value is a neg number!)
  348. value &= maskBeforeShift;
  349. // Pack it together.
  350. // Clear value
  351. *pDest &= mask;
  352. // Install value
  353. *pDest |= ( value << pUnpack->m_nBitOffset );
  354. }
  355. //-----------------------------------------------------------------------------
  356. // Method to unpack data into a structure
  357. //-----------------------------------------------------------------------------
  358. void CDmxElement::UnpackIntoStructure( void *pData, const DmxElementUnpackStructure_t *pUnpack ) const
  359. {
  360. for ( ; pUnpack->m_AttributeType != AT_UNKNOWN; ++pUnpack )
  361. {
  362. char *pDest = (char*)pData + pUnpack->m_nOffset;
  363. // Recurse?
  364. if ( pUnpack->m_pSub )
  365. {
  366. UnpackIntoStructure( (void *)pDest, pUnpack->m_pSub );
  367. continue;
  368. }
  369. if ( IsArrayType( pUnpack->m_AttributeType ) )
  370. {
  371. // NOTE: This does not work with string/bitfield array data at the moment
  372. if ( ( pUnpack->m_AttributeType == AT_STRING_ARRAY ) || ( pUnpack->m_nBitOffset != NO_BIT_OFFSET ) )
  373. {
  374. AssertMsg( 0, ( "CDmxElement::UnpackIntoStructure: String and bitfield array attribute types not currently supported!\n" ) );
  375. continue;
  376. }
  377. }
  378. if ( ( pUnpack->m_AttributeType == AT_VOID ) || ( pUnpack->m_AttributeType == AT_VOID_ARRAY ) )
  379. {
  380. AssertMsg( 0, ( "CDmxElement::UnpackIntoStructure: Binary blob attribute types not currently supported!\n" ) );
  381. continue;
  382. }
  383. CDmxAttribute temp( NULL );
  384. const CDmxAttribute *pAttribute = GetAttribute( pUnpack->m_pAttributeName );
  385. if ( !pAttribute )
  386. {
  387. if ( !pUnpack->m_pDefaultString )
  388. continue;
  389. temp.AllocateDataMemory_AndConstruct( pUnpack->m_AttributeType );
  390. if ( !IsArrayType( pUnpack->m_AttributeType ) )
  391. {
  392. // Convert the default string into the target (array types do this inside GetArrayValue below)
  393. temp.SetValueFromString( pUnpack->m_pDefaultString );
  394. }
  395. pAttribute = &temp;
  396. }
  397. if ( pUnpack->m_AttributeType != pAttribute->GetType() )
  398. {
  399. Warning( "CDmxElement::UnpackIntoStructure: Mismatched attribute type in attribute \"%s\"!\n", pUnpack->m_pAttributeName );
  400. continue;
  401. }
  402. if ( pAttribute->GetType() == AT_STRING )
  403. {
  404. if ( pUnpack->m_nSize == UTL_STRING_SIZE ) // the string is a UtlString.
  405. {
  406. *(CUtlString *)pDest = pAttribute->GetValueString();
  407. }
  408. else // the string is a preallocated char array.
  409. {
  410. // Strings get special treatment: they are stored as in-line arrays of chars
  411. Q_strncpy( pDest, pAttribute->GetValueString(), pUnpack->m_nSize );
  412. }
  413. continue;
  414. }
  415. // Get the basic type, if the attribute is an array:
  416. DmAttributeType_t basicType = CDmxAttribute::ArrayAttributeBasicType( pAttribute->GetType() );
  417. // Special case - if data type is float, but dest size == 16, we are unpacking into simd by replication
  418. if ( ( basicType == AT_FLOAT ) && ( pUnpack->m_nSize == sizeof( fltx4 ) ) )
  419. {
  420. if ( IsArrayType( pUnpack->m_AttributeType ) )
  421. {
  422. // Copy from the attribute into a fixed-size array:
  423. float *pfDest = (float *)pDest;
  424. const CUtlVector< float > &floatVector = pAttribute->GetArray< float >();
  425. for ( int i = 0; i < pUnpack->m_nArrayLength; i++ )
  426. {
  427. for ( int j = 0; j < 4; j++ ) memcpy( pfDest++, &floatVector[ i ], sizeof( float ) );
  428. }
  429. }
  430. else
  431. {
  432. memcpy( pDest + 0 * sizeof( float ), pAttribute->m_pData, sizeof( float ) );
  433. memcpy( pDest + 1 * sizeof( float ), pAttribute->m_pData, sizeof( float ) );
  434. memcpy( pDest + 2 * sizeof( float ), pAttribute->m_pData, sizeof( float ) );
  435. memcpy( pDest + 3 * sizeof( float ), pAttribute->m_pData, sizeof( float ) );
  436. }
  437. }
  438. else
  439. {
  440. int nDataTypeSize = pUnpack->m_nSize;
  441. if ( basicType == AT_INT )
  442. {
  443. if ( pUnpack->m_nBitOffset == NO_BIT_OFFSET ) // This test is not for bitfields
  444. {
  445. AssertMsg( nDataTypeSize <= CDmxAttribute::AttributeDataSize( basicType ),
  446. ( "CDmxElement::UnpackIntoStructure: Incorrect size to unpack data into in attribute \"%s\"!\n", pUnpack->m_pAttributeName ) );
  447. }
  448. }
  449. else
  450. {
  451. AssertMsg( nDataTypeSize == CDmxAttribute::AttributeDataSize( basicType ),
  452. ( "CDmxElement::UnpackIntoStructure: Incorrect size to unpack data into in attribute \"%s\"!\n", pUnpack->m_pAttributeName ) );
  453. }
  454. if ( IsArrayType( pUnpack->m_AttributeType ) )
  455. {
  456. // Copy from the attribute into a fixed-size array (padding with the default value if need be):
  457. pAttribute->GetArrayValue( pUnpack->m_AttributeType, pDest, nDataTypeSize, pUnpack->m_nArrayLength, pUnpack->m_pDefaultString );
  458. }
  459. else if ( pUnpack->m_nBitOffset == NO_BIT_OFFSET )
  460. {
  461. memcpy( pDest, pAttribute->m_pData, pUnpack->m_nSize );
  462. }
  463. else
  464. {
  465. if ( pAttribute->GetType() == AT_INT )
  466. {
  467. // Int attribute types are used for char/short/int.
  468. switch ( pUnpack->m_BitfieldType )
  469. {
  470. case BITFIELD_TYPE_BOOL:
  471. // Note: unsigned char handles bools as bitfields.
  472. UnpackBitfield( (unsigned char *)pDest, pUnpack, pAttribute );
  473. break;
  474. case BITFIELD_TYPE_CHAR :
  475. UnpackBitfield( (char *)pDest, pUnpack, pAttribute );
  476. break;
  477. case BITFIELD_TYPE_UNSIGNED_CHAR :
  478. UnpackBitfield( (unsigned char *)pDest, pUnpack, pAttribute );
  479. break;
  480. case BITFIELD_TYPE_SHORT :
  481. UnpackBitfield( (short *)pDest, pUnpack, pAttribute );
  482. break;
  483. case BITFIELD_TYPE_UNSIGNED_SHORT :
  484. UnpackBitfield( (unsigned short *)pDest, pUnpack, pAttribute );
  485. break;
  486. case BITFIELD_TYPE_INT :
  487. UnpackBitfield( (int *)pDest, pUnpack, pAttribute );
  488. break;
  489. case BITFIELD_TYPE_UNSIGNED_INT :
  490. UnpackBitfield( (unsigned int *)pDest, pUnpack, pAttribute );
  491. break;
  492. default:
  493. Assert(0);
  494. break;
  495. };
  496. }
  497. else
  498. {
  499. UnpackBitfield( (char *)pDest, pUnpack, pAttribute );
  500. }
  501. }
  502. }
  503. }
  504. }
  505. //-----------------------------------------------------------------------------
  506. // Creates attributes based on the unpack structure
  507. //-----------------------------------------------------------------------------
  508. void CDmxElement::AddAttributesFromStructure( const void *pData, const DmxElementUnpackStructure_t *pUnpack )
  509. {
  510. for ( ; pUnpack->m_AttributeType != AT_UNKNOWN; ++pUnpack )
  511. {
  512. const char *pSrc = (const char*)pData + pUnpack->m_nOffset;
  513. if ( pUnpack->m_pSub )
  514. {
  515. CDmxElement *pDest = CreateDmxElement( pUnpack->m_pTypeName );
  516. pDest->AddAttributesFromStructure( pSrc, pUnpack->m_pSub );
  517. SetValue( pUnpack->m_pAttributeName, pDest );
  518. continue;
  519. }
  520. if ( IsArrayType( pUnpack->m_AttributeType ) )
  521. {
  522. // NOTE: This does not work with string/bitfield array data at the moment
  523. if ( ( pUnpack->m_AttributeType == AT_STRING_ARRAY ) || ( pUnpack->m_nBitOffset != NO_BIT_OFFSET ) )
  524. {
  525. AssertMsg( 0, ( "CDmxElement::AddAttributesFromStructure: String and bitfield array attribute types not currently supported!\n" ) );
  526. continue;
  527. }
  528. }
  529. if ( ( pUnpack->m_AttributeType == AT_VOID ) || ( pUnpack->m_AttributeType == AT_VOID_ARRAY ) )
  530. {
  531. AssertMsg( 0, ( "CDmxElement::AddAttributesFromStructure: Binary blob attribute types not currently supported!\n" ) );
  532. continue;
  533. }
  534. if ( HasAttribute( pUnpack->m_pAttributeName ) )
  535. {
  536. AssertMsg( 0, ( "CDmxElement::AddAttributesFromStructure: Attribute %s already exists!\n", pUnpack->m_pAttributeName ) );
  537. continue;
  538. }
  539. {
  540. CDmxElementModifyScope modify( this );
  541. CDmxAttribute *pAttribute = AddAttribute( pUnpack->m_pAttributeName );
  542. if ( pUnpack->m_AttributeType == AT_STRING )
  543. {
  544. if ( pUnpack->m_nSize == UTL_STRING_SIZE ) // it is a UtlString.
  545. {
  546. const char *test = (*(CUtlString *)pSrc).Get();
  547. pAttribute->SetValue( test );
  548. }
  549. else
  550. {
  551. pAttribute->SetValue( pSrc );
  552. }
  553. }
  554. else
  555. {
  556. // Get the basic data type, if the attribute is an array:
  557. DmAttributeType_t basicType = CDmxAttribute::ArrayAttributeBasicType( pUnpack->m_AttributeType );
  558. int nDataTypeSize = pUnpack->m_nSize;
  559. // handle float attrs stored as replicated fltx4's
  560. if ( ( basicType == AT_FLOAT ) && ( nDataTypeSize == sizeof( fltx4 ) ) )
  561. {
  562. nDataTypeSize = sizeof( float );
  563. }
  564. if ( basicType == AT_INT )
  565. {
  566. if ( pUnpack->m_nBitOffset == NO_BIT_OFFSET ) // This test is not for bitfields.
  567. {
  568. AssertMsg( nDataTypeSize <= CDmxAttribute::AttributeDataSize( basicType ),
  569. ( "CDmxElement::UnpackIntoStructure: Incorrect size to unpack data into %s attribute \"%s\"!\n", CDmxAttribute::s_pAttributeTypeName[ pUnpack->m_AttributeType ], pUnpack->m_pAttributeName ) );
  570. }
  571. }
  572. else
  573. {
  574. AssertMsg( nDataTypeSize == CDmxAttribute::AttributeDataSize( basicType ),
  575. ( "CDmxElement::UnpackIntoStructure: Incorrect size to unpack data into %s attribute \"%s\"!\n", CDmxAttribute::s_pAttributeTypeName[ pUnpack->m_AttributeType ], pUnpack->m_pAttributeName ) );
  576. }
  577. if ( IsArrayType( pUnpack->m_AttributeType ) )
  578. {
  579. // Copy from a fixed-size array into the attribute:
  580. int nArrayStride = pUnpack->m_nSize;
  581. pAttribute->SetArrayValue( pUnpack->m_AttributeType, pSrc, nDataTypeSize, pUnpack->m_nArrayLength, nArrayStride );
  582. }
  583. else if ( pUnpack->m_nBitOffset == NO_BIT_OFFSET )
  584. {
  585. pAttribute->SetValue( pUnpack->m_AttributeType, pSrc, nDataTypeSize );
  586. }
  587. else
  588. {
  589. // Right now the max size bitfield we handle is 32.
  590. Assert( pUnpack->m_nBitOffset + pUnpack->m_nSize <= 32 );
  591. int mask = 0;
  592. if ( pUnpack->m_nSize == 32 )
  593. {
  594. mask = ~0;
  595. }
  596. else
  597. {
  598. mask = ( 1 << pUnpack->m_nSize ) - 1;
  599. mask <<= pUnpack->m_nBitOffset;
  600. }
  601. int value = ( ( *(int *)pSrc ) & mask );
  602. if ( ( pUnpack->m_BitfieldType == BITFIELD_TYPE_CHAR ) ||
  603. ( pUnpack->m_BitfieldType == BITFIELD_TYPE_SHORT ) ||
  604. ( pUnpack->m_BitfieldType == BITFIELD_TYPE_INT ) )
  605. {
  606. // move it all the way up to make sure we get the correct sign extension.
  607. value <<= ( 32 - ( pUnpack->m_nBitOffset + pUnpack->m_nSize ) );
  608. // move it back down into position.
  609. value >>= ( 32 - ( pUnpack->m_nBitOffset + pUnpack->m_nSize ) );
  610. }
  611. value >>= pUnpack->m_nBitOffset;
  612. pAttribute->SetValue( pUnpack->m_AttributeType, &value, sizeof( int ) );
  613. }
  614. }
  615. }
  616. }
  617. }