csgo-2018-source/public/resourcefile/resourceintrospection.h
2021-07-24 21:11:47 -07:00

431 lines
16 KiB
C++

//===== 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