//===== Copyright c 1996-2008, Valve Corporation, All rights reserved. ======// // // Purpose: Describes data which is used to help determine introspection // data for a resource file. Specifies which fields are what types, and // also specifies which fields refer to other types (by ptr or array). // // $NoKeywords: $ //===========================================================================// #ifndef RESOURCEINTROSPECTION_H #define RESOURCEINTROSPECTION_H #pragma once #include "resourcefile/schema.h" #include "mathlib/vmatrix.h" #include "mathlib/ssemath.h" class CResourceIntrospection; //----------------------------------------------------------------------------- // Enum definitions //----------------------------------------------------------------------------- schema enum ResourceIntrospectionVersion_t { RESOURCE_INTROSPECTION_VERSION = 2, }; // NOTE: If you add to this enum, you'll need to update s_pFieldTypes in resourceintrospection.cpp schema enum ResourceFieldType_t { RESOURCE_FIELD_TYPE_UNKNOWN, RESOURCE_FIELD_TYPE_RESOURCE_POINTER, // nFieldData = CResourcePointer for pointed-to type RESOURCE_FIELD_TYPE_RESOURCE_ARRAY, // nFieldData = CResourcePointer for element type RESOURCE_FIELD_TYPE_STRUCT, // nFieldData = hash(struct_name) RESOURCE_FIELD_TYPE_ENUM, // nFieldData = hash(enum_name) RESOURCE_FIELD_TYPE_RESOURCE_REFERENCE, // nFieldData = member of ResourceTypeEngine_t //////////////////////// // fields of these types are never serialized to disk RESOURCE_FIELD_TYPE_CHAR, RESOURCE_FIELD_TYPE_C_POINTER, //////////////////////// // ints and uints are always serialized at RESOURCE_PLAIN_INT_SERIALIZATION_SIZE bytes RESOURCE_FIELD_TYPE_INT, RESOURCE_FIELD_TYPE_UINT, // floats are always serialized at RESOURCE_PLAIN_FLOAT_SERIALIZATION_SIZE bytes RESOURCE_FIELD_TYPE_FLOAT, // simple types RESOURCE_FIELD_TYPE_INT8, RESOURCE_FIELD_TYPE_UINT8, RESOURCE_FIELD_TYPE_INT16, RESOURCE_FIELD_TYPE_UINT16, RESOURCE_FIELD_TYPE_INT32, RESOURCE_FIELD_TYPE_UINT32, RESOURCE_FIELD_TYPE_INT64, RESOURCE_FIELD_TYPE_UINT64, RESOURCE_FIELD_TYPE_FLOAT32, RESOURCE_FIELD_TYPE_FLOAT64, // common primitive types RESOURCE_FIELD_TYPE_TIME, RESOURCE_FIELD_TYPE_VECTOR2D, RESOURCE_FIELD_TYPE_VECTOR3D, RESOURCE_FIELD_TYPE_VECTOR4D, RESOURCE_FIELD_TYPE_QANGLE, RESOURCE_FIELD_TYPE_QUATERNION, RESOURCE_FIELD_TYPE_VMATRIX, RESOURCE_FIELD_TYPE_FLTX4, // TODO - RESOURCE_FIELD_TYPE_BOOL, RESOURCE_FIELD_TYPE_STRING, RESOURCE_FIELD_TYPE_VOID, RESOURCE_FIELD_TYPE_COUNT, }; schema enum ResourceIntrospectionMetadataType_t { RESOURCE_META_TYPE_NAMEONLY, RESOURCE_META_TYPE_STRING, RESOURCE_META_TYPE_INT, RESOURCE_META_TYPE_FLOAT, }; enum ResourceDataLayout_t { RESOURCE_DATA_LAYOUT_MEMORY, RESOURCE_DATA_LAYOUT_DISK, }; enum IntrospectionCompatibilityType_t { INTROSPECTION_COMPAT_UNKNOWN, INTROSPECTION_COMPAT_IDENTICAL, // Disk and memory layout are the same INTROSPECTION_COMPAT_REQUIRES_SCATTER, // Identical structures, but disk layout != memory layout INTROSPECTION_COMPAT_REQUIRES_CONVERSION, // CRCs don't match, requires name-based, per-element conversion }; const uint RESOURCE_PLAIN_INT_SERIALIZATION_SIZE = 4; const uint RESOURCE_PLAIN_FLOAT_SERIALIZATION_SIZE = 4; //----------------------------------------------------------------------------- // Structure id: it's generated by a hash of the structure name //----------------------------------------------------------------------------- typedef uint32 ResourceStructureId_t; #define RESOURCE_STRUCTURE_ID_INVALID ( (ResourceStructureId_t)0 ) //----------------------------------------------------------------------------- // Information for resource fields //----------------------------------------------------------------------------- struct ResourceFieldProperties_t { // helper function static const ResourceFieldProperties_t* GetFieldProperties( ResourceFieldType_t nFieldType ); const char * m_pTypeName; ResourceFieldType_t m_nFieldType; uint m_nMemorySize; uint m_nDiskSize; // 0 = not serialized to disk uint m_nAlignment; }; //----------------------------------------------------------------------------- schema class CResourceFieldIntrospection { DECLARE_SCHEMA_DATA_CLASS( CResourceFieldIntrospection ); // These methods are used for reading the data public: ResourceFieldType_t GetRootType() const; uint32 GetRootTypeData() const; ResourceFieldType_t ReadTypeChain( int nChainIndex ) const; // These methods are used for writing the data public: void SetFieldInfo( CResourceStream *pStream, const char *pFieldName, int nMemoryOffset, int nDiskOffset, int nArrayCount ); void SetFieldInfo( CResourceStream *pStream, const CResourceFieldIntrospection *src ); void SetFieldType( CResourceStream *pStream, const CUtlVector& TypeChain, uint32 nRootFieldData ); // Introspection helper routines public: int GetElementMemorySize( int nTypeChainIndex, const CResourceIntrospection* pIntroDct ) const; int GetElementDiskSize( int nTypeChainIndex, const CResourceIntrospection* pIntroDct ) const; int GetElementSize( const ResourceDataLayout_t nDataLocation, int nTypeChainIndex, const CResourceIntrospection* pIntroDct ) const; int GetElementAlignment( int nTypeChainIndex, const CResourceIntrospection* pIntroDct ) const; public: CResourceString m_pFieldName; int16 m_nCount; int16 m_nInMemoryOffset; int16 m_nOnDiskOffset; // -1 means not serialized to disk // FIXME: The following representation will need to be tweaked; // Ideally none of the simple cases requires an allocation, (including ptr to struct) // and we do have 16 bits to work with due to alignment, plus 8 bits if we want to trim TypeChainCount. // If m_nTypeChainCount == 1, then m_nTypeChain is the field data // If m_nTypeChainCount > 1, m_nTypeChain is a CResourcePointer to N uint32's // that looks like [FieldType, ..., FieldType, FieldData] // Examples of: [ m_nFieldType, m_nTypeChainCount ; m_nTypeChain ] // ------------------------------------------------------------------------------- // Simple inline int8: [ RESOURCE_FIELD_TYPE_INT8, 1 ; 0 ] // Pointer to int8: [ RESOURCE_FIELD_TYPE_RESOURCE_POINTER, 2 ; RESOURCE_FIELD_TYPE_INT8 ] // Pointer to struct X: [ RESOURCE_FIELD_TYPE_RESOURCE_POINTER, 3 ; Ptr ] // where *Ptr = [RESOURCE_FIELD_TYPE_STRUCT; hash(X)] // Array of pointers to struct X: [ RESOURCE_FIELD_TYPE_DYNAMIC_ARRAY, 4 ; Ptr ] // where *Ptr = [RESOURCE_FIELD_TYPE_RESOURCE_POINTER; RESOURCE_FIELD_TYPE_STRUCT; hash(X)] int16 m_nTypeChainCount; int16 m_nFieldType; uint32 m_nTypeChain; }; schema enum ResourceStructFlags_t { RESOURCE_STRUCT_HAS_VTABLE = 1, }; schema class CResourceStructIntrospection { DECLARE_SCHEMA_DATA_CLASS( CResourceStructIntrospection ); // These methods are used for reading the data public: // Iterate over all fields int GetFieldCount() const; const CResourceFieldIntrospection* GetField( int nIndex ) const; // Find a field const CResourceFieldIntrospection* FindField( const char *pFieldName ) const; bool HasVTable() const; // (to determine whether version up-conversion is necessary) // These methods are used for writing the data public: void SetStructInfo( CResourceStream *pStream, const char *pStructName, const char *pBaseStruct, const char *pUncacheableStruct, uint32 nMemorySize, uint32 nDiskSize, uint32 nAlignment, const char *pDmeElementType, const char *pBlockType, const char *pResourceType, bool bHasVTable ); void SetStructInfo( CResourceStream *pStream, const CResourceStructIntrospection *src ); void ComputeCRC( CResourceStream *pStream ); void AllocateFields( CResourceStream *pStream, int nCount ); CResourceFieldIntrospection* GetWritableField( int nIndex ); public: uint32 m_nId; CResourceString m_pName; uint32 m_nCrc; uint16 m_nMemorySize; uint16 m_nDiskSize; uint16 m_nAlignment; uint32 m_nBaseStructId; uint32 m_nUncacheableStructId; uint8 m_ResourceBlockType[4]; // Specifies the block four-CC code if this structure is a type associated with a resource file block. CResourceString m_pResourceType; // Specifies the resource type if this structure is a type associated with a resource type. CResourceString m_pDmeElementType; // Specifies the DmElement type associated with this structure. Empty string means use CDmElement. CResourceArray< CResourceFieldIntrospection > m_FieldIntrospection; uint8 m_nStructFlags; }; //----------------------------------------------------------------------------- // Enums //----------------------------------------------------------------------------- schema class CResourceEnumValueIntrospection { DECLARE_SCHEMA_DATA_CLASS( CResourceEnumValueIntrospection ); // These methods are used for reading the data public: const char *GetName() const; int GetValue() const; // These methods are used for writing the data public: void SetEnumValueInfo( CResourceStream *pStream, const char *pEnumValueName, int32 nValue ); public: CResourceString m_pEnumValueName; int32 m_nEnumValue; }; schema class CResourceEnumIntrospection { DECLARE_SCHEMA_DATA_CLASS( CResourceEnumIntrospection ); // These methods are used for reading the data public: // Iterate over all enum values int GetEnumValueCount() const; const CResourceEnumValueIntrospection* GetEnumValue( int nIndex ) const; CResourceEnumValueIntrospection* GetWritableEnumValue( int nIndex ); // Find a field const CResourceEnumValueIntrospection* FindEnumValue( const char *pEnumValueName ) const; const char *FindEnumString( int nValue ) const; // Gets CRC information about the struct // (to determine whether version up-conversion is necessary) // These methods are used for writing the data public: void SetEnumName( CResourceStream *pStream, const char *pEnumName ); void ComputeCRC( CResourceStream *pStream ); void AllocateEnumValues( CResourceStream *pStream, int nCount ); public: uint32 m_nId; CResourceString m_pName; uint32 m_nCrc; CResourceArray< CResourceEnumValueIntrospection > m_EnumValueIntrospection; }; //----------------------------------------------------------------------------- // Typedefs //----------------------------------------------------------------------------- schema class CResourceTypedefIntrospection { DECLARE_SCHEMA_DATA_CLASS( CResourceTypedefIntrospection ); // These methods are used for reading the data public: // These methods are used for writing the data public: void SetTypedefInfo( CResourceStream *pStream, const char *pTypedefName, const char *pTypedefType ); public: uint32 m_nId; CResourceString m_pName; CResourceString m_pType; }; //----------------------------------------------------------------------------- // Metadata //----------------------------------------------------------------------------- schema class CResourceIntrospectionMetadataElement { friend class CResourceIntrospectionMetadata; public: const char* GetStringValue() const; int GetIntValue() const; float GetFloatValue() const; private: CResourceString m_Name; ResourceIntrospectionMetadataType_t m_Type; uint32 m_Value; }; schema class CResourceIntrospectionChildMetadata { friend class CResourceIntrospectionMetadata; private: CResourceString m_ChildName; CResourceArray m_MetaElements; }; schema class CResourceIntrospectionMetadata { public: DECLARE_SCHEMA_DATA_CLASS( CResourceIntrospectionMetadata ); protected: CResourceString m_ObjectName; CResourceArray m_RootMetaElements; CResourceArray m_ChildrenMeta; }; //----------------------------------------------------------------------------- // Root introspection block //----------------------------------------------------------------------------- //! resourceBlockType = "RESI" schema class CResourceIntrospection { DECLARE_SCHEMA_DATA_CLASS( CResourceIntrospection ); public: static CResourceIntrospection* AddToStream( CResourceStream *pStream, ResourceFileHeader_t *pHeader, int nBlockIndex ); static const CResourceIntrospection* FindInFile( const ResourceFileHeader_t *pHeader ); // These methods are used for reading the data public: uint32 GetVersion() const; int GetStructCount() const; const CResourceStructIntrospection* GetStructIntrospection( int nIndex ) const; const CResourceStructIntrospection* FindStructIntrospection( ResourceStructureId_t id ) const; const CResourceStructIntrospection* FindStructIntrospection( const char *pStructName ) const; CResourceStructIntrospection* GetWritableStructIntrospection( int nIndex ); const CResourceStructIntrospection* FindStructIntrospectionForResourceType( ResourceType_t nType ) const; const CResourceStructIntrospection* FindPermanentStructIntrospectionForResourceType( ResourceType_t nType ) const; int GetEnumCount() const; const CResourceEnumIntrospection* GetEnumIntrospection( int nIndex ) const; const CResourceEnumIntrospection* FindEnumIntrospection( ResourceStructureId_t id ) const; const CResourceEnumIntrospection* FindEnumIntrospection( const char *pEnumName ) const; CResourceEnumIntrospection* GetWritableEnumIntrospection( int nIndex ); int GetTypedefCount() const; const CResourceTypedefIntrospection* GetTypedefIntrospection( int nIndex ) const; CResourceTypedefIntrospection* GetWritableTypedefIntrospection( int nIndex ); // Compare with the current EXE's introspection IntrospectionCompatibilityType_t CalculateCompatibility() const; // These methods are used for writing the data public: void AllocateStructs( CResourceStream *pStream, int nCount ); void AllocateEnums( CResourceStream *pStream, int nCount ); void AllocateTypedefs( CResourceStream *pStream, int nCount ); const void *GetPtr() const { return this; } private: // This should always be the first 4 bytes, since this structure can't be fully-introspected uint32 m_nVersion; CResourceArray< CResourceTypedefIntrospection > m_TypedefIntrospection; CResourceArray< CResourceEnumIntrospection > m_EnumIntrospection; CResourceArray< CResourceStructIntrospection > m_StructIntrospection; CResourcePointer< CResourceIntrospectionMetadata > m_Metadata; }; DEFINE_RESOURCE_BLOCK_TYPE( CResourceIntrospection, 'R', 'E', 'S', 'I' ) //----------------------------------------------------------------------------- // Computes a resource structure id given a structure name string //----------------------------------------------------------------------------- ResourceStructureId_t ComputeStructureNameHash( const char *pStructName ); //----------------------------------------------------------------------------- // Inherit from this to fully-traverse a piece of memory using introspection //----------------------------------------------------------------------------- class CResourceIntrospectionTraversal { public: CResourceIntrospectionTraversal( const CResourceIntrospection *pResIntro = NULL ); virtual void TraverseStruct( const void *pStruct, const CResourceStructIntrospection *pStructIntro ); protected: virtual void TraverseField( const void *pField, const CResourceFieldIntrospection *pFieldIntro, ResourceFieldType_t fieldType, int nTypeChainIndex ); virtual void TraverseRootField( const void *pField, const CResourceFieldIntrospection *pFieldIntro ); // Simple overridable methods virtual bool VisitField( const void *pFieldInstance, const CResourceFieldIntrospection *pFieldIntro, int nTypeChainIndex ) { return true; } virtual void PostVisitField( const void *pFieldInstance, const CResourceFieldIntrospection *pFieldIntro, int nTypeChainIndex ) { } virtual bool VisitRootField( const void *pFieldInstance, const CResourceFieldIntrospection *pFieldIntro ) { return true; } virtual bool VisitStruct( const void *pStruct, const CResourceStructIntrospection *pStructIntro ) { return true; } virtual bool VisitEnum( const void *pEnum, const CResourceEnumIntrospection *pEnumIntro ) { return true; } bool m_bTraverseDiskLayout; // as opposed to memory layout const CResourceIntrospection *m_pResIntro; // TODO: Probably want more flags, like bFollowStructPointers, etc. }; #endif // RESOURCEINTROSPECTION_H