diff options
Diffstat (limited to 'src/md/runtime')
30 files changed, 9844 insertions, 0 deletions
diff --git a/src/md/runtime/.gitmirror b/src/md/runtime/.gitmirror new file mode 100644 index 0000000000..f507630f94 --- /dev/null +++ b/src/md/runtime/.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/runtime/CMakeLists.txt b/src/md/runtime/CMakeLists.txt new file mode 100644 index 0000000000..96c9b5114a --- /dev/null +++ b/src/md/runtime/CMakeLists.txt @@ -0,0 +1,23 @@ +add_definitions(-DNO_COR) + +set(MDRUNTIME_SOURCES + mdcolumndescriptors.cpp + liteweightstgdb.cpp + mdfileformat.cpp + metamodel.cpp + metamodelro.cpp + recordpool.cpp + mdinternaldisp.cpp + mdinternalro.cpp +) + +convert_to_absolute_path(MDRUNTIME_SOURCES ${MDRUNTIME_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/runtime/Runtime.settings.targets b/src/md/runtime/Runtime.settings.targets new file mode 100644 index 0000000000..1ac62d7181 --- /dev/null +++ b/src/md/runtime/Runtime.settings.targets @@ -0,0 +1,43 @@ +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <!--Import the settings--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\src\MD\MD.props" /> + + <!--Leaf project Properties--> + <PropertyGroup> + <MDRuntimeSrcDirectory>$(ClrSrcDirectory)\MD\Runtime\</MDRuntimeSrcDirectory> + <UserIncludes> + $(UserIncludes); + $(ClrSrcDirectory)\MD\inc; + $(ClrSrcDirectory)\vm; + $(ClrSrcDirectory)\strongname\inc</UserIncludes> + <ClAdditionalOptions>$(ClAdditionalOptions) -DUNICODE -D_UNICODE -DNO_COR</ClAdditionalOptions> + <OutputPath>$(ClrLibDest)</OutputPath> + <TargetType>LIBRARY</TargetType> + <PCHHeader>stdafx.h</PCHHeader> + <EnableCxxPCHHeaders>true</EnableCxxPCHHeaders> + <!--PCH: Both precompiled header and cpp are on the same ..\ path this is likely to be wrong.--> + <PCHCompile>$(MDRuntimeSrcDirectory)\stdafx.cpp</PCHCompile> + <PCHObject>stdafx_mdruntime.obj</PCHObject> + <LinkUseCMT>false</LinkUseCMT> + </PropertyGroup> + + <ItemGroup> + <ProjectReference Include="$(ClrSrcDirectory)inc\corguids.nativeproj"> + <Comment>clrinternal.h</Comment> + </ProjectReference> + </ItemGroup> + + <!--Leaf Project Items--> + <ItemGroup> + <CppCompile Include="$(MDRuntimeSrcDirectory)\MDColumnDescriptors.cpp" /> + <CppCompile Include="$(MDRuntimeSrcDirectory)\LiteWeightStgdb.cpp" /> + <CppCompile Include="$(MDRuntimeSrcDirectory)\MDFileFormat.cpp" /> + <CppCompile Include="$(MDRuntimeSrcDirectory)\MetaModel.cpp" /> + <CppCompile Include="$(MDRuntimeSrcDirectory)\MetaModelRO.cpp" /> + <CppCompile Include="$(MDRuntimeSrcDirectory)\RecordPool.cpp" /> + + <!-- These sources contain internal Read-Only API implementation (IMDInternalRO) --> + <CppCompile Include="$(MDRuntimeSrcDirectory)\MDInternalDisp.cpp" /> + <CppCompile Include="$(MDRuntimeSrcDirectory)\MDInternalRO.cpp" /> + </ItemGroup> +</Project> diff --git a/src/md/runtime/crossgen/.gitmirror b/src/md/runtime/crossgen/.gitmirror new file mode 100644 index 0000000000..f507630f94 --- /dev/null +++ b/src/md/runtime/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/runtime/crossgen/CMakeLists.txt b/src/md/runtime/crossgen/CMakeLists.txt new file mode 100644 index 0000000000..dfd0f34665 --- /dev/null +++ b/src/md/runtime/crossgen/CMakeLists.txt @@ -0,0 +1,5 @@ +include(${CLR_DIR}/crossgen.cmake) +include(../../md_wks.cmake) + +add_precompiled_header(stdafx.h ../stdafx.cpp MDRUNTIME_SOURCES) +add_library_clr(mdruntime_crossgen ${MDRUNTIME_SOURCES}) diff --git a/src/md/runtime/crossgen/MDRuntime_crossgen.nativeproj b/src/md/runtime/crossgen/MDRuntime_crossgen.nativeproj new file mode 100644 index 0000000000..6b8cc00ffc --- /dev/null +++ b/src/md/runtime/crossgen/MDRuntime_crossgen.nativeproj @@ -0,0 +1,15 @@ +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood"> + <PropertyGroup> + <BuildSysBinaries>true</BuildSysBinaries> + <!-- All features are set in file:..\..\MD.props --> + <MetadataFlavor>wks</MetadataFlavor> + <OutputName>mdruntime_crossgen</OutputName> + </PropertyGroup> + + <!--Import the settings--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\xplat\SetCrossGen.props" /> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\src\MD\Runtime\Runtime.settings.targets" /> + + <!--Import the targets--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" /> +</Project> diff --git a/src/md/runtime/dac/.gitmirror b/src/md/runtime/dac/.gitmirror new file mode 100644 index 0000000000..f507630f94 --- /dev/null +++ b/src/md/runtime/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/runtime/dac/CMakeLists.txt b/src/md/runtime/dac/CMakeLists.txt new file mode 100644 index 0000000000..337968e2ed --- /dev/null +++ b/src/md/runtime/dac/CMakeLists.txt @@ -0,0 +1,7 @@ + +include(${CLR_DIR}/dac.cmake) +include(../../md_dac.cmake) + +add_precompiled_header(stdafx.h ../stdafx.cpp MDRUNTIME_SOURCES) + +add_library_clr(mdruntime_dac ${MDRUNTIME_SOURCES})
\ No newline at end of file diff --git a/src/md/runtime/dac/dirs.proj b/src/md/runtime/dac/dirs.proj new file mode 100644 index 0000000000..cc9e7a722c --- /dev/null +++ b/src/md/runtime/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" /> + + <!--The following projects will build during PHASE 1--> + <PropertyGroup> + <BuildInPhase1>true</BuildInPhase1> + <BuildInPhaseDefault>false</BuildInPhaseDefault> + <BuildCoreBinaries>true</BuildCoreBinaries> + <BuildSysBinaries>true</BuildSysBinaries> + </PropertyGroup> + + <ItemGroup Condition="'$(BuildExePhase)' == '1'"> + <ProjectFile Include="HostLocal\mdruntime_dac.nativeproj" /> + </ItemGroup> + + <!--Import the targets--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\tools\Microsoft.DevDiv.Traversal.targets" /> +</Project> diff --git a/src/md/runtime/dbi/.gitmirror b/src/md/runtime/dbi/.gitmirror new file mode 100644 index 0000000000..f507630f94 --- /dev/null +++ b/src/md/runtime/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/runtime/dbi/CMakeLists.txt b/src/md/runtime/dbi/CMakeLists.txt new file mode 100644 index 0000000000..6f706d2bfb --- /dev/null +++ b/src/md/runtime/dbi/CMakeLists.txt @@ -0,0 +1,3 @@ +include(../../md_dbi.cmake) +add_precompiled_header(stdafx.h ../stdafx.cpp MDRUNTIME_SOURCES) +add_library_clr(mdruntime-dbi ${MDRUNTIME_SOURCES})
\ No newline at end of file diff --git a/src/md/runtime/dbi/MDRuntime-dbi.props b/src/md/runtime/dbi/MDRuntime-dbi.props new file mode 100644 index 0000000000..ce3ff3224b --- /dev/null +++ b/src/md/runtime/dbi/MDRuntime-dbi.props @@ -0,0 +1,10 @@ +<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 the settings--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\src\MD\Runtime\Runtime.settings.targets" /> + +</Project> diff --git a/src/md/runtime/dbi/dirs.proj b/src/md/runtime/dbi/dirs.proj new file mode 100644 index 0000000000..0f2f9b0613 --- /dev/null +++ b/src/md/runtime/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" /> + + <!--The following projects will build during PHASE 1--> + <PropertyGroup> + <BuildInPhase1>true</BuildInPhase1> + <BuildInPhaseDefault>false</BuildInPhaseDefault> + <BuildCoreBinaries>true</BuildCoreBinaries> + <BuildSysBinaries>true</BuildSysBinaries> + </PropertyGroup> + + <ItemGroup Condition="'$(BuildExePhase)' == '1'"> + <ProjectFile Condition="'$(FeatureDbiDebugging)'=='true'" Include="HostLocal\mdruntime-dbi.nativeproj" /> + </ItemGroup> + + <!--Import the targets--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\tools\Microsoft.DevDiv.Traversal.targets" /> +</Project> diff --git a/src/md/runtime/dirs.proj b/src/md/runtime/dirs.proj new file mode 100644 index 0000000000..2bd75ad013 --- /dev/null +++ b/src/md/runtime/dirs.proj @@ -0,0 +1,22 @@ +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <!--Import the settings--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" /> + + <!--The following projects will build during PHASE 1--> + <PropertyGroup> + <BuildInPhase1>true</BuildInPhase1> + <BuildInPhaseDefault>false</BuildInPhaseDefault> + <BuildCoreBinaries>true</BuildCoreBinaries> + <BuildSysBinaries>true</BuildSysBinaries> + </PropertyGroup> + + <ItemGroup Condition="'$(BuildExePhase)' == '1'"> + <ProjectFile Include="wks\mdruntime.nativeproj" /> + <ProjectFile Include="dbi\dirs.proj" /> + <ProjectFile Include="dac\dirs.proj" /> + <ProjectFile Include="winrt\mdruntime-winrt.nativeproj" /> + </ItemGroup> + + <!--Import the targets--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\tools\Microsoft.DevDiv.Traversal.targets" /> +</Project> diff --git a/src/md/runtime/liteweightstgdb.cpp b/src/md/runtime/liteweightstgdb.cpp new file mode 100644 index 0000000000..8e64ad16e6 --- /dev/null +++ b/src/md/runtime/liteweightstgdb.cpp @@ -0,0 +1,262 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +//***************************************************************************** +// LiteWeightStgdb.cpp +// + +// +// This contains definition of class CLiteWeightStgDB. This is light weight +// read-only implementation for accessing compressed meta data format. +// +//***************************************************************************** +#include "stdafx.h" // Precompiled header. +#include "mdfileformat.h" +#include "metamodelro.h" +#include "liteweightstgdb.h" +#include "metadatatracker.h" + +#include "../hotdata/export.h" + +__checkReturn +HRESULT _CallInitOnMemHelper(CLiteWeightStgdb<CMiniMd> *pStgdb, ULONG cbData, LPCVOID pData) +{ + return pStgdb->InitOnMem(cbData,pData); +} + +//***************************************************************************** +// Open an in-memory metadata section for read +//***************************************************************************** +template <class MiniMd> +__checkReturn +HRESULT +CLiteWeightStgdb<MiniMd>::InitOnMem( + ULONG cbData, // count of bytes in pData + LPCVOID pData) // points to meta data section in memory +{ + STORAGEHEADER sHdr; // Header for the storage. + PSTORAGESTREAM pStream; // Pointer to each stream. + int bFoundMd = false; // true when compressed data found. + int i; // Loop control. + HRESULT hr = S_OK; + ULONG cbStreamBuffer; + + // Don't double open. + _ASSERTE((m_pvMd == NULL) && (m_cbMd == 0)); + + // Validate the signature of the format, or it isn't ours. + IfFailGo(MDFormat::VerifySignature((PSTORAGESIGNATURE)pData, cbData)); + +#ifdef FEATURE_PREJIT + m_MiniMd.m_pHotTablesDirectory = NULL; +#endif //FEATURE_PREJIT + + // Remaining buffer size behind the stream header (pStream). + cbStreamBuffer = cbData; + // Get back the first stream. + pStream = MDFormat::GetFirstStream_Verify(&sHdr, pData, &cbStreamBuffer); + if (pStream == NULL) + { + Debug_ReportError("Invalid MetaData storage signature - cannot get the first stream header."); + IfFailGo(CLDB_E_FILE_CORRUPT); + } + + // Loop through each stream and pick off the ones we need. + for (i = 0; i < sHdr.GetiStreams(); i++) + { + // Do we have enough buffer to read stream header? + if (cbStreamBuffer < sizeof(*pStream)) + { + Debug_ReportError("Stream header is not within MetaData block."); + IfFailGo(CLDB_E_FILE_CORRUPT); + } + // Pick off the location and size of the data. + if (pStream->GetOffset() >= cbData) + { // Stream data are not in the buffer. Stream header is corrupted. + Debug_ReportError("Stream data are not within MetaData block."); + IfFailGo(CLDB_E_FILE_CORRUPT); + } + void *pvCurrentData = (void *)((BYTE *)pData + pStream->GetOffset()); + ULONG cbCurrentData = pStream->GetSize(); + + // Get next stream. + PSTORAGESTREAM pNext = pStream->NextStream_Verify(); + if (pNext == NULL) + { // Stream header is corrupted. + Debug_ReportError("Invalid stream header - cannot get next stream header."); + IfFailGo(CLDB_E_FILE_CORRUPT); + } + + // Range check + if ((LPBYTE)pNext > ((LPBYTE)pData + cbData)) + { + Debug_ReportError("Stream header is not within MetaData block."); + IfFailGo(CLDB_E_FILE_CORRUPT); + } + + // Stream end must fit into the buffer and we have to check integer overflow (stream start is already checked) + if ((((LPBYTE)pvCurrentData + cbCurrentData) < (LPBYTE)pvCurrentData) || + (((LPBYTE)pvCurrentData + cbCurrentData) > ((LPBYTE)pData + cbData))) + { + Debug_ReportError("Stream data are not within MetaData block."); + IfFailGo(CLDB_E_FILE_CORRUPT); + } + + // String pool. + if (strcmp(pStream->GetName(), STRING_POOL_STREAM_A) == 0) + { + METADATATRACKER_ONLY(MetaDataTracker::NoteSection(TBL_COUNT + MDPoolStrings, pvCurrentData, cbCurrentData, 1)); + // String pool has to end with a null-terminator, therefore we don't have to check string pool content on access. + // Shrink size of the pool to the last null-terminator found. + while (cbCurrentData != 0) + { + if (((LPBYTE)pvCurrentData)[cbCurrentData - 1] == 0) + { // We have found last null terminator + break; + } + // Shrink size of the pool + cbCurrentData--; + Debug_ReportError("String heap/pool does not end with null-terminator ... shrinking the heap."); + } + // Initialize string heap with null-terminated block of data + IfFailGo(m_MiniMd.m_StringHeap.Initialize( + MetaData::DataBlob((BYTE *)pvCurrentData, cbCurrentData), + FALSE)); // fCopyData + } + + // Literal String Blob pool. + else if (strcmp(pStream->GetName(), US_BLOB_POOL_STREAM_A) == 0) + { + METADATATRACKER_ONLY(MetaDataTracker::NoteSection(TBL_COUNT + MDPoolUSBlobs, pvCurrentData, cbCurrentData, 1)); + // Initialize user string heap with block of data + IfFailGo(m_MiniMd.m_UserStringHeap.Initialize( + MetaData::DataBlob((BYTE *)pvCurrentData, cbCurrentData), + FALSE)); // fCopyData + } + + // GUID pool. + else if (strcmp(pStream->GetName(), GUID_POOL_STREAM_A) == 0) + { + METADATATRACKER_ONLY(MetaDataTracker::NoteSection(TBL_COUNT + MDPoolGuids, pvCurrentData, cbCurrentData, 1)); + // Initialize guid heap with block of data + IfFailGo(m_MiniMd.m_GuidHeap.Initialize( + MetaData::DataBlob((BYTE *)pvCurrentData, cbCurrentData), + FALSE)); // fCopyData + } + + // Blob pool. + else if (strcmp(pStream->GetName(), BLOB_POOL_STREAM_A) == 0) + { + METADATATRACKER_ONLY(MetaDataTracker::NoteSection(TBL_COUNT + MDPoolBlobs, pvCurrentData, cbCurrentData, 1)); + // Initialize blob heap with block of data + IfFailGo(m_MiniMd.m_BlobHeap.Initialize( + MetaData::DataBlob((BYTE *)pvCurrentData, cbCurrentData), + FALSE)); // fCopyData + } + + // Found the compressed meta data stream. + else if (strcmp(pStream->GetName(), COMPRESSED_MODEL_STREAM_A) == 0) + { + IfFailGo( m_MiniMd.InitOnMem(pvCurrentData, cbCurrentData) ); + bFoundMd = true; + } + + // Found the hot meta data stream + else if (strcmp(pStream->GetName(), HOT_MODEL_STREAM_A) == 0) + { +#ifdef FEATURE_PREJIT + BYTE * hotStreamEnd = reinterpret_cast< BYTE * >( pvCurrentData ) + cbCurrentData; + ULONG * hotMetadataDir = reinterpret_cast< ULONG * >( hotStreamEnd ) - 2; + ULONG hotPoolsSize = *hotMetadataDir; + + m_MiniMd.m_pHotTablesDirectory = (struct MetaData::HotTablesDirectory *) + (reinterpret_cast<BYTE *>(hotMetadataDir) - hotPoolsSize - sizeof(struct MetaData::HotTablesDirectory)); + MetaData::HotTable::CheckTables(m_MiniMd.m_pHotTablesDirectory); + + DataBuffer hotMetaData( + reinterpret_cast<BYTE *>(pvCurrentData), + cbCurrentData); + IfFailGo(InitHotPools(hotMetaData)); +#else //!FEATURE_PREJIT + Debug_ReportError("MetaData hot stream is peresent, but ngen is not supported."); + // Ignore the stream +#endif //!FEATURE_PREJIT + } + // Pick off the next stream if there is one. + pStream = pNext; + cbStreamBuffer = (ULONG)((LPBYTE)pData + cbData - (LPBYTE)pNext); + } + + // If the meta data wasn't found, we can't handle this file. + if (!bFoundMd) + { + Debug_ReportError("MetaData compressed model stream #~ not found."); + IfFailGo(CLDB_E_FILE_CORRUPT); + } + else + { // Validate sensible heaps. + IfFailGo(m_MiniMd.PostInit(0)); + } + + // Save off the location. + m_pvMd = pData; + m_cbMd = cbData; + +ErrExit: + return hr; +} // CLiteWeightStgdb<MiniMd>::InitOnMem + + +template <class MiniMd> +__checkReturn +HRESULT +CLiteWeightStgdb<MiniMd>::InitHotPools( + DataBuffer hotMetaDataBuffer) +{ + HRESULT hr; + MetaData::HotMetaData hotMetaData; + MetaData::HotHeapsDirectoryIterator heapsIterator; + + IfFailRet(hotMetaData.Initialize(hotMetaDataBuffer)); + + IfFailRet(hotMetaData.GetHeapsDirectoryIterator(&heapsIterator)); + + for (;;) + { + MetaData::HotHeap hotHeap; + MetaData::HeapIndex hotHeapIndex; + + hr = heapsIterator.GetNext(&hotHeap, &hotHeapIndex); + if (hr == S_FALSE) + { // End of iteration + return S_OK; + } + + switch (hotHeapIndex.Get()) + { + case MetaData::HeapIndex::StringHeapIndex: + { + m_MiniMd.m_StringHeap.InitializeHotData(hotHeap); + break; + } + case MetaData::HeapIndex::GuidHeapIndex: + { + m_MiniMd.m_GuidHeap.InitializeHotData(hotHeap); + break; + } + case MetaData::HeapIndex::UserStringHeapIndex: + { + m_MiniMd.m_UserStringHeap.InitializeHotData(hotHeap); + break; + } + case MetaData::HeapIndex::BlobHeapIndex: + { + m_MiniMd.m_BlobHeap.InitializeHotData(hotHeap); + break; + } + default: + Debug_ReportInternalError("There's a bug in HotHeapsDirectoryIterator - it should verify the heap index."); + IfFailRet(METADATA_E_INTERNAL_ERROR); + } + } +} // CLiteWeightStgdb<MiniMd>::InitHotPools diff --git a/src/md/runtime/mdcolumndescriptors.cpp b/src/md/runtime/mdcolumndescriptors.cpp new file mode 100644 index 0000000000..dfd063ecb6 --- /dev/null +++ b/src/md/runtime/mdcolumndescriptors.cpp @@ -0,0 +1,214 @@ +// 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. + +// + +#include "stdafx.h" + +const BYTE CMiniMdBase::s_ModuleCol[] = {2, + 97,0,2, 101,2,2, 102,4,2, 102,6,2, 102,8,2, + 97,0,2, 101,2,4, 102,6,2, 102,8,2, 102,10,2, +}; +const BYTE CMiniMdBase::s_TypeRefCol[] = {2, + 75,0,2, 101,2,2, 101,4,2, + 75,0,2, 101,2,4, 101,6,4, +}; +const BYTE CMiniMdBase::s_TypeDefCol[] = {2, + 99,0,4, 101,4,2, 101,6,2, 64,8,2, 4,10,2, 6,12,2, + 99,0,4, 101,4,4, 101,8,4, 64,12,2, 4,14,2, 6,16,2, +}; +const BYTE CMiniMdBase::s_FieldPtrCol[] = {1, + 4,0,2, +}; +const BYTE CMiniMdBase::s_FieldCol[] = {3, + 97,0,2, 101,2,2, 103,4,2, + 97,0,2, 101,2,4, 103,6,4, + 97,0,2, 101,2,4, 103,6,2, +}; +const BYTE CMiniMdBase::s_MethodPtrCol[] = {1, + 6,0,2, +}; +const BYTE CMiniMdBase::s_MethodCol[] = {3, + 99,0,4, 97,4,2, 97,6,2, 101,8,2, 103,10,2, 8,12,2, + 99,0,4, 97,4,2, 97,6,2, 101,8,4, 103,12,4, 8,16,2, + 99,0,4, 97,4,2, 97,6,2, 101,8,4, 103,12,2, 8,14,2, +}; +const BYTE CMiniMdBase::s_ParamPtrCol[] = {1, + 8,0,2, +}; +const BYTE CMiniMdBase::s_ParamCol[] = {2, + 97,0,2, 97,2,2, 101,4,2, + 97,0,2, 97,2,2, 101,4,4, +}; +const BYTE CMiniMdBase::s_InterfaceImplCol[] = {1, + 2,0,2, 64,2,2, +}; +const BYTE CMiniMdBase::s_MemberRefCol[] = {3, + 69,0,2, 101,2,2, 103,4,2, + 69,0,4, 101,4,4, 103,8,4, + 69,0,2, 101,2,4, 103,6,2, +}; +const BYTE CMiniMdBase::s_ConstantCol[] = {3, + 100,0,1, 65,2,2, 103,4,2, + 100,0,1, 65,2,4, 103,6,4, + 100,0,1, 65,2,2, 103,4,4, +}; +const BYTE CMiniMdBase::s_CustomAttributeCol[] = {3, + 66,0,2, 74,2,2, 103,4,2, + 66,0,4, 74,4,4, 103,8,4, + 66,0,4, 74,4,2, 103,6,2, +}; +const BYTE CMiniMdBase::s_FieldMarshalCol[] = {2, + 67,0,2, 103,2,2, + 67,0,2, 103,2,4, +}; +const BYTE CMiniMdBase::s_DeclSecurityCol[] = {3, + 96,0,2, 68,2,2, 103,4,2, + 96,0,2, 68,2,4, 103,6,4, + 96,0,2, 68,2,2, 103,4,4, +}; +const BYTE CMiniMdBase::s_ClassLayoutCol[] = {1, + 97,0,2, 99,2,4, 2,6,2, +}; +const BYTE CMiniMdBase::s_FieldLayoutCol[] = {1, + 99,0,4, 4,4,2, +}; +const BYTE CMiniMdBase::s_StandAloneSigCol[] = {2, + 103,0,2, + 103,0,4, +}; +const BYTE CMiniMdBase::s_EventMapCol[] = {1, + 2,0,2, 20,2,2, +}; +const BYTE CMiniMdBase::s_EventPtrCol[] = {1, + 20,0,2, +}; +const BYTE CMiniMdBase::s_EventCol[] = {2, + 97,0,2, 101,2,2, 64,4,2, + 97,0,2, 101,2,4, 64,6,2, +}; +const BYTE CMiniMdBase::s_PropertyMapCol[] = {1, + 2,0,2, 23,2,2, +}; +const BYTE CMiniMdBase::s_PropertyPtrCol[] = {1, + 23,0,2, +}; +const BYTE* CMiniMdBase::s_PropertyCol = s_FieldCol; +const BYTE CMiniMdBase::s_MethodSemanticsCol[] = {1, + 97,0,2, 6,2,2, 70,4,2, +}; +const BYTE CMiniMdBase::s_MethodImplCol[] = {1, + 2,0,2, 71,2,2, 71,4,2, +}; +const BYTE CMiniMdBase::s_ModuleRefCol[] = {2, + 101,0,2, + 101,0,4, +}; +const BYTE* CMiniMdBase::s_TypeSpecCol = s_StandAloneSigCol; +const BYTE CMiniMdBase::s_ImplMapCol[] = {2, + 97,0,2, 72,2,2, 101,4,2, 26,6,2, + 97,0,2, 72,2,2, 101,4,4, 26,8,2, +}; +const BYTE* CMiniMdBase::s_FieldRVACol = s_FieldLayoutCol; +const BYTE CMiniMdBase::s_ENCLogCol[] = {1, + 99,0,4, 99,4,4, +}; +const BYTE CMiniMdBase::s_ENCMapCol[] = {1, + 99,0,4, +}; +const BYTE CMiniMdBase::s_AssemblyCol[] = {3, + 99,0,4, 97,4,2, 97,6,2, 97,8,2, 97,10,2, 99,12,4, 103,16,2, 101,18,2, 101,20,2, + 99,0,4, 97,4,2, 97,6,2, 97,8,2, 97,10,2, 99,12,4, 103,16,4, 101,20,4, 101,24,4, + 99,0,4, 97,4,2, 97,6,2, 97,8,2, 97,10,2, 99,12,4, 103,16,2, 101,18,4, 101,22,4, +}; +const BYTE* CMiniMdBase::s_AssemblyProcessorCol = s_ENCMapCol; +const BYTE CMiniMdBase::s_AssemblyOSCol[] = {1, + 99,0,4, 99,4,4, 99,8,4, +}; +const BYTE CMiniMdBase::s_AssemblyRefCol[] = {3, + 97,0,2, 97,2,2, 97,4,2, 97,6,2, 99,8,4, 103,12,2, 101,14,2, 101,16,2, 103,18,2, + 97,0,2, 97,2,2, 97,4,2, 97,6,2, 99,8,4, 103,12,4, 101,16,4, 101,20,4, 103,24,4, + 97,0,2, 97,2,2, 97,4,2, 97,6,2, 99,8,4, 103,12,2, 101,14,4, 101,18,4, 103,22,2, +}; +const BYTE CMiniMdBase::s_AssemblyRefProcessorCol[] = {1, + 99,0,4, 35,4,2, +}; +const BYTE CMiniMdBase::s_AssemblyRefOSCol[] = {1, + 99,0,4, 99,4,4, 99,8,4, 35,12,2, +}; +const BYTE CMiniMdBase::s_FileCol[] = {3, + 99,0,4, 101,4,2, 103,6,2, + 99,0,4, 101,4,4, 103,8,4, + 99,0,4, 101,4,4, 103,8,2, +}; +const BYTE CMiniMdBase::s_ExportedTypeCol[] = {2, + 99,0,4, 99,4,4, 101,8,2, 101,10,2, 73,12,2, + 99,0,4, 99,4,4, 101,8,4, 101,12,4, 73,16,2, +}; +const BYTE CMiniMdBase::s_ManifestResourceCol[] = {2, + 99,0,4, 99,4,4, 101,8,2, 73,10,2, + 99,0,4, 99,4,4, 101,8,4, 73,12,2, +}; +const BYTE CMiniMdBase::s_NestedClassCol[] = {1, + 2,0,2, 2,2,2, +}; +const BYTE CMiniMdBase::s_GenericParamCol[] = {2, + 97,0,2, 97,2,2, 76,4,2, 101,6,2, 64,8,2, 64,10,2, + 97,0,2, 97,2,2, 76,4,2, 101,6,4, 64,10,2, 64,12,2, +}; +const BYTE CMiniMdBase::s_MethodSpecCol[] = {2, + 71,0,2, 103,2,2, + 71,0,2, 103,2,4, +}; +const BYTE CMiniMdBase::s_GenericParamConstraintCol[] = {1, + 42,0,2, 64,2,2, +}; + +const BYTE* const CMiniMdBase::s_TableColumnDescriptors[] = { +s_ModuleCol, +s_TypeRefCol, +s_TypeDefCol, +s_FieldPtrCol, +s_FieldCol, +s_MethodPtrCol, +s_MethodCol, +s_ParamPtrCol, +s_ParamCol, +s_InterfaceImplCol, +s_MemberRefCol, +s_ConstantCol, +s_CustomAttributeCol, +s_FieldMarshalCol, +s_DeclSecurityCol, +s_ClassLayoutCol, +s_FieldLayoutCol, +s_StandAloneSigCol, +s_EventMapCol, +s_EventPtrCol, +s_EventCol, +s_PropertyMapCol, +s_PropertyPtrCol, +s_FieldCol, +s_MethodSemanticsCol, +s_MethodImplCol, +s_ModuleRefCol, +s_StandAloneSigCol, +s_ImplMapCol, +s_FieldLayoutCol, +s_ENCLogCol, +s_ENCMapCol, +s_AssemblyCol, +s_ENCMapCol, +s_AssemblyOSCol, +s_AssemblyRefCol, +s_AssemblyRefProcessorCol, +s_AssemblyRefOSCol, +s_FileCol, +s_ExportedTypeCol, +s_ManifestResourceCol, +s_NestedClassCol, +s_GenericParamCol, +s_MethodSpecCol, +s_GenericParamConstraintCol +}; diff --git a/src/md/runtime/mdfileformat.cpp b/src/md/runtime/mdfileformat.cpp new file mode 100644 index 0000000000..2edd2e0292 --- /dev/null +++ b/src/md/runtime/mdfileformat.cpp @@ -0,0 +1,195 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +//***************************************************************************** +// MDFileFormat.cpp +// + +// +// This file contains a set of helpers to verify and read the file format. +// This code does not handle the paging of the data, or different types of +// I/O. See the StgTiggerStorage and StgIO code for this level of support. +// +//***************************************************************************** + +#include "stdafx.h" // Standard header file. +#include "mdfileformat.h" // The format helpers. +#include "posterror.h" // Error handling code. + +//***************************************************************************** +// Verify the signature at the front of the file to see what type it is. +//***************************************************************************** +#define STORAGE_MAGIC_OLD_SIG 0x2B4D4F43 // +MOC (old version of BSJB signature code:STORAGE_MAGIC_SIG) +HRESULT +MDFormat::VerifySignature( + PSTORAGESIGNATURE pSig, // The signature to check. + ULONG cbData) +{ + HRESULT hr = S_OK; + + // If signature didn't match, you shouldn't be here. + ULONG dwSignature = pSig->GetSignature(); + if (dwSignature == STORAGE_MAGIC_OLD_SIG) + { + Debug_ReportError("Invalid MetaData storage signature - old magic signature +MOC."); + return PostError(CLDB_E_FILE_OLDVER, 1, 0); + } + if (dwSignature != STORAGE_MAGIC_SIG) + { + Debug_ReportError("Invalid MetaData storage signature - unrecognized magic signature, should be BSJB."); + return PostError(CLDB_E_FILE_CORRUPT); + } + + // Check for overflow + ULONG lVersionString = pSig->GetVersionStringLength(); + ULONG sum = sizeof(STORAGESIGNATURE) + lVersionString; + if ((sum < sizeof(STORAGESIGNATURE)) || (sum < lVersionString)) + { + Debug_ReportError("Invalid MetaData storage signature - version string too long, integer overflow."); + return PostError(CLDB_E_FILE_CORRUPT); + } + + // Check for invalid version string size + if ((sizeof(STORAGESIGNATURE) + lVersionString) > cbData) + { + Debug_ReportError("Invalid MetaData storage signature - version string too long."); + return PostError(CLDB_E_FILE_CORRUPT); + } + + // Check that the version string is null terminated. This string + // is ANSI, so no double-null checks need to be made. + { + BYTE *pStart = &pSig->pVersion[0]; + BYTE *pEnd = pStart + lVersionString + 1; // Account for terminating NULL + BYTE *pCur; + + for (pCur = pStart; pCur < pEnd; pCur++) + { + if (*pCur == 0) + break; + } + + // If we got to the end without hitting a NULL, we have a bad version string + if (pCur == pEnd) + { + Debug_ReportError("Invalid MetaData storage signature - version string has not null-terminator."); + return PostError(CLDB_E_FILE_CORRUPT); + } + } + +#if !defined(FEATURE_METADATA_STANDALONE_WINRT) + // Only a specific version of the 0.x format is supported by this code + // in order to support the NT 5 beta clients which used this format. + if (pSig->GetMajorVer() == FILE_VER_MAJOR_v0) + { + if (pSig->GetMinorVer() < FILE_VER_MINOR_v0) + { + Debug_ReportError("Invalid MetaData storage signature - unrecognized version, should be 1.1."); + hr = CLDB_E_FILE_OLDVER; + } + } + else +#endif // !defined(FEATURE_METADATA_STANDALONE_WINRT) + // There is currently no code to migrate an old format of the 1.x. This + // would be added only under special circumstances. + if ((pSig->GetMajorVer() != FILE_VER_MAJOR) || (pSig->GetMinorVer() != FILE_VER_MINOR)) + { + Debug_ReportError("Invalid MetaData storage signature - unrecognized version, should be 1.1."); + hr = CLDB_E_FILE_OLDVER; + } + + if (FAILED(hr)) + hr = PostError(hr, (int)pSig->GetMajorVer(), (int)pSig->GetMinorVer()); + return hr; +} // MDFormat::VerifySignature + +//***************************************************************************** +// Skip over the header and find the actual stream data. +// It doesn't perform any checks for buffer overflow - use GetFirstStream_Verify +// instead. +//***************************************************************************** +PSTORAGESTREAM +MDFormat::GetFirstStream( + PSTORAGEHEADER pHeader, // Return copy of header struct. + const void *pvMd) // Pointer to the full file. +{ + const BYTE *pbMd; + + // Header data starts after signature. + pbMd = (const BYTE *) pvMd; + pbMd += sizeof(STORAGESIGNATURE); + pbMd += ((STORAGESIGNATURE*)pvMd)->GetVersionStringLength(); + PSTORAGEHEADER pHdr = (PSTORAGEHEADER) pbMd; + *pHeader = *pHdr; + pbMd += sizeof(STORAGEHEADER); + + // ECMA specifies that the flags field is "reserved, must be 0". + if (pHdr->GetFlags() != 0) + return NULL; + + // The pointer is now at the first stream in the list. + return ((PSTORAGESTREAM) pbMd); +} // MDFormat::GetFirstStream + +//***************************************************************************** +// Skip over the header and find the actual stream data. Secure version of +// GetFirstStream method. +// The header is supposed to be verified by VerifySignature. +// +// Returns pointer to the first stream (behind storage header) and the size of +// the remaining buffer in *pcbMd (could be 0). +// Returns NULL if there is not enough buffer for reading the headers. The *pcbMd +// could be changed if NULL returned. +// +// Caller has to check available buffer size before using the first stream. +//***************************************************************************** +PSTORAGESTREAM +MDFormat::GetFirstStream_Verify( + PSTORAGEHEADER pHeader, // Return copy of header struct. + const void *pvMd, // Pointer to the full file. + ULONG *pcbMd) // [in, out] Size of pvMd buffer (we don't want to read behind it) +{ + const BYTE *pbMd; + + // Header data starts after signature. + pbMd = (const BYTE *)pvMd; + // Check read buffer overflow + if (*pcbMd < sizeof(STORAGESIGNATURE)) + { + Debug_ReportError("Invalid MetaData - Storage signature doesn't fit."); + return NULL; + } + pbMd += sizeof(STORAGESIGNATURE); + *pcbMd -= sizeof(STORAGESIGNATURE); + + ULONG cbVersionString = ((STORAGESIGNATURE *)pvMd)->GetVersionStringLength(); + // Check read buffer overflow + if (*pcbMd < cbVersionString) + { + Debug_ReportError("Invalid MetaData storage signature - Version string doesn't fit."); + return NULL; + } + pbMd += cbVersionString; + *pcbMd -= cbVersionString; + + // Is there enough space for storage header? + if (*pcbMd < sizeof(STORAGEHEADER)) + { + Debug_ReportError("Invalid MetaData storage header - Storage header doesn't fit."); + return NULL; + } + PSTORAGEHEADER pHdr = (PSTORAGEHEADER) pbMd; + *pHeader = *pHdr; + pbMd += sizeof(STORAGEHEADER); + *pcbMd -= sizeof(STORAGEHEADER); + + // ECMA specifies that the flags field is "reserved, must be 0". + if (pHdr->GetFlags() != 0) + { + Debug_ReportError("Invalid MetaData storage header - Flags are not 0."); + return NULL; + } + + // The pointer is now at the first stream in the list. + return (PSTORAGESTREAM)pbMd; +} // MDFormat::GetFirstStream diff --git a/src/md/runtime/mdinternaldisp.cpp b/src/md/runtime/mdinternaldisp.cpp new file mode 100644 index 0000000000..1f5725ff01 --- /dev/null +++ b/src/md/runtime/mdinternaldisp.cpp @@ -0,0 +1,1834 @@ +// 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: MDInternalDisp.CPP +// + +// Notes: +// +// +// =========================================================================== +#include "stdafx.h" +#include "mdinternaldisp.h" +#include "mdinternalro.h" +#include "posterror.h" +#include "corpriv.h" +#include "assemblymdinternaldisp.h" +#include "pedecoder.h" +#include "winmdinterfaces.h" + +#ifdef FEATURE_METADATA_INTERNAL_APIS + +// forward declaration +HRESULT GetInternalWithRWFormat( + LPVOID pData, + ULONG cbData, + DWORD flags, // [IN] MDInternal_OpenForRead or MDInternal_OpenForENC + REFIID riid, // [in] The interface desired. + void **ppIUnk); // [out] Return interface on success. + +//***************************************************************************** +// CheckFileFormat +// This function will determine if the in-memory image is a readonly, readwrite, +// or ICR format. +//***************************************************************************** +HRESULT +CheckFileFormat( + LPVOID pData, + ULONG cbData, + MDFileFormat *pFormat) // [OUT] the file format +{ + HRESULT hr = NOERROR; + STORAGEHEADER sHdr; // Header for the storage. + PSTORAGESTREAM pStream; // Pointer to each stream. + int i; + ULONG cbStreamBuffer; + + _ASSERTE(pFormat != NULL); + + *pFormat = MDFormat_Invalid; + + // Validate the signature of the format, or it isn't ours. + if (FAILED(hr = MDFormat::VerifySignature((PSTORAGESIGNATURE) pData, cbData))) + goto ErrExit; + + // Remaining buffer size behind the stream header (pStream). + cbStreamBuffer = cbData; + // Get back the first stream. + pStream = MDFormat::GetFirstStream_Verify(&sHdr, pData, &cbStreamBuffer); + if (pStream == NULL) + { + Debug_ReportError("Invalid MetaData storage signature - cannot get the first stream header."); + IfFailGo(CLDB_E_FILE_CORRUPT); + } + + // Loop through each stream and pick off the ones we need. + for (i = 0; i < sHdr.GetiStreams(); i++) + { + // Do we have enough buffer to read stream header? + if (cbStreamBuffer < sizeof(*pStream)) + { + Debug_ReportError("Stream header is not within MetaData block."); + IfFailGo(CLDB_E_FILE_CORRUPT); + } + // Get next stream. + PSTORAGESTREAM pNext = pStream->NextStream_Verify(); + + // Check that stream header is within the buffer. + if (((LPBYTE)pStream >= ((LPBYTE)pData + cbData)) || + ((LPBYTE)pNext > ((LPBYTE)pData + cbData))) + { + Debug_ReportError("Stream header is not within MetaData block."); + hr = CLDB_E_FILE_CORRUPT; + goto ErrExit; + } + + // Check that the stream data starts and fits within the buffer. + // need two checks on size because of wraparound. + if ((pStream->GetOffset() > cbData) || + (pStream->GetSize() > cbData) || + ((pStream->GetSize() + pStream->GetOffset()) < pStream->GetOffset()) || + ((pStream->GetSize() + pStream->GetOffset()) > cbData)) + { + Debug_ReportError("Stream data are not within MetaData block."); + hr = CLDB_E_FILE_CORRUPT; + goto ErrExit; + } + + // Pick off the location and size of the data. + + if (strcmp(pStream->GetName(), COMPRESSED_MODEL_STREAM_A) == 0) + { + // Validate that only one of compressed/uncompressed is present. + if (*pFormat != MDFormat_Invalid) + { // Already found a good stream. + Debug_ReportError("Compressed model stream #~ is second important stream."); + hr = CLDB_E_FILE_CORRUPT; + goto ErrExit; + } + // Found the compressed meta data stream. + *pFormat = MDFormat_ReadOnly; + } + else if (strcmp(pStream->GetName(), ENC_MODEL_STREAM_A) == 0) + { +#ifdef FEATURE_METADATA_STANDALONE_WINRT + Debug_ReportError("ENC model stream #- is not supported."); + hr = CLDB_E_FILE_CORRUPT; + goto ErrExit; +#else //!FEATURE_METADATA_STANDALONE_WINRT + // Validate that only one of compressed/uncompressed is present. + if (*pFormat != MDFormat_Invalid) + { // Already found a good stream. + Debug_ReportError("ENC model stream #- is second important stream."); + hr = CLDB_E_FILE_CORRUPT; + goto ErrExit; + } + // Found the ENC meta data stream. + *pFormat = MDFormat_ReadWrite; +#endif //!FEATURE_METADATA_STANDALONE_WINRT + } + else if (strcmp(pStream->GetName(), SCHEMA_STREAM_A) == 0) + { +#ifdef FEATURE_METADATA_STANDALONE_WINRT + Debug_ReportError("Schema stream #Schema is not supported."); + hr = CLDB_E_FILE_CORRUPT; + goto ErrExit; +#else //!FEATURE_METADATA_STANDALONE_WINRT + // Found the uncompressed format + *pFormat = MDFormat_ICR; + + // keep going. We may find the compressed format later. + // If so, we want to use the compressed format. +#endif //!FEATURE_METADATA_STANDALONE_WINRT + } + + // Pick off the next stream if there is one. + pStream = pNext; + cbStreamBuffer = (ULONG)((LPBYTE)pData + cbData - (LPBYTE)pNext); + } + + if (*pFormat == MDFormat_Invalid) + { // Didn't find a good stream. + Debug_ReportError("Cannot find MetaData stream."); + hr = CLDB_E_FILE_CORRUPT; + } + +ErrExit: + return hr; +} // CheckFileFormat + + + +//***************************************************************************** +// GetMDInternalInterface. +// This function will check the metadata section and determine if it should +// return an interface which implements ReadOnly or ReadWrite. +//***************************************************************************** +STDAPI GetMDInternalInterface( + LPVOID pData, + ULONG cbData, + DWORD flags, // [IN] ofRead or ofWrite. + REFIID riid, // [in] The interface desired. + void **ppIUnk) // [out] Return interface on success. +{ + HRESULT hr = NOERROR; + MDInternalRO *pInternalRO = NULL; + IMDCommon *pInternalROMDCommon = NULL; + MDFileFormat format; + + BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW); + + if (ppIUnk == NULL) + IfFailGo(E_INVALIDARG); + + // Determine the file format we're trying to read. + IfFailGo( CheckFileFormat(pData, cbData, &format) ); + + // Found a fully-compressed, read-only format. + if ( format == MDFormat_ReadOnly ) + { + pInternalRO = new (nothrow) MDInternalRO; + IfNullGo( pInternalRO ); + + IfFailGo( pInternalRO->Init(const_cast<void*>(pData), cbData) ); + +#ifdef FEATURE_COMINTEROP + IfFailGo(pInternalRO->QueryInterface(IID_IMDCommon, (void**)&pInternalROMDCommon)); + IfFailGo( (flags & ofNoTransform) ? S_FALSE : CheckIfWinMDAdapterNeeded(pInternalROMDCommon)); + if (hr == S_OK) + { + IfFailGo(CreateWinMDInternalImportRO(pInternalROMDCommon, riid, (void**)ppIUnk)); + } + else +#endif // FEATURE_COMINTEROP + { + IfFailGo(pInternalRO->QueryInterface(riid, ppIUnk)); + } + + } + else + { + // Found a not-fully-compressed, ENC format. + _ASSERTE( format == MDFormat_ReadWrite ); + IfFailGo( GetInternalWithRWFormat( pData, cbData, flags, riid, ppIUnk ) ); + } + +ErrExit: + + // clean up + if ( pInternalRO ) + pInternalRO->Release(); + if ( pInternalROMDCommon ) + pInternalROMDCommon->Release(); + + END_SO_INTOLERANT_CODE; + + return hr; +} // GetMDInternalInterface + + +#ifdef FEATURE_FUSION + +#ifndef DACCESS_COMPILE + +//***************************************************************************** +// GetAssemblyMDInternalImport. +// Instantiating an instance of AssemblyMDInternalImport. +// This class can support the IMetaDataAssemblyImport and some functionalities +// of IMetaDataImport on the internal import interface (IMDInternalImport). +//***************************************************************************** +STDAPI GetAssemblyMDInternalImport( // Return code. + LPCWSTR szFileName, // [in] The scope to open. + REFIID riid, // [in] The interface desired. + IUnknown **ppIUnk) // [out] Return interface on success. +{ + return GetAssemblyMDInternalImportEx(szFileName, riid, MDInternalImport_Default, ppIUnk); +} + +STDAPI GetAssemblyMDInternalImportEx( // Return code. + LPCWSTR szFileName, // [in] The scope to open. + REFIID riid, // [in] The interface desired. + MDInternalImportFlags flags, // [in] Flags to control opening the assembly + IUnknown **ppIUnk, // [out] Return interface on success. + HANDLE hFile) +{ + HRESULT hr; + + if (!szFileName || !szFileName[0] || !ppIUnk) + return E_INVALIDARG; + + // Sanity check the name. + if (wcslen(szFileName) >= _MAX_PATH) + return E_INVALIDARG; + + if (memcmp(szFileName, W("file:"), 10) == 0) + szFileName = &szFileName[5]; + + HCORMODULEHolder hModule; + DWORD dwFileLength; + + BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW); + + IfFailGoto(RuntimeOpenImageInternal(szFileName, &hModule, &dwFileLength, flags, hFile), ErrAsmExpected); + + IfFailGo(GetAssemblyMDInternalImportHelper(hModule, riid, flags, ppIUnk)); + + +ErrAsmExpected: + if(hr == COR_E_BADIMAGEFORMAT) + hr = COR_E_ASSEMBLYEXPECTED; + +ErrExit: +; + END_SO_INTOLERANT_CODE; + + return hr; +} + +HRESULT GetAssemblyMDInternalImportFromImage( + HCORMODULE hImage, + REFIID riid, + IUnknown **ppIUnk) +{ + + HRESULT hr; + + IfFailGo(GetAssemblyMDInternalImportHelper(hImage, riid, MDInternalImport_Default, ppIUnk)); + +ErrExit: + return hr; +} + +STDAPI GetAssemblyMDInternalImportByStream( // Return code. + IStream *pIStream, // [in] The IStream for the file + UINT64 AssemblyId, // [in] Unique Id for the assembly + REFIID riid, // [in] The interface desired. + IUnknown **ppIUnk) // [out] Return interface on success. +{ + return GetAssemblyMDInternalImportByStreamEx(pIStream, AssemblyId, riid, MDInternalImport_Default, ppIUnk); +} + +STDAPI GetAssemblyMDInternalImportByStreamEx( // Return code. + IStream *pIStream, // [in] The IStream for the file + UINT64 AssemblyId, // [in] Unique Id for the assembly + REFIID riid, // [in] The interface desired. + MDInternalImportFlags flags, // [in[ Flags to control opening the assembly + IUnknown **ppIUnk) // [out] Return interface on success. +{ + if (!pIStream || !ppIUnk) + return E_INVALIDARG; + + HRESULT hr; + DWORD dwFileLength; + HCORMODULEHolder hModule; + + BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW); + + IfFailGoto(RuntimeOpenImageByStream(pIStream, AssemblyId, 0, &hModule, &dwFileLength, flags), ErrAsmExpected); + + IfFailGo(GetAssemblyMDInternalImportHelper(hModule, riid, flags, ppIUnk)); + + +ErrAsmExpected: + if(hr == COR_E_BADIMAGEFORMAT) + hr = COR_E_ASSEMBLYEXPECTED; + +ErrExit: + ; + END_SO_INTOLERANT_CODE; + + return hr; +} + + +HRESULT GetAssemblyMDInternalImportHelper(HCORMODULE hModule, + REFIID riid, + MDInternalImportFlags flags, + IUnknown **ppIUnk) +{ + AssemblyMDInternalImport *pAssemblyMDInternalImport = NULL; + HRESULT hr; + LPVOID base; + PEDecoder pe; + IfFailGoto(RuntimeGetImageBase(hModule,&base,TRUE,NULL), ErrAsmExpected); + + if (base!=NULL) + IfFailGoto(pe.Init(base), ErrAsmExpected); + else + { + COUNT_T lgth; + IfFailGoto(RuntimeGetImageBase(hModule,&base,FALSE,&lgth), ErrAsmExpected); + pe.Init(base, lgth); + } + + // Both of these need to pass. + if (!pe.HasCorHeader() || !pe.CheckCorHeader()) + IfFailGo(COR_E_ASSEMBLYEXPECTED); + // Only one of these needs to. + if (!pe.CheckILFormat() && !pe.CheckNativeFormat()) + IfFailGo(COR_E_BADIMAGEFORMAT); + + COUNT_T cbMetaData; + LPCVOID pMetaData; + pMetaData = pe.GetMetadata(&cbMetaData); + + // Get the IL metadata. + IMDInternalImport *pMDInternalImport; + IfFailGo(RuntimeGetMDInternalImport(hModule, flags, &pMDInternalImport)); + if (pMDInternalImport == NULL) + IfFailGo(E_OUTOFMEMORY); + + _ASSERTE(pMDInternalImport); + pAssemblyMDInternalImport = new (nothrow) AssemblyMDInternalImport (pMDInternalImport); + if (!pAssemblyMDInternalImport) { + pMDInternalImport->Release(); + IfFailGo(E_OUTOFMEMORY); + } + + { // identify PE kind and machine type, plus the version string location + DWORD dwKind=0; + DWORD dwMachine=0; + RuntimeGetImageKind(hModule,&dwKind,&dwMachine); + pAssemblyMDInternalImport->SetPEKind(dwKind); + pAssemblyMDInternalImport->SetMachine(dwMachine); + + { + LPCSTR pString = NULL; + IfFailGo(GetImageRuntimeVersionString((PVOID)pMetaData, &pString)); + + pAssemblyMDInternalImport->SetVersionString(pString); + } + + } + + pAssemblyMDInternalImport->SetHandle(hModule); + +#ifdef FEATURE_PREJIT + // Check for zap header for INativeImageInstallInfo + // Dont do this if we are returning the IL metadata as CORCOMPILE_DEPENDENCY + // references the native image metadata, not the IL metadata. + + if (pe.HasNativeHeader() && !(flags & MDInternalImport_ILMetaData)) + { + CORCOMPILE_VERSION_INFO *pNativeVersionInfo = pe.GetNativeVersionInfo(); + + COUNT_T cDeps; + CORCOMPILE_DEPENDENCY *pDeps = pe.GetNativeDependencies(&cDeps); + + pAssemblyMDInternalImport->SetZapVersionInfo(pNativeVersionInfo, pDeps, cDeps); + } +#endif // FEATURE_PREJIT + + IfFailGo(pAssemblyMDInternalImport->QueryInterface(riid, (void**)ppIUnk)); + + return hr; + +ErrAsmExpected: + if(hr == COR_E_BADIMAGEFORMAT) + hr = COR_E_ASSEMBLYEXPECTED; + +ErrExit: + + if (pAssemblyMDInternalImport) + delete pAssemblyMDInternalImport; + + return hr; +} + +AssemblyMDInternalImport::AssemblyMDInternalImport (IMDInternalImport *pMDInternalImport) +: m_cRef(0), + m_pHandle(0), + m_pBase(NULL), +#ifdef FEATURE_PREJIT + m_pZapVersionInfo(NULL), +#endif // FEATURE_PREJIT + m_pMDInternalImport(pMDInternalImport), + m_dwPEKind(0), + m_dwMachine(0), + m_szVersionString("") +{ + _ASSERTE(m_pMDInternalImport); +} // AssemblyMDInternalImport + +AssemblyMDInternalImport::~AssemblyMDInternalImport () +{ + m_pMDInternalImport->Release(); + + if (m_pBase) + { + UnmapViewOfFile(m_pBase); + m_pBase = NULL; + CloseHandle(m_pHandle); + } + else if(m_pHandle) + { + HRESULT hr; + hr = RuntimeReleaseHandle(m_pHandle); + _ASSERTE(SUCCEEDED(hr)); + } + + m_pHandle = NULL; +} + +ULONG AssemblyMDInternalImport::AddRef() +{ + return InterlockedIncrement(&m_cRef); +} // ULONG AssemblyMDInternalImport::AddRef() + +ULONG AssemblyMDInternalImport::Release() +{ + ULONG cRef = InterlockedDecrement(&m_cRef); + if (!cRef) + { + VALIDATE_BACKOUT_STACK_CONSUMPTION; + delete this; + } + return (cRef); +} // ULONG AssemblyMDInternalImport::Release() + +HRESULT AssemblyMDInternalImport::QueryInterface(REFIID riid, void **ppUnk) +{ + *ppUnk = 0; + + if (riid == IID_IUnknown) + *ppUnk = (IUnknown *) (IMetaDataAssemblyImport *) this; + else if (riid == IID_IMetaDataAssemblyImport) + *ppUnk = (IMetaDataAssemblyImport *) this; + else if (riid == IID_IMetaDataImport) + *ppUnk = (IMetaDataImport *) this; + else if (riid == IID_IMetaDataImport2) + *ppUnk = (IMetaDataImport2 *) this; + else if (riid == IID_ISNAssemblySignature) + *ppUnk = (ISNAssemblySignature *) this; +#ifdef FEATURE_PREJIT + else if (riid == IID_IGetIMDInternalImport) + *ppUnk = (IGetIMDInternalImport *) this; + else if (riid == IID_INativeImageInstallInfo && m_pZapVersionInfo) + *ppUnk = (INativeImageInstallInfo *) this; +#endif // FEATURE_PREJIT + else + return (E_NOINTERFACE); + AddRef(); + return (S_OK); +} + + +STDMETHODIMP AssemblyMDInternalImport::GetAssemblyProps ( // S_OK or error. + mdAssembly mda, // [IN] The Assembly for which to get the properties. + const void **ppbPublicKey, // [OUT] Pointer to the public key. + ULONG *pcbPublicKey, // [OUT] Count of bytes in the public key. + ULONG *pulHashAlgId, // [OUT] Hash Algorithm. + __out_ecount (cchName) LPWSTR szName, // [OUT] Buffer to fill with name. + ULONG cchName, // [IN] Size of buffer in wide chars. + ULONG *pchName, // [OUT] Actual # of wide chars in name. + ASSEMBLYMETADATA *pMetaData, // [OUT] Assembly MetaData. + DWORD *pdwAssemblyFlags) // [OUT] Flags. +{ + HRESULT hr; + LPCSTR _szName; + AssemblyMetaDataInternal _AssemblyMetaData; + + _AssemblyMetaData.ulProcessor = 0; + _AssemblyMetaData.ulOS = 0; + + IfFailRet(m_pMDInternalImport->GetAssemblyProps( + mda, // [IN] The Assembly for which to get the properties. + ppbPublicKey, // [OUT] Pointer to the public key. + pcbPublicKey, // [OUT] Count of bytes in the public key. + pulHashAlgId, // [OUT] Hash Algorithm. + &_szName, // [OUT] Buffer to fill with name. + &_AssemblyMetaData, // [OUT] Assembly MetaData. + pdwAssemblyFlags)); // [OUT] Flags. + + if (pchName != NULL) + { + *pchName = WszMultiByteToWideChar(CP_UTF8, 0, _szName, -1, szName, cchName); + if (*pchName == 0) + { + return HRESULT_FROM_GetLastError(); + } + } + + if (pMetaData) + { + pMetaData->usMajorVersion = _AssemblyMetaData.usMajorVersion; + pMetaData->usMinorVersion = _AssemblyMetaData.usMinorVersion; + pMetaData->usBuildNumber = _AssemblyMetaData.usBuildNumber; + pMetaData->usRevisionNumber = _AssemblyMetaData.usRevisionNumber; + pMetaData->ulProcessor = 0; + pMetaData->ulOS = 0; + + pMetaData->cbLocale = WszMultiByteToWideChar(CP_UTF8, 0, _AssemblyMetaData.szLocale, -1, pMetaData->szLocale, pMetaData->cbLocale); + if (pMetaData->cbLocale == 0) + { + return HRESULT_FROM_GetLastError(); + } + } + + return S_OK; +} + +STDMETHODIMP AssemblyMDInternalImport::GetAssemblyRefProps ( // S_OK or error. + mdAssemblyRef mdar, // [IN] The AssemblyRef for which to get the properties. + const void **ppbPublicKeyOrToken, // [OUT] Pointer to the public key or token. + ULONG *pcbPublicKeyOrToken, // [OUT] Count of bytes in the public key or token. + __out_ecount (cchName) LPWSTR szName, // [OUT] Buffer to fill with name. + ULONG cchName, // [IN] Size of buffer in wide chars. + ULONG *pchName, // [OUT] Actual # of wide chars in name. + ASSEMBLYMETADATA *pMetaData, // [OUT] Assembly MetaData. + const void **ppbHashValue, // [OUT] Hash blob. + ULONG *pcbHashValue, // [OUT] Count of bytes in the hash blob. + DWORD *pdwAssemblyRefFlags) // [OUT] Flags. +{ + HRESULT hr; + LPCSTR _szName; + AssemblyMetaDataInternal _AssemblyMetaData; + + _AssemblyMetaData.ulProcessor = 0; + _AssemblyMetaData.ulOS = 0; + + IfFailRet(m_pMDInternalImport->GetAssemblyRefProps( + mdar, // [IN] The Assembly for which to get the properties. + ppbPublicKeyOrToken, // [OUT] Pointer to the public key or token. + pcbPublicKeyOrToken, // [OUT] Count of bytes in the public key or token. + &_szName, // [OUT] Buffer to fill with name. + &_AssemblyMetaData, // [OUT] Assembly MetaData. + ppbHashValue, // [OUT] Hash blob. + pcbHashValue, // [OUT] Count of bytes in the hash blob. + pdwAssemblyRefFlags)); // [OUT] Flags. + + if (pchName != NULL) + { + *pchName = WszMultiByteToWideChar(CP_UTF8, 0, _szName, -1, szName, cchName); + if (*pchName == 0) + { + return HRESULT_FROM_GetLastError(); + } + } + + pMetaData->usMajorVersion = _AssemblyMetaData.usMajorVersion; + pMetaData->usMinorVersion = _AssemblyMetaData.usMinorVersion; + pMetaData->usBuildNumber = _AssemblyMetaData.usBuildNumber; + pMetaData->usRevisionNumber = _AssemblyMetaData.usRevisionNumber; + pMetaData->ulProcessor = 0; + pMetaData->ulOS = 0; + + pMetaData->cbLocale = WszMultiByteToWideChar(CP_UTF8, 0, _AssemblyMetaData.szLocale, -1, pMetaData->szLocale, pMetaData->cbLocale); + if (pMetaData->cbLocale == 0) + { + return HRESULT_FROM_GetLastError(); + } + + return S_OK; +} + +STDMETHODIMP AssemblyMDInternalImport::GetFileProps ( // S_OK or error. + mdFile mdf, // [IN] The File for which to get the properties. + __out_ecount (cchName) LPWSTR szName, // [OUT] Buffer to fill with name. + ULONG cchName, // [IN] Size of buffer in wide chars. + ULONG *pchName, // [OUT] Actual # of wide chars in name. + const void **ppbHashValue, // [OUT] Pointer to the Hash Value Blob. + ULONG *pcbHashValue, // [OUT] Count of bytes in the Hash Value Blob. + DWORD *pdwFileFlags) // [OUT] Flags. +{ + HRESULT hr; + LPCSTR _szName; + IfFailRet(m_pMDInternalImport->GetFileProps( + mdf, + &_szName, + ppbHashValue, + pcbHashValue, + pdwFileFlags)); + + if (pchName != NULL) + { + *pchName = WszMultiByteToWideChar(CP_UTF8, 0, _szName, -1, szName, cchName); + if (*pchName == 0) + { + return HRESULT_FROM_GetLastError(); + } + } + + return S_OK; +} + +STDMETHODIMP AssemblyMDInternalImport::GetExportedTypeProps ( // S_OK or error. + mdExportedType mdct, // [IN] The ExportedType for which to get the properties. + __out_ecount (cchName) LPWSTR szName, // [OUT] Buffer to fill with name. + ULONG cchName, // [IN] Size of buffer in wide chars. + ULONG *pchName, // [OUT] Actual # of wide chars in name. + mdToken *ptkImplementation, // [OUT] mdFile or mdAssemblyRef or mdExportedType. + mdTypeDef *ptkTypeDef, // [OUT] TypeDef token within the file. + DWORD *pdwExportedTypeFlags) // [OUT] Flags. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::GetManifestResourceProps ( // S_OK or error. + mdManifestResource mdmr, // [IN] The ManifestResource for which to get the properties. + __out_ecount (cchName) LPWSTR szName, // [OUT] Buffer to fill with name. + ULONG cchName, // [IN] Size of buffer in wide chars. + ULONG *pchName, // [OUT] Actual # of wide chars in name. + mdToken *ptkImplementation, // [OUT] mdFile or mdAssemblyRef that provides the ManifestResource. + DWORD *pdwOffset, // [OUT] Offset to the beginning of the resource within the file. + DWORD *pdwResourceFlags) // [OUT] Flags. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); + HRESULT hr = NOERROR; + HENUMInternal *pEnum; + + if (*ppmdEnum == NULL) + { + // create the enumerator. + IfFailGo(HENUMInternal::CreateSimpleEnum( + mdtAssemblyRef, + 0, + 1, + &pEnum)); + + IfFailGo(m_pMDInternalImport->EnumInit(mdtAssemblyRef, 0, 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); + + return hr; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); + HRESULT hr = NOERROR; + HENUMInternal *pEnum; + + if (*ppmdEnum == NULL) + { + // create the enumerator. + IfFailGo(HENUMInternal::CreateSimpleEnum( + mdtFile, + 0, + 1, + &pEnum)); + + IfFailGo(m_pMDInternalImport->EnumInit(mdtFile, 0, 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); + return hr; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::GetAssemblyFromScope ( // S_OK or error + mdAssembly *ptkAssembly) // [OUT] Put token here. +{ + return m_pMDInternalImport->GetAssemblyFromScope (ptkAssembly); +} + +STDMETHODIMP AssemblyMDInternalImport::FindExportedTypeByName (// S_OK or error + LPCWSTR szName, // [IN] Name of the ExportedType. + mdToken mdtExportedType, // [IN] ExportedType for the enclosing class. + mdExportedType *ptkExportedType) // [OUT] Put the ExportedType token here. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::FindManifestResourceByName ( // S_OK or error + LPCWSTR szName, // [IN] Name of the ManifestResource. + mdManifestResource *ptkManifestResource) // [OUT] Put the ManifestResource token here. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +void AssemblyMDInternalImport::CloseEnum ( + HCORENUM hEnum) // Enum to be closed. +{ + HENUMInternal *pmdEnum = reinterpret_cast<HENUMInternal *> (hEnum); + + if (pmdEnum == NULL) + return; + + HENUMInternal::DestroyEnum(pmdEnum); +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::CountEnum (HCORENUM hEnum, ULONG *pulCount) +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::ResetEnum (HCORENUM hEnum, ULONG ulPos) +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::EnumTypeDefs (HCORENUM *phEnum, mdTypeDef rTypeDefs[], + ULONG cMax, ULONG *pcTypeDefs) +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::EnumInterfaceImpls (HCORENUM *phEnum, mdTypeDef td, + mdInterfaceImpl rImpls[], ULONG cMax, + ULONG* pcImpls) +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::EnumTypeRefs (HCORENUM *phEnum, mdTypeRef rTypeRefs[], + ULONG cMax, ULONG* pcTypeRefs) +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::FindTypeDefByName ( // S_OK or error. + LPCWSTR szTypeDef, // [IN] Name of the Type. + mdToken tkEnclosingClass, // [IN] TypeDef/TypeRef for Enclosing class. + mdTypeDef *ptd) // [OUT] Put the TypeDef token here. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::GetScopeProps ( // S_OK or error. + __out_ecount (cchName) LPWSTR szName, // [OUT] Put the name here. + ULONG cchName, // [IN] Size of name buffer in wide chars. + ULONG *pchName, // [OUT] Put size of name (wide chars) here. + GUID *pmvid) // [OUT, OPTIONAL] Put MVID here. +{ + HRESULT hr; + LPCSTR _szName; + + if (!m_pMDInternalImport->IsValidToken(m_pMDInternalImport->GetModuleFromScope())) + return COR_E_BADIMAGEFORMAT; + + IfFailRet(m_pMDInternalImport->GetScopeProps(&_szName, pmvid)); + + if (pchName != NULL) + { + *pchName = WszMultiByteToWideChar(CP_UTF8, 0, _szName, -1, szName, cchName); + if (*pchName == 0) + { + return HRESULT_FROM_GetLastError(); + } + } + + return S_OK; + +} + +STDMETHODIMP AssemblyMDInternalImport::GetModuleFromScope ( // S_OK. + mdModule *pmd) // [OUT] Put mdModule token here. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::GetTypeDefProps ( // S_OK or error. + mdTypeDef td, // [IN] TypeDef token for inquiry. + __out_ecount (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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::GetTypeRefProps ( // S_OK or error. + mdTypeRef tr, // [IN] TypeRef token. + mdToken *ptkResolutionScope, // [OUT] Resolution scope, ModuleRef or AssemblyRef. + __out_ecount (cchName) LPWSTR szName, // [OUT] Name of the TypeRef. + ULONG cchName, // [IN] Size of buffer. + ULONG *pchName) // [OUT] Size of Name. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::ResolveTypeRef (mdTypeRef tr, REFIID riid, IUnknown **ppIScope, mdTypeDef *ptd) +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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 +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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 +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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 +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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 +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::GetMethodProps ( + mdMethodDef mb, // The method for which to get props. + mdTypeDef *pClass, // Put method's class here. + __out_ecount (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 +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::GetMemberRefProps ( // S_OK or error. + mdMemberRef mr, // [IN] given memberref + mdToken *ptk, // [OUT] Put classref or classdef here. + __out_ecount (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 +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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 +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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 +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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 +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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 +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::GetRVA ( // S_OK or error. + mdToken tk, // Member for which to set offset + ULONG *pulCodeRVA, // The offset + DWORD *pdwImplFlags) // the implementation flags +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::GetModuleRefProps ( // S_OK or error. + mdModuleRef mur, // [IN] moduleref token. + __out_ecount (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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::GetNameFromToken ( // Not Recommended! May be removed! + mdToken tk, // [IN] Token to get name from. Must have a name. + MDUTF8CSTR *pszUtf8NamePtr) // [OUT] Return pointer to UTF8 name in heap. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::GetUserString ( // S_OK or error. + mdString stk, // [IN] String token. + __out_ecount (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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::GetPinvokeMap ( // S_OK or error. + mdToken tk, // [IN] FieldDef or MethodDef. + DWORD *pdwMappingFlags, // [OUT] Flags used for mapping. + __out_ecount (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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::GetParamForMethodIndex ( // S_OK or error. + mdMethodDef md, // [IN] Method token. + ULONG ulParamSeq, // [IN] Parameter sequence. + mdParamDef *ppd) // [IN] Put Param token here. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::FindTypeRef ( + mdToken tkResolutionScope, // [IN] ModuleRef, AssemblyRef or TypeRef. + LPCWSTR szName, // [IN] TypeRef Name. + mdTypeRef *ptr) // [OUT] matching TypeRef. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::GetMemberProps ( + mdToken mb, // The member for which to get props. + mdTypeDef *pClass, // Put member's class here. + __out_ecount (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 *pcchValue) // [OUT] size of constant string in chars, 0 for non-strings. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::GetFieldProps ( + mdFieldDef mb, // The field for which to get props. + mdTypeDef *pClass, // Put field's class here. + __out_ecount (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 *pcchValue) // [OUT] size of constant string in chars, 0 for non-strings. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::GetPropertyProps ( // S_OK, S_FALSE, or error. + mdProperty prop, // [IN] property token + mdTypeDef *pClass, // [OUT] typedef containing the property declarion. + LPCWSTR szProperty, // [OUT] Property name + ULONG cchProperty, // [IN] the count of wchar of szProperty + ULONG *pchProperty, // [OUT] actual count of wchar for property name + DWORD *pdwPropFlags, // [OUT] property flags. + PCCOR_SIGNATURE *ppvSig, // [OUT] property type. pointing to meta data internal blob + ULONG *pbSig, // [OUT] count of bytes in *ppvSig + DWORD *pdwCPlusTypeFlag, // [OUT] flag for value type. selected ELEMENT_TYPE_* + UVCP_CONSTANT *ppDefaultValue, // [OUT] constant value + ULONG *pcchDefaultValue, // [OUT] size of constant string in chars, 0 for non-strings. + mdMethodDef *pmdSetter, // [OUT] setter method of the property + mdMethodDef *pmdGetter, // [OUT] getter method of the property + mdMethodDef rmdOtherMethod[], // [OUT] other method of the property + ULONG cMax, // [IN] size of rmdOtherMethod + ULONG *pcOtherMethod) // [OUT] total number of other method of this property +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::GetParamProps ( // S_OK or error. + mdParamDef tk, // [IN]The Parameter. + mdMethodDef *pmd, // [OUT] Parent Method token. + ULONG *pulSequence, // [OUT] Parameter sequence. + __out_ecount (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 *pcchValue) // [OUT] size of constant string in chars, 0 for non-strings. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +BOOL AssemblyMDInternalImport::IsValidToken ( // True or False. + mdToken tk) // [IN] Given token. +{ + _ASSERTE(!"NYI"); + return FALSE; +} + +STDMETHODIMP AssemblyMDInternalImport::GetNestedClassProps ( // S_OK or error. + mdTypeDef tdNestedClass, // [IN] NestedClass token. + mdTypeDef *ptdEnclosingClass) // [OUT] EnclosingClass token. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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). +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::IsGlobal ( // S_OK or error. + mdToken pd, // [IN] Type, Field, or Method token. + int *pbGlobal) // [OUT] Put 1 if global, 0 otherwise. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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 +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +// *** ISNAssemblySignature methods *** + +STDMETHODIMP AssemblyMDInternalImport::GetSNAssemblySignature( + BYTE *pbSig, // [IN, OUT] Buffer to write signature + DWORD *pcbSig) // [IN, OUT] Size of buffer, bytes written +{ + return RuntimeGetAssemblyStrongNameHashForModule(m_pHandle, this, pbSig, pcbSig); +} + + +#include "strongname.h" + +#ifdef FEATURE_PREJIT +// *** IGetIMDInternalImport *** +STDMETHODIMP AssemblyMDInternalImport::GetIMDInternalImport( + IMDInternalImport ** pIMDInternalImport) +{ + m_pMDInternalImport->AddRef(); + *pIMDInternalImport = m_pMDInternalImport; + return S_OK; +} + + + +// =========================================================================== + +class CNativeImageDependency : public INativeImageDependency +{ +public: + CNativeImageDependency(CORCOMPILE_DEPENDENCY * pDependency) + : m_cRef(1), m_pDependency(pDependency) + { + } + + ~CNativeImageDependency() + { + } + + // + // IUnknown + // + + STDMETHODIMP_(ULONG) AddRef() + { + return InterlockedIncrement(&m_cRef); + } + + STDMETHODIMP_(ULONG) Release() + { + ULONG cRef = InterlockedDecrement(&m_cRef); + if (!cRef) + delete this; + return (cRef); + } + + STDMETHODIMP QueryInterface(REFIID riid, void **ppUnk) + { + *ppUnk = 0; + + if (riid == IID_IUnknown) + *ppUnk = (IUnknown *) (IMetaDataAssemblyImport *) this; + else if (riid == IID_INativeImageDependency) + *ppUnk = (INativeImageDependency *) this; + else + return (E_NOINTERFACE); + AddRef(); + return (S_OK); + } + + // + // INativeImageDependency + // + + STDMETHODIMP GetILAssemblyRef(mdAssemblyRef * pAssemblyRef) + { + BEGIN_ENTRYPOINT_NOTHROW; + + *pAssemblyRef = m_pDependency->dwAssemblyRef; + END_ENTRYPOINT_NOTHROW; + + return S_OK; + } + + STDMETHODIMP GetILAssemblyDef( + mdAssemblyRef * ppAssemblyDef, + CORCOMPILE_ASSEMBLY_SIGNATURE * pSign) + { + BEGIN_ENTRYPOINT_NOTHROW; + + *ppAssemblyDef = m_pDependency->dwAssemblyDef; + *pSign = m_pDependency->signAssemblyDef; + END_ENTRYPOINT_NOTHROW; + + return S_OK; + } + + STDMETHODIMP GetNativeAssemblyDef(CORCOMPILE_NGEN_SIGNATURE * pNativeSign) + { + BEGIN_ENTRYPOINT_NOTHROW; + + *pNativeSign = m_pDependency->signNativeImage; + END_ENTRYPOINT_NOTHROW; + + return S_OK; + } + + STDMETHODIMP GetPEKind(PEKIND *pPEKind) + { + BEGIN_ENTRYPOINT_NOTHROW; + + *pPEKind = PEKIND((m_pDependency->dependencyInfo & CORCOMPILE_DEPENDENCY_PEKIND_MASK) >> CORCOMPILE_DEPENDENCY_PEKIND_SHIFT); + END_ENTRYPOINT_NOTHROW; + + return S_OK; + } + +protected: + + LONG m_cRef; + CORCOMPILE_DEPENDENCY * m_pDependency; +}; + +// =========================================================================== +// *** INativeImageInstallInfo *** +// =========================================================================== + +STDMETHODIMP AssemblyMDInternalImport::GetSignature(CORCOMPILE_NGEN_SIGNATURE * pNgenSign) +{ + BEGIN_ENTRYPOINT_NOTHROW; + + *pNgenSign = m_pZapVersionInfo->signature; + END_ENTRYPOINT_NOTHROW; + + return S_OK; +} + +STDMETHODIMP AssemblyMDInternalImport::GetVersionInfo(CORCOMPILE_VERSION_INFO * pVersionInfo) +{ + BEGIN_ENTRYPOINT_NOTHROW; + + *pVersionInfo = *m_pZapVersionInfo; + END_ENTRYPOINT_NOTHROW; + return S_OK; +} + + + +STDMETHODIMP AssemblyMDInternalImport::GetILSignature(CORCOMPILE_ASSEMBLY_SIGNATURE * pILSign) +{ + BEGIN_ENTRYPOINT_NOTHROW; + + *pILSign = m_pZapVersionInfo->sourceAssembly; + END_ENTRYPOINT_NOTHROW; + return S_OK; +} + +STDMETHODIMP AssemblyMDInternalImport::GetConfigMask(DWORD * pConfigMask) +{ + BEGIN_ENTRYPOINT_NOTHROW; + + *pConfigMask = m_pZapVersionInfo->wConfigFlags; + END_ENTRYPOINT_NOTHROW; + + return S_OK; +} + +STDMETHODIMP AssemblyMDInternalImport::EnumDependencies ( + HCORENUM * phEnum, // [IN/OUT] - Pointer to the enum + INativeImageDependency *rDeps[], // [OUT] + ULONG cMax, // Max dependancies to enumerate in this iteration + DWORD * pdwCount // [OUT] - Number of dependancies actually enumerated + ) +{ + HRESULT hr = S_OK; + + BEGIN_ENTRYPOINT_NOTHROW; + + CORCOMPILE_DEPENDENCY * pDependenciesEnd = m_pZapDependencies + m_cZapDependencies; + + CORCOMPILE_DEPENDENCY * pNextDependency; + + // Is the enum just being initialized, or are we walking an existing one? + if ((*phEnum) == NULL) + pNextDependency = m_pZapDependencies; + else + pNextDependency = (CORCOMPILE_DEPENDENCY *)(*phEnum); + + DWORD count; + for (count = 0; + pNextDependency < pDependenciesEnd && count < cMax; + count++, pNextDependency++) + { + CNativeImageDependency * pDep = new (nothrow) CNativeImageDependency(pNextDependency); + IfNullGo( pDep ); + + rDeps[count] = pDep; + } + + *phEnum = (HCORENUM)(pNextDependency < pDependenciesEnd) ? pNextDependency : NULL; + *pdwCount = count; + +ErrExit: + END_ENTRYPOINT_NOTHROW; + + return hr; +} + + +STDMETHODIMP AssemblyMDInternalImport::GetDependency ( + const CORCOMPILE_NGEN_SIGNATURE *pcngenSign, // [IN] ngenSig of dependency you want + CORCOMPILE_DEPENDENCY *pDep // [OUT] matching dependency + ) +{ + HRESULT hr = S_OK; + + BEGIN_ENTRYPOINT_NOTHROW; + + _ASSERTE(pcngenSign != NULL); + _ASSERTE(*pcngenSign != INVALID_NGEN_SIGNATURE); + _ASSERTE(pDep != NULL); + + CORCOMPILE_DEPENDENCY * pDependenciesEnd = m_pZapDependencies + m_cZapDependencies; + CORCOMPILE_DEPENDENCY * pNextDependency = m_pZapDependencies; + while (pNextDependency != pDependenciesEnd) + { + if (pNextDependency->signNativeImage == *pcngenSign) + { + *pDep = *pNextDependency; + hr = S_OK; + goto ErrExit; + } + pNextDependency++; + } + hr = S_FALSE; + +ErrExit: + END_ENTRYPOINT_NOTHROW; + + return hr; +} + + +#endif // FEATURE_PREJIT + + +//***************************************************************************** +// IMetaDataImport2 methods +//***************************************************************************** +STDMETHODIMP AssemblyMDInternalImport::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 (cchName) LPWSTR wzname, // [OUT] Put name here + ULONG cchName, // [IN] Size of buffer + ULONG *pchName) // [OUT] Put size of name (wide chars) here. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::GetGenericParamConstraintProps( // S_OK or error. + mdGenericParamConstraint gpc, // [IN] GenericParamConstraint + mdGenericParam *ptGenericParam, // [OUT] GenericParam that is constrained + mdToken *ptkConstraintType) // [OUT] TypeDef/Ref/Spec constraint +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::EnumMethodSpecs( // S_OK or error. + 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. +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} + +STDMETHODIMP AssemblyMDInternalImport::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 = S_OK; + if(pdwPEKind) *pdwPEKind = m_dwPEKind; + if(pdwMachine) *pdwMachine = m_dwMachine; + return hr; +} + +STDMETHODIMP AssemblyMDInternalImport::GetVersionString( // S_OK or error. + __out_ecount (ccBufSize) LPWSTR pwzBuf, // Put version string here. + DWORD ccBufSize, // [in] size of the buffer, in wide chars + DWORD *pccBufSize) // [out] Size of the version string, wide chars, including terminating nul. +{ + HRESULT hr=S_OK; + DWORD L = WszMultiByteToWideChar(CP_UTF8,0,m_szVersionString,-1,pwzBuf,ccBufSize); + if(ccBufSize < L) + hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW); + + if(pccBufSize) *pccBufSize = L; + return hr; +} + +#endif //!DACCESS_COMPILE + +#endif // FEATURE_FUSION + +#endif //FEATURE_METADATA_INTERNAL_APIS diff --git a/src/md/runtime/mdinternaldisp.h b/src/md/runtime/mdinternaldisp.h new file mode 100644 index 0000000000..689e1f498e --- /dev/null +++ b/src/md/runtime/mdinternaldisp.h @@ -0,0 +1,44 @@ +// 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. +//***************************************************************************** +// MDInternalDispenser.h +// + +// +// Contains utility code for MD directory +// +//***************************************************************************** +#ifndef __MDInternalDispenser__h__ +#define __MDInternalDispenser__h__ + +#ifdef FEATURE_METADATA_INTERNAL_APIS + +#include "mdinternalro.h" + + +enum MDFileFormat +{ + MDFormat_ReadOnly = 0, + MDFormat_ReadWrite = 1, + MDFormat_ICR = 2, + MDFormat_Invalid = 3 +}; + + +HRESULT CheckFileFormat(LPVOID pData, ULONG cbData, MDFileFormat *pFormat); +STDAPI GetMDInternalInterface( + LPVOID pData, // [IN] Buffer with the metadata. + ULONG cbData, // [IN] Size of the data in the buffer. + DWORD flags, // [IN] MDInternal_OpenForRead or MDInternal_OpenForENC + REFIID riid, // [in] The interface desired. + void **ppIUnk); // [out] Return interface on success. + +HRESULT GetAssemblyMDInternalImportHelper(HCORMODULE hModule, + REFIID riid, + MDInternalImportFlags flags, + IUnknown **ppIUnk); + +#endif //FEATURE_METADATA_INTERNAL_APIS + +#endif // __MDInternalDispenser__h__ diff --git a/src/md/runtime/mdinternalro.cpp b/src/md/runtime/mdinternalro.cpp new file mode 100644 index 0000000000..d16d2b02eb --- /dev/null +++ b/src/md/runtime/mdinternalro.cpp @@ -0,0 +1,3742 @@ +// 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: MDInternalRO.CPP +// + +// Notes: +// +// +// =========================================================================== +#include "stdafx.h" +#include "mdinternalro.h" +#include "metamodelro.h" +#include "liteweightstgdb.h" +#include "corhlpr.h" +#include "../compiler/regmeta.h" +#include "caparser.h" + +#ifdef FEATURE_METADATA_INTERNAL_APIS + +__checkReturn +HRESULT _FillMDDefaultValue( + BYTE bType, + void const *pValue, + ULONG cbValue, + MDDefaultValue *pMDDefaultValue); + +#ifndef DACCESS_COMPILE +__checkReturn +HRESULT TranslateSigHelper( // S_OK or error. + IMDInternalImport *pImport, // [IN] import scope. + IMDInternalImport *pAssemImport, // [IN] import assembly scope. + const void *pbHashValue, // [IN] hash value for the import assembly. + ULONG cbHashValue, // [IN] count of bytes in the hash value. + PCCOR_SIGNATURE pbSigBlob, // [IN] signature in the importing scope + ULONG cbSigBlob, // [IN] count of bytes of signature + IMetaDataAssemblyEmit *pAssemEmit, // [IN] assembly emit scope. + IMetaDataEmit *emit, // [IN] emit interface + CQuickBytes *pqkSigEmit, // [OUT] buffer to hold translated signature + ULONG *pcbSig); // [OUT] count of bytes in the translated signature +#endif //!DACCESS_COMPILE + +__checkReturn +HRESULT GetInternalWithRWFormat( + LPVOID pData, + ULONG cbData, + DWORD flags, // [IN] MDInternal_OpenForRead or MDInternal_OpenForENC + REFIID riid, // [in] The interface desired. + void **ppIUnk); // [out] Return interface on success. + +// forward declaration +__checkReturn +HRESULT MDApplyEditAndContinue( // S_OK or error. + IMDInternalImport **ppIMD, // [in, out] The metadata to be updated. + IMDInternalImportENC *pDeltaMD); // [in] The delta metadata. + + +//***************************************************************************** +// Constructor +//***************************************************************************** +MDInternalRO::MDInternalRO() + : m_pMethodSemanticsMap(0), + m_cRefs(1) +{ +} // MDInternalRO::MDInternalRO + + + +//***************************************************************************** +// Destructor +//***************************************************************************** +MDInternalRO::~MDInternalRO() +{ + m_LiteWeightStgdb.Uninit(); + if (m_pMethodSemanticsMap) + delete[] m_pMethodSemanticsMap; + m_pMethodSemanticsMap = 0; +} // MDInternalRO::~MDInternalRO + +//***************************************************************************** +// IUnknown +//***************************************************************************** +ULONG MDInternalRO::AddRef() +{ + return InterlockedIncrement(&m_cRefs); +} // MDInternalRO::AddRef + +ULONG MDInternalRO::Release() +{ + ULONG cRef = InterlockedDecrement(&m_cRefs); + if (cRef == 0) + delete this; + return cRef; +} // MDInternalRO::Release + +__checkReturn +HRESULT MDInternalRO::QueryInterface(REFIID riid, void **ppUnk) +{ + *ppUnk = 0; + + if (riid == IID_IUnknown) + *ppUnk = this; // ! QI for IID_IUnknown must return MDInternalRO. ConvertRO2RW() has dependency on this. + else if (riid == IID_IMDInternalImport) + *ppUnk = (IMDInternalImport *)this; + else if (riid == IID_IMDCommon) + *ppUnk = (IMDCommon *)this; + else + return E_NOINTERFACE; + AddRef(); + return S_OK; +} // MDInternalRO::QueryInterface + + +//***************************************************************************** +// Initialize +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::Init( + LPVOID pData, // points to meta data section in memory + ULONG cbData) // count of bytes in pData +{ + m_tdModule = COR_GLOBAL_PARENT_TOKEN; + + extern HRESULT _CallInitOnMemHelper(CLiteWeightStgdb<CMiniMd> *pStgdb, ULONG cbData, LPCVOID pData); + + return _CallInitOnMemHelper(&m_LiteWeightStgdb, cbData, (BYTE*) pData); +} // MDInternalRO::Init + +#ifndef DACCESS_COMPILE +//***************************************************************************** +// Given a scope, determine whether imported from a typelib. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::TranslateSigWithScope( + IMDInternalImport* pAssemImport, // [IN] import assembly scope. + const void* pbHashValue, // [IN] hash value for the import assembly. + ULONG cbHashValue, // [IN] count of bytes in the hash value. + PCCOR_SIGNATURE pbSigBlob, // [IN] signature in the importing scope + ULONG cbSigBlob, // [IN] count of bytes of signature + IMetaDataAssemblyEmit* pAssemEmit, // [IN] assembly emit scope. + IMetaDataEmit* emit, // [IN] emit interface + CQuickBytes* pqkSigEmit, // [OUT] buffer to hold translated signature + ULONG* pcbSig) // [OUT] count of bytes in the translated signature +{ + return TranslateSigHelper( + this, + pAssemImport, + pbHashValue, + cbHashValue, + pbSigBlob, + cbSigBlob, + pAssemEmit, + emit, + pqkSigEmit, + pcbSig); +} // MDInternalRO::TranslateSigWithScope +#endif // DACCESS_COMPILE + +__checkReturn +HRESULT MDInternalRO::GetTypeDefRefTokenInTypeSpec(// return S_FALSE if enclosing type does not have a token + mdTypeSpec tkTypeSpec, // [IN] TypeSpec token to look at + mdToken *tkEnclosedToken) // [OUT] The enclosed type token +{ + return m_LiteWeightStgdb.m_MiniMd.GetTypeDefRefTokenInTypeSpec(tkTypeSpec, tkEnclosedToken); +} // MDInternalRO::GetTypeDefRefTokenInTypeSpec + +#ifndef DACCESS_COMPILE +//***************************************************************************** +// Given a scope, return the number of tokens in a given table +//***************************************************************************** +ULONG MDInternalRO::GetCountWithTokenKind( // return hresult + DWORD tkKind) // [IN] pass in the kind of token. +{ + ULONG ulCount = m_LiteWeightStgdb.m_MiniMd.CommonGetRowCount(tkKind); + if (tkKind == mdtTypeDef) + { + // Remove global typedef from the count of typedefs (and handle the case where there is no global typedef) + if (ulCount > 0) + ulCount--; + } + return ulCount; +} // MDInternalRO::GetCountWithTokenKind +#endif //!DACCESS_COMPILE + +//******************************************************************************* +// Enumerator helpers +//******************************************************************************* + + +//***************************************************************************** +// enumerator init for typedef +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::EnumTypeDefInit( // return hresult + HENUMInternal *phEnum) // [OUT] buffer to fill for enumerator data +{ + HRESULT hr = NOERROR; + + _ASSERTE(phEnum); + + memset(phEnum, 0, sizeof(HENUMInternal)); + phEnum->m_tkKind = mdtTypeDef; + phEnum->m_EnumType = MDSimpleEnum; + phEnum->m_ulCount = m_LiteWeightStgdb.m_MiniMd.getCountTypeDefs(); + + // Skip over the global model typedef + // + // phEnum->u.m_ulCur : the current rid that is not yet enumerated + // phEnum->u.m_ulStart : the first rid that will be returned by enumerator + // phEnum->u.m_ulEnd : the last rid that will be returned by enumerator + phEnum->u.m_ulStart = phEnum->u.m_ulCur = 2; + phEnum->u.m_ulEnd = phEnum->m_ulCount + 1; + if (phEnum->m_ulCount > 0) + phEnum->m_ulCount --; + + return hr; +} // MDInternalRO::EnumTypeDefInit + + +//***************************************************************************** +// get the number of typedef in a scope +//***************************************************************************** +ULONG MDInternalRO::EnumTypeDefGetCount( + HENUMInternal *phEnum) // [IN] the enumerator to retrieve information +{ + _ASSERTE(phEnum->m_tkKind == mdtTypeDef); + return phEnum->m_ulCount; +} // MDInternalRO::EnumTypeDefGetCount + + +//***************************************************************************** +// enumerator for typedef +//***************************************************************************** +bool MDInternalRO::EnumTypeDefNext( // return hresult + HENUMInternal *phEnum, // [IN] input enum + mdTypeDef *ptd) // [OUT] return token +{ + _ASSERTE(phEnum && ptd); + + if (phEnum->u.m_ulCur >= phEnum->u.m_ulEnd) + return false; + + *ptd = phEnum->u.m_ulCur++; + RidToToken(*ptd, mdtTypeDef); + return true; +} // MDInternalRO::EnumTypeDefNext + + +//***************************************** +// Reset the enumerator to the beginning. +//***************************************** +void MDInternalRO::EnumTypeDefReset( + HENUMInternal *phEnum) // [IN] the enumerator to be reset +{ + _ASSERTE(phEnum); + _ASSERTE( phEnum->m_EnumType == MDSimpleEnum ); + + // not using CRCURSOR + phEnum->u.m_ulCur = phEnum->u.m_ulStart; +} // MDInternalRO::EnumTypeDefReset + + +//***************************************** +// Close the enumerator. Only for read/write mode that we need to close the cursor. +// Hopefully with readonly mode, it will be a no-op +//***************************************** +void MDInternalRO::EnumTypeDefClose( + HENUMInternal *phEnum) // [IN] the enumerator to be closed +{ + _ASSERTE( phEnum->m_EnumType == MDSimpleEnum ); +} // MDInternalRO::EnumTypeDefClose + + +//***************************************************************************** +// Enumerator init for MethodImpl. The second HENUMInternal* parameter is +// only used for the R/W version of the MetaData. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::EnumMethodImplInit( // return hresult + mdTypeDef td, // [IN] TypeDef over which to scope the enumeration. + HENUMInternal *phEnumBody, // [OUT] buffer to fill for enumerator data for MethodBody tokens. + HENUMInternal *phEnumDecl) // [OUT] buffer to fill for enumerator data for MethodDecl tokens. +{ + return EnumInit(TBL_MethodImpl << 24, td, phEnumBody); +} // MDInternalRO::EnumMethodImplInit + +//***************************************************************************** +// get the number of MethodImpls in a scope +//***************************************************************************** +ULONG MDInternalRO::EnumMethodImplGetCount( + HENUMInternal *phEnumBody, // [IN] MethodBody enumerator. + HENUMInternal *phEnumDecl) // [IN] MethodDecl enumerator. +{ + _ASSERTE(phEnumBody && ((phEnumBody->m_tkKind >> 24) == TBL_MethodImpl)); + return phEnumBody->m_ulCount; +} // MDInternalRO::EnumMethodImplGetCount + + +//***************************************************************************** +// enumerator for MethodImpl. +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRO::EnumMethodImplNext( // return hresult + HENUMInternal *phEnumBody, // [IN] input enum for MethodBody + HENUMInternal *phEnumDecl, // [IN] input enum for MethodDecl + mdToken *ptkBody, // [OUT] return token for MethodBody + mdToken *ptkDecl) // [OUT] return token for MethodDecl +{ + HRESULT hr; + MethodImplRec *pRecord; + + _ASSERTE(phEnumBody && ((phEnumBody->m_tkKind >> 24) == TBL_MethodImpl)); + _ASSERTE(ptkBody && ptkDecl); + + if (phEnumBody->u.m_ulCur >= phEnumBody->u.m_ulEnd) + { + return S_FALSE; + } + + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetMethodImplRecord(phEnumBody->u.m_ulCur, &pRecord)); + *ptkBody = m_LiteWeightStgdb.m_MiniMd.getMethodBodyOfMethodImpl(pRecord); + *ptkDecl = m_LiteWeightStgdb.m_MiniMd.getMethodDeclarationOfMethodImpl(pRecord); + phEnumBody->u.m_ulCur++; + + return S_OK; +} // MDInternalRO::EnumMethodImplNext + +//***************************************** +// Reset the enumerator to the beginning. +//***************************************** +void MDInternalRO::EnumMethodImplReset( + HENUMInternal *phEnumBody, // [IN] MethodBody enumerator. + HENUMInternal *phEnumDecl) // [IN] MethodDecl enumerator. +{ + _ASSERTE(phEnumBody && ((phEnumBody->m_tkKind >> 24) == TBL_MethodImpl)); + _ASSERTE(phEnumBody->m_EnumType == MDSimpleEnum); + + phEnumBody->u.m_ulCur = phEnumBody->u.m_ulStart; +} // MDInternalRO::EnumMethodImplReset + + +//***************************************** +// Close the enumerator. +//***************************************** +void MDInternalRO::EnumMethodImplClose( + HENUMInternal *phEnumBody, // [IN] MethodBody enumerator. + HENUMInternal *phEnumDecl) // [IN] MethodDecl enumerator. +{ + _ASSERTE(phEnumBody && ((phEnumBody->m_tkKind >> 24) == TBL_MethodImpl)); + _ASSERTE(phEnumBody->m_EnumType == MDSimpleEnum); +} // MDInternalRO::EnumMethodImplClose + + +//****************************************************************************** +// enumerator for global functions +//****************************************************************************** +__checkReturn +HRESULT MDInternalRO::EnumGlobalFunctionsInit( // return hresult + HENUMInternal *phEnum) // [OUT] buffer to fill for enumerator data +{ + return EnumInit(mdtMethodDef, m_tdModule, phEnum); +} + + +//****************************************************************************** +// enumerator for global Fields +//****************************************************************************** +__checkReturn +HRESULT MDInternalRO::EnumGlobalFieldsInit( // return hresult + HENUMInternal *phEnum) // [OUT] buffer to fill for enumerator data +{ + return EnumInit(mdtFieldDef, m_tdModule, phEnum); +} + + +//***************************************** +// Enumerator initializer +//***************************************** +__checkReturn +HRESULT MDInternalRO::EnumInit( // return S_FALSE if record not found + DWORD tkKind, // [IN] which table to work on + mdToken tkParent, // [IN] token to scope the search + HENUMInternal *phEnum) // [OUT] the enumerator to fill +{ + HRESULT hr = S_OK; + ULONG ulMax = 0; + + // Vars for query. + _ASSERTE(phEnum); + HENUMInternal::ZeroEnum(phEnum); + + // cache the tkKind and the scope + phEnum->m_tkKind = TypeFromToken(tkKind); + + TypeDefRec *pRec; + + phEnum->m_EnumType = MDSimpleEnum; + + switch (TypeFromToken(tkKind)) + { + case mdtFieldDef: + IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetTypeDefRecord(RidFromToken(tkParent), &pRec)); + phEnum->u.m_ulStart = m_LiteWeightStgdb.m_MiniMd.getFieldListOfTypeDef(pRec); + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getEndFieldListOfTypeDef(RidFromToken(tkParent), &(phEnum->u.m_ulEnd))); + break; + + case mdtMethodDef: + IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetTypeDefRecord(RidFromToken(tkParent), &pRec)); + phEnum->u.m_ulStart = m_LiteWeightStgdb.m_MiniMd.getMethodListOfTypeDef(pRec); + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getEndMethodListOfTypeDef(RidFromToken(tkParent), &(phEnum->u.m_ulEnd))); + break; + + case mdtGenericParam: + _ASSERTE(TypeFromToken(tkParent) == mdtTypeDef || TypeFromToken(tkParent) == mdtMethodDef); + + if (TypeFromToken(tkParent) != mdtTypeDef && TypeFromToken(tkParent) != mdtMethodDef) + IfFailGo(CLDB_E_FILE_CORRUPT); + + if (TypeFromToken(tkParent) == mdtTypeDef) + { + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getGenericParamsForTypeDef( + RidFromToken(tkParent), + &phEnum->u.m_ulEnd, + &(phEnum->u.m_ulStart))); + } + else + { + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getGenericParamsForMethodDef( + RidFromToken(tkParent), + &phEnum->u.m_ulEnd, + &(phEnum->u.m_ulStart))); + } + break; + + case mdtGenericParamConstraint: + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getGenericParamConstraintsForGenericParam( + RidFromToken(tkParent), + &phEnum->u.m_ulEnd, + &phEnum->u.m_ulStart)); + break; + + case mdtInterfaceImpl: + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getInterfaceImplsForTypeDef(RidFromToken(tkParent), &phEnum->u.m_ulEnd, &phEnum->u.m_ulStart)); + break; + + case mdtProperty: + RID ridPropertyMap; + PropertyMapRec *pPropertyMapRec; + + // get the starting/ending rid of properties of this typedef + IfFailGo(m_LiteWeightStgdb.m_MiniMd.FindPropertyMapFor(RidFromToken(tkParent), &ridPropertyMap)); + if (!InvalidRid(ridPropertyMap)) + { + IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetPropertyMapRecord(ridPropertyMap, &pPropertyMapRec)); + phEnum->u.m_ulStart = m_LiteWeightStgdb.m_MiniMd.getPropertyListOfPropertyMap(pPropertyMapRec); + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getEndPropertyListOfPropertyMap(ridPropertyMap, &(phEnum->u.m_ulEnd))); + ulMax = m_LiteWeightStgdb.m_MiniMd.getCountPropertys() + 1; + if(phEnum->u.m_ulStart == 0) phEnum->u.m_ulStart = 1; + if(phEnum->u.m_ulEnd > ulMax) phEnum->u.m_ulEnd = ulMax; + if(phEnum->u.m_ulStart > phEnum->u.m_ulEnd) phEnum->u.m_ulStart = phEnum->u.m_ulEnd; + } + break; + + case mdtEvent: + RID ridEventMap; + EventMapRec *pEventMapRec; + + // get the starting/ending rid of events of this typedef + IfFailGo(m_LiteWeightStgdb.m_MiniMd.FindEventMapFor(RidFromToken(tkParent), &ridEventMap)); + if (!InvalidRid(ridEventMap)) + { + IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetEventMapRecord(ridEventMap, &pEventMapRec)); + phEnum->u.m_ulStart = m_LiteWeightStgdb.m_MiniMd.getEventListOfEventMap(pEventMapRec); + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getEndEventListOfEventMap(ridEventMap, &(phEnum->u.m_ulEnd))); + ulMax = m_LiteWeightStgdb.m_MiniMd.getCountEvents() + 1; + if(phEnum->u.m_ulStart == 0) phEnum->u.m_ulStart = 1; + if(phEnum->u.m_ulEnd > ulMax) phEnum->u.m_ulEnd = ulMax; + if(phEnum->u.m_ulStart > phEnum->u.m_ulEnd) phEnum->u.m_ulStart = phEnum->u.m_ulEnd; + } + break; + + case mdtParamDef: + _ASSERTE(TypeFromToken(tkParent) == mdtMethodDef); + + MethodRec *pMethodRec; + IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetMethodRecord(RidFromToken(tkParent), &pMethodRec)); + + // figure out the start rid and end rid of the parameter list of this methoddef + phEnum->u.m_ulStart = m_LiteWeightStgdb.m_MiniMd.getParamListOfMethod(pMethodRec); + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getEndParamListOfMethod(RidFromToken(tkParent), &(phEnum->u.m_ulEnd))); + break; + case mdtCustomAttribute: + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getCustomAttributeForToken(tkParent, &phEnum->u.m_ulEnd, &phEnum->u.m_ulStart)); + break; + case mdtAssemblyRef: + _ASSERTE(IsNilToken(tkParent)); + phEnum->u.m_ulStart = 1; + phEnum->u.m_ulEnd = m_LiteWeightStgdb.m_MiniMd.getCountAssemblyRefs() + 1; + break; + case mdtFile: + _ASSERTE(IsNilToken(tkParent)); + phEnum->u.m_ulStart = 1; + phEnum->u.m_ulEnd = m_LiteWeightStgdb.m_MiniMd.getCountFiles() + 1; + break; + case mdtExportedType: + _ASSERTE(IsNilToken(tkParent)); + phEnum->u.m_ulStart = 1; + phEnum->u.m_ulEnd = m_LiteWeightStgdb.m_MiniMd.getCountExportedTypes() + 1; + break; + case mdtManifestResource: + _ASSERTE(IsNilToken(tkParent)); + phEnum->u.m_ulStart = 1; + phEnum->u.m_ulEnd = m_LiteWeightStgdb.m_MiniMd.getCountManifestResources() + 1; + break; + case mdtModuleRef: + _ASSERTE(IsNilToken(tkParent)); + phEnum->u.m_ulStart = 1; + phEnum->u.m_ulEnd = m_LiteWeightStgdb.m_MiniMd.getCountModuleRefs() + 1; + break; + case (TBL_MethodImpl << 24): + _ASSERTE(! IsNilToken(tkParent)); + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getMethodImplsForClass( + RidFromToken(tkParent), + &phEnum->u.m_ulEnd, + &phEnum->u.m_ulStart)); + break; + default: + _ASSERTE(!"ENUM INIT not implemented for the compressed format!"); + IfFailGo(E_NOTIMPL); + break; + } + + // If the count is negative, the metadata is corrupted somehow. + if (phEnum->u.m_ulEnd < phEnum->u.m_ulStart) + IfFailGo(CLDB_E_FILE_CORRUPT); + + phEnum->m_ulCount = phEnum->u.m_ulEnd - phEnum->u.m_ulStart; + phEnum->u.m_ulCur = phEnum->u.m_ulStart; + +ErrExit: + // we are done + return hr; +} + + +//***************************************** +// Enumerator initializer +//***************************************** +__checkReturn +HRESULT MDInternalRO::EnumAllInit( // return S_FALSE if record not found + DWORD tkKind, // [IN] which table to work on + HENUMInternal *phEnum) // [OUT] the enumerator to fill +{ + HRESULT hr = S_OK; + + // Vars for query. + _ASSERTE(phEnum); + memset(phEnum, 0, sizeof(HENUMInternal)); + + // cache the tkKind and the scope + phEnum->m_tkKind = TypeFromToken(tkKind); + phEnum->m_EnumType = MDSimpleEnum; + + switch (TypeFromToken(tkKind)) + { + case mdtTypeRef: + phEnum->m_ulCount = m_LiteWeightStgdb.m_MiniMd.getCountTypeRefs(); + break; + + case mdtMemberRef: + phEnum->m_ulCount = m_LiteWeightStgdb.m_MiniMd.getCountMemberRefs(); + break; + + case mdtSignature: + phEnum->m_ulCount = m_LiteWeightStgdb.m_MiniMd.getCountStandAloneSigs(); + break; + + case mdtMethodDef: + phEnum->m_ulCount = m_LiteWeightStgdb.m_MiniMd.getCountMethods(); + break; + + case mdtMethodSpec: + phEnum->m_ulCount = m_LiteWeightStgdb.m_MiniMd.getCountMethodSpecs(); + break; + + case mdtFieldDef: + phEnum->m_ulCount = m_LiteWeightStgdb.m_MiniMd.getCountFields(); + break; + + case mdtTypeSpec: + phEnum->m_ulCount = m_LiteWeightStgdb.m_MiniMd.getCountTypeSpecs(); + break; + + case mdtAssemblyRef: + phEnum->m_ulCount = m_LiteWeightStgdb.m_MiniMd.getCountAssemblyRefs(); + break; + + case mdtModuleRef: + phEnum->m_ulCount = m_LiteWeightStgdb.m_MiniMd.getCountModuleRefs(); + break; + + case mdtTypeDef: + phEnum->m_ulCount = m_LiteWeightStgdb.m_MiniMd.getCountTypeDefs(); + break; + + case mdtFile: + phEnum->m_ulCount = m_LiteWeightStgdb.m_MiniMd.getCountFiles(); + break; + + default: + _ASSERTE(!"Bad token kind!"); + break; + } + phEnum->u.m_ulStart = phEnum->u.m_ulCur = 1; + phEnum->u.m_ulEnd = phEnum->m_ulCount + 1; + + // we are done + return hr; +} // MDInternalRO::EnumAllInit + + +//***************************************** +// get the count +//***************************************** +ULONG MDInternalRO::EnumGetCount( + HENUMInternal *phEnum) // [IN] the enumerator to retrieve information +{ + _ASSERTE(phEnum); + return phEnum->m_ulCount; +} + +//***************************************** +// Get next value contained in the enumerator +//***************************************** +bool MDInternalRO::EnumNext( + HENUMInternal *phEnum, // [IN] the enumerator to retrieve information + mdToken *ptk) // [OUT] token to scope the search +{ + _ASSERTE(phEnum && ptk); + if (phEnum->u.m_ulCur >= phEnum->u.m_ulEnd) + return false; + + if ( phEnum->m_EnumType == MDSimpleEnum ) + { + *ptk = phEnum->u.m_ulCur | phEnum->m_tkKind; + phEnum->u.m_ulCur++; + } + else + { + TOKENLIST *pdalist = (TOKENLIST *)&(phEnum->m_cursor); + + _ASSERTE( phEnum->m_EnumType == MDDynamicArrayEnum ); + *ptk = *( pdalist->Get(phEnum->u.m_ulCur++) ); + } + return true; +} // MDInternalRO::EnumNext + + +//***************************************** +// Reset the enumerator to the beginning. +//***************************************** +void MDInternalRO::EnumReset( + HENUMInternal *phEnum) // [IN] the enumerator to be reset +{ + _ASSERTE(phEnum); + _ASSERTE( phEnum->m_EnumType == MDSimpleEnum || phEnum->m_EnumType == MDDynamicArrayEnum); + + phEnum->u.m_ulCur = phEnum->u.m_ulStart; +} // MDInternalRO::EnumReset + + +//***************************************** +// Close the enumerator. Only for read/write mode that we need to close the cursor. +// Hopefully with readonly mode, it will be a no-op +//***************************************** +void MDInternalRO::EnumClose( + HENUMInternal *phEnum) // [IN] the enumerator to be closed +{ + _ASSERTE( phEnum->m_EnumType == MDSimpleEnum || + phEnum->m_EnumType == MDDynamicArrayEnum || + phEnum->m_EnumType == MDCustomEnum ); + if (phEnum->m_EnumType == MDDynamicArrayEnum) + HENUMInternal::ClearEnum(phEnum); +} // MDInternalRO::EnumClose + + +//--------------------------------------------------------------------------------------- +// +// Initialize enumerator of PermissionSets. +// +// Return Value: +// CLDB_E_RECORD_NOTFOUND ... If record not found. +// S_OK and empty enumeration ... If tkParent is nil token and Action is dclActionNil. +// +__checkReturn +HRESULT +MDInternalRO::EnumPermissionSetsInit( + mdToken tkParent, // [IN] Token to scope the search. + CorDeclSecurity Action, // [IN] Action to scope the search. + HENUMInternal *phEnum) // [OUT] Enumerator to fill. +{ + HRESULT hr = S_OK; + + _ASSERTE(phEnum != NULL); + HENUMInternal::ZeroEnum(phEnum); + + // cache the tkKind + phEnum->m_tkKind = mdtPermission; + + DeclSecurityRec *pDecl; + RID ridCur; + RID ridEnd; + + phEnum->m_EnumType = MDSimpleEnum; + + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getDeclSecurityForToken(tkParent, &ridEnd, &ridCur)); + if (Action != dclActionNil) + { + for (; ridCur < ridEnd; ridCur++) + { + IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetDeclSecurityRecord(ridCur, &pDecl)); + if (Action == m_LiteWeightStgdb.m_MiniMd.getActionOfDeclSecurity(pDecl)) + { + // found a match + phEnum->u.m_ulStart = phEnum->u.m_ulCur = ridCur; + phEnum->u.m_ulEnd = ridCur + 1; + phEnum->m_ulCount = 1; + goto ErrExit; + } + } + hr = CLDB_E_RECORD_NOTFOUND; + } + else + { + phEnum->u.m_ulStart = phEnum->u.m_ulCur = ridCur; + phEnum->u.m_ulEnd = ridEnd; + phEnum->m_ulCount = ridEnd - ridCur; + } + +ErrExit: + return hr; +} // MDInternalRO::EnumPermissionSetInit + + +//***************************************** +// Enumerator initializer for CustomAttributes +//***************************************** +__checkReturn +HRESULT MDInternalRO::EnumCustomAttributeByNameInit(// return S_FALSE if record not found + mdToken tkParent, // [IN] token to scope the search + LPCSTR szName, // [IN] CustomAttribute's name to scope the search + HENUMInternal *phEnum) // [OUT] the enumerator to fill +{ + return m_LiteWeightStgdb.m_MiniMd.CommonEnumCustomAttributeByName(tkParent, szName, false, phEnum); +} // MDInternalRO::EnumCustomAttributeByNameInit + +//***************************************** +// Enumerator for CustomAttributes which doesn't +// allocate any memory +//***************************************** +__checkReturn +HRESULT MDInternalRO::SafeAndSlowEnumCustomAttributeByNameInit(// return S_FALSE if record not found + mdToken tkParent, // [IN] token to scope the search + LPCSTR szName, // [IN] CustomAttribute's name to scope the search + HENUMInternal *phEnum) // [OUT] The enumerator +{ + _ASSERTE(phEnum); + + HRESULT hr; + ULONG ridStart, ridEnd; // Loop start and endpoints. + + // Get the list of custom values for the parent object. + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getCustomAttributeForToken(tkParent, &ridEnd, &ridStart)); + // If found none, done. + if (ridStart == 0) + goto NoMatch; + + phEnum->m_EnumType = MDCustomEnum; + phEnum->m_tkKind = mdtCustomAttribute; + phEnum->u.m_ulStart = ridStart; + phEnum->u.m_ulEnd = ridEnd; + phEnum->u.m_ulCur = ridStart; + + return S_OK; + +NoMatch: + return S_FALSE; +} // MDInternalRO::SafeAndSlowEnumCustomAttributeByNameInit + +__checkReturn +HRESULT MDInternalRO::SafeAndSlowEnumCustomAttributeByNameNext(// return S_FALSE if record not found + mdToken tkParent, // [IN] token to scope the search + LPCSTR szName, // [IN] CustomAttribute's name to scope the search + HENUMInternal *phEnum, // [IN] The enumerator + mdCustomAttribute *mdAttribute) // [OUT] The custom attribute that was found +{ + _ASSERTE(phEnum); + _ASSERTE(phEnum->m_EnumType == MDCustomEnum); + _ASSERTE(phEnum->m_tkKind == mdtCustomAttribute); + + // Look for one with the given name. + for (; phEnum->u.m_ulCur < phEnum->u.m_ulEnd; ++phEnum->u.m_ulCur) + { + if (S_OK == m_LiteWeightStgdb.m_MiniMd.CompareCustomAttribute( tkParent, szName, phEnum->u.m_ulCur)) + { + // If here, found a match. + *mdAttribute = TokenFromRid(phEnum->u.m_ulCur, mdtCustomAttribute); + phEnum->u.m_ulCur++; + return S_OK; + } + } + // No match... + return S_FALSE; +} // MDInternalRO::SafeAndSlowEnumCustomAttributeByNameNext + + +//***************************************** +// Nagivator helper to navigate back to the parent token given a token. +// For example, given a memberdef token, it will return the containing typedef. +// +// the mapping is as following: +// ---given child type---------parent type +// mdMethodDef mdTypeDef +// mdFieldDef mdTypeDef +// mdInterfaceImpl mdTypeDef +// mdParam mdMethodDef +// mdProperty mdTypeDef +// mdEvent mdTypeDef +// +//***************************************** +__checkReturn +HRESULT MDInternalRO::GetParentToken( + mdToken tkChild, // [IN] given child token + mdToken *ptkParent) // [OUT] returning parent +{ + HRESULT hr = NOERROR; + + _ASSERTE(ptkParent); + + switch (TypeFromToken(tkChild)) + { + case mdtTypeDef: + hr = GetNestedClassProps(tkChild, ptkParent); + // If not found, the *ptkParent has to be left unchanged! (callers depend on that) + if (hr == CLDB_E_RECORD_NOTFOUND) + { + hr = S_OK; + } + break; + + case mdtMethodDef: + IfFailRet(m_LiteWeightStgdb.m_MiniMd.FindParentOfMethod(RidFromToken(tkChild), (RID *)ptkParent)); + RidToToken(*ptkParent, mdtTypeDef); + break; + + case mdtMethodSpec: + { + MethodSpecRec *pRec; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetMethodSpecRecord(RidFromToken(tkChild), &pRec)); + *ptkParent = m_LiteWeightStgdb.m_MiniMd.getMethodOfMethodSpec(pRec); + break; + } + + case mdtFieldDef: + IfFailRet(m_LiteWeightStgdb.m_MiniMd.FindParentOfField(RidFromToken(tkChild), (RID *)ptkParent)); + RidToToken(*ptkParent, mdtTypeDef); + break; + + case mdtParamDef: + IfFailRet(m_LiteWeightStgdb.m_MiniMd.FindParentOfParam(RidFromToken(tkChild), (RID *)ptkParent)); + RidToToken(*ptkParent, mdtMethodDef); + break; + + case mdtMemberRef: + { + MemberRefRec *pRec; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetMemberRefRecord(RidFromToken(tkChild), &pRec)); + *ptkParent = m_LiteWeightStgdb.m_MiniMd.getClassOfMemberRef(pRec); + break; + } + + case mdtCustomAttribute: + { + CustomAttributeRec *pRec; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetCustomAttributeRecord(RidFromToken(tkChild), &pRec)); + *ptkParent = m_LiteWeightStgdb.m_MiniMd.getParentOfCustomAttribute(pRec); + break; + } + + case mdtEvent: + hr = m_LiteWeightStgdb.m_MiniMd.FindParentOfEventHelper(tkChild, ptkParent); + break; + + case mdtProperty: + hr = m_LiteWeightStgdb.m_MiniMd.FindParentOfPropertyHelper(tkChild, ptkParent); + break; + + default: + _ASSERTE(!"NYI: for compressed format!"); + break; + } + return hr; +} // MDInternalRO::GetParentToken + + + +//***************************************************************************** +// Get information about a CustomAttribute. +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRO::GetCustomAttributeProps( // S_OK or error. + mdCustomAttribute at, // The attribute. + mdToken *ptkType) // Put attribute type here. +{ + HRESULT hr; + _ASSERTE(TypeFromToken(at) == mdtCustomAttribute); + + // Do a linear search on compressed version as we do not want to + // depends on ICR. + // + CustomAttributeRec *pCustomAttributeRec; + + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetCustomAttributeRecord(RidFromToken(at), &pCustomAttributeRec)); + *ptkType = m_LiteWeightStgdb.m_MiniMd.getTypeOfCustomAttribute(pCustomAttributeRec); + return S_OK; +} // MDInternalRO::GetCustomAttributeProps + +//***************************************************************************** +// return custom value +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRO::GetCustomAttributeAsBlob( + mdCustomAttribute cv, // [IN] given custom attribute token + void const **ppBlob, // [OUT] return the pointer to internal blob + ULONG *pcbSize) // [OUT] return the size of the blob +{ + HRESULT hr; + _ASSERTE(ppBlob && pcbSize && TypeFromToken(cv) == mdtCustomAttribute); + + CustomAttributeRec *pCustomAttributeRec; + + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetCustomAttributeRecord(RidFromToken(cv), &pCustomAttributeRec)); + + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getValueOfCustomAttribute(pCustomAttributeRec, (const BYTE **)ppBlob, pcbSize)); + return S_OK; +} // MDInternalRO::GetCustomAttributeAsBlob + +//***************************************************************************** +// Helper function to lookup and retrieve a CustomAttribute. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetCustomAttributeByName( // S_OK or error. + mdToken tkObj, // [IN] Object with Custom Attribute. + LPCUTF8 szName, // [IN] Name of desired Custom Attribute. + __deref_out_bcount(*pcbData) const void **ppData, // [OUT] Put pointer to data here. + __out ULONG *pcbData) // [OUT] Put size of data here. +{ + return m_LiteWeightStgdb.m_MiniMd.CommonGetCustomAttributeByName(tkObj, szName, ppData, pcbData); +} // MDInternalRO::GetCustomAttributeByName + + +//***************************************************************************** +// return the name of a custom attribute +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetNameOfCustomAttribute( // S_OK or error. + mdCustomAttribute mdAttribute, // [IN] The Custom Attribute + LPCUTF8 *pszNamespace, // [OUT] Namespace of Custom Attribute. + LPCUTF8 *pszName) // [OUT] Name of Custom Attribute. +{ + _ASSERTE(TypeFromToken(mdAttribute) == mdtCustomAttribute); + + HRESULT hr = m_LiteWeightStgdb.m_MiniMd.CommonGetNameOfCustomAttribute(RidFromToken(mdAttribute), pszNamespace, pszName); + return (hr == S_FALSE) ? E_FAIL : hr; +} // MDInternalRO::GetNameOfCustomAttribute + +//***************************************************************************** +// return scope properties +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRO::GetScopeProps( + LPCSTR *pszName, // [OUT] scope name + GUID *pmvid) // [OUT] version id +{ + HRESULT hr; + + ModuleRec *pModuleRec; + + // there is only one module record + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetModuleRecord(1, &pModuleRec)); + + if (pmvid != NULL) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getMvidOfModule(pModuleRec, pmvid)); + } + if (pszName != NULL) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNameOfModule(pModuleRec, pszName)); + } + + return S_OK; +} // MDInternalRO::GetScopeProps + + +//***************************************************************************** +// Compare two signatures from the same scope. Varags signatures need to be +// preprocessed so they only contain the fixed part. +//***************************************************************************** +BOOL MDInternalRO::CompareSignatures(PCCOR_SIGNATURE pvFirstSigBlob, // First signature + DWORD cbFirstSigBlob, // + PCCOR_SIGNATURE pvSecondSigBlob, // Second signature + DWORD cbSecondSigBlob, // + void * SigArguments) // No additional arguments required +{ + if (cbFirstSigBlob != cbSecondSigBlob || memcmp(pvFirstSigBlob, pvSecondSigBlob, cbSecondSigBlob)) + return FALSE; + else + return TRUE; +} + +//***************************************************************************** +// Find a given member in a TypeDef (typically a class). +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::FindMethodDef( // S_OK or error. + mdTypeDef classdef, // The owning class of the member. + LPCSTR szName, // Name of the member in utf8. + PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of COM+ signature + ULONG cbSigBlob, // [IN] count of bytes in the signature blob + mdMethodDef *pmethoddef) // Put MemberDef token here. +{ + + return FindMethodDefUsingCompare(classdef, + szName, + pvSigBlob, + cbSigBlob, + CompareSignatures, + NULL, + pmethoddef); +} + +//***************************************************************************** +// Find a given member in a TypeDef (typically a class). +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::FindMethodDefUsingCompare( // S_OK or error. + mdTypeDef classdef, // The owning class of the member. + LPCSTR szName, // Name of the member in utf8. + PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of COM+ signature + ULONG cbSigBlob, // [IN] count of bytes in the signature blob + PSIGCOMPARE SigCompare, // [IN] Signature comparison routine + void* pSigArgs, // [IN] Additional arguments passed to signature compare + mdMethodDef *pmethoddef) // Put MemberDef token here. +{ + HRESULT hr = NOERROR; + PCCOR_SIGNATURE pvSigTemp = pvSigBlob; + CQuickBytes qbSig; + + _ASSERTE(szName && pmethoddef); + + // initialize the output parameter + *pmethoddef = mdMethodDefNil; + + // 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(pvSigBlob, cbSigBlob, &qbSig, &cbSigBlob) ); + pvSigBlob = (PCCOR_SIGNATURE) qbSig.Ptr(); + } + + // Do a linear search on compressed version + // + RID ridMax; + MethodRec *pMethodRec; + LPCUTF8 szCurMethodName; + void const *pvCurMethodSig; + ULONG cbSig; + TypeDefRec *pRec; + RID ridStart; + + // get the typedef record + IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetTypeDefRecord(RidFromToken(classdef), &pRec)); + + // get the range of methoddef rids given the classdef + ridStart = m_LiteWeightStgdb.m_MiniMd.getMethodListOfTypeDef(pRec); + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getEndMethodListOfTypeDef(RidFromToken(classdef), &ridMax)); + + // loop through each methoddef + for (; ridStart < ridMax; ridStart++) + { + IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetMethodRecord(ridStart, &pMethodRec)); + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getNameOfMethod(pMethodRec, &szCurMethodName)); + if (strcmp(szCurMethodName, szName) == 0) + { + // name match, now check the signature if specified. + if (cbSigBlob && SigCompare) + { + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getSignatureOfMethod(pMethodRec, (PCCOR_SIGNATURE *)&pvCurMethodSig, &cbSig)); + // Signature comparison is required + // Note that if pvSigBlob is vararg, we already preprocess it so that + // it only contains the fix part. Therefore, it still should be an exact + // match!!!. + // + if(SigCompare((PCCOR_SIGNATURE) pvCurMethodSig, cbSig, pvSigBlob, cbSigBlob, pSigArgs) == FALSE) + continue; + } + // Ignore PrivateScope methods. + if (IsMdPrivateScope(m_LiteWeightStgdb.m_MiniMd.getFlagsOfMethod(pMethodRec))) + continue; + // found the match + *pmethoddef = TokenFromRid(ridStart, mdtMethodDef); + goto ErrExit; + } + } + hr = CLDB_E_RECORD_NOTFOUND; + +ErrExit: + return hr; +} + +//***************************************************************************** +// Find a given param of a Method. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::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; + + _ASSERTE(TypeFromToken(md) == mdtMethodDef && pparamdef); + + // get the methoddef record + MethodRec *pMethodRec; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetMethodRecord(RidFromToken(md), &pMethodRec)); + + // figure out the start rid and end rid of the parameter list of this methoddef + ridStart = m_LiteWeightStgdb.m_MiniMd.getParamListOfMethod(pMethodRec); + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getEndParamListOfMethod(RidFromToken(md), &ridEnd)); + + // Ensure that the paramList is valid. If the count is negative, the metadata + // is corrupted somehow. Thus, return CLDB_E_FILE_CORRUPT. + if (ridEnd < ridStart) + return CLDB_E_FILE_CORRUPT; + + // loop through each param + //<TODO>@consider: parameters are sorted by sequence. Maybe a binary search? + //</TODO> + for (; ridStart < ridEnd; ridStart++) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetParamRecord(ridStart, &pParamRec)); + if (iSeq == m_LiteWeightStgdb.m_MiniMd.getSequenceOfParam(pParamRec)) + { + // parameter has the sequence number matches what we are looking for + *pparamdef = TokenFromRid(ridStart, mdtParamDef); + return S_OK; + } + } + return CLDB_E_RECORD_NOTFOUND; +} + + + +//***************************************************************************** +// return a pointer which points to meta data's internal string +// return the the type name in utf8 +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRO::GetNameOfTypeDef( // return hresult + mdTypeDef classdef, // given typedef + LPCSTR* pszname, // pointer to an internal UTF8 string + LPCSTR* psznamespace) // pointer to the namespace. +{ + HRESULT hr; + + if (pszname != NULL) + { + *pszname = NULL; + } + if (psznamespace != NULL) + { + *psznamespace = NULL; + } + + if (TypeFromToken(classdef) == mdtTypeDef) + { + TypeDefRec *pTypeDefRec; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetTypeDefRecord(RidFromToken(classdef), &pTypeDefRec)); + + if (pszname != NULL) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNameOfTypeDef(pTypeDefRec, pszname)); + } + + if (psznamespace != NULL) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNamespaceOfTypeDef(pTypeDefRec, psznamespace)); + } + return S_OK; + } + + _ASSERTE(!"Invalid argument(s) of GetNameOfTypeDef"); + return CLDB_E_INTERNALERROR; +} // MDInternalRO::GetNameOfTypeDef + + +__checkReturn +HRESULT MDInternalRO::GetIsDualOfTypeDef(// return hresult + mdTypeDef classdef, // given classdef + ULONG *pDual) // [OUT] return dual flag here. +{ + ULONG iFace=0; // Iface type. + HRESULT hr; // A result. + + hr = GetIfaceTypeOfTypeDef(classdef, &iFace); + if (hr == S_OK) + *pDual = (iFace == ifDual); + else + *pDual = 1; + + return hr; +} // MDInternalRO::GetIsDualOfTypeDef + +__checkReturn +HRESULT MDInternalRO::GetIfaceTypeOfTypeDef( + mdTypeDef classdef, // [IN] given classdef. + ULONG *pIface) // [OUT] 0=dual, 1=vtable, 2=dispinterface +{ + HRESULT hr; // A result. + const BYTE *pVal; // The custom value. + ULONG cbVal; // Size of the custom value. + ULONG ItfType = DEFAULT_COM_INTERFACE_TYPE; // Set the interface type to the default. + + // If the value is not present, the class is assumed dual. + hr = GetCustomAttributeByName(classdef, INTEROP_INTERFACETYPE_TYPE, (const void**)&pVal, &cbVal); + if (hr == S_OK) + { + CustomAttributeParser cap(pVal, cbVal); + BYTE u1; + if (SUCCEEDED(cap.SkipProlog()) && + SUCCEEDED(cap.GetU1(&u1))) + { + ItfType = u1; + } + if (ItfType >= ifLast) + ItfType = DEFAULT_COM_INTERFACE_TYPE; + } + + // Set the return value. + *pIface = ItfType; + + return hr; +} // MDInternalRO::GetIfaceTypeOfTypeDef + +//***************************************************************************** +// Given a methoddef, return a pointer to methoddef's name +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRO::GetNameOfMethodDef( + mdMethodDef md, + LPCSTR *pszMethodName) +{ + HRESULT hr; + MethodRec *pMethodRec; + *pszMethodName = NULL; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetMethodRecord(RidFromToken(md), &pMethodRec)); + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNameOfMethod(pMethodRec, pszMethodName)); + return S_OK; +} // MDInternalRO::GetNameOfMethodDef + +//***************************************************************************** +// Given a methoddef, return a pointer to methoddef's signature and methoddef's name +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRO::GetNameAndSigOfMethodDef( + mdMethodDef methoddef, // [IN] given memberdef + PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to a blob value of COM+ signature + ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob + LPCSTR *pszMethodName) +{ + HRESULT hr; + // Output parameter should not be NULL + _ASSERTE(ppvSigBlob && pcbSigBlob); + _ASSERTE(TypeFromToken(methoddef) == mdtMethodDef); + + MethodRec *pMethodRec; + *pszMethodName = NULL; + *ppvSigBlob = NULL; + *pcbSigBlob = 0; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetMethodRecord(RidFromToken(methoddef), &pMethodRec)); + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getSignatureOfMethod(pMethodRec, (PCCOR_SIGNATURE *)ppvSigBlob, pcbSigBlob)); + + return GetNameOfMethodDef(methoddef, pszMethodName); +} // MDInternalRO::GetNameAndSigOfMethodDef + +//***************************************************************************** +// Given a FieldDef, return a pointer to FieldDef's name in UTF8 +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRO::GetNameOfFieldDef( // return hresult + mdFieldDef fd, // given field + LPCSTR *pszFieldName) +{ + HRESULT hr; + FieldRec *pFieldRec; + *pszFieldName = NULL; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetFieldRecord(RidFromToken(fd), &pFieldRec)); + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNameOfField(pFieldRec, pszFieldName)); + return S_OK; +} // MDInternalRO::GetNameOfFieldDef + + +//***************************************************************************** +// Given a classdef, return the name and namespace of the typeref +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRO::GetNameOfTypeRef( // return TypeDef's name + mdTypeRef classref, // [IN] given typeref + LPCSTR *psznamespace, // [OUT] return typeref name + LPCSTR *pszname) // [OUT] return typeref namespace + +{ + _ASSERTE(TypeFromToken(classref) == mdtTypeRef); + + HRESULT hr; + TypeRefRec *pTypeRefRec; + + *psznamespace = NULL; + *pszname = NULL; + + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetTypeRefRecord(RidFromToken(classref), &pTypeRefRec)); + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNamespaceOfTypeRef(pTypeRefRec, psznamespace)); + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNameOfTypeRef(pTypeRefRec, pszname)); + return S_OK; +} + +//***************************************************************************** +// return the resolutionscope of typeref +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRO::GetResolutionScopeOfTypeRef( + mdTypeRef classref, // given classref + mdToken *ptkResolutionScope) +{ + _ASSERTE(TypeFromToken(classref) == mdtTypeRef && RidFromToken(classref)); + HRESULT hr; + + TypeRefRec *pTypeRefRec; + + *ptkResolutionScope = mdTokenNil; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetTypeRefRecord(RidFromToken(classref), &pTypeRefRec)); + *ptkResolutionScope = m_LiteWeightStgdb.m_MiniMd.getResolutionScopeOfTypeRef(pTypeRefRec); + return S_OK; +} // MDInternalRO::GetResolutionScopeOfTypeRef + +//***************************************************************************** +// Given a name, find the corresponding TypeRef. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::FindTypeRefByName( // S_OK or error. + LPCSTR szNamespace, // [IN] Namespace for the TypeRef. + LPCSTR szName, // [IN] Name of the TypeRef. + mdToken tkResolutionScope, // [IN] Resolution Scope fo the TypeRef. + mdTypeRef *ptk) // [OUT] TypeRef token returned. +{ + HRESULT hr = NOERROR; + + _ASSERTE(ptk); + + // initialize the output parameter + *ptk = mdTypeRefNil; + + // Treat no namespace as empty string. + if (!szNamespace) + szNamespace = ""; + + // Do a linear search on compressed version as we do not want to + // depends on ICR. + // + ULONG cTypeRefRecs = m_LiteWeightStgdb.m_MiniMd.getCountTypeRefs(); + TypeRefRec *pTypeRefRec; + LPCUTF8 szNamespaceTmp; + LPCUTF8 szNameTmp; + mdToken tkRes; + + for (ULONG i = 1; i <= cTypeRefRecs; i++) + { + IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetTypeRefRecord(i, &pTypeRefRec)); + tkRes = m_LiteWeightStgdb.m_MiniMd.getResolutionScopeOfTypeRef(pTypeRefRec); + + if (IsNilToken(tkRes)) + { + if (!IsNilToken(tkResolutionScope)) + continue; + } + else if (tkRes != tkResolutionScope) + continue; + + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getNamespaceOfTypeRef(pTypeRefRec, &szNamespaceTmp)); + if (strcmp(szNamespace, szNamespaceTmp)) + continue; + + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getNameOfTypeRef(pTypeRefRec, &szNameTmp)); + if (!strcmp(szNameTmp, szName)) + { + *ptk = TokenFromRid(i, mdtTypeRef); + goto ErrExit; + } + } + + // cannot find the typedef + hr = CLDB_E_RECORD_NOTFOUND; +ErrExit: + return hr; +} + +//***************************************************************************** +// return flags for a given class +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetTypeDefProps( + mdTypeDef td, // given classdef + DWORD *pdwAttr, // return flags on class + mdToken *ptkExtends) // [OUT] Put base class TypeDef/TypeRef here. +{ + HRESULT hr; + TypeDefRec *pTypeDefRec; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetTypeDefRecord(RidFromToken(td), &pTypeDefRec)); + + if (ptkExtends) + { + *ptkExtends = m_LiteWeightStgdb.m_MiniMd.getExtendsOfTypeDef(pTypeDefRec); + } + if (pdwAttr) + { + *pdwAttr = m_LiteWeightStgdb.m_MiniMd.getFlagsOfTypeDef(pTypeDefRec); + } + + return S_OK; +} + + +//***************************************************************************** +// return guid pointer to MetaData internal guid pool given a given class +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetItemGuid( // return hresult + mdToken tkObj, // given item + CLSID *pGuid) +{ + + HRESULT hr; // A result. + const BYTE *pBlob = NULL; // Blob with dispid. + ULONG cbBlob; // Length of blob. + int ix; // Loop control. + + // Get the GUID, if any. + hr = GetCustomAttributeByName(tkObj, 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)) + IfFailGo(E_INVALIDARG); + + WCHAR wzBlob[40]; // Wide char format of guid. + for (ix=1; ix<=36; ++ix) + wzBlob[ix] = pBlob[ix+2]; + wzBlob[0] = '{'; + wzBlob[37] = '}'; + wzBlob[38] = 0; + hr = IIDFromString(wzBlob, pGuid); + } + else + *pGuid = GUID_NULL; + +ErrExit: + return hr; +} // MDInternalRO::GetItemGuid + + +//***************************************************************************** +// // get enclosing class of NestedClass +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetNestedClassProps( // S_OK or error + mdTypeDef tkNestedClass, // [IN] NestedClass token. + mdTypeDef *ptkEnclosingClass) // [OUT] EnclosingClass token. +{ + HRESULT hr; + _ASSERTE(TypeFromToken(tkNestedClass) == mdtTypeDef && ptkEnclosingClass); + + RID rid; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.FindNestedClassFor(RidFromToken(tkNestedClass), &rid)); + + if (InvalidRid(rid)) + { + return CLDB_E_RECORD_NOTFOUND; + } + else + { + NestedClassRec *pRecord; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetNestedClassRecord(rid, &pRecord)); + *ptkEnclosingClass = m_LiteWeightStgdb.m_MiniMd.getEnclosingClassOfNestedClass(pRecord); + return S_OK; + } +} + +//******************************************************************************* +// Get count of Nested classes given the enclosing class. +//******************************************************************************* +__checkReturn +HRESULT +MDInternalRO::GetCountNestedClasses( // return count of Nested classes. + mdTypeDef tkEnclosingClass, // [IN]Enclosing class. + ULONG *pcNestedClassesCount) +{ + HRESULT hr; + ULONG ulCount; + ULONG ulRetCount = 0; + NestedClassRec *pRecord; + + _ASSERTE(TypeFromToken(tkEnclosingClass) == mdtTypeDef && !IsNilToken(tkEnclosingClass)); + + *pcNestedClassesCount = 0; + + ulCount = m_LiteWeightStgdb.m_MiniMd.getCountNestedClasss(); + + for (ULONG i = 1; i <= ulCount; i++) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetNestedClassRecord(i, &pRecord)); + if (tkEnclosingClass == m_LiteWeightStgdb.m_MiniMd.getEnclosingClassOfNestedClass(pRecord)) + ulRetCount++; + } + *pcNestedClassesCount = ulRetCount; + return S_OK; +} // MDInternalRO::GetCountNestedClasses + +//******************************************************************************* +// Return array of Nested classes given the enclosing class. +//******************************************************************************* +__checkReturn +HRESULT +MDInternalRO::GetNestedClasses( // Return actual count. + mdTypeDef tkEnclosingClass, // [IN] Enclosing class. + mdTypeDef *rNestedClasses, // [OUT] Array of nested class tokens. + ULONG ulNestedClasses, // [IN] Size of array. + ULONG *pcNestedClasses) +{ + HRESULT hr; + ULONG ulCount; + ULONG ulRetCount = 0; + NestedClassRec *pRecord; + + _ASSERTE(TypeFromToken(tkEnclosingClass) == mdtTypeDef && + !IsNilToken(tkEnclosingClass)); + + *pcNestedClasses = 0; + + ulCount = m_LiteWeightStgdb.m_MiniMd.getCountNestedClasss(); + + for (ULONG i = 1; i <= ulCount; i++) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetNestedClassRecord(i, &pRecord)); + if (tkEnclosingClass == m_LiteWeightStgdb.m_MiniMd.getEnclosingClassOfNestedClass(pRecord)) + { + if (ovadd_le(ulRetCount, 1, ulNestedClasses)) // ulRetCount is 0 based. + rNestedClasses[ulRetCount] = m_LiteWeightStgdb.m_MiniMd.getNestedClassOfNestedClass(pRecord); + ulRetCount++; + } + } + *pcNestedClasses = ulRetCount; + return S_OK; +} // MDInternalRO::GetNestedClasses + +//******************************************************************************* +// return the ModuleRef properties +//******************************************************************************* +__checkReturn +HRESULT MDInternalRO::GetModuleRefProps( // return hresult + mdModuleRef mur, // [IN] moduleref token + LPCSTR *pszName) // [OUT] buffer to fill with the moduleref name +{ + _ASSERTE(TypeFromToken(mur) == mdtModuleRef); + _ASSERTE(pszName); + + HRESULT hr; + + // Is it a valid token? + if (!IsValidToken(mur)) + { + *pszName = NULL; // Not every caller checks returned HRESULT, allow to fail fast in that case + return COR_E_BADIMAGEFORMAT; // Invalid Token + } + + ModuleRefRec *pModuleRefRec; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetModuleRefRecord(RidFromToken(mur), &pModuleRefRec)); + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNameOfModuleRef(pModuleRefRec, pszName)); + + return S_OK; +} + + + +//***************************************************************************** +// Given a scope and a methoddef, return a pointer to methoddef's signature +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRO::GetSigOfMethodDef( + mdMethodDef methoddef, // given a methoddef + ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob + PCCOR_SIGNATURE *ppSig) +{ + // Output parameter should not be NULL + _ASSERTE(pcbSigBlob); + _ASSERTE(TypeFromToken(methoddef) == mdtMethodDef); + + HRESULT hr; + MethodRec *pMethodRec; + *ppSig = NULL; + *pcbSigBlob = 0; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetMethodRecord(RidFromToken(methoddef), &pMethodRec)); + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getSignatureOfMethod(pMethodRec, ppSig, pcbSigBlob)); + return S_OK; +} // MDInternalRO::GetSigOfMethodDef + + +//***************************************************************************** +// Given a scope and a fielddef, return a pointer to fielddef's signature +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRO::GetSigOfFieldDef( + mdFieldDef fielddef, // given a methoddef + ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob + PCCOR_SIGNATURE *ppSig) +{ + _ASSERTE(pcbSigBlob); + _ASSERTE(TypeFromToken(fielddef) == mdtFieldDef); + + HRESULT hr; + FieldRec *pFieldRec; + *ppSig = NULL; + *pcbSigBlob = 0; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetFieldRecord(RidFromToken(fielddef), &pFieldRec)); + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getSignatureOfField(pFieldRec, ppSig, pcbSigBlob)); + return S_OK; +} // MDInternalRO::GetSigOfFieldDef + +//***************************************************************************** +// Get signature for the token (FieldDef, MethodDef, Signature, or TypeSpec). +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRO::GetSigFromToken( + mdToken tk, + ULONG * pcbSig, + PCCOR_SIGNATURE * ppSig) +{ + HRESULT hr; + + *ppSig = NULL; + *pcbSig = 0; + switch (TypeFromToken(tk)) + { + case mdtSignature: + { + StandAloneSigRec * pRec; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetStandAloneSigRecord(RidFromToken(tk), &pRec)); + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getSignatureOfStandAloneSig(pRec, ppSig, pcbSig)); + return S_OK; + } + case mdtTypeSpec: + { + TypeSpecRec * pRec; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetTypeSpecRecord(RidFromToken(tk), &pRec)); + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getSignatureOfTypeSpec(pRec, ppSig, pcbSig)); + return S_OK; + } + case mdtMethodDef: + { + IfFailRet(GetSigOfMethodDef(tk, pcbSig, ppSig)); + return S_OK; + } + case mdtFieldDef: + { + IfFailRet(GetSigOfFieldDef(tk, pcbSig, ppSig)); + return S_OK; + } + } + + // not a known token type. + *pcbSig = 0; + return META_E_INVALID_TOKEN_TYPE; +} // MDInternalRO::GetSigFromToken + + +//***************************************************************************** +// Given methoddef, return the flags +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRO::GetMethodDefProps( + mdMethodDef md, + DWORD *pdwFlags) // return mdPublic, mdAbstract, etc +{ + HRESULT hr; + MethodRec *pMethodRec; + + *pdwFlags = (DWORD)-1; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetMethodRecord(RidFromToken(md), &pMethodRec)); + *pdwFlags = m_LiteWeightStgdb.m_MiniMd.getFlagsOfMethod(pMethodRec); + + return S_OK; +} // MDInternalRO::GetMethodDefProps + +//***************************************************************************** +// Given a scope and a methoddef/methodimpl, return RVA and impl flags +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetMethodImplProps( + mdMethodDef tk, // [IN] MethodDef + ULONG *pulCodeRVA, // [OUT] CodeRVA + DWORD *pdwImplFlags) // [OUT] Impl. Flags +{ + HRESULT hr; + _ASSERTE(TypeFromToken(tk) == mdtMethodDef); + + MethodRec *pMethodRec; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetMethodRecord(RidFromToken(tk), &pMethodRec)); + + if (pulCodeRVA) + { + *pulCodeRVA = m_LiteWeightStgdb.m_MiniMd.getRVAOfMethod(pMethodRec); + } + + if (pdwImplFlags) + { + *pdwImplFlags = m_LiteWeightStgdb.m_MiniMd.getImplFlagsOfMethod(pMethodRec); + } + + return S_OK; +} // MDInternalRO::GetMethodImplProps + + +//***************************************************************************** +// return the field RVA +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetFieldRVA( + mdToken fd, // [IN] FieldDef + ULONG *pulCodeRVA) // [OUT] CodeRVA +{ + HRESULT hr; + _ASSERTE(TypeFromToken(fd) == mdtFieldDef); + _ASSERTE(pulCodeRVA); + + RID iRecord; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.FindFieldRVAFor(RidFromToken(fd), &iRecord)); + + if (InvalidRid(iRecord)) + { + if (pulCodeRVA) + *pulCodeRVA = 0; + return CLDB_E_RECORD_NOTFOUND; + } + + FieldRVARec *pFieldRVARec; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetFieldRVARecord(iRecord, &pFieldRVARec)); + + *pulCodeRVA = m_LiteWeightStgdb.m_MiniMd.getRVAOfFieldRVA(pFieldRVARec); + return NOERROR; +} + +//***************************************************************************** +// Given a fielddef, return the flags. Such as fdPublic, fdStatic, etc +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRO::GetFieldDefProps( + mdFieldDef fd, // given memberdef + DWORD *pdwFlags) // [OUT] return fdPublic, fdPrive, etc flags +{ + HRESULT hr; + _ASSERTE(TypeFromToken(fd) == mdtFieldDef); + + FieldRec *pFieldRec; + + *pdwFlags = (DWORD)-1; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetFieldRecord(RidFromToken(fd), &pFieldRec)); + *pdwFlags = m_LiteWeightStgdb.m_MiniMd.getFlagsOfField(pFieldRec); + + return S_OK; +} // MDInternalRO::GetFieldDefProps + +//***************************************************************************** +// return default value of a token(could be paramdef, fielddef, or property) +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetDefaultValue( // return hresult + mdToken tk, // [IN] given FieldDef, ParamDef, or Property + MDDefaultValue *pMDDefaultValue) // [OUT] default value +{ + _ASSERTE(pMDDefaultValue); + + HRESULT hr; + BYTE bType; + const VOID *pValue; + ULONG cbValue; + RID rid; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.FindConstantFor(RidFromToken(tk), TypeFromToken(tk), &rid)); + if (InvalidRid(rid)) + { + pMDDefaultValue->m_bType = ELEMENT_TYPE_VOID; + return S_OK; + } + ConstantRec *pConstantRec; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetConstantRecord(rid, &pConstantRec)); + + // get the type of constant value + bType = m_LiteWeightStgdb.m_MiniMd.getTypeOfConstant(pConstantRec); + + // get the value blob + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getValueOfConstant(pConstantRec, reinterpret_cast<const BYTE **>(&pValue), &cbValue)); + // convert it to our internal default value representation + hr = _FillMDDefaultValue(bType, pValue, cbValue, pMDDefaultValue); + return hr; +} // MDInternalRO::GetDefaultValue + +//***************************************************************************** +// Given a scope and a methoddef/fielddef, return the dispid +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetDispIdOfMemberDef( // return hresult + mdToken tk, // given methoddef or fielddef + ULONG *pDispid) // Put the dispid here. +{ +#ifdef FEATURE_COMINTEROP + HRESULT hr; // A result. + const BYTE *pBlob; // Blob with dispid. + ULONG cbBlob; // Length of blob. + UINT32 dispid; // temporary for dispid. + + // Get the DISPID, if any. + _ASSERTE(pDispid); + + *pDispid = DISPID_UNKNOWN; + hr = GetCustomAttributeByName(tk, INTEROP_DISPID_TYPE, (const void**)&pBlob, &cbBlob); + if (hr == S_OK) + { + CustomAttributeParser cap(pBlob, cbBlob); + IfFailGo(cap.SkipProlog()); + IfFailGo(cap.GetU4(&dispid)); + *pDispid = dispid; + } + +ErrExit: + return hr; +#else // FEATURE_COMINTEROP + _ASSERTE(false); + return E_NOTIMPL; +#endif // FEATURE_COMINTEROP +} // MDInternalRO::GetDispIdOfMemberDef + +//***************************************************************************** +// Given interfaceimpl, return the TypeRef/TypeDef and flags +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRO::GetTypeOfInterfaceImpl( // return hresult + mdInterfaceImpl iiImpl, // given a interfaceimpl + mdToken *ptkType) +{ + HRESULT hr; + _ASSERTE(TypeFromToken(iiImpl) == mdtInterfaceImpl); + + *ptkType = mdTypeDefNil; + + InterfaceImplRec *pIIRec; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetInterfaceImplRecord(RidFromToken(iiImpl), &pIIRec)); + *ptkType = m_LiteWeightStgdb.m_MiniMd.getInterfaceOfInterfaceImpl(pIIRec); + return S_OK; +} // MDInternalRO::GetTypeOfInterfaceImpl + +//***************************************************************************** +// This routine gets the properties for the given MethodSpec token. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::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; + MethodSpecRec *pMethodSpecRec; + + LOG((LOGMD, "MD RegMeta::GetMethodSpecProps(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + mi, tkParent, ppvSigBlob, pcbSigBlob)); + + _ASSERTE(TypeFromToken(mi) == mdtMethodSpec); + + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetMethodSpecRecord(RidFromToken(mi), &pMethodSpecRec)); + + if (tkParent) + *tkParent = m_LiteWeightStgdb.m_MiniMd.getMethodOfMethodSpec(pMethodSpecRec); + + if (ppvSigBlob || pcbSigBlob) + { + // caller wants signature information + PCCOR_SIGNATURE pvSigTmp; + ULONG cbSig; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getInstantiationOfMethodSpec(pMethodSpecRec, &pvSigTmp, &cbSig)); + if ( ppvSigBlob ) + *ppvSigBlob = pvSigTmp; + if ( pcbSigBlob) + *pcbSigBlob = cbSig; + } + + + return hr; +} // MDInternalRO::GetMethodSpecProps + + + +//***************************************************************************** +// Given a classname, return the typedef +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRO::FindTypeDef( + LPCSTR szTypeDefNamespace, // [IN] Namespace for the TypeDef. + LPCSTR szTypeDefName, // [IN] Name of the TypeDef. + mdToken tkEnclosingClass, // [IN] TypeDef/TypeRef of enclosing class. + mdTypeDef * ptkTypeDef) // [OUT] return typedef +{ + HRESULT hr = S_OK; + + _ASSERTE((szTypeDefName != NULL) && (ptkTypeDef != NULL)); + _ASSERTE((TypeFromToken(tkEnclosingClass) == mdtTypeRef) || + (TypeFromToken(tkEnclosingClass) == mdtTypeDef) || + IsNilToken(tkEnclosingClass)); + + // initialize the output parameter + *ptkTypeDef = mdTypeDefNil; + + // Treat no namespace as empty string. + if (szTypeDefNamespace == NULL) + szTypeDefNamespace = ""; + + // Do a linear search + ULONG cTypeDefRecs = m_LiteWeightStgdb.m_MiniMd.getCountTypeDefs(); + TypeDefRec * pTypeDefRec; + LPCUTF8 szName; + LPCUTF8 szNamespace; + DWORD dwFlags; + + // Get TypeDef of the tkEnclosingClass passed in + if (TypeFromToken(tkEnclosingClass) == mdtTypeRef) + { + TypeRefRec * pTypeRefRec; + mdToken tkResolutionScope; + + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetTypeRefRecord(RidFromToken(tkEnclosingClass), &pTypeRefRec)); + tkResolutionScope = m_LiteWeightStgdb.m_MiniMd.getResolutionScopeOfTypeRef(pTypeRefRec); + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNamespaceOfTypeRef(pTypeRefRec, &szNamespace)); + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNameOfTypeRef(pTypeRefRec, &szName)); + + // Update tkEnclosingClass to TypeDef + IfFailRet(FindTypeDef( + szNamespace, + szName, + (TypeFromToken(tkResolutionScope) == mdtTypeRef) ? tkResolutionScope : mdTokenNil, + &tkEnclosingClass)); + _ASSERTE(TypeFromToken(tkEnclosingClass) == mdtTypeDef); + } + + // Search for the TypeDef + for (ULONG i = 1; i <= cTypeDefRecs; i++) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetTypeDefRecord(i, &pTypeDefRec)); + + dwFlags = m_LiteWeightStgdb.m_MiniMd.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(m_LiteWeightStgdb.m_MiniMd.FindNestedClassFor(i, &iNestedClassRec)); + if (InvalidRid(iNestedClassRec)) + continue; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetNestedClassRecord(iNestedClassRec, &pNestedClassRec)); + tkEnclosingClassTmp = m_LiteWeightStgdb.m_MiniMd.getEnclosingClassOfNestedClass(pNestedClassRec); + if (tkEnclosingClass != tkEnclosingClassTmp) + continue; + } + + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNameOfTypeDef(pTypeDefRec, &szName)); + if (strcmp(szTypeDefName, szName) == 0) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNamespaceOfTypeDef(pTypeDefRec, &szNamespace)); + if (strcmp(szTypeDefNamespace, szNamespace) == 0) + { + *ptkTypeDef = TokenFromRid(i, mdtTypeDef); + return S_OK; + } + } + } + // Cannot find the TypeDef by name + return CLDB_E_RECORD_NOTFOUND; +} // MDInternalRO::FindTypeDef + +//***************************************************************************** +// Given a memberref, return a pointer to memberref's name and signature +//***************************************************************************** +// Warning: Even when the return value is ok, *ppvSigBlob could be NULL if +// the metadata is corrupted! (e.g. if CPackedLen::GetLength returned -1). +// TODO: consider returning a HRESULT to make errors evident to the caller. +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRO::GetNameAndSigOfMemberRef( // meberref's name + mdMemberRef memberref, // given a memberref + PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to a blob value of COM+ signature + ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob + LPCSTR *pszMemberRefName) +{ + _ASSERTE(TypeFromToken(memberref) == mdtMemberRef); + + HRESULT hr; + MemberRefRec *pMemberRefRec; + *pszMemberRefName = NULL; + if (ppvSigBlob != NULL) + { + _ASSERTE(pcbSigBlob != NULL); + *ppvSigBlob = NULL; + *pcbSigBlob = 0; + } + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetMemberRefRecord(RidFromToken(memberref), &pMemberRefRec)); + if (ppvSigBlob != NULL) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getSignatureOfMemberRef(pMemberRefRec, ppvSigBlob, pcbSigBlob)); + } + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNameOfMemberRef(pMemberRefRec, pszMemberRefName)); + return S_OK; +} // MDInternalRO::GetNameAndSigOfMemberRef + +//***************************************************************************** +// Given a memberref, return parent token. It can be a TypeRef, ModuleRef, or a MethodDef +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRO::GetParentOfMemberRef( + mdMemberRef memberref, // given a typedef + mdToken *ptkParent) // return the parent token +{ + HRESULT hr; + _ASSERTE(TypeFromToken(memberref) == mdtMemberRef); + + MemberRefRec *pMemberRefRec; + + *ptkParent = mdTokenNil; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetMemberRefRecord(RidFromToken(memberref), &pMemberRefRec)); + *ptkParent = m_LiteWeightStgdb.m_MiniMd.getClassOfMemberRef(pMemberRefRec); + + return S_OK; +} // MDInternalRO::GetParentOfMemberRef + +//***************************************************************************** +// return properties of a paramdef +//*****************************************************************************/ +__checkReturn +HRESULT +MDInternalRO::GetParamDefProps ( + mdParamDef paramdef, // given a paramdef + USHORT *pusSequence, // [OUT] slot number for this parameter + DWORD *pdwAttr, // [OUT] flags + LPCSTR *pszName) // [OUT] return the name of the parameter +{ + _ASSERTE(TypeFromToken(paramdef) == mdtParamDef); + HRESULT hr; + ParamRec *pParamRec; + + *pszName = NULL; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetParamRecord(RidFromToken(paramdef), &pParamRec)); + if (pdwAttr != NULL) + { + *pdwAttr = m_LiteWeightStgdb.m_MiniMd.getFlagsOfParam(pParamRec); + } + if (pusSequence != NULL) + { + *pusSequence = m_LiteWeightStgdb.m_MiniMd.getSequenceOfParam(pParamRec); + } + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNameOfParam(pParamRec, pszName)); + + return S_OK; +} // MDInternalRO::GetParamDefProps + +//***************************************************************************** +// Get property info for the method. +//***************************************************************************** +int MDInternalRO::CMethodSemanticsMapSearcher::Compare( + const CMethodSemanticsMap *psFirst, + const CMethodSemanticsMap *psSecond) +{ + if (psFirst->m_mdMethod < psSecond->m_mdMethod) + return -1; + if (psFirst->m_mdMethod > psSecond->m_mdMethod) + return 1; + return 0; +} // MDInternalRO::CMethodSemanticsMapSearcher::Compare + +#ifndef DACCESS_COMPILE +int MDInternalRO::CMethodSemanticsMapSorter::Compare( + CMethodSemanticsMap *psFirst, + CMethodSemanticsMap *psSecond) +{ + if (psFirst->m_mdMethod < psSecond->m_mdMethod) + return -1; + if (psFirst->m_mdMethod > psSecond->m_mdMethod) + return 1; + return 0; +} // MDInternalRO::CMethodSemanticsMapSorter::Compare + +__checkReturn +HRESULT MDInternalRO::GetPropertyInfoForMethodDef( // Result. + mdMethodDef md, // [IN] memberdef + mdProperty *ppd, // [OUT] put property token here + LPCSTR *pName, // [OUT] put pointer to name here + ULONG *pSemantic) // [OUT] put semantic here +{ + HRESULT hr; + MethodSemanticsRec *pSemantics; // A MethodSemantics record. + MethodSemanticsRec *pFound=0; // A MethodSemantics record that is a property for the desired function. + RID ridCur; // loop control. + RID ridMax; // Count of entries in table. + USHORT usSemantics = 0; // A method's semantics. + mdToken tk; // A method def. + + ridMax = m_LiteWeightStgdb.m_MiniMd.getCountMethodSemantics(); + + // Lazy initialization of m_pMethodSemanticsMap + if ((ridMax > 10) && (m_pMethodSemanticsMap == NULL)) + { + NewHolder<CMethodSemanticsMap> pMethodSemanticsMap = new (nothrow) CMethodSemanticsMap[ridMax]; + if (pMethodSemanticsMap != NULL) + { + // Fill the table in MethodSemantics order. + for (ridCur = 1; ridCur <= ridMax; ridCur++) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetMethodSemanticsRecord(ridCur, &pSemantics)); + tk = m_LiteWeightStgdb.m_MiniMd.getMethodOfMethodSemantics(pSemantics); + pMethodSemanticsMap[ridCur-1].m_mdMethod = tk; + pMethodSemanticsMap[ridCur-1].m_ridSemantics = ridCur; + } + // Sort to MethodDef order. + CMethodSemanticsMapSorter sorter(pMethodSemanticsMap, ridMax); + sorter.Sort(); + + if (InterlockedCompareExchangeT<CMethodSemanticsMap *>( + &m_pMethodSemanticsMap, pMethodSemanticsMap, NULL) == NULL) + { // The exchange did happen, supress of the allocated map + pMethodSemanticsMap.SuppressRelease(); + } + } + } + + // Use m_pMethodSemanticsMap if it has been built. + if (m_pMethodSemanticsMap != NULL) + { + CMethodSemanticsMapSearcher searcher(m_pMethodSemanticsMap, ridMax); + CMethodSemanticsMap target; + const CMethodSemanticsMap * pMatchedMethod; + target.m_mdMethod = md; + pMatchedMethod = searcher.Find(&target); + + // Was there at least one match? + if (pMatchedMethod != NULL) + { + _ASSERTE(pMatchedMethod >= m_pMethodSemanticsMap); + _ASSERTE(pMatchedMethod < m_pMethodSemanticsMap+ridMax); + _ASSERTE(pMatchedMethod->m_mdMethod == md); + + ridCur = pMatchedMethod->m_ridSemantics; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetMethodSemanticsRecord(ridCur, &pSemantics)); + usSemantics = m_LiteWeightStgdb.m_MiniMd.getSemanticOfMethodSemantics(pSemantics); + + // If the semantics record is a getter or setter for the method, that's what we want. + if (usSemantics == msGetter || usSemantics == msSetter) + pFound = pSemantics; + else + { // The semantics record was neither getter or setter. Because there can be + // multiple semantics records for a given method, look for other semantics + // records that match this record. + const CMethodSemanticsMap *pScan; + const CMethodSemanticsMap *pLo=m_pMethodSemanticsMap; + const CMethodSemanticsMap *pHi=pLo+ridMax-1; + for (pScan = pMatchedMethod-1; pScan >= pLo; --pScan) + { + if (pScan->m_mdMethod == md) + { + ridCur = pScan->m_ridSemantics; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetMethodSemanticsRecord(ridCur, &pSemantics)); + usSemantics = m_LiteWeightStgdb.m_MiniMd.getSemanticOfMethodSemantics(pSemantics); + + if (usSemantics == msGetter || usSemantics == msSetter) + { + pFound = pSemantics; + break; + } + } + else + break; + } + + if (pFound == 0) + { // Not found looking down, try looking up. + for (pScan = pMatchedMethod+1; pScan <= pHi; ++pScan) + { + if (pScan->m_mdMethod == md) + { + ridCur = pScan->m_ridSemantics; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetMethodSemanticsRecord(ridCur, &pSemantics)); + usSemantics = m_LiteWeightStgdb.m_MiniMd.getSemanticOfMethodSemantics(pSemantics); + + if (usSemantics == msGetter || usSemantics == msSetter) + { + pFound = pSemantics; + break; + } + } + else + break; + } + + } + } + } + } + else + { // Scan entire table. + for (ridCur = 1; ridCur <= ridMax; ridCur++) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetMethodSemanticsRecord(ridCur, &pSemantics)); + if (md == m_LiteWeightStgdb.m_MiniMd.getMethodOfMethodSemantics(pSemantics)) + { // The method matched, is this a property? + usSemantics = m_LiteWeightStgdb.m_MiniMd.getSemanticOfMethodSemantics(pSemantics); + if (usSemantics == msGetter || usSemantics == msSetter) + { // found a match. + pFound = pSemantics; + break; + } + } + } + } + + // Did the search find anything? + if (pFound) + { // found a match. Fill out the output parameters + PropertyRec *pProperty; + mdProperty prop; + prop = m_LiteWeightStgdb.m_MiniMd.getAssociationOfMethodSemantics(pFound); + + if (ppd) + *ppd = prop; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetPropertyRecord(RidFromToken(prop), &pProperty)); + + if (pName != NULL) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNameOfProperty(pProperty, pName)); + } + + if (pSemantic) + *pSemantic = usSemantics; + return S_OK; + } + return S_FALSE; +} // MDInternalRO::GetPropertyInfoForMethodDef +#endif //!DACCESS_COMPILE + +//***************************************************************************** +// return the pack size of a class +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetClassPackSize( + mdTypeDef td, // [IN] give typedef + DWORD *pdwPackSize) // [OUT] +{ + HRESULT hr = NOERROR; + + _ASSERTE(TypeFromToken(td) == mdtTypeDef && pdwPackSize); + + ClassLayoutRec *pRec; + RID ridClassLayout; + + IfFailGo(m_LiteWeightStgdb.m_MiniMd.FindClassLayoutFor(RidFromToken(td), &ridClassLayout)); + if (InvalidRid(ridClassLayout)) + { + hr = CLDB_E_RECORD_NOTFOUND; + goto ErrExit; + } + + IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetClassLayoutRecord(RidFromToken(ridClassLayout), &pRec)); + *pdwPackSize = m_LiteWeightStgdb.m_MiniMd.getPackingSizeOfClassLayout(pRec); +ErrExit: + return hr; +} // MDInternalRO::GetClassPackSize + + +//***************************************************************************** +// return the total size of a value class +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetClassTotalSize( // return error if a class does not have total size info + mdTypeDef td, // [IN] give typedef + ULONG *pulClassSize) // [OUT] return the total size of the class +{ + _ASSERTE(TypeFromToken(td) == mdtTypeDef && pulClassSize); + + ClassLayoutRec *pRec; + HRESULT hr = NOERROR; + RID ridClassLayout; + + IfFailGo(m_LiteWeightStgdb.m_MiniMd.FindClassLayoutFor(RidFromToken(td), &ridClassLayout)); + if (InvalidRid(ridClassLayout)) + { + hr = CLDB_E_RECORD_NOTFOUND; + goto ErrExit; + } + + IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetClassLayoutRecord(RidFromToken(ridClassLayout), &pRec)); + *pulClassSize = m_LiteWeightStgdb.m_MiniMd.getClassSizeOfClassLayout(pRec); +ErrExit: + return hr; +} // MDInternalRO::GetClassTotalSize + + +//***************************************************************************** +// init the layout enumerator of a class +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetClassLayoutInit( + mdTypeDef td, // [IN] give typedef + MD_CLASS_LAYOUT *pmdLayout) // [OUT] set up the status of query here +{ + HRESULT hr = NOERROR; + _ASSERTE(TypeFromToken(td) == mdtTypeDef); + + // initialize the output parameter + _ASSERTE(pmdLayout); + memset(pmdLayout, 0, sizeof(MD_CLASS_LAYOUT)); + + TypeDefRec *pTypeDefRec; + + // record for this typedef in TypeDef Table + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetTypeDefRecord(RidFromToken(td), &pTypeDefRec)); + + // find the starting and end field for this typedef + pmdLayout->m_ridFieldCur = m_LiteWeightStgdb.m_MiniMd.getFieldListOfTypeDef(pTypeDefRec); + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getEndFieldListOfTypeDef(RidFromToken(td), &(pmdLayout->m_ridFieldEnd))); + return hr; +} // MDInternalRO::GetClassLayoutInit + + +//***************************************************************************** +// return the field offset for a given field +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetFieldOffset( + mdFieldDef fd, // [IN] fielddef + ULONG *pulOffset) // [OUT] FieldOffset +{ + HRESULT hr = S_OK; + FieldLayoutRec *pRec; + + _ASSERTE(pulOffset); + + RID iLayout; + + IfFailGo(m_LiteWeightStgdb.m_MiniMd.FindFieldLayoutFor(RidFromToken(fd), &iLayout)); + + if (InvalidRid(iLayout)) + { + hr = S_FALSE; + goto ErrExit; + } + + IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetFieldLayoutRecord(iLayout, &pRec)); + *pulOffset = m_LiteWeightStgdb.m_MiniMd.getOffSetOfFieldLayout(pRec); + _ASSERTE(*pulOffset != ULONG_MAX); + +ErrExit: + return hr; +} + + +//***************************************************************************** +// enum the next the field layout +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetClassLayoutNext( + MD_CLASS_LAYOUT *pLayout, // [IN|OUT] set up the status of query here + mdFieldDef *pfd, // [OUT] field def + ULONG *pulOffset) // [OUT] field offset or sequence +{ + HRESULT hr = S_OK; + + _ASSERTE(pfd && pulOffset && pLayout); + + RID iLayout2; + FieldLayoutRec *pRec; + + // Make sure no one is messing with pLayout->m_ridFieldLayoutCur, since this doesn't + // mean anything if we are using FieldLayout table. + while (pLayout->m_ridFieldCur < pLayout->m_ridFieldEnd) + { + IfFailGo(m_LiteWeightStgdb.m_MiniMd.FindFieldLayoutFor(pLayout->m_ridFieldCur, &iLayout2)); + pLayout->m_ridFieldCur++; + if (!InvalidRid(iLayout2)) + { + IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetFieldLayoutRecord(iLayout2, &pRec)); + *pulOffset = m_LiteWeightStgdb.m_MiniMd.getOffSetOfFieldLayout(pRec); + _ASSERTE(*pulOffset != ULONG_MAX); + *pfd = TokenFromRid(pLayout->m_ridFieldCur - 1, mdtFieldDef); + goto ErrExit; + } + } + + *pfd = mdFieldDefNil; + hr = S_FALSE; + + // fall through + +ErrExit: + return hr; +} // MDInternalRO::GetClassLayoutNext + + +//***************************************************************************** +// return the field's native type signature +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetFieldMarshal( // return error if no native type associate with the token + mdToken tk, // [IN] given fielddef or paramdef + PCCOR_SIGNATURE *pSigNativeType, // [OUT] the native type signature + ULONG *pcbNativeType) // [OUT] the count of bytes of *ppvNativeType +{ + // output parameters have to be supplied + _ASSERTE(pcbNativeType); + + RID rid; + FieldMarshalRec *pFieldMarshalRec; + HRESULT hr = NOERROR; + + // find the row containing the marshal definition for tk + IfFailGo(m_LiteWeightStgdb.m_MiniMd.FindFieldMarshalFor(RidFromToken(tk), TypeFromToken(tk), &rid)); + if (InvalidRid(rid)) + { + *pSigNativeType = NULL; + *pcbNativeType = 0; + hr = CLDB_E_RECORD_NOTFOUND; + goto ErrExit; + } + IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetFieldMarshalRecord(rid, &pFieldMarshalRec)); + + // get the native type + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getNativeTypeOfFieldMarshal(pFieldMarshalRec, pSigNativeType, pcbNativeType)); +ErrExit: + return hr; +} // MDInternalRO::GetFieldMarshal + + + +//***************************************** +// property APIs +//***************************************** + +//***************************************************************************** +// Find property by name +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::FindProperty( + mdTypeDef td, // [IN] given a typdef + LPCSTR szPropName, // [IN] property name + mdProperty *pProp) // [OUT] return property token +{ + HRESULT hr = NOERROR; + + // output parameters have to be supplied + _ASSERTE(TypeFromToken(td) == mdtTypeDef && pProp); + + PropertyMapRec *pRec; + PropertyRec *pProperty; + RID ridPropertyMap; + RID ridCur; + RID ridEnd; + LPCUTF8 szName; + + IfFailGo(m_LiteWeightStgdb.m_MiniMd.FindPropertyMapFor(RidFromToken(td), &ridPropertyMap)); + if (InvalidRid(ridPropertyMap)) + { + // not found! + hr = CLDB_E_RECORD_NOTFOUND; + goto ErrExit; + } + + IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetPropertyMapRecord(ridPropertyMap, &pRec)); + + // get the starting/ending rid of properties of this typedef + ridCur = m_LiteWeightStgdb.m_MiniMd.getPropertyListOfPropertyMap(pRec); + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getEndPropertyListOfPropertyMap(ridPropertyMap, &ridEnd)); + + for (; ridCur < ridEnd; ridCur ++) + { + IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetPropertyRecord(ridCur, &pProperty)); + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getNameOfProperty(pProperty, &szName)); + if (strcmp(szName, szPropName) ==0) + { + // Found the match. Set the output parameter and we are done. + *pProp = TokenFromRid(ridCur, mdtProperty); + goto ErrExit; + } + } + + // not found + hr = CLDB_E_RECORD_NOTFOUND; +ErrExit: + return hr; + +} // MDInternalRO::FindProperty + + + +//***************************************************************************** +// return the properties of a property +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetPropertyProps( + mdProperty prop, // [IN] property token + LPCSTR *pszProperty, // [OUT] property name + DWORD *pdwPropFlags, // [OUT] property flags. + PCCOR_SIGNATURE *ppvSig, // [OUT] property type. pointing to meta data internal blob + ULONG *pcbSig) // [OUT] count of bytes in *ppvSig +{ + // output parameters have to be supplied + _ASSERTE(TypeFromToken(prop) == mdtProperty); + + HRESULT hr; + + PropertyRec *pProperty; + ULONG cbSig; + + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetPropertyRecord(RidFromToken(prop), &pProperty)); + + // get name of the property + if (pszProperty != NULL) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNameOfProperty(pProperty, pszProperty)); + } + + // get the flags of property + if (pdwPropFlags) + *pdwPropFlags = m_LiteWeightStgdb.m_MiniMd.getPropFlagsOfProperty(pProperty); + + // get the type of the property + if (ppvSig != NULL) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getTypeOfProperty(pProperty, ppvSig, &cbSig)); + if (pcbSig != NULL) + { + *pcbSig = cbSig; + } + } + + return S_OK; +} // MDInternalRO::GetPropertyProps + + +//********************************** +// +// Event APIs +// +//********************************** + +//***************************************************************************** +// return an event by given the name +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::FindEvent( + mdTypeDef td, // [IN] given a typdef + LPCSTR szEventName, // [IN] event name + mdEvent *pEvent) // [OUT] return event token +{ + HRESULT hr = NOERROR; + + // output parameters have to be supplied + _ASSERTE(TypeFromToken(td) == mdtTypeDef && pEvent); + + EventMapRec *pRec; + EventRec *pEventRec; + RID ridEventMap; + RID ridCur; + RID ridEnd; + LPCUTF8 szName; + + IfFailGo(m_LiteWeightStgdb.m_MiniMd.FindEventMapFor(RidFromToken(td), &ridEventMap)); + if (InvalidRid(ridEventMap)) + { + // not found! + hr = CLDB_E_RECORD_NOTFOUND; + goto ErrExit; + } + IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetEventMapRecord(ridEventMap, &pRec)); + + // get the starting/ending rid of properties of this typedef + ridCur = m_LiteWeightStgdb.m_MiniMd.getEventListOfEventMap(pRec); + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getEndEventListOfEventMap(ridEventMap, &ridEnd)); + + for (; ridCur < ridEnd; ridCur ++) + { + IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetEventRecord(ridCur, &pEventRec)); + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getNameOfEvent(pEventRec, &szName)); + if (strcmp(szName, szEventName) ==0) + { + // Found the match. Set the output parameter and we are done. + *pEvent = TokenFromRid(ridCur, mdtEvent); + goto ErrExit; + } + } + + // not found + hr = CLDB_E_RECORD_NOTFOUND; +ErrExit: + return hr; +} // MDInternalRO::FindEvent + + +//***************************************************************************** +// return the properties of an event +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetEventProps( // S_OK, S_FALSE, or error. + mdEvent ev, // [IN] event token + LPCSTR *pszEvent, // [OUT] Event name + DWORD *pdwEventFlags, // [OUT] Event flags. + mdToken *ptkEventType) // [OUT] EventType class +{ + // output parameters have to be supplied + _ASSERTE(TypeFromToken(ev) == mdtEvent); + + HRESULT hr; + EventRec *pEvent; + + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetEventRecord(RidFromToken(ev), &pEvent)); + if (pszEvent != NULL) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNameOfEvent(pEvent, pszEvent)); + } + if (pdwEventFlags) + *pdwEventFlags = m_LiteWeightStgdb.m_MiniMd.getEventFlagsOfEvent(pEvent); + if (ptkEventType) + *ptkEventType = m_LiteWeightStgdb.m_MiniMd.getEventTypeOfEvent(pEvent); + + return S_OK; +} // MDInternalRO::GetEventProps + +//***************************************************************************** +// return the properties of a generic param +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetGenericParamProps( // S_OK or error. + mdGenericParam rd, // [IN] The type parameter + ULONG* pulSequence, // [OUT] Parameter sequence number + DWORD* pdwAttr, // [OUT] Type parameter flags (for future use) + mdToken *ptOwner, // [OUT] The owner (TypeDef or MethodDef) + DWORD *reserved, // [OUT] The kind (TypeDef/Ref/Spec, for future use) + LPCSTR *szName) // [OUT] The name +{ + HRESULT hr = NOERROR; + GenericParamRec * pGenericParamRec = NULL; + + // See if this version of the metadata can do Generics + if (!m_LiteWeightStgdb.m_MiniMd.SupportsGenerics()) + IfFailGo(CLDB_E_INCOMPATIBLE); + + _ASSERTE(TypeFromToken(rd) == mdtGenericParam); + if (TypeFromToken(rd) != mdtGenericParam) + { + IfFailGo(CLDB_E_FILE_CORRUPT); + } + + IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetGenericParamRecord(RidFromToken(rd), &pGenericParamRec)); + + if (pulSequence) + *pulSequence = m_LiteWeightStgdb.m_MiniMd.getNumberOfGenericParam(pGenericParamRec); + if (pdwAttr) + *pdwAttr = m_LiteWeightStgdb.m_MiniMd.getFlagsOfGenericParam(pGenericParamRec); + if (ptOwner) + *ptOwner = m_LiteWeightStgdb.m_MiniMd.getOwnerOfGenericParam(pGenericParamRec); + if (szName != NULL) + { + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getNameOfGenericParam(pGenericParamRec, szName)); + } +ErrExit: + return hr; +} // MDInternalRO::GetGenericParamProps + +//***************************************************************************** +// This routine gets the properties for the given GenericParamConstraint token. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::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; + GenericParamConstraintRec *pGPCRec; + RID ridRD = RidFromToken(rd); + + // See if this version of the metadata can do Generics + if (!m_LiteWeightStgdb.m_MiniMd.SupportsGenerics()) + IfFailGo(CLDB_E_INCOMPATIBLE); + + if((TypeFromToken(rd) == mdtGenericParamConstraint) && (ridRD != 0)) + { + IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetGenericParamConstraintRecord(ridRD, &pGPCRec)); + + if (ptGenericParam) + *ptGenericParam = TokenFromRid(m_LiteWeightStgdb.m_MiniMd.getOwnerOfGenericParamConstraint(pGPCRec),mdtGenericParam); + if (ptkConstraintType) + *ptkConstraintType = m_LiteWeightStgdb.m_MiniMd.getConstraintOfGenericParamConstraint(pGPCRec); + } + else + hr = META_E_BAD_INPUT_PARAMETER; + +ErrExit: + return hr; +} // MDInternalRO::GetGenericParamConstraintProps + +//***************************************************************************** +// Find methoddef of a particular associate with a property or an event +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::FindAssociate( + mdToken evprop, // [IN] given a property or event token + DWORD dwSemantics, // [IN] given a associate semantics(setter, getter, testdefault, reset) + mdMethodDef *pmd) // [OUT] return method def token +{ + HRESULT hr = NOERROR; + + // output parameters have to be supplied + _ASSERTE(pmd); + _ASSERTE(TypeFromToken(evprop) == mdtEvent || TypeFromToken(evprop) == mdtProperty); + + MethodSemanticsRec *pSemantics; + RID ridCur; + RID ridEnd; + + IfFailGo(m_LiteWeightStgdb.m_MiniMd.getAssociatesForToken(evprop, &ridEnd, &ridCur)); + for (; ridCur < ridEnd; ridCur++) + { + IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetMethodSemanticsRecord(ridCur, &pSemantics)); + if (dwSemantics == m_LiteWeightStgdb.m_MiniMd.getSemanticOfMethodSemantics(pSemantics)) + { + // found a match + *pmd = m_LiteWeightStgdb.m_MiniMd.getMethodOfMethodSemantics(pSemantics); + goto ErrExit; + } + } + + // not found + hr = CLDB_E_RECORD_NOTFOUND; +ErrExit: + return hr; +} // MDInternalRO::FindAssociate + + +//***************************************************************************** +// get counts of methodsemantics associated with a particular property/event +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::EnumAssociateInit( + mdToken evprop, // [IN] given a property or an event token + HENUMInternal *phEnum) // [OUT] cursor to hold the query result +{ + HRESULT hr; + _ASSERTE(phEnum); + + memset(phEnum, 0, sizeof(HENUMInternal)); + + // There is no token kind!!! + phEnum->m_tkKind = ULONG_MAX; + + // output parameters have to be supplied + _ASSERTE(TypeFromToken(evprop) == mdtEvent || TypeFromToken(evprop) == mdtProperty); + + phEnum->m_EnumType = MDSimpleEnum; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getAssociatesForToken(evprop, &phEnum->u.m_ulEnd, &phEnum->u.m_ulStart)); + phEnum->u.m_ulCur = phEnum->u.m_ulStart; + phEnum->m_ulCount = phEnum->u.m_ulEnd - phEnum->u.m_ulStart; + + return S_OK; +} // MDInternalRO::EnumAssociateInit + + +//***************************************************************************** +// get all methodsemantics associated with a particular property/event +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetAllAssociates( + HENUMInternal *phEnum, // [OUT] cursor to hold the query result + ASSOCIATE_RECORD *pAssociateRec, // [OUT] struct to fill for output + ULONG cAssociateRec) // [IN] size of the buffer +{ + _ASSERTE(phEnum && pAssociateRec); + + HRESULT hr; + MethodSemanticsRec *pSemantics; + RID ridCur; + _ASSERTE(cAssociateRec == phEnum->m_ulCount); + + // Convert from row pointers to RIDs. + for (ridCur = phEnum->u.m_ulStart; ridCur < phEnum->u.m_ulEnd; ++ridCur) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetMethodSemanticsRecord(ridCur, &pSemantics)); + + pAssociateRec[ridCur-phEnum->u.m_ulStart].m_memberdef = m_LiteWeightStgdb.m_MiniMd.getMethodOfMethodSemantics(pSemantics); + pAssociateRec[ridCur-phEnum->u.m_ulStart].m_dwSemantics = m_LiteWeightStgdb.m_MiniMd.getSemanticOfMethodSemantics(pSemantics); + } + + return S_OK; +} // MDInternalRO::GetAllAssociates + + +//***************************************************************************** +// Get the Action and Permissions blob for a given PermissionSet. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::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; + _ASSERTE(TypeFromToken(pm) == mdtPermission); + _ASSERTE(pdwAction && ppvPermission && pcbPermission); + + DeclSecurityRec *pPerm; + + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetDeclSecurityRecord(RidFromToken(pm), &pPerm)); + *pdwAction = m_LiteWeightStgdb.m_MiniMd.getActionOfDeclSecurity(pPerm); + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getPermissionSetOfDeclSecurity(pPerm, (const BYTE **)ppvPermission, pcbPermission)); + + return S_OK; +} // MDInternalRO::GetPermissionSetProps + +//***************************************************************************** +// Get the String given the String token. +// Return a pointer to the string, or NULL in case of error. +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRO::GetUserString( // Offset into the string blob heap. + mdString stk, // [IN] the string token. + ULONG *pcchStringSize, // [OUT] count of characters in the string. + BOOL *pfIs80Plus, // [OUT] specifies where there are extended characters >= 0x80. + LPCWSTR *pwszUserString) +{ + HRESULT hr; + LPWSTR wszTmp; + + if (pfIs80Plus != NULL) + { + *pfIs80Plus = FALSE; + } + *pwszUserString = NULL; + *pcchStringSize = 0; + + _ASSERTE(pcchStringSize != NULL); + MetaData::DataBlob userString; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetUserString(RidFromToken(stk), &userString)); + + wszTmp = reinterpret_cast<LPWSTR>(userString.GetDataPointer()); + + *pcchStringSize = userString.GetSize() / sizeof(WCHAR); + + if (userString.IsEmpty()) + { + *pwszUserString = NULL; + return S_OK; + } + + if (pfIs80Plus != NULL) + { + if (userString.GetSize() % sizeof(WCHAR) == 0) + { + *pfIs80Plus = TRUE; // no indicator, presume the worst + } + // Return the user string terminator (contains value fIs80Plus) + *pfIs80Plus = *(reinterpret_cast<PBYTE>(wszTmp + *pcchStringSize)); + } + + *pwszUserString = wszTmp; + return S_OK; +} // MDInternalRO::GetUserString + +//***************************************************************************** +// Return contents of Pinvoke given the forwarded member token. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetPinvokeMap( + mdToken tk, // [IN] FieldDef or MethodDef. + DWORD *pdwMappingFlags, // [OUT] Flags used for mapping. + LPCSTR *pszImportName, // [OUT] Import name. + mdModuleRef *pmrImportDLL) // [OUT] ModuleRef token for the target DLL. +{ + HRESULT hr; + ImplMapRec *pRecord; + RID iRecord; + + IfFailRet(m_LiteWeightStgdb.m_MiniMd.FindImplMapFor(RidFromToken(tk), TypeFromToken(tk), &iRecord)); + if (InvalidRid(iRecord)) + { + return CLDB_E_RECORD_NOTFOUND; + } + else + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetImplMapRecord(iRecord, &pRecord)); + } + + if (pdwMappingFlags) + *pdwMappingFlags = m_LiteWeightStgdb.m_MiniMd.getMappingFlagsOfImplMap(pRecord); + if (pszImportName != NULL) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getImportNameOfImplMap(pRecord, pszImportName)); + } + if (pmrImportDLL) + *pmrImportDLL = m_LiteWeightStgdb.m_MiniMd.getImportScopeOfImplMap(pRecord); + + return S_OK; +} // MDInternalRO::GetPinvokeMap + +//***************************************************************************** +// Get the properties for the given Assembly token. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetAssemblyProps( + mdAssembly mda, // [IN] The Assembly for which to get the properties. + const void **ppbPublicKey, // [OUT] Pointer to the public key. + ULONG *pcbPublicKey, // [OUT] Count of bytes in the public key. + ULONG *pulHashAlgId, // [OUT] Hash Algorithm. + LPCSTR *pszName, // [OUT] Buffer to fill with name. + AssemblyMetaDataInternal *pMetaData,// [OUT] Assembly MetaData. + DWORD *pdwAssemblyFlags) // [OUT] Flags. +{ + HRESULT hr; + AssemblyRec *pRecord; + + _ASSERTE(TypeFromToken(mda) == mdtAssembly && RidFromToken(mda)); + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetAssemblyRecord(RidFromToken(mda), &pRecord)); + + if (ppbPublicKey != NULL) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getPublicKeyOfAssembly(pRecord, reinterpret_cast<const BYTE **>(ppbPublicKey), pcbPublicKey)); + } + if (pulHashAlgId) + *pulHashAlgId = m_LiteWeightStgdb.m_MiniMd.getHashAlgIdOfAssembly(pRecord); + if (pszName != NULL) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNameOfAssembly(pRecord, pszName)); + } + if (pMetaData) + { + pMetaData->usMajorVersion = m_LiteWeightStgdb.m_MiniMd.getMajorVersionOfAssembly(pRecord); + pMetaData->usMinorVersion = m_LiteWeightStgdb.m_MiniMd.getMinorVersionOfAssembly(pRecord); + pMetaData->usBuildNumber = m_LiteWeightStgdb.m_MiniMd.getBuildNumberOfAssembly(pRecord); + pMetaData->usRevisionNumber = m_LiteWeightStgdb.m_MiniMd.getRevisionNumberOfAssembly(pRecord); + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getLocaleOfAssembly(pRecord, &pMetaData->szLocale)); + pMetaData->ulProcessor = 0; + pMetaData->ulOS = 0; + } + if (pdwAssemblyFlags) + { + *pdwAssemblyFlags = m_LiteWeightStgdb.m_MiniMd.getFlagsOfAssembly(pRecord); + +#ifdef FEATURE_WINDOWSPHONE + // Turn on the afPublicKey if PublicKey blob is not empty + DWORD cbPublicKey; + const BYTE *pbPublicKey; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.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 *pPublicKey; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getPublicKeyOfAssembly(pRecord, &pPublicKey, &cbPublicKey)); + bool hasPublicKey = cbPublicKey != 0; + bool hasPublicKeyFlag = ( *pdwAssemblyFlags & afPublicKey ) != 0; + if(REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_AssertOnBadImageFormat, 0)) + _ASSERTE( hasPublicKey == hasPublicKeyFlag ); +#endif + } +#endif // FEATURE_WINDOWSPHONE + } + + return S_OK; +} // MDInternalRO::GetAssemblyProps + +//***************************************************************************** +// Get the properties for the given AssemblyRef token. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetAssemblyRefProps( + mdAssemblyRef mdar, // [IN] The AssemblyRef for which to get the properties. + const void **ppbPublicKeyOrToken, // [OUT] Pointer to the public key or token. + ULONG *pcbPublicKeyOrToken, // [OUT] Count of bytes in the public key or token. + LPCSTR *pszName, // [OUT] Buffer to fill with name. + AssemblyMetaDataInternal *pMetaData,// [OUT] Assembly MetaData. + const void **ppbHashValue, // [OUT] Hash blob. + ULONG *pcbHashValue, // [OUT] Count of bytes in the hash blob. + DWORD *pdwAssemblyRefFlags) // [OUT] Flags. +{ + HRESULT hr; + AssemblyRefRec *pRecord; + + _ASSERTE(TypeFromToken(mdar) == mdtAssemblyRef && RidFromToken(mdar)); + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetAssemblyRefRecord(RidFromToken(mdar), &pRecord)); + + if (ppbPublicKeyOrToken != NULL) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getPublicKeyOrTokenOfAssemblyRef(pRecord, reinterpret_cast<const BYTE **>(ppbPublicKeyOrToken), pcbPublicKeyOrToken)); + } + if (pszName != NULL) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNameOfAssemblyRef(pRecord, pszName)); + } + if (pMetaData) + { + pMetaData->usMajorVersion = m_LiteWeightStgdb.m_MiniMd.getMajorVersionOfAssemblyRef(pRecord); + pMetaData->usMinorVersion = m_LiteWeightStgdb.m_MiniMd.getMinorVersionOfAssemblyRef(pRecord); + pMetaData->usBuildNumber = m_LiteWeightStgdb.m_MiniMd.getBuildNumberOfAssemblyRef(pRecord); + pMetaData->usRevisionNumber = m_LiteWeightStgdb.m_MiniMd.getRevisionNumberOfAssemblyRef(pRecord); + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getLocaleOfAssemblyRef(pRecord, &pMetaData->szLocale)); + pMetaData->ulProcessor = 0; + pMetaData->ulOS = 0; + } + if (ppbHashValue != NULL) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getHashValueOfAssemblyRef(pRecord, reinterpret_cast<const BYTE **>(ppbHashValue), pcbHashValue)); + } + if (pdwAssemblyRefFlags != NULL) + { + *pdwAssemblyRefFlags = m_LiteWeightStgdb.m_MiniMd.getFlagsOfAssemblyRef(pRecord); + } + + return S_OK; +} // MDInternalRO::GetAssemblyRefProps + +//***************************************************************************** +// Get the properties for the given File token. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetFileProps( + mdFile mdf, // [IN] The File for which to get the properties. + LPCSTR *pszName, // [OUT] Buffer to fill with name. + const void **ppbHashValue, // [OUT] Pointer to the Hash Value Blob. + ULONG *pcbHashValue, // [OUT] Count of bytes in the Hash Value Blob. + DWORD *pdwFileFlags) // [OUT] Flags. +{ + HRESULT hr; + FileRec *pRecord; + + _ASSERTE(TypeFromToken(mdf) == mdtFile && RidFromToken(mdf)); + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetFileRecord(RidFromToken(mdf), &pRecord)); + + if (pszName != NULL) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNameOfFile(pRecord, pszName)); + } + if (ppbHashValue != NULL) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getHashValueOfFile(pRecord, reinterpret_cast<const BYTE **>(ppbHashValue), pcbHashValue)); + } + if (pdwFileFlags != NULL) + { + *pdwFileFlags = m_LiteWeightStgdb.m_MiniMd.getFlagsOfFile(pRecord); + } + + return S_OK; +} // MDInternalRO::GetFileProps + +//***************************************************************************** +// Get the properties for the given ExportedType token. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetExportedTypeProps( + mdExportedType mdct, // [IN] The ExportedType for which to get the properties. + LPCSTR *pszNamespace, // [OUT] Buffer to fill with namespace. + LPCSTR *pszName, // [OUT] Buffer to fill with name. + mdToken *ptkImplementation, // [OUT] mdFile or mdAssemblyRef that provides the ExportedType. + mdTypeDef *ptkTypeDef, // [OUT] TypeDef token within the file. + DWORD *pdwExportedTypeFlags) // [OUT] Flags. +{ + HRESULT hr; + ExportedTypeRec *pRecord; + + _ASSERTE(TypeFromToken(mdct) == mdtExportedType && RidFromToken(mdct)); + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetExportedTypeRecord(RidFromToken(mdct), &pRecord)); + + if (pszNamespace != NULL) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getTypeNamespaceOfExportedType(pRecord, pszNamespace)); + } + if (pszName != NULL) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getTypeNameOfExportedType(pRecord, pszName)); + } + if (ptkImplementation) + *ptkImplementation = m_LiteWeightStgdb.m_MiniMd.getImplementationOfExportedType(pRecord); + if (ptkTypeDef) + *ptkTypeDef = m_LiteWeightStgdb.m_MiniMd.getTypeDefIdOfExportedType(pRecord); + if (pdwExportedTypeFlags) + *pdwExportedTypeFlags = m_LiteWeightStgdb.m_MiniMd.getFlagsOfExportedType(pRecord); + + return S_OK; +} // MDInternalRO::GetExportedTypeProps + +//***************************************************************************** +// Get the properties for the given Resource token. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetManifestResourceProps( + mdManifestResource mdmr, // [IN] The ManifestResource for which to get the properties. + LPCSTR *pszName, // [OUT] Buffer to fill with name. + mdToken *ptkImplementation, // [OUT] mdFile or mdAssemblyRef that provides the ExportedType. + DWORD *pdwOffset, // [OUT] Offset to the beginning of the resource within the file. + DWORD *pdwResourceFlags) // [OUT] Flags. +{ + HRESULT hr; + ManifestResourceRec *pRecord; + + _ASSERTE(TypeFromToken(mdmr) == mdtManifestResource && RidFromToken(mdmr)); + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetManifestResourceRecord(RidFromToken(mdmr), &pRecord)); + + if (pszName != NULL) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNameOfManifestResource(pRecord, pszName)); + } + if (ptkImplementation) + *ptkImplementation = m_LiteWeightStgdb.m_MiniMd.getImplementationOfManifestResource(pRecord); + if (pdwOffset) + *pdwOffset = m_LiteWeightStgdb.m_MiniMd.getOffsetOfManifestResource(pRecord); + if (pdwResourceFlags) + *pdwResourceFlags = m_LiteWeightStgdb.m_MiniMd.getFlagsOfManifestResource(pRecord); + + return S_OK; +} // MDInternalRO::GetManifestResourceProps + +//***************************************************************************** +// Find the ExportedType given the name. +//***************************************************************************** +__checkReturn +STDMETHODIMP MDInternalRO::FindExportedTypeByName( // S_OK or error + LPCSTR szNamespace, // [IN] Namespace of the ExportedType. + LPCSTR szName, // [IN] Name of the ExportedType. + mdExportedType tkEnclosingType, // [IN] Token for the Enclosing Type. + mdExportedType *pmct) // [OUT] Put ExportedType token here. +{ + IMetaModelCommon *pCommon = static_cast<IMetaModelCommon*>(&m_LiteWeightStgdb.m_MiniMd); + return pCommon->CommonFindExportedType(szNamespace, szName, tkEnclosingType, pmct); +} // MDInternalRO::FindExportedTypeByName + +//***************************************************************************** +// Find the ManifestResource given the name. +//***************************************************************************** +__checkReturn +STDMETHODIMP MDInternalRO::FindManifestResourceByName( // S_OK or error + LPCSTR szName, // [IN] Name of the resource. + mdManifestResource *pmmr) // [OUT] Put ManifestResource token here. +{ + _ASSERTE(szName && pmmr); + + HRESULT hr; + ManifestResourceRec *pRecord; + ULONG cRecords; // Count of records. + LPCUTF8 szNameTmp = 0; // Name obtained from the database. + ULONG i; + + cRecords = m_LiteWeightStgdb.m_MiniMd.getCountManifestResources(); + + // Search for the ExportedType. + for (i = 1; i <= cRecords; i++) + { + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetManifestResourceRecord(i, &pRecord)); + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNameOfManifestResource(pRecord, &szNameTmp)); + if (! strcmp(szName, szNameTmp)) + { + *pmmr = TokenFromRid(i, mdtManifestResource); + return S_OK; + } + } + return CLDB_E_RECORD_NOTFOUND; +} // MDInternalRO::FindManifestResourceByName + +//***************************************************************************** +// Get the Assembly token from the given scope. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetAssemblyFromScope( // S_OK or error + mdAssembly *ptkAssembly) // [OUT] Put token here. +{ + _ASSERTE(ptkAssembly); + + if (m_LiteWeightStgdb.m_MiniMd.getCountAssemblys()) + { + *ptkAssembly = TokenFromRid(1, mdtAssembly); + return S_OK; + } + else + return CLDB_E_RECORD_NOTFOUND; +} // MDInternalRO::GetAssemblyFromScope + +//******************************************************************************* +// return properties regarding a TypeSpec +//******************************************************************************* +__checkReturn +HRESULT MDInternalRO::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; + + _ASSERTE(TypeFromToken(typespec) == mdtTypeSpec); + _ASSERTE(ppvSig && pcbSig); + + if (!IsValidToken(typespec)) + { + *ppvSig = NULL; + *pcbSig = 0; + return E_INVALIDARG; + } + + TypeSpecRec *pRec; + IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetTypeSpecRecord(RidFromToken(typespec), &pRec)); + + if (pRec == NULL) + { + *ppvSig = NULL; + *pcbSig = 0; + return CLDB_E_FILE_CORRUPT; + } + + IfFailRet(m_LiteWeightStgdb.m_MiniMd.getSignatureOfTypeSpec(pRec, ppvSig, pcbSig)); + + return hr; +} // MDInternalRO::GetTypeSpecFromToken + +//***************************************************************************** +// This function gets the "built for" version of a metadata scope. +// NOTE: if the scope has never been saved, it will not have a built-for +// version, and an empty string will be returned. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetVersionString( + LPCSTR * pVer) // [OUT] Put version string here. +{ + HRESULT hr = NOERROR; + + if (m_LiteWeightStgdb.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_LiteWeightStgdb.m_pvMd)->pVersion); + } + else + { // No string. + *pVer = NULL; + } + + return hr; +} // MDInternalRO::GetVersionString + +//***************************************************************************** +// convert a text signature to com format +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::ConvertTextSigToComSig(// Return hresult. + BOOL fCreateTrIfNotFound, // create typeref if not found or not + LPCSTR pSignature, // class file format signature + CQuickBytes *pqbNewSig, // [OUT] place holder for COM+ signature + ULONG *pcbCount) // [OUT] the result size of signature +{ + return E_NOTIMPL; +} // MDInternalRO::ConvertTextSigToComSig + + +//***************************************************************************** +// determine if a token is valid or not +//***************************************************************************** +BOOL MDInternalRO::IsValidToken( // True or False. + mdToken tk) // [IN] Given token. +{ + RID rid = RidFromToken(tk); + if (rid == 0) + { + return FALSE; + } + switch (TypeFromToken(tk)) + { + case mdtModule: + // can have only one module record + return (rid <= m_LiteWeightStgdb.m_MiniMd.getCountModules()); + case mdtTypeRef: + return (rid <= m_LiteWeightStgdb.m_MiniMd.getCountTypeRefs()); + case mdtTypeDef: + return (rid <= m_LiteWeightStgdb.m_MiniMd.getCountTypeDefs()); + case mdtFieldDef: + return (rid <= m_LiteWeightStgdb.m_MiniMd.getCountFields()); + case mdtMethodDef: + return (rid <= m_LiteWeightStgdb.m_MiniMd.getCountMethods()); + case mdtParamDef: + return (rid <= m_LiteWeightStgdb.m_MiniMd.getCountParams()); + case mdtInterfaceImpl: + return (rid <= m_LiteWeightStgdb.m_MiniMd.getCountInterfaceImpls()); + case mdtMemberRef: + return (rid <= m_LiteWeightStgdb.m_MiniMd.getCountMemberRefs()); + case mdtCustomAttribute: + return (rid <= m_LiteWeightStgdb.m_MiniMd.getCountCustomAttributes()); + case mdtPermission: + return (rid <= m_LiteWeightStgdb.m_MiniMd.getCountDeclSecuritys()); + case mdtSignature: + return (rid <= m_LiteWeightStgdb.m_MiniMd.getCountStandAloneSigs()); + case mdtEvent: + return (rid <= m_LiteWeightStgdb.m_MiniMd.getCountEvents()); + case mdtProperty: + return (rid <= m_LiteWeightStgdb.m_MiniMd.getCountPropertys()); + case mdtModuleRef: + return (rid <= m_LiteWeightStgdb.m_MiniMd.getCountModuleRefs()); + case mdtTypeSpec: + return (rid <= m_LiteWeightStgdb.m_MiniMd.getCountTypeSpecs()); + case mdtAssembly: + return (rid <= m_LiteWeightStgdb.m_MiniMd.getCountAssemblys()); + case mdtAssemblyRef: + return (rid <= m_LiteWeightStgdb.m_MiniMd.getCountAssemblyRefs()); + case mdtFile: + return (rid <= m_LiteWeightStgdb.m_MiniMd.getCountFiles()); + case mdtExportedType: + return (rid <= m_LiteWeightStgdb.m_MiniMd.getCountExportedTypes()); + case mdtManifestResource: + return (rid <= m_LiteWeightStgdb.m_MiniMd.getCountManifestResources()); + case mdtMethodSpec: + return (rid <= m_LiteWeightStgdb.m_MiniMd.getCountMethodSpecs()); + case mdtString: + // need to check the user string heap + return m_LiteWeightStgdb.m_MiniMd.m_UserStringHeap.IsValidIndex(rid); + default: +/* Don't Assert here, this will break verifier tests. + _ASSERTE(!"Unknown token kind!"); +*/ + return FALSE; + } +} // MDInternalRO::IsValidToken + +mdModule MDInternalRO::GetModuleFromScope(void) +{ + return TokenFromRid(1, mdtModule); +} // MDInternalRO::GetModuleFromScope + +//***************************************************************************** +// Fill a variant given a MDDefaultValue +// This routine will create a bstr if the ELEMENT_TYPE of default value is STRING +//***************************************************************************** +__checkReturn +HRESULT _FillVariant( + MDDefaultValue *pMDDefaultValue, + VARIANT *pvar) +{ + HRESULT hr = NOERROR; + + _ASSERTE(pMDDefaultValue); + + switch (pMDDefaultValue->m_bType) + { + case ELEMENT_TYPE_BOOLEAN: + V_VT(pvar) = VT_BOOL; + V_BOOL(pvar) = pMDDefaultValue->m_bValue; + break; + case ELEMENT_TYPE_I1: + V_VT(pvar) = VT_I1; + V_I1(pvar) = pMDDefaultValue->m_cValue; + break; + case ELEMENT_TYPE_U1: + V_VT(pvar) = VT_UI1; + V_UI1(pvar) = pMDDefaultValue->m_byteValue; + break; + case ELEMENT_TYPE_I2: + V_VT(pvar) = VT_I2; + V_I2(pvar) = pMDDefaultValue->m_sValue; + break; + case ELEMENT_TYPE_U2: + case ELEMENT_TYPE_CHAR: // char is stored as UI2 internally + V_VT(pvar) = VT_UI2; + V_UI2(pvar) = pMDDefaultValue->m_usValue; + break; + case ELEMENT_TYPE_I4: + V_VT(pvar) = VT_I4; + V_I4(pvar) = pMDDefaultValue->m_lValue; + break; + case ELEMENT_TYPE_U4: + V_VT(pvar) = VT_UI4; + V_UI4(pvar) = pMDDefaultValue->m_ulValue; + break; + case ELEMENT_TYPE_R4: + V_VT(pvar) = VT_R4; + V_R4(pvar) = pMDDefaultValue->m_fltValue; + break; + case ELEMENT_TYPE_R8: + V_VT(pvar) = VT_R8; + V_R8(pvar) = pMDDefaultValue->m_dblValue; + break; + case ELEMENT_TYPE_STRING: + // allocated bstr here + V_BSTR(pvar) = ::SysAllocStringLen(pMDDefaultValue->m_wzValue, pMDDefaultValue->m_cbSize / sizeof(WCHAR)); + if (V_BSTR(pvar) == NULL) + hr = E_OUTOFMEMORY; + V_VT(pvar) = VT_BSTR; + break; + case ELEMENT_TYPE_CLASS: + V_VT(pvar) = VT_UNKNOWN; + V_UNKNOWN(pvar) = pMDDefaultValue->m_unkValue; + break; + case ELEMENT_TYPE_I8: + V_VT(pvar) = VT_I8; + V_CY(pvar).int64 = pMDDefaultValue->m_llValue; + break; + case ELEMENT_TYPE_U8: + V_VT(pvar) = VT_UI8; + V_CY(pvar).int64 = pMDDefaultValue->m_ullValue; + break; + case ELEMENT_TYPE_VOID: + V_VT(pvar) = VT_EMPTY; + break; + default: + _ASSERTE(!"bad constant value type!"); + } + + return hr; +} // _FillVariant + + +//***************************************************************************** +// Fill a variant given a MDDefaultValue +// This routine will create a bstr if the ELEMENT_TYPE of default value is STRING +//***************************************************************************** +__checkReturn +HRESULT _FillMDDefaultValue( + BYTE bType, + void const *pValue, + ULONG cbValue, + MDDefaultValue *pMDDefaultValue) +{ + HRESULT hr = NOERROR; + + pMDDefaultValue->m_bType = bType; + pMDDefaultValue->m_cbSize = cbValue; + switch (bType) + { + case ELEMENT_TYPE_BOOLEAN: + if (cbValue < 1) + { + IfFailGo(CLDB_E_FILE_CORRUPT); + } + pMDDefaultValue->m_bValue = *((BYTE *) pValue); + break; + case ELEMENT_TYPE_I1: + if (cbValue < 1) + { + IfFailGo(CLDB_E_FILE_CORRUPT); + } + pMDDefaultValue->m_cValue = *((CHAR *) pValue); + break; + case ELEMENT_TYPE_U1: + if (cbValue < 1) + { + IfFailGo(CLDB_E_FILE_CORRUPT); + } + pMDDefaultValue->m_byteValue = *((BYTE *) pValue); + break; + case ELEMENT_TYPE_I2: + if (cbValue < 2) + { + IfFailGo(CLDB_E_FILE_CORRUPT); + } + pMDDefaultValue->m_sValue = GET_UNALIGNED_VAL16(pValue); + break; + case ELEMENT_TYPE_U2: + case ELEMENT_TYPE_CHAR: + if (cbValue < 2) + { + IfFailGo(CLDB_E_FILE_CORRUPT); + } + pMDDefaultValue->m_usValue = GET_UNALIGNED_VAL16(pValue); + break; + case ELEMENT_TYPE_I4: + if (cbValue < 4) + { + IfFailGo(CLDB_E_FILE_CORRUPT); + } + pMDDefaultValue->m_lValue = GET_UNALIGNED_VAL32(pValue); + break; + case ELEMENT_TYPE_U4: + if (cbValue < 4) + { + IfFailGo(CLDB_E_FILE_CORRUPT); + } + pMDDefaultValue->m_ulValue = GET_UNALIGNED_VAL32(pValue); + break; + case ELEMENT_TYPE_R4: + { + if (cbValue < 4) + { + IfFailGo(CLDB_E_FILE_CORRUPT); + } + __int32 Value = GET_UNALIGNED_VAL32(pValue); + pMDDefaultValue->m_fltValue = (float &)Value; + } + break; + case ELEMENT_TYPE_R8: + { + if (cbValue < 8) + { + IfFailGo(CLDB_E_FILE_CORRUPT); + } + __int64 Value = GET_UNALIGNED_VAL64(pValue); + pMDDefaultValue->m_dblValue = (double &) Value; + } + break; + case ELEMENT_TYPE_STRING: + if (cbValue == 0) + pValue = NULL; + +#if BIGENDIAN + { + // We need to allocate and swap the string if we're on a big endian + pMDDefaultValue->m_wzValue = new WCHAR[(cbValue + 1) / sizeof (WCHAR)]; + _ASSERTE(FALSE); // Nothing ever free's this newly allocated array. Inserting assert so that if we ever actually + // use this code path, we'll fix it then. (Don't want to fix something I can't test.) + IfNullGo(pMDDefaultValue->m_wzValue); + memcpy(const_cast<WCHAR *>(pMDDefaultValue->m_wzValue), pValue, cbValue); + _ASSERTE(cbValue % sizeof(WCHAR) == 0); + SwapStringLength(const_cast<WCHAR *>(pMDDefaultValue->m_wzValue), cbValue / sizeof(WCHAR)); + } +#else + pMDDefaultValue->m_wzValue = (LPWSTR) pValue; +#endif + break; + case ELEMENT_TYPE_CLASS: + // + // There is only a 4-byte quantity in the MetaData, and it must always + // be zero. So, we load an INT32 and zero-extend it to be pointer-sized. + // + if (cbValue < 4) + { + IfFailGo(CLDB_E_FILE_CORRUPT); + } + pMDDefaultValue->m_unkValue = (IUnknown *)(UINT_PTR)GET_UNALIGNED_VAL32(pValue); + if (pMDDefaultValue->m_unkValue != NULL) + { + _ASSERTE(!"Non-NULL objectref's are not supported as default values!"); + IfFailGo(CLDB_E_FILE_CORRUPT); + } + break; + case ELEMENT_TYPE_I8: + if (cbValue < 8) + { + IfFailGo(CLDB_E_FILE_CORRUPT); + } + pMDDefaultValue->m_llValue = GET_UNALIGNED_VAL64(pValue); + break; + case ELEMENT_TYPE_U8: + if (cbValue < 8) + { + IfFailGo(CLDB_E_FILE_CORRUPT); + } + pMDDefaultValue->m_ullValue = GET_UNALIGNED_VAL64(pValue); + break; + case ELEMENT_TYPE_VOID: + break; + default: + _ASSERTE(!"BAD TYPE!"); + IfFailGo(CLDB_E_FILE_CORRUPT); + break; + } +ErrExit: + return hr; +} // _FillMDDefaultValue + +//***************************************************************************** +// Given a scope, return the table size and table ptr for a given index +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::GetTableInfoWithIndex( // return size + ULONG index, // [IN] pass in the index + void **pTable, // [OUT] pointer to table at index + void **pTableSize) // [OUT] size of table at index +{ + _ASSERTE(!"NYI"); + return E_NOTIMPL; +} // MDInternalRO::GetTableInfoWithIndex + + + +//***************************************************************************** +// Given a delta metadata byte stream, apply the changes to the current metadata +// object returning the resulting metadata object in ppv +//***************************************************************************** +__checkReturn +HRESULT MDInternalRO::ApplyEditAndContinue( + void *pDeltaMD, // [IN] the delta metadata + ULONG cbDeltaMD, // [IN] length of pData + IMDInternalImport **ppv) // [OUT] the resulting metadata interface +{ + _ASSERTE(pDeltaMD); + _ASSERTE(ppv); + + HRESULT hr = E_FAIL; + + IMDInternalImportENC *pDeltaMDImport = NULL; + + IfFailGo(GetInternalWithRWFormat(pDeltaMD, cbDeltaMD, 0, IID_IMDInternalImportENC, (void**)&pDeltaMDImport)); + + *ppv = this; + IfFailGo(MDApplyEditAndContinue(ppv, pDeltaMDImport)); + +ErrExit: + if (pDeltaMDImport) + pDeltaMDImport->Release(); + return hr; +} + +HRESULT MDInternalRO::GetRvaOffsetData( + DWORD *pFirstMethodRvaOffset, // [OUT] Offset (from start of metadata) to the first RVA field in MethodDef table. + DWORD *pMethodDefRecordSize, // [OUT] Size of each record in MethodDef table. + DWORD *pMethodDefCount, // [OUT] Number of records in MethodDef table. + DWORD *pFirstFieldRvaOffset, // [OUT] Offset (from start of metadata) to the first RVA field in FieldRVA table. + DWORD *pFieldRvaRecordSize, // [OUT] Size of each record in FieldRVA table. + DWORD *pFieldRvaCount) // [OUT] Number of records in FieldRVA table. +{ + HRESULT hr = S_OK; + DWORD methodDefCount = *pMethodDefCount = m_LiteWeightStgdb.m_MiniMd.getCountMethods(); + if (methodDefCount == 0) + *pFirstMethodRvaOffset = *pMethodDefRecordSize = 0; + else + { + MethodRec *pMethodRec; + IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetMethodRecord(1, &pMethodRec)); + + // RVA is the first column of the MethodDef table, so the address of MethodRec is also address of RVA column. + if ((const BYTE *)m_LiteWeightStgdb.m_pvMd > (const BYTE *)pMethodRec) + { + Debug_ReportError("Stream header is not within MetaData block."); + IfFailGo(CLDB_E_FILE_CORRUPT); + } + *pFirstMethodRvaOffset = (DWORD)((const BYTE *)pMethodRec - (const BYTE *)m_LiteWeightStgdb.m_pvMd); + *pMethodDefRecordSize = m_LiteWeightStgdb.m_MiniMd._CBREC(Method); + } + + { + DWORD fieldRvaCount = *pFieldRvaCount = m_LiteWeightStgdb.m_MiniMd.getCountFieldRVAs(); + if (fieldRvaCount == 0) + *pFirstFieldRvaOffset = *pFieldRvaRecordSize = 0; + else + { + + // orig + // FieldRVARec *pFieldRVARec = m_LiteWeightStgdb.m_MiniMd.getFieldRVA(1); + FieldRVARec *pFieldRVARec; + IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetFieldRVARecord(1, &pFieldRVARec)); + +//FieldRVARec *pFieldRVARec; +//mdToken fakeTok = 1; +//RidToToken(&fakeTok, mdtFieldDef); +//GetFieldRVA(fakeTok, &pFieldRVARec); + // RVA is the first column of the FieldRVA table, so the address of FieldRVARec is also address of RVA column. + if ((const BYTE *)m_LiteWeightStgdb.m_pvMd > (const BYTE *)pFieldRVARec) + { + Debug_ReportError("Stream header is not within MetaData block."); + IfFailGo(CLDB_E_FILE_CORRUPT); + } + *pFirstFieldRvaOffset = (DWORD)((const BYTE *)pFieldRVARec - (const BYTE *)m_LiteWeightStgdb.m_pvMd); + *pFieldRvaRecordSize = m_LiteWeightStgdb.m_MiniMd._CBREC(FieldRVA); + } + } + hr = S_OK; + +ErrExit: + return hr; +} + +#endif //FEATURE_METADATA_INTERNAL_APIS diff --git a/src/md/runtime/mdinternalro.h b/src/md/runtime/mdinternalro.h new file mode 100644 index 0000000000..92e5393ffa --- /dev/null +++ b/src/md/runtime/mdinternalro.h @@ -0,0 +1,849 @@ +// 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. +//***************************************************************************** +// MDInternalRO.h +// + +// +// Contains utility code for MD directory +// +//***************************************************************************** +#ifndef __MDInternalRO__h__ +#define __MDInternalRO__h__ + +#include "winmdinterfaces.h" + +#ifdef FEATURE_METADATA_INTERNAL_APIS + +class MDInternalRO : public IMDInternalImport, IMDCommon +{ +public: + + MDInternalRO(); + virtual ~MDInternalRO(); + __checkReturn + HRESULT Init(LPVOID pData, ULONG cbData); + + // *** IUnknown methods *** + __checkReturn + STDMETHODIMP QueryInterface(REFIID riid, void** ppv); + STDMETHODIMP_(ULONG) AddRef(void); + STDMETHODIMP_(ULONG) Release(void); + + __checkReturn + STDMETHODIMP TranslateSigWithScope( + IMDInternalImport *pAssemImport, // [IN] import assembly scope. + const void *pbHashValue, // [IN] hash value for the import assembly. + ULONG cbHashValue, // [IN] count of bytes in the hash value. + PCCOR_SIGNATURE pbSigBlob, // [IN] signature in the importing scope + ULONG cbSigBlob, // [IN] count of bytes of signature + IMetaDataAssemblyEmit *pAssemEmit, // [IN] assembly emit scope. + IMetaDataEmit *emit, // [IN] emit interface + CQuickBytes *pqkSigEmit, // [OUT] buffer to hold translated signature + ULONG *pcbSig) // [OUT] count of bytes in the translated signature + DAC_UNEXPECTED(); + + + __checkReturn + STDMETHODIMP GetTypeDefRefTokenInTypeSpec(// return S_FALSE if enclosing type does not have a token + mdTypeSpec tkTypeSpec, // [IN] TypeSpec token to look at + mdToken *tkEnclosedToken); // [OUT] The enclosed type token + + + + STDMETHODIMP_(IMetaModelCommon*) GetMetaModelCommon() + { + return static_cast<IMetaModelCommon*>(&m_LiteWeightStgdb.m_MiniMd); + } + + STDMETHODIMP_(IMetaModelCommonRO*) GetMetaModelCommonRO() + { + if (m_LiteWeightStgdb.m_MiniMd.IsWritable()) + { + _ASSERTE(!"IMetaModelCommonRO methods cannot be used because this importer is writable."); + return NULL; + } + return static_cast<IMetaModelCommonRO*>(&m_LiteWeightStgdb.m_MiniMd); + } + + __checkReturn + STDMETHODIMP SetOptimizeAccessForSpeed( + BOOL fOptSpeed) + { + // The metadata cache of hot items is an optional working-set optimization + // that has a large speed cost relative to direct table lookup + if (fOptSpeed) + { // We want to disable usage of hot data (e.g. in ngen compilation process) + m_LiteWeightStgdb.m_MiniMd.DisableHotDataUsage(); + } + return S_OK; + } + + //***************************************************************************** + // return the count of entries of a given kind in a scope + // For example, pass in mdtMethodDef will tell you how many MethodDef + // contained in a scope + //***************************************************************************** + STDMETHODIMP_(ULONG) GetCountWithTokenKind(// return hresult + DWORD tkKind) // [IN] pass in the kind of token. + DAC_UNEXPECTED(); + + //***************************************************************************** + // enumerator for typedef + //***************************************************************************** + __checkReturn + STDMETHODIMP EnumTypeDefInit( // return hresult + HENUMInternal *phEnum); // [OUT] buffer to fill for enumerator data + + STDMETHODIMP_(ULONG) EnumTypeDefGetCount( + HENUMInternal *phEnum); // [IN] the enumerator to retrieve information + + STDMETHODIMP_(void) EnumTypeDefReset( + HENUMInternal *phEnum); // [IN] the enumerator to retrieve information + + STDMETHODIMP_(bool) EnumTypeDefNext( // return hresult + HENUMInternal *phEnum, // [IN] input enum + mdTypeDef *ptd); // [OUT] return token + + STDMETHODIMP_(void) EnumTypeDefClose( + HENUMInternal *phEnum); // [IN] the enumerator to retrieve information + + //***************************************************************************** + // enumerator for MethodImpl + //***************************************************************************** + __checkReturn + STDMETHODIMP EnumMethodImplInit( // return hresult + mdTypeDef td, // [IN] TypeDef over which to scope the enumeration. + HENUMInternal *phEnumBody, // [OUT] buffer to fill for enumerator data for MethodBody tokens. + HENUMInternal *phEnumDecl); // [OUT] buffer to fill for enumerator data for MethodDecl tokens. + + STDMETHODIMP_(ULONG) EnumMethodImplGetCount( + HENUMInternal *phEnumBody, // [IN] MethodBody enumerator. + HENUMInternal *phEnumDecl); // [IN] MethodDecl enumerator. + + STDMETHODIMP_(void) EnumMethodImplReset( + HENUMInternal *phEnumBody, // [IN] MethodBody enumerator. + HENUMInternal *phEnumDecl); // [IN] MethodDecl enumerator. + + __checkReturn + STDMETHODIMP EnumMethodImplNext( // return hresult + HENUMInternal *phEnumBody, // [IN] input enum for MethodBody + HENUMInternal *phEnumDecl, // [IN] input enum for MethodDecl + mdToken *ptkBody, // [OUT] return token for MethodBody + mdToken *ptkDecl); // [OUT] return token for MethodDecl + + STDMETHODIMP_(void) EnumMethodImplClose( + HENUMInternal *phEnumBody, // [IN] MethodBody enumerator. + HENUMInternal *phEnumDecl); // [IN] MethodDecl enumerator. + + //***************************************** + // Enumerator helpers for memberdef, memberref, interfaceimp, + // event, property, param, methodimpl + //***************************************** + + __checkReturn + STDMETHODIMP EnumGlobalFunctionsInit( // return hresult + HENUMInternal *phEnum); // [OUT] buffer to fill for enumerator data + + __checkReturn + STDMETHODIMP EnumGlobalFieldsInit( // return hresult + HENUMInternal *phEnum); // [OUT] buffer to fill for enumerator data + + __checkReturn + STDMETHODIMP EnumInit( // return S_FALSE if record not found + DWORD tkKind, // [IN] which table to work on + mdToken tkParent, // [IN] token to scope the search + HENUMInternal *phEnum); // [OUT] the enumerator to fill + + __checkReturn + STDMETHODIMP EnumAllInit( // return S_FALSE if record not found + DWORD tkKind, // [IN] which table to work on + HENUMInternal *phEnum); // [OUT] the enumerator to fill + + STDMETHODIMP_(bool) EnumNext( + HENUMInternal *phEnum, // [IN] the enumerator to retrieve information + mdToken *ptk); // [OUT] token to scope the search + + STDMETHODIMP_(ULONG) EnumGetCount( + HENUMInternal *phEnum); // [IN] the enumerator to retrieve information + + STDMETHODIMP_(void) EnumReset( + HENUMInternal *phEnum); // [IN] the enumerator to be reset + + STDMETHODIMP_(void) EnumClose( + HENUMInternal *phEnum); // [IN] the enumerator to be closed + + __checkReturn + STDMETHODIMP EnumPermissionSetsInit( // return S_FALSE if record not found + mdToken tkParent, // [IN] token to scope the search + CorDeclSecurity Action, // [IN] Action to scope the search + HENUMInternal *phEnum); // [OUT] the enumerator to fill + + __checkReturn + STDMETHODIMP EnumCustomAttributeByNameInit(// return S_FALSE if record not found + mdToken tkParent, // [IN] token to scope the search + LPCSTR szName, // [IN] CustomAttribute's name to scope the search + HENUMInternal *phEnum); // [OUT] the enumerator to fill + + __checkReturn + STDMETHODIMP GetParentToken( + mdToken tkChild, // [IN] given child token + mdToken *ptkParent); // [OUT] returning parent + + __checkReturn + STDMETHODIMP GetCustomAttributeProps( + mdCustomAttribute at, // [IN] The attribute. + mdToken *ptkType); // [OUT] Put attribute type here. + + __checkReturn + STDMETHODIMP GetCustomAttributeAsBlob( + mdCustomAttribute cv, // [IN] given custom attribute token + void const **ppBlob, // [OUT] return the pointer to internal blob + ULONG *pcbSize); // [OUT] return the size of the blob + + __checkReturn + STDMETHODIMP GetCustomAttributeByName( // S_OK or error. + mdToken tkObj, // [IN] Object with Custom Attribute. + LPCUTF8 szName, // [IN] Name of desired Custom Attribute. + const void **ppData, // [OUT] Put pointer to data here. + ULONG *pcbData); // [OUT] Put size of data here. + + __checkReturn + STDMETHODIMP GetNameOfCustomAttribute( // S_OK or error. + mdCustomAttribute mdAttribute, // [IN] The Custom Attribute + LPCUTF8 *pszNamespace, // [OUT] Namespace of Custom Attribute. + LPCUTF8 *pszName); // [OUT] Name of Custom Attribute. + + __checkReturn + STDMETHODIMP SafeAndSlowEnumCustomAttributeByNameInit(// return S_FALSE if record not found + mdToken tkParent, // [IN] token to scope the search + LPCSTR szName, // [IN] CustomAttribute's name to scope the search + HENUMInternal *phEnum); // [OUT] The enumerator + + __checkReturn + STDMETHODIMP SafeAndSlowEnumCustomAttributeByNameNext(// return S_FALSE if record not found + mdToken tkParent, // [IN] token to scope the search + LPCSTR szName, // [IN] CustomAttribute's name to scope the search + HENUMInternal *phEnum, // [IN] The enumerator + mdCustomAttribute *mdAttribute); // [OUT] The custom attribute that was found + + __checkReturn + STDMETHODIMP GetScopeProps( + LPCSTR *pszName, // [OUT] scope name + GUID *pmvid); // [OUT] version id + + // finding a particular method + __checkReturn + STDMETHODIMP FindMethodDef( + mdTypeDef classdef, // [IN] given typedef + LPCSTR szName, // [IN] member name + PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of COM+ signature + ULONG cbSigBlob, // [IN] count of bytes in the signature blob + mdMethodDef *pmd); // [OUT] matching memberdef + + // return a iSeq's param given a MethodDef + __checkReturn + STDMETHODIMP FindParamOfMethod( // S_OK or error. + mdMethodDef md, // [IN] The owning method of the param. + ULONG iSeq, // [IN] The sequence # of the param. + mdParamDef *pparamdef); // [OUT] Put ParamDef token here. + + //***************************************** + // + // GetName* functions + // + //***************************************** + + // return the name and namespace of typedef + __checkReturn + STDMETHODIMP GetNameOfTypeDef( + mdTypeDef classdef, // given classdef + LPCSTR *pszname, // return class name(unqualified) + LPCSTR *psznamespace); // return the name space name + + __checkReturn + STDMETHODIMP GetIsDualOfTypeDef( + mdTypeDef classdef, // [IN] given classdef. + ULONG *pDual); // [OUT] return dual flag here. + + __checkReturn + STDMETHODIMP GetIfaceTypeOfTypeDef( + mdTypeDef classdef, // [IN] given classdef. + ULONG *pIface); // [OUT] 0=dual, 1=vtable, 2=dispinterface + + // get the name of either methoddef + __checkReturn + STDMETHODIMP GetNameOfMethodDef( // return the name of the memberdef in UTF8 + mdMethodDef md, // given memberdef + LPCSTR *pszName); + + __checkReturn + STDMETHODIMP GetNameAndSigOfMethodDef( + mdMethodDef methoddef, // [IN] given memberdef + PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to a blob value of COM+ signature + ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob + LPCSTR *pszName); + + // return the name of a FieldDef + __checkReturn + STDMETHODIMP GetNameOfFieldDef( + mdFieldDef fd, // given memberdef + LPCSTR *pszName); + + // return the name of typeref + __checkReturn + STDMETHODIMP GetNameOfTypeRef( + mdTypeRef classref, // [IN] given typeref + LPCSTR *psznamespace, // [OUT] return typeref name + LPCSTR *pszname); // [OUT] return typeref namespace + + // return the resolutionscope of typeref + __checkReturn + STDMETHODIMP GetResolutionScopeOfTypeRef( + mdTypeRef classref, // given classref + mdToken *ptkResolutionScope); + + // return the typeref token given the name. + __checkReturn + STDMETHODIMP FindTypeRefByName( + LPCSTR szNamespace, // [IN] Namespace for the TypeRef. + LPCSTR szName, // [IN] Name of the TypeRef. + mdToken tkResolutionScope, // [IN] Resolution Scope fo the TypeRef. + mdTypeRef *ptk); // [OUT] TypeRef token returned. + + // return the TypeDef properties + __checkReturn + STDMETHODIMP GetTypeDefProps( // return hresult + mdTypeDef classdef, // given classdef + DWORD *pdwAttr, // return flags on class, tdPublic, tdAbstract + mdToken *ptkExtends); // [OUT] Put base class TypeDef/TypeRef here. + + // return the item's guid + __checkReturn + STDMETHODIMP GetItemGuid( // return hresult + mdToken tkObj, // [IN] given item. + CLSID *pGuid); // [OUT] Put guid here. + + // get enclosing class of NestedClass. + __checkReturn + STDMETHODIMP GetNestedClassProps( // S_OK or error + mdTypeDef tkNestedClass, // [IN] NestedClass token. + mdTypeDef *ptkEnclosingClass); // [OUT] EnclosingClass token. + + // Get count of Nested classes given the enclosing class. + __checkReturn + STDMETHODIMP GetCountNestedClasses( // return count of Nested classes. + mdTypeDef tkEnclosingClass, // [IN]Enclosing class. + ULONG *pcNestedClassesCount); + + // Return array of Nested classes given the enclosing class. + __checkReturn + STDMETHODIMP GetNestedClasses( // Return actual count. + mdTypeDef tkEnclosingClass, // [IN] Enclosing class. + mdTypeDef *rNestedClasses, // [OUT] Array of nested class tokens. + ULONG ulNestedClasses, // [IN] Size of array. + ULONG *pcNestedClasses); + + // return the ModuleRef properties + __checkReturn + STDMETHODIMP GetModuleRefProps( + mdModuleRef mur, // [IN] moduleref token + LPCSTR *pszName); // [OUT] buffer to fill with the moduleref name + + //***************************************** + // + // GetSig* functions + // + //***************************************** + __checkReturn + STDMETHODIMP GetSigOfMethodDef( + mdMethodDef methoddef, // [IN] given memberdef + ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob + PCCOR_SIGNATURE *ppSig); + + __checkReturn + STDMETHODIMP GetSigOfFieldDef( + mdMethodDef methoddef, // [IN] given memberdef + ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob + PCCOR_SIGNATURE *ppSig); + + __checkReturn + STDMETHODIMP GetSigFromToken( + mdToken tk, // FieldDef, MethodDef, Signature or TypeSpec token + ULONG * pcbSig, + PCCOR_SIGNATURE * ppSig); + + + + //***************************************** + // get method property + //***************************************** + __checkReturn + STDMETHODIMP GetMethodDefProps( + mdMethodDef md, // The method for which to get props. + DWORD *pdwFlags); + + __checkReturn + STDMETHODIMP_(ULONG) GetMethodDefSlot( + mdMethodDef mb); // The method for which to get props. + + //***************************************** + // return method implementation informaiton, like RVA and implflags + //***************************************** + __checkReturn + STDMETHODIMP GetMethodImplProps( + mdMethodDef tk, // [IN] MethodDef + ULONG *pulCodeRVA, // [OUT] CodeRVA + DWORD *pdwImplFlags); // [OUT] Impl. Flags + + //***************************************************************************** + // return the field RVA + //***************************************************************************** + __checkReturn + STDMETHODIMP GetFieldRVA( + mdToken fd, // [IN] FieldDef + ULONG *pulCodeRVA); // [OUT] CodeRVA + + //***************************************************************************** + // return the field offset for a given field + //***************************************************************************** + __checkReturn + STDMETHODIMP GetFieldOffset( + mdFieldDef fd, // [IN] fielddef + ULONG *pulOffset); // [OUT] FieldOffset + + //***************************************** + // get field property + //***************************************** + __checkReturn + STDMETHODIMP GetFieldDefProps( + mdFieldDef fd, // [IN] given fielddef + DWORD *pdwFlags); // [OUT] return fdPublic, fdPrive, etc flags + + //***************************************************************************** + // return default value of a token (could be paramdef, fielddef, or property) + //***************************************************************************** + __checkReturn + STDMETHODIMP GetDefaultValue( + mdToken tk, // [IN] given FieldDef, ParamDef, or Property + MDDefaultValue *pDefaultValue); // [OUT] default value to fill + + + //***************************************** + // get dispid of a MethodDef or a FieldDef + //***************************************** + __checkReturn + STDMETHODIMP GetDispIdOfMemberDef( // return hresult + mdToken tk, // [IN] given methoddef or fielddef + ULONG *pDispid); // [OUT] Put the dispid here. + + //***************************************** + // return TypeRef/TypeDef given an InterfaceImpl token + //***************************************** + __checkReturn + STDMETHODIMP GetTypeOfInterfaceImpl( // return the TypeRef/typedef token for the interfaceimpl + mdInterfaceImpl iiImpl, // given a interfaceimpl + mdToken *ptkType); + + //***************************************** + // return information about a generic method instantiation + //***************************************** + __checkReturn + STDMETHODIMP GetMethodSpecProps( + mdMethodSpec mi, // [IN] The method instantiation + mdToken *tkParent, // [OUT] MethodDef or MemberRef + PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to the blob value of meta data + ULONG *pcbSigBlob); // [OUT] actual size of signature blob + + //***************************************** + // look up function for TypeDef + //***************************************** + __checkReturn + STDMETHODIMP FindTypeDef( + LPCSTR szNamespace, // [IN] Namespace for the TypeDef. + LPCSTR szName, // [IN] Name of the TypeDef. + mdToken tkEnclosingClass, // [IN] TypeDef/TypeRef of enclosing class. + mdTypeDef *ptypedef); // [OUT] return typedef + + __checkReturn + STDMETHODIMP FindTypeDefByGUID( + REFGUID guid, // guid to look up + mdTypeDef *ptypedef); // return typedef + + + + //***************************************** + // return name and sig of a memberref + //***************************************** + __checkReturn + STDMETHODIMP GetNameAndSigOfMemberRef( // return name here + mdMemberRef memberref, // given memberref + PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to a blob value of COM+ signature + ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob + LPCSTR *pszName); + + //***************************************************************************** + // Given memberref, return the parent. It can be TypeRef, ModuleRef, MethodDef + //***************************************************************************** + __checkReturn + STDMETHODIMP GetParentOfMemberRef( + mdMemberRef memberref, // given memberref + mdToken *ptkParent); // return the parent token + + __checkReturn + STDMETHODIMP GetParamDefProps( + mdParamDef paramdef, // given a paramdef + USHORT *pusSequence, // [OUT] slot number for this parameter + DWORD *pdwAttr, // [OUT] flags + LPCSTR *pszName); // [OUT] return the name of the parameter + + //****************************************** + // property info for method. + //****************************************** + __checkReturn + STDMETHODIMP GetPropertyInfoForMethodDef( // Result. + mdMethodDef md, // [IN] memberdef + mdProperty *ppd, // [OUT] put property token here + LPCSTR *pName, // [OUT] put pointer to name here + ULONG *pSemantic) // [OUT] put semantic here + DAC_UNEXPECTED(); + + //***************************************** + // class layout/sequence information + //***************************************** + __checkReturn + STDMETHODIMP GetClassPackSize( // [OUT] return error if a class doesn't have packsize info + mdTypeDef td, // [IN] give typedef + ULONG *pdwPackSize); // [OUT] return the pack size of the class. 1, 2, 4, 8 or 16 + + __checkReturn + STDMETHODIMP GetClassTotalSize( // [OUT] return error if a class doesn't have total size info + mdTypeDef td, // [IN] give typedef + ULONG *pdwClassSize); // [OUT] return the total size of the class + + __checkReturn + STDMETHODIMP GetClassLayoutInit( + mdTypeDef td, // [IN] give typedef + MD_CLASS_LAYOUT *pLayout); // [OUT] set up the status of query here + + __checkReturn + STDMETHODIMP GetClassLayoutNext( + MD_CLASS_LAYOUT *pLayout, // [IN|OUT] set up the status of query here + mdFieldDef *pfd, // [OUT] return the fielddef + ULONG *pulOffset); // [OUT] return the offset/ulSequence associate with it + + //***************************************** + // marshal information of a field + //***************************************** + __checkReturn + STDMETHODIMP GetFieldMarshal( // return error if no native type associate with the token + mdFieldDef fd, // [IN] given fielddef + PCCOR_SIGNATURE *pSigNativeType, // [OUT] the native type signature + ULONG *pcbNativeType); // [OUT] the count of bytes of *ppvNativeType + + + //***************************************** + // property APIs + //***************************************** + // find a property by name + __checkReturn + STDMETHODIMP FindProperty( + mdTypeDef td, // [IN] given a typdef + LPCSTR szPropName, // [IN] property name + mdProperty *pProp); // [OUT] return property token + + __checkReturn + STDMETHODIMP GetPropertyProps( + mdProperty prop, // [IN] property token + LPCSTR *szProperty, // [OUT] property name + DWORD *pdwPropFlags, // [OUT] property flags. + PCCOR_SIGNATURE *ppvSig, // [OUT] property type. pointing to meta data internal blob + ULONG *pcbSig); // [OUT] count of bytes in *ppvSig + + //********************************** + // Event APIs + //********************************** + __checkReturn + STDMETHODIMP FindEvent( + mdTypeDef td, // [IN] given a typdef + LPCSTR szEventName, // [IN] event name + mdEvent *pEvent); // [OUT] return event token + + __checkReturn + STDMETHODIMP GetEventProps( // S_OK, S_FALSE, or error. + mdEvent ev, // [IN] event token + LPCSTR *pszEvent, // [OUT] Event name + DWORD *pdwEventFlags, // [OUT] Event flags. + mdToken *ptkEventType); // [OUT] EventType class + + //********************************** + // Generics APIs + //********************************** + __checkReturn + STDMETHODIMP GetGenericParamProps( // S_OK or error. + mdGenericParam rd, // [IN] The type parameter + ULONG* pulSequence, // [OUT] Parameter sequence number + DWORD* pdwAttr, // [OUT] Type parameter flags (for future use) + mdToken *ptOwner, // [OUT] The owner (TypeDef or MethodDef) + DWORD *reserved, // [OUT] The kind (TypeDef/Ref/Spec, for future use) + LPCSTR *szName); // [OUT] The name + + __checkReturn + STDMETHODIMP GetGenericParamConstraintProps( // S_OK or error. + mdGenericParamConstraint rd, // [IN] The constraint token + mdGenericParam *ptGenericParam, // [OUT] GenericParam that is constrained + mdToken *ptkConstraintType); // [OUT] TypeDef/Ref/Spec constraint + + + //********************************** + // find a particular associate of a property or an event + //********************************** + __checkReturn + STDMETHODIMP FindAssociate( + mdToken evprop, // [IN] given a property or event token + DWORD associate, // [IN] given a associate semantics(setter, getter, testdefault, reset, AddOn, RemoveOn, Fire) + mdMethodDef *pmd); // [OUT] return method def token + + __checkReturn + STDMETHODIMP EnumAssociateInit( + mdToken evprop, // [IN] given a property or an event token + HENUMInternal *phEnum); // [OUT] cursor to hold the query result + + __checkReturn + STDMETHODIMP GetAllAssociates( + HENUMInternal *phEnum, // [IN] query result form GetPropertyAssociateCounts + ASSOCIATE_RECORD *pAssociateRec, // [OUT] struct to fill for output + ULONG cAssociateRec); // [IN] size of the buffer + + + //********************************** + // Get info about a PermissionSet. + //********************************** + __checkReturn + STDMETHODIMP GetPermissionSetProps( + mdPermission pm, // [IN] the permission token. + DWORD *pdwAction, // [OUT] CorDeclSecurity. + void const **ppvPermission, // [OUT] permission blob. + ULONG *pcbPermission); // [OUT] count of bytes of pvPermission. + + //**************************************** + // Get the String given the String token. + // Returns a pointer to the string, or NULL in case of error. + //**************************************** + __checkReturn + STDMETHODIMP GetUserString( + mdString stk, // [IN] the string token. + ULONG *pchString, // [OUT] count of characters in the string. + BOOL *pbIs80Plus, // [OUT] specifies where there are extended characters >= 0x80. + LPCWSTR *pwszUserString); + + //***************************************************************************** + // p-invoke APIs. + //***************************************************************************** + __checkReturn + STDMETHODIMP GetPinvokeMap( + mdMethodDef tk, // [IN] FieldDef or MethodDef. + DWORD *pdwMappingFlags, // [OUT] Flags used for mapping. + LPCSTR *pszImportName, // [OUT] Import name. + mdModuleRef *pmrImportDLL); // [OUT] ModuleRef token for the target DLL. + + //***************************************************************************** + // Assembly MetaData APIs. + //***************************************************************************** + __checkReturn + STDMETHODIMP GetAssemblyProps( + mdAssembly mda, // [IN] The Assembly for which to get the properties. + const void **ppbPublicKey, // [OUT] Pointer to the public key. + ULONG *pcbPublicKey, // [OUT] Count of bytes in the public key. + ULONG *pulHashAlgId, // [OUT] Hash Algorithm. + LPCSTR *pszName, // [OUT] Buffer to fill with name. + AssemblyMetaDataInternal *pMetaData,// [OUT] Assembly MetaData. + DWORD *pdwAssemblyFlags); // [OUT] Flags. + + __checkReturn + STDMETHODIMP GetAssemblyRefProps( + mdAssemblyRef mdar, // [IN] The AssemblyRef for which to get the properties. + const void **ppbPublicKeyOrToken, // [OUT] Pointer to the public key or token. + ULONG *pcbPublicKeyOrToken, // [OUT] Count of bytes in the public key or token. + LPCSTR *pszName, // [OUT] Buffer to fill with name. + AssemblyMetaDataInternal *pMetaData,// [OUT] Assembly MetaData. + const void **ppbHashValue, // [OUT] Hash blob. + ULONG *pcbHashValue, // [OUT] Count of bytes in the hash blob. + DWORD *pdwAssemblyRefFlags); // [OUT] Flags. + + __checkReturn + STDMETHODIMP GetFileProps( + mdFile mdf, // [IN] The File for which to get the properties. + LPCSTR *pszName, // [OUT] Buffer to fill with name. + const void **ppbHashValue, // [OUT] Pointer to the Hash Value Blob. + ULONG *pcbHashValue, // [OUT] Count of bytes in the Hash Value Blob. + DWORD *pdwFileFlags); // [OUT] Flags. + + __checkReturn + STDMETHODIMP GetExportedTypeProps( + mdExportedType mdct, // [IN] The ExportedType for which to get the properties. + LPCSTR *pszNamespace, // [OUT] Buffer to fill with namespace. + LPCSTR *pszName, // [OUT] Buffer to fill with name. + mdToken *ptkImplementation, // [OUT] mdFile or mdAssemblyRef that provides the ExportedType. + mdTypeDef *ptkTypeDef, // [OUT] TypeDef token within the file. + DWORD *pdwExportedTypeFlags); // [OUT] Flags. + + __checkReturn + STDMETHODIMP GetManifestResourceProps( + mdManifestResource mdmr, // [IN] The ManifestResource for which to get the properties. + LPCSTR *pszName, // [OUT] Buffer to fill with name. + mdToken *ptkImplementation, // [OUT] mdFile or mdAssemblyRef that provides the ExportedType. + DWORD *pdwOffset, // [OUT] Offset to the beginning of the resource within the file. + DWORD *pdwResourceFlags); // [OUT] Flags. + + __checkReturn + STDMETHODIMP FindExportedTypeByName( // S_OK or error + LPCSTR szNamespace, // [IN] Namespace of the ExportedType. + LPCSTR szName, // [IN] Name of the ExportedType. + mdExportedType tkEnclosingType, // [IN] Enclosing ExportedType. + mdExportedType *pmct); // [OUT] Put ExportedType token here. + + __checkReturn + STDMETHODIMP FindManifestResourceByName(// S_OK or error + LPCSTR szName, // [IN] Name of the resource. + mdManifestResource *pmmr); // [OUT] Put ManifestResource token here. + + __checkReturn + STDMETHODIMP GetAssemblyFromScope( // S_OK or error + mdAssembly *ptkAssembly); // [OUT] Put token here. + + //*************************************************************************** + // return properties regarding a TypeSpec + //*************************************************************************** + __checkReturn + STDMETHODIMP GetTypeSpecFromToken( // S_OK or error. + mdTypeSpec typespec, // [IN] Signature token. + PCCOR_SIGNATURE *ppvSig, // [OUT] return pointer to token. + ULONG *pcbSig); // [OUT] return size of signature. + + //***************************************************************************** + // This function gets the "built for" version of a metadata scope. + // NOTE: if the scope has never been saved, it will not have a built-for + // version, and an empty string will be returned. + //***************************************************************************** + __checkReturn + STDMETHODIMP GetVersionString( // S_OK or error. + LPCSTR *pVer); // [OUT] Put version string here. + + + //***************************************************************************** + // helpers to convert a text signature to a com format + //***************************************************************************** + __checkReturn + STDMETHODIMP ConvertTextSigToComSig( // Return hresult. + BOOL fCreateTrIfNotFound, // [IN] create typeref if not found + LPCSTR pSignature, // [IN] class file format signature + CQuickBytes *pqbNewSig, // [OUT] place holder for COM+ signature + ULONG *pcbCount); // [OUT] the result size of signature + + __checkReturn + STDMETHODIMP SetUserContextData( // S_OK or E_NOTIMPL + IUnknown *pIUnk) // The user context. + { return E_NOTIMPL; } + + STDMETHODIMP_(BOOL) IsValidToken( // True or False. + mdToken tk); // [IN] Given token. + + STDMETHODIMP_(IUnknown *) GetCachedPublicInterface(BOOL fWithLock) { return NULL;} // return the cached public interface + __checkReturn + STDMETHODIMP SetCachedPublicInterface(IUnknown *pUnk) { return E_FAIL;} ;// return hresult + STDMETHODIMP_(UTSemReadWrite*) GetReaderWriterLock() {return NULL;} // return the reader writer lock + __checkReturn + STDMETHODIMP SetReaderWriterLock(UTSemReadWrite *pSem) { return NOERROR; } + STDMETHODIMP_(mdModule) GetModuleFromScope(void); + + // Find a paticular method and pass in the signature comparison routine. Very + // helpful when the passed in signature does not come from the same scope. + __checkReturn + STDMETHODIMP FindMethodDefUsingCompare( + mdTypeDef classdef, // [IN] given typedef + LPCSTR szName, // [IN] member name + PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of COM+ signature + ULONG cbSigBlob, // [IN] count of bytes in the signature blob + PSIGCOMPARE pSignatureCompare, // [IN] Routine to compare signatures + void* pSignatureArgs, // [IN] Additional info to supply the compare function + mdMethodDef *pmd); // [OUT] matching memberdef + + + //***************************************************************************** + // return the table pointer and size for a given table index + //***************************************************************************** + __checkReturn + STDMETHODIMP GetTableInfoWithIndex( + ULONG index, // [IN] pass in the index + void **pTable, // [OUT] pointer to table at index + void **pTableSize); // [OUT] size of table at index + + __checkReturn + STDMETHODIMP ApplyEditAndContinue( + void *pData, // [IN] the delta metadata + ULONG cbData, // [IN] length of pData + IMDInternalImport **ppv); // [OUT] the resulting metadata interface + + STDMETHODIMP GetRvaOffsetData( + DWORD *pFirstMethodRvaOffset, // [OUT] Offset (from start of metadata) to the first RVA field in MethodDef table. + DWORD *pMethodDefRecordSize, // [OUT] Size of each record in MethodDef table. + DWORD *pMethodDefCount, // [OUT] Number of records in MethodDef table. + DWORD *pFirstFieldRvaOffset, // [OUT] Offset (from start of metadata) to the first RVA field in FieldRVA table. + DWORD *pFieldRvaRecordSize, // [OUT] Size of each record in FieldRVA table. + DWORD *pFieldRvaCount // [OUT] Number of records in FieldRVA table. + ); + + CLiteWeightStgdb<CMiniMd> m_LiteWeightStgdb; + +private: + + struct CMethodSemanticsMap + { + mdToken m_mdMethod; // Method token. + RID m_ridSemantics; // RID of semantics record. + }; + CMethodSemanticsMap *m_pMethodSemanticsMap; // Possible array of method semantics pointers, ordered by method token. + +#ifndef DACCESS_COMPILE + class CMethodSemanticsMapSorter : public CQuickSort<CMethodSemanticsMap> + { + public: + CMethodSemanticsMapSorter(CMethodSemanticsMap *pBase, int iCount) : CQuickSort<CMethodSemanticsMap>(pBase, iCount) {} + virtual int Compare(CMethodSemanticsMap *psFirst, CMethodSemanticsMap *psSecond); + }; +#endif //!DACCESS_COMPILE + + class CMethodSemanticsMapSearcher : public CBinarySearch<CMethodSemanticsMap> + { + public: + CMethodSemanticsMapSearcher(const CMethodSemanticsMap *pBase, int iCount) : CBinarySearch<CMethodSemanticsMap>(pBase, iCount) {} + virtual int Compare(const CMethodSemanticsMap *psFirst, const CMethodSemanticsMap *psSecond); + }; + + static BOOL CompareSignatures(PCCOR_SIGNATURE pvFirstSigBlob, DWORD cbFirstSigBlob, + PCCOR_SIGNATURE pvSecondSigBlob, DWORD cbSecondSigBlob, + void* SigARguments); + + mdTypeDef m_tdModule; // <Module> typedef value. + LONG m_cRefs; // Ref count. + +public: + STDMETHODIMP_(DWORD) GetMetadataStreamVersion() + { + return (DWORD)m_LiteWeightStgdb.m_MiniMd.m_Schema.m_minor | + ((DWORD)m_LiteWeightStgdb.m_MiniMd.m_Schema.m_major << 16); + }; + + STDMETHODIMP SetVerifiedByTrustedSource(// return hresult + BOOL fVerified) + { + m_LiteWeightStgdb.m_MiniMd.SetVerifiedByTrustedSource(fVerified); + return S_OK; + } +}; // class MDInternalRO + +#endif //FEATURE_METADATA_INTERNAL_APIS + +#endif // __MDInternalRO__h__ diff --git a/src/md/runtime/metamodel.cpp b/src/md/runtime/metamodel.cpp new file mode 100644 index 0000000000..293e5b6b5e --- /dev/null +++ b/src/md/runtime/metamodel.cpp @@ -0,0 +1,1240 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +//***************************************************************************** +// MetaModel.cpp -- Base portion of compressed COM+ metadata. +// + +// +//***************************************************************************** +#include "stdafx.h" + +#include <metamodel.h> +#include <corerror.h> +#include <posterror.h> + +//***************************************************************************** +// meta-meta model. +//***************************************************************************** + +//----------------------------------------------------------------------------- +// Start of column definitions. +//----------------------------------------------------------------------------- +// Column type, offset, size. +#define SCHEMA_TABLE_START(tbl) static CMiniColDef r##tbl##Cols[] = { +#define SCHEMA_ITEM_NOFIXED() +#define SCHEMA_ITEM_ENTRY(col,typ) {typ, 0,0}, +#define SCHEMA_ITEM_ENTRY2(col,typ,ofs,siz) {typ, ofs, siz}, +#define SCHEMA_ITEM(tbl,typ,col) SCHEMA_ITEM_ENTRY2(col, i##typ, offsetof(tbl##Rec,m_##col), sizeof(((tbl##Rec*)(0))->m_##col)) +#define SCHEMA_ITEM_RID(tbl,col,tbl2) SCHEMA_ITEM_ENTRY(col,TBL_##tbl2) +#define SCHEMA_ITEM_STRING(tbl,col) SCHEMA_ITEM_ENTRY(col,iSTRING) +#define SCHEMA_ITEM_GUID(tbl,col) SCHEMA_ITEM_ENTRY(col,iGUID) +#define SCHEMA_ITEM_BLOB(tbl,col) SCHEMA_ITEM_ENTRY(col,iBLOB) +#define SCHEMA_ITEM_CDTKN(tbl,col,tkns) SCHEMA_ITEM_ENTRY(col,iCodedToken+(CDTKN_##tkns)) +#define SCHEMA_TABLE_END(tbl) }; +//----------------------------------------------------------------------------- +#include "metamodelcolumndefs.h" +//----------------------------------------------------------------------------- +#undef SCHEMA_TABLE_START +#undef SCHEMA_ITEM_NOFIXED +#undef SCHEMA_ITEM_ENTRY +#undef SCHEMA_ITEM_ENTRY2 +#undef SCHEMA_ITEM +#undef SCHEMA_ITEM_RID +#undef SCHEMA_ITEM_STRING +#undef SCHEMA_ITEM_GUID +#undef SCHEMA_ITEM_BLOB +#undef SCHEMA_ITEM_CDTKN +#undef SCHEMA_TABLE_END +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Column names. +#define SCHEMA_TABLE_START(tbl) static const char *r##tbl##ColNames[] = { +#define SCHEMA_ITEM_NOFIXED() +#define SCHEMA_ITEM_ENTRY(col,typ) #col, +#define SCHEMA_ITEM_ENTRY2(col,typ,ofs,siz) #col, +#define SCHEMA_ITEM(tbl,typ,col) SCHEMA_ITEM_ENTRY2(col, i##typ, offsetof(tbl##Rec,m_##col), sizeof(((tbl##Rec*)(0))->m_##col)) +#define SCHEMA_ITEM_RID(tbl,col,tbl2) SCHEMA_ITEM_ENTRY(col,TBL_##tbl2) +#define SCHEMA_ITEM_STRING(tbl,col) SCHEMA_ITEM_ENTRY(col,iSTRING) +#define SCHEMA_ITEM_GUID(tbl,col) SCHEMA_ITEM_ENTRY(col,iGUID) +#define SCHEMA_ITEM_BLOB(tbl,col) SCHEMA_ITEM_ENTRY(col,iBLOB) +#define SCHEMA_ITEM_CDTKN(tbl,col,tkns) SCHEMA_ITEM_ENTRY(col,iCodedToken+(CDTKN_##tkns)) +#define SCHEMA_TABLE_END(tbl) }; +//----------------------------------------------------------------------------- +#include "metamodelcolumndefs.h" +//----------------------------------------------------------------------------- +#undef SCHEMA_TABLE_START +#undef SCHEMA_ITEM_NOFIXED +#undef SCHEMA_ITEM_ENTRY +#undef SCHEMA_ITEM_ENTRY2 +#undef SCHEMA_ITEM +#undef SCHEMA_ITEM_RID +#undef SCHEMA_ITEM_STRING +#undef SCHEMA_ITEM_GUID +#undef SCHEMA_ITEM_BLOB +#undef SCHEMA_ITEM_CDTKN +#undef SCHEMA_TABLE_END + +//----------------------------------------------------------------------------- +// End of column definitions. +//----------------------------------------------------------------------------- + +// Define the array of Coded Token Definitions. +#define MiniMdCodedToken(x) {lengthof(CMiniMdBase::mdt##x), CMiniMdBase::mdt##x, #x}, +const CCodedTokenDef g_CodedTokens [] = { + MiniMdCodedTokens() +}; +#undef MiniMdCodedToken + +// Define the array of Table Definitions. +#undef MiniMdTable +#define MiniMdTable(x) { { r##x##Cols, lengthof(r##x##Cols), x##Rec::COL_KEY, 0 }, r##x##ColNames, #x}, +const CMiniTableDefEx g_Tables[TBL_COUNT] = { + MiniMdTables() +}; + +// Define a table descriptor for the obsolete v1.0 GenericParam table definition. +const CMiniTableDefEx g_Table_GenericParamV1_1 = { { rGenericParamV1_1Cols, lengthof(rGenericParamV1_1Cols), GenericParamV1_1Rec::COL_KEY, 0 }, rGenericParamV1_1ColNames, "GenericParamV1_"}; + + + +// Define the array of Ptr Tables. This is initialized to TBL_COUNT here. +// The correct values will be set in the constructor for MiniMdRW. +#undef MiniMdTable +#define MiniMdTable(x) { TBL_COUNT, 0 }, +TblCol g_PtrTableIxs[TBL_COUNT] = { + MiniMdTables() +}; + +//***************************************************************************** +// Initialize a new schema. +//***************************************************************************** +HRESULT +CMiniMdSchema::InitNew( + MetadataVersion mdVersion) +{ + // Make sure the tables fit in the mask. + _ASSERTE((sizeof(m_maskvalid) * 8) > TBL_COUNT); + + m_ulReserved = 0; + + if(mdVersion == MDVersion1) + { + m_major = METAMODEL_MAJOR_VER_V1_0; + m_minor = METAMODEL_MINOR_VER_V1_0; + } + else if (mdVersion == MDVersion2) + { + m_major = METAMODEL_MAJOR_VER; + m_minor = METAMODEL_MINOR_VER; + } + else + { + return E_INVALIDARG; + } + + m_heaps = 0; + m_rid = 0; + m_maskvalid = 0; + m_sorted = 0; + memset(m_cRecs, 0, sizeof(m_cRecs)); + m_ulExtra = 0; + + return S_OK; +} // CMiniMdSchema::InitNew + +//***************************************************************************** +// Compress a schema into a compressed version of the schema. +//***************************************************************************** +ULONG +CMiniMdSchema::SaveTo( + void *pvData) +{ + ULONG ulData; // Bytes stored. + CMiniMdSchema *pDest = reinterpret_cast<CMiniMdSchema*>(pvData); + const unsigned __int64 one = 1; + + // Make sure the tables fit in the mask. + _ASSERTE((sizeof(m_maskvalid) * 8) > TBL_COUNT); + + // Set the flag for the extra data. +#if defined(EXTRA_DATA) + if (m_ulExtra != 0) + { + m_heaps |= EXTRA_DATA; + } + else +#endif // 0 + { + m_heaps &= ~EXTRA_DATA; + } + + // Minor version is preset when we instantiate the MiniMd. + + // Make sure we're saving out a version that Beta1 version can read + _ASSERTE((m_major == METAMODEL_MAJOR_VER && m_minor == METAMODEL_MINOR_VER) || + (m_major == METAMODEL_MAJOR_VER_B1 && m_minor == METAMODEL_MINOR_VER_B1) || + (m_major == METAMODEL_MAJOR_VER_V1_0 && m_minor == METAMODEL_MINOR_VER_V1_0)); + + // Transfer the fixed fields. + *static_cast<CMiniMdSchemaBase*>(pDest) = *static_cast<CMiniMdSchemaBase*>(this); + static_cast<CMiniMdSchemaBase*>(pDest)->ConvertEndianness(); + ulData = sizeof(CMiniMdSchemaBase); + + // Transfer the variable fields. + m_maskvalid = 0; + for (int iSrc=0, iDst=0; iSrc<TBL_COUNT; ++iSrc) + { + if (m_cRecs[iSrc] != 0) + { + pDest->m_cRecs[iDst++] = VAL32(m_cRecs[iSrc]); + m_maskvalid |= (one << iSrc); + ulData += sizeof(m_cRecs[iSrc]); + } + } + // Refresh the mask. + pDest->m_maskvalid = VAL64(m_maskvalid); + +#if defined(EXTRA_DATA) + // Store the extra data. + if (m_ulExtra != 0) + { + *reinterpret_cast<ULONG*>(&pDest->m_cRecs[iDst]) = VAL32(m_ulExtra); + ulData += sizeof(ULONG); + } +#endif // 0 + return ulData; +} // CMiniMdSchema::SaveTo + +//***************************************************************************** +// Load a schema from a compressed version of the schema. +// Returns count of bytes consumed. -1 if error. +//***************************************************************************** +ULONG +CMiniMdSchema::LoadFrom( + const void *pvData, // Data to load from. + ULONG cbData) // Amount of data available. +{ + ULONG ulData; // Bytes consumed. + + ulData = sizeof(CMiniMdSchemaBase); + + // Be sure we can get the base part. + if (cbData < ulData) + return (ULONG)(-1); + + // Transfer the fixed fields. The (void*) casts prevents the compiler + // from making bad assumptions about the alignment. + memcpy((void *)this, (void *)pvData, sizeof(CMiniMdSchemaBase)); + static_cast<CMiniMdSchemaBase*>(this)->ConvertEndianness(); + + unsigned __int64 maskvalid = m_maskvalid; + + // Transfer the variable fields. + memset(m_cRecs, 0, sizeof(m_cRecs)); + int iDst; + for (iDst = 0; iDst < TBL_COUNT; ++iDst, maskvalid >>= 1) + { + if ((maskvalid & 1) != 0) + { + // Check integer overflow for: ulData + sizeof(UINT32) + ULONG ulDataTemp; + if (!ClrSafeInt<ULONG>::addition(ulData, sizeof(UINT32), ulDataTemp)) + { + return (ULONG)(-1); + } + // Verify that the data is there before touching it. + if (cbData < (ulData + sizeof(UINT32))) + return (ULONG)(-1); + + m_cRecs[iDst] = GET_UNALIGNED_VAL32((const BYTE *)pvData + ulData); + // It's safe to sum, because we checked integer overflow above + ulData += sizeof(UINT32); + } + } + // Also accumulate the sizes of any counters that we don't understand. + for (iDst = TBL_COUNT; (maskvalid != 0) && (iDst < ((int)sizeof(m_maskvalid) * 8)); ++iDst, maskvalid >>= 1) + { + if ((maskvalid & 1) != 0) + { + // Check integer overflow for: ulData += sizeof(UINT32); + if (!ClrSafeInt<ULONG>::addition(ulData, sizeof(UINT32), ulData)) + { + return (ULONG)(-1); + } + // Did we go past end of buffer? + if (cbData < ulData) + { + return (ULONG)(-1); + } + } + } + + // Retrieve the extra 4 bytes data. + if ((m_heaps & EXTRA_DATA) != 0) + { + // Check integer overflow for: ulData + sizeof(UINT32) + ULONG ulDataTemp; + if (!ClrSafeInt<ULONG>::addition(ulData, sizeof(UINT32), ulDataTemp)) + { + return (ULONG)(-1); + } + // Verify that the 4 bytes data is there before touching it. + if (cbData < (ulData + sizeof(UINT32))) + return (ULONG)(-1); + + m_ulExtra = GET_UNALIGNED_VAL32((const BYTE *)pvData + ulData); + // Check the size we used for buffer overflow verification above + ulData += sizeof(UINT32); + } + + // Did we go past end of buffer? + if (cbData < ulData) + return (ULONG)(-1); + + return ulData; +} // CMiniMdSchema::LoadFrom + + +const mdToken CMiniMdBase::mdtTypeDefOrRef[3] = { + mdtTypeDef, + mdtTypeRef, + mdtTypeSpec +}; + +// This array needs to be ordered the same as the source tables are processed (currently +// {field, param, property}) for binary search. +const mdToken CMiniMdBase::mdtHasConstant[3] = { + mdtFieldDef, + mdtParamDef, + mdtProperty +}; + +const mdToken CMiniMdBase::mdtHasCustomAttribute[24] = { + mdtMethodDef, + mdtFieldDef, + mdtTypeRef, + mdtTypeDef, + mdtParamDef, + mdtInterfaceImpl, + mdtMemberRef, + mdtModule, + mdtPermission, + mdtProperty, + mdtEvent, + mdtSignature, + mdtModuleRef, + mdtTypeSpec, + mdtAssembly, + mdtAssemblyRef, + mdtFile, + mdtExportedType, + mdtManifestResource, + mdtGenericParam, + mdtGenericParamConstraint, + mdtMethodSpec +}; + +const mdToken CMiniMdBase::mdtHasFieldMarshal[2] = { + mdtFieldDef, + mdtParamDef, +}; + +const mdToken CMiniMdBase::mdtHasDeclSecurity[3] = { + mdtTypeDef, + mdtMethodDef, + mdtAssembly +}; + +const mdToken CMiniMdBase::mdtMemberRefParent[5] = { + mdtTypeDef, + mdtTypeRef, + mdtModuleRef, + mdtMethodDef, + mdtTypeSpec +}; + +const mdToken CMiniMdBase::mdtHasSemantic[2] = { + mdtEvent, + mdtProperty, +}; + +const mdToken CMiniMdBase::mdtMethodDefOrRef[2] = { + mdtMethodDef, + mdtMemberRef +}; + +const mdToken CMiniMdBase::mdtMemberForwarded[2] = { + mdtFieldDef, + mdtMethodDef +}; + +const mdToken CMiniMdBase::mdtImplementation[3] = { + mdtFile, + mdtAssemblyRef, + mdtExportedType +}; + +const mdToken CMiniMdBase::mdtCustomAttributeType[5] = { + 0, + 0, + mdtMethodDef, + mdtMemberRef, + 0 +}; + +const mdToken CMiniMdBase::mdtResolutionScope[4] = { + mdtModule, + mdtModuleRef, + mdtAssemblyRef, + mdtTypeRef +}; + +const mdToken CMiniMdBase::mdtTypeOrMethodDef[2] = { + mdtTypeDef, + mdtMethodDef +}; + +const int CMiniMdBase::m_cb[] = {0,1,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5}; + +//***************************************************************************** +// Function to encode a token into fewer bits. Looks up token type in array of types. +//***************************************************************************** +//<TODO>@consider whether this could be a binary search.</TODO> +ULONG +CMiniMdBase::encodeToken( + RID rid, // Rid to encode. + mdToken typ, // Token type to encode. + const mdToken rTokens[], // Table of valid token. + ULONG32 cTokens) // Size of the table. +{ + mdToken tk = TypeFromToken(typ); + size_t ix; + for (ix = 0; ix < cTokens; ++ix) + { + if (rTokens[ix] == tk) + break; + } + _ASSERTE(ix < cTokens); + if (ix >= cTokens) + return mdTokenNil; + //<TODO>@FUTURE: make compile-time calculation</TODO> + return (ULONG)((rid << m_cb[cTokens]) | ix); +} // CMiniMd::encodeToken + + +//***************************************************************************** +// Helpers for populating the hard-coded schema. +//***************************************************************************** +inline BYTE cbRID(ULONG ixMax) { return ixMax > USHRT_MAX ? (BYTE) sizeof(ULONG) : (BYTE) sizeof(USHORT); } + +#define _CBTKN(cRecs,tkns) cbRID(cRecs << m_cb[lengthof(tkns)]) + +//***************************************************************************** +// Constructor. +//***************************************************************************** +CMiniMdBase::CMiniMdBase() +{ +#undef MiniMdTable +#define MiniMdTable(tbl) \ + m_TableDefs[TBL_##tbl] = g_Tables[TBL_##tbl].m_Def; \ + m_TableDefs[TBL_##tbl].m_pColDefs = BYTEARRAY_TO_COLDES(s_##tbl##Col); + MiniMdTables() + + m_TblCount = TBL_COUNT; + _ASSERTE(TBL_COUNT == TBL_COUNT_V2); // v2 counts. + + m_fVerifiedByTrustedSource = FALSE; + + // Validator depends on the Table Ids and the Token Ids being identical. + // Catch it if this ever breaks. + _ASSERTE((TypeFromToken(mdtModule) >> 24) == TBL_Module); + _ASSERTE((TypeFromToken(mdtTypeRef) >> 24) == TBL_TypeRef); + _ASSERTE((TypeFromToken(mdtTypeDef) >> 24) == TBL_TypeDef); + _ASSERTE((TypeFromToken(mdtFieldDef) >> 24) == TBL_Field); + _ASSERTE((TypeFromToken(mdtMethodDef) >> 24) == TBL_Method); + _ASSERTE((TypeFromToken(mdtParamDef) >> 24) == TBL_Param); + _ASSERTE((TypeFromToken(mdtInterfaceImpl) >> 24) == TBL_InterfaceImpl); + _ASSERTE((TypeFromToken(mdtMemberRef) >> 24) == TBL_MemberRef); + _ASSERTE((TypeFromToken(mdtCustomAttribute) >> 24) == TBL_CustomAttribute); + _ASSERTE((TypeFromToken(mdtPermission) >> 24) == TBL_DeclSecurity); + _ASSERTE((TypeFromToken(mdtSignature) >> 24) == TBL_StandAloneSig); + _ASSERTE((TypeFromToken(mdtEvent) >> 24) == TBL_Event); + _ASSERTE((TypeFromToken(mdtProperty) >> 24) == TBL_Property); + _ASSERTE((TypeFromToken(mdtModuleRef) >> 24) == TBL_ModuleRef); + _ASSERTE((TypeFromToken(mdtTypeSpec) >> 24) == TBL_TypeSpec); + _ASSERTE((TypeFromToken(mdtAssembly) >> 24) == TBL_Assembly); + _ASSERTE((TypeFromToken(mdtAssemblyRef) >> 24) == TBL_AssemblyRef); + _ASSERTE((TypeFromToken(mdtFile) >> 24) == TBL_File); + _ASSERTE((TypeFromToken(mdtExportedType) >> 24) == TBL_ExportedType); + _ASSERTE((TypeFromToken(mdtManifestResource) >> 24) == TBL_ManifestResource); + _ASSERTE((TypeFromToken(mdtGenericParam) >> 24) == TBL_GenericParam); + _ASSERTE((TypeFromToken(mdtMethodSpec) >> 24) == TBL_MethodSpec); + _ASSERTE((TypeFromToken(mdtGenericParamConstraint) >> 24) == TBL_GenericParamConstraint); +} // CMiniMdBase::CMiniMdBase + + +//***************************************************************************** +// Destructor. +//***************************************************************************** +CMiniMdBase::~CMiniMdBase() +{ + for (ULONG i = 0; i < m_TblCount; i++) + { + if ((m_TableDefs[i].m_pColDefs != NULL) && UsesAllocatedMemory(m_TableDefs[i].m_pColDefs)) + { + delete[] COLDES_TO_BYTEARRAY(m_TableDefs[i].m_pColDefs); + m_TableDefs[i].m_pColDefs = NULL; + } + } +} // CMiniMdBase::~CMiniMdBase + +//***************************************************************************** +// Build the schema based on the header data provided. +// Handle all supported versions, and adjust data structures appropriately. +//***************************************************************************** +HRESULT +CMiniMdBase::SchemaPopulate( + const void *pvData, // Pointer to the buffer. + ULONG cbData, // Size of the buffer. + ULONG *pcbUsed) // Put size of the header here. +{ + HRESULT hr; + ULONG cb; // Bytes read for header. + ULONG cbTables; // Bytes needed for tables. + ULONG cbTotal; // Bytes read for header + needed for tables. + + // Uncompress the schema from the buffer into our structures. + cb = m_Schema.LoadFrom(pvData, cbData); + + if ((cb > cbData) || (cb == (ULONG)(-1))) + { + Debug_ReportError("Schema is not in MetaData block."); + return PostError(CLDB_E_FILE_CORRUPT); + } + + // Is this the "native" version of the metadata for this runtime? + if ((m_Schema.m_major != METAMODEL_MAJOR_VER) || (m_Schema.m_minor != METAMODEL_MINOR_VER)) + { + // No it's not. Is this an older version that we support? + +#ifndef FEATURE_METADATA_STANDALONE_WINRT + // Is this v1.0? + if ((m_Schema.m_major == METAMODEL_MAJOR_VER_V1_0) && + (m_Schema.m_minor == METAMODEL_MINOR_VER_V1_0)) + { + // Older version has fewer tables. + m_TblCount = TBL_COUNT_V1; + } + else if ((m_Schema.m_major == METAMODEL_MAJOR_VER_B1) && + (m_Schema.m_minor == METAMODEL_MINOR_VER_B1)) + { + // 1.1 had a different type of GenericParam table + m_TableDefs[TBL_GenericParam] = g_Table_GenericParamV1_1.m_Def; + m_TableDefs[TBL_GenericParam].m_pColDefs = BYTEARRAY_TO_COLDES(s_GenericParamCol); + } + else +#endif //!FEATURE_METADATA_STANDALONE_WINRT + { // We don't support this version of the metadata + Debug_ReportError("Unsupported version of MetaData."); + return PostError(CLDB_E_FILE_OLDVER, m_Schema.m_major, m_Schema.m_minor); + } + } + + // Populate the schema, based on the row counts and heap sizes. + IfFailRet(SchemaPopulate2(&cbTables)); + + // Check that header plus tables fits within the size given. + if (!ClrSafeInt<ULONG>::addition(cb, cbTables, cbTotal) || (cbTotal > cbData)) + { + Debug_ReportError("Tables are not within MetaData block."); + return PostError(CLDB_E_FILE_CORRUPT); + } + + *pcbUsed = cb; + return S_OK; +} // CMiniMdBase::SchemaPopulate + +//***************************************************************************** +// Initialize from another MD +//***************************************************************************** +HRESULT +CMiniMdBase::SchemaPopulate( + const CMiniMdBase &that) +{ + HRESULT hr; + // Copy over the schema. + m_Schema = that.m_Schema; + + // Adjust for prior versions. + if (m_Schema.m_major != METAMODEL_MAJOR_VER || m_Schema.m_minor != METAMODEL_MINOR_VER) + { + if ((m_Schema.m_major == METAMODEL_MAJOR_VER_V1_0) && (m_Schema.m_minor == METAMODEL_MINOR_VER_V1_0)) + { // Older version has fewer tables. + m_TblCount = that.m_TblCount; + _ASSERTE(m_TblCount == TBL_COUNT_V1); + } + else if (m_Schema.m_major == METAMODEL_MAJOR_VER_B1 && m_Schema.m_minor == METAMODEL_MINOR_VER_B1) + { + // 1.1 had a different type of GenericParam table + m_TableDefs[TBL_GenericParam] = g_Table_GenericParamV1_1.m_Def; + m_TableDefs[TBL_GenericParam].m_pColDefs = BYTEARRAY_TO_COLDES(s_GenericParamCol); + } + // Is it a supported old version? This should never fail! + else + { + Debug_ReportError("Initializing on an unknown schema version"); + return PostError(CLDB_E_FILE_OLDVER, m_Schema.m_major,m_Schema.m_minor); + } + } + + IfFailRet(SchemaPopulate2(NULL)); + + return S_OK; +} // CMiniMdBase::SchemaPopulate + +//***************************************************************************** +// Iterate the tables, and fix the column sizes, based on size of data. +//***************************************************************************** +HRESULT CMiniMdBase::SchemaPopulate2( + ULONG *pcbTables, // [out, optional] Put size needed for tables here. + int bExtra) // Reserve an extra bit for rid columns? +{ + HRESULT hr; // A result. + ULONG cbTotal = 0; // Total size of all tables. + + // How big are the various pool inidices? + m_iStringsMask = (m_Schema.m_heaps & CMiniMdSchema::HEAP_STRING_4) ? 0xffffffff : 0xffff; + m_iGuidsMask = (m_Schema.m_heaps & CMiniMdSchema::HEAP_GUID_4) ? 0xffffffff : 0xffff; + m_iBlobsMask = (m_Schema.m_heaps & CMiniMdSchema::HEAP_BLOB_4) ? 0xffffffff : 0xffff; + + // Make extra bits exactly zero or one bit. + if (bExtra) + bExtra = 1; + + // Until ENC, make extra bits exactly zero. + bExtra = 0; + + // For each table... + for (int ixTbl = 0; ixTbl < (int)m_TblCount; ++ixTbl) + { + IfFailRet(InitColsForTable(m_Schema, ixTbl, &m_TableDefs[ixTbl], bExtra, TRUE)); + + // Accumulate size of this table. + // Check integer overflow for table size: USHORT * ULONG: m_TableDefs[ixTbl].m_cbRec * GetCountRecs(ixTbl) + ULONG cbTable; + if (!ClrSafeInt<ULONG>::multiply(m_TableDefs[ixTbl].m_cbRec, GetCountRecs(ixTbl), cbTable)) + { + Debug_ReportError("Table is too large - size overflow."); + return PostError(CLDB_E_FILE_CORRUPT); + } + // Check integer overflow for all tables so far: cbTotal += cbTable + if (!ClrSafeInt<ULONG>::addition(cbTotal, cbTable, cbTotal)) + { + Debug_ReportError("Tables are too large - size overflow."); + return PostError(CLDB_E_FILE_CORRUPT); + } + } + // Check that unused table (e.g. generic tables in v1 format) are empty + for (ULONG ixTbl = m_TblCount; ixTbl < TBL_COUNT; ixTbl++) + { + // All unused tables have to be empty - malicious assemblies can have v1 format version, but can + // contain non-empty v2-only tables, this will catch it and refuse to load such assemblies + if (GetCountRecs(ixTbl) != 0) + { + Debug_ReportError("Invalid table present - 2.0 table in v1.x image."); + return PostError(CLDB_E_FILE_CORRUPT); + } + } + + // Let caller know sizes required. + if (pcbTables != NULL) + *pcbTables = cbTotal; + + return S_OK; +} // CMiniMdBase::SchemaPopulate2 + +//***************************************************************************** +// Get the template table definition for a given table. +//***************************************************************************** +const CMiniTableDef * +CMiniMdBase::GetTableDefTemplate( + int ixTbl) +{ + const CMiniTableDef *pTemplate; // the return value. + + // Return the table definition for the given table. Account for version of schema. + if ((m_Schema.m_major == METAMODEL_MAJOR_VER_B1) && (m_Schema.m_minor == METAMODEL_MINOR_VER_B1) && (ixTbl == TBL_GenericParam)) + { + pTemplate = &g_Table_GenericParamV1_1.m_Def; + } + else + { + pTemplate = &g_Tables[ixTbl].m_Def; + } + + return pTemplate; +} // CMiniMdBase::GetTableDefTemplate + +//***************************************************************************** +// Initialize the column defs for a table, based on their types and sizes. +//***************************************************************************** +HRESULT +CMiniMdBase::InitColsForTable( + CMiniMdSchema &Schema, // Schema with sizes. + int ixTbl, // Index of table to init. + CMiniTableDef *pTable, // Table to init. + int bExtra, // Extra bits for rid column. + BOOL fUsePointers) // Should we have pTable point to it's Column Descriptors, or + // should we write the data into the structure +{ + const CMiniTableDef *pTemplate; // Template table definition. + CMiniColDef pCols[9]; // The col defs to init. + BYTE iOffset; // Running size of a record. + BYTE iSize; // Size of a field. + HRESULT hr = S_OK; + + _ASSERTE((bExtra == 0) || (bExtra == 1)); + _ASSERTE(NumItems(pCols) >= pTable->m_cCols); + + bExtra = 0;//<TODO>@FUTURE: save in schema header. until then use 0.</TODO> + + iOffset = 0; + + pTemplate = GetTableDefTemplate(ixTbl); + + PREFIX_ASSUME(pTemplate->m_pColDefs != NULL); + + // For each column in the table... + for (ULONG ixCol = 0; ixCol < pTable->m_cCols; ++ixCol) + { + // Initialize from the template values (type, maybe offset, size). + pCols[ixCol] = pTemplate->m_pColDefs[ixCol]; + + // Is the field a RID into a table? + if (pCols[ixCol].m_Type <= iRidMax) + { + iSize = cbRID(Schema.m_cRecs[pCols[ixCol].m_Type] << bExtra); + } + else + // Is the field a coded token? + if (pCols[ixCol].m_Type <= iCodedTokenMax) + { + ULONG iCdTkn = pCols[ixCol].m_Type - iCodedToken; + ULONG cRecs = 0; + + _ASSERTE(iCdTkn < lengthof(g_CodedTokens)); + CCodedTokenDef const *pCTD = &g_CodedTokens[iCdTkn]; + + // Iterate the token list of this coded token. + for (ULONG ixToken=0; ixToken<pCTD->m_cTokens; ++ixToken) + { // Ignore string tokens. + if (pCTD->m_pTokens[ixToken] != mdtString) + { + // Get the table for the token. + ULONG nTokenTable = CMiniMdRW::GetTableForToken(pCTD->m_pTokens[ixToken]); + _ASSERTE(nTokenTable < TBL_COUNT); + // If largest token seen so far, remember it. + if (Schema.m_cRecs[nTokenTable] > cRecs) + cRecs = Schema.m_cRecs[nTokenTable]; + } + } + + iSize = cbRID(cRecs << (bExtra + m_cb[pCTD->m_cTokens])); + + } + else + { // Fixed type. + switch (pCols[ixCol].m_Type) + { + case iBYTE: + iSize = 1; + _ASSERTE(pCols[ixCol].m_cbColumn == iSize); + _ASSERTE(pCols[ixCol].m_oColumn == iOffset); + break; + case iSHORT: + case iUSHORT: + iSize = 2; + _ASSERTE(pCols[ixCol].m_cbColumn == iSize); + _ASSERTE(pCols[ixCol].m_oColumn == iOffset); + break; + case iLONG: + case iULONG: + iSize = 4; + _ASSERTE(pCols[ixCol].m_cbColumn == iSize); + _ASSERTE(pCols[ixCol].m_oColumn == iOffset); + break; + case iSTRING: + iSize = (Schema.m_heaps & CMiniMdSchema::HEAP_STRING_4) ? 4 : 2; + break; + case iGUID: + iSize = (Schema.m_heaps & CMiniMdSchema::HEAP_GUID_4) ? 4 : 2; + break; + case iBLOB: + iSize = (Schema.m_heaps & CMiniMdSchema::HEAP_BLOB_4) ? 4 : 2; + break; + default: + _ASSERTE(!"Unexpected schema type"); + iSize = 0; + break; + } + } + + // Now save the size and offset. + pCols[ixCol].m_oColumn = iOffset; + pCols[ixCol].m_cbColumn = iSize; + + // Align to 2 bytes. + iSize += iSize & 1; + + iOffset += iSize; + } + // Record size of entire record. + pTable->m_cbRec = iOffset; + + _ASSERTE(pTable->m_pColDefs != NULL); + + // Can we write to the memory + if (!fUsePointers) + { + memcpy(pTable->m_pColDefs, pCols, sizeof(CMiniColDef)*pTable->m_cCols); + } + else + { + // We'll need to have pTable->m_pColDefs point to some data instead + hr = SetNewColumnDefinition(pTable, pCols, ixTbl); + } + // If no key, set to a distinct value. + if (pTable->m_iKey >= pTable->m_cCols) + pTable->m_iKey = (BYTE) -1; + + return hr; +} // CMiniMdBase::InitColsForTable + +//***************************************************************************** +// Place a new Column Definition into the metadata. +//***************************************************************************** +HRESULT +CMiniMdBase::SetNewColumnDefinition( + CMiniTableDef *pTable, + CMiniColDef *pCols, + DWORD ixTbl) +{ + // Look up the global cache to see if we can use a cached copy + if (UsesAllocatedMemory(pCols) || + !FindSharedColDefs(pTable, pCols, ixTbl)) + { + // See if we've already allocated memory for this item + + if (!UsesAllocatedMemory(pTable->m_pColDefs)) + { + // We don't have this column definition cached. Allocate new memory for it. + // Notice, we allocate one more byte than necessary, so we can 'mark' this chunk of memory + // as allocated so we can free it later. + + BYTE *newMemory = new (nothrow) BYTE[(sizeof(CMiniColDef)*pTable->m_cCols)+1]; + + if (newMemory == NULL) + return E_OUTOFMEMORY; + + // Mark the first byte in this as with the "allocated memory marker" + *newMemory = ALLOCATED_MEMORY_MARKER; + + // Have the pointer point to the first Column Descriptor + pTable->m_pColDefs = BYTEARRAY_TO_COLDES(newMemory); + } + + memcpy(pTable->m_pColDefs, pCols, sizeof(CMiniColDef)*pTable->m_cCols); + } + + return S_OK; +} // CMiniMdBase::SetNewColumnDefinition + + +//***************************************************************************** +// Get the count of records in a table. Virtual. +//***************************************************************************** +ULONG +CMiniMdBase::GetCountRecs( + ULONG ixTbl) +{ + _ASSERTE(ixTbl < TBL_COUNT); + return m_Schema.m_cRecs[ixTbl]; +} // CMiniMdBase::GetCountRecs + +//***************************************************************************** +// Search a table for multiple (adjacent) rows containing the given +// key value. EG, InterfaceImpls all point back to the implementing class. +//***************************************************************************** +__checkReturn +HRESULT +CMiniMdBase::SearchTableForMultipleRows( + ULONG ixTbl, // Table to search. + CMiniColDef sColumn, // Sorted key column, containing search value. + ULONG ulTarget, // Target for search. + RID *pEnd, // [OPTIONAL, OUT] + RID *pFoundRid) // First RID found, or 0. +{ + HRESULT hr; + ULONG ridBegin; // RID of first entry. + ULONG ridEnd; // RID of first entry past last entry. + + // Search for any entry in the table. + IfFailRet(vSearchTable(ixTbl, sColumn, ulTarget, &ridBegin)); + + // If nothing found, return invalid RID. + if (ridBegin == 0) + { + if (pEnd != NULL) + { + *pEnd = 0; + } + *pFoundRid = 0; + return S_OK; + } + + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // If you change the rows touched while searching, please update + // CMiniMdRW::GetHotMetadataTokensSearchAware + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + + // End will be at least one larger than found record. + ridEnd = ridBegin + 1; + + // Search back to start of group. + for (;;) + { + void *pRow; + if (ridBegin <= 1) + { + break; + } + IfFailRet(vGetRow(ixTbl, ridBegin-1, &pRow)); + if (getIX(pRow, sColumn) != ulTarget) + { + break; + } + --ridBegin; + } + + // If desired, search forward to end of group. + if (pEnd != NULL) + { + for (;;) + { + void *pRow; + if (ridEnd > GetCountRecs(ixTbl)) + { + break; + } + IfFailRet(vGetRow(ixTbl, ridEnd, &pRow)); + if (getIX(pRow, sColumn) != ulTarget) + { + break; + } + ++ridEnd; + } + *pEnd = ridEnd; + } + + *pFoundRid = ridBegin; + return S_OK; +} // CMiniMdBase::SearchTableForMultipleRows + + +#if BIGENDIAN +// Endian Swaps the passed in blob representing a constant into the passed in StgPool +HRESULT +CMiniMdBase::SwapConstant( + const void *pBlobValue, // Original Value pointer + DWORD dwType, // Type of the constant + void *pConstant, // [Out] Location to store constant into + ULONG ValueLength) // [In] Length of constant +{ + HRESULT hr = NOERROR; + + switch (dwType) + { + case ELEMENT_TYPE_BOOLEAN: + case ELEMENT_TYPE_I1: + case ELEMENT_TYPE_U1: + case ELEMENT_TYPE_VOID: + // Just return the value + *(BYTE *)pConstant = *(BYTE *)pBlobValue; + return NOERROR; + + case ELEMENT_TYPE_I2: + case ELEMENT_TYPE_U2: + case ELEMENT_TYPE_CHAR: + _ASSERTE(ValueLength == 2); + *(SHORT *)pConstant = GET_UNALIGNED_VAL16(pBlobValue); + break; + case ELEMENT_TYPE_CLASS: + case ELEMENT_TYPE_I4: + case ELEMENT_TYPE_U4: + _ASSERTE(ValueLength == 4); + *(__int32 *)pConstant = GET_UNALIGNED_VAL32(pBlobValue); + break; + case ELEMENT_TYPE_R4: + { + __int32 Value = GET_UNALIGNED_VAL32(pBlobValue); + *(float *)pConstant = (float &)Value; + } + break; + + case ELEMENT_TYPE_R8: + { + __int64 Value = GET_UNALIGNED_VAL64(pBlobValue); + *(double *)pConstant = (double &) Value; + } + break; + + case ELEMENT_TYPE_I8: + case ELEMENT_TYPE_U8: + _ASSERTE(ValueLength == 8); + *(__int64 *)pConstant = GET_UNALIGNED_VAL64(pBlobValue); + break; + case ELEMENT_TYPE_STRING: + memcpy(pConstant, pBlobValue, ValueLength); + SwapStringLength((WCHAR *)pConstant, (ValueLength)/sizeof(WCHAR)); + break; + default: + _ASSERTE(!"BAD TYPE!"); + return E_INVALIDARG; + break; + } + return hr; +} // CMiniMdBase::SwapConstant +#endif //BIGENDIAN + +//***************************************************************************** +// It is non-trivial to sort propertymap. VB is generating properties in +// non-sorted order!!! +//***************************************************************************** +HRESULT +CMiniMdBase::FindPropertyMapFor( + RID ridParent, + RID *pFoundRid) +{ + HRESULT hr; + ULONG i; + ULONG iCount; + void *pRec; + RID rid; + + // If the table is sorted, use binary search. However we can only trust + // the sorted bit if we have verified it (see definition in MetaModel.h) + if (IsVerified() && m_Schema.IsSorted(TBL_PropertyMap)) + { + return vSearchTable(TBL_PropertyMap, + _COLDEF(PropertyMap,Parent), + ridParent, + pFoundRid); + } + else + { + iCount = GetCountRecs(TBL_PropertyMap); + + // loop through all LocalVar + for (i = 1; i <= iCount; i++) + { + IfFailRet(vGetRow(TBL_PropertyMap, i, &pRec)); + + // linear search for propertymap record + rid = getIX(pRec, _COLDEF(PropertyMap,Parent)); + if (rid == ridParent) + { + *pFoundRid = i; + return S_OK; + } + } + + *pFoundRid = 0; + return S_OK; + } + +} // CMiniMdBase::FindPropertyMapFor + + +//***************************************************************************** +// It is non-trivial to sort eventmap. VB is generating events in +// non-sorted order!!! +//***************************************************************************** +__checkReturn +HRESULT +CMiniMdBase::FindEventMapFor( + RID ridParent, + RID *pFoundRid) +{ + HRESULT hr; + ULONG i; + ULONG iCount; + void *pRec; + RID rid; + + // If the table is sorted, use binary search. However we can only trust + // the sorted bit if we have verified it (see definition in MetaModel.h) + if (IsVerified() && m_Schema.IsSorted(TBL_EventMap)) + { + return vSearchTable(TBL_EventMap, + _COLDEF(EventMap,Parent), + ridParent, + pFoundRid); + } + else + { + iCount = GetCountRecs(TBL_EventMap); + + // loop through all LocalVar + for (i = 1; i <= iCount; i++) + { + IfFailRet(vGetRow(TBL_EventMap, i, &pRec)); + + // linear search for propertymap record + rid = getIX(pRec, _COLDEF(EventMap,Parent)); + if (rid == ridParent) + { + *pFoundRid = i; + return S_OK; + } + } + + *pFoundRid = 0; + return S_OK; + } +} // CMiniMdBase::FindEventMapFor + + +//***************************************************************************** +// Search for a custom value with a given type. +//***************************************************************************** +__checkReturn +HRESULT +CMiniMdBase::FindCustomAttributeFor( + RID rid, // The object's rid. + mdToken tkObj, // The object's type. + mdToken tkType, // Type of custom value. + RID *pFoundRid) // RID of custom value, or 0. +{ + HRESULT hr; + int ixFound; // index of some custom value row. + ULONG ulTarget = encodeToken(rid,tkObj,mdtHasCustomAttribute,lengthof(mdtHasCustomAttribute)); // encoded token representing target. + ULONG ixCur; // Current row being examined. + mdToken tkFound; // Type of some custom value row. + void *pCur; // A custom value entry. + + // Search for any entry in CustomAttribute table. Convert to RID. + IfFailRet(vSearchTable(TBL_CustomAttribute, _COLDEF(CustomAttribute,Parent), ulTarget, (RID *)&ixFound)); + if (ixFound == 0) + { + *pFoundRid = 0; + return S_OK; + } + + // Found an entry that matches the item. Could be anywhere in a range of + // custom values for the item, somewhat at random. Search for a match + // on name. On entry to the first loop, we know the object is the desired + // one, so the object test is at the bottom. + ixCur = ixFound; + IfFailRet(vGetRow(TBL_CustomAttribute, ixCur, &pCur)); + for(;;) + { + // Test the type of the current row. + tkFound = getIX(pCur, _COLDEF(CustomAttribute,Type)); + tkFound = decodeToken(tkFound, mdtCustomAttributeType, lengthof(mdtCustomAttributeType)); + if (tkFound == tkType) + { + *pFoundRid = ixCur; + return S_OK; + } + // Was this the last row of the CustomAttribute table? + if (ixCur == GetCountRecs(TBL_CustomAttribute)) + break; + // No match, more rows, try for the next row. + ++ixCur; + // Get the row and see if it is for the same object. + IfFailRet(vGetRow(TBL_CustomAttribute, ixCur, &pCur)); + if (getIX(pCur, _COLDEF(CustomAttribute,Parent)) != ulTarget) + break; + } + // Didn't find the name looking up. Try looking down. + ixCur = ixFound - 1; + for(;;) + { + // Run out of table yet? + if (ixCur == 0) + break; + // Get the row and see if it is for the same object. + IfFailRet(vGetRow(TBL_CustomAttribute, ixCur, &pCur)); + // still looking at the same object? + if (getIX(pCur, _COLDEF(CustomAttribute,Parent)) != ulTarget) + break; + // Test the type of the current row. + tkFound = getIX(pCur, _COLDEF(CustomAttribute,Type)); + tkFound = decodeToken(tkFound, mdtCustomAttributeType, lengthof(mdtCustomAttributeType)); + if (tkFound == tkType) + { + *pFoundRid = ixCur; + return S_OK; + } + // No match, try for the previous row. + --ixCur; + } + // Didn't find anything. + *pFoundRid = 0; + return S_OK; +} // CMiniMdBase::FindCustomAttributeFor + +//***************************************************************************** +// See if we can find a globally shared Column Def Array for this table +//***************************************************************************** +BOOL +CMiniMdBase::FindSharedColDefs( + CMiniTableDef *pTable, + CMiniColDef *pColsToMatch, + DWORD ixTbl) +{ + // The majority of the time, m_pColDefs will point to the correct Column Definition Array. + if (!memcmp(pTable->m_pColDefs, pColsToMatch, sizeof(CMiniColDef)*(pTable->m_cCols))) + return TRUE; + + else + { + // m_pColDefs points to a set of Column Def Arrays, with the byte previous to it the number + // of column descriptors that we have. + CMiniColDef *pListOfColumnDefs = BYTEARRAY_TO_COLDES(s_TableColumnDescriptors[ixTbl]); + + BYTE nNumColDes = *(s_TableColumnDescriptors[ixTbl]); + + // Start at '1' since we already compared the first set of column definitions above. + for (int i = 1; i < nNumColDes; i++) + { + pListOfColumnDefs += pTable->m_cCols; + + if (!memcmp(pListOfColumnDefs, pColsToMatch, sizeof(CMiniColDef)*(pTable->m_cCols))) + { + pTable->m_pColDefs = pListOfColumnDefs; + return TRUE; + } + } + } + + // We weren't able to find a shared column definition + return FALSE; +}// CMiniMdBase::FindSharedColDefs + +//***************************************************************************** +// Determines where the Table Def's Column Definitions used shared memory or +// allocated memory +//***************************************************************************** +BOOL +CMiniMdBase::UsesAllocatedMemory( + CMiniColDef *pCols) +{ + BYTE *pMem = COLDES_TO_BYTEARRAY(pCols); + + // If the byte preceding this pointer is -1, then we allocated it and it must be freed + return (*pMem == ALLOCATED_MEMORY_MARKER); +}// CMiniMdBase::UsesAllocatedMemory diff --git a/src/md/runtime/metamodelcolumndefs.h b/src/md/runtime/metamodelcolumndefs.h new file mode 100644 index 0000000000..311ec97078 --- /dev/null +++ b/src/md/runtime/metamodelcolumndefs.h @@ -0,0 +1,401 @@ +// 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. +//***************************************************************************** +// MetaModelColumnDefs.h -- Table definitions for MetaData. +// + +// +//***************************************************************************** + +#if METAMODEL_MAJOR_VER != 2 +#if METAMODEL_MAJOR_VER != 1 +#error "METAMODEL_MAJOR_VER other than 1 or 2 is not implemented" +#endif +#endif + // + // These are used by #defining appropriately, then #including this file. + // + //------------------------------------------------------------------------- + //Module + SCHEMA_TABLE_START(Module) + SCHEMA_ITEM(Module, USHORT, Generation) + SCHEMA_ITEM_STRING(Module, Name) + SCHEMA_ITEM_GUID(Module, Mvid) + SCHEMA_ITEM_GUID(Module, EncId) + SCHEMA_ITEM_GUID(Module, EncBaseId) + SCHEMA_TABLE_END(Module) + + //------------------------------------------------------------------------- + //TypeRef + SCHEMA_TABLE_START(TypeRef) + SCHEMA_ITEM_CDTKN(TypeRef, ResolutionScope, ResolutionScope) + SCHEMA_ITEM_STRING(TypeRef, Name) + SCHEMA_ITEM_STRING(TypeRef, Namespace) + SCHEMA_TABLE_END(TypeRef) + + //------------------------------------------------------------------------- + // TypeDef + SCHEMA_TABLE_START(TypeDef) + SCHEMA_ITEM(TypeDef, ULONG, Flags) + SCHEMA_ITEM_STRING(TypeDef, Name) + SCHEMA_ITEM_STRING(TypeDef, Namespace) + SCHEMA_ITEM_CDTKN(TypeDef, Extends, TypeDefOrRef) + SCHEMA_ITEM_RID(TypeDef, FieldList, Field) + SCHEMA_ITEM_RID(TypeDef, MethodList, Method) + SCHEMA_TABLE_END(TypeDef) + + //------------------------------------------------------------------------- + //FieldPtr + SCHEMA_TABLE_START(FieldPtr) + SCHEMA_ITEM_NOFIXED() + SCHEMA_ITEM_RID(FieldPtr, Field, Field) + SCHEMA_TABLE_END(FieldPtr) + + //------------------------------------------------------------------------- + //Field + SCHEMA_TABLE_START(Field) + SCHEMA_ITEM(Field, USHORT, Flags) + SCHEMA_ITEM_STRING(Field,Name) + SCHEMA_ITEM_BLOB(Field,Signature) + SCHEMA_TABLE_END(Field) + + //------------------------------------------------------------------------- + //MethodPtr + SCHEMA_TABLE_START(MethodPtr) + SCHEMA_ITEM_NOFIXED() + SCHEMA_ITEM_RID(MethodPtr, Method, Method) + SCHEMA_TABLE_END(MethodPtr) + + //------------------------------------------------------------------------- + //Method + SCHEMA_TABLE_START(Method) + SCHEMA_ITEM(Method, ULONG, RVA) + SCHEMA_ITEM(Method, USHORT, ImplFlags) + SCHEMA_ITEM(Method, USHORT, Flags) + SCHEMA_ITEM_STRING(Method,Name) + SCHEMA_ITEM_BLOB(Method,Signature) + SCHEMA_ITEM_RID(Method,ParamList,Param) + SCHEMA_TABLE_END(Method) + + //------------------------------------------------------------------------- + //ParamPtr + SCHEMA_TABLE_START(ParamPtr) + SCHEMA_ITEM_NOFIXED() + SCHEMA_ITEM_RID(ParamPtr, Param, Param) + SCHEMA_TABLE_END(ParamPtr) + + //------------------------------------------------------------------------- + // Param + SCHEMA_TABLE_START(Param) + SCHEMA_ITEM(Param, USHORT, Flags) + SCHEMA_ITEM(Param, USHORT, Sequence) + SCHEMA_ITEM_STRING(Param,Name) + SCHEMA_TABLE_END(Param) + + //------------------------------------------------------------------------- + //InterfaceImpl + SCHEMA_TABLE_START(InterfaceImpl) + SCHEMA_ITEM_RID(InterfaceImpl,Class,TypeDef) + SCHEMA_ITEM_CDTKN(InterfaceImpl,Interface,TypeDefOrRef) + SCHEMA_TABLE_END(InterfaceImpl) + + //------------------------------------------------------------------------- + //MemberRef + SCHEMA_TABLE_START(MemberRef) + SCHEMA_ITEM_NOFIXED() + SCHEMA_ITEM_CDTKN(MemberRef,Class,MemberRefParent) + SCHEMA_ITEM_STRING(MemberRef,Name) + SCHEMA_ITEM_BLOB(MemberRef,Signature) + SCHEMA_TABLE_END(MemberRef) + + //------------------------------------------------------------------------- + //Constant + SCHEMA_TABLE_START(Constant) + SCHEMA_ITEM(Constant, BYTE, Type) + SCHEMA_ITEM_CDTKN(Constant,Parent,HasConstant) + SCHEMA_ITEM_BLOB(Constant,Value) + SCHEMA_TABLE_END(Constant) + + //------------------------------------------------------------------------- + //CustomAttribute + SCHEMA_TABLE_START(CustomAttribute) + SCHEMA_ITEM_NOFIXED() + SCHEMA_ITEM_CDTKN(CustomAttribute,Parent,HasCustomAttribute) + SCHEMA_ITEM_CDTKN(CustomAttribute,Type,CustomAttributeType) + SCHEMA_ITEM_BLOB(CustomAttribute,Value) + SCHEMA_TABLE_END(CustomAttribute) + + //------------------------------------------------------------------------- + //FieldMarshal + SCHEMA_TABLE_START(FieldMarshal) + SCHEMA_ITEM_NOFIXED() + SCHEMA_ITEM_CDTKN(FieldMarshal,Parent,HasFieldMarshal) + SCHEMA_ITEM_BLOB(FieldMarshal,NativeType) + SCHEMA_TABLE_END(FieldMarshal) + + //------------------------------------------------------------------------- + //DeclSecurity + SCHEMA_TABLE_START(DeclSecurity) + SCHEMA_ITEM(DeclSecurity, SHORT, Action) + SCHEMA_ITEM_CDTKN(DeclSecurity,Parent,HasDeclSecurity) + SCHEMA_ITEM_BLOB(DeclSecurity,PermissionSet) + SCHEMA_TABLE_END(DeclSecurity) + + //------------------------------------------------------------------------- + //ClassLayout + SCHEMA_TABLE_START(ClassLayout) + SCHEMA_ITEM(ClassLayout, USHORT, PackingSize) + SCHEMA_ITEM(ClassLayout, ULONG, ClassSize) + SCHEMA_ITEM_RID(ClassLayout,Parent,TypeDef) + SCHEMA_TABLE_END(ClassLayout) + + //------------------------------------------------------------------------- + //FieldLayout + SCHEMA_TABLE_START(FieldLayout) + SCHEMA_ITEM(FieldLayout, ULONG, OffSet) + SCHEMA_ITEM_RID(FieldLayout, Field, Field) + SCHEMA_TABLE_END(FieldLayout) + + //------------------------------------------------------------------------- + //StandAloneSig + SCHEMA_TABLE_START(StandAloneSig) + SCHEMA_ITEM_NOFIXED() + SCHEMA_ITEM_BLOB(StandAloneSig,Signature) + SCHEMA_TABLE_END(StandAloneSig) + + //------------------------------------------------------------------------- + //EventMap + SCHEMA_TABLE_START(EventMap) + SCHEMA_ITEM_NOFIXED() + SCHEMA_ITEM_RID(EventMap,Parent,TypeDef) + SCHEMA_ITEM_RID(EventMap,EventList,Event) + SCHEMA_TABLE_END(EventMap) + + //------------------------------------------------------------------------- + //EventPtr + SCHEMA_TABLE_START(EventPtr) + SCHEMA_ITEM_NOFIXED() + SCHEMA_ITEM_RID(EventPtr, Event, Event) + SCHEMA_TABLE_END(EventPtr) + + //------------------------------------------------------------------------- + //Event + SCHEMA_TABLE_START(Event) + SCHEMA_ITEM(Event, USHORT, EventFlags) + SCHEMA_ITEM_STRING(Event,Name) + SCHEMA_ITEM_CDTKN(Event,EventType,TypeDefOrRef) + SCHEMA_TABLE_END(Event) + + //------------------------------------------------------------------------- + //PropertyMap + SCHEMA_TABLE_START(PropertyMap) + SCHEMA_ITEM_NOFIXED() + SCHEMA_ITEM_RID(PropertyMap,Parent,TypeDef) + SCHEMA_ITEM_RID(PropertyMap,PropertyList,Property) + SCHEMA_TABLE_END(PropertyMap) + + //------------------------------------------------------------------------- + //PropertyPtr + SCHEMA_TABLE_START(PropertyPtr) + SCHEMA_ITEM_NOFIXED() + SCHEMA_ITEM_RID(PropertyPtr, Property, Property) + SCHEMA_TABLE_END(PropertyPtr) + + //------------------------------------------------------------------------- + //Property + SCHEMA_TABLE_START(Property) + SCHEMA_ITEM(Property, USHORT, PropFlags) + SCHEMA_ITEM_STRING(Property,Name) + SCHEMA_ITEM_BLOB(Property,Type) + SCHEMA_TABLE_END(Property) + + //------------------------------------------------------------------------- + //MethodSemantics + SCHEMA_TABLE_START(MethodSemantics) + SCHEMA_ITEM(MethodSemantics, USHORT, Semantic) + SCHEMA_ITEM_RID(MethodSemantics,Method,Method) + SCHEMA_ITEM_CDTKN(MethodSemantics,Association,HasSemantic) + SCHEMA_TABLE_END(MethodSemantics) + + //------------------------------------------------------------------------- + //MethodImpl + SCHEMA_TABLE_START(MethodImpl) + SCHEMA_ITEM_RID(MethodImpl,Class,TypeDef) + SCHEMA_ITEM_CDTKN(MethodImpl,MethodBody,MethodDefOrRef) + SCHEMA_ITEM_CDTKN(MethodImpl, MethodDeclaration, MethodDefOrRef) + SCHEMA_TABLE_END(MethodImpl) + + //------------------------------------------------------------------------- + //ModuleRef + SCHEMA_TABLE_START(ModuleRef) + SCHEMA_ITEM_NOFIXED() + SCHEMA_ITEM_STRING(ModuleRef, Name) + SCHEMA_TABLE_END(ModuleRef) + + //------------------------------------------------------------------------- + // TypeSpec + SCHEMA_TABLE_START(TypeSpec) + SCHEMA_ITEM_NOFIXED() + SCHEMA_ITEM_BLOB(TypeSpec,Signature) + SCHEMA_TABLE_END(TypeSpec) + + //------------------------------------------------------------------------- + // ENCLog + SCHEMA_TABLE_START(ENCLog) + SCHEMA_ITEM(ENCLog, ULONG, Token) + SCHEMA_ITEM(ENCLog, ULONG, FuncCode) + SCHEMA_TABLE_END(ENCLog) + + //------------------------------------------------------------------------- + // ImplMap + SCHEMA_TABLE_START(ImplMap) + SCHEMA_ITEM(ImplMap, USHORT, MappingFlags) + SCHEMA_ITEM_CDTKN(ImplMap, MemberForwarded, MemberForwarded) + SCHEMA_ITEM_STRING(ImplMap, ImportName) + SCHEMA_ITEM_RID(ImplMap, ImportScope, ModuleRef) + SCHEMA_TABLE_END(ImplMap) + + //------------------------------------------------------------------------- + // ENCMap + SCHEMA_TABLE_START(ENCMap) + SCHEMA_ITEM(ENCMap, ULONG, Token) + SCHEMA_TABLE_END(ENCMap) + + //------------------------------------------------------------------------- + // FieldRVA + SCHEMA_TABLE_START(FieldRVA) + SCHEMA_ITEM(FieldRVA, ULONG, RVA) + SCHEMA_ITEM_RID(FieldRVA, Field, Field) + SCHEMA_TABLE_END(FieldRVA) + + //------------------------------------------------------------------------- + // Assembly + SCHEMA_TABLE_START(Assembly) + SCHEMA_ITEM(Assembly, ULONG, HashAlgId) + SCHEMA_ITEM(Assembly, USHORT, MajorVersion) + SCHEMA_ITEM(Assembly, USHORT, MinorVersion) + SCHEMA_ITEM(Assembly, USHORT, BuildNumber) + SCHEMA_ITEM(Assembly, USHORT, RevisionNumber) + SCHEMA_ITEM(Assembly, ULONG, Flags) + SCHEMA_ITEM_BLOB(Assembly, PublicKey) + SCHEMA_ITEM_STRING(Assembly, Name) + SCHEMA_ITEM_STRING(Assembly, Locale) + SCHEMA_TABLE_END(Assembly) + + //------------------------------------------------------------------------- + // AssemblyProcessor + SCHEMA_TABLE_START(AssemblyProcessor) + SCHEMA_ITEM(AssemblyProcessor, ULONG, Processor) + SCHEMA_TABLE_END(AssemblyProcessor) + + //------------------------------------------------------------------------- + // AssemblyOS + SCHEMA_TABLE_START(AssemblyOS) + SCHEMA_ITEM(AssemblyOS, ULONG, OSPlatformId) + SCHEMA_ITEM(AssemblyOS, ULONG, OSMajorVersion) + SCHEMA_ITEM(AssemblyOS, ULONG, OSMinorVersion) + SCHEMA_TABLE_END(AssemblyOS) + + //------------------------------------------------------------------------- + // AssemblyRef + SCHEMA_TABLE_START(AssemblyRef) + SCHEMA_ITEM(AssemblyRef, USHORT, MajorVersion) + SCHEMA_ITEM(AssemblyRef, USHORT, MinorVersion) + SCHEMA_ITEM(AssemblyRef, USHORT, BuildNumber) + SCHEMA_ITEM(AssemblyRef, USHORT, RevisionNumber) + SCHEMA_ITEM(AssemblyRef, ULONG, Flags) + SCHEMA_ITEM_BLOB(AssemblyRef, PublicKeyOrToken) + SCHEMA_ITEM_STRING(AssemblyRef, Name) + SCHEMA_ITEM_STRING(AssemblyRef, Locale) + SCHEMA_ITEM_BLOB(AssemblyRef, HashValue) + SCHEMA_TABLE_END(AssemblyRef) + + //------------------------------------------------------------------------- + // AssemblyRefProcessor + SCHEMA_TABLE_START(AssemblyRefProcessor) + SCHEMA_ITEM(AssemblyRefProcessor, ULONG, Processor) + SCHEMA_ITEM_RID(AssemblyRefProcessor, AssemblyRef, AssemblyRef) + SCHEMA_TABLE_END(AssemblyRefProcessor) + + //------------------------------------------------------------------------- + // AssemblyRefOS + SCHEMA_TABLE_START(AssemblyRefOS) + SCHEMA_ITEM(AssemblyRefOS, ULONG, OSPlatformId) + SCHEMA_ITEM(AssemblyRefOS, ULONG, OSMajorVersion) + SCHEMA_ITEM(AssemblyRefOS, ULONG, OSMinorVersion) + SCHEMA_ITEM_RID(AssemblyRefOS, AssemblyRef, AssemblyRef) + SCHEMA_TABLE_END(AssemblyRefOS) + + //------------------------------------------------------------------------- + // File + SCHEMA_TABLE_START(File) + SCHEMA_ITEM(File, ULONG, Flags) + SCHEMA_ITEM_STRING(File, Name) + SCHEMA_ITEM_BLOB(File, HashValue) + SCHEMA_TABLE_END(File) + + //------------------------------------------------------------------------- + // ExportedType + SCHEMA_TABLE_START(ExportedType) + SCHEMA_ITEM(ExportedType, ULONG, Flags) + SCHEMA_ITEM(ExportedType, ULONG, TypeDefId) + SCHEMA_ITEM_STRING(ExportedType, TypeName) + SCHEMA_ITEM_STRING(ExportedType, TypeNamespace) + SCHEMA_ITEM_CDTKN(ExportedType, Implementation, Implementation) + SCHEMA_TABLE_END(ExportedType) + + //------------------------------------------------------------------------- + // ManifestResource + SCHEMA_TABLE_START(ManifestResource) + SCHEMA_ITEM(ManifestResource, ULONG, Offset) + SCHEMA_ITEM(ManifestResource, ULONG, Flags) + SCHEMA_ITEM_STRING(ManifestResource, Name) + SCHEMA_ITEM_CDTKN(ManifestResource, Implementation, Implementation) + SCHEMA_TABLE_END(ManifestResource) + + //------------------------------------------------------------------------- + // NestedClass + SCHEMA_TABLE_START(NestedClass) + SCHEMA_ITEM_RID(NestedClass, NestedClass, TypeDef) + SCHEMA_ITEM_RID(NestedClass, EnclosingClass, TypeDef) + SCHEMA_TABLE_END(NestedClass) + + + //------------------------------------------------------------------------- + // GenericParam + SCHEMA_TABLE_START(GenericParam) + SCHEMA_ITEM(GenericParam, USHORT, Number) + SCHEMA_ITEM(GenericParam, USHORT, Flags) + SCHEMA_ITEM_CDTKN(GenericParam, Owner, TypeOrMethodDef) + SCHEMA_ITEM_STRING(GenericParam, Name) + SCHEMA_TABLE_END(GenericParam) + + //------------------------------------------------------------------------- + // Transitional table for Metadata v1.1 for GenericParam + SCHEMA_TABLE_START(GenericParamV1_1) + SCHEMA_ITEM(GenericParam, USHORT, Number) + SCHEMA_ITEM(GenericParam, USHORT, Flags) + SCHEMA_ITEM_CDTKN(GenericParam, Owner, TypeOrMethodDef) + SCHEMA_ITEM_STRING(GenericParam, Name) + SCHEMA_ITEM_CDTKN(GenericParam, Kind, TypeDefOrRef) + SCHEMA_TABLE_END(GenericParam) + + + + //------------------------------------------------------------------------- + //MethodSpec + SCHEMA_TABLE_START(MethodSpec) + SCHEMA_ITEM_NOFIXED() + SCHEMA_ITEM_CDTKN(MethodSpec, Method, MethodDefOrRef) + SCHEMA_ITEM_BLOB(MethodSpec, Instantiation) + SCHEMA_TABLE_END(MethodSpec) + + //------------------------------------------------------------------------- + // GenericParamConstraint + SCHEMA_TABLE_START(GenericParamConstraint) + SCHEMA_ITEM_RID(GenericParamConstraint, Owner, GenericParam) + SCHEMA_ITEM_CDTKN(GenericParamConstraint, Constraint, TypeDefOrRef) + SCHEMA_TABLE_END(GenericParamConstraint) + +// eof ------------------------------------------------------------------------ diff --git a/src/md/runtime/metamodelro.cpp b/src/md/runtime/metamodelro.cpp new file mode 100644 index 0000000000..0feb153a2f --- /dev/null +++ b/src/md/runtime/metamodelro.cpp @@ -0,0 +1,444 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +//***************************************************************************** +// MetaModelRO.cpp -- Read-only implementation of compressed COM+ metadata. +// + +// +//***************************************************************************** +#include "stdafx.h" + +#include "metamodelro.h" +#include <posterror.h> +#include <corerror.h> +#include "metadatatracker.h" + +//***************************************************************************** +// Set the pointers to consecutive areas of a large buffer. +//***************************************************************************** +__checkReturn +HRESULT +CMiniMd::InitializeTables( + MetaData::DataBlob tablesData) +{ + HRESULT hr; + + for (int i = 0; i < TBL_COUNT; i++) + { + // This table data + MetaData::DataBlob tableData; + + S_UINT32 cbTableSize = + S_UINT32(m_TableDefs[i].m_cbRec) * + S_UINT32(m_Schema.m_cRecs[i]); + if (cbTableSize.IsOverflow()) + { + Debug_ReportError("Table is too large - size overflow."); + return CLDB_E_FILE_CORRUPT; + } + if (!tablesData.GetDataOfSize(cbTableSize.Value(), &tableData)) + { + Debug_ReportError("Table is not within MetaData tables block."); + return CLDB_E_FILE_CORRUPT; + } + _ASSERTE(cbTableSize.Value() == tableData.GetSize()); + + METADATATRACKER_ONLY(MetaDataTracker::NoteSection( + i, + tableData.GetDataPointer(), + tableData.GetSize(), + m_TableDefs[i].m_cbRec)); + + IfFailRet(m_Tables[i].Initialize( + m_TableDefs[i].m_cbRec, + tableData, + FALSE)); // fCopyData + } + + return S_OK; +} // CMiniMd::SetTablePointers + +//***************************************************************************** +// Given a buffer that contains a MiniMd, init to read it. +//***************************************************************************** +HRESULT +CMiniMd::InitOnMem( + void *pvBuf, // The buffer. + ULONG ulBufLen) // Size of the buffer.. +{ + HRESULT hr = S_OK; + ULONG cbData; + BYTE *pBuf = reinterpret_cast<BYTE*>(pvBuf); + + // Uncompress the schema from the buffer into our structures. + IfFailGo(SchemaPopulate(pvBuf, ulBufLen, &cbData)); + PREFAST_ASSUME(cbData <= ulBufLen); + + // There shouldn't be any pointer tables. + if ((m_Schema.m_cRecs[TBL_MethodPtr] != 0) || (m_Schema.m_cRecs[TBL_FieldPtr] != 0)) + { + Debug_ReportError("MethodPtr and FieldPtr tables are not allowed in Read-Only format."); + return PostError(CLDB_E_FILE_CORRUPT); + } + + // initialize the pointers to the rest of the data. + IfFailGo(InitializeTables(MetaData::DataBlob(pBuf + Align4(cbData), ulBufLen-cbData))); + +ErrExit: + return hr; +} // CMiniMd::InitOnMem + +//***************************************************************************** +// Validate cross-stream consistency. +//***************************************************************************** +HRESULT +CMiniMd::PostInit( + int iLevel) +{ + return S_OK; +} // CMiniMd::PostInit + +//***************************************************************************** +// converting a ANSI heap string to unicode string to an output buffer +//***************************************************************************** +HRESULT +CMiniMd::Impl_GetStringW( + ULONG ix, + __inout_ecount (cchBuffer) LPWSTR szOut, + ULONG cchBuffer, + ULONG *pcchBuffer) +{ + LPCSTR szString; // Single byte version. + int iSize; // Size of resulting string, in wide chars. + HRESULT hr = NOERROR; + + IfFailGo(getString(ix, &szString)); + + if (*szString == 0) + { + // If emtpy string "", return pccBuffer 0 + if ((szOut != NULL) && (cchBuffer != 0)) + szOut[0] = W('\0'); + if (pcchBuffer != NULL) + *pcchBuffer = 0; + goto ErrExit; + } + iSize = ::WszMultiByteToWideChar(CP_UTF8, 0, szString, -1, szOut, cchBuffer); + if (iSize == 0) + { + // What was the problem? + DWORD dwNT = GetLastError(); + + // Not truncation? + if (dwNT != ERROR_INSUFFICIENT_BUFFER) + IfFailGo(HRESULT_FROM_NT(dwNT)); + + // Truncation error; get the size required. + if (pcchBuffer != NULL) + *pcchBuffer = ::WszMultiByteToWideChar(CP_UTF8, 0, szString, -1, NULL, 0); + + if ((szOut != NULL) && (cchBuffer > 0)) + { // null-terminate the truncated output string + szOut[cchBuffer - 1] = W('\0'); + } + + hr = CLDB_S_TRUNCATION; + goto ErrExit; + } + if (pcchBuffer != NULL) + *pcchBuffer = iSize; + +ErrExit: + return hr; +} // CMiniMd::Impl_GetStringW + + +//***************************************************************************** +// Given a table with a pointer (index) to a sequence of rows in another +// table, get the RID of the end row. This is the STL-ish end; the first row +// not in the list. Thus, for a list of 0 elements, the start and end will +// be the same. +//***************************************************************************** +__checkReturn +HRESULT +CMiniMd::Impl_GetEndRidForColumn( // The End rid. + UINT32 nTableIndex, + RID nRowIndex, + CMiniColDef &def, // Column containing the RID into other table. + UINT32 nTargetTableIndex, // The other table. + RID *pEndRid) +{ + HRESULT hr; + _ASSERTE(nTableIndex < TBL_COUNT); + RID nLastRowIndex = m_Schema.m_cRecs[nTableIndex]; + + // Last rid in range from NEXT record, or count of table, if last record. + if (nRowIndex < nLastRowIndex) + { + BYTE *pRow; + IfFailRet(Impl_GetRow(nTableIndex, nRowIndex + 1, &pRow)); + *pEndRid = getIX(pRow, def); + } + else // Convert count to 1-based rid. + { + if (nRowIndex != nLastRowIndex) + { + Debug_ReportError("Invalid table row index."); + IfFailRet(METADATA_E_INDEX_NOTFOUND); + } + _ASSERTE(nTargetTableIndex < TBL_COUNT); + *pEndRid = m_Schema.m_cRecs[nTargetTableIndex] + 1; + } + + return S_OK; +} // CMiniMd::Impl_GetEndRidForColumn + + +//***************************************************************************** +// return all found CAs in an enumerator +//***************************************************************************** +HRESULT +CMiniMd::CommonEnumCustomAttributeByName( + mdToken tkObj, // [IN] Object with Custom Attribute. + LPCUTF8 szName, // [IN] Name of desired Custom Attribute. + bool fStopAtFirstFind, // [IN] just find the first one + HENUMInternal *phEnum) // enumerator to fill up +{ + HRESULT hr = S_OK; + HRESULT hrRet = S_FALSE; // Assume that we won't find any + ULONG ridStart, ridEnd; // Loop start and endpoints. + + _ASSERTE(phEnum != NULL); + + memset(phEnum, 0, sizeof(HENUMInternal)); + + HENUMInternal::InitDynamicArrayEnum(phEnum); + + phEnum->m_tkKind = mdtCustomAttribute; + + // Get the list of custom values for the parent object. + + IfFailGo(getCustomAttributeForToken(tkObj, &ridEnd, &ridStart)); + if (ridStart == 0) + return S_FALSE; + + // Look for one with the given name. + for (; ridStart < ridEnd; ++ridStart) + { + IfFailGoto(CompareCustomAttribute( tkObj, szName, ridStart), ErrExit); + if (hr == S_OK) + { + // If here, found a match. + hrRet = S_OK; + IfFailGo(HENUMInternal::AddElementToEnum( + phEnum, + TokenFromRid(ridStart, mdtCustomAttribute))); + if (fStopAtFirstFind) + goto ErrExit; + } + } + +ErrExit: + if (FAILED(hr)) + return hr; + return hrRet; +} // CMiniMd::CommonEnumCustomAttributeByName + + +//***************************************************************************** +// Search a table for the row containing the given key value. +// EG. Constant table has pointer back to Param or Field. +// +//***************************************************************************** +__checkReturn +HRESULT +CMiniMd::vSearchTable( + ULONG ixTbl, // Table to search. + CMiniColDef sColumn, // Sorted key column, containing search value. + ULONG ulTarget, // Target for search. + RID *pRid) // RID of matching row, or 0. +{ + HRESULT hr; + void *pRow = NULL; // Row from a table. + ULONG val; // Value from a row. + int lo, mid, hi; // binary search indices. + + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // If you change the rows touched while searching, please update + // CMiniMdRW::GetHotMetadataTokensSearchAware + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + // Start with entire table. + lo = 1; + hi = GetCountRecs(ixTbl); + // While there are rows in the range... + while (lo <= hi) + { // Look at the one in the middle. + mid = (lo + hi) / 2; + IfFailRet(getRow(ixTbl, mid, &pRow)); + val = getIX_NoLogging(pRow, sColumn); + // If equal to the target, done. + if (val == ulTarget) + { + *pRid = mid; + METADATATRACKER_ONLY(MetaDataTracker::NoteSearch(pRow)); + return S_OK; + } + // If middle item is too small, search the top half. + if (val < ulTarget) + lo = mid + 1; + else // but if middle is to big, search bottom half. + hi = mid - 1; + } + // Didn't find anything that matched. + *pRid = 0; + + METADATATRACKER_ONLY(MetaDataTracker::NoteSearch(pRow)); + return S_OK; +} // CMiniMd::vSearchTable + +//***************************************************************************** +// Search a table for the highest-RID row containing a value that is less than +// or equal to the target value. EG. TypeDef points to first Field, but if +// a TypeDef has no fields, it points to first field of next TypeDef. +//***************************************************************************** +__checkReturn +HRESULT +CMiniMd::vSearchTableNotGreater( + ULONG ixTbl, // Table to search. + CMiniColDef sColumn, // the column def containing search value + ULONG ulTarget, // target for search + RID *pRid) // RID of matching row, or 0 +{ + HRESULT hr; + void *pRow = NULL; // Row from a table. + ULONG cRecs; // Rows in the table. + ULONG val = 0; // Value from a table. + ULONG lo, mid = 0, hi; // binary search indices. + + cRecs = GetCountRecs(ixTbl); + + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // If you change the rows touched while searching, please update + // CMiniMdRW::GetHotMetadataTokensSearchAware + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + // Start with entire table. + lo = 1; + hi = cRecs; + // If no recs, return. + if (lo > hi) + { + *pRid = 0; + return S_OK; + } + // While there are rows in the range... + while (lo <= hi) + { // Look at the one in the middle. + mid = (lo + hi) / 2; + IfFailRet(getRow(ixTbl, mid, &pRow)); + val = getIX_NoLogging(pRow, sColumn); + // If equal to the target, done searching. + if (val == ulTarget) + break; + // If middle item is too small, search the top half. + if (val < ulTarget) + lo = mid + 1; + else // but if middle is to big, search bottom half. + hi = mid - 1; + } + + METADATATRACKER_ONLY(MetaDataTracker::NoteSearch(pRow)); + + // May or may not have found anything that matched. Mid will be close, but may + // be to high or too low. It should point to the highest acceptable + // record. + + // If the value is greater than the target, back up just until the value is + // less than or equal to the target. SHOULD only be one step. + if (val > ulTarget) + { + while (val > ulTarget) + { + // If there is nothing else to look at, we won't find it. + if (--mid < 1) + break; + IfFailRet(getRow(ixTbl, mid, &pRow)); + val = getIX(pRow, sColumn); + } + } + else + { + // Value is less than or equal to the target. As long as the next + // record is also acceptable, move forward. + while (mid < cRecs) + { + // There is another record. Get its value. + IfFailRet(getRow(ixTbl, mid+1, &pRow)); + val = getIX(pRow, sColumn); + // If that record is too high, stop. + if (val > ulTarget) + break; + mid++; + } + } + + // Return the value that's just less than the target. + *pRid = mid; + return S_OK; +} // CMiniMd::vSearchTableNotGreater + +//***************************************************************************** +// return just the blob value of the first found CA matching the query. +// returns S_FALSE if there is no match +//***************************************************************************** +HRESULT +CMiniMd::CommonGetCustomAttributeByNameEx( + mdToken tkObj, // [IN] Object with Custom Attribute. + LPCUTF8 szName, // [IN] Name of desired Custom Attribute. + mdCustomAttribute *ptkCA, // [OUT] put custom attribute token here + const void **ppData, // [OUT] Put pointer to data here. + ULONG *pcbData) // [OUT] Put size of data here. +{ + HRESULT hr; + + ULONG cbData; + CustomAttributeRec *pRec; + + ULONG ridStart, ridEnd; // Loop start and endpoints. + + // Get the list of custom values for the parent object. + + IfFailGo(getCustomAttributeForToken(tkObj, &ridEnd, &ridStart)); + + hr = S_FALSE; + if (ridStart == 0) + { + goto ErrExit; + } + + // Look for one with the given name. + for (; ridStart < ridEnd; ++ridStart) + { + IfFailGoto(CompareCustomAttribute( tkObj, szName, ridStart), ErrExit); + if (hr == S_OK) + { + if (ppData != NULL) + { + // now get the record out. + if (pcbData == NULL) + pcbData = &cbData; + + IfFailGo(GetCustomAttributeRecord(ridStart, &pRec)); + IfFailGo(getValueOfCustomAttribute(pRec, reinterpret_cast<const BYTE **>(ppData), pcbData)); + if (ptkCA) + *ptkCA = TokenFromRid(mdtCustomAttribute, ridStart); + } + break; + } + } + +ErrExit: + return hr; +} // CMiniMd::CommonGetCustomAttributeByName diff --git a/src/md/runtime/recordpool.cpp b/src/md/runtime/recordpool.cpp new file mode 100644 index 0000000000..da4bcbc9e9 --- /dev/null +++ b/src/md/runtime/recordpool.cpp @@ -0,0 +1,388 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +//***************************************************************************** +// RecordPool.cpp -- Implementation of record heaps. +// + +// +//***************************************************************************** +#include "stdafx.h" +#include <recordpool.h> + +#define RECORDPOOL_GROW_FACTOR 8 +#define RECORDPOOL_GROW_MAX 2048 +#define RECORDPOOL_GROW_MINROWS 2 +#define RECORDPOOL_GROW_DEFAULTROWS 16 + +HRESULT +RecordPool::InitNew( + UINT32 cbRec, // Record size. + UINT32 cRecsInit) // Initial guess of count of record. +{ + HRESULT hr; + S_UINT32 cbGrow; // Initial grow size of the pool. + + // Size of each record is fixed. + m_cbRec = cbRec; + + if (cRecsInit > 0) + { + cbGrow = S_UINT32(cbRec) * S_UINT32(cRecsInit); + } + else + { + cbGrow = S_UINT32(cbRec) * S_UINT32(RECORDPOOL_GROW_DEFAULTROWS); + } + if (cbGrow.IsOverflow()) + { + Debug_ReportInternalError("Growing record pool overflowed."); + return CLDB_E_INTERNALERROR; + } + + m_ulGrowInc = cbGrow.Value(); + + IfFailRet(StgPool::InitNew()); + + // If there is an initial size for the record pool, grow to that now. + if (cRecsInit > 0) + { + if (!Grow(cbGrow.Value())) + return E_OUTOFMEMORY; + } + + return S_OK; +} // RecordPool::InitNew + +//***************************************************************************** +// Load a Record heap from persisted memory. If a copy of the data is made +// (so that it may be updated), then a new hash table is generated which can +// be used to elminate duplicates with new Records. +//***************************************************************************** +HRESULT +RecordPool::InitOnMem( + ULONG cbRec, // Record size. + void *pData, // Predefined data. + ULONG iSize, // Size of data. + BOOL fReadOnly) // true if append is forbidden. +{ + HRESULT hr; + m_cbRec = cbRec; + + // Let base class init our memory structure. + IfFailRet(StgPool::InitOnMem(pData, iSize, fReadOnly)); + + // For init on existing mem case. + if ((pData != NULL) && (iSize != 0)) + { + // If we are doing an update in place don't make a copy + // If we cannot update, then we don't need a hash table. + if (fReadOnly) + return S_OK; + + // Other wise copy the memory to do the update + IfFailRet(TakeOwnershipOfInitMem()); + } + + return S_OK; +} // RecordPool::InitOnMem + +//***************************************************************************** +// Allocate memory if we don't have any, or grow what we have. If successful, +// then at least iRequired bytes will be allocated. +//***************************************************************************** +bool RecordPool::Grow( // true if successful. + ULONG iRequired) // Min required bytes to allocate. +{ + // Allocate the memory. + if (!StgPool::Grow(iRequired)) + return false; + + // Zero the new memory. + memset(GetNextLocation(), 0, GetCbSegAvailable()); + + return true; +} // bool RecordProol::Grow() + +//***************************************************************************** +// The Record will be added to the pool. The index of the Record in the pool +// is returned in *piIndex. If the Record is already in the pool, then the +// index will be to the existing copy of the Record. +//***************************************************************************** +HRESULT +RecordPool::AddRecord( + BYTE **ppRecord, + UINT32 *pnIndex) // Return 1-based index of Record here. +{ + _ASSERTE(pnIndex != NULL); + + // Space on heap for new Record? + if (m_cbRec > GetCbSegAvailable()) + { + if (!Grow(m_cbRec)) + { + *ppRecord = NULL; + return E_OUTOFMEMORY; + } + } + + // Records should be aligned on record boundaries. + _ASSERTE((GetNextOffset() % m_cbRec) == 0); + + // Copy the Record to the heap. + *ppRecord = GetNextLocation(); + + // Give the 1-based index back to caller. + *pnIndex = (GetNextOffset() / m_cbRec) + 1; + + // Update heap counters. + SegAllocate(m_cbRec); + + return S_OK; +} // RecordPool::AddRecord + +//***************************************************************************** +// Insert a Record into the pool. The index of the Record before which to +// insert is specified. Shifts all records down. Return a pointer to the +// new record. +//***************************************************************************** +HRESULT +RecordPool::InsertRecord( + UINT32 nIndex, // [IN] Insert record before this. + BYTE **ppRecord) +{ + HRESULT hr; + StgPoolSeg *pCurSeg; // Current segment. + StgPoolSeg *pPrevSeg; // Previous segment. + BYTE *pSegEnd; // Last record in a segment. + BYTE *pFrom; // A copy/move source. + ULONG cbMove; // Bytes to move. + BYTE *pNew; // New record. + + // Notice the case of appending. + if (nIndex == (Count() + 1)) + { + UINT32 nNewIndex_Ignore; + return AddRecord(ppRecord, &nNewIndex_Ignore); + } + + // If past end or before beginning, invalid. + if ((nIndex > Count()) || (nIndex == 0)) + { + Debug_ReportError("Invalid index passed for inserting record."); + return CLDB_E_INDEX_NOTFOUND; + } + + // This code works by allocating a new record at the end. + // The last record is moved to the new end record. + // Working backwards through the chained segments, + // shift the segment by one record, so the empty record + // is at the start of the segment instead of the end. + // copy the last record of the previous segment to the + // newly emptied first record of the current segment. + // When the segment containing the insert point is finally + // reached, its last record is empty (from above loop), so + // shift from the insertion point to the end-1 by one record. + + // Current last record. + pCurSeg = m_pCurSeg; + IfFailRet(GetRecord(Count(), &pSegEnd)); + _ASSERTE(hr == S_OK); + + // Add an empty record to the end of the heap. + { + UINT32 nLastRecordIndex_Ignore; + IfFailRet(AddRecord(&pNew, &nLastRecordIndex_Ignore)); + } + + // Copy the current last record to the new record. + memcpy(pNew, pSegEnd, m_cbRec); + + // While the insert location is prior to the current segment, + while (nIndex < GetIndexForRecord(pCurSeg->m_pSegData)) + { + // Shift the segment up by one record. + cbMove = (ULONG)(pSegEnd - pCurSeg->m_pSegData); + memmove(pCurSeg->m_pSegData + m_cbRec, pCurSeg->m_pSegData, cbMove); + + // Find the previous segment. + pPrevSeg = this; + while (pPrevSeg->m_pNextSeg != pCurSeg) + { + pPrevSeg = pPrevSeg->m_pNextSeg; + } + + // Copy the final record of the previous segment to the start of this one. + pSegEnd = pPrevSeg->m_pSegData+pPrevSeg->m_cbSegNext-m_cbRec; + memcpy(pCurSeg->m_pSegData, pSegEnd, m_cbRec); + + // Make the previous segment the current segment. + pCurSeg = pPrevSeg; + } + + // Shift at the insert location, forward by one. + IfFailRet(GetRecord(nIndex, &pFrom)); + _ASSERTE(hr == S_OK); + + cbMove = (ULONG)(pSegEnd - pFrom); + memmove(pFrom + m_cbRec, pFrom, cbMove); + + *ppRecord = pFrom; + + return S_OK; +} // RecordPool::InsertRecord + +//***************************************************************************** +// Return a pointer to a Record given an index previously handed out by +// AddRecord or FindRecord. +//***************************************************************************** +HRESULT +RecordPool::GetRecord( + UINT32 nIndex, // 1-based index of Record in pool. + BYTE **ppRecord) +{ + MetaData::DataBlob record; + + if (nIndex == 0) + { + Debug_ReportError("Invalid index 0 passed."); + *ppRecord = NULL; + return CLDB_E_INDEX_NOTFOUND; + } + + // Convert to 0-based internal form, defer to implementation. + HRESULT hr = GetData((nIndex - 1) * m_cbRec, &record); + if (FAILED(hr)) + { + *ppRecord = NULL; + return hr; + } + _ASSERTE(record.ContainsData(m_cbRec)); + *ppRecord = record.GetDataPointer(); + + return hr; +} // RecordPool::GetRecord + +//***************************************************************************** +// Return the first record in a pool, and set up a context for fast +// iterating through the pool. Note that this scheme does pretty minimal +// error checking. +//***************************************************************************** +void *RecordPool::GetFirstRecord( // Pointer to Record in pool. + void **pContext) // Store context here. +{ + StgPoolSeg **ppSeg = reinterpret_cast<StgPoolSeg**>(pContext); + + *ppSeg = static_cast<StgPoolSeg*>(this); + return (*ppSeg)->m_pSegData; +} // void *RecordPool::GetFirstRecord() + +//***************************************************************************** +// Given a pointer to a record, return a pointer to the next record. +// Note that this scheme does pretty minimal error checking. In particular, +// this will let the caller walk off of the end of valid data in the last +// segment. +//***************************************************************************** +void *RecordPool::GetNextRecord( // Pointer to Record in pool. + void *pRecord, // Current record. + void **pContext) // Stored context here. +{ + BYTE *pbRec = reinterpret_cast<BYTE*>(pRecord); + StgPoolSeg **ppSeg = reinterpret_cast<StgPoolSeg**>(pContext); + + // Get the next record. + pbRec += m_cbRec; + + // Is the next record outside of the current segment? + if (static_cast<ULONG>(pbRec - (*ppSeg)->m_pSegData) >= (*ppSeg)->m_cbSegSize) + { + // Better be exactly one past current segment. + _ASSERTE(static_cast<ULONG>(pbRec - (*ppSeg)->m_pSegData) == (*ppSeg)->m_cbSegSize); + // Switch the context pointer. + *ppSeg = (*ppSeg)->m_pNextSeg; + // Next record is start of next segment. + if (*ppSeg) + return (*ppSeg)->m_pSegData; + else + return 0; + } + + return pbRec; +} // void *RecordPool::GetNextRecord() + +//***************************************************************************** +// Given a pointer to a record, determine the index corresponding to the +// record. +//***************************************************************************** +ULONG RecordPool::GetIndexForRecord( // 1-based index of Record in pool. + const void *pvRecord) // Pointer to Record in pool. +{ + ULONG iPrev = 0; // cumulative index of previous segments. + const StgPoolSeg *pSeg = this; + const BYTE *pRecord = reinterpret_cast<const BYTE*>(pvRecord); + const BYTE *pSegData = NULL; + ULONG ulSegSize; + for (;;) + { // Does the current segment contain the record? + pSegData = pSeg->GetSegData(); + ulSegSize = pSeg->GetSegSize(); + if (pRecord >= pSegData && pRecord < pSegData + ulSegSize) + { // The pointer should be to the start of a record. + _ASSERTE(((pRecord - pSegData) % m_cbRec) == 0); + return (ULONG)(1 + iPrev + (pRecord - pSegData) / m_cbRec); + } + _ASSERTE((ulSegSize % m_cbRec) == 0); + iPrev += ulSegSize / m_cbRec; + pSeg = pSeg->GetNextSeg(); + // If out of data, didn't find the record. + if (pSeg == 0) + return 0; + } +} // ULONG RecordPool::GetIndexForRecord() + +//***************************************************************************** +// Given a purported pointer to a record, determine if the pointer is valid. +//***************************************************************************** +int RecordPool::IsValidPointerForRecord(// true or false. + const void *pvRecord) // Pointer to Record in pool. +{ + const StgPoolSeg *pSeg; + const BYTE *pRecord = reinterpret_cast<const BYTE*>(pvRecord); + const BYTE *pSegData = NULL; + for (pSeg = this; (pSeg); pSeg = pSeg->GetNextSeg()) + { // Does the current segment contain the record? + pSegData = pSeg->GetSegData(); + if ((pRecord >= pSegData) && (pRecord < pSegData + pSeg->GetSegSize())) + { // The pointer should be to the start of a record. + return (((pRecord - pSegData) % m_cbRec) == 0); + } + _ASSERTE((pSeg->GetSegSize() % m_cbRec) == 0); + } + return 0; +} // int RecordPool::IsValidPointerForRecord() + +//***************************************************************************** +// Replace the contents of this pool with those from another pool. The other +// pool loses ownership of the memory. +//***************************************************************************** +HRESULT RecordPool::ReplaceContents( + RecordPool *pOther) // The other record pool. +{ + // Release any memory currently held. + Uninit(); + + // Grab the new data. + *this = *pOther; + + // If the other pool's curseg pointed to itself, make this pool point to itself. + if (pOther->m_pCurSeg == pOther) + m_pCurSeg = this; + + // Fix the other pool so it won't free the memory that this one + // just hijacked. + pOther->m_pSegData = (BYTE*)m_zeros; + pOther->m_pNextSeg = 0; + pOther->Uninit(); + + return S_OK; +} // HRESULT RecordPool::ReplaceContents() diff --git a/src/md/runtime/stdafx.cpp b/src/md/runtime/stdafx.cpp new file mode 100644 index 0000000000..ff341e19a7 --- /dev/null +++ b/src/md/runtime/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/runtime/stdafx.h b/src/md/runtime/stdafx.h new file mode 100644 index 0000000000..061551a832 --- /dev/null +++ b/src/md/runtime/stdafx.h @@ -0,0 +1,24 @@ +// 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 "mdcommon.h" + +#endif // __STDAFX_H_ diff --git a/src/md/runtime/wks/.gitmirror b/src/md/runtime/wks/.gitmirror new file mode 100644 index 0000000000..f507630f94 --- /dev/null +++ b/src/md/runtime/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/runtime/wks/CMakeLists.txt b/src/md/runtime/wks/CMakeLists.txt new file mode 100644 index 0000000000..9a1f72ed25 --- /dev/null +++ b/src/md/runtime/wks/CMakeLists.txt @@ -0,0 +1,5 @@ +include(../../md_wks.cmake) + +add_precompiled_header(stdafx.h ../stdafx.cpp MDRUNTIME_SOURCES) +add_library_clr(mdruntime_wks ${MDRUNTIME_SOURCES}) + diff --git a/src/md/runtime/wks/MDRuntime.nativeproj b/src/md/runtime/wks/MDRuntime.nativeproj new file mode 100644 index 0000000000..bc95bf65f2 --- /dev/null +++ b/src/md/runtime/wks/MDRuntime.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\Runtime\Runtime.settings.targets" /> + + <!--Leaf project Properties--> + <PropertyGroup> + <BuildCoreBinaries>true</BuildCoreBinaries> + <BuildSysBinaries>true</BuildSysBinaries> + <OutputName>MDRuntime</OutputName> + </PropertyGroup> + + <!--Import the targets--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" /> +</Project> |