summaryrefslogtreecommitdiff
path: root/src/md/compiler/custattr_import.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/md/compiler/custattr_import.cpp')
-rw-r--r--src/md/compiler/custattr_import.cpp283
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