summaryrefslogtreecommitdiff
path: root/src/md/inc
diff options
context:
space:
mode:
Diffstat (limited to 'src/md/inc')
-rw-r--r--src/md/inc/.gitmirror1
-rw-r--r--src/md/inc/VerifyLayouts.inc351
-rw-r--r--src/md/inc/assemblymdinternaldisp.h723
-rw-r--r--src/md/inc/cahlprinternal.h94
-rw-r--r--src/md/inc/imptlb.h777
-rw-r--r--src/md/inc/liteweightstgdb.h257
-rw-r--r--src/md/inc/mdcolumndescriptors.h51
-rw-r--r--src/md/inc/mdfileformat.h269
-rw-r--r--src/md/inc/mdinternalrw.h862
-rw-r--r--src/md/inc/mdlog.h25
-rw-r--r--src/md/inc/metadatahash.h207
-rw-r--r--src/md/inc/metamodel.h2072
-rw-r--r--src/md/inc/metamodelro.h240
-rw-r--r--src/md/inc/metamodelrw.h1479
-rw-r--r--src/md/inc/recordpool.h161
-rw-r--r--src/md/inc/rwutil.h369
-rw-r--r--src/md/inc/stgio.h293
-rw-r--r--src/md/inc/stgtiggerstorage.h328
-rw-r--r--src/md/inc/stgtiggerstream.h112
-rw-r--r--src/md/inc/streamutil.h221
-rw-r--r--src/md/inc/verifylayouts.h186
-rw-r--r--src/md/inc/winmdinterfaces.h120
22 files changed, 9198 insertions, 0 deletions
diff --git a/src/md/inc/.gitmirror b/src/md/inc/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/md/inc/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/md/inc/VerifyLayouts.inc b/src/md/inc/VerifyLayouts.inc
new file mode 100644
index 0000000000..4c0bd65b30
--- /dev/null
+++ b/src/md/inc/VerifyLayouts.inc
@@ -0,0 +1,351 @@
+// 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.
+
+
+// This file provides an explicit check of field layouts using some macro magic
+// in VerifyLayouts.h. The goal is that if any field changes offset or type changes
+// size then a build time assert should trigger. DO NOT change these definitions without
+// reading the comments in VerifyLayouts.h and understanding what other code you need
+// to change at the same time.
+//
+//
+// AN EXAMPLE:
+// You want to validate the fields in type CDerived
+//
+// class CFoo
+// {
+// void* m_ptrField;
+// }
+//
+// struct BigStruct
+// {
+// DWORD m_one;
+// DWORD m_two;
+// DWORD m_three;
+// }
+//
+// CDerived : CFoo
+// {
+// DWORD m_cRef;
+// SomeOtherType* m_otherType;
+// #ifdef _SOME_DEFINE
+// BigStruct m_struct;
+// #endif //_SOME_DEFINE
+// }
+//
+//
+// and the layout validation is written as:
+//
+// BEGIN_TYPE(CDerived, sizeof(CFoo)) // a) The first field starts at sizeof(CFoo) to account for base class data
+// // b) Beware of vtable pointers, they take up space before the data fields too
+// // c) Beware of using sizeof(some_other_type) unless you also explicitly verify
+// // the layout of that type here. Changing the base type would change the derived types
+// // layout and won't be caught unless the base type is explicitly verified.
+// // d) sizeof(<primitive_type>) is fine - they never change over time and we know how
+// // to deal with platform pointer size differences
+// FIELD(CDerived, m_cRef, 4)
+// FIELD(CDerived, m_otherType, sizeof(void*))
+// #ifdef _SOME_DEFINE_
+// ALIGN_FIELD(CDerived, m_struct, sizeof(BigStruct), 4) // We need to use the ALIGN_FIELD macro because the alignment isn't the same as
+// // the field size. The alignment of a structure is typically the max alignment
+// // of any member. The alignment of a primitive type is typically the size of the type.
+// #endif _SOME_DEFINE_
+// END_TYPE(CDerived, sizeof(void*)
+//
+//
+// BEGIN_TYPE(CFoo, 0) // We must verify this type because we used it to define the starting offset of CDerived
+// FIELD(CFoo, m_ptrField, sizeof(void*))
+// END_TYPE(CFoo, sizeof(void*))
+//
+//
+// BEGIN_TYPE(BigStruct, 0) // We must verify this type because we used sizeof(BigStruct) to define the size of
+// // CDerived::m_struct field
+// FIELD(BigStruct, m_one, 4)
+// FIELD(BigStruct, m_two, 4)
+// FIELD(BigStruct, m_thee, 4)
+// END_TYPE(BigStruct, 4)
+//
+//
+//
+//
+// OTHER CONSIDERATIONS:
+//
+// 1) if the type layout is conditional on a define, just include the same define here in the layout verification
+// Make sure that the define is registered in the list of defines and the debugger reading code knows how to dynamically
+// adjust for it (See VerifyLayouts.h comment item (b) and (c))
+//
+// 2) If your type names use characters that aren't valid identifiers (such as the '<' and '>' chars in templates)
+// then you need to provide an escaped name. There are variations of the macros above to do that:
+// BEGIN_TYPE_ESCAPED(typeName, escaptedTypeName, firstFieldOffset)
+// FIELD_ESCAPED(typeName, escapedTypeName, fieldName, fieldSize)
+// ALIGN_FIELD_ESCAPED(typeName, escapedTypeName, fieldName, fieldSize, fieldAlign)
+// END_TYPE_ESCAPED(typeName, escapedTypeName, typeAlignment)
+//
+// If CFoo above had instead been CFoo<ULONG> we would write:
+// BEGIN_TYPE_ESCAPED(CFoo<ULONG>, CFoo__ULONG__, 0)
+// FIELD_ESCAPED(CFoo<ULONG>, CFoo__ULONG__, m_ptrField, sizeof(void*))
+// END_TYPE_ESCAPED(CFoo<ULONG>, CFoo__ULONG__, sizeof(void*))
+//
+// The escapedTypeName is relatively arbitrary, but convention is to replace the illegal characters with double underscore
+// The name does show up in build error messages, so it should close to the real name for people to understand
+//
+// 3) If your type name has commas in it (such as in a list of template arguments) the macros could interpret it as seperate
+// arguments (no good). To fix this use the IGNORE_COMMAS() macro to escape any typeNames with commas. If CFoo above had
+// been CFoo<ULONG,INT> you could rewrite the defines as:
+// BEGIN_TYPE_ESCAPED(IGNORE_COMMAS(CFoo<ULONG,INT>), CFoo__ULONG__INT__, 0)
+// FIELD_ESCAPED(IGNORE_COMMAS(CFoo<ULONG,INT>), CFoo__ULONG__INT__, m_ptrField, sizeof(void*))
+// END_TYPE_ESCAPED(IGNORE_COMMAS(CFoo<ULONG,INT>), CFoo__ULONG__INT__, sizeof(void*))
+//
+// 4) If you have a bitfield in your type, the offsetof macro can't be used which will break the static asserts.
+// There is a special BITFIELD macro that can work around it:
+// BITFIELD(typeName, fieldName, expectedFieldOffset, fieldSize, fieldAlign)
+//
+// The macro is just like FIELD execpt you must provide the offset yourself. Since you can't use offsetof on the field directly
+// the convention is to use the offset of the previous field and then add the size and alignment requirements. For example if your
+// type had this:
+// CMiniMdRW
+// {
+// ULONG m_cbSaveSize;
+// int m_fIsReadOnly : 1;
+// int m_bPreSaveDone : 1;
+// int m_bSaveCompressed : 1;
+// int m_bPostGSSMod : 1;
+// }
+//
+// You could write
+// FIELD(CMiniMdRW, m_cbSaveSize, 4)
+// BITFIELD(CMiniMdRW, m_fIsReadOnly, offsetof(CMiniMdRW, m_cbSaveSize)+4, 4)
+//
+// Don't include al the fields in the bitfield, just pick one as the canonical field name
+//
+//
+//
+// HOW DO I DEBUG THIS STUFF WHEN THE BUILD DOESN'T WORK?
+//
+// One way that has been effective for me is to write a few static_assert_no_msg entries manually in VerifyLayouts.h
+// You can use those to verify your assumptions such as:
+// static_assert_no_msg(sizeof(Foo) == 24)
+// static_assert_no_msg(offset(Foo, m_lastField) == 20)
+// static_assert_no_msg(offset_of_field_affter_Foo_m_lastField == 24)
+// Then rebuild and find out where the compiler disagress with you.
+//
+// Another option is to run the source through the preprocessor
+//
+//
+//
+
+
+
+
+
+
+BEGIN_TYPE(MDInternalRW, 2*sizeof(void*))
+FIELD(MDInternalRW, m_pStgdb, sizeof(void*))
+FIELD(MDInternalRW, m_tdModule, 4)
+FIELD(MDInternalRW, m_cRefs, 4)
+FIELD(MDInternalRW, m_fOwnStgdb, 4)
+FIELD(MDInternalRW, m_pUnk, sizeof(void*))
+FIELD(MDInternalRW, m_pUserUnk, sizeof(void*))
+FIELD(MDInternalRW, m_pIMetaDataHelper, sizeof(void*))
+FIELD(MDInternalRW, m_pSemReadWrite, sizeof(void*))
+FIELD(MDInternalRW, m_fOwnSem, 4)
+END_TYPE(MDInternalRW, sizeof(void*))
+
+BEGIN_TYPE(CLiteWeightStgdbRW, sizeof(CLiteWeightStgdb<CMiniMdRW>))
+FIELD(CLiteWeightStgdbRW, m_cbSaveSize, 4)
+FIELD(CLiteWeightStgdbRW, m_bSaveCompressed, 4)
+FIELD(CLiteWeightStgdbRW, m_pImage, sizeof(void*))
+FIELD(CLiteWeightStgdbRW, m_dwImageSize, 4)
+FIELD(CLiteWeightStgdbRW, m_dwPEKind, 4)
+FIELD(CLiteWeightStgdbRW, m_dwMachine, 4)
+FIELD(CLiteWeightStgdbRW, m_pStreamList, sizeof(void*))
+FIELD(CLiteWeightStgdbRW, m_pNextStgdb, sizeof(void*))
+FIELD(CLiteWeightStgdbRW, m_eFileType, 4)
+FIELD(CLiteWeightStgdbRW, m_wszFileName, sizeof(void*))
+FIELD(CLiteWeightStgdbRW, m_dwDatabaseLFT, 4)
+FIELD(CLiteWeightStgdbRW, m_dwDatabaseLFS, 4)
+FIELD(CLiteWeightStgdbRW, m_pStgIO, sizeof(void*))
+END_TYPE(CLiteWeightStgdbRW, 8)
+
+BEGIN_TYPE_ESCAPED(CLiteWeightStgdb<CMiniMdRW>, CLiteWeightStgdb__CMiniMdRW__, 0)
+ALIGN_FIELD_ESCAPED(CLiteWeightStgdb<CMiniMdRW>, CLiteWeightStgdb__CMiniMdRW__, m_MiniMd, sizeof(CMiniMdRW), sizeof(void*))
+FIELD_ESCAPED(CLiteWeightStgdb<CMiniMdRW>, CLiteWeightStgdb__CMiniMdRW__, m_pvMd, sizeof(void*))
+FIELD_ESCAPED(CLiteWeightStgdb<CMiniMdRW>, CLiteWeightStgdb__CMiniMdRW__, m_cbMd, 4)
+END_TYPE_ESCAPED(CLiteWeightStgdb<CMiniMdRW>, CLiteWeightStgdb__CMiniMdRW__, sizeof(void*))
+
+BEGIN_TYPE(CMiniMdRW, sizeof(CMiniMdTemplate<CMiniMdRW>))
+FIELD(CMiniMdRW, m_pMemberRefHash, sizeof(void*))
+FIELD(CMiniMdRW, m_pMemberDefHash, sizeof(void*))
+ALIGN_FIELD(CMiniMdRW, m_pLookUpHashs, sizeof(void*)*TBL_COUNT, sizeof(void*))
+ALIGN_FIELD(CMiniMdRW, m_StringPoolOffsetHash, sizeof(MapSHash<UINT32, UINT32>), 4)
+FIELD(CMiniMdRW, m_pNamedItemHash, sizeof(void*))
+FIELD(CMiniMdRW, m_maxRid, 4)
+FIELD(CMiniMdRW, m_limRid, 4)
+FIELD(CMiniMdRW, m_maxIx, 4)
+FIELD(CMiniMdRW, m_limIx, 4)
+FIELD(CMiniMdRW, m_eGrow, 4)
+ALIGN_FIELD(CMiniMdRW, m_Tables, sizeof(RecordPool)*TBL_COUNT, sizeof(void*))
+ALIGN_FIELD(CMiniMdRW, m_pVS, sizeof(void*)*TBL_COUNT, sizeof(void*))
+ALIGN_FIELD(CMiniMdRW, m_StringHeap, sizeof(StgStringPool), sizeof(void*))
+ALIGN_FIELD(CMiniMdRW, m_BlobHeap, sizeof(StgBlobPool), sizeof(void*))
+ALIGN_FIELD(CMiniMdRW, m_UserStringHeap, sizeof(StgBlobPool), sizeof(void*))
+ALIGN_FIELD(CMiniMdRW, m_GuidHeap, sizeof(StgGuidPool), sizeof(void*))
+FIELD(CMiniMdRW, m_pHandler, sizeof(void*))
+FIELD(CMiniMdRW, m_cbSaveSize, 4)
+BITFIELD(CMiniMdRW, m_fIsReadOnly, offsetof(CMiniMdRW, m_cbSaveSize)+4, 4)
+FIELD(CMiniMdRW, m_pMethodMap, sizeof(void*))
+FIELD(CMiniMdRW, m_pFieldMap, sizeof(void*))
+FIELD(CMiniMdRW, m_pPropertyMap, sizeof(void*))
+FIELD(CMiniMdRW, m_pEventMap, sizeof(void*))
+FIELD(CMiniMdRW, m_pParamMap, sizeof(void*))
+FIELD(CMiniMdRW, m_pFilterTable, sizeof(void*))
+FIELD(CMiniMdRW, m_pHostFilter, sizeof(void*))
+FIELD(CMiniMdRW, m_pTokenRemapManager, sizeof(void*))
+ALIGN_FIELD(CMiniMdRW, m_OptionValue, sizeof(OptionValue), 4)
+ALIGN_FIELD(CMiniMdRW, m_StartupSchema, sizeof(CMiniMdSchema), 8)
+ALIGN_FIELD(CMiniMdRW, m_bSortable, sizeof(BYTE)*TBL_COUNT, sizeof(BYTE))
+#ifdef _DEBUG
+FIELD(CMiniMdRW, dbg_m_pLock, sizeof(void*))
+#endif
+FIELD(CMiniMdRW, m_fMinimalDelta, 4)
+FIELD(CMiniMdRW, m_rENCRecs, sizeof(void*))
+END_TYPE(CMiniMdRW, 8)
+
+BEGIN_TYPE(OptionValue, 0)
+FIELD(OptionValue, m_DupCheck, 4)
+FIELD(OptionValue, m_RefToDefCheck, 4)
+FIELD(OptionValue, m_NotifyRemap, 4)
+FIELD(OptionValue, m_UpdateMode, 4)
+FIELD(OptionValue, m_ErrorIfEmitOutOfOrder, 4)
+FIELD(OptionValue, m_ThreadSafetyOptions, 4)
+FIELD(OptionValue, m_ImportOption, 4)
+FIELD(OptionValue, m_LinkerOption, 4)
+FIELD(OptionValue, m_GenerateTCEAdapters, 4)
+FIELD(OptionValue, m_RuntimeVersion, sizeof(void*))
+FIELD(OptionValue, m_MetadataVersion, 4)
+FIELD(OptionValue, m_MergeOptions, 4)
+FIELD(OptionValue, m_InitialSize, 4)
+FIELD(OptionValue, m_LocalRefPreservation, 4)
+END_TYPE(OptionValue, sizeof(void*))
+
+
+BEGIN_TYPE(StgBlobPool, sizeof(StgPool))
+ALIGN_FIELD(StgBlobPool, m_Hash, sizeof(CBlobPoolHash), sizeof(void*))
+END_TYPE(StgBlobPool, sizeof(void*))
+
+BEGIN_TYPE(StgStringPool, sizeof(StgPool))
+ALIGN_FIELD(StgStringPool, m_Hash, sizeof(CStringPoolHash), sizeof(void*))
+FIELD(StgStringPool, m_bHash, sizeof(BOOL))
+END_TYPE(StgStringPool, sizeof(void*))
+
+BEGIN_TYPE(StgGuidPool, sizeof(StgPool))
+ALIGN_FIELD(StgGuidPool, m_Hash, sizeof(CGuidPoolHash), sizeof(void*))
+FIELD(StgGuidPool, m_bHash, sizeof(BOOL))
+END_TYPE(StgGuidPool, sizeof(void*))
+
+BEGIN_TYPE(RecordPool, sizeof(StgPool))
+FIELD(RecordPool, m_cbRec, 4)
+END_TYPE(RecordPool, sizeof(void*))
+
+BEGIN_TYPE(StgPool, sizeof(StgPoolReadOnly))
+FIELD(StgPool, m_ulGrowInc, 4)
+FIELD(StgPool, m_pCurSeg, sizeof(void*))
+FIELD(StgPool, m_cbCurSegOffset, 4)
+BITFIELD(StgPool, m_bFree, offsetof(StgPool, m_cbCurSegOffset)+4, 4) // can't take offsetof on a bitfield so we have to provide the offset another way
+FIELD(StgPool, m_nVariableAlignmentMask, 4)
+FIELD(StgPool, m_cbStartOffsetOfEdit, 4)
+FIELD(StgPool, m_fValidOffsetOfEdit, 4)
+END_TYPE(StgPool, sizeof(void*))
+
+
+BEGIN_TYPE(CStringPoolHash, sizeof(CChainedHash<STRINGHASH>))
+FIELD(CStringPoolHash, m_Pool, sizeof(void*))
+END_TYPE(CStringPoolHash, sizeof(void*))
+
+
+BEGIN_TYPE(CBlobPoolHash, sizeof(CChainedHash<STRINGHASH>))
+FIELD(CBlobPoolHash, m_Pool, sizeof(void*))
+END_TYPE(CStringPoolHash, sizeof(void*))
+
+
+BEGIN_TYPE(CGuidPoolHash, sizeof(CChainedHash<GUIDHASH>))
+FIELD(CGuidPoolHash, m_Pool, sizeof(void*))
+END_TYPE(CGuidPoolHash, sizeof(void*))
+
+
+BEGIN_TYPE_ESCAPED(MetaData::HotHeap, MetaData__HotHeap, 0)
+FIELD_ESCAPED(MetaData::HotHeap, MetaData__HotHeap, m_pHotHeapHeader, sizeof(void*))
+END_TYPE_ESCAPED(MetaData::HotHeap, MetaData__HotHeap, sizeof(void*))
+
+
+BEGIN_TYPE(StgPoolReadOnly, sizeof(StgPoolSeg) + sizeof(void*)) //vtable pointer
+ALIGN_FIELD(StgPoolReadOnly, m_HotHeap, sizeof(MetaData::HotHeap), sizeof(void*))
+END_TYPE(StgPoolReadOnly, sizeof(void*))
+
+BEGIN_TYPE_ESCAPED(IGNORE_COMMAS(MapSHash<ULONG, ULONG>), MapSHash__ULONG__ULONG, sizeof(void*))
+FIELD_ESCAPED(IGNORE_COMMAS(MapSHash<ULONG, ULONG>), MapSHash__ULONG__ULONG, m_table, sizeof(void*))
+FIELD_ESCAPED(IGNORE_COMMAS(MapSHash<ULONG, ULONG>), MapSHash__ULONG__ULONG, m_tableSize, 4)
+FIELD_ESCAPED(IGNORE_COMMAS(MapSHash<ULONG, ULONG>), MapSHash__ULONG__ULONG, m_tableCount, 4)
+FIELD_ESCAPED(IGNORE_COMMAS(MapSHash<ULONG, ULONG>), MapSHash__ULONG__ULONG, m_tableOccupied, 4)
+FIELD_ESCAPED(IGNORE_COMMAS(MapSHash<ULONG, ULONG>), MapSHash__ULONG__ULONG, m_tableMax, 4)
+END_TYPE_ESCAPED(IGNORE_COMMAS(MapSHash<ULONG, ULONG>), MapSHash__ULONG__ULONG, sizeof(void*))
+
+
+BEGIN_TYPE(StgPoolSeg, 0)
+FIELD(StgPoolSeg, m_pSegData, sizeof(void*))
+FIELD(StgPoolSeg, m_pNextSeg, sizeof(void*))
+FIELD(StgPoolSeg, m_cbSegSize, 4)
+FIELD(StgPoolSeg, m_cbSegNext, 4)
+END_TYPE(StgPoolSeg, sizeof(void*))
+
+
+BEGIN_TYPE_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, sizeof(void*)) // vtable pointer
+FIELD_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, m_rgData, sizeof(void*))
+FIELD_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, m_iBuckets, 4)
+FIELD_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, m_iSize, 4)
+FIELD_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, m_iCount, 4)
+FIELD_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, m_iMaxChain, 4)
+FIELD_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, m_iFree, 4)
+END_TYPE_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, sizeof(void*))
+
+
+BEGIN_TYPE(CMiniColDef, 0)
+FIELD(CMiniColDef, m_Type, 1)
+FIELD(CMiniColDef, m_oColumn, 1)
+FIELD(CMiniColDef, m_cbColumn, 1)
+END_TYPE(CMiniColDef, 1)
+
+
+BEGIN_TYPE(CMiniTableDef, 0)
+FIELD(CMiniTableDef, m_pColDefs, sizeof(void*))
+FIELD(CMiniTableDef, m_cCols, 1)
+FIELD(CMiniTableDef, m_iKey, 1)
+FIELD(CMiniTableDef, m_cbRec, 1)
+END_TYPE(CMiniTableDef, sizeof(void*))
+
+BEGIN_TYPE(CMiniMdBase, 8) //vtable ptr and first field 8-byte alignment
+ALIGN_FIELD(CMiniMdBase, m_Schema, sizeof(CMiniMdSchema), 8)
+FIELD(CMiniMdBase, m_TblCount, 4)
+FIELD(CMiniMdBase, m_fVerifiedByTrustedSource, 4)
+ALIGN_FIELD(CMiniMdBase, m_TableDefs, sizeof(CMiniTableDef)*TBL_COUNT, sizeof(void*))
+FIELD(CMiniMdBase, m_iStringsMask, 4)
+FIELD(CMiniMdBase, m_iGuidsMask, 4)
+FIELD(CMiniMdBase, m_iBlobsMask, 4)
+END_TYPE(CMiniMdBase, 8)
+
+
+BEGIN_TYPE(CMiniMdSchemaBase, 0)
+FIELD(CMiniMdSchemaBase, m_ulReserved, 4)
+FIELD(CMiniMdSchemaBase, m_major, 1)
+FIELD(CMiniMdSchemaBase, m_minor, 1)
+FIELD(CMiniMdSchemaBase, m_heaps, 1)
+FIELD(CMiniMdSchemaBase, m_rid, 1)
+FIELD(CMiniMdSchemaBase, m_maskvalid, 8)
+FIELD(CMiniMdSchemaBase, m_sorted, 8)
+END_TYPE(CMiniMdSchemaBase, 8)
+
+BEGIN_TYPE(CMiniMdSchema, sizeof(CMiniMdSchemaBase))
+ALIGN_FIELD(CMiniMdSchema, m_cRecs, 4*TBL_COUNT, 4)
+FIELD(CMiniMdSchema, m_ulExtra, 4)
+END_TYPE(CMiniMdSchema, 8)
diff --git a/src/md/inc/assemblymdinternaldisp.h b/src/md/inc/assemblymdinternaldisp.h
new file mode 100644
index 0000000000..91b7d2cc29
--- /dev/null
+++ b/src/md/inc/assemblymdinternaldisp.h
@@ -0,0 +1,723 @@
+// 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.
+//*****************************************************************************
+// AssemblyMDInternalDispenser.h
+//
+
+//
+// Contains utility code for MD directory
+//
+//*****************************************************************************
+#ifndef __AssemblyMDInternalDispenser__h__
+#define __AssemblyMDInternalDispenser__h__
+
+#include "../runtime/mdinternalro.h"
+
+#ifdef FEATURE_FUSION
+
+#include "fusionpriv.h"
+
+struct CORCOMPILE_VERSION_INFO;
+struct CORCOMPILE_DEPENDENCY;
+
+//*****************************************************************************
+// This class can support the IMetaDataAssemblyImport and some funcationalities
+// of IMetaDataImport on the internal import interface (IMDInternalImport).
+//*****************************************************************************
+class AssemblyMDInternalImport :
+ public IMetaDataAssemblyImport,
+ public IMetaDataImport2,
+#ifdef FEATURE_PREJIT
+ public IGetIMDInternalImport,
+#endif //FEATURE_PREJIT
+ public ISNAssemblySignature
+#ifdef FEATURE_PREJIT
+ , public INativeImageInstallInfo
+#endif // FEATURE_PREJIT
+{
+public:
+ AssemblyMDInternalImport(IMDInternalImport *pMDInternalImport);
+ ~AssemblyMDInternalImport();
+
+ // *** IUnknown methods ***
+ STDMETHODIMP QueryInterface(REFIID riid, void** ppUnk);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+ // *** IMetaDataAssemblyImport methods ***
+ STDMETHODIMP GetAssemblyProps ( // S_OK or error.
+ mdAssembly mda, // [IN] The Assembly for which to get the properties.
+ const void **ppbPublicKey, // [OUT] Pointer to the public key.
+ ULONG *pcbPublicKey, // [OUT] Count of bytes in the public key.
+ ULONG *pulHashAlgId, // [OUT] Hash Algorithm.
+ __out_ecount (cchName) LPWSTR szName, // [OUT] Buffer to fill with name.
+ ULONG cchName, // [IN] Size of buffer in wide chars.
+ ULONG *pchName, // [OUT] Actual # of wide chars in name.
+ ASSEMBLYMETADATA *pMetaData, // [OUT] Assembly MetaData.
+ DWORD *pdwAssemblyFlags); // [OUT] Flags.
+
+ STDMETHODIMP GetAssemblyRefProps ( // S_OK or error.
+ mdAssemblyRef mdar, // [IN] The AssemblyRef for which to get the properties.
+ const void **ppbPublicKeyOrToken, // [OUT] Pointer to the public key or token.
+ ULONG *pcbPublicKeyOrToken, // [OUT] Count of bytes in the public key or token.
+ __out_ecount (cchName) LPWSTR szName, // [OUT] Buffer to fill with name.
+ ULONG cchName, // [IN] Size of buffer in wide chars.
+ ULONG *pchName, // [OUT] Actual # of wide chars in name.
+ ASSEMBLYMETADATA *pMetaData, // [OUT] Assembly MetaData.
+ const void **ppbHashValue, // [OUT] Hash blob.
+ ULONG *pcbHashValue, // [OUT] Count of bytes in the hash blob.
+ DWORD *pdwAssemblyRefFlags); // [OUT] Flags.
+
+ STDMETHODIMP GetFileProps ( // S_OK or error.
+ mdFile mdf, // [IN] The File for which to get the properties.
+ __out_ecount (cchName) LPWSTR szName, // [OUT] Buffer to fill with name.
+ ULONG cchName, // [IN] Size of buffer in wide chars.
+ ULONG *pchName, // [OUT] Actual # of wide chars in name.
+ const void **ppbHashValue, // [OUT] Pointer to the Hash Value Blob.
+ ULONG *pcbHashValue, // [OUT] Count of bytes in the Hash Value Blob.
+ DWORD *pdwFileFlags); // [OUT] Flags.
+
+ STDMETHODIMP GetExportedTypeProps ( // S_OK or error.
+ mdExportedType mdct, // [IN] The ExportedType for which to get the properties.
+ __out_ecount (cchName) LPWSTR szName, // [OUT] Buffer to fill with name.
+ ULONG cchName, // [IN] Size of buffer in wide chars.
+ ULONG *pchName, // [OUT] Actual # of wide chars in name.
+ mdToken *ptkImplementation, // [OUT] mdFile or mdAssemblyRef or mdExportedType.
+ mdTypeDef *ptkTypeDef, // [OUT] TypeDef token within the file.
+ DWORD *pdwExportedTypeFlags); // [OUT] Flags.
+
+ STDMETHODIMP GetManifestResourceProps ( // S_OK or error.
+ mdManifestResource mdmr, // [IN] The ManifestResource for which to get the properties.
+ __out_ecount (cchName) LPWSTR szName, // [OUT] Buffer to fill with name.
+ ULONG cchName, // [IN] Size of buffer in wide chars.
+ ULONG *pchName, // [OUT] Actual # of wide chars in name.
+ mdToken *ptkImplementation, // [OUT] mdFile or mdAssemblyRef that provides the ManifestResource.
+ DWORD *pdwOffset, // [OUT] Offset to the beginning of the resource within the file.
+ DWORD *pdwResourceFlags); // [OUT] Flags.
+
+ STDMETHODIMP EnumAssemblyRefs ( // S_OK or error
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdAssemblyRef rAssemblyRefs[], // [OUT] Put AssemblyRefs here.
+ ULONG cMax, // [IN] Max AssemblyRefs to put.
+ ULONG *pcTokens); // [OUT] Put # put here.
+
+ STDMETHODIMP EnumFiles ( // S_OK or error
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdFile rFiles[], // [OUT] Put Files here.
+ ULONG cMax, // [IN] Max Files to put.
+ ULONG *pcTokens); // [OUT] Put # put here.
+
+ STDMETHODIMP EnumExportedTypes ( // S_OK or error
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdExportedType rExportedTypes[], // [OUT] Put ExportedTypes here.
+ ULONG cMax, // [IN] Max ExportedTypes to put.
+ ULONG *pcTokens); // [OUT] Put # put here.
+
+ STDMETHODIMP EnumManifestResources ( // S_OK or error
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdManifestResource rManifestResources[], // [OUT] Put ManifestResources here.
+ ULONG cMax, // [IN] Max Resources to put.
+ ULONG *pcTokens); // [OUT] Put # put here.
+
+ STDMETHODIMP GetAssemblyFromScope ( // S_OK or error
+ mdAssembly *ptkAssembly); // [OUT] Put token here.
+
+ STDMETHODIMP FindExportedTypeByName ( // S_OK or error
+ LPCWSTR szName, // [IN] Name of the ExportedType.
+ mdToken mdtExportedType, // [IN] ExportedType for the enclosing class.
+ mdExportedType *ptkExportedType); // [OUT] Put the ExportedType token here.
+
+ STDMETHODIMP FindManifestResourceByName ( // S_OK or error
+ LPCWSTR szName, // [IN] Name of the ManifestResource.
+ mdManifestResource *ptkManifestResource); // [OUT] Put the ManifestResource token here.
+
+ STDMETHOD_(void, CloseEnum)(
+ HCORENUM hEnum); // Enum to be closed.
+
+ STDMETHODIMP FindAssembliesByName ( // S_OK or error
+ LPCWSTR szAppBase, // [IN] optional - can be NULL
+ LPCWSTR szPrivateBin, // [IN] optional - can be NULL
+ LPCWSTR szAssemblyName, // [IN] required - this is the assembly you are requesting
+ IUnknown *ppIUnk[], // [OUT] put IMetaDataAssemblyImport pointers here
+ ULONG cMax, // [IN] The max number to put
+ ULONG *pcAssemblies); // [OUT] The number of assemblies returned.
+
+ // *** IMetaDataImport methods ***
+ STDMETHOD(CountEnum)(HCORENUM hEnum, ULONG *pulCount);
+ STDMETHOD(ResetEnum)(HCORENUM hEnum, ULONG ulPos);
+ STDMETHOD(EnumTypeDefs)(HCORENUM *phEnum, mdTypeDef rTypeDefs[],
+ ULONG cMax, ULONG *pcTypeDefs);
+ STDMETHOD(EnumInterfaceImpls)(HCORENUM *phEnum, mdTypeDef td,
+ mdInterfaceImpl rImpls[], ULONG cMax,
+ ULONG* pcImpls);
+ STDMETHOD(EnumTypeRefs)(HCORENUM *phEnum, mdTypeRef rTypeRefs[],
+ ULONG cMax, ULONG* pcTypeRefs);
+
+ STDMETHOD(FindTypeDefByName)( // S_OK or error.
+ LPCWSTR szTypeDef, // [IN] Name of the Type.
+ mdToken tkEnclosingClass, // [IN] TypeDef/TypeRef for Enclosing class.
+ mdTypeDef *ptd); // [OUT] Put the TypeDef token here.
+
+ STDMETHOD(GetScopeProps)(
+ __out_ecount_part_opt(cchName, *pchName)
+ LPWSTR wszName, // [OUT] Put the name here.
+ ULONG cchName, // [IN] Size of name buffer in wide chars.
+ ULONG * pchName, // [OUT] Put size of name (wide chars) here.
+ GUID * pMvid); // [OUT, OPTIONAL] Put MVID here.
+
+ STDMETHOD(GetModuleFromScope)( // S_OK.
+ mdModule *pmd); // [OUT] Put mdModule token here.
+
+ STDMETHOD(GetTypeDefProps)(
+ mdTypeDef td, // [IN] TypeDef token for inquiry.
+ __out_ecount_part_opt(cchTypeDef, *pchTypeDef)
+ LPWSTR wszTypeDef, // [OUT] Put name here.
+ ULONG cchTypeDef, // [IN] size of name buffer in wide chars.
+ ULONG * pchTypeDef, // [OUT] put size of name (wide chars) here.
+ DWORD * pdwTypeDefFlags, // [OUT] Put flags here.
+ mdToken * ptkExtends); // [OUT] Put base class TypeDef/TypeRef here.
+
+ STDMETHOD(GetInterfaceImplProps)( // S_OK or error.
+ mdInterfaceImpl iiImpl, // [IN] InterfaceImpl token.
+ mdTypeDef *pClass, // [OUT] Put implementing class token here.
+ mdToken *ptkIface); // [OUT] Put implemented interface token here.
+
+ STDMETHOD(GetTypeRefProps)(
+ mdTypeRef tr, // [IN] TypeRef token.
+ mdToken * ptkResolutionScope, // [OUT] Resolution scope, ModuleRef or AssemblyRef.
+ __out_ecount_part_opt(cchName, *pchName)
+ LPWSTR wszName, // [OUT] Name of the TypeRef.
+ ULONG cchName, // [IN] Size of buffer.
+ ULONG * pchName); // [OUT] Size of Name.
+
+ STDMETHOD(ResolveTypeRef)(mdTypeRef tr, REFIID riid, IUnknown **ppIScope, mdTypeDef *ptd);
+
+ STDMETHOD(EnumMembers)( // S_OK, S_FALSE, or error.
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdTypeDef cl, // [IN] TypeDef to scope the enumeration.
+ mdToken rMembers[], // [OUT] Put MemberDefs here.
+ ULONG cMax, // [IN] Max MemberDefs to put.
+ ULONG *pcTokens); // [OUT] Put # put here.
+
+ STDMETHOD(EnumMembersWithName)( // S_OK, S_FALSE, or error.
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdTypeDef cl, // [IN] TypeDef to scope the enumeration.
+ LPCWSTR szName, // [IN] Limit results to those with this name.
+ mdToken rMembers[], // [OUT] Put MemberDefs here.
+ ULONG cMax, // [IN] Max MemberDefs to put.
+ ULONG *pcTokens); // [OUT] Put # put here.
+
+ STDMETHOD(EnumMethods)( // S_OK, S_FALSE, or error.
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdTypeDef cl, // [IN] TypeDef to scope the enumeration.
+ mdMethodDef rMethods[], // [OUT] Put MethodDefs here.
+ ULONG cMax, // [IN] Max MethodDefs to put.
+ ULONG *pcTokens); // [OUT] Put # put here.
+
+ STDMETHOD(EnumMethodsWithName)( // S_OK, S_FALSE, or error.
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdTypeDef cl, // [IN] TypeDef to scope the enumeration.
+ LPCWSTR szName, // [IN] Limit results to those with this name.
+ mdMethodDef rMethods[], // [OU] Put MethodDefs here.
+ ULONG cMax, // [IN] Max MethodDefs to put.
+ ULONG *pcTokens); // [OUT] Put # put here.
+
+ STDMETHOD(EnumFields)( // S_OK, S_FALSE, or error.
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdTypeDef cl, // [IN] TypeDef to scope the enumeration.
+ mdFieldDef rFields[], // [OUT] Put FieldDefs here.
+ ULONG cMax, // [IN] Max FieldDefs to put.
+ ULONG *pcTokens); // [OUT] Put # put here.
+
+ STDMETHOD(EnumFieldsWithName)( // S_OK, S_FALSE, or error.
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdTypeDef cl, // [IN] TypeDef to scope the enumeration.
+ LPCWSTR szName, // [IN] Limit results to those with this name.
+ mdFieldDef rFields[], // [OUT] Put MemberDefs here.
+ ULONG cMax, // [IN] Max MemberDefs to put.
+ ULONG *pcTokens); // [OUT] Put # put here.
+
+
+ STDMETHOD(EnumParams)( // S_OK, S_FALSE, or error.
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdMethodDef mb, // [IN] MethodDef to scope the enumeration.
+ mdParamDef rParams[], // [OUT] Put ParamDefs here.
+ ULONG cMax, // [IN] Max ParamDefs to put.
+ ULONG *pcTokens); // [OUT] Put # put here.
+
+ STDMETHOD(EnumMemberRefs)( // S_OK, S_FALSE, or error.
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdToken tkParent, // [IN] Parent token to scope the enumeration.
+ mdMemberRef rMemberRefs[], // [OUT] Put MemberRefs here.
+ ULONG cMax, // [IN] Max MemberRefs to put.
+ ULONG *pcTokens); // [OUT] Put # put here.
+
+ STDMETHOD(EnumMethodImpls)( // S_OK, S_FALSE, or error
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdTypeDef td, // [IN] TypeDef to scope the enumeration.
+ mdToken rMethodBody[], // [OUT] Put Method Body tokens here.
+ mdToken rMethodDecl[], // [OUT] Put Method Declaration tokens here.
+ ULONG cMax, // [IN] Max tokens to put.
+ ULONG *pcTokens); // [OUT] Put # put here.
+
+ STDMETHOD(EnumPermissionSets)( // S_OK, S_FALSE, or error.
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdToken tk, // [IN] if !NIL, token to scope the enumeration.
+ DWORD dwActions, // [IN] if !0, return only these actions.
+ mdPermission rPermission[], // [OUT] Put Permissions here.
+ ULONG cMax, // [IN] Max Permissions to put.
+ ULONG *pcTokens); // [OUT] Put # put here.
+
+ STDMETHOD(FindMember)(
+ mdTypeDef td, // [IN] given typedef
+ LPCWSTR szName, // [IN] member name
+ PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of COM+ signature
+ ULONG cbSigBlob, // [IN] count of bytes in the signature blob
+ mdToken *pmb); // [OUT] matching memberdef
+
+ STDMETHOD(FindMethod)(
+ mdTypeDef td, // [IN] given typedef
+ LPCWSTR szName, // [IN] member name
+ PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of COM+ signature
+ ULONG cbSigBlob, // [IN] count of bytes in the signature blob
+ mdMethodDef *pmb); // [OUT] matching memberdef
+
+ STDMETHOD(FindField)(
+ mdTypeDef td, // [IN] given typedef
+ LPCWSTR szName, // [IN] member name
+ PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of COM+ signature
+ ULONG cbSigBlob, // [IN] count of bytes in the signature blob
+ mdFieldDef *pmb); // [OUT] matching memberdef
+
+ STDMETHOD(FindMemberRef)(
+ mdTypeRef td, // [IN] given typeRef
+ LPCWSTR szName, // [IN] member name
+ PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of COM+ signature
+ ULONG cbSigBlob, // [IN] count of bytes in the signature blob
+ mdMemberRef *pmr); // [OUT] matching memberref
+
+ STDMETHOD (GetMethodProps)(
+ mdMethodDef mb, // The method for which to get props.
+ mdTypeDef * pClass, // Put method's class here.
+ __out_ecount_part_opt(cchMethod, *pchMethod)
+ LPWSTR wszMethod, // Put method's name here.
+ ULONG cchMethod, // Size of szMethod buffer in wide chars.
+ ULONG * pchMethod, // Put actual size here.
+ DWORD * pdwAttr, // Put flags here.
+ PCCOR_SIGNATURE * ppvSigBlob, // [OUT] point to the blob value of meta data
+ ULONG * pcbSigBlob, // [OUT] actual size of signature blob
+ ULONG * pulCodeRVA, // [OUT] codeRVA
+ DWORD * pdwImplFlags); // [OUT] Impl. Flags
+
+ STDMETHOD(GetMemberRefProps)(
+ mdMemberRef mr, // [IN] given memberref
+ mdToken * ptk, // [OUT] Put classref or classdef here.
+ __out_ecount_part_opt(cchMember, *pchMember)
+ LPWSTR wszMember, // [OUT] buffer to fill for member's name
+ ULONG cchMember, // [IN] the count of char of szMember
+ ULONG * pchMember, // [OUT] actual count of char in member name
+ PCCOR_SIGNATURE * ppvSigBlob, // [OUT] point to meta data blob value
+ ULONG * pbSig); // [OUT] actual size of signature blob
+
+ STDMETHOD(EnumProperties)( // S_OK, S_FALSE, or error.
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdTypeDef td, // [IN] TypeDef to scope the enumeration.
+ mdProperty rProperties[], // [OUT] Put Properties here.
+ ULONG cMax, // [IN] Max properties to put.
+ ULONG *pcProperties); // [OUT] Put # put here.
+
+ STDMETHOD(EnumEvents)( // S_OK, S_FALSE, or error.
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdTypeDef td, // [IN] TypeDef to scope the enumeration.
+ mdEvent rEvents[], // [OUT] Put events here.
+ ULONG cMax, // [IN] Max events to put.
+ ULONG *pcEvents); // [OUT] Put # put here.
+
+ STDMETHOD(GetEventProps)( // S_OK, S_FALSE, or error.
+ mdEvent ev, // [IN] event token
+ mdTypeDef *pClass, // [OUT] typedef containing the event declarion.
+ LPCWSTR szEvent, // [OUT] Event name
+ ULONG cchEvent, // [IN] the count of wchar of szEvent
+ ULONG *pchEvent, // [OUT] actual count of wchar for event's name
+ DWORD *pdwEventFlags, // [OUT] Event flags.
+ mdToken *ptkEventType, // [OUT] EventType class
+ mdMethodDef *pmdAddOn, // [OUT] AddOn method of the event
+ mdMethodDef *pmdRemoveOn, // [OUT] RemoveOn method of the event
+ mdMethodDef *pmdFire, // [OUT] Fire method of the event
+ mdMethodDef rmdOtherMethod[], // [OUT] other method of the event
+ ULONG cMax, // [IN] size of rmdOtherMethod
+ ULONG *pcOtherMethod); // [OUT] total number of other method of this event
+
+ STDMETHOD(EnumMethodSemantics)( // S_OK, S_FALSE, or error.
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdMethodDef mb, // [IN] MethodDef to scope the enumeration.
+ mdToken rEventProp[], // [OUT] Put Event/Property here.
+ ULONG cMax, // [IN] Max properties to put.
+ ULONG *pcEventProp); // [OUT] Put # put here.
+
+ STDMETHOD(GetMethodSemantics)( // S_OK, S_FALSE, or error.
+ mdMethodDef mb, // [IN] method token
+ mdToken tkEventProp, // [IN] event/property token.
+ DWORD *pdwSemanticsFlags); // [OUT] the role flags for the method/propevent pair
+
+ STDMETHOD(GetClassLayout) (
+ mdTypeDef td, // [IN] give typedef
+ DWORD *pdwPackSize, // [OUT] 1, 2, 4, 8, or 16
+ COR_FIELD_OFFSET rFieldOffset[], // [OUT] field offset array
+ ULONG cMax, // [IN] size of the array
+ ULONG *pcFieldOffset, // [OUT] needed array size
+ ULONG *pulClassSize); // [OUT] the size of the class
+
+ STDMETHOD(GetFieldMarshal) (
+ mdToken tk, // [IN] given a field's memberdef
+ PCCOR_SIGNATURE *ppvNativeType, // [OUT] native type of this field
+ ULONG *pcbNativeType); // [OUT] the count of bytes of *ppvNativeType
+
+ STDMETHOD(GetRVA)( // S_OK or error.
+ mdToken tk, // Member for which to set offset
+ ULONG *pulCodeRVA, // The offset
+ DWORD *pdwImplFlags); // the implementation flags
+
+ STDMETHOD(GetPermissionSetProps) (
+ mdPermission pm, // [IN] the permission token.
+ DWORD *pdwAction, // [OUT] CorDeclSecurity.
+ void const **ppvPermission, // [OUT] permission blob.
+ ULONG *pcbPermission); // [OUT] count of bytes of pvPermission.
+
+ STDMETHOD(GetSigFromToken)( // S_OK or error.
+ mdSignature mdSig, // [IN] Signature token.
+ PCCOR_SIGNATURE *ppvSig, // [OUT] return pointer to token.
+ ULONG *pcbSig); // [OUT] return size of signature.
+
+ STDMETHOD(GetModuleRefProps)(
+ mdModuleRef mur, // [IN] moduleref token.
+ __out_ecount_part_opt(cchName, *pchName)
+ LPWSTR wszName, // [OUT] buffer to fill with the moduleref name.
+ ULONG cchName, // [IN] size of szName in wide characters.
+ ULONG * pchName); // [OUT] actual count of characters in the name.
+
+ STDMETHOD(EnumModuleRefs)( // S_OK or error.
+ HCORENUM *phEnum, // [IN|OUT] pointer to the enum.
+ mdModuleRef rModuleRefs[], // [OUT] put modulerefs here.
+ ULONG cmax, // [IN] max memberrefs to put.
+ ULONG *pcModuleRefs); // [OUT] put # put here.
+
+ STDMETHOD(GetTypeSpecFromToken)( // S_OK or error.
+ mdTypeSpec typespec, // [IN] TypeSpec token.
+ PCCOR_SIGNATURE *ppvSig, // [OUT] return pointer to TypeSpec signature
+ ULONG *pcbSig); // [OUT] return size of signature.
+
+ STDMETHOD(GetNameFromToken)( // <TODO>Not Recommended! May be removed!</TODO>
+ mdToken tk, // [IN] Token to get name from. Must have a name.
+ MDUTF8CSTR *pszUtf8NamePtr); // [OUT] Return pointer to UTF8 name in heap.
+
+ STDMETHOD(EnumUnresolvedMethods)( // S_OK, S_FALSE, or error.
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdToken rMethods[], // [OUT] Put MemberDefs here.
+ ULONG cMax, // [IN] Max MemberDefs to put.
+ ULONG *pcTokens); // [OUT] Put # put here.
+
+ STDMETHOD(GetUserString)(
+ mdString stk, // [IN] String token.
+ __out_ecount_part_opt(cchString, *pchString)
+ LPWSTR wszString, // [OUT] Copy of string.
+ ULONG cchString, // [IN] Max chars of room in szString.
+ ULONG * pchString); // [OUT] How many chars in actual string.
+
+ STDMETHOD(GetPinvokeMap)(
+ mdToken tk, // [IN] FieldDef or MethodDef.
+ DWORD * pdwMappingFlags, // [OUT] Flags used for mapping.
+ __out_ecount_part_opt(cchImportName, *pchImportName)
+ LPWSTR wszImportName, // [OUT] Import name.
+ ULONG cchImportName, // [IN] Size of the name buffer.
+ ULONG * pchImportName, // [OUT] Actual number of characters stored.
+ mdModuleRef * pmrImportDLL); // [OUT] ModuleRef token for the target DLL.
+
+ STDMETHOD(EnumSignatures)( // S_OK or error.
+ HCORENUM *phEnum, // [IN|OUT] pointer to the enum.
+ mdSignature rSignatures[], // [OUT] put signatures here.
+ ULONG cmax, // [IN] max signatures to put.
+ ULONG *pcSignatures); // [OUT] put # put here.
+
+ STDMETHOD(EnumTypeSpecs)( // S_OK or error.
+ HCORENUM *phEnum, // [IN|OUT] pointer to the enum.
+ mdTypeSpec rTypeSpecs[], // [OUT] put TypeSpecs here.
+ ULONG cmax, // [IN] max TypeSpecs to put.
+ ULONG *pcTypeSpecs); // [OUT] put # put here.
+
+ STDMETHOD(EnumUserStrings)( // S_OK or error.
+ HCORENUM *phEnum, // [IN/OUT] pointer to the enum.
+ mdString rStrings[], // [OUT] put Strings here.
+ ULONG cmax, // [IN] max Strings to put.
+ ULONG *pcStrings); // [OUT] put # put here.
+
+ STDMETHOD(GetParamForMethodIndex)( // S_OK or error.
+ mdMethodDef md, // [IN] Method token.
+ ULONG ulParamSeq, // [IN] Parameter sequence.
+ mdParamDef *ppd); // [IN] Put Param token here.
+
+ STDMETHOD(EnumCustomAttributes)( // S_OK or error.
+ HCORENUM *phEnum, // [IN, OUT] COR enumerator.
+ mdToken tk, // [IN] Token to scope the enumeration, 0 for all.
+ mdToken tkType, // [IN] Type of interest, 0 for all.
+ mdCustomAttribute rCustomAttributes[], // [OUT] Put custom attribute tokens here.
+ ULONG cMax, // [IN] Size of rCustomAttributes.
+ ULONG *pcCustomAttributes); // [OUT, OPTIONAL] Put count of token values here.
+
+ STDMETHOD(GetCustomAttributeProps)( // S_OK or error.
+ mdCustomAttribute cv, // [IN] CustomAttribute token.
+ mdToken *ptkObj, // [OUT, OPTIONAL] Put object token here.
+ mdToken *ptkType, // [OUT, OPTIONAL] Put AttrType token here.
+ void const **ppBlob, // [OUT, OPTIONAL] Put pointer to data here.
+ ULONG *pcbSize); // [OUT, OPTIONAL] Put size of date here.
+
+ STDMETHOD(FindTypeRef)(
+ mdToken tkResolutionScope, // [IN] ModuleRef, AssemblyRef or TypeRef.
+ LPCWSTR szName, // [IN] TypeRef Name.
+ mdTypeRef *ptr); // [OUT] matching TypeRef.
+
+ STDMETHOD(GetMemberProps)(
+ mdToken mb, // The member for which to get props.
+ mdTypeDef * pClass, // Put member's class here.
+ __out_ecount_part_opt(cchMember, *pchMember)
+ LPWSTR wszMember, // Put member's name here.
+ ULONG cchMember, // Size of szMember buffer in wide chars.
+ ULONG * pchMember, // Put actual size here
+ DWORD * pdwAttr, // Put flags here.
+ PCCOR_SIGNATURE * ppvSigBlob, // [OUT] point to the blob value of meta data
+ ULONG * pcbSigBlob, // [OUT] actual size of signature blob
+ ULONG * pulCodeRVA, // [OUT] codeRVA
+ DWORD * pdwImplFlags, // [OUT] Impl. Flags
+ DWORD * pdwCPlusTypeFlag, // [OUT] flag for value type. selected ELEMENT_TYPE_*
+ UVCP_CONSTANT * ppValue, // [OUT] constant value
+ ULONG * pcchValue); // [OUT] size of constant string in chars, 0 for non-strings.
+
+ STDMETHOD(GetFieldProps)(
+ mdFieldDef mb, // The field for which to get props.
+ mdTypeDef * pClass, // Put field's class here.
+ __out_ecount_part_opt(cchField, *pchField)
+ LPWSTR szField, // Put field's name here.
+ ULONG cchField, // Size of szField buffer in wide chars.
+ ULONG * pchField, // Put actual size here.
+ DWORD * pdwAttr, // Put flags here.
+ PCCOR_SIGNATURE * ppvSigBlob, // [OUT] point to the blob value of meta data.
+ ULONG * pcbSigBlob, // [OUT] actual size of signature blob.
+ DWORD * pdwCPlusTypeFlag, // [OUT] flag for value type. selected ELEMENT_TYPE_*.
+ UVCP_CONSTANT * ppValue, // [OUT] constant value.
+ ULONG * pcchValue); // [OUT] size of constant string in chars, 0 for non-strings.
+
+ STDMETHOD(GetPropertyProps)( // S_OK, S_FALSE, or error.
+ mdProperty prop, // [IN] property token
+ mdTypeDef *pClass, // [OUT] typedef containing the property declarion.
+ LPCWSTR szProperty, // [OUT] Property name
+ ULONG cchProperty, // [IN] the count of wchar of szProperty
+ ULONG *pchProperty, // [OUT] actual count of wchar for property name
+ DWORD *pdwPropFlags, // [OUT] property flags.
+ PCCOR_SIGNATURE *ppvSig, // [OUT] property type. pointing to meta data internal blob
+ ULONG *pbSig, // [OUT] count of bytes in *ppvSig
+ DWORD *pdwCPlusTypeFlag, // [OUT] flag for value type. selected ELEMENT_TYPE_*
+ UVCP_CONSTANT *ppDefaultValue, // [OUT] constant value
+ ULONG *pcchDefaultValue, // [OUT] size of constant string in chars, 0 for non-strings.
+ mdMethodDef *pmdSetter, // [OUT] setter method of the property
+ mdMethodDef *pmdGetter, // [OUT] getter method of the property
+ mdMethodDef rmdOtherMethod[], // [OUT] other method of the property
+ ULONG cMax, // [IN] size of rmdOtherMethod
+ ULONG *pcOtherMethod); // [OUT] total number of other method of this property
+
+ STDMETHOD(GetParamProps)(
+ mdParamDef tk, // [IN]The Parameter.
+ mdMethodDef * pmd, // [OUT] Parent Method token.
+ ULONG * pulSequence, // [OUT] Parameter sequence.
+ __out_ecount_part_opt(cchName, *pchName)
+ LPWSTR wszName, // [OUT] Put name here.
+ ULONG cchName, // [OUT] Size of name buffer.
+ ULONG * pchName, // [OUT] Put actual size of name here.
+ DWORD * pdwAttr, // [OUT] Put flags here.
+ DWORD * pdwCPlusTypeFlag, // [OUT] Flag for value type. selected ELEMENT_TYPE_*.
+ UVCP_CONSTANT * ppValue, // [OUT] Constant value.
+ ULONG * pcchValue); // [OUT] size of constant string in chars, 0 for non-strings.
+
+ STDMETHOD(GetCustomAttributeByName)( // S_OK or error.
+ mdToken tkObj, // [IN] Object with Custom Attribute.
+ LPCWSTR szName, // [IN] Name of desired Custom Attribute.
+ const void **ppData, // [OUT] Put pointer to data here.
+ ULONG *pcbData); // [OUT] Put size of data here.
+
+ STDMETHOD_(BOOL, IsValidToken)( // True or False.
+ mdToken tk); // [IN] Given token.
+
+ STDMETHOD(GetNestedClassProps)( // S_OK or error.
+ mdTypeDef tdNestedClass, // [IN] NestedClass token.
+ mdTypeDef *ptdEnclosingClass); // [OUT] EnclosingClass token.
+
+ STDMETHOD(GetNativeCallConvFromSig)( // S_OK or error.
+ void const *pvSig, // [IN] Pointer to signature.
+ ULONG cbSig, // [IN] Count of signature bytes.
+ ULONG *pCallConv); // [OUT] Put calling conv here (see CorPinvokemap).
+
+ STDMETHOD(IsGlobal)( // S_OK or error.
+ mdToken pd, // [IN] Type, Field, or Method token.
+ int *pbGlobal); // [OUT] Put 1 if global, 0 otherwise.
+
+//*****************************************************************************
+// IMetaDataImport2 methods
+//*****************************************************************************
+ STDMETHOD(GetMethodSpecProps)(
+ mdMethodSpec mi, // [IN] The method instantiation
+ mdToken *tkParent, // [OUT] MethodDef or MemberRef
+ PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to the blob value of meta data
+ ULONG *pcbSigBlob); // [OUT] actual size of signature blob
+
+ STDMETHOD(GetGenericParamProps)(
+ mdGenericParam gp, // [IN] GenericParam
+ ULONG * pulParamSeq, // [OUT] Index of the type parameter
+ DWORD * pdwParamFlags, // [OUT] Flags, for future use (e.g. variance)
+ mdToken * ptOwner, // [OUT] Owner (TypeDef or MethodDef)
+ DWORD * pdwReserved, // [OUT] For future use (e.g. non-type parameters)
+ __out_ecount_part_opt(cchName, *pchName)
+ LPWSTR wszName, // [OUT] Put name here
+ ULONG cchName, // [IN] Size of buffer
+ ULONG * pchName); // [OUT] Put size of name (wide chars) here.
+
+ STDMETHOD(GetGenericParamConstraintProps)( // S_OK or error.
+ mdGenericParamConstraint gpc, // [IN] GenericParamConstraint
+ mdGenericParam *ptGenericParam, // [OUT] GenericParam that is constrained
+ mdToken *ptkConstraintType); // [OUT] TypeDef/Ref/Spec constraint
+
+ STDMETHOD(EnumGenericParams)( // S_OK or error.
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdToken tk, // [IN] TypeDef or MethodDef whose generic parameters are requested
+ mdGenericParam rGenericParams[], // [OUT] Put GenericParams here.
+ ULONG cMax, // [IN] Max GenericParams to put.
+ ULONG *pcGenericParams); // [OUT] Put # put here.
+
+ STDMETHOD(EnumGenericParamConstraints)( // S_OK or error.
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdGenericParam tk, // [IN] GenericParam whose constraints are requested
+ mdGenericParamConstraint rGenericParamConstraints[], // [OUT] Put GenericParamConstraints here.
+ ULONG cMax, // [IN] Max GenericParamConstraints to put.
+ ULONG *pcGenericParamConstraints); // [OUT] Put # put here.
+
+ STDMETHOD(EnumMethodSpecs)(
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdToken tk, // [IN] MethodDef or MemberRef whose MethodSpecs are requested
+ mdMethodSpec rMethodSpecs[], // [OUT] Put MethodSpecs here.
+ ULONG cMax, // [IN] Max tokens to put.
+ ULONG *pcMethodSpecs); // [OUT] Put actual count here.
+
+ STDMETHOD(GetPEKind)( // S_OK or error.
+ DWORD* pdwPEKind, // [OUT] The kind of PE (0 - not a PE)
+ DWORD* pdwMachine); // [OUT] Machine as defined in NT header
+
+ STDMETHOD(GetVersionString)(
+ __out_ecount_part_opt(ccBufSize, *pccBufSize)
+ LPWSTR pwzBuf, // Put version string here.
+ DWORD ccBufSize, // [in] Size of the buffer, in wide chars.
+ DWORD * pccBufSize); // [out] Size of the version string, wide chars, including terminating nul.
+
+
+ // *** ISNAssemblySignature methods ***
+
+ STDMETHOD(GetSNAssemblySignature)( // S_OK or error.
+ BYTE *pbSig, // [IN, OUT] Buffer to write signature
+ DWORD *pcbSig); // [IN, OUT] Size of buffer, bytes written
+
+
+#ifdef FEATURE_PREJIT
+ // *** IGetIMDInternalImport methods ***
+
+ STDMETHOD(GetIMDInternalImport) (
+ IMDInternalImport ** ppIMDInternalImport);
+
+ // *** INativeImageInstallInfo ***
+
+ STDMETHOD (GetSignature) (
+ CORCOMPILE_NGEN_SIGNATURE * pNgenSign
+ );
+
+ STDMETHOD (GetVersionInfo) (
+ CORCOMPILE_VERSION_INFO * pVersionInfo
+ );
+
+
+ STDMETHOD (GetILSignature) (
+ CORCOMPILE_ASSEMBLY_SIGNATURE * pILSign
+ );
+
+ STDMETHOD (GetConfigMask) (
+ DWORD * pConfigMask
+ );
+
+ STDMETHOD (EnumDependencies) (
+ HCORENUM * phEnum,
+ INativeImageDependency *rDeps[],
+ ULONG cMax,
+ DWORD * pdwCount
+ );
+
+ STDMETHOD (GetDependency) (
+ const CORCOMPILE_NGEN_SIGNATURE *pcngenSign,
+ CORCOMPILE_DEPENDENCY *pDep
+ );
+
+
+#endif // FEATURE_PREJIT
+
+ //------------ setters for privates -----------
+ void SetHandle(HCORMODULE hHandle)
+ {
+ RuntimeAddRefHandle(hHandle);
+ m_pHandle = hHandle;
+ }
+
+ void SetPEKind(DWORD dwPEKind)
+ {
+ m_dwPEKind = dwPEKind;
+ }
+
+ void SetMachine(DWORD dwMachine)
+ {
+ m_dwMachine = dwMachine;
+ }
+
+ void SetVersionString(const char* szVersionString)
+ {
+ m_szVersionString = szVersionString;
+ }
+
+ void SetBase(LPVOID base)
+ {
+ m_pBase = base;
+ }
+
+#ifdef FEATURE_PREJIT
+ void SetZapVersionInfo(CORCOMPILE_VERSION_INFO * info, CORCOMPILE_DEPENDENCY * pDeps, COUNT_T cDeps)
+ {
+ m_pZapVersionInfo = info;
+ m_pZapDependencies = pDeps;
+ m_cZapDependencies = cDeps;
+ }
+#endif // FEATURE_PREJIT
+
+private:
+ LONG m_cRef;
+ HCORMODULE m_pHandle; // Handle to a cached PE image
+ LPVOID m_pBase; // File mapping (if runtime is not inited)
+#ifdef FEATURE_PREJIT
+ struct CORCOMPILE_VERSION_INFO * m_pZapVersionInfo; // Zap image information
+ struct CORCOMPILE_DEPENDENCY * m_pZapDependencies; // Zap Dependancies directory
+ COUNT_T m_cZapDependencies;
+#endif // FEATURE_PREJIT
+ IMDInternalImport * m_pMDInternalImport;
+ DWORD m_dwPEKind;
+ DWORD m_dwMachine;
+ const char * m_szVersionString;
+#ifdef _DEBUG
+ IMetaDataAssemblyImport * m_pDebugMDImport;
+#endif //_DEBUG
+};
+
+#endif // FEATURE_FUSION
+
+#endif // __AssemblyMDInternalDispenser__h__
diff --git a/src/md/inc/cahlprinternal.h b/src/md/inc/cahlprinternal.h
new file mode 100644
index 0000000000..c4ae18b0f9
--- /dev/null
+++ b/src/md/inc/cahlprinternal.h
@@ -0,0 +1,94 @@
+// 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.
+
+//
+
+#ifndef __CAHLPR_H__
+#define __CAHLPR_H__
+
+#include "sarray.h"
+#include "caparser.h"
+
+//*****************************************************************************
+// This class assists in the parsing of CustomAttribute blobs.
+//*****************************************************************************
+struct CaType
+{
+ void Init(CorSerializationType _type)
+ {
+ _ASSERTE(_type != SERIALIZATION_TYPE_SZARRAY && _type != SERIALIZATION_TYPE_ENUM);
+ tag = _type;
+ arrayType = SERIALIZATION_TYPE_UNDEFINED;
+ enumType = SERIALIZATION_TYPE_UNDEFINED;
+ szEnumName = NULL;
+ cEnumName = 0;
+ }
+
+ void Init(CorSerializationType _type, CorSerializationType _arrayType, CorSerializationType _enumType, LPCSTR _szEnumName, ULONG _cEnumName)
+ {
+ tag = _type;
+ arrayType = _arrayType;
+ enumType = _enumType;
+ szEnumName = _szEnumName;
+ cEnumName = _cEnumName;
+ }
+
+ CorSerializationType tag;
+ CorSerializationType arrayType;
+ CorSerializationType enumType;
+ LPCSTR szEnumName;
+ ULONG cEnumName;
+};
+
+struct CaTypeCtor : public CaType
+{
+ CaTypeCtor(CorSerializationType _type)
+ {
+ Init(_type);
+ }
+
+ CaTypeCtor(CorSerializationType _type, CorSerializationType _arrayType, CorSerializationType _enumType, LPCSTR _szEnumName, ULONG _cEnumName)
+ {
+ Init(_type, _arrayType, _enumType, _szEnumName, _cEnumName);
+ }
+};
+
+typedef struct CaValue
+{
+ union
+ {
+ unsigned __int8 boolean;
+ signed __int8 i1;
+ unsigned __int8 u1;
+ signed __int16 i2;
+ unsigned __int16 u2;
+ signed __int32 i4;
+ unsigned __int32 u4;
+ signed __int64 i8;
+ unsigned __int64 u8;
+ float r4;
+ double r8;
+
+ struct
+ {
+ CorSerializationType tag;
+ SArray<CaValue>* pSArray;
+ ULONG length;
+ inline CaValue &operator[](int index) { return (*pSArray)[index]; }
+ } arr;
+
+ struct
+ {
+ LPCUTF8 pStr;
+ ULONG cbStr;
+ } str;
+ };
+
+ CaType type;
+
+} CaValue;
+
+
+
+#endif // __CAHLPR_H__
diff --git a/src/md/inc/imptlb.h b/src/md/inc/imptlb.h
new file mode 100644
index 0000000000..ba2981a415
--- /dev/null
+++ b/src/md/inc/imptlb.h
@@ -0,0 +1,777 @@
+// 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.
+//*****************************************************************************
+// File: imptlb.h
+//
+
+//
+// TypeLib importer.
+//*****************************************************************************
+#ifndef __imptlb_h__
+#define __imptlb_h__
+
+#ifndef FEATURE_COMINTEROP
+#error FEATURE_COMINTEROP is required for this file
+#endif // FEATURE_COMINTEROP
+#ifndef FEATURE_COMINTEROP_TLB_SUPPORT
+#error FEATURE_COMINTEROP_TLB_SUPPORT is required for this file
+#endif // FEATURE_COMINTEROP_TLB_SUPPORT
+
+//#define TLB_STATS
+
+#define MAX_TLB_VT VT_LPWSTR + 1
+#define MAX_INIT_SIG 3
+#define MAX_COM_GUID_SIG 6
+#define MAX_COM_ADDLISTENER_SIG 8
+#define MAX_COM_REMOVELISTENER_SIG 8
+#define CB_MAX_ELEMENT_TYPE 4
+
+// Forward declarations.
+struct ITypeLibImporterNotifySink;
+class Assembly;
+class Module;
+class CImportTlb;
+
+//*****************************************************************************
+// Class to perform memory management. Memory is not moved as the heap is
+// expanded, and all of the allocations are cleaned up in the destructor.
+//*****************************************************************************
+class CWCHARPool : public StgPool
+{
+public:
+ CWCHARPool() : StgPool()
+ {
+ HRESULT hr = InitNew();
+ _ASSERTE(hr == S_OK);
+ }
+
+ // Allocate some bytes from the pool.
+ WCHAR * Alloc(ULONG nChars)
+ {
+ BYTE *pRslt;
+ // Convert from characters to bytes.
+ nChars *= sizeof(WCHAR);
+ if (nChars > GetCbSegAvailable())
+ if (!Grow(nChars))
+ return 0;
+ pRslt = GetNextLocation();
+ SegAllocate(nChars);
+ return (WCHAR*)pRslt;
+ }
+}; // class CDescPool : public StgPool
+
+
+//*****************************************************************************
+// This helper method is used to track an url to typeref token. This makes
+// defining new typerefs faster.
+//*****************************************************************************
+class CImpTlbTypeRef
+{
+public:
+ CImpTlbTypeRef() { }
+ ~CImpTlbTypeRef() { m_Map.Clear(); }
+
+ //*****************************************************************************
+ // Look for an existing typeref in the map and return if found. If not found,
+ // then create a new one and add it to the map for later.
+ //*****************************************************************************
+ HRESULT DefineTypeRef( // S_OK or error.
+ IMetaDataEmit *pEmit, // Emit interface.
+ mdAssemblyRef ar, // Containing assembly.
+ const LPCWSTR szURL, // URL of the TypeDef, wide chars.
+ mdTypeRef *ptr); // Put mdTypeRef here
+
+ class TokenOfTypeRefHashKey
+ {
+ public:
+ mdToken tkResolutionScope; // TypeRef's resolution scope.
+ LPCWSTR szName; // TypeRef's name.
+ mdTypeRef tr; // The TypeRef's token.
+ };
+
+private:
+
+ class CTokenOfTypeRefHash : public CClosedHash<class TokenOfTypeRefHashKey>
+ {
+ public:
+ typedef CClosedHash<class TokenOfTypeRefHashKey> Super;
+ typedef TokenOfTypeRefHashKey T;
+
+ CTokenOfTypeRefHash() : CClosedHash<class TokenOfTypeRefHashKey>(101) {}
+ ~CTokenOfTypeRefHash() { Clear(); }
+
+ virtual void Clear();
+
+ unsigned int Hash(const void *pData) {return Hash((const T*)pData);}
+ unsigned int Hash(const T *pData);
+
+ unsigned int Compare(const void *p1, BYTE *p2) {return Compare((const T*)p1, (T*)p2);}
+ unsigned int Compare(const T *p1, T *p2);
+
+ ELEMENTSTATUS Status(BYTE *p) {return Status((T*)p);}
+ ELEMENTSTATUS Status(T *p);
+
+ void SetStatus(BYTE *p, ELEMENTSTATUS s) {SetStatus((T*)p, s);}
+ void SetStatus(T *p, ELEMENTSTATUS s);
+
+ void* GetKey(BYTE *p) {return GetKey((T*)p);}
+ void *GetKey(T *p);
+
+ T* Add(const T *pData);
+
+ CWCHARPool m_Names; // Heap of names.
+ };
+
+ CTokenOfTypeRefHash m_Map; // Map of namespace to token.
+};
+
+
+//*****************************************************************************
+// This helper class is used to track source interface ITypeInfo*'s to event
+// information.
+//*****************************************************************************
+class ImpTlbEventInfo
+{
+public:
+ LPCWSTR szSrcItfName; // The source interface name (the key).
+ mdTypeRef trEventItf; // The event interface typedef.
+ LPCWSTR szEventItfName; // The event interface name.
+ LPCWSTR szEventProviderName; // The event provider name.
+ Assembly* SrcItfAssembly; // The assembly where source interface resides.
+};
+
+class CImpTlbEventInfoMap : protected CClosedHash<class ImpTlbEventInfo>
+{
+public:
+ typedef CClosedHash<class ImpTlbEventInfo> Super;
+ typedef ImpTlbEventInfo T;
+
+ CImpTlbEventInfoMap() : CClosedHash<class ImpTlbEventInfo>(101) {}
+ ~CImpTlbEventInfoMap() { Clear(); }
+
+ HRESULT AddEventInfo(LPCWSTR szSrcItfName, mdTypeRef trEventItf, LPCWSTR szEventItfName, LPCWSTR szEventProviderName, Assembly* SrcItfAssembly);
+ ImpTlbEventInfo *FindEventInfo(LPCWSTR szSrcItfName);
+
+ HRESULT GetEventInfoList(CQuickArray<ImpTlbEventInfo*> &qbEvInfoList);
+
+private:
+ unsigned int Hash(const void *pData) {return Hash((const T*)pData);}
+ unsigned int Hash(const T *pData);
+
+ unsigned int Compare(const void *p1, BYTE *p2) {return Compare((const T*)p1, (T*)p2);}
+ unsigned int Compare(const T *p1, T *p2);
+
+ ELEMENTSTATUS Status(BYTE *p) {return Status((T*)p);}
+ ELEMENTSTATUS Status(T *p);
+
+ void SetStatus(BYTE *p, ELEMENTSTATUS s) {SetStatus((T*)p, s);}
+ void SetStatus(T *p, ELEMENTSTATUS s);
+
+ void* GetKey(BYTE *p) {return GetKey((T*)p);}
+ void *GetKey(T *p);
+
+ T* Add(const T *pData);
+
+ CWCHARPool m_Names; // Heap of names.
+};
+
+
+#if defined(_UNICODE) || defined(UNICODE)
+#define _tHashString(szStr) HashString(szStr)
+#else
+#define _tHashString(szStr) HashStringA(szStr)
+#endif
+
+
+
+//*****************************************************************************
+// This helper template is used by the TStringMap to track an item by its
+// character name.
+//*****************************************************************************
+template <class T> class TStringMapItem : HASHENTRY
+{
+public:
+ TStringMapItem() :
+ m_szString(0)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+ ~TStringMapItem()
+ {
+ LIMITED_METHOD_CONTRACT;
+ delete [] m_szString;
+ }
+
+ HRESULT SetString(LPCTSTR szValue)
+ {
+ WRAPPER_NO_CONTRACT;
+ int iLen = (int)(::_tcslen(szValue) + 1);
+ if ((m_szString = new TCHAR[iLen]) == 0)
+ return (OutOfMemory());
+ ::_tcscpy_s((TCHAR*)m_szString, iLen, szValue);
+ return (S_OK);
+ }
+
+public:
+ LPTSTR m_szString; // Key data.
+ T m_value; // Value for this key.
+};
+
+
+//*****************************************************************************
+// IMPORTANT: This data structure is deprecated, please do not add any new uses.
+// The hashtable implementation that should be used instead is code:SHash.
+// If code:SHash does not work for you, talk to mailto:clrdeag.
+//*****************************************************************************
+// This template provides a map from string to item, determined by the template
+// type passed in.
+//*****************************************************************************
+template <class T, int iBuckets=17, class TAllocator=CNewData, int iMaxSize=4096>
+class TStringMap :
+ protected CHashTableAndData<TAllocator>
+{
+ typedef CHashTableAndData<TAllocator> Super;
+
+public:
+ typedef TStringMapItem<T> TItemType;
+ typedef TStringMapItem<long> TOffsetType;
+
+#ifndef DACCESS_COMPILE
+
+ TStringMap() :
+ CHashTableAndData<TAllocator>(iBuckets)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+//*****************************************************************************
+// This is the second part of construction where we do all of the work that
+// can fail. We also take the array of structs here because the calling class
+// presumably needs to allocate it in its NewInit.
+//*****************************************************************************
+ HRESULT NewInit() // Return status.
+ {
+ WRAPPER_NO_CONTRACT;
+ return (CHashTableAndData<TAllocator>::NewInit(
+ CNewData::GrowSize(0)/sizeof(TItemType),
+ sizeof(TItemType),
+ iMaxSize));
+ }
+
+//*****************************************************************************
+// For each item still allocated, invoke its dtor so it frees up anything it
+// holds onto.
+//*****************************************************************************
+ void Clear()
+ {
+ WRAPPER_NO_CONTRACT;
+ HASHFIND sSrch;
+ TItemType *p = (TItemType *) FindFirstEntry(&sSrch);
+
+ while (p != 0)
+ {
+ // Call dtor on the item, since m_value is contained the scalar
+ // dtor will get called.
+ p->~TStringMapItem<T>();
+ p = (TItemType *) FindNextEntry(&sSrch);
+ }
+ CHashTableAndData<TAllocator>::Clear();
+ }
+
+#endif // #ifndef DACCESS_COMPILE
+
+//*****************************************************************************
+// Retrieve an item by name.
+//*****************************************************************************
+ T *GetItem( // Null or object.
+ LPCTSTR szKey) // What to do the lookup on.
+ {
+ WRAPPER_NO_CONTRACT;
+ TItemType sInfo;
+ TItemType *ptr; // Working pointer.
+
+ // Create a key.
+ sInfo.m_szString = (LPTSTR) szKey;
+
+ // Look it up in the hash table.
+ ptr = (TItemType *) Super::Find( _tHashString(szKey), (SIZE_T) &sInfo);
+
+ // Don't let dtor free our string.
+ sInfo.m_szString = 0;
+
+ // If pointer found, return to caller. To handle T's that have
+ // an operator &(), find raw address without going through &m_value.
+ if (ptr)
+ return ((T *) ((BYTE *) ptr + offsetof(TOffsetType, m_value)));
+ else
+ return (0);
+ }
+
+//*****************************************************************************
+// Initialize an iterator and return the first item.
+//*****************************************************************************
+ TItemType *FindFirstEntry(
+ HASHFIND *psSrch)
+ {
+ WRAPPER_NO_CONTRACT;
+ TItemType *ptr = (TItemType *) Super::FindFirstEntry(psSrch);
+
+ return (ptr);
+ }
+
+//*****************************************************************************
+// Return the next item, via an iterator.
+//*****************************************************************************
+ TItemType *FindNextEntry(
+ HASHFIND *psSrch)
+ {
+ WRAPPER_NO_CONTRACT;
+ TItemType *ptr = (TItemType *) Super::FindNextEntry(psSrch);
+
+ return (ptr);
+ }
+
+#ifndef DACCESS_COMPILE
+
+//*****************************************************************************
+// Add an item to the list.
+//*****************************************************************************
+ HRESULT AddItem( // S_OK, or S_FALSE.
+ LPCTSTR szKey, // The key value for the item.
+ T &item) // Thing to add.
+ {
+ WRAPPER_NO_CONTRACT;
+ TItemType *ptr; // Working pointer.
+
+ // Allocate an entry in the hash table.
+ if ((ptr = (TItemType *) this->Add( _tHashString(szKey))) == 0)
+ return (OutOfMemory());
+
+ // Fill the record.
+ if (ptr->SetString(szKey) < 0)
+ {
+ DelItem(ptr);
+ return (OutOfMemory());
+ }
+
+ // Call the placement new operator on the item so it can init itself.
+ // To handle T's that have an operator &(), find raw address without
+ // going through &m_value.
+ T *p = new ((void *) ((BYTE *) ptr + offsetof(TOffsetType, m_value))) T;
+ *p = item;
+ return (S_OK);
+ }
+
+//*****************************************************************************
+// Delete an item.
+//*****************************************************************************
+ void DelItem(
+ LPCTSTR szKey) // What to delete.
+ {
+ WRAPPER_NO_CONTRACT;
+ TItemType sInfo;
+ TItemType *ptr; // Working pointer.
+
+ // Create a key.
+ sInfo.m_szString = (LPTSTR) szKey;
+
+ // Look it up in the hash table.
+ ptr = (TItemType *) this->Find( _tHashString(szKey), (BYTE *) &sInfo);
+
+ // Don't let dtor free our string.
+ sInfo.m_szString = 0;
+
+ // If found, delete.
+ if (ptr)
+ DelItem(ptr);
+ }
+
+#endif // #ifndef DACCESS_COMPILE
+
+//*****************************************************************************
+// Compare the keys for two collections.
+//*****************************************************************************
+ BOOL Cmp( // 0 or != 0.
+ SIZE_T data, // Raw key data on lookup.
+ const HASHENTRY *pElement) // The element to compare data against.
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ TItemType *p = (TItemType *) (size_t) pElement;
+ return (::_tcscmp(((TItemType *) data)->m_szString, p->m_szString));
+ }
+
+private:
+ void DelItem(
+ TItemType *pItem) // Entry to delete.
+ {
+ WRAPPER_NO_CONTRACT;
+ // Need to destruct this item.
+ pItem->~TStringMapItem<T>();
+ CHashTableAndData<TAllocator>::Delete( HashString(pItem->m_szString), (HASHENTRY *)(void *)pItem);
+ }
+};
+
+class CImpTlbReservedNames
+{
+public:
+ CImpTlbReservedNames() {}
+ ~CImpTlbReservedNames() {/*m_StringMap.Clear();*/}
+
+#ifndef DACCESS_COMPILE
+ HRESULT Init() {return m_StringMap.NewInit();}
+
+ void AddReservedName(LPCWSTR szName) {BOOL flag = TRUE; m_StringMap.AddItem(szName, flag);}
+#endif
+ BOOL IsReservedName(LPCWSTR szName) {return m_StringMap.GetItem(szName) != 0;}
+
+private:
+ TStringMap<BOOL> m_StringMap;
+};
+
+
+//*****************************************************************************
+// Helper class to keep track of the mappings from default interfaces to
+// class interfaces.
+//*****************************************************************************
+class ImpTlbClassItfInfo
+{
+public:
+ IID ItfIID; // The IID of the interface.
+ LPCWSTR szClassItfName; // The class interface name.
+};
+
+class CImpTlbDefItfToClassItfMap : protected CClosedHash<class ImpTlbClassItfInfo>
+{
+public:
+ typedef CClosedHash<class ImpTlbClassItfInfo> Super;
+ typedef ImpTlbClassItfInfo T;
+
+ CImpTlbDefItfToClassItfMap();
+ ~CImpTlbDefItfToClassItfMap();
+
+ HRESULT Init(ITypeLib *pTlb, BSTR bstrNameSpace);
+
+ LPCWSTR GetClassItfName(IID &rItfIID);
+
+private:
+ HRESULT AddCoClassInterfaces(ITypeInfo *pCoClassITI, TYPEATTR *pCoClassTypeAttr);
+
+ unsigned int Hash(const void *pData) {return Hash((const T*)pData);}
+ unsigned int Hash(const T *pData);
+
+ unsigned int Compare(const void *p1, BYTE *p2) {return Compare((const T*)p1, (T*)p2);}
+ unsigned int Compare(const T *p1, T *p2);
+
+ ELEMENTSTATUS Status(BYTE *p) {return Status((T*)p);}
+ ELEMENTSTATUS Status(T *p);
+
+ void SetStatus(BYTE *p, ELEMENTSTATUS s) {SetStatus((T*)p, s);}
+ void SetStatus(T *p, ELEMENTSTATUS s);
+
+ void* GetKey(BYTE *p) {return GetKey((T*)p);}
+ void *GetKey(T *p);
+
+ T* Add(const T *pData);
+
+ CWCHARPool m_Names; // Heap of names.
+ BSTR m_bstrNameSpace; // Namespace of the typelib.
+};
+
+
+//*****************************************************************************
+// Helper class to keep track of imported typelibs. Typically, a typelib
+// imports only 2 or 3 other typelibs, so a simple array is used.
+//*****************************************************************************
+struct CTlbRef
+{
+ GUID guid; // GUID of referenced typelib.
+ mdAssemblyRef ar; // AssemblyRef for the module containing reference.
+ BSTR szNameSpace; // The namespace of the types contained in the assembly.
+ BSTR szAsmName; // The assembly name.
+ Assembly* Asm; // The assembly.
+ CImpTlbDefItfToClassItfMap *pDefItfToClassItfMap; // The default interface to class interface map.
+
+ ~CTlbRef()
+ {
+ SysFreeString(szNameSpace);
+ SysFreeString(szAsmName);
+ delete pDefItfToClassItfMap;
+ }
+};
+
+class CImpTlbLibRef : public CQuickArray<CTlbRef>
+{
+ typedef CQuickArray<CTlbRef> base;
+public:
+ CImpTlbLibRef() {base::Shrink(0);}
+ ~CImpTlbLibRef();
+
+ HRESULT Add(ITypeLib *pITLB, CImportTlb *pImporter, mdAssemblyRef ar, BSTR wzNamespace, BSTR wzAsmName, Assembly* assm, CImpTlbDefItfToClassItfMap **ppMap);
+ int Find(ITypeLib *pITLB, mdAssemblyRef *par, BSTR *pwzNamespace, BSTR *pwzAsmName, Assembly** assm, CImpTlbDefItfToClassItfMap **ppDefItfToClassItfMap);
+};
+
+
+class CImportTlb
+{
+public:
+ static CImportTlb* CreateImporter(LPCWSTR szLibrary, ITypeLib *pitlb, BOOL bGenerateTCEAdapters, BOOL bUnsafeInterfaces, BOOL bSafeArrayAsSystemArray, BOOL bTransformDispRetVals, BOOL bPreventClassMembers, BOOL bSerializableValueClasses);
+
+ CImportTlb();
+ CImportTlb(LPCWSTR szLibrary, ITypeLib *pitlb, BOOL bGenerateTCEAdapters, BOOL bUnsafeInterfaces, BOOL bSafeArrayAsSystemArray, BOOL bTransformDispRetVals, BOOL bPreventClassMembers, BOOL bSerializableValueClasses);
+ ~CImportTlb();
+
+ HRESULT Import();
+ HRESULT SetNamespace(WCHAR const *pNamespace);
+ WCHAR *GetNamespace() {return m_wzNamespace;}
+ HRESULT SetNotification(ITypeLibImporterNotifySink *pINotify);
+ HRESULT SetMetaData(IUnknown *pIUnk);
+ void SetAssembly(Assembly *pAssembly) {m_pAssembly = pAssembly;}
+ void SetModule(Module *pModule) {m_pModule = pModule;}
+ HRESULT GetNamespaceOfRefTlb(ITypeLib *pITLB, BSTR *pwzNamespace, CImpTlbDefItfToClassItfMap **ppDefItfToClassItfMap);
+ HRESULT GetEventInfoList(CQuickArray<ImpTlbEventInfo*> &qbEvInfoList) {return m_EventInfoMap.GetEventInfoList(qbEvInfoList);}
+
+ static HRESULT GetDefaultInterface(ITypeInfo *pCoClassTI, ITypeInfo **pDefaultItfTI);
+
+protected:
+
+ struct MemberInfo
+ {
+ union
+ {
+ FUNCDESC *m_psFunc; // Pointer to FuncDesc.
+ VARDESC *m_psVar; // Pointer to VarDesc.
+ };
+ LPWSTR m_pName; // Function/Prop's name, possibly decorated.
+ int m_iMember; // The index of the member in the ITypeInfo.
+ union
+ {
+ LPWSTR m_pName2; // Prop's second name, if any.
+ mdToken m_mdFunc; // Function's token & semantics, if not property.
+ USHORT m_msSemantics; // Semantics only.
+ };
+ void SetFuncInfo(mdMethodDef mdFunc, USHORT msSemantics) {m_mdFunc = RidFromToken(mdFunc) | (msSemantics<<24);}
+ void GetFuncInfo(mdMethodDef &mdFunc, USHORT &msSemantics) {mdFunc = m_mdFunc&0xffffff | mdtMethodDef; msSemantics = m_mdFunc>>24;}
+ };
+
+
+ HRESULT ConvertTypeLib();
+ HRESULT ConvertTypeInfo();
+
+ HRESULT ExplicitlyImplementsIEnumerable(ITypeInfo *pITI, TYPEATTR *psAttr, BOOL fLookupPartner = TRUE);
+
+ HRESULT _NewLibraryObject();
+ HRESULT ConvCoclass(ITypeInfo *pITI, TYPEATTR *psAttr);
+ HRESULT ConvEnum(ITypeInfo *pITI, TYPEATTR *psAttr);
+ HRESULT ConvRecord(ITypeInfo *pITI, TYPEATTR *psAttr, BOOL bUnion);
+ HRESULT ConvIface(ITypeInfo *pITI, TYPEATTR *psAttr, BOOL bVtblGaps=true);
+ HRESULT ConvDispatch(ITypeInfo *pITI, TYPEATTR *psAttr, BOOL bVtblGaps=true);
+ HRESULT ConvModule(ITypeInfo *pITI, TYPEATTR *psAttr);
+
+ HRESULT IsIUnknownDerived(ITypeInfo *pITI, TYPEATTR *psAttr);
+ HRESULT IsIDispatchDerived(ITypeInfo *pITI, TYPEATTR *psAttr);
+ HRESULT HasNewEnumMember(ITypeInfo *pItfTI);
+ HRESULT FuncIsNewEnum(ITypeInfo *pITI, FUNCDESC *pFuncDesc, DWORD index);
+ HRESULT PropertyIsNewEnum(ITypeInfo *pITI, VARDESC *pVarDesc, DWORD index);
+
+ HRESULT HasObjectFields(ITypeInfo *pITI, TYPEATTR *psAttr);
+ HRESULT IsObjectType(ITypeInfo *pITI, const TYPEDESC *pType);
+ HRESULT CompareSigsIgnoringRetType(PCCOR_SIGNATURE pbSig1, ULONG cbSig1, PCCOR_SIGNATURE pbSig2, ULONG cbSig2);
+
+ HRESULT FindMethod(mdTypeDef td, LPCWSTR szName, PCCOR_SIGNATURE pbSig, ULONG cbSig, mdMethodDef *pmb);
+ HRESULT FindProperty(mdTypeDef td, LPCWSTR szName, PCCOR_SIGNATURE pSig, ULONG cbSig, mdProperty *pPr);
+ HRESULT FindEvent(mdTypeDef td, LPCWSTR szName, mdProperty *pEv);
+
+ HRESULT ReportEvent(int ev, int hr, ...);
+
+ HRESULT _DefineSysRefs();
+ HRESULT _GetNamespaceName(ITypeLib *pITLB, BSTR *pwzNamespace);
+ HRESULT _GetTokenForTypeInfo(ITypeInfo *pITI, BOOL bConvDefItfToClassItf, mdToken *pToken, __out_ecount (chTypeRef) __out_opt LPWSTR pszTypeRef=0, int chTypeRef=0, int *pchTypeRef=0, BOOL bAsmQualifiedName = FALSE);
+
+ HRESULT _FindFirstUserMethod(ITypeInfo *pITI, TYPEATTR *psAttr, int *pIx);
+ HRESULT _ResolveTypeDescAliasTypeKind(ITypeInfo *pITIAlias, TYPEDESC *ptdesc, TYPEKIND *ptkind);
+ HRESULT _ResolveTypeDescAlias(ITypeInfo *pITIAlias, const TYPEDESC *ptdesc, ITypeInfo **ppTIResolved, TYPEATTR **ppsAttrResolved, GUID *pGuid=0);
+
+ HRESULT _SetHiddenCA(mdTypeDef token);
+ HRESULT _ForceIEnumerableCVExists(ITypeInfo* pITI, BOOL* CVExists);
+ HRESULT _SetDispIDCA(ITypeInfo* pITI, int iMember, long lDispId, mdToken func, BOOL fAlwaysAdd, long* lDispSet, BOOL bFunc);
+ HRESULT _GetDispIDCA(ITypeInfo* pITI, int iMember, long* lDispSet, BOOL bFunc);
+ HRESULT _CheckForPropertyCustomAttributes(ITypeInfo* pITI, int index, INVOKEKIND* ikind);
+
+ HRESULT _ConvIfaceMembers(ITypeInfo *pITI, TYPEATTR *psAttr, BOOL bVtblGaps, BOOL bAddDispIds, BOOL bInheritsIEnum);
+ HRESULT _ConvSrcIfaceMembers(ITypeInfo *pITI, TYPEATTR* psAttr, BOOL fInheritsIEnum);
+ HRESULT _ConvDispatchMembers(ITypeInfo *pITI, TYPEATTR *psAttr, BOOL fInheritsIEnum);
+ HRESULT _GetFunctionPropertyInfo(FUNCDESC *psFunc, USHORT *pSemantics, FUNCDESC **ppSig, TYPEDESC **ppProperty, BOOL *pbRetval, BOOL fUseLastParam, BSTR strName);
+ HRESULT _ConvFunction(ITypeInfo *pITI, MemberInfo *pMember, int bVtblGapFuncs, BOOL bAddDispIds, BOOL bDelegateInvokeMeth, BOOL* bAllowIEnum);
+ HRESULT _GenerateEvent(ITypeInfo *pITI, MemberInfo *pMember, BOOL fInheritsIEnum);
+ HRESULT _GenerateEventDelegate(ITypeInfo *pITI, MemberInfo *pMember, mdTypeDef *ptd, BOOL fInheritsIEnum);
+ HRESULT _AddSrcItfMembersToClass(mdTypeRef trSrcItf);
+
+ HRESULT _ConvPropertiesForFunctions(ITypeInfo *pITI, TYPEATTR *psAttr);
+ enum ParamOpts{ParamNormal=0, ParamOptional, ParamVarArg};
+ HRESULT _ConvParam(ITypeInfo *pITI, mdMethodDef mbFunc, int iSequence, const ELEMDESC *pdesc, ParamOpts paramOpts, const WCHAR *pszName, BYTE *pbNative, ULONG cbNative);
+ HRESULT _ConvConstant(ITypeInfo *pITI, VARDESC *psVar, BOOL bEnumMember=false);
+ HRESULT _ConvField(ITypeInfo *pITI, VARDESC *psVar, mdFieldDef *pmdField, BOOL bUnion);
+ HRESULT _ConvProperty(ITypeInfo *pITI, MemberInfo *pMember);
+ HRESULT _ConvNewEnumProperty(ITypeInfo *pITI, VARDESC *psVar, MemberInfo *pMember);
+
+ HRESULT _HandleAliasInfo(ITypeInfo *pITI, TYPEDESC *pTypeDesc, mdToken tk);
+
+ HRESULT _AddTlbRef(ITypeLib *pITLB, mdAssemblyRef *par, BSTR *pwzNamespace, BSTR *pwzAsmName, CImpTlbDefItfToClassItfMap **ppDefItfToClassItfMap);
+
+ HRESULT _AddGuidCa(mdToken tkObj, REFGUID guid);
+ HRESULT _AddDefaultMemberCa(mdToken tkObj, LPCWSTR szName);
+
+ HRESULT _AddStringCa(int attr, mdToken tk, LPCWSTR wzString);
+
+ HRESULT GetKnownTypeToken(VARTYPE vt, mdTypeRef *ptr);
+
+ HRESULT _GetTokenForEventItf(ITypeInfo *pSrcItfITI, mdTypeRef *ptr);
+ HRESULT _CreateClassInterface(ITypeInfo *pCoClassITI, ITypeInfo *pDefItfITI, mdTypeRef trDefItf, mdTypeRef rtDefEvItf, mdToken *ptr);
+
+ HRESULT GetManagedNameForCoClass(ITypeInfo *pITI, CQuickArray<WCHAR> &qbClassName);
+ HRESULT GenerateUniqueTypeName(CQuickArray<WCHAR> &qbTypeName);
+ HRESULT GenerateUniqueMemberName(CQuickArray<WCHAR> &qbMemberName, PCCOR_SIGNATURE pSig, ULONG SigSize, LPCWSTR szPrefix, mdToken type);
+ HRESULT _IsAlias(ITypeInfo *pITI, TYPEDESC *pTypeDesc);
+
+ HRESULT GetDefMemberName(ITypeInfo *pITI, BOOL bItfQualified, CQuickArray<WCHAR> &qbDefMemberName);
+
+ enum SigFlags {
+ // These match the typelib values
+ SIG_IN = 0x0001, // Input param.
+ SIG_OUT = 0x0002, // Output param.
+ SIG_RET = 0x0008, // Retval. Currently unused.
+ SIG_OPT = 0x0010, // Optional param. Currently unused.
+ SIG_FLAGS_MASK = 0x001b, // Mask of flags from TypeLib PARAMFLAGs
+
+ SIG_FUNC = 0x0100, // Convert signature for function.
+ SIG_FIELD = 0x0200, // Convert signature for field.
+ SIG_ELEM = 0x0300, // Convert signature for sub element (eg, array of X).
+ SIG_TYPE_MASK = 0x0300,
+
+ SIG_USE_BYREF = 0x1000, // If set convert one ptr as E_T_BYREF.
+ SIG_VARARG = 0x4000, // If set, this is a paramarray type. Use szArray, not System.Array.
+
+ SIG_FLAGS_NONE = 0 // '0' of this enum type.
+ };
+
+ #define IsSigIn(flags) ((flags & SIG_IN) == SIG_IN)
+ #define IsSigOut(flags) ((flags & SIG_OUT) == SIG_OUT)
+ #define IsSigRet(flags) ((flags & SIG_RET) == SIG_RET)
+ #define IsSigOpt(flags) ((flags & SIG_OPT) == SIG_OPT)
+ #define IsSigOutRet(flags) ((flags & (SIG_OUT|SIG_RET)) == (SIG_OUT|SIG_RET))
+
+ #define IsSigFunc(flags) ((flags & SIG_TYPE_MASK) == SIG_FUNC)
+ #define IsSigField(flags) ((flags & SIG_TYPE_MASK) == SIG_FIELD)
+ #define IsSigElem(flags) ((flags & SIG_TYPE_MASK) == SIG_ELEM)
+
+ #define IsSigUseByref(flags) ((flags & SIG_USE_BYREF) == SIG_USE_BYREF)
+ #define IsSigVarArg(flags) ((flags & SIG_VARARG) == SIG_VARARG)
+
+ HRESULT _ConvSignature(ITypeInfo *pITI, const TYPEDESC *pType, ULONG Flags, CQuickBytes &qbSigBuf, ULONG cbSig, ULONG *pcbSig, CQuickArray<BYTE> &qbNativeTypeBuf, ULONG cbNativeType, ULONG *pcbNativeType, BOOL bNewEnumMember, int iByRef=0);
+
+ // For handling out-of-order vtables.
+ CQuickArray<MemberInfo> m_MemberList;
+ CWCHARPool *m_pMemberNames;
+ int m_cMemberProps; // Count of props in memberlist.
+ HRESULT BuildMemberList(ITypeInfo *pITI, int iStart, int iEnd, BOOL bInheritsIEnum);
+ HRESULT FreeMemberList(ITypeInfo *pITI);
+
+ // List of predefined token types for custom attributes.
+#define INTEROP_ATTRIBUTES() \
+ INTEROP_ATTRIBUTE(DISPID) \
+ INTEROP_ATTRIBUTE(CLASSINTERFACE) \
+ INTEROP_ATTRIBUTE(INTERFACETYPE) \
+ INTEROP_ATTRIBUTE(TYPELIBTYPE) \
+ INTEROP_ATTRIBUTE(TYPELIBVAR) \
+ INTEROP_ATTRIBUTE(TYPELIBFUNC) \
+ INTEROP_ATTRIBUTE(COMSOURCEINTERFACES) \
+ INTEROP_ATTRIBUTE(COMCONVERSIONLOSS) \
+ INTEROP_ATTRIBUTE(GUID) \
+ INTEROP_ATTRIBUTE(DEFAULTMEMBER) \
+ INTEROP_ATTRIBUTE(COMALIASNAME) \
+ INTEROP_ATTRIBUTE(PARAMARRAY) \
+ INTEROP_ATTRIBUTE(LCIDCONVERSION) \
+ INTEROP_ATTRIBUTE(DECIMALVALUE) \
+ INTEROP_ATTRIBUTE(DATETIMEVALUE) \
+ INTEROP_ATTRIBUTE(IUNKNOWNVALUE) \
+ INTEROP_ATTRIBUTE(IDISPATCHVALUE) \
+ INTEROP_ATTRIBUTE(COMVISIBLE) \
+ INTEROP_ATTRIBUTE(SERIALIZABLE) \
+ INTEROP_ATTRIBUTE_SPECIAL(COMEVENTINTERFACE) \
+ INTEROP_ATTRIBUTE_SPECIAL(COCLASS) \
+
+#define INTEROP_ATTRIBUTE(x) ATTR_##x,
+#define INTEROP_ATTRIBUTE_SPECIAL(x) ATTR_##x,
+ enum {INTEROP_ATTRIBUTES()
+ // Last value gives array size.
+ ATTR_COUNT};
+#undef INTEROP_ATTRIBUTE
+#undef INTEROP_ATTRIBUTE_SPECIAL
+
+ mdToken m_tkAttr[ATTR_COUNT];
+ HRESULT GetAttrType(int attr, mdToken *ptk);
+
+ // look up table for known type
+ mdTypeRef m_tkKnownTypes[MAX_TLB_VT];
+
+ LPCWSTR m_szLibrary; // Name of typelib being imported.
+ BOOL m_bGenerateTCEAdapters; // A flag indicating if the TCE adapters are being generated or not.
+ BOOL m_bUnsafeInterfaces; // A flag indicating whether runtime security checks should be disabled on an interface
+ BOOL m_bSafeArrayAsSystemArray; // A flag indicating whether to import SAFEARRAY's as System.Array's.
+ BOOL m_bTransformDispRetVals; // A flag indicating if we should do [out,retval] transformation on disp only itfs.
+ BOOL m_bPreventClassMembers; // A flag indicating if we should add members to CoClasses.
+ BOOL m_bSerializableValueClasses; // A flag indicating if we should mark value classes as serializable.
+ mdMemberRef m_tkSuppressCheckAttr; // Cached ctor for security check custom attribute
+ ITypeLib *m_pITLB; // Typelib being imported.
+ IMetaDataEmit2 *m_pEmit; // Emit API Interface pointer.
+ IMetaDataImport2 *m_pImport; // Import API Interface pointer.
+
+ BSTR m_wzNamespace; // Namespace of the created TypeDefs.
+ mdTypeRef m_trObject; // Token of System.Object.
+ mdTypeRef m_trValueType; // Token of System.ValueType.
+ mdTypeRef m_trEnum; // Token of System.Enum.
+ mdAssemblyRef m_arSystem; // AssemblyRef for classlib.
+
+ ITypeInfo *m_pITI; // "Current" ITypeInfo being converted.
+ ITypeInfo *m_pOrigITI; // Original "Current" ITypeInfo being converted,
+ // represents TKIND_ALIAS or is equal to m_pITI.
+
+ TYPEATTR *m_psAttr; // "TYPEATTR" of current ITypeInfo.
+
+ BSTR m_szName; // Name of original current ITypeInfo.
+ BSTR m_szMember; // Name of current Member (method or field).
+ LPWSTR m_szMngName; // Full name of the managed type.
+
+ ULONG m_cbVtableSlot; // Size of a vtable slot.
+ ULONG m_Slot; // "Current" vtbl index within an interface.
+
+ void *m_psClass; // "Current" class record.
+ mdTypeDef m_tdTypeDef; // Current TypeDef.
+ mdTypeDef m_tdHasDefault; // Most recent TypeDef with a default.
+ enum {eImplIfaceNone, eImplIfaceDefault, eImplIface} m_ImplIface;
+ mdToken m_tkInterface; // Interface being added to a coclass.
+ BSTR m_szInterface; // Interface name for decoration.
+
+ CImpTlbTypeRef m_TRMap; // Typeref map.
+ CImpTlbLibRef m_LibRefs; // Referenced typelibs.
+ CImpTlbDefItfToClassItfMap m_DefItfToClassItfMap; // The default interface to class interface map.
+
+ CImpTlbReservedNames m_ReservedNames; // Reserved names.
+ CImpTlbEventInfoMap m_EventInfoMap; // Map of event info's.
+
+ ITypeLibImporterNotifySink *m_Notify; // Notification object.
+ Assembly *m_pAssembly; // Containing assembly.
+ Module *m_pModule; // Module we are emiting into.
+
+#if defined(TLB_STATS)
+ LARGE_INTEGER m_freqVal; // Frequency of perf counter.
+ BOOL m_bStats; // If true, collect timings.
+#endif // TLB_STATS
+};
+
+
+
+#endif
+
+//-eof-************************************************************************
diff --git a/src/md/inc/liteweightstgdb.h b/src/md/inc/liteweightstgdb.h
new file mode 100644
index 0000000000..1234524731
--- /dev/null
+++ b/src/md/inc/liteweightstgdb.h
@@ -0,0 +1,257 @@
+// 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.
+//*****************************************************************************
+// LiteWeightStgdb.h
+//
+
+//
+// This contains definition of class CLiteWeightStgDB. This is light weight
+// read-only implementation for accessing compressed meta data format.
+//
+//*****************************************************************************
+#ifndef __LiteWeightStgdb_h__
+#define __LiteWeightStgdb_h__
+
+#include "metamodelro.h"
+#include "metamodelrw.h"
+
+#include "stgtiggerstorage.h"
+
+class StgIO;
+
+#include "mdcommon.h"
+
+#ifdef _PREFAST_
+#pragma warning(push)
+#pragma warning(disable:28718) // public header missing SAL annotations
+#endif // _PREFAST_
+class TiggerStorage;
+#ifdef _PREFAST_
+#pragma warning(pop)
+#endif // _PREFAST_
+
+//*****************************************************************************
+// This class provides common definitions for heap segments. It is both the
+// base class for the heap, and the class for heap extensions (additional
+// memory that must be allocated to grow the heap).
+//*****************************************************************************
+template <class MiniMd>
+class CLiteWeightStgdb
+{
+ friend class VerifyLayoutsMD;
+public:
+ CLiteWeightStgdb() : m_pvMd(NULL), m_cbMd(0)
+ {}
+
+ ~CLiteWeightStgdb()
+ { Uninit(); }
+
+ // open an in-memory metadata section for read.
+ __checkReturn
+ HRESULT InitOnMem(
+ ULONG cbData,
+ LPCVOID pbData);
+
+ __checkReturn
+ HRESULT InitHotPools(DataBuffer hotMetaData);
+
+ void Uninit();
+
+protected:
+ MiniMd m_MiniMd; // embedded compress meta data schemas definition
+ const void *m_pvMd; // Pointer to meta data.
+ ULONG m_cbMd; // Size of the meta data.
+
+ friend class CorMetaDataScope;
+ friend class COR;
+ friend class RegMeta;
+ friend class MERGER;
+ friend class NEWMERGER;
+ friend class MDInternalRO;
+ friend class MDInternalRW;
+};
+
+//*****************************************************************************
+// Open an in-memory metadata section for read
+//*****************************************************************************
+template <class MiniMd>
+void CLiteWeightStgdb<MiniMd>::Uninit()
+{
+ m_MiniMd.m_StringHeap.Delete();
+ m_MiniMd.m_UserStringHeap.Delete();
+ m_MiniMd.m_GuidHeap.Delete();
+ m_MiniMd.m_BlobHeap.Delete();
+ m_pvMd = NULL;
+ m_cbMd = 0;
+}
+
+class CLiteWeightStgdbRW : public CLiteWeightStgdb<CMiniMdRW>
+{
+ friend class CImportTlb;
+ friend class RegMeta;
+ friend class VerifyLayoutsMD;
+ friend HRESULT TranslateSigHelper(
+ IMDInternalImport* pImport,
+ IMDInternalImport* pAssemImport,
+ const void* pbHashValue,
+ ULONG cbHashValue,
+ PCCOR_SIGNATURE pbSigBlob,
+ ULONG cbSigBlob,
+ IMetaDataAssemblyEmit* pAssemEmit,
+ IMetaDataEmit* emit,
+ CQuickBytes* pqkSigEmit,
+ ULONG* pcbSig);
+public:
+ CLiteWeightStgdbRW() : m_cbSaveSize(0), m_pStreamList(0), m_pNextStgdb(NULL), m_pStgIO(NULL)
+ {
+ m_wszFileName = NULL;
+ m_pImage = NULL;
+ m_dwImageSize = 0;
+ m_dwPEKind = (DWORD)(-1);
+ m_dwDatabaseLFS = 0;
+ m_dwDatabaseLFT = 0;
+ }
+ ~CLiteWeightStgdbRW();
+
+ __checkReturn
+ HRESULT InitNew();
+
+ // open an in-memory metadata section for read.
+ __checkReturn
+ HRESULT InitOnMem(
+ ULONG cbData,
+ LPCVOID pbData,
+ int bReadOnly);
+
+ __checkReturn
+ HRESULT GetSaveSize(
+ CorSaveSize fSize,
+ UINT32 *pcbSaveSize,
+ MetaDataReorderingOptions reorderingOptions = NoReordering,
+ CorProfileData *pProfileData = NULL); // optional IBC profile data for working set optimization
+
+ __checkReturn
+ HRESULT SaveToStream(
+ IStream *pIStream, // Stream to which to write
+ MetaDataReorderingOptions reorderingOptions = NoReordering,
+ CorProfileData *pProfileData = NULL); // optional IBC profile data for working set optimization
+
+ __checkReturn
+ HRESULT Save(
+ LPCWSTR szFile,
+ DWORD dwSaveFlags);
+
+ // Open a metadata section for read/write
+ __checkReturn
+ HRESULT OpenForRead(
+ LPCWSTR szDatabase, // Name of database.
+ void *pbData, // Data to open on top of, 0 default.
+ ULONG cbData, // How big is the data.
+ DWORD dwFlags); // Flags for the open.
+
+#ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE
+ // Open a metadata section for read/write
+ __checkReturn
+ HRESULT OpenForRead(
+ IMDCustomDataSource *pDataSource, // data to open on top of
+ DWORD dwFlags); // Flags for the open.
+#endif
+
+ __checkReturn
+ HRESULT FindImageMetaData(
+ PVOID pImage, // Pointer to head of a file
+ DWORD dwFileLength, // length of a flat file
+ BOOL bMappedImage, // Is the file mapped
+ PVOID *ppMetaData, // [out] pointer to the metadata
+ ULONG *pcbMetaData); // [out] size of the metadata
+
+ __checkReturn
+ HRESULT FindObjMetaData(
+ PVOID pImage, // Pointer to an OBJ file
+ DWORD dwFileLength, // Length of the file
+ PVOID *ppMetaData, // [out] pointer to the metadata
+ ULONG *pcbMetaData); // [out] size of the metadata
+
+ __checkReturn
+ HRESULT GetPEKind( // S_OK or error.
+ MAPPINGTYPE mtMapping, // The type of mapping the image has
+ DWORD* pdwPEKind, // [OUT] The kind of PE (0 - not a PE)
+ DWORD* pdwMachine); // [OUT] Machine as defined in NT header
+
+ // Low level data access; not useful for most clients.
+ __checkReturn
+ HRESULT GetRawData(
+ const void **ppvMd, // [OUT] put pointer to MD section here (aka, 'BSJB').
+ ULONG *pcbMd); // [OUT] put size of the stream here.
+
+ __checkReturn
+ STDMETHODIMP GetRawStreamInfo( // Get info about the MD stream.
+ ULONG ix, // [IN] Stream ordinal desired.
+ const char **ppchName, // [OUT] put pointer to stream name here.
+ const void **ppv, // [OUT] put pointer to MD stream here.
+ ULONG *pcb); // [OUT] put size of the stream here.
+
+ UINT32 m_cbSaveSize; // Size of the saved streams.
+ int m_bSaveCompressed; // If true, save as compressed stream (#-, not #~)
+ VOID* m_pImage; // Set in OpenForRead, NULL for anything but PE files
+ DWORD m_dwImageSize; // On-disk size of image
+
+protected:
+ DWORD m_dwPEKind; // The kind of PE - 0: not a PE.
+ DWORD m_dwMachine; // Machine as defined in NT header.
+
+ __checkReturn
+ HRESULT GetPoolSaveSize(
+ LPCWSTR szHeap, // Name of the heap stream.
+ int iPool, // The pool whose size to get.
+ UINT32 *pcbSaveSize); // Add pool data to this value.
+
+ __checkReturn
+ HRESULT GetTablesSaveSize(
+ CorSaveSize fSave,
+ UINT32 *pcbSaveSize,
+ MetaDataReorderingOptions reorderingOptions,
+ CorProfileData *pProfileData = NULL); // Add pool data to this value.
+
+ __checkReturn
+ HRESULT AddStreamToList(
+ UINT32 cbSize, // Size of the stream data.
+ LPCWSTR szName); // Name of the stream.
+
+ __checkReturn
+ HRESULT SaveToStorage(
+ TiggerStorage *pStorage,
+ MetaDataReorderingOptions reorderingOptions = NoReordering,
+ CorProfileData *pProfileData = NULL);
+
+ __checkReturn
+ HRESULT SavePool(LPCWSTR szName, TiggerStorage *pStorage, int iPool);
+
+ STORAGESTREAMLST *m_pStreamList;
+
+ __checkReturn
+ HRESULT InitFileForRead(
+ StgIO *pStgIO, // For file i/o.
+ int bReadOnly=true); // If read-only.
+
+ // Set file name of this database (makes copy of the file name).
+ __checkReturn HRESULT SetFileName(const WCHAR * wszFileName);
+ // Returns TRUE if wszFileName has valid file name length.
+ static BOOL IsValidFileNameLength(const WCHAR * wszFileName);
+
+ CLiteWeightStgdbRW *m_pNextStgdb;
+
+public:
+ FORCEINLINE FILETYPE GetFileType() { return m_eFileType; }
+
+private:
+ FILETYPE m_eFileType;
+ WCHAR * m_wszFileName; // Database file name (NULL or non-empty string)
+ DWORD m_dwDatabaseLFT; // Low bytes of the database file's last write time
+ DWORD m_dwDatabaseLFS; // Low bytes of the database file's size
+ StgIO * m_pStgIO; // For file i/o.
+
+}; // class CLiteWeightStgdbRW
+
+#endif // __LiteWeightStgdb_h__
diff --git a/src/md/inc/mdcolumndescriptors.h b/src/md/inc/mdcolumndescriptors.h
new file mode 100644
index 0000000000..ac2565cdb5
--- /dev/null
+++ b/src/md/inc/mdcolumndescriptors.h
@@ -0,0 +1,51 @@
+// 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.
+
+//
+
+static const BYTE s_ModuleCol[];
+static const BYTE s_TypeRefCol[];
+static const BYTE s_TypeDefCol[];
+static const BYTE s_FieldPtrCol[];
+static const BYTE s_FieldCol[];
+static const BYTE s_MethodPtrCol[];
+static const BYTE s_MethodCol[];
+static const BYTE s_ParamPtrCol[];
+static const BYTE s_ParamCol[];
+static const BYTE s_InterfaceImplCol[];
+static const BYTE s_MemberRefCol[];
+static const BYTE s_ConstantCol[];
+static const BYTE s_CustomAttributeCol[];
+static const BYTE s_FieldMarshalCol[];
+static const BYTE s_DeclSecurityCol[];
+static const BYTE s_ClassLayoutCol[];
+static const BYTE s_FieldLayoutCol[];
+static const BYTE s_StandAloneSigCol[];
+static const BYTE s_EventMapCol[];
+static const BYTE s_EventPtrCol[];
+static const BYTE s_EventCol[];
+static const BYTE s_PropertyMapCol[];
+static const BYTE s_PropertyPtrCol[];
+static const BYTE* s_PropertyCol;
+static const BYTE s_MethodSemanticsCol[];
+static const BYTE s_MethodImplCol[];
+static const BYTE s_ModuleRefCol[];
+static const BYTE* s_TypeSpecCol;
+static const BYTE s_ImplMapCol[];
+static const BYTE* s_FieldRVACol;
+static const BYTE s_ENCLogCol[];
+static const BYTE s_ENCMapCol[];
+static const BYTE s_AssemblyCol[];
+static const BYTE* s_AssemblyProcessorCol;
+static const BYTE s_AssemblyOSCol[];
+static const BYTE s_AssemblyRefCol[];
+static const BYTE s_AssemblyRefProcessorCol[];
+static const BYTE s_AssemblyRefOSCol[];
+static const BYTE s_FileCol[];
+static const BYTE s_ExportedTypeCol[];
+static const BYTE s_ManifestResourceCol[];
+static const BYTE s_NestedClassCol[];
+static const BYTE s_GenericParamCol[];
+static const BYTE s_MethodSpecCol[];
+static const BYTE s_GenericParamConstraintCol[];
diff --git a/src/md/inc/mdfileformat.h b/src/md/inc/mdfileformat.h
new file mode 100644
index 0000000000..a86549323e
--- /dev/null
+++ b/src/md/inc/mdfileformat.h
@@ -0,0 +1,269 @@
+// 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.
+//*****************************************************************************
+// MDFileFormat.h
+//
+
+//
+// This file contains a set of helpers to verify and read the file format.
+// This code does not handle the paging of the data, or different types of
+// I/O. See the StgTiggerStorage and StgIO code for this level of support.
+//
+//*****************************************************************************
+#ifndef __MDFileFormat_h__
+#define __MDFileFormat_h__
+
+//*****************************************************************************
+// The signature ULONG is the first 4 bytes of the file format. The second
+// signature string starts the header containing the stream list. It is used
+// for an integrity check when reading the header in lieu of a more complicated
+// system.
+//*****************************************************************************
+#define STORAGE_MAGIC_SIG 0x424A5342 // BSJB
+
+
+
+//*****************************************************************************
+// These values get written to the signature at the front of the file. Changing
+// these values should not be done lightly because all old files will no longer
+// be supported. In a future revision if a format change is required, a
+// backwards compatible migration path must be provided.
+//*****************************************************************************
+
+#define FILE_VER_MAJOR 1
+#define FILE_VER_MINOR 1
+
+// These are the last legitimate 0.x version macros. The file format has
+// sinced move up to 1.x (see macros above). After COM+ 1.0/NT 5 RTM's, these
+// macros should no longer be required or ever seen.
+#define FILE_VER_MAJOR_v0 0
+
+#define FILE_VER_MINOR_v0 19
+
+
+#define MAXSTREAMNAME 32
+
+enum
+{
+ STGHDR_NORMAL = 0x00, // Normal default flags.
+ STGHDR_EXTRADATA = 0x01, // Additional data exists after header.
+};
+
+
+//*****************************************************************************
+// This is the formal signature area at the front of the file. This structure
+// is not allowed to change, the shim depends on it staying the same size.
+// Use the reserved pointer if it must extended.
+//*****************************************************************************
+struct STORAGESIGNATURE;
+typedef STORAGESIGNATURE UNALIGNED * PSTORAGESIGNATURE;
+
+#include "pshpack1.h"
+struct STORAGESIGNATURE
+{
+METADATA_FIELDS_PROTECTION:
+ ULONG lSignature; // "Magic" signature.
+ USHORT iMajorVer; // Major file version.
+ USHORT iMinorVer; // Minor file version.
+ ULONG iExtraData; // Offset to next structure of information
+ ULONG iVersionString; // Length of version string
+public:
+ BYTE pVersion[0]; // Version string
+ ULONG GetSignature()
+ {
+ return VAL32(lSignature);
+ }
+ void SetSignature(ULONG Signature)
+ {
+ lSignature = VAL32(Signature);
+ }
+
+ USHORT GetMajorVer()
+ {
+ return VAL16(iMajorVer);
+ }
+ void SetMajorVer(USHORT MajorVer)
+ {
+ iMajorVer = VAL16(MajorVer);
+ }
+
+ USHORT GetMinorVer()
+ {
+ return VAL16(iMinorVer);
+ }
+ void SetMinorVer(USHORT MinorVer)
+ {
+ iMinorVer = VAL16(MinorVer);
+ }
+
+ ULONG GetExtraDataOffset()
+ {
+ return VAL32(iExtraData);
+ }
+ void SetExtraDataOffset(ULONG ExtraDataOffset)
+ {
+ iExtraData = VAL32(ExtraDataOffset);
+ }
+
+ ULONG GetVersionStringLength()
+ {
+ return VAL32(iVersionString);
+ }
+ void SetVersionStringLength(ULONG VersionStringLength)
+ {
+ iVersionString = VAL32(VersionStringLength);
+ }
+};
+#include "poppack.h"
+
+
+//*****************************************************************************
+// The header of the storage format.
+//*****************************************************************************
+struct STORAGEHEADER;
+typedef STORAGEHEADER UNALIGNED * PSTORAGEHEADER;
+
+#include "pshpack1.h"
+struct STORAGEHEADER
+{
+METADATA_FIELDS_PROTECTION:
+ BYTE fFlags; // STGHDR_xxx flags.
+ BYTE pad;
+ USHORT iStreams; // How many streams are there.
+public:
+ BYTE GetFlags()
+ {
+ return fFlags;
+ }
+ void SetFlags(BYTE flags)
+ {
+ fFlags = flags;
+ }
+ void AddFlags(BYTE flags)
+ {
+ fFlags |= flags;
+ }
+
+
+ USHORT GetiStreams()
+ {
+ return VAL16(iStreams);
+ }
+ void SetiStreams(USHORT iStreamsCount)
+ {
+ iStreams = VAL16(iStreamsCount);
+ }
+};
+#include "poppack.h"
+
+
+//*****************************************************************************
+// Each stream is described by this struct, which includes the offset and size
+// of the data. The name is stored in ANSI null terminated.
+//*****************************************************************************
+struct STORAGESTREAM;
+typedef STORAGESTREAM UNALIGNED * PSTORAGESTREAM;
+
+#include "pshpack1.h"
+struct STORAGESTREAM
+{
+METADATA_FIELDS_PROTECTION:
+ ULONG iOffset; // Offset in file for this stream.
+ ULONG iSize; // Size of the file.
+ char rcName[MAXSTREAMNAME]; // Start of name, null terminated.
+public:
+ // Returns pointer to the next stream. Doesn't validate the structure.
+ inline PSTORAGESTREAM NextStream()
+ {
+ int iLen = (int)(strlen(rcName) + 1);
+ iLen = ALIGN4BYTE(iLen);
+ return ((PSTORAGESTREAM) (((BYTE*)this) + (sizeof(ULONG) * 2) + iLen));
+ }
+ // Returns pointer to the next stream.
+ // Returns NULL if the structure has invalid format.
+ inline PSTORAGESTREAM NextStream_Verify()
+ {
+ // Check existence of null-terminator in the name
+ if (memchr(rcName, 0, MAXSTREAMNAME) == NULL)
+ {
+ return NULL;
+ }
+ return NextStream();
+ }
+
+ inline ULONG GetStreamSize()
+ {
+ return (ULONG)(strlen(rcName) + 1 + (sizeof(STORAGESTREAM) - sizeof(rcName)));
+ }
+
+ inline char* GetName()
+ {
+ return rcName;
+ }
+ inline LPCWSTR GetName(__inout_ecount (iMaxSize) LPWSTR szName, int iMaxSize)
+ {
+ VERIFY(::WszMultiByteToWideChar(CP_ACP, 0, rcName, -1, szName, iMaxSize));
+ return (szName);
+ }
+ inline void SetName(LPCWSTR szName)
+ {
+ int size;
+ size = WszWideCharToMultiByte(CP_ACP, 0, szName, -1, rcName, MAXSTREAMNAME, 0, 0);
+ _ASSERTE(size > 0);
+ }
+
+ ULONG GetSize()
+ {
+ return VAL32(iSize);
+ }
+ void SetSize(ULONG Size)
+ {
+ iSize = VAL32(Size);
+ }
+
+ ULONG GetOffset()
+ {
+ return VAL32(iOffset);
+ }
+ void SetOffset(ULONG Offset)
+ {
+ iOffset = VAL32(Offset);
+ }
+};
+#include "poppack.h"
+
+
+class MDFormat
+{
+public:
+//*****************************************************************************
+// Verify the signature at the front of the file to see what type it is.
+//*****************************************************************************
+ static HRESULT VerifySignature(
+ PSTORAGESIGNATURE pSig, // The signature to check.
+ ULONG cbData); // Size of metadata.
+
+//*****************************************************************************
+// Skip over the header and find the actual stream data.
+// It doesn't perform any checks for buffer overflow - use GetFirstStream_Verify
+// instead.
+//*****************************************************************************
+ static PSTORAGESTREAM GetFirstStream(// Return pointer to the first stream.
+ PSTORAGEHEADER pHeader, // Return copy of header struct.
+ const void *pvMd); // Pointer to the full file.
+//*****************************************************************************
+// Skip over the header and find the actual stream data. Secure version of
+// GetFirstStream method.
+// The header is supposed to be verified by VerifySignature.
+//
+// Caller has to check available buffer size before using the first stream.
+//*****************************************************************************
+ static PSTORAGESTREAM GetFirstStream_Verify(// Return pointer to the first stream.
+ PSTORAGEHEADER pHeader, // Return copy of header struct.
+ const void *pvMd, // Pointer to the full file.
+ ULONG *pcbMd); // [in, out] Size of pvMd buffer (we don't want to read behind it)
+
+};
+
+#endif // __MDFileFormat_h__
diff --git a/src/md/inc/mdinternalrw.h b/src/md/inc/mdinternalrw.h
new file mode 100644
index 0000000000..a0cc4816a4
--- /dev/null
+++ b/src/md/inc/mdinternalrw.h
@@ -0,0 +1,862 @@
+// 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.
+//*****************************************************************************
+// MDInternalRW.h
+//
+
+//
+// Contains utility code for MD directory
+//
+//*****************************************************************************
+#ifndef __MDInternalRW__h__
+#define __MDInternalRW__h__
+
+#ifdef FEATURE_METADATA_INTERNAL_APIS
+
+#include "../inc/mdlog.h"
+
+class UTSemReadWrite;
+
+class MDInternalRW : public IMDInternalImportENC, public IMDCommon
+{
+ friend class VerifyLayoutsMD;
+public:
+
+
+ MDInternalRW();
+ virtual ~MDInternalRW();
+ __checkReturn
+ HRESULT Init(LPVOID pData, ULONG cbData, int bReadOnly);
+ __checkReturn
+ HRESULT InitWithStgdb(IUnknown *pUnk, CLiteWeightStgdbRW *pStgdb);
+ __checkReturn
+ HRESULT InitWithRO(MDInternalRO *pRO, int bReadOnly);
+
+ // *** IUnknown methods ***
+ __checkReturn
+ STDMETHODIMP QueryInterface(REFIID riid, void** ppv);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+ __checkReturn
+ STDMETHODIMP TranslateSigWithScope(
+ IMDInternalImport *pAssemImport, // [IN] import assembly scope.
+ const void *pbHashValue, // [IN] hash value for the import assembly.
+ ULONG cbHashValue, // [IN] count of bytes in the hash value.
+ PCCOR_SIGNATURE pbSigBlob, // [IN] signature in the importing scope
+ ULONG cbSigBlob, // [IN] count of bytes of signature
+ IMetaDataAssemblyEmit *pAssemEmit, // [IN] assembly emit scope.
+ IMetaDataEmit *emit, // [IN] emit interface
+ CQuickBytes *pqkSigEmit, // [OUT] buffer to hold translated signature
+ ULONG *pcbSig) // [OUT] count of bytes in the translated signature
+ DAC_UNEXPECTED();
+
+ __checkReturn
+ STDMETHODIMP GetTypeDefRefTokenInTypeSpec(// return S_FALSE if enclosing type does not have a token
+ mdTypeSpec tkTypeSpec, // [IN] TypeSpec token to look at
+ mdToken *tkEnclosedToken) // [OUT] The enclosed type token
+ DAC_UNEXPECTED();
+
+ STDMETHODIMP_(IMetaModelCommon*) GetMetaModelCommon()
+ {
+ return static_cast<IMetaModelCommon*>(&m_pStgdb->m_MiniMd);
+ }
+
+ STDMETHODIMP_(IMetaModelCommonRO*) GetMetaModelCommonRO()
+ {
+ if (m_pStgdb->m_MiniMd.IsWritable())
+ {
+ _ASSERTE(!"IMetaModelCommonRO methods cannot be used because this importer is writable.");
+ return NULL;
+ }
+
+ return static_cast<IMetaModelCommonRO*>(&m_pStgdb->m_MiniMd);
+ }
+
+ __checkReturn
+ STDMETHODIMP SetOptimizeAccessForSpeed(// return hresult
+ BOOL fOptSpeed)
+ {
+ // If there is any optional work we can avoid (for example, because we have
+ // traded space for speed) this is the place to turn it off or on.
+
+ return S_OK;
+ }
+
+ //*****************************************************************************
+ // return the count of entries of a given kind in a scope
+ // For example, pass in mdtMethodDef will tell you how many MethodDef
+ // contained in a scope
+ //*****************************************************************************
+ STDMETHODIMP_(ULONG) GetCountWithTokenKind(// return hresult
+ DWORD tkKind) // [IN] pass in the kind of token.
+ DAC_UNEXPECTED();
+
+ //*****************************************************************************
+ // enumerator for typedef
+ //*****************************************************************************
+ __checkReturn
+ STDMETHODIMP EnumTypeDefInit( // return hresult
+ HENUMInternal *phEnum); // [OUT] buffer to fill for enumerator data
+
+ STDMETHODIMP_(ULONG) EnumTypeDefGetCount(
+ HENUMInternal *phEnum); // [IN] the enumerator to retrieve information
+
+ STDMETHODIMP_(void) EnumTypeDefReset(
+ HENUMInternal *phEnum); // [IN] the enumerator to retrieve information
+
+ STDMETHODIMP_(bool) EnumTypeDefNext( // return hresult
+ HENUMInternal *phEnum, // [IN] input enum
+ mdTypeDef *ptd); // [OUT] return token
+
+ STDMETHODIMP_(void) EnumTypeDefClose(
+ HENUMInternal *phEnum); // [IN] the enumerator to retrieve information
+
+ //*****************************************************************************
+ // enumerator for MethodImpl
+ //*****************************************************************************
+ __checkReturn
+ STDMETHODIMP EnumMethodImplInit( // return hresult
+ mdTypeDef td, // [IN] TypeDef over which to scope the enumeration.
+ HENUMInternal *phEnumBody, // [OUT] buffer to fill for enumerator data for MethodBody tokens.
+ HENUMInternal *phEnumDecl) // [OUT] buffer to fill for enumerator data for MethodDecl tokens.
+ DAC_UNEXPECTED();
+
+ STDMETHODIMP_(ULONG) EnumMethodImplGetCount(
+ HENUMInternal *phEnumBody, // [IN] MethodBody enumerator.
+ HENUMInternal *phEnumDecl) // [IN] MethodDecl enumerator.
+ DAC_UNEXPECTED();
+
+ STDMETHODIMP_(void) EnumMethodImplReset(
+ HENUMInternal *phEnumBody, // [IN] MethodBody enumerator.
+ HENUMInternal *phEnumDecl) // [IN] MethodDecl enumerator.
+ DAC_UNEXPECTED();
+
+ __checkReturn
+ STDMETHODIMP EnumMethodImplNext( // return hresult (S_OK = TRUE, S_FALSE = FALSE or error code)
+ HENUMInternal *phEnumBody, // [IN] input enum for MethodBody
+ HENUMInternal *phEnumDecl, // [IN] input enum for MethodDecl
+ mdToken *ptkBody, // [OUT] return token for MethodBody
+ mdToken *ptkDecl) // [OUT] return token for MethodDecl
+ DAC_UNEXPECTED();
+
+ STDMETHODIMP_(void) EnumMethodImplClose(
+ HENUMInternal *phEnumBody, // [IN] MethodBody enumerator.
+ HENUMInternal *phEnumDecl) // [IN] MethodDecl enumerator.
+ DAC_UNEXPECTED();
+
+ //*****************************************
+ // Enumerator helpers for memberdef, memberref, interfaceimp,
+ // event, property, param, methodimpl
+ //*****************************************
+
+ __checkReturn
+ STDMETHODIMP EnumGlobalFunctionsInit( // return hresult
+ HENUMInternal *phEnum); // [OUT] buffer to fill for enumerator data
+
+ __checkReturn
+ STDMETHODIMP EnumGlobalFieldsInit( // return hresult
+ HENUMInternal *phEnum); // [OUT] buffer to fill for enumerator data
+
+
+ __checkReturn
+ STDMETHODIMP EnumInit( // return S_FALSE if record not found
+ DWORD tkKind, // [IN] which table to work on
+ mdToken tkParent, // [IN] token to scope the search
+ HENUMInternal *phEnum); // [OUT] the enumerator to fill
+
+ __checkReturn
+ STDMETHODIMP EnumAllInit( // return S_FALSE if record not found
+ DWORD tkKind, // [IN] which table to work on
+ HENUMInternal *phEnum); // [OUT] the enumerator to fill
+
+ STDMETHODIMP_(bool) EnumNext(
+ HENUMInternal *phEnum, // [IN] the enumerator to retrieve information
+ mdToken *ptk); // [OUT] token to scope the search
+
+ STDMETHODIMP_(ULONG) EnumGetCount(
+ HENUMInternal *phEnum); // [IN] the enumerator to retrieve information
+
+ STDMETHODIMP_(void) EnumReset(
+ HENUMInternal *phEnum); // [IN] the enumerator to be reset
+
+ STDMETHODIMP_(void) EnumClose(
+ HENUMInternal *phEnum); // [IN] the enumerator to be closed
+
+ __checkReturn
+ STDMETHODIMP EnumPermissionSetsInit( // return S_FALSE if record not found
+ mdToken tkParent, // [IN] token to scope the search
+ CorDeclSecurity Action, // [IN] Action to scope the search
+ HENUMInternal *phEnum) // [OUT] the enumerator to fill
+ DAC_UNEXPECTED();
+
+ __checkReturn
+ STDMETHODIMP EnumCustomAttributeByNameInit(// return S_FALSE if record not found
+ mdToken tkParent, // [IN] token to scope the search
+ LPCSTR szName, // [IN] CustomAttribute's name to scope the search
+ HENUMInternal *phEnum); // [OUT] the enumerator to fill
+
+ __checkReturn
+ STDMETHODIMP GetParentToken(
+ mdToken tkChild, // [IN] given child token
+ mdToken *ptkParent); // [OUT] returning parent
+
+ __checkReturn
+ STDMETHODIMP GetCustomAttributeProps(
+ mdCustomAttribute at, // The attribute.
+ mdToken *ptkType); // Put attribute type here.
+
+ __checkReturn
+ STDMETHODIMP GetCustomAttributeAsBlob(
+ mdCustomAttribute cv, // [IN] given custom attribute token
+ void const **ppBlob, // [OUT] return the pointer to internal blob
+ ULONG *pcbSize); // [OUT] return the size of the blob
+
+ __checkReturn
+ STDMETHODIMP GetCustomAttributeByName( // 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.
+
+ __checkReturn
+ STDMETHODIMP GetNameOfCustomAttribute( // S_OK or error.
+ mdCustomAttribute mdAttribute, // [IN] The Custom Attribute
+ LPCUTF8 *pszNamespace, // [OUT] Namespace of Custom Attribute.
+ LPCUTF8 *pszName); // [OUT] Name of Custom Attribute.
+
+ __checkReturn
+ STDMETHODIMP SafeAndSlowEnumCustomAttributeByNameInit(// return S_FALSE if record not found
+ mdToken tkParent, // [IN] token to scope the search
+ LPCSTR szName, // [IN] CustomAttribute's name to scope the search
+ HENUMInternal *phEnum); // [OUT] The enumerator
+
+ __checkReturn
+ STDMETHODIMP SafeAndSlowEnumCustomAttributeByNameNext(// return S_FALSE if record not found
+ mdToken tkParent, // [IN] token to scope the search
+ LPCSTR szName, // [IN] CustomAttribute's name to scope the search
+ HENUMInternal *phEnum, // [IN] The enumerator
+ mdCustomAttribute *mdAttribute); // [OUT] The custom attribute that was found
+
+ // returned void in v1.0/v1.1
+ __checkReturn
+ STDMETHODIMP GetScopeProps(
+ LPCSTR *pszName, // [OUT] scope name
+ GUID *pmvid); // [OUT] version id
+
+ // finding a particular method
+ __checkReturn
+ STDMETHODIMP FindMethodDef(
+ mdTypeDef classdef, // [IN] given typedef
+ LPCSTR szName, // [IN] member name
+ PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of COM+ signature
+ ULONG cbSigBlob, // [IN] count of bytes in the signature blob
+ mdMethodDef *pmd); // [OUT] matching memberdef
+
+ // return a iSeq's param given a MethodDef
+ __checkReturn
+ STDMETHODIMP FindParamOfMethod( // S_OK or error.
+ mdMethodDef md, // [IN] The owning method of the param.
+ ULONG iSeq, // [IN} The sequence # of the param.
+ mdParamDef *pparamdef); // [OUT] Put ParamDef token here.
+
+ //*****************************************
+ //
+ // GetName* functions
+ //
+ //*****************************************
+
+ // return the name and namespace of typedef
+ __checkReturn
+ STDMETHODIMP GetNameOfTypeDef(
+ mdTypeDef classdef, // given classdef
+ LPCSTR *pszname, // return class name(unqualified)
+ LPCSTR *psznamespace); // return the name space name
+
+ __checkReturn
+ STDMETHODIMP GetIsDualOfTypeDef(
+ mdTypeDef classdef, // [IN] given classdef.
+ ULONG *pDual); // [OUT] return dual flag here.
+
+ __checkReturn
+ STDMETHODIMP GetIfaceTypeOfTypeDef(
+ mdTypeDef tkTypeDef,
+ ULONG * pIface); // [OUT] 0=dual, 1=vtable, 2=dispinterface
+
+ __checkReturn
+ STDMETHODIMP GetNameOfMethodDef(
+ mdMethodDef tkMethodDef,
+ LPCSTR * pszName);
+
+ __checkReturn
+ STDMETHODIMP GetNameAndSigOfMethodDef(
+ mdMethodDef methoddef, // [IN] given memberdef
+ PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to a blob value of COM+ signature
+ ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob
+ LPCSTR *pszName);
+
+ // return the name of a FieldDef
+ __checkReturn
+ STDMETHODIMP GetNameOfFieldDef(
+ mdFieldDef fd, // given memberdef
+ LPCSTR *pszName);
+
+ // return the name of typeref
+ __checkReturn
+ STDMETHODIMP GetNameOfTypeRef(
+ mdTypeRef classref, // [IN] given typeref
+ LPCSTR *psznamespace, // [OUT] return typeref name
+ LPCSTR *pszname); // [OUT] return typeref namespace
+
+ // return the resolutionscope of typeref
+ __checkReturn
+ STDMETHODIMP GetResolutionScopeOfTypeRef(
+ mdTypeRef classref, // given classref
+ mdToken *ptkResolutionScope);
+
+ // return the typeref token given the name.
+ __checkReturn
+ STDMETHODIMP FindTypeRefByName(
+ LPCSTR szNamespace, // [IN] Namespace for the TypeRef.
+ LPCSTR szName, // [IN] Name of the TypeRef.
+ mdToken tkResolutionScope, // [IN] Resolution Scope fo the TypeRef.
+ mdTypeRef *ptk); // [OUT] TypeRef token returned.
+
+ // return the TypeDef properties
+ __checkReturn
+ STDMETHODIMP GetTypeDefProps( // return hresult
+ mdTypeDef classdef, // given classdef
+ DWORD *pdwAttr, // return flags on class, tdPublic, tdAbstract
+ mdToken *ptkExtends); // [OUT] Put base class TypeDef/TypeRef here.
+
+ // return the item's guid
+ __checkReturn
+ STDMETHODIMP GetItemGuid( // return hresult
+ mdToken tkObj, // [IN] given item.
+ CLSID *pGuid); // [OUT] Put guid here.
+
+ // get enclosing class of NestedClass.
+ __checkReturn
+ STDMETHODIMP GetNestedClassProps( // S_OK or error
+ mdTypeDef tkNestedClass, // [IN] NestedClass token.
+ mdTypeDef *ptkEnclosingClass); // [OUT] EnclosingClass token.
+
+ // Get count of Nested classes given the enclosing class.
+ __checkReturn
+ STDMETHODIMP GetCountNestedClasses( // return count of Nested classes.
+ mdTypeDef tkEnclosingClass, // [IN]Enclosing class.
+ ULONG *pcNestedClassesCount);
+
+ // Return array of Nested classes given the enclosing class.
+ __checkReturn
+ STDMETHODIMP GetNestedClasses( // Return actual count.
+ mdTypeDef tkEnclosingClass, // [IN] Enclosing class.
+ mdTypeDef *rNestedClasses, // [OUT] Array of nested class tokens.
+ ULONG ulNestedClasses, // [IN] Size of array.
+ ULONG *pcNestedClasses);
+
+ // return the ModuleRef properties
+ __checkReturn
+ STDMETHODIMP GetModuleRefProps(
+ mdModuleRef mur, // [IN] moduleref token
+ LPCSTR *pszName); // [OUT] buffer to fill with the moduleref name
+
+
+ //*****************************************
+ //
+ // GetSig* functions
+ //
+ //*****************************************
+ __checkReturn
+ STDMETHODIMP GetSigOfMethodDef(
+ mdMethodDef methoddef, // [IN] given memberdef
+ ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob
+ PCCOR_SIGNATURE *ppSig);
+
+ __checkReturn
+ STDMETHODIMP GetSigOfFieldDef(
+ mdMethodDef methoddef, // [IN] given memberdef
+ ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob
+ PCCOR_SIGNATURE *ppSig);
+
+ __checkReturn
+ STDMETHODIMP GetSigFromToken(
+ mdToken tk, // FieldDef, MethodDef, Signature or TypeSpec token
+ ULONG * pcbSig,
+ PCCOR_SIGNATURE * ppSig);
+
+
+
+ //*****************************************
+ // get method property
+ //*****************************************
+ __checkReturn
+ STDMETHODIMP GetMethodDefProps(
+ mdMethodDef md, // The method for which to get props.
+ DWORD *pdwFlags);
+
+ STDMETHODIMP_(ULONG) GetMethodDefSlot(
+ mdMethodDef mb); // The method for which to get props.
+
+ //*****************************************
+ // return method implementation informaiton, like RVA and implflags
+ //*****************************************
+ __checkReturn
+ STDMETHODIMP GetMethodImplProps(
+ mdToken tk, // [IN] MethodDef or MethodImpl
+ DWORD *pulCodeRVA, // [OUT] CodeRVA
+ DWORD *pdwImplFlags); // [OUT] Impl. Flags
+
+ //*****************************************************************************
+ // return the field RVA
+ //*****************************************************************************
+ __checkReturn
+ STDMETHODIMP GetFieldRVA(
+ mdToken fd, // [IN] FieldDef
+ ULONG *pulCodeRVA); // [OUT] CodeRVA
+
+ //*****************************************************************************
+ // return the field offset for a given field
+ //*****************************************************************************
+ __checkReturn
+ STDMETHODIMP GetFieldOffset(
+ mdFieldDef fd, // [IN] fielddef
+ ULONG *pulOffset); // [OUT] FieldOffset
+
+ //*****************************************
+ // get field property
+ //*****************************************
+ __checkReturn
+ STDMETHODIMP GetFieldDefProps(
+ mdFieldDef fd, // [IN] given fielddef
+ DWORD *pdwFlags); // [OUT] return fdPublic, fdPrive, etc flags
+
+ //*****************************************************************************
+ // return default value of a token(could be paramdef, fielddef, or property
+ //*****************************************************************************
+ __checkReturn
+ STDMETHODIMP GetDefaultValue(
+ mdToken tk, // [IN] given FieldDef, ParamDef, or Property
+ MDDefaultValue *pDefaultValue); // [OUT] default value to fill
+
+
+ //*****************************************
+ // get dispid of a MethodDef or a FieldDef
+ //*****************************************
+ __checkReturn
+ STDMETHODIMP GetDispIdOfMemberDef( // return hresult
+ mdToken tk, // [IN] given methoddef or fielddef
+ ULONG *pDispid); // [OUT] Put the dispid here.
+
+ //*****************************************
+ // return TypeRef/TypeDef given an InterfaceImpl token
+ //*****************************************
+ __checkReturn
+ STDMETHODIMP GetTypeOfInterfaceImpl( // return the TypeRef/typedef token for the interfaceimpl
+ mdInterfaceImpl iiImpl, // given a interfaceimpl
+ mdToken *ptkType);
+
+ __checkReturn
+ STDMETHODIMP GetMethodSpecProps(
+ mdMethodSpec mi, // [IN] The method instantiation
+ mdToken *tkParent, // [OUT] MethodDef or MemberRef
+ PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to the blob value of meta data
+ ULONG *pcbSigBlob); // [OUT] actual size of signature blob
+
+ //*****************************************
+ // look up function for TypeDef
+ //*****************************************
+ __checkReturn
+ STDMETHODIMP FindTypeDef(
+ LPCSTR szNamespace, // [IN] Namespace for the TypeDef.
+ LPCSTR szName, // [IN] Name of the TypeDef.
+ mdToken tkEnclosingClass, // [IN] TypeDef/TypeRef of enclosing class.
+ mdTypeDef *ptypedef); // [OUT] return typedef
+
+ __checkReturn
+ STDMETHODIMP FindTypeDefByGUID(
+ REFGUID guid, // guid to look up
+ mdTypeDef *ptypedef); // return typedef
+
+
+
+ //*****************************************
+ // return name and sig of a memberref
+ //*****************************************
+ __checkReturn
+ STDMETHODIMP GetNameAndSigOfMemberRef( // return name here
+ mdMemberRef memberref, // given memberref
+ PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to a blob value of COM+ signature
+ ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob
+ LPCSTR *pszName);
+
+ //*****************************************************************************
+ // Given memberref, return the parent. It can be TypeRef, ModuleRef, MethodDef
+ //*****************************************************************************
+ __checkReturn
+ STDMETHODIMP GetParentOfMemberRef(
+ mdMemberRef memberref, // given memberref
+ mdToken *ptkParent); // return the parent token
+
+ __checkReturn
+ STDMETHODIMP GetParamDefProps(
+ mdParamDef paramdef, // given a paramdef
+ USHORT *pusSequence, // [OUT] slot number for this parameter
+ DWORD *pdwAttr, // [OUT] flags
+ LPCSTR *pszName); // [OUT] return the name of the parameter
+
+ //******************************************
+ // property info for method.
+ //******************************************
+ __checkReturn
+ STDMETHODIMP GetPropertyInfoForMethodDef( // Result.
+ mdMethodDef md, // [IN] memberdef
+ mdProperty *ppd, // [OUT] put property token here
+ LPCSTR *pName, // [OUT] put pointer to name here
+ ULONG *pSemantic); // [OUT] put semantic here
+
+ //*****************************************
+ // class layout/sequence information
+ //*****************************************
+ __checkReturn
+ STDMETHODIMP GetClassPackSize( // [OUT] return error if a class doesn't have packsize info
+ mdTypeDef td, // [IN] give typedef
+ ULONG *pdwPackSize); // [OUT] return the pack size of the class. 1, 2, 4, 8 or 16
+
+ __checkReturn
+ STDMETHODIMP GetClassTotalSize( // [OUT] return error if a class doesn't have total size info
+ mdTypeDef td, // [IN] give typedef
+ ULONG *pdwClassSize); // [OUT] return the total size of the class
+
+ __checkReturn
+ STDMETHODIMP GetClassLayoutInit(
+ mdTypeDef td, // [IN] give typedef
+ MD_CLASS_LAYOUT *pLayout); // [OUT] set up the status of query here
+
+ __checkReturn
+ STDMETHODIMP GetClassLayoutNext(
+ MD_CLASS_LAYOUT *pLayout, // [IN|OUT] set up the status of query here
+ mdFieldDef *pfd, // [OUT] return the fielddef
+ ULONG *pulOffset); // [OUT] return the offset/ulSequence associate with it
+
+ //*****************************************
+ // marshal information of a field
+ //*****************************************
+ __checkReturn
+ STDMETHODIMP GetFieldMarshal( // return error if no native type associate with the token
+ mdFieldDef fd, // [IN] given fielddef
+ PCCOR_SIGNATURE *pSigNativeType, // [OUT] the native type signature
+ ULONG *pcbNativeType); // [OUT] the count of bytes of *ppvNativeType
+
+
+ //*****************************************
+ // property APIs
+ //*****************************************
+ // find a property by name
+ __checkReturn
+ STDMETHODIMP FindProperty(
+ mdTypeDef td, // [IN] given a typdef
+ LPCSTR szPropName, // [IN] property name
+ mdProperty *pProp); // [OUT] return property token
+
+ __checkReturn
+ STDMETHODIMP GetPropertyProps(
+ mdProperty prop, // [IN] property token
+ LPCSTR *szProperty, // [OUT] property name
+ DWORD *pdwPropFlags, // [OUT] property flags.
+ PCCOR_SIGNATURE *ppvSig, // [OUT] property type. pointing to meta data internal blob
+ ULONG *pcbSig); // [OUT] count of bytes in *ppvSig
+
+ //**********************************
+ // Event APIs
+ //**********************************
+ __checkReturn
+ STDMETHODIMP FindEvent(
+ mdTypeDef td, // [IN] given a typdef
+ LPCSTR szEventName, // [IN] event name
+ mdEvent *pEvent); // [OUT] return event token
+
+ __checkReturn
+ STDMETHODIMP GetEventProps( // S_OK, S_FALSE, or error.
+ mdEvent ev, // [IN] event token
+ LPCSTR *pszEvent, // [OUT] Event name
+ DWORD *pdwEventFlags, // [OUT] Event flags.
+ mdToken *ptkEventType); // [OUT] EventType class
+
+
+ //**********************************
+ // Generics APIs
+ //**********************************
+ __checkReturn
+ STDMETHODIMP GetGenericParamProps( // S_OK or error.
+ mdGenericParam rd, // [IN] The type parameter
+ ULONG* pulSequence, // [OUT] Parameter sequence number
+ DWORD* pdwAttr, // [OUT] Type parameter flags (for future use)
+ mdToken *ptOwner, // [OUT] The owner (TypeDef or MethodDef)
+ DWORD *reserved, // [OUT] The kind (TypeDef/Ref/Spec, for future use)
+ LPCSTR *szName); // [OUT] The name
+
+ __checkReturn
+ STDMETHODIMP GetGenericParamConstraintProps( // S_OK or error.
+ mdGenericParamConstraint rd, // [IN] The constraint token
+ mdGenericParam *ptGenericParam, // [OUT] GenericParam that is constrained
+ mdToken *ptkConstraintType); // [OUT] TypeDef/Ref/Spec constraint
+
+ //**********************************
+ // find a particular associate of a property or an event
+ //**********************************
+ __checkReturn
+ STDMETHODIMP FindAssociate(
+ mdToken evprop, // [IN] given a property or event token
+ DWORD associate, // [IN] given a associate semantics(setter, getter, testdefault, reset, AddOn, RemoveOn, Fire)
+ mdMethodDef *pmd); // [OUT] return method def token
+
+ __checkReturn
+ STDMETHODIMP EnumAssociateInit(
+ mdToken evprop, // [IN] given a property or an event token
+ HENUMInternal *phEnum); // [OUT] cursor to hold the query result
+
+ __checkReturn
+ STDMETHODIMP GetAllAssociates(
+ HENUMInternal *phEnum, // [IN] query result form GetPropertyAssociateCounts
+ ASSOCIATE_RECORD *pAssociateRec, // [OUT] struct to fill for output
+ ULONG cAssociateRec); // [IN] size of the buffer
+
+
+ //**********************************
+ // Get info about a PermissionSet.
+ //**********************************
+ __checkReturn
+ STDMETHODIMP GetPermissionSetProps(
+ mdPermission pm, // [IN] the permission token.
+ DWORD *pdwAction, // [OUT] CorDeclSecurity.
+ void const **ppvPermission, // [OUT] permission blob.
+ ULONG *pcbPermission); // [OUT] count of bytes of pvPermission.
+
+ //****************************************
+ // Get the String given the String token.
+ // Returns a pointer to the string, or NULL in case of error.
+ //****************************************
+ __checkReturn
+ STDMETHODIMP GetUserString(
+ mdString stk, // [IN] the string token.
+ ULONG *pchString, // [OUT] count of characters in the string.
+ BOOL *pbIs80Plus, // [OUT] specifies where there are extended characters >= 0x80.
+ LPCWSTR *pwszUserString);
+
+ //*****************************************************************************
+ // p-invoke APIs.
+ //*****************************************************************************
+ __checkReturn
+ STDMETHODIMP GetPinvokeMap(
+ mdToken tk, // [IN] FieldDef or MethodDef.
+ DWORD *pdwMappingFlags, // [OUT] Flags used for mapping.
+ LPCSTR *pszImportName, // [OUT] Import name.
+ mdModuleRef *pmrImportDLL); // [OUT] ModuleRef token for the target DLL.
+
+ //*****************************************************************************
+ // Assembly MetaData APIs.
+ //*****************************************************************************
+ __checkReturn
+ STDMETHODIMP GetAssemblyProps(
+ mdAssembly mda, // [IN] The Assembly for which to get the properties.
+ const void **ppbPublicKey, // [OUT] Pointer to the public key.
+ ULONG *pcbPublicKey, // [OUT] Count of bytes in the public key.
+ ULONG *pulHashAlgId, // [OUT] Hash Algorithm.
+ LPCSTR *pszName, // [OUT] Buffer to fill with name.
+ AssemblyMetaDataInternal *pMetaData,// [OUT] Assembly MetaData.
+ DWORD *pdwAssemblyFlags); // [OUT] Flags.
+
+ __checkReturn
+ STDMETHODIMP GetAssemblyRefProps(
+ mdAssemblyRef mdar, // [IN] The AssemblyRef for which to get the properties.
+ const void **ppbPublicKeyOrToken, // [OUT] Pointer to the public key or token.
+ ULONG *pcbPublicKeyOrToken, // [OUT] Count of bytes in the public key or token.
+ LPCSTR *pszName, // [OUT] Buffer to fill with name.
+ AssemblyMetaDataInternal *pMetaData,// [OUT] Assembly MetaData.
+ const void **ppbHashValue, // [OUT] Hash blob.
+ ULONG *pcbHashValue, // [OUT] Count of bytes in the hash blob.
+ DWORD *pdwAssemblyRefFlags); // [OUT] Flags.
+
+ __checkReturn
+ STDMETHODIMP GetFileProps(
+ mdFile mdf, // [IN] The File for which to get the properties.
+ LPCSTR *pszName, // [OUT] Buffer to fill with name.
+ const void **ppbHashValue, // [OUT] Pointer to the Hash Value Blob.
+ ULONG *pcbHashValue, // [OUT] Count of bytes in the Hash Value Blob.
+ DWORD *pdwFileFlags); // [OUT] Flags.
+
+ __checkReturn
+ STDMETHODIMP GetExportedTypeProps(
+ mdExportedType mdct, // [IN] The ExportedType for which to get the properties.
+ LPCSTR *pszNamespace, // [OUT] Buffer to fill with namespace.
+ LPCSTR *pszName, // [OUT] Buffer to fill with name.
+ mdToken *ptkImplementation, // [OUT] mdFile or mdAssemblyRef that provides the ExportedType.
+ mdTypeDef *ptkTypeDef, // [OUT] TypeDef token within the file.
+ DWORD *pdwExportedTypeFlags); // [OUT] Flags.
+
+ __checkReturn
+ STDMETHODIMP GetManifestResourceProps(
+ mdManifestResource mdmr, // [IN] The ManifestResource for which to get the properties.
+ LPCSTR *pszName, // [OUT] Buffer to fill with name.
+ mdToken *ptkImplementation, // [OUT] mdFile or mdAssemblyRef that provides the ExportedType.
+ DWORD *pdwOffset, // [OUT] Offset to the beginning of the resource within the file.
+ DWORD *pdwResourceFlags); // [OUT] Flags.
+
+ __checkReturn
+ STDMETHODIMP FindExportedTypeByName( // S_OK or error
+ LPCSTR szNamespace, // [IN] Namespace of the ExportedType.
+ LPCSTR szName, // [IN] Name of the ExportedType.
+ mdExportedType tkEnclosingType, // [IN] Token for the enclosing Type.
+ mdExportedType *pmct); // [OUT] Put ExportedType token here.
+
+ __checkReturn
+ STDMETHODIMP FindManifestResourceByName(// S_OK or error
+ LPCSTR szName, // [IN] Name of the resource.
+ mdManifestResource *pmmr); // [OUT] Put ManifestResource token here.
+
+ __checkReturn
+ STDMETHODIMP GetAssemblyFromScope( // S_OK or error
+ mdAssembly *ptkAssembly); // [OUT] Put token here.
+
+ //***************************************************************************
+ // return properties regarding a TypeSpec
+ //***************************************************************************
+ __checkReturn
+ STDMETHODIMP GetTypeSpecFromToken( // S_OK or error.
+ mdTypeSpec typespec, // [IN] Signature token.
+ PCCOR_SIGNATURE *ppvSig, // [OUT] return pointer to token.
+ ULONG *pcbSig); // [OUT] return size of signature.
+
+
+ //*****************************************************************************
+ // This function gets the "built for" version of a metadata scope.
+ // NOTE: if the scope has never been saved, it will not have a built-for
+ // version, and an empty string will be returned.
+ //*****************************************************************************
+ __checkReturn
+ STDMETHODIMP GetVersionString( // S_OK or error.
+ LPCSTR *pVer); // [OUT] Put version string here.
+
+
+ //*****************************************************************************
+ // helpers to convert a text signature to a com format
+ //*****************************************************************************
+ __checkReturn
+ STDMETHODIMP ConvertTextSigToComSig( // Return hresult.
+ BOOL fCreateTrIfNotFound, // [IN] create typeref if not found
+ LPCSTR pSignature, // [IN] class file format signature
+ CQuickBytes *pqbNewSig, // [OUT] place holder for COM+ signature
+ ULONG *pcbCount); // [OUT] the result size of signature
+
+ __checkReturn
+ STDMETHODIMP SetUserContextData( // S_OK or E_NOTIMPL
+ IUnknown *pIUnk); // The user context.
+
+ STDMETHODIMP_(BOOL) IsValidToken( // True or False.
+ mdToken tk); // [IN] Given token.
+
+ STDMETHODIMP_(IUnknown *) GetCachedPublicInterface(BOOL fWithLock); // return the cached public interface
+ __checkReturn
+ STDMETHODIMP SetCachedPublicInterface(IUnknown *pUnk); // return hresult
+ STDMETHODIMP_(UTSemReadWrite*) GetReaderWriterLock(); // return the reader writer lock
+ __checkReturn
+ STDMETHODIMP SetReaderWriterLock(UTSemReadWrite *pSem)
+ {
+ _ASSERTE(m_pSemReadWrite == NULL);
+ m_pSemReadWrite = pSem;
+ INDEBUG(m_pStgdb->m_MiniMd.Debug_SetLock(m_pSemReadWrite);)
+ return NOERROR;
+ }
+
+ // *** IMDInternalImportENC methods ***
+ __checkReturn
+ STDMETHODIMP ApplyEditAndContinue( // S_OK or error.
+ MDInternalRW *pDelta); // MD with the ENC delta.
+
+ __checkReturn
+ STDMETHODIMP EnumDeltaTokensInit( // return hresult
+ HENUMInternal *phEnum); // [OUT] buffer to fill for enumerator data
+
+ STDMETHODIMP_(mdModule) GetModuleFromScope(void);
+
+ // finding a particular method
+ __checkReturn
+ STDMETHODIMP FindMethodDefUsingCompare(
+ mdTypeDef classdef, // [IN] given typedef
+ LPCSTR szName, // [IN] member name
+ PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of COM+ signature
+ ULONG cbSigBlob, // [IN] count of bytes in the signature blob
+ PSIGCOMPARE pSignatureCompare, // [IN] Routine to compare signatures
+ void* pSignatureArgs, // [IN] Additional info to supply the compare function
+ mdMethodDef *pmd); // [OUT] matching memberdef
+
+ //*****************************************************************************
+ // return the table pointer and size for a given table index
+ //*****************************************************************************
+ __checkReturn
+ STDMETHODIMP GetTableInfoWithIndex(
+ ULONG index, // [IN] pass in the index
+ void **pTable, // [OUT] pointer to table at index
+ void **pTableSize); // [OUT] size of table at index
+
+ __checkReturn
+ STDMETHODIMP ApplyEditAndContinue(
+ void *pData, // [IN] the delta metadata
+ ULONG cbData, // [IN] length of pData
+ IMDInternalImport **ppv); // [OUT] the resulting metadata interface
+
+
+ FORCEINLINE CLiteWeightStgdbRW* GetMiniStgdb() { return m_pStgdb; }
+ FORCEINLINE UTSemReadWrite *getReaderWriterLock() { return m_pSemReadWrite; }
+
+
+ CLiteWeightStgdbRW *m_pStgdb;
+
+private:
+ mdTypeDef m_tdModule; // <Module> typedef value.
+ LONG m_cRefs; // Ref count.
+ bool m_fOwnStgdb;
+ IUnknown *m_pUnk;
+ IUnknown *m_pUserUnk; // Release at shutdown.
+ IMetaDataHelper *m_pIMetaDataHelper;// pointer to cached public interface
+ UTSemReadWrite *m_pSemReadWrite; // read write lock for multi-threading.
+ bool m_fOwnSem; // Does MDInternalRW own this read write lock object?
+
+public:
+ STDMETHODIMP_(DWORD) GetMetadataStreamVersion()
+ {
+ return (DWORD)m_pStgdb->m_MiniMd.m_Schema.m_minor |
+ ((DWORD)m_pStgdb->m_MiniMd.m_Schema.m_major << 16);
+ };
+
+ __checkReturn
+ STDMETHODIMP SetVerifiedByTrustedSource(// return hresult
+ BOOL fVerified)
+ {
+ m_pStgdb->m_MiniMd.SetVerifiedByTrustedSource(fVerified);
+ return S_OK;
+ }
+
+ 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.
+ {
+ return m_pStgdb->m_MiniMd.GetRvaOffsetData(
+ pFirstMethodRvaOffset,
+ pMethodDefRecordSize,
+ pMethodDefCount,
+ pFirstFieldRvaOffset,
+ pFieldRvaRecordSize,
+ pFieldRvaCount);
+ }
+}; // class MDInternalRW
+
+#endif //FEATURE_METADATA_INTERNAL_APIS
+
+#endif // __MDInternalRW__h__
diff --git a/src/md/inc/mdlog.h b/src/md/inc/mdlog.h
new file mode 100644
index 0000000000..7eb792f9cc
--- /dev/null
+++ b/src/md/inc/mdlog.h
@@ -0,0 +1,25 @@
+// 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.
+//*****************************************************************************
+// MDLog.h - Meta data logging helper.
+//
+
+//
+//*****************************************************************************
+#ifndef __MDLog_h__
+#define __MDLog_h__
+
+#if defined(_DEBUG) && !defined(DACCESS_COMPILE)
+#define LOGGING
+#endif
+
+#include <log.h>
+
+#define LOGMD LF_METADATA, LL_INFO10000
+#define LOG_MDCALL(func) LOG((LF_METADATA, LL_INFO10000, "MD: %s\n", #func))
+
+#define MDSTR(str) ((str) ? str : W("<null>"))
+#define MDSTRA(str) ((str) ? str : "<null>")
+
+#endif // __MDLog_h__
diff --git a/src/md/inc/metadatahash.h b/src/md/inc/metadatahash.h
new file mode 100644
index 0000000000..6fa43dbb99
--- /dev/null
+++ b/src/md/inc/metadatahash.h
@@ -0,0 +1,207 @@
+// 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.
+//*****************************************************************************
+// MetaDataHash.h -- Meta data hash data structures.
+//
+
+//
+// Used by Emitters and by E&C.
+//
+//*****************************************************************************
+#ifndef _MetaDataHash_h_
+#define _MetaDataHash_h_
+
+#if _MSC_VER >= 1100
+ # pragma once
+#endif
+
+#include "utilcode.h"
+
+
+#define REHASH_THREADSHOLD 3
+
+
+//*****************************************************************************
+// A hash entry list item.
+//*****************************************************************************
+struct TOKENHASHENTRY
+{
+ mdToken tok;
+ ULONG ulHash;
+ ULONG iNext;
+};
+
+//*****************************************************************************
+// The following is a hash class definition used for hashing MemberDef. The difference
+// from the hash table above is because it is expansive to retrieve the parent for MemberDef.
+//
+//*****************************************************************************
+struct MEMBERDEFHASHENTRY
+{
+ mdToken tok;
+ mdToken tkParent;
+ ULONG ulHash;
+ ULONG iNext;
+};
+
+
+//*****************************************************************************
+// This class is used to create transient indexes for meta data structures.
+// This class is generic; one must override it to provide hashing and
+// accessor methods for your specific record type. It can start out on top
+// of malloc with a small memory footprint, and as you get larger, it must
+// be capable of rehashing.
+//*****************************************************************************
+template <class Entry> class CMetaDataHashTemplate
+{
+public:
+ CMetaDataHashTemplate()
+ {
+ m_rgBuckets = 0;
+ m_cItems = 0;
+ m_iBuckets = 0;
+ }
+
+ ~CMetaDataHashTemplate()
+ {
+ // Free the bucket list.
+ if (m_rgBuckets)
+ {
+ delete [] m_rgBuckets;
+ m_rgBuckets = 0;
+ m_cItems = 0;
+ m_iBuckets = 0;
+ }
+ }
+
+//*****************************************************************************
+// Called to allocate the hash table entries so that new data may be added.
+//*****************************************************************************
+ HRESULT NewInit( // Return status.
+ int iBuckets=17) // How many buckets you want.
+ {
+ m_rgBuckets = new (nothrow) int[iBuckets];
+ if (!m_rgBuckets)
+ return (OutOfMemory());
+ m_iBuckets = iBuckets;
+ memset(m_rgBuckets, ~0, sizeof(int) * iBuckets);
+ return (S_OK);
+ }
+
+//*****************************************************************************
+// Add new items to the hash list.
+//*****************************************************************************
+ Entry *Add( // Pointer to element to write to.
+ ULONG iHash) // Hash value of entry to add.
+ {
+ Entry *p = 0;
+ HRESULT hr;
+
+ int iBucket = iHash % m_iBuckets;
+
+ if (m_cItems > REHASH_THREADSHOLD * m_iBuckets)
+ {
+ hr = ReHash();
+ if (FAILED(hr))
+ return (0);
+ iBucket = iHash % m_iBuckets;
+ }
+
+ // Add a new item pointer.
+ p = m_Heap.Append();
+ if (!p)
+ return (0);
+
+ // Chain the new item to the front of the heap.
+ p->iNext = m_rgBuckets[iBucket];
+ p->ulHash = iHash;
+ m_cItems++;
+ m_rgBuckets[iBucket] = m_Heap.ItemIndex(p);
+ return (p);
+ }
+
+
+//*****************************************************************************
+// Grow the hash table
+//*****************************************************************************
+ HRESULT ReHash()
+ {
+ int *rgBuckets;
+ int iBuckets;
+ int iBucket;
+ int index;
+ int iCount;
+ Entry *p = 0;
+
+ iBuckets = m_iBuckets*2 -1;
+ rgBuckets = new (nothrow) int[iBuckets];
+ if (!rgBuckets)
+ return (OutOfMemory());
+ memset(rgBuckets, ~0, sizeof(int) * iBuckets);
+
+ // loop through each of data and rehash them
+ iCount = m_Heap.Count();
+ for (index = 0; index < iCount; index++)
+ {
+ // get the hash value of the entry
+ p = m_Heap.Get(index);
+
+ // rehash the entry
+ iBucket = p->ulHash % iBuckets;
+
+ // Chain the item to the front of the new heap.
+ p->iNext = rgBuckets[iBucket];
+ rgBuckets[iBucket] = index;
+ }
+
+ // swap the hash table
+ delete [] m_rgBuckets;
+ m_rgBuckets = rgBuckets;
+ m_iBuckets = iBuckets;
+ return NOERROR;
+
+ }
+
+//*****************************************************************************
+// Find first/find next node for a chain given the hash.
+//*****************************************************************************
+ Entry *FindFirst( // Return entry.
+ ULONG iHash, // The hash value for the entry.
+ int &POS) // Current position.
+ {
+ int iBucket = iHash % m_iBuckets;
+ POS = m_rgBuckets[iBucket];
+ return (FindNext(POS));
+ }
+
+ Entry *FindNext( // Return entry or 0.
+ int &POS) // Current location.
+ {
+ Entry *p;
+
+ if (POS == ~0)
+ return (0);
+
+ p = m_Heap.Get(POS);
+ POS = p->iNext;
+ return (p);
+ }
+
+private:
+ CDynArray<Entry> m_Heap; // First heap in the list.
+ int *m_rgBuckets; // Bucket list.
+ int m_iBuckets; // How many buckets.
+ int m_cItems; // Number of items in the hash
+};
+
+
+class CMetaDataHashBase : public CMetaDataHashTemplate<TOKENHASHENTRY>
+{
+};
+
+class CMemberDefHash : public CMetaDataHashTemplate<MEMBERDEFHASHENTRY>
+{
+};
+
+#endif // _MetaDataHash_h_
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 ------------------------------------------------------------------------
diff --git a/src/md/inc/metamodelro.h b/src/md/inc/metamodelro.h
new file mode 100644
index 0000000000..00d4ead5f9
--- /dev/null
+++ b/src/md/inc/metamodelro.h
@@ -0,0 +1,240 @@
+// 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.
+//*****************************************************************************
+// MetaModelRO.h -- header file for Read-Only compressed COM+ metadata.
+//
+
+//
+// Used by the EE.
+//
+//*****************************************************************************
+#ifndef _METAMODELRO_H_
+#define _METAMODELRO_H_
+
+#if _MSC_VER >= 1100
+ # pragma once
+#endif
+
+#include "metamodel.h"
+
+#include "../heaps/export.h"
+#include "../tables/export.h"
+
+//*****************************************************************************
+// A read-only MiniMd. This is the fastest and smallest possible MiniMd,
+// and as such, is the preferred EE metadata provider.
+//*****************************************************************************
+
+template <class MiniMd> class CLiteWeightStgdb;
+class CMiniMdRW;
+class MDInternalRO;
+class CMiniMd : public CMiniMdTemplate<CMiniMd>
+{
+public:
+ friend class CLiteWeightStgdb<CMiniMd>;
+ friend class CMiniMdTemplate<CMiniMd>;
+ friend class CMiniMdRW;
+ friend class MDInternalRO;
+
+ __checkReturn
+ HRESULT InitOnMem(void *pBuf, ULONG ulBufLen);
+ __checkReturn
+ HRESULT PostInit(int iLevel); // higher number : more checking
+
+ // Returns TRUE if token (tk) is valid.
+ // For user strings, consideres 0 as valid token.
+ BOOL _IsValidToken(
+ mdToken tk) // [IN] token to be checked
+ {
+ if (TypeFromToken(tk) == mdtString)
+ {
+ return m_UserStringHeap.IsValidIndex(RidFromToken(tk));
+ }
+ // Base type doesn't know about user string blob (yet)
+ return _IsValidTokenBase(tk);
+ } // CMiniMdRO::_IsValidToken
+
+ __checkReturn
+ FORCEINLINE HRESULT GetUserString(ULONG nIndex, MetaData::DataBlob *pData)
+ {
+ MINIMD_POSSIBLE_INTERNAL_POINTER_EXPOSED();
+ return m_UserStringHeap.GetBlob(nIndex, pData);
+ }
+
+#ifdef FEATURE_PREJIT
+ void DisableHotDataUsage()
+ {
+ MetaData::HotHeap emptyHotHeap;
+ // Initialize hot data again with empty heap to disable their usage
+ m_StringHeap.InitializeHotData(emptyHotHeap);
+ m_BlobHeap.InitializeHotData(emptyHotHeap);
+ m_UserStringHeap.InitializeHotData(emptyHotHeap);
+ m_GuidHeap.InitializeHotData(emptyHotHeap);
+ // Disable usage of hot table data (throw it away)
+ m_pHotTablesDirectory = NULL;
+ }
+#endif //FEATURE_PREJIT
+
+protected:
+ // Table info.
+ MetaData::TableRO m_Tables[TBL_COUNT];
+#ifdef FEATURE_PREJIT
+ struct MetaData::HotTablesDirectory * m_pHotTablesDirectory;
+#endif //FEATURE_PREJIT
+
+ __checkReturn
+ HRESULT InitializeTables(MetaData::DataBlob tablesData);
+
+ __checkReturn
+ virtual HRESULT vSearchTable(ULONG ixTbl, CMiniColDef sColumn, ULONG ulTarget, RID *pRid);
+ __checkReturn
+ virtual HRESULT vSearchTableNotGreater(ULONG ixTbl, CMiniColDef sColumn, ULONG ulTarget, RID *pRid);
+
+ // Heaps
+ MetaData::StringHeapRO m_StringHeap;
+ MetaData::BlobHeapRO m_BlobHeap;
+ MetaData::BlobHeapRO m_UserStringHeap;
+ MetaData::GuidHeapRO m_GuidHeap;
+
+protected:
+
+ //*************************************************************************
+ // Overridables -- must be provided in derived classes.
+ __checkReturn
+ FORCEINLINE HRESULT Impl_GetString(UINT32 nIndex, __out LPCSTR *pszString)
+ { return m_StringHeap.GetString(nIndex, pszString); }
+ __checkReturn
+ HRESULT Impl_GetStringW(ULONG ix, __inout_ecount (cchBuffer) LPWSTR szOut, ULONG cchBuffer, ULONG *pcchBuffer);
+ __checkReturn
+ FORCEINLINE HRESULT Impl_GetGuid(UINT32 nIndex, GUID *pTargetGuid)
+ {
+ HRESULT hr;
+ GUID UNALIGNED *pSourceGuid;
+ IfFailRet(m_GuidHeap.GetGuid(
+ nIndex,
+ &pSourceGuid));
+ // Add void* casts so that the compiler can't make assumptions about alignment.
+ CopyMemory((void *)pTargetGuid, (void *)pSourceGuid, sizeof(GUID));
+ SwapGuid(pTargetGuid);
+ return S_OK;
+ }
+ __checkReturn
+ FORCEINLINE HRESULT Impl_GetBlob(UINT32 nIndex, __out MetaData::DataBlob *pData)
+ { return m_BlobHeap.GetBlob(nIndex, pData); }
+
+ __checkReturn
+ FORCEINLINE HRESULT Impl_GetRow(
+ UINT32 nTableIndex,
+ UINT32 nRowIndex,
+ __deref_out_opt BYTE **ppRecord)
+ {
+ _ASSERTE(nTableIndex < TBL_COUNT);
+ return m_Tables[nTableIndex].GetRecord(
+ nRowIndex,
+ ppRecord,
+ m_TableDefs[nTableIndex].m_cbRec,
+ m_Schema.m_cRecs[nTableIndex],
+#ifdef FEATURE_PREJIT
+ m_pHotTablesDirectory,
+#endif //FEATURE_PREJIT
+ nTableIndex);
+ }
+
+ // Count of rows in tbl2, pointed to by the column in tbl.
+ __checkReturn
+ HRESULT Impl_GetEndRidForColumn(
+ UINT32 nTableIndex,
+ RID nRowIndex,
+ CMiniColDef &def, // Column containing the RID into other table.
+ UINT32 nTargetTableIndex, // The other table.
+ RID *pEndRid);
+
+ __checkReturn
+ FORCEINLINE HRESULT Impl_SearchTable(ULONG ixTbl, CMiniColDef sColumn, ULONG ixCol, ULONG ulTarget, RID *pFoundRid)
+ {
+ return vSearchTable(ixTbl, sColumn, ulTarget, pFoundRid);
+ }
+
+ // given a rid to the Property table, find an entry in PropertyMap 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);
+ }
+
+ __checkReturn
+ HRESULT FindParentOfPropertyHelper(
+ mdProperty pr,
+ mdTypeDef *ptd)
+ {
+ HRESULT hr = NOERROR;
+
+ RID ridPropertyMap;
+ PropertyMapRec *pRec;
+
+ IfFailRet(FindPropertyMapParentOfProperty(RidFromToken(pr), &ridPropertyMap));
+ IfFailRet(GetPropertyMapRecord(ridPropertyMap, &pRec));
+ *ptd = getParentOfPropertyMap( pRec );
+
+ RidToToken(*ptd, mdtTypeDef);
+
+ return hr;
+ } // HRESULT CMiniMdRW::FindParentOfPropertyHelper()
+
+ // 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);
+ }
+
+ __checkReturn
+ HRESULT FindParentOfEventHelper(
+ mdEvent pr,
+ mdTypeDef *ptd)
+ {
+ HRESULT hr = NOERROR;
+
+ RID ridEventMap;
+ EventMapRec *pRec;
+
+ IfFailRet(FindEventMapParentOfEvent(RidFromToken(pr), &ridEventMap));
+ IfFailRet(GetEventMapRecord(ridEventMap, &pRec));
+ *ptd = getParentOfEventMap( pRec );
+
+ RidToToken(*ptd, mdtTypeDef);
+
+ return hr;
+ } // HRESULT CMiniMdRW::FindParentOfEventHelper()
+
+ FORCEINLINE int Impl_IsRo()
+ { return 1; }
+ //*************************************************************************
+
+ __checkReturn
+ HRESULT CommonEnumCustomAttributeByName( // S_OK or error.
+ mdToken tkObj, // [IN] Object with Custom Attribute.
+ LPCUTF8 szName, // [IN] Name of desired Custom Attribute.
+ bool fStopAtFirstFind, // [IN] just find the first one
+ HENUMInternal* phEnum); // enumerator to fill up
+
+ __checkReturn
+ 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); // [OUT] Put size of data here.
+
+ public:
+ virtual BOOL IsWritable()
+ {
+ return FALSE;
+ }
+
+}; // class CMiniMd
+
+#endif // _METAMODELRO_H_
diff --git a/src/md/inc/metamodelrw.h b/src/md/inc/metamodelrw.h
new file mode 100644
index 0000000000..6e00d3cf3e
--- /dev/null
+++ b/src/md/inc/metamodelrw.h
@@ -0,0 +1,1479 @@
+// 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.
+
+//*****************************************************************************
+// MetaModelRW.h -- header file for Read/Write compressed COM+ metadata.
+//
+
+//
+// Used by Emitters and by E&C.
+//
+//*****************************************************************************
+#ifndef _METAMODELRW_H_
+#define _METAMODELRW_H_
+
+#if _MSC_VER >= 1100
+ # pragma once
+#endif
+
+#include "metamodel.h" // Base classes for the MetaModel.
+#include "metadatahash.h"
+#include "rwutil.h"
+#include "shash.h"
+
+#include "../heaps/export.h"
+#include "../hotdata/export.h"
+#include "../tables/export.h"
+
+struct HENUMInternal;
+#ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE
+struct IMDCustomDataSource;
+#endif
+
+// ENUM for marking bit
+enum
+{
+ InvalidMarkedBit = 0x00000000,
+ ModuleMarkedBit = 0x00000001,
+ TypeRefMarkedBit = 0x00000002,
+ TypeDefMarkedBit = 0x00000004,
+ FieldMarkedBit = 0x00000008,
+ MethodMarkedBit = 0x00000010,
+ ParamMarkedBit = 0x00000020,
+ MemberRefMarkedBit = 0x00000040,
+ CustomAttributeMarkedBit = 0x00000080,
+ DeclSecurityMarkedBit = 0x00000100,
+ SignatureMarkedBit = 0x00000200,
+ EventMarkedBit = 0x00000400,
+ PropertyMarkedBit = 0x00000800,
+ MethodImplMarkedBit = 0x00001000,
+ ModuleRefMarkedBit = 0x00002000,
+ TypeSpecMarkedBit = 0x00004000,
+ InterfaceImplMarkedBit = 0x00008000,
+ AssemblyRefMarkedBit = 0x00010000,
+ MethodSpecMarkedBit = 0x00020000,
+
+};
+
+// entry for marking UserString
+struct FilterUserStringEntry
+{
+ DWORD m_tkString;
+ bool m_fMarked;
+};
+
+class FilterTable : public CDynArray<DWORD>
+{
+public:
+ FilterTable() { m_daUserStringMarker = NULL; }
+ ~FilterTable();
+
+ __checkReturn FORCEINLINE HRESULT MarkTypeRef(mdToken tk) { return MarkToken(tk, TypeRefMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkTypeDef(mdToken tk) { return MarkToken(tk, TypeDefMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkField(mdToken tk) { return MarkToken(tk, FieldMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkMethod(mdToken tk) { return MarkToken(tk, MethodMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkParam(mdToken tk) { return MarkToken(tk, ParamMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkMemberRef(mdToken tk) { return MarkToken(tk, MemberRefMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkCustomAttribute(mdToken tk) { return MarkToken(tk, CustomAttributeMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkDeclSecurity(mdToken tk) { return MarkToken(tk, DeclSecurityMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkSignature(mdToken tk) { return MarkToken(tk, SignatureMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkEvent(mdToken tk) { return MarkToken(tk, EventMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkProperty(mdToken tk) { return MarkToken(tk, PropertyMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkMethodImpl(RID rid)
+ {
+ return MarkToken(TokenFromRid(rid, TBL_MethodImpl << 24), MethodImplMarkedBit);
+ }
+ __checkReturn FORCEINLINE HRESULT MarkModuleRef(mdToken tk) { return MarkToken(tk, ModuleRefMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkTypeSpec(mdToken tk) { return MarkToken(tk, TypeSpecMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkInterfaceImpl(mdToken tk) { return MarkToken(tk, InterfaceImplMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkAssemblyRef(mdToken tk) { return MarkToken(tk, AssemblyRefMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkMethodSpec(mdToken tk) { return MarkToken(tk, MethodSpecMarkedBit); }
+
+ // It may look inconsistent but it is because taht UserString an offset to the heap.
+ // We don't want to grow the FilterTable to the size of the UserString heap.
+ // So we use the heap's marking system instead...
+ //
+ __checkReturn HRESULT MarkUserString(mdString str);
+
+ __checkReturn HRESULT MarkNewUserString(mdString str);
+
+ FORCEINLINE bool IsTypeRefMarked(mdToken tk) { return IsTokenMarked(tk, TypeRefMarkedBit); }
+ FORCEINLINE bool IsTypeDefMarked(mdToken tk) { return IsTokenMarked(tk, TypeDefMarkedBit); }
+ FORCEINLINE bool IsFieldMarked(mdToken tk) { return IsTokenMarked(tk, FieldMarkedBit); }
+ FORCEINLINE bool IsMethodMarked(mdToken tk) { return IsTokenMarked(tk, MethodMarkedBit); }
+ FORCEINLINE bool IsParamMarked(mdToken tk) { return IsTokenMarked(tk, ParamMarkedBit); }
+ FORCEINLINE bool IsMemberRefMarked(mdToken tk) { return IsTokenMarked(tk, MemberRefMarkedBit); }
+ FORCEINLINE bool IsCustomAttributeMarked(mdToken tk) { return IsTokenMarked(tk, CustomAttributeMarkedBit); }
+ FORCEINLINE bool IsDeclSecurityMarked(mdToken tk) { return IsTokenMarked(tk, DeclSecurityMarkedBit); }
+ FORCEINLINE bool IsSignatureMarked(mdToken tk) { return IsTokenMarked(tk, SignatureMarkedBit); }
+ FORCEINLINE bool IsEventMarked(mdToken tk) { return IsTokenMarked(tk, EventMarkedBit); }
+ FORCEINLINE bool IsPropertyMarked(mdToken tk) { return IsTokenMarked(tk, PropertyMarkedBit); }
+ FORCEINLINE bool IsMethodImplMarked(RID rid)
+ {
+ return IsTokenMarked(TokenFromRid(rid, TBL_MethodImpl << 24), MethodImplMarkedBit);
+ }
+ FORCEINLINE bool IsModuleRefMarked(mdToken tk) { return IsTokenMarked(tk, ModuleRefMarkedBit); }
+ FORCEINLINE bool IsTypeSpecMarked(mdToken tk) { return IsTokenMarked(tk, TypeSpecMarkedBit); }
+ FORCEINLINE bool IsInterfaceImplMarked(mdToken tk){ return IsTokenMarked(tk, InterfaceImplMarkedBit); }
+ FORCEINLINE bool IsAssemblyRefMarked(mdToken tk){ return IsTokenMarked(tk, AssemblyRefMarkedBit); }
+ FORCEINLINE bool IsMethodSpecMarked(mdToken tk){ return IsTokenMarked(tk, MethodSpecMarkedBit); }
+
+ bool IsUserStringMarked(mdString str);
+
+ __checkReturn HRESULT UnmarkAll(CMiniMdRW *pMiniMd, ULONG ulSize);
+ __checkReturn HRESULT MarkAll(CMiniMdRW *pMiniMd, ULONG ulSize);
+ bool IsTokenMarked(mdToken);
+
+ __checkReturn FORCEINLINE HRESULT UnmarkTypeDef(mdToken tk) { return UnmarkToken(tk, TypeDefMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT UnmarkField(mdToken tk) { return UnmarkToken(tk, FieldMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT UnmarkMethod(mdToken tk) { return UnmarkToken(tk, MethodMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT UnmarkCustomAttribute(mdToken tk) { return UnmarkToken(tk, CustomAttributeMarkedBit); }
+
+private:
+ CDynArray<FilterUserStringEntry> *m_daUserStringMarker;
+ bool IsTokenMarked(mdToken tk, DWORD bitMarked);
+ __checkReturn HRESULT MarkToken(mdToken tk, DWORD bit);
+ __checkReturn HRESULT UnmarkToken(mdToken tk, DWORD bit);
+}; // class FilterTable : public CDynArray<DWORD>
+
+class CMiniMdRW;
+
+//*****************************************************************************
+// This class is used to keep a list of RID. This list of RID can be sorted
+// base on the m_ixCol's value of the m_ixTbl table.
+//*****************************************************************************
+class VirtualSort
+{
+public:
+ void Init(ULONG ixTbl, ULONG ixCol, CMiniMdRW *pMiniMd);
+ void Uninit();
+ TOKENMAP *m_pMap; // RID for m_ixTbl table. Sorted by on the ixCol
+ bool m_isMapValid;
+ ULONG m_ixTbl; // Table this is a sorter for.
+ ULONG m_ixCol; // Key column in the table.
+ CMiniMdRW *m_pMiniMd; // The MiniMd with the data.
+ __checkReturn
+ HRESULT Sort();
+private:
+ mdToken m_tkBuf;
+ __checkReturn
+ HRESULT SortRange(int iLeft, int iRight);
+public:
+ __checkReturn
+ HRESULT Compare(
+ RID iLeft, // First item to compare.
+ RID iRight, // Second item to compare.
+ int *pnResult); // -1, 0, or 1
+
+private:
+ FORCEINLINE void Swap(
+ RID iFirst,
+ RID iSecond)
+ {
+ if ( iFirst == iSecond ) return;
+ m_tkBuf = *(m_pMap->Get(iFirst));
+ *(m_pMap->Get(iFirst)) = *(m_pMap->Get(iSecond));
+ *(m_pMap->Get(iSecond)) = m_tkBuf;
+ }
+
+
+}; // class VirtualSort
+
+class ReorderData
+{
+public:
+ typedef enum
+ {
+ MinReorderBucketType=0, // bucket# shouldn't be less than this value
+ Undefined=0, // use this for initialization
+ Duplicate=1, // duplicate string
+ ProfileData=2, // bucket# for IBC data
+ PublicData=3, // bucket# for public data
+ OtherData=4, // bucket# for other data
+ NonPublicData=5, // bucket# for non-public data
+ MaxReorderBucketType=255 // bucket# shouldn't exceeed this value
+ } ReorderBucketType;
+};
+
+typedef CMetaDataHashBase CMemberRefHash;
+typedef CMetaDataHashBase CLookUpHash;
+
+class MDTOKENMAP;
+class MDInternalRW;
+class CorProfileData;
+class UTSemReadWrite;
+
+enum MetaDataReorderingOptions {
+ NoReordering=0x0,
+ ReArrangeStringPool=0x1
+};
+
+#ifdef FEATURE_PREJIT
+
+// {0702E333-8D64-4ca7-B564-4AA56B1FCEA3}
+EXTERN_GUID(IID_IMetaDataCorProfileData, 0x702e333, 0x8d64, 0x4ca7, 0xb5, 0x64, 0x4a, 0xa5, 0x6b, 0x1f, 0xce, 0xa3 );
+
+#undef INTERFACE
+#define INTERFACE IMetaDataCorProfileData
+DECLARE_INTERFACE_(IMetaDataCorProfileData, IUnknown)
+{
+ STDMETHOD(SetCorProfileData)(
+ CorProfileData *pProfileData) PURE; // [IN] Pointer to profile data
+};
+
+// {2B464817-C0F6-454e-99E7-C352D8384D7B}
+EXTERN_GUID(IID_IMDInternalMetadataReorderingOptions, 0x2B464817, 0xC0F6, 0x454e, 0x99, 0xE7, 0xC3, 0x52, 0xD8, 0x38, 0x4D, 0x7B );
+
+#undef INTERFACE
+#define INTERFACE IMDInternalMetadataReorderingOptions
+DECLARE_INTERFACE_(IMDInternalMetadataReorderingOptions, IUnknown)
+{
+ STDMETHOD(SetMetaDataReorderingOptions)(
+ MetaDataReorderingOptions options) PURE; // [IN] metadata reordering options
+};
+
+#endif //FEATURE_PREJIT
+
+template <class MiniMd> class CLiteWeightStgdb;
+//*****************************************************************************
+// Read/Write MiniMd.
+//*****************************************************************************
+class CMiniMdRW : public CMiniMdTemplate<CMiniMdRW>
+{
+public:
+ friend class CLiteWeightStgdb<CMiniMdRW>;
+ friend class CLiteWeightStgdbRW;
+ friend class CMiniMdTemplate<CMiniMdRW>;
+ friend class CQuickSortMiniMdRW;
+ friend class VirtualSort;
+ friend class MDInternalRW;
+ friend class RegMeta;
+ friend class FilterTable;
+ friend class ImportHelper;
+ friend class VerifyLayoutsMD;
+
+ CMiniMdRW();
+ ~CMiniMdRW();
+
+ __checkReturn
+ HRESULT InitNew();
+ __checkReturn
+ HRESULT InitOnMem(const void *pBuf, ULONG ulBufLen, int bReadOnly);
+ __checkReturn
+ HRESULT PostInit(int iLevel);
+ __checkReturn
+ HRESULT InitPoolOnMem(int iPool, void *pbData, ULONG cbData, int bReadOnly);
+ __checkReturn
+ HRESULT InitOnRO(CMiniMd *pMd, int bReadOnly);
+#ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE
+ __checkReturn
+ HRESULT InitOnCustomDataSource(IMDCustomDataSource* pDataSouce);
+#endif
+ __checkReturn
+ HRESULT ConvertToRW();
+
+ __checkReturn
+ HRESULT GetSaveSize(
+ CorSaveSize fSave,
+ UINT32 *pcbSize,
+ DWORD *pbCompressed,
+ MetaDataReorderingOptions reorderingOptions = NoReordering,
+ CorProfileData *pProfileData = NULL);
+ int IsPoolEmpty(int iPool);
+ __checkReturn
+ HRESULT GetPoolSaveSize(int iPool, UINT32 *pcbSize);
+
+ __checkReturn
+ HRESULT SaveTablesToStream(IStream *pIStream, MetaDataReorderingOptions reorderingOptions, CorProfileData *pProfileData);
+ __checkReturn
+ HRESULT SavePoolToStream(int iPool, IStream *pIStream);
+ __checkReturn
+ HRESULT SaveDone();
+
+ __checkReturn
+ HRESULT SetHandler(IUnknown *pIUnk);
+
+ __checkReturn
+ HRESULT SetOption(OptionValue *pOptionValue);
+ __checkReturn
+ HRESULT GetOption(OptionValue *pOptionValue);
+
+ static ULONG GetTableForToken(mdToken tkn);
+ static mdToken GetTokenForTable(ULONG ixTbl);
+
+ FORCEINLINE static ULONG TblFromRecId(ULONG ul) { return (ul >> 24)&0x7f; }
+ FORCEINLINE static ULONG RidFromRecId(ULONG ul) { return ul & 0xffffff; }
+ FORCEINLINE static ULONG RecIdFromRid(ULONG rid, ULONG ixTbl) { return rid | ((ixTbl|0x80) << 24); }
+ FORCEINLINE static int IsRecId(ULONG ul) { return (ul & 0x80000000) != 0;}
+
+ // Place in every API function before doing any allocations.
+ __checkReturn
+ FORCEINLINE HRESULT PreUpdate()
+ {
+ if (m_eGrow == eg_grow)
+ {
+ return ExpandTables();
+ }
+ return S_OK;
+ }
+
+ __checkReturn
+ HRESULT AddRecord(
+ UINT32 nTableIndex,
+ void **ppRow,
+ RID *pRid);
+
+ __checkReturn
+ FORCEINLINE HRESULT PutCol(ULONG ixTbl, ULONG ixCol, void *pRecord, ULONG uVal)
+ { _ASSERTE(ixTbl < TBL_COUNT); _ASSERTE(ixCol < m_TableDefs[ixTbl].m_cCols);
+ return PutCol(m_TableDefs[ixTbl].m_pColDefs[ixCol], pRecord, uVal);
+ } // HRESULT CMiniMdRW::PutCol()
+ __checkReturn
+ HRESULT PutString(ULONG ixTbl, ULONG ixCol, void *pRecord, LPCSTR szString);
+ __checkReturn
+ HRESULT PutStringW(ULONG ixTbl, ULONG ixCol, void *pRecord, LPCWSTR wszString);
+ __checkReturn
+ HRESULT PutGuid(ULONG ixTbl, ULONG ixCol, void *pRecord, REFGUID guid);
+ __checkReturn
+ HRESULT ChangeMvid(REFGUID newMvid);
+ __checkReturn
+ HRESULT PutToken(ULONG ixTbl, ULONG ixCol, void *pRecord, mdToken tk);
+ __checkReturn
+ HRESULT PutBlob(ULONG ixTbl, ULONG ixCol, void *pRecord, const void *pvData, ULONG cbData);
+
+ __checkReturn
+ HRESULT PutUserString(MetaData::DataBlob data, UINT32 *pnIndex)
+ { return m_UserStringHeap.AddBlob(data, pnIndex); }
+
+ ULONG GetCol(ULONG ixTbl, ULONG ixCol, void *pRecord);
+ mdToken GetToken(ULONG ixTbl, ULONG ixCol, void *pRecord);
+
+ // Add a record to a table, and return a typed XXXRec *.
+// #undef AddTblRecord
+ #define AddTblRecord(tbl) \
+ __checkReturn HRESULT Add##tbl##Record(tbl##Rec **ppRow, RID *pnRowIndex) \
+ { return AddRecord(TBL_##tbl, reinterpret_cast<void **>(ppRow), pnRowIndex); }
+
+ AddTblRecord(Module)
+ AddTblRecord(TypeRef)
+ __checkReturn HRESULT AddTypeDefRecord( // Specialized implementation.
+ TypeDefRec **ppRow,
+ RID *pnRowIndex);
+ AddTblRecord(Field)
+ __checkReturn HRESULT AddMethodRecord( // Specialized implementation.
+ MethodRec **ppRow,
+ RID *pnRowIndex);
+ AddTblRecord(Param)
+ AddTblRecord(InterfaceImpl)
+ AddTblRecord(MemberRef)
+ AddTblRecord(Constant)
+ AddTblRecord(CustomAttribute)
+ AddTblRecord(FieldMarshal)
+ AddTblRecord(DeclSecurity)
+ AddTblRecord(ClassLayout)
+ AddTblRecord(FieldLayout)
+ AddTblRecord(StandAloneSig)
+ __checkReturn HRESULT AddEventMapRecord( // Specialized implementation.
+ EventMapRec **ppRow,
+ RID *pnRowIndex);
+ AddTblRecord(Event)
+ __checkReturn HRESULT AddPropertyMapRecord( // Specialized implementation.
+ PropertyMapRec **ppRow,
+ RID *pnRowIndex);
+ AddTblRecord(Property)
+ AddTblRecord(MethodSemantics)
+ AddTblRecord(MethodImpl)
+ AddTblRecord(ModuleRef)
+ AddTblRecord(FieldPtr)
+ AddTblRecord(MethodPtr)
+ AddTblRecord(ParamPtr)
+ AddTblRecord(PropertyPtr)
+ AddTblRecord(EventPtr)
+
+ AddTblRecord(ENCLog)
+ AddTblRecord(TypeSpec)
+ AddTblRecord(ImplMap)
+ AddTblRecord(ENCMap)
+ AddTblRecord(FieldRVA)
+
+ // Assembly Tables.
+ AddTblRecord(Assembly)
+ AddTblRecord(AssemblyProcessor)
+ AddTblRecord(AssemblyOS)
+ AddTblRecord(AssemblyRef)
+ AddTblRecord(AssemblyRefProcessor)
+ AddTblRecord(AssemblyRefOS)
+ AddTblRecord(File)
+ AddTblRecord(ExportedType)
+ AddTblRecord(ManifestResource)
+
+ AddTblRecord(NestedClass)
+ AddTblRecord(GenericParam)
+ AddTblRecord(MethodSpec)
+ AddTblRecord(GenericParamConstraint)
+
+ // Specialized AddXxxToYyy() functions.
+ __checkReturn HRESULT AddMethodToTypeDef(RID td, RID md);
+ __checkReturn HRESULT AddFieldToTypeDef(RID td, RID md);
+ __checkReturn HRESULT AddParamToMethod(RID md, RID pd);
+ __checkReturn HRESULT AddPropertyToPropertyMap(RID pmd, RID pd);
+ __checkReturn HRESULT AddEventToEventMap(ULONG emd, RID ed);
+
+ // does the MiniMdRW has the indirect tables, such as FieldPtr, MethodPtr
+ FORCEINLINE int HasIndirectTable(ULONG ix)
+ { if (g_PtrTableIxs[ix].m_ixtbl < TBL_COUNT) return GetCountRecs(g_PtrTableIxs[ix].m_ixtbl); return 0;}
+
+ FORCEINLINE int IsVsMapValid(ULONG ixTbl)
+ { _ASSERTE(ixTbl<TBL_COUNT); return (m_pVS[ixTbl] && m_pVS[ixTbl]->m_isMapValid); }
+
+ // translate index returned by getMethodListOfTypeDef to a rid into Method table
+ __checkReturn
+ FORCEINLINE HRESULT GetMethodRid(ULONG index, ULONG *pRid)
+ {
+ HRESULT hr;
+ if (HasIndirectTable(TBL_Method))
+ {
+ MethodPtrRec *pMethodPtrRecord;
+ IfFailGo(GetMethodPtrRecord(index, &pMethodPtrRecord));
+ *pRid = getMethodOfMethodPtr(pMethodPtrRecord);
+ }
+ else
+ {
+ *pRid = index;
+ }
+ return S_OK;
+ ErrExit:
+ *pRid = 0;
+ return hr;
+ }
+
+ // translate index returned by getFieldListOfTypeDef to a rid into Field table
+ __checkReturn
+ FORCEINLINE HRESULT GetFieldRid(ULONG index, ULONG *pRid)
+ {
+ HRESULT hr;
+ if (HasIndirectTable(TBL_Field))
+ {
+ FieldPtrRec *pFieldPtrRecord;
+ IfFailGo(GetFieldPtrRecord(index, &pFieldPtrRecord));
+ *pRid = getFieldOfFieldPtr(pFieldPtrRecord);
+ }
+ else
+ {
+ *pRid = index;
+ }
+ return S_OK;
+ ErrExit:
+ *pRid = 0;
+ return hr;
+ }
+
+ // translate index returned by getParamListOfMethod to a rid into Param table
+ __checkReturn
+ FORCEINLINE HRESULT GetParamRid(ULONG index, ULONG *pRid)
+ {
+ HRESULT hr;
+ if (HasIndirectTable(TBL_Param))
+ {
+ ParamPtrRec *pParamPtrRecord;
+ IfFailGo(GetParamPtrRecord(index, &pParamPtrRecord));
+ *pRid = getParamOfParamPtr(pParamPtrRecord);
+ }
+ else
+ {
+ *pRid = index;
+ }
+ return S_OK;
+ ErrExit:
+ *pRid = 0;
+ return hr;
+ }
+
+ // translate index returned by getEventListOfEventMap to a rid into Event table
+ __checkReturn
+ FORCEINLINE HRESULT GetEventRid(ULONG index, ULONG *pRid)
+ {
+ HRESULT hr;
+ if (HasIndirectTable(TBL_Event))
+ {
+ EventPtrRec *pEventPtrRecord;
+ IfFailGo(GetEventPtrRecord(index, &pEventPtrRecord));
+ *pRid = getEventOfEventPtr(pEventPtrRecord);
+ }
+ else
+ {
+ *pRid = index;
+ }
+ return S_OK;
+ ErrExit:
+ *pRid = 0;
+ return hr;
+ }
+
+ // translate index returned by getPropertyListOfPropertyMap to a rid into Property table
+ __checkReturn
+ FORCEINLINE HRESULT GetPropertyRid(ULONG index, ULONG *pRid)
+ {
+ HRESULT hr;
+ if (HasIndirectTable(TBL_Property))
+ {
+ PropertyPtrRec *pPropertyPtrRecord;
+ IfFailGo(GetPropertyPtrRecord(index, &pPropertyPtrRecord));
+ *pRid = getPropertyOfPropertyPtr(pPropertyPtrRecord);
+ }
+ else
+ {
+ *pRid = index;
+ }
+ return S_OK;
+ ErrExit:
+ *pRid = 0;
+ return hr;
+ }
+
+ // Convert a pseudo-RID from a Virtual Sort into a real RID.
+ FORCEINLINE ULONG GetRidFromVirtualSort(ULONG ixTbl, ULONG index)
+ { return IsVsMapValid(ixTbl) ? *(m_pVS[ixTbl]->m_pMap->Get(index)) : index; }
+
+ // Index returned by GetInterfaceImplForTypeDef. It could be index to VirtualSort table
+ // or directly to InterfaceImpl
+ FORCEINLINE ULONG GetInterfaceImplRid(ULONG index)
+ { return GetRidFromVirtualSort(TBL_InterfaceImpl, index); }
+
+ // Index returned by GetGenericParamForToken. It could be index to VirtualSort table
+ // or directly to GenericParam
+ FORCEINLINE ULONG GetGenericParamRid(ULONG index)
+ { return GetRidFromVirtualSort(TBL_GenericParam, index); }
+
+ // Index returned by GetGenericParamConstraintForToken. It could be index to VirtualSort table
+ // or directly to GenericParamConstraint
+ FORCEINLINE ULONG GetGenericParamConstraintRid(ULONG index)
+ { return GetRidFromVirtualSort(TBL_GenericParamConstraint, index); }
+
+ // Index returned by GetDeclSecurityForToken. It could be index to VirtualSort table
+ // or directly to DeclSecurity
+ FORCEINLINE ULONG GetDeclSecurityRid(ULONG index)
+ { return GetRidFromVirtualSort(TBL_DeclSecurity, index); }
+
+ // Index returned by GetCustomAttributeForToken. It could be index to VirtualSort table
+ // or directly to CustomAttribute
+ FORCEINLINE ULONG GetCustomAttributeRid(ULONG index)
+ { return GetRidFromVirtualSort(TBL_CustomAttribute, index); }
+
+ // add method, field, property, event, param to the map table
+ __checkReturn HRESULT AddMethodToLookUpTable(mdMethodDef md, mdTypeDef td);
+ __checkReturn HRESULT AddFieldToLookUpTable(mdFieldDef fd, mdTypeDef td);
+ __checkReturn HRESULT AddPropertyToLookUpTable(mdProperty pr, mdTypeDef td);
+ __checkReturn HRESULT AddEventToLookUpTable(mdEvent ev, mdTypeDef td);
+ __checkReturn HRESULT AddParamToLookUpTable(mdParamDef pd, mdMethodDef md);
+
+ // look up the parent of method, field, property, event, or param
+ __checkReturn HRESULT FindParentOfMethodHelper(mdMethodDef md, mdTypeDef *ptd);
+ __checkReturn HRESULT FindParentOfFieldHelper(mdFieldDef fd, mdTypeDef *ptd);
+ __checkReturn HRESULT FindParentOfPropertyHelper(mdProperty pr, mdTypeDef *ptd);
+ __checkReturn HRESULT FindParentOfEventHelper(mdEvent ev, mdTypeDef *ptd);
+ __checkReturn HRESULT FindParentOfParamHelper(mdParamDef pd, mdMethodDef *pmd);
+
+ bool IsMemberDefHashPresent() { return m_pMemberDefHash != NULL; }
+
+ // Function to reorganize the string pool based on IBC profile data (if available) and static analysis.
+ // Throws on error.
+ VOID OrganizeStringPool(CorProfileData *pProfileData);
+
+ // Result of hash search
+ enum HashSearchResult
+ {
+ Found, // Item was found.
+ NotFound, // Item not found.
+ NoTable // Table hasn't been built.
+ };
+
+ // Create MemberRef hash table.
+ __checkReturn
+ HRESULT CreateMemberRefHash();
+
+ // Add a new MemberRef to the hash table.
+ __checkReturn
+ HRESULT AddMemberRefToHash( // Return code.
+ mdMemberRef mr); // Token of new guy.
+
+ // If the hash is built, search for the item. Ignore token *ptkMemberRef.
+ HashSearchResult FindMemberRefFromHash(
+ mdToken tkParent, // Parent token.
+ LPCUTF8 szName, // Name of item.
+ PCCOR_SIGNATURE pvSigBlob, // Signature.
+ ULONG cbSigBlob, // Size of signature.
+ mdMemberRef * ptkMemberRef); // IN: Ignored token. OUT: Return if found.
+
+ //*************************************************************************
+ // Check a given mr token to see if this one is a match.
+ //*************************************************************************
+ __checkReturn
+ HRESULT CompareMemberRefs( // S_OK match, S_FALSE no match.
+ mdMemberRef mr, // Token to check.
+ mdToken tkPar, // Parent token.
+ LPCUTF8 szNameUtf8, // Name of item.
+ PCCOR_SIGNATURE pvSigBlob, // Signature.
+ ULONG cbSigBlob); // Size of signature.
+
+ // Add a new MemberDef to the hash table.
+ __checkReturn
+ HRESULT AddMemberDefToHash(
+ mdToken tkMember, // Token of new guy. It can be MethodDef or FieldDef
+ mdToken tkParent); // Parent token.
+
+ // Create MemberDef Hash
+ __checkReturn
+ HRESULT CreateMemberDefHash();
+
+ // If the hash is built, search for the item. Ignore token *ptkMember.
+ HashSearchResult FindMemberDefFromHash(
+ mdToken tkParent, // Parent token.
+ LPCUTF8 szName, // Name of item.
+ PCCOR_SIGNATURE pvSigBlob, // Signature.
+ ULONG cbSigBlob, // Size of signature.
+ mdToken * ptkMember); // IN: Ignored token. OUT: Return if found. It can be MethodDef or FieldDef
+
+ //*************************************************************************
+ // Check a given Method/Field token to see if this one is a match.
+ //*************************************************************************
+ __checkReturn
+ HRESULT CompareMemberDefs( // S_OK match, S_FALSE no match.
+ mdToken tkMember, // Token to check. It can be MethodDef or FieldDef
+ mdToken tkParent, // Parent token recorded in the hash entry
+ mdToken tkPar, // Parent token.
+ LPCUTF8 szNameUtf8, // Name of item.
+ PCCOR_SIGNATURE pvSigBlob, // Signature.
+ ULONG cbSigBlob); // Size of signature.
+
+ //*************************************************************************
+ // Add a new CustomAttributes to the hash table.
+ //*************************************************************************
+ __checkReturn
+ HRESULT AddCustomAttributesToHash( // Return code.
+ mdCustomAttribute cv) // Token of new guy.
+ { return GenericAddToHash(TBL_CustomAttribute, CustomAttributeRec::COL_Parent, RidFromToken(cv)); }
+
+ inline ULONG HashMemberRef(mdToken tkPar, LPCUTF8 szName)
+ {
+ ULONG l = HashBytes((const BYTE *) &tkPar, sizeof(mdToken)) + HashStringA(szName);
+ return (l);
+ }
+
+ inline ULONG HashMemberDef(mdToken tkPar, LPCUTF8 szName)
+ {
+ return HashMemberRef(tkPar, szName);
+ }
+
+ // helper to calculate the hash value given a token
+ inline ULONG HashCustomAttribute(mdToken tkObject)
+ {
+ return HashToken(tkObject);
+ }
+
+ CMemberRefHash *m_pMemberRefHash;
+
+ // Hash table for Methods and Fields
+ CMemberDefHash *m_pMemberDefHash;
+
+ // helper to calculate the hash value given a pair of tokens
+ inline ULONG HashToken(mdToken tkObject)
+ {
+ ULONG l = HashBytes((const BYTE *) &tkObject, sizeof(mdToken));
+ return (l);
+ }
+
+
+ //*************************************************************************
+ // Add a new FieldMarhsal Rid to the hash table.
+ //*************************************************************************
+ __checkReturn
+ HRESULT AddFieldMarshalToHash( // Return code.
+ RID rid) // Token of new guy.
+ { return GenericAddToHash(TBL_FieldMarshal, FieldMarshalRec::COL_Parent, rid); }
+
+ //*************************************************************************
+ // Add a new Constant Rid to the hash table.
+ //*************************************************************************
+ __checkReturn
+ HRESULT AddConstantToHash( // Return code.
+ RID rid) // Token of new guy.
+ { return GenericAddToHash(TBL_Constant, ConstantRec::COL_Parent, rid); }
+
+ //*************************************************************************
+ // Add a new MethodSemantics Rid to the hash table.
+ //*************************************************************************
+ __checkReturn
+ HRESULT AddMethodSemanticsToHash( // Return code.
+ RID rid) // Token of new guy.
+ { return GenericAddToHash(TBL_MethodSemantics, MethodSemanticsRec::COL_Association, rid); }
+
+ //*************************************************************************
+ // Add a new ClassLayout Rid to the hash table.
+ //*************************************************************************
+ __checkReturn
+ HRESULT AddClassLayoutToHash( // Return code.
+ RID rid) // Token of new guy.
+ { return GenericAddToHash(TBL_ClassLayout, ClassLayoutRec::COL_Parent, rid); }
+
+ //*************************************************************************
+ // Add a new FieldLayout Rid to the hash table.
+ //*************************************************************************
+ __checkReturn
+ HRESULT AddFieldLayoutToHash( // Return code.
+ RID rid) // Token of new guy.
+ { return GenericAddToHash(TBL_FieldLayout, FieldLayoutRec::COL_Field, rid); }
+
+ //*************************************************************************
+ // Add a new ImplMap Rid to the hash table.
+ //*************************************************************************
+ __checkReturn
+ HRESULT AddImplMapToHash( // Return code.
+ RID rid) // Token of new guy.
+ { return GenericAddToHash(TBL_ImplMap, ImplMapRec::COL_MemberForwarded, rid); }
+
+ //*************************************************************************
+ // Add a new FieldRVA Rid to the hash table.
+ //*************************************************************************
+ __checkReturn
+ HRESULT AddFieldRVAToHash( // Return code.
+ RID rid) // Token of new guy.
+ { return GenericAddToHash(TBL_FieldRVA, FieldRVARec::COL_Field, rid); }
+
+ //*************************************************************************
+ // Add a new nested class Rid to the hash table.
+ //*************************************************************************
+ __checkReturn
+ HRESULT AddNestedClassToHash( // Return code.
+ RID rid) // Token of new guy.
+ { return GenericAddToHash(TBL_NestedClass, NestedClassRec::COL_NestedClass, rid); }
+
+ //*************************************************************************
+ // Add a new MethodImpl Rid to the hash table.
+ //*************************************************************************
+ __checkReturn
+ HRESULT AddMethodImplToHash( // Return code.
+ RID rid) // Token of new guy.
+ { return GenericAddToHash(TBL_MethodImpl, MethodImplRec::COL_Class, rid); }
+
+
+ //*************************************************************************
+ // Build a hash table for the specified table if the size exceed the thresholds.
+ //*************************************************************************
+ __checkReturn
+ HRESULT GenericBuildHashTable( // Return code.
+ ULONG ixTbl, // Table with hash
+ ULONG ixCol); // col that we hash.
+
+ //*************************************************************************
+ // Add a rid from a table into a hash
+ //*************************************************************************
+ __checkReturn
+ HRESULT GenericAddToHash( // Return code.
+ ULONG ixTbl, // Table with hash
+ ULONG ixCol, // col that we hash.
+ RID rid); // new row of the table.
+
+ //*************************************************************************
+ // Add a rid from a table into a hash
+ //*************************************************************************
+ __checkReturn
+ HRESULT GenericFindWithHash( // Return code.
+ ULONG ixTbl, // Table with hash
+ ULONG ixCol, // col that we hash.
+ mdToken tkTarget, // token to be find in the hash
+ RID *pFoundRid);
+
+
+ // look up hash table for tokenless tables.
+ // They are constant, FieldMarshal, MethodSemantics, ClassLayout, FieldLayout, ImplMap, FieldRVA, NestedClass, and MethodImpl
+ CLookUpHash * m_pLookUpHashs[TBL_COUNT];
+
+#if defined(FEATURE_PREJIT) && !defined(DACCESS_COMPILE)
+ MapSHash<UINT32, UINT32> m_StringPoolOffsetHash;
+#endif
+
+ //*************************************************************************
+ // Hash for named items.
+ //*************************************************************************
+ __checkReturn
+ HRESULT AddNamedItemToHash( // Return code.
+ ULONG ixTbl, // Table with the new item.
+ mdToken tk, // Token of new guy.
+ LPCUTF8 szName, // Name of item.
+ mdToken tkParent); // Token of parent, if any.
+
+ HashSearchResult FindNamedItemFromHash(
+ ULONG ixTbl, // Table with the item.
+ LPCUTF8 szName, // Name of item.
+ mdToken tkParent, // Token of parent, if any.
+ mdToken * ptk); // Return if found.
+
+ __checkReturn
+ HRESULT CompareNamedItems( // S_OK match, S_FALSE no match.
+ ULONG ixTbl, // Table with the item.
+ mdToken tk, // Token to check.
+ LPCUTF8 szName, // Name of item.
+ mdToken tkParent); // Token of parent, if any.
+
+ FORCEINLINE ULONG HashNamedItem(mdToken tkPar, LPCUTF8 szName)
+ { return HashBytes((const BYTE *) &tkPar, sizeof(mdToken)) + HashStringA(szName); }
+
+ CMetaDataHashBase *m_pNamedItemHash;
+
+ //*****************************************************************************
+ // IMetaModelCommon - RW specific versions for some of the functions.
+ //*****************************************************************************
+ __checkReturn
+ virtual HRESULT CommonGetEnclosingClassOfTypeDef(
+ mdTypeDef td,
+ mdTypeDef *ptkEnclosingTypeDef)
+ {
+ _ASSERTE(ptkEnclosingTypeDef != NULL);
+
+ HRESULT hr;
+ NestedClassRec *pRec;
+ RID iRec;
+
+ IfFailRet(FindNestedClassHelper(td, &iRec));
+ if (iRec == 0)
+ {
+ *ptkEnclosingTypeDef = mdTypeDefNil;
+ return S_OK;
+ }
+
+ IfFailRet(GetNestedClassRecord(iRec, &pRec));
+ *ptkEnclosingTypeDef = getEnclosingClassOfNestedClass(pRec);
+ return S_OK;
+ }
+
+ __checkReturn
+ HRESULT CommonEnumCustomAttributeByName( // S_OK or error.
+ mdToken tkObj, // [IN] Object with Custom Attribute.
+ LPCUTF8 szName, // [IN] Name of desired Custom Attribute.
+ bool fStopAtFirstFind, // [IN] just find the first one
+ HENUMInternal* phEnum); // enumerator to fill up
+
+ __checkReturn
+ 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); // [OUT] Put size of data here.
+
+ //*****************************************************************************
+ // Find helper for a constant.
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindConstantHelper( // return index to the constant table
+ mdToken tkParent, // Parent token. Can be ParamDef, FieldDef, or Property.
+ RID *pFoundRid);
+
+ //*****************************************************************************
+ // Find helper for a FieldMarshal.
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindFieldMarshalHelper( // return index to the field marshal table
+ mdToken tkParent, // Parent token. Can be a FieldDef or ParamDef.
+ RID *pFoundRid);
+
+ //*****************************************************************************
+ // Find helper for a method semantics.
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindMethodSemanticsHelper( // return HRESULT
+ mdToken tkAssociate, // Event or property token
+ HENUMInternal *phEnum); // fill in the enum
+
+ //*****************************************************************************
+ // Find helper for a method semantics given a associate and semantics.
+ // This will look up methodsemantics based on its status!
+ // Return CLDB_E_RECORD_NOTFOUND if cannot find the matching one
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindAssociateHelper(// return HRESULT
+ mdToken tkAssociate, // Event or property token
+ DWORD dwSemantics, // [IN] given a associate semantics(setter, getter, testdefault, reset)
+ RID *pRid); // [OUT] return matching row index here
+
+ //*****************************************************************************
+ // Find helper for a MethodImpl.
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindMethodImplHelper(// return HRESULT
+ mdTypeDef td, // TypeDef token for the Class.
+ HENUMInternal *phEnum); // fill in the enum
+
+ //*****************************************************************************
+ // Find helper for a GenericParams
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindGenericParamHelper( // Return HRESULT
+ mdToken tkOwner, // Token for the GenericParams' owner
+ HENUMInternal *phEnum); // Fill in the enum.
+
+ //*****************************************************************************
+ // Find helper for a Generic Constraints
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindGenericParamConstraintHelper( // Return HRESULT
+ mdGenericParam tkParam, // Token for the GenericParam
+ HENUMInternal *phEnum); // Fill in the enum.
+
+ //*****************************************************************************
+ // Find helper for a ClassLayout.
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindClassLayoutHelper( // return index to the ClassLayout table
+ mdTypeDef tkParent, // Parent token.
+ RID *pFoundRid);
+
+ //*****************************************************************************
+ // Find helper for a FieldLayout.
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindFieldLayoutHelper( // return index to the FieldLayout table
+ mdFieldDef tkField, // Token for the field.
+ RID *pFoundRid);
+
+ //*****************************************************************************
+ // Find helper for a ImplMap.
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindImplMapHelper( // return index to the constant table
+ mdToken tk, // Member forwarded token.
+ RID *pFoundRid);
+
+ //*****************************************************************************
+ // Find helper for a FieldRVA.
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindFieldRVAHelper( // return index to the FieldRVA table
+ mdFieldDef tkField, // Token for the field.
+ RID *pFoundRid);
+
+ //*****************************************************************************
+ // Find helper for a NestedClass.
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindNestedClassHelper( // return index to the NestedClass table
+ mdTypeDef tkClass, // Token for the NestedClass.
+ RID *pFoundRid);
+
+ //*****************************************************************************
+ // IMPORTANT!!!!!!!! Use these set of functions if you are dealing with RW rather
+ // getInterfaceImplsForTypeDef, getDeclSecurityForToken, etc.
+ // The following functions can deal with these tables when they are not sorted and
+ // build the VirtualSort tables for quick lookup.
+ //*****************************************************************************
+ __checkReturn
+ HRESULT GetInterfaceImplsForTypeDef(mdTypeDef td, RID *pRidStart, RID *pRidEnd = 0)
+ {
+ return LookUpTableByCol( RidFromToken(td), m_pVS[TBL_InterfaceImpl], pRidStart, pRidEnd);
+ }
+
+ __checkReturn
+ HRESULT GetGenericParamsForToken(mdToken tk, RID *pRidStart, RID *pRidEnd = 0)
+ {
+ return LookUpTableByCol(
+ encodeToken(RidFromToken(tk), TypeFromToken(tk), mdtTypeOrMethodDef, lengthof(mdtTypeOrMethodDef)),
+ m_pVS[TBL_GenericParam], pRidStart, pRidEnd);
+ }
+
+ __checkReturn
+ HRESULT GetGenericParamConstraintsForToken(mdToken tk, RID *pRidStart, RID *pRidEnd = 0)
+ {
+ return LookUpTableByCol( RidFromToken(tk),
+ m_pVS[TBL_GenericParamConstraint], pRidStart, pRidEnd);
+ }
+
+ __checkReturn
+ HRESULT GetMethodSpecsForToken(mdToken tk, RID *pRidStart, RID *pRidEnd = 0)
+ {
+ return LookUpTableByCol(
+ encodeToken(RidFromToken(tk), TypeFromToken(tk), mdtMethodDefOrRef, lengthof(mdtMethodDefOrRef)),
+ m_pVS[TBL_MethodSpec], pRidStart, pRidEnd);
+ }
+
+ __checkReturn
+ HRESULT GetDeclSecurityForToken(mdToken tk, RID *pRidStart, RID *pRidEnd = 0)
+ {
+ return LookUpTableByCol(
+ encodeToken(RidFromToken(tk), TypeFromToken(tk), mdtHasDeclSecurity, lengthof(mdtHasDeclSecurity)),
+ m_pVS[TBL_DeclSecurity],
+ pRidStart,
+ pRidEnd);
+ }
+
+ __checkReturn
+ HRESULT GetCustomAttributeForToken(mdToken tk, RID *pRidStart, RID *pRidEnd = 0)
+ {
+ return LookUpTableByCol(
+ encodeToken(RidFromToken(tk), TypeFromToken(tk), mdtHasCustomAttribute, lengthof(mdtHasCustomAttribute)),
+ m_pVS[TBL_CustomAttribute],
+ pRidStart,
+ pRidEnd);
+ }
+
+ __checkReturn
+ FORCEINLINE HRESULT GetUserString(ULONG nIndex, MetaData::DataBlob *pData)
+ { return m_UserStringHeap.GetBlob(nIndex, pData); }
+ // Gets user string (*Data) at index (nIndex) and fills the index (*pnNextIndex) of the next user string
+ // in the heap.
+ // Returns S_OK and fills the string (*pData) and the next index (*pnNextIndex).
+ // Returns S_FALSE if the index (nIndex) is not valid user string index.
+ // Returns error code otherwise.
+ // Clears *pData and sets *pnNextIndex to 0 on error or S_FALSE.
+ __checkReturn
+ HRESULT GetUserStringAndNextIndex(
+ UINT32 nIndex,
+ MetaData::DataBlob *pData,
+ UINT32 *pnNextIndex);
+
+ FORCEINLINE int IsSorted(ULONG ixTbl) { return m_Schema.IsSorted(ixTbl);}
+ FORCEINLINE int IsSortable(ULONG ixTbl) { return m_bSortable[ixTbl];}
+ FORCEINLINE bool HasDelete() { return ((m_Schema.m_heaps & CMiniMdSchema::HAS_DELETE) ? true : false); }
+ FORCEINLINE int IsPreSaveDone() { return m_bPreSaveDone; }
+
+protected:
+ __checkReturn HRESULT PreSave(MetaDataReorderingOptions reorderingOptions=NoReordering, CorProfileData *pProfileData=NULL);
+ __checkReturn HRESULT PostSave();
+
+ __checkReturn HRESULT PreSaveFull();
+ __checkReturn HRESULT PreSaveEnc();
+
+ __checkReturn HRESULT GetFullPoolSaveSize(int iPool, UINT32 *pcbSize);
+ __checkReturn HRESULT GetENCPoolSaveSize(int iPool, UINT32 *pcbSize);
+
+ __checkReturn HRESULT SaveFullPoolToStream(int iPool, IStream *pIStream);
+ __checkReturn HRESULT SaveENCPoolToStream(int iPool, IStream *pIStream);
+
+ __checkReturn
+ HRESULT GetHotMetadataTokensSearchAware(
+ CorProfileData *pProfileData,
+ ULONG ixTbl,
+ ULONG *pResultCount,
+ mdToken *tokenBuffer,
+ ULONG maxCount);
+
+ __checkReturn
+ HRESULT GetFullSaveSize(
+ CorSaveSize fSave,
+ UINT32 *pcbSize,
+ DWORD *pbCompressed,
+ MetaDataReorderingOptions reorderingOptions = NoReordering,
+ CorProfileData *pProfileData = NULL);
+ __checkReturn
+ HRESULT GetENCSaveSize(UINT32 *pcbSize);
+ __checkReturn
+ HRESULT GetHotPoolsSaveSize(
+ UINT32 *pcbSize,
+ MetaDataReorderingOptions reorderingOptions,
+ CorProfileData *pProfileData);
+
+ __checkReturn
+ HRESULT SaveFullTablesToStream(IStream *pIStream, MetaDataReorderingOptions reorderingOptions=NoReordering, CorProfileData *pProfileData = NULL );
+ __checkReturn
+ HRESULT SaveENCTablesToStream(IStream *pIStream);
+ __checkReturn
+ HRESULT SaveHotPoolsToStream(
+ IStream *pStream,
+ MetaDataReorderingOptions reorderingOptions,
+ CorProfileData *pProfileData,
+ UINT32 *pnPoolDirSize,
+ UINT32 *pnSavedPoolsSize);
+ __checkReturn
+ HRESULT SaveHotPoolToStream(
+ IStream *pStream,
+ CorProfileData *pProfileData,
+ MetaData::HotHeapWriter *pHotHeapWriter,
+ UINT32 *pnSavedSize);
+
+ // TO ELIMINATE:
+ __checkReturn
+ HRESULT AddGuid(REFGUID pGuid, UINT32 *pnIndex)
+ { return m_GuidHeap.AddGuid(&pGuid, pnIndex); }
+
+ // Allows putting into tables outside this MiniMd, specifically the temporary
+ // table used on save.
+ __checkReturn
+ HRESULT PutCol(CMiniColDef ColDef, void *pRecord, ULONG uVal);
+
+ // Returns TRUE if token (tk) is valid.
+ // For user strings, consideres 0 as valid token.
+ BOOL _IsValidToken(
+ mdToken tk) // [IN] token to be checked
+ {
+ if (TypeFromToken(tk) == mdtString)
+ {
+ // need to check the user string heap
+ return m_UserStringHeap.IsValidIndex(RidFromToken(tk));
+ }
+ // Base type doesn't know about user string blob (yet)
+ return _IsValidTokenBase(tk);
+ } // CMiniMdRW::_IsValidToken
+
+#ifdef _DEBUG
+ bool CanHaveCustomAttribute(ULONG ixTbl);
+#endif
+
+ __checkReturn
+ HRESULT ExpandTables();
+ __checkReturn
+ HRESULT ExpandTableColumns(CMiniMdSchema &Schema, ULONG ixTbl);
+
+ __checkReturn
+ HRESULT InitWithLargeTables();
+
+ void ComputeGrowLimits(int bSmall=TRUE); // Set max, lim, based on param.
+ ULONG m_maxRid; // Highest RID so far allocated.
+ ULONG m_limRid; // Limit on RID before growing.
+ ULONG m_maxIx; // Highest pool index so far.
+ ULONG m_limIx; // Limit on pool index before growing.
+ enum {eg_ok, eg_grow, eg_grown} m_eGrow; // Is a grow required? done?
+ #define AUTO_GROW_CODED_TOKEN_PADDING 5
+
+ // fix up these tables after PreSave has move the tokens
+ __checkReturn HRESULT FixUpTable(ULONG ixTbl);
+ __checkReturn HRESULT FixUpRefToDef();
+
+ // Table info.
+ MetaData::TableRW m_Tables[TBL_COUNT];
+ VirtualSort *m_pVS[TBL_COUNT]; // Virtual sorters, one per table, but sparse.
+
+ //*****************************************************************************
+ // look up a table by a col given col value is ulVal.
+ //*****************************************************************************
+ __checkReturn
+ HRESULT LookUpTableByCol(
+ ULONG ulVal,
+ VirtualSort *pVSTable,
+ RID *pRidStart,
+ RID *pRidEnd);
+
+ __checkReturn
+ HRESULT Impl_SearchTableRW(ULONG ixTbl, ULONG ixCol, ULONG ulTarget, RID *pFoundRid);
+ __checkReturn
+ virtual HRESULT vSearchTable(ULONG ixTbl, CMiniColDef sColumn, ULONG ulTarget, RID *pRid);
+ __checkReturn
+ virtual HRESULT vSearchTableNotGreater(ULONG ixTbl, CMiniColDef sColumn, ULONG ulTarget, RID *pRid);
+
+ void SetSorted(ULONG ixTbl, int bSorted)
+ { m_Schema.SetSorted(ixTbl, bSorted); }
+
+ void SetPreSaveDone(int bPreSaveDone)
+ { m_bPreSaveDone = bPreSaveDone; }
+
+ // Heaps
+ MetaData::StringHeapRW m_StringHeap;
+ MetaData::BlobHeapRW m_BlobHeap;
+ MetaData::BlobHeapRW m_UserStringHeap;
+ MetaData::GuidHeapRW m_GuidHeap;
+
+ IMapToken *m_pHandler; // Remap handler.
+ __checkReturn HRESULT MapToken(RID from, RID to, mdToken type);
+
+ ULONG m_cbSaveSize; // Estimate of save size.
+
+ int m_fIsReadOnly : 1; // Is this db read-only?
+ int m_bPreSaveDone : 1; // Has save optimization been done?
+ int m_bSaveCompressed : 1; // Can the data be saved as fully compressed?
+ int m_bPostGSSMod : 1; // true if a change was made post GetSaveSize.
+
+
+ //*************************************************************************
+ // Overridables -- must be provided in derived classes.
+ __checkReturn
+ FORCEINLINE HRESULT Impl_GetString(UINT32 nIndex, __out LPCSTR *pszString)
+ { return m_StringHeap.GetString(nIndex, pszString); }
+ __checkReturn
+ HRESULT Impl_GetStringW(ULONG ix, __inout_ecount (cchBuffer) LPWSTR szOut, ULONG cchBuffer, ULONG *pcchBuffer);
+ __checkReturn
+ FORCEINLINE HRESULT Impl_GetGuid(UINT32 nIndex, GUID *pTargetGuid)
+ {
+ HRESULT hr;
+ GUID UNALIGNED *pSourceGuid;
+ IfFailRet(m_GuidHeap.GetGuid(
+ nIndex,
+ &pSourceGuid));
+ // Add void* casts so that the compiler can't make assumptions about alignment.
+ CopyMemory((void *)pTargetGuid, (void *)pSourceGuid, sizeof(GUID));
+ SwapGuid(pTargetGuid);
+ return S_OK;
+ }
+
+ __checkReturn
+ FORCEINLINE HRESULT Impl_GetBlob(ULONG nIndex, __out MetaData::DataBlob *pData)
+ { return m_BlobHeap.GetBlob(nIndex, pData); }
+
+ __checkReturn
+ FORCEINLINE HRESULT Impl_GetRow(
+ UINT32 nTableIndex,
+ UINT32 nRowIndex,
+ __deref_out_opt BYTE **ppRecord)
+ {
+ _ASSERTE(nTableIndex < TBL_COUNT);
+ return m_Tables[nTableIndex].GetRecord(nRowIndex, ppRecord);
+ }
+
+ // Count of rows in tbl2, pointed to by the column in tbl.
+ __checkReturn
+ HRESULT Impl_GetEndRidForColumn(
+ UINT32 nTableIndex,
+ RID nRowIndex,
+ CMiniColDef &def, // Column containing the RID into other table.
+ UINT32 nTargetTableIndex, // The other table.
+ RID *pEndRid);
+
+ __checkReturn
+ FORCEINLINE HRESULT Impl_SearchTable(ULONG ixTbl, CMiniColDef sColumn, ULONG ixCol, ULONG ulTarget, RID *pFoundRid)
+ { return Impl_SearchTableRW(ixTbl, ixCol, ulTarget, pFoundRid); }
+
+ FORCEINLINE int Impl_IsRo()
+ { return 0; }
+
+
+ //*************************************************************************
+ enum {END_OF_TABLE = 0};
+ FORCEINLINE ULONG NewRecordPointerEndValue(ULONG ixTbl)
+ { if (HasIndirectTable(ixTbl)) return m_Schema.m_cRecs[ixTbl]+1; else return END_OF_TABLE; }
+
+ __checkReturn HRESULT ConvertMarkerToEndOfTable(ULONG tblParent, ULONG colParent, ULONG ridChild, RID ridParent);
+
+ // Add a child row, adjust pointers in parent rows.
+ __checkReturn
+ HRESULT AddChildRowIndirectForParent(
+ ULONG tblParent,
+ ULONG colParent,
+ ULONG tblChild,
+ RID ridParent,
+ void **ppRow);
+
+ // Update pointers in the parent table to reflect the addition of a child, if required
+ // create the indirect table in which case don't update pointers.
+ __checkReturn
+ HRESULT AddChildRowDirectForParent(ULONG tblParent, ULONG colParent, ULONG tblChild, RID ridParent);
+
+ // Given a table id, create the corresponding indirect table.
+ __checkReturn
+ HRESULT CreateIndirectTable(ULONG ixtbl, BOOL bOneLess = true);
+
+ // If the last param is not added in the right sequence, fix it up.
+ __checkReturn
+ HRESULT FixParamSequence(RID md);
+
+
+ // these are the map tables to map a method, a field, a property, a event, or a param to its parent
+ TOKENMAP *m_pMethodMap;
+ TOKENMAP *m_pFieldMap;
+ TOKENMAP *m_pPropertyMap;
+ TOKENMAP *m_pEventMap;
+ TOKENMAP *m_pParamMap;
+
+ // This table keep tracks tokens that are marked( or filtered)
+ FilterTable *m_pFilterTable;
+ IHostFilter *m_pHostFilter;
+
+ // TOKENMAP *m_pTypeRefToTypeDefMap;
+ TokenRemapManager *m_pTokenRemapManager;
+
+ OptionValue m_OptionValue;
+
+ CMiniMdSchema m_StartupSchema; // Schema at start time. Keep count of records.
+ BYTE m_bSortable[TBL_COUNT]; // Is a given table sortable? (Can it be reorganized?)
+#ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE
+ ReleaseHolder<IMDCustomDataSource> m_pCustomDataSource;
+#endif
+
+#ifdef _DEBUG
+
+protected:
+ UTSemReadWrite * dbg_m_pLock;
+
+public:
+ // Checks that MetaData is locked for write operation (if thread-safety is enabled and the lock exists)
+ void Debug_CheckIsLockedForWrite();
+
+ void Debug_SetLock(UTSemReadWrite * pLock)
+ {
+ dbg_m_pLock = pLock;
+ }
+
+#endif //_DEBUG
+
+public:
+
+ FilterTable *GetFilterTable();
+ __checkReturn HRESULT UnmarkAll();
+ __checkReturn HRESULT MarkAll();
+
+ FORCEINLINE IHostFilter *GetHostFilter() { return m_pHostFilter;}
+
+ __checkReturn HRESULT CalculateTypeRefToTypeDefMap();
+
+ FORCEINLINE TOKENMAP *GetTypeRefToTypeDefMap()
+ { return m_pTokenRemapManager ? m_pTokenRemapManager->GetTypeRefToTypeDefMap() : NULL; };
+
+ FORCEINLINE TOKENMAP *GetMemberRefToMemberDefMap()
+ { return m_pTokenRemapManager ? m_pTokenRemapManager->GetMemberRefToMemberDefMap() : NULL; };
+
+ FORCEINLINE MDTOKENMAP *GetTokenMovementMap()
+ { return m_pTokenRemapManager ? m_pTokenRemapManager->GetTokenMovementMap() : NULL; };
+
+ FORCEINLINE TokenRemapManager *GetTokenRemapManager() { return m_pTokenRemapManager; };
+
+ __checkReturn HRESULT InitTokenRemapManager();
+
+ virtual ULONG vGetCol(ULONG ixTbl, ULONG ixCol, void *pRecord)
+ { return GetCol(ixTbl, ixCol, pRecord);}
+
+public:
+ virtual BOOL IsWritable()
+ {
+ return !m_fIsReadOnly;
+ }
+
+
+ //*************************************************************************
+ // Delta MetaData (EditAndContinue) functions.
+public:
+ enum eDeltaFuncs{
+ eDeltaFuncDefault = 0,
+ eDeltaMethodCreate,
+ eDeltaFieldCreate,
+ eDeltaParamCreate,
+ eDeltaPropertyCreate,
+ eDeltaEventCreate,
+ };
+
+ __checkReturn HRESULT ApplyDelta(CMiniMdRW &mdDelta);
+
+public:
+ // Functions for updating ENC log tables ENC log.
+ FORCEINLINE BOOL IsENCOn()
+ {
+ return (m_OptionValue.m_UpdateMode & MDUpdateMask) == MDUpdateENC;
+ }
+
+ __checkReturn
+ FORCEINLINE HRESULT UpdateENCLog(mdToken tk, CMiniMdRW::eDeltaFuncs funccode = CMiniMdRW::eDeltaFuncDefault)
+ {
+ if (IsENCOn())
+ return UpdateENCLogHelper(tk, funccode);
+ else
+ return S_OK;
+ }
+
+ __checkReturn
+ FORCEINLINE HRESULT UpdateENCLog2(ULONG ixTbl, ULONG iRid, CMiniMdRW::eDeltaFuncs funccode = CMiniMdRW::eDeltaFuncDefault)
+ {
+ if (IsENCOn())
+ return UpdateENCLogHelper2(ixTbl, iRid, funccode);
+ else
+ return S_OK;
+ }
+
+ __checkReturn HRESULT ResetENCLog();
+
+private:
+ BOOL m_fMinimalDelta;
+
+ //
+ // String heap reorganization
+ //
+
+ // Check to see if it is safe to reorder the string pool.
+ BOOL IsSafeToReorderStringPool();
+ // Function to mark hot strings in the marks array based on the token information in profile data.
+ VOID MarkHotStrings(CorProfileData *pProfileData, BYTE * pMarks, ULONG poolSize);
+ // Function to mark hot strings referenced by hot tables based on token information in profile data.
+ VOID MarkStringsInHotTables(CorProfileData *pProfileData, BYTE * pMarks, ULONG poolSize);
+ // Function to mark strings referenced by the different metadata tables.
+ VOID MarkStringsInTables(BYTE * pMarks, ULONG poolSize);
+ // Function to mark duplicate strings in the mark array.
+ // Throws on error.
+ VOID MarkDuplicateStrings(BYTE * pMarks, ULONG poolSize);
+ // Function to update the tables with the modified string offsets.
+ VOID FixStringsInTables();
+ // Function to fill the given string pool with strings from the existing string pool using the mark array.
+ // Throws on error.
+ VOID CreateReorderedStringPool(
+ MetaData::StringHeapRW *pStringHeap,
+ BYTE *pMarks,
+ ULONG cbHeapSize,
+ CorProfileData *pProfileData);
+
+public:
+ BOOL IsMinimalDelta()
+ {
+ return m_fMinimalDelta;
+ }
+
+
+ // Turns on/off the ability to emit delta metadatas
+
+ // Unfortunately, we can't allow this to be set via the SetOption method anymore. In v1.0 and v1.1, this flag
+ // could be set but would still result in generating full metadatas. We can't automatically start generating
+ // true deltas for people... it could break them.
+ void EnableDeltaMetadataGeneration()
+ {
+ _ASSERTE(m_OptionValue.m_UpdateMode == MDUpdateENC);
+#ifndef FEATURE_CORECLR
+ if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_UseMinimalDeltas))
+ m_OptionValue.m_UpdateMode = MDUpdateDelta;
+#endif //!FEATURE_CORECLR
+ }
+ void DisableDeltaMetadataGeneration() {m_OptionValue.m_UpdateMode = MDUpdateENC;}
+
+protected:
+ // Internal Helper functions for ENC log.
+ __checkReturn
+ HRESULT UpdateENCLogHelper(mdToken tk, CMiniMdRW::eDeltaFuncs funccode);
+ __checkReturn
+ HRESULT UpdateENCLogHelper2(ULONG ixTbl, ULONG iRid, CMiniMdRW::eDeltaFuncs funccode);
+
+protected:
+ static ULONG m_TruncatedEncTables[];
+ static ULONG m_SuppressedDeltaColumns[TBL_COUNT];
+
+ ULONGARRAY *m_rENCRecs; // Array of RIDs affected by ENC.
+
+ __checkReturn
+ HRESULT ApplyRecordDelta(CMiniMdRW &mdDelta, ULONG ixTbl, void *pDelta, void *pRecord);
+ __checkReturn
+ HRESULT ApplyTableDelta(CMiniMdRW &mdDelta, ULONG ixTbl, RID iRid, int fc);
+ __checkReturn
+ HRESULT GetDeltaRecord(ULONG ixTbl, ULONG iRid, void **ppRecord);
+ __checkReturn
+ HRESULT ApplyHeapDeltas(CMiniMdRW &mdDelta);
+ __checkReturn
+ HRESULT ApplyHeapDeltasWithMinimalDelta(CMiniMdRW &mdDelta);
+ __checkReturn
+ HRESULT ApplyHeapDeltasWithFullDelta(CMiniMdRW &mdDelta);
+ __checkReturn
+ HRESULT StartENCMap(); // Call, on a delta MD, to prepare to access sparse rows.
+ __checkReturn
+ HRESULT EndENCMap(); // Call, on a delta MD, when done with sparse rows.
+
+public:
+ // Workaround for compiler performance issue VSW 584653 for 2.0 RTM.
+ // Get the table's VirtualSort validity state.
+ bool IsTableVirtualSorted(ULONG ixTbl);
+ // Workaround for compiler performance issue VSW 584653 for 2.0 RTM.
+ // Validate table's VirtualSort after adding one record into the table.
+ // Returns new VirtualSort validity state in *pfIsTableVirtualSortValid.
+ // Assumptions:
+ // Table's VirtualSort was valid before adding the record to the table.
+ // The caller must ensure validity of VirtualSort by calling to
+ // IsTableVirtualSorted or by using the returned state from previous
+ // call to this method.
+ __checkReturn
+ HRESULT ValidateVirtualSortAfterAddRecord(
+ ULONG ixTbl,
+ bool * pfIsTableVirtualSortValid);
+
+}; // class CMiniMdRW : public CMiniMdTemplate<CMiniMdRW>
+
+#endif // _METAMODELRW_H_
diff --git a/src/md/inc/recordpool.h b/src/md/inc/recordpool.h
new file mode 100644
index 0000000000..36bd67a656
--- /dev/null
+++ b/src/md/inc/recordpool.h
@@ -0,0 +1,161 @@
+// 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.
+//*****************************************************************************
+// RecordPool.h -- header file for record heaps.
+//
+
+//
+//*****************************************************************************
+#ifndef _RECORDPOOL_H_
+#define _RECORDPOOL_H_
+
+#if _MSC_VER >= 1100
+#pragma once
+#endif
+
+#include <stgpool.h>
+
+//*****************************************************************************
+// This Record pool class collects user Records into a big consecutive heap.
+// The list of Records is kept in memory while adding, and
+// finally flushed to a stream at the caller's request.
+//*****************************************************************************
+class RecordPool : public StgPool
+{
+ friend class VerifyLayoutsMD;
+
+ using StgPool::InitNew;
+ using StgPool::InitOnMem;
+
+public:
+ RecordPool() :
+ StgPool(1024, 1)
+ { }
+
+//*****************************************************************************
+// Init the pool for use. This is called for the create empty case.
+//*****************************************************************************
+ __checkReturn
+ HRESULT InitNew(
+ UINT32 cbRec, // Record size.
+ UINT32 cRecsInit); // Initial guess of count of record.
+
+//*****************************************************************************
+// Load a Record heap from persisted memory. If a copy of the data is made
+// (so that it may be updated), then a new hash table is generated which can
+// be used to elminate duplicates with new Records.
+//*****************************************************************************
+ __checkReturn
+ HRESULT InitOnMem(
+ ULONG cbRec, // Record size.
+ void *pData, // Predefined data.
+ ULONG iSize, // Size of data.
+ BOOL fReadOnly); // true if append is forbidden.
+
+//*****************************************************************************
+// Allocate memory if we don't have any, or grow what we have. If successful,
+// then at least iRequired bytes will be allocated.
+//*****************************************************************************
+ bool Grow( // true if successful.
+ ULONG iRequired); // Min required bytes to allocate.
+
+//*****************************************************************************
+// The Record will be added to the pool. The index of the Record in the pool
+// is returned in *piIndex. If the Record is already in the pool, then the
+// index will be to the existing copy of the Record.
+//*****************************************************************************
+ HRESULT AddRecord(
+ BYTE **ppRecord,
+ UINT32 *pnIndex); // Return 1-based index of Record here.
+
+//*****************************************************************************
+// Insert a Record into the pool. The index of the Record before which to
+// insert is specified. Shifts all records down. Return a pointer to the
+// new record.
+//*****************************************************************************
+ HRESULT InsertRecord(
+ UINT32 nIndex, // [IN] Insert record before this.
+ BYTE **ppRecord);
+
+//*****************************************************************************
+// Return a pointer to a Record given an index previously handed out by
+// AddRecord or FindRecord.
+//*****************************************************************************
+ __checkReturn
+ virtual HRESULT GetRecord(
+ UINT32 nIndex, // 1-based index of Record in pool.
+ BYTE **ppRecord);
+
+//*****************************************************************************
+// Given a pointer to a record, determine the index corresponding to the
+// record.
+//*****************************************************************************
+ virtual ULONG GetIndexForRecord( // 1-based index of Record in pool.
+ const void *pRecord); // Pointer to Record in pool.
+
+//*****************************************************************************
+// Given a purported pointer to a record, determine if the pointer is valid.
+//*****************************************************************************
+ virtual int IsValidPointerForRecord( // true or false.
+ const void *pRecord); // Pointer to Record in pool.
+
+//*****************************************************************************
+// How many objects are there in the pool? If the count is 0, you don't need
+// to persist anything at all to disk.
+//*****************************************************************************
+ UINT32 Count()
+ { return GetNextOffset() / m_cbRec; }
+
+//*****************************************************************************
+// Indicate if heap is empty. This has to be based on the size of the data
+// we are keeping. If you open in r/o mode on memory, there is no hash
+// table.
+//*****************************************************************************
+ virtual int IsEmpty() // true if empty.
+ { return (GetNextOffset() == 0); }
+
+//*****************************************************************************
+// Is the index valid for the Record?
+//*****************************************************************************
+ virtual int IsValidCookie(ULONG ulCookie)
+ { return (ulCookie == 0 || IsValidOffset((ulCookie-1) * m_cbRec)); }
+
+//*****************************************************************************
+// Return the size of the heap.
+//*****************************************************************************
+ ULONG GetNextIndex()
+ { return (GetNextOffset() / m_cbRec); }
+
+//*****************************************************************************
+// Replace the contents of this pool with those from another pool. The other
+// pool loses ownership of the memory.
+//*****************************************************************************
+ __checkReturn
+ HRESULT ReplaceContents(
+ RecordPool *pOther); // The other record pool.
+
+//*****************************************************************************
+// Return the first record in a pool, and set up a context for fast
+// iterating through the pool. Note that this scheme does pretty minimal
+// error checking.
+//*****************************************************************************
+ void *GetFirstRecord( // Pointer to Record in pool.
+ void **pContext); // Store context here.
+
+//*****************************************************************************
+// Given a pointer to a record, return a pointer to the next record.
+// Note that this scheme does pretty minimal error checking. In particular,
+// this will let the caller walk off of the end of valid data in the last
+// segment.
+//*****************************************************************************
+ void *GetNextRecord( // Pointer to Record in pool.
+ void *pRecord, // Current record.
+ void **pContext); // Stored context here.
+
+private:
+ UINT32 m_cbRec; // How large is each record?
+
+}; // class RecordPool
+
+#endif // _RECORDPOOL_H_
diff --git a/src/md/inc/rwutil.h b/src/md/inc/rwutil.h
new file mode 100644
index 0000000000..5d7f98919c
--- /dev/null
+++ b/src/md/inc/rwutil.h
@@ -0,0 +1,369 @@
+// 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.
+//*****************************************************************************
+// RWUtil.h
+//
+
+//
+// Contains utility code for MD directory
+//
+//*****************************************************************************
+#ifndef __RWUtil__h__
+#define __RWUtil__h__
+
+class UTSemReadWrite;
+
+#define UTF8STR(wszInput, szOutput) \
+ do { \
+ if ((wszInput) == NULL) \
+ { \
+ (szOutput) = NULL; \
+ } \
+ else \
+ { \
+ int cbBuffer = ((int)wcslen(wszInput) * 3) + 1; \
+ (szOutput) = (char *)_alloca(cbBuffer); \
+ Unicode2UTF((wszInput), (szOutput), cbBuffer); \
+ } \
+ } while (0)
+
+//*****************************************************************************
+// Helper methods
+//*****************************************************************************
+void
+Unicode2UTF(
+ LPCWSTR wszSrc, // The string to convert.
+ __out_ecount(cbDst)
+ LPUTF8 szDst, // Buffer for the output UTF8 string.
+ int cbDst); // Size of the buffer for UTF8 string.
+
+//*********************************************************************
+// The token remap record.
+//*********************************************************************
+struct TOKENREC
+{
+ mdToken m_tkFrom; // The imported token
+ bool m_isDuplicate; // Is record duplicate? This information is recorded during merge
+ bool m_isDeleted; // This information is recorded during RegMeta::ProcessFilter when we might have deleted a record
+ bool m_isFoundInImport; // This information is also recorded during RegMeta::ProcessFilter
+ mdToken m_tkTo; // The new token in the merged scope
+
+ void SetEmpty() {m_tkFrom = m_tkTo = (mdToken) -1;}
+ BOOL IsEmpty() {return m_tkFrom == (mdToken) -1;}
+};
+
+
+//*********************************************************************
+//
+// This structure keeps track on token remap for an imported scope. This map is initially sorted by from
+// tokens. It can then become sorted by To tokens. This usually happen during PreSave remap lookup. Thus
+// we assert if we try to look up or sort by From token.
+//
+//*********************************************************************
+class MDTOKENMAP : public CDynArray<TOKENREC>
+{
+public:
+
+ enum SortKind{
+ Unsorted = 0,
+ SortByFromToken = 1,
+ SortByToToken = 2,
+ Indexed = 3, // Indexed by table/rid. Implies that strings are sorted by "From".
+ };
+
+ MDTOKENMAP()
+ : m_pNextMap(NULL),
+ m_pMap(NULL),
+ m_iCountTotal(0),
+ m_iCountSorted(0),
+ m_sortKind(SortByFromToken),
+ m_iCountIndexed(0)
+#if defined(_DEBUG)
+ ,m_pImport(0)
+#endif
+ { }
+ ~MDTOKENMAP();
+
+ HRESULT Init(IUnknown *pImport);
+
+ // find a token in the tokenmap.
+ bool Find(mdToken tkFrom, TOKENREC **ppRec);
+
+ // remap a token. We assert if we don't find the tkFind in the table
+ HRESULT Remap(mdToken tkFrom, mdToken *ptkTo);
+
+ // Insert a record. This function will keep the inserted record in a sorted sequence
+ HRESULT InsertNotFound(mdToken tkFrom, bool fDuplicate, mdToken tkTo, TOKENREC **ppRec);
+
+ // This function will just append the record to the end of the list
+ HRESULT AppendRecord(
+ mdToken tkFrom,
+ bool fDuplicate,
+ mdToken tkTo,
+ TOKENREC **ppRec);
+
+ // This is a safe remap. *tpkTo will be tkFind if we cannot find tkFind in the lookup table.
+ mdToken SafeRemap(mdToken tkFrom); // [IN] the token value to find
+
+ bool FindWithToToken(
+ mdToken tkFind, // [IN] the token value to find
+ int *piPosition); // [OUT] return the first from-token that has the matching to-token
+
+ FORCEINLINE void SortTokensByFromToken()
+ {
+ _ASSERTE(m_sortKind == SortByFromToken || m_sortKind == Indexed);
+ // Only sort if there are unsorted records.
+ if (m_iCountSorted < m_iCountTotal)
+ {
+ SortRangeFromToken(m_iCountIndexed, m_iCountIndexed+m_iCountTotal - 1);
+ m_iCountSorted = m_iCountTotal;
+ }
+ } // void MDTOKENMAP::SortTokensByFromToken()
+
+ HRESULT EmptyMap();
+
+ void SortTokensByToToken();
+
+ MDTOKENMAP *m_pNextMap;
+ IMapToken *m_pMap;
+
+private:
+ FORCEINLINE int CompareFromToken( // -1, 0, or 1
+ int iLeft, // First item to compare.
+ int iRight) // Second item to compare.
+ {
+ if ( Get(iLeft)->m_tkFrom < Get(iRight)->m_tkFrom )
+ return -1;
+ if ( Get(iLeft)->m_tkFrom == Get(iRight)->m_tkFrom )
+ return 0;
+ return 1;
+ }
+
+ FORCEINLINE int CompareToToken( // -1, 0, or 1
+ int iLeft, // First item to compare.
+ int iRight) // Second item to compare.
+ {
+ if ( Get(iLeft)->m_tkTo < Get(iRight)->m_tkTo )
+ return -1;
+ if ( Get(iLeft)->m_tkTo == Get(iRight)->m_tkTo )
+ return 0;
+ return 1;
+ }
+
+ FORCEINLINE void Swap(
+ int iFirst,
+ int iSecond)
+ {
+ if ( iFirst == iSecond ) return;
+ memcpy( &m_buf, Get(iFirst), sizeof(TOKENREC) );
+ memcpy( Get(iFirst), Get(iSecond),sizeof(TOKENREC) );
+ memcpy( Get(iSecond), &m_buf, sizeof(TOKENREC) );
+ }
+
+ void SortRangeFromToken(int iLeft, int iRight);
+ void SortRangeToToken(int iLeft, int iRight);
+
+ TOKENREC m_buf;
+ ULONG m_iCountTotal; // total entry in the map
+ ULONG m_iCountSorted; // number of entries that are sorted
+
+ SortKind m_sortKind;
+
+ ULONG m_TableOffset[TBL_COUNT+1]; // Start of each table in map.
+ ULONG m_iCountIndexed; // number of entries that are indexed.
+#if defined(_DEBUG)
+ IMetaDataImport *m_pImport; // For data validation.
+#endif
+};
+
+
+
+//*********************************************************************
+//
+// Merge Token manager. This class is created in GetSaveSize as an agent to
+// notify linker regarding token movements. It does not have the ability to
+// keep track token movement.
+//
+//*********************************************************************
+class MergeTokenManager : public IMapToken
+{
+public:
+ STDMETHODIMP QueryInterface(REFIID riid, PVOID *pp);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+ STDMETHODIMP Map(mdToken tkImp, mdToken tkEmit);
+ MergeTokenManager(MDTOKENMAP *pTkMapList, IUnknown *pHandler);
+ virtual ~MergeTokenManager();
+private:
+ LONG m_cRef;
+ MDTOKENMAP *m_pTkMapList;
+ IMapToken *m_pDefaultHostRemap;
+};
+
+
+
+//*********************************************************************
+//
+// This CMapToken class implemented the IMapToken. It is used in RegMeta for
+// filter process. This class can track all of the tokens are mapped. It also
+// supplies a Find function.
+//
+//*********************************************************************
+class CMapToken : public IMapToken
+{
+ friend class RegMeta;
+
+public:
+ STDMETHODIMP QueryInterface(REFIID riid, PVOID *pp);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+ STDMETHODIMP Map(mdToken tkImp, mdToken tkEmit);
+ bool Find(mdToken tkFrom, TOKENREC **pRecTo);
+ CMapToken();
+ virtual ~CMapToken();
+ MDTOKENMAP *m_pTKMap;
+private:
+ LONG m_cRef;
+ bool m_isSorted;
+};
+
+typedef CDynArray<mdToken> TOKENMAP;
+
+//*********************************************************************
+//
+// This class records all sorts of token movement during optimization phase.
+// This including Ref to Def optimization. This also includes token movement
+// due to sorting or eleminating the pointer tables.
+//
+//*********************************************************************
+class TokenRemapManager
+{
+public:
+ //*********************************************************************
+ //
+ // This function is called when a TypeRef is resolved to a TypeDef.
+ //
+ //*********************************************************************
+ FORCEINLINE void RecordTypeRefToTypeDefOptimization(
+ mdToken tkFrom,
+ mdToken tkTo)
+ {
+ _ASSERTE( TypeFromToken(tkFrom) == mdtTypeRef );
+ _ASSERTE( TypeFromToken(tkTo) == mdtTypeDef );
+
+ m_TypeRefToTypeDefMap[RidFromToken(tkFrom)] = tkTo;
+ } // RecordTypeRefToTypeDefOptimization
+
+
+ //*********************************************************************
+ //
+ // This function is called when a MemberRef is resolved to a MethodDef or FieldDef.
+ //
+ //*********************************************************************
+ FORCEINLINE void RecordMemberRefToMemberDefOptimization(
+ mdToken tkFrom,
+ mdToken tkTo)
+ {
+ _ASSERTE( TypeFromToken(tkFrom) == mdtMemberRef );
+ _ASSERTE( TypeFromToken(tkTo) == mdtMethodDef || TypeFromToken(tkTo) == mdtFieldDef);
+
+ m_MemberRefToMemberDefMap[RidFromToken(tkFrom)] = tkTo;
+ } // RecordMemberRefToMemberDefOptimization
+
+ //*********************************************************************
+ //
+ // This function is called when the token kind does not change but token
+ // is moved. For example, when we sort CustomAttribute table or when we optimize
+ // away MethodPtr table. These operation will not change the token type.
+ //
+ //*********************************************************************
+ FORCEINLINE HRESULT RecordTokenMovement(
+ mdToken tkFrom,
+ mdToken tkTo)
+ {
+ TOKENREC *pTokenRec;
+
+ _ASSERTE( TypeFromToken(tkFrom) == TypeFromToken(tkTo) );
+ return m_TKMap.AppendRecord( tkFrom, false, tkTo, &pTokenRec );
+ } // RecordTokenMovement
+
+ bool ResolveRefToDef(
+ mdToken tkRef, // [IN] ref token
+ mdToken *ptkDef); // [OUT] def token that it resolves to. If it does not resolve to a def
+
+ FORCEINLINE TOKENMAP *GetTypeRefToTypeDefMap() { return &m_TypeRefToTypeDefMap; }
+ FORCEINLINE TOKENMAP *GetMemberRefToMemberDefMap() { return &m_MemberRefToMemberDefMap; }
+ FORCEINLINE MDTOKENMAP *GetTokenMovementMap() { return &m_TKMap; }
+
+ ~TokenRemapManager();
+ HRESULT ClearAndEnsureCapacity(ULONG cTypeRef, ULONG cMemberRef);
+private:
+ MDTOKENMAP m_TKMap;
+ TOKENMAP m_TypeRefToTypeDefMap;
+ TOKENMAP m_MemberRefToMemberDefMap;
+}; // class TokenRemapManager
+
+// value that can be set by SetOption APIs
+struct OptionValue
+{
+ CorCheckDuplicatesFor m_DupCheck; // Bit Map for checking duplicates during emit.
+ CorRefToDefCheck m_RefToDefCheck; // Bit Map for specifying whether to do a ref to def optimization.
+ CorNotificationForTokenMovement m_NotifyRemap; // Bit Map for token remap notification.
+ ULONG m_UpdateMode; // (CorSetENC) Specifies whether ENC or Extension mode is on.
+ CorErrorIfEmitOutOfOrder m_ErrorIfEmitOutOfOrder; // Do not generate pointer tables
+ CorThreadSafetyOptions m_ThreadSafetyOptions; // specify if thread safety is turn on or not.
+ CorImportOptions m_ImportOption; // import options such as to skip over deleted items or not
+ CorLinkerOptions m_LinkerOption; // Linker option. Currently only used in UnmarkAll
+ BOOL m_GenerateTCEAdapters; // Do not generate the TCE adapters for COM CPC.
+ LPSTR m_RuntimeVersion; // CLR Version stamp
+ MetadataVersion m_MetadataVersion; // Version of the metadata to emit
+ MergeFlags m_MergeOptions; // Options to pass to the merger
+ UINT32 m_InitialSize; // Initial size of MetaData with values: code:CorMetaDataInitialSize.
+ CorLocalRefPreservation m_LocalRefPreservation; // Preserve module-local refs instead of optimizing them to defs
+}; // struct OptionValue
+
+//*********************************************************************
+//
+// Helper class to ensure calling UTSemReadWrite correctly.
+// The destructor will call the correct UnlockRead or UnlockWrite depends what lock it is holding.
+// User should use macro defined in below instead of calling functions on this class directly.
+// They are LOCKREAD(), LOCKWRITE(), and CONVERT_READ_TO_WRITE_LOCK.
+//
+//*********************************************************************
+class CMDSemReadWrite
+{
+public:
+ CMDSemReadWrite(UTSemReadWrite *pSem);
+ ~CMDSemReadWrite();
+ HRESULT LockRead();
+ HRESULT LockWrite();
+ void UnlockWrite();
+ HRESULT ConvertReadLockToWriteLock();
+private:
+ bool m_fLockedForRead;
+ bool m_fLockedForWrite;
+ UTSemReadWrite *m_pSem;
+};
+
+
+#define LOCKREADIFFAILRET() CMDSemReadWrite cSem(m_pSemReadWrite);\
+ IfFailRet(cSem.LockRead());
+#define LOCKWRITEIFFAILRET() CMDSemReadWrite cSem(m_pSemReadWrite);\
+ IfFailRet(cSem.LockWrite());
+
+#define LOCKREADNORET() CMDSemReadWrite cSem(m_pSemReadWrite);\
+ hr = cSem.LockRead();
+#define LOCKWRITENORET() CMDSemReadWrite cSem(m_pSemReadWrite);\
+ hr = cSem.LockWrite();
+
+#define LOCKREAD() CMDSemReadWrite cSem(m_pSemReadWrite);\
+ IfFailGo(cSem.LockRead());
+#define LOCKWRITE() CMDSemReadWrite cSem(m_pSemReadWrite);\
+ IfFailGo(cSem.LockWrite());
+
+#define UNLOCKWRITE() cSem.UnlockWrite();
+#define CONVERT_READ_TO_WRITE_LOCK() IfFailGo(cSem.ConvertReadLockToWriteLock());
+
+
+#endif // __RWUtil__h__
diff --git a/src/md/inc/stgio.h b/src/md/inc/stgio.h
new file mode 100644
index 0000000000..96a2f1dddb
--- /dev/null
+++ b/src/md/inc/stgio.h
@@ -0,0 +1,293 @@
+// 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.
+//*****************************************************************************
+// StgIO.h
+//
+
+//
+// This module handles disk/memory i/o for a generic set of storage solutions,
+// including:
+// * File system handle (HFILE)
+// * IStream
+// * User supplied memory buffer (non-movable)
+//
+// The Read, Write, Seek, ... functions are all directed to the corresponding
+// method for each type of file, allowing the consumer to use one set of api's.
+//
+// File system data can be paged fully into memory in two scenarios:
+// read: Normal memory mapped file is created to manage paging.
+// write: A custom paging system provides storage for pages as required. This
+// data is invalidated when you call Rewrite on the file.
+//
+// Transactions and backups are handled in the existing file case only. The
+// Rewrite function can make a backup of the current contents, and the Restore
+// function can be used to recover the data into the current scope. The backup
+// file is flushed to disk (which is slower but safer) after the copy. The
+// Restore also flushed the recovered changes to disk. Worst case scenario you
+// get a crash after calling Rewrite but before Restore, in which case you will
+// have a foo.clb.txn file in the same directory as the source file, foo.clb in
+// this example.
+//<TODO>
+// @FUTURE: issues,
+// 1. For reading a .clb in an image, it would be great to memory map
+// only the portion of the file with the .clb in it.
+//</TODO>
+//*****************************************************************************
+#ifndef __STGIO_H_
+#define __STGIO_H_
+
+#define MAXSHMEM 32
+
+#define STGIO_READ 0x1
+#define STGIO_WRITE 0x2
+
+enum DBPROPMODE
+ { DBPROP_TMODEF_READ = 0x1,
+ DBPROP_TMODEF_WRITE = 0x2,
+ DBPROP_TMODEF_EXCLUSIVE = 0x4,
+#ifndef FEATURE_METADATA_STANDALONE_WINRT_RO
+ // Shared memory uses ole32.dll - we cannot depend on it in the standalone WinRT Read-Only DLL
+ DBPROP_TMODEF_SHAREDMEM = 0x8,
+#endif
+ DBPROP_TMODEF_CREATE = 0x10,
+ DBPROP_TMODEF_FAILIFTHERE = 0x20,
+ DBPROP_TMODEF_SLOWSAVE = 0x100,
+ // Means it is OK to use LoadLibrary to map the file. Used by code:ofTrustedImage.
+ // We prefer that because it is shared with loader's image loading.
+ DBPROP_TMODEF_TRYLOADLIBRARY = 0x400,
+#if 0 // dead code
+ DBPROP_TMODEF_NOTXNBACKUPFILE = 0x200,
+ DBPROP_TMODEF_COMPLUS = 0x1000,
+ DBPROP_TMODEF_SMEMCREATE = 0x2000,
+ DBPROP_TMODEF_SMEMOPEN = 0x4000,
+ DBPROP_TMODEF_ALIGNBLOBS = 0x10000
+ DBPROP_TMODEF_RESERVED = 0x80000000,
+#endif
+ DBPROP_TMODEF_DFTWRITEMASK = 0x113,
+ DBPROP_TMODEF_DFTREADWRITEMASK = 0x103,
+ };
+
+
+// Types of IO we can handle.
+enum STGIOTYPE
+{
+ STGIO_NODATA = 0, // Currently not open.
+ STGIO_HFILE = 1, // File handle contains data.
+ STGIO_HMODULE = 2, // The file was loaded via LoadLibrary as module.
+ STGIO_STREAM = 3, // Stream pointer has data.
+ STGIO_MEM = 4, // In memory pointer has data.
+#ifndef FEATURE_METADATA_STANDALONE_WINRT_RO
+ // Shared memory uses ole32.dll - we cannot depend on it in the standalone WinRT Read-Only DLL
+ STGIO_SHAREDMEM = 5, // Shared memory handle.
+#endif
+ STGIO_HFILEMEM = 6 // Handle open, but memory allocated.
+};
+
+class StgIO
+{
+ friend class CLiteWeightStgdbRW; // for low-level access to data for metainfo and such.
+ friend class TiggerStorage;
+public:
+ StgIO(
+ bool bAutoMap=true); // Memory map for read on open?
+
+ ~StgIO();
+
+//*****************************************************************************
+// Open the base file on top of: (a) file, (b) memory buffer, or (c) stream.
+// If create flag is specified, then this will create a new file with the
+// name supplied. No data is read from an opened file. You must call
+// MapFileToMem before doing direct pointer access to the contents.
+//*****************************************************************************
+ HRESULT Open( // Return code.
+ LPCWSTR szName, // Name of the storage.
+ int fFlags, // How to open the file.
+ const void *pbBuff, // Optional buffer for memory.
+ ULONG cbBuff, // Size of buffer.
+ IStream *pIStream, // Stream for input.
+ LPSECURITY_ATTRIBUTES pAttributes); // Security token.
+
+//*****************************************************************************
+// Shut down the file handles and allocated objects.
+//*****************************************************************************
+ void Close();
+
+//*****************************************************************************
+// Read data from the storage source. This will handle all types of backing
+// storage from mmf, streams, and file handles. No read ahead or MRU
+// caching is done.
+//*****************************************************************************
+ HRESULT Read( // Return code.
+ void *pbBuff, // Write buffer here.
+ ULONG cbBuff, // How much to read.
+ ULONG *pcbRead); // How much read.
+
+//*****************************************************************************
+// Write to disk. This function will cache up to a page of data in a buffer
+// and peridocially flush it on overflow and explicit request. This makes it
+// safe to do lots of small writes without too much performance overhead.
+//*****************************************************************************
+ HRESULT Write( // Return code.
+ const void *pbBuff, // Buffer to write.
+ ULONG cbWrite, // How much.
+ ULONG *pcbWritten); // Return how much written.
+
+//*****************************************************************************
+// Moves the file pointer to the new location. This handles the different
+// types of storage systems.
+//*****************************************************************************
+ HRESULT Seek( // New offset.
+ int lVal, // How much to move.
+ ULONG fMoveType); // Direction, use Win32 FILE_xxxx.
+
+//*****************************************************************************
+// Retrieves the current offset for the storage being used. This value is
+// tracked based on Read, Write, and Seek operations.
+//*****************************************************************************
+ ULONG GetCurrentOffset(); // Current offset.
+
+//*****************************************************************************
+// Map the file contents to a memory mapped file and return a pointer to the
+// data. For read/write with a backing store, map the file using an internal
+// paging system.
+//*****************************************************************************
+ HRESULT MapFileToMem( // Return code.
+ void *&ptr, // Return pointer to file data.
+ ULONG *pcbSize, // Return size of data.
+ LPSECURITY_ATTRIBUTES pAttributes=0); // Security token.
+
+//*****************************************************************************
+// Free the mapping object for shared memory but keep the rest of the internal
+// state intact.
+//*****************************************************************************
+ HRESULT ReleaseMappingObject(); // Return code.
+
+//*****************************************************************************
+// Resets the logical base address and size to the value given. This is for
+// cases like finding a section embedded in another format, like the .clb inside
+// of an image. GetPtrForMem, Read, and Seek will then behave as though only
+// data from pbStart to cbSize is valid.
+//*****************************************************************************
+ HRESULT SetBaseRange( // Return code.
+ void *pbStart, // Start of file data.
+ ULONG cbSize); // How big is the range.
+
+//*****************************************************************************
+// For read/write case, get a pointer to a chunk of the file at cbStart for
+// size cbSize. Return the pointer. This will page in parts of the file from
+// disk if not already loaded.
+//*****************************************************************************
+ HRESULT GetPtrForMem( // Return code.
+ ULONG cbStart, // Offset from beginning to load.
+ ULONG cbSize, // How much, rounded to page.
+ void *&ptr); // Return pointer on success.
+
+//*****************************************************************************
+// For cached writes, flush the cache to the data store.
+//*****************************************************************************
+ HRESULT FlushCache();
+
+//*****************************************************************************
+// Tells the file system to flush any cached data it may have. This is
+// expensive, but if successful guarantees you won't lose writes short of
+// a disk failure.
+//*****************************************************************************
+ HRESULT FlushFileBuffers();
+
+//*****************************************************************************
+// Called after a successful rewrite of an existing file. The in memory
+// backing store is no longer valid because all new data is in memory and
+// on disk. This is essentially the same state as created, so free up some
+// working set and remember this state.
+//*****************************************************************************
+ HRESULT ResetBackingStore(); // Return code.
+
+ FILETYPE GetFileType()
+ { return m_FileType; }
+
+ int IsReadOnly()
+ { return ((m_fFlags & STGIO_WRITE) == 0); }
+
+ ULONG GetFlags()
+ { return (m_fFlags); }
+
+ ULONG SetFlags(ULONG fFlags)
+ { m_fFlags = fFlags;
+ return (m_fFlags); }
+
+ ULONG GetDataSize()
+ { return (m_cbData); }
+
+ LONG AddRef()
+ {
+ return (++m_cRef);
+ }
+
+ LONG Release()
+ {
+ LONG cRef = --m_cRef;
+ if (cRef == 0)
+ delete this;
+ return (cRef);
+ }
+
+ int IsAlignedPtr(ULONG_PTR Value, int iAlignment);
+ MAPPINGTYPE GetMemoryMappedType()
+ { return m_mtMappedType;}
+
+
+//*****************************************************************************
+// Called to read the data into allocated memory and release the backing store.
+// Only available on read-only data.
+//*****************************************************************************
+ HRESULT LoadFileToMemory();
+
+
+private:
+ int IsBackingStore()
+ { return (m_rgPageMap != 0); }
+ int IsMemoryMapped()
+ { return ((m_hMapping != NULL) || (m_hModule != NULL)); }
+
+ void CtorInit();
+ HRESULT WriteToDisk(const void *pbBuff, ULONG cbWrite, ULONG *pcbWritten);
+ HRESULT ReadFromDisk(void *pbBuff, ULONG cbBuff, ULONG *pcbRead);
+ HRESULT CopyFileInternal(LPCWSTR szTo, int bFailIfThere, int bWriteThrough);
+ void FreePageMap();
+
+private:
+
+ // Flags and state data.
+ FILETYPE m_FileType; // Cached type of the file (based on extension).
+ LONG m_cRef; // Ref count on this object.
+ bool m_bWriteThrough : 1; // true for write through mode.
+ bool m_bRewrite : 1; // State check for rewrite mode.
+ bool m_bAutoMap : 1; // true to automatically memory map file.
+ bool m_bFreeMem : 1; // true to free allocated memory.
+
+ // Handles.
+ IStream * m_pIStream; // For save to stream instead of file.
+ HANDLE m_hFile; // The actual file with contents.
+ HANDLE m_hMapping; // Mapping handle.
+ HMODULE m_hModule; // If we load with LoadLibrary, this is the module (otherwise NULL).
+ void * m_pBaseData; // Base address for memory mapped file.
+ void * m_pData; // For memory mapped file read.
+ ULONG m_cbData; // Size of in memory data.
+ int m_fFlags; // Flags for open/create mode.
+ STGIOTYPE m_iType; // Where is the data.
+ MAPPINGTYPE m_mtMappedType; // How the file was memory mapped
+
+ // File cache information.
+ BYTE * m_rgBuff; // Cache buffer for writing.
+ ULONG m_cbBuff; // Current cache size.
+ ULONG m_cbOffset; // Current offset in file.
+
+ // Buffer read management.
+ static int m_iPageSize; // Size of an OS page.
+ static int m_iCacheSize; // How big a write back cache to use.
+ BYTE * m_rgPageMap; // Track loaded pages on read/write.
+
+}; // class StgIO
+
+#endif // __STGIO_H_
diff --git a/src/md/inc/stgtiggerstorage.h b/src/md/inc/stgtiggerstorage.h
new file mode 100644
index 0000000000..42407bab9f
--- /dev/null
+++ b/src/md/inc/stgtiggerstorage.h
@@ -0,0 +1,328 @@
+// 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.
+//*****************************************************************************
+// StgTiggerStorage.h
+//
+
+//
+// TiggerStorage is a stripped down version of compound doc files. Doc files
+// have some very useful and complex features to them, unfortunately nothing
+// comes for free. Given the incredibly tuned format of existing .tlb files,
+// every single byte counts and 10% added by doc files is just too exspensive.
+//
+// The storage itself is made up of a bunch of streams (each aligned to a 4 byte
+// value), followed at the end of the file with the header. The header is
+// put at the end so that you can continue to write as many streams as you
+// like without thrashing the disk.
+// +-------------------+
+// | Signature |
+// +-------------------+
+// | Stream 1, 2, [] |
+// +-------------------+
+// | STORAGEHEADER |
+// | Extra data |
+// | STORAGESTREAM[] |
+// +-------------------+
+// | offset |
+// +-------------------+
+//
+// The STORAGEHEADER contains flags describing the rest of the file, including
+// the ability to have extra data stored in the header. If there is extra
+// data, then immediately after the STORAGEHEADER struct is a 4 byte size of
+// that data, followed immediately by the extra data. The length must be
+// 4 byte aligned so that the first STORAGESTREAM starts on an aligned
+// boundary. The contents of the extra data is caller defined.
+//
+// This code handles the signature at the start of the file, and the list of
+// streams at the end (kept in the header). The data in each stream is, of
+// course, caller specific.
+//
+// This code requires the StgIO code to handle the input and output from the
+// backing storage, whatever scheme that may be. There are no consistency
+// checks on the data (for example crc's) due to the expense in computation
+// required. There is a signature at the front of the file and in the header.
+//
+//*****************************************************************************
+#ifndef __StgTiggerStorage_h__
+#define __StgTiggerStorage_h__
+
+//#include "utilcode.h" // Helpers.
+
+#include "mdfileformat.h"
+
+typedef CDynArray<STORAGESTREAM> STORAGESTREAMLST;
+
+
+// Forwards.
+class TiggerStream;
+class StgIO;
+
+
+
+class TiggerStorage :
+ public IStorage
+{
+friend class TiggerStream;
+public:
+ TiggerStorage();
+ virtual ~TiggerStorage();
+
+// IUnknown so you can ref count this thing.
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, PVOID *pp)
+ { return (BadError(E_NOTIMPL)); }
+ virtual ULONG STDMETHODCALLTYPE AddRef()
+ { return (InterlockedIncrement(&m_cRef)); }
+ virtual ULONG STDMETHODCALLTYPE Release()
+ {
+ SUPPORTS_DAC_HOST_ONLY;
+ ULONG cRef;
+ if ((cRef = InterlockedDecrement(&m_cRef)) == 0)
+ delete this;
+ return (cRef);
+ }
+
+
+//*****************************************************************************
+// Init this storage object on top of the given storage unit.
+//*****************************************************************************
+ HRESULT Init( // Return code.
+ StgIO *pStgIO, // The I/O subsystem.
+ __in __in_z LPSTR pVersion); // Compiler-supplied CLR version
+
+//*****************************************************************************
+// Retrieves a the size and a pointer to the extra data that can optionally be
+// written in the header of the storage system. This data is not required to
+// be in the file, in which case *pcbExtra will come back as 0 and pbData will
+// be set to null. You must have initialized the storage using Init() before
+// calling this function.
+//*****************************************************************************
+ HRESULT GetExtraData( // Return code.
+ ULONG *pcbExtra, // Return size of extra data.
+ BYTE *&pbData); // Return a pointer to extra data.
+
+//*****************************************************************************
+// Flushes the header to disk.
+//*****************************************************************************
+ HRESULT WriteHeader( // Return code.
+ STORAGESTREAMLST *pList, // List of streams.
+ ULONG cbExtraData, // Size of extra data, may be 0.
+ BYTE *pbExtraData); // Pointer to extra data for header.
+
+//*****************************************************************************
+// Called when all data has been written. Forces cached data to be flushed
+// and stream lists to be validated.
+//*****************************************************************************
+ HRESULT WriteFinished( // Return code.
+ STORAGESTREAMLST *pList, // List of streams.
+ ULONG *pcbSaveSize, // Return size of total data.
+ BOOL fDeltaSave); // Was this a delta
+
+//*****************************************************************************
+// Called after a successful rewrite of an existing file. The in memory
+// backing store is no longer valid because all new data is in memory and
+// on disk. This is essentially the same state as created, so free up some
+// working set and remember this state.
+//*****************************************************************************
+ HRESULT ResetBackingStore(); // Return code.
+
+//*****************************************************************************
+// Called to restore the original file. If this operation is successful, then
+// the backup file is deleted as requested. The restore of the file is done
+// in write through mode to the disk help ensure the contents are not lost.
+// This is not good enough to fulfill ACID props, but it ain't that bad.
+//*****************************************************************************
+ HRESULT Restore( // Return code.
+ __in __in_z LPWSTR szBackup, // If non-0, backup the file.
+ int bDeleteOnSuccess); // Delete backup file if successful.
+
+//*****************************************************************************
+// Given the name of a stream that will be persisted into a stream in this
+// storage type, figure out how big that stream would be including the user's
+// stream data and the header overhead the file format incurs. The name is
+// stored in ANSI and the header struct is aligned to 4 bytes.
+//*****************************************************************************
+ static HRESULT GetStreamSaveSize( // Return code.
+ LPCWSTR szStreamName, // Name of stream.
+ UINT32 cbDataSize, // Size of data to go into stream.
+ UINT32 *pcbSaveSize); // Return data size plus stream overhead.
+
+//*****************************************************************************
+// Return the fixed size overhead for the storage implementation. This includes
+// the signature and fixed header overhead. The overhead in the header for each
+// stream is calculated as part of GetStreamSaveSize because these structs are
+// variable sized on the name.
+//*****************************************************************************
+ static HRESULT GetStorageSaveSize( // Return code.
+ ULONG *pcbSaveSize, // [in] current size, [out] plus overhead.
+ ULONG cbExtra, // How much extra data to store in header.
+ LPCSTR pRuntimeVersion); // The version string as it's length is part of the total size.
+
+//*****************************************************************************
+// Adjust the offset in each known stream to match where it will wind up after
+// a save operation.
+//*****************************************************************************
+ static HRESULT CalcOffsets( // Return code.
+ STORAGESTREAMLST *pStreamList, // List of streams for header.
+ ULONG cbExtra, // Size of variable extra data in header.
+ LPCSTR pRuntimeVersion); // The version string as it's length is part of the total size.
+
+
+
+//*****************************************************************************
+// Returns the size of the signature plus the verion information
+//*****************************************************************************
+ static HRESULT SizeOfStorageSignature(
+ LPCSTR pRuntimeVersion, // The version string as it's length is part of the total size.
+ ULONG *pcbSignatureSize);
+
+// IStorage
+ virtual HRESULT STDMETHODCALLTYPE CreateStream(
+ const OLECHAR *pwcsName,
+ DWORD grfMode,
+ DWORD reserved1,
+ DWORD reserved2,
+ IStream **ppstm);
+
+ virtual HRESULT STDMETHODCALLTYPE CreateStream(
+ LPCSTR szName,
+ DWORD grfMode,
+ DWORD reserved1,
+ DWORD reserved2,
+ IStream **ppstm)
+ DAC_UNEXPECTED();
+
+ virtual HRESULT STDMETHODCALLTYPE OpenStream(
+ const OLECHAR *pwcsName,
+ void *reserved1,
+ DWORD grfMode,
+ DWORD reserved2,
+ IStream **ppstm);
+
+ virtual HRESULT STDMETHODCALLTYPE CreateStorage(
+ const OLECHAR *pwcsName,
+ DWORD grfMode,
+ DWORD dwStgFmt,
+ DWORD reserved2,
+ IStorage **ppstg);
+
+ virtual HRESULT STDMETHODCALLTYPE OpenStorage(
+ const OLECHAR * wcsName,
+ IStorage * pStgPriority,
+ DWORD dwMode,
+ __in
+ SNB snbExclude,
+ DWORD reserved,
+ IStorage ** ppStg);
+
+ virtual HRESULT STDMETHODCALLTYPE CopyTo(
+ DWORD cIidExclude,
+ const IID * rgIidExclude,
+ __in
+ SNB snbExclude,
+ IStorage * pStgDest);
+
+ virtual HRESULT STDMETHODCALLTYPE MoveElementTo(
+ const OLECHAR *pwcsName,
+ IStorage *pstgDest,
+ const OLECHAR *pwcsNewName,
+ DWORD grfFlags);
+
+ virtual HRESULT STDMETHODCALLTYPE Commit(
+ DWORD grfCommitFlags);
+
+ virtual HRESULT STDMETHODCALLTYPE Revert();
+
+ virtual HRESULT STDMETHODCALLTYPE EnumElements(
+ DWORD reserved1,
+ void *reserved2,
+ DWORD reserved3,
+ IEnumSTATSTG **ppenum);
+
+ virtual HRESULT STDMETHODCALLTYPE DestroyElement(
+ const OLECHAR *pwcsName);
+
+ virtual HRESULT STDMETHODCALLTYPE RenameElement(
+ const OLECHAR *pwcsOldName,
+ const OLECHAR *pwcsNewName);
+
+ virtual HRESULT STDMETHODCALLTYPE SetElementTimes(
+ const OLECHAR *pwcsName,
+ const FILETIME *pctime,
+ const FILETIME *patime,
+ const FILETIME *pmtime);
+
+ virtual HRESULT STDMETHODCALLTYPE SetClass(
+ REFCLSID clsid);
+
+ virtual HRESULT STDMETHODCALLTYPE SetStateBits(
+ DWORD grfStateBits,
+ DWORD grfMask);
+
+ virtual HRESULT STDMETHODCALLTYPE Stat(
+ STATSTG *pstatstg,
+ DWORD grfStatFlag);
+
+ virtual HRESULT STDMETHODCALLTYPE OpenStream(
+ LPCWSTR szStream,
+ ULONG *pcbData,
+ void **ppAddress);
+
+ // Access storage object.
+ StgIO *GetStgIO()
+ { return (m_pStgIO); }
+
+#if defined(_DEBUG)
+ ULONG PrintSizeInfo( // Size of streams.
+ bool verbose); // Be verbose?
+#endif
+
+protected:
+ HRESULT Write( // Return code.
+ LPCSTR szName, // Name of stream we're writing.
+ const void *pData, // Data to write.
+ ULONG cbData, // Size of data.
+ ULONG *pcbWritten); // How much did we write.
+
+private:
+ HRESULT FindStream(LPCSTR szName, __out PSTORAGESTREAM *stream);
+ HRESULT WriteSignature(LPCSTR pVersion);
+ HRESULT VerifySignature(PSTORAGESIGNATURE pSig);
+ HRESULT ReadHeader();
+ HRESULT VerifyHeader();
+
+ static HRESULT GetDefaultVersion(LPCSTR* ppVersion);
+
+public:
+ // This function is a workaround to allow access to the "version requested" string.
+ HRESULT GetHeaderPointer(const void **ppv, ULONG *pcb);
+
+private:
+ // State data.
+ StgIO *m_pStgIO; // Storage subsystem.
+ LONG m_cRef; // Ref count for COM.
+
+ // Header data.
+ STORAGEHEADER m_StgHdr; // Header for storage.
+ STORAGESTREAMLST m_Streams; // List of streams in the storage.
+ PSTORAGESTREAM m_pStreamList; // For read mode.
+ void *m_pbExtra; // Pointer to extra data if on disk.
+};
+
+
+//*****************************************************************************
+// Debugging helpers. #define __SAVESIZE_TRACE__ to enable.
+//*****************************************************************************
+
+// #define __SAVESIZE_TRACE__
+#ifdef __SAVESIZE_TRACE__
+#define SAVETRACE(func) DEBUG_STMT(func)
+#else
+#define SAVETRACE(func)
+#endif // __SAVESIZE_TRACE__
+
+#endif // StgTiggerStorage
+
+
+
+// EOF
diff --git a/src/md/inc/stgtiggerstream.h b/src/md/inc/stgtiggerstream.h
new file mode 100644
index 0000000000..51a2f967de
--- /dev/null
+++ b/src/md/inc/stgtiggerstream.h
@@ -0,0 +1,112 @@
+// 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.
+//*****************************************************************************
+// StgTiggerStream.h
+//
+
+//
+// TiggerStream is the companion to the TiggerStorage CoClass. It handles the
+// streams managed inside of the storage and does the direct file i/o.
+//
+//*****************************************************************************
+#ifndef __StgTiggerStream_h__
+#define __StgTiggerStream_h__
+
+
+
+#include "stgtiggerstorage.h" // Data definitions.
+
+enum
+{
+ STREAM_DATA_NAME
+};
+
+
+class TiggerStorage;
+
+
+class TiggerStream :
+ public IStream
+{
+public:
+ TiggerStream() :
+ m_pStorage(0),
+ m_cRef(1)
+ {}
+
+ virtual ~TiggerStream() {}
+
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, PVOID *pp)
+ { return (BadError(E_NOTIMPL)); }
+ virtual ULONG STDMETHODCALLTYPE AddRef()
+ { return InterlockedIncrement(&m_cRef); }
+ virtual ULONG STDMETHODCALLTYPE Release()
+ {
+ ULONG cRef;
+ if ((cRef = InterlockedDecrement(&m_cRef)) == 0)
+ delete this;
+ return (cRef);
+ }
+
+// IStream
+ virtual HRESULT STDMETHODCALLTYPE Read(
+ void *pv,
+ ULONG cb,
+ ULONG *pcbRead);
+
+ virtual HRESULT STDMETHODCALLTYPE Write(
+ const void *pv,
+ ULONG cb,
+ ULONG *pcbWritten);
+
+ virtual HRESULT STDMETHODCALLTYPE Seek(
+ LARGE_INTEGER dlibMove,
+ DWORD dwOrigin,
+ ULARGE_INTEGER *plibNewPosition);
+
+ virtual HRESULT STDMETHODCALLTYPE SetSize(
+ ULARGE_INTEGER libNewSize);
+
+ virtual HRESULT STDMETHODCALLTYPE CopyTo(
+ IStream *pstm,
+ ULARGE_INTEGER cb,
+ ULARGE_INTEGER *pcbRead,
+ ULARGE_INTEGER *pcbWritten);
+
+ virtual HRESULT STDMETHODCALLTYPE Commit(
+ DWORD grfCommitFlags);
+
+ virtual HRESULT STDMETHODCALLTYPE Revert( void);
+
+ virtual HRESULT STDMETHODCALLTYPE LockRegion(
+ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType);
+
+ virtual HRESULT STDMETHODCALLTYPE UnlockRegion(
+ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType);
+
+ virtual HRESULT STDMETHODCALLTYPE Stat(
+ STATSTG *pstatstg,
+ DWORD grfStatFlag);
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(
+ IStream **ppstm);
+
+
+ HRESULT Init( // Return code.
+ TiggerStorage *pStorage, // Parent storage.
+ LPCSTR szStream); // Stream name.
+
+ ULONG GetStreamSize();
+
+private:
+ TiggerStorage *m_pStorage; // Our parent storage.
+ char m_rcStream[MAXSTREAMNAME]; // Name of the stream.
+ LONG m_cRef; // Ref count.
+};
+
+#endif // __StgTiggerStream_h__
diff --git a/src/md/inc/streamutil.h b/src/md/inc/streamutil.h
new file mode 100644
index 0000000000..89c493476f
--- /dev/null
+++ b/src/md/inc/streamutil.h
@@ -0,0 +1,221 @@
+// 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.
+
+//
+
+#if !defined( __STREAMUTIL_H__ )
+#define __STREAMUTIL_H__
+
+namespace StreamUtil
+{
+
+// Write data to stream and advance the totalBytes counter
+//
+inline
+HRESULT WriteToStream( IStream * strm, void const * data, UINT32 sizeInBytes, UINT32 * totalBytes = NULL )
+{
+ HRESULT hr = strm->Write( data, sizeInBytes, NULL );
+ if ( SUCCEEDED( hr ) && totalBytes != NULL )
+ *totalBytes += sizeInBytes;
+ return hr;
+}
+
+
+// Write a POD to stream
+//
+template < typename T >
+HRESULT WritePODToStream( IStream * strm, T val, UINT32 * totalBytes )
+{
+ return WriteToStream( strm, & val, sizeof( val ), totalBytes );
+}
+
+
+// Write concrete data types to stream
+// Add additional overloads as needed
+//
+
+inline
+HRESULT WriteToStream( IStream * strm, int val, UINT32 * totalBytes = NULL )
+{
+ return WritePODToStream( strm, val, totalBytes );
+}
+
+
+inline
+HRESULT WriteToStream( IStream * strm, DWORD val, UINT32 * totalBytes = NULL )
+{
+ return WritePODToStream( strm, val, totalBytes );
+}
+
+
+inline
+HRESULT WriteToStream( IStream * strm, WORD val, UINT32 * totalBytes = NULL )
+{
+ return WritePODToStream( strm, val, totalBytes );
+}
+
+
+inline
+HRESULT WriteToStream( IStream * strm, BYTE val, UINT32 * totalBytes = NULL )
+{
+ return WritePODToStream( strm, val, totalBytes );
+}
+
+
+// Align to DWORD boundary
+//
+inline
+HRESULT AlignDWORD( IStream * strm, UINT32 * totalBytes )
+{
+ HRESULT hr = S_OK;
+
+ UINT32 aligned = *totalBytes + 3 & ~3;
+ if (aligned > *totalBytes)
+ { // The *totalBytes were not aligned to DWORD, we need to add padding
+ DWORD data = 0;
+ hr = WriteToStream( strm, & data, aligned - *totalBytes, totalBytes );
+ }
+ else if (aligned < *totalBytes)
+ { // We got an integer overflow in 'aligned' expression above
+ hr = COR_E_OVERFLOW;
+ }
+
+ return hr;
+}
+
+
+// Get stream position
+//
+inline
+HRESULT GetPos( IStream * strm, UINT32 * pos )
+{
+ LARGE_INTEGER temp = { {0} };
+ ULARGE_INTEGER ul_pos = { {0} };
+ HRESULT hr = strm->Seek( temp, STREAM_SEEK_CUR, & ul_pos );
+ * pos = ul_pos.u.LowPart;
+ return hr;
+}
+
+
+class NullStream : public IStream
+{
+public:
+ NullStream()
+ : m_pos( 0 )
+ {}
+
+ ULONG STDMETHODCALLTYPE AddRef()
+ {
+ _ASSERTE( false );
+ return 0;
+ }
+
+ ULONG STDMETHODCALLTYPE Release()
+ {
+ SUPPORTS_DAC_HOST_ONLY;
+ _ASSERTE( false );
+ return 0;
+ }
+
+ HRESULT STDMETHODCALLTYPE QueryInterface( REFIID, PVOID* )
+ {
+ _ASSERTE( false );
+ return E_NOTIMPL;
+ }
+
+ HRESULT STDMETHODCALLTYPE Read(void *pv, ULONG cb, ULONG *pcbRead)
+ {
+ _ASSERTE( false );
+ return E_NOTIMPL;
+ }
+
+ HRESULT STDMETHODCALLTYPE Write(const void *pv, ULONG cb, ULONG *pcbWritten)
+ {
+ m_pos += cb;
+ if (pcbWritten != NULL)
+ {
+ *pcbWritten = cb;
+ }
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER dlibMove,DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
+ {
+ if ( dwOrigin != STREAM_SEEK_CUR || dlibMove.QuadPart != 0 || plibNewPosition == NULL )
+ return E_NOTIMPL;
+
+ plibNewPosition->u.HighPart = 0;
+ plibNewPosition->u.LowPart = m_pos;
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER libNewSize)
+ {
+ _ASSERTE( false );
+ return E_NOTIMPL;
+ }
+
+ HRESULT STDMETHODCALLTYPE CopyTo(
+ IStream *pstm,
+ ULARGE_INTEGER cb,
+ ULARGE_INTEGER *pcbRead,
+ ULARGE_INTEGER *pcbWritten)
+ {
+ _ASSERTE( false );
+ return E_NOTIMPL;
+ }
+
+ HRESULT STDMETHODCALLTYPE Commit(
+ DWORD grfCommitFlags)
+ {
+ _ASSERTE( false );
+ return E_NOTIMPL;
+ }
+
+ HRESULT STDMETHODCALLTYPE Revert()
+ {
+ _ASSERTE( false );
+ return E_NOTIMPL;
+ }
+
+ HRESULT STDMETHODCALLTYPE LockRegion(
+ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType)
+ {
+ _ASSERTE( false );
+ return E_NOTIMPL;
+ }
+
+ HRESULT STDMETHODCALLTYPE UnlockRegion(
+ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType)
+ {
+ _ASSERTE( false );
+ return E_NOTIMPL;
+ }
+
+ HRESULT STDMETHODCALLTYPE Stat(
+ STATSTG *pstatstg,
+ DWORD grfStatFlag)
+ {
+ _ASSERTE( false );
+ return E_NOTIMPL;
+ }
+
+ HRESULT STDMETHODCALLTYPE Clone(
+ IStream **ppstm)
+ {
+ _ASSERTE( false );
+ return E_NOTIMPL;
+ }
+
+private:
+ UINT32 m_pos;
+}; // class NullStream
+
+}; // namespace StreamUtil
+
+#endif
diff --git a/src/md/inc/verifylayouts.h b/src/md/inc/verifylayouts.h
new file mode 100644
index 0000000000..035b52d3ec
--- /dev/null
+++ b/src/md/inc/verifylayouts.h
@@ -0,0 +1,186 @@
+// 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.
+//*****************************************************************************
+// VerifyLayouts.h
+//
+
+//
+// Make sure that layouts of MD data strucutres doesn't change accidentally
+//
+//*****************************************************************************
+
+// The code in MD\DataSource\TargetTypes.* takes a direct dependency on
+// the layouts of types in MD. This is used by the debugger to read metadata
+// from a seperate process by deserializing the memory for these datastructures.
+//
+// You are probably reading this comment because you changed a layout and
+// one of the static_asserts failed during build. This is what you should
+// do to fix it:
+//
+// a) Go to clr\src\Debug\EE\Debugger.cpp and increment the global version counter
+// m_mdDataStructureVersion set in Debugger::Debugger()
+// Please comment the change there with a new entry in the version table
+//
+// b) If a define is conditionally changing the layout:
+// i) add, if needed, an entry to the list of define bits in
+// clr\src\Debug\EE\debugger.h Debugger::_Target_Defines
+// ii) add code like this that sets the bit in the Debugger::_defines static
+// variable
+// #ifdef MY_DEFINE
+// | DEFINE_MY_DEFINE
+// #endif
+//
+// c) Update the code in MD\DataSource\TargetTypes.h/cpp to deserialize your
+// new layout correctly. The code needs to work for any version of the layouts
+// with or without defines set. Your reader code can access the current version
+// and defines by calling:
+// reader.GetMDStructuresVersion()
+// reader.IsDefined(Define_XYZ)
+//
+// d) If your changes affect what a debugger should be reading in order to fetch
+// metadata then you probably need to change other parts of the debugger
+// implementation as well. In general the debugger cares about the schema,
+// TableDefs, storage signature, table records, and storage pools.
+//
+// e) AFTER you have fixed up the debugger stuff above, now its time to update
+// layout definitions so the static asserts will quiet down. Check out
+// the comments in VerifyLayouts.inc for how to do that.
+//
+// Thanks for helping us keep the debugger working :)
+//
+
+
+
+
+//-------------------------------------------------------------------------------
+// Type layout verification
+//
+//
+// These macros includes VerifyLayouts.inc a few times with different definitions to build up
+// the source. The final result should look something like this:
+// (don't assume specific type names/fields/offsets/sizes are accurate in this example)
+//
+//
+// class VerifyLayoutsMD
+// {
+//
+// static const expected_offset_of_first_field_in_CMiniMdRW = 208;
+// static const actual_offset_of_first_field_in_CMiniMdRW =
+// 208;
+// static const offset_of_field_after_CMiniMdRW_m_Schema =
+// 312;
+// static const offset_of_field_after_CMiniMdRW_m_Tables =
+// 316;
+// ... many more lines like this covering all fields in all marked up types ...
+//
+//
+// static const alignment_of_first_field_in_CMiniMdRW =
+// 4;
+// static const alignment_of_field_after_CMiniMdRW_m_Schema =
+// 8;
+// static const alignment_of_field_after_CMiniMdRW_m_Tables =
+// 8;
+// ... many more lines like this cover all fields in all marked up types ...
+//
+//
+// static_assert_no_msg(expected_offset_of_first_field_in_CMiniMdRW == actual_offset_of_first_field_in_CMiniMdRW);
+// static_assert_no_msg(offset_of_field_after_CMiniMdRW_m_Schema ==
+// ALIGN_UP(offsetof(CMiniMdRW, m_Schema) + 104, alignment_of_field_after_CMiniMdRW_m_Schema));
+// static_assert_no_msg(offset_of_field_after_CMiniMdRW_m_Tables ==
+// ALIGN_UP(offsetof(CMiniMdRW, m_Tables) + 4, alignment_of_field_after_CMiniMdRW_m_Tables));
+// ... many more lines like this cover all fields in all marked up types ...
+//
+// };
+//
+//
+//
+//
+
+#ifdef FEATURE_METADATA_VERIFY_LAYOUTS
+
+#include <stddef.h> // offsetof
+#include "static_assert.h"
+#include "metamodel.h"
+#include "WinMDInterfaces.h"
+#include "MDInternalRW.h"
+
+// other types provide friend access to this type so that the
+// offsetof macro can access their private fields
+class VerifyLayoutsMD
+{
+ // we have a bunch of arrays with this fixed size, make sure it doesn't change
+ static_assert_no_msg(TBL_COUNT == 45);
+
+
+
+#define IGNORE_COMMAS(...) __VA_ARGS__ // use this to surround templated types with commas in the name
+
+#define BEGIN_TYPE(typeName, initialFieldOffset) BEGIN_TYPE_ESCAPED(typeName, typeName, initialFieldOffset)
+#define FIELD(typeName, fieldName, fieldSize) ALIGN_FIELD_ESCAPED(typeName, typeName, fieldName, fieldSize, fieldSize)
+#define ALIGN_FIELD(typeName, fieldName, fieldSize, fieldAlign) ALIGN_FIELD_ESCAPED(typeName, typeName, fieldName, fieldSize, fieldAlign)
+#define FIELD_ESCAPED(typeName, escapedTypeName, fieldName, fieldSize) ALIGN_FIELD_ESCAPED(typeName, escapedTypeName, fieldName, fieldSize, fieldSize)
+#define END_TYPE(typeName, typeAlign) END_TYPE_ESCAPED(typeName, typeName, typeAlign)
+
+#define BEGIN_TYPE_ESCAPED(typeName, typeNameEscaped, initialFieldOffset) \
+ static const expected_offset_of_first_field_in_##typeNameEscaped## = initialFieldOffset; \
+ static const actual_offset_of_first_field_in_##typeNameEscaped## =
+
+#define ALIGN_FIELD_ESCAPED(typeName, typeNameEscaped, fieldName, fieldSize, fieldAlign) \
+ offsetof(IGNORE_COMMAS(typeName), fieldName); \
+ static const offset_of_field_after_##typeNameEscaped##_##fieldName =
+
+#define BITFIELD(typeName, fieldName, fieldOffset, fieldSize) \
+ fieldOffset; \
+ static const offset_of_field_after_##typeName##_##fieldName =
+
+#define END_TYPE_ESCAPED(typeName, typeNameEscaped, typeAlignentSize) \
+ sizeof(typeName);
+
+#include "VerifyLayouts.inc"
+
+#undef BEGIN_TYPE_ESCAPED
+#undef ALIGN_FIELD_ESCAPED
+#undef END_TYPE_ESCAPED
+#undef BITFIELD
+
+#define BEGIN_TYPE_ESCAPED(typeName, escapedTypeName, initialFieldOffset) \
+ static const alignment_of_first_field_in_##escapedTypeName =
+#define ALIGN_FIELD_ESCAPED(typeName, escapedTypeName, fieldName, fieldSize, fieldAlign) \
+ fieldAlign; \
+ static const alignment_of_field_after_##escapedTypeName##_##fieldName =
+#define BITFIELD(typeName, fieldName, fieldOffset, fieldSize) \
+ fieldSize; \
+ static const alignment_of_field_after_##typeName##_##fieldName =
+#define END_TYPE_ESCAPED(typeName, escapedTypeName, typeAlignmentSize) \
+ typeAlignmentSize;
+
+#include "VerifyLayouts.inc"
+
+#undef BEGIN_TYPE_ESCAPED
+#undef ALIGN_FIELD_ESCAPED
+#undef END_TYPE_ESCAPED
+#undef BITFIELD
+
+
+#define BEGIN_TYPE_ESCAPED(typeName, escapedTypeName, initialFieldOffset) \
+ static_assert_no_msg(expected_offset_of_first_field_in_##escapedTypeName == actual_offset_of_first_field_in_##escapedTypeName);
+
+
+#define ALIGN_UP(value, alignment) (((value) + (alignment) - 1)&~((alignment) - 1))
+#define ALIGN_FIELD_ESCAPED(typeName, escapedTypeName, fieldName, fieldSize, fieldAlign) \
+ static_assert_no_msg(offset_of_field_after_##escapedTypeName##_##fieldName == \
+ ALIGN_UP(offsetof(IGNORE_COMMAS(typeName), fieldName) + fieldSize, alignment_of_field_after_##escapedTypeName##_##fieldName));
+#define BITFIELD(typeName, fieldName, fieldOffset, fieldSize) \
+ static_assert_no_msg(offset_of_field_after_##typeName##_##fieldName == \
+ ALIGN_UP(fieldOffset + fieldSize, alignment_of_field_after_##typeName##_##fieldName));
+
+#define END_TYPE_ESCAPED(typeName, escapedTypeName, typeAlignmentSize)
+#include "VerifyLayouts.inc"
+
+};
+
+
+
+
+#endif //FEATURE_METADATA_VERIFY_LAYOUTS
diff --git a/src/md/inc/winmdinterfaces.h b/src/md/inc/winmdinterfaces.h
new file mode 100644
index 0000000000..4233e615d3
--- /dev/null
+++ b/src/md/inc/winmdinterfaces.h
@@ -0,0 +1,120 @@
+// 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.
+
+//
+// =======================================================================================================
+// Defines the surface area between md\WinMD and md\everything-else.
+//
+// md\WinMD contains adapter importers that wrap RegMeta and MDInternalRO to make .winmd files look like
+// regular .NET assemblies.
+// =======================================================================================================
+
+#ifndef __WINMDINTERFACES_H__
+#define __WINMDINTERFACES_H__
+
+#include "metamodel.h"
+
+
+//-----------------------------------------------------------------------------------------------------
+// A common interface unifying RegMeta and MDInternalRO, giving the adapter a common interface to
+// access the raw metadata.
+//-----------------------------------------------------------------------------------------------------
+
+// {4F8EE8A3-24F8-4241-BC75-C8CAEC0255B5}
+EXTERN_GUID(IID_IMDCommon, 0x4f8ee8a3, 0x24f8, 0x4241, 0xbc, 0x75, 0xc8, 0xca, 0xec, 0x2, 0x55, 0xb5);
+
+#undef INTERFACE
+#define INTERFACE IID_IMDCommon
+DECLARE_INTERFACE_(IMDCommon, IUnknown)
+{
+ STDMETHOD_(IMetaModelCommon*, GetMetaModelCommon)() PURE;
+ STDMETHOD_(IMetaModelCommonRO*, GetMetaModelCommonRO)() PURE;
+ STDMETHOD(GetVersionString)(LPCSTR *pszVersionString) PURE;
+};
+
+
+//-----------------------------------------------------------------------------------------------------
+// Returns:
+// S_OK: if WinMD adapter should be used.
+// S_FALSE: if not
+//-----------------------------------------------------------------------------------------------------
+HRESULT CheckIfWinMDAdapterNeeded(IMDCommon *pRawMDCommon);
+
+
+
+//-----------------------------------------------------------------------------------------------------
+// Factory method that creates an WinMD adapter that implements:
+//
+// IMetaDataImport2
+// IMetaDataAssemblyImport
+// IMetaDataValidate
+// IMarshal
+// IMDCommon (subset)
+//
+// IMDCommon is included as a concession to the fact that certain IMetaDataEmit apis have
+// an (apparently undocumented) dependency on their importer arguments supporting this.
+//
+// You must provide a regular MD importer that implements:
+//
+// IMDCommon
+// IMetaDataImport2
+// IMetaDataAssemblyImport
+// IMetaDataValidate
+//
+// The underlying metadata file must follow these restrictions:
+//
+// - Have an existing assemblyRef to "mscorlib"
+//
+//-----------------------------------------------------------------------------------------------------
+HRESULT CreateWinMDImport(IMDCommon * pRawMDCommon, REFIID riid, /*[out]*/ void **ppWinMDImport);
+
+
+//-----------------------------------------------------------------------------------------------------
+// Factory method that creates an WinMD adapter that implements IMDInternalImport.
+// You must provide a regular MD importer that implements:
+//
+// IMDCommon
+// IMDInternalImport
+//
+// The underlying metadata file must follow these restrictions:
+//
+// - Have an existing assemblyRef to "mscorlib"
+//
+//-----------------------------------------------------------------------------------------------------
+#ifdef FEATURE_METADATA_INTERNAL_APIS
+HRESULT CreateWinMDInternalImportRO(IMDCommon * pRawMDCommon, REFIID riid, /*[out]*/ void **ppWinMDInternalImport);
+
+#endif // FEATURE_METADATA_INTERNAL_APIS
+//-----------------------------------------------------------------------------------------------------
+// S_OK if pUnknown is really a WinMD wrapper. This is just a polite way of asking "is it bad to
+// to static cast pUnknown to RegMeta/MDInternalRO."
+//-----------------------------------------------------------------------------------------------------
+HRESULT CheckIfImportingWinMD(IUnknown *pUnknown);
+
+
+//-----------------------------------------------------------------------------------------------------
+// E_NOTIMPL if pUnknown is really a WinMD wrapper.
+//-----------------------------------------------------------------------------------------------------
+HRESULT VerifyNotWinMDHelper(IUnknown *pUnknown
+#ifdef _DEBUG
+ ,LPCSTR assertMsg
+ ,LPCSTR file
+ ,int line
+#endif //_DEBUG
+ );
+#if defined(FEATURE_METADATA_IN_VM) && !defined(FEATURE_CORECLR)
+#ifdef _DEBUG
+#define VerifyNotWinMD(pUnknown, assertMsg) VerifyNotWinMDHelper(pUnknown, assertMsg, __FILE__, __LINE__)
+#else
+#define VerifyNotWinMD(pUnknown, assertMsg) VerifyNotWinMDHelper(pUnknown)
+#endif
+#else
+#define VerifyNotWinMD(pUnknown, assertMsg) S_OK
+#endif // FEATURE_METADATA_IN_VM
+
+
+#endif //__WINMDINTERFACES_H__
+
+
+