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.

1388 lines
40 KiB

  1. //====== Copyright � 1996-2004, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "dmserializerkeyvalues2.h"
  7. #include <ctype.h>
  8. #include "datamodel/idatamodel.h"
  9. #include "datamodel.h"
  10. #include "datamodel/dmelement.h"
  11. #include "datamodel/dmattributevar.h"
  12. #include "dmattributeinternal.h"
  13. #include "dmelementdictionary.h"
  14. #include "DmElementFramework.h"
  15. #include "tier1/utlbuffer.h"
  16. #include <limits.h>
  17. //-----------------------------------------------------------------------------
  18. // Forward declarations
  19. //-----------------------------------------------------------------------------
  20. class CUtlBuffer;
  21. //-----------------------------------------------------------------------------
  22. // a simple class to keep track of a stack of valid parsed symbols
  23. //-----------------------------------------------------------------------------
  24. class CKeyValues2ErrorStack
  25. {
  26. public:
  27. CKeyValues2ErrorStack();
  28. // Sets the filename to report with errors; sets the line number to 0
  29. void SetFilename( const char *pFilename );
  30. // Current line control
  31. void IncrementCurrentLine();
  32. void SetCurrentLine( int nLine );
  33. int GetCurrentLine() const;
  34. // entering a new keyvalues block, save state for errors
  35. // Not save symbols instead of pointers because the pointers can move!
  36. int Push( CUtlSymbolLarge symName );
  37. // exiting block, error isn't in this block, remove.
  38. void Pop();
  39. // Allows you to keep the same stack level, but change the name as you parse peers
  40. void Reset( int stackLevel, CUtlSymbolLarge symName );
  41. // Hit an error, report it and the parsing stack for context
  42. void ReportError( const char *pError, ... );
  43. private:
  44. enum
  45. {
  46. MAX_ERROR_STACK = 64
  47. };
  48. CUtlSymbolLarge m_errorStack[MAX_ERROR_STACK];
  49. const char *m_pFilename;
  50. int m_nFileLine;
  51. int m_errorIndex;
  52. int m_maxErrorIndex;
  53. };
  54. //-----------------------------------------------------------------------------
  55. // Singleton instance
  56. //-----------------------------------------------------------------------------
  57. static CKeyValues2ErrorStack g_KeyValues2ErrorStack;
  58. //-----------------------------------------------------------------------------
  59. // Constructor
  60. //-----------------------------------------------------------------------------
  61. CKeyValues2ErrorStack::CKeyValues2ErrorStack() :
  62. m_pFilename("NULL"), m_errorIndex(0), m_maxErrorIndex(0), m_nFileLine(1)
  63. {
  64. }
  65. //-----------------------------------------------------------------------------
  66. // Sets the filename
  67. //-----------------------------------------------------------------------------
  68. void CKeyValues2ErrorStack::SetFilename( const char *pFilename )
  69. {
  70. m_pFilename = pFilename;
  71. m_maxErrorIndex = 0;
  72. m_nFileLine = 1;
  73. }
  74. //-----------------------------------------------------------------------------
  75. // Current line control
  76. //-----------------------------------------------------------------------------
  77. void CKeyValues2ErrorStack::IncrementCurrentLine()
  78. {
  79. ++m_nFileLine;
  80. }
  81. void CKeyValues2ErrorStack::SetCurrentLine( int nLine )
  82. {
  83. m_nFileLine = nLine;
  84. }
  85. int CKeyValues2ErrorStack::GetCurrentLine() const
  86. {
  87. return m_nFileLine;
  88. }
  89. //-----------------------------------------------------------------------------
  90. // entering a new keyvalues block, save state for errors
  91. // Not save symbols instead of pointers because the pointers can move!
  92. //-----------------------------------------------------------------------------
  93. int CKeyValues2ErrorStack::Push( CUtlSymbolLarge symName )
  94. {
  95. if ( m_errorIndex < MAX_ERROR_STACK )
  96. {
  97. m_errorStack[m_errorIndex] = symName;
  98. }
  99. m_errorIndex++;
  100. m_maxErrorIndex = MAX( m_maxErrorIndex, (m_errorIndex-1) );
  101. return m_errorIndex-1;
  102. }
  103. //-----------------------------------------------------------------------------
  104. // exiting block, error isn't in this block, remove.
  105. //-----------------------------------------------------------------------------
  106. void CKeyValues2ErrorStack::Pop()
  107. {
  108. m_errorIndex--;
  109. Assert(m_errorIndex>=0);
  110. }
  111. //-----------------------------------------------------------------------------
  112. // Allows you to keep the same stack level, but change the name as you parse peers
  113. //-----------------------------------------------------------------------------
  114. void CKeyValues2ErrorStack::Reset( int stackLevel, CUtlSymbolLarge symName )
  115. {
  116. Assert( stackLevel >= 0 && stackLevel < m_errorIndex );
  117. m_errorStack[stackLevel] = symName;
  118. }
  119. //-----------------------------------------------------------------------------
  120. // Hit an error, report it and the parsing stack for context
  121. //-----------------------------------------------------------------------------
  122. void CKeyValues2ErrorStack::ReportError( const char *pFmt, ... )
  123. {
  124. char temp[2048];
  125. va_list args;
  126. va_start( args, pFmt );
  127. Q_vsnprintf( temp, sizeof( temp ), pFmt, args );
  128. va_end( args );
  129. char temp2[2048];
  130. Q_snprintf( temp2, sizeof( temp2 ), "%s(%d) : %s\n", m_pFilename, m_nFileLine, temp );
  131. Warning( temp2 );
  132. for ( int i = 0; i < m_maxErrorIndex; i++ )
  133. {
  134. if ( !m_errorStack[i].IsValid() )
  135. continue;
  136. if ( i < m_errorIndex )
  137. {
  138. Warning( "%s, ", m_errorStack[i].String() );
  139. }
  140. else
  141. {
  142. Warning( "(*%s*), ", m_errorStack[i].String() );
  143. }
  144. }
  145. Warning( "\n" );
  146. }
  147. //-----------------------------------------------------------------------------
  148. // a simple helper that creates stack entries as it goes in & out of scope
  149. //-----------------------------------------------------------------------------
  150. class CKeyValues2ErrorContext
  151. {
  152. public:
  153. CKeyValues2ErrorContext( const char *pSymName )
  154. {
  155. Init( g_pDataModel->GetSymbol( pSymName ) );
  156. }
  157. CKeyValues2ErrorContext( CUtlSymbolLarge symName )
  158. {
  159. Init( symName );
  160. }
  161. ~CKeyValues2ErrorContext()
  162. {
  163. g_KeyValues2ErrorStack.Pop();
  164. }
  165. void Reset( CUtlSymbolLarge symName )
  166. {
  167. g_KeyValues2ErrorStack.Reset( m_stackLevel, symName );
  168. }
  169. private:
  170. void Init( CUtlSymbolLarge symName )
  171. {
  172. m_stackLevel = g_KeyValues2ErrorStack.Push( symName );
  173. }
  174. int m_stackLevel;
  175. };
  176. //-----------------------------------------------------------------------------
  177. // Serialization class for Key Values 2
  178. //-----------------------------------------------------------------------------
  179. class CDmSerializerKeyValues2 : public IDmSerializer
  180. {
  181. public:
  182. CDmSerializerKeyValues2( bool bFlatMode ) : m_bFlatMode( bFlatMode ) {}
  183. // Inherited from IDMSerializer
  184. virtual const char *GetName() const { return m_bFlatMode ? "keyvalues2_flat" : "keyvalues2"; }
  185. virtual const char *GetDescription() const { return m_bFlatMode ? "KeyValues2 (flat)" : "KeyValues2"; }
  186. virtual bool StoresVersionInFile() const { return true; }
  187. virtual bool IsBinaryFormat() const { return false; }
  188. virtual int GetCurrentVersion() const { return 1; }
  189. virtual int GetImportedVersion() const { return 1; }
  190. virtual bool Serialize( CUtlBuffer &buf, CDmElement *pRoot );
  191. virtual bool Unserialize( CUtlBuffer &buf, const char *pEncodingName, int nEncodingVersion,
  192. const char *pSourceFormatName, int nSourceFormatVersion,
  193. DmFileId_t fileid, DmConflictResolution_t idConflictResolution, CDmElement **ppRoot );
  194. virtual const char *GetImportedFormat() const { return NULL; }
  195. private:
  196. enum TokenType_t
  197. {
  198. TOKEN_INVALID = -1, // A bogus token
  199. TOKEN_OPEN_BRACE, // {
  200. TOKEN_CLOSE_BRACE, // }
  201. TOKEN_OPEN_BRACKET, // [
  202. TOKEN_CLOSE_BRACKET, // ]
  203. TOKEN_COMMA, // ,
  204. // TOKEN_STRING, // Any non-quoted string
  205. TOKEN_DELIMITED_STRING, // Any quoted string
  206. TOKEN_INCLUDE, // #include
  207. TOKEN_EOF, // End of buffer
  208. };
  209. // Methods related to serialization
  210. void SerializeArrayAttribute( CUtlBuffer& buf, CDmAttribute *pAttribute );
  211. void SerializeElementAttribute( CUtlBuffer& buf, CDmElementSerializationDictionary &dict, CDmAttribute *pAttribute );
  212. void SerializeElementArrayAttribute( CUtlBuffer& buf, CDmElementSerializationDictionary &dict, CDmAttribute *pAttribute );
  213. bool SerializeAttributes( CUtlBuffer& buf, CDmElementSerializationDictionary &dict, CDmElement *pElement );
  214. bool SaveElement( CUtlBuffer& buf, CDmElementSerializationDictionary &dict, CDmElement *pElement, bool bWriteDelimiters = true );
  215. // Methods related to unserialization
  216. void EatWhitespacesAndComments( CUtlBuffer &buf );
  217. TokenType_t ReadToken( CUtlBuffer &buf, CUtlBuffer &token );
  218. DmElementDictHandle_t CreateDmElement( const char *pElementType );
  219. bool UnserializeAttributeValueFromToken( CDmAttribute *pAttribute, CUtlBuffer &tokenBuf );
  220. bool UnserializeElementAttribute( CUtlBuffer &buf, DmElementDictHandle_t hElement, const char *pAttributeName, const char *pElementType );
  221. bool UnserializeElementArrayAttribute( CUtlBuffer &buf, DmElementDictHandle_t hElement, const char *pAttributeName );
  222. bool UnserializeArrayAttribute( CUtlBuffer &buf, DmElementDictHandle_t hElement, const char *pAttributeName, DmAttributeType_t nAttrType );
  223. bool UnserializeAttribute( CUtlBuffer &buf, DmElementDictHandle_t hElement, const char *pAttributeName, DmAttributeType_t nAttrType );
  224. bool UnserializeElement( CUtlBuffer &buf, const char *pElementType, DmElementDictHandle_t *pHandle );
  225. bool UnserializeElement( CUtlBuffer &buf, DmElementDictHandle_t *pHandle );
  226. bool UnserializeElements( CUtlBuffer &buf, DmFileId_t fileid, DmConflictResolution_t idConflictResolution, CDmElement **ppRoot );
  227. // For unserialization
  228. CDmElementDictionary m_ElementDict;
  229. DmElementDictHandle_t m_hRoot;
  230. bool m_bFlatMode;
  231. DmConflictResolution_t m_idConflictResolution;
  232. DmFileId_t m_fileid;
  233. };
  234. //-----------------------------------------------------------------------------
  235. // Singleton instance
  236. //-----------------------------------------------------------------------------
  237. static CDmSerializerKeyValues2 s_DMSerializerKeyValues2( false );
  238. static CDmSerializerKeyValues2 s_DMSerializerKeyValues2Flat( true );
  239. void InstallKeyValues2Serializer( IDataModel *pFactory )
  240. {
  241. pFactory->AddSerializer( &s_DMSerializerKeyValues2 );
  242. pFactory->AddSerializer( &s_DMSerializerKeyValues2Flat );
  243. }
  244. //-----------------------------------------------------------------------------
  245. // Serializes a single element attribute
  246. //-----------------------------------------------------------------------------
  247. void CDmSerializerKeyValues2::SerializeElementAttribute( CUtlBuffer& buf, CDmElementSerializationDictionary &dict, CDmAttribute *pAttribute )
  248. {
  249. CDmElement *pElement = pAttribute->GetValueElement<CDmElement>();
  250. if ( dict.ShouldInlineElement( pElement ) )
  251. {
  252. buf.Printf( "\"%s\"\n{\n", pElement->GetTypeString() );
  253. if ( pElement )
  254. {
  255. SaveElement( buf, dict, pElement, false );
  256. }
  257. buf.Printf( "}\n" );
  258. }
  259. else
  260. {
  261. buf.Printf( "\"%s\" \"", g_pDataModel->GetAttributeNameForType( AT_ELEMENT ) );
  262. if ( pElement )
  263. {
  264. ::Serialize( buf, pElement->GetId() );
  265. }
  266. buf.PutChar( '\"' );
  267. }
  268. }
  269. //-----------------------------------------------------------------------------
  270. // Serializes an array element attribute
  271. //-----------------------------------------------------------------------------
  272. void CDmSerializerKeyValues2::SerializeElementArrayAttribute( CUtlBuffer& buf, CDmElementSerializationDictionary &dict, CDmAttribute *pAttribute )
  273. {
  274. CDmrElementArray<> array( pAttribute );
  275. buf.Printf( "\n[\n" );
  276. buf.PushTab();
  277. int nCount = array.Count();
  278. for ( int i = 0; i < nCount; ++i )
  279. {
  280. CDmElement *pElement = array[i];
  281. if ( dict.ShouldInlineElement( pElement ) )
  282. {
  283. buf.Printf( "\"%s\"\n{\n", pElement->GetTypeString() );
  284. if ( pElement )
  285. {
  286. SaveElement( buf, dict, pElement, false );
  287. }
  288. buf.PutChar( '}' );
  289. }
  290. else
  291. {
  292. const char *pAttributeType = AttributeTypeName( AT_ELEMENT );
  293. buf.Printf( "\"%s\" \"", pAttributeType );
  294. if ( pElement )
  295. {
  296. ::Serialize( buf, pElement->GetId() );
  297. }
  298. buf.PutChar( '\"' );
  299. }
  300. if ( i != nCount - 1 )
  301. {
  302. buf.PutChar( ',' );
  303. }
  304. buf.PutChar( '\n' );
  305. }
  306. buf.PopTab();
  307. buf.Printf( "]" );
  308. }
  309. //-----------------------------------------------------------------------------
  310. // Serializes array attributes
  311. //-----------------------------------------------------------------------------
  312. void CDmSerializerKeyValues2::SerializeArrayAttribute( CUtlBuffer& buf, CDmAttribute *pAttribute )
  313. {
  314. CDmrGenericArray array( pAttribute );
  315. int nCount = array.Count();
  316. buf.PutString( "\n[\n" );
  317. buf.PushTab();
  318. for ( int i = 0; i < nCount; ++i )
  319. {
  320. if ( pAttribute->GetType() != AT_STRING_ARRAY )
  321. {
  322. buf.PutChar( '\"' );
  323. buf.PushTab();
  324. }
  325. array.GetAttribute()->SerializeElement( i, buf );
  326. if ( pAttribute->GetType() != AT_STRING_ARRAY )
  327. {
  328. buf.PopTab();
  329. buf.PutChar( '\"' );
  330. }
  331. if ( i != nCount - 1 )
  332. {
  333. buf.PutChar( ',' );
  334. }
  335. buf.PutChar( '\n' );
  336. }
  337. buf.PopTab();
  338. buf.PutChar( ']' );
  339. }
  340. //-----------------------------------------------------------------------------
  341. // Serializes all attributes in an element
  342. //-----------------------------------------------------------------------------
  343. bool CDmSerializerKeyValues2::SerializeAttributes( CUtlBuffer& buf, CDmElementSerializationDictionary &dict, CDmElement *pElement )
  344. {
  345. // Collect the attributes to be written
  346. CDmAttribute **ppAttributes = ( CDmAttribute** )_alloca( pElement->AttributeCount() * sizeof( CDmAttribute* ) );
  347. int nAttributes = 0;
  348. for ( CDmAttribute *pAttribute = pElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
  349. {
  350. if ( pAttribute->IsFlagSet( FATTRIB_DONTSAVE ) )
  351. continue;
  352. ppAttributes[ nAttributes++ ] = pAttribute;
  353. }
  354. // Now write them all out in reverse order, since FirstAttribute is actually the *last* attribute for perf reasons
  355. for ( int i = nAttributes - 1; i >= 0; --i )
  356. {
  357. CDmAttribute *pAttribute = ppAttributes[ i ];
  358. Assert( pAttribute );
  359. const char *pName = pAttribute->GetName( );
  360. DmAttributeType_t nAttrType = pAttribute->GetType();
  361. if ( nAttrType != AT_ELEMENT )
  362. {
  363. buf.Printf( "\"%s\" \"%s\" ", pName, g_pDataModel->GetAttributeNameForType( nAttrType ) );
  364. }
  365. else
  366. {
  367. // Elements either serialize their type name or "element" depending on whether they are inlined
  368. buf.Printf( "\"%s\" ", pName );
  369. }
  370. switch( nAttrType )
  371. {
  372. default:
  373. if ( nAttrType >= AT_FIRST_ARRAY_TYPE )
  374. {
  375. SerializeArrayAttribute( buf, pAttribute );
  376. }
  377. else
  378. {
  379. if ( pAttribute->SerializesOnMultipleLines() )
  380. {
  381. buf.PutChar( '\n' );
  382. }
  383. buf.PutChar( '\"' );
  384. buf.PushTab();
  385. pAttribute->Serialize( buf );
  386. buf.PopTab();
  387. buf.PutChar( '\"' );
  388. }
  389. break;
  390. case AT_STRING:
  391. // Don't explicitly add string delimiters; serialization does that.
  392. pAttribute->Serialize( buf );
  393. break;
  394. case AT_ELEMENT:
  395. SerializeElementAttribute( buf, dict, pAttribute );
  396. break;
  397. case AT_ELEMENT_ARRAY:
  398. SerializeElementArrayAttribute( buf, dict, pAttribute );
  399. break;
  400. }
  401. buf.PutChar( '\n' );
  402. }
  403. return true;
  404. }
  405. bool CDmSerializerKeyValues2::SaveElement( CUtlBuffer& buf, CDmElementSerializationDictionary &dict, CDmElement *pElement, bool bWriteDelimiters )
  406. {
  407. if ( bWriteDelimiters )
  408. {
  409. buf.Printf( "\"%s\"\n{\n", pElement->GetTypeString() );
  410. }
  411. buf.PushTab();
  412. // explicitly serialize id, now that it's no longer an attribute
  413. buf.PutString( "\"id\" \"elementid\" " );
  414. buf.PutChar( '\"' );
  415. ::Serialize( buf, pElement->GetId() );
  416. buf.PutString( "\"\n" );
  417. SerializeAttributes( buf, dict, pElement );
  418. buf.PopTab();
  419. if ( bWriteDelimiters )
  420. {
  421. buf.Printf( "}\n" );
  422. }
  423. return true;
  424. }
  425. bool CDmSerializerKeyValues2::Serialize( CUtlBuffer &outBuf, CDmElement *pRoot )
  426. {
  427. SetSerializationDelimiter( GetCStringCharConversion() );
  428. SetSerializationArrayDelimiter( "," );
  429. // Save elements, attribute links
  430. CDmElementSerializationDictionary dict;
  431. dict.BuildElementList( pRoot, m_bFlatMode );
  432. // Save elements to buffer
  433. DmElementDictHandle_t i;
  434. for ( i = dict.FirstRootElement(); i != ELEMENT_DICT_HANDLE_INVALID; i = dict.NextRootElement(i) )
  435. {
  436. SaveElement( outBuf, dict, dict.GetRootElement( i ) );
  437. outBuf.PutChar( '\n' );
  438. }
  439. SetSerializationDelimiter( NULL );
  440. SetSerializationArrayDelimiter( NULL );
  441. return true;
  442. }
  443. //-----------------------------------------------------------------------------
  444. // Eats whitespaces and c++ style comments
  445. //-----------------------------------------------------------------------------
  446. #pragma warning (disable:4706)
  447. void CDmSerializerKeyValues2::EatWhitespacesAndComments( CUtlBuffer &buf )
  448. {
  449. // eating white spaces and remarks loop
  450. int nMaxPut = buf.TellMaxPut() - buf.TellGet();
  451. int nOffset = 0;
  452. while ( nOffset < nMaxPut )
  453. {
  454. // Eat whitespaces, keep track of line count
  455. const char *pPeek = NULL;
  456. while ( pPeek = (const char *)buf.PeekGet( sizeof(char), nOffset ) )
  457. {
  458. if ( !V_isspace( *pPeek ) )
  459. break;
  460. if ( *pPeek == '\n' )
  461. {
  462. g_KeyValues2ErrorStack.IncrementCurrentLine();
  463. }
  464. if ( ++nOffset >= nMaxPut )
  465. break;
  466. }
  467. // If we don't have a a c++ style comment next, we're done
  468. pPeek = (const char *)buf.PeekGet( 2 * sizeof(char), nOffset );
  469. if ( ( nOffset >= nMaxPut ) || !pPeek || ( pPeek[0] != '/' ) || ( pPeek[1] != '/' ) )
  470. break;
  471. // Deal with c++ style comments
  472. nOffset += 2;
  473. // read complete line
  474. while ( pPeek = (const char *)buf.PeekGet( sizeof(char), nOffset ) )
  475. {
  476. if ( *pPeek == '\n' )
  477. break;
  478. if ( ++nOffset >= nMaxPut )
  479. break;
  480. }
  481. g_KeyValues2ErrorStack.IncrementCurrentLine();
  482. }
  483. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, nOffset );
  484. }
  485. #pragma warning (default:4706)
  486. //-----------------------------------------------------------------------------
  487. // Reads a single token, points the token utlbuffer at it
  488. //-----------------------------------------------------------------------------
  489. CDmSerializerKeyValues2::TokenType_t CDmSerializerKeyValues2::ReadToken( CUtlBuffer &buf, CUtlBuffer &token )
  490. {
  491. EatWhitespacesAndComments( buf );
  492. // if message text buffers go over this size
  493. // change this value to make sure they will fit
  494. // affects loading of last active chat window
  495. if ( !buf.IsValid() || ( buf.TellGet() == buf.TellMaxPut() ) )
  496. return TOKEN_EOF;
  497. // Compute token length and type
  498. int nLength = 0;
  499. TokenType_t t = TOKEN_INVALID;
  500. char c = *((const char *)buf.PeekGet());
  501. switch( c )
  502. {
  503. case '{':
  504. nLength = 1;
  505. t = TOKEN_OPEN_BRACE;
  506. break;
  507. case '}':
  508. nLength = 1;
  509. t = TOKEN_CLOSE_BRACE;
  510. break;
  511. case '[':
  512. nLength = 1;
  513. t = TOKEN_OPEN_BRACKET;
  514. break;
  515. case ']':
  516. nLength = 1;
  517. t = TOKEN_CLOSE_BRACKET;
  518. break;
  519. case ',':
  520. nLength = 1;
  521. t = TOKEN_COMMA;
  522. break;
  523. case '\"':
  524. // NOTE: The -1 is because peek includes room for the /0
  525. nLength = buf.PeekDelimitedStringLength( GetCStringCharConversion(), false ) - 1;
  526. if ( (nLength <= 1) || ( *(const char *)buf.PeekGet( nLength - 1 ) != '\"' ))
  527. {
  528. g_KeyValues2ErrorStack.ReportError( "Unexpected EOF in quoted string" );
  529. t = TOKEN_INVALID;
  530. }
  531. else
  532. {
  533. t = TOKEN_DELIMITED_STRING;
  534. }
  535. break;
  536. default:
  537. t = TOKEN_INVALID;
  538. break;
  539. }
  540. token.EnsureCapacity( nLength );
  541. buf.Get( token.Base(), nLength );
  542. token.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );
  543. token.SeekPut( CUtlBuffer::SEEK_HEAD, nLength );
  544. // Count the number of crs in the token + update the current line
  545. const char *pMem = (const char *)token.Base();
  546. for ( int i = 0; i < nLength; ++i )
  547. {
  548. if ( pMem[i] == '\n' )
  549. {
  550. g_KeyValues2ErrorStack.IncrementCurrentLine();
  551. }
  552. }
  553. return t;
  554. }
  555. //-----------------------------------------------------------------------------
  556. // Creates a scene object, adds it to the element dictionary
  557. //-----------------------------------------------------------------------------
  558. DmElementDictHandle_t CDmSerializerKeyValues2::CreateDmElement( const char *pElementType )
  559. {
  560. // See if we can create an element of that type
  561. DmElementHandle_t hElement = g_pDataModel->CreateElement( pElementType, "", m_fileid );
  562. if ( hElement == DMELEMENT_HANDLE_INVALID )
  563. {
  564. g_KeyValues2ErrorStack.ReportError("Element uses unknown element type %s\n", pElementType );
  565. return ELEMENT_DICT_HANDLE_INVALID;
  566. }
  567. CDmElement *pElement = g_pDataModel->GetElement( hElement );
  568. CDmeElementAccessor::DisableOnChangedCallbacks( pElement );
  569. return m_ElementDict.InsertElement( pElement );
  570. }
  571. //-----------------------------------------------------------------------------
  572. // Reads an attribute for an element
  573. //-----------------------------------------------------------------------------
  574. bool CDmSerializerKeyValues2::UnserializeElementAttribute( CUtlBuffer &buf, DmElementDictHandle_t hElement, const char *pAttributeName, const char *pElementType )
  575. {
  576. CDmElement *pElement = m_ElementDict.GetElement( hElement );
  577. CDmAttribute *pAttribute = pElement->AddAttribute( pAttributeName, AT_ELEMENT );
  578. if ( !pAttribute )
  579. {
  580. g_KeyValues2ErrorStack.ReportError("Attempted to read an attribute (\"%s\") of unknown type %s!\n", pAttributeName, pElementType );
  581. return false;
  582. }
  583. DmElementDictHandle_t h;
  584. bool bOk = UnserializeElement( buf, pElementType, &h );
  585. if ( bOk )
  586. {
  587. CDmElement *pNewElement = m_ElementDict.GetElement( h );
  588. pAttribute->SetValue( pNewElement ? pNewElement->GetHandle() : DMELEMENT_HANDLE_INVALID );
  589. }
  590. return bOk;
  591. }
  592. //-----------------------------------------------------------------------------
  593. // Reads an attribute for an element array
  594. //-----------------------------------------------------------------------------
  595. bool CDmSerializerKeyValues2::UnserializeElementArrayAttribute( CUtlBuffer &buf, DmElementDictHandle_t hElement, const char *pAttributeName )
  596. {
  597. CDmElement *pElement = m_ElementDict.GetElement( hElement );
  598. CDmAttribute *pAttribute = pElement->AddAttribute( pAttributeName, AT_ELEMENT_ARRAY );
  599. if ( !pAttribute )
  600. {
  601. g_KeyValues2ErrorStack.ReportError("Attempted to read an attribute (\"%s\") of an inappropriate type!\n", pAttributeName );
  602. return false;
  603. }
  604. // Arrays first must have a '[' specified
  605. TokenType_t token;
  606. CUtlBuffer tokenBuf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  607. CUtlCharConversion *pConv = GetCStringCharConversion();
  608. token = ReadToken( buf, tokenBuf );
  609. if ( token != TOKEN_OPEN_BRACKET )
  610. {
  611. g_KeyValues2ErrorStack.ReportError( "Expecting '[', didn't find it!" );
  612. return false;
  613. }
  614. int nElementIndex = 0;
  615. // Now read a list of array values, separated by commas
  616. while ( buf.IsValid() )
  617. {
  618. token = ReadToken( buf, tokenBuf );
  619. if ( token == TOKEN_INVALID || token == TOKEN_EOF )
  620. {
  621. g_KeyValues2ErrorStack.ReportError( "Expecting ']', didn't find it!" );
  622. return false;
  623. }
  624. // Then, keep reading until we hit a ']'
  625. if ( token == TOKEN_CLOSE_BRACKET )
  626. break;
  627. // If we've already read in an array value, we need to read a comma next
  628. if ( nElementIndex > 0 )
  629. {
  630. if ( token != TOKEN_COMMA )
  631. {
  632. g_KeyValues2ErrorStack.ReportError( "Expecting ',', didn't find it!" );
  633. return false;
  634. }
  635. // Read in the next thing, which should be a value
  636. token = ReadToken( buf, tokenBuf );
  637. }
  638. // Ok, we must be reading an array type value
  639. if ( token != TOKEN_DELIMITED_STRING )
  640. {
  641. g_KeyValues2ErrorStack.ReportError( "Expecting element type, didn't find it!" );
  642. return false;
  643. }
  644. // Get the element type out
  645. char elementType[ 256 ];
  646. tokenBuf.GetDelimitedString( pConv, elementType, sizeof( elementType ) );
  647. // Use the element type to figure out if we're using a element reference or an inlined element
  648. if ( !V_strcmp( elementType, g_pDataModel->GetAttributeNameForType( AT_ELEMENT ) ) )
  649. {
  650. token = ReadToken( buf, tokenBuf );
  651. // Ok, we must be reading an array type value
  652. if ( token != TOKEN_DELIMITED_STRING )
  653. {
  654. g_KeyValues2ErrorStack.ReportError( "Expecting element reference, didn't find it!" );
  655. return false;
  656. }
  657. // Get the element type out
  658. char elementId[ 256 ];
  659. tokenBuf.GetDelimitedString( pConv, elementId, sizeof( elementId ) );
  660. if ( elementId[ 0 ] == '\0' )
  661. {
  662. m_ElementDict.AddArrayAttribute( pAttribute, ELEMENT_DICT_HANDLE_INVALID );
  663. }
  664. else
  665. {
  666. DmObjectId_t id;
  667. if ( !UniqueIdFromString( &id, elementId ) )
  668. {
  669. g_KeyValues2ErrorStack.ReportError( "Encountered invalid element ID data!" );
  670. return false;
  671. }
  672. Assert( IsUniqueIdValid( id ) );
  673. m_ElementDict.AddArrayAttribute( pAttribute, id );
  674. }
  675. }
  676. else
  677. {
  678. DmElementDictHandle_t hArrayElement;
  679. bool bOk = UnserializeElement( buf, elementType, &hArrayElement );
  680. if ( !bOk )
  681. return false;
  682. m_ElementDict.AddArrayAttribute( pAttribute, hArrayElement );
  683. }
  684. // Ok, we've read in another value
  685. ++nElementIndex;
  686. }
  687. return true;
  688. }
  689. //-----------------------------------------------------------------------------
  690. // Unserializes an attribute from a token buffer
  691. //-----------------------------------------------------------------------------
  692. bool CDmSerializerKeyValues2::UnserializeAttributeValueFromToken( CDmAttribute *pAttribute, CUtlBuffer &tokenBuf )
  693. {
  694. // NOTE: This code is necessary because the attribute code is using Scanf
  695. // which is not really friendly toward delimiters, so we must pass in
  696. // non-delimited buffers. Sucky. There must be a better way of doing this
  697. const char *pBuf = (const char*)tokenBuf.Base();
  698. int nLength = tokenBuf.TellMaxPut();
  699. char *pTemp = (char*)stackalloc( nLength + 1 );
  700. bool bIsString = ( pAttribute->GetType() == AT_STRING ) || ( pAttribute->GetType() == AT_STRING_ARRAY );
  701. if ( !bIsString )
  702. {
  703. nLength = tokenBuf.PeekDelimitedStringLength( GetCStringCharConversion() );
  704. tokenBuf.GetDelimitedString( GetCStringCharConversion(), pTemp, nLength + 1 );
  705. pBuf = pTemp;
  706. }
  707. else
  708. {
  709. SetSerializationDelimiter( GetCStringCharConversion() );
  710. }
  711. bool bOk;
  712. CUtlBuffer buf( pBuf, nLength, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::READ_ONLY );
  713. if ( pAttribute->GetType() < AT_FIRST_ARRAY_TYPE )
  714. {
  715. bOk = pAttribute->Unserialize( buf );
  716. }
  717. else
  718. {
  719. bOk = pAttribute->UnserializeElement( buf );
  720. }
  721. if ( bIsString )
  722. {
  723. SetSerializationDelimiter( NULL );
  724. }
  725. return bOk;
  726. }
  727. //-----------------------------------------------------------------------------
  728. // Reads an attribute for an element array
  729. //-----------------------------------------------------------------------------
  730. bool CDmSerializerKeyValues2::UnserializeArrayAttribute( CUtlBuffer &buf, DmElementDictHandle_t hElement, const char *pAttributeName, DmAttributeType_t nAttrType )
  731. {
  732. CDmElement *pElement = m_ElementDict.GetElement( hElement );
  733. CDmAttribute *pAttribute = pElement->AddAttribute( pAttributeName, nAttrType );
  734. if ( !pAttribute )
  735. {
  736. g_KeyValues2ErrorStack.ReportError("Attempted to read an attribute (\"%s\") of an inappropriate type %s!\n",
  737. pAttributeName, g_pDataModel->GetAttributeNameForType( nAttrType ) );
  738. return false;
  739. }
  740. // Arrays first must have a '[' specified
  741. TokenType_t token;
  742. CUtlBuffer tokenBuf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  743. token = ReadToken( buf, tokenBuf );
  744. if ( token != TOKEN_OPEN_BRACKET )
  745. {
  746. g_KeyValues2ErrorStack.ReportError( "Expecting '[', didn't find it!" );
  747. return false;
  748. }
  749. int nElementIndex = 0;
  750. // Now read a list of array values, separated by commas
  751. while ( buf.IsValid() )
  752. {
  753. token = ReadToken( buf, tokenBuf );
  754. if ( token == TOKEN_INVALID || token == TOKEN_EOF )
  755. {
  756. g_KeyValues2ErrorStack.ReportError( "Expecting ']', didn't find it!" );
  757. return false;
  758. }
  759. // Then, keep reading until we hit a ']'
  760. if ( token == TOKEN_CLOSE_BRACKET )
  761. break;
  762. // If we've already read in an array value, we need to read a comma next
  763. if ( nElementIndex > 0 )
  764. {
  765. if ( token != TOKEN_COMMA )
  766. {
  767. g_KeyValues2ErrorStack.ReportError( "Expecting ',', didn't find it!" );
  768. return false;
  769. }
  770. // Read in the next thing, which should be a value
  771. token = ReadToken( buf, tokenBuf );
  772. }
  773. // Ok, we must be reading an attributearray value
  774. if ( token != TOKEN_DELIMITED_STRING )
  775. {
  776. g_KeyValues2ErrorStack.ReportError( "Expecting array attribute value, didn't find it!" );
  777. return false;
  778. }
  779. if ( !UnserializeAttributeValueFromToken( pAttribute, tokenBuf ) )
  780. {
  781. g_KeyValues2ErrorStack.ReportError("Error reading in array attribute \"%s\" element %d", pAttributeName, nElementIndex );
  782. return false;
  783. }
  784. // Ok, we've read in another value
  785. ++nElementIndex;
  786. }
  787. return true;
  788. }
  789. //-----------------------------------------------------------------------------
  790. // Reads an attribute for an element
  791. //-----------------------------------------------------------------------------
  792. bool CDmSerializerKeyValues2::UnserializeAttribute( CUtlBuffer &buf,
  793. DmElementDictHandle_t hElement, const char *pAttributeName, DmAttributeType_t nAttrType )
  794. {
  795. // Read the attribute value
  796. CUtlBuffer tokenBuf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  797. TokenType_t token = ReadToken( buf, tokenBuf );
  798. if ( token != TOKEN_DELIMITED_STRING )
  799. {
  800. g_KeyValues2ErrorStack.ReportError( "Expecting quoted attribute value for attribute \"%s\", didn't find one!", pAttributeName );
  801. return false;
  802. }
  803. CDmElement *pElement = m_ElementDict.GetElement( hElement );
  804. CDmAttribute *pAttribute = pElement->AddAttribute( pAttributeName, nAttrType );
  805. if ( !pAttribute )
  806. {
  807. g_KeyValues2ErrorStack.ReportError("Attempted to read an attribute (\"%s\") of an inappropriate type %s!\n",
  808. pAttributeName, g_pDataModel->GetAttributeNameForType( nAttrType ) );
  809. return false;
  810. }
  811. switch( nAttrType )
  812. {
  813. case AT_ELEMENT:
  814. {
  815. // Get the attribute value out
  816. CUtlCharConversion *pConv = GetCStringCharConversion();
  817. int nLength = tokenBuf.PeekDelimitedStringLength( pConv );
  818. char *pAttributeValue = (char*)stackalloc( nLength * sizeof(char) );
  819. tokenBuf.GetDelimitedString( pConv, pAttributeValue, nLength );
  820. // No string? that's ok, it means we have a NULL pointer
  821. if ( !pAttributeValue[0] )
  822. return true;
  823. DmObjectId_t id;
  824. if ( !UniqueIdFromString( &id, pAttributeValue ) )
  825. {
  826. g_KeyValues2ErrorStack.ReportError("Invalid format for element ID encountered for attribute \"%s\"", pAttributeName );
  827. return false;
  828. }
  829. m_ElementDict.AddAttribute( pAttribute, id );
  830. }
  831. return true;
  832. default:
  833. if ( UnserializeAttributeValueFromToken( pAttribute, tokenBuf ) )
  834. return true;
  835. g_KeyValues2ErrorStack.ReportError("Error reading attribute \"%s\"", pAttributeName );
  836. return false;
  837. }
  838. }
  839. /*
  840. //-----------------------------------------------------------------------------
  841. // Purpose:
  842. // Input : includedKeys -
  843. //-----------------------------------------------------------------------------
  844. void KeyValues::AppendIncludedKeys( CUtlVector< KeyValues * >& includedKeys )
  845. {
  846. // Append any included keys, too...
  847. int includeCount = includedKeys.Count();
  848. int i;
  849. for ( i = 0; i < includeCount; i++ )
  850. {
  851. KeyValues *kv = includedKeys[ i ];
  852. Assert( kv );
  853. KeyValues *insertSpot = this;
  854. while ( insertSpot->GetNextKey() )
  855. {
  856. insertSpot = insertSpot->GetNextKey();
  857. }
  858. insertSpot->SetNextKey( kv );
  859. }
  860. }
  861. void KeyValues::ParseIncludedKeys( char const *resourceName, const char *filetoinclude,
  862. IBaseFileSystem* pFileSystem, const char *pPathID, CUtlVector< KeyValues * >& includedKeys )
  863. {
  864. Assert( resourceName );
  865. Assert( filetoinclude );
  866. Assert( pFileSystem );
  867. // Load it...
  868. if ( !pFileSystem )
  869. {
  870. return;
  871. }
  872. // Get relative subdirectory
  873. char fullpath[ 512 ];
  874. Q_strncpy( fullpath, resourceName, sizeof( fullpath ) );
  875. // Strip off characters back to start or first /
  876. bool done = false;
  877. int len = Q_strlen( fullpath );
  878. while ( !done )
  879. {
  880. if ( len <= 0 )
  881. {
  882. break;
  883. }
  884. if ( fullpath[ len - 1 ] == '\\' ||
  885. fullpath[ len - 1 ] == '/' )
  886. {
  887. break;
  888. }
  889. // zero it
  890. fullpath[ len - 1 ] = 0;
  891. --len;
  892. }
  893. // Append included file
  894. Q_strncat( fullpath, filetoinclude, sizeof( fullpath ), COPY_ALL_CHARACTERS );
  895. KeyValues *newKV = new KeyValues( fullpath );
  896. // CUtlSymbolLarge save = s_CurrentFileSymbol; // did that had any use ???
  897. newKV->UsesEscapeSequences( m_bHasEscapeSequences ); // use same format as parent
  898. if ( newKV->LoadFromFile( pFileSystem, fullpath, pPathID ) )
  899. {
  900. includedKeys.AddToTail( newKV );
  901. }
  902. else
  903. {
  904. DevMsg( "KeyValues::ParseIncludedKeys: Couldn't load included keyvalue file %s\n", fullpath );
  905. newKV->deleteThis();
  906. }
  907. // s_CurrentFileSymbol = save;
  908. }
  909. //-----------------------------------------------------------------------------
  910. // Read from a buffer...
  911. //-----------------------------------------------------------------------------
  912. bool KeyValues::LoadFromBuffer( char const *resourceName, const char *pBuffer, IBaseFileSystem* pFileSystem , const char *pPathID )
  913. {
  914. char *pfile = const_cast<char *>(pBuffer);
  915. KeyValues *pPreviousKey = NULL;
  916. KeyValues *pCurrentKey = this;
  917. CUtlVector< KeyValues * > includedKeys;
  918. bool wasQuoted;
  919. g_KeyValues2ErrorStack.SetFilename( resourceName );
  920. do
  921. {
  922. // the first thing must be a key
  923. const char *s = ReadToken( &pfile, wasQuoted );
  924. if ( !pfile || !s || *s == 0 )
  925. break;
  926. if ( !Q_stricmp( s, "#include" ) ) // special include macro (not a key name)
  927. {
  928. s = ReadToken( &pfile, wasQuoted );
  929. // Name of subfile to load is now in s
  930. if ( !s || *s == 0 )
  931. {
  932. g_KeyValues2ErrorStack.ReportError("#include is NULL " );
  933. }
  934. else
  935. {
  936. ParseIncludedKeys( resourceName, s, pFileSystem, pPathID, includedKeys );
  937. }
  938. continue;
  939. }
  940. if ( !pCurrentKey )
  941. {
  942. pCurrentKey = new KeyValues( s );
  943. Assert( pCurrentKey );
  944. pCurrentKey->UsesEscapeSequences( m_bHasEscapeSequences ); // same format has parent use
  945. if ( pPreviousKey )
  946. {
  947. pPreviousKey->SetNextKey( pCurrentKey );
  948. }
  949. }
  950. else
  951. {
  952. pCurrentKey->SetName( s );
  953. }
  954. // get the '{'
  955. s = ReadToken( &pfile, wasQuoted );
  956. if ( s && *s == '{' && !wasQuoted )
  957. {
  958. // header is valid so load the file
  959. pCurrentKey->RecursiveLoadFromBuffer( resourceName, &pfile );
  960. }
  961. else
  962. {
  963. g_KeyValues2ErrorStack.ReportError("LoadFromBuffer: missing {" );
  964. }
  965. pPreviousKey = pCurrentKey;
  966. pCurrentKey = NULL;
  967. } while ( pfile != NULL );
  968. AppendIncludedKeys( includedKeys );
  969. g_KeyValues2ErrorStack.SetFilename( "" );
  970. return true;
  971. }
  972. */
  973. //-----------------------------------------------------------------------------
  974. // Unserializes a single element given the type name
  975. //-----------------------------------------------------------------------------
  976. bool CDmSerializerKeyValues2::UnserializeElement( CUtlBuffer &buf, const char *pElementType, DmElementDictHandle_t *pHandle )
  977. {
  978. *pHandle = ELEMENT_DICT_HANDLE_INVALID;
  979. // Create the element
  980. DmElementDictHandle_t hElement = CreateDmElement( pElementType );
  981. if ( hElement == ELEMENT_DICT_HANDLE_INVALID )
  982. return false;
  983. // Report errors relative to this type name
  984. CKeyValues2ErrorContext errorReport( pElementType );
  985. TokenType_t token;
  986. CUtlBuffer tokenBuf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  987. CUtlCharConversion *pConv = GetCStringCharConversion();
  988. // Then we expect a '{'
  989. token = ReadToken( buf, tokenBuf );
  990. if ( token != TOKEN_OPEN_BRACE )
  991. {
  992. g_KeyValues2ErrorStack.ReportError( "Expecting '{', didn't find it!" );
  993. return false;
  994. }
  995. while ( buf.IsValid() )
  996. {
  997. token = ReadToken( buf, tokenBuf );
  998. if ( token == TOKEN_INVALID || token == TOKEN_EOF )
  999. {
  1000. g_KeyValues2ErrorStack.ReportError( "Expecting '}', didn't find it!" );
  1001. return false;
  1002. }
  1003. // Then, keep reading until we hit a '}'
  1004. if ( token == TOKEN_CLOSE_BRACE )
  1005. break;
  1006. // Ok, we must be reading an attribute
  1007. if ( token != TOKEN_DELIMITED_STRING )
  1008. {
  1009. g_KeyValues2ErrorStack.ReportError( "Expecting attribute name, didn't find it!" );
  1010. return false;
  1011. }
  1012. // First, read an attribute name
  1013. char attributeName[ 256 ];
  1014. tokenBuf.GetDelimitedString( pConv, attributeName, sizeof( attributeName ) );
  1015. // Next, read an attribute type
  1016. token = ReadToken( buf, tokenBuf );
  1017. if ( token != TOKEN_DELIMITED_STRING )
  1018. {
  1019. g_KeyValues2ErrorStack.ReportError( "Expecting attribute type for attribute %s, didn't find it!", attributeName );
  1020. return false;
  1021. }
  1022. char attributeType[ 256 ];
  1023. tokenBuf.GetDelimitedString( pConv, attributeType, sizeof( attributeType ) );
  1024. // read element's id (or any other id attribute, if any)
  1025. if ( !V_strcmp( attributeType, "elementid" ) )
  1026. {
  1027. // Next, read the id
  1028. token = ReadToken( buf, tokenBuf );
  1029. if ( token != TOKEN_DELIMITED_STRING )
  1030. {
  1031. g_KeyValues2ErrorStack.ReportError( "Expecting attribute type for attribute %s, didn't find it!", attributeName );
  1032. return false;
  1033. }
  1034. char elementId[ 256 ];
  1035. tokenBuf.GetDelimitedString( pConv, elementId, sizeof( elementId ) );
  1036. Assert( !V_stricmp( attributeName, "id" ) );
  1037. if ( !V_stricmp( attributeName, "id" ) )
  1038. {
  1039. DmObjectId_t id;
  1040. if ( !UniqueIdFromString( &id, elementId ) )
  1041. {
  1042. g_KeyValues2ErrorStack.ReportError( "Encountered invalid element ID data!" );
  1043. return false;
  1044. }
  1045. m_ElementDict.SetElementId( hElement, id, m_idConflictResolution );
  1046. }
  1047. continue;
  1048. }
  1049. DmAttributeType_t nAttrType = g_pDataModel->GetAttributeTypeForName( attributeType );
  1050. // Next, read an attribute value
  1051. bool bOk = true;
  1052. switch( nAttrType )
  1053. {
  1054. case AT_UNKNOWN:
  1055. bOk = UnserializeElementAttribute( buf, hElement, attributeName, attributeType );
  1056. break;
  1057. case AT_ELEMENT_ARRAY:
  1058. bOk = UnserializeElementArrayAttribute( buf, hElement, attributeName );
  1059. break;
  1060. default:
  1061. if ( nAttrType >= AT_FIRST_ARRAY_TYPE )
  1062. {
  1063. bOk = UnserializeArrayAttribute( buf, hElement, attributeName, nAttrType );
  1064. }
  1065. else
  1066. {
  1067. bOk = UnserializeAttribute( buf, hElement, attributeName, nAttrType );
  1068. }
  1069. break;
  1070. }
  1071. if ( !bOk )
  1072. return false;
  1073. }
  1074. *pHandle = hElement;
  1075. return true;
  1076. }
  1077. //-----------------------------------------------------------------------------
  1078. // Unserializes a single element
  1079. //-----------------------------------------------------------------------------
  1080. bool CDmSerializerKeyValues2::UnserializeElement( CUtlBuffer &buf, DmElementDictHandle_t *pHandle )
  1081. {
  1082. *pHandle = ELEMENT_DICT_HANDLE_INVALID;
  1083. // First, read the type name
  1084. CUtlBuffer tokenBuf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  1085. TokenType_t token = ReadToken( buf, tokenBuf );
  1086. if ( token == TOKEN_INVALID )
  1087. return false;
  1088. if ( token == TOKEN_EOF )
  1089. return true;
  1090. // Get the type name out
  1091. if ( token != TOKEN_DELIMITED_STRING )
  1092. {
  1093. g_KeyValues2ErrorStack.ReportError( "Expecting element type name, didn't find it!" );
  1094. return false;
  1095. }
  1096. CUtlCharConversion* pConv = GetCStringCharConversion();
  1097. int nLength = tokenBuf.PeekDelimitedStringLength( pConv );
  1098. char *pTypeName = (char*)stackalloc( nLength * sizeof(char) );
  1099. tokenBuf.GetDelimitedString( pConv, pTypeName, nLength );
  1100. return UnserializeElement( buf, pTypeName, pHandle );
  1101. }
  1102. //-----------------------------------------------------------------------------
  1103. // Main entry point for the unserialization
  1104. //-----------------------------------------------------------------------------
  1105. bool CDmSerializerKeyValues2::Unserialize( CUtlBuffer &buf, const char *pEncodingName, int nEncodingVersion,
  1106. const char *pSourceFormatName, int nSourceFormatVersion,
  1107. DmFileId_t fileid, DmConflictResolution_t idConflictResolution, CDmElement **ppRoot )
  1108. {
  1109. bool bSuccess = UnserializeElements( buf, fileid, idConflictResolution, ppRoot );
  1110. if ( !bSuccess )
  1111. return false;
  1112. return g_pDataModel->UpdateUnserializedElements( pSourceFormatName, nSourceFormatVersion, fileid, idConflictResolution, ppRoot );
  1113. }
  1114. bool CDmSerializerKeyValues2::UnserializeElements( CUtlBuffer &buf, DmFileId_t fileid, DmConflictResolution_t idConflictResolution, CDmElement **ppRoot )
  1115. {
  1116. *ppRoot = NULL;
  1117. m_idConflictResolution = idConflictResolution;
  1118. m_fileid = fileid;
  1119. g_KeyValues2ErrorStack.SetFilename( g_pDataModel->GetFileName( fileid ) );
  1120. m_hRoot = ELEMENT_DICT_HANDLE_INVALID;
  1121. m_ElementDict.Clear();
  1122. bool bOk = true;
  1123. while ( buf.IsValid() )
  1124. {
  1125. DmElementDictHandle_t h;
  1126. bOk = UnserializeElement( buf, &h );
  1127. if ( !bOk || ( h == ELEMENT_DICT_HANDLE_INVALID ) )
  1128. break;
  1129. if ( m_hRoot == ELEMENT_DICT_HANDLE_INVALID )
  1130. {
  1131. m_hRoot = h;
  1132. }
  1133. }
  1134. // do this *before* getting the root, since the first element might be deleted due to id conflicts
  1135. m_ElementDict.HookUpElementReferences();
  1136. *ppRoot = m_ElementDict.GetElement( m_hRoot );
  1137. // mark all unserialized elements as done unserializing, and call Resolve()
  1138. for ( DmElementDictHandle_t h = m_ElementDict.FirstElement();
  1139. h != ELEMENT_DICT_HANDLE_INVALID;
  1140. h = m_ElementDict.NextElement( h ) )
  1141. {
  1142. CDmElement *pElement = m_ElementDict.GetElement( h );
  1143. if ( !pElement )
  1144. continue;
  1145. CDmeElementAccessor::EnableOnChangedCallbacks( pElement );
  1146. CDmeElementAccessor::FinishUnserialization( pElement );
  1147. }
  1148. m_fileid = DMFILEID_INVALID;
  1149. g_pDmElementFrameworkImp->RemoveCleanElementsFromDirtyList( );
  1150. m_ElementDict.Clear();
  1151. return bOk;
  1152. }