diff options
Diffstat (limited to 'src/md/enc/mdinternalrw.cpp')
-rw-r--r-- | src/md/enc/mdinternalrw.cpp | 4355 |
1 files changed, 4355 insertions, 0 deletions
diff --git a/src/md/enc/mdinternalrw.cpp b/src/md/enc/mdinternalrw.cpp new file mode 100644 index 0000000000..02fb407358 --- /dev/null +++ b/src/md/enc/mdinternalrw.cpp @@ -0,0 +1,4355 @@ +// 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: MDInternalRW.cpp +// + +// Notes: +// +// +// =========================================================================== +#include "stdafx.h" +#include "../runtime/mdinternalro.h" +#include "../compiler/regmeta.h" +#include "../compiler/importhelper.h" +#include "mdinternalrw.h" +#include "metamodelro.h" +#include "liteweightstgdb.h" + +#ifdef FEATURE_METADATA_INTERNAL_APIS + +__checkReturn +HRESULT _GetFixedSigOfVarArg( // S_OK or error. + PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob of COM+ method signature + ULONG cbSigBlob, // [IN] size of signature + CQuickBytes *pqbSig, // [OUT] output buffer for fixed part of VarArg Signature + ULONG *pcbSigBlob); // [OUT] number of bytes written to the above output buffer + +__checkReturn +HRESULT _FillMDDefaultValue( + BYTE bType, + void const *pValue, + ULONG cbValue, + MDDefaultValue *pMDDefaultValue); + + +//***************************************************************************** +// Serve as a delegator to call ImportHelper::MergeUpdateTokenInSig. Or we will +// need to include ImportHelper into our md\runtime directory. +//***************************************************************************** +__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 +{ +#ifdef FEATURE_METADATA_EMIT + IMetaModelCommon *pCommon = pImport->GetMetaModelCommon(); + RegMeta *pAssemEmitRM = static_cast<RegMeta*>(pAssemEmit); + RegMeta *pEmitRM = static_cast<RegMeta*>(emit); + + CMiniMdRW *pMiniMdAssemEmit = pAssemEmitRM ? &pAssemEmitRM->m_pStgdb->m_MiniMd : NULL; + CMiniMdRW *pMiniMdEmit = &(pEmitRM->m_pStgdb->m_MiniMd); + IMetaModelCommon *pCommonAssemImport = pAssemImport ? pAssemImport->GetMetaModelCommon() : NULL; + + return ImportHelper::MergeUpdateTokenInSig( + pMiniMdAssemEmit, // The assembly emit scope. + pMiniMdEmit, // The emit scope. + pCommonAssemImport, // Assembly scope where the signature is from. + pbHashValue, // Hash value for the import scope. + cbHashValue, // Size in bytes. + pCommon, // The scope where signature is from. + pbSigBlob, // signature from the imported scope + NULL, // Internal OID mapping structure. + pqkSigEmit, // [OUT] translated signature + NULL, // start from first byte of the signature + NULL, // don't care how many bytes consumed + pcbSig); // [OUT] total number of bytes write to pqkSigEmit + +#else //!FEATURE_METADATA_EMIT + // This API doesn't make sense without supporting public Emit APIs + return E_NOTIMPL; +#endif //!FEATURE_METADATA_EMIT +} // TranslateSigHelper + + +//***************************************************************************** +// Given an IMDInternalImport on a CMiniMd[RO], convert to CMiniMdRW. +//***************************************************************************** +__checkReturn +STDAPI ConvertRO2RW( + IUnknown *pRO, // [IN] The RO interface to convert. + REFIID riid, // [IN] The interface desired. + void **ppIUnk) // [OUT] Return interface on success. +{ + HRESULT hr = S_OK; // A result. + IMDInternalImportENC *pRW = 0; // To test the RW-ness of the input iface. + MDInternalRW *pInternalRW = 0; // Gets the new RW object. + MDInternalRO *pTrustedRO = 0; + + // Avoid confusion. + *ppIUnk = 0; + + IfFailGo(VerifyNotWinMD(pRO, "ConvertRO2RW() not supported on .winmd files.")); + + // If the interface is already RW, done, just return. + if (pRO->QueryInterface(IID_IMDInternalImportENC, (void**)&pRW) == S_OK) + { + hr = pRO->QueryInterface(riid, ppIUnk); + goto ErrExit; + } + + // Create the new RW object. + pInternalRW = new (nothrow) MDInternalRW; + IfNullGo( pInternalRW ); + + // Init from the RO object. Convert as read-only; QI will make writable if + // so needed. + + // ! QI for IID_IUnknown will return MDInternalRO*. Not that COM guarantees such a thing but MDInternalRO knows about + IfFailGo( pRO->QueryInterface(IID_IUnknown, (void**)&pTrustedRO) ); + IfFailGo( pInternalRW->InitWithRO(pTrustedRO, true)); + IfFailGo( pInternalRW->QueryInterface(riid, ppIUnk) ); + +ErrExit: + if (pRW) + pRW->Release(); + if (pTrustedRO) + pTrustedRO->Release(); + // Clean up the object and [OUT] interface on error. + if (FAILED(hr)) + { + if (pInternalRW) + delete pInternalRW; + *ppIUnk = 0; + } + else if (pInternalRW) + pInternalRW->Release(); + + return hr; +} // ConvertRO2RW + + +//***************************************************************************** +// Helper to get the internal interface with RW format +//***************************************************************************** +__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. +{ + MDInternalRW *pInternalRW = NULL; + HRESULT hr; + + *ppIUnk = 0; + pInternalRW = new (nothrow) MDInternalRW; + IfNullGo( pInternalRW ); + IfFailGo( pInternalRW->Init( + const_cast<void*>(pData), + cbData, + (flags == ofRead) ? true : false) ); + IfFailGo( pInternalRW->QueryInterface(riid, ppIUnk) ); +ErrExit: + if (FAILED(hr)) + { + if (pInternalRW) + delete pInternalRW; + *ppIUnk = 0; + } + else if ( pInternalRW ) + pInternalRW->Release(); + return hr; +} // GetInternalWithRWFormat + + +//***************************************************************************** +// This function returns a IMDInternalImport interface based on the given +// public import interface i.e IMetaDataEmit or IMetaDataImport. +//***************************************************************************** +__checkReturn +STDAPI GetMDInternalInterfaceFromPublic( + IUnknown *pIUnkPublic, // [IN] Given public interface. Must be QI of IUnknown + REFIID riid, // [in] The interface desired. + void **ppIUnkInternal) // [out] Return interface on success. +{ + HRESULT hr = S_OK; + ReleaseHolder<IGetIMDInternalImport> pGetIMDInternalImport; + + // IMDInternalImport is the only internal import interface currently supported by + // this function. + _ASSERTE(riid == IID_IMDInternalImport && pIUnkPublic && ppIUnkInternal); + + if (riid != IID_IMDInternalImport || pIUnkPublic == NULL || ppIUnkInternal == NULL) + IfFailGo(E_INVALIDARG); + IfFailGo( pIUnkPublic->QueryInterface(IID_IGetIMDInternalImport, &pGetIMDInternalImport)); + IfFailGo( pGetIMDInternalImport->GetIMDInternalImport((IMDInternalImport **)ppIUnkInternal)); + +ErrExit: + if (FAILED(hr)) + { + if (ppIUnkInternal) + *ppIUnkInternal = 0; + } + return hr; +} // GetMDInternalInterfaceFromPublic + + +//***************************************************************************** +// This function returns the requested public interface based on the given +// internal import interface. It is caller's responsibility to Release ppIUnkPublic +//***************************************************************************** +__checkReturn +STDAPI GetMDPublicInterfaceFromInternal( + void *pIUnkInternal, // [IN] Given internal interface. + REFIID riid, // [in] The interface desired. + void **ppIUnkPublic) // [out] Return interface on success. +{ + HRESULT hr = S_OK; + IMDInternalImport *pInternalImport = 0;; + IUnknown *pIUnkPublic = NULL; + OptionValue optVal = { MDDupAll, MDRefToDefDefault, MDNotifyDefault, MDUpdateFull, MDErrorOutOfOrderDefault , MDThreadSafetyOn}; + RegMeta *pMeta = 0; + bool isLockedForWrite = false; + + + _ASSERTE(pIUnkInternal && ppIUnkPublic); + *ppIUnkPublic = 0; + + IfFailGo(VerifyNotWinMD((IUnknown*)pIUnkInternal, "GetMDPublicInterfaceFromInternal() not supported on .winmd files.")); + + IfFailGo(ConvertRO2RW((IUnknown*)pIUnkInternal, IID_IMDInternalImport, (void **)&pInternalImport)); + + pIUnkPublic = pInternalImport->GetCachedPublicInterface(TRUE); + if ( pIUnkPublic ) + { + // There is already a cached public interface. GetCachedPublicInterface already AddRef the returned + // public interface. We want to QueryInterface the riid... + // We are done! + hr = pIUnkPublic->QueryInterface(riid, ppIUnkPublic); + pIUnkPublic->Release(); + goto ErrExit; + } + + // grab the write lock when we are creating the corresponding regmeta for the public interface + _ASSERTE( pInternalImport->GetReaderWriterLock() != NULL ); + isLockedForWrite = true; + IfFailGo(pInternalImport->GetReaderWriterLock()->LockWrite()); + + // check again. Maybe someone else beat us to setting the public interface while we are waiting + // for the write lock. Don't need to grab the read lock since we already have the write lock. + *ppIUnkPublic = pInternalImport->GetCachedPublicInterface(FALSE); + if ( *ppIUnkPublic ) + { + // there is already a cached public interface. GetCachedPublicInterface already AddRef the returned + // public interface. + // We are done! + goto ErrExit; + } + + pMeta = new (nothrow) RegMeta(); + IfNullGo(pMeta); + IfFailGo(pMeta->SetOption(&optVal)); + IfFailGo( pMeta->InitWithStgdb((IUnknown*)pInternalImport, ((MDInternalRW*)pInternalImport)->GetMiniStgdb()) ); + IfFailGo( pMeta->QueryInterface(riid, ppIUnkPublic) ); + + // The following makes the public object and the internal object point to each other. + _ASSERTE( pMeta->GetReaderWriterLock() == NULL ); + IfFailGo( pMeta->SetCachedInternalInterface(pInternalImport) ); + IfFailGo( pInternalImport->SetCachedPublicInterface((IUnknown *) *ppIUnkPublic) ); + IfFailGo( pMeta->SetReaderWriterLock(pInternalImport->GetReaderWriterLock() )); + + // Add the new RegMeta to the cache. + IfFailGo( pMeta->AddToCache() ); + +ErrExit: + if (isLockedForWrite) + pInternalImport->GetReaderWriterLock()->UnlockWrite(); + + if (pInternalImport) + pInternalImport->Release(); + + if (FAILED(hr)) + { + if (pMeta) + delete pMeta; + *ppIUnkPublic = 0; + } + return hr; +} // GetMDPublicInterfaceFromInternal + +//***************************************************************************** +// Converts an internal MD import API into the read/write version of this API. +// This could support edit and continue, or modification of the metadata at +// runtime (say for profiling). +//***************************************************************************** +__checkReturn +STDAPI ConvertMDInternalImport( // S_OK, S_FALSE (no conversion), or error. + IMDInternalImport *pIMD, // [in] The metadata to be updated. + IMDInternalImport **ppIMD) // [out] Put the RW here. +{ + HRESULT hr; // A result. + IMDInternalImportENC *pENC = NULL; // ENC interface on the metadata. + + _ASSERTE(pIMD != NULL); + _ASSERTE(ppIMD != NULL); + + // Test whether the MD is already RW. + hr = pIMD->QueryInterface(IID_IMDInternalImportENC, (void**)&pENC); + if (FAILED(hr)) + { // Not yet RW, so do the conversion. + IfFailGo(ConvertRO2RW(pIMD, IID_IMDInternalImport, (void**)ppIMD)); + } + else + { // Already converted; give back same pointer. + *ppIMD = pIMD; + hr = S_FALSE; + } + +ErrExit: + if (pENC) + pENC->Release(); + return hr; +} // ConvertMDInternalImport + + + + + +//***************************************************************************** +// Constructor +//***************************************************************************** +MDInternalRW::MDInternalRW() + : m_pStgdb(NULL), + m_cRefs(1), + m_fOwnStgdb(false), + m_pUnk(NULL), + m_pUserUnk(NULL), + m_pIMetaDataHelper(NULL), + m_pSemReadWrite(NULL), + m_fOwnSem(false) +{ +} // MDInternalRW::MDInternalRW + + + +//***************************************************************************** +// Destructor +//***************************************************************************** +MDInternalRW::~MDInternalRW() +{ + HRESULT hr = S_OK; + + LOCKWRITENORET(); + + // This should have worked if we've cached the internal interface in the past + _ASSERTE(SUCCEEDED(hr) || m_pIMetaDataHelper == NULL || m_pIMetaDataHelper->GetCachedInternalInterface(false) == NULL); + + + if (SUCCEEDED(hr)) + { + + if (m_pIMetaDataHelper) + { + // The internal object is going away before the public object. + // If the internal object owns the reader writer lock, transfer the ownership + // to the public object and clear the cached internal interface from the public interface. + + m_pIMetaDataHelper->SetCachedInternalInterface(NULL); + m_pIMetaDataHelper = NULL; + m_fOwnSem = false; + + } + + UNLOCKWRITE(); + } + if (m_pSemReadWrite && m_fOwnSem) + delete m_pSemReadWrite; + + if ( m_pStgdb && m_fOwnStgdb ) + { + // we own the stgdb so we need to uninit and delete it. + m_pStgdb->Uninit(); + delete m_pStgdb; + } + if ( m_pUserUnk ) + m_pUserUnk->Release(); + if ( m_pUnk ) + m_pUnk->Release(); +} // MDInternalRW::~MDInternalRW + + +//***************************************************************************** +// Set or clear the cached public interfaces. +// NOTE:: Caller should take a Write lock on the reader writer lock. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::SetCachedPublicInterface(IUnknown * pUnk) +{ + IMetaDataHelper * pHelper = NULL; + HRESULT hr = S_OK; + + if (pUnk != NULL) + { + // Internal object and public regmeta should be one to one mapping!! + _ASSERTE(m_pIMetaDataHelper == NULL); + + IfFailRet(pUnk->QueryInterface(IID_IMetaDataHelper, (void **) &pHelper)); + _ASSERTE(pHelper != NULL); + + m_pIMetaDataHelper = pHelper; + pHelper->Release(); + } + else + { + // public object is going away before the internal object. If we don't own the + // reader writer lock, just take over the ownership. + m_fOwnSem = true; + m_pIMetaDataHelper = NULL; + } + return hr; +} // MDInternalRW::SetCachedPublicInterface + + +//***************************************************************************** +// Clear the cached public interfaces. +//***************************************************************************** +IUnknown * MDInternalRW::GetCachedPublicInterface(BOOL fWithLock) +{ + HRESULT hr = S_OK; + IUnknown * pRet = NULL; + if (fWithLock) + { + LOCKREAD(); + + pRet = m_pIMetaDataHelper; + if (pRet != NULL) + pRet->AddRef(); + } + else + { + pRet = m_pIMetaDataHelper; + if (pRet != NULL) + pRet->AddRef(); + } + +ErrExit: + return pRet; +} // MDInternalRW::GetCachedPublicInterface + + +//***************************************************************************** +// Get the Reader-Writer lock +//***************************************************************************** +UTSemReadWrite * MDInternalRW::GetReaderWriterLock() +{ + return getReaderWriterLock(); +} // MDInternalRW::GetReaderWriterLock + +//***************************************************************************** +// IUnknown +//***************************************************************************** +ULONG MDInternalRW::AddRef() +{ + return InterlockedIncrement(&m_cRefs); +} // MDInternalRW::AddRef + +ULONG MDInternalRW::Release() +{ + ULONG cRef; + + cRef = InterlockedDecrement(&m_cRefs); + if (cRef == 0) + { + LOG((LOGMD, "MDInternalRW(0x%08x)::destruction\n", this)); + delete this; + } + return cRef; +} // MDInternalRW::Release + +__checkReturn +HRESULT MDInternalRW::QueryInterface(REFIID riid, void **ppUnk) +{ + *ppUnk = 0; + + if (riid == IID_IUnknown) + *ppUnk = (IUnknown *) (IMDInternalImport *) this; + + else if (riid == IID_IMDInternalImport) + *ppUnk = (IMDInternalImport *) this; + + else if (riid == IID_IMDInternalImportENC) + *ppUnk = (IMDInternalImportENC *) this; + + else if (riid == IID_IMDCommon) + *ppUnk = (IMDCommon*)this; + + else + return E_NOINTERFACE; + AddRef(); + return S_OK; +} // MDInternalRW::QueryInterface + + +//***************************************************************************** +// Initialize +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::Init( + LPVOID pData, // points to meta data section in memory + ULONG cbData, // count of bytes in pData + int bReadOnly) // Is it open for read only? +{ + CLiteWeightStgdbRW * pStgdb = NULL; + HRESULT hr = NOERROR; + OptionValue optVal = { MDDupAll, MDRefToDefDefault, MDNotifyDefault, MDUpdateFull, MDErrorOutOfOrderDefault, MDThreadSafetyOn }; + + pStgdb = new (nothrow) CLiteWeightStgdbRW; + IfNullGo(pStgdb); + + m_pSemReadWrite = new (nothrow) UTSemReadWrite; + IfNullGo(m_pSemReadWrite); + IfFailGo(m_pSemReadWrite->Init()); + m_fOwnSem = true; + INDEBUG(pStgdb->m_MiniMd.Debug_SetLock(m_pSemReadWrite);) + + IfFailGo(pStgdb->InitOnMem(cbData, (BYTE*)pData, bReadOnly)); + IfFailGo(pStgdb->m_MiniMd.SetOption(&optVal)); + m_tdModule = COR_GLOBAL_PARENT_TOKEN; + m_fOwnStgdb = true; + m_pStgdb = pStgdb; + +ErrExit: + // clean up upon errors + if (FAILED(hr) && (pStgdb != NULL)) + { + delete pStgdb; + } + return hr; +} // MDInternalRW::Init + + +//***************************************************************************** +// Initialize with an existing RegMeta. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::InitWithStgdb( + IUnknown *pUnk, // The IUnknow that owns the life time for the existing stgdb + CLiteWeightStgdbRW *pStgdb) // existing lightweight stgdb +{ + // m_fOwnSem should be false because this is the case where we create the internal interface given a public + // interface. + + m_tdModule = COR_GLOBAL_PARENT_TOKEN; + m_fOwnStgdb = false; + m_pStgdb = pStgdb; + + // remember the owner of the light weight stgdb + // AddRef it to ensure the lifetime + // + m_pUnk = pUnk; + m_pUnk->AddRef(); + return NOERROR; +} // MDInternalRW::InitWithStgdb + + +//***************************************************************************** +// Initialize with an existing RO format +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::InitWithRO( + MDInternalRO * pRO, + int bReadOnly) +{ + CLiteWeightStgdbRW * pStgdb = NULL; + HRESULT hr = NOERROR; + OptionValue optVal = { MDDupAll, MDRefToDefDefault, MDNotifyDefault, MDUpdateFull, MDErrorOutOfOrderDefault, MDThreadSafetyOn }; + + pStgdb = new (nothrow) CLiteWeightStgdbRW; + IfNullGo(pStgdb); + + m_pSemReadWrite = new (nothrow) UTSemReadWrite; + IfNullGo(m_pSemReadWrite); + IfFailGo(m_pSemReadWrite->Init()); + m_fOwnSem = true; + INDEBUG(pStgdb->m_MiniMd.Debug_SetLock(m_pSemReadWrite);) + + IfFailGo(pStgdb->m_MiniMd.InitOnRO(&pRO->m_LiteWeightStgdb.m_MiniMd, bReadOnly)); + IfFailGo(pStgdb->m_MiniMd.SetOption(&optVal)); + m_tdModule = COR_GLOBAL_PARENT_TOKEN; + m_fOwnStgdb = true; + pStgdb->m_pvMd=pRO->m_LiteWeightStgdb.m_pvMd; + pStgdb->m_cbMd=pRO->m_LiteWeightStgdb.m_cbMd; + m_pStgdb = pStgdb; + +ErrExit: + // clean up upon errors + if (FAILED(hr) && (pStgdb != NULL)) + { + delete pStgdb; + } + return hr; +} // MDInternalRW::InitWithRO + + +#ifndef DACCESS_COMPILE +//***************************************************************************** +// Given a scope, determine whether imported from a typelib. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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); +} // MDInternalRW::TranslateSigWithScope + +__checkReturn +HRESULT MDInternalRW::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_pStgdb->m_MiniMd.GetTypeDefRefTokenInTypeSpec(tkTypeSpec, tkEnclosedToken); +}// MDInternalRW::GetTypeDefRefTokenInTypeSpec + +//***************************************************************************** +// Given a scope, return the number of tokens in a given table +//***************************************************************************** +ULONG MDInternalRW::GetCountWithTokenKind( // return hresult + DWORD tkKind) // [IN] pass in the kind of token. +{ + ULONG ulCount = 0; + HRESULT hr = S_OK; + LOCKREAD(); + + switch (tkKind) + { + case mdtTypeDef: + ulCount = m_pStgdb->m_MiniMd.getCountTypeDefs(); + // Remove global typedef from the count of typedefs (and handle the case where there is no global typedef) + if (ulCount > 0) + ulCount--; + break; + case mdtTypeRef: + ulCount = m_pStgdb->m_MiniMd.getCountTypeRefs(); + break; + case mdtMethodDef: + ulCount = m_pStgdb->m_MiniMd.getCountMethods(); + break; + case mdtFieldDef: + ulCount = m_pStgdb->m_MiniMd.getCountFields(); + break; + case mdtMemberRef: + ulCount = m_pStgdb->m_MiniMd.getCountMemberRefs(); + break; + case mdtInterfaceImpl: + ulCount = m_pStgdb->m_MiniMd.getCountInterfaceImpls(); + break; + case mdtParamDef: + ulCount = m_pStgdb->m_MiniMd.getCountParams(); + break; + case mdtFile: + ulCount = m_pStgdb->m_MiniMd.getCountFiles(); + break; + case mdtAssemblyRef: + ulCount = m_pStgdb->m_MiniMd.getCountAssemblyRefs(); + break; + case mdtAssembly: + ulCount = m_pStgdb->m_MiniMd.getCountAssemblys(); + break; + case mdtCustomAttribute: + ulCount = m_pStgdb->m_MiniMd.getCountCustomAttributes(); + break; + case mdtModule: + ulCount = m_pStgdb->m_MiniMd.getCountModules(); + break; + case mdtPermission: + ulCount = m_pStgdb->m_MiniMd.getCountDeclSecuritys(); + break; + case mdtSignature: + ulCount = m_pStgdb->m_MiniMd.getCountStandAloneSigs(); + break; + case mdtEvent: + ulCount = m_pStgdb->m_MiniMd.getCountEvents(); + break; + case mdtProperty: + ulCount = m_pStgdb->m_MiniMd.getCountPropertys(); + break; + case mdtModuleRef: + ulCount = m_pStgdb->m_MiniMd.getCountModuleRefs(); + break; + case mdtTypeSpec: + ulCount = m_pStgdb->m_MiniMd.getCountTypeSpecs(); + break; + case mdtExportedType: + ulCount = m_pStgdb->m_MiniMd.getCountExportedTypes(); + break; + case mdtManifestResource: + ulCount = m_pStgdb->m_MiniMd.getCountManifestResources(); + break; + case mdtGenericParam: + ulCount = m_pStgdb->m_MiniMd.getCountGenericParams(); + break; + case mdtGenericParamConstraint: + ulCount = m_pStgdb->m_MiniMd.getCountGenericParamConstraints(); + break; + case mdtMethodSpec: + ulCount = m_pStgdb->m_MiniMd.getCountMethodSpecs(); + break; + default: +#ifdef _DEBUG + if(REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_AssertOnBadImageFormat, 1)) + _ASSERTE(!"Invalid Blob Offset"); +#endif + ulCount = 0; + break; + } + +ErrExit: + + return ulCount; +} // MDInternalRW::GetCountWithTokenKind +#endif //!DACCESS_COMPILE + + +//******************************************************************************* +// Enumerator helpers +//******************************************************************************* + + +//***************************************************************************** +// enumerator init for typedef +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::EnumTypeDefInit( // return hresult + HENUMInternal *phEnum) // [OUT] buffer to fill for enumerator data +{ + HRESULT hr = NOERROR; + LOCKREAD(); + + _ASSERTE(phEnum); + + memset(phEnum, 0, sizeof(HENUMInternal)); + phEnum->m_tkKind = mdtTypeDef; + + if ( m_pStgdb->m_MiniMd.HasDelete() ) + { + HENUMInternal::InitDynamicArrayEnum(phEnum); + + phEnum->m_tkKind = mdtTypeDef; + for (ULONG index = 2; index <= m_pStgdb->m_MiniMd.getCountTypeDefs(); index ++ ) + { + TypeDefRec *pTypeDefRec; + IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(index, &pTypeDefRec)); + LPCSTR szTypeDefName; + IfFailGo(m_pStgdb->m_MiniMd.getNameOfTypeDef(pTypeDefRec, &szTypeDefName)); + if (IsDeletedName(szTypeDefName)) + { + continue; + } + IfFailGo( HENUMInternal::AddElementToEnum( + phEnum, + TokenFromRid(index, mdtTypeDef) ) ); + } + } + else + { + phEnum->m_EnumType = MDSimpleEnum; + phEnum->m_ulCount = m_pStgdb->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 --; + } +ErrExit: + + return hr; +} // MDInternalRW::EnumTypeDefInit + + +//***************************************************************************** +// get the number of typedef in a scope +//***************************************************************************** +ULONG MDInternalRW::EnumTypeDefGetCount( + HENUMInternal *phEnum) // [IN] the enumerator to retrieve information +{ + _ASSERTE(phEnum->m_tkKind == mdtTypeDef); + return phEnum->m_ulCount; +} // MDInternalRW::EnumTypeDefGetCount + + +//***************************************************************************** +// enumerator for typedef +//***************************************************************************** +bool MDInternalRW::EnumTypeDefNext( // return hresult + HENUMInternal *phEnum, // [IN] input enum + mdTypeDef *ptd) // [OUT] return token +{ + return EnumNext( + phEnum, + ptd); +} // MDInternalRW::EnumTypeDefNext + + +//***************************************** +// Reset the enumerator to the beginning. +//***************************************** +void MDInternalRW::EnumTypeDefReset( + HENUMInternal *phEnum) // [IN] the enumerator to be reset +{ + EnumReset(phEnum); +} // MDInternalRW::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 MDInternalRW::EnumTypeDefClose( + HENUMInternal *phEnum) // [IN] the enumerator to be closed +{ + EnumClose(phEnum); +} // MDInternalRW::EnumTypeDefClose + +#ifndef DACCESS_COMPILE +//***************************************************************************** +// enumerator init for MethodImpl +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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. +{ + HRESULT hr = NOERROR; + int ridCur; + mdToken tkMethodBody; + mdToken tkMethodDecl; + MethodImplRec *pRec; + HENUMInternal hEnum; + + LOCKREAD(); + + _ASSERTE(TypeFromToken(td) == mdtTypeDef && !IsNilToken(td)); + _ASSERTE(phEnumBody && phEnumDecl); + + memset(phEnumBody, 0, sizeof(HENUMInternal)); + memset(phEnumDecl, 0, sizeof(HENUMInternal)); + memset(&hEnum, 0, sizeof(HENUMInternal)); + + HENUMInternal::InitDynamicArrayEnum(phEnumBody); + HENUMInternal::InitDynamicArrayEnum(phEnumDecl); + + phEnumBody->m_tkKind = (TBL_MethodImpl << 24); + phEnumDecl->m_tkKind = (TBL_MethodImpl << 24); + + // Get the range of rids. + IfFailGo( m_pStgdb->m_MiniMd.FindMethodImplHelper(td, &hEnum) ); + + while (HENUMInternal::EnumNext(&hEnum, (mdToken *)&ridCur)) + { + // Get the MethodBody and MethodDeclaration tokens for the current + // MethodImpl record. + IfFailGo(m_pStgdb->m_MiniMd.GetMethodImplRecord(ridCur, &pRec)); + tkMethodBody = m_pStgdb->m_MiniMd.getMethodBodyOfMethodImpl(pRec); + tkMethodDecl = m_pStgdb->m_MiniMd.getMethodDeclarationOfMethodImpl(pRec); + + // Add the Method body/declaration pairs to the Enum + IfFailGo( HENUMInternal::AddElementToEnum(phEnumBody, tkMethodBody ) ); + IfFailGo( HENUMInternal::AddElementToEnum(phEnumDecl, tkMethodDecl ) ); + } +ErrExit: + HENUMInternal::ClearEnum(&hEnum); + return hr; +} // MDInternalRW::EnumMethodImplInit + +//***************************************************************************** +// get the number of MethodImpls in a scope +//***************************************************************************** +ULONG MDInternalRW::EnumMethodImplGetCount( + HENUMInternal *phEnumBody, // [IN] MethodBody enumerator. + HENUMInternal *phEnumDecl) // [IN] MethodDecl enumerator. +{ + _ASSERTE((phEnumBody->m_tkKind >> 24) == TBL_MethodImpl && + (phEnumDecl->m_tkKind >> 24) == TBL_MethodImpl); + _ASSERTE(phEnumBody->m_EnumType == MDDynamicArrayEnum && + phEnumDecl->m_EnumType == MDDynamicArrayEnum); + _ASSERTE(phEnumBody->m_ulCount == phEnumDecl->m_ulCount); + + return phEnumBody->m_ulCount; +} // MDInternalRW::EnumMethodImplGetCount + + +//***************************************************************************** +// enumerator for MethodImpl. +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRW::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 +{ + _ASSERTE((phEnumBody->m_tkKind >> 24) == TBL_MethodImpl && + (phEnumDecl->m_tkKind >> 24) == TBL_MethodImpl); + _ASSERTE(phEnumBody->m_EnumType == MDDynamicArrayEnum && + phEnumDecl->m_EnumType == MDDynamicArrayEnum); + _ASSERTE(phEnumBody->m_ulCount == phEnumDecl->m_ulCount); + _ASSERTE(ptkBody && ptkDecl); + + EnumNext(phEnumBody, ptkBody); + return EnumNext(phEnumDecl, ptkDecl) ? S_OK : S_FALSE; +} // MDInternalRW::EnumMethodImplNext + +//***************************************** +// Reset the enumerator to the beginning. +//***************************************** +void MDInternalRW::EnumMethodImplReset( + HENUMInternal *phEnumBody, // [IN] MethodBody enumerator. + HENUMInternal *phEnumDecl) // [IN] MethodDecl enumerator. +{ + _ASSERTE((phEnumBody->m_tkKind >> 24) == TBL_MethodImpl && + (phEnumDecl->m_tkKind >> 24) == TBL_MethodImpl); + _ASSERTE(phEnumBody->m_EnumType == MDDynamicArrayEnum && + phEnumDecl->m_EnumType == MDDynamicArrayEnum); + _ASSERTE(phEnumBody->m_ulCount == phEnumDecl->m_ulCount); + + EnumReset(phEnumBody); + EnumReset(phEnumDecl); +} // MDInternalRW::EnumMethodImplReset + + +//***************************************** +// Close the enumerator. +//***************************************** +void MDInternalRW::EnumMethodImplClose( + HENUMInternal *phEnumBody, // [IN] MethodBody enumerator. + HENUMInternal *phEnumDecl) // [IN] MethodDecl enumerator. +{ + _ASSERTE((phEnumBody->m_tkKind >> 24) == TBL_MethodImpl && + (phEnumDecl->m_tkKind >> 24) == TBL_MethodImpl); + _ASSERTE(phEnumBody->m_EnumType == MDDynamicArrayEnum && + phEnumDecl->m_EnumType == MDDynamicArrayEnum); + _ASSERTE(phEnumBody->m_ulCount == phEnumDecl->m_ulCount); + + EnumClose(phEnumBody); + EnumClose(phEnumDecl); +} // MDInternalRW::EnumMethodImplClose +#endif //!DACCESS_COMPILE + +//****************************************************************************** +// enumerator for global functions +//****************************************************************************** +__checkReturn +HRESULT MDInternalRW::EnumGlobalFunctionsInit( // return hresult + HENUMInternal *phEnum) // [OUT] buffer to fill for enumerator data +{ + return EnumInit(mdtMethodDef, m_tdModule, phEnum); +} // MDInternalRW::EnumGlobalFunctionsInit + + +//****************************************************************************** +// enumerator for global fields +//****************************************************************************** +__checkReturn +HRESULT MDInternalRW::EnumGlobalFieldsInit( // return hresult + HENUMInternal *phEnum) // [OUT] buffer to fill for enumerator data +{ + return EnumInit(mdtFieldDef, m_tdModule, phEnum); +} // MDInternalRW::EnumGlobalFieldsInit + + +#ifdef _PREFAST_ +#pragma warning(push) +#pragma warning(disable:21000) // Suppress PREFast warning about overly large function +#endif +//***************************************** +// Enumerator initializer +//***************************************** +__checkReturn +HRESULT MDInternalRW::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 ulStart, ulEnd, ulMax; + ULONG index; + LOCKREAD(); + + // Vars for query. + _ASSERTE(phEnum); + memset(phEnum, 0, sizeof(HENUMInternal)); + + // cache the tkKind and the scope + phEnum->m_tkKind = TypeFromToken(tkKind); + + TypeDefRec *pRec; + + phEnum->m_EnumType = MDSimpleEnum; + + switch (TypeFromToken(tkKind)) + { + case mdtFieldDef: + IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(tkParent), &pRec)); + ulStart = m_pStgdb->m_MiniMd.getFieldListOfTypeDef(pRec); + IfFailGo(m_pStgdb->m_MiniMd.getEndFieldListOfTypeDef(RidFromToken(tkParent), &ulEnd)); + if ( m_pStgdb->m_MiniMd.HasDelete() ) + { + HENUMInternal::InitDynamicArrayEnum(phEnum); + for (index = ulStart; index < ulEnd; index ++ ) + { + FieldRec *pFieldRec; + RID fieldRid; + IfFailGo(m_pStgdb->m_MiniMd.GetFieldRid(index, &fieldRid)); + IfFailGo(m_pStgdb->m_MiniMd.GetFieldRecord(index, &pFieldRec)); + LPCSTR szFieldName; + IfFailGo(m_pStgdb->m_MiniMd.getNameOfField(pFieldRec, &szFieldName)); + if (IsFdRTSpecialName(pFieldRec->GetFlags()) && IsDeletedName(szFieldName) ) + { + continue; + } + IfFailGo(m_pStgdb->m_MiniMd.GetFieldRid(index, &fieldRid)); + IfFailGo(HENUMInternal::AddElementToEnum( + phEnum, + TokenFromRid(fieldRid, mdtFieldDef))); + } + } + else if (m_pStgdb->m_MiniMd.HasIndirectTable(TBL_Field)) + { + HENUMInternal::InitDynamicArrayEnum(phEnum); + for (index = ulStart; index < ulEnd; index ++ ) + { + RID fieldRid; + IfFailGo(m_pStgdb->m_MiniMd.GetFieldRid(index, &fieldRid)); + IfFailGo(HENUMInternal::AddElementToEnum( + phEnum, + TokenFromRid(fieldRid, mdtFieldDef))); + } + } + else + { + HENUMInternal::InitSimpleEnum( mdtFieldDef, ulStart, ulEnd, phEnum); + } + break; + + case mdtMethodDef: + IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(tkParent), &pRec)); + ulStart = m_pStgdb->m_MiniMd.getMethodListOfTypeDef(pRec); + IfFailGo(m_pStgdb->m_MiniMd.getEndMethodListOfTypeDef(RidFromToken(tkParent), &ulEnd)); + if ( m_pStgdb->m_MiniMd.HasDelete() ) + { + HENUMInternal::InitDynamicArrayEnum(phEnum); + for (index = ulStart; index < ulEnd; index ++ ) + { + MethodRec *pMethodRec; + RID methodRid; + IfFailGo(m_pStgdb->m_MiniMd.GetMethodRid(index, &methodRid)); + IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(methodRid, &pMethodRec)); + LPCSTR szMethodName; + IfFailGo(m_pStgdb->m_MiniMd.getNameOfMethod(pMethodRec, &szMethodName)); + if (IsMdRTSpecialName(pMethodRec->GetFlags()) && IsDeletedName(szMethodName)) + { + continue; + } + IfFailGo(m_pStgdb->m_MiniMd.GetMethodRid(index, &methodRid)); + IfFailGo(HENUMInternal::AddElementToEnum( + phEnum, + TokenFromRid(methodRid, mdtMethodDef))); + } + } + else if (m_pStgdb->m_MiniMd.HasIndirectTable(TBL_Method)) + { + HENUMInternal::InitDynamicArrayEnum(phEnum); + for (index = ulStart; index < ulEnd; index ++ ) + { + RID methodRid; + IfFailGo(m_pStgdb->m_MiniMd.GetMethodRid(index, &methodRid)); + IfFailGo(HENUMInternal::AddElementToEnum( + phEnum, + TokenFromRid(methodRid, mdtMethodDef))); + } + } + else + { + HENUMInternal::InitSimpleEnum( mdtMethodDef, ulStart, ulEnd, phEnum); + } + break; + + case mdtInterfaceImpl: + if (!m_pStgdb->m_MiniMd.IsSorted(TBL_InterfaceImpl) && !m_pStgdb->m_MiniMd.IsTableVirtualSorted(TBL_InterfaceImpl)) + { + // virtual sort table will be created! + // + CONVERT_READ_TO_WRITE_LOCK(); + } + + IfFailGo( m_pStgdb->m_MiniMd.GetInterfaceImplsForTypeDef(RidFromToken(tkParent), &ulStart, &ulEnd) ); + if ( m_pStgdb->m_MiniMd.IsSorted( TBL_InterfaceImpl ) ) + { + // These are index to InterfaceImpl table directly + HENUMInternal::InitSimpleEnum( mdtInterfaceImpl, ulStart, ulEnd, phEnum); + } + else + { + // These are index to VirtualSort table. Skip over one level direction. + HENUMInternal::InitDynamicArrayEnum(phEnum); + for (index = ulStart; index < ulEnd; index ++ ) + { + IfFailGo( HENUMInternal::AddElementToEnum( + phEnum, + TokenFromRid(m_pStgdb->m_MiniMd.GetInterfaceImplRid(index), mdtInterfaceImpl) ) ); + } + } + break; + + case mdtGenericParam: + //@todo: deal with non-sorted case. + + if (TypeFromToken(tkParent) == mdtTypeDef) + { + IfFailGo(m_pStgdb->m_MiniMd.getGenericParamsForTypeDef( + RidFromToken(tkParent), + &phEnum->u.m_ulEnd, + &(phEnum->u.m_ulStart))); + } + else + { + IfFailGo(m_pStgdb->m_MiniMd.getGenericParamsForMethodDef( + RidFromToken(tkParent), + &phEnum->u.m_ulEnd, + &(phEnum->u.m_ulStart))); + } + break; + + case mdtGenericParamConstraint: + if ( !m_pStgdb->m_MiniMd.IsSorted(TBL_GenericParamConstraint) && !m_pStgdb->m_MiniMd.IsTableVirtualSorted(TBL_GenericParamConstraint)) + { + // virtual sort table will be created! + // + CONVERT_READ_TO_WRITE_LOCK(); + } + + IfFailGo( m_pStgdb->m_MiniMd.GetGenericParamConstraintsForToken(RidFromToken(tkParent), &ulStart, &ulEnd) ); + if ( m_pStgdb->m_MiniMd.IsSorted( TBL_GenericParamConstraint ) ) + { + // These are index to GenericParamConstraint table directly + HENUMInternal::InitSimpleEnum( mdtGenericParamConstraint, ulStart, ulEnd, phEnum); + } + else + { + // These are index to VirtualSort table. Skip over one level direction. + HENUMInternal::InitDynamicArrayEnum(phEnum); + for (index = ulStart; index < ulEnd; index ++ ) + { + IfFailGo( HENUMInternal::AddElementToEnum( + phEnum, + TokenFromRid(m_pStgdb->m_MiniMd.GetGenericParamConstraintRid(index), mdtGenericParamConstraint) ) ); + } + } + break; + + case mdtProperty: + RID ridPropertyMap; + PropertyMapRec *pPropertyMapRec; + + // get the starting/ending rid of properties of this typedef + IfFailGo(m_pStgdb->m_MiniMd.FindPropertyMapFor(RidFromToken(tkParent), &ridPropertyMap)); + if (!InvalidRid(ridPropertyMap)) + { + IfFailGo(m_pStgdb->m_MiniMd.GetPropertyMapRecord(ridPropertyMap, &pPropertyMapRec)); + ulStart = m_pStgdb->m_MiniMd.getPropertyListOfPropertyMap(pPropertyMapRec); + IfFailGo(m_pStgdb->m_MiniMd.getEndPropertyListOfPropertyMap(ridPropertyMap, &ulEnd)); + ulMax = m_pStgdb->m_MiniMd.getCountPropertys() + 1; + if(ulStart == 0) ulStart = 1; + if(ulEnd > ulMax) ulEnd = ulMax; + if(ulStart > ulEnd) ulStart = ulEnd; + if ( m_pStgdb->m_MiniMd.HasDelete() ) + { + HENUMInternal::InitDynamicArrayEnum(phEnum); + for (index = ulStart; index < ulEnd; index ++ ) + { + PropertyRec *pPropertyRec; + RID propertyRid; + IfFailGo(m_pStgdb->m_MiniMd.GetPropertyRid(index, &propertyRid)); + IfFailGo(m_pStgdb->m_MiniMd.GetPropertyRecord( + propertyRid, + &pPropertyRec)); + LPCSTR szPropertyName; + IfFailGo(m_pStgdb->m_MiniMd.getNameOfProperty(pPropertyRec, &szPropertyName)); + if (IsPrRTSpecialName(pPropertyRec->GetPropFlags()) && IsDeletedName(szPropertyName)) + { + continue; + } + IfFailGo(m_pStgdb->m_MiniMd.GetPropertyRid(index, &propertyRid)); + IfFailGo(HENUMInternal::AddElementToEnum( + phEnum, + TokenFromRid(propertyRid, mdtProperty))); + } + } + else if (m_pStgdb->m_MiniMd.HasIndirectTable(TBL_Property)) + { + HENUMInternal::InitDynamicArrayEnum(phEnum); + for (index = ulStart; index < ulEnd; index ++ ) + { + RID propertyRid; + IfFailGo(m_pStgdb->m_MiniMd.GetPropertyRid(index, &propertyRid)); + IfFailGo(HENUMInternal::AddElementToEnum( + phEnum, + TokenFromRid(propertyRid, mdtProperty))); + } + } + else + { + HENUMInternal::InitSimpleEnum( mdtProperty, ulStart, ulEnd, phEnum); + } + } + break; + + case mdtEvent: + RID ridEventMap; + EventMapRec *pEventMapRec; + + // get the starting/ending rid of events of this typedef + IfFailGo(m_pStgdb->m_MiniMd.FindEventMapFor(RidFromToken(tkParent), &ridEventMap)); + if (!InvalidRid(ridEventMap)) + { + IfFailGo(m_pStgdb->m_MiniMd.GetEventMapRecord(ridEventMap, &pEventMapRec)); + ulStart = m_pStgdb->m_MiniMd.getEventListOfEventMap(pEventMapRec); + IfFailGo(m_pStgdb->m_MiniMd.getEndEventListOfEventMap(ridEventMap, &ulEnd)); + ulMax = m_pStgdb->m_MiniMd.getCountEvents() + 1; + if(ulStart == 0) ulStart = 1; + if(ulEnd > ulMax) ulEnd = ulMax; + if(ulStart > ulEnd) ulStart = ulEnd; + if ( m_pStgdb->m_MiniMd.HasDelete() ) + { + HENUMInternal::InitDynamicArrayEnum(phEnum); + for (index = ulStart; index < ulEnd; index ++ ) + { + EventRec *pEventRec; + RID eventRid; + IfFailGo(m_pStgdb->m_MiniMd.GetEventRid(index, &eventRid)); + IfFailGo(m_pStgdb->m_MiniMd.GetEventRecord(eventRid, &pEventRec)); + LPCSTR szEventName; + IfFailGo(m_pStgdb->m_MiniMd.getNameOfEvent(pEventRec, &szEventName)); + if (IsEvRTSpecialName(pEventRec->GetEventFlags()) && IsDeletedName(szEventName)) + { + continue; + } + IfFailGo(m_pStgdb->m_MiniMd.GetEventRid(index, &eventRid)); + IfFailGo(HENUMInternal::AddElementToEnum( + phEnum, + TokenFromRid(eventRid, mdtEvent))); + } + } + else if (m_pStgdb->m_MiniMd.HasIndirectTable(TBL_Event)) + { + HENUMInternal::InitDynamicArrayEnum(phEnum); + for (index = ulStart; index < ulEnd; index ++ ) + { + RID eventRid; + IfFailGo(m_pStgdb->m_MiniMd.GetEventRid(index, &eventRid)); + IfFailGo( HENUMInternal::AddElementToEnum( + phEnum, + TokenFromRid(eventRid, mdtEvent) ) ); + } + } + else + { + HENUMInternal::InitSimpleEnum( mdtEvent, ulStart, ulEnd, phEnum); + } + } + break; + + case mdtParamDef: + _ASSERTE(TypeFromToken(tkParent) == mdtMethodDef); + + MethodRec *pMethodRec; + IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(tkParent), &pMethodRec)); + + // figure out the start rid and end rid of the parameter list of this methoddef + ulStart = m_pStgdb->m_MiniMd.getParamListOfMethod(pMethodRec); + IfFailGo(m_pStgdb->m_MiniMd.getEndParamListOfMethod(RidFromToken(tkParent), &ulEnd)); + if (m_pStgdb->m_MiniMd.HasIndirectTable(TBL_Param)) + { + HENUMInternal::InitDynamicArrayEnum(phEnum); + for (index = ulStart; index < ulEnd; index ++ ) + { + RID paramRid; + IfFailGo(m_pStgdb->m_MiniMd.GetParamRid(index, ¶mRid)); + IfFailGo(HENUMInternal::AddElementToEnum( + phEnum, + TokenFromRid(paramRid, mdtParamDef))); + } + } + else + { + HENUMInternal::InitSimpleEnum( mdtParamDef, ulStart, ulEnd, phEnum); + } + break; + + case mdtCustomAttribute: + if (!m_pStgdb->m_MiniMd.IsSorted(TBL_CustomAttribute) && !m_pStgdb->m_MiniMd.IsTableVirtualSorted(TBL_CustomAttribute)) + { + // CA's map table table will be sorted! + // + CONVERT_READ_TO_WRITE_LOCK(); + } + + IfFailGo( m_pStgdb->m_MiniMd.GetCustomAttributeForToken(tkParent, &ulStart, &ulEnd) ); + if ( m_pStgdb->m_MiniMd.IsSorted( TBL_CustomAttribute ) ) + { + // These are index to CustomAttribute table directly + HENUMInternal::InitSimpleEnum( mdtCustomAttribute, ulStart, ulEnd, phEnum); + } + else + { + // These are index to VirtualSort table. Skip over one level direction. + HENUMInternal::InitDynamicArrayEnum(phEnum); + for (index = ulStart; index < ulEnd; index ++ ) + { + IfFailGo( HENUMInternal::AddElementToEnum( + phEnum, + TokenFromRid(m_pStgdb->m_MiniMd.GetCustomAttributeRid(index), mdtCustomAttribute) ) ); + } + } + break; + case mdtAssemblyRef: + _ASSERTE(IsNilToken(tkParent)); + phEnum->u.m_ulStart = 1; + phEnum->u.m_ulEnd = m_pStgdb->m_MiniMd.getCountAssemblyRefs() + 1; + break; + case mdtFile: + _ASSERTE(IsNilToken(tkParent)); + phEnum->u.m_ulStart = 1; + phEnum->u.m_ulEnd = m_pStgdb->m_MiniMd.getCountFiles() + 1; + break; + case mdtExportedType: + _ASSERTE(IsNilToken(tkParent)); + if ( m_pStgdb->m_MiniMd.HasDelete() ) + { + HENUMInternal::InitDynamicArrayEnum(phEnum); + + phEnum->m_tkKind = mdtExportedType; + for (ULONG typeindex = 1; typeindex <= m_pStgdb->m_MiniMd.getCountExportedTypes(); typeindex ++ ) + { + ExportedTypeRec *pExportedTypeRec; + IfFailGo(m_pStgdb->m_MiniMd.GetExportedTypeRecord(typeindex, &pExportedTypeRec)); + LPCSTR szTypeName; + IfFailGo(m_pStgdb->m_MiniMd.getTypeNameOfExportedType(pExportedTypeRec, &szTypeName)); + if (IsDeletedName(szTypeName)) + { + continue; + } + IfFailGo( HENUMInternal::AddElementToEnum( + phEnum, + TokenFromRid(typeindex, mdtExportedType) ) ); + } + } + else + { + phEnum->u.m_ulStart = 1; + phEnum->u.m_ulEnd = m_pStgdb->m_MiniMd.getCountExportedTypes() + 1; + } + break; + case mdtManifestResource: + _ASSERTE(IsNilToken(tkParent)); + phEnum->u.m_ulStart = 1; + phEnum->u.m_ulEnd = m_pStgdb->m_MiniMd.getCountManifestResources() + 1; + break; + case mdtModuleRef: + _ASSERTE(IsNilToken(tkParent)); + phEnum->u.m_ulStart = 1; + phEnum->u.m_ulEnd = m_pStgdb->m_MiniMd.getCountModuleRefs() + 1; + break; + default: + _ASSERTE(!"ENUM INIT not implemented for the uncompressed 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; +} // MDInternalRW::EnumInit +#ifdef _PREFAST_ +#pragma warning(pop) +#endif + +//***************************************** +// Enumerator initializer +//***************************************** +__checkReturn +HRESULT MDInternalRW::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; + LOCKREAD(); + + // 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_pStgdb->m_MiniMd.getCountTypeRefs(); + break; + + case mdtMemberRef: + phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountMemberRefs(); + break; + + case mdtSignature: + phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountStandAloneSigs(); + break; + + case mdtMethodDef: + phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountMethods(); + break; + + case mdtMethodSpec: + phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountMethodSpecs(); + break; + + case mdtFieldDef: + phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountFields(); + break; + + case mdtTypeSpec: + phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountTypeSpecs(); + break; + + case mdtAssemblyRef: + phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountAssemblyRefs(); + break; + + case mdtModuleRef: + phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountModuleRefs(); + break; + + case mdtTypeDef: + phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountTypeDefs(); + break; + + case mdtFile: + phEnum->m_ulCount = m_pStgdb->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; + +ErrExit: + // we are done + + return hr; +} // MDInternalRW::EnumAllInit + + +//***************************************** +// get the count +//***************************************** +ULONG MDInternalRW::EnumGetCount( + HENUMInternal *phEnum) // [IN] the enumerator to retrieve information +{ + _ASSERTE(phEnum); + return phEnum->m_ulCount; +} // MDInternalRW::EnumGetCount + +//***************************************** +// Get next value contained in the enumerator +//***************************************** +bool MDInternalRW::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; +} // MDInternalRW::EnumNext + + +//***************************************** +// Reset the enumerator to the beginning. +//***************************************** +void MDInternalRW::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; +} // MDInternalRW::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 MDInternalRW::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); +} // MDInternalRW::EnumClose + + +#ifndef DACCESS_COMPILE +//--------------------------------------------------------------------------------------- +// +// 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 +MDInternalRW::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; + DeclSecurityRec *pDecl; + RID ridCur; + RID ridEnd; + + LOCKREAD(); + + _ASSERTE(phEnum != NULL); + + phEnum->m_EnumType = MDSimpleEnum; + + if (!m_pStgdb->m_MiniMd.IsSorted(TBL_DeclSecurity) && !m_pStgdb->m_MiniMd.IsTableVirtualSorted(TBL_DeclSecurity)) + { + // DeclSecurity lookup table might be created! + CONVERT_READ_TO_WRITE_LOCK(); + } + + // This call requires write-lock if the table is not sorted and doesn't have VirtualSort: + IfFailGo(m_pStgdb->m_MiniMd.GetDeclSecurityForToken(tkParent, &ridCur, &ridEnd)); + if (m_pStgdb->m_MiniMd.IsSorted(TBL_DeclSecurity)) + { + // These are index to DeclSecurity table directly + if (Action != dclActionNil) + { + for (; ridCur < ridEnd; ridCur++) + { + IfFailGo(m_pStgdb->m_MiniMd.GetDeclSecurityRecord(ridCur, &pDecl)); + if (Action == m_pStgdb->m_MiniMd.getActionOfDeclSecurity(pDecl)) + { + // found a match + HENUMInternal::InitSimpleEnum(mdtPermission, ridCur, ridCur + 1, phEnum); + goto ErrExit; + } + } + hr = CLDB_E_RECORD_NOTFOUND; + } + else + { + HENUMInternal::InitSimpleEnum(mdtPermission, ridCur, ridEnd, phEnum); + } + } + else + { + // These are index to VirtualSort table. Skip over one level direction. + if (Action != dclActionNil) + { + RID ridActual; + + for (; ridCur < ridEnd; ridCur++) + { + ridActual = m_pStgdb->m_MiniMd.GetDeclSecurityRid(ridCur); + IfFailGo(m_pStgdb->m_MiniMd.GetDeclSecurityRecord(ridActual, &pDecl)); + if (Action == m_pStgdb->m_MiniMd.getActionOfDeclSecurity(pDecl)) + { + // found a match + HENUMInternal::InitSimpleEnum(mdtPermission, ridActual, ridActual + 1, phEnum); + goto ErrExit; + } + } + hr = CLDB_E_RECORD_NOTFOUND; + } + else + { + HENUMInternal::InitDynamicArrayEnum(phEnum); + for (; ridCur < ridEnd; ridCur++) + { + IfFailGo(HENUMInternal::AddElementToEnum( + phEnum, + TokenFromRid(m_pStgdb->m_MiniMd.GetDeclSecurityRid(ridCur), mdtPermission))); + } + } + } + +ErrExit: + return hr; +} // MDInternalRW::EnumPermissionSetsInit +#endif //!DACCESS_COMPILE + +//***************************************** +// Enumerator initializer for CustomAttributes +//***************************************** +__checkReturn +HRESULT MDInternalRW::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_pStgdb->m_MiniMd.CommonEnumCustomAttributeByName(tkParent, szName, false, phEnum); +} // MDInternalRW::EnumCustomAttributeByNameInit + +//***************************************** +// Enumerator for CustomAttributes which doesn't +// allocate any memory +//***************************************** +__checkReturn +HRESULT MDInternalRW::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. + if (m_pStgdb->m_MiniMd.IsSorted(TBL_CustomAttribute)) + { + IfFailRet(m_pStgdb->m_MiniMd.getCustomAttributeForToken(tkParent, &ridEnd, &ridStart)); + // If found none, done. + if (ridStart == 0) + goto NoMatch; + } + else + { + // linear scan of entire table. + ridEnd = m_pStgdb->m_MiniMd.getCountCustomAttributes() + 1; + if (ridEnd == 1) + goto NoMatch; + + ridStart = 1; + } + 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; +} // MDInternalRW::SafeAndSlowEnumCustomAttributeByNameInit + +__checkReturn +HRESULT MDInternalRW::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_pStgdb->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; +}// MDInternalRW::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 MDInternalRW::GetParentToken( + mdToken tkChild, // [IN] given child token + mdToken *ptkParent) // [OUT] returning parent +{ + HRESULT hr = NOERROR; + LOCKREAD(); + + _ASSERTE(ptkParent); + + switch (TypeFromToken(tkChild)) + { + case mdtTypeDef: + { + RID rid; + if (!m_pStgdb->m_MiniMd.IsSorted(TBL_NestedClass) && !m_pStgdb->m_MiniMd.IsTableVirtualSorted(TBL_NestedClass)) + { + // NestedClass table is not sorted. + CONVERT_READ_TO_WRITE_LOCK(); + } + IfFailGo(m_pStgdb->m_MiniMd.FindNestedClassFor(RidFromToken(tkChild), &rid)); + + if (InvalidRid(rid)) + { + // If not found, the *ptkParent has to be left unchanged! (callers depend on that) + hr = S_OK; + } + else + { + NestedClassRec *pRecord; + IfFailGo(m_pStgdb->m_MiniMd.GetNestedClassRecord(rid, &pRecord)); + *ptkParent = m_pStgdb->m_MiniMd.getEnclosingClassOfNestedClass(pRecord); + } + break; + } + case mdtMethodDef: + IfFailGo(m_pStgdb->m_MiniMd.FindParentOfMethodHelper(RidFromToken(tkChild), ptkParent)); + RidToToken(*ptkParent, mdtTypeDef); + break; + case mdtMethodSpec: + { + MethodSpecRec *pRec; + IfFailGo(m_pStgdb->m_MiniMd.GetMethodSpecRecord(RidFromToken(tkChild), &pRec)); + *ptkParent = m_pStgdb->m_MiniMd.getMethodOfMethodSpec(pRec); + } + break; + case mdtFieldDef: + IfFailGo(m_pStgdb->m_MiniMd.FindParentOfFieldHelper(RidFromToken(tkChild), ptkParent)); + RidToToken(*ptkParent, mdtTypeDef); + break; + case mdtParamDef: + IfFailGo(m_pStgdb->m_MiniMd.FindParentOfParamHelper(RidFromToken(tkChild), ptkParent)); + RidToToken(*ptkParent, mdtMethodDef); + break; + case mdtMemberRef: + { + MemberRefRec *pRec; + IfFailGo(m_pStgdb->m_MiniMd.GetMemberRefRecord(RidFromToken(tkChild), &pRec)); + *ptkParent = m_pStgdb->m_MiniMd.getClassOfMemberRef(pRec); + break; + } + case mdtCustomAttribute: + { + CustomAttributeRec *pRec; + IfFailGo(m_pStgdb->m_MiniMd.GetCustomAttributeRecord(RidFromToken(tkChild), &pRec)); + *ptkParent = m_pStgdb->m_MiniMd.getParentOfCustomAttribute(pRec); + break; + } + case mdtEvent: + IfFailGo(m_pStgdb->m_MiniMd.FindParentOfEventHelper(tkChild, ptkParent)); + break; + case mdtProperty: + IfFailGo(m_pStgdb->m_MiniMd.FindParentOfPropertyHelper(tkChild, ptkParent)); + break; + default: + _ASSERTE(!"NYI: for compressed format!"); + break; + } +ErrExit: + return hr; +} // MDInternalRW::GetParentToken + +//***************************************************************************** +// Get information about a CustomAttribute. +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRW::GetCustomAttributeProps( // S_OK or error. + mdCustomAttribute at, // The attribute. + mdToken *pTkType) // Put attribute type here. +{ + HRESULT hr; + // Getting the custom value prop with a token, no need to lock! + + _ASSERTE(TypeFromToken(at) == mdtCustomAttribute); + + // Do a linear search on compressed version as we do not want to + // depend on ICR. + // + CustomAttributeRec *pCustomAttributeRec; + + IfFailRet(m_pStgdb->m_MiniMd.GetCustomAttributeRecord(RidFromToken(at), &pCustomAttributeRec)); + *pTkType = m_pStgdb->m_MiniMd.getTypeOfCustomAttribute(pCustomAttributeRec); + return S_OK; +} // MDInternalRW::GetCustomAttributeProps + + +//***************************************************************************** +// return custom value +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRW::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 +{ + // Getting the custom value prop with a token, no need to lock! + HRESULT hr; + _ASSERTE(ppBlob && pcbSize && TypeFromToken(cv) == mdtCustomAttribute); + + CustomAttributeRec *pCustomAttributeRec; + + IfFailRet(m_pStgdb->m_MiniMd.GetCustomAttributeRecord(RidFromToken(cv), &pCustomAttributeRec)); + + IfFailRet(m_pStgdb->m_MiniMd.getValueOfCustomAttribute(pCustomAttributeRec, reinterpret_cast<const BYTE **>(ppBlob), pcbSize)); + return S_OK; +} // MDInternalRW::GetCustomAttributeAsBlob + +//***************************************************************************** +// Helper function to lookup and retrieve a CustomAttribute. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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. +{ + HRESULT hr = S_OK; + LOCKREADIFFAILRET(); + return m_pStgdb->m_MiniMd.CommonGetCustomAttributeByName(tkObj, szName, ppData, pcbData); +} // MDInternalRW::GetCustomAttributeByName + +//***************************************************************************** +// return the name of a custom attribute +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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. +{ + HRESULT hr = S_OK; + LOCKREADIFFAILRET(); + hr = m_pStgdb->m_MiniMd.CommonGetNameOfCustomAttribute(RidFromToken(mdAttribute), pszNamespace, pszName); + return (hr == S_FALSE) ? E_FAIL : hr; +} // MDInternalRW::GetNameOfCustomAttribute + +//***************************************************************************** +// return scope properties +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::GetScopeProps( + LPCSTR *pszName, // [OUT] scope name + GUID *pmvid) // [OUT] version id +{ + HRESULT hr = S_OK; + LOCKREAD(); + + ModuleRec *pModuleRec; + + // there is only one module record + IfFailGo(m_pStgdb->m_MiniMd.GetModuleRecord(1, &pModuleRec)); + + if (pmvid != NULL) + { + IfFailGo(m_pStgdb->m_MiniMd.getMvidOfModule(pModuleRec, pmvid)); + } + + if (pszName != NULL) + { + IfFailGo(m_pStgdb->m_MiniMd.getNameOfModule(pModuleRec, pszName)); + } + +ErrExit: + return hr; +} // MDInternalRW::GetScopeProps + +//***************************************************************************** +// 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 MDInternalRW::GetVersionString( // S_OK or error. + LPCSTR *pVer) // [OUT] Put version string here. +{ + HRESULT hr = NOERROR; + + if (m_pStgdb->m_pvMd != NULL) + { + // For convenience, get a pointer to the version string. + // @todo: get from alternate locations when there is no STOREAGESIGNATURE. + *pVer = reinterpret_cast<const char*>(reinterpret_cast<const STORAGESIGNATURE*>(m_pStgdb->m_pvMd)->pVersion); + } + else + { // No string. + *pVer = NULL; + } + + return hr; +} // MDInternalRW::GetVersionString + +//***************************************************************************** +// Find a given member in a TypeDef (typically a class). +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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. +{ + HRESULT hr = S_OK; + LOCKREAD(); + + _ASSERTE(szName && pmethoddef); + + IfFailGo(ImportHelper::FindMethod(&(m_pStgdb->m_MiniMd), + classdef, + szName, + pvSigBlob, + cbSigBlob, + pmethoddef)); + +ErrExit: + return hr; +} + +//***************************************************************************** +// Find a given member in a TypeDef (typically a class). +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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 pSignatureCompare, // [IN] Routine to compare signatures + void* pSignatureArgs, // [IN] Additional info to supply the compare function + mdMethodDef *pmethoddef) // Put MemberDef token here. +{ + HRESULT hr = S_OK; + LOCKREAD(); + + _ASSERTE(szName && pmethoddef); + + IfFailGo(ImportHelper::FindMethod(&(m_pStgdb->m_MiniMd), + classdef, + szName, + pvSigBlob, + cbSigBlob, + pmethoddef, + 0, + pSignatureCompare, + pSignatureArgs)); + +ErrExit: + return hr; +} + +//***************************************************************************** +// Find a given param of a Method. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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. +{ + ParamRec *pParamRec; + RID ridStart, ridEnd; + HRESULT hr = NOERROR; + MethodRec *pMethodRec = NULL; + + LOCKREAD(); + + _ASSERTE(TypeFromToken(md) == mdtMethodDef && pparamdef); + + // get the methoddef record + IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(md), &pMethodRec)); + + // figure out the start rid and end rid of the parameter list of this methoddef + ridStart = m_pStgdb->m_MiniMd.getParamListOfMethod(pMethodRec); + IfFailGo(m_pStgdb->m_MiniMd.getEndParamListOfMethod(RidFromToken(md), &ridEnd)); + + // loop through each param + // + for (; ridStart < ridEnd; ridStart++) + { + RID paramRid; + IfFailGo(m_pStgdb->m_MiniMd.GetParamRid(ridStart, ¶mRid)); + IfFailGo(m_pStgdb->m_MiniMd.GetParamRecord(paramRid, &pParamRec)); + if (iSeq == m_pStgdb->m_MiniMd.getSequenceOfParam( pParamRec) ) + { + // parameter has the sequence number matches what we are looking for + *pparamdef = TokenFromRid(paramRid, mdtParamDef ); + goto ErrExit; + } + } + hr = CLDB_E_RECORD_NOTFOUND; +ErrExit: + + return hr; +} // MDInternalRW::FindParamOfMethod + + + +//***************************************************************************** +// return a pointer which points to meta data's internal string +// return the the type name in utf8 +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRW::GetNameOfTypeDef( // return hresult + mdTypeDef classdef, // given typedef + LPCSTR* pszname, // pointer to an internal UTF8 string + LPCSTR* psznamespace) // pointer to the namespace. +{ + // No need to lock this method. + HRESULT hr; + + if (pszname != NULL) + { + *pszname = NULL; + } + if (psznamespace != NULL) + { + *psznamespace = NULL; + } + + if (TypeFromToken(classdef) == mdtTypeDef) + { + TypeDefRec *pTypeDefRec; + IfFailRet(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(classdef), &pTypeDefRec)); + + if (pszname != NULL) + { + IfFailRet(m_pStgdb->m_MiniMd.getNameOfTypeDef(pTypeDefRec, pszname)); + } + + if (psznamespace != NULL) + { + IfFailRet(m_pStgdb->m_MiniMd.getNamespaceOfTypeDef(pTypeDefRec, psznamespace)); + } + return S_OK; + } + + _ASSERTE(!"Invalid argument(s) of GetNameOfTypeDef"); + return CLDB_E_INTERNALERROR; +} // MDInternalRW::GetNameOfTypeDef + +//***************************************************************************** +// return pDual indicating if the given TypeDef is marked as a Dual interface +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::GetIsDualOfTypeDef(// return hresult + mdTypeDef classdef, // given classdef + ULONG *pDual) // [OUT] return dual flag here. +{ + ULONG iFace=0; // Iface type. + HRESULT hr; // A result. + + // no need to lock at this level + + hr = GetIfaceTypeOfTypeDef(classdef, &iFace); + if (hr == S_OK) + *pDual = (iFace == ifDual); + else + *pDual = 1; + + return hr; +} // MDInternalRW::GetIsDualOfTypeDef + +__checkReturn +HRESULT MDInternalRW::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. + + // all of the public functions that it calls have proper locked + + // 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) + { + _ASSERTE("The ComInterfaceType custom attribute is invalid" && cbVal); + _ASSERTE("ComInterfaceType custom attribute does not have the right format" && (*pVal == 0x01) && (*(pVal + 1) == 0x00)); + ItfType = *(pVal + 2); + if (ItfType >= ifLast) + ItfType = DEFAULT_COM_INTERFACE_TYPE; + } + + // Set the return value. + *pIface = ItfType; + + return hr; +} // MDInternalRW::GetIfaceTypeOfTypeDef + +//***************************************************************************** +// Given a methoddef, return a pointer to methoddef's name +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRW::GetNameOfMethodDef( + mdMethodDef md, + LPCSTR *pszMethodName) +{ + // name of method will not change. So no need to lock + HRESULT hr; + MethodRec *pMethodRec; + *pszMethodName = NULL; + IfFailRet(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(md), &pMethodRec)); + IfFailRet(m_pStgdb->m_MiniMd.getNameOfMethod(pMethodRec, pszMethodName)); + return S_OK; +} // MDInternalRW::GetNameOfMethodDef + + +//***************************************************************************** +// Given a methoddef, return a pointer to methoddef's signature and methoddef's name +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRW::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; + // we don't need lock here because name and signature will not change + + // Output parameter should not be NULL + _ASSERTE(ppvSigBlob && pcbSigBlob); + _ASSERTE(TypeFromToken(methoddef) == mdtMethodDef); + + MethodRec *pMethodRec; + *pszMethodName = NULL; + *ppvSigBlob = NULL; + *ppvSigBlob = NULL; + IfFailRet(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(methoddef), &pMethodRec)); + IfFailRet(m_pStgdb->m_MiniMd.getSignatureOfMethod(pMethodRec, ppvSigBlob, pcbSigBlob)); + + return GetNameOfMethodDef(methoddef, pszMethodName); +} // MDInternalRW::GetNameAndSigOfMethodDef + + +//***************************************************************************** +// Given a FieldDef, return a pointer to FieldDef's name in UTF8 +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRW::GetNameOfFieldDef( // return hresult + mdFieldDef fd, // given field + LPCSTR *pszFieldName) +{ + // we don't need lock here because name of field will not change + HRESULT hr; + + FieldRec *pFieldRec; + *pszFieldName = NULL; + IfFailRet(m_pStgdb->m_MiniMd.GetFieldRecord(RidFromToken(fd), &pFieldRec)); + IfFailRet(m_pStgdb->m_MiniMd.getNameOfField(pFieldRec, pszFieldName)); + return S_OK; +} // MDInternalRW::GetNameOfFieldDef + + +//***************************************************************************** +// Given a classdef, return a pointer to classdef's name in UTF8 +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRW::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; + + *psznamespace = NULL; + *pszname = NULL; + + // we don't need lock here because name of a typeref will not change + + TypeRefRec *pTypeRefRec; + IfFailRet(m_pStgdb->m_MiniMd.GetTypeRefRecord(RidFromToken(classref), &pTypeRefRec)); + IfFailRet(m_pStgdb->m_MiniMd.getNamespaceOfTypeRef(pTypeRefRec, psznamespace)); + IfFailRet(m_pStgdb->m_MiniMd.getNameOfTypeRef(pTypeRefRec, pszname)); + return S_OK; +} // MDInternalRW::GetNameOfTypeRef + +//***************************************************************************** +// return the resolutionscope of typeref +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRW::GetResolutionScopeOfTypeRef( + mdTypeRef classref, // given classref + mdToken *ptkResolutionScope) +{ + HRESULT hr = S_OK; + TypeRefRec *pTypeRefRec = NULL; + + LOCKREAD(); + + _ASSERTE(TypeFromToken(classref) == mdtTypeRef && RidFromToken(classref)); + + IfFailGo(m_pStgdb->m_MiniMd.GetTypeRefRecord(RidFromToken(classref), &pTypeRefRec)); + _ASSERTE(hr == S_OK); + *ptkResolutionScope = m_pStgdb->m_MiniMd.getResolutionScopeOfTypeRef(pTypeRefRec); + return S_OK; + +ErrExit: + *ptkResolutionScope = mdTokenNil; + return hr; +} // MDInternalRW::GetResolutionScopeOfTypeRef + +//***************************************************************************** +// Given a name, find the corresponding TypeRef. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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; + ULONG cTypeRefRecs; + TypeRefRec *pTypeRefRec; + LPCUTF8 szNamespaceTmp; + LPCUTF8 szNameTmp; + mdToken tkRes; + + LOCKREAD(); + _ASSERTE(ptk); + + // initialize the output parameter + *ptk = mdTypeRefNil; + + // Treat no namespace as empty string. + if (!szNamespace) + szNamespace = ""; + + // It is a linear search here. Do we want to instantiate the name hash? + cTypeRefRecs = m_pStgdb->m_MiniMd.getCountTypeRefs(); + + for (ULONG i = 1; i <= cTypeRefRecs; i++) + { + IfFailGo(m_pStgdb->m_MiniMd.GetTypeRefRecord(i, &pTypeRefRec)); + + tkRes = m_pStgdb->m_MiniMd.getResolutionScopeOfTypeRef(pTypeRefRec); + if (IsNilToken(tkRes)) + { + if (!IsNilToken(tkResolutionScope)) + continue; + } + else if (tkRes != tkResolutionScope) + continue; + + IfFailGo(m_pStgdb->m_MiniMd.getNamespaceOfTypeRef(pTypeRefRec, &szNamespaceTmp)); + if (strcmp(szNamespace, szNamespaceTmp)) + continue; + + IfFailGo(m_pStgdb->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; +} // MDInternalRW::FindTypeRefByName + +//***************************************************************************** +// return flags for a given class +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::GetTypeDefProps( + mdTypeDef td, // given classdef + DWORD *pdwAttr, // return flags on class + mdToken *ptkExtends) // [OUT] Put base class TypeDef/TypeRef here. +{ + HRESULT hr = S_OK; + TypeDefRec *pTypeDefRec = NULL; + LOCKREAD(); + + IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(td), &pTypeDefRec)); + + if (ptkExtends) + { + *ptkExtends = m_pStgdb->m_MiniMd.getExtendsOfTypeDef(pTypeDefRec); + } + if (pdwAttr) + { + *pdwAttr = m_pStgdb->m_MiniMd.getFlagsOfTypeDef(pTypeDefRec); + } + +ErrExit: + + return hr; +} // MDInternalRW::GetTypeDefProps + + +//***************************************************************************** +// return guid pointer to MetaData internal guid pool given a given class +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::GetItemGuid( // return hresult + mdToken tkObj, // given item. + CLSID *pGuid) // [OUT] put guid here. +{ + + HRESULT hr; // A result. + const BYTE *pBlob = NULL; // Blob with dispid. + ULONG cbBlob; // Length of blob. + WCHAR wzBlob[40]; // Wide char format of guid. + 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); + 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; +} // MDInternalRW::GetItemGuid + +//***************************************************************************** +// // get enclosing class of NestedClass +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRW::GetNestedClassProps( + mdTypeDef tkNestedClass, // [IN] NestedClass token. + mdTypeDef *ptkEnclosingClass) // [OUT] EnclosingClass token. +{ + HRESULT hr = NOERROR; + RID rid; + + BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW); + + LOCKREAD(); + + if (!m_pStgdb->m_MiniMd.IsSorted(TBL_NestedClass) && !m_pStgdb->m_MiniMd.IsTableVirtualSorted(TBL_NestedClass)) + { + // NestedClass table is not sorted. + CONVERT_READ_TO_WRITE_LOCK(); + } + + // This is a binary search thus we need to grap a read lock. Or this table + // might be sorted underneath our feet. + + _ASSERTE(TypeFromToken(tkNestedClass) == mdtTypeDef && ptkEnclosingClass); + + IfFailGo(m_pStgdb->m_MiniMd.FindNestedClassFor(RidFromToken(tkNestedClass), &rid)); + + if (InvalidRid(rid)) + { + hr = CLDB_E_RECORD_NOTFOUND; + } + else + { + NestedClassRec *pRecord; + IfFailGo(m_pStgdb->m_MiniMd.GetNestedClassRecord(rid, &pRecord)); + *ptkEnclosingClass = m_pStgdb->m_MiniMd.getEnclosingClassOfNestedClass(pRecord); + } + +ErrExit: + END_SO_INTOLERANT_CODE; + return hr; +} // MDInternalRW::GetNestedClassProps + +//******************************************************************************* +// Get count of Nested classes given the enclosing class. +//******************************************************************************* +__checkReturn +HRESULT +MDInternalRW::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_pStgdb->m_MiniMd.getCountNestedClasss(); + + for (ULONG i = 1; i <= ulCount; i++) + { + IfFailRet(m_pStgdb->m_MiniMd.GetNestedClassRecord(i, &pRecord)); + if (tkEnclosingClass == m_pStgdb->m_MiniMd.getEnclosingClassOfNestedClass(pRecord)) + ulRetCount++; + } + *pcNestedClassesCount = ulRetCount; + return S_OK; +} // MDInternalRW::GetCountNestedClasses + +//******************************************************************************* +// Return array of Nested classes given the enclosing class. +//******************************************************************************* +__checkReturn +HRESULT +MDInternalRW::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_pStgdb->m_MiniMd.getCountNestedClasss(); + + for (ULONG i = 1; i <= ulCount; i++) + { + IfFailRet(m_pStgdb->m_MiniMd.GetNestedClassRecord(i, &pRecord)); + if (tkEnclosingClass == m_pStgdb->m_MiniMd.getEnclosingClassOfNestedClass(pRecord)) + { + if (ovadd_le(ulRetCount, 1, ulNestedClasses)) // ulRetCount is 0 based. + rNestedClasses[ulRetCount] = m_pStgdb->m_MiniMd.getNestedClassOfNestedClass(pRecord); + ulRetCount++; + } + } + *pcNestedClasses = ulRetCount; + return S_OK; +} // MDInternalRW::GetNestedClasses + +//******************************************************************************* +// return the ModuleRef properties +//******************************************************************************* +__checkReturn +HRESULT MDInternalRW::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 = S_OK; + ModuleRefRec *pModuleRefRec = NULL; + LOCKREAD(); + + IfFailGo(m_pStgdb->m_MiniMd.GetModuleRefRecord(RidFromToken(mur), &pModuleRefRec)); + IfFailGo(m_pStgdb->m_MiniMd.getNameOfModuleRef(pModuleRefRec, pszName)); + +ErrExit: + + return hr; +} // MDInternalRW::GetModuleRefProps + + + +//***************************************************************************** +// Given a scope and a methoddef, return a pointer to methoddef's signature +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRW::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; + // We don't change MethodDef signature. No need to lock. + + MethodRec *pMethodRec; + *ppSig = NULL; + *pcbSigBlob = 0; + IfFailRet(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(methoddef), &pMethodRec)); + IfFailRet(m_pStgdb->m_MiniMd.getSignatureOfMethod(pMethodRec, ppSig, pcbSigBlob)); + return S_OK; +} // MDInternalRW::GetSigOfMethodDef + + +//***************************************************************************** +// Given a scope and a fielddef, return a pointer to fielddef's signature +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRW::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; + // We don't change Field's signature. No need to lock. + + FieldRec *pFieldRec; + *ppSig = NULL; + *pcbSigBlob = 0; + IfFailRet(m_pStgdb->m_MiniMd.GetFieldRecord(RidFromToken(fielddef), &pFieldRec)); + IfFailRet(m_pStgdb->m_MiniMd.getSignatureOfField(pFieldRec, ppSig, pcbSigBlob)); + return S_OK; +} // MDInternalRW::GetSigOfFieldDef + + +//***************************************************************************** +// Get signature for the token (FieldDef, MethodDef, Signature, or TypeSpec). +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRW::GetSigFromToken( + mdToken tk, + ULONG * pcbSig, + PCCOR_SIGNATURE * ppSig) +{ + HRESULT hr; + // We don't change token's signature. Thus no need to lock. + + *ppSig = NULL; + *pcbSig = 0; + switch (TypeFromToken(tk)) + { + case mdtSignature: + { + StandAloneSigRec *pRec; + IfFailGo(m_pStgdb->m_MiniMd.GetStandAloneSigRecord(RidFromToken(tk), &pRec)); + IfFailGo(m_pStgdb->m_MiniMd.getSignatureOfStandAloneSig(pRec, ppSig, pcbSig)); + return S_OK; + } + case mdtTypeSpec: + { + TypeSpecRec *pRec; + IfFailGo(m_pStgdb->m_MiniMd.GetTypeSpecRecord(RidFromToken(tk), &pRec)); + IfFailGo(m_pStgdb->m_MiniMd.getSignatureOfTypeSpec(pRec, ppSig, pcbSig)); + return S_OK; + } + case mdtMethodDef: + { + IfFailGo(GetSigOfMethodDef(tk, pcbSig, ppSig)); + return S_OK; + } + case mdtFieldDef: + { + IfFailGo(GetSigOfFieldDef(tk, pcbSig, ppSig)); + return S_OK; + } + } + + // not a known token type. +#ifdef _DEBUG + if(REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_AssertOnBadImageFormat, 1)) + _ASSERTE(!"Unexpected token type"); +#endif + *pcbSig = 0; + hr = META_E_INVALID_TOKEN_TYPE; + +ErrExit: + return hr; +} // MDInternalRW::GetSigFromToken + + +//***************************************************************************** +// Given methoddef, return the flags +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRW::GetMethodDefProps( + mdMethodDef md, + DWORD *pdwFlags) // return mdPublic, mdAbstract, etc +{ + HRESULT hr = S_OK; + MethodRec *pMethodRec = NULL; + + LOCKREAD(); + + IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(md), &pMethodRec)); + _ASSERTE(hr == S_OK); + *pdwFlags = m_pStgdb->m_MiniMd.getFlagsOfMethod(pMethodRec); + return S_OK; + +ErrExit: + *pdwFlags = (DWORD)-1; + return hr; +} // MDInternalRW::GetMethodDefProps + +//***************************************************************************** +// Given a scope and a methoddef, return RVA and impl flags +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::GetMethodImplProps( + mdToken tk, // [IN] MethodDef + ULONG *pulCodeRVA, // [OUT] CodeRVA + DWORD *pdwImplFlags) // [OUT] Impl. Flags +{ + _ASSERTE(TypeFromToken(tk) == mdtMethodDef); + HRESULT hr = S_OK; + MethodRec *pMethodRec = NULL; + + LOCKREAD(); + + IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(tk), &pMethodRec)); + + if (pulCodeRVA) + { + *pulCodeRVA = m_pStgdb->m_MiniMd.getRVAOfMethod(pMethodRec); + } + + if (pdwImplFlags) + { + *pdwImplFlags = m_pStgdb->m_MiniMd.getImplFlagsOfMethod(pMethodRec); + } + +ErrExit: + + return hr; +} // MDInternalRW::GetMethodImplProps + + +//***************************************************************************** +// return the field RVA +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::GetFieldRVA( + mdToken fd, // [IN] FieldDef + ULONG *pulCodeRVA) // [OUT] CodeRVA +{ + _ASSERTE(TypeFromToken(fd) == mdtFieldDef); + _ASSERTE(pulCodeRVA); + ULONG iRecord; + HRESULT hr = NOERROR; + + LOCKREAD(); + + IfFailGo(m_pStgdb->m_MiniMd.FindFieldRVAHelper(fd, &iRecord)); + if (InvalidRid(iRecord)) + { + if (pulCodeRVA) + *pulCodeRVA = 0; + hr = CLDB_E_RECORD_NOTFOUND; + } + else + { + FieldRVARec *pFieldRVARec; + IfFailGo(m_pStgdb->m_MiniMd.GetFieldRVARecord(iRecord, &pFieldRVARec)); + + *pulCodeRVA = m_pStgdb->m_MiniMd.getRVAOfFieldRVA(pFieldRVARec); + } + +ErrExit: + return hr; +} // MDInternalRW::GetFieldRVA + + +//***************************************************************************** +// Given a fielddef, return the flags. Such as fdPublic, fdStatic, etc +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRW::GetFieldDefProps( + mdFieldDef fd, // given memberdef + DWORD *pdwFlags) // [OUT] return fdPublic, fdPrive, etc flags +{ + _ASSERTE(TypeFromToken(fd) == mdtFieldDef); + HRESULT hr = S_OK; + FieldRec *pFieldRec = NULL; + + LOCKREAD(); + + IfFailRet(m_pStgdb->m_MiniMd.GetFieldRecord(RidFromToken(fd), &pFieldRec)); + _ASSERTE(hr == S_OK); + *pdwFlags = m_pStgdb->m_MiniMd.getFlagsOfField(pFieldRec); + return S_OK; + +ErrExit: + *pdwFlags = (DWORD)-1; + return hr; +} // MDInternalRW::GetFieldDefProps + +//***************************************************************************** +// return default value of a token(could be paramdef, fielddef, or property) +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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; + ConstantRec *pConstantRec; + + LOCKREAD(); + + IfFailGo(m_pStgdb->m_MiniMd.FindConstantHelper(tk, &rid)); + if (InvalidRid(rid)) + { + pMDDefaultValue->m_bType = ELEMENT_TYPE_VOID; + return S_OK; + } + IfFailGo(m_pStgdb->m_MiniMd.GetConstantRecord(rid, &pConstantRec)); + + // get the type of constant value + bType = m_pStgdb->m_MiniMd.getTypeOfConstant(pConstantRec); + + // get the value blob + IfFailGo(m_pStgdb->m_MiniMd.getValueOfConstant(pConstantRec, reinterpret_cast<const BYTE **>(&pValue), &cbValue)); + + // convert it to our internal default value representation + hr = _FillMDDefaultValue(bType, pValue, cbValue, pMDDefaultValue); + +ErrExit: + + return hr; +} // MDInternalRW::GetDefaultValue + + +//***************************************************************************** +// Given a scope and a methoddef/fielddef, return the dispid +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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. + + // No need to lock this function. All of the function that it is calling is already locked! + + // Get the DISPID, if any. + _ASSERTE(pDispid); + + *pDispid = DISPID_UNKNOWN; + hr = GetCustomAttributeByName(tk, INTEROP_DISPID_TYPE, (const void**)&pBlob, &cbBlob); + if (hr != S_FALSE) + { + // Check that this might be a dispid. + if (cbBlob >= (sizeof(*pDispid)+2)) + *pDispid = GET_UNALIGNED_VAL32(pBlob+2); + else + IfFailGo(E_INVALIDARG); + } + +ErrExit: + return hr; +#else // FEATURE_COMINTEROP + _ASSERTE(false); + return E_NOTIMPL; +#endif // FEATURE_COMINTEROP +} // MDInternalRW::GetDispIdOfMemberDef + + +//***************************************************************************** +// Given interfaceimpl, return the TypeRef/TypeDef and flags +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRW::GetTypeOfInterfaceImpl( // return hresult + mdInterfaceImpl iiImpl, // given a interfaceimpl + mdToken *ptkType) +{ + HRESULT hr; + // no need to lock this function. + + _ASSERTE(TypeFromToken(iiImpl) == mdtInterfaceImpl); + + *ptkType = mdTypeDefNil; + + InterfaceImplRec *pIIRec; + IfFailRet(m_pStgdb->m_MiniMd.GetInterfaceImplRecord(RidFromToken(iiImpl), &pIIRec)); + *ptkType = m_pStgdb->m_MiniMd.getInterfaceOfInterfaceImpl(pIIRec); + return S_OK; +} // MDInternalRW::GetTypeOfInterfaceImpl + +//***************************************************************************** +// This routine gets the properties for the given MethodSpec token. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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; + + _ASSERTE(TypeFromToken(mi) == mdtMethodSpec); + + IfFailGo(m_pStgdb->m_MiniMd.GetMethodSpecRecord(RidFromToken(mi), &pMethodSpecRec)); + + if (tkParent) + *tkParent = m_pStgdb->m_MiniMd.getMethodOfMethodSpec(pMethodSpecRec); + + if (ppvSigBlob || pcbSigBlob) + { + // caller wants signature information + PCCOR_SIGNATURE pvSigTmp; + ULONG cbSig; + IfFailGo(m_pStgdb->m_MiniMd.getInstantiationOfMethodSpec(pMethodSpecRec, &pvSigTmp, &cbSig)); + if ( ppvSigBlob ) + *ppvSigBlob = pvSigTmp; + if ( pcbSigBlob) + *pcbSigBlob = cbSig; + } + +ErrExit: + return hr; +} // MDInternalRW::GetMethodSpecProps + +//***************************************************************************** +// Given a classname, return the typedef +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::FindTypeDef( // return hresult + 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 +{ + HRESULT hr = S_OK; + LOCKREADIFFAILRET(); + + _ASSERTE(ptypedef); + + // initialize the output parameter + *ptypedef = mdTypeDefNil; + + return ImportHelper::FindTypeDefByName(&(m_pStgdb->m_MiniMd), + szNamespace, + szName, + tkEnclosingClass, + ptypedef); +} // MDInternalRW::FindTypeDef + +//***************************************************************************** +// Given a memberref, return a pointer to memberref's name and signature +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRW::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) +{ + HRESULT hr; + + // MemberRef's name and sig won't change. Don't need to lock this. + + _ASSERTE(TypeFromToken(memberref) == mdtMemberRef); + + MemberRefRec *pMemberRefRec; + *pszMemberRefName = NULL; + if (ppvSigBlob != NULL) + { + _ASSERTE(pcbSigBlob != NULL); + *ppvSigBlob = NULL; + *pcbSigBlob = 0; + } + IfFailRet(m_pStgdb->m_MiniMd.GetMemberRefRecord(RidFromToken(memberref), &pMemberRefRec)); + if (ppvSigBlob != NULL) + { + IfFailRet(m_pStgdb->m_MiniMd.getSignatureOfMemberRef(pMemberRefRec, ppvSigBlob, pcbSigBlob)); + } + IfFailRet(m_pStgdb->m_MiniMd.getNameOfMemberRef(pMemberRefRec, pszMemberRefName)); + return S_OK; +} // MDInternalRW::GetNameAndSigOfMemberRef + + + +//***************************************************************************** +// Given a memberref, return parent token. It can be a TypeRef, ModuleRef, or a MethodDef +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRW::GetParentOfMemberRef( // return parent token + mdMemberRef memberref, // given a typedef + mdToken *ptkParent) // return the parent token +{ + HRESULT hr = S_OK; + MemberRefRec *pMemberRefRec = NULL; + + LOCKREAD(); + + // parent for MemberRef can change. See SetParent. + + _ASSERTE(TypeFromToken(memberref) == mdtMemberRef); + + IfFailRet(m_pStgdb->m_MiniMd.GetMemberRefRecord(RidFromToken(memberref), &pMemberRefRec)); + _ASSERTE(hr == S_OK); + *ptkParent = m_pStgdb->m_MiniMd.getClassOfMemberRef(pMemberRefRec); + return S_OK; + +ErrExit: + *ptkParent = mdTokenNil; + return hr; +} // MDInternalRW::GetParentOfMemberRef + +//***************************************************************************** +// return properties of a paramdef +//*****************************************************************************/ +__checkReturn +HRESULT +MDInternalRW::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 +{ + HRESULT hr = S_OK; + ParamRec *pParamRec = NULL; + + LOCKREAD(); + + // parent for MemberRef can change. See SetParamProps. + + _ASSERTE(TypeFromToken(paramdef) == mdtParamDef); + IfFailGo(m_pStgdb->m_MiniMd.GetParamRecord(RidFromToken(paramdef), &pParamRec)); + _ASSERTE(hr == S_OK); + if (pdwAttr != NULL) + { + *pdwAttr = m_pStgdb->m_MiniMd.getFlagsOfParam(pParamRec); + } + if (pusSequence != NULL) + { + *pusSequence = m_pStgdb->m_MiniMd.getSequenceOfParam(pParamRec); + } + IfFailGo(m_pStgdb->m_MiniMd.getNameOfParam(pParamRec, pszName)); + _ASSERTE(hr == S_OK); + return S_OK; + +ErrExit: + *pszName = NULL; + return S_OK; +} // MDInternalRW::GetParamDefProps + +//***************************************************************************** +// Get property info for the method. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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 +{ + MethodSemanticsRec *pSemantics; + RID ridCur; + RID ridMax; + USHORT usSemantics; + HRESULT hr = S_OK; + LOCKREAD(); + + ridMax = m_pStgdb->m_MiniMd.getCountMethodSemantics(); + for (ridCur = 1; ridCur <= ridMax; ridCur++) + { + IfFailGo(m_pStgdb->m_MiniMd.GetMethodSemanticsRecord(ridCur, &pSemantics)); + if (md == m_pStgdb->m_MiniMd.getMethodOfMethodSemantics(pSemantics)) + { + // match the method + usSemantics = m_pStgdb->m_MiniMd.getSemanticOfMethodSemantics(pSemantics); + if (usSemantics == msGetter || usSemantics == msSetter) + { + // Make sure that it is not an invalid entry + if (m_pStgdb->m_MiniMd.getAssociationOfMethodSemantics(pSemantics) != mdPropertyNil) + { + // found a match. Fill out the output parameters + PropertyRec *pProperty; + mdProperty prop; + prop = m_pStgdb->m_MiniMd.getAssociationOfMethodSemantics(pSemantics); + + if (ppd) + *ppd = prop; + IfFailGo(m_pStgdb->m_MiniMd.GetPropertyRecord(RidFromToken(prop), &pProperty)); + + if (pName) + { + IfFailGo(m_pStgdb->m_MiniMd.getNameOfProperty(pProperty, pName)); + } + + if (pSemantic) + *pSemantic = usSemantics; + goto ErrExit; + } + } + } + } + + hr = S_FALSE; +ErrExit: + return hr; +} // MDInternalRW::GetPropertyInfoForMethodDef + +//***************************************************************************** +// return the pack size of a class +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::GetClassPackSize( + mdTypeDef td, // [IN] give typedef + DWORD *pdwPackSize) // [OUT] +{ + HRESULT hr = NOERROR; + RID ridClassLayout = 0; + + LOCKREAD(); + + _ASSERTE(TypeFromToken(td) == mdtTypeDef && pdwPackSize); + + ClassLayoutRec *pRec; + IfFailGo(m_pStgdb->m_MiniMd.FindClassLayoutHelper(td, &ridClassLayout)); + + if (InvalidRid(ridClassLayout)) + { + hr = CLDB_E_RECORD_NOTFOUND; + goto ErrExit; + } + + IfFailGo(m_pStgdb->m_MiniMd.GetClassLayoutRecord(RidFromToken(ridClassLayout), &pRec)); + *pdwPackSize = m_pStgdb->m_MiniMd.getPackingSizeOfClassLayout(pRec); +ErrExit: + return hr; +} // MDInternalRW::GetClassPackSize + + +//***************************************************************************** +// return the total size of a value class +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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 +{ + CONTRACT_VIOLATION(ThrowsViolation); + + _ASSERTE(TypeFromToken(td) == mdtTypeDef && pulClassSize); + + ClassLayoutRec *pRec; + HRESULT hr = NOERROR; + RID ridClassLayout; + + LOCKREAD(); + + IfFailGo(m_pStgdb->m_MiniMd.FindClassLayoutHelper(td, &ridClassLayout)); + if (InvalidRid(ridClassLayout)) + { + hr = CLDB_E_RECORD_NOTFOUND; + goto ErrExit; + } + + IfFailGo(m_pStgdb->m_MiniMd.GetClassLayoutRecord(RidFromToken(ridClassLayout), &pRec)); + *pulClassSize = m_pStgdb->m_MiniMd.getClassSizeOfClassLayout(pRec); +ErrExit: + return hr; +} // MDInternalRW::GetClassTotalSize + + +//***************************************************************************** +// init the layout enumerator of a class +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::GetClassLayoutInit( + mdTypeDef td, // [IN] give typedef + MD_CLASS_LAYOUT *pmdLayout) // [OUT] set up the status of query here +{ + HRESULT hr = NOERROR; + LOCKREAD(); + _ASSERTE(TypeFromToken(td) == mdtTypeDef); + + // <TODO>Do we need to lock this function? Can clints add more Fields on a TypeDef?</TODO> + + // initialize the output parameter + _ASSERTE(pmdLayout); + memset(pmdLayout, 0, sizeof(MD_CLASS_LAYOUT)); + + TypeDefRec *pTypeDefRec; + + // record for this typedef in TypeDef Table + IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(td), &pTypeDefRec)); + + // find the starting and end field for this typedef + pmdLayout->m_ridFieldCur = m_pStgdb->m_MiniMd.getFieldListOfTypeDef(pTypeDefRec); + IfFailGo(m_pStgdb->m_MiniMd.getEndFieldListOfTypeDef(RidFromToken(td), &(pmdLayout->m_ridFieldEnd))); + +ErrExit: + + return hr; +} // MDInternalRW::GetClassLayoutInit + +//***************************************************************************** +// Get the field offset for a given field token +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::GetFieldOffset( + mdFieldDef fd, // [IN] fielddef + ULONG *pulOffset) // [OUT] FieldOffset +{ + HRESULT hr = S_OK; + FieldLayoutRec *pRec; + + _ASSERTE(pulOffset); + + RID iLayout; + + LOCKREAD(); + + IfFailGo(m_pStgdb->m_MiniMd.FindFieldLayoutHelper(fd, &iLayout)); + + if (InvalidRid(iLayout)) + { + hr = S_FALSE; + goto ErrExit; + } + + IfFailGo(m_pStgdb->m_MiniMd.GetFieldLayoutRecord(iLayout, &pRec)); + *pulOffset = m_pStgdb->m_MiniMd.getOffSetOfFieldLayout(pRec); + _ASSERTE(*pulOffset != ULONG_MAX); + +ErrExit: + return hr; +} // MDInternalRW::GetFieldOffset + +//***************************************************************************** +// enum the next the field layout +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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; + + LOCKREAD(); + + while (pLayout->m_ridFieldCur < pLayout->m_ridFieldEnd) + { + RID fieldRid; + IfFailGo(m_pStgdb->m_MiniMd.GetFieldRid(pLayout->m_ridFieldCur, &fieldRid)); + mdFieldDef fd = TokenFromRid(fieldRid, mdtFieldDef); + IfFailGo(m_pStgdb->m_MiniMd.FindFieldLayoutHelper(fd, &iLayout2)); + pLayout->m_ridFieldCur++; + if (!InvalidRid(iLayout2)) + { + IfFailGo(m_pStgdb->m_MiniMd.GetFieldLayoutRecord(iLayout2, &pRec)); + *pulOffset = m_pStgdb->m_MiniMd.getOffSetOfFieldLayout(pRec); + _ASSERTE(*pulOffset != ULONG_MAX); + *pfd = fd; + goto ErrExit; + } + } + + *pfd = mdFieldDefNil; + hr = S_FALSE; + + // fall through + +ErrExit: + return hr; +} // MDInternalRW::GetClassLayoutNext + + +//***************************************************************************** +// return the field's native type signature +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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; + + LOCKREAD(); + + // find the row containing the marshal definition for tk + IfFailGo(m_pStgdb->m_MiniMd.FindFieldMarshalHelper(tk, &rid)); + if (InvalidRid(rid)) + { + hr = CLDB_E_RECORD_NOTFOUND; + goto ErrExit; + } + IfFailGo(m_pStgdb->m_MiniMd.GetFieldMarshalRecord(rid, &pFieldMarshalRec)); + + // get the native type + IfFailGo(m_pStgdb->m_MiniMd.getNativeTypeOfFieldMarshal(pFieldMarshalRec, pSigNativeType, pcbNativeType)); +ErrExit: + return hr; +} // MDInternalRW::GetFieldMarshal + + + +//***************************************** +// property APIs +//***************************************** + +//***************************************************************************** +// Find property by name +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::FindProperty( + mdTypeDef td, // [IN] given a typdef + LPCSTR szPropName, // [IN] property name + mdProperty *pProp) // [OUT] return property token +{ + HRESULT hr = NOERROR; + LOCKREAD(); + + // 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_pStgdb->m_MiniMd.FindPropertyMapFor(RidFromToken(td), &ridPropertyMap)); + if (InvalidRid(ridPropertyMap)) + { + // not found! + hr = CLDB_E_RECORD_NOTFOUND; + goto ErrExit; + } + + IfFailGo(m_pStgdb->m_MiniMd.GetPropertyMapRecord(ridPropertyMap, &pRec)); + + // get the starting/ending rid of properties of this typedef + ridCur = m_pStgdb->m_MiniMd.getPropertyListOfPropertyMap(pRec); + IfFailGo(m_pStgdb->m_MiniMd.getEndPropertyListOfPropertyMap(ridPropertyMap, &ridEnd)); + + for ( ; ridCur < ridEnd; ridCur ++ ) + { + RID propertyRid; + IfFailGo(m_pStgdb->m_MiniMd.GetPropertyRid(ridCur, &propertyRid)); + IfFailGo(m_pStgdb->m_MiniMd.GetPropertyRecord(propertyRid, &pProperty)); + IfFailGo(m_pStgdb->m_MiniMd.getNameOfProperty(pProperty, &szName)); + if ( strcmp(szName, szPropName) ==0 ) + { + // Found the match. Set the output parameter and we are done. + *pProp = TokenFromRid(propertyRid, mdtProperty); + goto ErrExit; + } + } + + // not found + hr = CLDB_E_RECORD_NOTFOUND; +ErrExit: + return hr; +} // MDInternalRW::FindProperty + + + +//***************************************************************************** +// return the properties of a property +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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 +{ + HRESULT hr = S_OK; + LOCKREAD(); + + // output parameters have to be supplied + _ASSERTE(TypeFromToken(prop) == mdtProperty); + + PropertyRec *pProperty; + ULONG cbSig; + + IfFailGo(m_pStgdb->m_MiniMd.GetPropertyRecord(RidFromToken(prop), &pProperty)); + + // get name of the property + if (pszProperty) + { + IfFailGo(m_pStgdb->m_MiniMd.getNameOfProperty(pProperty, pszProperty)); + } + + // get the flags of property + if (pdwPropFlags) + *pdwPropFlags = m_pStgdb->m_MiniMd.getPropFlagsOfProperty(pProperty); + + // get the type of the property + if (ppvSig) + { + IfFailGo(m_pStgdb->m_MiniMd.getTypeOfProperty(pProperty, ppvSig, &cbSig)); + if (pcbSig) + { + *pcbSig = cbSig; + } + } + +ErrExit: + return hr; +} // MDInternalRW::GetPropertyProps + + +//********************************** +// +// Event APIs +// +//********************************** + +//***************************************************************************** +// return an event by given the name +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::FindEvent( + mdTypeDef td, // [IN] given a typdef + LPCSTR szEventName, // [IN] event name + mdEvent *pEvent) // [OUT] return event token +{ + HRESULT hr = NOERROR; + LOCKREAD(); + + // 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_pStgdb->m_MiniMd.FindEventMapFor(RidFromToken(td), &ridEventMap)); + if (InvalidRid(ridEventMap)) + { + // not found! + hr = CLDB_E_RECORD_NOTFOUND; + goto ErrExit; + } + IfFailGo(m_pStgdb->m_MiniMd.GetEventMapRecord(ridEventMap, &pRec)); + + // get the starting/ending rid of properties of this typedef + ridCur = m_pStgdb->m_MiniMd.getEventListOfEventMap(pRec); + IfFailGo(m_pStgdb->m_MiniMd.getEndEventListOfEventMap(ridEventMap, &ridEnd)); + + for (; ridCur < ridEnd; ridCur ++) + { + RID eventRid; + IfFailGo(m_pStgdb->m_MiniMd.GetEventRid(ridCur, &eventRid)); + IfFailGo(m_pStgdb->m_MiniMd.GetEventRecord(eventRid, &pEventRec)); + IfFailGo(m_pStgdb->m_MiniMd.getNameOfEvent(pEventRec, &szName)); + if ( strcmp(szName, szEventName) ==0 ) + { + // Found the match. Set the output parameter and we are done. + *pEvent = TokenFromRid(eventRid, mdtEvent); + goto ErrExit; + } + } + + // not found + hr = CLDB_E_RECORD_NOTFOUND; +ErrExit: + + return hr; +} // MDInternalRW::FindEvent + + +//***************************************************************************** +// return the properties of an event +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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 +{ + HRESULT hr = S_OK; + LOCKREAD(); + EventRec *pEvent; + + // output parameters have to be supplied + _ASSERTE(TypeFromToken(ev) == mdtEvent); + + IfFailGo(m_pStgdb->m_MiniMd.GetEventRecord(RidFromToken(ev), &pEvent)); + if (pszEvent != NULL) + { + IfFailGo(m_pStgdb->m_MiniMd.getNameOfEvent(pEvent, pszEvent)); + } + if (pdwEventFlags) + *pdwEventFlags = m_pStgdb->m_MiniMd.getEventFlagsOfEvent(pEvent); + if (ptkEventType) + *ptkEventType = m_pStgdb->m_MiniMd.getEventTypeOfEvent(pEvent); + +ErrExit: + + return hr; +} // MDInternalRW::GetEventProps + +//***************************************************************************** +// return the properties of a generic param +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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_pStgdb->m_MiniMd.SupportsGenerics()) + IfFailGo(CLDB_E_INCOMPATIBLE); + + _ASSERTE(TypeFromToken(rd) == mdtGenericParam); + if (TypeFromToken(rd) != mdtGenericParam) + IfFailGo(CLDB_E_FILE_CORRUPT); + + IfFailGo(m_pStgdb->m_MiniMd.GetGenericParamRecord(RidFromToken(rd), &pGenericParamRec)); + + if (pulSequence) + *pulSequence = m_pStgdb->m_MiniMd.getNumberOfGenericParam(pGenericParamRec); + if (pdwAttr) + *pdwAttr = m_pStgdb->m_MiniMd.getFlagsOfGenericParam(pGenericParamRec); + if (ptOwner) + *ptOwner = m_pStgdb->m_MiniMd.getOwnerOfGenericParam(pGenericParamRec); + if (szName != NULL) + { + IfFailGo(m_pStgdb->m_MiniMd.getNameOfGenericParam(pGenericParamRec, szName)); + } + +ErrExit: + return hr; +} // MDInternalRW::GetGenericParamProps + + +//***************************************************************************** +// This routine gets the properties for the given GenericParamConstraint token. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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_pStgdb->m_MiniMd.SupportsGenerics()) + IfFailGo(CLDB_E_INCOMPATIBLE); + + if((TypeFromToken(rd) == mdtGenericParamConstraint) && (ridRD != 0)) + { + IfFailGo(m_pStgdb->m_MiniMd.GetGenericParamConstraintRecord(ridRD, &pGPCRec)); + + if (ptGenericParam) + *ptGenericParam = TokenFromRid(m_pStgdb->m_MiniMd.getOwnerOfGenericParamConstraint(pGPCRec),mdtGenericParam); + if (ptkConstraintType) + *ptkConstraintType = m_pStgdb->m_MiniMd.getConstraintOfGenericParamConstraint(pGPCRec); + } + else + hr = META_E_BAD_INPUT_PARAMETER; + +ErrExit: + return hr; +} // MDInternalRW::GetGenericParamConstraintProps + +//***************************************************************************** +// Find methoddef of a particular associate with a property or an event +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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; + RID rid; + MethodSemanticsRec *pMethodSemantics; + + // output parameters have to be supplied + _ASSERTE(pmd); + _ASSERTE(TypeFromToken(evprop) == mdtEvent || TypeFromToken(evprop) == mdtProperty); + + LOCKREAD(); + + hr = m_pStgdb->m_MiniMd.FindAssociateHelper(evprop, dwSemantics, &rid); + if (SUCCEEDED(hr)) + { + IfFailGo(m_pStgdb->m_MiniMd.GetMethodSemanticsRecord(rid, &pMethodSemantics)); + *pmd = m_pStgdb->m_MiniMd.getMethodOfMethodSemantics(pMethodSemantics); + } + +ErrExit: + + return hr; +} // MDInternalRW::FindAssociate + + +//***************************************************************************** +// get counts of methodsemantics associated with a particular property/event +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::EnumAssociateInit( + mdToken evprop, // [IN] given a property or an event token + HENUMInternal *phEnum) // [OUT] cursor to hold the query result +{ + HRESULT hr; + + LOCKREAD(); + + // output parameters have to be supplied + _ASSERTE(phEnum); + _ASSERTE(TypeFromToken(evprop) == mdtEvent || TypeFromToken(evprop) == mdtProperty); + + hr = m_pStgdb->m_MiniMd.FindMethodSemanticsHelper(evprop, phEnum); + +ErrExit: + return hr; +} // MDInternalRW::EnumAssociateInit + + +//***************************************************************************** +// get all methodsemantics associated with a particular property/event +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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 +{ + HRESULT hr = S_OK; + MethodSemanticsRec *pSemantics; + RID ridCur; + int index = 0; + + LOCKREAD(); + + // <TODO>@FUTURE: rewrite the EnumAssociateInit and GetAllAssociates. Because we might add more properties and events. + // Then we might resort MethodSemantics table. So this can be totally out of sync.</TODO> + + _ASSERTE(phEnum && pAssociateRec); + _ASSERTE(cAssociateRec == phEnum->m_ulCount); + + // Convert from row pointers to RIDs. + while (HENUMInternal::EnumNext(phEnum, (mdToken *)&ridCur)) + { + IfFailGo(m_pStgdb->m_MiniMd.GetMethodSemanticsRecord(ridCur, &pSemantics)); + + pAssociateRec[index].m_memberdef = m_pStgdb->m_MiniMd.getMethodOfMethodSemantics(pSemantics); + pAssociateRec[index].m_dwSemantics = m_pStgdb->m_MiniMd.getSemanticOfMethodSemantics(pSemantics); + index++; + } + +ErrExit: + + return hr; +} // MDInternalRW::GetAllAssociates + + +//***************************************************************************** +// Get the Action and Permissions blob for a given PermissionSet. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::GetPermissionSetProps( + mdPermission pm, // [IN] the permission token. + DWORD *pdwAction, // [OUT] CorDeclSecurity. + void const **ppvPermission, // [OUT] permission blob. + ULONG *pcbPermission) // [OUT] count of bytes of pvPermission. +{ + HRESULT hr = S_OK; + _ASSERTE(TypeFromToken(pm) == mdtPermission); + _ASSERTE(pdwAction && ppvPermission && pcbPermission); + + DeclSecurityRec *pPerm; + LOCKREAD(); + + IfFailGo(m_pStgdb->m_MiniMd.GetDeclSecurityRecord(RidFromToken(pm), &pPerm)); + *pdwAction = m_pStgdb->m_MiniMd.getActionOfDeclSecurity(pPerm); + IfFailGo(m_pStgdb->m_MiniMd.getPermissionSetOfDeclSecurity(pPerm, reinterpret_cast<const BYTE **>(ppvPermission), pcbPermission)); + +ErrExit: + + return hr; +} // MDInternalRW::GetPermissionSetProps + + +//***************************************************************************** +// Get the String given the String token. +// Return a pointer to the string, or NULL in case of error. +//***************************************************************************** +__checkReturn +HRESULT +MDInternalRW::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; + + // no need to lock this function. + + if (pfIs80Plus != NULL) + { + *pfIs80Plus = FALSE; + } + *pwszUserString = NULL; + *pcchStringSize = 0; + + _ASSERTE(pcchStringSize != NULL); + MetaData::DataBlob userString; + IfFailRet(m_pStgdb->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; +} // MDInternalRW::GetUserString + +//***************************************************************************** +// Get the properties for the given Assembly token. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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. +{ + AssemblyRec *pRecord; + HRESULT hr = S_OK; + LOCKREAD(); + + _ASSERTE(TypeFromToken(mda) == mdtAssembly && RidFromToken(mda)); + IfFailGo(m_pStgdb->m_MiniMd.GetAssemblyRecord(RidFromToken(mda), &pRecord)); + + if (ppbPublicKey != NULL) + { + IfFailGo(m_pStgdb->m_MiniMd.getPublicKeyOfAssembly(pRecord, reinterpret_cast<const BYTE **>(ppbPublicKey), pcbPublicKey)); + } + if (pulHashAlgId) + *pulHashAlgId = m_pStgdb->m_MiniMd.getHashAlgIdOfAssembly(pRecord); + if (pszName != NULL) + { + IfFailGo(m_pStgdb->m_MiniMd.getNameOfAssembly(pRecord, pszName)); + } + if (pMetaData) + { + pMetaData->usMajorVersion = m_pStgdb->m_MiniMd.getMajorVersionOfAssembly(pRecord); + pMetaData->usMinorVersion = m_pStgdb->m_MiniMd.getMinorVersionOfAssembly(pRecord); + pMetaData->usBuildNumber = m_pStgdb->m_MiniMd.getBuildNumberOfAssembly(pRecord); + pMetaData->usRevisionNumber = m_pStgdb->m_MiniMd.getRevisionNumberOfAssembly(pRecord); + IfFailGo(m_pStgdb->m_MiniMd.getLocaleOfAssembly(pRecord, &pMetaData->szLocale)); + pMetaData->ulProcessor = 0; + pMetaData->ulOS = 0; + } + if (pdwAssemblyFlags) + { + *pdwAssemblyFlags = m_pStgdb->m_MiniMd.getFlagsOfAssembly(pRecord); + + // Turn on the afPublicKey if PublicKey blob is not empty + DWORD cbPublicKey; + const BYTE *pbPublicKey; + IfFailGo(m_pStgdb->m_MiniMd.getPublicKeyOfAssembly(pRecord, &pbPublicKey, &cbPublicKey)); + if (cbPublicKey) + *pdwAssemblyFlags |= afPublicKey; + } + +ErrExit: + return hr; + +} // MDInternalRW::GetAssemblyProps + +//***************************************************************************** +// Get the properties for the given AssemblyRef token. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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. +{ + AssemblyRefRec *pRecord; + HRESULT hr = S_OK; + + LOCKREAD(); + + _ASSERTE(TypeFromToken(mdar) == mdtAssemblyRef && RidFromToken(mdar)); + IfFailGo(m_pStgdb->m_MiniMd.GetAssemblyRefRecord(RidFromToken(mdar), &pRecord)); + + if (ppbPublicKeyOrToken != NULL) + { + IfFailGo(m_pStgdb->m_MiniMd.getPublicKeyOrTokenOfAssemblyRef(pRecord, reinterpret_cast<const BYTE **>(ppbPublicKeyOrToken), pcbPublicKeyOrToken)); + } + if (pszName != NULL) + { + IfFailGo(m_pStgdb->m_MiniMd.getNameOfAssemblyRef(pRecord, pszName)); + } + if (pMetaData) + { + pMetaData->usMajorVersion = m_pStgdb->m_MiniMd.getMajorVersionOfAssemblyRef(pRecord); + pMetaData->usMinorVersion = m_pStgdb->m_MiniMd.getMinorVersionOfAssemblyRef(pRecord); + pMetaData->usBuildNumber = m_pStgdb->m_MiniMd.getBuildNumberOfAssemblyRef(pRecord); + pMetaData->usRevisionNumber = m_pStgdb->m_MiniMd.getRevisionNumberOfAssemblyRef(pRecord); + IfFailGo(m_pStgdb->m_MiniMd.getLocaleOfAssemblyRef(pRecord, &pMetaData->szLocale)); + pMetaData->ulProcessor = 0; + pMetaData->ulOS = 0; + } + if (ppbHashValue != NULL) + { + IfFailGo(m_pStgdb->m_MiniMd.getHashValueOfAssemblyRef(pRecord, reinterpret_cast<const BYTE **>(ppbHashValue), pcbHashValue)); + } + if (pdwAssemblyRefFlags) + *pdwAssemblyRefFlags = m_pStgdb->m_MiniMd.getFlagsOfAssemblyRef(pRecord); + +ErrExit: + return hr; +} // MDInternalRW::GetAssemblyRefProps + +//***************************************************************************** +// Get the properties for the given File token. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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. +{ + FileRec *pRecord; + HRESULT hr = S_OK; + + LOCKREAD(); + + _ASSERTE(TypeFromToken(mdf) == mdtFile && RidFromToken(mdf)); + IfFailGo(m_pStgdb->m_MiniMd.GetFileRecord(RidFromToken(mdf), &pRecord)); + + if (pszName != NULL) + { + IfFailGo(m_pStgdb->m_MiniMd.getNameOfFile(pRecord, pszName)); + } + if (ppbHashValue != NULL) + { + IfFailGo(m_pStgdb->m_MiniMd.getHashValueOfFile(pRecord, reinterpret_cast<const BYTE **>(ppbHashValue), pcbHashValue)); + } + if (pdwFileFlags) + *pdwFileFlags = m_pStgdb->m_MiniMd.getFlagsOfFile(pRecord); + +ErrExit: + return hr; +} // MDInternalRW::GetFileProps + +//***************************************************************************** +// Get the properties for the given ExportedType token. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::GetExportedTypeProps( + mdExportedType mdct, // [IN] The ExportedType for which to get the properties. + LPCSTR *pszNamespace, // [OUT] Buffer to fill with name. + 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. +{ + ExportedTypeRec *pRecord; + HRESULT hr = S_OK; + + LOCKREAD(); + + _ASSERTE(TypeFromToken(mdct) == mdtExportedType && RidFromToken(mdct)); + IfFailGo(m_pStgdb->m_MiniMd.GetExportedTypeRecord(RidFromToken(mdct), &pRecord)); + + if (pszNamespace != NULL) + { + IfFailGo(m_pStgdb->m_MiniMd.getTypeNamespaceOfExportedType(pRecord, pszNamespace)); + } + if (pszName != NULL) + { + IfFailGo(m_pStgdb->m_MiniMd.getTypeNameOfExportedType(pRecord, pszName)); + } + if (ptkImplementation) + *ptkImplementation = m_pStgdb->m_MiniMd.getImplementationOfExportedType(pRecord); + if (ptkTypeDef) + *ptkTypeDef = m_pStgdb->m_MiniMd.getTypeDefIdOfExportedType(pRecord); + if (pdwExportedTypeFlags) + *pdwExportedTypeFlags = m_pStgdb->m_MiniMd.getFlagsOfExportedType(pRecord); + +ErrExit: + return hr; +} // MDInternalRW::GetExportedTypeProps + +//***************************************************************************** +// Get the properties for the given Resource token. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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. +{ + ManifestResourceRec *pRecord; + HRESULT hr = S_OK; + + LOCKREAD(); + + _ASSERTE(TypeFromToken(mdmr) == mdtManifestResource && RidFromToken(mdmr)); + IfFailGo(m_pStgdb->m_MiniMd.GetManifestResourceRecord(RidFromToken(mdmr), &pRecord)); + + if (pszName != NULL) + { + IfFailGo(m_pStgdb->m_MiniMd.getNameOfManifestResource(pRecord, pszName)); + } + if (ptkImplementation) + *ptkImplementation = m_pStgdb->m_MiniMd.getImplementationOfManifestResource(pRecord); + if (pdwOffset) + *pdwOffset = m_pStgdb->m_MiniMd.getOffsetOfManifestResource(pRecord); + if (pdwResourceFlags) + *pdwResourceFlags = m_pStgdb->m_MiniMd.getFlagsOfManifestResource(pRecord); + +ErrExit: + return hr; +} // MDInternalRW::GetManifestResourceProps + +//***************************************************************************** +// Find the ExportedType given the name. +//***************************************************************************** +__checkReturn +STDMETHODIMP MDInternalRW::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. +{ + _ASSERTE(szName && pmct); + HRESULT hr = S_OK; + LOCKREADIFFAILRET(); + + IMetaModelCommon *pCommon = static_cast<IMetaModelCommon*>(&m_pStgdb->m_MiniMd); + return pCommon->CommonFindExportedType(szNamespace, szName, tkEnclosingType, pmct); +} // MDInternalRW::FindExportedTypeByName + +//***************************************************************************** +// Find the ManifestResource given the name. +//***************************************************************************** +__checkReturn +STDMETHODIMP MDInternalRW::FindManifestResourceByName(// S_OK or error + LPCSTR szName, // [IN] Name of the resource. + mdManifestResource *pmmr) // [OUT] Put ManifestResource token here. +{ + _ASSERTE(szName && pmmr); + + ManifestResourceRec *pRecord; + ULONG cRecords; // Count of records. + LPCUTF8 szNameTmp = 0; // Name obtained from the database. + ULONG i; + HRESULT hr = S_OK; + + LOCKREAD(); + + cRecords = m_pStgdb->m_MiniMd.getCountManifestResources(); + + // Search for the ExportedType. + for (i = 1; i <= cRecords; i++) + { + IfFailGo(m_pStgdb->m_MiniMd.GetManifestResourceRecord(i, &pRecord)); + IfFailGo(m_pStgdb->m_MiniMd.getNameOfManifestResource(pRecord, &szNameTmp)); + if (! strcmp(szName, szNameTmp)) + { + *pmmr = TokenFromRid(i, mdtManifestResource); + goto ErrExit; + } + } + hr = CLDB_E_RECORD_NOTFOUND; +ErrExit: + + return hr; +} // MDInternalRW::FindManifestResourceByName + +//***************************************************************************** +// Get the Assembly token from the given scope. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::GetAssemblyFromScope( // S_OK or error + mdAssembly *ptkAssembly) // [OUT] Put token here. +{ + _ASSERTE(ptkAssembly); + + if (m_pStgdb->m_MiniMd.getCountAssemblys()) + { + *ptkAssembly = TokenFromRid(1, mdtAssembly); + return S_OK; + } + else + return CLDB_E_RECORD_NOTFOUND; +} // MDInternalRW::GetAssemblyFromScope + +//******************************************************************************* +// return properties regarding a TypeSpec +//******************************************************************************* +//******************************************************************************* +// return properties regarding a TypeSpec +//******************************************************************************* +__checkReturn +HRESULT MDInternalRW::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)) + return E_INVALIDARG; + + TypeSpecRec *pRec; + IfFailRet(m_pStgdb->m_MiniMd.GetTypeSpecRecord(RidFromToken(typespec), &pRec)); + + if (pRec == NULL) + return CLDB_E_FILE_CORRUPT; + + IfFailRet(m_pStgdb->m_MiniMd.getSignatureOfTypeSpec(pRec, ppvSig, pcbSig)); + + return hr; +} // MDInternalRW::GetTypeSpecFromToken + + +//***************************************************************************** +// Return contents of Pinvoke given the forwarded member token. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::GetPinvokeMap( + mdToken tk, // [IN] FieldDef, MethodDef or MethodImpl. + DWORD *pdwMappingFlags, // [OUT] Flags used for mapping. + LPCSTR *pszImportName, // [OUT] Import name. + mdModuleRef *pmrImportDLL) // [OUT] ModuleRef token for the target DLL. +{ + ImplMapRec *pRecord; + ULONG iRecord; + HRESULT hr = S_OK; + + LOCKREAD(); + + IfFailGo(m_pStgdb->m_MiniMd.FindImplMapHelper(tk, &iRecord)); + if (InvalidRid(iRecord)) + { + hr = CLDB_E_RECORD_NOTFOUND; + goto ErrExit; + } + else + IfFailGo(m_pStgdb->m_MiniMd.GetImplMapRecord(iRecord, &pRecord)); + + if (pdwMappingFlags) + *pdwMappingFlags = m_pStgdb->m_MiniMd.getMappingFlagsOfImplMap(pRecord); + if (pszImportName != NULL) + { + IfFailGo(m_pStgdb->m_MiniMd.getImportNameOfImplMap(pRecord, pszImportName)); + } + if (pmrImportDLL) + *pmrImportDLL = m_pStgdb->m_MiniMd.getImportScopeOfImplMap(pRecord); +ErrExit: + return hr; +} // MDInternalRW::GetPinvokeMap + +//***************************************************************************** +// convert a text signature to com format +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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; +} // _ConvertTextSigToComSig + +//***************************************************************************** +// This is a way for the EE to associate some data with this RW metadata to +// be released when this RW goes away. This is useful when a RO metadata is +// converted to RW, because arbitrary threads can be executing in the RO. +// So, we hold onto the RO here, and when the module shuts down, we release it. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::SetUserContextData(// S_OK or E_NOTIMPL + IUnknown *pIUnk) // The user context. +{ + // Only one chance to do this. + if (m_pUserUnk) + return E_UNEXPECTED; + m_pUserUnk = pIUnk; + return S_OK; +} // MDInternalRW::SetUserContextData + +//***************************************************************************** +// determine if a token is valid or not +//***************************************************************************** +BOOL MDInternalRW::IsValidToken( // True or False. + mdToken tk) // [IN] Given token. +{ + RID rid = RidFromToken(tk); + // no need to lock on this function. + if (rid == 0) + { + return FALSE; + } + switch (TypeFromToken(tk)) + { + case mdtModule: + // can have only one module record + return (rid <= m_pStgdb->m_MiniMd.getCountModules()); + case mdtTypeRef: + return (rid <= m_pStgdb->m_MiniMd.getCountTypeRefs()); + case mdtTypeDef: + return (rid <= m_pStgdb->m_MiniMd.getCountTypeDefs()); + case mdtFieldDef: + return (rid <= m_pStgdb->m_MiniMd.getCountFields()); + case mdtMethodDef: + return (rid <= m_pStgdb->m_MiniMd.getCountMethods()); + case mdtParamDef: + return (rid <= m_pStgdb->m_MiniMd.getCountParams()); + case mdtInterfaceImpl: + return (rid <= m_pStgdb->m_MiniMd.getCountInterfaceImpls()); + case mdtMemberRef: + return (rid <= m_pStgdb->m_MiniMd.getCountMemberRefs()); + case mdtCustomAttribute: + return (rid <= m_pStgdb->m_MiniMd.getCountCustomAttributes()); + case mdtPermission: + return (rid <= m_pStgdb->m_MiniMd.getCountDeclSecuritys()); + case mdtSignature: + return (rid <= m_pStgdb->m_MiniMd.getCountStandAloneSigs()); + case mdtEvent: + return (rid <= m_pStgdb->m_MiniMd.getCountEvents()); + case mdtProperty: + return (rid <= m_pStgdb->m_MiniMd.getCountPropertys()); + case mdtModuleRef: + return (rid <= m_pStgdb->m_MiniMd.getCountModuleRefs()); + case mdtTypeSpec: + return (rid <= m_pStgdb->m_MiniMd.getCountTypeSpecs()); + case mdtAssembly: + return (rid <= m_pStgdb->m_MiniMd.getCountAssemblys()); + case mdtAssemblyRef: + return (rid <= m_pStgdb->m_MiniMd.getCountAssemblyRefs()); + case mdtFile: + return (rid <= m_pStgdb->m_MiniMd.getCountFiles()); + case mdtExportedType: + return (rid <= m_pStgdb->m_MiniMd.getCountExportedTypes()); + case mdtManifestResource: + return (rid <= m_pStgdb->m_MiniMd.getCountManifestResources()); + case mdtMethodSpec: + return (rid <= m_pStgdb->m_MiniMd.getCountMethodSpecs()); + case mdtString: + // need to check the user string heap + return m_pStgdb->m_MiniMd.m_UserStringHeap.IsValidIndex(rid); + } + return FALSE; +} // MDInternalRW::IsValidToken + +mdModule MDInternalRW::GetModuleFromScope(void) +{ + return TokenFromRid(1, mdtModule); +} // MDInternalRW::GetModuleFromScope + +//***************************************************************************** +// Given a MetaData with ENC changes, apply those changes to this MetaData. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::ApplyEditAndContinue( // S_OK or error. + MDInternalRW *pDeltaMD) // Interface to MD with the ENC delta. +{ + HRESULT hr; // A result. + // Get the MiniMd on the delta. + + LOCKWRITEIFFAILRET(); + + CMiniMdRW &mdDelta = pDeltaMD->m_pStgdb->m_MiniMd; + CMiniMdRW &mdBase = m_pStgdb->m_MiniMd; + + + IfFailGo(mdBase.ConvertToRW()); + IfFailGo(mdBase.ApplyDelta(mdDelta)); +ErrExit: + return hr; +} // MDInternalRW::ApplyEditAndContinue + +//***************************************************************************** +// Given a MetaData with ENC changes, enumerate the changed tokens. +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::EnumDeltaTokensInit( // return hresult + HENUMInternal *phEnum) // Enumerator to initialize. +{ + HRESULT hr = S_OK; // A result. + ULONG index; // Loop control. + ENCLogRec *pRec; // An ENCLog record. + + // Vars for query. + _ASSERTE(phEnum); + memset(phEnum, 0, sizeof(HENUMInternal)); + + // cache the tkKind and the scope + phEnum->m_tkKind = 0; + + phEnum->m_EnumType = MDSimpleEnum; + + HENUMInternal::InitDynamicArrayEnum(phEnum); + for (index = 1; index <= m_pStgdb->m_MiniMd.m_Schema.m_cRecs[TBL_ENCLog]; ++index) + { + // Get the token type; see if it is a real token. + IfFailGo(m_pStgdb->m_MiniMd.GetENCLogRecord(index, &pRec)); + if (CMiniMdRW::IsRecId(pRec->GetToken())) + continue; + // If there is a function code, that means that this flags a child-record + // addition. The child record will generate its own token, so did the + // parent, so skip the record. + if (pRec->GetFuncCode()) + continue; + + IfFailGo( HENUMInternal::AddElementToEnum( + phEnum, + pRec->GetToken())); + } + +ErrExit: + // we are done + return hr; +} // MDInternalRW::EnumDeltaTokensInit + + +//***************************************************************************** +// Static function to apply a delta md. This is what the EE calls to apply +// the metadata updates from an update PE to live metadata. +// <TODO>MAY REPLACE THE IMDInternalImport POINTER!</TODO> +//***************************************************************************** +__checkReturn +HRESULT MDApplyEditAndContinue( // S_OK or error. + IMDInternalImport **ppIMD, // [in, out] The metadata to be updated. + IMDInternalImportENC *pDeltaMD) // [in] The delta metadata. +{ + HRESULT hr; // A result. + IMDInternalImportENC *pENC; // ENC interface on the metadata. + + // If the input metadata isn't RW, convert it. + hr = (*ppIMD)->QueryInterface(IID_IMDInternalImportENC, (void**)&pENC); + if (FAILED(hr)) + { + IfFailGo(ConvertRO2RW(*ppIMD, IID_IMDInternalImportENC, (void**)&pENC)); + // Replace the old interface pointer with the ENC one. + (*ppIMD)->Release(); + IfFailGo(pENC->QueryInterface(IID_IMDInternalImport, (void**)ppIMD)); + } + + // Apply the delta to the input metadata. + hr = pENC->ApplyEditAndContinue(static_cast<MDInternalRW*>(pDeltaMD)); + +ErrExit: + if (pENC) + pENC->Release(); + return hr; +} // MDApplyEditAndContinue + +//***************************************************************************** +// Given a scope, return the table size and table ptr for a given index +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::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; +} + +//***************************************************************************** +// Given a delta metadata byte stream, apply the changes to the current metadata +// object returning the resulting metadata object in ppv +//***************************************************************************** +__checkReturn +HRESULT MDInternalRW::ApplyEditAndContinue( + void *pDeltaMD, // [IN] the delta metadata + ULONG cbDeltaMD, // [IN] length of pData + IMDInternalImport **ppv) // [OUT] the resulting metadata interface +{ + _ASSERTE(pDeltaMD); + _ASSERTE(ppv); + + // debugging-specific usages don't need SO hardening + SO_NOT_MAINLINE_FUNCTION; + + 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; +} // MDInternalRW::ApplyEditAndContinue + +#endif //FEATURE_METADATA_INTERNAL_APIS |