diff options
Diffstat (limited to 'src/md/compiler/custattr_import.cpp')
-rw-r--r-- | src/md/compiler/custattr_import.cpp | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/src/md/compiler/custattr_import.cpp b/src/md/compiler/custattr_import.cpp new file mode 100644 index 0000000000..b5ed3647a5 --- /dev/null +++ b/src/md/compiler/custattr_import.cpp @@ -0,0 +1,283 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +//***************************************************************************** + +// +// CustAttr_Import.cpp +// +// Implementation for the meta data custom attribute import code (code:IMetaDataImport). +// +//***************************************************************************** +#include "stdafx.h" +#include "regmeta.h" +#include "metadata.h" +#include "corerror.h" +#include "mdutil.h" +#include "rwutil.h" +#include "mdlog.h" +#include "importhelper.h" +#include "mdperf.h" +#include "posterror.h" +#include "cahlprinternal.h" +#include "custattr.h" +#include "corhdr.h" +#include <metamodelrw.h> + +//***************************************************************************** +// Implementation of hash for custom attribute types. +//***************************************************************************** +unsigned int CCustAttrHash::Hash(const CCustAttrHashKey *pData) +{ + return static_cast<unsigned int>(pData->tkType); +} // unsigned long CCustAttrHash::Hash() +unsigned int CCustAttrHash::Compare(const CCustAttrHashKey *p1, CCustAttrHashKey *p2) +{ + if (p1->tkType == p2->tkType) + return 0; + return 1; +} // unsigned long CCustAttrHash::Compare() +CCustAttrHash::ELEMENTSTATUS CCustAttrHash::Status(CCustAttrHashKey *p) +{ + if (p->tkType == FREE) + return (FREE); + if (p->tkType == DELETED) + return (DELETED); + return (USED); +} // CCustAttrHash::ELEMENTSTATUS CCustAttrHash::Status() +void CCustAttrHash::SetStatus(CCustAttrHashKey *p, CCustAttrHash::ELEMENTSTATUS s) +{ + p->tkType = s; +} // void CCustAttrHash::SetStatus() +void* CCustAttrHash::GetKey(CCustAttrHashKey *p) +{ + return &p->tkType; +} // void* CCustAttrHash::GetKey() + + +//***************************************************************************** +// Get the value of a CustomAttribute, using only TypeName for lookup. +//***************************************************************************** +STDMETHODIMP RegMeta::GetCustomAttributeByName( // S_OK or error. + mdToken tkObj, // [IN] Object with Custom Attribute. + LPCWSTR wzName, // [IN] Name of desired Custom Attribute. + const void **ppData, // [OUT] Put pointer to data here. + ULONG *pcbData) // [OUT] Put size of data here. +{ + HRESULT hr; // A result. + + BEGIN_ENTRYPOINT_NOTHROW; + + LPUTF8 szName; // Name in UFT8. + int iLen; // A length. + CMiniMdRW *pMiniMd = NULL; + + START_MD_PERF(); + LOCKREAD(); + pMiniMd = &(m_pStgdb->m_MiniMd); + + iLen = WszWideCharToMultiByte(CP_UTF8,0, wzName,-1, NULL,0, 0,0); + szName = (LPUTF8)_alloca(iLen); + VERIFY(WszWideCharToMultiByte(CP_UTF8,0, wzName,-1, szName,iLen, 0,0)); + + hr = ImportHelper::GetCustomAttributeByName(pMiniMd, tkObj, szName, ppData, pcbData); + +ErrExit: + + STOP_MD_PERF(GetCustomAttributeByName); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::GetCustomAttributeByName() + + +//***************************************************************************** +// Enumerate the CustomAttributes for a given token. +//***************************************************************************** +STDMETHODIMP RegMeta::EnumCustomAttributes( + HCORENUM *phEnum, // Pointer to the enum. + mdToken tk, // Token to scope the enumeration. + mdToken tkType, // Type to limit the enumeration. + mdCustomAttribute rCustomAttributes[], // Put CustomAttributes here. + ULONG cMax, // Max CustomAttributes to put. + ULONG *pcCustomAttributes) // Put # tokens returned here. +{ + HRESULT hr = S_OK; + + BEGIN_ENTRYPOINT_NOTHROW; + + HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); + ULONG ridStart; + ULONG ridEnd; + HENUMInternal *pEnum = *ppmdEnum; + CustomAttributeRec *pRec; + ULONG index; + + LOG((LOGMD, "RegMeta::EnumCustomAttributes(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + phEnum, tk, tkType, rCustomAttributes, cMax, pcCustomAttributes)); + START_MD_PERF(); + LOCKREAD(); + + if ( pEnum == 0 ) + { + // instantiating a new ENUM + CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); + CLookUpHash *pHashTable = pMiniMd->m_pLookUpHashs[TBL_CustomAttribute]; + + // Does caller want all custom Values? + if (IsNilToken(tk)) + { + IfFailGo( HENUMInternal::CreateSimpleEnum(mdtCustomAttribute, 1, pMiniMd->getCountCustomAttributes()+1, &pEnum) ); + } + else + { // Scope by some object. + if ( pMiniMd->IsSorted( TBL_CustomAttribute ) ) + { + // Get CustomAttributes for the object. + IfFailGo(pMiniMd->getCustomAttributeForToken(tk, &ridEnd, &ridStart)); + + if (IsNilToken(tkType)) + { + // Simple enumerator for object's entire list. + IfFailGo( HENUMInternal::CreateSimpleEnum( mdtCustomAttribute, ridStart, ridEnd, &pEnum) ); + } + else + { + // Dynamic enumerator for subsetted list. + + IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtCustomAttribute, &pEnum) ); + + for (index = ridStart; index < ridEnd; index ++ ) + { + IfFailGo(pMiniMd->GetCustomAttributeRecord(index, &pRec)); + if (tkType == pMiniMd->getTypeOfCustomAttribute(pRec)) + { + IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtCustomAttribute) ) ); + } + } + } + } + else + { + + if (pHashTable) + { + // table is not sorted but hash is built + // We want to create dynmaic array to hold the dynamic enumerator. + TOKENHASHENTRY *p; + ULONG iHash; + int pos; + mdToken tkParentTmp; + mdToken tkTypeTmp; + + // Hash the data. + iHash = pMiniMd->HashCustomAttribute(tk); + + IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtCustomAttribute, &pEnum) ); + + // Go through every entry in the hash chain looking for ours. + for (p = pHashTable->FindFirst(iHash, pos); + p; + p = pHashTable->FindNext(pos)) + { + + CustomAttributeRec *pCustomAttribute; + IfFailGo(pMiniMd->GetCustomAttributeRecord(RidFromToken(p->tok), &pCustomAttribute)); + tkParentTmp = pMiniMd->getParentOfCustomAttribute(pCustomAttribute); + tkTypeTmp = pMiniMd->getTypeOfCustomAttribute(pCustomAttribute); + if (tkParentTmp == tk) + { + if (IsNilToken(tkType) || tkType == tkTypeTmp) + { + // compare the blob value + IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(p->tok, mdtCustomAttribute )) ); + } + } + } + } + else + { + + // table is not sorted and hash is not built so we have to create dynmaic array + // create the dynamic enumerator and loop through CA table linearly + // + ridStart = 1; + ridEnd = pMiniMd->getCountCustomAttributes() + 1; + + IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtCustomAttribute, &pEnum) ); + + for (index = ridStart; index < ridEnd; index ++ ) + { + IfFailGo(pMiniMd->GetCustomAttributeRecord(index, &pRec)); + if ( tk == pMiniMd->getParentOfCustomAttribute(pRec) && + (tkType == pMiniMd->getTypeOfCustomAttribute(pRec) || IsNilToken(tkType))) + { + IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtCustomAttribute) ) ); + } + } + } + } + } + + // set the output parameter + *ppmdEnum = pEnum; + } + + // fill the output token buffer + hr = HENUMInternal::EnumWithCount(pEnum, cMax, rCustomAttributes, pcCustomAttributes); + +ErrExit: + HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); + + STOP_MD_PERF(EnumCustomAttributes); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // STDMETHODIMP RegMeta::EnumCustomAttributes() + + +//***************************************************************************** +// Get information about a CustomAttribute. +//***************************************************************************** +STDMETHODIMP RegMeta::GetCustomAttributeProps( + mdCustomAttribute cv, // The attribute token + mdToken *ptkObj, // [OUT, OPTIONAL] Put object token here. + mdToken *ptkType, // [OUT, OPTIONAL] Put TypeDef/TypeRef token here. + void const **ppBlob, // [OUT, OPTIONAL] Put pointer to data here. + ULONG *pcbSize) // [OUT, OPTIONAL] Put size of data here. +{ + HRESULT hr = S_OK; // A result. + + BEGIN_ENTRYPOINT_NOTHROW; + + CMiniMdRW *pMiniMd; + + START_MD_PERF(); + LOCKREAD(); + + _ASSERTE(TypeFromToken(cv) == mdtCustomAttribute); + + pMiniMd = &(m_pStgdb->m_MiniMd); + CustomAttributeRec *pCustomAttributeRec; // The custom value record. + + IfFailGo(pMiniMd->GetCustomAttributeRecord(RidFromToken(cv), &pCustomAttributeRec)); + + if (ptkObj) + *ptkObj = pMiniMd->getParentOfCustomAttribute(pCustomAttributeRec); + + if (ptkType) + *ptkType = pMiniMd->getTypeOfCustomAttribute(pCustomAttributeRec); + + if (ppBlob != NULL) + { + IfFailGo(pMiniMd->getValueOfCustomAttribute(pCustomAttributeRec, (const BYTE **)ppBlob, pcbSize)); + } + +ErrExit: + + STOP_MD_PERF(GetCustomAttributeProps); + END_ENTRYPOINT_NOTHROW; + + return hr; +} // RegMeta::GetCustomAttributeProps |