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.

443 lines
14 KiB

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