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.

788 lines
25 KiB

  1. //====== Copyright � 1996-2004, 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 "tier1/utlbufferutil.h"
  15. #include "DmElementFramework.h"
  16. //-----------------------------------------------------------------------------
  17. // Forward declarations
  18. //-----------------------------------------------------------------------------
  19. class CUtlBuffer;
  20. class CBaseSceneObject;
  21. //-----------------------------------------------------------------------------
  22. // special element indices
  23. //-----------------------------------------------------------------------------
  24. enum
  25. {
  26. ELEMENT_INDEX_NULL = -1,
  27. ELEMENT_INDEX_EXTERNAL = -2,
  28. };
  29. // Versions
  30. enum
  31. {
  32. DM_BINARY_VER_STRINGTABLE = 2,
  33. DM_BINARY_VER_GLOBAL_STRINGTABLE = 4, // stringtable used for all strings, and count is an int (symbols still shorts)
  34. DM_BINARY_VER_STRINGTABLE_LARGESYMBOLS = 5, // stringtable used for all strings, and count is an int (symbols are ints, too)
  35. };
  36. //-----------------------------------------------------------------------------
  37. // Serialization class for Binary output
  38. //-----------------------------------------------------------------------------
  39. class CDmSerializerBinary : public IDmSerializer
  40. {
  41. public:
  42. CDmSerializerBinary() {}
  43. // Inherited from IDMSerializer
  44. virtual const char *GetName() const { return "binary"; }
  45. virtual const char *GetDescription() const { return "Binary"; }
  46. virtual bool StoresVersionInFile() const { return true; }
  47. virtual bool IsBinaryFormat() const { return true; }
  48. virtual int GetCurrentVersion() const { return DM_BINARY_VER_STRINGTABLE_LARGESYMBOLS; }
  49. virtual const char *GetImportedFormat() const { return NULL; }
  50. virtual int GetImportedVersion() const { return 1; }
  51. virtual bool Serialize( CUtlBuffer &buf, CDmElement *pRoot );
  52. virtual bool Unserialize( CUtlBuffer &buf, const char *pEncodingName, int nEncodingVersion,
  53. const char *pSourceFormatName, int nFormatVersion,
  54. DmFileId_t fileid, DmConflictResolution_t idConflictResolution, CDmElement **ppRoot );
  55. private:
  56. // For serialize
  57. typedef CUtlDict< int, int > mapSymbolToIndex_t;
  58. // For unserialize
  59. typedef CUtlMap< int, CUtlSymbolLarge > mapIndexToSymbol_t;
  60. // Methods related to serialization
  61. void SerializeElementIndex( CUtlBuffer& buf, CDmElementSerializationDictionary& list, DmElementHandle_t hElement, DmFileId_t fileid );
  62. void SerializeElementAttribute( CUtlBuffer& buf, CDmElementSerializationDictionary& list, CDmAttribute *pAttribute );
  63. void SerializeElementArrayAttribute( CUtlBuffer& buf, CDmElementSerializationDictionary& list, CDmAttribute *pAttribute );
  64. bool SerializeAttributes( CUtlBuffer& buf, CDmElementSerializationDictionary& list, mapSymbolToIndex_t *pStringValueSymbols, CDmElement *pElement );
  65. bool SaveElementDict( CUtlBuffer& buf, mapSymbolToIndex_t *pStringValueSymbols, CDmElement *pElement );
  66. bool SaveElement( CUtlBuffer& buf, CDmElementSerializationDictionary& dict, mapSymbolToIndex_t *pStringValueSymbols, CDmElement *pElement);
  67. void GatherSymbols( CUtlSymbolTableLarge *pStringValueSymbols, CDmElement *pElement );
  68. // Methods related to unserialization
  69. DmElementHandle_t UnserializeElementIndex( CUtlBuffer &buf, CUtlVector<CDmElement*> &elementList );
  70. void UnserializeElementAttribute( CUtlBuffer &buf, CDmAttribute *pAttribute, CUtlVector<CDmElement*> &elementList );
  71. void UnserializeElementArrayAttribute( CUtlBuffer &buf, CDmAttribute *pAttribute, CUtlVector<CDmElement*> &elementList );
  72. void UnserializeStringArrayAttribute( CUtlBuffer &buf, CDmAttribute *pAttribute, CUtlString &tempString );
  73. bool UnserializeAttributes( CUtlBuffer &buf, CDmElement *pElement, CUtlVector<CDmElement*> &elementList, mapIndexToSymbol_t *pSymbolTable, int nEncodingVersion );
  74. bool UnserializeElements( CUtlBuffer &buf, DmFileId_t fileid, DmConflictResolution_t idConflictResolution, CDmElement **ppRoot, mapIndexToSymbol_t *pSymbolTable, int nEncodingVersion );
  75. void GetStringTable( CUtlBuffer &buf, int nStrings, int nEncodingVersion, mapIndexToSymbol_t *pMap );
  76. inline char const *Dme_GetStringFromBuffer( CUtlBuffer &buf, bool bUseLargeSymbols, mapIndexToSymbol_t *pMap )
  77. {
  78. unsigned int uSym = ( bUseLargeSymbols ) ? buf.GetInt() : buf.GetShort();
  79. return pMap->Element( uSym ).String();
  80. }
  81. inline CUtlSymbolLarge Dme_GetSymbolFromBuffer( CUtlBuffer &buf, bool bUseLargeSymbols, mapIndexToSymbol_t *pMap )
  82. {
  83. unsigned int uSym = ( bUseLargeSymbols ) ? buf.GetInt() : buf.GetShort();
  84. return pMap->Element( uSym );
  85. }
  86. };
  87. //-----------------------------------------------------------------------------
  88. // Singleton instance
  89. //-----------------------------------------------------------------------------
  90. static CDmSerializerBinary s_DMSerializerBinary;
  91. void InstallBinarySerializer( IDataModel *pFactory )
  92. {
  93. pFactory->AddSerializer( &s_DMSerializerBinary );
  94. }
  95. //-----------------------------------------------------------------------------
  96. // Write out the index of the element to avoid looks at read time
  97. //-----------------------------------------------------------------------------
  98. void CDmSerializerBinary::SerializeElementIndex( CUtlBuffer& buf, CDmElementSerializationDictionary& list, DmElementHandle_t hElement, DmFileId_t fileid )
  99. {
  100. if ( hElement == DMELEMENT_HANDLE_INVALID )
  101. {
  102. buf.PutInt( ELEMENT_INDEX_NULL ); // invalid handle
  103. }
  104. else
  105. {
  106. CDmElement *pElement = g_pDataModel->GetElement( hElement );
  107. if ( pElement )
  108. {
  109. if ( pElement->GetFileId() == fileid )
  110. {
  111. buf.PutInt( list.Find( pElement ) );
  112. }
  113. else
  114. {
  115. buf.PutInt( ELEMENT_INDEX_EXTERNAL );
  116. char idstr[ 40 ];
  117. UniqueIdToString( pElement->GetId(), idstr, sizeof( idstr ) );
  118. buf.PutString( idstr );
  119. }
  120. }
  121. else
  122. {
  123. DmObjectId_t *pId = NULL;
  124. DmElementReference_t *pRef = g_pDataModelImp->FindElementReference( hElement, &pId );
  125. if ( pRef && pId )
  126. {
  127. buf.PutInt( ELEMENT_INDEX_EXTERNAL );
  128. char idstr[ 40 ];
  129. UniqueIdToString( *pId, idstr, sizeof( idstr ) );
  130. buf.PutString( idstr );
  131. }
  132. else
  133. {
  134. buf.PutInt( ELEMENT_INDEX_NULL ); // invalid handle
  135. }
  136. }
  137. }
  138. }
  139. //-----------------------------------------------------------------------------
  140. // Writes out element attributes
  141. //-----------------------------------------------------------------------------
  142. void CDmSerializerBinary::SerializeElementAttribute( CUtlBuffer& buf, CDmElementSerializationDictionary& list, CDmAttribute *pAttribute )
  143. {
  144. SerializeElementIndex( buf, list, pAttribute->GetValue< DmElementHandle_t >(), pAttribute->GetOwner()->GetFileId() );
  145. }
  146. //-----------------------------------------------------------------------------
  147. // Writes out element array attributes
  148. //-----------------------------------------------------------------------------
  149. void CDmSerializerBinary::SerializeElementArrayAttribute( CUtlBuffer& buf, CDmElementSerializationDictionary& list, CDmAttribute *pAttribute )
  150. {
  151. DmFileId_t fileid = pAttribute->GetOwner()->GetFileId();
  152. CDmrElementArray<> vec( pAttribute );
  153. int nCount = vec.Count();
  154. buf.PutInt( nCount );
  155. for ( int i = 0; i < nCount; ++i )
  156. {
  157. SerializeElementIndex( buf, list, vec.GetHandle(i), fileid );
  158. }
  159. }
  160. //-----------------------------------------------------------------------------
  161. // Writes out all attributes
  162. //-----------------------------------------------------------------------------
  163. bool CDmSerializerBinary::SerializeAttributes( CUtlBuffer& buf, CDmElementSerializationDictionary& list, mapSymbolToIndex_t *pStringValueSymbols, CDmElement *pElement )
  164. {
  165. // Collect the attributes to be written
  166. CDmAttribute **ppAttributes = ( CDmAttribute** )_alloca( pElement->AttributeCount() * sizeof( CDmAttribute* ) );
  167. int nAttributes = 0;
  168. for ( CDmAttribute *pAttribute = pElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
  169. {
  170. if ( pAttribute->IsStandard() || pAttribute->IsFlagSet( FATTRIB_DONTSAVE ) )
  171. continue;
  172. ppAttributes[ nAttributes++ ] = pAttribute;
  173. }
  174. // Now write them all out in reverse order, since FirstAttribute is actually the *last* attribute for perf reasons
  175. buf.PutInt( nAttributes );
  176. for ( int i = nAttributes - 1; i >= 0; --i )
  177. {
  178. CDmAttribute *pAttribute = ppAttributes[ i ];
  179. Assert( pAttribute );
  180. buf.PutInt( pStringValueSymbols->Find(pAttribute->GetName()) );
  181. buf.PutChar( pAttribute->GetType() );
  182. switch( pAttribute->GetType() )
  183. {
  184. default:
  185. pAttribute->Serialize( buf );
  186. break;
  187. case AT_ELEMENT:
  188. SerializeElementAttribute( buf, list, pAttribute );
  189. break;
  190. case AT_ELEMENT_ARRAY:
  191. SerializeElementArrayAttribute( buf, list, pAttribute );
  192. break;
  193. case AT_STRING:
  194. buf.PutInt( pStringValueSymbols->Find(pAttribute->GetValueString()) );
  195. break;
  196. }
  197. }
  198. return buf.IsValid();
  199. }
  200. bool CDmSerializerBinary::SaveElement( CUtlBuffer& buf, CDmElementSerializationDictionary& list, mapSymbolToIndex_t *pStringValueSymbols, CDmElement *pElement )
  201. {
  202. SerializeAttributes( buf, list, pStringValueSymbols, pElement );
  203. return buf.IsValid();
  204. }
  205. bool CDmSerializerBinary::SaveElementDict( CUtlBuffer& buf, mapSymbolToIndex_t *pStringValueSymbols, CDmElement *pElement )
  206. {
  207. buf.PutInt( pStringValueSymbols->Find( pElement->GetTypeString() ) );
  208. buf.PutInt( pStringValueSymbols->Find( pElement->GetName() ) );
  209. buf.Put( &pElement->GetId(), sizeof(DmObjectId_t) );
  210. return buf.IsValid();
  211. }
  212. void CDmSerializerBinary::GatherSymbols( CUtlSymbolTableLarge *pStringValueSymbols, CDmElement *pElement )
  213. {
  214. pStringValueSymbols->AddString( pElement->GetTypeString() );
  215. pStringValueSymbols->AddString( pElement->GetName() );
  216. for ( CDmAttribute *pAttr = pElement->FirstAttribute(); pAttr; pAttr = pAttr->NextAttribute() )
  217. {
  218. pStringValueSymbols->AddString( pAttr->GetName() );
  219. if ( pAttr->GetType() == AT_STRING )
  220. {
  221. pStringValueSymbols->AddString( pAttr->GetValueString() );
  222. }
  223. }
  224. }
  225. bool CDmSerializerBinary::Serialize( CUtlBuffer &outBuf, CDmElement *pRoot )
  226. {
  227. // Save elements, attribute links
  228. CDmElementSerializationDictionary dict;
  229. dict.BuildElementList( pRoot, true );
  230. DmElementDictHandle_t i;
  231. CUtlSymbolTableLarge stringSymbols;
  232. for ( i = dict.FirstRootElement(); i != ELEMENT_DICT_HANDLE_INVALID; i = dict.NextRootElement(i) )
  233. {
  234. GatherSymbols( &stringSymbols, dict.GetRootElement( i ) );
  235. }
  236. // write out the symbol table for this file (may be significantly smaller than datamodel's full symbol table)
  237. int nSymbols = stringSymbols.GetNumStrings();
  238. outBuf.PutInt( nSymbols );
  239. CUtlVector< CUtlSymbolLarge > symbols;
  240. symbols.EnsureCount( nSymbols );
  241. stringSymbols.GetElements( 0, nSymbols, symbols.Base() );
  242. // It's case sensitive
  243. mapSymbolToIndex_t symbolToIndexMap( k_eDictCompareTypeCaseSensitive );
  244. // Build the helper map based on the gathered symbols
  245. for ( int si = 0; si < nSymbols; ++si )
  246. {
  247. CUtlSymbolLarge sym = symbols[ si ];
  248. const char *pStr = sym.String();
  249. symbolToIndexMap.Insert( pStr, si );
  250. outBuf.PutString( pStr );
  251. }
  252. // First write out the dictionary of all elements (to avoid later stitching up in unserialize)
  253. outBuf.PutInt( dict.RootElementCount() );
  254. for ( i = dict.FirstRootElement(); i != ELEMENT_DICT_HANDLE_INVALID; i = dict.NextRootElement(i) )
  255. {
  256. SaveElementDict( outBuf, &symbolToIndexMap, dict.GetRootElement( i ) );
  257. }
  258. // Now write out the attributes of each of those elements
  259. for ( i = dict.FirstRootElement(); i != ELEMENT_DICT_HANDLE_INVALID; i = dict.NextRootElement(i) )
  260. {
  261. SaveElement( outBuf, dict, &symbolToIndexMap, dict.GetRootElement( i ) );
  262. }
  263. return true;
  264. }
  265. //-----------------------------------------------------------------------------
  266. // Reads an element index and converts it to a handle (local or external)
  267. //-----------------------------------------------------------------------------
  268. DmElementHandle_t CDmSerializerBinary::UnserializeElementIndex( CUtlBuffer &buf, CUtlVector<CDmElement*> &elementList )
  269. {
  270. int nElementIndex = buf.GetInt();
  271. Assert( nElementIndex < elementList.Count() );
  272. if ( nElementIndex == ELEMENT_INDEX_EXTERNAL )
  273. {
  274. char idstr[ 40 ];
  275. buf.GetString( idstr, sizeof( idstr ) );
  276. DmObjectId_t id;
  277. UniqueIdFromString( &id, idstr, sizeof( idstr ) );
  278. return g_pDataModelImp->FindOrCreateElementHandle( id );
  279. }
  280. Assert( nElementIndex >= 0 || nElementIndex == ELEMENT_INDEX_NULL );
  281. if ( nElementIndex < 0 || !elementList[ nElementIndex ] )
  282. return DMELEMENT_HANDLE_INVALID;
  283. return elementList[ nElementIndex ]->GetHandle();
  284. }
  285. //-----------------------------------------------------------------------------
  286. // Reads an element attribute
  287. //-----------------------------------------------------------------------------
  288. void CDmSerializerBinary::UnserializeElementAttribute( CUtlBuffer &buf, CDmAttribute *pAttribute, CUtlVector<CDmElement*> &elementList )
  289. {
  290. DmElementHandle_t hElement = UnserializeElementIndex( buf, elementList );
  291. if ( !pAttribute )
  292. return;
  293. pAttribute->SetValue( hElement );
  294. }
  295. //-----------------------------------------------------------------------------
  296. // Reads an element array attribute
  297. //-----------------------------------------------------------------------------
  298. void CDmSerializerBinary::UnserializeElementArrayAttribute( CUtlBuffer &buf, CDmAttribute *pAttribute, CUtlVector<CDmElement*> &elementList )
  299. {
  300. int nElementCount = buf.GetInt();
  301. if ( !pAttribute || pAttribute->GetType() != AT_ELEMENT_ARRAY )
  302. {
  303. // Parse past the data
  304. for ( int i = 0; i < nElementCount; ++i )
  305. {
  306. UnserializeElementIndex( buf, elementList );
  307. }
  308. return;
  309. }
  310. CDmrElementArray<> array( pAttribute );
  311. array.RemoveAll();
  312. array.EnsureCapacity( nElementCount );
  313. for ( int i = 0; i < nElementCount; ++i )
  314. {
  315. DmElementHandle_t hElement = UnserializeElementIndex( buf, elementList );
  316. array.AddToTail( hElement );
  317. }
  318. }
  319. //-----------------------------------------------------------------------------
  320. // Read an array of strings
  321. //-----------------------------------------------------------------------------
  322. void CDmSerializerBinary::UnserializeStringArrayAttribute( CUtlBuffer &buf, CDmAttribute *pAttribute, CUtlString &tempString )
  323. {
  324. CDmrStringArray stringArray( pAttribute );
  325. stringArray.RemoveAll();
  326. if ( buf.IsText() )
  327. {
  328. while ( true )
  329. {
  330. buf.EatWhiteSpace();
  331. if ( !buf.IsValid() )
  332. break;
  333. if ( !::Unserialize( buf, tempString ) )
  334. return;
  335. stringArray.AddToTail( tempString.Get() );
  336. }
  337. }
  338. else
  339. {
  340. int nNumStrings = buf.GetInt();
  341. if ( nNumStrings )
  342. {
  343. stringArray.EnsureCapacity( nNumStrings );
  344. for ( int i = 0; i < nNumStrings; ++i )
  345. {
  346. if ( !::Unserialize( buf, tempString ) )
  347. return;
  348. stringArray.AddToTail( tempString.Get() );
  349. }
  350. }
  351. }
  352. }
  353. //-----------------------------------------------------------------------------
  354. // Reads a single element
  355. //-----------------------------------------------------------------------------
  356. bool CDmSerializerBinary::UnserializeAttributes( CUtlBuffer &buf, CDmElement *pElement, CUtlVector<CDmElement*> &elementList, mapIndexToSymbol_t *pSymbolTable, int nEncodingVersion )
  357. {
  358. char nameBuf[ 1024 ];
  359. CUtlString tempString;
  360. tempString.SetLength( 1024 );
  361. bool bReadTimeAsObjectId = nEncodingVersion < 3; // version 3 and up put AT_TIME in the same slot that AT_OBJECTID used to be
  362. bool bUseLargeSymbols = nEncodingVersion >= DM_BINARY_VER_STRINGTABLE_LARGESYMBOLS;
  363. int nAttributeCount = buf.GetInt();
  364. for ( int i = 0; i < nAttributeCount; ++i )
  365. {
  366. const char *pName = NULL;
  367. {
  368. DMX_PROFILE_SCOPE( UnserializeAttributes_GetNameString );
  369. if ( pSymbolTable )
  370. {
  371. pName = Dme_GetStringFromBuffer( buf, bUseLargeSymbols, pSymbolTable );
  372. }
  373. else
  374. {
  375. buf.GetString( nameBuf, sizeof( nameBuf ) );
  376. pName = nameBuf;
  377. }
  378. }
  379. DmAttributeType_t nAttributeType = (DmAttributeType_t)buf.GetChar();
  380. Assert( pName != NULL && pName[ 0 ] != '\0' );
  381. Assert( nAttributeType != AT_UNKNOWN );
  382. if ( nAttributeType == AT_TIME && bReadTimeAsObjectId )
  383. {
  384. Warning( "CDmSerializerBinary: Removing deprecated objectid attribute '%s' of element '%s'\n", pName, pElement->GetName() );
  385. DmObjectId_t id;
  386. ::Unserialize( buf, id );
  387. continue;
  388. }
  389. CDmAttribute *pAttribute = NULL;
  390. {
  391. DMX_PROFILE_SCOPE( UnserializeAttributes_AddAttribute );
  392. pAttribute = pElement ? pElement->AddAttribute( pName, nAttributeType ) : NULL;
  393. if ( pElement && !pAttribute )
  394. {
  395. CDmAttribute *pExistingAttr = pElement->GetAttribute( pName );
  396. if ( pExistingAttr )
  397. {
  398. Warning( "CDmSerializerBinary: Attribute '%s' of element '%s' read as '%s' but expected '%s'\n",
  399. pName, pElement->GetName(), GetTypeString( nAttributeType ), pExistingAttr->GetTypeString() );
  400. }
  401. else
  402. {
  403. Warning( "CDmSerializerBinary: Unknown error reading '%s' attribute '%s' of element '%s'\n",
  404. GetTypeString( nAttributeType ), pName, pElement->GetName() );
  405. return false;
  406. }
  407. }
  408. }
  409. switch( nAttributeType )
  410. {
  411. default:
  412. {
  413. DMX_PROFILE_SCOPE( UnserializeAttributes_Unserialize );
  414. if ( !pAttribute )
  415. {
  416. SkipUnserialize( buf, nAttributeType );
  417. }
  418. else
  419. {
  420. pAttribute->Unserialize( buf );
  421. }
  422. }
  423. break;
  424. case AT_ELEMENT:
  425. {
  426. DMX_PROFILE_SCOPE( UnserializeAttributes_UnserializeElementAttr );
  427. UnserializeElementAttribute( buf, pAttribute, elementList );
  428. }
  429. break;
  430. case AT_ELEMENT_ARRAY:
  431. {
  432. DMX_PROFILE_SCOPE( UnserializeAttributes_UnserializeElementArrayAttr );
  433. UnserializeElementArrayAttribute( buf, pAttribute, elementList );
  434. }
  435. break;
  436. case AT_STRING:
  437. {
  438. DMX_PROFILE_SCOPE( UnserializeAttributes_UnserializeStringAttr );
  439. if ( pSymbolTable && nEncodingVersion >= DM_BINARY_VER_GLOBAL_STRINGTABLE )
  440. {
  441. CUtlSymbolLarge symbol = Dme_GetSymbolFromBuffer( buf, bUseLargeSymbols, pSymbolTable );
  442. if ( pAttribute )
  443. {
  444. pAttribute->SetValue( symbol );
  445. }
  446. }
  447. else
  448. {
  449. if ( !pAttribute )
  450. {
  451. SkipUnserialize( buf, nAttributeType );
  452. }
  453. else
  454. {
  455. ::Unserialize( buf, tempString );
  456. pAttribute->SetValue( tempString.Get() );
  457. }
  458. }
  459. }
  460. break;
  461. case AT_STRING_ARRAY:
  462. {
  463. DMX_PROFILE_SCOPE( UnserializeAttributes_UnserializeStringArrayAttr );
  464. if ( !pAttribute )
  465. {
  466. SkipUnserialize( buf, nAttributeType );
  467. }
  468. else
  469. {
  470. UnserializeStringArrayAttribute( buf, pAttribute, tempString );
  471. }
  472. }
  473. break;
  474. }
  475. }
  476. return buf.IsValid();
  477. }
  478. struct DmIdPair_t
  479. {
  480. DmObjectId_t m_oldId;
  481. DmObjectId_t m_newId;
  482. DmIdPair_t &operator=( const DmIdPair_t &that )
  483. {
  484. CopyUniqueId( that.m_oldId, &m_oldId );
  485. CopyUniqueId( that.m_newId, &m_newId );
  486. return *this;
  487. }
  488. static unsigned int HashKey( const DmIdPair_t& that )
  489. {
  490. return *( unsigned int* )&that.m_oldId.m_Value;
  491. }
  492. static bool Compare( const DmIdPair_t& a, const DmIdPair_t& b )
  493. {
  494. return IsUniqueIdEqual( a.m_oldId, b.m_oldId );
  495. }
  496. };
  497. DmElementHandle_t CreateElementWithFallback( const char *pType, const char *pName, DmFileId_t fileid, const DmObjectId_t &id )
  498. {
  499. DmElementHandle_t hElement = g_pDataModel->CreateElement( pType, pName, fileid, &id );
  500. if ( hElement == DMELEMENT_HANDLE_INVALID )
  501. {
  502. Warning("Binary: Element uses unknown element type %s\n", pType );
  503. hElement = g_pDataModel->CreateElement( "DmElement", pName, fileid, &id );
  504. Assert( hElement != DMELEMENT_HANDLE_INVALID );
  505. }
  506. return hElement;
  507. }
  508. void CDmSerializerBinary::GetStringTable( CUtlBuffer &buf, int nStrings, int nEncodingVersion, mapIndexToSymbol_t *pMap )
  509. {
  510. char pStrBuf[2048];
  511. for ( int i = 0; i < nStrings; ++i )
  512. {
  513. buf.GetString( pStrBuf, sizeof(pStrBuf) );
  514. CUtlSymbolLarge sym = g_pDataModel->GetSymbol( pStrBuf );
  515. pMap->Insert( i, sym );
  516. }
  517. }
  518. //-----------------------------------------------------------------------------
  519. // Main entry point for the unserialization
  520. //-----------------------------------------------------------------------------
  521. bool CDmSerializerBinary::Unserialize( CUtlBuffer &buf, const char *pEncodingName, int nEncodingVersion,
  522. const char *pSourceFormatName, int nSourceFormatVersion,
  523. DmFileId_t fileid, DmConflictResolution_t idConflictResolution, CDmElement **ppRoot )
  524. {
  525. DMX_PROFILE_SCOPE( CDmSerializerBinary_Unserialize );
  526. Assert( !V_stricmp( pEncodingName, GetName() ) );
  527. if ( V_stricmp( pEncodingName, GetName() ) != 0 )
  528. return false;
  529. Assert( nEncodingVersion >= 0 && nEncodingVersion <= GetCurrentVersion() );
  530. if ( nEncodingVersion < 0 || nEncodingVersion > GetCurrentVersion() )
  531. return false;
  532. bool bReadSymbolTable = nEncodingVersion >= DM_BINARY_VER_STRINGTABLE;
  533. // Read string table
  534. int nStrings = 0;
  535. mapIndexToSymbol_t indexToSymbolMap( 0, 0, DefLessFunc( int ) );
  536. if ( bReadSymbolTable )
  537. {
  538. if ( nEncodingVersion >= DM_BINARY_VER_GLOBAL_STRINGTABLE )
  539. {
  540. nStrings = buf.GetInt();
  541. }
  542. else
  543. {
  544. nStrings = buf.GetShort();
  545. }
  546. GetStringTable( buf, nStrings, nEncodingVersion, &indexToSymbolMap );
  547. }
  548. bool bSuccess = UnserializeElements( buf, fileid, idConflictResolution, ppRoot, bReadSymbolTable?(&indexToSymbolMap):NULL, nEncodingVersion );
  549. if ( !bSuccess )
  550. return false;
  551. return g_pDataModel->UpdateUnserializedElements( pSourceFormatName, nSourceFormatVersion, fileid, idConflictResolution, ppRoot );
  552. }
  553. bool CDmSerializerBinary::UnserializeElements( CUtlBuffer &buf, DmFileId_t fileid, DmConflictResolution_t idConflictResolution, CDmElement **ppRoot, mapIndexToSymbol_t *pSymbolTable, int nEncodingVersion )
  554. {
  555. DMX_PROFILE_SCOPE( CDmSerializerBinary_UnserializeElements );
  556. *ppRoot = NULL;
  557. bool bLargeSymbols = nEncodingVersion >= DM_BINARY_VER_STRINGTABLE_LARGESYMBOLS;
  558. // Read in the element count.
  559. int nElementCount = buf.GetInt();
  560. if ( !nElementCount )
  561. return true;
  562. CElementIdHash hashExistingElements;
  563. if ( CR_FORCE_COPY != idConflictResolution )
  564. {
  565. DMX_PROFILE_SCOPE( UnserializeElements_GetExistingElements );
  566. g_pDataModel->GetExistingElements( hashExistingElements );
  567. }
  568. UtlHashHandle_t hashInvalidHandle = hashExistingElements.InvalidHandle();
  569. // Read + create all elements
  570. char nameBuf[ 2048 ];
  571. char typeBuf[ 512 ];
  572. CUtlVector<CDmElement*> elementList( 0, nElementCount );
  573. for ( int i = 0; i < nElementCount; ++i )
  574. {
  575. const char *pName = NULL;
  576. const char *pType = NULL;
  577. DmObjectId_t id;
  578. {
  579. DMX_PROFILE_SCOPE( UnserializeElements_TypeAndName_GetString );
  580. if ( pSymbolTable )
  581. {
  582. pType = Dme_GetStringFromBuffer( buf, bLargeSymbols, pSymbolTable );
  583. }
  584. else
  585. {
  586. buf.GetString( typeBuf, sizeof(typeBuf) );
  587. pType = typeBuf;
  588. }
  589. if ( pSymbolTable && nEncodingVersion >= DM_BINARY_VER_GLOBAL_STRINGTABLE )
  590. {
  591. pName = Dme_GetStringFromBuffer( buf, bLargeSymbols, pSymbolTable );
  592. }
  593. else
  594. {
  595. buf.GetString( nameBuf, sizeof(nameBuf) );
  596. pName = nameBuf;
  597. }
  598. }
  599. buf.Get( &id, sizeof(DmObjectId_t) );
  600. DmElementHandle_t hElement = DMELEMENT_HANDLE_INVALID;
  601. if ( idConflictResolution == CR_FORCE_COPY )
  602. {
  603. CreateUniqueId( &id );
  604. }
  605. else
  606. {
  607. DMX_PROFILE_SCOPE( UnserializeElements_ConflictCheck );
  608. UtlHashHandle_t search = hashExistingElements.Find( id );
  609. DmElementHandle_t hExistingElement = ( search == hashInvalidHandle ? DMELEMENT_HANDLE_INVALID : hashExistingElements[ search ] );
  610. if ( hExistingElement != DMELEMENT_HANDLE_INVALID )
  611. {
  612. // id is already in use - need to resolve conflict
  613. if ( idConflictResolution == CR_DELETE_NEW )
  614. {
  615. elementList.AddToTail( g_pDataModel->GetElement( hExistingElement ) );
  616. continue; // just don't create this element
  617. }
  618. else if ( idConflictResolution == CR_DELETE_OLD )
  619. {
  620. g_pDataModelImp->DeleteElement( hExistingElement, HR_NEVER ); // keep the handle around until CreateElementWithFallback
  621. hElement = CreateElementWithFallback( pType, pName, fileid, id );
  622. Assert( hElement == hExistingElement );
  623. }
  624. else if ( idConflictResolution == CR_COPY_NEW )
  625. {
  626. CreateUniqueId( &id );
  627. hElement = CreateElementWithFallback( pType, pName, fileid, id );
  628. }
  629. else
  630. {
  631. Assert( 0 );
  632. }
  633. }
  634. }
  635. // if not found, then create it
  636. if ( hElement == DMELEMENT_HANDLE_INVALID )
  637. {
  638. DMX_PROFILE_SCOPE( UnserializeElements_CreateElementWithFallback );
  639. hElement = CreateElementWithFallback( pType, pName, fileid, id );
  640. }
  641. CDmElement *pElement = g_pDataModel->GetElement( hElement );
  642. CDmeElementAccessor::DisableOnChangedCallbacks( pElement );
  643. elementList.AddToTail( pElement );
  644. }
  645. // The root is the 0th element
  646. *ppRoot = elementList[ 0 ];
  647. {
  648. DMX_PROFILE_SCOPE( UnserializeElements_UnserializeAttributes );
  649. // Now read all attributes
  650. for ( int i = 0; i < nElementCount; ++i )
  651. {
  652. CDmElement *pInternal = elementList[ i ];
  653. if ( !UnserializeAttributes( buf, pInternal->GetFileId() == fileid ? pInternal : NULL, elementList, pSymbolTable, nEncodingVersion ) )
  654. return false;
  655. }
  656. }
  657. {
  658. DMX_PROFILE_SCOPE( UnserializeElements_MarkNotBeingUnserializedAndResolve );
  659. for ( int i = 0; i < nElementCount; ++i )
  660. {
  661. CDmElement *pElement = elementList[ i ];
  662. if ( pElement->GetFileId() == fileid )
  663. {
  664. // mark all unserialized elements as done unserializing, and call Resolve()
  665. CDmeElementAccessor::EnableOnChangedCallbacks( pElement );
  666. CDmeElementAccessor::FinishUnserialization( pElement );
  667. }
  668. }
  669. }
  670. g_pDmElementFrameworkImp->RemoveCleanElementsFromDirtyList( );
  671. return buf.IsValid();
  672. }