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.

931 lines
30 KiB

  1. //===== Copyright c 1996-2008, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "resourcefile/schema.h"
  8. #include "resourcesystem/iresourcesystem.h"
  9. #include "tier1/generichash.h"
  10. #include "tier0/dbg.h"
  11. // Must be last
  12. #include "tier0/memdbgon.h"
  13. #define STRUCT_NAME_HASH_SEED 0xBAADFEED
  14. #define FIELD_CRC_HASH_SEED 0x12345678
  15. //-----------------------------------------------------------------------------
  16. // Computes a resource structure id given a structure name string
  17. //-----------------------------------------------------------------------------
  18. ResourceStructureId_t ComputeStructureNameHash( const char *pStructName )
  19. {
  20. int nLength = Q_strlen( pStructName );
  21. return (ResourceStructureId_t)MurmurHash2( pStructName, nLength, STRUCT_NAME_HASH_SEED );
  22. }
  23. //////////////////////////////////////////////////////////////////////////
  24. CResourceIntrospection* CResourceIntrospection::AddToStream( CResourceStream *pStream, ResourceFileHeader_t *pHeader, int nBlockIndex )
  25. {
  26. CResourceIntrospection* pResult = Resource_AllocateBlock< CResourceIntrospection >( pStream, pHeader, nBlockIndex );
  27. pResult->m_nVersion = RESOURCE_INTROSPECTION_VERSION;
  28. pResult->m_Metadata = NULL;
  29. return pResult;
  30. }
  31. const CResourceIntrospection* CResourceIntrospection::FindInFile( const ResourceFileHeader_t *pHeader )
  32. {
  33. const CResourceIntrospection* pResult = Resource_GetBlock<CResourceIntrospection>( pHeader );
  34. Assert( !pResult || pResult->m_nVersion == RESOURCE_INTROSPECTION_VERSION );
  35. return pResult;
  36. }
  37. uint32 CResourceIntrospection::GetVersion() const
  38. {
  39. return m_nVersion;
  40. }
  41. const CResourceStructIntrospection* CResourceIntrospection::FindStructIntrospectionForResourceType( ResourceType_t nType ) const
  42. {
  43. // FIXME: Assumes identical ResourceTypeEngine_t + metadata
  44. const CResourceStructIntrospection* pLocalStruct = g_pResourceSystem->FindStructIntrospectionForResourceType( nType );
  45. if ( pLocalStruct )
  46. {
  47. return FindStructIntrospection( pLocalStruct->m_nId );
  48. }
  49. else
  50. {
  51. return NULL;
  52. }
  53. /*
  54. const CResourceEnumIntrospection* pEnumIntrospect = FindEnumIntrospection( "ResourceTypeEngine_t" );
  55. if ( pEnumIntrospect == NULL )
  56. {
  57. Warning( "Encountered a CResourceIntrospection with no ResourceTypeEngine_t entry.\n" );
  58. return NULL;
  59. }
  60. const char *pResourceType = pEnumIntrospect->FindEnumString( nType );
  61. for ( int i = 0; i < m_StructIntrospection.Count(); ++i )
  62. {
  63. if ( !Q_stricmp( m_StructIntrospection[i].m_pResourceType, pResourceType ) )
  64. return &m_StructIntrospection[i];
  65. }
  66. return NULL;
  67. */
  68. }
  69. const CResourceStructIntrospection* CResourceIntrospection::FindPermanentStructIntrospectionForResourceType( ResourceType_t nType ) const
  70. {
  71. // FIXME: Assumes identical ResourceTypeEngine_t + metadata
  72. const CResourceStructIntrospection* pLocalStruct = g_pResourceSystem->FindPermanentStructIntrospectionForResourceType( nType );
  73. if ( pLocalStruct )
  74. {
  75. return FindStructIntrospection( pLocalStruct->m_nId );
  76. }
  77. else
  78. {
  79. return NULL;
  80. }
  81. /*
  82. const CResourceEnumIntrospection* pEnumIntrospect = FindEnumIntrospection( "ResourceTypeEngine_t" );
  83. if ( pEnumIntrospect == NULL )
  84. {
  85. // See above
  86. Warning( "Encountered a CResourceIntrospection with no ResourceTypeEngine_t entry.\n" );
  87. return NULL;
  88. }
  89. const char *pResourceType = pEnumIntrospect->FindEnumString( nType );
  90. for ( int i = 0; i < m_StructIntrospection.Count(); ++i )
  91. {
  92. if ( !Q_stricmp( m_StructIntrospection[i].m_pResourceType, pResourceType ) )
  93. return FindStructIntrospection( m_StructIntrospection[i].m_nUncacheableStructId );
  94. }
  95. return NULL;
  96. */
  97. }
  98. //-----------------------------------------------------------------------------
  99. // Iteration of resource introspection structs
  100. //-----------------------------------------------------------------------------
  101. int CResourceIntrospection::GetStructCount() const
  102. {
  103. return m_StructIntrospection.Count();
  104. }
  105. const CResourceStructIntrospection* CResourceIntrospection::GetStructIntrospection( int nIndex ) const
  106. {
  107. return &m_StructIntrospection[nIndex];
  108. }
  109. CResourceStructIntrospection* CResourceIntrospection::GetWritableStructIntrospection( int nIndex )
  110. {
  111. return &m_StructIntrospection[nIndex];
  112. }
  113. //-----------------------------------------------------------------------------
  114. // Finds a struct introspection record
  115. //-----------------------------------------------------------------------------
  116. const CResourceStructIntrospection* CResourceIntrospection::FindStructIntrospection( ResourceStructureId_t id ) const
  117. {
  118. int nCount = GetStructCount();
  119. for ( int i = 0; i < nCount; ++i )
  120. {
  121. if ( m_StructIntrospection[i].m_nId == id )
  122. return &m_StructIntrospection[i];
  123. }
  124. return NULL;
  125. }
  126. const CResourceStructIntrospection* CResourceIntrospection::FindStructIntrospection( const char *pStructName ) const
  127. {
  128. ResourceStructureId_t id = ComputeStructureNameHash( pStructName );
  129. return FindStructIntrospection( id );
  130. }
  131. //-----------------------------------------------------------------------------
  132. // Iteration of resource introspection enums
  133. //-----------------------------------------------------------------------------
  134. int CResourceIntrospection::GetEnumCount() const
  135. {
  136. return m_EnumIntrospection.Count();
  137. }
  138. const CResourceEnumIntrospection* CResourceIntrospection::GetEnumIntrospection( int nIndex ) const
  139. {
  140. return &m_EnumIntrospection[nIndex];
  141. }
  142. CResourceEnumIntrospection* CResourceIntrospection::GetWritableEnumIntrospection( int nIndex )
  143. {
  144. return &m_EnumIntrospection[nIndex];
  145. }
  146. //-----------------------------------------------------------------------------
  147. // Finds an enum introspection record
  148. //-----------------------------------------------------------------------------
  149. const CResourceEnumIntrospection* CResourceIntrospection::FindEnumIntrospection( ResourceStructureId_t id ) const
  150. {
  151. int nCount = GetEnumCount();
  152. for ( int i = 0; i < nCount; ++i )
  153. {
  154. if ( m_EnumIntrospection[i].m_nId == id )
  155. return &m_EnumIntrospection[i];
  156. }
  157. return NULL;
  158. }
  159. const CResourceEnumIntrospection* CResourceIntrospection::FindEnumIntrospection( const char *pEnumName ) const
  160. {
  161. ResourceStructureId_t id = ComputeStructureNameHash( pEnumName );
  162. return FindEnumIntrospection( id );
  163. }
  164. //-----------------------------------------------------------------------------
  165. // Iteration of resource introspection typedefs
  166. //-----------------------------------------------------------------------------
  167. int CResourceIntrospection::GetTypedefCount() const
  168. {
  169. return m_TypedefIntrospection.Count();
  170. }
  171. const CResourceTypedefIntrospection* CResourceIntrospection::GetTypedefIntrospection( int nIndex ) const
  172. {
  173. return &m_TypedefIntrospection[nIndex];
  174. }
  175. CResourceTypedefIntrospection* CResourceIntrospection::GetWritableTypedefIntrospection( int nIndex )
  176. {
  177. return &m_TypedefIntrospection[nIndex];
  178. }
  179. //-----------------------------------------------------------------------------
  180. // Methods used for writing data
  181. //-----------------------------------------------------------------------------
  182. void CResourceIntrospection::AllocateStructs( CResourceStream *pStream, int nCount )
  183. {
  184. m_StructIntrospection = pStream->Allocate< CResourceStructIntrospection >( nCount );
  185. }
  186. void CResourceIntrospection::AllocateEnums( CResourceStream *pStream, int nCount )
  187. {
  188. m_EnumIntrospection = pStream->Allocate< CResourceEnumIntrospection >( nCount );
  189. }
  190. void CResourceIntrospection::AllocateTypedefs( CResourceStream *pStream, int nCount )
  191. {
  192. m_TypedefIntrospection = pStream->Allocate< CResourceTypedefIntrospection >( nCount );
  193. }
  194. IntrospectionCompatibilityType_t CResourceIntrospection::CalculateCompatibility( ) const
  195. {
  196. IntrospectionCompatibilityType_t nCompatibilityType = INTROSPECTION_COMPAT_IDENTICAL;
  197. for ( int i = 0; i < m_StructIntrospection.Count(); ++i )
  198. {
  199. const CResourceStructIntrospection *pMine = &m_StructIntrospection[i];
  200. const CResourceStructIntrospection *pGlobal = g_pResourceSystem->FindStructIntrospection( pMine->m_nId );
  201. if ( pGlobal == NULL )
  202. {
  203. Warning( "Resource introspection block contained a struct '%s' which doesn't exist anymore.\n", pMine->m_pName.GetPtr() );
  204. return INTROSPECTION_COMPAT_REQUIRES_CONVERSION;
  205. }
  206. if ( pMine->m_nCrc != pGlobal->m_nCrc )
  207. {
  208. return INTROSPECTION_COMPAT_REQUIRES_CONVERSION;
  209. }
  210. if ( pGlobal->m_nDiskSize != pGlobal->m_nMemorySize )
  211. {
  212. if ( !V_strcmp( pMine->m_pName, "MaterialDrawDescriptor_t" ) )
  213. {
  214. Warning( "****** HARDCODED CHECK FOR MaterialDrawDescriptor_t - REPLACE WITH METADATA LOOKUP WHEN AVAILABLE ******\n" );
  215. continue;
  216. }
  217. if ( nCompatibilityType == INTROSPECTION_COMPAT_IDENTICAL )
  218. {
  219. // don't want to say scatter if other things require full conversion
  220. nCompatibilityType = INTROSPECTION_COMPAT_REQUIRES_SCATTER;
  221. }
  222. }
  223. }
  224. for ( int i = 0; i < m_EnumIntrospection.Count(); ++i )
  225. {
  226. const CResourceEnumIntrospection *pMine = &m_EnumIntrospection[i];
  227. const CResourceEnumIntrospection *pGlobal = g_pResourceSystem->FindEnumIntrospection( pMine->m_nId );
  228. if ( pMine->m_nCrc != pGlobal->m_nCrc )
  229. {
  230. return INTROSPECTION_COMPAT_REQUIRES_CONVERSION;
  231. }
  232. }
  233. return nCompatibilityType;
  234. }
  235. //-----------------------------------------------------------------------------
  236. //
  237. // Introspection data associated with a single structure
  238. //
  239. //-----------------------------------------------------------------------------
  240. //-----------------------------------------------------------------------------
  241. // Iteration of fields of a particular struct
  242. //-----------------------------------------------------------------------------
  243. int CResourceStructIntrospection::GetFieldCount() const
  244. {
  245. return m_FieldIntrospection.Count();
  246. }
  247. const CResourceFieldIntrospection* CResourceStructIntrospection::GetField( int nIndex ) const
  248. {
  249. return &m_FieldIntrospection[nIndex];
  250. }
  251. CResourceFieldIntrospection* CResourceStructIntrospection::GetWritableField( int nIndex )
  252. {
  253. return &m_FieldIntrospection[nIndex];
  254. }
  255. //-----------------------------------------------------------------------------
  256. // Find a field
  257. //-----------------------------------------------------------------------------
  258. const CResourceFieldIntrospection* CResourceStructIntrospection::FindField( const char *pFieldName ) const
  259. {
  260. int nCount = GetFieldCount();
  261. for ( int i = 0; i < nCount; ++i )
  262. {
  263. if ( !Q_stricmp( m_FieldIntrospection[i].m_pFieldName, pFieldName ) )
  264. return &m_FieldIntrospection[i];
  265. }
  266. return NULL;
  267. }
  268. //-----------------------------------------------------------------------------
  269. // Methods used for writing data
  270. //-----------------------------------------------------------------------------
  271. static char s_pEmptyBlockType[4] = { 0, 0, 0, 0 };
  272. void CResourceStructIntrospection::SetStructInfo( CResourceStream *pStream,
  273. const char *pStructName, const char *pBaseStruct, const char *pUncacheableStruct, uint32 nMemorySize, uint32 nDiskSize,
  274. uint32 nAlignment, const char *pDmeElementType, const char *pBlockType, const char *pResourceType, bool bHasVTable )
  275. {
  276. ResourceStructureId_t id = ComputeStructureNameHash( pStructName );
  277. ResourceStructureId_t baseId = pBaseStruct ? ComputeStructureNameHash( pBaseStruct ) : 0;
  278. ResourceStructureId_t uncacheableId = pUncacheableStruct ? ComputeStructureNameHash( pUncacheableStruct ) : 0;
  279. m_pName = pStream->WriteString( pStructName );
  280. m_nId = id;
  281. m_nBaseStructId = baseId;
  282. m_nUncacheableStructId = uncacheableId;
  283. m_pDmeElementType = pStream->WriteString( pDmeElementType );
  284. m_nMemorySize = nMemorySize;
  285. m_nDiskSize = nDiskSize;
  286. m_nAlignment = nAlignment;
  287. if ( !pBlockType || !pBlockType[0] )
  288. {
  289. pBlockType = s_pEmptyBlockType;
  290. }
  291. memcpy( m_ResourceBlockType, pBlockType, 4 * sizeof(uint8) );
  292. m_pResourceType = pStream->WriteString( pResourceType );
  293. m_nStructFlags = bHasVTable ? RESOURCE_STRUCT_HAS_VTABLE : 0;
  294. }
  295. bool CResourceStructIntrospection::HasVTable() const
  296. {
  297. return (m_nStructFlags & RESOURCE_STRUCT_HAS_VTABLE);
  298. }
  299. void CResourceStructIntrospection::SetStructInfo( CResourceStream *pStream, const CResourceStructIntrospection *src )
  300. {
  301. SetStructInfo( pStream, src->m_pName, NULL, NULL, src->m_nMemorySize, src->m_nDiskSize, src->m_nAlignment, src->m_pDmeElementType, (const char*)src->m_ResourceBlockType, src->m_pResourceType, src->HasVTable() );
  302. m_nBaseStructId = src->m_nBaseStructId;
  303. m_nUncacheableStructId = src->m_nUncacheableStructId;
  304. }
  305. void CResourceStructIntrospection::ComputeCRC( CResourceStream *pStream )
  306. {
  307. m_nCrc = MurmurHash2( m_FieldIntrospection.GetPtr(),
  308. m_FieldIntrospection.Count() * sizeof(CResourceFieldIntrospection),
  309. FIELD_CRC_HASH_SEED );
  310. }
  311. void CResourceStructIntrospection::AllocateFields( CResourceStream *pStream, int nCount )
  312. {
  313. m_FieldIntrospection = pStream->Allocate< CResourceFieldIntrospection >( nCount );
  314. }
  315. //-----------------------------------------------------------------------------
  316. //
  317. // Introspection data associated with a field in a structure
  318. //
  319. //-----------------------------------------------------------------------------
  320. DEFINE_SCHEMA_DATA_CLASS( CResourceFieldIntrospection );
  321. void CResourceFieldIntrospection::SetFieldInfo( CResourceStream *pStream,
  322. const char *pFieldName, int nMemoryOffset, int nDiskOffset, int nArrayCount )
  323. {
  324. m_pFieldName = pStream->WriteString( pFieldName );
  325. m_nInMemoryOffset = nMemoryOffset;
  326. m_nOnDiskOffset = nDiskOffset;
  327. m_nCount = nArrayCount;
  328. }
  329. void CResourceFieldIntrospection::SetFieldType( CResourceStream *pStream,
  330. const CUtlVector<ResourceFieldType_t>& TypeChain, uint32 nRootFieldData )
  331. {
  332. Assert( TypeChain.Count() > 0 );
  333. m_nTypeChainCount = TypeChain.Count();
  334. m_nFieldType = TypeChain[0];
  335. if ( m_nTypeChainCount == 1 )
  336. {
  337. m_nTypeChain = nRootFieldData;
  338. }
  339. else
  340. {
  341. CLockedResource<uint32> pChainAlloc = pStream->Allocate<uint32>( m_nTypeChainCount );
  342. for ( int i = 1; i < m_nTypeChainCount; ++i )
  343. {
  344. pChainAlloc[i-1] = TypeChain[i];
  345. }
  346. pChainAlloc[m_nTypeChainCount-1] = nRootFieldData;
  347. CResourcePointer<uint32>* pResult = reinterpret_cast< CResourcePointer<uint32>* >( &m_nTypeChain );
  348. *pResult = pChainAlloc;
  349. }
  350. }
  351. void CResourceFieldIntrospection::SetFieldInfo( CResourceStream *pStream, const CResourceFieldIntrospection *src )
  352. {
  353. SetFieldInfo( pStream, src->m_pFieldName, src->m_nInMemoryOffset, src->m_nOnDiskOffset, src->m_nCount );
  354. m_nTypeChainCount = src->m_nTypeChainCount;
  355. m_nFieldType = src->ReadTypeChain(0);
  356. if ( m_nTypeChainCount == 1 )
  357. {
  358. m_nTypeChain = src->GetRootTypeData();
  359. }
  360. else
  361. {
  362. CLockedResource<uint32> pChainAlloc = pStream->Allocate<uint32>( m_nTypeChainCount );
  363. for ( int i = 1; i < m_nTypeChainCount; ++i )
  364. {
  365. pChainAlloc[i-1] = src->ReadTypeChain(i);
  366. }
  367. pChainAlloc[m_nTypeChainCount-1] = src->GetRootTypeData();
  368. CResourcePointer<uint32>* pResult = reinterpret_cast< CResourcePointer<uint32>* >( &m_nTypeChain );
  369. *pResult = pChainAlloc;
  370. }
  371. }
  372. ResourceFieldType_t CResourceFieldIntrospection::ReadTypeChain( int nChainIndex ) const
  373. {
  374. Assert ( nChainIndex < m_nTypeChainCount );
  375. if ( nChainIndex == 0 )
  376. {
  377. // fieldtype is always the first element
  378. return (ResourceFieldType_t)m_nFieldType;
  379. }
  380. else
  381. {
  382. return (ResourceFieldType_t)(((const CResourcePointer<const uint32>*)( &m_nTypeChain ))->GetPtr())[nChainIndex-1];
  383. }
  384. }
  385. uint32 CResourceFieldIntrospection::GetRootTypeData() const
  386. {
  387. if ( m_nTypeChainCount == 1 )
  388. {
  389. return m_nTypeChain;
  390. }
  391. else
  392. {
  393. const uint32* pChain = ((const CResourcePointer<const uint32>*)( &m_nTypeChain ))->GetPtr();
  394. return pChain[m_nTypeChainCount-1];
  395. }
  396. }
  397. ResourceFieldType_t CResourceFieldIntrospection::GetRootType() const
  398. {
  399. if ( m_nTypeChainCount == 1 )
  400. {
  401. return (ResourceFieldType_t)m_nFieldType;
  402. }
  403. else
  404. {
  405. Assert( m_nTypeChainCount >= 2 );
  406. const uint32* pChain = ((const CResourcePointer<const uint32>*)( &m_nTypeChain ))->GetPtr();
  407. return (ResourceFieldType_t)pChain[m_nTypeChainCount-2];
  408. }
  409. }
  410. int CResourceFieldIntrospection::GetElementMemorySize( int nTypeChainIndex, const CResourceIntrospection* pIntroDct ) const
  411. {
  412. ResourceFieldType_t fieldType = ReadTypeChain( nTypeChainIndex );
  413. if ( fieldType == RESOURCE_FIELD_TYPE_STRUCT )
  414. {
  415. // a struct must be at the end of a type chain
  416. Assert( nTypeChainIndex == m_nTypeChainCount - 1 );
  417. const CResourceStructIntrospection* pStructIntro = NULL;
  418. if ( pIntroDct != NULL )
  419. {
  420. pStructIntro = pIntroDct->FindStructIntrospection( (ResourceStructureId_t)GetRootTypeData() );
  421. }
  422. else
  423. {
  424. pStructIntro = g_pResourceSystem->FindStructIntrospection( (ResourceStructureId_t)GetRootTypeData() );
  425. }
  426. Assert( pStructIntro != NULL );
  427. return pStructIntro->m_nMemorySize;
  428. }
  429. else
  430. {
  431. return g_pResourceSystem->GetFieldSize( fieldType );
  432. }
  433. }
  434. int CResourceFieldIntrospection::GetElementDiskSize( int nTypeChainIndex, const CResourceIntrospection* pIntroDct ) const
  435. {
  436. ResourceFieldType_t fieldType = ReadTypeChain( nTypeChainIndex );
  437. if ( fieldType == RESOURCE_FIELD_TYPE_STRUCT )
  438. {
  439. // a struct must be at the end of a type chain
  440. Assert( nTypeChainIndex == m_nTypeChainCount - 1 );
  441. const CResourceStructIntrospection* pStructIntro = NULL;
  442. if ( pIntroDct != NULL )
  443. {
  444. pStructIntro = pIntroDct->FindStructIntrospection( (ResourceStructureId_t)GetRootTypeData() );
  445. }
  446. else
  447. {
  448. pStructIntro = g_pResourceSystem->FindStructIntrospection( (ResourceStructureId_t)GetRootTypeData() );
  449. }
  450. Assert( pStructIntro != NULL );
  451. return pStructIntro->m_nDiskSize;
  452. }
  453. else
  454. {
  455. return g_pResourceSystem->GetFieldSize( fieldType );
  456. }
  457. }
  458. int CResourceFieldIntrospection::GetElementSize( const ResourceDataLayout_t nDataLocation, int nTypeChainIndex, const CResourceIntrospection* pIntroDct ) const
  459. {
  460. if ( nDataLocation == RESOURCE_DATA_LAYOUT_MEMORY )
  461. {
  462. return GetElementMemorySize(nTypeChainIndex,pIntroDct);
  463. }
  464. else
  465. {
  466. Assert( nDataLocation == RESOURCE_DATA_LAYOUT_DISK );
  467. return GetElementDiskSize(nTypeChainIndex,pIntroDct);
  468. }
  469. }
  470. int CResourceFieldIntrospection::GetElementAlignment( int nTypeChainIndex, const CResourceIntrospection* pIntroDct ) const
  471. {
  472. ResourceFieldType_t fieldType = ReadTypeChain( nTypeChainIndex );
  473. if ( fieldType == RESOURCE_FIELD_TYPE_STRUCT )
  474. {
  475. // a struct must be at the end of a type chain
  476. Assert( nTypeChainIndex == m_nTypeChainCount - 1 );
  477. const CResourceStructIntrospection* pStructIntro = NULL;
  478. if ( pIntroDct != NULL )
  479. {
  480. pStructIntro = pIntroDct->FindStructIntrospection( (ResourceStructureId_t)GetRootTypeData() );
  481. }
  482. else
  483. {
  484. pStructIntro = g_pResourceSystem->FindStructIntrospection( (ResourceStructureId_t)GetRootTypeData() );
  485. }
  486. Assert( pStructIntro != NULL );
  487. return pStructIntro->m_nAlignment;
  488. }
  489. else
  490. {
  491. return g_pResourceSystem->GetFieldAlignment( fieldType );
  492. }
  493. }
  494. //-----------------------------------------------------------------------------
  495. //
  496. // Introspection data associated with a single enumerated type
  497. //
  498. //-----------------------------------------------------------------------------
  499. DEFINE_SCHEMA_DATA_CLASS( CResourceEnumIntrospection );
  500. int CResourceEnumIntrospection::GetEnumValueCount() const
  501. {
  502. return m_EnumValueIntrospection.Count();
  503. }
  504. const CResourceEnumValueIntrospection* CResourceEnumIntrospection::GetEnumValue( int nIndex ) const
  505. {
  506. return &m_EnumValueIntrospection[nIndex];
  507. }
  508. CResourceEnumValueIntrospection* CResourceEnumIntrospection::GetWritableEnumValue( int nIndex )
  509. {
  510. return &m_EnumValueIntrospection[nIndex];
  511. }
  512. const CResourceEnumValueIntrospection* CResourceEnumIntrospection::FindEnumValue( const char *pEnumValueName ) const
  513. {
  514. int nCount = GetEnumValueCount();
  515. for ( int i = 0; i < nCount; ++i )
  516. {
  517. if ( !Q_stricmp( m_EnumValueIntrospection[i].m_pEnumValueName, pEnumValueName ) )
  518. return &m_EnumValueIntrospection[i];
  519. }
  520. return NULL;
  521. }
  522. const char *CResourceEnumIntrospection::FindEnumString( int nValue ) const
  523. {
  524. int nCount = GetEnumValueCount();
  525. for ( int i = 0; i < nCount; ++i )
  526. {
  527. if ( m_EnumValueIntrospection[i].m_nEnumValue == nValue )
  528. return m_EnumValueIntrospection[i].m_pEnumValueName;
  529. }
  530. return NULL;
  531. }
  532. void CResourceEnumIntrospection::SetEnumName( CResourceStream *pStream, const char *pEnumName )
  533. {
  534. m_pName = pStream->WriteString( pEnumName );
  535. m_nId = ComputeStructureNameHash( pEnumName );
  536. }
  537. void CResourceEnumIntrospection::ComputeCRC( CResourceStream *pStream )
  538. {
  539. m_nCrc = MurmurHash2( m_EnumValueIntrospection.GetPtr(),
  540. m_EnumValueIntrospection.Count() * sizeof(CResourceEnumValueIntrospection),
  541. FIELD_CRC_HASH_SEED );
  542. }
  543. void CResourceEnumIntrospection::AllocateEnumValues( CResourceStream *pStream, int nCount )
  544. {
  545. m_EnumValueIntrospection = pStream->Allocate< CResourceEnumValueIntrospection >( nCount );
  546. }
  547. void CResourceEnumValueIntrospection::SetEnumValueInfo( CResourceStream *pStream, const char *pEnumValueName, int32 nValue )
  548. {
  549. m_pEnumValueName = pStream->WriteString( pEnumValueName );
  550. m_nEnumValue = nValue;
  551. }
  552. const char *CResourceEnumValueIntrospection::GetName() const
  553. {
  554. return m_pEnumValueName;
  555. }
  556. int CResourceEnumValueIntrospection::GetValue() const
  557. {
  558. return m_nEnumValue;
  559. }
  560. //-----------------------------------------------------------------------------
  561. //
  562. // Introspection data associated with a typedef
  563. //
  564. //-----------------------------------------------------------------------------
  565. DEFINE_SCHEMA_DATA_CLASS( CResourceTypedefIntrospection );
  566. void CResourceTypedefIntrospection::SetTypedefInfo( CResourceStream *pStream, const char *pTypedefName, const char *pTypedefType )
  567. {
  568. m_nId = ComputeStructureNameHash( pTypedefName );
  569. m_pName = pStream->WriteString( pTypedefName );
  570. m_pType = pStream->WriteString( pTypedefType );
  571. }
  572. //-----------------------------------------------------------------------------
  573. //
  574. // Helper for traversal of an introspected piece of memory
  575. //
  576. //-----------------------------------------------------------------------------
  577. CResourceIntrospectionTraversal::CResourceIntrospectionTraversal( const CResourceIntrospection *pResIntro ) :
  578. m_pResIntro( pResIntro ),
  579. m_bTraverseDiskLayout( false )
  580. {
  581. }
  582. void CResourceIntrospectionTraversal::TraverseStruct( const void *pStruct, const CResourceStructIntrospection *pStructIntro )
  583. {
  584. Assert( pStruct != NULL );
  585. Assert( pStructIntro != NULL );
  586. if ( !VisitStruct( pStruct, pStructIntro ) )
  587. {
  588. return;
  589. }
  590. int nFields = pStructIntro->GetFieldCount();
  591. for ( int i = 0; i < nFields; ++i )
  592. {
  593. const CResourceFieldIntrospection *pFieldIntro = pStructIntro->GetField(i);
  594. void *pField = (uint8*)pStruct + ( m_bTraverseDiskLayout ?
  595. pFieldIntro->m_nOnDiskOffset :
  596. pFieldIntro->m_nInMemoryOffset );
  597. TraverseField( pField, pFieldIntro, (ResourceFieldType_t)pFieldIntro->m_nFieldType, 0 );
  598. }
  599. }
  600. void CResourceIntrospectionTraversal::TraverseRootField( const void *pField, const CResourceFieldIntrospection *pFieldIntro )
  601. {
  602. if ( !VisitRootField( pField, pFieldIntro ) )
  603. {
  604. return;
  605. }
  606. if ( pField == NULL )
  607. {
  608. return;
  609. }
  610. ResourceFieldType_t nFieldType = pFieldIntro->GetRootType();
  611. uint32 nFieldData = pFieldIntro->GetRootTypeData();
  612. switch( nFieldType )
  613. {
  614. case RESOURCE_FIELD_TYPE_STRUCT:
  615. {
  616. const CResourceStructIntrospection* pStructIntro = NULL;
  617. if ( m_pResIntro )
  618. {
  619. pStructIntro = m_pResIntro->FindStructIntrospection( (ResourceStructureId_t)nFieldData );
  620. }
  621. else
  622. {
  623. pStructIntro = g_pResourceSystem->FindStructIntrospection( (ResourceStructureId_t)nFieldData );
  624. }
  625. TraverseStruct( pField, pStructIntro );
  626. break;
  627. }
  628. case RESOURCE_FIELD_TYPE_ENUM:
  629. {
  630. const CResourceEnumIntrospection* pEnumIntro = NULL;
  631. if ( m_pResIntro )
  632. {
  633. pEnumIntro = m_pResIntro->FindEnumIntrospection( (ResourceStructureId_t)nFieldData );
  634. }
  635. else
  636. {
  637. pEnumIntro = g_pResourceSystem->FindEnumIntrospection( (ResourceStructureId_t)nFieldData );
  638. }
  639. VisitEnum( pField, pEnumIntro );
  640. break;
  641. }
  642. }
  643. }
  644. void CResourceIntrospectionTraversal::TraverseField( const void *pField, const CResourceFieldIntrospection *pFieldIntro, ResourceFieldType_t fieldType, int nTypeChainIndex )
  645. {
  646. if ( !VisitField( pField, pFieldIntro, nTypeChainIndex ) )
  647. {
  648. return;
  649. }
  650. int nElementSize = m_bTraverseDiskLayout ? pFieldIntro->GetElementDiskSize( nTypeChainIndex, m_pResIntro )
  651. : pFieldIntro->GetElementMemorySize( nTypeChainIndex, m_pResIntro );
  652. int nInlineCount = 1;
  653. if ( nTypeChainIndex == 0 )
  654. {
  655. nInlineCount = pFieldIntro->m_nCount > 0 ? pFieldIntro->m_nCount : 1;
  656. }
  657. if ( nTypeChainIndex == pFieldIntro->m_nTypeChainCount-1 )
  658. {
  659. for ( int i = 0; i < nInlineCount; ++i )
  660. {
  661. void* pFieldInstance = (byte*)pField + nElementSize * i;
  662. TraverseRootField( pFieldInstance, pFieldIntro );
  663. }
  664. }
  665. else
  666. {
  667. ResourceFieldType_t subFieldType = pFieldIntro->ReadTypeChain(nTypeChainIndex);
  668. for ( int i = 0; i < nInlineCount; ++i )
  669. {
  670. void* pFieldInstance = (byte*)pField + nElementSize * i;
  671. switch ( fieldType )
  672. {
  673. case RESOURCE_FIELD_TYPE_RESOURCE_POINTER:
  674. {
  675. void *pPointedTo = ( ( CResourcePointer< char >* )pFieldInstance )->GetPtr();
  676. TraverseField( pPointedTo, pFieldIntro, subFieldType, nTypeChainIndex + 1 );
  677. break;
  678. }
  679. case RESOURCE_FIELD_TYPE_RESOURCE_REFERENCE:
  680. {
  681. // SCHEMAFIXME: Sometimes we might want to follow resource references during a traversal
  682. break;
  683. }
  684. case RESOURCE_FIELD_TYPE_RESOURCE_ARRAY:
  685. {
  686. int nStride = m_bTraverseDiskLayout ? pFieldIntro->GetElementDiskSize( nTypeChainIndex+1, m_pResIntro )
  687. : pFieldIntro->GetElementMemorySize( nTypeChainIndex+1, m_pResIntro );
  688. // can't do a CResourceArray cast because element size is unknown
  689. uint32 nArrayCount = ((uint32*)pFieldInstance)[1];
  690. if ( nArrayCount )
  691. {
  692. byte* pArrayRoot = ResolveOffsetFast( (const int32*)pFieldInstance );
  693. for ( uint32 i = 0; i < nArrayCount; ++i )
  694. {
  695. TraverseField( pArrayRoot+i*nStride, pFieldIntro, subFieldType, nTypeChainIndex + 1 );
  696. }
  697. }
  698. break;
  699. }
  700. case RESOURCE_FIELD_TYPE_C_POINTER:
  701. {
  702. void *pPointedTo = *((void**)pFieldInstance);
  703. TraverseField( pPointedTo, pFieldIntro, subFieldType, nTypeChainIndex + 1 );
  704. break;
  705. }
  706. break;
  707. default:
  708. AssertMsg(false, "Unrecognized non-root resource field type" );
  709. break;
  710. }
  711. }
  712. }
  713. PostVisitField( pField, pFieldIntro, nTypeChainIndex );
  714. }
  715. //////////////////////////////////////////////////////////////////////////
  716. #define DEFINE_TYPE( _type_name, _resource_field_type, _memory_size, _disk_size, _alignment )\
  717. { _type_name, _resource_field_type, _memory_size, _disk_size, _alignment }
  718. #define DEFINE_ATOMIC_TYPE_SIMPLE( _type_name, _resource_field_type ) DEFINE_TYPE( #_type_name, _resource_field_type, sizeof(_type_name), sizeof(_type_name), sizeof(_type_name) )
  719. #define DEFINE_ATOMIC_TYPE_NOSERIALIZE( _type_name, _resource_field_type ) DEFINE_TYPE( #_type_name, _resource_field_type, sizeof(_type_name), 0, sizeof(_type_name) )
  720. #define DEFINE_ATOMIC_TYPE_SPECIAL_ALIGN( _type_name, _resource_field_type, _align ) DEFINE_TYPE( #_type_name, _resource_field_type, sizeof(_type_name), sizeof(_type_name), _align )
  721. #define DEFINE_PARAMETERIZED_TYPE( _type_name, _representative_type, _resource_field_type )\
  722. DEFINE_TYPE( _type_name, _resource_field_type, sizeof(_representative_type), sizeof(_representative_type), sizeof(_representative_type) )
  723. static ResourceFieldProperties_t s_pFieldTypes[] =
  724. {
  725. { "unknown", RESOURCE_FIELD_TYPE_UNKNOWN, 0, 0, 0 },
  726. DEFINE_PARAMETERIZED_TYPE( "CResourcePointer", CResourcePointer<char>, RESOURCE_FIELD_TYPE_RESOURCE_POINTER ),
  727. DEFINE_PARAMETERIZED_TYPE( "CResourceArray", CResourceArray<char>, RESOURCE_FIELD_TYPE_RESOURCE_ARRAY ),
  728. { "struct", RESOURCE_FIELD_TYPE_STRUCT, 0, 0, 0 },
  729. { "enum", RESOURCE_FIELD_TYPE_ENUM, 0, 0, 0 },
  730. DEFINE_PARAMETERIZED_TYPE( "CResourceReference", CResourceReference<char>, RESOURCE_FIELD_TYPE_RESOURCE_REFERENCE ),
  731. { "char", RESOURCE_FIELD_TYPE_CHAR, sizeof(char), 0, sizeof(char) },
  732. { "pointer", RESOURCE_FIELD_TYPE_C_POINTER, sizeof(void*), 0, sizeof(void*) },
  733. { "int", RESOURCE_FIELD_TYPE_INT, sizeof(int), RESOURCE_PLAIN_INT_SERIALIZATION_SIZE, sizeof(int) },
  734. { "uint", RESOURCE_FIELD_TYPE_UINT, sizeof(uint), RESOURCE_PLAIN_INT_SERIALIZATION_SIZE, sizeof(uint) },
  735. { "float", RESOURCE_FIELD_TYPE_FLOAT, sizeof(float), RESOURCE_PLAIN_FLOAT_SERIALIZATION_SIZE, sizeof(float) },
  736. DEFINE_ATOMIC_TYPE_SIMPLE( int8, RESOURCE_FIELD_TYPE_INT8 ),
  737. DEFINE_ATOMIC_TYPE_SIMPLE( uint8, RESOURCE_FIELD_TYPE_UINT8 ),
  738. DEFINE_ATOMIC_TYPE_SIMPLE( int16, RESOURCE_FIELD_TYPE_INT16 ),
  739. DEFINE_ATOMIC_TYPE_SIMPLE( uint16, RESOURCE_FIELD_TYPE_UINT16 ),
  740. DEFINE_ATOMIC_TYPE_SIMPLE( int32, RESOURCE_FIELD_TYPE_INT32 ),
  741. DEFINE_ATOMIC_TYPE_SIMPLE( uint32, RESOURCE_FIELD_TYPE_UINT32 ),
  742. DEFINE_ATOMIC_TYPE_SIMPLE( int64, RESOURCE_FIELD_TYPE_INT64 ),
  743. DEFINE_ATOMIC_TYPE_SIMPLE( uint64, RESOURCE_FIELD_TYPE_UINT64 ),
  744. DEFINE_ATOMIC_TYPE_SIMPLE( float32, RESOURCE_FIELD_TYPE_FLOAT32 ),
  745. DEFINE_ATOMIC_TYPE_SIMPLE( float64, RESOURCE_FIELD_TYPE_FLOAT64 ),
  746. { "time", RESOURCE_FIELD_TYPE_TIME, 0, 0, 0 }, // SCHEMAFIXME: Time?
  747. DEFINE_ATOMIC_TYPE_SPECIAL_ALIGN( Vector2D, RESOURCE_FIELD_TYPE_VECTOR2D, sizeof(vec_t) ),
  748. DEFINE_ATOMIC_TYPE_SPECIAL_ALIGN( Vector, RESOURCE_FIELD_TYPE_VECTOR3D, sizeof(vec_t) ),
  749. DEFINE_ATOMIC_TYPE_SPECIAL_ALIGN( Vector4D, RESOURCE_FIELD_TYPE_VECTOR4D, sizeof(vec_t) ),
  750. DEFINE_ATOMIC_TYPE_SPECIAL_ALIGN( QAngle, RESOURCE_FIELD_TYPE_QANGLE, sizeof(vec_t) ),
  751. DEFINE_ATOMIC_TYPE_SPECIAL_ALIGN( Quaternion, RESOURCE_FIELD_TYPE_QUATERNION, sizeof(vec_t) ),
  752. DEFINE_ATOMIC_TYPE_SPECIAL_ALIGN( VMatrix, RESOURCE_FIELD_TYPE_VMATRIX, sizeof(vec_t) ),
  753. DEFINE_ATOMIC_TYPE_SIMPLE( fltx4, RESOURCE_FIELD_TYPE_FLTX4 ),
  754. DEFINE_ATOMIC_TYPE_SIMPLE( bool, RESOURCE_FIELD_TYPE_BOOL ),
  755. DEFINE_ATOMIC_TYPE_SIMPLE( CResourceString, RESOURCE_FIELD_TYPE_STRING ),
  756. { "void", RESOURCE_FIELD_TYPE_VOID, 0, 0, 0 },
  757. };
  758. const ResourceFieldProperties_t* ResourceFieldProperties_t::GetFieldProperties( ResourceFieldType_t nFieldType )
  759. {
  760. COMPILE_TIME_ASSERT( ARRAYSIZE( s_pFieldTypes ) == RESOURCE_FIELD_TYPE_COUNT );
  761. Assert( nFieldType >= 0 && nFieldType < RESOURCE_FIELD_TYPE_COUNT );
  762. Assert( s_pFieldTypes[nFieldType].m_nFieldType == nFieldType );
  763. return &(s_pFieldTypes[nFieldType]);
  764. }