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//*****************************************************************************
25STDMETHODIMP 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
90ErrExit:
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//*****************************************************************************
113HRESULT 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
125ErrExit:
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//*****************************************************************************
135HRESULT
136RegMeta::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
148ErrExit:
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//*******************************************************************************
163HRESULT 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
172ErrExit:
173 return hr;
174} // RegMeta::DefineMethodSemantics
175
176//*******************************************************************************
177// helper to set field layout
178//
179// Implements internal API code:IMetaDataEmitHelper::SetFieldLayoutHelper.
180//*******************************************************************************
181HRESULT 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
209ErrExit:
210
211 return hr;
212} // RegMeta::SetFieldLayout
213
214//*******************************************************************************
215// helper to define event
216//
217// Implements internal API code:IMetaDataEmitHelper::DefineEventHelper.
218//*******************************************************************************
219STDMETHODIMP 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
236ErrExit:
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//*******************************************************************************
246STDMETHODIMP 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
320ErrExit:
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//*******************************************************************************
331HRESULT 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
343ErrExit:
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//*******************************************************************************
353HRESULT 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
369ErrExit:
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//*****************************************************************************
382STDMETHODIMP
383RegMeta::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//*******************************************************************************
414HRESULT 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//*******************************************************************************
425HRESULT
426RegMeta::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
441ErrExit:
442 return hr;
443} // RegMeta::SetMDUpdateMode
444
445#endif //FEATURE_METADATA_INTERNAL_APIS
446