1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//*****************************************************************************
5
6//
7// CustAttr_Import.cpp
8//
9// Implementation for the meta data custom attribute import code (code:IMetaDataImport).
10//
11//*****************************************************************************
12#include "stdafx.h"
13#include "regmeta.h"
14#include "metadata.h"
15#include "corerror.h"
16#include "mdutil.h"
17#include "rwutil.h"
18#include "mdlog.h"
19#include "importhelper.h"
20#include "mdperf.h"
21#include "posterror.h"
22#include "cahlprinternal.h"
23#include "custattr.h"
24#include "corhdr.h"
25#include <metamodelrw.h>
26
27//*****************************************************************************
28// Implementation of hash for custom attribute types.
29//*****************************************************************************
30unsigned int CCustAttrHash::Hash(const CCustAttrHashKey *pData)
31{
32 return static_cast<unsigned int>(pData->tkType);
33} // unsigned long CCustAttrHash::Hash()
34unsigned int CCustAttrHash::Compare(const CCustAttrHashKey *p1, CCustAttrHashKey *p2)
35{
36 if (p1->tkType == p2->tkType)
37 return 0;
38 return 1;
39} // unsigned long CCustAttrHash::Compare()
40CCustAttrHash::ELEMENTSTATUS CCustAttrHash::Status(CCustAttrHashKey *p)
41{
42 if (p->tkType == FREE)
43 return (FREE);
44 if (p->tkType == DELETED)
45 return (DELETED);
46 return (USED);
47} // CCustAttrHash::ELEMENTSTATUS CCustAttrHash::Status()
48void CCustAttrHash::SetStatus(CCustAttrHashKey *p, CCustAttrHash::ELEMENTSTATUS s)
49{
50 p->tkType = s;
51} // void CCustAttrHash::SetStatus()
52void* CCustAttrHash::GetKey(CCustAttrHashKey *p)
53{
54 return &p->tkType;
55} // void* CCustAttrHash::GetKey()
56
57
58//*****************************************************************************
59// Get the value of a CustomAttribute, using only TypeName for lookup.
60//*****************************************************************************
61STDMETHODIMP RegMeta::GetCustomAttributeByName( // S_OK or error.
62 mdToken tkObj, // [IN] Object with Custom Attribute.
63 LPCWSTR wzName, // [IN] Name of desired Custom Attribute.
64 const void **ppData, // [OUT] Put pointer to data here.
65 ULONG *pcbData) // [OUT] Put size of data here.
66{
67 HRESULT hr; // A result.
68
69 BEGIN_ENTRYPOINT_NOTHROW;
70
71 LPUTF8 szName; // Name in UFT8.
72 int iLen; // A length.
73 CMiniMdRW *pMiniMd = NULL;
74
75 START_MD_PERF();
76 LOCKREAD();
77 pMiniMd = &(m_pStgdb->m_MiniMd);
78
79 iLen = WszWideCharToMultiByte(CP_UTF8,0, wzName,-1, NULL,0, 0,0);
80 szName = (LPUTF8)_alloca(iLen);
81 VERIFY(WszWideCharToMultiByte(CP_UTF8,0, wzName,-1, szName,iLen, 0,0));
82
83 hr = ImportHelper::GetCustomAttributeByName(pMiniMd, tkObj, szName, ppData, pcbData);
84
85ErrExit:
86
87 STOP_MD_PERF(GetCustomAttributeByName);
88 END_ENTRYPOINT_NOTHROW;
89
90 return hr;
91} // STDMETHODIMP RegMeta::GetCustomAttributeByName()
92
93
94//*****************************************************************************
95// Enumerate the CustomAttributes for a given token.
96//*****************************************************************************
97STDMETHODIMP RegMeta::EnumCustomAttributes(
98 HCORENUM *phEnum, // Pointer to the enum.
99 mdToken tk, // Token to scope the enumeration.
100 mdToken tkType, // Type to limit the enumeration.
101 mdCustomAttribute rCustomAttributes[], // Put CustomAttributes here.
102 ULONG cMax, // Max CustomAttributes to put.
103 ULONG *pcCustomAttributes) // Put # tokens returned here.
104{
105 HRESULT hr = S_OK;
106
107 BEGIN_ENTRYPOINT_NOTHROW;
108
109 HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
110 ULONG ridStart;
111 ULONG ridEnd;
112 HENUMInternal *pEnum = *ppmdEnum;
113 CustomAttributeRec *pRec;
114 ULONG index;
115
116 LOG((LOGMD, "RegMeta::EnumCustomAttributes(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
117 phEnum, tk, tkType, rCustomAttributes, cMax, pcCustomAttributes));
118 START_MD_PERF();
119 LOCKREAD();
120
121 if ( pEnum == 0 )
122 {
123 // instantiating a new ENUM
124 CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
125 CLookUpHash *pHashTable = pMiniMd->m_pLookUpHashs[TBL_CustomAttribute];
126
127 // Does caller want all custom Values?
128 if (IsNilToken(tk))
129 {
130 IfFailGo( HENUMInternal::CreateSimpleEnum(mdtCustomAttribute, 1, pMiniMd->getCountCustomAttributes()+1, &pEnum) );
131 }
132 else
133 { // Scope by some object.
134 if ( pMiniMd->IsSorted( TBL_CustomAttribute ) )
135 {
136 // Get CustomAttributes for the object.
137 IfFailGo(pMiniMd->getCustomAttributeForToken(tk, &ridEnd, &ridStart));
138
139 if (IsNilToken(tkType))
140 {
141 // Simple enumerator for object's entire list.
142 IfFailGo( HENUMInternal::CreateSimpleEnum( mdtCustomAttribute, ridStart, ridEnd, &pEnum) );
143 }
144 else
145 {
146 // Dynamic enumerator for subsetted list.
147
148 IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtCustomAttribute, &pEnum) );
149
150 for (index = ridStart; index < ridEnd; index ++ )
151 {
152 IfFailGo(pMiniMd->GetCustomAttributeRecord(index, &pRec));
153 if (tkType == pMiniMd->getTypeOfCustomAttribute(pRec))
154 {
155 IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtCustomAttribute) ) );
156 }
157 }
158 }
159 }
160 else
161 {
162
163 if (pHashTable)
164 {
165 // table is not sorted but hash is built
166 // We want to create dynmaic array to hold the dynamic enumerator.
167 TOKENHASHENTRY *p;
168 ULONG iHash;
169 int pos;
170 mdToken tkParentTmp;
171 mdToken tkTypeTmp;
172
173 // Hash the data.
174 iHash = pMiniMd->HashCustomAttribute(tk);
175
176 IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtCustomAttribute, &pEnum) );
177
178 // Go through every entry in the hash chain looking for ours.
179 for (p = pHashTable->FindFirst(iHash, pos);
180 p;
181 p = pHashTable->FindNext(pos))
182 {
183
184 CustomAttributeRec *pCustomAttribute;
185 IfFailGo(pMiniMd->GetCustomAttributeRecord(RidFromToken(p->tok), &pCustomAttribute));
186 tkParentTmp = pMiniMd->getParentOfCustomAttribute(pCustomAttribute);
187 tkTypeTmp = pMiniMd->getTypeOfCustomAttribute(pCustomAttribute);
188 if (tkParentTmp == tk)
189 {
190 if (IsNilToken(tkType) || tkType == tkTypeTmp)
191 {
192 // compare the blob value
193 IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(p->tok, mdtCustomAttribute )) );
194 }
195 }
196 }
197 }
198 else
199 {
200
201 // table is not sorted and hash is not built so we have to create dynmaic array
202 // create the dynamic enumerator and loop through CA table linearly
203 //
204 ridStart = 1;
205 ridEnd = pMiniMd->getCountCustomAttributes() + 1;
206
207 IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtCustomAttribute, &pEnum) );
208
209 for (index = ridStart; index < ridEnd; index ++ )
210 {
211 IfFailGo(pMiniMd->GetCustomAttributeRecord(index, &pRec));
212 if ( tk == pMiniMd->getParentOfCustomAttribute(pRec) &&
213 (tkType == pMiniMd->getTypeOfCustomAttribute(pRec) || IsNilToken(tkType)))
214 {
215 IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtCustomAttribute) ) );
216 }
217 }
218 }
219 }
220 }
221
222 // set the output parameter
223 *ppmdEnum = pEnum;
224 }
225
226 // fill the output token buffer
227 hr = HENUMInternal::EnumWithCount(pEnum, cMax, rCustomAttributes, pcCustomAttributes);
228
229ErrExit:
230 HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
231
232 STOP_MD_PERF(EnumCustomAttributes);
233 END_ENTRYPOINT_NOTHROW;
234
235 return hr;
236} // STDMETHODIMP RegMeta::EnumCustomAttributes()
237
238
239//*****************************************************************************
240// Get information about a CustomAttribute.
241//*****************************************************************************
242STDMETHODIMP RegMeta::GetCustomAttributeProps(
243 mdCustomAttribute cv, // The attribute token
244 mdToken *ptkObj, // [OUT, OPTIONAL] Put object token here.
245 mdToken *ptkType, // [OUT, OPTIONAL] Put TypeDef/TypeRef token here.
246 void const **ppBlob, // [OUT, OPTIONAL] Put pointer to data here.
247 ULONG *pcbSize) // [OUT, OPTIONAL] Put size of data here.
248{
249 HRESULT hr = S_OK; // A result.
250
251 BEGIN_ENTRYPOINT_NOTHROW;
252
253 CMiniMdRW *pMiniMd;
254
255 START_MD_PERF();
256 LOCKREAD();
257
258 _ASSERTE(TypeFromToken(cv) == mdtCustomAttribute);
259
260 pMiniMd = &(m_pStgdb->m_MiniMd);
261 CustomAttributeRec *pCustomAttributeRec; // The custom value record.
262
263 IfFailGo(pMiniMd->GetCustomAttributeRecord(RidFromToken(cv), &pCustomAttributeRec));
264
265 if (ptkObj)
266 *ptkObj = pMiniMd->getParentOfCustomAttribute(pCustomAttributeRec);
267
268 if (ptkType)
269 *ptkType = pMiniMd->getTypeOfCustomAttribute(pCustomAttributeRec);
270
271 if (ppBlob != NULL)
272 {
273 IfFailGo(pMiniMd->getValueOfCustomAttribute(pCustomAttributeRec, (const BYTE **)ppBlob, pcbSize));
274 }
275
276ErrExit:
277
278 STOP_MD_PERF(GetCustomAttributeProps);
279 END_ENTRYPOINT_NOTHROW;
280
281 return hr;
282} // RegMeta::GetCustomAttributeProps
283