diff options
Diffstat (limited to 'src/md/inc/metamodel.h')
-rw-r--r-- | src/md/inc/metamodel.h | 2072 |
1 files changed, 2072 insertions, 0 deletions
diff --git a/src/md/inc/metamodel.h b/src/md/inc/metamodel.h new file mode 100644 index 0000000000..317501bfa5 --- /dev/null +++ b/src/md/inc/metamodel.h @@ -0,0 +1,2072 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +//***************************************************************************** +// MetaModel.h -- header file for compressed COM+ metadata. +// + +// +//***************************************************************************** +#ifndef _METAMODEL_H_ +#define _METAMODEL_H_ + +#if _MSC_VER >= 1100 +#pragma once +#endif + +#include <cor.h> +#include <stgpool.h> +#include <metamodelpub.h> +#include "metadatatracker.h" + +#include "../datablob.h" +#include "../debug_metadata.h" + +#undef __unaligned + +#define ALLOCATED_MEMORY_MARKER 0xff + +// Version numbers for metadata format. + +#define METAMODEL_MAJOR_VER_V1_0 1 // Major version for v1.0 +#define METAMODEL_MINOR_VER_V1_0 0 // Minor version for v1.0 + +#define METAMODEL_MAJOR_VER_V2_0 2 // Major version for v2.0 +#define METAMODEL_MINOR_VER_V2_0 0 // Minor version for v2.0 + +#define METAMODEL_MAJOR_VER 2 +#define METAMODEL_MINOR_VER 0 + +// Metadata version number up through Whidbey Beta2 +#define METAMODEL_MAJOR_VER_B1 1 +#define METAMODEL_MINOR_VER_B1 1 + + +typedef enum MetadataVersion +{ + MDVersion1 = 0x00000001, + MDVersion2 = 0x00000002, + + // @TODO - this value should be updated when we increase the version number + MDDefaultVersion = 0x00000002 +} MetadataVersion; + + + +struct HENUMInternal; +extern const CCodedTokenDef g_CodedTokens[CDTKN_COUNT]; +extern const CMiniTableDefEx g_Tables[TBL_COUNT]; // The table definitions. + +struct TblCol +{ + ULONG m_ixtbl; // Table ID. + ULONG m_ixcol; // Column ID. +}; +extern TblCol g_PtrTableIxs[TBL_COUNT]; + +// This abstract defines the common functions that can be used for RW and RO internally +// (The primary user for this is Compiler\ImportHelper.cpp) +class IMetaModelCommon +{ +public: + __checkReturn + virtual HRESULT CommonGetScopeProps( + LPCUTF8 *pszName, + GUID *pMvid) = 0; + + __checkReturn + virtual HRESULT CommonGetTypeRefProps( + mdTypeRef tr, + LPCUTF8 *pszNamespace, + LPCUTF8 *pszName, + mdToken *ptkResolution) = 0; + + __checkReturn + virtual HRESULT CommonGetTypeDefProps( + mdTypeDef td, + LPCUTF8 *pszNameSpace, + LPCUTF8 *pszName, + DWORD *pdwFlags, + mdToken *pdwExtends, + ULONG *pMethodList) = 0; + + __checkReturn + virtual HRESULT CommonGetTypeSpecProps( + mdTypeSpec ts, + PCCOR_SIGNATURE *ppvSig, + ULONG *pcbSig) = 0; + + __checkReturn + virtual HRESULT CommonGetEnclosingClassOfTypeDef( + mdTypeDef td, + mdTypeDef *ptkEnclosingTypeDef) = 0; + + __checkReturn + virtual HRESULT CommonGetAssemblyProps( + USHORT *pusMajorVersion, + USHORT *pusMinorVersion, + USHORT *pusBuildNumber, + USHORT *pusRevisionNumber, + DWORD *pdwFlags, + const void **ppbPublicKey, + ULONG *pcbPublicKey, + LPCUTF8 *pszName, + LPCUTF8 *pszLocale) = 0; + + __checkReturn + virtual HRESULT CommonGetAssemblyRefProps( + mdAssemblyRef tkAssemRef, + USHORT *pusMajorVersion, + USHORT *pusMinorVersion, + USHORT *pusBuildNumber, + USHORT *pusRevisionNumber, + DWORD *pdwFlags, + const void **ppbPublicKeyOrToken, + ULONG *pcbPublicKeyOrToken, + LPCUTF8 *pszName, + LPCUTF8 *pszLocale, + const void **ppbHashValue, + ULONG *pcbHashValue) = 0; + + __checkReturn + virtual HRESULT CommonGetModuleRefProps( + mdModuleRef tkModuleRef, + LPCUTF8 *pszName) = 0; + + __checkReturn + virtual HRESULT CommonFindExportedType( + LPCUTF8 szNamespace, + LPCUTF8 szName, + mdToken tkEnclosingType, + mdExportedType *ptkExportedType) = 0; + + __checkReturn + virtual HRESULT CommonGetExportedTypeProps( + mdToken tkExportedType, + LPCUTF8 *pszNamespace, + LPCUTF8 *pszName, + mdToken *ptkImpl) = 0; + + virtual int CommonIsRo() = 0; + + __checkReturn + virtual HRESULT CommonGetCustomAttributeByName( // S_OK or error. + mdToken tkObj, // [IN] Object with Custom Attribute. + LPCUTF8 szName, // [IN] Name of desired Custom Attribute. + const void **ppData, // [OUT] Put pointer to data here. + ULONG *pcbData) // [OUT] Put size of data here. + { + return CommonGetCustomAttributeByNameEx(tkObj, szName, NULL, ppData, pcbData); + } + + __checkReturn + virtual HRESULT CommonGetCustomAttributeByNameEx( // S_OK or error. + mdToken tkObj, // [IN] Object with Custom Attribute. + LPCUTF8 szName, // [IN] Name of desired Custom Attribute. + mdCustomAttribute *ptkCA, // [OUT] put custom attribute token here + const void **ppData, // [OUT] Put pointer to data here. + ULONG *pcbData) = 0; // [OUT] Put size of data here. + + __checkReturn + virtual HRESULT FindParentOfMethodHelper(mdMethodDef md, mdTypeDef *ptd) = 0; + +}; // class IMetaModelCommon + + + +// An extension of IMetaModelCommon, exposed by read-only importers only. +// (The primary user for this is the WinMD import adapter which needs +// a unified view of RegMeta and MDInternalRO.) +// +// These methods were separated from IMetaModelCommon as they are only used by +// the WinMDAdapter and we don't want the maintainence and code-coverage cost +// of providing Enc-aware versions of these methods. +class IMetaModelCommonRO : public IMetaModelCommon +{ +public: + virtual HRESULT CommonGetMethodDefProps( + mdMethodDef tkMethodDef, + LPCUTF8 *pszName, + DWORD *pdwFlags, + PCCOR_SIGNATURE *ppvSigBlob, + ULONG *pcbSigBlob + ) = 0; + + virtual HRESULT CommonGetMemberRefProps( + mdMemberRef tkMemberRef, + mdToken *pParentToken + ) = 0; + + virtual ULONG CommonGetRowCount( // return hresult + DWORD tkKind) = 0; // [IN] pass in the kind of token. + + virtual HRESULT CommonGetMethodImpls( + mdTypeDef tkTypeDef, // [IN] typeDef to scope search + mdToken *ptkMethodImplFirst, // [OUT] returns first methodImpl token + ULONG *pMethodImplCount // [OUT] returns # of methodImpl tokens scoped to type + ) = 0; + + virtual HRESULT CommonGetMethodImplProps( + mdToken tkMethodImpl, // [IN] methodImpl + mdToken *pBody, // [OUT] returns body token + mdToken *pDecl // [OUT] returns decl token + ) = 0; + + virtual HRESULT CommonGetCustomAttributeProps( + mdCustomAttribute cv, // [IN] CustomAttribute token. + mdToken *ptkObj, // [OUT, OPTIONAL] Put object token here. + mdToken *ptkType, // [OUT, OPTIONAL] Put AttrType token here. + const void **ppBlob, // [OUT, OPTIONAL] Put pointer to data here. + ULONG *pcbSize) = 0; // [OUT, OPTIONAL] Put size of date here. + + virtual HRESULT CommonGetFieldDefProps( + mdFieldDef tkFieldDef, + mdTypeDef *ptkParent, + LPCUTF8 *pszName, + DWORD *pdwFlags + ) = 0; +}; // class IMetaModelCommonRO + + +//***************************************************************************** +// The mini, hard-coded schema. For each table, we persist the count of +// records. We also persist the size of string, blob, guid, and rid +// columns. From this information, we can calculate the record sizes, and +// then the sizes of the tables. +//***************************************************************************** + +class CMiniMdSchemaBase +{ +public: + ULONG m_ulReserved; // Reserved, must be zero. + BYTE m_major; // Version numbers. + BYTE m_minor; + BYTE m_heaps; // Bits for heap sizes. + BYTE m_rid; // log-base-2 of largest rid. + + // Bits for heap sizes. + enum { + HEAP_STRING_4 = 0x01, + HEAP_GUID_4 = 0x02, + HEAP_BLOB_4 = 0x04, + + PADDING_BIT = 0x08, // Tables can be created with an extra bit in columns, for growth. + + DELTA_ONLY = 0x20, // If set, only deltas were persisted. + EXTRA_DATA = 0x40, // If set, schema persists an extra 4 bytes of data. + HAS_DELETE = 0x80, // If set, this metadata can contain _Delete tokens. + }; + + unsigned __int64 m_maskvalid; // Bit mask of present table counts. + + unsigned __int64 m_sorted; // Bit mask of sorted tables. + FORCEINLINE bool IsSorted(ULONG ixTbl) + { return m_sorted & BIT(ixTbl) ? true : false; } + void SetSorted(ULONG ixTbl, int bVal) + { if (bVal) m_sorted |= BIT(ixTbl); + else m_sorted &= ~BIT(ixTbl); } + +#if BIGENDIAN + // Verify that the size hasn't changed (Update if necessary) + void ConvertEndianness() + { + _ASSERTE(sizeof(CMiniMdSchemaBase) == 0x18); + m_ulReserved = VAL32(m_ulReserved); + m_maskvalid = VAL64(m_maskvalid); + m_sorted = VAL64(m_sorted); + } +#else + // Nothing to do on little endian machine + void ConvertEndianness() {return ;} +#endif + +private: + FORCEINLINE unsigned __int64 BIT(ULONG ixBit) + { _ASSERTE(ixBit < (sizeof(__int64)*CHAR_BIT)); + return UI64(1) << ixBit; } + +}; + +class CMiniMdSchema : public CMiniMdSchemaBase +{ +public: + // These are not all persisted to disk. See LoadFrom() for details. + ULONG m_cRecs[TBL_COUNT]; // Counts of various tables. + + ULONG m_ulExtra; // Extra data, only persisted if non-zero. (m_heaps&EXTRA_DATA flags) + + ULONG LoadFrom(const void*, ULONG); // Load from a compressed version. Return bytes consumed. + ULONG SaveTo(void *); // Store a compressed version. Return bytes used in buffer. + __checkReturn + HRESULT InitNew(MetadataVersion); +}; + +//***************************************************************************** +// Helper macros and inline functions for navigating through the data. Many +// of the macros are used to define inline accessor functions. Everything +// is based on the naming conventions outlined at the top of the file. +//***************************************************************************** +#define _GETTER(tbl,fld) get##fld##Of##tbl(tbl##Rec *pRec) +#define _GETTER2(tbl,fld,x) get##fld##Of##tbl(tbl##Rec *pRec, x) +#define _GETTER3(tbl,fld,x,y) get##fld##Of##tbl(tbl##Rec *pRec, x, y) +#define _GETTER4(tbl,fld,x,y,z) get##fld##Of##tbl(tbl##Rec *pRec, x, y,z) + +// Direct getter for a field. Defines an inline function like: +// getSomeFieldOfXyz(XyzRec *pRec) { return pRec->m_SomeField;} +// Note that the returned value declaration is NOT included. +#if METADATATRACKER_ENABLED +#define _GETFLD(tbl,fld) _GETTER(tbl,fld){ PVOID pVal = (BYTE*)pRec + offsetof(tbl##Rec, m_##fld); \ + pVal = MetaDataTracker::NoteAccess(pVal); \ + return ((tbl##Rec*)((BYTE*)pVal - offsetof(tbl##Rec, m_##fld)))->Get##fld(); } +#else +#define _GETFLD(tbl,fld) _GETTER(tbl,fld){ return pRec->Get##fld();} +#endif + +// These functions call the helper function getIX to get a two or four byte value from a record, +// and then use that value as an index into the appropriate pool. +// getSomeFieldOfXyz(XyzRec *pRec) { return m_pStrings->GetString(getIX(pRec, _COLDEF(tbl,fld))); } +// Note that the returned value declaration is NOT included. + +// Column definition of a field: Looks like: +// m_XyzCol[XyzRec::COL_SomeField] +#define _COLDEF(tbl,fld) m_TableDefs[TBL_##tbl].m_pColDefs[tbl##Rec::COL_##fld] +#define _COLPAIR(tbl,fld) _COLDEF(tbl,fld), tbl##Rec::COL_##fld +// Size of a record. +#define _CBREC(tbl) m_TableDefs[TBL_##tbl].m_cbRec +// Count of records in a table. +#define _TBLCNT(tbl) m_Schema.m_cRecs[TBL_##tbl] + +#define _GETSTRA(tbl,fld) _GETTER2(tbl, fld, LPCSTR *pszString) \ +{ return getString(getI4(pRec, _COLDEF(tbl,fld)) & m_iStringsMask, pszString); } + +#define _GETSTRW(tbl,fld) _GETTER4(tbl, fld, LPWSTR szOut, ULONG cchBuffer, ULONG *pcchBuffer) \ +{ return getStringW(getI4(pRec, _COLDEF(tbl,fld)) & m_iStringsMask, szOut, cchBuffer, pcchBuffer); } + +#define _GETSTR(tbl, fld) \ + __checkReturn HRESULT _GETSTRA(tbl, fld); \ + __checkReturn HRESULT _GETSTRW(tbl, fld); + + +#define _GETGUID(tbl,fld) _GETTER2(tbl,fld,GUID *pGuid) \ +{ return getGuid(getI4(pRec, _COLDEF(tbl,fld)) & m_iGuidsMask, pGuid); } + +#define _GETBLOB(tbl,fld) __checkReturn HRESULT _GETTER3(tbl,fld,const BYTE **ppbData,ULONG *pcbSize) \ +{ \ + MetaData::DataBlob data; \ + HRESULT hr = getBlob(getI4(pRec, _COLDEF(tbl,fld)) & m_iBlobsMask, &data); \ + *ppbData = data.GetDataPointer(); \ + *pcbSize = (ULONG)data.GetSize(); \ + return hr; \ +} + +#define _GETSIGBLOB(tbl,fld) __checkReturn HRESULT _GETTER3(tbl,fld,PCCOR_SIGNATURE *ppbData,ULONG *pcbSize) \ +{ \ + MetaData::DataBlob data; \ + HRESULT hr = getBlob(getI4(pRec, _COLDEF(tbl,fld)) & m_iBlobsMask, &data); \ + *ppbData = (PCCOR_SIGNATURE)data.GetDataPointer(); \ + *pcbSize = (ULONG)data.GetSize(); \ + return hr; \ +} + +// Like the above functions, but just returns the RID, not a looked-up value. +#define _GETRID(tbl,fld) _GETTER(tbl,fld) \ +{ return getIX(pRec, _COLDEF(tbl,fld)); } + +// Like a RID, but turn into an actual token. +#define _GETTKN(tbl,fld,tok) _GETTER(tbl,fld) \ +{ return TokenFromRid(getIX(pRec, _COLDEF(tbl,fld)), tok); } + +// Get a coded token. +#define _GETCDTKN(tbl,fld,toks) _GETTER(tbl,fld) \ +{ return decodeToken(getIX(pRec, _COLDEF(tbl,fld)), toks, sizeof(toks)/sizeof(toks[0])); } + +// Functions for the start and end of a list. +#define _GETLIST(tbl,fld,tbl2) \ + RID _GETRID(tbl,fld); \ + __checkReturn HRESULT getEnd##fld##Of##tbl(RID nRowIndex, RID *pEndRid) { return getEndRidForColumn(TBL_##tbl, nRowIndex, _COLDEF(tbl,fld), TBL_##tbl2, pEndRid); } + + +#define BYTEARRAY_TO_COLDES(bytearray) (CMiniColDef*)((bytearray) + 1) +#define COLDES_TO_BYTEARRAY(coldes) (((BYTE*)(coldes))-1) + + +//***************************************************************************** +// Base class for the MiniMd. This class provides the schema to derived +// classes. It defines some virtual functions for access to data, suitable +// for use by functions where utmost performance is NOT a requirement. +// Finally, it provides some searching functions, built on the virtual +// data access functions (it is here assumed that if we are searching a table +// for some value, the cost of a virtual function call is acceptable). +// Some static utility functions and associated static data, shared across +// implementations, is provided here. +// +// NB: It's unfortunate that CMiniMDBase "implements" IMetaModelCommonRO rather +// than IMetaModelCommon, as methods on IMetaModelCommonRO are by definition, +// not Enc-aware. Ideally, CMiniMDBase should only implement IMetaModelCommon +// and CMiniMd should be the one implementing IMetaModelCommonRO. +// +// To make that happen would be a substantial refactoring job as RegMeta +// always embeds CMiniMdRW even when it was opened for ReadOnly. +//***************************************************************************** +class CMiniMdBase : public IMetaModelCommonRO +{ + + friend class VerifyLayoutsMD; // verifies class layout doesn't accidentally change + +public: + CMiniMdBase(); + ~CMiniMdBase(); + __checkReturn + virtual HRESULT vGetRow(UINT32 nTableIndex, UINT32 nRowIndex, void **ppRow) = 0; + ULONG GetCountRecs(ULONG ixTbl); + ULONG GetCountTables() { return m_TblCount;} + + // Search a table for the row containing the given key value. + // EG. Constant table has pointer back to Param or Field. + __checkReturn + virtual HRESULT vSearchTable( // RID of matching row, or 0. + ULONG ixTbl, // Table to search. + CMiniColDef sColumn, // Sorted key column, containing search value. + ULONG ulTarget, // Target for search. + RID *pRid) = 0; + + // Search a table for the highest-RID row containing a value that is less than + // or equal to the target value. EG. TypeDef points to first Field, but if + // a TypeDef has no fields, it points to first field of next TypeDef. + __checkReturn + virtual HRESULT vSearchTableNotGreater( // RID of matching row, or 0. + ULONG ixTbl, // Table to search. + CMiniColDef sColumn, // the column def containing search value + ULONG ulTarget, // target for search + RID *pRid) = 0; + + // Search a table for multiple (adjacent) rows containing the given + // key value. EG, InterfaceImpls all point back to the implementing class. + __checkReturn + HRESULT SearchTableForMultipleRows( // First RID found, or 0. + ULONG ixTbl, // Table to search. + CMiniColDef sColumn, // Sorted key column, containing search value. + ULONG ulTarget, // Target for search. + RID *pEnd, // [OPTIONAL, OUT] + RID *pFoundRid); + + // Search for a custom value with a given type. + __checkReturn + HRESULT FindCustomAttributeFor(// RID of custom value, or 0. + RID rid, // The object's rid. + mdToken tkOjb, // The object's type. + mdToken tkType, // Type of custom value. + RID *pFoundRid); + + // Search for the specified Column Definition array in the global cache + BOOL FindSharedColDefs(// TRUE if we found a match in the global cache and updated pTable, FALSE otherwise + CMiniTableDef *pTable, // The table def that wants the column definition array + CMiniColDef *pColsToMatch, // The columns that we need to match + DWORD ixTbl); + + // Return RID to EventMap table, given the rid to a TypeDef. + __checkReturn + HRESULT FindEventMapFor(RID ridParent, RID *pFoundRid); + + // Return RID to PropertyMap table, given the rid to a TypeDef. + __checkReturn + HRESULT FindPropertyMapFor(RID ridParent, RID *pFoundRid); + +#if BIGENDIAN + // Swap a constant + __checkReturn + HRESULT SwapConstant(const void *pBlobValue, DWORD dwType, VOID *pConstant, ULONG BlobLength); +#endif + + // Pull two or four bytes out of a record. + inline static ULONG getIX(const void *pRec, CMiniColDef &def) + { + PVOID pVal = (BYTE *)pRec + def.m_oColumn; + if (def.m_cbColumn == 2) + { + METADATATRACKER_ONLY(pVal = MetaDataTracker::NoteAccess(pVal)); + ULONG ix = GET_UNALIGNED_VAL16(pVal); + return ix; + } + _ASSERTE(def.m_cbColumn == 4); + METADATATRACKER_ONLY(pVal = MetaDataTracker::NoteAccess(pVal)); + return GET_UNALIGNED_VAL32(pVal); + } + + inline static ULONG getIX_NoLogging(const void *pRec, CMiniColDef &def) + { + PVOID pVal = (BYTE *)pRec + def.m_oColumn; + if (def.m_cbColumn == 2) + { + ULONG ix = GET_UNALIGNED_VAL16(pVal); + return ix; + } + _ASSERTE(def.m_cbColumn == 4); + return GET_UNALIGNED_VAL32(pVal); + } + + // Pull four bytes out of a record. + FORCEINLINE static ULONG getI1(const void *pRec, CMiniColDef &def) + { + PVOID pVal = (BYTE *)pRec + def.m_oColumn; + METADATATRACKER_ONLY(pVal = MetaDataTracker::NoteAccess(pVal)); + return *(BYTE*)pVal; + } + + // Pull four bytes out of a record. + FORCEINLINE static ULONG getI4(const void *pRec, CMiniColDef &def) + { + PVOID pVal = (BYTE *)pRec + def.m_oColumn; + METADATATRACKER_ONLY(pVal = MetaDataTracker::NoteAccess(pVal)); + return GET_UNALIGNED_VAL32(pVal); + } + + // Function to encode a token into fewer bits. Looks up token type in array of types. + ULONG static encodeToken(RID rid, mdToken typ, const mdToken rTokens[], ULONG32 cTokens); + + // Decode a token. + inline static mdToken decodeToken(mdToken val, const mdToken rTokens[], ULONG32 cTokens) + { + //<TODO>@FUTURE: make compile-time calculation</TODO> + ULONG32 ix = (ULONG32)(val & ~(-1 << m_cb[cTokens])); + // If the coded token has an invalid table index, return the first entry + // from the array of valid token types. It would be preferable to + // return an error or to raise an exception. + if (ix >= cTokens) + return rTokens[0]; + return TokenFromRid(val >> m_cb[cTokens], rTokens[ix]); + } + static const int m_cb[]; + + // Given a token, what table does it live in? + inline ULONG GetTblForToken(mdToken tk) + { + tk = TypeFromToken(tk); + return (tk < mdtString) ? tk >> 24 : (ULONG) -1; + } + + //***************************************************************************** + // Returns whether the data has been verified, which means it was verified by a + // trusted source and has not changed. + // + // If so, this means the following aspects of the data can be trusted as accurate: + // - m_Schema.IsSorted[TBL_PropertyMap] reflects whether that table is sorted by Parent (see CMiniMdRW::PreSaveFull) + // - m_Schema.IsSorted[TBL_EventMap] reflects whether that table is sorted by Parent (see CMiniMdRW::PreSaveFull) + // + // Currently, metadata saved in NGen images is the only trusted source. + //***************************************************************************** + BOOL IsVerified() + { + return m_fVerifiedByTrustedSource && CommonIsRo(); + } + + void SetVerifiedByTrustedSource(BOOL fVerifiedByTrustedSource) + { + m_fVerifiedByTrustedSource = fVerifiedByTrustedSource; + } + + STDMETHODIMP GetRvaOffsetData(// S_OK or error + DWORD *pFirstMethodRvaOffset, // [OUT] Offset (from start of metadata) to the first RVA field in MethodDef table. + DWORD *pMethodDefRecordSize, // [OUT] Size of each record in MethodDef table. + DWORD *pMethodDefCount, // [OUT] Number of records in MethodDef table. + DWORD *pFirstFieldRvaOffset, // [OUT] Offset (from start of metadata) to the first RVA field in FieldRVA table. + DWORD *pFieldRvaRecordSize, // [OUT] Size of each record in FieldRVA table. + DWORD *pFieldRvaCount) // [OUT] Number of records in FieldRVA table. + { + _ASSERTE("Not implemented"); + return E_NOTIMPL; + } + + //***************************************************************************** + // Some of the tables need coded tokens, not just rids (ie, the column can + // refer to more than one other table). Code the tokens into as few bits + // as possible, by using 1, 2, 3, etc., bits to code the token type, then + // use that value to index into an array of token types. + //***************************************************************************** + static const mdToken mdtTypeDefOrRef[3]; + static const mdToken mdtHasConstant[3]; + static const mdToken mdtHasCustomAttribute[24]; + static const mdToken mdtHasFieldMarshal[2]; + static const mdToken mdtHasDeclSecurity[3]; + static const mdToken mdtMemberRefParent[5]; + static const mdToken mdtHasSemantic[2]; + static const mdToken mdtMethodDefOrRef[2]; + static const mdToken mdtMemberForwarded[2]; + static const mdToken mdtImplementation[3]; + static const mdToken mdtCustomAttributeType[5]; + static const mdToken mdtResolutionScope[4]; + static const mdToken mdtTypeOrMethodDef[2]; + + +public: + virtual BOOL IsWritable() = 0; + + +protected: + CMiniMdSchema m_Schema; // data header. + ULONG m_TblCount; // Tables in this database. + BOOL m_fVerifiedByTrustedSource; // whether the data was verified by a trusted source + + // Declare CMiniColDefs for every table. They look like either: + // static const BYTE s_xyz[]; + // or + // static const BYTE* s_xyz; + + #include "mdcolumndescriptors.h" + + static const BYTE* const s_TableColumnDescriptors[TBL_COUNT]; + CMiniTableDef m_TableDefs[TBL_COUNT]; + + ULONG m_iStringsMask; + ULONG m_iGuidsMask; + ULONG m_iBlobsMask; + + __checkReturn + HRESULT SchemaPopulate(const void *pvData, ULONG cbData, ULONG *pcbUsed); + __checkReturn + HRESULT SchemaPopulate(const CMiniMdBase &that); + __checkReturn + HRESULT InitColsForTable(CMiniMdSchema &Schema, int ixTbl, CMiniTableDef *pTable, int bExtra, BOOL fUsePointers); + __checkReturn + HRESULT SchemaPopulate2(ULONG *pcbTables, int bExtra=false); + const CMiniTableDef* GetTableDefTemplate(int ixTbl); + __checkReturn + HRESULT SetNewColumnDefinition(CMiniTableDef *pTable, CMiniColDef* pCols, DWORD ixTbl); + +private: + + BOOL UsesAllocatedMemory(CMiniColDef* pCols); +}; + + +#ifdef FEATURE_METADATA_RELEASE_MEMORY_ON_REOPEN +#define MINIMD_POSSIBLE_INTERNAL_POINTER_EXPOSED() MarkUnsafeToDelete() +#else +#define MINIMD_POSSIBLE_INTERNAL_POINTER_EXPOSED() +#endif + +//***************************************************************************** +// This class defines the interface to the MiniMd. The template parameter is +// a derived class which provides implementations for a few primitives that +// the interface is built upon. +// To use, declare a class: +// class CMyMiniMd : public CMiniMdTemplate<CMyMiniMd> {...}; +// and provide implementations of the primitives. Any non-trivial +// implementation will also provide initialization, and probably serialization +// functions as well. +//***************************************************************************** +template <class Impl> class CMiniMdTemplate : public CMiniMdBase +{ +#ifdef FEATURE_METADATA_RELEASE_MEMORY_ON_REOPEN +protected: + CMiniMdTemplate() : m_isSafeToDelete(TRUE) { } +#endif + + // Primitives -- these must be implemented in the Impl class. +public: + __checkReturn + FORCEINLINE HRESULT getString(UINT32 nIndex, __out LPCSTR *pszString) + { + MINIMD_POSSIBLE_INTERNAL_POINTER_EXPOSED(); + return static_cast<Impl*>(this)->Impl_GetString(nIndex, pszString); + } + __checkReturn + FORCEINLINE HRESULT getStringW(ULONG nIndex, __inout_ecount (cchBuffer) LPWSTR szOut, ULONG cchBuffer, ULONG *pcchBuffer) + { + MINIMD_POSSIBLE_INTERNAL_POINTER_EXPOSED(); + return static_cast<Impl*>(this)->Impl_GetStringW(nIndex, szOut, cchBuffer, pcchBuffer); + } + __checkReturn + FORCEINLINE HRESULT getGuid(UINT32 nIndex, GUID *pGuid) + { + MINIMD_POSSIBLE_INTERNAL_POINTER_EXPOSED(); + return static_cast<Impl*>(this)->Impl_GetGuid(nIndex, pGuid); + } + __checkReturn + FORCEINLINE HRESULT getBlob(UINT32 nIndex, __out MetaData::DataBlob *pData) + { + MINIMD_POSSIBLE_INTERNAL_POINTER_EXPOSED(); + return static_cast<Impl*>(this)->Impl_GetBlob(nIndex, pData); + } + __checkReturn + FORCEINLINE HRESULT getRow(UINT32 nTableIndex, UINT32 nRowIndex, __deref_out void **ppRow) + { + MINIMD_POSSIBLE_INTERNAL_POINTER_EXPOSED(); + return static_cast<Impl*>(this)->Impl_GetRow(nTableIndex, nRowIndex, reinterpret_cast<BYTE **>(ppRow)); + } + __checkReturn + FORCEINLINE HRESULT getEndRidForColumn( + UINT32 nTableIndex, + RID nRowIndex, + CMiniColDef &columnDefinition, + UINT32 nTargetTableIndex, + __out RID *pEndRid) + { + MINIMD_POSSIBLE_INTERNAL_POINTER_EXPOSED(); + return static_cast<Impl*>(this)->Impl_GetEndRidForColumn(nTableIndex, nRowIndex, columnDefinition, nTargetTableIndex, pEndRid); + } + __checkReturn + FORCEINLINE HRESULT doSearchTable(ULONG ixTbl, CMiniColDef sColumn, ULONG ixColumn, ULONG ulTarget, RID *pFoundRid) + { + MINIMD_POSSIBLE_INTERNAL_POINTER_EXPOSED(); + return static_cast<Impl*>(this)->Impl_SearchTable(ixTbl, sColumn, ixColumn, ulTarget, pFoundRid); + } + + // IMetaModelCommonRO interface beginning + __checkReturn + HRESULT CommonGetScopeProps( + LPCUTF8 *pszName, + GUID *pMvid) + { + HRESULT hr = S_OK; + ModuleRec *pRec; + IfFailRet(GetModuleRecord(1, &pRec)); + if (pszName != NULL) + { + IfFailRet(getNameOfModule(pRec, pszName)); + } + if (pMvid != NULL) + { + IfFailRet(getMvidOfModule(pRec, pMvid)); + } + return hr; + } + + //***************************************************************************** + // Get name and sig of a methodDef + //***************************************************************************** + HRESULT CommonGetMethodDefProps( + mdMethodDef tkMethodDef, + LPCUTF8 *pszName, + DWORD *pdwFlags, + PCCOR_SIGNATURE *ppvSigBlob, + ULONG *pcbSigBlob + ) + { + + _ASSERTE(!IsWritable() && "IMetaModelCommonRO methods cannot be used because this importer is writable."); + + HRESULT hr; + + LPCUTF8 szName; + DWORD dwFlags; + PCCOR_SIGNATURE pvSigBlob; + ULONG cbSigBlob; + + _ASSERTE(TypeFromToken(tkMethodDef) == mdtMethodDef); + MethodRec *pMethodRec; + IfFailRet(GetMethodRecord(RidFromToken(tkMethodDef), &pMethodRec)); + IfFailRet(getNameOfMethod(pMethodRec, &szName)); + dwFlags = getFlagsOfMethod(pMethodRec); + IfFailRet(getSignatureOfMethod(pMethodRec, &pvSigBlob, &cbSigBlob)); + + if (pszName) + *pszName = szName; + if (pdwFlags) + *pdwFlags = dwFlags; + if (ppvSigBlob) + *ppvSigBlob = pvSigBlob; + if (pcbSigBlob) + *pcbSigBlob = cbSigBlob; + + return S_OK; + } + + HRESULT CommonGetMemberRefProps( + mdMemberRef tkMemberRef, + mdToken *pParentToken + ) + { + _ASSERTE(!IsWritable() && "IMetaModelCommonRO methods cannot be used because this importer is writable."); + + HRESULT hr; + + _ASSERTE(TypeFromToken(tkMemberRef) == mdtMemberRef); + + MemberRefRec *pMemberRefRec; + IfFailRet(GetMemberRefRecord(RidFromToken(tkMemberRef), &pMemberRefRec)); + if (pParentToken != NULL) + *pParentToken = getClassOfMemberRef(pMemberRefRec); + + return S_OK; + } + + + + + __checkReturn + HRESULT CommonGetTypeRefProps( + mdTypeRef tr, + LPCUTF8 *pszNamespace, + LPCUTF8 *pszName, + mdToken *ptkResolution) + { + HRESULT hr = S_OK; + TypeRefRec *pRec; + IfFailRet(GetTypeRefRecord(RidFromToken(tr), &pRec)); + if (pszNamespace != NULL) + { + IfFailRet(getNamespaceOfTypeRef(pRec, pszNamespace)); + } + if (pszName != NULL) + { + IfFailRet(getNameOfTypeRef(pRec, pszName)); + } + if (ptkResolution != NULL) + { + *ptkResolution = getResolutionScopeOfTypeRef(pRec); + } + return hr; + } + + __checkReturn + virtual HRESULT CommonGetTypeDefProps( + mdTypeDef td, + LPCUTF8 *pszNamespace, + LPCUTF8 *pszName, + DWORD *pdwFlags, + mdToken *pdwExtends, + ULONG *pMethodList) + { + HRESULT hr = S_OK; + TypeDefRec *pRec; + IfFailRet(GetTypeDefRecord(RidFromToken(td), &pRec)); + if (pszNamespace != NULL) + { + IfFailRet(getNamespaceOfTypeDef(pRec, pszNamespace)); + } + if (pszName != NULL) + { + IfFailRet(getNameOfTypeDef(pRec, pszName)); + } + if (pdwFlags != NULL) + { + *pdwFlags = getFlagsOfTypeDef(pRec); + } + if (pdwExtends != NULL) + { + *pdwExtends = getExtendsOfTypeDef(pRec); + } + if (pMethodList != NULL) + { + *pMethodList = getMethodListOfTypeDef(pRec); + } + return hr; + } + + __checkReturn + virtual HRESULT CommonGetTypeSpecProps( + mdTypeSpec ts, + PCCOR_SIGNATURE *ppvSig, + ULONG *pcbSig) + { + HRESULT hr = S_OK; + TypeSpecRec *pRec; + IfFailRet(GetTypeSpecRecord(RidFromToken(ts), &pRec)); + ULONG cb; + IfFailRet(getSignatureOfTypeSpec(pRec, ppvSig, &cb)); + *pcbSig = cb; + return hr; + } + + __checkReturn + virtual HRESULT CommonGetEnclosingClassOfTypeDef( + mdTypeDef td, + mdTypeDef *ptkEnclosingTypeDef) + { + _ASSERTE(ptkEnclosingTypeDef != NULL); + + HRESULT hr; + NestedClassRec *pRec; + RID iRec; + + IfFailRet(FindNestedClassFor(RidFromToken(td), &iRec)); + if (iRec == 0) + { + *ptkEnclosingTypeDef = mdTypeDefNil; + return S_OK; + } + + IfFailRet(GetNestedClassRecord(iRec, &pRec)); + *ptkEnclosingTypeDef = getEnclosingClassOfNestedClass(pRec); + return S_OK; + } + + + __checkReturn + virtual HRESULT CommonGetAssemblyProps( + USHORT *pusMajorVersion, + USHORT *pusMinorVersion, + USHORT *pusBuildNumber, + USHORT *pusRevisionNumber, + DWORD *pdwFlags, + const void **ppbPublicKey, + ULONG *pcbPublicKey, + LPCUTF8 *pszName, + LPCUTF8 *pszLocale) + { + HRESULT hr = S_OK; + AssemblyRec *pRec; + + IfFailRet(GetAssemblyRecord(1, &pRec)); + + if (pusMajorVersion) *pusMajorVersion = pRec->GetMajorVersion(); + if (pusMinorVersion) *pusMinorVersion = pRec->GetMinorVersion(); + if (pusBuildNumber) *pusBuildNumber = pRec->GetBuildNumber(); + if (pusRevisionNumber) *pusRevisionNumber = pRec->GetRevisionNumber(); + if (pdwFlags != NULL) + { + *pdwFlags = pRec->GetFlags(); + } + + // Turn on the afPublicKey if PublicKey blob is not empty + if (pdwFlags != NULL) + { + DWORD cbPublicKey; + const BYTE *pbPublicKey; + IfFailRet(getPublicKeyOfAssembly(pRec, &pbPublicKey, &cbPublicKey)); + if (cbPublicKey) + *pdwFlags |= afPublicKey; + } + if (ppbPublicKey != NULL) + { + IfFailRet(getPublicKeyOfAssembly(pRec, reinterpret_cast<const BYTE **>(ppbPublicKey), pcbPublicKey)); + } + if (pszName != NULL) + { + IfFailRet(getNameOfAssembly(pRec, pszName)); + } + if (pszLocale != NULL) + { + IfFailRet(getLocaleOfAssembly(pRec, pszLocale)); + } + return hr; + } + + __checkReturn + virtual HRESULT CommonGetAssemblyRefProps( + mdAssemblyRef tkAssemRef, + USHORT *pusMajorVersion, + USHORT *pusMinorVersion, + USHORT *pusBuildNumber, + USHORT *pusRevisionNumber, + DWORD *pdwFlags, + const void **ppbPublicKeyOrToken, + ULONG *pcbPublicKeyOrToken, + LPCUTF8 *pszName, + LPCUTF8 *pszLocale, + const void **ppbHashValue, + ULONG *pcbHashValue) + { + HRESULT hr = S_OK; + AssemblyRefRec *pRec; + + IfFailRet(GetAssemblyRefRecord(RidFromToken(tkAssemRef), &pRec)); + + if (pusMajorVersion) *pusMajorVersion = pRec->GetMajorVersion(); + if (pusMinorVersion) *pusMinorVersion = pRec->GetMinorVersion(); + if (pusBuildNumber) *pusBuildNumber = pRec->GetBuildNumber(); + if (pusRevisionNumber) *pusRevisionNumber = pRec->GetRevisionNumber(); + if (pdwFlags) *pdwFlags = pRec->GetFlags(); + if (ppbPublicKeyOrToken != NULL) + { + IfFailRet(getPublicKeyOrTokenOfAssemblyRef(pRec, reinterpret_cast<const BYTE **>(ppbPublicKeyOrToken), pcbPublicKeyOrToken)); + } + if (pszName != NULL) + { + IfFailRet(getNameOfAssemblyRef(pRec, pszName)); + } + if (pszLocale != NULL) + { + IfFailRet(getLocaleOfAssemblyRef(pRec, pszLocale)); + } + if (ppbHashValue != NULL) + { + IfFailRet(getHashValueOfAssemblyRef(pRec, reinterpret_cast<const BYTE **>(ppbHashValue), pcbHashValue)); + } + return hr; + } + + __checkReturn + virtual HRESULT CommonGetModuleRefProps( + mdModuleRef tkModuleRef, + LPCUTF8 *pszName) + { + HRESULT hr = S_OK; + ModuleRefRec *pRec; + + IfFailRet(GetModuleRefRecord(RidFromToken(tkModuleRef), &pRec)); + IfFailRet(getNameOfModuleRef(pRec, pszName)); + return hr; + } + + __checkReturn + HRESULT CommonFindExportedType( + LPCUTF8 szNamespace, + LPCUTF8 szName, + mdToken tkEnclosingType, + mdExportedType *ptkExportedType) + { + HRESULT hr; + ExportedTypeRec *pRec; + ULONG ulCount; + LPCUTF8 szTmp; + mdToken tkImpl; + + _ASSERTE(szName && ptkExportedType); + + // Set NULL namespace to empty string. + if (!szNamespace) + szNamespace = ""; + + // Set output to Nil. + *ptkExportedType = mdTokenNil; + + ulCount = getCountExportedTypes(); + while (ulCount) + { + IfFailRet(GetExportedTypeRecord(ulCount--, &pRec)); + + // Handle the case of nested vs. non-nested classes. + tkImpl = getImplementationOfExportedType(pRec); + if (TypeFromToken(tkImpl) == mdtExportedType && !IsNilToken(tkImpl)) + { + // Current ExportedType being looked at is a nested type, so + // comparing the implementation token. + if (tkImpl != tkEnclosingType) + continue; + } + else if (TypeFromToken(tkEnclosingType) == mdtExportedType && + !IsNilToken(tkEnclosingType)) + { + // ExportedType passed in is nested but the current ExportedType is not. + continue; + } + + // Compare name and namespace. + IfFailRet(getTypeNameOfExportedType(pRec, &szTmp)); + if (strcmp(szTmp, szName)) + continue; + IfFailRet(getTypeNamespaceOfExportedType(pRec, &szTmp)); + if (!strcmp(szTmp, szNamespace)) + { + *ptkExportedType = TokenFromRid(ulCount+1, mdtExportedType); + return S_OK; + } + } + return CLDB_E_RECORD_NOTFOUND; + } + + __checkReturn + virtual HRESULT CommonGetExportedTypeProps( + mdToken tkExportedType, + LPCUTF8 *pszNamespace, + LPCUTF8 *pszName, + mdToken *ptkImpl) + { + HRESULT hr = S_OK; + ExportedTypeRec *pRec; + + IfFailRet(GetExportedTypeRecord(RidFromToken(tkExportedType), &pRec)); + + if (pszNamespace != NULL) + { + IfFailRet(getTypeNamespaceOfExportedType(pRec, pszNamespace)); + } + if (pszName != NULL) + { + IfFailRet(getTypeNameOfExportedType(pRec, pszName)); + } + if (ptkImpl) *ptkImpl = getImplementationOfExportedType(pRec); + return hr; + } + + int CommonIsRo() + { + return static_cast<Impl*>(this)->Impl_IsRo(); + } + + + + HRESULT CommonGetCustomAttributeProps( + mdCustomAttribute cv, // [IN] CustomAttribute token. + mdToken *ptkObj, // [OUT, OPTIONAL] Put object token here. + mdToken *ptkType, // [OUT, OPTIONAL] Put AttrType token here. + const void **ppBlob, // [OUT, OPTIONAL] Put pointer to data here. + ULONG *pcbSize) // [OUT, OPTIONAL] Put size of date here. + { + _ASSERTE(!IsWritable() && "IMetaModelCommonRO methods cannot be used because this importer is writable."); + + HRESULT hr; + _ASSERTE(TypeFromToken(cv) == mdtCustomAttribute); + CustomAttributeRec *pRec; // A CustomAttribute record. + const void *pBlob; + ULONG cbSize; + IfFailRet(GetCustomAttributeRecord(RidFromToken(cv), &pRec)); + if (ptkObj) + *ptkObj = getParentOfCustomAttribute(pRec); + if (ptkType) + *ptkType = getTypeOfCustomAttribute(pRec); + + if (!ppBlob) + ppBlob = &pBlob; + if (!pcbSize) + pcbSize = &cbSize; + IfFailRet(getValueOfCustomAttribute(pRec, (const BYTE **)ppBlob, pcbSize)); + return S_OK; + } + + //***************************************************************************** + // Get name, parent and flags of a fieldDef + //***************************************************************************** + HRESULT CommonGetFieldDefProps( + mdFieldDef tkFieldDef, + mdTypeDef *ptkParent, + LPCUTF8 *pszName, + DWORD *pdwFlags + ) + { + _ASSERTE(!IsWritable() && "IMetaModelCommonRO methods cannot be used because this importer is writable."); + _ASSERTE(TypeFromToken(tkFieldDef) == mdtFieldDef); + + HRESULT hr; + + FieldRec *pFieldRec; + IfFailRet(GetFieldRecord(RidFromToken(tkFieldDef), &pFieldRec)); + + if(ptkParent) + { + IfFailRet(FindParentOfField(RidFromToken(tkFieldDef), (RID *) ptkParent)); + RidToToken(*ptkParent, mdtTypeDef); + } + if (pszName) + IfFailRet(getNameOfField(pFieldRec, pszName)); + if (pdwFlags) + *pdwFlags = getFlagsOfField(pFieldRec); + + return S_OK; + } + + __checkReturn + HRESULT FindParentOfMethodHelper(mdMethodDef md, mdTypeDef *ptd) + { + HRESULT hr; + IfFailRet(FindParentOfMethod(RidFromToken(md), (RID *)ptd)); + RidToToken(*ptd, mdtTypeDef); + return NOERROR; + } + + //***************************************************************************** + // Helper function to lookup and retrieve a CustomAttribute. + //***************************************************************************** + __checkReturn + HRESULT CompareCustomAttribute( + mdToken tkObj, // [IN] Object with Custom Attribute. + LPCUTF8 szName, // [IN] Name of desired Custom Attribute. + ULONG rid) // [IN] the rid of the custom attribute to compare to + { + CustomAttributeRec *pRec; // A CustomAttribute record. + LPCUTF8 szNamespaceTmp = NULL; // Namespace of a CustomAttribute's type. + LPCUTF8 szNameTmp = NULL; // Name of a CustomAttribute's type. + int iLen; // Length of a component name. + HRESULT hr = S_FALSE; + HRESULT hrMatch = S_FALSE; + + if (!_IsValidTokenBase(tkObj)) + return COR_E_BADIMAGEFORMAT; + + // Get the row. + IfFailGo(GetCustomAttributeRecord(rid, &pRec)); + + // Check the parent. In debug, always check. In retail, only when scanning. + mdToken tkParent; + tkParent = getParentOfCustomAttribute(pRec); + if (tkObj != tkParent) + { + goto ErrExit; + } + + hr = CommonGetNameOfCustomAttribute(rid, &szNamespaceTmp, &szNameTmp); + if (hr != S_OK) + goto ErrExit; + + iLen = -1; + if (*szNamespaceTmp) + { + iLen = (int)strlen(szNamespaceTmp); + if (strncmp(szName, szNamespaceTmp, iLen) != 0) + goto ErrExit; + // Namespace separator after the Namespace? + if (szName[iLen] != NAMESPACE_SEPARATOR_CHAR) + goto ErrExit; + } + // Check the type name after the separator. + if (strcmp(szName+iLen+1, szNameTmp) != 0) + goto ErrExit; + + hrMatch = S_OK; + ErrExit: + + if (FAILED(hr)) + return hr; + + return hrMatch; + } // CompareCustomAttribute + + + //***************************************************************************** + // Helper function to lookup the name of a custom attribute + // Note that this function can return S_FALSE to support being called + // by CompareCustomAttribute. See GetTypeDefRefTokenInTypeSpec for + // details on when this will happen. + //***************************************************************************** + __checkReturn + HRESULT CommonGetNameOfCustomAttribute( + ULONG rid, // [IN] the rid of the custom attribute + LPCUTF8 *pszNamespace, // [OUT] Namespace of Custom Attribute. + LPCUTF8 *pszName) // [OUT] Name of Custom Attribute. + { + CustomAttributeRec *pRec; // A CustomAttribute record. + mdToken tkTypeTmp; // Type of some CustomAttribute. + RID ridTmp; // Rid of some custom value. + HRESULT hr = S_FALSE; + + // Get the row. + IfFailGo(GetCustomAttributeRecord(rid, &pRec)); + + // Get the type. + tkTypeTmp = getTypeOfCustomAttribute(pRec); + + // If the record is a MemberRef or a MethodDef, we will come back here to check + // the type of the parent. + CheckParentType: + + if (!_IsValidTokenBase(tkTypeTmp)) + return COR_E_BADIMAGEFORMAT; + + ridTmp = RidFromToken(tkTypeTmp); + + // Get the name of the type. + switch (TypeFromToken(tkTypeTmp)) + { + case mdtTypeRef: + { + TypeRefRec *pTR; + IfFailGo(GetTypeRefRecord(ridTmp, &pTR)); + IfFailGo(getNamespaceOfTypeRef(pTR, pszNamespace)); + IfFailGo(getNameOfTypeRef(pTR, pszName)); + } + break; + case mdtTypeDef: + { + TypeDefRec *pTD; + IfFailGo(GetTypeDefRecord(ridTmp, &pTD)); + IfFailGo(getNamespaceOfTypeDef(pTD, pszNamespace)); + IfFailGo(getNameOfTypeDef(pTD, pszName)); + } + break; + case mdtTypeSpec: + { + // If this has an encoded token, we'll take a look. If it contains + // a base type, we'll just return a non-match. + + hr = GetTypeDefRefTokenInTypeSpec(tkTypeTmp, &tkTypeTmp); + IfFailGo(hr); + + if (hr == S_OK) + // Ok, tkTypeTmp should be the type token now. + goto CheckParentType; + + // This doesn't have a coded typedef or typeref. + goto ErrExit; + } + case mdtMethodDef: + { + // Follow the parent. + IfFailGo( FindParentOfMethodHelper(tkTypeTmp, &tkTypeTmp)); + goto CheckParentType; + } + break; + case mdtMemberRef: + { + MemberRefRec *pMember; + IfFailGo(GetMemberRefRecord(ridTmp, &pMember)); + // Follow the parent. + tkTypeTmp = getClassOfMemberRef(pMember); + goto CheckParentType; + } + break; + case mdtString: + default: + if(REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_AssertOnBadImageFormat, 0)) + _ASSERTE(!"Unexpected token type in FindCustomAttributeByName"); + hr = COR_E_BADIMAGEFORMAT; + goto ErrExit; + } // switch (TypeFromToken(tkTypeTmp)) + + hr = S_OK; + ErrExit: + + return hr; + } // CommonGetNameOfCustomAttribute + + __checkReturn + HRESULT GetTypeDefRefTokenInTypeSpec(mdTypeSpec tkTypeSpec, // [IN] TypeSpec token to look + mdToken *tkEnclosedToken) // [OUT] The enclosed type token + { + _ASSERTE(TypeFromToken(tkTypeSpec) == mdtTypeSpec); + if (TypeFromToken(tkTypeSpec) != mdtTypeSpec || !_IsValidTokenBase(tkTypeSpec)) + return COR_E_BADIMAGEFORMAT; + + HRESULT hr; + TypeSpecRec *pTS; + IfFailRet(GetTypeSpecRecord(RidFromToken(tkTypeSpec), &pTS)); + ULONG cbSig = 0; + PCCOR_SIGNATURE pSig; + PCCOR_SIGNATURE pEnd; + ULONG data = 0; + + IfFailRet(getSignatureOfTypeSpec(pTS, &pSig, &cbSig)); + pEnd = pSig + cbSig; + + if (cbSig == 0) + return COR_E_BADIMAGEFORMAT; + + pSig += CorSigUncompressData(pSig, &data); + + while (pSig < pEnd && CorIsModifierElementType((CorElementType) data)) + { + pSig += CorSigUncompressData(pSig, &data); + } + + // See if the signature was bad + if (pSig >= pEnd) + return COR_E_BADIMAGEFORMAT; + + // pSig should point to the element type now. + if (data == ELEMENT_TYPE_VALUETYPE || data == ELEMENT_TYPE_CLASS) + { + // Get the new type token + if (CorSigUncompressToken(pSig, tkEnclosedToken) == 0) + return COR_E_BADIMAGEFORMAT; + + // Ok, tkEnclosedToken should be the type token now + return S_OK; + } + + // The enclosed type is a base type or an array. We don't have a token to hand out + *tkEnclosedToken = mdTokenNil; + + return S_FALSE; + } + + + + //***************************************************************************** + // Given a scope, return the number of tokens in a given table + //***************************************************************************** + ULONG CommonGetRowCount( // return hresult + DWORD tkKind) // [IN] pass in the kind of token. + { + _ASSERTE(!IsWritable() && "IMetaModelCommonRO methods cannot be used because this importer is writable."); + + ULONG ulCount = 0; + + switch (tkKind) + { + case mdtTypeDef: + ulCount = getCountTypeDefs(); + break; + case mdtTypeRef: + ulCount = getCountTypeRefs(); + break; + case mdtMethodDef: + ulCount = getCountMethods(); + break; + case mdtFieldDef: + ulCount = getCountFields(); + break; + case mdtMemberRef: + ulCount = getCountMemberRefs(); + break; + case mdtInterfaceImpl: + ulCount = getCountInterfaceImpls(); + break; + case mdtParamDef: + ulCount = getCountParams(); + break; + case mdtFile: + ulCount = getCountFiles(); + break; + case mdtAssemblyRef: + ulCount = getCountAssemblyRefs(); + break; + case mdtAssembly: + ulCount = getCountAssemblys(); + break; + case mdtCustomAttribute: + ulCount = getCountCustomAttributes(); + break; + case mdtModule: + ulCount = getCountModules(); + break; + case mdtPermission: + ulCount = getCountDeclSecuritys(); + break; + case mdtSignature: + ulCount = getCountStandAloneSigs(); + break; + case mdtEvent: + ulCount = getCountEvents(); + break; + case mdtProperty: + ulCount = getCountPropertys(); + break; + case mdtModuleRef: + ulCount = getCountModuleRefs(); + break; + case mdtTypeSpec: + ulCount = getCountTypeSpecs(); + break; + case mdtExportedType: + ulCount = getCountExportedTypes(); + break; + case mdtManifestResource: + ulCount = getCountManifestResources(); + break; + case mdtGenericParam: + ulCount = getCountGenericParams(); + break; + case mdtMethodSpec: + ulCount = getCountMethodSpecs(); + break; + default: + Debug_ReportError("Invalid token kind (table)"); + ulCount = 0; + break; + } + return ulCount; + } // ULONG CommonGetRowCount() + + + + //***************************************************************************** + // Locate methodimpl token range for a given typeDef + //***************************************************************************** + HRESULT CommonGetMethodImpls( + mdTypeDef tkTypeDef, // [IN] typeDef to scope search + mdToken *ptkMethodImplFirst, // [OUT] returns first methodImpl token + ULONG *pMethodImplCount // [OUT] returns # of methodImpl tokens scoped to type + ) + { + _ASSERTE(!IsWritable() && "IMetaModelCommonRO methods cannot be used because this importer is writable."); + + _ASSERTE(TypeFromToken(tkTypeDef) == mdtTypeDef); + _ASSERTE(ptkMethodImplFirst != NULL); + _ASSERTE(pMethodImplCount != NULL); + + HRESULT hr; + + RID ridEnd; + RID ridStart; + IfFailGo(getMethodImplsForClass(RidFromToken(tkTypeDef), &ridEnd, &ridStart)); + *pMethodImplCount = ridEnd - ridStart; + if (*pMethodImplCount) + { + *ptkMethodImplFirst = TokenFromRid(TBL_MethodImpl << 24, ridStart); + } + hr = S_OK; + + ErrExit: + return hr; + } + + //***************************************************************************** + // Extract row info for methodImpl + //***************************************************************************** + HRESULT CommonGetMethodImplProps( + mdToken tkMethodImpl, // [IN] methodImpl + mdToken *pBody, // [OUT] returns body token + mdToken *pDecl // [OUT] returns decl token + ) + { + _ASSERTE(!IsWritable() && "IMetaModelCommonRO methods cannot be used because this importer is writable."); + + HRESULT hr; + _ASSERTE(TypeFromToken(tkMethodImpl) == (TBL_MethodImpl << 24)); + _ASSERTE(pBody != NULL); + _ASSERTE(pDecl != NULL); + MethodImplRec *pRec; + IfFailGo(GetMethodImplRecord(RidFromToken(tkMethodImpl), &pRec)); + *pBody = getMethodBodyOfMethodImpl(pRec); + *pDecl = getMethodDeclarationOfMethodImpl(pRec); + hr = S_OK; + ErrExit: + return hr; + } + + // IMetaModelCommonRO interface end + + + + +public: +// friend class CLiteWeightStgdb; + + __checkReturn + virtual HRESULT vGetRow(UINT32 nTableIndex, UINT32 nRowIndex, void **ppRow) + { + return getRow(nTableIndex, nRowIndex, ppRow); + } + +public: + + //************************************************************************* + // This group of functions are table-level (one function per table). Functions like + // getting a count of rows. + + // Functions to get the count of rows in a table. Functions like: + // ULONG getCountXyzs() { return m_Schema.m_cRecs[TBL_Xyz];} +#undef MiniMdTable +#define MiniMdTable(tbl) ULONG getCount##tbl##s() { return _TBLCNT(tbl); } + MiniMdTables(); + // macro misspells some names. + ULONG getCountProperties() {return getCountPropertys();} + ULONG getCountMethodSemantics() {return getCountMethodSemanticss();} + + // Functions for getting a row by rid. Look like: + // HRESULT GetXyzRecord(RID rid, XyzRec **ppRecord) { return m_Tables[TBL_Xyz].GetRecord(rid, ppRecord); } + // e.g.: + // HRESULT GetMethodRecord(RID rid, MethodRec **ppRecord) { return m_Tables[TBL_Method].GetRecord(rid, ppRecord); } + #undef MiniMdTable +#define MiniMdTable(tbl) __checkReturn HRESULT Get##tbl##Record(RID rid, tbl##Rec **ppRecord) { \ + return getRow(TBL_##tbl, rid, reinterpret_cast<void **>(ppRecord)); } + MiniMdTables(); + + //************************************************************************* + // These are specialized searching functions. Mostly generic (ie, find + // a custom value for any object). + + // Functions to search for a record relating to another record. + // Return RID to Constant table. + __checkReturn + HRESULT FindConstantFor(RID rid, mdToken typ, RID *pFoundRid) + { return doSearchTable(TBL_Constant, _COLPAIR(Constant,Parent), encodeToken(rid,typ,mdtHasConstant,lengthof(mdtHasConstant)), pFoundRid); } + + // Return RID to FieldMarshal table. + __checkReturn + HRESULT FindFieldMarshalFor(RID rid, mdToken typ, RID *pFoundRid) + { return doSearchTable(TBL_FieldMarshal, _COLPAIR(FieldMarshal,Parent), encodeToken(rid,typ,mdtHasFieldMarshal,lengthof(mdtHasFieldMarshal)), pFoundRid); } + + // Return RID to ClassLayout table, given the rid to a TypeDef. + __checkReturn + HRESULT FindClassLayoutFor(RID rid, RID *pFoundRid) + { return doSearchTable(TBL_ClassLayout, _COLPAIR(ClassLayout,Parent), RidFromToken(rid), pFoundRid); } + + // given a rid to the Event table, find an entry in EventMap table that contains the back pointer + // to its typedef parent + __checkReturn + HRESULT FindEventMapParentOfEvent(RID rid, RID *pFoundRid) + { + return vSearchTableNotGreater(TBL_EventMap, _COLDEF(EventMap,EventList), rid, pFoundRid); + } + // return the parent eventmap rid given a event rid + __checkReturn + HRESULT FindParentOfEvent(RID rid, RID *pFoundRid) + { + return vSearchTableNotGreater(TBL_EventMap, _COLDEF(EventMap,EventList), rid, pFoundRid); + } + + // given a rid to the Event table, find an entry in EventMap table that contains the back pointer + // to its typedef parent + __checkReturn + HRESULT FindPropertyMapParentOfProperty(RID rid, RID *pFoundRid) + { + return vSearchTableNotGreater(TBL_PropertyMap, _COLDEF(PropertyMap,PropertyList), rid, pFoundRid); + } + // return the parent propertymap rid given a property rid + __checkReturn + HRESULT FindParentOfProperty(RID rid, RID *pFoundRid) + { + return vSearchTableNotGreater(TBL_PropertyMap, _COLDEF(PropertyMap,PropertyList), rid, pFoundRid); + } + + // Return RID to MethodSemantics table, given the rid to a MethodDef. + __checkReturn + HRESULT FindMethodSemanticsFor(RID rid, RID *pFoundRid) + { return doSearchTable(TBL_MethodSemantics, _COLPAIR(MethodSemantics,Method), RidFromToken(rid), pFoundRid); } + + // return the parent typedef rid given a field def rid + __checkReturn + HRESULT FindParentOfField(RID rid, RID *pFoundRid) + { + return vSearchTableNotGreater(TBL_TypeDef, _COLDEF(TypeDef,FieldList), rid, pFoundRid); + } + + // return the parent typedef rid given a method def rid + __checkReturn + HRESULT FindParentOfMethod(RID rid, RID *pFoundRid) + { + return vSearchTableNotGreater(TBL_TypeDef, _COLDEF(TypeDef,MethodList), rid, pFoundRid); + } + + __checkReturn + HRESULT FindParentOfParam(RID rid, RID *pFoundRid) + { + return vSearchTableNotGreater(TBL_Method, _COLDEF(Method,ParamList), rid, pFoundRid); + } + + // Find a FieldLayout record given the corresponding Field. + __checkReturn + HRESULT FindFieldLayoutFor(RID rid, RID *pFoundRid) + { return doSearchTable(TBL_FieldLayout, _COLPAIR(FieldLayout, Field), rid, pFoundRid); } + + // Return RID to Constant table. + __checkReturn + HRESULT FindImplMapFor(RID rid, mdToken typ, RID *pFoundRid) + { return doSearchTable(TBL_ImplMap, _COLPAIR(ImplMap,MemberForwarded), encodeToken(rid,typ,mdtMemberForwarded,lengthof(mdtMemberForwarded)), pFoundRid); } + + // Return RID to FieldRVA table. + __checkReturn + HRESULT FindFieldRVAFor(RID rid, RID *pFoundRid) + { return doSearchTable(TBL_FieldRVA, _COLPAIR(FieldRVA, Field), rid, pFoundRid); } + + // Find a NestedClass record given the corresponding Field. + __checkReturn + HRESULT FindNestedClassFor(RID rid, RID *pFoundRid) + { return doSearchTable(TBL_NestedClass, _COLPAIR(NestedClass, NestedClass), rid, pFoundRid); } + + //************************************************************************* + // These are table-specific functions. + + // ModuleRec + _GETSTR(Module,Name); + __checkReturn HRESULT _GETGUID(Module,Mvid); + __checkReturn HRESULT _GETGUID(Module,EncId); + __checkReturn HRESULT _GETGUID(Module,EncBaseId); + + // TypeRefRec + mdToken _GETCDTKN(TypeRef, ResolutionScope, mdtResolutionScope); + _GETSTR(TypeRef, Name); + _GETSTR(TypeRef, Namespace); + + // TypeDefRec + ULONG _GETFLD(TypeDef,Flags); // USHORT getFlagsOfTypeDef(TypeDefRec *pRec); + _GETSTR(TypeDef,Name); + _GETSTR(TypeDef,Namespace); + + _GETLIST(TypeDef,FieldList,Field); // RID getFieldListOfTypeDef(TypeDefRec *pRec); + _GETLIST(TypeDef,MethodList,Method); // RID getMethodListOfTypeDef(TypeDefRec *pRec); + mdToken _GETCDTKN(TypeDef,Extends,mdtTypeDefOrRef); // mdToken getExtendsOfTypeDef(TypeDefRec *pRec); + + __checkReturn + HRESULT getGenericParamsForTypeDef(RID rid, RID *pEnd, RID *pFoundRid) + { + return SearchTableForMultipleRows(TBL_GenericParam, + _COLDEF(GenericParam,Owner), + encodeToken(rid, mdtTypeDef, mdtTypeOrMethodDef, lengthof(mdtTypeOrMethodDef)), + pEnd, + pFoundRid); + } + __checkReturn + HRESULT getGenericParamsForMethodDef(RID rid, RID *pEnd, RID *pFoundRid) + { + return SearchTableForMultipleRows(TBL_GenericParam, + _COLDEF(GenericParam,Owner), + encodeToken(rid, mdtMethodDef, mdtTypeOrMethodDef, lengthof(mdtTypeOrMethodDef)), + pEnd, + pFoundRid); + } + __checkReturn + HRESULT getMethodSpecsForMethodDef(RID rid, RID *pEnd, RID *pFoundRid) + { + return SearchTableForMultipleRows(TBL_MethodSpec, + _COLDEF(MethodSpec,Method), + encodeToken(rid, mdtMethodDef, mdtMethodDefOrRef, lengthof(mdtMethodDefOrRef)), + pEnd, + pFoundRid); + } + __checkReturn + HRESULT getMethodSpecsForMemberRef(RID rid, RID *pEnd, RID *pFoundRid) + { + return SearchTableForMultipleRows(TBL_MethodSpec, + _COLDEF(MethodSpec,Method), + encodeToken(rid, mdtMemberRef, mdtMethodDefOrRef, lengthof(mdtMethodDefOrRef)), + pEnd, + pFoundRid); + } + __checkReturn + HRESULT getInterfaceImplsForTypeDef(RID rid, RID *pEnd, RID *pFoundRid) + { + return SearchTableForMultipleRows(TBL_InterfaceImpl, + _COLDEF(InterfaceImpl,Class), + rid, + pEnd, + pFoundRid); + } + + // FieldPtr + ULONG _GETRID(FieldPtr,Field); + + // FieldRec + USHORT _GETFLD(Field,Flags); // USHORT getFlagsOfField(FieldRec *pRec); + _GETSTR(Field,Name); // HRESULT getNameOfField(FieldRec *pRec, LPCUTF8 *pszString); + _GETSIGBLOB(Field,Signature); // HRESULT getSignatureOfField(FieldRec *pRec, PCCOR_SIGNATURE *ppbData, ULONG *pcbSize); + + // MethodPtr + ULONG _GETRID(MethodPtr,Method); + + // MethodRec + ULONG _GETFLD(Method,RVA); + USHORT _GETFLD(Method,ImplFlags); + USHORT _GETFLD(Method,Flags); + _GETSTR(Method,Name); // HRESULT getNameOfMethod(MethodRec *pRec, LPCUTF8 *pszString); + _GETSIGBLOB(Method,Signature); // HRESULT getSignatureOfMethod(MethodRec *pRec, PCCOR_SIGNATURE *ppbData, ULONG *pcbSize); + _GETLIST(Method,ParamList,Param); + + // ParamPtr + ULONG _GETRID(ParamPtr,Param); + + // ParamRec + USHORT _GETFLD(Param,Flags); + USHORT _GETFLD(Param,Sequence); + _GETSTR(Param,Name); + + // InterfaceImplRec + mdToken _GETTKN(InterfaceImpl,Class,mdtTypeDef); + mdToken _GETCDTKN(InterfaceImpl,Interface,mdtTypeDefOrRef); + + // MemberRefRec + mdToken _GETCDTKN(MemberRef,Class,mdtMemberRefParent); + _GETSTR(MemberRef,Name); + _GETSIGBLOB(MemberRef,Signature); // HRESULT getSignatureOfMemberRef(MemberRefRec *pRec, PCCOR_SIGNATURE *ppbData, ULONG *pcbSize); + + // ConstantRec + BYTE _GETFLD(Constant,Type); + mdToken _GETCDTKN(Constant,Parent,mdtHasConstant); + _GETBLOB(Constant,Value); + + // CustomAttributeRec + __checkReturn + HRESULT getCustomAttributeForToken(mdToken tk, RID *pEnd, RID *pFoundRid) + { + return SearchTableForMultipleRows(TBL_CustomAttribute, + _COLDEF(CustomAttribute,Parent), + encodeToken(RidFromToken(tk), TypeFromToken(tk), mdtHasCustomAttribute, lengthof(mdtHasCustomAttribute)), + pEnd, + pFoundRid); + } + + mdToken _GETCDTKN(CustomAttribute,Parent,mdtHasCustomAttribute); + mdToken _GETCDTKN(CustomAttribute,Type,mdtCustomAttributeType); + _GETBLOB(CustomAttribute,Value); + + // FieldMarshalRec + mdToken _GETCDTKN(FieldMarshal,Parent,mdtHasFieldMarshal); + _GETSIGBLOB(FieldMarshal,NativeType); + + // DeclSecurityRec + __checkReturn + HRESULT getDeclSecurityForToken(mdToken tk, RID *pEnd, RID *pFoundRid) + { + return SearchTableForMultipleRows(TBL_DeclSecurity, + _COLDEF(DeclSecurity,Parent), + encodeToken(RidFromToken(tk), TypeFromToken(tk), mdtHasDeclSecurity, lengthof(mdtHasDeclSecurity)), + pEnd, + pFoundRid); + } + + short _GETFLD(DeclSecurity,Action); + mdToken _GETCDTKN(DeclSecurity,Parent,mdtHasDeclSecurity); + _GETBLOB(DeclSecurity,PermissionSet); + + // ClassLayoutRec + USHORT _GETFLD(ClassLayout,PackingSize); + ULONG _GETFLD(ClassLayout,ClassSize); + ULONG _GETTKN(ClassLayout,Parent, mdtTypeDef); + + // FieldLayout + ULONG _GETFLD(FieldLayout,OffSet); + ULONG _GETTKN(FieldLayout, Field, mdtFieldDef); + + // Event map. + _GETLIST(EventMap,EventList,Event); + ULONG _GETRID(EventMap, Parent); + + // EventPtr + ULONG _GETRID(EventPtr, Event); + + // Event. + USHORT _GETFLD(Event,EventFlags); + _GETSTR(Event,Name); + mdToken _GETCDTKN(Event,EventType,mdtTypeDefOrRef); + + // Property map. + _GETLIST(PropertyMap,PropertyList,Property); + ULONG _GETRID(PropertyMap, Parent); + + // PropertyPtr + ULONG _GETRID(PropertyPtr, Property); + + // Property. + USHORT _GETFLD(Property,PropFlags); + _GETSTR(Property,Name); + _GETSIGBLOB(Property,Type); + + // MethodSemantics. + // Given an event or a property token, return the beginning/ending + // associates. + // + __checkReturn + HRESULT getAssociatesForToken(mdToken tk, RID *pEnd, RID *pFoundRid) + { + return SearchTableForMultipleRows(TBL_MethodSemantics, + _COLDEF(MethodSemantics,Association), + encodeToken(RidFromToken(tk), TypeFromToken(tk), mdtHasSemantic, lengthof(mdtHasSemantic)), + pEnd, + pFoundRid); + } + + USHORT _GETFLD(MethodSemantics,Semantic); + mdToken _GETTKN(MethodSemantics,Method,mdtMethodDef); + mdToken _GETCDTKN(MethodSemantics,Association,mdtHasSemantic); + + // MethodImpl + // Given a class token, return the beginning/ending MethodImpls. + // + __checkReturn + HRESULT getMethodImplsForClass(RID rid, RID *pEnd, RID *pFoundRid) + { + return SearchTableForMultipleRows(TBL_MethodImpl, + _COLDEF(MethodImpl, Class), + rid, + pEnd, + pFoundRid); + } + + mdToken _GETTKN(MethodImpl,Class,mdtTypeDef); + mdToken _GETCDTKN(MethodImpl,MethodBody, mdtMethodDefOrRef); + mdToken _GETCDTKN(MethodImpl, MethodDeclaration, mdtMethodDefOrRef); + + // StandAloneSigRec + _GETSIGBLOB(StandAloneSig,Signature); // HRESULT getSignatureOfStandAloneSig(StandAloneSigRec *pRec, PCCOR_SIGNATURE *ppbData, ULONG *pcbSize); + + // TypeSpecRec + // const BYTE* getSignatureOfTypeSpec(TypeSpecRec *pRec, ULONG *pcb); + _GETSIGBLOB(TypeSpec,Signature); + + // ModuleRef + _GETSTR(ModuleRef,Name); + + // ENCLog + ULONG _GETFLD(ENCLog, FuncCode); // ULONG getFuncCodeOfENCLog(ENCLogRec *pRec); + + // ImplMap + USHORT _GETFLD(ImplMap, MappingFlags); // USHORT getMappingFlagsOfImplMap(ImplMapRec *pRec); + mdToken _GETCDTKN(ImplMap, MemberForwarded, mdtMemberForwarded); // mdToken getMemberForwardedOfImplMap(ImplMapRec *pRec); + _GETSTR(ImplMap, ImportName); // HRESULT getImportNameOfImplMap(ImplMapRec *pRec, LPCUTF8 *pszString); + mdToken _GETTKN(ImplMap, ImportScope, mdtModuleRef); // mdToken getImportScopeOfImplMap(ImplMapRec *pRec); + + // FieldRVA + ULONG _GETFLD(FieldRVA, RVA); // ULONG getRVAOfFieldRVA(FieldRVARec *pRec); + mdToken _GETTKN(FieldRVA, Field, mdtFieldDef); // mdToken getFieldOfFieldRVA(FieldRVARec *pRec); + + // Assembly + ULONG _GETFLD(Assembly, HashAlgId); + USHORT _GETFLD(Assembly, MajorVersion); + USHORT _GETFLD(Assembly, MinorVersion); + USHORT _GETFLD(Assembly, BuildNumber); + USHORT _GETFLD(Assembly, RevisionNumber); + ULONG _GETFLD(Assembly, Flags); + _GETBLOB(Assembly, PublicKey); + _GETSTR(Assembly, Name); + _GETSTR(Assembly, Locale); + + // AssemblyRef + USHORT _GETFLD(AssemblyRef, MajorVersion); + USHORT _GETFLD(AssemblyRef, MinorVersion); + USHORT _GETFLD(AssemblyRef, BuildNumber); + USHORT _GETFLD(AssemblyRef, RevisionNumber); + ULONG _GETFLD(AssemblyRef, Flags); + _GETBLOB(AssemblyRef, PublicKeyOrToken); + _GETSTR(AssemblyRef, Name); + _GETSTR(AssemblyRef, Locale); + _GETBLOB(AssemblyRef, HashValue); + + // File + ULONG _GETFLD(File, Flags); + _GETSTR(File, Name); + _GETBLOB(File, HashValue); + + // ExportedType + ULONG _GETFLD(ExportedType, Flags); + ULONG _GETFLD(ExportedType, TypeDefId); + _GETSTR(ExportedType, TypeName); + _GETSTR(ExportedType, TypeNamespace); + mdToken _GETCDTKN(ExportedType, Implementation, mdtImplementation); + + // ManifestResource + ULONG _GETFLD(ManifestResource, Offset); + ULONG _GETFLD(ManifestResource, Flags); + _GETSTR(ManifestResource, Name); + mdToken _GETCDTKN(ManifestResource, Implementation, mdtImplementation); + + // NestedClass + mdToken _GETTKN(NestedClass, NestedClass, mdtTypeDef); + mdToken _GETTKN(NestedClass, EnclosingClass, mdtTypeDef); + + int GetSizeOfMethodNameColumn() + { + return _COLDEF(Method,Name).m_cbColumn; + } + + // GenericParRec + USHORT _GETFLD(GenericParam,Number); + USHORT _GETFLD(GenericParam,Flags); + mdToken _GETCDTKN(GenericParam,Owner,mdtTypeOrMethodDef); + _GETSTR(GenericParam,Name); + + __checkReturn + HRESULT getGenericParamConstraintsForGenericParam(RID rid, RID *pEnd, RID *pFoundRid) + { + return SearchTableForMultipleRows(TBL_GenericParamConstraint, + _COLDEF(GenericParamConstraint,Owner), + rid, + pEnd, + pFoundRid); + } + + // MethodSpecRec + mdToken _GETCDTKN(MethodSpec,Method,mdtMethodDefOrRef); + _GETSIGBLOB(MethodSpec,Instantiation); + + //GenericParamConstraintRec + mdToken _GETTKN(GenericParamConstraint,Owner,mdtGenericParam); + mdToken _GETCDTKN(GenericParamConstraint,Constraint,mdtTypeDefOrRef); + + BOOL SupportsGenerics() + { + // Only 2.0 of the metadata (and 1.1) support generics + return (m_Schema.m_major >= METAMODEL_MAJOR_VER_V2_0 || + (m_Schema.m_major == METAMODEL_MAJOR_VER_B1 && m_Schema.m_minor == METAMODEL_MINOR_VER_B1)); + }// SupportGenerics + + protected: + //***************************************************************************** + // Helper: determine if a token is valid or not + //***************************************************************************** + BOOL _IsValidTokenBase( + mdToken tk) + { + BOOL bRet = FALSE; + RID rid = RidFromToken(tk); + + if (rid != 0) + { + switch (TypeFromToken(tk)) + { + case mdtModule: + // can have only one module record + bRet = (rid <= getCountModules()); + break; + case mdtTypeRef: + bRet = (rid <= getCountTypeRefs()); + break; + case mdtTypeDef: + bRet = (rid <= getCountTypeDefs()); + break; + case mdtFieldDef: + bRet = (rid <= getCountFields()); + break; + case mdtMethodDef: + bRet = (rid <= getCountMethods()); + break; + case mdtParamDef: + bRet = (rid <= getCountParams()); + break; + case mdtInterfaceImpl: + bRet = (rid <= getCountInterfaceImpls()); + break; + case mdtMemberRef: + bRet = (rid <= getCountMemberRefs()); + break; + case mdtCustomAttribute: + bRet = (rid <= getCountCustomAttributes()); + break; + case mdtPermission: + bRet = (rid <= getCountDeclSecuritys()); + break; + case mdtSignature: + bRet = (rid <= getCountStandAloneSigs()); + break; + case mdtEvent: + bRet = (rid <= getCountEvents()); + break; + case mdtProperty: + bRet = (rid <= getCountPropertys()); + break; + case mdtModuleRef: + bRet = (rid <= getCountModuleRefs()); + break; + case mdtTypeSpec: + bRet = (rid <= getCountTypeSpecs()); + break; + case mdtAssembly: + bRet = (rid <= getCountAssemblys()); + break; + case mdtAssemblyRef: + bRet = (rid <= getCountAssemblyRefs()); + break; + case mdtFile: + bRet = (rid <= getCountFiles()); + break; + case mdtExportedType: + bRet = (rid <= getCountExportedTypes()); + break; + case mdtManifestResource: + bRet = (rid <= getCountManifestResources()); + break; + case mdtGenericParam: + bRet = (rid <= getCountGenericParams()); + break; + case mdtGenericParamConstraint: + bRet = (rid <= getCountGenericParamConstraints()); + break; + case mdtMethodSpec: + bRet = (rid <= getCountMethodSpecs()); + break; + default: + _ASSERTE(!bRet); + Debug_ReportError("Unknown token kind!"); + } + } + return bRet; + } // _IsValidToken + +#ifdef FEATURE_METADATA_RELEASE_MEMORY_ON_REOPEN + bool IsSafeToDelete() + { + return m_isSafeToDelete; + } + + FORCEINLINE void MarkUnsafeToDelete() { m_isSafeToDelete = false; } + + bool m_isSafeToDelete; // This starts out true, but gets set to FALSE if we detect + // a MiniMd API call that might have given out an internal pointer. +#endif + +}; //class CMiniMdTemplate<Impl> + + + +#undef SETP +#undef _GETCDTKN +#undef _GETTKN +#undef _GETRID +#undef _GETBLOB +#undef _GETGUID +#undef _GETSTR +#undef SCHEMA + +#endif // _METAMODEL_H_ +// eof ------------------------------------------------------------------------ |