summaryrefslogtreecommitdiff
path: root/src/md/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/md/compiler')
-rw-r--r--src/md/compiler/.gitmirror1
-rw-r--r--src/md/compiler/CMakeLists.txt32
-rw-r--r--src/md/compiler/Compiler.settings.targets68
-rw-r--r--src/md/compiler/assemblymd.cpp758
-rw-r--r--src/md/compiler/assemblymd_emit.cpp811
-rw-r--r--src/md/compiler/cacheload.h27
-rw-r--r--src/md/compiler/classfactory.cpp173
-rw-r--r--src/md/compiler/classfactory.h95
-rw-r--r--src/md/compiler/crossgen/.gitmirror1
-rw-r--r--src/md/compiler/crossgen/CMakeLists.txt5
-rw-r--r--src/md/compiler/crossgen/MDCompiler_crossgen.nativeproj15
-rw-r--r--src/md/compiler/custattr.h117
-rw-r--r--src/md/compiler/custattr_emit.cpp2000
-rw-r--r--src/md/compiler/custattr_import.cpp282
-rw-r--r--src/md/compiler/dac/.gitmirror1
-rw-r--r--src/md/compiler/dac/CMakeLists.txt6
-rw-r--r--src/md/compiler/dac/dirs.proj19
-rw-r--r--src/md/compiler/dbi/.gitmirror1
-rw-r--r--src/md/compiler/dbi/CMakeLists.txt4
-rw-r--r--src/md/compiler/dbi/MDCompiler-dbi.props9
-rw-r--r--src/md/compiler/dbi/dirs.proj19
-rw-r--r--src/md/compiler/dirs.proj27
-rw-r--r--src/md/compiler/disp.cpp939
-rw-r--r--src/md/compiler/disp.h132
-rw-r--r--src/md/compiler/emit.cpp3001
-rw-r--r--src/md/compiler/filtermanager.cpp1458
-rw-r--r--src/md/compiler/filtermanager.h87
-rw-r--r--src/md/compiler/helper.cpp445
-rw-r--r--src/md/compiler/import.cpp3809
-rw-r--r--src/md/compiler/importhelper.cpp3415
-rw-r--r--src/md/compiler/importhelper.h368
-rw-r--r--src/md/compiler/mdperf.cpp96
-rw-r--r--src/md/compiler/mdperf.h243
-rw-r--r--src/md/compiler/mdsighelper.h128
-rw-r--r--src/md/compiler/mdutil.cpp774
-rw-r--r--src/md/compiler/mdutil.h119
-rw-r--r--src/md/compiler/mdvalidator.cpp7739
-rw-r--r--src/md/compiler/newmerger.cpp6303
-rw-r--r--src/md/compiler/newmerger.h256
-rw-r--r--src/md/compiler/regmeta.cpp1588
-rw-r--r--src/md/compiler/regmeta.h2123
-rw-r--r--src/md/compiler/regmeta_compilersupport.cpp506
-rw-r--r--src/md/compiler/regmeta_emit.cpp2116
-rw-r--r--src/md/compiler/regmeta_imetadatatables.cpp719
-rw-r--r--src/md/compiler/regmeta_import.cpp1204
-rw-r--r--src/md/compiler/regmeta_vm.cpp586
-rw-r--r--src/md/compiler/stdafx.cpp12
-rw-r--r--src/md/compiler/stdafx.h26
-rw-r--r--src/md/compiler/verifylayouts.cpp14
-rw-r--r--src/md/compiler/wks/.gitmirror1
-rw-r--r--src/md/compiler/wks/CMakeLists.txt4
-rw-r--r--src/md/compiler/wks/MDCompiler_wks.nativeproj19
52 files changed, 42701 insertions, 0 deletions
diff --git a/src/md/compiler/.gitmirror b/src/md/compiler/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/md/compiler/.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/compiler/CMakeLists.txt b/src/md/compiler/CMakeLists.txt
new file mode 100644
index 0000000000..4d99d11edc
--- /dev/null
+++ b/src/md/compiler/CMakeLists.txt
@@ -0,0 +1,32 @@
+set(MDCOMPILER_SOURCES
+ assemblymd.cpp
+ assemblymd_emit.cpp
+ classfactory.cpp
+ custattr_import.cpp
+ custattr_emit.cpp
+ disp.cpp
+ emit.cpp
+ filtermanager.cpp
+ helper.cpp
+ import.cpp
+ importhelper.cpp
+ mdutil.cpp
+ regmeta.cpp
+ regmeta_compilersupport.cpp
+ regmeta_emit.cpp
+ regmeta_import.cpp
+ regmeta_imetadatatables.cpp
+ regmeta_vm.cpp
+ verifylayouts.cpp
+)
+
+convert_to_absolute_path(MDCOMPILER_SOURCES ${MDCOMPILER_SOURCES})
+
+if(CLR_CMAKE_PLATFORM_UNIX)
+ add_compile_options(-fPIC)
+endif(CLR_CMAKE_PLATFORM_UNIX)
+
+add_subdirectory(dac)
+add_subdirectory(wks)
+add_subdirectory(dbi)
+add_subdirectory(crossgen)
diff --git a/src/md/compiler/Compiler.settings.targets b/src/md/compiler/Compiler.settings.targets
new file mode 100644
index 0000000000..97f2504796
--- /dev/null
+++ b/src/md/compiler/Compiler.settings.targets
@@ -0,0 +1,68 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+ <!--
+ We build MetaData in several flavors:
+ - Full version (wks) - part of clr.dll/coreclr.dll.
+ - dac version - does not need Emit APIs.
+ - Standalone versions for:
+ * mscordbi.dll (hands the interfaces over to debugger client (e.g. VS) - does not need Emit APIs.
+ * CorDbg - does not need Emit APIs.
+ * WinRT
+ - Read-Only version (ships in Windows) - does not need Emit and Internal APIs.
+ - Read-Writer version (ships as private component of MidlRt.exe SDK tool) - does not need Internal APIs.
+ -->
+
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\src\MD\MD.props" />
+
+ <PropertyGroup>
+ <MDCompilerSrcDirectory>$(ClrSrcDirectory)\MD\Compiler\</MDCompilerSrcDirectory>
+ <UserIncludes>
+ $(UserIncludes);
+ $(ClrSrcDirectory)\md\inc;
+ $(ClrSrcDirectory)\vm;
+ $(ClrSrcDirectory)\strongname\inc
+ </UserIncludes>
+ <ClAdditionalOptions>$(ClAdditionalOptions) -DUNICODE -D_UNICODE</ClAdditionalOptions>
+ <!--OK to delete NO_NTDLL for devdiv builds.-->
+ <OutputPath>$(ClrLibDest)</OutputPath>
+ <TargetType>LIBRARY</TargetType>
+ <PCHHeader>stdafx.h</PCHHeader>
+ <EnableCxxPCHHeaders>true</EnableCxxPCHHeaders>
+ <!--PCH: Both precompiled header and cpp are on the same $(MDCompilerSrcDirectory)\ path this is likely to be wrong.-->
+ <PCHCompile>$(MDCompilerSrcDirectory)\stdafx.cpp</PCHCompile>
+ <PCHObject>stdafx_compiler.obj</PCHObject>
+ <LinkUseCMT>false</LinkUseCMT>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="$(ClrSrcDirectory)inc\corguids.nativeproj">
+ <Comment>clrinternal.h</Comment>
+ </ProjectReference>
+ </ItemGroup>
+
+ <ItemGroup>
+ <CppCompile Include="$(MDCompilerSrcDirectory)\AssemblyMD.cpp" />
+ <CppCompile Include="$(MDCompilerSrcDirectory)\AssemblyMD_Emit.cpp" />
+ <CppCompile Include="$(MDCompilerSrcDirectory)\ClassFactory.cpp" />
+ <CppCompile Include="$(MDCompilerSrcDirectory)\CustAttr_Import.cpp" />
+ <CppCompile Include="$(MDCompilerSrcDirectory)\CustAttr_Emit.cpp" />
+ <CppCompile Include="$(MDCompilerSrcDirectory)\Disp.cpp" />
+ <CppCompile Include="$(MDCompilerSrcDirectory)\Emit.cpp" />
+ <CppCompile Include="$(MDCompilerSrcDirectory)\FilterManager.cpp" />
+ <CppCompile Include="$(MDCompilerSrcDirectory)\Helper.cpp" />
+ <CppCompile Include="$(MDCompilerSrcDirectory)\Import.cpp" />
+ <CppCompile Include="$(MDCompilerSrcDirectory)\ImportHelper.cpp" />
+ <CppCompile Include="$(MDCompilerSrcDirectory)\MDPerf.cpp" />
+ <CppCompile Include="$(MDCompilerSrcDirectory)\MDUtil.cpp" />
+ <CppCompile Include="$(MDCompilerSrcDirectory)\MDValidator.cpp" />
+ <CppCompile Include="$(MDCompilerSrcDirectory)\NewMerger.cpp" />
+ <CppCompile Include="$(MDCompilerSrcDirectory)\RegMeta.cpp" />
+ <CppCompile Include="$(MDCompilerSrcDirectory)\RegMeta_CompilerSupport.cpp" />
+ <CppCompile Include="$(MDCompilerSrcDirectory)\RegMeta_Emit.cpp" />
+ <CppCompile Include="$(MDCompilerSrcDirectory)\RegMeta_Import.cpp" />
+ <CppCompile Include="$(MDCompilerSrcDirectory)\RegMeta_IMetaDataTables.cpp" />
+ <CppCompile Include="$(MDCompilerSrcDirectory)\RegMeta_VM.cpp" />
+ <CppCompile Include="$(MDCompilerSrcDirectory)\VerifyLayouts.cpp" />
+ </ItemGroup>
+</Project>
diff --git a/src/md/compiler/assemblymd.cpp b/src/md/compiler/assemblymd.cpp
new file mode 100644
index 0000000000..8c0a22af4d
--- /dev/null
+++ b/src/md/compiler/assemblymd.cpp
@@ -0,0 +1,758 @@
+// 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.
+//*****************************************************************************
+// AssemblyMD.cpp
+//
+
+//
+// Implementation for the assembly meta data import code (code:IMetaDataAssemblyImport).
+//
+//*****************************************************************************
+#include "stdafx.h"
+#include "regmeta.h"
+#include "mdutil.h"
+#include "rwutil.h"
+#include "mdlog.h"
+#include "importhelper.h"
+
+#include <strongname.h>
+
+#ifdef _MSC_VER
+#pragma warning(disable: 4102)
+#endif
+
+//*******************************************************************************
+// Get the properties for the given Assembly token.
+//*******************************************************************************
+STDMETHODIMP RegMeta::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_part_opt(cchName, *pchName) 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.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ AssemblyRec *pRecord;
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ LOG((LOGMD, "RegMeta::GetAssemblyProps(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ mda, ppbPublicKey, pcbPublicKey, pulHashAlgId, szName, cchName, pchName, pMetaData,
+ pdwAssemblyFlags));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ _ASSERTE(TypeFromToken(mda) == mdtAssembly && RidFromToken(mda));
+ IfFailGo(pMiniMd->GetAssemblyRecord(RidFromToken(mda), &pRecord));
+
+ if (ppbPublicKey != NULL)
+ {
+ IfFailGo(pMiniMd->getPublicKeyOfAssembly(pRecord, (const BYTE **)ppbPublicKey, pcbPublicKey));
+ }
+ if (pulHashAlgId)
+ *pulHashAlgId = pMiniMd->getHashAlgIdOfAssembly(pRecord);
+ if (pMetaData)
+ {
+ pMetaData->usMajorVersion = pMiniMd->getMajorVersionOfAssembly(pRecord);
+ pMetaData->usMinorVersion = pMiniMd->getMinorVersionOfAssembly(pRecord);
+ pMetaData->usBuildNumber = pMiniMd->getBuildNumberOfAssembly(pRecord);
+ pMetaData->usRevisionNumber = pMiniMd->getRevisionNumberOfAssembly(pRecord);
+ IfFailGo(pMiniMd->getLocaleOfAssembly(pRecord, pMetaData->szLocale,
+ pMetaData->cbLocale, &pMetaData->cbLocale));
+ pMetaData->ulProcessor = 0;
+ pMetaData->ulOS = 0;
+ }
+ if (pdwAssemblyFlags)
+ {
+ *pdwAssemblyFlags = pMiniMd->getFlagsOfAssembly(pRecord);
+
+#ifdef FEATURE_WINDOWSPHONE
+ // Turn on the afPublicKey if PublicKey blob is not empty
+ DWORD cbPublicKey;
+ const BYTE *pbPublicKey;
+ IfFailGo(pMiniMd->getPublicKeyOfAssembly(pRecord, &pbPublicKey, &cbPublicKey));
+ if (cbPublicKey != 0)
+ *pdwAssemblyFlags |= afPublicKey;
+#else
+ if (ppbPublicKey)
+ {
+ if (pcbPublicKey && *pcbPublicKey)
+ *pdwAssemblyFlags |= afPublicKey;
+ }
+ else
+ {
+#ifdef _DEBUG
+ // Assert that afPublicKey is set if PublicKey blob is not empty
+ DWORD cbPublicKey;
+ const BYTE *pbPublicKey;
+ IfFailGo(pMiniMd->getPublicKeyOfAssembly(pRecord, &pbPublicKey, &cbPublicKey));
+ bool hasPublicKey = cbPublicKey != 0;
+ bool hasPublicKeyFlag = ( *pdwAssemblyFlags & afPublicKey ) != 0;
+ _ASSERTE( hasPublicKey == hasPublicKeyFlag );
+#endif
+ }
+#endif // FEATURE_WINDOWSPHONE
+ }
+ // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK
+ if (szName || pchName)
+ IfFailGo(pMiniMd->getNameOfAssembly(pRecord, szName, cchName, pchName));
+ErrExit:
+
+ STOP_MD_PERF(GetAssemblyProps);
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::GetAssemblyProps
+
+//*******************************************************************************
+// Get the properties for the given AssemblyRef token.
+//*******************************************************************************
+STDMETHODIMP RegMeta::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_part_opt(cchName, *pchName) 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.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ AssemblyRefRec *pRecord;
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ LOG((LOGMD, "RegMeta::GetAssemblyRefProps(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ mdar, ppbPublicKeyOrToken, pcbPublicKeyOrToken, szName, cchName,
+ pchName, pMetaData, ppbHashValue, pdwAssemblyRefFlags));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ _ASSERTE(TypeFromToken(mdar) == mdtAssemblyRef && RidFromToken(mdar));
+ IfFailGo(pMiniMd->GetAssemblyRefRecord(RidFromToken(mdar), &pRecord));
+
+ if (ppbPublicKeyOrToken != NULL)
+ {
+ IfFailGo(pMiniMd->getPublicKeyOrTokenOfAssemblyRef(pRecord, (const BYTE **)ppbPublicKeyOrToken, pcbPublicKeyOrToken));
+ }
+ if (pMetaData)
+ {
+ pMetaData->usMajorVersion = pMiniMd->getMajorVersionOfAssemblyRef(pRecord);
+ pMetaData->usMinorVersion = pMiniMd->getMinorVersionOfAssemblyRef(pRecord);
+ pMetaData->usBuildNumber = pMiniMd->getBuildNumberOfAssemblyRef(pRecord);
+ pMetaData->usRevisionNumber = pMiniMd->getRevisionNumberOfAssemblyRef(pRecord);
+ IfFailGo(pMiniMd->getLocaleOfAssemblyRef(pRecord, pMetaData->szLocale,
+ pMetaData->cbLocale, &pMetaData->cbLocale));
+ pMetaData->ulProcessor = 0;
+ pMetaData->ulOS = 0;
+ }
+ if (ppbHashValue != NULL)
+ {
+ IfFailGo(pMiniMd->getHashValueOfAssemblyRef(pRecord, (const BYTE **)ppbHashValue, pcbHashValue));
+ }
+ if (pdwAssemblyRefFlags)
+ *pdwAssemblyRefFlags = pMiniMd->getFlagsOfAssemblyRef(pRecord);
+ // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK
+ if (szName || pchName)
+ IfFailGo(pMiniMd->getNameOfAssemblyRef(pRecord, szName, cchName, pchName));
+ErrExit:
+
+ STOP_MD_PERF(GetAssemblyRefProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::GetAssemblyRefProps
+
+//*******************************************************************************
+// Get the properties for the given File token.
+//*******************************************************************************
+STDMETHODIMP RegMeta::GetFileProps( // S_OK or error.
+ mdFile mdf, // [IN] The File for which to get the properties.
+ __out_ecount_part_opt(cchName, *pchName) 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.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ FileRec *pRecord;
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ LOG((LOGMD, "RegMeta::GetFileProps(%#08x, %#08x, %#08x, %#08x, %#08x, %#08x, %#08x)\n",
+ mdf, szName, cchName, pchName, ppbHashValue, pcbHashValue, pdwFileFlags));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ _ASSERTE(TypeFromToken(mdf) == mdtFile && RidFromToken(mdf));
+ IfFailGo(pMiniMd->GetFileRecord(RidFromToken(mdf), &pRecord));
+
+ if (ppbHashValue != NULL)
+ {
+ IfFailGo(pMiniMd->getHashValueOfFile(pRecord, (const BYTE **)ppbHashValue, pcbHashValue));
+ }
+ if (pdwFileFlags != NULL)
+ *pdwFileFlags = pMiniMd->getFlagsOfFile(pRecord);
+ // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK
+ if ((szName != NULL) || (pchName != NULL))
+ {
+ IfFailGo(pMiniMd->getNameOfFile(pRecord, szName, cchName, pchName));
+ }
+
+ErrExit:
+ STOP_MD_PERF(GetFileProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::GetFileProps
+
+//*******************************************************************************
+// Get the properties for the given ExportedType token.
+//*******************************************************************************
+STDMETHODIMP RegMeta::GetExportedTypeProps( // S_OK or error.
+ mdExportedType mdct, // [IN] The ExportedType for which to get the properties.
+ __out_ecount_part_opt(cchName, *pchName) 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 ExportedType.
+ mdTypeDef *ptkTypeDef, // [OUT] TypeDef token within the file.
+ DWORD *pdwExportedTypeFlags) // [OUT] Flags.
+{
+ HRESULT hr = S_OK; // A result.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ ExportedTypeRec *pRecord; // The exported type.
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ int bTruncation=0; // Was there name truncation?
+
+ LOG((LOGMD, "RegMeta::GetExportedTypeProps(%#08x, %#08x, %#08x, %#08x, %#08x, %#08x, %#08x)\n",
+ mdct, szName, cchName, pchName,
+ ptkImplementation, ptkTypeDef, pdwExportedTypeFlags));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ _ASSERTE(TypeFromToken(mdct) == mdtExportedType && RidFromToken(mdct));
+ IfFailGo(pMiniMd->GetExportedTypeRecord(RidFromToken(mdct), &pRecord));
+
+ if (szName || pchName)
+ {
+ LPCSTR szTypeNamespace;
+ LPCSTR szTypeName;
+
+ IfFailGo(pMiniMd->getTypeNamespaceOfExportedType(pRecord, &szTypeNamespace));
+ PREFIX_ASSUME(szTypeNamespace != NULL);
+ MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzTypeNamespace, szTypeNamespace);
+ IfNullGo(wzTypeNamespace);
+
+ IfFailGo(pMiniMd->getTypeNameOfExportedType(pRecord, &szTypeName));
+ _ASSERTE(*szTypeName);
+ MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzTypeName, szTypeName);
+ IfNullGo(wzTypeName);
+
+ if (szName)
+ bTruncation = ! (ns::MakePath(szName, cchName, wzTypeNamespace, wzTypeName));
+ if (pchName)
+ {
+ if (bTruncation || !szName)
+ *pchName = ns::GetFullLength(wzTypeNamespace, wzTypeName);
+ else
+ *pchName = (ULONG)(wcslen(szName) + 1);
+ }
+ }
+ if (ptkImplementation)
+ *ptkImplementation = pMiniMd->getImplementationOfExportedType(pRecord);
+ if (ptkTypeDef)
+ *ptkTypeDef = pMiniMd->getTypeDefIdOfExportedType(pRecord);
+ if (pdwExportedTypeFlags)
+ *pdwExportedTypeFlags = pMiniMd->getFlagsOfExportedType(pRecord);
+
+ if (bTruncation && hr == S_OK)
+ {
+ if ((szName != NULL) && (cchName > 0))
+ { // null-terminate the truncated output string
+ szName[cchName - 1] = W('\0');
+ }
+ hr = CLDB_S_TRUNCATION;
+ }
+
+ErrExit:
+ STOP_MD_PERF(GetExportedTypeProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::GetExportedTypeProps
+
+//*******************************************************************************
+// Get the properties for the given Resource token.
+//*******************************************************************************
+STDMETHODIMP RegMeta::GetManifestResourceProps( // S_OK or error.
+ mdManifestResource mdmr, // [IN] The ManifestResource for which to get the properties.
+ __out_ecount_part_opt(cchName, *pchName)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 ExportedType.
+ DWORD *pdwOffset, // [OUT] Offset to the beginning of the resource within the file.
+ DWORD *pdwResourceFlags) // [OUT] Flags.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ ManifestResourceRec *pRecord;
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ LOG((LOGMD, "RegMeta::GetManifestResourceProps("
+ "%#08x, %#08x, %#08x, %#08x, %#08x, %#08x, %#08x)\n",
+ mdmr, szName, cchName, pchName,
+ ptkImplementation, pdwOffset,
+ pdwResourceFlags));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ _ASSERTE(TypeFromToken(mdmr) == mdtManifestResource && RidFromToken(mdmr));
+ IfFailGo(pMiniMd->GetManifestResourceRecord(RidFromToken(mdmr), &pRecord));
+
+ if (ptkImplementation)
+ *ptkImplementation = pMiniMd->getImplementationOfManifestResource(pRecord);
+ if (pdwOffset)
+ *pdwOffset = pMiniMd->getOffsetOfManifestResource(pRecord);
+ if (pdwResourceFlags)
+ *pdwResourceFlags = pMiniMd->getFlagsOfManifestResource(pRecord);
+ // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK
+ if (szName || pchName)
+ IfFailGo(pMiniMd->getNameOfManifestResource(pRecord, szName, cchName, pchName));
+ErrExit:
+
+ STOP_MD_PERF(GetManifestResourceProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::GetManifestResourceProps
+
+
+//*******************************************************************************
+// Enumerating through all of the AssemblyRefs.
+//*******************************************************************************
+STDMETHODIMP RegMeta::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.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ HENUMInternal *pEnum;
+
+ LOG((LOGMD, "MD RegMeta::EnumAssemblyRefs(%#08x, %#08x, %#08x, %#08x)\n",
+ phEnum, rAssemblyRefs, cMax, pcTokens));
+ START_MD_PERF();
+
+ LOCKREAD();
+
+ if (*ppmdEnum == 0)
+ {
+ // instantiate a new ENUM.
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ // create the enumerator.
+ IfFailGo(HENUMInternal::CreateSimpleEnum(
+ mdtAssemblyRef,
+ 1,
+ pMiniMd->getCountAssemblyRefs() + 1,
+ &pEnum) );
+
+ // set the output parameter.
+ *ppmdEnum = pEnum;
+ }
+ else
+ pEnum = *ppmdEnum;
+
+ // we can only fill the minimum of what the caller asked for or what we have left.
+ IfFailGo(HENUMInternal::EnumWithCount(pEnum, cMax, rAssemblyRefs, pcTokens));
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+
+ STOP_MD_PERF(EnumAssemblyRefs);
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::EnumAssemblyRefs
+
+//*******************************************************************************
+// Enumerating through all of the Files.
+//*******************************************************************************
+STDMETHODIMP RegMeta::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.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ HENUMInternal *pEnum;
+
+ LOG((LOGMD, "MD RegMeta::EnumFiles(%#08x, %#08x, %#08x, %#08x)\n",
+ phEnum, rFiles, cMax, pcTokens));
+ START_MD_PERF();
+ LOCKREAD();
+
+ if (*ppmdEnum == 0)
+ {
+ // instantiate a new ENUM.
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ // create the enumerator.
+ IfFailGo(HENUMInternal::CreateSimpleEnum(
+ mdtFile,
+ 1,
+ pMiniMd->getCountFiles() + 1,
+ &pEnum) );
+
+ // set the output parameter.
+ *ppmdEnum = pEnum;
+ }
+ else
+ pEnum = *ppmdEnum;
+
+ // we can only fill the minimum of what the caller asked for or what we have left.
+ IfFailGo(HENUMInternal::EnumWithCount(pEnum, cMax, rFiles, pcTokens));
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+
+ STOP_MD_PERF(EnumFiles);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::EnumFiles
+
+//*******************************************************************************
+// Enumerating through all of the ExportedTypes.
+//*******************************************************************************
+STDMETHODIMP RegMeta::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.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ HENUMInternal *pEnum;
+
+ LOG((LOGMD, "MD RegMeta::EnumExportedTypes(%#08x, %#08x, %#08x, %#08x)\n",
+ phEnum, rExportedTypes, cMax, pcTokens));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ if (*ppmdEnum == 0)
+ {
+ // instantiate a new ENUM.
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ if (pMiniMd->HasDelete() &&
+ ((m_OptionValue.m_ImportOption & MDImportOptionAllExportedTypes) == 0))
+ {
+ IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtExportedType, &pEnum) );
+
+ // add all Types to the dynamic array if name is not _Delete
+ for (ULONG index = 1; index <= pMiniMd->getCountExportedTypes(); index ++ )
+ {
+ ExportedTypeRec *pRec;
+ IfFailGo(pMiniMd->GetExportedTypeRecord(index, &pRec));
+ LPCSTR szTypeName;
+ IfFailGo(pMiniMd->getTypeNameOfExportedType(pRec, &szTypeName));
+ if (IsDeletedName(szTypeName))
+ {
+ continue;
+ }
+ IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtExportedType) ) );
+ }
+ }
+ else
+ {
+ // create the enumerator.
+ IfFailGo(HENUMInternal::CreateSimpleEnum(
+ mdtExportedType,
+ 1,
+ pMiniMd->getCountExportedTypes() + 1,
+ &pEnum) );
+ }
+
+ // set the output parameter.
+ *ppmdEnum = pEnum;
+ }
+ else
+ pEnum = *ppmdEnum;
+
+ // we can only fill the minimum of what the caller asked for or what we have left.
+ IfFailGo(HENUMInternal::EnumWithCount(pEnum, cMax, rExportedTypes, pcTokens));
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+
+ STOP_MD_PERF(EnumExportedTypes);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::EnumExportedTypes
+
+//*******************************************************************************
+// Enumerating through all of the Resources.
+//*******************************************************************************
+STDMETHODIMP RegMeta::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.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ HENUMInternal *pEnum;
+
+ LOG((LOGMD, "MD RegMeta::EnumManifestResources(%#08x, %#08x, %#08x, %#08x)\n",
+ phEnum, rManifestResources, cMax, pcTokens));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ if (*ppmdEnum == 0)
+ {
+ // instantiate a new ENUM.
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ // create the enumerator.
+ IfFailGo(HENUMInternal::CreateSimpleEnum(
+ mdtManifestResource,
+ 1,
+ pMiniMd->getCountManifestResources() + 1,
+ &pEnum) );
+
+ // set the output parameter.
+ *ppmdEnum = pEnum;
+ }
+ else
+ pEnum = *ppmdEnum;
+
+ // we can only fill the minimum of what the caller asked for or what we have left.
+ IfFailGo(HENUMInternal::EnumWithCount(pEnum, cMax, rManifestResources, pcTokens));
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+
+ STOP_MD_PERF(EnumManifestResources);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::EnumManifestResources
+
+//*******************************************************************************
+// Get the Assembly token for the given scope..
+//*******************************************************************************
+STDMETHODIMP RegMeta::GetAssemblyFromScope( // S_OK or error
+ mdAssembly *ptkAssembly) // [OUT] Put token here.
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMd = NULL;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "MD RegMeta::GetAssemblyFromScope(%#08x)\n", ptkAssembly));
+ START_MD_PERF();
+ LOCKREAD();
+ _ASSERTE(ptkAssembly);
+
+ pMiniMd = &(m_pStgdb->m_MiniMd);
+ if (pMiniMd->getCountAssemblys())
+ {
+ *ptkAssembly = TokenFromRid(1, mdtAssembly);
+ }
+ else
+ {
+ IfFailGo( CLDB_E_RECORD_NOTFOUND );
+ }
+ErrExit:
+ STOP_MD_PERF(GetAssemblyFromScope);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::GetAssemblyFromScope
+
+//*******************************************************************************
+// Find the ExportedType given the name.
+//*******************************************************************************
+STDMETHODIMP RegMeta::FindExportedTypeByName( // S_OK or error
+ LPCWSTR szName, // [IN] Name of the ExportedType.
+ mdExportedType tkEnclosingType, // [IN] Enclosing ExportedType.
+ mdExportedType *ptkExportedType) // [OUT] Put the ExportedType token here.
+{
+ HRESULT hr = S_OK; // A result.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CMiniMdRW *pMiniMd = NULL;
+ LPSTR szNameUTF8 = NULL;
+
+ LOG((LOGMD, "MD RegMeta::FindExportedTypeByName(%S, %#08x, %#08x)\n",
+ MDSTR(szName), tkEnclosingType, ptkExportedType));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+
+ // Validate name for prefix.
+ if (!szName)
+ IfFailGo(E_INVALIDARG);
+
+ _ASSERTE(szName && ptkExportedType);
+
+ pMiniMd = &(m_pStgdb->m_MiniMd);
+ UTF8STR(szName, szNameUTF8);
+ LPCSTR szTypeName;
+ LPCSTR szTypeNamespace;
+
+ ns::SplitInline(szNameUTF8, szTypeNamespace, szTypeName);
+
+ IfFailGo(ImportHelper::FindExportedType(pMiniMd,
+ szTypeNamespace,
+ szTypeName,
+ tkEnclosingType,
+ ptkExportedType));
+ErrExit:
+ STOP_MD_PERF(FindExportedTypeByName);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::FindExportedTypeByName
+
+//*******************************************************************************
+// Find the ManifestResource given the name.
+//*******************************************************************************
+STDMETHODIMP RegMeta::FindManifestResourceByName( // S_OK or error
+ LPCWSTR szName, // [IN] Name of the ManifestResource.
+ mdManifestResource *ptkManifestResource) // [OUT] Put the ManifestResource token here.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LPCUTF8 szNameTmp = NULL;
+ CMiniMdRW *pMiniMd = NULL;
+
+ LOG((LOGMD, "MD RegMeta::FindManifestResourceByName(%S, %#08x)\n",
+ MDSTR(szName), ptkManifestResource));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+
+ // Validate name for prefix.
+ if (!szName)
+ IfFailGo(E_INVALIDARG);
+
+ _ASSERTE(szName && ptkManifestResource);
+
+ ManifestResourceRec *pRecord;
+ ULONG cRecords; // Count of records.
+ LPUTF8 szUTF8Name; // UTF8 version of the name passed in.
+ ULONG i;
+
+ pMiniMd = &(m_pStgdb->m_MiniMd);
+ *ptkManifestResource = mdManifestResourceNil;
+ cRecords = pMiniMd->getCountManifestResources();
+ UTF8STR(szName, szUTF8Name);
+
+ // Search for the TypeRef.
+ for (i = 1; i <= cRecords; i++)
+ {
+ IfFailGo(pMiniMd->GetManifestResourceRecord(i, &pRecord));
+ IfFailGo(pMiniMd->getNameOfManifestResource(pRecord, &szNameTmp));
+ if (! strcmp(szUTF8Name, szNameTmp))
+ {
+ *ptkManifestResource = TokenFromRid(i, mdtManifestResource);
+ goto ErrExit;
+ }
+ }
+ IfFailGo( CLDB_E_RECORD_NOTFOUND );
+ErrExit:
+
+ STOP_MD_PERF(FindManifestResourceByName);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::FindManifestResourceByName
+
+extern HRESULT STDMETHODCALLTYPE
+ GetAssembliesByName(LPCWSTR szAppBase,
+ LPCWSTR szPrivateBin,
+ LPCWSTR szAssemblyName,
+ IUnknown *ppIUnk[],
+ ULONG cMax,
+ ULONG *pcAssemblies);
+
+//*******************************************************************************
+// Used to find assemblies either in Fusion cache or on disk at build time.
+//*******************************************************************************
+STDMETHODIMP RegMeta::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.
+{
+#ifdef FEATURE_METADATA_IN_VM
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "RegMeta::FindAssembliesByName(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ szAppBase, szPrivateBin, szAssemblyName, ppIUnk, cMax, pcAssemblies));
+ START_MD_PERF();
+
+ // No need to lock this function. It is going through fusion to find the matching Assemblies by name
+
+ IfFailGo(GetAssembliesByName(szAppBase, szPrivateBin,
+ szAssemblyName, ppIUnk, cMax, pcAssemblies));
+
+ErrExit:
+ STOP_MD_PERF(FindAssembliesByName);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+#else //!FEATURE_METADATA_IN_VM
+ // Calls to fusion are not suported outside VM
+ return E_NOTIMPL;
+#endif //!FEATURE_METADATA_IN_VM
+} // RegMeta::FindAssembliesByName
diff --git a/src/md/compiler/assemblymd_emit.cpp b/src/md/compiler/assemblymd_emit.cpp
new file mode 100644
index 0000000000..72fb034221
--- /dev/null
+++ b/src/md/compiler/assemblymd_emit.cpp
@@ -0,0 +1,811 @@
+// 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.
+//*****************************************************************************
+// AssemblyMD.cpp
+//
+
+//
+// Implementation for the assembly meta data emit code (code:IMetaDataAssemblyEmit).
+//
+//*****************************************************************************
+#include "stdafx.h"
+#include "regmeta.h"
+#include "mdutil.h"
+#include "rwutil.h"
+#include "mdlog.h"
+#include "importhelper.h"
+
+#include <strongname.h>
+
+#ifdef _MSC_VER
+#pragma warning(disable: 4102)
+#endif
+
+#ifdef FEATURE_METADATA_EMIT
+
+//*******************************************************************************
+// Define an Assembly and set the attributes.
+//*******************************************************************************
+STDMETHODIMP RegMeta::DefineAssembly( // S_OK or error.
+ const void *pbPublicKey, // [IN] Public key of the assembly.
+ ULONG cbPublicKey, // [IN] Count of bytes in the public key.
+ ULONG ulHashAlgId, // [IN] Hash Algorithm.
+ LPCWSTR szName, // [IN] Name of the assembly.
+ const ASSEMBLYMETADATA *pMetaData, // [IN] Assembly MetaData.
+ DWORD dwAssemblyFlags, // [IN] Flags.
+ mdAssembly *pma) // [OUT] Returned Assembly token.
+{
+ HRESULT hr = S_OK;
+
+ AssemblyRec *pRecord = NULL; // The assembly record.
+ ULONG iRecord; // RID of the assembly record.
+
+ if (szName == NULL || pMetaData == NULL || pma == NULL)
+ return E_INVALIDARG;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "RegMeta::DefineAssembly(0x%08x, 0x%08x, 0x%08x, %S, 0x%08x, 0x%08x, 0x%08x)\n",
+ pbPublicKey, cbPublicKey, ulHashAlgId, MDSTR(szName), pMetaData,
+ dwAssemblyFlags, pma));
+
+ START_MD_PERF();
+ LOCKWRITE();
+
+ _ASSERTE(szName && pMetaData && pma);
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ // Assembly defs always contain a full public key (assuming they're strong
+ // named) rather than the tokenized version. Force the flag on to indicate
+ // this, and this way blindly copying public key & flags from a def to a ref
+ // will work (though the ref will be bulkier than strictly necessary).
+ if (cbPublicKey != 0)
+ dwAssemblyFlags |= afPublicKey;
+
+ if (CheckDups(MDDupAssembly))
+ { // Should be no more than one -- just check count of records.
+ if (m_pStgdb->m_MiniMd.getCountAssemblys() > 0)
+ { // S/b only one, so we know the rid.
+ iRecord = 1;
+ // If ENC, let them update the existing record.
+ if (IsENCOn())
+ IfFailGo(m_pStgdb->m_MiniMd.GetAssemblyRecord(iRecord, &pRecord));
+ else
+ { // Not ENC, so it is a duplicate.
+ *pma = TokenFromRid(iRecord, mdtAssembly);
+ hr = META_S_DUPLICATE;
+ goto ErrExit;
+ }
+ }
+ }
+ else
+ { // Not ENC, not duplicate checking, so shouldn't already have one.
+ _ASSERTE(m_pStgdb->m_MiniMd.getCountAssemblys() == 0);
+ }
+
+ // Create a new record, if needed.
+ if (pRecord == NULL)
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.AddAssemblyRecord(&pRecord, &iRecord));
+ }
+
+ // Set the output parameter.
+ *pma = TokenFromRid(iRecord, mdtAssembly);
+
+ IfFailGo(_SetAssemblyProps(*pma, pbPublicKey, cbPublicKey, ulHashAlgId, szName, pMetaData, dwAssemblyFlags));
+
+ErrExit:
+
+ STOP_MD_PERF(DefineAssembly);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::DefineAssembly
+
+//*******************************************************************************
+// Define an AssemblyRef and set the attributes.
+//*******************************************************************************
+STDMETHODIMP RegMeta::DefineAssemblyRef( // S_OK or error.
+ const void *pbPublicKeyOrToken, // [IN] Public key or token of the assembly.
+ ULONG cbPublicKeyOrToken, // [IN] Count of bytes in the public key or token.
+ LPCWSTR szName, // [IN] Name of the assembly being referenced.
+ const ASSEMBLYMETADATA *pMetaData, // [IN] Assembly MetaData.
+ const void *pbHashValue, // [IN] Hash Blob.
+ ULONG cbHashValue, // [IN] Count of bytes in the Hash Blob.
+ DWORD dwAssemblyRefFlags, // [IN] Flags.
+ mdAssemblyRef *pmar) // [OUT] Returned AssemblyRef token.
+{
+ HRESULT hr = S_OK;
+
+ AssemblyRefRec *pRecord = NULL;
+ ULONG iRecord;
+
+ if (szName == NULL || pmar == NULL || pMetaData == NULL)
+ return E_INVALIDARG;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "RegMeta::DefineAssemblyRef(0x%08x, 0x%08x, %S, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ pbPublicKeyOrToken, cbPublicKeyOrToken, MDSTR(szName), pMetaData, pbHashValue,
+ cbHashValue, dwAssemblyRefFlags, pmar));
+
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ _ASSERTE(szName && pmar);
+
+ if (CheckDups(MDDupAssemblyRef))
+ {
+ LPUTF8 szUTF8Name, szUTF8Locale;
+ UTF8STR(szName, szUTF8Name);
+ UTF8STR(pMetaData->szLocale, szUTF8Locale);
+ hr = ImportHelper::FindAssemblyRef(&m_pStgdb->m_MiniMd,
+ szUTF8Name,
+ szUTF8Locale,
+ pbPublicKeyOrToken,
+ cbPublicKeyOrToken,
+ pMetaData->usMajorVersion,
+ pMetaData->usMinorVersion,
+ pMetaData->usBuildNumber,
+ pMetaData->usRevisionNumber,
+ dwAssemblyRefFlags,
+ pmar);
+ if (SUCCEEDED(hr))
+ {
+ if (IsENCOn())
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.GetAssemblyRefRecord(RidFromToken(*pmar), &pRecord));
+ }
+ else
+ {
+ hr = META_S_DUPLICATE;
+ goto ErrExit;
+ }
+ }
+ else if (hr != CLDB_E_RECORD_NOTFOUND)
+ {
+ IfFailGo(hr);
+ }
+ }
+
+ // Create a new record if needed.
+ if (pRecord == NULL)
+ {
+ // Create a new record.
+ IfFailGo(m_pStgdb->m_MiniMd.AddAssemblyRefRecord(&pRecord, &iRecord));
+
+ // Set the output parameter.
+ *pmar = TokenFromRid(iRecord, mdtAssemblyRef);
+ }
+
+ // Set rest of the attributes.
+ SetCallerDefine();
+ IfFailGo(_SetAssemblyRefProps(*pmar, pbPublicKeyOrToken, cbPublicKeyOrToken, szName, pMetaData,
+ pbHashValue, cbHashValue,
+ dwAssemblyRefFlags));
+ErrExit:
+ SetCallerExternal();
+
+ STOP_MD_PERF(DefineAssemblyRef);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::DefineAssemblyRef
+
+//*******************************************************************************
+// Define a File and set the attributes.
+//*******************************************************************************
+STDMETHODIMP RegMeta::DefineFile( // S_OK or error.
+ LPCWSTR szName, // [IN] Name of the file.
+ const void *pbHashValue, // [IN] Hash Blob.
+ ULONG cbHashValue, // [IN] Count of bytes in the Hash Blob.
+ DWORD dwFileFlags, // [IN] Flags.
+ mdFile *pmf) // [OUT] Returned File token.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ FileRec *pRecord = NULL;
+ ULONG iRecord;
+
+ LOG((LOGMD, "RegMeta::DefineFile(%S, %#08x, %#08x, %#08x, %#08x)\n",
+ MDSTR(szName), pbHashValue, cbHashValue, dwFileFlags, pmf));
+
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ _ASSERTE(szName && pmf);
+
+ if (CheckDups(MDDupFile))
+ {
+ LPUTF8 szUTF8Name;
+ UTF8STR(szName, szUTF8Name);
+ hr = ImportHelper::FindFile(&m_pStgdb->m_MiniMd, szUTF8Name, pmf);
+ if (SUCCEEDED(hr))
+ {
+ if (IsENCOn())
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.GetFileRecord(RidFromToken(*pmf), &pRecord));
+ }
+ else
+ {
+ hr = META_S_DUPLICATE;
+ goto ErrExit;
+ }
+ }
+ else if (hr != CLDB_E_RECORD_NOTFOUND)
+ {
+ IfFailGo(hr);
+ }
+ }
+
+ // Create a new record if needed.
+ if (pRecord == NULL)
+ {
+ // Create a new record.
+ IfFailGo(m_pStgdb->m_MiniMd.AddFileRecord(&pRecord, &iRecord));
+
+ // Set the output parameter.
+ *pmf = TokenFromRid(iRecord, mdtFile);
+
+ // Set the name.
+ IfFailGo(m_pStgdb->m_MiniMd.PutStringW(TBL_File, FileRec::COL_Name, pRecord, szName));
+ }
+
+ // Set rest of the attributes.
+ IfFailGo(_SetFileProps(*pmf, pbHashValue, cbHashValue, dwFileFlags));
+ErrExit:
+
+ STOP_MD_PERF(DefineFile);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::DefineFile
+
+//*******************************************************************************
+// Define a ExportedType and set the attributes.
+//*******************************************************************************
+STDMETHODIMP RegMeta::DefineExportedType( // S_OK or error.
+ LPCWSTR szName, // [IN] Name of the Com Type.
+ mdToken tkImplementation, // [IN] mdFile or mdAssemblyRef that provides the ExportedType.
+ mdTypeDef tkTypeDef, // [IN] TypeDef token within the file.
+ DWORD dwExportedTypeFlags, // [IN] Flags.
+ mdExportedType *pmct) // [OUT] Returned ExportedType token.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ ExportedTypeRec *pRecord = NULL;
+ ULONG iRecord;
+ LPSTR szNameUTF8;
+ LPCSTR szTypeNameUTF8;
+ LPCSTR szTypeNamespaceUTF8;
+
+ LOG((LOGMD, "RegMeta::DefineExportedType(%S, %#08x, %08x, %#08x, %#08x)\n",
+ MDSTR(szName), tkImplementation, tkTypeDef,
+ dwExportedTypeFlags, pmct));
+
+ START_MD_PERF();
+ LOCKWRITE();
+
+ // Validate name for prefix.
+ if (szName == NULL)
+ IfFailGo(E_INVALIDARG);
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ //SLASHES2DOTS_NAMESPACE_BUFFER_UNICODE(szName, szName);
+
+ UTF8STR(szName, szNameUTF8);
+ // Split the name into name/namespace pair.
+ ns::SplitInline(szNameUTF8, szTypeNamespaceUTF8, szTypeNameUTF8);
+
+ _ASSERTE(szName && dwExportedTypeFlags != ULONG_MAX && pmct);
+ _ASSERTE(TypeFromToken(tkImplementation) == mdtFile ||
+ TypeFromToken(tkImplementation) == mdtAssemblyRef ||
+ TypeFromToken(tkImplementation) == mdtExportedType ||
+ tkImplementation == mdTokenNil);
+
+ if (CheckDups(MDDupExportedType))
+ {
+ hr = ImportHelper::FindExportedType(&m_pStgdb->m_MiniMd,
+ szTypeNamespaceUTF8,
+ szTypeNameUTF8,
+ tkImplementation,
+ pmct);
+ if (SUCCEEDED(hr))
+ {
+ if (IsENCOn())
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.GetExportedTypeRecord(RidFromToken(*pmct), &pRecord));
+ }
+ else
+ {
+ hr = META_S_DUPLICATE;
+ goto ErrExit;
+ }
+ }
+ else if (hr != CLDB_E_RECORD_NOTFOUND)
+ {
+ IfFailGo(hr);
+ }
+ }
+
+ // Create a new record if needed.
+ if (pRecord == NULL)
+ {
+ // Create a new record.
+ IfFailGo(m_pStgdb->m_MiniMd.AddExportedTypeRecord(&pRecord, &iRecord));
+
+ // Set the output parameter.
+ *pmct = TokenFromRid(iRecord, mdtExportedType);
+
+ // Set the TypeName and TypeNamespace.
+ IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_ExportedType,
+ ExportedTypeRec::COL_TypeName, pRecord, szTypeNameUTF8));
+ if (szTypeNamespaceUTF8)
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_ExportedType,
+ ExportedTypeRec::COL_TypeNamespace, pRecord, szTypeNamespaceUTF8));
+ }
+ }
+
+ // Set rest of the attributes.
+ IfFailGo(_SetExportedTypeProps(*pmct, tkImplementation, tkTypeDef,
+ dwExportedTypeFlags));
+ErrExit:
+
+ STOP_MD_PERF(DefineExportedType);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::DefineExportedType
+
+//*******************************************************************************
+// Define a Resource and set the attributes.
+//*******************************************************************************
+STDMETHODIMP RegMeta::DefineManifestResource( // S_OK or error.
+ LPCWSTR szName, // [IN] Name of the ManifestResource.
+ mdToken tkImplementation, // [IN] mdFile or mdAssemblyRef that provides the resource.
+ DWORD dwOffset, // [IN] Offset to the beginning of the resource within the file.
+ DWORD dwResourceFlags, // [IN] Flags.
+ mdManifestResource *pmmr) // [OUT] Returned ManifestResource token.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ ManifestResourceRec *pRecord = NULL;
+ ULONG iRecord;
+
+ LOG((LOGMD, "RegMeta::DefineManifestResource(%S, %#08x, %#08x, %#08x, %#08x)\n",
+ MDSTR(szName), tkImplementation, dwOffset, dwResourceFlags, pmmr));
+
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ _ASSERTE(szName && dwResourceFlags != ULONG_MAX && pmmr);
+ _ASSERTE(TypeFromToken(tkImplementation) == mdtFile ||
+ TypeFromToken(tkImplementation) == mdtAssemblyRef ||
+ tkImplementation == mdTokenNil);
+
+ if (CheckDups(MDDupManifestResource))
+ {
+ LPUTF8 szUTF8Name;
+ UTF8STR(szName, szUTF8Name);
+ hr = ImportHelper::FindManifestResource(&m_pStgdb->m_MiniMd, szUTF8Name, pmmr);
+ if (SUCCEEDED(hr))
+ {
+ if (IsENCOn())
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.GetManifestResourceRecord(RidFromToken(*pmmr), &pRecord));
+ }
+ else
+ {
+ hr = META_S_DUPLICATE;
+ goto ErrExit;
+ }
+ }
+ else if (hr != CLDB_E_RECORD_NOTFOUND)
+ {
+ IfFailGo(hr);
+ }
+ }
+
+ // Create a new record if needed.
+ if (pRecord == NULL)
+ {
+ // Create a new record.
+ IfFailGo(m_pStgdb->m_MiniMd.AddManifestResourceRecord(&pRecord, &iRecord));
+
+ // Set the output parameter.
+ *pmmr = TokenFromRid(iRecord, mdtManifestResource);
+
+ // Set the name.
+ IfFailGo(m_pStgdb->m_MiniMd.PutStringW(TBL_ManifestResource,
+ ManifestResourceRec::COL_Name, pRecord, szName));
+ }
+
+ // Set the rest of the attributes.
+ IfFailGo(_SetManifestResourceProps(*pmmr, tkImplementation,
+ dwOffset, dwResourceFlags));
+
+ErrExit:
+
+ STOP_MD_PERF(DefineManifestResource);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::DefineManifestResource
+
+//*******************************************************************************
+// Set the specified attributes on the given Assembly token.
+//*******************************************************************************
+STDMETHODIMP RegMeta::SetAssemblyProps( // S_OK or error.
+ mdAssembly ma, // [IN] Assembly token.
+ const void *pbPublicKey, // [IN] Public key of the assembly.
+ ULONG cbPublicKey, // [IN] Count of bytes in the public key.
+ ULONG ulHashAlgId, // [IN] Hash Algorithm.
+ LPCWSTR szName, // [IN] Name of the assembly.
+ const ASSEMBLYMETADATA *pMetaData, // [IN] Assembly MetaData.
+ DWORD dwAssemblyFlags) // [IN] Flags.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ _ASSERTE(TypeFromToken(ma) == mdtAssembly && RidFromToken(ma));
+
+ LOG((LOGMD, "RegMeta::SetAssemblyProps(%#08x, %#08x, %#08x, %#08x %S, %#08x, %#08x)\n",
+ ma, pbPublicKey, cbPublicKey, ulHashAlgId, MDSTR(szName), pMetaData, dwAssemblyFlags));
+
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ IfFailGo(_SetAssemblyProps(ma, pbPublicKey, cbPublicKey, ulHashAlgId, szName, pMetaData, dwAssemblyFlags));
+
+ErrExit:
+ STOP_MD_PERF(SetAssemblyProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP SetAssemblyProps()
+
+//*******************************************************************************
+// Set the specified attributes on the given AssemblyRef token.
+//*******************************************************************************
+STDMETHODIMP RegMeta::SetAssemblyRefProps( // S_OK or error.
+ mdAssemblyRef ar, // [IN] AssemblyRefToken.
+ const void *pbPublicKeyOrToken, // [IN] Public key or token of the assembly.
+ ULONG cbPublicKeyOrToken, // [IN] Count of bytes in the public key or token.
+ LPCWSTR szName, // [IN] Name of the assembly being referenced.
+ const ASSEMBLYMETADATA *pMetaData, // [IN] Assembly MetaData.
+ const void *pbHashValue, // [IN] Hash Blob.
+ ULONG cbHashValue, // [IN] Count of bytes in the Hash Blob.
+ DWORD dwAssemblyRefFlags) // [IN] Flags.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ _ASSERTE(TypeFromToken(ar) == mdtAssemblyRef && RidFromToken(ar));
+
+ LOG((LOGMD, "RegMeta::SetAssemblyRefProps(0x%08x, 0x%08x, 0x%08x, %S, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ ar, pbPublicKeyOrToken, cbPublicKeyOrToken, MDSTR(szName), pMetaData, pbHashValue, cbHashValue,
+ dwAssemblyRefFlags));
+
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ IfFailGo(_SetAssemblyRefProps(
+ ar,
+ pbPublicKeyOrToken,
+ cbPublicKeyOrToken,
+ szName,
+ pMetaData,
+ pbHashValue,
+ cbHashValue,
+ dwAssemblyRefFlags));
+
+ErrExit:
+ STOP_MD_PERF(SetAssemblyRefProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::SetAssemblyRefProps
+
+//*******************************************************************************
+// Set the specified attributes on the given File token.
+//*******************************************************************************
+STDMETHODIMP RegMeta::SetFileProps( // S_OK or error.
+ mdFile file, // [IN] File token.
+ const void *pbHashValue, // [IN] Hash Blob.
+ ULONG cbHashValue, // [IN] Count of bytes in the Hash Blob.
+ DWORD dwFileFlags) // [IN] Flags.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+
+ _ASSERTE(TypeFromToken(file) == mdtFile && RidFromToken(file));
+
+ LOG((LOGMD, "RegMeta::SetFileProps(%#08x, %#08x, %#08x, %#08x)\n",
+ file, pbHashValue, cbHashValue, dwFileFlags));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ IfFailGo( _SetFileProps(file, pbHashValue, cbHashValue, dwFileFlags) );
+
+ErrExit:
+
+ STOP_MD_PERF(SetFileProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::SetFileProps
+
+//*******************************************************************************
+// Set the specified attributes on the given ExportedType token.
+//*******************************************************************************
+STDMETHODIMP RegMeta::SetExportedTypeProps( // S_OK or error.
+ mdExportedType ct, // [IN] ExportedType token.
+ mdToken tkImplementation, // [IN] mdFile or mdAssemblyRef that provides the ExportedType.
+ mdTypeDef tkTypeDef, // [IN] TypeDef token within the file.
+ DWORD dwExportedTypeFlags) // [IN] Flags.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+
+ LOG((LOGMD, "RegMeta::SetExportedTypeProps(%#08x, %#08x, %#08x, %#08x)\n",
+ ct, tkImplementation, tkTypeDef, dwExportedTypeFlags));
+
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo( _SetExportedTypeProps( ct, tkImplementation, tkTypeDef, dwExportedTypeFlags) );
+
+ErrExit:
+
+ STOP_MD_PERF(SetExportedTypeProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::SetExportedTypeProps
+
+//*******************************************************************************
+// Set the specified attributes on the given ManifestResource token.
+//*******************************************************************************
+STDMETHODIMP RegMeta::SetManifestResourceProps(// S_OK or error.
+ mdManifestResource mr, // [IN] ManifestResource token.
+ mdToken tkImplementation, // [IN] mdFile or mdAssemblyRef that provides the resource.
+ DWORD dwOffset, // [IN] Offset to the beginning of the resource within the file.
+ DWORD dwResourceFlags) // [IN] Flags.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "RegMeta::SetManifestResourceProps(%#08x, %#08x, %#08x, %#08x)\n",
+ mr, tkImplementation, dwOffset,
+ dwResourceFlags));
+
+ _ASSERTE(TypeFromToken(tkImplementation) == mdtFile ||
+ TypeFromToken(tkImplementation) == mdtAssemblyRef ||
+ tkImplementation == mdTokenNil);
+
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo( _SetManifestResourceProps( mr, tkImplementation, dwOffset, dwResourceFlags) );
+
+ErrExit:
+
+ STOP_MD_PERF(SetManifestResourceProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::SetManifestResourceProps()
+
+//*******************************************************************************
+// Helper: Set the specified attributes on the given Assembly token.
+//*******************************************************************************
+HRESULT RegMeta::_SetAssemblyProps( // S_OK or error.
+ mdAssembly ma, // [IN] Assembly token.
+ const void *pbPublicKey, // [IN] Originator of the assembly.
+ ULONG cbPublicKey, // [IN] Count of bytes in the Originator blob.
+ ULONG ulHashAlgId, // [IN] Hash Algorithm.
+ LPCWSTR szName, // [IN] Name of the assembly.
+ const ASSEMBLYMETADATA *pMetaData, // [IN] Assembly MetaData.
+ DWORD dwAssemblyFlags) // [IN] Flags.
+{
+ AssemblyRec *pRecord = NULL; // The assembly record.
+ HRESULT hr = S_OK;
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetAssemblyRecord(RidFromToken(ma), &pRecord));
+
+ // Set the data.
+ if (pbPublicKey)
+ IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_Assembly, AssemblyRec::COL_PublicKey,
+ pRecord, pbPublicKey, cbPublicKey));
+ if (ulHashAlgId != ULONG_MAX)
+ pRecord->SetHashAlgId(ulHashAlgId);
+ IfFailGo(m_pStgdb->m_MiniMd.PutStringW(TBL_Assembly, AssemblyRec::COL_Name, pRecord, szName));
+ if (pMetaData->usMajorVersion != USHRT_MAX)
+ pRecord->SetMajorVersion(pMetaData->usMajorVersion);
+ if (pMetaData->usMinorVersion != USHRT_MAX)
+ pRecord->SetMinorVersion(pMetaData->usMinorVersion);
+ if (pMetaData->usBuildNumber != USHRT_MAX)
+ pRecord->SetBuildNumber(pMetaData->usBuildNumber);
+ if (pMetaData->usRevisionNumber != USHRT_MAX)
+ pRecord->SetRevisionNumber(pMetaData->usRevisionNumber);
+ if (pMetaData->szLocale)
+ IfFailGo(m_pStgdb->m_MiniMd.PutStringW(TBL_Assembly, AssemblyRec::COL_Locale,
+ pRecord, pMetaData->szLocale));
+
+ dwAssemblyFlags = (dwAssemblyFlags & ~afPublicKey) | (cbPublicKey ? afPublicKey : 0);
+ pRecord->SetFlags(dwAssemblyFlags);
+ IfFailGo(UpdateENCLog(ma));
+
+ErrExit:
+
+
+ return hr;
+} // HRESULT RegMeta::_SetAssemblyProps()
+
+//*******************************************************************************
+// Helper: Set the specified attributes on the given AssemblyRef token.
+//*******************************************************************************
+HRESULT RegMeta::_SetAssemblyRefProps( // S_OK or error.
+ mdAssemblyRef ar, // [IN] AssemblyRefToken.
+ const void *pbPublicKeyOrToken, // [IN] Public key or token of the assembly.
+ ULONG cbPublicKeyOrToken, // [IN] Count of bytes in the public key or token.
+ LPCWSTR szName, // [IN] Name of the assembly being referenced.
+ const ASSEMBLYMETADATA *pMetaData, // [IN] Assembly MetaData.
+ const void *pbHashValue, // [IN] Hash Blob.
+ ULONG cbHashValue, // [IN] Count of bytes in the Hash Blob.
+ DWORD dwAssemblyRefFlags) // [IN] Flags.
+{
+ AssemblyRefRec *pRecord;
+ HRESULT hr = S_OK;
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetAssemblyRefRecord(RidFromToken(ar), &pRecord));
+
+ if (pbPublicKeyOrToken)
+ IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_AssemblyRef, AssemblyRefRec::COL_PublicKeyOrToken,
+ pRecord, pbPublicKeyOrToken, cbPublicKeyOrToken));
+ if (szName)
+ IfFailGo(m_pStgdb->m_MiniMd.PutStringW(TBL_AssemblyRef, AssemblyRefRec::COL_Name,
+ pRecord, szName));
+ if (pMetaData)
+ {
+ if (pMetaData->usMajorVersion != USHRT_MAX)
+ pRecord->SetMajorVersion(pMetaData->usMajorVersion);
+ if (pMetaData->usMinorVersion != USHRT_MAX)
+ pRecord->SetMinorVersion(pMetaData->usMinorVersion);
+ if (pMetaData->usBuildNumber != USHRT_MAX)
+ pRecord->SetBuildNumber(pMetaData->usBuildNumber);
+ if (pMetaData->usRevisionNumber != USHRT_MAX)
+ pRecord->SetRevisionNumber(pMetaData->usRevisionNumber);
+ if (pMetaData->szLocale)
+ IfFailGo(m_pStgdb->m_MiniMd.PutStringW(TBL_AssemblyRef,
+ AssemblyRefRec::COL_Locale, pRecord, pMetaData->szLocale));
+
+ }
+ if (pbHashValue)
+ IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_AssemblyRef, AssemblyRefRec::COL_HashValue,
+ pRecord, pbHashValue, cbHashValue));
+ if (dwAssemblyRefFlags != ULONG_MAX)
+ pRecord->SetFlags(PrepareForSaving(dwAssemblyRefFlags));
+
+ IfFailGo(UpdateENCLog(ar));
+
+ErrExit:
+
+
+ return hr;
+} // RegMeta::_SetAssemblyRefProps
+
+//*******************************************************************************
+// Helper: Set the specified attributes on the given File token.
+//*******************************************************************************
+HRESULT RegMeta::_SetFileProps( // S_OK or error.
+ mdFile file, // [IN] File token.
+ const void *pbHashValue, // [IN] Hash Blob.
+ ULONG cbHashValue, // [IN] Count of bytes in the Hash Blob.
+ DWORD dwFileFlags) // [IN] Flags.
+{
+ FileRec *pRecord;
+ HRESULT hr = S_OK;
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetFileRecord(RidFromToken(file), &pRecord));
+
+ if (pbHashValue)
+ IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_File, FileRec::COL_HashValue, pRecord,
+ pbHashValue, cbHashValue));
+ if (dwFileFlags != ULONG_MAX)
+ pRecord->SetFlags(dwFileFlags);
+
+ IfFailGo(UpdateENCLog(file));
+ErrExit:
+ return hr;
+} // RegMeta::_SetFileProps
+
+//*******************************************************************************
+// Helper: Set the specified attributes on the given ExportedType token.
+//*******************************************************************************
+HRESULT RegMeta::_SetExportedTypeProps( // S_OK or error.
+ mdExportedType ct, // [IN] ExportedType token.
+ mdToken tkImplementation, // [IN] mdFile or mdAssemblyRef that provides the ExportedType.
+ mdTypeDef tkTypeDef, // [IN] TypeDef token within the file.
+ DWORD dwExportedTypeFlags) // [IN] Flags.
+{
+ ExportedTypeRec *pRecord;
+ HRESULT hr = S_OK;
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetExportedTypeRecord(RidFromToken(ct), &pRecord));
+
+ if(! IsNilToken(tkImplementation))
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_ExportedType, ExportedTypeRec::COL_Implementation,
+ pRecord, tkImplementation));
+ if (! IsNilToken(tkTypeDef))
+ {
+ _ASSERTE(TypeFromToken(tkTypeDef) == mdtTypeDef);
+ pRecord->SetTypeDefId(tkTypeDef);
+ }
+ if (dwExportedTypeFlags != ULONG_MAX)
+ pRecord->SetFlags(dwExportedTypeFlags);
+
+ IfFailGo(UpdateENCLog(ct));
+ErrExit:
+ return hr;
+} // RegMeta::_SetExportedTypeProps
+
+//*******************************************************************************
+// Helper: Set the specified attributes on the given ManifestResource token.
+//*******************************************************************************
+HRESULT RegMeta::_SetManifestResourceProps(// S_OK or error.
+ mdManifestResource mr, // [IN] ManifestResource token.
+ mdToken tkImplementation, // [IN] mdFile or mdAssemblyRef that provides the resource.
+ DWORD dwOffset, // [IN] Offset to the beginning of the resource within the file.
+ DWORD dwResourceFlags) // [IN] Flags.
+{
+ ManifestResourceRec *pRecord = NULL;
+ HRESULT hr = S_OK;
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetManifestResourceRecord(RidFromToken(mr), &pRecord));
+
+ // Set the attributes.
+ if (tkImplementation != mdTokenNil)
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_ManifestResource,
+ ManifestResourceRec::COL_Implementation, pRecord, tkImplementation));
+ if (dwOffset != ULONG_MAX)
+ pRecord->SetOffset(dwOffset);
+ if (dwResourceFlags != ULONG_MAX)
+ pRecord->SetFlags(dwResourceFlags);
+
+ IfFailGo(UpdateENCLog(mr));
+
+ErrExit:
+ return hr;
+} // RegMeta::_SetManifestResourceProps
+
+#endif //FEATURE_METADATA_EMIT
diff --git a/src/md/compiler/cacheload.h b/src/md/compiler/cacheload.h
new file mode 100644
index 0000000000..e1c3126fd9
--- /dev/null
+++ b/src/md/compiler/cacheload.h
@@ -0,0 +1,27 @@
+// 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.
+//*****************************************************************************
+// CacheLoad.h
+//
+
+//
+// Class for returning the memory image where the image lives
+//
+//*****************************************************************************
+#ifndef __CACHELOAD__H__
+#define __CACHELOAD__H__
+
+
+#undef INTERFACE
+#define INTERFACE ICacheLoad
+DECLARE_INTERFACE_(ICacheLoad, IUnknown)
+{
+ STDMETHOD(GetCachedImaged)(
+ LPVOID* pImage);
+
+ STDMETHOD(SetCachedImaged)(
+ LPVOID pImage);
+};
+
+#endif
diff --git a/src/md/compiler/classfactory.cpp b/src/md/compiler/classfactory.cpp
new file mode 100644
index 0000000000..603f7975aa
--- /dev/null
+++ b/src/md/compiler/classfactory.cpp
@@ -0,0 +1,173 @@
+// 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.
+//*****************************************************************************
+// ClassFactory.cpp
+//
+
+//
+// Dll* routines for entry points, and support for COM framework. The class
+// factory and other routines live in this module.
+//
+// This file is not included in the standalone metadata version, because standalone can't use COM,
+// let alone COM-activation. So this file gets linked into mscorwks.dll, and then the mscorwks
+// class factory delegates to this co-creation routine.
+//
+//*****************************************************************************
+#include "stdafx.h"
+
+#ifdef FEATURE_METADATA_IN_VM
+
+#include "classfactory.h"
+#include "disp.h"
+#include "regmeta.h"
+#include "mscoree.h"
+#include "corhost.h"
+
+#include "clrprivhosting.h"
+
+extern HRESULT TypeNameFactoryCreateObject(REFIID riid, void **ppUnk);
+
+#include <ndpversion.h>
+
+
+//********** Locals. **********************************************************
+HINSTANCE GetModuleInst();
+
+// @telesto - why does Telesto export any Co-classes at all?
+
+// This map contains the list of coclasses which are exported from this module.
+// NOTE: CLSID_CorMetaDataDispenser must be the first entry in this table!
+const COCLASS_REGISTER g_CoClasses[] =
+{
+// pClsid szProgID pfnCreateObject
+ { &CLSID_CorMetaDataDispenser, W("CorMetaDataDispenser"), Disp::CreateObject },
+#if !defined(FEATURE_CORECLR) && !defined(CROSSGEN_COMPILE) // coreclr doesn't export these
+ { &CLSID_CorMetaDataDispenserRuntime, W("CorMetaDataDispenserRuntime"), Disp::CreateObject },
+
+ { &CLSID_CorRuntimeHost, W("CorRuntimeHost"), CorHost::CreateObject },
+ { &CLSID_CLRRuntimeHost, W("CLRRuntimeHost"), CorHost2::CreateObject },
+ { &__uuidof(CLRPrivRuntime), W("CLRPrivRuntime"), CorHost2::CreateObject },
+ { &CLSID_TypeNameFactory, NULL, (PFN_CREATE_OBJ)TypeNameFactoryCreateObject },
+#endif // FEATURE_CORECLR && !CROSSGEN_COMPILE
+ { NULL, NULL, NULL }
+};
+
+
+//*****************************************************************************
+// Called by COM to get a class factory for a given CLSID. If it is one we
+// support, instantiate a class factory object and prepare for create instance.
+//
+// Notes:
+// This gets invoked from mscorwks's DllGetClassObject.
+//*****************************************************************************
+STDAPI MetaDataDllGetClassObject( // Return code.
+ REFCLSID rclsid, // The class to desired.
+ REFIID riid, // Interface wanted on class factory.
+ LPVOID FAR *ppv) // Return interface pointer here.
+{
+ MDClassFactory *pClassFactory; // To create class factory object.
+ const COCLASS_REGISTER *pCoClass; // Loop control.
+ HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
+
+ // Scan for the right one.
+ for (pCoClass=g_CoClasses; pCoClass->pClsid; pCoClass++)
+ {
+ if (*pCoClass->pClsid == rclsid)
+ {
+ // Allocate the new factory object.
+ pClassFactory = new (nothrow) MDClassFactory(pCoClass);
+ if (!pClassFactory)
+ return (E_OUTOFMEMORY);
+
+ // Pick the v-table based on the caller's request.
+ hr = pClassFactory->QueryInterface(riid, ppv);
+
+ // Always release the local reference, if QI failed it will be
+ // the only one and the object gets freed.
+ pClassFactory->Release();
+ break;
+ }
+ }
+ return hr;
+}
+
+
+//*****************************************************************************
+//
+//********** Class factory code.
+//
+//*****************************************************************************
+
+
+//*****************************************************************************
+// QueryInterface is called to pick a v-table on the co-class.
+//*****************************************************************************
+HRESULT STDMETHODCALLTYPE MDClassFactory::QueryInterface(
+ REFIID riid,
+ void **ppvObject)
+{
+ HRESULT hr;
+
+ // Avoid confusion.
+ *ppvObject = NULL;
+
+ // Pick the right v-table based on the IID passed in.
+ if (riid == IID_IUnknown)
+ *ppvObject = (IUnknown *) this;
+ else if (riid == IID_IClassFactory)
+ *ppvObject = (IClassFactory *) this;
+
+ // If successful, add a reference for out pointer and return.
+ if (*ppvObject)
+ {
+ hr = S_OK;
+ AddRef();
+ }
+ else
+ hr = E_NOINTERFACE;
+ return hr;
+}
+
+
+//*****************************************************************************
+// CreateInstance is called to create a new instance of the coclass for which
+// this class was created in the first place. The returned pointer is the
+// v-table matching the IID if there.
+//*****************************************************************************
+HRESULT STDMETHODCALLTYPE MDClassFactory::CreateInstance(
+ IUnknown *pUnkOuter,
+ REFIID riid,
+ void **ppvObject)
+{
+ HRESULT hr;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+
+ // Avoid confusion.
+ *ppvObject = NULL;
+ _ASSERTE(m_pCoClass);
+
+ // Aggregation is not supported by these objects.
+ if (pUnkOuter)
+ IfFailGo(CLASS_E_NOAGGREGATION);
+
+ // Ask the object to create an instance of itself, and check the iid.
+ hr = (*m_pCoClass->pfnCreateObject)(riid, ppvObject);
+
+ErrExit:
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+}
+
+HRESULT STDMETHODCALLTYPE
+MDClassFactory::LockServer(
+ BOOL fLock)
+{
+ // @FUTURE: Should we return E_NOTIMPL instead of S_OK?
+ return S_OK;
+}
+
+#endif //FEATURE_METADATA_IN_VM
diff --git a/src/md/compiler/classfactory.h b/src/md/compiler/classfactory.h
new file mode 100644
index 0000000000..3430fed0f2
--- /dev/null
+++ b/src/md/compiler/classfactory.h
@@ -0,0 +1,95 @@
+// 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.
+//*****************************************************************************
+// ClassFactory.h
+//
+
+//
+// Class factories are used by the pluming in COM to activate new objects.
+// This module contains the class factory code to instantiate the debugger
+// objects described in <cordb.h>.
+//
+//*****************************************************************************
+#ifndef __ClassFactory__h__
+#define __ClassFactory__h__
+
+#include "disp.h"
+
+
+// This typedef is for a function which will create a new instance of an object.
+typedef HRESULT (* PFN_CREATE_OBJ)(REFIID riid, void **ppvObject);
+
+//*****************************************************************************
+// This structure is used to declare a global list of coclasses. The class
+// factory object is created with a pointer to the correct one of these, so
+// that when create instance is called, it can be created.
+//*****************************************************************************
+struct COCLASS_REGISTER
+{
+ const GUID *pClsid; // Class ID of the coclass.
+ LPCWSTR szProgID; // Prog ID of the class.
+ PFN_CREATE_OBJ pfnCreateObject; // Creation function for an instance.
+};
+
+
+
+//*****************************************************************************
+// One class factory object satifies all of our clsid's, to reduce overall
+// code bloat.
+//*****************************************************************************
+class MDClassFactory :
+ public IClassFactory
+{
+ MDClassFactory() { } // Can't use without data.
+
+public:
+ MDClassFactory(const COCLASS_REGISTER *pCoClass)
+ : m_cRef(1), m_pCoClass(pCoClass)
+ { }
+
+ virtual ~MDClassFactory() {}
+
+ //
+ // IUnknown methods.
+ //
+
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void **ppvObject);
+
+ virtual ULONG STDMETHODCALLTYPE AddRef()
+ {
+ return InterlockedIncrement(&m_cRef);
+ }
+
+ virtual ULONG STDMETHODCALLTYPE Release()
+ {
+ LONG cRef = InterlockedDecrement(&m_cRef);
+ if (cRef <= 0)
+ delete this;
+ return (cRef);
+ }
+
+
+ //
+ // IClassFactory methods.
+ //
+
+ virtual HRESULT STDMETHODCALLTYPE CreateInstance(
+ IUnknown *pUnkOuter,
+ REFIID riid,
+ void **ppvObject);
+
+ virtual HRESULT STDMETHODCALLTYPE LockServer(
+ BOOL fLock);
+
+
+private:
+ LONG m_cRef; // Reference count.
+ const COCLASS_REGISTER *m_pCoClass; // The class we belong to.
+};
+
+
+
+#endif // __ClassFactory__h__
diff --git a/src/md/compiler/crossgen/.gitmirror b/src/md/compiler/crossgen/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/md/compiler/crossgen/.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/compiler/crossgen/CMakeLists.txt b/src/md/compiler/crossgen/CMakeLists.txt
new file mode 100644
index 0000000000..7baf17448b
--- /dev/null
+++ b/src/md/compiler/crossgen/CMakeLists.txt
@@ -0,0 +1,5 @@
+include(${CLR_DIR}/crossgen.cmake)
+include(../../md_wks.cmake)
+
+add_precompiled_header(stdafx.h ../stdafx.cpp MDCOMPILER_SOURCES)
+add_library_clr(mdcompiler_crossgen ${MDCOMPILER_SOURCES})
diff --git a/src/md/compiler/crossgen/MDCompiler_crossgen.nativeproj b/src/md/compiler/crossgen/MDCompiler_crossgen.nativeproj
new file mode 100644
index 0000000000..8ea56d2cdc
--- /dev/null
+++ b/src/md/compiler/crossgen/MDCompiler_crossgen.nativeproj
@@ -0,0 +1,15 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood">
+ <PropertyGroup>
+ <!-- All features are set in file:..\..\MD.props -->
+ <BuildSysBinaries>true</BuildSysBinaries>
+ <MetadataFlavor>wks</MetadataFlavor>
+ <OutputName>mdcompiler_crossgen</OutputName>
+ </PropertyGroup>
+
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\xplat\SetCrossGen.props" />
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\src\MD\Compiler\Compiler.settings.targets" />
+
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" />
+</Project>
diff --git a/src/md/compiler/custattr.h b/src/md/compiler/custattr.h
new file mode 100644
index 0000000000..119c05922a
--- /dev/null
+++ b/src/md/compiler/custattr.h
@@ -0,0 +1,117 @@
+// 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 __CustAttr__h__
+#define __CustAttr__h__
+
+//#include "stdafx.h"
+#include "corhdr.h"
+#include "cahlprinternal.h"
+#include "sarray.h"
+#include "factory.h"
+
+//*****************************************************************************
+// Argument parsing. The custom attributes may have ctor arguments, and may
+// have named arguments. The arguments are defined by the following tables.
+//
+// These tables also include a member to contain the value of the argument,
+// which is used at runtime. When parsing a given custom attribute, a copy
+// of the argument descriptors is filled in with the values for the instance
+// of the custom attribute.
+//
+// For each ctor arg, there is a CaArg struct, with the type. At runtime,
+// a value is filled in for each ctor argument.
+//
+// For each named arg, there is a CaNamedArg struct, with the name of the
+// argument, the expected type of the argument, if the type is an enum,
+// the name of the enum. Also, at runtime, a value is filled in for
+// each named argument found.
+//
+// Note that arrays and variants are not supported.
+//
+// At runtime, after the args have been parsed, the tag field of CaValue
+// can be used to determine if a particular arg was given.
+//*****************************************************************************
+struct CaArg
+{
+ void InitEnum(CorSerializationType _enumType, INT64 _val = 0)
+ {
+ CaTypeCtor caType(SERIALIZATION_TYPE_ENUM, SERIALIZATION_TYPE_UNDEFINED, _enumType, NULL, 0);
+ Init(caType, _val);
+ }
+ void Init(CorSerializationType _type, INT64 _val = 0)
+ {
+ _ASSERTE(_type != SERIALIZATION_TYPE_ENUM);
+ _ASSERTE(_type != SERIALIZATION_TYPE_SZARRAY);
+ CaTypeCtor caType(_type);
+ Init(caType, _val);
+ }
+ void Init(CaType _type, INT64 _val = 0)
+ {
+ type = _type;
+ memset(&val, 0, sizeof(CaValue));
+ val.i8 = _val;
+ }
+
+ CaType type;
+ CaValue val;
+};
+
+struct CaNamedArg
+{
+ void InitI4FieldEnum(LPCSTR _szName, LPCSTR _szEnumName, INT64 _val = 0)
+ {
+ CaTypeCtor caType(SERIALIZATION_TYPE_ENUM, SERIALIZATION_TYPE_UNDEFINED, SERIALIZATION_TYPE_I4, _szEnumName, (ULONG)strlen(_szEnumName));
+ Init(_szName, SERIALIZATION_TYPE_FIELD, caType, _val);
+ }
+
+ void InitBoolField(LPCSTR _szName, INT64 _val = 0)
+ {
+ CaTypeCtor caType(SERIALIZATION_TYPE_BOOLEAN);
+ Init(_szName, SERIALIZATION_TYPE_FIELD, caType, _val);
+ }
+
+ void Init(LPCSTR _szName, CorSerializationType _propertyOrField, CaType _type, INT64 _val = 0)
+ {
+ szName = _szName;
+ cName = _szName ? (ULONG)strlen(_szName) : 0;
+ propertyOrField = _propertyOrField;
+ type = _type;
+
+ memset(&val, 0, sizeof(CaValue));
+ val.i8 = _val;
+ }
+
+ LPCSTR szName;
+ ULONG cName;
+ CorSerializationType propertyOrField;
+ CaType type;
+ CaValue val;
+};
+
+struct CaNamedArgCtor : public CaNamedArg
+{
+ CaNamedArgCtor()
+ {
+ memset(this, 0, sizeof(CaNamedArg));
+ }
+};
+
+HRESULT ParseEncodedType(
+ CustomAttributeParser &ca,
+ CaType* pCaType);
+
+HRESULT ParseKnownCaArgs(
+ CustomAttributeParser &ca, // The Custom Attribute blob.
+ CaArg *pArgs, // Array of argument descriptors.
+ ULONG cArgs); // Count of argument descriptors.
+
+HRESULT ParseKnownCaNamedArgs(
+ CustomAttributeParser &ca, // The Custom Attribute blob.
+ CaNamedArg *pNamedArgs, // Array of argument descriptors.
+ ULONG cNamedArgs); // Count of argument descriptors.
+
+#endif
diff --git a/src/md/compiler/custattr_emit.cpp b/src/md/compiler/custattr_emit.cpp
new file mode 100644
index 0000000000..3e23600176
--- /dev/null
+++ b/src/md/compiler/custattr_emit.cpp
@@ -0,0 +1,2000 @@
+// 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.
+//*****************************************************************************
+// CustAttr_Emit.cpp
+//
+
+//
+// Implementation for the meta data custom attribute emit code (code:IMetaDataEmit).
+//
+//*****************************************************************************
+#include "stdafx.h"
+#include "regmeta.h"
+#include "metadata.h"
+#include "corerror.h"
+#include "mdutil.h"
+#include "rwutil.h"
+#include "mdlog.h"
+#include "importhelper.h"
+#include "mdperf.h"
+#include "posterror.h"
+#include "cahlprinternal.h"
+#include "custattr.h"
+#include "corhdr.h"
+#include <metamodelrw.h>
+
+#ifdef FEATURE_METADATA_EMIT
+
+//*****************************************************************************
+//*****************************************************************************
+// Support for "Pseudo Custom Attributes"
+
+
+//*****************************************************************************
+// Enumeration of known custom attributes.
+//*****************************************************************************
+#define KnownCaList() \
+ KnownCa(UNKNOWN) \
+ KnownCa(DllImportAttribute) \
+ KnownCa(GuidAttribute) \
+ KnownCa(ComImportAttribute) \
+ KnownCa(InterfaceTypeAttribute) \
+ KnownCa(ClassInterfaceAttribute) \
+ KnownCa(SerializableAttribute) \
+ KnownCa(NonSerializedAttribute) \
+ KnownCa(MethodImplAttribute1) \
+ KnownCa(MethodImplAttribute2) \
+ KnownCa(MethodImplAttribute3) \
+ KnownCa(MarshalAsAttribute1) \
+ KnownCa(MarshalAsAttribute2) \
+ KnownCa(PreserveSigAttribute) \
+ KnownCa(InAttribute) \
+ KnownCa(OutAttribute) \
+ KnownCa(OptionalAttribute) \
+ KnownCa(StructLayoutAttribute1) \
+ KnownCa(StructLayoutAttribute2) \
+ KnownCa(FieldOffsetAttribute) \
+ KnownCa(TypeLibVersionAttribute) \
+ KnownCa(ComCompatibleVersionAttribute) \
+ KnownCa(SpecialNameAttribute) \
+ KnownCa(AllowPartiallyTrustedCallersAttribute) \
+ KnownCa(WindowsRuntimeImportAttribute) \
+
+// Ids for the CA's. CA_DllImportAttribute, etc.
+#define KnownCa(x) CA_##x,
+enum {
+ KnownCaList()
+ CA_COUNT
+};
+
+
+//*****************************************************************************
+// Properties of the known custom attributes.
+//
+// These tables describe the known custom attributes. For each custom
+// attribute, we know the namespace and name of the custom attribute,
+// the types to which the CA applies, the ctor args, and possible named
+// args. There is a flag which specifies whether the custom attribute
+// should be kept, in addition to any processing done with the data.
+//*****************************************************************************
+const BOOL bKEEPCA = TRUE;
+const BOOL bDONTKEEPCA = FALSE;
+const BOOL bMATCHBYSIG = TRUE;
+const BOOL bMATCHBYNAME = FALSE;
+
+struct KnownCaProp
+{
+ LPCUTF8 szNamespace; // Namespace of the custom attribute.
+ LPCUTF8 szName; // Name of the custom attribute.
+ const mdToken * rTypes; // Types that the CA applies to.
+ BOOL bKeepCa; // Keep the CA after processing?
+ const CaArg * pArgs; // List of ctor argument descriptors.
+ ULONG cArgs; // Count of ctor argument descriptors.
+ const CaNamedArg * pNamedArgs; // List of named arg descriptors.
+ ULONG cNamedArgs; // Count of named arg descriptors.
+ BOOL bMatchBySig; // For overloads; match by sig, not just name.
+ // WARNING: All overloads need the flag!
+};
+
+// Recognized targets for known custom attributes.
+// If Target includes mdtAssembly, then make sure to include mdtTypeRef as well,
+// aLink uses mdtTypeRef target temporarily for assembly target attributes
+const mdToken DllImportTargets[] = {mdtMethodDef, (ULONG32) -1};
+const mdToken GuidTargets[] = {mdtTypeDef, mdtTypeRef, mdtModule, mdtAssembly, (ULONG32) -1};
+const mdToken ComImportTargets[] = {mdtTypeDef, (ULONG32) -1};
+const mdToken InterfaceTypeTargets[] = {mdtTypeDef, (ULONG32) -1};
+const mdToken ClassInterfaceTargets[] = {mdtTypeDef, mdtAssembly, mdtTypeRef, (ULONG32) -1};
+const mdToken SerializableTargets[] = {mdtTypeDef, (ULONG32) -1};
+const mdToken NotInGCHeapTargets[] = {mdtTypeDef, (ULONG32) -1};
+const mdToken NonSerializedTargets[] = {mdtFieldDef, (ULONG32) -1};
+const mdToken MethodImplTargets[] = {mdtMethodDef, (ULONG32) -1};
+const mdToken MarshalTargets[] = {mdtFieldDef, mdtParamDef, mdtProperty, (ULONG32) -1};
+const mdToken PreserveSigTargets[] = {mdtMethodDef, (ULONG32) -1};
+const mdToken InOutTargets[] = {mdtParamDef, (ULONG32) -1};
+const mdToken StructLayoutTargets[] = {mdtTypeDef, (ULONG32) -1};
+const mdToken FieldOffsetTargets[] = {mdtFieldDef, (ULONG32) -1};
+const mdToken TypeLibVersionTargets[] = {mdtAssembly, mdtTypeRef,(ULONG32) -1};
+const mdToken ComCompatibleVersionTargets[] = {mdtAssembly, mdtTypeRef, (ULONG32) -1};
+const mdToken SpecialNameTargets[] = {mdtTypeDef, mdtMethodDef, mdtFieldDef, mdtProperty, mdtEvent, (ULONG32) -1};
+const mdToken AllowPartiallyTrustedCallersTargets[] = {mdtAssembly, mdtTypeRef, (ULONG32) -1};
+const mdToken WindowsRuntimeImportTargets[] = {mdtTypeDef, (ULONG32) -1};
+
+
+//#ifndef CEE_CALLCONV
+// # define CEE_CALLCONV (IMAGE_CEE_CS_CALLCONV_DEFAULT | IMAGE_CEE_CS_CALLCONV_HASTHIS)
+//#endif
+
+#define DEFINE_CA_CTOR_ARGS(NAME) \
+ const CaArg r##NAME##Args[] = \
+ {
+#define DEFINE_CA_CTOR_ARG(TYPE) {{TYPE}},
+#define DEFINE_CA_CTOR_ARGS_END() \
+ };
+
+
+
+#define DEFINE_CA_NAMED_ARGS(NAME) \
+ const CaNamedArg r##NAME##NamedArgs[] = \
+ {
+
+#define DEFINE_CA_NAMED_ARG(NAME, PROPORFIELD, TYPE, ARRAYTYPE, ENUMTYPE, ENUMNAME) \
+ { NAME, sizeof(NAME) - 1, PROPORFIELD, { TYPE, ARRAYTYPE, ENUMTYPE, ENUMNAME, sizeof(ENUMNAME) - 1 } },
+
+#define DEFINE_CA_NAMED_PROP_I4ENUM(NAME, ENUM) \
+ DEFINE_CA_NAMED_ARG(NAME, SERIALIZATION_TYPE_PROPERTY, SERIALIZATION_TYPE_ENUM, SERIALIZATION_TYPE_UNDEFINED, SERIALIZATION_TYPE_I4, ENUM)
+#define DEFINE_CA_NAMED_FIELD_I4ENUM(NAME, ENUM) \
+ DEFINE_CA_NAMED_ARG(NAME, SERIALIZATION_TYPE_FIELD, SERIALIZATION_TYPE_ENUM, SERIALIZATION_TYPE_UNDEFINED, SERIALIZATION_TYPE_I4, ENUM)
+#define DEFINE_CA_NAMED_PROP(NAME, TYPE) \
+ DEFINE_CA_NAMED_ARG(NAME, SERIALIZATION_TYPE_PROPERTY, TYPE, SERIALIZATION_TYPE_UNDEFINED, SERIALIZATION_TYPE_UNDEFINED, "")
+#define DEFINE_CA_NAMED_FIELD(NAME, TYPE) \
+ DEFINE_CA_NAMED_ARG(NAME, SERIALIZATION_TYPE_FIELD, TYPE, SERIALIZATION_TYPE_UNDEFINED, SERIALIZATION_TYPE_UNDEFINED, "")
+#define DEFINE_CA_NAMED_PROP_BOOL(NAME) DEFINE_CA_NAMED_PROP(NAME, SERIALIZATION_TYPE_BOOLEAN)
+#define DEFINE_CA_NAMED_FIELD_BOOL(NAME) DEFINE_CA_NAMED_FIELD(NAME, SERIALIZATION_TYPE_BOOLEAN)
+#define DEFINE_CA_NAMED_PROP_STRING(NAME) DEFINE_CA_NAMED_PROP(NAME, SERIALIZATION_TYPE_STRING)
+#define DEFINE_CA_NAMED_FIELD_STRING(NAME) DEFINE_CA_NAMED_FIELD(NAME, SERIALIZATION_TYPE_STRING)
+#define DEFINE_CA_NAMED_PROP_TYPE(NAME) DEFINE_CA_NAMED_PROP(NAME, SERIALIZATION_TYPE_TYPE)
+#define DEFINE_CA_NAMED_FIELD_TYPE(NAME) DEFINE_CA_NAMED_FIELD(NAME, SERIALIZATION_TYPE_TYPE)
+#define DEFINE_CA_NAMED_PROP_I2(NAME) DEFINE_CA_NAMED_PROP(NAME, SERIALIZATION_TYPE_I2)
+#define DEFINE_CA_NAMED_FIELD_I2(NAME) DEFINE_CA_NAMED_FIELD(NAME, SERIALIZATION_TYPE_I2)
+#define DEFINE_CA_NAMED_PROP_I4(NAME) DEFINE_CA_NAMED_PROP(NAME, SERIALIZATION_TYPE_I4)
+#define DEFINE_CA_NAMED_FIELD_I4(NAME) DEFINE_CA_NAMED_FIELD(NAME, SERIALIZATION_TYPE_I4)
+
+#define DEFINE_CA_NAMED_ARGS_END() \
+ };
+
+//-----------------------------------------------------------------------------
+// index 0 is used as a placeholder.
+const KnownCaProp UNKNOWNProps = {0};
+
+//-----------------------------------------------------------------------------
+// DllImport args, named args, and known attribute properties.
+DEFINE_CA_CTOR_ARGS(DllImportAttribute)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_STRING)
+DEFINE_CA_CTOR_ARGS_END()
+
+// NOTE: Keep this enum in sync with the array of named arguments.
+enum DllImportNamedArgs
+{
+ DI_CallingConvention,
+ DI_CharSet,
+ DI_EntryPoint,
+ DI_ExactSpelling,
+ DI_SetLastError,
+ DI_PreserveSig,
+ DI_BestFitMapping,
+ DI_ThrowOnUnmappableChar,
+ DI_COUNT
+};
+
+DEFINE_CA_NAMED_ARGS(DllImportAttribute)
+ DEFINE_CA_NAMED_FIELD_I4ENUM("CallingConvention", "System.Runtime.InteropServices.CallingConvention")
+ DEFINE_CA_NAMED_FIELD_I4ENUM("CharSet", "System.Runtime.InteropServices.CharSet")
+ DEFINE_CA_NAMED_FIELD_STRING("EntryPoint")
+ DEFINE_CA_NAMED_FIELD_BOOL("ExactSpelling")
+ DEFINE_CA_NAMED_FIELD_BOOL("SetLastError")
+ DEFINE_CA_NAMED_FIELD_BOOL("PreserveSig")
+ DEFINE_CA_NAMED_FIELD_BOOL("BestFitMapping")
+ DEFINE_CA_NAMED_FIELD_BOOL("ThrowOnUnmappableChar")
+DEFINE_CA_NAMED_ARGS_END()
+
+const KnownCaProp DllImportAttributeProps = {"System.Runtime.InteropServices", "DllImportAttribute", DllImportTargets, bDONTKEEPCA,
+ rDllImportAttributeArgs, lengthof(rDllImportAttributeArgs),
+ rDllImportAttributeNamedArgs, lengthof(rDllImportAttributeNamedArgs)};
+
+//-----------------------------------------------------------------------------
+// GUID args, named args (none), and known attribute properties.
+DEFINE_CA_CTOR_ARGS(GuidAttribute)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_STRING)
+DEFINE_CA_CTOR_ARGS_END()
+
+const KnownCaProp GuidAttributeProps = {"System.Runtime.InteropServices", "GuidAttribute", GuidTargets, bKEEPCA,
+ rGuidAttributeArgs, lengthof(rGuidAttributeArgs)};
+
+//-----------------------------------------------------------------------------
+// ComImport args (none), named args (none), and known attribute properties.
+const KnownCaProp ComImportAttributeProps = {"System.Runtime.InteropServices", "ComImportAttribute", ComImportTargets};
+
+//-----------------------------------------------------------------------------
+// Interface type args, named args (none), and known attribute properties.
+DEFINE_CA_CTOR_ARGS(InterfaceTypeAttribute)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_U2)
+DEFINE_CA_CTOR_ARGS_END()
+
+const KnownCaProp InterfaceTypeAttributeProps = {"System.Runtime.InteropServices", "InterfaceTypeAttribute", InterfaceTypeTargets, bKEEPCA,
+ rInterfaceTypeAttributeArgs, lengthof(rInterfaceTypeAttributeArgs)};
+
+//-----------------------------------------------------------------------------
+// Class interface type args, named args (none), and known attribute properties.
+DEFINE_CA_CTOR_ARGS(ClassInterfaceAttribute)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_U2)
+DEFINE_CA_CTOR_ARGS_END()
+
+const KnownCaProp ClassInterfaceAttributeProps = {"System.Runtime.InteropServices", "ClassInterfaceAttribute", ClassInterfaceTargets, bKEEPCA,
+ rClassInterfaceAttributeArgs, lengthof(rClassInterfaceAttributeArgs)};
+
+//-----------------------------------------------------------------------------
+// Serializable args (none), named args (none), and known attribute properties.
+const KnownCaProp SerializableAttributeProps = {"System", "SerializableAttribute", SerializableTargets};
+
+//-----------------------------------------------------------------------------
+// NonSerialized args (none), named args (none), and known attribute properties.
+const KnownCaProp NonSerializedAttributeProps = {"System", "NonSerializedAttribute", NonSerializedTargets};
+
+//-----------------------------------------------------------------------------
+// SpecialName args (none), named args (none), and known attribute properties.
+const KnownCaProp SpecialNameAttributeProps = {"System.Runtime.CompilerServices", "SpecialNameAttribute", SpecialNameTargets, bDONTKEEPCA};
+
+//-----------------------------------------------------------------------------
+// WindowsRuntimeImport args (none), named args (none), and known attribute properties.
+const KnownCaProp WindowsRuntimeImportAttributeProps = {"System.Runtime.InteropServices.WindowsRuntime", "WindowsRuntimeImportAttribute", WindowsRuntimeImportTargets};
+
+
+//-----------------------------------------------------------------------------
+// MethodImpl #1 args (none), named args, and known attribute properties.
+// MethodImpl #2 args (short), named args, and known attribute properties.
+// MethodImpl #3 args (enum), named args, and known attribute properties.
+// Note: first two match by signature; third by name only, because signature matching code is not
+// strong enough for enums.
+DEFINE_CA_CTOR_ARGS(MethodImplAttribute2)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I2)
+DEFINE_CA_CTOR_ARGS_END()
+
+DEFINE_CA_CTOR_ARGS(MethodImplAttribute3)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_U4)
+DEFINE_CA_CTOR_ARGS_END()
+
+enum MethodImplAttributeNamedArgs
+{
+ MI_CodeType,
+ MI_COUNT
+};
+
+DEFINE_CA_NAMED_ARGS(MethodImplAttribute)
+ DEFINE_CA_NAMED_FIELD_I4ENUM("MethodCodeType", "System.Runtime.CompilerServices.MethodCodeType")
+DEFINE_CA_NAMED_ARGS_END()
+
+const KnownCaProp MethodImplAttribute1Props = {"System.Runtime.CompilerServices", "MethodImplAttribute", MethodImplTargets, bDONTKEEPCA,
+ 0, 0,
+ rMethodImplAttributeNamedArgs, lengthof(rMethodImplAttributeNamedArgs),
+ bMATCHBYSIG};
+const KnownCaProp MethodImplAttribute2Props = {"System.Runtime.CompilerServices", "MethodImplAttribute", MethodImplTargets, bDONTKEEPCA,
+ rMethodImplAttribute2Args, lengthof(rMethodImplAttribute2Args),
+ rMethodImplAttributeNamedArgs, lengthof(rMethodImplAttributeNamedArgs),
+ bMATCHBYSIG};
+const KnownCaProp MethodImplAttribute3Props = {"System.Runtime.CompilerServices", "MethodImplAttribute", MethodImplTargets, bDONTKEEPCA,
+ rMethodImplAttribute3Args, lengthof(rMethodImplAttribute3Args),
+ rMethodImplAttributeNamedArgs, lengthof(rMethodImplAttributeNamedArgs),
+ bMATCHBYNAME};
+
+//-----------------------------------------------------------------------------
+// Marshal args, named args, and known attribute properties.
+DEFINE_CA_CTOR_ARGS(MarshalAsAttribute2)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_U4)
+DEFINE_CA_CTOR_ARGS_END()
+
+DEFINE_CA_CTOR_ARGS(MarshalAsAttribute1)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I2)
+DEFINE_CA_CTOR_ARGS_END()
+
+// NOTE: Keep this enum in sync with the array of named arguments.
+enum MarshalNamedArgs
+{
+ M_ArraySubType,
+ M_SafeArraySubType,
+ M_SafeArrayUserDefinedSubType,
+ M_SizeParamIndex,
+ M_SizeConst,
+ M_MarshalType,
+ M_MarshalTypeRef,
+ M_MarshalCookie,
+ M_IidParameterIndex,
+ M_COUNT
+};
+
+DEFINE_CA_NAMED_ARGS(MarshalAsAttribute)
+ DEFINE_CA_NAMED_FIELD_I4ENUM("ArraySubType", "System.Runtime.InteropServices.UnmanagedType")
+ DEFINE_CA_NAMED_FIELD_I4ENUM("SafeArraySubType", "System.Runtime.InteropServices.VarEnum")
+ DEFINE_CA_NAMED_FIELD_TYPE("SafeArrayUserDefinedSubType")
+ DEFINE_CA_NAMED_FIELD_I2("SizeParamIndex")
+ DEFINE_CA_NAMED_FIELD_I4("SizeConst")
+ DEFINE_CA_NAMED_FIELD_STRING("MarshalType")
+ DEFINE_CA_NAMED_FIELD_TYPE("MarshalTypeRef")
+ DEFINE_CA_NAMED_FIELD_STRING("MarshalCookie")
+ DEFINE_CA_NAMED_FIELD_I4("IidParameterIndex")
+DEFINE_CA_NAMED_ARGS_END()
+
+const KnownCaProp MarshalAsAttribute1Props = {"System.Runtime.InteropServices", "MarshalAsAttribute", MarshalTargets, bDONTKEEPCA,
+ rMarshalAsAttribute1Args, lengthof(rMarshalAsAttribute1Args),
+ rMarshalAsAttributeNamedArgs, lengthof(rMarshalAsAttributeNamedArgs),
+ bMATCHBYSIG};
+
+const KnownCaProp MarshalAsAttribute2Props = {"System.Runtime.InteropServices", "MarshalAsAttribute", MarshalTargets, bDONTKEEPCA,
+ rMarshalAsAttribute2Args, lengthof(rMarshalAsAttribute2Args),
+ rMarshalAsAttributeNamedArgs, lengthof(rMarshalAsAttributeNamedArgs),
+ bMATCHBYNAME};
+
+//-----------------------------------------------------------------------------
+// PreserveSignature args, named args (none), and known attribute properties.
+const KnownCaProp PreserveSigAttributeProps = {"System.Runtime.InteropServices", "PreserveSigAttribute", PreserveSigTargets, bDONTKEEPCA};
+
+//-----------------------------------------------------------------------------
+// In args (none), named args (none), and known attribute properties.
+const KnownCaProp InAttributeProps = {"System.Runtime.InteropServices", "InAttribute", InOutTargets};
+
+//-----------------------------------------------------------------------------
+// Out args (none), named args (none), and known attribute properties.
+const KnownCaProp OutAttributeProps = {"System.Runtime.InteropServices", "OutAttribute", InOutTargets};
+
+//-----------------------------------------------------------------------------
+// Optional args (none), named args (none), and known attribute properties.
+const KnownCaProp OptionalAttributeProps = {"System.Runtime.InteropServices", "OptionalAttribute", InOutTargets};
+
+//-----------------------------------------------------------------------------
+// StructLayout args, named args, and known attribute properties.
+DEFINE_CA_CTOR_ARGS(StructLayoutAttribute2)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4)
+DEFINE_CA_CTOR_ARGS_END()
+
+DEFINE_CA_CTOR_ARGS(StructLayoutAttribute1)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I2)
+DEFINE_CA_CTOR_ARGS_END()
+
+// NOTE: Keep this enum in sync with the array of named arguments.
+enum StructLayoutNamedArgs
+{
+ SL_Pack,
+ SL_Size,
+ SL_CharSet,
+ SL_COUNT
+};
+
+DEFINE_CA_NAMED_ARGS(StructLayoutAttribute)
+ DEFINE_CA_NAMED_FIELD_I4("Pack")
+ DEFINE_CA_NAMED_FIELD_I4("Size")
+ DEFINE_CA_NAMED_FIELD_I4ENUM("CharSet", "System.Runtime.InteropServices.CharSet")
+DEFINE_CA_NAMED_ARGS_END()
+
+const KnownCaProp StructLayoutAttribute1Props = {"System.Runtime.InteropServices", "StructLayoutAttribute", StructLayoutTargets, bDONTKEEPCA,
+ rStructLayoutAttribute1Args, lengthof(rStructLayoutAttribute1Args),
+ rStructLayoutAttributeNamedArgs, lengthof(rStructLayoutAttributeNamedArgs),
+ bMATCHBYSIG};
+const KnownCaProp StructLayoutAttribute2Props = {"System.Runtime.InteropServices", "StructLayoutAttribute", StructLayoutTargets, bDONTKEEPCA,
+ rStructLayoutAttribute2Args, lengthof(rStructLayoutAttribute2Args),
+ rStructLayoutAttributeNamedArgs, lengthof(rStructLayoutAttributeNamedArgs),
+ bMATCHBYNAME};
+
+//-----------------------------------------------------------------------------
+// FieldOffset args, named args (none), and known attribute properties.
+DEFINE_CA_CTOR_ARGS(FieldOffsetAttribute)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_U4)
+DEFINE_CA_CTOR_ARGS_END()
+
+const KnownCaProp FieldOffsetAttributeProps = {"System.Runtime.InteropServices", "FieldOffsetAttribute", FieldOffsetTargets, bDONTKEEPCA,
+ rFieldOffsetAttributeArgs, lengthof(rFieldOffsetAttributeArgs)};
+
+DEFINE_CA_CTOR_ARGS(TypeLibVersionAttribute)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4)
+DEFINE_CA_CTOR_ARGS_END()
+
+const KnownCaProp TypeLibVersionAttributeProps = {"System.Runtime.InteropServices", "TypeLibVersionAttribute", TypeLibVersionTargets, bKEEPCA,
+ rTypeLibVersionAttributeArgs, lengthof(rTypeLibVersionAttributeArgs)};
+
+
+DEFINE_CA_CTOR_ARGS(ComCompatibleVersionAttribute)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4)
+DEFINE_CA_CTOR_ARGS_END()
+
+const KnownCaProp ComCompatibleVersionAttributeProps = {"System.Runtime.InteropServices", "ComCompatibleVersionAttribute", ComCompatibleVersionTargets, bKEEPCA,
+ rComCompatibleVersionAttributeArgs, lengthof(rComCompatibleVersionAttributeArgs)};
+
+
+//-----------------------------------------------------------------------------
+// APTCA args (none), named args (none), and known attribute properties.
+const KnownCaProp AllowPartiallyTrustedCallersAttributeProps = {"System.Security", "AllowPartiallyTrustedCallersAttribute", AllowPartiallyTrustedCallersTargets, bKEEPCA};
+
+
+
+//-----------------------------------------------------------------------------
+// Array of known custom attribute properties
+#undef KnownCa
+#define KnownCa(x) &x##Props,
+const KnownCaProp * const rKnownCaProps[CA_COUNT] =
+{
+ KnownCaList()
+};
+
+//*****************************************************************************
+// Helper to turn on or off a single bit in a bitmask.
+//*****************************************************************************
+template<class T> FORCEINLINE void SetBitValue(T &bitmask, T bit, int bVal)
+{
+ if (bVal)
+ bitmask |= bit;
+ else
+ bitmask &= ~bit;
+} // template<class T> FORCEINLINE void SetBitValue()
+
+HRESULT ParseEncodedType(
+ CustomAttributeParser &ca,
+ CaType* pCaType)
+{
+ CONTRACTL
+ {
+ PRECONDITION(CheckPointer(pCaType));
+ NOTHROW;
+ }
+ CONTRACTL_END;
+
+ HRESULT hr = S_OK;
+
+ CorSerializationType* pType = &pCaType->tag;
+
+ IfFailGo(ca.GetTag(pType));
+
+ if (*pType == SERIALIZATION_TYPE_SZARRAY)
+ {
+ IfFailGo(ca.GetTag(&pCaType->arrayType));
+ pType = &pCaType->arrayType;
+ }
+
+ if (*pType == SERIALIZATION_TYPE_ENUM)
+ {
+ // We cannot determine the underlying type without loading the Enum.
+ pCaType->enumType = SERIALIZATION_TYPE_UNDEFINED;
+ IfFailGo(ca.GetNonNullString(&pCaType->szEnumName, &pCaType->cEnumName));
+ }
+
+ErrExit:
+ return hr;
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Helper to parse the values for the ctor argument list and the named argument list.
+//
+
+HRESULT ParseKnownCaValue(
+ CustomAttributeParser &ca,
+ CaValue* pCaArg,
+ CaType* pCaParam)
+{
+ CONTRACTL
+ {
+ PRECONDITION(CheckPointer(pCaArg));
+ PRECONDITION(CheckPointer(pCaParam));
+ PRECONDITION(pCaParam->tag != SERIALIZATION_TYPE_TAGGED_OBJECT && pCaParam->tag != SERIALIZATION_TYPE_SZARRAY);
+ NOTHROW;
+ }
+ CONTRACTL_END;
+
+ HRESULT hr = S_OK;
+ CorSerializationType underlyingType;
+
+ pCaArg->type = *pCaParam;
+
+ underlyingType = pCaArg->type.tag == SERIALIZATION_TYPE_ENUM ? pCaArg->type.enumType : pCaArg->type.tag;
+
+ // Grab the value.
+ switch (underlyingType)
+ {
+ case SERIALIZATION_TYPE_BOOLEAN:
+ case SERIALIZATION_TYPE_I1:
+ case SERIALIZATION_TYPE_U1:
+ IfFailGo(ca.GetU1(&pCaArg->u1));
+ break;
+
+ case SERIALIZATION_TYPE_CHAR:
+ case SERIALIZATION_TYPE_I2:
+ case SERIALIZATION_TYPE_U2:
+ IfFailGo(ca.GetU2(&pCaArg->u2));
+ break;
+
+ case SERIALIZATION_TYPE_I4:
+ case SERIALIZATION_TYPE_U4:
+ IfFailGo(ca.GetU4(&pCaArg->u4));
+ break;
+
+ case SERIALIZATION_TYPE_I8:
+ case SERIALIZATION_TYPE_U8:
+ IfFailGo(ca.GetU8(&pCaArg->u8));
+ break;
+
+ case SERIALIZATION_TYPE_R4:
+ IfFailGo(ca.GetR4(&pCaArg->r4));
+ break;
+
+ case SERIALIZATION_TYPE_R8:
+ IfFailGo(ca.GetR8(&pCaArg->r8));
+ break;
+
+ case SERIALIZATION_TYPE_STRING:
+ case SERIALIZATION_TYPE_TYPE:
+ IfFailGo(ca.GetString(&pCaArg->str.pStr, &pCaArg->str.cbStr));
+ break;
+
+ default:
+ // The arguments of all known custom attributes are Type, String, Enum, or primitive types.
+ _ASSERTE(!"Unexpected internal error");
+ hr = E_FAIL;
+ break;
+ } // End switch
+
+ErrExit:
+ return hr;
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Helper to parse the nanmed argument list.
+// This function is used by code:RegMeta::DefineCustomAttribute for IMetaDataEmit2 and
+// should not have any VM dependency.
+//
+
+HRESULT ParseKnownCaNamedArgs(
+ CustomAttributeParser &ca, // The Custom Attribute blob.
+ CaNamedArg *pNamedParams, // Array of argument descriptors.
+ ULONG cNamedParams)
+{
+ WRAPPER_NO_CONTRACT;
+
+ HRESULT hr = S_OK;
+ ULONG ixParam;
+ INT32 ixArg;
+ INT16 cActualArgs;
+ CaNamedArgCtor namedArg;
+ CaNamedArg* pNamedParam;
+
+ // Get actual count of named arguments.
+ if (FAILED(ca.GetI2(&cActualArgs)))
+ cActualArgs = 0; // Everett behavior
+
+ for (ixParam = 0; ixParam < cNamedParams; ixParam++)
+ pNamedParams[ixParam].val.type.tag = SERIALIZATION_TYPE_UNDEFINED;
+
+ // For each named argument...
+ for (ixArg = 0; ixArg < cActualArgs; ixArg++)
+ {
+ // Field or property?
+ IfFailGo(ca.GetTag(&namedArg.propertyOrField));
+ if (namedArg.propertyOrField != SERIALIZATION_TYPE_FIELD && namedArg.propertyOrField != SERIALIZATION_TYPE_PROPERTY)
+ IfFailGo(PostError(META_E_CA_INVALID_ARGTYPE));
+
+ // Get argument type information
+ IfFailGo(ParseEncodedType(ca, &namedArg.type));
+
+ // Get name of Arg.
+ if (FAILED(ca.GetNonEmptyString(&namedArg.szName, &namedArg.cName)))
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+
+ // Match arg by name and type
+ for (ixParam = 0; ixParam < cNamedParams; ixParam++)
+ {
+ pNamedParam = &pNamedParams[ixParam];
+
+ // Match type
+ if (pNamedParam->type.tag != SERIALIZATION_TYPE_TAGGED_OBJECT)
+ {
+ if (namedArg.type.tag != pNamedParam->type.tag)
+ continue;
+
+ // Match array type
+ if (namedArg.type.tag == SERIALIZATION_TYPE_SZARRAY &&
+ pNamedParam->type.arrayType != SERIALIZATION_TYPE_TAGGED_OBJECT &&
+ namedArg.type.arrayType != pNamedParam->type.arrayType)
+ continue;
+ }
+
+ // Match name (and its length to avoid substring matching)
+ if ((pNamedParam->cName != namedArg.cName) ||
+ (strncmp(pNamedParam->szName, namedArg.szName, namedArg.cName) != 0))
+ {
+ continue;
+ }
+
+ // If enum, match enum name.
+ if (pNamedParam->type.tag == SERIALIZATION_TYPE_ENUM ||
+ (pNamedParam->type.tag == SERIALIZATION_TYPE_SZARRAY && pNamedParam->type.arrayType == SERIALIZATION_TYPE_ENUM ))
+ {
+ if (pNamedParam->type.cEnumName > namedArg.type.cEnumName)
+ continue; // name cannot possibly match
+
+ if (strncmp(pNamedParam->type.szEnumName, namedArg.type.szEnumName, pNamedParam->type.cEnumName) != 0 ||
+ (pNamedParam->type.cEnumName < namedArg.type.cEnumName &&
+ namedArg.type.szEnumName[pNamedParam->type.cEnumName] != ','))
+ continue;
+
+ // TODO: For now assume the property\field array size is correct - later we should verify this
+ namedArg.type.enumType = pNamedParam->type.enumType;
+ }
+
+ // Found a match.
+ break;
+ }
+
+ // Better have found an argument.
+ if (ixParam == cNamedParams)
+ {
+ MAKE_WIDEPTR_FROMUTF8N(pWideStr, namedArg.szName, namedArg.cName)
+ IfFailGo(PostError(META_E_CA_UNKNOWN_ARGUMENT, wcslen(pWideStr), pWideStr));
+ }
+
+ // Argument had better not have been seen already.
+ if (pNamedParams[ixParam].val.type.tag != SERIALIZATION_TYPE_UNDEFINED)
+ {
+ MAKE_WIDEPTR_FROMUTF8N(pWideStr, namedArg.szName, namedArg.cName)
+ IfFailGo(PostError(META_E_CA_REPEATED_ARG, wcslen(pWideStr), pWideStr));
+ }
+
+ IfFailGo(ParseKnownCaValue(ca, &pNamedParams[ixParam].val, &namedArg.type));
+ }
+
+ErrExit:
+ return hr;
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Helper to parse the ctor argument list.
+// This function is used by code:RegMeta::DefineCustomAttribute for IMetaDataEmit2 and
+// should not have any VM dependency.
+//
+
+HRESULT ParseKnownCaArgs(
+ CustomAttributeParser &ca, // The Custom Attribute blob.
+ CaArg* pArgs, // Array of argument descriptors.
+ ULONG cArgs) // Count of argument descriptors.
+{
+ WRAPPER_NO_CONTRACT;
+
+ HRESULT hr = S_OK; // A result.
+ ULONG ix; // Loop control.
+
+ // If there is a blob, check the prolog.
+ if (FAILED(ca.ValidateProlog()))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+
+ // For each expected arg...
+ for (ix=0; ix<cArgs; ++ix)
+ {
+ CaArg* pArg = &pArgs[ix];
+ IfFailGo(ParseKnownCaValue(ca, &pArg->val, &pArg->type));
+ }
+
+ErrExit:
+ return hr;
+} // ParseKnownCaArgs
+
+//*****************************************************************************
+// Create a CustomAttribute record from a blob with the specified parent.
+//*****************************************************************************
+STDMETHODIMP RegMeta::DefineCustomAttribute(
+ mdToken tkOwner, // [IN] The object to put the value on.
+ mdToken tkCtor, // [IN] Constructor of the CustomAttribute type (MemberRef/MethodDef).
+ void const *pCustomAttribute, // [IN] Custom Attribute data.
+ ULONG cbCustomAttribute, // [IN] Size of custom Attribute data.
+ mdCustomAttribute *pcv) // [OUT, OPTIONAL] Put custom Attribute token here.
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CustomAttributeRec *pRecord = NULL; // New custom Attribute record.
+ RID iRecord; // New custom Attribute RID.
+ CMiniMdRW *pMiniMd = &m_pStgdb->m_MiniMd;
+ int ixKnown; // Index of known custom attribute.
+
+ LOG((LOGMD, "RegMeta::DefineCustomAttribute(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", tkOwner, tkCtor,
+ pCustomAttribute, cbCustomAttribute, pcv));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ _ASSERTE(TypeFromToken(tkCtor) == mdtMethodDef || TypeFromToken(tkCtor) == mdtMemberRef);
+
+ if (TypeFromToken(tkOwner) == mdtCustomAttribute)
+ IfFailGo(E_INVALIDARG);
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ if (IsNilToken(tkOwner) ||
+ IsNilToken(tkCtor) ||
+ (TypeFromToken(tkCtor) != mdtMethodDef &&
+ TypeFromToken(tkCtor) != mdtMemberRef) )
+ {
+ IfFailGo(E_INVALIDARG);
+ }
+
+ // See if this is a known custom attribute.
+ IfFailGo(_IsKnownCustomAttribute(tkCtor, &ixKnown));
+ if (ixKnown != 0)
+ {
+ int bKeep = false;
+ hr = _HandleKnownCustomAttribute(tkOwner, pCustomAttribute, cbCustomAttribute, ixKnown, &bKeep);
+ if (pcv)
+ *pcv = mdCustomAttributeNil;
+ IfFailGo(hr);
+ if (!bKeep)
+ goto ErrExit;
+ }
+
+ if (((TypeFromToken(tkOwner) == mdtTypeDef) || (TypeFromToken(tkOwner) == mdtMethodDef)) &&
+ (TypeFromToken(tkCtor) == mdtMethodDef || TypeFromToken(tkCtor) == mdtMemberRef))
+ {
+ CHAR szBuffer[MAX_CLASS_NAME + 1];
+ LPSTR szName = szBuffer;
+ LPCSTR szNamespace;
+ LPCSTR szClass;
+ TypeRefRec *pTypeRefRec = NULL;
+ TypeDefRec *pTypeDefRec = NULL;
+ mdToken tkParent;
+
+ if (TypeFromToken(tkCtor) == mdtMemberRef)
+ {
+ MemberRefRec *pMemberRefRec;
+ IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(tkCtor), &pMemberRefRec));
+ tkParent = pMiniMd->getClassOfMemberRef(pMemberRefRec);
+ if (TypeFromToken(tkParent) == mdtTypeRef)
+ {
+ IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tkParent), &pTypeRefRec));
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szNamespace));
+ IfFailGo(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szClass));
+ ns::MakePath(szName, sizeof(szBuffer) - 1, szNamespace, szClass);
+ }
+ else if (TypeFromToken(tkParent) == mdtTypeDef)
+ {
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeDefRec));
+ }
+ }
+ else
+ {
+ IfFailGo(pMiniMd->FindParentOfMethodHelper(tkCtor, &tkParent));
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeDefRec));
+ }
+
+ if (pTypeDefRec != NULL)
+ {
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeDefRec, &szNamespace));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeDefRec, &szClass));
+ ns::MakePath(szName, sizeof(szBuffer) - 1, szNamespace, szClass);
+ }
+
+ if ((TypeFromToken(tkOwner) == mdtMethodDef) && strcmp(szName, COR_REQUIRES_SECOBJ_ATTRIBUTE_ANSI) == 0)
+ {
+ // Turn REQ_SO attribute into flag bit on the methoddef.
+ MethodRec *pMethod;
+ IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(tkOwner), &pMethod));
+ pMethod->AddFlags(mdRequireSecObject);
+ IfFailGo(UpdateENCLog(tkOwner));
+ goto ErrExit;
+ }
+ else if (strcmp(szName, COR_SUPPRESS_UNMANAGED_CODE_CHECK_ATTRIBUTE_ANSI) == 0)
+ {
+ // If we spot an unmanged code check suppression attribute, turn on
+ // the bit that says there's declarative security on the
+ // class/method, but still write the attribute itself.
+ if (TypeFromToken(tkOwner) == mdtTypeDef)
+ {
+ IfFailGo(_TurnInternalFlagsOn(tkOwner, tdHasSecurity));
+ }
+ else if (TypeFromToken(tkOwner) == mdtMethodDef)
+ {
+ IfFailGo(_TurnInternalFlagsOn(tkOwner, mdHasSecurity));
+ }
+ IfFailGo(UpdateENCLog(tkOwner));
+ }
+ }
+
+ IfFailGo(m_pStgdb->m_MiniMd.AddCustomAttributeRecord(&pRecord, &iRecord));
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_CustomAttribute, CustomAttributeRec::COL_Type, pRecord, tkCtor));
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_CustomAttribute, CustomAttributeRec::COL_Parent, pRecord, tkOwner));
+
+ IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_CustomAttribute, CustomAttributeRec::COL_Value, pRecord, pCustomAttribute, cbCustomAttribute));
+
+ // Give token back to caller.
+ if (pcv != NULL)
+ *pcv = TokenFromRid(iRecord, mdtCustomAttribute);
+
+ IfFailGo(m_pStgdb->m_MiniMd.AddCustomAttributesToHash(TokenFromRid(iRecord, mdtCustomAttribute)) );
+
+ IfFailGo(UpdateENCLog(TokenFromRid(iRecord, mdtCustomAttribute)));
+
+ErrExit:
+ STOP_MD_PERF(DefineCustomAttribute);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::DefineCustomAttribute
+
+//*****************************************************************************
+// Replace the blob of an existing custom attribute.
+//*****************************************************************************
+STDMETHODIMP RegMeta::SetCustomAttributeValue( // Return code.
+ mdCustomAttribute tkAttr, // [IN] The object to be Attributed.
+ void const *pCustomAttribute, // [IN] Custom Attribute data.
+ ULONG cbCustomAttribute) // [IN] Size of custom Attribute data.
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CustomAttributeRec *pRecord = NULL;// Existing custom Attribute record.
+
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ _ASSERTE(TypeFromToken(tkAttr) == mdtCustomAttribute && !InvalidRid(tkAttr));
+
+ // Retrieve and update the custom value.
+ IfFailGo(m_pStgdb->m_MiniMd.GetCustomAttributeRecord(RidFromToken(tkAttr), &pRecord));
+ IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_CustomAttribute, CustomAttributeRec::COL_Value, pRecord, pCustomAttribute, cbCustomAttribute));
+
+ IfFailGo(UpdateENCLog(tkAttr));
+ErrExit:
+
+ STOP_MD_PERF(SetCustomAttributeValue);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::SetCustomAttributeValue
+
+//*****************************************************************************
+//*****************************************************************************
+HRESULT RegMeta::_IsKnownCustomAttribute( // S_OK, S_FALSE, or error.
+ mdToken tkCtor, // [IN] Token of custom attribute's constructor.
+ int *pca) // [OUT] Put value from KnownCustAttr enum here.
+{
+ HRESULT hr = S_OK; // A result.
+ CCustAttrHashKey sLookup; // For looking up a custom attribute.
+ CCustAttrHashKey *pFound; // Result of a lookup.
+ LPCSTR szNamespace = ""; // Namespace of custom attribute type.
+ LPCSTR szName = ""; // Name of custom attribute type.
+ TypeDefRec *pTypeDefRec = NULL; // Parent record, when a TypeDef.
+ TypeRefRec *pTypeRefRec = NULL; // Parent record, when a TypeRef.
+ CMiniMdRW *pMiniMd = &m_pStgdb->m_MiniMd;
+ int ixCa; // Index of Known CustomAttribute, or 0.
+ int i; // Loop control.
+ mdToken tkParent;
+
+ *pca = 0;
+
+ // Only for Custom Attributes.
+ _ASSERTE(TypeFromToken(tkCtor) != mdtTypeRef && TypeFromToken(tkCtor) != mdtTypeDef);
+
+ sLookup.tkType = tkCtor;
+
+ // See if this custom attribute type has been seen before.
+ if ((pFound = m_caHash.Find(&sLookup)))
+ { // Yes, already seen.
+ *pca = pFound->ca;
+ hr = (pFound->ca == CA_UNKNOWN) ? S_FALSE : S_OK;
+ goto ErrExit;
+ }
+
+ // Hasn't been seen before. See if it is well known.
+
+ // Get the CA name.
+ if (TypeFromToken(tkCtor) == mdtMemberRef)
+ {
+ MemberRefRec *pMember;
+ IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(tkCtor), &pMember));
+ tkParent = pMiniMd->getClassOfMemberRef(pMember);
+ if (TypeFromToken(tkParent) == mdtTypeRef)
+ {
+ IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tkParent), &pTypeRefRec));
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szNamespace));
+ IfFailGo(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szName));
+ }
+ else if (TypeFromToken(tkParent) == mdtTypeDef)
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeDefRec));
+ }
+ else
+ {
+ IfFailGo(pMiniMd->FindParentOfMethodHelper(tkCtor, &tkParent));
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeDefRec));
+ }
+
+ if (pTypeDefRec)
+ {
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeDefRec, &szNamespace));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeDefRec, &szName));
+ }
+
+ // Search in list of Known CAs.
+ for (ixCa=0, i=1; i<CA_COUNT; ++i)
+ {
+ if (strcmp(szName, rKnownCaProps[i]->szName) != 0)
+ continue;
+ if (strcmp(szNamespace, rKnownCaProps[i]->szNamespace) == 0)
+ {
+ // Some custom attributes have overloaded ctors. For those,
+ // see if this is the matching overload.
+ if (rKnownCaProps[i]->bMatchBySig)
+ {
+ // Name matches. Does the signature?
+ PCCOR_SIGNATURE pSig = NULL; // Signature of a method.
+ ULONG cbSig = 0; // Size of the signature.
+ ULONG cParams; // Count of signature parameters.
+ ULONG cb; // Size of an element
+ ULONG elem; // Signature element.
+ ULONG j; // Loop control.
+
+ // Get the signature.
+ if (TypeFromToken(tkCtor) == mdtMemberRef)
+ {
+ MemberRefRec *pMember;
+ IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(tkCtor), &pMember));
+ IfFailGo(pMiniMd->getSignatureOfMemberRef(pMember, &pSig, &cbSig));
+ }
+ else
+ {
+ MethodRec *pMethod;
+ IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(tkCtor), &pMethod));
+ IfFailGo(pMiniMd->getSignatureOfMethod(pMethod, &pSig, &cbSig));
+ }
+
+ // Skip calling convention.
+ cb = CorSigUncompressData(pSig, &elem);
+ pSig += cb;
+ cbSig -= cb;
+ // Count of params.
+ cb = CorSigUncompressData(pSig, &cParams);
+ pSig += cb;
+ cbSig -= cb;
+
+ // If param count mismatch, not the right CA.
+ if (cParams != rKnownCaProps[i]->cArgs)
+ continue;
+
+ // Count is fine, check each param. Skip return type (better be void).
+ cb = CorSigUncompressData(pSig, &elem);
+ _ASSERTE(elem == ELEMENT_TYPE_VOID);
+ pSig += cb;
+ cbSig -= cb;
+ for (j=0; j<cParams; ++j)
+ {
+ // Get next element from method signature.
+ cb = CorSigUncompressData(pSig, &elem);
+ pSig += cb;
+ cbSig -= cb;
+ if (rKnownCaProps[i]->pArgs[j].type.tag != (CorSerializationType) elem)
+ break;
+ }
+
+ // All matched?
+ if (j != cParams)
+ continue;
+ }
+ // All matched.
+ ixCa = i;
+ break;
+ }
+ }
+
+ // Add to hash.
+ sLookup.ca = ixCa;
+ pFound = m_caHash.Add(&sLookup);
+ IfNullGo(pFound);
+ *pFound = sLookup;
+ *pca = ixCa;
+
+ErrExit:
+ return hr;
+} // RegMeta::_IsKnownCustomAttribute
+
+//*****************************************************************************
+//*****************************************************************************
+#ifdef _PREFAST_
+#pragma warning(push)
+#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
+#endif
+HRESULT RegMeta::_HandleKnownCustomAttribute( // S_OK or error.
+ mdToken tkObj, // [IN] Object being attributed.
+ const void *pData, // [IN] Custom Attribute data blob.
+ ULONG cbData, // [IN] Count of bytes in the data.
+ int ixCa, // [IN] Value from KnownCustAttr enum.
+ int *bKeep) // [OUT] If true, keep the CA after processing.
+{
+ HRESULT hr = S_OK; // A result.
+ ULONG ixTbl; // Index of table with object.
+ void *pRow; // Whatever sort of record it is.
+ CMiniMdRW *pMiniMd = &m_pStgdb->m_MiniMd;
+ mdToken tkObjType; // Type of the object.
+ ULONG ix; // Loop control.
+ KnownCaProp const *props=rKnownCaProps[ixCa]; // For convenience.
+ CustomAttributeParser ca(pData, cbData);
+ CQuickArray<CaArg> qArgs; // Un-named arguments.
+ CQuickArray<CaNamedArg> qNamedArgs; // Named arguments.
+ CQuickArray<BYTE> qNativeType;// Native type string.
+
+ _ASSERTE(ixCa > 0 && ixCa < CA_COUNT);
+ *bKeep = props->bKeepCa || m_bKeepKnownCa;
+
+ // Validate that target is valid for attribute.
+ tkObjType = TypeFromToken(tkObj);
+ for (ix=0; props->rTypes[ix] != (mdToken) -1; ++ix)
+ {
+ if (props->rTypes[ix] == tkObjType)
+ break;
+ }
+ // Was the type found in list of valid targets?
+ if (props->rTypes[ix] == (mdToken) -1)
+ { // No, error.
+ IfFailGo(PostError(META_E_CA_INVALID_TARGET));
+ }
+ // Get the row.
+ ixTbl = pMiniMd->GetTblForToken(tkObj);
+ _ASSERTE(ixTbl >= 0 && ixTbl <= pMiniMd->GetCountTables());
+ IfFailGo(pMiniMd->getRow(ixTbl, RidFromToken(tkObj), &pRow));
+
+ // If this custom attribute expects any args...
+ if (props->cArgs || props->cNamedArgs)
+ { // Initialize array ctor arg descriptors.
+ IfFailGo(qArgs.ReSizeNoThrow(props->cArgs));
+ for (ix=0; ix<props->cArgs; ++ix)
+ qArgs[ix] = props->pArgs[ix];
+ // Parse any ctor args (unnamed, fixed args).
+ IfFailGo(ParseKnownCaArgs(ca, qArgs.Ptr(), props->cArgs));
+
+ // If this custom attribute accepts named args, parse them, or if there
+ // are unused bytes, parse them.
+ if (props->cNamedArgs || ca.BytesLeft() > 0)
+ { // Initialize array of named arg descriptors.
+ IfFailGo(qNamedArgs.ReSizeNoThrow(props->cNamedArgs));
+ for (ix=0; ix<props->cNamedArgs; ++ix)
+ qNamedArgs[ix] = props->pNamedArgs[ix];
+ // Parse named args.
+ IfFailGo(ParseKnownCaNamedArgs(ca, qNamedArgs.Ptr(), props->cNamedArgs));
+ }
+ }
+
+ switch (ixCa)
+ {
+ case CA_DllImportAttribute:
+ {
+ // Validate parameters.
+ if (qArgs[0].val.str.cbStr == 0 || qArgs[0].val.str.pStr == NULL)
+ {
+ // no name for DllImport.
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ }
+
+ // Retrieve / create a ModuleRef on the dll name.
+ mdModuleRef mrModule;
+ CQuickArray<char> qDllName;
+ IfFailGo(qDllName.ReSizeNoThrow(qArgs[0].val.str.cbStr+1));
+ memcpy(qDllName.Ptr(), qArgs[0].val.str.pStr, qArgs[0].val.str.cbStr);
+ qDllName[qArgs[0].val.str.cbStr] = '\0';
+ hr = ImportHelper::FindModuleRef(pMiniMd, qDllName.Ptr(), &mrModule);
+ if (hr != S_OK)
+ {
+ MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzDllName, qDllName.Ptr());
+ if (wzDllName == NULL)
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ IfFailGo(_DefineModuleRef(wzDllName, &mrModule));
+ }
+
+ // Create a p/invoke map entry.
+ ULONG dwFlags; dwFlags=0;
+ // Was a calling convention set?
+ if (qNamedArgs[DI_CallingConvention].val.type.tag)
+ { // Calling convention makes no sense on a field.
+ if (TypeFromToken(tkObj) == mdtFieldDef)
+ IfFailGo(PostError(META_E_CA_INVALID_ARG_FOR_TYPE, qNamedArgs[DI_CallingConvention].szName));
+ // Turn off all callconv bits, then turn on specified value.
+ dwFlags &= ~pmCallConvMask;
+ switch (qNamedArgs[DI_CallingConvention].val.u4)
+ { //<TODO>@future: sigh. keep in sync with System.Runtime.InteropServices.CallingConvention</TODO>
+ case 0: break; // 0 means "do nothing"
+ case 1: dwFlags |= pmCallConvWinapi; break;
+ case 2: dwFlags |= pmCallConvCdecl; break;
+ case 3: dwFlags |= pmCallConvStdcall; break;
+ case 4: dwFlags |= pmCallConvThiscall; break;
+ case 5: dwFlags |= pmCallConvFastcall; break;
+ default:
+ _ASSERTE(!"Flags are out of sync! ");
+ break;
+ }
+ }
+ else
+ if (TypeFromToken(tkObj) == mdtMethodDef)
+ { // No calling convention specified for a method. Default to pmCallConvWinApi.
+ dwFlags = (dwFlags & ~pmCallConvMask) | pmCallConvWinapi;
+ }
+
+ // Charset
+ if (qNamedArgs[DI_CharSet].val.type.tag)
+ { // Turn of all charset bits, then turn on specified bits.
+ dwFlags &= ~pmCharSetMask;
+ switch (qNamedArgs[DI_CharSet].val.u4)
+ { //<TODO>@future: keep in sync with System.Runtime.InteropServices.CharSet</TODO>
+ case 0: break; // 0 means "do nothing"
+ case 1: dwFlags |= pmCharSetNotSpec; break;
+ case 2: dwFlags |= pmCharSetAnsi; break;
+ case 3: dwFlags |= pmCharSetUnicode; break;
+ case 4: dwFlags |= pmCharSetAuto; break;
+ default:
+ _ASSERTE(!"Flags are out of sync! ");
+ break;
+ }
+ }
+ if (qNamedArgs[DI_ExactSpelling].val.u1)
+ dwFlags |= pmNoMangle;
+ if (qNamedArgs[DI_SetLastError].val.type.tag)
+ { // SetLastError makes no sense on a field.
+ if (TypeFromToken(tkObj) == mdtFieldDef)
+ IfFailGo(PostError(META_E_CA_INVALID_ARG_FOR_TYPE, qNamedArgs[DI_SetLastError].szName));
+ if (qNamedArgs[DI_SetLastError].val.u1)
+ dwFlags |= pmSupportsLastError;
+ }
+
+ // If an entrypoint name was specified, use it, otherrwise grab the name from the member.
+ LPCWSTR wzEntry;
+ if (qNamedArgs[DI_EntryPoint].val.type.tag)
+ {
+ if (qNamedArgs[DI_EntryPoint].val.str.cbStr > 0)
+ {
+ MAKE_WIDEPTR_FROMUTF8N_NOTHROW(wzEntryName, qNamedArgs[DI_EntryPoint].val.str.pStr, qNamedArgs[DI_EntryPoint].val.str.cbStr);
+ if (wzEntryName == NULL)
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ wzEntry = wzEntryName;
+ }
+ else
+ wzEntry = W("");
+ }
+ else
+ {
+ LPCUTF8 szMember = NULL;
+ if (TypeFromToken(tkObj) == mdtMethodDef)
+ {
+ IfFailGo(pMiniMd->getNameOfMethod(reinterpret_cast<MethodRec*>(pRow), &szMember));
+ }
+ MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzMemberName, szMember);
+ if (wzMemberName == NULL)
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ wzEntry = wzMemberName;
+ }
+
+ // Set the miPreserveSig bit based on the value of the preserve sig flag.
+ if (qNamedArgs[DI_PreserveSig].val.type.tag && !qNamedArgs[DI_PreserveSig].val.u1)
+ reinterpret_cast<MethodRec*>(pRow)->RemoveImplFlags(miPreserveSig);
+ else
+ reinterpret_cast<MethodRec*>(pRow)->AddImplFlags(miPreserveSig);
+
+ if (qNamedArgs[DI_BestFitMapping].val.type.tag)
+ {
+ if (qNamedArgs[DI_BestFitMapping].val.u1)
+ dwFlags |= pmBestFitEnabled;
+ else
+ dwFlags |= pmBestFitDisabled;
+ }
+
+ if (qNamedArgs[DI_ThrowOnUnmappableChar].val.type.tag)
+ {
+ if (qNamedArgs[DI_ThrowOnUnmappableChar].val.u1)
+ dwFlags |= pmThrowOnUnmappableCharEnabled;
+ else
+ dwFlags |= pmThrowOnUnmappableCharDisabled;
+ }
+
+ // Finally, create the PInvokeMap entry.,
+ IfFailGo(_DefinePinvokeMap(tkObj, dwFlags, wzEntry, mrModule));
+ goto ErrExit;
+ }
+ break;
+
+ case CA_GuidAttribute:
+ { // Just verify the attribute. It still gets stored as a real custom attribute.
+ // format is "{01234567-0123-0123-0123-001122334455}"
+ GUID guid;
+ WCHAR wzGuid[40];
+ int cch = qArgs[0].val.str.cbStr;
+
+ // Guid should be 36 characters; need to add curlies.
+ if (cch == 36)
+ {
+ WszMultiByteToWideChar(CP_UTF8, 0, qArgs[0].val.str.pStr,cch, wzGuid+1,39);
+ wzGuid[0] = '{';
+ wzGuid[37] = '}';
+ wzGuid[38] = 0;
+ hr = IIDFromString(wzGuid, &guid);
+ }
+ else
+ hr = META_E_CA_INVALID_UUID;
+ if (hr != S_OK)
+ IfFailGo(PostError(META_E_CA_INVALID_UUID));
+ goto ErrExit;
+ }
+ break;
+
+ case CA_ComImportAttribute:
+ reinterpret_cast<TypeDefRec*>(pRow)->AddFlags(tdImport);
+ break;
+
+ case CA_InterfaceTypeAttribute:
+ {
+ // Verify the attribute.
+ if (qArgs[0].val.u2 >= ifLast)
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ }
+ break;
+
+ case CA_ClassInterfaceAttribute:
+ {
+ // Verify the attribute.
+ if (qArgs[0].val.u2 >= clsIfLast)
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ }
+ break;
+
+ case CA_SpecialNameAttribute:
+
+ switch (TypeFromToken(tkObj))
+ {
+ case mdtTypeDef:
+ reinterpret_cast<TypeDefRec*>(pRow)->AddFlags(tdSpecialName);
+ break;
+
+ case mdtMethodDef:
+ reinterpret_cast<MethodRec*>(pRow)->AddFlags(mdSpecialName);
+ break;
+
+ case mdtFieldDef:
+ reinterpret_cast<FieldRec*>(pRow)->AddFlags(fdSpecialName);
+ break;
+
+ case mdtProperty:
+ reinterpret_cast<PropertyRec*>(pRow)->AddPropFlags(prSpecialName);
+ break;
+
+ case mdtEvent:
+ reinterpret_cast<EventRec*>(pRow)->AddEventFlags(evSpecialName);
+ break;
+
+ default:
+ _ASSERTE(!"Unfamilar type for SpecialName custom attribute");
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ }
+
+ break;
+ case CA_SerializableAttribute:
+ reinterpret_cast<TypeDefRec*>(pRow)->AddFlags(tdSerializable);
+ break;
+
+ case CA_NonSerializedAttribute:
+ reinterpret_cast<FieldRec*>(pRow)->AddFlags(fdNotSerialized);
+ break;
+
+ case CA_InAttribute:
+ reinterpret_cast<ParamRec*>(pRow)->AddFlags(pdIn);
+ break;
+
+ case CA_OutAttribute:
+ reinterpret_cast<ParamRec*>(pRow)->AddFlags(pdOut);
+ break;
+
+ case CA_OptionalAttribute:
+ reinterpret_cast<ParamRec*>(pRow)->AddFlags(pdOptional);
+ break;
+
+ case CA_MethodImplAttribute2:
+ // Force to wider value.
+ qArgs[0].val.u4 = (unsigned)qArgs[0].val.i2;
+ // Fall through to validation.
+ case CA_MethodImplAttribute3:
+ // Validate bits.
+ if (qArgs[0].val.u4 & ~(miUserMask))
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ reinterpret_cast<MethodRec*>(pRow)->AddImplFlags(qArgs[0].val.u4);
+ if (!qNamedArgs[MI_CodeType].val.type.tag)
+ break;
+ // fall through to set the code type.
+ case CA_MethodImplAttribute1:
+ {
+ USHORT usFlags = reinterpret_cast<MethodRec*>(pRow)->GetImplFlags();
+ if (qNamedArgs[MI_CodeType].val.i4 & ~(miCodeTypeMask))
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ // Mask out old value, put in new one.
+ usFlags = (usFlags & ~miCodeTypeMask) | qNamedArgs[MI_CodeType].val.i4;
+ reinterpret_cast<MethodRec*>(pRow)->SetImplFlags(usFlags);
+ }
+ break;
+
+ case CA_MarshalAsAttribute1:
+ // Force the U2 to a wider U4 value explicitly.
+ qArgs[0].val.u4 = qArgs[0].val.u2;
+ // Fall through to handle the CA.
+ case CA_MarshalAsAttribute2:
+ IfFailGo(_HandleNativeTypeCustomAttribute(tkObj, qArgs.Ptr(), qNamedArgs.Ptr(), qNativeType));
+ break;
+
+ case CA_PreserveSigAttribute:
+ reinterpret_cast<MethodRec*>(pRow)->AddImplFlags(miPreserveSig);
+ break;
+
+ case CA_StructLayoutAttribute1:
+ {
+ // Convert the I2 to a U2, then wide to an I4, then fall through.
+ qArgs[0].val.i4 = static_cast<int>(static_cast<USHORT>(qArgs[0].val.i2));
+ }
+ case CA_StructLayoutAttribute2:
+ {
+ // Get a copy of the flags to work with.
+ ULONG dwFlags;
+ dwFlags = reinterpret_cast<TypeDefRec*>(pRow)->GetFlags();
+ // Class layout. Keep in sync with LayoutKind.
+ switch (qArgs[0].val.i4)
+ {
+ case 0: // tdSequentialLayout:
+ dwFlags = (dwFlags & ~tdLayoutMask) | tdSequentialLayout;
+ break;
+ case 2: // tdExplicitLayout:
+ dwFlags = (dwFlags & ~tdLayoutMask) | tdExplicitLayout;
+ break;
+ case 3: // tdAutoLayout:
+ dwFlags = (dwFlags & ~tdLayoutMask) | tdAutoLayout;
+ break;
+ default:
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ break;
+ }
+
+ // Class packing and size.
+ ULONG ulSize, ulPack;
+ ulPack = ulSize = ULONG_MAX;
+ if (qNamedArgs[SL_Pack].val.type.tag)
+ { // Only 1,2,4,8,16,32,64,128 are legal values.
+ ulPack = qNamedArgs[SL_Pack].val.u4;
+ if ((ulPack > 128) ||
+ (ulPack & (ulPack-1)))
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ }
+ if (qNamedArgs[SL_Size].val.type.tag)
+ {
+ if (qNamedArgs[SL_Size].val.u4 > INT_MAX)
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ ulSize = qNamedArgs[SL_Size].val.u4;
+ }
+ if (ulPack!=ULONG_MAX || ulSize!=ULONG_MAX)
+ IfFailGo(_SetClassLayout(tkObj, ulPack, ulSize));
+
+ // Class character set.
+ if (qNamedArgs[SL_CharSet].val.type.tag)
+ {
+ switch (qNamedArgs[SL_CharSet].val.u4)
+ {
+ //case 1: // Not specified.
+ // IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ // break;
+ case 2: // ANSI
+ dwFlags = (dwFlags & ~tdStringFormatMask) | tdAnsiClass;
+ break;
+ case 3: // Unicode
+ dwFlags = (dwFlags & ~tdStringFormatMask) | tdUnicodeClass;
+ break;
+ case 4: // Auto
+ dwFlags = (dwFlags & ~tdStringFormatMask) | tdAutoClass;
+ break;
+ default:
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ break;
+ }
+ }
+
+ // Persist possibly-changed value of flags.
+ reinterpret_cast<TypeDefRec*>(pRow)->SetFlags(dwFlags);
+ }
+ break;
+
+ case CA_FieldOffsetAttribute:
+ if (qArgs[0].val.u4 > INT_MAX)
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ IfFailGo(_SetFieldOffset(tkObj, qArgs[0].val.u4));
+ break;
+
+ case CA_TypeLibVersionAttribute:
+ if ((qArgs[0].val.i4 < 0) || (qArgs[1].val.i4 < 0))
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ break;
+
+ case CA_ComCompatibleVersionAttribute:
+ if ( (qArgs[0].val.i4 < 0) || (qArgs[1].val.i4 < 0) || (qArgs[2].val.i4 < 0) || (qArgs[3].val.i4 < 0) )
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ break;
+
+ case CA_AllowPartiallyTrustedCallersAttribute:
+ break;
+
+ case CA_WindowsRuntimeImportAttribute:
+ reinterpret_cast<TypeDefRec*>(pRow)->AddFlags(tdWindowsRuntime);
+ break;
+
+ default:
+ _ASSERTE(!"Unexpected custom attribute type");
+ // Turn into ordinary custom attribute.
+ *bKeep = true;
+ hr = S_OK;
+ goto ErrExit;
+ break;
+ }
+
+ IfFailGo(UpdateENCLog(tkObj));
+
+ErrExit:
+ return hr;
+} // RegMeta::_HandleKnownCustomAttribute
+#ifdef _PREFAST_
+#pragma warning(pop)
+#endif
+
+//*****************************************************************************
+//*****************************************************************************
+#ifdef _PREFAST_
+#pragma warning(push)
+#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
+#endif
+HRESULT RegMeta::_HandleNativeTypeCustomAttribute(// S_OK or error.
+ mdToken tkObj, // The token this CA is applied on.
+ CaArg *pArgs, // Pointer to args.
+ CaNamedArg *pNamedArgs, // Pointer to named args.
+ CQuickArray<BYTE> &qNativeType) // Native type is built here.
+{
+ HRESULT hr = S_OK; // A result.
+ int cch = 0; // Size of a string argument.
+ ULONG cb; // Count of some character operation.
+ ULONG cbNative; // Size of native type string.
+ ULONG cbMax; // Max size of native type string.
+ BYTE *pbNative; // Pointer into native type buffer.
+ mdToken tkObjType; // The type of the token.
+ mdToken tkSetter; // Token for Property setter.
+ mdToken tkGetter; // Token for property getter.
+ mdParamDef tkParam; // Parameter of getter/setter.
+ ULONG cParams; // Count of params for getter/setter.
+ HCORENUM phEnum = 0; // Enumerator for params.
+ ULONG ulSeq; // Sequence of a param.
+
+ // Retrieve the type of the token.
+ tkObjType = TypeFromToken(tkObj);
+
+ // Compute maximum size of the native type.
+ if (pArgs[0].val.i4 == NATIVE_TYPE_CUSTOMMARSHALER)
+ { // N_T_* + 3 string lengths
+ cbMax = sizeof(ULONG) * 4;
+ // Marshal type - name of the type
+ cbMax += pNamedArgs[M_MarshalType].val.str.cbStr;
+ // Marshal type - type of the custom marshaler
+ cbMax += pNamedArgs[M_MarshalTypeRef].val.str.cbStr;
+ // String cookie.
+ cbMax += pNamedArgs[M_MarshalCookie].val.str.cbStr;
+ }
+ else if (pArgs[0].val.i4 == NATIVE_TYPE_SAFEARRAY)
+ { // N_T_* + safe array sub-type + string length.
+ cbMax = sizeof(ULONG) * 3;
+ // Safe array record sub type.
+ cbMax += pNamedArgs[M_SafeArrayUserDefinedSubType].val.str.cbStr;
+ }
+ else
+ { // N_T_* + sub-type + size + additive + NativeTypeArrayFlags.
+ cbMax = sizeof(ULONG) * 4 + sizeof(UINT16);
+ }
+
+ // IidParameterIndex.
+ cbMax += sizeof(DWORD);
+
+ // Extra space to prevent buffer overrun.
+ cbMax += 8;
+
+ // Size the array.
+ IfFailGo(qNativeType.ReSizeNoThrow(cbMax));
+ pbNative = qNativeType.Ptr();
+ cbNative = 0;
+
+ //<TODO>@FUTURE: check for valid combinations of args.</TODO>
+
+ // Put in the NativeType.
+ cb = CorSigCompressData(pArgs[0].val.i4, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Put in additional information, depending on native type.
+ switch (pArgs[0].val.i4)
+ {
+ case NATIVE_TYPE_INTF:
+ case NATIVE_TYPE_IUNKNOWN:
+ case NATIVE_TYPE_IDISPATCH:
+ // Validate that the IidParameterIndex field is valid if set.
+ if (pNamedArgs[M_IidParameterIndex].val.type.tag)
+ {
+ int iidparam = pNamedArgs[M_IidParameterIndex].val.i4;
+ if (iidparam < 0)
+ IfFailGo(PostError(META_E_CA_NEGATIVE_PARAMINDEX));
+
+ cb = CorSigCompressData(pNamedArgs[M_IidParameterIndex].val.i4, pbNative);
+ if (cb == ((ULONG)(-1)))
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ }
+ break;
+
+
+ case NATIVE_TYPE_FIXEDARRAY:
+ // Validate that only fields valid for NATIVE_TYPE_FIXEDARRAY are set.
+ if (pNamedArgs[M_SafeArraySubType].val.type.tag)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ if (pNamedArgs[M_SizeParamIndex].val.type.tag)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // This native type is only applicable on fields.
+ if (tkObjType != mdtFieldDef)
+ IfFailGo(PostError(META_E_CA_NT_FIELDONLY));
+
+ if (pNamedArgs[M_SizeConst].val.type.tag)
+ {
+ // Make sure the size is not negative.
+ if (pNamedArgs[M_SizeConst].val.i4 < 0)
+ IfFailGo(PostError(META_E_CA_NEGATIVE_CONSTSIZE));
+
+ cb = CorSigCompressData(pNamedArgs[M_SizeConst].val.i4, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_NEGATIVE_CONSTSIZE));
+ }
+
+ }
+ else
+ {
+ cb = CorSigCompressData(1, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Is there a sub type?
+ if (pNamedArgs[M_ArraySubType].val.type.tag)
+ {
+ // Put in the sub type.
+ cb = CorSigCompressData(pNamedArgs[M_ArraySubType].val.i4, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ }
+ break;
+
+ case NATIVE_TYPE_FIXEDSYSSTRING:
+ // Validate that the required fields are set.
+ if (!pNamedArgs[M_SizeConst].val.type.tag)
+ IfFailGo(PostError(META_E_CA_FIXEDSTR_SIZE_REQUIRED));
+
+ // Validate that other array fields are not set.
+ if (pNamedArgs[M_ArraySubType].val.type.tag)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ if (pNamedArgs[M_SizeParamIndex].val.type.tag)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ if (pNamedArgs[M_SafeArraySubType].val.type.tag)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // This native type is only applicable on fields.
+ if (tkObjType != mdtFieldDef)
+ IfFailGo(PostError(META_E_CA_NT_FIELDONLY));
+
+ // Put in the constant value.
+ cb = CorSigCompressData(pNamedArgs[M_SizeConst].val.i4, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ break;
+
+ case NATIVE_TYPE_BYVALSTR:
+ // This native type is only applicable on parameters.
+ if (tkObjType != mdtParamDef)
+ IfFailGo(PostError(META_E_CA_INVALID_TARGET));
+ break;
+
+ case NATIVE_TYPE_SAFEARRAY:
+ // Validate that other array fields are not set.
+ if (pNamedArgs[M_ArraySubType].val.type.tag)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ if (pNamedArgs[M_SizeParamIndex].val.type.tag)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ if (pNamedArgs[M_SizeConst].val.type.tag)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Is there a safe array sub type?
+ if (pNamedArgs[M_SafeArraySubType].val.type.tag)
+ {
+ // Put in the safe array sub type.
+ cb = CorSigCompressData(pNamedArgs[M_SafeArraySubType].val.i4, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // When the SAFEARRAY contains user defined types, the type of the
+ // UDT can be specified in the SafeArrayUserDefinedSubType field.
+ if (pNamedArgs[M_SafeArrayUserDefinedSubType].val.type.tag)
+ {
+ // Validate that this is only set for valid VT's.
+ if (pNamedArgs[M_SafeArraySubType].val.i4 != VT_RECORD &&
+ pNamedArgs[M_SafeArraySubType].val.i4 != VT_DISPATCH &&
+ pNamedArgs[M_SafeArraySubType].val.i4 != VT_UNKNOWN)
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ }
+
+ // Encode the size of the string.
+ cch = pNamedArgs[M_SafeArrayUserDefinedSubType].val.str.cbStr;
+ cb = CorSigCompressData(cch, pbNative);
+ if (cb == ((ULONG)(-1)))
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ cbNative += cb;
+ pbNative += cb;
+
+ // Check that memcpy will fit and then encode the type name itself.
+ if (ovadd_gt(cbNative, cch, cbMax))
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ memcpy(pbNative, pNamedArgs[M_SafeArrayUserDefinedSubType].val.str.pStr, cch);
+ cbNative += cch;
+ pbNative += cch;
+ _ASSERTE(cbNative <= cbMax);
+ }
+ }
+ break;
+
+ case NATIVE_TYPE_ARRAY:
+ // Validate that the array sub type is not set.
+ if (pNamedArgs[M_SafeArraySubType].val.type.tag)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Is there a sub type?
+ if (pNamedArgs[M_ArraySubType].val.type.tag)
+ {
+ // Do some validation on the array sub type.
+ if (pNamedArgs[M_ArraySubType].val.i4 == NATIVE_TYPE_CUSTOMMARSHALER)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Put in the sub type.
+ cb = CorSigCompressData(pNamedArgs[M_ArraySubType].val.i4, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ }
+ else
+ {
+ // Put in the sub type.
+ cb = CorSigCompressData(NATIVE_TYPE_MAX, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ }
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Is there a parameter index?
+ if (pNamedArgs[M_SizeParamIndex].val.type.tag)
+ {
+ // Make sure the parameter index is not negative.
+ if (pNamedArgs[M_SizeParamIndex].val.i4 < 0)
+ IfFailGo(PostError(META_E_CA_NEGATIVE_PARAMINDEX));
+
+ // Yes, put it in.
+ cb = CorSigCompressData(pNamedArgs[M_SizeParamIndex].val.i2, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Is there a const?
+ if (pNamedArgs[M_SizeConst].val.type.tag)
+ {
+ // Make sure the size is not negative.
+ if (pNamedArgs[M_SizeConst].val.i4 < 0)
+ IfFailGo(PostError(META_E_CA_NEGATIVE_CONSTSIZE));
+
+ // Yes, put it in.
+ cb = CorSigCompressData(pNamedArgs[M_SizeConst].val.i4, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Put in the flag indicating the size param index was specified.
+ cb = CorSigCompressData((UINT16)ntaSizeParamIndexSpecified, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ }
+ }
+ else
+ {
+ // Is there a const?
+ if (pNamedArgs[M_SizeConst].val.type.tag)
+ {
+ // Put in a param index of 0.
+ cb = CorSigCompressData(0, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Put in the constant value.
+ cb = CorSigCompressData(pNamedArgs[M_SizeConst].val.i4, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Set the flags field to 0 to indicate the size param index was not specified.
+ cb = CorSigCompressData((UINT16)0, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ }
+ }
+ break;
+
+ case NATIVE_TYPE_CUSTOMMARSHALER:
+ // Validate that the marshaler type field is set.
+ if (!pNamedArgs[M_MarshalType].val.type.tag && !pNamedArgs[M_MarshalTypeRef].val.type.tag)
+ IfFailGo(PostError(META_E_CA_CUSTMARSH_TYPE_REQUIRED));
+
+ // Put in the place holder for the unmanaged typelib guid.
+ cb = CorSigCompressData(0, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Put in the place holder for the unmanaged type name.
+ cb = CorSigCompressData(0, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Put in the marshaler type name.
+ if (pNamedArgs[M_MarshalType].val.type.tag)
+ {
+ cch = pNamedArgs[M_MarshalType].val.str.cbStr;
+ cb = CorSigCompressData(cch, pbNative);
+ if (cb == ((ULONG)(-1)))
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ cbNative += cb;
+ pbNative += cb;
+ // Check that memcpy will fit.
+ if ((cbNative+cch) > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ memcpy(pbNative, pNamedArgs[M_MarshalType].val.str.pStr, cch);
+ cbNative += cch;
+ pbNative += cch;
+ _ASSERTE(cbNative <= cbMax);
+ }
+ else
+ {
+ cch = pNamedArgs[M_MarshalTypeRef].val.str.cbStr;
+ cb = CorSigCompressData(cch, pbNative);
+ if (cb == ((ULONG)(-1)))
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ cbNative += cb;
+ pbNative += cb;
+ // Check that memcpy will fit.
+ if ((cbNative+cch) > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ memcpy(pbNative, pNamedArgs[M_MarshalTypeRef].val.str.pStr, cch);
+ cbNative += cch;
+ pbNative += cch;
+ _ASSERTE(cbNative <= cbMax);
+ }
+
+ // Put in the cookie.
+ cch = pNamedArgs[M_MarshalCookie].val.str.cbStr;
+ cb = CorSigCompressData(cch, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ // Check that memcpy will fit.
+ if ((cbNative+cch) > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ memcpy(pbNative, pNamedArgs[M_MarshalCookie].val.str.pStr, cch);
+ cbNative += cch;
+ pbNative += cch;
+ break;
+ }
+ _ASSERTE(cbNative <= cbMax);
+
+ // Resize to actual size.
+ IfFailGo(qNativeType.ReSizeNoThrow(cbNative));
+
+ // Now apply the native type to actual token. If it is a property token,
+ // apply to the methods.
+ switch (TypeFromToken(tkObj))
+ {
+ case mdtParamDef:
+ case mdtFieldDef:
+ IfFailGo(_SetFieldMarshal(tkObj, (PCCOR_SIGNATURE)qNativeType.Ptr(), (DWORD)qNativeType.Size()));
+ break;
+
+ case mdtProperty:
+ // Get any setter/getter methods.
+ IfFailGo(GetPropertyProps(tkObj, 0,0,0,0,0,0,0,0,0,0, &tkSetter, &tkGetter, 0,0,0));
+ // For getter, put the field marshal on the return value.
+ if (!IsNilToken(tkGetter))
+ {
+ // Search for first param.
+ mdToken tk;
+ tkParam = mdParamDefNil;
+ do {
+ IfFailGo(EnumParams(&phEnum, tkGetter, &tk, 1, &cParams));
+ if (cParams > 0)
+ {
+ IfFailGo(GetParamProps(tk, 0, &ulSeq, 0,0,0,0,0,0,0));
+ if (ulSeq == 0)
+ {
+ tkParam = tk;
+ break;
+ }
+ }
+
+ } while (hr == S_OK);
+ if (!IsNilToken(tkParam))
+ IfFailGo(_SetFieldMarshal(tkParam, (PCCOR_SIGNATURE)qNativeType.Ptr(), (DWORD)qNativeType.Size()));
+ CloseEnum(phEnum);
+ phEnum = 0;
+ }
+ if (!IsNilToken(tkSetter))
+ {
+ // Determine the last param.
+ PCCOR_SIGNATURE pSig;
+ ULONG cbSig;
+ mdToken tk;
+ ULONG iSeq;
+ IfFailGo(GetMethodProps(tkSetter, 0,0,0,0,0, &pSig,&cbSig, 0,0));
+ tkParam = mdParamDefNil;
+ CorSigUncompressData(pSig+1, &iSeq);
+ // Search for last param.
+ if (iSeq != 0)
+ {
+ do {
+ IfFailGo(EnumParams(&phEnum, tkSetter, &tk, 1, &cParams));
+ if (cParams > 0)
+ {
+ IfFailGo(GetParamProps(tk, 0, &ulSeq, 0,0,0,0,0,0,0));
+ if (ulSeq == iSeq)
+ {
+ tkParam = tk;
+ break;
+ }
+ }
+ } while (hr == S_OK);
+ }
+ // If found one that is not return value
+ if (!IsNilToken(tkParam))
+ IfFailGo(_SetFieldMarshal(tkParam, (PCCOR_SIGNATURE)qNativeType.Ptr(), (DWORD)qNativeType.Size()));
+ CloseEnum(phEnum);
+ phEnum = 0;
+ }
+ break;
+
+ default:
+ _ASSERTE(!"Should not have this token type in _HandleNativeTypeCustomAttribute()");
+ break;
+ }
+
+ErrExit:
+ if (phEnum)
+ CloseEnum(phEnum);
+ return hr;
+} // RegMeta::_HandleNativeTypeCustomAttribute
+#ifdef _PREFAST_
+#pragma warning(pop)
+#endif
+
+#endif //FEATURE_METADATA_EMIT
diff --git a/src/md/compiler/custattr_import.cpp b/src/md/compiler/custattr_import.cpp
new file mode 100644
index 0000000000..7710eb3790
--- /dev/null
+++ b/src/md/compiler/custattr_import.cpp
@@ -0,0 +1,282 @@
+// 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.
+//*****************************************************************************
+
+//
+// CustAttr_Import.cpp
+//
+// Implementation for the meta data custom attribute import code (code:IMetaDataImport).
+//
+//*****************************************************************************
+#include "stdafx.h"
+#include "regmeta.h"
+#include "metadata.h"
+#include "corerror.h"
+#include "mdutil.h"
+#include "rwutil.h"
+#include "mdlog.h"
+#include "importhelper.h"
+#include "mdperf.h"
+#include "posterror.h"
+#include "cahlprinternal.h"
+#include "custattr.h"
+#include "corhdr.h"
+#include <metamodelrw.h>
+
+//*****************************************************************************
+// Implementation of hash for custom attribute types.
+//*****************************************************************************
+unsigned int CCustAttrHash::Hash(const CCustAttrHashKey *pData)
+{
+ return static_cast<unsigned int>(pData->tkType);
+} // unsigned long CCustAttrHash::Hash()
+unsigned int CCustAttrHash::Compare(const CCustAttrHashKey *p1, CCustAttrHashKey *p2)
+{
+ if (p1->tkType == p2->tkType)
+ return 0;
+ return 1;
+} // unsigned long CCustAttrHash::Compare()
+CCustAttrHash::ELEMENTSTATUS CCustAttrHash::Status(CCustAttrHashKey *p)
+{
+ if (p->tkType == FREE)
+ return (FREE);
+ if (p->tkType == DELETED)
+ return (DELETED);
+ return (USED);
+} // CCustAttrHash::ELEMENTSTATUS CCustAttrHash::Status()
+void CCustAttrHash::SetStatus(CCustAttrHashKey *p, CCustAttrHash::ELEMENTSTATUS s)
+{
+ p->tkType = s;
+} // void CCustAttrHash::SetStatus()
+void* CCustAttrHash::GetKey(CCustAttrHashKey *p)
+{
+ return &p->tkType;
+} // void* CCustAttrHash::GetKey()
+
+
+//*****************************************************************************
+// Get the value of a CustomAttribute, using only TypeName for lookup.
+//*****************************************************************************
+STDMETHODIMP RegMeta::GetCustomAttributeByName( // S_OK or error.
+ mdToken tkObj, // [IN] Object with Custom Attribute.
+ LPCWSTR wzName, // [IN] Name of desired Custom Attribute.
+ const void **ppData, // [OUT] Put pointer to data here.
+ ULONG *pcbData) // [OUT] Put size of data here.
+{
+ HRESULT hr; // A result.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LPUTF8 szName; // Name in UFT8.
+ int iLen; // A length.
+ CMiniMdRW *pMiniMd = NULL;
+
+ START_MD_PERF();
+ LOCKREAD();
+ pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ iLen = WszWideCharToMultiByte(CP_UTF8,0, wzName,-1, NULL,0, 0,0);
+ szName = (LPUTF8)_alloca(iLen);
+ VERIFY(WszWideCharToMultiByte(CP_UTF8,0, wzName,-1, szName,iLen, 0,0));
+
+ hr = ImportHelper::GetCustomAttributeByName(pMiniMd, tkObj, szName, ppData, pcbData);
+
+ErrExit:
+
+ STOP_MD_PERF(GetCustomAttributeByName);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::GetCustomAttributeByName()
+
+
+//*****************************************************************************
+// Enumerate the CustomAttributes for a given token.
+//*****************************************************************************
+STDMETHODIMP RegMeta::EnumCustomAttributes(
+ HCORENUM *phEnum, // Pointer to the enum.
+ mdToken tk, // Token to scope the enumeration.
+ mdToken tkType, // Type to limit the enumeration.
+ mdCustomAttribute rCustomAttributes[], // Put CustomAttributes here.
+ ULONG cMax, // Max CustomAttributes to put.
+ ULONG *pcCustomAttributes) // Put # tokens returned here.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ ULONG ridStart;
+ ULONG ridEnd;
+ HENUMInternal *pEnum = *ppmdEnum;
+ CustomAttributeRec *pRec;
+ ULONG index;
+
+ LOG((LOGMD, "RegMeta::EnumCustomAttributes(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, tk, tkType, rCustomAttributes, cMax, pcCustomAttributes));
+ START_MD_PERF();
+ LOCKREAD();
+
+ if ( pEnum == 0 )
+ {
+ // instantiating a new ENUM
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ CLookUpHash *pHashTable = pMiniMd->m_pLookUpHashs[TBL_CustomAttribute];
+
+ // Does caller want all custom Values?
+ if (IsNilToken(tk))
+ {
+ IfFailGo( HENUMInternal::CreateSimpleEnum(mdtCustomAttribute, 1, pMiniMd->getCountCustomAttributes()+1, &pEnum) );
+ }
+ else
+ { // Scope by some object.
+ if ( pMiniMd->IsSorted( TBL_CustomAttribute ) )
+ {
+ // Get CustomAttributes for the object.
+ IfFailGo(pMiniMd->getCustomAttributeForToken(tk, &ridEnd, &ridStart));
+
+ if (IsNilToken(tkType))
+ {
+ // Simple enumerator for object's entire list.
+ IfFailGo( HENUMInternal::CreateSimpleEnum( mdtCustomAttribute, ridStart, ridEnd, &pEnum) );
+ }
+ else
+ {
+ // Dynamic enumerator for subsetted list.
+
+ IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtCustomAttribute, &pEnum) );
+
+ for (index = ridStart; index < ridEnd; index ++ )
+ {
+ IfFailGo(pMiniMd->GetCustomAttributeRecord(index, &pRec));
+ if (tkType == pMiniMd->getTypeOfCustomAttribute(pRec))
+ {
+ IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtCustomAttribute) ) );
+ }
+ }
+ }
+ }
+ else
+ {
+
+ if (pHashTable)
+ {
+ // table is not sorted but hash is built
+ // We want to create dynmaic array to hold the dynamic enumerator.
+ TOKENHASHENTRY *p;
+ ULONG iHash;
+ int pos;
+ mdToken tkParentTmp;
+ mdToken tkTypeTmp;
+
+ // Hash the data.
+ iHash = pMiniMd->HashCustomAttribute(tk);
+
+ IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtCustomAttribute, &pEnum) );
+
+ // Go through every entry in the hash chain looking for ours.
+ for (p = pHashTable->FindFirst(iHash, pos);
+ p;
+ p = pHashTable->FindNext(pos))
+ {
+
+ CustomAttributeRec *pCustomAttribute;
+ IfFailGo(pMiniMd->GetCustomAttributeRecord(RidFromToken(p->tok), &pCustomAttribute));
+ tkParentTmp = pMiniMd->getParentOfCustomAttribute(pCustomAttribute);
+ tkTypeTmp = pMiniMd->getTypeOfCustomAttribute(pCustomAttribute);
+ if (tkParentTmp == tk)
+ {
+ if (IsNilToken(tkType) || tkType == tkTypeTmp)
+ {
+ // compare the blob value
+ IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(p->tok, mdtCustomAttribute )) );
+ }
+ }
+ }
+ }
+ else
+ {
+
+ // table is not sorted and hash is not built so we have to create dynmaic array
+ // create the dynamic enumerator and loop through CA table linearly
+ //
+ ridStart = 1;
+ ridEnd = pMiniMd->getCountCustomAttributes() + 1;
+
+ IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtCustomAttribute, &pEnum) );
+
+ for (index = ridStart; index < ridEnd; index ++ )
+ {
+ IfFailGo(pMiniMd->GetCustomAttributeRecord(index, &pRec));
+ if ( tk == pMiniMd->getParentOfCustomAttribute(pRec) &&
+ (tkType == pMiniMd->getTypeOfCustomAttribute(pRec) || IsNilToken(tkType)))
+ {
+ IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtCustomAttribute) ) );
+ }
+ }
+ }
+ }
+ }
+
+ // set the output parameter
+ *ppmdEnum = pEnum;
+ }
+
+ // fill the output token buffer
+ hr = HENUMInternal::EnumWithCount(pEnum, cMax, rCustomAttributes, pcCustomAttributes);
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+
+ STOP_MD_PERF(EnumCustomAttributes);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::EnumCustomAttributes()
+
+
+//*****************************************************************************
+// Get information about a CustomAttribute.
+//*****************************************************************************
+STDMETHODIMP RegMeta::GetCustomAttributeProps(
+ mdCustomAttribute cv, // The attribute token
+ mdToken *ptkObj, // [OUT, OPTIONAL] Put object token here.
+ mdToken *ptkType, // [OUT, OPTIONAL] Put TypeDef/TypeRef token here.
+ void const **ppBlob, // [OUT, OPTIONAL] Put pointer to data here.
+ ULONG *pcbSize) // [OUT, OPTIONAL] Put size of data here.
+{
+ HRESULT hr = S_OK; // A result.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CMiniMdRW *pMiniMd;
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ _ASSERTE(TypeFromToken(cv) == mdtCustomAttribute);
+
+ pMiniMd = &(m_pStgdb->m_MiniMd);
+ CustomAttributeRec *pCustomAttributeRec; // The custom value record.
+
+ IfFailGo(pMiniMd->GetCustomAttributeRecord(RidFromToken(cv), &pCustomAttributeRec));
+
+ if (ptkObj)
+ *ptkObj = pMiniMd->getParentOfCustomAttribute(pCustomAttributeRec);
+
+ if (ptkType)
+ *ptkType = pMiniMd->getTypeOfCustomAttribute(pCustomAttributeRec);
+
+ if (ppBlob != NULL)
+ {
+ IfFailGo(pMiniMd->getValueOfCustomAttribute(pCustomAttributeRec, (const BYTE **)ppBlob, pcbSize));
+ }
+
+ErrExit:
+
+ STOP_MD_PERF(GetCustomAttributeProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::GetCustomAttributeProps
diff --git a/src/md/compiler/dac/.gitmirror b/src/md/compiler/dac/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/md/compiler/dac/.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/compiler/dac/CMakeLists.txt b/src/md/compiler/dac/CMakeLists.txt
new file mode 100644
index 0000000000..dda76e1cd9
--- /dev/null
+++ b/src/md/compiler/dac/CMakeLists.txt
@@ -0,0 +1,6 @@
+
+include(${CLR_DIR}/dac.cmake)
+include(../../md_dac.cmake)
+
+add_precompiled_header(stdafx.h ../stdafx.cpp MDCOMPILER_SOURCES)
+add_library_clr(mdcompiler_dac ${MDCOMPILER_SOURCES})
diff --git a/src/md/compiler/dac/dirs.proj b/src/md/compiler/dac/dirs.proj
new file mode 100644
index 0000000000..cf39ab9ea2
--- /dev/null
+++ b/src/md/compiler/dac/dirs.proj
@@ -0,0 +1,19 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+
+ <PropertyGroup>
+ <BuildInPhase1>true</BuildInPhase1>
+ <BuildInPhaseDefault>false</BuildInPhaseDefault>
+ <BuildCoreBinaries>true</BuildCoreBinaries>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ </PropertyGroup>
+
+ <!--The following projects will build during PHASE 1-->
+ <ItemGroup Condition="'$(BuildExePhase)' == '1'">
+ <ProjectFile Include="HostLocal\mdcompiler_dac.nativeproj" />
+ </ItemGroup>
+
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\tools\Microsoft.DevDiv.Traversal.targets" />
+</Project>
diff --git a/src/md/compiler/dbi/.gitmirror b/src/md/compiler/dbi/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/md/compiler/dbi/.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/compiler/dbi/CMakeLists.txt b/src/md/compiler/dbi/CMakeLists.txt
new file mode 100644
index 0000000000..b870984309
--- /dev/null
+++ b/src/md/compiler/dbi/CMakeLists.txt
@@ -0,0 +1,4 @@
+include(../../md_dbi.cmake)
+
+add_precompiled_header(stdafx.h ../stdafx.cpp MDCOMPILER_SOURCES)
+add_library_clr(mdcompiler-dbi ${MDCOMPILER_SOURCES}) \ No newline at end of file
diff --git a/src/md/compiler/dbi/MDCompiler-dbi.props b/src/md/compiler/dbi/MDCompiler-dbi.props
new file mode 100644
index 0000000000..a9c469c98e
--- /dev/null
+++ b/src/md/compiler/dbi/MDCompiler-dbi.props
@@ -0,0 +1,9 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood">
+ <PropertyGroup>
+ <!-- All features are set in file:..\..\MD.props -->
+ <MetadataFlavor>mscordbi</MetadataFlavor>
+ </PropertyGroup>
+
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\src\MD\Compiler\Compiler.settings.targets" />
+
+</Project>
diff --git a/src/md/compiler/dbi/dirs.proj b/src/md/compiler/dbi/dirs.proj
new file mode 100644
index 0000000000..89a842727c
--- /dev/null
+++ b/src/md/compiler/dbi/dirs.proj
@@ -0,0 +1,19 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+
+ <PropertyGroup>
+ <BuildInPhase1>true</BuildInPhase1>
+ <BuildInPhaseDefault>false</BuildInPhaseDefault>
+ <BuildCoreBinaries>true</BuildCoreBinaries>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ </PropertyGroup>
+
+ <!--The following projects will build during PHASE 1-->
+ <ItemGroup Condition="'$(BuildExePhase)' == '1'">
+ <ProjectFile Condition="'$(FeatureDbiDebugging)'=='true'" Include="HostLocal\mdcompiler-dbi.nativeproj" />
+ </ItemGroup>
+
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\tools\Microsoft.DevDiv.Traversal.targets" />
+</Project>
diff --git a/src/md/compiler/dirs.proj b/src/md/compiler/dirs.proj
new file mode 100644
index 0000000000..2e97d62490
--- /dev/null
+++ b/src/md/compiler/dirs.proj
@@ -0,0 +1,27 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+
+ <PropertyGroup>
+ <BuildInPhase1>true</BuildInPhase1>
+ <BuildInPhaseDefault>false</BuildInPhaseDefault>
+ <BuildCoreBinaries>true</BuildCoreBinaries>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ </PropertyGroup>
+
+ <!--The following projects will build during PHASE 1-->
+ <ItemGroup Condition="'$(BuildExePhase)' == '1'">
+ <ProjectFile Include="wks\mdcompiler_wks.nativeproj" />
+ <ProjectFile Include="dac\dirs.proj" />
+ <ProjectFile Include="dbi\dirs.proj" />
+ </ItemGroup>
+
+ <!--The following projects will build during PHASE 1 of the Desktop build -->
+ <ItemGroup Condition="'$(BuildExePhase)' == '1' and '$(FeatureCoreClr)' != 'true'">
+ <ProjectFile Include="winrt-ro\mdcompiler-winrt-ro.nativeproj" />
+ <ProjectFile Include="winrt-rw\mdcompiler-winrt-rw.nativeproj" />
+ </ItemGroup>
+
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\tools\Microsoft.DevDiv.Traversal.targets" />
+</Project>
diff --git a/src/md/compiler/disp.cpp b/src/md/compiler/disp.cpp
new file mode 100644
index 0000000000..b091729744
--- /dev/null
+++ b/src/md/compiler/disp.cpp
@@ -0,0 +1,939 @@
+// 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.
+//*****************************************************************************
+// Disp.cpp
+//
+
+//
+// Implementation for the meta data dispenser code.
+//
+//*****************************************************************************
+#include "stdafx.h"
+#include "disp.h"
+#include "regmeta.h"
+#include "mdutil.h"
+#include <corerror.h>
+#include <mdlog.h>
+#include <mdcommon.h>
+#ifdef FEATURE_COMINTEROP_TLB_SUPPORT
+#include <imptlb.h>
+#endif
+
+#ifdef EnC_SUPPORTED
+#define ENC_DELTA_HACK
+#endif
+
+//*****************************************************************************
+// Ctor.
+//*****************************************************************************
+Disp::Disp() : m_cRef(0)
+{
+#if defined(LOGGING)
+ // InitializeLogging() calls scattered around the code.
+ // <TODO>@future: make this make some sense.</TODO>
+ InitializeLogging();
+#endif
+
+ m_OptionValue.m_DupCheck = MDDupDefault;
+ m_OptionValue.m_RefToDefCheck = MDRefToDefDefault;
+ m_OptionValue.m_NotifyRemap = MDNotifyDefault;
+ m_OptionValue.m_UpdateMode = MDUpdateFull;
+ m_OptionValue.m_ErrorIfEmitOutOfOrder = MDErrorOutOfOrderDefault;
+ m_OptionValue.m_ThreadSafetyOptions = MDThreadSafetyDefault;
+ m_OptionValue.m_GenerateTCEAdapters = FALSE;
+ m_OptionValue.m_ImportOption = MDImportOptionDefault;
+ m_OptionValue.m_LinkerOption = MDAssembly;
+ m_OptionValue.m_RuntimeVersion = NULL;
+ m_OptionValue.m_MetadataVersion = MDDefaultVersion;
+ m_OptionValue.m_MergeOptions = MergeFlagsNone;
+ m_OptionValue.m_InitialSize = MDInitialSizeDefault;
+ m_OptionValue.m_LocalRefPreservation = MDPreserveLocalRefsNone;
+
+ // Allow Avalon to use the SecurityCriticalAttribute
+ if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_FORCE_ASSEMREF_DUPCHECK))
+ {
+ m_OptionValue.m_DupCheck = (CorCheckDuplicatesFor)(m_OptionValue.m_DupCheck|MDDupAssemblyRef);
+ }
+
+} // Disp::Disp
+
+Disp::~Disp()
+{
+ if (m_OptionValue.m_RuntimeVersion != NULL)
+ delete [] m_OptionValue.m_RuntimeVersion;
+} // Disp::~Disp
+
+//*****************************************************************************
+// Create a brand new scope. This is based on the CLSID that was used to get
+// the dispenser.
+//*****************************************************************************
+__checkReturn
+HRESULT
+Disp::DefineScope(
+ REFCLSID rclsid, // [in] What version to create.
+ DWORD dwCreateFlags, // [in] Flags on the create.
+ REFIID riid, // [in] The interface desired.
+ IUnknown **ppIUnk) // [out] Return interface on success.
+{
+#ifdef FEATURE_METADATA_EMIT
+ HRESULT hr = S_OK;
+ PathString szFileName(PathString::Literal, W("file:"));
+ PathString szFileNameSuffix;
+ DWORD len;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ RegMeta *pMeta = 0;
+ OptionValue optionForNewScope = m_OptionValue;
+
+
+ LOG((LF_METADATA, LL_INFO10, "Disp::DefineScope(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", rclsid, dwCreateFlags, riid, ppIUnk));
+
+ if (dwCreateFlags)
+ IfFailGo(E_INVALIDARG);
+
+ // Figure out what version of the metadata to emit
+ if (rclsid == CLSID_CLR_v1_MetaData)
+ {
+#ifdef FEATURE_METADATA_STANDALONE_WINRT
+ IfFailGo(E_NOTIMPL);
+#else
+ optionForNewScope.m_MetadataVersion = MDVersion1;
+#endif //!FEATURE_METADATA_STANDALONE_WINRT
+ }
+ else if (rclsid == CLSID_CLR_v2_MetaData)
+ {
+ optionForNewScope.m_MetadataVersion = MDVersion2;
+ }
+ else
+ {
+ // If it is a version we don't understand, then we cannot continue.
+ IfFailGo(CLDB_E_FILE_OLDVER);
+ }
+
+#ifdef ENC_DELTA_HACK
+// Testers need this flag for their tests.
+
+ EX_TRY{
+ len = WszGetEnvironmentVariable(W("COMP_ENC_OPENSCOPE"), szFileNameSuffix);
+ szFileName.Append(szFileNameSuffix);
+ }
+ EX_CATCH_HRESULT(hr);
+
+ if (len > 0)
+ {
+ // _ASSERTE(!"ENC override on DefineScope");
+// m_OptionValue.m_UpdateMode = MDUpdateENC;
+// m_OptionValue.m_ErrorIfEmitOutOfOrder = MDErrorOutOfOrderDefault;
+// hr = OpenScope(szFileName, ofWrite, riid, ppIUnk);
+
+ IMetaDataEmit *pMetaEmit;
+ hr = OpenScope(szFileName, ofWrite, IID_IMetaDataEmit, (IUnknown **)&pMetaEmit);
+ DWORD cb;
+ CQuickBytes pbMetadata;
+ hr = pMetaEmit->GetSaveSize(cssAccurate,&cb);
+ _ASSERTE(SUCCEEDED(hr));
+
+ IfFailGo(pbMetadata.ReSizeNoThrow(cb));
+
+ hr = pMetaEmit->SaveToMemory(pbMetadata.Ptr(),cb);
+ _ASSERTE(SUCCEEDED(hr));
+// hr = OpenScopeOnMemory( pbMetadata.Ptr(), cb, ofWrite|MDUpdateENC|MDUpdateDelta, riid, ppIUnk);
+
+
+ VARIANT encOption;
+ V_VT(&encOption) = VT_UI4;
+ V_UI4(&encOption) = MDUpdateENC;
+ SetOption(MetaDataSetENC, &encOption);
+ V_UI4(&encOption) = MDErrorOutOfOrderDefault;
+ SetOption(MetaDataErrorIfEmitOutOfOrder, &encOption);
+ hr = OpenScopeOnMemory( pbMetadata.Ptr(), cb, ofWrite, riid, ppIUnk);
+ _ASSERTE(SUCCEEDED(hr));
+ BOOL fResult = SUCCEEDED(hr);
+ // print out a message so people know what's happening
+ printf("Defining scope for EnC using %S %s\n",
+ static_cast<LPCWSTR>(szFileNameSuffix), fResult ? "succeeded" : "failed");
+
+ goto ErrExit;
+ }
+#endif // ENC_DELTA_HACK
+
+ // Create a new coclass for this guy.
+ pMeta = new (nothrow) RegMeta();
+ IfNullGo(pMeta);
+
+ IfFailGo(pMeta->SetOption(&optionForNewScope));
+
+ // Create the MiniMd-style scope.
+ IfFailGo(pMeta->CreateNewMD());
+
+ // Get the requested interface.
+ IfFailGo(pMeta->QueryInterface(riid, (void **)ppIUnk));
+
+ // Add the new RegMeta to the cache.
+ IfFailGo(pMeta->AddToCache());
+
+ LOG((LOGMD, "{%08x} Created new emit scope\n", pMeta));
+
+ErrExit:
+ if (FAILED(hr))
+ {
+ if (pMeta != NULL)
+ delete pMeta;
+ *ppIUnk = NULL;
+ }
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+#else //!FEATURE_METADATA_EMIT
+ return E_NOTIMPL;
+#endif //!FEATURE_METADATA_EMIT
+} // Disp::DefineScope
+
+
+//*****************************************************************************
+// Deliver scope to caller of OpenScope or OpenScopeOnMemory (this may
+// involve wrapping a WinMD adapter.)
+//*****************************************************************************
+static HRESULT DeliverScope(IMDCommon *pMDCommon, REFIID riid, DWORD dwOpenFlags, IUnknown **ppIUnk)
+{
+ HRESULT hr;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+#if !defined(FEATURE_METADATA_STANDALONE_WINRT) && defined(FEATURE_COMINTEROP)
+ IfFailGo((dwOpenFlags & ofNoTransform) ? S_FALSE : CheckIfWinMDAdapterNeeded(pMDCommon));
+ if (hr == S_OK)
+ {
+ IfFailGo(CreateWinMDImport(pMDCommon, riid, (void**)ppIUnk));
+ }
+ else
+#endif
+ {
+ IfFailGo(pMDCommon->QueryInterface(riid, (void**)ppIUnk));
+ }
+
+ ErrExit:
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+}
+
+//*****************************************************************************
+// Open an existing scope.
+//*****************************************************************************
+HRESULT Disp::OpenScope( // Return code.
+ LPCWSTR szFileName, // [in] The scope to open.
+ DWORD dwOpenFlags, // [in] Open mode flags.
+ REFIID riid, // [in] The interface desired.
+ IUnknown **ppIUnk) // [out] Return interface on success.
+{
+ HRESULT hr;
+ BEGIN_ENTRYPOINT_NOTHROW;
+ LOG((LF_METADATA, LL_INFO10, "Disp::OpenScope(%S, 0x%08x, 0x%08x, 0x%08x)\n", MDSTR(szFileName), dwOpenFlags, riid, ppIUnk));
+
+ IMDCommon *pMDCommon = NULL;
+
+ // Validate that there is some sort of file name.
+ if ((szFileName == NULL) || (szFileName[0] == 0) || (ppIUnk == NULL))
+ IfFailGo(E_INVALIDARG);
+
+ *ppIUnk = NULL;
+ IfFailGo(OpenRawScope(szFileName, dwOpenFlags, IID_IMDCommon, (IUnknown**)&pMDCommon));
+ IfFailGo(DeliverScope(pMDCommon, riid, dwOpenFlags, ppIUnk));
+ ErrExit:
+ if (pMDCommon)
+ pMDCommon->Release();
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+}
+
+
+//*****************************************************************************
+// Open a raw view of existing scope.
+//*****************************************************************************
+__checkReturn
+HRESULT
+Disp::OpenRawScope(
+ LPCWSTR szFileName, // [in] The scope to open.
+ DWORD dwOpenFlags, // [in] Open mode flags.
+ REFIID riid, // [in] The interface desired.
+ IUnknown **ppIUnk) // [out] Return interface on success.
+{
+ HRESULT hr;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ _ASSERTE(szFileName != NULL);
+ _ASSERTE(ppIUnk != NULL);
+ RegMeta *pMeta = NULL;
+
+#ifdef FEATURE_METADATA_LOAD_TRUSTED_IMAGES
+ // Don't assert for code:ofTrustedImage (reserved) flag if the feature is supported
+ _ASSERTE(!IsOfReserved(dwOpenFlags & ~ofTrustedImage));
+#else
+ _ASSERTE(!IsOfReserved(dwOpenFlags));
+#endif //!FEATURE_METADATA_LOAD_TRUSTED_IMAGES
+
+ {
+ }
+
+ if (IsOfReadOnly(dwOpenFlags) && IsOfReadWrite(dwOpenFlags))
+ { // Invalid combination of flags - ofReadOnly & ofWrite
+ IfFailGo(E_INVALIDARG);
+ }
+ // If open-for-read, and there is already an open-for-read copy, return it.
+ if (IsOfReadOnly(dwOpenFlags))
+ {
+ RegMeta::FindCachedReadOnlyEntry(szFileName, dwOpenFlags, &pMeta);
+ if (pMeta != NULL)
+ {
+ // Return the requested interface.
+ hr = pMeta->QueryInterface(riid, (void **) ppIUnk);
+ if (FAILED(hr))
+ {
+ pMeta = NULL; // Don't delete cached RegMeta!
+ }
+ else
+ {
+ pMeta->Release(); // Give back refcount from QI
+ LOG((LOGMD, "{%08x} Found in cache '%S'\n", pMeta, MDSTR(szFileName)));
+ }
+
+ goto ErrExit;
+ }
+ }
+ // Create a new coclass for this guy.
+ pMeta = new (nothrow) RegMeta();
+ IfNullGo(pMeta);
+
+ IfFailGo(pMeta->SetOption(&m_OptionValue));
+
+ // Always initialize the RegMeta's stgdb.
+ // <TODO>@FUTURE: there are some cleanup for the open code!!</TODO>
+ if (memcmp(szFileName, W("file:"), 10) == 0)
+ {
+ szFileName = &szFileName[5];
+ }
+
+ // Try to open the MiniMd-style scope.
+ IfFailGo(pMeta->OpenExistingMD(szFileName, 0 /* pbData */,0 /* cbData */, dwOpenFlags));
+
+ // Obtain the requested interface.
+ IfFailGo(pMeta->QueryInterface(riid, (void **)ppIUnk) );
+
+ // Add the new RegMeta to the cache. If this is read-only, any future opens will
+ // find this entry. If, due to another thread concurrently opening the same file,
+ // there is already another copy in the cache, well, then there will be two
+ // read-only copies in the cache. This is considered to be somewhat of a corner
+ // case, and the only harm is temporary memory usage. All requests will be
+ // satisfied by one or the other (depending on search algorithm), and eventually,
+ // the "other" copy will be released.
+ IfFailGo(pMeta->AddToCache());
+
+ LOG((LOGMD, "{%08x} Successfully opened '%S'\n", pMeta, MDSTR(szFileName)));
+
+#if defined(_DEBUG)
+ if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_RegMetaDump))
+ {
+ int DumpMD_impl(RegMeta *pMD);
+ DumpMD_impl(pMeta);
+ }
+#endif // _DEBUG
+
+
+ErrExit:
+ if (FAILED(hr))
+ {
+ if (pMeta != NULL)
+ delete pMeta;
+ *ppIUnk = NULL;
+ }
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // Disp::OpenScope
+
+
+//*****************************************************************************
+// Open an existing scope.
+//*****************************************************************************
+HRESULT Disp::OpenScopeOnMemory( // Return code.
+ LPCVOID pData, // [in] Location of scope data.
+ ULONG cbData, // [in] Size of the data pointed to by pData.
+ DWORD dwOpenFlags, // [in] Open mode flags.
+ REFIID riid, // [in] The interface desired.
+ IUnknown **ppIUnk) // [out] Return interface on success.
+{
+ HRESULT hr;
+ BEGIN_ENTRYPOINT_NOTHROW;
+ LOG((LF_METADATA, LL_INFO10, "Disp::OpenScopeOnMemory(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", pData, cbData, dwOpenFlags, riid, ppIUnk));
+
+ IMDCommon *pMDCommon = NULL;
+
+ _ASSERTE(!IsOfReserved(dwOpenFlags));
+ if (ppIUnk == NULL)
+ IfFailGo(E_INVALIDARG);
+ *ppIUnk = NULL;
+ IfFailGo(OpenRawScopeOnMemory(pData, cbData, dwOpenFlags, IID_IMDCommon, (IUnknown**)&pMDCommon));
+ IfFailGo(DeliverScope(pMDCommon, riid, dwOpenFlags, ppIUnk));
+ ErrExit:
+ if (pMDCommon)
+ pMDCommon->Release();
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+}
+
+//*****************************************************************************
+// Open a raw voew of existing scope.
+//*****************************************************************************
+HRESULT Disp::OpenRawScopeOnMemory( // Return code.
+ LPCVOID pData, // [in] Location of scope data.
+ ULONG cbData, // [in] Size of the data pointed to by pData.
+ DWORD dwOpenFlags, // [in] Open mode flags.
+ REFIID riid, // [in] The interface desired.
+ IUnknown **ppIUnk) // [out] Return interface on success.
+{
+ HRESULT hr;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ RegMeta *pMeta = 0;
+
+ _ASSERTE(!IsOfReserved(dwOpenFlags));
+
+ // Create a new coclass for this guy.
+ pMeta = new (nothrow) RegMeta();
+ IfNullGo(pMeta);
+ IfFailGo(pMeta->SetOption(&m_OptionValue));
+
+
+ PREFIX_ASSUME(pMeta != NULL);
+ // Always initialize the RegMeta's stgdb.
+ IfFailGo(pMeta->OpenExistingMD(0 /* szFileName */, const_cast<void*>(pData), cbData, dwOpenFlags));
+
+ LOG((LOGMD, "{%08x} Opened new scope on memory, pData: %08x cbData: %08x\n", pMeta, pData, cbData));
+
+ // Return the requested interface.
+ IfFailGo( pMeta->QueryInterface(riid, (void **) ppIUnk) );
+
+ // Add the new RegMeta to the cache.
+ IfFailGo(pMeta->AddToCache());
+
+#if defined(_DEBUG)
+ if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_RegMetaDump))
+ {
+ int DumpMD_impl(RegMeta *pMD);
+ DumpMD_impl(pMeta);
+ }
+#endif // _DEBUG
+
+ErrExit:
+ if (FAILED(hr))
+ {
+ if (pMeta) delete pMeta;
+ *ppIUnk = 0;
+ }
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // Disp::OpenScopeOnMemory
+
+#if defined(FEATURE_METADATA_IN_VM) && !defined(FEATURE_CORECLR) && !defined(CROSSGEN_COMPILE)
+
+#include <metahost.h>
+// Pointer to the activated CLR interface provided by the shim.
+extern ICLRRuntimeInfo * g_pCLRRuntime;
+
+#endif
+
+//*****************************************************************************
+// Get the directory where the CLR system resides.
+//
+// Implements public API code:IMetaDataDispenserEx::GetCORSystemDirectory.
+//*****************************************************************************
+HRESULT
+Disp::GetCORSystemDirectory(
+ __out_ecount (cchBuffer) LPWSTR szBuffer, // [out] Buffer for the directory name
+ DWORD cchBuffer, // [in] Size of the buffer
+ DWORD *pcchBuffer) // [out] Number of characters returned
+{
+#if defined(FEATURE_METADATA_IN_VM) && !defined(FEATURE_CORECLR) && !defined(CROSSGEN_COMPILE)
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ // This implies a machine-wide CLR install root, which may not exist for some CLR
+ // skus using standalone metadata.
+ *pcchBuffer = cchBuffer;
+ hr = g_pCLRRuntime->GetRuntimeDirectory(szBuffer, pcchBuffer);
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+#else //!FEATURE_METADATA_IN_VM || FEATURE_CORECLR
+
+#ifdef FEATURE_CORECLR
+ UNREACHABLE_MSG("Calling IMetaDataDispenser::GetCORSystemDirectory! This code should not be "
+ "reachable or needs to be reimplemented for CoreCLR!");
+#endif //FEATURE_CORECLR
+
+ return E_NOTIMPL;
+#endif //!FEATURE_METADATA_IN_VM || FEATURE_CORECLR
+} // Disp::GetCORSystemDirectory
+
+HRESULT Disp::FindAssembly( // S_OK or error
+ LPCWSTR szAppBase, // [IN] optional - can be NULL
+ LPCWSTR szPrivateBin, // [IN] optional - can be NULL
+ LPCWSTR szGlobalBin, // [IN] optional - can be NULL
+ LPCWSTR szAssemblyName, // [IN] required - this is the assembly you are requesting
+ LPCWSTR szName, // [OUT] buffer - to hold name
+ ULONG cchName, // [IN] the name buffer's size
+ ULONG *pcName) // [OUT] the number of characters returend in the buffer
+{
+ BEGIN_ENTRYPOINT_NOTHROW;
+ END_ENTRYPOINT_NOTHROW;
+
+ return E_NOTIMPL;
+} // Disp::FindAssembly
+
+HRESULT Disp::FindAssemblyModule( // S_OK or error
+ LPCWSTR szAppBase, // [IN] optional - can be NULL
+ LPCWSTR szPrivateBin, // [IN] optional - can be NULL
+ LPCWSTR szGlobalBin, // [IN] optional - can be NULL
+ LPCWSTR szAssemblyName, // [IN] The assembly name or code base of the assembly
+ LPCWSTR szModuleName, // [IN] required - the name of the module
+ __out_ecount (cchName) LPWSTR szName, // [OUT] buffer - to hold name
+ ULONG cchName, // [IN] the name buffer's size
+ ULONG *pcName) // [OUT] the number of characters returend in the buffer
+{
+ BEGIN_ENTRYPOINT_NOTHROW;
+ END_ENTRYPOINT_NOTHROW;
+
+ return E_NOTIMPL;
+} // Disp::FindAssemblyModule
+
+//*****************************************************************************
+// Open a scope on an ITypeInfo
+//*****************************************************************************
+HRESULT Disp::OpenScopeOnITypeInfo( // Return code.
+ ITypeInfo *pITI, // [in] ITypeInfo to open.
+ DWORD dwOpenFlags, // [in] Open mode flags.
+ REFIID riid, // [in] The interface desired.
+ IUnknown **ppIUnk) // [out] Return interface on success.
+{
+ BEGIN_ENTRYPOINT_NOTHROW;
+ END_ENTRYPOINT_NOTHROW;
+
+ return E_NOTIMPL;
+} // Disp::OpenScopeOnITypeInfo
+
+#ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE
+
+//*****************************************************************************
+// IMetaDataDispenserCustom
+//*****************************************************************************
+
+HRESULT Disp::OpenScopeOnCustomDataSource( // S_OK or error
+ IMDCustomDataSource *pCustomSource, // [in] The scope to open.
+ DWORD dwOpenFlags, // [in] Open mode flags.
+ REFIID riid, // [in] The interface desired.
+ IUnknown **ppIUnk) // [out] Return interface on success.
+{
+ HRESULT hr;
+ BEGIN_ENTRYPOINT_NOTHROW;
+ LOG((LF_METADATA, LL_INFO10, "Disp::OpenScopeOnCustomDataSource(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", pCustomSource, dwOpenFlags, riid, ppIUnk));
+
+ IMDCommon *pMDCommon = NULL;
+
+ _ASSERTE(!IsOfReserved(dwOpenFlags));
+ if (ppIUnk == NULL)
+ IfFailGo(E_INVALIDARG);
+ *ppIUnk = NULL;
+ IfFailGo(OpenRawScopeOnCustomDataSource(pCustomSource, dwOpenFlags, IID_IMDCommon, (IUnknown**)&pMDCommon));
+ IfFailGo(DeliverScope(pMDCommon, riid, dwOpenFlags, ppIUnk));
+ErrExit:
+ if (pMDCommon)
+ pMDCommon->Release();
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+}
+
+
+//*****************************************************************************
+// Open a raw view of existing scope.
+//*****************************************************************************
+HRESULT Disp::OpenRawScopeOnCustomDataSource( // Return code.
+ IMDCustomDataSource* pDataSource, // [in] scope data.
+ DWORD dwOpenFlags, // [in] Open mode flags.
+ REFIID riid, // [in] The interface desired.
+ IUnknown **ppIUnk) // [out] Return interface on success.
+{
+ HRESULT hr;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ RegMeta *pMeta = 0;
+
+ _ASSERTE(!IsOfReserved(dwOpenFlags));
+
+ // Create a new coclass for this guy.
+ pMeta = new (nothrow)RegMeta();
+ IfNullGo(pMeta);
+ IfFailGo(pMeta->SetOption(&m_OptionValue));
+
+
+ PREFIX_ASSUME(pMeta != NULL);
+ // Always initialize the RegMeta's stgdb.
+ // TODO
+ IfFailGo(pMeta->OpenExistingMD(pDataSource, dwOpenFlags));
+
+ LOG((LOGMD, "{%08x} Opened new scope on custom data source, pDataSource: %08x\n", pMeta, pDataSource));
+
+ // Return the requested interface.
+ IfFailGo(pMeta->QueryInterface(riid, (void **)ppIUnk));
+
+ // Add the new RegMeta to the cache.
+ IfFailGo(pMeta->AddToCache());
+
+#if defined(_DEBUG)
+ if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_RegMetaDump))
+ {
+ int DumpMD_impl(RegMeta *pMD);
+ DumpMD_impl(pMeta);
+ }
+#endif // _DEBUG
+
+ErrExit:
+ if (FAILED(hr))
+ {
+ if (pMeta) delete pMeta;
+ *ppIUnk = 0;
+ }
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // Disp::OpenRawScopeOnCustomDataSource
+
+#endif
+
+//*****************************************************************************
+// IUnknown
+//*****************************************************************************
+
+ULONG Disp::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+} // Disp::AddRef
+
+ULONG Disp::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (cRef == 0)
+ delete this;
+ return cRef;
+} // Disp::Release
+
+HRESULT Disp::QueryInterface(REFIID riid, void **ppUnk)
+{
+ *ppUnk = 0;
+
+ if (riid == IID_IUnknown)
+ *ppUnk = (IUnknown *) (IMetaDataDispenser *) this;
+ else if (riid == IID_IMetaDataDispenser)
+ *ppUnk = (IMetaDataDispenser *) this;
+ else if (riid == IID_IMetaDataDispenserEx)
+ *ppUnk = (IMetaDataDispenserEx *) this;
+#ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE
+ else if (riid == IID_IMetaDataDispenserCustom)
+ *ppUnk = static_cast<IMetaDataDispenserCustom*>(this);
+#endif
+ else
+ return E_NOINTERFACE;
+ AddRef();
+ return S_OK;
+} // Disp::QueryInterface
+
+
+//*****************************************************************************
+// Called by the class factory template to create a new instance of this object.
+//*****************************************************************************
+HRESULT Disp::CreateObject(REFIID riid, void **ppUnk)
+{
+ HRESULT hr;
+ Disp *pDisp = new (nothrow) Disp();
+
+ if (pDisp == 0)
+ return (E_OUTOFMEMORY);
+
+ hr = pDisp->QueryInterface(riid, ppUnk);
+ if (FAILED(hr))
+ delete pDisp;
+ return hr;
+} // Disp::CreateObject
+
+//*****************************************************************************
+// This routine provides the user a way to set certain properties on the
+// Dispenser.
+//
+// Implements public API code:IMetaDataDispenserEx::SetOption.
+//*****************************************************************************
+__checkReturn
+HRESULT
+Disp::SetOption(
+ REFGUID optionid, // [in] GUID for the option to be set.
+ const VARIANT *pvalue) // [in] Value to which the option is to be set.
+{
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LF_METADATA, LL_INFO10, "Disp::SetOption(0x%08x, 0x%08x)\n", optionid, pvalue));
+
+ if (optionid == MetaDataCheckDuplicatesFor)
+ {
+ if (V_VT(pvalue) != VT_UI4)
+ {
+ _ASSERTE(!"Invalid Variant Type value!");
+ IfFailGo(E_INVALIDARG);
+ }
+ m_OptionValue.m_DupCheck = (CorCheckDuplicatesFor) V_UI4(pvalue);
+ }
+ else if (optionid == MetaDataRefToDefCheck)
+ {
+ if (V_VT(pvalue) != VT_UI4)
+ {
+ _ASSERTE(!"Invalid Variant Type value!");
+ IfFailGo(E_INVALIDARG);
+ }
+ m_OptionValue.m_RefToDefCheck = (CorRefToDefCheck) V_UI4(pvalue);
+ }
+ else if (optionid == MetaDataErrorIfEmitOutOfOrder)
+ {
+ if (V_VT(pvalue) != VT_UI4)
+ {
+ _ASSERTE(!"Invalid Variant Type value!");
+ IfFailGo(E_INVALIDARG);
+ }
+ m_OptionValue.m_ErrorIfEmitOutOfOrder = (CorErrorIfEmitOutOfOrder) V_UI4(pvalue);
+ }
+ else if (optionid == MetaDataThreadSafetyOptions)
+ {
+ if (V_VT(pvalue) != VT_UI4)
+ {
+ _ASSERTE(!"Invalid Variant Type value!");
+ IfFailGo(E_INVALIDARG);
+ }
+ m_OptionValue.m_ThreadSafetyOptions = (CorThreadSafetyOptions) V_UI4(pvalue);
+ }
+// Note: mscordbi had all these options accessible in 3.5/4.0 RTM, let's keep it this way for AppCompat.
+#if defined(FEATURE_METADATA_EMIT_ALL) || defined(FEATURE_METADATA_EMIT_IN_DEBUGGER)
+ else if (optionid == MetaDataNotificationForTokenMovement)
+ { // Note: This is not used in CLR sources anymore, but we store the value and return it back in
+ // IMetaDataDispenserEx::GetOption (code:RegMeta::GetOption), so we keep it here for backward-compat.
+ if (V_VT(pvalue) != VT_UI4)
+ {
+ _ASSERTE(!"Invalid Variant Type value!");
+ IfFailGo(E_INVALIDARG);
+ }
+ m_OptionValue.m_NotifyRemap = (CorNotificationForTokenMovement)V_UI4(pvalue);
+ }
+ else if (optionid == MetaDataSetENC)
+ { // EnC update mode (also aliased as code:MetaDataSetUpdate)
+ if (V_VT(pvalue) != VT_UI4)
+ {
+ _ASSERTE(!"Invalid Variant Type value!");
+ IfFailGo(E_INVALIDARG);
+ }
+ m_OptionValue.m_UpdateMode = V_UI4(pvalue);
+ }
+ else if (optionid == MetaDataImportOption)
+ { // Allows enumeration of EnC deleted items by Import API
+ if (V_VT(pvalue) != VT_UI4)
+ {
+ _ASSERTE(!"Invalid Variant Type value!");
+ IfFailGo(E_INVALIDARG);
+ }
+ m_OptionValue.m_ImportOption = (CorImportOptions) V_UI4(pvalue);
+ }
+ else if (optionid == MetaDataLinkerOptions)
+ { // Used only by code:RegMeta::UnmarkAll (code:IMetaDataFilter::UnmarkAll)
+ if (V_VT(pvalue) != VT_UI4)
+ {
+ _ASSERTE(!"Invalid Variant Type value!");
+ IfFailGo(E_INVALIDARG);
+ }
+ m_OptionValue.m_LinkerOption = (CorLinkerOptions) V_UI4(pvalue);
+ }
+ else if (optionid == MetaDataMergerOptions)
+ {
+ if (V_VT(pvalue) != VT_UI4)
+ {
+ _ASSERTE(!"Invalid Variant Type value!");
+ IfFailGo(E_INVALIDARG);
+ }
+ m_OptionValue.m_MergeOptions = (MergeFlags) V_UI4(pvalue);
+ }
+ else if (optionid == MetaDataGenerateTCEAdapters)
+ { // Note: This is not used in CLR sources anymore, but we store the value and return it back in
+ // IMetaDataDispenserEx::GetOption (code:RegMeta::GetOption), so we keep it for backward-compat.
+ if (V_VT(pvalue) != VT_BOOL)
+ {
+ _ASSERTE(!"Invalid Variant Type value!");
+ IfFailGo(E_INVALIDARG);
+ }
+ m_OptionValue.m_GenerateTCEAdapters = V_BOOL(pvalue);
+ }
+ else if (optionid == MetaDataTypeLibImportNamespace)
+ { // Note: This is not used in CLR sources anymore, keep it here for backward-compat
+ if (V_VT(pvalue) != VT_BSTR && V_VT(pvalue) != VT_EMPTY && V_VT(pvalue) != VT_NULL)
+ {
+ _ASSERTE(!"Invalid Variant Type value for namespace.");
+ IfFailGo(E_INVALIDARG);
+ }
+ }
+#endif //FEATURE_METADATA_EMIT_ALL || FEATURE_METADATA_EMIT_IN_DEBUGGER
+ else if (optionid == MetaDataRuntimeVersion)
+ {
+ if (V_VT(pvalue) != VT_BSTR && V_VT(pvalue) != VT_EMPTY && V_VT(pvalue) != VT_NULL)
+ {
+ _ASSERTE(!"Invalid Variant Type value for version.");
+ IfFailGo(E_INVALIDARG);
+ }
+ if (m_OptionValue.m_RuntimeVersion)
+ delete [] m_OptionValue.m_RuntimeVersion;
+
+ if ((V_VT(pvalue) == VT_EMPTY) || (V_VT(pvalue) == VT_NULL) || (*V_BSTR(pvalue) == 0))
+ {
+ m_OptionValue.m_RuntimeVersion = NULL;
+ }
+ else
+ {
+ INT32 len = WszWideCharToMultiByte(CP_UTF8, 0, V_BSTR(pvalue), -1, NULL, 0, NULL, NULL);
+ m_OptionValue.m_RuntimeVersion = new (nothrow) char[len];
+ if (m_OptionValue.m_RuntimeVersion == NULL)
+ IfFailGo(E_INVALIDARG);
+ WszWideCharToMultiByte(CP_UTF8, 0, V_BSTR(pvalue), -1, m_OptionValue.m_RuntimeVersion, len, NULL, NULL);
+ }
+ }
+ else if (optionid == MetaDataInitialSize)
+ {
+ if (V_VT(pvalue) != VT_UI4)
+ {
+ _ASSERTE(!"Invalid Variant Type value!");
+ IfFailGo(E_INVALIDARG);
+ }
+ m_OptionValue.m_InitialSize = V_UI4(pvalue);
+ }
+ else if (optionid == MetaDataPreserveLocalRefs)
+ {
+ if (V_VT(pvalue) != VT_UI4)
+ {
+ _ASSERTE(!"Invalid Variant Type value!");
+ IfFailGo(E_INVALIDARG);
+ }
+
+ m_OptionValue.m_LocalRefPreservation = (CorLocalRefPreservation) V_UI4(pvalue);
+ }
+ else
+ {
+ _ASSERTE(!"Invalid GUID");
+ IfFailGo(E_INVALIDARG);
+ }
+
+ErrExit:
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // Disp::SetOption
+
+//*****************************************************************************
+// This routine provides the user a way to set certain properties on the
+// Dispenser.
+//
+// Implements public API code:IMetaDataDispenserEx::GetOption.
+//*****************************************************************************
+HRESULT Disp::GetOption( // Return code.
+ REFGUID optionid, // [in] GUID for the option to be set.
+ VARIANT *pvalue) // [out] Value to which the option is currently set.
+{
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LF_METADATA, LL_INFO10, "Disp::GetOption(0x%08x, 0x%08x)\n", optionid, pvalue));
+
+ _ASSERTE(pvalue);
+ if (optionid == MetaDataCheckDuplicatesFor)
+ {
+ V_VT(pvalue) = VT_UI4;
+ V_UI4(pvalue) = m_OptionValue.m_DupCheck;
+ }
+ else if (optionid == MetaDataRefToDefCheck)
+ {
+ V_VT(pvalue) = VT_UI4;
+ V_UI4(pvalue) = m_OptionValue.m_RefToDefCheck;
+ }
+ else if (optionid == MetaDataErrorIfEmitOutOfOrder)
+ {
+ V_VT(pvalue) = VT_UI4;
+ V_UI4(pvalue) = m_OptionValue.m_ErrorIfEmitOutOfOrder;
+ }
+// Note: mscordbi had all these options accessible in 3.5/4.0 RTM, let's keep it this way for AppCompat.
+#if defined(FEATURE_METADATA_EMIT_ALL) || defined(FEATURE_METADATA_EMIT_IN_DEBUGGER)
+ else if (optionid == MetaDataNotificationForTokenMovement)
+ { // Note: This is not used in CLR sources anymore, but we store the value and return it here,
+ // so we keep it for backward-compat.
+ V_VT(pvalue) = VT_UI4;
+ V_UI4(pvalue) = m_OptionValue.m_NotifyRemap;
+ }
+ else if (optionid == MetaDataSetENC)
+ { // EnC update mode (also aliased as code:MetaDataSetUpdate)
+ V_VT(pvalue) = VT_UI4;
+ V_UI4(pvalue) = m_OptionValue.m_UpdateMode;
+ }
+ else if (optionid == MetaDataLinkerOptions)
+ { // Allows enumeration of EnC deleted items by Import API
+ V_VT(pvalue) = VT_BOOL;
+ V_UI4(pvalue) = m_OptionValue.m_LinkerOption;
+ }
+ else if (optionid == MetaDataGenerateTCEAdapters)
+ { // Note: This is not used in CLR sources anymore, but we store the value and return it here,
+ // so we keep it for backward-compat.
+ V_VT(pvalue) = VT_BOOL;
+ V_BOOL(pvalue) = m_OptionValue.m_GenerateTCEAdapters;
+ }
+#endif //FEATURE_METADATA_EMIT_ALL || FEATURE_METADATA_EMIT_IN_DEBUGGER
+ else
+ {
+ _ASSERTE(!"Invalid GUID");
+ IfFailGo(E_INVALIDARG);
+ }
+ErrExit:
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // Disp::GetOption
+
+#if defined(FEATURE_METADATA_IN_VM) || defined(FEATURE_METADATA_STANDALONE_WINRT)
+
+//---------------------------------------------------------------------------------------
+//
+// Process detach destruction.
+// Called from DllMain of clr.dll/RoMetadata.dll/MidlrtMd.dll.
+//
+void DeleteMetaData()
+{
+ LOADEDMODULES::DeleteStatics();
+}
+
+#endif //FEATURE_METADATA_IN_VM || FEATURE_METADATA_STANDALONE_WINRT
+
+//
+// This is the entrypoint for usages of MetaData that need to start with the dispenser (e.g.
+// mscordbi.dll and profiling API).
+//
+// Notes:
+// This could be merged with the class factory support.
+HRESULT InternalCreateMetaDataDispenser(REFIID riid, void ** pMetaDataDispenserOut)
+{
+ _ASSERTE(pMetaDataDispenserOut != NULL);
+ return Disp::CreateObject(riid, pMetaDataDispenserOut);
+}
diff --git a/src/md/compiler/disp.h b/src/md/compiler/disp.h
new file mode 100644
index 0000000000..76a49e0d24
--- /dev/null
+++ b/src/md/compiler/disp.h
@@ -0,0 +1,132 @@
+// 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.
+//*****************************************************************************
+// Disp.h
+//
+
+//
+// Class factories are used by the pluming in COM to activate new objects.
+// This module contains the class factory code to instantiate the debugger
+// objects described in <cordb.h>.
+//
+//*****************************************************************************
+#ifndef __Disp__h__
+#define __Disp__h__
+
+
+class Disp :
+ public IMetaDataDispenserEx
+#ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE
+ , IMetaDataDispenserCustom
+#endif
+{
+public:
+ Disp();
+ virtual ~Disp();
+
+ // *** IUnknown methods ***
+ STDMETHODIMP QueryInterface(REFIID riid, void** ppv);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+ // *** IMetaDataDispenser methods ***
+ STDMETHODIMP DefineScope( // Return code.
+ REFCLSID rclsid, // [in] What version to create.
+ DWORD dwCreateFlags, // [in] Flags on the create.
+ REFIID riid, // [in] The interface desired.
+ IUnknown **ppIUnk); // [out] Return interface on success.
+
+ STDMETHODIMP OpenScope( // Return code.
+ LPCWSTR szScope, // [in] The scope to open.
+ DWORD dwOpenFlags, // [in] Open mode flags.
+ REFIID riid, // [in] The interface desired.
+ IUnknown **ppIUnk); // [out] Return interface on success.
+
+ STDMETHODIMP OpenScopeOnMemory( // Return code.
+ LPCVOID pData, // [in] Location of scope data.
+ ULONG cbData, // [in] Size of the data pointed to by pData.
+ DWORD dwOpenFlags, // [in] Open mode flags.
+ REFIID riid, // [in] The interface desired.
+ IUnknown **ppIUnk); // [out] Return interface on success.
+
+ // *** IMetaDataDispenserEx methods ***
+ STDMETHODIMP SetOption( // Return code.
+ REFGUID optionid, // [in] GUID for the option to be set.
+ const VARIANT *pvalue); // [in] Value to which the option is to be set.
+
+ STDMETHODIMP GetOption( // Return code.
+ REFGUID optionid, // [in] GUID for the option to be set.
+ VARIANT *pvalue); // [out] Value to which the option is currently set.
+
+ STDMETHODIMP OpenScopeOnITypeInfo( // Return code.
+ ITypeInfo *pITI, // [in] ITypeInfo to open.
+ DWORD dwOpenFlags, // [in] Open mode flags.
+ REFIID riid, // [in] The interface desired.
+ IUnknown **ppIUnk); // [out] Return interface on success.
+
+ STDMETHODIMP GetCORSystemDirectory( // Return code.
+ __out_ecount (cchBuffer) LPWSTR szBuffer, // [out] Buffer for the directory name
+ DWORD cchBuffer, // [in] Size of the buffer
+ DWORD* pchBuffer); // [OUT] Number of characters returned
+
+ STDMETHODIMP FindAssembly( // S_OK or error
+ LPCWSTR szAppBase, // [IN] optional - can be NULL
+ LPCWSTR szPrivateBin, // [IN] optional - can be NULL
+ LPCWSTR szGlobalBin, // [IN] optional - can be NULL
+ LPCWSTR szAssemblyName, // [IN] required - this is the assembly you are requesting
+ LPCWSTR szName, // [OUT] buffer - to hold name
+ ULONG cchName, // [IN] the name buffer's size
+ ULONG *pcName); // [OUT] the number of characters returend in the buffer
+
+ STDMETHODIMP FindAssemblyModule( // S_OK or error
+ LPCWSTR szAppBase, // [IN] optional - can be NULL
+ LPCWSTR szPrivateBin, // [IN] optional - can be NULL
+ LPCWSTR szGlobalBin, // [IN] optional - can be NULL
+ LPCWSTR szAssemblyName, // [IN] required - this is the assembly you are requesting
+ LPCWSTR szModuleName, // [IN] required - the name of the module
+ __out_ecount (cchName)LPWSTR szName,// [OUT] buffer - to hold name
+ ULONG cchName, // [IN] the name buffer's size
+ ULONG *pcName); // [OUT] the number of characters returend in the buffer
+
+#ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE
+ // *** IMetaDataDispenserCustom methods ***
+ STDMETHODIMP OpenScopeOnCustomDataSource( // S_OK or error
+ IMDCustomDataSource *pCustomSource, // [in] The scope to open.
+ DWORD dwOpenFlags, // [in] Open mode flags.
+ REFIID riid, // [in] The interface desired.
+ IUnknown **ppIUnk); // [out] Return interface on success.
+#endif
+
+ // Class factory hook-up.
+ static HRESULT CreateObject(REFIID riid, void **ppUnk);
+
+private:
+ HRESULT OpenRawScope( // Return code.
+ LPCWSTR szScope, // [in] The scope to open.
+ DWORD dwOpenFlags, // [in] Open mode flags.
+ REFIID riid, // [in] The interface desired.
+ IUnknown **ppIUnk); // [out] Return interface on success.
+
+ HRESULT OpenRawScopeOnMemory( // Return code.
+ LPCVOID pData, // [in] Location of scope data.
+ ULONG cbData, // [in] Size of the data pointed to by pData.
+ DWORD dwOpenFlags, // [in] Open mode flags.
+ REFIID riid, // [in] The interface desired.
+ IUnknown **ppIUnk); // [out] Return interface on success.
+
+#ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE
+ HRESULT OpenRawScopeOnCustomDataSource( // Return code.
+ IMDCustomDataSource* pDataSource, // [in] scope data.
+ DWORD dwOpenFlags, // [in] Open mode flags.
+ REFIID riid, // [in] The interface desired.
+ IUnknown **ppIUnk); // [out] Return interface on success.
+#endif
+
+
+private:
+ LONG m_cRef; // Ref count
+ OptionValue m_OptionValue; // values can be set by using SetOption
+};
+
+#endif // __Disp__h__
diff --git a/src/md/compiler/emit.cpp b/src/md/compiler/emit.cpp
new file mode 100644
index 0000000000..c77e28fa0f
--- /dev/null
+++ b/src/md/compiler/emit.cpp
@@ -0,0 +1,3001 @@
+// 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.
+//*****************************************************************************
+// Emit.cpp
+//
+
+//
+// Implementation for the meta data emit code.
+//
+//*****************************************************************************
+#include "stdafx.h"
+#include "regmeta.h"
+#include "mdutil.h"
+#include "rwutil.h"
+#include "mdlog.h"
+#include "importhelper.h"
+
+#ifdef FEATURE_METADATA_EMIT
+
+#ifdef _MSC_VER
+#pragma warning(disable: 4102)
+#endif
+
+//*****************************************************************************
+// Create and set a new MethodDef record.
+//*****************************************************************************
+STDMETHODIMP RegMeta::DefineMethod( // S_OK or error.
+ mdTypeDef td, // Parent TypeDef
+ LPCWSTR szName, // Name of member
+ DWORD dwMethodFlags, // Member attributes
+ PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of COM+ signature
+ ULONG cbSigBlob, // [IN] count of bytes in the signature blob
+ ULONG ulCodeRVA,
+ DWORD dwImplFlags,
+ mdMethodDef *pmd) // Put member token here
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ MethodRec *pRecord = NULL; // The new record.
+ RID iRecord; // The new record's RID.
+ LPUTF8 szNameUtf8;
+ UTF8STR(szName, szNameUtf8);
+
+ LOG((LOGMD, "MD: RegMeta::DefineMethod(0x%08x, %S, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ td, MDSTR(szName), dwMethodFlags, pvSigBlob, cbSigBlob, ulCodeRVA, dwImplFlags, pmd));
+ START_MD_PERF();
+
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ _ASSERTE(pmd);
+
+ // Make sure no one sets the reserved bits on the way in.
+ dwMethodFlags &= (~mdReservedMask);
+
+ IsGlobalMethodParent(&td);
+
+ // See if this method has already been defined.
+ if (CheckDups(MDDupMethodDef))
+ {
+ hr = ImportHelper::FindMethod(
+ &(m_pStgdb->m_MiniMd),
+ td,
+ szNameUtf8,
+ pvSigBlob,
+ cbSigBlob,
+ pmd);
+
+ if (SUCCEEDED(hr))
+ {
+ if (IsENCOn())
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(*pmd), &pRecord));
+ }
+ else
+ {
+ hr = META_S_DUPLICATE;
+ goto ErrExit;
+ }
+ }
+ else if (hr != CLDB_E_RECORD_NOTFOUND)
+ {
+ IfFailGo(hr);
+ }
+ }
+
+ // Create the new record.
+ if (pRecord == NULL)
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.AddMethodRecord(&pRecord, &iRecord));
+
+ // Give token back to caller.
+ *pmd = TokenFromRid(iRecord, mdtMethodDef);
+
+ // Add to parent's list of child records.
+ IfFailGo(m_pStgdb->m_MiniMd.AddMethodToTypeDef(RidFromToken(td), iRecord));
+
+ IfFailGo(UpdateENCLog(td, CMiniMdRW::eDeltaMethodCreate));
+
+ // record the more defs are introduced.
+ SetMemberDefDirty(true);
+ }
+
+ // Set the method properties.
+ IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_Method, MethodRec::COL_Name, pRecord, szNameUtf8));
+ IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_Method, MethodRec::COL_Signature, pRecord, pvSigBlob, cbSigBlob));
+
+ // <TODO>@FUTURE: possible performance improvement here to check _ first of all.</TODO>
+ // .ctor and .cctor below are defined in corhdr.h. However, corhdr.h does not have the
+ // the W() macro we need (since it's distributed to windows). We substitute the values of each
+ // macro in the code below to work around this issue.
+ // #define COR_CTOR_METHOD_NAME_W L".ctor"
+ // #define COR_CCTOR_METHOD_NAME_W L".cctor"
+
+ if (!wcscmp(szName, W(".ctor")) || // COR_CTOR_METHOD_NAME_W
+ !wcscmp(szName, W(".cctor")) || // COR_CCTOR_METHOD_NAME_W
+ !wcsncmp(szName, W("_VtblGap"), 8) )
+ {
+ dwMethodFlags |= mdRTSpecialName | mdSpecialName;
+ }
+ SetCallerDefine();
+ IfFailGo(_SetMethodProps(*pmd, dwMethodFlags, ulCodeRVA, dwImplFlags));
+
+ IfFailGo(m_pStgdb->m_MiniMd.AddMemberDefToHash(*pmd, td) );
+
+ErrExit:
+ SetCallerExternal();
+
+ STOP_MD_PERF(DefineMethod);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::DefineMethod
+
+//*****************************************************************************
+// Create and set a MethodImpl Record.
+//*****************************************************************************
+STDMETHODIMP RegMeta::DefineMethodImpl( // S_OK or error.
+ mdTypeDef td, // [IN] The class implementing the method
+ mdToken tkBody, // [IN] Method body, MethodDef or MethodRef
+ mdToken tkDecl) // [IN] Method declaration, MethodDef or MethodRef
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ MethodImplRec *pMethodImplRec = NULL;
+ RID iMethodImplRec;
+
+ LOG((LOGMD, "MD RegMeta::DefineMethodImpl(0x%08x, 0x%08x, 0x%08x)\n",
+ td, tkBody, tkDecl));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ _ASSERTE(TypeFromToken(td) == mdtTypeDef);
+ _ASSERTE(TypeFromToken(tkBody) == mdtMemberRef || TypeFromToken(tkBody) == mdtMethodDef);
+ _ASSERTE(TypeFromToken(tkDecl) == mdtMemberRef || TypeFromToken(tkDecl) == mdtMethodDef);
+ _ASSERTE(!IsNilToken(td) && !IsNilToken(tkBody) && !IsNilToken(tkDecl));
+
+ // Check for duplicates.
+ if (CheckDups(MDDupMethodDef))
+ {
+ hr = ImportHelper::FindMethodImpl(&m_pStgdb->m_MiniMd, td, tkBody, tkDecl, NULL);
+ if (SUCCEEDED(hr))
+ {
+ hr = META_S_DUPLICATE;
+ goto ErrExit;
+ }
+ else if (hr != CLDB_E_RECORD_NOTFOUND)
+ IfFailGo(hr);
+ }
+
+ // Create the MethodImpl record.
+ IfFailGo(m_pStgdb->m_MiniMd.AddMethodImplRecord(&pMethodImplRec, &iMethodImplRec));
+
+ // Set the values.
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_MethodImpl, MethodImplRec::COL_Class,
+ pMethodImplRec, td));
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_MethodImpl, MethodImplRec::COL_MethodBody,
+ pMethodImplRec, tkBody));
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_MethodImpl, MethodImplRec::COL_MethodDeclaration,
+ pMethodImplRec, tkDecl));
+
+ IfFailGo( m_pStgdb->m_MiniMd.AddMethodImplToHash(iMethodImplRec) );
+
+ IfFailGo(UpdateENCLog2(TBL_MethodImpl, iMethodImplRec));
+ErrExit:
+
+ STOP_MD_PERF(DefineMethodImpl);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::DefineMethodImpl
+
+
+//*****************************************************************************
+// Set or update RVA and ImplFlags for the given MethodDef or FieldDef record.
+//*****************************************************************************
+STDMETHODIMP RegMeta::SetMethodImplFlags( // [IN] S_OK or error.
+ mdMethodDef md, // [IN] Method for which to set impl flags
+ DWORD dwImplFlags)
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ MethodRec *pMethodRec;
+
+ LOG((LOGMD, "MD RegMeta::SetMethodImplFlags(0x%08x, 0x%08x)\n",
+ md, dwImplFlags));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ _ASSERTE(TypeFromToken(md) == mdtMethodDef && dwImplFlags != ULONG_MAX);
+
+ // Get the record.
+ IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(md), &pMethodRec));
+ pMethodRec->SetImplFlags(static_cast<USHORT>(dwImplFlags));
+
+ IfFailGo(UpdateENCLog(md));
+
+ErrExit:
+ STOP_MD_PERF(SetMethodImplFlags);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::SetMethodImplFlags
+
+
+//*****************************************************************************
+// Set or update RVA and ImplFlags for the given MethodDef or FieldDef record.
+//*****************************************************************************
+STDMETHODIMP RegMeta::SetFieldRVA( // [IN] S_OK or error.
+ mdFieldDef fd, // [IN] Field for which to set offset
+ ULONG ulRVA) // [IN] The offset
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ FieldRVARec *pFieldRVARec;
+ RID iFieldRVA;
+ FieldRec *pFieldRec;
+
+ LOG((LOGMD, "MD RegMeta::SetFieldRVA(0x%08x, 0x%08x)\n",
+ fd, ulRVA));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ _ASSERTE(TypeFromToken(fd) == mdtFieldDef);
+
+
+ IfFailGo(m_pStgdb->m_MiniMd.FindFieldRVAHelper(fd, &iFieldRVA));
+
+ if (InvalidRid(iFieldRVA))
+ {
+ // turn on the has field RVA bit
+ IfFailGo(m_pStgdb->m_MiniMd.GetFieldRecord(RidFromToken(fd), &pFieldRec));
+ pFieldRec->AddFlags(fdHasFieldRVA);
+
+ // Create a new record.
+ IfFailGo(m_pStgdb->m_MiniMd.AddFieldRVARecord(&pFieldRVARec, &iFieldRVA));
+
+ // Set the data.
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_FieldRVA, FieldRVARec::COL_Field,
+ pFieldRVARec, fd));
+ IfFailGo( m_pStgdb->m_MiniMd.AddFieldRVAToHash(iFieldRVA) );
+ }
+ else
+ {
+ // Get the record.
+ IfFailGo(m_pStgdb->m_MiniMd.GetFieldRVARecord(iFieldRVA, &pFieldRVARec));
+ }
+
+ // Set the data.
+ pFieldRVARec->SetRVA(ulRVA);
+
+ IfFailGo(UpdateENCLog2(TBL_FieldRVA, iFieldRVA));
+
+ErrExit:
+ STOP_MD_PERF(SetFieldRVA);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::SetFieldRVA
+
+
+//*****************************************************************************
+// Helper: Set or update RVA and ImplFlags for the given MethodDef or MethodImpl record.
+//*****************************************************************************
+HRESULT RegMeta::_SetRVA( // [IN] S_OK or error.
+ mdToken tk, // [IN] Member for which to set offset
+ ULONG ulCodeRVA, // [IN] The offset
+ DWORD dwImplFlags)
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ _ASSERTE(TypeFromToken(tk) == mdtMethodDef || TypeFromToken(tk) == mdtFieldDef);
+ _ASSERTE(!IsNilToken(tk));
+
+ if (TypeFromToken(tk) == mdtMethodDef)
+ {
+ MethodRec *pMethodRec;
+
+ // Get the record.
+ IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(tk), &pMethodRec));
+
+ // Set the data.
+ pMethodRec->SetRVA(ulCodeRVA);
+
+ // Do not set the flag value unless its valid.
+ if (dwImplFlags != ULONG_MAX)
+ pMethodRec->SetImplFlags(static_cast<USHORT>(dwImplFlags));
+
+ IfFailGo(UpdateENCLog(tk));
+ }
+ else // TypeFromToken(tk) == mdtFieldDef
+ {
+ _ASSERTE(dwImplFlags==0 || dwImplFlags==ULONG_MAX);
+
+ FieldRVARec *pFieldRVARec;
+ RID iFieldRVA;
+ FieldRec *pFieldRec;
+
+ IfFailGo(m_pStgdb->m_MiniMd.FindFieldRVAHelper(tk, &iFieldRVA));
+
+ if (InvalidRid(iFieldRVA))
+ {
+ // turn on the has field RVA bit
+ IfFailGo(m_pStgdb->m_MiniMd.GetFieldRecord(RidFromToken(tk), &pFieldRec));
+ pFieldRec->AddFlags(fdHasFieldRVA);
+
+ // Create a new record.
+ IfFailGo(m_pStgdb->m_MiniMd.AddFieldRVARecord(&pFieldRVARec, &iFieldRVA));
+
+ // Set the data.
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_FieldRVA, FieldRVARec::COL_Field,
+ pFieldRVARec, tk));
+
+ IfFailGo( m_pStgdb->m_MiniMd.AddFieldRVAToHash(iFieldRVA) );
+
+ }
+ else
+ {
+ // Get the record.
+ IfFailGo(m_pStgdb->m_MiniMd.GetFieldRVARecord(iFieldRVA, &pFieldRVARec));
+ }
+
+ // Set the data.
+ pFieldRVARec->SetRVA(ulCodeRVA);
+
+ IfFailGo(UpdateENCLog2(TBL_FieldRVA, iFieldRVA));
+ }
+
+ErrExit:
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::_SetRVA
+
+//*****************************************************************************
+// Given a name, create a TypeRef.
+//*****************************************************************************
+STDMETHODIMP RegMeta::DefineTypeRefByName( // S_OK or error.
+ mdToken tkResolutionScope, // [IN] ModuleRef or AssemblyRef.
+ LPCWSTR szName, // [IN] Name of the TypeRef.
+ mdTypeRef *ptr) // [OUT] Put TypeRef token here.
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+
+ LOG((LOGMD, "MD RegMeta::DefineTypeRefByName(0x%08x, %S, 0x%08x)\n",
+ tkResolutionScope, MDSTR(szName), ptr));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ // Common helper function does all of the work.
+ IfFailGo(_DefineTypeRef(tkResolutionScope, szName, TRUE, ptr));
+
+ErrExit:
+ STOP_MD_PERF(DefineTypeRefByName);
+
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::DefineTypeRefByName
+
+//*****************************************************************************
+// Create a reference, in an emit scope, to a TypeDef in another scope.
+//*****************************************************************************
+STDMETHODIMP RegMeta::DefineImportType( // S_OK or error.
+ IMetaDataAssemblyImport *pAssemImport, // [IN] Assemby containing the TypeDef.
+ const void *pbHashValue, // [IN] Hash Blob for Assembly.
+ ULONG cbHashValue, // [IN] Count of bytes.
+ IMetaDataImport *pImport, // [IN] Scope containing the TypeDef.
+ mdTypeDef tdImport, // [IN] The imported TypeDef.
+ IMetaDataAssemblyEmit *pAssemEmit, // [IN] Assembly into which the TypeDef is imported.
+ mdTypeRef *ptr) // [OUT] Put TypeRef token here.
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ IMetaDataImport2 *pImport2 = NULL;
+ IMDCommon *pImport2MDCommon = NULL;
+
+ IMDCommon *pAssemImportMDCommon = NULL;
+
+ RegMeta *pAssemEmitRM = NULL;
+ CMiniMdRW *pMiniMdAssemEmit = NULL;
+ CMiniMdRW *pMiniMdEmit = NULL;
+
+ IMetaModelCommon *pAssemImportMetaModelCommon;
+ IMetaModelCommon *pImport2MetaModelCommon;
+
+ LOG((LOGMD, "MD RegMeta::DefineImportType(0x%08x, 0x%08x, 0x%08x, 0x%08x, "
+ "0x%08x, 0x%08x, 0x%08x)\n",
+ pAssemImport, pbHashValue, cbHashValue,
+ pImport, tdImport, pAssemEmit, ptr));
+
+ START_MD_PERF();
+
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+ IfFailGo(pImport->QueryInterface(IID_IMetaDataImport2, (void**)&pImport2));
+
+ if (pAssemImport)
+ {
+ IfFailGo(pAssemImport->QueryInterface(IID_IMDCommon, (void**)&pAssemImportMDCommon));
+ }
+
+ pAssemImportMetaModelCommon = pAssemImportMDCommon ? pAssemImportMDCommon->GetMetaModelCommon() : 0;
+
+ IfFailGo(pImport2->QueryInterface(IID_IMDCommon, (void**)&pImport2MDCommon));
+ pImport2MetaModelCommon = pImport2MDCommon->GetMetaModelCommon();
+
+ pAssemEmitRM = static_cast<RegMeta*>(pAssemEmit);
+ pMiniMdAssemEmit = pAssemEmitRM ? static_cast<CMiniMdRW*>(&pAssemEmitRM->m_pStgdb->m_MiniMd) : 0;
+ pMiniMdEmit = &m_pStgdb->m_MiniMd;
+
+ IfFailGo(ImportHelper::ImportTypeDef(
+ pMiniMdAssemEmit,
+ pMiniMdEmit,
+ pAssemImportMetaModelCommon,
+ pbHashValue, cbHashValue,
+ pImport2MetaModelCommon,
+ tdImport,
+ false, // Do not optimize to TypeDef if import and emit scopes are identical.
+ ptr));
+
+ErrExit:
+ if (pImport2)
+ pImport2->Release();
+ if (pImport2MDCommon)
+ pImport2MDCommon->Release();
+ if (pAssemImportMDCommon)
+ pAssemImportMDCommon->Release();
+ STOP_MD_PERF(DefineImportType);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::DefineImportType
+
+//*****************************************************************************
+// Create and set a MemberRef record.
+//*****************************************************************************
+STDMETHODIMP RegMeta::DefineMemberRef( // S_OK or error
+ mdToken tkImport, // [IN] ClassRef or ClassDef importing a member.
+ LPCWSTR szName, // [IN] member's 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] memberref token
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ MemberRefRec *pRecord = 0; // The MemberRef record.
+ RID iRecord; // RID of new MemberRef record.
+ LPUTF8 szNameUtf8;
+ UTF8STR(szName, szNameUtf8);
+
+ LOG((LOGMD, "MD RegMeta::DefineMemberRef(0x%08x, %S, 0x%08x, 0x%08x, 0x%08x)\n",
+ tkImport, MDSTR(szName), pvSigBlob, cbSigBlob, pmr));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ _ASSERTE(TypeFromToken(tkImport) == mdtTypeRef ||
+ TypeFromToken(tkImport) == mdtModuleRef ||
+ TypeFromToken(tkImport) == mdtMethodDef ||
+ TypeFromToken(tkImport) == mdtTypeSpec ||
+ (TypeFromToken(tkImport) == mdtTypeDef) ||
+ IsNilToken(tkImport));
+
+ _ASSERTE(szName && pvSigBlob && cbSigBlob && pmr);
+
+ // _ASSERTE(_IsValidToken(tkImport));
+
+ // Set token to m_tdModule if referring to a global function.
+ if (IsNilToken(tkImport))
+ tkImport = m_tdModule;
+
+ // If the MemberRef already exists, just return the token, else
+ // create a new record.
+ if (CheckDups(MDDupMemberRef))
+ {
+ hr = ImportHelper::FindMemberRef(&(m_pStgdb->m_MiniMd), tkImport, szNameUtf8, pvSigBlob, cbSigBlob, pmr);
+ if (SUCCEEDED(hr))
+ {
+ if (IsENCOn())
+ IfFailGo(m_pStgdb->m_MiniMd.GetMemberRefRecord(RidFromToken(*pmr), &pRecord));
+ else
+ {
+ hr = META_S_DUPLICATE;
+ goto ErrExit;
+ }
+ }
+ else if (hr != CLDB_E_RECORD_NOTFOUND) // MemberRef exists
+ IfFailGo(hr);
+ }
+
+ if (!pRecord)
+ { // Create the record.
+ IfFailGo(m_pStgdb->m_MiniMd.AddMemberRefRecord(&pRecord, &iRecord));
+
+ // record the more defs are introduced.
+ SetMemberDefDirty(true);
+
+ // Give token to caller.
+ *pmr = TokenFromRid(iRecord, mdtMemberRef);
+ }
+
+ // Save row data.
+ IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_MemberRef, MemberRefRec::COL_Name, pRecord, szNameUtf8));
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_MemberRef, MemberRefRec::COL_Class, pRecord, tkImport));
+ IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_MemberRef, MemberRefRec::COL_Signature, pRecord,
+ pvSigBlob, cbSigBlob));
+
+ IfFailGo(m_pStgdb->m_MiniMd.AddMemberRefToHash(*pmr) );
+
+ IfFailGo(UpdateENCLog(*pmr));
+
+ErrExit:
+
+ STOP_MD_PERF(DefineMemberRef);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::DefineMemberRef
+
+//*****************************************************************************
+// Create a MemberRef record based on a member in an import scope.
+//*****************************************************************************
+STDMETHODIMP RegMeta::DefineImportMember( // S_OK or error.
+ IMetaDataAssemblyImport *pAssemImport, // [IN] Assemby containing the Member.
+ const void *pbHashValue, // [IN] Hash Blob for Assembly.
+ ULONG cbHashValue, // [IN] Count of bytes.
+ IMetaDataImport *pImport, // [IN] Import scope, with member.
+ mdToken mbMember, // [IN] Member in import scope.
+ IMetaDataAssemblyEmit *pAssemEmit, // [IN] Assembly into which the Member is imported.
+ mdToken tkImport, // [IN] Classref or classdef in emit scope.
+ mdMemberRef *pmr) // [OUT] Put member ref here.
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+
+ LOG((LOGMD, "MD RegMeta::DefineImportMember("
+ "0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x,"
+ " 0x%08x, 0x%08x, 0x%08x)\n",
+ pAssemImport, pbHashValue, cbHashValue, pImport, mbMember,
+ pAssemEmit, tkImport, pmr));
+ START_MD_PERF();
+
+ // No need to lock this function. All the functions that it calls are public APIs.
+
+ _ASSERTE(pImport && pmr);
+ _ASSERTE(TypeFromToken(tkImport) == mdtTypeRef || TypeFromToken(tkImport) == mdtModuleRef ||
+ IsNilToken(tkImport) || TypeFromToken(tkImport) == mdtTypeSpec);
+ _ASSERTE((TypeFromToken(mbMember) == mdtMethodDef && mbMember != mdMethodDefNil) ||
+ (TypeFromToken(mbMember) == mdtFieldDef && mbMember != mdFieldDefNil));
+
+ CQuickArray<WCHAR> qbMemberName; // Name of the imported member.
+ CQuickArray<WCHAR> qbScopeName; // Name of the imported member's scope.
+ GUID mvidImport; // MVID of the import module.
+ GUID mvidEmit; // MVID of the emit module.
+ ULONG cchName; // Length of a name, in wide chars.
+ PCCOR_SIGNATURE pvSig; // Member's signature.
+ ULONG cbSig; // Length of member's signature.
+ CQuickBytes cqbTranslatedSig; // Buffer for signature translation.
+ ULONG cbTranslatedSig; // Length of translated signature.
+
+ if (TypeFromToken(mbMember) == mdtMethodDef)
+ {
+ do {
+ hr = pImport->GetMethodProps(mbMember, 0, qbMemberName.Ptr(),(DWORD)qbMemberName.MaxSize(),&cchName,
+ 0, &pvSig,&cbSig, 0,0);
+ if (hr == CLDB_S_TRUNCATION)
+ {
+ IfFailGo(qbMemberName.ReSizeNoThrow(cchName));
+ continue;
+ }
+ break;
+ } while (1);
+ }
+ else // TypeFromToken(mbMember) == mdtFieldDef
+ {
+ do {
+ hr = pImport->GetFieldProps(mbMember, 0, qbMemberName.Ptr(),(DWORD)qbMemberName.MaxSize(),&cchName,
+ 0, &pvSig,&cbSig, 0,0, 0);
+ if (hr == CLDB_S_TRUNCATION)
+ {
+ IfFailGo(qbMemberName.ReSizeNoThrow(cchName));
+ continue;
+ }
+ break;
+ } while (1);
+ }
+ IfFailGo(hr);
+
+ IfFailGo(cqbTranslatedSig.ReSizeNoThrow(cbSig * 3)); // Set size conservatively.
+
+ IfFailGo(TranslateSigWithScope(
+ pAssemImport,
+ pbHashValue,
+ cbHashValue,
+ pImport,
+ pvSig,
+ cbSig,
+ pAssemEmit,
+ static_cast<IMetaDataEmit*>(static_cast<IMetaDataEmit2*>(this)),
+ (COR_SIGNATURE *)cqbTranslatedSig.Ptr(),
+ cbSig * 3,
+ &cbTranslatedSig));
+
+ // Define ModuleRef for imported Member functions
+
+ // Check if the Member being imported is a global function.
+ IfFailGo(GetScopeProps(0, 0, 0, &mvidEmit));
+ IfFailGo(pImport->GetScopeProps(0, 0,&cchName, &mvidImport));
+ if (mvidEmit != mvidImport && IsNilToken(tkImport))
+ {
+ IfFailGo(qbScopeName.ReSizeNoThrow(cchName));
+ IfFailGo(pImport->GetScopeProps(qbScopeName.Ptr(),(DWORD)qbScopeName.MaxSize(),
+ 0, 0));
+ IfFailGo(DefineModuleRef(qbScopeName.Ptr(), &tkImport));
+ }
+
+ // Define MemberRef base on the name, sig, and parent
+ IfFailGo(DefineMemberRef(
+ tkImport,
+ qbMemberName.Ptr(),
+ reinterpret_cast<PCCOR_SIGNATURE>(cqbTranslatedSig.Ptr()),
+ cbTranslatedSig,
+ pmr));
+
+ErrExit:
+ STOP_MD_PERF(DefineImportMember);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::DefineImportMember
+
+//*****************************************************************************
+// Define and set a Event record.
+//*****************************************************************************
+STDMETHODIMP RegMeta::DefineEvent(
+ mdTypeDef td, // [IN] the class/interface on which the event is being defined
+ LPCWSTR szEvent, // [IN] Name of the event
+ DWORD dwEventFlags, // [IN] CorEventAttr
+ mdToken tkEventType, // [IN] a reference (mdTypeRef or mdTypeRef(to the Event class
+ mdMethodDef mdAddOn, // [IN] required add method
+ mdMethodDef mdRemoveOn, // [IN] required remove method
+ mdMethodDef mdFire, // [IN] optional fire method
+ mdMethodDef rmdOtherMethods[], // [IN] optional array of other methods associate with the event
+ mdEvent *pmdEvent) // [OUT] output event token
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+
+ LOG((LOGMD, "MD RegMeta::DefineEvent(0x%08x, %S, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ td, szEvent, dwEventFlags, tkEventType, mdAddOn, mdRemoveOn, mdFire, rmdOtherMethods, pmdEvent));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ _ASSERTE(TypeFromToken(td) == mdtTypeDef && td != mdTypeDefNil);
+ _ASSERTE(IsNilToken(tkEventType) || TypeFromToken(tkEventType) == mdtTypeDef ||
+ TypeFromToken(tkEventType) == mdtTypeRef || TypeFromToken(tkEventType) == mdtTypeSpec);
+ _ASSERTE(TypeFromToken(mdAddOn) == mdtMethodDef && mdAddOn != mdMethodDefNil);
+ _ASSERTE(TypeFromToken(mdRemoveOn) == mdtMethodDef && mdRemoveOn != mdMethodDefNil);
+ _ASSERTE(IsNilToken(mdFire) || TypeFromToken(mdFire) == mdtMethodDef);
+ _ASSERTE(szEvent && pmdEvent);
+
+ hr = _DefineEvent(td, szEvent, dwEventFlags, tkEventType, pmdEvent);
+ if (hr != S_OK)
+ goto ErrExit;
+
+ IfFailGo(_SetEventProps2(*pmdEvent, mdAddOn, mdRemoveOn, mdFire, rmdOtherMethods, IsENCOn()));
+ IfFailGo(UpdateENCLog(*pmdEvent));
+ErrExit:
+
+ STOP_MD_PERF(DefineEvent);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::DefineEvent
+
+//*****************************************************************************
+// Set the ClassLayout information.
+//
+// If a row already exists for this class in the layout table, the layout
+// information is overwritten.
+//*****************************************************************************
+STDMETHODIMP RegMeta::SetClassLayout(
+ mdTypeDef td, // [IN] typedef
+ DWORD dwPackSize, // [IN] packing size specified as 1, 2, 4, 8, or 16
+ COR_FIELD_OFFSET rFieldOffsets[], // [IN] array of layout specification
+ ULONG ulClassSize) // [IN] size of the class
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK; // A result.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ int index = 0; // Loop control.
+
+ LOG((LOGMD, "MD RegMeta::SetClassLayout(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ td, dwPackSize, rFieldOffsets, ulClassSize));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ _ASSERTE(TypeFromToken(td) == mdtTypeDef);
+
+ // Create entries in the FieldLayout table.
+ if (rFieldOffsets)
+ {
+ mdFieldDef tkfd;
+ // Iterate the list of fields...
+ for (index = 0; rFieldOffsets[index].ridOfField != mdFieldDefNil; index++)
+ {
+ if (rFieldOffsets[index].ulOffset != ULONG_MAX)
+ {
+ tkfd = TokenFromRid(rFieldOffsets[index].ridOfField, mdtFieldDef);
+
+ IfFailGo(_SetFieldOffset(tkfd, rFieldOffsets[index].ulOffset));
+ }
+ }
+ }
+
+ IfFailGo(_SetClassLayout(td, dwPackSize, ulClassSize));
+
+ErrExit:
+
+ STOP_MD_PERF(SetClassLayout);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::SetClassLayout
+
+//*****************************************************************************
+// Helper function to set a class layout for a given class.
+//*****************************************************************************
+HRESULT RegMeta::_SetClassLayout( // S_OK or error.
+ mdTypeDef td, // [IN] The class.
+ ULONG dwPackSize, // [IN] The packing size.
+ ULONG ulClassSize) // [IN, OPTIONAL] The class size.
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK; // A result.
+ ClassLayoutRec *pClassLayout; // A classlayout record.
+ RID iClassLayout = 0; // RID of classlayout record.
+
+ // See if a ClassLayout record already exists for the given TypeDef.
+ IfFailGo(m_pStgdb->m_MiniMd.FindClassLayoutHelper(td, &iClassLayout));
+
+ if (InvalidRid(iClassLayout))
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.AddClassLayoutRecord(&pClassLayout, &iClassLayout));
+ // Set the Parent entry.
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_ClassLayout, ClassLayoutRec::COL_Parent,
+ pClassLayout, td));
+ IfFailGo( m_pStgdb->m_MiniMd.AddClassLayoutToHash(iClassLayout) );
+ }
+ else
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.GetClassLayoutRecord(iClassLayout, &pClassLayout));
+ }
+
+ // Set the data.
+ if (dwPackSize != ULONG_MAX)
+ pClassLayout->SetPackingSize(static_cast<USHORT>(dwPackSize));
+ if (ulClassSize != ULONG_MAX)
+ pClassLayout->SetClassSize(ulClassSize);
+
+ // Create the log record for the non-token record.
+ IfFailGo(UpdateENCLog2(TBL_ClassLayout, iClassLayout));
+
+ErrExit:
+
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::_SetClassLayout
+
+//*****************************************************************************
+// Helper function to set a field offset for a given field def.
+//*****************************************************************************
+HRESULT RegMeta::_SetFieldOffset( // S_OK or error.
+ mdFieldDef fd, // [IN] The field.
+ ULONG ulOffset) // [IN] The offset of the field.
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr;
+ FieldLayoutRec * pFieldLayoutRec=0; // A FieldLayout record.
+ RID iFieldLayoutRec=0; // RID of a FieldLayout record.
+
+ // See if an entry already exists for the Field in the FieldLayout table.
+ IfFailGo(m_pStgdb->m_MiniMd.FindFieldLayoutHelper(fd, &iFieldLayoutRec));
+ if (InvalidRid(iFieldLayoutRec))
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.AddFieldLayoutRecord(&pFieldLayoutRec, &iFieldLayoutRec));
+ // Set the Field entry.
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_FieldLayout, FieldLayoutRec::COL_Field,
+ pFieldLayoutRec, fd));
+ IfFailGo( m_pStgdb->m_MiniMd.AddFieldLayoutToHash(iFieldLayoutRec) );
+ }
+ else
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.GetFieldLayoutRecord(iFieldLayoutRec, &pFieldLayoutRec));
+ }
+
+ // Set the offset.
+ pFieldLayoutRec->SetOffSet(ulOffset);
+
+ // Create the log record for the non-token record.
+ IfFailGo(UpdateENCLog2(TBL_FieldLayout, iFieldLayoutRec));
+
+ErrExit:
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::_SetFieldOffset
+
+//*****************************************************************************
+// Delete the ClassLayout information.
+//*****************************************************************************
+STDMETHODIMP RegMeta::DeleteClassLayout(
+ mdTypeDef td) // [IN] typdef token
+{
+#ifdef FEATURE_METADATA_EMIT_ALL
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ ClassLayoutRec *pClassLayoutRec;
+ TypeDefRec *pTypeDefRec;
+ FieldLayoutRec *pFieldLayoutRec;
+ RID iClassLayoutRec;
+ RID iFieldLayoutRec;
+ RID ridStart;
+ RID ridEnd;
+ RID ridCur;
+ ULONG index;
+
+ LOG((LOGMD, "MD RegMeta::DeleteClassLayout(0x%08x)\n", td));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ _ASSERTE(!m_bSaveOptimized && "Cannot change records after PreSave() and before Save().");
+ _ASSERTE(TypeFromToken(td) == mdtTypeDef && !IsNilToken(td));
+
+ // Get the ClassLayout record.
+ IfFailGo(m_pStgdb->m_MiniMd.FindClassLayoutHelper(td, &iClassLayoutRec));
+ if (InvalidRid(iClassLayoutRec))
+ {
+ hr = CLDB_E_RECORD_NOTFOUND;
+ goto ErrExit;
+ }
+ IfFailGo(m_pStgdb->m_MiniMd.GetClassLayoutRecord(iClassLayoutRec, &pClassLayoutRec));
+
+ // Clear the parent.
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_ClassLayout,
+ ClassLayoutRec::COL_Parent,
+ pClassLayoutRec, mdTypeDefNil));
+
+ // Create the log record for the non-token record.
+ IfFailGo(UpdateENCLog2(TBL_ClassLayout, iClassLayoutRec));
+
+ // Delete all the corresponding FieldLayout records if there are any.
+ IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(td), &pTypeDefRec));
+ ridStart = m_pStgdb->m_MiniMd.getFieldListOfTypeDef(pTypeDefRec);
+ IfFailGo(m_pStgdb->m_MiniMd.getEndFieldListOfTypeDef(RidFromToken(td), &ridEnd));
+
+ for (index = ridStart; index < ridEnd; index++)
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.GetFieldRid(index, &ridCur));
+ IfFailGo(m_pStgdb->m_MiniMd.FindFieldLayoutHelper(TokenFromRid(ridCur, mdtFieldDef), &iFieldLayoutRec));
+ if (InvalidRid(iFieldLayoutRec))
+ continue;
+ else
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.GetFieldLayoutRecord(iFieldLayoutRec, &pFieldLayoutRec));
+ // Set the Field entry.
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_FieldLayout, FieldLayoutRec::COL_Field,
+ pFieldLayoutRec, mdFieldDefNil));
+ // Create the log record for the non-token record.
+ IfFailGo(UpdateENCLog2(TBL_FieldLayout, iFieldLayoutRec));
+ }
+ }
+ErrExit:
+ STOP_MD_PERF(DeleteClassLayout);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#else //!FEATURE_METADATA_EMIT_ALL
+ return E_NOTIMPL;
+#endif //!FEATURE_METADATA_EMIT_ALL
+} // RegMeta::DeleteClassLayout
+
+//*****************************************************************************
+// Set the field's native type.
+//*****************************************************************************
+STDMETHODIMP RegMeta::SetFieldMarshal(
+ mdToken tk, // [IN] given a fieldDef or paramDef token
+ PCCOR_SIGNATURE pvNativeType, // [IN] native type specification
+ ULONG cbNativeType) // [IN] count of bytes of pvNativeType
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+
+ LOG((LOGMD, "MD RegMeta::SetFieldMarshal(0x%08x, 0x%08x, 0x%08x)\n",
+ tk, pvNativeType, cbNativeType));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ hr = _SetFieldMarshal(tk, pvNativeType, cbNativeType);
+
+ErrExit:
+ STOP_MD_PERF(SetFieldMarshal);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::SetFieldMarshal
+
+HRESULT RegMeta::_SetFieldMarshal(
+ mdToken tk, // [IN] given a fieldDef or paramDef token
+ PCCOR_SIGNATURE pvNativeType, // [IN] native type specification
+ ULONG cbNativeType) // [IN] count of bytes of pvNativeType
+{
+ HRESULT hr = S_OK;
+ FieldMarshalRec *pFieldMarshRec;
+ RID iFieldMarshRec = 0; // initialize to invalid rid
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ _ASSERTE(TypeFromToken(tk) == mdtFieldDef || TypeFromToken(tk) == mdtParamDef);
+ _ASSERTE(!IsNilToken(tk));
+
+ // turn on the HasFieldMarshal
+ if (TypeFromToken(tk) == mdtFieldDef)
+ {
+ FieldRec *pFieldRec;
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetFieldRecord(RidFromToken(tk), &pFieldRec));
+ pFieldRec->AddFlags(fdHasFieldMarshal);
+ }
+ else // TypeFromToken(tk) == mdtParamDef
+ {
+ ParamRec *pParamRec;
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetParamRecord(RidFromToken(tk), &pParamRec));
+ pParamRec->AddFlags(pdHasFieldMarshal);
+ }
+ IfFailGo(UpdateENCLog(tk));
+
+ IfFailGo(m_pStgdb->m_MiniMd.FindFieldMarshalHelper(tk, &iFieldMarshRec));
+ if (InvalidRid(iFieldMarshRec))
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.AddFieldMarshalRecord(&pFieldMarshRec, &iFieldMarshRec));
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_FieldMarshal, FieldMarshalRec::COL_Parent, pFieldMarshRec, tk));
+ IfFailGo( m_pStgdb->m_MiniMd.AddFieldMarshalToHash(iFieldMarshRec) );
+ }
+ else
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.GetFieldMarshalRecord(iFieldMarshRec, &pFieldMarshRec));
+ }
+
+ // Set data.
+ IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_FieldMarshal, FieldMarshalRec::COL_NativeType, pFieldMarshRec,
+ pvNativeType, cbNativeType));
+
+ // Create the log record for the non-token record.
+ IfFailGo(UpdateENCLog2(TBL_FieldMarshal, iFieldMarshRec));
+
+ErrExit:
+
+ return hr;
+} // RegMeta::_SetFieldMarshal
+
+
+//*****************************************************************************
+// Delete the FieldMarshal record for the given token.
+//*****************************************************************************
+STDMETHODIMP RegMeta::DeleteFieldMarshal(
+ mdToken tk) // [IN] fieldDef or paramDef token to be deleted.
+{
+#ifdef FEATURE_METADATA_EMIT_ALL
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ FieldMarshalRec *pFieldMarshRec;
+ RID iFieldMarshRec;
+
+
+
+ LOG((LOGMD, "MD RegMeta::DeleteFieldMarshal(0x%08x)\n", tk));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ _ASSERTE(TypeFromToken(tk) == mdtFieldDef || TypeFromToken(tk) == mdtParamDef);
+ _ASSERTE(!IsNilToken(tk));
+ _ASSERTE(!m_bSaveOptimized && "Cannot delete records after PreSave() and before Save().");
+
+ // Get the FieldMarshal record.
+ IfFailGo(m_pStgdb->m_MiniMd.FindFieldMarshalHelper(tk, &iFieldMarshRec));
+ if (InvalidRid(iFieldMarshRec))
+ {
+ hr = CLDB_E_RECORD_NOTFOUND;
+ goto ErrExit;
+ }
+ IfFailGo(m_pStgdb->m_MiniMd.GetFieldMarshalRecord(iFieldMarshRec, &pFieldMarshRec));
+ // Clear the parent token from the FieldMarshal record.
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_FieldMarshal,
+ FieldMarshalRec::COL_Parent, pFieldMarshRec, mdFieldDefNil));
+
+ // turn off the HasFieldMarshal
+ if (TypeFromToken(tk) == mdtFieldDef)
+ {
+ FieldRec *pFieldRec;
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetFieldRecord(RidFromToken(tk), &pFieldRec));
+ pFieldRec->RemoveFlags(fdHasFieldMarshal);
+ }
+ else // TypeFromToken(tk) == mdtParamDef
+ {
+ ParamRec *pParamRec;
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetParamRecord(RidFromToken(tk), &pParamRec));
+ pParamRec->RemoveFlags(pdHasFieldMarshal);
+ }
+
+ // Update the ENC log for the parent token.
+ IfFailGo(UpdateENCLog(tk));
+ // Create the log record for the non-token record.
+ IfFailGo(UpdateENCLog2(TBL_FieldMarshal, iFieldMarshRec));
+
+ErrExit:
+ STOP_MD_PERF(DeleteFieldMarshal);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#else //!FEATURE_METADATA_EMIT_ALL
+ return E_NOTIMPL;
+#endif //!FEATURE_METADATA_EMIT_ALL
+} // RegMeta::DeleteFieldMarshal
+
+//*****************************************************************************
+// Define a new permission set for an object.
+//*****************************************************************************
+STDMETHODIMP RegMeta::DefinePermissionSet(
+ mdToken tk, // [IN] the object to be decorated.
+ DWORD dwAction, // [IN] CorDeclSecurity.
+ void const *pvPermission, // [IN] permission blob.
+ ULONG cbPermission, // [IN] count of bytes of pvPermission.
+ mdPermission *ppm) // [OUT] returned permission token.
+{
+#ifdef FEATURE_METADATA_EMIT_ALL
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "MD RegMeta::DefinePermissionSet(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ tk, dwAction, pvPermission, cbPermission, ppm));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ IfFailGo(_DefinePermissionSet(tk, dwAction, pvPermission, cbPermission, ppm));
+
+ErrExit:
+ STOP_MD_PERF(DefinePermissionSet);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#else //!FEATURE_METADATA_EMIT_ALL
+ return E_NOTIMPL;
+#endif //!FEATURE_METADATA_EMIT_ALL
+} // RegMeta::DefinePermissionSet
+
+
+//*****************************************************************************
+// Define a new permission set for an object.
+//*****************************************************************************
+HRESULT RegMeta::_DefinePermissionSet(
+ mdToken tk, // [IN] the object to be decorated.
+ DWORD dwAction, // [IN] CorDeclSecurity.
+ void const *pvPermission, // [IN] permission blob.
+ ULONG cbPermission, // [IN] count of bytes of pvPermission.
+ mdPermission *ppm) // [OUT] returned permission token.
+{
+#ifdef FEATURE_METADATA_EMIT_ALL
+ HRESULT hr = S_OK;
+ DeclSecurityRec *pDeclSec = NULL;
+ RID iDeclSec;
+ short sAction = static_cast<short>(dwAction); // To match with the type in DeclSecurityRec.
+ mdPermission tkPerm; // New permission token.
+
+ _ASSERTE(TypeFromToken(tk) == mdtTypeDef || TypeFromToken(tk) == mdtMethodDef ||
+ TypeFromToken(tk) == mdtAssembly);
+
+ // Check for valid Action.
+ if (sAction == 0 || sAction > dclMaximumValue)
+ IfFailGo(E_INVALIDARG);
+
+ if (CheckDups(MDDupPermission))
+ {
+ hr = ImportHelper::FindPermission(&(m_pStgdb->m_MiniMd), tk, sAction, &tkPerm);
+
+ if (SUCCEEDED(hr))
+ {
+ // Set output parameter.
+ if (ppm)
+ *ppm = tkPerm;
+ if (IsENCOn())
+ IfFailGo(m_pStgdb->m_MiniMd.GetDeclSecurityRecord(RidFromToken(tkPerm), &pDeclSec));
+ else
+ {
+ hr = META_S_DUPLICATE;
+ goto ErrExit;
+ }
+ }
+ else if (hr != CLDB_E_RECORD_NOTFOUND)
+ IfFailGo(hr);
+ }
+
+ // Create a new record.
+ if (!pDeclSec)
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.AddDeclSecurityRecord(&pDeclSec, &iDeclSec));
+ tkPerm = TokenFromRid(iDeclSec, mdtPermission);
+
+ // Set output parameter.
+ if (ppm)
+ *ppm = tkPerm;
+
+ // Save parent and action information.
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_DeclSecurity, DeclSecurityRec::COL_Parent, pDeclSec, tk));
+ pDeclSec->SetAction(sAction);
+
+ // Turn on the internal security flag on the parent.
+ if (TypeFromToken(tk) == mdtTypeDef)
+ IfFailGo(_TurnInternalFlagsOn(tk, tdHasSecurity));
+ else if (TypeFromToken(tk) == mdtMethodDef)
+ IfFailGo(_TurnInternalFlagsOn(tk, mdHasSecurity));
+ IfFailGo(UpdateENCLog(tk));
+ }
+
+ IfFailGo(_SetPermissionSetProps(tkPerm, sAction, pvPermission, cbPermission));
+ IfFailGo(UpdateENCLog(tkPerm));
+ErrExit:
+
+ STOP_MD_PERF(DefinePermissionSet);
+ return hr;
+#else //!FEATURE_METADATA_EMIT_ALL
+ return E_NOTIMPL;
+#endif //!FEATURE_METADATA_EMIT_ALL
+} // RegMeta::_DefinePermissionSet
+
+
+
+//*****************************************************************************
+// Set the RVA of a methoddef
+//*****************************************************************************
+STDMETHODIMP RegMeta::SetRVA( // [IN] S_OK or error.
+ mdToken md, // [IN] Member for which to set offset
+ ULONG ulRVA) // [IN] The offset#endif
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "MD RegMeta::SetRVA(0x%08x, 0x%08x)\n",
+ md, ulRVA));
+ START_MD_PERF();
+
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+ IfFailGo(_SetRVA(md, ulRVA, ULONG_MAX)); // 0xbaad
+
+ErrExit:
+ STOP_MD_PERF(SetRVA);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::SetRVA
+
+//*****************************************************************************
+// Given a signature, return a token to the user. If there isn't an existing
+// token, create a new record. This should more appropriately be called
+// DefineSignature.
+//*****************************************************************************
+STDMETHODIMP RegMeta::GetTokenFromSig( // [IN] S_OK or error.
+ PCCOR_SIGNATURE pvSig, // [IN] Signature to define.
+ ULONG cbSig, // [IN] Size of signature data.
+ mdSignature *pmsig) // [OUT] returned signature token.
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "MD RegMeta::GetTokenFromSig(0x%08x, 0x%08x, 0x%08x)\n",
+ pvSig, cbSig, pmsig));
+ START_MD_PERF();
+
+ LOCKWRITE();
+
+ _ASSERTE(pmsig);
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+ IfFailGo(_GetTokenFromSig(pvSig, cbSig, pmsig));
+
+ErrExit:
+ STOP_MD_PERF(GetTokenFromSig);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::GetTokenFromSig
+
+//*****************************************************************************
+// Define and set a ModuleRef record.
+//*****************************************************************************
+STDMETHODIMP RegMeta::DefineModuleRef( // S_OK or error.
+ LPCWSTR szName, // [IN] DLL name
+ mdModuleRef *pmur) // [OUT] returned module ref token
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "MD RegMeta::DefineModuleRef(%S, 0x%08x)\n", MDSTR(szName), pmur));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ hr = _DefineModuleRef(szName, pmur);
+
+ErrExit:
+ STOP_MD_PERF(DefineModuleRef);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::DefineModuleRef
+
+HRESULT RegMeta::_DefineModuleRef( // S_OK or error.
+ LPCWSTR szName, // [IN] DLL name
+ mdModuleRef *pmur) // [OUT] returned module ref token
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+ ModuleRefRec *pModuleRef = 0; // The ModuleRef record.
+ RID iModuleRef; // Rid of new ModuleRef record.
+ LPUTF8 szUTF8Name;
+ UTF8STR((LPCWSTR)szName, szUTF8Name);
+
+ _ASSERTE(szName && pmur);
+
+ // See if the given ModuleRef already exists. If it exists just return.
+ // Else create a new record.
+ if (CheckDups(MDDupModuleRef))
+ {
+ hr = ImportHelper::FindModuleRef(&(m_pStgdb->m_MiniMd), szUTF8Name, pmur);
+ if (SUCCEEDED(hr))
+ {
+ if (IsENCOn())
+ IfFailGo(m_pStgdb->m_MiniMd.GetModuleRefRecord(RidFromToken(*pmur), &pModuleRef));
+ else
+ {
+ hr = META_S_DUPLICATE;
+ goto ErrExit;
+ }
+ }
+ else if (hr != CLDB_E_RECORD_NOTFOUND)
+ IfFailGo(hr);
+ }
+
+ if (!pModuleRef)
+ {
+ // Create new record and set the values.
+ IfFailGo(m_pStgdb->m_MiniMd.AddModuleRefRecord(&pModuleRef, &iModuleRef));
+
+ // Set the output parameter.
+ *pmur = TokenFromRid(iModuleRef, mdtModuleRef);
+ }
+
+ // Save the data.
+ IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_ModuleRef, ModuleRefRec::COL_Name,
+ pModuleRef, szUTF8Name));
+ IfFailGo(UpdateENCLog(*pmur));
+
+ErrExit:
+
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::_DefineModuleRef
+
+//*****************************************************************************
+// Set the parent for the specified MemberRef.
+//*****************************************************************************
+STDMETHODIMP RegMeta::SetParent( // S_OK or error.
+ mdMemberRef mr, // [IN] Token for the ref to be fixed up.
+ mdToken tk) // [IN] The ref parent.
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ MemberRefRec *pMemberRef;
+
+ LOG((LOGMD, "MD RegMeta::SetParent(0x%08x, 0x%08x)\n",
+ mr, tk));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ _ASSERTE(TypeFromToken(mr) == mdtMemberRef);
+ _ASSERTE(IsNilToken(tk) || TypeFromToken(tk) == mdtTypeRef || TypeFromToken(tk) == mdtTypeDef ||
+ TypeFromToken(tk) == mdtModuleRef || TypeFromToken(tk) == mdtMethodDef);
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetMemberRefRecord(RidFromToken(mr), &pMemberRef));
+
+ // If the token is nil set it to to m_tdModule.
+ tk = IsNilToken(tk) ? m_tdModule : tk;
+
+ // Set the parent.
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_MemberRef, MemberRefRec::COL_Class, pMemberRef, tk));
+
+ // Add the updated MemberRef to the hash.
+ IfFailGo(m_pStgdb->m_MiniMd.AddMemberRefToHash(mr) );
+
+ IfFailGo(UpdateENCLog(mr));
+
+ErrExit:
+
+ STOP_MD_PERF(SetParent);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::SetParent
+
+//*****************************************************************************
+// Define an TypeSpec token given a type description.
+//*****************************************************************************
+STDMETHODIMP RegMeta::GetTokenFromTypeSpec( // [IN] S_OK or error.
+ PCCOR_SIGNATURE pvSig, // [IN] Signature to define.
+ ULONG cbSig, // [IN] Size of signature data.
+ mdTypeSpec *ptypespec) // [OUT] returned signature token.
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ TypeSpecRec *pTypeSpecRec;
+ RID iRec;
+
+ LOG((LOGMD, "MD RegMeta::GetTokenFromTypeSpec(0x%08x, 0x%08x, 0x%08x)\n",
+ pvSig, cbSig, ptypespec));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ _ASSERTE(ptypespec);
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ if (CheckDups(MDDupTypeSpec))
+ {
+ hr = ImportHelper::FindTypeSpec(&(m_pStgdb->m_MiniMd), pvSig, cbSig, ptypespec);
+ if (SUCCEEDED(hr))
+ {
+ //@GENERICS: Generalizing from similar code in this file, should we not set
+ // hr = META_S_DUPLICATE;
+ // here?
+ goto ErrExit;
+ }
+ else if (hr != CLDB_E_RECORD_NOTFOUND)
+ IfFailGo(hr);
+ }
+
+ // Create a new record.
+ IfFailGo(m_pStgdb->m_MiniMd.AddTypeSpecRecord(&pTypeSpecRec, &iRec));
+
+ // Set output parameter.
+ *ptypespec = TokenFromRid(iRec, mdtTypeSpec);
+
+ // Set the signature field
+ IfFailGo(m_pStgdb->m_MiniMd.PutBlob(
+ TBL_TypeSpec,
+ TypeSpecRec::COL_Signature,
+ pTypeSpecRec,
+ pvSig,
+ cbSig));
+ IfFailGo(UpdateENCLog(*ptypespec));
+
+ErrExit:
+
+ STOP_MD_PERF(GetTokenFromTypeSpec);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::GetTokenFromTypeSpec
+
+//*****************************************************************************
+// This API defines a user literal string to be stored in the MetaData section.
+// The token for this string has embedded in it the offset into the BLOB pool
+// where the string is stored in UNICODE format. An additional byte is padded
+// at the end to indicate whether the string has any characters that are >= 0x80.
+//*****************************************************************************
+STDMETHODIMP RegMeta::DefineUserString( // S_OK or error.
+ LPCWSTR szString, // [IN] User literal string.
+ ULONG cchString, // [IN] Length of string.
+ mdString *pstk) // [OUT] String token.
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ UINT32 nIndex; // Index into the user string heap.
+ CQuickBytes qb; // For storing the string with the byte prefix.
+ ULONG i; // Loop counter.
+ BOOL bIs80Plus = false; // Is there an 80+ WCHAR.
+ ULONG ulMemSize; // Size of memory taken by the string passed in.
+ PBYTE pb; // Pointer into memory allocated by qb.
+ WCHAR c; // Temporary used during comparison;
+
+
+
+ LOG((LOGMD, "MD RegMeta::DefineUserString(0x%08x, 0x%08x, 0x%08x)\n",
+ szString, cchString, pstk));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ _ASSERTE(pstk && szString && cchString != ULONG_MAX);
+
+ //
+ // Walk the entire string looking for characters that would block us from doing
+ // a fast comparison of the string. These characters include anything greater than
+ // 0x80 or an apostrophe or a hyphen. Apostrophe and hyphen are excluded because
+ // they would prevent words like coop and co-op from sorting together in a culture-aware
+ // comparison. We also need to exclude some set of the control characters. This check
+ // is more restrictive
+ //
+ for (i=0; i<cchString; i++) {
+ c = szString[i];
+ if (c>=0x80 || HighCharHelper::IsHighChar((int)c)) {
+ bIs80Plus = true;
+ break;
+ }
+ }
+
+ // Copy over the string to memory.
+ ulMemSize = cchString * sizeof(WCHAR);
+ IfFailGo(qb.ReSizeNoThrow(ulMemSize + 1));
+ pb = reinterpret_cast<PBYTE>(qb.Ptr());
+ memcpy(pb, szString, ulMemSize);
+ SwapStringLength((WCHAR *) pb, cchString);
+ // Set the last byte of memory to indicate whether there is a 80+ character.
+ *(pb + ulMemSize) = bIs80Plus ? 1 : 0;
+
+ IfFailGo(m_pStgdb->m_MiniMd.PutUserString(
+ MetaData::DataBlob(pb, ulMemSize + 1),
+ &nIndex));
+
+ // Fail if the offset requires the high byte which is reserved for the token ID.
+ if (nIndex & 0xff000000)
+ IfFailGo(META_E_STRINGSPACE_FULL);
+ else
+ *pstk = TokenFromRid(nIndex, mdtString);
+
+ErrExit:
+ END_ENTRYPOINT_NOTHROW;
+
+ STOP_MD_PERF(DefineUserString);
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::DefineUserString
+
+//*****************************************************************************
+// Delete a token.
+// We only allow deleting a subset of tokens at this moment. These are TypeDef,
+// MethodDef, FieldDef, Event, Property, and CustomAttribute. Except
+// CustomAttribute, all the other tokens are named. We reserved a special
+// name COR_DELETED_NAME_A to indicating a named record is deleted when
+// xxRTSpecialName is set.
+//*****************************************************************************
+
+STDMETHODIMP RegMeta::DeleteToken(
+ mdToken tkObj) // [IN] The token to be deleted
+{
+#ifdef FEATURE_METADATA_EMIT_ALL
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "MD RegMeta::DeleteToken(0x%08x)\n", tkObj));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ if (!IsValidToken(tkObj))
+ IfFailGo( E_INVALIDARG );
+
+ // make sure that MetaData scope is opened for incremental compilation
+ if (!m_pStgdb->m_MiniMd.HasDelete())
+ {
+ _ASSERTE( !"You cannot call delete token when you did not open the scope with proper Update flags in the SetOption!");
+ IfFailGo( E_INVALIDARG );
+ }
+
+ _ASSERTE(!m_bSaveOptimized && "Cannot delete records after PreSave() and before Save().");
+
+ switch ( TypeFromToken(tkObj) )
+ {
+ case mdtTypeDef:
+ {
+ TypeDefRec *pRecord;
+ IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(tkObj), &pRecord));
+ IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_TypeDef, TypeDefRec::COL_Name, pRecord, COR_DELETED_NAME_A));
+ pRecord->AddFlags(tdSpecialName | tdRTSpecialName);
+ break;
+ }
+ case mdtMethodDef:
+ {
+ MethodRec *pRecord;
+ IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(tkObj), &pRecord));
+ IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_Method, MethodRec::COL_Name, pRecord, COR_DELETED_NAME_A));
+ pRecord->AddFlags(mdSpecialName | mdRTSpecialName);
+ break;
+ }
+ case mdtFieldDef:
+ {
+ FieldRec *pRecord;
+ IfFailGo(m_pStgdb->m_MiniMd.GetFieldRecord(RidFromToken(tkObj), &pRecord));
+ IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_Field, FieldRec::COL_Name, pRecord, COR_DELETED_NAME_A));
+ pRecord->AddFlags(fdSpecialName | fdRTSpecialName);
+ break;
+ }
+ case mdtEvent:
+ {
+ EventRec *pRecord;
+ IfFailGo(m_pStgdb->m_MiniMd.GetEventRecord(RidFromToken(tkObj), &pRecord));
+ IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_Event, EventRec::COL_Name, pRecord, COR_DELETED_NAME_A));
+ pRecord->AddEventFlags(evSpecialName | evRTSpecialName);
+ break;
+ }
+ case mdtProperty:
+ {
+ PropertyRec *pRecord;
+ IfFailGo(m_pStgdb->m_MiniMd.GetPropertyRecord(RidFromToken(tkObj), &pRecord));
+ IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_Property, PropertyRec::COL_Name, pRecord, COR_DELETED_NAME_A));
+ pRecord->AddPropFlags(prSpecialName | prRTSpecialName);
+ break;
+ }
+ case mdtExportedType:
+ {
+ ExportedTypeRec *pRecord;
+ IfFailGo(m_pStgdb->m_MiniMd.GetExportedTypeRecord(RidFromToken(tkObj), &pRecord));
+ IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_ExportedType, ExportedTypeRec::COL_TypeName, pRecord, COR_DELETED_NAME_A));
+ break;
+ }
+ case mdtCustomAttribute:
+ {
+ mdToken tkParent;
+ CustomAttributeRec *pRecord;
+ IfFailGo(m_pStgdb->m_MiniMd.GetCustomAttributeRecord(RidFromToken(tkObj), &pRecord));
+
+ // replace the parent column of the custom value record to a nil token.
+ tkParent = m_pStgdb->m_MiniMd.getParentOfCustomAttribute(pRecord);
+ tkParent = TokenFromRid( mdTokenNil, TypeFromToken(tkParent) );
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_CustomAttribute, CustomAttributeRec::COL_Parent, pRecord, tkParent));
+
+ // now the CustomAttribute table is no longer sorted
+ m_pStgdb->m_MiniMd.SetSorted(TBL_CustomAttribute, false);
+ break;
+ }
+ case mdtGenericParam:
+ {
+ mdToken tkParent;
+ GenericParamRec *pRecord;
+ IfFailGo(m_pStgdb->m_MiniMd.GetGenericParamRecord(RidFromToken(tkObj), &pRecord));
+
+ // replace the Parent column of the GenericParam record with a nil token.
+ tkParent = m_pStgdb->m_MiniMd.getOwnerOfGenericParam(pRecord);
+ tkParent = TokenFromRid( mdTokenNil, TypeFromToken(tkParent) );
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_GenericParam, GenericParamRec::COL_Owner,
+ pRecord, tkParent));
+
+ // now the GenericParam table is no longer sorted
+ m_pStgdb->m_MiniMd.SetSorted(TBL_GenericParam, false);
+ break;
+ }
+ case mdtGenericParamConstraint:
+ {
+ GenericParamConstraintRec *pRecord;
+ IfFailGo(m_pStgdb->m_MiniMd.GetGenericParamConstraintRecord(RidFromToken(tkObj), &pRecord));
+
+ // replace the Param column of the GenericParamConstraint record with zero RID.
+ IfFailGo(m_pStgdb->m_MiniMd.PutCol(TBL_GenericParamConstraint,
+ GenericParamConstraintRec::COL_Owner,pRecord, 0));
+ // now the GenericParamConstraint table is no longer sorted
+ m_pStgdb->m_MiniMd.SetSorted(TBL_GenericParamConstraint, false);
+ break;
+ }
+ case mdtPermission:
+ {
+ mdToken tkParent;
+ mdToken tkNil;
+ DeclSecurityRec *pRecord;
+ IfFailGo(m_pStgdb->m_MiniMd.GetDeclSecurityRecord(RidFromToken(tkObj), &pRecord));
+
+ // Replace the parent column of the permission record with a nil tokne.
+ tkParent = m_pStgdb->m_MiniMd.getParentOfDeclSecurity(pRecord);
+ tkNil = TokenFromRid( mdTokenNil, TypeFromToken(tkParent) );
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_DeclSecurity, DeclSecurityRec::COL_Parent, pRecord, tkNil ));
+
+ // The table is no longer sorted.
+ m_pStgdb->m_MiniMd.SetSorted(TBL_DeclSecurity, false);
+
+ // If the parent has no more security attributes, turn off the "has security" bit.
+ HCORENUM hEnum = 0;
+ mdPermission rPerms[1];
+ ULONG cPerms = 0;
+ EnumPermissionSets(&hEnum, tkParent, 0 /* all actions */, rPerms, 1, &cPerms);
+ CloseEnum(hEnum);
+ if (cPerms == 0)
+ {
+ void *pRow;
+ ULONG ixTbl;
+ // Get the row for the parent object.
+ ixTbl = m_pStgdb->m_MiniMd.GetTblForToken(tkParent);
+ _ASSERTE(ixTbl >= 0 && ixTbl <= m_pStgdb->m_MiniMd.GetCountTables());
+ IfFailGo(m_pStgdb->m_MiniMd.getRow(ixTbl, RidFromToken(tkParent), &pRow));
+
+ switch (TypeFromToken(tkParent))
+ {
+ case mdtTypeDef:
+ reinterpret_cast<TypeDefRec*>(pRow)->RemoveFlags(tdHasSecurity);
+ break;
+ case mdtMethodDef:
+ reinterpret_cast<MethodRec*>(pRow)->RemoveFlags(mdHasSecurity);
+ break;
+ case mdtAssembly:
+ // No security bit.
+ break;
+ }
+ }
+ break;
+ }
+ default:
+ _ASSERTE(!"Bad token type!");
+ IfFailGo( E_INVALIDARG );
+ break;
+ }
+
+ ErrExit:
+
+ STOP_MD_PERF(DeleteToken);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+#else //!FEATURE_METADATA_EMIT_ALL
+ return E_NOTIMPL;
+#endif //!FEATURE_METADATA_EMIT_ALL
+} // RegMeta::DeleteToken
+
+//*****************************************************************************
+// Set the properties on the given TypeDef token.
+//*****************************************************************************
+STDMETHODIMP RegMeta::SetTypeDefProps( // S_OK or error.
+ mdTypeDef td, // [IN] The TypeDef.
+ DWORD dwTypeDefFlags, // [IN] TypeDef flags.
+ mdToken tkExtends, // [IN] Base TypeDef or TypeRef.
+ mdToken rtkImplements[]) // [IN] Implemented interfaces.
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "RegMeta::SetTypeDefProps(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ td, dwTypeDefFlags, tkExtends, rtkImplements));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ hr = _SetTypeDefProps(td, dwTypeDefFlags, tkExtends, rtkImplements);
+
+ErrExit:
+
+ STOP_MD_PERF(SetTypeDefProps);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::SetTypeDefProps
+
+
+//*****************************************************************************
+// Define a Nested Type.
+//*****************************************************************************
+STDMETHODIMP RegMeta::DefineNestedType( // S_OK or error.
+ LPCWSTR szTypeDef, // [IN] Name of TypeDef
+ DWORD dwTypeDefFlags, // [IN] CustomAttribute flags
+ mdToken tkExtends, // [IN] extends this TypeDef or typeref
+ mdToken rtkImplements[], // [IN] Implements interfaces
+ mdTypeDef tdEncloser, // [IN] TypeDef token of the enclosing type.
+ mdTypeDef *ptd) // [OUT] Put TypeDef token here
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "RegMeta::DefineNestedType(%S, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ MDSTR(szTypeDef), dwTypeDefFlags, tkExtends,
+ rtkImplements, tdEncloser, ptd));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ _ASSERTE(TypeFromToken(tdEncloser) == mdtTypeDef && !IsNilToken(tdEncloser));
+ _ASSERTE(IsTdNested(dwTypeDefFlags));
+
+ IfFailGo(_DefineTypeDef(szTypeDef, dwTypeDefFlags,
+ tkExtends, rtkImplements, tdEncloser, ptd));
+
+ErrExit:
+ STOP_MD_PERF(DefineNestedType);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::DefineNestedType
+
+//*****************************************************************************
+// Define a formal type parameter for the given TypeDef or MethodDef token.
+//*****************************************************************************
+STDMETHODIMP RegMeta::DefineGenericParam( // S_OK or error.
+ mdToken tkOwner, // [IN] TypeDef or MethodDef
+ ULONG ulParamSeq, // [IN] Index of the type parameter
+ DWORD dwParamFlags, // [IN] Flags, for future use (e.g. variance)
+ LPCWSTR szName, // [IN] Name
+ DWORD reserved, // [IN] For future use
+ mdToken rtkConstraints[], // [IN] Array of type constraints (TypeDef,TypeRef,TypeSpec)
+ mdGenericParam *pgp) // [OUT] Put GenericParam token here
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ mdToken tkRet = mdGenericParamNil;
+ mdToken tkOwnerType = TypeFromToken(tkOwner);
+
+ LOG((LOGMD, "RegMeta::DefineGenericParam(0x%08x, %d, 0x%08x, %S, 0x%08x, 0x%08x, 0x%08x)\n",
+ tkOwner, ulParamSeq, dwParamFlags, szName, reserved, rtkConstraints, pgp));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ if (reserved != 0)
+ IfFailGo(META_E_BAD_INPUT_PARAMETER);
+
+ // See if this version of the metadata can do Generics
+ if (!m_pStgdb->m_MiniMd.SupportsGenerics())
+ IfFailGo(CLDB_E_INCOMPATIBLE);
+
+ if ((tkOwnerType == mdtTypeDef) || (tkOwnerType == mdtMethodDef))
+ {
+ // 1. Find/create GP (unique tkOwner+ulParamSeq) = tkRet
+ GenericParamRec *pGenericParam = NULL;
+ RID iGenericParam,rid;
+ RID ridStart;
+ RID ridEnd;
+
+ // See if this GenericParam has already been defined.
+ if (CheckDups(MDDupGenericParam))
+ {
+ // Enumerate any GenericParams for the parent, looking for this sequence number.
+ IfFailGo(m_pStgdb->m_MiniMd.GetGenericParamsForToken(tkOwner, &ridStart, &ridEnd));
+ for (rid = ridStart; rid < ridEnd; rid++)
+ {
+ iGenericParam = m_pStgdb->m_MiniMd.GetGenericParamRid(rid);
+ IfFailGo(m_pStgdb->m_MiniMd.GetGenericParamRecord(iGenericParam, &pGenericParam));
+ // Is this the desired GenericParam #?
+ if (pGenericParam->GetNumber() == (USHORT)ulParamSeq)
+ {
+ tkRet = TokenFromRid(iGenericParam,mdtGenericParam);
+ // This is a duplicate. If not ENC, just return 'DUPLICATE'. If ENC, overwrite.
+ if (!IsENCOn())
+ {
+ IfFailGo(META_S_DUPLICATE);
+ }
+ break;
+ }
+ }
+ }
+ else
+ { // Clear rid, ridStart, ridEnd, so we no we didn't find one.
+ rid = ridStart = ridEnd = 0;
+ }
+
+ // If none was found, create one.
+ if(rid >= ridEnd)
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.AddGenericParamRecord(&pGenericParam, &iGenericParam));
+ pGenericParam->SetNumber((USHORT)ulParamSeq);
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_GenericParam, GenericParamRec::COL_Owner,
+ pGenericParam, tkOwner));
+ tkRet = TokenFromRid(iGenericParam,mdtGenericParam);
+ }
+
+ // 2. Set its props
+ IfFailGo(_SetGenericParamProps(tkRet, pGenericParam, dwParamFlags, szName, reserved ,rtkConstraints));
+ IfFailGo(UpdateENCLog(tkRet));
+ }
+ else
+ hr = META_E_BAD_INPUT_PARAMETER;
+
+ErrExit:
+
+ if(pgp != NULL)
+ *pgp = tkRet;
+ STOP_MD_PERF(DefineGenericParam);
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::DefineGenericParam
+
+//*****************************************************************************
+// Set props of a formal type parameter.
+//*****************************************************************************
+STDMETHODIMP RegMeta::SetGenericParamProps( // S_OK or error.
+ mdGenericParam gp, // [IN] GenericParam
+ DWORD dwParamFlags, // [IN] Flags, for future use (e.g. variance)
+ LPCWSTR szName, // [IN] Optional name
+ DWORD reserved, // [IN] For future use (e.g. non-type parameters)
+ mdToken rtkConstraints[]) // [IN] Array of type constraints (TypeDef,TypeRef,TypeSpec)
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "RegMeta::SetGenericParamProps(0x%08x, 0x%08x, %S, 0x%08x, 0x%08x, 0x%08x)\n",
+ gp, dwParamFlags,szName,reserved,rtkConstraints));
+ START_MD_PERF();
+
+ if (reserved != 0)
+ IfFailGo(META_E_BAD_INPUT_PARAMETER);
+
+ // See if this version of the metadata can do Generics
+ if (!m_pStgdb->m_MiniMd.SupportsGenerics())
+ IfFailGo(CLDB_E_INCOMPATIBLE);
+
+ if (TypeFromToken(gp) == mdtGenericParam)
+ {
+ GenericParamRec *pGenericParam;
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetGenericParamRecord(RidFromToken(gp), &pGenericParam));
+ IfFailGo(_SetGenericParamProps(gp,pGenericParam,dwParamFlags,szName,reserved,rtkConstraints));
+ IfFailGo(UpdateENCLog(gp));
+ }
+ else
+ hr = META_E_BAD_INPUT_PARAMETER;
+
+ErrExit:
+ STOP_MD_PERF(SetGenericParamProps);
+
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::SetGenericParamProps
+
+//*****************************************************************************
+// Set props of a formal type parameter (internal).
+//*****************************************************************************
+HRESULT RegMeta::_SetGenericParamProps( // S_OK or error.
+ mdGenericParam tkGP, // [IN] Formal parameter token
+ GenericParamRec *pGenericParam, // [IN] GenericParam record ptr
+ DWORD dwParamFlags, // [IN] Flags, for future use (e.g. variance)
+ LPCWSTR szName, // [IN] Optional name
+ DWORD reserved, // [IN] For future use (e.g. non-type parameters)
+ mdToken rtkConstraints[]) // [IN] Array of type constraints (TypeDef,TypeRef,TypeSpec)
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ if (pGenericParam != NULL)
+ {
+ // If there is a name, set it.
+ if ((szName != NULL) && (*szName != 0))
+ IfFailGo(m_pStgdb->m_MiniMd.PutStringW(TBL_GenericParam, GenericParamRec::COL_Name,
+ pGenericParam, szName));
+
+ // If there are new flags, set them.
+ if (dwParamFlags != (DWORD) -1)
+ pGenericParam->SetFlags((USHORT)dwParamFlags);
+
+ // If there is a new array of constraints, apply it.
+ if (rtkConstraints != NULL)
+ {
+ //Clear existing constraints
+ GenericParamConstraintRec* pGPCRec;
+ RID ridGPC;
+ RID rid;
+ RID ridStart;
+ RID ridEnd;
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetGenericParamConstraintsForToken(tkGP, &ridStart, &ridEnd));
+ for (rid = ridStart; rid < ridEnd; rid++)
+ {
+ ridGPC = m_pStgdb->m_MiniMd.GetGenericParamConstraintRid(rid);
+ IfFailGo(m_pStgdb->m_MiniMd.GetGenericParamConstraintRecord(ridGPC, &pGPCRec));
+ IfFailGo(m_pStgdb->m_MiniMd.PutCol(TBL_GenericParamConstraint,
+ GenericParamConstraintRec::COL_Owner,
+ pGPCRec, 0));
+ IfFailGo(UpdateENCLog(TokenFromRid(ridGPC,mdtGenericParamConstraint)));
+ }
+
+ //Emit new constraints
+ mdToken* ptk;
+ for (ptk = rtkConstraints; (ptk != NULL)&&(RidFromToken(*ptk)!=0); ptk++)
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.AddGenericParamConstraintRecord(&pGPCRec, &ridGPC));
+ IfFailGo(m_pStgdb->m_MiniMd.PutCol(TBL_GenericParamConstraint,
+ GenericParamConstraintRec::COL_Owner,
+ pGPCRec, RidFromToken(tkGP)));
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_GenericParamConstraint,
+ GenericParamConstraintRec::COL_Constraint,
+ pGPCRec, *ptk));
+ IfFailGo(UpdateENCLog(TokenFromRid(ridGPC,mdtGenericParamConstraint)));
+ }
+ }
+ }
+ else
+ hr = META_E_BAD_INPUT_PARAMETER;
+
+ErrExit:
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::_SetGenericParamProps
+
+//*****************************************************************************
+// Create and set a MethodSpec record.
+//*****************************************************************************
+STDMETHODIMP RegMeta::DefineMethodSpec( // S_OK or error
+ mdToken tkImport, // [IN] MethodDef or MemberRef
+ PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of COM+ signature
+ ULONG cbSigBlob, // [IN] count of bytes in the signature blob
+ mdMethodSpec *pmi) // [OUT] method instantiation token
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ MethodSpecRec *pRecord = 0; // The MethodSpec record.
+ RID iRecord; // RID of new MethodSpec record.
+
+
+ LOG((LOGMD, "MD RegMeta::DefineMethodSpec(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ tkImport, pvSigBlob, cbSigBlob, pmi));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ // See if this version of the metadata can do Generics
+ if (!m_pStgdb->m_MiniMd.SupportsGenerics())
+ IfFailGo(CLDB_E_INCOMPATIBLE);
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ // Check that it is a method, or at least memberref.
+ if ((TypeFromToken(tkImport) != mdtMethodDef) && (TypeFromToken(tkImport) != mdtMemberRef))
+ IfFailGo(META_E_BAD_INPUT_PARAMETER);
+
+ // Must have a signature, and someplace to return the token.
+ if ((pvSigBlob == NULL) || (cbSigBlob == 0) || (pmi == NULL))
+ IfFailGo(META_E_BAD_INPUT_PARAMETER);
+
+ // If the MethodSpec already exists, just return the token, else
+ // create a new record.
+ if (CheckDups(MDDupMethodSpec))
+ {
+ hr = ImportHelper::FindMethodSpecByMethodAndInstantiation(&(m_pStgdb->m_MiniMd), tkImport,pvSigBlob, cbSigBlob, pmi);
+ if (SUCCEEDED(hr))
+ {
+ if (IsENCOn()) //GENERICS: is this correct? Do we really want to support ENC of MethodSpecs?
+ IfFailGo(m_pStgdb->m_MiniMd.GetMethodSpecRecord(RidFromToken(*pmi), &pRecord));
+ else
+ {
+ hr = META_S_DUPLICATE;
+ goto ErrExit;
+ }
+ }
+ else if (hr != CLDB_E_RECORD_NOTFOUND) // MemberRef exists
+ IfFailGo(hr);
+ }
+
+
+ if (!pRecord)
+ { // Create the record.
+ IfFailGo(m_pStgdb->m_MiniMd.AddMethodSpecRecord(&pRecord, &iRecord));
+
+ /*GENERICS: do we need to do anything like this?
+ Probably not, since SetMemberDefDirty is for ref to def optimization, and there are no method spec "refs".
+ // record the more defs are introduced.
+ SetMemberDefDirty(true);
+ */
+
+ // Give token to caller.
+ *pmi = TokenFromRid(iRecord, mdtMethodSpec);
+ }
+
+ // Save row data.
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_MethodSpec, MethodSpecRec::COL_Method, pRecord, tkImport));
+ IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_MethodSpec, MethodSpecRec::COL_Instantiation, pRecord,
+ pvSigBlob, cbSigBlob));
+ /*@GENERICS: todo: update MethodSpec hash table */
+ /* IfFailGo(m_pStgdb->m_MiniMd.AddMemberRefToHash(*pmi) ); */
+
+ IfFailGo(UpdateENCLog(*pmi));
+
+ErrExit:
+
+ STOP_MD_PERF(DefineMethodSpec);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::DefineMethodSpec
+
+//*****************************************************************************
+// Set the properties on the given Method token.
+//*****************************************************************************
+STDMETHODIMP RegMeta::SetMethodProps( // S_OK or error.
+ mdMethodDef md, // [IN] The MethodDef.
+ DWORD dwMethodFlags, // [IN] Method attributes.
+ ULONG ulCodeRVA, // [IN] Code RVA.
+ DWORD dwImplFlags) // [IN] MethodImpl flags.
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "RegMeta::SetMethodProps(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ md, dwMethodFlags, ulCodeRVA, dwImplFlags));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ if (dwMethodFlags != ULONG_MAX)
+ {
+ // Make sure no one sets the reserved bits on the way in.
+ _ASSERTE((dwMethodFlags & (mdReservedMask&~mdRTSpecialName)) == 0);
+ dwMethodFlags &= (~mdReservedMask);
+ }
+
+ hr = _SetMethodProps(md, dwMethodFlags, ulCodeRVA, dwImplFlags);
+
+ErrExit:
+
+ STOP_MD_PERF(SetMethodProps);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::SetMethodProps
+
+//*****************************************************************************
+// Set the properties on the given Event token.
+//*****************************************************************************
+STDMETHODIMP RegMeta::SetEventProps( // S_OK or error.
+ mdEvent ev, // [IN] The event token.
+ DWORD dwEventFlags, // [IN] CorEventAttr.
+ mdToken tkEventType, // [IN] A reference (mdTypeRef or mdTypeRef) to the Event class.
+ mdMethodDef mdAddOn, // [IN] Add method.
+ mdMethodDef mdRemoveOn, // [IN] Remove method.
+ mdMethodDef mdFire, // [IN] Fire method.
+ mdMethodDef rmdOtherMethods[]) // [IN] Array of other methods associate with the event.
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "MD RegMeta::SetEventProps(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ ev, dwEventFlags, tkEventType, mdAddOn, mdRemoveOn, mdFire, rmdOtherMethods));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ IfFailGo(_SetEventProps1(ev, dwEventFlags, tkEventType));
+ IfFailGo(_SetEventProps2(ev, mdAddOn, mdRemoveOn, mdFire, rmdOtherMethods, true));
+
+ErrExit:
+
+ STOP_MD_PERF(SetEventProps);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::SetEventProps
+
+//*****************************************************************************
+// Set the properties on the given Permission token.
+//*****************************************************************************
+STDMETHODIMP RegMeta::SetPermissionSetProps( // S_OK or error.
+ mdToken tk, // [IN] The object to be decorated.
+ DWORD dwAction, // [IN] CorDeclSecurity.
+ void const *pvPermission, // [IN] Permission blob.
+ ULONG cbPermission, // [IN] Count of bytes of pvPermission.
+ mdPermission *ppm) // [OUT] Permission token.
+{
+#ifdef FEATURE_METADATA_EMIT_ALL
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ USHORT sAction = static_cast<USHORT>(dwAction); // Corresponding DeclSec field is a USHORT.
+ mdPermission tkPerm;
+
+ LOG((LOGMD, "MD RegMeta::SetPermissionSetProps(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ tk, dwAction, pvPermission, cbPermission, ppm));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ _ASSERTE(TypeFromToken(tk) == mdtTypeDef || TypeFromToken(tk) == mdtMethodDef ||
+ TypeFromToken(tk) == mdtAssembly);
+
+ // Check for valid Action.
+ if (dwAction == ULONG_MAX || dwAction == 0 || dwAction > dclMaximumValue)
+ IfFailGo(E_INVALIDARG);
+
+ IfFailGo(ImportHelper::FindPermission(&(m_pStgdb->m_MiniMd), tk, sAction, &tkPerm));
+ if (ppm)
+ *ppm = tkPerm;
+ IfFailGo(_SetPermissionSetProps(tkPerm, dwAction, pvPermission, cbPermission));
+ErrExit:
+
+ STOP_MD_PERF(SetPermissionSetProps);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#else //!FEATURE_METADATA_EMIT_ALL
+ return E_NOTIMPL;
+#endif //!FEATURE_METADATA_EMIT_ALL
+} // RegMeta::SetPermissionSetProps
+
+//*****************************************************************************
+// This routine sets the p-invoke information for the specified Field or Method.
+//*****************************************************************************
+STDMETHODIMP RegMeta::DefinePinvokeMap( // Return code.
+ mdToken tk, // [IN] FieldDef or MethodDef.
+ DWORD dwMappingFlags, // [IN] Flags used for mapping.
+ LPCWSTR szImportName, // [IN] Import name.
+ mdModuleRef mrImportDLL) // [IN] ModuleRef token for the target DLL.
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "MD RegMeta::DefinePinvokeMap(0x%08x, 0x%08x, %S, 0x%08x)\n",
+ tk, dwMappingFlags, MDSTR(szImportName), mrImportDLL));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ hr = _DefinePinvokeMap(tk, dwMappingFlags, szImportName, mrImportDLL);
+
+ErrExit:
+
+ STOP_MD_PERF(DefinePinvokeMap);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::DefinePinvokeMap
+
+//*****************************************************************************
+// Internal worker function for setting p-invoke info.
+//*****************************************************************************
+HRESULT RegMeta::_DefinePinvokeMap( // Return hresult.
+ mdToken tk, // [IN] FieldDef or MethodDef.
+ DWORD dwMappingFlags, // [IN] Flags used for mapping.
+ LPCWSTR szImportName, // [IN] Import name.
+ mdModuleRef mrImportDLL) // [IN] ModuleRef token for the target DLL.
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ ImplMapRec *pRecord;
+ ULONG iRecord;
+ bool bDupFound = false;
+ HRESULT hr = S_OK;
+
+ _ASSERTE(TypeFromToken(tk) == mdtFieldDef || TypeFromToken(tk) == mdtMethodDef);
+ _ASSERTE(TypeFromToken(mrImportDLL) == mdtModuleRef);
+ _ASSERTE(RidFromToken(tk) && RidFromToken(mrImportDLL) && szImportName);
+
+ // Turn on the quick lookup flag.
+ if (TypeFromToken(tk) == mdtMethodDef)
+ {
+ if (CheckDups(MDDupMethodDef))
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.FindImplMapHelper(tk, &iRecord));
+ if (! InvalidRid(iRecord))
+ bDupFound = true;
+ }
+ MethodRec *pMethod;
+ IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(tk), &pMethod));
+ pMethod->AddFlags(mdPinvokeImpl);
+ }
+ else // TypeFromToken(tk) == mdtFieldDef
+ {
+ if (CheckDups(MDDupFieldDef))
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.FindImplMapHelper(tk, &iRecord));
+ if (!InvalidRid(iRecord))
+ bDupFound = true;
+ }
+ FieldRec *pField;
+ IfFailGo(m_pStgdb->m_MiniMd.GetFieldRecord(RidFromToken(tk), &pField));
+ pField->AddFlags(fdPinvokeImpl);
+ }
+
+ // Create a new record.
+ if (bDupFound)
+ {
+ if (IsENCOn())
+ IfFailGo(m_pStgdb->m_MiniMd.GetImplMapRecord(RidFromToken(iRecord), &pRecord));
+ else
+ {
+ hr = META_S_DUPLICATE;
+ goto ErrExit;
+ }
+ }
+ else
+ {
+ IfFailGo(UpdateENCLog(tk));
+ IfFailGo(m_pStgdb->m_MiniMd.AddImplMapRecord(&pRecord, &iRecord));
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_ImplMap,
+ ImplMapRec::COL_MemberForwarded, pRecord, tk));
+ IfFailGo( m_pStgdb->m_MiniMd.AddImplMapToHash(iRecord) );
+
+ }
+
+ // If no module, create a dummy, empty module.
+ if (IsNilToken(mrImportDLL))
+ {
+ hr = ImportHelper::FindModuleRef(&m_pStgdb->m_MiniMd, "", &mrImportDLL);
+ if (hr == CLDB_E_RECORD_NOTFOUND)
+ IfFailGo(_DefineModuleRef(W(""), &mrImportDLL));
+ }
+
+ // Set the data.
+ if (dwMappingFlags != ULONG_MAX)
+ pRecord->SetMappingFlags(static_cast<USHORT>(dwMappingFlags));
+ IfFailGo(m_pStgdb->m_MiniMd.PutStringW(TBL_ImplMap, ImplMapRec::COL_ImportName,
+ pRecord, szImportName));
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_ImplMap,
+ ImplMapRec::COL_ImportScope, pRecord, mrImportDLL));
+
+ IfFailGo(UpdateENCLog2(TBL_ImplMap, iRecord));
+
+ErrExit:
+
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::DefinePinvokeMap
+
+//*****************************************************************************
+// This routine sets the p-invoke information for the specified Field or Method.
+//*****************************************************************************
+STDMETHODIMP RegMeta::SetPinvokeMap( // Return code.
+ mdToken tk, // [IN] FieldDef or MethodDef.
+ DWORD dwMappingFlags, // [IN] Flags used for mapping.
+ LPCWSTR szImportName, // [IN] Import name.
+ mdModuleRef mrImportDLL) // [IN] ModuleRef token for the target DLL.
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ ImplMapRec *pRecord;
+ ULONG iRecord;
+
+ LOG((LOGMD, "MD RegMeta::SetPinvokeMap(0x%08x, 0x%08x, %S, 0x%08x)\n",
+ tk, dwMappingFlags, MDSTR(szImportName), mrImportDLL));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ _ASSERTE(TypeFromToken(tk) == mdtFieldDef || TypeFromToken(tk) == mdtMethodDef);
+ _ASSERTE(RidFromToken(tk));
+
+ IfFailGo(m_pStgdb->m_MiniMd.FindImplMapHelper(tk, &iRecord));
+
+ if (InvalidRid(iRecord))
+ IfFailGo(CLDB_E_RECORD_NOTFOUND);
+ else
+ IfFailGo(m_pStgdb->m_MiniMd.GetImplMapRecord(iRecord, &pRecord));
+
+ // Set the data.
+ if (dwMappingFlags != ULONG_MAX)
+ pRecord->SetMappingFlags(static_cast<USHORT>(dwMappingFlags));
+ if (szImportName)
+ IfFailGo(m_pStgdb->m_MiniMd.PutStringW(TBL_ImplMap, ImplMapRec::COL_ImportName,
+ pRecord, szImportName));
+ if (! IsNilToken(mrImportDLL))
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_ImplMap, ImplMapRec::COL_ImportScope,
+ pRecord, mrImportDLL));
+
+ IfFailGo(UpdateENCLog2(TBL_ImplMap, iRecord));
+
+ErrExit:
+
+ STOP_MD_PERF(SetPinvokeMap);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::SetPinvokeMap
+
+//*****************************************************************************
+// This routine deletes the p-invoke record for the specified Field or Method.
+//*****************************************************************************
+STDMETHODIMP RegMeta::DeletePinvokeMap( // Return code.
+ mdToken tk) // [IN]FieldDef or MethodDef.
+{
+#ifdef FEATURE_METADATA_EMIT_ALL
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ ImplMapRec *pRecord;
+ RID iRecord;
+
+ LOG((LOGMD, "MD RegMeta::DeletePinvokeMap(0x%08x)\n", tk));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ _ASSERTE(TypeFromToken(tk) == mdtFieldDef || TypeFromToken(tk) == mdtMethodDef);
+ _ASSERTE(!IsNilToken(tk));
+ _ASSERTE(!m_bSaveOptimized && "Cannot delete records after PreSave() and before Save().");
+
+ // Get the PinvokeMap record.
+ IfFailGo(m_pStgdb->m_MiniMd.FindImplMapHelper(tk, &iRecord));
+ if (InvalidRid(iRecord))
+ {
+ IfFailGo(CLDB_E_RECORD_NOTFOUND);
+ }
+ IfFailGo(m_pStgdb->m_MiniMd.GetImplMapRecord(iRecord, &pRecord));
+
+ // Clear the MemberForwarded token from the PinvokeMap record.
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_ImplMap,
+ ImplMapRec::COL_MemberForwarded, pRecord, mdFieldDefNil));
+
+ // turn off the PinvokeImpl bit.
+ if (TypeFromToken(tk) == mdtFieldDef)
+ {
+ FieldRec *pFieldRec;
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetFieldRecord(RidFromToken(tk), &pFieldRec));
+ pFieldRec->RemoveFlags(fdPinvokeImpl);
+ }
+ else // TypeFromToken(tk) == mdtMethodDef
+ {
+ MethodRec *pMethodRec;
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(tk), &pMethodRec));
+ pMethodRec->RemoveFlags(mdPinvokeImpl);
+ }
+
+ // Update the ENC log for the parent token.
+ IfFailGo(UpdateENCLog(tk));
+ // Create the log record for the non-token record.
+ IfFailGo(UpdateENCLog2(TBL_ImplMap, iRecord));
+
+ErrExit:
+ STOP_MD_PERF(DeletePinvokeMap);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#else //!FEATURE_METADATA_EMIT_ALL
+ return E_NOTIMPL;
+#endif //!FEATURE_METADATA_EMIT_ALL
+} // RegMeta::DeletePinvokeMap
+
+//*****************************************************************************
+// Create and define a new FieldDef record.
+//*****************************************************************************
+HRESULT RegMeta::DefineField( // S_OK or error.
+ mdTypeDef td, // Parent TypeDef
+ LPCWSTR szName, // Name of member
+ DWORD dwFieldFlags, // Member attributes
+ PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of COM+ signature
+ ULONG cbSigBlob, // [IN] count of bytes in the signature blob
+ DWORD dwCPlusTypeFlag, // [IN] flag for value type. selected ELEMENT_TYPE_*
+ void const *pValue, // [IN] constant value
+ ULONG cchValue, // [IN] size of constant value (string, in wide chars).
+ mdFieldDef *pmd) // [OUT] Put member token here
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ FieldRec *pRecord = NULL; // The new record.
+ RID iRecord; // RID of new record.
+ LPUTF8 szNameUtf8;
+ UTF8STR(szName, szNameUtf8);
+
+ LOG((LOGMD, "MD: RegMeta::DefineField(0x%08x, %S, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ td, MDSTR(szName), dwFieldFlags, pvSigBlob, cbSigBlob, dwCPlusTypeFlag, pValue, cchValue, pmd));
+
+ START_MD_PERF();
+ LOCKWRITE();
+
+ _ASSERTE(pmd);
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+ IsGlobalMethodParent(&td);
+
+ // Validate flags.
+ if (dwFieldFlags != ULONG_MAX)
+ {
+ // fdHasFieldRVA is settable, but not re-settable by applications.
+ _ASSERTE((dwFieldFlags & (fdReservedMask&~(fdHasFieldRVA|fdRTSpecialName))) == 0);
+ dwFieldFlags &= ~(fdReservedMask&~fdHasFieldRVA);
+ }
+
+ // See if this field has already been defined as a forward reference
+ // from a MemberRef. If so, then update the data to match what we know now.
+ if (CheckDups(MDDupFieldDef))
+ {
+
+ hr = ImportHelper::FindField(&(m_pStgdb->m_MiniMd),
+ td,
+ szNameUtf8,
+ pvSigBlob,
+ cbSigBlob,
+ pmd);
+ if (SUCCEEDED(hr))
+ {
+ if (IsENCOn())
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.GetFieldRecord(RidFromToken(*pmd), &pRecord));
+ }
+ else
+ {
+ hr = META_S_DUPLICATE;
+ goto ErrExit;
+ }
+ }
+ else if (hr != CLDB_E_RECORD_NOTFOUND)
+ {
+ IfFailGo(hr);
+ }
+ }
+
+ // Create a new record.
+ if (pRecord == NULL)
+ {
+ // Create the field record.
+ IfFailGo(m_pStgdb->m_MiniMd.AddFieldRecord(&pRecord, &iRecord));
+
+ // Set output parameter pmd.
+ *pmd = TokenFromRid(iRecord, mdtFieldDef);
+
+ // Add to parent's list of child records.
+ IfFailGo(m_pStgdb->m_MiniMd.AddFieldToTypeDef(RidFromToken(td), iRecord));
+
+ IfFailGo(UpdateENCLog(td, CMiniMdRW::eDeltaFieldCreate));
+
+ // record the more defs are introduced.
+ SetMemberDefDirty(true);
+ }
+
+ // Set the Field properties.
+ IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_Field, FieldRec::COL_Name, pRecord, szNameUtf8));
+ IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_Field, FieldRec::COL_Signature, pRecord,
+ pvSigBlob, cbSigBlob));
+
+ // Check to see if it is value__ for enum type
+ // <TODO>@FUTURE: shouldn't we have checked the type containing the field to be a Enum type first of all?</TODO>
+ // value__ is defined in corhdr.h. However, corhdr.h does not have the
+ // the W() macro we need (since it's distributed to windows). We substitute the values of the
+ // macro in the code below to work around this issue.
+ // #define COR_ENUM_FIELD_NAME_W L"value__"
+
+ if (!wcscmp(szName, W("value__")))
+ {
+ dwFieldFlags |= fdRTSpecialName | fdSpecialName;
+ }
+ SetCallerDefine();
+ IfFailGo(_SetFieldProps(*pmd, dwFieldFlags, dwCPlusTypeFlag, pValue, cchValue));
+ IfFailGo(m_pStgdb->m_MiniMd.AddMemberDefToHash(*pmd, td) );
+
+ErrExit:
+ SetCallerExternal();
+
+ STOP_MD_PERF(DefineField);
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::DefineField
+
+//*****************************************************************************
+// Define and set a Property record.
+//*****************************************************************************
+HRESULT RegMeta::DefineProperty(
+ mdTypeDef td, // [IN] the class/interface on which the property is being defined
+ LPCWSTR szProperty, // [IN] Name of the property
+ DWORD dwPropFlags, // [IN] CorPropertyAttr
+ PCCOR_SIGNATURE pvSig, // [IN] the required type signature
+ ULONG cbSig, // [IN] the size of the type signature blob
+ DWORD dwCPlusTypeFlag, // [IN] flag for value type. selected ELEMENT_TYPE_*
+ void const *pValue, // [IN] constant value
+ ULONG cchValue, // [IN] size of constant value (string, in wide chars).
+ mdMethodDef mdSetter, // [IN] optional setter of the property
+ mdMethodDef mdGetter, // [IN] optional getter of the property
+ mdMethodDef rmdOtherMethods[], // [IN] an optional array of other methods
+ mdProperty *pmdProp) // [OUT] output property token
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ PropertyRec *pPropRec = NULL;
+ RID iPropRec;
+ PropertyMapRec *pPropMap;
+ RID iPropMap;
+ LPUTF8 szUTF8Property;
+ UTF8STR(szProperty, szUTF8Property);
+
+ LOG((LOGMD, "MD RegMeta::DefineProperty(0x%08x, %S, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ td, szProperty, dwPropFlags, pvSig, cbSig, dwCPlusTypeFlag, pValue, cchValue, mdSetter, mdGetter,
+ rmdOtherMethods, pmdProp));
+
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ _ASSERTE(TypeFromToken(td) == mdtTypeDef && td != mdTypeDefNil &&
+ szProperty && pvSig && cbSig && pmdProp);
+
+ if (CheckDups(MDDupProperty))
+ {
+ hr = ImportHelper::FindProperty(&(m_pStgdb->m_MiniMd), td, szUTF8Property, pvSig, cbSig, pmdProp);
+ if (SUCCEEDED(hr))
+ {
+ if (IsENCOn())
+ IfFailGo(m_pStgdb->m_MiniMd.GetPropertyRecord(RidFromToken(*pmdProp), &pPropRec));
+ else
+ {
+ hr = META_S_DUPLICATE;
+ goto ErrExit;
+ }
+ }
+ else if (hr != CLDB_E_RECORD_NOTFOUND)
+ IfFailGo(hr);
+ }
+
+ if (! pPropRec)
+ {
+ // Create a new map if one doesn't exist already, else retrieve the existing one.
+ // The property map must be created before the PropertyRecord, the new property
+ // map will be pointing past the first property record.
+ IfFailGo(m_pStgdb->m_MiniMd.FindPropertyMapFor(RidFromToken(td), &iPropMap));
+ if (InvalidRid(iPropMap))
+ {
+ // Create new record.
+ IfFailGo(m_pStgdb->m_MiniMd.AddPropertyMapRecord(&pPropMap, &iPropMap));
+ // Set parent.
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_PropertyMap,
+ PropertyMapRec::COL_Parent, pPropMap, td));
+ IfFailGo(UpdateENCLog2(TBL_PropertyMap, iPropMap));
+ }
+ else
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.GetPropertyMapRecord(iPropMap, &pPropMap));
+ }
+
+ // Create a new record.
+ IfFailGo(m_pStgdb->m_MiniMd.AddPropertyRecord(&pPropRec, &iPropRec));
+
+ // Set output parameter.
+ *pmdProp = TokenFromRid(iPropRec, mdtProperty);
+
+ // Add Property to the PropertyMap.
+ IfFailGo(m_pStgdb->m_MiniMd.AddPropertyToPropertyMap(RidFromToken(iPropMap), iPropRec));
+
+ IfFailGo(UpdateENCLog2(TBL_PropertyMap, iPropMap, CMiniMdRW::eDeltaPropertyCreate));
+ }
+
+ // Save the data.
+ IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_Property, PropertyRec::COL_Type, pPropRec,
+ pvSig, cbSig));
+ IfFailGo( m_pStgdb->m_MiniMd.PutString(TBL_Property, PropertyRec::COL_Name,
+ pPropRec, szUTF8Property) );
+
+ SetCallerDefine();
+ IfFailGo(_SetPropertyProps(*pmdProp, dwPropFlags, dwCPlusTypeFlag, pValue, cchValue, mdSetter,
+ mdGetter, rmdOtherMethods));
+
+ // Add the <property token, typedef token> to the lookup table
+ if (m_pStgdb->m_MiniMd.HasIndirectTable(TBL_Property))
+ IfFailGo( m_pStgdb->m_MiniMd.AddPropertyToLookUpTable(*pmdProp, td) );
+
+ErrExit:
+ SetCallerExternal();
+
+ STOP_MD_PERF(DefineProperty);
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::DefineProperty
+
+//*****************************************************************************
+// Create a record in the Param table. Any set of name, flags, or default value
+// may be set.
+//*****************************************************************************
+HRESULT RegMeta::DefineParam(
+ mdMethodDef md, // [IN] Owning method
+ ULONG ulParamSeq, // [IN] Which param
+ LPCWSTR szName, // [IN] Optional param name
+ DWORD dwParamFlags, // [IN] Optional param flags
+ DWORD dwCPlusTypeFlag, // [IN] flag for value type. selected ELEMENT_TYPE_*
+ void const *pValue, // [IN] constant value
+ ULONG cchValue, // [IN] size of constant value (string, in wide chars).
+ mdParamDef *ppd) // [OUT] Put param token here
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ RID iRecord;
+ ParamRec *pRecord = 0;
+
+ LOG((LOGMD, "MD RegMeta::DefineParam(0x%08x, 0x%08x, %S, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ md, ulParamSeq, MDSTR(szName), dwParamFlags, dwCPlusTypeFlag, pValue, cchValue, ppd));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ _ASSERTE(TypeFromToken(md) == mdtMethodDef && md != mdMethodDefNil &&
+ ulParamSeq != ULONG_MAX && ppd);
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ // Retrieve or create the Param row.
+ if (CheckDups(MDDupParamDef))
+ {
+ hr = _FindParamOfMethod(md, ulParamSeq, ppd);
+ if (SUCCEEDED(hr))
+ {
+ if (IsENCOn())
+ IfFailGo(m_pStgdb->m_MiniMd.GetParamRecord(RidFromToken(*ppd), &pRecord));
+ else
+ {
+ hr = META_S_DUPLICATE;
+ goto ErrExit;
+ }
+ }
+ else if (hr != CLDB_E_RECORD_NOTFOUND)
+ IfFailGo(hr);
+ }
+
+ if (!pRecord)
+ {
+ // Create the Param record.
+ IfFailGo(m_pStgdb->m_MiniMd.AddParamRecord(&pRecord, &iRecord));
+
+ // Set the output parameter.
+ *ppd = TokenFromRid(iRecord, mdtParamDef);
+
+ // Set sequence number.
+ pRecord->SetSequence(static_cast<USHORT>(ulParamSeq));
+
+ // Add to the parent's list of child records.
+ IfFailGo(m_pStgdb->m_MiniMd.AddParamToMethod(RidFromToken(md), iRecord));
+
+ IfFailGo(UpdateENCLog(md, CMiniMdRW::eDeltaParamCreate));
+ }
+
+ SetCallerDefine();
+ // Set the properties.
+ IfFailGo(_SetParamProps(*ppd, szName, dwParamFlags, dwCPlusTypeFlag, pValue, cchValue));
+
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+ SetCallerExternal();
+
+ STOP_MD_PERF(DefineParam);
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::DefineParam
+
+//*****************************************************************************
+// Set the properties on the given Field token.
+//*****************************************************************************
+HRESULT RegMeta::SetFieldProps( // S_OK or error.
+ mdFieldDef fd, // [IN] The FieldDef.
+ DWORD dwFieldFlags, // [IN] Field attributes.
+ DWORD dwCPlusTypeFlag, // [IN] Flag for the value type, selected ELEMENT_TYPE_*
+ void const *pValue, // [IN] Constant value.
+ ULONG cchValue) // [IN] size of constant value (string, in wide chars).
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+
+ LOG((LOGMD, "MD: RegMeta::SetFieldProps(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ fd, dwFieldFlags, dwCPlusTypeFlag, pValue, cchValue));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ // Validate flags.
+ if (dwFieldFlags != ULONG_MAX)
+ {
+ // fdHasFieldRVA is settable, but not re-settable by applications.
+ _ASSERTE((dwFieldFlags & (fdReservedMask&~(fdHasFieldRVA|fdRTSpecialName))) == 0);
+ dwFieldFlags &= ~(fdReservedMask&~fdHasFieldRVA);
+ }
+
+ hr = _SetFieldProps(fd, dwFieldFlags, dwCPlusTypeFlag, pValue, cchValue);
+
+ErrExit:
+
+ STOP_MD_PERF(SetFieldProps);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::SetFieldProps
+
+//*****************************************************************************
+// Set the properties on the given Property token.
+//*****************************************************************************
+HRESULT RegMeta::SetPropertyProps( // S_OK or error.
+ mdProperty pr, // [IN] Property token.
+ DWORD dwPropFlags, // [IN] CorPropertyAttr.
+ DWORD dwCPlusTypeFlag, // [IN] Flag for value type, selected ELEMENT_TYPE_*
+ void const *pValue, // [IN] Constant value.
+ ULONG cchValue, // [IN] size of constant value (string, in wide chars).
+ mdMethodDef mdSetter, // [IN] Setter of the property.
+ mdMethodDef mdGetter, // [IN] Getter of the property.
+ mdMethodDef rmdOtherMethods[]) // [IN] Array of other methods.
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+
+ LOG((LOGMD, "MD RegMeta::SetPropertyProps(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ pr, dwPropFlags, dwCPlusTypeFlag, pValue, cchValue, mdSetter, mdGetter,
+ rmdOtherMethods));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ hr = _SetPropertyProps(pr, dwPropFlags, dwCPlusTypeFlag, pValue, cchValue, mdSetter, mdGetter, rmdOtherMethods);
+
+ErrExit:
+
+ STOP_MD_PERF(SetPropertyProps);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::SetPropertyProps
+
+
+//*****************************************************************************
+// This routine sets properties on the given Param token.
+//*****************************************************************************
+HRESULT RegMeta::SetParamProps( // Return code.
+ mdParamDef pd, // [IN] Param token.
+ LPCWSTR szName, // [IN] Param name.
+ DWORD dwParamFlags, // [IN] Param flags.
+ DWORD dwCPlusTypeFlag, // [IN] Flag for value type. selected ELEMENT_TYPE_*.
+ void const *pValue, // [OUT] Constant value.
+ ULONG cchValue) // [IN] size of constant value (string, in wide chars).
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "MD RegMeta::SetParamProps(0x%08x, %S, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ pd, MDSTR(szName), dwParamFlags, dwCPlusTypeFlag, pValue, cchValue));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ hr = _SetParamProps(pd, szName, dwParamFlags, dwCPlusTypeFlag, pValue, cchValue);
+
+ErrExit:
+
+ STOP_MD_PERF(SetParamProps);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::SetParamProps
+
+//*****************************************************************************
+// Apply edit and continue changes to this metadata.
+//*****************************************************************************
+STDMETHODIMP RegMeta::ApplyEditAndContinue( // S_OK or error.
+ IUnknown *pUnk) // [IN] Metadata from the delta PE.
+{
+#ifdef FEATURE_METADATA_EMIT_ALL
+ HRESULT hr;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ IMetaDataImport2 *pImport=0; // Interface on the delta metadata.
+ RegMeta *pDeltaMD=0; // The delta metadata.
+ CMiniMdRW *mdDelta = NULL;
+ CMiniMdRW *mdBase = NULL;
+
+ // Get the MiniMd on the delta.
+ IfFailGo(pUnk->QueryInterface(IID_IMetaDataImport2, (void**)&pImport));
+
+ pDeltaMD = static_cast<RegMeta*>(pImport);
+
+ mdDelta = &(pDeltaMD->m_pStgdb->m_MiniMd);
+ mdBase = &(m_pStgdb->m_MiniMd);
+
+ IfFailGo(mdBase->ConvertToRW());
+ IfFailGo(mdBase->ApplyDelta(*mdDelta));
+
+ErrExit:
+ if (pImport)
+ pImport->Release();
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+#else //!FEATURE_METADATA_EMIT_ALL
+ return E_NOTIMPL;
+#endif //!FEATURE_METADATA_EMIT_ALL
+} // RegMeta::ApplyEditAndContinue
+
+#endif //FEATURE_METADATA_EMIT
diff --git a/src/md/compiler/filtermanager.cpp b/src/md/compiler/filtermanager.cpp
new file mode 100644
index 0000000000..c8e9ac3e07
--- /dev/null
+++ b/src/md/compiler/filtermanager.cpp
@@ -0,0 +1,1458 @@
+// 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.
+//*****************************************************************************
+// FilterManager.cpp
+//
+
+//
+// contains utility code to MD directory
+//
+//*****************************************************************************
+#include "stdafx.h"
+#include "filtermanager.h"
+
+#define IsGlobalTypeDef(td) (td == TokenFromRid(mdtTypeDef, 1))
+
+//*****************************************************************************
+// Walk up to the containing tree and
+// mark the transitive closure of the root token
+//*****************************************************************************
+HRESULT FilterManager::Mark(mdToken tk)
+{
+ HRESULT hr = NOERROR;
+ mdTypeDef td;
+
+ // We hard coded System.Object as mdTypeDefNil
+ // The backing Field of property can be NULL as well.
+ if (RidFromToken(tk) == mdTokenNil)
+ goto ErrExit;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME(m_pMiniMd->GetFilterTable() != NULL);
+
+ switch ( TypeFromToken(tk) )
+ {
+ case mdtTypeDef:
+ IfFailGo( MarkTypeDef(tk) );
+ break;
+
+ case mdtMethodDef:
+ // Get the typedef containing the MethodDef and mark the whole type
+ IfFailGo( m_pMiniMd->FindParentOfMethodHelper(tk, &td) );
+
+ // Global function so only mark the function itself and the typedef.
+ // Don't call MarkTypeDef. That will trigger all of the global methods/fields
+ // marked.
+ //
+ if (IsGlobalTypeDef(td))
+ {
+ IfFailGo( m_pMiniMd->GetFilterTable()->MarkTypeDef(td) );
+ IfFailGo( MarkMethod(tk) );
+ }
+ else
+ {
+ IfFailGo( MarkTypeDef(td) );
+ }
+ break;
+
+ case mdtFieldDef:
+ // Get the typedef containing the FieldDef and mark the whole type
+ IfFailGo( m_pMiniMd->FindParentOfFieldHelper(tk, &td) );
+ if (IsGlobalTypeDef(td))
+ {
+ IfFailGo( m_pMiniMd->GetFilterTable()->MarkTypeDef(td) );
+ IfFailGo( MarkField(tk) );
+ }
+ else
+ {
+ IfFailGo( MarkTypeDef(td) );
+ }
+ break;
+
+ case mdtMemberRef:
+ IfFailGo( MarkMemberRef(tk) );
+ break;
+
+ case mdtTypeRef:
+ IfFailGo( MarkTypeRef(tk) );
+ break;
+
+ case mdtTypeSpec:
+ IfFailGo( MarkTypeSpec(tk) );
+ break;
+ case mdtSignature:
+ IfFailGo( MarkStandAloneSig(tk) );
+ break;
+
+ case mdtModuleRef:
+ IfFailGo( MarkModuleRef(tk) );
+ break;
+
+ case mdtAssemblyRef:
+ IfFailGo( MarkAssemblyRef(tk) );
+ break;
+
+ case mdtModule:
+ IfFailGo( MarkModule(tk) );
+ break;
+
+ case mdtString:
+ IfFailGo( MarkUserString(tk) );
+ break;
+
+ case mdtBaseType:
+ // don't need to mark any base type.
+ break;
+
+ case mdtAssembly:
+ IfFailGo( MarkAssembly(tk) );
+ break;
+
+ case mdtMethodSpec:
+ IfFailGo( MarkMethodSpec(tk) );
+ break;
+
+ case mdtProperty:
+ case mdtEvent:
+ case mdtParamDef:
+ case mdtInterfaceImpl:
+ default:
+ _ASSERTE(!" unknown type!");
+ hr = E_INVALIDARG;
+ break;
+ }
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::Mark()
+
+
+
+//*****************************************************************************
+// marking only module property
+//*****************************************************************************
+HRESULT FilterManager::MarkAssembly(mdAssembly as)
+{
+ HRESULT hr = NOERROR;
+
+ if (hasAssemblyBeenMarked == false)
+ {
+ hasAssemblyBeenMarked = true;
+ IfFailGo( MarkCustomAttributesWithParentToken(as) );
+ IfFailGo( MarkDeclSecuritiesWithParentToken(as) );
+ }
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkAssembly()
+
+
+//*****************************************************************************
+// marking only module property
+//*****************************************************************************
+HRESULT FilterManager::MarkModule(mdModule mo)
+{
+ HRESULT hr = NOERROR;
+
+ if (hasModuleBeenMarked == false)
+ {
+ hasModuleBeenMarked = true;
+ IfFailGo( MarkCustomAttributesWithParentToken(mo) );
+ }
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkModule()
+
+
+//*****************************************************************************
+// cascading Mark of a CustomAttribute
+//*****************************************************************************
+HRESULT FilterManager::MarkCustomAttribute(mdCustomAttribute cv)
+{
+ HRESULT hr = NOERROR;
+ CustomAttributeRec *pRec;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME(m_pMiniMd->GetFilterTable() != NULL);
+
+ IfFailGo( m_pMiniMd->GetFilterTable()->MarkCustomAttribute( cv ) );
+
+ // Mark the type (and any family) of the CustomAttribue.
+ IfFailGo(m_pMiniMd->GetCustomAttributeRecord(RidFromToken(cv), &pRec));
+ IfFailGo( Mark(m_pMiniMd->getTypeOfCustomAttribute(pRec)) );
+
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkCustomAttribute()
+
+
+//*****************************************************************************
+// cascading Mark of a DeclSecurity
+//*****************************************************************************
+HRESULT FilterManager::MarkDeclSecurity(mdPermission pe)
+{
+ HRESULT hr = NOERROR;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME(m_pMiniMd->GetFilterTable() != NULL);
+
+ IfFailGo( m_pMiniMd->GetFilterTable()->MarkDeclSecurity( pe ) );
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkDeclSecurity()
+
+
+
+//*****************************************************************************
+// cascading Mark of a signature
+//*****************************************************************************
+HRESULT FilterManager::MarkStandAloneSig(mdSignature sig)
+{
+ HRESULT hr = NOERROR;
+ StandAloneSigRec *pRec;
+ ULONG cbSize;
+ ULONG cbUsed;
+ PCCOR_SIGNATURE pbSig;
+ IHostFilter *pFilter = m_pMiniMd->GetHostFilter();
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME(m_pMiniMd->GetFilterTable() != NULL);
+
+ // if TypeRef is already marked, just return
+ if (m_pMiniMd->GetFilterTable()->IsSignatureMarked(sig))
+ goto ErrExit;
+
+ // To mark the signature, we will need to mark
+ // all of the embedded TypeRef or TypeDef
+ //
+ IfFailGo( m_pMiniMd->GetFilterTable()->MarkSignature( sig ) );
+
+ if (pFilter)
+ pFilter->MarkToken(sig);
+
+ // Walk the signature and mark all of the embedded types
+ IfFailGo(m_pMiniMd->GetStandAloneSigRecord(RidFromToken(sig), &pRec));
+ IfFailGo(m_pMiniMd->getSignatureOfStandAloneSig(pRec, &pbSig, &cbSize));
+ IfFailGo( MarkSignature(pbSig, cbSize, &cbUsed) );
+
+ IfFailGo( MarkCustomAttributesWithParentToken(sig) );
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkStandAloneSig()
+
+
+
+//*****************************************************************************
+// cascading Mark of a TypeSpec
+//*****************************************************************************
+HRESULT FilterManager::MarkTypeSpec(mdTypeSpec ts)
+{
+ HRESULT hr = NOERROR;
+ TypeSpecRec *pRec;
+ ULONG cbSize;
+ ULONG cbUsed;
+ PCCOR_SIGNATURE pbSig;
+ IHostFilter *pFilter = m_pMiniMd->GetHostFilter();
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME(m_pMiniMd->GetFilterTable() != NULL);
+
+ // if TypeRef is already marked, just return
+ if (m_pMiniMd->GetFilterTable()->IsTypeSpecMarked(ts))
+ goto ErrExit;
+
+ // To mark the TypeSpec, we will need to mark
+ // all of the embedded TypeRef or TypeDef
+ //
+ IfFailGo( m_pMiniMd->GetFilterTable()->MarkTypeSpec( ts ) );
+
+ if (pFilter)
+ pFilter->MarkToken(ts);
+
+ // Walk the signature and mark all of the embedded types
+ IfFailGo(m_pMiniMd->GetTypeSpecRecord(RidFromToken(ts), &pRec));
+ IfFailGo(m_pMiniMd->getSignatureOfTypeSpec(pRec, &pbSig, &cbSize));
+ IfFailGo( MarkFieldSignature(pbSig, cbSize, &cbUsed) );
+ IfFailGo( MarkCustomAttributesWithParentToken(ts) );
+
+
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkTypeSpec()
+
+
+
+
+//*****************************************************************************
+// cascading Mark of a TypeRef
+//*****************************************************************************
+HRESULT FilterManager::MarkTypeRef(mdTypeRef tr)
+{
+ HRESULT hr = NOERROR;
+ TOKENMAP *tkMap;
+ mdTypeDef td;
+ IHostFilter *pFilter = m_pMiniMd->GetHostFilter();
+ TypeRefRec *pRec;
+ mdToken parentTk;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME(m_pMiniMd->GetFilterTable() != NULL);
+
+ // if TypeRef is already marked, just return
+ if (m_pMiniMd->GetFilterTable()->IsTypeRefMarked(tr))
+ goto ErrExit;
+
+ IfFailGo( m_pMiniMd->GetFilterTable()->MarkTypeRef( tr ) );
+
+ if (pFilter)
+ pFilter->MarkToken(tr);
+
+ IfFailGo(m_pMiniMd->GetTypeRefRecord(RidFromToken(tr), &pRec));
+ parentTk = m_pMiniMd->getResolutionScopeOfTypeRef(pRec);
+ if ( RidFromToken(parentTk) )
+ {
+ IfFailGo( Mark( parentTk ) );
+ }
+
+ tkMap = m_pMiniMd->GetTypeRefToTypeDefMap();
+ PREFIX_ASSUME(tkMap != NULL);
+ td = *(tkMap->Get(RidFromToken(tr)));
+ if ( td != mdTokenNil )
+ {
+ // TypeRef is referring to a TypeDef within the same module.
+ // Mark the TypeDef as well.
+ //
+ IfFailGo( Mark(td) );
+ }
+
+ IfFailGo( MarkCustomAttributesWithParentToken(tr) );
+
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkTypeRef()
+
+
+//*****************************************************************************
+// cascading Mark of a MemberRef
+//*****************************************************************************
+HRESULT FilterManager::MarkMemberRef(mdMemberRef mr)
+{
+ HRESULT hr = NOERROR;
+ MemberRefRec *pRec;
+ ULONG cbSize;
+ ULONG cbUsed;
+ PCCOR_SIGNATURE pbSig;
+ IHostFilter *pFilter = m_pMiniMd->GetHostFilter();
+ mdToken md;
+ TOKENMAP *tkMap;
+ mdToken tkParent;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME(m_pMiniMd->GetFilterTable() != NULL);
+
+ // if MemberRef is already marked, just return
+ if (m_pMiniMd->GetFilterTable()->IsMemberRefMarked(mr))
+ goto ErrExit;
+
+ IfFailGo( m_pMiniMd->GetFilterTable()->MarkMemberRef( mr ) );
+
+ if (pFilter)
+ pFilter->MarkToken(mr);
+
+ IfFailGo(m_pMiniMd->GetMemberRefRecord(RidFromToken(mr), &pRec));
+
+ // we want to mark the parent of MemberRef as well
+ tkParent = m_pMiniMd->getClassOfMemberRef(pRec);
+
+ // If the parent is the global TypeDef, mark only the TypeDef itself (low-level function).
+ // Other parents, do the transitive mark (ie, the high-level function).
+ //
+ if (IsGlobalTypeDef(tkParent))
+ IfFailGo( m_pMiniMd->GetFilterTable()->MarkTypeDef( tkParent ) );
+ else
+ IfFailGo( Mark( tkParent ) );
+
+ // Walk the signature and mark all of the embedded types
+ IfFailGo(m_pMiniMd->getSignatureOfMemberRef(pRec, &pbSig, &cbSize));
+ IfFailGo( MarkSignature(pbSig, cbSize, &cbUsed) );
+
+ tkMap = m_pMiniMd->GetMemberRefToMemberDefMap();
+ PREFIX_ASSUME(tkMap != NULL);
+ md = *(tkMap->Get(RidFromToken(mr))); // can be fielddef or methoddef
+ if ( RidFromToken(md) != mdTokenNil )
+ {
+ // MemberRef is referring to either a FieldDef or MethodDef.
+ // If it is referring to MethodDef, we have fix the parent of MemberRef to be the MethodDef.
+ // However, if it is mapped to a FieldDef, the parent column does not track this information.
+ // Therefore we need to mark it explicitly.
+ //
+ IfFailGo( Mark(md) );
+ }
+
+ IfFailGo( MarkCustomAttributesWithParentToken(mr) );
+
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkMemberRef()
+
+
+//*****************************************************************************
+// cascading Mark of a UserString
+//*****************************************************************************
+HRESULT FilterManager::MarkUserString(mdString str)
+{
+ HRESULT hr = NOERROR;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME(m_pMiniMd->GetFilterTable() != NULL);
+
+ // if UserString is already marked, just return
+ if (m_pMiniMd->GetFilterTable()->IsUserStringMarked(str))
+ goto ErrExit;
+
+ IfFailGo( m_pMiniMd->GetFilterTable()->MarkUserString( str ) );
+
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkUserString()
+
+
+//*****************************************************************************
+// Mark of a new UserString
+//*****************************************************************************
+HRESULT FilterManager::MarkNewUserString(mdString str)
+{
+ HRESULT hr = NOERROR;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME(m_pMiniMd->GetFilterTable() != NULL);
+
+ IfFailGo( m_pMiniMd->GetFilterTable()->MarkNewUserString( str ) );
+
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkUserString()
+
+
+//*****************************************************************************
+// cascading Mark of a MethodSpec
+//*****************************************************************************
+HRESULT FilterManager::MarkMethodSpec(mdMethodSpec ms)
+{
+ HRESULT hr = NOERROR;
+ MethodSpecRec *pRec;
+ ULONG cbSize;
+ ULONG cbUsed;
+ PCCOR_SIGNATURE pbSig;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME(m_pMiniMd->GetFilterTable() != NULL);
+
+ // if MethodSpec is already marked, just return
+ if (m_pMiniMd->GetFilterTable()->IsMethodSpecMarked(ms))
+ goto ErrExit;
+
+ IfFailGo( m_pMiniMd->GetFilterTable()->MarkMethodSpec( ms ) );
+
+ // Mark MethodRef or MethodDef and embedded TypeRef and TypeDef tokens
+
+ IfFailGo(m_pMiniMd->GetMethodSpecRecord(RidFromToken(ms), &pRec));
+
+ IfFailGo( Mark(m_pMiniMd->getMethodOfMethodSpec(pRec)) );
+
+ IfFailGo(m_pMiniMd->getInstantiationOfMethodSpec(pRec, &pbSig, &cbSize));
+ IfFailGo( MarkSignature(pbSig, cbSize, &cbUsed) );
+
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkMethodSpec()
+
+
+//*****************************************************************************
+// cascading Mark of a ModuleRef
+//*****************************************************************************
+HRESULT FilterManager::MarkModuleRef(mdModuleRef mr)
+{
+ HRESULT hr = NOERROR;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME(m_pMiniMd->GetFilterTable() != NULL);
+
+ // if ModuleRef is already marked, just return
+ if (m_pMiniMd->GetFilterTable()->IsModuleRefMarked(mr))
+ goto ErrExit;
+
+ IfFailGo( m_pMiniMd->GetFilterTable()->MarkModuleRef( mr ) );
+ IfFailGo( MarkCustomAttributesWithParentToken(mr) );
+
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkModuleRef()
+
+
+//*****************************************************************************
+// cascading Mark of a AssemblyRef
+//*****************************************************************************
+HRESULT FilterManager::MarkAssemblyRef(mdAssemblyRef ar)
+{
+ HRESULT hr = NOERROR;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME(m_pMiniMd->GetFilterTable() != NULL);
+
+ // if ModuleREf is already marked, just return
+ if (m_pMiniMd->GetFilterTable()->IsAssemblyRefMarked(ar))
+ goto ErrExit;
+
+ IfFailGo( m_pMiniMd->GetFilterTable()->MarkAssemblyRef( ar ) );
+ IfFailGo( MarkCustomAttributesWithParentToken(ar) );
+
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkAssemblyRef()
+
+
+//*****************************************************************************
+// cascading Mark of all of the custom values associated with a token
+//*****************************************************************************
+HRESULT FilterManager::MarkCustomAttributesWithParentToken(mdToken tkParent)
+{
+ HRESULT hr = NOERROR;
+ RID ridStart, ridEnd;
+ RID index;
+ CustomAttributeRec *pRec;
+
+ if ( m_pMiniMd->IsSorted( TBL_CustomAttribute ) )
+ {
+ // table is sorted. ridStart to ridEnd - 1 are all CustomAttribute
+ // associated with tkParent
+ //
+ IfFailGo(m_pMiniMd->getCustomAttributeForToken(tkParent, &ridEnd, &ridStart));
+ for (index = ridStart; index < ridEnd; index ++ )
+ {
+ IfFailGo( MarkCustomAttribute( TokenFromRid(index, mdtCustomAttribute) ) );
+ }
+ }
+ else
+ {
+ // table scan is needed
+ ridStart = 1;
+ ridEnd = m_pMiniMd->getCountCustomAttributes() + 1;
+ for (index = ridStart; index < ridEnd; index ++ )
+ {
+ IfFailGo(m_pMiniMd->GetCustomAttributeRecord(index, &pRec));
+ if ( tkParent == m_pMiniMd->getParentOfCustomAttribute(pRec) )
+ {
+ // This CustomAttribute is associated with tkParent
+ IfFailGo( MarkCustomAttribute( TokenFromRid(index, mdtCustomAttribute) ) );
+ }
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkCustomAttributesWithParentToken()
+
+
+//*****************************************************************************
+// cascading Mark of all securities associated with a token
+//*****************************************************************************
+HRESULT FilterManager::MarkDeclSecuritiesWithParentToken(mdToken tkParent)
+{
+ HRESULT hr = NOERROR;
+ RID ridStart, ridEnd;
+ RID index;
+ DeclSecurityRec *pRec;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME(m_pMiniMd->GetFilterTable() != NULL);
+
+ if ( m_pMiniMd->IsSorted( TBL_DeclSecurity ) )
+ {
+ // table is sorted. ridStart to ridEnd - 1 are all DeclSecurity
+ // associated with tkParent
+ //
+ IfFailGo(m_pMiniMd->getDeclSecurityForToken(tkParent, &ridEnd, &ridStart));
+ for (index = ridStart; index < ridEnd; index ++ )
+ {
+ IfFailGo( m_pMiniMd->GetFilterTable()->MarkDeclSecurity( TokenFromRid(index, mdtPermission) ) );
+ }
+ }
+ else
+ {
+ // table scan is needed
+ ridStart = 1;
+ ridEnd = m_pMiniMd->getCountDeclSecuritys() + 1;
+ for (index = ridStart; index < ridEnd; index ++ )
+ {
+ IfFailGo(m_pMiniMd->GetDeclSecurityRecord(index, &pRec));
+ if ( tkParent == m_pMiniMd->getParentOfDeclSecurity(pRec) )
+ {
+ // This DeclSecurity is associated with tkParent
+ IfFailGo( m_pMiniMd->GetFilterTable()->MarkDeclSecurity( TokenFromRid(index, mdtPermission) ) );
+ }
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkDeclSecuritiesWithParentToken()
+
+
+//*****************************************************************************
+// cascading Mark of all MemberRefs associated with a parent token
+//*****************************************************************************
+HRESULT FilterManager::MarkMemberRefsWithParentToken(mdToken tk)
+{
+ HRESULT hr = NOERROR;
+ RID ulEnd;
+ RID index;
+ mdToken tkParent;
+ MemberRefRec *pRec;
+
+ ulEnd = m_pMiniMd->getCountMemberRefs();
+
+ for (index = 1; index <= ulEnd; index ++ )
+ {
+ // memberRef table is not sorted. Table scan is needed.
+ IfFailGo(m_pMiniMd->GetMemberRefRecord(index, &pRec));
+ tkParent = m_pMiniMd->getClassOfMemberRef(pRec);
+ if ( tk == tkParent )
+ {
+ IfFailGo( MarkMemberRef( TokenFromRid(index, mdtMemberRef) ) );
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkMemberRefsWithParentToken()
+
+
+//*****************************************************************************
+// cascading Mark of a ParamDef token
+//*****************************************************************************
+HRESULT FilterManager::MarkParam(mdParamDef pd)
+{
+ HRESULT hr;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME(m_pMiniMd->GetFilterTable() != NULL);
+
+ IfFailGo( m_pMiniMd->GetFilterTable()->MarkParam( pd ) );
+
+ IfFailGo( MarkCustomAttributesWithParentToken(pd) );
+ // Parameter does not have declsecurity
+ // IfFailGo( MarkDeclSecuritiesWithParentToken(pd) );
+
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkParam()
+
+
+//*****************************************************************************
+// cascading Mark of a method token
+//*****************************************************************************
+HRESULT FilterManager::MarkMethod(mdMethodDef md)
+{
+ HRESULT hr = NOERROR;
+ MethodRec *pRec;
+ ULONG cbSize;
+ ULONG cbUsed;
+ PCCOR_SIGNATURE pbSig;
+ ULONG i, iCount;
+ ImplMapRec *pImplMapRec = NULL;
+ mdMethodDef mdImp;
+ mdModuleRef mrImp;
+ IHostFilter *pFilter = m_pMiniMd->GetHostFilter();
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME(m_pMiniMd->GetFilterTable() != NULL);
+
+ // if MethodDef is already marked, just return
+ if (m_pMiniMd->GetFilterTable()->IsMethodMarked(md))
+ goto ErrExit;
+
+ IfFailGo( m_pMiniMd->GetFilterTable()->MarkMethod( md ) );
+ if (pFilter)
+ pFilter->MarkToken(md);
+
+ IfFailGo( MarkParamsWithParentToken(md) );
+
+ // mark any GenericParam of this Method
+ IfFailGo( MarkGenericParamWithParentToken(md) );
+
+
+ // Walk the signature and mark all of the embedded types
+ IfFailGo(m_pMiniMd->GetMethodRecord(RidFromToken(md), &pRec));
+ IfFailGo(m_pMiniMd->getSignatureOfMethod(pRec, &pbSig, &cbSize));
+ IfFailGo( MarkSignature(pbSig, cbSize, &cbUsed) );
+
+ iCount = m_pMiniMd->getCountImplMaps();
+
+ // loop through all ImplMaps and find the Impl map associated with this method def tokens
+ // and mark the Module Ref tokens in the entries
+ //
+ for (i = 1; i <= iCount; i++)
+ {
+ IfFailGo(m_pMiniMd->GetImplMapRecord(i, &pImplMapRec));
+
+ // Get the MethodDef that the impl map is associated with
+ mdImp = m_pMiniMd->getMemberForwardedOfImplMap(pImplMapRec);
+
+ if (mdImp != md)
+ {
+ // Impl Map entry does not associated with the method def that we are marking
+ continue;
+ }
+
+ // Get the ModuleRef token
+ mrImp = m_pMiniMd->getImportScopeOfImplMap(pImplMapRec);
+ IfFailGo( Mark(mrImp) );
+ }
+
+ // We should not mark all of the memberref with the parent of this methoddef token.
+ // Because not all of the call sites are needed.
+ //
+ // IfFailGo( MarkMemberRefsWithParentToken(md) );
+ IfFailGo( MarkCustomAttributesWithParentToken(md) );
+ IfFailGo( MarkDeclSecuritiesWithParentToken(md) );
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkMethod()
+
+
+//*****************************************************************************
+// cascading Mark of a field token
+//*****************************************************************************
+HRESULT FilterManager::MarkField(mdFieldDef fd)
+{
+ HRESULT hr = NOERROR;
+ FieldRec *pRec;
+ ULONG cbSize;
+ ULONG cbUsed;
+ PCCOR_SIGNATURE pbSig;
+ IHostFilter *pFilter = m_pMiniMd->GetHostFilter();
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME(m_pMiniMd->GetFilterTable() != NULL);
+
+ // if FieldDef is already marked, just return
+ if (m_pMiniMd->GetFilterTable()->IsFieldMarked(fd))
+ goto ErrExit;
+
+ IfFailGo( m_pMiniMd->GetFilterTable()->MarkField( fd ) );
+ if (pFilter)
+ pFilter->MarkToken(fd);
+
+ // We should not mark all of the MemberRef with the parent of this FieldDef token.
+ // Because not all of the call sites are needed.
+ //
+
+ // Walk the signature and mark all of the embedded types
+ IfFailGo(m_pMiniMd->GetFieldRecord(RidFromToken(fd), &pRec));
+ IfFailGo(m_pMiniMd->getSignatureOfField(pRec, &pbSig, &cbSize));
+ IfFailGo( MarkSignature(pbSig, cbSize, &cbUsed) );
+
+ IfFailGo( MarkCustomAttributesWithParentToken(fd) );
+ // IfFailGo( MarkDeclSecuritiesWithParentToken(fd) );
+
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkField()
+
+
+//*****************************************************************************
+// cascading Mark of an event token
+//*****************************************************************************
+HRESULT FilterManager::MarkEvent(mdEvent ev)
+{
+ HRESULT hr = NOERROR;
+ EventRec *pRec;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME(m_pMiniMd->GetFilterTable() != NULL);
+
+ // if Event is already marked, just return
+ if (m_pMiniMd->GetFilterTable()->IsEventMarked(ev))
+ goto ErrExit;
+
+ IfFailGo( m_pMiniMd->GetFilterTable()->MarkEvent( ev ) );
+
+ // mark the event type as well
+ IfFailGo(m_pMiniMd->GetEventRecord(RidFromToken(ev), &pRec));
+ IfFailGo( Mark(m_pMiniMd->getEventTypeOfEvent(pRec)) );
+
+ // Note that we don't need to mark the MethodSemantics. Because the association of MethodSemantics
+ // is marked. The Method column can only store MethodDef, ie the MethodDef has the same parent as
+ // this Event.
+
+ IfFailGo( MarkCustomAttributesWithParentToken(ev) );
+ // IfFailGo( MarkDeclSecuritiesWithParentToken(ev) );
+
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkEvent()
+
+
+
+//*****************************************************************************
+// cascading Mark of a Property token
+//*****************************************************************************
+HRESULT FilterManager::MarkProperty(mdProperty pr)
+{
+ HRESULT hr = NOERROR;
+ PropertyRec *pRec;
+ ULONG cbSize;
+ ULONG cbUsed;
+ PCCOR_SIGNATURE pbSig;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME(m_pMiniMd->GetFilterTable() != NULL);
+
+ // if Property is already marked, just return
+ if (m_pMiniMd->GetFilterTable()->IsPropertyMarked(pr))
+ goto ErrExit;
+
+ IfFailGo( m_pMiniMd->GetFilterTable()->MarkProperty( pr ) );
+
+ // marking the backing field, event changing and event changed
+ IfFailGo(m_pMiniMd->GetPropertyRecord(RidFromToken(pr), &pRec));
+
+ // Walk the signature and mark all of the embedded types
+ IfFailGo(m_pMiniMd->getTypeOfProperty(pRec, &pbSig, &cbSize));
+ IfFailGo( MarkSignature(pbSig, cbSize, &cbUsed) );
+
+ // Note that we don't need to mark the MethodSemantics. Because the association of MethodSemantics
+ // is marked. The Method column can only store MethodDef, ie the MethodDef has the same parent as
+ // this Property.
+
+ IfFailGo( MarkCustomAttributesWithParentToken(pr) );
+ // IfFailGo( MarkDeclSecuritiesWithParentToken(pr) );
+
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkProperty()
+
+//*****************************************************************************
+// cascading Mark of all ParamDef associated with a methoddef
+//*****************************************************************************
+HRESULT FilterManager::MarkParamsWithParentToken(mdMethodDef md)
+{
+ HRESULT hr = NOERROR;
+ RID ulStart, ulEnd;
+ RID index;
+ MethodRec *pMethodRec;
+
+ IfFailGo(m_pMiniMd->GetMethodRecord(RidFromToken(md), &pMethodRec));
+
+ // figure out the start rid and end rid of the parameter list of this methoddef
+ ulStart = m_pMiniMd->getParamListOfMethod(pMethodRec);
+ IfFailGo(m_pMiniMd->getEndParamListOfMethod(RidFromToken(md), &ulEnd));
+ for (index = ulStart; index < ulEnd; index ++ )
+ {
+ RID rid;
+ IfFailGo(m_pMiniMd->GetParamRid(index, &rid));
+ IfFailGo(MarkParam(TokenFromRid(
+ rid,
+ mdtParamDef)));
+ }
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkParamsWithParentToken()
+
+
+//*****************************************************************************
+// cascading Mark of all methods associated with a TypeDef token
+//*****************************************************************************
+HRESULT FilterManager::MarkMethodsWithParentToken(mdTypeDef td)
+{
+ HRESULT hr = NOERROR;
+ RID ulStart, ulEnd;
+ RID index;
+ TypeDefRec *pTypeDefRec;
+
+ IfFailGo(m_pMiniMd->GetTypeDefRecord(RidFromToken(td), &pTypeDefRec));
+ ulStart = m_pMiniMd->getMethodListOfTypeDef( pTypeDefRec );
+ IfFailGo(m_pMiniMd->getEndMethodListOfTypeDef(RidFromToken(td), &ulEnd));
+ for ( index = ulStart; index < ulEnd; index ++ )
+ {
+ RID rid;
+ IfFailGo(m_pMiniMd->GetMethodRid(index, &rid));
+ IfFailGo(MarkMethod(TokenFromRid(
+ rid,
+ mdtMethodDef)));
+ }
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkMethodsWithParentToken()
+
+
+//*****************************************************************************
+// cascading Mark of all MethodImpls associated with a TypeDef token
+//*****************************************************************************
+HRESULT FilterManager::MarkMethodImplsWithParentToken(mdTypeDef td)
+{
+ HRESULT hr = NOERROR;
+ RID index;
+ mdToken tkBody;
+ mdToken tkDecl;
+ MethodImplRec *pMethodImplRec;
+ HENUMInternal hEnum;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME(m_pMiniMd->GetFilterTable() != NULL);
+
+ memset(&hEnum, 0, sizeof(HENUMInternal));
+ IfFailGo( m_pMiniMd->FindMethodImplHelper(td, &hEnum) );
+
+ while (HENUMInternal::EnumNext(&hEnum, (mdToken *)&index))
+ {
+ IfFailGo(m_pMiniMd->GetMethodImplRecord(index, &pMethodImplRec));
+ IfFailGo(m_pMiniMd->GetFilterTable()->MarkMethodImpl(index));
+
+ tkBody = m_pMiniMd->getMethodBodyOfMethodImpl(pMethodImplRec);
+ IfFailGo( Mark(tkBody) );
+
+ tkDecl = m_pMiniMd->getMethodDeclarationOfMethodImpl(pMethodImplRec);
+ IfFailGo( Mark(tkDecl) );
+ }
+ErrExit:
+ HENUMInternal::ClearEnum(&hEnum);
+ return hr;
+} // HRESULT FilterManager::MarkMethodImplsWithParentToken()
+
+
+//*****************************************************************************
+// cascading Mark of all fields associated with a TypeDef token
+//*****************************************************************************
+HRESULT FilterManager::MarkFieldsWithParentToken(mdTypeDef td)
+{
+ HRESULT hr = NOERROR;
+ RID ulStart, ulEnd;
+ RID index;
+ TypeDefRec *pTypeDefRec;
+
+ IfFailGo(m_pMiniMd->GetTypeDefRecord(RidFromToken(td), &pTypeDefRec));
+ ulStart = m_pMiniMd->getFieldListOfTypeDef( pTypeDefRec );
+ IfFailGo(m_pMiniMd->getEndFieldListOfTypeDef(RidFromToken(td), &ulEnd));
+ for ( index = ulStart; index < ulEnd; index ++ )
+ {
+ RID rid;
+ IfFailGo(m_pMiniMd->GetFieldRid(index, &rid));
+ IfFailGo(MarkField(TokenFromRid(
+ rid,
+ mdtFieldDef)));
+ }
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkFieldsWithParentToken()
+
+
+//*****************************************************************************
+// cascading Mark of all events associated with a TypeDef token
+//*****************************************************************************
+HRESULT FilterManager::MarkEventsWithParentToken(
+ mdTypeDef td)
+{
+ HRESULT hr = NOERROR;
+ RID ridEventMap;
+ RID ulStart, ulEnd;
+ RID index;
+ EventMapRec *pEventMapRec;
+
+ // get the starting/ending rid of Events of this typedef
+ IfFailGo(m_pMiniMd->FindEventMapFor(RidFromToken(td), &ridEventMap));
+ if ( !InvalidRid(ridEventMap) )
+ {
+ IfFailGo(m_pMiniMd->GetEventMapRecord(ridEventMap, &pEventMapRec));
+ ulStart = m_pMiniMd->getEventListOfEventMap( pEventMapRec );
+ IfFailGo(m_pMiniMd->getEndEventListOfEventMap(ridEventMap, &ulEnd));
+ for ( index = ulStart; index < ulEnd; index ++ )
+ {
+ RID rid;
+ IfFailGo(m_pMiniMd->GetEventRid(index, &rid));
+ IfFailGo(MarkEvent(TokenFromRid(
+ rid,
+ mdtEvent)));
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkEventsWithParentToken()
+
+
+
+//*****************************************************************************
+// cascading Mark of all properties associated with a TypeDef token
+//*****************************************************************************
+HRESULT FilterManager::MarkPropertiesWithParentToken(
+ mdTypeDef td)
+{
+ HRESULT hr = NOERROR;
+ RID ridPropertyMap;
+ RID ulStart, ulEnd;
+ RID index;
+ PropertyMapRec *pPropertyMapRec;
+
+ // get the starting/ending rid of properties of this typedef
+ IfFailGo(m_pMiniMd->FindPropertyMapFor(RidFromToken(td), &ridPropertyMap));
+ if ( !InvalidRid(ridPropertyMap) )
+ {
+ IfFailGo(m_pMiniMd->GetPropertyMapRecord(ridPropertyMap, &pPropertyMapRec));
+ ulStart = m_pMiniMd->getPropertyListOfPropertyMap( pPropertyMapRec );
+ IfFailGo(m_pMiniMd->getEndPropertyListOfPropertyMap(ridPropertyMap, &ulEnd));
+ for ( index = ulStart; index < ulEnd; index ++ )
+ {
+ RID rid;
+ IfFailGo(m_pMiniMd->GetPropertyRid(index, &rid));
+ IfFailGo(MarkProperty(TokenFromRid(
+ rid,
+ mdtProperty)));
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkPropertiesWithParentToken()
+
+
+//*****************************************************************************
+// cascading Mark of all GenericPar associated with a TypeDef or MethodDef token
+//*****************************************************************************
+HRESULT FilterManager::MarkGenericParamWithParentToken(
+ mdToken tk)
+{
+ HRESULT hr = NOERROR;
+ RID ulStart, ulEnd;
+ RID index;
+ GenericParamRec *pGenericParamRec;
+ mdToken constraint;
+ HENUMInternal hEnum; // To enumerate constraints.
+
+ // Enumerate the GenericPar
+ //@todo: Handle the unsorted case.
+ IfFailGo( m_pMiniMd->GetGenericParamsForToken(tk, &ulStart, &ulEnd) );
+
+ for (; ulStart < ulEnd; ++ulStart)
+ {
+ index = m_pMiniMd->GetGenericParamRid(ulStart);
+ IfFailGo(m_pMiniMd->GetGenericParamRecord(index, &pGenericParamRec));
+
+ RID ridConstraint;
+ IfFailGo( m_pMiniMd->FindGenericParamConstraintHelper(TokenFromRid(ulStart, mdtGenericParam), &hEnum) );
+ while (HENUMInternal::EnumNext(&hEnum, (mdToken *) &ridConstraint))
+ {
+ // Get the constraint.
+ GenericParamConstraintRec *pRec;
+ IfFailGo(m_pMiniMd->GetGenericParamConstraintRecord(RidFromToken(ridConstraint), &pRec));
+ constraint = m_pMiniMd->getConstraintOfGenericParamConstraint(pRec);
+
+ // Mark it.
+ IfFailGo( Mark(constraint) );
+ }
+ HENUMInternal::ClearEnum(&hEnum);
+ }
+
+ErrExit:
+ HENUMInternal::ClearEnum(&hEnum);
+
+ return hr;
+} // HRESULT FilterManager::MarkGenericParamWithParentToken()
+
+
+//*****************************************************************************
+// cascading Mark of an TypeDef token
+//*****************************************************************************
+HRESULT FilterManager::MarkInterfaceImpls(
+ mdTypeDef td)
+{
+ HRESULT hr = NOERROR;
+ ULONG ridStart, ridEnd;
+ ULONG i;
+ InterfaceImplRec *pRec;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME(m_pMiniMd->GetFilterTable() != NULL);
+
+ if ( m_pMiniMd->IsSorted(TBL_InterfaceImpl) )
+ {
+ IfFailGo(m_pMiniMd->getInterfaceImplsForTypeDef(RidFromToken(td), &ridEnd, &ridStart));
+ }
+ else
+ {
+ ridStart = 1;
+ ridEnd = m_pMiniMd->getCountInterfaceImpls() + 1;
+ }
+
+ // Search for the interfaceimpl with the parent of td
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ IfFailGo(m_pMiniMd->GetInterfaceImplRecord(i, &pRec));
+ if ( td != m_pMiniMd->getClassOfInterfaceImpl(pRec) )
+ continue;
+
+ // found an InterfaceImpl associate with td. Mark the interface row and the interfaceimpl type
+ IfFailGo( m_pMiniMd->GetFilterTable()->MarkInterfaceImpl(TokenFromRid(i, mdtInterfaceImpl)) );
+ IfFailGo( MarkCustomAttributesWithParentToken(TokenFromRid(i, mdtInterfaceImpl)) );
+ // IfFailGo( MarkDeclSecuritiesWithParentToken(TokenFromRid(i, mdtInterfaceImpl)) );
+ IfFailGo( Mark(m_pMiniMd->getInterfaceOfInterfaceImpl(pRec)) );
+ }
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkInterfaceImpls()
+
+//*****************************************************************************
+// cascading Mark of an TypeDef token
+//*****************************************************************************
+HRESULT FilterManager::MarkTypeDef(
+ mdTypeDef td)
+{
+ HRESULT hr = NOERROR;
+ TypeDefRec *pRec;
+ IHostFilter *pFilter = m_pMiniMd->GetHostFilter();
+ DWORD dwFlags;
+ RID iNester;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME(m_pMiniMd->GetFilterTable() != NULL);
+
+ // if TypeDef is already marked, just return
+ if (m_pMiniMd->GetFilterTable()->IsTypeDefMarked(td))
+ goto ErrExit;
+
+ // Mark the TypeDef first to avoid duplicate marking
+ IfFailGo( m_pMiniMd->GetFilterTable()->MarkTypeDef(td) );
+ if (pFilter)
+ pFilter->MarkToken(td);
+
+ // We don't need to mark InterfaceImpl but we need to mark the
+ // TypeDef/TypeRef associated with InterfaceImpl.
+ IfFailGo( MarkInterfaceImpls(td) );
+
+ // mark the base class
+ IfFailGo(m_pMiniMd->GetTypeDefRecord(RidFromToken(td), &pRec));
+ IfFailGo( Mark(m_pMiniMd->getExtendsOfTypeDef(pRec)) );
+
+ // mark all of the children of this TypeDef
+ IfFailGo( MarkMethodsWithParentToken(td) );
+ IfFailGo( MarkMethodImplsWithParentToken(td) );
+ IfFailGo( MarkFieldsWithParentToken(td) );
+ IfFailGo( MarkEventsWithParentToken(td) );
+ IfFailGo( MarkPropertiesWithParentToken(td) );
+
+ // mark any GenericParam of this TypeDef
+ IfFailGo( MarkGenericParamWithParentToken(td) );
+
+ // mark custom value and permission
+ IfFailGo( MarkCustomAttributesWithParentToken(td) );
+ IfFailGo( MarkDeclSecuritiesWithParentToken(td) );
+
+ // If the class is a Nested class mark the parent, recursively.
+ dwFlags = m_pMiniMd->getFlagsOfTypeDef(pRec);
+ if (IsTdNested(dwFlags))
+ {
+ NestedClassRec *pNestClassRec;
+ IfFailGo(m_pMiniMd->FindNestedClassHelper(td, &iNester));
+ if (InvalidRid(iNester))
+ IfFailGo(CLDB_E_RECORD_NOTFOUND);
+ IfFailGo(m_pMiniMd->GetNestedClassRecord(iNester, &pNestClassRec));
+ IfFailGo(MarkTypeDef(m_pMiniMd->getEnclosingClassOfNestedClass(pNestClassRec)));
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT FilterManager::MarkTypeDef()
+
+
+//*****************************************************************************
+// walk signature and mark tokens embedded in the signature
+//*****************************************************************************
+
+#define VALIDATE_SIGNATURE_LEN(x) \
+ do{ cb = (x); \
+ cbUsed += cb; pbSig += cb; \
+ if (cbUsed > cbSig) IfFailGo(META_E_BAD_SIGNATURE); \
+ }while (0)
+
+#define VALIDATE_SIGNATURE_LEN_HR(x) \
+ do{ IfFailGo(x); \
+ cbUsed += cb; pbSig += cb; \
+ if (cbUsed > cbSig) IfFailGo(META_E_BAD_SIGNATURE); \
+ }while (0)
+
+HRESULT FilterManager::MarkSignature(
+ PCCOR_SIGNATURE pbSig, // [IN] point to the current byte to visit in the signature
+ ULONG cbSig, // [IN] count of bytes available.
+ ULONG *pcbUsed) // [OUT] count of bytes consumed.
+{
+ HRESULT hr = NOERROR; // A result.
+ ULONG cArg = 0; // count of arguments in the signature
+ ULONG cTypes = 0; // Count of argument types in the signature.
+ ULONG cb; // Bytes used in a sig element.
+ ULONG cbUsed = 0; // Total bytes consumed.
+ ULONG callingconv = IMAGE_CEE_CS_CALLCONV_MAX;
+
+ // calling convention
+ VALIDATE_SIGNATURE_LEN( CorSigUncompressData(pbSig, &callingconv) );
+
+ if ((callingconv & IMAGE_CEE_CS_CALLCONV_MASK) >= IMAGE_CEE_CS_CALLCONV_MAX)
+ IfFailGo(META_E_BAD_SIGNATURE);
+
+ // Field signature is a single element.
+ if (isCallConv(callingconv, IMAGE_CEE_CS_CALLCONV_FIELD))
+ {
+ // It is a FieldDef
+ VALIDATE_SIGNATURE_LEN_HR( MarkFieldSignature(pbSig, cbSig - cbUsed, &cb) );
+ }
+ else
+ {
+ // If Generic call, get count of type parameters.
+ //@TODO: where are the type params?
+ if (callingconv & IMAGE_CEE_CS_CALLCONV_GENERIC)
+ {
+ VALIDATE_SIGNATURE_LEN( CorSigUncompressData(pbSig, &cTypes) );
+ }
+
+ // Count of arguments passed in call.
+ VALIDATE_SIGNATURE_LEN( CorSigUncompressData(pbSig, &cArg) );
+
+ // Mark the return type, if there is one (LocalVarSig and GenericInst don't have return types).
+ if ( !( isCallConv(callingconv, IMAGE_CEE_CS_CALLCONV_LOCAL_SIG) || isCallConv(callingconv, IMAGE_CEE_CS_CALLCONV_GENERICINST)) )
+ { // process the return type
+ VALIDATE_SIGNATURE_LEN_HR( MarkFieldSignature(pbSig, cbSig - cbUsed, &cb) );
+ }
+
+ // Iterate over the arguments, and mark each one.
+ while (cArg--)
+ {
+ VALIDATE_SIGNATURE_LEN_HR( MarkFieldSignature(pbSig, cbSig - cbUsed, &cb) );
+ }
+ }
+
+ErrExit:
+ *pcbUsed = cbUsed;
+ return hr;
+} // HRESULT FilterManager::MarkSignature()
+
+
+//*****************************************************************************
+// walk one type and mark tokens embedded in the signature
+//*****************************************************************************
+HRESULT FilterManager::MarkFieldSignature(
+ PCCOR_SIGNATURE pbSig, // [IN] point to the current byte to visit in the signature
+ ULONG cbSig, // [IN] count of bytes available.
+ ULONG *pcbUsed) // [OUT] count of bytes consumed.
+{
+ HRESULT hr = NOERROR; // A result.
+ ULONG cb; // Bytes in one signature element.
+ ULONG cbUsed = 0; // Total bytes consumed from signature.
+ CorElementType ulElementType; // ELEMENT_TYPE_xxx from signature.
+ ULONG ulData; // Some data (like a count) from the signature.
+ ULONG ulTemp; // Unused data.
+ mdToken token; // A token from the signature.
+ int iData; // Integer data from signature.
+
+ VALIDATE_SIGNATURE_LEN( CorSigUncompressElementType(pbSig, &ulElementType) );
+
+ // Skip the modifiers...
+ while (CorIsModifierElementType((CorElementType) ulElementType))
+ {
+ VALIDATE_SIGNATURE_LEN( CorSigUncompressElementType(pbSig, &ulElementType) );
+ }
+
+ // Examine the signature element
+ switch (ulElementType)
+ {
+ case ELEMENT_TYPE_SZARRAY:
+ // syntax: SZARRAY <BaseType>
+
+ // conver the base type for the SZARRAY or GENERICARRAY
+ VALIDATE_SIGNATURE_LEN_HR( MarkFieldSignature(pbSig, cbSig - cbUsed, &cb) );
+ break;
+
+ case ELEMENT_TYPE_CMOD_REQD:
+ case ELEMENT_TYPE_CMOD_OPT:
+ // syntax: {CMOD_REQD|CMOD_OPT} <token> <signature>
+
+ // now get the embedded token
+ VALIDATE_SIGNATURE_LEN( CorSigUncompressToken(pbSig, &token) );
+
+ // Mark the token
+ IfFailGo( Mark(token) );
+
+ // mark the base type
+ VALIDATE_SIGNATURE_LEN_HR( MarkFieldSignature(pbSig, cbSig - cbUsed, &cb) );
+ break;
+
+ case ELEMENT_TYPE_VAR:
+ case ELEMENT_TYPE_MVAR:
+ // syntax: VAR <index>
+ VALIDATE_SIGNATURE_LEN( CorSigUncompressData(pbSig, &ulData) );
+ break;
+
+ case ELEMENT_TYPE_ARRAY:
+ // syntax: ARRAY BaseType <rank> [i size_1... size_i] [j lowerbound_1 ... lowerbound_j]
+
+ VALIDATE_SIGNATURE_LEN_HR( MarkFieldSignature(pbSig, cbSig - cbUsed, &cb) );
+
+ // Parse for the rank
+ VALIDATE_SIGNATURE_LEN( CorSigUncompressData(pbSig, &ulData) );
+
+ // if rank == 0, we are done
+ if (ulData == 0)
+ break;
+
+ // Any size of dimension specified?
+ VALIDATE_SIGNATURE_LEN( CorSigUncompressData(pbSig, &ulData) );
+
+ // Consume sizes of dimension.
+ while (ulData--)
+ {
+ VALIDATE_SIGNATURE_LEN( CorSigUncompressData(pbSig, &ulTemp) );
+ }
+
+ // Any lower bounds specified?
+ VALIDATE_SIGNATURE_LEN( CorSigUncompressData(pbSig, &ulData) );
+
+ // Consume lower bounds.
+ while (ulData--)
+ {
+ VALIDATE_SIGNATURE_LEN( CorSigUncompressSignedInt(pbSig, &iData) );
+ }
+
+ break;
+
+ case ELEMENT_TYPE_FNPTR:
+ // function pointer is followed by another complete signature
+ VALIDATE_SIGNATURE_LEN_HR( MarkSignature(pbSig, cbSig - cbUsed, &cb) );
+ break;
+
+ case ELEMENT_TYPE_VALUETYPE:
+ case ELEMENT_TYPE_CLASS:
+ // syntax: {CLASS | VALUECLASS} <token>
+ VALIDATE_SIGNATURE_LEN( CorSigUncompressToken(pbSig, &token) );
+
+ // Mark it.
+ IfFailGo( Mark(token) );
+ break;
+
+ case ELEMENT_TYPE_GENERICINST:
+ // syntax: ELEMENT_TYPE_GEENRICINST <ELEMENT_TYPE_CLASS | ELEMENT_TYPE_VALUECLASS> <token> <n> <n params>
+ VALIDATE_SIGNATURE_LEN_HR( MarkFieldSignature(pbSig, cbSig - cbUsed, &cb) );
+
+ // Get the number of generic parameters
+ VALIDATE_SIGNATURE_LEN( CorSigUncompressData(pbSig, &ulData) );
+
+ // Get the generic parameters
+ while (ulData--)
+ {
+ VALIDATE_SIGNATURE_LEN_HR( MarkFieldSignature(pbSig, cbSig - cbUsed, &cb) );
+ }
+ break;
+
+ default:
+ // If valid element (I4, etc), great. Otherwise, return error.
+ if ((ulElementType >= ELEMENT_TYPE_MAX) ||
+ (ulElementType == ELEMENT_TYPE_PTR) ||
+ (ulElementType == ELEMENT_TYPE_BYREF) ||
+ (ulElementType == ELEMENT_TYPE_VALUEARRAY_UNSUPPORTED))
+ {
+ IfFailGo(META_E_BAD_SIGNATURE);
+ }
+ break;
+ }
+
+ErrExit:
+ *pcbUsed = cbUsed;
+ return hr;
+} // HRESULT FilterManager::MarkFieldSignature()
+
+
+
+//*****************************************************************************
+//
+// Unmark the TypeDef
+//
+//*****************************************************************************
+HRESULT FilterManager::UnmarkTypeDef(
+ mdTypeDef td)
+{
+ HRESULT hr = NOERROR;
+ TypeDefRec *pTypeDefRec;
+ RID ridStart, ridEnd;
+ RID index;
+ CustomAttributeRec *pCARec;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME(m_pMiniMd->GetFilterTable() != NULL);
+
+ // if TypeDef is already unmarked, just return
+ if (m_pMiniMd->GetFilterTable()->IsTypeDefMarked(td) == false)
+ goto ErrExit;
+
+ // Mark the TypeDef first to avoid duplicate marking
+ IfFailGo( m_pMiniMd->GetFilterTable()->UnmarkTypeDef(td) );
+
+ // Don't need to unmark InterfaceImpl because the TypeDef is unmarked that will make
+ // the InterfaceImpl automatically unmarked.
+
+ // unmark all of the children of this TypeDef
+ IfFailGo(m_pMiniMd->GetTypeDefRecord(RidFromToken(td), &pTypeDefRec));
+
+ // unmark the methods
+ ridStart = m_pMiniMd->getMethodListOfTypeDef(pTypeDefRec);
+ IfFailGo(m_pMiniMd->getEndMethodListOfTypeDef(RidFromToken(td), &ridEnd));
+ for ( index = ridStart; index < ridEnd; index ++ )
+ {
+ RID rid;
+ IfFailGo(m_pMiniMd->GetMethodRid(index, &rid));
+ IfFailGo(m_pMiniMd->GetFilterTable()->UnmarkMethod(TokenFromRid(
+ rid,
+ mdtMethodDef)));
+ }
+
+ // unmark the fields
+ ridStart = m_pMiniMd->getFieldListOfTypeDef(pTypeDefRec);
+ IfFailGo(m_pMiniMd->getEndFieldListOfTypeDef(RidFromToken(td), &ridEnd));
+ for ( index = ridStart; index < ridEnd; index ++ )
+ {
+ RID rid;
+ IfFailGo(m_pMiniMd->GetFieldRid(index, &rid));
+ IfFailGo(m_pMiniMd->GetFilterTable()->UnmarkField(TokenFromRid(
+ rid,
+ mdtFieldDef)));
+ }
+
+ // unmark custom value
+ if ( m_pMiniMd->IsSorted( TBL_CustomAttribute ) )
+ {
+ // table is sorted. ridStart to ridEnd - 1 are all CustomAttribute
+ // associated with tkParent
+ //
+ IfFailGo(m_pMiniMd->getCustomAttributeForToken(td, &ridEnd, &ridStart));
+ for (index = ridStart; index < ridEnd; index ++ )
+ {
+ IfFailGo( m_pMiniMd->GetFilterTable()->UnmarkCustomAttribute( TokenFromRid(index, mdtCustomAttribute) ) );
+ }
+ }
+ else
+ {
+ // table scan is needed
+ ridStart = 1;
+ ridEnd = m_pMiniMd->getCountCustomAttributes() + 1;
+ for (index = ridStart; index < ridEnd; index ++ )
+ {
+ IfFailGo(m_pMiniMd->GetCustomAttributeRecord(index, &pCARec));
+ if ( td == m_pMiniMd->getParentOfCustomAttribute(pCARec) )
+ {
+ // This CustomAttribute is associated with tkParent
+ IfFailGo( m_pMiniMd->GetFilterTable()->UnmarkCustomAttribute( TokenFromRid(index, mdtCustomAttribute) ) );
+ }
+ }
+ }
+
+ // We don't support nested type!!
+
+ErrExit:
+ return hr;
+
+} // HRESULT FilterManager::UnmarkTypeDef()
+
+
diff --git a/src/md/compiler/filtermanager.h b/src/md/compiler/filtermanager.h
new file mode 100644
index 0000000000..374afb7dfd
--- /dev/null
+++ b/src/md/compiler/filtermanager.h
@@ -0,0 +1,87 @@
+// 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.
+//*****************************************************************************
+// FilterManager.h
+//
+
+//
+// Contains utility code for MD directory
+//
+//*****************************************************************************
+#ifndef __FilterManager__h__
+#define __FilterManager__h__
+
+
+
+
+//*********************************************************************
+// FilterManager Class
+//*********************************************************************
+class FilterManager
+{
+public:
+ FilterManager(CMiniMdRW *pMiniMd) {m_pMiniMd = pMiniMd; hasModuleBeenMarked = false; hasAssemblyBeenMarked = false;}
+ ~FilterManager() {};
+
+ HRESULT Mark(mdToken tk);
+
+ // Unmark helper
+ HRESULT UnmarkTypeDef(mdTypeDef td);
+ HRESULT MarkNewUserString(mdString str);
+
+
+private:
+ HRESULT MarkCustomAttribute(mdCustomAttribute cv);
+ HRESULT MarkDeclSecurity(mdPermission pe);
+ HRESULT MarkStandAloneSig(mdSignature sig);
+ HRESULT MarkTypeSpec(mdTypeSpec ts);
+ HRESULT MarkTypeRef(mdTypeRef tr);
+ HRESULT MarkMemberRef(mdMemberRef mr);
+ HRESULT MarkModuleRef(mdModuleRef mr);
+ HRESULT MarkAssemblyRef(mdAssemblyRef ar);
+ HRESULT MarkModule(mdModule mo);
+ HRESULT MarkAssembly(mdAssembly as);
+ HRESULT MarkInterfaceImpls(mdTypeDef td);
+ HRESULT MarkUserString(mdString str);
+
+ HRESULT MarkMethodSpec(mdMethodSpec ms);
+
+ HRESULT MarkCustomAttributesWithParentToken(mdToken tkParent);
+ HRESULT MarkDeclSecuritiesWithParentToken(mdToken tkParent);
+ HRESULT MarkMemberRefsWithParentToken(mdToken tk);
+
+ HRESULT MarkParam(mdParamDef pd);
+ HRESULT MarkMethod(mdMethodDef md);
+ HRESULT MarkField(mdFieldDef fd);
+ HRESULT MarkEvent(mdEvent ev);
+ HRESULT MarkProperty(mdProperty pr);
+
+ HRESULT MarkParamsWithParentToken(mdMethodDef md);
+ HRESULT MarkMethodsWithParentToken(mdTypeDef td);
+ HRESULT MarkMethodImplsWithParentToken(mdTypeDef td);
+ HRESULT MarkFieldsWithParentToken(mdTypeDef td);
+ HRESULT MarkEventsWithParentToken(mdTypeDef td);
+ HRESULT MarkPropertiesWithParentToken(mdTypeDef td);
+
+ HRESULT MarkGenericParamWithParentToken(mdToken tk);
+
+
+ HRESULT MarkTypeDef(mdTypeDef td);
+
+
+ // <TODO>We don't want to keep track the debug info with bits because these are going away...</TODO>
+ HRESULT MarkMethodDebugInfo(mdMethodDef md);
+
+ // walk the signature and mark all of the embedded TypeDef or TypeRef
+ HRESULT MarkSignature(PCCOR_SIGNATURE pbSig, ULONG cbSig, ULONG *pcbUsed);
+ HRESULT MarkFieldSignature(PCCOR_SIGNATURE pbSig, ULONG cbSig, ULONG *pcbUsed);
+
+
+private:
+ CMiniMdRW *m_pMiniMd;
+ bool hasModuleBeenMarked;
+ bool hasAssemblyBeenMarked;
+};
+
+#endif // __FilterManager__h__
diff --git a/src/md/compiler/helper.cpp b/src/md/compiler/helper.cpp
new file mode 100644
index 0000000000..0727176f07
--- /dev/null
+++ b/src/md/compiler/helper.cpp
@@ -0,0 +1,445 @@
+// 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.
+//*****************************************************************************
+// Helper.cpp
+//
+
+//
+// Implementation of some internal APIs from code:IMetaDataHelper and code:IMetaDataEmitHelper.
+//
+//*****************************************************************************
+#include "stdafx.h"
+#include "regmeta.h"
+#include "importhelper.h"
+#include "mdlog.h"
+
+#if defined(FEATURE_METADATA_EMIT) || defined(FEATURE_METADATA_INTERNAL_APIS)
+
+//*****************************************************************************
+// translating signature from one scope to another scope
+//
+// Implements public API code:IMetaDataEmit::TranslateSigWithScope.
+// Implements internal API code:IMetaDataHelper::TranslateSigWithScope.
+//*****************************************************************************
+STDMETHODIMP RegMeta::TranslateSigWithScope( // S_OK or error.
+ IMetaDataAssemblyImport *pAssemImport, // [IN] importing assembly interface
+ const void *pbHashValue, // [IN] Hash Blob for Assembly.
+ ULONG cbHashValue, // [IN] Count of bytes.
+ IMetaDataImport *pImport, // [IN] importing interface
+ PCCOR_SIGNATURE pbSigBlob, // [IN] signature in the importing scope
+ ULONG cbSigBlob, // [IN] count of bytes of signature
+ IMetaDataAssemblyEmit *pAssemEmit,// [IN] emit assembly interface
+ IMetaDataEmit *pEmit, // [IN] emit interface
+ PCOR_SIGNATURE pvTranslatedSig, // [OUT] buffer to hold translated signature
+ ULONG cbTranslatedSigMax,
+ ULONG *pcbTranslatedSig) // [OUT] count of bytes in the translated signature
+{
+#ifdef FEATURE_METADATA_EMIT
+ HRESULT hr = S_OK;
+
+ IMDCommon *pAssemImportMDCommon = NULL;
+ IMDCommon *pImportMDCommon = NULL;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ RegMeta *pRegMetaAssemEmit = static_cast<RegMeta*>(pAssemEmit);
+ RegMeta *pRegMetaEmit = NULL;
+
+ CQuickBytes qkSigEmit;
+ ULONG cbEmit;
+
+ pRegMetaEmit = static_cast<RegMeta*>(pEmit);
+
+ {
+ // This function can cause new TypeRef being introduced.
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ _ASSERTE(pvTranslatedSig && pcbTranslatedSig);
+
+ if (pAssemImport)
+ {
+ IfFailGo(pAssemImport->QueryInterface(IID_IMDCommon, (void**)&pAssemImportMDCommon));
+ }
+ IMetaModelCommon *pAssemImportMetaModelCommon = pAssemImportMDCommon ? pAssemImportMDCommon->GetMetaModelCommon() : 0;
+
+ IfFailGo(pImport->QueryInterface(IID_IMDCommon, (void**)&pImportMDCommon));
+ IMetaModelCommon *pImportMetaModelCommon = pImportMDCommon->GetMetaModelCommon();
+
+ IfFailGo( ImportHelper::MergeUpdateTokenInSig( // S_OK or error.
+ pRegMetaAssemEmit ? &(pRegMetaAssemEmit->m_pStgdb->m_MiniMd) : 0, // The assembly emit scope.
+ &(pRegMetaEmit->m_pStgdb->m_MiniMd), // The emit scope.
+ pAssemImportMetaModelCommon, // Assembly where the signature is from.
+ pbHashValue, // Hash value for the import assembly.
+ cbHashValue, // Size in bytes.
+ pImportMetaModelCommon, // The scope where signature is from.
+ pbSigBlob, // signature from the imported scope
+ NULL, // Internal OID mapping structure.
+ &qkSigEmit, // [OUT] translated signature
+ 0, // start from first byte of the signature
+ 0, // don't care how many bytes consumed
+ &cbEmit)); // [OUT] total number of bytes write to pqkSigEmit
+ memcpy(pvTranslatedSig, qkSigEmit.Ptr(), cbEmit > cbTranslatedSigMax ? cbTranslatedSigMax :cbEmit );
+ *pcbTranslatedSig = cbEmit;
+ if (cbEmit > cbTranslatedSigMax)
+ hr = CLDB_S_TRUNCATION;
+ }
+
+ErrExit:
+ END_ENTRYPOINT_NOTHROW;
+
+ if (pAssemImportMDCommon)
+ pAssemImportMDCommon->Release();
+ if (pImportMDCommon)
+ pImportMDCommon->Release();
+
+ return hr;
+#else //!FEATURE_METADATA_EMIT
+ return E_NOTIMPL;
+#endif //!FEATURE_METADATA_EMIT
+} // RegMeta::TranslateSigWithScope
+
+#endif //FEATURE_METADATA_EMIT || FEATURE_METADATA_INTERNAL_APIS
+
+#if defined(FEATURE_METADATA_EMIT) && defined(FEATURE_METADATA_INTERNAL_APIS)
+
+//*****************************************************************************
+// Helper : Set ResolutionScope of a TypeRef
+//
+// Implements internal API code:IMetaDataEmitHelper::SetResolutionScopeHelper.
+//*****************************************************************************
+HRESULT RegMeta::SetResolutionScopeHelper( // Return hresult.
+ mdTypeRef tr, // [IN] TypeRef record to update
+ mdToken rs) // [IN] new ResolutionScope
+{
+ HRESULT hr = NOERROR;
+ TypeRefRec * pTypeRef;
+
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetTypeRefRecord(RidFromToken(tr), &pTypeRef));
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_TypeRef, TypeRefRec::COL_ResolutionScope, pTypeRef, rs));
+
+ErrExit:
+ return hr;
+} // RegMeta::SetResolutionScopeHelper
+
+
+//*****************************************************************************
+// Helper : Set offset of a ManifestResource
+//
+// Implements internal API code:IMetaDataEmitHelper::SetManifestResourceOffsetHelper.
+//*****************************************************************************
+HRESULT
+RegMeta::SetManifestResourceOffsetHelper(
+ mdManifestResource mr, // [IN] The manifest token
+ ULONG ulOffset) // [IN] new offset
+{
+ HRESULT hr = NOERROR;
+ ManifestResourceRec * pRec;
+
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetManifestResourceRecord(RidFromToken(mr), &pRec));
+ pRec->SetOffset(ulOffset);
+
+ErrExit:
+ return hr;
+} // RegMeta::SetManifestResourceOffsetHelper
+
+//*******************************************************************************
+//
+// Following APIs are used by reflection emit.
+//
+//*******************************************************************************
+
+//*******************************************************************************
+// helper to define method semantics
+//
+// Implements internal API code:IMetaDataEmitHelper::DefineMethodSemanticsHelper.
+//*******************************************************************************
+HRESULT RegMeta::DefineMethodSemanticsHelper(
+ mdToken tkAssociation, // [IN] property or event token
+ DWORD dwFlags, // [IN] semantics
+ mdMethodDef md) // [IN] method to associated with
+{
+ HRESULT hr;
+ LOCKWRITE();
+ hr = _DefineMethodSemantics((USHORT) dwFlags, md, tkAssociation, false);
+
+ErrExit:
+ return hr;
+} // RegMeta::DefineMethodSemantics
+
+//*******************************************************************************
+// helper to set field layout
+//
+// Implements internal API code:IMetaDataEmitHelper::SetFieldLayoutHelper.
+//*******************************************************************************
+HRESULT RegMeta::SetFieldLayoutHelper( // Return hresult.
+ mdFieldDef fd, // [IN] field to associate the layout info
+ ULONG ulOffset) // [IN] the offset for the field
+{
+ HRESULT hr;
+ FieldLayoutRec *pFieldLayoutRec;
+ RID iFieldLayoutRec;
+
+ LOCKWRITE();
+
+ if (ulOffset == ULONG_MAX)
+ {
+ // invalid argument
+ IfFailGo( E_INVALIDARG );
+ }
+
+ // create a field layout record
+ IfFailGo(m_pStgdb->m_MiniMd.AddFieldLayoutRecord(&pFieldLayoutRec, &iFieldLayoutRec));
+
+ // Set the Field entry.
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(
+ TBL_FieldLayout,
+ FieldLayoutRec::COL_Field,
+ pFieldLayoutRec,
+ fd));
+ pFieldLayoutRec->SetOffSet(ulOffset);
+ IfFailGo( m_pStgdb->m_MiniMd.AddFieldLayoutToHash(iFieldLayoutRec) );
+
+ErrExit:
+
+ return hr;
+} // RegMeta::SetFieldLayout
+
+//*******************************************************************************
+// helper to define event
+//
+// Implements internal API code:IMetaDataEmitHelper::DefineEventHelper.
+//*******************************************************************************
+STDMETHODIMP RegMeta::DefineEventHelper( // Return hresult.
+ mdTypeDef td, // [IN] the class/interface on which the event is being defined
+ LPCWSTR szEvent, // [IN] Name of the event
+ DWORD dwEventFlags, // [IN] CorEventAttr
+ mdToken tkEventType, // [IN] a reference (mdTypeRef or mdTypeRef) to the Event class
+ mdEvent *pmdEvent) // [OUT] output event token
+{
+ HRESULT hr = S_OK;
+ LOG((LOGMD, "MD RegMeta::DefineEventHelper(0x%08x, %S, 0x%08x, 0x%08x, 0x%08x)\n",
+ td, szEvent, dwEventFlags, tkEventType, pmdEvent));
+
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ hr = _DefineEvent(td, szEvent, dwEventFlags, tkEventType, pmdEvent);
+
+ErrExit:
+ return hr;
+} // RegMeta::DefineEvent
+
+
+//*******************************************************************************
+// helper to add a declarative security blob to a class or method
+//
+// Implements internal API code:IMetaDataEmitHelper::AddDeclarativeSecurityHelper.
+//*******************************************************************************
+STDMETHODIMP RegMeta::AddDeclarativeSecurityHelper(
+ mdToken tk, // [IN] Parent token (typedef/methoddef)
+ DWORD dwAction, // [IN] Security action (CorDeclSecurity)
+ void const *pValue, // [IN] Permission set blob
+ DWORD cbValue, // [IN] Byte count of permission set blob
+ mdPermission*pmdPermission) // [OUT] Output permission token
+{
+ HRESULT hr = S_OK;
+ DeclSecurityRec *pDeclSec = NULL;
+ RID iDeclSec;
+ short sAction = static_cast<short>(dwAction);
+ mdPermission tkPerm;
+
+ LOG((LOGMD, "MD RegMeta::AddDeclarativeSecurityHelper(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ tk, dwAction, pValue, cbValue, pmdPermission));
+
+ LOCKWRITE();
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ _ASSERTE(TypeFromToken(tk) == mdtTypeDef || TypeFromToken(tk) == mdtMethodDef || TypeFromToken(tk) == mdtAssembly);
+
+ // Check for valid Action.
+ if (sAction == 0 || sAction > dclMaximumValue)
+ IfFailGo(E_INVALIDARG);
+
+ if (CheckDups(MDDupPermission))
+ {
+ hr = ImportHelper::FindPermission(&(m_pStgdb->m_MiniMd), tk, sAction, &tkPerm);
+
+ if (SUCCEEDED(hr))
+ {
+ // Set output parameter.
+ if (pmdPermission)
+ *pmdPermission = tkPerm;
+ if (IsENCOn())
+ IfFailGo(m_pStgdb->m_MiniMd.GetDeclSecurityRecord(RidFromToken(tkPerm), &pDeclSec));
+ else
+ {
+ hr = META_S_DUPLICATE;
+ goto ErrExit;
+ }
+ }
+ else if (hr != CLDB_E_RECORD_NOTFOUND)
+ IfFailGo(hr);
+ }
+
+ // Create a new record.
+ if (!pDeclSec)
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.AddDeclSecurityRecord(&pDeclSec, &iDeclSec));
+ tkPerm = TokenFromRid(iDeclSec, mdtPermission);
+
+ // Set output parameter.
+ if (pmdPermission)
+ *pmdPermission = tkPerm;
+
+ // Save parent and action information.
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_DeclSecurity, DeclSecurityRec::COL_Parent, pDeclSec, tk));
+ pDeclSec->SetAction(sAction);
+
+ // Turn on the internal security flag on the parent.
+ if (TypeFromToken(tk) == mdtTypeDef)
+ IfFailGo(_TurnInternalFlagsOn(tk, tdHasSecurity));
+ else if (TypeFromToken(tk) == mdtMethodDef)
+ IfFailGo(_TurnInternalFlagsOn(tk, mdHasSecurity));
+ IfFailGo(UpdateENCLog(tk));
+ }
+
+ // Write the blob into the record.
+ IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_DeclSecurity, DeclSecurityRec::COL_PermissionSet,
+ pDeclSec, pValue, cbValue));
+
+ IfFailGo(UpdateENCLog(tkPerm));
+
+ErrExit:
+
+ return hr;
+} // RegMeta::AddDeclarativeSecurityHelper
+
+
+//*******************************************************************************
+// helper to set type's extends column
+//
+// Implements internal API code:IMetaDataEmitHelper::SetTypeParent.
+//*******************************************************************************
+HRESULT RegMeta::SetTypeParent( // Return hresult.
+ mdTypeDef td, // [IN] Type definition
+ mdToken tkExtends) // [IN] parent type
+{
+ HRESULT hr;
+ TypeDefRec *pRec;
+
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(td), &pRec));
+ IfFailGo( m_pStgdb->m_MiniMd.PutToken(TBL_TypeDef, TypeDefRec::COL_Extends, pRec, tkExtends) );
+
+ErrExit:
+ return hr;
+} // RegMeta::SetTypeParent
+
+
+//*******************************************************************************
+// helper to set type's extends column
+//
+// Implements internal API code:IMetaDataEmitHelper::AddInterfaceImpl.
+//*******************************************************************************
+HRESULT RegMeta::AddInterfaceImpl( // Return hresult.
+ mdTypeDef td, // [IN] Type definition
+ mdToken tkInterface) // [IN] interface type
+{
+ HRESULT hr;
+ InterfaceImplRec *pRec;
+ RID ii;
+
+ LOCKWRITE();
+ hr = ImportHelper::FindInterfaceImpl(&(m_pStgdb->m_MiniMd), td, tkInterface, (mdInterfaceImpl *)&ii);
+ if (hr == S_OK)
+ goto ErrExit;
+ IfFailGo(m_pStgdb->m_MiniMd.AddInterfaceImplRecord(&pRec, &ii));
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken( TBL_InterfaceImpl, InterfaceImplRec::COL_Class, pRec, td));
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken( TBL_InterfaceImpl, InterfaceImplRec::COL_Interface, pRec, tkInterface));
+
+ErrExit:
+ return hr;
+} // RegMeta::AddInterfaceImpl
+
+#endif //FEATURE_METADATA_EMIT && FEATURE_METADATA_INTERNAL_APIS
+
+#ifdef FEATURE_METADATA_INTERNAL_APIS
+
+//*****************************************************************************
+// Helper : get metadata information
+//
+// Implements internal API code:IMetaDataHelper::GetMetadata.
+//*****************************************************************************
+STDMETHODIMP
+RegMeta::GetMetadata(
+ ULONG ulSelect, // [IN] Selector.
+ void ** ppData) // [OUT] Put pointer to data here.
+{
+
+ REGMETA_POSSIBLE_INTERNAL_POINTER_EXPOSED();
+
+ switch (ulSelect)
+ {
+ case 0:
+ *ppData = &m_pStgdb->m_MiniMd;
+ break;
+ case 1:
+ *ppData = (void*)g_CodedTokens;
+ break;
+ case 2:
+ *ppData = (void*)g_Tables;
+ break;
+ default:
+ *ppData = 0;
+ break;
+ }
+
+ return S_OK;
+} // RegMeta::GetMetadata
+
+//*******************************************************************************
+// helper to change MVID
+//
+// Implements internal API code:IMDInternalEmit::ChangeMvid.
+//*******************************************************************************
+HRESULT RegMeta::ChangeMvid( // S_OK or error.
+ REFGUID newMvid) // GUID to use as the MVID
+{
+ return GetMiniMd()->ChangeMvid(newMvid);
+}
+
+//*******************************************************************************
+// Helper to change MDUpdateMode value to updateMode.
+//
+// Implements internal API code:IMDInternalEmit::SetMDUpdateMode.
+//*******************************************************************************
+HRESULT
+RegMeta::SetMDUpdateMode(
+ ULONG updateMode,
+ ULONG * pPreviousUpdateMode)
+{
+ HRESULT hr;
+
+ OptionValue optionValue;
+ IfFailGo(m_pStgdb->m_MiniMd.GetOption(&optionValue));
+ if (pPreviousUpdateMode != NULL)
+ {
+ *pPreviousUpdateMode = optionValue.m_UpdateMode;
+ }
+ optionValue.m_UpdateMode = updateMode;
+ IfFailGo(m_pStgdb->m_MiniMd.SetOption(&optionValue));
+
+ErrExit:
+ return hr;
+} // RegMeta::SetMDUpdateMode
+
+#endif //FEATURE_METADATA_INTERNAL_APIS
diff --git a/src/md/compiler/import.cpp b/src/md/compiler/import.cpp
new file mode 100644
index 0000000000..9d1dfc8116
--- /dev/null
+++ b/src/md/compiler/import.cpp
@@ -0,0 +1,3809 @@
+// 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.
+//*****************************************************************************
+// Import.cpp
+//
+
+//
+// Methods of code:RegMeta class which implement public API interfaces:
+// * code:IMetaDataImport, and
+// * code:IMetaDataImport2.
+//
+//*****************************************************************************
+#include "stdafx.h"
+#include "regmeta.h"
+#include "metadata.h"
+#include "corerror.h"
+#include "mdutil.h"
+#include "rwutil.h"
+#include "corpriv.h"
+#include "importhelper.h"
+#include "mdlog.h"
+#include "mdperf.h"
+#include "stgio.h"
+
+//*****************************************************************************
+// Enumerate over all the Methods in a TypeDef.
+//*****************************************************************************
+STDMETHODIMP RegMeta::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.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ ULONG ridStartMethod;
+ ULONG ridEndMethod;
+ ULONG ridStartField;
+ ULONG ridEndField;
+ ULONG index;
+ ULONG indexField;
+ TypeDefRec *pRec;
+ HENUMInternal *pEnum = *ppmdEnum;
+
+ LOG((LOGMD, "MD RegMeta::EnumMembers(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, cl, rMembers, cMax, pcTokens));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ if ( pEnum == 0 )
+ {
+ // instantiating a new ENUM
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ if ( IsGlobalMethodParentTk(cl) )
+ {
+ cl = m_tdModule;
+ }
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(cl), &pRec));
+
+ ridStartMethod = m_pStgdb->m_MiniMd.getMethodListOfTypeDef(pRec);
+ IfFailGo(m_pStgdb->m_MiniMd.getEndMethodListOfTypeDef(RidFromToken(cl), &ridEndMethod));
+
+ ridStartField = m_pStgdb->m_MiniMd.getFieldListOfTypeDef(pRec);
+ IfFailGo(m_pStgdb->m_MiniMd.getEndFieldListOfTypeDef(RidFromToken(cl), &ridEndField));
+
+
+ IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtMethodDef, &pEnum) );
+
+ // add all methods to the dynamic array
+ for (index = ridStartMethod; index < ridEndMethod; index++ )
+ {
+ RID rid;
+ IfFailGo(pMiniMd->GetMethodRid(index, &rid));
+ IfFailGo(HENUMInternal::AddElementToEnum(
+ pEnum,
+ TokenFromRid(rid, mdtMethodDef)));
+ }
+
+ // add all fields to the dynamic array
+ for (indexField = ridStartField; indexField < ridEndField; indexField++ )
+ {
+ RID rid;
+ IfFailGo(pMiniMd->GetFieldRid(indexField, &rid));
+ IfFailGo(HENUMInternal::AddElementToEnum(
+ pEnum,
+ TokenFromRid(rid, mdtFieldDef)));
+ }
+
+ // set the output parameter
+ *ppmdEnum = pEnum;
+ }
+
+ // fill the output token buffer
+ hr = HENUMInternal::EnumWithCount(pEnum, cMax, rMembers, pcTokens);
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+
+ STOP_MD_PERF(EnumMembers);
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::EnumMembers()
+
+//*****************************************************************************
+// Enumerate over all the Methods in a TypeDef that has szName
+//*****************************************************************************
+STDMETHODIMP RegMeta::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.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ ULONG ridStart;
+ ULONG ridEnd;
+ ULONG index;
+ TypeDefRec *pRec;
+ MethodRec *pMethod;
+ FieldRec *pField;
+ HENUMInternal *pEnum = *ppmdEnum;
+ LPUTF8 szNameUtf8;
+ UTF8STR(szName, szNameUtf8);
+ LPCUTF8 szNameUtf8Tmp;
+
+ LOG((LOGMD, "MD RegMeta::EnumMembersWithName(0x%08x, 0x%08x, %S, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, cl, MDSTR(szName), rMembers, cMax, pcTokens));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ if ( pEnum == 0 )
+ {
+ // instantiating a new ENUM
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ // create the enumerator
+ IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtMethodDef, &pEnum) );
+
+ if ( IsGlobalMethodParentTk(cl) )
+ {
+ cl = m_tdModule;
+ }
+
+ // get the range of method rids given a typedef
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(cl), &pRec));
+ ridStart = pMiniMd->getMethodListOfTypeDef(pRec);
+ IfFailGo(pMiniMd->getEndMethodListOfTypeDef(RidFromToken(cl), &ridEnd));
+
+ for (index = ridStart; index < ridEnd; index++ )
+ {
+ if (szNameUtf8 == NULL)
+ {
+ RID rid;
+ IfFailGo(pMiniMd->GetMethodRid(index, &rid));
+ IfFailGo(HENUMInternal::AddElementToEnum(
+ pEnum,
+ TokenFromRid(rid, mdtMethodDef)));
+ }
+ else
+ {
+ RID rid;
+ IfFailGo(pMiniMd->GetMethodRid(index, &rid));
+ IfFailGo(pMiniMd->GetMethodRecord(rid, &pMethod));
+ IfFailGo(pMiniMd->getNameOfMethod(pMethod, &szNameUtf8Tmp));
+ if ( strcmp(szNameUtf8Tmp, szNameUtf8) == 0 )
+ {
+ IfFailGo(pMiniMd->GetMethodRid(index, &rid));
+ IfFailGo(HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(rid, mdtMethodDef)));
+ }
+ }
+ }
+
+ ridStart = m_pStgdb->m_MiniMd.getFieldListOfTypeDef(pRec);
+ IfFailGo(m_pStgdb->m_MiniMd.getEndFieldListOfTypeDef(RidFromToken(cl), &ridEnd));
+
+ for (index = ridStart; index < ridEnd; index++ )
+ {
+ if (szNameUtf8 == NULL)
+ {
+ RID rid;
+ IfFailGo(pMiniMd->GetFieldRid(index, &rid));
+ IfFailGo(HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(rid, mdtFieldDef)));
+ }
+ else
+ {
+ RID rid;
+ IfFailGo(pMiniMd->GetFieldRid(index, &rid));
+ IfFailGo(pMiniMd->GetFieldRecord(rid, &pField));
+ IfFailGo(pMiniMd->getNameOfField(pField, &szNameUtf8Tmp));
+ if ( strcmp(szNameUtf8Tmp, szNameUtf8) == 0 )
+ {
+ IfFailGo(pMiniMd->GetFieldRid(index, &rid));
+ IfFailGo(HENUMInternal::AddElementToEnum(
+ pEnum,
+ TokenFromRid(rid, mdtFieldDef)));
+ }
+ }
+ }
+
+ // set the output parameter
+ *ppmdEnum = pEnum;
+ }
+
+ // fill the output token buffer
+ hr = HENUMInternal::EnumWithCount(pEnum, cMax, rMembers, pcTokens);
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+
+ STOP_MD_PERF(EnumMembersWithName);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::EnumMembersWithName()
+
+//*****************************************************************************
+// enumerating through methods given a Typedef and the flag
+//*****************************************************************************
+STDMETHODIMP RegMeta::EnumMethods(
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdTypeDef td, // [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.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ ULONG ridStart;
+ ULONG ridEnd;
+ TypeDefRec *pRec;
+ HENUMInternal *pEnum = *ppmdEnum;
+
+ LOG((LOGMD, "MD RegMeta::EnumMethods(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, td, rMethods, cMax, pcTokens));
+
+
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ if ( pEnum == 0 )
+ {
+ // instantiating a new ENUM
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ // Check for mdTypeDefNil (representing <Module>).
+ // If so, this will map it to its token.
+ //
+ if ( IsGlobalMethodParentTk(td) )
+ {
+ td = m_tdModule;
+ }
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(td), &pRec));
+ ridStart = m_pStgdb->m_MiniMd.getMethodListOfTypeDef(pRec);
+ IfFailGo(m_pStgdb->m_MiniMd.getEndMethodListOfTypeDef(RidFromToken(td), &ridEnd));
+
+ if (pMiniMd->HasIndirectTable(TBL_Method) || pMiniMd->HasDelete())
+ {
+ IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtMethodDef, &pEnum) );
+
+ // add all methods to the dynamic array
+ for (ULONG index = ridStart; index < ridEnd; index++ )
+ {
+ if (pMiniMd->HasDelete() &&
+ ((m_OptionValue.m_ImportOption & MDImportOptionAllMethodDefs) == 0))
+ {
+ MethodRec *pMethRec;
+ RID rid;
+ IfFailGo(pMiniMd->GetMethodRid(index, &rid));
+ IfFailGo(pMiniMd->GetMethodRecord(rid, &pMethRec));
+ LPCSTR szMethodName;
+ IfFailGo(pMiniMd->getNameOfMethod(pMethRec, &szMethodName));
+ if (IsMdRTSpecialName(pMethRec->GetFlags()) && IsDeletedName(szMethodName) )
+ {
+ continue;
+ }
+ }
+ RID rid;
+ IfFailGo(pMiniMd->GetMethodRid(index, &rid));
+ IfFailGo(HENUMInternal::AddElementToEnum(
+ pEnum,
+ TokenFromRid(rid, mdtMethodDef)));
+ }
+ }
+ else
+ {
+ IfFailGo( HENUMInternal::CreateSimpleEnum( mdtMethodDef, ridStart, ridEnd, &pEnum) );
+ }
+
+ // set the output parameter
+ *ppmdEnum = pEnum;
+ }
+
+ // fill the output token buffer
+ hr = HENUMInternal::EnumWithCount(pEnum, cMax, rMethods, pcTokens);
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+
+ STOP_MD_PERF(EnumMethods);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::EnumMethods()
+
+
+
+
+//*****************************************************************************
+// Enumerate over all the methods with szName in a TypeDef.
+//*****************************************************************************
+STDMETHODIMP RegMeta::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.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ ULONG ridStart;
+ ULONG ridEnd;
+ ULONG index;
+ TypeDefRec *pRec;
+ MethodRec *pMethod;
+ HENUMInternal *pEnum = *ppmdEnum;
+ LPUTF8 szNameUtf8;
+ UTF8STR(szName, szNameUtf8);
+ LPCUTF8 szNameUtf8Tmp;
+
+ LOG((LOGMD, "MD RegMeta::EnumMethodsWithName(0x%08x, 0x%08x, %S, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, cl, MDSTR(szName), rMethods, cMax, pcTokens));
+
+
+
+ START_MD_PERF();
+ LOCKREAD();
+
+
+ if ( pEnum == 0 )
+ {
+ // instantiating a new ENUM
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ // Check for mdTypeDefNil (representing <Module>).
+ // If so, this will map it to its token.
+ //
+ if ( IsGlobalMethodParentTk(cl) )
+ {
+ cl = m_tdModule;
+ }
+
+
+ // create the enumerator
+ IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtMethodDef, &pEnum) );
+
+ // get the range of method rids given a typedef
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(cl), &pRec));
+ ridStart = pMiniMd->getMethodListOfTypeDef(pRec);
+ IfFailGo(pMiniMd->getEndMethodListOfTypeDef(RidFromToken(cl), &ridEnd));
+
+ for (index = ridStart; index < ridEnd; index++ )
+ {
+ if ( szNameUtf8 == NULL )
+ {
+ RID rid;
+ IfFailGo(pMiniMd->GetMethodRid(index, &rid));
+ IfFailGo(HENUMInternal::AddElementToEnum(
+ pEnum,
+ TokenFromRid(rid, mdtMethodDef)));
+ }
+ else
+ {
+ RID rid;
+ IfFailGo(pMiniMd->GetMethodRid(index, &rid));
+ IfFailGo(pMiniMd->GetMethodRecord(rid, &pMethod));
+ IfFailGo(pMiniMd->getNameOfMethod(pMethod, &szNameUtf8Tmp));
+ if ( strcmp(szNameUtf8Tmp, szNameUtf8) == 0 )
+ {
+ IfFailGo(pMiniMd->GetMethodRid(index, &rid));
+ IfFailGo(HENUMInternal::AddElementToEnum(
+ pEnum,
+ TokenFromRid(rid, mdtMethodDef)));
+ }
+ }
+ }
+
+ // set the output parameter
+ *ppmdEnum = pEnum;
+ }
+
+ // fill the output token buffer
+ hr = HENUMInternal::EnumWithCount(pEnum, cMax, rMethods, pcTokens);
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+
+ STOP_MD_PERF(EnumMethodsWithName);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::EnumMethodsWithName()
+
+
+
+//*****************************************************************************
+// Enumerate over all the fields in a TypeDef and a flag.
+//*****************************************************************************
+STDMETHODIMP
+RegMeta::EnumFields(
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdTypeDef td, // [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.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **>(phEnum);
+ ULONG ridStart;
+ ULONG ridEnd;
+ TypeDefRec *pRec;
+ HENUMInternal *pEnum = *ppmdEnum;
+
+ LOG((LOGMD, "MD RegMeta::EnumFields(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, td, rFields, cMax, pcTokens));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ if (pEnum == NULL)
+ {
+ // instantiating a new ENUM
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ // Check for mdTypeDefNil (representing <Module>).
+ // If so, this will map it to its token.
+ //
+ if (IsGlobalMethodParentTk(td))
+ {
+ td = m_tdModule;
+ }
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(td), &pRec));
+ ridStart = m_pStgdb->m_MiniMd.getFieldListOfTypeDef(pRec);
+ IfFailGo(m_pStgdb->m_MiniMd.getEndFieldListOfTypeDef(RidFromToken(td), &ridEnd));
+
+ if (pMiniMd->HasIndirectTable(TBL_Field) || pMiniMd->HasDelete())
+ {
+ IfFailGo(HENUMInternal::CreateDynamicArrayEnum(mdtFieldDef, &pEnum));
+
+ // add all methods to the dynamic array
+ for (ULONG index = ridStart; index < ridEnd; index++)
+ {
+ if (pMiniMd->HasDelete() &&
+ ((m_OptionValue.m_ImportOption & MDImportOptionAllFieldDefs) == 0))
+ {
+ FieldRec *pFieldRec;
+ RID rid;
+ IfFailGo(pMiniMd->GetFieldRid(index, &rid));
+ IfFailGo(pMiniMd->GetFieldRecord(rid, &pFieldRec));
+ LPCUTF8 szFieldName;
+ IfFailGo(pMiniMd->getNameOfField(pFieldRec, &szFieldName));
+ if (IsFdRTSpecialName(pFieldRec->GetFlags()) && IsDeletedName(szFieldName))
+ {
+ continue;
+ }
+ }
+ RID rid;
+ IfFailGo(pMiniMd->GetFieldRid(index, &rid));
+ IfFailGo(HENUMInternal::AddElementToEnum(
+ pEnum,
+ TokenFromRid(rid, mdtFieldDef)));
+ }
+ }
+ else
+ {
+ IfFailGo(HENUMInternal::CreateSimpleEnum(mdtFieldDef, ridStart, ridEnd, &pEnum));
+ }
+
+ // set the output parameter
+ *ppmdEnum = pEnum;
+ }
+
+ // fill the output token buffer
+ hr = HENUMInternal::EnumWithCount(pEnum, cMax, rFields, pcTokens);
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+
+ STOP_MD_PERF(EnumFields);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::EnumFields
+
+
+
+//*****************************************************************************
+// Enumerate over all the fields with szName in a TypeDef.
+//*****************************************************************************
+STDMETHODIMP RegMeta::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.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ ULONG ridStart;
+ ULONG ridEnd;
+ ULONG index;
+ TypeDefRec *pRec;
+ FieldRec *pField;
+ HENUMInternal *pEnum = *ppmdEnum;
+ LPUTF8 szNameUtf8;
+ UTF8STR(szName, szNameUtf8);
+ LPCUTF8 szNameUtf8Tmp;
+
+ LOG((LOGMD, "MD RegMeta::EnumFields(0x%08x, 0x%08x, %S, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, cl, MDSTR(szName), rFields, cMax, pcTokens));
+
+
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ if ( pEnum == 0 )
+ {
+ // instantiating a new ENUM
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ // Check for mdTypeDefNil (representing <Module>).
+ // If so, this will map it to its token.
+ //
+ if ( IsGlobalMethodParentTk(cl) )
+ {
+ cl = m_tdModule;
+ }
+
+ // create the enumerator
+ IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtMethodDef, &pEnum) );
+
+ // get the range of field rids given a typedef
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(cl), &pRec));
+ ridStart = m_pStgdb->m_MiniMd.getFieldListOfTypeDef(pRec);
+ IfFailGo(m_pStgdb->m_MiniMd.getEndFieldListOfTypeDef(RidFromToken(cl), &ridEnd));
+
+ for (index = ridStart; index < ridEnd; index++ )
+ {
+ if ( szNameUtf8 == NULL )
+ {
+ RID rid;
+ IfFailGo(pMiniMd->GetFieldRid(index, &rid));
+ IfFailGo(HENUMInternal::AddElementToEnum(
+ pEnum,
+ TokenFromRid(rid, mdtFieldDef)));
+ }
+ else
+ {
+ RID rid;
+ IfFailGo(pMiniMd->GetFieldRid(index, &rid));
+ IfFailGo(pMiniMd->GetFieldRecord(rid, &pField));
+ IfFailGo(pMiniMd->getNameOfField(pField, &szNameUtf8Tmp));
+ if ( strcmp(szNameUtf8Tmp, szNameUtf8) == 0 )
+ {
+ IfFailGo(pMiniMd->GetFieldRid(index, &rid));
+ IfFailGo( HENUMInternal::AddElementToEnum(
+ pEnum,
+ TokenFromRid(rid, mdtFieldDef) ) );
+ }
+ }
+ }
+
+ // set the output parameter
+ *ppmdEnum = pEnum;
+ }
+
+ // fill the output token buffer
+ hr = HENUMInternal::EnumWithCount(pEnum, cMax, rFields, pcTokens);
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+
+ STOP_MD_PERF(EnumFieldsWithName);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::EnumFieldsWithName()
+
+
+//*****************************************************************************
+// Enumerate over the ParamDefs in a Method.
+//*****************************************************************************
+STDMETHODIMP RegMeta::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.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ ULONG ridStart;
+ ULONG ridEnd;
+ MethodRec *pRec;
+ HENUMInternal *pEnum = *ppmdEnum;
+
+ LOG((LOGMD, "MD RegMeta::EnumParams(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, mb, rParams, cMax, pcTokens));
+ START_MD_PERF();
+ LOCKREAD();
+
+
+ if ( pEnum == 0 )
+ {
+ // instantiating a new ENUM
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(mb), &pRec));
+ ridStart = m_pStgdb->m_MiniMd.getParamListOfMethod(pRec);
+ IfFailGo(m_pStgdb->m_MiniMd.getEndParamListOfMethod(RidFromToken(mb), &ridEnd));
+
+ if (pMiniMd->HasIndirectTable(TBL_Param))
+ {
+ IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtParamDef, &pEnum) );
+
+ // add all methods to the dynamic array
+ for (ULONG index = ridStart; index < ridEnd; index++ )
+ {
+ RID rid;
+ IfFailGo(pMiniMd->GetParamRid(index, &rid));
+ IfFailGo(HENUMInternal::AddElementToEnum(
+ pEnum,
+ TokenFromRid(rid, mdtParamDef)));
+ }
+ }
+ else
+ {
+ IfFailGo( HENUMInternal::CreateSimpleEnum( mdtParamDef, ridStart, ridEnd, &pEnum) );
+ }
+
+ // set the output parameter
+ *ppmdEnum = pEnum;
+ }
+
+ // fill the output token buffer
+ hr = HENUMInternal::EnumWithCount(pEnum, cMax, rParams, pcTokens);
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+
+ STOP_MD_PERF(EnumParams);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::EnumParams()
+
+
+
+//*****************************************************************************
+// Enumerate the MemberRefs given the parent token.
+//*****************************************************************************
+STDMETHODIMP RegMeta::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.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ ULONG ridEnd;
+ ULONG index;
+ MemberRefRec *pRec;
+ HENUMInternal *pEnum = *ppmdEnum;
+
+ LOG((LOGMD, "MD RegMeta::EnumMemberRefs(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, tkParent, rMemberRefs, cMax, pcTokens));
+
+
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ if ( pEnum == 0 )
+ {
+ // instantiating a new ENUM
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ mdToken tk;
+
+ // Check for mdTypeDefNil (representing <Module>).
+ // If so, this will map it to its token.
+ //
+ IsGlobalMethodParent(&tkParent);
+
+ // create the enumerator
+ IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtMemberRef, &pEnum) );
+
+ // get the range of field rids given a typedef
+ ridEnd = pMiniMd->getCountMemberRefs();
+
+ for (index = 1; index <= ridEnd; index++ )
+ {
+ IfFailGo(pMiniMd->GetMemberRefRecord(index, &pRec));
+ tk = pMiniMd->getClassOfMemberRef(pRec);
+ if ( tk == tkParent )
+ {
+ // add the matched ones to the enumerator
+ IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtMemberRef) ) );
+ }
+ }
+
+ // set the output parameter
+ *ppmdEnum = pEnum;
+ }
+
+ // fill the output token buffer
+ hr = HENUMInternal::EnumWithCount(pEnum, cMax, rMemberRefs, pcTokens);
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+
+ STOP_MD_PERF(EnumMemberRefs);
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::EnumMemberRefs()
+
+
+//*****************************************************************************
+// Enumerate methodimpls given a typedef
+//*****************************************************************************
+STDMETHODIMP RegMeta::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.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ MethodImplRec *pRec;
+ HENUMInternal *pEnum = *ppmdEnum;
+ HENUMInternal hEnum;
+
+
+ LOG((LOGMD, "MD RegMeta::EnumMethodImpls(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, td, rMethodBody, rMethodDecl, cMax, pcTokens));
+
+
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ memset(&hEnum, 0, sizeof(HENUMInternal));
+
+ if ( pEnum == 0 )
+ {
+ // instantiating a new ENUM
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ mdToken tkMethodBody;
+ mdToken tkMethodDecl;
+ RID ridCur;
+
+ // Get the range of rids.
+ IfFailGo( pMiniMd->FindMethodImplHelper(td, &hEnum) );
+
+ // Create the enumerator, DynamicArrayEnum does not use the token type.
+ IfFailGo( HENUMInternal::CreateDynamicArrayEnum( (TBL_MethodImpl << 24), &pEnum) );
+
+ while (HENUMInternal::EnumNext(&hEnum, (mdToken *)&ridCur))
+ {
+ // Get the MethodBody and MethodDeclaration tokens for the current
+ // MethodImpl record.
+ IfFailGo(pMiniMd->GetMethodImplRecord(ridCur, &pRec));
+ tkMethodBody = pMiniMd->getMethodBodyOfMethodImpl(pRec);
+ tkMethodDecl = pMiniMd->getMethodDeclarationOfMethodImpl(pRec);
+
+ // Add the Method body/declaration pairs to the Enum
+ IfFailGo( HENUMInternal::AddElementToEnum(pEnum, tkMethodBody ) );
+ IfFailGo( HENUMInternal::AddElementToEnum(pEnum, tkMethodDecl ) );
+ }
+
+ // set the output parameter
+ *ppmdEnum = pEnum;
+ }
+
+ // fill the output token buffer
+ hr = HENUMInternal::EnumWithCount(pEnum, cMax, rMethodBody, rMethodDecl, pcTokens);
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+ HENUMInternal::ClearEnum(&hEnum);
+
+ STOP_MD_PERF(EnumMethodImpls);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::EnumMethodImpls()
+
+
+//*****************************************************************************
+// Enumerate over PermissionSets. Optionally limit to an object and/or an
+// action.
+//*****************************************************************************
+STDMETHODIMP RegMeta::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.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ ULONG ridStart;
+ ULONG ridEnd;
+ ULONG index;
+ DeclSecurityRec *pRec;
+ HENUMInternal *pEnum = *ppmdEnum;
+ bool fCompareParent = false;
+ mdToken typ = TypeFromToken(tk);
+ mdToken tkParent;
+
+ LOG((LOGMD, "MD RegMeta::EnumPermissionSets(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, tk, dwActions, rPermission, cMax, pcTokens));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ if ( pEnum == 0 )
+ {
+ // Does this token type even have security?
+ if (tk != 0 &&
+ !(typ == mdtTypeDef || typ == mdtMethodDef || typ == mdtAssembly))
+ {
+ if (pcTokens)
+ *pcTokens = 0;
+ hr = S_FALSE;
+ goto ErrExit;
+ }
+
+ // instantiating a new ENUM
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ if (!IsNilToken(tk))
+ {
+ // parent is provided for lookup
+ if ( pMiniMd->IsSorted( TBL_DeclSecurity ) )
+ {
+ IfFailGo(pMiniMd->getDeclSecurityForToken(tk, &ridEnd, &ridStart));
+ }
+ else
+ {
+ // table is not sorted. So we have to do a table scan
+ ridStart = 1;
+ ridEnd = pMiniMd->getCountDeclSecuritys() + 1;
+ fCompareParent = true;
+ }
+ }
+ else
+ {
+ ridStart = 1;
+ ridEnd = pMiniMd->getCountDeclSecuritys() + 1;
+ }
+
+ if (IsDclActionNil(dwActions) && !fCompareParent && !m_pStgdb->m_MiniMd.HasDelete())
+ {
+ // create simple enumerator
+ IfFailGo( HENUMInternal::CreateSimpleEnum( mdtPermission, ridStart, ridEnd, &pEnum) );
+ }
+ else
+ {
+ // create the dynamic enumerator
+ IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtPermission, &pEnum) );
+
+ for (index = ridStart; index < ridEnd; index++ )
+ {
+ IfFailGo(pMiniMd->GetDeclSecurityRecord(index, &pRec));
+ tkParent = pMiniMd->getParentOfDeclSecurity(pRec);
+ if ( (fCompareParent && tk != tkParent) ||
+ IsNilToken(tkParent) )
+ {
+ // We need to compare parent token and they are not equal so skip
+ // over this row.
+ //
+ continue;
+ }
+ if ( IsDclActionNil(dwActions) ||
+ ( (DWORD)(pMiniMd->getActionOfDeclSecurity(pRec))) == dwActions )
+ {
+ // If we don't need to compare the action, just add to the enum.
+ // Or we need to compare the action and the action values are equal, add to enum as well.
+ //
+ IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtPermission) ) );
+ }
+ }
+ }
+
+ // set the output parameter
+ *ppmdEnum = pEnum;
+ }
+
+ // fill the output token buffer
+ hr = HENUMInternal::EnumWithCount(pEnum, cMax, rPermission, pcTokens);
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+
+ STOP_MD_PERF(EnumPermissionSets);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::EnumPermissionSets()
+
+
+//*****************************************************************************
+// Find a given member in a TypeDef (typically a class).
+//*****************************************************************************
+STDMETHODIMP RegMeta::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
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+
+ LOG((LOGMD, "MD RegMeta::FindMember(0x%08x, %S, 0x%08x, 0x%08x, 0x%08x)\n",
+ td, MDSTR(szName), pvSigBlob, cbSigBlob, pmb));
+
+ START_MD_PERF();
+
+ // Don't lock this function. All of the functions that it calls are public APIs. keep it that way.
+
+ // try to match with method first of all
+ hr = FindMethod(
+ td,
+ szName,
+ pvSigBlob,
+ cbSigBlob,
+ pmb);
+
+ if ( hr == CLDB_E_RECORD_NOTFOUND )
+ {
+ // now try field table
+ IfFailGo( FindField(
+ td,
+ szName,
+ pvSigBlob,
+ cbSigBlob,
+ pmb) );
+ }
+ErrExit:
+ STOP_MD_PERF(FindMember);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::FindMember()
+
+
+
+//*****************************************************************************
+// Find a given member in a TypeDef (typically a class).
+//*****************************************************************************
+STDMETHODIMP RegMeta::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
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ LPUTF8 szNameUtf8;
+ UTF8STR(szName, szNameUtf8);
+
+ LOG((LOGMD, "MD RegMeta::FindMethod(0x%08x, %S, 0x%08x, 0x%08x, 0x%08x)\n",
+ td, MDSTR(szName), pvSigBlob, cbSigBlob, pmb));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ if (szName == NULL)
+ IfFailGo(E_INVALIDARG);
+ PREFIX_ASSUME(szName != NULL);
+
+ // If this is a global method, then use the <Module> typedef as parent.
+ IsGlobalMethodParent(&td);
+
+ IfFailGo(ImportHelper::FindMethod(pMiniMd,
+ td,
+ szNameUtf8,
+ pvSigBlob,
+ cbSigBlob,
+ pmb));
+
+ErrExit:
+ STOP_MD_PERF(FindMethod);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::FindMethod
+
+
+//*****************************************************************************
+// Find a given member in a TypeDef (typically a class).
+//*****************************************************************************
+STDMETHODIMP
+RegMeta::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
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ LOG((LOGMD, "MD RegMeta::FindField(0x%08x, %S, 0x%08x, 0x%08x, 0x%08x)\n",
+ td, MDSTR(szName), pvSigBlob, cbSigBlob, pmb));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ if (szName == NULL)
+ IfFailGo(E_INVALIDARG);
+
+ LPUTF8 szNameUtf8;
+ UTF8STR(szName, szNameUtf8);
+
+ // If this is a global method, then use the <Module> typedef as parent.
+ IsGlobalMethodParent(&td);
+
+ IfFailGo(ImportHelper::FindField(pMiniMd,
+ td,
+ szNameUtf8,
+ pvSigBlob,
+ cbSigBlob,
+ pmb));
+
+ErrExit:
+ STOP_MD_PERF(FindField);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::FindField
+
+
+//*****************************************************************************
+// Find a given MemberRef in a TypeRef (typically a class). If no TypeRef
+// is specified, the query will be for a random member in the scope.
+//*****************************************************************************
+STDMETHODIMP RegMeta::FindMemberRef(
+ mdToken tkPar, // [IN] given parent token.
+ 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
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ LPUTF8 szNameUtf8;
+ UTF8STR(szName, szNameUtf8);
+
+ LOG((LOGMD, "MD RegMeta::FindMemberRef(0x%08x, %S, 0x%08x, 0x%08x, 0x%08x)\n",
+ tkPar, MDSTR(szName), pvSigBlob, cbSigBlob, pmr));
+
+
+
+ START_MD_PERF();
+
+ // <TODO>@todo: Can this causing building hash table? If so, should this consider the write lock?</TODO>
+ LOCKREAD();
+
+ // get the range of field rids given a typedef
+ _ASSERTE(TypeFromToken(tkPar) == mdtTypeRef || TypeFromToken(tkPar) == mdtMethodDef ||
+ TypeFromToken(tkPar) == mdtModuleRef || TypeFromToken(tkPar) == mdtTypeDef ||
+ TypeFromToken(tkPar) == mdtTypeSpec);
+
+ // Set parent to global class m_tdModule if mdTokenNil is passed.
+ if (IsNilToken(tkPar))
+ tkPar = m_tdModule;
+
+ IfFailGo( ImportHelper::FindMemberRef(pMiniMd, tkPar, szNameUtf8, pvSigBlob, cbSigBlob, pmr) );
+
+ErrExit:
+
+ STOP_MD_PERF(FindMemberRef);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::FindMemberRef()
+
+
+//*****************************************************************************
+// Return the property of a MethodDef
+//*****************************************************************************
+STDMETHODIMP RegMeta::GetMethodProps(
+ mdMethodDef mb, // The method for which to get props.
+ mdTypeDef *pClass, // Put method's class here.
+ __out_ecount_opt (cchMethod) LPWSTR szMethod, // 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
+{
+ HRESULT hr = NOERROR;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ MethodRec *pMethodRec;
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ LOG((LOGMD, "MD RegMeta::GetMethodProps(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ mb, pClass, szMethod, cchMethod, pchMethod, pdwAttr, ppvSigBlob, pcbSigBlob,
+ pulCodeRVA, pdwImplFlags));
+
+
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ _ASSERTE(TypeFromToken(mb) == mdtMethodDef);
+
+ IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(mb), &pMethodRec));
+
+ if (pClass)
+ {
+ // caller wants parent typedef
+ IfFailGo( pMiniMd->FindParentOfMethodHelper(mb, pClass) );
+
+ if ( IsGlobalMethodParentToken(*pClass) )
+ {
+ // If the parent of Method is the <Module>, return mdTypeDefNil instead.
+ *pClass = mdTypeDefNil;
+ }
+
+ }
+ if (ppvSigBlob || pcbSigBlob)
+ {
+ // caller wants signature information
+ PCCOR_SIGNATURE pvSigTmp;
+ ULONG cbSig;
+ IfFailGo(pMiniMd->getSignatureOfMethod(pMethodRec, &pvSigTmp, &cbSig));
+ if ( ppvSigBlob )
+ *ppvSigBlob = pvSigTmp;
+ if ( pcbSigBlob)
+ *pcbSigBlob = cbSig;
+ }
+ if ( pdwAttr )
+ {
+ *pdwAttr = pMiniMd->getFlagsOfMethod(pMethodRec);
+ }
+ if ( pulCodeRVA )
+ {
+ *pulCodeRVA = pMiniMd->getRVAOfMethod(pMethodRec);
+ }
+ if ( pdwImplFlags )
+ {
+ *pdwImplFlags = (DWORD )pMiniMd->getImplFlagsOfMethod(pMethodRec);
+ }
+ // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK
+ if (szMethod || pchMethod)
+ {
+ IfFailGo( pMiniMd->getNameOfMethod(pMethodRec, szMethod, cchMethod, pchMethod) );
+ }
+
+ErrExit:
+ STOP_MD_PERF(GetMethodProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::GetMethodProps()
+
+
+//*****************************************************************************
+// Return the property of a MemberRef
+//*****************************************************************************
+STDMETHODIMP RegMeta::GetMemberRefProps( // S_OK or error.
+ mdMemberRef mr, // [IN] given memberref
+ mdToken *ptk, // [OUT] Put classref or classdef here.
+ __out_ecount_opt (cchMember) LPWSTR szMember, // [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
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ MemberRefRec *pMemberRefRec;
+
+ LOG((LOGMD, "MD RegMeta::GetMemberRefProps(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ mr, ptk, szMember, cchMember, pchMember, ppvSigBlob, pbSig));
+
+
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ _ASSERTE(TypeFromToken(mr) == mdtMemberRef);
+
+ IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(mr), &pMemberRefRec));
+
+ if (ptk)
+ {
+ *ptk = pMiniMd->getClassOfMemberRef(pMemberRefRec);
+ if ( IsGlobalMethodParentToken(*ptk) )
+ {
+ // If the parent of MemberRef is the <Module>, return mdTypeDefNil instead.
+ *ptk = mdTypeDefNil;
+ }
+
+ }
+ if (ppvSigBlob || pbSig)
+ {
+ // caller wants signature information
+ PCCOR_SIGNATURE pvSigTmp;
+ ULONG cbSig;
+ IfFailGo(pMiniMd->getSignatureOfMemberRef(pMemberRefRec, &pvSigTmp, &cbSig));
+ if ( ppvSigBlob )
+ *ppvSigBlob = pvSigTmp;
+ if ( pbSig)
+ *pbSig = cbSig;
+ }
+ // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK
+ if (szMember || pchMember)
+ {
+ IfFailGo( pMiniMd->getNameOfMemberRef(pMemberRefRec, szMember, cchMember, pchMember) );
+ }
+
+ErrExit:
+
+ STOP_MD_PERF(GetMemberRefProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::GetMemberRefProps()
+
+
+//*****************************************************************************
+// enumerate Property tokens for a typedef
+//*****************************************************************************
+STDMETHODIMP RegMeta::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.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ ULONG ridStart = 0;
+ ULONG ridEnd = 0;
+ ULONG ridMax = 0;
+ HENUMInternal *pEnum = *ppmdEnum;
+
+ LOG((LOGMD, "MD RegMeta::EnumProperties(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, td, rProperties, cMax, pcProperties));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ if (IsNilToken(td))
+ {
+ if (pcProperties)
+ *pcProperties = 0;
+ hr = S_FALSE;
+ goto ErrExit;
+ }
+
+ _ASSERTE(TypeFromToken(td) == mdtTypeDef);
+
+
+ if ( pEnum == 0 )
+ {
+ // instantiating a new ENUM
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ RID ridPropertyMap;
+ PropertyMapRec *pPropertyMapRec;
+
+ // get the starting/ending rid of properties of this typedef
+ IfFailGo(pMiniMd->FindPropertyMapFor(RidFromToken(td), &ridPropertyMap));
+ if (!InvalidRid(ridPropertyMap))
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.GetPropertyMapRecord(ridPropertyMap, &pPropertyMapRec));
+ ridStart = pMiniMd->getPropertyListOfPropertyMap(pPropertyMapRec);
+ IfFailGo(pMiniMd->getEndPropertyListOfPropertyMap(ridPropertyMap, &ridEnd));
+ ridMax = pMiniMd->getCountPropertys() + 1;
+ if(ridStart == 0) ridStart = 1;
+ if(ridEnd > ridMax) ridEnd = ridMax;
+ if(ridStart > ridEnd) ridStart=ridEnd;
+ }
+
+ if (pMiniMd->HasIndirectTable(TBL_Property) || pMiniMd->HasDelete())
+ {
+ IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtProperty, &pEnum) );
+
+ // add all methods to the dynamic array
+ for (ULONG index = ridStart; index < ridEnd; index++ )
+ {
+ if (pMiniMd->HasDelete() &&
+ ((m_OptionValue.m_ImportOption & MDImportOptionAllProperties) == 0))
+ {
+ PropertyRec *pRec;
+ RID rid;
+ IfFailGo(pMiniMd->GetPropertyRid(index, &rid));
+ IfFailGo(pMiniMd->GetPropertyRecord(rid, &pRec));
+ LPCUTF8 szPropertyName;
+ IfFailGo(pMiniMd->getNameOfProperty(pRec, &szPropertyName));
+ if (IsPrRTSpecialName(pRec->GetPropFlags()) && IsDeletedName(szPropertyName))
+ {
+ continue;
+ }
+ }
+ RID rid;
+ IfFailGo(pMiniMd->GetPropertyRid(index, &rid));
+ IfFailGo(HENUMInternal::AddElementToEnum(
+ pEnum,
+ TokenFromRid(rid, mdtProperty)));
+ }
+ }
+ else
+ {
+ IfFailGo( HENUMInternal::CreateSimpleEnum( mdtProperty, ridStart, ridEnd, &pEnum) );
+ }
+
+ // set the output parameter
+ *ppmdEnum = pEnum;
+ }
+
+ // fill the output token buffer
+ hr = HENUMInternal::EnumWithCount(pEnum, cMax, rProperties, pcProperties);
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+
+
+ STOP_MD_PERF(EnumProperties);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+
+} // STDMETHODIMP RegMeta::EnumProperties()
+
+
+//*****************************************************************************
+// enumerate event tokens for a typedef
+//*****************************************************************************
+STDMETHODIMP RegMeta::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.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ ULONG ridStart = 0;
+ ULONG ridEnd = 0;
+ ULONG ridMax = 0;
+ HENUMInternal *pEnum = *ppmdEnum;
+
+ LOG((LOGMD, "MD RegMeta::EnumEvents(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, td, rEvents, cMax, pcEvents));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ _ASSERTE(TypeFromToken(td) == mdtTypeDef);
+
+
+ if ( pEnum == 0 )
+ {
+ // instantiating a new ENUM
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ RID ridEventMap;
+ EventMapRec *pEventMapRec;
+
+ // get the starting/ending rid of properties of this typedef
+ IfFailGo(pMiniMd->FindEventMapFor(RidFromToken(td), &ridEventMap));
+ if (!InvalidRid(ridEventMap))
+ {
+ IfFailGo(pMiniMd->GetEventMapRecord(ridEventMap, &pEventMapRec));
+ ridStart = pMiniMd->getEventListOfEventMap(pEventMapRec);
+ IfFailGo(pMiniMd->getEndEventListOfEventMap(ridEventMap, &ridEnd));
+ ridMax = pMiniMd->getCountEvents() + 1;
+ if(ridStart == 0) ridStart = 1;
+ if(ridEnd > ridMax) ridEnd = ridMax;
+ if(ridStart > ridEnd) ridStart=ridEnd;
+ }
+
+ if (pMiniMd->HasIndirectTable(TBL_Event) || pMiniMd->HasDelete())
+ {
+ IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtEvent, &pEnum) );
+
+ // add all methods to the dynamic array
+ for (ULONG index = ridStart; index < ridEnd; index++ )
+ {
+ if (pMiniMd->HasDelete() &&
+ ((m_OptionValue.m_ImportOption & MDImportOptionAllEvents) == 0))
+ {
+ EventRec *pRec;
+ RID rid;
+ IfFailGo(pMiniMd->GetEventRid(index, &rid));
+ IfFailGo(pMiniMd->GetEventRecord(rid, &pRec));
+ LPCSTR szEventName;
+ IfFailGo(pMiniMd->getNameOfEvent(pRec, &szEventName));
+ if (IsEvRTSpecialName(pRec->GetEventFlags()) && IsDeletedName(szEventName))
+ {
+ continue;
+ }
+ }
+ RID rid;
+ IfFailGo(pMiniMd->GetEventRid(index, &rid));
+ IfFailGo(HENUMInternal::AddElementToEnum(
+ pEnum,
+ TokenFromRid(rid, mdtEvent)));
+ }
+ }
+ else
+ {
+ IfFailGo( HENUMInternal::CreateSimpleEnum( mdtEvent, ridStart, ridEnd, &pEnum) );
+ }
+
+ // set the output parameter
+ *ppmdEnum = pEnum;
+ }
+
+ // fill the output token buffer
+ hr = HENUMInternal::EnumWithCount(pEnum, cMax, rEvents, pcEvents);
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+
+
+ STOP_MD_PERF(EnumEvents);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::EnumEvents()
+
+
+
+//*****************************************************************************
+// return the properties of an event token
+//*****************************************************************************
+STDMETHODIMP RegMeta::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
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ EventRec *pRec;
+ HENUMInternal hEnum;
+
+ LOG((LOGMD, "MD RegMeta::GetEventProps(0x%08x, 0x%08x, %S, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ ev, pClass, MDSTR(szEvent), cchEvent, pchEvent, pdwEventFlags, ptkEventType,
+ pmdAddOn, pmdRemoveOn, pmdFire, rmdOtherMethod, cMax, pcOtherMethod));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ _ASSERTE(TypeFromToken(ev) == mdtEvent);
+
+ memset(&hEnum, 0, sizeof(HENUMInternal));
+ IfFailGo(pMiniMd->GetEventRecord(RidFromToken(ev), &pRec));
+
+ if ( pClass )
+ {
+ // find the event map entry corresponding to this event
+ IfFailGo( pMiniMd->FindParentOfEventHelper( ev, pClass ) );
+ }
+ if ( pdwEventFlags )
+ {
+ *pdwEventFlags = pMiniMd->getEventFlagsOfEvent(pRec);
+ }
+ if ( ptkEventType )
+ {
+ *ptkEventType = pMiniMd->getEventTypeOfEvent(pRec);
+ }
+ {
+ MethodSemanticsRec *pSemantics;
+ RID ridCur;
+ ULONG cCurOtherMethod = 0;
+ ULONG ulSemantics;
+ mdMethodDef tkMethod;
+
+ // initialize output parameters
+ if (pmdAddOn)
+ *pmdAddOn = mdMethodDefNil;
+ if (pmdRemoveOn)
+ *pmdRemoveOn = mdMethodDefNil;
+ if (pmdFire)
+ *pmdFire = mdMethodDefNil;
+
+ IfFailGo( pMiniMd->FindMethodSemanticsHelper(ev, &hEnum) );
+ while (HENUMInternal::EnumNext(&hEnum, (mdToken *)&ridCur))
+ {
+ IfFailGo(pMiniMd->GetMethodSemanticsRecord(ridCur, &pSemantics));
+ ulSemantics = pMiniMd->getSemanticOfMethodSemantics(pSemantics);
+ tkMethod = TokenFromRid( pMiniMd->getMethodOfMethodSemantics(pSemantics), mdtMethodDef );
+ switch (ulSemantics)
+ {
+ case msAddOn:
+ if (pmdAddOn) *pmdAddOn = tkMethod;
+ break;
+ case msRemoveOn:
+ if (pmdRemoveOn) *pmdRemoveOn = tkMethod;
+ break;
+ case msFire:
+ if (pmdFire) *pmdFire = tkMethod;
+ break;
+ case msOther:
+ if (cCurOtherMethod < cMax)
+ rmdOtherMethod[cCurOtherMethod] = tkMethod;
+ cCurOtherMethod++;
+ break;
+ default:
+ _ASSERTE(!"BadKind!");
+ }
+ }
+
+ // set the output parameter
+ if (pcOtherMethod)
+ *pcOtherMethod = cCurOtherMethod;
+ }
+ // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK
+ if (szEvent || pchEvent)
+ {
+ IfFailGo( pMiniMd->getNameOfEvent(pRec, (LPWSTR) szEvent, cchEvent, pchEvent) );
+ }
+
+ErrExit:
+ HENUMInternal::ClearEnum(&hEnum);
+ STOP_MD_PERF(GetEventProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::GetEventProps()
+
+
+//*****************************************************************************
+// given a method, return an arra of event/property tokens for each accessor role
+// it is defined to have
+//*****************************************************************************
+STDMETHODIMP RegMeta::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.
+{
+ HRESULT hr = NOERROR;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ ULONG ridEnd;
+ ULONG index;
+ HENUMInternal *pEnum = *ppmdEnum;
+ MethodSemanticsRec *pRec;
+
+ LOG((LOGMD, "MD RegMeta::EnumMethodSemantics(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, mb, rEventProp, cMax, pcEventProp));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+
+ if ( pEnum == 0 )
+ {
+ // instantiating a new ENUM
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ // create the enumerator
+ IfFailGo( HENUMInternal::CreateDynamicArrayEnum( (DWORD) -1, &pEnum) );
+
+ // get the range of method rids given a typedef
+ ridEnd = pMiniMd->getCountMethodSemantics();
+
+ for (index = 1; index <= ridEnd; index++ )
+ {
+ IfFailGo(pMiniMd->GetMethodSemanticsRecord(index, &pRec));
+ if ( pMiniMd->getMethodOfMethodSemantics(pRec) == mb )
+ {
+ IfFailGo( HENUMInternal::AddElementToEnum(pEnum, pMiniMd->getAssociationOfMethodSemantics(pRec) ) );
+ }
+ }
+
+ // set the output parameter
+ *ppmdEnum = pEnum;
+ }
+
+ // fill the output token buffer
+ hr = HENUMInternal::EnumWithCount(pEnum, cMax, rEventProp, pcEventProp);
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+
+
+ STOP_MD_PERF(EnumMethodSemantics);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::EnumMethodSemantics()
+
+
+
+//*****************************************************************************
+// return the role flags for the method/propevent pair
+//*****************************************************************************
+STDMETHODIMP RegMeta::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
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ MethodSemanticsRec *pRec;
+ ULONG ridCur;
+ HENUMInternal hEnum;
+
+ LOG((LOGMD, "MD RegMeta::GetMethodSemantics(0x%08x, 0x%08x, 0x%08x)\n",
+ mb, tkEventProp, pdwSemanticsFlags));
+
+
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ _ASSERTE(TypeFromToken(mb) == mdtMethodDef);
+ _ASSERTE( pdwSemanticsFlags );
+
+ *pdwSemanticsFlags = 0;
+ memset(&hEnum, 0, sizeof(HENUMInternal));
+
+ // loop through all methods associated with this tkEventProp
+ IfFailGo( pMiniMd->FindMethodSemanticsHelper(tkEventProp, &hEnum) );
+ while (HENUMInternal::EnumNext(&hEnum, (mdToken *)&ridCur))
+ {
+ IfFailGo(pMiniMd->GetMethodSemanticsRecord(ridCur, &pRec));
+ if ( pMiniMd->getMethodOfMethodSemantics(pRec) == mb )
+ {
+ // we findd the match
+ *pdwSemanticsFlags = pMiniMd->getSemanticOfMethodSemantics(pRec);
+ goto ErrExit;
+ }
+ }
+
+ IfFailGo( CLDB_E_RECORD_NOTFOUND );
+
+ErrExit:
+ HENUMInternal::ClearEnum(&hEnum);
+ STOP_MD_PERF(GetMethodSemantics);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::GetMethodSemantics()
+
+
+
+//*****************************************************************************
+// return the class layout information
+//*****************************************************************************
+STDMETHODIMP RegMeta::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
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ ClassLayoutRec *pRec;
+ RID ridClassLayout;
+ int bLayout=0; // Was any layout information found?
+
+ _ASSERTE(TypeFromToken(td) == mdtTypeDef);
+
+ LOG((LOGMD, "MD RegMeta::GetClassLayout(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ td, pdwPackSize, rFieldOffset, cMax, pcFieldOffset, pulClassSize));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ IfFailGo(pMiniMd->FindClassLayoutHelper(td, &ridClassLayout));
+
+ if (InvalidRid(ridClassLayout))
+ { // Nothing specified - return default values of 0.
+ if ( pdwPackSize )
+ *pdwPackSize = 0;
+ if ( pulClassSize )
+ *pulClassSize = 0;
+ }
+ else
+ {
+ IfFailGo(pMiniMd->GetClassLayoutRecord(RidFromToken(ridClassLayout), &pRec));
+ if ( pdwPackSize )
+ *pdwPackSize = pMiniMd->getPackingSizeOfClassLayout(pRec);
+ if ( pulClassSize )
+ *pulClassSize = pMiniMd->getClassSizeOfClassLayout(pRec);
+ bLayout = 1;
+ }
+
+ // fill the layout array
+ if (rFieldOffset || pcFieldOffset)
+ {
+ ULONG iFieldOffset = 0;
+ ULONG ridFieldStart;
+ ULONG ridFieldEnd;
+ ULONG ridFieldLayout;
+ ULONG ulOffset;
+ TypeDefRec *pTypeDefRec;
+ FieldLayoutRec *pLayout2Rec;
+ mdFieldDef fd;
+
+ // record for this typedef in TypeDef Table
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(td), &pTypeDefRec));
+
+ // find the starting and end field for this typedef
+ ridFieldStart = pMiniMd->getFieldListOfTypeDef(pTypeDefRec);
+ IfFailGo(pMiniMd->getEndFieldListOfTypeDef(RidFromToken(td), &ridFieldEnd));
+
+ // loop through the field table
+
+ for(; ridFieldStart < ridFieldEnd; ridFieldStart++)
+ {
+ // Calculate the field token.
+ RID rid;
+ IfFailGo(pMiniMd->GetFieldRid(ridFieldStart, &rid));
+ fd = TokenFromRid(rid, mdtFieldDef);
+
+ // Calculate the FieldLayout rid for the current field.
+ IfFailGo(pMiniMd->FindFieldLayoutHelper(fd, &ridFieldLayout));
+
+ // Calculate the offset.
+ if (InvalidRid(ridFieldLayout))
+ ulOffset = (ULONG) -1;
+ else
+ {
+ // get the FieldLayout record.
+ IfFailGo(pMiniMd->GetFieldLayoutRecord(ridFieldLayout, &pLayout2Rec));
+ ulOffset = pMiniMd->getOffSetOfFieldLayout(pLayout2Rec);
+ bLayout = 1;
+ }
+
+ // fill in the field layout if output buffer still has space.
+ if (cMax > iFieldOffset && rFieldOffset)
+ {
+ rFieldOffset[iFieldOffset].ridOfField = fd;
+ rFieldOffset[iFieldOffset].ulOffset = ulOffset;
+ }
+
+ // advance the index to the buffer.
+ iFieldOffset++;
+ }
+
+ if (bLayout && pcFieldOffset)
+ *pcFieldOffset = iFieldOffset;
+ }
+
+ if (!bLayout)
+ hr = CLDB_E_RECORD_NOTFOUND;
+
+ErrExit:
+ STOP_MD_PERF(GetClassLayout);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::GetClassLayout()
+
+
+
+//*****************************************************************************
+// return the native type of a field
+//*****************************************************************************
+STDMETHODIMP RegMeta::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
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ RID rid;
+ FieldMarshalRec *pFieldMarshalRec;
+
+
+ _ASSERTE(ppvNativeType != NULL && pcbNativeType != NULL);
+
+ LOG((LOGMD, "MD RegMeta::GetFieldMarshal(0x%08x, 0x%08x, 0x%08x)\n",
+ tk, ppvNativeType, pcbNativeType));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ _ASSERTE(TypeFromToken(tk) == mdtParamDef || TypeFromToken(tk) == mdtFieldDef);
+
+ // find the row containing the marshal definition for tk
+ IfFailGo(pMiniMd->FindFieldMarshalHelper(tk, &rid));
+ if (InvalidRid(rid))
+ {
+ IfFailGo( CLDB_E_RECORD_NOTFOUND );
+ }
+ IfFailGo(pMiniMd->GetFieldMarshalRecord(rid, &pFieldMarshalRec));
+
+ // get the native type
+ IfFailGo(pMiniMd->getNativeTypeOfFieldMarshal(pFieldMarshalRec, ppvNativeType, pcbNativeType));
+
+ErrExit:
+ STOP_MD_PERF(GetFieldMarshal);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::GetFieldMarshal()
+
+
+
+//*****************************************************************************
+// return the RVA and implflag for MethodDef or FieldDef token
+//*****************************************************************************
+STDMETHODIMP
+RegMeta::GetRVA(
+ mdToken tk, // Member for which to set offset
+ ULONG *pulCodeRVA, // The offset
+ DWORD *pdwImplFlags) // the implementation flags
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ LOG((LOGMD, "MD RegMeta::GetRVA(0x%08x, 0x%08x, 0x%08x)\n",
+ tk, pulCodeRVA, pdwImplFlags));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ if (TypeFromToken(tk) == mdtMethodDef)
+ {
+ if (tk == mdMethodDefNil)
+ { // Backward compatibility with CLR 2.0 implementation
+ if (pulCodeRVA != NULL)
+ *pulCodeRVA = 0;
+ if (pdwImplFlags != NULL)
+ *pdwImplFlags = 0;
+
+ hr = S_OK;
+ goto ErrExit;
+ }
+
+ // MethodDef token
+ MethodRec *pMethodRec;
+ IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(tk), &pMethodRec));
+
+ if (pulCodeRVA != NULL)
+ {
+ *pulCodeRVA = pMiniMd->getRVAOfMethod(pMethodRec);
+ }
+ if (pdwImplFlags != NULL)
+ {
+ *pdwImplFlags = pMiniMd->getImplFlagsOfMethod(pMethodRec);
+ }
+ }
+ else
+ { // FieldDef token or invalid type of token (not mdtMethodDef)
+ ULONG iRecord;
+
+ IfFailGo(pMiniMd->FindFieldRVAHelper(tk, &iRecord));
+
+ if (InvalidRid(iRecord))
+ {
+ if (pulCodeRVA != NULL)
+ *pulCodeRVA = 0;
+
+ IfFailGo(CLDB_E_RECORD_NOTFOUND);
+ }
+
+ FieldRVARec *pFieldRVARec;
+ IfFailGo(pMiniMd->GetFieldRVARecord(iRecord, &pFieldRVARec));
+
+ if (pulCodeRVA != NULL)
+ {
+ *pulCodeRVA = pMiniMd->getRVAOfFieldRVA(pFieldRVARec);
+ }
+ if (pdwImplFlags != NULL)
+ {
+ *pdwImplFlags = 0;
+ }
+ }
+ErrExit:
+ STOP_MD_PERF(GetRVA);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::GetRVA
+
+
+
+//*****************************************************************************
+// Get the Action and Permissions blob for a given PermissionSet.
+//*****************************************************************************
+STDMETHODIMP RegMeta::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.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "MD RegMeta::GetPermissionSetProps(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ pm, pdwAction, ppvPermission, pcbPermission));
+
+ CMiniMdRW *pMiniMd = NULL;
+ DeclSecurityRec *pRecord = NULL;
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ pMiniMd = &(m_pStgdb->m_MiniMd);
+ IfFailGo(pMiniMd->GetDeclSecurityRecord(RidFromToken(pm), &pRecord));
+
+ _ASSERTE(TypeFromToken(pm) == mdtPermission && RidFromToken(pm));
+
+ // If you want the BLOB, better get the BLOB size as well.
+ _ASSERTE(!ppvPermission || pcbPermission);
+
+ if (pdwAction)
+ *pdwAction = pMiniMd->getActionOfDeclSecurity(pRecord);
+
+ if (ppvPermission != NULL)
+ {
+ IfFailGo(pMiniMd->getPermissionSetOfDeclSecurity(pRecord, (const BYTE **)ppvPermission, pcbPermission));
+ }
+
+ErrExit:
+
+ STOP_MD_PERF(GetPermissionSetProps);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // STDMETHODIMP RegMeta::GetPermissionSetProps()
+
+
+
+//*****************************************************************************
+// Given a signature token, get return a pointer to the signature to the caller.
+//
+//<TODO>@FUTURE: for short term we have a problem where there is no way to get a
+// fixed up address for a blob and do Merge at the same time. So we've created
+// this dummy table called StandAloneSig which you hand out a rid for. This
+// makes finding the sig an extra indirection that is not required. The
+// Model Compression save code needs to map the token into a byte offset in
+// the heap. Perhaps we can have another mdt* type to switch on the difference.
+// But ultimately it has to simply be "pBlobHeapBase + RidFromToken(mdSig)".</TODO>
+//*****************************************************************************
+STDMETHODIMP RegMeta::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.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ StandAloneSigRec *pRec;
+
+ LOG((LOGMD, "MD RegMeta::GetSigFromToken(0x%08x, 0x%08x, 0x%08x)\n",
+ mdSig, ppvSig, pcbSig));
+
+
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ _ASSERTE(TypeFromToken(mdSig) == mdtSignature);
+ _ASSERTE(ppvSig && pcbSig);
+
+ IfFailGo(pMiniMd->GetStandAloneSigRecord(RidFromToken(mdSig), &pRec));
+ IfFailGo(pMiniMd->getSignatureOfStandAloneSig(pRec, ppvSig, pcbSig));
+
+
+ErrExit:
+
+ STOP_MD_PERF(GetSigFromToken);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::GetSigFromToken()
+
+
+//*******************************************************************************
+// return the ModuleRef properties
+//*******************************************************************************
+STDMETHODIMP RegMeta::GetModuleRefProps( // S_OK or error.
+ mdModuleRef mur, // [IN] moduleref token.
+ __out_ecount_opt (cchName) LPWSTR szName, // [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.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ ModuleRefRec *pModuleRefRec;
+
+
+
+ LOG((LOGMD, "MD RegMeta::GetModuleRefProps(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ mur, szName, cchName, pchName));
+ START_MD_PERF();
+ LOCKREAD();
+
+ IfFailGo(pMiniMd->GetModuleRefRecord(RidFromToken(mur), &pModuleRefRec));
+
+ _ASSERTE(TypeFromToken(mur) == mdtModuleRef);
+
+ // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK
+ if (szName || pchName)
+ {
+ IfFailGo( pMiniMd->getNameOfModuleRef(pModuleRefRec, szName, cchName, pchName) );
+ }
+
+ErrExit:
+
+ STOP_MD_PERF(GetModuleRefProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::GetModuleRefProps()
+
+
+
+//*******************************************************************************
+// enumerating through all of the ModuleRefs
+//*******************************************************************************
+STDMETHODIMP RegMeta::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.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ HENUMInternal *pEnum;
+
+ LOG((LOGMD, "MD RegMeta::EnumModuleRefs(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, rModuleRefs, cMax, pcModuleRefs));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ if (*ppmdEnum == NULL)
+ {
+ // instantiating a new ENUM
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ // create the enumerator
+ IfFailGo(HENUMInternal::CreateSimpleEnum(
+ mdtModuleRef,
+ 1,
+ pMiniMd->getCountModuleRefs() + 1,
+ &pEnum));
+
+ // set the output parameter
+ *ppmdEnum = pEnum;
+ }
+ else
+ {
+ pEnum = *ppmdEnum;
+ }
+
+ // we can only fill the minimun of what caller asked for or what we have left
+ IfFailGo(HENUMInternal::EnumWithCount(pEnum, cMax, rModuleRefs, pcModuleRefs));
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+
+ STOP_MD_PERF(EnumModuleRefs);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::EnumModuleRefs()
+
+
+//*******************************************************************************
+// return properties regarding a TypeSpec
+//*******************************************************************************
+STDMETHODIMP RegMeta::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.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ TypeSpecRec *pRec = NULL;
+
+ LOG((LOGMD, "MD RegMeta::GetTypeSpecFromToken(0x%08x, 0x%08x, 0x%08x)\n",
+ typespec, ppvSig, pcbSig));
+
+
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ _ASSERTE(TypeFromToken(typespec) == mdtTypeSpec);
+ _ASSERTE(ppvSig && pcbSig);
+
+ IfFailGo(pMiniMd->GetTypeSpecRecord(RidFromToken(typespec), &pRec));
+ IfFailGo(pMiniMd->getSignatureOfTypeSpec(pRec, ppvSig, pcbSig));
+
+ErrExit:
+
+ STOP_MD_PERF(GetTypeSpecFromToken);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // STDMETHODIMP RegMeta::GetTypeSpecFromToken()
+
+
+//*****************************************************************************
+// For those items that have a name, retrieve a direct pointer to the name
+// off of the heap. This reduces copies made for the caller.
+//*****************************************************************************
+#define NAME_FROM_TOKEN_TYPE(RecType, TokenType) \
+ case mdt ## TokenType: \
+ { \
+ RecType ## Rec *pRecord; \
+ IfFailGo(pMiniMd->Get ## RecType ## Record(RidFromToken(tk), &pRecord)); \
+ IfFailGo(pMiniMd->getNameOf ## RecType (pRecord, pszUtf8NamePtr)); \
+ } \
+ break;
+#define NAME_FROM_TOKEN(RecType) NAME_FROM_TOKEN_TYPE(RecType, RecType)
+
+STDMETHODIMP RegMeta::GetNameFromToken( // S_OK or error.
+ mdToken tk, // [IN] Token to get name from. Must have a name.
+ MDUTF8CSTR *pszUtf8NamePtr) // [OUT] Return pointer to UTF8 name in heap.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ LOG((LOGMD, "MD RegMeta::GetNameFromToken(0x%08x, 0x%08x)\n",
+ tk, pszUtf8NamePtr));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ _ASSERTE(pszUtf8NamePtr);
+
+ switch (TypeFromToken(tk))
+ {
+ NAME_FROM_TOKEN(Module);
+ NAME_FROM_TOKEN(TypeRef);
+ NAME_FROM_TOKEN(TypeDef);
+ NAME_FROM_TOKEN_TYPE(Field, FieldDef);
+ NAME_FROM_TOKEN_TYPE(Method, MethodDef);
+ NAME_FROM_TOKEN_TYPE(Param, ParamDef);
+ NAME_FROM_TOKEN(MemberRef);
+ NAME_FROM_TOKEN(Event);
+ NAME_FROM_TOKEN(Property);
+ NAME_FROM_TOKEN(ModuleRef);
+
+ default:
+ hr = E_INVALIDARG;
+ }
+
+ErrExit:
+
+ STOP_MD_PERF(GetNameFromToken);
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return (hr);
+} // RegMeta::GetNameFromToken
+
+
+//*****************************************************************************
+// Get the symbol binding data back from the module if it is there. It is
+// stored as a custom value.
+//*****************************************************************************
+STDMETHODIMP RegMeta::EnumUnresolvedMethods( // S_OK 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.
+{
+#ifdef FEATURE_METADATA_EMIT
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal ** ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ ULONG iCountTypeDef; // Count of TypeDefs.
+ ULONG ulStart, ulEnd; // Bounds of methods on a given TypeDef.
+ ULONG index; // For counting methods on a TypeDef.
+ ULONG indexTypeDef; // For counting TypeDefs.
+ bool bIsInterface; // Is a given TypeDef an interface?
+ HENUMInternal * pEnum = *ppmdEnum; // Enum we're working with.
+ CMiniMdRW * pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ LOG((LOGMD, "MD RegMeta::EnumUnresolvedMethods(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, rMethods, cMax, pcTokens));
+
+ START_MD_PERF();
+
+ // take the write lock. Because we should have not have two EnumUnresolvedMethods being called at the
+ // same time. Ref to Def map may be calculated incorrectly.
+ LOCKWRITE();
+
+ if ( pEnum == 0 )
+ {
+ // instantiating a new ENUM
+ MethodRec *pMethodRec;
+ TypeDefRec *pTypeDefRec;
+
+ // make sure our ref to def optimization is up to date
+ IfFailGo( RefToDefOptimization() );
+ IfFailGo( HENUMInternal::CreateDynamicArrayEnum( (DWORD) -1, &pEnum) );
+
+ // Loop through all of the methoddef except global functions.
+ // If methoddef has RVA 0 and not miRuntime, mdAbstract, mdVirtual, mdNative,
+ // we will fill it into the enumerator.
+ //
+ iCountTypeDef = pMiniMd->getCountTypeDefs();
+
+ for (indexTypeDef = 2; indexTypeDef <= iCountTypeDef; indexTypeDef ++ )
+ {
+ IfFailGo(pMiniMd->GetTypeDefRecord(indexTypeDef, &pTypeDefRec));
+
+ // If the type is an interface, check the static methods.
+ bIsInterface = IsTdInterface(pTypeDefRec->GetFlags());
+
+ ulStart = pMiniMd->getMethodListOfTypeDef(pTypeDefRec);
+ IfFailGo(pMiniMd->getEndMethodListOfTypeDef(indexTypeDef, &ulEnd));
+
+ // always report errors even with any unimplemented methods
+ for (index = ulStart; index < ulEnd; index++)
+ {
+ RID methodRid;
+ IfFailGo(pMiniMd->GetMethodRid(index, &methodRid));
+ IfFailGo(pMiniMd->GetMethodRecord(methodRid, &pMethodRec));
+
+ // If the type is an interface, and the method is not static, on to next.
+ if (bIsInterface && !IsMdStatic(pMethodRec->GetFlags()))
+ continue;
+
+ if ( IsMiForwardRef(pMethodRec->GetImplFlags()) )
+ {
+ if ( IsMdPinvokeImpl(pMethodRec->GetFlags()) )
+ {
+ continue;
+ }
+ if ( IsMiRuntime(pMethodRec->GetImplFlags()) || IsMiInternalCall(pMethodRec->GetImplFlags()))
+ {
+ continue;
+ }
+
+ if (IsMdAbstract(pMethodRec->GetFlags()))
+ continue;
+
+ // If a methoddef has RVA 0 and it is not an abstract or virtual method.
+ // Nor it is a runtime generated method nore a native method, then we add it
+ // to the unresolved list.
+ //
+ IfFailGo(pMiniMd->GetMethodRid(index, &methodRid));
+ IfFailGo(HENUMInternal::AddElementToEnum(
+ pEnum,
+ TokenFromRid(methodRid, mdtMethodDef)));
+
+ LOG((LOGMD, "MD adding unresolved MethodDef: token=%08x, flags=%08x, impl flags=%08x\n",
+ TokenFromRid(methodRid, mdtMethodDef),
+ pMethodRec->GetFlags(), pMethodRec->GetImplFlags()));
+ }
+ }
+ }
+
+ MemberRefRec *pMemberRefRec;
+ ULONG iCount;
+
+ // loop through MemberRef tables and find all of the unsats
+ iCount = pMiniMd->getCountMemberRefs();
+ for (index = 1; index <= iCount; index++ )
+ {
+ mdToken defToken;
+ mdMemberRef refToken = TokenFromRid(index, mdtMemberRef);
+ IfFailGo(pMiniMd->GetMemberRefRecord(index, &pMemberRefRec));
+ pMiniMd->GetTokenRemapManager()->ResolveRefToDef(refToken, &defToken);
+
+ if ( pMiniMd->getClassOfMemberRef(pMemberRefRec) == m_tdModule && defToken == refToken )
+ {
+ // unresovled externals reference if parent token is not resolved and this ref token does not
+ // map to any def token (can be MethodDef or FieldDef).
+ //
+ IfFailGo( HENUMInternal::AddElementToEnum(pEnum, refToken) );
+
+ LOG((LOGMD, "MD adding unresolved MemberRef: token=%08x, doesn't have a proper parent\n",
+ refToken ));
+ }
+ }
+
+ // set the output parameter
+ *ppmdEnum = pEnum;
+ }
+
+ // fill the output token buffer
+ hr = HENUMInternal::EnumWithCount(pEnum, cMax, rMethods, pcTokens);
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+
+ STOP_MD_PERF(EnumUnresolvedMethods);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+#else //!FEATURE_METADATA_EMIT
+ return E_NOTIMPL;
+#endif //!FEATURE_METADATA_EMIT
+} // RegMeta::EnumUnresolvedMethods
+
+//*****************************************************************************
+// Return the User string given the token. The offset into the Blob pool where
+// the string is stored in Unicode is embedded inside the token.
+//*****************************************************************************
+STDMETHODIMP RegMeta::GetUserString( // S_OK or error.
+ mdString stk, // [IN] String token.
+ __out_ecount_opt(cchStringSize) LPWSTR wszString, // [OUT] Copy of string.
+ ULONG cchStringSize, // [IN] Max chars of room in szString.
+ ULONG *pcchStringSize) // [OUT] How many chars in actual string.
+{
+ HRESULT hr = S_OK;
+ ULONG cchStringSize_Dummy;
+ MetaData::DataBlob userString;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "MD RegMeta::GetUserString(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ stk, wszString, cchStringSize, pcchStringSize));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ // Get the string data.
+ IfFailGo(m_pStgdb->m_MiniMd.GetUserString(RidFromToken(stk), &userString));
+ // Want to get whole characters, followed by byte to indicate whether there
+ // are extended characters (>= 0x80).
+ if ((userString.GetSize() % sizeof(WCHAR)) == 0)
+ {
+ Debug_ReportError("User strings should have 1 byte terminator (either 0x00 or 0x80).");
+ IfFailGo(CLDB_E_FILE_CORRUPT);
+ }
+
+ // Strip off the last byte.
+ if (!userString.TruncateBySize(1))
+ {
+ Debug_ReportInternalError("There's a bug, because previous % 2 check didn't return 0.");
+ IfFailGo(METADATA_E_INTERNAL_ERROR);
+ }
+
+ // Convert bytes to characters.
+ if (pcchStringSize == NULL)
+ {
+ pcchStringSize = &cchStringSize_Dummy;
+ }
+ *pcchStringSize = userString.GetSize() / sizeof(WCHAR);
+
+ // Copy the string back to the caller.
+ if ((wszString != NULL) && (cchStringSize > 0))
+ {
+ ULONG cbStringSize = cchStringSize * sizeof(WCHAR);
+ memcpy(
+ wszString,
+ userString.GetDataPointer(),
+ min(userString.GetSize(), cbStringSize));
+ if (cbStringSize < userString.GetSize())
+ {
+ if ((wszString != NULL) && (cchStringSize > 0))
+ { // null-terminate the truncated output string
+ wszString[cchStringSize - 1] = W('\0');
+ }
+
+ hr = CLDB_S_TRUNCATION;
+ }
+ }
+
+ ErrExit:
+ STOP_MD_PERF(GetUserString);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // RegMeta::GetUserString
+
+//*****************************************************************************
+// Return contents of Pinvoke given the forwarded member token.
+//*****************************************************************************
+STDMETHODIMP RegMeta::GetPinvokeMap( // S_OK or error.
+ mdToken tk, // [IN] FieldDef or MethodDef.
+ DWORD *pdwMappingFlags, // [OUT] Flags used for mapping.
+ __out_ecount_opt (cchImportName) LPWSTR szImportName, // [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.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ ImplMapRec * pRecord;
+ ULONG iRecord;
+
+ LOG((LOGMD, "MD RegMeta::GetPinvokeMap(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ tk, pdwMappingFlags, szImportName, cchImportName, pchImportName, pmrImportDLL));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ _ASSERTE(TypeFromToken(tk) == mdtFieldDef ||
+ TypeFromToken(tk) == mdtMethodDef);
+
+ IfFailGo(m_pStgdb->m_MiniMd.FindImplMapHelper(tk, &iRecord));
+ if (InvalidRid(iRecord))
+ {
+ IfFailGo( CLDB_E_RECORD_NOTFOUND );
+ }
+ else
+ IfFailGo(m_pStgdb->m_MiniMd.GetImplMapRecord(iRecord, &pRecord));
+
+ if (pdwMappingFlags)
+ *pdwMappingFlags = m_pStgdb->m_MiniMd.getMappingFlagsOfImplMap(pRecord);
+ if (pmrImportDLL)
+ *pmrImportDLL = m_pStgdb->m_MiniMd.getImportScopeOfImplMap(pRecord);
+ // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK
+ if (szImportName || pchImportName)
+ IfFailGo(m_pStgdb->m_MiniMd.getImportNameOfImplMap(pRecord, szImportName, cchImportName, pchImportName));
+ErrExit:
+ STOP_MD_PERF(GetPinvokeMap);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // HRESULT RegMeta::GetPinvokeMap()
+
+//*****************************************************************************
+// Enumerate through all the local sigs.
+//*****************************************************************************
+STDMETHODIMP RegMeta::EnumSignatures( // S_OK or error.
+ HCORENUM *phEnum, // [IN|OUT] pointer to the enum.
+ mdModuleRef rSignatures[], // [OUT] put signatures here.
+ ULONG cmax, // [IN] max signatures to put.
+ ULONG *pcSignatures) // [OUT] put # put here.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppsigEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ HENUMInternal *pEnum;
+
+ LOG((LOGMD, "MD RegMeta::EnumSignatures(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, rSignatures, cmax, pcSignatures));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ if (*ppsigEnum == NULL)
+ {
+ // instantiating a new ENUM
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ // create the enumerator.
+ IfFailGo(HENUMInternal::CreateSimpleEnum(
+ mdtSignature,
+ 1,
+ pMiniMd->getCountStandAloneSigs() + 1,
+ &pEnum));
+
+ // set the output parameter
+ *ppsigEnum = pEnum;
+ }
+ else
+ {
+ pEnum = *ppsigEnum;
+ }
+
+ // we can only fill the minimum of what caller asked for or what we have left.
+ IfFailGo(HENUMInternal::EnumWithCount(pEnum, cmax, rSignatures, pcSignatures));
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppsigEnum);
+
+ STOP_MD_PERF(EnumSignatures);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::EnumSignatures
+
+
+//*****************************************************************************
+// Enumerate through all the TypeSpec
+//*****************************************************************************
+STDMETHODIMP RegMeta::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.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ HENUMInternal *pEnum;
+
+ LOG((LOGMD, "MD RegMeta::EnumTypeSpecs(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, rTypeSpecs, cmax, pcTypeSpecs));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ if (*ppEnum == NULL)
+ {
+ // instantiating a new ENUM
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ // create the enumerator.
+ IfFailGo(HENUMInternal::CreateSimpleEnum(
+ mdtTypeSpec,
+ 1,
+ pMiniMd->getCountTypeSpecs() + 1,
+ &pEnum));
+
+ // set the output parameter
+ *ppEnum = pEnum;
+ }
+ else
+ {
+ pEnum = *ppEnum;
+ }
+
+ // we can only fill the minimum of what caller asked for or what we have left.
+ IfFailGo(HENUMInternal::EnumWithCount(pEnum, cmax, rTypeSpecs, pcTypeSpecs));
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppEnum);
+
+ STOP_MD_PERF(EnumTypeSpecs);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::EnumTypeSpecs
+
+
+//*****************************************************************************
+// Enumerate through all the User Strings.
+//*****************************************************************************
+STDMETHODIMP RegMeta::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.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ HENUMInternal *pEnum = *ppEnum;
+
+ LOG((LOGMD, "MD RegMeta::EnumUserStrings(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, rStrings, cmax, pcStrings));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ if (pEnum == NULL)
+ {
+ // instantiating a new ENUM.
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ IfFailGo(HENUMInternal::CreateDynamicArrayEnum(mdtString, &pEnum));
+
+ // Add all strings to the dynamic array
+ for (UINT32 nIndex = 0; ;)
+ {
+ MetaData::DataBlob userString;
+ UINT32 nNextIndex;
+ hr = pMiniMd->GetUserStringAndNextIndex(
+ nIndex,
+ &userString,
+ &nNextIndex);
+ IfFailGo(hr);
+ if (hr == S_FALSE)
+ { // We reached the last user string
+ hr = S_OK;
+ break;
+ }
+ _ASSERTE(hr == S_OK);
+
+ // Skip empty strings
+ if (userString.IsEmpty())
+ {
+ nIndex = nNextIndex;
+ continue;
+ }
+ // Add the user string into dynamic array
+ IfFailGo(HENUMInternal::AddElementToEnum(
+ pEnum,
+ TokenFromRid(nIndex, mdtString)));
+
+ // Process next user string in the heap
+ nIndex = nNextIndex;
+ }
+
+ // set the output parameter.
+ *ppEnum = pEnum;
+ }
+
+ // fill the output token buffer.
+ hr = HENUMInternal::EnumWithCount(pEnum, cmax, rStrings, pcStrings);
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppEnum);
+
+
+ STOP_MD_PERF(EnumUserStrings);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::EnumUserStrings
+
+
+//*****************************************************************************
+// This routine gets the param token given a method and index of the parameter.
+//*****************************************************************************
+STDMETHODIMP RegMeta::GetParamForMethodIndex( // S_OK or error.
+ mdMethodDef md, // [IN] Method token.
+ ULONG ulParamSeq, // [IN] Parameter sequence.
+ mdParamDef *ppd) // [IN] Put Param token here.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+
+ LOG((LOGMD, "MD RegMeta::GetParamForMethodIndex(0x%08x, 0x%08x, 0x%08x)\n",
+ md, ulParamSeq, ppd));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ _ASSERTE((TypeFromToken(md) == mdtMethodDef) && (ulParamSeq != ULONG_MAX) && (ppd != NULL));
+
+ IfFailGo(_FindParamOfMethod(md, ulParamSeq, ppd));
+ErrExit:
+
+ STOP_MD_PERF(GetParamForMethodIndex);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::GetParamForMethodIndex()
+
+//*****************************************************************************
+// Return the property of a MethodDef or a FieldDef
+//*****************************************************************************
+HRESULT RegMeta::GetMemberProps(
+ mdToken mb, // The member for which to get props.
+ mdTypeDef *pClass, // Put member's class here.
+ __out_ecount_opt (cchMember) LPWSTR szMember, // 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 *pchValue) // [OUT] size of constant value, string only, wide chars
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "MD RegMeta::GetMemberProps(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ mb, pClass, szMember, cchMember, pchMember, pdwAttr, ppvSigBlob, pcbSigBlob,
+ pulCodeRVA, pdwImplFlags, pdwCPlusTypeFlag, ppValue, pchValue));
+
+
+
+ START_MD_PERF();
+
+ _ASSERTE(TypeFromToken(mb) == mdtMethodDef || TypeFromToken(mb) == mdtFieldDef);
+
+ // No need to lock this function. It is calling public APIs. Keep it that way.
+
+ if (TypeFromToken(mb) == mdtMethodDef)
+ {
+ // It is a Method
+ IfFailGo( GetMethodProps(
+ mb,
+ pClass,
+ szMember,
+ cchMember,
+ pchMember,
+ pdwAttr,
+ ppvSigBlob,
+ pcbSigBlob,
+ pulCodeRVA,
+ pdwImplFlags) );
+ }
+ else
+ {
+ // It is a Field
+ IfFailGo( GetFieldProps(
+ mb,
+ pClass,
+ szMember,
+ cchMember,
+ pchMember,
+ pdwAttr,
+ ppvSigBlob,
+ pcbSigBlob,
+ pdwCPlusTypeFlag,
+ ppValue,
+ pchValue) );
+ }
+ErrExit:
+ STOP_MD_PERF(GetMemberProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // HRESULT RegMeta::GetMemberProps()
+
+//*****************************************************************************
+// Return the property of a FieldDef
+//*****************************************************************************
+HRESULT RegMeta::GetFieldProps(
+ mdFieldDef fd, // The field for which to get props.
+ mdTypeDef *pClass, // Put field's class here.
+ __out_ecount_opt (cchField) 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 *pchValue) // [OUT] size of constant value, string only, wide chars
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ FieldRec *pFieldRec;
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ LOG((LOGMD, "MD RegMeta::GetFieldProps(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ fd, pClass, szField, cchField, pchField, pdwAttr, ppvSigBlob, pcbSigBlob, pdwCPlusTypeFlag,
+ ppValue, pchValue));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ _ASSERTE(TypeFromToken(fd) == mdtFieldDef);
+
+ IfFailGo(pMiniMd->GetFieldRecord(RidFromToken(fd), &pFieldRec));
+
+ if (pClass)
+ {
+ // caller wants parent typedef
+ IfFailGo( pMiniMd->FindParentOfFieldHelper(fd, pClass) );
+
+ if ( IsGlobalMethodParentToken(*pClass) )
+ {
+ // If the parent of Field is the <Module>, return mdTypeDefNil instead.
+ *pClass = mdTypeDefNil;
+ }
+ }
+ if (ppvSigBlob || pcbSigBlob)
+ {
+ // caller wants signature information
+ PCCOR_SIGNATURE pvSigTmp;
+ ULONG cbSig;
+ IfFailGo(pMiniMd->getSignatureOfField(pFieldRec, &pvSigTmp, &cbSig));
+ if ( ppvSigBlob )
+ *ppvSigBlob = pvSigTmp;
+ if ( pcbSigBlob)
+ *pcbSigBlob = cbSig;
+ }
+ if ( pdwAttr )
+ {
+ *pdwAttr = pMiniMd->getFlagsOfField(pFieldRec);
+ }
+ if ( pdwCPlusTypeFlag || ppValue || pchValue)
+ {
+ // get the constant value
+ ULONG cbValue;
+ RID rid;
+ IfFailGo(pMiniMd->FindConstantHelper(fd, &rid));
+
+ if (pchValue)
+ *pchValue = 0;
+
+ if (InvalidRid(rid))
+ {
+ // There is no constant value associate with it
+ if (pdwCPlusTypeFlag)
+ *pdwCPlusTypeFlag = ELEMENT_TYPE_VOID;
+
+ if ( ppValue )
+ *ppValue = NULL;
+ }
+ else
+ {
+ ConstantRec *pConstantRec;
+ IfFailGo(m_pStgdb->m_MiniMd.GetConstantRecord(rid, &pConstantRec));
+ DWORD dwType;
+
+ // get the type of constant value
+ dwType = pMiniMd->getTypeOfConstant(pConstantRec);
+ if ( pdwCPlusTypeFlag )
+ *pdwCPlusTypeFlag = dwType;
+
+ // get the value blob
+ if (ppValue != NULL)
+ {
+ IfFailGo(pMiniMd->getValueOfConstant(pConstantRec, (const BYTE **)ppValue, &cbValue));
+ if (pchValue && dwType == ELEMENT_TYPE_STRING)
+ *pchValue = cbValue / sizeof(WCHAR);
+ }
+ }
+ }
+ // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK
+ if (szField || pchField)
+ {
+ IfFailGo( pMiniMd->getNameOfField(pFieldRec, szField, cchField, pchField) );
+ }
+
+ErrExit:
+ STOP_MD_PERF(GetFieldProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // HRESULT RegMeta::GetFieldProps()
+
+//*****************************************************************************
+// return the properties of a property token
+//*****************************************************************************
+HRESULT RegMeta::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 *pchDefaultValue, // [OUT] size of constant value, string only, wide chars
+ 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
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CMiniMdRW *pMiniMd;
+ PropertyRec *pRec;
+ HENUMInternal hEnum;
+
+ LOG((LOGMD, "MD RegMeta::GetPropertyProps(0x%08x, 0x%08x, %S, 0x%08x, 0x%08x, "
+ "0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, "
+ "0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, "
+ "0x%08x)\n",
+ prop, pClass, MDSTR(szProperty), cchProperty, pchProperty,
+ pdwPropFlags, ppvSig, pbSig, pdwCPlusTypeFlag, ppDefaultValue,
+ pchDefaultValue, pmdSetter, pmdGetter, rmdOtherMethod, cMax,
+ pcOtherMethod));
+
+
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ _ASSERTE(TypeFromToken(prop) == mdtProperty);
+
+ pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ memset(&hEnum, 0, sizeof(HENUMInternal));
+ IfFailGo(pMiniMd->GetPropertyRecord(RidFromToken(prop), &pRec));
+
+ if ( pClass )
+ {
+ // find the property map entry corresponding to this property
+ IfFailGo( pMiniMd->FindParentOfPropertyHelper( prop, pClass) );
+ }
+ if ( pdwPropFlags )
+ {
+ *pdwPropFlags = pMiniMd->getPropFlagsOfProperty(pRec);
+ }
+ if ( ppvSig || pbSig )
+ {
+ // caller wants the signature
+ //
+ ULONG cbSig;
+ PCCOR_SIGNATURE pvSig;
+ IfFailGo(pMiniMd->getTypeOfProperty(pRec, &pvSig, &cbSig));
+ if ( ppvSig )
+ {
+ *ppvSig = pvSig;
+ }
+ if ( pbSig )
+ {
+ *pbSig = cbSig;
+ }
+ }
+ if ( pdwCPlusTypeFlag || ppDefaultValue || pchDefaultValue)
+ {
+ // get the constant value
+ ULONG cbValue;
+ RID rid;
+ IfFailGo(pMiniMd->FindConstantHelper(prop, &rid));
+
+ if (pchDefaultValue)
+ *pchDefaultValue = 0;
+
+ if (InvalidRid(rid))
+ {
+ // There is no constant value associate with it
+ if (pdwCPlusTypeFlag)
+ *pdwCPlusTypeFlag = ELEMENT_TYPE_VOID;
+
+ if ( ppDefaultValue )
+ *ppDefaultValue = NULL;
+ }
+ else
+ {
+ ConstantRec *pConstantRec;
+ IfFailGo(m_pStgdb->m_MiniMd.GetConstantRecord(rid, &pConstantRec));
+ DWORD dwType;
+
+ // get the type of constant value
+ dwType = pMiniMd->getTypeOfConstant(pConstantRec);
+ if ( pdwCPlusTypeFlag )
+ *pdwCPlusTypeFlag = dwType;
+
+ // get the value blob
+ if (ppDefaultValue != NULL)
+ {
+ IfFailGo(pMiniMd->getValueOfConstant(pConstantRec, (const BYTE **)ppDefaultValue, &cbValue));
+ if (pchDefaultValue && dwType == ELEMENT_TYPE_STRING)
+ *pchDefaultValue = cbValue / sizeof(WCHAR);
+ }
+ }
+ }
+ {
+ MethodSemanticsRec *pSemantics;
+ RID ridCur;
+ ULONG cCurOtherMethod = 0;
+ ULONG ulSemantics;
+ mdMethodDef tkMethod;
+
+ // initialize output parameters
+ if (pmdSetter)
+ *pmdSetter = mdMethodDefNil;
+ if (pmdGetter)
+ *pmdGetter = mdMethodDefNil;
+
+ IfFailGo( pMiniMd->FindMethodSemanticsHelper(prop, &hEnum) );
+ while (HENUMInternal::EnumNext(&hEnum, (mdToken *)&ridCur))
+ {
+ IfFailGo(pMiniMd->GetMethodSemanticsRecord(ridCur, &pSemantics));
+ ulSemantics = pMiniMd->getSemanticOfMethodSemantics(pSemantics);
+ tkMethod = TokenFromRid( pMiniMd->getMethodOfMethodSemantics(pSemantics), mdtMethodDef );
+ switch (ulSemantics)
+ {
+ case msSetter:
+ if (pmdSetter) *pmdSetter = tkMethod;
+ break;
+ case msGetter:
+ if (pmdGetter) *pmdGetter = tkMethod;
+ break;
+ case msOther:
+ if (cCurOtherMethod < cMax)
+ rmdOtherMethod[cCurOtherMethod] = tkMethod;
+ cCurOtherMethod ++;
+ break;
+ default:
+ _ASSERTE(!"BadKind!");
+ }
+ }
+
+ // set the output parameter
+ if (pcOtherMethod)
+ *pcOtherMethod = cCurOtherMethod;
+ }
+ // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK
+ if (szProperty || pchProperty)
+ {
+ IfFailGo( pMiniMd->getNameOfProperty(pRec, (LPWSTR) szProperty, cchProperty, pchProperty) );
+ }
+
+ErrExit:
+ HENUMInternal::ClearEnum(&hEnum);
+ STOP_MD_PERF(GetPropertyProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // HRESULT RegMeta::GetPropertyProps()
+
+
+//*****************************************************************************
+// This routine gets the properties for the given Param token.
+//*****************************************************************************
+HRESULT RegMeta::GetParamProps( // S_OK or error.
+ mdParamDef pd, // [IN]The Parameter.
+ mdMethodDef *pmd, // [OUT] Parent Method token.
+ ULONG *pulSequence, // [OUT] Parameter sequence.
+ __out_ecount_opt (cchName) LPWSTR szName, // [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 *pchValue) // [OUT] size of constant value, string only, wide chars
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ ParamRec *pParamRec;
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ LOG((LOGMD, "MD RegMeta::GetParamProps(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ pd, pmd, pulSequence, szName, cchName, pchName, pdwAttr, pdwCPlusTypeFlag, ppValue, pchValue));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ _ASSERTE(TypeFromToken(pd) == mdtParamDef);
+
+ IfFailGo(pMiniMd->GetParamRecord(RidFromToken(pd), &pParamRec));
+
+ if (pmd)
+ {
+ IfFailGo(pMiniMd->FindParentOfParamHelper(pd, pmd));
+ _ASSERTE(TypeFromToken(*pmd) == mdtMethodDef);
+ }
+ if (pulSequence)
+ *pulSequence = pMiniMd->getSequenceOfParam(pParamRec);
+ if (pdwAttr)
+ {
+ *pdwAttr = pMiniMd->getFlagsOfParam(pParamRec);
+ }
+ if ( pdwCPlusTypeFlag || ppValue || pchValue)
+ {
+ // get the constant value
+ ULONG cbValue;
+ RID rid;
+ IfFailGo(pMiniMd->FindConstantHelper(pd, &rid));
+
+ if (pchValue)
+ *pchValue = 0;
+
+ if (InvalidRid(rid))
+ {
+ // There is no constant value associate with it
+ if (pdwCPlusTypeFlag)
+ *pdwCPlusTypeFlag = ELEMENT_TYPE_VOID;
+
+ if ( ppValue )
+ *ppValue = NULL;
+ }
+ else
+ {
+ ConstantRec *pConstantRec;
+ IfFailGo(m_pStgdb->m_MiniMd.GetConstantRecord(rid, &pConstantRec));
+ DWORD dwType;
+
+ // get the type of constant value
+ dwType = pMiniMd->getTypeOfConstant(pConstantRec);
+ if ( pdwCPlusTypeFlag )
+ *pdwCPlusTypeFlag = dwType;
+
+ // get the value blob
+ if (ppValue != NULL)
+ {
+ IfFailGo(pMiniMd->getValueOfConstant(pConstantRec, (const BYTE **)ppValue, &cbValue));
+ if (pchValue && dwType == ELEMENT_TYPE_STRING)
+ *pchValue = cbValue / sizeof(WCHAR);
+ }
+ }
+ }
+ // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK
+ if (szName || pchName)
+ IfFailGo( pMiniMd->getNameOfParam(pParamRec, szName, cchName, pchName) );
+
+ErrExit:
+ STOP_MD_PERF(GetParamProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // HRESULT RegMeta::GetParamProps()
+
+//*****************************************************************************
+// This routine gets the properties for the given GenericParam token.
+//*****************************************************************************
+HRESULT RegMeta::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)
+ __out_ecount_opt (cchName) LPWSTR szName, // [OUT] The name
+ ULONG cchName, // [IN] Size of name buffer
+ ULONG *pchName) // [OUT] Actual size of name
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ GenericParamRec *pGenericParamRec;
+ CMiniMdRW *pMiniMd = NULL;
+ RID ridRD = RidFromToken(rd);
+
+
+ LOG((LOGMD, "MD RegMeta::GetGenericParamProps(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ rd, pulSequence, pdwAttr, ptOwner, reserved, szName, cchName, pchName));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ // See if this version of the metadata can do Generics
+ if (!pMiniMd->SupportsGenerics())
+ IfFailGo(CLDB_E_INCOMPATIBLE);
+
+
+ if((TypeFromToken(rd) == mdtGenericParam) && (ridRD != 0))
+ {
+ IfFailGo(pMiniMd->GetGenericParamRecord(RidFromToken(rd), &pGenericParamRec));
+
+ if (pulSequence)
+ *pulSequence = pMiniMd->getNumberOfGenericParam(pGenericParamRec);
+ if (pdwAttr)
+ *pdwAttr = pMiniMd->getFlagsOfGenericParam(pGenericParamRec);
+ if (ptOwner)
+ *ptOwner = pMiniMd->getOwnerOfGenericParam(pGenericParamRec);
+ // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK
+ if (pchName || szName)
+ IfFailGo(pMiniMd->getNameOfGenericParam(pGenericParamRec, szName, cchName, pchName));
+ }
+ else
+ hr = META_E_BAD_INPUT_PARAMETER;
+
+ErrExit:
+ STOP_MD_PERF(GetGenericParamProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // HRESULT RegMeta::GetGenericParamProps()
+
+//*****************************************************************************
+// This routine gets the properties for the given GenericParamConstraint token.
+//*****************************************************************************
+HRESULT RegMeta::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
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ GenericParamConstraintRec *pGPCRec;
+ CMiniMdRW *pMiniMd = NULL;
+ RID ridRD = RidFromToken(rd);
+
+ LOG((LOGMD, "MD RegMeta::GetGenericParamConstraintProps(0x%08x, 0x%08x, 0x%08x)\n",
+ rd, ptGenericParam, ptkConstraintType));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ // See if this version of the metadata can do Generics
+ if (!pMiniMd->SupportsGenerics())
+ IfFailGo(CLDB_E_INCOMPATIBLE);
+
+
+ if((TypeFromToken(rd) == mdtGenericParamConstraint) && (ridRD != 0))
+ {
+ IfFailGo(pMiniMd->GetGenericParamConstraintRecord(ridRD, &pGPCRec));
+
+ if (ptGenericParam)
+ *ptGenericParam = TokenFromRid(pMiniMd->getOwnerOfGenericParamConstraint(pGPCRec),mdtGenericParam);
+ if (ptkConstraintType)
+ *ptkConstraintType = pMiniMd->getConstraintOfGenericParamConstraint(pGPCRec);
+ }
+ else
+ hr = META_E_BAD_INPUT_PARAMETER;
+
+ErrExit:
+ STOP_MD_PERF(GetGenericParamConstraintProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // HRESULT RegMeta::GetGenericParamConstraintProps()
+
+//*****************************************************************************
+// This routine gets the properties for the given MethodSpec token.
+//*****************************************************************************
+HRESULT RegMeta::GetMethodSpecProps( // S_OK or error.
+ 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
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ MethodSpecRec *pMethodSpecRec;
+ CMiniMdRW *pMiniMd = NULL;
+
+ LOG((LOGMD, "MD RegMeta::GetMethodSpecProps(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ mi, tkParent, ppvSigBlob, pcbSigBlob));
+ START_MD_PERF();
+ LOCKREAD();
+
+ pMiniMd = &(m_pStgdb->m_MiniMd);
+
+
+ // See if this version of the metadata can do Generics
+ if (!pMiniMd->SupportsGenerics())
+ IfFailGo(CLDB_E_INCOMPATIBLE);
+
+ _ASSERTE(TypeFromToken(mi) == mdtMethodSpec && RidFromToken(mi));
+
+ IfFailGo(pMiniMd->GetMethodSpecRecord(RidFromToken(mi), &pMethodSpecRec));
+
+ if (tkParent)
+ *tkParent = pMiniMd->getMethodOfMethodSpec(pMethodSpecRec);
+
+ if (ppvSigBlob || pcbSigBlob)
+ {
+ // caller wants signature information
+ PCCOR_SIGNATURE pvSigTmp;
+ ULONG cbSig;
+ IfFailGo(pMiniMd->getInstantiationOfMethodSpec(pMethodSpecRec, &pvSigTmp, &cbSig));
+ if ( ppvSigBlob )
+ *ppvSigBlob = pvSigTmp;
+ if ( pcbSigBlob)
+ *pcbSigBlob = cbSig;
+ }
+
+
+ErrExit:
+
+ STOP_MD_PERF(GetMethodSpecProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // HRESULT RegMeta::GetMethodSpecProps()
+
+//*****************************************************************************
+// This routine gets the type and machine of the PE file the scope is opened on.
+//*****************************************************************************
+HRESULT RegMeta::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
+{
+ HRESULT hr = NOERROR;
+ MAPPINGTYPE mt = MTYPE_NOMAPPING;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "MD RegMeta::GetPEKind(0x%08x, 0x%08x)\n",pdwPEKind,pdwMachine));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+
+ if (m_pStgdb->m_pStgIO != NULL)
+ mt = m_pStgdb->m_pStgIO->GetMemoryMappedType();
+
+ hr = m_pStgdb->GetPEKind(mt, pdwPEKind, pdwMachine);
+
+ ErrExit:
+
+ STOP_MD_PERF(GetPEKind);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // HRESULT RegMeta::GetPEKind()
+
+//*****************************************************************************
+// 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.
+//*****************************************************************************
+HRESULT RegMeta::GetVersionString( // S_OK or error.
+ __out_ecount_opt (cchBufSize) LPWSTR pwzBuf, // [OUT] Put version string here.
+ DWORD cchBufSize, // [in] size of the buffer, in wide chars
+ DWORD *pchBufSize) // [out] Size of the version string, wide chars, including terminating nul.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+ REGMETA_POSSIBLE_INTERNAL_POINTER_EXPOSED();
+
+ DWORD cch; // Length of WideChar string.
+ LPCSTR pVer; // Pointer to version string.
+
+ LOG((LOGMD, "MD RegMeta::GetVersionString(0x%08x, 0x%08x, 0x%08x)\n",pwzBuf,cchBufSize,pchBufSize));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ if (m_pStgdb->m_pvMd != NULL)
+ {
+ // For convenience, get a pointer to the version string.
+ // @todo: get from alternate locations when there is no STOREAGESIGNATURE.
+ pVer = reinterpret_cast<const char*>(reinterpret_cast<const STORAGESIGNATURE*>(m_pStgdb->m_pvMd)->pVersion);
+ // Attempt to convert into caller's buffer.
+ cch = WszMultiByteToWideChar(CP_UTF8,0, pVer,-1, pwzBuf,cchBufSize);
+ // Did the string fit?
+ if (cch == 0)
+ { // No, didn't fit. Find out space required.
+ cch = WszMultiByteToWideChar(CP_UTF8,0, pVer,-1, pwzBuf,0);
+ // NUL terminate string.
+ if (cchBufSize > 0)
+ pwzBuf[cchBufSize-1] = W('\0');
+ // Truncation return code.
+ hr = CLDB_S_TRUNCATION;
+ }
+ }
+ else
+ { // No string.
+ if (cchBufSize > 0)
+ *pwzBuf = W('\0');
+ cch = 0;
+ }
+
+ if (pchBufSize)
+ *pchBufSize = cch;
+
+ErrExit:
+
+ STOP_MD_PERF(GetVersionString);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // HRESULT RegMeta::GetVersionString()
+
+//*****************************************************************************
+// This routine gets the parent class for the nested class.
+//*****************************************************************************
+HRESULT RegMeta::GetNestedClassProps( // S_OK or error.
+ mdTypeDef tdNestedClass, // [IN] NestedClass token.
+ mdTypeDef *ptdEnclosingClass) // [OUT] EnclosingClass token.
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ NestedClassRec *pRecord;
+ ULONG iRecord;
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+
+ LOG((LOGMD, "MD RegMeta::GetNestedClassProps(0x%08x, 0x%08x)\n",
+ tdNestedClass, ptdEnclosingClass));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ // If not a typedef -- return error.
+ if (TypeFromToken(tdNestedClass) != mdtTypeDef)
+ {
+ IfFailGo(META_E_INVALID_TOKEN_TYPE); // PostError(META_E_INVALID_TOKEN_TYPE, tdNestedClass));
+ }
+
+ _ASSERTE(TypeFromToken(tdNestedClass) && !IsNilToken(tdNestedClass) && ptdEnclosingClass);
+
+ IfFailGo(pMiniMd->FindNestedClassHelper(tdNestedClass, &iRecord));
+
+ if (InvalidRid(iRecord))
+ {
+ hr = CLDB_E_RECORD_NOTFOUND;
+ goto ErrExit;
+ }
+
+ IfFailGo(pMiniMd->GetNestedClassRecord(iRecord, &pRecord));
+
+ _ASSERTE(tdNestedClass == pMiniMd->getNestedClassOfNestedClass(pRecord));
+ *ptdEnclosingClass = pMiniMd->getEnclosingClassOfNestedClass(pRecord);
+
+ErrExit:
+ STOP_MD_PERF(GetNestedClassProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // HRESULT RegMeta::GetNestedClassProps()
+
+//*****************************************************************************
+// Given a signature, parse it for custom modifier with calling convention.
+//*****************************************************************************
+HRESULT RegMeta::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).
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ PCCOR_SIGNATURE pvSigBlob = reinterpret_cast<PCCOR_SIGNATURE>(pvSig);
+ ULONG cbTotal = 0; // total of number bytes for return type + all fixed arguments
+ ULONG cbCur = 0; // index through the pvSigBlob
+ ULONG cb;
+ ULONG cArg;
+ ULONG cTyArg = 0;
+ ULONG callingconv;
+ ULONG cArgsIndex;
+ ULONG callConv = pmCallConvWinapi; // The calling convention.
+
+
+
+
+ *pCallConv = pmCallConvWinapi;
+
+ // remember the number of bytes to represent the calling convention
+ cb = CorSigUncompressData (pvSigBlob, &callingconv);
+ if (cb == ((ULONG)(-1)))
+ {
+ hr = CORSEC_E_INVALID_IMAGE_FORMAT;
+ goto ErrExit;
+ }
+ cbCur += cb;
+
+ // remember the number of bytes to represent the type parameter count
+ if (callingconv & IMAGE_CEE_CS_CALLCONV_GENERIC)
+ {
+ cb= CorSigUncompressData (&pvSigBlob[cbCur], &cTyArg);
+ if (cb == ((ULONG)(-1)))
+ {
+ hr = CORSEC_E_INVALID_IMAGE_FORMAT;
+ goto ErrExit;
+ }
+ cbCur += cb;
+ }
+
+
+ // remember number of bytes to represent the arg counts
+ cb= CorSigUncompressData (&pvSigBlob[cbCur], &cArg);
+ if (cb == ((ULONG)(-1)))
+ {
+ hr = CORSEC_E_INVALID_IMAGE_FORMAT;
+ goto ErrExit;
+ }
+
+ cbCur += cb;
+
+ // Look at the return type.
+ hr = _SearchOneArgForCallConv( &pvSigBlob[cbCur], &cb, &callConv);
+ if (hr == (HRESULT)-1)
+ {
+ *pCallConv = callConv;
+ hr = S_OK;
+ goto ErrExit;
+ }
+ IfFailGo(hr);
+ cbCur += cb;
+ cbTotal += cb;
+
+ // loop through argument until we found ELEMENT_TYPE_SENTINEL or run
+ // out of arguments
+ for (cArgsIndex = 0; cArgsIndex < cArg; cArgsIndex++)
+ {
+ _ASSERTE(cbCur < cbSig);
+ hr = _SearchOneArgForCallConv( &pvSigBlob[cbCur], &cb, &callConv);
+ if (hr == (HRESULT)-1)
+ {
+ *pCallConv = callConv;
+ hr = S_OK;
+ goto ErrExit;
+ }
+ IfFailGo(hr);
+ cbTotal += cb;
+ cbCur += cb;
+ }
+
+ErrExit:
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // HRESULT RegMeta::GetNativeCallConvFromSig()
+
+//*****************************************************************************
+// Helper used by GetNativeCallingConvFromSig.
+//*****************************************************************************
+HRESULT RegMeta::_CheckCmodForCallConv( // S_OK, -1 if found, or error.
+ PCCOR_SIGNATURE pbSig, // [IN] Signature to check.
+ ULONG *pcbTotal, // [OUT] Put bytes consumed here.
+ ULONG *pCallConv) // [OUT] If found, put calling convention here.
+{
+ ULONG cbTotal = 0; // Bytes consumed.
+ mdToken tk; // Token for callconv.
+ HRESULT hr = NOERROR; // A result.
+ LPCUTF8 szName=0; // Callconv name.
+ LPCUTF8 szNamespace=0; // Callconv namespace.
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ _ASSERTE(pcbTotal);
+
+
+
+
+ // count the bytes for the token compression
+ cbTotal += CorSigUncompressToken(&pbSig[cbTotal], &tk);
+
+ // workaround to skip nil tokens and TypeSpec tokens.
+ if (IsNilToken(tk) || TypeFromToken(tk) == mdtTypeSpec)
+ {
+ *pcbTotal = cbTotal;
+ goto ErrExit;
+ }
+
+ // See if this token is a calling convention.
+ if (TypeFromToken(tk) == mdtTypeRef)
+ {
+ TypeRefRec *pTypeRefRec;
+ IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tk), &pTypeRefRec));
+ IfFailGo(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szNamespace));
+ }
+ else
+ if (TypeFromToken(tk) == mdtTypeDef)
+ {
+ TypeDefRec *pTypeDefRec;
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tk), &pTypeDefRec));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeDefRec, &szName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeDefRec, &szNamespace));
+ }
+
+ if ((szNamespace && szName) &&
+ (strcmp(szNamespace, CMOD_CALLCONV_NAMESPACE) == 0 ||
+ strcmp(szNamespace, CMOD_CALLCONV_NAMESPACE_OLD) == 0) )
+ {
+ // Set the hr to -1, which is an unspecified 'error'. This will percolate
+ // back up to the caller, where the 'error' should be recognized.
+ hr=(HRESULT)-1;
+ if (strcmp(szName, CMOD_CALLCONV_NAME_CDECL) == 0)
+ *pCallConv = pmCallConvCdecl;
+ else
+ if (strcmp(szName, CMOD_CALLCONV_NAME_STDCALL) == 0)
+ *pCallConv = pmCallConvStdcall;
+ else
+ if (strcmp(szName, CMOD_CALLCONV_NAME_THISCALL) == 0)
+ *pCallConv = pmCallConvThiscall;
+ else
+ if (strcmp(szName, CMOD_CALLCONV_NAME_FASTCALL) == 0)
+ *pCallConv = pmCallConvFastcall;
+ else
+ hr = S_OK; // keep looking
+ IfFailGo(hr);
+ }
+ *pcbTotal = cbTotal;
+
+ErrExit:
+
+ return hr;
+} // HRESULT RegMeta::_CheckCmodForCallConv()
+
+//*****************************************************************************
+// Helper used by GetNativeCallingConvFromSig.
+//*****************************************************************************
+HRESULT RegMeta::_SearchOneArgForCallConv(// S_OK, -1 if found, or error.
+ PCCOR_SIGNATURE pbSig, // [IN] Signature to check.
+ ULONG *pcbTotal, // [OUT] Put bytes consumed here.
+ ULONG *pCallConv) // [OUT] If found, put calling convention here.
+{
+ ULONG cb;
+ ULONG cbTotal = 0;
+ CorElementType ulElementType;
+ ULONG ulData;
+ ULONG ulTemp;
+ int iData;
+ mdToken tk;
+ ULONG cArg;
+ ULONG callingconv;
+ ULONG cArgsIndex;
+ HRESULT hr = NOERROR;
+
+ _ASSERTE(pcbTotal);
+
+ cbTotal += CorSigUncompressElementType(&pbSig[cbTotal], &ulElementType);
+ while (CorIsModifierElementType(ulElementType) || ulElementType == ELEMENT_TYPE_SENTINEL)
+ {
+ cbTotal += CorSigUncompressElementType(&pbSig[cbTotal], &ulElementType);
+ }
+ switch (ulElementType)
+ {
+ case ELEMENT_TYPE_SZARRAY:
+ // skip over base type
+ IfFailGo( _SearchOneArgForCallConv(&pbSig[cbTotal], &cb, pCallConv) );
+ cbTotal += cb;
+ break;
+
+ case ELEMENT_TYPE_VAR :
+ case ELEMENT_TYPE_MVAR :
+ // skip over index
+ cbTotal += CorSigUncompressData(&pbSig[cbTotal], &ulData);
+ break;
+
+ case ELEMENT_TYPE_GENERICINST :
+ // skip over generic type
+ IfFailGo( _SearchOneArgForCallConv(&pbSig[cbTotal], &cb, pCallConv) );
+ cbTotal += cb;
+
+ // skip over number of parameters
+ cbTotal += CorSigUncompressData(&pbSig[cbTotal], &cArg);
+
+ // loop through type parameters
+ for (cArgsIndex = 0; cArgsIndex < cArg; cArgsIndex++)
+ {
+ IfFailGo( _SearchOneArgForCallConv( &pbSig[cbTotal], &cb, pCallConv) );
+ cbTotal += cb;
+ }
+
+ break;
+
+ case ELEMENT_TYPE_FNPTR:
+ cbTotal += CorSigUncompressData (&pbSig[cbTotal], &callingconv);
+
+ // remember number of bytes to represent the arg counts
+ cbTotal += CorSigUncompressData (&pbSig[cbTotal], &cArg);
+
+ // how many bytes to represent the return type
+ IfFailGo( _SearchOneArgForCallConv( &pbSig[cbTotal], &cb, pCallConv) );
+ cbTotal += cb;
+
+ // loop through argument
+ for (cArgsIndex = 0; cArgsIndex < cArg; cArgsIndex++)
+ {
+ IfFailGo( _SearchOneArgForCallConv( &pbSig[cbTotal], &cb, pCallConv) );
+ cbTotal += cb;
+ }
+
+ break;
+
+ case ELEMENT_TYPE_ARRAY:
+ // syntax : ARRAY BaseType <rank> [i size_1... size_i] [j lowerbound_1 ... lowerbound_j]
+
+ // skip over base type
+ IfFailGo( _SearchOneArgForCallConv(&pbSig[cbTotal], &cb, pCallConv) );
+ cbTotal += cb;
+
+ // Parse for the rank
+ cbTotal += CorSigUncompressData(&pbSig[cbTotal], &ulData);
+
+ // if rank == 0, we are done
+ if (ulData == 0)
+ break;
+
+ // any size of dimension specified?
+ cbTotal += CorSigUncompressData(&pbSig[cbTotal], &ulData);
+ while (ulData--)
+ {
+ cbTotal += CorSigUncompressData(&pbSig[cbTotal], &ulTemp);
+ }
+
+ // any lower bound specified?
+ cbTotal = CorSigUncompressData(&pbSig[cbTotal], &ulData);
+
+ while (ulData--)
+ {
+ cbTotal += CorSigUncompressSignedInt(&pbSig[cbTotal], &iData);
+ }
+
+ break;
+ case ELEMENT_TYPE_VALUETYPE:
+ case ELEMENT_TYPE_CLASS:
+ // count the bytes for the token compression
+ cbTotal += CorSigUncompressToken(&pbSig[cbTotal], &tk);
+ break;
+ case ELEMENT_TYPE_CMOD_REQD:
+ case ELEMENT_TYPE_CMOD_OPT:
+ // Check for the calling convention.
+ IfFailGo(_CheckCmodForCallConv(&pbSig[cbTotal], &cb, pCallConv));
+ cbTotal += cb;
+ // skip over base type
+ IfFailGo( _SearchOneArgForCallConv(&pbSig[cbTotal], &cb, pCallConv) );
+ cbTotal += cb;
+ break;
+ default:
+ break;
+ }
+ *pcbTotal = cbTotal;
+
+ErrExit:
+
+ return hr;
+} // HRESULT RegMeta::_SearchOneArgForCallConv()
diff --git a/src/md/compiler/importhelper.cpp b/src/md/compiler/importhelper.cpp
new file mode 100644
index 0000000000..abebe1e805
--- /dev/null
+++ b/src/md/compiler/importhelper.cpp
@@ -0,0 +1,3415 @@
+// 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.
+//*****************************************************************************
+// ImportHelper.cpp
+//
+
+//
+// contains utility code to MD directory
+//
+//*****************************************************************************
+#include "stdafx.h"
+#include "importhelper.h"
+#include "mdutil.h"
+#include "rwutil.h"
+#include "mdlog.h"
+#include "strongname.h"
+#include "sstring.h"
+
+#define COM_RUNTIME_LIBRARY "ComRuntimeLibrary"
+
+
+//*******************************************************************************
+// Find the MethodSpec by Method and Instantiation
+//*******************************************************************************
+//@GENERICS: todo: look in hashtable (cf. MetaModelRW.cpp) if necessary
+HRESULT ImportHelper::FindMethodSpecByMethodAndInstantiation(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ /*mdMethodDefOrRef*/ mdToken tkMethod, // [IN] MethodSpec method field
+ PCCOR_SIGNATURE pInstantiation, // [IN] MethodSpec instantiation (a signature)
+ ULONG cbInstantiation, // [IN] Size of instantiation.
+ mdMethodSpec *pMethodSpec, // [OUT] Put the MethodSpec token here.
+ RID rid /* = 0*/) // [IN] Optional rid to be ignored.
+{
+ HRESULT hr;
+ MethodSpecRec *pRecord;
+ /*mdMethodDefOrRef*/ mdToken tkMethodTmp;
+ PCCOR_SIGNATURE pInstantiationTmp;
+ ULONG cbInstantiationTmp;
+ ULONG cMethodSpecs;
+ ULONG i;
+
+ _ASSERTE(pMethodSpec);
+
+ cMethodSpecs = pMiniMd->getCountMethodSpecs();
+
+ // linear scan through the MethodSpec table
+ for (i=1; i <= cMethodSpecs; ++i)
+ {
+ // For the call from Validator ignore the rid passed in.
+ if (i == rid)
+ continue;
+
+ IfFailRet(pMiniMd->GetMethodSpecRecord(i, &pRecord));
+
+ tkMethodTmp = pMiniMd->getMethodOfMethodSpec(pRecord);
+ if ((tkMethodTmp != tkMethod))
+ continue;
+
+ //@GENERICS: not sure what is meant by duplicate here: identical sig pointers or sig pointer contents?
+ IfFailRet(pMiniMd->getInstantiationOfMethodSpec(pRecord, &pInstantiationTmp, &cbInstantiationTmp));
+ if (cbInstantiationTmp != cbInstantiation || memcmp(pInstantiation, pInstantiationTmp, cbInstantiation))
+ continue;
+
+ // Matching record found.
+ *pMethodSpec = TokenFromRid(i, mdtMethodSpec);
+ return S_OK;
+ }
+ return CLDB_E_RECORD_NOTFOUND;
+} // HRESULT ImportHelper::FindMethodSpecByMethodAndInstantiation()
+
+
+//*******************************************************************************
+// Find the GenericParam by owner and constraint
+//*******************************************************************************
+//@GENERICS: todo: look in hashtable (cf. MetaModelRW.cpp) if necessary
+HRESULT ImportHelper::FindGenericParamConstraintByOwnerAndConstraint(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ mdGenericParam tkOwner, // [IN] GenericParamConstraint Owner
+ mdToken tkConstraint, // [IN] GenericParamConstraint Constraint
+ mdGenericParamConstraint *pGenericParamConstraint,// [OUT] Put the GenericParam token here.
+ RID rid /* = 0*/) // [IN] Optional rid to be ignored.
+{
+ HRESULT hr;
+ GenericParamConstraintRec *pRecord;
+ mdGenericParam tkOwnerTmp;
+ mdToken tkConstraintTmp;
+ ULONG cGenericParamConstraints;
+
+ ULONG i;
+
+ _ASSERTE(pGenericParamConstraint);
+
+ cGenericParamConstraints = pMiniMd->getCountGenericParamConstraints();
+
+ // linear scan through the GenericParam table
+ for (i=1; i <= cGenericParamConstraints; ++i)
+ {
+ // For the call from Validator ignore the rid passed in.
+ if (i == rid)
+ continue;
+
+ IfFailRet(pMiniMd->GetGenericParamConstraintRecord(i, &pRecord));
+
+ tkOwnerTmp = pMiniMd->getOwnerOfGenericParamConstraint(pRecord);
+ tkConstraintTmp = pMiniMd->getConstraintOfGenericParamConstraint(pRecord);
+
+ if ((tkOwnerTmp != tkOwner) || (tkConstraintTmp != tkConstraint))
+ continue;
+
+ // Matching record found.
+ *pGenericParamConstraint = TokenFromRid(i, mdtGenericParamConstraint);
+ return S_OK;
+ }
+ return CLDB_E_RECORD_NOTFOUND;
+} // HRESULT ImportHelper::FindGenericParamConstraintByOwnerAndConstraint()
+
+//*******************************************************************************
+// Find the GenericParam by owner and name or number
+//*******************************************************************************
+//<REVISIT_TODO> @GENERICS: todo: look in hashtable (cf. MetaModelRW.cpp) if necessary </REVISIT_TODO>
+HRESULT ImportHelper::FindGenericParamByOwner(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ mdToken tkOwner, // [IN] GenericParam Owner
+ LPCUTF8 szUTF8Name, // [IN] GeneriParam Name, may be NULL if not used for search
+ ULONG *pNumber, // [IN] GeneriParam Number, may be NULL if not used for search
+ mdGenericParam *pGenericParam, // [OUT] Put the GenericParam token here.
+ RID rid /* = 0*/) // [IN] Optional rid to be ignored.
+{
+ HRESULT hr;
+ GenericParamRec *pRecord;
+ mdToken tkOwnerTmp;
+ ULONG cGenericParams;
+ LPCUTF8 szCurName;
+ ULONG curNumber;
+ ULONG i;
+
+ _ASSERTE(pGenericParam);
+
+ cGenericParams = pMiniMd->getCountGenericParams();
+
+ // linear scan through the GenericParam table
+ for (i=1; i <= cGenericParams; ++i)
+ {
+ // For the call from Validator ignore the rid passed in.
+ if (i == rid)
+ continue;
+
+ IfFailRet(pMiniMd->GetGenericParamRecord(i, &pRecord));
+
+ tkOwnerTmp = pMiniMd->getOwnerOfGenericParam(pRecord);
+ if ( tkOwnerTmp != tkOwner)
+ continue;
+
+ // if the name is significant, try to match it
+ if (szUTF8Name)
+ {
+ IfFailRet(pMiniMd->getNameOfGenericParam(pRecord, &szCurName));
+ if (strcmp(szCurName, szUTF8Name))
+ continue;
+ }
+
+ // if the number is significant, try to match it
+ if (pNumber)
+ { curNumber = pMiniMd->getNumberOfGenericParam(pRecord);
+ if (*pNumber != curNumber)
+ continue;
+ }
+
+ // Matching record found.
+ *pGenericParam = TokenFromRid(i, mdtGenericParam);
+ return S_OK;
+ }
+ return CLDB_E_RECORD_NOTFOUND;
+} // HRESULT ImportHelper::FindGenericParamByOwner()
+
+//*******************************************************************************
+// Find a Method given a parent, name and signature.
+//*******************************************************************************
+HRESULT ImportHelper::FindMethod(
+ CMiniMdRW * pMiniMd, // [IN] the minimd to lookup
+ mdTypeDef td, // [IN] parent.
+ LPCUTF8 szName, // [IN] MethodDef name.
+ PCCOR_SIGNATURE pSig, // [IN] Signature.
+ ULONG cbSig, // [IN] Size of signature.
+ mdMethodDef * pmb, // [OUT] Put the MethodDef token here.
+ RID rid, // = 0 // [IN] Optional rid to be ignored.
+ PSIGCOMPARE pSignatureCompare, // = NULL // [IN] Optional Routine to compare signatures
+ void * pCompareContext) // = NULL // [IN] Optional context for the compare function
+{
+ HRESULT hr = S_OK;
+ ULONG ridStart; // Start of td's methods.
+ ULONG ridEnd; // End of td's methods.
+ ULONG index; // Loop control.
+ TypeDefRec *pRec; // A TypeDef Record.
+ MethodRec *pMethod; // A MethodDef Record.
+ LPCUTF8 szNameUtf8Tmp; // A found MethodDef's name.
+ PCCOR_SIGNATURE pSigTmp; // A found MethodDef's signature.
+ ULONG cbSigTmp; // Size of a found MethodDef's signature.
+ PCCOR_SIGNATURE pvSigTemp = pSig; // For use in parsing a signature.
+ CQuickBytes qbSig; // Struct to build a non-varargs signature.
+ CMiniMdRW::HashSearchResult rtn;
+
+ if (cbSig)
+ { // check to see if this is a vararg signature
+ if (isCallConv(CorSigUncompressCallingConv(pvSigTemp), IMAGE_CEE_CS_CALLCONV_VARARG))
+ { // Get the fix part of VARARG signature
+ IfFailGo(_GetFixedSigOfVarArg(pSig, cbSig, &qbSig, &cbSig));
+ pSig = (PCCOR_SIGNATURE) qbSig.Ptr();
+ }
+ }
+
+ *pmb = TokenFromRid(rid, mdtMethodDef); // to know what to ignore
+ rtn = pMiniMd->FindMemberDefFromHash(td, szName, pSig, cbSig, pmb);
+ if (rtn == CMiniMdRW::Found)
+ {
+ goto ErrExit;
+ }
+ else if (rtn == CMiniMdRW::NotFound)
+ {
+ IfFailGo(CLDB_E_RECORD_NOTFOUND);
+ }
+ _ASSERTE(rtn == CMiniMdRW::NoTable);
+
+ *pmb = mdMethodDefNil;
+
+ // get the range of method rids given a typedef
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(td), &pRec));
+ ridStart = pMiniMd->getMethodListOfTypeDef(pRec);
+ IfFailGo(pMiniMd->getEndMethodListOfTypeDef(RidFromToken(td), &ridEnd));
+ // Iterate over the methods.
+ for (index = ridStart; index < ridEnd; index ++ )
+ {
+ RID methodRID;
+ IfFailGo(pMiniMd->GetMethodRid(index, &methodRID));
+ // For the call from Validator ignore the rid passed in.
+ if (methodRID != rid)
+ {
+ // Get the method and its name.
+ IfFailGo(pMiniMd->GetMethodRecord(methodRID, &pMethod));
+ IfFailGo(pMiniMd->getNameOfMethod(pMethod, &szNameUtf8Tmp));
+
+ // If name matches what was requested...
+ if ( strcmp(szNameUtf8Tmp, szName) == 0 )
+ {
+ if (cbSig && pSig)
+ {
+ IfFailGo(pMiniMd->getSignatureOfMethod(pMethod, &pSigTmp, &cbSigTmp));
+
+ // If the caller did not provide a custom compare routine
+ // then we use memcmp to match the signatures
+ //
+ if (pSignatureCompare == NULL)
+ {
+ if (cbSigTmp != cbSig || memcmp(pSig, pSigTmp, cbSig))
+ continue;
+ }
+ else
+ {
+ // Call the custom compare routine
+ //
+ if (!pSignatureCompare(pSigTmp, cbSigTmp, pSig, cbSig, pCompareContext))
+ continue;
+ }
+ }
+ // Ignore PrivateScope methods.
+ if (IsMdPrivateScope(pMiniMd->getFlagsOfMethod(pMethod)))
+ continue;
+
+ // Found method.
+ *pmb = TokenFromRid(methodRID, mdtMethodDef);
+ goto ErrExit;
+ }
+ }
+ }
+
+ // record not found
+ *pmb = mdMethodDefNil;
+ hr = CLDB_E_RECORD_NOTFOUND;
+
+ErrExit:
+ return hr;
+} // ImportHelper::FindMethod
+
+//*******************************************************************************
+// Find a Field given a parent, name and signature.
+//*******************************************************************************
+HRESULT ImportHelper::FindField(
+ CMiniMdRW * pMiniMd, // [IN] the minimd to lookup
+ mdTypeDef td, // [IN] parent.
+ LPCUTF8 szName, // [IN] FieldDef name.
+ PCCOR_SIGNATURE pSig, // [IN] Signature.
+ ULONG cbSig, // [IN] Size of signature.
+ mdFieldDef * pfd, // [OUT] Put the FieldDef token here.
+ RID rid) // = 0 // [IN] Optional rid to be ignored.
+{
+ HRESULT hr = S_OK; // A result.
+ ULONG ridStart; // Start of td's methods.
+ ULONG ridEnd; // End of td's methods.
+ ULONG index; // Loop control.
+ TypeDefRec *pRec; // A TypeDef Record.
+ FieldRec *pField; // A FieldDef Record.
+ LPCUTF8 szNameUtf8Tmp; // A found FieldDef's name.
+ PCCOR_SIGNATURE pSigTmp; // A found FieldDef's signature.
+ ULONG cbSigTmp; // Size of a found FieldDef's signature.
+ CMiniMdRW::HashSearchResult rtn;
+
+ *pfd = TokenFromRid(rid,mdtFieldDef); // to know what to ignore
+ rtn = pMiniMd->FindMemberDefFromHash(td, szName, pSig, cbSig, pfd);
+ if (rtn == CMiniMdRW::Found)
+ {
+ goto ErrExit;
+ }
+ else if (rtn == CMiniMdRW::NotFound)
+ {
+ IfFailGo(CLDB_E_RECORD_NOTFOUND);
+ }
+ _ASSERTE(rtn == CMiniMdRW::NoTable);
+
+ *pfd = mdFieldDefNil;
+
+ // get the range of method rids given a typedef
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(td), &pRec));
+ ridStart = pMiniMd->getFieldListOfTypeDef(pRec);
+ IfFailGo(pMiniMd->getEndFieldListOfTypeDef(RidFromToken(td), &ridEnd));
+
+ // Iterate over the methods.
+ for (index = ridStart; index < ridEnd; index ++ )
+ {
+ RID fieldRID;
+ IfFailGo(pMiniMd->GetFieldRid(index, &fieldRID));
+ // For the call from Validator ignore the rid passed in.
+ if (fieldRID != rid)
+ {
+ // Get the field and its name.
+ IfFailGo(pMiniMd->GetFieldRecord(fieldRID, &pField));
+ IfFailGo(pMiniMd->getNameOfField(pField, &szNameUtf8Tmp));
+
+ // If name matches what was requested...
+ if ( strcmp(szNameUtf8Tmp, szName) == 0 )
+ {
+ // Check signature if specified.
+ if (cbSig && pSig)
+ {
+ IfFailGo(pMiniMd->getSignatureOfField(pField, &pSigTmp, &cbSigTmp));
+ if (cbSigTmp != cbSig || memcmp(pSig, pSigTmp, cbSig))
+ continue;
+ }
+ // Ignore PrivateScope fields.
+ if (IsFdPrivateScope(pMiniMd->getFlagsOfField(pField)))
+ continue;
+ // Field found.
+ *pfd = TokenFromRid(fieldRID, mdtFieldDef);
+ goto ErrExit;
+ }
+ }
+ }
+
+ // record not found
+ *pfd = mdFieldDefNil;
+ hr = CLDB_E_RECORD_NOTFOUND;
+
+ErrExit:
+ return hr;
+} // ImportHelper::FindField
+
+//*******************************************************************************
+// Find a Member given a parent, name and signature.
+//*******************************************************************************
+HRESULT ImportHelper::FindMember(
+ CMiniMdRW * pMiniMd, // [IN] the minimd to lookup
+ mdTypeDef td, // [IN] parent.
+ LPCUTF8 szName, // [IN] Member name.
+ PCCOR_SIGNATURE pSig, // [IN] Signature.
+ ULONG cbSig, // [IN] Size of signature.
+ mdToken * ptk) // [OUT] Put the token here.
+{
+ HRESULT hr;
+
+ if (cbSig == 0)
+ {
+ Debug_ReportError("Invalid signature size 0.");
+ return CLDB_E_INDEX_NOTFOUND;
+ }
+
+ // determine if it is ref to MethodDef or FieldDef
+ if ((pSig[0] & IMAGE_CEE_CS_CALLCONV_MASK) != IMAGE_CEE_CS_CALLCONV_FIELD)
+ {
+ hr = FindMethod(pMiniMd, td, szName, pSig, cbSig, ptk);
+ }
+ else
+ {
+ hr = FindField(pMiniMd, td, szName, pSig, cbSig, ptk);
+ }
+
+ if (hr == CLDB_E_RECORD_NOTFOUND)
+ *ptk = mdTokenNil;
+
+ return hr;
+} // ImportHelper::FindMember
+
+
+//*******************************************************************************
+// Find the memberref given name, sig, and parent
+//*******************************************************************************
+HRESULT ImportHelper::FindMemberRef(
+ CMiniMdRW * pMiniMd, // [IN] the minimd to lookup
+ mdToken tkParent, // [IN] the parent token
+ LPCUTF8 szName, // [IN] memberref name
+ const COR_SIGNATURE * pbSig, // [IN] Signature.
+ ULONG cbSig, // [IN] Size of signature.
+ mdMemberRef * pmr, // [OUT] Put the MemberRef token found
+ RID rid, // = 0 // [IN] Optional rid to be ignored.
+ HashSearchOption fCreateHash) // = DoNotCreateHash // [IN] Should we create hash first? (Optimize for multiple calls vs. single isolated call)
+{
+ ULONG cMemberRefRecs;
+ MemberRefRec * pMemberRefRec;
+ LPCUTF8 szNameTmp = 0;
+ const COR_SIGNATURE * pbSigTmp; // Signature.
+ ULONG cbSigTmp; // Size of signature.
+ mdToken tkParentTmp; // the parent token
+ HRESULT hr = NOERROR;
+ CMiniMdRW::HashSearchResult rtn;
+
+ if ((szName == NULL) || (pmr == NULL))
+ {
+ IfFailGo(CLDB_E_RECORD_NOTFOUND);
+ }
+
+ if (fCreateHash == CreateHash)
+ { // Caller asked for creating hash to optimize for multiple calls
+ IfFailGo(pMiniMd->CreateMemberRefHash());
+ }
+
+ *pmr = TokenFromRid(rid, mdtMemberRef); // to know what to ignore
+ rtn = pMiniMd->FindMemberRefFromHash(tkParent, szName, pbSig, cbSig, pmr);
+ if (rtn == CMiniMdRW::Found)
+ {
+ goto ErrExit;
+ }
+ else if (rtn == CMiniMdRW::NotFound)
+ {
+ IfFailGo(CLDB_E_RECORD_NOTFOUND);
+ }
+ _ASSERTE(rtn == CMiniMdRW::NoTable);
+
+ *pmr = mdMemberRefNil;
+
+ cMemberRefRecs = pMiniMd->getCountMemberRefs();
+
+ // Search for the MemberRef
+ for (ULONG i = 1; i <= cMemberRefRecs; i++)
+ {
+ // For the call from Validator ignore the rid passed in.
+ if (i == rid)
+ continue;
+
+ IfFailGo(pMiniMd->GetMemberRefRecord(i, &pMemberRefRec));
+ if (!IsNilToken(tkParent))
+ {
+ // given a valid parent
+ tkParentTmp = pMiniMd->getClassOfMemberRef(pMemberRefRec);
+ if (tkParentTmp != tkParent)
+ {
+ // if parent is specified and not equal to the current row,
+ // try the next row.
+ continue;
+ }
+ }
+ if ((szName != NULL) && (*szName != 0))
+ {
+ // name is specified
+ IfFailGo(pMiniMd->getNameOfMemberRef(pMemberRefRec, &szNameTmp));
+ if (strcmp(szName, szNameTmp) != 0)
+ {
+ // Name is not equal. Try next row.
+ continue;
+ }
+ }
+ if ((cbSig != 0) && (pbSig != NULL))
+ {
+ // signature is specifed
+ IfFailGo(pMiniMd->getSignatureOfMemberRef(pMemberRefRec, &pbSigTmp, &cbSigTmp));
+ if (cbSigTmp != cbSig)
+ continue;
+ if (memcmp( pbSig, pbSigTmp, cbSig ) != 0)
+ continue;
+ }
+
+ // we found a match
+ *pmr = TokenFromRid(i, mdtMemberRef);
+ return S_OK;
+ }
+ hr = CLDB_E_RECORD_NOTFOUND;
+ErrExit:
+ return hr;
+} // ImportHelper::FindMemberRef
+
+
+
+//*******************************************************************************
+// Find duplicate StandAloneSig
+//*******************************************************************************
+HRESULT ImportHelper::FindStandAloneSig(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ const COR_SIGNATURE *pbSig, // [IN] Signature.
+ ULONG cbSig, // [IN] Size of signature.
+ mdSignature *psa) // [OUT] Put the StandAloneSig token found
+{
+ HRESULT hr;
+ ULONG cRecs;
+ StandAloneSigRec *pRec;
+ const COR_SIGNATURE *pbSigTmp; // Signature.
+ ULONG cbSigTmp; // Size of signature.
+
+
+ _ASSERTE(cbSig && psa);
+ *psa = mdSignatureNil;
+
+ cRecs = pMiniMd->getCountStandAloneSigs();
+
+ // Search for the StandAloneSignature
+ for (ULONG i = 1; i <= cRecs; i++)
+ {
+ IfFailRet(pMiniMd->GetStandAloneSigRecord(i, &pRec));
+ IfFailRet(pMiniMd->getSignatureOfStandAloneSig(pRec, &pbSigTmp, &cbSigTmp));
+ if (cbSigTmp != cbSig)
+ continue;
+ if (memcmp( pbSig, pbSigTmp, cbSig ) != 0)
+ continue;
+
+ // we found a match
+ *psa = TokenFromRid(i, mdtSignature);
+ return S_OK;
+ }
+ return CLDB_E_RECORD_NOTFOUND;
+} // HRESULT ImportHelper::FindStandAloneSig()
+
+//*******************************************************************************
+// Find duplicate TypeSpec
+//*******************************************************************************
+HRESULT
+ImportHelper::FindTypeSpec(
+ CMiniMdRW * pMiniMd, // [IN] the minimd to lookup
+ const COR_SIGNATURE * pbSig, // [IN] Signature.
+ ULONG cbSig, // [IN] Size of signature.
+ mdTypeSpec * pTypeSpec) // [OUT] Put the TypeSpec token found
+{
+ HRESULT hr;
+ ULONG cRecs;
+ TypeSpecRec * pRec;
+ const COR_SIGNATURE * pbSigTmp; // Signature.
+ ULONG cbSigTmp; // Size of signature.
+
+ // cbSig can be 0
+ _ASSERTE(pTypeSpec != NULL);
+ *pTypeSpec = mdSignatureNil;
+
+ cRecs = pMiniMd->getCountTypeSpecs();
+
+ // Search for the TypeSpec
+ for (ULONG i = 1; i <= cRecs; i++)
+ {
+ IfFailRet(pMiniMd->GetTypeSpecRecord(i, &pRec));
+ IfFailRet(pMiniMd->getSignatureOfTypeSpec(pRec, &pbSigTmp, &cbSigTmp));
+ if (cbSigTmp != cbSig)
+ continue;
+ if (memcmp(pbSig, pbSigTmp, cbSig) != 0)
+ continue;
+
+ // we found a match
+ *pTypeSpec = TokenFromRid(i, mdtTypeSpec);
+ return S_OK;
+ }
+ return CLDB_E_RECORD_NOTFOUND;
+} // ImportHelper::FindTypeSpec
+
+
+//*******************************************************************************
+// Find the MethodImpl
+//*******************************************************************************
+HRESULT ImportHelper::FindMethodImpl(
+ CMiniMdRW *pMiniMd, // [IN] The MiniMd to lookup.
+ mdTypeDef tkClass, // [IN] The parent TypeDef token.
+ mdMethodDef tkBody, // [IN] Method body token.
+ mdMethodDef tkDecl, // [IN] Method declaration token.
+ RID *pRid) // [OUT] Put the MethodImpl rid here
+{
+ HRESULT hr;
+ MethodImplRec *pMethodImplRec; // MethodImpl record.
+ ULONG cMethodImplRecs; // Count of MethodImpl records.
+ mdTypeDef tkClassTmp; // Parent TypeDef token.
+ mdToken tkBodyTmp; // Method body token.
+ mdToken tkDeclTmp; // Method declaration token.
+
+ _ASSERTE(TypeFromToken(tkClass) == mdtTypeDef);
+ _ASSERTE(TypeFromToken(tkBody) == mdtMemberRef || TypeFromToken(tkBody) == mdtMethodDef);
+ _ASSERTE(TypeFromToken(tkDecl) == mdtMemberRef || TypeFromToken(tkDecl) == mdtMethodDef);
+ _ASSERTE(!IsNilToken(tkClass) && !IsNilToken(tkBody) && !IsNilToken(tkDecl));
+
+ if (pRid)
+ *pRid = 0;
+
+ cMethodImplRecs = pMiniMd->getCountMethodImpls();
+
+ // Search for the MethodImpl.
+ for (ULONG i = 1; i <= cMethodImplRecs; i++)
+ {
+ IfFailRet(pMiniMd->GetMethodImplRecord(i, &pMethodImplRec));
+
+ // match the parent column
+ tkClassTmp = pMiniMd->getClassOfMethodImpl(pMethodImplRec);
+ if (tkClassTmp != tkClass)
+ continue;
+
+ // match the method body column
+ tkBodyTmp = pMiniMd->getMethodBodyOfMethodImpl(pMethodImplRec);
+ if (tkBodyTmp != tkBody)
+ continue;
+
+ // match the method declaration column
+ tkDeclTmp = pMiniMd->getMethodDeclarationOfMethodImpl(pMethodImplRec);
+ if (tkDeclTmp != tkDecl)
+ continue;
+
+ // we found a match
+ if (pRid)
+ *pRid = i;
+ return S_OK;
+ }
+ return CLDB_E_RECORD_NOTFOUND;
+} // HRESULT ImportHelper::FindMethodImpl()
+
+//*******************************************************************************
+// Find the TypeRef given the fully qualified name and the assembly name
+//*******************************************************************************
+HRESULT ImportHelper::FindCustomAttributeCtorByName(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ LPCUTF8 szAssemblyName, // [IN] Assembly Name.
+ LPCUTF8 szNamespace, // [IN] TypeRef Namespace.
+ LPCUTF8 szName, // [IN] TypeRef Name.
+ mdTypeDef *ptk, // [OUT] Put the TypeRef token here.
+ RID rid /* = 0*/) // [IN] Optional rid to be ignored.
+{
+ HRESULT hr;
+ ULONG cRecs; // Count of records.
+ AssemblyRefRec *pRec; // Current record being looked at.
+ LPCUTF8 szTmp; // Temp string.
+ mdTypeRef tkCAType;
+
+ cRecs = pMiniMd->getCountAssemblyRefs();
+ // Search for the AssemblyRef record.
+ for (ULONG i = 1; i <= cRecs; i++)
+ {
+ IfFailRet(pMiniMd->GetAssemblyRefRecord(i, &pRec));
+
+ IfFailRet(pMiniMd->getNameOfAssemblyRef(pRec, &szTmp));
+ if (!strcmp(szTmp, szAssemblyName) &&
+ (SUCCEEDED(FindTypeRefByName(pMiniMd, TokenFromRid(i, mdtAssemblyRef), szNamespace, szName, &tkCAType, rid))) &&
+ (SUCCEEDED(FindMemberRef(pMiniMd, tkCAType, COR_CTOR_METHOD_NAME, NULL, 0 ,ptk))))
+ {
+ return S_OK;
+ }
+ }
+
+ return CLDB_E_RECORD_NOTFOUND;
+}
+
+//*******************************************************************************
+// Find the TypeRef given the fully qualified name.
+//*******************************************************************************
+HRESULT ImportHelper::FindTypeRefByName(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ mdToken tkResolutionScope, // [IN] Resolution scope for the TypeRef.
+ LPCUTF8 szNamespace, // [IN] TypeRef Namespace.
+ LPCUTF8 szName, // [IN] TypeRef Name.
+ mdTypeRef *ptk, // [OUT] Put the TypeRef token here.
+ RID rid /* = 0*/) // [IN] Optional rid to be ignored.
+{
+ HRESULT hr=S_OK; // A result.
+ ULONG cTypeRefRecs; // Count of TypeRefs to scan.
+ TypeRefRec *pTypeRefRec; // A TypeRef record.
+ LPCUTF8 szNameTmp; // A TypeRef's Name.
+ LPCUTF8 szNamespaceTmp; // A TypeRef's Namespace.
+ mdToken tkResTmp; // TypeRef's resolution scope.
+ ULONG i; // Loop control.
+
+ _ASSERTE(szName && ptk);
+ *ptk = mdTypeRefNil;
+
+ // Treat no namespace as empty string.
+ if (!szNamespace)
+ szNamespace = "";
+
+ if (pMiniMd->m_pNamedItemHash)
+ {
+ // If hash is build, go through the hash table
+ TOKENHASHENTRY *p; // Hash entry from chain.
+ ULONG iHash; // Item's hash value.
+ int pos; // Position in hash chain.
+
+ // Hash the data.
+ iHash = pMiniMd->HashNamedItem(0, szName);
+
+ // Go through every entry in the hash chain looking for ours.
+ for (p = pMiniMd->m_pNamedItemHash->FindFirst(iHash, pos);
+ p;
+ p = pMiniMd->m_pNamedItemHash->FindNext(pos))
+ {
+
+ // name hash can hold more than one kind of token
+ if (TypeFromToken(p->tok) != (ULONG)mdtTypeRef)
+ {
+ continue;
+ }
+
+ // skip this one if asked
+ if (RidFromToken(p->tok) == rid)
+ continue;
+
+ IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(p->tok), &pTypeRefRec));
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szNamespaceTmp));
+ IfFailGo(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szNameTmp));
+ if (strcmp(szName, szNameTmp) || strcmp(szNamespace, szNamespaceTmp))
+ {
+ // if the name space is not equal, then check the next one.
+ continue;
+ }
+ tkResTmp = pMiniMd->getResolutionScopeOfTypeRef(pTypeRefRec);
+
+ if (tkResTmp == tkResolutionScope ||
+ (IsNilToken(tkResTmp) && IsNilToken(tkResolutionScope)))
+ {
+ // we found a match
+ *ptk = p->tok;
+ return S_OK;
+ }
+ }
+ hr = CLDB_E_RECORD_NOTFOUND;
+ }
+ else
+ {
+ cTypeRefRecs = pMiniMd->getCountTypeRefs();
+
+ // Search for the TypeRef.
+ for (i = 1; i <= cTypeRefRecs; i++)
+ {
+ // For the call from Validator ignore the rid passed in.
+ if (i == rid)
+ continue;
+
+ IfFailGo(pMiniMd->GetTypeRefRecord(i, &pTypeRefRec));
+
+ // See if the Resolution scopes match.
+ tkResTmp = pMiniMd->getResolutionScopeOfTypeRef(pTypeRefRec);
+ if (IsNilToken(tkResTmp))
+ {
+ if (!IsNilToken(tkResolutionScope))
+ continue;
+ }
+ else if (tkResTmp != tkResolutionScope)
+ continue;
+
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szNamespaceTmp));
+ if (strcmp(szNamespace, szNamespaceTmp))
+ continue;
+
+ IfFailGo(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szNameTmp));
+ if (! strcmp(szName, szNameTmp))
+ {
+ *ptk = TokenFromRid(i, mdtTypeRef);
+ return S_OK;
+ }
+ }
+ hr = CLDB_E_RECORD_NOTFOUND;
+ }
+ErrExit:
+ return hr;
+} // HRESULT ImportHelper::FindTypeRefByName()
+
+
+//*******************************************************************************
+// Find the ModuleRef given the name, guid and mvid.
+//*******************************************************************************
+HRESULT ImportHelper::FindModuleRef(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ LPCUTF8 szUTF8Name, // [IN] ModuleRef name.
+ mdModuleRef *pmur, // [OUT] Put the ModuleRef token here.
+ RID rid /* = 0*/) // [IN] Optional rid to be ignored.
+{
+ HRESULT hr;
+ ModuleRefRec *pModuleRef;
+ ULONG cModuleRefs;
+ LPCUTF8 szCurName;
+ ULONG i;
+
+ _ASSERTE(pmur);
+ _ASSERTE(szUTF8Name);
+
+ cModuleRefs = pMiniMd->getCountModuleRefs();
+
+ // linear scan through the ModuleRef table
+ for (i=1; i <= cModuleRefs; ++i)
+ {
+ // For the call from Validator ignore the rid passed in.
+ if (i == rid)
+ continue;
+
+ IfFailRet(pMiniMd->GetModuleRefRecord(i, &pModuleRef));
+
+ if (szUTF8Name != NULL)
+ {
+ IfFailRet(pMiniMd->getNameOfModuleRef(pModuleRef, &szCurName));
+ if (strcmp(szCurName, szUTF8Name))
+ continue;
+ }
+ // Matching record found.
+ *pmur = TokenFromRid(i, mdtModuleRef);
+ return S_OK;
+ }
+ return CLDB_E_RECORD_NOTFOUND;
+} // HRESULT ImportHelper::FindModuleRef()
+
+
+
+//*******************************************************************************
+// Find the TypeDef given the type and namespace name
+//*******************************************************************************
+HRESULT
+ImportHelper::FindTypeDefByName(
+ CMiniMdRW * pMiniMd, // [IN] the minimd to lookup
+ LPCUTF8 szTypeDefNamespace, // [IN] Full qualified TypeRef name.
+ LPCUTF8 szTypeDefName, // [IN] Full qualified TypeRef name.
+ mdToken tkEnclosingClass, // [IN] TypeDef/TypeRef/Module for Enclosing class.
+ mdTypeDef * ptkTypeDef, // [OUT] Put the TypeRef token here.
+ RID ridIgnore) // =0 // [IN] Optional rid to be ignored.
+{
+ ULONG cTypeDefRecs;
+ TypeDefRec * pTypeDefRec;
+ LPCUTF8 szName;
+ LPCUTF8 szNamespace;
+ DWORD dwFlags;
+ HRESULT hr = S_OK;
+
+ _ASSERTE((szTypeDefName != NULL) && (ptkTypeDef != NULL));
+ _ASSERTE((TypeFromToken(tkEnclosingClass) == mdtTypeDef) ||
+ (TypeFromToken(tkEnclosingClass) == mdtTypeRef) ||
+ (tkEnclosingClass == TokenFromRid(1, mdtModule)) ||
+ IsNilToken(tkEnclosingClass));
+
+ *ptkTypeDef = mdTypeDefNil;
+
+ cTypeDefRecs = pMiniMd->getCountTypeDefs();
+
+ // Treat no namespace as empty string.
+ if (szTypeDefNamespace == NULL)
+ szTypeDefNamespace = "";
+
+ if (tkEnclosingClass == TokenFromRid(1, mdtModule))
+ { // Module scope is the same as no scope (used in .winmd files as TypeRef scope for self-references)
+ tkEnclosingClass = mdTokenNil;
+ }
+
+ // Get TypeDef of the tkEnclosingClass passed in
+ if (TypeFromToken(tkEnclosingClass) == mdtTypeRef)
+ {
+ // Resolve the TypeRef to a TypeDef
+ TypeRefRec * pTypeRefRec;
+ mdToken tkResolutionScope;
+ LPCUTF8 szTypeRefName;
+ LPCUTF8 szTypeRefNamespace;
+
+ IfFailRet(pMiniMd->GetTypeRefRecord(RidFromToken(tkEnclosingClass), &pTypeRefRec));
+ tkResolutionScope = pMiniMd->getResolutionScopeOfTypeRef(pTypeRefRec);
+ IfFailRet(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szTypeRefName));
+ IfFailRet(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szTypeRefNamespace));
+
+ if (tkEnclosingClass == tkResolutionScope && !strcmp(szTypeDefName, szTypeRefName) &&
+ ((szTypeDefNamespace == nullptr && szTypeRefNamespace == nullptr) ||
+ (szTypeDefNamespace != nullptr && szTypeRefNamespace != nullptr && !strcmp(szTypeDefNamespace, szTypeRefNamespace))))
+ {
+ //
+ // This defensive workaround works around a feature of DotFuscator that adds a bad type-ref
+ // which causes tools like ILDASM to crash. The type-ref's parent is set to itself
+ // which causes this function to recurse infinitely. A side-effect is that during Ngen we
+ // parse all the type-refs in an assembly and Ngen also hangs infinitely.
+ // This workaround is necessary because several popular gaming libraries experience hangs
+ // and we need binary compatibility in Apollo.
+ //
+ return CLDB_E_FILE_CORRUPT;
+ }
+
+ // Update tkEnclosingClass to TypeDef
+ IfFailRet(FindTypeDefByName(
+ pMiniMd,
+ szTypeRefNamespace,
+ szTypeRefName,
+ (TypeFromToken(tkResolutionScope) == mdtTypeRef) ? tkResolutionScope : mdTokenNil,
+ &tkEnclosingClass));
+ _ASSERTE(TypeFromToken(tkEnclosingClass) == mdtTypeDef);
+ }
+
+ // Search for the TypeDef
+ for (ULONG i = 1; i <= cTypeDefRecs; i++)
+ {
+ // For the call from Validator ignore the rid passed in.
+ if (i == ridIgnore)
+ continue;
+
+ IfFailRet(pMiniMd->GetTypeDefRecord(i, &pTypeDefRec));
+
+ dwFlags = pMiniMd->getFlagsOfTypeDef(pTypeDefRec);
+
+ if (!IsTdNested(dwFlags) && !IsNilToken(tkEnclosingClass))
+ {
+ // If the class is not Nested and EnclosingClass passed in is not nil
+ continue;
+ }
+ else if (IsTdNested(dwFlags) && IsNilToken(tkEnclosingClass))
+ {
+ // If the class is nested and EnclosingClass passed is nil
+ continue;
+ }
+ else if (!IsNilToken(tkEnclosingClass))
+ {
+ _ASSERTE(TypeFromToken(tkEnclosingClass) == mdtTypeDef);
+
+ RID iNestedClassRec;
+ NestedClassRec * pNestedClassRec;
+ mdTypeDef tkEnclosingClassTmp;
+
+ IfFailRet(pMiniMd->FindNestedClassHelper(TokenFromRid(i, mdtTypeDef), &iNestedClassRec));
+ if (InvalidRid(iNestedClassRec))
+ continue;
+ IfFailRet(pMiniMd->GetNestedClassRecord(iNestedClassRec, &pNestedClassRec));
+ tkEnclosingClassTmp = pMiniMd->getEnclosingClassOfNestedClass(pNestedClassRec);
+ if (tkEnclosingClass != tkEnclosingClassTmp)
+ continue;
+ }
+
+ IfFailRet(pMiniMd->getNameOfTypeDef(pTypeDefRec, &szName));
+ if (strcmp(szTypeDefName, szName) == 0)
+ {
+ IfFailRet(pMiniMd->getNamespaceOfTypeDef(pTypeDefRec, &szNamespace));
+ if (strcmp(szTypeDefNamespace, szNamespace) == 0)
+ {
+ *ptkTypeDef = TokenFromRid(i, mdtTypeDef);
+ return S_OK;
+ }
+ }
+ }
+ return CLDB_E_RECORD_NOTFOUND;
+} // ImportHelper::FindTypeDefByName
+
+//*******************************************************************************
+// Find the InterfaceImpl given the typedef and implemented interface
+//*******************************************************************************
+HRESULT ImportHelper::FindInterfaceImpl(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ mdToken tkClass, // [IN] TypeDef of the type
+ mdToken tkInterface, // [IN] could be typedef/typeref
+ mdInterfaceImpl *ptk, // [OUT] Put the interface token here.
+ RID rid /* = 0*/) // [IN] Optional rid to be ignored.
+{
+ HRESULT hr;
+ ULONG ridStart, ridEnd;
+ ULONG i;
+ InterfaceImplRec *pInterfaceImplRec;
+
+ _ASSERTE(ptk);
+ *ptk = mdInterfaceImplNil;
+ if ( pMiniMd->IsSorted(TBL_InterfaceImpl) )
+ {
+ IfFailRet(pMiniMd->getInterfaceImplsForTypeDef(RidFromToken(tkClass), &ridEnd, &ridStart));
+ }
+ else
+ {
+ ridStart = 1;
+ ridEnd = pMiniMd->getCountInterfaceImpls() + 1;
+ }
+
+ // Search for the interfaceimpl
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ // For the call from Validator ignore the rid passed in.
+ if (i == rid)
+ continue;
+
+ IfFailRet(pMiniMd->GetInterfaceImplRecord(i, &pInterfaceImplRec));
+ if ( tkClass != pMiniMd->getClassOfInterfaceImpl(pInterfaceImplRec) )
+ continue;
+ if ( tkInterface == pMiniMd->getInterfaceOfInterfaceImpl(pInterfaceImplRec) )
+ {
+ *ptk = TokenFromRid(i, mdtInterfaceImpl);
+ return S_OK;
+ }
+ }
+ return CLDB_E_RECORD_NOTFOUND;
+} // HRESULT ImportHelper::FindInterfaceImpl()
+
+
+
+//*******************************************************************************
+// Find the Permission by parent and action
+//*******************************************************************************
+HRESULT ImportHelper::FindPermission(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ mdToken tkParent, // [IN] Token with the Permission
+ USHORT usAction, // [IN] The action of the permission
+ mdPermission *ppm) // [OUT] Put permission token here
+{
+ HRESULT hr;
+ DeclSecurityRec *pRec;
+ ULONG ridStart, ridEnd;
+ ULONG i;
+ mdToken tkParentTmp;
+
+ _ASSERTE(ppm);
+
+ if ( pMiniMd->IsSorted(TBL_DeclSecurity) )
+ {
+
+ IfFailRet(pMiniMd->getDeclSecurityForToken(tkParent, &ridEnd, &ridStart));
+ }
+ else
+ {
+ ridStart = 1;
+ ridEnd = pMiniMd->getCountDeclSecuritys() + 1;
+ }
+ // loop through all permission
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ IfFailRet(pMiniMd->GetDeclSecurityRecord(i, &pRec));
+ tkParentTmp = pMiniMd->getParentOfDeclSecurity(pRec);
+ if ( tkParentTmp != tkParent )
+ continue;
+ if (pRec->GetAction() == usAction)
+ {
+ *ppm = TokenFromRid(i, mdtPermission);
+ return S_OK;
+ }
+ }
+ return CLDB_E_RECORD_NOTFOUND;
+} // HRESULT ImportHelper::FindPermission()
+
+
+//*****************************************************************************
+// find a property record
+//*****************************************************************************
+HRESULT ImportHelper::FindProperty(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ mdToken tkTypeDef, // [IN] typedef token
+ LPCUTF8 szName, // [IN] name of the property
+ const COR_SIGNATURE *pbSig, // [IN] Signature.
+ ULONG cbSig, // [IN] Size of signature.
+ mdProperty *ppr) // [OUT] Property token
+{
+ HRESULT hr;
+ RID ridPropertyMap;
+ PropertyMapRec *pPropertyMapRec;
+ PropertyRec *pRec;
+ ULONG ridStart;
+ ULONG ridEnd;
+ ULONG i;
+ LPCUTF8 szNameTmp;
+ PCCOR_SIGNATURE pbSigTmp;
+ ULONG cbSigTmp;
+ ULONG pr;
+
+ IfFailRet(pMiniMd->FindPropertyMapFor(RidFromToken(tkTypeDef), &ridPropertyMap));
+ if ( !InvalidRid(ridPropertyMap) )
+ {
+ IfFailRet(pMiniMd->GetPropertyMapRecord(ridPropertyMap, &pPropertyMapRec));
+ ridStart = pMiniMd->getPropertyListOfPropertyMap(pPropertyMapRec);
+ IfFailRet(pMiniMd->getEndPropertyListOfPropertyMap(ridPropertyMap, &ridEnd));
+
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ // get the property rid
+ IfFailRet(pMiniMd->GetPropertyRid(i, &pr));
+ IfFailRet(pMiniMd->GetPropertyRecord(pr, &pRec));
+ IfFailRet(pMiniMd->getNameOfProperty(pRec, &szNameTmp));
+ IfFailRet(pMiniMd->getTypeOfProperty(pRec, &pbSigTmp, &cbSigTmp));
+ if ( strcmp (szName, szNameTmp) != 0 )
+ continue;
+ if ( cbSig != 0 && (cbSigTmp != cbSig || memcmp(pbSig, pbSigTmp, cbSig) != 0 ) )
+ continue;
+ *ppr = TokenFromRid( i, mdtProperty );
+ return S_OK;
+ }
+ return CLDB_E_RECORD_NOTFOUND;
+ }
+ else
+ {
+ return CLDB_E_RECORD_NOTFOUND;
+ }
+} // HRESULT ImportHelper::FindProperty()
+
+
+
+
+//*****************************************************************************
+// find an Event record
+//*****************************************************************************
+HRESULT ImportHelper::FindEvent(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ mdToken tkTypeDef, // [IN] typedef token
+ LPCUTF8 szName, // [IN] name of the event
+ mdProperty *pev) // [OUT] Event token
+{
+ HRESULT hr;
+ RID ridEventMap;
+ EventMapRec *pEventMapRec;
+ EventRec *pRec;
+ ULONG ridStart;
+ ULONG ridEnd;
+ ULONG i;
+ LPCUTF8 szNameTmp;
+ ULONG ev;
+
+ IfFailRet(pMiniMd->FindEventMapFor(RidFromToken(tkTypeDef), &ridEventMap));
+ if ( !InvalidRid(ridEventMap) )
+ {
+ IfFailRet(pMiniMd->GetEventMapRecord(ridEventMap, &pEventMapRec));
+ ridStart = pMiniMd->getEventListOfEventMap(pEventMapRec);
+ IfFailRet(pMiniMd->getEndEventListOfEventMap(ridEventMap, &ridEnd));
+
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ // get the Event rid
+ IfFailRet(pMiniMd->GetEventRid(i, &ev));
+
+ // get the event row
+ IfFailRet(pMiniMd->GetEventRecord(ev, &pRec));
+ IfFailRet(pMiniMd->getNameOfEvent(pRec, &szNameTmp));
+ if ( strcmp (szName, szNameTmp) == 0)
+ {
+ *pev = TokenFromRid( ev, mdtEvent );
+ return S_OK;
+ }
+ }
+ return CLDB_E_RECORD_NOTFOUND;
+ }
+ else
+ {
+ return CLDB_E_RECORD_NOTFOUND;
+ }
+} // HRESULT ImportHelper::FindEvent()
+
+
+
+//*****************************************************************************
+// find an custom value record given by parent and type token. This will always return
+// the first one that is found regardless duplicated.
+//*****************************************************************************
+HRESULT ImportHelper::FindCustomAttributeByToken(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ mdToken tkParent, // [IN] the parent that custom value is associated with
+ mdToken tkType, // [IN] type of the CustomAttribute
+ const void *pCustBlob, // [IN] custom attribute blob
+ ULONG cbCustBlob, // [IN] size of the blob.
+ mdCustomAttribute *pcv) // [OUT] CustomAttribute token
+{
+ HRESULT hr;
+ CustomAttributeRec *pRec;
+ ULONG ridStart, ridEnd;
+ ULONG i;
+ mdToken tkParentTmp;
+ mdToken tkTypeTmp;
+ const void *pCustBlobTmp;
+ ULONG cbCustBlobTmp;
+
+ _ASSERTE(pcv);
+ *pcv = mdCustomAttributeNil;
+ if ( pMiniMd->IsSorted(TBL_CustomAttribute) )
+ {
+ IfFailRet(pMiniMd->FindCustomAttributeFor(
+ RidFromToken(tkParent),
+ TypeFromToken(tkParent),
+ tkType,
+ (RID *)pcv));
+ if (InvalidRid(*pcv))
+ {
+ return S_FALSE;
+ }
+ else if (pCustBlob)
+ {
+ IfFailRet(pMiniMd->GetCustomAttributeRecord(RidFromToken(*pcv), &pRec));
+ IfFailRet(pMiniMd->getValueOfCustomAttribute(pRec, (const BYTE **)&pCustBlobTmp, &cbCustBlobTmp));
+ if (cbCustBlob == cbCustBlobTmp &&
+ !memcmp(pCustBlob, pCustBlobTmp, cbCustBlob))
+ {
+ return S_OK;
+ }
+ }
+ else
+ {
+ return S_OK;
+ }
+ }
+ else
+ {
+ CLookUpHash *pHashTable = pMiniMd->m_pLookUpHashs[TBL_CustomAttribute];
+
+ if (pHashTable)
+ {
+ // table is not sorted but hash is built
+ // We want to create dynmaic array to hold the dynamic enumerator.
+ TOKENHASHENTRY *p;
+ ULONG iHash;
+ int pos;
+
+ // Hash the data.
+ iHash = pMiniMd->HashCustomAttribute(tkParent);
+
+ // Go through every entry in the hash chain looking for ours.
+ for (p = pHashTable->FindFirst(iHash, pos);
+ p;
+ p = pHashTable->FindNext(pos))
+ {
+ IfFailRet(pMiniMd->GetCustomAttributeRecord(RidFromToken(p->tok), &pRec));
+
+ tkParentTmp = pMiniMd->getParentOfCustomAttribute(pRec);
+ if (tkParentTmp != tkParent)
+ continue;
+
+ tkTypeTmp = pMiniMd->getTypeOfCustomAttribute(pRec);
+ if (tkType != tkTypeTmp)
+ continue;
+ if (pCustBlob != NULL)
+ {
+ IfFailRet(pMiniMd->getValueOfCustomAttribute(pRec, (const BYTE **)&pCustBlobTmp, &cbCustBlobTmp));
+ if (cbCustBlob == cbCustBlobTmp &&
+ !memcmp(pCustBlob, pCustBlobTmp, cbCustBlob))
+ {
+ *pcv = TokenFromRid(p->tok, mdtCustomAttribute);
+ return S_OK;
+ }
+ }
+ else
+ return S_OK;
+ }
+ }
+ else
+ {
+ // linear scan
+ ridStart = 1;
+ ridEnd = pMiniMd->getCountCustomAttributes() + 1;
+
+ // loop through all custom values
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ IfFailRet(pMiniMd->GetCustomAttributeRecord(i, &pRec));
+
+ tkParentTmp = pMiniMd->getParentOfCustomAttribute(pRec);
+ if ( tkParentTmp != tkParent )
+ continue;
+
+ tkTypeTmp = pMiniMd->getTypeOfCustomAttribute(pRec);
+ if (tkType != tkTypeTmp)
+ continue;
+
+ if (pCustBlob != NULL)
+ {
+ IfFailRet(pMiniMd->getValueOfCustomAttribute(pRec, (const BYTE **)&pCustBlobTmp, &cbCustBlobTmp));
+ if (cbCustBlob == cbCustBlobTmp &&
+ !memcmp(pCustBlob, pCustBlobTmp, cbCustBlob))
+ {
+ *pcv = TokenFromRid(i, mdtCustomAttribute);
+ return S_OK;
+ }
+ }
+ else
+ return S_OK;
+ }
+ }
+ // fall through
+ }
+ return S_FALSE;
+} // ImportHelper::FindCustomAttributeByToken
+
+//*****************************************************************************
+// Helper function to lookup and retrieve a CustomAttribute.
+//*****************************************************************************
+HRESULT ImportHelper::GetCustomAttributeByName( // S_OK or error.
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ 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 pMiniMd->CommonGetCustomAttributeByName(tkObj, szName, ppData, pcbData);
+} // ImportHelper::GetCustomAttributeByName
+
+#ifdef FEATURE_METADATA_EMIT
+
+//*******************************************************************************
+// Find an AssemblyRef record given the name.
+//*******************************************************************************
+HRESULT ImportHelper::FindAssemblyRef(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup.
+ LPCUTF8 szName, // [IN] Name.
+ LPCUTF8 szLocale, // [IN] Locale.
+ const void *pbPublicKeyOrToken, // [IN] Public key or token (based on flags).
+ ULONG cbPublicKeyOrToken, // [IN] Byte count of public key or token.
+ USHORT usMajorVersion, // [IN] Major version.
+ USHORT usMinorVersion, // [IN] Minor version.
+ USHORT usBuildNumber, // [IN] Build number.
+ USHORT usRevisionNumber, // [IN] Revision number.
+ DWORD dwFlags, // [IN] Flags.
+ mdAssemblyRef *pmar) // [OUT] returned AssemblyRef token.
+{
+ HRESULT hr;
+ ULONG cRecs; // Count of records.
+ AssemblyRefRec *pRec; // Current record being looked at.
+ LPCUTF8 szTmp; // Temp string.
+ const void *pbTmp; // Temp blob.
+ ULONG cbTmp; // Temp byte count.
+ DWORD dwTmp; // Temp flags.
+ const void *pbToken = NULL; // Token version of public key.
+ ULONG cbToken = 0; // Count of bytes in token.
+#if !defined(FEATURE_METADATA_EMIT_IN_DEBUGGER) || defined(DACCESS_COMPILE)
+ const void *pbTmpToken; // Token version of public key.
+ ULONG cbTmpToken; // Count of bytes in token.
+ bool fMatch; // Did public key or tokens match?
+#endif // !FEATURE_METADATA_EMIT_IN_DEBUGGER || DACCESS_COMPILE
+
+ // Handle special cases upfront.
+ if (!szLocale)
+ szLocale = "";
+ if (!pbPublicKeyOrToken)
+ cbPublicKeyOrToken = 0;
+
+ if (!IsAfPublicKey(dwFlags))
+ {
+ pbToken = pbPublicKeyOrToken;
+ cbToken = cbPublicKeyOrToken;
+ }
+
+ _ASSERTE(pMiniMd && szName && pmar);
+ *pmar = 0;
+
+ cRecs = pMiniMd->getCountAssemblyRefs();
+
+ // Search for the AssemblyRef record.
+ for (ULONG i = 1; i <= cRecs; i++)
+ {
+ IfFailRet(pMiniMd->GetAssemblyRefRecord(i, &pRec));
+
+ IfFailRet(pMiniMd->getNameOfAssemblyRef(pRec, &szTmp));
+ if (strcmp(szTmp, szName))
+ continue;
+
+ IfFailRet(pMiniMd->getLocaleOfAssemblyRef(pRec, &szTmp));
+ if (strcmp(szTmp, szLocale))
+ continue;
+
+ if (pRec->GetMajorVersion() != usMajorVersion)
+ continue;
+ if (pRec->GetMinorVersion() != usMinorVersion)
+ continue;
+
+ // We'll "unify" all versions of mscorlib and Microsoft.VisualC... so if this
+ // is one of those, we won't do the version check beyond the major/minor
+
+ LPCUTF8 szAssemblyRefName;
+ IfFailRet(pMiniMd->getNameOfAssemblyRef(pRec, &szAssemblyRefName));
+ if (SString::_stricmp(szAssemblyRefName, "mscorlib") &&
+ SString::_stricmp(szAssemblyRefName, "microsoft.visualc"))
+ {
+ if (pRec->GetBuildNumber() != usBuildNumber)
+ continue;
+ if (pRec->GetRevisionNumber() != usRevisionNumber)
+ continue;
+ }
+
+ IfFailRet(pMiniMd->getPublicKeyOrTokenOfAssemblyRef(pRec, (const BYTE **)&pbTmp, &cbTmp));
+
+ if ((cbPublicKeyOrToken && !cbTmp) ||
+ (!cbPublicKeyOrToken && cbTmp))
+ continue;
+
+ if (cbTmp)
+ {
+ // Either ref may be using either a full public key or a token
+ // (determined by the ref flags). Must cope with all variations.
+ dwTmp = pMiniMd->getFlagsOfAssemblyRef(pRec);
+ if (IsAfPublicKey(dwTmp) == IsAfPublicKey(dwFlags))
+ {
+ // Easy case, they're both in the same form.
+ if (cbTmp != cbPublicKeyOrToken || memcmp(pbTmp, pbPublicKeyOrToken, cbTmp))
+ continue;
+ }
+ else if (IsAfPublicKey(dwTmp))
+ {
+#if defined(FEATURE_METADATA_EMIT_IN_DEBUGGER) && !defined(DACCESS_COMPILE)
+ return E_FAIL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER || DACCESS_COMPILE
+ // Need to compress target public key to see if it matches.
+ if (!StrongNameTokenFromPublicKey((BYTE*)pbTmp,
+ cbTmp,
+ (BYTE**)&pbTmpToken,
+ &cbTmpToken))
+ {
+ return StrongNameErrorInfo();
+ }
+ fMatch = cbTmpToken == cbPublicKeyOrToken && !memcmp(pbTmpToken, pbPublicKeyOrToken, cbTmpToken);
+ StrongNameFreeBuffer((BYTE*)pbTmpToken);
+ if (!fMatch)
+ continue;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER || DACCESS_COMPILE
+ }
+ else
+ {
+ // Need to compress out public key to see if it matches. We
+ // cache the result of this for further iterations.
+ if (!pbToken)
+ {
+#if defined(FEATURE_METADATA_EMIT_IN_DEBUGGER) && !defined(DACCESS_COMPILE)
+ return E_FAIL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER || DACCESS_COMPILE
+ if (!StrongNameTokenFromPublicKey((BYTE*)pbPublicKeyOrToken,
+ cbPublicKeyOrToken,
+ (BYTE**)&pbToken,
+ &cbToken))
+ {
+ return StrongNameErrorInfo();
+ }
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER || DACCESS_COMPILE
+ }
+ if (cbTmp != cbToken || memcmp(pbTmp, pbToken, cbToken))
+ continue;
+ }
+ }
+
+ if (pbToken && IsAfPublicKey(dwFlags))
+ {
+#if !defined(FEATURE_METADATA_EMIT_IN_DEBUGGER) || defined(DACCESS_COMPILE)
+ StrongNameFreeBuffer((BYTE*)pbToken);
+#endif
+ }
+ *pmar = TokenFromRid(i, mdtAssemblyRef);
+ return S_OK;
+ }
+ if (pbToken && IsAfPublicKey(dwFlags))
+ {
+#if !defined(FEATURE_METADATA_EMIT_IN_DEBUGGER) || defined(DACCESS_COMPILE)
+ StrongNameFreeBuffer((BYTE*)pbToken);
+#endif
+ }
+ return CLDB_E_RECORD_NOTFOUND;
+} // ImportHelper::FindAssemblyRef
+
+//*******************************************************************************
+// Find a File record given the name.
+//*******************************************************************************
+HRESULT ImportHelper::FindFile(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup.
+ LPCUTF8 szName, // [IN] name for the File.
+ mdFile *pmf, // [OUT] returned File token.
+ RID rid /* = 0 */) // [IN] Optional rid to be ignored.
+{
+ HRESULT hr;
+ ULONG cRecs; // Count of records.
+ FileRec *pRec; // Current record being looked at.
+
+ LPCUTF8 szNameTmp;
+
+ _ASSERTE(pMiniMd && szName && pmf);
+ *pmf = 0;
+
+ cRecs = pMiniMd->getCountFiles();
+
+ // Search for the File record.
+ for (ULONG i = 1; i <= cRecs; i++)
+ {
+ // For the call from Validator ignore the rid passed in.
+ if (i == rid)
+ continue;
+
+ IfFailRet(pMiniMd->GetFileRecord(i, &pRec));
+
+ IfFailRet(pMiniMd->getNameOfFile(pRec, &szNameTmp));
+ if (!strcmp(szNameTmp, szName))
+ {
+ *pmf = TokenFromRid(i, mdtFile);
+ return S_OK;
+ }
+ }
+ return CLDB_E_RECORD_NOTFOUND;
+} // ImportHelper::FindFile
+
+#endif //FEATURE_METADATA_EMIT
+
+//*******************************************************************************
+// Find a ExportedType record given the name.
+//*******************************************************************************
+HRESULT ImportHelper::FindExportedType(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup.
+ LPCUTF8 szNamespace, // [IN] namespace for the ExportedType.
+ LPCUTF8 szName, // [IN] name for the ExportedType.
+ mdExportedType tkEnclosingType, // [IN] token for the enclosing type.
+ mdExportedType *pmct, // [OUT] returned ExportedType token.
+ RID rid /* = 0 */) // [IN] Optional rid to be ignored.
+{
+ HRESULT hr;
+ ULONG cRecs; // Count of records.
+ ExportedTypeRec *pRec; // Current record being looked at.
+ mdToken tkImpl;
+ LPCUTF8 szNamespaceTmp;
+ LPCUTF8 szNameTmp;
+
+ _ASSERTE(pMiniMd && szName && pmct);
+ *pmct = 0;
+
+ // Treat no namespace as empty string.
+ if (!szNamespace)
+ szNamespace = "";
+
+ cRecs = pMiniMd->getCountExportedTypes();
+
+ // Search for the ExportedType record.
+ for (ULONG i = 1; i <= cRecs; i++)
+ {
+ // For the call from Validator ignore the rid passed in.
+ if (i == rid)
+ continue;
+
+ IfFailRet(pMiniMd->GetExportedTypeRecord(i, &pRec));
+
+ // Handle the case of nested vs. non-nested classes.
+ tkImpl = pMiniMd->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;
+ }
+
+ IfFailRet(pMiniMd->getTypeNamespaceOfExportedType(pRec, &szNamespaceTmp));
+ if (strcmp(szNamespaceTmp, szNamespace))
+ continue;
+
+ IfFailRet(pMiniMd->getTypeNameOfExportedType(pRec, &szNameTmp));
+ if (!strcmp(szNameTmp, szName))
+ {
+ *pmct = TokenFromRid(i, mdtExportedType);
+ return S_OK;
+ }
+ }
+ return CLDB_E_RECORD_NOTFOUND;
+} // HRESULT ImportHelper::FindExportedType()
+
+//*******************************************************************************
+// Find a ManifestResource record given the name.
+//*******************************************************************************
+HRESULT ImportHelper::FindManifestResource(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup.
+ LPCUTF8 szName, // [IN] name for the ManifestResource.
+ mdManifestResource *pmmr, // [OUT] returned ManifestResource token.
+ RID rid /* = 0 */) // [IN] Optional rid to be ignored.
+{
+ HRESULT hr;
+ ULONG cRecs; // Count of records.
+ ManifestResourceRec *pRec; // Current record being looked at.
+
+ LPCUTF8 szNameTmp;
+
+ _ASSERTE(pMiniMd && szName && pmmr);
+ *pmmr = 0;
+
+ cRecs = pMiniMd->getCountManifestResources();
+
+ // Search for the ManifestResource record.
+ for (ULONG i = 1; i <= cRecs; i++)
+ {
+ // For the call from Validator ignore the rid passed in.
+ if (i == rid)
+ continue;
+
+ IfFailRet(pMiniMd->GetManifestResourceRecord(i, &pRec));
+
+ IfFailRet(pMiniMd->getNameOfManifestResource(pRec, &szNameTmp));
+ if (!strcmp(szNameTmp, szName))
+ {
+ *pmmr = TokenFromRid(i, mdtManifestResource);
+ return S_OK;
+ }
+ }
+ return CLDB_E_RECORD_NOTFOUND;
+} // HRESULT ImportHelper::FindManifestResource()
+
+#ifdef FEATURE_METADATA_EMIT
+
+//****************************************************************************
+// Convert tokens contained in an element type
+//****************************************************************************
+HRESULT
+ImportHelper::MergeUpdateTokenInFieldSig(
+ CMiniMdRW *pMiniMdAssemEmit, // [IN] The assembly emit scope.
+ CMiniMdRW *pMiniMdEmit, // [IN] The emit scope.
+ IMetaModelCommon *pCommonAssemImport,// [IN] Assembly scope where the signature is from.
+ const void *pbHashValue, // [IN] Hash value for the import assembly.
+ ULONG cbHashValue, // [IN] Size in bytes for the hash value.
+ IMetaModelCommon *pCommonImport, // [IN] The scope to merge into the emit scope.
+ PCCOR_SIGNATURE pbSigImp, // signature from the imported scope
+ MDTOKENMAP *ptkMap, // Internal OID mapping structure.
+ CQuickBytes *pqkSigEmit, // [OUT] buffer for translated signature
+ ULONG cbStartEmit, // [IN] start point of buffer to write to
+ ULONG *pcbImp, // [OUT] total number of bytes consumed from pbSigImp
+ ULONG *pcbEmit) // [OUT] total number of bytes write to pqkSigEmit
+{
+
+ HRESULT hr; // A result.
+ ULONG cb; // count of bytes
+ ULONG cb1; // count of bytes
+ ULONG cb2; // count of bytes
+ ULONG cbSubTotal;
+ ULONG cbImp;
+ ULONG cbEmit;
+ ULONG cbSrcTotal = 0; // count of bytes consumed in the imported signature
+ ULONG cbDestTotal = 0; // count of bytes for the new signature
+ ULONG ulElementType = 0; // place holder for expanded data
+ ULONG ulData;
+ ULONG ulTemp;
+ mdToken tkRidFrom; // Original rid
+ mdToken tkRidTo; // new rid
+ int iData;
+ CQuickArray<mdToken> cqaNesters; // Array of Nester tokens.
+ CQuickArray<LPCUTF8> cqaNesterNamespaces; // Array of Nester Namespaces.
+ CQuickArray<LPCUTF8> cqaNesterNames; // Array of Nester names.
+
+ _ASSERTE(pcbEmit);
+
+ cb = CorSigUncompressData(&pbSigImp[cbSrcTotal], &ulElementType);
+ cbSrcTotal += cb;
+
+ // count numbers of modifiers
+ while (CorIsModifierElementType((CorElementType) ulElementType))
+ {
+ cb = CorSigUncompressData(&pbSigImp[cbSrcTotal], &ulElementType);
+ cbSrcTotal += cb;
+ }
+
+ // copy ELEMENT_TYPE_* over
+ cbDestTotal = cbSrcTotal;
+ IfFailGo(pqkSigEmit->ReSizeNoThrow(cbStartEmit + cbDestTotal));
+ memcpy(((BYTE *)pqkSigEmit->Ptr()) + cbStartEmit, pbSigImp, cbDestTotal);
+ switch (ulElementType)
+ {
+ case ELEMENT_TYPE_SZARRAY:
+ // syntax : SZARRAY <BaseType>
+
+ // conver the base type for the SZARRAY or GENERICARRAY
+ IfFailGo(MergeUpdateTokenInFieldSig(
+ pMiniMdAssemEmit, // The assembly emit scope.
+ pMiniMdEmit, // The emit scope.
+ pCommonAssemImport, // The assembly scope where the signature is from.
+ pbHashValue, // Hash value for the import assembly.
+ cbHashValue, // Size in bytes for the hash value.
+ pCommonImport, // scope to merge into the emit scope.
+ &pbSigImp[cbSrcTotal], // from the imported scope
+ ptkMap, // OID mapping structure.
+ pqkSigEmit, // [OUT] buffer for translated signature
+ cbStartEmit + cbDestTotal, // [IN] start point of buffer to write to
+ &cbImp, // [OUT] total number of bytes consumed from pbSigImp
+ &cbEmit)); // [OUT] total number of bytes write to pqkSigEmit
+ cbSrcTotal += cbImp;
+ cbDestTotal += cbEmit;
+ break;
+
+ case ELEMENT_TYPE_GENERICINST:
+ {
+ // syntax : WITH (ELEMENT_TYPE_CLASS | ELEMENT_TYPE_VALUECLASS) <BaseType>
+
+ IfFailGo(MergeUpdateTokenInFieldSig(
+ pMiniMdAssemEmit, // The assembly emit scope.
+ pMiniMdEmit, // The emit scope.
+ pCommonAssemImport, // The assembly scope where the signature is from.
+ pbHashValue, // Hash value for the import assembly.
+ cbHashValue, // Size in bytes for the hash value.
+ pCommonImport, // scope to merge into the emit scope.
+ &pbSigImp[cbSrcTotal], // from the imported scope
+ ptkMap, // OID mapping structure.
+ pqkSigEmit, // [OUT] buffer for translated signature
+ cbStartEmit + cbDestTotal, // [IN] start point of buffer to write to
+ &cbImp, // [OUT] total number of bytes consumed from pbSigImp
+ &cbEmit)); // [OUT] total number of bytes write to pqkSigEmit
+ cbSrcTotal += cbImp;
+ cbDestTotal += cbEmit;
+
+ // copy over the number of arguments
+ ULONG nargs;
+ cb = CorSigUncompressData(&pbSigImp[cbSrcTotal], &nargs);
+
+ IfFailGo(pqkSigEmit->ReSizeNoThrow(cbStartEmit + cbDestTotal + cb));
+ cb1 = CorSigCompressData(nargs, ((BYTE *)pqkSigEmit->Ptr()) + cbStartEmit + cbDestTotal);
+ _ASSERTE(cb == cb1);
+
+ cbSrcTotal += cb;
+ cbDestTotal += cb1;
+
+ for (ULONG narg = 0; narg < nargs; narg++) {
+ IfFailGo(MergeUpdateTokenInFieldSig(
+ pMiniMdAssemEmit, // The assembly emit scope.
+ pMiniMdEmit, // The emit scope.
+ pCommonAssemImport, // The assembly scope where the signature is from.
+ pbHashValue, // Hash value for the import assembly.
+ cbHashValue, // Size in bytes for the hash value.
+ pCommonImport, // The scope to merge into the emit scope.
+ &pbSigImp[cbSrcTotal], // signature from the imported scope
+ ptkMap, // Internal OID mapping structure.
+ pqkSigEmit, // [OUT] buffer for translated signature
+ cbStartEmit + cbDestTotal, // [IN] start point of buffer to write to
+ &cbImp, // [OUT] total number of bytes consumed from pbSigImp
+ &cbEmit)); // [OUT] total number of bytes write to pqkSigEmit
+ cbSrcTotal += cbImp;
+ cbDestTotal += cbEmit;
+ }
+ }
+
+ break;
+
+ case ELEMENT_TYPE_MVAR:
+ case ELEMENT_TYPE_VAR:
+ // syntax : VAR <n>
+ // syntax : MVAR <n>
+
+ // after the VAR or MVAR there is an integer indicating which type variable
+ //
+ cb = CorSigUncompressData(&pbSigImp[cbSrcTotal], &ulData);
+
+ IfFailGo(pqkSigEmit->ReSizeNoThrow(cbStartEmit + cbDestTotal + cb));
+ cb1 = CorSigCompressData(ulData, ((BYTE *)pqkSigEmit->Ptr()) + cbStartEmit + cbDestTotal);
+ _ASSERTE(cb == cb1);
+
+ cbSrcTotal += cb;
+ cbDestTotal += cb1;
+
+ break;
+
+ case ELEMENT_TYPE_ARRAY:
+ // syntax : ARRAY BaseType <rank> [i size_1... size_i] [j lowerbound_1 ... lowerbound_j]
+
+ // conver the base type for the MDARRAY
+ IfFailGo(MergeUpdateTokenInFieldSig(
+ pMiniMdAssemEmit, // The assembly emit scope.
+ pMiniMdEmit, // The emit scope.
+ pCommonAssemImport, // The assembly scope where the signature is from.
+ pbHashValue, // Hash value for the import assembly.
+ cbHashValue, // Size in bytes for the hash value.
+ pCommonImport, // The scope to merge into the emit scope.
+ &pbSigImp[cbSrcTotal], // signature from the imported scope
+ ptkMap, // Internal OID mapping structure.
+ pqkSigEmit, // [OUT] buffer for translated signature
+ cbStartEmit + cbSrcTotal, // [IN] start point of buffer to write to
+ &cbImp, // [OUT] total number of bytes consumed from pbSigImp
+ &cbEmit)); // [OUT] total number of bytes write to pqkSigEmit
+ cbSrcTotal += cbImp;
+ cbDestTotal += cbEmit;
+
+ // Parse for the rank
+ cbSubTotal = CorSigUncompressData(&pbSigImp[cbSrcTotal], &ulData);
+
+ // if rank == 0, we are done
+ if (ulData != 0)
+ {
+ // any size of dimension specified?
+ cb = CorSigUncompressData(&pbSigImp[cbSrcTotal + cbSubTotal], &ulData);
+ cbSubTotal += cb;
+
+ while (ulData--)
+ {
+ cb = CorSigUncompressData(&pbSigImp[cbSrcTotal + cbSubTotal], &ulTemp);
+ cbSubTotal += cb;
+ }
+
+ // any lower bound specified?
+ cb = CorSigUncompressData(&pbSigImp[cbSrcTotal + cbSubTotal], &ulData);
+ cbSubTotal += cb;
+
+ while (ulData--)
+ {
+ cb = CorSigUncompressSignedInt(&pbSigImp[cbSrcTotal + cbSubTotal], &iData);
+ cbSubTotal += cb;
+ }
+ }
+
+ // cbSubTotal is now the number of bytes still left to move over
+ // cbSrcTotal is where bytes start on the pbSigImp to be copied over
+ // cbStartEmit + cbDestTotal is where the destination of copy
+
+ IfFailGo(pqkSigEmit->ReSizeNoThrow(cbStartEmit + cbDestTotal + cbSubTotal));
+ memcpy(((BYTE *)pqkSigEmit->Ptr())+cbStartEmit + cbDestTotal, &pbSigImp[cbSrcTotal], cbSubTotal);
+
+ cbSrcTotal = cbSrcTotal + cbSubTotal;
+ cbDestTotal = cbDestTotal + cbSubTotal;
+
+ break;
+ case ELEMENT_TYPE_FNPTR:
+ // function pointer is followed by another complete signature
+ IfFailGo(MergeUpdateTokenInSig(
+ pMiniMdAssemEmit, // The assembly emit scope.
+ pMiniMdEmit, // The emit scope.
+ pCommonAssemImport, // The assembly scope where the signature is from.
+ pbHashValue, // Hash value for the import assembly.
+ cbHashValue, // Size in bytes for the hash value.
+ pCommonImport, // The scope to merge into the emit scope.
+ &pbSigImp[cbSrcTotal], // signature from the imported scope
+ ptkMap, // Internal OID mapping structure.
+ pqkSigEmit, // [OUT] buffer for translated signature
+ cbStartEmit + cbDestTotal, // [IN] start point of buffer to write to
+ &cbImp, // [OUT] total number of bytes consumed from pbSigImp
+ &cbEmit)); // [OUT] total number of bytes write to pqkSigEmit
+ cbSrcTotal += cbImp;
+ cbDestTotal += cbEmit;
+ break;
+ case ELEMENT_TYPE_VALUETYPE:
+ case ELEMENT_TYPE_CLASS:
+ case ELEMENT_TYPE_CMOD_REQD:
+ case ELEMENT_TYPE_CMOD_OPT:
+
+ // syntax for CLASS = ELEMENT_TYPE_CLASS <rid>
+ // syntax for VALUE_CLASS = ELEMENT_TYPE_VALUECLASS <rid>
+
+ // now get the embedded typeref token
+ cb = CorSigUncompressToken(&pbSigImp[cbSrcTotal], &tkRidFrom);
+
+ // Map the ulRidFrom to ulRidTo
+ if (ptkMap)
+ {
+ // mdtBaseType does not record in the map. It is unique across modules
+ if ( TypeFromToken(tkRidFrom) == mdtBaseType )
+ {
+ tkRidTo = tkRidFrom;
+ }
+ else
+ {
+ IfFailGo( ptkMap->Remap(tkRidFrom, &tkRidTo) );
+ }
+ }
+ else
+ {
+ // If the token is a TypeDef or a TypeRef, get/create the
+ // ResolutionScope for the outermost TypeRef.
+ if (TypeFromToken(tkRidFrom) == mdtTypeDef)
+ {
+ IfFailGo(ImportTypeDef(pMiniMdAssemEmit,
+ pMiniMdEmit,
+ pCommonAssemImport,
+ pbHashValue,
+ cbHashValue,
+ pCommonImport,
+ tkRidFrom,
+ true, // Optimize to TypeDef if emit and import scopes are identical.
+ &tkRidTo));
+ }
+ else if (TypeFromToken(tkRidFrom) == mdtTypeRef)
+ {
+ IfFailGo(ImportTypeRef(pMiniMdAssemEmit,
+ pMiniMdEmit,
+ pCommonAssemImport,
+ pbHashValue,
+ cbHashValue,
+ pCommonImport,
+ tkRidFrom,
+ &tkRidTo));
+ }
+ else if ( TypeFromToken(tkRidFrom) == mdtTypeSpec )
+ {
+ // copy over the TypeSpec
+ PCCOR_SIGNATURE pvTypeSpecSig;
+ ULONG cbTypeSpecSig;
+ CQuickBytes qkTypeSpecSigEmit;
+ ULONG cbTypeSpecEmit;
+
+ IfFailGo(pCommonImport->CommonGetTypeSpecProps(
+ tkRidFrom,
+ &pvTypeSpecSig,
+ &cbTypeSpecSig));
+
+ // Translate the typespec signature before look up
+ IfFailGo(MergeUpdateTokenInFieldSig(
+ pMiniMdAssemEmit, // The assembly emit scope.
+ pMiniMdEmit, // The emit scope.
+ pCommonAssemImport, // The assembly scope where the signature is from.
+ pbHashValue, // Hash value for the import assembly.
+ cbHashValue, // Size in bytes for the hash value.
+ pCommonImport, // The scope to merge into the emit scope.
+ pvTypeSpecSig, // signature from the imported scope
+ ptkMap, // Internal OID mapping structure.
+ &qkTypeSpecSigEmit, // [OUT] buffer for translated signature
+ 0, // start from first byte of TypeSpec signature
+ 0, // don't care how many bytes are consumed
+ &cbTypeSpecEmit) ); // [OUT] total number of bytes write to pqkSigEmit
+
+ hr = FindTypeSpec(pMiniMdEmit,
+ (PCCOR_SIGNATURE) (qkTypeSpecSigEmit.Ptr()),
+ cbTypeSpecEmit,
+ &tkRidTo);
+
+ if ( hr == CLDB_E_RECORD_NOTFOUND )
+ {
+ // Create TypeSpec record.
+ TypeSpecRec *pRecEmit;
+
+ IfFailGo(pMiniMdEmit->AddTypeSpecRecord(&pRecEmit, (RID *)&tkRidTo));
+
+ IfFailGo(pMiniMdEmit->PutBlob(
+ TBL_TypeSpec,
+ TypeSpecRec::COL_Signature,
+ pRecEmit,
+ (PCCOR_SIGNATURE) (qkTypeSpecSigEmit.Ptr()),
+ cbTypeSpecEmit));
+ tkRidTo = TokenFromRid( tkRidTo, mdtTypeSpec );
+ IfFailGo(pMiniMdEmit->UpdateENCLog(tkRidTo));
+ }
+ IfFailGo( hr );
+ }
+ else
+ {
+ _ASSERTE( TypeFromToken(tkRidFrom) == mdtBaseType );
+
+ // base type is unique across module
+ tkRidTo = tkRidFrom;
+ }
+ }
+
+ // How many bytes the new rid will consume?
+ cb1 = CorSigCompressToken(tkRidTo, &ulData);
+
+ // ensure buffer is big enough
+ IfFailGo(pqkSigEmit->ReSizeNoThrow(cbStartEmit + cbDestTotal + cb1));
+
+ // store the new token
+ cb2 = CorSigCompressToken(
+ tkRidTo,
+ (ULONG *)( ((BYTE *)pqkSigEmit->Ptr()) + cbStartEmit + cbDestTotal) );
+
+ // inconsistency on CorSigCompressToken and CorSigUncompressToken
+ _ASSERTE(cb1 == cb2);
+
+ cbSrcTotal = cbSrcTotal + cb;
+ cbDestTotal = cbDestTotal + cb1;
+
+ if ( ulElementType == ELEMENT_TYPE_CMOD_REQD ||
+ ulElementType == ELEMENT_TYPE_CMOD_OPT)
+ {
+ // need to skip over the base type
+ IfFailGo(MergeUpdateTokenInFieldSig(
+ pMiniMdAssemEmit, // The assembly emit scope.
+ pMiniMdEmit, // The emit scope.
+ pCommonAssemImport, // The assembly scope where the signature is from.
+ pbHashValue, // Hash value for the import assembly.
+ cbHashValue, // Size in bytes for the hash value.
+ pCommonImport, // The scope to merge into the emit scope.
+ &pbSigImp[cbSrcTotal], // signature from the imported scope
+ ptkMap, // Internal OID mapping structure.
+ pqkSigEmit, // [OUT] buffer for translated signature
+ cbStartEmit + cbDestTotal, // [IN] start point of buffer to write to
+ &cbImp, // [OUT] total number of bytes consumed from pbSigImp
+ &cbEmit)); // [OUT] total number of bytes write to pqkSigEmit
+ cbSrcTotal += cbImp;
+ cbDestTotal += cbEmit;
+ }
+
+ break;
+ default:
+ _ASSERTE(cbSrcTotal == cbDestTotal);
+
+ if ((ulElementType >= ELEMENT_TYPE_MAX) ||
+ (ulElementType == ELEMENT_TYPE_PTR) ||
+ (ulElementType == ELEMENT_TYPE_BYREF) ||
+ (ulElementType == ELEMENT_TYPE_VALUEARRAY_UNSUPPORTED))
+ {
+ IfFailGo(META_E_BAD_SIGNATURE);
+ }
+ break;
+ }
+ if (pcbImp)
+ *pcbImp = cbSrcTotal;
+ *pcbEmit = cbDestTotal;
+
+ErrExit:
+ return hr;
+} // ImportHelper::MergeUpdateTokenInFieldSig
+
+#endif //FEATURE_METADATA_EMIT
+
+//****************************************************************************
+// convert tokens contained in a COM+ signature
+//****************************************************************************
+HRESULT ImportHelper::MergeUpdateTokenInSig(// S_OK or error.
+ CMiniMdRW *pMiniMdAssemEmit, // [IN] The assembly emit scope.
+ CMiniMdRW *pMiniMdEmit, // [IN] The emit scope.
+ IMetaModelCommon *pCommonAssemImport,// [IN] Assembly scope where the signature is from.
+ const void *pbHashValue, // [IN] Hash value for the import assembly.
+ ULONG cbHashValue, // [IN] Size in bytes for the hash value.
+ IMetaModelCommon *pCommonImport, // [IN] The scope to merge into the emit scope.
+ PCCOR_SIGNATURE pbSigImp, // signature from the imported scope
+ MDTOKENMAP *ptkMap, // Internal OID mapping structure.
+ CQuickBytes *pqkSigEmit, // [OUT] translated signature
+ ULONG cbStartEmit, // [IN] start point of buffer to write to
+ ULONG *pcbImp, // [OUT] total number of bytes consumed from pbSigImp
+ ULONG *pcbEmit) // [OUT] total number of bytes write to pqkSigEmit
+{
+#ifdef FEATURE_METADATA_EMIT
+ HRESULT hr = NOERROR; // A result.
+ ULONG cb; // count of bytes
+ ULONG cb1;
+ ULONG cbSrcTotal = 0; // count of bytes consumed in the imported signature
+ ULONG cbDestTotal = 0; // count of bytes for the new signature
+ ULONG cbEmit; // count of bytes consumed in the imported signature
+ ULONG cbImp; // count of bytes for the new signature
+ ULONG cArg = 0; // count of arguments in the signature
+ ULONG cTyArg = 0;
+ ULONG callingconv = 0; // calling convention from signature
+
+ _ASSERTE(pcbEmit && pqkSigEmit && pbSigImp);
+
+ // calling convention
+ cb = CorSigUncompressData(&pbSigImp[cbSrcTotal], &callingconv);
+ _ASSERTE((callingconv & IMAGE_CEE_CS_CALLCONV_MASK) < IMAGE_CEE_CS_CALLCONV_MAX);
+
+ // skip over calling convention
+ cbSrcTotal += cb;
+
+ if (isCallConv(callingconv, IMAGE_CEE_CS_CALLCONV_FIELD))
+ {
+ // It is a FieldRef
+ cb1 = CorSigCompressData(callingconv, ((BYTE *)pqkSigEmit->Ptr()) + cbStartEmit);
+
+ // compression and uncompression better match
+ _ASSERTE(cb == cb1);
+
+ cbDestTotal = cbSrcTotal = cb;
+ IfFailGo(MergeUpdateTokenInFieldSig(
+ pMiniMdAssemEmit,
+ pMiniMdEmit,
+ pCommonAssemImport,
+ pbHashValue,
+ cbHashValue,
+ pCommonImport,
+ &pbSigImp[cbSrcTotal],
+ ptkMap,
+ pqkSigEmit, // output buffer to hold the new sig for the field
+ cbStartEmit + cbDestTotal, // number of bytes already in pqkSigDest
+ &cbImp, // number of bytes consumed from imported signature
+ &cbEmit)); // number of bytes write to the new signature
+ *pcbEmit = cbDestTotal + cbEmit;
+ }
+ else
+ {
+
+ // It is a MethodRef
+ // count of type arguments
+ if (callingconv & IMAGE_CEE_CS_CALLCONV_GENERIC)
+ {
+ cb = CorSigUncompressData(&pbSigImp[cbSrcTotal], &cTyArg);
+ cbSrcTotal += cb;
+ }
+
+ // count of argument
+ cb = CorSigUncompressData(&pbSigImp[cbSrcTotal], &cArg);
+ cbSrcTotal += cb;
+
+ // move over the calling convention and the count of arguments
+ IfFailGo(pqkSigEmit->ReSizeNoThrow(cbStartEmit + cbSrcTotal));
+ memcpy(((BYTE *)pqkSigEmit->Ptr()) + cbStartEmit, pbSigImp, cbSrcTotal);
+ cbDestTotal = cbSrcTotal;
+
+ if ( !( isCallConv(callingconv, IMAGE_CEE_CS_CALLCONV_LOCAL_SIG) || isCallConv(callingconv, IMAGE_CEE_CS_CALLCONV_GENERICINST)) )
+ {
+ // LocalVar sig does not have return type
+ // process the return type
+ IfFailGo(MergeUpdateTokenInFieldSig(
+ pMiniMdAssemEmit,
+ pMiniMdEmit,
+ pCommonAssemImport,
+ pbHashValue,
+ cbHashValue,
+ pCommonImport,
+ &pbSigImp[cbSrcTotal],
+ ptkMap,
+ pqkSigEmit, // output buffer to hold the new sig for the field
+ cbStartEmit + cbDestTotal, // number of bytes already in pqkSigDest
+ &cbImp, // number of bytes consumed from imported signature
+ &cbEmit)); // number of bytes write to the new signature
+
+ // advance the count
+ cbSrcTotal += cbImp;
+ cbDestTotal += cbEmit;
+ }
+
+
+ while (cArg)
+ {
+ // process every argument
+ IfFailGo(MergeUpdateTokenInFieldSig(
+ pMiniMdAssemEmit,
+ pMiniMdEmit,
+ pCommonAssemImport,
+ pbHashValue,
+ cbHashValue,
+ pCommonImport,
+ &pbSigImp[cbSrcTotal],
+ ptkMap,
+ pqkSigEmit, // output buffer to hold the new sig for the field
+ cbStartEmit + cbDestTotal,
+ &cbImp, // number of bytes consumed from imported signature
+ &cbEmit)); // number of bytes write to the new signature
+ cbSrcTotal += cbImp;
+ cbDestTotal += cbEmit;
+ cArg--;
+ }
+
+ // total of number of bytes consumed from imported signature
+ if (pcbImp)
+ *pcbImp = cbSrcTotal;
+
+ // total number of bytes emitted by this function call to the emitting signature
+ *pcbEmit = cbDestTotal;
+ }
+
+ErrExit:
+ return hr;
+#else //!FEATURE_METADATA_EMIT
+ // This code should be called only with public emit APIs
+ _ASSERTE_MSG(FALSE, "This method should not be reachable");
+ return E_NOTIMPL;
+#endif //!FEATURE_METADATA_EMIT
+} // ImportHelper::MergeUpdateTokenInSig
+
+//****************************************************************************
+// Given a TypeDef or a TypeRef, return the Nesting hierarchy. The first
+// element in the returned array always refers to the class token passed and
+// the nesting hierarchy expands outwards from there.
+//****************************************************************************
+HRESULT ImportHelper::GetNesterHierarchy(
+ IMetaModelCommon *pCommon, // Scope in which to find the hierarchy.
+ mdToken tk, // TypeDef/TypeRef whose hierarchy is needed.
+ CQuickArray<mdToken> &cqaNesters, // Array of Nesters.
+ CQuickArray<LPCUTF8> &cqaNamespaces, // Names of the nesters.
+ CQuickArray<LPCUTF8> &cqaNames) // Namespaces of the nesters.
+{
+ _ASSERTE(pCommon &&
+ (TypeFromToken(tk) == mdtTypeDef ||
+ TypeFromToken(tk) == mdtTypeRef) &&
+ !IsNilToken(tk));
+
+ if (TypeFromToken(tk) == mdtTypeDef)
+ {
+ return GetTDNesterHierarchy(pCommon,
+ tk,
+ cqaNesters,
+ cqaNamespaces,
+ cqaNames);
+ }
+ else
+ {
+ return GetTRNesterHierarchy(pCommon,
+ tk,
+ cqaNesters,
+ cqaNamespaces,
+ cqaNames);
+ }
+} // HRESULT ImportHelper::GetNesterHierarchy()
+
+//****************************************************************************
+// Get Nesting hierarchy given a TypeDef.
+//****************************************************************************
+HRESULT ImportHelper::GetTDNesterHierarchy(
+ IMetaModelCommon *pCommon, // Scope in which to find the hierarchy.
+ mdTypeDef td, // TypeDef whose hierarchy is needed.
+ CQuickArray<mdTypeDef> &cqaTdNesters,// Array of Nesters.
+ CQuickArray<LPCUTF8> &cqaNamespaces, // Namespaces of the nesters.
+ CQuickArray<LPCUTF8> &cqaNames) // Names of the nesters.
+{
+ LPCUTF8 szName, szNamespace;
+ DWORD dwFlags;
+ mdTypeDef tdNester;
+ ULONG ulNesters;
+ HRESULT hr = NOERROR;
+
+ _ASSERTE(pCommon &&
+ TypeFromToken(td) == mdtTypeDef &&
+ !IsNilToken(td));
+
+ // Set current Nester index to 0.
+ ulNesters = 0;
+ // The first element in the hierarchy is the TypeDef itself.
+ tdNester = td;
+ // Bogus initialization to kick off the while loop.
+ dwFlags = tdNestedPublic;
+ // Loop as long as the TypeDef is a Nested TypeDef.
+ while (IsTdNested(dwFlags))
+ {
+ if (InvalidRid(tdNester))
+ IfFailGo(CLDB_E_RECORD_NOTFOUND);
+ // Get the name and namespace for the TypeDef.
+ IfFailGo(pCommon->CommonGetTypeDefProps(
+ tdNester,
+ &szNamespace,
+ &szName,
+ &dwFlags,
+ NULL,
+ NULL));
+
+ // Update the dynamic arrays.
+ ulNesters++;
+
+ IfFailGo(cqaTdNesters.ReSizeNoThrow(ulNesters));
+ cqaTdNesters[ulNesters-1] = tdNester;
+
+ IfFailGo(cqaNamespaces.ReSizeNoThrow(ulNesters));
+ cqaNamespaces[ulNesters-1] = szNamespace;
+
+ IfFailGo(cqaNames.ReSizeNoThrow(ulNesters));
+ cqaNames[ulNesters-1] = szName;
+
+ IfFailGo(pCommon->CommonGetEnclosingClassOfTypeDef(tdNester, &tdNester));
+ }
+ // Outermost class must have enclosing of Nil.
+ _ASSERTE(IsNilToken(tdNester));
+ErrExit:
+ return hr;
+} // HRESULT ImportHelper::GetTDNesterHierarchy()
+
+
+//****************************************************************************
+// Get Nesting hierarchy given a TypeRef.
+//****************************************************************************
+HRESULT ImportHelper::GetTRNesterHierarchy(
+ IMetaModelCommon *pCommon, // [IN] Scope in which to find the hierarchy.
+ mdTypeRef tr, // [IN] TypeRef whose hierarchy is needed.
+ CQuickArray<mdTypeRef> &cqaTrNesters,// [OUT] Array of Nesters.
+ CQuickArray<LPCUTF8> &cqaNamespaces, // [OUT] Namespaces of the nesters.
+ CQuickArray<LPCUTF8> &cqaNames) // [OUT] Names of the nesters.
+{
+ LPCUTF8 szNamespace;
+ LPCUTF8 szName;
+ mdTypeRef trNester;
+ mdToken tkResolutionScope;
+ ULONG ulNesters;
+ HRESULT hr = S_OK;
+
+ _ASSERTE(pCommon &&
+ TypeFromToken(tr) == mdtTypeRef &&
+ !IsNilToken(tr));
+
+ // Set current Nester index to 0.
+ ulNesters = 0;
+ // The first element in the hierarchy is the TypeRef itself.
+ trNester = tr;
+ // Loop as long as the TypeRef is a Nested TypeRef.
+ while (TypeFromToken(trNester) == mdtTypeRef && !IsNilToken(trNester))
+ {
+ // Get the name and namespace for the TypeDef.
+ IfFailGo(pCommon->CommonGetTypeRefProps(
+ trNester,
+ &szNamespace,
+ &szName,
+ &tkResolutionScope));
+
+ // Update the dynamic arrays.
+ ulNesters++;
+
+ IfFailGo(cqaTrNesters.ReSizeNoThrow(ulNesters));
+ cqaTrNesters[ulNesters-1] = trNester;
+
+ IfFailGo(cqaNamespaces.ReSizeNoThrow(ulNesters));
+ cqaNamespaces[ulNesters-1] = szNamespace;
+
+ IfFailGo(cqaNames.ReSizeNoThrow(ulNesters));
+ cqaNames[ulNesters-1] = szName;
+
+ trNester = tkResolutionScope;
+ }
+ErrExit:
+ return hr;
+} // HRESULT ImportHelper::GetTRNesterHierarchy()
+
+//****************************************************************************
+// Create the Nesting hierarchy given the array of TypeRef names. The first
+// TypeRef in the array is the innermost TypeRef.
+//****************************************************************************
+HRESULT ImportHelper::CreateNesterHierarchy(
+ CMiniMdRW *pMiniMdEmit, // [IN] Emit scope to create the Nesters in.
+ CQuickArray<LPCUTF8> &cqaNesterNamespaces, // [IN] Array of Nester namespaces.
+ CQuickArray<LPCUTF8> &cqaNesterNames, // [IN] Array of Nester names.
+ mdToken tkResolutionScope, // [IN] ResolutionScope for the innermost TypeRef.
+ mdTypeRef *ptr) // [OUT] Token for the innermost TypeRef.
+{
+ TypeRefRec *pRecEmit;
+ ULONG iRecord;
+ LPCUTF8 szName;
+ LPCUTF8 szNamespace;
+ mdTypeRef trNester;
+ mdTypeRef trCur;
+ ULONG ulNesters;
+ HRESULT hr = S_OK;
+
+ _ASSERTE(cqaNesterNames.Size() == cqaNesterNamespaces.Size() &&
+ cqaNesterNames.Size());
+
+ // Initialize the output parameter.
+ *ptr = mdTypeRefNil;
+
+ // Get count of Nesters in the hierarchy.
+ ulNesters = (ULONG)cqaNesterNames.Size();
+
+ // For each nester try to find the corresponding TypeRef in the emit scope.
+ // For the outermost TypeRef, ResolutionScope is what's passed in.
+ if (tkResolutionScope == mdTokenNil)
+ trNester = mdTypeRefNil;
+ else
+ trNester = tkResolutionScope;
+ ULONG ulCurNester;
+ for (ulCurNester = ulNesters-1; ulCurNester != (ULONG) -1; ulCurNester--)
+ {
+ hr = FindTypeRefByName(pMiniMdEmit,
+ trNester,
+ cqaNesterNamespaces[ulCurNester],
+ cqaNesterNames[ulCurNester],
+ &trCur);
+ if (hr == CLDB_E_RECORD_NOTFOUND)
+ break;
+ else
+ IfFailGo(hr);
+ trNester = trCur;
+ }
+ if (SUCCEEDED(hr))
+ *ptr = trNester;
+ else if ( hr == CLDB_E_RECORD_NOTFOUND )
+ {
+ // Create TypeRef records for the part of the hierarchy for which
+ // TypeRefs are not already present.
+ for (;ulCurNester != (ULONG) -1; ulCurNester--)
+ {
+ szName = cqaNesterNames[ulCurNester];
+ szNamespace = cqaNesterNamespaces[ulCurNester];
+
+ IfFailGo(pMiniMdEmit->AddTypeRefRecord(&pRecEmit, &iRecord));
+ if (szNamespace && szNamespace[0] != '\0')
+ {
+ // only put the namespace if it is not an empty string and not NULL
+ IfFailGo(pMiniMdEmit->PutString(TBL_TypeRef, TypeRefRec::COL_Namespace,
+ pRecEmit, szNamespace));
+ }
+ IfFailGo(pMiniMdEmit->PutString(TBL_TypeRef, TypeRefRec::COL_Name,
+ pRecEmit, szName));
+ IfFailGo(pMiniMdEmit->PutToken(TBL_TypeRef,
+ TypeRefRec::COL_ResolutionScope, pRecEmit, trNester));
+
+ trNester = TokenFromRid(iRecord, mdtTypeRef);
+ IfFailGo(pMiniMdEmit->UpdateENCLog(trNester));
+
+ // Hash the name.
+ IfFailGo(pMiniMdEmit->AddNamedItemToHash(TBL_TypeRef, trNester, szName, 0));
+ }
+ *ptr = trNester;
+ }
+ else
+ IfFailGo(hr);
+ErrExit:
+ return hr;
+} // ImportHelper::CreateNesterHierarchy
+
+//****************************************************************************
+// Given the arrays of names and namespaces for the Nested Type hierarchy,
+// find the innermost TypeRef token. The arrays start with the innermost
+// TypeRefs and go outwards.
+//****************************************************************************
+HRESULT ImportHelper::FindNestedTypeRef(
+ CMiniMdRW *pMiniMd, // [IN] Scope in which to find the TypeRef.
+ CQuickArray<LPCUTF8> &cqaNesterNamespaces, // [IN] Array of Names.
+ CQuickArray<LPCUTF8> &cqaNesterNames, // [IN] Array of Namespaces.
+ mdToken tkResolutionScope, // [IN] Resolution scope for the outermost TypeRef.
+ mdTypeRef *ptr) // [OUT] Inner most TypeRef token.
+{
+ ULONG ulNesters;
+ ULONG ulCurNester;
+ HRESULT hr = S_OK;
+
+ _ASSERTE(cqaNesterNames.Size() == cqaNesterNamespaces.Size() &&
+ cqaNesterNames.Size());
+
+ // Set the output parameter to Nil token.
+ *ptr = mdTokenNil;
+
+ // Get count in the hierarchy, the give TypeDef included.
+ ulNesters = (ULONG)cqaNesterNames.Size();
+
+ // For each nester try to find the corresponding TypeRef in
+ // the emit scope. For the outermost TypeDef enclosing class is Nil.
+ for (ulCurNester = ulNesters-1; ulCurNester != (ULONG) -1; ulCurNester--)
+ {
+ IfFailGo(FindTypeRefByName(pMiniMd,
+ tkResolutionScope,
+ cqaNesterNamespaces[ulCurNester],
+ cqaNesterNames[ulCurNester],
+ &tkResolutionScope));
+ }
+ *ptr = tkResolutionScope;
+ErrExit:
+ return hr;
+} // HRESULT ImportHelper::FindNestedTypeRef()
+
+
+//****************************************************************************
+// Given the arrays of names and namespaces for the Nested Type hierarchy,
+// find the innermost TypeDef token. The arrays start with the innermost
+// TypeDef and go outwards.
+//****************************************************************************
+HRESULT ImportHelper::FindNestedTypeDef(
+ CMiniMdRW *pMiniMd, // [IN] Scope in which to find the TypeRef.
+ CQuickArray<LPCUTF8> &cqaNesterNamespaces, // [IN] Array of Namespaces.
+ CQuickArray<LPCUTF8> &cqaNesterNames, // [IN] Array of Names.
+ mdTypeDef tdNester, // [IN] Enclosing class for the Outermost TypeDef.
+ mdTypeDef *ptd) // [OUT] Inner most TypeRef token.
+{
+ ULONG ulNesters;
+ ULONG ulCurNester;
+ HRESULT hr = S_OK;
+
+ _ASSERTE(cqaNesterNames.Size() == cqaNesterNamespaces.Size() &&
+ cqaNesterNames.Size());
+
+ // Set the output parameter to Nil token.
+ *ptd = mdTokenNil;
+
+ // Get count in the hierarchy, the give TypeDef included.
+ ulNesters = (ULONG)cqaNesterNames.Size();
+
+ // For each nester try to find the corresponding TypeRef in
+ // the emit scope. For the outermost TypeDef enclosing class is Nil.
+ for (ulCurNester = ulNesters-1; ulCurNester != (ULONG) -1; ulCurNester--)
+ {
+ IfFailGo(FindTypeDefByName(pMiniMd,
+ cqaNesterNamespaces[ulCurNester],
+ cqaNesterNames[ulCurNester],
+ tdNester,
+ &tdNester));
+ }
+ *ptd = tdNester;
+ErrExit:
+ return hr;
+} // ImportHelper::FindNestedTypeDef
+
+#ifdef FEATURE_METADATA_EMIT
+
+//****************************************************************************
+// Given the TypeDef and the corresponding assembly and module import scopes,
+// create a corresponding TypeRef in the given emit scope.
+//****************************************************************************
+HRESULT
+ImportHelper::ImportTypeDef(
+ CMiniMdRW * pMiniMdAssemEmit, // [IN] Assembly emit scope.
+ CMiniMdRW * pMiniMdEmit, // [IN] Module emit scope.
+ IMetaModelCommon * pCommonAssemImport, // [IN] Assembly import scope.
+ const void * pbHashValue, // [IN] Hash value for import assembly.
+ ULONG cbHashValue, // [IN] Size in bytes of hash value.
+ IMetaModelCommon * pCommonImport, // [IN] Module import scope.
+ mdTypeDef tdImport, // [IN] Imported TypeDef.
+ bool bReturnTd, // [IN] If the import and emit scopes are identical, return the TypeDef.
+ mdToken * ptkType) // [OUT] Output token for the imported type in the emit scope.
+{
+ CQuickArray<mdTypeDef> cqaNesters;
+ CQuickArray<LPCUTF8> cqaNesterNames;
+ CQuickArray<LPCUTF8> cqaNesterNamespaces;
+ GUID nullguid = GUID_NULL;
+ GUID MvidAssemImport = nullguid;
+ GUID MvidAssemEmit = nullguid;
+ GUID MvidImport = nullguid;
+ GUID MvidEmit = nullguid;
+ GUID GuidImport = GUID_NULL;
+ LPCUTF8 szModuleImport;
+ mdToken tkOuterRes = mdTokenNil;
+ HRESULT hr = S_OK;
+ BOOL bBCL = false;
+
+ _ASSERTE(pMiniMdEmit && pCommonImport && ptkType);
+ _ASSERTE(TypeFromToken(tdImport) == mdtTypeDef && tdImport != mdTypeDefNil);
+
+ // Get MVIDs for import and emit, assembly and module scopes.
+ if (pCommonAssemImport != NULL)
+ {
+ IfFailGo(pCommonAssemImport->CommonGetScopeProps(0, &MvidAssemImport));
+ }
+ IfFailGo(pCommonImport->CommonGetScopeProps(&szModuleImport, &MvidImport));
+ if (pMiniMdAssemEmit != NULL)
+ {
+ IfFailGo(static_cast<IMetaModelCommon*>(pMiniMdAssemEmit)->CommonGetScopeProps(0, &MvidAssemEmit));
+ }
+ IfFailGo(static_cast<IMetaModelCommon*>(pMiniMdEmit)->CommonGetScopeProps(0, &MvidEmit));
+
+ if (pCommonAssemImport == NULL && strcmp(szModuleImport, COM_RUNTIME_LIBRARY) == 0)
+ {
+ const BYTE *pBlob; // Blob with dispid.
+ ULONG cbBlob; // Length of blob.
+ WCHAR wzBlob[40]; // Wide char format of guid.
+ int ix; // Loop control.
+
+ hr = pCommonImport->CommonGetCustomAttributeByName(1, INTEROP_GUID_TYPE, (const void **)&pBlob, &cbBlob);
+ if (hr != S_FALSE)
+ {
+ // Should be in format. Total length == 41
+ // <0x0001><0x24>01234567-0123-0123-0123-001122334455<0x0000>
+ if ((cbBlob == 41) || (GET_UNALIGNED_VAL16(pBlob) == 1))
+ {
+ for (ix=1; ix<=36; ++ix)
+ wzBlob[ix] = pBlob[ix+2];
+ wzBlob[0] = '{';
+ wzBlob[37] = '}';
+ wzBlob[38] = 0;
+ // It's ok that we ignore the hr here. It's not needed, but I
+ // don't want to remove it in case a code analysis tool will complain
+ // about not capturing return codes.
+ hr = IIDFromString(wzBlob, &GuidImport);
+ }
+ }
+ bBCL = (GuidImport == LIBID_ComPlusRuntime);
+ }
+
+ // Compute the ResolutionScope for the imported type.
+ if (bBCL)
+ {
+ // This is the case that we are referring to mscorlib.dll but client does not provide the manifest for
+ // mscorlib.dll!! Do not generate ModuleRef to the mscorlib.dll. But instead we should just leave the
+ // ResolutionScope empty
+ tkOuterRes = mdTokenNil;
+ }
+ else if (MvidAssemImport == MvidAssemEmit && MvidImport == MvidEmit)
+ {
+ // The TypeDef is in the same Assembly and the Same scope.
+ if (bReturnTd)
+ {
+ *ptkType = tdImport;
+ goto ErrExit;
+ }
+ else
+ tkOuterRes = TokenFromRid(1, mdtModule);
+ }
+ else if (MvidAssemImport == MvidAssemEmit && MvidImport != MvidEmit)
+ {
+ // The TypeDef is in the same Assembly but a different module.
+
+ // Create a ModuleRef corresponding to the import scope.
+ IfFailGo(CreateModuleRefFromScope(pMiniMdEmit, pCommonImport, &tkOuterRes));
+ }
+ else if (MvidAssemImport != MvidAssemEmit)
+ {
+ if (pCommonAssemImport)
+ {
+ // The TypeDef is from a different Assembly.
+
+ // Import and Emit scopes can't be identical and be from different
+ // Assemblies at the same time.
+ _ASSERTE(MvidImport != MvidEmit &&
+ "Import scope can't be identical to the Emit scope and be from a different Assembly at the same time.");
+
+ _ASSERTE(pCommonAssemImport);
+
+ // Create an AssemblyRef corresponding to the import scope.
+ IfFailGo(CreateAssemblyRefFromAssembly(pMiniMdAssemEmit,
+ pMiniMdEmit,
+ pCommonAssemImport,
+ pbHashValue,
+ cbHashValue,
+ &tkOuterRes));
+ }
+ else
+ {
+ // <REVISIT_TODO>@FUTURE: review this fix! We may want to return error in the future.
+ // This is to enable smc to reference mscorlib.dll while it does not have the manifest for mscorlib.dll opened.</REVISIT_TODO>
+ // Create a Nil ResolutionScope to the TypeRef.
+ tkOuterRes = mdTokenNil;
+ }
+ }
+
+ // Get the nesting hierarchy for the Type from the import scope and create
+ // the corresponding Type hierarchy in the emit scope. Note that the non-
+ // nested class case simply folds into this scheme.
+
+ IfFailGo(GetNesterHierarchy(pCommonImport,
+ tdImport,
+ cqaNesters,
+ cqaNesterNamespaces,
+ cqaNesterNames));
+
+ IfFailGo(CreateNesterHierarchy(pMiniMdEmit,
+ cqaNesterNamespaces,
+ cqaNesterNames,
+ tkOuterRes,
+ ptkType));
+ErrExit:
+ return hr;
+} // ImportHelper::ImportTypeDef
+
+//****************************************************************************
+// Given the TypeRef and the corresponding assembly and module import scopes,
+// return the corresponding token in the given emit scope.
+// <REVISIT_TODO>@FUTURE: Should we look at visibility flags on ExportedTypes and TypeDefs when
+// handling references across Assemblies?</REVISIT_TODO>
+//****************************************************************************
+HRESULT ImportHelper::ImportTypeRef(
+ CMiniMdRW *pMiniMdAssemEmit, // [IN] Assembly emit scope.
+ CMiniMdRW *pMiniMdEmit, // [IN] Module emit scope.
+ IMetaModelCommon *pCommonAssemImport, // [IN] Assembly import scope.
+ const void *pbHashValue, // [IN] Hash value for import assembly.
+ ULONG cbHashValue, // [IN] Size in bytes of hash value.
+ IMetaModelCommon *pCommonImport, // [IN] Module import scope.
+ mdTypeRef trImport, // [IN] Imported TypeRef.
+ mdToken *ptkType) // [OUT] Output token for the imported type in the emit scope.
+{
+ CQuickArray<mdTypeDef> cqaNesters;
+ CQuickArray<LPCUTF8> cqaNesterNames;
+ CQuickArray<LPCUTF8> cqaNesterNamespaces;
+ LPCUTF8 szScopeNameEmit;
+ GUID nullguid = GUID_NULL;
+ GUID MvidAssemImport = nullguid;
+ GUID MvidAssemEmit = nullguid;
+ GUID MvidImport = nullguid;
+ GUID MvidEmit = nullguid;
+ mdToken tkOuterImportRes; // ResolutionScope for the outermost TypeRef in import scope.
+ mdToken tkOuterEmitRes = mdTokenNil; // ResolutionScope for outermost TypeRef in emit scope.
+ HRESULT hr = S_OK;
+ bool bAssemblyRefFromAssemScope = false;
+
+ _ASSERTE(pMiniMdEmit && pCommonImport && ptkType);
+ _ASSERTE(TypeFromToken(trImport) == mdtTypeRef);
+
+ // Get MVIDs for import and emit, assembly and module scopes.
+ if (pCommonAssemImport != NULL)
+ {
+ IfFailGo(pCommonAssemImport->CommonGetScopeProps(0, &MvidAssemImport));
+ }
+ IfFailGo(pCommonImport->CommonGetScopeProps(0, &MvidImport));
+ if (pMiniMdAssemEmit != NULL)
+ {
+ IfFailGo(static_cast<IMetaModelCommon*>(pMiniMdAssemEmit)->CommonGetScopeProps(
+ 0,
+ &MvidAssemEmit));
+ }
+ IfFailGo(static_cast<IMetaModelCommon*>(pMiniMdEmit)->CommonGetScopeProps(
+ &szScopeNameEmit,
+ &MvidEmit));
+
+ // Get the outermost resolution scope for the TypeRef being imported.
+ IfFailGo(GetNesterHierarchy(pCommonImport,
+ trImport,
+ cqaNesters,
+ cqaNesterNamespaces,
+ cqaNesterNames));
+ IfFailGo(pCommonImport->CommonGetTypeRefProps(
+ cqaNesters[cqaNesters.Size() - 1],
+ 0,
+ 0,
+ &tkOuterImportRes));
+
+ // Compute the ResolutionScope for the imported type.
+ if (MvidAssemImport == MvidAssemEmit && MvidImport == MvidEmit)
+ {
+ *ptkType = trImport;
+ goto ErrExit;
+ }
+ else if (MvidAssemImport == MvidAssemEmit && MvidImport != MvidEmit)
+ {
+ // The TypeRef is in the same Assembly but a different module.
+
+ if (IsNilToken(tkOuterImportRes))
+ {
+ tkOuterEmitRes = tkOuterImportRes;
+ }
+ else if (TypeFromToken(tkOuterImportRes) == mdtModule)
+ {
+ // TypeRef resolved to the import module in which its defined.
+
+ //
+ if (pMiniMdAssemEmit == NULL && pCommonAssemImport == NULL)
+ {
+ tkOuterEmitRes = TokenFromRid(1, mdtModule);
+ }
+ else
+ {
+ // Create a ModuleRef corresponding to the import scope.
+ IfFailGo(CreateModuleRefFromScope(pMiniMdEmit,
+ pCommonImport,
+ &tkOuterEmitRes));
+ }
+ }
+ else if (TypeFromToken(tkOuterImportRes) == mdtAssemblyRef)
+ {
+ // TypeRef is from a different Assembly.
+
+ // Create a corresponding AssemblyRef in the emit scope.
+ IfFailGo(CreateAssemblyRefFromAssemblyRef(pMiniMdAssemEmit,
+ pMiniMdEmit,
+ pCommonImport,
+ tkOuterImportRes,
+ &tkOuterEmitRes));
+ }
+ else if (TypeFromToken(tkOuterImportRes) == mdtModuleRef)
+ {
+ // Get Name of the ModuleRef.
+ LPCUTF8 szMRName;
+ IfFailGo(pCommonImport->CommonGetModuleRefProps(tkOuterImportRes, &szMRName));
+
+ if (!strcmp(szMRName, szScopeNameEmit))
+ {
+ // ModuleRef from import scope resolves to the emit scope.
+ tkOuterEmitRes = TokenFromRid(1, mdtModule);
+ }
+ else
+ {
+ // ModuleRef does not correspond to the emit scope.
+ // Create a corresponding ModuleRef.
+ IfFailGo(CreateModuleRefFromModuleRef(pMiniMdEmit,
+ pCommonImport,
+ tkOuterImportRes,
+ &tkOuterEmitRes));
+ }
+ }
+ }
+ else if (MvidAssemImport != MvidAssemEmit)
+ {
+ // The TypeDef is from a different Assembly.
+
+ // Import and Emit scopes can't be identical and be from different
+ // Assemblies at the same time.
+ _ASSERTE(MvidImport != MvidEmit &&
+ "Import scope can't be identical to the Emit scope and be from a different Assembly at the same time.");
+
+ mdToken tkImplementation; // Implementation token for ExportedType.
+ if (IsNilToken(tkOuterImportRes))
+ {
+ // <REVISIT_TODO>BUG FIX:: URT 13626
+ // Well, before all of the clients generate AR for mscorlib.dll reference, it is not true
+ // that tkOuterImportRes == nil will imply that we have to find such an entry in the import manifest!!</REVISIT_TODO>
+
+ // Look for a ExportedType entry in the import Assembly. Its an error
+ // if we don't find a ExportedType entry.
+ mdExportedType tkExportedType;
+ hr = pCommonAssemImport->CommonFindExportedType(
+ cqaNesterNamespaces[cqaNesters.Size() - 1],
+ cqaNesterNames[cqaNesters.Size() - 1],
+ mdTokenNil,
+ &tkExportedType);
+ if (SUCCEEDED(hr))
+ {
+ IfFailGo(pCommonAssemImport->CommonGetExportedTypeProps(
+ tkExportedType,
+ NULL,
+ NULL,
+ &tkImplementation));
+ if (TypeFromToken(tkImplementation) == mdtFile)
+ {
+ // Type is from a different Assembly.
+ IfFailGo(CreateAssemblyRefFromAssembly(pMiniMdAssemEmit,
+ pMiniMdEmit,
+ pCommonAssemImport,
+ pbHashValue,
+ cbHashValue,
+ &tkOuterEmitRes));
+ }
+ else if (TypeFromToken(tkImplementation) == mdtAssemblyRef)
+ {
+ // This folds into the case where the Type is AssemblyRef. So
+ // let it fall through to that case.
+
+ // Remember that this AssemblyRef token is actually from the Manifest scope not
+ // the module scope!!!
+ bAssemblyRefFromAssemScope = true;
+ tkOuterImportRes = tkImplementation;
+ }
+ else
+ _ASSERTE(!"Unexpected ExportedType implementation token.");
+ }
+ else
+ {
+ // In this case, we will just move over the TypeRef with Nil ResolutionScope.
+ hr = NOERROR;
+ tkOuterEmitRes = mdTokenNil;
+ }
+ }
+ else if (TypeFromToken(tkOuterImportRes) == mdtModule)
+ {
+ // Type is from a different Assembly.
+ IfFailGo(CreateAssemblyRefFromAssembly(pMiniMdAssemEmit,
+ pMiniMdEmit,
+ pCommonAssemImport,
+ pbHashValue,
+ cbHashValue,
+ &tkOuterEmitRes));
+ }
+ // Not else if, because mdtModule case above could change
+ // tkOuterImportRes to an AssemblyRef.
+ if (TypeFromToken(tkOuterImportRes) == mdtAssemblyRef)
+ {
+ // If there is an emit assembly, see if the import assembly ref points to
+ // it. If there is no emit assembly, the import assembly, by definition,
+ // does not point to this one.
+ if (pMiniMdAssemEmit == NULL || !pMiniMdAssemEmit->getCountAssemblys())
+ hr = S_FALSE;
+ else
+ {
+ if (bAssemblyRefFromAssemScope)
+ {
+ // Check to see if the AssemblyRef resolves to the emit assembly.
+ IfFailGo(CompareAssemblyRefToAssembly(pCommonAssemImport,
+ tkOuterImportRes,
+ static_cast<IMetaModelCommon*>(pMiniMdAssemEmit)));
+
+ }
+ else
+ {
+ // Check to see if the AssemblyRef resolves to the emit assembly.
+ IfFailGo(CompareAssemblyRefToAssembly(pCommonImport,
+ tkOuterImportRes,
+ static_cast<IMetaModelCommon*>(pMiniMdAssemEmit)));
+ }
+ }
+ if (hr == S_OK)
+ {
+ // The TypeRef being imported is defined in the current Assembly.
+
+ // Find the ExportedType for the outermost TypeRef in the Emit assembly.
+ mdExportedType tkExportedType;
+
+ hr = FindExportedType(pMiniMdAssemEmit,
+ cqaNesterNamespaces[cqaNesters.Size() - 1],
+ cqaNesterNames[cqaNesters.Size() - 1],
+ mdTokenNil, // Enclosing ExportedType.
+ &tkExportedType);
+ if (hr == S_OK)
+ {
+ // Create a ModuleRef based on the File name for the ExportedType.
+ // If the ModuleRef corresponds to pMiniMdEmit, the function
+ // will return S_FALSE, in which case set tkOuterEmitRes to
+ // the Module token.
+ hr = CreateModuleRefFromExportedType(pMiniMdAssemEmit,
+ pMiniMdEmit,
+ tkExportedType,
+ &tkOuterEmitRes);
+ if (hr == S_FALSE)
+ tkOuterEmitRes = TokenFromRid(1, mdtModule);
+ else
+ IfFailGo(hr);
+ }
+ else if (hr == CLDB_E_RECORD_NOTFOUND)
+ {
+ // Find the Type in the Assembly emit scope to cover the
+ // case where ExportedTypes may be implicitly defined. Its an
+ // error if we can't find the Type at this point.
+ IfFailGo(FindTypeDefByName(pMiniMdAssemEmit,
+ cqaNesterNamespaces[cqaNesters.Size() - 1],
+ cqaNesterNames[cqaNesters.Size() - 1],
+ mdTokenNil, // Enclosing Type.
+ &tkOuterEmitRes));
+ tkOuterEmitRes = TokenFromRid(1, mdtModule);
+ }
+ else
+ {
+ _ASSERTE(FAILED(hr));
+ IfFailGo(hr);
+ }
+ }
+ else if (hr == S_FALSE)
+ {
+ // The TypeRef being imported is from a different Assembly.
+
+ if (bAssemblyRefFromAssemScope)
+ {
+ // Create a corresponding AssemblyRef.
+ IfFailGo(CreateAssemblyRefFromAssemblyRef(pMiniMdAssemEmit,
+ pMiniMdEmit,
+ pCommonAssemImport,
+ tkOuterImportRes,
+ &tkOuterEmitRes));
+ }
+ else
+ {
+ // Create a corresponding AssemblyRef.
+ IfFailGo(CreateAssemblyRefFromAssemblyRef(pMiniMdAssemEmit,
+ pMiniMdEmit,
+ pCommonImport,
+ tkOuterImportRes,
+ &tkOuterEmitRes));
+ }
+ }
+ else
+ {
+ _ASSERTE(FAILED(hr));
+ IfFailGo(hr);
+ }
+ }
+ else if (TypeFromToken(tkOuterImportRes) == mdtModuleRef)
+ {
+ // Type is from a different Assembly.
+ IfFailGo(CreateAssemblyRefFromAssembly(pMiniMdAssemEmit,
+ pMiniMdEmit,
+ pCommonAssemImport,
+ pbHashValue,
+ cbHashValue,
+ &tkOuterEmitRes));
+ }
+ }
+
+ // Try to find the TypeDef in the emit scope. If we cannot find the
+ // typedef, we need to introduce a typeref.
+
+ // See if the Nested TypeDef is present in the Emit scope.
+ hr = CLDB_E_RECORD_NOTFOUND;
+ if (TypeFromToken(tkOuterEmitRes) == mdtModule && !IsNilToken(tkOuterEmitRes))
+ {
+ hr = FindNestedTypeDef(pMiniMdEmit,
+ cqaNesterNamespaces,
+ cqaNesterNames,
+ mdTokenNil,
+ ptkType);
+
+ // <REVISIT_TODO>cannot assert now!! Due to the IJW workaround!
+ // _ASSERTE(SUCCEEDED(hr));</REVISIT_TODO>
+ }
+
+ if (hr == CLDB_E_RECORD_NOTFOUND)
+ {
+ IfFailGo(CreateNesterHierarchy(pMiniMdEmit,
+ cqaNesterNamespaces,
+ cqaNesterNames,
+ tkOuterEmitRes,
+ ptkType));
+ }
+ else
+ IfFailGo(hr);
+ErrExit:
+ return hr;
+} // ImportHelper::ImportTypeRef
+
+//******************************************************************************
+// Given import scope, create a corresponding ModuleRef.
+//******************************************************************************
+HRESULT ImportHelper::CreateModuleRefFromScope( // S_OK or error.
+ CMiniMdRW *pMiniMdEmit, // [IN] Emit scope in which the ModuleRef is to be created.
+ IMetaModelCommon *pCommonImport, // [IN] Import scope.
+ mdModuleRef *ptkModuleRef) // [OUT] Output token for ModuleRef.
+{
+ HRESULT hr = S_OK;
+ LPCSTR szName;
+ ModuleRefRec *pRecordEmit;
+ RID iRecordEmit;
+
+ // Set output to nil.
+ *ptkModuleRef = mdTokenNil;
+
+ // Get name of import scope.
+ IfFailGo(pCommonImport->CommonGetScopeProps(&szName, 0));
+
+ // See if the ModuleRef exists in the Emit scope.
+ hr = FindModuleRef(pMiniMdEmit, szName, ptkModuleRef);
+
+ if (hr == CLDB_E_RECORD_NOTFOUND)
+ {
+ if (szName[0] == '\0')
+ {
+ // It the referenced Module does not have a proper name, use the nil token instead.
+ LOG((LOGMD, "WARNING!!! MD ImportHelper::CreatemoduleRefFromScope but scope does not have a proper name!!!!"));
+
+ // clear the error
+ hr = NOERROR;
+
+ // It is a bug to create an ModuleRef to an empty name!!!
+ *ptkModuleRef = mdTokenNil;
+ }
+ else
+ {
+ // Create ModuleRef record and set the output parameter.
+ IfFailGo(pMiniMdEmit->AddModuleRefRecord(&pRecordEmit, &iRecordEmit));
+ *ptkModuleRef = TokenFromRid(iRecordEmit, mdtModuleRef);
+ IfFailGo(pMiniMdEmit->UpdateENCLog(*ptkModuleRef));
+
+ // It is a bug to create an ModuleRef to mscorlib.dll
+ _ASSERTE(strcmp(szName, COM_RUNTIME_LIBRARY) != 0);
+
+ // Set the name of ModuleRef.
+ IfFailGo(pMiniMdEmit->PutString(TBL_ModuleRef, ModuleRefRec::COL_Name,
+ pRecordEmit, szName));
+ }
+ }
+ else
+ IfFailGo(hr);
+ErrExit:
+ return hr;
+} // ImportHelper::CreateModuleRefFromScope
+
+
+//******************************************************************************
+// Given an import scope and a ModuleRef, create a corresponding ModuleRef in
+// the given emit scope.
+//******************************************************************************
+HRESULT ImportHelper::CreateModuleRefFromModuleRef( // S_OK or error.
+ CMiniMdRW *pMiniMdEmit, // [IN] Emit scope.
+ IMetaModelCommon *pCommon, // [IN] Import scope.
+ mdModuleRef tkModuleRef, // [IN] ModuleRef token.
+ mdModuleRef *ptkModuleRef) // [OUT] ModuleRef token in the emit scope.
+{
+ HRESULT hr = S_OK;
+ LPCSTR szName;
+ ModuleRefRec *pRecord;
+ RID iRecord;
+
+ // Set output to Nil.
+ *ptkModuleRef = mdTokenNil;
+
+ // Get name of the ModuleRef being imported.
+ IfFailGo(pCommon->CommonGetModuleRefProps(tkModuleRef, &szName));
+
+ // See if the ModuleRef exist in the Emit scope.
+ hr = FindModuleRef(pMiniMdEmit, szName, ptkModuleRef);
+
+ if (hr == CLDB_E_RECORD_NOTFOUND)
+ {
+ // Create ModuleRef record and set the output parameter.
+ IfFailGo(pMiniMdEmit->AddModuleRefRecord(&pRecord, &iRecord));
+ *ptkModuleRef = TokenFromRid(iRecord, mdtModuleRef);
+ IfFailGo(pMiniMdEmit->UpdateENCLog(*ptkModuleRef));
+
+ // Set the name of ModuleRef.
+ IfFailGo(pMiniMdEmit->PutString(TBL_ModuleRef, ModuleRefRec::COL_Name,
+ pRecord, szName));
+ }
+ else
+ {
+ IfFailGo(hr);
+ }
+ErrExit:
+ return hr;
+} // ImportHelper::CreateModuleRefFromModuleRef
+
+
+//******************************************************************************
+// Given a ExportedType and the Assembly emit scope, create a corresponding ModuleRef
+// in the give emit scope. The ExportedType being passed in must belong to the
+// Assembly passed in. Function returns S_FALSE if the ExportedType is implemented
+// by the emit scope passed in.
+//******************************************************************************
+HRESULT ImportHelper::CreateModuleRefFromExportedType( // S_OK or error.
+ CMiniMdRW *pAssemEmit, // [IN] Import assembly scope.
+ CMiniMdRW *pMiniMdEmit, // [IN] Emit scope.
+ mdExportedType tkExportedType, // [IN] ExportedType token in Assembly emit scope.
+ mdModuleRef *ptkModuleRef) // [OUT] ModuleRef token in the emit scope.
+{
+ mdFile tkFile;
+ LPCUTF8 szFile;
+ LPCUTF8 szScope;
+ FileRec *pFileRec;
+ HRESULT hr = S_OK;
+
+ // Set output to nil.
+ *ptkModuleRef = mdTokenNil;
+
+ // Get the implementation token for the ExportedType. It must be a File token
+ // since the caller should call this function only on ExportedTypes that resolve
+ // to the same Assembly.
+ IfFailGo(static_cast<IMetaModelCommon*>(pAssemEmit)->CommonGetExportedTypeProps(
+ tkExportedType,
+ NULL,
+ NULL,
+ &tkFile));
+ _ASSERTE(TypeFromToken(tkFile) == mdtFile);
+
+ // Get the name of the file.
+ IfFailGo(pAssemEmit->GetFileRecord(RidFromToken(tkFile), &pFileRec));
+ IfFailGo(pAssemEmit->getNameOfFile(pFileRec, &szFile));
+
+ // Get the name of the emit scope.
+ IfFailGo(static_cast<IMetaModelCommon*>(pMiniMdEmit)->CommonGetScopeProps(
+ &szScope,
+ 0));
+
+ // If the file corresponds to the emit scope, return S_FALSE;
+ if (!strcmp(szFile, szScope))
+ return S_FALSE;
+
+ // See if a ModuleRef exists with this name.
+ hr = FindModuleRef(pMiniMdEmit, szFile, ptkModuleRef);
+
+ if (hr == CLDB_E_RECORD_NOTFOUND)
+ {
+ // Create ModuleRef record and set the output parameter.
+
+ ModuleRefRec *pRecord;
+ RID iRecord;
+
+ IfFailGo(pMiniMdEmit->AddModuleRefRecord(&pRecord, &iRecord));
+ *ptkModuleRef = TokenFromRid(iRecord, mdtModuleRef);
+ IfFailGo(pMiniMdEmit->UpdateENCLog(*ptkModuleRef));
+
+ // Set the name of ModuleRef.
+ IfFailGo(pMiniMdEmit->PutString(TBL_ModuleRef, ModuleRefRec::COL_Name,
+ pRecord, szFile));
+ }
+ else
+ IfFailGo(hr);
+ErrExit:
+ return hr;
+} // ImportHelper::CreateModuleRefFromExportedType
+
+//******************************************************************************
+// Given an AssemblyRef and the corresponding scope, create an AssemblyRef in
+// the given Module scope and Assembly scope.
+//******************************************************************************
+HRESULT ImportHelper::CreateAssemblyRefFromAssemblyRef(
+ CMiniMdRW *pMiniMdAssemEmit, // [IN] Assembly emit scope.
+ CMiniMdRW *pMiniMdModuleEmit, // [IN] Module emit scope
+ IMetaModelCommon *pCommonImport, // [IN] Scope to import the assembly ref from.
+ mdAssemblyRef tkAssemRef, // [IN] Assembly ref to be imported.
+ mdAssemblyRef *ptkAssemblyRef) // [OUT] AssemblyRef in the emit scope.
+{
+ AssemblyRefRec *pRecordEmit;
+ CMiniMdRW *rMiniMdRW[2];
+ CMiniMdRW *pMiniMdEmit;
+ RID iRecordEmit;
+ USHORT usMajorVersion;
+ USHORT usMinorVersion;
+ USHORT usBuildNumber;
+ USHORT usRevisionNumber;
+ DWORD dwFlags;
+ const void *pbPublicKeyOrToken;
+ ULONG cbPublicKeyOrToken;
+ LPCUTF8 szName;
+ LPCUTF8 szLocale;
+ const void *pbHashValue;
+ ULONG cbHashValue;
+ HRESULT hr = S_OK;
+
+ // Set output to Nil.
+ *ptkAssemblyRef = mdTokenNil;
+
+ // Get import AssemblyRef props.
+ IfFailGo(pCommonImport->CommonGetAssemblyRefProps(
+ tkAssemRef,
+ &usMajorVersion, &usMinorVersion, &usBuildNumber, &usRevisionNumber,
+ &dwFlags, &pbPublicKeyOrToken, &cbPublicKeyOrToken,
+ &szName, &szLocale,
+ &pbHashValue, &cbHashValue));
+
+ // Create the AssemblyRef in both the Assembly and Module emit scopes.
+ rMiniMdRW[0] = pMiniMdAssemEmit;
+ rMiniMdRW[1] = pMiniMdModuleEmit;
+
+ for (ULONG i = 0; i < 2; i++)
+ {
+ pMiniMdEmit = rMiniMdRW[i];
+
+ if (!pMiniMdEmit)
+ continue;
+
+ // See if the AssemblyRef already exists in the emit scope.
+ hr = FindAssemblyRef(pMiniMdEmit, szName, szLocale, pbPublicKeyOrToken,
+ cbPublicKeyOrToken, usMajorVersion, usMinorVersion,
+ usBuildNumber, usRevisionNumber, dwFlags, &tkAssemRef);
+ if (hr == CLDB_E_RECORD_NOTFOUND)
+ {
+ // Create the AssemblyRef record and set the output parameter.
+ IfFailGo(pMiniMdEmit->AddAssemblyRefRecord(&pRecordEmit, &iRecordEmit));
+ tkAssemRef = TokenFromRid(iRecordEmit, mdtAssemblyRef);
+ IfFailGo(pMiniMdEmit->UpdateENCLog(tkAssemRef));
+
+ // Set parameters derived from the import Assembly.
+ pRecordEmit->SetMajorVersion(usMajorVersion);
+ pRecordEmit->SetMinorVersion(usMinorVersion);
+ pRecordEmit->SetBuildNumber(usBuildNumber);
+ pRecordEmit->SetRevisionNumber(usRevisionNumber);
+ pRecordEmit->SetFlags(dwFlags);
+
+ IfFailGo(pMiniMdEmit->PutBlob(TBL_AssemblyRef, AssemblyRefRec::COL_PublicKeyOrToken,
+ pRecordEmit, pbPublicKeyOrToken, cbPublicKeyOrToken));
+ IfFailGo(pMiniMdEmit->PutString(TBL_AssemblyRef, AssemblyRefRec::COL_Name,
+ pRecordEmit, szName));
+ IfFailGo(pMiniMdEmit->PutString(TBL_AssemblyRef, AssemblyRefRec::COL_Locale,
+ pRecordEmit, szLocale));
+
+ // Set the parameters passed in for the AssemblyRef.
+ IfFailGo(pMiniMdEmit->PutBlob(TBL_AssemblyRef, AssemblyRefRec::COL_HashValue,
+ pRecordEmit, pbHashValue, cbHashValue));
+ }
+ else
+ IfFailGo(hr);
+
+ // Set the output parameter for the AssemblyRef emitted in Module emit scope.
+ if (i)
+ *ptkAssemblyRef = tkAssemRef;
+ }
+ErrExit:
+ return hr;
+} // ImportHelper::CreateAssemblyRefFromAssemblyRef
+
+//******************************************************************************
+// Given the Assembly Import scope, hash value and execution location, create
+// a corresponding AssemblyRef in the given assembly and module emit scope.
+// Set the output parameter to the AssemblyRef token emitted in the module emit
+// scope.
+//******************************************************************************
+HRESULT
+ImportHelper::CreateAssemblyRefFromAssembly(
+ CMiniMdRW * pMiniMdAssemEmit, // [IN] Emit assembly scope.
+ CMiniMdRW * pMiniMdModuleEmit, // [IN] Emit module scope.
+ IMetaModelCommon * pCommonAssemImport, // [IN] Assembly import scope.
+ const void * pbHashValue, // [IN] Hash Blob for Assembly.
+ ULONG cbHashValue, // [IN] Count of bytes.
+ mdAssemblyRef * ptkAssemblyRef) // [OUT] AssemblyRef token.
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ AssemblyRefRec *pRecordEmit;
+ CMiniMdRW *rMiniMdRW[2];
+ CMiniMdRW *pMiniMdEmit;
+ RID iRecordEmit;
+ USHORT usMajorVersion;
+ USHORT usMinorVersion;
+ USHORT usBuildNumber;
+ USHORT usRevisionNumber;
+ DWORD dwFlags;
+ const void *pbPublicKey;
+ ULONG cbPublicKey;
+ LPCUTF8 szName;
+ LPCUTF8 szLocale;
+ mdAssemblyRef tkAssemRef;
+ HRESULT hr = S_OK;
+ const void *pbToken = NULL;
+ ULONG cbToken = 0;
+ ULONG i;
+
+ // Set output to Nil.
+ *ptkAssemblyRef = mdTokenNil;
+
+ // Get the Assembly props.
+ IfFailGo(pCommonAssemImport->CommonGetAssemblyProps(
+ &usMajorVersion, &usMinorVersion, &usBuildNumber, &usRevisionNumber,
+ &dwFlags, &pbPublicKey, &cbPublicKey,
+ &szName, &szLocale));
+
+ // Compress the public key into a token.
+ if ((pbPublicKey != NULL) && (cbPublicKey != 0))
+ {
+ _ASSERTE(IsAfPublicKey(dwFlags));
+ dwFlags &= ~afPublicKey;
+ if (!StrongNameTokenFromPublicKey((BYTE*)pbPublicKey,
+ cbPublicKey,
+ (BYTE**)&pbToken,
+ &cbToken))
+ IfFailGo(StrongNameErrorInfo());
+ }
+ else
+ _ASSERTE(!IsAfPublicKey(dwFlags));
+
+ // Create the AssemblyRef in both the Assembly and Module emit scopes.
+ rMiniMdRW[0] = pMiniMdAssemEmit;
+ rMiniMdRW[1] = pMiniMdModuleEmit;
+
+ for (i = 0; i < 2; i++)
+ {
+ pMiniMdEmit = rMiniMdRW[i];
+
+ if (!pMiniMdEmit)
+ continue;
+
+ // See if the AssemblyRef already exists in the emit scope.
+ hr = FindAssemblyRef(pMiniMdEmit, szName, szLocale, pbToken,
+ cbToken, usMajorVersion, usMinorVersion,
+ usBuildNumber, usRevisionNumber, dwFlags,
+ &tkAssemRef);
+ if (hr == CLDB_E_RECORD_NOTFOUND)
+ {
+ // Create the AssemblyRef record and set the output parameter.
+ IfFailGo(pMiniMdEmit->AddAssemblyRefRecord(&pRecordEmit, &iRecordEmit));
+ tkAssemRef = TokenFromRid(iRecordEmit, mdtAssemblyRef);
+ IfFailGo(pMiniMdEmit->UpdateENCLog(tkAssemRef));
+
+ // Set parameters derived from the import Assembly.
+ pRecordEmit->SetMajorVersion(usMajorVersion);
+ pRecordEmit->SetMinorVersion(usMinorVersion);
+ pRecordEmit->SetBuildNumber(usBuildNumber);
+ pRecordEmit->SetRevisionNumber(usRevisionNumber);
+ pRecordEmit->SetFlags(dwFlags);
+
+ IfFailGo(pMiniMdEmit->PutBlob(TBL_AssemblyRef, AssemblyRefRec::COL_PublicKeyOrToken,
+ pRecordEmit, pbToken, cbToken));
+ IfFailGo(pMiniMdEmit->PutString(TBL_AssemblyRef, AssemblyRefRec::COL_Name,
+ pRecordEmit, szName));
+ IfFailGo(pMiniMdEmit->PutString(TBL_AssemblyRef, AssemblyRefRec::COL_Locale,
+ pRecordEmit, szLocale));
+
+ // Set the parameters passed in for the AssemblyRef.
+ IfFailGo(pMiniMdEmit->PutBlob(TBL_AssemblyRef, AssemblyRefRec::COL_HashValue,
+ pRecordEmit, pbHashValue, cbHashValue));
+ }
+ else
+ IfFailGo(hr);
+
+ // Set the output parameter for the AssemblyRef emitted in Module emit scope.
+ if (i)
+ *ptkAssemblyRef = tkAssemRef;
+ }
+ErrExit:
+ if (pbToken)
+ StrongNameFreeBuffer((BYTE*)pbToken);
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // ImportHelper::CreateAssemblyRefFromAssembly
+
+//******************************************************************************
+// Given an AssemblyRef and the corresponding scope, compare it to see if it
+// refers to the given Assembly.
+//******************************************************************************
+HRESULT ImportHelper::CompareAssemblyRefToAssembly( // S_OK, S_FALSE or error.
+ IMetaModelCommon *pCommonAssem1, // [IN] Scope that defines the AssemblyRef.
+ mdAssemblyRef tkAssemRef, // [IN] AssemblyRef.
+ IMetaModelCommon *pCommonAssem2) // [IN] Assembly against which the Ref is compared.
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr;
+
+ USHORT usMajorVersion1;
+ USHORT usMinorVersion1;
+ USHORT usBuildNumber1;
+ USHORT usRevisionNumber1;
+ const void *pbPublicKeyOrToken1;
+ ULONG cbPublicKeyOrToken1;
+ LPCUTF8 szName1;
+ LPCUTF8 szLocale1;
+ DWORD dwFlags1;
+
+ USHORT usMajorVersion2;
+ USHORT usMinorVersion2;
+ USHORT usBuildNumber2;
+ USHORT usRevisionNumber2;
+ const void *pbPublicKey2;
+ ULONG cbPublicKey2;
+ LPCUTF8 szName2;
+ LPCUTF8 szLocale2;
+ const void *pbToken = NULL;
+ ULONG cbToken = 0;
+ bool fMatch;
+
+ // Get the AssemblyRef props.
+ IfFailRet(pCommonAssem1->CommonGetAssemblyRefProps(
+ tkAssemRef,
+ &usMajorVersion1, &usMinorVersion1, &usBuildNumber1, &usRevisionNumber1,
+ &dwFlags1, &pbPublicKeyOrToken1, &cbPublicKeyOrToken1,
+ &szName1, &szLocale1,
+ NULL, NULL));
+ // Get the Assembly props.
+ IfFailRet(pCommonAssem2->CommonGetAssemblyProps(
+ &usMajorVersion2, &usMinorVersion2, &usBuildNumber2, &usRevisionNumber2,
+ 0, &pbPublicKey2, &cbPublicKey2,
+ &szName2, &szLocale2));
+
+ // Compare.
+ if (usMajorVersion1 != usMajorVersion2 ||
+ usMinorVersion1 != usMinorVersion2 ||
+ usBuildNumber1 != usBuildNumber2 ||
+ usRevisionNumber1 != usRevisionNumber2 ||
+ strcmp(szName1, szName2) ||
+ strcmp(szLocale1, szLocale2))
+ {
+ return S_FALSE;
+ }
+
+ // Defs always contain a full public key (or no key at all). Refs may have
+ // no key, a full public key or a tokenized key.
+ if ((cbPublicKeyOrToken1 && !cbPublicKey2) ||
+ (!cbPublicKeyOrToken1 && cbPublicKey2))
+ return S_FALSE;
+
+ if (cbPublicKeyOrToken1)
+ {
+ // If ref contains a full public key we can just directly compare.
+ if (IsAfPublicKey(dwFlags1) &&
+ (cbPublicKeyOrToken1 != cbPublicKey2 ||
+ memcmp(pbPublicKeyOrToken1, pbPublicKey2, cbPublicKeyOrToken1)))
+ return S_FALSE;
+
+ // Otherwise we need to compress the def public key into a token.
+ if (!StrongNameTokenFromPublicKey((BYTE*)pbPublicKey2,
+ cbPublicKey2,
+ (BYTE**)&pbToken,
+ &cbToken))
+ return StrongNameErrorInfo();
+
+ fMatch = cbPublicKeyOrToken1 == cbToken &&
+ !memcmp(pbPublicKeyOrToken1, pbToken, cbPublicKeyOrToken1);
+
+ StrongNameFreeBuffer((BYTE*)pbToken);
+
+ if (!fMatch)
+ return S_FALSE;
+ }
+
+ return S_OK;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // ImportHelper::CompareAssemblyRefToAssembly
+
+#endif //FEATURE_METADATA_EMIT
diff --git a/src/md/compiler/importhelper.h b/src/md/compiler/importhelper.h
new file mode 100644
index 0000000000..ea152f53ef
--- /dev/null
+++ b/src/md/compiler/importhelper.h
@@ -0,0 +1,368 @@
+// 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.
+//*****************************************************************************
+// ImportHelper.h
+//
+
+//
+// contains utility code to MD directory
+//
+//*****************************************************************************
+#ifndef __IMPORTHELPER__h__
+#define __IMPORTHELPER__h__
+
+class CMiniMdRW;
+class MDTOKENMAP;
+
+//*********************************************************************
+// Class to handle merge
+//*********************************************************************
+class ImportHelper
+{
+public:
+ // Options for code:FindMemberRef.
+ enum HashSearchOption
+ {
+ DoNotCreateHash, // Do not create hash if it does not exist (faster for isolated calls)
+ CreateHash // Create hash if it does not exist (faster for multiple calls)
+ };
+
+
+ static HRESULT FindMethodSpecByMethodAndInstantiation(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ /*mdMethodDefOrRef*/ mdToken tkMethod, // [IN] MethodSpec method field
+ PCCOR_SIGNATURE pInstantiation, // [IN] MethodSpec instantiation (a signature)
+ ULONG cbInstantiation, // [IN] Size of instantiation.
+ mdMethodSpec *pMethodSpec, // [OUT] Put the MethodSpec token here.
+ RID rid = 0); // [IN] Optional rid to be ignored.
+
+
+ static HRESULT FindGenericParamConstraintByOwnerAndConstraint(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ mdGenericParam tkOwner, // [IN] GenericParamConstraint Owner
+ mdToken tkConstraint, // [IN] GenericParamConstraint Constraint
+ mdGenericParamConstraint *pGenericParamConstraint, // [OUT] Put the GenericParamConstraint token here.
+ RID rid = 0); // [IN] Optional rid to be ignored.
+
+
+ static HRESULT FindGenericParamByOwner(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ mdToken tkOwner, // [IN] GenericParam Owner
+ LPCUTF8 szUTF8Name, // [IN] GeneriParam Name, may be NULL if not used for search
+ ULONG *pNumber, // [IN] GeneriParam Number, may be NULL if not used for search
+ mdGenericParam *pGenericParam, // [OUT] Put the GenericParam token here.
+ RID rid = 0); // [IN] Optional rid to be ignored.
+
+ static HRESULT FindMethod(
+ CMiniMdRW * pMiniMd, // [IN] the minimd to lookup
+ mdTypeDef td, // [IN] parent.
+ LPCUTF8 szName, // [IN] MethodDef name.
+ PCCOR_SIGNATURE pSig, // [IN] Signature.
+ ULONG cbSig, // [IN] Size of signature.
+ mdMethodDef * pmb, // [OUT] Put the MethodDef token here.
+ RID rid = 0, // [IN] Optional rid to be ignored.
+ PSIGCOMPARE pSignatureCompare = NULL, // [IN] Optional Routine to compare signatures
+ void * pCompareContext = NULL); // [IN] Optional context for the compare function
+
+ static HRESULT FindField(
+ CMiniMdRW * pMiniMd, // [IN] the minimd to lookup
+ mdTypeDef td, // [IN] parent.
+ LPCUTF8 szName, // [IN] FieldDef name.
+ PCCOR_SIGNATURE pSig, // [IN] Signature.
+ ULONG cbSig, // [IN] Size of signature.
+ mdFieldDef * pfd, // [OUT] Put the FieldDef token here.
+ RID rid = 0); // [IN] Optional rid to be ignored.
+
+ static HRESULT FindMember(
+ CMiniMdRW * pMiniMd, // [IN] the minimd to lookup
+ mdTypeDef td, // [IN] parent.
+ LPCUTF8 szName, // [IN] Member name.
+ PCCOR_SIGNATURE pSig, // [IN] Signature.
+ ULONG cbSig, // [IN] Size of signature.
+ mdToken * ptk); // [OUT] Put the token here.
+
+ static HRESULT FindMemberRef(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ mdToken tkParent, // [IN] the parent token
+ LPCUTF8 szName, // [IN] memberref name
+ const COR_SIGNATURE *pSig, // [IN] Signature.
+ ULONG cbSig, // [IN] Size of signature.
+ mdMemberRef *pmr, // [OUT] Put the MemberRef token found
+ RID rid = 0, // [IN] Optional rid to be ignored.
+ HashSearchOption fCreateHash = DoNotCreateHash); // [IN] Should we create hash first? (Optimize for multiple calls vs. single isolated call)
+
+ static HRESULT FindStandAloneSig(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ const COR_SIGNATURE *pbSig, // [IN] Signature.
+ ULONG cbSig, // [IN] Size of signature.
+ mdSignature *psa); // [OUT] Put the StandAloneSig token found
+
+ static HRESULT FindTypeSpec(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ const COR_SIGNATURE *pbSig, // [IN] Signature.
+ ULONG cbSig, // [IN] Size of signature.
+ mdTypeSpec *ptypespec); // [OUT] Put the TypeSpec token found
+
+ static HRESULT FindMethodImpl(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ mdTypeDef tkClass, // [IN] The parent TypeDef token.
+ mdToken tkBody, // [IN] Method body token.
+ mdToken tkDecl, // [IN] Method declaration token.
+ RID *pRid); // [OUT] Put the MethodImpl rid here
+
+ static HRESULT FindCustomAttributeCtorByName(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ LPCUTF8 szAssemblyName, // [IN] Assembly Name.
+ LPCUTF8 szNamespace, // [IN] TypeRef Namespace.
+ LPCUTF8 szName, // [IN] TypeRef Name.
+ mdTypeDef *ptk, // [OUT] Put the TypeRef token here.
+ RID rid = 0); // [IN] Optional rid to be ignored.
+
+ static HRESULT FindTypeRefByName(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ mdToken tkResolutionScope, // [IN] ResolutionScope, mdAssemblyRef or mdModuleRef.
+ LPCUTF8 szNamespace, // [IN] TypeRef Namespace.
+ LPCUTF8 szName, // [IN] TypeRef Name.
+ mdTypeDef *ptk, // [OUT] Put the TypeRef token here.
+ RID rid = 0); // [IN] Optional rid to be ignored.
+
+ static HRESULT FindModuleRef(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ LPCUTF8 szUTF8Name, // [IN] ModuleRef name.
+ mdModuleRef *pmur, // [OUT] Put the ModuleRef token here.
+ RID rid = 0); // [IN] Optional rid to be ignored.
+
+ static HRESULT FindTypeDefByName(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ LPCUTF8 szNamespace, // [IN] Namespace of the TypeDef.
+ LPCUTF8 szName, // [IN] Name of the TypeDef.
+ mdToken tkEnclosingClass, // [IN] TypeDef/TypeRef enclosing class.
+ mdTypeDef *ptk, // [OUT] Put the TypeDef token here.
+ RID rid = 0); // [IN] Optional rid to be ignored.
+
+ static HRESULT FindInterfaceImpl(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ mdToken tkClass, // [IN] TypeDef of the type
+ mdToken tkInterface, // [IN] could be typedef/typeref
+ mdInterfaceImpl *ptk, // [OUT] Put the interface token here.
+ RID rid = 0); // [IN] Optional rid to be ignored.
+
+ static HRESULT FindPermission(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ mdToken tkParent, // [IN] Token with the Permission
+ USHORT usAction, // [IN] The action of the permission
+ mdPermission *ppm); // [OUT] Put permission token here
+
+ static HRESULT FindProperty(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ mdToken tkTypeDef, // [IN] typedef token
+ LPCUTF8 szName, // [IN] name of the property
+ const COR_SIGNATURE *pbSig, // [IN] Signature.
+ ULONG cbSig, // [IN] Size of signature.
+ mdProperty *ppr); // [OUT] Property token
+
+ static HRESULT FindEvent(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ mdToken tkTypeDef, // [IN] typedef token
+ LPCUTF8 szName, // [IN] name of the event
+ mdProperty *pev); // [OUT] Event token
+
+ static HRESULT FindCustomAttributeByToken(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ mdToken tkParent, // [IN] the parent that custom value is associated with
+ mdToken tkType, // [IN] type of the CustomAttribute
+ const void *pCustBlob, // [IN] custom value blob
+ ULONG cbCustBlob, // [IN] size of the blob.
+ mdCustomAttribute *pcv); // [OUT] CustomAttribute token
+
+ static HRESULT GetCustomAttributeByName(// S_OK or error.
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ 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.
+
+ static HRESULT GetCustomAttributeByName(// S_OK or error.
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ mdToken tkObj, // [IN] Object with Custom Attribute.
+ LPCUTF8 szName, // [IN] Name of desired Custom Attribute.
+ mdCustomAttribute pca); // [OUT] found CA token
+
+ static HRESULT MergeUpdateTokenInFieldSig(
+ CMiniMdRW *pMiniMdAssemEmit, // [IN] The assembly emit scope.
+ CMiniMdRW *pMiniMdEmit, // [IN] The emit scope.
+ IMetaModelCommon *pCommonAssemImport, // [IN] Assembly scope where the signature is from.
+ const void *pbHashValue, // [IN] Hash value for the import assembly.
+ ULONG cbHashValue, // [IN] Size in bytes for the hash value.
+ IMetaModelCommon *pCommonImport, // [IN] The scope to merge into the emit scope.
+ PCCOR_SIGNATURE pbSigImp, // [IN] signature from the imported scope
+ MDTOKENMAP *ptkMap, // [IN] Internal OID mapping structure.
+ CQuickBytes *pqkSigEmit, // [OUT] buffer for translated signature
+ ULONG cbStartEmit, // [IN] start point of buffer to write to
+ ULONG *pcbImp, // [OUT] total number of bytes consumed from pbSigImp
+ ULONG *pcbEmit); // [OUT] total number of bytes write to pqkSigEmit
+
+ static HRESULT MergeUpdateTokenInSig( // S_OK or error.
+ CMiniMdRW *pMiniMdAssemEmit, // [IN] The assembly emit scope.
+ CMiniMdRW *pMiniMdEmit, // [IN] The emit scope.
+ IMetaModelCommon *pCommonAssemImport, // [IN] Assembly scope where the signature is from.
+ const void *pbHashValue, // [IN] Hash value for the import assembly.
+ ULONG cbHashValue, // [IN] Size in bytes for the hash value.
+ IMetaModelCommon *pCommonImport, // [IN] The scope to merge into the emit scope.
+ PCCOR_SIGNATURE pbSigImp, // [IN] signature from the imported scope
+ MDTOKENMAP *ptkMap, // [IN] Internal OID mapping structure.
+ CQuickBytes *pqkSigEmit, // [OUT] translated signature
+ ULONG cbStartEmit, // [IN] start point of buffer to write to
+ ULONG *pcbImp, // [OUT] total number of bytes consumed from pbSigImp
+ ULONG *pcbEmit); // [OUT] total number of bytes write to pqkSigEmit
+
+ // This is implemented in a satellite lib because it is only used in emit and depends on
+ // strong name support in mscorwks.dll.
+ static HRESULT FindAssemblyRef(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup.
+ LPCUTF8 szName, // [IN] Name.
+ LPCUTF8 szLocale, // [IN] Locale.
+ const void *pbPublicKeyOrToken, // [IN] Public key or token (based on flags).
+ ULONG cbPublicKeyOrToken, // [IN] Byte count of public key or token.
+ USHORT usMajorVersion, // [IN] Major version.
+ USHORT usMinorVersion, // [IN] Minor version.
+ USHORT usBuildNumber, // [IN] Build number.
+ USHORT usRevisionNumber, // [IN] Revision number.
+ DWORD dwFlags, // [IN] Flags.
+ mdAssemblyRef *pmar); // [OUT] returned AssemblyRef token.
+
+ static HRESULT FindFile(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup.
+ LPCUTF8 szName, // [IN] name for the File.
+ mdFile *pmf, // [OUT] returned File token.
+ RID rid = 0); // [IN] Optional rid to be ignored.
+
+ static HRESULT FindExportedType(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup.
+ LPCUTF8 szNamespace, // [IN] namespace for the ExportedType.
+ LPCUTF8 szName, // [IN] name for the ExportedType.
+ mdExportedType tkEnclosingType, // [IN] enclosing ExportedType token.
+ mdExportedType *pmct, // [OUT] returned ExportedType token.
+ RID rid = 0); // [IN] Optional rid to be ignored.
+
+ static HRESULT FindManifestResource(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup.
+ LPCUTF8 szName, // [IN] name for the ManifestResource.
+ mdManifestResource *pmmr, // [OUT] returned ManifestResource token.
+ RID rid = 0); // [IN] Optional rid to be ignored.
+
+ static HRESULT GetNesterHierarchy(
+ IMetaModelCommon *pCommon, // Scope in which to find the hierarchy.
+ mdTypeDef td, // TypeDef whose hierarchy is needed.
+ CQuickArray<mdTypeDef> &cqaTdNesters, // Array of Nesters.
+ CQuickArray<LPCUTF8> &cqaNamespaces, // Namespaces of the nesters.
+ CQuickArray<LPCUTF8> &cqaNames); // Names of the nesters.
+
+ static HRESULT FindNestedTypeRef(
+ CMiniMdRW *pMiniMd, // [IN] Scope in which to find the TypeRef.
+ CQuickArray<LPCUTF8> &cqaNesterNamespaces, // [IN] Array of Namespaces.
+ CQuickArray<LPCUTF8> &cqaNesterNames, // [IN] Array of Names.
+ mdToken tkResolutionScope, // [IN] Resolution scope for the outermost TypeRef.
+ mdTypeRef *ptr); // [OUT] Inner most TypeRef token.
+
+ static HRESULT FindNestedTypeDef(
+ CMiniMdRW *pMiniMd, // [IN] Scope in which to find the TypeRef.
+ CQuickArray<LPCUTF8> &cqaNesterNamespaces, // [IN] Array of Namespaces.
+ CQuickArray<LPCUTF8> &cqaNesterNames, // [IN] Array of Names.
+ mdTypeDef tdNester, // [IN] Enclosing class for the Outermost TypeDef.
+ mdTypeDef *ptd); // [OUT] Inner most TypeRef token.
+
+ static HRESULT CreateNesterHierarchy(
+ CMiniMdRW *pMiniMdEmit, // [IN] Emit scope to create the Nesters in.
+ CQuickArray<LPCUTF8> &cqaNesterNamespaces, // [IN] Array of Nester namespaces.
+ CQuickArray<LPCUTF8> &cqaNesterNames, // [IN] Array of Nester names.
+ mdToken tkResolutionScope, // [IN] ResolutionScope for the innermost TypeRef.
+ mdTypeRef *ptr); // [OUT] Token for the innermost TypeRef.
+
+ static HRESULT ImportTypeDef(
+ CMiniMdRW *pMiniMdAssemEmit, // [IN] Assembly emit scope.
+ CMiniMdRW *pMiniMdEmit, // [IN] Module emit scope.
+ IMetaModelCommon *pCommonAssemImport, // [IN] Assembly import scope.
+ const void *pbHashValue, // [IN] Hash value for import assembly.
+ ULONG cbHashValue, // [IN] Size in bytes of hash value.
+ IMetaModelCommon *pCommonImport, // [IN] Module import scope.
+ mdTypeDef tdImport, // [IN] Imported TypeDef.
+ bool bReturnTd, // [IN] If the import and emit scopes are identical, return the TypeDef.
+ mdToken *ptkType); // [OUT] Output token for the imported type in the emit scope.
+
+ static HRESULT ImportTypeRef(
+ CMiniMdRW *pMiniMdAssemEmit, // [IN] Assembly emit scope.
+ CMiniMdRW *pMiniMdEmit, // [IN] Module emit scope.
+ IMetaModelCommon *pCommonAssemImport, // [IN] Assembly import scope.
+ const void *pbHashValue, // [IN] Hash value for import assembly.
+ ULONG cbHashValue, // [IN] Size in bytes of hash value.
+ IMetaModelCommon *pCommonImport, // [IN] Module import scope.
+ mdTypeRef trImport, // [IN] Imported TypeRef.
+ mdToken *ptkType); // [OUT] Output token for the imported type in the emit scope.
+
+private:
+ /*
+ static bool ImportHelper::CompareCustomAttribute( //
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ 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
+ */
+
+ static HRESULT GetTDNesterHierarchy(
+ IMetaModelCommon *pCommon, // Scope in which to find the hierarchy.
+ mdTypeDef td, // TypeDef whose hierarchy is needed.
+ CQuickArray<mdTypeDef> &cqaTdNesters,// Array of Nesters.
+ CQuickArray<LPCUTF8> &cqaNamespaces, // Namespaces of the nesters.
+ CQuickArray<LPCUTF8> &cqaNames); // Names of the nesters.
+
+ static HRESULT GetTRNesterHierarchy(
+ IMetaModelCommon *pCommon, // Scope in which to find the hierarchy.
+ mdTypeRef tr, // TypeRef whose hierarchy is needed.
+ CQuickArray<mdTypeRef> &cqaTrNesters,// Array of Nesters.
+ CQuickArray<LPCUTF8> &cqaNamespaces, // Namespaces of the nesters.
+ CQuickArray<LPCUTF8> &cqaNames); // Names of the nesters.
+
+ static HRESULT CreateModuleRefFromScope(
+ CMiniMdRW *pMiniMdEmit, // [IN] Emit scope in which the ModuleRef is to be created.
+ IMetaModelCommon *pCommonImport, // [IN] Import scope.
+ mdModuleRef *ptkModuleRef); // [OUT] Output token for ModuleRef.
+
+ static HRESULT CreateModuleRefFromModuleRef( // S_OK or error.
+ CMiniMdRW *pMiniMdEmit, // [IN] Emit scope.
+ IMetaModelCommon *pCommon, // [IN] Import scope.
+ mdModuleRef tkModuleRef, // [IN] ModuleRef token.
+ mdModuleRef *ptkModuleRef); // [OUT] ModuleRef token in the emit scope.
+
+ static HRESULT CreateModuleRefFromExportedType( // S_OK, S_FALSE or error.
+ CMiniMdRW *pAssemEmit, // [IN] Import assembly scope.
+ CMiniMdRW *pMiniMdEmit, // [IN] Emit scope.
+ mdExportedType tkExportedType, // [IN] ExportedType token in Assembly emit scope.
+ mdModuleRef *ptkModuleRef); // [OUT] ModuleRef token in the emit scope.
+
+ // CreateAssemblyRefFromAssembly, CompareAssemblyRefToAssembly are in satellite libs because
+ // they are only used in emit cases and need strong-name support in mscorwks.dll.
+
+ static HRESULT CreateAssemblyRefFromAssembly( // S_OK or error.
+ CMiniMdRW *pMiniMdAssemEmit, // [IN] Emit assembly scope.
+ CMiniMdRW *pMiniMdModuleEmit, // [IN] Emit module scope.
+ IMetaModelCommon *pCommonAssemImport, // [IN] Assembly import scope.
+ const void *pbHashValue, // [IN] Hash Blob for Assembly.
+ ULONG cbHashValue, // [IN] Count of bytes.
+ mdAssemblyRef *ptkAssemblyRef); // [OUT] AssemblyRef token.
+
+ static HRESULT CompareAssemblyRefToAssembly( // S_OK, S_FALSE or error.
+ IMetaModelCommon *pCommonAssem1, // [IN] Assembly that defines the AssemblyRef.
+ mdAssemblyRef tkAssemRef, // [IN] AssemblyRef.
+ IMetaModelCommon *pCommonAssem2); // [IN] Assembly against which the Ref is compared.
+
+ static HRESULT CreateAssemblyRefFromAssemblyRef(
+ CMiniMdRW *pMiniMdAssemEmit, // [IN] Assembly emit scope.
+ CMiniMdRW *pMiniMdModuleEmit, // [IN] Module emit scope
+ IMetaModelCommon *pCommonImport, // [IN] Scope to import the assembly ref from.
+ mdAssemblyRef tkAssemRef, // [IN] Assembly ref to be imported.
+ mdAssemblyRef *ptkAssemblyRef); // [OUT] AssemblyRef in the emit scope.
+};
+
+#endif // __IMPORTHELPER__h__
diff --git a/src/md/compiler/mdperf.cpp b/src/md/compiler/mdperf.cpp
new file mode 100644
index 0000000000..4c63af84a9
--- /dev/null
+++ b/src/md/compiler/mdperf.cpp
@@ -0,0 +1,96 @@
+// 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.
+//*****************************************************************************
+// MDperf.cpp
+//
+
+//
+// This file provides Compiler Support functionality in metadata.
+//*****************************************************************************
+
+#include "stdafx.h"
+
+#include "mdperf.h"
+
+#ifdef FEATURE_METADATA_PERF_STATS
+
+//-----------------------------------------------------------------------------
+// Global array containing the name of the APIs. This is shared across
+// all instances of MDCompilerPerf.
+//-----------------------------------------------------------------------------
+char g_szNameOfAPI[LAST_MD_API][API_NAME_STR_SIZE];
+
+//-----------------------------------------------------------------------------
+// Constructor. Initialize counters to 0. Initialize names of MD APIs.
+//-----------------------------------------------------------------------------
+MDCompilerPerf::MDCompilerPerf()
+{
+ // Initialize counters
+ for (int idx=0; idx < LAST_MD_API; idx++)
+ {
+ MDPerfStats[idx].dwCalledNumTimes = 0;
+ MDPerfStats[idx].dwQueryPerfCycles = 0;
+ }
+
+#undef MD_FUNC
+#define MD_FUNC(MDTag)\
+ strncpy(g_szNameOfAPI[MDTag ## _ENUM], #MDTag, API_NAME_STR_SIZE-1);
+
+ MD_COMPILER_PERF_TABLE; // Relies on the MD_FUNC defined above.
+}
+
+MDCompilerPerf::~MDCompilerPerf()
+ {
+ // Output the stats and cleanup.
+ MetaDataPerfReport ();
+ }
+
+//-----------------------------------------------------------------------------
+// Output stats. <TODO>TODO: grow this into stats for per fautomation</TODO>
+//-----------------------------------------------------------------------------
+void MDCompilerPerf::MetaDataPerfReport ()
+{
+ LARGE_INTEGER freqVal;
+ DWORD totalCalls=0, totalCycles=0;
+
+ if (!QueryPerformanceFrequency(&freqVal))
+ {
+ printf("Perf counters not supported\n");
+ return;
+ }
+
+ for (int idx=0; idx < LAST_MD_API; idx++)
+ {
+ totalCalls += MDPerfStats[idx].dwCalledNumTimes;
+ totalCycles += MDPerfStats[idx].dwQueryPerfCycles;
+ }
+
+ if (!(totalCalls && totalCycles && freqVal.QuadPart))
+ {
+ // if any of above is 0 then things don't look good.
+ printf("No data gathered ...\n");
+ return;
+ }
+
+ printf("\n%-32.32s %-16.16s %-16.16s %-16.16s\n", "API Name", "# Calls", "Cycles", "Time (msec)");
+ for (idx=0; idx < LAST_MD_API; idx++)
+ {
+ if(MDPerfStats[idx].dwCalledNumTimes != 0)
+ printf( "%-32.32s %-9d [%3.2d%%] %-16d %-8.2f [%3.2d%%]\n",
+ g_szNameOfAPI[idx],
+ MDPerfStats[idx].dwCalledNumTimes,
+ (MDPerfStats[idx].dwCalledNumTimes*100)/totalCalls,
+ MDPerfStats[idx].dwQueryPerfCycles,
+ ((float)MDPerfStats[idx].dwQueryPerfCycles*1000)/(float)freqVal.QuadPart,
+ (MDPerfStats[idx].dwQueryPerfCycles*100)/totalCycles);
+ }
+ printf( "%-32.32s %-9d [100%%] %-16d %-8.2f [100%%]\n\n",
+ "Total Stats",
+ totalCalls,
+ totalCycles,
+ ((float)totalCycles*1000)/(float)freqVal.QuadPart);
+
+}
+
+#endif //FEATURE_METADATA_PERF_STATS
diff --git a/src/md/compiler/mdperf.h b/src/md/compiler/mdperf.h
new file mode 100644
index 0000000000..77def32d21
--- /dev/null
+++ b/src/md/compiler/mdperf.h
@@ -0,0 +1,243 @@
+// 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.
+//*****************************************************************************
+// Mdperf.h
+//
+
+//
+//*****************************************************************************
+
+#ifndef __MDCOMPILERPERF_H__
+#define __MDCOMPILERPERF_H__
+
+//#define FEATURE_METADATA_PERF_STATS
+
+#ifdef FEATURE_METADATA_PERF_STATS
+
+// Avoid dynamic allocs to display the API names.
+#define API_NAME_STR_SIZE 80
+
+//-----------------------------------------------------------------------------
+// In order to add instrumentation for an API, two changes have to be made.
+// One, add the API name in the table below (MD_TABLE).
+// Second, add two lines of code (shown below) in the implementation
+// of the API itself. e.g.
+// RegMeta::MyNewMetataDataAPI(...)
+// {
+// LOG(...);
+// START_MD_PERF(); // <------ add this line as is.
+// ....
+// // API implementation
+// ErrExit:
+// STOP_MD_PERF(RegMeta_MyNewMetaDataAPI); // <---------- add this line with the appropriate name
+// return (hr);
+// ]
+//
+//-----------------------------------------------------------------------------
+#define MD_COMPILER_PERF_TABLE\
+ MD_FUNC(SaveToMemory)\
+ MD_FUNC(DefineMethod)\
+ MD_FUNC(DefineMethodImpl)\
+ MD_FUNC(SetRVA)\
+ MD_FUNC(DefineTypeRefByName)\
+ MD_FUNC(DefineImportType)\
+ MD_FUNC(DefineMemberRef)\
+ MD_FUNC(DefineImportMember)\
+ MD_FUNC(DefineEvent)\
+ MD_FUNC(SetClassLayout)\
+ MD_FUNC(DeleteClassLayout)\
+ MD_FUNC(SetFieldMarshal)\
+ MD_FUNC(DeleteFieldMarshal)\
+ MD_FUNC(DefinePermissionSet)\
+ MD_FUNC(SetMemberIndex)\
+ MD_FUNC(GetTokenFromSig)\
+ MD_FUNC(DefineModuleRef)\
+ MD_FUNC(SetParent)\
+ MD_FUNC(GetTokenFromTypeSpec)\
+ MD_FUNC(DefineUserString)\
+ MD_FUNC(DeleteToken)\
+ MD_FUNC(SetTypeDefProps)\
+ MD_FUNC(DefineNestedType)\
+ MD_FUNC(SetMethodProps)\
+ MD_FUNC(SetEventProps)\
+ MD_FUNC(SetPermissionSetProps)\
+ MD_FUNC(DefinePinvokeMap)\
+ MD_FUNC(SetPinvokeMap)\
+ MD_FUNC(DeletePinvokeMap)\
+ MD_FUNC(DefineField)\
+ MD_FUNC(DefineProperty)\
+ MD_FUNC(DefineParam)\
+ MD_FUNC(SetFieldProps)\
+ MD_FUNC(SetPropertyProps)\
+ MD_FUNC(SetParamProps)\
+ MD_FUNC(EnumMembers)\
+ MD_FUNC(EnumMembersWithName)\
+ MD_FUNC(EnumMethods)\
+ MD_FUNC(EnumMethodsWithName)\
+ MD_FUNC(EnumFields)\
+ MD_FUNC(EnumFieldsWithName)\
+ MD_FUNC(EnumParams)\
+ MD_FUNC(EnumMemberRefs)\
+ MD_FUNC(EnumMethodImpls)\
+ MD_FUNC(EnumPermissionSets)\
+ MD_FUNC(FindMember)\
+ MD_FUNC(FindMethod)\
+ MD_FUNC(FindField)\
+ MD_FUNC(FindMemberRef)\
+ MD_FUNC(GetMethodProps)\
+ MD_FUNC(GetMemberRefProps)\
+ MD_FUNC(EnumProperties)\
+ MD_FUNC(EnumEvents)\
+ MD_FUNC(GetEventProps)\
+ MD_FUNC(EnumMethodSemantics)\
+ MD_FUNC(GetMethodSemantics)\
+ MD_FUNC(GetClassLayout)\
+ MD_FUNC(GetFieldMarshal)\
+ MD_FUNC(GetRVA)\
+ MD_FUNC(GetPermissionSetProps)\
+ MD_FUNC(GetSigFromToken)\
+ MD_FUNC(GetModuleRefProps)\
+ MD_FUNC(EnumModuleRefs)\
+ MD_FUNC(GetTypeSpecFromToken)\
+ MD_FUNC(GetNameFromToken)\
+ MD_FUNC(EnumUnresolvedMethods)\
+ MD_FUNC(GetUserString)\
+ MD_FUNC(GetPinvokeMap)\
+ MD_FUNC(EnumSignatures)\
+ MD_FUNC(EnumTypeSpecs)\
+ MD_FUNC(EnumUserStrings)\
+ MD_FUNC(GetParamForMethodIndex)\
+ MD_FUNC(GetMemberProps)\
+ MD_FUNC(GetFieldProps)\
+ MD_FUNC(GetPropertyProps)\
+ MD_FUNC(GetParamProps)\
+ MD_FUNC(SetModuleProps)\
+ MD_FUNC(Save)\
+ MD_FUNC(SaveToStream)\
+ MD_FUNC(GetSaveSize)\
+ MD_FUNC(Merge)\
+ MD_FUNC(DefineCustomAttribute)\
+ MD_FUNC(SetCustomAttributeValue)\
+ MD_FUNC(DefineSecurityAttributeSet)\
+ MD_FUNC(UnmarkAll)\
+ MD_FUNC(MarkToken)\
+ MD_FUNC(IsTokenMarked)\
+ MD_FUNC(DefineTypeDef)\
+ MD_FUNC(SetHandler)\
+ MD_FUNC(CountEnum)\
+ MD_FUNC(ResetEnum)\
+ MD_FUNC(EnumTypeDefs)\
+ MD_FUNC(EnumInterfaceImpls)\
+ MD_FUNC(EnumTypeRefs)\
+ MD_FUNC(FindTypeDefByName)\
+ MD_FUNC(FindTypeDefByGUID)\
+ MD_FUNC(GetScopeProps)\
+ MD_FUNC(GetModuleFromScope)\
+ MD_FUNC(GetTypeDefProps)\
+ MD_FUNC(GetInterfaceImplProps)\
+ MD_FUNC(GetCustomAttributeByName)\
+ MD_FUNC(GetTypeRefProps)\
+ MD_FUNC(ResolveTypeRef)\
+ MD_FUNC(EnumCustomAttributes)\
+ MD_FUNC(GetCustomAttributeProps)\
+ MD_FUNC(FindTypeRef)\
+ MD_FUNC(RefToDefOptimization)\
+ MD_FUNC(ProcessFilter)\
+ MD_FUNC(DefineAssembly)\
+ MD_FUNC(DefineAssemblyRef)\
+ MD_FUNC(DefineFile)\
+ MD_FUNC(DefineExportedType)\
+ MD_FUNC(DefineManifestResource)\
+ MD_FUNC(DefineExecutionLocation)\
+ MD_FUNC(SetAssemblyProps)\
+ MD_FUNC(SetAssemblyRefProps)\
+ MD_FUNC(SetFileProps)\
+ MD_FUNC(SetExportedTypeProps)\
+ MD_FUNC(GetAssemblyProps)\
+ MD_FUNC(GetAssemblyRefProps)\
+ MD_FUNC(GetFileProps)\
+ MD_FUNC(GetExportedTypeProps)\
+ MD_FUNC(GetManifestResourceProps)\
+ MD_FUNC(EnumAssemblyRefs)\
+ MD_FUNC(EnumFiles)\
+ MD_FUNC(EnumExportedTypes)\
+ MD_FUNC(EnumManifestResources)\
+ MD_FUNC(EnumExecutionLocations)\
+ MD_FUNC(GetAssemblyFromScope)\
+ MD_FUNC(FindExportedTypeByName)\
+ MD_FUNC(FindManifestResourceByName)\
+ MD_FUNC(FindAssembliesByName)\
+ MD_FUNC(SetGenericPars)\
+ MD_FUNC(DefineGenericParam)\
+ MD_FUNC(SetGenericParamProps)\
+ MD_FUNC(EnumGenericParamConstraints)\
+ MD_FUNC(GetGenericParamProps)\
+ MD_FUNC(GetGenericParamConstraintProps)\
+ MD_FUNC(GetPEKind)\
+ MD_FUNC(GetVersionString)\
+ MD_FUNC(GetAssemblyUnification)
+
+//-----------------------------------------------------------------------------
+// Create an enum of all the API names. This is the index to access the APIs.
+//-----------------------------------------------------------------------------
+#undef MD_FUNC
+#define MD_FUNC(MDTag)\
+ MDTag ## _ENUM,
+
+typedef enum _MDAPIs
+{
+ MD_COMPILER_PERF_TABLE
+ LAST_MD_API
+} MDApis;
+
+//-----------------------------------------------------------------------------
+// Declare the struct which contais all the interesting stats for a particular
+// API call.
+//-----------------------------------------------------------------------------
+typedef struct _MDAPIPerfData
+{
+ DWORD dwQueryPerfCycles; // # of cycles spent in this call
+ DWORD dwCalledNumTimes; // # of times this API was called
+} MDAPIPerfData;
+
+
+//-----------------------------------------------------------------------------
+// MDCompilerPerf
+//-----------------------------------------------------------------------------
+class MDCompilerPerf
+{
+public:
+ MDCompilerPerf();
+ ~MDCompilerPerf();
+
+private:
+ MDAPIPerfData MDPerfStats[LAST_MD_API];
+
+ void MetaDataPerfReport ();
+};
+
+// Note that this macro declares a local var.
+#define START_MD_PERF()\
+ LARGE_INTEGER __startVal;\
+ QueryPerformanceCounter(&__startVal);
+
+#undef MD_FUNC
+#define MD_FUNC(MDTag)\
+ MDTag ## _ENUM
+
+// Note that this macro uses the local var startVal declared in START_MD_PERF()
+#define STOP_MD_PERF(MDTag)\
+ LARGE_INTEGER __stopVal;\
+ QueryPerformanceCounter(&__stopVal);\
+ m_MDCompilerPerf.MDPerfStats[MD_FUNC(MDTag)].dwCalledNumTimes++;\
+ m_MDCompilerPerf.MDPerfStats[MD_FUNC(MDTag)].dwQueryPerfCycles += (DWORD)(__stopVal.QuadPart - __startVal.QuadPart);
+
+#else //!FEATURE_METADATA_PERF_STATS
+
+#define START_MD_PERF()
+#define STOP_MD_PERF(MDTag)
+
+#endif //!FEATURE_METADATA_PERF_STATS
+
+#endif // __MDCOMPILERPERF_H__
diff --git a/src/md/compiler/mdsighelper.h b/src/md/compiler/mdsighelper.h
new file mode 100644
index 0000000000..0d089729bb
--- /dev/null
+++ b/src/md/compiler/mdsighelper.h
@@ -0,0 +1,128 @@
+// 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.
+//*****************************************************************************
+
+//
+// MDSigHelp.h
+//
+// contains utility code for signature parsing and comparisons.
+//
+// This is needed for validator support, especially because it may need to compare signatures
+// across multiple metadata scopes.
+//*****************************************************************************
+
+#ifndef __mdsighelper_h_
+#define __mdsighelper_h_
+
+#include "regmeta.h"
+
+
+//****************************************************************************
+//****************************************************************************
+class MDSigParser : public SigParser
+{
+ friend class MDSigComparer;
+
+ public:
+ //------------------------------------------------------------------------
+ // Constructor.
+ //------------------------------------------------------------------------
+ FORCEINLINE MDSigParser(PCCOR_SIGNATURE ptr, DWORD len)
+ : SigParser(ptr, len)
+ { }
+
+ FORCEINLINE MDSigParser(const MDSigParser &sig)
+ : SigParser(sig.m_ptr, sig.m_dwLen)
+ { }
+};
+
+//****************************************************************************
+//****************************************************************************
+class MDSigComparer
+{
+ public:
+ //------------------------------------------------------------------------
+ // This is the base type used to provide callback comparison functionality.
+ //------------------------------------------------------------------------
+ class MDSigComparerBaseType
+ {
+ public:
+ //------------------------------------------------------------------------
+ // Returns S_OK if the tokens are equivalent, E_FAIL if they are not, or
+ // error.
+ //------------------------------------------------------------------------
+ virtual HRESULT CompareToken(const mdToken &tok1, const mdToken &tok2) = 0;
+ };
+
+ //------------------------------------------------------------------------
+ // Ctor
+ //------------------------------------------------------------------------
+ MDSigComparer(const MDSigParser &sig1,
+ const MDSigParser &sig2,
+ MDSigComparerBaseType &comparer)
+ : m_sig1(sig1), m_sig2(sig2), m_comparer(comparer)
+ { }
+
+ //------------------------------------------------------------------------
+ // Returns S_OK if the signatures are equivalent, E_FAIL if they are not,
+ // or error.
+ //------------------------------------------------------------------------
+ HRESULT CompareMethodSignature();
+
+ protected:
+ MDSigParser m_sig1;
+ MDSigParser m_sig2;
+ MDSigComparerBaseType &m_comparer;
+
+ // This will compare exactly one type in each signature to determine
+ // if they are equal
+ HRESULT _CompareMethodSignature();
+ HRESULT _CompareExactlyOne();
+ HRESULT _CompareData(ULONG *pulData);
+ HRESULT _CompareMethodSignatureHeader(ULONG &cArgs);
+};
+
+//****************************************************************************
+//****************************************************************************
+class UnifiedAssemblySigComparer : public MDSigComparer::MDSigComparerBaseType
+{
+ public:
+ //------------------------------------------------------------------------
+ // Ctor
+ //------------------------------------------------------------------------
+ UnifiedAssemblySigComparer(const RegMeta &regMeta)
+ : m_pRegMeta(const_cast<RegMeta*>(&regMeta))
+ { }
+
+ //------------------------------------------------------------------------
+ // Returns S_OK if the tokens are equivalent, E_FAIL if they are not, or
+ // error.
+ //------------------------------------------------------------------------
+ virtual HRESULT CompareToken(const mdToken &tok1, const mdToken &tok2);
+
+ protected:
+ RegMeta *m_pRegMeta;
+
+#ifdef FEATURE_FUSION
+ HRESULT _CreateIAssemblyNameFromAssemblyRef(
+ mdToken tkAsmRef,
+ IAssemblyName **ppAsmName);
+#else
+ HRESULT _CompareAssemblies(mdToken tkAsmRef1,mdToken tkAsmRef2, BOOL* pfEquivalent);
+#endif
+
+ HRESULT _CreateTypeNameFromTypeRef(
+ mdToken tkTypeRef,
+ SString &ssName,
+ mdToken &tkParent);
+
+ HRESULT _CreateFullyQualifiedTypeNameFromTypeRef(
+ mdToken tkTypeRef,
+ SString &ssFullName,
+ mdToken &tkParent);
+};
+
+
+#endif // __mdsighelper_h_
+
diff --git a/src/md/compiler/mdutil.cpp b/src/md/compiler/mdutil.cpp
new file mode 100644
index 0000000000..2e01258bea
--- /dev/null
+++ b/src/md/compiler/mdutil.cpp
@@ -0,0 +1,774 @@
+// 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.
+//*****************************************************************************
+// MDUtil.cpp
+//
+
+//
+// contains utility code to MD directory. This is only used for the full version.
+//
+//*****************************************************************************
+#include "stdafx.h"
+#include "metadata.h"
+#include "mdutil.h"
+#include "regmeta.h"
+#include "disp.h"
+#include "mdcommon.h"
+#include "importhelper.h"
+#include "sstring.h"
+
+#include <rwutil.h>
+
+#if defined(FEATURE_METADATA_IN_VM) || defined(FEATURE_METADATA_STANDALONE_WINRT)
+
+LOADEDMODULES * LOADEDMODULES::s_pLoadedModules = NULL;
+UTSemReadWrite * LOADEDMODULES::m_pSemReadWrite = NULL;
+RegMeta * (LOADEDMODULES::m_HashedModules[LOADEDMODULES_HASH_SIZE]) = { NULL };
+
+//*****************************************************************************
+// Hash a file name.
+//*****************************************************************************
+ULONG LOADEDMODULES::HashFileName(
+ LPCWSTR szName)
+{
+ return HashString(szName) % LOADEDMODULES_HASH_SIZE;
+} // LOADEDMODULES::HashFileName
+
+//---------------------------------------------------------------------------------------
+//
+// Initialize the static instance and lock.
+//
+HRESULT
+LOADEDMODULES::InitializeStatics()
+{
+ HRESULT hr = S_OK;
+
+ if (VolatileLoad(&s_pLoadedModules) == NULL)
+ {
+ // Initialize global read-write lock
+ {
+ NewHolder<UTSemReadWrite> pSemReadWrite = new (nothrow) UTSemReadWrite();
+ IfNullGo(pSemReadWrite);
+ IfFailGo(pSemReadWrite->Init());
+
+ if (InterlockedCompareExchangeT<UTSemReadWrite *>(&m_pSemReadWrite, pSemReadWrite, NULL) == NULL)
+ { // We won the initialization race
+ pSemReadWrite.SuppressRelease();
+ }
+ }
+
+ // Initialize the global instance
+ {
+ NewHolder<LOADEDMODULES> pLoadedModules = new (nothrow) LOADEDMODULES();
+ IfNullGo(pLoadedModules);
+
+ {
+ LOCKWRITE();
+
+ if (VolatileLoad(&s_pLoadedModules) == NULL)
+ {
+ VolatileStore(&s_pLoadedModules, pLoadedModules.Extract());
+ }
+ }
+ }
+ }
+
+ErrExit:
+ return hr;
+} // LOADEDMODULES::InitializeStatics
+
+//---------------------------------------------------------------------------------------
+//
+// Destroy the static instance and lock.
+//
+void
+LOADEDMODULES::DeleteStatics()
+{
+ HRESULT hr = S_OK;
+
+ if (s_pLoadedModules != NULL)
+ {
+ delete s_pLoadedModules;
+ s_pLoadedModules = NULL;
+ }
+ if (m_pSemReadWrite != NULL)
+ {
+ delete m_pSemReadWrite;
+ m_pSemReadWrite = NULL;
+ }
+} // LOADEDMODULES::DeleteStatics
+
+//*****************************************************************************
+// Add a RegMeta pointer to the loaded module list
+//*****************************************************************************
+HRESULT LOADEDMODULES::AddModuleToLoadedList(RegMeta * pRegMeta)
+{
+ HRESULT hr = NOERROR;
+ RegMeta ** ppRegMeta;
+
+ IfFailGo(InitializeStatics());
+
+ {
+ LOCKWRITE();
+
+ ppRegMeta = s_pLoadedModules->Append();
+ IfNullGo(ppRegMeta);
+
+ // The cache holds a copy of the pointer, but no ref-count. There is no
+ // point to the ref-count, because it just changes comparisons against 0
+ // to comparisons against 1.
+ *ppRegMeta = pRegMeta;
+
+ // If the module is read-only, hash it.
+ if (pRegMeta->IsReadOnly())
+ {
+ ULONG ixHash = HashFileName(pRegMeta->GetNameOfDBFile());
+ m_HashedModules[ixHash] = pRegMeta;
+ }
+ }
+
+ErrExit:
+ return hr;
+} // LOADEDMODULES::AddModuleToLoadedList
+
+//*****************************************************************************
+// Remove a RegMeta pointer from the loaded module list
+//*****************************************************************************
+BOOL LOADEDMODULES::RemoveModuleFromLoadedList(RegMeta * pRegMeta)
+{
+ BOOL bRemoved = FALSE; // Was this module removed from the cache?
+ int iFound = -1; // Index at which it was found.
+ ULONG cRef; // Ref count of the module.
+
+ // Lock the cache for write, so that no other thread will find what this
+ // thread is about to delete, and so that no other thread will delete
+ // what this thread is about to try to find.
+ HRESULT hr = S_OK;
+
+ IfFailGo(InitializeStatics());
+
+ {
+ LOCKWRITE();
+
+ // Search for this module in list of loaded modules.
+ int count = s_pLoadedModules->Count();
+ for (int index = 0; index < count; index++)
+ {
+ if ((*s_pLoadedModules)[index] == pRegMeta)
+ { // found a match to remove
+ iFound = index;
+ break;
+ }
+ }
+
+ // If the module is still in the cache, it hasn't been deleted yet.
+ if (iFound >= 0)
+ {
+ // See if there are any external references left.
+ cRef = pRegMeta->GetRefCount();
+
+ // If the cRef that we got from the module is zero, it will stay that way,
+ // because no other thread can discover the module while this thread holds
+ // the lock.
+
+ // OTOH, if the cRef is not zero, this thread can just return, because the
+ // other thread will eventually take the ref count to zero, and will then
+ // come through here to clean up the module. And this thread must not
+ // delete the module out from under other threads.
+
+ // It is possible that the cRef is zero, yet another thread has a pointer that
+ // it discovered before this thread took the lock. (And that thread has
+ // released the ref-counts.) In such a case, this thread can still remove the
+ // module from the cache, and tell the caller to delete it, because the
+ // other thread will wait on the lock, then discover that the module
+ // is not in the cache, and it won't try to delete the module.
+
+ if (cRef != 0)
+ { // Some other thread snuck in and found the entry in the cache.
+ return FALSE;
+ }
+
+ // No other thread owns the object. Remove from cache, and tell caller
+ // that we're done with it. (Caller will delete.)
+ s_pLoadedModules->Delete(iFound);
+ bRemoved = TRUE;
+
+ // If the module is read-only, remove from hash.
+ if (pRegMeta->IsReadOnly())
+ {
+ // There may have been multiple capitalizations pointing to the same entry.
+ // Find and remove all of them.
+ for (ULONG ixHash = 0; ixHash < LOADEDMODULES_HASH_SIZE; ++ixHash)
+ {
+ if (m_HashedModules[ixHash] == pRegMeta)
+ m_HashedModules[ixHash] = NULL;
+ }
+ }
+ }
+ }
+
+ErrExit:
+ return bRemoved;
+} // LOADEDMODULES::RemoveModuleFromLoadedList
+
+
+//*****************************************************************************
+// Search the cached RegMetas for a given scope.
+//*****************************************************************************
+HRESULT LOADEDMODULES::FindCachedReadOnlyEntry(
+ LPCWSTR szName, // Name of the desired file.
+ DWORD dwOpenFlags, // Flags the new file is opened with.
+ RegMeta ** ppMeta) // Put found RegMeta here.
+{
+ RegMeta * pRegMeta = 0;
+ BOOL bWillBeCopyMemory; // Will the opened file be copied to memory?
+ DWORD dwLowFileSize; // Low bytes of this file's size
+ DWORD dwLowFileTime; // Low butes of this file's last write time
+ HRESULT hr;
+ ULONG ixHash = 0;
+
+ IfFailGo(InitializeStatics());
+
+ {
+ LOCKREAD();
+
+ hr = S_FALSE; // We haven't found a match yet.
+
+ // Avoid confusion.
+ *ppMeta = NULL;
+
+ bWillBeCopyMemory = IsOfCopyMemory(dwOpenFlags);
+
+ // The cache is locked for read, so the list will not change.
+
+ // Figure out the size and timestamp of this file
+ WIN32_FILE_ATTRIBUTE_DATA faData;
+ if (!WszGetFileAttributesEx(szName, GetFileExInfoStandard, &faData))
+ return E_FAIL;
+ dwLowFileSize = faData.nFileSizeLow;
+ dwLowFileTime = faData.ftLastWriteTime.dwLowDateTime;
+
+ // Check the hash first.
+ ixHash = HashFileName(szName);
+ if ((pRegMeta = m_HashedModules[ixHash]) != NULL)
+ {
+ _ASSERTE(pRegMeta->IsReadOnly());
+
+ // Only match if the IsOfCopyMemory() bit is the same in both. This is because
+ // when ofCopyMemory is set, the file is not locked on disk, and may become stale
+ // in memory.
+ //
+ // Also, only match if the date and size are the same
+ if (pRegMeta->IsCopyMemory() == bWillBeCopyMemory &&
+ pRegMeta->GetLowFileTimeOfDBFile() == dwLowFileTime &&
+ pRegMeta->GetLowFileSizeOfDBFile() == dwLowFileSize)
+ {
+ // If the name matches...
+ LPCWSTR pszName = pRegMeta->GetNameOfDBFile();
+ #ifdef FEATURE_CASE_SENSITIVE_FILESYSTEM
+ if (wcscmp(szName, pszName) == 0)
+ #else
+ if (SString::_wcsicmp(szName, pszName) == 0)
+ #endif
+ {
+ ULONG cRefs;
+
+ // Found it. Add a reference, and return it.
+ *ppMeta = pRegMeta;
+ cRefs = pRegMeta->AddRef();
+
+ LOG((LF_METADATA, LL_INFO10, "Disp::OpenScope found cached RegMeta in hash: %#8x, crefs: %d\n", pRegMeta, cRefs));
+
+ return S_OK;
+ }
+ }
+ }
+
+ // Not found in hash; loop through each loaded modules
+ int count = s_pLoadedModules->Count();
+ for (int index = 0; index < count; index++)
+ {
+ pRegMeta = (*s_pLoadedModules)[index];
+
+ // If the module is read-only, and the CopyMemory bit matches, and the date
+ // and size are the same....
+ if (pRegMeta->IsReadOnly() &&
+ pRegMeta->IsCopyMemory() == bWillBeCopyMemory &&
+ pRegMeta->GetLowFileTimeOfDBFile() == dwLowFileTime &&
+ pRegMeta->GetLowFileSizeOfDBFile() == dwLowFileSize)
+ {
+ // If the name matches...
+ LPCWSTR pszName = pRegMeta->GetNameOfDBFile();
+ #ifdef FEATURE_CASE_SENSITIVE_FILESYSTEM
+ if (wcscmp(szName, pszName) == 0)
+ #else
+ if (SString::_wcsicmp(szName, pszName) == 0)
+ #endif
+ {
+ ULONG cRefs;
+
+ // Found it. Add a reference, and return it.
+ *ppMeta = pRegMeta;
+ cRefs = pRegMeta->AddRef();
+
+ // Update the hash.
+ m_HashedModules[ixHash] = pRegMeta;
+
+ LOG((LF_METADATA, LL_INFO10, "Disp::OpenScope found cached RegMeta by search: %#8x, crefs: %d\n", pRegMeta, cRefs));
+
+ return S_OK;
+ }
+ }
+ }
+ }
+
+ErrExit:
+ // Didn't find it.
+ LOG((LF_METADATA, LL_INFO10, "Disp::OpenScope did not find cached RegMeta\n"));
+
+ _ASSERTE(hr != S_OK);
+ return hr;
+} // LOADEDMODULES::FindCachedReadOnlyEntry
+
+#ifdef _DEBUG
+
+//*****************************************************************************
+// Search the cached RegMetas for a given scope.
+//*****************************************************************************
+BOOL LOADEDMODULES::IsEntryInList(
+ RegMeta * pRegMeta)
+{
+ HRESULT hr = S_OK;
+
+ IfFailGo(InitializeStatics());
+
+ {
+ LOCKREAD();
+
+ // Loop through each loaded modules
+ int count = s_pLoadedModules->Count();
+ for (int index = 0; index < count; index++)
+ {
+ if ((*s_pLoadedModules)[index] == pRegMeta)
+ {
+ return TRUE;
+ }
+ }
+ }
+
+ErrExit:
+ return FALSE;
+} // LOADEDMODULES::IsEntryInList
+
+#endif //_DEBUG
+
+#endif //FEATURE_METADATA_IN_VM || FEATURE_METADATA_STANDALONE_WINRT
+
+#ifdef FEATURE_METADATA_IN_VM
+
+//*****************************************************************************
+// Remove a RegMeta pointer from the loaded module list
+//*****************************************************************************
+// static
+HRESULT
+LOADEDMODULES::ResolveTypeRefWithLoadedModules(
+ mdTypeRef tkTypeRef, // [IN] TypeRef to be resolved.
+ RegMeta * pTypeRefRegMeta, // [IN] Scope in which the TypeRef is defined.
+ IMetaModelCommon * pTypeRefScope, // [IN] Scope in which the TypeRef is defined.
+ REFIID riid, // [IN] iid for the return interface.
+ IUnknown ** ppIScope, // [OUT] Return interface.
+ mdTypeDef * ptd) // [OUT] TypeDef corresponding the TypeRef.
+{
+ HRESULT hr = NOERROR;
+ RegMeta * pRegMeta;
+ CQuickArray<mdTypeRef> cqaNesters;
+ CQuickArray<LPCUTF8> cqaNesterNamespaces;
+ CQuickArray<LPCUTF8> cqaNesterNames;
+
+ IfFailGo(InitializeStatics());
+
+ {
+ LOCKREAD();
+
+ // Get the Nesting hierarchy.
+ IfFailGo(ImportHelper::GetNesterHierarchy(
+ pTypeRefScope,
+ tkTypeRef,
+ cqaNesters,
+ cqaNesterNamespaces,
+ cqaNesterNames));
+
+ int count = s_pLoadedModules->Count();
+ for (int index = 0; index < count; index++)
+ {
+ pRegMeta = (*s_pLoadedModules)[index];
+
+ {
+ // Do not lock the TypeRef RegMeta (again), as it is already locked for read by the caller.
+ // The code:UTSemReadWrite will block ReadLock even for thread holding already the read lock if
+ // some other thread is waiting for WriteLock on the same lock. That would cause dead-lock if we
+ // try to lock for read again here.
+ CMDSemReadWrite cSemRegMeta((pRegMeta == pTypeRefRegMeta) ? NULL : pRegMeta->GetReaderWriterLock());
+ IfFailGo(cSemRegMeta.LockRead());
+
+ hr = ImportHelper::FindNestedTypeDef(
+ pRegMeta->GetMiniMd(),
+ cqaNesterNamespaces,
+ cqaNesterNames,
+ mdTokenNil,
+ ptd);
+ }
+ if (hr == CLDB_E_RECORD_NOTFOUND)
+ { // Process next MetaData module
+ continue;
+ }
+ IfFailGo(hr);
+
+ // Found a loaded module containing the TypeDef.
+ IfFailGo(pRegMeta->QueryInterface(riid, (void **)ppIScope));
+ break;
+ }
+ }
+ if (FAILED(hr))
+ {
+ // cannot find the match!
+ hr = E_FAIL;
+ }
+ErrExit:
+ return hr;
+} // LOADEDMODULES::ResolveTypeRefWithLoadedModules
+
+#endif //FEATURE_METADATA_IN_VM
+
+#if defined(FEATURE_METADATA_IN_VM)
+
+//*****************************************************************************
+// This is a routine to try to find a class implementation given its fully
+// qualified name by using the CORPATH environment variable. CORPATH is a list
+// of directories (like PATH). Before checking CORPATH, this checks the current
+// directory, then the directory that the exe lives in. The search is
+// performed by parsing off one element at a time from the class name,
+// appending it to the directory and looking for a subdirectory or image with
+// that name. If the subdirectory exists, it drills down into that subdirectory
+// and tries the next element of the class name. When it finally bottoms out
+// but can't find the image it takes the rest of the fully qualified class name
+// and appends them with intervening '.'s trying to find a matching DLL.
+// Example:
+//
+// CORPATH=c:\bin;c:\prog
+// classname = namespace.class
+//
+// checks the following things in order:
+// c:\bin\namespace, (if <-exists) c:\bin\namespace\class.dll,
+// c:\bin\namespace.dll, c:\bin\namespace.class.dll
+// c:\prog\namespace, (if <-exists) c:\prog\namespace\class.dll,
+// c:\prog\namespace.dll, c:\prog\namespace.class.dll
+//*****************************************************************************
+HRESULT CORPATHService::GetClassFromCORPath(
+ __in __in_z LPWSTR wzClassname, // [IN] fully qualified class name
+ mdTypeRef tr, // [IN] TypeRef to be resolved.
+ IMetaModelCommon *pCommon, // [IN] Scope in which the TypeRef is defined.
+ REFIID riid, // [IN] Interface type to be returned.
+ IUnknown **ppIScope, // [OUT] Scope in which the TypeRef resolves.
+ mdTypeDef *ptd) // [OUT] typedef corresponding the typeref
+{
+ PathString rcCorPath; // The CORPATH environment variable.
+ LPWSTR szCorPath; // Used to parse CORPATH.
+ int iLen; // Length of the directory.
+ PathString rcCorDir; // Buffer for the directory.
+ WCHAR *temp; // Used as a parsing temp.
+ WCHAR *szSemiCol;
+
+ // Get the CORPATH environment variable.
+ if (WszGetEnvironmentVariable(W("CORPATH"), rcCorPath))
+ {
+ NewArrayHolder<WCHAR> szCorPathHolder = rcCorPath.GetCopyOfUnicodeString();
+ szCorPath = szCorPathHolder.GetValue();
+ // Try each directory in the path.
+ for(;*szCorPath != W('\0');)
+ {
+ // Get the next directory off the path.
+ if ((szSemiCol = wcschr(szCorPath, W(';'))))
+ {
+ temp = szCorPath;
+ *szSemiCol = W('\0');
+ szCorPath = szSemiCol + 1;
+ }
+ else
+ {
+ temp = szCorPath;
+ szCorPath += wcslen(temp);
+ }
+
+ rcCorDir.Set(temp);
+
+ // Check if we can find the class in the directory.
+ if (CORPATHService::GetClassFromDir(wzClassname, rcCorDir, tr, pCommon, riid, ppIScope, ptd) == S_OK)
+ return S_OK;
+ }
+ }
+
+ //<TODO>These should go before the path search, but it will cause test
+ // some headaches right now, so we'll give them a little time to transition.</TODO>
+
+ // Try the current directory first.
+ if ((iLen = WszGetCurrentDirectory( rcCorDir)) > 0 &&
+ CORPATHService::GetClassFromDir(wzClassname, rcCorDir, tr, pCommon, riid, ppIScope, ptd) == S_OK)
+ {
+ return S_OK;
+ }
+
+ // Try the app directory next.
+ if ((iLen = WszGetModuleFileName(NULL, rcCorDir)) > 0)
+ {
+
+ if(SUCCEEDED(CopySystemDirectory(rcCorDir, rcCorDir)) &&
+ CORPATHService::GetClassFromDir(
+ wzClassname,
+ rcCorDir,
+ tr,
+ pCommon,
+ riid,
+ ppIScope,
+ ptd) == S_OK)
+ {
+ return (S_OK);
+ }
+ }
+
+ // Couldn't find the class.
+ return S_FALSE;
+} // CORPATHService::GetClassFromCORPath
+
+//*****************************************************************************
+// This is used in conjunction with GetClassFromCORPath. See it for details
+// of the algorithm.
+//*****************************************************************************
+HRESULT CORPATHService::GetClassFromDir(
+ __in __in_z LPWSTR wzClassname, // Fully qualified class name.
+ __in SString& directory, // Directory to try. at most appended with a '\\'
+ mdTypeRef tr, // TypeRef to resolve.
+ IMetaModelCommon *pCommon, // Scope in which the TypeRef is defined.
+ REFIID riid,
+ IUnknown **ppIScope,
+ mdTypeDef *ptd) // [OUT] typedef
+{
+ WCHAR *temp; // Used as a parsing temp.
+ int iTmp;
+ bool bContinue; // Flag to check if the for loop should end.
+ LPWSTR wzSaveClassname = NULL; // Saved offset into the class name string.
+
+ // Process the class name appending each segment of the name to the
+ // directory until we find a DLL.
+ PathString dir;
+ if (!directory.EndsWith(DIRECTORY_SEPARATOR_CHAR_W))
+ {
+ directory.Append(DIRECTORY_SEPARATOR_CHAR_W);
+ }
+
+ for(;;)
+ {
+ bContinue = false;
+ dir.Set(directory);
+
+ if ((temp = wcschr(wzClassname, NAMESPACE_SEPARATOR_WCHAR)) != NULL)
+ {
+ *temp = W('\0'); //terminate with null so that it can be appended
+ dir.Append(wzClassname);
+ *temp = NAMESPACE_SEPARATOR_WCHAR; //recover the '.'
+
+ wzClassname = temp+1;
+ // Check if a directory by this name exists.
+ DWORD iAttrs = WszGetFileAttributes(dir);
+ if (iAttrs != 0xffffffff && (iAttrs & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ // Next element in the class spec.
+ bContinue = true;
+ wzSaveClassname = wzClassname;
+ }
+ }
+ else
+ {
+ dir.Append(wzClassname);
+
+ // Advance past the class name.
+ iTmp = (int)wcslen(wzClassname);
+ wzClassname += iTmp;
+ }
+
+ // Try to load the image.
+ dir.Append(W(".dll"));
+
+ // OpenScope given the dll name and make sure that the class is defined in the module.
+ if ( SUCCEEDED( CORPATHService::FindTypeDef(dir, tr, pCommon, riid, ppIScope, ptd) ) )
+ {
+ return (S_OK);
+ }
+
+ // If we didn't find the dll, try some more.
+ while (*wzClassname != W('\0'))
+ {
+ // Find the length of the next class name element.
+ if ((temp = wcschr(wzClassname, NAMESPACE_SEPARATOR_WCHAR)) == NULL)
+ {
+ temp = wzClassname + wcslen(wzClassname);
+ }
+
+ // Tack on ".element.dll"
+ SString::Iterator iter = dir.End();
+ BOOL findperiod = dir.FindBack(iter, NAMESPACE_SEPARATOR_WCHAR);
+ _ASSERTE(findperiod);
+ iter++;
+ dir.Truncate(iter);
+
+ WCHAR save = *temp;
+ *temp = W('\0');
+ dir.Append(wzClassname); //element
+ *temp = save;
+
+ // Try to load the image.
+ dir.Append(W(".dll"));
+
+ // OpenScope given the dll name and make sure that the class is defined in the module.
+ if ( SUCCEEDED( CORPATHService::FindTypeDef(dir, tr, pCommon, riid, ppIScope, ptd) ) )
+ {
+ return (S_OK);
+ }
+
+ // Advance to the next class name element.
+ wzClassname = temp;
+ if (*wzClassname != '\0')
+ ++wzClassname;
+ }
+ if (bContinue)
+ {
+
+ wzClassname = wzSaveClassname;
+ }
+ else
+ {
+ break;
+ }
+ }
+ return S_FALSE;
+} // CORPATHService::GetClassFromDir
+
+//*************************************************************
+//
+// Open the file with anme wzModule and check to see if there is a type
+// with namespace/class of wzNamespace/wzType. If so, return the RegMeta
+// corresponding to the file and the mdTypeDef of the typedef
+//
+//*************************************************************
+HRESULT CORPATHService::FindTypeDef(
+ __in __in_z LPCWSTR wzModule, // name of the module that we are going to open
+ mdTypeRef tr, // TypeRef to resolve.
+ IMetaModelCommon * pCommon, // Scope in which the TypeRef is defined.
+ REFIID riid,
+ IUnknown ** ppIScope,
+ mdTypeDef * ptd) // [OUT] the type that we resolve to
+{
+ HRESULT hr = NOERROR;
+ NewHolder<Disp> pDisp;
+ ReleaseHolder<IMetaDataImport2> pImport = NULL;
+ CQuickArray<mdTypeRef> cqaNesters;
+ CQuickArray<LPCUTF8> cqaNesterNamespaces;
+ CQuickArray<LPCUTF8> cqaNesterNames;
+ RegMeta * pRegMeta;
+
+ _ASSERTE((ppIScope != NULL) && (ptd != NULL));
+
+ *ppIScope = NULL;
+
+ pDisp = new (nothrow) Disp;
+ IfNullGo(pDisp);
+
+ IfFailGo(pDisp->OpenScope(wzModule, 0, IID_IMetaDataImport2, (IUnknown **)&pImport));
+ pRegMeta = static_cast<RegMeta *>(pImport.GetValue());
+
+ // Get the Nesting hierarchy.
+ IfFailGo(ImportHelper::GetNesterHierarchy(pCommon, tr, cqaNesters,
+ cqaNesterNamespaces, cqaNesterNames));
+
+ hr = ImportHelper::FindNestedTypeDef(
+ pRegMeta->GetMiniMd(),
+ cqaNesterNamespaces,
+ cqaNesterNames,
+ mdTokenNil,
+ ptd);
+ if (SUCCEEDED(hr))
+ {
+ *ppIScope = pImport.Extract();
+ }
+
+ErrExit:
+ return hr;
+} // CORPATHService::FindTypeDef
+
+#endif //FEATURE_METADATA_IN_VM
+
+//*******************************************************************************
+//
+// Determine the blob size base of the ELEMENT_TYPE_* associated with the blob.
+// This cannot be a table lookup because ELEMENT_TYPE_STRING is an unicode string.
+// The size of the blob is determined by calling wcsstr of the string + 1.
+//
+//*******************************************************************************
+ULONG _GetSizeOfConstantBlob(
+ DWORD dwCPlusTypeFlag, // ELEMENT_TYPE_*
+ void * pValue, // BLOB value
+ ULONG cchString) // String length in wide chars, or -1 for auto.
+{
+ ULONG ulSize = 0;
+
+ switch (dwCPlusTypeFlag)
+ {
+ case ELEMENT_TYPE_BOOLEAN:
+ ulSize = sizeof(BYTE);
+ break;
+ case ELEMENT_TYPE_I1:
+ case ELEMENT_TYPE_U1:
+ ulSize = sizeof(BYTE);
+ break;
+ case ELEMENT_TYPE_CHAR:
+ case ELEMENT_TYPE_I2:
+ case ELEMENT_TYPE_U2:
+ ulSize = sizeof(SHORT);
+ break;
+ case ELEMENT_TYPE_I4:
+ case ELEMENT_TYPE_U4:
+ case ELEMENT_TYPE_R4:
+ ulSize = sizeof(LONG);
+
+ break;
+
+ case ELEMENT_TYPE_I8:
+ case ELEMENT_TYPE_U8:
+ case ELEMENT_TYPE_R8:
+ ulSize = sizeof(DOUBLE);
+ break;
+
+ case ELEMENT_TYPE_STRING:
+ if (pValue == 0)
+ ulSize = 0;
+ else
+ if (cchString != (ULONG) -1)
+ ulSize = cchString * sizeof(WCHAR);
+ else
+ ulSize = (ULONG)(sizeof(WCHAR) * wcslen((LPWSTR)pValue));
+ break;
+
+ case ELEMENT_TYPE_CLASS:
+ // This was originally 'sizeof(IUnknown *)', but that varies across platforms.
+ // The only legal value is a null pointer, and on 32 bit platforms we've already
+ // stored 32 bits, so we will use just 32 bits of null. If the type is
+ // E_T_CLASS, the caller should know that the value is always NULL anyway.
+ ulSize = sizeof(ULONG);
+ break;
+ default:
+ _ASSERTE(!"Not a valid type to specify default value!");
+ break;
+ }
+ return ulSize;
+} // _GetSizeOfConstantBlob
diff --git a/src/md/compiler/mdutil.h b/src/md/compiler/mdutil.h
new file mode 100644
index 0000000000..58cdbf108a
--- /dev/null
+++ b/src/md/compiler/mdutil.h
@@ -0,0 +1,119 @@
+// 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.
+//*****************************************************************************
+// MDUtil.h
+//
+
+//
+// Contains utility code for MD directory
+//
+//*****************************************************************************
+#ifndef __MDUtil__h__
+#define __MDUtil__h__
+
+#include "metadata.h"
+
+
+HRESULT _GetFixedSigOfVarArg( // S_OK or error.
+ PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob of COM+ method signature
+ ULONG cbSigBlob, // [IN] size of signature
+ CQuickBytes *pqbSig, // [OUT] output buffer for fixed part of VarArg Signature
+ ULONG *pcbSigBlob); // [OUT] number of bytes written to the above output buffer
+
+ULONG _GetSizeOfConstantBlob(
+ DWORD dwCPlusTypeFlag, // ELEMENT_TYPE_*
+ void *pValue, // BLOB value
+ ULONG cchString); // Size of string in wide chars, or -1 for auto.
+
+
+//*********************************************************************
+// APIs to help look up TypeRef using CORPATH environment variable
+//*********************************************************************
+class CORPATHService
+{
+public:
+
+ static HRESULT GetClassFromCORPath(
+ __in __in_z LPWSTR wzClassname, // fully qualified class name
+ mdTypeRef tr, // TypeRef to be resolved
+ IMetaModelCommon *pCommon, // Scope in which the TypeRef is defined.
+ REFIID riid,
+ IUnknown **ppIScope,
+ mdTypeDef *ptd); // [OUT] typedef corresponding the typeref
+
+ static HRESULT GetClassFromDir(
+ __in __in_z LPWSTR wzClassname, // Fully qualified class name.
+ __in SString& dir, // Directory to try.
+ mdTypeRef tr, // TypeRef to resolve.
+ IMetaModelCommon *pCommon, // Scope in which the TypeRef is defined.
+ REFIID riid,
+ IUnknown **ppIScope,
+ mdTypeDef *ptd); // [OUT] typedef
+
+ static HRESULT FindTypeDef(
+ __in __in_z LPCWSTR wzModule, // name of the module that we are going to open
+ mdTypeRef tr, // TypeRef to resolve.
+ IMetaModelCommon *pCommon, // Scope in which the TypeRef is defined.
+ REFIID riid,
+ IUnknown **ppIScope,
+ mdTypeDef *ptd ); // [OUT] the type that we resolve to
+}; // class CORPATHService
+
+
+#if defined(FEATURE_METADATA_IN_VM) || defined(FEATURE_METADATA_STANDALONE_WINRT)
+
+class RegMeta;
+
+//*********************************************************************
+//
+// Structure to record the all loaded modules and helpers.
+// RegMeta instance is added to the global variable that is tracking
+// the opened scoped. This happens in RegMeta's constructor.
+// In RegMeta's destructor, the RegMeta pointer will be removed from
+// this list.
+//
+//*********************************************************************
+class UTSemReadWrite;
+#define LOADEDMODULES_HASH_SIZE 47
+
+class LOADEDMODULES : public CDynArray<RegMeta *>
+{
+private:
+ static HRESULT InitializeStatics();
+
+ // Global per-process list of loaded modules
+ static LOADEDMODULES * s_pLoadedModules;
+
+public:
+ static void DeleteStatics();
+
+ // Named for locking macros - see code:LOCKREAD
+ static UTSemReadWrite * m_pSemReadWrite;
+ static RegMeta *(m_HashedModules[LOADEDMODULES_HASH_SIZE]);
+
+ static ULONG HashFileName(LPCWSTR szName);
+
+ static HRESULT AddModuleToLoadedList(RegMeta *pRegMeta);
+ static BOOL RemoveModuleFromLoadedList(RegMeta *pRegMeta); // true if found and removed.
+
+ static HRESULT FindCachedReadOnlyEntry(LPCWSTR szName, DWORD dwOpenFlags, RegMeta **ppMeta);
+
+#ifdef FEATURE_METADATA_IN_VM
+ static HRESULT ResolveTypeRefWithLoadedModules(
+ mdTypeRef tkTypeRef, // [IN] TypeRef to be resolved.
+ RegMeta * pTypeRefRegMeta, // [IN] Scope in which the TypeRef is defined.
+ IMetaModelCommon * pTypeRefScope, // [IN] Scope in which the TypeRef is defined.
+ REFIID riid, // [IN] iid for the return interface.
+ IUnknown ** ppIScope, // [OUT] Return interface.
+ mdTypeDef * ptd); // [OUT] TypeDef corresponding the TypeRef.
+#endif //FEATURE_METADATA_IN_VM
+
+#ifdef _DEBUG
+ static BOOL IsEntryInList(RegMeta *pRegMeta);
+#endif
+}; // class LOADEDMODULES
+
+#endif //FEATURE_METADATA_IN_VM || FEATURE_METADATA_STANDALONE_WINRT
+
+#endif // __MDUtil__h__
diff --git a/src/md/compiler/mdvalidator.cpp b/src/md/compiler/mdvalidator.cpp
new file mode 100644
index 0000000000..adcfd51eb3
--- /dev/null
+++ b/src/md/compiler/mdvalidator.cpp
@@ -0,0 +1,7739 @@
+// 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.
+//*****************************************************************************
+// MDValidator.cpp
+//
+
+//
+// Implementation for the MetaData validator.
+// Only supported for full mscorwks version.
+//
+//*****************************************************************************
+#include "stdafx.h"
+
+#ifdef FEATURE_METADATA_VALIDATOR
+
+#include "regmeta.h"
+#include "importhelper.h"
+#include "pedecoder.h"
+#include "stgio.h"
+#include "corhost.h"
+#ifdef FEATURE_FUSION
+#include "fusion.h"
+#endif
+#include "sstring.h"
+#include "nsutilpriv.h"
+#include "holder.h"
+#include "vererror.h"
+
+#include "mdsighelper.h"
+
+#ifdef DACCESS_COMPILE
+#error Dac should be using standalone version of metadata, not Wks version.
+#endif
+
+//-----------------------------------------------------------------------------
+// Application specific debug macro.
+#define IfBreakGo(EXPR) \
+do {if ((EXPR) != S_OK) IfFailGo(VLDTR_E_INTERRUPTED); } while (0)
+
+//-----------------------------------------------------------------------------
+
+//#define CACHE_IMPLMAP_VALIDATION_RESULT
+#ifdef CACHE_IMPLMAP_VALIDATION_RESULT
+// To avoid multiple validation of the same thing:
+struct ValidationResult
+{
+ mdToken tok;
+ HRESULT hr;
+};
+ValidationResult* g_rValidated=NULL; // allocated in ValidateMetaData
+unsigned g_nValidated=0;
+#endif
+
+//-----------------------------------------------------------------------------
+
+#define BASE_OBJECT_CLASSNAME "Object"
+#define BASE_NAMESPACE "System"
+#define BASE_VTYPE_CLASSNAME "ValueType"
+#define BASE_ENUM_CLASSNAME "Enum"
+#define BASE_VALUE_FIELDNAME "value__"
+#define BASE_CTOR_NAME ".ctor"
+#define BASE_CCTOR_NAME ".cctor"
+#define BASE_MCDELEGATE_CLASSNAME "MulticastDelegate"
+
+#define SYSTEM_OBJECT_TOSTRING_METHODNAME "ToString"
+#define SYSTEM_OBJECT_GETHASHCODE_METHODNAME "GetHashCode"
+#define SYSTEM_OBJECT_EQUALS_METHODNAME "Equals"
+
+// string ToString()
+static const BYTE g_sigSystemObject_ToString[] =
+{
+ IMAGE_CEE_CS_CALLCONV_HASTHIS, // 0x20
+ 0, // 0x00 ... Param Count
+ ELEMENT_TYPE_STRING // 0x0e ... Return Type - string
+};
+
+// int GetHashCode()
+static const BYTE g_sigSystemObject_GetHashCode[] =
+{
+ IMAGE_CEE_CS_CALLCONV_HASTHIS, // 0x20
+ 0, // 0x00 ... Param Count
+ ELEMENT_TYPE_I4 // 0x08 ... Return Type - I4
+};
+
+// bool Equals(object)
+static const BYTE g_sigSystemObject_Equals[] =
+{
+ IMAGE_CEE_CS_CALLCONV_HASTHIS, // 0x20
+ 1, // 0x01 ... Param Count
+ ELEMENT_TYPE_BOOLEAN, // 0x02 ... Return Type - bool
+ ELEMENT_TYPE_OBJECT // 0x1c ... Param #1 - object
+};
+
+// as defined in src\vm\vars.hpp
+#define MAX_CLASSNAME_LENGTH 1024
+//-----------------------------------------------------------------------------
+// Class names used in long form signatures (namespace is always "System")
+unsigned g_NumSigLongForms = 19;
+static const LPCSTR g_SigLongFormName[] = {
+ "String",
+ "______", // "Object", <REVISIT_TODO>// uncomment when EE handles ELEMENT_TYPE_OBJECT</REVISIT_TODO>
+ "Boolean",
+ "Char",
+ "Byte",
+ "SByte",
+ "UInt16",
+ "Int16",
+ "UInt32",
+ "Int32",
+ "UInt64",
+ "Int64",
+ "Single",
+ "Double",
+ "SysInt", // Review this.
+ "SysUInt", // Review this.
+ "SingleResult",
+ "Void",
+ "IntPtr"
+};
+
+// <REVISIT_TODO>: Why are these global variables?</REVISIT_TODO>
+mdToken g_tkEntryPoint;
+bool g_fValidatingMscorlib;
+bool g_fIsDLL;
+
+//-----------------------------------------------------------------------------
+
+static HRESULT _FindClassLayout(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ mdTypeDef tkParent, // [IN] the parent that ClassLayout is associated with
+ RID *clRid, // [OUT] rid for the ClassLayout.
+ RID rid); // [IN] rid to be ignored.
+
+static HRESULT _FindFieldLayout(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ mdFieldDef tkParent, // [IN] the parent that FieldLayout is associated with
+ RID *flRid, // [OUT] rid for the FieldLayout record.
+ RID rid); // [IN] rid to be ignored.
+
+static BOOL _IsValidLocale(LPCUTF8 szLocale,
+ BOOL fIsV2Assembly);
+
+
+#define REPORT_ERROR0(_VECode) \
+ IfFailGo(_ValidateErrorHelper(_VECode, veCtxt))
+#define REPORT_ERROR1(_VECode, _Arg0) \
+ IfFailGo(_ValidateErrorHelper(_VECode, veCtxt, _Arg0))
+#define REPORT_ERROR2(_VECode, _Arg0, _Arg1) \
+ IfFailGo(_ValidateErrorHelper(_VECode, veCtxt, _Arg0, _Arg1))
+#define REPORT_ERROR3(_VECode, _Arg0, _Arg1, _Arg2) \
+ IfFailGo(_ValidateErrorHelper(_VECode, veCtxt, _Arg0, _Arg1, _Arg2))
+
+//*****************************************************************************
+// Returns true if ixPtrTbl and ixParTbl are a valid parent-child combination
+// in the pointer table scheme.
+//*****************************************************************************
+static inline bool IsTblPtr(ULONG ixPtrTbl, ULONG ixParTbl)
+{
+ if ((ixPtrTbl == TBL_Field && ixParTbl == TBL_TypeDef) ||
+ (ixPtrTbl == TBL_Method && ixParTbl == TBL_TypeDef) ||
+ (ixPtrTbl == TBL_Param && ixParTbl == TBL_Method) ||
+ (ixPtrTbl == TBL_Property && ixParTbl == TBL_PropertyMap) ||
+ (ixPtrTbl == TBL_Event && ixParTbl == TBL_EventMap))
+ {
+ return true;
+ }
+ return false;
+} // IsTblPtr()
+
+//*****************************************************************************
+// This inline function is used to set the return hr value for the Validate
+// functions to one of VLDTR_S_WRN, VLDTR_S_ERR or VLDTR_S_WRNERR based on
+// the current hr value and the new success code.
+// The general algorithm for error codes from the validation functions is:
+// if (no warnings or errors found)
+// return S_OK or S_FALSE
+// else if (warnings found)
+// return VLDTR_S_WRN
+// else if (errors found)
+// return VLDTR_S_ERR
+// else if (warnings and errors found)
+// return VLDTR_S_WRNERR
+//*****************************************************************************
+static inline void SetVldtrCode(HRESULT *phr, HRESULT successcode)
+{
+ _ASSERTE(successcode == S_OK || successcode == S_FALSE ||successcode == VLDTR_S_WRN ||
+ successcode == VLDTR_S_ERR || successcode == VLDTR_S_WRNERR);
+ _ASSERTE(*phr == S_OK || *phr == VLDTR_S_WRN || *phr == VLDTR_S_ERR ||
+ *phr == VLDTR_S_WRNERR);
+ if (successcode == S_OK || successcode == S_FALSE ||*phr == VLDTR_S_WRNERR)
+ return;
+ else if (*phr == S_OK || *phr == S_FALSE)
+ *phr = successcode;
+ else if (*phr != successcode)
+ *phr = VLDTR_S_WRNERR;
+} // SetVldtrCode()
+
+//*****************************************************************************
+// Initialize the Validator related structures in RegMeta.
+//*****************************************************************************
+HRESULT RegMeta::ValidatorInit( // S_OK or error.
+ DWORD dwModuleType, // [IN] Specifies whether the module is a PE file or an obj.
+ IUnknown *pUnk) // [IN] Validation error handler.
+{
+ HRESULT hr = S_OK; // Return value.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ int i = 0; // Index into the function pointer table.
+
+ // Initialize the array of function pointers to the validation function on
+ // each table.
+#undef MiniMdTable
+#define MiniMdTable(x) m_ValidateRecordFunctionTable[i++] = &RegMeta::Validate##x;
+ MiniMdTables()
+
+ // Verify that the ModuleType passed in is a valid one.
+ if (dwModuleType < ValidatorModuleTypeMin ||
+ dwModuleType > ValidatorModuleTypeMax)
+ {
+ IfFailGo(E_INVALIDARG);
+ }
+
+ // Verify that the interface passed in supports IID_IVEHandler.
+ IfFailGo(pUnk->QueryInterface(IID_IVEHandler, (void **)&m_pVEHandler));
+
+ // Set the ModuleType class member. Do this last, this is used in
+ // ValidateMetaData to see if the validator is correctly initialized.
+ m_ModuleType = (CorValidatorModuleType)dwModuleType;
+ErrExit:
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // HRESULT RegMeta::ValidatorInit()
+
+
+//*****************************************************************************
+// Public implementation for code:IMetaDataValidate::ValidateMetaData
+//
+// Validate the entire MetaData. Here is the basic algorithm.
+// for each table
+// for each record
+// {
+// Do generic validation - validate that the offsets into the blob
+// pool are good, validate that all the rids are within range,
+// validate that token encodings are consistent.
+// }
+// if (problems found in generic validation)
+// return;
+// for each table
+// for each record
+// Do semantic validation.
+//******************************************************************************
+HRESULT RegMeta::ValidateMetaData()
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CMiniMdRW * pMiniMd = &(m_pStgdb->m_MiniMd);
+ HRESULT hrSave = S_OK; // Saved hr from generic validation.
+ ULONG ulCount; // Count of records in the current table.
+ ULONG i; // Index to iterate over the tables.
+ ULONG j; // Index to iterate over the records in a given table.
+ IHostTaskManager * pHostTaskManager = NULL;
+
+#ifdef CACHE_IMPLMAP_VALIDATION_RESULT
+ ULONG rValidatedSize=0; // Size of g_rValidated array
+#endif
+
+ // Verify that the validator is initialized correctly
+ if (m_ModuleType == ValidatorModuleTypeInvalid)
+ {
+ _ASSERTE(!"Validator not initialized, initialize with ValidatorInit().");
+ IfFailGo(VLDTR_E_NOTINIT);
+ }
+
+ // First do a validation pass to do some basic structural checks based on
+ // the Meta-Meta data. This'll validate all the offsets into the pools,
+ // rid value and coded token ranges.
+ for (i = 0; i < pMiniMd->GetCountTables(); i++)
+ {
+ ulCount = pMiniMd->GetCountRecs(i);
+
+#ifdef CACHE_IMPLMAP_VALIDATION_RESULT
+ switch(i)
+ {
+ case TBL_ImplMap:
+ rValidatedSize += ulCount;
+ default:
+ ;
+ }
+#endif
+ for (j = 1; j <= ulCount; j++)
+ {
+ IfFailGo(ValidateRecord(i, j));
+ SetVldtrCode(&hrSave, hr);
+ }
+ }
+ // Validate that the size of the Ptr tables matches with the corresponding
+ // real tables.
+
+ // Do not do semantic validation if structural validation failed.
+ if (hrSave != S_OK)
+ {
+ hr = hrSave;
+ goto ErrExit;
+ }
+
+ // Verify the entry point (if any)
+ ::g_tkEntryPoint = 0;
+ ::g_fIsDLL = false;
+ if(m_pStgdb && m_pStgdb->m_pImage)
+ {
+ NewHolder<PEDecoder> pe;
+
+ EX_TRY
+ {
+ // We need to use different PEDecoder constructors based on the type of data we give it.
+ // We use the one with a 'bool' as the second argument when dealing with a mapped file,
+ // and we use the one that takes a COUNT_T as the second argument when dealing with a
+ // flat file.
+
+ if (m_pStgdb->m_pStgIO->GetMemoryMappedType() == MTYPE_IMAGE)
+ pe = new (nothrow) PEDecoder(m_pStgdb->m_pImage, false);
+ else
+ pe = new (nothrow) PEDecoder(m_pStgdb->m_pImage, (COUNT_T)(m_pStgdb->m_dwImageSize));
+
+ hr = S_OK;
+ }
+ EX_CATCH
+ {
+ hr = COR_E_BADIMAGEFORMAT;
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ if (SUCCEEDED(hr) && pe == NULL)
+ IfFailGo(E_OUTOFMEMORY);
+
+ if(FAILED(hr) || !pe->CheckFormat())
+ {
+ VEContext veCtxt; // Context structure.
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+ veCtxt.Token = 0;
+ veCtxt.uOffset = 0;
+ REPORT_ERROR0(COR_E_BADIMAGEFORMAT);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else if(!pe->IsILOnly())
+ {
+ VEContext veCtxt; // Context structure.
+ memset(&veCtxt, 0, sizeof(VEContext));
+ veCtxt.Token = 0;
+ veCtxt.uOffset = 0;
+ REPORT_ERROR0(VER_E_BAD_PE);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ if((pe->GetCorHeader()->Flags & COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) == 0)
+ g_tkEntryPoint = pe->GetEntryPointToken();
+ g_fIsDLL = pe->IsDll() ? true : false;
+
+ if(g_tkEntryPoint)
+ {
+ RID rid = RidFromToken(g_tkEntryPoint);
+ RID maxrid = 0;
+ switch(TypeFromToken(g_tkEntryPoint))
+ {
+ case mdtMethodDef: maxrid = pMiniMd->getCountMethods(); break;
+ case mdtFile: maxrid = pMiniMd->getCountFiles(); break;
+ default: break;
+ }
+ if((rid == 0)||(rid > maxrid))
+ {
+ VEContext veCtxt; // Context structure.
+ memset(&veCtxt, 0, sizeof(VEContext));
+ veCtxt.Token = g_tkEntryPoint;
+ veCtxt.uOffset = 0;
+ REPORT_ERROR0(VLDTR_E_EP_BADTOKEN);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ else if(!g_fIsDLL) // exe must have an entry point
+ {
+ VEContext veCtxt; // Context structure.
+ memset(&veCtxt, 0, sizeof(VEContext));
+ veCtxt.Token = g_tkEntryPoint;
+ veCtxt.uOffset = 0;
+ REPORT_ERROR0(VLDTR_E_EP_BADTOKEN);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+
+ g_fValidatingMscorlib = false;
+ if(pMiniMd->GetCountRecs(TBL_Assembly))
+ {
+ AssemblyRec *pRecord;
+ IfFailGo(pMiniMd->GetAssemblyRecord(1, &pRecord));
+ LPCSTR szName;
+ IfFailGo(pMiniMd->getNameOfAssembly(pRecord, &szName));
+ g_fValidatingMscorlib = (0 == SString::_stricmp(szName,"mscorlib"));
+ }
+ // Verify there are no circular class hierarchies.
+
+ // Do per record semantic validation on the MetaData. The function
+ // pointers to the per record validation are stored in the table by the
+ // ValidatorInit() function.
+
+#ifdef CACHE_IMPLMAP_VALIDATION_RESULT
+ g_rValidated = NULL;
+ ::g_nValidated = 0;
+ if (rValidatedSize)
+ {
+ g_rValidated = new(nothrow) ValidationResult[rValidatedSize];
+ IfNullGo(g_rValidated);
+ }
+#endif
+ pHostTaskManager = CorHost2::GetHostTaskManager();
+
+#ifdef Sleep
+#undef Sleep
+#endif
+ //DWORD cBegin=0,cEnd=0;
+ for (i = 0; i < pMiniMd->GetCountTables(); i++)
+ {
+ ulCount = pMiniMd->GetCountRecs(i);
+ //cBegin = GetTickCount();
+ for (j = 1; j <= ulCount; j++)
+ {
+ IfFailGo((this->*m_ValidateRecordFunctionTable[i])(j));
+ SetVldtrCode(&hrSave, hr);
+ if(pHostTaskManager)
+ {
+ // SwitchToTask forces the current thread to give up quantum, while a host can decide what
+ // to do with Sleep if the current thread has not run out of quantum yet.
+ ClrSleepEx(0, FALSE);
+ }
+ }
+ //cEnd = GetTickCount();
+ //printf("Table %d, recs: %d, time: %d\n",i,ulCount,(cEnd-cBegin));
+ }
+ hr = hrSave;
+ErrExit:
+
+#ifdef CACHE_IMPLMAP_VALIDATION_RESULT
+ if(g_rValidated) delete [] g_rValidated;
+#endif
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateMetaData()
+
+//*****************************************************************************
+// Validate the Module record.
+//*****************************************************************************
+HRESULT RegMeta::ValidateModule(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
+ ModuleRec *pRecord; // Module record.
+ VEContext veCtxt; // Context structure.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+ LPCSTR szName;
+ GUID GuidOfModule;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+
+ // Get the Module record.
+ veCtxt.Token = TokenFromRid(rid, mdtModule);
+ veCtxt.uOffset = 0;
+ IfFailGo(pMiniMd->GetModuleRecord(rid, &pRecord));
+
+ // There can only be one Module record.
+ if (rid > 1)
+ {
+ REPORT_ERROR0(VLDTR_E_MOD_MULTI);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Verify the name
+ IfFailGo(pMiniMd->getNameOfModule(pRecord, &szName));
+ if(szName && *szName)
+ {
+ ULONG L = (ULONG)strlen(szName);
+ if(L >= MAX_CLASSNAME_LENGTH)
+ {
+ // Name too long
+ REPORT_ERROR2(VLDTR_E_TD_NAMETOOLONG, L, (ULONG)(MAX_CLASSNAME_LENGTH-1));
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ if(strchr(szName,':') || strchr(szName,'\\'))
+ {
+ REPORT_ERROR0(VLDTR_E_MOD_NAMEFULLQLFD);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ else
+ {
+ REPORT_ERROR0(VLDTR_E_MOD_NONAME);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Verify that the MVID is valid.
+ IfFailGo(pMiniMd->getMvidOfModule(pRecord, &GuidOfModule));
+ if (GuidOfModule == GUID_NULL)
+ {
+ REPORT_ERROR0(VLDTR_E_MOD_NULLMVID);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateModule()
+
+//*****************************************************************************
+// Validate the given TypeRef.
+//*****************************************************************************
+HRESULT RegMeta::ValidateTypeRef(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
+ TypeRefRec *pRecord; // TypeRef record.
+ mdToken tkRes; // Resolution scope.
+ LPCSTR szNamespace; // TypeRef Namespace.
+ LPCSTR szName; // TypeRef Name.
+ mdTypeRef tkTypeRef; // Duplicate TypeRef.
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+ // Get the TypeRef record.
+ veCtxt.Token = TokenFromRid(rid, mdtTypeRef);
+ veCtxt.uOffset = 0;
+
+ IfFailGo(pMiniMd->GetTypeRefRecord(rid, &pRecord));
+
+ // Check name is not NULL.
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pRecord, &szNamespace));
+ IfFailGo(pMiniMd->getNameOfTypeRef(pRecord, &szName));
+ if (!*szName)
+ {
+ REPORT_ERROR0(VLDTR_E_TR_NAMENULL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ {
+ RID ridScope;
+ // Look for a Duplicate, this function reports only one duplicate.
+ tkRes = pMiniMd->getResolutionScopeOfTypeRef(pRecord);
+ hr = ImportHelper::FindTypeRefByName(pMiniMd, tkRes, szNamespace, szName, &tkTypeRef, rid);
+ if (hr == S_OK)
+ {
+ REPORT_ERROR1(VLDTR_E_TR_DUP, tkTypeRef);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else if (hr == CLDB_E_RECORD_NOTFOUND)
+ hr = S_OK;
+ else
+ IfFailGo(hr);
+ ULONG L = (ULONG)(strlen(szName)+strlen(szNamespace));
+ if(L >= MAX_CLASSNAME_LENGTH)
+ {
+ REPORT_ERROR2(VLDTR_E_TD_NAMETOOLONG, L, (ULONG)(MAX_CLASSNAME_LENGTH-1));
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ ridScope = RidFromToken(tkRes);
+ if(ridScope)
+ {
+ bool badscope = true;
+ //check if valid scope
+ switch(TypeFromToken(tkRes))
+ {
+ case mdtAssemblyRef:
+ case mdtModuleRef:
+ case mdtModule:
+ case mdtTypeRef:
+ badscope = !IsValidToken(tkRes);
+ break;
+ default:
+ break;
+ }
+ if(badscope)
+ {
+ REPORT_ERROR1(VLDTR_E_TR_BADSCOPE, tkTypeRef);
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ }
+ }
+ else
+ {
+ // check if there is a ExportedType
+ //hr = ImportHelper::FindExportedType(pMiniMd, szNamespace, szName, tkImpl, &tkExportedType, rid);
+ }
+ // Check if there is TypeDef with the same name
+ if(!ridScope)
+ {
+ if((TypeFromToken(tkRes) != mdtTypeRef) &&
+ (S_OK == ImportHelper::FindTypeDefByName(pMiniMd, szNamespace, szName, mdTokenNil,&tkTypeRef, 0)))
+ {
+ REPORT_ERROR1(VLDTR_E_TR_HASTYPEDEF, tkTypeRef);
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ }
+ }
+ }
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateTypeRef()
+
+//*****************************************************************************
+// Validate the given TypeDef.
+//*****************************************************************************
+#ifdef _PREFAST_
+#pragma warning(push)
+#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
+#endif
+HRESULT RegMeta::ValidateTypeDef(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
+ TypeDefRec *pRecord; // TypeDef record.
+ TypeDefRec *pExtendsRec = 0; // TypeDef record for the parent class.
+ mdTypeDef tkTypeDef; // Duplicate TypeDef token.
+ DWORD dwFlags; // TypeDef flags.
+ DWORD dwExtendsFlags; // TypeDef flags of the parent class.
+ LPCSTR szName; // TypeDef Name.
+ LPCSTR szNameSpace; // TypeDef NameSpace.
+ LPCSTR szExtName = NULL; // Parent Name.
+ LPCSTR szExtNameSpace = NULL; // Parent NameSpace.
+ CQuickBytes qb; // QuickBytes for flexible allocation.
+ mdToken tkExtends; // TypeDef of the parent class.
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+ mdToken tkEncloser=mdTokenNil; // Encloser, if any
+ BOOL bIsEnum,bExtendsEnum,bExtendsVType,bIsVType,bExtendsObject,bIsObject,bExtendsMCDelegate;
+ BOOL bHasMethods=FALSE, bHasFields=FALSE;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ // Skip validating m_tdModule class.
+ if (rid == RidFromToken(m_tdModule))
+ goto ErrExit;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+
+ // Get the TypeDef record.
+ veCtxt.Token = TokenFromRid(rid, mdtTypeDef);
+ veCtxt.uOffset = 0;
+
+ IfFailGo(pMiniMd->GetTypeDefRecord(rid, &pRecord));
+
+ // Do checks for name validity..
+ IfFailGo(pMiniMd->getNameOfTypeDef(pRecord, &szName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pRecord, &szNameSpace));
+ if (!*szName)
+ {
+ // TypeDef Name is null.
+ REPORT_ERROR0(VLDTR_E_TD_NAMENULL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else if (!IsDeletedName(szName))
+ {
+ RID iRecord;
+ IfFailGo(pMiniMd->FindNestedClassHelper(TokenFromRid(rid, mdtTypeDef), &iRecord));
+
+ if (InvalidRid(iRecord))
+ {
+ tkEncloser = mdTokenNil;
+ }
+ else
+ {
+ NestedClassRec *pNestedClassRec;
+ IfFailGo(pMiniMd->GetNestedClassRecord(iRecord, &pNestedClassRec));
+ tkEncloser = pMiniMd->getEnclosingClassOfNestedClass(pNestedClassRec);
+ }
+
+ // Check for duplicates based on Name/NameSpace. Do not do Dup checks
+ // on deleted records.
+ hr = ImportHelper::FindTypeDefByName(pMiniMd, szNameSpace, szName, tkEncloser,
+ &tkTypeDef, rid);
+ if (hr == S_OK)
+ {
+ REPORT_ERROR1(VLDTR_E_TD_DUPNAME, tkTypeDef);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else if (hr == CLDB_E_RECORD_NOTFOUND)
+ hr = S_OK;
+ else
+ IfFailGo(hr);
+ ULONG L = (ULONG)(strlen(szName)+strlen(szNameSpace));
+ if(L >= MAX_CLASSNAME_LENGTH)
+ {
+ REPORT_ERROR2(VLDTR_E_TD_NAMETOOLONG, L, (ULONG)(MAX_CLASSNAME_LENGTH-1));
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+
+ // Get the flag value for the TypeDef.
+ dwFlags = pMiniMd->getFlagsOfTypeDef(pRecord);
+ // Do semantic checks on the flags.
+ // RTSpecialName bit must be set on Deleted records.
+ if (IsDeletedName(szName))
+ {
+ if(!IsTdRTSpecialName(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_TD_DLTNORTSPCL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ hr = hrSave;
+ goto ErrExit;
+ }
+
+ // If RTSpecialName bit is set, the record must be a Deleted record.
+ if (IsTdRTSpecialName(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_TD_RTSPCLNOTDLT);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ if(!IsTdSpecialName(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_TD_RTSPCLNOTSPCL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+
+ // Check if flag value is valid
+ {
+ DWORD dwInvalidMask, dwExtraBits;
+ dwInvalidMask = (DWORD)~(tdVisibilityMask | tdLayoutMask | tdClassSemanticsMask |
+ tdAbstract | tdSealed | tdSpecialName | tdImport | tdSerializable | tdWindowsRuntime |
+ tdStringFormatMask | tdBeforeFieldInit | tdReservedMask);
+ // check for extra bits
+ dwExtraBits = dwFlags & dwInvalidMask;
+ if (dwExtraBits == 0)
+ {
+ // if no extra bits, check layout
+ dwExtraBits = dwFlags & tdLayoutMask;
+ if (dwExtraBits != tdLayoutMask)
+ {
+ // layout OK, check string format
+ dwExtraBits = dwFlags & tdStringFormatMask;
+ if (dwExtraBits != tdStringFormatMask)
+ dwExtraBits = 0;
+ }
+ }
+ if (dwExtraBits != 0)
+ {
+ REPORT_ERROR1(VLDTR_E_TD_EXTRAFLAGS, dwExtraBits);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+
+ // Generic types may be specified to have only AutoLayout or SequentialLayout (never ExplicitLayout).
+ if (IsTdExplicitLayout(dwFlags))
+ {
+ HENUMInternal hEnumTyPars;
+ ULONG ulTypeDefArity;
+ hr = pMiniMd->FindGenericParamHelper(TokenFromRid(rid, mdtTypeDef), &hEnumTyPars);
+ if (SUCCEEDED(hr))
+ {
+ IfFailGo(HENUMInternal::GetCount(&hEnumTyPars,&ulTypeDefArity));
+ HENUMInternal::ClearEnum(&hEnumTyPars);
+ if (ulTypeDefArity != 0)
+ {
+ REPORT_ERROR0(VLDTR_E_TD_GENERICHASEXPLAYOUT);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ }
+
+ }
+
+ // Get the parent of the TypeDef.
+ tkExtends = pMiniMd->getExtendsOfTypeDef(pRecord);
+
+ // Check if TypeDef extends itself
+ if (tkExtends == veCtxt.Token)
+ {
+ REPORT_ERROR0(VLDTR_E_TD_EXTENDSITSELF);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Check if TypeDef extends one of its children
+ if (RidFromToken(tkExtends)&&(TypeFromToken(tkExtends)==mdtTypeDef))
+ {
+ TypeDefRec *pRec;
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkExtends), &pRec));
+ mdToken tkExtends2 = pMiniMd->getExtendsOfTypeDef(pRec);
+ if( tkExtends2 == veCtxt.Token)
+ {
+ REPORT_ERROR0(VLDTR_E_TD_EXTENDSCHILD);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+
+
+
+ if (IsNilToken(tkEncloser) == IsTdNested(dwFlags))
+ {
+ REPORT_ERROR0(IsNilToken(tkEncloser) ? VLDTR_E_TD_NESTEDNOENCL : VLDTR_E_TD_ENCLNOTNESTED);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ bIsObject = bIsEnum = bIsVType = FALSE;
+ if(0 == strcmp(szNameSpace,BASE_NAMESPACE))
+ {
+ bIsObject = (0 == strcmp(szName,BASE_OBJECT_CLASSNAME));
+ if(!bIsObject)
+ {
+ bIsEnum = (0 == strcmp(szName,BASE_ENUM_CLASSNAME));
+ if(!bIsEnum)
+ {
+ bIsVType = (0 == strcmp(szName,BASE_VTYPE_CLASSNAME));
+ }
+ }
+ }
+
+ if (IsNilToken(tkExtends))
+ {
+ // If the parent token is nil, the class must be marked Interface,
+ // unless it's the System.Object class.
+ if ( !(bIsObject || IsTdInterface(dwFlags)))
+ {
+ REPORT_ERROR0(VLDTR_E_TD_NOTIFACEOBJEXTNULL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ szExtName = "";
+ szExtNameSpace = "";
+ }
+ else
+ {
+
+ // If tkExtends is a TypeSpec, extract the generic type and continue
+ if (TypeFromToken(tkExtends) == mdtTypeSpec)
+ {
+ //@GENERICSVER: TODO first validate the spec
+
+ TypeSpecRec *pRec;
+ IfFailGo(pMiniMd->GetTypeSpecRecord(RidFromToken(tkExtends), &pRec));
+ PCCOR_SIGNATURE pSig;
+ ULONG cSig;
+
+ IfFailGo(pMiniMd->getSignatureOfTypeSpec(pRec, &pSig, &cSig));
+
+ switch(CorSigUncompressElementType(pSig))
+ {
+ default:
+ {
+ REPORT_ERROR1(VLDTR_E_TD_EXTBADTYPESPEC, tkExtends);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ szExtName = "";
+ szExtNameSpace = "";
+ break;
+ }
+ case ELEMENT_TYPE_GENERICINST:
+ {
+ switch(CorSigUncompressElementType(pSig))
+ {
+ default:
+ {
+ REPORT_ERROR1(VLDTR_E_TD_EXTBADTYPESPEC, tkExtends);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ szExtName = "";
+ szExtNameSpace = "";
+ break;
+ }
+ case ELEMENT_TYPE_VALUETYPE:
+ case ELEMENT_TYPE_CLASS:
+ {
+ tkExtends = CorSigUncompressToken(pSig);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // If tkExtends is a TypeRef try to resolve it to a corresponding
+ // TypeDef. If it resolves successfully, issue a warning. It means
+ // that the Ref to Def optimization didn't happen successfully.
+ if (TypeFromToken(tkExtends) == mdtTypeRef)
+ {
+ TypeRefRec *pTypeRefRec;
+ IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tkExtends), &pTypeRefRec));
+
+ IfFailGo(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szExtName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szExtNameSpace));
+
+ BOOL fLookForDef = TRUE;
+ mdToken tkResScope = pMiniMd->getResolutionScopeOfTypeRef(pTypeRefRec);
+ if (TypeFromToken(tkResScope) == mdtAssemblyRef)
+ { // We will look for the TypeDef of the same name, only if the AssemblyRef has the same name as AssemblyDef
+ fLookForDef = FALSE;
+ RID ridResScope = RidFromToken(tkResScope);
+ if ((ridResScope > 0) && (ridResScope <= pMiniMd->GetCountRecs(TBL_AssemblyRef)))
+ {
+ if (pMiniMd->GetCountRecs(TBL_Assembly) > 0)
+ {
+ AssemblyRefRec * pAsmRefRec;
+ IfFailGo(pMiniMd->GetAssemblyRefRecord(ridResScope, &pAsmRefRec));
+ AssemblyRec *pAsmRec;
+ IfFailGo(pMiniMd->GetAssemblyRecord(1, &pAsmRec));
+ if ((pAsmRec != NULL) && (pAsmRefRec != NULL))
+ {
+ LPCUTF8 szAsmName;
+ IfFailGo(pMiniMd->getNameOfAssembly(pAsmRec, &szAsmName));
+ LPCUTF8 szAsmRefName;
+ IfFailGo(pMiniMd->getNameOfAssemblyRef(pAsmRefRec, &szAsmRefName));
+ if ((szAsmName != NULL) && (szAsmRefName != NULL))
+ fLookForDef = (strcmp(szAsmName,szAsmRefName) == 0);
+ }
+ }
+ }
+ }
+
+ if (fLookForDef)
+ {
+ mdTypeDef tkResTd;
+
+ if (ImportHelper::FindTypeDefByName(pMiniMd,
+ szExtNameSpace,
+ szExtName,
+ tkResScope,
+ &tkResTd) == S_OK)
+ {
+ // Ref to Def optimization is not expected to happen for Obj files.
+ /*
+ if (m_ModuleType != ValidatorModuleTypeObj)
+ {
+ REPORT_ERROR2(VLDTR_E_TD_EXTTRRES, tkExtends, tkResTd);
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ }
+ */
+
+ // Set tkExtends to the new TypeDef, so we can continue
+ // with the validation.
+ tkExtends = tkResTd;
+ }
+ }
+ }
+
+ // Continue validation, even for the case where TypeRef got resolved
+ // to a corresponding TypeDef in the same Module.
+ if (TypeFromToken(tkExtends) == mdtTypeDef)
+ {
+ // Extends must not be sealed.
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkExtends), &pExtendsRec));
+ dwExtendsFlags = pMiniMd->getFlagsOfTypeDef(pExtendsRec);
+ IfFailGo(pMiniMd->getNameOfTypeDef(pExtendsRec, &szExtName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pExtendsRec, &szExtNameSpace));
+ if (IsTdSealed(dwExtendsFlags))
+ {
+ REPORT_ERROR1(VLDTR_E_TD_EXTENDSSEALED, tkExtends);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ if (IsTdInterface(dwExtendsFlags))
+ {
+ REPORT_ERROR1(VLDTR_E_TD_EXTENDSIFACE, tkExtends);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ else if(TypeFromToken(tkExtends) == mdtTypeSpec)
+ {
+ //If we got here, the instantiated generic type is itself a type spec, which is illegal
+ REPORT_ERROR1(VLDTR_E_TD_EXTBADTYPESPEC, tkExtends);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ szExtName = "";
+ szExtNameSpace = "";
+
+ }
+ // If the parent token is non-null, the class must not be System.Object.
+ if (bIsObject)
+ {
+ REPORT_ERROR1(VLDTR_E_TD_OBJEXTENDSNONNULL, tkExtends);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+
+ bExtendsObject = bExtendsEnum = bExtendsVType = bExtendsMCDelegate = FALSE;
+ if(0 == strcmp(szExtNameSpace,BASE_NAMESPACE))
+ {
+ bExtendsObject = (0 == strcmp(szExtName,BASE_OBJECT_CLASSNAME));
+ if(!bExtendsObject)
+ {
+ bExtendsEnum = (0 == strcmp(szExtName,BASE_ENUM_CLASSNAME));
+ if(!bExtendsEnum)
+ {
+ bExtendsVType = (0 == strcmp(szExtName,BASE_VTYPE_CLASSNAME));
+ if(!bExtendsVType)
+ {
+ bExtendsMCDelegate = (0 == strcmp(szExtName,BASE_MCDELEGATE_CLASSNAME));
+ }
+ }
+ }
+ }
+
+ // System.ValueType must extend System.Object
+ if(bIsVType && !bExtendsObject)
+ {
+ REPORT_ERROR0(VLDTR_E_TD_SYSVTNOTEXTOBJ);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Validate rules for interface. Some of the VOS rules are verified as
+ // part of the validation for the corresponding Methods, fields etc.
+ if (IsTdInterface(dwFlags))
+ {
+ // Interface type must be marked abstract.
+ if (!IsTdAbstract(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_TD_IFACENOTABS);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Interface must not be sealed
+ if(IsTdSealed(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_TD_IFACESEALED);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Interface must have parent Nil token.
+ if (!IsNilToken(tkExtends))
+ {
+ REPORT_ERROR1(VLDTR_E_TD_IFACEPARNOTNIL, tkExtends);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ //Interface must have only static fields -- checked in ValidateField
+ //Interface must have only public fields -- checked in ValidateField
+ //Interface must have only abstract or static methods -- checked in ValidateMethod
+ //Interface must have only public methods -- checked in ValidateMethod
+
+ // Interface must have GUID
+ /*
+ if (*pGuid == GUID_NULL)
+ {
+ REPORT_ERROR0(VLDTR_E_TD_IFACEGUIDNULL);
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ }
+ */
+ }
+
+
+ // Class must have valid method and field lists
+ {
+ ULONG ridStart,ridEnd;
+ ridStart = pMiniMd->getMethodListOfTypeDef(pRecord);
+ ridEnd = pMiniMd->getCountMethods() + 1;
+ if(ridStart > ridEnd)
+ {
+ REPORT_ERROR0(VLDTR_E_TD_BADMETHODLST);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ {
+ IfFailGo(pMiniMd->getEndMethodListOfTypeDef(rid, &ridEnd));
+ bHasMethods = (ridStart && (ridStart < ridEnd));
+ }
+
+ ridStart = pMiniMd->getFieldListOfTypeDef(pRecord);
+ ridEnd = pMiniMd->getCountFields() + 1;
+ if(ridStart > ridEnd)
+ {
+ REPORT_ERROR0(VLDTR_E_TD_BADFIELDLST);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ {
+ IfFailGo(pMiniMd->getEndFieldListOfTypeDef(rid, &ridEnd));
+ bHasFields = (ridStart && (ridStart < ridEnd));
+ }
+ }
+
+ // Validate rules for System.Enum
+ if(bIsEnum)
+ {
+ if(!IsTdClass(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_TD_SYSENUMNOTCLASS);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ if(!bExtendsVType)
+ {
+ REPORT_ERROR0(VLDTR_E_TD_SYSENUMNOTEXTVTYPE);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ else
+ {
+ if(bExtendsVType || bExtendsEnum)
+ {
+ // ValueTypes and Enums must be sealed
+ if(!IsTdSealed(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_TD_VTNOTSEAL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Value class must have fields or size
+ if(!bHasFields)
+ {
+ ULONG ulClassSize = 0;
+ ClassLayoutRec *pRec;
+ RID ridClassLayout;
+ IfFailGo(pMiniMd->FindClassLayoutHelper(TokenFromRid(rid, mdtTypeDef), &ridClassLayout));
+
+ if (!InvalidRid(ridClassLayout))
+ {
+ IfFailGo(pMiniMd->GetClassLayoutRecord(RidFromToken(ridClassLayout), &pRec));
+ ulClassSize = pMiniMd->getClassSizeOfClassLayout(pRec);
+ }
+ if(ulClassSize == 0)
+ {
+ REPORT_ERROR0(VLDTR_E_TD_VTNOSIZE);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ }
+ else if(bExtendsMCDelegate)
+ {
+ // Delegates must be sealed
+ if(!IsTdSealed(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_TD_VTNOTSEAL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ }
+
+ // Enum-related checks
+ if (bExtendsEnum)
+ {
+ {
+ PCCOR_SIGNATURE pValueSig = NULL;
+ ULONG cbValueSig = 0;
+ mdFieldDef tkValueField=0, tkField, tkValue__Field = 0;
+ ULONG ridStart,ridEnd,index;
+ FieldRec *pFieldRecord; // Field record.
+ DWORD dwRecordFlags, dwTally, dwValueFlags, dwValue__Flags = 0;
+ RID ridField,ridValue=0,ridValue__ = 0;
+
+ ridStart = pMiniMd->getFieldListOfTypeDef(pRecord);
+ IfFailGo(pMiniMd->getEndFieldListOfTypeDef(rid, &ridEnd));
+ // check the instance (value__) field(s)
+ dwTally = 0;
+ for (index = ridStart; index < ridEnd; index++ )
+ {
+ IfFailGo(pMiniMd->GetFieldRid(index, &ridField));
+ IfFailGo(pMiniMd->GetFieldRecord(ridField, &pFieldRecord));
+ dwRecordFlags = pFieldRecord->GetFlags();
+ if(!IsFdStatic(dwRecordFlags))
+ {
+ dwTally++;
+ if(ridValue == 0)
+ {
+ ridValue = ridField;
+ tkValueField = TokenFromRid(ridField, mdtFieldDef);
+ IfFailGo(pMiniMd->getSignatureOfField(pFieldRecord, &pValueSig, &cbValueSig));
+ dwValueFlags = dwRecordFlags;
+ }
+ }
+ LPCSTR szFieldName;
+ IfFailGo(pMiniMd->getNameOfField(pFieldRecord, &szFieldName));
+ if(!strcmp(szFieldName, BASE_VALUE_FIELDNAME))
+ {
+ ridValue__ = ridField;
+ dwValue__Flags = dwRecordFlags;
+ tkValue__Field = TokenFromRid(ridField, mdtFieldDef);
+ }
+ }
+ // Enum must have one (and only one) inst.field
+ if(dwTally == 0)
+ {
+ REPORT_ERROR0(VLDTR_E_TD_ENUMNOINSTFLD);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else if(dwTally > 1)
+ {
+ REPORT_ERROR0(VLDTR_E_TD_ENUMMULINSTFLD);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // inst.field name must be "value__" (CLS)
+ if(ridValue__ == 0)
+ {
+ REPORT_ERROR0(VLDTR_E_TD_ENUMNOVALUE);
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ }
+ else
+ {
+ // if "value__" field is present ...
+ // ... it must be 1st instance field
+ if(ridValue__ != ridValue)
+ {
+ REPORT_ERROR1(VLDTR_E_TD_ENUMVALNOT1ST, tkValue__Field);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // ... it must not be static
+ if(IsFdStatic(dwValue__Flags))
+ {
+ REPORT_ERROR1(VLDTR_E_TD_ENUMVALSTATIC, tkValue__Field);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // ... it must be fdRTSpecialName
+ if(!IsFdRTSpecialName(dwValue__Flags))
+ {
+ REPORT_ERROR1(VLDTR_E_TD_ENUMVALNOTSN, tkValueField);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // ... its type must be integral
+ if(cbValueSig && pValueSig)
+ {
+ //ULONG ulCurByte = CorSigUncompressedDataSize(pValueSig);
+ //CorSigUncompressData(pValueSig);
+ //ULONG ulElemSize,ulElementType;
+ //ulCurByte += (ulElemSize = CorSigUncompressedDataSize(pValueSig));
+ //ulElementType = CorSigUncompressData(pValueSig);
+ //switch (ulElementType)
+ BYTE* pB = (BYTE*)pValueSig;
+ pB++; // skip the calling convention
+ while((*pB == ELEMENT_TYPE_CMOD_OPT)||
+ (*pB == ELEMENT_TYPE_CMOD_REQD))
+ {
+ mdToken tok;
+ pB++; // move from E_T_... to compressed token
+ pB += CorSigUncompressToken((PCOR_SIGNATURE)pB,&tok);
+ }
+ switch(*pB)
+ {
+ case ELEMENT_TYPE_BOOLEAN:
+ case ELEMENT_TYPE_CHAR:
+ case ELEMENT_TYPE_I1:
+ case ELEMENT_TYPE_U1:
+ case ELEMENT_TYPE_I2:
+ case ELEMENT_TYPE_U2:
+ case ELEMENT_TYPE_I4:
+ case ELEMENT_TYPE_U4:
+ case ELEMENT_TYPE_I8:
+ case ELEMENT_TYPE_U8:
+ case ELEMENT_TYPE_U:
+ case ELEMENT_TYPE_I:
+ case ELEMENT_TYPE_R4:
+ case ELEMENT_TYPE_R8:
+ break;
+ default:
+ REPORT_ERROR1(VLDTR_E_TD_ENUMFLDBADTYPE, tkValue__Field);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ }
+ // check all the fields
+ dwTally = 0;
+ for (index = ridStart; index < ridEnd; index++ )
+ {
+ IfFailGo(pMiniMd->GetFieldRid(index, &ridField));
+ if(ridField == ridValue) continue;
+ IfFailGo(pMiniMd->GetFieldRecord(ridField, &pFieldRecord));
+ LPCSTR szFieldName;
+ IfFailGo(pMiniMd->getNameOfField(pFieldRecord, &szFieldName));
+ if(IsFdRTSpecialName(pFieldRecord->GetFlags())
+ && IsDeletedName(szFieldName)) continue;
+ dwTally++;
+ tkField = TokenFromRid(ridField, mdtFieldDef);
+ if(!IsFdStatic(pFieldRecord->GetFlags()))
+ {
+ REPORT_ERROR1(VLDTR_E_TD_ENUMFLDNOTST, tkField);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ if(!IsFdLiteral(pFieldRecord->GetFlags()))
+ {
+ REPORT_ERROR1(VLDTR_E_TD_ENUMFLDNOTLIT, tkField);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ /*
+ IfFailGo(pMiniMd->getSignatureOfField(pFieldRecord, &pvSigTmp, &cbSig));
+ if(!(pvSigTmp && (cbSig==cbValueSig) &&(memcmp(pvSigTmp,pValueSig,cbSig)==0)))
+ {
+ REPORT_ERROR1(VLDTR_E_TD_ENUMFLDSIGMISMATCH, tkField);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ */
+ }
+ if(dwTally == 0)
+ {
+ REPORT_ERROR0(VLDTR_E_TD_ENUMNOLITFLDS);
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ }
+ }
+ // Enum must have no methods
+ if (bHasMethods)
+ {
+ REPORT_ERROR0(VLDTR_E_TD_ENUMHASMETHODS);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Enum must implement no interfaces
+ {
+ ULONG ridStart = 1;
+ ULONG ridEnd = pMiniMd->getCountInterfaceImpls() + 1;
+ ULONG index;
+ for (index = ridStart; index < ridEnd; index ++ )
+ {
+ InterfaceImplRec *pInterfaceImplRecord;
+ IfFailGo(pMiniMd->GetInterfaceImplRecord(index, &pInterfaceImplRecord));
+ if (veCtxt.Token == pMiniMd->getClassOfInterfaceImpl(pInterfaceImplRecord))
+ {
+ REPORT_ERROR0(VLDTR_E_TD_ENUMIMPLIFACE);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ }
+ }
+ }
+ // Enum must have no properties
+ {
+ ULONG ridStart = 1;
+ ULONG ridEnd = pMiniMd->getCountPropertys() + 1;
+ ULONG index;
+ mdToken tkClass;
+ for (index = ridStart; index < ridEnd; index ++ )
+ {
+ IfFailGo(pMiniMd->FindParentOfPropertyHelper(index | mdtProperty, &tkClass));
+ if (veCtxt.Token == tkClass)
+ {
+ REPORT_ERROR0(VLDTR_E_TD_ENUMHASPROP);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ }
+ }
+ }
+ // Enum must have no events
+ {
+ ULONG ridStart = 1;
+ ULONG ridEnd = pMiniMd->getCountEvents() + 1;
+ ULONG index;
+ mdToken tkClass;
+ for (index = ridStart; index < ridEnd; index ++ )
+ {
+ IfFailGo(pMiniMd->FindParentOfEventHelper(index | mdtEvent, &tkClass));
+ if (veCtxt.Token == tkClass)
+ {
+ REPORT_ERROR0(VLDTR_E_TD_ENUMHASEVENT);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ }
+ }
+ }
+ } // end if(bExtendsEnum)
+ // Class having security must be marked tdHasSecurity and vice versa
+ {
+ ULONG ridStart = 1;
+ ULONG ridEnd = pMiniMd->getCountDeclSecuritys() + 1;
+ ULONG index;
+ BOOL bHasSecurity = FALSE;
+ for (index = ridStart; index < ridEnd; index ++ )
+ {
+ DeclSecurityRec *pDeclSecurityRecord;
+ IfFailGo(pMiniMd->GetDeclSecurityRecord(index, &pDeclSecurityRecord));
+ if (veCtxt.Token == pMiniMd->getParentOfDeclSecurity(pDeclSecurityRecord))
+ {
+ bHasSecurity = TRUE;
+ break;
+ }
+ }
+ if (!bHasSecurity) // No records, check for CA "SuppressUnmanagedCodeSecurityAttribute"
+ {
+ bHasSecurity = (S_OK == ImportHelper::GetCustomAttributeByName(pMiniMd, veCtxt.Token,
+ "System.Security.SuppressUnmanagedCodeSecurityAttribute", NULL, NULL));
+ }
+ if(bHasSecurity != (IsTdHasSecurity(pRecord->GetFlags())!=0))
+ {
+ REPORT_ERROR0(bHasSecurity ? VLDTR_E_TD_SECURNOTMARKED : VLDTR_E_TD_MARKEDNOSECUR);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateTypeDef()
+#ifdef _PREFAST_
+#pragma warning(pop)
+#endif
+
+//*****************************************************************************
+// Validate the given FieldPtr.
+//*****************************************************************************
+HRESULT RegMeta::ValidateFieldPtr(RID rid)
+{
+ return S_OK;
+} // RegMeta::ValidateFieldPtr()
+
+
+//*****************************************************************************
+// Validate the given Field.
+//*****************************************************************************
+HRESULT RegMeta::ValidateField(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
+ FieldRec *pRecord; // Field record.
+ mdTypeDef tkTypeDef; // Parent TypeDef token.
+ mdFieldDef tkFieldDef; // Duplicate FieldDef token.
+ LPCSTR szName; // FieldDef name.
+ PCCOR_SIGNATURE pbSig; // FieldDef signature.
+ ULONG cbSig; // Signature size in bytes.
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+ BOOL bIsValueField;
+ BOOL bIsGlobalField = FALSE;
+ BOOL bHasValidRVA = FALSE;
+ DWORD dwInvalidFlags;
+ DWORD dwFlags;
+ RID tempRid;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+
+ // Get the FieldDef record.
+ veCtxt.Token = TokenFromRid(rid, mdtFieldDef);
+ veCtxt.uOffset = 0;
+
+ IfFailGo(pMiniMd->GetFieldRecord(rid, &pRecord));
+
+ // Do checks for name validity.
+ IfFailGo(pMiniMd->getNameOfField(pRecord, &szName));
+ if (!*szName)
+ {
+ // Field name is NULL.
+ REPORT_ERROR0(VLDTR_E_FD_NAMENULL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ {
+ if(!strcmp(szName,COR_DELETED_NAME_A)) goto ErrExit;
+ ULONG L = (ULONG)strlen(szName);
+ if(L >= MAX_CLASSNAME_LENGTH)
+ {
+ REPORT_ERROR2(VLDTR_E_TD_NAMETOOLONG, L, (ULONG)(MAX_CLASSNAME_LENGTH-1));
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ bIsValueField = (strcmp(szName,BASE_VALUE_FIELDNAME)==0);
+ // If field is RTSpecialName, its name must be 'value__' and vice versa
+ if((IsFdRTSpecialName(pRecord->GetFlags())!=0) != bIsValueField)
+ {
+ REPORT_ERROR1(bIsValueField ? VLDTR_E_TD_ENUMVALNOTSN : VLDTR_E_FD_NOTVALUERTSN, veCtxt.Token);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Validate flags
+ dwFlags = pRecord->GetFlags();
+ dwInvalidFlags = ~(fdFieldAccessMask | fdStatic | fdInitOnly | fdLiteral | fdNotSerialized | fdSpecialName
+ | fdPinvokeImpl | fdReservedMask);
+ if(dwFlags & dwInvalidFlags)
+ {
+ REPORT_ERROR1(VLDTR_E_TD_EXTRAFLAGS, dwFlags & dwInvalidFlags);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Validate access
+ if((dwFlags & fdFieldAccessMask) == fdFieldAccessMask)
+ {
+ REPORT_ERROR0(VLDTR_E_FMD_BADACCESSFLAG);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Literal : Static, !InitOnly
+ if(IsFdLiteral(dwFlags))
+ {
+ if(IsFdInitOnly(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_FD_INITONLYANDLITERAL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ if(!IsFdStatic(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_FD_LITERALNOTSTATIC);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ if(!IsFdHasDefault(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_FD_LITERALNODEFAULT);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ // RTSpecialName => SpecialName
+ if(IsFdRTSpecialName(dwFlags) && !IsFdSpecialName(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_FMD_RTSNNOTSN);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Validate Field signature.
+ IfFailGo(pMiniMd->getSignatureOfField(pRecord, &pbSig, &cbSig));
+ IfFailGo(ValidateFieldSig(TokenFromRid(rid, mdtFieldDef), pbSig, cbSig));
+ if (hr != S_OK)
+ SetVldtrCode(&hrSave, hr);
+
+ // Validate Field RVA
+ if(IsFdHasFieldRVA(dwFlags))
+ {
+ ULONG iFieldRVARid;
+ IfFailGo(pMiniMd->FindFieldRVAHelper(TokenFromRid(rid, mdtFieldDef), &iFieldRVARid));
+ if((iFieldRVARid==0) || (iFieldRVARid > pMiniMd->getCountFieldRVAs()))
+ {
+ REPORT_ERROR0(VLDTR_E_FD_RVAHASNORVA);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ {
+ /*
+ FieldRVARec *pRVARec;
+ IfFailGo(pMiniMd->GetFieldRVARecord(iFieldRVARid, &pRVARec));
+ if(pRVARec->GetRVA() == 0)
+ {
+ REPORT_ERROR0(VLDTR_E_FD_RVAHASZERORVA);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ */
+ bHasValidRVA = TRUE;
+ }
+ }
+
+ // Get the parent of the Field.
+ IfFailGo(pMiniMd->FindParentOfFieldHelper(TokenFromRid(rid, mdtFieldDef), &tkTypeDef));
+ // Validate that the parent is not nil.
+ if (IsNilToken(tkTypeDef))
+ {
+ REPORT_ERROR0(VLDTR_E_FD_PARNIL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else if (RidFromToken(tkTypeDef) != RidFromToken(m_tdModule))
+ {
+ if(IsValidToken(tkTypeDef) && (TypeFromToken(tkTypeDef) == mdtTypeDef))
+ {
+ TypeDefRec *pParentRec;
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkTypeDef), &pParentRec));
+ // If the name is "value__" ...
+ if(bIsValueField)
+ {
+ // parent must be Enum
+ mdToken tkExtends = pMiniMd->getExtendsOfTypeDef(pParentRec);
+ RID ridExtends = RidFromToken(tkExtends);
+ LPCSTR szExtName="",szExtNameSpace="";
+ if(ridExtends)
+ {
+ if(TypeFromToken(tkExtends) == mdtTypeRef)
+ {
+ TypeRefRec *pExtRec;
+ IfFailGo(pMiniMd->GetTypeRefRecord(ridExtends, &pExtRec));
+ IfFailGo(pMiniMd->getNameOfTypeRef(pExtRec, &szExtName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pExtRec, &szExtNameSpace));
+ }
+ else if(TypeFromToken(tkExtends) == mdtTypeDef)
+ {
+ TypeDefRec *pExtRec;
+ IfFailGo(pMiniMd->GetTypeDefRecord(ridExtends, &pExtRec));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pExtRec, &szExtName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pExtRec, &szExtNameSpace));
+ }
+ }
+ if(strcmp(szExtName,BASE_ENUM_CLASSNAME) || strcmp(szExtNameSpace,BASE_NAMESPACE))
+ {
+ REPORT_ERROR0(VLDTR_E_FD_VALUEPARNOTENUM);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // field must be instance - checked in ValidateTypeDef
+ // must be no other instance fields - checked in ValidateTypeDef
+ // must be first field - checked in ValidateTypeDef
+ // must be RTSpecialName -- checked in ValidateTypeDef
+ }
+ if(IsTdInterface(pMiniMd->getFlagsOfTypeDef(pParentRec)))
+ {
+ // Fields in interface are not CLS compliant
+ REPORT_ERROR0(VLDTR_E_FD_FLDINIFACE);
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+
+ // If field is not static, verify parent is not interface.
+ if(!IsFdStatic(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_FD_INSTINIFACE);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ // If field is not public, verify parent is not interface.
+ if(!IsFdPublic(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_FD_NOTPUBINIFACE);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ }
+ } // end if Valid and TypeDef
+ else
+ {
+ REPORT_ERROR1(VLDTR_E_FD_BADPARENT, tkTypeDef);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ else // i.e. if (RidFromToken(tkTypeDef) == RidFromToken(m_tdModule))
+ {
+ bIsGlobalField = TRUE;
+ // Globals are not CLS-compliant
+ REPORT_ERROR0(VLDTR_E_FMD_GLOBALITEM);
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ // Validate global field:
+ // Must be static
+ if(!IsFdStatic(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_FMD_GLOBALNOTSTATIC);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Must have a non-zero RVA
+ /*
+ if(!bHasValidRVA)
+ {
+ REPORT_ERROR0(VLDTR_E_FD_GLOBALNORVA);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ */
+ }
+
+ // Check for duplicates, except global fields with PrivateScope.
+ if (*szName && cbSig && !IsFdPrivateScope(dwFlags))
+ {
+ hr = ImportHelper::FindField(pMiniMd, tkTypeDef, szName, pbSig, cbSig, &tkFieldDef, rid);
+ if (hr == S_OK)
+ {
+ if(!IsFdPrivateScope(dwFlags))
+ {
+ REPORT_ERROR1(VLDTR_E_FD_DUP, tkFieldDef);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else hr = S_OK;
+ }
+ else if (hr == CLDB_E_RECORD_NOTFOUND)
+ {
+ hr = S_OK;
+ }
+ else
+ {
+ IfFailGo(hr);
+ }
+ }
+ // Field having security must be marked fdHasSecurity and vice versa
+ {
+ ULONG ridStart = 1;
+ ULONG ridEnd = pMiniMd->getCountDeclSecuritys() + 1;
+ ULONG index;
+ BOOL bHasSecurity = FALSE;
+ for (index = ridStart; index < ridEnd; index ++ )
+ {
+ DeclSecurityRec *pDeclSecurityRecord;
+ IfFailGo(pMiniMd->GetDeclSecurityRecord(index, &pDeclSecurityRecord));
+ if ( veCtxt.Token == pMiniMd->getParentOfDeclSecurity(pDeclSecurityRecord))
+ {
+ bHasSecurity = TRUE;
+ break;
+ }
+ }
+ if(!bHasSecurity) // No records, check for CA "SuppressUnmanagedCodeSecurityAttribute"
+ {
+ bHasSecurity = (S_OK == ImportHelper::GetCustomAttributeByName(pMiniMd, veCtxt.Token,
+ "System.Security.SuppressUnmanagedCodeSecurityAttribute", NULL, NULL));
+ }
+ if(bHasSecurity)
+ {
+ REPORT_ERROR0(VLDTR_E_FMD_SECURNOTMARKED);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ // Field having marshaling must be marked fdHasFieldMarshal and vice versa
+ IfFailGo(pMiniMd->FindFieldMarshalHelper(veCtxt.Token, &tempRid));
+ if (InvalidRid(tempRid) == (IsFdHasFieldMarshal(dwFlags) != 0))
+ {
+ REPORT_ERROR0(IsFdHasFieldMarshal(dwFlags)? VLDTR_E_FD_MARKEDNOMARSHAL : VLDTR_E_FD_MARSHALNOTMARKED);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Field having const value must be marked fdHasDefault and vice versa
+ IfFailGo(pMiniMd->FindConstantHelper(veCtxt.Token, &tempRid));
+ if(InvalidRid(tempRid) == (IsFdHasDefault(dwFlags) != 0))
+ {
+ REPORT_ERROR0(IsFdHasDefault(dwFlags)? VLDTR_E_FD_MARKEDNODEFLT : VLDTR_E_FD_DEFLTNOTMARKED);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Check the field's impl.map
+ {
+ ULONG iRecord;
+ IfFailGo(pMiniMd->FindImplMapHelper(veCtxt.Token, &iRecord));
+ if(IsFdPinvokeImpl(dwFlags))
+ {
+ // must be static
+ if(!IsFdStatic(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_FMD_PINVOKENOTSTATIC);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // must have ImplMap
+ if (InvalidRid(iRecord))
+ {
+ REPORT_ERROR0(VLDTR_E_FMD_MARKEDNOPINVOKE);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ else
+ {
+ // must have no ImplMap
+ if (!InvalidRid(iRecord))
+ {
+ REPORT_ERROR0(VLDTR_E_FMD_PINVOKENOTMARKED);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ if (!InvalidRid(iRecord))
+ {
+ hr = ValidateImplMap(iRecord);
+ if(hr != S_OK)
+ {
+ REPORT_ERROR0(VLDTR_E_FMD_BADIMPLMAP);
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ }
+ }
+
+ }
+
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateField()
+
+//*****************************************************************************
+// Validate the given MethodPtr.
+//*****************************************************************************
+HRESULT RegMeta::ValidateMethodPtr(RID rid)
+{
+ return S_OK;
+} // RegMeta::ValidateMethodPtr()
+
+
+//*****************************************************************************
+// Validate the given Method.
+//*****************************************************************************
+#ifdef _PREFAST_
+#pragma warning(push)
+#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
+#endif
+HRESULT RegMeta::ValidateMethod(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
+ MethodRec *pRecord = NULL; // Method record.
+ mdTypeDef tkTypeDef; // Parent TypeDef token.
+ mdMethodDef tkMethodDef; // Duplicate MethodDef token.
+ LPCSTR szName; // MethodDef name.
+ DWORD dwFlags = 0; // Method flags.
+ DWORD dwImplFlags = 0; // Method impl.flags.
+ PCCOR_SIGNATURE pbSig; // MethodDef signature.
+ ULONG cbSig; // Signature size in bytes.
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+ BOOL bIsCtor=FALSE;
+ BOOL bIsCctor=FALSE;
+ BOOL bIsGlobal=FALSE;
+ BOOL bIsParentImport = FALSE;
+ BOOL bIsGeneric = FALSE;
+ unsigned retType;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+
+ // Get the MethodDef record.
+ veCtxt.Token = TokenFromRid(rid, mdtMethodDef);
+ veCtxt.uOffset = 0;
+
+ IfFailGo(pMiniMd->GetMethodRecord(rid, &pRecord));
+
+ // Do checks for name validity.
+ IfFailGo(pMiniMd->getNameOfMethod(pRecord, &szName));
+ if (!*szName)
+ {
+ // Method name is NULL.
+ REPORT_ERROR0(VLDTR_E_MD_NAMENULL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ {
+ if(!strcmp(szName,COR_DELETED_NAME_A)) goto ErrExit;
+ bIsCtor = (0 == strcmp(szName,BASE_CTOR_NAME));
+ bIsCctor = (0 == strcmp(szName,BASE_CCTOR_NAME));
+ ULONG L = (ULONG)strlen(szName);
+ if(L >= MAX_CLASSNAME_LENGTH)
+ {
+ REPORT_ERROR2(VLDTR_E_TD_NAMETOOLONG, L, (ULONG)(MAX_CLASSNAME_LENGTH-1));
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+
+ // Get the parent, flags and signature of the Method.
+ IfFailGo(pMiniMd->FindParentOfMethodHelper(TokenFromRid(rid, mdtMethodDef), &tkTypeDef));
+ dwFlags = pMiniMd->getFlagsOfMethod(pRecord);
+ dwImplFlags = pMiniMd->getImplFlagsOfMethod(pRecord);
+ IfFailGo(pMiniMd->getSignatureOfMethod(pRecord, &pbSig, &cbSig));
+
+ // Check for duplicates.
+ if (*szName && cbSig && !IsNilToken(tkTypeDef) && !IsMdPrivateScope(dwFlags))
+ {
+ hr = ImportHelper::FindMethod(pMiniMd, tkTypeDef, szName, pbSig, cbSig, &tkMethodDef, rid);
+ if (hr == S_OK)
+ {
+ REPORT_ERROR1(VLDTR_E_MD_DUP, tkMethodDef);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else if (hr == CLDB_E_RECORD_NOTFOUND)
+ hr = S_OK;
+ else
+ IfFailGo(hr);
+ }
+
+ // No further error checking for VtblGap methods.
+ if (IsVtblGapName(szName))
+ {
+ hr = hrSave;
+ goto ErrExit;
+ }
+
+ // Validate Method signature.
+ IfFailGo(ValidateMethodSig(TokenFromRid(rid, mdtMethodDef), pbSig, cbSig,
+ dwFlags));
+ if (hr != S_OK)
+ SetVldtrCode(&hrSave, hr);
+
+ // Validate that the parent is not nil.
+ if (IsNilToken(tkTypeDef))
+ {
+ REPORT_ERROR0(VLDTR_E_MD_PARNIL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else if (RidFromToken(tkTypeDef) != RidFromToken(m_tdModule))
+ {
+ if(TypeFromToken(tkTypeDef) == mdtTypeDef)
+ {
+ TypeDefRec *pTDRec;
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkTypeDef), &pTDRec));
+ DWORD dwTDFlags = pTDRec->GetFlags();
+ LPCSTR szTDName;
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTDRec, &szTDName));
+ LPCSTR szTDNameSpace;
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTDRec, &szTDNameSpace));
+ BOOL fIsTdValue=FALSE, fIsTdEnum=FALSE;
+ mdToken tkExtends = pMiniMd->getExtendsOfTypeDef(pTDRec);
+
+ if(0 == strcmp(szTDNameSpace,BASE_NAMESPACE))
+ {
+ fIsTdEnum = (0 == strcmp(szTDName,BASE_ENUM_CLASSNAME));
+ if(!fIsTdEnum)
+ {
+ fIsTdValue = (0 == strcmp(szTDName,BASE_VTYPE_CLASSNAME));
+ }
+ }
+ if(fIsTdEnum || fIsTdValue)
+ {
+ fIsTdEnum = fIsTdValue = FALSE; // System.Enum and System.ValueType themselves are classes
+ }
+ else if(RidFromToken(tkExtends))
+ {
+ if(TypeFromToken(tkExtends) == mdtTypeDef)
+ {
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkExtends), &pTDRec));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTDRec, &szTDName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTDRec, &szTDNameSpace));
+ }
+ else if(TypeFromToken(tkExtends) == mdtTypeSpec)
+ {
+ fIsTdEnum = fIsTdValue = FALSE; // a type extending a spec cannot be an enum or value type
+ // the assignments are redundant, but clear.
+ }
+ else
+ {
+ TypeRefRec *pTRRec;
+ IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tkExtends), &pTRRec));
+ IfFailGo(pMiniMd->getNameOfTypeRef(pTRRec, &szTDName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTRRec, &szTDNameSpace));
+ }
+
+ if(0 == strcmp(szTDNameSpace,BASE_NAMESPACE))
+ {
+ fIsTdEnum = (0 == strcmp(szTDName,BASE_ENUM_CLASSNAME));
+ if(!fIsTdEnum)
+ {
+ fIsTdValue = (0 == strcmp(szTDName,BASE_VTYPE_CLASSNAME));
+ }
+ else fIsTdValue = FALSE;
+ }
+ }
+
+ // If Method is abstract, verify parent is abstract.
+ if(IsMdAbstract(dwFlags) && !IsTdAbstract(dwTDFlags))
+ {
+ REPORT_ERROR1(VLDTR_E_MD_ABSTPARNOTABST, tkTypeDef);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // If parent is import, method must have zero RVA, otherwise it depends...
+ if(IsTdImport(dwTDFlags)) bIsParentImport = TRUE;
+ if(IsTdInterface(dwTDFlags))
+ {
+ if(!IsMdStatic(dwFlags))
+ {
+ // No non-abstract instance methods in interface.
+ if(!IsMdAbstract(dwFlags))
+ {
+ REPORT_ERROR1(VLDTR_E_MD_NOTSTATABSTININTF, tkTypeDef);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // No non-public instance methods in interface.
+ if(!IsMdPublic(dwFlags))
+ {
+ REPORT_ERROR1(VLDTR_E_MD_NOTPUBININTF, tkTypeDef);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ // If Method is constructor, verify parent is not interface.
+ if(bIsCtor)
+ {
+ REPORT_ERROR1(VLDTR_E_MD_CTORININTF, tkTypeDef);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }//end if(interface)
+ if((fIsTdValue || fIsTdEnum) && IsMiSynchronized(dwImplFlags))
+ {
+ REPORT_ERROR1(VLDTR_E_MD_SYNCMETHODINVTYPE, tkTypeDef);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ if(bIsCtor)
+ {
+ // .ctor must be instance
+ if(IsMdStatic(dwFlags))
+ {
+ REPORT_ERROR1(VLDTR_E_MD_CTORSTATIC, tkTypeDef);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }//end if .ctor
+ else if(bIsCctor)
+ {
+ // .cctor must be static
+ if(!IsMdStatic(dwFlags))
+ {
+ REPORT_ERROR1(VLDTR_E_MD_CCTORNOTSTATIC, tkTypeDef);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // ..cctor must have default callconv
+ IfFailGo(pMiniMd->getSignatureOfMethod(pRecord, &pbSig, &cbSig));
+ if(IMAGE_CEE_CS_CALLCONV_DEFAULT != CorSigUncompressData(pbSig))
+ {
+ REPORT_ERROR0(VLDTR_E_MD_CCTORCALLCONV);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // .cctor must have no arguments
+ if(0 != CorSigUncompressData(pbSig))
+ {
+ REPORT_ERROR0(VLDTR_E_MD_CCTORHASARGS);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+
+ }//end if .cctor
+ if(bIsCtor || bIsCctor)
+ {
+ // .ctor, .cctor must be SpecialName and RTSpecialName
+ if(!(IsMdSpecialName(dwFlags) && IsMdRTSpecialName(dwFlags)))
+ {
+ REPORT_ERROR1(VLDTR_E_MD_CTORNOTSNRTSN, tkTypeDef);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+#ifdef NO_SUCH_CHECKS_NEEDED_SPEC_TO_BE_UODATED
+ // .ctor, .cctor must not be virtual
+ if(IsMdVirtual(dwFlags))
+ {
+ REPORT_ERROR1(VLDTR_E_MD_CTORVIRT, tkTypeDef);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // .ctor, .cctor must not be abstract
+ if(IsMdAbstract(dwFlags))
+ {
+ REPORT_ERROR1(VLDTR_E_MD_CTORABST, tkTypeDef);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // .ctor, .cctor must not be PInvoke
+ if(IsMdPinvokeImpl(dwFlags))
+ {
+ REPORT_ERROR1(VLDTR_E_MD_CTORPINVOKE, tkTypeDef);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // .ctor,.cctor must have RVA!=0
+ if(pRecord->GetRVA()==0)
+ {
+ REPORT_ERROR0(VLDTR_E_MD_CTORZERORVA);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+#endif
+ }//end if .ctor or .cctor
+ }// end if(parent == TypeDef)
+ }// end if not Module
+ else // i.e. if (RidFromToken(tkTypeDef) == RidFromToken(m_tdModule))
+ {
+ bIsGlobal = TRUE;
+ // Globals are not CLS-compliant
+ REPORT_ERROR0(VLDTR_E_FMD_GLOBALITEM);
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ // Validate global method:
+ // Must be static
+ if(!IsMdStatic(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_FMD_GLOBALNOTSTATIC);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Must not be abstract or virtual
+ if(IsMdAbstract(dwFlags) || IsMdVirtual(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_MD_GLOBALABSTORVIRT);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Must be not .ctor or .cctor
+ if(bIsCtor)
+ {
+ REPORT_ERROR0(VLDTR_E_MD_GLOBALCTORCCTOR);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ } //end if Module
+
+ // Signature specifics: .ctor, .cctor, entrypoint
+ if(bIsCtor || bIsCctor)
+ {
+ // .ctor, .cctor must return void
+ IfFailGo(pMiniMd->getSignatureOfMethod(pRecord, &pbSig, &cbSig));
+ CorSigUncompressData(pbSig); // get call conv out of the way
+ CorSigUncompressData(pbSig); // get num args out of the way
+ while (((retType=CorSigUncompressData(pbSig)) == ELEMENT_TYPE_CMOD_OPT)
+ || (retType == ELEMENT_TYPE_CMOD_REQD)) CorSigUncompressToken(pbSig);
+ if(retType != ELEMENT_TYPE_VOID)
+ {
+ REPORT_ERROR0(VLDTR_E_MD_CTORNOTVOID);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ if(g_tkEntryPoint == veCtxt.Token)
+ {
+ ULONG ulCallConv;
+ // EP must be static
+ if(!IsMdStatic(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_EP_INSTANCE);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // EP can't belong to generic class or nested in generic class
+ mdToken tkTypeDefCur;
+ for(tkTypeDefCur = tkTypeDef; tkTypeDefCur != mdTokenNil;)
+ {
+ HENUMInternal hEnumTyPars;
+ ULONG ulTypeDefArity = 0;
+ hr = pMiniMd->FindGenericParamHelper(tkTypeDefCur, &hEnumTyPars);
+ if (SUCCEEDED(hr))
+ {
+ IfFailGo(HENUMInternal::GetCount(&hEnumTyPars,&ulTypeDefArity));
+ HENUMInternal::ClearEnum(&hEnumTyPars);
+ if (ulTypeDefArity != 0)
+ {
+ REPORT_ERROR0(VLDTR_E_EP_GENERIC_TYPE);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ if(ulTypeDefArity == 0)
+ {
+ // This class is not generic, how about the encloser?
+ RID iRecord;
+ IfFailGo(pMiniMd->FindNestedClassHelper(tkTypeDefCur, &iRecord));
+
+ if (InvalidRid(iRecord))
+ {
+ tkTypeDefCur = mdTokenNil;
+ }
+ else
+ {
+ NestedClassRec *pNestedClassRec;
+ IfFailGo(pMiniMd->GetNestedClassRecord(iRecord, &pNestedClassRec));
+ tkTypeDefCur = pMiniMd->getEnclosingClassOfNestedClass(pNestedClassRec);
+ }
+ }
+ else
+ tkTypeDefCur = mdTokenNil;
+ }
+
+ // EP must have a predetermined signature (different for DLL and EXE
+ IfFailGo(pMiniMd->getSignatureOfMethod(pRecord, &pbSig, &cbSig));
+ ulCallConv = CorSigUncompressData(pbSig); // get call conv out of the way
+ // EP can't be generic
+ if (ulCallConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
+ {
+ // Skip the arity
+ CorSigUncompressData(pbSig);
+ REPORT_ERROR0(VLDTR_E_EP_GENERIC_METHOD);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // EP must have 0 or 1 argument
+ unsigned nArgs = CorSigUncompressData(pbSig);
+ if(g_fIsDLL)
+ {
+ if(nArgs != 3)
+ {
+ REPORT_ERROR1(VLDTR_E_EP_TOOMANYARGS, 3);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ //EP must return I4
+ while (((retType=CorSigUncompressData(pbSig)) == ELEMENT_TYPE_CMOD_OPT)
+ || (retType == ELEMENT_TYPE_CMOD_REQD)) CorSigUncompressToken(pbSig);
+
+ if(retType != ELEMENT_TYPE_I4)
+ {
+ REPORT_ERROR0(VLDTR_E_EP_BADRET);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Arguments must be VOID*, U4, VOID*
+ if(nArgs)
+ {
+ unsigned jj;
+ bool badarg;
+ for(jj=0; jj<nArgs;jj++)
+ {
+ while (((retType=CorSigUncompressData(pbSig)) == ELEMENT_TYPE_CMOD_OPT)
+ || (retType == ELEMENT_TYPE_CMOD_REQD)) CorSigUncompressToken(pbSig);
+
+ switch(jj)
+ {
+ case 0:
+ case 2:
+ badarg = (retType != ELEMENT_TYPE_PTR)
+ ||(CorSigUncompressData(pbSig) != ELEMENT_TYPE_VOID);
+ break;
+
+ case 1:
+ badarg = (retType != ELEMENT_TYPE_U4);
+ break;
+
+ default:
+ badarg = true;
+ }
+ if(badarg)
+ {
+ REPORT_ERROR1(VLDTR_E_EP_BADARG, jj+1);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ }
+ }
+ else
+ {
+ if(nArgs > 1)
+ {
+ REPORT_ERROR1(VLDTR_E_EP_TOOMANYARGS, 1);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ //EP must return VOID, I4 or U4
+ while (((retType=CorSigUncompressData(pbSig)) == ELEMENT_TYPE_CMOD_OPT)
+ || (retType == ELEMENT_TYPE_CMOD_REQD)) CorSigUncompressToken(pbSig);
+
+ if((retType != ELEMENT_TYPE_VOID)&&(retType != ELEMENT_TYPE_I4)&&(retType != ELEMENT_TYPE_U4))
+ {
+ REPORT_ERROR0(VLDTR_E_EP_BADRET);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Argument (if any) must be vector of strings
+ if(nArgs)
+ {
+ while (((retType=CorSigUncompressData(pbSig)) == ELEMENT_TYPE_CMOD_OPT)
+ || (retType == ELEMENT_TYPE_CMOD_REQD)) CorSigUncompressToken(pbSig);
+
+ if((retType != ELEMENT_TYPE_SZARRAY)||(CorSigUncompressData(pbSig) != ELEMENT_TYPE_STRING))
+ {
+ REPORT_ERROR1(VLDTR_E_EP_BADARG, 1);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ } // end if(IsDll)--else
+ } // end if (IsEntryPoint)
+
+
+ // Check method RVA
+ if(pRecord->GetRVA()==0)
+ {
+ if(!(IsMdPinvokeImpl(dwFlags) || IsMdAbstract(dwFlags)
+ || IsMiRuntime(dwImplFlags) || IsMiInternalCall(dwImplFlags)
+ || bIsParentImport))
+ {
+ REPORT_ERROR0(VLDTR_E_MD_ZERORVA);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ else
+ {
+ if(m_pStgdb && m_pStgdb->m_pImage)
+ {
+ NewHolder<PEDecoder> pe;
+
+ EX_TRY
+ {
+ // We need to use different PEDecoder constructors based on the type of data we give it.
+ // We use the one with a 'bool' as the second argument when dealing with a mapped file,
+ // and we use the one that takes a COUNT_T as the second argument when dealing with a
+ // flat file.
+
+ if (m_pStgdb->m_pStgIO->GetMemoryMappedType() == MTYPE_IMAGE)
+ pe = new (nothrow) PEDecoder(m_pStgdb->m_pImage, false);
+ else
+ pe = new (nothrow) PEDecoder(m_pStgdb->m_pImage, (COUNT_T)(m_pStgdb->m_dwImageSize));
+
+ }
+ EX_CATCH
+ {
+ hr = COR_E_BADIMAGEFORMAT;
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ IfFailGo(hr);
+ IfNullGo(pe);
+
+ if (!pe->CheckRva(pRecord->GetRVA()))
+ {
+ REPORT_ERROR1(VLDTR_E_MD_BADRVA, pRecord->GetRVA());
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ {
+ if(IsMiManaged(dwImplFlags) && (IsMiIL(dwImplFlags) || IsMiOPTIL(dwImplFlags)))
+ {
+ HRESULT hrTemp = S_OK;
+ // validate locals signature token
+ EX_TRY
+ {
+ COR_ILMETHOD_DECODER method((COR_ILMETHOD*) pe->GetRvaData(pRecord->GetRVA()));
+ if (method.LocalVarSigTok)
+ {
+ if((TypeFromToken(method.GetLocalVarSigTok()) != mdtSignature) ||
+ (!IsValidToken(method.GetLocalVarSigTok())) || (RidFromToken(method.GetLocalVarSigTok())==0))
+ {
+ hrTemp = _ValidateErrorHelper(VLDTR_E_MD_BADLOCALSIGTOK, veCtxt, method.GetLocalVarSigTok());
+ if (SUCCEEDED(hrTemp))
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ }
+ EX_CATCH
+ {
+ hrTemp = _ValidateErrorHelper(VLDTR_E_MD_BADHEADER, veCtxt);
+ if (SUCCEEDED(hrTemp))
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ IfFailGo(hrTemp);
+ }
+ }
+ }
+
+ if(IsMdAbstract(dwFlags) || bIsParentImport
+ || IsMiRuntime(dwImplFlags) || IsMiInternalCall(dwImplFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_MD_ZERORVA);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ // Check the method flags
+ // Validate access
+ if((dwFlags & mdMemberAccessMask) == mdMemberAccessMask)
+ {
+ REPORT_ERROR0(VLDTR_E_FMD_BADACCESSFLAG);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Final/NewSlot must be virtual
+ if((IsMdFinal(dwFlags)||IsMdNewSlot(dwFlags)||IsMdCheckAccessOnOverride(dwFlags))
+ && !IsMdVirtual(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_MD_FINNOTVIRT);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Static can't be final or virtual
+ if(IsMdStatic(dwFlags))
+ {
+ if(IsMdFinal(dwFlags) || IsMdVirtual(dwFlags) || IsMdNewSlot(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_MD_STATANDFINORVIRT);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ else // non-static can't be an entry point
+ {
+ if(g_tkEntryPoint == veCtxt.Token)
+ {
+ REPORT_ERROR0(VLDTR_E_EP_INSTANCE);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ if(IsMdAbstract(dwFlags))
+ {
+ // Can't be both abstract and final
+ if(IsMdFinal(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_MD_ABSTANDFINAL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // If abstract, must be not miForwardRef, not Pinvoke, and must be virtual
+ if(IsMiForwardRef(dwImplFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_MD_ABSTANDIMPL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ if(IsMdPinvokeImpl(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_MD_ABSTANDPINVOKE);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ if(!IsMdVirtual(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_MD_ABSTNOTVIRT);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ // If PrivateScope, must have RVA!=0
+ if(IsMdPrivateScope(dwFlags) && (pRecord->GetRVA() ==0))
+ {
+ REPORT_ERROR0(VLDTR_E_MD_PRIVSCOPENORVA);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // RTSpecialName => SpecialName
+ if(IsMdRTSpecialName(dwFlags) && !IsMdSpecialName(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_FMD_RTSNNOTSN);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Method having security must be marked mdHasSecurity and vice versa
+ {
+ ULONG ridStart = 1;
+ ULONG ridEnd = pMiniMd->getCountDeclSecuritys() + 1;
+ ULONG index;
+ BOOL bHasSecurity = FALSE;
+ for (index = ridStart; index < ridEnd; index ++ )
+ {
+ DeclSecurityRec *pDeclSecurityRecord;
+ IfFailGo(pMiniMd->GetDeclSecurityRecord(index, &pDeclSecurityRecord));
+ if ( veCtxt.Token == pMiniMd->getParentOfDeclSecurity(pDeclSecurityRecord))
+ {
+ bHasSecurity = TRUE;
+ break;
+ }
+ }
+ if(!bHasSecurity) // No records, check for CA "SuppressUnmanagedCodeSecurityAttribute"
+ {
+ bHasSecurity = (S_OK == ImportHelper::GetCustomAttributeByName(pMiniMd, veCtxt.Token,
+ "System.Security.SuppressUnmanagedCodeSecurityAttribute", NULL, NULL));
+ }
+ if(bHasSecurity != (IsMdHasSecurity(dwFlags)!=0))
+ {
+ REPORT_ERROR0(bHasSecurity ? VLDTR_E_FMD_SECURNOTMARKED : VLDTR_E_FMD_MARKEDNOSECUR);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ // Validate method semantics
+ {
+ MethodSemanticsRec *pRec;
+ ULONG ridEnd;
+ ULONG index;
+ unsigned uTally = 0;
+ mdToken tkEventProp;
+ ULONG iCount;
+ DWORD dwSemantic;
+ // get the range of method rids given a typedef
+ ridEnd = pMiniMd->getCountMethodSemantics();
+
+ for (index = 1; index <= ridEnd; index++ )
+ {
+ IfFailGo(pMiniMd->GetMethodSemanticsRecord(index, &pRec));
+ if ( pMiniMd->getMethodOfMethodSemantics(pRec) == veCtxt.Token )
+ {
+ uTally++;
+ if(uTally > 1)
+ {
+ REPORT_ERROR0(VLDTR_E_MD_MULTIPLESEMANTICS);
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ }
+ tkEventProp = pMiniMd->getAssociationOfMethodSemantics(pRec);
+ if((TypeFromToken(tkEventProp) == mdtEvent)||(TypeFromToken(tkEventProp) == mdtProperty))
+ {
+ iCount = (TypeFromToken(tkEventProp) == mdtEvent) ? pMiniMd->getCountEvents() :
+ pMiniMd->getCountPropertys();
+ if(RidFromToken(tkEventProp) > iCount)
+ {
+ REPORT_ERROR1(VLDTR_E_MD_SEMANTICSNOTEXIST, tkEventProp);
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ }
+ }
+ else
+ {
+ REPORT_ERROR1(VLDTR_E_MD_INVALIDSEMANTICS, tkEventProp);
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ }
+ // One and only one semantics flag must be set
+ iCount = 0;
+ dwSemantic = pRec->GetSemantic();
+ if(IsMsSetter(dwSemantic)) iCount++;
+ if(IsMsGetter(dwSemantic)) iCount++;
+ if(IsMsOther(dwSemantic)) iCount++;
+ if(IsMsAddOn(dwSemantic)) iCount++;
+ if(IsMsRemoveOn(dwSemantic)) iCount++;
+ if(IsMsFire(dwSemantic)) iCount++;
+ if(iCount != 1)
+ {
+ REPORT_ERROR1(iCount ? VLDTR_E_MD_MULTSEMANTICFLAGS : VLDTR_E_MD_NOSEMANTICFLAGS, tkEventProp);
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ }
+ }
+ }// end for(index)
+ }
+ // Check the method's impl.map
+ {
+ RID iRecord;
+ IfFailGo(pMiniMd->FindImplMapHelper(veCtxt.Token, &iRecord));
+ if(IsMdPinvokeImpl(dwFlags))
+ {
+ // must be static
+ if(!IsMdStatic(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_FMD_PINVOKENOTSTATIC);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // must have either ImplMap or RVA == 0
+ if (InvalidRid(iRecord))
+ {
+ if(pRecord->GetRVA()==0)
+ {
+ REPORT_ERROR0(VLDTR_E_FMD_MARKEDNOPINVOKE);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ else
+ {
+ if(pRecord->GetRVA()!=0)
+ {
+ // C++ emits ImplMaps for IJW methods,
+ // with resolution=ModuleRef with name ""
+ ImplMapRec *pIMRecord;
+ mdToken tkModuleRef;
+ IfFailGo(pMiniMd->GetImplMapRecord(iRecord, &pIMRecord));
+ tkModuleRef = pMiniMd->getImportScopeOfImplMap(pIMRecord);
+ if((TypeFromToken(tkModuleRef) == mdtModuleRef) && (!IsNilToken(tkModuleRef)))
+ {
+ ModuleRefRec *pMRRecord; // ModuleRef record.
+ LPCUTF8 szMRName; // ModuleRef name.
+ // Get the ModuleRef record.
+ IfFailGo(pMiniMd->GetModuleRefRecord(RidFromToken(tkModuleRef), &pMRRecord));
+ // Check ModuleRef name is "".
+ IfFailGo(pMiniMd->getNameOfModuleRef(pMRRecord, &szMRName));
+ if (*szMRName)
+ {
+ REPORT_ERROR0(VLDTR_E_MD_RVAANDIMPLMAP);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ }
+ else
+ {
+ hr = ValidateImplMap(iRecord);
+ if(hr != S_OK)
+ {
+ REPORT_ERROR0(VLDTR_E_FMD_BADIMPLMAP);
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ }
+ }
+ }
+
+ }
+ else
+ {
+ // must have no ImplMap
+ if (!InvalidRid(iRecord))
+ {
+ REPORT_ERROR0(VLDTR_E_FMD_PINVOKENOTMARKED);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ }
+ // Validate params
+ {
+ ULONG ridStart = pMiniMd->getParamListOfMethod(pRecord);
+ ULONG ridEnd;
+ IfFailGo(pMiniMd->getEndParamListOfMethod(rid, &ridEnd));
+ ParamRec* pRec;
+ ULONG cbSigT;
+ PCCOR_SIGNATURE typePtr;
+ IfFailGo(pMiniMd->getSignatureOfMethod(pRecord, &typePtr, &cbSigT));
+ unsigned callConv = CorSigUncompressData(typePtr); // get the calling convention out of the way
+ unsigned numTyArgs = 0;
+ if (callConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
+ {
+ bIsGeneric = TRUE;
+ numTyArgs = CorSigUncompressData(typePtr);
+ }
+
+ unsigned numArgs = CorSigUncompressData(typePtr);
+ USHORT usPrevSeq = 0;
+
+ for(ULONG ridP = ridStart; ridP < ridEnd; ridP++)
+ {
+ RID tempRid;
+ IfFailGo(pMiniMd->GetParamRecord(ridP, &pRec));
+ // Sequence order must be ascending
+ if(ridP > ridStart)
+ {
+ if(pRec->GetSequence() <= usPrevSeq)
+ {
+ REPORT_ERROR2(VLDTR_E_MD_PARAMOUTOFSEQ, ridP-ridStart,pRec->GetSequence());
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ }
+ }
+ usPrevSeq = pRec->GetSequence();
+ // Sequence value must not exceed num of arguments
+ if(usPrevSeq > numArgs)
+ {
+ REPORT_ERROR2(VLDTR_E_MD_PARASEQTOOBIG, ridP-ridStart,usPrevSeq);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Param having marshaling must be marked pdHasFieldMarshal and vice versa
+ IfFailGo(pMiniMd->FindFieldMarshalHelper(TokenFromRid(ridP,mdtParamDef), &tempRid));
+ if (InvalidRid(tempRid) == (IsPdHasFieldMarshal(pRec->GetFlags()) != 0))
+ {
+ REPORT_ERROR1(IsPdHasFieldMarshal(pRec->GetFlags()) ? VLDTR_E_MD_PARMMARKEDNOMARSHAL
+ : VLDTR_E_MD_PARMMARSHALNOTMARKED, ridP-ridStart);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Param having const value must be marked pdHasDefault and vice versa
+ IfFailGo(pMiniMd->FindConstantHelper(TokenFromRid(ridP,mdtParamDef), &tempRid));
+ if (InvalidRid(tempRid) == (IsPdHasDefault(pRec->GetFlags()) != 0))
+ {
+ REPORT_ERROR1(IsPdHasDefault(pRec->GetFlags()) ? VLDTR_E_MD_PARMMARKEDNODEFLT
+ : VLDTR_E_MD_PARMDEFLTNOTMARKED, ridP-ridStart);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ }
+
+ // Generic Method related checks
+ if (bIsGeneric)
+ {
+ if (bIsCctor)
+ {
+ REPORT_ERROR0(VLDTR_E_MD_GENERIC_CCTOR);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ if (bIsCtor)
+ {
+ REPORT_ERROR0(VLDTR_E_MD_GENERIC_CTOR);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ if (bIsParentImport)
+ {
+ REPORT_ERROR0(VLDTR_E_MD_GENERIC_IMPORT);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ }
+
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateMethod()
+#ifdef _PREFAST_
+#pragma warning(pop)
+#endif
+
+//*****************************************************************************
+// Validate the given ParamPtr.
+//*****************************************************************************
+HRESULT RegMeta::ValidateParamPtr(RID rid)
+{
+ return S_OK;
+} // RegMeta::ValidateParamPtr()
+
+//*****************************************************************************
+// Validate the given Param.
+//*****************************************************************************
+HRESULT RegMeta::ValidateParam(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
+ ParamRec *pRecord; // Param record
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+ LPCSTR szName; // Param name.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+
+ // Get the InterfaceImpl record.
+ veCtxt.Token = TokenFromRid(rid, mdtParamDef);
+ veCtxt.uOffset = 0;
+
+ DWORD dwBadFlags = 0;
+ DWORD dwFlags = 0;
+ IfFailGo(pMiniMd->GetParamRecord(rid, &pRecord));
+ // Name, if any, must not exceed MAX_CLASSNAME_LENGTH
+ IfFailGo(pMiniMd->getNameOfParam(pRecord, &szName));
+ ULONG L = (ULONG)strlen(szName);
+ if(L >= MAX_CLASSNAME_LENGTH)
+ {
+ REPORT_ERROR2(VLDTR_E_TD_NAMETOOLONG, L, (ULONG)(MAX_CLASSNAME_LENGTH-1));
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Flags must be as defined in CorHdr.h
+ dwBadFlags = ~(pdIn | pdOut | pdOptional | pdHasDefault | pdHasFieldMarshal);
+ dwFlags = pRecord->GetFlags();
+ if(dwFlags & dwBadFlags)
+ {
+ REPORT_ERROR1(VLDTR_E_PD_BADFLAGS, dwFlags);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateParam()
+
+//*****************************************************************************
+// Helper function for ValidateInterfaceImpl
+//*****************************************************************************
+int IsMethodImplementedByClass(CMiniMdRW *pMiniMd,
+ mdToken tkMethod,
+ LPCUTF8 szName,
+ PCCOR_SIGNATURE pSig,
+ ULONG cbSig,
+ mdToken tkClass)
+{
+ HRESULT hr;
+ int numImpl = 0;
+ if(TypeFromToken(tkMethod) == mdtMethodDef)
+ {
+ if(TypeFromToken(tkClass) == mdtTypeSpec)
+ {
+ // We are trying to find out if an interface method is implemented in the generic class tkClass.
+ // Simple signature comparison doesn't work here, because "int Method()" in the interface might
+ // be implemented by "T Type.Method()" in the generic type.
+ // Therefore we assume it is implemented. Atlernatively we could implement better signature
+ // comparison which would match T with any other type, etc.
+ numImpl = 1;
+ }
+ else if(TypeFromToken(tkClass) == mdtTypeDef)
+ {
+ TypeDefRec *pClass;
+ IfFailRet(pMiniMd->GetTypeDefRecord(RidFromToken(tkClass), &pClass));
+ RID ridClsStart = pMiniMd->getMethodListOfTypeDef(pClass);
+ RID ridClsEnd;
+ IfFailRet(pMiniMd->getEndMethodListOfTypeDef(RidFromToken(tkClass), &ridClsEnd));
+ mdMethodDef tkFoundMethod = 0;
+ DWORD dwFoundMethodFlags = 0;
+ // Check among methods
+ hr = ImportHelper::FindMethod(pMiniMd, tkClass, szName, pSig, cbSig, &tkFoundMethod, 0);
+ if(SUCCEEDED(hr))
+ {
+ MethodRec * pMethod;
+ IfFailRet(pMiniMd->GetMethodRecord(RidFromToken(tkFoundMethod), &pMethod));
+ if(pMethod)
+ {
+ dwFoundMethodFlags = pMiniMd->getFlagsOfMethod(pMethod);
+ if(IsMdVirtual(dwFoundMethodFlags)) //&&!IsMdNewSlot(dwFoundMethodFlags))
+ numImpl = 1;
+ }
+ }
+ if (numImpl==0) //if(hr == CLDB_E_RECORD_NOTFOUND)
+ { // Check among MethodImpls
+ RID ridImpl;
+ for(RID idxCls = ridClsStart; idxCls < ridClsEnd; idxCls++)
+ {
+ RID ridCls;
+ IfFailRet(pMiniMd->GetMethodRid(idxCls, &ridCls));
+
+ hr = ImportHelper::FindMethodImpl(pMiniMd,tkClass,TokenFromRid(ridCls,mdtMethodDef),
+ tkMethod,&ridImpl);
+ if(hr != CLDB_E_RECORD_NOTFOUND)
+ {
+ if(SUCCEEDED(hr)) numImpl++;
+ break;
+ }
+ }
+ if(numImpl == 0)
+ {
+ // Check if parent class implements this method
+ mdToken tkParent = pMiniMd->getExtendsOfTypeDef(pClass);
+ if(RidFromToken(tkParent))
+ numImpl = IsMethodImplementedByClass(pMiniMd,tkMethod,szName,pSig,cbSig,tkParent);
+ }
+ }
+ }
+ else if (TypeFromToken(tkClass) == mdtTypeRef)
+ {
+ TypeRefRec *pRecord; // TypeRef record.
+ LPCSTR szTRNamespace; // TypeRef Namespace.
+ LPCSTR szTRName; // TypeRef Name.
+
+ // Get the TypeRef record.
+ IfFailRet(pMiniMd->GetTypeRefRecord(RidFromToken(tkClass), &pRecord));
+
+ // Check name is not NULL.
+ IfFailRet(pMiniMd->getNamespaceOfTypeRef(pRecord, &szTRNamespace));
+ IfFailRet(pMiniMd->getNameOfTypeRef(pRecord, &szTRName));
+
+ mdToken tkRefScope = pMiniMd->getResolutionScopeOfTypeRef(pRecord);
+ if (tkRefScope == TokenFromRid(1, mdtModule))
+ {
+ // if the typeref is referring to a type in this module then
+ // we should check the type definition it is referring to
+ mdTypeDef tkTypeDef;
+ hr = ImportHelper::FindTypeDefByName(pMiniMd, szTRNamespace, szTRName, tkRefScope, &tkTypeDef);
+ if (SUCCEEDED(hr))
+ numImpl = IsMethodImplementedByClass(pMiniMd, tkMethod, szName, pSig, cbSig, tkTypeDef);
+ }
+ else if ((strcmp(szTRNamespace, BASE_NAMESPACE) == 0) &&
+ ((strcmp(szTRName, BASE_OBJECT_CLASSNAME) == 0) ||
+ (strcmp(szTRName, BASE_VTYPE_CLASSNAME) == 0) ||
+ (strcmp(szTRName, BASE_ENUM_CLASSNAME) == 0)))
+ {
+ if (((strcmp(szName, SYSTEM_OBJECT_TOSTRING_METHODNAME) == 0) &&
+ (cbSig == _countof(g_sigSystemObject_ToString)) &&
+ (memcmp(pSig, g_sigSystemObject_ToString, cbSig) == 0)) ||
+ ((strcmp(szName, SYSTEM_OBJECT_GETHASHCODE_METHODNAME) == 0) &&
+ (cbSig == _countof(g_sigSystemObject_GetHashCode)) &&
+ (memcmp(pSig, g_sigSystemObject_GetHashCode, cbSig) == 0)) ||
+ ((strcmp(szName, SYSTEM_OBJECT_EQUALS_METHODNAME) == 0) &&
+ (cbSig == _countof(g_sigSystemObject_Equals)) &&
+ (memcmp(pSig, g_sigSystemObject_Equals, cbSig) == 0)))
+ {
+ numImpl = 1; // Method signature matches one of System.Object's virtual methods
+ }
+ else
+ {
+ numImpl = 0; // These classes (System.Object, System.ValueType and System.Enum) don't implement any other virtual methods
+ }
+ }
+ else
+ {
+ numImpl = -1; // The method is defined in another module, we cannot verify it (no external modules are loaded)
+ }
+ }
+ }
+ return numImpl;
+}
+
+//*****************************************************************************
+// Validate the given InterfaceImpl.
+//*****************************************************************************
+//@todo GENERICS: complete logic for type specs
+// - for now, we just allow them, but we should be checking more properties
+HRESULT RegMeta::ValidateInterfaceImpl(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
+ InterfaceImplRec *pRecord; // InterfaceImpl record.
+ mdTypeDef tkClass; // Class implementing the interface.
+ mdToken tkInterface; // TypeDef for the interface.
+ mdInterfaceImpl tkInterfaceImpl; // Duplicate InterfaceImpl.
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+ BOOL fCheckTheMethods=TRUE;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+
+ // Get the InterfaceImpl record.
+ veCtxt.Token = TokenFromRid(rid, mdtInterfaceImpl);
+ veCtxt.uOffset = 0;
+
+ IfFailGo(pMiniMd->GetInterfaceImplRecord(rid, &pRecord));
+
+ // Get implementing Class and the TypeDef for the interface.
+ tkClass = pMiniMd->getClassOfInterfaceImpl(pRecord);
+
+ // No validation needs to be done on deleted records.
+ if (IsNilToken(tkClass))
+ goto ErrExit;
+
+ tkInterface = pMiniMd->getInterfaceOfInterfaceImpl(pRecord);
+
+ // Validate that the Class is TypeDef.
+ if((!IsValidToken(tkClass))||(TypeFromToken(tkClass) != mdtTypeDef)/*&&(TypeFromToken(tkClass) != mdtTypeRef)*/)
+ {
+ REPORT_ERROR1(VLDTR_E_IFACE_BADIMPL, tkClass);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ fCheckTheMethods = FALSE;
+ }
+ // Validate that the Interface is TypeDef or TypeRef or TypeSpec
+ if((!IsValidToken(tkInterface))||(TypeFromToken(tkInterface) != mdtTypeDef)&&(TypeFromToken(tkInterface) != mdtTypeRef)
+ &&(TypeFromToken(tkInterface) != mdtTypeSpec))
+ {
+ REPORT_ERROR1(VLDTR_E_IFACE_BADIFACE, tkInterface);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ fCheckTheMethods = FALSE;
+ }
+ // Validate that Interface is marked tdInterface.
+ else if(TypeFromToken(tkInterface) == mdtTypeDef)
+ {
+ TypeDefRec *pTDRec;
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkInterface), &pTDRec));
+ if(!IsTdInterface(pTDRec->GetFlags()))
+ {
+ REPORT_ERROR1(VLDTR_E_IFACE_NOTIFACE, tkInterface);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ }
+
+ // Look for duplicates.
+ hr = ImportHelper::FindInterfaceImpl(pMiniMd, tkClass, tkInterface,
+ &tkInterfaceImpl, rid);
+ if (hr == S_OK)
+ {
+ REPORT_ERROR1(VLDTR_E_IFACE_DUP, tkInterfaceImpl);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else if (hr == CLDB_E_RECORD_NOTFOUND)
+ hr = S_OK;
+ else
+ IfFailGo(hr);
+
+ // Validate that the Class (if not interface or abstract) implements all the methods of Interface
+ if((TypeFromToken(tkInterface) == mdtTypeDef) && fCheckTheMethods && (tkInterface != tkClass))
+ {
+ TypeDefRec *pClass;
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkClass), &pClass));
+ if(!(IsTdAbstract(pClass->GetFlags())
+ ||IsTdImport(pClass->GetFlags())
+ ||IsTdInterface(pClass->GetFlags())))
+ {
+ TypeDefRec *pInterface;
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkInterface), &pInterface));
+ RID ridIntStart = pMiniMd->getMethodListOfTypeDef(pInterface);
+ RID ridIntEnd;
+ IfFailGo(pMiniMd->getEndMethodListOfTypeDef(RidFromToken(tkInterface), &ridIntEnd));
+ MethodRec* pIntMethod;
+ for(RID idxInt = ridIntStart; idxInt < ridIntEnd; idxInt++)
+ {
+ RID ridInt;
+ IfFailGo(pMiniMd->GetMethodRid(idxInt, &ridInt));
+ IfFailGo(pMiniMd->GetMethodRecord(ridInt, &pIntMethod));
+ const char* szName;
+ IfFailGo(pMiniMd->getNameOfMethod(pIntMethod, &szName));
+ if(!IsMdStatic(pIntMethod->GetFlags())
+ && !IsDeletedName(szName)
+ && !IsVtblGapName(szName))
+ {
+ ULONG cbSig;
+ PCCOR_SIGNATURE pSig;
+ IfFailGo(pMiniMd->getSignatureOfMethod(pIntMethod, &pSig, &cbSig));
+ if(cbSig)
+ {
+ int num = IsMethodImplementedByClass(pMiniMd,TokenFromRid(ridInt,mdtMethodDef),szName,pSig,cbSig,tkClass);
+ if(num == 0)
+ { // Error: method not implemented
+ REPORT_ERROR3(VLDTR_E_IFACE_METHNOTIMPL, tkClass, tkInterface, TokenFromRid(ridInt,mdtMethodDef));
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ if(num == -1)
+ {
+ // Traced to a TypeRef, which might implement the method, give warning
+ REPORT_ERROR3(VLDTR_E_IFACE_METHNOTIMPLTHISMOD, tkClass, tkInterface, TokenFromRid(ridInt,mdtMethodDef));
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ }
+ if(num > 1)
+ { // Error: multiple method implementation
+ REPORT_ERROR3(VLDTR_E_IFACE_METHMULTIMPL, tkClass, tkInterface, TokenFromRid(ridInt,mdtMethodDef));
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ }
+ }
+ }
+ }
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateInterfaceImpl()
+
+//*****************************************************************************
+// Validate the given GenericParam.
+//*****************************************************************************
+HRESULT RegMeta::ValidateGenericParam(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
+ GenericParamRec *pRecord; // GenericParam record.
+ LPCSTR szName; // GenericParam name field.
+ mdToken tkOwner; // GenericParam owner field.
+ ULONG ulNumber; // GenericParam number field.
+ DWORD dwFlags; // GenericParam flags field
+
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+
+ // Get the GenericParam record.
+ veCtxt.Token = TokenFromRid(rid, mdtGenericParam);
+ veCtxt.uOffset = 0;
+ IfFailGo(pMiniMd->GetGenericParamRecord(rid, &pRecord));
+
+ // 1. GenericParam may contain zero or more rows.
+ // (Nothing to check.)
+
+ tkOwner = pMiniMd->getOwnerOfGenericParam(pRecord);
+ // 2. Owner must be a valid token and a type def or method def
+ // (Already checked by ValidateRecord)
+
+ // CLR tolerates Nil owners, ECMA does not
+ if(IsNilToken(tkOwner))
+ {
+ REPORT_ERROR0(VLDTR_E_GP_OWNERNIL);
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ }
+
+ //3. Every generic type shall own one row in the Generic Param table for each of its type parameters. [ERROR]
+ // (Nothing to check, as the arity of a generic type is, by definition, the number of generic param entries).
+
+ //4. Every generic method shall own one row in the Generic Param table for each of its type parameters. [ERROR]
+ // (This is checked in ValidateMethodSig, error VLDTR_E_MD_GPMISMATCH).
+
+ ulNumber = pMiniMd->getNumberOfGenericParam(pRecord);
+
+ // 5. Flags must be valid
+ {
+ DWORD dwInvalidMask, dwExtraBits;
+
+ dwFlags = pMiniMd->getFlagsOfGenericParam(pRecord);
+
+
+ // check for extra bits
+ dwInvalidMask = (DWORD)~(gpVarianceMask|gpSpecialConstraintMask);
+ dwExtraBits = dwFlags & dwInvalidMask;
+ if(dwExtraBits)
+ {
+ //@GENERICS: we could use a custom error,
+ // but this is one is already used in more than one context.
+ REPORT_ERROR1(VLDTR_E_TD_EXTRAFLAGS, dwExtraBits);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ //Check Variance
+ {
+ DWORD dwVariance = dwFlags & gpVarianceMask;
+ switch (dwVariance)
+ {
+ case gpNonVariant:
+ // always ok
+ break;
+ case gpCovariant:
+ case gpContravariant:
+ if (TypeFromToken(tkOwner)==mdtTypeDef)
+ {
+ if (IsNilToken(tkOwner))
+ break;
+ TypeDefRec *pTypeDefRec;
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkOwner), &pTypeDefRec));
+ // co-contra variance only legal on interfaces and delegates
+ // If owner is not an interface and does not extend MultiCastDelegate, report an error
+ if(!IsTdInterface(pTypeDefRec->GetFlags()))
+ {
+ // Get the parent of the TypeDef.
+ mdToken tkExtends = pMiniMd->getExtendsOfTypeDef(pTypeDefRec);
+ LPCSTR szExtName = NULL; // Parent Name.
+ LPCSTR szExtNameSpace = NULL; // Parent NameSpace.
+ BOOL bExtendsMCDelegate = FALSE;
+
+ // Determine if the parent is MCDelegate
+ if (TypeFromToken(tkExtends) != mdtTypeSpec)
+ {
+ if (TypeFromToken(tkExtends) == mdtTypeRef)
+ {
+ TypeRefRec *pExtTypeRefRec;
+ IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tkExtends), &pExtTypeRefRec));
+ mdToken tkResScope = pMiniMd->getResolutionScopeOfTypeRef(pExtTypeRefRec);
+ if (RidFromToken(tkResScope) && (TypeFromToken(tkResScope) == mdtAssemblyRef))
+ {
+ AssemblyRefRec * pARRec;
+ IfFailGo(pMiniMd->GetAssemblyRefRecord(RidFromToken(tkResScope), &pARRec));
+ LPCSTR szAssemblyRefName;
+ IfFailGo(pMiniMd->getNameOfAssemblyRef(pARRec, &szAssemblyRefName));
+ if ((0 == SString::_stricmp("mscorlib", szAssemblyRefName)) || (0 == SString::_stricmp("System.Runtime", szAssemblyRefName)))
+ // otherwise don't even bother extracting the name
+ {
+ IfFailGo(pMiniMd->getNameOfTypeRef(pExtTypeRefRec, &szExtName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pExtTypeRefRec, &szExtNameSpace));
+ }
+ }
+ }
+ else if (TypeFromToken(tkExtends) == mdtTypeDef)
+ {
+ if (g_fValidatingMscorlib) // otherwise don't even bother extracting the name
+ {
+ TypeDefRec * pExtTypeRefRec;
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkExtends), &pExtTypeRefRec));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pExtTypeRefRec, &szExtName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pExtTypeRefRec, &szExtNameSpace));
+ }
+ }
+
+ bExtendsMCDelegate =
+ szExtNameSpace && szExtName &&
+ (0 == strcmp(szExtNameSpace,BASE_NAMESPACE)) &&
+ (0 == strcmp(szExtName,BASE_MCDELEGATE_CLASSNAME));
+ }
+
+ // Report any error
+ if (!bExtendsMCDelegate)
+ {
+ REPORT_ERROR1(VLDTR_E_GP_UNEXPECTED_OWNER_FOR_VARIANT_VAR,tkOwner);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ }
+ else
+ {
+ // co-contra variance never legal on MVARs
+ REPORT_ERROR0(VLDTR_E_GP_ILLEGAL_VARIANT_MVAR);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ break;
+ default:
+ REPORT_ERROR1(VLDTR_E_GP_ILLEGAL_VARIANCE_FLAGS,dwFlags);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ }
+ }
+
+ // Check special constraints
+ {
+ DWORD dwSpecialConstraints = dwFlags & gpSpecialConstraintMask;
+ // It is illegal go declare both gpNotNullableValueTypeConstraint
+ // and gpReferenceTypeConstraint, but gpDefaultConstructorConstraint
+ // is legal with either (or neither).
+ if ((dwSpecialConstraints & (gpReferenceTypeConstraint | gpNotNullableValueTypeConstraint)) ==
+ (gpReferenceTypeConstraint | gpNotNullableValueTypeConstraint))
+ {
+ REPORT_ERROR1(VLDTR_E_GP_REFANDVALUETYPE,dwFlags);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ }
+
+ // 6. Number shall have a value >=0 and < number of type parameters in owner type or method.
+ // 7. Successive rows of the GenericParam table that are owned by the same method (sic) (owner?) shall
+ // be ordered by increasing Number value; there can be no gaps in the Number sequence.
+ {
+ if(ulNumber>0)
+ { if(rid==1)
+ {
+ REPORT_ERROR0(VLDTR_E_GP_NONSEQ_BY_NUMBER);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ {
+ GenericParamRec *pPredRecord;
+ IfFailGo(pMiniMd->GetGenericParamRecord(rid-1, &pPredRecord));
+ mdToken tkPredOwner = pMiniMd->getOwnerOfGenericParam(pPredRecord);
+ ULONG ulPredNumber = pMiniMd->getNumberOfGenericParam(pPredRecord);
+ if (tkPredOwner != tkOwner)
+ {
+ REPORT_ERROR0(VLDTR_E_GP_NONSEQ_BY_OWNER);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ if (ulPredNumber != ulNumber-1)
+ {
+ REPORT_ERROR0(VLDTR_E_GP_NONSEQ_BY_NUMBER);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ }
+ }
+
+ // 8. Name must be non-null and not too long
+ IfFailGo(pMiniMd->getNameOfGenericParam(pRecord, &szName));
+ if (!*szName)
+ {
+ // name is NULL.
+ REPORT_ERROR0(VLDTR_E_GP_NAMENULL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ {
+ if(!strcmp(szName,COR_DELETED_NAME_A)) goto ErrExit; //@GENERICS: do we allow parameters to be deleted?
+ ULONG L = (ULONG)strlen(szName);
+ if(L >= MAX_CLASSNAME_LENGTH)
+ {
+ REPORT_ERROR2(VLDTR_E_TD_NAMETOOLONG, L, (ULONG)(MAX_CLASSNAME_LENGTH-1));
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+
+#ifdef THIS_RULE_IS_DISABLED_BECAUSE_CSHARP_EMITS_DUP_NAMES_AND_DOESNT_WANT_TO_STOP
+ // 9. There shall be no duplicates based upon Owner and Name
+ if (szName)
+ {
+ mdGenericParam tkDupGenericParam;
+ hr = ImportHelper::FindGenericParamByOwner(pMiniMd, tkOwner, szName, NULL, &tkDupGenericParam, rid);
+ if (hr == S_OK)
+ {
+ REPORT_ERROR1(VLDTR_E_GP_DUPNAME, tkDupGenericParam);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else if (hr == CLDB_E_RECORD_NOTFOUND)
+ hr = S_OK;
+ else
+ IfFailGo(hr);
+ }
+#endif
+
+ // 10. There shall be no duplicates based upon Owner and Number
+ {
+ mdGenericParam tkDupGenericParam;
+ hr = ImportHelper::FindGenericParamByOwner(pMiniMd, tkOwner, NULL, &ulNumber, &tkDupGenericParam, rid);
+ if (hr == S_OK)
+ {
+ REPORT_ERROR1(VLDTR_E_GP_DUPNUMBER, tkDupGenericParam);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else if (hr == CLDB_E_RECORD_NOTFOUND)
+ hr = S_OK;
+ else
+ IfFailGo(hr);
+ }
+
+ hr = hrSave;
+
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateGenericParam()
+
+//*****************************************************************************
+// Validate the given MemberRef.
+//*****************************************************************************
+HRESULT RegMeta::ValidateMemberRef(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
+ MemberRefRec *pRecord; // MemberRef record.
+ mdMemberRef tkMemberRef; // Duplicate MemberRef.
+ mdToken tkClass; // MemberRef parent.
+ LPCSTR szName; // MemberRef name.
+ PCCOR_SIGNATURE pbSig; // MemberRef signature.
+ PCCOR_SIGNATURE pbSigTmp; // Temp copy of pbSig, so that can be changed.
+ ULONG cbSig; // Size of sig in bytes.
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+
+ // Get the MemberRef record.
+ veCtxt.Token = TokenFromRid(rid, mdtMemberRef);
+ veCtxt.uOffset = 0;
+
+ IfFailGo(pMiniMd->GetMemberRefRecord(rid, &pRecord));
+
+ // Do checks for name validity.
+ IfFailGo(pMiniMd->getNameOfMemberRef(pRecord, &szName));
+ if (!*szName)
+ {
+ REPORT_ERROR0(VLDTR_E_MR_NAMENULL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ {
+ if (IsVtblGapName(szName))
+ {
+ REPORT_ERROR0(VLDTR_E_MR_VTBLNAME);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else if (IsDeletedName(szName))
+ {
+ REPORT_ERROR0(VLDTR_E_MR_DELNAME);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ ULONG L = (ULONG)strlen(szName);
+ if(L >= MAX_CLASSNAME_LENGTH)
+ {
+ // Name too long
+ REPORT_ERROR2(VLDTR_E_TD_NAMETOOLONG, L, (ULONG)(MAX_CLASSNAME_LENGTH-1));
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+
+ // MemberRef parent should never be nil in a PE file.
+ tkClass = pMiniMd->getClassOfMemberRef(pRecord);
+ if (m_ModuleType == ValidatorModuleTypePE && IsNilToken(tkClass))
+ {
+ REPORT_ERROR0(VLDTR_E_MR_PARNIL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Verify that the signature is a valid signature as per signature spec.
+ IfFailGo(pMiniMd->getSignatureOfMemberRef(pRecord, &pbSig, &cbSig));
+
+ // Do some semantic checks based on the signature.
+ if (hr == S_OK)
+ {
+ ULONG ulCallingConv;
+ ULONG ulArgCount;
+ ULONG ulTyArgCount = 0;
+ ULONG ulCurByte = 0;
+
+ // Extract calling convention.
+ pbSigTmp = pbSig;
+ ulCurByte += CorSigUncompressedDataSize(pbSigTmp);
+ ulCallingConv = CorSigUncompressData(pbSigTmp);
+
+ // Get the type argument count
+ if (ulCallingConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
+ {
+ ulCurByte += CorSigUncompressedDataSize(pbSigTmp);
+ ulTyArgCount = CorSigUncompressData(pbSigTmp);
+ }
+
+ // Get the argument count.
+ ulCurByte += CorSigUncompressedDataSize(pbSigTmp);
+ ulArgCount = CorSigUncompressData(pbSigTmp);
+
+ // Calling convention must be one of IMAGE_CEE_CS_CALLCONV_DEFAULT,
+ // IMAGE_CEE_CS_CALLCONV_VARARG or IMAGE_CEE_CS_CALLCONV_FIELD.
+ if (!isCallConv(ulCallingConv, IMAGE_CEE_CS_CALLCONV_DEFAULT) &&
+ !isCallConv(ulCallingConv, IMAGE_CEE_CS_CALLCONV_VARARG) &&
+ !isCallConv(ulCallingConv, IMAGE_CEE_CS_CALLCONV_FIELD))
+ {
+ REPORT_ERROR1(VLDTR_E_MR_BADCALLINGCONV, ulCallingConv);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // [CLS] Calling convention must not be VARARG
+ if(isCallConv(ulCallingConv, IMAGE_CEE_CS_CALLCONV_VARARG))
+ {
+ REPORT_ERROR0(VLDTR_E_MR_VARARGCALLINGCONV);
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ }
+
+ // If the parent is a MethodDef...
+ if (TypeFromToken(tkClass) == mdtMethodDef)
+ {
+ if (RidFromToken(tkClass) != 0)
+ {
+ // The MethodDef must be the same name and the fixed part of the
+ // vararg signature must be the same.
+ MethodRec *pMethodRecord; // Method Record.
+ LPCSTR szMethodName; // Method name.
+ PCCOR_SIGNATURE pbMethodSig; // Method signature.
+ ULONG cbMethodSig; // Size in bytes of signature.
+
+ // Get Method record, name and signature.
+ IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(tkClass), &pMethodRecord));
+ IfFailGo(pMiniMd->getNameOfMethod(pMethodRecord, &szMethodName));
+ IfFailGo(pMiniMd->getSignatureOfMethod(pMethodRecord, &pbMethodSig, &cbMethodSig));
+
+ // Verify that the name of the Method is the same as the MemberRef.
+ if (strcmp(szName, szMethodName))
+ {
+ REPORT_ERROR1(VLDTR_E_MR_NAMEDIFF, tkClass);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ if (isCallConv(ulCallingConv, IMAGE_CEE_CS_CALLCONV_VARARG))
+ { // It's VARARG calling convention
+ CQuickBytes qbFixedSig; // Quick bytes to hold the fixed part of the variable signature.
+ ULONG cbFixedSig; // Size in bytes of the fixed part.
+
+ // Get the fixed part of the vararg signature of the MemberRef.
+ hr = _GetFixedSigOfVarArg(pbSig, cbSig, &qbFixedSig, &cbFixedSig);
+ if (FAILED(hr) || cbFixedSig != cbMethodSig ||
+ memcmp(pbMethodSig, qbFixedSig.Ptr(), cbFixedSig))
+ {
+ UnifiedAssemblySigComparer uasc(*this);
+ MDSigComparer sc(MDSigParser(pbMethodSig, cbMethodSig),
+ MDSigParser((PCCOR_SIGNATURE)qbFixedSig.Ptr(), cbFixedSig),
+ uasc);
+
+ hr = sc.CompareMethodSignature();
+ if (FAILED(hr))
+ {
+ hr = S_OK;
+ REPORT_ERROR1(VLDTR_E_MR_SIGDIFF, tkClass);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ }
+ else
+ { // It's not VARARG calling convention - a MemberRef is referencing MethodDef (part of
+ // NoPIA)
+ UnifiedAssemblySigComparer uasc(*this);
+ MDSigComparer sc(MDSigParser(pbMethodSig, cbMethodSig),
+ MDSigParser(pbSig, cbSig),
+ uasc);
+
+ // Compare signatures
+ hr = sc.CompareMethodSignature();
+ if (FAILED(hr))
+ {
+ hr = S_OK;
+ REPORT_ERROR1(VLDTR_E_MR_SIGDIFF, tkClass);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ }
+ }
+
+ // There should be no duplicate MemberRefs.
+ if (*szName && pbSig && cbSig)
+ {
+ hr = ImportHelper::FindMemberRef(pMiniMd, tkClass, szName, pbSig,
+ cbSig, &tkMemberRef, rid,
+ ImportHelper::CreateHash); // Optimize for multiple calls
+ if (hr == S_OK)
+ {
+ REPORT_ERROR1(VLDTR_E_MR_DUP, tkMemberRef);
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ }
+ else if (hr == CLDB_E_RECORD_NOTFOUND)
+ {
+ hr = S_OK;
+ }
+ else
+ {
+ IfFailGo(hr);
+ }
+ }
+
+ if (!isCallConv(ulCallingConv, IMAGE_CEE_CS_CALLCONV_FIELD))
+ {
+ hr = ValidateMethodSig(veCtxt.Token,pbSig, cbSig,0);
+ SetVldtrCode(&hrSave,hr);
+ }
+ }
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateMemberRef()
+
+//*****************************************************************************
+// Validate the given Constant.
+//*****************************************************************************
+HRESULT RegMeta::ValidateConstant(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
+ ConstantRec *pRecord; // Constant record.
+ mdToken tkParent; // Constant parent.
+ const VOID* pbBlob; // Constant value blob ptr
+ DWORD cbBlob; // Constant value blob size
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+
+ // Get the MemberRef record.
+ veCtxt.Token = rid;
+ veCtxt.uOffset = 0;
+
+ ULONG maxrid = 0;
+ ULONG typ = 0;
+ IfFailGo(pMiniMd->GetConstantRecord(rid, &pRecord));
+ IfFailGo(pMiniMd->getValueOfConstant(pRecord, (const BYTE **)&pbBlob, &cbBlob));
+ switch(pRecord->GetType())
+ {
+ case ELEMENT_TYPE_BOOLEAN:
+ case ELEMENT_TYPE_CHAR:
+ case ELEMENT_TYPE_I1:
+ case ELEMENT_TYPE_U1:
+ case ELEMENT_TYPE_I2:
+ case ELEMENT_TYPE_U2:
+ case ELEMENT_TYPE_I4:
+ case ELEMENT_TYPE_U4:
+ case ELEMENT_TYPE_R4:
+ case ELEMENT_TYPE_I8:
+ case ELEMENT_TYPE_U8:
+ case ELEMENT_TYPE_R8:
+ if(pbBlob == NULL)
+ {
+ REPORT_ERROR1(VLDTR_E_CN_BLOBNULL, pRecord->GetType());
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ case ELEMENT_TYPE_STRING:
+ break;
+
+ case ELEMENT_TYPE_CLASS:
+ if(GET_UNALIGNED_32(pbBlob) != 0)
+ {
+ REPORT_ERROR1(VLDTR_E_CN_BLOBNOTNULL, pRecord->GetType());
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ break;
+
+ default:
+ REPORT_ERROR1(VLDTR_E_CN_BADTYPE, pRecord->GetType());
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ }
+ tkParent = pMiniMd->getParentOfConstant(pRecord);
+ typ = TypeFromToken(tkParent);
+ switch(typ)
+ {
+ case mdtFieldDef:
+ maxrid = pMiniMd->getCountFields();
+ break;
+ case mdtParamDef:
+ maxrid = pMiniMd->getCountParams();
+ break;
+ case mdtProperty:
+ maxrid = pMiniMd->getCountPropertys();
+ break;
+ }
+ switch(typ)
+ {
+ case mdtFieldDef:
+ case mdtParamDef:
+ case mdtProperty:
+ {
+ ULONG rid_p = RidFromToken(tkParent);
+ if((0==rid_p)||(rid_p > maxrid))
+ {
+ REPORT_ERROR1(VLDTR_E_CN_PARENTRANGE, tkParent);
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ }
+ break;
+ }
+
+ default:
+ REPORT_ERROR1(VLDTR_E_CN_PARENTTYPE, tkParent);
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ break;
+ }
+
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateConstant()
+
+//*****************************************************************************
+// Validate the given CustomAttribute.
+//*****************************************************************************
+HRESULT RegMeta::ValidateCustomAttribute(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CustomAttributeRec *pRecord;
+ IfFailGo(pMiniMd->GetCustomAttributeRecord(rid, &pRecord));
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+
+ veCtxt.Token = TokenFromRid(rid,mdtCustomAttribute);
+ veCtxt.uOffset = 0;
+
+ if (pRecord != NULL)
+ {
+ mdToken tkOwner = pMiniMd->getParentOfCustomAttribute(pRecord);
+ if(RidFromToken(tkOwner))
+ { // if 0, it's deleted CA, don't pay attention
+ mdToken tkCAType = pMiniMd->getTypeOfCustomAttribute(pRecord);
+ DWORD cbValue=0;
+ const BYTE *pbValue;
+ IfFailGo(pMiniMd->getValueOfCustomAttribute(pRecord, &pbValue, &cbValue));
+ if((TypeFromToken(tkOwner)==mdtCustomAttribute)||(!IsValidToken(tkOwner)))
+ {
+ REPORT_ERROR1(VLDTR_E_CA_BADPARENT, tkOwner);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ if(((TypeFromToken(tkCAType)!=mdtMethodDef)&&(TypeFromToken(tkCAType)!=mdtMemberRef))
+ ||(!IsValidToken(tkCAType))||(RidFromToken(tkCAType)==0))
+ {
+ REPORT_ERROR1(VLDTR_E_CA_BADTYPE, tkCAType);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ { //i.e. Type is valid MethodDef or MemberRef
+ LPCUTF8 szName;
+ PCCOR_SIGNATURE pSig=NULL;
+ DWORD cbSig=0;
+ DWORD dwFlags=0;
+ if (TypeFromToken(tkCAType) == mdtMethodDef)
+ {
+ MethodRec *pTypeRec;
+ IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(tkCAType), &pTypeRec));
+ IfFailGo(pMiniMd->getNameOfMethod(pTypeRec, &szName));
+ IfFailGo(pMiniMd->getSignatureOfMethod(pTypeRec, &pSig, &cbSig));
+ dwFlags = pTypeRec->GetFlags();
+ }
+ else // it can be only MemberRef, otherwise we wouldn't be here
+ {
+ MemberRefRec *pTypeRec;
+ IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(tkCAType), &pTypeRec));
+ IfFailGo(pMiniMd->getNameOfMemberRef(pTypeRec, &szName));
+ IfFailGo(pMiniMd->getSignatureOfMemberRef(pTypeRec, &pSig, &cbSig));
+ }
+ if (strcmp(szName, ".ctor") != 0)
+ {
+ REPORT_ERROR1(VLDTR_E_CA_NOTCTOR, tkCAType);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ if ((cbSig > 0) && (pSig != NULL))
+ {
+ if(FAILED(ValidateMethodSig(tkCAType, pSig,cbSig,dwFlags))
+ || (!((*pSig) & IMAGE_CEE_CS_CALLCONV_HASTHIS)))
+ {
+ REPORT_ERROR1(VLDTR_E_CA_BADSIG, tkCAType);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ { // sig seems to be OK
+ if ((pbValue != NULL) && (cbValue > 0))
+ {
+ // Check if prolog is OK
+ WORD pW = *((UNALIGNED WORD*)pbValue);
+ if(pW != 0x0001)
+ {
+ REPORT_ERROR1(VLDTR_E_CA_BADPROLOG, pW);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Check if blob corresponds to the signature
+ }
+ }
+
+ }
+ else
+ {
+ REPORT_ERROR1(VLDTR_E_CA_NOSIG, tkCAType);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ } // end if bad Type - else
+ } // end if RidFromToken(tkOwner)
+ } // end if pRecord
+
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateCustomAttribute()
+
+//*****************************************************************************
+// Validate the given FieldMarshal.
+//*****************************************************************************
+HRESULT RegMeta::ValidateFieldMarshal(RID rid)
+{
+ return S_OK;
+} // RegMeta::ValidateFieldMarshal()
+
+//*****************************************************************************
+// Validate the given DeclSecurity.
+//*****************************************************************************
+HRESULT RegMeta::ValidateDeclSecurity(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+ DeclSecurityRec *pRecord;
+ mdToken tkOwner; // Owner of the decl security
+ DWORD dwAction; // action flags
+ BOOL bIsValidOwner = FALSE;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ IfFailGo(pMiniMd->GetDeclSecurityRecord(rid, &pRecord));
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+
+ veCtxt.Token = TokenFromRid(rid,mdtPermission);
+ veCtxt.uOffset = 0;
+
+ // Must have a valid owner
+ tkOwner = pMiniMd->getParentOfDeclSecurity(pRecord);
+ if(RidFromToken(tkOwner)==0) goto ErrExit; // deleted record, no need to validate
+ switch(TypeFromToken(tkOwner))
+ {
+ case mdtModule:
+ case mdtAssembly:
+ case mdtTypeDef:
+ case mdtMethodDef:
+ case mdtFieldDef:
+ case mdtInterfaceImpl:
+ bIsValidOwner = IsValidToken(tkOwner);
+ break;
+ default:
+ break;
+ }
+ if(!bIsValidOwner)
+ {
+ REPORT_ERROR1(VLDTR_E_DS_BADOWNER, tkOwner);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Must have one and only one flag set
+ dwAction = pRecord->GetAction() & dclActionMask;
+ if(dwAction > dclMaximumValue) // the flags are 0,1,2,3,...,dclMaximumValue
+ {
+ REPORT_ERROR1(VLDTR_E_DS_BADFLAGS, dwAction);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // If field has DeclSecurity, verify its parent is not an interface.-- checked in ValidateField
+ // If method has DeclSecurity, verify its parent is not an interface.-- checked in ValidateMethod
+
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateDeclSecurity()
+
+//*****************************************************************************
+// Validate the given ClassLayout.
+//*****************************************************************************
+HRESULT RegMeta::ValidateClassLayout(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
+ ClassLayoutRec *pRecord; // ClassLayout record.
+ TypeDefRec *pTypeDefRec; // Parent TypeDef record.
+ DWORD dwPackingSize; // Packing size.
+ mdTypeDef tkParent; // Parent TypeDef token.
+ DWORD dwTypeDefFlags; // Parent TypeDef flags.
+ RID clRid; // Duplicate ClassLayout rid.
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ // Extract the record.
+ veCtxt.Token = rid;
+ veCtxt.uOffset = 0;
+ IfFailGo(pMiniMd->GetClassLayoutRecord(rid, &pRecord));
+
+ // Get the parent, if parent is nil its a deleted record. Skip validation.
+ tkParent = pMiniMd->getParentOfClassLayout(pRecord);
+ if (IsNilToken(tkParent))
+ goto ErrExit;
+
+ // Parent should not have AutoLayout set on it.
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeDefRec));
+ dwTypeDefFlags = pMiniMd->getFlagsOfTypeDef(pTypeDefRec);
+ if (IsTdAutoLayout(dwTypeDefFlags))
+ {
+ REPORT_ERROR1(VLDTR_E_CL_TDAUTO, tkParent);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Parent must not be an Interface
+ if(IsTdInterface(dwTypeDefFlags))
+ {
+ REPORT_ERROR1(VLDTR_E_CL_TDINTF, tkParent);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Validate the PackingSize.
+ dwPackingSize = pMiniMd->getPackingSizeOfClassLayout(pRecord);
+ if((dwPackingSize > 128)||((dwPackingSize & (dwPackingSize-1)) !=0 ))
+ {
+ REPORT_ERROR2(VLDTR_E_CL_BADPCKSZ, tkParent, dwPackingSize);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Validate that there are no duplicates.
+ hr = _FindClassLayout(pMiniMd, tkParent, &clRid, rid);
+ if (hr == S_OK)
+ {
+ REPORT_ERROR2(VLDTR_E_CL_DUP, tkParent, clRid);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else if (hr == CLDB_E_RECORD_NOTFOUND)
+ hr = S_OK;
+ else
+ IfFailGo(hr);
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateClassLayout()
+
+//*****************************************************************************
+// Validate the given FieldLayout.
+//*****************************************************************************
+HRESULT RegMeta::ValidateFieldLayout(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
+ FieldLayoutRec *pRecord; // FieldLayout record.
+ mdFieldDef tkField; // Field token.
+ ULONG ulOffset; // Field offset.
+ FieldRec *pFieldRec; // Field record.
+ TypeDefRec *pTypeDefRec; // Parent TypeDef record.
+ mdTypeDef tkTypeDef; // Parent TypeDef token.
+ RID clRid; // Corresponding ClassLayout token.
+ RID flRid = 0; // Duplicate FieldLayout rid.
+ DWORD dwTypeDefFlags; // Parent TypeDef flags.
+ DWORD dwFieldFlags; // Field flags.
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+
+ // Extract the record.
+ veCtxt.Token = rid;
+ veCtxt.uOffset = 0;
+ IfFailGo(pMiniMd->GetFieldLayoutRecord(rid, &pRecord));
+
+ // Get the field, if it's nil it's a deleted record, so just skip it.
+ tkField = pMiniMd->getFieldOfFieldLayout(pRecord);
+ if (IsNilToken(tkField))
+ goto ErrExit;
+
+ // Validate the Offset value.
+ ulOffset = pMiniMd->getOffSetOfFieldLayout(pRecord);
+ if (ulOffset == ULONG_MAX)
+ {
+ REPORT_ERROR2(VLDTR_E_FL_BADOFFSET, tkField, ulOffset);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Get the parent of the Field.
+ IfFailGo(pMiniMd->FindParentOfFieldHelper(tkField, &tkTypeDef));
+ // Validate that the parent is not nil.
+ if (IsNilToken(tkTypeDef))
+ {
+ REPORT_ERROR1(VLDTR_E_FL_TDNIL, tkField);
+ SetVldtrCode(&hr, hrSave);
+ goto ErrExit;
+ }
+
+ // Validate that there exists a ClassLayout record associated with
+ // this TypeDef.
+ IfFailGo(pMiniMd->FindClassLayoutHelper(tkTypeDef, &clRid));
+ if (InvalidRid(rid))
+ {
+ REPORT_ERROR2(VLDTR_E_FL_NOCL, tkField, tkTypeDef);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Validate that ExplicitLayout is set on the TypeDef flags.
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkTypeDef), &pTypeDefRec));
+ dwTypeDefFlags = pMiniMd->getFlagsOfTypeDef(pTypeDefRec);
+ if (IsTdAutoLayout(dwTypeDefFlags))
+ {
+ REPORT_ERROR2(VLDTR_E_FL_TDNOTEXPLCT, tkField, tkTypeDef);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Extract Field record.
+ IfFailGo(pMiniMd->GetFieldRecord(RidFromToken(tkField), &pFieldRec));
+ // Validate that the field is non-static.
+ dwFieldFlags = pMiniMd->getFlagsOfField(pFieldRec);
+ if (IsFdStatic(dwFieldFlags))
+ {
+ REPORT_ERROR1(VLDTR_E_FL_FLDSTATIC, tkField);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Look for duplicates.
+ hr = _FindFieldLayout(pMiniMd, tkField, &flRid, rid);
+ if (hr == S_OK)
+ {
+ REPORT_ERROR1(VLDTR_E_FL_DUP, flRid);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else if (hr == CLDB_E_RECORD_NOTFOUND)
+ hr = S_OK;
+ else
+ IfFailGo(hr);
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateFieldLayout()
+
+//*****************************************************************************
+// Validate the given StandAloneSig.
+//*****************************************************************************
+HRESULT RegMeta::ValidateStandAloneSig(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
+ StandAloneSigRec *pRecord; // FieldLayout record.
+ PCCOR_SIGNATURE pbSig; // Signature.
+ ULONG cbSig; // Size in bytes of the signature.
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+ ULONG ulCurByte = 0; // Current index into the signature.
+ ULONG ulCallConv; // Calling convention.
+ ULONG ulArgCount; // Count of arguments.
+ ULONG ulTyArgCount = 0; // Count of type arguments.
+ ULONG i; // Looping index.
+ ULONG ulNSentinels = 0; // Number of sentinels in the signature
+ BOOL bNoVoidAllowed=TRUE;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+
+ // Extract the record.
+ veCtxt.Token = TokenFromRid(rid,mdtSignature);
+ veCtxt.uOffset = 0;
+ IfFailGo(pMiniMd->GetStandAloneSigRecord(rid, &pRecord));
+ IfFailGo(pMiniMd->getSignatureOfStandAloneSig(pRecord, &pbSig, &cbSig));
+
+ // Validate the signature is well-formed with respect to the compression
+ // scheme. If this fails, no further validation needs to be done.
+ if ( (hr = ValidateSigCompression(veCtxt.Token, pbSig, cbSig)) != S_OK)
+ goto ErrExit;
+
+ //_ASSERTE((rid != 0x2c2)&&(rid!=0x2c8)&&(rid!=0x2c9)&&(rid!=0x2d6)&&(rid!=0x38b));
+ // Validate the calling convention.
+ ulCurByte += CorSigUncompressedDataSize(pbSig);
+ ulCallConv = CorSigUncompressData(pbSig);
+ i = ulCallConv & IMAGE_CEE_CS_CALLCONV_MASK;
+ if(i == IMAGE_CEE_CS_CALLCONV_FIELD) // <REVISIT_TODO>it's a temporary bypass (VB bug)</REVISIT_TODO>
+ ulArgCount = 1;
+ else
+ {
+ if(i != IMAGE_CEE_CS_CALLCONV_LOCAL_SIG) // then it is function sig for calli
+ {
+ if((i >= IMAGE_CEE_CS_CALLCONV_FIELD)
+ ||((ulCallConv & IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS)
+ &&(!(ulCallConv & IMAGE_CEE_CS_CALLCONV_HASTHIS))))
+ {
+ REPORT_ERROR1(VLDTR_E_MD_BADCALLINGCONV, ulCallConv);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ bNoVoidAllowed = FALSE;
+ }
+ // Is there any sig left for arguments?
+ _ASSERTE(ulCurByte <= cbSig);
+ if (cbSig == ulCurByte)
+ {
+ REPORT_ERROR1(VLDTR_E_MD_NOARGCNT, ulCurByte+1);
+ SetVldtrCode(&hr, hrSave);
+ goto ErrExit;
+ }
+
+ // Get the type argument count.
+ if (ulCallConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
+ {
+ ulCurByte += CorSigUncompressedDataSize(pbSig);
+ ulTyArgCount = CorSigUncompressData(pbSig);
+ }
+
+ // Get the argument count.
+ ulCurByte += CorSigUncompressedDataSize(pbSig);
+ ulArgCount = CorSigUncompressData(pbSig);
+ }
+ // Validate the the arguments.
+ if(ulArgCount)
+ {
+ for(i=1; ulCurByte < cbSig; i++)
+ {
+ hr = ValidateOneArg(veCtxt.Token, pbSig, cbSig, &ulCurByte,&ulNSentinels,bNoVoidAllowed);
+ if (hr != S_OK)
+ {
+ if(hr == VLDTR_E_SIG_MISSARG)
+ {
+ REPORT_ERROR1(VLDTR_E_SIG_MISSARG, i);
+ }
+ SetVldtrCode(&hr, hrSave);
+ hrSave = hr;
+ break;
+ }
+ bNoVoidAllowed = TRUE; // whatever it was for the 1st arg, it must be TRUE for the rest
+ }
+ if((ulNSentinels != 0) && (!isCallConv(ulCallConv, IMAGE_CEE_CS_CALLCONV_VARARG )))
+ {
+ REPORT_ERROR0(VLDTR_E_SIG_SENTMUSTVARARG);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ if(ulNSentinels > 1)
+ {
+ REPORT_ERROR0(VLDTR_E_SIG_MULTSENTINELS);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateStandAloneSig()
+
+//*****************************************************************************
+// Validate the given EventMap.
+//*****************************************************************************
+HRESULT RegMeta::ValidateEventMap(RID rid)
+{
+ return S_OK;
+} // RegMeta::ValidateEventMap()
+
+//*****************************************************************************
+// Validate the given EventPtr.
+//*****************************************************************************
+HRESULT RegMeta::ValidateEventPtr(RID rid)
+{
+ return S_OK;
+} // RegMeta::ValidateEventPtr()
+
+//*****************************************************************************
+// Validate the given Event.
+//*****************************************************************************
+HRESULT RegMeta::ValidateEvent(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+ mdToken tkClass; // Declaring TypeDef
+ mdToken tkEventType; // Event Type (TypeDef/TypeRef)
+ EventRec *pRecord;
+ HENUMInternal hEnum;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ IfFailGo(pMiniMd->GetEventRecord(rid, &pRecord));
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+ memset(&hEnum, 0, sizeof(HENUMInternal));
+ veCtxt.Token = TokenFromRid(rid,mdtEvent);
+ veCtxt.uOffset = 0;
+
+ // The scope must be a valid TypeDef
+ if (FAILED(pMiniMd->FindParentOfEventHelper(veCtxt.Token, &tkClass)) ||
+ (TypeFromToken(tkClass) != mdtTypeDef) ||
+ !IsValidToken(tkClass))
+ {
+ REPORT_ERROR1(VLDTR_E_EV_BADSCOPE, tkClass);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ tkClass = 0;
+ }
+ // Must have name
+ {
+ LPCUTF8 szName;
+ IfFailGo(pMiniMd->getNameOfEvent(pRecord, &szName));
+
+ if (*szName == 0)
+ {
+ REPORT_ERROR0(VLDTR_E_EV_NONAME);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ {
+ if (strcmp(szName, COR_DELETED_NAME_A) == 0)
+ goto ErrExit;
+ if (tkClass != 0) // Must be no duplicates
+ {
+ RID ridEventMap;
+ EventMapRec *pEventMapRec;
+ EventRec *pRec;
+ ULONG ridStart;
+ ULONG ridEnd;
+ ULONG i;
+
+ IfFailGo(pMiniMd->FindEventMapFor(RidFromToken(tkClass), &ridEventMap));
+ if (!InvalidRid(ridEventMap))
+ {
+ IfFailGo(pMiniMd->GetEventMapRecord(ridEventMap, &pEventMapRec));
+ ridStart = pMiniMd->getEventListOfEventMap(pEventMapRec);
+ IfFailGo(pMiniMd->getEndEventListOfEventMap(ridEventMap, &ridEnd));
+
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ if (i == rid)
+ continue;
+ IfFailGo(pMiniMd->GetEventRecord(i, &pRec));
+
+ LPCSTR szEventName;
+ IfFailGo(pMiniMd->getNameOfEvent(pRec, &szEventName));
+ if (strcmp(szName, szEventName) != 0)
+ continue;
+
+ REPORT_ERROR1(VLDTR_E_EV_DUP, TokenFromRid(i, mdtEvent));
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ }
+ }
+ }// end of name block
+ // EventType must be Nil or valid TypeDef, TypeRef or TypeSpec representing an instantiated generic type
+ tkEventType = pMiniMd->getEventTypeOfEvent(pRecord);
+ if (!IsNilToken(tkEventType))
+ {
+ if(IsValidToken(tkEventType) &&
+ ((TypeFromToken(tkEventType)==mdtTypeDef)||
+ (TypeFromToken(tkEventType)==mdtTypeRef)||
+ (TypeFromToken(tkEventType)==mdtTypeSpec)))
+ {
+ // TypeSpecs can be many things, we only handle instantiated generic types currently.
+ if (TypeFromToken(tkEventType)==mdtTypeSpec)
+ {
+ TypeSpecRec *pRec;
+ IfFailGo(pMiniMd->GetTypeSpecRecord(RidFromToken(tkEventType), &pRec));
+ PCCOR_SIGNATURE pSig;
+ ULONG cSig;
+
+ IfFailGo(pMiniMd->getSignatureOfTypeSpec(pRec, &pSig, &cSig));
+
+ if (CorSigUncompressElementType(pSig) == ELEMENT_TYPE_GENERICINST &&
+ CorSigUncompressElementType(pSig) == ELEMENT_TYPE_CLASS)
+ {
+ // Just update the event type token variable and fall through to the validation code below (it doesn't care
+ // whether the type is generic or not).
+ tkEventType = CorSigUncompressToken(pSig);
+ }
+ else
+ {
+ REPORT_ERROR1(VLDTR_E_EV_BADEVTYPE, tkEventType);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+
+ // EventType must not be Interface or ValueType
+ if(TypeFromToken(tkEventType)==mdtTypeDef) // can't say anything about TypeRef: no flags available!
+ {
+ TypeDefRec *pTypeDefRecord;
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkEventType), &pTypeDefRecord));
+ DWORD dwFlags = pTypeDefRecord->GetFlags();
+ if(!IsTdClass(dwFlags))
+ {
+ REPORT_ERROR2(VLDTR_E_EV_EVTYPENOTCLASS, tkEventType, dwFlags);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ }
+ else
+ {
+ REPORT_ERROR1(VLDTR_E_EV_BADEVTYPE, tkEventType);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ // Validate related methods
+ {
+ MethodSemanticsRec *pSemantics;
+ RID ridCur;
+ ULONG ulSemantics;
+ mdMethodDef tkMethod;
+ bool bHasAddOn = false;
+ bool bHasRemoveOn = false;
+
+ IfFailGo( pMiniMd->FindMethodSemanticsHelper(veCtxt.Token, &hEnum) );
+ while (HENUMInternal::EnumNext(&hEnum, (mdToken *)&ridCur))
+ {
+ IfFailGo(pMiniMd->GetMethodSemanticsRecord(ridCur, &pSemantics));
+ ulSemantics = pMiniMd->getSemanticOfMethodSemantics(pSemantics);
+ tkMethod = TokenFromRid( pMiniMd->getMethodOfMethodSemantics(pSemantics), mdtMethodDef );
+ // Semantics must be Setter, Getter or Other
+ switch (ulSemantics)
+ {
+ case msAddOn:
+ bHasAddOn = true;
+ break;
+ case msRemoveOn:
+ bHasRemoveOn = true;
+ break;
+ case msFire:
+ case msOther:
+ break;
+ default:
+ REPORT_ERROR2(VLDTR_E_EV_BADSEMANTICS, tkMethod,ulSemantics);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Method must be valid
+ if(!IsValidToken(tkMethod))
+ {
+ REPORT_ERROR1(VLDTR_E_EV_BADMETHOD, tkMethod);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ {
+ // Method's parent must be the same
+ mdToken tkTypeDef;
+ IfFailGo(pMiniMd->FindParentOfMethodHelper(tkMethod, &tkTypeDef));
+ if(tkTypeDef != tkClass)
+ {
+ REPORT_ERROR2(VLDTR_E_EV_ALIENMETHOD, tkMethod,tkTypeDef);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ } // end loop over methods
+ // AddOn and RemoveOn are a must
+ if(!bHasAddOn)
+ {
+ REPORT_ERROR0(VLDTR_E_EV_NOADDON);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ if(!bHasRemoveOn)
+ {
+ REPORT_ERROR0(VLDTR_E_EV_NOREMOVEON);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }// end of related method validation block
+
+ hr = hrSave;
+ErrExit:
+ HENUMInternal::ClearEnum(&hEnum);
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateEvent()
+
+
+//*****************************************************************************
+// Validate the given PropertyMap.
+//*****************************************************************************
+HRESULT RegMeta::ValidatePropertyMap(RID rid)
+{
+ return S_OK;
+} // RegMeta::ValidatePropertyMap(0
+
+//*****************************************************************************
+// Validate the given PropertyPtr.
+//*****************************************************************************
+HRESULT RegMeta::ValidatePropertyPtr(RID rid)
+{
+ return S_OK;
+} // RegMeta::ValidatePropertyPtr()
+
+//*****************************************************************************
+// Validate the given Property.
+//*****************************************************************************
+HRESULT RegMeta::ValidateProperty(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+ mdToken tkClass = mdTokenNil; // Declaring TypeDef
+ PropertyRec *pRecord;
+ HENUMInternal hEnum;
+ RID tempRid;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ IfFailGo(pMiniMd->GetPropertyRecord(rid, &pRecord));
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+ memset(&hEnum, 0, sizeof(HENUMInternal));
+ veCtxt.Token = TokenFromRid(rid,mdtProperty);
+ veCtxt.uOffset = 0;
+ // The scope must be a valid TypeDef
+ IfFailGo(pMiniMd->FindParentOfPropertyHelper( veCtxt.Token, &tkClass));
+ if ((TypeFromToken(tkClass) != mdtTypeDef) ||
+ !IsValidToken(tkClass) ||
+ IsNilToken(tkClass))
+ {
+ REPORT_ERROR1(VLDTR_E_PR_BADSCOPE, tkClass);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Must have name and signature
+ {
+ ULONG cbSig;
+ PCCOR_SIGNATURE pvSig;
+ IfFailGo(pMiniMd->getTypeOfProperty(pRecord, &pvSig, &cbSig));
+
+ LPCUTF8 szName;
+ IfFailGo(pMiniMd->getNameOfProperty(pRecord, &szName));
+ ULONG ulNameLen = (szName != NULL) ? (ULONG)strlen(szName) : 0;
+
+ if (ulNameLen == 0)
+ {
+ REPORT_ERROR0(VLDTR_E_PR_NONAME);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ {
+ if(strcmp(szName, COR_DELETED_NAME_A) == 0)
+ goto ErrExit;
+ }
+ if (cbSig == 0)
+ {
+ REPORT_ERROR0(VLDTR_E_PR_NOSIG);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Must be no duplicates
+ if ((ulNameLen != 0) && (cbSig != 0))
+ {
+ RID ridPropertyMap;
+ PropertyMapRec *pPropertyMapRec;
+ PropertyRec *pRec;
+ ULONG ridStart;
+ ULONG ridEnd;
+ ULONG i;
+ ULONG cbSig1;
+ PCCOR_SIGNATURE pvSig1;
+
+ IfFailGo(pMiniMd->FindPropertyMapFor(RidFromToken(tkClass), &ridPropertyMap));
+ if (!InvalidRid(ridPropertyMap) )
+ {
+ IfFailGo(pMiniMd->GetPropertyMapRecord(ridPropertyMap, &pPropertyMapRec));
+ ridStart = pMiniMd->getPropertyListOfPropertyMap(pPropertyMapRec);
+ IfFailGo(pMiniMd->getEndPropertyListOfPropertyMap(ridPropertyMap, &ridEnd));
+
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ if (i == rid)
+ continue;
+ IfFailGo(pMiniMd->GetPropertyRecord(i, &pRec));
+ IfFailGo(pMiniMd->getTypeOfProperty(pRec, &pvSig1, &cbSig1));
+
+ if (cbSig != cbSig1)
+ continue;
+ if (memcmp(pvSig,pvSig1,cbSig) != 0)
+ continue;
+
+ LPCSTR szPropertyName;
+ IfFailGo(pMiniMd->getNameOfProperty(pRec, &szPropertyName));
+ if (strcmp(szName, szPropertyName) != 0)
+ continue;
+
+ REPORT_ERROR1(VLDTR_E_PR_DUP, TokenFromRid(i,mdtProperty));
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ }
+ // Validate the signature
+ if ((pvSig != NULL) && (cbSig != 0))
+ {
+ ULONG ulCurByte = 0; // Current index into the signature.
+ ULONG ulCallConv; // Calling convention.
+ ULONG ulArgCount;
+ ULONG i;
+ ULONG ulNSentinels = 0;
+
+ // Validate the calling convention.
+ ulCurByte += CorSigUncompressedDataSize(pvSig);
+ ulCallConv = CorSigUncompressData(pvSig);
+ if (!isCallConv(ulCallConv, IMAGE_CEE_CS_CALLCONV_PROPERTY ))
+ {
+ REPORT_ERROR1(VLDTR_E_PR_BADCALLINGCONV, ulCallConv);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Get the argument count.
+ ulCurByte += CorSigUncompressedDataSize(pvSig);
+ ulArgCount = CorSigUncompressData(pvSig);
+
+ // Validate the arguments.
+ for (i = 0; i < ulArgCount; i++)
+ {
+ hr = ValidateOneArg(veCtxt.Token, pvSig, cbSig, &ulCurByte,&ulNSentinels,(i>0));
+ if (hr != S_OK)
+ {
+ if (hr == VLDTR_E_SIG_MISSARG)
+ {
+ REPORT_ERROR1(VLDTR_E_SIG_MISSARG, i+1);
+ }
+ SetVldtrCode(&hr, hrSave);
+ break;
+ }
+ }
+ }//end if(pvSig && cbSig)
+ }// end of name/signature block
+
+ // Marked HasDefault <=> has default value
+ IfFailGo(pMiniMd->FindConstantHelper(veCtxt.Token, &tempRid));
+ if (InvalidRid(tempRid) == IsPrHasDefault(pRecord->GetPropFlags()))
+ {
+ REPORT_ERROR0(IsPrHasDefault(pRecord->GetPropFlags())? VLDTR_E_PR_MARKEDNODEFLT : VLDTR_E_PR_DEFLTNOTMARKED);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Validate related methods
+ {
+ MethodSemanticsRec *pSemantics;
+ RID ridCur;
+ ULONG ulSemantics;
+ mdMethodDef tkMethod;
+
+ IfFailGo( pMiniMd->FindMethodSemanticsHelper(veCtxt.Token, &hEnum) );
+ while (HENUMInternal::EnumNext(&hEnum, (mdToken *) &ridCur))
+ {
+ IfFailGo(pMiniMd->GetMethodSemanticsRecord(ridCur, &pSemantics));
+ ulSemantics = pMiniMd->getSemanticOfMethodSemantics(pSemantics);
+ tkMethod = TokenFromRid( pMiniMd->getMethodOfMethodSemantics(pSemantics), mdtMethodDef );
+ // Semantics must be Setter, Getter or Other
+ switch (ulSemantics)
+ {
+ case msSetter:
+ case msGetter:
+ case msOther:
+ break;
+ default:
+ REPORT_ERROR2(VLDTR_E_PR_BADSEMANTICS, tkMethod, ulSemantics);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Method must be valid
+ if(!IsValidToken(tkMethod))
+ {
+ REPORT_ERROR1(VLDTR_E_PR_BADMETHOD, tkMethod);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ {
+ // Method's parent must be the same
+ mdToken tkTypeDef;
+ IfFailGo(pMiniMd->FindParentOfMethodHelper(tkMethod, &tkTypeDef));
+ if(tkTypeDef != tkClass)
+ {
+ REPORT_ERROR2(VLDTR_E_PR_ALIENMETHOD, tkMethod, tkTypeDef);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ } // end loop over methods
+ }// end of related method validation block
+
+ hr = hrSave;
+ErrExit:
+ HENUMInternal::ClearEnum(&hEnum);
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateProperty()
+
+//*****************************************************************************
+// Validate the given MethodSemantics.
+//*****************************************************************************
+HRESULT RegMeta::ValidateMethodSemantics(RID rid)
+{
+ return S_OK;
+} // RegMeta::ValidateMethodSemantics()
+
+//*****************************************************************************
+// Validate the given MethodImpl.
+//*****************************************************************************
+HRESULT RegMeta::ValidateMethodImpl(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
+ MethodImplRec* pRecord;
+ MethodImplRec* pRec;
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+ mdToken tkClass; // Declaring TypeDef
+ mdToken tkBody; // Implementing method (MethodDef or MemberRef)
+ mdToken tkDecl; // Implemented method (MethodDef or MemberRef)
+ unsigned iCount;
+ unsigned index;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+ veCtxt.Token = TokenFromRid(rid, mdtMethodImpl);
+ veCtxt.uOffset = 0;
+
+ PCCOR_SIGNATURE pbBodySig = NULL;
+ PCCOR_SIGNATURE pbDeclSig = NULL;
+
+ IfFailGo(pMiniMd->GetMethodImplRecord(rid, &pRecord));
+ tkClass = pMiniMd->getClassOfMethodImpl(pRecord);
+ // Class must be valid
+ if(!IsValidToken(tkClass) || (TypeFromToken(tkClass) != mdtTypeDef))
+ {
+ REPORT_ERROR1(VLDTR_E_MI_BADCLASS, tkClass);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ { // ... and not an Interface
+ TypeDefRec *pTypeDefRecord;
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkClass), &pTypeDefRecord));
+ if(IsTdInterface(pTypeDefRecord->GetFlags()))
+ {
+ REPORT_ERROR1(VLDTR_E_MI_CLASSISINTF, tkClass);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ // Decl must be valid MethodDef or MemberRef
+ tkDecl = pMiniMd->getMethodDeclarationOfMethodImpl(pRecord);
+ if(!(IsValidToken(tkDecl) &&
+ ((TypeFromToken(tkDecl) == mdtMethodDef) || (TypeFromToken(tkDecl) == mdtMemberRef))))
+ {
+ REPORT_ERROR1(VLDTR_E_MI_BADDECL, tkDecl);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Body must be valid MethodDef or MemberRef
+ tkBody = pMiniMd->getMethodBodyOfMethodImpl(pRecord);
+ if(!(IsValidToken(tkBody) &&
+ ((TypeFromToken(tkBody) == mdtMethodDef) || (TypeFromToken(tkBody) == mdtMemberRef))))
+ {
+ REPORT_ERROR1(VLDTR_E_MI_BADBODY, tkBody);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // No duplicates based on (tkClass,tkDecl)
+ iCount = pMiniMd->getCountMethodImpls();
+ for(index = rid+1; index <= iCount; index++)
+ {
+ IfFailGo(pMiniMd->GetMethodImplRecord(index, &pRec));
+ if((tkClass == pMiniMd->getClassOfMethodImpl(pRec)) &&
+ (tkDecl == pMiniMd->getMethodDeclarationOfMethodImpl(pRec)))
+ {
+ REPORT_ERROR1(VLDTR_E_MI_DUP, index);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+
+ mdToken tkBodyParent;
+ ULONG cbBodySig;
+
+ if(TypeFromToken(tkBody) == mdtMethodDef)
+ {
+ MethodRec *pBodyRec;
+ IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(tkBody), &pBodyRec));
+ IfFailGo(pMiniMd->getSignatureOfMethod(pBodyRec, &pbBodySig, &cbBodySig));
+ IfFailGo(pMiniMd->FindParentOfMethodHelper(tkBody, &tkBodyParent));
+ // Body must not be static
+ if(IsMdStatic(pBodyRec->GetFlags()))
+ {
+ REPORT_ERROR1(VLDTR_E_MI_BODYSTATIC, tkBody);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ else if(TypeFromToken(tkBody) == mdtMemberRef)
+ {
+ MemberRefRec *pBodyRec;
+ IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(tkBody), &pBodyRec));
+ tkBodyParent = pMiniMd->getClassOfMemberRef(pBodyRec);
+ IfFailGo(pMiniMd->getSignatureOfMemberRef(pBodyRec, &pbBodySig, &cbBodySig));
+ }
+ // Body must belong to the same class
+ if(tkBodyParent != tkClass)
+ {
+ REPORT_ERROR1(VLDTR_E_MI_ALIENBODY, tkBodyParent);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ mdToken tkDeclParent;
+ ULONG cbDeclSig;
+
+ if(TypeFromToken(tkDecl) == mdtMethodDef)
+ {
+ MethodRec *pDeclRec;
+ IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(tkDecl), &pDeclRec));
+ IfFailGo(pMiniMd->getSignatureOfMethod(pDeclRec, &pbDeclSig, &cbDeclSig));
+ IfFailGo(pMiniMd->FindParentOfMethodHelper(tkDecl, &tkDeclParent));
+ // Decl must be virtual
+ if(!IsMdVirtual(pDeclRec->GetFlags()))
+ {
+ REPORT_ERROR1(VLDTR_E_MI_DECLNOTVIRT, tkDecl);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Decl must not be final
+ if(IsMdFinal(pDeclRec->GetFlags()))
+ {
+ REPORT_ERROR1(VLDTR_E_MI_DECLFINAL, tkDecl);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Decl must not be private
+ if(IsMdPrivate(pDeclRec->GetFlags()) && IsMdCheckAccessOnOverride(pDeclRec->GetFlags()))
+ {
+ REPORT_ERROR1(VLDTR_E_MI_DECLPRIV, tkDecl);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ else if(TypeFromToken(tkDecl) == mdtMemberRef)
+ {
+ MemberRefRec *pDeclRec;
+ IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(tkDecl), &pDeclRec));
+ tkDeclParent = pMiniMd->getClassOfMemberRef(pDeclRec);
+ IfFailGo(pMiniMd->getSignatureOfMemberRef(pDeclRec, &pbDeclSig, &cbDeclSig));
+ }
+
+ // Compare the signatures as best we can, delegating some comparisons to the loader.
+ if (*pbBodySig & IMAGE_CEE_CS_CALLCONV_GENERIC)
+ {
+ // decl's callconv must be generic
+ if (*pbDeclSig & IMAGE_CEE_CS_CALLCONV_GENERIC)
+ {
+ // and the arities must match
+ ULONG ulBodyArity = CorSigUncompressData(++pbBodySig);
+ ULONG ulDeclArity = CorSigUncompressData(++pbDeclSig);
+ if(ulBodyArity != ulDeclArity)
+ {
+ REPORT_ERROR3(VLDTR_E_MI_ARITYMISMATCH,tkDecl,ulDeclArity,ulBodyArity);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ else
+ {
+ REPORT_ERROR1(VLDTR_E_MI_DECLNOTGENERIC,tkDecl);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // delegate precise signature checking to the loader,
+ // as this requires signature comparison modulo substitution
+ }
+ else if (*pbDeclSig & IMAGE_CEE_CS_CALLCONV_GENERIC)
+ {
+ REPORT_ERROR1(VLDTR_E_MI_IMPLNOTGENERIC,tkDecl);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else if (TypeFromToken(tkDeclParent) == mdtTypeSpec)
+ {
+ // do nothing for now...
+ // delegate precise signature checking to the loader,
+ // as this requires signature comparison modulo substitution
+ }
+ // Signatures must match (except call conv)
+ else if((cbDeclSig != cbBodySig)||(memcmp(pbDeclSig+1,pbBodySig+1,cbDeclSig-1)))
+ {
+ //@GENERICSVER: todo:
+ /*
+ //@TODO: Fix to have peverify resolve assemblies
+ // through the runtime. At that point, use this method instead
+ // of the current compare
+
+ // @TODO: check for other bad memcmp sig comparisons in peverify
+
+ // Can't use memcmp because there may be two AssemblyRefs
+ // in this scope, pointing to the same assembly, etc.).
+ if (!MetaSig::CompareMethodSigs(pbDeclSig,
+ cbDeclSig,
+ Module* pModule1,
+ pbBodySig,
+ cbDeclSig,
+ Module* pModule2))
+ */
+ UnifiedAssemblySigComparer uasc(*this);
+ MDSigComparer sc(MDSigParser(pbDeclSig, cbDeclSig),
+ MDSigParser(pbBodySig, cbBodySig),
+ uasc);
+
+ hr = sc.CompareMethodSignature();
+
+ if (FAILED(hr))
+ {
+ REPORT_ERROR2(VLDTR_E_MI_SIGMISMATCH,tkDecl,tkBody);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateMethodImpl()
+
+//*****************************************************************************
+// Validate the given ModuleRef.
+//*****************************************************************************
+HRESULT RegMeta::ValidateModuleRef(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
+ ModuleRefRec *pRecord; // ModuleRef record.
+ LPCUTF8 szName; // ModuleRef name.
+ mdModuleRef tkModuleRef; // Duplicate ModuleRef.
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+ // Get the ModuleRef record.
+ veCtxt.Token = TokenFromRid(rid, mdtModuleRef);
+ veCtxt.uOffset = 0;
+
+ IfFailGo(pMiniMd->GetModuleRefRecord(rid, &pRecord));
+
+ // C++ emits IJW methods with ImplMaps
+ // which have resolution=ModuleRef with empty name
+ IfFailGo(pMiniMd->getNameOfModuleRef(pRecord, &szName));
+ if (*szName)
+ {
+ // Look for a Duplicate, this function reports only one duplicate.
+ hr = ImportHelper::FindModuleRef(pMiniMd, szName, &tkModuleRef, rid);
+ if (hr == S_OK)
+ {
+ REPORT_ERROR1(VLDTR_E_MODREF_DUP, tkModuleRef);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else if (hr == CLDB_E_RECORD_NOTFOUND)
+ hr = S_OK;
+ else
+ IfFailGo(hr);
+ }
+ else
+ hrSave = S_FALSE;
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateModuleRef()
+
+//*****************************************************************************
+// Validate the given TypeSpec.
+//*****************************************************************************
+//@todo GENERICS: reject duplicate specs?
+HRESULT RegMeta::ValidateTypeSpec(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
+ TypeSpecRec *pRecord; // TypeSpec record.
+ PCCOR_SIGNATURE pbSig; // Signature.
+ ULONG cbSig; // Size in bytes of the signature.
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+ ULONG ulCurByte = 0; // Current index into the signature.
+ ULONG ulNSentinels = 0; // Number of sentinels in the signature
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+ // Extract the record.
+ veCtxt.Token = TokenFromRid(rid,mdtTypeSpec);
+ veCtxt.uOffset = 0;
+ IfFailGo(pMiniMd->GetTypeSpecRecord(rid, &pRecord));
+ IfFailGo(pMiniMd->getSignatureOfTypeSpec(pRecord, &pbSig, &cbSig));
+
+ // Validate the signature is well-formed with respect to the compression
+ // scheme. If this fails, no further validation needs to be done.
+ if ( (hr = ValidateSigCompression(veCtxt.Token, pbSig, cbSig)) != S_OK)
+ goto ErrExit;
+
+ hr = ValidateOneArg(veCtxt.Token, pbSig, cbSig, &ulCurByte,&ulNSentinels,FALSE);
+ if (hr != S_OK)
+ {
+ if(hr == VLDTR_E_SIG_MISSARG)
+ {
+ REPORT_ERROR0(VLDTR_E_TS_EMPTY);
+ }
+ SetVldtrCode(&hr, hrSave);
+ hrSave = hr;
+ }
+ if(ulNSentinels != 0)
+ {
+ REPORT_ERROR0(VLDTR_E_TS_HASSENTINALS);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateTypeSpec()
+
+//*****************************************************************************
+// This function validates the given Field signature. This function works
+// with Field signature for both the MemberRef and FieldDef.
+//*****************************************************************************
+HRESULT RegMeta::ValidateMethodSpecSig(
+ mdMethodSpec tk, // [IN] Token whose signature needs to be validated.
+ PCCOR_SIGNATURE pbSig, // [IN] Signature.
+ ULONG cbSig, // [IN] Size in bytes of the signature.
+ ULONG *pArity) // [Out] Arity of the instantiation
+{
+ ULONG ulCurByte = 0; // Current index into the signature.
+ ULONG ulCallConv; // Calling convention.
+ ULONG ulArity; // Arity of instantiation.
+ ULONG ulArgCnt;
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+ _ASSERTE(TypeFromToken(tk) == mdtMethodSpec);
+
+ veCtxt.Token = tk;
+ veCtxt.uOffset = 0;
+
+ // Validate the calling convention.
+ ulCurByte += CorSigUncompressedDataSize(pbSig);
+ ulCallConv = CorSigUncompressData(pbSig);
+ if (!isCallConv(ulCallConv, IMAGE_CEE_CS_CALLCONV_GENERICINST))
+ {
+ REPORT_ERROR1(VLDTR_E_MS_BADCALLINGCONV, ulCallConv);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ if (cbSig == ulCurByte)
+ {
+ REPORT_ERROR1(VLDTR_E_MS_MISSARITY, ulCurByte + 1);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ ulCurByte += CorSigUncompressedDataSize(pbSig);
+ ulArity = CorSigUncompressData(pbSig);
+
+ if (ulArity == 0)
+ {
+ REPORT_ERROR1(VLDTR_E_MS_ARITYZERO, ulCurByte);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ ulArgCnt = ulArity;
+
+ if(pArity != NULL)
+ {
+ *pArity = ulArity;
+ }
+
+ // Validate and consume the arguments.
+ while(ulArgCnt--)
+ {
+
+ PCCOR_SIGNATURE pbTypeArg = pbSig;
+ ULONG ulTypeArgByte = ulCurByte;
+
+ IfFailGo(ValidateOneArg(tk, pbSig, cbSig, &ulCurByte, NULL, TRUE));
+ if (hr != S_OK)
+ {
+ if(hr == VLDTR_E_SIG_MISSARG)
+ {
+ REPORT_ERROR1(VLDTR_E_MS_MISSARG, ulArity-ulArgCnt);
+ }
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ }
+ // reject byref-like args
+ switch (CorSigUncompressData(pbTypeArg))
+ {
+ case ELEMENT_TYPE_TYPEDBYREF:
+ case ELEMENT_TYPE_BYREF:
+ {
+ REPORT_ERROR1(VLDTR_E_MS_BYREFINST, ulTypeArgByte);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateMethodSpecSig()
+
+
+//*****************************************************************************
+// Validate the given MethodSpec.
+//*****************************************************************************
+HRESULT RegMeta::ValidateMethodSpec(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
+ MethodSpecRec *pRecord; // MethodSpec record.
+ mdToken tkMethod; // Method field (a MethodDefOrRef)
+ PCCOR_SIGNATURE pInstantiation; // MethodSpec instantiation (a signature)
+ ULONG cbInstantiation; // Size of instantiation.
+ ULONG ulInstantiationArity; // Arity of the Instantiation
+
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+ // Get the GenericParamConstraint record.
+ veCtxt.Token = TokenFromRid(rid, mdtMethodSpec);
+ veCtxt.uOffset = 0;
+ IfFailGo(pMiniMd->GetMethodSpecRecord(rid, &pRecord));
+
+ // 1. The MethodSpec table may contain zero or more rows.
+ // (Nothing to check.)
+
+ // Implicit (missing from spec): Method is not nil [ERROR]
+ tkMethod = pMiniMd->getMethodOfMethodSpec(pRecord);
+ if(IsNilToken(tkMethod))
+ {
+ REPORT_ERROR0(VLDTR_E_MS_METHODNIL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Implicit in ValidateRecord: Method is a valid mdMethodDefOrRef.
+
+ // 2. One or more rows may refer to the same row in the MethodDef or MethodRef table.
+ // (There may be more multiple instantions of the same generic method)
+ // (nothing to check!)
+
+ // 3. "The signature stored at Instantiation shall be a valid instantiation of the signature of the generic method stored at Method. [ERROR]
+ {
+ IfFailGo(pMiniMd->getInstantiationOfMethodSpec(pRecord, &pInstantiation, &cbInstantiation));
+ IfFailGo(ValidateMethodSpecSig(TokenFromRid(rid, mdtMethodSpec), pInstantiation, cbInstantiation,&ulInstantiationArity));
+ if (hr != S_OK)
+ SetVldtrCode(&hrSave, hr);
+ }
+
+ IfFailGo(pMiniMd->getInstantiationOfMethodSpec(pRecord, &pInstantiation, &cbInstantiation));
+ // 4. There shall be no duplicate rows based upon Method and Instantiation [ERROR]
+ {
+ mdMethodSpec tkDupMethodSpec;
+ hr = ImportHelper::FindMethodSpecByMethodAndInstantiation(pMiniMd, tkMethod, pInstantiation, cbInstantiation, &tkDupMethodSpec, rid);
+ if (hr == S_OK)
+ {
+ REPORT_ERROR1(VLDTR_E_MS_DUP, tkDupMethodSpec);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else if (hr == CLDB_E_RECORD_NOTFOUND)
+ hr = S_OK;
+ else
+ IfFailGo(hr);
+ }
+
+ // check the method is generic and that the arity of the instantiation is correct
+ {
+ PCCOR_SIGNATURE pbGenericMethodSig;
+ ULONG cbGenericMethodSig;
+
+ if(TypeFromToken(tkMethod) == mdtMethodDef)
+ {
+ MethodRec *pMethodRec;
+ IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(tkMethod), &pMethodRec));
+ IfFailGo(pMiniMd->getSignatureOfMethod(pMethodRec, &pbGenericMethodSig, &cbGenericMethodSig));
+ }
+ else
+ {
+ _ASSERTE(TypeFromToken(tkMethod) == mdtMemberRef);
+ MemberRefRec *pMethodRefRec;
+ IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(tkMethod), &pMethodRefRec));
+ IfFailGo(pMiniMd->getSignatureOfMemberRef(pMethodRefRec, &pbGenericMethodSig, &cbGenericMethodSig));
+ }
+
+ if (*pbGenericMethodSig & IMAGE_CEE_CS_CALLCONV_GENERIC)
+ {
+ ULONG ulGenericArity = CorSigUncompressData(++pbGenericMethodSig);
+ if(ulGenericArity != ulInstantiationArity)
+ {
+ REPORT_ERROR2(VLDTR_E_MS_ARITYMISMATCH,ulGenericArity,ulInstantiationArity);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ else
+ {
+ REPORT_ERROR1(VLDTR_E_MS_METHODNOTGENERIC, tkMethod);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+
+ hr = hrSave;
+
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateMethodSpec()
+
+
+//*****************************************************************************
+// Validate the given GenericParamConstraint.
+//*****************************************************************************
+HRESULT RegMeta::ValidateGenericParamConstraint(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
+ GenericParamConstraintRec *pRecord; // GenericParamConstraint record.
+ mdGenericParam tkOwner; // GenericParamConstraint owner field.
+ mdToken tkConstraint; // GenericParamConstraint constraint field.
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+ // Get the GenericParamConstraint record.
+ veCtxt.Token = TokenFromRid(rid, mdtGenericParamConstraint);
+ veCtxt.uOffset = 0;
+ IfFailGo(pMiniMd->GetGenericParamConstraintRecord(rid, &pRecord));
+
+ // 1. GenericParamConstraint may contain zero or more rows.
+ // (Nothing to check.)
+
+ // 2. Each row shall have one, and only one, owner row in the GenericParamTable [ERROR]
+ // (Nothing to check except owner not nil)
+ tkOwner = pMiniMd->getOwnerOfGenericParamConstraint(pRecord);
+ if(IsNilToken(tkOwner))
+ {
+ REPORT_ERROR0(VLDTR_E_GPC_OWNERNIL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // 3. Each row in the GenericParam table shall own a separate row in the GenericParamConstraint table for each constraint that type parameter has [ERROR]
+ // (Nothing to check)
+
+ // 4.All of the rows in the GenericParamConstraint table that are owned by a given row in the GenericParamTable
+ // shall form a contiguous range of rows [ERROR]
+ //@NOTE: this check is (iterated over all rows) is quadratic in the (typically small) number of constraints
+ {
+ RID curRid = rid;
+ GenericParamConstraintRec *pCurRecord;
+ mdGenericParam tkCurOwner = tkOwner;
+ // find the first preceding row with a distinct owner
+ while (curRid > 1 && tkCurOwner == tkOwner)
+ {
+ curRid--;
+ IfFailGo(pMiniMd->GetGenericParamConstraintRecord(curRid, &pCurRecord));
+ tkCurOwner = pMiniMd->getOwnerOfGenericParamConstraint(pCurRecord);
+ };
+ // reject this row if there is some row preceding the current row with this owner
+ while (curRid > 1)
+ {
+ curRid--;
+ IfFailGo(pMiniMd->GetGenericParamConstraintRecord(curRid, &pCurRecord));
+ tkCurOwner = pMiniMd->getOwnerOfGenericParamConstraint(pCurRecord);
+ if (tkCurOwner == tkOwner)
+ {
+ REPORT_ERROR1(VLDTR_E_GPC_NONCONTIGUOUS,tkOwner);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ }
+ };
+ }
+
+ // 5. "At most one class constraint per GenericParam" --- no longer required.
+ // 6. "Zero or more interface constraints per GenericParam" --- no longer required.
+
+ tkConstraint = pMiniMd->getConstraintOfGenericParamConstraint(pRecord);
+ // 7. There shall be no duplicates based upon Owner and Constraint
+ {
+ mdGenericParamConstraint tkDupGenericParamConstraint;
+ hr = ImportHelper::FindGenericParamConstraintByOwnerAndConstraint(pMiniMd, tkOwner, tkConstraint, &tkDupGenericParamConstraint, rid);
+ if (hr == S_OK)
+ {
+ REPORT_ERROR1(VLDTR_E_GPC_DUP, tkDupGenericParamConstraint);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else if (hr == CLDB_E_RECORD_NOTFOUND)
+ hr = S_OK;
+ else
+ IfFailGo(hr);
+ }
+
+ hr = hrSave;
+
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateGenericParamConstraint()
+
+//*****************************************************************************
+// Validate the given ImplMap.
+//*****************************************************************************
+HRESULT RegMeta::ValidateImplMap(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
+ ImplMapRec *pRecord;
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+ HRESULT hrModuleRef=S_OK;
+ mdToken tkModuleRef;
+ mdToken tkMember;
+ USHORT usFlags;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+#ifdef CACHE_IMPLMAP_VALIDATION_RESULT
+ for(unsigned jjj=0; jjj<g_nValidated; jjj++)
+ {
+ if(g_rValidated[jjj].tok == (rid | 0x51000000)) return g_rValidated[jjj].hr;
+ }
+#endif
+ veCtxt.Token = rid;
+ veCtxt.uOffset = 0;
+ IfFailGo(pMiniMd->GetImplMapRecord(rid, &pRecord));
+ if(pRecord == NULL) IfFailGo(E_FAIL);
+ // ImplMap must have ModuleRef
+ tkModuleRef = pMiniMd->getImportScopeOfImplMap(pRecord);
+ if((TypeFromToken(tkModuleRef) != mdtModuleRef) || IsNilToken(tkModuleRef)
+ || FAILED(hrModuleRef= ValidateModuleRef(RidFromToken(tkModuleRef))))
+ {
+ REPORT_ERROR1(VLDTR_E_IMAP_BADMODREF, tkModuleRef);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // ImplMap must belong to FieldDef or MethodDef
+ tkMember = pMiniMd->getMemberForwardedOfImplMap(pRecord);
+ if((TypeFromToken(tkMember) != mdtFieldDef) && (TypeFromToken(tkMember) != mdtMethodDef))
+ {
+ REPORT_ERROR1(VLDTR_E_IMAP_BADMEMBER, tkMember);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // ImplMap must have import name, unless ModuleRef has no name
+ // (special case for C++ IJW methods)
+ if(hrModuleRef != S_FALSE)
+ {
+ LPCSTR szName; // Import name.
+ IfFailGo(pMiniMd->getImportNameOfImplMap(pRecord, &szName));
+ if((szName==NULL)||(*szName == 0))
+ {
+ REPORT_ERROR0(VLDTR_E_IMAP_BADIMPORTNAME);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ // ImplMap must have valid flags:
+ // one value of pmCharSetMask - always so, no check needed (values: 0,2,4,6, mask=6)
+ // one value of pmCallConvMask...
+ // ...and it's not pmCallConvThiscall
+ usFlags = pRecord->GetMappingFlags() & pmCallConvMask;
+ if((usFlags < pmCallConvWinapi)||(usFlags > pmCallConvFastcall))
+ {
+ REPORT_ERROR1(VLDTR_E_IMAP_BADCALLCONV, usFlags);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ErrExit:
+
+#ifdef CACHE_IMPLMAP_VALIDATION_RESULT
+ g_rValidated[g_nValidated].tok = rid | 0x51000000;
+ g_rValidated[g_nValidated].hr = hrSave;
+ g_nValidated++;
+#endif
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateImplMap()
+
+//*****************************************************************************
+// Validate the given FieldRVA.
+//*****************************************************************************
+HRESULT RegMeta::ValidateFieldRVA(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
+ FieldRVARec *pRecord;
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+ mdToken tkField;
+ ULONG ulRVA;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+ veCtxt.Token = rid;
+ veCtxt.uOffset = 0;
+ IfFailGo(pMiniMd->GetFieldRVARecord(rid, &pRecord));
+ ulRVA = pRecord->GetRVA();
+ tkField = pMiniMd->getFieldOfFieldRVA(pRecord);
+ /*
+ if(ulRVA == 0)
+ {
+ REPORT_ERROR1(VLDTR_E_FRVA_ZERORVA, tkField);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ */
+ if((0==RidFromToken(tkField))||(TypeFromToken(tkField) != mdtFieldDef)||(!IsValidToken(tkField)))
+ {
+ REPORT_ERROR2(VLDTR_E_FRVA_BADFIELD, tkField, ulRVA);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ {
+ RID N = pMiniMd->getCountFieldRVAs();
+ RID tmp;
+ FieldRVARec* pRecTmp;
+ for(tmp = rid+1; tmp <= N; tmp++)
+ {
+ IfFailGo(pMiniMd->GetFieldRVARecord(tmp, &pRecTmp));
+ if(tkField == pMiniMd->getFieldOfFieldRVA(pRecTmp))
+ {
+ REPORT_ERROR2(VLDTR_E_FRVA_DUPFIELD, tkField, tmp);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ }
+
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateFieldRVA()
+
+//*****************************************************************************
+// Validate the given ENCLog.
+//*****************************************************************************
+HRESULT RegMeta::ValidateENCLog(RID rid)
+{
+ return S_OK;
+} // RegMeta::ValidateENCLog()
+
+//*****************************************************************************
+// Validate the given ENCMap.
+//*****************************************************************************
+HRESULT RegMeta::ValidateENCMap(RID rid)
+{
+ return S_OK;
+} // RegMeta::ValidateENCMap()
+
+//*****************************************************************************
+// Validate the given Assembly.
+//*****************************************************************************
+HRESULT RegMeta::ValidateAssembly(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
+ AssemblyRec *pRecord; // Assembly record.
+ CorAssemblyFlags dwFlags; // Assembly flags.
+ LPCSTR szName; // Assembly Name.
+ VEContext veCtxt; // Context structure.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+ BOOL invalidAssemblyFlags; // Whether the CorAssemblyFlags are valid.
+ BOOL fIsV2Assembly = FALSE;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+ // Get the Assembly record.
+ veCtxt.Token = TokenFromRid(rid, mdtAssembly);
+ veCtxt.uOffset = 0;
+
+ IfFailGo(pMiniMd->GetAssemblyRecord(rid, &pRecord));
+
+ // There can only be one Assembly record.
+ if (rid > 1)
+ {
+ REPORT_ERROR0(VLDTR_E_AS_MULTI);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Do checks for name validity..
+ IfFailGo(pMiniMd->getNameOfAssembly(pRecord, &szName));
+ if (!*szName)
+ {
+ // Assembly Name is null.
+ REPORT_ERROR0(VLDTR_E_AS_NAMENULL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ {
+ unsigned L = (unsigned)strlen(szName);
+ if((*szName==' ')||strchr(szName,':') || strchr(szName,'\\') || strchr(szName, '/')
+ || strchr(szName, ',') || strchr(szName, '\n') || strchr(szName, '\r')
+ || ((L > 4)&&((!SString::_stricmp(&szName[L-4],".exe"))||(!SString::_stricmp(&szName[L-4],".dll")))))
+ {
+ //Assembly name has path and/or extension
+ REPORT_ERROR0(VLDTR_E_AS_BADNAME);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+
+ // Get the flags value for the Assembly.
+ dwFlags = (CorAssemblyFlags) pMiniMd->getFlagsOfAssembly(pRecord);
+
+ // Validate the flags
+ invalidAssemblyFlags = dwFlags & (~(afPublicKey | afRetargetable | afPA_FullMask | afEnableJITcompileTracking | afDisableJITcompileOptimizer | afContentType_Mask));
+
+ // Validate we only set a legal processor architecture flags
+ // The processor architecture flags were introduced in CLR v2.0.
+ // Note that METAMODEL_MINOR_VER_V2_0 is 0. GCC points out the comparison
+ // is useless, so that part is commented out.
+ fIsV2Assembly = (m_pStgdb->m_MiniMd.m_Schema.m_major >= METAMODEL_MAJOR_VER_V2_0
+ /* && m_pStgdb->m_MiniMd.m_Schema.m_minor >= METAMODEL_MINOR_VER_V2_0*/);
+ if (fIsV2Assembly)
+ {
+ if ((dwFlags & afPA_Mask) > afPA_AMD64 && !IsAfPA_NoPlatform(dwFlags))
+ invalidAssemblyFlags = true;
+ }
+ else {
+ if ((dwFlags & afPA_Mask) != 0)
+ invalidAssemblyFlags = true;
+ }
+
+ if (!IsAfContentType_Default(dwFlags) && !IsAfContentType_WindowsRuntime(dwFlags))
+ { // Unknown ContentType value
+ invalidAssemblyFlags = true;
+ }
+
+ if (invalidAssemblyFlags)
+ {
+ REPORT_ERROR1(VLDTR_E_AS_BADFLAGS, dwFlags);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Validate hash algorithm ID
+ switch(pRecord->GetHashAlgId())
+ {
+ case CALG_MD2:
+ case CALG_MD4:
+ case CALG_MD5:
+ case CALG_SHA:
+ //case CALG_SHA1: // same as CALG_SHA
+ case CALG_MAC:
+ case CALG_SSL3_SHAMD5:
+ case CALG_HMAC:
+ case 0:
+ break;
+ default:
+ REPORT_ERROR1(VLDTR_E_AS_HASHALGID, pRecord->GetHashAlgId());
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ }
+ // Validate locale
+ {
+ LPCSTR szLocale;
+ IfFailGo(pMiniMd->getLocaleOfAssembly(pRecord, &szLocale));
+ if(!_IsValidLocale(szLocale, fIsV2Assembly))
+ {
+ REPORT_ERROR0(VLDTR_E_AS_BADLOCALE);
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ }
+ }
+
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateAssembly()
+
+//*****************************************************************************
+// Validate the given AssemblyProcessor.
+//*****************************************************************************
+HRESULT RegMeta::ValidateAssemblyProcessor(RID rid)
+{
+ return S_OK;
+} // RegMeta::ValidateAssemblyProcessor()
+
+//*****************************************************************************
+// Validate the given AssemblyOS.
+//*****************************************************************************
+HRESULT RegMeta::ValidateAssemblyOS(RID rid)
+{
+ return S_OK;
+} // RegMeta::ValidateAssemblyOS()
+
+//*****************************************************************************
+// Validate the given AssemblyRef.
+//*****************************************************************************
+HRESULT RegMeta::ValidateAssemblyRef(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
+ AssemblyRefRec *pRecord; // Assembly record.
+ LPCSTR szName; // AssemblyRef Name.
+ VEContext veCtxt; // Context structure.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+ veCtxt.Token = TokenFromRid(rid, mdtAssemblyRef);
+ veCtxt.uOffset = 0;
+
+ // Get the AssemblyRef record.
+ IfFailGo(pMiniMd->GetAssemblyRefRecord(rid, &pRecord));
+
+ // Do checks for name and alias validity.
+ IfFailGo(pMiniMd->getNameOfAssemblyRef(pRecord, &szName));
+ if (!*szName)
+ {
+ // AssemblyRef Name is null.
+ REPORT_ERROR0(VLDTR_E_AR_NAMENULL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ {
+ unsigned L = (unsigned)strlen(szName);
+ if((*szName==' ')||strchr(szName,':') || strchr(szName,'\\') || strchr(szName, '/')
+ || strchr(szName, ',') || strchr(szName, '\n') || strchr(szName, '\r')
+ || ((L > 4)&&((!SString::_stricmp(&szName[L-4],".exe"))||(!SString::_stricmp(&szName[L-4],".dll")))))
+ {
+ //Assembly name has path and/or extension
+ REPORT_ERROR0(VLDTR_E_AS_BADNAME);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+
+ // Validate locale
+ {
+ LPCSTR szLocale;
+ IfFailGo(pMiniMd->getLocaleOfAssemblyRef(pRecord, &szLocale));
+ BOOL fIsV2Assembly = (m_pStgdb->m_MiniMd.m_Schema.m_major >= METAMODEL_MAJOR_VER_V2_0
+ /* && m_pStgdb->m_MiniMd.m_Schema.m_minor >= METAMODEL_MINOR_VER_V2_0*/);
+ if(!_IsValidLocale(szLocale, fIsV2Assembly))
+ {
+ REPORT_ERROR0(VLDTR_E_AS_BADLOCALE);
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ }
+ }
+
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateAssemblyRef()
+
+//*****************************************************************************
+// Validate the given AssemblyRefProcessor.
+//*****************************************************************************
+HRESULT RegMeta::ValidateAssemblyRefProcessor(RID rid)
+{
+ return S_OK;
+} // RegMeta::ValidateAssemblyRefProcessor()
+
+//*****************************************************************************
+// Validate the given AssemblyRefOS.
+//*****************************************************************************
+HRESULT RegMeta::ValidateAssemblyRefOS(RID rid)
+{
+ return S_OK;
+} // RegMeta::ValidateAssemblyRefOS()
+
+//*****************************************************************************
+// Validate the given File.
+//*****************************************************************************
+HRESULT RegMeta::ValidateFile(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
+ FileRec *pRecord; // File record.
+ mdFile tkFile; // Duplicate File token.
+ LPCSTR szName; // File Name.
+ VEContext veCtxt; // Context structure.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+ veCtxt.Token = TokenFromRid(rid, mdtFile);
+ veCtxt.uOffset = 0;
+
+ // Get the File record.
+ IfFailGo(pMiniMd->GetFileRecord(rid, &pRecord));
+
+ // Do checks for name validity.
+ IfFailGo(pMiniMd->getNameOfFile(pRecord, &szName));
+ if (!*szName)
+ {
+ // File Name is null.
+ REPORT_ERROR0(VLDTR_E_FILE_NAMENULL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ {
+ ULONG L = (ULONG)strlen(szName);
+ if(L >= MAX_PATH_FNAME)
+ {
+ // Name too long
+ REPORT_ERROR2(VLDTR_E_TD_NAMETOOLONG, L, (ULONG)(MAX_PATH_FNAME-1));
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Check for duplicates based on Name.
+ hr = ImportHelper::FindFile(pMiniMd, szName, &tkFile, rid);
+ if (hr == S_OK)
+ {
+ REPORT_ERROR1(VLDTR_E_FILE_DUP, tkFile);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else if (hr == CLDB_E_RECORD_NOTFOUND)
+ hr = S_OK;
+ else
+ IfFailGo(hr);
+
+ // File name must not be fully qualified.
+ if(strchr(szName,':') || strchr(szName,'\\') || strchr(szName,'/'))
+ {
+ REPORT_ERROR0(VLDTR_E_FILE_NAMEFULLQLFD);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // File name must not be one of system names.
+ char *sysname[6]={"con","aux","lpt","prn","null","com"};
+ char *syssymbol = "0123456789$:";
+ for(unsigned i=0; i<6; i++)
+ {
+ L = (ULONG)strlen(sysname[i]);
+ if(!SString::_strnicmp(szName,sysname[i],L))
+ {
+ if((szName[L]==0)|| strchr(syssymbol,szName[L]))
+ {
+ REPORT_ERROR0(VLDTR_E_FILE_SYSNAME);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ }
+ }
+ }
+ }
+
+ if (pRecord->GetFlags() & (~0x00000003))
+ {
+ REPORT_ERROR1(VLDTR_E_FILE_BADFLAGS, pRecord->GetFlags());
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Validate hash value
+ {
+ const BYTE *pbHashValue = NULL;
+ ULONG cbHashValue;
+ IfFailGo(m_pStgdb->m_MiniMd.getHashValueOfFile(pRecord, &pbHashValue, &cbHashValue));
+ if ((pbHashValue == NULL) || (cbHashValue == 0))
+ {
+ REPORT_ERROR0(VLDTR_E_FILE_NULLHASH);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+
+ // Validate that the name is not the same as the file containing
+ // the manifest.
+
+ // File name must be a valid file name.
+
+ // Each ModuleRef in the assembly must have a corresponding File table entry.
+
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateFile()
+
+//*****************************************************************************
+// Validate the given ExportedType.
+//*****************************************************************************
+HRESULT RegMeta::ValidateExportedType(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
+ ExportedTypeRec *pRecord; // ExportedType record.
+ mdExportedType tkExportedType; // Duplicate ExportedType.
+ mdToken tkImpl; // Implementation token
+ mdToken tkTypeDef; // TypeDef token
+
+ LPCSTR szName; // ExportedType Name.
+ LPCSTR szNamespace; // ExportedType Namespace.
+ VEContext veCtxt; // Context structure.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+ veCtxt.Token = TokenFromRid(rid, mdtExportedType);
+ veCtxt.uOffset = 0;
+
+ // Get the ExportedType record.
+ IfFailGo(pMiniMd->GetExportedTypeRecord(rid, &pRecord));
+
+ tkImpl = pMiniMd->getImplementationOfExportedType(pRecord);
+
+ tkTypeDef = pRecord->GetTypeDefId();
+ if ((TypeFromToken(tkImpl) == mdtFile) && IsNilToken(tkTypeDef))
+ { // Report 'No TypeDefId' warning only for types exported from other modules (do not report it for
+ // type forwarders)
+ REPORT_ERROR0(VLDTR_E_CT_NOTYPEDEFID);
+ SetVldtrCode(&hrSave, VLDTR_S_WRN);
+ }
+
+ // Do checks for name validity.
+ IfFailGo(pMiniMd->getTypeNameOfExportedType(pRecord, &szName));
+ IfFailGo(pMiniMd->getTypeNamespaceOfExportedType(pRecord, &szNamespace));
+ if (!*szName)
+ {
+ // ExportedType Name is null.
+ REPORT_ERROR0(VLDTR_E_CT_NAMENULL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ {
+ if(!strcmp(szName,COR_DELETED_NAME_A)) goto ErrExit;
+ ULONG L = (ULONG)(strlen(szName)+strlen(szNamespace));
+ if(L >= MAX_CLASSNAME_LENGTH)
+ {
+ // Name too long
+ REPORT_ERROR2(VLDTR_E_TD_NAMETOOLONG, L, (ULONG)(MAX_CLASSNAME_LENGTH-1));
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Check for duplicates based on Name and Enclosing ExportedType.
+ hr = ImportHelper::FindExportedType(pMiniMd, szNamespace, szName, tkImpl, &tkExportedType, rid);
+ if (hr == S_OK)
+ {
+ REPORT_ERROR1(VLDTR_E_CT_DUP, tkExportedType);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else if (hr == CLDB_E_RECORD_NOTFOUND)
+ hr = S_OK;
+ else
+ IfFailGo(hr);
+ // Check for duplicate TypeDef based on Name/NameSpace - only for top-level ExportedTypes.
+ if(TypeFromToken(tkImpl)==mdtFile)
+ {
+ mdToken tkTypeDef2;
+ hr = ImportHelper::FindTypeDefByName(pMiniMd, szNamespace, szName, mdTypeDefNil,
+ &tkTypeDef2, 0);
+ if (hr == S_OK)
+ {
+ REPORT_ERROR1(VLDTR_E_CT_DUPTDNAME, tkTypeDef2);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else if (hr == CLDB_E_RECORD_NOTFOUND)
+ hr = S_OK;
+ else
+ IfFailGo(hr);
+ }
+ }
+ // Check if flag value is valid
+ {
+ DWORD dwFlags = pRecord->GetFlags();
+ DWORD dwInvalidMask, dwExtraBits;
+ dwInvalidMask = (DWORD)~(tdVisibilityMask | tdLayoutMask | tdClassSemanticsMask |
+ tdAbstract | tdSealed | tdSpecialName | tdImport | tdSerializable | tdForwarder |
+ tdStringFormatMask | tdBeforeFieldInit | tdReservedMask);
+ // check for extra bits
+ dwExtraBits = dwFlags & dwInvalidMask;
+ if(!dwExtraBits)
+ {
+ // if no extra bits, check layout
+ dwExtraBits = dwFlags & tdLayoutMask;
+ if(dwExtraBits != tdLayoutMask)
+ {
+ // layout OK, check string format
+ dwExtraBits = dwFlags & tdStringFormatMask;
+ if(dwExtraBits != tdStringFormatMask) dwExtraBits = 0;
+ }
+ }
+ if(dwExtraBits)
+ {
+ REPORT_ERROR1(VLDTR_E_TD_EXTRAFLAGS, dwExtraBits);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+
+ if(IsNilToken(tkImpl)
+ || ((TypeFromToken(tkImpl) != mdtFile)&&(TypeFromToken(tkImpl) != mdtExportedType)&&(TypeFromToken(tkImpl) != mdtAssemblyRef))
+ || (!IsValidToken(tkImpl)))
+ {
+ REPORT_ERROR1(VLDTR_E_CT_BADIMPL, tkImpl);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateExportedType()
+
+//*****************************************************************************
+// Validate the given ManifestResource.
+//*****************************************************************************
+HRESULT RegMeta::ValidateManifestResource(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
+ ManifestResourceRec *pRecord; // ManifestResource record.
+ LPCSTR szName; // ManifestResource Name.
+ DWORD dwFlags; // ManifestResource flags.
+ mdManifestResource tkmar; // Duplicate ManifestResource.
+ VEContext veCtxt; // Context structure.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+ mdToken tkImplementation;
+ BOOL bIsValidImplementation = TRUE;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+ veCtxt.Token = TokenFromRid(rid, mdtManifestResource);
+ veCtxt.uOffset = 0;
+
+ // Get the ManifestResource record.
+ IfFailGo(pMiniMd->GetManifestResourceRecord(rid, &pRecord));
+
+ // Do checks for name validity.
+ IfFailGo(pMiniMd->getNameOfManifestResource(pRecord, &szName));
+ if (!*szName)
+ {
+ // ManifestResource Name is null.
+ REPORT_ERROR0(VLDTR_E_MAR_NAMENULL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ {
+ // Check for duplicates based on Name.
+ hr = ImportHelper::FindManifestResource(pMiniMd, szName, &tkmar, rid);
+ if (hr == S_OK)
+ {
+ REPORT_ERROR1(VLDTR_E_MAR_DUP, tkmar);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else if (hr == CLDB_E_RECORD_NOTFOUND)
+ hr = S_OK;
+ else
+ IfFailGo(hr);
+ }
+
+ // Get the flags of the ManifestResource.
+ dwFlags = pMiniMd->getFlagsOfManifestResource(pRecord);
+ if(dwFlags &(~0x00000003))
+ {
+ REPORT_ERROR1(VLDTR_E_MAR_BADFLAGS, dwFlags);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Visibility of ManifestResource flags must either be public or private.
+ if (!IsMrPublic(dwFlags) && !IsMrPrivate(dwFlags))
+ {
+ REPORT_ERROR0(VLDTR_E_MAR_NOTPUBPRIV);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Implementation must be Nil or valid AssemblyRef or File
+ tkImplementation = pMiniMd->getImplementationOfManifestResource(pRecord);
+ if(!IsNilToken(tkImplementation))
+ {
+ switch(TypeFromToken(tkImplementation))
+ {
+ case mdtAssemblyRef:
+ bIsValidImplementation = IsValidToken(tkImplementation);
+ break;
+ case mdtFile:
+ if((bIsValidImplementation = IsValidToken(tkImplementation)))
+ { // if file not PE, offset must be 0
+ FileRec *pFR;
+ IfFailGo(pMiniMd->GetFileRecord(RidFromToken(tkImplementation), &pFR));
+ if(IsFfContainsNoMetaData(pFR->GetFlags())
+ && pRecord->GetOffset())
+ {
+ REPORT_ERROR1(VLDTR_E_MAR_BADOFFSET, tkImplementation);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ break;
+ default:
+ bIsValidImplementation = FALSE;
+ }
+ }
+ if(!bIsValidImplementation)
+ {
+ REPORT_ERROR1(VLDTR_E_MAR_BADIMPL, tkImplementation);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Validate the Offset into the PE file.
+
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateManifestResource()
+
+//*****************************************************************************
+// Validate the given NestedClass.
+//*****************************************************************************
+HRESULT RegMeta::ValidateNestedClass(RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
+ NestedClassRec *pRecord; // NestedClass record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save the current state.
+ VEContext veCtxt; // Context structure.
+ mdToken tkNested;
+ mdToken tkEncloser;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+ veCtxt.Token = rid;
+ veCtxt.uOffset = 0;
+
+ // Get the NestedClass record.
+ IfFailGo(pMiniMd->GetNestedClassRecord(rid, &pRecord));
+ tkNested = pMiniMd->getNestedClassOfNestedClass(pRecord);
+ tkEncloser = pMiniMd->getEnclosingClassOfNestedClass(pRecord);
+
+ // Nested must be valid TypeDef
+ if((TypeFromToken(tkNested) != mdtTypeDef) || !IsValidToken(tkNested))
+ {
+ REPORT_ERROR1(VLDTR_E_NC_BADNESTED, tkNested);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Encloser must be valid TypeDef
+ if((TypeFromToken(tkEncloser) != mdtTypeDef) || !IsValidToken(tkEncloser))
+ {
+ REPORT_ERROR1(VLDTR_E_NC_BADENCLOSER, tkEncloser);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ // Check for duplicates
+ {
+ RID N = pMiniMd->getCountNestedClasss();
+ RID tmp;
+ NestedClassRec* pRecTmp;
+ mdToken tkEncloserTmp;
+ for(tmp = rid+1; tmp <= N; tmp++)
+ {
+ IfFailGo(pMiniMd->GetNestedClassRecord(tmp, &pRecTmp));
+ if(tkNested == pMiniMd->getNestedClassOfNestedClass(pRecTmp))
+ {
+ if(tkEncloser == (tkEncloserTmp = pMiniMd->getEnclosingClassOfNestedClass(pRecTmp)))
+ {
+ REPORT_ERROR1(VLDTR_E_NC_DUP, tmp);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ else
+ {
+ REPORT_ERROR3(VLDTR_E_NC_DUPENCLOSER, tkNested, tkEncloser, tkEncloserTmp);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ }
+ }
+
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateLocalVariable()
+
+//*****************************************************************************
+// Given a Table ID and a Row ID, validate all the columns contain meaningful
+// values given the column definitions. Validate that the offsets into the
+// different pools are valid, the rids are within range and the coded tokens
+// are valid. Every failure here is considered an error.
+//*****************************************************************************
+HRESULT RegMeta::ValidateRecord(ULONG ixTbl, RID rid)
+{
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save the current state.
+ ULONG ulCount; // Count of records in the table.
+ ULONG ulRawColVal; // Raw value of the column.
+ void *pRow; // Row with the data.
+ CMiniTableDef *pTbl; // Table definition.
+ CMiniColDef *pCol; // Column definition.
+ const CCodedTokenDef *pCdTkn; // Coded token definition.
+ ULONG ix; // Index into the array of coded tokens.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ // Get the table definition.
+ pTbl = &pMiniMd->m_TableDefs[ixTbl];
+
+ // Get the row. We may assume that the Row pointer we get back from
+ // this call is correct since we do the verification on the Record
+ // pools for each table during the open sequence. The only place
+ // this is not valid is for Dynamic IL and we don't do this
+ // verification in that case since we go through IMetaData* APIs
+ // in that case and it should all be consistent.
+ IfFailGo(m_pStgdb->m_MiniMd.getRow(ixTbl, rid, &pRow));
+
+ for (ULONG ixCol = 0; ixCol < pTbl->m_cCols; ixCol++)
+ {
+ // Get the column definition.
+ pCol = &pTbl->m_pColDefs[ixCol];
+
+ // Get the raw value stored in the column. getIX currently doesn't
+ // handle byte sized fields, but there are some BYTE fields in the
+ // MetaData. So using the conditional to access BYTE fields.
+ if (pCol->m_cbColumn == 1)
+ ulRawColVal = pMiniMd->getI1(pRow, *pCol);
+ else
+ ulRawColVal = pMiniMd->getIX(pRow, *pCol);
+
+ // Do some basic checks on the non-absurdity of the value stored in the
+ // column.
+ if (IsRidType(pCol->m_Type))
+ {
+ // Verify that the RID is within range.
+ _ASSERTE(pCol->m_Type < pMiniMd->GetCountTables());
+ ulCount = pMiniMd->GetCountRecs(pCol->m_Type);
+ // For records storing rids to pointer tables, the stored value may
+ // be one beyond the last record.
+ if (IsTblPtr(pCol->m_Type, ixTbl))
+ ulCount++;
+ if (ulRawColVal > ulCount)
+ {
+ VEContext veCtxt;
+ memset(&veCtxt, 0, sizeof(VEContext));
+ veCtxt.Token = 0;
+ veCtxt.uOffset = 0;
+ REPORT_ERROR3(VLDTR_E_RID_OUTOFRANGE, ixTbl, ixCol, rid);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ else if (IsCodedTokenType(pCol->m_Type))
+ {
+ // Verify that the Coded token and rid are valid.
+ pCdTkn = &g_CodedTokens[pCol->m_Type - iCodedToken];
+ ix = ulRawColVal & ~(-1 << CMiniMdRW::m_cb[pCdTkn->m_cTokens]);
+ if (ix >= pCdTkn->m_cTokens)
+ {
+ VEContext veCtxt;
+ memset(&veCtxt, 0, sizeof(VEContext));
+ veCtxt.Token = 0;
+ veCtxt.uOffset = 0;
+ REPORT_ERROR3(VLDTR_E_CDTKN_OUTOFRANGE, ixTbl, ixCol, rid);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ ulCount = pMiniMd->GetCountRecs(TypeFromToken(pCdTkn->m_pTokens[ix]) >> 24);
+ if ( (ulRawColVal >> CMiniMdRW::m_cb[pCdTkn->m_cTokens]) > ulCount)
+ {
+ VEContext veCtxt;
+ memset(&veCtxt, 0, sizeof(VEContext));
+ veCtxt.Token = 0;
+ veCtxt.uOffset = 0;
+ REPORT_ERROR3(VLDTR_E_CDRID_OUTOFRANGE, ixTbl, ixCol, rid);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ else if (IsHeapType(pCol->m_Type))
+ {
+ // Verify that the offsets for the Heap type fields are valid offsets
+ // into the heaps.
+ switch (pCol->m_Type)
+ {
+ case iSTRING:
+ if (!pMiniMd->m_StringHeap.IsValidIndex(ulRawColVal))
+ {
+ VEContext veCtxt;
+ memset(&veCtxt, 0, sizeof(VEContext));
+ veCtxt.Token = 0;
+ veCtxt.uOffset = 0;
+ REPORT_ERROR3(VLDTR_E_STRING_INVALID, ixTbl, ixCol, rid);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ break;
+ case iGUID:
+ if (ulRawColVal == 0)
+ { // GUID value 0 is valid value, though it's invalid GUID heap index
+ break;
+ }
+ if (!pMiniMd->m_GuidHeap.IsValidIndex(ulRawColVal))
+ {
+ VEContext veCtxt;
+ memset(&veCtxt, 0, sizeof(VEContext));
+ veCtxt.Token = 0;
+ veCtxt.uOffset = 0;
+ REPORT_ERROR3(VLDTR_E_GUID_INVALID, ixTbl, ixCol, rid);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ break;
+ case iBLOB:
+ if (! pMiniMd->m_BlobHeap.IsValidIndex(ulRawColVal))
+ {
+ VEContext veCtxt;
+ memset(&veCtxt, 0, sizeof(VEContext));
+ veCtxt.Token = 0;
+ veCtxt.uOffset = 0;
+ REPORT_ERROR3(VLDTR_E_BLOB_INVALID, ixTbl, ixCol, rid);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ break;
+ default:
+ _ASSERTE(!"Invalid heap type encountered!");
+ }
+ }
+ else
+ {
+ // Not much checking that can be done on the fixed type in a generic sense.
+ _ASSERTE (IsFixedType(pCol->m_Type));
+ }
+ hr = hrSave;
+ }
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateRecord()
+
+//*****************************************************************************
+// This function validates that the given Method signature is consistent as per
+// the compression scheme.
+//*****************************************************************************
+HRESULT RegMeta::ValidateSigCompression(
+ mdToken tk, // [IN] Token whose signature needs to be validated.
+ PCCOR_SIGNATURE pbSig, // [IN] Signature.
+ ULONG cbSig) // [IN] Size in bytes of the signature.
+{
+ VEContext veCtxt; // Context record.
+ ULONG ulCurByte = 0; // Current index into the signature.
+ ULONG ulSize; // Size of uncompressed data at each point.
+ HRESULT hr = S_OK; // Value returned.
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+ veCtxt.Token = tk;
+ veCtxt.uOffset = 0;
+
+ // Check for NULL signature.
+ if (!cbSig)
+ {
+ REPORT_ERROR0(VLDTR_E_SIGNULL);
+ SetVldtrCode(&hr, VLDTR_S_ERR);
+ goto ErrExit;
+ }
+
+ // Walk through the signature. At each point make sure there is enough
+ // room left in the signature based on the encoding in the current byte.
+ while (cbSig - ulCurByte)
+ {
+ _ASSERTE(ulCurByte <= cbSig);
+ // Get next chunk of uncompressed data size.
+ if ((ulSize = CorSigUncompressedDataSize(pbSig)) > (cbSig - ulCurByte))
+ {
+ REPORT_ERROR1(VLDTR_E_SIGNODATA, ulCurByte+1);
+ SetVldtrCode(&hr, VLDTR_S_ERR);
+ goto ErrExit;
+ }
+ // Go past this chunk.
+ ulCurByte += ulSize;
+ CorSigUncompressData(pbSig);
+ }
+ErrExit:
+
+ return hr;
+} // RegMeta::ValidateSigCompression()
+
+//*****************************************************************************
+// This function validates one argument given an offset into the signature
+// where the argument begins. This function assumes that the signature is well
+// formed as far as the compression scheme is concerned.
+//*****************************************************************************
+//@GENERICS: todo: reject uninstantiated generic types used as types.
+#ifdef _PREFAST_
+#pragma warning(push)
+#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
+#endif
+HRESULT RegMeta::ValidateOneArg(
+ mdToken tk, // [IN] Token whose signature is being processed.
+ PCCOR_SIGNATURE &pbSig, // [IN] Pointer to the beginning of argument.
+ ULONG cbSig, // [IN] Size in bytes of the full signature.
+ ULONG *pulCurByte, // [IN/OUT] Current offset into the signature..
+ ULONG *pulNSentinels, // [IN/OUT] Number of sentinels
+ BOOL bNoVoidAllowed) // [IN] Flag indicating whether "void" is disallowed for this arg
+{
+ ULONG ulElementType; // Current element type being processed.
+ ULONG ulElemSize; // Size of the element type.
+ mdToken token; // Embedded token.
+ ULONG ulArgCnt; // Argument count for function pointer.
+ ULONG ulRank; // Rank of the array.
+ ULONG ulSizes; // Count of sized dimensions of the array.
+ ULONG ulLbnds; // Count of lower bounds of the array.
+ ULONG ulTkSize; // Token size.
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+ BOOL bRepeat = TRUE; // MODOPT and MODREQ belong to the arg after them
+ BOOL bByRefForbidden = FALSE;// ByRef is not allowed for fields
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ switch(TypeFromToken(tk))
+ {
+ case mdtFieldDef:
+ bByRefForbidden = TRUE;
+ break;
+ case mdtName:
+ tk = TokenFromRid(RidFromToken(tk),mdtFieldDef);
+ // Field type can be a FNPTR with a sig containing ByRefs.
+ // So we change the token type not to be mdtFieldDef and thus allow ByRefs,
+ // but the token needs to be restored to its original type for reporting
+ break;
+ }
+
+ _ASSERTE (pulCurByte);
+ memset(&veCtxt, 0, sizeof(VEContext));
+ veCtxt.Token = tk;
+ veCtxt.uOffset = 0;
+
+ while(bRepeat)
+ {
+ bRepeat = FALSE;
+ // Validate that the argument is not missing.
+ _ASSERTE(*pulCurByte <= cbSig);
+ if (cbSig == *pulCurByte)
+ {
+ hr = VLDTR_E_SIG_MISSARG;
+ goto ErrExit;
+ }
+
+ // Get the element type.
+ *pulCurByte += (ulElemSize = CorSigUncompressedDataSize(pbSig));
+ ulElementType = CorSigUncompressData(pbSig);
+
+ // Walk past all the modifier types.
+ while (ulElementType & ELEMENT_TYPE_MODIFIER)
+ {
+ _ASSERTE(*pulCurByte <= cbSig);
+ if(ulElementType == ELEMENT_TYPE_SENTINEL)
+ {
+ if(pulNSentinels) *pulNSentinels+=1;
+ if(TypeFromToken(tk) == mdtMethodDef)
+ {
+ REPORT_ERROR0(VLDTR_E_SIG_SENTINMETHODDEF);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ if (cbSig == *pulCurByte)
+ {
+ REPORT_ERROR0(VLDTR_E_SIG_LASTSENTINEL);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ goto ErrExit;
+ }
+ }
+ if (cbSig == *pulCurByte)
+ {
+ REPORT_ERROR2(VLDTR_E_SIG_MISSELTYPE, ulElementType, *pulCurByte + 1);
+ SetVldtrCode(&hr, hrSave);
+ goto ErrExit;
+ }
+ *pulCurByte += (ulElemSize = CorSigUncompressedDataSize(pbSig));
+ ulElementType = CorSigUncompressData(pbSig);
+ }
+
+ switch (ulElementType)
+ {
+ case ELEMENT_TYPE_VOID:
+ if(bNoVoidAllowed)
+ {
+ IfBreakGo(m_pVEHandler->VEHandler(VLDTR_E_SIG_BADVOID, veCtxt, 0));
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ case ELEMENT_TYPE_BOOLEAN:
+ case ELEMENT_TYPE_CHAR:
+ case ELEMENT_TYPE_I1:
+ case ELEMENT_TYPE_U1:
+ case ELEMENT_TYPE_I2:
+ case ELEMENT_TYPE_U2:
+ case ELEMENT_TYPE_I4:
+ case ELEMENT_TYPE_U4:
+ case ELEMENT_TYPE_I8:
+ case ELEMENT_TYPE_U8:
+ case ELEMENT_TYPE_R4:
+ case ELEMENT_TYPE_R8:
+ case ELEMENT_TYPE_STRING:
+ case ELEMENT_TYPE_OBJECT:
+ case ELEMENT_TYPE_TYPEDBYREF:
+ case ELEMENT_TYPE_U:
+ case ELEMENT_TYPE_I:
+ break;
+ case ELEMENT_TYPE_BYREF: //fallthru
+ if(bByRefForbidden)
+ {
+ IfBreakGo(m_pVEHandler->VEHandler(VLDTR_E_SIG_BYREFINFIELD, veCtxt, 0));
+ SetVldtrCode(&hr, hrSave);
+ }
+ case ELEMENT_TYPE_PTR:
+ // Validate the referenced type.
+ IfFailGo(ValidateOneArg(tk, pbSig, cbSig, pulCurByte,pulNSentinels,FALSE));
+ if (hr != S_OK)
+ SetVldtrCode(&hrSave, hr);
+ break;
+ case ELEMENT_TYPE_PINNED:
+ case ELEMENT_TYPE_SZARRAY:
+ // Validate the referenced type.
+ IfFailGo(ValidateOneArg(tk, pbSig, cbSig, pulCurByte,pulNSentinels,TRUE));
+ if (hr != S_OK)
+ SetVldtrCode(&hrSave, hr);
+ break;
+ case ELEMENT_TYPE_VALUETYPE: //fallthru
+ case ELEMENT_TYPE_CLASS:
+ case ELEMENT_TYPE_CMOD_OPT:
+ case ELEMENT_TYPE_CMOD_REQD:
+ // See if the token is missing.
+ _ASSERTE(*pulCurByte <= cbSig);
+ if (cbSig == *pulCurByte)
+ {
+ REPORT_ERROR1(VLDTR_E_SIG_MISSTKN, ulElementType);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ }
+ // See if the token is a valid token.
+ ulTkSize = CorSigUncompressedDataSize(pbSig);
+ token = CorSigUncompressToken(pbSig);
+ if (!IsValidToken(token))
+ {
+ REPORT_ERROR2(VLDTR_E_SIG_TKNBAD, token, *pulCurByte);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ *pulCurByte += ulTkSize;
+ break;
+ }
+ *pulCurByte += ulTkSize;
+ if ((ulElementType == ELEMENT_TYPE_CLASS) || (ulElementType == ELEMENT_TYPE_VALUETYPE))
+ {
+ // Check for long-form encoding
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ LPCSTR szName = ""; // token's Name.
+ LPCSTR szNameSpace = ""; // token's NameSpace.
+
+
+ // Check for TypeDef or TypeRef
+ // To prevent cycles in metadata, token must not be a TypeSpec.
+ if ((TypeFromToken(token) != mdtTypeRef) && (TypeFromToken(token) != mdtTypeDef))
+ {
+ REPORT_ERROR2(VLDTR_E_SIG_BADTOKTYPE, token, *pulCurByte);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ if (TypeFromToken(token) == mdtTypeRef)
+ {
+ TypeRefRec *pTokenRec;
+ IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(token), &pTokenRec));
+ mdToken tkResScope = pMiniMd->getResolutionScopeOfTypeRef(pTokenRec);
+ if (RidFromToken(tkResScope) && (TypeFromToken(tkResScope) == mdtAssemblyRef))
+ {
+ AssemblyRefRec * pARRec;
+ IfFailGo(pMiniMd->GetAssemblyRefRecord(RidFromToken(tkResScope), &pARRec));
+ LPCSTR szAssemblyRefName;
+ IfFailGo(pMiniMd->getNameOfAssemblyRef(pARRec, &szAssemblyRefName));
+ if((0 == SString::_stricmp("mscorlib", szAssemblyRefName)) || (0 == SString::_stricmp("System.Runtime", szAssemblyRefName)))
+ {
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTokenRec, &szNameSpace));
+ IfFailGo(pMiniMd->getNameOfTypeRef(pTokenRec, &szName));
+ }
+ }
+ }
+ else if (TypeFromToken(token) == mdtTypeDef)
+ {
+ TypeDefRec *pTokenRec;
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(token), &pTokenRec));
+ if(g_fValidatingMscorlib) // otherwise don't even bother checking the name
+ {
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTokenRec, &szName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTokenRec, &szNameSpace));
+ }
+ // while at it, check if token is indeed a class (valuetype)
+ BOOL bValueType = FALSE;
+ if(!IsTdInterface(pTokenRec->GetFlags()))
+ {
+ mdToken tkExtends = pMiniMd->getExtendsOfTypeDef(pTokenRec);
+ if(RidFromToken(tkExtends))
+ {
+ LPCSTR szExtName = ""; // parent's Name.
+ LPCSTR szExtNameSpace = ""; // parent's NameSpace.
+ if(TypeFromToken(tkExtends)==mdtTypeRef)
+ {
+ TypeRefRec *pExtRec;
+ IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tkExtends), &pExtRec));
+ mdToken tkResScope = pMiniMd->getResolutionScopeOfTypeRef(pExtRec);
+ if(RidFromToken(tkResScope) && (TypeFromToken(tkResScope)==mdtAssemblyRef))
+ {
+ AssemblyRefRec *pARRec;
+ IfFailGo(pMiniMd->GetAssemblyRefRecord(RidFromToken(tkResScope), &pARRec));
+ LPCSTR szAssemblyRefName;
+ IfFailGo(pMiniMd->getNameOfAssemblyRef(pARRec, &szAssemblyRefName));
+ if((0 == SString::_stricmp("mscorlib", szAssemblyRefName)) || (0 == SString::_stricmp("System.Runtime", szAssemblyRefName)))
+ {
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pExtRec, &szExtNameSpace));
+ IfFailGo(pMiniMd->getNameOfTypeRef(pExtRec, &szExtName));
+ }
+ }
+ }
+ else if(TypeFromToken(tkExtends)==mdtTypeDef)
+ {
+ if(g_fValidatingMscorlib) // otherwise don't even bother checking the name
+ {
+ TypeDefRec *pExtRec;
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkExtends), &pExtRec));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pExtRec, &szExtName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pExtRec, &szExtNameSpace));
+ }
+ }
+ if(0 == strcmp(szExtNameSpace,BASE_NAMESPACE))
+ {
+ if(0==strcmp(szExtName,BASE_ENUM_CLASSNAME)) bValueType = TRUE;
+ else if(0==strcmp(szExtName,BASE_VTYPE_CLASSNAME))
+ {
+ bValueType = (strcmp(szNameSpace,BASE_NAMESPACE) ||
+ strcmp(szName,BASE_ENUM_CLASSNAME));
+ }
+ }
+ }
+ }
+ if(bValueType != (ulElementType == ELEMENT_TYPE_VALUETYPE))
+ {
+ REPORT_ERROR2(VLDTR_E_SIG_TOKTYPEMISMATCH, token, *pulCurByte);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ }
+ if(0 == strcmp(szNameSpace,BASE_NAMESPACE))
+ {
+ for(unsigned jjj = 0; jjj < g_NumSigLongForms; jjj++)
+ {
+ if(0 == strcmp(szName,g_SigLongFormName[jjj]))
+ {
+ REPORT_ERROR2(VLDTR_E_SIG_LONGFORM, token, *pulCurByte);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ }
+ }
+ }
+ }
+ else // i.e. if(ELEMENT_TYPE_CMOD_OPT || ELEMENT_TYPE_CMOD_REQD)
+ bRepeat = TRUE; // go on validating, we're not done with this arg
+ break;
+
+ case ELEMENT_TYPE_FNPTR:
+ // Validate that calling convention is present.
+ _ASSERTE(*pulCurByte <= cbSig);
+ if (cbSig == *pulCurByte)
+ {
+ REPORT_ERROR1(VLDTR_E_SIG_MISSFPTR, *pulCurByte + 1);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ }
+ // Consume calling convention.
+ *pulCurByte += CorSigUncompressedDataSize(pbSig);
+ CorSigUncompressData(pbSig);
+
+ // Validate that argument count is present.
+ _ASSERTE(*pulCurByte <= cbSig);
+ if (cbSig == *pulCurByte)
+ {
+ REPORT_ERROR1(VLDTR_E_SIG_MISSFPTRARGCNT, *pulCurByte + 1);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ }
+ // Consume argument count.
+ *pulCurByte += CorSigUncompressedDataSize(pbSig);
+ ulArgCnt = CorSigUncompressData(pbSig);
+
+ // Checking the signature, ByRefs OK
+ if(bByRefForbidden)
+ tk = TokenFromRid(RidFromToken(tk),mdtName);
+
+ // Validate and consume return type.
+ IfFailGo(ValidateOneArg(tk, pbSig, cbSig, pulCurByte,NULL,FALSE));
+ if (hr != S_OK)
+ {
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ }
+
+ // Validate and consume the arguments.
+ while(ulArgCnt--)
+ {
+ IfFailGo(ValidateOneArg(tk, pbSig, cbSig, pulCurByte,NULL,TRUE));
+ if (hr != S_OK)
+ {
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ }
+ }
+ break;
+
+ case ELEMENT_TYPE_ARRAY:
+ // Validate and consume the base type.
+ IfFailGo(ValidateOneArg(tk, pbSig, cbSig, pulCurByte,pulNSentinels,TRUE));
+
+ // Validate that the rank is present.
+ _ASSERTE(*pulCurByte <= cbSig);
+ if (cbSig == *pulCurByte)
+ {
+ REPORT_ERROR1(VLDTR_E_SIG_MISSRANK, *pulCurByte + 1);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ }
+ // Consume the rank.
+ *pulCurByte += CorSigUncompressedDataSize(pbSig);
+ ulRank = CorSigUncompressData(pbSig);
+
+ // Process the sizes.
+ if (ulRank)
+ {
+ // Validate that the count of sized-dimensions is specified.
+ _ASSERTE(*pulCurByte <= cbSig);
+ if (cbSig == *pulCurByte)
+ {
+ REPORT_ERROR1(VLDTR_E_SIG_MISSNSIZE, *pulCurByte + 1);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ }
+ // Consume the count of sized dimensions.
+ *pulCurByte += CorSigUncompressedDataSize(pbSig);
+ ulSizes = CorSigUncompressData(pbSig);
+
+ // Loop over the sizes.
+ while (ulSizes--)
+ {
+ // Validate the current size.
+ _ASSERTE(*pulCurByte <= cbSig);
+ if (cbSig == *pulCurByte)
+ {
+ REPORT_ERROR1(VLDTR_E_SIG_MISSSIZE, *pulCurByte + 1);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ }
+ // Consume the current size.
+ *pulCurByte += CorSigUncompressedDataSize(pbSig);
+ CorSigUncompressData(pbSig);
+ }
+
+ // Validate that the count of lower bounds is specified.
+ _ASSERTE(*pulCurByte <= cbSig);
+ if (cbSig == *pulCurByte)
+ {
+ REPORT_ERROR1(VLDTR_E_SIG_MISSNLBND, *pulCurByte + 1);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ }
+ // Consume the count of lower bound.
+ *pulCurByte += CorSigUncompressedDataSize(pbSig);
+ ulLbnds = CorSigUncompressData(pbSig);
+
+ // Loop over the lower bounds.
+ while (ulLbnds--)
+ {
+ // Validate the current lower bound.
+ _ASSERTE(*pulCurByte <= cbSig);
+ if (cbSig == *pulCurByte)
+ {
+ REPORT_ERROR1(VLDTR_E_SIG_MISSLBND, *pulCurByte + 1);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ }
+ // Consume the current size.
+ *pulCurByte += CorSigUncompressedDataSize(pbSig);
+ CorSigUncompressData(pbSig);
+ }
+ }
+ break;
+
+ case ELEMENT_TYPE_VAR:
+ case ELEMENT_TYPE_MVAR:
+ // Consume index.
+ *pulCurByte += CorSigUncompressedDataSize(pbSig);
+ CorSigUncompressData(pbSig);
+ break;
+
+ case ELEMENT_TYPE_GENERICINST:
+ {
+ PCCOR_SIGNATURE pbGenericTypeSig = pbSig;
+ BOOL fCheckArity = FALSE;
+ ULONG ulGenericArity = 0;
+
+ // Validate and consume the type constructor
+ IfFailGo(ValidateOneArg(tk, pbSig, cbSig, pulCurByte, NULL, TRUE));
+
+ // Extract its arity
+ {
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ switch(CorSigUncompressElementType(pbGenericTypeSig))
+ {
+ case ELEMENT_TYPE_VALUETYPE:
+ case ELEMENT_TYPE_CLASS:
+ {
+ mdToken tkGenericType = CorSigUncompressToken(pbGenericTypeSig);
+ if (TypeFromToken(tkGenericType) == mdtTypeDef)
+ {
+ HENUMInternal hEnumTyPars;
+ hr = pMiniMd->FindGenericParamHelper(tkGenericType, &hEnumTyPars);
+ if (SUCCEEDED(hr))
+ {
+ IfFailGo(HENUMInternal::GetCount(&hEnumTyPars,&ulGenericArity));
+ HENUMInternal::ClearEnum(&hEnumTyPars);
+ fCheckArity = TRUE;
+ }
+ ;
+ }
+ // for a mdtTypeRef, don't check anything until load time
+ break;
+ }
+ default:
+ break;
+ }
+
+ }
+
+ // Consume argument count.
+ if (cbSig == *pulCurByte)
+ {
+ REPORT_ERROR1(VLDTR_E_SIG_MISSARITY, *pulCurByte + 1);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ }
+
+ *pulCurByte += CorSigUncompressedDataSize(pbSig);
+ ulArgCnt = CorSigUncompressData(pbSig);
+
+ if (ulArgCnt == 0)
+ {
+ REPORT_ERROR1(VLDTR_E_SIG_ARITYZERO,*pulCurByte);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ if (fCheckArity && ulArgCnt != ulGenericArity)
+ {
+ REPORT_ERROR3(VLDTR_E_SIG_ARITYMISMATCH,ulGenericArity,ulArgCnt,*pulCurByte);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Validate and consume the arguments.
+ while(ulArgCnt--)
+ {
+ PCCOR_SIGNATURE pbTypeArg = pbSig;
+ ULONG ulTypeArgByte = *pulCurByte;
+ IfFailGo(ValidateOneArg(tk, pbSig, cbSig, pulCurByte, NULL, TRUE));
+ if (hr != S_OK)
+ {
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ }
+
+ // reject byref-like args
+ switch (CorSigUncompressData(pbTypeArg))
+ {
+ case ELEMENT_TYPE_TYPEDBYREF:
+ case ELEMENT_TYPE_BYREF:
+ {
+ REPORT_ERROR1(VLDTR_E_SIG_BYREFINST, ulTypeArgByte);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ break;
+ }
+
+
+ case ELEMENT_TYPE_SENTINEL: // this case never works because all modifiers are skipped before switch
+ if(TypeFromToken(tk) == mdtMethodDef)
+ {
+ REPORT_ERROR0(VLDTR_E_SIG_SENTINMETHODDEF);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ break;
+ default:
+ REPORT_ERROR2(VLDTR_E_SIG_BADELTYPE, ulElementType, *pulCurByte - ulElemSize);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ break;
+ } // switch (ulElementType)
+ } // end while(bRepeat)
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateOneArg()
+#ifdef _PREFAST_
+#pragma warning(pop)
+#endif
+
+//*****************************************************************************
+// This function validates the given Method signature. This function works
+// with Method signature for both the MemberRef and MethodDef.
+//*****************************************************************************
+HRESULT RegMeta::ValidateMethodSig(
+ mdToken tk, // [IN] Token whose signature needs to be validated.
+ PCCOR_SIGNATURE pbSig, // [IN] Signature.
+ ULONG cbSig, // [IN] Size in bytes of the signature.
+ DWORD dwFlags) // [IN] Method flags.
+{
+ ULONG ulCurByte = 0; // Current index into the signature.
+ ULONG ulCallConv; // Calling convention.
+ ULONG ulArgCount; // Count of arguments.
+ ULONG ulTyArgCount; // Count of type arguments.
+ ULONG i; // Looping index.
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+ ULONG ulNSentinels = 0;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ _ASSERTE(TypeFromToken(tk) == mdtMethodDef ||
+ TypeFromToken(tk) == mdtMemberRef);
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+ veCtxt.Token = tk;
+ veCtxt.uOffset = 0;
+
+ // Validate the signature is well-formed with respect to the compression
+ // scheme. If this fails, no further validation needs to be done.
+ if ((hr = ValidateSigCompression(tk, pbSig, cbSig)) != S_OK)
+ goto ErrExit;
+
+ // Validate the calling convention.
+ ulCurByte += CorSigUncompressedDataSize(pbSig);
+ ulCallConv = CorSigUncompressData(pbSig);
+
+ i = ulCallConv & IMAGE_CEE_CS_CALLCONV_MASK;
+ if ((i != IMAGE_CEE_CS_CALLCONV_DEFAULT)&&( i != IMAGE_CEE_CS_CALLCONV_VARARG)
+ || (ulCallConv & IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS))
+ {
+ REPORT_ERROR1(VLDTR_E_MD_BADCALLINGCONV, ulCallConv);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ if (TypeFromToken(tk) == mdtMethodDef) // MemberRefs have no flags available
+ {
+ // If HASTHIS is set on the calling convention, the method should not be static.
+ if ((ulCallConv & IMAGE_CEE_CS_CALLCONV_HASTHIS) &&
+ IsMdStatic(dwFlags))
+ {
+ REPORT_ERROR1(VLDTR_E_MD_THISSTATIC, ulCallConv);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // If HASTHIS is not set on the calling convention, the method should be static.
+ if (!(ulCallConv & IMAGE_CEE_CS_CALLCONV_HASTHIS) &&
+ !IsMdStatic(dwFlags))
+ {
+ REPORT_ERROR1(VLDTR_E_MD_NOTTHISNOTSTATIC, ulCallConv);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+
+ // Get the type argument count.
+ if (ulCallConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
+ {
+ if (i != IMAGE_CEE_CS_CALLCONV_DEFAULT)
+ {
+ REPORT_ERROR1(VLDTR_E_MD_GENERIC_BADCALLCONV, ulCallConv);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ if (cbSig == ulCurByte)
+ {
+ REPORT_ERROR1(VLDTR_E_MD_MISSARITY, ulCurByte+1);
+ SetVldtrCode(&hr, hrSave);
+ goto ErrExit;
+ }
+
+ ulCurByte += CorSigUncompressedDataSize(pbSig);
+ ulTyArgCount = CorSigUncompressData(pbSig);
+
+ if (ulTyArgCount == 0)
+ {
+ REPORT_ERROR1(VLDTR_E_MD_ARITYZERO, ulCurByte);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // If this is a def, check the arity against the number of generic params
+ if (TypeFromToken(tk) == mdtMethodDef)
+ {
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ ULONG ulGenericParamCount;
+ HENUMInternal hEnumTyPars;
+ hr = pMiniMd->FindGenericParamHelper(tk, &hEnumTyPars);
+ if (SUCCEEDED(hr))
+ {
+ IfFailGo(HENUMInternal::GetCount(&hEnumTyPars,&ulGenericParamCount));
+ HENUMInternal::ClearEnum(&hEnumTyPars);
+ if (ulTyArgCount != ulGenericParamCount)
+ {
+ REPORT_ERROR2(VLDTR_E_MD_GPMISMATCH,ulTyArgCount,ulGenericParamCount);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ }
+ }
+ }
+
+
+ // Is there any sig left for arguments?
+ _ASSERTE(ulCurByte <= cbSig);
+ if (cbSig == ulCurByte)
+ {
+ REPORT_ERROR1(VLDTR_E_MD_NOARGCNT, ulCurByte+1);
+ SetVldtrCode(&hr, hrSave);
+ goto ErrExit;
+ }
+
+ // Get the argument count.
+ ulCurByte += CorSigUncompressedDataSize(pbSig);
+ ulArgCount = CorSigUncompressData(pbSig);
+
+ // Validate the return type and the arguments.
+// for (i = 0; i < (ulArgCount + 1); i++)
+ for(i=1; ulCurByte < cbSig; i++)
+ {
+ hr = ValidateOneArg(tk, pbSig, cbSig, &ulCurByte,&ulNSentinels,(i > 1));
+ if (hr != S_OK)
+ {
+ if(hr == VLDTR_E_SIG_MISSARG)
+ {
+ REPORT_ERROR1(VLDTR_E_SIG_MISSARG, i);
+ }
+ SetVldtrCode(&hr, hrSave);
+ hrSave = hr;
+ break;
+ }
+ }
+ if((ulNSentinels != 0) && (!isCallConv(ulCallConv, IMAGE_CEE_CS_CALLCONV_VARARG )))
+ {
+ REPORT_ERROR0(VLDTR_E_SIG_SENTMUSTVARARG);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+ if(ulNSentinels > 1)
+ {
+ REPORT_ERROR0(VLDTR_E_SIG_MULTSENTINELS);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateMethodSig()
+
+//*****************************************************************************
+// This function validates the given Field signature. This function works
+// with Field signature for both the MemberRef and FieldDef.
+//*****************************************************************************
+HRESULT RegMeta::ValidateFieldSig(
+ mdToken tk, // [IN] Token whose signature needs to be validated.
+ PCCOR_SIGNATURE pbSig, // [IN] Signature.
+ ULONG cbSig) // [IN] Size in bytes of the signature.
+{
+ ULONG ulCurByte = 0; // Current index into the signature.
+ ULONG ulCallConv; // Calling convention.
+ VEContext veCtxt; // Context record.
+ HRESULT hr = S_OK; // Value returned.
+ HRESULT hrSave = S_OK; // Save state.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ _ASSERTE(TypeFromToken(tk) == mdtFieldDef ||
+ TypeFromToken(tk) == mdtMemberRef);
+
+ memset(&veCtxt, 0, sizeof(VEContext));
+ veCtxt.Token = tk;
+ veCtxt.uOffset = 0;
+
+ // Validate the calling convention.
+ ulCurByte += CorSigUncompressedDataSize(pbSig);
+ ulCallConv = CorSigUncompressData(pbSig);
+ if (!isCallConv(ulCallConv, IMAGE_CEE_CS_CALLCONV_FIELD ))
+ {
+ REPORT_ERROR1(VLDTR_E_FD_BADCALLINGCONV, ulCallConv);
+ SetVldtrCode(&hrSave, VLDTR_S_ERR);
+ }
+
+ // Validate the field.
+ IfFailGo(ValidateOneArg(tk, pbSig, cbSig, &ulCurByte,NULL,TRUE));
+ SetVldtrCode(&hrSave, hr);
+
+ hr = hrSave;
+ErrExit:
+ ;
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::ValidateFieldSig()
+
+//*****************************************************************************
+// This is a utility function to allocate a one-dimensional zero-based safe
+// array of variants.
+//*****************************************************************************
+static HRESULT _AllocSafeVariantArrayVector( // Return status.
+ VARIANT *rVar, // [IN] Variant array.
+ int cElem, // [IN] Size of the array.
+ SAFEARRAY **ppArray) // [OUT] Double pointer to SAFEARRAY.
+{
+ HRESULT hr = S_OK;
+ LONG i;
+
+ _ASSERTE(rVar && cElem && ppArray);
+
+ IfNullGo(*ppArray = SafeArrayCreateVector(VT_VARIANT, 0, cElem));
+ for (i = 0; i < cElem; i++)
+ IfFailGo(SafeArrayPutElement(*ppArray, &i, &rVar[i]));
+ErrExit:
+ return hr;
+} // _AllocSafeVariantArrayVector()
+
+//*****************************************************************************
+// Helper function for reporting error with no arguments
+//*****************************************************************************
+HRESULT RegMeta::_ValidateErrorHelper(
+ HRESULT VECode,
+ VEContext Context)
+{
+ HRESULT hr = S_OK;
+
+ //
+ // MDValidator does not zero out the Context. Fix it here. This fix relies
+ // on the fact that MDValidator just uses the token and offset field of the
+ // context.
+ //
+
+ if (Context.Token != 0) {
+ Context.flags = VER_ERR_TOKEN;
+ }
+
+ IfBreakGo(m_pVEHandler->VEHandler(VECode, Context, NULL));
+ErrExit:
+
+ return hr;
+} // _ValidateErrorHelper()
+
+//*****************************************************************************
+// Helper function for reporting error with 1 argument
+//*****************************************************************************
+HRESULT RegMeta::_ValidateErrorHelper(
+ HRESULT VECode,
+ VEContext Context,
+ ULONG ulVal1)
+{
+ HRESULT hr = S_OK;
+ SAFEARRAY *psa = 0; // The SAFEARRAY.
+ VARIANT rVar[1]; // The VARIANT array
+
+ if (Context.Token != 0) {
+ Context.flags = VER_ERR_TOKEN;
+ }
+
+ V_VT(&rVar[0]) = VT_UI4;
+ V_UI4(&rVar[0]) = ulVal1;
+ IfFailGo(_AllocSafeVariantArrayVector(rVar, 1, &psa));
+ IfBreakGo(m_pVEHandler->VEHandler(VECode, Context, psa));
+
+ErrExit:
+ if (psa)
+ {
+ HRESULT hrSave = SafeArrayDestroy(psa);
+ if (FAILED(hrSave))
+ hr = hrSave;
+ }
+ return hr;
+} // _ValidateErrorHelper()
+
+//*****************************************************************************
+// Helper function for reporting error with 2 arguments
+//*****************************************************************************
+HRESULT RegMeta::_ValidateErrorHelper(
+ HRESULT VECode,
+ VEContext Context,
+ ULONG ulVal1,
+ ULONG ulVal2)
+{
+ HRESULT hr = S_OK;
+ SAFEARRAY *psa = 0; // The SAFEARRAY.
+ VARIANT rVar[2]; // The VARIANT array
+
+ if (Context.Token != 0) {
+ Context.flags = VER_ERR_TOKEN;
+ }
+
+ V_VT(&rVar[0]) = VT_UI4;
+ V_UI4(&rVar[0]) = ulVal1;
+ V_VT(&rVar[1]) = VT_UI4;
+ V_UI4(&rVar[1]) = ulVal2;
+
+ IfFailGo(_AllocSafeVariantArrayVector(rVar, 2, &psa));
+ IfBreakGo(m_pVEHandler->VEHandler(VECode, Context, psa));
+
+ErrExit:
+ if (psa)
+ {
+ HRESULT hrSave = SafeArrayDestroy(psa);
+ if (FAILED(hrSave))
+ hr = hrSave;
+ }
+ return hr;
+} // _ValidateErrorHelper()
+
+//*****************************************************************************
+// Helper function for reporting error with 3 arguments
+//*****************************************************************************
+HRESULT RegMeta::_ValidateErrorHelper(
+ HRESULT VECode,
+ VEContext Context,
+ ULONG ulVal1,
+ ULONG ulVal2,
+ ULONG ulVal3)
+{
+ HRESULT hr = S_OK;
+ SAFEARRAY *psa = 0; // The SAFEARRAY.
+ VARIANT rVar[3]; // The VARIANT array
+
+ if (Context.Token != 0) {
+ Context.flags = VER_ERR_TOKEN;
+ }
+
+ V_VT(&rVar[0]) = VT_UI4;
+ V_UI4(&rVar[0]) = ulVal1;
+ V_VT(&rVar[1]) = VT_UI4;
+ V_UI4(&rVar[1]) = ulVal2;
+ V_VT(&rVar[2]) = VT_UI4;
+ V_UI4(&rVar[2]) = ulVal3;
+
+ IfFailGo(_AllocSafeVariantArrayVector(rVar, 3, &psa));
+ IfBreakGo(m_pVEHandler->VEHandler(VECode, Context, psa));
+
+ErrExit:
+ if (psa)
+ {
+ HRESULT hrSave = SafeArrayDestroy(psa);
+ if (FAILED(hrSave))
+ hr = hrSave;
+ }
+ return hr;
+}
+
+//*****************************************************************************
+// Helper function to see if there is a duplicate record for ClassLayout.
+//*****************************************************************************
+static HRESULT _FindClassLayout(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ mdTypeDef tkParent, // [IN] the parent that ClassLayout is associated with
+ RID *pclRid, // [OUT] rid for the ClassLayout.
+ RID rid) // [IN] rid to be ignored.
+{
+ HRESULT hr;
+ ULONG cClassLayoutRecs;
+ ClassLayoutRec *pRecord;
+ mdTypeDef tkParTmp;
+ ULONG i;
+
+ _ASSERTE(pMiniMd && pclRid && rid);
+ _ASSERTE(TypeFromToken(tkParent) == mdtTypeDef && RidFromToken(tkParent));
+
+ cClassLayoutRecs = pMiniMd->getCountClassLayouts();
+
+ for (i = 1; i <= cClassLayoutRecs; i++)
+ {
+ // Ignore the rid to be ignored!
+ if (rid == i)
+ continue;
+
+ IfFailRet(pMiniMd->GetClassLayoutRecord(i, &pRecord));
+ tkParTmp = pMiniMd->getParentOfClassLayout(pRecord);
+ if (tkParTmp == tkParent)
+ {
+ *pclRid = i;
+ return S_OK;
+ }
+ }
+ return CLDB_E_RECORD_NOTFOUND;
+} // _FindClassLayout()
+
+//*****************************************************************************
+// Helper function to see if there is a duplicate for FieldLayout.
+//*****************************************************************************
+static HRESULT _FindFieldLayout(
+ CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
+ mdFieldDef tkParent, // [IN] the parent that FieldLayout is associated with
+ RID *pflRid, // [OUT] rid for the FieldLayout record.
+ RID rid) // [IN] rid to be ignored.
+{
+ HRESULT hr;
+ ULONG cFieldLayoutRecs;
+ FieldLayoutRec *pRecord;
+ mdFieldDef tkField;
+ ULONG i;
+
+ _ASSERTE(pMiniMd && pflRid && rid);
+ _ASSERTE(TypeFromToken(tkParent) == mdtFieldDef && RidFromToken(tkParent));
+
+ cFieldLayoutRecs = pMiniMd->getCountFieldLayouts();
+
+ for (i = 1; i <= cFieldLayoutRecs; i++)
+ {
+ // Ignore the rid to be ignored!
+ if (rid == i)
+ continue;
+
+ IfFailRet(pMiniMd->GetFieldLayoutRecord(i, &pRecord));
+ tkField = pMiniMd->getFieldOfFieldLayout(pRecord);
+ if (tkField == tkParent)
+ {
+ *pflRid = i;
+ return S_OK;
+ }
+ }
+ return CLDB_E_RECORD_NOTFOUND;
+} // _FindFieldLayout()
+
+//*****************************************************************************
+//*****************************************************************************
+HRESULT
+MDSigComparer::CompareMethodSignature()
+{
+ HRESULT hr = S_OK;
+
+ EX_TRY
+ {
+ hr = _CompareMethodSignature();
+ }
+ EX_CATCH
+ {
+ hr = E_FAIL;
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ return hr;
+}
+
+//*****************************************************************************
+//*****************************************************************************
+HRESULT
+MDSigComparer::_CompareMethodSignature()
+{
+ HRESULT hr;
+
+ // Test equivalency of method signature header
+ ULONG cArgs;
+ IfFailRet(_CompareMethodSignatureHeader(cArgs));
+
+ // Iterate for cArgs + 1 to include the return type
+ for (ULONG i = 0; i < cArgs + 1; i++)
+ {
+ IfFailRet(_CompareExactlyOne());
+ }
+
+ return S_OK;
+}
+
+//*****************************************************************************
+//*****************************************************************************
+HRESULT
+MDSigComparer::_CompareExactlyOne()
+{
+ HRESULT hr;
+
+ CorElementType typ1, typ2;
+ IfFailRet(m_sig1.GetElemType(&typ1));
+ IfFailRet(m_sig2.GetElemType(&typ2));
+
+ if (typ1 != typ2)
+ {
+ return E_FAIL;
+ }
+
+ CorElementType typ = typ1;
+ if (!CorIsPrimitiveType((CorElementType)typ))
+ {
+ switch (typ)
+ {
+ default:
+ {
+ // _ASSERT(!"Illegal or unimplement type in COM+ sig.");
+ return META_E_BAD_SIGNATURE;
+ break;
+ }
+ case ELEMENT_TYPE_VAR:
+ case ELEMENT_TYPE_MVAR:
+ {
+ IfFailRet(_CompareData(NULL)); // Skip variable number
+ break;
+ }
+ case ELEMENT_TYPE_OBJECT:
+ case ELEMENT_TYPE_STRING:
+ case ELEMENT_TYPE_TYPEDBYREF:
+ {
+ break;
+ }
+
+ case ELEMENT_TYPE_BYREF: // fallthru
+ case ELEMENT_TYPE_PTR:
+ case ELEMENT_TYPE_PINNED:
+ case ELEMENT_TYPE_SZARRAY:
+ {
+ IfFailRet(_CompareExactlyOne()); // Compare referenced type
+ break;
+ }
+
+ case ELEMENT_TYPE_VALUETYPE: // fallthru
+ case ELEMENT_TYPE_CLASS:
+ {
+ mdToken tok1, tok2;
+ IfFailRet(m_sig1.GetToken(&tok1));
+ IfFailRet(m_sig2.GetToken(&tok2));
+ IfFailRet(m_comparer.CompareToken(tok1, tok2));
+ break;
+ }
+
+ case ELEMENT_TYPE_FNPTR:
+ {
+ IfFailRet(_CompareMethodSignature());
+ break;
+ }
+
+ case ELEMENT_TYPE_ARRAY:
+ {
+ IfFailRet(_CompareExactlyOne()); // Compare element type
+
+ ULONG rank;
+ IfFailRet(_CompareData(&rank)); // Compare & get rank
+
+ if (rank)
+ {
+ ULONG nsizes;
+ IfFailRet(_CompareData(&nsizes)); // Compare & get # of sizes
+ while (nsizes--)
+ {
+ IfFailRet(_CompareData(NULL)); // Compare size
+ }
+
+ ULONG nlbounds;
+ IfFailRet(_CompareData(&nlbounds)); // Compare & get # of lower bounds
+ while (nlbounds--)
+ {
+ IfFailRet(_CompareData(NULL)); // Compare lower bounds
+ }
+ }
+
+ break;
+ }
+
+ case ELEMENT_TYPE_SENTINEL:
+ {
+ // Should be unreachable since GetElem strips it
+ break;
+ }
+
+ case ELEMENT_TYPE_INTERNAL:
+ {
+ // Shouldn't ever get this since it is internal to the runtime,
+ // but just in case we know how to compare and skip these.
+ PVOID val1 = *((PVOID *)m_sig1.m_ptr);
+ PVOID val2 = *((PVOID *)m_sig2.m_ptr);
+
+ if (val1 != val2)
+ {
+ return E_FAIL;
+ }
+
+ m_sig1.SkipBytes(sizeof(void*));
+ m_sig2.SkipBytes(sizeof(void*));
+ break;
+ }
+
+ case ELEMENT_TYPE_GENERICINST:
+ {
+ IfFailRet(_CompareExactlyOne()); // Compare generic type
+ ULONG argCnt;
+ IfFailRet(_CompareData(&argCnt)); // Compare & get number of parameters
+ _ASSERTE(argCnt > 0);
+ while (argCnt--)
+ {
+ IfFailRet(_CompareExactlyOne()); // Compare the parameters
+ }
+ break;
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+//*****************************************************************************
+//*****************************************************************************
+HRESULT
+MDSigComparer::_CompareData(
+ ULONG *pulData)
+{
+ ULONG cbCompressedData1, cbCompressedData2;
+ ULONG ulData1, ulData2;
+
+ cbCompressedData1 = CorSigUncompressData(m_sig1.m_ptr, &ulData1);
+ cbCompressedData2 = CorSigUncompressData(m_sig2.m_ptr, &ulData2);
+
+ if ((cbCompressedData1 == ((ULONG)(-1))) ||
+ (cbCompressedData2 == ((ULONG)(-1))) ||
+ (cbCompressedData1 != cbCompressedData2) ||
+ (ulData1 != ulData2))
+ {
+ return E_FAIL;
+ }
+
+ m_sig1.SkipBytes(cbCompressedData1);
+ m_sig2.SkipBytes(cbCompressedData2);
+
+ // Out data
+ if (pulData)
+ *pulData = ulData1;
+
+ return S_OK;
+}
+
+//*****************************************************************************
+//*****************************************************************************
+HRESULT
+MDSigComparer::_CompareMethodSignatureHeader(
+ ULONG &cArgs)
+{
+ HRESULT hr;
+
+ // Get calling convention information, but only use it to get type param information.
+ ULONG uCallConv1, uCallConv2;
+ IfFailRet(m_sig1.GetData(&uCallConv1));
+ IfFailRet(m_sig2.GetData(&uCallConv2));
+
+ // Check type parameter information
+ ULONG uTypeParamCount1 = 0;
+ ULONG uTypeParamCount2 = 0;
+
+ if (uCallConv1 & IMAGE_CEE_CS_CALLCONV_GENERIC)
+ IfFailRet(m_sig1.GetData(&uTypeParamCount1));
+
+ if (uCallConv2 & IMAGE_CEE_CS_CALLCONV_GENERIC)
+ IfFailRet(m_sig2.GetData(&uTypeParamCount2));
+
+ if (uTypeParamCount1 != uTypeParamCount2)
+ {
+ return E_FAIL;
+ }
+
+ // Get arg count
+ ULONG cArgs1, cArgs2;
+ IfFailRet(m_sig1.GetData(&cArgs1));
+ IfFailRet(m_sig2.GetData(&cArgs2));
+
+ if (cArgs1 != cArgs2)
+ {
+ return E_FAIL;
+ }
+
+ // Out parameter
+ cArgs = cArgs1;
+
+ return S_OK;
+}
+
+//*****************************************************************************
+//*****************************************************************************
+
+#ifdef FEATURE_FUSION
+HRESULT
+UnifiedAssemblySigComparer::_CreateIAssemblyNameFromAssemblyRef(
+ mdToken tkAsmRef,
+ IAssemblyName **ppAsmName)
+{
+ HRESULT hr;
+
+ void const * pvPublicKey;
+ ULONG cbPublicKey;
+ ULONG cchName;
+ ASSEMBLYMETADATA amd;
+ void const * pvHashValue;
+ ULONG cbHashValue;
+ DWORD dwFlags;
+
+ ZeroMemory(&amd, sizeof(amd));
+
+ IfFailRet(m_pRegMeta->GetAssemblyRefProps(tkAsmRef,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ &cchName,
+ &amd,
+ NULL,
+ NULL,
+ NULL));
+
+ StackSString ssName;
+ StackSString ssLocale;
+ amd.szLocale = ssLocale.OpenUnicodeBuffer(amd.cbLocale);
+
+ IfFailRet(m_pRegMeta->GetAssemblyRefProps(tkAsmRef,
+ &pvPublicKey,
+ &cbPublicKey,
+ ssName.OpenUnicodeBuffer(cchName),
+ cchName,
+ &cchName,
+ &amd,
+ &pvHashValue,
+ &cbHashValue,
+ &dwFlags));
+
+ ssName.CloseBuffer();
+ ssLocale.CloseBuffer();
+
+ IAssemblyName *pAsmName = NULL;
+
+ IfFailRet(CreateAssemblyNameObject(&pAsmName,
+ ssName.GetUnicode(),
+ CANOF_SET_DEFAULT_VALUES,
+ NULL));
+
+ // Set the public key token
+ IfFailRet(pAsmName->SetProperty(ASM_NAME_PUBLIC_KEY_TOKEN,
+ (LPVOID)pvPublicKey,
+ cbPublicKey));
+
+ // Set the culture
+ if (amd.cbLocale == 0 || amd.szLocale == NULL)
+ {
+ IfFailRet(pAsmName->SetProperty(ASM_NAME_CULTURE,
+ W("Neutral"),
+ sizeof(W("Neutral"))));
+ }
+ else
+ {
+ IfFailRet(pAsmName->SetProperty(ASM_NAME_CULTURE,
+ amd.szLocale,
+ amd.cbLocale));
+ }
+
+ // Set the major version
+ IfFailRet(pAsmName->SetProperty(ASM_NAME_MAJOR_VERSION,
+ &amd.usMajorVersion,
+ sizeof(amd.usMajorVersion)));
+
+ // Set the minor version
+ IfFailRet(pAsmName->SetProperty(ASM_NAME_MINOR_VERSION,
+ &amd.usMinorVersion,
+ sizeof(amd.usMinorVersion)));
+
+ // Set the build number
+ IfFailRet(pAsmName->SetProperty(ASM_NAME_BUILD_NUMBER,
+ &amd.usBuildNumber,
+ sizeof(amd.usBuildNumber)));
+
+ // Set the revision number
+ IfFailRet(pAsmName->SetProperty(ASM_NAME_REVISION_NUMBER,
+ &amd.usRevisionNumber,
+ sizeof(amd.usRevisionNumber)));
+
+ *ppAsmName = pAsmName;
+
+ return S_OK;
+}
+
+//*****************************************************************************
+// Define holder to release IAssemblyName on exception.
+//*****************************************************************************
+void UnifiedAssemblySigComparer_IAssemblyNameRelease(IAssemblyName *value)
+{
+ if (value != NULL)
+ {
+ value->Release();
+ }
+}
+
+typedef Holder<IAssemblyName*,
+ DoNothing<IAssemblyName*>,
+ &UnifiedAssemblySigComparer_IAssemblyNameRelease,
+ NULL> UnifiedAssemblySigComparer_IAssemblyNameHolder;
+
+#endif // FEATURE_FUSION
+
+#ifndef FEATURE_FUSION
+HRESULT UnifiedAssemblySigComparer::_CompareAssemblies(mdToken tkAsmRef1,mdToken tkAsmRef2, BOOL* pfEquivalent)
+{
+
+ HRESULT hr;
+ void const * pvPublicKey1;
+ ULONG cbPublicKey1;
+ ULONG cchName1;
+ ASSEMBLYMETADATA amd1;
+ void const * pvHashValue;
+ ULONG cbHashValue;
+ DWORD dwFlags1;
+
+ void const * pvPublicKey2;
+ ULONG cbPublicKey2;
+ ULONG cchName2;
+ ASSEMBLYMETADATA amd2;
+ DWORD dwFlags2;
+
+
+ ZeroMemory(&amd1, sizeof(amd1));
+ ZeroMemory(&amd2, sizeof(amd2));
+
+ IfFailRet(m_pRegMeta->GetAssemblyRefProps(tkAsmRef1,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ &cchName1,
+ &amd1,
+ NULL,
+ NULL,
+ NULL));
+
+ StackSString ssName1;
+ StackSString ssLocale1;
+ amd1.szLocale = ssLocale1.OpenUnicodeBuffer(amd1.cbLocale);
+
+ IfFailRet(m_pRegMeta->GetAssemblyRefProps(tkAsmRef1,
+ &pvPublicKey1,
+ &cbPublicKey1,
+ ssName1.OpenUnicodeBuffer(cchName1),
+ cchName1,
+ &cchName1,
+ &amd1,
+ &pvHashValue,
+ &cbHashValue,
+ &dwFlags1));
+
+ ssName1.CloseBuffer();
+ ssLocale1.CloseBuffer();
+
+ IfFailRet(m_pRegMeta->GetAssemblyRefProps(tkAsmRef2,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ &cchName2,
+ &amd2,
+ NULL,
+ NULL,
+ NULL));
+
+ StackSString ssName2;
+ StackSString ssLocale2;
+ amd2.szLocale = ssLocale2.OpenUnicodeBuffer(amd2.cbLocale);
+
+ IfFailRet(m_pRegMeta->GetAssemblyRefProps(tkAsmRef2,
+ &pvPublicKey2,
+ &cbPublicKey2,
+ ssName2.OpenUnicodeBuffer(cchName2),
+ cchName2,
+ &cchName2,
+ &amd2,
+ &pvHashValue,
+ &cbHashValue,
+ &dwFlags2));
+
+ ssName2.CloseBuffer();
+ ssLocale2.CloseBuffer();
+
+ StackSString sMscorlib(W("mscorlib"));
+
+
+ if(ssName1.CompareCaseInsensitive(sMscorlib)==0 &&
+ ssName2.CompareCaseInsensitive(sMscorlib)==0 )
+ {
+ *pfEquivalent=TRUE;
+ return S_OK;
+ }
+
+ *pfEquivalent=FALSE;
+
+ if (ssName1.CompareCaseInsensitive(ssName2)!=0)
+ return S_OK;
+ if (ssLocale1.CompareCaseInsensitive(ssLocale2)!=0)
+ return S_OK;
+ if(cbPublicKey1!=cbPublicKey2)
+ return S_OK;
+ if(memcmp(pvPublicKey1,pvPublicKey2,cbPublicKey1)!=0)
+ return S_OK;
+ if(dwFlags1!=dwFlags2)
+ return S_OK;
+ if(amd1.usMajorVersion!=amd2.usMajorVersion)
+ return S_OK;
+ if(amd1.usMinorVersion!=amd2.usMinorVersion)
+ return S_OK;
+ if(amd1.usBuildNumber!=amd2.usBuildNumber)
+ return S_OK;
+ if(amd1.usRevisionNumber!=amd2.usRevisionNumber)
+ return S_OK;
+
+ *pfEquivalent=TRUE;
+ return S_OK;
+
+};
+#endif // FEATURE_FUSION
+
+//*****************************************************************************
+//*****************************************************************************
+HRESULT
+UnifiedAssemblySigComparer::_CreateTypeNameFromTypeRef(
+ mdToken tkTypeRef,
+ SString &ssName,
+ mdToken &tkParent)
+{
+ HRESULT hr;
+
+ // Get the parent token as well as the name, and return.
+ ULONG cchTypeRef;
+ IfFailRet(m_pRegMeta->GetTypeRefProps(tkTypeRef, NULL, NULL, 0, &cchTypeRef));
+ IfFailRet(m_pRegMeta->GetTypeRefProps(tkTypeRef, &tkParent, ssName.OpenUnicodeBuffer(cchTypeRef), cchTypeRef, NULL));
+ ssName.CloseBuffer();
+
+ return S_OK;
+}
+
+//*****************************************************************************
+//*****************************************************************************
+HRESULT
+UnifiedAssemblySigComparer::_CreateFullyQualifiedTypeNameFromTypeRef(
+ mdToken tkTypeRef,
+ SString &ssFullName,
+ mdToken &tkParent)
+{
+ HRESULT hr;
+
+ StackSString ssBuf;
+ StackSString ssName;
+ mdToken tok = tkTypeRef;
+ BOOL fFirstLoop = TRUE;
+
+ // Loop stops at first non-typeref parent token.
+ do
+ {
+ // Get the name for this token, as well as the parent token value.
+ IfFailRet(_CreateTypeNameFromTypeRef(tok, ssName, tok));
+
+ // If this is the first time through the loop, just assign values.
+ if (fFirstLoop)
+ {
+ ssFullName = ssName;
+ fFirstLoop = FALSE;
+ }
+ // If this isn't the first time through, make nested type name
+ else
+ {
+ ns::MakeNestedTypeName(ssBuf, ssName, ssFullName);
+ ssFullName = ssBuf;
+ }
+ } while (TypeFromToken(tok) == mdtTypeRef);
+
+ // Assign non-typeref token parent
+ tkParent = tok;
+
+ return S_OK;
+}
+
+
+
+//*****************************************************************************
+//*****************************************************************************
+HRESULT
+UnifiedAssemblySigComparer::CompareToken(
+ const mdToken &tok1,
+ const mdToken &tok2)
+{
+ HRESULT hr;
+
+ // Check binary equality
+ if (tok1 == tok2)
+ {
+ return S_OK;
+ }
+
+ // Currently only want to do extra checking on TypeRefs
+ if (TypeFromToken(tok1) != mdtTypeRef || TypeFromToken(tok2) != mdtTypeRef)
+ {
+ return E_FAIL;
+ }
+
+ // Get the fully qualified type names as well as the non-typeref parents.
+ mdToken tkParent1, tkParent2;
+ StackSString ssName1, ssName2;
+
+ IfFailRet(_CreateFullyQualifiedTypeNameFromTypeRef(tok1, ssName1, tkParent1));
+ IfFailRet(_CreateFullyQualifiedTypeNameFromTypeRef(tok2, ssName2, tkParent2));
+
+ // Currently only want to do extra checking if the parent tokens are AssemblyRefs
+ if (TypeFromToken(tkParent1) != mdtAssemblyRef || TypeFromToken(tkParent2) != mdtAssemblyRef)
+ {
+ return E_FAIL;
+ }
+
+ // If the type names are not equal, no need to check the assembly refs for unification since
+ // we know the types couldn't possibly match.
+ if (!ssName1.Equals(ssName2))
+ {
+ return E_FAIL;
+ }
+ BOOL fEquivalent;
+
+#ifdef FEATURE_FUSION //move into _CompareAssemblies
+ IAssemblyName *pAsmName1 = NULL;
+ IfFailRet(_CreateIAssemblyNameFromAssemblyRef(tkParent1, &pAsmName1));
+ UnifiedAssemblySigComparer_IAssemblyNameHolder anh1(pAsmName1);
+
+ IAssemblyName *pAsmName2 = NULL;
+ IfFailRet(_CreateIAssemblyNameFromAssemblyRef(tkParent2, &pAsmName2));
+ UnifiedAssemblySigComparer_IAssemblyNameHolder anh2(pAsmName2);
+
+ DWORD cchDisplayName = 0;
+
+ StackSString ssDisplayName1;
+ pAsmName1->GetDisplayName(NULL, &cchDisplayName, NULL);
+ IfFailRet(pAsmName1->GetDisplayName(ssDisplayName1.OpenUnicodeBuffer(cchDisplayName), &cchDisplayName, NULL));
+ ssDisplayName1.CloseBuffer();
+
+ StackSString ssDisplayName2;
+ pAsmName2->GetDisplayName(NULL, &cchDisplayName, NULL);
+ IfFailRet(pAsmName2->GetDisplayName(ssDisplayName2.OpenUnicodeBuffer(cchDisplayName), &cchDisplayName, NULL));
+ ssDisplayName2.CloseBuffer();
+
+ AssemblyComparisonResult res;
+ IfFailRet(CompareAssemblyIdentity(ssDisplayName1.GetUnicode(),
+ TRUE,
+ ssDisplayName2.GetUnicode(),
+ TRUE,
+ &fEquivalent,
+ &res));
+#else
+ // no redirects supported
+ IfFailRet(_CompareAssemblies(tkParent1,tkParent2,&fEquivalent));
+#endif
+
+ if (!fEquivalent)
+ {
+ return E_FAIL;
+ }
+
+ return S_OK;
+}
+
+
+//*****************************************************************************
+// Helper function to validate a locale.
+//*****************************************************************************
+static const char* const g_szValidLocale_V1[] = {
+"ar","ar-SA","ar-IQ","ar-EG","ar-LY","ar-DZ","ar-MA","ar-TN","ar-OM","ar-YE","ar-SY","ar-JO","ar-LB","ar-KW","ar-AE","ar-BH","ar-QA",
+"bg","bg-BG",
+"ca","ca-ES",
+"zh-CHS","zh-TW","zh-CN","zh-HK","zh-SG","zh-MO","zh-CHT",
+"cs","cs-CZ",
+"da","da-DK",
+"de","de-DE","de-CH","de-AT","de-LU","de-LI",
+"el","el-GR",
+"en","en-US","en-GB","en-AU","en-CA","en-NZ","en-IE","en-ZA","en-JM","en-CB","en-BZ","en-TT","en-ZW","en-PH",
+"es","es-ES-Ts","es-MX","es-ES","es-GT","es-CR","es-PA","es-DO","es-VE","es-CO","es-PE","es-AR","es-EC","es-CL",
+"es-UY","es-PY","es-BO","es-SV","es-HN","es-NI","es-PR",
+"fi","fi-FI",
+"fr","fr-FR","fr-BE","fr-CA","fr-CH","fr-LU","fr-MC",
+"he","he-IL",
+"hu","hu-HU",
+"is","is-IS",
+"it","it-IT","it-CH",
+"ja","ja-JP",
+"ko","ko-KR",
+"nl","nl-NL","nl-BE",
+"no",
+"nb-NO",
+"nn-NO",
+"pl","pl-PL",
+"pt","pt-BR","pt-PT",
+"ro","ro-RO",
+"ru","ru-RU",
+"hr","hr-HR",
+"sk","sk-SK",
+"sq","sq-AL",
+"sv","sv-SE","sv-FI",
+"th","th-TH",
+"tr","tr-TR",
+"ur","ur-PK",
+"id","id-ID",
+"uk","uk-UA",
+"be","be-BY",
+"sl","sl-SI",
+"et","et-EE",
+"lv","lv-LV",
+"lt","lt-LT",
+"fa","fa-IR",
+"vi","vi-VN",
+"hy","hy-AM",
+"az",
+"eu","eu-ES",
+"mk","mk-MK",
+"af","af-ZA",
+"ka","ka-GE",
+"fo","fo-FO",
+"hi","hi-IN",
+"ms","ms-MY","ms-BN",
+"kk","kk-KZ",
+"ky","ky-KZ",
+"sw","sw-KE",
+"uz",
+"tt","tt-RU",
+"pa","pa-IN",
+"gu","gu-IN",
+"ta","ta-IN",
+"te","te-IN",
+"kn","kn-IN",
+"mr","mr-IN",
+"sa","sa-IN",
+"mn","mn-MN",
+"gl","gl-ES",
+"kok","kok-IN",
+"syr","syr-SY",
+"div"
+};
+
+static const char* const g_szValidLocale_V2[] = {
+ "bn", "bn-IN",
+ "bs-Latn-BA", "bs-Cyrl-BA",
+ "hr-BA",
+ "fil", "fil-PH",
+ "fy", "fy-NL",
+ "iu-Latn-CA",
+ "ga", "ga-IE",
+ "ky-KG",
+ "lb", "lb-LU",
+ "ml", "ml-IN",
+ "mt", "mt-MT",
+ "mi", "mi-NZ",
+ "arn", "arn-CL",
+ "moh", "moh-CA",
+ "ne", "ne-NP",
+ "ps", "ps-AF",
+ "quz", "quz-BO", "quz-EC", "quz-PE",
+ "rm", "rm-CH",
+ "smn", "smn-FI",
+ "smj" , "smj-SE", "smj-NO",
+ "se", "se-NO", "se-SE", "se-FI",
+ "sms", "sms-FI",
+ "sma", "sma-NO", "sma-SE",
+ "sr-Latn-BA", "sr-Cyrl-BA",
+ "nso", "nso-ZA"
+};
+
+// Pre-vista specific cultures (renamed on Vista)
+static const char* const g_szValidLocale_PreVista[] = {
+ "div-MV",
+ "sr-SP-Latn", "sr-SP-Cyrl",
+ "az-AZ-Latn", "az-AZ-Cyrl",
+ "uz-UZ-Latn", "uz-UZ-Cyrl",
+};
+
+// Vista only specific cultures (renamed and freshly introduced)
+static const char * const g_szValidLocale_Vista[] = {
+ "dv-MV",
+ "sr-Latn-CS", "sr-Cyrl-CS",
+ "az-Latn-AZ", "az-Cyrl-AZ",
+ "uz-Latn-UZ", "uz-Cyrl-UZ",
+ "zh-Hant", "zh-Hans",
+ "gsw", "gsw-FR",
+ "am", "am-ET",
+ "as", "as-IN",
+ "ba", "ba-RU",
+ "br", "br-FR",
+ "en-IN",
+ "kl", "kl-GL",
+ "iu-Cans-CA",
+ "km", "km-KH",
+ "lo", "lo-LA",
+ "dsb", "dsb-DE",
+ "mn-Mong-CN",
+ "oc", "oc-FR",
+ "or", "or-IN"
+};
+
+static BOOL FindInArray(LPCUTF8 szLocale, const char * const *cultureArr, const int nCultures)
+{
+ for (int i = 0; i < nCultures; i++)
+ {
+ if(!SString::_stricmp(szLocale, cultureArr[i]))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#define LENGTH_OF(x) (sizeof(x) / sizeof(x[0]))
+
+// For Everett assemblies, only the preVista cultures are valid even if running on Vista.
+static BOOL _IsValidLocale(LPCUTF8 szLocale,
+ BOOL fIsV2Assembly)
+{
+ if (szLocale && *szLocale)
+ {
+ // Locales valid for Everett and Whidbey
+ if (FindInArray(szLocale, g_szValidLocale_V1, LENGTH_OF(g_szValidLocale_V1)))
+ return TRUE;
+
+ // Locales valid for Whidbey assemblies only
+ if (fIsV2Assembly &&
+ FindInArray(szLocale, g_szValidLocale_V2, LENGTH_OF(g_szValidLocale_V2)))
+ return TRUE;
+
+ // Finally search OS specific cultures
+ if (fIsV2Assembly)
+ return FindInArray(szLocale, g_szValidLocale_Vista, LENGTH_OF(g_szValidLocale_Vista));
+ else
+ return FindInArray(szLocale, g_szValidLocale_PreVista, LENGTH_OF(g_szValidLocale_PreVista));
+ }
+
+ return TRUE;
+}
+
+#endif //FEATURE_METADATA_VALIDATOR
diff --git a/src/md/compiler/newmerger.cpp b/src/md/compiler/newmerger.cpp
new file mode 100644
index 0000000000..d5199bb570
--- /dev/null
+++ b/src/md/compiler/newmerger.cpp
@@ -0,0 +1,6303 @@
+// 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.
+//*****************************************************************************
+// NewMerger.cpp
+//
+
+//
+// contains utility code to MD directory
+//
+// This file provides Compiler Support functionality in metadata.
+//*****************************************************************************
+#include "stdafx.h"
+
+#include "newmerger.h"
+#include "regmeta.h"
+
+
+#include "importhelper.h"
+#include "rwutil.h"
+#include "mdlog.h"
+#include <posterror.h>
+#include <sstring.h>
+#include "ndpversion.h"
+
+#ifdef FEATURE_METADATA_EMIT_ALL
+
+#define MODULEDEFTOKEN TokenFromRid(1, mdtModule)
+
+#define COR_MSCORLIB_NAME "mscorlib"
+#define COR_MSCORLIB_TYPEREF {0xb7, 0x7a, 0x5c, 0x56,0x19,0x34,0xe0,0x89}
+
+#define COR_CONSTRUCTOR_METADATA_IDENTIFIER W(".ctor")
+
+#define COR_COMPILERSERVICE_NAMESPACE "System.Runtime.CompilerServices"
+#define COR_EXCEPTIONSERVICE_NAMESPACE "System.Runtime.ExceptionServices"
+#define COR_SUPPRESS_MERGE_CHECK_ATTRIBUTE "SuppressMergeCheckAttribute"
+#define COR_HANDLE_PROCESS_CORRUPTED_STATE_EXCEPTION_ATTRIBUTE "HandleProcessCorruptedStateExceptionsAttribute"
+#define COR_MISCBITS_NAMESPACE "Microsoft.VisualC"
+#define COR_MISCBITS_ATTRIBUTE "Microsoft.VisualC.MiscellaneousBitsAttribute"
+#define COR_NATIVECPPCLASS_ATTRIBUTE "System.Runtime.CompilerServices.NativeCppClassAttribute"
+
+// MODULE_CA_LOCATION W("System.Runtime.CompilerServices.AssemblyAttributesGoHere")
+#define MODULE_CA_TYPENAME "AssemblyAttributesGoHere" // fake assembly type-ref for hanging Assembly-level CAs off of
+
+//*****************************************************************************
+// BEGIN: Security Critical Attributes and Enumeration
+//*****************************************************************************
+#define COR_SECURITYCRITICALSCOPE_ENUM_W W("System.Security.SecurityCriticalScope")
+
+#define COR_SECURITYCRITICAL_ATTRIBUTE_FULL "System.Security.SecurityCriticalAttribute"
+#define COR_SECURITYTRANSPARENT_ATTRIBUTE_FULL "System.Security.SecurityTransparentAttribute"
+#define COR_SECURITYTREATASSAFE_ATTRIBUTE_FULL "System.Security.SecurityTreatAsSafeAttribute"
+
+#define COR_SECURITYCRITICAL_ATTRIBUTE_FULL_W W("System.Security.SecurityCriticalAttribute")
+#define COR_SECURITYTRANSPARENT_ATTRIBUTE_FULL_W W("System.Security.SecurityTransparentAttribute")
+#define COR_SECURITYTREATASSAFE_ATTRIBUTE_FULL_W W("System.Security.SecurityTreatAsSafeAttribute")
+#define COR_SECURITYSAFECRITICAL_ATTRIBUTE_FULL_W W("System.Security.SecuritySafeCriticalAttribute")
+
+ // definitions of enumeration for System.Security.SecurityCriticalScope (Explicit or Everything)
+#define COR_SECURITYCRITICAL_CTOR_ARGCOUNT_NO_SCOPE 0
+#define COR_SECURITYCRITICAL_CTOR_ARGCOUNT_SCOPE_EVERYTHING 1
+#define COR_SECURITYCRITICAL_CTOR_NO_SCOPE_SIG_MAX_SIZE (3)
+#define COR_SECURITYCRITICAL_CTOR_SCOPE_SIG_MAX_SIZE (5 + sizeof(mdTypeRef) * 1)
+
+#define COR_SECURITYCRITICAL_ATTRIBUTE_NAMESPACE "System.Security"
+#define COR_SECURITYCRITICAL_ATTRIBUTE "SecurityCriticalAttribute"
+#define COR_SECURITYTRANSPARENT_ATTRIBUTE_NAMESPACE "System.Security"
+#define COR_SECURITYTRANSPARENT_ATTRIBUTE "SecurityTransparentAttribute"
+#define COR_SECURITYTREATASSAFE_ATTRIBUTE_NAMESPACE "System.Security"
+#define COR_SECURITYTREATASSAFE_ATTRIBUTE "SecurityTreatAsSafeAttribute"
+#define COR_SECURITYSAFECRITICAL_ATTRIBUTE "SecuritySafeCriticalAttribute"
+
+
+#define COR_SECURITYCRITICAL_ATTRIBUTE_VALUE_EVERYTHING { 0x01, 0x00 ,0x01, 0x00, 0x00, 0x00 ,0x00, 0x00 }
+#define COR_SECURITYCRITICAL_ATTRIBUTE_VALUE_EXPLICIT {0x01, 0x00, 0x00 ,0x00}
+#define COR_SECURITYTREATASSAFE_ATTRIBUTE_VALUE {0x01, 0x00, 0x00 ,0x00}
+
+
+ // if true, then registry has been read for enabling or disabling SecurityCritical support
+static BOOL g_fRefShouldMergeCriticalChecked = FALSE;
+
+// by default, security critical attributes will be merged (e.g. unmarked CRT marked Critical/TAS)
+// - unless registry config explicitly disables merging
+static BOOL g_fRefShouldMergeCritical = TRUE;
+//*****************************************************************************
+// END: Security Critical Attributes and Enumeration
+//*****************************************************************************
+
+//*****************************************************************************
+// Checks to see if the given type is managed or native. We'll key off of the
+// Custom Attribute "Microsoft.VisualC.MiscellaneousBitsAttribute". If the third
+// byte has the 01000000 bit set then it is an unmanaged type.
+// If we can't find the attribute, we will also check for the presence of the
+// "System.Runtime.CompilerServices.NativeCppClassAttribute" Custom Attribute
+// since the CPP compiler stopped emitting MiscellaneousBitsAttribute in Dev11.
+//*****************************************************************************
+HRESULT IsManagedType(CMiniMdRW* pMiniMd,
+ mdTypeDef td,
+ BOOL *fIsManagedType)
+{
+ // First look for the custom attribute
+ HENUMInternal hEnum;
+ HRESULT hr = S_OK;
+
+ IfFailRet(pMiniMd->CommonEnumCustomAttributeByName(td, COR_MISCBITS_ATTRIBUTE, false, &hEnum));
+
+ // If there aren't any custom attributes here, then this must be a managed type
+ if (hEnum.m_ulCount > 0)
+ {
+ // Let's loop through these, and see if any of them have that magical bit set.
+ mdCustomAttribute ca;
+ CustomAttributeRec *pRec;
+ ULONG cbData = 0;
+
+ while(HENUMInternal::EnumNext(&hEnum, &ca))
+ {
+ const BYTE* pData = NULL;
+
+ IfFailGo(pMiniMd->GetCustomAttributeRecord(RidFromToken(ca), &pRec));
+ IfFailGo(pMiniMd->getValueOfCustomAttribute(pRec, &pData, &cbData));
+
+ if (pData != NULL && cbData >=3)
+ {
+ // See if the magical bit is set to make this an unmanaged type
+ if ((*(pData+2)&0x40) > 0)
+ {
+ // Yes, this is an unmanaged type
+ HENUMInternal::ClearEnum(&hEnum);
+ *fIsManagedType = FALSE;
+ return S_OK;
+ }
+ }
+ }
+
+ }
+
+ HENUMInternal::ClearEnum(&hEnum);
+
+ // If this was emitted by a Dev11+ CPP compiler, we only have NativeCppClassAttribute
+ // so let's check for that before calling this a managed class.
+ IfFailRet(pMiniMd->CommonEnumCustomAttributeByName(td, COR_NATIVECPPCLASS_ATTRIBUTE, false, &hEnum));
+ if (hEnum.m_ulCount > 0)
+ {
+ // Yes, this is an unmanaged type
+ HENUMInternal::ClearEnum(&hEnum);
+ *fIsManagedType = FALSE;
+ return S_OK;
+ }
+
+ // Nope, this isn't an unmanaged type.... must be managed
+ HENUMInternal::ClearEnum(&hEnum);
+ *fIsManagedType = TRUE;
+ hr = S_OK;
+ErrExit:
+ return hr;
+}// IsManagedType
+
+
+//*****************************************************************************
+// "Is CustomAttribute from certain namespace and assembly" check helper
+// Returns S_OK and fills **ppTypeRefRec.
+// Returns error code or S_FALSE otherwise as not found and fills **ppTypeRefRec with NULL.
+//*****************************************************************************
+HRESULT IsAttributeFromNamespace(
+ CMiniMdRW *pMiniMd,
+ mdToken tk,
+ LPCSTR szNamespace,
+ LPCSTR szAssembly,
+ TypeRefRec **ppTypeRefRec)
+{
+ HRESULT hr = S_OK;
+ if(TypeFromToken(tk) == mdtMemberRef)
+ {
+ MemberRefRec *pMemRefRec;
+ IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(tk), &pMemRefRec));
+ tk = pMiniMd->getClassOfMemberRef(pMemRefRec);
+ }
+ if(TypeFromToken(tk) == mdtTypeRef)
+ {
+ TypeRefRec *pTypeRefRec;
+ IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tk), &pTypeRefRec));
+ LPCSTR szTypeRefNamespace;
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szTypeRefNamespace));
+ if (strcmp(szTypeRefNamespace, szNamespace) == 0)
+ {
+ mdToken tkResTmp = pMiniMd->getResolutionScopeOfTypeRef(pTypeRefRec);
+ if (TypeFromToken(tkResTmp) == mdtAssemblyRef)
+ {
+ AssemblyRefRec *pAsmRefRec;
+ IfFailGo(pMiniMd->GetAssemblyRefRecord(RidFromToken(tkResTmp), &pAsmRefRec));
+ LPCSTR szAssemblyRefName;
+ IfFailGo(pMiniMd->getNameOfAssemblyRef(pAsmRefRec, &szAssemblyRefName));
+ if(SString::_stricmp(szAssemblyRefName, szAssembly) == 0)
+ {
+ *ppTypeRefRec = pTypeRefRec;
+ return S_OK;
+ }
+ }
+ }
+ }
+ // Record not found
+ hr = S_FALSE;
+ErrExit:
+ *ppTypeRefRec = NULL;
+ return hr;
+}
+
+//*****************************************************************************
+// constructor
+//*****************************************************************************
+NEWMERGER::NEWMERGER()
+ : m_pRegMetaEmit(0),
+ m_pImportDataList(NULL),
+ m_optimizeRefToDef(MDRefToDefDefault),
+ m_isscsSecurityCritical(ISSCS_Unknown),
+ m_isscsSecurityCriticalAllScopes(~ISSCS_Unknown)
+{
+ m_pImportDataTail = &(m_pImportDataList);
+#if _DEBUG
+ m_iImport = 0;
+#endif // _DEBUG
+} // NEWMERGER::NEWMERGER()
+
+//*****************************************************************************
+// initializer
+//*****************************************************************************
+HRESULT NEWMERGER::Init(RegMeta *pRegMeta)
+{
+ HRESULT hr = NOERROR;
+ MergeTypeData * pMTD;
+
+ m_pRegMetaEmit = pRegMeta;
+
+ // burn an entry so that the RID matches the array index
+ IfNullGo(pMTD = m_rMTDs.Append());
+
+ pMTD->m_bSuppressMergeCheck = false;
+ pMTD->m_cMethods = 0;
+ pMTD->m_cFields = 0;
+ pMTD->m_cEvents = 0;
+ pMTD->m_cProperties = 0;
+
+ErrExit:
+ return hr;
+} // NEWMERGER::Init
+
+//*****************************************************************************
+// destructor
+//*****************************************************************************
+NEWMERGER::~NEWMERGER()
+{
+ if (m_pImportDataList)
+ {
+ // delete this list and release all AddRef'ed interfaces!
+ MergeImportData *pNext;
+ for (pNext = m_pImportDataList; pNext != NULL; )
+ {
+ pNext = m_pImportDataList->m_pNextImportData;
+ if (m_pImportDataList->m_pHandler)
+ m_pImportDataList->m_pHandler->Release();
+ if (m_pImportDataList->m_pHostMapToken)
+ m_pImportDataList->m_pHostMapToken->Release();
+ if (m_pImportDataList->m_pMDTokenMap)
+ delete m_pImportDataList->m_pMDTokenMap;
+ m_pImportDataList->m_pRegMetaImport->Release();
+ delete m_pImportDataList;
+ m_pImportDataList = pNext;
+ }
+ }
+} // NEWMERGER::~NEWMERGER
+
+//*****************************************************************************
+CMiniMdRW *NEWMERGER::GetMiniMdEmit()
+{
+ return &(m_pRegMetaEmit->m_pStgdb->m_MiniMd);
+} // CMiniMdRW *NEWMERGER::GetMiniMdEmit()
+
+//*****************************************************************************
+// Adding a new import
+//*****************************************************************************
+HRESULT NEWMERGER::AddImport(
+ IMetaDataImport2 *pImport, // [IN] The scope to be merged.
+ IMapToken *pHostMapToken, // [IN] Host IMapToken interface to receive token remap notification
+ IUnknown *pHandler) // [IN] An object to receive error notification.
+{
+ HRESULT hr = NOERROR;
+ MergeImportData *pData;
+
+ RegMeta *pRM = static_cast<RegMeta*>(pImport);
+
+ // Add a MergeImportData to track the information for this import scope
+ pData = new (nothrow) MergeImportData;
+ IfNullGo( pData );
+ pData->m_pRegMetaImport = pRM;
+ pData->m_pRegMetaImport->AddRef();
+ pData->m_pHostMapToken = pHostMapToken;
+ if (pData->m_pHostMapToken)
+ pData->m_pHostMapToken->AddRef();
+ if (pHandler)
+ {
+ pData->m_pHandler = pHandler;
+ pData->m_pHandler->AddRef();
+ }
+ else
+ {
+ pData->m_pHandler = NULL;
+ }
+
+ pData->m_pMDTokenMap = NULL;
+ pData->m_pNextImportData = NULL;
+#if _DEBUG
+ pData->m_iImport = ++m_iImport;
+#endif // _DEBUG
+
+ pData->m_tkHandleProcessCorruptedStateCtor = mdTokenNil;
+ // add the newly create node to the tail of the list
+ *m_pImportDataTail = pData;
+ m_pImportDataTail = &(pData->m_pNextImportData);
+
+ErrExit:
+
+ return hr;
+} // HRESULT NEWMERGER::AddImport()
+
+HRESULT NEWMERGER::InitMergeTypeData()
+{
+ CMiniMdRW *pMiniMdEmit;
+ ULONG cTypeDefRecs;
+ ULONG i, j;
+ bool bSuppressMergeCheck;
+
+ ULONG ridStart, ridEnd;
+ RID ridMap;
+
+ mdToken tkSuppressMergeCheckCtor = mdTokenNil;
+ mdToken tkCA;
+ mdMethodDef mdEmit;
+ mdFieldDef fdEmit;
+ mdEvent evEmit;
+ mdProperty prEmit;
+
+ TypeDefRec *pTypeDefRec;
+ EventMapRec *pEventMapRec;
+ PropertyMapRec *pPropertyMapRec;
+
+ MergeTypeData *pMTD;
+
+ HRESULT hr = NOERROR;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ // cache the SuppressMergeCheckAttribute.ctor token
+ ImportHelper::FindCustomAttributeCtorByName(
+ pMiniMdEmit, COR_MSCORLIB_NAME,
+ COR_COMPILERSERVICE_NAMESPACE, COR_SUPPRESS_MERGE_CHECK_ATTRIBUTE,
+ &tkSuppressMergeCheckCtor);
+
+ cTypeDefRecs = pMiniMdEmit->getCountTypeDefs();
+ _ASSERTE(m_rMTDs.Count() > 0);
+
+ for (i = m_rMTDs.Count(); i <= cTypeDefRecs; i++)
+ {
+ IfNullGo(pMTD = m_rMTDs.Append());
+
+ pMTD->m_cMethods = 0;
+ pMTD->m_cFields = 0;
+ pMTD->m_cEvents = 0;
+ pMTD->m_cProperties = 0;
+ pMTD->m_bSuppressMergeCheck = (tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdEmit,
+ TokenFromRid(i, mdtTypeDef), tkSuppressMergeCheckCtor,
+ NULL, 0, &tkCA));
+
+ IfFailGo(pMiniMdEmit->GetTypeDefRecord(i, &pTypeDefRec));
+
+ // Count the number methods
+ ridStart = pMiniMdEmit->getMethodListOfTypeDef(pTypeDefRec);
+ IfFailGo(pMiniMdEmit->getEndMethodListOfTypeDef(i, &ridEnd));
+
+ for (j = ridStart; j < ridEnd; j++)
+ {
+ IfFailGo(pMiniMdEmit->GetMethodRid(j, (ULONG *)&mdEmit));
+ bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck ||
+ ((tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdEmit,
+ mdEmit, tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+ if (!bSuppressMergeCheck)
+ {
+ pMTD->m_cMethods++;
+ }
+ }
+
+ // Count the number fields
+ ridStart = pMiniMdEmit->getFieldListOfTypeDef(pTypeDefRec);
+ IfFailGo(pMiniMdEmit->getEndFieldListOfTypeDef(i, &ridEnd));
+
+ for (j = ridStart; j < ridEnd; j++)
+ {
+ IfFailGo(pMiniMdEmit->GetFieldRid(j, (ULONG *)&fdEmit));
+ bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck ||
+ ((tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdEmit,
+ fdEmit, tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+ if (!bSuppressMergeCheck)
+ {
+ pMTD->m_cFields++;
+ }
+ }
+
+ // Count the number of events
+ IfFailGo(pMiniMdEmit->FindEventMapFor(i, &ridMap));
+ if (!InvalidRid(ridMap))
+ {
+ IfFailGo(pMiniMdEmit->GetEventMapRecord(ridMap, &pEventMapRec));
+ ridStart = pMiniMdEmit->getEventListOfEventMap(pEventMapRec);
+ IfFailGo(pMiniMdEmit->getEndEventListOfEventMap(ridMap, &ridEnd));
+
+ for (j = ridStart; j < ridEnd; j++)
+ {
+ IfFailGo(pMiniMdEmit->GetEventRid(j, (ULONG *)&evEmit));
+ bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck ||
+ ((tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdEmit,
+ evEmit, tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+ if (!bSuppressMergeCheck)
+ {
+ pMTD->m_cEvents++;
+ }
+ }
+ }
+
+ // Count the number of properties
+ IfFailGo(pMiniMdEmit->FindPropertyMapFor(i, &ridMap));
+ if (!InvalidRid(ridMap))
+ {
+ IfFailGo(pMiniMdEmit->GetPropertyMapRecord(ridMap, &pPropertyMapRec));
+ ridStart = pMiniMdEmit->getPropertyListOfPropertyMap(pPropertyMapRec);
+ IfFailGo(pMiniMdEmit->getEndPropertyListOfPropertyMap(ridMap, &ridEnd));
+
+ for (j = ridStart; j < ridEnd; j++)
+ {
+ IfFailGo(pMiniMdEmit->GetPropertyRid(j, (ULONG *)&prEmit));
+ bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck ||
+ ((tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdEmit,
+ prEmit, tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+ if (!bSuppressMergeCheck)
+ {
+ pMTD->m_cProperties++;
+ }
+ }
+ }
+ }
+
+ErrExit:
+ return hr;
+}
+
+//*****************************************************************************
+// Merge now
+//*****************************************************************************
+HRESULT NEWMERGER::Merge(MergeFlags dwMergeFlags, CorRefToDefCheck optimizeRefToDef)
+{
+ MergeImportData *pImportData = m_pImportDataList;
+ MDTOKENMAP **pPrevMap = NULL;
+ MDTOKENMAP *pMDTokenMap;
+ HRESULT hr = NOERROR;
+ MDTOKENMAP *pCurTKMap;
+ int i;
+
+#if _DEBUG
+ {
+ LOG((LOGMD, "++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"));
+ LOG((LOGMD, "Merge scope list\n"));
+ i = 0;
+ for (MergeImportData *pID = m_pImportDataList; pID != NULL; pID = pID->m_pNextImportData)
+ {
+ WCHAR szScope[1024], szGuid[40];
+ GUID mvid;
+ ULONG cchScope;
+ pID->m_pRegMetaImport->GetScopeProps(szScope, 1024, &cchScope, &mvid);
+ szScope[1023] = 0;
+ GuidToLPWSTR(mvid, szGuid, 40);
+ ++i; // Counter is 1-based.
+ LOG((LOGMD, "%3d: %ls : %ls\n", i, szGuid, szScope));
+ }
+ LOG((LOGMD, "++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"));
+ }
+#endif // _DEBUG
+
+ m_dwMergeFlags = dwMergeFlags;
+ m_optimizeRefToDef = optimizeRefToDef;
+
+ // check to see if we need to do dup check
+ m_fDupCheck = ((m_dwMergeFlags & NoDupCheck) != NoDupCheck);
+
+ while (pImportData)
+ {
+ // Verify that we have a filter for each import scope.
+ IfNullGo( pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd.GetFilterTable() );
+
+ // cache the SuppressMergeCheckAttribute.ctor token for each import scope
+ ImportHelper::FindCustomAttributeCtorByName(
+ &pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd, COR_MSCORLIB_NAME,
+ COR_COMPILERSERVICE_NAMESPACE, COR_SUPPRESS_MERGE_CHECK_ATTRIBUTE,
+ &pImportData->m_tkSuppressMergeCheckCtor);
+
+ // cache the HandleProcessCorruptedStateExceptionsAttribute.ctor token for each import scope
+ ImportHelper::FindCustomAttributeCtorByName(
+ &pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd, COR_MSCORLIB_NAME,
+ COR_EXCEPTIONSERVICE_NAMESPACE, COR_HANDLE_PROCESS_CORRUPTED_STATE_EXCEPTION_ATTRIBUTE,
+ &pImportData->m_tkHandleProcessCorruptedStateCtor);
+
+ // check for security critical attribute in the assembly (i.e. explicit annotations)
+ InputScopeSecurityCriticalStatus isscsTemp = CheckInputScopeIsCritical(pImportData, hr);
+ IfFailGo(hr);
+ // clear the unset flag bits (e.g. if critical, clear transparent bit)
+ // whatever bits remain are bits that have been set in all scopes
+ if (ISSCS_Unknown == (isscsTemp & ISSCS_SECURITYCRITICAL_FLAGS))
+ m_isscsSecurityCriticalAllScopes &= ISSCS_SECURITYCRITICAL_LEGACY;
+ else
+ m_isscsSecurityCriticalAllScopes &= isscsTemp;
+ // set the flag bits (essentially, this allows us to see if _any_ scopes requested a bit)
+ m_isscsSecurityCritical |= isscsTemp;
+
+ // create the tokenmap class to track metadata token remap for each import scope
+ pMDTokenMap = new (nothrow) MDTOKENMAP;
+ IfNullGo(pMDTokenMap);
+ IfFailGo(pMDTokenMap->Init((IMetaDataImport2*)pImportData->m_pRegMetaImport));
+ pImportData->m_pMDTokenMap = pMDTokenMap;
+ pImportData->m_pMDTokenMap->m_pMap = pImportData->m_pHostMapToken;
+ if (pImportData->m_pHostMapToken)
+ pImportData->m_pHostMapToken->AddRef();
+ pImportData->m_pMDTokenMap->m_pNextMap = NULL;
+ if (pPrevMap)
+ *pPrevMap = pImportData->m_pMDTokenMap;
+ pPrevMap = &(pImportData->m_pMDTokenMap->m_pNextMap);
+ pImportData = pImportData->m_pNextImportData;
+ }
+
+ // Populate the m_rMTDs with the type info already defined in the emit scope
+ IfFailGo( InitMergeTypeData() );
+
+ // 1. Merge Module
+ IfFailGo( MergeModule( ) );
+
+ // 2. Merge TypeDef partially (i.e. only name)
+ IfFailGo( MergeTypeDefNamesOnly() );
+
+ // 3. Merge ModuleRef property and do ModuleRef to ModuleDef optimization
+ IfFailGo( MergeModuleRefs() );
+
+ // 4. Merge AssemblyRef.
+ IfFailGo( MergeAssemblyRefs() );
+
+ // 5. Merge TypeRef with TypeRef to TypeDef optimization
+ IfFailGo( MergeTypeRefs() );
+
+ // 6. Merge TypeSpec & MethodSpec
+ IfFailGo( MergeTypeSpecs() );
+
+ // 7. Now Merge the remaining of TypeDef records
+ IfFailGo( CompleteMergeTypeDefs() );
+
+ // 8. Merge Methods and Fields. Such that Signature translation is respecting the TypeRef to TypeDef optimization.
+ IfFailGo( MergeTypeDefChildren() );
+
+ // 9. Merge MemberRef with MemberRef to MethodDef/FieldDef optimization
+ IfFailGo( MergeMemberRefs( ) );
+
+ // 10. Merge InterfaceImpl
+ IfFailGo( MergeInterfaceImpls( ) );
+
+ // merge all of the remaining in metadata ....
+
+ // 11. constant has dependency on property, field, param
+ IfFailGo( MergeConstants() );
+
+ // 12. field marshal has dependency on param and field
+ IfFailGo( MergeFieldMarshals() );
+
+ // 13. in ClassLayout, move over the FieldLayout and deal with FieldLayout as well
+ IfFailGo( MergeClassLayouts() );
+
+ // 14. FieldLayout has dependency on FieldDef.
+ IfFailGo( MergeFieldLayouts() );
+
+ // 15. FieldRVA has dependency on FieldDef.
+ IfFailGo( MergeFieldRVAs() );
+
+ // 16. MethodImpl has dependency on MemberRef, MethodDef, TypeRef and TypeDef.
+ IfFailGo( MergeMethodImpls() );
+
+ // 17. pinvoke depends on MethodDef and ModuleRef
+ IfFailGo( MergePinvoke() );
+
+ IfFailGo( MergeStandAloneSigs() );
+
+ IfFailGo( MergeMethodSpecs() );
+
+ IfFailGo( MergeStrings() );
+
+ if (m_dwMergeFlags & MergeManifest)
+ {
+ // keep the manifest!!
+ IfFailGo( MergeAssembly() );
+ IfFailGo( MergeFiles() );
+ IfFailGo( MergeExportedTypes() );
+ IfFailGo( MergeManifestResources() );
+ }
+ else if (m_dwMergeFlags & ::MergeExportedTypes)
+ {
+ IfFailGo( MergeFiles() );
+ IfFailGo( MergeExportedTypes() );
+ }
+
+ IfFailGo( MergeCustomAttributes() );
+ IfFailGo( MergeDeclSecuritys() );
+
+
+ // Please don't add any MergeXxx() below here. CustomAttributess must be
+ // very late, because custom values are various other types.
+
+ // Fixup list cannot be merged. Linker will need to re-emit them.
+
+ // Now call back to host for the result of token remap
+ //
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // Send token remap information for each import scope
+ pCurTKMap = pImportData->m_pMDTokenMap;
+ TOKENREC *pRec;
+ if (pImportData->m_pHostMapToken)
+ {
+ for (i = 0; i < pCurTKMap->Count(); i++)
+ {
+ pRec = pCurTKMap->Get(i);
+ if (!pRec->IsEmpty())
+ pImportData->m_pHostMapToken->Map(pRec->m_tkFrom, pRec->m_tkTo);
+ }
+ }
+ }
+
+ // And last, but not least, let's do Security critical module-level attribute consolidation
+ // and metadata fixups.
+ IfFailGo( MergeSecurityCriticalAttributes() );
+
+
+
+
+
+#if _DEBUG
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // dump the mapping
+ LOG((LOGMD, "++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"));
+ LOG((LOGMD, "Dumping token remap for one import scope!\n"));
+ LOG((LOGMD, "This is the %d import scope for merge!\n", pImportData->m_iImport));
+
+ pCurTKMap = pImportData->m_pMDTokenMap;
+ TOKENREC *pRec;
+ for (i = 0; i < pCurTKMap->Count(); i++)
+ {
+ pRec = pCurTKMap->Get(i);
+ if (!pRec->IsEmpty())
+ {
+ LOG((LOGMD, " Token 0x%08x ====>>>> Token 0x%08x\n", pRec->m_tkFrom, pRec->m_tkTo));
+ }
+ }
+ LOG((LOGMD, "End dumping token remap!\n"));
+ LOG((LOGMD, "++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"));
+ }
+#endif // _DEBUG
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::Merge()
+
+
+//*****************************************************************************
+// Merge ModuleDef
+//*****************************************************************************
+HRESULT NEWMERGER::MergeModule()
+{
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+ HRESULT hr = NOERROR;
+ TOKENREC *pTokenRec;
+
+ // we don't really merge Module information but we create a one to one mapping for each module token into the TokenMap
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ // set the current MDTokenMap
+
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ IfFailGo( pCurTkMap->InsertNotFound(MODULEDEFTOKEN, true, MODULEDEFTOKEN, &pTokenRec) );
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeModule()
+
+
+//*****************************************************************************
+// Merge TypeDef but only Names. This is a partial merge to support TypeRef to TypeDef optimization
+//*****************************************************************************
+HRESULT NEWMERGER::MergeTypeDefNamesOnly()
+{
+ HRESULT hr = NOERROR;
+ TypeDefRec *pRecImport = NULL;
+ TypeDefRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ mdTypeDef tdEmit;
+ mdTypeDef tdImport;
+ bool bDuplicate;
+ DWORD dwFlags;
+ DWORD dwExportFlags;
+ NestedClassRec *pNestedRec;
+ RID iNestedRec;
+ mdTypeDef tdNester;
+ TOKENREC *pTokenRec;
+
+ LPCUTF8 szNameImp;
+ LPCUTF8 szNamespaceImp;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ MergeTypeData *pMTD;
+ BOOL bSuppressMergeCheck;
+ mdCustomAttribute tkCA;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ iCount = pMiniMdImport->getCountTypeDefs();
+
+ // Merge the typedefs
+ for (i = 1; i <= iCount; i++)
+ {
+ // only merge those TypeDefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsTypeDefMarked(TokenFromRid(i, mdtTypeDef)) == false)
+ continue;
+
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetTypeDefRecord(i, &pRecImport));
+ IfFailGo(pMiniMdImport->getNameOfTypeDef(pRecImport, &szNameImp));
+ IfFailGo(pMiniMdImport->getNamespaceOfTypeDef(pRecImport, &szNamespaceImp));
+
+ // If the class is a Nested class, get the parent token.
+ dwFlags = pMiniMdImport->getFlagsOfTypeDef(pRecImport);
+ if (IsTdNested(dwFlags))
+ {
+ IfFailGo(pMiniMdImport->FindNestedClassHelper(TokenFromRid(i, mdtTypeDef), &iNestedRec));
+ if (InvalidRid(iNestedRec))
+ {
+ _ASSERTE(!"Bad state!");
+ IfFailGo(META_E_BADMETADATA);
+ }
+ else
+ {
+ IfFailGo(pMiniMdImport->GetNestedClassRecord(iNestedRec, &pNestedRec));
+ tdNester = pMiniMdImport->getEnclosingClassOfNestedClass(pNestedRec);
+ _ASSERTE(!IsNilToken(tdNester));
+ IfFailGo(pCurTkMap->Remap(tdNester, &tdNester));
+ }
+ }
+ else
+ tdNester = mdTokenNil;
+
+ bSuppressMergeCheck = (pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport,
+ TokenFromRid(i, mdtTypeDef), pImportData->m_tkSuppressMergeCheckCtor,
+ NULL, 0, &tkCA));
+
+ // does this TypeDef already exist in the emit scope?
+ if ( ImportHelper::FindTypeDefByName(
+ pMiniMdEmit,
+ szNamespaceImp,
+ szNameImp,
+ tdNester,
+ &tdEmit) == S_OK )
+ {
+ // Yes, it does
+ bDuplicate = true;
+
+ // Let's look at their accessiblities.
+ IfFailGo(pMiniMdEmit->GetTypeDefRecord(RidFromToken(tdEmit), &pRecEmit));
+ dwExportFlags = pMiniMdEmit->getFlagsOfTypeDef(pRecEmit);
+
+ // Managed types need to have the same accessiblity
+ BOOL fManagedType = FALSE;
+ IfFailGo(IsManagedType(pMiniMdImport, TokenFromRid(i, mdtTypeDef), &fManagedType));
+ if (fManagedType)
+ {
+ if ((dwFlags&tdVisibilityMask) != (dwExportFlags&tdVisibilityMask))
+ {
+ CheckContinuableErrorEx(META_E_MISMATCHED_VISIBLITY, pImportData, TokenFromRid(i, mdtTypeDef));
+ }
+
+ }
+ pMTD = m_rMTDs.Get(RidFromToken(tdEmit));
+ if (pMTD->m_bSuppressMergeCheck != bSuppressMergeCheck)
+ {
+ CheckContinuableErrorEx(META_E_MD_INCONSISTENCY, pImportData, TokenFromRid(i, mdtTypeDef));
+ }
+ }
+ else
+ {
+ // No, it doesn't. Copy it over.
+ bDuplicate = false;
+ IfFailGo(pMiniMdEmit->AddTypeDefRecord(&pRecEmit, (RID *)&tdEmit));
+
+ // make sure the index matches
+ _ASSERTE(((mdTypeDef)m_rMTDs.Count()) == tdEmit);
+
+ IfNullGo(pMTD = m_rMTDs.Append());
+
+ pMTD->m_cMethods = 0;
+ pMTD->m_cFields = 0;
+ pMTD->m_cEvents = 0;
+ pMTD->m_cProperties = 0;
+ pMTD->m_bSuppressMergeCheck = bSuppressMergeCheck;
+
+ tdEmit = TokenFromRid( tdEmit, mdtTypeDef );
+
+ // Set Full Qualified Name.
+ IfFailGo( CopyTypeDefPartially( pRecEmit, pMiniMdImport, pRecImport) );
+
+ // Create a NestedClass record if the class is a Nested class.
+ if (! IsNilToken(tdNester))
+ {
+ IfFailGo(pMiniMdEmit->AddNestedClassRecord(&pNestedRec, &iNestedRec));
+
+ // copy over the information
+ IfFailGo( pMiniMdEmit->PutToken(TBL_NestedClass, NestedClassRec::COL_NestedClass,
+ pNestedRec, tdEmit));
+
+ // tdNester has already been remapped above to the Emit scope.
+ IfFailGo( pMiniMdEmit->PutToken(TBL_NestedClass, NestedClassRec::COL_EnclosingClass,
+ pNestedRec, tdNester));
+ IfFailGo( pMiniMdEmit->AddNestedClassToHash(iNestedRec) );
+
+ }
+ }
+
+ // record the token movement
+ tdImport = TokenFromRid(i, mdtTypeDef);
+ IfFailGo( pCurTkMap->InsertNotFound(tdImport, bDuplicate, tdEmit, &pTokenRec) );
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeTypeDefNamesOnly()
+
+
+//*****************************************************************************
+// Merge EnclosingType tables
+//*****************************************************************************
+HRESULT NEWMERGER::CopyTypeDefPartially(
+ TypeDefRec *pRecEmit, // [IN] the emit record to fill
+ CMiniMdRW *pMiniMdImport, // [IN] the importing scope
+ TypeDefRec *pRecImp) // [IN] the record to import
+
+{
+ HRESULT hr;
+ LPCUTF8 szNameImp;
+ LPCUTF8 szNamespaceImp;
+ CMiniMdRW *pMiniMdEmit = GetMiniMdEmit();
+
+ IfFailGo(pMiniMdImport->getNameOfTypeDef(pRecImp, &szNameImp));
+ IfFailGo(pMiniMdImport->getNamespaceOfTypeDef(pRecImp, &szNamespaceImp));
+
+ IfFailGo( pMiniMdEmit->PutString( TBL_TypeDef, TypeDefRec::COL_Name, pRecEmit, szNameImp) );
+ IfFailGo( pMiniMdEmit->PutString( TBL_TypeDef, TypeDefRec::COL_Namespace, pRecEmit, szNamespaceImp) );
+
+ pRecEmit->SetFlags(pRecImp->GetFlags());
+
+ // Don't copy over the extends until TypeRef's remap is calculated
+
+ErrExit:
+ return hr;
+
+} // HRESULT NEWMERGER::CopyTypeDefPartially()
+
+
+//*****************************************************************************
+// Merge ModuleRef tables including ModuleRef to ModuleDef optimization
+//*****************************************************************************
+HRESULT NEWMERGER::MergeModuleRefs()
+{
+ HRESULT hr = NOERROR;
+ ModuleRefRec *pRecImport = NULL;
+ ModuleRefRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ mdModuleRef mrEmit;
+ bool bDuplicate = false;
+ TOKENREC *pTokenRec;
+ LPCUTF8 szNameImp;
+ bool isModuleDef;
+
+ MergeImportData *pImportData;
+ MergeImportData *pData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountModuleRefs();
+
+ // loop through all ModuleRef
+ for (i = 1; i <= iCount; i++)
+ {
+ // only merge those ModuleRefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsModuleRefMarked(TokenFromRid(i, mdtModuleRef)) == false)
+ continue;
+
+ isModuleDef = false;
+
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetModuleRefRecord(i, &pRecImport));
+ IfFailGo(pMiniMdImport->getNameOfModuleRef(pRecImport, &szNameImp));
+
+ // Only do the ModuleRef to ModuleDef optimization if ModuleRef's name is meaningful!
+ if ( szNameImp && szNameImp[0] != '\0')
+ {
+
+ // Check to see if this ModuleRef has become the ModuleDef token
+ for (pData = m_pImportDataList; pData != NULL; pData = pData->m_pNextImportData)
+ {
+ CMiniMdRW *pMiniMd = &(pData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ ModuleRec *pRec;
+ LPCUTF8 szName;
+
+ IfFailGo(pMiniMd->GetModuleRecord(MODULEDEFTOKEN, &pRec));
+ IfFailGo(pMiniMd->getNameOfModule(pRec, &szName));
+ if (szName && szName[0] != '\0' && strcmp(szNameImp, szName) == 0)
+ {
+ // We found an import Module for merging that has the same name as the ModuleRef
+ isModuleDef = true;
+ bDuplicate = true;
+ mrEmit = MODULEDEFTOKEN; // set the resulting token to ModuleDef Token
+ break;
+ }
+ }
+ }
+
+ if (isModuleDef == false)
+ {
+ // does this ModuleRef already exist in the emit scope?
+ hr = ImportHelper::FindModuleRef(pMiniMdEmit,
+ szNameImp,
+ &mrEmit);
+ if (hr == S_OK)
+ {
+ // Yes, it does
+ bDuplicate = true;
+ }
+ else if (hr == CLDB_E_RECORD_NOTFOUND)
+ {
+ // No, it doesn't. Copy it over.
+ bDuplicate = false;
+ IfFailGo(pMiniMdEmit->AddModuleRefRecord(&pRecEmit, (RID*)&mrEmit));
+ mrEmit = TokenFromRid(mrEmit, mdtModuleRef);
+
+ // Set ModuleRef Name.
+ IfFailGo( pMiniMdEmit->PutString(TBL_ModuleRef, ModuleRefRec::COL_Name, pRecEmit, szNameImp) );
+ }
+ else
+ IfFailGo(hr);
+ }
+
+ // record the token movement
+ IfFailGo( pCurTkMap->InsertNotFound(
+ TokenFromRid(i, mdtModuleRef),
+ bDuplicate,
+ mrEmit,
+ &pTokenRec) );
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeModuleRefs()
+
+
+//*****************************************************************************
+// Merge AssemblyRef tables
+//*****************************************************************************
+HRESULT NEWMERGER::MergeAssemblyRefs()
+{
+ HRESULT hr = NOERROR;
+ AssemblyRefRec *pRecImport = NULL;
+ AssemblyRefRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ mdAssemblyRef arEmit;
+ bool bDuplicate = false;
+ LPCUTF8 szTmp;
+ const void *pbTmp;
+ ULONG cbTmp;
+ ULONG iCount;
+ ULONG i;
+ ULONG iRecord;
+ TOKENREC *pTokenRec;
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountAssemblyRefs();
+
+ // loope through all the AssemblyRefs.
+ for (i = 1; i <= iCount; i++)
+ {
+ // Compare with the emit scope.
+ IfFailGo(pMiniMdImport->GetAssemblyRefRecord(i, &pRecImport));
+ IfFailGo(pMiniMdImport->getPublicKeyOrTokenOfAssemblyRef(pRecImport, (const BYTE **)&pbTmp, &cbTmp));
+ hr = CLDB_E_RECORD_NOTFOUND;
+ if (m_fDupCheck)
+ {
+ LPCSTR szAssemblyRefName;
+ LPCSTR szAssemblyRefLocale;
+ IfFailGo(pMiniMdImport->getNameOfAssemblyRef(pRecImport, &szAssemblyRefName));
+ IfFailGo(pMiniMdImport->getLocaleOfAssemblyRef(pRecImport, &szAssemblyRefLocale));
+ hr = ImportHelper::FindAssemblyRef(
+ pMiniMdEmit,
+ szAssemblyRefName,
+ szAssemblyRefLocale,
+ pbTmp,
+ cbTmp,
+ pRecImport->GetMajorVersion(),
+ pRecImport->GetMinorVersion(),
+ pRecImport->GetBuildNumber(),
+ pRecImport->GetRevisionNumber(),
+ pRecImport->GetFlags(),
+ &arEmit);
+ }
+ if (hr == S_OK)
+ {
+ // Yes, it does
+ bDuplicate = true;
+
+ // <TODO>@FUTURE: more verification?</TODO>
+ }
+ else if (hr == CLDB_E_RECORD_NOTFOUND)
+ {
+ // No, it doesn't. Copy it over.
+ bDuplicate = false;
+ IfFailGo(pMiniMdEmit->AddAssemblyRefRecord(&pRecEmit, &iRecord));
+ arEmit = TokenFromRid(iRecord, mdtAssemblyRef);
+
+ pRecEmit->Copy(pRecImport);
+
+ IfFailGo(pMiniMdImport->getPublicKeyOrTokenOfAssemblyRef(pRecImport, (const BYTE **)&pbTmp, &cbTmp));
+ IfFailGo(pMiniMdEmit->PutBlob(TBL_AssemblyRef, AssemblyRefRec::COL_PublicKeyOrToken,
+ pRecEmit, pbTmp, cbTmp));
+
+ IfFailGo(pMiniMdImport->getNameOfAssemblyRef(pRecImport, &szTmp));
+ IfFailGo(pMiniMdEmit->PutString(TBL_AssemblyRef, AssemblyRefRec::COL_Name,
+ pRecEmit, szTmp));
+
+ IfFailGo(pMiniMdImport->getLocaleOfAssemblyRef(pRecImport, &szTmp));
+ IfFailGo(pMiniMdEmit->PutString(TBL_AssemblyRef, AssemblyRefRec::COL_Locale,
+ pRecEmit, szTmp));
+
+ IfFailGo(pMiniMdImport->getHashValueOfAssemblyRef(pRecImport, (const BYTE **)&pbTmp, &cbTmp));
+ IfFailGo(pMiniMdEmit->PutBlob(TBL_AssemblyRef, AssemblyRefRec::COL_HashValue,
+ pRecEmit, pbTmp, cbTmp));
+
+ }
+ else
+ IfFailGo(hr);
+
+ // record the token movement.
+ IfFailGo(pCurTkMap->InsertNotFound(
+ TokenFromRid(i, mdtAssemblyRef),
+ bDuplicate,
+ arEmit,
+ &pTokenRec));
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeAssemblyRefs()
+
+
+//*****************************************************************************
+// Merge TypeRef tables also performing TypeRef to TypeDef opitimization. ie.
+// we will not introduce a TypeRef record if we can optimize it to a TypeDef.
+//*****************************************************************************
+HRESULT NEWMERGER::MergeTypeRefs()
+{
+ HRESULT hr = NOERROR;
+ TypeRefRec *pRecImport = NULL;
+ TypeRefRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ mdTypeRef trEmit;
+ bool bDuplicate = false;
+ TOKENREC *pTokenRec;
+ bool isTypeDef;
+
+ mdToken tkResImp;
+ mdToken tkResEmit;
+ LPCUTF8 szNameImp;
+ LPCUTF8 szNamespaceImp;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountTypeRefs();
+
+ // loop through all TypeRef
+ for (i = 1; i <= iCount; i++)
+ {
+ // only merge those TypeRefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsTypeRefMarked(TokenFromRid(i, mdtTypeRef)) == false)
+ continue;
+
+ isTypeDef = false;
+
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetTypeRefRecord(i, &pRecImport));
+ tkResImp = pMiniMdImport->getResolutionScopeOfTypeRef(pRecImport);
+ IfFailGo(pMiniMdImport->getNamespaceOfTypeRef(pRecImport, &szNamespaceImp));
+ IfFailGo(pMiniMdImport->getNameOfTypeRef(pRecImport, &szNameImp));
+ if (!IsNilToken(tkResImp))
+ {
+ IfFailGo(pCurTkMap->Remap(tkResImp, &tkResEmit));
+ }
+ else
+ {
+ tkResEmit = tkResImp;
+ }
+
+ // There are some interesting cases to consider here.
+ // 1) If the TypeRef's ResolutionScope is a nil token, or is the MODULEDEFTOKEN (current module),
+ // then the TypeRef refers to a type in the current scope, so we should find a corresponding
+ // TypeDef in the output scope. If we find the TypeDef, we'll remap this TypeRef token
+ // to that TypeDef token.
+ // If we don't find that TypeDef, or if "TypeRef to TypeDef" optimization is turned off, we'll
+ // create the TypeRef in the output scope.
+ // 2) If the TypeRef's ResolutionScope has been resolved to a TypeDef, then this TypeRef was part
+ // of a nested type definition. In that case, we'd better find a corresponding TypeDef
+ // or we have an error.
+ if (IsNilToken(tkResEmit) || tkResEmit == MODULEDEFTOKEN || TypeFromToken(tkResEmit) == mdtTypeDef)
+ {
+ hr = ImportHelper::FindTypeDefByName(
+ pMiniMdEmit,
+ szNamespaceImp,
+ szNameImp,
+ (TypeFromToken(tkResEmit) == mdtTypeDef) ? tkResEmit : mdTokenNil,
+ &trEmit);
+ if (hr == S_OK)
+ {
+ isTypeDef = true;
+
+ // it really does not matter if we set the duplicate to true or false.
+ bDuplicate = true;
+ }
+ }
+
+ // If the ResolutionScope was merged as a TypeDef, and this token wasn't found as TypeDef, send the error.
+ if (TypeFromToken(tkResEmit) == mdtTypeDef && !isTypeDef)
+ {
+ // Send the error notification. Use the "continuable error" callback, but even if linker says it is
+ // ok, don't continue.
+ CheckContinuableErrorEx(META_E_TYPEDEF_MISSING, pImportData, TokenFromRid(i, mdtTypeRef));
+ IfFailGo(META_E_TYPEDEF_MISSING);
+ }
+
+ // If this TypeRef cannot be optmized to a TypeDef or the Ref to Def optimization is turned off, do the following.
+ if (!isTypeDef || !((m_optimizeRefToDef & MDTypeRefToDef) == MDTypeRefToDef))
+ {
+ // does this TypeRef already exist in the emit scope?
+ if ( m_fDupCheck && ImportHelper::FindTypeRefByName(
+ pMiniMdEmit,
+ tkResEmit,
+ szNamespaceImp,
+ szNameImp,
+ &trEmit) == S_OK )
+ {
+ // Yes, it does
+ bDuplicate = true;
+ }
+ else
+ {
+ // No, it doesn't. Copy it over.
+ bDuplicate = false;
+ IfFailGo(pMiniMdEmit->AddTypeRefRecord(&pRecEmit, (RID*)&trEmit));
+ trEmit = TokenFromRid(trEmit, mdtTypeRef);
+
+ // Set ResolutionScope. tkResEmit has already been re-mapped.
+ IfFailGo(pMiniMdEmit->PutToken(TBL_TypeRef, TypeRefRec::COL_ResolutionScope,
+ pRecEmit, tkResEmit));
+
+ // Set Name.
+ IfFailGo(pMiniMdEmit->PutString(TBL_TypeRef, TypeRefRec::COL_Name,
+ pRecEmit, szNameImp));
+ IfFailGo(pMiniMdEmit->AddNamedItemToHash(TBL_TypeRef, trEmit, szNameImp, 0));
+
+ // Set Namespace.
+ IfFailGo(pMiniMdEmit->PutString(TBL_TypeRef, TypeRefRec::COL_Namespace,
+ pRecEmit, szNamespaceImp));
+ }
+ }
+
+ // record the token movement
+ IfFailGo( pCurTkMap->InsertNotFound(
+ TokenFromRid(i, mdtTypeRef),
+ bDuplicate,
+ trEmit,
+ &pTokenRec) );
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeTypeRefs()
+
+
+//*****************************************************************************
+// copy over the remaining information of partially merged TypeDef records. Right now only
+// extends field is delayed to here. The reason that we delay extends field is because we want
+// to optimize TypeRef to TypeDef if possible.
+//*****************************************************************************
+HRESULT NEWMERGER::CompleteMergeTypeDefs()
+{
+ HRESULT hr = NOERROR;
+ TypeDefRec *pRecImport = NULL;
+ TypeDefRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ TOKENREC *pTokenRec;
+ mdToken tkExtendsImp;
+ mdToken tkExtendsEmit;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ iCount = pMiniMdImport->getCountTypeDefs();
+
+ // Merge the typedefs
+ for (i = 1; i <= iCount; i++)
+ {
+ // only merge those TypeDefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsTypeDefMarked(TokenFromRid(i, mdtTypeDef)) == false)
+ continue;
+
+ if ( !pCurTkMap->Find(TokenFromRid(i, mdtTypeDef), &pTokenRec) )
+ {
+ _ASSERTE( !"bad state!");
+ IfFailGo( META_E_BADMETADATA );
+ }
+
+ if (pTokenRec->m_isDuplicate == false)
+ {
+ // get the extends token from the import
+ IfFailGo(pMiniMdImport->GetTypeDefRecord(i, &pRecImport));
+ tkExtendsImp = pMiniMdImport->getExtendsOfTypeDef(pRecImport);
+
+ // map the extends token to an merged token
+ IfFailGo( pCurTkMap->Remap(tkExtendsImp, &tkExtendsEmit) );
+
+ // set the extends to the merged TypeDef records.
+ IfFailGo(pMiniMdEmit->GetTypeDefRecord(RidFromToken(pTokenRec->m_tkTo), &pRecEmit));
+ IfFailGo(pMiniMdEmit->PutToken(TBL_TypeDef, TypeDefRec::COL_Extends, pRecEmit, tkExtendsEmit));
+ }
+ else
+ {
+ // <TODO>@FUTURE: we can check to make sure the import extends maps to the one that is set to the emit scope.
+ // Otherwise, it is a error to report to linker.</TODO>
+ }
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CompleteMergeTypeDefs()
+
+
+//*****************************************************************************
+// merging TypeSpecs
+//*****************************************************************************
+HRESULT NEWMERGER::MergeTypeSpecs()
+{
+ HRESULT hr = NOERROR;
+ TypeSpecRec *pRecImport = NULL;
+ TypeSpecRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ TOKENREC *pTokenRec;
+ mdTypeSpec tsImp;
+ mdTypeSpec tsEmit;
+ bool fDuplicate;
+ PCCOR_SIGNATURE pbSig;
+ ULONG cbSig;
+ ULONG cbEmit;
+ CQuickBytes qbSig;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ iCount = pMiniMdImport->getCountTypeSpecs();
+
+ // loop through all TypeSpec
+ for (i = 1; i <= iCount; i++)
+ {
+ // only merge those TypeSpecs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsTypeSpecMarked(TokenFromRid(i, mdtTypeSpec)) == false)
+ continue;
+
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetTypeSpecRecord(i, &pRecImport));
+ IfFailGo(pMiniMdImport->getSignatureOfTypeSpec(pRecImport, &pbSig, &cbSig));
+
+ // convert tokens contained in signature to new scope
+ IfFailGo(ImportHelper::MergeUpdateTokenInFieldSig(
+ NULL, // Assembly emit scope.
+ pMiniMdEmit, // The emit scope.
+ NULL, NULL, 0, // Import assembly information.
+ pMiniMdImport, // The scope to merge into the emit scope.
+ pbSig, // signature from the imported scope
+ pCurTkMap, // Internal token mapping structure.
+ &qbSig, // [OUT] translated signature
+ 0, // start from first byte of the signature
+ 0, // don't care how many bytes consumed
+ &cbEmit)); // number of bytes write to cbEmit
+
+ hr = CLDB_E_RECORD_NOTFOUND;
+ if (m_fDupCheck)
+ hr = ImportHelper::FindTypeSpec(
+ pMiniMdEmit,
+ (PCOR_SIGNATURE) qbSig.Ptr(),
+ cbEmit,
+ &tsEmit );
+
+ if ( hr == S_OK )
+ {
+ // find a duplicate
+ fDuplicate = true;
+ }
+ else
+ {
+ // copy over
+ fDuplicate = false;
+ IfFailGo(pMiniMdEmit->AddTypeSpecRecord(&pRecEmit, (ULONG *)&tsEmit));
+ tsEmit = TokenFromRid(tsEmit, mdtTypeSpec);
+ IfFailGo( pMiniMdEmit->PutBlob(
+ TBL_TypeSpec,
+ TypeSpecRec::COL_Signature,
+ pRecEmit,
+ (PCOR_SIGNATURE)qbSig.Ptr(),
+ cbEmit));
+ }
+ tsImp = TokenFromRid(i, mdtTypeSpec);
+
+ // Record the token movement
+ IfFailGo( pCurTkMap->InsertNotFound(tsImp, fDuplicate, tsEmit, &pTokenRec) );
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeTypeSpecs()
+
+
+//*****************************************************************************
+// merging Children of TypeDefs. This includes field, method, parameter, property, event
+//*****************************************************************************
+HRESULT NEWMERGER::MergeTypeDefChildren()
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ mdTypeDef tdEmit;
+ mdTypeDef tdImport;
+ TOKENREC *pTokenRec;
+
+#if _DEBUG
+ TypeDefRec *pRecImport = NULL;
+ LPCUTF8 szNameImp;
+ LPCUTF8 szNamespaceImp;
+#endif // _DEBUG
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountTypeDefs();
+
+ // loop through all TypeDef again to merge/copy Methods, fields, events, and properties
+ //
+ for (i = 1; i <= iCount; i++)
+ {
+ // only merge those TypeDefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsTypeDefMarked(TokenFromRid(i, mdtTypeDef)) == false)
+ continue;
+
+#if _DEBUG
+ IfFailGo(pMiniMdImport->GetTypeDefRecord(i, &pRecImport));
+ IfFailGo(pMiniMdImport->getNameOfTypeDef(pRecImport, &szNameImp));
+ IfFailGo(pMiniMdImport->getNamespaceOfTypeDef(pRecImport, &szNamespaceImp));
+#endif // _DEBUG
+
+ // check to see if the typedef is duplicate or not
+ tdImport = TokenFromRid(i, mdtTypeDef);
+ if ( pCurTkMap->Find( tdImport, &pTokenRec) == false)
+ {
+ _ASSERTE( !"bad state!");
+ IfFailGo( META_E_BADMETADATA );
+ }
+ tdEmit = pTokenRec->m_tkTo;
+ if (pTokenRec->m_isDuplicate == false)
+ {
+ // now move all of the children records over
+ IfFailGo( CopyMethods(pImportData, tdImport, tdEmit) );
+ IfFailGo( CopyFields(pImportData, tdImport, tdEmit) );
+
+ IfFailGo( CopyEvents(pImportData, tdImport, tdEmit) );
+
+ // Property has dependency on events
+ IfFailGo( CopyProperties(pImportData, tdImport, tdEmit) );
+
+ // Generic Params.
+ IfFailGo( CopyGenericParams(pImportData, tdImport, tdEmit) );
+ }
+ else
+ {
+ // verify the children records
+ IfFailGo( VerifyMethods(pImportData, tdImport, tdEmit) );
+ IfFailGo( VerifyFields(pImportData, tdImport, tdEmit) );
+ IfFailGo( VerifyEvents(pImportData, tdImport, tdEmit) );
+
+ // property has dependency on events
+ IfFailGo( VerifyProperties(pImportData, tdImport, tdEmit) );
+
+ IfFailGo( VerifyGenericParams(pImportData, tdImport, tdEmit) );
+ }
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeTypeDefChildren()
+
+
+//*******************************************************************************
+// Helper to copy an Method record
+//*******************************************************************************
+HRESULT NEWMERGER::CopyMethod(
+ MergeImportData *pImportData, // [IN] import scope
+ MethodRec *pRecImp, // [IN] the record to import
+ MethodRec *pRecEmit) // [IN] the emit record to fill
+{
+ HRESULT hr;
+ CMiniMdRW *pMiniMdImp = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ CMiniMdRW *pMiniMdEmit = GetMiniMdEmit();
+ LPCUTF8 szName;
+ PCCOR_SIGNATURE pbSig;
+ ULONG cbSig;
+ ULONG cbEmit;
+ CQuickBytes qbSig;
+ MDTOKENMAP *pCurTkMap;
+
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // copy over the fix part of the record
+ pRecEmit->Copy(pRecImp);
+
+ // copy over the name
+ IfFailGo(pMiniMdImp->getNameOfMethod(pRecImp, &szName));
+ IfFailGo(pMiniMdEmit->PutString(TBL_Method, MethodRec::COL_Name, pRecEmit, szName));
+
+ // copy over the signature
+ IfFailGo(pMiniMdImp->getSignatureOfMethod(pRecImp, &pbSig, &cbSig));
+
+ // convert rid contained in signature to new scope
+ IfFailGo(ImportHelper::MergeUpdateTokenInSig(
+ NULL, // Assembly emit scope.
+ pMiniMdEmit, // The emit scope.
+ NULL, NULL, 0, // Import assembly scope information.
+ pMiniMdImp, // The scope to merge into the emit scope.
+ pbSig, // signature from the imported scope
+ pCurTkMap, // Internal token mapping structure.
+ &qbSig, // [OUT] translated signature
+ 0, // start from first byte of the signature
+ 0, // don't care how many bytes consumed
+ &cbEmit)); // number of bytes write to cbEmit
+
+ IfFailGo(pMiniMdEmit->PutBlob(TBL_Method, MethodRec::COL_Signature, pRecEmit, qbSig.Ptr(), cbEmit));
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyMethod()
+
+
+//*******************************************************************************
+// Helper to copy an field record
+//*******************************************************************************
+HRESULT NEWMERGER::CopyField(
+ MergeImportData *pImportData, // [IN] import scope
+ FieldRec *pRecImp, // [IN] the record to import
+ FieldRec *pRecEmit) // [IN] the emit record to fill
+{
+ HRESULT hr;
+ CMiniMdRW *pMiniMdImp = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ CMiniMdRW *pMiniMdEmit = GetMiniMdEmit();
+ LPCUTF8 szName;
+ PCCOR_SIGNATURE pbSig;
+ ULONG cbSig;
+ ULONG cbEmit;
+ CQuickBytes qbSig;
+ MDTOKENMAP *pCurTkMap;
+
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // copy over the fix part of the record
+ pRecEmit->SetFlags(pRecImp->GetFlags());
+
+ // copy over the name
+ IfFailGo(pMiniMdImp->getNameOfField(pRecImp, &szName));
+ IfFailGo(pMiniMdEmit->PutString(TBL_Field, FieldRec::COL_Name, pRecEmit, szName));
+
+ // copy over the signature
+ IfFailGo(pMiniMdImp->getSignatureOfField(pRecImp, &pbSig, &cbSig));
+
+ // convert rid contained in signature to new scope
+ IfFailGo(ImportHelper::MergeUpdateTokenInSig(
+ NULL, // Emit assembly scope.
+ pMiniMdEmit, // The emit scope.
+ NULL, NULL, 0, // Import assembly scope information.
+ pMiniMdImp, // The scope to merge into the emit scope.
+ pbSig, // signature from the imported scope
+ pCurTkMap, // Internal token mapping structure.
+ &qbSig, // [OUT] translated signature
+ 0, // start from first byte of the signature
+ 0, // don't care how many bytes consumed
+ &cbEmit)); // number of bytes write to cbEmit
+
+ IfFailGo(pMiniMdEmit->PutBlob(TBL_Field, FieldRec::COL_Signature, pRecEmit, qbSig.Ptr(), cbEmit));
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyField()
+
+//*******************************************************************************
+// Helper to copy an field record
+//*******************************************************************************
+HRESULT NEWMERGER::CopyParam(
+ MergeImportData *pImportData, // [IN] import scope
+ ParamRec *pRecImp, // [IN] the record to import
+ ParamRec *pRecEmit) // [IN] the emit record to fill
+{
+ HRESULT hr;
+ CMiniMdRW *pMiniMdImp = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ CMiniMdRW *pMiniMdEmit = GetMiniMdEmit();
+ LPCUTF8 szName;
+ MDTOKENMAP *pCurTkMap;
+
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // copy over the fix part of the record
+ pRecEmit->Copy(pRecImp);
+
+ // copy over the name
+ IfFailGo(pMiniMdImp->getNameOfParam(pRecImp, &szName));
+ IfFailGo(pMiniMdEmit->PutString(TBL_Param, ParamRec::COL_Name, pRecEmit, szName));
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyParam()
+
+//*******************************************************************************
+// Helper to copy an Event record
+//*******************************************************************************
+HRESULT NEWMERGER::CopyEvent(
+ MergeImportData *pImportData, // [IN] import scope
+ EventRec *pRecImp, // [IN] the record to import
+ EventRec *pRecEmit) // [IN] the emit record to fill
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImp = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ CMiniMdRW *pMiniMdEmit = GetMiniMdEmit();
+ mdToken tkEventTypeImp;
+ mdToken tkEventTypeEmit; // could be TypeDef or TypeRef
+ LPCUTF8 szName;
+ MDTOKENMAP *pCurTkMap;
+
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ pRecEmit->SetEventFlags(pRecImp->GetEventFlags());
+
+ //move over the event name
+ IfFailGo(pMiniMdImp->getNameOfEvent(pRecImp, &szName));
+ IfFailGo( pMiniMdEmit->PutString(TBL_Event, EventRec::COL_Name, pRecEmit, szName) );
+
+ // move over the EventType
+ tkEventTypeImp = pMiniMdImp->getEventTypeOfEvent(pRecImp);
+ if ( !IsNilToken(tkEventTypeImp) )
+ {
+ IfFailGo( pCurTkMap->Remap(tkEventTypeImp, &tkEventTypeEmit) );
+ IfFailGo(pMiniMdEmit->PutToken(TBL_Event, EventRec::COL_EventType, pRecEmit, tkEventTypeEmit));
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyEvent()
+
+
+//*******************************************************************************
+// Helper to copy a property record
+//*******************************************************************************
+HRESULT NEWMERGER::CopyProperty(
+ MergeImportData *pImportData, // [IN] import scope
+ PropertyRec *pRecImp, // [IN] the record to import
+ PropertyRec *pRecEmit) // [IN] the emit record to fill
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImp = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ CMiniMdRW *pMiniMdEmit = GetMiniMdEmit();
+ LPCUTF8 szName;
+ PCCOR_SIGNATURE pbSig;
+ ULONG cbSig;
+ ULONG cbEmit;
+ CQuickBytes qbSig;
+ MDTOKENMAP *pCurTkMap;
+
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // move over the flag value
+ pRecEmit->SetPropFlags(pRecImp->GetPropFlags());
+
+ //move over the property name
+ IfFailGo(pMiniMdImp->getNameOfProperty(pRecImp, &szName));
+ IfFailGo( pMiniMdEmit->PutString(TBL_Property, PropertyRec::COL_Name, pRecEmit, szName) );
+
+ // move over the type of the property
+ IfFailGo(pMiniMdImp->getTypeOfProperty(pRecImp, &pbSig, &cbSig));
+
+ // convert rid contained in signature to new scope
+ IfFailGo( ImportHelper::MergeUpdateTokenInSig(
+ NULL, // Assembly emit scope.
+ pMiniMdEmit, // The emit scope.
+ NULL, NULL, 0, // Import assembly scope information.
+ pMiniMdImp, // The scope to merge into the emit scope.
+ pbSig, // signature from the imported scope
+ pCurTkMap, // Internal token mapping structure.
+ &qbSig, // [OUT] translated signature
+ 0, // start from first byte of the signature
+ 0, // don't care how many bytes consumed
+ &cbEmit) ); // number of bytes write to cbEmit
+
+ IfFailGo(pMiniMdEmit->PutBlob(TBL_Property, PropertyRec::COL_Type, pRecEmit, qbSig.Ptr(), cbEmit));
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyProperty()
+
+
+//*****************************************************************************
+// Copy MethodSemantics for an event or a property
+//*****************************************************************************
+HRESULT NEWMERGER::CopyMethodSemantics(
+ MergeImportData *pImportData,
+ mdToken tkImport, // Event or property in the import scope
+ mdToken tkEmit) // corresponding event or property in the emitting scope
+{
+ HRESULT hr = NOERROR;
+ MethodSemanticsRec *pRecImport = NULL;
+ MethodSemanticsRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ CMiniMdRW *pMiniMdEmit = GetMiniMdEmit();
+ ULONG i;
+ ULONG msEmit; // MethodSemantics are just index not tokens
+ mdToken tkMethodImp;
+ mdToken tkMethodEmit;
+ MDTOKENMAP *pCurTkMap;
+ HENUMInternal hEnum;
+
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // copy over the associates
+ IfFailGo( pMiniMdImport->FindMethodSemanticsHelper(tkImport, &hEnum) );
+ while (HENUMInternal::EnumNext(&hEnum, (mdToken *) &i))
+ {
+ IfFailGo(pMiniMdImport->GetMethodSemanticsRecord(i, &pRecImport));
+ IfFailGo(pMiniMdEmit->AddMethodSemanticsRecord(&pRecEmit, &msEmit));
+ pRecEmit->SetSemantic(pRecImport->GetSemantic());
+
+ // set the MethodSemantics
+ tkMethodImp = pMiniMdImport->getMethodOfMethodSemantics(pRecImport);
+ IfFailGo( pCurTkMap->Remap(tkMethodImp, &tkMethodEmit) );
+ IfFailGo( pMiniMdEmit->PutToken(TBL_MethodSemantics, MethodSemanticsRec::COL_Method, pRecEmit, tkMethodEmit));
+
+ // set the associate
+ _ASSERTE( pMiniMdImport->getAssociationOfMethodSemantics(pRecImport) == tkImport );
+ IfFailGo( pMiniMdEmit->PutToken(TBL_MethodSemantics, MethodSemanticsRec::COL_Association, pRecEmit, tkEmit));
+
+ // no need to record the movement since it is not a token
+ IfFailGo( pMiniMdEmit->AddMethodSemanticsToHash(msEmit) );
+ }
+ErrExit:
+ HENUMInternal::ClearEnum(&hEnum);
+ return hr;
+} // HRESULT NEWMERGER::CopyMethodSemantics()
+
+
+//*****************************************************************************
+// Copy Methods given a TypeDef
+//*****************************************************************************
+HRESULT NEWMERGER::CopyMethods(
+ MergeImportData *pImportData,
+ mdTypeDef tdImport,
+ mdTypeDef tdEmit)
+{
+ HRESULT hr = NOERROR;
+ MethodRec *pRecImport = NULL;
+ MethodRec *pRecEmit = NULL;
+ TypeDefRec *pTypeDefRec;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG ridStart, ridEnd;
+ ULONG i;
+ mdMethodDef mdEmit;
+ mdMethodDef mdImp;
+ TOKENREC *pTokenRec;
+ MDTOKENMAP *pCurTkMap;
+
+ MergeTypeData *pMTD;
+ BOOL bSuppressMergeCheck;
+ mdCustomAttribute tkCA;
+
+ pMiniMdEmit = GetMiniMdEmit();
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ IfFailGo(pMiniMdImport->GetTypeDefRecord(RidFromToken(tdImport), &pTypeDefRec));
+ ridStart = pMiniMdImport->getMethodListOfTypeDef(pTypeDefRec);
+ IfFailGo(pMiniMdImport->getEndMethodListOfTypeDef(RidFromToken(tdImport), &ridEnd));
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ pMTD = m_rMTDs.Get(RidFromToken(tdEmit));
+
+ // make sure we didn't count the methods yet
+ _ASSERTE(pMTD->m_cMethods == 0);
+
+ // loop through all Methods
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetMethodRid(i, (ULONG *)&mdImp));
+
+ // only merge those MethodDefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsMethodMarked(TokenFromRid(mdImp, mdtMethodDef)) == false)
+ continue;
+
+ IfFailGo(pMiniMdImport->GetMethodRecord(mdImp, &pRecImport));
+ IfFailGo(pMiniMdEmit->AddMethodRecord(&pRecEmit, (RID *)&mdEmit));
+
+ // copy the method content over
+ IfFailGo( CopyMethod(pImportData, pRecImport, pRecEmit) );
+
+ IfFailGo( pMiniMdEmit->AddMethodToTypeDef(RidFromToken(tdEmit), mdEmit));
+
+ // record the token movement
+ mdImp = TokenFromRid(mdImp, mdtMethodDef);
+ mdEmit = TokenFromRid(mdEmit, mdtMethodDef);
+ IfFailGo( pMiniMdEmit->AddMemberDefToHash(
+ mdEmit,
+ tdEmit) );
+
+ IfFailGo( pCurTkMap->InsertNotFound(mdImp, false, mdEmit, &pTokenRec) );
+
+ // copy over the children
+ IfFailGo( CopyParams(pImportData, mdImp, mdEmit) );
+ IfFailGo( CopyGenericParams(pImportData, mdImp, mdEmit) );
+
+ bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck ||
+ ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport,
+ mdImp, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+
+ if (!bSuppressMergeCheck) {
+ pMTD->m_cMethods++;
+ }
+ }
+
+ // make sure we don't count any methods if merge check is suppressed on the type
+ _ASSERTE(pMTD->m_cMethods == 0 || !pMTD->m_bSuppressMergeCheck);
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyMethods()
+
+
+//*****************************************************************************
+// Copy Fields given a TypeDef
+//*****************************************************************************
+HRESULT NEWMERGER::CopyFields(
+ MergeImportData *pImportData,
+ mdTypeDef tdImport,
+ mdTypeDef tdEmit)
+{
+ HRESULT hr = NOERROR;
+ FieldRec *pRecImport = NULL;
+ FieldRec *pRecEmit = NULL;
+ TypeDefRec *pTypeDefRec;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG ridStart, ridEnd;
+ ULONG i;
+ mdFieldDef fdEmit;
+ mdFieldDef fdImp;
+ bool bDuplicate;
+ TOKENREC *pTokenRec;
+ PCCOR_SIGNATURE pvSigBlob;
+ ULONG cbSigBlob;
+ MDTOKENMAP *pCurTkMap;
+
+ MergeTypeData *pMTD;
+ BOOL bSuppressMergeCheck;
+ mdCustomAttribute tkCA;
+
+ pMiniMdEmit = GetMiniMdEmit();
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ IfFailGo(pMiniMdImport->GetTypeDefRecord(RidFromToken(tdImport), &pTypeDefRec));
+ ridStart = pMiniMdImport->getFieldListOfTypeDef(pTypeDefRec);
+ IfFailGo(pMiniMdImport->getEndFieldListOfTypeDef(RidFromToken(tdImport), &ridEnd));
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ pMTD = m_rMTDs.Get(RidFromToken(tdEmit));
+
+ // make sure we didn't count the methods yet
+ _ASSERTE(pMTD->m_cFields == 0);
+
+ // loop through all FieldDef of a TypeDef
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetFieldRid(i, (ULONG *)&fdImp));
+
+ // only merge those FieldDefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsFieldMarked(TokenFromRid(fdImp, mdtFieldDef)) == false)
+ continue;
+
+
+ IfFailGo(pMiniMdImport->GetFieldRecord(fdImp, &pRecImport));
+ bDuplicate = false;
+ IfFailGo(pMiniMdEmit->AddFieldRecord(&pRecEmit, (RID *)&fdEmit));
+
+ // copy the field content over
+ IfFailGo( CopyField(pImportData, pRecImport, pRecEmit) );
+
+ IfFailGo( pMiniMdEmit->AddFieldToTypeDef(RidFromToken(tdEmit), fdEmit));
+
+ // record the token movement
+ fdImp = TokenFromRid(fdImp, mdtFieldDef);
+ fdEmit = TokenFromRid(fdEmit, mdtFieldDef);
+ IfFailGo(pMiniMdEmit->getSignatureOfField(pRecEmit, &pvSigBlob, &cbSigBlob));
+ IfFailGo( pMiniMdEmit->AddMemberDefToHash(
+ fdEmit,
+ tdEmit) );
+
+ IfFailGo( pCurTkMap->InsertNotFound(fdImp, false, fdEmit, &pTokenRec) );
+
+ // count the number of fields that didn't suppress merge check
+ // non-static fields doesn't inherite the suppress merge check attribute from the type
+ bSuppressMergeCheck =
+ (IsFdStatic(pRecEmit->GetFlags()) && pMTD->m_bSuppressMergeCheck) ||
+ ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport,
+ fdImp, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+ if (!bSuppressMergeCheck) {
+ pMTD->m_cFields++;
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyFields()
+
+
+//*****************************************************************************
+// Copy Events given a TypeDef
+//*****************************************************************************
+HRESULT NEWMERGER::CopyEvents(
+ MergeImportData *pImportData,
+ mdTypeDef tdImport,
+ mdTypeDef tdEmit)
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ CMiniMdRW *pMiniMdEmit = GetMiniMdEmit();
+ RID ridEventMap;
+ EventMapRec *pEventMapRec;
+ EventRec *pRecImport;
+ EventRec *pRecEmit;
+ ULONG ridStart;
+ ULONG ridEnd;
+ ULONG i;
+ mdEvent evImp;
+ mdEvent evEmit;
+ TOKENREC *pTokenRec;
+ ULONG iEventMap;
+ EventMapRec *pEventMap;
+ MDTOKENMAP *pCurTkMap;
+
+ MergeTypeData *pMTD;
+ BOOL bSuppressMergeCheck;
+ mdCustomAttribute tkCA;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ pMTD = m_rMTDs.Get(RidFromToken(tdEmit));
+
+ // make sure we didn't count the events yet
+ _ASSERTE(pMTD->m_cEvents == 0);
+
+ IfFailGo(pMiniMdImport->FindEventMapFor(RidFromToken(tdImport), &ridEventMap));
+ if (!InvalidRid(ridEventMap))
+ {
+ IfFailGo(pMiniMdImport->GetEventMapRecord(ridEventMap, &pEventMapRec));
+ ridStart = pMiniMdImport->getEventListOfEventMap(pEventMapRec);
+ IfFailGo(pMiniMdImport->getEndEventListOfEventMap(ridEventMap, &ridEnd));
+
+ if (ridEnd > ridStart)
+ {
+ // If there is any event, create the eventmap record in the emit scope
+ // Create new record.
+ IfFailGo(pMiniMdEmit->AddEventMapRecord(&pEventMap, &iEventMap));
+
+ // Set parent.
+ IfFailGo(pMiniMdEmit->PutToken(TBL_EventMap, EventMapRec::COL_Parent, pEventMap, tdEmit));
+ }
+
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ // get the real event rid
+ IfFailGo(pMiniMdImport->GetEventRid(i, (ULONG *)&evImp));
+
+ // only merge those Events that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsEventMarked(TokenFromRid(evImp, mdtEvent)) == false)
+ continue;
+
+ IfFailGo(pMiniMdImport->GetEventRecord(evImp, &pRecImport));
+ IfFailGo(pMiniMdEmit->AddEventRecord(&pRecEmit, (RID *)&evEmit));
+
+ // copy the event record over
+ IfFailGo( CopyEvent(pImportData, pRecImport, pRecEmit) );
+
+ // Add Event to the EventMap.
+ IfFailGo( pMiniMdEmit->AddEventToEventMap(iEventMap, evEmit) );
+
+ // record the token movement
+ evImp = TokenFromRid(evImp, mdtEvent);
+ evEmit = TokenFromRid(evEmit, mdtEvent);
+
+ IfFailGo( pCurTkMap->InsertNotFound(evImp, false, evEmit, &pTokenRec) );
+
+ // copy over the method semantics
+ IfFailGo( CopyMethodSemantics(pImportData, evImp, evEmit) );
+
+ bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck ||
+ ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport,
+ evImp, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+ if (!bSuppressMergeCheck) {
+ pMTD->m_cEvents++;
+ }
+ }
+ }
+
+ // make sure we don't count any events if merge check is suppressed on the type
+ _ASSERTE(pMTD->m_cEvents == 0 || !pMTD->m_bSuppressMergeCheck);
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyEvents()
+
+
+//*****************************************************************************
+// Copy Properties given a TypeDef
+//*****************************************************************************
+HRESULT NEWMERGER::CopyProperties(
+ MergeImportData *pImportData,
+ mdTypeDef tdImport,
+ mdTypeDef tdEmit)
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ CMiniMdRW *pMiniMdEmit = GetMiniMdEmit();
+ RID ridPropertyMap;
+ PropertyMapRec *pPropertyMapRec;
+ PropertyRec *pRecImport;
+ PropertyRec *pRecEmit;
+ ULONG ridStart;
+ ULONG ridEnd;
+ ULONG i;
+ mdProperty prImp;
+ mdProperty prEmit;
+ TOKENREC *pTokenRec;
+ ULONG iPropertyMap;
+ PropertyMapRec *pPropertyMap;
+ MDTOKENMAP *pCurTkMap;
+
+ MergeTypeData *pMTD;
+ BOOL bSuppressMergeCheck;
+ mdCustomAttribute tkCA;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ pMTD = m_rMTDs.Get(RidFromToken(tdEmit));
+
+ // make sure we didn't count the properties yet
+ _ASSERTE(pMTD->m_cProperties == 0);
+
+ IfFailGo(pMiniMdImport->FindPropertyMapFor(RidFromToken(tdImport), &ridPropertyMap));
+ if (!InvalidRid(ridPropertyMap))
+ {
+ IfFailGo(pMiniMdImport->GetPropertyMapRecord(ridPropertyMap, &pPropertyMapRec));
+ ridStart = pMiniMdImport->getPropertyListOfPropertyMap(pPropertyMapRec);
+ IfFailGo(pMiniMdImport->getEndPropertyListOfPropertyMap(ridPropertyMap, &ridEnd));
+
+ if (ridEnd > ridStart)
+ {
+ // If there is any event, create the PropertyMap record in the emit scope
+ // Create new record.
+ IfFailGo(pMiniMdEmit->AddPropertyMapRecord(&pPropertyMap, &iPropertyMap));
+
+ // Set parent.
+ IfFailGo(pMiniMdEmit->PutToken(TBL_PropertyMap, PropertyMapRec::COL_Parent, pPropertyMap, tdEmit));
+ }
+
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ // get the property rid
+ IfFailGo(pMiniMdImport->GetPropertyRid(i, (ULONG *)&prImp));
+
+ // only merge those Properties that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsPropertyMarked(TokenFromRid(prImp, mdtProperty)) == false)
+ continue;
+
+
+ IfFailGo(pMiniMdImport->GetPropertyRecord(prImp, &pRecImport));
+ IfFailGo(pMiniMdEmit->AddPropertyRecord(&pRecEmit, (RID *)&prEmit));
+
+ // copy the property record over
+ IfFailGo( CopyProperty(pImportData, pRecImport, pRecEmit) );
+
+ // Add Property to the PropertyMap.
+ IfFailGo( pMiniMdEmit->AddPropertyToPropertyMap(iPropertyMap, prEmit) );
+
+ // record the token movement
+ prImp = TokenFromRid(prImp, mdtProperty);
+ prEmit = TokenFromRid(prEmit, mdtProperty);
+
+ IfFailGo( pCurTkMap->InsertNotFound(prImp, false, prEmit, &pTokenRec) );
+
+ // copy over the method semantics
+ IfFailGo( CopyMethodSemantics(pImportData, prImp, prEmit) );
+
+ bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck ||
+ ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport,
+ prImp, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+ if (!bSuppressMergeCheck) {
+ pMTD->m_cProperties++;
+ }
+ }
+ }
+
+ // make sure we don't count any properties if merge check is suppressed on the type
+ _ASSERTE(pMTD->m_cProperties == 0 || !pMTD->m_bSuppressMergeCheck);
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyProperties()
+
+
+//*****************************************************************************
+// Copy Parameters given a TypeDef
+//*****************************************************************************
+HRESULT NEWMERGER::CopyParams(
+ MergeImportData *pImportData,
+ mdMethodDef mdImport,
+ mdMethodDef mdEmit)
+{
+ HRESULT hr = NOERROR;
+ ParamRec *pRecImport = NULL;
+ ParamRec *pRecEmit = NULL;
+ MethodRec *pMethodRec;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG ridStart, ridEnd;
+ ULONG i;
+ mdParamDef pdEmit;
+ mdParamDef pdImp;
+ TOKENREC *pTokenRec;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+
+ IfFailGo(pMiniMdImport->GetMethodRecord(RidFromToken(mdImport), &pMethodRec));
+ ridStart = pMiniMdImport->getParamListOfMethod(pMethodRec);
+ IfFailGo(pMiniMdImport->getEndParamListOfMethod(RidFromToken(mdImport), &ridEnd));
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // loop through all InterfaceImpl
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ // Get the param rid
+ IfFailGo(pMiniMdImport->GetParamRid(i, (ULONG *)&pdImp));
+
+ // only merge those Params that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsParamMarked(TokenFromRid(pdImp, mdtParamDef)) == false)
+ continue;
+
+
+ IfFailGo(pMiniMdImport->GetParamRecord(pdImp, &pRecImport));
+ IfFailGo(pMiniMdEmit->AddParamRecord(&pRecEmit, (RID *)&pdEmit));
+
+ // copy the Parameter record over
+ IfFailGo( CopyParam(pImportData, pRecImport, pRecEmit) );
+
+ // warning!! warning!!
+ // We cannot add paramRec to method list until it is fully set.
+ // AddParamToMethod will use the ulSequence in the record
+ IfFailGo( pMiniMdEmit->AddParamToMethod(RidFromToken(mdEmit), pdEmit));
+
+ // record the token movement
+ pdImp = TokenFromRid(pdImp, mdtParamDef);
+ pdEmit = TokenFromRid(pdEmit, mdtParamDef);
+
+ IfFailGo( pCurTkMap->InsertNotFound(pdImp, false, pdEmit, &pTokenRec) );
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyParams()
+
+
+//*****************************************************************************
+// Copy GenericParams given a TypeDef
+//*****************************************************************************
+HRESULT NEWMERGER::CopyGenericParams(
+ MergeImportData *pImportData,
+ mdToken tkImport,
+ mdToken tkEmit)
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ TOKENREC *pTokenRec;
+ GenericParamRec *pRecImport = NULL;
+ GenericParamRec *pRecEmit = NULL;
+ MDTOKENMAP *pCurTkMap;
+ HENUMInternal hEnum;
+ mdGenericParam gpImport;
+ mdGenericParam gpEmit;
+ LPCSTR szGenericParamName;
+
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pMiniMdEmit = GetMiniMdEmit();
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ IfFailGo( pMiniMdImport->FindGenericParamHelper(tkImport, &hEnum) );
+
+ while (HENUMInternal::EnumNext(&hEnum, (mdToken *) &gpImport))
+ {
+ // Get the import GenericParam record
+ _ASSERTE(TypeFromToken(gpImport) == mdtGenericParam);
+ IfFailGo(pMiniMdImport->GetGenericParamRecord(RidFromToken(gpImport), &pRecImport));
+
+ // Create new emit record.
+ IfFailGo(pMiniMdEmit->AddGenericParamRecord(&pRecEmit, (RID *)&gpEmit));
+
+ // copy the GenericParam content
+ pRecEmit->SetNumber( pRecImport->GetNumber());
+ pRecEmit->SetFlags( pRecImport->GetFlags());
+
+ IfFailGo( pMiniMdEmit->PutToken(TBL_GenericParam, GenericParamRec::COL_Owner, pRecEmit, tkEmit));
+
+ IfFailGo(pMiniMdImport->getNameOfGenericParam(pRecImport, &szGenericParamName));
+ IfFailGo( pMiniMdEmit->PutString(TBL_GenericParam, GenericParamRec::COL_Name, pRecEmit, szGenericParamName));
+
+ // record the token movement
+ gpImport = TokenFromRid(gpImport, mdtGenericParam);
+ gpEmit = TokenFromRid(gpEmit, mdtGenericParam);
+
+ IfFailGo( pCurTkMap->InsertNotFound(gpImport, false, gpEmit, &pTokenRec) );
+
+ // copy over any constraints
+ IfFailGo( CopyGenericParamConstraints(pImportData, gpImport, gpEmit) );
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyGenericParams()
+
+
+//*****************************************************************************
+// Copy GenericParamConstraints given a GenericParam
+//*****************************************************************************
+HRESULT NEWMERGER::CopyGenericParamConstraints(
+ MergeImportData *pImportData,
+ mdGenericParamConstraint tkImport,
+ mdGenericParamConstraint tkEmit)
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ TOKENREC *pTokenRec;
+ GenericParamConstraintRec *pRecImport = NULL;
+ GenericParamConstraintRec *pRecEmit = NULL;
+ MDTOKENMAP *pCurTkMap;
+ HENUMInternal hEnum;
+ mdGenericParamConstraint gpImport;
+ mdGenericParamConstraint gpEmit;
+ mdToken tkConstraint;
+
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pMiniMdEmit = GetMiniMdEmit();
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ IfFailGo( pMiniMdImport->FindGenericParamConstraintHelper(tkImport, &hEnum) );
+
+ while (HENUMInternal::EnumNext(&hEnum, (mdToken *) &gpImport))
+ {
+ // Get the import GenericParam record
+ _ASSERTE(TypeFromToken(gpImport) == mdtGenericParamConstraint);
+ IfFailGo(pMiniMdImport->GetGenericParamConstraintRecord(RidFromToken(gpImport), &pRecImport));
+
+ // Translate the constraint before creating new record.
+ tkConstraint = pMiniMdImport->getConstraintOfGenericParamConstraint(pRecImport);
+ if (pCurTkMap->Find(tkConstraint, &pTokenRec) == false)
+ {
+ // This should never fire unless the TypeDefs/Refs weren't merged
+ // before this code runs.
+ _ASSERTE(!"GenericParamConstraint Constraint not found in MERGER::CopyGenericParamConstraints. Bad state!");
+ IfFailGo( META_E_BADMETADATA );
+ }
+ tkConstraint = pTokenRec->m_tkTo;
+
+ // Create new emit record.
+ IfFailGo(pMiniMdEmit->AddGenericParamConstraintRecord(&pRecEmit, (RID *)&gpEmit));
+
+ // copy the GenericParamConstraint content
+ IfFailGo( pMiniMdEmit->PutToken(TBL_GenericParamConstraint, GenericParamConstraintRec::COL_Owner, pRecEmit, tkEmit));
+
+ IfFailGo( pMiniMdEmit->PutToken(TBL_GenericParamConstraint, GenericParamConstraintRec::COL_Constraint, pRecEmit, tkConstraint));
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyGenericParamConstraints()
+
+
+//*****************************************************************************
+// Verify GenericParams given a TypeDef
+//*****************************************************************************
+HRESULT NEWMERGER::VerifyGenericParams(
+ MergeImportData *pImportData,
+ mdToken tkImport,
+ mdToken tkEmit)
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ TOKENREC *pTokenRec;
+ MDTOKENMAP *pCurTkMap;
+ HENUMInternal hEnumImport; // Enumerator for import scope.
+ HENUMInternal hEnumEmit; // Enumerator for emit scope.
+ ULONG cImport, cEmit; // Count of import & emit records.
+ ULONG i; // Enumerating records in import scope.
+ ULONG iEmit; // Tracking records in emit scope.
+ mdGenericParam gpImport; // Import scope GenericParam token.
+ mdGenericParam gpEmit; // Emit scope GenericParam token.
+ GenericParamRec *pRecImport = NULL;
+ GenericParamRec *pRecEmit = NULL;
+ LPCSTR szNameImport; // Name of param in import scope.
+ LPCSTR szNameEmit; // Name of param in emit scope.
+
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pMiniMdEmit = GetMiniMdEmit();
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // Get enumerators for the input and output scopes.
+ IfFailGo(pMiniMdImport->FindGenericParamHelper(tkImport, &hEnumImport));
+ IfFailGo(pMiniMdEmit->FindGenericParamHelper(tkEmit, &hEnumEmit));
+
+ // The counts should be the same.
+ IfFailGo(HENUMInternal::GetCount(&hEnumImport, &cImport));
+ IfFailGo(HENUMInternal::GetCount(&hEnumEmit, &cEmit));
+
+ if (cImport != cEmit)
+ {
+ CheckContinuableErrorEx(META_E_GENERICPARAM_INCONSISTENT, pImportData, tkImport);
+ // If we are here, the linker says this error is OK.
+ }
+
+ for (i=iEmit=0; i<cImport; ++i)
+ {
+ // Get the import GenericParam record
+ IfFailGo(HENUMInternal::GetElement(&hEnumImport, i, &gpImport));
+ _ASSERTE(TypeFromToken(gpImport) == mdtGenericParam);
+ IfFailGo(pMiniMdImport->GetGenericParamRecord(RidFromToken(gpImport), &pRecImport));
+
+ // Find the emit record. If the import and emit scopes are ordered the same
+ // this is easy; otherwise go looking for it.
+ // Get the "next" emit record.
+ if (iEmit < cEmit)
+ {
+ IfFailGo(HENUMInternal::GetElement(&hEnumEmit, iEmit, &gpEmit));
+ _ASSERTE(TypeFromToken(gpEmit) == mdtGenericParam);
+ IfFailGo(pMiniMdEmit->GetGenericParamRecord(RidFromToken(gpEmit), &pRecEmit));
+ }
+
+ // If the import and emit sequence numbers don't match, go looking.
+ // Also, if we would have walked off end of array, go looking.
+ if (iEmit >= cEmit || pRecImport->GetNumber() != pRecEmit->GetNumber())
+ {
+ for (iEmit=0; iEmit<cEmit; ++iEmit)
+ {
+ IfFailGo( HENUMInternal::GetElement(&hEnumEmit, iEmit, &gpEmit));
+ _ASSERTE(TypeFromToken(gpEmit) == mdtGenericParam);
+ IfFailGo(pMiniMdEmit->GetGenericParamRecord(RidFromToken(gpEmit), &pRecEmit));
+
+ // The one we want?
+ if (pRecImport->GetNumber() == pRecEmit->GetNumber())
+ break;
+ }
+ if (iEmit >= cEmit)
+ goto Error; // Didn't find it
+ }
+
+ // Check that these "n'th" GenericParam records match.
+
+ // Flags.
+ if (pRecImport->GetFlags() != pRecEmit->GetFlags())
+ goto Error;
+
+ // Name.
+ IfFailGo(pMiniMdImport->getNameOfGenericParam(pRecImport, &szNameImport));
+ IfFailGo(pMiniMdEmit->getNameOfGenericParam(pRecEmit, &szNameEmit));
+ if (strcmp(szNameImport, szNameEmit) != 0)
+ goto Error;
+
+ // Verify any constraints.
+ gpImport = TokenFromRid(gpImport, mdtGenericParam);
+ gpEmit = TokenFromRid(gpEmit, mdtGenericParam);
+ hr = VerifyGenericParamConstraints(pImportData, gpImport, gpEmit);
+
+ if (SUCCEEDED(hr))
+ {
+ // record the token movement
+ IfFailGo( pCurTkMap->InsertNotFound(gpImport, true, gpEmit, &pTokenRec) );
+ }
+ else
+ {
+Error:
+ // inconsistent in GenericParams
+ hr = S_OK; // discard old error; new error will be returned from CheckContinuableError
+ CheckContinuableErrorEx(META_E_GENERICPARAM_INCONSISTENT, pImportData, tkImport);
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::VerifyGenericParams()
+
+
+//*****************************************************************************
+// Verify GenericParamConstraints given a GenericParam
+//*****************************************************************************
+HRESULT NEWMERGER::VerifyGenericParamConstraints(
+ MergeImportData *pImportData, // The import scope.
+ mdGenericParam gpImport, // Import GenericParam.
+ mdGenericParam gpEmit) // Emit GenericParam.
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ TOKENREC *pTokenRec;
+ HENUMInternal hEnumImport; // Enumerator for import scope.
+ HENUMInternal hEnumEmit; // Enumerator for emit scope.
+ ULONG cImport, cEmit; // Count of import & emit records.
+ ULONG i; // Enumerating records in import scope.
+ ULONG iEmit; // Tracking records in emit scope.
+ GenericParamConstraintRec *pRecImport = NULL;
+ GenericParamConstraintRec *pRecEmit = NULL;
+ MDTOKENMAP *pCurTkMap;
+ mdToken tkConstraintImport = mdTokenNil;
+ mdToken tkConstraintEmit = mdTokenNil;
+
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pMiniMdEmit = GetMiniMdEmit();
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // Get enumerators for the input and output scopes.
+ IfFailGo(pMiniMdImport->FindGenericParamConstraintHelper(gpImport, &hEnumImport));
+ IfFailGo(pMiniMdEmit->FindGenericParamConstraintHelper(gpEmit, &hEnumEmit));
+
+ // The counts should be the same.
+ IfFailGo(HENUMInternal::GetCount(&hEnumImport, &cImport));
+ IfFailGo(HENUMInternal::GetCount(&hEnumEmit, &cEmit));
+
+ if (cImport != cEmit)
+ IfFailGo(META_E_GENERICPARAM_INCONSISTENT); // Different numbers of constraints.
+
+ for (i=iEmit=0; i<cImport; ++i)
+ {
+ // Get the import GenericParam record
+ IfFailGo( HENUMInternal::GetElement(&hEnumImport, i, &gpImport));
+ _ASSERTE(TypeFromToken(gpImport) == mdtGenericParamConstraint);
+ IfFailGo(pMiniMdImport->GetGenericParamConstraintRecord(RidFromToken(gpImport), &pRecImport));
+
+ // Get the constraint.
+ tkConstraintImport = pMiniMdImport->getConstraintOfGenericParamConstraint(pRecImport);
+ if (pCurTkMap->Find(tkConstraintImport, &pTokenRec) == false)
+ {
+ // This should never fire unless the TypeDefs/Refs weren't merged
+ // before this code runs.
+ _ASSERTE(!"GenericParamConstraint Constraint not found in MERGER::VerifyGenericParamConstraints. Bad state!");
+ IfFailGo( META_E_BADMETADATA );
+ }
+ tkConstraintImport = pTokenRec->m_tkTo;
+
+ // Find the emit record. If the import and emit scopes are ordered the same
+ // this is easy; otherwise go looking for it.
+ // Get the "next" emit record.
+ if (iEmit < cEmit)
+ {
+ IfFailGo( HENUMInternal::GetElement(&hEnumEmit, iEmit, &gpEmit));
+ _ASSERTE(TypeFromToken(gpEmit) == mdtGenericParamConstraint);
+ IfFailGo(pMiniMdEmit->GetGenericParamConstraintRecord(RidFromToken(gpEmit), &pRecEmit));
+ tkConstraintEmit = pMiniMdEmit->getConstraintOfGenericParamConstraint(pRecEmit);
+ }
+
+ // If the import and emit constraints don't match, go looking.
+ if (iEmit >= cEmit || tkConstraintEmit != tkConstraintImport)
+ {
+ for (iEmit=0; iEmit<cEmit; ++iEmit)
+ {
+ IfFailGo( HENUMInternal::GetElement(&hEnumEmit, iEmit, &gpEmit));
+ _ASSERTE(TypeFromToken(gpEmit) == mdtGenericParamConstraint);
+ IfFailGo(pMiniMdEmit->GetGenericParamConstraintRecord(RidFromToken(gpEmit), &pRecEmit));
+ tkConstraintEmit = pMiniMdEmit->getConstraintOfGenericParamConstraint(pRecEmit);
+
+ // The one we want?
+ if (tkConstraintEmit == tkConstraintImport)
+ break;
+ }
+ if (iEmit >= cEmit)
+ {
+ IfFailGo(META_E_GENERICPARAM_INCONSISTENT); // Didn't find the constraint
+ }
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::VerifyGenericParamConstraints()
+
+
+//*****************************************************************************
+// Verify Methods
+//*****************************************************************************
+HRESULT NEWMERGER::VerifyMethods(
+ MergeImportData *pImportData,
+ mdTypeDef tdImport,
+ mdTypeDef tdEmit)
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ MethodRec *pRecImp;
+ MethodRec *pRecEmit;
+ ULONG ridStart;
+ ULONG ridEnd;
+ ULONG i;
+
+ TypeDefRec *pTypeDefRec;
+ LPCUTF8 szName;
+ PCCOR_SIGNATURE pbSig;
+ ULONG cbSig;
+ ULONG cbEmit;
+ CQuickBytes qbSig;
+ TOKENREC *pTokenRec;
+ mdMethodDef mdImp;
+ mdMethodDef mdEmit;
+ MDTOKENMAP *pCurTkMap;
+
+ MergeTypeData *pMTD;
+ BOOL bSuppressMergeCheck;
+ ULONG cImport = 0; // count of non-merge check suppressed methods
+ mdCustomAttribute tkCA;
+
+ pMiniMdEmit = GetMiniMdEmit();
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // Get a count of records in the import scope; prepare to enumerate them.
+ IfFailGo(pMiniMdImport->GetTypeDefRecord(RidFromToken(tdImport), &pTypeDefRec));
+ ridStart = pMiniMdImport->getMethodListOfTypeDef(pTypeDefRec);
+ IfFailGo(pMiniMdImport->getEndMethodListOfTypeDef(RidFromToken(tdImport), &ridEnd));
+
+ pMTD = m_rMTDs.Get(RidFromToken(tdEmit));
+
+ // loop through all Methods of the TypeDef
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ IfFailGo(pMiniMdImport->GetMethodRid(i, (ULONG *)&mdImp));
+
+ // only verify those Methods that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsMethodMarked(TokenFromRid(mdImp, mdtMethodDef)) == false)
+ continue;
+
+ IfFailGo(pMiniMdImport->GetMethodRecord(mdImp, &pRecImp));
+
+ if (m_fDupCheck == FALSE && tdImport == pImportData->m_pRegMetaImport->m_tdModule) // TokenFromRid(1, mdtTypeDef))
+ {
+ // No dup check. This is the scenario that we only have one import scope. Just copy over the
+ // globals.
+ goto CopyMethodLabel;
+ }
+
+ IfFailGo(pMiniMdImport->getNameOfMethod(pRecImp, &szName));
+ IfFailGo(pMiniMdImport->getSignatureOfMethod(pRecImp, &pbSig, &cbSig));
+
+ mdImp = TokenFromRid(mdImp, mdtMethodDef);
+
+ if ( IsMdPrivateScope( pRecImp->GetFlags() ) )
+ {
+ // Trigger additive merge
+ goto CopyMethodLabel;
+ }
+
+ // convert rid contained in signature to new scope
+ IfFailGo(ImportHelper::MergeUpdateTokenInSig(
+ NULL, // Assembly emit scope.
+ pMiniMdEmit, // The emit scope.
+ NULL, NULL, 0, // Import assembly scope information.
+ pMiniMdImport, // The scope to merge into the emit scope.
+ pbSig, // signature from the imported scope
+ pCurTkMap, // Internal token mapping structure.
+ &qbSig, // [OUT] translated signature
+ 0, // start from first byte of the signature
+ 0, // don't care how many bytes consumed
+ &cbEmit)); // number of bytes write to cbEmit
+
+ hr = ImportHelper::FindMethod(
+ pMiniMdEmit,
+ tdEmit,
+ szName,
+ (const COR_SIGNATURE *)qbSig.Ptr(),
+ cbEmit,
+ &mdEmit);
+
+ bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck ||
+ ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport,
+ mdImp, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+ if (bSuppressMergeCheck || (tdImport == pImportData->m_pRegMetaImport->m_tdModule))
+ {
+ // global functions! Make sure that we move over the non-duplicate global function
+ // declaration
+ //
+ if (hr == S_OK)
+ {
+ // found the duplicate
+ IfFailGo( VerifyMethod(pImportData, mdImp, mdEmit) );
+ }
+ else
+ {
+CopyMethodLabel:
+ // not a duplicate! Copy over the
+ IfFailGo(pMiniMdEmit->AddMethodRecord(&pRecEmit, (RID *)&mdEmit));
+
+ // copy the method content over
+ IfFailGo( CopyMethod(pImportData, pRecImp, pRecEmit) );
+
+ IfFailGo( pMiniMdEmit->AddMethodToTypeDef(RidFromToken(tdEmit), mdEmit));
+
+ // record the token movement
+ mdEmit = TokenFromRid(mdEmit, mdtMethodDef);
+ IfFailGo( pMiniMdEmit->AddMemberDefToHash(
+ mdEmit,
+ tdEmit) );
+
+ mdImp = TokenFromRid(mdImp, mdtMethodDef);
+ IfFailGo( pCurTkMap->InsertNotFound(mdImp, false, mdEmit, &pTokenRec) );
+
+ // copy over the children
+ IfFailGo( CopyParams(pImportData, mdImp, mdEmit) );
+ IfFailGo( CopyGenericParams(pImportData, mdImp, mdEmit) );
+
+ }
+ }
+ else
+ {
+ if (hr == S_OK)
+ {
+ // Good! We are supposed to find a duplicate
+ IfFailGo( VerifyMethod(pImportData, mdImp, mdEmit) );
+ }
+ else
+ {
+ // Oops! The typedef is duplicated but the method is not!!
+ hr = S_OK; // discard old error; new error will be returned from CheckContinuableError
+ CheckContinuableErrorEx(META_E_METHD_NOT_FOUND, pImportData, mdImp);
+ }
+
+ cImport++;
+ }
+ }
+
+ // The counts should be the same, unless this is <module>
+ if (cImport != pMTD->m_cMethods && tdImport != pImportData->m_pRegMetaImport->m_tdModule)
+ {
+ CheckContinuableErrorEx(META_E_METHOD_COUNTS, pImportData, tdImport);
+ // If we are here, the linker says this error is OK.
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::VerifyMethods()
+
+
+//*****************************************************************************
+// verify a duplicated method
+//*****************************************************************************
+HRESULT NEWMERGER::VerifyMethod(
+ MergeImportData *pImportData,
+ mdMethodDef mdImp, // [IN] the emit record to fill
+ mdMethodDef mdEmit) // [IN] the record to import
+{
+ HRESULT hr;
+ MethodRec *pRecImp;
+ MethodRec *pRecEmit;
+ TOKENREC *pTokenRec;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ IfFailGo( pCurTkMap->InsertNotFound(mdImp, true, mdEmit, &pTokenRec) );
+
+ IfFailGo(pMiniMdImport->GetMethodRecord(RidFromToken(mdImp), &pRecImp));
+
+ // We need to make sure that the impl flags are propagated .
+ // Rules are: if the first method has miForwardRef flag set but the new method does not,
+ // we want to disable the miForwardRef flag. If the one found in the emit scope does not have
+ // miForwardRef set and the second one doesn't either, we want to make sure that the rest of
+ // impl flags are the same.
+ //
+ if ( !IsMiForwardRef( pRecImp->GetImplFlags() ) )
+ {
+ IfFailGo(pMiniMdEmit->GetMethodRecord(RidFromToken(mdEmit), &pRecEmit));
+ if (!IsMiForwardRef(pRecEmit->GetImplFlags()))
+ {
+ // make sure the rest of ImplFlags are the same
+ if (pRecEmit->GetImplFlags() != pRecImp->GetImplFlags())
+ {
+ // inconsistent in implflags
+ CheckContinuableErrorEx(META_E_METHDIMPL_INCONSISTENT, pImportData, mdImp);
+ }
+ }
+ else
+ {
+ // propagate the importing ImplFlags
+ pRecEmit->SetImplFlags(pRecImp->GetImplFlags());
+ }
+ }
+
+ // verify the children
+ IfFailGo( VerifyParams(pImportData, mdImp, mdEmit) );
+ IfFailGo( VerifyGenericParams(pImportData, mdImp, mdEmit) );
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::VerifyMethod()
+
+
+//*****************************************************************************
+// Verify Fields
+//*****************************************************************************
+HRESULT NEWMERGER::VerifyFields(
+ MergeImportData *pImportData,
+ mdTypeDef tdImport,
+ mdTypeDef tdEmit)
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ FieldRec *pRecImp;
+ FieldRec *pRecEmit;
+ mdFieldDef fdImp;
+ mdFieldDef fdEmit;
+ ULONG ridStart;
+ ULONG ridEnd;
+ ULONG i;
+
+ TypeDefRec *pTypeDefRec;
+ LPCUTF8 szName;
+ PCCOR_SIGNATURE pbSig;
+ ULONG cbSig;
+ ULONG cbEmit;
+ CQuickBytes qbSig;
+ TOKENREC *pTokenRec;
+ MDTOKENMAP *pCurTkMap;
+
+ MergeTypeData *pMTD;
+ BOOL bSuppressMergeCheck;
+ ULONG cImport = 0; // count of non-merge check suppressed fields
+ mdCustomAttribute tkCA;
+
+ pMiniMdEmit = GetMiniMdEmit();
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // Get a count of records in the import scope; prepare to enumerate them.
+ IfFailGo(pMiniMdImport->GetTypeDefRecord(RidFromToken(tdImport), &pTypeDefRec));
+ ridStart = pMiniMdImport->getFieldListOfTypeDef(pTypeDefRec);
+ IfFailGo(pMiniMdImport->getEndFieldListOfTypeDef(RidFromToken(tdImport), &ridEnd));
+
+ pMTD = m_rMTDs.Get(RidFromToken(tdEmit));
+
+ // loop through all fields of the TypeDef
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ IfFailGo(pMiniMdImport->GetFieldRid(i, (ULONG *)&fdImp));
+
+ // only verify those fields that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsFieldMarked(TokenFromRid(fdImp, mdtFieldDef)) == false)
+ continue;
+
+ IfFailGo(pMiniMdImport->GetFieldRecord(fdImp, &pRecImp));
+
+ if (m_fDupCheck == FALSE && tdImport == pImportData->m_pRegMetaImport->m_tdModule)
+ {
+ // No dup check. This is the scenario that we only have one import scope. Just copy over the
+ // globals.
+ goto CopyFieldLabel;
+ }
+
+ IfFailGo(pMiniMdImport->getNameOfField(pRecImp, &szName));
+ IfFailGo(pMiniMdImport->getSignatureOfField(pRecImp, &pbSig, &cbSig));
+
+ if ( IsFdPrivateScope(pRecImp->GetFlags()))
+ {
+ // Trigger additive merge
+ fdImp = TokenFromRid(fdImp, mdtFieldDef);
+ goto CopyFieldLabel;
+ }
+
+ // convert rid contained in signature to new scope
+ IfFailGo(ImportHelper::MergeUpdateTokenInSig(
+ NULL, // Assembly emit scope.
+ pMiniMdEmit, // The emit scope.
+ NULL, NULL, 0, // Import assembly scope information.
+ pMiniMdImport, // The scope to merge into the emit scope.
+ pbSig, // signature from the imported scope
+ pCurTkMap, // Internal token mapping structure.
+ &qbSig, // [OUT] translated signature
+ 0, // start from first byte of the signature
+ 0, // don't care how many bytes consumed
+ &cbEmit)); // number of bytes write to cbEmit
+
+ hr = ImportHelper::FindField(
+ pMiniMdEmit,
+ tdEmit,
+ szName,
+ (const COR_SIGNATURE *)qbSig.Ptr(),
+ cbEmit,
+ &fdEmit);
+
+ fdImp = TokenFromRid(fdImp, mdtFieldDef);
+
+ bSuppressMergeCheck =
+ (IsFdStatic(pRecImp->GetFlags()) && pMTD->m_bSuppressMergeCheck) ||
+ ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport,
+ fdImp, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+ if (bSuppressMergeCheck || (tdImport == pImportData->m_pRegMetaImport->m_tdModule))
+ {
+ // global data! Make sure that we move over the non-duplicate global function
+ // declaration
+ //
+ if (hr == S_OK)
+ {
+ // found the duplicate
+ IfFailGo( pCurTkMap->InsertNotFound(fdImp, true, fdEmit, &pTokenRec) );
+ }
+ else
+ {
+CopyFieldLabel:
+ // not a duplicate! Copy over the
+ IfFailGo(pMiniMdEmit->AddFieldRecord(&pRecEmit, (RID *)&fdEmit));
+
+ // copy the field record over
+ IfFailGo( CopyField(pImportData, pRecImp, pRecEmit) );
+
+ IfFailGo( pMiniMdEmit->AddFieldToTypeDef(RidFromToken(tdEmit), fdEmit));
+
+ // record the token movement
+ fdEmit = TokenFromRid(fdEmit, mdtFieldDef);
+ IfFailGo( pMiniMdEmit->AddMemberDefToHash(
+ fdEmit,
+ tdEmit) );
+
+ fdImp = TokenFromRid(fdImp, mdtFieldDef);
+ IfFailGo( pCurTkMap->InsertNotFound(fdImp, false, fdEmit, &pTokenRec) );
+ }
+ }
+ else
+ {
+ if (hr == S_OK)
+ {
+ // Good! We are supposed to find a duplicate
+ IfFailGo( pCurTkMap->InsertNotFound(fdImp, true, fdEmit, &pTokenRec) );
+ }
+ else
+ {
+ // Oops! The typedef is duplicated but the field is not!!
+ hr = S_OK; // discard old error; new error will be returned from CheckContinuableError
+ CheckContinuableErrorEx(META_E_FIELD_NOT_FOUND, pImportData, fdImp);
+ }
+
+ cImport++;
+ }
+ }
+
+ // The counts should be the same, unless this is <module>
+ if (cImport != pMTD->m_cFields && tdImport != pImportData->m_pRegMetaImport->m_tdModule)
+ {
+ CheckContinuableErrorEx(META_E_FIELD_COUNTS, pImportData, tdImport);
+ // If we are here, the linker says this error is OK.
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::VerifyFields()
+
+
+//*****************************************************************************
+// Verify Events
+//*****************************************************************************
+HRESULT NEWMERGER::VerifyEvents(
+ MergeImportData *pImportData,
+ mdTypeDef tdImport,
+ mdTypeDef tdEmit)
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ RID ridEventMap, ridEventMapEmit;
+ EventMapRec *pEventMapRec;
+ EventRec *pRecImport;
+ ULONG ridStart;
+ ULONG ridEnd;
+ ULONG i;
+ mdEvent evImport;
+ mdEvent evEmit;
+ TOKENREC *pTokenRec;
+ LPCUTF8 szName;
+ mdToken tkType;
+ MDTOKENMAP *pCurTkMap;
+
+ EventMapRec *pEventMapEmit;
+ EventRec *pRecEmit;
+ MergeTypeData *pMTD;
+ BOOL bSuppressMergeCheck;
+ ULONG cImport = 0; // count of non-merge check suppressed events
+ mdCustomAttribute tkCA;
+
+ pMiniMdEmit = GetMiniMdEmit();
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ IfFailGo(pMiniMdImport->FindEventMapFor(RidFromToken(tdImport), &ridEventMap));
+ if (!InvalidRid(ridEventMap))
+ {
+ // Get a count of records already in emit scope.
+ IfFailGo(pMiniMdEmit->FindEventMapFor(RidFromToken(tdEmit), &ridEventMapEmit));
+
+ if (InvalidRid(ridEventMapEmit)) {
+ // If there is any event, create the eventmap record in the emit scope
+ // Create new record.
+ IfFailGo(pMiniMdEmit->AddEventMapRecord(&pEventMapEmit, &ridEventMapEmit));
+
+ // Set parent.
+ IfFailGo(pMiniMdEmit->PutToken(TBL_EventMap, EventMapRec::COL_Parent, pEventMapEmit, tdEmit));
+ }
+
+ // Get a count of records in the import scope; prepare to enumerate them.
+ IfFailGo(pMiniMdImport->GetEventMapRecord(ridEventMap, &pEventMapRec));
+ ridStart = pMiniMdImport->getEventListOfEventMap(pEventMapRec);
+ IfFailGo(pMiniMdImport->getEndEventListOfEventMap(ridEventMap, &ridEnd));
+
+ pMTD = m_rMTDs.Get(RidFromToken(tdEmit));
+
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ // get the property rid
+ IfFailGo(pMiniMdImport->GetEventRid(i, (ULONG *)&evImport));
+
+ // only verify those Events that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsEventMarked(TokenFromRid(evImport, mdtEvent)) == false)
+ continue;
+
+ IfFailGo(pMiniMdImport->GetEventRecord(evImport, &pRecImport));
+ IfFailGo(pMiniMdImport->getNameOfEvent(pRecImport, &szName));
+ tkType = pMiniMdImport->getEventTypeOfEvent( pRecImport );
+ IfFailGo( pCurTkMap->Remap(tkType, &tkType) );
+ evImport = TokenFromRid( evImport, mdtEvent);
+
+ hr = ImportHelper::FindEvent(
+ pMiniMdEmit,
+ tdEmit,
+ szName,
+ &evEmit);
+
+ bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck ||
+ ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport,
+ evImport, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+ if (bSuppressMergeCheck)
+ {
+
+ if (hr == S_OK )
+ {
+ // Good. We found the matching event when we have a duplicate typedef
+ IfFailGo( pCurTkMap->InsertNotFound(evImport, true, evEmit, &pTokenRec) );
+ }
+ else
+ {
+ // not a duplicate! Copy over the
+ IfFailGo(pMiniMdEmit->AddEventRecord(&pRecEmit, (RID *)&evEmit));
+
+ // copy the event record over
+ IfFailGo( CopyEvent(pImportData, pRecImport, pRecEmit) );
+
+ // Add Event to the EventMap.
+ IfFailGo( pMiniMdEmit->AddEventToEventMap(ridEventMapEmit, evEmit) );
+
+ // record the token movement
+ evEmit = TokenFromRid(evEmit, mdtEvent);
+
+ IfFailGo( pCurTkMap->InsertNotFound(evImport, false, evEmit, &pTokenRec) );
+
+ // copy over the method semantics
+ IfFailGo( CopyMethodSemantics(pImportData, evImport, evEmit) );
+ }
+ }
+ else
+ {
+ if (hr == S_OK )
+ {
+ // Good. We found the matching event when we have a duplicate typedef
+ IfFailGo( pCurTkMap->InsertNotFound(evImport, true, evEmit, &pTokenRec) );
+ }
+ else
+ {
+ // Oops! The typedef is duplicated but the event is not!!
+ hr = S_OK; // discard old error; new error will be returned from CheckContinuableError
+ CheckContinuableErrorEx(META_E_EVENT_NOT_FOUND, pImportData, evImport);
+
+ }
+
+ cImport++;
+ }
+ }
+
+ // The counts should be the same, unless this is <module>
+ if (cImport != pMTD->m_cEvents && tdImport != pImportData->m_pRegMetaImport->m_tdModule)
+ {
+ CheckContinuableErrorEx(META_E_EVENT_COUNTS, pImportData, tdImport);
+ // If we are here, the linker says this error is OK.
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::VerifyEvents()
+
+
+//*****************************************************************************
+// Verify Properties
+//*****************************************************************************
+HRESULT NEWMERGER::VerifyProperties(
+ MergeImportData *pImportData,
+ mdTypeDef tdImport,
+ mdTypeDef tdEmit)
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ RID ridPropertyMap, ridPropertyMapEmit;
+ PropertyMapRec *pPropertyMapRec;
+ PropertyRec *pRecImport;
+ ULONG ridStart;
+ ULONG ridEnd;
+ ULONG i;
+ mdProperty prImp;
+ mdProperty prEmit;
+ TOKENREC *pTokenRec;
+ LPCUTF8 szName;
+ PCCOR_SIGNATURE pbSig;
+ ULONG cbSig;
+ ULONG cbEmit;
+ CQuickBytes qbSig;
+ MDTOKENMAP *pCurTkMap;
+
+ PropertyMapRec *pPropertyMapEmit;
+ PropertyRec *pRecEmit;
+ MergeTypeData *pMTD;
+ BOOL bSuppressMergeCheck;
+ ULONG cImport = 0; // count of non-merge check suppressed properties
+ mdCustomAttribute tkCA;
+
+ pMiniMdEmit = GetMiniMdEmit();
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ IfFailGo(pMiniMdImport->FindPropertyMapFor(RidFromToken(tdImport), &ridPropertyMap));
+ if (!InvalidRid(ridPropertyMap))
+ {
+ // Get a count of records already in emit scope.
+ IfFailGo(pMiniMdEmit->FindPropertyMapFor(RidFromToken(tdEmit), &ridPropertyMapEmit));
+
+ if (InvalidRid(ridPropertyMapEmit))
+ {
+ // If there is any event, create the PropertyMap record in the emit scope
+ // Create new record.
+ IfFailGo(pMiniMdEmit->AddPropertyMapRecord(&pPropertyMapEmit, &ridPropertyMapEmit));
+
+ // Set parent.
+ IfFailGo(pMiniMdEmit->PutToken(TBL_PropertyMap, PropertyMapRec::COL_Parent, pPropertyMapEmit, tdEmit));
+ }
+
+ // Get a count of records in the import scope; prepare to enumerate them.
+ IfFailGo(pMiniMdImport->GetPropertyMapRecord(ridPropertyMap, &pPropertyMapRec));
+ ridStart = pMiniMdImport->getPropertyListOfPropertyMap(pPropertyMapRec);
+ IfFailGo(pMiniMdImport->getEndPropertyListOfPropertyMap(ridPropertyMap, &ridEnd));
+
+ pMTD = m_rMTDs.Get(RidFromToken(tdEmit));
+
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ // get the property rid
+ IfFailGo(pMiniMdImport->GetPropertyRid(i, (ULONG *)&prImp));
+
+ // only verify those Properties that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsPropertyMarked(TokenFromRid(prImp, mdtProperty)) == false)
+ continue;
+
+ IfFailGo(pMiniMdImport->GetPropertyRecord(prImp, &pRecImport));
+ IfFailGo(pMiniMdImport->getNameOfProperty(pRecImport, &szName));
+ IfFailGo(pMiniMdImport->getTypeOfProperty(pRecImport, &pbSig, &cbSig));
+ prImp = TokenFromRid( prImp, mdtProperty);
+
+ // convert rid contained in signature to new scope
+ IfFailGo( ImportHelper::MergeUpdateTokenInSig(
+ NULL, // Emit assembly.
+ pMiniMdEmit, // The emit scope.
+ NULL, NULL, 0, // Import assembly scope information.
+ pMiniMdImport, // The scope to merge into the emit scope.
+ pbSig, // signature from the imported scope
+ pCurTkMap, // Internal token mapping structure.
+ &qbSig, // [OUT] translated signature
+ 0, // start from first byte of the signature
+ 0, // don't care how many bytes consumed
+ &cbEmit) ); // number of bytes write to cbEmit
+
+ hr = ImportHelper::FindProperty(
+ pMiniMdEmit,
+ tdEmit,
+ szName,
+ (PCCOR_SIGNATURE) qbSig.Ptr(),
+ cbEmit,
+ &prEmit);
+
+ bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck ||
+ ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport,
+ prImp, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+ if (bSuppressMergeCheck)
+ {
+ if (hr == S_OK)
+ {
+ // Good. We found the matching property when we have a duplicate typedef
+ IfFailGo( pCurTkMap->InsertNotFound(prImp, true, prEmit, &pTokenRec) );
+ }
+ else
+ {
+ IfFailGo(pMiniMdEmit->AddPropertyRecord(&pRecEmit, (RID *)&prEmit));
+
+ // copy the property record over
+ IfFailGo( CopyProperty(pImportData, pRecImport, pRecEmit) );
+
+ // Add Property to the PropertyMap.
+ IfFailGo( pMiniMdEmit->AddPropertyToPropertyMap(ridPropertyMapEmit, prEmit) );
+
+ // record the token movement
+ prEmit = TokenFromRid(prEmit, mdtProperty);
+
+ IfFailGo( pCurTkMap->InsertNotFound(prImp, false, prEmit, &pTokenRec) );
+
+ // copy over the method semantics
+ IfFailGo( CopyMethodSemantics(pImportData, prImp, prEmit) );
+ }
+ }
+ else
+ {
+ if (hr == S_OK)
+ {
+ // Good. We found the matching property when we have a duplicate typedef
+ IfFailGo( pCurTkMap->InsertNotFound(prImp, true, prEmit, &pTokenRec) );
+ }
+ else
+ {
+ hr = S_OK; // discard old error; new error will be returned from CheckContinuableError
+ CheckContinuableErrorEx(META_E_PROP_NOT_FOUND, pImportData, prImp);
+ }
+
+ cImport++;
+ }
+ }
+
+ // The counts should be the same, unless this is <module>
+ if (cImport != pMTD->m_cProperties && tdImport != pImportData->m_pRegMetaImport->m_tdModule)
+ {
+ CheckContinuableErrorEx(META_E_PROPERTY_COUNTS, pImportData, tdImport);
+ // If we are here, the linker says this error is OK.
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::VerifyProperties()
+
+
+//*****************************************************************************
+// Verify Parameters given a Method
+//*****************************************************************************
+HRESULT NEWMERGER::VerifyParams(
+ MergeImportData *pImportData,
+ mdMethodDef mdImport,
+ mdMethodDef mdEmit)
+{
+ HRESULT hr = NOERROR;
+ ParamRec *pRecImport = NULL;
+ ParamRec *pRecEmit = NULL;
+ MethodRec *pMethodRec;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG ridStart, ridEnd;
+ ULONG ridStartEmit, ridEndEmit;
+ ULONG cImport, cEmit;
+ ULONG i, j;
+ mdParamDef pdEmit = 0;
+ mdParamDef pdImp;
+ TOKENREC *pTokenRec;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // Get count of params in import scope; prepare to enumerate.
+ IfFailGo(pMiniMdImport->GetMethodRecord(RidFromToken(mdImport), &pMethodRec));
+ ridStart = pMiniMdImport->getParamListOfMethod(pMethodRec);
+ IfFailGo(pMiniMdImport->getEndParamListOfMethod(RidFromToken(mdImport), &ridEnd));
+ cImport = ridEnd - ridStart;
+
+ // Get count of params in emit scope; prepare to enumerate.
+ IfFailGo(pMiniMdEmit->GetMethodRecord(RidFromToken(mdEmit), &pMethodRec));
+ ridStartEmit = pMiniMdEmit->getParamListOfMethod(pMethodRec);
+ IfFailGo(pMiniMdEmit->getEndParamListOfMethod(RidFromToken(mdEmit), &ridEndEmit));
+ cEmit = ridEndEmit - ridStartEmit;
+
+ // The counts should be the same.
+ if (cImport != cEmit)
+ {
+ // That is, unless this is <module>, so get the method's parent.
+ mdTypeDef tdImport;
+ IfFailGo(pMiniMdImport->FindParentOfMethodHelper(mdImport, &tdImport));
+ if (tdImport != pImportData->m_pRegMetaImport->m_tdModule)
+ CheckContinuableErrorEx(META_E_PARAM_COUNTS, pImportData, mdImport);
+ // If we are here, the linker says this error is OK.
+ }
+
+ // loop through all Parameters
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ // Get the importing param row
+ IfFailGo(pMiniMdImport->GetParamRid(i, (ULONG *)&pdImp));
+
+ // only verify those Params that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsParamMarked(TokenFromRid(pdImp, mdtParamDef)) == false)
+ continue;
+
+
+ IfFailGo(pMiniMdImport->GetParamRecord(pdImp, &pRecImport));
+ pdImp = TokenFromRid(pdImp, mdtParamDef);
+
+ // It turns out when we merge a typelib with itself, the emit and import scope
+ // has different sequence of parameter
+ //
+ // find the corresponding emit param row
+ for (j = ridStartEmit; j < ridEndEmit; j++)
+ {
+ IfFailGo(pMiniMdEmit->GetParamRid(j, (ULONG *)&pdEmit));
+ IfFailGo(pMiniMdEmit->GetParamRecord(pdEmit, &pRecEmit));
+ if (pRecEmit->GetSequence() == pRecImport->GetSequence())
+ break;
+ }
+
+ if (j == ridEndEmit)
+ {
+ // did not find the corresponding parameter in the emiting scope
+ hr = S_OK; // discard old error; new error will be returned from CheckContinuableError
+ CheckContinuableErrorEx(META_S_PARAM_MISMATCH, pImportData, pdImp);
+ }
+
+ else
+ {
+ _ASSERTE( pRecEmit->GetSequence() == pRecImport->GetSequence() );
+
+ pdEmit = TokenFromRid(pdEmit, mdtParamDef);
+
+ // record the token movement
+#ifdef WE_DONT_NEED_TO_CHECK_NAMES__THEY_DONT_AFFECT_ANYTHING
+ LPCUTF8 szNameImp;
+ LPCUTF8 szNameEmit;
+ IfFailGo(pMiniMdImport->getNameOfParam(pRecImport, &szNameImp));
+ IfFailGo(pMiniMdEmit->getNameOfParam(pRecEmit, &szNameEmit));
+ if (szNameImp && szNameEmit && strcmp(szNameImp, szNameEmit) != 0)
+ {
+ // parameter name doesn't match
+ CheckContinuableErrorEx(META_S_PARAM_MISMATCH, pImportData, pdImp);
+ }
+#endif
+ if (pRecEmit->GetFlags() != pRecImport->GetFlags())
+ {
+ // flags doesn't match
+ CheckContinuableErrorEx(META_S_PARAM_MISMATCH, pImportData, pdImp);
+ }
+
+ // record token movement. This is a duplicate.
+ IfFailGo( pCurTkMap->InsertNotFound(pdImp, true, pdEmit, &pTokenRec) );
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::VerifyParams()
+
+
+//*****************************************************************************
+// merging MemberRef
+//*****************************************************************************
+HRESULT NEWMERGER::MergeMemberRefs( )
+{
+ HRESULT hr = NOERROR;
+ MemberRefRec *pRecImport = NULL;
+ MemberRefRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ mdMemberRef mrEmit;
+ mdMemberRef mrImp;
+ bool bDuplicate = false;
+ TOKENREC *pTokenRec;
+ mdToken tkParentImp;
+ mdToken tkParentEmit;
+
+ LPCUTF8 szNameImp;
+ PCCOR_SIGNATURE pbSig;
+ ULONG cbSig;
+ ULONG cbEmit;
+ CQuickBytes qbSig;
+
+ bool isRefOptimizedToDef;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ iCount = pMiniMdImport->getCountMemberRefs();
+
+ // loop through all MemberRef
+ for (i = 1; i <= iCount; i++)
+ {
+
+ // only merge those MemberRefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsMemberRefMarked(TokenFromRid(i, mdtMemberRef)) == false)
+ continue;
+
+ isRefOptimizedToDef = false;
+
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetMemberRefRecord(i, &pRecImport));
+ IfFailGo(pMiniMdImport->getNameOfMemberRef(pRecImport, &szNameImp));
+ IfFailGo(pMiniMdImport->getSignatureOfMemberRef(pRecImport, &pbSig, &cbSig));
+ tkParentImp = pMiniMdImport->getClassOfMemberRef(pRecImport);
+
+ IfFailGo( pCurTkMap->Remap(tkParentImp, &tkParentEmit) );
+
+ // convert rid contained in signature to new scope
+ IfFailGo(ImportHelper::MergeUpdateTokenInSig(
+ NULL, // Assembly emit scope.
+ pMiniMdEmit, // The emit scope.
+ NULL, NULL, 0, // Import assembly information.
+ pMiniMdImport, // The scope to merge into the emit scope.
+ pbSig, // signature from the imported scope
+ pCurTkMap, // Internal token mapping structure.
+ &qbSig, // [OUT] translated signature
+ 0, // start from first byte of the signature
+ 0, // don't care how many bytes consumed
+ &cbEmit)); // number of bytes write to cbEmit
+
+ // We want to know if we can optimize this MemberRef to a FieldDef or MethodDef
+ if (TypeFromToken(tkParentEmit) == mdtTypeDef && RidFromToken(tkParentEmit) != 0)
+ {
+ // The parent of this MemberRef has been successfully optimized to a TypeDef. Then this MemberRef should be
+ // be able to optimized to a MethodDef or FieldDef unless one of the parent in the inheritance hierachy
+ // is through TypeRef. Then this MemberRef stay as MemberRef. If This is a VarArg calling convention, then
+ // we will remap the MemberRef's parent to a MethodDef or stay as TypeRef.
+ //
+ mdToken tkParent = tkParentEmit;
+ mdToken tkMethDefOrFieldDef;
+ PCCOR_SIGNATURE pbSigTmp = (const COR_SIGNATURE *) qbSig.Ptr();
+
+ while (TypeFromToken(tkParent) == mdtTypeDef && RidFromToken(tkParent) != 0)
+ {
+ TypeDefRec *pRec;
+ hr = ImportHelper::FindMember(pMiniMdEmit, tkParent, szNameImp, pbSigTmp, cbEmit, &tkMethDefOrFieldDef);
+ if (hr == S_OK)
+ {
+ // We have found a match!!
+ if (isCallConv(CorSigUncompressCallingConv(pbSigTmp), IMAGE_CEE_CS_CALLCONV_VARARG))
+ {
+ // The found MethodDef token will replace this MemberRef's parent token
+ _ASSERTE(TypeFromToken(tkMethDefOrFieldDef) == mdtMethodDef);
+ tkParentEmit = tkMethDefOrFieldDef;
+ break;
+ }
+ else
+ {
+ // The found MethodDef/FieldDef token will replace this MemberRef token and we won't introduce a MemberRef
+ // record.
+ //
+ mrEmit = tkMethDefOrFieldDef;
+ isRefOptimizedToDef = true;
+ bDuplicate = true;
+ break;
+ }
+ }
+
+ // now walk up to the parent class of tkParent and try to resolve this MemberRef
+ IfFailGo(pMiniMdEmit->GetTypeDefRecord(RidFromToken(tkParent), &pRec));
+ tkParent = pMiniMdEmit->getExtendsOfTypeDef(pRec);
+ }
+
+ // When we exit the loop, there are several possibilities:
+ // 1. We found a MethodDef/FieldDef to replace the MemberRef
+ // 2. We found a MethodDef matches the MemberRef but the MemberRef is VarArg, thus we want to use the MethodDef in the
+ // parent column but not replacing it.
+ // 3. We exit because we run out the TypeDef on the parent chain. If it is because we encounter a TypeRef, this TypeRef will
+ // replace the parent column of the MemberRef. Or we encounter nil token! (This can be unresolved global MemberRef or
+ // compiler error to put an undefined MemberRef. In this case, we should just use the old tkParentEmit
+ // on the parent column for the MemberRef.
+
+ if (TypeFromToken(tkParent) == mdtTypeRef && RidFromToken(tkParent) != 0)
+ {
+ // we had walked up the parent's chain to resolve it but we have not been successful and got stopped by a TypeRef.
+ // Then we will use this TypeRef as the parent of the emit MemberRef record
+ //
+ tkParentEmit = tkParent;
+ }
+ }
+ else if ((TypeFromToken(tkParentEmit) == mdtMethodDef &&
+ !isCallConv(CorSigUncompressCallingConv(pbSig), IMAGE_CEE_CS_CALLCONV_VARARG)) ||
+ (TypeFromToken(tkParentEmit) == mdtFieldDef))
+ {
+ // If the MemberRef's parent is already a non-vararg MethodDef or FieldDef, we can also
+ // safely drop the MemberRef
+ mrEmit = tkParentEmit;
+ isRefOptimizedToDef = true;
+ bDuplicate = true;
+ }
+
+ // If the Ref cannot be optimized to a Def or MemberRef to Def optmization is turned off, do the following.
+ if (isRefOptimizedToDef == false || !((m_optimizeRefToDef & MDMemberRefToDef) == MDMemberRefToDef))
+ {
+ // does this MemberRef already exist in the emit scope?
+ if ( m_fDupCheck && ImportHelper::FindMemberRef(
+ pMiniMdEmit,
+ tkParentEmit,
+ szNameImp,
+ (const COR_SIGNATURE *) qbSig.Ptr(),
+ cbEmit,
+ &mrEmit) == S_OK )
+ {
+ // Yes, it does
+ bDuplicate = true;
+ }
+ else
+ {
+ // No, it doesn't. Copy it over.
+ bDuplicate = false;
+ IfFailGo(pMiniMdEmit->AddMemberRefRecord(&pRecEmit, (RID *)&mrEmit));
+ mrEmit = TokenFromRid( mrEmit, mdtMemberRef );
+
+ // Copy over the MemberRef context
+ IfFailGo(pMiniMdEmit->PutString(TBL_MemberRef, MemberRefRec::COL_Name, pRecEmit, szNameImp));
+ IfFailGo(pMiniMdEmit->PutToken(TBL_MemberRef, MemberRefRec::COL_Class, pRecEmit, tkParentEmit));
+ IfFailGo(pMiniMdEmit->PutBlob(TBL_MemberRef, MemberRefRec::COL_Signature, pRecEmit,
+ qbSig.Ptr(), cbEmit));
+ IfFailGo(pMiniMdEmit->AddMemberRefToHash(mrEmit) );
+ }
+ }
+ // record the token movement
+ mrImp = TokenFromRid(i, mdtMemberRef);
+ IfFailGo( pCurTkMap->InsertNotFound(mrImp, bDuplicate, mrEmit, &pTokenRec) );
+ }
+ }
+
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeMemberRefs()
+
+
+//*****************************************************************************
+// merge interface impl
+//*****************************************************************************
+HRESULT NEWMERGER::MergeInterfaceImpls( )
+{
+ HRESULT hr = NOERROR;
+ InterfaceImplRec *pRecImport = NULL;
+ InterfaceImplRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ mdTypeDef tkParent;
+ mdInterfaceImpl iiEmit;
+ bool bDuplicate;
+ TOKENREC *pTokenRec;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountInterfaceImpls();
+
+ // loop through all InterfaceImpl
+ for (i = 1; i <= iCount; i++)
+ {
+ // only merge those InterfaceImpls that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsInterfaceImplMarked(TokenFromRid(i, mdtInterfaceImpl)) == false)
+ continue;
+
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetInterfaceImplRecord(i, &pRecImport));
+ tkParent = pMiniMdImport->getClassOfInterfaceImpl(pRecImport);
+
+ // does this TypeRef already exist in the emit scope?
+ if ( pCurTkMap->Find(tkParent, &pTokenRec) )
+ {
+ if ( pTokenRec->m_isDuplicate )
+ {
+ // parent in the emit scope
+ mdToken tkParentEmit;
+ mdToken tkInterface;
+
+ // remap the typedef token
+ tkParentEmit = pTokenRec->m_tkTo;
+
+ // remap the implemented interface token
+ tkInterface = pMiniMdImport->getInterfaceOfInterfaceImpl(pRecImport);
+ IfFailGo( pCurTkMap->Remap( tkInterface, &tkInterface) );
+
+ // Set duplicate flag
+ bDuplicate = true;
+
+ // find the corresponding interfaceimpl in the emit scope
+ if ( ImportHelper::FindInterfaceImpl(pMiniMdEmit, tkParentEmit, tkInterface, &iiEmit) != S_OK )
+ {
+ // bad state!! We have a duplicate typedef but the interface impl is not the same!!
+
+ // continuable error
+ CheckContinuableErrorEx(
+ META_E_INTFCEIMPL_NOT_FOUND,
+ pImportData,
+ TokenFromRid(i, mdtInterfaceImpl));
+
+ iiEmit = mdTokenNil;
+ }
+ }
+ else
+ {
+ // No, it doesn't. Copy it over.
+ bDuplicate = false;
+ IfFailGo(pMiniMdEmit->AddInterfaceImplRecord(&pRecEmit, (RID *)&iiEmit));
+
+ // copy the interfaceimp record over
+ IfFailGo( CopyInterfaceImpl( pRecEmit, pImportData, pRecImport) );
+ }
+ }
+ else
+ {
+ _ASSERTE( !"bad state!");
+ IfFailGo( META_E_BADMETADATA );
+ }
+
+ // record the token movement
+ IfFailGo( pCurTkMap->InsertNotFound(
+ TokenFromRid(i, mdtInterfaceImpl),
+ bDuplicate,
+ TokenFromRid( iiEmit, mdtInterfaceImpl ),
+ &pTokenRec) );
+ }
+ }
+
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeInterfaceImpls()
+
+
+//*****************************************************************************
+// merge all of the constant for field, property, and parameter
+//*****************************************************************************
+HRESULT NEWMERGER::MergeConstants()
+{
+ HRESULT hr = NOERROR;
+ ConstantRec *pRecImport = NULL;
+ ConstantRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ ULONG csEmit; // constant value is not a token
+ mdToken tkParentImp;
+ TOKENREC *pTokenRec;
+ void const *pValue;
+ ULONG cbBlob;
+#if _DEBUG
+ ULONG typeParent;
+#endif // _DEBUG
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountConstants();
+
+ // loop through all Constants
+ for (i = 1; i <= iCount; i++)
+ {
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetConstantRecord(i, &pRecImport));
+ tkParentImp = pMiniMdImport->getParentOfConstant(pRecImport);
+
+ // only move those constant over if their parents are marked
+ // If MDTOKENMAP::Find returns false, we don't need to copy the constant value over
+ if ( pCurTkMap->Find(tkParentImp, &pTokenRec) )
+ {
+ // If the parent is duplicated, no need to move over the constant value
+ if ( !pTokenRec->m_isDuplicate )
+ {
+ IfFailGo(pMiniMdEmit->AddConstantRecord(&pRecEmit, &csEmit));
+ pRecEmit->SetType(pRecImport->GetType());
+
+ // set the parent
+ IfFailGo( pMiniMdEmit->PutToken(TBL_Constant, ConstantRec::COL_Parent, pRecEmit, pTokenRec->m_tkTo) );
+
+ // move over the constant blob value
+ IfFailGo(pMiniMdImport->getValueOfConstant(pRecImport, (const BYTE **)&pValue, &cbBlob));
+ IfFailGo( pMiniMdEmit->PutBlob(TBL_Constant, ConstantRec::COL_Value, pRecEmit, pValue, cbBlob) );
+ IfFailGo( pMiniMdEmit->AddConstantToHash(csEmit) );
+ }
+ else
+ {
+ // <TODO>@FUTURE: more verification on the duplicate??</TODO>
+ }
+ }
+#if _DEBUG
+ // Include this block only under Debug build. The reason is that
+ // the linker chooses all the errors that we report (such as unmatched MethodDef or FieldDef)
+ // as a continuable error. It is likely to hit this else while the tkparentImp is marked if there
+ // is any error reported earlier!!
+ else
+ {
+ typeParent = TypeFromToken(tkParentImp);
+ if (typeParent == mdtFieldDef)
+ {
+ // FieldDef should not be marked.
+ if ( pMiniMdImport->GetFilterTable()->IsFieldMarked(tkParentImp) == false)
+ continue;
+ }
+ else if (typeParent == mdtParamDef)
+ {
+ // ParamDef should not be marked.
+ if ( pMiniMdImport->GetFilterTable()->IsParamMarked(tkParentImp) == false)
+ continue;
+ }
+ else
+ {
+ _ASSERTE(typeParent == mdtProperty);
+ // Property should not be marked.
+ if ( pMiniMdImport->GetFilterTable()->IsPropertyMarked(tkParentImp) == false)
+ continue;
+ }
+
+ // If we come to here, we have a constant whose parent is marked but we could not
+ // find it in the map!! Bad state.
+
+ _ASSERTE(!"Ignore this error if you have seen error reported earlier! Otherwise bad token map or bad metadata!");
+ }
+#endif // _DEBUG
+ // Note that we don't need to record the token movement since constant is not a valid token kind.
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeConstants()
+
+
+//*****************************************************************************
+// Merge field marshal information
+//*****************************************************************************
+HRESULT NEWMERGER::MergeFieldMarshals()
+{
+ HRESULT hr = NOERROR;
+ FieldMarshalRec *pRecImport = NULL;
+ FieldMarshalRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ ULONG fmEmit; // FieldMarhsal is not a token
+ mdToken tkParentImp;
+ TOKENREC *pTokenRec;
+ void const *pValue;
+ ULONG cbBlob;
+#if _DEBUG
+ ULONG typeParent;
+#endif // _DEBUG
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountFieldMarshals();
+
+ // loop through all TypeRef
+ for (i = 1; i <= iCount; i++)
+ {
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetFieldMarshalRecord(i, &pRecImport));
+ tkParentImp = pMiniMdImport->getParentOfFieldMarshal(pRecImport);
+
+ // We want to merge only those field marshals that parents are marked.
+ // Find will return false if the parent is not marked
+ //
+ if ( pCurTkMap->Find(tkParentImp, &pTokenRec) )
+ {
+ // If the parent is duplicated, no need to move over the constant value
+ if ( !pTokenRec->m_isDuplicate )
+ {
+ IfFailGo(pMiniMdEmit->AddFieldMarshalRecord(&pRecEmit, &fmEmit));
+
+ // set the parent
+ IfFailGo( pMiniMdEmit->PutToken(
+ TBL_FieldMarshal,
+ FieldMarshalRec::COL_Parent,
+ pRecEmit,
+ pTokenRec->m_tkTo) );
+
+ // move over the constant blob value
+ IfFailGo(pMiniMdImport->getNativeTypeOfFieldMarshal(pRecImport, (const BYTE **)&pValue, &cbBlob));
+ IfFailGo( pMiniMdEmit->PutBlob(TBL_FieldMarshal, FieldMarshalRec::COL_NativeType, pRecEmit, pValue, cbBlob) );
+ IfFailGo( pMiniMdEmit->AddFieldMarshalToHash(fmEmit) );
+
+ }
+ else
+ {
+ // <TODO>@FUTURE: more verification on the duplicate??</TODO>
+ }
+ }
+#if _DEBUG
+ else
+ {
+ typeParent = TypeFromToken(tkParentImp);
+
+ if (typeParent == mdtFieldDef)
+ {
+ // FieldDefs should not be marked
+ if ( pMiniMdImport->GetFilterTable()->IsFieldMarked(tkParentImp) == false)
+ continue;
+ }
+ else
+ {
+ _ASSERTE(typeParent == mdtParamDef);
+ // ParamDefs should not be marked
+ if ( pMiniMdImport->GetFilterTable()->IsParamMarked(tkParentImp) == false)
+ continue;
+ }
+
+ // If we come to here, that is we have a FieldMarshal whose parent is marked and we don't find it
+ // in the map!!!
+
+ // either bad lookup map or bad metadata
+ _ASSERTE(!"Ignore this assert if you have seen error reported earlier. Otherwise, it is bad state!");
+ }
+#endif // _DEBUG
+ }
+ // Note that we don't need to record the token movement since FieldMarshal is not a valid token kind.
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeFieldMarshals()
+
+
+//*****************************************************************************
+// Merge class layout information
+//*****************************************************************************
+HRESULT NEWMERGER::MergeClassLayouts()
+{
+ HRESULT hr = NOERROR;
+ ClassLayoutRec *pRecImport = NULL;
+ ClassLayoutRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ ULONG iRecord; // class layout is not a token
+ mdToken tkParentImp;
+ TOKENREC *pTokenRec;
+ RID ridClassLayout;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountClassLayouts();
+
+ // loop through all TypeRef
+ for (i = 1; i <= iCount; i++)
+ {
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetClassLayoutRecord(i, &pRecImport));
+ tkParentImp = pMiniMdImport->getParentOfClassLayout(pRecImport);
+
+ // only merge those TypeDefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsTypeDefMarked(tkParentImp) == false)
+ continue;
+
+ if ( pCurTkMap->Find(tkParentImp, &pTokenRec) )
+ {
+ if ( !pTokenRec->m_isDuplicate )
+ {
+ // If the parent is not duplicated, just copy over the classlayout information
+ IfFailGo(pMiniMdEmit->AddClassLayoutRecord(&pRecEmit, &iRecord));
+
+ // copy over the fix part information
+ pRecEmit->Copy(pRecImport);
+ IfFailGo( pMiniMdEmit->PutToken(TBL_ClassLayout, ClassLayoutRec::COL_Parent, pRecEmit, pTokenRec->m_tkTo));
+ IfFailGo( pMiniMdEmit->AddClassLayoutToHash(iRecord) );
+ }
+ else
+ {
+
+ IfFailGo(pMiniMdEmit->FindClassLayoutHelper(pTokenRec->m_tkTo, &ridClassLayout));
+
+ if (InvalidRid(ridClassLayout))
+ {
+ // class is duplicated but not class layout info
+ CheckContinuableErrorEx(META_E_CLASS_LAYOUT_INCONSISTENT, pImportData, tkParentImp);
+ }
+ else
+ {
+ IfFailGo(pMiniMdEmit->GetClassLayoutRecord(RidFromToken(ridClassLayout), &pRecEmit));
+ if (pMiniMdImport->getPackingSizeOfClassLayout(pRecImport) != pMiniMdEmit->getPackingSizeOfClassLayout(pRecEmit) ||
+ pMiniMdImport->getClassSizeOfClassLayout(pRecImport) != pMiniMdEmit->getClassSizeOfClassLayout(pRecEmit) )
+ {
+ CheckContinuableErrorEx(META_E_CLASS_LAYOUT_INCONSISTENT, pImportData, tkParentImp);
+ }
+ }
+ }
+ }
+ else
+ {
+ // bad lookup map
+ _ASSERTE( !"bad state!");
+ IfFailGo( META_E_BADMETADATA );
+ }
+ // no need to record the index movement. Classlayout is not a token.
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeClassLayouts()
+
+//*****************************************************************************
+// Merge field layout information
+//*****************************************************************************
+HRESULT NEWMERGER::MergeFieldLayouts()
+{
+ HRESULT hr = NOERROR;
+ FieldLayoutRec *pRecImport = NULL;
+ FieldLayoutRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ ULONG iRecord; // field layout2 is not a token.
+ mdToken tkFieldImp;
+ TOKENREC *pTokenRec;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountFieldLayouts();
+
+ // loop through all FieldLayout records.
+ for (i = 1; i <= iCount; i++)
+ {
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetFieldLayoutRecord(i, &pRecImport));
+ tkFieldImp = pMiniMdImport->getFieldOfFieldLayout(pRecImport);
+
+ // only merge those FieldDefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsFieldMarked(tkFieldImp) == false)
+ continue;
+
+ if ( pCurTkMap->Find(tkFieldImp, &pTokenRec) )
+ {
+ if ( !pTokenRec->m_isDuplicate )
+ {
+ // If the Field is not duplicated, just copy over the FieldLayout information
+ IfFailGo(pMiniMdEmit->AddFieldLayoutRecord(&pRecEmit, &iRecord));
+
+ // copy over the fix part information
+ pRecEmit->Copy(pRecImport);
+ IfFailGo( pMiniMdEmit->PutToken(TBL_FieldLayout, FieldLayoutRec::COL_Field, pRecEmit, pTokenRec->m_tkTo));
+ IfFailGo( pMiniMdEmit->AddFieldLayoutToHash(iRecord) );
+ }
+ else
+ {
+ // <TODO>@FUTURE: more verification??</TODO>
+ }
+ }
+ else
+ {
+ // bad lookup map
+ _ASSERTE( !"bad state!");
+ IfFailGo( META_E_BADMETADATA );
+ }
+ // no need to record the index movement. fieldlayout2 is not a token.
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeFieldLayouts()
+
+
+//*****************************************************************************
+// Merge field RVAs
+//*****************************************************************************
+HRESULT NEWMERGER::MergeFieldRVAs()
+{
+ HRESULT hr = NOERROR;
+ FieldRVARec *pRecImport = NULL;
+ FieldRVARec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ ULONG iRecord; // FieldRVA is not a token.
+ mdToken tkFieldImp;
+ TOKENREC *pTokenRec;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountFieldRVAs();
+
+ // loop through all FieldRVA records.
+ for (i = 1; i <= iCount; i++)
+ {
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetFieldRVARecord(i, &pRecImport));
+ tkFieldImp = pMiniMdImport->getFieldOfFieldRVA(pRecImport);
+
+ // only merge those FieldDefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsFieldMarked(TokenFromRid(tkFieldImp, mdtFieldDef)) == false)
+ continue;
+
+ if ( pCurTkMap->Find(tkFieldImp, &pTokenRec) )
+ {
+ if ( !pTokenRec->m_isDuplicate )
+ {
+ // If the Field is not duplicated, just copy over the FieldRVA information
+ IfFailGo(pMiniMdEmit->AddFieldRVARecord(&pRecEmit, &iRecord));
+
+ // copy over the fix part information
+ pRecEmit->Copy(pRecImport);
+ IfFailGo( pMiniMdEmit->PutToken(TBL_FieldRVA, FieldRVARec::COL_Field, pRecEmit, pTokenRec->m_tkTo));
+ IfFailGo( pMiniMdEmit->AddFieldRVAToHash(iRecord) );
+ }
+ else
+ {
+ // <TODO>@FUTURE: more verification??</TODO>
+ }
+ }
+ else
+ {
+ // bad lookup map
+ _ASSERTE( !"bad state!");
+ IfFailGo( META_E_BADMETADATA );
+ }
+ // no need to record the index movement. FieldRVA is not a token.
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeFieldRVAs()
+
+
+//*****************************************************************************
+// Merge MethodImpl information
+//*****************************************************************************
+HRESULT NEWMERGER::MergeMethodImpls()
+{
+ HRESULT hr = NOERROR;
+ MethodImplRec *pRecImport = NULL;
+ MethodImplRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ RID iRecord;
+ mdTypeDef tkClassImp;
+ mdToken tkBodyImp;
+ mdToken tkDeclImp;
+ TOKENREC *pTokenRecClass;
+ mdToken tkBodyEmit;
+ mdToken tkDeclEmit;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountMethodImpls();
+
+ // loop through all the MethodImpls.
+ for (i = 1; i <= iCount; i++)
+ {
+ // only merge those MethodImpls that are marked.
+ if ( pMiniMdImport->GetFilterTable()->IsMethodImplMarked(i) == false)
+ continue;
+
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetMethodImplRecord(i, &pRecImport));
+ tkClassImp = pMiniMdImport->getClassOfMethodImpl(pRecImport);
+ tkBodyImp = pMiniMdImport->getMethodBodyOfMethodImpl(pRecImport);
+ tkDeclImp = pMiniMdImport->getMethodDeclarationOfMethodImpl(pRecImport);
+
+ if ( pCurTkMap->Find(tkClassImp, &pTokenRecClass))
+ {
+ // If the TypeDef is duplicated, no need to move over the MethodImpl record.
+ if ( !pTokenRecClass->m_isDuplicate )
+ {
+ // Create a new record and set the data.
+
+ // <TODO>@FUTURE: We might want to consider changing the error for the remap into a continuable error.
+ // Because we probably can continue merging for more data...</TODO>
+
+ IfFailGo( pCurTkMap->Remap(tkBodyImp, &tkBodyEmit) );
+ IfFailGo( pCurTkMap->Remap(tkDeclImp, &tkDeclEmit) );
+ IfFailGo(pMiniMdEmit->AddMethodImplRecord(&pRecEmit, &iRecord));
+ IfFailGo( pMiniMdEmit->PutToken(TBL_MethodImpl, MethodImplRec::COL_Class, pRecEmit, pTokenRecClass->m_tkTo) );
+ IfFailGo( pMiniMdEmit->PutToken(TBL_MethodImpl, MethodImplRec::COL_MethodBody, pRecEmit, tkBodyEmit) );
+ IfFailGo( pMiniMdEmit->PutToken(TBL_MethodImpl, MethodImplRec::COL_MethodDeclaration, pRecEmit, tkDeclEmit) );
+ IfFailGo( pMiniMdEmit->AddMethodImplToHash(iRecord) );
+ }
+ else
+ {
+ // <TODO>@FUTURE: more verification on the duplicate??</TODO>
+ }
+ // No need to record the token movement, MethodImpl is not a token.
+ }
+ else
+ {
+ // either bad lookup map or bad metadata
+ _ASSERTE(!"bad state");
+ IfFailGo( META_E_BADMETADATA );
+ }
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeMethodImpls()
+
+
+//*****************************************************************************
+// Merge PInvoke
+//*****************************************************************************
+HRESULT NEWMERGER::MergePinvoke()
+{
+ HRESULT hr = NOERROR;
+ ImplMapRec *pRecImport = NULL;
+ ImplMapRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ mdModuleRef mrImp;
+ mdModuleRef mrEmit;
+ mdMethodDef mdImp;
+ RID mdImplMap;
+ TOKENREC *pTokenRecMR;
+ TOKENREC *pTokenRecMD;
+
+ USHORT usMappingFlags;
+ LPCUTF8 szImportName;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountImplMaps();
+
+ // loop through all ImplMaps
+ for (i = 1; i <= iCount; i++)
+ {
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetImplMapRecord(i, &pRecImport));
+
+ // Get the MethodDef token in the new space.
+ mdImp = pMiniMdImport->getMemberForwardedOfImplMap(pRecImport);
+
+ // only merge those MethodDefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsMethodMarked(mdImp) == false)
+ continue;
+
+ // Get the ModuleRef token in the new space.
+ mrImp = pMiniMdImport->getImportScopeOfImplMap(pRecImport);
+
+ // map the token to the new scope
+ if (pCurTkMap->Find(mrImp, &pTokenRecMR) == false)
+ {
+ // This should never fire unless the module refs weren't merged
+ // before this code ran.
+ _ASSERTE(!"Parent ModuleRef not found in MERGER::MergePinvoke. Bad state!");
+ IfFailGo( META_E_BADMETADATA );
+ }
+
+ // If the ModuleRef has been remapped to the "module token", we need to undo that
+ // for the pinvokeimpl. A pinvoke can only have a ModuleRef for the ImportScope.
+ mrEmit = pTokenRecMR->m_tkTo;
+ if (mrEmit == MODULEDEFTOKEN)
+ { // Yes, the ModuleRef has been remapped to the module token. So,
+ // find the ModuleRef in the output scope; if it is not found, add
+ // it.
+ ModuleRefRec *pModRefImport;
+ LPCUTF8 szNameImp;
+ IfFailGo(pMiniMdImport->GetModuleRefRecord(RidFromToken(mrImp), &pModRefImport));
+ IfFailGo(pMiniMdImport->getNameOfModuleRef(pModRefImport, &szNameImp));
+
+ // does this ModuleRef already exist in the emit scope?
+ hr = ImportHelper::FindModuleRef(pMiniMdEmit,
+ szNameImp,
+ &mrEmit);
+
+ if (hr == CLDB_E_RECORD_NOTFOUND)
+ { // No, it doesn't. Copy it over.
+ ModuleRefRec *pModRefEmit;
+ IfFailGo(pMiniMdEmit->AddModuleRefRecord(&pModRefEmit, (RID*)&mrEmit));
+ mrEmit = TokenFromRid(mrEmit, mdtModuleRef);
+
+ // Set ModuleRef Name.
+ IfFailGo( pMiniMdEmit->PutString(TBL_ModuleRef, ModuleRefRec::COL_Name, pModRefEmit, szNameImp) );
+ }
+ else
+ IfFailGo(hr);
+ }
+
+
+ if (pCurTkMap->Find(mdImp, &pTokenRecMD) == false)
+ {
+ // This should never fire unless the method defs weren't merged
+ // before this code ran.
+ _ASSERTE(!"Parent MethodDef not found in MERGER::MergePinvoke. Bad state!");
+ IfFailGo( META_E_BADMETADATA );
+ }
+
+
+ // Get copy of rest of data.
+ usMappingFlags = pMiniMdImport->getMappingFlagsOfImplMap(pRecImport);
+ IfFailGo(pMiniMdImport->getImportNameOfImplMap(pRecImport, &szImportName));
+
+ // If the method associated with PInvokeMap is not duplicated, then don't bother to look up the
+ // duplicated PInvokeMap information.
+ if (pTokenRecMD->m_isDuplicate == true)
+ {
+ // Does the correct ImplMap entry exist in the emit scope?
+ IfFailGo(pMiniMdEmit->FindImplMapHelper(pTokenRecMD->m_tkTo, &mdImplMap));
+ }
+ else
+ {
+ mdImplMap = mdTokenNil;
+ }
+ if (!InvalidRid(mdImplMap))
+ {
+ // Verify that the rest of the data is identical, else it's an error.
+ IfFailGo(pMiniMdEmit->GetImplMapRecord(mdImplMap, &pRecEmit));
+ _ASSERTE(pMiniMdEmit->getMemberForwardedOfImplMap(pRecEmit) == pTokenRecMD->m_tkTo);
+ LPCSTR szImplMapImportName;
+ IfFailGo(pMiniMdEmit->getImportNameOfImplMap(pRecEmit, &szImplMapImportName));
+ if (pMiniMdEmit->getImportScopeOfImplMap(pRecEmit) != mrEmit ||
+ pMiniMdEmit->getMappingFlagsOfImplMap(pRecEmit) != usMappingFlags ||
+ strcmp(szImplMapImportName, szImportName))
+ {
+ // Mismatched p-invoke entries are found.
+ _ASSERTE(!"Mismatched P-invoke entries during merge. Bad State!");
+ IfFailGo(E_FAIL);
+ }
+ }
+ else
+ {
+ IfFailGo(pMiniMdEmit->AddImplMapRecord(&pRecEmit, &mdImplMap));
+
+ // Copy rest of data.
+ IfFailGo( pMiniMdEmit->PutToken(TBL_ImplMap, ImplMapRec::COL_MemberForwarded, pRecEmit, pTokenRecMD->m_tkTo) );
+ IfFailGo( pMiniMdEmit->PutToken(TBL_ImplMap, ImplMapRec::COL_ImportScope, pRecEmit, mrEmit) );
+ IfFailGo( pMiniMdEmit->PutString(TBL_ImplMap, ImplMapRec::COL_ImportName, pRecEmit, szImportName) );
+ pRecEmit->SetMappingFlags(usMappingFlags);
+ IfFailGo( pMiniMdEmit->AddImplMapToHash(mdImplMap) );
+ }
+ }
+ }
+
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergePinvoke()
+
+
+//*****************************************************************************
+// Merge StandAloneSigs
+//*****************************************************************************
+HRESULT NEWMERGER::MergeStandAloneSigs()
+{
+ HRESULT hr = NOERROR;
+ StandAloneSigRec *pRecImport = NULL;
+ StandAloneSigRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ TOKENREC *pTokenRec;
+ mdSignature saImp;
+ mdSignature saEmit;
+ bool fDuplicate;
+ PCCOR_SIGNATURE pbSig;
+ ULONG cbSig;
+ ULONG cbEmit;
+ CQuickBytes qbSig;
+ PCOR_SIGNATURE rgSig;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountStandAloneSigs();
+
+ // loop through all Signatures
+ for (i = 1; i <= iCount; i++)
+ {
+ // only merge those Signatures that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsSignatureMarked(TokenFromRid(i, mdtSignature)) == false)
+ continue;
+
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetStandAloneSigRecord(i, &pRecImport));
+ IfFailGo(pMiniMdImport->getSignatureOfStandAloneSig(pRecImport, &pbSig, &cbSig));
+
+ // This is a signature containing the return type after count of args
+ // convert rid contained in signature to new scope
+ IfFailGo(ImportHelper::MergeUpdateTokenInSig(
+ NULL, // Assembly emit scope.
+ pMiniMdEmit, // The emit scope.
+ NULL, NULL, 0, // Assembly import scope info.
+ pMiniMdImport, // The scope to merge into the emit scope.
+ pbSig, // signature from the imported scope
+ pCurTkMap, // Internal token mapping structure.
+ &qbSig, // [OUT] translated signature
+ 0, // start from first byte of the signature
+ 0, // don't care how many bytes consumed
+ &cbEmit)); // number of bytes write to cbEmit
+ rgSig = ( PCOR_SIGNATURE ) qbSig.Ptr();
+
+ hr = ImportHelper::FindStandAloneSig(
+ pMiniMdEmit,
+ rgSig,
+ cbEmit,
+ &saEmit );
+ if ( hr == S_OK )
+ {
+ // find a duplicate
+ fDuplicate = true;
+ }
+ else
+ {
+ // copy over
+ fDuplicate = false;
+ IfFailGo(pMiniMdEmit->AddStandAloneSigRecord(&pRecEmit, (ULONG *)&saEmit));
+ saEmit = TokenFromRid(saEmit, mdtSignature);
+ IfFailGo( pMiniMdEmit->PutBlob(TBL_StandAloneSig, StandAloneSigRec::COL_Signature, pRecEmit, rgSig, cbEmit));
+ }
+ saImp = TokenFromRid(i, mdtSignature);
+
+ // Record the token movement
+ IfFailGo( pCurTkMap->InsertNotFound(saImp, fDuplicate, saEmit, &pTokenRec) );
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeStandAloneSigs()
+
+//*****************************************************************************
+// Merge MethodSpecs
+//*****************************************************************************
+HRESULT NEWMERGER::MergeMethodSpecs()
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ mdToken tk;
+ ULONG iRecord;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // Loop through all MethodSpec
+ iCount = pMiniMdImport->getCountMethodSpecs();
+ for (i=1; i<=iCount; ++i)
+ {
+ MethodSpecRec *pRecImport;
+ MethodSpecRec *pRecEmit;
+ TOKENREC *pTokenRecMethod;
+ TOKENREC *pTokenRecMethodNew;
+ PCCOR_SIGNATURE pvSig;
+ ULONG cbSig;
+ CQuickBytes qbSig;
+ ULONG cbEmit;
+
+ // Only copy marked records.
+ if (!pMiniMdImport->GetFilterTable()->IsMethodSpecMarked(i))
+ continue;
+
+ IfFailGo(pMiniMdImport->GetMethodSpecRecord(i, &pRecImport));
+ tk = pMiniMdImport->getMethodOfMethodSpec(pRecImport);
+
+ // Map the token to the new scope.
+ if (pCurTkMap->Find(tk, &pTokenRecMethod) == false)
+ {
+ // This should never fire unless the TypeDefs/Refs weren't merged
+ // before this code runs.
+ _ASSERTE(!"MethodSpec method not found in MERGER::MergeGenericsInfo. Bad state!");
+ IfFailGo( META_E_BADMETADATA );
+ }
+ // Copy to output scope.
+ IfFailGo(pMiniMdEmit->AddMethodSpecRecord(&pRecEmit, &iRecord));
+ IfFailGo( pMiniMdEmit->PutToken(TBL_MethodSpec, MethodSpecRec::COL_Method, pRecEmit, pTokenRecMethod->m_tkTo));
+
+ // Copy the signature, translating any embedded tokens.
+ IfFailGo(pMiniMdImport->getInstantiationOfMethodSpec(pRecImport, &pvSig, &cbSig));
+
+ // ...convert rid contained in signature to new scope
+ IfFailGo(ImportHelper::MergeUpdateTokenInSig(
+ NULL, // Assembly emit scope.
+ pMiniMdEmit, // The emit scope.
+ NULL, NULL, 0, // Import assembly scope information.
+ pMiniMdImport, // The scope to merge into the emit scope.
+ pvSig, // signature from the imported scope
+ pCurTkMap, // Internal token mapping structure.
+ &qbSig, // [OUT] translated signature
+ 0, // start from first byte of the signature
+ 0, // don't care how many bytes consumed
+ &cbEmit)); // number of bytes write to cbEmit
+
+ // ...persist the converted signature
+ IfFailGo( pMiniMdEmit->PutBlob(TBL_MethodSpec, MethodSpecRec::COL_Instantiation, pRecEmit, qbSig.Ptr(), cbEmit) );
+
+ IfFailGo( pCurTkMap->InsertNotFound(TokenFromRid(i, mdtMethodSpec), false,
+ TokenFromRid(iRecord, mdtMethodSpec), &pTokenRecMethodNew) );
+ }
+ }
+
+ ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeMethodSpecs()
+
+//*****************************************************************************
+// Merge DeclSecuritys
+//*****************************************************************************
+HRESULT NEWMERGER::MergeDeclSecuritys()
+{
+ HRESULT hr = NOERROR;
+ DeclSecurityRec *pRecImport = NULL;
+ DeclSecurityRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ mdToken tkParentImp;
+ TOKENREC *pTokenRec;
+ void const *pValue;
+ ULONG cbBlob;
+ mdPermission pmImp;
+ mdPermission pmEmit;
+ bool fDuplicate;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountDeclSecuritys();
+
+ // loop through all DeclSecurity
+ for (i = 1; i <= iCount; i++)
+ {
+ // only merge those DeclSecurities that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsDeclSecurityMarked(TokenFromRid(i, mdtPermission)) == false)
+ continue;
+
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetDeclSecurityRecord(i, &pRecImport));
+ tkParentImp = pMiniMdImport->getParentOfDeclSecurity(pRecImport);
+ if ( pCurTkMap->Find(tkParentImp, &pTokenRec) )
+ {
+ if ( !pTokenRec->m_isDuplicate )
+ {
+ // If the parent is not duplicated, just copy over the custom value
+ goto CopyPermission;
+ }
+ else
+ {
+ // Try to see if the Permission is there in the emit scope or not.
+ // If not, move it over still
+ if ( ImportHelper::FindPermission(
+ pMiniMdEmit,
+ pTokenRec->m_tkTo,
+ pRecImport->GetAction(),
+ &pmEmit) == S_OK )
+ {
+ // found a match
+ // <TODO>@FUTURE: more verification??</TODO>
+ fDuplicate = true;
+ }
+ else
+ {
+ // Parent is duplicated but the Permission is not. Still copy over the
+ // Permission.
+CopyPermission:
+ fDuplicate = false;
+ IfFailGo(pMiniMdEmit->AddDeclSecurityRecord(&pRecEmit, (ULONG *)&pmEmit));
+ pmEmit = TokenFromRid(pmEmit, mdtPermission);
+
+ pRecEmit->Copy(pRecImport);
+
+ // set the parent
+ IfFailGo( pMiniMdEmit->PutToken(
+ TBL_DeclSecurity,
+ DeclSecurityRec::COL_Parent,
+ pRecEmit,
+ pTokenRec->m_tkTo) );
+
+ // move over the CustomAttribute blob value
+ IfFailGo(pMiniMdImport->getPermissionSetOfDeclSecurity(pRecImport, (const BYTE **)&pValue, &cbBlob));
+ IfFailGo(pMiniMdEmit->PutBlob(
+ TBL_DeclSecurity,
+ DeclSecurityRec::COL_PermissionSet,
+ pRecEmit,
+ pValue,
+ cbBlob));
+ }
+ }
+ pmEmit = TokenFromRid(pmEmit, mdtPermission);
+ pmImp = TokenFromRid(i, mdtPermission);
+
+ // Record the token movement
+ IfFailGo( pCurTkMap->InsertNotFound(pmImp, fDuplicate, pmEmit, &pTokenRec) );
+ }
+ else
+ {
+ // bad lookup map
+ _ASSERTE(!"bad state");
+ IfFailGo( META_E_BADMETADATA );
+ }
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeDeclSecuritys()
+
+
+//*****************************************************************************
+// Merge Strings
+//*****************************************************************************
+HRESULT NEWMERGER::MergeStrings()
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ TOKENREC *pTokenRec;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ for (UINT32 nIndex = 0; ;)
+ {
+ MetaData::DataBlob userString;
+ UINT32 nNextIndex;
+ UINT32 nEmitIndex;
+
+ hr = pMiniMdImport->GetUserStringAndNextIndex(
+ nIndex,
+ &userString,
+ &nNextIndex);
+ IfFailGo(hr);
+ if (hr == S_FALSE)
+ { // We reached the last user string
+ hr = S_OK;
+ break;
+ }
+ _ASSERTE(hr == S_OK);
+
+ // Skip empty strings
+ if (userString.IsEmpty())
+ {
+ nIndex = nNextIndex;
+ continue;
+ }
+
+ if (pMiniMdImport->GetFilterTable()->IsUserStringMarked(TokenFromRid(nIndex, mdtString)) == false)
+ {
+ // Process next user string in the heap
+ nIndex = nNextIndex;
+ continue;
+ }
+
+ IfFailGo(pMiniMdEmit->PutUserString(
+ userString,
+ &nEmitIndex));
+
+ IfFailGo(pCurTkMap->InsertNotFound(
+ TokenFromRid(nIndex, mdtString),
+ false,
+ TokenFromRid(nEmitIndex, mdtString),
+ &pTokenRec));
+
+ // Process next user string in the heap
+ nIndex = nNextIndex;
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeStrings()
+
+// Helper method to merge the module-level security critical attributes
+// Strips all module-level security critical attribute [that won't be ultimately needed]
+// Returns:
+// FAILED(hr): Failure occurred retrieving metadata or parsing scopes
+// S_OK: Attribute should be merged into final output scope
+// S_FALSE: Attribute should be ignored/dropped from output scope
+HRESULT NEWMERGER::MergeSecurityCriticalModuleLevelAttributes(
+ MergeImportData* pImportData, // import scope
+ mdToken tkParentImp, // parent token with attribute
+ TOKENREC* pTypeRec, // token record of attribute ctor
+ mdToken mrSecurityTreatAsSafeAttributeCtor, // 'generic' TAS attribute token
+ mdToken mrSecurityTransparentAttributeCtor, // 'generic' Transparent attribute token
+ mdToken mrSecurityCriticalExplicitAttributeCtor, // 'generic' Critical attribute token
+ mdToken mrSecurityCriticalEverythingAttributeCtor)
+{
+ HRESULT hr = S_OK;
+
+ // if ANY assembly-level critical attributes were specified, then we'll output
+ // one assembly-level Critical(Explicit) attribute only
+ // AND if this scope has tags
+ if (ISSCS_Unknown != pImportData->m_isscsSecurityCriticalStatus)
+ {
+ _ASSERTE(ISSCS_Unknown != m_isscsSecurityCritical);
+ // drop only assembly-level attributes
+ TypeRefRec* pTypeRefRec;
+ // metadata emitter
+ CMiniMdRW* pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // if compiler is generating a module - then this will be a module token
+ LPCSTR szTypeRefName;
+ if (tkParentImp == MODULEDEFTOKEN ||
+ // otherwise, if merging assemblies, we have a fake type ref called MODULE_CA_LOCATION
+ (TypeFromToken(tkParentImp) == mdtTypeRef &&
+ (IsAttributeFromNamespace(pMiniMdImport, tkParentImp,
+ COR_COMPILERSERVICE_NAMESPACE, COR_MSCORLIB_NAME,
+ &pTypeRefRec) == S_OK) &&
+ (pMiniMdImport->getNameOfTypeRef(pTypeRefRec, &szTypeRefName) == S_OK) &&
+ (strcmp(MODULE_CA_TYPENAME, szTypeRefName) == 0)))
+ {
+ // drop the TAS attribute (unless all scopes have TAS)
+ if ( pTypeRec->m_tkTo == mrSecurityTreatAsSafeAttributeCtor )
+ {
+ if ((m_isscsSecurityCriticalAllScopes & ISSCS_SecurityTreatAsSafe) ==
+ ISSCS_SecurityTreatAsSafe)
+ {
+ _ASSERTE((pImportData->m_isscsSecurityCriticalStatus & ISSCS_SecurityTreatAsSafe) ==
+ ISSCS_SecurityTreatAsSafe);
+ return S_OK;
+ }
+ return S_FALSE;
+ }
+ // drop the Transparent attribute (unless all scopes have Transparent)
+ else if (pTypeRec->m_tkTo == mrSecurityTransparentAttributeCtor)
+ {
+ if ((m_isscsSecurityCriticalAllScopes & ISSCS_SecurityTransparent) ==
+ ISSCS_SecurityTransparent)
+ {
+ _ASSERTE((pImportData->m_isscsSecurityCriticalStatus & ISSCS_SecurityTransparent) ==
+ ISSCS_SecurityTransparent);
+ return S_OK;
+ }
+ return S_FALSE;
+ }
+ else if (pTypeRec->m_tkTo == mrSecurityCriticalExplicitAttributeCtor)
+ {
+ // if NOT Critical Everything, then leave the Critical.Explicit attribute
+ // the Critical.Explicit attribute will be used as the final global attribute
+ if ((m_isscsSecurityCriticalAllScopes & ISSCS_SecurityCriticalEverything) !=
+ ISSCS_SecurityCriticalEverything)
+ {
+ _ASSERTE((pImportData->m_isscsSecurityCriticalStatus & ISSCS_SecurityCriticalExplicit) ==
+ ISSCS_SecurityCriticalExplicit);
+ return S_OK;
+ }
+ else
+ {
+ // drop this attribute
+ return S_FALSE;
+ }
+ }
+ else if (pTypeRec->m_tkTo == mrSecurityCriticalEverythingAttributeCtor)
+ {
+ // OPTIMIZATION: if all attributes are Critical.Everything,
+ // then leave the global Critical attribute
+ if ((m_isscsSecurityCriticalAllScopes & ISSCS_SecurityCriticalEverything) ==
+ ISSCS_SecurityCriticalEverything)
+ {
+ _ASSERTE((pImportData->m_isscsSecurityCriticalStatus & ISSCS_SecurityCriticalEverything) ==
+ ISSCS_SecurityCriticalEverything);
+ return S_OK;
+ }
+ else
+ {
+ // drop this attribute
+ return S_FALSE;
+ }
+ }
+ }
+ }
+
+ return hr;
+} // NEWMERGER::MergeSecurityCriticalModuleLevelAttributes
+
+// HELPER: Retrieve the meta-data info related to SecurityCritical
+HRESULT NEWMERGER::RetrieveStandardSecurityCriticalMetaData(
+ mdAssemblyRef& tkMscorlib,
+ mdTypeRef& securityEnum,
+ BYTE*& rgSigBytesSecurityCriticalEverythingCtor,
+ DWORD& dwSigEverythingSize,
+ BYTE*& rgSigBytesSecurityCriticalExplicitCtor,
+ DWORD& dwSigExplicitSize)
+{
+ HRESULT hr = S_OK;
+
+ CMiniMdRW* emit = GetMiniMdEmit();
+
+ // get typeref for mscorlib
+ BYTE pbMscorlibToken[] = COR_MSCORLIB_TYPEREF;
+ BYTE* pCurr = rgSigBytesSecurityCriticalEverythingCtor;
+
+ IfFailGo(ImportHelper::FindAssemblyRef(emit,
+ COR_MSCORLIB_NAME,
+ NULL,
+ pbMscorlibToken,
+ sizeof(pbMscorlibToken),
+ asm_rmj,
+ asm_rmm,
+ asm_rup,
+ asm_rpt,
+ 0,
+ &tkMscorlib));
+
+ IfFailGo(m_pRegMetaEmit->DefineTypeRefByName(tkMscorlib,
+ COR_SECURITYCRITICALSCOPE_ENUM_W,
+ &securityEnum));
+
+ // build the constructor sig that takes SecurityCriticalScope argument
+ if (rgSigBytesSecurityCriticalEverythingCtor)
+ {
+ *pCurr++ = IMAGE_CEE_CS_CALLCONV_DEFAULT_HASTHIS;
+ *pCurr++ = COR_SECURITYCRITICAL_CTOR_ARGCOUNT_SCOPE_EVERYTHING; // one argument to constructor
+ *pCurr++ = ELEMENT_TYPE_VOID;
+ *pCurr++ = ELEMENT_TYPE_VALUETYPE;
+ pCurr += CorSigCompressToken(securityEnum, pCurr);
+ dwSigEverythingSize = (DWORD)(pCurr - rgSigBytesSecurityCriticalEverythingCtor);
+ _ASSERTE(dwSigEverythingSize <= COR_SECURITYCRITICAL_CTOR_SCOPE_SIG_MAX_SIZE);
+ }
+
+ // if Explicit ctor is requested
+ if (rgSigBytesSecurityCriticalExplicitCtor)
+ {
+ // build the constructor sig that has NO arguments
+ pCurr = rgSigBytesSecurityCriticalExplicitCtor;
+ *pCurr++ = IMAGE_CEE_CS_CALLCONV_DEFAULT_HASTHIS;
+ *pCurr++ = COR_SECURITYCRITICAL_CTOR_ARGCOUNT_NO_SCOPE; // no arguments to constructor
+ *pCurr++ = ELEMENT_TYPE_VOID;
+ dwSigExplicitSize = (DWORD)(pCurr - rgSigBytesSecurityCriticalExplicitCtor);
+ _ASSERTE(dwSigExplicitSize <= COR_SECURITYCRITICAL_CTOR_NO_SCOPE_SIG_MAX_SIZE);
+ }
+
+ErrExit:
+ return hr;
+} // NEWMERGER::RetrieveStandardSecurityCriticalMetaData
+
+//*****************************************************************************
+// Merge CustomAttributes
+//*****************************************************************************
+HRESULT NEWMERGER::MergeCustomAttributes()
+{
+
+ HRESULT hr = NOERROR;
+ CustomAttributeRec *pRecImport = NULL;
+ CustomAttributeRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ mdToken tkParentImp; // Token of attributed object (parent).
+ TOKENREC *pTokenRec; // Parent's remap.
+ mdToken tkType; // Token of attribute's type.
+ TOKENREC *pTypeRec; // Type's remap.
+ void const *pValue; // The actual value.
+ ULONG cbBlob; // Size of the value.
+ mdToken cvImp;
+ mdToken cvEmit;
+ bool fDuplicate;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ TypeRefRec *pTypeRefRec;
+ ULONG cTypeRefRecs;
+ mdToken mrSuppressMergeCheckAttributeCtor = mdTokenNil;
+ mdToken mrSecurityCriticalExplicitAttributeCtor = mdTokenNil;
+ mdToken mrSecurityCriticalEverythingAttributeCtor = mdTokenNil;
+ mdToken mrSecurityTransparentAttributeCtor = mdTokenNil;
+ mdToken mrSecurityTreatAsSafeAttributeCtor = mdTokenNil;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ // Find out the TypeRef referring to our library's System.CompilerServices.SuppressMergeCheckAttribute,
+ // System.Security.SecurityCriticalAttribute, System.Security.SecurityTransparentAttribute, and
+ // System.Security.SecurityTreatAsSafeAttibute
+ cTypeRefRecs = pMiniMdEmit->getCountTypeRefs();
+
+ { // retrieve global attribute TypeRefs
+
+ mdAssemblyRef tkMscorlib = mdTokenNil;
+ mdTypeRef securityEnum = mdTokenNil;
+
+ NewArrayHolder<BYTE> rgSigBytesSecurityCriticalEverythingCtor(new (nothrow)BYTE[COR_SECURITYCRITICAL_CTOR_SCOPE_SIG_MAX_SIZE]);
+ BYTE* pSigBytesSecurityCriticalEverythingCtor = rgSigBytesSecurityCriticalEverythingCtor.GetValue();
+ IfFailGo((pSigBytesSecurityCriticalEverythingCtor == NULL)?E_OUTOFMEMORY:S_OK);
+ DWORD dwSigEverythingSize = 0;
+
+ NewArrayHolder<BYTE> rgSigBytesSecurityCriticalExplicitCtor(new (nothrow)BYTE[COR_SECURITYCRITICAL_CTOR_NO_SCOPE_SIG_MAX_SIZE]);
+ BYTE* pSigBytesSecurityCriticalExplicitCtor = rgSigBytesSecurityCriticalExplicitCtor.GetValue();
+ IfFailGo((pSigBytesSecurityCriticalExplicitCtor == NULL)?E_OUTOFMEMORY:S_OK);
+ DWORD dwSigExplicitSize = 0;
+
+ // retrieve security critical metadata info if necessary
+ if(ISSCS_Unknown != m_isscsSecurityCritical)
+ {
+
+ hr = RetrieveStandardSecurityCriticalMetaData(
+ tkMscorlib,
+ securityEnum,
+ pSigBytesSecurityCriticalEverythingCtor,
+ dwSigEverythingSize,
+ pSigBytesSecurityCriticalExplicitCtor,
+ dwSigExplicitSize);
+
+ }
+
+ // Search for the TypeRef.
+ for (i = 1; i <= cTypeRefRecs; i++)
+ {
+ mdToken tkTmp = TokenFromRid(i,mdtTypeRef);
+
+ if (IsAttributeFromNamespace(pMiniMdEmit, tkTmp,
+ COR_COMPILERSERVICE_NAMESPACE, COR_MSCORLIB_NAME,
+ &pTypeRefRec) == S_OK)
+ {
+ LPCSTR szNameOfTypeRef;
+ IfFailGo(pMiniMdEmit->getNameOfTypeRef(pTypeRefRec, &szNameOfTypeRef));
+ if (strcmp(szNameOfTypeRef, COR_SUPPRESS_MERGE_CHECK_ATTRIBUTE) == 0)
+ {
+ hr = ImportHelper::FindMemberRef(
+ pMiniMdEmit, tkTmp,
+ COR_CTOR_METHOD_NAME,
+ NULL, 0,
+ &mrSuppressMergeCheckAttributeCtor);
+ if (S_OK == hr) continue;
+ }
+ }
+ else
+ // if we are merging security critical attributes, then look for transparent-related attributes
+ if ((ISSCS_Unknown != m_isscsSecurityCritical) &&
+ (IsAttributeFromNamespace(pMiniMdEmit, tkTmp,
+ COR_SECURITYCRITICAL_ATTRIBUTE_NAMESPACE, COR_MSCORLIB_NAME,
+ &pTypeRefRec) == S_OK))
+ {
+ LPCSTR szNameOfTypeRef;
+ IfFailGo(pMiniMdEmit->getNameOfTypeRef(pTypeRefRec, &szNameOfTypeRef));
+
+ // look for the SecurityCritical attribute
+ if (strcmp(szNameOfTypeRef, COR_SECURITYCRITICAL_ATTRIBUTE) == 0)
+ {
+ // since the SecurityCritical attribute can be either
+ // parameterless constructor or SecurityCriticalScope constructor, we
+ // look for both
+ hr = ImportHelper::FindMemberRef(
+ pMiniMdEmit, tkTmp,
+ COR_CTOR_METHOD_NAME,
+ rgSigBytesSecurityCriticalEverythingCtor.GetValue(), dwSigEverythingSize,
+ &mrSecurityCriticalEverythingAttributeCtor);
+ if (S_OK == hr) continue;
+ hr = ImportHelper::FindMemberRef(
+ pMiniMdEmit, tkTmp,
+ COR_CTOR_METHOD_NAME,
+ rgSigBytesSecurityCriticalExplicitCtor.GetValue(), dwSigExplicitSize,
+ &mrSecurityCriticalExplicitAttributeCtor);
+ if (S_OK == hr) continue;
+ }
+ else
+ // look for the SecurityTransparent attribute
+ if (strcmp(szNameOfTypeRef, COR_SECURITYTRANSPARENT_ATTRIBUTE) == 0)
+ {
+ hr = ImportHelper::FindMemberRef(
+ pMiniMdEmit, tkTmp,
+ COR_CTOR_METHOD_NAME,
+ NULL, 0,
+ &mrSecurityTransparentAttributeCtor);
+ if (S_OK == hr) continue;
+ }
+ else
+ // look for the SecurityTreatAsSafe attribute
+ if (strcmp(szNameOfTypeRef, COR_SECURITYTREATASSAFE_ATTRIBUTE) == 0)
+ {
+ hr = ImportHelper::FindMemberRef(
+ pMiniMdEmit, tkTmp,
+ COR_CTOR_METHOD_NAME,
+ NULL, 0,
+ &mrSecurityTreatAsSafeAttributeCtor);
+ if (S_OK == hr) continue;
+ }
+ }
+ hr = S_OK; // ignore failures since the attribute may not be used
+ }
+ }
+
+ // Loop over every module scope
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountCustomAttributes();
+
+ // loop through all CustomAttribute
+ for (i = 1; i <= iCount; i++)
+ {
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetCustomAttributeRecord(i, &pRecImport));
+ tkParentImp = pMiniMdImport->getParentOfCustomAttribute(pRecImport);
+ tkType = pMiniMdImport->getTypeOfCustomAttribute(pRecImport);
+ IfFailGo(pMiniMdImport->getValueOfCustomAttribute(pRecImport, (const BYTE **)&pValue, &cbBlob));
+
+ // only merge those CustomAttributes that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsCustomAttributeMarked(TokenFromRid(i, mdtCustomAttribute)) == false)
+ continue;
+
+ // Check the type of the CustomAttribute. If it is not marked, then we don't need to move over the CustomAttributes.
+ // This will only occur for compiler defined discardable CAs during linking.
+ //
+ if ( pMiniMdImport->GetFilterTable()->IsTokenMarked(tkType) == false)
+ continue;
+
+ if ( pCurTkMap->Find(tkParentImp, &pTokenRec) )
+ {
+ // If the From token type is different from the To token's type, we have optimized the ref to def.
+ // In this case, we are dropping the CA associated with the Ref tokens.
+ //
+ if (TypeFromToken(tkParentImp) == TypeFromToken(pTokenRec->m_tkTo))
+ {
+
+ // If tkParentImp is a MemberRef and it is also mapped to a MemberRef in the merged scope with a MethodDef
+ // parent, then it is a MemberRef optimized to a MethodDef. We are keeping the MemberRef because it is a
+ // vararg call. So we can drop CAs on this MemberRef.
+ if (TypeFromToken(tkParentImp) == mdtMemberRef)
+ {
+ MemberRefRec *pTempRec;
+ IfFailGo(pMiniMdEmit->GetMemberRefRecord(RidFromToken(pTokenRec->m_tkTo), &pTempRec));
+ if (TypeFromToken(pMiniMdEmit->getClassOfMemberRef(pTempRec)) == mdtMethodDef)
+ continue;
+ }
+
+
+ if (! pCurTkMap->Find(tkType, &pTypeRec) )
+ {
+ _ASSERTE(!"CustomAttribute Type not found in output scope");
+ IfFailGo(META_E_BADMETADATA);
+ }
+
+ // Determine if we need to copy or ignore security-critical-related attributes
+ hr = MergeSecurityCriticalModuleLevelAttributes(
+ pImportData, tkParentImp, pTypeRec,
+ mrSecurityTreatAsSafeAttributeCtor, mrSecurityTransparentAttributeCtor,
+ mrSecurityCriticalExplicitAttributeCtor,
+ mrSecurityCriticalEverythingAttributeCtor);
+ IfFailGo(hr);
+ // S_FALSE means skip attribute
+ if (hr == S_FALSE) continue;
+ // S_OK means consider copying attribute
+
+ // if it's the SuppressMergeCheckAttribute, don't copy it
+ if ( pTypeRec->m_tkTo == mrSuppressMergeCheckAttributeCtor )
+ {
+ continue;
+ }
+
+ if ( pTokenRec->m_isDuplicate)
+ {
+ // Try to see if the custom value is there in the emit scope or not.
+ // If not, move it over still
+ hr = ImportHelper::FindCustomAttributeByToken(
+ pMiniMdEmit,
+ pTokenRec->m_tkTo,
+ pTypeRec->m_tkTo,
+ pValue,
+ cbBlob,
+ &cvEmit);
+
+ if ( hr == S_OK )
+ {
+ // found a match
+ // <TODO>@FUTURE: more verification??</TODO>
+ fDuplicate = true;
+ }
+ else
+ {
+ TypeRefRec *pAttributeTypeRefRec;
+ // We need to allow additive merge on TypeRef for CustomAttributes because compiler
+ // could build module but not assembly. They are hanging of Assembly level CAs on a bogus
+ // TypeRef.
+ // Also allow additive merge for CAs from CompilerServices and Microsoft.VisualC
+ if (tkParentImp == MODULEDEFTOKEN
+ || TypeFromToken(tkParentImp) == mdtTypeRef
+ || (IsAttributeFromNamespace(pMiniMdImport, tkType,
+ COR_COMPILERSERVICE_NAMESPACE, COR_MSCORLIB_NAME,
+ &pAttributeTypeRefRec) == S_OK)
+ || (IsAttributeFromNamespace(pMiniMdImport, tkType,
+ COR_MISCBITS_NAMESPACE, COR_MISCBITS_NAMESPACE,
+ &pAttributeTypeRefRec) == S_OK))
+ {
+ // clear the error
+ hr = NOERROR;
+
+ // custom value of module token! Copy over the custom value
+ goto CopyCustomAttribute;
+ }
+
+ // another case to support additive merge if the CA on MehtodDef is
+ // HandleProcessCorruptedStateExceptionsAttribute
+ if ( TypeFromToken(tkParentImp) == mdtMethodDef && tkType == pImportData->m_tkHandleProcessCorruptedStateCtor)
+ {
+ // clear the error
+ hr = NOERROR;
+
+ // custom value of module token! Copy over the custom value
+ goto CopyCustomAttribute;
+ }
+ CheckContinuableErrorEx(META_E_MD_INCONSISTENCY, pImportData, TokenFromRid(i, mdtCustomAttribute));
+ }
+ }
+ else
+ {
+CopyCustomAttribute:
+ if ((m_dwMergeFlags & DropMemberRefCAs) && TypeFromToken(pTokenRec->m_tkTo) == mdtMemberRef)
+ {
+ // CustomAttributes associated with MemberRef. If the parent of MemberRef is a MethodDef or FieldDef, drop
+ // the custom attribute.
+ MemberRefRec *pMemberRefRec;
+ IfFailGo(pMiniMdEmit->GetMemberRefRecord(RidFromToken(pTokenRec->m_tkTo), &pMemberRefRec));
+ mdToken mrParent = pMiniMdEmit->getClassOfMemberRef(pMemberRefRec);
+ if (TypeFromToken(mrParent) == mdtMethodDef || TypeFromToken(mrParent) == mdtFieldDef)
+ {
+ // Don't bother to copy over
+ continue;
+ }
+ }
+
+ // Parent is duplicated but the custom value is not. Still copy over the
+ // custom value.
+ fDuplicate = false;
+ IfFailGo(pMiniMdEmit->AddCustomAttributeRecord(&pRecEmit, (ULONG *)&cvEmit));
+ cvEmit = TokenFromRid(cvEmit, mdtCustomAttribute);
+
+ // set the parent
+ IfFailGo( pMiniMdEmit->PutToken(TBL_CustomAttribute, CustomAttributeRec::COL_Parent, pRecEmit, pTokenRec->m_tkTo) );
+ // set the type
+ IfFailGo( pMiniMdEmit->PutToken(TBL_CustomAttribute, CustomAttributeRec::COL_Type, pRecEmit, pTypeRec->m_tkTo));
+
+ // move over the CustomAttribute blob value
+ IfFailGo(pMiniMdImport->getValueOfCustomAttribute(pRecImport, (const BYTE **)&pValue, &cbBlob));
+
+ IfFailGo( pMiniMdEmit->PutBlob(TBL_CustomAttribute, CustomAttributeRec::COL_Value, pRecEmit, pValue, cbBlob));
+ IfFailGo( pMiniMdEmit->AddCustomAttributesToHash(cvEmit) );
+ }
+ cvEmit = TokenFromRid(cvEmit, mdtCustomAttribute);
+ cvImp = TokenFromRid(i, mdtCustomAttribute);
+
+ // Record the token movement
+ IfFailGo( pCurTkMap->InsertNotFound(cvImp, pTokenRec->m_isDuplicate, cvEmit, &pTokenRec) );
+ }
+ }
+ else
+ {
+
+ // either bad lookup map or bad metadata
+ _ASSERTE(!"Bad state");
+ IfFailGo( META_E_BADMETADATA );
+ }
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeCustomAttributes()
+
+//*******************************************************************************
+// Helper to check if input scope has assembly-level security transparent awareness (either SecurityTransparent or SecurityCritical)
+// SIDE EFFECT: pImportData->m_isscsSecurityCriticalStatus will be explicitly set [same value as return value]
+// SecurityCritical.Explicit attribute injection occurs for all scopes that have tags (e.g. NOT ISSCS_Unknown)
+// If the tagged scopes are all SecurityCritical.Everything, then the final attribute should be SecurityCritical.Everything
+// anyway. Otherwise, at least one SecurityCritical.Explicit tag will be used/injected
+//*******************************************************************************
+InputScopeSecurityCriticalStatus NEWMERGER::CheckInputScopeIsCritical(MergeImportData* pImportData, HRESULT& hr)
+{
+ hr = S_OK;
+
+ // the attribute should be in a known state no matter how we return from this function
+ // default to no attribute explicitly specified
+ pImportData->m_isscsSecurityCriticalStatus = ISSCS_Unknown;
+
+ mdTypeRef fakeModuleTypeRef = mdTokenNil;
+ mdAssemblyRef tkMscorlib = mdTokenNil;
+
+ // TODO: Should we remove the ability to disable merging critical attributes?
+ if (g_fRefShouldMergeCriticalChecked == FALSE)
+ {
+ // shouldn't require thread safety lock
+ g_fRefShouldMergeCritical = (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_MergeCriticalAttributes) != 0);
+ g_fRefShouldMergeCriticalChecked = TRUE;
+ }
+
+ // return no merge needed, if the merge critical attribute setting is not enabled.
+ if (!g_fRefShouldMergeCritical) return ISSCS_Unknown;
+
+ // get typeref for mscorlib
+ BYTE pbMscorlibToken[] = COR_MSCORLIB_TYPEREF;
+
+ CMiniMdRW* pImportedMiniMd = &pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd;
+
+ if (S_OK != ImportHelper::FindAssemblyRef(pImportedMiniMd,
+ COR_MSCORLIB_NAME,
+ NULL,
+ pbMscorlibToken,
+ sizeof(pbMscorlibToken),
+ asm_rmj,
+ asm_rmm,
+ asm_rup,
+ asm_rpt,
+ 0,
+ &tkMscorlib))
+ {
+ // there isn't an mscorlib ref here... we can't have the security critical attribute
+ return ISSCS_Unknown;
+ }
+
+ if (S_OK != ImportHelper::FindTypeRefByName(pImportedMiniMd,
+ tkMscorlib,
+ COR_COMPILERSERVICE_NAMESPACE,
+ MODULE_CA_TYPENAME,
+ &fakeModuleTypeRef))
+ {
+ // for now let use the fake module ref as the assembly def
+ fakeModuleTypeRef = 0x000001;
+ }
+
+ // Check the input scope for TreatAsSafe
+ if (S_OK == ImportHelper::GetCustomAttributeByName(pImportedMiniMd,
+ fakeModuleTypeRef, // This is the assembly def token
+ COR_SECURITYTREATASSAFE_ATTRIBUTE_FULL,
+ NULL,
+ NULL))
+ {
+ pImportData->m_isscsSecurityCriticalStatus |= ISSCS_SecurityTreatAsSafe;
+ }
+
+ // Check the input scope for security transparency awareness
+ // For example, the assembly is marked SecurityTransparent, SecurityCritical(Explicit), or SecurityCritical(Everything)
+
+
+ const void *pbData = NULL; // [OUT] Put pointer to data here.
+ ULONG cbData = 0; // number of bytes in pbData
+
+ // Check if the SecurityTransparent attribute is present
+ if (S_OK == ImportHelper::GetCustomAttributeByName(pImportedMiniMd,
+ fakeModuleTypeRef, // This is the assembly def token
+ COR_SECURITYTRANSPARENT_ATTRIBUTE_FULL,
+ NULL,
+ NULL))
+ {
+ pImportData->m_isscsSecurityCriticalStatus |= ISSCS_SecurityTransparent;
+ }
+ else
+ // Check if the SecurityCritical attribute is present
+ if (S_OK == ImportHelper::GetCustomAttributeByName(pImportedMiniMd,
+ fakeModuleTypeRef, // This is the assembly def token
+ COR_SECURITYCRITICAL_ATTRIBUTE_FULL,
+ &pbData,
+ &cbData))
+ {
+ // find out if critical everything or explicit
+
+ // default to critical
+ pImportData->m_isscsSecurityCriticalStatus = ISSCS_SecurityCritical;
+
+ BYTE rgSecurityCriticalEverythingCtorValue[] = COR_SECURITYCRITICAL_ATTRIBUTE_VALUE_EVERYTHING;
+ // if value is non-0 (i.e. 1), then mark as SecurityCritical everything, otherwise, explicit
+ if (NULL != pbData && cbData == 8 &&
+ memcmp(rgSecurityCriticalEverythingCtorValue, pbData, cbData) == 0)
+ {
+ pImportData->m_isscsSecurityCriticalStatus |= ISSCS_SecurityCriticalEverything;
+ }
+ else
+ {
+ pImportData->m_isscsSecurityCriticalStatus |= ISSCS_SecurityCriticalExplicit;
+ }
+ }
+
+ return pImportData->m_isscsSecurityCriticalStatus;
+} // HRESULT NEWMERGER::CheckInputScopeIsCritical()
+
+//*******************************************************************************
+// Helper to merge security critical annotations across assemblies and types
+//*******************************************************************************
+HRESULT NEWMERGER::MergeSecurityCriticalAttributes()
+{
+ // if no assembly-level critical attributes were specified, then none are needed,
+ // and no need to do special attribute merging
+ if (ISSCS_Unknown == m_isscsSecurityCritical)
+ {
+ return S_OK;
+ }
+ // or if the global-scope already has TAS/Critical.Everything, then ignore individual type fixes
+ else if ((ISSCS_SECURITYCRITICAL_LEGACY & m_isscsSecurityCriticalAllScopes) == ISSCS_SECURITYCRITICAL_LEGACY)
+ {
+ return S_OK;
+ }
+
+ HRESULT hr = S_OK;
+
+ CMiniMdRW* emit = GetMiniMdEmit();
+ // The attribute we want to decorate all of the types with has not been defined.
+ mdMemberRef tkSecurityCriticalEverythingAttribute = mdTokenNil;
+ mdMemberRef tkSecurityTreatAsSafeAttribute = mdTokenNil;
+ mdMemberRef tkSecuritySafeCriticalAttribute = mdTokenNil;
+
+ mdAssemblyRef tkMscorlib = mdTokenNil;
+ mdTypeRef fakeModuleTypeRef = mdTokenNil;
+ mdTypeRef securityEnum = mdTokenNil;
+
+ DWORD dwSigSize;
+ BYTE* rgSigBytesSecurityCriticalExplicitCtor = 0;
+ DWORD dwSigSize_TEMP;
+
+ BYTE rgSigBytesTreatAsSafeCtor[] = {IMAGE_CEE_CS_CALLCONV_DEFAULT_HASTHIS, 0x00, ELEMENT_TYPE_VOID};
+
+ BYTE rgSecurityCriticalEverythingCtorValue[] = COR_SECURITYCRITICAL_ATTRIBUTE_VALUE_EVERYTHING;
+
+
+ mdTypeRef tkSecurityCriticalEverythingAttributeType = mdTokenNil;
+ mdTypeRef tkSecurityTreatAsSafeAttributeType = mdTokenNil;
+
+ NewArrayHolder<BYTE> rgSigBytesSecurityCriticalEverythingCtor(new (nothrow)BYTE[COR_SECURITYCRITICAL_CTOR_SCOPE_SIG_MAX_SIZE]);
+ BYTE* pSigBytesSecurityCriticalEverythingCtor = rgSigBytesSecurityCriticalEverythingCtor.GetValue();
+ IfFailGo((pSigBytesSecurityCriticalEverythingCtor == NULL)?E_OUTOFMEMORY:S_OK);
+
+ IfFailGo(RetrieveStandardSecurityCriticalMetaData(
+ tkMscorlib,
+ securityEnum,
+ pSigBytesSecurityCriticalEverythingCtor,
+ dwSigSize,
+ rgSigBytesSecurityCriticalExplicitCtor,
+ dwSigSize_TEMP));
+
+ if (S_OK != ImportHelper::FindTypeRefByName(emit,
+ tkMscorlib,
+ COR_COMPILERSERVICE_NAMESPACE,
+ MODULE_CA_TYPENAME,
+ &fakeModuleTypeRef))
+ {
+ // for now let use the fake module ref as the assembly def
+ fakeModuleTypeRef = 0x000001;
+ }
+
+ IfFailGo(m_pRegMetaEmit->DefineTypeRefByName(
+ tkMscorlib, COR_SECURITYCRITICAL_ATTRIBUTE_FULL_W, &tkSecurityCriticalEverythingAttributeType));
+
+ IfFailGo(m_pRegMetaEmit->DefineMemberRef(tkSecurityCriticalEverythingAttributeType,
+ COR_CONSTRUCTOR_METADATA_IDENTIFIER,
+ rgSigBytesSecurityCriticalEverythingCtor.GetValue(),
+ dwSigSize,
+ &tkSecurityCriticalEverythingAttribute));
+
+ IfFailGo(m_pRegMetaEmit->DefineTypeRefByName(
+ tkMscorlib, COR_SECURITYTREATASSAFE_ATTRIBUTE_FULL_W,
+ &tkSecurityTreatAsSafeAttributeType));
+
+ IfFailGo(m_pRegMetaEmit->DefineMemberRef(tkSecurityTreatAsSafeAttributeType,
+ COR_CONSTRUCTOR_METADATA_IDENTIFIER,
+ rgSigBytesTreatAsSafeCtor,
+ sizeof(rgSigBytesTreatAsSafeCtor),
+ &tkSecurityTreatAsSafeAttribute));
+
+
+ // place this block in a new scope so that we can safely goto past it
+ {
+ mdTypeRef tkSecuritySafeCriticalAttributeType = mdTokenNil;
+ if (FAILED (hr = m_pRegMetaEmit->DefineTypeRefByName(tkMscorlib, COR_SECURITYSAFECRITICAL_ATTRIBUTE_FULL_W,
+ &tkSecuritySafeCriticalAttributeType)))
+ {
+ _ASSERTE(!"Couldn't Emit a Typeref for SafeCritical attribute");
+ return hr;
+ }
+
+ BYTE rgSigBytesSafeCriticalCtor[] = {IMAGE_CEE_CS_CALLCONV_DEFAULT_HASTHIS, 0x00, ELEMENT_TYPE_VOID};
+ if (FAILED(hr = m_pRegMetaEmit->DefineMemberRef(tkSecuritySafeCriticalAttributeType,
+ W(".ctor"),
+ rgSigBytesSafeCriticalCtor,
+ sizeof(rgSigBytesSafeCriticalCtor),
+ &tkSecuritySafeCriticalAttribute)))
+ {
+ _ASSERTE(!"Couldn't Emit a MemberRef for SafeCritical attribute .ctor");
+ return hr;
+ }
+ }
+
+
+ for (MergeImportData* pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // if the import is marked TAS, then we need to explicitly mark each type as TAS
+ // if the import is marked Crit/Everything, then we need to explicitly mark each type as Crit
+ // if the import is not marked at all, then we need to explicitly mark each type TAS/Crit
+
+ // if the import is marked ONLY Crit/Explicit or ONLY Transparent then we can ignore it
+ if (ISSCS_SecurityTransparent == pImportData->m_isscsSecurityCriticalStatus ||
+ ISSCS_SecurityCriticalExplicit == pImportData->m_isscsSecurityCriticalStatus) continue;
+
+ // Run through the scopes that need to have their types decorated with this attribute
+ MDTOKENMAP*pCurTKMap = pImportData->m_pMDTokenMap;
+ BYTE rgTreatAsSafeCtorValue[] = COR_SECURITYTREATASSAFE_ATTRIBUTE_VALUE;
+
+ BOOL fMarkEachTokenAsCritical = FALSE;
+ // if the import is unmarked or marked Crit/Everything,
+ // then we need to explicitly mark each token as Crit
+ // Unless the the global scope already has SecurityCritical.Everything
+ if (((ISSCS_SecurityCriticalEverything & m_isscsSecurityCriticalAllScopes) != ISSCS_SecurityCriticalEverything) &&
+ (((ISSCS_SecurityCriticalEverything & pImportData->m_isscsSecurityCriticalStatus) == ISSCS_SecurityCriticalEverything ) ||
+
+ // OR this scope is NOT transparent or critical-explicit
+ (ISSCS_SecurityTransparent & pImportData->m_isscsSecurityCriticalStatus) == 0 ||
+ (ISSCS_SecurityCritical & pImportData->m_isscsSecurityCriticalStatus) == 0 ||
+
+ // OR this scope is UNKNOWN
+ (ISSCS_Unknown == (ISSCS_SECURITYCRITICAL_FLAGS & pImportData->m_isscsSecurityCriticalStatus))))
+ {
+ fMarkEachTokenAsCritical = TRUE;
+ }
+
+ BOOL fMarkEachTokenAsSafe = FALSE;
+ // if the import is unmarked or marked TAS,
+ // then we need to explicitly mark each token as TAS
+ // Unless the the global scope already has SecurityTreatAsSafe
+ if (((ISSCS_SecurityTreatAsSafe & m_isscsSecurityCriticalAllScopes) != ISSCS_SecurityTreatAsSafe) &&
+ ((ISSCS_SecurityTreatAsSafe & pImportData->m_isscsSecurityCriticalStatus) ||
+ ISSCS_Unknown == (pImportData->m_isscsSecurityCriticalStatus & ISSCS_SECURITYCRITICAL_FLAGS)))
+ {
+ fMarkEachTokenAsSafe = TRUE;
+ }
+
+ BYTE rgSafeCriticalCtorValue[] = {0x01, 0x00, 0x00 ,0x00};
+
+ for (int i = 0; i < pCurTKMap->Count(); i++)
+ {
+ TOKENREC* pRec = pCurTKMap->Get(i);
+ BOOL fInjectSecurityAttributes = FALSE;
+
+ // skip empty records
+ if (pRec->IsEmpty()) continue;
+
+ // If this scope contained a typeref that was resolved to a typedef, let's not mark it. We'll let the owner
+ // of the actual typedef decide if that type should be marked.
+ if ((TypeFromToken(pRec->m_tkFrom) == mdtTypeRef) && (TypeFromToken(pRec->m_tkTo) == mdtTypeDef))
+ continue;
+
+ // Same for method refs/method defs
+ if ((TypeFromToken(pRec->m_tkFrom) == mdtMemberRef) && (TypeFromToken(pRec->m_tkTo) == mdtMethodDef))
+ continue;
+
+ // check for typedefs, but don't put this on the global typedef
+ if ((TypeFromToken(pRec->m_tkTo) == mdtTypeDef) && (pRec->m_tkTo != TokenFromRid(1, mdtTypeDef)))
+ {
+ // by default we will inject
+ fInjectSecurityAttributes = TRUE;
+ // except for Enums
+ DWORD dwClassAttrs = 0;
+ mdTypeRef crExtends = mdTokenNil;
+
+ if (FAILED(hr = m_pRegMetaEmit->GetTypeDefProps(pRec->m_tkTo, NULL, NULL, 0 , &dwClassAttrs, &crExtends)))
+ {
+ // TODO: should we fail ??
+ }
+
+ // check for Enum types
+ if (!IsNilToken(crExtends) && (TypeFromToken(crExtends)==mdtTypeRef))
+ {
+ // get the namespace and the name for this token
+ CMiniMdRW *pMiniMd = GetMiniMdEmit();
+ TypeRefRec *pTypeRefRec;
+ IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(crExtends), &pTypeRefRec));
+ LPCSTR szNamespace;
+ LPCSTR szName;
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szNamespace));;
+ IfFailGo(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szName));
+ // check for System.Enum
+ BOOL bIsEnum = (!strcmp(szNamespace,"System"))&&(!strcmp(szName,"Enum"));
+ if (bIsEnum)
+ {
+ fInjectSecurityAttributes = FALSE;
+ }
+ }
+ }
+ else // check for global method defs
+ if (TypeFromToken(pRec->m_tkTo) == mdtMethodDef)
+ {
+ int isGlobal = 0;
+ if (!FAILED(m_pRegMetaEmit->IsGlobal(pRec->m_tkTo, &isGlobal)))
+ {
+ // check for global methods
+ if (isGlobal != 0)
+ {
+ fInjectSecurityAttributes = TRUE;
+ }
+ }
+ }
+
+ if (fInjectSecurityAttributes)
+ {
+ // check to see if the token already has a custom attribute
+ const void *pbData = NULL; // [OUT] Put pointer to data here.
+ ULONG cbData = 0;
+
+ if (fMarkEachTokenAsCritical)
+ {
+ // Check if the Type already has SecurityCritical
+ BOOL fInjectSecurityCriticalEverything = TRUE;
+ if (S_OK == m_pRegMetaEmit->GetCustomAttributeByName(pRec->m_tkTo, COR_SECURITYCRITICAL_ATTRIBUTE_FULL_W, &pbData, &cbData))
+ {
+ // if value is non-0 (i.e. 1), then it is SecurityCritical.Everything - so do not inject another
+ fInjectSecurityCriticalEverything = !(NULL != pbData && cbData == 8 &&
+ memcmp(rgSecurityCriticalEverythingCtorValue, pbData, cbData) == 0);
+ }
+
+ // either inject or overwrite SecurityCritical.Everything
+ if (fInjectSecurityCriticalEverything)
+ {
+ IfFailGo(m_pRegMetaEmit->DefineCustomAttribute(
+ pRec->m_tkTo, tkSecurityCriticalEverythingAttribute,
+ rgSecurityCriticalEverythingCtorValue, // Use this if you need specific custom attribute data (presence of the attribute isn't enough)
+ sizeof(rgSecurityCriticalEverythingCtorValue), // Length of your custom attribute data
+ NULL));
+ }
+ }
+
+ // If the Type does NOT already have TAS then add it
+ if (fMarkEachTokenAsSafe &&
+ S_OK != m_pRegMetaEmit->GetCustomAttributeByName(pRec->m_tkTo, COR_SECURITYTREATASSAFE_ATTRIBUTE_FULL_W, &pbData, &cbData))
+ {
+ IfFailGo(m_pRegMetaEmit->DefineCustomAttribute(
+ pRec->m_tkTo, tkSecurityTreatAsSafeAttribute,
+ rgTreatAsSafeCtorValue, // Use this if you need specific custom attribute data (presence of the attribute isn't enough)
+ sizeof(rgTreatAsSafeCtorValue), // Length of your custom attribute data
+ NULL));
+ }
+
+ hr = m_pRegMetaEmit->DefineCustomAttribute(pRec->m_tkTo, tkSecuritySafeCriticalAttribute,
+ rgSafeCriticalCtorValue, // Use this if you need specific custom attribute data (presence of the attribute isn't enough)
+ sizeof(rgSafeCriticalCtorValue), // Length of your custom attribute data
+ NULL);
+
+ }
+ }
+ }
+
+ // If the global scope is not Transparent, we should emit SecurityCritical.Explicit || Everything
+ if ((m_isscsSecurityCriticalAllScopes & ISSCS_SecurityTransparent) != ISSCS_SecurityTransparent &&
+ (m_isscsSecurityCritical & ISSCS_SecurityCriticalEverything) != ISSCS_SecurityCriticalExplicit)
+ {
+ BOOL fEmitSecurityEverything = FALSE;
+ // in the case of Unmarked and TAS/Unmarked, we need to emit the SecurityCritical.Everything attribute
+ // if it hasn't already been emitted
+ if ((m_isscsSecurityCriticalAllScopes & ISSCS_SecurityCriticalEverything) ==
+ ISSCS_SecurityCriticalEverything)
+ {
+ fEmitSecurityEverything = TRUE;
+ }
+ // otherwise, emit the SecurityCritical.Explicit attribute
+
+ BOOL fSecurityCriticalExists = FALSE;
+ // check to see if the assembly already has the appropriate SecurityCritical attribute
+ // [from one of the input scopes]
+ const void *pbData = NULL;
+ ULONG cbData = 0;
+ if (S_OK == ImportHelper::GetCustomAttributeByName(emit,
+ fakeModuleTypeRef, // This is the assembly def token
+ COR_SECURITYCRITICAL_ATTRIBUTE_FULL,
+ &pbData,
+ &cbData))
+ {
+ // find out if critical everything or explicit
+ // default to critical
+ // if value is non-0 (i.e. 1), then mark as SecurityCritical everything, otherwise, explicit
+ if (NULL != pbData && cbData == 8 &&
+ memcmp(rgSecurityCriticalEverythingCtorValue, pbData, cbData) == 0)
+ {
+ if (!fEmitSecurityEverything)
+ {
+ _ASSERTE(!"Unexpected SecurityCritical.Everything attribute detected");
+ IfFailGo(META_E_BADMETADATA);
+ }
+ }
+ else
+ {
+ if (fEmitSecurityEverything)
+ {
+ _ASSERTE(!"Unexpected SecurityCritical.Explicit attribute detected");
+ IfFailGo(META_E_BADMETADATA);
+ }
+ }
+ fSecurityCriticalExists = TRUE;
+ }
+
+ if (!fSecurityCriticalExists)
+ {
+ // retrieve the type and CustomAttribute
+ mdCustomAttribute tkSecurityCriticalAttributeExplicit;
+
+ mdTypeRef tkSecurityCriticalExplicitAttributeType = mdTokenNil;
+
+ IfFailGo(m_pRegMetaEmit->DefineTypeRefByName(
+ tkMscorlib, COR_SECURITYCRITICAL_ATTRIBUTE_FULL_W,
+ &tkSecurityCriticalExplicitAttributeType));
+
+ BYTE rgSigBytesSecurityCriticalExplicitCtorLocal[] = {IMAGE_CEE_CS_CALLCONV_DEFAULT_HASTHIS, 0x00, ELEMENT_TYPE_VOID};
+ BYTE rgSecurityCriticalExplicitCtorValue[] = COR_SECURITYCRITICAL_ATTRIBUTE_VALUE_EXPLICIT;
+
+ IfFailGo(m_pRegMetaEmit->DefineMemberRef(tkSecurityCriticalExplicitAttributeType,
+ COR_CONSTRUCTOR_METADATA_IDENTIFIER,
+ rgSigBytesSecurityCriticalExplicitCtorLocal,
+ sizeof(rgSigBytesSecurityCriticalExplicitCtorLocal),
+ &tkSecurityCriticalAttributeExplicit));
+
+ IfFailGo(m_pRegMetaEmit->DefineCustomAttribute(
+ fakeModuleTypeRef,
+ fEmitSecurityEverything?tkSecurityCriticalEverythingAttribute:tkSecurityCriticalAttributeExplicit,
+ fEmitSecurityEverything?rgSecurityCriticalEverythingCtorValue:rgSecurityCriticalExplicitCtorValue,
+ fEmitSecurityEverything?sizeof(rgSecurityCriticalEverythingCtorValue):sizeof(rgSecurityCriticalExplicitCtorValue),
+ NULL));
+
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeSecurityCriticalAttributes()
+
+//*******************************************************************************
+// Helper to copy an InterfaceImpl record
+//*******************************************************************************
+HRESULT NEWMERGER::CopyInterfaceImpl(
+ InterfaceImplRec *pRecEmit, // [IN] the emit record to fill
+ MergeImportData *pImportData, // [IN] the importing context
+ InterfaceImplRec *pRecImp) // [IN] the record to import
+{
+ HRESULT hr;
+ mdToken tkParent;
+ mdToken tkInterface;
+ CMiniMdRW *pMiniMdEmit = GetMiniMdEmit();
+ CMiniMdRW *pMiniMdImp;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdImp = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ tkParent = pMiniMdImp->getClassOfInterfaceImpl(pRecImp);
+ tkInterface = pMiniMdImp->getInterfaceOfInterfaceImpl(pRecImp);
+
+ IfFailGo( pCurTkMap->Remap(tkParent, &tkParent) );
+ IfFailGo( pCurTkMap->Remap(tkInterface, &tkInterface) );
+
+ IfFailGo( pMiniMdEmit->PutToken( TBL_InterfaceImpl, InterfaceImplRec::COL_Class, pRecEmit, tkParent) );
+ IfFailGo( pMiniMdEmit->PutToken( TBL_InterfaceImpl, InterfaceImplRec::COL_Interface, pRecEmit, tkInterface) );
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyInterfaceImpl()
+
+
+//*****************************************************************************
+// Merge Assembly table
+//*****************************************************************************
+HRESULT NEWMERGER::MergeAssembly()
+{
+ HRESULT hr = NOERROR;
+ AssemblyRec *pRecImport = NULL;
+ AssemblyRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ LPCUTF8 szTmp;
+ const BYTE *pbTmp;
+ ULONG cbTmp;
+ ULONG iRecord;
+ TOKENREC *pTokenRec;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ if (!pMiniMdImport->getCountAssemblys())
+ goto ErrExit; // There is no Assembly in the import scope to merge.
+
+ // Copy the Assembly map record to the Emit scope and send a token remap notifcation
+ // to the client. No duplicate checking needed since the Assembly can be present in
+ // only one scope and there can be atmost one entry.
+ IfFailGo(pMiniMdImport->GetAssemblyRecord(1, &pRecImport));
+ IfFailGo(pMiniMdEmit->AddAssemblyRecord(&pRecEmit, &iRecord));
+
+ pRecEmit->Copy(pRecImport);
+
+ IfFailGo(pMiniMdImport->getPublicKeyOfAssembly(pRecImport, &pbTmp, &cbTmp));
+ IfFailGo(pMiniMdEmit->PutBlob(TBL_Assembly, AssemblyRec::COL_PublicKey, pRecEmit,
+ pbTmp, cbTmp));
+
+ IfFailGo(pMiniMdImport->getNameOfAssembly(pRecImport, &szTmp));
+ IfFailGo(pMiniMdEmit->PutString(TBL_Assembly, AssemblyRec::COL_Name, pRecEmit, szTmp));
+
+ IfFailGo(pMiniMdImport->getLocaleOfAssembly(pRecImport, &szTmp));
+ IfFailGo(pMiniMdEmit->PutString(TBL_Assembly, AssemblyRec::COL_Locale, pRecEmit, szTmp));
+
+ // record the token movement.
+ IfFailGo(pCurTkMap->InsertNotFound(
+ TokenFromRid(1, mdtAssembly),
+ false,
+ TokenFromRid(iRecord, mdtAssembly),
+ &pTokenRec));
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeAssembly()
+
+
+
+
+//*****************************************************************************
+// Merge File table
+//*****************************************************************************
+HRESULT NEWMERGER::MergeFiles()
+{
+ HRESULT hr = NOERROR;
+ FileRec *pRecImport = NULL;
+ FileRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ LPCUTF8 szTmp;
+ const void *pbTmp;
+ ULONG cbTmp;
+ ULONG iCount;
+ ULONG i;
+ ULONG iRecord;
+ TOKENREC *pTokenRec;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountFiles();
+
+ // Loop through all File records and copy them to the Emit scope.
+ // Since there can only be one File table in all the scopes combined,
+ // there isn't any duplicate checking that needs to be done.
+ for (i = 1; i <= iCount; i++)
+ {
+ IfFailGo(pMiniMdImport->GetFileRecord(i, &pRecImport));
+ IfFailGo(pMiniMdEmit->AddFileRecord(&pRecEmit, &iRecord));
+
+ pRecEmit->Copy(pRecImport);
+
+ IfFailGo(pMiniMdImport->getNameOfFile(pRecImport, &szTmp));
+ IfFailGo(pMiniMdEmit->PutString(TBL_File, FileRec::COL_Name, pRecEmit, szTmp));
+
+ IfFailGo(pMiniMdImport->getHashValueOfFile(pRecImport, (const BYTE **)&pbTmp, &cbTmp));
+ IfFailGo(pMiniMdEmit->PutBlob(TBL_File, FileRec::COL_HashValue, pRecEmit, pbTmp, cbTmp));
+
+ // record the token movement.
+ IfFailGo(pCurTkMap->InsertNotFound(
+ TokenFromRid(i, mdtFile),
+ false,
+ TokenFromRid(iRecord, mdtFile),
+ &pTokenRec));
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeFiles()
+
+
+//*****************************************************************************
+// Merge ExportedType table
+//*****************************************************************************
+HRESULT NEWMERGER::MergeExportedTypes()
+{
+ HRESULT hr = NOERROR;
+ ExportedTypeRec *pRecImport = NULL;
+ ExportedTypeRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ LPCUTF8 szTmp;
+ mdToken tkTmp;
+ ULONG iCount;
+ ULONG i;
+ ULONG iRecord;
+ TOKENREC *pTokenRec;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountExportedTypes();
+
+ // Loop through all ExportedType records and copy them to the Emit scope.
+ // Since there can only be one ExportedType table in all the scopes combined,
+ // there isn't any duplicate checking that needs to be done.
+ for (i = 1; i <= iCount; i++)
+ {
+ IfFailGo(pMiniMdImport->GetExportedTypeRecord(i, &pRecImport));
+ IfFailGo(pMiniMdEmit->AddExportedTypeRecord(&pRecEmit, &iRecord));
+
+ pRecEmit->Copy(pRecImport);
+
+ IfFailGo(pMiniMdImport->getTypeNameOfExportedType(pRecImport, &szTmp));
+ IfFailGo(pMiniMdEmit->PutString(TBL_ExportedType, ExportedTypeRec::COL_TypeName, pRecEmit, szTmp));
+
+ IfFailGo(pMiniMdImport->getTypeNamespaceOfExportedType(pRecImport, &szTmp));
+ IfFailGo(pMiniMdEmit->PutString(TBL_ExportedType, ExportedTypeRec::COL_TypeNamespace, pRecEmit, szTmp));
+
+ tkTmp = pMiniMdImport->getImplementationOfExportedType(pRecImport);
+ IfFailGo(pCurTkMap->Remap(tkTmp, &tkTmp));
+ IfFailGo(pMiniMdEmit->PutToken(TBL_ExportedType, ExportedTypeRec::COL_Implementation,
+ pRecEmit, tkTmp));
+
+
+ // record the token movement.
+ IfFailGo(pCurTkMap->InsertNotFound(
+ TokenFromRid(i, mdtExportedType),
+ false,
+ TokenFromRid(iRecord, mdtExportedType),
+ &pTokenRec));
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeExportedTypes()
+
+
+//*****************************************************************************
+// Merge ManifestResource table
+//*****************************************************************************
+HRESULT NEWMERGER::MergeManifestResources()
+{
+ HRESULT hr = NOERROR;
+ ManifestResourceRec *pRecImport = NULL;
+ ManifestResourceRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ LPCUTF8 szTmp;
+ mdToken tkTmp;
+ ULONG iCount;
+ ULONG i;
+ ULONG iRecord;
+ TOKENREC *pTokenRec;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountManifestResources();
+
+ // Loop through all ManifestResource records and copy them to the Emit scope.
+ // Since there can only be one ManifestResource table in all the scopes combined,
+ // there isn't any duplicate checking that needs to be done.
+ for (i = 1; i <= iCount; i++)
+ {
+ IfFailGo(pMiniMdImport->GetManifestResourceRecord(i, &pRecImport));
+ IfFailGo(pMiniMdEmit->AddManifestResourceRecord(&pRecEmit, &iRecord));
+
+ pRecEmit->Copy(pRecImport);
+
+ IfFailGo(pMiniMdImport->getNameOfManifestResource(pRecImport, &szTmp));
+ IfFailGo(pMiniMdEmit->PutString(TBL_ManifestResource, ManifestResourceRec::COL_Name,
+ pRecEmit, szTmp));
+
+ tkTmp = pMiniMdImport->getImplementationOfManifestResource(pRecImport);
+ IfFailGo(pCurTkMap->Remap(tkTmp, &tkTmp));
+ IfFailGo(pMiniMdEmit->PutToken(TBL_ManifestResource, ManifestResourceRec::COL_Implementation,
+ pRecEmit, tkTmp));
+
+ // record the token movement.
+ IfFailGo(pCurTkMap->InsertNotFound(
+ TokenFromRid(i, mdtManifestResource),
+ false,
+ TokenFromRid(iRecord, mdtManifestResource),
+ &pTokenRec));
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeManifestResources()
+
+
+
+
+
+//*****************************************************************************
+// Error handling. Call back to host to see what they want to do.
+//*****************************************************************************
+HRESULT NEWMERGER::OnError(
+ HRESULT hrIn, // The error HR we're reporting.
+ MergeImportData *pImportData, // The input scope with the error.
+ mdToken token) // The token with the error.
+{
+ // This function does a QI and a Release on every call. However, it should be
+ // called very infrequently, and lets the scope just keep a generic handler.
+ IMetaDataError *pIErr = NULL;
+ IUnknown *pHandler = pImportData->m_pHandler;
+ CMiniMdRW *pMiniMd = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ CQuickArray<WCHAR> rName; // Name of the TypeDef in unicode.
+ LPCUTF8 szTypeName;
+ LPCUTF8 szNSName;
+ TypeDefRec *pTypeRec;
+ int iLen; // Length of a name.
+ mdToken tkParent;
+ HRESULT hr = NOERROR;
+
+ if (pHandler && pHandler->QueryInterface(IID_IMetaDataError, (void**)&pIErr)==S_OK)
+ {
+ switch (hrIn)
+ {
+
+ case META_E_PARAM_COUNTS:
+ case META_E_METHD_NOT_FOUND:
+ case META_E_METHDIMPL_INCONSISTENT:
+ {
+ LPCUTF8 szMethodName;
+ MethodRec *pMethodRec;
+
+ // Method name.
+ _ASSERTE(TypeFromToken(token) == mdtMethodDef);
+ IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(token), &pMethodRec));
+ IfFailGo(pMiniMd->getNameOfMethod(pMethodRec, &szMethodName));
+ MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzMethodName, szMethodName);
+ IfNullGo(wzMethodName);
+
+ // Type and its name.
+ IfFailGo( pMiniMd->FindParentOfMethodHelper(token, &tkParent) );
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeRec));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName));
+ // Put namespace + name together.
+ iLen = ns::GetFullLength(szNSName, szTypeName);
+ IfFailGo(rName.ReSizeNoThrow(iLen+1));
+ ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName);
+
+ PostError(hrIn, (LPWSTR) rName.Ptr(), wzMethodName, token);
+ break;
+ }
+ case META_E_FIELD_NOT_FOUND:
+ {
+ LPCUTF8 szFieldName;
+ FieldRec *pFieldRec;
+
+ // Field name.
+ _ASSERTE(TypeFromToken(token) == mdtFieldDef);
+ IfFailGo(pMiniMd->GetFieldRecord(RidFromToken(token), &pFieldRec));
+ IfFailGo(pMiniMd->getNameOfField(pFieldRec, &szFieldName));
+ MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzFieldName, szFieldName);
+ IfNullGo(wzFieldName);
+
+ // Type and its name.
+ IfFailGo( pMiniMd->FindParentOfFieldHelper(token, &tkParent) );
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeRec));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName));
+ // Put namespace + name together.
+ iLen = ns::GetFullLength(szNSName, szTypeName);
+ IfFailGo(rName.ReSizeNoThrow(iLen+1));
+ ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName);
+
+ PostError(hrIn, (LPWSTR) rName.Ptr(), wzFieldName, token);
+ break;
+ }
+ case META_E_EVENT_NOT_FOUND:
+ {
+ LPCUTF8 szEventName;
+ EventRec *pEventRec;
+
+ // Event name.
+ _ASSERTE(TypeFromToken(token) == mdtEvent);
+ IfFailGo(pMiniMd->GetEventRecord(RidFromToken(token), &pEventRec));
+ IfFailGo(pMiniMd->getNameOfEvent(pEventRec, &szEventName));
+ MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzEventName, szEventName);
+ IfNullGo(wzEventName);
+
+ // Type and its name.
+ IfFailGo( pMiniMd->FindParentOfEventHelper(token, &tkParent) );
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeRec));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName));
+ // Put namespace + name together.
+ iLen = ns::GetFullLength(szNSName, szTypeName);
+ IfFailGo(rName.ReSizeNoThrow(iLen+1));
+ ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName);
+
+ PostError(hrIn, (LPWSTR) rName.Ptr(), wzEventName, token);
+ break;
+ }
+ case META_E_PROP_NOT_FOUND:
+ {
+ LPCUTF8 szPropertyName;
+ PropertyRec *pPropertyRec;
+
+ // Property name.
+ _ASSERTE(TypeFromToken(token) == mdtProperty);
+ IfFailGo(pMiniMd->GetPropertyRecord(RidFromToken(token), &pPropertyRec));
+ IfFailGo(pMiniMd->getNameOfProperty(pPropertyRec, &szPropertyName));
+ MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzPropertyName, szPropertyName);
+ IfNullGo(wzPropertyName);
+
+ // Type and its name.
+ IfFailGo( pMiniMd->FindParentOfPropertyHelper(token, &tkParent) );
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeRec));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName));
+ // Put namespace + name together.
+ iLen = ns::GetFullLength(szNSName, szTypeName);
+ IfFailGo(rName.ReSizeNoThrow(iLen+1));
+ ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName);
+
+ PostError(hrIn, (LPWSTR) rName.Ptr(), wzPropertyName, token);
+ break;
+ }
+ case META_S_PARAM_MISMATCH:
+ {
+ LPCUTF8 szMethodName;
+ MethodRec *pMethodRec;
+ mdToken tkMethod;
+
+ // Method name.
+ _ASSERTE(TypeFromToken(token) == mdtParamDef);
+ IfFailGo( pMiniMd->FindParentOfParamHelper(token, &tkMethod) );
+ IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(tkMethod), &pMethodRec));
+ IfFailGo(pMiniMd->getNameOfMethod(pMethodRec, &szMethodName));
+ MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzMethodName, szMethodName);
+ IfNullGo(wzMethodName);
+
+ // Type and its name.
+ IfFailGo( pMiniMd->FindParentOfMethodHelper(token, &tkParent) );
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeRec));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName));
+ // Put namespace + name together.
+ iLen = ns::GetFullLength(szNSName, szTypeName);
+ IfFailGo(rName.ReSizeNoThrow(iLen+1));
+ ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName);
+
+ // use the error hresult so that we can post the correct error.
+ PostError(META_E_PARAM_MISMATCH, wzMethodName, (LPWSTR) rName.Ptr(), token);
+ break;
+ }
+ case META_E_INTFCEIMPL_NOT_FOUND:
+ {
+ InterfaceImplRec *pRec; // The InterfaceImpl
+ mdToken tkIface; // Token of the implemented interface.
+ CQuickArray<WCHAR> rIface; // Name of the Implemented Interface in unicode.
+ TypeRefRec *pRef; // TypeRef record when II is a typeref.
+ InterfaceImplRec *pInterfaceImplRec;
+
+ // Get the record.
+ _ASSERTE(TypeFromToken(token) == mdtInterfaceImpl);
+ IfFailGo(pMiniMd->GetInterfaceImplRecord(RidFromToken(token), &pRec));
+ // Get the name of the class.
+ tkParent = pMiniMd->getClassOfInterfaceImpl(pRec);
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeRec));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName));
+ // Put namespace + name together.
+ iLen = ns::GetFullLength(szNSName, szTypeName);
+ IfFailGo(rName.ReSizeNoThrow(iLen+1));
+ ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName);
+
+ // Get the name of the implemented interface.
+ IfFailGo(pMiniMd->GetInterfaceImplRecord(RidFromToken(token), &pInterfaceImplRec));
+ tkIface = pMiniMd->getInterfaceOfInterfaceImpl(pInterfaceImplRec);
+ if (TypeFromToken(tkIface) == mdtTypeDef)
+ { // If it is a typedef...
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkIface), &pTypeRec));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName));
+ }
+ else
+ { // If it is a typeref...
+ _ASSERTE(TypeFromToken(tkIface) == mdtTypeRef);
+ IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tkIface), &pRef));
+ IfFailGo(pMiniMd->getNameOfTypeRef(pRef, &szTypeName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pRef, &szNSName));
+ }
+ // Put namespace + name together.
+ iLen = ns::GetFullLength(szNSName, szTypeName);
+ IfFailGo(rIface.ReSizeNoThrow(iLen+1));
+ ns::MakePath(rIface.Ptr(), iLen+1, szNSName, szTypeName);
+
+
+ PostError(hrIn, (LPWSTR) rName.Ptr(), (LPWSTR)rIface.Ptr(), token);
+ break;
+ }
+ case META_E_CLASS_LAYOUT_INCONSISTENT:
+ case META_E_METHOD_COUNTS:
+ case META_E_FIELD_COUNTS:
+ case META_E_EVENT_COUNTS:
+ case META_E_PROPERTY_COUNTS:
+ {
+ // get the type name.
+ _ASSERTE(TypeFromToken(token) == mdtTypeDef);
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(token), &pTypeRec));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName));
+ // Put namespace + name together.
+ iLen = ns::GetFullLength(szNSName, szTypeName);
+ IfFailGo(rName.ReSizeNoThrow(iLen+1));
+ ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName);
+
+ PostError(hrIn, (LPWSTR) rName.Ptr(), token);
+ break;
+ }
+ case META_E_GENERICPARAM_INCONSISTENT:
+ {
+ // If token is type, get type name; if method, get method name.
+ LPWSTR wzName;
+ LPCUTF8 szMethodName;
+ MethodRec *pMethodRec;
+
+ if ((TypeFromToken(token) == mdtMethodDef))
+ {
+ // Get the method name.
+ IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(token), &pMethodRec));
+ IfFailGo(pMiniMd->getNameOfMethod(pMethodRec, &szMethodName));
+ MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzMethodName, szMethodName);
+ IfNullGo(wzMethodName);
+ wzName = wzMethodName;
+ }
+ else
+ {
+ // Get the type name.
+ _ASSERTE(TypeFromToken(token) == mdtTypeDef);
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(token), &pTypeRec));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName));
+ // Put namespace + name together.
+ iLen = ns::GetFullLength(szNSName, szTypeName);
+ IfFailGo(rName.ReSizeNoThrow(iLen+1));
+ ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName);
+ wzName = (LPWSTR)rName.Ptr();
+ }
+
+ PostError(hrIn, wzName, token);
+ break;
+ }
+ case META_E_TYPEDEF_MISSING:
+ {
+ TypeRefRec *pRef; // TypeRef record when II is a typeref.
+
+ // Get the record.
+ _ASSERTE(TypeFromToken(token) == mdtTypeRef);
+ IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(token), &pRef));
+ IfFailGo(pMiniMd->getNameOfTypeRef(pRef, &szTypeName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pRef, &szNSName));
+
+ // Put namespace + name together.
+ iLen = ns::GetFullLength(szNSName, szTypeName);
+ IfFailGo(rName.ReSizeNoThrow(iLen+1));
+ ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName);
+
+
+ PostError(hrIn, (LPWSTR) rName.Ptr(), token);
+ break;
+ }
+ default:
+ {
+ PostError(hrIn, token);
+ break;
+ }
+ }
+ hr = pIErr->OnError(hrIn, token);
+ }
+ else
+ hr = S_FALSE;
+ErrExit:
+ if (pIErr)
+ pIErr->Release();
+ return (hr);
+} // NEWMERGER::OnError
+
+#endif //FEATURE_METADATA_EMIT_ALL
diff --git a/src/md/compiler/newmerger.h b/src/md/compiler/newmerger.h
new file mode 100644
index 0000000000..fc89ab7f61
--- /dev/null
+++ b/src/md/compiler/newmerger.h
@@ -0,0 +1,256 @@
+// 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.
+//*****************************************************************************
+// NewMerger.h
+//
+
+//
+// Contains utility code for MD directory
+//
+//*****************************************************************************
+#ifndef __NEWMERGER__h__
+#define __NEWMERGER__h__
+
+class RegMeta;
+
+class MDTOKENMAP;
+
+// module-level awareness of Security critical annotions
+typedef BYTE InputScopeSecurityCriticalStatus;
+#define ISSCS_Unknown 0x0
+#define ISSCS_SecurityCritical 0x1
+#define ISSCS_SecurityCriticalEverything (ISSCS_SecurityCritical | 0x2)
+#define ISSCS_SecurityCriticalExplicit (ISSCS_SecurityCritical)
+#define ISSCS_SecurityTransparent 0x4
+#define ISSCS_SecurityTreatAsSafe 0x8
+#define ISSCS_SECURITYCRITICAL_LEGACY (ISSCS_SecurityCriticalEverything | ISSCS_SecurityTreatAsSafe)
+#define ISSCS_SECURITYCRITICAL_FLAGS (ISSCS_SecurityCriticalEverything | ISSCS_SecurityTransparent)
+
+//*********************************************************************
+// MergeImportData
+//*********************************************************************
+class MergeImportData
+{
+public:
+ RegMeta *m_pRegMetaImport;
+ IUnknown *m_pHandler;
+ IMapToken *m_pHostMapToken;
+ MDTOKENMAP *m_pMDTokenMap;
+ MergeImportData *m_pNextImportData;
+
+ mdMemberRef m_tkSuppressMergeCheckCtor; // caches the SuppressMergeCheckAttribute's .ctor token
+ mdMemberRef m_tkHandleProcessCorruptedStateCtor; // caches the memberRef token to HandleProcessCorruptedStateExceptionsAttribute's .ctor token
+
+ // import contains assembly-level SecurityTransparent or SecurityCritical
+ InputScopeSecurityCriticalStatus m_isscsSecurityCriticalStatus;
+#if _DEBUG
+ int m_iImport; // debug only. This is the ith import for merge.
+#endif // _DEBUG
+};
+
+//*********************************************************************
+// MergeTypeData
+//*********************************************************************
+struct MergeTypeData
+{
+ ULONG m_cMethods;
+ ULONG m_cFields;
+ ULONG m_cEvents;
+ ULONG m_cProperties;
+ BOOL m_bSuppressMergeCheck;
+};
+
+
+//*********************************************************************
+// Class to handle merge
+//*********************************************************************
+class NEWMERGER
+{
+ friend class RegMeta;
+public:
+ NEWMERGER();
+ ~NEWMERGER();
+
+ HRESULT Init(RegMeta *pRegMetaDest);
+
+ HRESULT AddImport(
+ IMetaDataImport2 *pImport, // [IN] The scope to be merged.
+ IMapToken *pHostMapToken, // [IN] Host IMapToken interface to receive token remap notification
+ IUnknown *pHandler); // [IN] An object to receive to receive error notification.
+
+ HRESULT Merge(MergeFlags flags, CorRefToDefCheck optimizeRefToDef);
+
+protected:
+
+ CMiniMdRW *GetMiniMdEmit();
+
+ HRESULT InitMergeTypeData();
+
+ HRESULT MergeTypeDefNamesOnly();
+ HRESULT MergeModuleRefs();
+ HRESULT MergeAssemblyRefs();
+ HRESULT MergeTypeRefs();
+ HRESULT CompleteMergeTypeDefs();
+
+ HRESULT CopyTypeDefPartially(
+ TypeDefRec *pRecEmit, // [IN] the emit record to fill
+ CMiniMdRW *pMiniMdImport, // [IN] the importing scope
+ TypeDefRec *pRecImp); // [IN] the record to import
+
+ // helpers for merging tables
+ HRESULT MergeModule( );
+ HRESULT MergeTypeDefChildren();
+ HRESULT MergeInterfaceImpls( );
+ HRESULT MergeMemberRefs( );
+ HRESULT MergePinvoke();
+
+ HRESULT MergeConstants( );
+ HRESULT MergeCustomAttributes( );
+ HRESULT MergeFieldMarshals( );
+ HRESULT MergeDeclSecuritys( );
+ HRESULT MergeClassLayouts( );
+ HRESULT MergeFieldLayouts( );
+ HRESULT MergeFieldRVAs();
+ HRESULT MergeMethodImpls( );
+ HRESULT MergeStandAloneSigs();
+ HRESULT MergeMethodSpecs();
+ HRESULT MergeTypeSpecs();
+ HRESULT MergeSourceFiles( );
+ HRESULT MergeBlocks( );
+ HRESULT MergeScopes( );
+ HRESULT MergeLocalVariables( );
+ HRESULT MergeStrings( );
+
+ HRESULT MergeAssembly();
+ HRESULT MergeFiles();
+ HRESULT MergeExportedTypes();
+ HRESULT MergeManifestResources();
+
+ // helpers for SecurityCritical-related merging
+ InputScopeSecurityCriticalStatus CheckInputScopeIsCritical(MergeImportData* pImportData, HRESULT& hr);
+ HRESULT RetrieveStandardSecurityCriticalMetaData(
+ mdAssemblyRef& tkMscorlib,
+ mdTypeRef& securityEnum,
+ BYTE*& rgSigBytesSecurityCriticalEverythingCtor,
+ DWORD& dwSigEverythingSize,
+ BYTE*& rgSigBytesSecurityCriticalExplicitCtor,
+ DWORD& dwSigExplicitSize);
+
+ HRESULT MergeSecurityCriticalModuleLevelAttributes(
+ MergeImportData* pImportData,
+ mdToken tkParentImp, TOKENREC* pTypeRec,
+ mdToken mrSecurityTreatAsSafeAttributeCtor,
+ mdToken mrSecurityTransparentAttributeCtor,
+ mdToken mrSecurityCriticalExplicitAttributeCtor,
+ mdToken mrSecurityCriticalEverythingAttributeCtor);
+ HRESULT MergeSecurityCriticalAttributes();
+
+ // copy over a interfaceimpl record
+ HRESULT CopyInterfaceImpl(
+ InterfaceImplRec *pRecEmit, // [IN] the emit record to fill
+ MergeImportData *pImportData, // [IN] the importing context
+ InterfaceImplRec *pRecImp); // [IN] the record to import
+
+ // verification helpers
+ HRESULT VerifyMethods(MergeImportData *pImportData, mdTypeDef tdImp, mdTypeDef tdEmit);
+ HRESULT VerifyFields(MergeImportData *pImportData, mdTypeDef tdImp, mdTypeDef tdEmit);
+ HRESULT VerifyEvents(MergeImportData *pImportData, mdTypeDef tdImp, mdTypeDef tdEmit);
+ HRESULT VerifyProperties(MergeImportData *pImportData, mdTypeDef tdImp, mdTypeDef tdEmit);
+ HRESULT VerifyParams(MergeImportData *pImportData, mdMethodDef mdImp, mdMethodDef mdEmit);
+ HRESULT VerifyGenericParams(MergeImportData *pImportData, mdTypeDef tdImp, mdTypeDef tdEmit);
+ HRESULT VerifyGenericParamConstraints(MergeImportData *pImportData, mdGenericParam gpImp, mdGenericParam gpEmit);
+
+ // Copy helpers
+ HRESULT CopyMethods(MergeImportData *pImportData, mdTypeDef tdImp, mdTypeDef tdEmit);
+ HRESULT CopyFields(MergeImportData *pImportData, mdTypeDef tdImp, mdTypeDef tdEmit);
+ HRESULT CopyEvents(MergeImportData *pImportData, mdTypeDef tdImp, mdTypeDef tdEmit);
+ HRESULT CopyProperties(MergeImportData *pImportData, mdTypeDef tdImp, mdTypeDef tdEmit);
+ HRESULT CopyParams(MergeImportData *pImportData, mdMethodDef mdImp, mdMethodDef mdEmit);
+ HRESULT CopyGenericParams(MergeImportData *pImportData, mdToken tkImp, mdToken tkEmit);
+ HRESULT CopyGenericParamConstraints(MergeImportData *pImportData, mdGenericParam gpImp, mdGenericParam gpEmit);
+
+ HRESULT CopyMethod(
+ MergeImportData *pImportData, // [IN] import scope
+ MethodRec *pRecImp, // [IN] the record to import
+ MethodRec *pRecEmit); // [IN] the emit record to fill
+
+ HRESULT CopyField(
+ MergeImportData *pImportData, // [IN] import scope
+ FieldRec *pRecImp, // [IN] the record to import
+ FieldRec *pRecEmit); // [IN] the emit record to fill
+
+ HRESULT CopyEvent(
+ MergeImportData *pImportData, // [IN] import scope
+ EventRec *pRecImp, // [IN] the record to import
+ EventRec *pRecEmit); // [IN] the emit record to fill
+
+ HRESULT CopyProperty(
+ MergeImportData *pImportData, // [IN] import scope
+ PropertyRec *pRecImp, // [IN] the record to import
+ PropertyRec *pRecEmit); // [IN] the emit record to fill
+
+ HRESULT CopyParam(
+ MergeImportData *pImportData, // [IN] import scope
+ ParamRec *pRecImp, // [IN] the record to import
+ ParamRec *pRecEmit); // [IN] the emit record to fill
+
+ HRESULT CopyMethodSemantics(
+ MergeImportData *pImportData,
+ mdToken tkImport, // Event or property in the import scope
+ mdToken tkEmit); // corresponding event or property in the emitting scope
+
+ HRESULT VerifyMethod(
+ MergeImportData *pImportData,
+ mdMethodDef mdImp, // [IN] the emit record to fill
+ mdMethodDef mdEmit); // [IN] the record to import
+
+ HRESULT OnError(HRESULT hr, MergeImportData *pImportData, mdToken token);
+
+private:
+ RegMeta *m_pRegMetaEmit;
+ MergeImportData *m_pImportDataList;
+ MergeImportData **m_pImportDataTail;
+ MergeFlags m_dwMergeFlags;
+ BOOL m_fDupCheck;
+ CorRefToDefCheck m_optimizeRefToDef;
+ // the combined value of the Security Critical input scopes (e.g. UNION of each scope's attributes)
+ // if ANY of the scopes have a bit set, then we must do some merging
+ InputScopeSecurityCriticalStatus m_isscsSecurityCritical;
+ // the common values of the Security Critical input scopes (e.g. INTERSECTION of each scope's attributes)
+ // if all scopes have the same bit set, then we can emit one bit at the final output scope
+ InputScopeSecurityCriticalStatus m_isscsSecurityCriticalAllScopes;
+
+ CDynArray<MergeTypeData> m_rMTDs;
+#if _DEBUG
+ int m_iImport; // debug only. To count how many import scopes to be merged.
+#endif // _DEBUG
+};
+
+
+#define CheckContinuableErrorEx(EXPR, HANDLER, TOKEN) \
+{ \
+ HRESULT hrOnErr, hrExpr; \
+ hrExpr = EXPR; \
+ \
+ hrOnErr = OnError(hrExpr, HANDLER, TOKEN); \
+ if (hrOnErr != S_OK) \
+ { \
+ if (hrOnErr == S_FALSE) \
+ { \
+ hr = hrExpr; \
+ } \
+ else if (SUCCEEDED(hrOnErr)) \
+ { \
+ hr = E_UNEXPECTED; \
+ } \
+ else if (FAILED(hrOnErr)) \
+ { \
+ hr = hrOnErr; \
+ } \
+ IfFailGo(hr); \
+ } \
+}
+
+
+#endif // __NEWMERGER__h__
diff --git a/src/md/compiler/regmeta.cpp b/src/md/compiler/regmeta.cpp
new file mode 100644
index 0000000000..230d1e4ff0
--- /dev/null
+++ b/src/md/compiler/regmeta.cpp
@@ -0,0 +1,1588 @@
+// 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.
+//*****************************************************************************
+// RegMeta.cpp
+//
+
+//
+// Implementation for meta data public interface methods.
+//
+//*****************************************************************************
+#include "stdafx.h"
+#include "regmeta.h"
+#include "metadata.h"
+#include "corerror.h"
+#include "mdutil.h"
+#include "rwutil.h"
+#include "mdlog.h"
+#include "importhelper.h"
+#include "filtermanager.h"
+#include "mdperf.h"
+#include "switches.h"
+#include "posterror.h"
+#include "stgio.h"
+#include "sstring.h"
+
+#include "mdinternalrw.h"
+
+
+#include <metamodelrw.h>
+
+#define DEFINE_CUSTOM_NODUPCHECK 1
+#define DEFINE_CUSTOM_DUPCHECK 2
+#define SET_CUSTOM 3
+
+#if defined(_DEBUG) && defined(_TRACE_REMAPS)
+#define LOGGING
+#endif
+#include <log.h>
+
+#ifdef _MSC_VER
+#pragma warning(disable: 4102)
+#endif
+
+RegMeta::RegMeta() :
+ m_pStgdb(0),
+ m_pStgdbFreeList(NULL),
+ m_pUnk(0),
+ m_pFilterManager(NULL),
+#ifdef FEATURE_METADATA_INTERNAL_APIS
+ m_pInternalImport(NULL),
+#endif
+ m_pSemReadWrite(NULL),
+ m_fOwnSem(false),
+ m_bRemap(false),
+ m_bSaveOptimized(false),
+ m_hasOptimizedRefToDef(false),
+ m_pHandler(0),
+ m_fIsTypeDefDirty(false),
+ m_fIsMemberDefDirty(false),
+ m_fStartedEE(false),
+#ifdef FEATURE_INCLUDE_ALL_INTERFACES
+ m_pCorHost(NULL),
+#endif // FEATURE_INCLUDE_ALL_INTERFACES
+ m_pAppDomain(NULL),
+ m_OpenFlags(0),
+ m_cRef(0),
+ m_pFreeThreadedMarshaler(NULL),
+ m_bCached(false),
+ m_trLanguageType(0),
+ m_SetAPICaller(EXTERNAL_CALLER),
+ m_ModuleType(ValidatorModuleTypeInvalid),
+ m_pVEHandler(0),
+ m_bKeepKnownCa(false),
+ m_pCorProfileData(NULL),
+ m_ReorderingOptions(NoReordering)
+#ifdef FEATURE_METADATA_RELEASE_MEMORY_ON_REOPEN
+ , m_safeToDeleteStgdb(true)
+#endif
+{
+ memset(&m_OptionValue, 0, sizeof(OptionValue));
+
+#ifdef _DEBUG
+ if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_RegMetaBreak))
+ {
+ _ASSERTE(!"RegMeta()");
+ }
+ if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_KeepKnownCA))
+ m_bKeepKnownCa = true;
+#endif // _DEBUG
+
+} // RegMeta::RegMeta()
+
+RegMeta::~RegMeta()
+{
+ BEGIN_CLEANUP_ENTRYPOINT;
+
+ _ASSERTE(!m_bCached);
+
+ HRESULT hr = S_OK;
+
+ LOCKWRITENORET();
+
+#ifdef FEATURE_METADATA_INTERNAL_APIS
+ // This should have worked if we've cached the public interface in the past
+ _ASSERTE(SUCCEEDED(hr) || (m_pInternalImport == NULL) || (m_pInternalImport->GetCachedPublicInterface(false) == NULL));
+#endif //FEATURE_METADATA_INTERNAL_APIS
+
+ if (SUCCEEDED(hr))
+ {
+#ifdef FEATURE_METADATA_INTERNAL_APIS
+ if (m_pInternalImport != NULL)
+ {
+ // RegMeta is going away. Make sure we clear up the pointer from MDInternalRW to this RegMeta.
+ if (FAILED(m_pInternalImport->SetCachedPublicInterface(NULL)))
+ { // Do nothing on error
+ }
+ m_pInternalImport = NULL;
+ m_fOwnSem = false;
+ }
+#endif //FEATURE_METADATA_INTERNAL_APIS
+
+ UNLOCKWRITE();
+ }
+
+ if (m_pFreeThreadedMarshaler)
+ {
+ m_pFreeThreadedMarshaler->Release();
+ m_pFreeThreadedMarshaler = NULL;
+ }
+
+ if (m_pSemReadWrite && m_fOwnSem)
+ delete m_pSemReadWrite;
+
+ // If this RegMeta is a wrapper on an external StgDB, release it.
+ if (IsOfExternalStgDB(m_OpenFlags))
+ {
+ _ASSERTE(m_pUnk != NULL); // Owning IUnknown for external StgDB.
+ if (m_pUnk)
+ m_pUnk->Release();
+ m_pUnk = 0;
+ }
+ else
+ { // Not a wrapper, so free our StgDB.
+ _ASSERTE(m_pUnk == NULL);
+ // It's possible m_pStdbg is NULL in OOM scenarios
+ if (m_pStgdb != NULL)
+ delete m_pStgdb;
+ m_pStgdb = 0;
+ }
+
+ // Delete the old copies of Stgdb list. This is the list track all of the
+ // old snapshuts with ReOpenWithMemory call.
+ CLiteWeightStgdbRW *pCur;
+ while (m_pStgdbFreeList)
+ {
+ pCur = m_pStgdbFreeList;
+ m_pStgdbFreeList = m_pStgdbFreeList->m_pNextStgdb;
+ delete pCur;
+ }
+
+ if (m_pVEHandler)
+ m_pVEHandler->Release();
+
+ // If This RegMeta spun up the runtime (probably to process security
+ // attributes), shut it down now.
+ if (m_fStartedEE)
+ {
+ m_pAppDomain->Release();
+#ifdef FEATURE_INCLUDE_ALL_INTERFACES
+ m_pCorHost->Stop();
+ m_pCorHost->Release();
+#endif // FEATURE_INCLUDE_ALL_INTERFACES
+ }
+
+ if (m_pFilterManager != NULL)
+ delete m_pFilterManager;
+
+
+ if (m_OptionValue.m_RuntimeVersion != NULL)
+ delete[] m_OptionValue.m_RuntimeVersion;
+
+ END_CLEANUP_ENTRYPOINT;
+
+} // RegMeta::~RegMeta()
+
+HRESULT RegMeta::SetOption(OptionValue *pOptionValue)
+{
+ _ASSERTE(pOptionValue);
+ char* pszRuntimeVersion = NULL;
+
+ if (pOptionValue->m_RuntimeVersion != NULL)
+ {
+ SIZE_T dwBufferSize = strlen(pOptionValue->m_RuntimeVersion) + 1; // +1 for null
+ pszRuntimeVersion = new (nothrow) char[dwBufferSize];
+ if (pszRuntimeVersion == NULL)
+ {
+ return E_OUTOFMEMORY;
+ }
+ strcpy_s(pszRuntimeVersion, dwBufferSize, pOptionValue->m_RuntimeVersion);
+ }
+
+ memcpy(&m_OptionValue, pOptionValue, sizeof(OptionValue));
+ m_OptionValue.m_RuntimeVersion = pszRuntimeVersion;
+
+ return S_OK;
+}// SetOption
+
+
+//*****************************************************************************
+// Initialize with an existing stgdb.
+//*****************************************************************************
+__checkReturn
+HRESULT
+RegMeta::InitWithStgdb(
+ IUnknown *pUnk, // The IUnknown that owns the life time for the existing stgdb
+ CLiteWeightStgdbRW *pStgdb) // existing light weight stgdb
+{
+ // RegMeta created this way will not create a read/write lock semaphore.
+ HRESULT hr = S_OK;
+
+ _ASSERTE(m_pStgdb == NULL);
+ m_tdModule = COR_GLOBAL_PARENT_TOKEN;
+ m_pStgdb = pStgdb;
+
+ m_OpenFlags = ofExternalStgDB;
+
+ // remember the owner of the light weight stgdb
+ // AddRef it to ensure the lifetime
+ //
+ m_pUnk = pUnk;
+ m_pUnk->AddRef();
+ IfFailGo(m_pStgdb->m_MiniMd.GetOption(&m_OptionValue));
+ErrExit:
+ return hr;
+} // RegMeta::InitWithStgdb
+
+#ifdef FEATURE_METADATA_EMIT
+
+//*****************************************************************************
+// call stgdb InitNew
+//*****************************************************************************
+__checkReturn
+HRESULT
+RegMeta::CreateNewMD()
+{
+ HRESULT hr = NOERROR;
+
+ m_OpenFlags = ofWrite;
+
+ // Allocate our m_pStgdb.
+ _ASSERTE(m_pStgdb == NULL);
+ IfNullGo(m_pStgdb = new (nothrow) CLiteWeightStgdbRW);
+
+ // Initialize the new, empty database.
+
+ // First tell the new database what sort of metadata to create
+ m_pStgdb->m_MiniMd.m_OptionValue.m_MetadataVersion = m_OptionValue.m_MetadataVersion;
+ m_pStgdb->m_MiniMd.m_OptionValue.m_InitialSize = m_OptionValue.m_InitialSize;
+ IfFailGo(m_pStgdb->InitNew());
+
+ // Set up the Module record.
+ ULONG iRecord;
+ ModuleRec *pModule;
+ GUID mvid;
+ IfFailGo(m_pStgdb->m_MiniMd.AddModuleRecord(&pModule, &iRecord));
+ IfFailGo(CoCreateGuid(&mvid));
+ IfFailGo(m_pStgdb->m_MiniMd.PutGuid(TBL_Module, ModuleRec::COL_Mvid, pModule, mvid));
+
+ // Add the dummy module typedef which we are using to parent global items.
+ TypeDefRec *pRecord;
+ IfFailGo(m_pStgdb->m_MiniMd.AddTypeDefRecord(&pRecord, &iRecord));
+ m_tdModule = TokenFromRid(iRecord, mdtTypeDef);
+ IfFailGo(m_pStgdb->m_MiniMd.PutStringW(TBL_TypeDef, TypeDefRec::COL_Name, pRecord, COR_WMODULE_CLASS));
+ IfFailGo(m_pStgdb->m_MiniMd.SetOption(&m_OptionValue));
+
+ if (IsThreadSafetyOn())
+ {
+ m_pSemReadWrite = new (nothrow) UTSemReadWrite();
+ IfNullGo(m_pSemReadWrite);
+ IfFailGo(m_pSemReadWrite->Init());
+ m_fOwnSem = true;
+
+ INDEBUG(m_pStgdb->m_MiniMd.Debug_SetLock(m_pSemReadWrite);)
+ }
+
+#ifdef FEATURE_METADATA_EMIT_ALL
+ // initialize the embedded merger
+ m_newMerger.Init(this);
+#endif //FEATURE_METADATA_EMIT_ALL
+
+ErrExit:
+ return hr;
+} // RegMeta::CreateNewMD
+
+#endif //FEATURE_METADATA_EMIT
+
+//*****************************************************************************
+// call stgdb OpenForRead
+//*****************************************************************************
+HRESULT RegMeta::OpenExistingMD(
+ LPCWSTR szDatabase, // Name of database.
+ void *pData, // Data to open on top of, 0 default.
+ ULONG cbData, // How big is the data.
+ ULONG dwOpenFlags) // Flags for the open.
+{
+ HRESULT hr = NOERROR;
+ void *pbData = pData; // Pointer to original or copied data.
+
+
+
+ m_OpenFlags = dwOpenFlags;
+
+ if (!IsOfReOpen(dwOpenFlags))
+ {
+ // Allocate our m_pStgdb, if we should.
+ _ASSERTE(m_pStgdb == NULL);
+ IfNullGo( m_pStgdb = new (nothrow) CLiteWeightStgdbRW );
+ }
+
+ IfFailGo( m_pStgdb->OpenForRead(
+ szDatabase,
+ pbData,
+ cbData,
+ m_OpenFlags) );
+
+ if (m_pStgdb->m_MiniMd.m_Schema.m_major == METAMODEL_MAJOR_VER_V1_0 &&
+ m_pStgdb->m_MiniMd.m_Schema.m_minor == METAMODEL_MINOR_VER_V1_0)
+ m_OptionValue.m_MetadataVersion = MDVersion1;
+
+ else
+ m_OptionValue.m_MetadataVersion = MDVersion2;
+
+
+
+ IfFailGo( m_pStgdb->m_MiniMd.SetOption(&m_OptionValue) );
+
+ if (IsThreadSafetyOn())
+ {
+ m_pSemReadWrite = new (nothrow) UTSemReadWrite();
+ IfNullGo(m_pSemReadWrite);
+ IfFailGo(m_pSemReadWrite->Init());
+ m_fOwnSem = true;
+
+ INDEBUG(m_pStgdb->m_MiniMd.Debug_SetLock(m_pSemReadWrite);)
+ }
+
+ if (!IsOfReOpen(dwOpenFlags))
+ {
+#ifdef FEATURE_METADATA_EMIT_ALL
+ // initialize the embedded merger
+ m_newMerger.Init(this);
+#endif //FEATURE_METADATA_EMIT_ALL
+
+ // There must always be a Global Module class and its the first entry in
+ // the TypeDef table.
+ m_tdModule = TokenFromRid(1, mdtTypeDef);
+ }
+
+ErrExit:
+
+ return hr;
+} //RegMeta::OpenExistingMD
+
+#ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE
+HRESULT RegMeta::OpenExistingMD(
+ IMDCustomDataSource* pDataSource, // Name of database.
+ ULONG dwOpenFlags) // Flags to control open.
+{
+ HRESULT hr = NOERROR;
+
+ m_OpenFlags = dwOpenFlags;
+
+ if (!IsOfReOpen(dwOpenFlags))
+ {
+ // Allocate our m_pStgdb, if we should.
+ _ASSERTE(m_pStgdb == NULL);
+ IfNullGo(m_pStgdb = new (nothrow)CLiteWeightStgdbRW);
+ }
+
+ IfFailGo(m_pStgdb->OpenForRead(
+ pDataSource,
+ m_OpenFlags));
+
+ if (m_pStgdb->m_MiniMd.m_Schema.m_major == METAMODEL_MAJOR_VER_V1_0 &&
+ m_pStgdb->m_MiniMd.m_Schema.m_minor == METAMODEL_MINOR_VER_V1_0)
+ m_OptionValue.m_MetadataVersion = MDVersion1;
+
+ else
+ m_OptionValue.m_MetadataVersion = MDVersion2;
+
+
+
+ IfFailGo(m_pStgdb->m_MiniMd.SetOption(&m_OptionValue));
+
+ if (IsThreadSafetyOn())
+ {
+ m_pSemReadWrite = new (nothrow)UTSemReadWrite();
+ IfNullGo(m_pSemReadWrite);
+ IfFailGo(m_pSemReadWrite->Init());
+ m_fOwnSem = true;
+
+ INDEBUG(m_pStgdb->m_MiniMd.Debug_SetLock(m_pSemReadWrite);)
+ }
+
+ if (!IsOfReOpen(dwOpenFlags))
+ {
+#ifdef FEATURE_METADATA_EMIT_ALL
+ // initialize the embedded merger
+ m_newMerger.Init(this);
+#endif //FEATURE_METADATA_EMIT_ALL
+
+ // There must always be a Global Module class and its the first entry in
+ // the TypeDef table.
+ m_tdModule = TokenFromRid(1, mdtTypeDef);
+ }
+
+ErrExit:
+
+ return hr;
+} //RegMeta::OpenExistingMD
+#endif // FEATURE_METADATA_CUSTOM_DATA_SOURCE
+
+#ifdef FEATURE_METADATA_INTERNAL_APIS
+
+//*****************************************************************************
+// Gets a cached Internal importer, if available.
+//
+// Arguments:
+// fWithLock - if true, takes a reader lock.
+// If false, assumes caller is handling the synchronization.
+//
+// Returns:
+// A cached Internal importer, which gets addreffed. Caller must release!
+// If no importer is set, returns NULL
+//
+// Notes:
+// This function also does not trigger the creation of Internal interface.
+// Set the cached importer via code:RegMeta.SetCachedInternalInterface
+//
+// Implements internal API code:IMetaDataHelper::GetCachedInternalInterface.
+//*****************************************************************************
+IUnknown* RegMeta::GetCachedInternalInterface(BOOL fWithLock)
+{
+ IUnknown *pRet = NULL;
+ HRESULT hr = S_OK;
+
+ if (fWithLock)
+ {
+ LOCKREAD();
+
+ pRet = m_pInternalImport;
+ }
+ else
+ {
+ pRet = m_pInternalImport;
+ }
+ if (pRet) pRet->AddRef();
+
+ErrExit:
+
+ return pRet;
+} //RegMeta::GetCachedInternalInterface
+
+//*****************************************************************************
+// Set the cached Internal interface. This function will return an Error is the
+// current cached internal interface is not empty and trying set a non-empty internal
+// interface. One RegMeta will only associated
+// with one Internal Object. Unless we have bugs somewhere else. It will QI on the
+// IUnknown for the IMDInternalImport. If this failed, error will be returned.
+// Note: Caller should take a write lock
+//
+// This does addref the importer (the public and private importers maintain
+// weak references to each other).
+//
+// Implements internal API code:IMetaDataHelper::SetCachedInternalInterface.
+//*****************************************************************************
+HRESULT RegMeta::SetCachedInternalInterface(IUnknown *pUnk)
+{
+ HRESULT hr = NOERROR;
+ IMDInternalImport *pInternal = NULL;
+
+ if (pUnk)
+ {
+ if (m_pInternalImport)
+ {
+ _ASSERTE(!"Bad state!");
+ }
+ IfFailRet( pUnk->QueryInterface(IID_IMDInternalImport, (void **) &pInternal) );
+
+ // Should be non-null
+ _ASSERTE(pInternal);
+ m_pInternalImport = pInternal;
+
+ // We don't want to add ref the internal interface, so undo the AddRef() from the QI.
+ pInternal->Release();
+ }
+ else
+ {
+ // Internal interface is going away before the public interface. Take ownership on the
+ // reader writer lock.
+ m_fOwnSem = true;
+ m_pInternalImport = NULL;
+ }
+ return hr;
+} // RegMeta::SetCachedInternalInterface
+
+#endif //FEATURE_METADATA_INTERNAL_APIS
+
+//*****************************************************************************
+// IUnknown
+//*****************************************************************************
+
+ULONG RegMeta::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+} // ULONG RegMeta::AddRef()
+
+
+HRESULT
+RegMeta::QueryInterface(
+ REFIID riid,
+ void ** ppUnk)
+{
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW;
+ int fIsInterfaceRW = false;
+ *ppUnk = 0;
+
+ if (riid == IID_IUnknown)
+ {
+ *ppUnk = (IUnknown *)(IMetaDataImport2 *)this;
+ }
+ else if (riid == IID_IMDCommon)
+ {
+ *ppUnk = (IMDCommon *)this;
+ }
+ else if (riid == IID_IMetaDataImport)
+ {
+ *ppUnk = (IMetaDataImport2 *)this;
+ }
+ else if (riid == IID_IMetaDataImport2)
+ {
+ *ppUnk = (IMetaDataImport2 *)this;
+ }
+ else if (riid == IID_IMetaDataAssemblyImport)
+ {
+ *ppUnk = (IMetaDataAssemblyImport *)this;
+ }
+ else if (riid == IID_IMetaDataTables)
+ {
+ *ppUnk = static_cast<IMetaDataTables *>(this);
+ }
+ else if (riid == IID_IMetaDataTables2)
+ {
+ *ppUnk = static_cast<IMetaDataTables2 *>(this);
+ }
+
+#ifndef FEATURE_METADATA_STANDALONE_WINRT
+ else if (riid == IID_IMetaDataInfo)
+ {
+ *ppUnk = static_cast<IMetaDataInfo *>(this);
+ }
+#endif //!FEATURE_METADATA_STANDALONE_WINRT
+
+#ifdef FEATURE_METADATA_EMIT
+ else if (riid == IID_IMetaDataEmit)
+ {
+ *ppUnk = (IMetaDataEmit2 *)this;
+ fIsInterfaceRW = true;
+ }
+ else if (riid == IID_IMetaDataEmit2)
+ {
+ *ppUnk = (IMetaDataEmit2 *)this;
+ fIsInterfaceRW = true;
+ }
+ else if (riid == IID_IMetaDataAssemblyEmit)
+ {
+ *ppUnk = (IMetaDataAssemblyEmit *)this;
+ fIsInterfaceRW = true;
+ }
+#endif //FEATURE_METADATA_EMIT
+
+#if defined(FEATURE_METADATA_IN_VM) && !defined(FEATURE_CORECLR)
+ else if (riid == IID_IMetaDataValidate)
+ {
+ *ppUnk = (IMetaDataValidate *)this;
+ }
+#endif //defined(FEATURE_METADATA_IN_VM) && !defined(FEATURE_CORECLR)
+
+#ifdef FEATURE_METADATA_EMIT_ALL
+ else if (riid == IID_IMetaDataFilter)
+ {
+ *ppUnk = (IMetaDataFilter *)this;
+ }
+#endif //FEATURE_METADATA_EMIT_ALL
+
+#ifdef FEATURE_METADATA_INTERNAL_APIS
+ else if (riid == IID_IMetaDataHelper)
+ {
+ *ppUnk = (IMetaDataHelper *)this;
+ }
+ else if (riid == IID_IMDInternalEmit)
+ {
+ *ppUnk = static_cast<IMDInternalEmit *>(this);
+ }
+ else if (riid == IID_IGetIMDInternalImport)
+ {
+ *ppUnk = static_cast<IGetIMDInternalImport *>(this);
+ }
+#endif //FEATURE_METADATA_INTERNAL_APIS
+
+#if defined(FEATURE_METADATA_EMIT) && defined(FEATURE_METADATA_INTERNAL_APIS)
+ else if (riid == IID_IMetaDataEmitHelper)
+ {
+ *ppUnk = (IMetaDataEmitHelper *)this;
+ fIsInterfaceRW = true;
+ }
+#endif //FEATURE_METADATA_EMIT && FEATURE_METADATA_INTERNAL_APIS
+
+#ifdef FEATURE_METADATA_IN_VM
+#ifdef FEATURE_COMINTEROP
+ else if (riid == IID_IMarshal)
+ {
+ // We will only repond to this interface if scope is opened for ReadOnly
+ if (IsOfReadOnly(m_OpenFlags))
+ {
+ if (m_pFreeThreadedMarshaler == NULL)
+ {
+ // Guard ourselves against first time QI on IMarshal from two different threads..
+ LOCKWRITE();
+ if (m_pFreeThreadedMarshaler == NULL)
+ {
+ // First time! Create the FreeThreadedMarshaler
+ IfFailGo(CoCreateFreeThreadedMarshaler((IUnknown *)(IMetaDataEmit2 *)this, &m_pFreeThreadedMarshaler));
+ }
+ }
+
+ _ASSERTE(m_pFreeThreadedMarshaler != NULL);
+
+ IfFailGo(m_pFreeThreadedMarshaler->QueryInterface(riid, ppUnk));
+
+ // AddRef has happened in the QueryInterface and thus should just return
+ goto ErrExit;
+ }
+ else
+ {
+ IfFailGo(E_NOINTERFACE);
+ }
+ }
+#endif // FEATURE_COMINTEROP
+#ifdef FEATURE_PREJIT
+ else if (riid == IID_IMetaDataCorProfileData)
+ {
+ *ppUnk = (IMetaDataCorProfileData *)this;
+ }
+ else if (riid == IID_IMDInternalMetadataReorderingOptions)
+ {
+ *ppUnk = (IMDInternalMetadataReorderingOptions *)this;
+ }
+#endif //FEATURE_PREJIT
+#endif //FEATURE_METADATA_IN_VM
+ else
+ {
+ IfFailGo(E_NOINTERFACE);
+ }
+
+ if (fIsInterfaceRW && IsOfReadOnly(m_OpenFlags))
+ {
+ // They are asking for a read/write interface and this scope was
+ // opened as Read-Only
+
+ *ppUnk = NULL;
+ IfFailGo(CLDB_E_INCOMPATIBLE);
+ }
+
+ if (fIsInterfaceRW)
+ {
+ LOCKWRITENORET();
+
+ if (SUCCEEDED(hr))
+ {
+ hr = m_pStgdb->m_MiniMd.ConvertToRW();
+ }
+
+ if (FAILED(hr))
+ {
+ *ppUnk = NULL;
+ goto ErrExit;
+ }
+ }
+
+ AddRef();
+ErrExit:
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::QueryInterface
+
+#ifndef FEATURE_METADATA_STANDALONE_WINRT
+
+//---------------------------------------------------------------------------------------
+//
+// Returns the memory region of the mapped file and type of its mapping. The choice of the file mapping type
+// for each scope is CLR implementation specific and user cannot explicitly set it.
+//
+// The memory is valid only as long as the underlying MetaData scope is opened (there's a reference to
+// a MetaData interface for this scope).
+//
+// Implements public API code:IMetaDataInfo::GetFileMapping.
+//
+// Arguments:
+// ppvData - Fills with pointer to the start of the mapped file.
+// pcbData - Fills with the size of the mapped memory region (for flat-mapping it is the size of the
+// file).
+// pdwMappingType - Fills with type of file mapping (code:CorFileMapping).
+// Current CLR implementation returns always code:fmFlat. The other value(s) are reserved for future
+// usage. See code:StgIO::MapFileToMem#CreateFileMapping_SEC_IMAGE for more details.
+//
+// Return Value:
+// S_OK - All output data are filled.
+// COR_E_NOTSUPPORTED - CLR cannot (or doesn't want to) provide the memory region.
+// This can happen when:
+// - The MetaData scope was opened with flag code:ofWrite or code:ofCopyMemory.
+// Note: code:ofCopyMemory could be supported in future CLR versions. For example if we change
+// code:CLiteWeightStgdbRW::OpenForRead to copy whole file (or add a new flag ofCopyWholeFile).
+// - The MetaData scope was opened without flag code:ofReadOnly.
+// Note: We could support this API without code:ofReadOnly flag in future CLR versions. We just
+// need some test coverage and user scenario for it.
+// - Only MetaData part of the file was opened using code:OpenScopeOnMemory.
+// - The file is not NT PE file (e.g. it is NT OBJ = .obj file produced by managed C++).
+// E_INVALIDARG - NULL was passed as an argument value.
+//
+HRESULT
+RegMeta::GetFileMapping(
+ const void ** ppvData,
+ ULONGLONG * pcbData,
+ DWORD * pdwMappingType)
+{
+ HRESULT hr = S_OK;
+
+ if ((ppvData == NULL) || (pcbData == NULL) || (pdwMappingType == NULL))
+ {
+ return E_INVALIDARG;
+ }
+
+ // Note: Some of the following checks are duplicit (as some combinations are invalid and ensured by CLR
+ // implementation), but it is easier to check them all
+
+ // OpenScope flags have to be (ofRead | ofReadOnly) and not ofCopyMemory
+ // (as code:CLiteWeightStgdbRW::OpenForRead will copy only the MetaData part of the file)
+ if (((m_OpenFlags & ofReadWriteMask) != ofRead) ||
+ ((m_OpenFlags & ofReadOnly) == 0) ||
+ ((m_OpenFlags & ofCopyMemory) != 0))
+ {
+ IfFailGo(COR_E_NOTSUPPORTED);
+ }
+ // The file has to be NT PE file (not CLDB = managed C++ .obj file) and we have to have its full mapping
+ // (see code:CLiteWeightStgdbRW::OpenForRead)
+ if ((m_pStgdb->m_pImage == NULL) ||
+ (m_pStgdb->m_dwImageSize == 0) ||
+ (m_pStgdb->GetFileType() != FILETYPE_NTPE))
+ {
+ IfFailGo(COR_E_NOTSUPPORTED);
+ }
+ if (m_pStgdb->m_pStgIO->GetFlags() != DBPROP_TMODEF_READ)
+ {
+ IfFailGo(COR_E_NOTSUPPORTED);
+ }
+ // The file has to be flat-mapped, or copied to memory (file mapping code:MTYPE_IMAGE is not currently
+ // supported - see code:StgIO::MapFileToMem#CreateFileMapping_SEC_IMAGE)
+ // Note: Only small files (<=64K) are copied to memory - see code:StgIO::MapFileToMem#CopySmallFiles
+ if ((m_pStgdb->m_pStgIO->GetMemoryMappedType() != MTYPE_FLAT) &&
+ (m_pStgdb->m_pStgIO->GetMemoryMappedType() != MTYPE_NOMAPPING))
+ {
+ IfFailGo(COR_E_NOTSUPPORTED);
+ }
+ // All necessary conditions are satisfied
+
+ *ppvData = m_pStgdb->m_pImage;
+ *pcbData = m_pStgdb->m_dwImageSize;
+ // We checked that the file was flat-mapped above
+ *pdwMappingType = fmFlat;
+
+ErrExit:
+ if (FAILED(hr))
+ {
+ *ppvData = NULL;
+ *pcbData = 0;
+ *pdwMappingType = 0;
+ }
+
+ return hr;
+} // RegMeta::GetFileMapping
+
+#endif //!FEATURE_METADATA_STANDALONE_WINRT
+
+//------------------------------------------------------------------------------
+// Metadata dump
+//
+#ifdef _DEBUG
+
+#define STRING_BUFFER_LEN 1024
+#define ENUM_BUFFER_SIZE 10
+
+int DumpMD_Write(__in __in_z const char *str)
+{
+ OutputDebugStringA(str);
+ return 0; // strlen(str);
+} // int DumpMD_Write()
+
+int DumpMD_WriteLine(__in __in_z const char *str)
+{
+ OutputDebugStringA(str);
+ OutputDebugStringA("\n");
+ return 0; // strlen(str);
+} // int DumpMD_Write()
+
+int DumpMD_VWriteMarker(__in __in_z const char *str, va_list marker)
+{
+ CQuickBytes m_output;
+
+ int count = -1;
+ int i = 1;
+ HRESULT hr;
+
+ while (count < 0)
+ {
+ if (FAILED(hr = m_output.ReSizeNoThrow(STRING_BUFFER_LEN * i)))
+ return 0;
+ count = _vsnprintf((char *)m_output.Ptr(), STRING_BUFFER_LEN * i, str, marker);
+ i *= 2;
+ }
+ OutputDebugStringA((LPCSTR)m_output.Ptr());
+ return count;
+} // int DumpMD_VWriteMarker()
+
+int DumpMD_VWrite(__in __in_z const char *str, ...)
+{
+ va_list marker;
+ int count;
+
+ va_start(marker, str);
+ count = DumpMD_VWriteMarker(str, marker);
+ va_end(marker);
+ return count;
+} // int DumpMD_VWrite()
+
+int DumpMD_VWriteLine(__in __in_z const char *str, ...)
+{
+ va_list marker;
+ int count;
+
+ va_start(marker, str);
+ count = DumpMD_VWriteMarker(str, marker);
+ DumpMD_Write("\n");
+ va_end(marker);
+ return count;
+} // int DumpMD_VWriteLine()
+
+
+const char *DumpMD_DumpRawNameOfType(RegMeta *pMD, ULONG iType)
+{
+ if (iType <= iRidMax)
+ {
+ const char *pNameTable;
+ pMD->GetTableInfo(iType, 0,0,0,0, &pNameTable);
+ return pNameTable;
+ }
+ else
+ // Is the field a coded token?
+ if (iType <= iCodedTokenMax)
+ {
+ int iCdTkn = iType - iCodedToken;
+ const char *pNameCdTkn;
+ pMD->GetCodedTokenInfo(iCdTkn, 0,0, &pNameCdTkn);
+ return pNameCdTkn;
+ }
+
+ // Fixed type.
+ switch (iType)
+ {
+ case iBYTE:
+ return "BYTE";
+ case iSHORT:
+ return "short";
+ case iUSHORT:
+ return "USHORT";
+ case iLONG:
+ return "long";
+ case iULONG:
+ return "ULONG";
+ case iSTRING:
+ return "string";
+ case iGUID:
+ return "GUID";
+ case iBLOB:
+ return "blob";
+ }
+ // default:
+ static char buf[30];
+ sprintf_s(buf, NumItems(buf), "unknown type 0x%02x", iType);
+ return buf;
+} // const char *DumpMD_DumpRawNameOfType()
+
+void DumpMD_DumpRawCol(RegMeta *pMD, ULONG ixTbl, ULONG ixCol, ULONG rid, bool bStats)
+{
+ ULONG ulType; // Type of a column.
+ ULONG ulVal; // Value of a column.
+ LPCUTF8 pString; // Pointer to a string.
+ const void *pBlob; // Pointer to a blob.
+ ULONG cb; // Size of something.
+
+ pMD->GetColumn(ixTbl, ixCol, rid, &ulVal);
+ pMD->GetColumnInfo(ixTbl, ixCol, 0, 0, &ulType, 0);
+
+ if (ulType <= iRidMax)
+ {
+ const char *pNameTable;
+ pMD->GetTableInfo(ulType, 0,0,0,0, &pNameTable);
+ DumpMD_VWrite("%s[%x]", pNameTable, ulVal);
+ }
+ else
+ // Is the field a coded token?
+ if (ulType <= iCodedTokenMax)
+ {
+ int iCdTkn = ulType - iCodedToken;
+ const char *pNameCdTkn;
+ pMD->GetCodedTokenInfo(iCdTkn, 0,0, &pNameCdTkn);
+ DumpMD_VWrite("%s[%08x]", pNameCdTkn, ulVal);
+ }
+ else
+ {
+ // Fixed type.
+ switch (ulType)
+ {
+ case iBYTE:
+ DumpMD_VWrite("%02x", ulVal);
+ break;
+ case iSHORT:
+ case iUSHORT:
+ DumpMD_VWrite("%04x", ulVal);
+ break;
+ case iLONG:
+ case iULONG:
+ DumpMD_VWrite("%08x", ulVal);
+ break;
+ case iSTRING:
+ DumpMD_VWrite("string#%x", ulVal);
+ if (bStats && ulVal)
+ {
+ pMD->GetString(ulVal, &pString);
+ cb = (ULONG) strlen(pString) + 1;
+ DumpMD_VWrite("(%d)", cb);
+ }
+ break;
+ case iGUID:
+ DumpMD_VWrite("guid#%x", ulVal);
+ if (bStats && ulVal)
+ {
+ DumpMD_VWrite("(16)");
+ }
+ break;
+ case iBLOB:
+ DumpMD_VWrite("blob#%x", ulVal);
+ if (bStats && ulVal)
+ {
+ pMD->GetBlob(ulVal, &cb, &pBlob);
+ cb += 1;
+ if (cb > 128)
+ cb += 1;
+ if (cb > 16535)
+ cb += 1;
+ DumpMD_VWrite("(%d)", cb);
+ }
+ break;
+ default:
+ DumpMD_VWrite("unknown type 0x%04x", ulVal);
+ break;
+ }
+ }
+} // void DumpMD_DumpRawCol()
+
+ULONG DumpMD_DumpRawColStats(RegMeta *pMD, ULONG ixTbl, ULONG ixCol, ULONG cRows)
+{
+ ULONG rslt = 0;
+ ULONG ulType; // Type of a column.
+ ULONG ulVal; // Value of a column.
+ LPCUTF8 pString; // Pointer to a string.
+ const void *pBlob; // Pointer to a blob.
+ ULONG cb; // Size of something.
+
+ pMD->GetColumnInfo(ixTbl, ixCol, 0, 0, &ulType, 0);
+
+ if (IsHeapType(ulType))
+ {
+ for (ULONG rid=1; rid<=cRows; ++rid)
+ {
+ pMD->GetColumn(ixTbl, ixCol, rid, &ulVal);
+ // Fixed type.
+ switch (ulType)
+ {
+ case iSTRING:
+ if (ulVal)
+ {
+ pMD->GetString(ulVal, &pString);
+ cb = (ULONG) strlen(pString);
+ rslt += cb + 1;
+ }
+ break;
+ case iGUID:
+ if (ulVal)
+ rslt += 16;
+ break;
+ case iBLOB:
+ if (ulVal)
+ {
+ pMD->GetBlob(ulVal, &cb, &pBlob);
+ rslt += cb + 1;
+ if (cb > 128)
+ rslt += 1;
+ if (cb > 16535)
+ rslt += 1;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return rslt;
+} // ULONG DumpMD_DumpRawColStats()
+
+int DumpMD_DumpHex(
+ const char *szPrefix, // String prefix for first line.
+ const void *pvData, // The data to print.
+ ULONG cbData, // Bytes of data to print.
+ int bText=1, // If true, also dump text.
+ ULONG nLine=16) // Bytes per line to print.
+{
+ const BYTE *pbData = static_cast<const BYTE*>(pvData);
+ ULONG i; // Loop control.
+ ULONG nPrint; // Number to print in an iteration.
+ ULONG nSpace; // Spacing calculations.
+ ULONG nPrefix; // Size of the prefix.
+ ULONG nLines=0; // Number of lines printed.
+ const char *pPrefix; // For counting spaces in the prefix.
+
+ // Round down to 8 characters.
+ nLine = nLine & ~0x7;
+
+ for (nPrefix=0, pPrefix=szPrefix; *pPrefix; ++pPrefix)
+ {
+ if (*pPrefix == '\t')
+ nPrefix = (nPrefix + 8) & ~7;
+ else
+ ++nPrefix;
+ }
+ //nPrefix = strlen(szPrefix);
+ do
+ { // Write the line prefix.
+ if (szPrefix)
+ DumpMD_VWrite("%s:", szPrefix);
+ else
+ DumpMD_VWrite("%*s:", nPrefix, "");
+ szPrefix = 0;
+ ++nLines;
+
+ // Calculate spacing.
+ nPrint = min(cbData, nLine);
+ nSpace = nLine - nPrint;
+
+ // dump in hex.
+ for(i=0; i<nPrint; i++)
+ {
+ if ((i&7) == 0)
+ DumpMD_Write(" ");
+ DumpMD_VWrite("%02x ", pbData[i]);
+ }
+ if (bText)
+ {
+ // Space out to the text spot.
+ if (nSpace)
+ DumpMD_VWrite("%*s", nSpace*3+nSpace/8, "");
+ // Dump in text.
+ DumpMD_Write(">");
+ for(i=0; i<nPrint; i++)
+ DumpMD_VWrite("%c", (isprint(pbData[i])) ? pbData[i] : ' ');
+ // Space out the text, and finish the line.
+ DumpMD_VWrite("%*s<", nSpace, "");
+ }
+ DumpMD_VWriteLine("");
+
+ // Next data to print.
+ cbData -= nPrint;
+ pbData += nPrint;
+ }
+ while (cbData > 0);
+
+ return nLines;
+} // int DumpMD_DumpHex()
+
+void DumpMD_DisplayUserStrings(
+ RegMeta *pMD) // The scope to dump.
+{
+ HCORENUM stringEnum = NULL; // string enumerator.
+ mdString Strings[ENUM_BUFFER_SIZE]; // String tokens from enumerator.
+ CQuickArray<WCHAR> rUserString; // Buffer to receive string.
+ WCHAR *szUserString; // Working pointer into buffer.
+ ULONG chUserString; // Size of user string.
+ CQuickArray<char> rcBuf; // Buffer to hold the BLOB version of the string.
+ char *szBuf; // Working pointer into buffer.
+ ULONG chBuf; // Saved size of the user string.
+ ULONG count; // Items returned from enumerator.
+ ULONG totalCount = 1; // Running count of strings.
+ bool bUnprint = false; // Is an unprintable character found?
+ HRESULT hr; // A result.
+ while (SUCCEEDED(hr = pMD->EnumUserStrings( &stringEnum,
+ Strings, NumItems(Strings), &count)) &&
+ count > 0)
+ {
+ if (totalCount == 1)
+ { // If only one, it is the NULL string, so don't print it.
+ DumpMD_WriteLine("User Strings");
+ DumpMD_WriteLine("-------------------------------------------------------");
+ }
+ for (ULONG i = 0; i < count; i++, totalCount++)
+ {
+ do { // Try to get the string into the existing buffer.
+ hr = pMD->GetUserString( Strings[i], rUserString.Ptr(),(ULONG32)rUserString.MaxSize(), &chUserString);
+ if (hr == CLDB_S_TRUNCATION)
+ { // Buffer wasn't big enough, try to enlarge it.
+ if (FAILED(rUserString.ReSizeNoThrow(chUserString)))
+ DumpMD_VWriteLine("malloc failed: %#8x.", E_OUTOFMEMORY);
+ continue;
+ }
+ } while (0);
+ if (FAILED(hr)) DumpMD_VWriteLine("GetUserString failed: %#8x.", hr);
+
+ szUserString = rUserString.Ptr();
+ chBuf = chUserString;
+
+ DumpMD_VWrite("%08x : (%2d) L\"", Strings[i], chUserString);
+ while (chUserString)
+ {
+ switch (*szUserString)
+ {
+ case 0:
+ DumpMD_Write("\\0"); break;
+ case W('\r'):
+ DumpMD_Write("\\r"); break;
+ case W('\n'):
+ DumpMD_Write("\\n"); break;
+ case W('\t'):
+ DumpMD_Write("\\t"); break;
+ default:
+ if (iswprint(*szUserString))
+ DumpMD_VWrite("%lc", *szUserString);
+ else
+ {
+ bUnprint = true;
+ DumpMD_Write(".");
+ }
+ break;
+ }
+ ++szUserString;
+ --chUserString;
+ }
+ DumpMD_WriteLine("\"");
+
+ // Print the user string as a blob if an unprintable character is found.
+ if (bUnprint)
+ {
+ bUnprint = false;
+ szUserString = rUserString.Ptr();
+ // REVISIT_TODO: ReSizeNoThrow can fail. Check its return value and add an error path.
+ rcBuf.ReSizeNoThrow(81); //(chBuf * 5 + 1);
+ szBuf = rcBuf.Ptr();
+ ULONG j,k;
+ DumpMD_WriteLine("\t\tUser string has unprintables, hex format below:");
+ for (j = 0,k=0; j < chBuf; j++)
+ {
+ // See rcBuf.ResSizeNoThrow(81) above
+ sprintf_s (&szBuf[k*5],81-(k*5), "%04x ", szUserString[j]);
+ k++;
+ if((k==16)||(j == (chBuf-1)))
+ {
+ szBuf[k*5] = '\0';
+ DumpMD_VWriteLine("\t\t%s", szBuf);
+ k=0;
+ }
+ }
+ }
+ }
+ }
+ if (stringEnum)
+ pMD->CloseEnum(stringEnum);
+} // void MDInfo::DisplayUserStrings()
+
+void DumpMD_DumpRawHeaps(
+ RegMeta *pMD) // The scope to dump.
+{
+ HRESULT hr; // A result.
+ ULONG ulSize; // Bytes in a heap.
+ const BYTE *pData; // Pointer to a blob.
+ ULONG cbData; // Size of a blob.
+ ULONG oData; // Offset of current blob.
+ char rcPrefix[30]; // To format line prefix.
+
+ pMD->GetBlobHeapSize(&ulSize);
+ DumpMD_VWriteLine("");
+ DumpMD_VWriteLine("Blob Heap: %d(%#x) bytes", ulSize,ulSize);
+ oData = 0;
+ do
+ {
+ pMD->GetBlob(oData, &cbData, (const void**)&pData);
+ sprintf_s(rcPrefix, NumItems(rcPrefix), "%5x,%-2x", oData, cbData);
+ DumpMD_DumpHex(rcPrefix, pData, cbData);
+ hr = pMD->GetNextBlob(oData, &oData);
+ }
+ while (hr == S_OK);
+
+ pMD->GetStringHeapSize(&ulSize);
+ DumpMD_VWriteLine("");
+ DumpMD_VWriteLine("String Heap: %d(%#x) bytes", ulSize,ulSize);
+ oData = 0;
+ const char *pString;
+ do
+ {
+ pMD->GetString(oData, &pString);
+ sprintf_s(rcPrefix, NumItems(rcPrefix), "%08x", oData);
+ DumpMD_DumpHex(rcPrefix, pString, (ULONG)strlen(pString)+1);
+ if (*pString != 0)
+ DumpMD_VWrite("%08x: %s\n", oData, pString);
+ hr = pMD->GetNextString(oData, &oData);
+ }
+ while (hr == S_OK);
+ DumpMD_VWriteLine("");
+
+ DumpMD_DisplayUserStrings(pMD);
+
+} // void DumpMD_DumpRawHeaps()
+
+
+void DumpMD_DumpRaw(RegMeta *pMD, int iDump, bool bStats)
+{
+ ULONG cTables; // Tables in the database.
+ ULONG cCols; // Columns in a table.
+ ULONG cRows; // Rows in a table.
+ ULONG cbRow; // Bytes in a row of a table.
+ ULONG iKey; // Key column of a table.
+ const char *pNameTable; // Name of a table.
+ ULONG oCol; // Offset of a column.
+ ULONG cbCol; // Size of a column.
+ ULONG ulType; // Type of a column.
+ const char *pNameColumn; // Name of a column.
+ ULONG ulSize;
+
+ pMD->GetNumTables(&cTables);
+
+ pMD->GetStringHeapSize(&ulSize);
+ DumpMD_VWrite("Strings: %d(%#x)", ulSize, ulSize);
+ pMD->GetBlobHeapSize(&ulSize);
+ DumpMD_VWrite(", Blobs: %d(%#x)", ulSize, ulSize);
+ pMD->GetGuidHeapSize(&ulSize);
+ DumpMD_VWrite(", Guids: %d(%#x)", ulSize, ulSize);
+ pMD->GetUserStringHeapSize(&ulSize);
+ DumpMD_VWriteLine(", User strings: %d(%#x)", ulSize, ulSize);
+
+ for (ULONG ixTbl = 0; ixTbl < cTables; ++ixTbl)
+ {
+ pMD->GetTableInfo(ixTbl, &cbRow, &cRows, &cCols, &iKey, &pNameTable);
+
+ if (cRows == 0 && iDump < 3)
+ continue;
+
+ if (iDump >= 2)
+ DumpMD_VWriteLine("=================================================");
+ DumpMD_VWriteLine("%2d: %-20s cRecs:%5d(%#x), cbRec:%3d(%#x), cbTable:%6d(%#x)",
+ ixTbl, pNameTable, cRows, cRows, cbRow, cbRow, cbRow * cRows, cbRow * cRows);
+
+ if (iDump < 2)
+ continue;
+
+ // Dump column definitions for the table.
+ ULONG ixCol;
+ for (ixCol=0; ixCol<cCols; ++ixCol)
+ {
+ pMD->GetColumnInfo(ixTbl, ixCol, &oCol, &cbCol, &ulType, &pNameColumn);
+
+ DumpMD_VWrite(" col %2x:%c %-12s oCol:%2x, cbCol:%x, %-7s",
+ ixCol, ((ixCol==iKey)?'*':' '), pNameColumn, oCol, cbCol, DumpMD_DumpRawNameOfType(pMD, ulType));
+
+ if (bStats)
+ {
+ ulSize = DumpMD_DumpRawColStats(pMD, ixTbl, ixCol, cRows);
+ if (ulSize)
+ DumpMD_VWrite("(%d)", ulSize);
+ }
+ DumpMD_VWriteLine("");
+ }
+
+ if (iDump < 3)
+ continue;
+
+ // Dump the rows.
+ for (ULONG rid = 1; rid <= cRows; ++rid)
+ {
+ if (rid == 1)
+ DumpMD_VWriteLine("-------------------------------------------------");
+ DumpMD_VWrite(" %3x == ", rid);
+ for (ixCol=0; ixCol < cCols; ++ixCol)
+ {
+ if (ixCol) DumpMD_VWrite(", ");
+ DumpMD_VWrite("%d:", ixCol);
+ DumpMD_DumpRawCol(pMD, ixTbl, ixCol, rid, bStats);
+ }
+ DumpMD_VWriteLine("");
+ }
+ }
+
+ DumpMD_DumpRawHeaps(pMD);
+
+} // void DumpMD_DumpRaw()
+
+
+int DumpMD_impl(RegMeta *pMD)
+{
+ DumpMD_DumpRaw(pMD, 3, false);
+ return 0;
+}
+
+int DumpMD(UINT_PTR iMD)
+{
+ RegMeta *pMD = reinterpret_cast<RegMeta*>(iMD);
+ return DumpMD_impl(pMD);
+}
+
+#endif //_DEBUG
+
+//*****************************************************************************
+// Using the existing RegMeta and reopen with another chuck of memory. Make sure that all stgdb
+// is still kept alive.
+//*****************************************************************************
+HRESULT RegMeta::ReOpenWithMemory(
+ LPCVOID pData, // [in] Location of scope data.
+ ULONG cbData, // [in] Size of the data pointed to by pData.
+ DWORD dwReOpenFlags) // [in] ReOpen flags
+{
+ HRESULT hr = NOERROR;
+
+ // Only allow the ofCopyMemory and ofTakeOwnership flags
+ if (dwReOpenFlags != 0 && ((dwReOpenFlags & (~(ofCopyMemory|ofTakeOwnership))) > 0))
+ return E_INVALIDARG;
+
+ LOCKWRITE();
+
+
+ // put the current m_pStgdb to the free list
+ m_pStgdb->m_pNextStgdb = m_pStgdbFreeList;
+ m_pStgdbFreeList = m_pStgdb;
+ m_pStgdb = new (nothrow) CLiteWeightStgdbRW;
+ IfNullGo( m_pStgdb );
+ IfFailGo( OpenExistingMD(0 /* szFileName */, const_cast<void*>(pData), cbData, ofReOpen|dwReOpenFlags /* flags */) );
+
+#ifdef FEATURE_METADATA_INTERNAL_APIS
+ // We've created a new Stgdb, but may still have an Internal Importer hanging around accessing the old Stgdb.
+ // The free list ensures we don't have a dangling pointer, but the
+ // If we have a corresponding InternalInterface, need to clear it because it's now using stale data.
+ // Others will need to update their Internal interface to get the new data.
+ {
+ HRESULT hrIgnore = SetCachedInternalInterface(NULL);
+ (void)hrIgnore; //prevent "unused variable" error from GCC
+ _ASSERTE(hrIgnore == NOERROR); // clearing the cached interface should always succeed.
+ }
+#endif //FEATURE_METADATA_INTERNAL_APIS
+
+ // we are done!
+ErrExit:
+ if (FAILED(hr))
+ {
+ // recover to the old state
+ if (m_pStgdb)
+ delete m_pStgdb;
+ m_pStgdb = m_pStgdbFreeList;
+ m_pStgdbFreeList = m_pStgdbFreeList->m_pNextStgdb;
+ }
+#ifdef FEATURE_METADATA_RELEASE_MEMORY_ON_REOPEN
+ else
+ {
+ if( !(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_MD_PreserveDebuggerMetadataMemory)) && IsSafeToDeleteStgdb())
+ {
+ // now that success is assured, delete the old block of memory
+ // This isn't normally a safe operation because we would have given out
+ // internal pointers to the memory. However when this feature is enabled
+ // we track calls that might have given out internal pointers. If none
+ // of the APIs were ever called then we can safely delete.
+ CLiteWeightStgdbRW* pStgdb = m_pStgdbFreeList;
+ m_pStgdbFreeList = m_pStgdbFreeList->m_pNextStgdb;
+ delete pStgdb;
+ }
+
+ MarkSafeToDeleteStgdb(); // As of right now, no APIs have given out internal pointers
+ // to the newly allocated stgdb
+ }
+#endif
+
+ return hr;
+} // RegMeta::ReOpenWithMemory
+
+
+//*****************************************************************************
+// This function returns the requested public interface based on the given
+// internal import interface.
+// A common path to call this is updating the matedata for dynamic modules.
+//*****************************************************************************
+STDAPI MDReOpenMetaDataWithMemoryEx(
+ void *pImport, // [IN] Given scope. public interfaces
+ LPCVOID pData, // [in] Location of scope data.
+ ULONG cbData, // [in] Size of the data pointed to by pData.
+ DWORD dwReOpenFlags) // [in] Flags for ReOpen
+{
+ HRESULT hr = S_OK;
+ IUnknown *pUnk = (IUnknown *) pImport;
+ IMetaDataImport2 *pMDImport = NULL;
+ RegMeta *pRegMeta = NULL;
+
+ _ASSERTE(pImport);
+
+ IfFailGo( pUnk->QueryInterface(IID_IMetaDataImport2, (void **) &pMDImport) );
+ pRegMeta = (RegMeta*) pMDImport;
+
+ IfFailGo( pRegMeta->ReOpenWithMemory(pData, cbData, dwReOpenFlags) );
+
+ErrExit:
+ if (pMDImport)
+ pMDImport->Release();
+
+ return hr;
+} // MDReOpenMetaDataWithMemoryEx
+
+STDAPI MDReOpenMetaDataWithMemory(
+ void *pImport, // [IN] Given scope. public interfaces
+ LPCVOID pData, // [in] Location of scope data.
+ ULONG cbData) // [in] Size of the data pointed to by pData.
+{
+ return MDReOpenMetaDataWithMemoryEx(pImport, pData, cbData, 0);
+}
+
+// --------------------------------------------------------------------------------------
+//
+// Zeros used by public APIs as return value (or pointer to this memory) for invalid input.
+// It is used by methods:
+// * code:RegMeta::GetPublicApiCompatibilityZeros, and
+// * code:RegMeta::GetPublicApiCompatibilityZerosOfSize.
+//
+const BYTE
+RegMeta::s_rgMetaDataPublicApiCompatibilityZeros[64] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+// --------------------------------------------------------------------------------------
+//
+// Returns pointer to zeros of size (cbSize).
+// Used by public APIs to return compatible values with previous releases.
+//
+const BYTE *
+RegMeta::GetPublicApiCompatibilityZerosOfSize(UINT32 cbSize)
+{
+ if (cbSize <= sizeof(s_rgMetaDataPublicApiCompatibilityZeros))
+ {
+ return s_rgMetaDataPublicApiCompatibilityZeros;
+ }
+ _ASSERTE(!"Dangerous call to this method! Reconsider fixing the caller.");
+ return NULL;
+} // RegMeta::GetPublicApiCompatibilityZerosOfSize
+
+
+
+
+//
+// returns the "built for" version of a metadata scope.
+//
+HRESULT RegMeta::GetVersionString( // S_OK or error.
+ LPCSTR *pVer) // [OUT] Put version string here.
+{
+ _ASSERTE(pVer != NULL);
+ HRESULT hr;
+ LOCKREAD();
+#ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE
+ if (m_pStgdb->m_pvMd != NULL)
+ {
+#endif
+ *pVer = reinterpret_cast<const char*>(reinterpret_cast<const STORAGESIGNATURE*>(m_pStgdb->m_pvMd)->pVersion);
+#ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE
+ }
+ else
+ {
+ //This emptry string matches the fallback behavior we have in other places that query the version string.
+ //From what I can tell the only caller to this method is the code that tests if we need to apply the WinMD adapter
+ //and it checks if pVer == "WindowsRuntime". We don't support the debugger custom metadata source scenario with WinMDs (yet?)
+ //so we intend for that check to return FALSE.
+ *pVer = "";
+ }
+#endif
+ hr = S_OK;
+ ErrExit:
+ return hr;
+}
+
+#ifdef FEATURE_METADATA_INTERNAL_APIS
+//*****************************************************************************
+// IGetIMDInternalImport methods
+//*****************************************************************************
+HRESULT RegMeta::GetIMDInternalImport(
+ IMDInternalImport ** ppIMDInternalImport // [OUT] Buffer to receive IMDInternalImport*
+ )
+{
+ HRESULT hr = S_OK;
+ MDInternalRW *pInternalRW = NULL;
+ bool isLockedForWrite = false;
+ IUnknown *pIUnkInternal = NULL;
+ IUnknown *pThis = (IMetaDataImport2*)this;
+
+ pIUnkInternal = this->GetCachedInternalInterface(TRUE);
+ if (pIUnkInternal)
+ {
+ // there is already a cached Internal interface. GetCachedInternalInterface does add ref the
+ // returned interface
+ IfFailGo(pIUnkInternal->QueryInterface(IID_IMDInternalImport, (void**)ppIMDInternalImport));
+ goto ErrExit;
+ }
+
+ if (this->IsThreadSafetyOn())
+ {
+ _ASSERTE( this->GetReaderWriterLock() );
+ IfFailGo(this->GetReaderWriterLock()->LockWrite());
+ isLockedForWrite = true;
+ }
+
+ // check again. Maybe someone else beat us to setting the internal interface while we are waiting
+ // for the write lock. Don't need to grab the read lock since we already have the write lock.
+ pIUnkInternal = this->GetCachedInternalInterface(FALSE);
+ if (pIUnkInternal)
+ {
+ // there is already a cached Internal interface. GetCachedInternalInterface does add ref the
+ // returned interface
+ IfFailGo(pIUnkInternal->QueryInterface(IID_IMDInternalImport, (void**)ppIMDInternalImport));
+ goto ErrExit;
+ }
+
+ // now create the compressed object
+ IfNullGo( pInternalRW = new (nothrow) MDInternalRW );
+ IfFailGo( pInternalRW->InitWithStgdb(pThis, this->GetMiniStgdb() ) );
+
+ // make the public object and the internal object point to each other.
+ _ASSERTE( pInternalRW->GetReaderWriterLock() == NULL &&
+ (! this->IsThreadSafetyOn() || this->GetReaderWriterLock() != NULL ));
+ IfFailGo( this->SetCachedInternalInterface(static_cast<IMDInternalImportENC*>(pInternalRW)) );
+ IfFailGo( pInternalRW->SetCachedPublicInterface(pThis));
+ IfFailGo( pInternalRW->SetReaderWriterLock(this->GetReaderWriterLock() ));
+ IfFailGo( pInternalRW->QueryInterface(IID_IMDInternalImport, (void**)ppIMDInternalImport));
+
+ErrExit:
+ if (isLockedForWrite == true)
+ this->GetReaderWriterLock()->UnlockWrite();
+ if (pIUnkInternal)
+ pIUnkInternal->Release();
+ if (pInternalRW)
+ pInternalRW->Release();
+ if (FAILED(hr))
+ {
+ if (ppIMDInternalImport)
+ *ppIMDInternalImport = 0;
+ }
+ return hr;
+}
+#endif //FEATURE_METADATA_INTERNAL_APIS
+
diff --git a/src/md/compiler/regmeta.h b/src/md/compiler/regmeta.h
new file mode 100644
index 0000000000..cb7bae17b5
--- /dev/null
+++ b/src/md/compiler/regmeta.h
@@ -0,0 +1,2123 @@
+// 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.
+//*****************************************************************************
+// RegMeta.h
+//
+
+//
+// This is the code for the MetaData coclass including both the emit and
+// import API's.
+//
+// This provides an implementation of the public Metadata interfaces via the RegMeta class. It's
+// primarily intended for use by tools such as compilers, debuggers, and profilers.
+//*****************************************************************************
+#ifndef __RegMeta__h__
+#define __RegMeta__h__
+
+#include <metamodelrw.h>
+#include <corperm.h>
+#include "../inc/mdlog.h"
+#include "utsem.h"
+
+#include "newmerger.h"
+
+#include "rwutil.h"
+#include "mdperf.h"
+#include <ivehandler.h>
+
+#include "sigparser.h"
+#ifdef FEATURE_FUSION
+#include "fusion.h"
+#endif
+
+#include "winmdinterfaces.h"
+
+class FilterManager;
+
+// Support for symbol binding meta data. This is a custom value hung off of
+// the Module entry. The CORDBG_SYMBOL_URL needs to be allocated on top of
+// a buffer large enough to hold it.
+//
+#define SZ_CORDBG_SYMBOL_URL W("DebugSymbolUrlData")
+
+struct CORDBG_SYMBOL_URL
+{
+ GUID FormatID; // ID of the format type.
+ WCHAR rcName[2]; // Variable sized name of the item.
+
+#ifdef _PREFAST_
+#pragma warning(push)
+#pragma warning(disable:6305) // "Potential mismatch between sizeof and countof quantities"
+#endif
+
+ ULONG Size() const
+ {
+ return (ULONG)(sizeof(GUID) + ((wcslen(rcName) + 1) * 2));
+ }
+
+#ifdef _PREFAST_
+#pragma warning(pop)
+#endif
+};
+
+
+//
+// Internal open flags.
+//
+#define ofExternalStgDB ofReserved1
+#define IsOfExternalStgDB(x) ((x) & ofExternalStgDB)
+#define ofReOpen ofReserved2
+#define IsOfReOpen(x) ((x) & ofReOpen)
+
+
+// Set API caller type
+enum SetAPICallerType
+{
+ DEFINE_API = 0x1,
+ EXTERNAL_CALLER = 0x2
+};
+
+// Define the record entry for the table over which ValidateMetaData iterates over.
+// Add a forward declaration for RegMeta.
+class RegMeta;
+typedef HRESULT (RegMeta::*ValidateRecordFunction)(RID);
+
+// Support for security attributes. Bundles of attributes (they look much like
+// custom attributes) are passed into a single API (DefineSecurityAttributeSet)
+// where they're processed and written into the metadata as one or more opaque
+// blobs of data.
+struct CORSEC_ATTR
+{
+ CORSEC_ATTR *pNext; // Next structure in list or NULL.
+ mdToken tkObj; // The object to put the value on.
+ mdMemberRef tkCtor; // The security attribute constructor.
+ mdTypeRef tkTypeRef; // Ref to the security attribute type.
+ mdAssemblyRef tkAssemblyRef; // Ref to the assembly containing the security attribute class.
+ void const *pCustomAttribute; // The custom value data.
+ ULONG cbCustomAttribute; // The custom value data length.
+};
+
+// Support for "Pseudo Custom Attributes".
+struct CCustAttrHashKey
+{
+ mdToken tkType; // Token of the custom attribute type.
+ int ca; // flag indicating what the ca is.
+};
+
+class CCustAttrHash : public CClosedHashEx<CCustAttrHashKey, CCustAttrHash>
+{
+ typedef CCustAttrHashKey T;
+
+ using CClosedHashEx<CCustAttrHashKey, CCustAttrHash>::Hash;
+ using CClosedHashEx<CCustAttrHashKey, CCustAttrHash>::Compare;
+ using CClosedHashEx<CCustAttrHashKey, CCustAttrHash>::Status;
+ using CClosedHashEx<CCustAttrHashKey, CCustAttrHash>::SetStatus;
+ using CClosedHashEx<CCustAttrHashKey, CCustAttrHash>::GetKey;
+
+public:
+ CCustAttrHash(int iBuckets=37) : CClosedHashEx<CCustAttrHashKey,CCustAttrHash>(iBuckets) {}
+ unsigned int Hash(const T *pData);
+ unsigned int Compare(const T *p1, T *p2);
+ ELEMENTSTATUS Status(T *pEntry);
+ void SetStatus(T *pEntry, ELEMENTSTATUS s);
+ void* GetKey(T *pEntry);
+};
+
+class MDInternalRW;
+struct CaArg;
+struct CaNamedArg;
+
+#ifdef FEATURE_METADATA_RELEASE_MEMORY_ON_REOPEN
+#define REGMETA_POSSIBLE_INTERNAL_POINTER_EXPOSED() MarkUnsafeToDeleteStgdb()
+#else
+#define REGMETA_POSSIBLE_INTERNAL_POINTER_EXPOSED()
+#endif
+
+// The RegMeta class implements the public metadata interfaces.
+//
+// Notes:
+// This object is primarily consumed by tools, not the runtime itself. (The runtime should be
+// using the internal metadata interfaces, not the public ones implemented here).
+// The VM uses it for IMetaDataEmit* interfaces. Define* methods are not exposed to the VM
+// (eg for Reflection) otherwise.
+// This object is a thin veneer exposing a public interface on top of the real storage.
+// The runtime also has internal interfaces to access that storage.
+//
+// This is included outside of md\compiler; so be very careful about using #ifdef to change class layout
+// (adding removing interfaces changes class layout)
+//
+// This exists in both the full and standalone versions of the metadata.
+//
+
+class RegMeta :
+ public IMetaDataImport2,
+ public IMetaDataAssemblyImport,
+ public IMetaDataTables2
+
+#ifndef FEATURE_METADATA_STANDALONE_WINRT
+ , public IMetaDataInfo
+#endif
+
+#ifdef FEATURE_METADATA_EMIT
+ , public IMetaDataEmit2
+ , public IMetaDataAssemblyEmit
+#endif
+
+#ifdef FEATURE_METADATA_VALIDATOR
+ , public IMetaDataValidate
+#endif
+
+#ifdef FEATURE_METADATA_EMIT_ALL
+ , public IMetaDataFilter
+#endif
+
+#ifdef FEATURE_METADATA_INTERNAL_APIS
+ , public IMetaDataHelper
+ , public IMDInternalEmit
+ , public IGetIMDInternalImport
+#endif
+
+#if defined(FEATURE_METADATA_EMIT) && defined(FEATURE_METADATA_INTERNAL_APIS)
+ , public IMetaDataEmitHelper
+#endif
+
+#if defined(FEATURE_METADATA_IN_VM) && defined(FEATURE_PREJIT)
+ , public IMetaDataCorProfileData
+ , public IMDInternalMetadataReorderingOptions
+#endif
+ , public IMDCommon
+{
+ friend class NEWMERGER;
+ friend class CImportTlb;
+ friend class MDInternalRW;
+ friend class MDInternalRO;
+ 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:
+//*****************************************************************************
+// IUnknown methods
+//*****************************************************************************
+ STDMETHODIMP QueryInterface(REFIID riid, void** ppv);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+//*****************************************************************************
+// IMetaDataImport methods
+//*****************************************************************************
+ void STDMETHODCALLTYPE CloseEnum(HCORENUM hEnum);
+ STDMETHODIMP CountEnum(HCORENUM hEnum, ULONG *pulCount);
+ STDMETHODIMP ResetEnum(HCORENUM hEnum, ULONG ulPos);
+ STDMETHODIMP EnumTypeDefs(HCORENUM *phEnum, mdTypeDef rTypeDefs[],
+ ULONG cMax, ULONG *pcTypeDefs);
+ STDMETHODIMP EnumInterfaceImpls(HCORENUM *phEnum, mdTypeDef td,
+ mdInterfaceImpl rImpls[], ULONG cMax,
+ ULONG* pcImpls);
+ STDMETHODIMP EnumTypeRefs(HCORENUM *phEnum, mdTypeRef rTypeRefs[],
+ ULONG cMax, ULONG* pcTypeRefs);
+ STDMETHODIMP FindTypeDefByName( // S_OK or error.
+ LPCWSTR szTypeDef, // [IN] Name of the Type.
+ mdToken tdEncloser, // [IN] TypeDef/TypeRef of Enclosing class.
+ mdTypeDef *ptd); // [OUT] Put the TypeDef token here.
+
+ STDMETHODIMP GetScopeProps( // S_OK or error.
+ __out_ecount_opt (cchName) LPWSTR szName, // [OUT] Put 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] Put MVID here.
+
+ STDMETHODIMP GetModuleFromScope( // S_OK.
+ mdModule *pmd); // [OUT] Put mdModule token here.
+
+ STDMETHODIMP GetTypeDefProps( // S_OK or error.
+ mdTypeDef td, // [IN] TypeDef token for inquiry.
+ __out_ecount_opt (cchTypeDef) LPWSTR szTypeDef, // [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.
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP GetTypeRefProps(
+ mdTypeRef tr, // S_OK or error.
+ mdToken *ptkResolutionScope, // [OUT] Resolution scope, mdModuleRef or mdAssemblyRef.
+ __out_ecount_opt (cchName) LPWSTR szName, // [OUT] Name buffer.
+ ULONG cchName, // [IN] Size of Name buffer.
+ ULONG *pchName); // [OUT] Actual size of Name.
+
+ // This access global shared state to looks across multiple metadata scopes that would
+ // otherwise be independent.
+ STDMETHODIMP ResolveTypeRef(mdTypeRef tr, REFIID riid, IUnknown **ppIScope, mdTypeDef *ptd);
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP 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.
+
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP 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
+
+ STDMETHODIMP 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
+
+ STDMETHODIMP 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
+
+ STDMETHODIMP 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
+
+ STDMETHODIMP GetMethodProps(
+ mdMethodDef mb, // The method for which to get props.
+ mdTypeDef *pClass, // Put method's class here.
+ __out_ecount_opt (cchMethod) LPWSTR szMethod, // 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
+
+ STDMETHODIMP GetMemberRefProps( // S_OK or error.
+ mdMemberRef mr, // [IN] given memberref
+ mdToken *ptk, // [OUT] Put classref or classdef here.
+ __out_ecount_opt (cchMember) LPWSTR szMember, // [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
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP 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
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP 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
+
+ STDMETHODIMP 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
+
+ STDMETHODIMP 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
+
+ STDMETHODIMP GetRVA( // S_OK or error.
+ mdToken tk, // Member for which to set offset
+ ULONG *pulCodeRVA, // The offset
+ DWORD *pdwImplFlags); // the implementation flags
+
+ 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.
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP GetModuleRefProps( // S_OK or error.
+ mdModuleRef mur, // [IN] moduleref token.
+ __out_ecount_opt (cchName) LPWSTR szName, // [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.
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP GetNameFromToken( // S_OK or error.
+ mdToken tk, // [IN] Token to get name from. Must have a name.
+ MDUTF8CSTR *pszUtf8NamePtr); // [OUT] Return pointer to UTF8 name in heap.
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP GetUserString( // S_OK or error.
+ mdString stk, // [IN] String token.
+ __out_ecount_opt (cchString) LPWSTR szString, // [OUT] Copy of string.
+ ULONG cchString, // [IN] Max chars of room in szString.
+ ULONG *pchString); // [OUT] How many chars in actual string.
+
+ STDMETHODIMP GetPinvokeMap( // S_OK or error.
+ mdToken tk, // [IN] FieldDef or MethodDef.
+ DWORD *pdwMappingFlags, // [OUT] Flags used for mapping.
+ __out_ecount_opt (cchImportName) LPWSTR szImportName, // [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.
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP GetParamForMethodIndex( // S_OK or error.
+ mdMethodDef md, // [IN] Method token.
+ ULONG ulParamSeq, // [IN] Parameter sequence.
+ mdParamDef *ppd); // [IN] Put Param token here.
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP FindTypeRef( // S_OK or error.
+ mdToken tkResolutionScope, // ResolutionScope.
+ LPCWSTR szName, // [IN] TypeRef name.
+ mdTypeRef *ptr); // [OUT] matching TypeRef.
+
+ STDMETHODIMP GetMemberProps(
+ mdToken mb, // The member for which to get props.
+ mdTypeDef *pClass, // Put member's class here.
+ __out_ecount_opt (cchMember) LPWSTR szMember, // 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 *pcbValue); // [OUT] size of constant value
+
+ STDMETHODIMP GetFieldProps(
+ mdFieldDef mb, // The field for which to get props.
+ mdTypeDef *pClass, // Put field's class here.
+ __out_ecount_opt (cchField) 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 *pcbValue); // [OUT] size of constant value
+
+ STDMETHODIMP 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 *pcbValue, // [OUT] size of constant value
+ 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
+
+ STDMETHODIMP GetParamProps( // S_OK or error.
+ mdParamDef tk, // [IN]The Parameter.
+ mdMethodDef *pmd, // [OUT] Parent Method token.
+ ULONG *pulSequence, // [OUT] Parameter sequence.
+ __out_ecount_opt (cchName) LPWSTR szName, // [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 *pcbValue); // [OUT] size of constant value
+
+ STDMETHODIMP_(BOOL) IsValidToken( // True or False.
+ mdToken tk); // [IN] Given token.
+
+ STDMETHODIMP GetNestedClassProps( // S_OK or error.
+ mdTypeDef tdNestedClass, // [IN] NestedClass token.
+ mdTypeDef *ptdEnclosingClass); // [OUT] EnclosingClass token.
+
+ STDMETHODIMP 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).
+
+ STDMETHODIMP IsGlobal( // S_OK or error.
+ mdToken pd, // [IN] Type, Field, or Method token.
+ int *pbGlobal); // [OUT] Put 1 if global, 0 otherwise.
+
+//*****************************************************************************
+// IMetaDataImport2 methods
+//*****************************************************************************
+ STDMETHODIMP GetGenericParamProps( // S_OK or error.
+ 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 *reserved, // [OUT] For future use (e.g. non-type parameters)
+ __out_ecount_opt (cchName) LPWSTR wzname, // [OUT] Put name here
+ ULONG cchName, // [IN] Size of buffer
+ ULONG *pchName); // [OUT] Put size of name (wide chars) here.
+
+ STDMETHODIMP GetGenericParamConstraintProps( // S_OK or error.
+ mdGenericParamConstraint gpc, // [IN] GenericParamConstraint
+ mdGenericParam *ptGenericParam, // [OUT] GenericParam that is constrained
+ mdToken *ptkConstraintType); // [OUT] TypeDef/Ref/Spec constraint
+
+ 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
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP 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.
+
+ STDMETHODIMP 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
+
+ STDMETHODIMP GetVersionString( // S_OK or error.
+ __out_ecount_opt (cchBufSize) LPWSTR pwzBuf, // [OUT] Put version string here.
+ DWORD cchBufSize, // [IN] size of the buffer, in wide chars
+ DWORD *pchBufSize); // [OUT] Size of the version string, wide chars, including terminating nul.
+
+//*****************************************************************************
+// IMetaDataAssemblyImport
+//*****************************************************************************
+ 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_part_opt(cchName, *pchName) LPWSTR szName, // [OUT] Buffer to fill with assembly's simply 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_part_opt(cchName, *pchName)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_part_opt(cchName, *pchName) 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_part_opt(cchName, *pchName) 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 ExportedType.
+ 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_part_opt(cchName, *pchName)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 ExportedType.
+ 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 FindExportedTypeByName( // S_OK or error
+ LPCWSTR szName, // [IN] Name of the ExportedType.
+ mdExportedType tkEnclosingType, // [IN] Enclosing ExportedType.
+ 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.
+
+ STDMETHODIMP GetAssemblyFromScope( // S_OK or error
+ mdAssembly *ptkAssembly); // [OUT] Put token here.
+
+ // This uses Fusion to lookup, so it's E_NOTIMPL in the standalone versions.
+ 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.
+
+#ifdef FEATURE_METADATA_EMIT
+//*****************************************************************************
+// IMetaDataEmit
+//*****************************************************************************
+ STDMETHODIMP DefineMethod( // S_OK or error.
+ mdTypeDef td, // Parent TypeDef
+ LPCWSTR szName, // Name of member
+ DWORD dwMethodFlags, // Member attributes
+ PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of COM+ signature
+ ULONG cbSigBlob, // [IN] count of bytes in the signature blob
+ ULONG ulCodeRVA,
+ DWORD dwImplFlags,
+ mdMethodDef *pmd); // Put member token here
+
+ STDMETHODIMP DefineMethodImpl( // S_OK or error.
+ mdTypeDef td, // [IN] The class implementing the method
+ mdToken tkBody, // [IN] Method body, MethodDef or MethodRef
+ mdToken tkDecl); // [IN] Method declaration, MethodDef or MethodRef
+
+ STDMETHODIMP SetMethodImplFlags( // [IN] S_OK or error.
+ mdMethodDef md, // [IN] Method for which to set impl flags
+ DWORD dwImplFlags);
+
+ STDMETHODIMP SetFieldRVA( // [IN] S_OK or error.
+ mdFieldDef fd, // [IN] Field for which to set offset
+ ULONG ulRVA); // [IN] The offset
+
+ STDMETHODIMP DefineTypeRefByName( // S_OK or error.
+ mdToken tkResolutionScope, // [IN] ModuleRef or AssemblyRef.
+ LPCWSTR szName, // [IN] Name of the TypeRef.
+ mdTypeRef *ptr); // [OUT] Put TypeRef token here.
+
+ STDMETHODIMP DefineImportType( // S_OK or error.
+ IMetaDataAssemblyImport *pAssemImport, // [IN] Assemby containing the TypeDef.
+ const void *pbHashValue, // [IN] Hash Blob for Assembly.
+ ULONG cbHashValue, // [IN] Count of bytes.
+ IMetaDataImport *pImport, // [IN] Scope containing the TypeDef.
+ mdTypeDef tdImport, // [IN] The imported TypeDef.
+ IMetaDataAssemblyEmit *pAssemEmit, // [IN] Assembly into which the TypeDef is imported.
+ mdTypeRef *ptr); // [OUT] Put TypeRef token here.
+
+ STDMETHODIMP DefineMemberRef( // S_OK or error
+ mdToken tkImport, // [IN] ClassRef or ClassDef importing a member.
+ LPCWSTR szName, // [IN] member's 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] memberref token
+
+ STDMETHODIMP DefineImportMember( // S_OK or error.
+ IMetaDataAssemblyImport *pAssemImport, // [IN] Assemby containing the Member.
+ const void *pbHashValue, // [IN] Hash Blob for Assembly.
+ ULONG cbHashValue, // [IN] Count of bytes.
+ IMetaDataImport *pImport, // [IN] Import scope, with member.
+ mdToken mbMember, // [IN] Member in import scope.
+ IMetaDataAssemblyEmit *pAssemEmit, // [IN] Assembly into which the Member is imported.
+ mdToken tkImport, // [IN] Classref or classdef in emit scope.
+ mdMemberRef *pmr); // [OUT] Put member ref here.
+
+ STDMETHODIMP DefineEvent(
+ mdTypeDef td, // [IN] the class/interface on which the event is being defined
+ LPCWSTR szEvent, // [IN] Name of the event
+ DWORD dwEventFlags, // [IN] CorEventAttr
+ mdToken tkEventType, // [IN] a reference (mdTypeRef or mdTypeRef(to the Event class
+ mdMethodDef mdAddOn, // [IN] required add method
+ mdMethodDef mdRemoveOn, // [IN] required remove method
+ mdMethodDef mdFire, // [IN] optional fire method
+ mdMethodDef rmdOtherMethods[], // [IN] optional array of other methods associate with the event
+ mdEvent *pmdEvent); // [OUT] output event token
+
+ STDMETHODIMP SetClassLayout(
+ mdTypeDef td, // [IN] typedef
+ DWORD dwPackSize, // [IN] packing size specified as 1, 2, 4, 8, or 16
+ COR_FIELD_OFFSET rFieldOffsets[], // [IN] array of layout specification
+ ULONG ulClassSize); // [IN] size of the class
+
+ STDMETHODIMP DeleteClassLayout(
+ mdTypeDef td); // [IN] typdef token
+
+ STDMETHODIMP SetFieldMarshal(
+ mdToken tk, // [IN] given a fieldDef or paramDef token
+ PCCOR_SIGNATURE pvNativeType, // [IN] native type specification
+ ULONG cbNativeType); // [IN] count of bytes of pvNativeType
+
+ STDMETHODIMP DeleteFieldMarshal(
+ mdToken tk); // [IN] fieldDef or paramDef token to be deleted.
+
+ STDMETHODIMP DefinePermissionSet(
+ mdToken tk, // [IN] the object to be decorated.
+ DWORD dwAction, // [IN] CorDeclSecurity.
+ void const *pvPermission, // [IN] permission blob.
+ ULONG cbPermission, // [IN] count of bytes of pvPermission.
+ mdPermission *ppm); // [OUT] returned permission token.
+
+ STDMETHODIMP SetRVA( // [IN] S_OK or error.
+ mdToken md, // [IN] MethodDef for which to set offset
+ ULONG ulRVA); // [IN] The offset#endif
+
+ STDMETHODIMP GetTokenFromSig( // [IN] S_OK or error.
+ PCCOR_SIGNATURE pvSig, // [IN] Signature to define.
+ ULONG cbSig, // [IN] Size of signature data.
+ mdSignature *pmsig); // [OUT] returned signature token.
+
+ STDMETHODIMP DefineModuleRef( // S_OK or error.
+ LPCWSTR szName, // [IN] DLL name
+ mdModuleRef *pmur); // [OUT] returned module ref token
+
+ STDMETHODIMP SetParent( // S_OK or error.
+ mdMemberRef mr, // [IN] Token for the ref to be fixed up.
+ mdToken tk); // [IN] The ref parent.
+
+ STDMETHODIMP GetTokenFromTypeSpec( // S_OK or error.
+ PCCOR_SIGNATURE pvSig, // [IN] ArraySpec Signature to define.
+ ULONG cbSig, // [IN] Size of signature data.
+ mdTypeSpec *ptypespec); // [OUT] returned TypeSpec token.
+
+ STDMETHODIMP SaveToMemory( // S_OK or error.
+ void *pbData, // [OUT] Location to write data.
+ ULONG cbData); // [IN] Max size of data buffer.
+
+ STDMETHODIMP DefineUserString( // S_OK or error.
+ LPCWSTR szString, // [IN] User literal string.
+ ULONG cchString, // [IN] Length of string.
+ mdString *pstk); // [OUT] String token.
+
+ STDMETHODIMP DeleteToken( // Return code.
+ mdToken tkObj); // [IN] The token to be deleted
+
+ STDMETHODIMP SetTypeDefProps( // S_OK or error.
+ mdTypeDef td, // [IN] The TypeDef.
+ DWORD dwTypeDefFlags, // [IN] TypeDef flags.
+ mdToken tkExtends, // [IN] Base TypeDef or TypeRef.
+ mdToken rtkImplements[]); // [IN] Implemented interfaces.
+
+ STDMETHODIMP DefineNestedType( // S_OK or error.
+ LPCWSTR szTypeDef, // [IN] Name of TypeDef
+ DWORD dwTypeDefFlags, // [IN] CustomAttribute flags
+ mdToken tkExtends, // [IN] extends this TypeDef or typeref
+ mdToken rtkImplements[], // [IN] Implements interfaces
+ mdTypeDef tdEncloser, // [IN] TypeDef token of the enclosing type.
+ mdTypeDef *ptd); // [OUT] Put TypeDef token here
+
+ STDMETHODIMP SetMethodProps( // S_OK or error.
+ mdMethodDef md, // [IN] The MethodDef.
+ DWORD dwMethodFlags, // [IN] Method attributes.
+ ULONG ulCodeRVA, // [IN] Code RVA.
+ DWORD dwImplFlags); // [IN] MethodImpl flags.
+
+ STDMETHODIMP SetEventProps( // S_OK or error.
+ mdEvent ev, // [IN] The event token.
+ DWORD dwEventFlags, // [IN] CorEventAttr.
+ mdToken tkEventType, // [IN] A reference (mdTypeRef or mdTypeRef) to the Event class.
+ mdMethodDef mdAddOn, // [IN] Add method.
+ mdMethodDef mdRemoveOn, // [IN] Remove method.
+ mdMethodDef mdFire, // [IN] Fire method.
+ mdMethodDef rmdOtherMethods[]); // [IN] Array of other methods associated with the event.
+
+ STDMETHODIMP SetPermissionSetProps( // S_OK or error.
+ mdToken tk, // [IN] The object to be decorated.
+ DWORD dwAction, // [IN] CorDeclSecurity.
+ void const *pvPermission, // [IN] Permission blob.
+ ULONG cbPermission, // [IN] Count of bytes of pvPermission.
+ mdPermission *ppm); // [OUT] Permission token.
+
+ STDMETHODIMP DefinePinvokeMap( // Return code.
+ mdToken tk, // [IN] FieldDef or MethodDef.
+ DWORD dwMappingFlags, // [IN] Flags used for mapping.
+ LPCWSTR szImportName, // [IN] Import name.
+ mdModuleRef mrImportDLL); // [IN] ModuleRef token for the target DLL.
+
+ STDMETHODIMP SetPinvokeMap( // Return code.
+ mdToken tk, // [IN] FieldDef or MethodDef.
+ DWORD dwMappingFlags, // [IN] Flags used for mapping.
+ LPCWSTR szImportName, // [IN] Import name.
+ mdModuleRef mrImportDLL); // [IN] ModuleRef token for the target DLL.
+
+ STDMETHODIMP DeletePinvokeMap( // Return code.
+ mdToken tk); // [IN]FieldDef or MethodDef.
+
+ STDMETHODIMP DefineCustomAttribute( // Return code.
+ mdToken tkOwner, // [IN] The object to put the value on.
+ mdToken tkCtor, // [IN] Constructor of the CustomAttribute type (MemberRef/MethodDef).
+ void const *pCustomAttribute, // [IN] The custom value data.
+ ULONG cbCustomAttribute, // [IN] The custom value data length.
+ mdCustomAttribute *pcv); // [OUT] The custom value token value on return.
+
+ STDMETHODIMP SetCustomAttributeValue( // Return code.
+ mdCustomAttribute pcv, // [IN] The custom value token whose value to replace.
+ void const *pCustomAttribute, // [IN] The custom value data.
+ ULONG cbCustomAttribute); // [IN] The custom value data length.
+
+ STDMETHODIMP DefineField( // S_OK or error.
+ mdTypeDef td, // Parent TypeDef
+ LPCWSTR szName, // Name of member
+ DWORD dwFieldFlags, // Member attributes
+ PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of COM+ signature
+ ULONG cbSigBlob, // [IN] count of bytes in the signature blob
+ DWORD dwCPlusTypeFlag, // [IN] flag for value type. selected ELEMENT_TYPE_*
+ void const *pValue, // [IN] constant value
+ ULONG cchValue, // [IN] size of constant value (string, in wide chars).
+ mdFieldDef *pmd); // [OUT] Put member token here
+
+ STDMETHODIMP DefineProperty(
+ mdTypeDef td, // [IN] the class/interface on which the property is being defined
+ LPCWSTR szProperty, // [IN] Name of the property
+ DWORD dwPropFlags, // [IN] CorPropertyAttr
+ PCCOR_SIGNATURE pvSig, // [IN] the required type signature
+ ULONG cbSig, // [IN] the size of the type signature blob
+ DWORD dwCPlusTypeFlag, // [IN] flag for value type. selected ELEMENT_TYPE_*
+ void const *pValue, // [IN] constant value
+ ULONG cchValue, // [IN] size of constant value (string, in wide chars).
+ mdMethodDef mdSetter, // [IN] optional setter of the property
+ mdMethodDef mdGetter, // [IN] optional getter of the property
+ mdMethodDef rmdOtherMethods[], // [IN] an optional array of other methods
+ mdProperty *pmdProp); // [OUT] output property token
+
+ STDMETHODIMP DefineParam(
+ mdMethodDef md, // [IN] Owning method
+ ULONG ulParamSeq, // [IN] Which param
+ LPCWSTR szName, // [IN] Optional param name
+ DWORD dwParamFlags, // [IN] Optional param flags
+ DWORD dwCPlusTypeFlag, // [IN] flag for value type. selected ELEMENT_TYPE_*
+ void const *pValue, // [IN] constant value
+ ULONG cchValue, // [IN] size of constant value (string, in wide chars).
+ mdParamDef *ppd); // [OUT] Put param token here
+
+ STDMETHODIMP SetFieldProps( // S_OK or error.
+ mdFieldDef fd, // [IN] The FieldDef.
+ DWORD dwFieldFlags, // [IN] Field attributes.
+ DWORD dwCPlusTypeFlag, // [IN] Flag for the value type, selected ELEMENT_TYPE_*
+ void const *pValue, // [IN] Constant value.
+ ULONG cchValue); // [IN] size of constant value (string, in wide chars).
+
+ STDMETHODIMP SetPropertyProps( // S_OK or error.
+ mdProperty pr, // [IN] Property token.
+ DWORD dwPropFlags, // [IN] CorPropertyAttr.
+ DWORD dwCPlusTypeFlag, // [IN] Flag for value type, selected ELEMENT_TYPE_*
+ void const *pValue, // [IN] Constant value.
+ ULONG cchValue, // [IN] size of constant value (string, in wide chars).
+ mdMethodDef mdSetter, // [IN] Setter of the property.
+ mdMethodDef mdGetter, // [IN] Getter of the property.
+ mdMethodDef rmdOtherMethods[]); // [IN] Array of other methods.
+
+ STDMETHODIMP SetParamProps( // Return code.
+ mdParamDef pd, // [IN] Param token.
+ LPCWSTR szName, // [IN] Param name.
+ DWORD dwParamFlags, // [IN] Param flags.
+ DWORD dwCPlusTypeFlag, // [IN] Flag for value type. selected ELEMENT_TYPE_*.
+ void const *pValue, // [OUT] Constant value.
+ ULONG cchValue); // [IN] size of constant value (string, in wide chars).
+
+ STDMETHODIMP ApplyEditAndContinue( // S_OK or error.
+ IUnknown *pImport); // [IN] Metadata from the delta PE.
+
+ // Specialized Custom Attributes for security.
+ STDMETHODIMP DefineSecurityAttributeSet(// Return code.
+ mdToken tkObj, // [IN] Class or method requiring security attributes.
+ COR_SECATTR rSecAttrs[], // [IN] Array of security attribute descriptions.
+ ULONG cSecAttrs, // [IN] Count of elements in above array.
+ ULONG *pulErrorAttr); // [OUT] On error, index of attribute causing problem.
+
+ STDMETHODIMP TranslateSigWithScope(
+ IMetaDataAssemblyImport *pAssemImport, // [IN] assembly importing interface
+ const void *pbHashValue, // [IN] Hash Blob for Assembly.
+ ULONG cbHashValue, // [IN] Count of bytes.
+ IMetaDataImport *import, // [IN] importing interface
+ PCCOR_SIGNATURE pbSigBlob, // [IN] signature in the importing scope
+ ULONG cbSigBlob, // [IN] count of bytes of signature
+ IMetaDataAssemblyEmit *pAssemEmti, // [IN] emit assembly interface
+ IMetaDataEmit *emit, // [IN] emit interface
+ PCOR_SIGNATURE pvTranslatedSig, // [OUT] buffer to hold translated signature
+ ULONG cbTranslatedSigMax,
+ ULONG *pcbTranslatedSig); // [OUT] count of bytes in the translated signature
+
+//*****************************************************************************
+// IMetaDataEmit2 methods
+//*****************************************************************************
+ STDMETHODIMP SetModuleProps( // S_OK or error.
+ LPCWSTR szName); // [IN] If not NULL, the name to set.
+
+ STDMETHODIMP Save( // S_OK or error.
+ LPCWSTR szFile, // [IN] The filename to save to.
+ DWORD dwSaveFlags); // [IN] Flags for the save.
+
+ STDMETHODIMP SaveToStream( // S_OK or error.
+ IStream *pIStream, // [IN] A writable stream to save to.
+ DWORD dwSaveFlags); // [IN] Flags for the save.
+
+ STDMETHODIMP GetSaveSize( // S_OK or error.
+ CorSaveSize fSave, // [IN] cssAccurate or cssQuick.
+ DWORD *pdwSaveSize); // [OUT] Put the size here.
+
+ STDMETHODIMP Merge( // S_OK or error.
+ IMetaDataImport *pImport, // [IN] The scope to be merged.
+ IMapToken *pHostMapToken, // [IN] Host IMapToken interface to receive token remap notification
+ IUnknown *pHandler); // [IN] An object to receive to receive error notification.
+
+ STDMETHODIMP MergeEnd(); // S_OK or error.
+
+ STDMETHODIMP DefineMethodSpec( // S_OK or error
+ mdToken tkImport, // [IN] MethodDef or MemberRef
+ PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of COM+ signature
+ ULONG cbSigBlob, // [IN] count of bytes in the signature blob
+ mdMethodSpec *pmi); // [OUT] method instantiation token
+
+ STDMETHODIMP DefineTypeDef( // S_OK or error.
+ LPCWSTR szTypeDef, // [IN] Name of TypeDef
+ DWORD dwTypeDefFlags, // [IN] CustomAttribute flags
+ mdToken tkExtends, // [IN] extends this TypeDef or typeref
+ mdToken rtkImplements[], // [IN] Implements interfaces
+ mdTypeDef *ptd); // [OUT] Put TypeDef token here
+
+ STDMETHODIMP SetHandler( // S_OK.
+ IUnknown *pUnk); // [IN] The new error handler.
+
+ STDMETHODIMP GetDeltaSaveSize( // S_OK or error.
+ CorSaveSize fSave, // [IN] cssAccurate or cssQuick.
+ DWORD *pdwSaveSize); // [OUT] Put the size here.
+
+ STDMETHODIMP SaveDelta( // S_OK or error.
+ LPCWSTR szFile, // [IN] The filename to save to.
+ DWORD dwSaveFlags); // [IN] Flags for the save.
+
+ STDMETHODIMP SaveDeltaToStream( // S_OK or error.
+ IStream *pIStream, // [IN] A writable stream to save to.
+ DWORD dwSaveFlags); // [IN] Flags for the save.
+
+ STDMETHODIMP SaveDeltaToMemory( // S_OK or error.
+ void *pbData, // [OUT] Location to write data.
+ ULONG cbData); // [IN] Max size of data buffer.
+
+ STDMETHODIMP ResetENCLog(); // S_OK or error.
+
+ STDMETHODIMP DefineGenericParam( // S_OK or error.
+ mdToken tk, // [IN] TypeDef or MethodDef
+ ULONG ulParamSeq, // [IN] Index of the type parameter
+ DWORD dwParamFlags, // [IN] Flags, for future use (e.g. variance)
+ LPCWSTR szname, // [IN] Name
+ DWORD reserved, // [IN] For future use (e.g. non-type parameters)
+ mdToken rtkConstraints[], // [IN] Array of type constraints (TypeDef,TypeRef,TypeSpec)
+ mdGenericParam *pgp); // [OUT] Put GenericParam token here
+
+ STDMETHODIMP SetGenericParamProps( // S_OK or error.
+ mdGenericParam gp, // [IN] GenericParam
+ DWORD dwParamFlags, // [IN] Flags, for future use (e.g. variance)
+ LPCWSTR szName, // [IN] Optional name
+ DWORD reserved, // [IN] For future use (e.g. non-type parameters)
+ mdToken rtkConstraints[]); // [IN] Array of type constraints (TypeDef,TypeRef,TypeSpec)
+
+//*****************************************************************************
+// IMetaDataAssemblyEmit
+//*****************************************************************************
+ STDMETHODIMP DefineAssembly( // S_OK or error.
+ const void *pbPublicKey, // [IN] Public key of the assembly.
+ ULONG cbPublicKey, // [IN] Count of bytes in the public key.
+ ULONG ulHashAlgId, // [IN] Hash Algorithm.
+ LPCWSTR szName, // [IN] Name of the assembly.
+ const ASSEMBLYMETADATA *pMetaData, // [IN] Assembly MetaData.
+ DWORD dwAssemblyFlags, // [IN] Flags.
+ mdAssembly *pma); // [OUT] Returned Assembly token.
+
+ STDMETHODIMP DefineAssemblyRef( // S_OK or error.
+ const void *pbPublicKeyOrToken, // [IN] Public key or token of the assembly.
+ ULONG cbPublicKeyOrToken, // [IN] Count of bytes in the public key or token.
+ LPCWSTR szName, // [IN] Name of the assembly being referenced.
+ const ASSEMBLYMETADATA *pMetaData, // [IN] Assembly MetaData.
+ const void *pbHashValue, // [IN] Hash Blob.
+ ULONG cbHashValue, // [IN] Count of bytes in the Hash Blob.
+ DWORD dwAssemblyRefFlags, // [IN] Token for Execution Location.
+ mdAssemblyRef *pmar); // [OUT] Returned AssemblyRef token.
+
+ STDMETHODIMP DefineFile( // S_OK or error.
+ LPCWSTR szName, // [IN] Name of the file.
+ const void *pbHashValue, // [IN] Hash Blob.
+ ULONG cbHashValue, // [IN] Count of bytes in the Hash Blob.
+ DWORD dwFileFlags, // [IN] Flags.
+ mdFile *pmf); // [OUT] Returned File token.
+
+ STDMETHODIMP DefineExportedType( // S_OK or error.
+ LPCWSTR szName, // [IN] Name of the Com Type.
+ mdToken tkImplementation, // [IN] mdFile or mdAssemblyRef that provides the ExportedType.
+ mdTypeDef tkTypeDef, // [IN] TypeDef token within the file.
+ DWORD dwExportedTypeFlags, // [IN] Flags.
+ mdExportedType *pmct); // [OUT] Returned ExportedType token.
+
+ STDMETHODIMP DefineManifestResource( // S_OK or error.
+ LPCWSTR szName, // [IN] Name of the resource.
+ mdToken tkImplementation, // [IN] mdFile or mdAssemblyRef that provides the resource.
+ DWORD dwOffset, // [IN] Offset to the beginning of the resource within the file.
+ DWORD dwResourceFlags, // [IN] Flags.
+ mdManifestResource *pmmr); // [OUT] Returned ManifestResource token.
+
+ STDMETHODIMP SetAssemblyProps( // S_OK or error.
+ mdAssembly pma, // [IN] Assembly token.
+ const void *pbPublicKey, // [IN] Public key of the assembly.
+ ULONG cbPublicKey, // [IN] Count of bytes in the public key.
+ ULONG ulHashAlgId, // [IN] Hash Algorithm.
+ LPCWSTR szName, // [IN] Name of the assembly.
+ const ASSEMBLYMETADATA *pMetaData, // [IN] Assembly MetaData.
+ DWORD dwAssemblyFlags); // [IN] Flags.
+
+ STDMETHODIMP SetAssemblyRefProps( // S_OK or error.
+ mdAssemblyRef ar, // [IN] AssemblyRefToken.
+ const void *pbPublicKeyOrToken, // [IN] Public key or token of the assembly.
+ ULONG cbPublicKeyOrToken, // [IN] Count of bytes in the public key or token.
+ LPCWSTR szName, // [IN] Name of the assembly being referenced.
+ const ASSEMBLYMETADATA *pMetaData, // [IN] Assembly MetaData.
+ const void *pbHashValue, // [IN] Hash Blob.
+ ULONG cbHashValue, // [IN] Count of bytes in the Hash Blob.
+ DWORD dwAssemblyRefFlags); // [IN] Token for Execution Location.
+
+ STDMETHODIMP SetFileProps( // S_OK or error.
+ mdFile file, // [IN] File token.
+ const void *pbHashValue, // [IN] Hash Blob.
+ ULONG cbHashValue, // [IN] Count of bytes in the Hash Blob.
+ DWORD dwFileFlags); // [IN] Flags.
+
+ STDMETHODIMP SetExportedTypeProps( // S_OK or error.
+ mdExportedType ct, // [IN] ExportedType token.
+ mdToken tkImplementation, // [IN] mdFile or mdAssemblyRef that provides the ExportedType.
+ mdTypeDef tkTypeDef, // [IN] TypeDef token within the file.
+ DWORD dwExportedTypeFlags); // [IN] Flags.
+
+ STDMETHODIMP SetManifestResourceProps( // S_OK or error.
+ mdManifestResource mr, // [IN] ManifestResource token.
+ mdToken tkImplementation, // [IN] mdFile or mdAssemblyRef that provides the resource.
+ DWORD dwOffset, // [IN] Offset to the beginning of the resource within the file.
+ DWORD dwResourceFlags); // [IN] Flags.
+
+#endif //FEATURE_METADATA_EMIT
+
+#ifdef FEATURE_METADATA_VALIDATOR
+//*****************************************************************************
+// IMetaDataValidator
+//*****************************************************************************
+
+ STDMETHODIMP ValidatorInit(
+ DWORD dwModuleType, // [IN] Specifies whether the module is a PE file or an obj.
+ IUnknown * pUnk); // [IN] Validation error handler.
+
+ STDMETHODIMP ValidateMetaData();
+#endif //FEATURE_METADATA_VALIDATOR
+
+#ifdef FEATURE_METADATA_EMIT_ALL
+//*****************************************************************************
+// IMetaDataFilter
+//*****************************************************************************
+ STDMETHODIMP UnmarkAll(); // unmark everything in a module
+
+ STDMETHODIMP MarkToken(
+ mdToken tk); // [IN] Token to be marked
+
+ STDMETHODIMP IsTokenMarked(
+ mdToken tk, // [IN] Token to be checked
+ BOOL *pIsMarked); // [OUT] TRUE if token is marked
+
+#endif //FEATURE_METADATA_EMIT_ALL
+
+#ifdef FEATURE_METADATA_INTERNAL_APIS
+
+//*****************************************************************************
+// IMetaDataEmitHelper
+//*****************************************************************************
+ STDMETHODIMP DefineMethodSemanticsHelper(
+ mdToken tkAssociation, // [IN] property or event token
+ DWORD dwFlags, // [IN] semantics
+ mdMethodDef md); // [IN] method to associated with
+
+ STDMETHODIMP SetFieldLayoutHelper( // Return hresult.
+ mdFieldDef fd, // [IN] field to associate the layout info
+ ULONG ulOffset); // [IN] the offset for the field
+
+ STDMETHODIMP DefineEventHelper(
+ mdTypeDef td, // [IN] the class/interface on which the event is being defined
+ LPCWSTR szEvent, // [IN] Name of the event
+ DWORD dwEventFlags, // [IN] CorEventAttr
+ mdToken tkEventType, // [IN] a reference (mdTypeRef or mdTypeRef) to the Event class
+ mdEvent *pmdEvent); // [OUT] output event token
+
+ STDMETHODIMP AddDeclarativeSecurityHelper(
+ mdToken tk, // [IN] Parent token (typedef/methoddef)
+ DWORD dwAction, // [IN] Security action (CorDeclSecurity)
+ void const *pValue, // [IN] Permission set blob
+ DWORD cbValue, // [IN] Byte count of permission set blob
+ mdPermission*pmdPermission); // [OUT] Output permission token
+
+ STDMETHODIMP SetResolutionScopeHelper( // Return hresult.
+ mdTypeRef tr, // [IN] TypeRef record to update
+ mdToken rs); // [IN] new ResolutionScope
+
+ STDMETHODIMP SetManifestResourceOffsetHelper( // Return hresult.
+ mdManifestResource mr, // [IN] The manifest token
+ ULONG ulOffset); // [IN] new offset
+
+ STDMETHODIMP SetTypeParent( // Return hresult.
+ mdTypeDef td, // [IN] Type definition
+ mdToken tkExtends); // [IN] parent type
+
+ STDMETHODIMP AddInterfaceImpl( // Return hresult.
+ mdTypeDef td, // [IN] Type definition
+ mdToken tkInterface); // [IN] interface type
+
+//*****************************************************************************
+// IMDInternalEmit
+//*****************************************************************************
+
+ STDMETHODIMP ChangeMvid( // S_OK or error.
+ REFGUID newMvid); // GUID to use as the MVID
+
+ STDMETHOD(SetMDUpdateMode)(
+ ULONG updateMode, ULONG *pPreviousUpdateMode);
+
+//*****************************************************************************
+// IMetaDataHelper
+//*****************************************************************************
+ STDMETHODIMP GetMetadata( // Result.
+ ULONG ulSelect, // [IN] Selector.
+ void **ppData); // [OUT] Put pointer to data here.
+
+ STDMETHODIMP_(IUnknown *) GetCachedInternalInterface(BOOL fWithLock); // S_OK or error
+ STDMETHODIMP SetCachedInternalInterface(IUnknown *pUnk); // S_OK or error
+ STDMETHODIMP SetReaderWriterLock(UTSemReadWrite * pSem)
+ {
+ _ASSERTE(m_pSemReadWrite == NULL);
+ m_pSemReadWrite = pSem;
+ INDEBUG(m_pStgdb->m_MiniMd.Debug_SetLock(m_pSemReadWrite);)
+ return NOERROR;
+ }
+ STDMETHODIMP_(UTSemReadWrite *) GetReaderWriterLock() { return m_pSemReadWrite; }
+
+#ifndef FEATURE_METADATA_EMIT
+ // This method is also part of IMetaDataEmit interface, do not declare it twice
+ STDMETHODIMP TranslateSigWithScope(
+ IMetaDataAssemblyImport *pAssemImport, // [IN] assembly importing interface
+ const void *pbHashValue, // [IN] Hash Blob for Assembly.
+ ULONG cbHashValue, // [IN] Count of bytes.
+ IMetaDataImport *import, // [IN] importing interface
+ PCCOR_SIGNATURE pbSigBlob, // [IN] signature in the importing scope
+ ULONG cbSigBlob, // [IN] count of bytes of signature
+ IMetaDataAssemblyEmit *pAssemEmti, // [IN] emit assembly interface
+ IMetaDataEmit *emit, // [IN] emit interface
+ PCOR_SIGNATURE pvTranslatedSig, // [OUT] buffer to hold translated signature
+ ULONG cbTranslatedSigMax,
+ ULONG *pcbTranslatedSig); // [OUT] count of bytes in the translated signature
+#endif //!FEATURE_METADATA_EMIT
+
+ //*****************************************************************************
+ // IGetIMDInternalImport methods
+ //*****************************************************************************
+ STDMETHOD(GetIMDInternalImport) (
+ IMDInternalImport ** ppIMDInternalImport // [OUT] Buffer to receive IMDInternalImport*
+ );
+
+#endif //FEATURE_METADATA_INTERNAL_APIS
+
+//*****************************************************************************
+// IMetaDataTables
+//*****************************************************************************
+
+ // Fills size (*pcbStringsHeapSize) of internal strings heap (#String).
+ // Returns S_OK or error code. Fills *pcbStringsHeapSize with 0 on error.
+ // Implements public API code:IMetaDataTables::GetStringHeapSize.
+ STDMETHODIMP GetStringHeapSize(
+ __out ULONG *pcbStringsHeapSize); // [OUT] Size of the string heap.
+
+ // Fills size (*pcbBlobsHeapSize) of blobs heap (#Blob).
+ // Returns S_OK or error code. Fills *pcbBlobsHeapSize with 0 on error.
+ // Implements public API code:IMetaDataTables::GetBlobHeapSize.
+ STDMETHODIMP GetBlobHeapSize(
+ __out ULONG *pcbBlobsHeapSize); // [OUT] Size of the blob heap.
+
+ // Fills size (*pcbGuidsHeapSize) of guids heap (#GUID).
+ // Returns S_OK or error code. Fills *pcbGuidsHeapSize with 0 on error.
+ // Implements public API code:IMetaDataTables::GetGuidHeapSize.
+ STDMETHODIMP GetGuidHeapSize(
+ __out ULONG *pcbGuidsHeapSize); // [OUT] Size of the Guid heap.
+
+ // Fills size (*pcbUserStringsHeapSize) of user strings heap (#US) (referenced from IL).
+ // Returns S_OK or error code. Fills *pcbUserStringsHeapSize with 0 on error.
+ // Implements public API code:IMetaDataTables::GetUserStringHeapSize.
+ // Backward compatibility: returns S_OK even if the string doesn't have odd number of bytes as specified
+ // in CLI ECMA specification.
+ STDMETHODIMP GetUserStringHeapSize(
+ __out ULONG *pcbUserStringsHeapSize); // [OUT] Size of the user string heap.
+
+ // Implements public API code:IMetaDataTables::GetNumTables.
+ STDMETHODIMP GetNumTables(
+ __out ULONG *pcTables); // [OUT] Count of tables.
+
+ // Implements public API code:IMetaDataTables::GetNumTables.
+ STDMETHODIMP GetTableIndex(
+ ULONG token, // [IN] Token for which to get table index.
+ __out ULONG *pixTbl); // [OUT] Put table index here.
+
+ // Implements public API code:IMetaDataTables::GetTableInfo.
+ STDMETHODIMP GetTableInfo(
+ ULONG ixTbl, // [IN] Which table.
+ ULONG *pcbRow, // [OUT] Size of a row, bytes.
+ ULONG *pcRows, // [OUT] Number of rows.
+ ULONG *pcCols, // [OUT] Number of columns in each row.
+ ULONG *piKey, // [OUT] Key column, or -1 if none.
+ const char **ppName); // [OUT] Name of the table.
+
+ // Implements public API code:IMetaDataTables::GetColumnInfo.
+ STDMETHODIMP GetColumnInfo(
+ ULONG ixTbl, // [IN] Which Table.
+ ULONG ixCol, // [IN] Which Column in the table.
+ ULONG *poCol, // [OUT] Offset of the column in the row.
+ ULONG *pcbCol, // [OUT] Size of a column, bytes.
+ ULONG *pType, // [OUT] Type of the column.
+ const char **ppName); // [OUT] Name of the Column.
+
+ // Implements public API code:IMetaDataTables::GetCodedTokenInfo.
+ STDMETHODIMP GetCodedTokenInfo(
+ ULONG ixCdTkn, // [IN] Which kind of coded token.
+ ULONG *pcTokens, // [OUT] Count of tokens.
+ ULONG **ppTokens, // [OUT] List of tokens.
+ const char **ppName); // [OUT] Name of the CodedToken.
+
+ // Implements public API code:IMetaDataTables::GetRow.
+ STDMETHODIMP GetRow(
+ ULONG ixTbl, // [IN] Which table.
+ ULONG rid, // [IN] Which row.
+ void **ppRow); // [OUT] Put pointer to row here.
+
+ // Implements public API code:IMetaDataTables::GetColumn.
+ STDMETHODIMP GetColumn(
+ ULONG ixTbl, // [IN] Which table.
+ ULONG ixCol, // [IN] Which column.
+ ULONG rid, // [IN] Which row.
+ ULONG *pVal); // [OUT] Put the column contents here.
+
+ //#GetString_IMetaDataTables
+ // Fills internal null-terminated string (*pszString) at index ixString from string heap (#String).
+ // Returns S_OK (even for index 0) or error code (if index is invalid, fills *pszString with NULL then).
+ // Implements public API code:IMetaDataTables::GetString.
+ STDMETHODIMP GetString(
+ ULONG ixString, // [IN] Value from a string column.
+ const char **pszString); // [OUT] Put a pointer to the string here.
+
+ //#GetBlob_IMetaDataTables
+ // Fills blob entry (*ppvData of size *pcbDataSize) at index ixBlob from blob heap (#Blob).
+ // Returns S_OK (even for index 0) or error code (if index is invalid, fills NULL and o then).
+ // Implements public API code:IMetaDataTables::GetBlob.
+ STDMETHODIMP GetBlob(
+ ULONG ixBlob, // [IN] Value from a blob column.
+ ULONG *pcbDataSize, // [OUT] Put size of the blob here.
+ const void **ppvData); // [OUT] Put a pointer to the blob here.
+
+ //#GetGuid_IMetaDataTables
+ // Fills guid (*ppGuid) at index ixGuid from guid heap (#GUID).
+ // Returns S_OK and fills *ppGuid. Returns S_OK even for (invalid) index 0 (fills *ppGuid with pointer
+ // to zeros then).
+ // Retruns error code (if index is invalid except 0, fills NULL and o then).
+ // Implements public API code:IMetaDataTables::GetGuid.
+ // Backward compatibility: returns S_OK even if the index is 0 which is invalid as specified in CLI ECMA
+ // specification. In that case returns pointer to GUID from zeros.
+ STDMETHODIMP GetGuid(
+ ULONG ixGuid, // [IN] Value from a guid column.
+ const GUID **ppGuid); // [OUT] Put a pointer to the GUID here.
+
+ //#GetUserString_IMetaDataTables
+ // Fills user string (*ppvData of size *pcbDataSize) at index ixUserString.
+ // Returns S_OK (even for index 0) or error code (if index is invalid, fills NULL and o then).
+ // Implements public API code:IMetaDataTables::GetUserString.
+ STDMETHODIMP GetUserString(
+ ULONG ixUserString, // [IN] Value from a UserString column.
+ __out ULONG *pcbData, // [OUT] Put size of the UserString here.
+ __deref_out_opt const void **ppData); // [OUT] Put a pointer to the UserString here.
+
+ //#GetNextString_IMetaDataTables
+ // Fills index of string (*pixNextString) from the internal strings heap (#String) starting behind
+ // string at index ixString.
+ // Returns S_OK or S_FALSE (if either index is invalid). Fills *pixNextString with 0 on S_FALSE.
+ // Implements public API code:IMetaDataTables::.GetNextString.
+ STDMETHODIMP GetNextString(
+ ULONG ixString, // [IN] Value from a string column.
+ __out ULONG *pixNextString); // [OUT] Put the index of the next string here.
+
+ //#GetNextBlob_IMetaDataTables
+ // Fills index of blob (*pixNextBlob) from the blobs heap (#Blob) starting behind blob at index ixBlob.
+ // Returns S_OK or S_FALSE (if either index is invalid). Fills *pixNextBlob with 0 on S_FALSE.
+ // Implements public API code:IMetaDataTables::GetNextString.
+ STDMETHODIMP GetNextBlob(
+ ULONG ixBlob, // [IN] Value from a blob column.
+ __out ULONG *pixNextBlob); // [OUT] Put the index of the next blob here.
+
+ //#GetNextGuid_IMetaDataTables
+ // Fills index of guid (*pixNextGuid) from the guids heap (#GUID) starting behind guid at index ixGuid.
+ // Returns S_OK or S_FALSE (if the new index is invalid). Fills *pixNextGuid with 0 on S_FALSE.
+ // Implements public API code:IMetaDataTables::GetNextGuid.
+ // Backward compatibility: returns S_OK even if the guid index (ixGuid) is 0 which is invalid as
+ // specified in CLI ECMA specification.
+ STDMETHODIMP GetNextGuid(
+ ULONG ixGuid, // [IN] Value from a guid column.
+ __out ULONG *pixNextGuid); // [OUT] Put the index of the next guid here.
+
+ //#GetNextUserString_IMetaDataTables
+ // Fills index of user string (*pixNextUserString) from the user strings heap (#US) starting behind string
+ // at index ixUserString.
+ // Returns S_OK or S_FALSE (if either index is invalid). Fills *pixNextUserString with 0 on S_FALSE.
+ // Implements public API code:IMetaDataTables::GetNextUserString.
+ // Backward compatibility: returns S_OK even if the string doesn't have odd number of bytes as specified
+ // in CLI ECMA specification.
+ STDMETHODIMP GetNextUserString(
+ ULONG ixUserString, // [IN] Value from a UserString column.
+ __out ULONG *ixpNextUserString); // [OUT] Put the index of the next user string here.
+
+ // Implements public API code:IMetaDataTables2::GetMetaDataStorage.
+ STDMETHODIMP GetMetaDataStorage(
+ const void **ppvMd, // [OUT] put pointer to MD section here (aka, 'BSJB').
+ ULONG *pcbMd); // [OUT] put size of the stream here.
+
+ // Implements public API code:IMetaDataTables2::GetMetaDataStreamInfo.
+ STDMETHODIMP GetMetaDataStreamInfo( // 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.
+
+#ifndef FEATURE_METADATA_STANDALONE_WINRT
+
+//*****************************************************************************
+// IMetaDataInfo
+//*****************************************************************************
+
+ // Returns the memory region of the mapped file and type of its mapping. The choice of the file mapping
+ // type for each scope is CLR implementation specific and user cannot explicitly set it.
+ //
+ // The memory is valid only as long as the underlying MetaData scope is opened (there's a reference to
+ // a MetaData interface for this scope).
+ //
+ // Returns S_OK, COR_E_NOTSUPPORTED (.obj files, etc.), or E_INVALIDARG (if NULL is passed).
+ // Implements public API code:IMetaDataInfo::GetFileMapping.
+ STDMETHODIMP GetFileMapping(
+ const void ** ppvData, // [out] Pointer to the start of the mapped file.
+ ULONGLONG * pcbData, // [out] Size of the mapped memory region..
+ DWORD * pdwMappingType); // [out] Type of file mapping (code:CorFileMapping).
+
+#endif //!FEATURE_METADATA_STANDALONE_WINRT
+
+#if defined(FEATURE_METADATA_IN_VM) && defined(FEATURE_PREJIT)
+
+//*****************************************************************************
+// IMetaDataCorProfileData
+//*****************************************************************************
+
+ STDMETHOD(SetCorProfileData)(
+ CorProfileData *pProfileData); // [IN] Pointer to profile data
+
+//*****************************************************************************
+// IMDInternalMetadataReorderingOptions
+//*****************************************************************************
+
+ STDMETHOD(SetMetaDataReorderingOptions)(
+ MetaDataReorderingOptions options); // [IN] metadata reordering options
+
+#endif //FEATURE_METADATA_IN_VM && FEATURE_PREJIT
+
+//*****************************************************************************
+// IMDCommon methods
+//*****************************************************************************
+ STDMETHOD_(IMetaModelCommon*, GetMetaModelCommon)()
+ {
+ return GetMiniMd();
+ }
+
+ STDMETHOD_(IMetaModelCommonRO*, GetMetaModelCommonRO)()
+ {
+ if (GetMiniMd()->IsWritable())
+ {
+ _ASSERTE(!"IMetaModelCommonRO methods cannot be used because this importer is writable.");
+ return NULL;
+ }
+ return GetMiniMd();
+ }
+
+
+ // returns the "built for" version of a metadata scope.
+ __checkReturn
+ STDMETHOD(GetVersionString)( // S_OK or error.
+ LPCSTR *pVer); // [OUT] Put version string here.
+
+//*****************************************************************************
+// Helpers.
+//*****************************************************************************
+
+ HRESULT MarkAll(); // mark everything in a module
+
+//*****************************************************************************
+// Open / Create support.
+//*****************************************************************************
+
+ RegMeta();
+ virtual ~RegMeta();
+
+ HRESULT SetOption(OptionValue *pOptionValue);
+
+ // HRESULT Init();
+ // void Cleanup();
+
+ HRESULT InitWithStgdb(
+ IUnknown *pUnk, // The IUnknown that owns the life time for the existing stgdb
+ CLiteWeightStgdbRW *pStgdb); // existing light weight stgdb
+
+ ULONG GetRefCount() { return m_cRef; }
+ HRESULT AddToCache();
+ static HRESULT FindCachedReadOnlyEntry(LPCWSTR szName, DWORD dwOpenFlags, RegMeta **ppMeta);
+ BOOL IsReadOnly() { return IsOfReadOnly(m_OpenFlags); }
+ BOOL IsCopyMemory() { return IsOfCopyMemory(m_OpenFlags); }
+
+
+ // helper function to reopen RegMeta with a new chuck of memory
+ HRESULT ReOpenWithMemory(
+ LPCVOID pData, // [in] Location of scope data.
+ ULONG cbData, // [in] ReOpen flags
+ DWORD dwReOpenFlags); // [in] Size of the data pointed to by pData.
+
+ HRESULT CreateNewMD();
+
+ HRESULT OpenExistingMD(
+ LPCWSTR szDatabase, // Name of database.
+ void *pbData, // Data to open on top of, 0 default.
+ ULONG cbData, // How big is the data.
+ ULONG dwFlags); // Flags to control open.
+
+#ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE
+ HRESULT OpenExistingMD(
+ IMDCustomDataSource* pDataSource, // Name of database.
+ ULONG dwFlags); // Flags to control open.
+#endif
+
+ FORCEINLINE CLiteWeightStgdbRW* GetMiniStgdb() { return m_pStgdb; }
+ FORCEINLINE CMiniMdRW* GetMiniMd() { return &m_pStgdb->m_MiniMd; }
+
+//*****************************************************************************
+
+ bool IsTypeDefDirty() { return m_fIsTypeDefDirty;}
+ void SetTypeDefDirty(bool fDirty) { m_fIsTypeDefDirty = fDirty;}
+
+ bool IsMemberDefDirty() { return m_fIsMemberDefDirty;}
+ void SetMemberDefDirty(bool fDirty) { m_fIsMemberDefDirty = fDirty;}
+
+ FORCEINLINE BOOL IsThreadSafetyOn()
+ {
+ return (m_OptionValue.m_ThreadSafetyOptions & MDThreadSafetyOn) == MDThreadSafetyOn;
+ }
+
+ LPCWSTR GetNameOfDBFile() { return (m_pStgdb->m_wszFileName == NULL) ? W("") : m_pStgdb->m_wszFileName; }
+ DWORD GetLowFileTimeOfDBFile() { return m_pStgdb->m_dwDatabaseLFT; }
+ DWORD GetLowFileSizeOfDBFile() { return m_pStgdb->m_dwDatabaseLFS; }
+protected:
+ // Helper functions used for implementation of MetaData APIs.
+ HRESULT RefToDefOptimization();
+
+ FORCEINLINE BOOL PreserveLocalRefs(CorLocalRefPreservation localRefType)
+ {
+ return (m_OptionValue.m_LocalRefPreservation & localRefType) == localRefType;
+ }
+
+ HRESULT PreSave();
+ HRESULT ProcessFilter();
+ HRESULT ProcessFilterWorker();
+
+ // Initialize the EE
+ HRESULT StartupEE();
+
+ // Define a TypeRef given the name.
+ enum eCheckDups {eCheckDefault=0, eCheckNo=1, eCheckYes=2};
+
+ HRESULT _DefinePermissionSet(
+ mdToken tk, // [IN] the object to be decorated.
+ DWORD dwAction, // [IN] CorDeclSecurity.
+ void const *pvPermission, // [IN] permission blob.
+ ULONG cbPermission, // [IN] count of bytes of pvPermission.
+ mdPermission *ppm); // [OUT] returned permission token.
+
+ HRESULT _DefineTypeRef(
+ mdToken tkResolutionScope, // [IN] ModuleRef or AssemblyRef.
+ const void *szName, // [IN] Name of the TypeRef.
+ BOOL isUnicode, // [IN] Specifies whether the URL is unicode.
+ mdTypeRef *ptk, // [OUT] Put mdTypeRef here.
+ eCheckDups eCheck=eCheckDefault); // [IN] Specifies whether to check for duplicates.
+
+ // Define MethodSemantics
+ HRESULT _DefineMethodSemantics( // S_OK or error.
+ USHORT usAttr, // [IN] CorMethodSemanticsAttr
+ mdMethodDef md, // [IN] Method
+ mdToken tkAssoc, // [IN] Association
+ BOOL bClear); // [IN] Specifies whether to delete the existing records.
+
+ HRESULT _SaveToStream( // S_OK or error.
+ IStream *pIStream, // [IN] A writable stream to save to.
+ DWORD dwSaveFlags); // [IN] Flags for the save.
+
+ HRESULT _SetRVA( // [IN] S_OK or error.
+ mdToken md, // [IN] Member for which to set offset
+ ULONG ulCodeRVA, // [IN] The offset
+ DWORD dwImplFlags);
+
+ HRESULT _DefineEvent( // Return hresult.
+ mdTypeDef td, // [IN] the class/interface on which the event is being defined
+ LPCWSTR szEvent, // [IN] Name of the event
+ DWORD dwEventFlags, // [IN] CorEventAttr
+ mdToken tkEventType, // [IN] a reference (mdTypeRef or mdTypeRef) to the Event class
+ mdEvent *pmdEvent); // [OUT] output event token
+
+ // Creates and sets a row in the InterfaceImpl table. Optionally clear
+ // pre-existing records for the owning class.
+ HRESULT _SetImplements( // S_OK or error.
+ mdToken rTk[], // Array of TypeRef or TypeDef tokens for implemented interfaces.
+ mdTypeDef td, // Implementing TypeDef.
+ BOOL bClear); // Specifies whether to clear the existing records.
+
+ // Sets flags, name and constraints for a single GenericParam record
+ HRESULT _SetGenericParamProps( // S_OK or error.
+ mdGenericParam tkGP, // [IN] Formal parameter token
+ GenericParamRec *pGenericParam, // [IN] GenericParam record ptr
+ DWORD dwParamFlags, // [IN] Flags, for future use (e.g. variance)
+ LPCWSTR szName, // [IN] Optional name
+ DWORD reserved, // [IN] For future use (e.g. non-type parameters)
+ mdToken rtkConstraints[]); // [IN] Array of type constraints (TypeDef,TypeRef,TypeSpec)
+
+ HRESULT _SetTypeDefProps( // S_OK or error.
+ mdTypeDef td, // [IN] The TypeDef.
+ DWORD dwTypeDefFlags, // [IN] TypeDef flags.
+ mdToken tkExtends, // [IN] Base TypeDef or TypeRef.
+ mdToken rtkImplements[]); // [IN] Implemented interfaces.
+
+ HRESULT _SetEventProps1( // Return hresult.
+ mdEvent ev, // [IN] Event token.
+ DWORD dwEventFlags, // [IN] Event flags.
+ mdToken tkEventType); // [IN] Event type class.
+
+ HRESULT _SetEventProps2( // Return hresult.
+ mdEvent ev, // [IN] Event token.
+ mdMethodDef mdAddOn, // [IN] Add method.
+ mdMethodDef mdRemoveOn, // [IN] Remove method.
+ mdMethodDef mdFire, // [IN] Fire method.
+ mdMethodDef rmdOtherMethods[], // [IN] An array of other methods.
+ BOOL bClear); // [IN] Specifies whether to clear the existing MethodSemantics records.
+
+ HRESULT _SetPermissionSetProps( // Return hresult.
+ mdPermission tkPerm, // [IN] Permission token.
+ DWORD dwAction, // [IN] CorDeclSecurity.
+ void const *pvPermission, // [IN] Permission blob.
+ ULONG cbPermission); // [IN] Count of bytes of pvPermission.
+
+ HRESULT _DefinePinvokeMap( // Return hresult.
+ mdToken tk, // [IN] FieldDef or MethodDef.
+ DWORD dwMappingFlags, // [IN] Flags used for mapping.
+ LPCWSTR szImportName, // [IN] Import name.
+ mdModuleRef mrImportDLL); // [IN] ModuleRef token for the target DLL.
+
+ HRESULT _DefineSetConstant( // Return hresult.
+ mdToken tk, // [IN] Parent token.
+ DWORD dwCPlusTypeFlag, // [IN] Flag for the value type, selected ELEMENT_TYPE_*
+ void const *pValue, // [IN] Constant value.
+ ULONG cchString, // [IN] Size of string in wide chars, or -1 for default.
+ BOOL bSearch); // [IN] Specifies whether to search for an existing record.
+
+ HRESULT _SetMethodProps( // S_OK or error.
+ mdMethodDef md, // [IN] The MethodDef.
+ DWORD dwMethodFlags, // [IN] Method attributes.
+ ULONG ulCodeRVA, // [IN] Code RVA.
+ DWORD dwImplFlags); // [IN] MethodImpl flags.
+
+ HRESULT _SetFieldProps( // S_OK or error.
+ mdFieldDef fd, // [IN] The FieldDef.
+ DWORD dwFieldFlags, // [IN] Field attributes.
+ DWORD dwCPlusTypeFlag, // [IN] Flag for the value type, selected ELEMENT_TYPE_*
+ void const *pValue, // [IN] Constant value.
+ ULONG cchValue); // [IN] size of constant value (string, in wide chars).
+
+ HRESULT _SetClassLayout( // S_OK or error.
+ mdTypeDef td, // [IN] The class.
+ ULONG dwPackSize, // [IN] The packing size.
+ ULONG ulClassSize); // [IN, OPTIONAL] The class size.
+
+ HRESULT _SetFieldOffset( // S_OK or error.
+ mdFieldDef fd, // [IN] The field.
+ ULONG ulOffset); // [IN] The offset of the field.
+
+ HRESULT _SetPropertyProps( // S_OK or error.
+ mdProperty pr, // [IN] Property token.
+ DWORD dwPropFlags, // [IN] CorPropertyAttr.
+ DWORD dwCPlusTypeFlag, // [IN] Flag for value type, selected ELEMENT_TYPE_*
+ void const *pValue, // [IN] Constant value.
+ ULONG cchValue, // [IN] size of constant value (string, in wide chars).
+ mdMethodDef mdSetter, // [IN] Setter of the property.
+ mdMethodDef mdGetter, // [IN] Getter of the property.
+ mdMethodDef rmdOtherMethods[]); // [IN] Array of other methods.
+
+ HRESULT _SetParamProps( // Return code.
+ mdParamDef pd, // [IN] Param token.
+ LPCWSTR szName, // [IN] Param name.
+ DWORD dwParamFlags, // [IN] Param flags.
+ DWORD dwCPlusTypeFlag, // [IN] Flag for value type. selected ELEMENT_TYPE_*.
+ void const *pValue, // [OUT] Constant value.
+ ULONG cchValue); // [IN] size of constant value (string, in wide chars).
+
+ HRESULT _SetAssemblyProps( // S_OK or error.
+ mdAssembly pma, // [IN] Assembly token.
+ const void *pbOriginator, // [IN] Originator of the assembly.
+ ULONG cbOriginator, // [IN] Count of bytes in the Originator blob.
+ ULONG ulHashAlgId, // [IN] Hash Algorithm.
+ LPCWSTR szName, // [IN] Name of the assembly.
+ const ASSEMBLYMETADATA *pMetaData, // [IN] Assembly MetaData.
+ DWORD dwAssemblyFlags); // [IN] Flags.
+
+ HRESULT _SetAssemblyRefProps( // S_OK or error.
+ mdAssemblyRef ar, // [IN] AssemblyRefToken.
+ const void *pbPublicKeyOrToken, // [IN] Public key or token of the assembly.
+ ULONG cbPublicKeyOrToken, // [IN] Count of bytes in the public key or token.
+ LPCWSTR szName, // [IN] Name of the assembly being referenced.
+ const ASSEMBLYMETADATA *pMetaData, // [IN] Assembly MetaData.
+ const void *pbHashValue, // [IN] Hash Blob.
+ ULONG cbHashValue, // [IN] Count of bytes in the Hash Blob.
+ DWORD dwAssemblyRefFlags); // [IN] Token for Execution Location.
+
+ HRESULT _SetFileProps( // S_OK or error.
+ mdFile file, // [IN] File token.
+ const void *pbHashValue, // [IN] Hash Blob.
+ ULONG cbHashValue, // [IN] Count of bytes in the Hash Blob.
+ DWORD dwFileFlags) ; // [IN] Flags.
+
+ HRESULT _SetExportedTypeProps( // S_OK or error.
+ mdExportedType ct, // [IN] ExportedType token.
+ mdToken tkImplementation, // [IN] mdFile or mdAssemblyRef that provides the ExportedType.
+ mdTypeDef tkTypeDef, // [IN] TypeDef token within the file.
+ DWORD dwExportedTypeFlags); // [IN] Flags.
+
+ HRESULT _SetManifestResourceProps( // S_OK or error.
+ mdManifestResource mr, // [IN] ManifestResource token.
+ mdToken tkImplementation, // [IN] mdFile or mdAssemblyRef that provides the resource.
+ DWORD dwOffset, // [IN] Offset to the beginning of the resource within the file.
+ DWORD dwResourceFlags); // [IN] Flags.
+
+ HRESULT _DefineTypeDef( // S_OK or error.
+ LPCWSTR szTypeDef, // [IN] Name of TypeDef
+ DWORD dwTypeDefFlags, // [IN] CustomAttribute flags
+ mdToken tkExtends, // [IN] extends this TypeDef or typeref
+ mdToken rtkImplements[], // [IN] Implements interfaces
+ mdTypeDef tdEncloser, // [IN] TypeDef token of the Enclosing Type.
+ mdTypeDef *ptd); // [OUT] Put TypeDef token here
+
+ HRESULT _SetFieldMarshal(
+ mdToken tk, // [IN] given a fieldDef or paramDef token
+ PCCOR_SIGNATURE pvNativeType, // [IN] native type specification
+ ULONG cbNativeType); // [IN] count of bytes of pvNativeType
+
+ HRESULT _IsKnownCustomAttribute( // S_OK, S_FALSE, or error.
+ mdToken tkType, // [IN] Token of custom attribute's type.
+ int *pca); // [OUT] Put value from KnownCustAttr enum here.
+
+ HRESULT _DefineModuleRef( // S_OK or error.
+ LPCWSTR szName, // [IN] DLL name
+ mdModuleRef *pmur); // [OUT] returned module ref token
+
+ HRESULT _HandleKnownCustomAttribute( // S_OK or error.
+ mdToken tkObj, // [IN] Object being attributed.
+ const void *pData, // [IN] Custom Attribute data blob.
+ ULONG cbData, // [IN] Count of bytes in the data.
+ int ca, // [IN] Value from KnownCustAttr enum.
+ int *bKeep); // [OUT} Keep the known CA?
+
+ HRESULT _HandleNativeTypeCustomAttribute(// S_OK or error.
+ mdToken tkObj, // Object being attributed.
+ CaArg *pArgs, // Pointer to args.
+ CaNamedArg *pNamedArgs, // Pointer to named args.
+ CQuickArray<BYTE> &qNativeType); // Native type is built here.
+
+ // Find a given param of a Method.
+ HRESULT _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.
+
+ // Given the signature, return the token for signature.
+ HRESULT _GetTokenFromSig( // S_OK or error.
+ PCCOR_SIGNATURE pvSig, // [IN] Signature to define.
+ ULONG cbSig, // [IN] Size of signature data.
+ mdSignature *pmsig); // [OUT] returned signature token.
+
+ // Turn the specified internal flags on.
+ HRESULT _TurnInternalFlagsOn( // S_OK or error.
+ mdToken tkObj, // [IN] Target object whose internal flags are targeted.
+ DWORD flags); // [IN] Specifies flags to be turned on.
+
+ // This routine eliminates duplicates from the given list of InterfaceImpl tokens
+ // to be defined. It checks for duplicates against the database only if the
+ // TypeDef for which these tokens are being defined is not a new one.
+ HRESULT _InterfaceImplDupProc( // S_OK or error.
+ mdToken rTk[], // Array of TypeRef or TypeDef tokens for implemented interfaces.
+ mdTypeDef td, // Implementing TypeDef.
+ CQuickBytes *pcqbTk); // Quick Byte object for placing the array of unique tokens.
+
+ // Helper : convert a text field signature to a com format
+ HRESULT _ConvertTextElementTypeToComSig(// Return hresult.
+ IMetaDataEmit *emit, // [IN] emit interface.
+ BOOL fCreateTrIfNotFound, // [IN] create typeref if not found or fail out?
+ LPCSTR *ppOneArgSig, // [IN|OUT] class file format signature. On exit, it will be next arg starting point
+ CQuickBytes *pqbNewSig, // [OUT] place holder for COM+ signature
+ ULONG cbStart, // [IN] bytes that are already in pqbNewSig
+ ULONG *pcbCount); // [OUT] count of bytes put into the QuickBytes buffer
+
+ HRESULT _CheckCmodForCallConv( // S_OK, -1 if found, or error.
+ PCCOR_SIGNATURE pbSig, // [IN] Signature to check.
+ ULONG *pcbTotal, // [OUT] Put bytes consumed here.
+ ULONG *pCallConv); // [OUT] If found, put calling convention here.
+
+ HRESULT _SearchOneArgForCallConv( // S_OK, -1 if found, or error.
+ PCCOR_SIGNATURE pbSig, // [IN] Signature to check.
+ ULONG *pcbTotal, // [OUT] Put bytes consumed here.
+ ULONG *pCallConv); // [OUT] If found, put calling convention here.
+
+
+
+ int inline IsGlobalMethodParent(mdTypeDef *ptd)
+ {
+ if (IsGlobalMethodParentTk(*ptd))
+ {
+ *ptd = m_tdModule;
+ return (true);
+ }
+ return (false);
+ }
+
+ int inline IsGlobalMethodParentToken(mdTypeDef td)
+ {
+ return (!IsNilToken(m_tdModule) && td == m_tdModule);
+ }
+
+ FORCEINLINE BOOL IsENCOn()
+ {
+ _ASSERTE( ((m_OptionValue.m_UpdateMode & MDUpdateMask) == MDUpdateENC) ==
+ m_pStgdb->m_MiniMd.IsENCOn() );
+ return (m_OptionValue.m_UpdateMode & MDUpdateMask) == MDUpdateENC;
+ }
+
+ FORCEINLINE BOOL IsIncrementalOn()
+ {
+ return (m_OptionValue.m_UpdateMode & MDUpdateMask) == MDUpdateIncremental;
+ }
+
+ FORCEINLINE BOOL CheckDups(CorCheckDuplicatesFor checkdup)
+ {
+ return ((m_OptionValue.m_DupCheck & checkdup) ||
+ (m_OptionValue.m_UpdateMode == MDUpdateIncremental ||
+ m_OptionValue.m_UpdateMode == MDUpdateENC) );
+ }
+
+ FORCEINLINE HRESULT UpdateENCLog(mdToken tk, CMiniMdRW::eDeltaFuncs funccode = CMiniMdRW::eDeltaFuncDefault)
+ {
+ _ASSERTE( ((m_OptionValue.m_UpdateMode & MDUpdateMask) == MDUpdateENC) ==
+ m_pStgdb->m_MiniMd.IsENCOn() );
+ return m_pStgdb->m_MiniMd.UpdateENCLog(tk, funccode);
+ }
+
+ FORCEINLINE HRESULT UpdateENCLog2(ULONG ixTbl, ULONG iRid, CMiniMdRW::eDeltaFuncs funccode = CMiniMdRW::eDeltaFuncDefault)
+ {
+ _ASSERTE( ((m_OptionValue.m_UpdateMode & MDUpdateMask) == MDUpdateENC) ==
+ m_pStgdb->m_MiniMd.IsENCOn() );
+ return m_pStgdb->m_MiniMd.UpdateENCLog2(ixTbl, iRid, funccode);
+ }
+
+ FORCEINLINE bool IsCallerDefine() { return m_SetAPICaller == DEFINE_API; }
+ FORCEINLINE void SetCallerDefine() { m_SetAPICaller = DEFINE_API; }
+ FORCEINLINE bool IsCallerExternal() { return m_SetAPICaller == EXTERNAL_CALLER; }
+ FORCEINLINE void SetCallerExternal() { m_SetAPICaller = EXTERNAL_CALLER; }
+
+#ifdef FEATURE_METADATA_RELEASE_MEMORY_ON_REOPEN
+ bool IsSafeToDeleteStgdb()
+ {
+ return m_safeToDeleteStgdb && m_pStgdb->m_MiniMd.IsSafeToDelete();
+ }
+
+ FORCEINLINE void MarkUnsafeToDeleteStgdb() { m_safeToDeleteStgdb = false; }
+ FORCEINLINE void MarkSafeToDeleteStgdb() { m_safeToDeleteStgdb = true; }
+#endif
+
+ // Define Validate methods for all tables.
+#undef MiniMdTable
+#define MiniMdTable(x) HRESULT Validate##x(RID rid);
+ MiniMdTables()
+
+ // Validate a record in a generic sense using Meta-Meta data.
+ STDMETHODIMP ValidateRecord(ULONG ixTbl, ULONG ulRow);
+
+ // Validate if the signature is properly formed with regards to the
+ // compression scheme.
+ STDMETHODIMP ValidateSigCompression(
+ mdToken tk, // [IN] Token whose signature needs to be validated.
+ PCCOR_SIGNATURE pbSig, // [IN] Signature.
+ ULONG cbSig); // [IN] Size in bytes of the signature.
+
+ // Validate one argument given the offset to the beginning of the
+ // argument, size of the full signature and the currentl offset value.
+ STDMETHODIMP ValidateOneArg(
+ mdToken tk, // [IN] Token whose signature is being processed.
+ PCCOR_SIGNATURE &pbSig, // [IN] Pointer to the beginning of argument.
+ ULONG cbSig, // [IN] Size in bytes of the full signature.
+ ULONG *pulCurByte, // [IN/OUT] Current offset into the signature..
+ ULONG *pulNSentinels, // [IN/OUT] Number of sentinels
+ BOOL bNoVoidAllowed); // [IN] Flag indicating whether "void" is disallowed for this arg
+
+ // Validate the given Method signature.
+ STDMETHODIMP ValidateMethodSig(
+ mdToken tk, // [IN] Token whose signature needs to be validated.
+ PCCOR_SIGNATURE pbSig, // [IN] Signature.
+ ULONG cbSig, // [IN] Size in bytes of the signature.
+ DWORD dwFlags); // [IN] Method flags.
+
+ // Validate the given Field signature.
+ STDMETHODIMP ValidateFieldSig(
+ mdToken tk, // [IN] Token whose signature needs to be validated.
+ PCCOR_SIGNATURE pbSig, // [IN] Signature.
+ ULONG cbSig); // [IN] Size in bytes of the signature.
+
+ // Validate the given MethodSpec signature.
+ STDMETHODIMP ValidateMethodSpecSig(
+ mdMethodSpec tk, // [IN] Token whose signature needs to be validated.
+ PCCOR_SIGNATURE pbSig, // [IN] Signature.
+ ULONG cbSig, // [IN] Size in bytes of the signature.
+ ULONG *ulArity); // [OUT] Arity of the instantiation.
+
+
+protected:
+
+ // This scope's Stgdb. This stores the actual data which the class then exposes.
+ // This storage may be shared by an internal metadata object too.
+ // This is read-write so that the RegMeta class can implement the emit interfaces.
+ CLiteWeightStgdbRW *m_pStgdb;
+
+ CLiteWeightStgdbRW *m_pStgdbFreeList; // This scope's Stgdb.
+ mdTypeDef m_tdModule; // The global module.
+ IUnknown *m_pUnk; // The IUnknown that owns the Stgdb.
+ FilterManager *m_pFilterManager; // Contains helper functions for marking
+
+#ifdef FEATURE_METADATA_INTERNAL_APIS
+ // Pointer to internal interface. This is a weak reference (it doesn't addref/release).
+ IMDInternalImport *m_pInternalImport;
+#endif //FEATURE_METADATA_INTERNAL_APIS
+
+ UTSemReadWrite *m_pSemReadWrite;
+ bool m_fOwnSem;
+
+ unsigned m_bRemap : 1; // If true, there is a token mapper.
+ unsigned m_bSaveOptimized : 1; // If true, save optimization has been done.
+ unsigned m_hasOptimizedRefToDef : 1; // true if we have performed ref to def optimization
+ IUnknown *m_pHandler;
+ bool m_fIsTypeDefDirty; // This flag is set when the TypeRef to TypeDef map is not valid
+ bool m_fIsMemberDefDirty; // This flag is set when the MemberRef to MemberDef map is not valid
+ bool m_fStartedEE; // Set when EE runtime has been started up.
+#ifdef FEATURE_INCLUDE_ALL_INTERFACES
+ ICorRuntimeHost *m_pCorHost; // Hosting environment for EE runtime.
+#endif // FEATURE_INCLUDE_ALL_INTERFACES
+ IUnknown *m_pAppDomain; // AppDomain in which managed security code will be run.
+
+private:
+ ULONG m_OpenFlags; // Open time flags.
+
+ LONG m_cRef; // Ref count.
+#ifdef FEATURE_METADATA_EMIT_ALL
+ NEWMERGER m_newMerger; // class for handling merge
+#endif //FEATURE_METADATA_EMIT_ALL
+ IUnknown *m_pFreeThreadedMarshaler; // FreeThreadedMarshaler
+
+#ifdef FEATURE_METADATA_PERF_STATS
+ MDCompilerPerf m_MDCompilerPerf; // Compiler perf object to store all stats.
+#endif
+
+ // If true, cached in list of global scopes. This is very dangerous because it may allow
+ // unpredictable state sharing between seemingly unrelated dispensers.
+ bool m_bCached;
+
+ OptionValue m_OptionValue;
+
+ mdTypeRef m_trLanguageType;
+
+ // Specifies whether the caller of the Set API is one of the Define functions
+ // or an external API. This allows for performance optimization in the Set APIs
+ // by not checking for Duplicates in certain cases.
+ SetAPICallerType m_SetAPICaller;
+
+ CorValidatorModuleType m_ModuleType;
+ IVEHandler *m_pVEHandler;
+#ifndef FEATURE_CORECLR
+ ValidateRecordFunction m_ValidateRecordFunctionTable[TBL_COUNT];
+#endif
+ CCustAttrHash m_caHash; // Hashed list of custom attribute types seen.
+
+ bool m_bKeepKnownCa; // Should all known CA's be kept?
+
+ CorProfileData *m_pCorProfileData;
+
+ MetaDataReorderingOptions m_ReorderingOptions;
+
+#ifdef FEATURE_METADATA_RELEASE_MEMORY_ON_REOPEN
+ bool m_safeToDeleteStgdb; // This starts out true, but gets set to FALSE if we detect
+ // a RegMeta API call that might have given out an internal pointer.
+ // There is an equivalent state in MiniMD, and both must be
+ // TRUE in order to delete safely.
+#endif
+
+ HRESULT _ValidateErrorHelper(
+ HRESULT VECode,
+ VEContext Context);
+
+ HRESULT _ValidateErrorHelper(
+ HRESULT VECode,
+ VEContext Context,
+ ULONG ulVal1);
+
+ HRESULT _ValidateErrorHelper(
+ HRESULT VECode,
+ VEContext Context,
+ ULONG ulVal1,
+ ULONG ulVal2);
+
+ HRESULT _ValidateErrorHelper(
+ HRESULT VECode,
+ VEContext Context,
+ ULONG ulVal1,
+ ULONG ulVal2,
+ ULONG ulVal3);
+
+private:
+ // Returns pointer to zeros of size (cbSize).
+ // Used by public APIs to return compatible values with previous releases.
+ static const BYTE *GetPublicApiCompatibilityZerosOfSize(UINT32 cbSize);
+ // Returns pointer to zeros typed as type T.
+ // Used by public APIs to return compatible values with previous releases.
+ template<class T>
+ T *GetPublicApiCompatibilityZeros()
+ {
+ static_assert_no_msg(sizeof(T) <= sizeof(s_rgMetaDataPublicApiCompatibilityZeros));
+ return reinterpret_cast<T *>(s_rgMetaDataPublicApiCompatibilityZeros);
+ }
+ // Zeros used by public APIs as return value (or pointer to this memory) for invalid input.
+ // It is used by methods:
+ // * code:RegMeta::GetPublicApiCompatibilityZeros, and
+ // * code:RegMeta::GetPublicApiCompatibilityZerosOfSize.
+ static const BYTE s_rgMetaDataPublicApiCompatibilityZeros[64];
+
+}; // class RegMeta
+
+
+#endif // __RegMeta__h__
diff --git a/src/md/compiler/regmeta_compilersupport.cpp b/src/md/compiler/regmeta_compilersupport.cpp
new file mode 100644
index 0000000000..0bea06699b
--- /dev/null
+++ b/src/md/compiler/regmeta_compilersupport.cpp
@@ -0,0 +1,506 @@
+// 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.
+//*****************************************************************************
+// RegMeta.cpp
+//
+
+//
+// Implementation for meta data public interface methods.
+//
+//*****************************************************************************
+#include "stdafx.h"
+#include "regmeta.h"
+#include "metadata.h"
+#include "corerror.h"
+#include "mdutil.h"
+#include "rwutil.h"
+#include "mdlog.h"
+#include "importhelper.h"
+#include "filtermanager.h"
+#include "mdperf.h"
+#include "switches.h"
+#include "posterror.h"
+#include "stgio.h"
+#include "sstring.h"
+
+#include <metamodelrw.h>
+
+#define DEFINE_CUSTOM_NODUPCHECK 1
+#define DEFINE_CUSTOM_DUPCHECK 2
+#define SET_CUSTOM 3
+
+#if defined(_DEBUG) && defined(_TRACE_REMAPS)
+#define LOGGING
+#endif
+#include <log.h>
+
+#ifdef _MSC_VER
+#pragma warning(disable: 4102)
+#endif
+
+#ifdef FEATURE_METADATA_EMIT
+
+//*****************************************************************************
+// Merge the pImport scope to this scope
+//*****************************************************************************
+STDMETHODIMP RegMeta::Merge( // S_OK or error.
+ IMetaDataImport *pImport, // [IN] The scope to be merged.
+ IMapToken *pHostMapToken, // [IN] Host IMapToken interface to receive token remap notification
+ IUnknown *pHandler) // [IN] An object to receive to receive error notification.
+{
+#ifdef FEATURE_METADATA_EMIT_ALL
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ IMetaDataImport2 *pI2=NULL;
+
+ LOG((LOGMD, "RegMeta::Merge(0x%08x, 0x%08x)\n", pImport, pHandler));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(VerifyNotWinMD(pImport, "IMetaDataEmit::Merge(): merging with a .winmd file not supported."));
+
+ IfFailGo(pImport->QueryInterface(IID_IMetaDataImport2, (void**)&pI2));
+ m_hasOptimizedRefToDef = false;
+
+ // track this import
+ IfFailGo( m_newMerger.AddImport(pI2, pHostMapToken, pHandler) );
+
+ErrExit:
+ if (pI2)
+ pI2->Release();
+ STOP_MD_PERF(Merge);
+ END_ENTRYPOINT_NOTHROW;
+
+ return (hr);
+#else //!FEATURE_METADATA_EMIT_ALL
+ return E_NOTIMPL;
+#endif //!FEATURE_METADATA_EMIT_ALL
+} // RegMeta::Merge
+
+
+//*****************************************************************************
+// real merge takes place here
+//*****************************************************************************
+STDMETHODIMP RegMeta::MergeEnd() // S_OK or error.
+{
+#ifdef FEATURE_METADATA_EMIT_ALL
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "RegMeta::MergeEnd()\n"));
+ START_MD_PERF();
+ LOCKWRITE();
+ // Merge happens here!!
+
+ // <REVISIT_TODO>bug 16719. Merge itself is doing a lots of small changes in literally
+ // dozens of places. It would be to hard to maintain and would cause code
+ // bloat to auto-grow the tables. So instead, we've opted to just expand
+ // the world right away and avoid the trouble.</REVISIT_TODO>
+ IfFailGo(m_pStgdb->m_MiniMd.ExpandTables());
+
+ IfFailGo(m_newMerger.Merge(m_OptionValue.m_MergeOptions, m_OptionValue.m_RefToDefCheck) );
+
+ErrExit:
+ STOP_MD_PERF(MergeEnd);
+ END_ENTRYPOINT_NOTHROW;
+
+ return (hr);
+#else //!FEATURE_METADATA_EMIT_ALL
+ return E_NOTIMPL;
+#endif //!FEATURE_METADATA_EMIT_ALL
+} // RegMeta::MergeEnd
+
+
+//*****************************************************************************
+// As the Stgdb object to get the save size for the metadata delta.
+//*****************************************************************************
+STDMETHODIMP RegMeta::GetDeltaSaveSize( // S_OK or error.
+ CorSaveSize fSave, // [IN] cssAccurate or cssQuick.
+ DWORD *pdwSaveSize) // [OUT] Put the size here.
+{
+#ifdef FEATURE_METADATA_EMIT_ALL
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ // Make sure we're in EnC mode
+ if (!IsENCOn())
+ {
+ _ASSERTE(!"Not in EnC mode!");
+ IfFailGo(META_E_NOT_IN_ENC_MODE);
+ }
+
+ m_pStgdb->m_MiniMd.EnableDeltaMetadataGeneration();
+ hr = GetSaveSize(fSave, pdwSaveSize);
+ m_pStgdb->m_MiniMd.DisableDeltaMetadataGeneration();
+
+ErrExit:
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+#else //!FEATURE_METADATA_EMIT_ALL
+ return E_NOTIMPL;
+#endif //!FEATURE_METADATA_EMIT_ALL
+} // RegMeta::GetDeltaSaveSize
+
+//*****************************************************************************
+// Saves a metadata delta to a file of a given name.
+//*****************************************************************************
+STDMETHODIMP RegMeta::SaveDelta( // S_OK or error.
+ LPCWSTR szFile, // [IN] The filename to save to.
+ DWORD dwSaveFlags) // [IN] Flags for the save.
+{
+#ifdef FEATURE_METADATA_EMIT_ALL
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+
+ // Make sure we're in EnC mode
+ if (!IsENCOn())
+ {
+ _ASSERTE(!"Not in EnC mode!");
+ IfFailGo(META_E_NOT_IN_ENC_MODE);
+ }
+
+
+
+ m_pStgdb->m_MiniMd.EnableDeltaMetadataGeneration();
+ hr = Save(szFile, dwSaveFlags);
+ m_pStgdb->m_MiniMd.DisableDeltaMetadataGeneration();
+
+ErrExit:
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+#else //!FEATURE_METADATA_EMIT_ALL
+ return E_NOTIMPL;
+#endif //!FEATURE_METADATA_EMIT_ALL
+} // RegMeta::SaveDelta
+
+//*****************************************************************************
+// Saves a metadata delta to a stream.
+//*****************************************************************************
+STDMETHODIMP RegMeta::SaveDeltaToStream( // S_OK or error.
+ IStream *pIStream, // [IN] A writable stream to save to.
+ DWORD dwSaveFlags) // [IN] Flags for the save.
+{
+#ifdef FEATURE_METADATA_EMIT_ALL
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ // Make sure we're in EnC mode
+ if (!IsENCOn())
+ {
+ _ASSERTE(!"Not in EnC mode!");
+ IfFailGo(META_E_NOT_IN_ENC_MODE);
+ }
+
+
+
+ m_pStgdb->m_MiniMd.EnableDeltaMetadataGeneration();
+ hr = SaveToStream(pIStream, dwSaveFlags);
+ m_pStgdb->m_MiniMd.DisableDeltaMetadataGeneration();
+
+ErrExit:
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+#else //!FEATURE_METADATA_EMIT_ALL
+ return E_NOTIMPL;
+#endif //!FEATURE_METADATA_EMIT_ALL
+} // RegMeta::SaveDeltaToStream
+
+//*****************************************************************************
+// Saves a copy of the scope into the memory buffer provided. The buffer size
+// must be at least as large as the GetSaveSize value.
+//*****************************************************************************
+STDMETHODIMP RegMeta::SaveDeltaToMemory( // S_OK or error.
+ void *pbData, // [OUT] Location to write data.
+ ULONG cbData) // [IN] Max size of data buffer.
+{
+#ifdef FEATURE_METADATA_EMIT_ALL
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ // Make sure we're in EnC mode
+ if (!IsENCOn())
+ {
+ _ASSERTE(!"Not in EnC mode!");
+ IfFailGo(META_E_NOT_IN_ENC_MODE);
+ }
+
+
+ m_pStgdb->m_MiniMd.EnableDeltaMetadataGeneration();
+ hr = SaveToMemory(pbData, cbData);
+ m_pStgdb->m_MiniMd.DisableDeltaMetadataGeneration();
+
+ErrExit:
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+#else //!FEATURE_METADATA_EMIT_ALL
+ return E_NOTIMPL;
+#endif //!FEATURE_METADATA_EMIT_ALL
+} // RegMeta::SaveDeltaToMemory
+
+//*****************************************************************************
+// Resets the current edit and continue session
+//
+// Implements public API code:IMetaDataEmit2::ResetENCLog.
+//*****************************************************************************
+STDMETHODIMP
+RegMeta::ResetENCLog()
+{
+#ifdef FEATURE_METADATA_EMIT_ALL
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ // Make sure we're in EnC mode
+ if (!IsENCOn())
+ {
+ _ASSERTE(!"Not in EnC mode!");
+ IfFailGo(META_E_NOT_IN_ENC_MODE);
+ }
+
+ IfFailGo(m_pStgdb->m_MiniMd.ResetENCLog());
+ErrExit:
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+#else //!FEATURE_METADATA_EMIT_ALL
+ return E_NOTIMPL;
+#endif //!FEATURE_METADATA_EMIT_ALL
+} // RegMeta::ResetENCLog
+
+#ifdef FEATURE_METADATA_EMIT_ALL
+
+// Helper for code:RegMeta::ProcessFilter
+HRESULT RegMeta::ProcessFilterWorker()
+{
+ HRESULT hr = S_OK;
+
+ CMiniMdRW *pMiniMd; // The MiniMd with the data.
+ RegMeta *pMetaNew = NULL;
+ CMapToken *pMergeMap = NULL;
+ IMapToken *pMapNew = NULL;
+ MergeTokenManager *pCompositHandler = NULL;
+ IMapToken *pHostMapToken = NULL;
+
+ // For convenience.
+ pMiniMd = &(m_pStgdb->m_MiniMd);
+ IfNullGo( pMiniMd->GetFilterTable() );
+ _ASSERTE(pMiniMd->GetFilterTable()->Count() != 0); // caller verified this
+
+ // Yes, client has used filter to specify what are the metadata needed.
+ // We will create another instance of RegMeta and make this module an imported module
+ // to be merged into the new RegMeta. We will provide the handler to track all of the token
+ // movements. We will replace the merged light weight stgdb to this RegMeta..
+ // Then we will need to fix up the MergeTokenManager with this new movement.
+ // The reason that we decide to choose this approach is because it will be more complicated
+ // and very likely less efficient to fix up the signature blob pool and then compact all of the pools!
+ //
+
+ // Create a new RegMeta.
+ pMetaNew = new (nothrow) RegMeta();
+ IfNullGo( pMetaNew );
+ pMetaNew->AddRef();
+ IfFailGo(pMetaNew->SetOption(&m_OptionValue));
+
+
+ // Remember the open type.
+ IfFailGo(pMetaNew->CreateNewMD());
+ IfFailGo(pMetaNew->AddToCache());
+
+ // Ignore the error return by setting handler
+ hr = pMetaNew->SetHandler(m_pHandler);
+
+ // create the IMapToken to receive token remap information from merge
+ pMergeMap = new (nothrow) CMapToken;
+ IfNullGo( pMergeMap );
+
+ // use merge to filter out the unneeded data. But we need to keep COMType and also need to drop off the
+ // CustomAttributes that associated with MemberRef with parent MethodDef
+ //
+ pMetaNew->m_hasOptimizedRefToDef = false;
+ IfFailGo( pMetaNew->m_newMerger.AddImport(this, pMergeMap, NULL) );
+ IfFailGo( pMetaNew->m_pStgdb->m_MiniMd.ExpandTables());
+ IfFailGo( pMetaNew->m_newMerger.Merge((MergeFlags)(MergeManifest | DropMemberRefCAs | NoDupCheck), MDRefToDefDefault) );
+
+ // Now we need to recalculate the token movement
+ //
+ if (m_newMerger.m_pImportDataList)
+ {
+
+ // This is the case the filter is applied to merged emit scope. We need calculate how this implicit merge
+ // affects the original merge remap. Basically we need to walk all the m_pTkMapList in the merger and replace
+ // the to token to the most recent to token.
+ //
+ MDTOKENMAP *pMDTokenMapList;
+
+ pMDTokenMapList = m_newMerger.m_pImportDataList->m_pMDTokenMap;
+
+ MDTOKENMAP *pMap;
+ TOKENREC *pTKRec;
+ ULONG i;
+ mdToken tkFinalTo;
+ ModuleRec *pMod;
+ ModuleRec *pModNew;
+ LPCUTF8 szName;
+
+ // update each import map from merge to have the m_tkTo points to the final mapped to token
+ for (pMap = pMDTokenMapList; pMap; pMap = pMap->m_pNextMap)
+ {
+ // update each record
+ for (i = 0; i < (ULONG) (pMap->Count()); i++)
+ {
+ TOKENREC *pRecTo;
+ pTKRec = pMap->Get(i);
+ if ( pMergeMap->Find( pTKRec->m_tkTo, &pRecTo ) )
+ {
+ // This record is kept by the filter and the tkTo is changed
+ pRecTo->m_isFoundInImport = true;
+ tkFinalTo = pRecTo->m_tkTo;
+ pTKRec->m_tkTo = tkFinalTo;
+ pTKRec->m_isDeleted = false;
+
+ // send the notification now. Because after merge, we may have everything in order and
+ // won't send another set of notification.
+ //
+ LOG((LOGMD, "TokenRemap in RegMeta::ProcessFilter (IMapToken 0x%08x): from 0x%08x to 0x%08x\n", pMap->m_pMap, pTKRec->m_tkFrom, pTKRec->m_tkTo));
+
+ pMap->m_pMap->Map(pTKRec->m_tkFrom, pTKRec->m_tkTo);
+ }
+ else
+ {
+ // This record is pruned by the filter upon save
+ pTKRec->m_isDeleted = true;
+ }
+ }
+ }
+
+ // now walk the pMergeMap and check to see if there is any entry that is not set to true for m_isFoundInImport.
+ // These are the records that from calling DefineXXX methods directly on the Emitting scope!
+ if (m_pHandler)
+ m_pHandler->QueryInterface(IID_IMapToken, (void **)&pHostMapToken);
+ if (pHostMapToken)
+ {
+ for (i = 0; i < (ULONG) (pMergeMap->m_pTKMap->Count()); i++)
+ {
+ pTKRec = pMergeMap->m_pTKMap->Get(i);
+ if (pTKRec->m_isFoundInImport == false)
+ {
+ LOG((LOGMD, "TokenRemap in RegMeta::ProcessFilter (default IMapToken 0x%08x): from 0x%08x to 0x%08x\n", pHostMapToken, pTKRec->m_tkFrom, pTKRec->m_tkTo));
+
+ // send the notification on the IMapToken from SetHandler of this RegMeta
+ pHostMapToken->Map(pTKRec->m_tkFrom, pTKRec->m_tkTo);
+ }
+ }
+ }
+
+ // Preserve module name across merge.
+ IfFailGo(m_pStgdb->m_MiniMd.GetModuleRecord(1, &pMod));
+ IfFailGo(pMetaNew->m_pStgdb->m_MiniMd.GetModuleRecord(1, &pModNew));
+ IfFailGo(m_pStgdb->m_MiniMd.getNameOfModule(pMod, &szName));
+ IfFailGo(pMetaNew->m_pStgdb->m_MiniMd.PutString(TBL_Module, ModuleRec::COL_Name, pModNew, szName));
+
+ // now swap the stgdb but keep the merger...
+ _ASSERTE( !IsOfExternalStgDB(m_OpenFlags) );
+
+ CLiteWeightStgdbRW * pStgdbTmp = m_pStgdb;
+ m_pStgdb = pMetaNew->m_pStgdb;
+ pMetaNew->m_pStgdb = pStgdbTmp;
+ // Update RuntimeVersion string pointers to point to the owning RegMeta string (the strings are 2 copies of the same string content)
+ m_pStgdb->m_MiniMd.m_OptionValue.m_RuntimeVersion = m_OptionValue.m_RuntimeVersion;
+ pMetaNew->m_pStgdb->m_MiniMd.m_OptionValue.m_RuntimeVersion = pMetaNew->m_OptionValue.m_RuntimeVersion;
+ }
+ else
+ {
+ // swap the Stgdb
+ CLiteWeightStgdbRW * pStgdbTmp = m_pStgdb;
+ m_pStgdb = pMetaNew->m_pStgdb;
+ pMetaNew->m_pStgdb = pStgdbTmp;
+ // Update RuntimeVersion string pointers to point to the owning RegMeta string (the strings are 2 copies of the same string content)
+ m_pStgdb->m_MiniMd.m_OptionValue.m_RuntimeVersion = m_OptionValue.m_RuntimeVersion;
+ pMetaNew->m_pStgdb->m_MiniMd.m_OptionValue.m_RuntimeVersion = pMetaNew->m_OptionValue.m_RuntimeVersion;
+
+ // Client either open an existing scope and apply the filter mechanism, or client define the scope and then
+ // apply the filter mechanism.
+
+ // In this case, host better has supplied the handler!!
+ _ASSERTE( m_bRemap && m_pHandler);
+ IfFailGo( m_pHandler->QueryInterface(IID_IMapToken, (void **) &pMapNew) );
+
+
+ {
+ // Send the notification of token movement now because after merge we may not move tokens again
+ // and thus no token notification will be send.
+ MDTOKENMAP *pMap = pMergeMap->m_pTKMap;
+ TOKENREC *pTKRec;
+ ULONG i;
+
+ for (i=0; i < (ULONG) (pMap->Count()); i++)
+ {
+ pTKRec = pMap->Get(i);
+ pMap->m_pMap->Map(pTKRec->m_tkFrom, pTKRec->m_tkTo);
+ }
+
+ }
+
+
+ // What we need to do here is create a IMapToken that will replace the original handler. This new IMapToken
+ // upon called will first map the from token to the most original from token.
+ //
+ pCompositHandler = new (nothrow) MergeTokenManager(pMergeMap->m_pTKMap, NULL);
+ IfNullGo( pCompositHandler );
+
+ // now update the following field to hold on to the real IMapToken supplied by our client by SetHandler
+ if (pMergeMap->m_pTKMap->m_pMap)
+ pMergeMap->m_pTKMap->m_pMap->Release();
+ _ASSERTE(pMapNew);
+ pMergeMap->m_pTKMap->m_pMap = pMapNew;
+
+ // ownership transferred
+ pMergeMap = NULL;
+ pMapNew = NULL;
+
+ // now you want to replace all of the IMapToken set by calling SetHandler to this new MergeTokenManager
+ IfFailGo( m_pStgdb->m_MiniMd.SetHandler(pCompositHandler) );
+
+ m_pHandler = pCompositHandler;
+
+ // ownership transferred
+ pCompositHandler = NULL;
+ }
+
+ // Force a ref to def optimization because the remap information was stored in the thrown away CMiniMdRW
+ m_hasOptimizedRefToDef = false;
+ IfFailGo( RefToDefOptimization() );
+
+ErrExit:
+ if (pHostMapToken)
+ pHostMapToken->Release();
+ if (pMetaNew)
+ pMetaNew->Release();
+ if (pMergeMap)
+ pMergeMap->Release();
+ if (pCompositHandler)
+ pCompositHandler->Release();
+ if (pMapNew)
+ pMapNew->Release();
+
+ return hr;
+} // RegMeta::ProcessFilter
+
+#endif //FEATURE_METADATA_EMIT_ALL
+
+#endif //FEATURE_METADATA_EMIT
diff --git a/src/md/compiler/regmeta_emit.cpp b/src/md/compiler/regmeta_emit.cpp
new file mode 100644
index 0000000000..22d2979343
--- /dev/null
+++ b/src/md/compiler/regmeta_emit.cpp
@@ -0,0 +1,2116 @@
+// 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: RegMeta_IMetaDataImport.cpp
+//
+
+//
+// Some methods of code:RegMeta class which implement public API interfaces:
+// * code:IMetaDataEmit
+// * code:IMetaDataEmit2
+//
+// ======================================================================================
+
+#include "stdafx.h"
+#include "regmeta.h"
+#include "metadata.h"
+#include "corerror.h"
+#include "mdutil.h"
+#include "rwutil.h"
+#include "mdlog.h"
+#include "importhelper.h"
+#include "filtermanager.h"
+#include "mdperf.h"
+#include "switches.h"
+#include "posterror.h"
+#include "stgio.h"
+#include "sstring.h"
+
+#include <metamodelrw.h>
+
+#define DEFINE_CUSTOM_NODUPCHECK 1
+#define DEFINE_CUSTOM_DUPCHECK 2
+#define SET_CUSTOM 3
+
+#if defined(_DEBUG) && defined(_TRACE_REMAPS)
+#define LOGGING
+#endif
+#include <log.h>
+
+#ifdef _MSC_VER
+#pragma warning(disable: 4102)
+#endif
+
+#ifdef FEATURE_METADATA_EMIT
+
+//*****************************************************************************
+// Set module properties on a scope.
+//*****************************************************************************
+STDMETHODIMP RegMeta::SetModuleProps( // S_OK or error.
+ LPCWSTR szName) // [IN] If not NULL, the name to set.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ ModuleRec *pModule; // The module record to modify.
+
+ LOG((LOGMD, "RegMeta::SetModuleProps(%S)\n", MDSTR(szName)));
+
+
+ START_MD_PERF()
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetModuleRecord(1, &pModule));
+ if (szName != NULL)
+ {
+ LPCWSTR szFile = NULL;
+ size_t cchFile;
+
+ SplitPathInterior(szName, NULL, 0, NULL, 0, &szFile, &cchFile, NULL, 0);
+ IfFailGo(m_pStgdb->m_MiniMd.PutStringW(TBL_Module, ModuleRec::COL_Name, pModule, szFile));
+ }
+
+ IfFailGo(UpdateENCLog(TokenFromRid(1, mdtModule)));
+
+ErrExit:
+
+ STOP_MD_PERF(SetModuleProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::SetModuleProps()
+
+//*****************************************************************************
+// Saves a scope to a file of a given name.
+//*****************************************************************************
+STDMETHODIMP RegMeta::Save( // S_OK or error.
+ LPCWSTR szFile, // [IN] The filename to save to.
+ DWORD dwSaveFlags) // [IN] Flags for the save.
+{
+ HRESULT hr=S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "RegMeta::Save(%S, 0x%08x)\n", MDSTR(szFile), dwSaveFlags));
+ START_MD_PERF()
+ LOCKWRITE();
+
+ // Check reserved param..
+ if (dwSaveFlags != 0)
+ IfFailGo (E_INVALIDARG);
+ IfFailGo(PreSave());
+ IfFailGo(m_pStgdb->Save(szFile, dwSaveFlags));
+
+ // Reset m_bSaveOptimized, this is to handle the incremental and ENC
+ // scenerios where one may do multiple saves.
+ _ASSERTE(m_bSaveOptimized && !m_pStgdb->m_MiniMd.IsPreSaveDone());
+ m_bSaveOptimized = false;
+
+#if defined(_DEBUG)
+ if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_RegMetaDump))
+ {
+ int DumpMD_impl(RegMeta *pMD);
+ DumpMD_impl(this);
+ }
+#endif // _DEBUG
+
+ErrExit:
+
+ STOP_MD_PERF(Save);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::Save()
+
+//*****************************************************************************
+// Saves a scope to a stream.
+//*****************************************************************************
+STDMETHODIMP RegMeta::SaveToStream( // S_OK or error.
+ IStream *pIStream, // [IN] A writable stream to save to.
+ DWORD dwSaveFlags) // [IN] Flags for the save.
+{
+ HRESULT hr=S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOCKWRITE();
+
+ LOG((LOGMD, "RegMeta::SaveToStream(0x%08x, 0x%08x)\n", pIStream, dwSaveFlags));
+ START_MD_PERF()
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ hr = _SaveToStream(pIStream, dwSaveFlags);
+
+ STOP_MD_PERF(SaveToStream);
+
+#if defined(_DEBUG)
+ if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_RegMetaDump))
+ {
+ int DumpMD_impl(RegMeta *pMD);
+ DumpMD_impl(this);
+ }
+#endif // _DEBUG
+
+ErrExit:
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::SaveToStream()
+
+//*****************************************************************************
+// Saves a scope to a stream.
+//*****************************************************************************
+HRESULT RegMeta::_SaveToStream( // S_OK or error.
+ IStream *pIStream, // [IN] A writable stream to save to.
+ DWORD dwSaveFlags) // [IN] Flags for the save.
+{
+ HRESULT hr=S_OK;
+
+ IfFailGo(PreSave());
+ IfFailGo( m_pStgdb->SaveToStream(pIStream, m_ReorderingOptions, m_pCorProfileData) );
+
+ // Reset m_bSaveOptimized, this is to handle the incremental and ENC
+ // scenerios where one may do multiple saves.
+ _ASSERTE(m_bSaveOptimized && !m_pStgdb->m_MiniMd.IsPreSaveDone());
+ m_bSaveOptimized = false;
+
+ErrExit:
+
+ return hr;
+} // STDMETHODIMP RegMeta::_SaveToStream()
+
+//*****************************************************************************
+// Saves a copy of the scope into the memory buffer provided. The buffer size
+// must be at least as large as the GetSaveSize value.
+//*****************************************************************************
+STDMETHODIMP RegMeta::SaveToMemory( // S_OK or error.
+ void *pbData, // [OUT] Location to write data.
+ ULONG cbData) // [IN] Max size of data buffer.
+{
+ HRESULT hr;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ IStream *pStream = 0; // Working pointer for save.
+
+ LOG((LOGMD, "MD RegMeta::SaveToMemory(0x%08x, 0x%08x)\n",
+ pbData, cbData));
+ START_MD_PERF();
+
+#ifdef _DEBUG
+ ULONG cbActual; // Size of the real data.
+ IfFailGo(GetSaveSize(cssAccurate, &cbActual));
+ _ASSERTE(cbData >= cbActual);
+#endif
+
+ { // cannot lock before the debug statement. Because GetSaveSize is also a public API which will take the Write lock.
+ LOCKWRITE();
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+ // Create a stream interface on top of the user's data buffer, then simply
+ // call the save to stream method.
+ IfFailGo(CInMemoryStream::CreateStreamOnMemory(pbData, cbData, &pStream));
+ IfFailGo(_SaveToStream(pStream, 0));
+ }
+ErrExit:
+ if (pStream)
+ pStream->Release();
+ STOP_MD_PERF(SaveToMemory);
+ END_ENTRYPOINT_NOTHROW;
+
+ return (hr);
+} // STDMETHODIMP RegMeta::SaveToMemory()
+
+//*****************************************************************************
+// As the Stgdb object to get the save size for the scope.
+//*****************************************************************************
+STDMETHODIMP RegMeta::GetSaveSize( // S_OK or error.
+ CorSaveSize fSave, // [IN] cssAccurate or cssQuick.
+ DWORD *pdwSaveSize) // [OUT] Put the size here.
+{
+ HRESULT hr=S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ FilterTable *ft = NULL;
+
+ LOG((LOGMD, "RegMeta::GetSaveSize(0x%08x, 0x%08x)\n", fSave, pdwSaveSize));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ ft = m_pStgdb->m_MiniMd.GetFilterTable();
+ IfNullGo(ft);
+
+ if (m_pStgdb->m_MiniMd.m_UserStringHeap.GetUnalignedSize() == 0)
+ {
+ if (!IsENCDelta(m_pStgdb->m_MiniMd.m_OptionValue.m_UpdateMode) &&
+ !m_pStgdb->m_MiniMd.IsMinimalDelta())
+ {
+ BYTE rgData[] = {' ', 0, 0};
+ UINT32 nIndex;
+ IfFailGo(m_pStgdb->m_MiniMd.PutUserString(
+ MetaData::DataBlob(rgData, sizeof(rgData)),
+ &nIndex));
+ // Make sure this user string is marked
+ if (ft->Count() != 0)
+ {
+ IfFailGo( m_pFilterManager->MarkNewUserString(TokenFromRid(nIndex, mdtString)));
+ }
+ }
+ }
+
+
+ if (ft->Count() != 0)
+ {
+ int iCount;
+
+ // There is filter table. Linker is using /opt:ref.
+ // Make sure that we are marking the AssemblyDef token!
+ iCount = m_pStgdb->m_MiniMd.getCountAssemblys();
+ _ASSERTE(iCount <= 1);
+
+ if (iCount)
+ {
+ IfFailGo(m_pFilterManager->Mark(TokenFromRid(iCount, mdtAssembly)));
+ }
+ }
+#ifdef FEATURE_METADATA_EMIT_ALL
+ else if (m_newMerger.m_pImportDataList)
+ {
+ // always pipe through another pass of merge to drop unnecessary ref for linker.
+ MarkAll();
+ }
+#endif //FEATURE_METADATA_EMIT_ALL
+
+ IfFailGo(PreSave());
+
+ hr = m_pStgdb->GetSaveSize(fSave, (UINT32 *)pdwSaveSize, m_ReorderingOptions, m_pCorProfileData);
+
+ErrExit:
+ STOP_MD_PERF(GetSaveSize);
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::GetSaveSize
+
+#ifdef FEATURE_METADATA_EMIT_ALL
+
+//*****************************************************************************
+// Unmark everything in this module
+//
+// Implements public API code:IMetaDataFilter::UnmarkAll.
+//*****************************************************************************
+HRESULT RegMeta::UnmarkAll()
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+ int i;
+ int iCount;
+ TypeDefRec *pRec;
+ ULONG ulEncloser;
+ NestedClassRec *pNestedClass;
+ CustomAttributeRec *pCARec;
+ mdToken tkParent;
+ int iStart, iEnd;
+
+ LOG((LOGMD, "RegMeta::UnmarkAll\n"));
+
+ START_MD_PERF();
+ LOCKWRITE();
+
+#if 0
+ // We cannot enable this check. Because our tests are depending on this.. Sigh..
+ if (m_pFilterManager != NULL)
+ {
+ // UnmarkAll has been called before
+ IfFailGo( META_E_HAS_UNMARKALL );
+ }
+#endif // 0
+
+ // calculate the TypeRef and TypeDef mapping here
+ //
+ IfFailGo( RefToDefOptimization() );
+
+ // unmark everything in the MiniMd.
+ IfFailGo( m_pStgdb->m_MiniMd.UnmarkAll() );
+
+ // instantiate the filter manager
+ m_pFilterManager = new (nothrow) FilterManager( &(m_pStgdb->m_MiniMd) );
+ IfNullGo( m_pFilterManager );
+
+ // Mark all public typedefs.
+ iCount = m_pStgdb->m_MiniMd.getCountTypeDefs();
+
+ // Mark all of the public TypeDef. We need to skip over the <Module> typedef
+ for (i = 2; i <= iCount; i++)
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(i, &pRec));
+ if (m_OptionValue.m_LinkerOption == MDNetModule)
+ {
+ // Client is asking us to keep private type as well.
+ IfFailGo( m_pFilterManager->Mark(TokenFromRid(i, mdtTypeDef)) );
+ }
+ else if (i != 1)
+ {
+ // when client is not set to MDNetModule, global functions/fields won't be keep by default
+ //
+ if (IsTdPublic(pRec->GetFlags()))
+ {
+ IfFailGo( m_pFilterManager->Mark(TokenFromRid(i, mdtTypeDef)) );
+ }
+ else if ( IsTdNestedPublic(pRec->GetFlags()) ||
+ IsTdNestedFamily(pRec->GetFlags()) ||
+ IsTdNestedFamORAssem(pRec->GetFlags()) )
+ {
+ // This nested class would potentially be visible outside, either
+ // directly or through inheritence. If the enclosing class is
+ // marked, this nested class must be marked.
+ //
+ IfFailGo(m_pStgdb->m_MiniMd.FindNestedClassHelper(TokenFromRid(i, mdtTypeDef), &ulEncloser));
+ _ASSERTE( !InvalidRid(ulEncloser) &&
+ "Bad metadata for nested type!" );
+ IfFailGo(m_pStgdb->m_MiniMd.GetNestedClassRecord(ulEncloser, &pNestedClass));
+ tkParent = m_pStgdb->m_MiniMd.getEnclosingClassOfNestedClass(pNestedClass);
+ if ( m_pStgdb->m_MiniMd.GetFilterTable()->IsTypeDefMarked(tkParent))
+ IfFailGo( m_pFilterManager->Mark(TokenFromRid(i, mdtTypeDef)) );
+ }
+ }
+ }
+
+ if (m_OptionValue.m_LinkerOption == MDNetModule)
+ {
+ // Mark global function if NetModule. We will not keep _Delete method.
+ IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(1, &pRec));
+ iStart = m_pStgdb->m_MiniMd.getMethodListOfTypeDef(pRec);
+ IfFailGo(m_pStgdb->m_MiniMd.getEndMethodListOfTypeDef(1, (RID *)&iEnd));
+ for ( i = iStart; i < iEnd; i ++ )
+ {
+ RID rid;
+ MethodRec *pMethodRec;
+ IfFailGo(m_pStgdb->m_MiniMd.GetMethodRid(i, &rid));
+ IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(rid, &pMethodRec));
+
+ // check the name
+ if (IsMdRTSpecialName(pMethodRec->GetFlags()))
+ {
+ LPCUTF8 szName;
+ IfFailGo(m_pStgdb->m_MiniMd.getNameOfMethod(pMethodRec, &szName));
+
+ // Only mark method if not a _Deleted method
+ if (strcmp(szName, COR_DELETED_NAME_A) != 0)
+ IfFailGo( m_pFilterManager->Mark( TokenFromRid( rid, mdtMethodDef) ) );
+ }
+ else
+ {
+ //
+ if (!IsMiForwardRef(pMethodRec->GetImplFlags()) ||
+ IsMiRuntime(pMethodRec->GetImplFlags()) ||
+ IsMdPinvokeImpl(pMethodRec->GetFlags()) )
+
+ IfFailGo( m_pFilterManager->Mark( TokenFromRid( rid, mdtMethodDef) ) );
+ }
+ }
+ }
+
+ // mark the module property
+ IfFailGo( m_pFilterManager->Mark(TokenFromRid(1, mdtModule)) );
+
+ // We will also keep all of the TypeRef that has any CustomAttribute hang off it.
+ iCount = m_pStgdb->m_MiniMd.getCountCustomAttributes();
+
+ // Mark all of the TypeRef used by CA's
+ for (i = 1; i <= iCount; i++)
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.GetCustomAttributeRecord(i, &pCARec));
+ tkParent = m_pStgdb->m_MiniMd.getParentOfCustomAttribute(pCARec);
+ if (TypeFromToken(tkParent) == mdtTypeRef)
+ {
+ m_pFilterManager->Mark(tkParent);
+ }
+ }
+ErrExit:
+
+ STOP_MD_PERF(UnmarkAll);
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::UnmarkAll
+
+#endif //FEATURE_METADATA_EMIT_ALL
+
+//*****************************************************************************
+// Mark everything in this module
+//*****************************************************************************
+HRESULT RegMeta::MarkAll()
+{
+ HRESULT hr = NOERROR;
+
+ // mark everything in the MiniMd.
+ IfFailGo( m_pStgdb->m_MiniMd.MarkAll() );
+
+ // instantiate the filter manager if not instantiated
+ if (m_pFilterManager == NULL)
+ {
+ m_pFilterManager = new (nothrow) FilterManager( &(m_pStgdb->m_MiniMd) );
+ IfNullGo( m_pFilterManager );
+ }
+ErrExit:
+
+ return hr;
+} // HRESULT RegMeta::MarkAll
+
+#ifdef FEATURE_METADATA_EMIT_ALL
+
+//*****************************************************************************
+// Mark the transitive closure of a token
+//@todo GENERICS: What about GenericParam, MethodSpec?
+//
+// Implements public API code:IMetaDataFilter::MarkToken.
+//*****************************************************************************
+STDMETHODIMP RegMeta::MarkToken( // Return code.
+ mdToken tk) // [IN] token to be Marked
+{
+ HRESULT hr = NOERROR;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ // LOG((LOGMD, "RegMeta::MarkToken(0x%08x)\n", tk));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ if (m_pStgdb->m_MiniMd.GetFilterTable() == NULL || m_pFilterManager == NULL)
+ {
+ // UnmarkAll has not been called. Everything is considered marked.
+ // No need to do anything extra!
+ IfFailGo( META_E_MUST_CALL_UNMARKALL );
+ }
+
+ switch ( TypeFromToken(tk) )
+ {
+ case mdtTypeDef:
+ case mdtMethodDef:
+ case mdtFieldDef:
+ case mdtMemberRef:
+ case mdtTypeRef:
+ case mdtTypeSpec:
+ case mdtMethodSpec:
+ case mdtSignature:
+ case mdtString:
+#if _DEBUG
+ if (TypeFromToken(tk) == mdtTypeDef)
+ {
+ TypeDefRec *pType;
+ IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(tk), &pType));
+ LPCSTR szTypeDefName;
+ if (m_pStgdb->m_MiniMd.getNameOfTypeDef(pType, &szTypeDefName) == S_OK)
+ {
+ LOG((LOGMD, "MarkToken: Host is marking typetoken 0x%08x with name <%s>\n", tk, szTypeDefName));
+ }
+ }
+ else
+ if (TypeFromToken(tk) == mdtMethodDef)
+ {
+ MethodRec *pMeth;
+ IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(tk), &pMeth));
+ LPCSTR szMethodName;
+ if (m_pStgdb->m_MiniMd.getNameOfMethod(pMeth, &szMethodName) == S_OK)
+ {
+ LOG((LOGMD, "MarkToken: Host is marking methodtoken 0x%08x with name <%s>\n", tk, szMethodName));
+ }
+ }
+ else
+ if (TypeFromToken(tk) == mdtFieldDef)
+ {
+ FieldRec *pField;
+ IfFailGo(m_pStgdb->m_MiniMd.GetFieldRecord(RidFromToken(tk), &pField));
+ LPCSTR szFieldName;
+ if (m_pStgdb->m_MiniMd.getNameOfField(pField, &szFieldName) == S_OK)
+ {
+ LOG((LOGMD, "MarkToken: Host is marking field token 0x%08x with name <%s>\n", tk, szFieldName));
+ }
+ }
+ else
+ {
+ LOG((LOGMD, "MarkToken: Host is marking token 0x%08x\n", tk));
+ }
+#endif // _DEBUG
+ if (!IsValidToken(tk))
+ IfFailGo( E_INVALIDARG );
+
+ IfFailGo( m_pFilterManager->Mark(tk) );
+ break;
+
+ case mdtBaseType:
+ // no need to mark base type
+ goto ErrExit;
+
+ default:
+ _ASSERTE(!"Bad token type!");
+ hr = E_INVALIDARG;
+ break;
+ }
+ErrExit:
+
+ STOP_MD_PERF(MarkToken);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::MarkToken
+
+//*****************************************************************************
+// Unmark everything in this module
+//@todo GENERICS: What about GenericParam, MethodSpec?
+//
+// Implements public API code:IMetaDataFilter::IsTokenMarked.
+//*****************************************************************************
+HRESULT RegMeta::IsTokenMarked(
+ mdToken tk, // [IN] Token to check if marked or not
+ BOOL *pIsMarked) // [OUT] true if token is marked
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ FilterTable *pFilter = NULL;
+
+ LOG((LOGMD, "RegMeta::IsTokenMarked(0x%08x)\n", tk));
+ START_MD_PERF();
+ LOCKREAD();
+
+ pFilter = m_pStgdb->m_MiniMd.GetFilterTable();
+ IfNullGo( pFilter );
+
+ if (!IsValidToken(tk))
+ IfFailGo( E_INVALIDARG );
+
+ switch ( TypeFromToken(tk) )
+ {
+ case mdtTypeRef:
+ *pIsMarked = pFilter->IsTypeRefMarked(tk);
+ break;
+ case mdtTypeDef:
+ *pIsMarked = pFilter->IsTypeDefMarked(tk);
+ break;
+ case mdtFieldDef:
+ *pIsMarked = pFilter->IsFieldMarked(tk);
+ break;
+ case mdtMethodDef:
+ *pIsMarked = pFilter->IsMethodMarked(tk);
+ break;
+ case mdtParamDef:
+ *pIsMarked = pFilter->IsParamMarked(tk);
+ break;
+ case mdtMemberRef:
+ *pIsMarked = pFilter->IsMemberRefMarked(tk);
+ break;
+ case mdtCustomAttribute:
+ *pIsMarked = pFilter->IsCustomAttributeMarked(tk);
+ break;
+ case mdtPermission:
+ *pIsMarked = pFilter->IsDeclSecurityMarked(tk);
+ break;
+ case mdtSignature:
+ *pIsMarked = pFilter->IsSignatureMarked(tk);
+ break;
+ case mdtEvent:
+ *pIsMarked = pFilter->IsEventMarked(tk);
+ break;
+ case mdtProperty:
+ *pIsMarked = pFilter->IsPropertyMarked(tk);
+ break;
+ case mdtModuleRef:
+ *pIsMarked = pFilter->IsModuleRefMarked(tk);
+ break;
+ case mdtTypeSpec:
+ *pIsMarked = pFilter->IsTypeSpecMarked(tk);
+ break;
+ case mdtInterfaceImpl:
+ *pIsMarked = pFilter->IsInterfaceImplMarked(tk);
+ break;
+ case mdtString:
+ default:
+ _ASSERTE(!"Bad token type!");
+ hr = E_INVALIDARG;
+ break;
+ }
+ErrExit:
+
+ STOP_MD_PERF(IsTokenMarked);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::IsTokenMarked
+
+#endif //FEATURE_METADATA_EMIT_ALL
+
+//*****************************************************************************
+// Create and populate a new TypeDef record.
+//*****************************************************************************
+STDMETHODIMP RegMeta::DefineTypeDef( // S_OK or error.
+ LPCWSTR szTypeDef, // [IN] Name of TypeDef
+ DWORD dwTypeDefFlags, // [IN] CustomAttribute flags
+ mdToken tkExtends, // [IN] extends this TypeDef or typeref
+ mdToken rtkImplements[], // [IN] Implements interfaces
+ mdTypeDef *ptd) // [OUT] Put TypeDef token here
+{
+ HRESULT hr = S_OK; // A result.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "RegMeta::DefineTypeDef(%S, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ MDSTR(szTypeDef), dwTypeDefFlags, tkExtends,
+ rtkImplements, ptd));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ _ASSERTE(!IsTdNested(dwTypeDefFlags));
+
+ IfFailGo(_DefineTypeDef(szTypeDef, dwTypeDefFlags,
+ tkExtends, rtkImplements, mdTokenNil, ptd));
+ErrExit:
+ STOP_MD_PERF(DefineTypeDef);
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::DefineTypeDef()
+
+
+//*****************************************************************************
+// Implements public API code:IMetaDataFilter::SetHandler.
+//*****************************************************************************
+STDMETHODIMP RegMeta::SetHandler( // S_OK.
+ IUnknown *pUnk) // [IN] The new error handler.
+{
+ HRESULT hr = S_OK; // A result.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ IMapToken *pIMap = NULL;
+
+ LOG((LOGMD, "RegMeta::SetHandler(0x%08x)\n", pUnk));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ m_pHandler = pUnk;
+
+ // Ignore the error return by SetHandler
+ IfFailGo(m_pStgdb->m_MiniMd.SetHandler(pUnk));
+
+ // Figure out up front if remap is supported.
+ if (pUnk)
+ pUnk->QueryInterface(IID_IMapToken, (PVOID *) &pIMap);
+ m_bRemap = (pIMap != 0);
+ if (pIMap)
+ pIMap->Release();
+
+ErrExit:
+
+ STOP_MD_PERF(SetHandler);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::SetHandler()
+
+//*******************************************************************************
+// Internal helper functions.
+//*******************************************************************************
+
+//*******************************************************************************
+// Perform optimizations of the metadata prior to saving.
+//*******************************************************************************
+HRESULT RegMeta::PreSave() // Return code.
+{
+ HRESULT hr = S_OK; // A result.
+ CMiniMdRW *pMiniMd; // The MiniMd with the data.
+ unsigned bRemapOld = m_bRemap;
+ MergeTokenManager *ptkMgr = NULL;
+
+ // For convenience.
+ pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ // If the code has already been optimized there is nothing to do.
+ if (m_bSaveOptimized)
+ goto ErrExit;
+
+#ifdef FEATURE_METADATA_EMIT_ALL
+ if (m_newMerger.m_pImportDataList != NULL)
+ {
+ // This is the linker scenario. We we have IMap for each scope. We will create an instance of our own mapper
+ // who knows how to send notification back to host!
+
+ // cache the host provided handler to the end our MergeTokenManager
+
+ ptkMgr = new (nothrow) MergeTokenManager(m_newMerger.m_pImportDataList->m_pMDTokenMap, m_pHandler);
+ IfNullGo(ptkMgr);
+ hr = m_pStgdb->m_MiniMd.SetHandler(ptkMgr);
+ _ASSERTE(SUCCEEDED(hr));
+ }
+#endif //FEATURE_METADATA_EMIT_ALL
+
+ IfFailGo(RefToDefOptimization());
+
+ // we need to update MethodImpl table here with ref to def result
+ if (pMiniMd->GetMemberRefToMemberDefMap() != NULL)
+ {
+ MethodImplRec *pMethodImplRec;
+ mdToken tkMethodBody;
+ mdToken tkMethodDecl;
+ mdToken newTK;
+ ULONG cMethodImplRecs; // Count of MemberRefs.
+ ULONG iMI;
+
+ cMethodImplRecs = pMiniMd->getCountMethodImpls();
+ // Enum through all member ref's looking for ref's to internal things.
+ for (iMI = 1; iMI <= cMethodImplRecs; iMI++)
+ { // Get a MethodImpl.
+ IfFailGo(pMiniMd->GetMethodImplRecord(iMI, &pMethodImplRec));
+ tkMethodBody = pMiniMd->getMethodBodyOfMethodImpl(pMethodImplRec);
+ if (TypeFromToken(tkMethodBody) == mdtMemberRef)
+ {
+ // did it get remapped to a def
+ newTK = *(pMiniMd->GetMemberRefToMemberDefMap()->Get(RidFromToken(tkMethodBody)));
+ if (!IsNilToken(newTK))
+ {
+ // yes... fix up the value...
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_MethodImpl,
+ MethodImplRec::COL_MethodBody,
+ pMethodImplRec,
+ newTK));
+ }
+ }
+ // do the same thing for MethodDecl
+ tkMethodDecl = pMiniMd->getMethodDeclarationOfMethodImpl(pMethodImplRec);
+ if (TypeFromToken(tkMethodDecl) == mdtMemberRef)
+ {
+ // did it get remapped to a def
+ newTK = *(pMiniMd->GetMemberRefToMemberDefMap()->Get(RidFromToken(tkMethodDecl)));
+ if (!IsNilToken(newTK))
+ {
+ // yes... fix up the value...
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_MethodImpl,
+ MethodImplRec::COL_MethodDeclaration,
+ pMethodImplRec,
+ newTK));
+ }
+ }
+ }
+ }
+
+#ifdef FEATURE_METADATA_EMIT_ALL
+ IfFailGo(ProcessFilter());
+
+ if (m_newMerger.m_pImportDataList != NULL)
+ {
+ // Allocate a token mapper object that will be used for phase 1 if there is not Handler but
+ // linker has provided the IMapToken
+ //
+ m_bRemap = true;
+ }
+#endif //FEATURE_METADATA_EMIT_ALL
+
+ // reget the minimd because it can be swapped in the call of ProcessFilter
+ pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ // Don't repeat this process again.
+ m_bSaveOptimized = true;
+
+ // call get save size to trigger the PreSaveXXX on MetaModelRW class.
+ IfFailGo(m_pStgdb->m_MiniMd.PreSave(m_ReorderingOptions, m_pCorProfileData));
+
+ErrExit:
+ if (ptkMgr != NULL)
+ {
+ // recovery the initial state
+ hr = m_pStgdb->m_MiniMd.SetHandler(NULL);
+ ptkMgr->Release();
+ }
+
+ m_bRemap = bRemapOld;
+
+ return hr;
+} // RegMeta::PreSave
+
+//*******************************************************************************
+// Perform optimizations of ref to def
+//*******************************************************************************
+HRESULT RegMeta::RefToDefOptimization()
+{
+ mdToken mfdef; // Method or Field Def.
+ LPCSTR szName; // MemberRef or TypeRef name.
+ const COR_SIGNATURE *pvSig; // Signature of the MemberRef.
+ ULONG cbSig; // Size of the signature blob.
+ HRESULT hr = S_OK; // A result.
+ ULONG iMR; // For iterating MemberRefs.
+ CMiniMdRW *pMiniMd; // The MiniMd with the data.
+ ULONG cMemberRefRecs; // Count of MemberRefs.
+ MemberRefRec *pMemberRefRec; // A MemberRefRec.
+
+
+
+ START_MD_PERF();
+
+ // the Ref to Def map is still up-to-date
+ if (IsMemberDefDirty() == false && IsTypeDefDirty() == false && m_hasOptimizedRefToDef == true)
+ goto ErrExit;
+
+ pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ // The basic algorithm here is:
+ //
+ // calculate all of the TypeRef to TypeDef map and store it at TypeRefToTypeDefMap
+ // for each MemberRef mr
+ // {
+ // get the parent of mr
+ // if (parent of mr is a TypeRef and has been mapped to a TypeDef)
+ // {
+ // Remap MemberRef to MemberDef
+ // }
+ // }
+ //
+ // There are several places where errors are eaten, since this whole thing is
+ // an optimization step and not doing it would still be valid.
+ //
+
+ // Ensure the size
+ // initialize the token remap manager. This class will track all of the Refs to Defs map and also
+ // token movements due to removing pointer tables or sorting.
+ //
+ if ( pMiniMd->GetTokenRemapManager() == NULL)
+ {
+
+ IfFailGo( pMiniMd->InitTokenRemapManager() );
+ }
+ else
+ {
+ IfFailGo( pMiniMd->GetTokenRemapManager()->ClearAndEnsureCapacity(pMiniMd->getCountTypeRefs(), pMiniMd->getCountMemberRefs()));
+ }
+
+ // If this is the first time or more TypeDef has been introduced, recalculate the TypeRef to TypeDef map
+ if (IsTypeDefDirty() || m_hasOptimizedRefToDef == false)
+ {
+ IfFailGo( pMiniMd->CalculateTypeRefToTypeDefMap() );
+ }
+
+ // If this is the first time or more memberdefs has been introduced, recalculate the TypeRef to TypeDef map
+ if (IsMemberDefDirty() || m_hasOptimizedRefToDef == false)
+ {
+ mdToken tkParent;
+ cMemberRefRecs = pMiniMd->getCountMemberRefs();
+
+ // Enum through all member ref's looking for ref's to internal things.
+ for (iMR = 1; iMR<=cMemberRefRecs; iMR++)
+ { // Get a MemberRef.
+ IfFailGo(pMiniMd->GetMemberRefRecord(iMR, &pMemberRefRec));
+
+ // If not member of the TypeRef, skip it.
+ tkParent = pMiniMd->getClassOfMemberRef(pMemberRefRec);
+
+ if ( TypeFromToken(tkParent) == mdtMethodDef )
+ {
+ // always track the map even though it is already in the original scope
+ *(pMiniMd->GetMemberRefToMemberDefMap()->Get(iMR)) = tkParent;
+ continue;
+ }
+
+ if ( TypeFromToken(tkParent) != mdtTypeRef && TypeFromToken(tkParent) != mdtTypeDef )
+ {
+ // this has been either optimized to mdtMethodDef, mdtFieldDef or referring to
+ // ModuleRef
+ continue;
+ }
+
+ // In the case of global function, we have tkParent as m_tdModule.
+ // We will always do the optmization.
+ if (TypeFromToken(tkParent) == mdtTypeRef)
+ {
+ // If we're preserving local typerefs, skip this token
+ if (PreserveLocalRefs(MDPreserveLocalTypeRef))
+ {
+ continue;
+ }
+
+ // The parent is a TypeRef. We need to check to see if this TypeRef is optimized to a TypeDef
+ tkParent = *(pMiniMd->GetTypeRefToTypeDefMap()->Get(RidFromToken(tkParent)) );
+ // tkParent = pMapTypeRefToTypeDef[RidFromToken(tkParent)];
+ if ( RidFromToken(tkParent) == 0)
+ {
+ continue;
+ }
+ }
+
+ // If we're preserving local memberrefs, skip this token
+ if (PreserveLocalRefs(MDPreserveLocalMemberRef))
+ {
+ continue;
+ }
+
+ // Get the name and signature of this mr.
+ IfFailGo(pMiniMd->getNameOfMemberRef(pMemberRefRec, &szName));
+ IfFailGo(pMiniMd->getSignatureOfMemberRef(pMemberRefRec, &pvSig, &cbSig));
+
+ // Look for a member with the same def. Might not be found if it is
+ // inherited from a base class.
+ //<TODO>@future: this should support inheritence checking.
+ // Look for a member with the same name and signature.</TODO>
+ hr = ImportHelper::FindMember(pMiniMd, tkParent, szName, pvSig, cbSig, &mfdef);
+ if (hr != S_OK)
+ {
+ #if _TRACE_REMAPS
+ // Log the failure.
+ LOG((LF_METADATA, LL_INFO10, "Member %S//%S.%S not found\n", szNamespace, szTDName, rcMRName));
+ #endif
+ continue;
+ }
+
+ // We will only record this if mfdef is a methoddef. We don't support
+ // parent of MemberRef as fielddef. As if we can optimize MemberRef to FieldDef,
+ // we can remove this row.
+ //
+ if ( (TypeFromToken(mfdef) == mdtMethodDef) &&
+ (m_bRemap || tkParent == m_tdModule ) )
+ {
+ // Always change the parent if it is the global function.
+ // Or change the parent if we have a remap that we can send notification.
+ //
+ IfFailGo(pMiniMd->PutToken(TBL_MemberRef, MemberRefRec::COL_Class, pMemberRefRec, mfdef));
+ }
+
+ // We will always track the changes. In MiniMd::PreSaveFull, we will use this map to send
+ // notification to our host if there is any IMapToken provided.
+ //
+ *(pMiniMd->GetMemberRefToMemberDefMap()->Get(iMR)) = mfdef;
+
+ } // EnumMemberRefs
+ }
+
+ // Reset return code from likely search failures.
+ hr = S_OK;
+
+ SetMemberDefDirty(false);
+ SetTypeDefDirty(false);
+ m_hasOptimizedRefToDef = true;
+ErrExit:
+ STOP_MD_PERF(RefToDefOptimization);
+
+ return hr;
+} // RegMeta::RefToDefOptimization
+
+#ifdef FEATURE_METADATA_EMIT_ALL
+
+//*****************************************************************************
+// Process filter
+//*****************************************************************************
+HRESULT RegMeta::ProcessFilter()
+{
+ HRESULT hr = S_OK;
+
+ CMiniMdRW *pMiniMd; // The MiniMd with the data.
+
+ START_MD_PERF();
+
+ // For convenience.
+ pMiniMd = &(m_pStgdb->m_MiniMd);
+ IfNullGo( pMiniMd->GetFilterTable() );
+ if ( pMiniMd->GetFilterTable()->Count() == 0 )
+ {
+ // there is no filter
+ goto ErrExit;
+ }
+ hr = ProcessFilterWorker();
+
+ErrExit:
+ STOP_MD_PERF(ProcessFilter);
+
+ return hr;
+} // RegMeta::ProcessFilter
+
+#endif //FEATURE_METADATA_EMIT_ALL
+
+//*****************************************************************************
+// Define a TypeRef given the fully qualified name.
+//*****************************************************************************
+HRESULT RegMeta::_DefineTypeRef(
+ mdToken tkResolutionScope, // [IN] ModuleRef or AssemblyRef.
+ const void *szName, // [IN] Name of the TypeRef.
+ BOOL isUnicode, // [IN] Specifies whether the URL is unicode.
+ mdTypeRef *ptk, // [OUT] Put mdTypeRef here.
+ eCheckDups eCheck) // [IN] Specifies whether to check for duplicates.
+{
+ HRESULT hr = S_OK;
+ LPUTF8 szUTF8FullQualName;
+ CQuickBytes qbNamespace;
+ CQuickBytes qbName;
+ int bSuccess;
+ ULONG ulStringLen;
+
+
+
+
+ _ASSERTE(ptk && szName);
+ _ASSERTE (TypeFromToken(tkResolutionScope) == mdtModule ||
+ TypeFromToken(tkResolutionScope) == mdtModuleRef ||
+ TypeFromToken(tkResolutionScope) == mdtAssemblyRef ||
+ TypeFromToken(tkResolutionScope) == mdtTypeRef ||
+ tkResolutionScope == mdTokenNil);
+
+ if (isUnicode)
+ {
+ UTF8STR((LPCWSTR)szName, szUTF8FullQualName);
+ }
+ else
+ {
+ szUTF8FullQualName = (LPUTF8)szName;
+ }
+ PREFIX_ASSUME(szUTF8FullQualName != NULL);
+
+ ulStringLen = (ULONG)(strlen(szUTF8FullQualName) + 1);
+ IfFailGo(qbNamespace.ReSizeNoThrow(ulStringLen));
+ IfFailGo(qbName.ReSizeNoThrow(ulStringLen));
+ bSuccess = ns::SplitPath(szUTF8FullQualName,
+ (LPUTF8)qbNamespace.Ptr(),
+ ulStringLen,
+ (LPUTF8)qbName.Ptr(),
+ ulStringLen);
+ _ASSERTE(bSuccess);
+
+ // Search for existing TypeRef record.
+ if (eCheck==eCheckYes || (eCheck==eCheckDefault && CheckDups(MDDupTypeRef)))
+ {
+ hr = ImportHelper::FindTypeRefByName(&(m_pStgdb->m_MiniMd), tkResolutionScope,
+ (LPCUTF8)qbNamespace.Ptr(),
+ (LPCUTF8)qbName.Ptr(), ptk);
+ if (SUCCEEDED(hr))
+ {
+ if (IsENCOn())
+ {
+ hr = S_OK;
+ goto NormalExit;
+ }
+ else
+ {
+ hr = META_S_DUPLICATE;
+ goto NormalExit;
+ }
+ }
+ else if (hr != CLDB_E_RECORD_NOTFOUND)
+ IfFailGo(hr);
+ }
+
+ // Create TypeRef record.
+ TypeRefRec *pRecord;
+ RID iRecord;
+
+ IfFailGo(m_pStgdb->m_MiniMd.AddTypeRefRecord(&pRecord, &iRecord));
+
+ // record the more defs are introduced.
+ SetTypeDefDirty(true);
+
+ // Give token back to caller.
+ *ptk = TokenFromRid(iRecord, mdtTypeRef);
+
+ // Set the fields of the TypeRef record.
+ IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_TypeRef, TypeRefRec::COL_Namespace,
+ pRecord, (LPUTF8)qbNamespace.Ptr()));
+
+ IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_TypeRef, TypeRefRec::COL_Name,
+ pRecord, (LPUTF8)qbName.Ptr()));
+
+ if (!IsNilToken(tkResolutionScope))
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_TypeRef, TypeRefRec::COL_ResolutionScope,
+ pRecord, tkResolutionScope));
+ IfFailGo(UpdateENCLog(*ptk));
+
+ // Hash the name.
+ IfFailGo(m_pStgdb->m_MiniMd.AddNamedItemToHash(TBL_TypeRef, *ptk, (LPUTF8)qbName.Ptr(), 0));
+
+ErrExit:
+ ;
+NormalExit:
+
+ return hr;
+} // HRESULT RegMeta::_DefineTypeRef()
+
+//*******************************************************************************
+// Define MethodSemantics
+//*******************************************************************************
+HRESULT RegMeta::_DefineMethodSemantics( // S_OK or error.
+ USHORT usAttr, // [IN] CorMethodSemanticsAttr.
+ mdMethodDef md, // [IN] Method.
+ mdToken tkAssoc, // [IN] Association.
+ BOOL bClear) // [IN] Specifies whether to delete the exisiting entries.
+{
+ HRESULT hr = S_OK;
+ MethodSemanticsRec *pRecord = 0;
+ MethodSemanticsRec *pRecord1; // Use this to recycle a MethodSemantics record.
+ RID iRecord;
+ HENUMInternal hEnum;
+
+
+
+ _ASSERTE(TypeFromToken(md) == mdtMethodDef || IsNilToken(md));
+ _ASSERTE(RidFromToken(tkAssoc));
+ memset(&hEnum, 0, sizeof(HENUMInternal));
+
+ // Clear all matching records by setting association to a Nil token.
+ if (bClear)
+ {
+ RID i;
+
+ IfFailGo( m_pStgdb->m_MiniMd.FindMethodSemanticsHelper(tkAssoc, &hEnum) );
+ while (HENUMInternal::EnumNext(&hEnum, (mdToken *)&i))
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.GetMethodSemanticsRecord(i, &pRecord1));
+ if (usAttr == pRecord1->GetSemantic())
+ {
+ pRecord = pRecord1;
+ iRecord = i;
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_MethodSemantics,
+ MethodSemanticsRec::COL_Association, pRecord, mdPropertyNil));
+ // In Whidbey, we should create ENC log record here.
+ }
+ }
+ }
+ // If setting (not just clearing) the association, do that now.
+ if (!IsNilToken(md))
+ {
+ // Create a new record required
+ if (pRecord == NULL)
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.AddMethodSemanticsRecord(&pRecord, &iRecord));
+ }
+
+ // Save the data.
+ pRecord->SetSemantic(usAttr);
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_MethodSemantics,
+ MethodSemanticsRec::COL_Method, pRecord, md));
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_MethodSemantics,
+ MethodSemanticsRec::COL_Association, pRecord, tkAssoc));
+
+ // regardless if we reuse the record or create the record, add the MethodSemantics to the hash
+ IfFailGo( m_pStgdb->m_MiniMd.AddMethodSemanticsToHash(iRecord) );
+
+ // Create log record for non-token table.
+ IfFailGo(UpdateENCLog2(TBL_MethodSemantics, iRecord));
+ }
+
+ErrExit:
+ HENUMInternal::ClearEnum(&hEnum);
+
+ return hr;
+} // HRESULT RegMeta::_DefineMethodSemantics()
+
+//*******************************************************************************
+// Turn the specified internal flags on.
+//*******************************************************************************
+HRESULT RegMeta::_TurnInternalFlagsOn( // S_OK or error.
+ mdToken tkObj, // [IN] Target object whose internal flags are targetted.
+ DWORD flags) // [IN] Specifies flags to be turned on.
+{
+ HRESULT hr;
+ MethodRec *pMethodRec;
+ FieldRec *pFieldRec;
+ TypeDefRec *pTypeDefRec;
+
+ switch (TypeFromToken(tkObj))
+ {
+ case mdtMethodDef:
+ IfFailRet(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(tkObj), &pMethodRec));
+ pMethodRec->AddFlags(flags);
+ break;
+ case mdtFieldDef:
+ IfFailRet(m_pStgdb->m_MiniMd.GetFieldRecord(RidFromToken(tkObj), &pFieldRec));
+ pFieldRec->AddFlags(flags);
+ break;
+ case mdtTypeDef:
+ IfFailRet(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(tkObj), &pTypeDefRec));
+ pTypeDefRec->AddFlags(flags);
+ break;
+ default:
+ _ASSERTE(!"Not supported token type!");
+ return E_INVALIDARG;
+ }
+ return S_OK;
+} // RegMeta::_TurnInternalFlagsOn
+
+//*****************************************************************************
+// Helper: Set the properties on the given TypeDef token.
+//*****************************************************************************
+HRESULT RegMeta::_SetTypeDefProps( // S_OK or error.
+ mdTypeDef td, // [IN] The TypeDef.
+ DWORD dwTypeDefFlags, // [IN] TypeDef flags.
+ mdToken tkExtends, // [IN] Base TypeDef or TypeRef.
+ mdToken rtkImplements[]) // [IN] Implemented interfaces.
+{
+ HRESULT hr = S_OK; // A result.
+ BOOL bClear = IsENCOn() || IsCallerExternal(); // Specifies whether to clear the InterfaceImpl records.
+ TypeDefRec *pRecord; // New TypeDef record.
+
+ _ASSERTE(TypeFromToken(td) == mdtTypeDef);
+ _ASSERTE(TypeFromToken(tkExtends) == mdtTypeDef || TypeFromToken(tkExtends) == mdtTypeRef || TypeFromToken(tkExtends) == mdtTypeSpec ||
+ IsNilToken(tkExtends) || tkExtends == ULONG_MAX);
+
+ // Get the record.
+ IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(td), &pRecord));
+
+ if (dwTypeDefFlags != ULONG_MAX)
+ {
+ // No one should try to set the reserved flags explicitly.
+ _ASSERTE((dwTypeDefFlags & (tdReservedMask&~tdRTSpecialName)) == 0);
+ // Clear the reserved flags from the flags passed in.
+ dwTypeDefFlags &= (~tdReservedMask);
+ // Preserve the reserved flags stored.
+ dwTypeDefFlags |= (pRecord->GetFlags() & tdReservedMask);
+ // Set the flags.
+ pRecord->SetFlags(dwTypeDefFlags);
+ }
+ if (tkExtends != ULONG_MAX)
+ {
+ if (IsNilToken(tkExtends))
+ tkExtends = mdTypeDefNil;
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_TypeDef, TypeDefRec::COL_Extends,
+ pRecord, tkExtends));
+ }
+
+ // Implemented interfaces.
+ if (rtkImplements)
+ IfFailGo(_SetImplements(rtkImplements, td, bClear));
+
+ IfFailGo(UpdateENCLog(td));
+ErrExit:
+ return hr;
+} // HRESULT RegMeta::_SetTypeDefProps()
+
+//******************************************************************************
+// Creates and sets a row in the InterfaceImpl table. Optionally clear
+// pre-existing records for the owning class.
+//******************************************************************************
+HRESULT RegMeta::_SetImplements( // S_OK or error.
+ mdToken rTk[], // Array of TypeRef or TypeDef or TypeSpec tokens for implemented interfaces.
+ mdTypeDef td, // Implementing TypeDef.
+ BOOL bClear) // Specifies whether to clear the existing records.
+{
+ HRESULT hr = S_OK;
+ ULONG i = 0;
+ ULONG j;
+ InterfaceImplRec *pInterfaceImpl;
+ RID iInterfaceImpl;
+ RID ridStart;
+ RID ridEnd;
+ CQuickBytes cqbTk;
+ const mdToken *pTk;
+ bool fIsTableVirtualSortValid;
+
+
+ _ASSERTE(TypeFromToken(td) == mdtTypeDef && rTk);
+ _ASSERTE(!m_bSaveOptimized && "Cannot change records after PreSave() and before Save().");
+
+ // Clear all exising InterfaceImpl records by setting the parent to Nil.
+ if (bClear)
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.GetInterfaceImplsForTypeDef(
+ RidFromToken(td), &ridStart, &ridEnd));
+ for (j = ridStart; j < ridEnd; j++)
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.GetInterfaceImplRecord(
+ m_pStgdb->m_MiniMd.GetInterfaceImplRid(j),
+ &pInterfaceImpl));
+ _ASSERTE (td == m_pStgdb->m_MiniMd.getClassOfInterfaceImpl(pInterfaceImpl));
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_InterfaceImpl, InterfaceImplRec::COL_Class,
+ pInterfaceImpl, mdTypeDefNil));
+ }
+ }
+
+ // Eliminate duplicates from the array passed in.
+ if (CheckDups(MDDupInterfaceImpl))
+ {
+ IfFailGo(_InterfaceImplDupProc(rTk, td, &cqbTk));
+ pTk = (mdToken *)cqbTk.Ptr();
+ }
+ else
+ pTk = rTk;
+
+ // Get the state of InterfaceImpl table's VirtualSort
+ fIsTableVirtualSortValid = m_pStgdb->m_MiniMd.IsTableVirtualSorted(TBL_InterfaceImpl);
+ // Loop for each implemented interface.
+ while (!IsNilToken(pTk[i]))
+ {
+ _ASSERTE(TypeFromToken(pTk[i]) == mdtTypeRef || TypeFromToken(pTk[i]) == mdtTypeDef
+ || TypeFromToken(pTk[i]) == mdtTypeSpec);
+
+ // Create the interface implementation record.
+ IfFailGo(m_pStgdb->m_MiniMd.AddInterfaceImplRecord(&pInterfaceImpl, &iInterfaceImpl));
+
+ // Set data.
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_InterfaceImpl, InterfaceImplRec::COL_Class,
+ pInterfaceImpl, td));
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_InterfaceImpl, InterfaceImplRec::COL_Interface,
+ pInterfaceImpl, pTk[i]));
+ // Had the table valid VirtualSort?
+ if (fIsTableVirtualSortValid)
+ { // Validate table's VistualSort after adding 1 record and store its
+ // new validation state
+ IfFailGo(m_pStgdb->m_MiniMd.ValidateVirtualSortAfterAddRecord(
+ TBL_InterfaceImpl,
+ &fIsTableVirtualSortValid));
+ }
+
+ i++;
+
+ IfFailGo(UpdateENCLog(TokenFromRid(mdtInterfaceImpl, iInterfaceImpl)));
+ }
+ErrExit:
+
+ return hr;
+} // HRESULT RegMeta::_SetImplements()
+
+//******************************************************************************
+// This routine eliminates duplicates from the given list of InterfaceImpl tokens
+// to be defined. It checks for duplicates against the database only if the
+// TypeDef for which these tokens are being defined is not a new one.
+//******************************************************************************
+HRESULT RegMeta::_InterfaceImplDupProc( // S_OK or error.
+ mdToken rTk[], // Array of TypeRef or TypeDef or TypeSpec tokens for implemented interfaces.
+ mdTypeDef td, // Implementing TypeDef.
+ CQuickBytes *pcqbTk) // Quick Byte object for placing the array of unique tokens.
+{
+ HRESULT hr = S_OK;
+ ULONG i = 0;
+ ULONG iUniqCount = 0;
+ BOOL bDupFound;
+
+ while (!IsNilToken(rTk[i]))
+ {
+ _ASSERTE(TypeFromToken(rTk[i]) == mdtTypeRef || TypeFromToken(rTk[i]) == mdtTypeDef
+ || TypeFromToken(rTk[i]) == mdtTypeSpec);
+ bDupFound = false;
+
+ // Eliminate duplicates from the input list of tokens by looking within the list.
+ for (ULONG j = 0; j < iUniqCount; j++)
+ {
+ if (rTk[i] == ((mdToken *)pcqbTk->Ptr())[j])
+ {
+ bDupFound = true;
+ break;
+ }
+ }
+
+ // If no duplicate is found record it in the list.
+ if (!bDupFound)
+ {
+ IfFailGo(pcqbTk->ReSizeNoThrow((iUniqCount+1) * sizeof(mdToken)));
+ ((mdToken *)pcqbTk->Ptr())[iUniqCount] = rTk[i];
+ iUniqCount++;
+ }
+ i++;
+ }
+
+ // Create a Nil token to signify the end of list.
+ IfFailGo(pcqbTk->ReSizeNoThrow((iUniqCount+1) * sizeof(mdToken)));
+ ((mdToken *)pcqbTk->Ptr())[iUniqCount] = mdTokenNil;
+ErrExit:
+
+ return hr;
+} // HRESULT RegMeta::_InterfaceImplDupProc()
+
+//*******************************************************************************
+// helper to define event
+//*******************************************************************************
+HRESULT RegMeta::_DefineEvent( // Return hresult.
+ mdTypeDef td, // [IN] the class/interface on which the event is being defined
+ LPCWSTR szEvent, // [IN] Name of the event
+ DWORD dwEventFlags, // [IN] CorEventAttr
+ mdToken tkEventType, // [IN] a reference (mdTypeRef or mdTypeRef) to the Event class
+ mdEvent *pmdEvent) // [OUT] output event token
+{
+ HRESULT hr = S_OK;
+ EventRec *pEventRec = NULL;
+ RID iEventRec;
+ EventMapRec *pEventMap;
+ RID iEventMap;
+ mdEvent mdEv;
+ LPUTF8 szUTF8Event;
+ UTF8STR(szEvent, szUTF8Event);
+ PREFIX_ASSUME(szUTF8Event != NULL);
+
+
+
+ _ASSERTE(TypeFromToken(td) == mdtTypeDef && td != mdTypeDefNil);
+ _ASSERTE(IsNilToken(tkEventType) || TypeFromToken(tkEventType) == mdtTypeDef ||
+ TypeFromToken(tkEventType) == mdtTypeRef || TypeFromToken(tkEventType) == mdtTypeSpec);
+ _ASSERTE(szEvent && pmdEvent);
+
+ if (CheckDups(MDDupEvent))
+ {
+ hr = ImportHelper::FindEvent(&(m_pStgdb->m_MiniMd), td, szUTF8Event, pmdEvent);
+ if (SUCCEEDED(hr))
+ {
+ if (IsENCOn())
+ IfFailGo(m_pStgdb->m_MiniMd.GetEventRecord(RidFromToken(*pmdEvent), &pEventRec));
+ else
+ {
+ hr = META_S_DUPLICATE;
+ goto ErrExit;
+ }
+ }
+ else if (hr != CLDB_E_RECORD_NOTFOUND)
+ IfFailGo(hr);
+ }
+
+ if (! pEventRec)
+ {
+ // Create a new map if one doesn't exist already, else retrieve the existing one.
+ // The event map must be created before the EventRecord, the new event map will
+ // be pointing past the first event record.
+ IfFailGo(m_pStgdb->m_MiniMd.FindEventMapFor(RidFromToken(td), &iEventMap));
+ if (InvalidRid(iEventMap))
+ {
+ // Create new record.
+ IfFailGo(m_pStgdb->m_MiniMd.AddEventMapRecord(&pEventMap, &iEventMap));
+ // Set parent.
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_EventMap,
+ EventMapRec::COL_Parent, pEventMap, td));
+ IfFailGo(UpdateENCLog2(TBL_EventMap, iEventMap));
+ }
+ else
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.GetEventMapRecord(iEventMap, &pEventMap));
+ }
+
+ // Create a new event record.
+ IfFailGo(m_pStgdb->m_MiniMd.AddEventRecord(&pEventRec, &iEventRec));
+
+ // Set output parameter.
+ *pmdEvent = TokenFromRid(iEventRec, mdtEvent);
+
+ // Add Event to EventMap.
+ IfFailGo(m_pStgdb->m_MiniMd.AddEventToEventMap(RidFromToken(iEventMap), iEventRec));
+
+ IfFailGo(UpdateENCLog2(TBL_EventMap, iEventMap, CMiniMdRW::eDeltaEventCreate));
+ }
+
+ mdEv = *pmdEvent;
+
+ // Set data
+ IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_Event, EventRec::COL_Name, pEventRec, szUTF8Event));
+ IfFailGo(_SetEventProps1(*pmdEvent, dwEventFlags, tkEventType));
+
+ // Add the <Event token, typedef token> to the lookup table
+ if (m_pStgdb->m_MiniMd.HasIndirectTable(TBL_Event))
+ IfFailGo( m_pStgdb->m_MiniMd.AddEventToLookUpTable(*pmdEvent, td) );
+
+ IfFailGo(UpdateENCLog(*pmdEvent));
+
+ErrExit:
+
+ return hr;
+} // HRESULT RegMeta::_DefineEvent()
+
+
+//******************************************************************************
+// Set the specified properties on the Event Token.
+//******************************************************************************
+HRESULT RegMeta::_SetEventProps1( // Return hresult.
+ mdEvent ev, // [IN] Event token.
+ DWORD dwEventFlags, // [IN] Event flags.
+ mdToken tkEventType) // [IN] Event type class.
+{
+ EventRec *pRecord;
+ HRESULT hr = S_OK;
+
+ _ASSERTE(TypeFromToken(ev) == mdtEvent && RidFromToken(ev));
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetEventRecord(RidFromToken(ev), &pRecord));
+ if (dwEventFlags != ULONG_MAX)
+ {
+ // Don't let caller set reserved bits
+ dwEventFlags &= ~evReservedMask;
+ // Preserve reserved bits.
+ dwEventFlags |= (pRecord->GetEventFlags() & evReservedMask);
+
+ pRecord->SetEventFlags(static_cast<USHORT>(dwEventFlags));
+ }
+ if (!IsNilToken(tkEventType))
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_Event, EventRec::COL_EventType,
+ pRecord, tkEventType));
+ErrExit:
+ return hr;
+} // HRESULT RegMeta::_SetEventProps1()
+
+//******************************************************************************
+// Set the specified properties on the given Event token.
+//******************************************************************************
+HRESULT RegMeta::_SetEventProps2( // Return hresult.
+ mdEvent ev, // [IN] Event token.
+ mdMethodDef mdAddOn, // [IN] Add method.
+ mdMethodDef mdRemoveOn, // [IN] Remove method.
+ mdMethodDef mdFire, // [IN] Fire method.
+ mdMethodDef rmdOtherMethods[], // [IN] An array of other methods.
+ BOOL bClear) // [IN] Specifies whether to clear the existing MethodSemantics records.
+{
+ EventRec *pRecord;
+ HRESULT hr = S_OK;
+
+
+
+ _ASSERTE(TypeFromToken(ev) == mdtEvent && RidFromToken(ev));
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetEventRecord(RidFromToken(ev), &pRecord));
+
+ // Remember the AddOn method.
+ if (!IsNilToken(mdAddOn))
+ {
+ _ASSERTE(TypeFromToken(mdAddOn) == mdtMethodDef);
+ IfFailGo(_DefineMethodSemantics(msAddOn, mdAddOn, ev, bClear));
+ }
+
+ // Remember the RemoveOn method.
+ if (!IsNilToken(mdRemoveOn))
+ {
+ _ASSERTE(TypeFromToken(mdRemoveOn) == mdtMethodDef);
+ IfFailGo(_DefineMethodSemantics(msRemoveOn, mdRemoveOn, ev, bClear));
+ }
+
+ // Remember the fire method.
+ if (!IsNilToken(mdFire))
+ {
+ _ASSERTE(TypeFromToken(mdFire) == mdtMethodDef);
+ IfFailGo(_DefineMethodSemantics(msFire, mdFire, ev, bClear));
+ }
+
+ // Store all of the other methods.
+ if (rmdOtherMethods)
+ {
+ int i = 0;
+ mdMethodDef mb;
+
+ while (1)
+ {
+ mb = rmdOtherMethods[i++];
+ if (IsNilToken(mb))
+ break;
+ _ASSERTE(TypeFromToken(mb) == mdtMethodDef);
+ IfFailGo(_DefineMethodSemantics(msOther, mb, ev, bClear));
+
+ // The first call would've cleared all the existing ones.
+ bClear = false;
+ }
+ }
+ErrExit:
+
+ return hr;
+} // HRESULT RegMeta::_SetEventProps2()
+
+//******************************************************************************
+// Set Permission on the given permission token.
+//******************************************************************************
+HRESULT RegMeta::_SetPermissionSetProps( // Return hresult.
+ mdPermission tkPerm, // [IN] Permission token.
+ DWORD dwAction, // [IN] CorDeclSecurity.
+ void const *pvPermission, // [IN] Permission blob.
+ ULONG cbPermission) // [IN] Count of bytes of pvPermission.
+{
+ DeclSecurityRec *pRecord;
+ HRESULT hr = S_OK;
+
+ _ASSERTE(TypeFromToken(tkPerm) == mdtPermission && cbPermission != ULONG_MAX);
+ _ASSERTE(dwAction && dwAction <= dclMaximumValue);
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetDeclSecurityRecord(RidFromToken(tkPerm), &pRecord));
+
+ IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_DeclSecurity, DeclSecurityRec::COL_PermissionSet,
+ pRecord, pvPermission, cbPermission));
+ErrExit:
+ return hr;
+} // HRESULT RegMeta::_SetPermissionSetProps()
+
+//******************************************************************************
+// Define or set value on a constant record.
+//******************************************************************************
+HRESULT RegMeta::_DefineSetConstant( // Return hresult.
+ mdToken tk, // [IN] Parent token.
+ DWORD dwCPlusTypeFlag, // [IN] Flag for the value type, selected ELEMENT_TYPE_*
+ void const *pValue, // [IN] Constant value.
+ ULONG cchString, // [IN] Size of string in wide chars, or -1 for default.
+ BOOL bSearch) // [IN] Specifies whether to search for an existing record.
+{
+ HRESULT hr = S_OK;
+
+
+
+ if ((dwCPlusTypeFlag != ELEMENT_TYPE_VOID && dwCPlusTypeFlag != ELEMENT_TYPE_END &&
+ dwCPlusTypeFlag != ULONG_MAX) &&
+ (pValue || (pValue == 0 && (dwCPlusTypeFlag == ELEMENT_TYPE_STRING ||
+ dwCPlusTypeFlag == ELEMENT_TYPE_CLASS))))
+ {
+ ConstantRec *pConstRec = 0;
+ RID iConstRec;
+ ULONG cbBlob;
+ ULONG ulValue = 0;
+
+ if (bSearch)
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.FindConstantHelper(tk, &iConstRec));
+ if (!InvalidRid(iConstRec))
+ IfFailGo(m_pStgdb->m_MiniMd.GetConstantRecord(iConstRec, &pConstRec));
+ }
+ if (! pConstRec)
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.AddConstantRecord(&pConstRec, &iConstRec));
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_Constant, ConstantRec::COL_Parent,
+ pConstRec, tk));
+ IfFailGo( m_pStgdb->m_MiniMd.AddConstantToHash(iConstRec) );
+ }
+
+ // Add values to the various columns of the constant value row.
+ pConstRec->SetType(static_cast<BYTE>(dwCPlusTypeFlag));
+ if (!pValue)
+ pValue = &ulValue;
+ cbBlob = _GetSizeOfConstantBlob(dwCPlusTypeFlag, (void *)pValue, cchString);
+ if (cbBlob > 0)
+ {
+#if BIGENDIAN
+ void *pValueTemp;
+ pValueTemp = (void *)alloca(cbBlob);
+ IfFailGo(m_pStgdb->m_MiniMd.SwapConstant(pValue, dwCPlusTypeFlag, pValueTemp, cbBlob));
+ pValue = pValueTemp;
+#endif
+ IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_Constant, ConstantRec::COL_Value,
+ pConstRec, pValue, cbBlob));
+ }
+
+
+ // Create log record for non-token record.
+ IfFailGo(UpdateENCLog2(TBL_Constant, iConstRec));
+ }
+ErrExit:
+
+ return hr;
+} // HRESULT RegMeta::_DefineSetConstant()
+
+
+//*****************************************************************************
+// Helper: Set the properties on the given Method token.
+//*****************************************************************************
+HRESULT RegMeta::_SetMethodProps( // S_OK or error.
+ mdMethodDef md, // [IN] The MethodDef.
+ DWORD dwMethodFlags, // [IN] Method attributes.
+ ULONG ulCodeRVA, // [IN] Code RVA.
+ DWORD dwImplFlags) // [IN] MethodImpl flags.
+{
+ MethodRec *pRecord;
+ HRESULT hr = S_OK;
+
+ _ASSERTE(TypeFromToken(md) == mdtMethodDef && RidFromToken(md));
+
+ // Get the Method record.
+ IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(md), &pRecord));
+
+ // Set the data.
+ if (dwMethodFlags != ULONG_MAX)
+ {
+ // Preserve the reserved flags stored already and always keep the mdRTSpecialName
+ dwMethodFlags |= (pRecord->GetFlags() & mdReservedMask);
+
+ // Set the flags.
+ pRecord->SetFlags(static_cast<USHORT>(dwMethodFlags));
+ }
+ if (ulCodeRVA != ULONG_MAX)
+ pRecord->SetRVA(ulCodeRVA);
+ if (dwImplFlags != ULONG_MAX)
+ pRecord->SetImplFlags(static_cast<USHORT>(dwImplFlags));
+
+ IfFailGo(UpdateENCLog(md));
+ErrExit:
+ return hr;
+} // HRESULT RegMeta::_SetMethodProps()
+
+
+//*****************************************************************************
+// Helper: Set the properties on the given Field token.
+//*****************************************************************************
+HRESULT RegMeta::_SetFieldProps( // S_OK or error.
+ mdFieldDef fd, // [IN] The FieldDef.
+ DWORD dwFieldFlags, // [IN] Field attributes.
+ DWORD dwCPlusTypeFlag, // [IN] Flag for the value type, selected ELEMENT_TYPE_*
+ void const *pValue, // [IN] Constant value.
+ ULONG cchValue) // [IN] size of constant value (string, in wide chars).
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ FieldRec *pRecord;
+ HRESULT hr = S_OK;
+ int bHasDefault = false; // If defining a constant, in this call.
+
+ _ASSERTE (TypeFromToken(fd) == mdtFieldDef && RidFromToken(fd));
+
+ // Get the Field record.
+ IfFailGo(m_pStgdb->m_MiniMd.GetFieldRecord(RidFromToken(fd), &pRecord));
+
+ // See if there is a Constant.
+ if ((dwCPlusTypeFlag != ELEMENT_TYPE_VOID && dwCPlusTypeFlag != ELEMENT_TYPE_END &&
+ dwCPlusTypeFlag != ULONG_MAX) &&
+ (pValue || (pValue == 0 && (dwCPlusTypeFlag == ELEMENT_TYPE_STRING ||
+ dwCPlusTypeFlag == ELEMENT_TYPE_CLASS))))
+ {
+ if (dwFieldFlags == ULONG_MAX)
+ dwFieldFlags = pRecord->GetFlags();
+ dwFieldFlags |= fdHasDefault;
+
+ bHasDefault = true;
+ }
+
+ // Set the flags.
+ if (dwFieldFlags != ULONG_MAX)
+ {
+ if ( IsFdHasFieldRVA(dwFieldFlags) && !IsFdHasFieldRVA(pRecord->GetFlags()) )
+ {
+ // This will trigger field RVA to be created if it is not yet created!
+ _SetRVA(fd, 0, 0);
+ }
+
+ // Preserve the reserved flags stored.
+ dwFieldFlags |= (pRecord->GetFlags() & fdReservedMask);
+ // Set the flags.
+ pRecord->SetFlags(static_cast<USHORT>(dwFieldFlags));
+ }
+
+ IfFailGo(UpdateENCLog(fd));
+
+ // Set the Constant.
+ if (bHasDefault)
+ {
+ BOOL bSearch = IsCallerExternal() || IsENCOn();
+ IfFailGo(_DefineSetConstant(fd, dwCPlusTypeFlag, pValue, cchValue, bSearch));
+ }
+
+ErrExit:
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::_SetFieldProps
+
+//*****************************************************************************
+// Helper: Set the properties on the given Property token.
+//*****************************************************************************
+HRESULT RegMeta::_SetPropertyProps( // S_OK or error.
+ mdProperty pr, // [IN] Property token.
+ DWORD dwPropFlags, // [IN] CorPropertyAttr.
+ DWORD dwCPlusTypeFlag, // [IN] Flag for value type, selected ELEMENT_TYPE_*
+ void const *pValue, // [IN] Constant value.
+ ULONG cchValue, // [IN] size of constant value (string, in wide chars).
+ mdMethodDef mdSetter, // [IN] Setter of the property.
+ mdMethodDef mdGetter, // [IN] Getter of the property.
+ mdMethodDef rmdOtherMethods[]) // [IN] Array of other methods.
+{
+ PropertyRec *pRecord;
+ BOOL bClear = IsCallerExternal() || IsENCOn() || IsIncrementalOn();
+ HRESULT hr = S_OK;
+ int bHasDefault = false; // If true, constant value this call.
+
+
+
+ _ASSERTE(TypeFromToken(pr) == mdtProperty && RidFromToken(pr));
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetPropertyRecord(RidFromToken(pr), &pRecord));
+
+ if (dwPropFlags != ULONG_MAX)
+ {
+ // Clear the reserved flags from the flags passed in.
+ dwPropFlags &= (~prReservedMask);
+ }
+ // See if there is a constant.
+ if ((dwCPlusTypeFlag != ELEMENT_TYPE_VOID && dwCPlusTypeFlag != ELEMENT_TYPE_END &&
+ dwCPlusTypeFlag != ULONG_MAX) &&
+ (pValue || (pValue == 0 && (dwCPlusTypeFlag == ELEMENT_TYPE_STRING ||
+ dwCPlusTypeFlag == ELEMENT_TYPE_CLASS))))
+ {
+ if (dwPropFlags == ULONG_MAX)
+ dwPropFlags = pRecord->GetPropFlags();
+ dwPropFlags |= prHasDefault;
+
+ bHasDefault = true;
+ }
+ if (dwPropFlags != ULONG_MAX)
+ {
+ // Preserve the reserved flags.
+ dwPropFlags |= (pRecord->GetPropFlags() & prReservedMask);
+ // Set the flags.
+ pRecord->SetPropFlags(static_cast<USHORT>(dwPropFlags));
+ }
+
+ // store the getter (or clear out old one).
+ if (mdGetter != ULONG_MAX)
+ {
+ _ASSERTE(TypeFromToken(mdGetter) == mdtMethodDef || IsNilToken(mdGetter));
+ IfFailGo(_DefineMethodSemantics(msGetter, mdGetter, pr, bClear));
+ }
+
+ // Store the setter (or clear out old one).
+ if (mdSetter != ULONG_MAX)
+ {
+ _ASSERTE(TypeFromToken(mdSetter) == mdtMethodDef || IsNilToken(mdSetter));
+ IfFailGo(_DefineMethodSemantics(msSetter, mdSetter, pr, bClear));
+ }
+
+ // Store all of the other methods.
+ if (rmdOtherMethods)
+ {
+ int i = 0;
+ mdMethodDef mb;
+
+ while (1)
+ {
+ mb = rmdOtherMethods[i++];
+ if (IsNilToken(mb))
+ break;
+ _ASSERTE(TypeFromToken(mb) == mdtMethodDef);
+ IfFailGo(_DefineMethodSemantics(msOther, mb, pr, bClear));
+
+ // The first call to _DefineMethodSemantics would've cleared all the records
+ // that match with msOther and pr.
+ bClear = false;
+ }
+ }
+
+ IfFailGo(UpdateENCLog(pr));
+
+ // Set the constant.
+ if (bHasDefault)
+ {
+ BOOL bSearch = IsCallerExternal() || IsENCOn() || IsIncrementalOn();
+ IfFailGo(_DefineSetConstant(pr, dwCPlusTypeFlag, pValue, cchValue, bSearch));
+ }
+
+ErrExit:
+
+ return hr;
+} // HRESULT RegMeta::_SetPropertyProps()
+
+
+//*****************************************************************************
+// Helper: This routine sets properties on the given Param token.
+//*****************************************************************************
+HRESULT RegMeta::_SetParamProps( // Return code.
+ mdParamDef pd, // [IN] Param token.
+ LPCWSTR szName, // [IN] Param name.
+ DWORD dwParamFlags, // [IN] Param flags.
+ DWORD dwCPlusTypeFlag, // [IN] Flag for value type. selected ELEMENT_TYPE_*.
+ void const *pValue, // [OUT] Constant value.
+ ULONG cchValue) // [IN] size of constant value (string, in wide chars).
+{
+ HRESULT hr = S_OK;
+ ParamRec *pRecord;
+ int bHasDefault = false; // Is there a default for this call.
+
+ _ASSERTE(TypeFromToken(pd) == mdtParamDef && RidFromToken(pd));
+
+ IfFailGo(m_pStgdb->m_MiniMd.GetParamRecord(RidFromToken(pd), &pRecord));
+
+ // Set the properties.
+ if (szName != NULL)
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.PutStringW(TBL_Param, ParamRec::COL_Name, pRecord, szName));
+ }
+
+ if (dwParamFlags != ULONG_MAX)
+ {
+ // No one should try to set the reserved flags explicitly.
+ _ASSERTE((dwParamFlags & pdReservedMask) == 0);
+ // Clear the reserved flags from the flags passed in.
+ dwParamFlags &= (~pdReservedMask);
+ }
+ // See if there is a constant.
+ if ((dwCPlusTypeFlag != ELEMENT_TYPE_VOID && dwCPlusTypeFlag != ELEMENT_TYPE_END &&
+ dwCPlusTypeFlag != ULONG_MAX) &&
+ (pValue || (pValue == 0 && (dwCPlusTypeFlag == ELEMENT_TYPE_STRING ||
+ dwCPlusTypeFlag == ELEMENT_TYPE_CLASS))))
+ {
+ if (dwParamFlags == ULONG_MAX)
+ dwParamFlags = pRecord->GetFlags();
+ dwParamFlags |= pdHasDefault;
+
+ bHasDefault = true;
+ }
+ // Set the flags.
+ if (dwParamFlags != ULONG_MAX)
+ {
+ // Preserve the reserved flags stored.
+ dwParamFlags |= (pRecord->GetFlags() & pdReservedMask);
+ // Set the flags.
+ pRecord->SetFlags(static_cast<USHORT>(dwParamFlags));
+ }
+
+ // ENC log for the param record.
+ IfFailGo(UpdateENCLog(pd));
+
+ // Defer setting the constant until after the ENC log for the param. Due to the way that
+ // parameter records are re-ordered, ENC needs the param record log entry to be IMMEDIATELY
+ // after the param added function.
+
+ // Set the constant.
+ if (bHasDefault)
+ {
+ BOOL bSearch = IsCallerExternal() || IsENCOn();
+ IfFailGo(_DefineSetConstant(pd, dwCPlusTypeFlag, pValue, cchValue, bSearch));
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT RegMeta::_SetParamProps()
+
+//*****************************************************************************
+// Create and populate a new TypeDef record.
+//*****************************************************************************
+HRESULT RegMeta::_DefineTypeDef( // S_OK or error.
+ LPCWSTR szTypeDef, // [IN] Name of TypeDef
+ DWORD dwTypeDefFlags, // [IN] CustomAttribute flags
+ mdToken tkExtends, // [IN] extends this TypeDef or typeref
+ mdToken rtkImplements[], // [IN] Implements interfaces
+ mdTypeDef tdEncloser, // [IN] TypeDef token of the Enclosing Type.
+ mdTypeDef *ptd) // [OUT] Put TypeDef token here
+{
+ HRESULT hr = S_OK; // A result.
+ TypeDefRec *pRecord = NULL; // New TypeDef record.
+ RID iRecord; // New TypeDef RID.
+ CQuickBytes qbNamespace; // Namespace buffer.
+ CQuickBytes qbName; // Name buffer.
+ LPUTF8 szTypeDefUTF8; // Full name in UTF8.
+ ULONG ulStringLen; // Length of the TypeDef string.
+ int bSuccess; // Return value for SplitPath().
+
+
+
+ _ASSERTE(IsTdAutoLayout(dwTypeDefFlags) || IsTdSequentialLayout(dwTypeDefFlags) || IsTdExplicitLayout(dwTypeDefFlags));
+
+ _ASSERTE(ptd);
+ _ASSERTE(TypeFromToken(tkExtends) == mdtTypeRef || TypeFromToken(tkExtends) == mdtTypeDef || TypeFromToken(tkExtends) == mdtTypeSpec
+ || IsNilToken(tkExtends));
+ _ASSERTE(szTypeDef && *szTypeDef);
+ _ASSERTE(IsNilToken(tdEncloser) || IsTdNested(dwTypeDefFlags));
+
+ UTF8STR(szTypeDef, szTypeDefUTF8);
+ PREFIX_ASSUME(szTypeDefUTF8 != NULL);
+
+ ulStringLen = (ULONG)(strlen(szTypeDefUTF8) + 1);
+ IfFailGo(qbNamespace.ReSizeNoThrow(ulStringLen));
+ IfFailGo(qbName.ReSizeNoThrow(ulStringLen));
+ bSuccess = ns::SplitPath(szTypeDefUTF8,
+ (LPUTF8)qbNamespace.Ptr(),
+ ulStringLen,
+ (LPUTF8)qbName.Ptr(),
+ ulStringLen);
+ _ASSERTE(bSuccess);
+
+ if (CheckDups(MDDupTypeDef))
+ {
+ // Check for existence. Do a query by namespace and name.
+ hr = ImportHelper::FindTypeDefByName(&(m_pStgdb->m_MiniMd),
+ (LPCUTF8)qbNamespace.Ptr(),
+ (LPCUTF8)qbName.Ptr(),
+ tdEncloser,
+ ptd);
+ if (SUCCEEDED(hr))
+ {
+ if (IsENCOn())
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(*ptd), &pRecord));
+ // <TODO>@FUTURE: Should we check to see if the GUID passed is correct?</TODO>
+ }
+ else
+ {
+ hr = META_S_DUPLICATE;
+ goto ErrExit;
+ }
+ }
+ else if (hr != CLDB_E_RECORD_NOTFOUND)
+ IfFailGo(hr);
+ }
+
+ if (!pRecord)
+ {
+ // Create the new record.
+ IfFailGo(m_pStgdb->m_MiniMd.AddTypeDefRecord(&pRecord, &iRecord));
+
+ // Invalidate the ref to def optimization since more def is introduced
+ SetTypeDefDirty(true);
+
+ if (!IsNilToken(tdEncloser))
+ {
+ NestedClassRec *pNestedClassRec;
+ RID iNestedClassRec;
+
+ // Create a new NestedClass record.
+ IfFailGo(m_pStgdb->m_MiniMd.AddNestedClassRecord(&pNestedClassRec, &iNestedClassRec));
+ // Set the NestedClass value.
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_NestedClass, NestedClassRec::COL_NestedClass,
+ pNestedClassRec, TokenFromRid(iRecord, mdtTypeDef)));
+ // Set the NestedClass value.
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_NestedClass, NestedClassRec::COL_EnclosingClass,
+ pNestedClassRec, tdEncloser));
+
+ IfFailGo( m_pStgdb->m_MiniMd.AddNestedClassToHash(iNestedClassRec) );
+
+ // Create the log record for the non-token record.
+ IfFailGo(UpdateENCLog2(TBL_NestedClass, iNestedClassRec));
+ }
+
+ // Give token back to caller.
+ *ptd = TokenFromRid(iRecord, mdtTypeDef);
+ }
+
+ // Set the namespace and name.
+ IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_TypeDef, TypeDefRec::COL_Name,
+ pRecord, (LPCUTF8)qbName.Ptr()));
+ IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_TypeDef, TypeDefRec::COL_Namespace,
+ pRecord, (LPCUTF8)qbNamespace.Ptr()));
+
+ SetCallerDefine();
+ IfFailGo(_SetTypeDefProps(*ptd, dwTypeDefFlags, tkExtends, rtkImplements));
+ErrExit:
+ SetCallerExternal();
+
+ return hr;
+} // RegMeta::_DefineTypeDef
+
+#endif //FEATURE_METADATA_EMIT
+
+#if defined(FEATURE_METADATA_IN_VM) && defined(FEATURE_PREJIT)
+
+//******************************************************************************
+//--- IMetaDataCorProfileData
+//******************************************************************************
+
+HRESULT RegMeta::SetCorProfileData(
+ CorProfileData *pProfileData) // [IN] Pointer to profile data
+{
+ m_pCorProfileData = pProfileData;
+
+ return S_OK;
+}
+
+//******************************************************************************
+//--- IMDInternalMetadataReorderingOptions
+//******************************************************************************
+
+HRESULT RegMeta::SetMetaDataReorderingOptions(
+ MetaDataReorderingOptions options) // [IN] Metadata reordering options
+{
+ m_ReorderingOptions = options;
+
+ return S_OK;
+}
+
+#endif //defined(FEATURE_METADATA_IN_VM) && defined(FEATURE_PREJIT)
diff --git a/src/md/compiler/regmeta_imetadatatables.cpp b/src/md/compiler/regmeta_imetadatatables.cpp
new file mode 100644
index 0000000000..a36ccfc38b
--- /dev/null
+++ b/src/md/compiler/regmeta_imetadatatables.cpp
@@ -0,0 +1,719 @@
+// 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: RegMeta_IMetaDataTables.cpp
+//
+
+//
+// Methods of code:RegMeta class which implement public API interfaces code:IMetaDataTables:
+// * code:RegMeta::GetStringHeapSize
+// * code:RegMeta::GetBlobHeapSize
+// * code:RegMeta::GetGuidHeapSize
+// * code:RegMeta::GetUserStringHeapSize
+//
+// * code:RegMeta#GetString_IMetaDataTables
+// * code:RegMeta#GetBlob_IMetaDataTables
+// * code:RegMeta#GetGuid_IMetaDataTables
+// * code:RegMeta#GetUserString_IMetaDataTables
+//
+// * code:RegMeta::GetNextString
+// * code:RegMeta::GetNextBlob
+// * code:RegMeta::GetNextGuid
+// * code:RegMeta::GetNextUserString
+//
+// * code:RegMeta::GetNumTables
+// * code:RegMeta::GetTableIndex
+// * code:RegMeta::GetTableInfo
+// * code:RegMeta::GetColumnInfo
+// * code:RegMeta::GetCodedTokenInfo
+// * code:RegMeta::GetRow
+// * code:RegMeta::GetColumn
+//
+// Methods of code:RegMeta class which implement public API interfaces code:IMetaDataTables2:
+// * code:RegMeta::GetMetaDataStorage
+// * code:RegMeta::GetMetaDataStreamInfo
+//
+// ======================================================================================
+
+#include "stdafx.h"
+#include "regmeta.h"
+
+// --------------------------------------------------------------------------------------
+//
+// Fills size (*pcbStringsHeapSize) of internal strings heap (#String).
+// Returns S_OK or error code. Fills *pcbStringsHeapSize with 0 on error.
+// Implements public API code:IMetaDataTables::GetStringHeapSize.
+//
+HRESULT
+RegMeta::GetStringHeapSize(
+ __out ULONG *pcbStringsHeapSize) // [OUT] Size of the string heap.
+{
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ *pcbStringsHeapSize = m_pStgdb->m_MiniMd.m_StringHeap.GetUnalignedSize();
+
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // RegMeta::GetStringHeapSize
+
+// --------------------------------------------------------------------------------------
+//
+// Fills size (*pcbBlobsHeapSize) of blobs heap (#Blob).
+// Returns S_OK or error code. Fills *pcbBlobsHeapSize with 0 on error.
+// Implements public API code:IMetaDataTables::GetBlobHeapSize.
+//
+HRESULT
+RegMeta::GetBlobHeapSize(
+ __out ULONG *pcbBlobsHeapSize) // [OUT] Size of the blob heap.
+{
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ *pcbBlobsHeapSize = m_pStgdb->m_MiniMd.m_BlobHeap.GetUnalignedSize();
+
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // RegMeta::GetBlobHeapSize
+
+// --------------------------------------------------------------------------------------
+//
+// Fills size (*pcbGuidsHeapSize) of guids heap (#GUID).
+// Returns S_OK or error code. Fills *pcbGuidsHeapSize with 0 on error.
+// Implements public API code:IMetaDataTables::GetGuidHeapSize.
+//
+HRESULT
+RegMeta::GetGuidHeapSize(
+ __out ULONG *pcbGuidsHeapSize) // [OUT] Size of the Guid heap.
+{
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ *pcbGuidsHeapSize = m_pStgdb->m_MiniMd.m_GuidHeap.GetSize();
+
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // RegMeta::GetGuidHeapSize
+
+// --------------------------------------------------------------------------------------
+//
+// Fills size (*pcbUserStringsHeapSize) of user strings heap (#US) (referenced from IL).
+// Returns S_OK or error code. Fills *pcbUserStringsHeapSize with 0 on error.
+// Implements public API code:IMetaDataTables::GetUserStringHeapSize.
+//
+HRESULT
+RegMeta::GetUserStringHeapSize(
+ __out ULONG *pcbUserStringsHeapSize) // [OUT] Size of the user string heap.
+{
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ *pcbUserStringsHeapSize = m_pStgdb->m_MiniMd.m_UserStringHeap.GetUnalignedSize();
+
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // RegMeta::GetUserStringHeapSize
+
+// --------------------------------------------------------------------------------------
+//
+//#GetString_IMetaDataTables
+//
+// Fills internal null-terminated string (*pszString) at index ixString from string heap (#String).
+// Returns S_OK (even for index 0) or error code (if index is invalid, fills *pszString with NULL then).
+// Implements public API code:IMetaDataTables::GetString.
+//
+HRESULT RegMeta::GetString(
+ ULONG ixString, // [IN] Value from a string column.
+ const char **pszString) // [OUT] Put a pointer to the string here.
+{
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ IfFailGo(m_pStgdb->m_MiniMd.getString(
+ ixString,
+ pszString));
+
+ _ASSERTE(hr == S_OK);
+ goto Exit;
+ErrExit:
+ *pszString = NULL;
+Exit:
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // RegMeta::GetString
+
+// --------------------------------------------------------------------------------------
+//
+//#GetBlob_IMetaDataTables
+//
+// Fills blob entry (*ppvData of size *pcbDataSize) at index ixBlob from blob heap (#Blob).
+// Returns S_OK (even for index 0) or error code (if index is invalid, fills NULL and o then).
+// Implements public API code:IMetaDataTables::GetBlob.
+//
+HRESULT RegMeta::GetBlob(
+ ULONG ixBlob, // [IN] Value from a blob column.
+ __out ULONG *pcbDataSize, // [OUT] Put size of the blob here.
+ __deref_out const void **ppvData) // [OUT] Put a pointer to the blob here.
+{
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ MetaData::DataBlob dataBlob;
+ IfFailGo(m_pStgdb->m_MiniMd.getBlob(ixBlob, &dataBlob));
+
+ *ppvData = (const void *)dataBlob.GetDataPointer();
+ *pcbDataSize = dataBlob.GetSize();
+
+ _ASSERTE(hr == S_OK);
+ goto Exit;
+ErrExit:
+ *ppvData = NULL;
+ *pcbDataSize = 0;
+Exit:
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // RegMeta::GetBlob
+
+// --------------------------------------------------------------------------------------
+//
+//#GetGuid_IMetaDataTables
+//
+// Fills guid (*ppGuid) at index ixGuid from guid heap (#GUID).
+// Returns S_OK and fills *ppGuid. Returns S_OK even for (invalid) index 0 (fills *ppGuid with pointer to
+// zeros then).
+// Retruns error code (if index is invalid except 0, fills NULL and o then).
+// Implements public API code:IMetaDataTables::GetGuid.
+//
+// Backward compatibility: returns S_OK even if the index is 0 which is invalid as specified in CLI ECMA
+// specification. In that case returns pointer to GUID from zeros.
+//
+HRESULT RegMeta::GetGuid(
+ ULONG ixGuid, // [IN] Value from a guid column.
+ const GUID **ppGuid) // [OUT] Put a pointer to the GUID here.
+{
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ REGMETA_POSSIBLE_INTERNAL_POINTER_EXPOSED();
+
+ if (ixGuid == 0)
+ {
+ // Return zeros
+ *ppGuid = GetPublicApiCompatibilityZeros<const GUID>();
+ hr = S_OK;
+ }
+ else
+ {
+ IfFailGo(m_pStgdb->m_MiniMd.m_GuidHeap.GetGuid(
+ ixGuid,
+ ppGuid));
+ }
+
+ErrExit:
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // RegMeta::GetGuid
+
+// --------------------------------------------------------------------------------------
+//
+//#GetUserString_IMetaDataTables
+//
+// Fills user string (*ppvData of size *pcbDataSize) at index ixUserString.
+// Returns S_OK (even for index 0) or error code (if index is invalid, fills NULL and o then).
+// Implements public API code:IMetaDataTables::GetUserString.
+//
+HRESULT
+RegMeta::GetUserString(
+ ULONG ixUserString, // [IN] Value from a UserString column.
+ __out ULONG *pcbDataSize, // [OUT] Put size of the UserString here.
+ __deref_out_opt const void **ppvData) // [OUT] Put a pointer to the UserString here.
+{
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ MetaData::DataBlob userString;
+ IfFailGo(m_pStgdb->m_MiniMd.GetUserString(ixUserString, &userString));
+ _ASSERTE(hr == S_OK);
+
+ *ppvData = (const void *)userString.GetDataPointer();
+ *pcbDataSize = userString.GetSize();
+
+ goto Exit;
+ErrExit:
+ *ppvData = NULL;
+ *pcbDataSize = 0;
+Exit:
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // RegMeta::GetUserString
+
+// --------------------------------------------------------------------------------------
+//
+//#GetNextString_IMetaDataTables
+//
+// Fills index of string (*pixNextString) from the internal strings heap (#String) starting behind string
+// at index ixString.
+// Returns S_OK or S_FALSE (if either index is invalid). Fills *pixNextString with 0 on S_FALSE.
+// Implements public API code:IMetaDataTables::GetNextString.
+//
+HRESULT
+RegMeta::GetNextString(
+ ULONG ixString, // [IN] Value from a string column.
+ __out ULONG *pixNextString) // [OUT] Put the index of the next string here.
+{
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ REGMETA_POSSIBLE_INTERNAL_POINTER_EXPOSED();
+
+ // Get string at index ixString
+ LPCSTR szString;
+ IfFailGo(m_pStgdb->m_MiniMd.m_StringHeap.GetString(
+ ixString,
+ &szString));
+ _ASSERTE(hr == S_OK);
+
+ // Get index behind the string - doesn't overflow, because string heap was verified
+ UINT32 ixNextString;
+ ixNextString = ixString + (UINT32)(strlen(szString) + 1);
+
+ // Verify that the next index is in the string heap
+ if (!m_pStgdb->m_MiniMd.m_StringHeap.IsValidIndex(ixNextString))
+ { // The next index is invalid
+ goto ErrExit;
+ }
+ // The next index is valid
+ *pixNextString = ixNextString;
+ goto Exit;
+
+ErrExit:
+ // Fill output parameters on error
+ *pixNextString = 0;
+ // Return S_FALSE if either of the string indexes is invalid (backward API compatibility)
+ hr = S_FALSE;
+Exit:
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // RegMeta::GetNextString
+
+// --------------------------------------------------------------------------------------
+//
+//#GetNextBlob_IMetaDataTables
+//
+// Fills index of blob (*pixNextBlob) from the blobs heap (#Blob) starting behind blob at index ixBlob.
+// Returns S_OK or S_FALSE (if either index is invalid). Fills *pixNextBlob with 0 on S_FALSE.
+// Implements public API code:IMetaDataTables::GetNextString.
+//
+HRESULT
+RegMeta::GetNextBlob(
+ ULONG ixBlob, // [IN] Value from a blob column.
+ __out ULONG *pixNextBlob) // [OUT] Put the index of the next blob here.
+{
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ REGMETA_POSSIBLE_INTERNAL_POINTER_EXPOSED();
+
+ // Get blob at index ixBlob (verifies that the blob is in the blob heap)
+ MetaData::DataBlob blob;
+ IfFailGo(m_pStgdb->m_MiniMd.m_BlobHeap.GetBlobWithSizePrefix(
+ ixBlob,
+ &blob));
+ _ASSERTE(hr == S_OK);
+
+ // Get index behind the blob - doesn't overflow, because the blob is in the blob heap
+ UINT32 ixNextBlob;
+ ixNextBlob = ixBlob + blob.GetSize();
+
+ // Verify that the next index is in the blob heap
+ if (!m_pStgdb->m_MiniMd.m_BlobHeap.IsValidIndex(ixNextBlob))
+ { // The next index is invalid
+ goto ErrExit;
+ }
+ // The next index is valid
+ *pixNextBlob = ixNextBlob;
+ goto Exit;
+
+ErrExit:
+ // Fill output parameters on error
+ *pixNextBlob = 0;
+ // Return S_FALSE if either of the string indexes is invalid (backward API compatibility)
+ hr = S_FALSE;
+Exit:
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // RegMeta::GetNextBlob
+
+// --------------------------------------------------------------------------------------
+//
+//#GetNextGuid_IMetaDataTables
+//
+// Fills index of guid (*pixNextGuid) from the guids heap (#GUID) starting behind guid at index ixGuid.
+// Returns S_OK or S_FALSE (if the new index is invalid). Fills *pixNextGuid with 0 on S_FALSE.
+// Implements public API code:IMetaDataTables::GetNextGuid.
+//
+// Backward compatibility: returns S_OK even if the guid index (ixGuid) is 0 which is invalid as
+// specified in CLI ECMA specification.
+//
+HRESULT
+RegMeta::GetNextGuid(
+ ULONG ixGuid, // [IN] Value from a guid column.
+ __out ULONG *pixNextGuid) // [OUT] Put the index of the next guid here.
+{
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ S_UINT32 ixNextGuid = S_UINT32(ixGuid) + S_UINT32(1);
+ if (ixNextGuid.IsOverflow())
+ { // It's invalid index (UINT32_MAX)
+ goto ErrExit;
+ }
+ if (!m_pStgdb->m_MiniMd.m_GuidHeap.IsValidIndex(ixNextGuid.Value()))
+ { // The next index is invalid
+ goto ErrExit;
+ }
+ _ASSERTE(hr == S_OK);
+ // The next index is valid
+ *pixNextGuid = ixNextGuid.Value();
+ goto Exit;
+
+ErrExit:
+ // Fill output parameters on error
+ *pixNextGuid = 0;
+ // Return S_FALSE if next guid index is invalid (backward API compatibility)
+ hr = S_FALSE;
+Exit:
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // RegMeta::GetNextGuid
+
+// --------------------------------------------------------------------------------------
+//
+//#GetNextUserString_IMetaDataTables
+//
+// Fills index of user string (*pixNextUserString) from the user strings heap (#US) starting behind string
+// at index ixUserString.
+// Returns S_OK or S_FALSE (if either index is invalid). Fills *pixNextUserString with 0 on S_FALSE.
+// Implements public API code:IMetaDataTables::GetNextUserString.
+//
+// Backward compatibility: returns S_OK even if the string doesn't have odd number of bytes as specified
+// in CLI ECMA specification.
+//
+HRESULT
+RegMeta::GetNextUserString(
+ ULONG ixUserString, // [IN] Value from a UserString column.
+ __out ULONG *pixNextUserString) // [OUT] Put the index of the next user string here.
+{
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ REGMETA_POSSIBLE_INTERNAL_POINTER_EXPOSED();
+
+ // Get user string at index ixUserString (verifies that the user string is in the heap)
+ MetaData::DataBlob userString;
+ IfFailGo(m_pStgdb->m_MiniMd.m_UserStringHeap.GetBlobWithSizePrefix(
+ ixUserString,
+ &userString));
+ _ASSERTE(hr == S_OK);
+
+ // Get index behind the user string - doesn't overflow, because the user string is in the heap
+ UINT32 ixNextUserString;
+ ixNextUserString = ixUserString + userString.GetSize();
+
+ // Verify that the next index is in the user string heap
+ if (!m_pStgdb->m_MiniMd.m_UserStringHeap.IsValidIndex(ixNextUserString))
+ { // The next index is invalid
+ goto ErrExit;
+ }
+ // The next index is valid
+ *pixNextUserString = ixNextUserString;
+ goto Exit;
+
+ErrExit:
+ // Fill output parameters on error
+ *pixNextUserString = 0;
+ // Return S_FALSE if either of the string indexes is invalid (backward API compatibility)
+ hr = S_FALSE;
+Exit:
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // RegMeta::GetNextUserString
+
+// --------------------------------------------------------------------------------------
+//
+// Implements public API code:IMetaDataTables::GetNumTables.
+//
+HRESULT
+RegMeta::GetNumTables(
+ __out ULONG *pcTables) // [OUT] Count of tables.
+{
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ // These are for dumping metadata information.
+ // We probably don't need to do any lock here.
+
+ *pcTables = m_pStgdb->m_MiniMd.GetCountTables();
+ END_ENTRYPOINT_NOTHROW;
+
+ return S_OK;
+} // RegMeta::GetNumTables
+
+// --------------------------------------------------------------------------------------
+//
+// Implements public API code:IMetaDataTables::GetTableIndex.
+//
+HRESULT
+RegMeta::GetTableIndex(
+ ULONG token, // [IN] Token for which to get table index.
+ __out ULONG *pixTbl) // [OUT] Put table index here.
+{
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ // These are for dumping metadata information.
+ // We probably don't need to do any lock here.
+
+ *pixTbl = CMiniMdRW::GetTableForToken(token);
+ END_ENTRYPOINT_NOTHROW;
+
+ return S_OK;
+} // RegMeta::GetTableIndex
+
+// --------------------------------------------------------------------------------------
+//
+// Implements public API code:IMetaDataTables::GetTableInfo.
+//
+HRESULT
+RegMeta::GetTableInfo(
+ ULONG ixTbl, // [IN] Which table.
+ ULONG *pcbRow, // [OUT] Size of a row, bytes.
+ ULONG *pcRows, // [OUT] Number of rows.
+ ULONG *pcCols, // [OUT] Number of columns in each row.
+ ULONG *piKey, // [OUT] Key column, or -1 if none.
+ const char **ppName) // [OUT] Name of the table.
+{
+ HRESULT hr = S_OK;
+ CMiniTableDef *pTbl = NULL;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ // These are for dumping metadata information.
+ // We probably don't need to do any lock here.
+
+ if (ixTbl >= m_pStgdb->m_MiniMd.GetCountTables())
+ IfFailGo(E_INVALIDARG);
+ pTbl = &m_pStgdb->m_MiniMd.m_TableDefs[ixTbl];
+ if (pcbRow != NULL)
+ *pcbRow = pTbl->m_cbRec;
+ if (pcRows != NULL)
+ *pcRows = m_pStgdb->m_MiniMd.GetCountRecs(ixTbl);
+ if (pcCols != NULL)
+ *pcCols = pTbl->m_cCols;
+ if (piKey != NULL)
+ *piKey = (pTbl->m_iKey == (BYTE) -1) ? -1 : pTbl->m_iKey;
+ if (ppName != NULL)
+ *ppName = g_Tables[ixTbl].m_pName;
+
+ErrExit:
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // RegMeta::GetTableInfo
+
+// --------------------------------------------------------------------------------------
+//
+// Implements public API code:IMetaDataTables::GetColumnInfo.
+//
+HRESULT
+RegMeta::GetColumnInfo(
+ ULONG ixTbl, // [IN] Which Table
+ ULONG ixCol, // [IN] Which Column in the table
+ ULONG *poCol, // [OUT] Offset of the column in the row.
+ ULONG *pcbCol, // [OUT] Size of a column, bytes.
+ ULONG *pType, // [OUT] Type of the column.
+ const char **ppName) // [OUT] Name of the Column.
+{
+ HRESULT hr = S_OK;
+ CMiniTableDef *pTbl = NULL;
+ CMiniColDef *pCol = NULL;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ // These are for dumping metadata information.
+ // We probably don't need to do any lock here.
+
+ if (ixTbl >= m_pStgdb->m_MiniMd.GetCountTables())
+ IfFailGo(E_INVALIDARG);
+ pTbl = &m_pStgdb->m_MiniMd.m_TableDefs[ixTbl];
+ if (ixCol >= pTbl->m_cCols)
+ IfFailGo(E_INVALIDARG);
+ pCol = &pTbl->m_pColDefs[ixCol];
+ if (poCol != NULL)
+ *poCol = pCol->m_oColumn;
+ if (pcbCol != NULL)
+ *pcbCol = pCol->m_cbColumn;
+ if (pType != NULL)
+ *pType = pCol->m_Type;
+ if (ppName != NULL)
+ *ppName = g_Tables[ixTbl].m_pColNames[ixCol];
+
+ErrExit:
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // RegMeta::GetColumnInfo
+
+// --------------------------------------------------------------------------------------
+//
+// Implements public API code:IMetaDataTables::GetCodedTokenInfo.
+//
+HRESULT
+RegMeta::GetCodedTokenInfo(
+ ULONG ixCdTkn, // [IN] Which kind of coded token.
+ ULONG *pcTokens, // [OUT] Count of tokens.
+ ULONG **ppTokens, // [OUT] List of tokens.
+ const char **ppName) // [OUT] Name of the CodedToken.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ // These are for dumping metadata information.
+ // We probably don't need to do any lock here.
+
+ // Validate arguments.
+ if (ixCdTkn >= CDTKN_COUNT)
+ IfFailGo(E_INVALIDARG);
+
+ if (pcTokens != NULL)
+ *pcTokens = g_CodedTokens[ixCdTkn].m_cTokens;
+ if (ppTokens != NULL)
+ *ppTokens = (ULONG*)g_CodedTokens[ixCdTkn].m_pTokens;
+ if (ppName != NULL)
+ *ppName = g_CodedTokens[ixCdTkn].m_pName;
+
+ErrExit:
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // RegMeta::GetCodedTokenInfo
+
+// --------------------------------------------------------------------------------------
+//
+// Implements public API code:IMetaDataTables::GetRow.
+//
+HRESULT
+RegMeta::GetRow(
+ ULONG ixTbl, // [IN] Which table.
+ ULONG rid, // [IN] Which row.
+ void **ppRow) // [OUT] Put pointer to row here.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ // These are for dumping metadata information.
+ // We probably don't need to do any lock here.
+
+ // Validate arguments.
+ if (ixTbl >= m_pStgdb->m_MiniMd.GetCountTables())
+ IfFailGo(E_INVALIDARG);
+ if (rid == 0 || rid > m_pStgdb->m_MiniMd.m_Schema.m_cRecs[ixTbl])
+ IfFailGo(E_INVALIDARG);
+
+ // Get the row.
+ IfFailGo(m_pStgdb->m_MiniMd.getRow(ixTbl, rid, ppRow));
+
+ErrExit:
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // RegMeta::GetRow
+
+// --------------------------------------------------------------------------------------
+//
+// Implements public API code:IMetaDataTables::GetColumn.
+//
+HRESULT
+RegMeta::GetColumn(
+ ULONG ixTbl, // [IN] Which table.
+ ULONG ixCol, // [IN] Which column.
+ ULONG rid, // [IN] Which row.
+ ULONG *pVal) // [OUT] Put the column contents here.
+{
+ HRESULT hr = S_OK;
+ CMiniColDef *pCol = NULL;
+ CMiniTableDef *pTbl = NULL;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ // These are for dumping metadata information.
+ // We probably don't need to do any lock here.
+
+ void *pRow = NULL; // Row with data.
+
+ // Validate arguments.
+ if (ixTbl >= m_pStgdb->m_MiniMd.GetCountTables())
+ IfFailGo(E_INVALIDARG);
+ pTbl = &m_pStgdb->m_MiniMd.m_TableDefs[ixTbl];
+ if (ixCol >= pTbl->m_cCols)
+ IfFailGo(E_INVALIDARG);
+ if (rid == 0 || rid > m_pStgdb->m_MiniMd.m_Schema.m_cRecs[ixTbl])
+ IfFailGo(E_INVALIDARG);
+
+ // Get the row.
+ IfFailGo(m_pStgdb->m_MiniMd.getRow(ixTbl, rid, &pRow));
+
+ // Is column a token column?
+ pCol = &pTbl->m_pColDefs[ixCol];
+ if (pCol->m_Type <= iCodedTokenMax)
+ {
+ *pVal = m_pStgdb->m_MiniMd.GetToken(ixTbl, ixCol, pRow);
+ }
+ else
+ {
+ *pVal = m_pStgdb->m_MiniMd.GetCol(ixTbl, ixCol, pRow);
+ }
+
+ErrExit:
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // RegMeta::GetColumn
+
+// --------------------------------------------------------------------------------------
+//
+// Implements public API code:IMetaDataTables2::GetMetaDataStorage.
+//
+HRESULT
+RegMeta::GetMetaDataStorage(
+ const void **ppvMd, // [OUT] put pointer to MD section here (aka, 'BSJB').
+ ULONG *pcbMd) // [OUT] put size of the stream here.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+ REGMETA_POSSIBLE_INTERNAL_POINTER_EXPOSED();
+
+ hr = m_pStgdb->GetRawData(ppvMd, pcbMd);
+
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // RegMeta::GetMetaDataStorage
+
+// --------------------------------------------------------------------------------------
+//
+// Implements public API code:IMetaDataTables2::GetMetaDataStreamInfo.
+//
+HRESULT
+RegMeta::GetMetaDataStreamInfo(
+ 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.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+ REGMETA_POSSIBLE_INTERNAL_POINTER_EXPOSED();
+
+ hr = m_pStgdb->GetRawStreamInfo(ix, ppchName, ppv, pcb);
+
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // RegMeta::GetMetaDataStreamInfo
diff --git a/src/md/compiler/regmeta_import.cpp b/src/md/compiler/regmeta_import.cpp
new file mode 100644
index 0000000000..dd260b42a8
--- /dev/null
+++ b/src/md/compiler/regmeta_import.cpp
@@ -0,0 +1,1204 @@
+// 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: RegMeta_IMetaDataImport.cpp
+//
+
+//
+// Methods of code:RegMeta class which implement public API interfaces:
+// * code:IMetaDataImport
+// * code:IMetaDataImport2
+//
+// ======================================================================================
+
+#include "stdafx.h"
+#include "regmeta.h"
+#include "metadata.h"
+#include "corerror.h"
+#include "mdutil.h"
+#include "rwutil.h"
+#include "mdlog.h"
+#include "importhelper.h"
+#include "filtermanager.h"
+#include "mdperf.h"
+#include "switches.h"
+#include "posterror.h"
+#include "stgio.h"
+#include "sstring.h"
+
+#include <metamodelrw.h>
+
+#define DEFINE_CUSTOM_NODUPCHECK 1
+#define DEFINE_CUSTOM_DUPCHECK 2
+#define SET_CUSTOM 3
+
+#if defined(_DEBUG) && defined(_TRACE_REMAPS)
+#define LOGGING
+#endif
+#include <log.h>
+
+#ifdef _MSC_VER
+#pragma warning(disable: 4102)
+#endif
+
+//*****************************************************************************
+// determine if a token is valid or not
+//*****************************************************************************
+BOOL RegMeta::IsValidToken( // true if tk is valid token
+ mdToken tk) // [IN] token to be checked
+{
+ BOOL fRet = FALSE;
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_VOIDRET;
+
+ LOCKREADNORET();
+
+ // If acquiring the lock failed...
+ IfFailGo(hr);
+
+ fRet = m_pStgdb->m_MiniMd._IsValidToken(tk);
+
+ErrExit:
+ END_ENTRYPOINT_VOIDRET;
+ return fRet;
+} // RegMeta::IsValidToken
+
+//*****************************************************************************
+// Close an enumerator.
+//*****************************************************************************
+void __stdcall RegMeta::CloseEnum(
+ HCORENUM hEnum) // The enumerator.
+{
+ BEGIN_CLEANUP_ENTRYPOINT;
+
+ LOG((LOGMD, "RegMeta::CloseEnum(0x%08x)\n", hEnum));
+
+ // No need to lock this function.
+ HENUMInternal *pmdEnum = reinterpret_cast<HENUMInternal *> (hEnum);
+
+ if (pmdEnum == NULL)
+ return;
+
+ // This function may be called through RCW. When hosted, we have probed before this call, so the
+ // following contract violation is OK.
+ CONTRACT_VIOLATION(SOToleranceViolation);
+ HENUMInternal::DestroyEnum(pmdEnum);
+ END_CLEANUP_ENTRYPOINT;
+} // RegMeta::CloseEnum
+
+//*****************************************************************************
+// Query the count of items represented by an enumerator.
+//*****************************************************************************
+HRESULT CountEnum(
+ HCORENUM hEnum, // The enumerator.
+ ULONG *pulCount) // Put the count here.
+{
+ HENUMInternal *pmdEnum = reinterpret_cast<HENUMInternal *> (hEnum);
+ HRESULT hr = S_OK;
+
+ // No need to lock this function.
+
+ LOG((LOGMD, "RegMeta::CountEnum(0x%08x, 0x%08x)\n", hEnum, pulCount));
+ START_MD_PERF();
+
+ _ASSERTE( pulCount );
+
+ if (pmdEnum == NULL)
+ {
+ *pulCount = 0;
+ goto ErrExit;
+ }
+
+ if (pmdEnum->m_tkKind == (TBL_MethodImpl << 24))
+ {
+ // Number of tokens must always be a multiple of 2.
+ _ASSERTE(! (pmdEnum->m_ulCount % 2) );
+ // There are two entries in the Enumerator for each MethodImpl.
+ *pulCount = pmdEnum->m_ulCount / 2;
+ }
+ else
+ *pulCount = pmdEnum->m_ulCount;
+ErrExit:
+ STOP_MD_PERF(CountEnum);
+ return hr;
+} // ::CountEnum
+
+STDMETHODIMP RegMeta::CountEnum(
+ HCORENUM hEnum, // The enumerator.
+ ULONG *pulCount) // Put the count here.
+{
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ hr = ::CountEnum(hEnum, pulCount);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // RegMeta::CountEnum
+
+//*****************************************************************************
+// Reset an enumerator to any position within the enumerator.
+//*****************************************************************************
+STDMETHODIMP RegMeta::ResetEnum(
+ HCORENUM hEnum, // The enumerator.
+ ULONG ulPos) // Seek position.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal *pmdEnum = reinterpret_cast<HENUMInternal *> (hEnum);
+
+ // No need to lock this function.
+
+ LOG((LOGMD, "RegMeta::ResetEnum(0x%08x, 0x%08x)\n", hEnum, ulPos));
+ START_MD_PERF();
+
+ if (pmdEnum == NULL)
+ goto ErrExit;
+
+ pmdEnum->u.m_ulCur = pmdEnum->u.m_ulStart + ulPos;
+
+ErrExit:
+ STOP_MD_PERF(ResetEnum);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // RegMeta::ResetEnum
+
+//*****************************************************************************
+// Enumerate Sym.TypeDef.
+//*****************************************************************************
+STDMETHODIMP RegMeta::EnumTypeDefs(
+ HCORENUM *phEnum, // Pointer to the enumerator.
+ mdTypeDef rTypeDefs[], // Put TypeDefs here.
+ ULONG cMax, // Max TypeDefs to put.
+ ULONG *pcTypeDefs) // Put # put here.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ HENUMInternal *pEnum;
+
+ LOG((LOGMD, "RegMeta::EnumTypeDefs(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, rTypeDefs, cMax, pcTypeDefs));
+ START_MD_PERF();
+ LOCKREAD();
+
+
+ if ( *ppmdEnum == 0 )
+ {
+ // instantiating a new ENUM
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ if (pMiniMd->HasDelete() &&
+ ((m_OptionValue.m_ImportOption & MDImportOptionAllTypeDefs) == 0))
+ {
+ IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtTypeDef, &pEnum) );
+
+ // add all Types to the dynamic array if name is not _Delete
+ for (ULONG index = 2; index <= pMiniMd->getCountTypeDefs(); index ++ )
+ {
+ TypeDefRec *pRec;
+ IfFailGo(pMiniMd->GetTypeDefRecord(index, &pRec));
+ LPCSTR szTypeDefName;
+ IfFailGo(pMiniMd->getNameOfTypeDef(pRec, &szTypeDefName));
+ if (IsDeletedName(szTypeDefName))
+ {
+ continue;
+ }
+ IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtTypeDef) ) );
+ }
+ }
+ else
+ {
+ // create the enumerator
+ IfFailGo( HENUMInternal::CreateSimpleEnum(
+ mdtTypeDef,
+ 2,
+ pMiniMd->getCountTypeDefs() + 1,
+ &pEnum) );
+ }
+
+ // set the output parameter
+ *ppmdEnum = pEnum;
+ }
+ else
+ {
+ pEnum = *ppmdEnum;
+ }
+
+ // we can only fill the minimun of what caller asked for or what we have left
+ hr = HENUMInternal::EnumWithCount(pEnum, cMax, rTypeDefs, pcTypeDefs);
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+
+ STOP_MD_PERF(EnumTypeDefs);
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::EnumTypeDefs
+
+//*****************************************************************************
+// Enumerate Sym.InterfaceImpl where Coclass == td
+//*****************************************************************************
+STDMETHODIMP RegMeta::EnumInterfaceImpls(
+ HCORENUM *phEnum, // Pointer to the enum.
+ mdTypeDef td, // TypeDef to scope the enumeration.
+ mdInterfaceImpl rImpls[], // Put InterfaceImpls here.
+ ULONG cMax, // Max InterfaceImpls to put.
+ ULONG *pcImpls) // Put # put here.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ ULONG ridStart;
+ ULONG ridEnd;
+ HENUMInternal *pEnum;
+ InterfaceImplRec *pRec;
+ ULONG index;
+
+ LOG((LOGMD, "RegMeta::EnumInterfaceImpls(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, td, rImpls, cMax, pcImpls));
+ START_MD_PERF();
+ LOCKREAD();
+
+ _ASSERTE(TypeFromToken(td) == mdtTypeDef);
+
+
+ if ( *ppmdEnum == 0 )
+ {
+ // instantiating a new ENUM
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ if ( pMiniMd->IsSorted( TBL_InterfaceImpl ) )
+ {
+ IfFailGo(pMiniMd->getInterfaceImplsForTypeDef(RidFromToken(td), &ridEnd, &ridStart));
+ IfFailGo( HENUMInternal::CreateSimpleEnum( mdtInterfaceImpl, ridStart, ridEnd, &pEnum) );
+ }
+ else
+ {
+ // table is not sorted so we have to create dynmaic array
+ // create the dynamic enumerator
+ //
+ ridStart = 1;
+ ridEnd = pMiniMd->getCountInterfaceImpls() + 1;
+
+ IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtInterfaceImpl, &pEnum) );
+
+ for (index = ridStart; index < ridEnd; index ++ )
+ {
+ IfFailGo(pMiniMd->GetInterfaceImplRecord(index, &pRec));
+ if ( td == pMiniMd->getClassOfInterfaceImpl(pRec) )
+ {
+ IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtInterfaceImpl) ) );
+ }
+ }
+ }
+
+ // set the output parameter
+ *ppmdEnum = pEnum;
+ }
+ else
+ {
+ pEnum = *ppmdEnum;
+ }
+
+ // fill the output token buffer
+ hr = HENUMInternal::EnumWithCount(pEnum, cMax, rImpls, pcImpls);
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+
+ STOP_MD_PERF(EnumInterfaceImpls);
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::EnumInterfaceImpls
+
+STDMETHODIMP RegMeta::EnumGenericParams(HCORENUM *phEnum, mdToken tkOwner,
+ mdGenericParam rTokens[], ULONG cMaxTokens, ULONG *pcTokens)
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ ULONG ridStart;
+ ULONG ridEnd;
+ HENUMInternal *pEnum;
+ GenericParamRec *pRec;
+ ULONG index;
+ CMiniMdRW *pMiniMd = NULL;
+
+
+ LOG((LOGMD, "RegMeta::EnumGenericParams(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, tkOwner, rTokens, cMaxTokens, pcTokens));
+ START_MD_PERF();
+ LOCKREAD();
+
+ pMiniMd = &(m_pStgdb->m_MiniMd);
+
+
+ // See if this version of the metadata can do Generics
+ if (!pMiniMd->SupportsGenerics())
+ {
+ if (pcTokens)
+ *pcTokens = 0;
+ hr = S_FALSE;
+ goto ErrExit;
+ }
+
+
+ _ASSERTE(TypeFromToken(tkOwner) == mdtTypeDef || TypeFromToken(tkOwner) == mdtMethodDef);
+
+
+ if ( *ppmdEnum == 0 )
+ {
+ // instantiating a new ENUM
+
+ //@todo GENERICS: review this. Are we expecting a sorted table or not?
+ if ( pMiniMd->IsSorted( TBL_GenericParam ) )
+ {
+ if (TypeFromToken(tkOwner) == mdtTypeDef)
+ {
+ IfFailGo(pMiniMd->getGenericParamsForTypeDef(RidFromToken(tkOwner), &ridEnd, &ridStart));
+ }
+ else
+ {
+ IfFailGo(pMiniMd->getGenericParamsForMethodDef(RidFromToken(tkOwner), &ridEnd, &ridStart));
+ }
+
+ IfFailGo( HENUMInternal::CreateSimpleEnum(mdtGenericParam, ridStart, ridEnd, &pEnum) );
+ }
+ else
+ {
+ // table is not sorted so we have to create dynamic array
+ // create the dynamic enumerator
+ //
+ ridStart = 1;
+ ridEnd = pMiniMd->getCountGenericParams() + 1;
+
+ IfFailGo( HENUMInternal::CreateDynamicArrayEnum(mdtGenericParam, &pEnum) );
+
+ for (index = ridStart; index < ridEnd; index ++ )
+ {
+ IfFailGo(pMiniMd->GetGenericParamRecord(index, &pRec));
+ if ( tkOwner == pMiniMd->getOwnerOfGenericParam(pRec) )
+ {
+ IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtGenericParam) ) );
+ }
+ }
+ }
+
+ // set the output parameter
+ *ppmdEnum = pEnum;
+ }
+ else
+ {
+ pEnum = *ppmdEnum;
+ }
+
+ // fill the output token buffer
+ hr = HENUMInternal::EnumWithCount(pEnum, cMaxTokens, rTokens, pcTokens);
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+ STOP_MD_PERF(EnumGenericPars);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // RegMeta::EnumGenericParams
+
+STDMETHODIMP RegMeta::EnumMethodSpecs(
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdToken tkOwner, // [IN] MethodDef or MemberRef whose MethodSpecs are requested
+ mdMethodSpec rTokens[], // [OUT] Put MethodSpecs here.
+ ULONG cMaxTokens, // [IN] Max tokens to put.
+ ULONG *pcTokens) // [OUT] Put actual count here.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ ULONG ridStart;
+ ULONG ridEnd;
+ HENUMInternal *pEnum;
+ MethodSpecRec *pRec;
+ ULONG index;
+ CMiniMdRW *pMiniMd = NULL;
+
+ LOG((LOGMD, "RegMeta::EnumMethodSpecs(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, tkOwner, rTokens, cMaxTokens, pcTokens));
+ START_MD_PERF();
+ LOCKREAD();
+
+ pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ // See if this version of the metadata can do Generics
+ if (!pMiniMd->SupportsGenerics())
+ {
+ if (pcTokens)
+ *pcTokens = 0;
+ hr = S_FALSE;
+ goto ErrExit;
+ }
+
+
+ _ASSERTE(RidFromToken(tkOwner)==0 || TypeFromToken(tkOwner) == mdtMethodDef || TypeFromToken(tkOwner) == mdtMemberRef);
+
+
+ if ( *ppmdEnum == 0 )
+ {
+ // instantiating a new ENUM
+
+ if(RidFromToken(tkOwner)==0) // enumerate all MethodSpecs
+ {
+ ridStart = 1;
+ ridEnd = pMiniMd->getCountMethodSpecs() + 1;
+
+ IfFailGo( HENUMInternal::CreateSimpleEnum( mdtMethodSpec, ridStart, ridEnd, &pEnum) );
+ }
+ else
+ {
+ //@todo GENERICS: review this. Are we expecting a sorted table or not?
+ if ( pMiniMd->IsSorted( TBL_MethodSpec ) )
+ {
+ if (TypeFromToken(tkOwner) == mdtMemberRef)
+ {
+ IfFailGo(pMiniMd->getMethodSpecsForMemberRef(RidFromToken(tkOwner), &ridEnd, &ridStart));
+ }
+ else
+ {
+ IfFailGo(pMiniMd->getMethodSpecsForMethodDef(RidFromToken(tkOwner), &ridEnd, &ridStart));
+ }
+
+ IfFailGo( HENUMInternal::CreateSimpleEnum(mdtMethodSpec, ridStart, ridEnd, &pEnum) );
+ }
+ else
+ {
+ // table is not sorted so we have to create dynamic array
+ // create the dynamic enumerator
+ //
+ ridStart = 1;
+ ridEnd = pMiniMd->getCountMethodSpecs() + 1;
+
+ IfFailGo( HENUMInternal::CreateDynamicArrayEnum(mdtMethodSpec, &pEnum) );
+
+ for (index = ridStart; index < ridEnd; index ++ )
+ {
+ IfFailGo(pMiniMd->GetMethodSpecRecord(index, &pRec));
+ if ( tkOwner == pMiniMd->getMethodOfMethodSpec(pRec) )
+ {
+ IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtMethodSpec) ) );
+ }
+ }
+ }
+ }
+ // set the output parameter
+ *ppmdEnum = pEnum;
+ }
+ else
+ {
+ pEnum = *ppmdEnum;
+ }
+
+ // fill the output token buffer
+ hr = HENUMInternal::EnumWithCount(pEnum, cMaxTokens, rTokens, pcTokens);
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+ STOP_MD_PERF(EnumMethodSpecs);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::EnumMethodSpecs()
+
+STDMETHODIMP RegMeta::EnumGenericParamConstraints(
+ HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
+ mdGenericParam tkOwner, // [IN] GenericParam whose constraints are requested
+ mdGenericParamConstraint rTokens[], // [OUT] Put GenericParamConstraints here.
+ ULONG cMaxTokens, // [IN] Max GenericParamConstraints to put.
+ ULONG *pcTokens) // [OUT] Put # of tokens here.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ ULONG ridStart;
+ ULONG ridEnd;
+ HENUMInternal *pEnum;
+ GenericParamConstraintRec *pRec;
+ ULONG index;
+ CMiniMdRW *pMiniMd = NULL;
+
+ LOG((LOGMD, "RegMeta::EnumGenericParamConstraints(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, tkOwner, rTokens, cMaxTokens, pcTokens));
+ START_MD_PERF();
+ LOCKREAD();
+
+ pMiniMd = &(m_pStgdb->m_MiniMd);
+
+
+ if(TypeFromToken(tkOwner) != mdtGenericParam)
+ IfFailGo(META_E_BAD_INPUT_PARAMETER);
+
+ // See if this version of the metadata can do Generics
+ if (!pMiniMd->SupportsGenerics())
+ {
+ if (pcTokens)
+ *pcTokens = 0;
+ hr = S_FALSE;
+ goto ErrExit;
+ }
+
+ if ( *ppmdEnum == 0 )
+ {
+ // instantiating a new ENUM
+
+ //<TODO> GENERICS: review this. Are we expecting a sorted table or not? </TODO>
+ if ( pMiniMd->IsSorted( TBL_GenericParamConstraint ) )
+ {
+ IfFailGo(pMiniMd->getGenericParamConstraintsForGenericParam(RidFromToken(tkOwner), &ridEnd, &ridStart));
+ IfFailGo( HENUMInternal::CreateSimpleEnum(mdtGenericParamConstraint, ridStart, ridEnd, &pEnum) );
+ }
+ else
+ {
+ // table is not sorted so we have to create dynamic array
+ // create the dynamic enumerator
+ //
+ ridStart = 1;
+ ridEnd = pMiniMd->getCountGenericParamConstraints() + 1;
+
+ IfFailGo( HENUMInternal::CreateDynamicArrayEnum(mdtGenericParamConstraint, &pEnum));
+
+ for (index = ridStart; index < ridEnd; index ++ )
+ {
+ IfFailGo(pMiniMd->GetGenericParamConstraintRecord(index, &pRec));
+ if ( tkOwner == pMiniMd->getOwnerOfGenericParamConstraint(pRec))
+ {
+ IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index,
+ mdtGenericParamConstraint)));
+ }
+ }
+ }
+
+ // set the output parameter
+ *ppmdEnum = pEnum;
+ }
+ else
+ {
+ pEnum = *ppmdEnum;
+ }
+
+ // fill the output token buffer
+ hr = HENUMInternal::EnumWithCount(pEnum, cMaxTokens, rTokens, pcTokens);
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+ STOP_MD_PERF(EnumGenericParamConstraints);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+}
+
+//*****************************************************************************
+// Enumerate Sym.TypeRef
+//*****************************************************************************
+STDMETHODIMP RegMeta::EnumTypeRefs(
+ HCORENUM *phEnum, // Pointer to the enumerator.
+ mdTypeRef rTypeRefs[], // Put TypeRefs here.
+ ULONG cMax, // Max TypeRefs to put.
+ ULONG *pcTypeRefs) // Put # put here.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
+ ULONG cTotal;
+ HENUMInternal *pEnum = *ppmdEnum;
+
+
+
+ LOG((LOGMD, "RegMeta::EnumTypeRefs(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ phEnum, rTypeRefs, cMax, pcTypeRefs));
+ START_MD_PERF();
+ LOCKREAD();
+
+ if ( pEnum == 0 )
+ {
+ // instantiating a new ENUM
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ cTotal = pMiniMd->getCountTypeRefs();
+
+ IfFailGo( HENUMInternal::CreateSimpleEnum( mdtTypeRef, 1, cTotal + 1, &pEnum) );
+
+ // set the output parameter
+ *ppmdEnum = pEnum;
+ }
+
+ // fill the output token buffer
+ hr = HENUMInternal::EnumWithCount(pEnum, cMax, rTypeRefs, pcTypeRefs);
+
+ErrExit:
+ HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
+
+
+ STOP_MD_PERF(EnumTypeRefs);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::EnumTypeRefs()
+
+//*****************************************************************************
+// Given a namespace and a class name, return the typedef
+//*****************************************************************************
+STDMETHODIMP RegMeta::FindTypeDefByName(// S_OK or error.
+ LPCWSTR wzTypeDef, // [IN] Name of the Type.
+ mdToken tkEnclosingClass, // [IN] Enclosing class.
+ mdTypeDef *ptd) // [OUT] Put the TypeDef token here.
+{
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW
+
+ LOG((LOGMD, "{%08x} RegMeta::FindTypeDefByName(%S, 0x%08x, 0x%08x)\n",
+ this, MDSTR(wzTypeDef), tkEnclosingClass, ptd));
+ START_MD_PERF();
+ LOCKREAD();
+
+
+ if (wzTypeDef == NULL)
+ IfFailGo(E_INVALIDARG);
+ PREFIX_ASSUME(wzTypeDef != NULL);
+ LPSTR szTypeDef;
+ UTF8STR(wzTypeDef, szTypeDef);
+ LPCSTR szNamespace;
+ LPCSTR szName;
+
+ _ASSERTE(ptd);
+ _ASSERTE(TypeFromToken(tkEnclosingClass) == mdtTypeDef ||
+ TypeFromToken(tkEnclosingClass) == mdtTypeRef ||
+ IsNilToken(tkEnclosingClass));
+
+ // initialize output parameter
+ *ptd = mdTypeDefNil;
+
+ ns::SplitInline(szTypeDef, szNamespace, szName);
+ hr = ImportHelper::FindTypeDefByName(&(m_pStgdb->m_MiniMd),
+ szNamespace,
+ szName,
+ tkEnclosingClass,
+ ptd);
+ErrExit:
+
+ STOP_MD_PERF(FindTypeDefByName);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::FindTypeDefByName()
+
+//*****************************************************************************
+// Get values from Sym.Module
+//*****************************************************************************
+STDMETHODIMP RegMeta::GetScopeProps(
+ __out_ecount_opt (cchName) LPWSTR szName, // Put name here
+ ULONG cchName, // Size in chars of name buffer
+ ULONG *pchName, // Put actual length of name here
+ GUID *pmvid) // Put MVID here
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ ModuleRec *pModuleRec;
+
+
+ LOG((LOGMD, "RegMeta::GetScopeProps(%S, 0x%08x, 0x%08x, 0x%08x)\n",
+ MDSTR(szName), cchName, pchName, pmvid));
+ START_MD_PERF();
+ LOCKREAD();
+
+ // there is only one module record
+ IfFailGo(pMiniMd->GetModuleRecord(1, &pModuleRec));
+
+ if (pmvid != NULL)
+ {
+ IfFailGo(pMiniMd->getMvidOfModule(pModuleRec, pmvid));
+ }
+ // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK
+ if (szName || pchName)
+ IfFailGo( pMiniMd->getNameOfModule(pModuleRec, szName, cchName, pchName) );
+ErrExit:
+
+ STOP_MD_PERF(GetScopeProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::GetScopeProps()
+
+//*****************************************************************************
+// Get the token for a Scope's (primary) module record.
+//*****************************************************************************
+STDMETHODIMP RegMeta::GetModuleFromScope(// S_OK.
+ mdModule *pmd) // [OUT] Put mdModule token here.
+{
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LOG((LOGMD, "RegMeta::GetModuleFromScope(0x%08x)\n", pmd));
+ START_MD_PERF();
+
+ _ASSERTE(pmd);
+
+ // No need to lock this function.
+
+ *pmd = TokenFromRid(1, mdtModule);
+
+ STOP_MD_PERF(GetModuleFromScope);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::GetModuleFromScope()
+
+//*****************************************************************************
+// Given a token, is it (or its parent) global?
+//*****************************************************************************
+HRESULT RegMeta::IsGlobal( // S_OK ir error.
+ mdToken tk, // [IN] Type, Field, or Method token.
+ int *pbGlobal) // [OUT] Put 1 if global, 0 otherwise.
+{
+ HRESULT hr=S_OK; // A result.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ mdToken tkParent; // Parent of field or method.
+
+ LOG((LOGMD, "RegMeta::GetTokenForGlobalType(0x%08x, %08x)\n", tk, pbGlobal));
+ //START_MD_PERF();
+
+ // No need to lock this function.
+
+ if (!IsValidToken(tk))
+ IfFailGo(E_INVALIDARG);
+
+ switch (TypeFromToken(tk))
+ {
+ case mdtTypeDef:
+ *pbGlobal = IsGlobalMethodParentToken(tk);
+ break;
+
+ case mdtFieldDef:
+ IfFailGo( pMiniMd->FindParentOfFieldHelper(tk, &tkParent) );
+ *pbGlobal = IsGlobalMethodParentToken(tkParent);
+ break;
+
+ case mdtMethodDef:
+ IfFailGo( pMiniMd->FindParentOfMethodHelper(tk, &tkParent) );
+ *pbGlobal = IsGlobalMethodParentToken(tkParent);
+ break;
+
+ case mdtProperty:
+ IfFailGo( pMiniMd->FindParentOfPropertyHelper(tk, &tkParent) );
+ *pbGlobal = IsGlobalMethodParentToken(tkParent);
+ break;
+
+ case mdtEvent:
+ IfFailGo( pMiniMd->FindParentOfEventHelper(tk, &tkParent) );
+ *pbGlobal = IsGlobalMethodParentToken(tkParent);
+ break;
+
+ // Anything else is NOT global.
+ default:
+ *pbGlobal = FALSE;
+ }
+
+ErrExit:
+ //STOP_MD_PERF(GetModuleFromScope);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // HRESULT RegMeta::IsGlobal()
+
+//*****************************************************************************
+// return flags for a given class
+//*****************************************************************************
+HRESULT
+RegMeta::GetTypeDefProps(
+ mdTypeDef td, // [IN] TypeDef token for inquiry.
+ __out_ecount_opt (cchTypeDef) LPWSTR szTypeDef, // [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.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+ TypeDefRec *pTypeDefRec;
+ BOOL fTruncation = FALSE; // Was there name truncation?
+
+ LOG((LOGMD, "{%08x} RegMeta::GetTypeDefProps(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ this, td, szTypeDef, cchTypeDef, pchTypeDef,
+ pdwTypeDefFlags, ptkExtends));
+ START_MD_PERF();
+ LOCKREAD();
+
+ if (TypeFromToken(td) != mdtTypeDef)
+ {
+ hr = S_FALSE;
+ goto ErrExit;
+ }
+ if (td == mdTypeDefNil)
+ { // Backward compatibility with CLR 2.0 implementation
+ if (pdwTypeDefFlags != NULL)
+ *pdwTypeDefFlags = 0;
+ if (ptkExtends != NULL)
+ *ptkExtends = mdTypeRefNil;
+ if (pchTypeDef != NULL)
+ *pchTypeDef = 1;
+ if ((szTypeDef != NULL) && (cchTypeDef > 0))
+ szTypeDef[0] = 0;
+
+ hr = S_OK;
+ goto ErrExit;
+ }
+
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(td), &pTypeDefRec));
+
+ if ((szTypeDef != NULL) || (pchTypeDef != NULL))
+ {
+ LPCSTR szNamespace;
+ LPCSTR szName;
+
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeDefRec, &szNamespace));
+ MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzNamespace, szNamespace);
+ IfNullGo(wzNamespace);
+
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeDefRec, &szName));
+ MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzName, szName);
+ IfNullGo(wzName);
+
+ if (szTypeDef != NULL)
+ {
+ fTruncation = !(ns::MakePath(szTypeDef, cchTypeDef, wzNamespace, wzName));
+ }
+ if (pchTypeDef != NULL)
+ {
+ if (fTruncation || (szTypeDef == NULL))
+ {
+ *pchTypeDef = ns::GetFullLength(wzNamespace, wzName);
+ }
+ else
+ {
+ *pchTypeDef = (ULONG)(wcslen(szTypeDef) + 1);
+ }
+ }
+ }
+ if (pdwTypeDefFlags != NULL)
+ { // caller wants type flags
+ *pdwTypeDefFlags = pMiniMd->getFlagsOfTypeDef(pTypeDefRec);
+ }
+ if (ptkExtends != NULL)
+ {
+ *ptkExtends = pMiniMd->getExtendsOfTypeDef(pTypeDefRec);
+
+ // take care of the 0 case
+ if (RidFromToken(*ptkExtends) == 0)
+ {
+ *ptkExtends = mdTypeRefNil;
+ }
+ }
+
+ if (fTruncation && (hr == S_OK))
+ {
+ if ((szTypeDef != NULL) && (cchTypeDef > 0))
+ { // null-terminate the truncated output string
+ szTypeDef[cchTypeDef - 1] = W('\0');
+ }
+ hr = CLDB_S_TRUNCATION;
+ }
+
+ErrExit:
+ END_ENTRYPOINT_NOTHROW;
+
+ STOP_MD_PERF(GetTypeDefProps);
+
+ return hr;
+} // RegMeta::GetTypeDefProps
+
+//*****************************************************************************
+// Retrieve information about an implemented interface.
+//*****************************************************************************
+STDMETHODIMP RegMeta::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.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CMiniMdRW *pMiniMd = NULL;
+ InterfaceImplRec *pIIRec = NULL;
+
+
+
+ LOG((LOGMD, "RegMeta::GetInterfaceImplProps(0x%08x, 0x%08x, 0x%08x)\n",
+ iiImpl, pClass, ptkIface));
+ START_MD_PERF();
+ LOCKREAD();
+
+ _ASSERTE(TypeFromToken(iiImpl) == mdtInterfaceImpl);
+
+ pMiniMd = &(m_pStgdb->m_MiniMd);
+ IfFailGo(pMiniMd->GetInterfaceImplRecord(RidFromToken(iiImpl), &pIIRec));
+
+ if (pClass)
+ {
+ *pClass = pMiniMd->getClassOfInterfaceImpl(pIIRec);
+ }
+ if (ptkIface)
+ {
+ *ptkIface = pMiniMd->getInterfaceOfInterfaceImpl(pIIRec);
+ }
+
+ErrExit:
+ STOP_MD_PERF(GetInterfaceImplProps);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::GetInterfaceImplProps()
+
+//*****************************************************************************
+// Retrieve information about a TypeRef.
+//*****************************************************************************
+STDMETHODIMP
+RegMeta::GetTypeRefProps(
+ mdTypeRef tr, // The class ref token.
+ mdToken *ptkResolutionScope, // Resolution scope, ModuleRef or AssemblyRef.
+ __out_ecount_opt (cchTypeRef) LPWSTR szTypeRef, // Put the name here.
+ ULONG cchTypeRef, // Size of the name buffer, wide chars.
+ ULONG *pchTypeRef) // Put actual size of name here.
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CMiniMdRW *pMiniMd;
+ TypeRefRec *pTypeRefRec;
+ BOOL fTruncation = FALSE; // Was there name truncation?
+
+ LOG((LOGMD, "RegMeta::GetTypeRefProps(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ tr, ptkResolutionScope, szTypeRef, cchTypeRef, pchTypeRef));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ if (TypeFromToken(tr) != mdtTypeRef)
+ {
+ hr = S_FALSE;
+ goto ErrExit;
+ }
+ if (tr == mdTypeRefNil)
+ { // Backward compatibility with CLR 2.0 implementation
+ if (ptkResolutionScope != NULL)
+ *ptkResolutionScope = mdTokenNil;
+ if (pchTypeRef != NULL)
+ *pchTypeRef = 1;
+ if ((szTypeRef != NULL) && (cchTypeRef > 0))
+ szTypeRef[0] = 0;
+
+ hr = S_OK;
+ goto ErrExit;
+ }
+
+ pMiniMd = &(m_pStgdb->m_MiniMd);
+ IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tr), &pTypeRefRec));
+
+ if (ptkResolutionScope != NULL)
+ {
+ *ptkResolutionScope = pMiniMd->getResolutionScopeOfTypeRef(pTypeRefRec);
+ }
+
+ if ((szTypeRef != NULL) || (pchTypeRef != NULL))
+ {
+ LPCSTR szNamespace;
+ LPCSTR szName;
+
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szNamespace));
+ MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzNamespace, szNamespace);
+ IfNullGo(wzNamespace);
+
+ IfFailGo(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szName));
+ MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzName, szName);
+ IfNullGo(wzName);
+
+ if (szTypeRef != NULL)
+ {
+ fTruncation = !(ns::MakePath(szTypeRef, cchTypeRef, wzNamespace, wzName));
+ }
+ if (pchTypeRef != NULL)
+ {
+ if (fTruncation || (szTypeRef == NULL))
+ {
+ *pchTypeRef = ns::GetFullLength(wzNamespace, wzName);
+ }
+ else
+ {
+ *pchTypeRef = (ULONG)(wcslen(szTypeRef) + 1);
+ }
+ }
+ }
+ if (fTruncation && (hr == S_OK))
+ {
+ if ((szTypeRef != NULL) && (cchTypeRef > 0))
+ { // null-terminate the truncated output string
+ szTypeRef[cchTypeRef - 1] = W('\0');
+ }
+ hr = CLDB_S_TRUNCATION;
+ }
+
+ErrExit:
+ STOP_MD_PERF(GetTypeRefProps);
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+} // RegMeta::GetTypeRefProps
+
+//*****************************************************************************
+// Given a TypeRef name, return the typeref
+//*****************************************************************************
+STDMETHODIMP RegMeta::FindTypeRef( // S_OK or error.
+ mdToken tkResolutionScope, // [IN] Resolution Scope.
+ LPCWSTR wzTypeName, // [IN] Name of the TypeRef.
+ mdTypeRef *ptk) // [OUT] Put the TypeRef token here.
+{
+ HRESULT hr = S_OK; // A result.
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ LPUTF8 szFullName;
+ LPCUTF8 szNamespace;
+ LPCUTF8 szName;
+ CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ _ASSERTE(wzTypeName && ptk);
+
+
+
+ LOG((LOGMD, "RegMeta::FindTypeRef(0x%8x, %ls, 0x%08x)\n",
+ tkResolutionScope, MDSTR(wzTypeName), ptk));
+ START_MD_PERF();
+ LOCKREAD();
+
+ // Convert the name to UTF8.
+ PREFIX_ASSUME(wzTypeName != NULL); // caller might pass NULL, but they'll AV.
+ UTF8STR(wzTypeName, szFullName);
+ ns::SplitInline(szFullName, szNamespace, szName);
+
+ // Look up the name.
+ hr = ImportHelper::FindTypeRefByName(pMiniMd, tkResolutionScope,
+ szNamespace,
+ szName,
+ ptk);
+ErrExit:
+
+ STOP_MD_PERF(FindTypeRef);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+} // STDMETHODIMP RegMeta::FindTypeRef()
+
+//*******************************************************************************
+// Find a given param of a Method.
+//*******************************************************************************
+HRESULT RegMeta::_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.
+{
+ HRESULT hr;
+ ParamRec *pParamRec;
+ RID ridStart, ridEnd;
+ RID pmRid;
+
+ _ASSERTE(TypeFromToken(md) == mdtMethodDef && pParamDef);
+
+ // get the methoddef record
+ MethodRec *pMethodRec;
+ IfFailRet(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(md), &pMethodRec));
+
+ // figure out the start rid and end rid of the parameter list of this methoddef
+ ridStart = m_pStgdb->m_MiniMd.getParamListOfMethod(pMethodRec);
+ IfFailRet(m_pStgdb->m_MiniMd.getEndParamListOfMethod(RidFromToken(md), &ridEnd));
+
+ // loop through each param
+ // <TODO>@consider: parameters are sorted by sequence. Maybe a binary search?
+ //</TODO>
+ for (; ridStart < ridEnd; ridStart++)
+ {
+ IfFailRet(m_pStgdb->m_MiniMd.GetParamRid(ridStart, &pmRid));
+ IfFailRet(m_pStgdb->m_MiniMd.GetParamRecord(pmRid, &pParamRec));
+ if (iSeq == m_pStgdb->m_MiniMd.getSequenceOfParam(pParamRec))
+ {
+ // parameter has the sequence number matches what we are looking for
+ *pParamDef = TokenFromRid(pmRid, mdtParamDef);
+ return S_OK;
+ }
+ }
+ return CLDB_E_RECORD_NOTFOUND;
+} // HRESULT RegMeta::_FindParamOfMethod()
+
+//*******************************************************************************
+// Given the signature, return the token for signature.
+//*******************************************************************************
+HRESULT RegMeta::_GetTokenFromSig( // S_OK or error.
+ PCCOR_SIGNATURE pvSig, // [IN] Signature to define.
+ ULONG cbSig, // [IN] Size of signature data.
+ mdSignature *pmsig) // [OUT] returned signature token.
+{
+ HRESULT hr = S_OK;
+
+ _ASSERTE(pmsig);
+
+ if (CheckDups(MDDupSignature))
+ {
+ hr = ImportHelper::FindStandAloneSig(&(m_pStgdb->m_MiniMd), pvSig, cbSig, pmsig);
+ if (SUCCEEDED(hr))
+ {
+ if (IsENCOn())
+ return S_OK;
+ else
+ return META_S_DUPLICATE;
+ }
+ else if (hr != CLDB_E_RECORD_NOTFOUND)
+ IfFailGo(hr);
+ }
+
+ // Create a new record.
+ StandAloneSigRec *pSigRec;
+ RID iSigRec;
+
+ IfFailGo(m_pStgdb->m_MiniMd.AddStandAloneSigRecord(&pSigRec, &iSigRec));
+
+ // Set output parameter.
+ *pmsig = TokenFromRid(iSigRec, mdtSignature);
+
+ // Save signature.
+ IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_StandAloneSig, StandAloneSigRec::COL_Signature,
+ pSigRec, pvSig, cbSig));
+ IfFailGo(UpdateENCLog(*pmsig));
+ErrExit:
+ return hr;
+} // RegMeta::_GetTokenFromSig
diff --git a/src/md/compiler/regmeta_vm.cpp b/src/md/compiler/regmeta_vm.cpp
new file mode 100644
index 0000000000..beebb08b5c
--- /dev/null
+++ b/src/md/compiler/regmeta_vm.cpp
@@ -0,0 +1,586 @@
+// 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.
+
+
+//*****************************************************************************
+
+//
+// RegMeta.cpp
+//
+// Implementation for meta data public interface methods for full version.
+//
+//*****************************************************************************
+#include "stdafx.h"
+#include "regmeta.h"
+#include "metadata.h"
+#include "corerror.h"
+#include "mdutil.h"
+#include "rwutil.h"
+#include "mdlog.h"
+#include "importhelper.h"
+#include "filtermanager.h"
+#include "mdperf.h"
+#include "switches.h"
+#include "posterror.h"
+#include "stgio.h"
+#include "sstring.h"
+
+#include <metamodelrw.h>
+
+
+#ifndef FEATURE_CORECLR
+
+#include <metahost.h>
+
+// Pointer to the activated CLR interface provided by the shim.
+extern ICLRRuntimeInfo *g_pCLRRuntime;
+
+#ifdef FEATURE_METADATA_EMIT_ALL
+
+#include "iappdomainsetup.h"
+
+// {27FFF232-A7A8-40dd-8D4A-734AD59FCD41}
+EXTERN_GUID(IID_IAppDomainSetup, 0x27FFF232, 0xA7A8, 0x40dd, 0x8D, 0x4A, 0x73, 0x4A, 0xD5, 0x9F, 0xCD, 0x41);
+
+#endif //FEATURE_METADATA_EMIT_ALL
+
+#endif // !FEATURE_CORECLR
+
+
+#define DEFINE_CUSTOM_NODUPCHECK 1
+#define DEFINE_CUSTOM_DUPCHECK 2
+#define SET_CUSTOM 3
+
+#if defined(_DEBUG) && defined(_TRACE_REMAPS)
+#define LOGGING
+#endif
+#include <log.h>
+
+#ifdef _MSC_VER
+#pragma warning(disable: 4102)
+#endif
+
+//*****************************************************************************
+// Call this after initialization is complete.
+//*****************************************************************************
+HRESULT RegMeta::AddToCache()
+{
+#if defined(FEATURE_METADATA_IN_VM) || defined(FEATURE_METADATA_STANDALONE_WINRT)
+ HRESULT hr = S_OK;
+
+ // The ref count must be > 0 before the module is published, else another
+ // thread could find, use, and release the module, causing it to be deleted
+ // before this thread gets a chance to addref.
+ _ASSERTE(GetRefCount() > 0);
+ // add this RegMeta to the loaded module list.
+ m_bCached = true;
+ IfFailGo(LOADEDMODULES::AddModuleToLoadedList(this));
+ErrExit:
+ if (FAILED(hr))
+ {
+ _ASSERTE(!LOADEDMODULES::IsEntryInList(this));
+ m_bCached = false;
+ }
+ return hr;
+#else //!FEATURE_METADATA_IN_VM && !FEATURE_METADATA_STANDALONE_WINRT
+ return S_OK;
+#endif //!FEATURE_METADATA_IN_VM && !FEATURE_METADATA_STANDALONE_WINRT
+} // RegMeta::AddToCache
+
+
+//*****************************************************************************
+// Search the cached RegMetas for a given scope.
+//*****************************************************************************
+HRESULT RegMeta::FindCachedReadOnlyEntry(
+ LPCWSTR szName, // Name of the desired file.
+ DWORD dwOpenFlags, // Flags the new file is opened with.
+ RegMeta **ppMeta) // Put found RegMeta here.
+{
+#if defined(FEATURE_METADATA_IN_VM) || defined(FEATURE_METADATA_STANDALONE_WINRT)
+ return LOADEDMODULES::FindCachedReadOnlyEntry(szName, dwOpenFlags, ppMeta);
+#else //!FEATURE_METADATA_IN_VM && !FEATURE_METADATA_STANDALONE_WINRT
+ // No cache support in standalone version.
+ *ppMeta = NULL;
+ return S_FALSE;
+#endif //!FEATURE_METADATA_IN_VM && !FEATURE_METADATA_STANDALONE_WINRT
+} // RegMeta::FindCachedReadOnlyEntry
+
+
+#ifdef FEATURE_METADATA_EMIT_ALL
+
+//*****************************************************************************
+// Helper function to startup the EE
+//
+// Notes:
+// This is called by code:RegMeta.DefineSecurityAttributeSet.
+//*****************************************************************************
+HRESULT RegMeta::StartupEE()
+{
+#ifdef FEATURE_CORECLR
+ UNREACHABLE_MSG_RET("About to CoCreateInstance! This code should not be "
+ "reachable or needs to be reimplemented for CoreCLR!");
+#else // !FEATURE_CORECLR
+
+ struct Param
+ {
+ RegMeta *pThis;
+ IUnknown *pSetup;
+ IAppDomainSetup *pDomainSetup;
+ bool fDoneStart;
+ HRESULT hr;
+ } param;
+ param.pThis = this;
+ param.pSetup = NULL;
+ param.pDomainSetup = NULL;
+ param.fDoneStart = false;
+ param.hr = S_OK;
+
+ PAL_TRY(Param *, pParam, &param)
+ {
+ HRESULT hr = S_OK;
+
+ DWORD dwBuffer[1 + (MAX_LONGPATH+1) * sizeof(WCHAR) / sizeof(DWORD) + 1];
+ BSTR bstrDir = NULL;
+
+ // Create a hosting environment.
+ IfFailGo(g_pCLRRuntime->GetInterface(
+ CLSID_CorRuntimeHost,
+ IID_ICorRuntimeHost,
+ (void **)&pParam->pThis->m_pCorHost));
+
+ // Startup the runtime.
+ IfFailGo(pParam->pThis->m_pCorHost->Start());
+ pParam->fDoneStart = true;
+
+ // Create an AppDomain Setup so we can set the AppBase.
+ IfFailGo(pParam->pThis->m_pCorHost->CreateDomainSetup(&pParam->pSetup));
+
+ // Get the current directory (place it in a BSTR).
+ bstrDir = (BSTR)(dwBuffer + 1);
+ if ((dwBuffer[0] = (WszGetCurrentDirectory(MAX_LONGPATH + 1, bstrDir) * sizeof(WCHAR))))
+ {
+ // QI for the IAppDomainSetup interface.
+ IfFailGo(pParam->pSetup->QueryInterface(IID_IAppDomainSetup,
+ (void**)&pParam->pDomainSetup));
+
+ // Set the AppBase.
+ pParam->pDomainSetup->put_ApplicationBase(bstrDir);
+ }
+
+ // Create a new AppDomain.
+ IfFailGo(pParam->pThis->m_pCorHost->CreateDomainEx(W("Compilation Domain"),
+ pParam->pSetup,
+ NULL,
+ &pParam->pThis->m_pAppDomain));
+
+ // That's it, we're all set up.
+ _ASSERTE(pParam->pThis->m_pAppDomain != NULL);
+ pParam->pThis->m_fStartedEE = true;
+
+ ErrExit:
+ pParam->hr = hr;
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ _ASSERTE(!"Unexpected exception setting up hosting environment for security attributes");
+ param.hr = E_FAIL;
+ }
+ PAL_ENDTRY
+
+ // Cleanup temporary resources.
+ if (m_pAppDomain && FAILED(param.hr))
+ m_pAppDomain->Release();
+ if (param.pDomainSetup)
+ param.pDomainSetup->Release();
+ if (param.pSetup)
+ param.pSetup->Release();
+ if (param.fDoneStart && FAILED(param.hr))
+ m_pCorHost->Stop();
+ if (m_pCorHost && FAILED(param.hr))
+ m_pCorHost->Release();
+ return param.hr;
+#endif // FEATURE_CORECLR
+}
+
+#endif //FEATURE_METADATA_EMIT_ALL
+
+#ifdef FEATURE_METADATA_EMIT
+
+//*****************************************************************************
+// Persist a set of security custom attributes into a set of permission set
+// blobs on the same class or method.
+//
+// Notes:
+// Only in the full version because this is an emit operation.
+//*****************************************************************************
+HRESULT RegMeta::DefineSecurityAttributeSet(// Return code.
+ mdToken tkObj, // [IN] Class or method requiring security attributes.
+ COR_SECATTR rSecAttrs[], // [IN] Array of security attribute descriptions.
+ ULONG cSecAttrs, // [IN] Count of elements in above array.
+ ULONG *pulErrorAttr) // [OUT] On error, index of attribute causing problem.
+{
+#ifdef FEATURE_METADATA_EMIT_ALL
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ NewArrayHolder <CORSEC_ATTRSET> rAttrSets;
+ DWORD i;
+ mdPermission ps;
+ DWORD dwAction;
+ bool fProcessDeclarativeSecurityAtRuntime;
+
+ LOG((LOGMD, "RegMeta::DefineSecurityAttributeSet(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ tkObj, rSecAttrs, cSecAttrs, pulErrorAttr));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ rAttrSets = new (nothrow) CORSEC_ATTRSET[dclMaximumValue + 1];
+ if (rAttrSets == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+ goto ErrExit;
+ }
+
+ memset(rAttrSets, 0, sizeof(CORSEC_ATTRSET) * (dclMaximumValue + 1));
+
+ // Initialize error index to indicate a general error.
+ if (pulErrorAttr)
+ *pulErrorAttr = cSecAttrs;
+
+ fProcessDeclarativeSecurityAtRuntime = true;
+
+ // See if we should default to old v1.0/v1.1 serialization behavior
+ if (m_OptionValue.m_MetadataVersion < MDVersion2)
+ fProcessDeclarativeSecurityAtRuntime = false;
+
+ // Startup the EE just once, no matter how many times we're called (this is
+ // better on performance and the EE falls over if we try a start-stop-start
+ // cycle anyway).
+ if (!m_fStartedEE && !fProcessDeclarativeSecurityAtRuntime)
+ {
+ IfFailGo(StartupEE());
+ }
+
+ // Group the security attributes by SecurityAction (thus creating an array of CORSEC_PERM's)
+ IfFailGo(GroupSecurityAttributesByAction(/*OUT*/rAttrSets, rSecAttrs, cSecAttrs, tkObj, pulErrorAttr, &m_pStgdb->m_MiniMd, NULL));
+
+ // Put appropriate data in the metadata
+ for (i = 0; i <= dclMaximumValue; i++)
+ {
+ NewArrayHolder <BYTE> pbBlob(NULL);
+ NewArrayHolder <BYTE> pbNonCasBlob(NULL);
+ DWORD cbBlob = 0;
+ DWORD cbNonCasBlob = 0;
+
+ rAttrSets[i].pImport = this;
+ rAttrSets[i].pAppDomain = m_pAppDomain;
+ if (rAttrSets[i].dwAttrCount == 0)
+ continue;
+ if (pulErrorAttr)
+ *pulErrorAttr = i;
+
+ if(fProcessDeclarativeSecurityAtRuntime)
+ {
+ // Put a serialized CORSEC_ATTRSET in the metadata
+ SIZE_T cbAttrSet = 0;
+ IfFailGo(AttributeSetToBlob(&rAttrSets[i], NULL, &cbAttrSet, this, i)); // count size required for buffer
+ if (!FitsIn<DWORD>(cbAttrSet))
+ {
+ hr = COR_E_OVERFLOW;
+ goto ErrExit;
+ }
+ cbBlob = static_cast<DWORD>(cbAttrSet);
+
+ pbBlob = new (nothrow) BYTE[cbBlob]; // allocate buffer
+ if (pbBlob == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+ goto ErrExit;
+ }
+
+ IfFailGo(AttributeSetToBlob(&rAttrSets[i], pbBlob, NULL, this, i)); // serialize into the buffer
+ IfFailGo(_DefinePermissionSet(rAttrSets[i].tkObj, rAttrSets[i].dwAction, pbBlob, cbBlob, &ps)); // put it in metadata
+ }
+ else
+ {
+ // Now translate the sets of security attributes into a real permission
+ // set and convert this to a serialized Xml blob. We may possibly end up
+ // with two sets as the result of splitting CAS and non-CAS permissions
+ // into separate sets.
+ hr = TranslateSecurityAttributes(&rAttrSets[i], &pbBlob, &cbBlob, &pbNonCasBlob, &cbNonCasBlob, pulErrorAttr);
+ IfFailGo(hr);
+
+ // Persist the permission set blob into the metadata. For empty CAS
+ // blobs this is only done if the corresponding non-CAS blob is empty
+ if (cbBlob || !cbNonCasBlob)
+ IfFailGo(_DefinePermissionSet(rAttrSets[i].tkObj, rAttrSets[i].dwAction, pbBlob, cbBlob, &ps));
+
+ if (pbNonCasBlob)
+ {
+ // Map the SecurityAction to a special non-CAS action so this
+ // blob will have its own entry in the metadata
+ switch (rAttrSets[i].dwAction)
+ {
+ case dclDemand:
+ dwAction = dclNonCasDemand;
+ break;
+ case dclLinktimeCheck:
+ dwAction = dclNonCasLinkDemand;
+ break;
+ case dclInheritanceCheck:
+ dwAction = dclNonCasInheritance;
+ break;
+ default:
+ PostError(CORSECATTR_E_BAD_NONCAS);
+ IfFailGo(CORSECATTR_E_BAD_NONCAS);
+ }
+
+ // Persist to metadata
+ IfFailGo(_DefinePermissionSet(rAttrSets[i].tkObj,
+ dwAction,
+ pbNonCasBlob,
+ cbNonCasBlob,
+ &ps));
+ }
+ }
+ }
+
+ErrExit:
+ STOP_MD_PERF(DefineSecurityAttributeSet);
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return (hr);
+#else //!FEATURE_METADATA_EMIT_ALL
+ return E_NOTIMPL;
+#endif //!FEATURE_METADATA_EMIT_ALL
+} // RegMeta::DefineSecurityAttributeSet
+
+#endif //FEATURE_METADATA_EMIT
+
+
+//*****************************************************************************
+// Implementation of IMetaDataImport::ResolveTypeRef to resolve a typeref across scopes.
+//
+// Arguments:
+// tr - typeref within this scope to resolve
+// riid - interface on ppIScope to support
+// ppIScope - out-parameter to get metadata scope for typedef (*ptd)
+// ptd - out-parameter to get typedef that the ref resolves to.
+//
+// Notes:
+// TypeDefs define a type within a scope. TypeRefs refer to type-defs in other scopes
+// and allow you to import a type from another scope. This function attempts to determine
+// which type-def a type-ref points to.
+//
+// This resolve (type-ref, this cope) --> (type-def=*ptd, other scope=*ppIScope)
+//
+// However, this resolution requires knowing what modules have been loaded, which is not decided
+// until runtime via loader / fusion policy. Thus this interface can't possibly be correct since
+// it doesn't have that knowledge. Furthermore, when inspecting metadata from another process
+// (such as a debugger inspecting the debuggee's metadata), this API can be truly misleading.
+//
+// This API usage should be avoided.
+//
+//*****************************************************************************
+STDMETHODIMP
+RegMeta::ResolveTypeRef(
+ mdTypeRef tr,
+ REFIID riid,
+ IUnknown ** ppIScope,
+ mdTypeDef * ptd)
+{
+#ifdef FEATURE_METADATA_IN_VM
+ HRESULT hr;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ TypeRefRec * pTypeRefRec;
+ WCHAR wzNameSpace[_MAX_PATH];
+ CMiniMdRW * pMiniMd = NULL;
+ WCHAR rcModule[_MAX_PATH];
+
+ LOG((LOGMD, "{%08x} RegMeta::ResolveTypeRef(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
+ this, tr, riid, ppIScope, ptd));
+
+ START_MD_PERF();
+ LOCKREAD();
+
+ pMiniMd = &(m_pStgdb->m_MiniMd);
+
+ _ASSERTE((ppIScope != NULL) && (ptd != NULL));
+
+ // Init the output values.
+ *ppIScope = NULL;
+ *ptd = 0;
+
+ if (IsNilToken(tr))
+ {
+ if (ptd != NULL)
+ {
+ *ptd = mdTypeDefNil;
+ }
+
+ if (ppIScope != NULL)
+ {
+ *ppIScope = NULL;
+ }
+
+ STOP_MD_PERF(ResolveTypeRef);
+ hr = E_INVALIDARG;
+ goto ErrExit;
+ }
+
+ if (TypeFromToken(tr) == mdtTypeDef)
+ {
+ // Shortcut when we receive a TypeDef token
+ *ptd = tr;
+ STOP_MD_PERF(ResolveTypeRef);
+ hr = this->QueryInterface(riid, (void **)ppIScope);
+ goto ErrExit;
+ }
+
+ // Get the class ref row.
+ _ASSERTE(TypeFromToken(tr) == mdtTypeRef);
+
+ IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tr), &pTypeRefRec));
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, wzNameSpace, lengthof(wzNameSpace), NULL));
+ if (hr != NOERROR)
+ {
+ _ASSERTE(hr == CLDB_S_TRUNCATION);
+ // Truncate the namespace string
+ wzNameSpace[lengthof(wzNameSpace) - 1] = 0;
+ }
+
+ //***********************
+ // before we go off to CORPATH, check the loaded modules!
+ //***********************
+ if (LOADEDMODULES::ResolveTypeRefWithLoadedModules(
+ tr,
+ this,
+ pMiniMd,
+ riid,
+ ppIScope,
+ ptd) == NOERROR)
+ {
+ // Done!! We found one match among the loaded modules.
+ goto ErrExit;
+ }
+
+#ifndef FEATURE_CORECLR
+ wcscpy_s(rcModule, _MAX_PATH, wzNameSpace);
+
+ //******************
+ // Try to find the module on CORPATH
+ //******************
+
+ if ((wcsncmp(rcModule, W("System."), 16) != 0) &&
+ (wcsncmp(rcModule, W("System/"), 16) != 0))
+ {
+ // only go through regular CORPATH lookup by fully qualified class name when
+ // it is not System.*
+ hr = CORPATHService::GetClassFromCORPath(
+ rcModule,
+ tr,
+ pMiniMd,
+ riid,
+ ppIScope,
+ ptd);
+ }
+ else
+ {
+ // force it to look for System.* in mscorlib.dll
+ hr = S_FALSE;
+ }
+
+ if (hr == S_FALSE)
+ {
+ LPWSTR szTmp;
+ WszSearchPath(
+ NULL,
+ W("mscorlib.dll"),
+ NULL,
+ sizeof(rcModule) / sizeof(rcModule[0]),
+ rcModule,
+ &szTmp);
+
+ //*******************
+ // Last desperate try!!
+ //*******************
+
+ // Use the file name "mscorlib:
+ IfFailGo(CORPATHService::FindTypeDef(
+ rcModule,
+ tr,
+ pMiniMd,
+ riid,
+ ppIScope,
+ ptd));
+ if (hr == S_FALSE)
+ {
+ IfFailGo(META_E_CANNOTRESOLVETYPEREF);
+ }
+ }
+#else //FEATURE_CORECLR
+ IfFailGo(META_E_CANNOTRESOLVETYPEREF);
+#endif //FEATURE_CORECLR
+
+ErrExit:
+ STOP_MD_PERF(ResolveTypeRef);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+#else //!FEATURE_METADATA_IN_VM
+ return E_NOTIMPL;
+#endif //!FEATURE_METADATA_IN_VM
+} // RegMeta::ResolveTypeRef
+
+
+
+// Full version handles metadata caching, which Release() needs to coordinate with.
+// Thus Release() is in a satellite lib.
+ULONG RegMeta::Release()
+{
+ // This is called during cleanup. We can not fail this call by probing.
+ // As long as we make sure the cleanup does not use too much space through
+ // BEGIN_CLEANUP_ENTRYPOINT, we are OK.
+ CONTRACT_VIOLATION (SOToleranceViolation);
+ BEGIN_CLEANUP_ENTRYPOINT;
+
+#if defined(FEATURE_METADATA_IN_VM) || defined(FEATURE_METADATA_STANDALONE_WINRT)
+ _ASSERTE(!m_bCached || LOADEDMODULES::IsEntryInList(this));
+#else
+ _ASSERTE(!m_bCached);
+#endif //!FEATURE_METADATA_IN_VM && !FEATURE_METADATA_STANDALONE_WINRT
+ BOOL bCached = m_bCached;
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ // NOTE: 'this' may be unsafe after this point, if the module is cached, and
+ // another thread finds the module in the cache, releases it, and deletes it
+ // before we get around to deleting it. (That's why we must make a local copy
+ // of m_bCached.)
+ // If no references left...
+ if (cRef == 0)
+ {
+ if (!bCached)
+ { // If the module is not (was not) cached, no other thread can have
+ // discovered the module, so this thread can now safely delete it.
+ delete this;
+ }
+#if defined(FEATURE_METADATA_IN_VM) || defined(FEATURE_METADATA_STANDALONE_WINRT)
+ else if (LOADEDMODULES::RemoveModuleFromLoadedList(this))
+ { // If the module was cached, RemoveModuleFromLoadedList() will try to
+ // safely un-publish the module, and if it succeeds, no other thread
+ // has (or will) discover the module, so this thread can delete it.
+ m_bCached = false;
+ delete this;
+ }
+#endif //!FEATURE_METADATA_IN_VM && !FEATURE_METADATA_STANDALONE_WINRT
+ }
+ END_CLEANUP_ENTRYPOINT
+
+ return cRef;
+} // RegMeta::Release
diff --git a/src/md/compiler/stdafx.cpp b/src/md/compiler/stdafx.cpp
new file mode 100644
index 0000000000..ff341e19a7
--- /dev/null
+++ b/src/md/compiler/stdafx.cpp
@@ -0,0 +1,12 @@
+// 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.
+//*****************************************************************************
+// stdafx.cpp
+//
+
+//
+// Precompiled headers.
+//
+//*****************************************************************************
+#include "stdafx.h"
diff --git a/src/md/compiler/stdafx.h b/src/md/compiler/stdafx.h
new file mode 100644
index 0000000000..520fe44d05
--- /dev/null
+++ b/src/md/compiler/stdafx.h
@@ -0,0 +1,26 @@
+// 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.
+//*****************************************************************************
+// stdafx.h
+//
+
+//
+// Precompiled headers.
+//
+//*****************************************************************************
+#ifndef __STDAFX_H_
+#define __STDAFX_H_
+
+#include <crtwrap.h>
+#include <winwrap.h>
+#include <utilcode.h>
+
+#include <cor.h>
+#include <corpriv.h>
+
+#include "nsutilpriv.h"
+
+#include "utsem.h"
+
+#endif // __STDAFX_H_
diff --git a/src/md/compiler/verifylayouts.cpp b/src/md/compiler/verifylayouts.cpp
new file mode 100644
index 0000000000..bbf7b94b14
--- /dev/null
+++ b/src/md/compiler/verifylayouts.cpp
@@ -0,0 +1,14 @@
+// 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.cpp
+//
+
+//
+// Make sure that layouts of MD data structures doesn't change accidentally
+//
+//*****************************************************************************
+
+#include "stdafx.h"
+#include "verifylayouts.h"
diff --git a/src/md/compiler/wks/.gitmirror b/src/md/compiler/wks/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/md/compiler/wks/.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/compiler/wks/CMakeLists.txt b/src/md/compiler/wks/CMakeLists.txt
new file mode 100644
index 0000000000..6bf6c80868
--- /dev/null
+++ b/src/md/compiler/wks/CMakeLists.txt
@@ -0,0 +1,4 @@
+include(../../md_wks.cmake)
+
+add_precompiled_header(stdafx.h ../stdafx.cpp MDCOMPILER_SOURCES)
+add_library_clr(mdcompiler_wks ${MDCOMPILER_SOURCES}) \ No newline at end of file
diff --git a/src/md/compiler/wks/MDCompiler_wks.nativeproj b/src/md/compiler/wks/MDCompiler_wks.nativeproj
new file mode 100644
index 0000000000..8457d87c19
--- /dev/null
+++ b/src/md/compiler/wks/MDCompiler_wks.nativeproj
@@ -0,0 +1,19 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood">
+ <PropertyGroup>
+ <!-- All features are set in file:..\..\MD.props -->
+ <MetadataFlavor>wks</MetadataFlavor>
+ </PropertyGroup>
+
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\src\MD\Compiler\Compiler.settings.targets" />
+
+ <!--Leaf project Properties-->
+ <PropertyGroup>
+ <BuildCoreBinaries>true</BuildCoreBinaries>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ <OutputName>MDCompiler_wks</OutputName>
+ </PropertyGroup>
+
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" />
+</Project>