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.

1377 lines
40 KiB

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