|
|
//===== 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<CResourceFieldTypeIntrospection> for pointed-to type
RESOURCE_FIELD_TYPE_RESOURCE_ARRAY, // nFieldData = CResourcePointer<CResourceFieldTypeIntrospection> 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<ResourceFieldType_t>& 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<uint32> 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<CResourceIntrospectionMetadataElement> m_MetaElements; };
schema class CResourceIntrospectionMetadata { public: DECLARE_SCHEMA_DATA_CLASS( CResourceIntrospectionMetadata ); protected: CResourceString m_ObjectName; CResourceArray<CResourceIntrospectionMetadataElement> m_RootMetaElements; CResourceArray<CResourceIntrospectionChildMetadata> 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
|