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 | // Helper.cpp |
6 | // |
7 | |
8 | // |
9 | // Implementation of some internal APIs from code:IMetaDataHelper and code:IMetaDataEmitHelper. |
10 | // |
11 | //***************************************************************************** |
12 | #include "stdafx.h" |
13 | #include "regmeta.h" |
14 | #include "importhelper.h" |
15 | #include "mdlog.h" |
16 | |
17 | #if defined(FEATURE_METADATA_EMIT) || defined(FEATURE_METADATA_INTERNAL_APIS) |
18 | |
19 | //***************************************************************************** |
20 | // translating signature from one scope to another scope |
21 | // |
22 | // Implements public API code:IMetaDataEmit::TranslateSigWithScope. |
23 | // Implements internal API code:IMetaDataHelper::TranslateSigWithScope. |
24 | //***************************************************************************** |
25 | STDMETHODIMP RegMeta::TranslateSigWithScope( // S_OK or error. |
26 | IMetaDataAssemblyImport *pAssemImport, // [IN] importing assembly interface |
27 | const void *pbHashValue, // [IN] Hash Blob for Assembly. |
28 | ULONG cbHashValue, // [IN] Count of bytes. |
29 | IMetaDataImport *pImport, // [IN] importing interface |
30 | PCCOR_SIGNATURE pbSigBlob, // [IN] signature in the importing scope |
31 | ULONG cbSigBlob, // [IN] count of bytes of signature |
32 | IMetaDataAssemblyEmit *pAssemEmit,// [IN] emit assembly interface |
33 | IMetaDataEmit *pEmit, // [IN] emit interface |
34 | PCOR_SIGNATURE pvTranslatedSig, // [OUT] buffer to hold translated signature |
35 | ULONG cbTranslatedSigMax, |
36 | ULONG *pcbTranslatedSig) // [OUT] count of bytes in the translated signature |
37 | { |
38 | #ifdef FEATURE_METADATA_EMIT |
39 | HRESULT hr = S_OK; |
40 | |
41 | IMDCommon *pAssemImportMDCommon = NULL; |
42 | IMDCommon *pImportMDCommon = NULL; |
43 | |
44 | BEGIN_ENTRYPOINT_NOTHROW; |
45 | |
46 | RegMeta *pRegMetaAssemEmit = static_cast<RegMeta*>(pAssemEmit); |
47 | RegMeta *pRegMetaEmit = NULL; |
48 | |
49 | CQuickBytes qkSigEmit; |
50 | ULONG cbEmit; |
51 | |
52 | pRegMetaEmit = static_cast<RegMeta*>(pEmit); |
53 | |
54 | { |
55 | // This function can cause new TypeRef being introduced. |
56 | LOCKWRITE(); |
57 | |
58 | IfFailGo(m_pStgdb->m_MiniMd.PreUpdate()); |
59 | |
60 | _ASSERTE(pvTranslatedSig && pcbTranslatedSig); |
61 | |
62 | if (pAssemImport) |
63 | { |
64 | IfFailGo(pAssemImport->QueryInterface(IID_IMDCommon, (void**)&pAssemImportMDCommon)); |
65 | } |
66 | IMetaModelCommon *pAssemImportMetaModelCommon = pAssemImportMDCommon ? pAssemImportMDCommon->GetMetaModelCommon() : 0; |
67 | |
68 | IfFailGo(pImport->QueryInterface(IID_IMDCommon, (void**)&pImportMDCommon)); |
69 | IMetaModelCommon *pImportMetaModelCommon = pImportMDCommon->GetMetaModelCommon(); |
70 | |
71 | IfFailGo( ImportHelper::MergeUpdateTokenInSig( // S_OK or error. |
72 | pRegMetaAssemEmit ? &(pRegMetaAssemEmit->m_pStgdb->m_MiniMd) : 0, // The assembly emit scope. |
73 | &(pRegMetaEmit->m_pStgdb->m_MiniMd), // The emit scope. |
74 | pAssemImportMetaModelCommon, // Assembly where the signature is from. |
75 | pbHashValue, // Hash value for the import assembly. |
76 | cbHashValue, // Size in bytes. |
77 | pImportMetaModelCommon, // The scope where signature is from. |
78 | pbSigBlob, // signature from the imported scope |
79 | NULL, // Internal OID mapping structure. |
80 | &qkSigEmit, // [OUT] translated signature |
81 | 0, // start from first byte of the signature |
82 | 0, // don't care how many bytes consumed |
83 | &cbEmit)); // [OUT] total number of bytes write to pqkSigEmit |
84 | memcpy(pvTranslatedSig, qkSigEmit.Ptr(), cbEmit > cbTranslatedSigMax ? cbTranslatedSigMax :cbEmit ); |
85 | *pcbTranslatedSig = cbEmit; |
86 | if (cbEmit > cbTranslatedSigMax) |
87 | hr = CLDB_S_TRUNCATION; |
88 | } |
89 | |
90 | ErrExit: |
91 | END_ENTRYPOINT_NOTHROW; |
92 | |
93 | if (pAssemImportMDCommon) |
94 | pAssemImportMDCommon->Release(); |
95 | if (pImportMDCommon) |
96 | pImportMDCommon->Release(); |
97 | |
98 | return hr; |
99 | #else //!FEATURE_METADATA_EMIT |
100 | return E_NOTIMPL; |
101 | #endif //!FEATURE_METADATA_EMIT |
102 | } // RegMeta::TranslateSigWithScope |
103 | |
104 | #endif //FEATURE_METADATA_EMIT || FEATURE_METADATA_INTERNAL_APIS |
105 | |
106 | #if defined(FEATURE_METADATA_EMIT) && defined(FEATURE_METADATA_INTERNAL_APIS) |
107 | |
108 | //***************************************************************************** |
109 | // Helper : Set ResolutionScope of a TypeRef |
110 | // |
111 | // Implements internal API code:IMetaDataEmitHelper::SetResolutionScopeHelper. |
112 | //***************************************************************************** |
113 | HRESULT RegMeta::SetResolutionScopeHelper( // Return hresult. |
114 | mdTypeRef tr, // [IN] TypeRef record to update |
115 | mdToken rs) // [IN] new ResolutionScope |
116 | { |
117 | HRESULT hr = NOERROR; |
118 | TypeRefRec * pTypeRef; |
119 | |
120 | LOCKWRITE(); |
121 | |
122 | IfFailGo(m_pStgdb->m_MiniMd.GetTypeRefRecord(RidFromToken(tr), &pTypeRef)); |
123 | IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_TypeRef, TypeRefRec::COL_ResolutionScope, pTypeRef, rs)); |
124 | |
125 | ErrExit: |
126 | return hr; |
127 | } // RegMeta::SetResolutionScopeHelper |
128 | |
129 | |
130 | //***************************************************************************** |
131 | // Helper : Set offset of a ManifestResource |
132 | // |
133 | // Implements internal API code:IMetaDataEmitHelper::SetManifestResourceOffsetHelper. |
134 | //***************************************************************************** |
135 | HRESULT |
136 | RegMeta::SetManifestResourceOffsetHelper( |
137 | mdManifestResource mr, // [IN] The manifest token |
138 | ULONG ulOffset) // [IN] new offset |
139 | { |
140 | HRESULT hr = NOERROR; |
141 | ManifestResourceRec * pRec; |
142 | |
143 | LOCKWRITE(); |
144 | |
145 | IfFailGo(m_pStgdb->m_MiniMd.GetManifestResourceRecord(RidFromToken(mr), &pRec)); |
146 | pRec->SetOffset(ulOffset); |
147 | |
148 | ErrExit: |
149 | return hr; |
150 | } // RegMeta::SetManifestResourceOffsetHelper |
151 | |
152 | //******************************************************************************* |
153 | // |
154 | // Following APIs are used by reflection emit. |
155 | // |
156 | //******************************************************************************* |
157 | |
158 | //******************************************************************************* |
159 | // helper to define method semantics |
160 | // |
161 | // Implements internal API code:IMetaDataEmitHelper::DefineMethodSemanticsHelper. |
162 | //******************************************************************************* |
163 | HRESULT RegMeta::DefineMethodSemanticsHelper( |
164 | mdToken tkAssociation, // [IN] property or event token |
165 | DWORD dwFlags, // [IN] semantics |
166 | mdMethodDef md) // [IN] method to associated with |
167 | { |
168 | HRESULT hr; |
169 | LOCKWRITE(); |
170 | hr = _DefineMethodSemantics((USHORT) dwFlags, md, tkAssociation, false); |
171 | |
172 | ErrExit: |
173 | return hr; |
174 | } // RegMeta::DefineMethodSemantics |
175 | |
176 | //******************************************************************************* |
177 | // helper to set field layout |
178 | // |
179 | // Implements internal API code:IMetaDataEmitHelper::SetFieldLayoutHelper. |
180 | //******************************************************************************* |
181 | HRESULT RegMeta::SetFieldLayoutHelper( // Return hresult. |
182 | mdFieldDef fd, // [IN] field to associate the layout info |
183 | ULONG ulOffset) // [IN] the offset for the field |
184 | { |
185 | HRESULT hr; |
186 | FieldLayoutRec *pFieldLayoutRec; |
187 | RID iFieldLayoutRec; |
188 | |
189 | LOCKWRITE(); |
190 | |
191 | if (ulOffset == ULONG_MAX) |
192 | { |
193 | // invalid argument |
194 | IfFailGo( E_INVALIDARG ); |
195 | } |
196 | |
197 | // create a field layout record |
198 | IfFailGo(m_pStgdb->m_MiniMd.AddFieldLayoutRecord(&pFieldLayoutRec, &iFieldLayoutRec)); |
199 | |
200 | // Set the Field entry. |
201 | IfFailGo(m_pStgdb->m_MiniMd.PutToken( |
202 | TBL_FieldLayout, |
203 | FieldLayoutRec::COL_Field, |
204 | pFieldLayoutRec, |
205 | fd)); |
206 | pFieldLayoutRec->SetOffSet(ulOffset); |
207 | IfFailGo( m_pStgdb->m_MiniMd.AddFieldLayoutToHash(iFieldLayoutRec) ); |
208 | |
209 | ErrExit: |
210 | |
211 | return hr; |
212 | } // RegMeta::SetFieldLayout |
213 | |
214 | //******************************************************************************* |
215 | // helper to define event |
216 | // |
217 | // Implements internal API code:IMetaDataEmitHelper::DefineEventHelper. |
218 | //******************************************************************************* |
219 | STDMETHODIMP RegMeta::DefineEventHelper( // Return hresult. |
220 | mdTypeDef td, // [IN] the class/interface on which the event is being defined |
221 | LPCWSTR szEvent, // [IN] Name of the event |
222 | DWORD dwEventFlags, // [IN] CorEventAttr |
223 | mdToken tkEventType, // [IN] a reference (mdTypeRef or mdTypeRef) to the Event class |
224 | mdEvent *pmdEvent) // [OUT] output event token |
225 | { |
226 | HRESULT hr = S_OK; |
227 | LOG((LOGMD, "MD RegMeta::DefineEventHelper(0x%08x, %S, 0x%08x, 0x%08x, 0x%08x)\n" , |
228 | td, szEvent, dwEventFlags, tkEventType, pmdEvent)); |
229 | |
230 | LOCKWRITE(); |
231 | |
232 | IfFailGo(m_pStgdb->m_MiniMd.PreUpdate()); |
233 | |
234 | hr = _DefineEvent(td, szEvent, dwEventFlags, tkEventType, pmdEvent); |
235 | |
236 | ErrExit: |
237 | return hr; |
238 | } // RegMeta::DefineEvent |
239 | |
240 | |
241 | //******************************************************************************* |
242 | // helper to add a declarative security blob to a class or method |
243 | // |
244 | // Implements internal API code:IMetaDataEmitHelper::AddDeclarativeSecurityHelper. |
245 | //******************************************************************************* |
246 | STDMETHODIMP RegMeta::AddDeclarativeSecurityHelper( |
247 | mdToken tk, // [IN] Parent token (typedef/methoddef) |
248 | DWORD dwAction, // [IN] Security action (CorDeclSecurity) |
249 | void const *pValue, // [IN] Permission set blob |
250 | DWORD cbValue, // [IN] Byte count of permission set blob |
251 | mdPermission*pmdPermission) // [OUT] Output permission token |
252 | { |
253 | HRESULT hr = S_OK; |
254 | DeclSecurityRec *pDeclSec = NULL; |
255 | RID iDeclSec; |
256 | short sAction = static_cast<short>(dwAction); |
257 | mdPermission tkPerm; |
258 | |
259 | LOG((LOGMD, "MD RegMeta::AddDeclarativeSecurityHelper(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n" , |
260 | tk, dwAction, pValue, cbValue, pmdPermission)); |
261 | |
262 | LOCKWRITE(); |
263 | IfFailGo(m_pStgdb->m_MiniMd.PreUpdate()); |
264 | |
265 | _ASSERTE(TypeFromToken(tk) == mdtTypeDef || TypeFromToken(tk) == mdtMethodDef || TypeFromToken(tk) == mdtAssembly); |
266 | |
267 | // Check for valid Action. |
268 | if (sAction == 0 || sAction > dclMaximumValue) |
269 | IfFailGo(E_INVALIDARG); |
270 | |
271 | if (CheckDups(MDDupPermission)) |
272 | { |
273 | hr = ImportHelper::FindPermission(&(m_pStgdb->m_MiniMd), tk, sAction, &tkPerm); |
274 | |
275 | if (SUCCEEDED(hr)) |
276 | { |
277 | // Set output parameter. |
278 | if (pmdPermission) |
279 | *pmdPermission = tkPerm; |
280 | if (IsENCOn()) |
281 | IfFailGo(m_pStgdb->m_MiniMd.GetDeclSecurityRecord(RidFromToken(tkPerm), &pDeclSec)); |
282 | else |
283 | { |
284 | hr = META_S_DUPLICATE; |
285 | goto ErrExit; |
286 | } |
287 | } |
288 | else if (hr != CLDB_E_RECORD_NOTFOUND) |
289 | IfFailGo(hr); |
290 | } |
291 | |
292 | // Create a new record. |
293 | if (!pDeclSec) |
294 | { |
295 | IfFailGo(m_pStgdb->m_MiniMd.AddDeclSecurityRecord(&pDeclSec, &iDeclSec)); |
296 | tkPerm = TokenFromRid(iDeclSec, mdtPermission); |
297 | |
298 | // Set output parameter. |
299 | if (pmdPermission) |
300 | *pmdPermission = tkPerm; |
301 | |
302 | // Save parent and action information. |
303 | IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_DeclSecurity, DeclSecurityRec::COL_Parent, pDeclSec, tk)); |
304 | pDeclSec->SetAction(sAction); |
305 | |
306 | // Turn on the internal security flag on the parent. |
307 | if (TypeFromToken(tk) == mdtTypeDef) |
308 | IfFailGo(_TurnInternalFlagsOn(tk, tdHasSecurity)); |
309 | else if (TypeFromToken(tk) == mdtMethodDef) |
310 | IfFailGo(_TurnInternalFlagsOn(tk, mdHasSecurity)); |
311 | IfFailGo(UpdateENCLog(tk)); |
312 | } |
313 | |
314 | // Write the blob into the record. |
315 | IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_DeclSecurity, DeclSecurityRec::COL_PermissionSet, |
316 | pDeclSec, pValue, cbValue)); |
317 | |
318 | IfFailGo(UpdateENCLog(tkPerm)); |
319 | |
320 | ErrExit: |
321 | |
322 | return hr; |
323 | } // RegMeta::AddDeclarativeSecurityHelper |
324 | |
325 | |
326 | //******************************************************************************* |
327 | // helper to set type's extends column |
328 | // |
329 | // Implements internal API code:IMetaDataEmitHelper::SetTypeParent. |
330 | //******************************************************************************* |
331 | HRESULT RegMeta::SetTypeParent( // Return hresult. |
332 | mdTypeDef td, // [IN] Type definition |
333 | mdToken tkExtends) // [IN] parent type |
334 | { |
335 | HRESULT hr; |
336 | TypeDefRec *pRec; |
337 | |
338 | LOCKWRITE(); |
339 | |
340 | IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(td), &pRec)); |
341 | IfFailGo( m_pStgdb->m_MiniMd.PutToken(TBL_TypeDef, TypeDefRec::COL_Extends, pRec, tkExtends) ); |
342 | |
343 | ErrExit: |
344 | return hr; |
345 | } // RegMeta::SetTypeParent |
346 | |
347 | |
348 | //******************************************************************************* |
349 | // helper to set type's extends column |
350 | // |
351 | // Implements internal API code:IMetaDataEmitHelper::AddInterfaceImpl. |
352 | //******************************************************************************* |
353 | HRESULT RegMeta::AddInterfaceImpl( // Return hresult. |
354 | mdTypeDef td, // [IN] Type definition |
355 | mdToken tkInterface) // [IN] interface type |
356 | { |
357 | HRESULT hr; |
358 | InterfaceImplRec *pRec; |
359 | RID ii; |
360 | |
361 | LOCKWRITE(); |
362 | hr = ImportHelper::FindInterfaceImpl(&(m_pStgdb->m_MiniMd), td, tkInterface, (mdInterfaceImpl *)&ii); |
363 | if (hr == S_OK) |
364 | goto ErrExit; |
365 | IfFailGo(m_pStgdb->m_MiniMd.AddInterfaceImplRecord(&pRec, &ii)); |
366 | IfFailGo(m_pStgdb->m_MiniMd.PutToken( TBL_InterfaceImpl, InterfaceImplRec::COL_Class, pRec, td)); |
367 | IfFailGo(m_pStgdb->m_MiniMd.PutToken( TBL_InterfaceImpl, InterfaceImplRec::COL_Interface, pRec, tkInterface)); |
368 | |
369 | ErrExit: |
370 | return hr; |
371 | } // RegMeta::AddInterfaceImpl |
372 | |
373 | #endif //FEATURE_METADATA_EMIT && FEATURE_METADATA_INTERNAL_APIS |
374 | |
375 | #ifdef FEATURE_METADATA_INTERNAL_APIS |
376 | |
377 | //***************************************************************************** |
378 | // Helper : get metadata information |
379 | // |
380 | // Implements internal API code:IMetaDataHelper::GetMetadata. |
381 | //***************************************************************************** |
382 | STDMETHODIMP |
383 | RegMeta::GetMetadata( |
384 | ULONG ulSelect, // [IN] Selector. |
385 | void ** ppData) // [OUT] Put pointer to data here. |
386 | { |
387 | |
388 | REGMETA_POSSIBLE_INTERNAL_POINTER_EXPOSED(); |
389 | |
390 | switch (ulSelect) |
391 | { |
392 | case 0: |
393 | *ppData = &m_pStgdb->m_MiniMd; |
394 | break; |
395 | case 1: |
396 | *ppData = (void*)g_CodedTokens; |
397 | break; |
398 | case 2: |
399 | *ppData = (void*)g_Tables; |
400 | break; |
401 | default: |
402 | *ppData = 0; |
403 | break; |
404 | } |
405 | |
406 | return S_OK; |
407 | } // RegMeta::GetMetadata |
408 | |
409 | //******************************************************************************* |
410 | // helper to change MVID |
411 | // |
412 | // Implements internal API code:IMDInternalEmit::ChangeMvid. |
413 | //******************************************************************************* |
414 | HRESULT RegMeta::ChangeMvid( // S_OK or error. |
415 | REFGUID newMvid) // GUID to use as the MVID |
416 | { |
417 | return GetMiniMd()->ChangeMvid(newMvid); |
418 | } |
419 | |
420 | //******************************************************************************* |
421 | // Helper to change MDUpdateMode value to updateMode. |
422 | // |
423 | // Implements internal API code:IMDInternalEmit::SetMDUpdateMode. |
424 | //******************************************************************************* |
425 | HRESULT |
426 | RegMeta::SetMDUpdateMode( |
427 | ULONG updateMode, |
428 | ULONG * pPreviousUpdateMode) |
429 | { |
430 | HRESULT hr; |
431 | |
432 | OptionValue optionValue; |
433 | IfFailGo(m_pStgdb->m_MiniMd.GetOption(&optionValue)); |
434 | if (pPreviousUpdateMode != NULL) |
435 | { |
436 | *pPreviousUpdateMode = optionValue.m_UpdateMode; |
437 | } |
438 | optionValue.m_UpdateMode = updateMode; |
439 | IfFailGo(m_pStgdb->m_MiniMd.SetOption(&optionValue)); |
440 | |
441 | ErrExit: |
442 | return hr; |
443 | } // RegMeta::SetMDUpdateMode |
444 | |
445 | #endif //FEATURE_METADATA_INTERNAL_APIS |
446 | |