Team Fortress 2 Source Code as on 22/4/2020
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.

587 lines
20 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "dmserializerbinary.h"
  7. #include "datamodel/idatamodel.h"
  8. #include "datamodel.h"
  9. #include "datamodel/dmelement.h"
  10. #include "datamodel/dmattributevar.h"
  11. #include "dmattributeinternal.h"
  12. #include "dmelementdictionary.h"
  13. #include "tier1/utlbuffer.h"
  14. #include "DmElementFramework.h"
  15. //-----------------------------------------------------------------------------
  16. // Forward declarations
  17. //-----------------------------------------------------------------------------
  18. class CUtlBuffer;
  19. class CBaseSceneObject;
  20. //-----------------------------------------------------------------------------
  21. // special element indices
  22. //-----------------------------------------------------------------------------
  23. enum
  24. {
  25. ELEMENT_INDEX_NULL = -1,
  26. ELEMENT_INDEX_EXTERNAL = -2,
  27. };
  28. //-----------------------------------------------------------------------------
  29. // Serialization class for Binary output
  30. //-----------------------------------------------------------------------------
  31. class CDmSerializerBinary : public IDmSerializer
  32. {
  33. public:
  34. CDmSerializerBinary() {}
  35. // Inherited from IDMSerializer
  36. virtual const char *GetName() const { return "binary"; }
  37. virtual const char *GetDescription() const { return "Binary"; }
  38. virtual bool StoresVersionInFile() const { return true; }
  39. virtual bool IsBinaryFormat() const { return true; }
  40. virtual int GetCurrentVersion() const { return 2; }
  41. virtual bool Serialize( CUtlBuffer &buf, CDmElement *pRoot );
  42. virtual bool Unserialize( CUtlBuffer &buf, const char *pEncodingName, int nEncodingVersion,
  43. const char *pSourceFormatName, int nFormatVersion,
  44. DmFileId_t fileid, DmConflictResolution_t idConflictResolution, CDmElement **ppRoot );
  45. private:
  46. // Methods related to serialization
  47. void SerializeElementIndex( CUtlBuffer& buf, CDmElementSerializationDictionary& list, DmElementHandle_t hElement, DmFileId_t fileid );
  48. void SerializeElementAttribute( CUtlBuffer& buf, CDmElementSerializationDictionary& list, CDmAttribute *pAttribute );
  49. void SerializeElementArrayAttribute( CUtlBuffer& buf, CDmElementSerializationDictionary& list, CDmAttribute *pAttribute );
  50. bool SerializeAttributes( CUtlBuffer& buf, CDmElementSerializationDictionary& list, unsigned short *symbolToIndexMap, CDmElement *pElement );
  51. bool SaveElementDict( CUtlBuffer& buf, unsigned short *symbolToIndexMap, CDmElement *pElement );
  52. bool SaveElement( CUtlBuffer& buf, CDmElementSerializationDictionary& dict, unsigned short *symbolToIndexMap, CDmElement *pElement);
  53. // Methods related to unserialization
  54. DmElementHandle_t UnserializeElementIndex( CUtlBuffer &buf, CUtlVector<CDmElement*> &elementList );
  55. void UnserializeElementAttribute( CUtlBuffer &buf, CDmAttribute *pAttribute, CUtlVector<CDmElement*> &elementList );
  56. void UnserializeElementArrayAttribute( CUtlBuffer &buf, CDmAttribute *pAttribute, CUtlVector<CDmElement*> &elementList );
  57. bool UnserializeAttributes( CUtlBuffer &buf, CDmElement *pElement, CUtlVector<CDmElement*> &elementList, UtlSymId_t *symbolTable );
  58. bool UnserializeElements( CUtlBuffer &buf, DmFileId_t fileid, DmConflictResolution_t idConflictResolution, CDmElement **ppRoot, UtlSymId_t *symbolTable );
  59. };
  60. //-----------------------------------------------------------------------------
  61. // Singleton instance
  62. //-----------------------------------------------------------------------------
  63. static CDmSerializerBinary s_DMSerializerBinary;
  64. void InstallBinarySerializer( IDataModel *pFactory )
  65. {
  66. pFactory->AddSerializer( &s_DMSerializerBinary );
  67. }
  68. //-----------------------------------------------------------------------------
  69. // Write out the index of the element to avoid looks at read time
  70. //-----------------------------------------------------------------------------
  71. void CDmSerializerBinary::SerializeElementIndex( CUtlBuffer& buf, CDmElementSerializationDictionary& list, DmElementHandle_t hElement, DmFileId_t fileid )
  72. {
  73. if ( hElement == DMELEMENT_HANDLE_INVALID )
  74. {
  75. buf.PutInt( ELEMENT_INDEX_NULL ); // invalid handle
  76. }
  77. else
  78. {
  79. CDmElement *pElement = g_pDataModel->GetElement( hElement );
  80. if ( pElement )
  81. {
  82. if ( pElement->GetFileId() == fileid )
  83. {
  84. buf.PutInt( list.Find( pElement ) );
  85. }
  86. else
  87. {
  88. buf.PutInt( ELEMENT_INDEX_EXTERNAL );
  89. char idstr[ 40 ];
  90. UniqueIdToString( pElement->GetId(), idstr, sizeof( idstr ) );
  91. buf.PutString( idstr );
  92. }
  93. }
  94. else
  95. {
  96. DmObjectId_t *pId = NULL;
  97. DmElementReference_t *pRef = g_pDataModelImp->FindElementReference( hElement, &pId );
  98. if ( pRef && pId )
  99. {
  100. buf.PutInt( ELEMENT_INDEX_EXTERNAL );
  101. char idstr[ 40 ];
  102. UniqueIdToString( *pId, idstr, sizeof( idstr ) );
  103. buf.PutString( idstr );
  104. }
  105. else
  106. {
  107. buf.PutInt( ELEMENT_INDEX_NULL ); // invalid handle
  108. }
  109. }
  110. }
  111. }
  112. //-----------------------------------------------------------------------------
  113. // Writes out element attributes
  114. //-----------------------------------------------------------------------------
  115. void CDmSerializerBinary::SerializeElementAttribute( CUtlBuffer& buf, CDmElementSerializationDictionary& list, CDmAttribute *pAttribute )
  116. {
  117. SerializeElementIndex( buf, list, pAttribute->GetValue< DmElementHandle_t >(), pAttribute->GetOwner()->GetFileId() );
  118. }
  119. //-----------------------------------------------------------------------------
  120. // Writes out element array attributes
  121. //-----------------------------------------------------------------------------
  122. void CDmSerializerBinary::SerializeElementArrayAttribute( CUtlBuffer& buf, CDmElementSerializationDictionary& list, CDmAttribute *pAttribute )
  123. {
  124. DmFileId_t fileid = pAttribute->GetOwner()->GetFileId();
  125. CDmrElementArray<> vec( pAttribute );
  126. int nCount = vec.Count();
  127. buf.PutInt( nCount );
  128. for ( int i = 0; i < nCount; ++i )
  129. {
  130. SerializeElementIndex( buf, list, vec.GetHandle(i), fileid );
  131. }
  132. }
  133. //-----------------------------------------------------------------------------
  134. // Writes out all attributes
  135. //-----------------------------------------------------------------------------
  136. bool CDmSerializerBinary::SerializeAttributes( CUtlBuffer& buf, CDmElementSerializationDictionary& list, unsigned short *symbolToIndexMap, CDmElement *pElement )
  137. {
  138. // Collect the attributes to be written
  139. CDmAttribute **ppAttributes = ( CDmAttribute** )_alloca( pElement->AttributeCount() * sizeof( CDmAttribute* ) );
  140. int nAttributes = 0;
  141. for ( CDmAttribute *pAttribute = pElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
  142. {
  143. if ( pAttribute->IsFlagSet( FATTRIB_DONTSAVE | FATTRIB_STANDARD ) )
  144. continue;
  145. ppAttributes[ nAttributes++ ] = pAttribute;
  146. }
  147. // Now write them all out in reverse order, since FirstAttribute is actually the *last* attribute for perf reasons
  148. buf.PutInt( nAttributes );
  149. for ( int i = nAttributes - 1; i >= 0; --i )
  150. {
  151. CDmAttribute *pAttribute = ppAttributes[ i ];
  152. Assert( pAttribute );
  153. buf.PutShort( symbolToIndexMap[ pAttribute->GetNameSymbol() ] );
  154. buf.PutChar( pAttribute->GetType() );
  155. switch( pAttribute->GetType() )
  156. {
  157. default:
  158. pAttribute->Serialize( buf );
  159. break;
  160. case AT_ELEMENT:
  161. SerializeElementAttribute( buf, list, pAttribute );
  162. break;
  163. case AT_ELEMENT_ARRAY:
  164. SerializeElementArrayAttribute( buf, list, pAttribute );
  165. break;
  166. }
  167. }
  168. return buf.IsValid();
  169. }
  170. bool CDmSerializerBinary::SaveElement( CUtlBuffer& buf, CDmElementSerializationDictionary& list, unsigned short *symbolToIndexMap, CDmElement *pElement )
  171. {
  172. SerializeAttributes( buf, list, symbolToIndexMap, pElement );
  173. return buf.IsValid();
  174. }
  175. bool CDmSerializerBinary::SaveElementDict( CUtlBuffer& buf, unsigned short *symbolToIndexMap, CDmElement *pElement )
  176. {
  177. buf.PutShort( symbolToIndexMap[ pElement->GetType() ] );
  178. buf.PutString( pElement->GetName() );
  179. buf.Put( &pElement->GetId(), sizeof(DmObjectId_t) );
  180. return buf.IsValid();
  181. }
  182. void MarkSymbol( UtlSymId_t *indexToSymbolMap, unsigned short *symbolToIndexMap, unsigned short &nSymbols, UtlSymId_t sym )
  183. {
  184. if ( symbolToIndexMap[ sym ] != 0xffff )
  185. return;
  186. symbolToIndexMap[ sym ] = nSymbols;
  187. indexToSymbolMap[ nSymbols ] = sym;
  188. nSymbols++;
  189. }
  190. void MarkSymbols( UtlSymId_t *indexToSymbolMap, unsigned short *symbolToIndexMap, unsigned short &nSymbols, CDmElement *pElement )
  191. {
  192. MarkSymbol( indexToSymbolMap, symbolToIndexMap, nSymbols, pElement->GetType() );
  193. for ( CDmAttribute *pAttr = pElement->FirstAttribute(); pAttr; pAttr = pAttr->NextAttribute() )
  194. {
  195. MarkSymbol( indexToSymbolMap, symbolToIndexMap, nSymbols, pAttr->GetNameSymbol() );
  196. }
  197. }
  198. bool CDmSerializerBinary::Serialize( CUtlBuffer &outBuf, CDmElement *pRoot )
  199. {
  200. // Save elements, attribute links
  201. CDmElementSerializationDictionary dict;
  202. dict.BuildElementList( pRoot, true );
  203. // TODO - consider allowing dmxconvert to skip the collection step, since the only datamodel symbols will be the ones from the file
  204. unsigned short nTotalSymbols = g_pDataModelImp->GetSymbolCount();
  205. UtlSymId_t *indexToSymbolMap = ( UtlSymId_t * )stackalloc( nTotalSymbols * sizeof( UtlSymId_t ) );
  206. unsigned short *symbolToIndexMap = ( unsigned short* )stackalloc( nTotalSymbols * sizeof( unsigned short ) );
  207. V_memset( indexToSymbolMap, 0xff, nTotalSymbols * sizeof( UtlSymId_t ) );
  208. V_memset( symbolToIndexMap, 0xff, nTotalSymbols * sizeof( unsigned short ) );
  209. // collect list of attribute names and element types into string table
  210. unsigned short nUsedSymbols = 0;
  211. DmElementDictHandle_t i;
  212. for ( i = dict.FirstRootElement(); i != ELEMENT_DICT_HANDLE_INVALID; i = dict.NextRootElement(i) )
  213. {
  214. MarkSymbols( indexToSymbolMap, symbolToIndexMap, nUsedSymbols, dict.GetRootElement( i ) );
  215. }
  216. Assert( nUsedSymbols <= nTotalSymbols );
  217. // write out the symbol table for this file (may be significantly smaller than datamodel's full symbol table)
  218. outBuf.PutShort( nUsedSymbols );
  219. for ( int si = 0; si < nUsedSymbols; ++si )
  220. {
  221. UtlSymId_t sym = indexToSymbolMap[ si ];
  222. const char *pStr = g_pDataModel->GetString( sym );
  223. outBuf.PutString( pStr );
  224. }
  225. // First write out the dictionary of all elements (to avoid later stitching up in unserialize)
  226. outBuf.PutInt( dict.RootElementCount() );
  227. for ( i = dict.FirstRootElement(); i != ELEMENT_DICT_HANDLE_INVALID; i = dict.NextRootElement(i) )
  228. {
  229. SaveElementDict( outBuf, symbolToIndexMap, dict.GetRootElement( i ) );
  230. }
  231. // Now write out the attributes of each of those elements
  232. for ( i = dict.FirstRootElement(); i != ELEMENT_DICT_HANDLE_INVALID; i = dict.NextRootElement(i) )
  233. {
  234. SaveElement( outBuf, dict, symbolToIndexMap, dict.GetRootElement( i ) );
  235. }
  236. return true;
  237. }
  238. //-----------------------------------------------------------------------------
  239. // Reads an element index and converts it to a handle (local or external)
  240. //-----------------------------------------------------------------------------
  241. DmElementHandle_t CDmSerializerBinary::UnserializeElementIndex( CUtlBuffer &buf, CUtlVector<CDmElement*> &elementList )
  242. {
  243. int nElementIndex = buf.GetInt();
  244. Assert( nElementIndex < elementList.Count() );
  245. if ( nElementIndex == ELEMENT_INDEX_EXTERNAL )
  246. {
  247. char idstr[ 40 ];
  248. buf.GetString( idstr );
  249. DmObjectId_t id;
  250. UniqueIdFromString( &id, idstr, sizeof( idstr ) );
  251. return g_pDataModelImp->FindOrCreateElementHandle( id );
  252. }
  253. Assert( nElementIndex >= 0 || nElementIndex == ELEMENT_INDEX_NULL );
  254. if ( nElementIndex < 0 || !elementList[ nElementIndex ] )
  255. return DMELEMENT_HANDLE_INVALID;
  256. return elementList[ nElementIndex ]->GetHandle();
  257. }
  258. //-----------------------------------------------------------------------------
  259. // Reads an element attribute
  260. //-----------------------------------------------------------------------------
  261. void CDmSerializerBinary::UnserializeElementAttribute( CUtlBuffer &buf, CDmAttribute *pAttribute, CUtlVector<CDmElement*> &elementList )
  262. {
  263. DmElementHandle_t hElement = UnserializeElementIndex( buf, elementList );
  264. if ( !pAttribute )
  265. return;
  266. pAttribute->SetValue( hElement );
  267. }
  268. //-----------------------------------------------------------------------------
  269. // Reads an element array attribute
  270. //-----------------------------------------------------------------------------
  271. void CDmSerializerBinary::UnserializeElementArrayAttribute( CUtlBuffer &buf, CDmAttribute *pAttribute, CUtlVector<CDmElement*> &elementList )
  272. {
  273. int nElementCount = buf.GetInt();
  274. if ( !pAttribute || pAttribute->GetType() != AT_ELEMENT_ARRAY )
  275. {
  276. // Parse past the data
  277. for ( int i = 0; i < nElementCount; ++i )
  278. {
  279. UnserializeElementIndex( buf, elementList );
  280. }
  281. return;
  282. }
  283. CDmrElementArray<> array( pAttribute );
  284. array.RemoveAll();
  285. array.EnsureCapacity( nElementCount );
  286. for ( int i = 0; i < nElementCount; ++i )
  287. {
  288. DmElementHandle_t hElement = UnserializeElementIndex( buf, elementList );
  289. array.AddToTail( hElement );
  290. }
  291. }
  292. //-----------------------------------------------------------------------------
  293. // Reads a single element
  294. //-----------------------------------------------------------------------------
  295. bool CDmSerializerBinary::UnserializeAttributes( CUtlBuffer &buf, CDmElement *pElement, CUtlVector<CDmElement*> &elementList, UtlSymId_t *symbolTable )
  296. {
  297. char nameBuf[ 1024 ];
  298. int nAttributeCount = buf.GetInt();
  299. for ( int i = 0; i < nAttributeCount; ++i )
  300. {
  301. const char *pName = NULL;
  302. if ( symbolTable )
  303. {
  304. unsigned short nName = buf.GetShort();
  305. pName = g_pDataModel->GetString( symbolTable[ nName ] );
  306. }
  307. else
  308. {
  309. buf.GetString( nameBuf );
  310. pName = nameBuf;
  311. }
  312. DmAttributeType_t nAttributeType = (DmAttributeType_t)buf.GetChar();
  313. Assert( pName != NULL && pName[ 0 ] != '\0' );
  314. Assert( nAttributeType != AT_UNKNOWN );
  315. CDmAttribute *pAttribute = pElement ? pElement->AddAttribute( pName, nAttributeType ) : NULL;
  316. if ( pElement && !pAttribute )
  317. {
  318. Warning("Dm: Attempted to read an attribute (\"%s\") of an inappropriate type!\n", pName );
  319. return false;
  320. }
  321. switch( nAttributeType )
  322. {
  323. default:
  324. if ( !pAttribute )
  325. {
  326. SkipUnserialize( buf, nAttributeType );
  327. }
  328. else
  329. {
  330. pAttribute->Unserialize( buf );
  331. }
  332. break;
  333. case AT_ELEMENT:
  334. UnserializeElementAttribute( buf, pAttribute, elementList );
  335. break;
  336. case AT_ELEMENT_ARRAY:
  337. UnserializeElementArrayAttribute( buf, pAttribute, elementList );
  338. break;
  339. }
  340. }
  341. return buf.IsValid();
  342. }
  343. struct DmIdPair_t
  344. {
  345. DmObjectId_t m_oldId;
  346. DmObjectId_t m_newId;
  347. DmIdPair_t &operator=( const DmIdPair_t &that )
  348. {
  349. CopyUniqueId( that.m_oldId, &m_oldId );
  350. CopyUniqueId( that.m_newId, &m_newId );
  351. return *this;
  352. }
  353. static unsigned int HashKey( const DmIdPair_t& that )
  354. {
  355. return *( unsigned int* )&that.m_oldId.m_Value;
  356. }
  357. static bool Compare( const DmIdPair_t& a, const DmIdPair_t& b )
  358. {
  359. return IsUniqueIdEqual( a.m_oldId, b.m_oldId );
  360. }
  361. };
  362. DmElementHandle_t CreateElementWithFallback( const char *pType, const char *pName, DmFileId_t fileid, const DmObjectId_t &id )
  363. {
  364. DmElementHandle_t hElement = g_pDataModel->CreateElement( pType, pName, fileid, &id );
  365. if ( hElement == DMELEMENT_HANDLE_INVALID )
  366. {
  367. Warning("Binary: Element uses unknown element type %s\n", pType );
  368. hElement = g_pDataModel->CreateElement( "DmElement", pName, fileid, &id );
  369. Assert( hElement != DMELEMENT_HANDLE_INVALID );
  370. }
  371. return hElement;
  372. }
  373. //-----------------------------------------------------------------------------
  374. // Main entry point for the unserialization
  375. //-----------------------------------------------------------------------------
  376. bool CDmSerializerBinary::Unserialize( CUtlBuffer &buf, const char *pEncodingName, int nEncodingVersion,
  377. const char *pSourceFormatName, int nSourceFormatVersion,
  378. DmFileId_t fileid, DmConflictResolution_t idConflictResolution, CDmElement **ppRoot )
  379. {
  380. Assert( !V_stricmp( pEncodingName, GetName() ) );
  381. if ( V_stricmp( pEncodingName, GetName() ) != 0 )
  382. return false;
  383. Assert( nEncodingVersion >= 0 && nEncodingVersion <= 2 );
  384. if ( nEncodingVersion < 0 || nEncodingVersion > 2 )
  385. return false;
  386. bool bReadSymbolTable = nEncodingVersion >= 2;
  387. // Read string table
  388. unsigned short nStrings = 0;
  389. UtlSymId_t *symbolTable = NULL;
  390. if ( bReadSymbolTable )
  391. {
  392. char stringBuf[ 256 ];
  393. nStrings = buf.GetShort();
  394. symbolTable = ( UtlSymId_t* )stackalloc( nStrings * sizeof( UtlSymId_t ) );
  395. for ( int i = 0; i < nStrings; ++i )
  396. {
  397. buf.GetString( stringBuf );
  398. symbolTable[ i ] = g_pDataModel->GetSymbol( stringBuf );
  399. }
  400. }
  401. bool bSuccess = UnserializeElements( buf, fileid, idConflictResolution, ppRoot, symbolTable );
  402. if ( !bSuccess )
  403. return false;
  404. return g_pDataModel->UpdateUnserializedElements( pSourceFormatName, nSourceFormatVersion, fileid, idConflictResolution, ppRoot );
  405. }
  406. bool CDmSerializerBinary::UnserializeElements( CUtlBuffer &buf, DmFileId_t fileid, DmConflictResolution_t idConflictResolution, CDmElement **ppRoot, UtlSymId_t *symbolTable )
  407. {
  408. *ppRoot = NULL;
  409. // Read in the element count.
  410. int nElementCount = buf.GetInt();
  411. if ( !nElementCount )
  412. return true;
  413. int nMaxIdConflicts = min( nElementCount, g_pDataModel->GetAllocatedElementCount() );
  414. int nExpectedIdCopyConflicts = ( idConflictResolution == CR_FORCE_COPY || idConflictResolution == CR_COPY_NEW ) ? nMaxIdConflicts : 0;
  415. int nBuckets = min( 0x10000, max( 16, nExpectedIdCopyConflicts / 16 ) ); // CUtlHash can only address up to 65k buckets
  416. CUtlHash< DmIdPair_t > idmap( nBuckets, 0, 0, DmIdPair_t::Compare, DmIdPair_t::HashKey );
  417. // Read + create all elements
  418. CUtlVector<CDmElement*> elementList( 0, nElementCount );
  419. for ( int i = 0; i < nElementCount; ++i )
  420. {
  421. char pName[2048];
  422. DmObjectId_t id;
  423. char typeBuf[ 256 ];
  424. const char *pType = NULL;
  425. if ( symbolTable )
  426. {
  427. unsigned short nType = buf.GetShort();
  428. pType = g_pDataModel->GetString( symbolTable[ nType ] );
  429. }
  430. else
  431. {
  432. buf.GetString( typeBuf );
  433. pType = typeBuf;
  434. }
  435. buf.GetString( pName );
  436. buf.Get( &id, sizeof(DmObjectId_t) );
  437. if ( idConflictResolution == CR_FORCE_COPY )
  438. {
  439. DmIdPair_t idpair;
  440. CopyUniqueId( id, &idpair.m_oldId );
  441. CreateUniqueId( &idpair.m_newId );
  442. idmap.Insert( idpair );
  443. CopyUniqueId( idpair.m_newId, &id );
  444. }
  445. DmElementHandle_t hElement = DMELEMENT_HANDLE_INVALID;
  446. DmElementHandle_t hExistingElement = g_pDataModel->FindElement( id );
  447. if ( hExistingElement != DMELEMENT_HANDLE_INVALID )
  448. {
  449. // id is already in use - need to resolve conflict
  450. if ( idConflictResolution == CR_DELETE_NEW )
  451. {
  452. elementList.AddToTail( g_pDataModel->GetElement( hExistingElement ) );
  453. continue; // just don't create this element
  454. }
  455. else if ( idConflictResolution == CR_DELETE_OLD )
  456. {
  457. g_pDataModelImp->DeleteElement( hExistingElement, HR_NEVER ); // keep the handle around until CreateElementWithFallback
  458. hElement = CreateElementWithFallback( pType, pName, fileid, id );
  459. Assert( hElement == hExistingElement );
  460. }
  461. else if ( idConflictResolution == CR_COPY_NEW )
  462. {
  463. DmIdPair_t idpair;
  464. CopyUniqueId( id, &idpair.m_oldId );
  465. CreateUniqueId( &idpair.m_newId );
  466. idmap.Insert( idpair );
  467. hElement = CreateElementWithFallback( pType, pName, fileid, idpair.m_newId );
  468. }
  469. else
  470. Assert( 0 );
  471. }
  472. // if not found, then create it
  473. if ( hElement == DMELEMENT_HANDLE_INVALID )
  474. {
  475. hElement = CreateElementWithFallback( pType, pName, fileid, id );
  476. }
  477. CDmElement *pElement = g_pDataModel->GetElement( hElement );
  478. CDmeElementAccessor::MarkBeingUnserialized( pElement, true );
  479. elementList.AddToTail( pElement );
  480. }
  481. // The root is the 0th element
  482. *ppRoot = elementList[ 0 ];
  483. // Now read all attributes
  484. for ( int i = 0; i < nElementCount; ++i )
  485. {
  486. CDmElement *pInternal = elementList[ i ];
  487. UnserializeAttributes( buf, pInternal->GetFileId() == fileid ? pInternal : NULL, elementList, symbolTable );
  488. }
  489. for ( int i = 0; i < nElementCount; ++i )
  490. {
  491. CDmElement *pElement = elementList[ i ];
  492. if ( pElement->GetFileId() == fileid )
  493. {
  494. // mark all unserialized elements as done unserializing, and call Resolve()
  495. CDmeElementAccessor::MarkBeingUnserialized( pElement, false );
  496. }
  497. }
  498. g_pDmElementFrameworkImp->RemoveCleanElementsFromDirtyList( );
  499. return buf.IsValid();
  500. }