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.

466 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "dmserializerkeyvalues.h"
  7. #include "datamodel/idatamodel.h"
  8. #include "datamodel.h"
  9. #include "datamodel/dmelement.h"
  10. #include "datamodel/dmattributevar.h"
  11. #include "dmattributeinternal.h"
  12. #include "tier1/KeyValues.h"
  13. #include "tier1/utlbuffer.h"
  14. #include "tier1/utlvector.h"
  15. #include <limits.h>
  16. #include "DmElementFramework.h"
  17. // memdbgon must be the last include file in a .cpp file!!!
  18. #include "tier0/memdbgon.h"
  19. //-----------------------------------------------------------------------------
  20. // Forward declarations
  21. //-----------------------------------------------------------------------------
  22. class CUtlBuffer;
  23. class CBaseSceneObject;
  24. //-----------------------------------------------------------------------------
  25. // Used to remap keyvalues names
  26. //-----------------------------------------------------------------------------
  27. struct AttributeRemap_t
  28. {
  29. const char *m_pKeyValuesName;
  30. const char *m_pDmeName;
  31. };
  32. static AttributeRemap_t s_pAttributeRemap[] =
  33. {
  34. { "type", "_type" }, // FIXME - remove this once we've made type no longer be an attribute
  35. { "name", "_name" },
  36. { "id", "_id" }, // FIXME - remove this once we've made id no longer be an attribute
  37. { NULL, NULL }
  38. };
  39. //-----------------------------------------------------------------------------
  40. // Serialization class for Key Values
  41. //-----------------------------------------------------------------------------
  42. class CDmSerializerKeyValues : public IDmSerializer
  43. {
  44. public:
  45. // Inherited from IDMSerializer
  46. virtual const char *GetName() const { return "keyvalues"; }
  47. virtual const char *GetDescription() const { return "KeyValues"; }
  48. virtual bool StoresVersionInFile() const { return false; }
  49. virtual bool IsBinaryFormat() const { return false; }
  50. virtual int GetCurrentVersion() const { return 0; } // doesn't store a version
  51. virtual bool Serialize( CUtlBuffer &buf, CDmElement *pRoot );
  52. virtual bool Unserialize( CUtlBuffer &buf, const char *pEncodingName, int nEncodingVersion,
  53. const char *pSourceFormatName, int nSourceFormatVersion,
  54. DmFileId_t fileid, DmConflictResolution_t idConflictResolution, CDmElement **ppRoot );
  55. private:
  56. // Methods related to serialization
  57. void SerializeSubKeys( CUtlBuffer& buf, CDmAttribute *pSubKeys );
  58. bool SerializeAttributes( CUtlBuffer& buf, CDmElement *pElement );
  59. bool SerializeElement( CUtlBuffer& buf, CDmElement *pElement );
  60. // Methods related to unserialization
  61. DmElementHandle_t UnserializeElement( KeyValues *pKeyValues, int iNestingLevel );
  62. void UnserializeAttribute( CDmElement *pElement, KeyValues *pKeyValues );
  63. DmElementHandle_t CreateDmElement( const char *pElementType, const char *pElementName );
  64. CDmElement* UnserializeFromKeyValues( KeyValues *pKeyValues );
  65. // Deterimines the attribute type of a keyvalue
  66. DmAttributeType_t DetermineAttributeType( KeyValues *pKeyValues );
  67. // For unserialization
  68. CUtlVector<DmElementHandle_t> m_ElementList;
  69. DmElementHandle_t m_hRoot;
  70. DmFileId_t m_fileid;
  71. };
  72. //-----------------------------------------------------------------------------
  73. // Singleton instance
  74. //-----------------------------------------------------------------------------
  75. static CDmSerializerKeyValues s_DMSerializerKeyValues;
  76. void InstallKeyValuesSerializer( IDataModel *pFactory )
  77. {
  78. pFactory->AddSerializer( &s_DMSerializerKeyValues );
  79. }
  80. //-----------------------------------------------------------------------------
  81. // Serializes a single element attribute
  82. //-----------------------------------------------------------------------------
  83. void CDmSerializerKeyValues::SerializeSubKeys( CUtlBuffer& buf, CDmAttribute *pSubKeys )
  84. {
  85. CDmrElementArray<> array( pSubKeys );
  86. int c = array.Count();
  87. for ( int i = 0; i < c; ++i )
  88. {
  89. CDmElement *pChild = array[i];
  90. if ( pChild )
  91. {
  92. SerializeElement( buf, pChild );
  93. }
  94. }
  95. }
  96. //-----------------------------------------------------------------------------
  97. // Serializes all attributes in an element
  98. //-----------------------------------------------------------------------------
  99. bool CDmSerializerKeyValues::SerializeAttributes( CUtlBuffer& buf, CDmElement *pElement )
  100. {
  101. // Collect the attributes to be written
  102. CDmAttribute **ppAttributes = ( CDmAttribute** )_alloca( pElement->AttributeCount() * sizeof( CDmAttribute* ) );
  103. int nAttributes = 0;
  104. for ( CDmAttribute *pAttribute = pElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
  105. {
  106. if ( pAttribute->IsFlagSet( FATTRIB_DONTSAVE | FATTRIB_STANDARD ) )
  107. continue;
  108. ppAttributes[ nAttributes++ ] = pAttribute;
  109. }
  110. // Now write them all out in reverse order, since FirstAttribute is actually the *last* attribute for perf reasons
  111. for ( int i = nAttributes - 1; i >= 0; --i )
  112. {
  113. CDmAttribute *pAttribute = ppAttributes[ i ];
  114. Assert( pAttribute );
  115. const char *pName = pAttribute->GetName();
  116. // Rename "_type", "_name", or "_id" fields, since they are special fields
  117. for ( int iAttr = 0; s_pAttributeRemap[i].m_pKeyValuesName; ++i )
  118. {
  119. if ( !Q_stricmp( pName, s_pAttributeRemap[iAttr].m_pDmeName ) )
  120. {
  121. pName = s_pAttributeRemap[iAttr].m_pKeyValuesName;
  122. break;
  123. }
  124. }
  125. DmAttributeType_t nAttrType = pAttribute->GetType();
  126. if ( ( nAttrType == AT_ELEMENT_ARRAY ) && !Q_stricmp( pName, "subkeys" ) )
  127. {
  128. SerializeSubKeys( buf, pAttribute );
  129. continue;
  130. }
  131. buf.Printf( "\"%s\" ", pName );
  132. switch( nAttrType )
  133. {
  134. case AT_VOID:
  135. case AT_STRING_ARRAY:
  136. case AT_VOID_ARRAY:
  137. case AT_ELEMENT:
  138. case AT_ELEMENT_ARRAY:
  139. Warning("KeyValues: Can't serialize attribute of type %s into KeyValues files!\n",
  140. g_pDataModel->GetAttributeNameForType( nAttrType ) );
  141. buf.PutChar( '\"' );
  142. buf.PutChar( '\"' );
  143. break;
  144. case AT_FLOAT:
  145. case AT_INT:
  146. case AT_BOOL:
  147. pAttribute->Serialize( buf );
  148. break;
  149. case AT_VECTOR4:
  150. case AT_VECTOR3:
  151. case AT_VECTOR2:
  152. case AT_STRING:
  153. default:
  154. buf.PutChar( '\"' );
  155. buf.PushTab();
  156. pAttribute->Serialize( buf );
  157. buf.PopTab();
  158. buf.PutChar( '\"' );
  159. break;
  160. }
  161. buf.PutChar( '\n' );
  162. }
  163. return true;
  164. }
  165. bool CDmSerializerKeyValues::SerializeElement( CUtlBuffer& buf, CDmElement *pElement )
  166. {
  167. buf.Printf( "\"%s\"\n{\n", pElement->GetName() );
  168. buf.PushTab();
  169. SerializeAttributes( buf, pElement );
  170. buf.PopTab();
  171. buf.Printf( "}\n" );
  172. return true;
  173. }
  174. bool CDmSerializerKeyValues::Serialize( CUtlBuffer &outBuf, CDmElement *pRoot )
  175. {
  176. if ( !pRoot )
  177. return true;
  178. CDmAttribute* pSubKeys = pRoot->GetAttribute( "subkeys" );
  179. if ( !pSubKeys )
  180. return true;
  181. //SetSerializationDelimiter( GetCStringCharConversion() );
  182. SerializeSubKeys( outBuf, pSubKeys );
  183. //SetSerializationDelimiter( NULL );
  184. return true;
  185. }
  186. //-----------------------------------------------------------------------------
  187. // Creates a scene object, adds it to the element dictionary
  188. //-----------------------------------------------------------------------------
  189. DmElementHandle_t CDmSerializerKeyValues::CreateDmElement( const char *pElementType, const char *pElementName )
  190. {
  191. // See if we can create an element of that type
  192. DmElementHandle_t hElement = g_pDataModel->CreateElement( pElementType, pElementName, m_fileid );
  193. if ( hElement == DMELEMENT_HANDLE_INVALID )
  194. {
  195. Warning("KeyValues: Element uses unknown element type %s\n", pElementType );
  196. return DMELEMENT_HANDLE_INVALID;
  197. }
  198. m_ElementList.AddToTail( hElement );
  199. CDmElement *pElement = g_pDataModel->GetElement( hElement );
  200. CDmeElementAccessor::MarkBeingUnserialized( pElement, true );
  201. return hElement;
  202. }
  203. //-----------------------------------------------------------------------------
  204. // Deterimines the attribute type of a keyvalue
  205. //-----------------------------------------------------------------------------
  206. DmAttributeType_t CDmSerializerKeyValues::DetermineAttributeType( KeyValues *pKeyValues )
  207. {
  208. // FIXME: Add detection of vectors/matrices?
  209. switch( pKeyValues->GetDataType() )
  210. {
  211. default:
  212. case KeyValues::TYPE_NONE:
  213. Assert( 0 );
  214. return AT_UNKNOWN;
  215. case KeyValues::TYPE_STRING:
  216. {
  217. float f1, f2, f3, f4;
  218. if ( sscanf( pKeyValues->GetString(), "%f %f %f %f", &f1, &f2, &f3, &f4 ) == 4 )
  219. return AT_VECTOR4;
  220. if ( sscanf( pKeyValues->GetString(), "%f %f %f",&f1, &f2, &f3 ) == 3 )
  221. return AT_VECTOR3;
  222. if ( sscanf( pKeyValues->GetString(), "%f %f", &f1, &f2 ) == 2 )
  223. return AT_VECTOR2;
  224. int i = pKeyValues->GetInt( NULL, INT_MAX );
  225. if ( ( sscanf( pKeyValues->GetString(), "%d", &i ) == 1 ) &&
  226. ( !strchr( pKeyValues->GetString(), '.' ) ) )
  227. return AT_INT;
  228. if ( sscanf( pKeyValues->GetString(), "%f", &f1 ) == 1 )
  229. return AT_FLOAT;
  230. return AT_STRING;
  231. }
  232. case KeyValues::TYPE_INT:
  233. return AT_INT;
  234. case KeyValues::TYPE_FLOAT:
  235. return AT_FLOAT;
  236. case KeyValues::TYPE_PTR:
  237. return AT_VOID;
  238. case KeyValues::TYPE_COLOR:
  239. return AT_COLOR;
  240. }
  241. }
  242. //-----------------------------------------------------------------------------
  243. // Reads an attribute for an element
  244. //-----------------------------------------------------------------------------
  245. void CDmSerializerKeyValues::UnserializeAttribute( CDmElement *pElement, KeyValues *pKeyValues )
  246. {
  247. // It's an attribute
  248. const char *pAttributeName = pKeyValues->GetName();
  249. const char *pAttributeValue = pKeyValues->GetString();
  250. // Convert to lower case
  251. CUtlString pLowerName = pAttributeName;
  252. pLowerName.ToLower();
  253. // Rename "type", "name", or "id" fields, since they are special fields
  254. for ( int i = 0; s_pAttributeRemap[i].m_pKeyValuesName; ++i )
  255. {
  256. if ( !Q_stricmp( pLowerName, s_pAttributeRemap[i].m_pKeyValuesName ) )
  257. {
  258. pLowerName = s_pAttributeRemap[i].m_pDmeName;
  259. break;
  260. }
  261. }
  262. // Element types are stored out by GUID, we need to hang onto the guid and
  263. // link it back up once all elements have been loaded from the file
  264. DmAttributeType_t type = DetermineAttributeType( pKeyValues );
  265. // In this case, we have an inlined element or element array attribute
  266. if ( type == AT_UNKNOWN )
  267. {
  268. // Assume this is an empty attribute or attribute array element
  269. Warning("Dm Unserialize: Attempted to read an attribute (\"%s\") of an inappropriate type!\n", pLowerName.Get() );
  270. return;
  271. }
  272. CDmAttribute *pAttribute = pElement->AddAttribute( pLowerName, type );
  273. if ( !pAttribute )
  274. {
  275. Warning("Dm Unserialize: Attempted to read an attribute (\"%s\") of an inappropriate type!\n", pLowerName.Get() );
  276. return;
  277. }
  278. switch( type )
  279. {
  280. case AT_STRING:
  281. {
  282. // Strings have different delimiter rules for KeyValues,
  283. // so let's just directly copy the string instead of going through unserialize
  284. pAttribute->SetValue( pAttributeValue );
  285. }
  286. break;
  287. default:
  288. {
  289. int nLen = Q_strlen( pAttributeValue );
  290. CUtlBuffer buf( pAttributeValue, nLen, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::READ_ONLY );
  291. pAttribute->Unserialize( buf );
  292. }
  293. break;
  294. }
  295. }
  296. //-----------------------------------------------------------------------------
  297. // Reads a single element
  298. //-----------------------------------------------------------------------------
  299. DmElementHandle_t CDmSerializerKeyValues::UnserializeElement( KeyValues *pKeyValues, int iNestingLevel )
  300. {
  301. const char *pElementName = pKeyValues->GetName( );
  302. const char *pszKeyValuesElement = g_pDataModel->GetKeyValuesElementName( pElementName, iNestingLevel );
  303. if ( !pszKeyValuesElement )
  304. {
  305. pszKeyValuesElement = "DmElement";
  306. }
  307. DmElementHandle_t handle = CreateDmElement( pszKeyValuesElement, pElementName );
  308. Assert( handle != DMELEMENT_HANDLE_INVALID );
  309. iNestingLevel++;
  310. CDmElement *pElement = g_pDataModel->GetElement( handle );
  311. CDmrElementArray<> subKeys;
  312. for ( KeyValues *pSub = pKeyValues->GetFirstSubKey(); pSub != NULL ; pSub = pSub->GetNextKey() )
  313. {
  314. // Read in a subkey
  315. if ( pSub->GetDataType() == KeyValues::TYPE_NONE )
  316. {
  317. if ( !subKeys.IsValid() )
  318. {
  319. subKeys.Init( pElement->AddAttribute( "subkeys", AT_ELEMENT_ARRAY ) );
  320. }
  321. DmElementHandle_t hChild = UnserializeElement( pSub, iNestingLevel );
  322. if ( hChild != DMELEMENT_HANDLE_INVALID )
  323. {
  324. subKeys.AddToTail( hChild );
  325. }
  326. }
  327. else
  328. {
  329. UnserializeAttribute( pElement, pSub );
  330. }
  331. }
  332. return handle;
  333. }
  334. //-----------------------------------------------------------------------------
  335. // Main entry point for the unserialization
  336. //-----------------------------------------------------------------------------
  337. CDmElement* CDmSerializerKeyValues::UnserializeFromKeyValues( KeyValues *pKeyValues )
  338. {
  339. m_ElementList.RemoveAll();
  340. m_hRoot = CreateDmElement( "DmElement", "root" );
  341. CDmElement *pRoot = g_pDataModel->GetElement( m_hRoot );
  342. CDmrElementArray<> subkeys( pRoot->AddAttribute( "subkeys", AT_ELEMENT_ARRAY ) );
  343. int iNestingLevel = 0;
  344. for ( KeyValues *pElementKey = pKeyValues; pElementKey != NULL; pElementKey = pElementKey->GetNextKey() )
  345. {
  346. DmElementHandle_t hChild = UnserializeElement( pElementKey, iNestingLevel );
  347. if ( hChild != DMELEMENT_HANDLE_INVALID )
  348. {
  349. subkeys.AddToTail( hChild );
  350. }
  351. }
  352. // mark all unserialized elements as done unserializing, and call Resolve()
  353. int c = m_ElementList.Count();
  354. for ( int i = 0; i < c; ++i )
  355. {
  356. CDmElement *pElement = g_pDataModel->GetElement( m_ElementList[i] );
  357. CDmeElementAccessor::MarkBeingUnserialized( pElement, false );
  358. }
  359. g_pDmElementFrameworkImp->RemoveCleanElementsFromDirtyList( );
  360. m_ElementList.RemoveAll();
  361. return pRoot;
  362. }
  363. //-----------------------------------------------------------------------------
  364. // Main entry point for the unserialization
  365. //-----------------------------------------------------------------------------
  366. bool CDmSerializerKeyValues::Unserialize( CUtlBuffer &buf, const char *pEncodingName, int nEncodingVersion,
  367. const char *pSourceFormatName, int nSourceFormatVersion,
  368. DmFileId_t fileid, DmConflictResolution_t idConflictResolution, CDmElement **ppRoot )
  369. {
  370. Assert( !V_stricmp( pEncodingName, "keyvalues" ) );
  371. *ppRoot = NULL;
  372. KeyValues *kv = new KeyValues( "keyvalues file" );
  373. if ( !kv )
  374. return false;
  375. m_fileid = fileid;
  376. bool bOk = kv->LoadFromBuffer( "keyvalues file", buf );
  377. if ( bOk )
  378. {
  379. //SetSerializationDelimiter( GetCStringCharConversion() );
  380. *ppRoot = UnserializeFromKeyValues( kv );
  381. //SetSerializationDelimiter( NULL );
  382. }
  383. m_fileid = DMFILEID_INVALID;
  384. kv->deleteThis();
  385. return bOk;
  386. }