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// ImportHelper.cpp
6//
7
8//
9// contains utility code to MD directory
10//
11//*****************************************************************************
12#include "stdafx.h"
13#include "importhelper.h"
14#include "mdutil.h"
15#include "rwutil.h"
16#include "mdlog.h"
17#include "strongname.h"
18#include "sstring.h"
19
20#define COM_RUNTIME_LIBRARY "ComRuntimeLibrary"
21
22
23//*******************************************************************************
24// Find the MethodSpec by Method and Instantiation
25//*******************************************************************************
26//@GENERICS: todo: look in hashtable (cf. MetaModelRW.cpp) if necessary
27HRESULT ImportHelper::FindMethodSpecByMethodAndInstantiation(
28 CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
29 /*mdMethodDefOrRef*/ mdToken tkMethod, // [IN] MethodSpec method field
30 PCCOR_SIGNATURE pInstantiation, // [IN] MethodSpec instantiation (a signature)
31 ULONG cbInstantiation, // [IN] Size of instantiation.
32 mdMethodSpec *pMethodSpec, // [OUT] Put the MethodSpec token here.
33 RID rid /* = 0*/) // [IN] Optional rid to be ignored.
34{
35 HRESULT hr;
36 MethodSpecRec *pRecord;
37 /*mdMethodDefOrRef*/ mdToken tkMethodTmp;
38 PCCOR_SIGNATURE pInstantiationTmp;
39 ULONG cbInstantiationTmp;
40 ULONG cMethodSpecs;
41 ULONG i;
42
43 _ASSERTE(pMethodSpec);
44
45 cMethodSpecs = pMiniMd->getCountMethodSpecs();
46
47 // linear scan through the MethodSpec table
48 for (i=1; i <= cMethodSpecs; ++i)
49 {
50 // For the call from Validator ignore the rid passed in.
51 if (i == rid)
52 continue;
53
54 IfFailRet(pMiniMd->GetMethodSpecRecord(i, &pRecord));
55
56 tkMethodTmp = pMiniMd->getMethodOfMethodSpec(pRecord);
57 if ((tkMethodTmp != tkMethod))
58 continue;
59
60 //@GENERICS: not sure what is meant by duplicate here: identical sig pointers or sig pointer contents?
61 IfFailRet(pMiniMd->getInstantiationOfMethodSpec(pRecord, &pInstantiationTmp, &cbInstantiationTmp));
62 if (cbInstantiationTmp != cbInstantiation || memcmp(pInstantiation, pInstantiationTmp, cbInstantiation))
63 continue;
64
65 // Matching record found.
66 *pMethodSpec = TokenFromRid(i, mdtMethodSpec);
67 return S_OK;
68 }
69 return CLDB_E_RECORD_NOTFOUND;
70} // HRESULT ImportHelper::FindMethodSpecByMethodAndInstantiation()
71
72
73//*******************************************************************************
74// Find the GenericParam by owner and constraint
75//*******************************************************************************
76//@GENERICS: todo: look in hashtable (cf. MetaModelRW.cpp) if necessary
77HRESULT ImportHelper::FindGenericParamConstraintByOwnerAndConstraint(
78 CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
79 mdGenericParam tkOwner, // [IN] GenericParamConstraint Owner
80 mdToken tkConstraint, // [IN] GenericParamConstraint Constraint
81 mdGenericParamConstraint *pGenericParamConstraint,// [OUT] Put the GenericParam token here.
82 RID rid /* = 0*/) // [IN] Optional rid to be ignored.
83{
84 HRESULT hr;
85 GenericParamConstraintRec *pRecord;
86 mdGenericParam tkOwnerTmp;
87 mdToken tkConstraintTmp;
88 ULONG cGenericParamConstraints;
89
90 ULONG i;
91
92 _ASSERTE(pGenericParamConstraint);
93
94 cGenericParamConstraints = pMiniMd->getCountGenericParamConstraints();
95
96 // linear scan through the GenericParam table
97 for (i=1; i <= cGenericParamConstraints; ++i)
98 {
99 // For the call from Validator ignore the rid passed in.
100 if (i == rid)
101 continue;
102
103 IfFailRet(pMiniMd->GetGenericParamConstraintRecord(i, &pRecord));
104
105 tkOwnerTmp = pMiniMd->getOwnerOfGenericParamConstraint(pRecord);
106 tkConstraintTmp = pMiniMd->getConstraintOfGenericParamConstraint(pRecord);
107
108 if ((tkOwnerTmp != tkOwner) || (tkConstraintTmp != tkConstraint))
109 continue;
110
111 // Matching record found.
112 *pGenericParamConstraint = TokenFromRid(i, mdtGenericParamConstraint);
113 return S_OK;
114 }
115 return CLDB_E_RECORD_NOTFOUND;
116} // HRESULT ImportHelper::FindGenericParamConstraintByOwnerAndConstraint()
117
118//*******************************************************************************
119// Find the GenericParam by owner and name or number
120//*******************************************************************************
121//<REVISIT_TODO> @GENERICS: todo: look in hashtable (cf. MetaModelRW.cpp) if necessary </REVISIT_TODO>
122HRESULT ImportHelper::FindGenericParamByOwner(
123 CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
124 mdToken tkOwner, // [IN] GenericParam Owner
125 LPCUTF8 szUTF8Name, // [IN] GeneriParam Name, may be NULL if not used for search
126 ULONG *pNumber, // [IN] GeneriParam Number, may be NULL if not used for search
127 mdGenericParam *pGenericParam, // [OUT] Put the GenericParam token here.
128 RID rid /* = 0*/) // [IN] Optional rid to be ignored.
129{
130 HRESULT hr;
131 GenericParamRec *pRecord;
132 mdToken tkOwnerTmp;
133 ULONG cGenericParams;
134 LPCUTF8 szCurName;
135 ULONG curNumber;
136 ULONG i;
137
138 _ASSERTE(pGenericParam);
139
140 cGenericParams = pMiniMd->getCountGenericParams();
141
142 // linear scan through the GenericParam table
143 for (i=1; i <= cGenericParams; ++i)
144 {
145 // For the call from Validator ignore the rid passed in.
146 if (i == rid)
147 continue;
148
149 IfFailRet(pMiniMd->GetGenericParamRecord(i, &pRecord));
150
151 tkOwnerTmp = pMiniMd->getOwnerOfGenericParam(pRecord);
152 if ( tkOwnerTmp != tkOwner)
153 continue;
154
155 // if the name is significant, try to match it
156 if (szUTF8Name)
157 {
158 IfFailRet(pMiniMd->getNameOfGenericParam(pRecord, &szCurName));
159 if (strcmp(szCurName, szUTF8Name))
160 continue;
161 }
162
163 // if the number is significant, try to match it
164 if (pNumber)
165 { curNumber = pMiniMd->getNumberOfGenericParam(pRecord);
166 if (*pNumber != curNumber)
167 continue;
168 }
169
170 // Matching record found.
171 *pGenericParam = TokenFromRid(i, mdtGenericParam);
172 return S_OK;
173 }
174 return CLDB_E_RECORD_NOTFOUND;
175} // HRESULT ImportHelper::FindGenericParamByOwner()
176
177//*******************************************************************************
178// Find a Method given a parent, name and signature.
179//*******************************************************************************
180HRESULT ImportHelper::FindMethod(
181 CMiniMdRW * pMiniMd, // [IN] the minimd to lookup
182 mdTypeDef td, // [IN] parent.
183 LPCUTF8 szName, // [IN] MethodDef name.
184 PCCOR_SIGNATURE pSig, // [IN] Signature.
185 ULONG cbSig, // [IN] Size of signature.
186 mdMethodDef * pmb, // [OUT] Put the MethodDef token here.
187 RID rid, // = 0 // [IN] Optional rid to be ignored.
188 PSIGCOMPARE pSignatureCompare, // = NULL // [IN] Optional Routine to compare signatures
189 void * pCompareContext) // = NULL // [IN] Optional context for the compare function
190{
191 HRESULT hr = S_OK;
192 ULONG ridStart; // Start of td's methods.
193 ULONG ridEnd; // End of td's methods.
194 ULONG index; // Loop control.
195 TypeDefRec *pRec; // A TypeDef Record.
196 MethodRec *pMethod; // A MethodDef Record.
197 LPCUTF8 szNameUtf8Tmp; // A found MethodDef's name.
198 PCCOR_SIGNATURE pSigTmp; // A found MethodDef's signature.
199 ULONG cbSigTmp; // Size of a found MethodDef's signature.
200 PCCOR_SIGNATURE pvSigTemp = pSig; // For use in parsing a signature.
201 CQuickBytes qbSig; // Struct to build a non-varargs signature.
202 CMiniMdRW::HashSearchResult rtn;
203
204 if (cbSig)
205 { // check to see if this is a vararg signature
206 if (isCallConv(CorSigUncompressCallingConv(pvSigTemp), IMAGE_CEE_CS_CALLCONV_VARARG))
207 { // Get the fix part of VARARG signature
208 IfFailGo(_GetFixedSigOfVarArg(pSig, cbSig, &qbSig, &cbSig));
209 pSig = (PCCOR_SIGNATURE) qbSig.Ptr();
210 }
211 }
212
213 *pmb = TokenFromRid(rid, mdtMethodDef); // to know what to ignore
214 rtn = pMiniMd->FindMemberDefFromHash(td, szName, pSig, cbSig, pmb);
215 if (rtn == CMiniMdRW::Found)
216 {
217 goto ErrExit;
218 }
219 else if (rtn == CMiniMdRW::NotFound)
220 {
221 IfFailGo(CLDB_E_RECORD_NOTFOUND);
222 }
223 _ASSERTE(rtn == CMiniMdRW::NoTable);
224
225 *pmb = mdMethodDefNil;
226
227 // get the range of method rids given a typedef
228 IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(td), &pRec));
229 ridStart = pMiniMd->getMethodListOfTypeDef(pRec);
230 IfFailGo(pMiniMd->getEndMethodListOfTypeDef(RidFromToken(td), &ridEnd));
231 // Iterate over the methods.
232 for (index = ridStart; index < ridEnd; index ++ )
233 {
234 RID methodRID;
235 IfFailGo(pMiniMd->GetMethodRid(index, &methodRID));
236 // For the call from Validator ignore the rid passed in.
237 if (methodRID != rid)
238 {
239 // Get the method and its name.
240 IfFailGo(pMiniMd->GetMethodRecord(methodRID, &pMethod));
241 IfFailGo(pMiniMd->getNameOfMethod(pMethod, &szNameUtf8Tmp));
242
243 // If name matches what was requested...
244 if ( strcmp(szNameUtf8Tmp, szName) == 0 )
245 {
246 if (cbSig && pSig)
247 {
248 IfFailGo(pMiniMd->getSignatureOfMethod(pMethod, &pSigTmp, &cbSigTmp));
249
250 // If the caller did not provide a custom compare routine
251 // then we use memcmp to match the signatures
252 //
253 if (pSignatureCompare == NULL)
254 {
255 if (cbSigTmp != cbSig || memcmp(pSig, pSigTmp, cbSig))
256 continue;
257 }
258 else
259 {
260 // Call the custom compare routine
261 //
262 if (!pSignatureCompare(pSigTmp, cbSigTmp, pSig, cbSig, pCompareContext))
263 continue;
264 }
265 }
266 // Ignore PrivateScope methods.
267 if (IsMdPrivateScope(pMiniMd->getFlagsOfMethod(pMethod)))
268 continue;
269
270 // Found method.
271 *pmb = TokenFromRid(methodRID, mdtMethodDef);
272 goto ErrExit;
273 }
274 }
275 }
276
277 // record not found
278 *pmb = mdMethodDefNil;
279 hr = CLDB_E_RECORD_NOTFOUND;
280
281ErrExit:
282 return hr;
283} // ImportHelper::FindMethod
284
285//*******************************************************************************
286// Find a Field given a parent, name and signature.
287//*******************************************************************************
288HRESULT ImportHelper::FindField(
289 CMiniMdRW * pMiniMd, // [IN] the minimd to lookup
290 mdTypeDef td, // [IN] parent.
291 LPCUTF8 szName, // [IN] FieldDef name.
292 PCCOR_SIGNATURE pSig, // [IN] Signature.
293 ULONG cbSig, // [IN] Size of signature.
294 mdFieldDef * pfd, // [OUT] Put the FieldDef token here.
295 RID rid) // = 0 // [IN] Optional rid to be ignored.
296{
297 HRESULT hr = S_OK; // A result.
298 ULONG ridStart; // Start of td's methods.
299 ULONG ridEnd; // End of td's methods.
300 ULONG index; // Loop control.
301 TypeDefRec *pRec; // A TypeDef Record.
302 FieldRec *pField; // A FieldDef Record.
303 LPCUTF8 szNameUtf8Tmp; // A found FieldDef's name.
304 PCCOR_SIGNATURE pSigTmp; // A found FieldDef's signature.
305 ULONG cbSigTmp; // Size of a found FieldDef's signature.
306 CMiniMdRW::HashSearchResult rtn;
307
308 *pfd = TokenFromRid(rid,mdtFieldDef); // to know what to ignore
309 rtn = pMiniMd->FindMemberDefFromHash(td, szName, pSig, cbSig, pfd);
310 if (rtn == CMiniMdRW::Found)
311 {
312 goto ErrExit;
313 }
314 else if (rtn == CMiniMdRW::NotFound)
315 {
316 IfFailGo(CLDB_E_RECORD_NOTFOUND);
317 }
318 _ASSERTE(rtn == CMiniMdRW::NoTable);
319
320 *pfd = mdFieldDefNil;
321
322 // get the range of method rids given a typedef
323 IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(td), &pRec));
324 ridStart = pMiniMd->getFieldListOfTypeDef(pRec);
325 IfFailGo(pMiniMd->getEndFieldListOfTypeDef(RidFromToken(td), &ridEnd));
326
327 // Iterate over the methods.
328 for (index = ridStart; index < ridEnd; index ++ )
329 {
330 RID fieldRID;
331 IfFailGo(pMiniMd->GetFieldRid(index, &fieldRID));
332 // For the call from Validator ignore the rid passed in.
333 if (fieldRID != rid)
334 {
335 // Get the field and its name.
336 IfFailGo(pMiniMd->GetFieldRecord(fieldRID, &pField));
337 IfFailGo(pMiniMd->getNameOfField(pField, &szNameUtf8Tmp));
338
339 // If name matches what was requested...
340 if ( strcmp(szNameUtf8Tmp, szName) == 0 )
341 {
342 // Check signature if specified.
343 if (cbSig && pSig)
344 {
345 IfFailGo(pMiniMd->getSignatureOfField(pField, &pSigTmp, &cbSigTmp));
346 if (cbSigTmp != cbSig || memcmp(pSig, pSigTmp, cbSig))
347 continue;
348 }
349 // Ignore PrivateScope fields.
350 if (IsFdPrivateScope(pMiniMd->getFlagsOfField(pField)))
351 continue;
352 // Field found.
353 *pfd = TokenFromRid(fieldRID, mdtFieldDef);
354 goto ErrExit;
355 }
356 }
357 }
358
359 // record not found
360 *pfd = mdFieldDefNil;
361 hr = CLDB_E_RECORD_NOTFOUND;
362
363ErrExit:
364 return hr;
365} // ImportHelper::FindField
366
367//*******************************************************************************
368// Find a Member given a parent, name and signature.
369//*******************************************************************************
370HRESULT ImportHelper::FindMember(
371 CMiniMdRW * pMiniMd, // [IN] the minimd to lookup
372 mdTypeDef td, // [IN] parent.
373 LPCUTF8 szName, // [IN] Member name.
374 PCCOR_SIGNATURE pSig, // [IN] Signature.
375 ULONG cbSig, // [IN] Size of signature.
376 mdToken * ptk) // [OUT] Put the token here.
377{
378 HRESULT hr;
379
380 if (cbSig == 0)
381 {
382 Debug_ReportError("Invalid signature size 0.");
383 return CLDB_E_INDEX_NOTFOUND;
384 }
385
386 // determine if it is ref to MethodDef or FieldDef
387 if ((pSig[0] & IMAGE_CEE_CS_CALLCONV_MASK) != IMAGE_CEE_CS_CALLCONV_FIELD)
388 {
389 hr = FindMethod(pMiniMd, td, szName, pSig, cbSig, ptk);
390 }
391 else
392 {
393 hr = FindField(pMiniMd, td, szName, pSig, cbSig, ptk);
394 }
395
396 if (hr == CLDB_E_RECORD_NOTFOUND)
397 *ptk = mdTokenNil;
398
399 return hr;
400} // ImportHelper::FindMember
401
402
403//*******************************************************************************
404// Find the memberref given name, sig, and parent
405//*******************************************************************************
406HRESULT ImportHelper::FindMemberRef(
407 CMiniMdRW * pMiniMd, // [IN] the minimd to lookup
408 mdToken tkParent, // [IN] the parent token
409 LPCUTF8 szName, // [IN] memberref name
410 const COR_SIGNATURE * pbSig, // [IN] Signature.
411 ULONG cbSig, // [IN] Size of signature.
412 mdMemberRef * pmr, // [OUT] Put the MemberRef token found
413 RID rid, // = 0 // [IN] Optional rid to be ignored.
414 HashSearchOption fCreateHash) // = DoNotCreateHash // [IN] Should we create hash first? (Optimize for multiple calls vs. single isolated call)
415{
416 ULONG cMemberRefRecs;
417 MemberRefRec * pMemberRefRec;
418 LPCUTF8 szNameTmp = 0;
419 const COR_SIGNATURE * pbSigTmp; // Signature.
420 ULONG cbSigTmp; // Size of signature.
421 mdToken tkParentTmp; // the parent token
422 HRESULT hr = NOERROR;
423 CMiniMdRW::HashSearchResult rtn;
424
425 if ((szName == NULL) || (pmr == NULL))
426 {
427 IfFailGo(CLDB_E_RECORD_NOTFOUND);
428 }
429
430 if (fCreateHash == CreateHash)
431 { // Caller asked for creating hash to optimize for multiple calls
432 IfFailGo(pMiniMd->CreateMemberRefHash());
433 }
434
435 *pmr = TokenFromRid(rid, mdtMemberRef); // to know what to ignore
436 rtn = pMiniMd->FindMemberRefFromHash(tkParent, szName, pbSig, cbSig, pmr);
437 if (rtn == CMiniMdRW::Found)
438 {
439 goto ErrExit;
440 }
441 else if (rtn == CMiniMdRW::NotFound)
442 {
443 IfFailGo(CLDB_E_RECORD_NOTFOUND);
444 }
445 _ASSERTE(rtn == CMiniMdRW::NoTable);
446
447 *pmr = mdMemberRefNil;
448
449 cMemberRefRecs = pMiniMd->getCountMemberRefs();
450
451 // Search for the MemberRef
452 for (ULONG i = 1; i <= cMemberRefRecs; i++)
453 {
454 // For the call from Validator ignore the rid passed in.
455 if (i == rid)
456 continue;
457
458 IfFailGo(pMiniMd->GetMemberRefRecord(i, &pMemberRefRec));
459 if (!IsNilToken(tkParent))
460 {
461 // given a valid parent
462 tkParentTmp = pMiniMd->getClassOfMemberRef(pMemberRefRec);
463 if (tkParentTmp != tkParent)
464 {
465 // if parent is specified and not equal to the current row,
466 // try the next row.
467 continue;
468 }
469 }
470 if ((szName != NULL) && (*szName != 0))
471 {
472 // name is specified
473 IfFailGo(pMiniMd->getNameOfMemberRef(pMemberRefRec, &szNameTmp));
474 if (strcmp(szName, szNameTmp) != 0)
475 {
476 // Name is not equal. Try next row.
477 continue;
478 }
479 }
480 if ((cbSig != 0) && (pbSig != NULL))
481 {
482 // signature is specifed
483 IfFailGo(pMiniMd->getSignatureOfMemberRef(pMemberRefRec, &pbSigTmp, &cbSigTmp));
484 if (cbSigTmp != cbSig)
485 continue;
486 if (memcmp( pbSig, pbSigTmp, cbSig ) != 0)
487 continue;
488 }
489
490 // we found a match
491 *pmr = TokenFromRid(i, mdtMemberRef);
492 return S_OK;
493 }
494 hr = CLDB_E_RECORD_NOTFOUND;
495ErrExit:
496 return hr;
497} // ImportHelper::FindMemberRef
498
499
500
501//*******************************************************************************
502// Find duplicate StandAloneSig
503//*******************************************************************************
504HRESULT ImportHelper::FindStandAloneSig(
505 CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
506 const COR_SIGNATURE *pbSig, // [IN] Signature.
507 ULONG cbSig, // [IN] Size of signature.
508 mdSignature *psa) // [OUT] Put the StandAloneSig token found
509{
510 HRESULT hr;
511 ULONG cRecs;
512 StandAloneSigRec *pRec;
513 const COR_SIGNATURE *pbSigTmp; // Signature.
514 ULONG cbSigTmp; // Size of signature.
515
516
517 _ASSERTE(cbSig && psa);
518 *psa = mdSignatureNil;
519
520 cRecs = pMiniMd->getCountStandAloneSigs();
521
522 // Search for the StandAloneSignature
523 for (ULONG i = 1; i <= cRecs; i++)
524 {
525 IfFailRet(pMiniMd->GetStandAloneSigRecord(i, &pRec));
526 IfFailRet(pMiniMd->getSignatureOfStandAloneSig(pRec, &pbSigTmp, &cbSigTmp));
527 if (cbSigTmp != cbSig)
528 continue;
529 if (memcmp( pbSig, pbSigTmp, cbSig ) != 0)
530 continue;
531
532 // we found a match
533 *psa = TokenFromRid(i, mdtSignature);
534 return S_OK;
535 }
536 return CLDB_E_RECORD_NOTFOUND;
537} // HRESULT ImportHelper::FindStandAloneSig()
538
539//*******************************************************************************
540// Find duplicate TypeSpec
541//*******************************************************************************
542HRESULT
543ImportHelper::FindTypeSpec(
544 CMiniMdRW * pMiniMd, // [IN] the minimd to lookup
545 const COR_SIGNATURE * pbSig, // [IN] Signature.
546 ULONG cbSig, // [IN] Size of signature.
547 mdTypeSpec * pTypeSpec) // [OUT] Put the TypeSpec token found
548{
549 HRESULT hr;
550 ULONG cRecs;
551 TypeSpecRec * pRec;
552 const COR_SIGNATURE * pbSigTmp; // Signature.
553 ULONG cbSigTmp; // Size of signature.
554
555 // cbSig can be 0
556 _ASSERTE(pTypeSpec != NULL);
557 *pTypeSpec = mdSignatureNil;
558
559 cRecs = pMiniMd->getCountTypeSpecs();
560
561 // Search for the TypeSpec
562 for (ULONG i = 1; i <= cRecs; i++)
563 {
564 IfFailRet(pMiniMd->GetTypeSpecRecord(i, &pRec));
565 IfFailRet(pMiniMd->getSignatureOfTypeSpec(pRec, &pbSigTmp, &cbSigTmp));
566 if (cbSigTmp != cbSig)
567 continue;
568 if (memcmp(pbSig, pbSigTmp, cbSig) != 0)
569 continue;
570
571 // we found a match
572 *pTypeSpec = TokenFromRid(i, mdtTypeSpec);
573 return S_OK;
574 }
575 return CLDB_E_RECORD_NOTFOUND;
576} // ImportHelper::FindTypeSpec
577
578
579//*******************************************************************************
580// Find the MethodImpl
581//*******************************************************************************
582HRESULT ImportHelper::FindMethodImpl(
583 CMiniMdRW *pMiniMd, // [IN] The MiniMd to lookup.
584 mdTypeDef tkClass, // [IN] The parent TypeDef token.
585 mdMethodDef tkBody, // [IN] Method body token.
586 mdMethodDef tkDecl, // [IN] Method declaration token.
587 RID *pRid) // [OUT] Put the MethodImpl rid here
588{
589 HRESULT hr;
590 MethodImplRec *pMethodImplRec; // MethodImpl record.
591 ULONG cMethodImplRecs; // Count of MethodImpl records.
592 mdTypeDef tkClassTmp; // Parent TypeDef token.
593 mdToken tkBodyTmp; // Method body token.
594 mdToken tkDeclTmp; // Method declaration token.
595
596 _ASSERTE(TypeFromToken(tkClass) == mdtTypeDef);
597 _ASSERTE(TypeFromToken(tkBody) == mdtMemberRef || TypeFromToken(tkBody) == mdtMethodDef);
598 _ASSERTE(TypeFromToken(tkDecl) == mdtMemberRef || TypeFromToken(tkDecl) == mdtMethodDef);
599 _ASSERTE(!IsNilToken(tkClass) && !IsNilToken(tkBody) && !IsNilToken(tkDecl));
600
601 if (pRid)
602 *pRid = 0;
603
604 cMethodImplRecs = pMiniMd->getCountMethodImpls();
605
606 // Search for the MethodImpl.
607 for (ULONG i = 1; i <= cMethodImplRecs; i++)
608 {
609 IfFailRet(pMiniMd->GetMethodImplRecord(i, &pMethodImplRec));
610
611 // match the parent column
612 tkClassTmp = pMiniMd->getClassOfMethodImpl(pMethodImplRec);
613 if (tkClassTmp != tkClass)
614 continue;
615
616 // match the method body column
617 tkBodyTmp = pMiniMd->getMethodBodyOfMethodImpl(pMethodImplRec);
618 if (tkBodyTmp != tkBody)
619 continue;
620
621 // match the method declaration column
622 tkDeclTmp = pMiniMd->getMethodDeclarationOfMethodImpl(pMethodImplRec);
623 if (tkDeclTmp != tkDecl)
624 continue;
625
626 // we found a match
627 if (pRid)
628 *pRid = i;
629 return S_OK;
630 }
631 return CLDB_E_RECORD_NOTFOUND;
632} // HRESULT ImportHelper::FindMethodImpl()
633
634//*******************************************************************************
635// Find the TypeRef given the fully qualified name and the assembly name
636//*******************************************************************************
637HRESULT ImportHelper::FindCustomAttributeCtorByName(
638 CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
639 LPCUTF8 szAssemblyName, // [IN] Assembly Name.
640 LPCUTF8 szNamespace, // [IN] TypeRef Namespace.
641 LPCUTF8 szName, // [IN] TypeRef Name.
642 mdTypeDef *ptk, // [OUT] Put the TypeRef token here.
643 RID rid /* = 0*/) // [IN] Optional rid to be ignored.
644{
645 HRESULT hr;
646 ULONG cRecs; // Count of records.
647 AssemblyRefRec *pRec; // Current record being looked at.
648 LPCUTF8 szTmp; // Temp string.
649 mdTypeRef tkCAType;
650
651 cRecs = pMiniMd->getCountAssemblyRefs();
652 // Search for the AssemblyRef record.
653 for (ULONG i = 1; i <= cRecs; i++)
654 {
655 IfFailRet(pMiniMd->GetAssemblyRefRecord(i, &pRec));
656
657 IfFailRet(pMiniMd->getNameOfAssemblyRef(pRec, &szTmp));
658 if (!strcmp(szTmp, szAssemblyName) &&
659 (SUCCEEDED(FindTypeRefByName(pMiniMd, TokenFromRid(i, mdtAssemblyRef), szNamespace, szName, &tkCAType, rid))) &&
660 (SUCCEEDED(FindMemberRef(pMiniMd, tkCAType, COR_CTOR_METHOD_NAME, NULL, 0 ,ptk))))
661 {
662 return S_OK;
663 }
664 }
665
666 return CLDB_E_RECORD_NOTFOUND;
667}
668
669//*******************************************************************************
670// Find the TypeRef given the fully qualified name.
671//*******************************************************************************
672HRESULT ImportHelper::FindTypeRefByName(
673 CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
674 mdToken tkResolutionScope, // [IN] Resolution scope for the TypeRef.
675 LPCUTF8 szNamespace, // [IN] TypeRef Namespace.
676 LPCUTF8 szName, // [IN] TypeRef Name.
677 mdTypeRef *ptk, // [OUT] Put the TypeRef token here.
678 RID rid /* = 0*/) // [IN] Optional rid to be ignored.
679{
680 HRESULT hr=S_OK; // A result.
681 ULONG cTypeRefRecs; // Count of TypeRefs to scan.
682 TypeRefRec *pTypeRefRec; // A TypeRef record.
683 LPCUTF8 szNameTmp; // A TypeRef's Name.
684 LPCUTF8 szNamespaceTmp; // A TypeRef's Namespace.
685 mdToken tkResTmp; // TypeRef's resolution scope.
686 ULONG i; // Loop control.
687
688 _ASSERTE(szName && ptk);
689 *ptk = mdTypeRefNil;
690
691 // Treat no namespace as empty string.
692 if (!szNamespace)
693 szNamespace = "";
694
695 if (pMiniMd->m_pNamedItemHash)
696 {
697 // If hash is build, go through the hash table
698 TOKENHASHENTRY *p; // Hash entry from chain.
699 ULONG iHash; // Item's hash value.
700 int pos; // Position in hash chain.
701
702 // Hash the data.
703 iHash = pMiniMd->HashNamedItem(0, szName);
704
705 // Go through every entry in the hash chain looking for ours.
706 for (p = pMiniMd->m_pNamedItemHash->FindFirst(iHash, pos);
707 p;
708 p = pMiniMd->m_pNamedItemHash->FindNext(pos))
709 {
710
711 // name hash can hold more than one kind of token
712 if (TypeFromToken(p->tok) != (ULONG)mdtTypeRef)
713 {
714 continue;
715 }
716
717 // skip this one if asked
718 if (RidFromToken(p->tok) == rid)
719 continue;
720
721 IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(p->tok), &pTypeRefRec));
722 IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szNamespaceTmp));
723 IfFailGo(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szNameTmp));
724 if (strcmp(szName, szNameTmp) || strcmp(szNamespace, szNamespaceTmp))
725 {
726 // if the name space is not equal, then check the next one.
727 continue;
728 }
729 tkResTmp = pMiniMd->getResolutionScopeOfTypeRef(pTypeRefRec);
730
731 if (tkResTmp == tkResolutionScope ||
732 (IsNilToken(tkResTmp) && IsNilToken(tkResolutionScope)))
733 {
734 // we found a match
735 *ptk = p->tok;
736 return S_OK;
737 }
738 }
739 hr = CLDB_E_RECORD_NOTFOUND;
740 }
741 else
742 {
743 cTypeRefRecs = pMiniMd->getCountTypeRefs();
744
745 // Search for the TypeRef.
746 for (i = 1; i <= cTypeRefRecs; i++)
747 {
748 // For the call from Validator ignore the rid passed in.
749 if (i == rid)
750 continue;
751
752 IfFailGo(pMiniMd->GetTypeRefRecord(i, &pTypeRefRec));
753
754 // See if the Resolution scopes match.
755 tkResTmp = pMiniMd->getResolutionScopeOfTypeRef(pTypeRefRec);
756 if (IsNilToken(tkResTmp))
757 {
758 if (!IsNilToken(tkResolutionScope))
759 continue;
760 }
761 else if (tkResTmp != tkResolutionScope)
762 continue;
763
764 IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szNamespaceTmp));
765 if (strcmp(szNamespace, szNamespaceTmp))
766 continue;
767
768 IfFailGo(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szNameTmp));
769 if (! strcmp(szName, szNameTmp))
770 {
771 *ptk = TokenFromRid(i, mdtTypeRef);
772 return S_OK;
773 }
774 }
775 hr = CLDB_E_RECORD_NOTFOUND;
776 }
777ErrExit:
778 return hr;
779} // HRESULT ImportHelper::FindTypeRefByName()
780
781
782//*******************************************************************************
783// Find the ModuleRef given the name, guid and mvid.
784//*******************************************************************************
785HRESULT ImportHelper::FindModuleRef(
786 CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
787 LPCUTF8 szUTF8Name, // [IN] ModuleRef name.
788 mdModuleRef *pmur, // [OUT] Put the ModuleRef token here.
789 RID rid /* = 0*/) // [IN] Optional rid to be ignored.
790{
791 HRESULT hr;
792 ModuleRefRec *pModuleRef;
793 ULONG cModuleRefs;
794 LPCUTF8 szCurName;
795 ULONG i;
796
797 _ASSERTE(pmur);
798 _ASSERTE(szUTF8Name);
799
800 cModuleRefs = pMiniMd->getCountModuleRefs();
801
802 // linear scan through the ModuleRef table
803 for (i=1; i <= cModuleRefs; ++i)
804 {
805 // For the call from Validator ignore the rid passed in.
806 if (i == rid)
807 continue;
808
809 IfFailRet(pMiniMd->GetModuleRefRecord(i, &pModuleRef));
810
811 if (szUTF8Name != NULL)
812 {
813 IfFailRet(pMiniMd->getNameOfModuleRef(pModuleRef, &szCurName));
814 if (strcmp(szCurName, szUTF8Name))
815 continue;
816 }
817 // Matching record found.
818 *pmur = TokenFromRid(i, mdtModuleRef);
819 return S_OK;
820 }
821 return CLDB_E_RECORD_NOTFOUND;
822} // HRESULT ImportHelper::FindModuleRef()
823
824
825
826//*******************************************************************************
827// Find the TypeDef given the type and namespace name
828//*******************************************************************************
829HRESULT
830ImportHelper::FindTypeDefByName(
831 CMiniMdRW * pMiniMd, // [IN] the minimd to lookup
832 LPCUTF8 szTypeDefNamespace, // [IN] Full qualified TypeRef name.
833 LPCUTF8 szTypeDefName, // [IN] Full qualified TypeRef name.
834 mdToken tkEnclosingClass, // [IN] TypeDef/TypeRef/Module for Enclosing class.
835 mdTypeDef * ptkTypeDef, // [OUT] Put the TypeRef token here.
836 RID ridIgnore) // =0 // [IN] Optional rid to be ignored.
837{
838 ULONG cTypeDefRecs;
839 TypeDefRec * pTypeDefRec;
840 LPCUTF8 szName;
841 LPCUTF8 szNamespace;
842 DWORD dwFlags;
843 HRESULT hr = S_OK;
844
845 _ASSERTE((szTypeDefName != NULL) && (ptkTypeDef != NULL));
846 _ASSERTE((TypeFromToken(tkEnclosingClass) == mdtTypeDef) ||
847 (TypeFromToken(tkEnclosingClass) == mdtTypeRef) ||
848 (tkEnclosingClass == TokenFromRid(1, mdtModule)) ||
849 IsNilToken(tkEnclosingClass));
850
851 *ptkTypeDef = mdTypeDefNil;
852
853 cTypeDefRecs = pMiniMd->getCountTypeDefs();
854
855 // Treat no namespace as empty string.
856 if (szTypeDefNamespace == NULL)
857 szTypeDefNamespace = "";
858
859 if (tkEnclosingClass == TokenFromRid(1, mdtModule))
860 { // Module scope is the same as no scope (used in .winmd files as TypeRef scope for self-references)
861 tkEnclosingClass = mdTokenNil;
862 }
863
864 // Get TypeDef of the tkEnclosingClass passed in
865 if (TypeFromToken(tkEnclosingClass) == mdtTypeRef)
866 {
867 // Resolve the TypeRef to a TypeDef
868 TypeRefRec * pTypeRefRec;
869 mdToken tkResolutionScope;
870 LPCUTF8 szTypeRefName;
871 LPCUTF8 szTypeRefNamespace;
872
873 IfFailRet(pMiniMd->GetTypeRefRecord(RidFromToken(tkEnclosingClass), &pTypeRefRec));
874 tkResolutionScope = pMiniMd->getResolutionScopeOfTypeRef(pTypeRefRec);
875 IfFailRet(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szTypeRefName));
876 IfFailRet(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szTypeRefNamespace));
877
878 if (tkEnclosingClass == tkResolutionScope && !strcmp(szTypeDefName, szTypeRefName) &&
879 ((szTypeDefNamespace == nullptr && szTypeRefNamespace == nullptr) ||
880 (szTypeDefNamespace != nullptr && szTypeRefNamespace != nullptr && !strcmp(szTypeDefNamespace, szTypeRefNamespace))))
881 {
882 //
883 // This defensive workaround works around a feature of DotFuscator that adds a bad type-ref
884 // which causes tools like ILDASM to crash. The type-ref's parent is set to itself
885 // which causes this function to recurse infinitely. A side-effect is that during Ngen we
886 // parse all the type-refs in an assembly and Ngen also hangs infinitely.
887 // This workaround is necessary because several popular gaming libraries experience hangs
888 // and we need binary compatibility in Apollo.
889 //
890 return CLDB_E_FILE_CORRUPT;
891 }
892
893 // Update tkEnclosingClass to TypeDef
894 IfFailRet(FindTypeDefByName(
895 pMiniMd,
896 szTypeRefNamespace,
897 szTypeRefName,
898 (TypeFromToken(tkResolutionScope) == mdtTypeRef) ? tkResolutionScope : mdTokenNil,
899 &tkEnclosingClass));
900 _ASSERTE(TypeFromToken(tkEnclosingClass) == mdtTypeDef);
901 }
902
903 // Search for the TypeDef
904 for (ULONG i = 1; i <= cTypeDefRecs; i++)
905 {
906 // For the call from Validator ignore the rid passed in.
907 if (i == ridIgnore)
908 continue;
909
910 IfFailRet(pMiniMd->GetTypeDefRecord(i, &pTypeDefRec));
911
912 dwFlags = pMiniMd->getFlagsOfTypeDef(pTypeDefRec);
913
914 if (!IsTdNested(dwFlags) && !IsNilToken(tkEnclosingClass))
915 {
916 // If the class is not Nested and EnclosingClass passed in is not nil
917 continue;
918 }
919 else if (IsTdNested(dwFlags) && IsNilToken(tkEnclosingClass))
920 {
921 // If the class is nested and EnclosingClass passed is nil
922 continue;
923 }
924 else if (!IsNilToken(tkEnclosingClass))
925 {
926 _ASSERTE(TypeFromToken(tkEnclosingClass) == mdtTypeDef);
927
928 RID iNestedClassRec;
929 NestedClassRec * pNestedClassRec;
930 mdTypeDef tkEnclosingClassTmp;
931
932 IfFailRet(pMiniMd->FindNestedClassHelper(TokenFromRid(i, mdtTypeDef), &iNestedClassRec));
933 if (InvalidRid(iNestedClassRec))
934 continue;
935 IfFailRet(pMiniMd->GetNestedClassRecord(iNestedClassRec, &pNestedClassRec));
936 tkEnclosingClassTmp = pMiniMd->getEnclosingClassOfNestedClass(pNestedClassRec);
937 if (tkEnclosingClass != tkEnclosingClassTmp)
938 continue;
939 }
940
941 IfFailRet(pMiniMd->getNameOfTypeDef(pTypeDefRec, &szName));
942 if (strcmp(szTypeDefName, szName) == 0)
943 {
944 IfFailRet(pMiniMd->getNamespaceOfTypeDef(pTypeDefRec, &szNamespace));
945 if (strcmp(szTypeDefNamespace, szNamespace) == 0)
946 {
947 *ptkTypeDef = TokenFromRid(i, mdtTypeDef);
948 return S_OK;
949 }
950 }
951 }
952 return CLDB_E_RECORD_NOTFOUND;
953} // ImportHelper::FindTypeDefByName
954
955//*******************************************************************************
956// Find the InterfaceImpl given the typedef and implemented interface
957//*******************************************************************************
958HRESULT ImportHelper::FindInterfaceImpl(
959 CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
960 mdToken tkClass, // [IN] TypeDef of the type
961 mdToken tkInterface, // [IN] could be typedef/typeref
962 mdInterfaceImpl *ptk, // [OUT] Put the interface token here.
963 RID rid /* = 0*/) // [IN] Optional rid to be ignored.
964{
965 HRESULT hr;
966 ULONG ridStart, ridEnd;
967 ULONG i;
968 InterfaceImplRec *pInterfaceImplRec;
969
970 _ASSERTE(ptk);
971 *ptk = mdInterfaceImplNil;
972 if ( pMiniMd->IsSorted(TBL_InterfaceImpl) )
973 {
974 IfFailRet(pMiniMd->getInterfaceImplsForTypeDef(RidFromToken(tkClass), &ridEnd, &ridStart));
975 }
976 else
977 {
978 ridStart = 1;
979 ridEnd = pMiniMd->getCountInterfaceImpls() + 1;
980 }
981
982 // Search for the interfaceimpl
983 for (i = ridStart; i < ridEnd; i++)
984 {
985 // For the call from Validator ignore the rid passed in.
986 if (i == rid)
987 continue;
988
989 IfFailRet(pMiniMd->GetInterfaceImplRecord(i, &pInterfaceImplRec));
990 if ( tkClass != pMiniMd->getClassOfInterfaceImpl(pInterfaceImplRec) )
991 continue;
992 if ( tkInterface == pMiniMd->getInterfaceOfInterfaceImpl(pInterfaceImplRec) )
993 {
994 *ptk = TokenFromRid(i, mdtInterfaceImpl);
995 return S_OK;
996 }
997 }
998 return CLDB_E_RECORD_NOTFOUND;
999} // HRESULT ImportHelper::FindInterfaceImpl()
1000
1001
1002
1003//*******************************************************************************
1004// Find the Permission by parent and action
1005//*******************************************************************************
1006HRESULT ImportHelper::FindPermission(
1007 CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
1008 mdToken tkParent, // [IN] Token with the Permission
1009 USHORT usAction, // [IN] The action of the permission
1010 mdPermission *ppm) // [OUT] Put permission token here
1011{
1012 HRESULT hr;
1013 DeclSecurityRec *pRec;
1014 ULONG ridStart, ridEnd;
1015 ULONG i;
1016 mdToken tkParentTmp;
1017
1018 _ASSERTE(ppm);
1019
1020 if ( pMiniMd->IsSorted(TBL_DeclSecurity) )
1021 {
1022
1023 IfFailRet(pMiniMd->getDeclSecurityForToken(tkParent, &ridEnd, &ridStart));
1024 }
1025 else
1026 {
1027 ridStart = 1;
1028 ridEnd = pMiniMd->getCountDeclSecuritys() + 1;
1029 }
1030 // loop through all permission
1031 for (i = ridStart; i < ridEnd; i++)
1032 {
1033 IfFailRet(pMiniMd->GetDeclSecurityRecord(i, &pRec));
1034 tkParentTmp = pMiniMd->getParentOfDeclSecurity(pRec);
1035 if ( tkParentTmp != tkParent )
1036 continue;
1037 if (pRec->GetAction() == usAction)
1038 {
1039 *ppm = TokenFromRid(i, mdtPermission);
1040 return S_OK;
1041 }
1042 }
1043 return CLDB_E_RECORD_NOTFOUND;
1044} // HRESULT ImportHelper::FindPermission()
1045
1046
1047//*****************************************************************************
1048// find a property record
1049//*****************************************************************************
1050HRESULT ImportHelper::FindProperty(
1051 CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
1052 mdToken tkTypeDef, // [IN] typedef token
1053 LPCUTF8 szName, // [IN] name of the property
1054 const COR_SIGNATURE *pbSig, // [IN] Signature.
1055 ULONG cbSig, // [IN] Size of signature.
1056 mdProperty *ppr) // [OUT] Property token
1057{
1058 HRESULT hr;
1059 RID ridPropertyMap;
1060 PropertyMapRec *pPropertyMapRec;
1061 PropertyRec *pRec;
1062 ULONG ridStart;
1063 ULONG ridEnd;
1064 ULONG i;
1065 LPCUTF8 szNameTmp;
1066 PCCOR_SIGNATURE pbSigTmp;
1067 ULONG cbSigTmp;
1068 ULONG pr;
1069
1070 IfFailRet(pMiniMd->FindPropertyMapFor(RidFromToken(tkTypeDef), &ridPropertyMap));
1071 if ( !InvalidRid(ridPropertyMap) )
1072 {
1073 IfFailRet(pMiniMd->GetPropertyMapRecord(ridPropertyMap, &pPropertyMapRec));
1074 ridStart = pMiniMd->getPropertyListOfPropertyMap(pPropertyMapRec);
1075 IfFailRet(pMiniMd->getEndPropertyListOfPropertyMap(ridPropertyMap, &ridEnd));
1076
1077 for (i = ridStart; i < ridEnd; i++)
1078 {
1079 // get the property rid
1080 IfFailRet(pMiniMd->GetPropertyRid(i, &pr));
1081 IfFailRet(pMiniMd->GetPropertyRecord(pr, &pRec));
1082 IfFailRet(pMiniMd->getNameOfProperty(pRec, &szNameTmp));
1083 IfFailRet(pMiniMd->getTypeOfProperty(pRec, &pbSigTmp, &cbSigTmp));
1084 if ( strcmp (szName, szNameTmp) != 0 )
1085 continue;
1086 if ( cbSig != 0 && (cbSigTmp != cbSig || memcmp(pbSig, pbSigTmp, cbSig) != 0 ) )
1087 continue;
1088 *ppr = TokenFromRid( i, mdtProperty );
1089 return S_OK;
1090 }
1091 return CLDB_E_RECORD_NOTFOUND;
1092 }
1093 else
1094 {
1095 return CLDB_E_RECORD_NOTFOUND;
1096 }
1097} // HRESULT ImportHelper::FindProperty()
1098
1099
1100
1101
1102//*****************************************************************************
1103// find an Event record
1104//*****************************************************************************
1105HRESULT ImportHelper::FindEvent(
1106 CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
1107 mdToken tkTypeDef, // [IN] typedef token
1108 LPCUTF8 szName, // [IN] name of the event
1109 mdProperty *pev) // [OUT] Event token
1110{
1111 HRESULT hr;
1112 RID ridEventMap;
1113 EventMapRec *pEventMapRec;
1114 EventRec *pRec;
1115 ULONG ridStart;
1116 ULONG ridEnd;
1117 ULONG i;
1118 LPCUTF8 szNameTmp;
1119 ULONG ev;
1120
1121 IfFailRet(pMiniMd->FindEventMapFor(RidFromToken(tkTypeDef), &ridEventMap));
1122 if ( !InvalidRid(ridEventMap) )
1123 {
1124 IfFailRet(pMiniMd->GetEventMapRecord(ridEventMap, &pEventMapRec));
1125 ridStart = pMiniMd->getEventListOfEventMap(pEventMapRec);
1126 IfFailRet(pMiniMd->getEndEventListOfEventMap(ridEventMap, &ridEnd));
1127
1128 for (i = ridStart; i < ridEnd; i++)
1129 {
1130 // get the Event rid
1131 IfFailRet(pMiniMd->GetEventRid(i, &ev));
1132
1133 // get the event row
1134 IfFailRet(pMiniMd->GetEventRecord(ev, &pRec));
1135 IfFailRet(pMiniMd->getNameOfEvent(pRec, &szNameTmp));
1136 if ( strcmp (szName, szNameTmp) == 0)
1137 {
1138 *pev = TokenFromRid( ev, mdtEvent );
1139 return S_OK;
1140 }
1141 }
1142 return CLDB_E_RECORD_NOTFOUND;
1143 }
1144 else
1145 {
1146 return CLDB_E_RECORD_NOTFOUND;
1147 }
1148} // HRESULT ImportHelper::FindEvent()
1149
1150
1151
1152//*****************************************************************************
1153// find an custom value record given by parent and type token. This will always return
1154// the first one that is found regardless duplicated.
1155//*****************************************************************************
1156HRESULT ImportHelper::FindCustomAttributeByToken(
1157 CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
1158 mdToken tkParent, // [IN] the parent that custom value is associated with
1159 mdToken tkType, // [IN] type of the CustomAttribute
1160 const void *pCustBlob, // [IN] custom attribute blob
1161 ULONG cbCustBlob, // [IN] size of the blob.
1162 mdCustomAttribute *pcv) // [OUT] CustomAttribute token
1163{
1164 HRESULT hr;
1165 CustomAttributeRec *pRec;
1166 ULONG ridStart, ridEnd;
1167 ULONG i;
1168 mdToken tkParentTmp;
1169 mdToken tkTypeTmp;
1170 const void *pCustBlobTmp;
1171 ULONG cbCustBlobTmp;
1172
1173 _ASSERTE(pcv);
1174 *pcv = mdCustomAttributeNil;
1175 if ( pMiniMd->IsSorted(TBL_CustomAttribute) )
1176 {
1177 IfFailRet(pMiniMd->FindCustomAttributeFor(
1178 RidFromToken(tkParent),
1179 TypeFromToken(tkParent),
1180 tkType,
1181 (RID *)pcv));
1182 if (InvalidRid(*pcv))
1183 {
1184 return S_FALSE;
1185 }
1186 else if (pCustBlob)
1187 {
1188 IfFailRet(pMiniMd->GetCustomAttributeRecord(RidFromToken(*pcv), &pRec));
1189 IfFailRet(pMiniMd->getValueOfCustomAttribute(pRec, (const BYTE **)&pCustBlobTmp, &cbCustBlobTmp));
1190 if (cbCustBlob == cbCustBlobTmp &&
1191 !memcmp(pCustBlob, pCustBlobTmp, cbCustBlob))
1192 {
1193 return S_OK;
1194 }
1195 }
1196 else
1197 {
1198 return S_OK;
1199 }
1200 }
1201 else
1202 {
1203 CLookUpHash *pHashTable = pMiniMd->m_pLookUpHashs[TBL_CustomAttribute];
1204
1205 if (pHashTable)
1206 {
1207 // table is not sorted but hash is built
1208 // We want to create dynmaic array to hold the dynamic enumerator.
1209 TOKENHASHENTRY *p;
1210 ULONG iHash;
1211 int pos;
1212
1213 // Hash the data.
1214 iHash = pMiniMd->HashCustomAttribute(tkParent);
1215
1216 // Go through every entry in the hash chain looking for ours.
1217 for (p = pHashTable->FindFirst(iHash, pos);
1218 p;
1219 p = pHashTable->FindNext(pos))
1220 {
1221 IfFailRet(pMiniMd->GetCustomAttributeRecord(RidFromToken(p->tok), &pRec));
1222
1223 tkParentTmp = pMiniMd->getParentOfCustomAttribute(pRec);
1224 if (tkParentTmp != tkParent)
1225 continue;
1226
1227 tkTypeTmp = pMiniMd->getTypeOfCustomAttribute(pRec);
1228 if (tkType != tkTypeTmp)
1229 continue;
1230 if (pCustBlob != NULL)
1231 {
1232 IfFailRet(pMiniMd->getValueOfCustomAttribute(pRec, (const BYTE **)&pCustBlobTmp, &cbCustBlobTmp));
1233 if (cbCustBlob == cbCustBlobTmp &&
1234 !memcmp(pCustBlob, pCustBlobTmp, cbCustBlob))
1235 {
1236 *pcv = TokenFromRid(p->tok, mdtCustomAttribute);
1237 return S_OK;
1238 }
1239 }
1240 else
1241 return S_OK;
1242 }
1243 }
1244 else
1245 {
1246 // linear scan
1247 ridStart = 1;
1248 ridEnd = pMiniMd->getCountCustomAttributes() + 1;
1249
1250 // loop through all custom values
1251 for (i = ridStart; i < ridEnd; i++)
1252 {
1253 IfFailRet(pMiniMd->GetCustomAttributeRecord(i, &pRec));
1254
1255 tkParentTmp = pMiniMd->getParentOfCustomAttribute(pRec);
1256 if ( tkParentTmp != tkParent )
1257 continue;
1258
1259 tkTypeTmp = pMiniMd->getTypeOfCustomAttribute(pRec);
1260 if (tkType != tkTypeTmp)
1261 continue;
1262
1263 if (pCustBlob != NULL)
1264 {
1265 IfFailRet(pMiniMd->getValueOfCustomAttribute(pRec, (const BYTE **)&pCustBlobTmp, &cbCustBlobTmp));
1266 if (cbCustBlob == cbCustBlobTmp &&
1267 !memcmp(pCustBlob, pCustBlobTmp, cbCustBlob))
1268 {
1269 *pcv = TokenFromRid(i, mdtCustomAttribute);
1270 return S_OK;
1271 }
1272 }
1273 else
1274 return S_OK;
1275 }
1276 }
1277 // fall through
1278 }
1279 return S_FALSE;
1280} // ImportHelper::FindCustomAttributeByToken
1281
1282//*****************************************************************************
1283// Helper function to lookup and retrieve a CustomAttribute.
1284//*****************************************************************************
1285HRESULT ImportHelper::GetCustomAttributeByName( // S_OK or error.
1286 CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
1287 mdToken tkObj, // [IN] Object with Custom Attribute.
1288 LPCUTF8 szName, // [IN] Name of desired Custom Attribute.
1289 const void **ppData, // [OUT] Put pointer to data here.
1290 ULONG *pcbData) // [OUT] Put size of data here.
1291{
1292 return pMiniMd->CommonGetCustomAttributeByName(tkObj, szName, ppData, pcbData);
1293} // ImportHelper::GetCustomAttributeByName
1294
1295#ifdef FEATURE_METADATA_EMIT
1296
1297//*******************************************************************************
1298// Find an AssemblyRef record given the name.
1299//*******************************************************************************
1300HRESULT ImportHelper::FindAssemblyRef(
1301 CMiniMdRW *pMiniMd, // [IN] the minimd to lookup.
1302 LPCUTF8 szName, // [IN] Name.
1303 LPCUTF8 szLocale, // [IN] Locale.
1304 const void *pbPublicKeyOrToken, // [IN] Public key or token (based on flags).
1305 ULONG cbPublicKeyOrToken, // [IN] Byte count of public key or token.
1306 USHORT usMajorVersion, // [IN] Major version.
1307 USHORT usMinorVersion, // [IN] Minor version.
1308 USHORT usBuildNumber, // [IN] Build number.
1309 USHORT usRevisionNumber, // [IN] Revision number.
1310 DWORD dwFlags, // [IN] Flags.
1311 mdAssemblyRef *pmar) // [OUT] returned AssemblyRef token.
1312{
1313 HRESULT hr;
1314 ULONG cRecs; // Count of records.
1315 AssemblyRefRec *pRec; // Current record being looked at.
1316 LPCUTF8 szTmp; // Temp string.
1317 const void *pbTmp; // Temp blob.
1318 ULONG cbTmp; // Temp byte count.
1319 DWORD dwTmp; // Temp flags.
1320 const void *pbToken = NULL; // Token version of public key.
1321 ULONG cbToken = 0; // Count of bytes in token.
1322#if !defined(FEATURE_METADATA_EMIT_IN_DEBUGGER) || defined(DACCESS_COMPILE)
1323 const void *pbTmpToken; // Token version of public key.
1324 ULONG cbTmpToken; // Count of bytes in token.
1325 bool fMatch; // Did public key or tokens match?
1326#endif // !FEATURE_METADATA_EMIT_IN_DEBUGGER || DACCESS_COMPILE
1327
1328 // Handle special cases upfront.
1329 if (!szLocale)
1330 szLocale = "";
1331 if (!pbPublicKeyOrToken)
1332 cbPublicKeyOrToken = 0;
1333
1334 if (!IsAfPublicKey(dwFlags))
1335 {
1336 pbToken = pbPublicKeyOrToken;
1337 cbToken = cbPublicKeyOrToken;
1338 }
1339
1340 _ASSERTE(pMiniMd && szName && pmar);
1341 *pmar = 0;
1342
1343 cRecs = pMiniMd->getCountAssemblyRefs();
1344
1345 // Search for the AssemblyRef record.
1346 for (ULONG i = 1; i <= cRecs; i++)
1347 {
1348 IfFailRet(pMiniMd->GetAssemblyRefRecord(i, &pRec));
1349
1350 IfFailRet(pMiniMd->getNameOfAssemblyRef(pRec, &szTmp));
1351 if (strcmp(szTmp, szName))
1352 continue;
1353
1354 IfFailRet(pMiniMd->getLocaleOfAssemblyRef(pRec, &szTmp));
1355 if (strcmp(szTmp, szLocale))
1356 continue;
1357
1358 if (pRec->GetMajorVersion() != usMajorVersion)
1359 continue;
1360 if (pRec->GetMinorVersion() != usMinorVersion)
1361 continue;
1362
1363 // We'll "unify" all versions of mscorlib and Microsoft.VisualC... so if this
1364 // is one of those, we won't do the version check beyond the major/minor
1365
1366 LPCUTF8 szAssemblyRefName;
1367 IfFailRet(pMiniMd->getNameOfAssemblyRef(pRec, &szAssemblyRefName));
1368 if (SString::_stricmp(szAssemblyRefName, "mscorlib") &&
1369 SString::_stricmp(szAssemblyRefName, "microsoft.visualc"))
1370 {
1371 if (pRec->GetBuildNumber() != usBuildNumber)
1372 continue;
1373 if (pRec->GetRevisionNumber() != usRevisionNumber)
1374 continue;
1375 }
1376
1377 IfFailRet(pMiniMd->getPublicKeyOrTokenOfAssemblyRef(pRec, (const BYTE **)&pbTmp, &cbTmp));
1378
1379 if ((cbPublicKeyOrToken && !cbTmp) ||
1380 (!cbPublicKeyOrToken && cbTmp))
1381 continue;
1382
1383 if (cbTmp)
1384 {
1385 // Either ref may be using either a full public key or a token
1386 // (determined by the ref flags). Must cope with all variations.
1387 dwTmp = pMiniMd->getFlagsOfAssemblyRef(pRec);
1388 if (IsAfPublicKey(dwTmp) == IsAfPublicKey(dwFlags))
1389 {
1390 // Easy case, they're both in the same form.
1391 if (cbTmp != cbPublicKeyOrToken || memcmp(pbTmp, pbPublicKeyOrToken, cbTmp))
1392 continue;
1393 }
1394 else if (IsAfPublicKey(dwTmp))
1395 {
1396#if defined(FEATURE_METADATA_EMIT_IN_DEBUGGER) && !defined(DACCESS_COMPILE)
1397 return E_FAIL;
1398#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER || DACCESS_COMPILE
1399 // Need to compress target public key to see if it matches.
1400 if (!StrongNameTokenFromPublicKey((BYTE*)pbTmp,
1401 cbTmp,
1402 (BYTE**)&pbTmpToken,
1403 &cbTmpToken))
1404 {
1405 return StrongNameErrorInfo();
1406 }
1407 fMatch = cbTmpToken == cbPublicKeyOrToken && !memcmp(pbTmpToken, pbPublicKeyOrToken, cbTmpToken);
1408 StrongNameFreeBuffer((BYTE*)pbTmpToken);
1409 if (!fMatch)
1410 continue;
1411#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER || DACCESS_COMPILE
1412 }
1413 else
1414 {
1415 // Need to compress out public key to see if it matches. We
1416 // cache the result of this for further iterations.
1417 if (!pbToken)
1418 {
1419#if defined(FEATURE_METADATA_EMIT_IN_DEBUGGER) && !defined(DACCESS_COMPILE)
1420 return E_FAIL;
1421#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER || DACCESS_COMPILE
1422 if (!StrongNameTokenFromPublicKey((BYTE*)pbPublicKeyOrToken,
1423 cbPublicKeyOrToken,
1424 (BYTE**)&pbToken,
1425 &cbToken))
1426 {
1427 return StrongNameErrorInfo();
1428 }
1429#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER || DACCESS_COMPILE
1430 }
1431 if (cbTmp != cbToken || memcmp(pbTmp, pbToken, cbToken))
1432 continue;
1433 }
1434 }
1435
1436 if (pbToken && IsAfPublicKey(dwFlags))
1437 {
1438#if !defined(FEATURE_METADATA_EMIT_IN_DEBUGGER) || defined(DACCESS_COMPILE)
1439 StrongNameFreeBuffer((BYTE*)pbToken);
1440#endif
1441 }
1442 *pmar = TokenFromRid(i, mdtAssemblyRef);
1443 return S_OK;
1444 }
1445 if (pbToken && IsAfPublicKey(dwFlags))
1446 {
1447#if !defined(FEATURE_METADATA_EMIT_IN_DEBUGGER) || defined(DACCESS_COMPILE)
1448 StrongNameFreeBuffer((BYTE*)pbToken);
1449#endif
1450 }
1451 return CLDB_E_RECORD_NOTFOUND;
1452} // ImportHelper::FindAssemblyRef
1453
1454//*******************************************************************************
1455// Find a File record given the name.
1456//*******************************************************************************
1457HRESULT ImportHelper::FindFile(
1458 CMiniMdRW *pMiniMd, // [IN] the minimd to lookup.
1459 LPCUTF8 szName, // [IN] name for the File.
1460 mdFile *pmf, // [OUT] returned File token.
1461 RID rid /* = 0 */) // [IN] Optional rid to be ignored.
1462{
1463 HRESULT hr;
1464 ULONG cRecs; // Count of records.
1465 FileRec *pRec; // Current record being looked at.
1466
1467 LPCUTF8 szNameTmp;
1468
1469 _ASSERTE(pMiniMd && szName && pmf);
1470 *pmf = 0;
1471
1472 cRecs = pMiniMd->getCountFiles();
1473
1474 // Search for the File record.
1475 for (ULONG i = 1; i <= cRecs; i++)
1476 {
1477 // For the call from Validator ignore the rid passed in.
1478 if (i == rid)
1479 continue;
1480
1481 IfFailRet(pMiniMd->GetFileRecord(i, &pRec));
1482
1483 IfFailRet(pMiniMd->getNameOfFile(pRec, &szNameTmp));
1484 if (!strcmp(szNameTmp, szName))
1485 {
1486 *pmf = TokenFromRid(i, mdtFile);
1487 return S_OK;
1488 }
1489 }
1490 return CLDB_E_RECORD_NOTFOUND;
1491} // ImportHelper::FindFile
1492
1493#endif //FEATURE_METADATA_EMIT
1494
1495//*******************************************************************************
1496// Find a ExportedType record given the name.
1497//*******************************************************************************
1498HRESULT ImportHelper::FindExportedType(
1499 CMiniMdRW *pMiniMd, // [IN] the minimd to lookup.
1500 LPCUTF8 szNamespace, // [IN] namespace for the ExportedType.
1501 LPCUTF8 szName, // [IN] name for the ExportedType.
1502 mdExportedType tkEnclosingType, // [IN] token for the enclosing type.
1503 mdExportedType *pmct, // [OUT] returned ExportedType token.
1504 RID rid /* = 0 */) // [IN] Optional rid to be ignored.
1505{
1506 HRESULT hr;
1507 ULONG cRecs; // Count of records.
1508 ExportedTypeRec *pRec; // Current record being looked at.
1509 mdToken tkImpl;
1510 LPCUTF8 szNamespaceTmp;
1511 LPCUTF8 szNameTmp;
1512
1513 _ASSERTE(pMiniMd && szName && pmct);
1514 *pmct = 0;
1515
1516 // Treat no namespace as empty string.
1517 if (!szNamespace)
1518 szNamespace = "";
1519
1520 cRecs = pMiniMd->getCountExportedTypes();
1521
1522 // Search for the ExportedType record.
1523 for (ULONG i = 1; i <= cRecs; i++)
1524 {
1525 // For the call from Validator ignore the rid passed in.
1526 if (i == rid)
1527 continue;
1528
1529 IfFailRet(pMiniMd->GetExportedTypeRecord(i, &pRec));
1530
1531 // Handle the case of nested vs. non-nested classes.
1532 tkImpl = pMiniMd->getImplementationOfExportedType(pRec);
1533 if (TypeFromToken(tkImpl) == mdtExportedType && !IsNilToken(tkImpl))
1534 {
1535 // Current ExportedType being looked at is a nested type, so
1536 // comparing the implementation token.
1537 if (tkImpl != tkEnclosingType)
1538 continue;
1539 }
1540 else if (TypeFromToken(tkEnclosingType) == mdtExportedType &&
1541 !IsNilToken(tkEnclosingType))
1542 {
1543 // ExportedType passed in is nested but the current ExportedType is not.
1544 continue;
1545 }
1546
1547 IfFailRet(pMiniMd->getTypeNamespaceOfExportedType(pRec, &szNamespaceTmp));
1548 if (strcmp(szNamespaceTmp, szNamespace))
1549 continue;
1550
1551 IfFailRet(pMiniMd->getTypeNameOfExportedType(pRec, &szNameTmp));
1552 if (!strcmp(szNameTmp, szName))
1553 {
1554 *pmct = TokenFromRid(i, mdtExportedType);
1555 return S_OK;
1556 }
1557 }
1558 return CLDB_E_RECORD_NOTFOUND;
1559} // HRESULT ImportHelper::FindExportedType()
1560
1561//*******************************************************************************
1562// Find a ManifestResource record given the name.
1563//*******************************************************************************
1564HRESULT ImportHelper::FindManifestResource(
1565 CMiniMdRW *pMiniMd, // [IN] the minimd to lookup.
1566 LPCUTF8 szName, // [IN] name for the ManifestResource.
1567 mdManifestResource *pmmr, // [OUT] returned ManifestResource token.
1568 RID rid /* = 0 */) // [IN] Optional rid to be ignored.
1569{
1570 HRESULT hr;
1571 ULONG cRecs; // Count of records.
1572 ManifestResourceRec *pRec; // Current record being looked at.
1573
1574 LPCUTF8 szNameTmp;
1575
1576 _ASSERTE(pMiniMd && szName && pmmr);
1577 *pmmr = 0;
1578
1579 cRecs = pMiniMd->getCountManifestResources();
1580
1581 // Search for the ManifestResource record.
1582 for (ULONG i = 1; i <= cRecs; i++)
1583 {
1584 // For the call from Validator ignore the rid passed in.
1585 if (i == rid)
1586 continue;
1587
1588 IfFailRet(pMiniMd->GetManifestResourceRecord(i, &pRec));
1589
1590 IfFailRet(pMiniMd->getNameOfManifestResource(pRec, &szNameTmp));
1591 if (!strcmp(szNameTmp, szName))
1592 {
1593 *pmmr = TokenFromRid(i, mdtManifestResource);
1594 return S_OK;
1595 }
1596 }
1597 return CLDB_E_RECORD_NOTFOUND;
1598} // HRESULT ImportHelper::FindManifestResource()
1599
1600#ifdef FEATURE_METADATA_EMIT
1601
1602//****************************************************************************
1603// Convert tokens contained in an element type
1604//****************************************************************************
1605HRESULT
1606ImportHelper::MergeUpdateTokenInFieldSig(
1607 CMiniMdRW *pMiniMdAssemEmit, // [IN] The assembly emit scope.
1608 CMiniMdRW *pMiniMdEmit, // [IN] The emit scope.
1609 IMetaModelCommon *pCommonAssemImport,// [IN] Assembly scope where the signature is from.
1610 const void *pbHashValue, // [IN] Hash value for the import assembly.
1611 ULONG cbHashValue, // [IN] Size in bytes for the hash value.
1612 IMetaModelCommon *pCommonImport, // [IN] The scope to merge into the emit scope.
1613 PCCOR_SIGNATURE pbSigImp, // signature from the imported scope
1614 MDTOKENMAP *ptkMap, // Internal OID mapping structure.
1615 CQuickBytes *pqkSigEmit, // [OUT] buffer for translated signature
1616 ULONG cbStartEmit, // [IN] start point of buffer to write to
1617 ULONG *pcbImp, // [OUT] total number of bytes consumed from pbSigImp
1618 ULONG *pcbEmit) // [OUT] total number of bytes write to pqkSigEmit
1619{
1620
1621 HRESULT hr; // A result.
1622 ULONG cb; // count of bytes
1623 ULONG cb1; // count of bytes
1624 ULONG cb2; // count of bytes
1625 ULONG cbSubTotal;
1626 ULONG cbImp;
1627 ULONG cbEmit;
1628 ULONG cbSrcTotal = 0; // count of bytes consumed in the imported signature
1629 ULONG cbDestTotal = 0; // count of bytes for the new signature
1630 ULONG ulElementType = 0; // place holder for expanded data
1631 ULONG ulData;
1632 ULONG ulTemp;
1633 mdToken tkRidFrom; // Original rid
1634 mdToken tkRidTo; // new rid
1635 int iData;
1636 CQuickArray<mdToken> cqaNesters; // Array of Nester tokens.
1637 CQuickArray<LPCUTF8> cqaNesterNamespaces; // Array of Nester Namespaces.
1638 CQuickArray<LPCUTF8> cqaNesterNames; // Array of Nester names.
1639
1640 _ASSERTE(pcbEmit);
1641
1642 cb = CorSigUncompressData(&pbSigImp[cbSrcTotal], &ulElementType);
1643 cbSrcTotal += cb;
1644
1645 // count numbers of modifiers
1646 while (CorIsModifierElementType((CorElementType) ulElementType))
1647 {
1648 cb = CorSigUncompressData(&pbSigImp[cbSrcTotal], &ulElementType);
1649 cbSrcTotal += cb;
1650 }
1651
1652 // copy ELEMENT_TYPE_* over
1653 cbDestTotal = cbSrcTotal;
1654 IfFailGo(pqkSigEmit->ReSizeNoThrow(cbStartEmit + cbDestTotal));
1655 memcpy(((BYTE *)pqkSigEmit->Ptr()) + cbStartEmit, pbSigImp, cbDestTotal);
1656 switch (ulElementType)
1657 {
1658 case ELEMENT_TYPE_SZARRAY:
1659 // syntax : SZARRAY <BaseType>
1660
1661 // conver the base type for the SZARRAY or GENERICARRAY
1662 IfFailGo(MergeUpdateTokenInFieldSig(
1663 pMiniMdAssemEmit, // The assembly emit scope.
1664 pMiniMdEmit, // The emit scope.
1665 pCommonAssemImport, // The assembly scope where the signature is from.
1666 pbHashValue, // Hash value for the import assembly.
1667 cbHashValue, // Size in bytes for the hash value.
1668 pCommonImport, // scope to merge into the emit scope.
1669 &pbSigImp[cbSrcTotal], // from the imported scope
1670 ptkMap, // OID mapping structure.
1671 pqkSigEmit, // [OUT] buffer for translated signature
1672 cbStartEmit + cbDestTotal, // [IN] start point of buffer to write to
1673 &cbImp, // [OUT] total number of bytes consumed from pbSigImp
1674 &cbEmit)); // [OUT] total number of bytes write to pqkSigEmit
1675 cbSrcTotal += cbImp;
1676 cbDestTotal += cbEmit;
1677 break;
1678
1679 case ELEMENT_TYPE_GENERICINST:
1680 {
1681 // syntax : WITH (ELEMENT_TYPE_CLASS | ELEMENT_TYPE_VALUECLASS) <BaseType>
1682
1683 IfFailGo(MergeUpdateTokenInFieldSig(
1684 pMiniMdAssemEmit, // The assembly emit scope.
1685 pMiniMdEmit, // The emit scope.
1686 pCommonAssemImport, // The assembly scope where the signature is from.
1687 pbHashValue, // Hash value for the import assembly.
1688 cbHashValue, // Size in bytes for the hash value.
1689 pCommonImport, // scope to merge into the emit scope.
1690 &pbSigImp[cbSrcTotal], // from the imported scope
1691 ptkMap, // OID mapping structure.
1692 pqkSigEmit, // [OUT] buffer for translated signature
1693 cbStartEmit + cbDestTotal, // [IN] start point of buffer to write to
1694 &cbImp, // [OUT] total number of bytes consumed from pbSigImp
1695 &cbEmit)); // [OUT] total number of bytes write to pqkSigEmit
1696 cbSrcTotal += cbImp;
1697 cbDestTotal += cbEmit;
1698
1699 // copy over the number of arguments
1700 ULONG nargs;
1701 cb = CorSigUncompressData(&pbSigImp[cbSrcTotal], &nargs);
1702
1703 IfFailGo(pqkSigEmit->ReSizeNoThrow(cbStartEmit + cbDestTotal + cb));
1704 cb1 = CorSigCompressData(nargs, ((BYTE *)pqkSigEmit->Ptr()) + cbStartEmit + cbDestTotal);
1705 _ASSERTE(cb == cb1);
1706
1707 cbSrcTotal += cb;
1708 cbDestTotal += cb1;
1709
1710 for (ULONG narg = 0; narg < nargs; narg++) {
1711 IfFailGo(MergeUpdateTokenInFieldSig(
1712 pMiniMdAssemEmit, // The assembly emit scope.
1713 pMiniMdEmit, // The emit scope.
1714 pCommonAssemImport, // The assembly scope where the signature is from.
1715 pbHashValue, // Hash value for the import assembly.
1716 cbHashValue, // Size in bytes for the hash value.
1717 pCommonImport, // The scope to merge into the emit scope.
1718 &pbSigImp[cbSrcTotal], // signature from the imported scope
1719 ptkMap, // Internal OID mapping structure.
1720 pqkSigEmit, // [OUT] buffer for translated signature
1721 cbStartEmit + cbDestTotal, // [IN] start point of buffer to write to
1722 &cbImp, // [OUT] total number of bytes consumed from pbSigImp
1723 &cbEmit)); // [OUT] total number of bytes write to pqkSigEmit
1724 cbSrcTotal += cbImp;
1725 cbDestTotal += cbEmit;
1726 }
1727 }
1728
1729 break;
1730
1731 case ELEMENT_TYPE_MVAR:
1732 case ELEMENT_TYPE_VAR:
1733 // syntax : VAR <n>
1734 // syntax : MVAR <n>
1735
1736 // after the VAR or MVAR there is an integer indicating which type variable
1737 //
1738 cb = CorSigUncompressData(&pbSigImp[cbSrcTotal], &ulData);
1739
1740 IfFailGo(pqkSigEmit->ReSizeNoThrow(cbStartEmit + cbDestTotal + cb));
1741 cb1 = CorSigCompressData(ulData, ((BYTE *)pqkSigEmit->Ptr()) + cbStartEmit + cbDestTotal);
1742 _ASSERTE(cb == cb1);
1743
1744 cbSrcTotal += cb;
1745 cbDestTotal += cb1;
1746
1747 break;
1748
1749 case ELEMENT_TYPE_ARRAY:
1750 // syntax : ARRAY BaseType <rank> [i size_1... size_i] [j lowerbound_1 ... lowerbound_j]
1751
1752 // conver the base type for the MDARRAY
1753 IfFailGo(MergeUpdateTokenInFieldSig(
1754 pMiniMdAssemEmit, // The assembly emit scope.
1755 pMiniMdEmit, // The emit scope.
1756 pCommonAssemImport, // The assembly scope where the signature is from.
1757 pbHashValue, // Hash value for the import assembly.
1758 cbHashValue, // Size in bytes for the hash value.
1759 pCommonImport, // The scope to merge into the emit scope.
1760 &pbSigImp[cbSrcTotal], // signature from the imported scope
1761 ptkMap, // Internal OID mapping structure.
1762 pqkSigEmit, // [OUT] buffer for translated signature
1763 cbStartEmit + cbSrcTotal, // [IN] start point of buffer to write to
1764 &cbImp, // [OUT] total number of bytes consumed from pbSigImp
1765 &cbEmit)); // [OUT] total number of bytes write to pqkSigEmit
1766 cbSrcTotal += cbImp;
1767 cbDestTotal += cbEmit;
1768
1769 // Parse for the rank
1770 cbSubTotal = CorSigUncompressData(&pbSigImp[cbSrcTotal], &ulData);
1771
1772 // if rank == 0, we are done
1773 if (ulData != 0)
1774 {
1775 // any size of dimension specified?
1776 cb = CorSigUncompressData(&pbSigImp[cbSrcTotal + cbSubTotal], &ulData);
1777 cbSubTotal += cb;
1778
1779 while (ulData--)
1780 {
1781 cb = CorSigUncompressData(&pbSigImp[cbSrcTotal + cbSubTotal], &ulTemp);
1782 cbSubTotal += cb;
1783 }
1784
1785 // any lower bound specified?
1786 cb = CorSigUncompressData(&pbSigImp[cbSrcTotal + cbSubTotal], &ulData);
1787 cbSubTotal += cb;
1788
1789 while (ulData--)
1790 {
1791 cb = CorSigUncompressSignedInt(&pbSigImp[cbSrcTotal + cbSubTotal], &iData);
1792 cbSubTotal += cb;
1793 }
1794 }
1795
1796 // cbSubTotal is now the number of bytes still left to move over
1797 // cbSrcTotal is where bytes start on the pbSigImp to be copied over
1798 // cbStartEmit + cbDestTotal is where the destination of copy
1799
1800 IfFailGo(pqkSigEmit->ReSizeNoThrow(cbStartEmit + cbDestTotal + cbSubTotal));
1801 memcpy(((BYTE *)pqkSigEmit->Ptr())+cbStartEmit + cbDestTotal, &pbSigImp[cbSrcTotal], cbSubTotal);
1802
1803 cbSrcTotal = cbSrcTotal + cbSubTotal;
1804 cbDestTotal = cbDestTotal + cbSubTotal;
1805
1806 break;
1807 case ELEMENT_TYPE_FNPTR:
1808 // function pointer is followed by another complete signature
1809 IfFailGo(MergeUpdateTokenInSig(
1810 pMiniMdAssemEmit, // The assembly emit scope.
1811 pMiniMdEmit, // The emit scope.
1812 pCommonAssemImport, // The assembly scope where the signature is from.
1813 pbHashValue, // Hash value for the import assembly.
1814 cbHashValue, // Size in bytes for the hash value.
1815 pCommonImport, // The scope to merge into the emit scope.
1816 &pbSigImp[cbSrcTotal], // signature from the imported scope
1817 ptkMap, // Internal OID mapping structure.
1818 pqkSigEmit, // [OUT] buffer for translated signature
1819 cbStartEmit + cbDestTotal, // [IN] start point of buffer to write to
1820 &cbImp, // [OUT] total number of bytes consumed from pbSigImp
1821 &cbEmit)); // [OUT] total number of bytes write to pqkSigEmit
1822 cbSrcTotal += cbImp;
1823 cbDestTotal += cbEmit;
1824 break;
1825 case ELEMENT_TYPE_VALUETYPE:
1826 case ELEMENT_TYPE_CLASS:
1827 case ELEMENT_TYPE_CMOD_REQD:
1828 case ELEMENT_TYPE_CMOD_OPT:
1829
1830 // syntax for CLASS = ELEMENT_TYPE_CLASS <rid>
1831 // syntax for VALUE_CLASS = ELEMENT_TYPE_VALUECLASS <rid>
1832
1833 // now get the embedded typeref token
1834 cb = CorSigUncompressToken(&pbSigImp[cbSrcTotal], &tkRidFrom);
1835
1836 // Map the ulRidFrom to ulRidTo
1837 if (ptkMap)
1838 {
1839 // mdtBaseType does not record in the map. It is unique across modules
1840 if ( TypeFromToken(tkRidFrom) == mdtBaseType )
1841 {
1842 tkRidTo = tkRidFrom;
1843 }
1844 else
1845 {
1846 IfFailGo( ptkMap->Remap(tkRidFrom, &tkRidTo) );
1847 }
1848 }
1849 else
1850 {
1851 // If the token is a TypeDef or a TypeRef, get/create the
1852 // ResolutionScope for the outermost TypeRef.
1853 if (TypeFromToken(tkRidFrom) == mdtTypeDef)
1854 {
1855 IfFailGo(ImportTypeDef(pMiniMdAssemEmit,
1856 pMiniMdEmit,
1857 pCommonAssemImport,
1858 pbHashValue,
1859 cbHashValue,
1860 pCommonImport,
1861 tkRidFrom,
1862 true, // Optimize to TypeDef if emit and import scopes are identical.
1863 &tkRidTo));
1864 }
1865 else if (TypeFromToken(tkRidFrom) == mdtTypeRef)
1866 {
1867 IfFailGo(ImportTypeRef(pMiniMdAssemEmit,
1868 pMiniMdEmit,
1869 pCommonAssemImport,
1870 pbHashValue,
1871 cbHashValue,
1872 pCommonImport,
1873 tkRidFrom,
1874 &tkRidTo));
1875 }
1876 else if ( TypeFromToken(tkRidFrom) == mdtTypeSpec )
1877 {
1878 // copy over the TypeSpec
1879 PCCOR_SIGNATURE pvTypeSpecSig;
1880 ULONG cbTypeSpecSig;
1881 CQuickBytes qkTypeSpecSigEmit;
1882 ULONG cbTypeSpecEmit;
1883
1884 IfFailGo(pCommonImport->CommonGetTypeSpecProps(
1885 tkRidFrom,
1886 &pvTypeSpecSig,
1887 &cbTypeSpecSig));
1888
1889 // Translate the typespec signature before look up
1890 IfFailGo(MergeUpdateTokenInFieldSig(
1891 pMiniMdAssemEmit, // The assembly emit scope.
1892 pMiniMdEmit, // The emit scope.
1893 pCommonAssemImport, // The assembly scope where the signature is from.
1894 pbHashValue, // Hash value for the import assembly.
1895 cbHashValue, // Size in bytes for the hash value.
1896 pCommonImport, // The scope to merge into the emit scope.
1897 pvTypeSpecSig, // signature from the imported scope
1898 ptkMap, // Internal OID mapping structure.
1899 &qkTypeSpecSigEmit, // [OUT] buffer for translated signature
1900 0, // start from first byte of TypeSpec signature
1901 0, // don't care how many bytes are consumed
1902 &cbTypeSpecEmit) ); // [OUT] total number of bytes write to pqkSigEmit
1903
1904 hr = FindTypeSpec(pMiniMdEmit,
1905 (PCCOR_SIGNATURE) (qkTypeSpecSigEmit.Ptr()),
1906 cbTypeSpecEmit,
1907 &tkRidTo);
1908
1909 if ( hr == CLDB_E_RECORD_NOTFOUND )
1910 {
1911 // Create TypeSpec record.
1912 TypeSpecRec *pRecEmit;
1913
1914 IfFailGo(pMiniMdEmit->AddTypeSpecRecord(&pRecEmit, (RID *)&tkRidTo));
1915
1916 IfFailGo(pMiniMdEmit->PutBlob(
1917 TBL_TypeSpec,
1918 TypeSpecRec::COL_Signature,
1919 pRecEmit,
1920 (PCCOR_SIGNATURE) (qkTypeSpecSigEmit.Ptr()),
1921 cbTypeSpecEmit));
1922 tkRidTo = TokenFromRid( tkRidTo, mdtTypeSpec );
1923 IfFailGo(pMiniMdEmit->UpdateENCLog(tkRidTo));
1924 }
1925 IfFailGo( hr );
1926 }
1927 else
1928 {
1929 _ASSERTE( TypeFromToken(tkRidFrom) == mdtBaseType );
1930
1931 // base type is unique across module
1932 tkRidTo = tkRidFrom;
1933 }
1934 }
1935
1936 // How many bytes the new rid will consume?
1937 cb1 = CorSigCompressToken(tkRidTo, &ulData);
1938
1939 // ensure buffer is big enough
1940 IfFailGo(pqkSigEmit->ReSizeNoThrow(cbStartEmit + cbDestTotal + cb1));
1941
1942 // store the new token
1943 cb2 = CorSigCompressToken(
1944 tkRidTo,
1945 (ULONG *)( ((BYTE *)pqkSigEmit->Ptr()) + cbStartEmit + cbDestTotal) );
1946
1947 // inconsistency on CorSigCompressToken and CorSigUncompressToken
1948 _ASSERTE(cb1 == cb2);
1949
1950 cbSrcTotal = cbSrcTotal + cb;
1951 cbDestTotal = cbDestTotal + cb1;
1952
1953 if ( ulElementType == ELEMENT_TYPE_CMOD_REQD ||
1954 ulElementType == ELEMENT_TYPE_CMOD_OPT)
1955 {
1956 // need to skip over the base type
1957 IfFailGo(MergeUpdateTokenInFieldSig(
1958 pMiniMdAssemEmit, // The assembly emit scope.
1959 pMiniMdEmit, // The emit scope.
1960 pCommonAssemImport, // The assembly scope where the signature is from.
1961 pbHashValue, // Hash value for the import assembly.
1962 cbHashValue, // Size in bytes for the hash value.
1963 pCommonImport, // The scope to merge into the emit scope.
1964 &pbSigImp[cbSrcTotal], // signature from the imported scope
1965 ptkMap, // Internal OID mapping structure.
1966 pqkSigEmit, // [OUT] buffer for translated signature
1967 cbStartEmit + cbDestTotal, // [IN] start point of buffer to write to
1968 &cbImp, // [OUT] total number of bytes consumed from pbSigImp
1969 &cbEmit)); // [OUT] total number of bytes write to pqkSigEmit
1970 cbSrcTotal += cbImp;
1971 cbDestTotal += cbEmit;
1972 }
1973
1974 break;
1975 default:
1976 _ASSERTE(cbSrcTotal == cbDestTotal);
1977
1978 if ((ulElementType >= ELEMENT_TYPE_MAX) ||
1979 (ulElementType == ELEMENT_TYPE_PTR) ||
1980 (ulElementType == ELEMENT_TYPE_BYREF) ||
1981 (ulElementType == ELEMENT_TYPE_VALUEARRAY_UNSUPPORTED))
1982 {
1983 IfFailGo(META_E_BAD_SIGNATURE);
1984 }
1985 break;
1986 }
1987 if (pcbImp)
1988 *pcbImp = cbSrcTotal;
1989 *pcbEmit = cbDestTotal;
1990
1991ErrExit:
1992 return hr;
1993} // ImportHelper::MergeUpdateTokenInFieldSig
1994
1995#endif //FEATURE_METADATA_EMIT
1996
1997//****************************************************************************
1998// convert tokens contained in a COM+ signature
1999//****************************************************************************
2000HRESULT ImportHelper::MergeUpdateTokenInSig(// S_OK or error.
2001 CMiniMdRW *pMiniMdAssemEmit, // [IN] The assembly emit scope.
2002 CMiniMdRW *pMiniMdEmit, // [IN] The emit scope.
2003 IMetaModelCommon *pCommonAssemImport,// [IN] Assembly scope where the signature is from.
2004 const void *pbHashValue, // [IN] Hash value for the import assembly.
2005 ULONG cbHashValue, // [IN] Size in bytes for the hash value.
2006 IMetaModelCommon *pCommonImport, // [IN] The scope to merge into the emit scope.
2007 PCCOR_SIGNATURE pbSigImp, // signature from the imported scope
2008 MDTOKENMAP *ptkMap, // Internal OID mapping structure.
2009 CQuickBytes *pqkSigEmit, // [OUT] translated signature
2010 ULONG cbStartEmit, // [IN] start point of buffer to write to
2011 ULONG *pcbImp, // [OUT] total number of bytes consumed from pbSigImp
2012 ULONG *pcbEmit) // [OUT] total number of bytes write to pqkSigEmit
2013{
2014#ifdef FEATURE_METADATA_EMIT
2015 HRESULT hr = NOERROR; // A result.
2016 ULONG cb; // count of bytes
2017 ULONG cb1;
2018 ULONG cbSrcTotal = 0; // count of bytes consumed in the imported signature
2019 ULONG cbDestTotal = 0; // count of bytes for the new signature
2020 ULONG cbEmit; // count of bytes consumed in the imported signature
2021 ULONG cbImp; // count of bytes for the new signature
2022 ULONG cArg = 0; // count of arguments in the signature
2023 ULONG cTyArg = 0;
2024 ULONG callingconv = 0; // calling convention from signature
2025
2026 _ASSERTE(pcbEmit && pqkSigEmit && pbSigImp);
2027
2028 // calling convention
2029 cb = CorSigUncompressData(&pbSigImp[cbSrcTotal], &callingconv);
2030 _ASSERTE((callingconv & IMAGE_CEE_CS_CALLCONV_MASK) < IMAGE_CEE_CS_CALLCONV_MAX);
2031
2032 // skip over calling convention
2033 cbSrcTotal += cb;
2034
2035 if (isCallConv(callingconv, IMAGE_CEE_CS_CALLCONV_FIELD))
2036 {
2037 // It is a FieldRef
2038 cb1 = CorSigCompressData(callingconv, ((BYTE *)pqkSigEmit->Ptr()) + cbStartEmit);
2039
2040 // compression and uncompression better match
2041 _ASSERTE(cb == cb1);
2042
2043 cbDestTotal = cbSrcTotal = cb;
2044 IfFailGo(MergeUpdateTokenInFieldSig(
2045 pMiniMdAssemEmit,
2046 pMiniMdEmit,
2047 pCommonAssemImport,
2048 pbHashValue,
2049 cbHashValue,
2050 pCommonImport,
2051 &pbSigImp[cbSrcTotal],
2052 ptkMap,
2053 pqkSigEmit, // output buffer to hold the new sig for the field
2054 cbStartEmit + cbDestTotal, // number of bytes already in pqkSigDest
2055 &cbImp, // number of bytes consumed from imported signature
2056 &cbEmit)); // number of bytes write to the new signature
2057 *pcbEmit = cbDestTotal + cbEmit;
2058 }
2059 else
2060 {
2061
2062 // It is a MethodRef
2063 // count of type arguments
2064 if (callingconv & IMAGE_CEE_CS_CALLCONV_GENERIC)
2065 {
2066 cb = CorSigUncompressData(&pbSigImp[cbSrcTotal], &cTyArg);
2067 cbSrcTotal += cb;
2068 }
2069
2070 // count of argument
2071 cb = CorSigUncompressData(&pbSigImp[cbSrcTotal], &cArg);
2072 cbSrcTotal += cb;
2073
2074 // move over the calling convention and the count of arguments
2075 IfFailGo(pqkSigEmit->ReSizeNoThrow(cbStartEmit + cbSrcTotal));
2076 memcpy(((BYTE *)pqkSigEmit->Ptr()) + cbStartEmit, pbSigImp, cbSrcTotal);
2077 cbDestTotal = cbSrcTotal;
2078
2079 if ( !( isCallConv(callingconv, IMAGE_CEE_CS_CALLCONV_LOCAL_SIG) || isCallConv(callingconv, IMAGE_CEE_CS_CALLCONV_GENERICINST)) )
2080 {
2081 // LocalVar sig does not have return type
2082 // process the return type
2083 IfFailGo(MergeUpdateTokenInFieldSig(
2084 pMiniMdAssemEmit,
2085 pMiniMdEmit,
2086 pCommonAssemImport,
2087 pbHashValue,
2088 cbHashValue,
2089 pCommonImport,
2090 &pbSigImp[cbSrcTotal],
2091 ptkMap,
2092 pqkSigEmit, // output buffer to hold the new sig for the field
2093 cbStartEmit + cbDestTotal, // number of bytes already in pqkSigDest
2094 &cbImp, // number of bytes consumed from imported signature
2095 &cbEmit)); // number of bytes write to the new signature
2096
2097 // advance the count
2098 cbSrcTotal += cbImp;
2099 cbDestTotal += cbEmit;
2100 }
2101
2102
2103 while (cArg)
2104 {
2105 // process every argument
2106 IfFailGo(MergeUpdateTokenInFieldSig(
2107 pMiniMdAssemEmit,
2108 pMiniMdEmit,
2109 pCommonAssemImport,
2110 pbHashValue,
2111 cbHashValue,
2112 pCommonImport,
2113 &pbSigImp[cbSrcTotal],
2114 ptkMap,
2115 pqkSigEmit, // output buffer to hold the new sig for the field
2116 cbStartEmit + cbDestTotal,
2117 &cbImp, // number of bytes consumed from imported signature
2118 &cbEmit)); // number of bytes write to the new signature
2119 cbSrcTotal += cbImp;
2120 cbDestTotal += cbEmit;
2121 cArg--;
2122 }
2123
2124 // total of number of bytes consumed from imported signature
2125 if (pcbImp)
2126 *pcbImp = cbSrcTotal;
2127
2128 // total number of bytes emitted by this function call to the emitting signature
2129 *pcbEmit = cbDestTotal;
2130 }
2131
2132ErrExit:
2133 return hr;
2134#else //!FEATURE_METADATA_EMIT
2135 // This code should be called only with public emit APIs
2136 _ASSERTE_MSG(FALSE, "This method should not be reachable");
2137 return E_NOTIMPL;
2138#endif //!FEATURE_METADATA_EMIT
2139} // ImportHelper::MergeUpdateTokenInSig
2140
2141//****************************************************************************
2142// Given a TypeDef or a TypeRef, return the Nesting hierarchy. The first
2143// element in the returned array always refers to the class token passed and
2144// the nesting hierarchy expands outwards from there.
2145//****************************************************************************
2146HRESULT ImportHelper::GetNesterHierarchy(
2147 IMetaModelCommon *pCommon, // Scope in which to find the hierarchy.
2148 mdToken tk, // TypeDef/TypeRef whose hierarchy is needed.
2149 CQuickArray<mdToken> &cqaNesters, // Array of Nesters.
2150 CQuickArray<LPCUTF8> &cqaNamespaces, // Names of the nesters.
2151 CQuickArray<LPCUTF8> &cqaNames) // Namespaces of the nesters.
2152{
2153 _ASSERTE(pCommon &&
2154 (TypeFromToken(tk) == mdtTypeDef ||
2155 TypeFromToken(tk) == mdtTypeRef) &&
2156 !IsNilToken(tk));
2157
2158 if (TypeFromToken(tk) == mdtTypeDef)
2159 {
2160 return GetTDNesterHierarchy(pCommon,
2161 tk,
2162 cqaNesters,
2163 cqaNamespaces,
2164 cqaNames);
2165 }
2166 else
2167 {
2168 return GetTRNesterHierarchy(pCommon,
2169 tk,
2170 cqaNesters,
2171 cqaNamespaces,
2172 cqaNames);
2173 }
2174} // HRESULT ImportHelper::GetNesterHierarchy()
2175
2176//****************************************************************************
2177// Get Nesting hierarchy given a TypeDef.
2178//****************************************************************************
2179HRESULT ImportHelper::GetTDNesterHierarchy(
2180 IMetaModelCommon *pCommon, // Scope in which to find the hierarchy.
2181 mdTypeDef td, // TypeDef whose hierarchy is needed.
2182 CQuickArray<mdTypeDef> &cqaTdNesters,// Array of Nesters.
2183 CQuickArray<LPCUTF8> &cqaNamespaces, // Namespaces of the nesters.
2184 CQuickArray<LPCUTF8> &cqaNames) // Names of the nesters.
2185{
2186 LPCUTF8 szName, szNamespace;
2187 DWORD dwFlags;
2188 mdTypeDef tdNester;
2189 ULONG ulNesters;
2190 HRESULT hr = NOERROR;
2191
2192 _ASSERTE(pCommon &&
2193 TypeFromToken(td) == mdtTypeDef &&
2194 !IsNilToken(td));
2195
2196 // Set current Nester index to 0.
2197 ulNesters = 0;
2198 // The first element in the hierarchy is the TypeDef itself.
2199 tdNester = td;
2200 // Bogus initialization to kick off the while loop.
2201 dwFlags = tdNestedPublic;
2202 // Loop as long as the TypeDef is a Nested TypeDef.
2203 while (IsTdNested(dwFlags))
2204 {
2205 if (InvalidRid(tdNester))
2206 IfFailGo(CLDB_E_RECORD_NOTFOUND);
2207 // Get the name and namespace for the TypeDef.
2208 IfFailGo(pCommon->CommonGetTypeDefProps(
2209 tdNester,
2210 &szNamespace,
2211 &szName,
2212 &dwFlags,
2213 NULL,
2214 NULL));
2215
2216 // Update the dynamic arrays.
2217 ulNesters++;
2218
2219 IfFailGo(cqaTdNesters.ReSizeNoThrow(ulNesters));
2220 cqaTdNesters[ulNesters-1] = tdNester;
2221
2222 IfFailGo(cqaNamespaces.ReSizeNoThrow(ulNesters));
2223 cqaNamespaces[ulNesters-1] = szNamespace;
2224
2225 IfFailGo(cqaNames.ReSizeNoThrow(ulNesters));
2226 cqaNames[ulNesters-1] = szName;
2227
2228 IfFailGo(pCommon->CommonGetEnclosingClassOfTypeDef(tdNester, &tdNester));
2229 }
2230 // Outermost class must have enclosing of Nil.
2231 _ASSERTE(IsNilToken(tdNester));
2232ErrExit:
2233 return hr;
2234} // HRESULT ImportHelper::GetTDNesterHierarchy()
2235
2236
2237//****************************************************************************
2238// Get Nesting hierarchy given a TypeRef.
2239//****************************************************************************
2240HRESULT ImportHelper::GetTRNesterHierarchy(
2241 IMetaModelCommon *pCommon, // [IN] Scope in which to find the hierarchy.
2242 mdTypeRef tr, // [IN] TypeRef whose hierarchy is needed.
2243 CQuickArray<mdTypeRef> &cqaTrNesters,// [OUT] Array of Nesters.
2244 CQuickArray<LPCUTF8> &cqaNamespaces, // [OUT] Namespaces of the nesters.
2245 CQuickArray<LPCUTF8> &cqaNames) // [OUT] Names of the nesters.
2246{
2247 LPCUTF8 szNamespace;
2248 LPCUTF8 szName;
2249 mdTypeRef trNester;
2250 mdToken tkResolutionScope;
2251 ULONG ulNesters;
2252 HRESULT hr = S_OK;
2253
2254 _ASSERTE(pCommon &&
2255 TypeFromToken(tr) == mdtTypeRef &&
2256 !IsNilToken(tr));
2257
2258 // Set current Nester index to 0.
2259 ulNesters = 0;
2260 // The first element in the hierarchy is the TypeRef itself.
2261 trNester = tr;
2262 // Loop as long as the TypeRef is a Nested TypeRef.
2263 while (TypeFromToken(trNester) == mdtTypeRef && !IsNilToken(trNester))
2264 {
2265 // Get the name and namespace for the TypeDef.
2266 IfFailGo(pCommon->CommonGetTypeRefProps(
2267 trNester,
2268 &szNamespace,
2269 &szName,
2270 &tkResolutionScope));
2271
2272 // Update the dynamic arrays.
2273 ulNesters++;
2274
2275 IfFailGo(cqaTrNesters.ReSizeNoThrow(ulNesters));
2276 cqaTrNesters[ulNesters-1] = trNester;
2277
2278 IfFailGo(cqaNamespaces.ReSizeNoThrow(ulNesters));
2279 cqaNamespaces[ulNesters-1] = szNamespace;
2280
2281 IfFailGo(cqaNames.ReSizeNoThrow(ulNesters));
2282 cqaNames[ulNesters-1] = szName;
2283
2284 trNester = tkResolutionScope;
2285 }
2286ErrExit:
2287 return hr;
2288} // HRESULT ImportHelper::GetTRNesterHierarchy()
2289
2290//****************************************************************************
2291// Create the Nesting hierarchy given the array of TypeRef names. The first
2292// TypeRef in the array is the innermost TypeRef.
2293//****************************************************************************
2294HRESULT ImportHelper::CreateNesterHierarchy(
2295 CMiniMdRW *pMiniMdEmit, // [IN] Emit scope to create the Nesters in.
2296 CQuickArray<LPCUTF8> &cqaNesterNamespaces, // [IN] Array of Nester namespaces.
2297 CQuickArray<LPCUTF8> &cqaNesterNames, // [IN] Array of Nester names.
2298 mdToken tkResolutionScope, // [IN] ResolutionScope for the innermost TypeRef.
2299 mdTypeRef *ptr) // [OUT] Token for the innermost TypeRef.
2300{
2301 TypeRefRec *pRecEmit;
2302 ULONG iRecord;
2303 LPCUTF8 szName;
2304 LPCUTF8 szNamespace;
2305 mdTypeRef trNester;
2306 mdTypeRef trCur;
2307 ULONG ulNesters;
2308 HRESULT hr = S_OK;
2309
2310 _ASSERTE(cqaNesterNames.Size() == cqaNesterNamespaces.Size() &&
2311 cqaNesterNames.Size());
2312
2313 // Initialize the output parameter.
2314 *ptr = mdTypeRefNil;
2315
2316 // Get count of Nesters in the hierarchy.
2317 ulNesters = (ULONG)cqaNesterNames.Size();
2318
2319 // For each nester try to find the corresponding TypeRef in the emit scope.
2320 // For the outermost TypeRef, ResolutionScope is what's passed in.
2321 if (tkResolutionScope == mdTokenNil)
2322 trNester = mdTypeRefNil;
2323 else
2324 trNester = tkResolutionScope;
2325 ULONG ulCurNester;
2326 for (ulCurNester = ulNesters-1; ulCurNester != (ULONG) -1; ulCurNester--)
2327 {
2328 hr = FindTypeRefByName(pMiniMdEmit,
2329 trNester,
2330 cqaNesterNamespaces[ulCurNester],
2331 cqaNesterNames[ulCurNester],
2332 &trCur);
2333 if (hr == CLDB_E_RECORD_NOTFOUND)
2334 break;
2335 else
2336 IfFailGo(hr);
2337 trNester = trCur;
2338 }
2339 if (SUCCEEDED(hr))
2340 *ptr = trNester;
2341 else if ( hr == CLDB_E_RECORD_NOTFOUND )
2342 {
2343 // Create TypeRef records for the part of the hierarchy for which
2344 // TypeRefs are not already present.
2345 for (;ulCurNester != (ULONG) -1; ulCurNester--)
2346 {
2347 szName = cqaNesterNames[ulCurNester];
2348 szNamespace = cqaNesterNamespaces[ulCurNester];
2349
2350 IfFailGo(pMiniMdEmit->AddTypeRefRecord(&pRecEmit, &iRecord));
2351 if (szNamespace && szNamespace[0] != '\0')
2352 {
2353 // only put the namespace if it is not an empty string and not NULL
2354 IfFailGo(pMiniMdEmit->PutString(TBL_TypeRef, TypeRefRec::COL_Namespace,
2355 pRecEmit, szNamespace));
2356 }
2357 IfFailGo(pMiniMdEmit->PutString(TBL_TypeRef, TypeRefRec::COL_Name,
2358 pRecEmit, szName));
2359 IfFailGo(pMiniMdEmit->PutToken(TBL_TypeRef,
2360 TypeRefRec::COL_ResolutionScope, pRecEmit, trNester));
2361
2362 trNester = TokenFromRid(iRecord, mdtTypeRef);
2363 IfFailGo(pMiniMdEmit->UpdateENCLog(trNester));
2364
2365 // Hash the name.
2366 IfFailGo(pMiniMdEmit->AddNamedItemToHash(TBL_TypeRef, trNester, szName, 0));
2367 }
2368 *ptr = trNester;
2369 }
2370 else
2371 IfFailGo(hr);
2372ErrExit:
2373 return hr;
2374} // ImportHelper::CreateNesterHierarchy
2375
2376//****************************************************************************
2377// Given the arrays of names and namespaces for the Nested Type hierarchy,
2378// find the innermost TypeRef token. The arrays start with the innermost
2379// TypeRefs and go outwards.
2380//****************************************************************************
2381HRESULT ImportHelper::FindNestedTypeRef(
2382 CMiniMdRW *pMiniMd, // [IN] Scope in which to find the TypeRef.
2383 CQuickArray<LPCUTF8> &cqaNesterNamespaces, // [IN] Array of Names.
2384 CQuickArray<LPCUTF8> &cqaNesterNames, // [IN] Array of Namespaces.
2385 mdToken tkResolutionScope, // [IN] Resolution scope for the outermost TypeRef.
2386 mdTypeRef *ptr) // [OUT] Inner most TypeRef token.
2387{
2388 ULONG ulNesters;
2389 ULONG ulCurNester;
2390 HRESULT hr = S_OK;
2391
2392 _ASSERTE(cqaNesterNames.Size() == cqaNesterNamespaces.Size() &&
2393 cqaNesterNames.Size());
2394
2395 // Set the output parameter to Nil token.
2396 *ptr = mdTokenNil;
2397
2398 // Get count in the hierarchy, the give TypeDef included.
2399 ulNesters = (ULONG)cqaNesterNames.Size();
2400
2401 // For each nester try to find the corresponding TypeRef in
2402 // the emit scope. For the outermost TypeDef enclosing class is Nil.
2403 for (ulCurNester = ulNesters-1; ulCurNester != (ULONG) -1; ulCurNester--)
2404 {
2405 IfFailGo(FindTypeRefByName(pMiniMd,
2406 tkResolutionScope,
2407 cqaNesterNamespaces[ulCurNester],
2408 cqaNesterNames[ulCurNester],
2409 &tkResolutionScope));
2410 }
2411 *ptr = tkResolutionScope;
2412ErrExit:
2413 return hr;
2414} // HRESULT ImportHelper::FindNestedTypeRef()
2415
2416
2417//****************************************************************************
2418// Given the arrays of names and namespaces for the Nested Type hierarchy,
2419// find the innermost TypeDef token. The arrays start with the innermost
2420// TypeDef and go outwards.
2421//****************************************************************************
2422HRESULT ImportHelper::FindNestedTypeDef(
2423 CMiniMdRW *pMiniMd, // [IN] Scope in which to find the TypeRef.
2424 CQuickArray<LPCUTF8> &cqaNesterNamespaces, // [IN] Array of Namespaces.
2425 CQuickArray<LPCUTF8> &cqaNesterNames, // [IN] Array of Names.
2426 mdTypeDef tdNester, // [IN] Enclosing class for the Outermost TypeDef.
2427 mdTypeDef *ptd) // [OUT] Inner most TypeRef token.
2428{
2429 ULONG ulNesters;
2430 ULONG ulCurNester;
2431 HRESULT hr = S_OK;
2432
2433 _ASSERTE(cqaNesterNames.Size() == cqaNesterNamespaces.Size() &&
2434 cqaNesterNames.Size());
2435
2436 // Set the output parameter to Nil token.
2437 *ptd = mdTokenNil;
2438
2439 // Get count in the hierarchy, the give TypeDef included.
2440 ulNesters = (ULONG)cqaNesterNames.Size();
2441
2442 // For each nester try to find the corresponding TypeRef in
2443 // the emit scope. For the outermost TypeDef enclosing class is Nil.
2444 for (ulCurNester = ulNesters-1; ulCurNester != (ULONG) -1; ulCurNester--)
2445 {
2446 IfFailGo(FindTypeDefByName(pMiniMd,
2447 cqaNesterNamespaces[ulCurNester],
2448 cqaNesterNames[ulCurNester],
2449 tdNester,
2450 &tdNester));
2451 }
2452 *ptd = tdNester;
2453ErrExit:
2454 return hr;
2455} // ImportHelper::FindNestedTypeDef
2456
2457#ifdef FEATURE_METADATA_EMIT
2458
2459//****************************************************************************
2460// Given the TypeDef and the corresponding assembly and module import scopes,
2461// create a corresponding TypeRef in the given emit scope.
2462//****************************************************************************
2463HRESULT
2464ImportHelper::ImportTypeDef(
2465 CMiniMdRW * pMiniMdAssemEmit, // [IN] Assembly emit scope.
2466 CMiniMdRW * pMiniMdEmit, // [IN] Module emit scope.
2467 IMetaModelCommon * pCommonAssemImport, // [IN] Assembly import scope.
2468 const void * pbHashValue, // [IN] Hash value for import assembly.
2469 ULONG cbHashValue, // [IN] Size in bytes of hash value.
2470 IMetaModelCommon * pCommonImport, // [IN] Module import scope.
2471 mdTypeDef tdImport, // [IN] Imported TypeDef.
2472 bool bReturnTd, // [IN] If the import and emit scopes are identical, return the TypeDef.
2473 mdToken * ptkType) // [OUT] Output token for the imported type in the emit scope.
2474{
2475 CQuickArray<mdTypeDef> cqaNesters;
2476 CQuickArray<LPCUTF8> cqaNesterNames;
2477 CQuickArray<LPCUTF8> cqaNesterNamespaces;
2478 GUID nullguid = GUID_NULL;
2479 GUID MvidAssemImport = nullguid;
2480 GUID MvidAssemEmit = nullguid;
2481 GUID MvidImport = nullguid;
2482 GUID MvidEmit = nullguid;
2483 GUID GuidImport = GUID_NULL;
2484 LPCUTF8 szModuleImport;
2485 mdToken tkOuterRes = mdTokenNil;
2486 HRESULT hr = S_OK;
2487 BOOL bBCL = false;
2488
2489 _ASSERTE(pMiniMdEmit && pCommonImport && ptkType);
2490 _ASSERTE(TypeFromToken(tdImport) == mdtTypeDef && tdImport != mdTypeDefNil);
2491
2492 // Get MVIDs for import and emit, assembly and module scopes.
2493 if (pCommonAssemImport != NULL)
2494 {
2495 IfFailGo(pCommonAssemImport->CommonGetScopeProps(0, &MvidAssemImport));
2496 }
2497 IfFailGo(pCommonImport->CommonGetScopeProps(&szModuleImport, &MvidImport));
2498 if (pMiniMdAssemEmit != NULL)
2499 {
2500 IfFailGo(static_cast<IMetaModelCommon*>(pMiniMdAssemEmit)->CommonGetScopeProps(0, &MvidAssemEmit));
2501 }
2502 IfFailGo(static_cast<IMetaModelCommon*>(pMiniMdEmit)->CommonGetScopeProps(0, &MvidEmit));
2503
2504 if (pCommonAssemImport == NULL && strcmp(szModuleImport, COM_RUNTIME_LIBRARY) == 0)
2505 {
2506 const BYTE *pBlob; // Blob with dispid.
2507 ULONG cbBlob; // Length of blob.
2508 WCHAR wzBlob[40]; // Wide char format of guid.
2509 int ix; // Loop control.
2510
2511 hr = pCommonImport->CommonGetCustomAttributeByName(1, INTEROP_GUID_TYPE, (const void **)&pBlob, &cbBlob);
2512 if (hr != S_FALSE)
2513 {
2514 // Should be in format. Total length == 41
2515 // <0x0001><0x24>01234567-0123-0123-0123-001122334455<0x0000>
2516 if ((cbBlob == 41) || (GET_UNALIGNED_VAL16(pBlob) == 1))
2517 {
2518 for (ix=1; ix<=36; ++ix)
2519 wzBlob[ix] = pBlob[ix+2];
2520 wzBlob[0] = '{';
2521 wzBlob[37] = '}';
2522 wzBlob[38] = 0;
2523 // It's ok that we ignore the hr here. It's not needed, but I
2524 // don't want to remove it in case a code analysis tool will complain
2525 // about not capturing return codes.
2526 hr = IIDFromString(wzBlob, &GuidImport);
2527 }
2528 }
2529 bBCL = (GuidImport == LIBID_ComPlusRuntime);
2530 }
2531
2532 // Compute the ResolutionScope for the imported type.
2533 if (bBCL)
2534 {
2535 // This is the case that we are referring to mscorlib.dll but client does not provide the manifest for
2536 // mscorlib.dll!! Do not generate ModuleRef to the mscorlib.dll. But instead we should just leave the
2537 // ResolutionScope empty
2538 tkOuterRes = mdTokenNil;
2539 }
2540 else if (MvidAssemImport == MvidAssemEmit && MvidImport == MvidEmit)
2541 {
2542 // The TypeDef is in the same Assembly and the Same scope.
2543 if (bReturnTd)
2544 {
2545 *ptkType = tdImport;
2546 goto ErrExit;
2547 }
2548 else
2549 tkOuterRes = TokenFromRid(1, mdtModule);
2550 }
2551 else if (MvidAssemImport == MvidAssemEmit && MvidImport != MvidEmit)
2552 {
2553 // The TypeDef is in the same Assembly but a different module.
2554
2555 // Create a ModuleRef corresponding to the import scope.
2556 IfFailGo(CreateModuleRefFromScope(pMiniMdEmit, pCommonImport, &tkOuterRes));
2557 }
2558 else if (MvidAssemImport != MvidAssemEmit)
2559 {
2560 if (pCommonAssemImport)
2561 {
2562 // The TypeDef is from a different Assembly.
2563
2564 // Import and Emit scopes can't be identical and be from different
2565 // Assemblies at the same time.
2566 _ASSERTE(MvidImport != MvidEmit &&
2567 "Import scope can't be identical to the Emit scope and be from a different Assembly at the same time.");
2568
2569 _ASSERTE(pCommonAssemImport);
2570
2571 // Create an AssemblyRef corresponding to the import scope.
2572 IfFailGo(CreateAssemblyRefFromAssembly(pMiniMdAssemEmit,
2573 pMiniMdEmit,
2574 pCommonAssemImport,
2575 pbHashValue,
2576 cbHashValue,
2577 &tkOuterRes));
2578 }
2579 else
2580 {
2581 // <REVISIT_TODO>@FUTURE: review this fix! We may want to return error in the future.
2582 // This is to enable smc to reference mscorlib.dll while it does not have the manifest for mscorlib.dll opened.</REVISIT_TODO>
2583 // Create a Nil ResolutionScope to the TypeRef.
2584 tkOuterRes = mdTokenNil;
2585 }
2586 }
2587
2588 // Get the nesting hierarchy for the Type from the import scope and create
2589 // the corresponding Type hierarchy in the emit scope. Note that the non-
2590 // nested class case simply folds into this scheme.
2591
2592 IfFailGo(GetNesterHierarchy(pCommonImport,
2593 tdImport,
2594 cqaNesters,
2595 cqaNesterNamespaces,
2596 cqaNesterNames));
2597
2598 IfFailGo(CreateNesterHierarchy(pMiniMdEmit,
2599 cqaNesterNamespaces,
2600 cqaNesterNames,
2601 tkOuterRes,
2602 ptkType));
2603ErrExit:
2604 return hr;
2605} // ImportHelper::ImportTypeDef
2606
2607//****************************************************************************
2608// Given the TypeRef and the corresponding assembly and module import scopes,
2609// return the corresponding token in the given emit scope.
2610// <REVISIT_TODO>@FUTURE: Should we look at visibility flags on ExportedTypes and TypeDefs when
2611// handling references across Assemblies?</REVISIT_TODO>
2612//****************************************************************************
2613HRESULT ImportHelper::ImportTypeRef(
2614 CMiniMdRW *pMiniMdAssemEmit, // [IN] Assembly emit scope.
2615 CMiniMdRW *pMiniMdEmit, // [IN] Module emit scope.
2616 IMetaModelCommon *pCommonAssemImport, // [IN] Assembly import scope.
2617 const void *pbHashValue, // [IN] Hash value for import assembly.
2618 ULONG cbHashValue, // [IN] Size in bytes of hash value.
2619 IMetaModelCommon *pCommonImport, // [IN] Module import scope.
2620 mdTypeRef trImport, // [IN] Imported TypeRef.
2621 mdToken *ptkType) // [OUT] Output token for the imported type in the emit scope.
2622{
2623 CQuickArray<mdTypeDef> cqaNesters;
2624 CQuickArray<LPCUTF8> cqaNesterNames;
2625 CQuickArray<LPCUTF8> cqaNesterNamespaces;
2626 LPCUTF8 szScopeNameEmit;
2627 GUID nullguid = GUID_NULL;
2628 GUID MvidAssemImport = nullguid;
2629 GUID MvidAssemEmit = nullguid;
2630 GUID MvidImport = nullguid;
2631 GUID MvidEmit = nullguid;
2632 mdToken tkOuterImportRes; // ResolutionScope for the outermost TypeRef in import scope.
2633 mdToken tkOuterEmitRes = mdTokenNil; // ResolutionScope for outermost TypeRef in emit scope.
2634 HRESULT hr = S_OK;
2635 bool bAssemblyRefFromAssemScope = false;
2636
2637 _ASSERTE(pMiniMdEmit && pCommonImport && ptkType);
2638 _ASSERTE(TypeFromToken(trImport) == mdtTypeRef);
2639
2640 // Get MVIDs for import and emit, assembly and module scopes.
2641 if (pCommonAssemImport != NULL)
2642 {
2643 IfFailGo(pCommonAssemImport->CommonGetScopeProps(0, &MvidAssemImport));
2644 }
2645 IfFailGo(pCommonImport->CommonGetScopeProps(0, &MvidImport));
2646 if (pMiniMdAssemEmit != NULL)
2647 {
2648 IfFailGo(static_cast<IMetaModelCommon*>(pMiniMdAssemEmit)->CommonGetScopeProps(
2649 0,
2650 &MvidAssemEmit));
2651 }
2652 IfFailGo(static_cast<IMetaModelCommon*>(pMiniMdEmit)->CommonGetScopeProps(
2653 &szScopeNameEmit,
2654 &MvidEmit));
2655
2656 // Get the outermost resolution scope for the TypeRef being imported.
2657 IfFailGo(GetNesterHierarchy(pCommonImport,
2658 trImport,
2659 cqaNesters,
2660 cqaNesterNamespaces,
2661 cqaNesterNames));
2662 IfFailGo(pCommonImport->CommonGetTypeRefProps(
2663 cqaNesters[cqaNesters.Size() - 1],
2664 0,
2665 0,
2666 &tkOuterImportRes));
2667
2668 // Compute the ResolutionScope for the imported type.
2669 if (MvidAssemImport == MvidAssemEmit && MvidImport == MvidEmit)
2670 {
2671 *ptkType = trImport;
2672 goto ErrExit;
2673 }
2674 else if (MvidAssemImport == MvidAssemEmit && MvidImport != MvidEmit)
2675 {
2676 // The TypeRef is in the same Assembly but a different module.
2677
2678 if (IsNilToken(tkOuterImportRes))
2679 {
2680 tkOuterEmitRes = tkOuterImportRes;
2681 }
2682 else if (TypeFromToken(tkOuterImportRes) == mdtModule)
2683 {
2684 // TypeRef resolved to the import module in which its defined.
2685
2686 //
2687 if (pMiniMdAssemEmit == NULL && pCommonAssemImport == NULL)
2688 {
2689 tkOuterEmitRes = TokenFromRid(1, mdtModule);
2690 }
2691 else
2692 {
2693 // Create a ModuleRef corresponding to the import scope.
2694 IfFailGo(CreateModuleRefFromScope(pMiniMdEmit,
2695 pCommonImport,
2696 &tkOuterEmitRes));
2697 }
2698 }
2699 else if (TypeFromToken(tkOuterImportRes) == mdtAssemblyRef)
2700 {
2701 // TypeRef is from a different Assembly.
2702
2703 // Create a corresponding AssemblyRef in the emit scope.
2704 IfFailGo(CreateAssemblyRefFromAssemblyRef(pMiniMdAssemEmit,
2705 pMiniMdEmit,
2706 pCommonImport,
2707 tkOuterImportRes,
2708 &tkOuterEmitRes));
2709 }
2710 else if (TypeFromToken(tkOuterImportRes) == mdtModuleRef)
2711 {
2712 // Get Name of the ModuleRef.
2713 LPCUTF8 szMRName;
2714 IfFailGo(pCommonImport->CommonGetModuleRefProps(tkOuterImportRes, &szMRName));
2715
2716 if (!strcmp(szMRName, szScopeNameEmit))
2717 {
2718 // ModuleRef from import scope resolves to the emit scope.
2719 tkOuterEmitRes = TokenFromRid(1, mdtModule);
2720 }
2721 else
2722 {
2723 // ModuleRef does not correspond to the emit scope.
2724 // Create a corresponding ModuleRef.
2725 IfFailGo(CreateModuleRefFromModuleRef(pMiniMdEmit,
2726 pCommonImport,
2727 tkOuterImportRes,
2728 &tkOuterEmitRes));
2729 }
2730 }
2731 }
2732 else if (MvidAssemImport != MvidAssemEmit)
2733 {
2734 // The TypeDef is from a different Assembly.
2735
2736 // Import and Emit scopes can't be identical and be from different
2737 // Assemblies at the same time.
2738 _ASSERTE(MvidImport != MvidEmit &&
2739 "Import scope can't be identical to the Emit scope and be from a different Assembly at the same time.");
2740
2741 mdToken tkImplementation; // Implementation token for ExportedType.
2742 if (IsNilToken(tkOuterImportRes))
2743 {
2744 // <REVISIT_TODO>BUG FIX:: URT 13626
2745 // Well, before all of the clients generate AR for mscorlib.dll reference, it is not true
2746 // that tkOuterImportRes == nil will imply that we have to find such an entry in the import manifest!!</REVISIT_TODO>
2747
2748 // Look for a ExportedType entry in the import Assembly. Its an error
2749 // if we don't find a ExportedType entry.
2750 mdExportedType tkExportedType;
2751 hr = pCommonAssemImport->CommonFindExportedType(
2752 cqaNesterNamespaces[cqaNesters.Size() - 1],
2753 cqaNesterNames[cqaNesters.Size() - 1],
2754 mdTokenNil,
2755 &tkExportedType);
2756 if (SUCCEEDED(hr))
2757 {
2758 IfFailGo(pCommonAssemImport->CommonGetExportedTypeProps(
2759 tkExportedType,
2760 NULL,
2761 NULL,
2762 &tkImplementation));
2763 if (TypeFromToken(tkImplementation) == mdtFile)
2764 {
2765 // Type is from a different Assembly.
2766 IfFailGo(CreateAssemblyRefFromAssembly(pMiniMdAssemEmit,
2767 pMiniMdEmit,
2768 pCommonAssemImport,
2769 pbHashValue,
2770 cbHashValue,
2771 &tkOuterEmitRes));
2772 }
2773 else if (TypeFromToken(tkImplementation) == mdtAssemblyRef)
2774 {
2775 // This folds into the case where the Type is AssemblyRef. So
2776 // let it fall through to that case.
2777
2778 // Remember that this AssemblyRef token is actually from the Manifest scope not
2779 // the module scope!!!
2780 bAssemblyRefFromAssemScope = true;
2781 tkOuterImportRes = tkImplementation;
2782 }
2783 else
2784 _ASSERTE(!"Unexpected ExportedType implementation token.");
2785 }
2786 else
2787 {
2788 // In this case, we will just move over the TypeRef with Nil ResolutionScope.
2789 hr = NOERROR;
2790 tkOuterEmitRes = mdTokenNil;
2791 }
2792 }
2793 else if (TypeFromToken(tkOuterImportRes) == mdtModule)
2794 {
2795 // Type is from a different Assembly.
2796 IfFailGo(CreateAssemblyRefFromAssembly(pMiniMdAssemEmit,
2797 pMiniMdEmit,
2798 pCommonAssemImport,
2799 pbHashValue,
2800 cbHashValue,
2801 &tkOuterEmitRes));
2802 }
2803 // Not else if, because mdtModule case above could change
2804 // tkOuterImportRes to an AssemblyRef.
2805 if (TypeFromToken(tkOuterImportRes) == mdtAssemblyRef)
2806 {
2807 // If there is an emit assembly, see if the import assembly ref points to
2808 // it. If there is no emit assembly, the import assembly, by definition,
2809 // does not point to this one.
2810 if (pMiniMdAssemEmit == NULL || !pMiniMdAssemEmit->getCountAssemblys())
2811 hr = S_FALSE;
2812 else
2813 {
2814 if (bAssemblyRefFromAssemScope)
2815 {
2816 // Check to see if the AssemblyRef resolves to the emit assembly.
2817 IfFailGo(CompareAssemblyRefToAssembly(pCommonAssemImport,
2818 tkOuterImportRes,
2819 static_cast<IMetaModelCommon*>(pMiniMdAssemEmit)));
2820
2821 }
2822 else
2823 {
2824 // Check to see if the AssemblyRef resolves to the emit assembly.
2825 IfFailGo(CompareAssemblyRefToAssembly(pCommonImport,
2826 tkOuterImportRes,
2827 static_cast<IMetaModelCommon*>(pMiniMdAssemEmit)));
2828 }
2829 }
2830 if (hr == S_OK)
2831 {
2832 // The TypeRef being imported is defined in the current Assembly.
2833
2834 // Find the ExportedType for the outermost TypeRef in the Emit assembly.
2835 mdExportedType tkExportedType;
2836
2837 hr = FindExportedType(pMiniMdAssemEmit,
2838 cqaNesterNamespaces[cqaNesters.Size() - 1],
2839 cqaNesterNames[cqaNesters.Size() - 1],
2840 mdTokenNil, // Enclosing ExportedType.
2841 &tkExportedType);
2842 if (hr == S_OK)
2843 {
2844 // Create a ModuleRef based on the File name for the ExportedType.
2845 // If the ModuleRef corresponds to pMiniMdEmit, the function
2846 // will return S_FALSE, in which case set tkOuterEmitRes to
2847 // the Module token.
2848 hr = CreateModuleRefFromExportedType(pMiniMdAssemEmit,
2849 pMiniMdEmit,
2850 tkExportedType,
2851 &tkOuterEmitRes);
2852 if (hr == S_FALSE)
2853 tkOuterEmitRes = TokenFromRid(1, mdtModule);
2854 else
2855 IfFailGo(hr);
2856 }
2857 else if (hr == CLDB_E_RECORD_NOTFOUND)
2858 {
2859 // Find the Type in the Assembly emit scope to cover the
2860 // case where ExportedTypes may be implicitly defined. Its an
2861 // error if we can't find the Type at this point.
2862 IfFailGo(FindTypeDefByName(pMiniMdAssemEmit,
2863 cqaNesterNamespaces[cqaNesters.Size() - 1],
2864 cqaNesterNames[cqaNesters.Size() - 1],
2865 mdTokenNil, // Enclosing Type.
2866 &tkOuterEmitRes));
2867 tkOuterEmitRes = TokenFromRid(1, mdtModule);
2868 }
2869 else
2870 {
2871 _ASSERTE(FAILED(hr));
2872 IfFailGo(hr);
2873 }
2874 }
2875 else if (hr == S_FALSE)
2876 {
2877 // The TypeRef being imported is from a different Assembly.
2878
2879 if (bAssemblyRefFromAssemScope)
2880 {
2881 // Create a corresponding AssemblyRef.
2882 IfFailGo(CreateAssemblyRefFromAssemblyRef(pMiniMdAssemEmit,
2883 pMiniMdEmit,
2884 pCommonAssemImport,
2885 tkOuterImportRes,
2886 &tkOuterEmitRes));
2887 }
2888 else
2889 {
2890 // Create a corresponding AssemblyRef.
2891 IfFailGo(CreateAssemblyRefFromAssemblyRef(pMiniMdAssemEmit,
2892 pMiniMdEmit,
2893 pCommonImport,
2894 tkOuterImportRes,
2895 &tkOuterEmitRes));
2896 }
2897 }
2898 else
2899 {
2900 _ASSERTE(FAILED(hr));
2901 IfFailGo(hr);
2902 }
2903 }
2904 else if (TypeFromToken(tkOuterImportRes) == mdtModuleRef)
2905 {
2906 // Type is from a different Assembly.
2907 IfFailGo(CreateAssemblyRefFromAssembly(pMiniMdAssemEmit,
2908 pMiniMdEmit,
2909 pCommonAssemImport,
2910 pbHashValue,
2911 cbHashValue,
2912 &tkOuterEmitRes));
2913 }
2914 }
2915
2916 // Try to find the TypeDef in the emit scope. If we cannot find the
2917 // typedef, we need to introduce a typeref.
2918
2919 // See if the Nested TypeDef is present in the Emit scope.
2920 hr = CLDB_E_RECORD_NOTFOUND;
2921 if (TypeFromToken(tkOuterEmitRes) == mdtModule && !IsNilToken(tkOuterEmitRes))
2922 {
2923 hr = FindNestedTypeDef(pMiniMdEmit,
2924 cqaNesterNamespaces,
2925 cqaNesterNames,
2926 mdTokenNil,
2927 ptkType);
2928
2929 // <REVISIT_TODO>cannot assert now!! Due to the IJW workaround!
2930 // _ASSERTE(SUCCEEDED(hr));</REVISIT_TODO>
2931 }
2932
2933 if (hr == CLDB_E_RECORD_NOTFOUND)
2934 {
2935 IfFailGo(CreateNesterHierarchy(pMiniMdEmit,
2936 cqaNesterNamespaces,
2937 cqaNesterNames,
2938 tkOuterEmitRes,
2939 ptkType));
2940 }
2941 else
2942 IfFailGo(hr);
2943ErrExit:
2944 return hr;
2945} // ImportHelper::ImportTypeRef
2946
2947//******************************************************************************
2948// Given import scope, create a corresponding ModuleRef.
2949//******************************************************************************
2950HRESULT ImportHelper::CreateModuleRefFromScope( // S_OK or error.
2951 CMiniMdRW *pMiniMdEmit, // [IN] Emit scope in which the ModuleRef is to be created.
2952 IMetaModelCommon *pCommonImport, // [IN] Import scope.
2953 mdModuleRef *ptkModuleRef) // [OUT] Output token for ModuleRef.
2954{
2955 HRESULT hr = S_OK;
2956 LPCSTR szName;
2957 ModuleRefRec *pRecordEmit;
2958 RID iRecordEmit;
2959
2960 // Set output to nil.
2961 *ptkModuleRef = mdTokenNil;
2962
2963 // Get name of import scope.
2964 IfFailGo(pCommonImport->CommonGetScopeProps(&szName, 0));
2965
2966 // See if the ModuleRef exists in the Emit scope.
2967 hr = FindModuleRef(pMiniMdEmit, szName, ptkModuleRef);
2968
2969 if (hr == CLDB_E_RECORD_NOTFOUND)
2970 {
2971 if (szName[0] == '\0')
2972 {
2973 // It the referenced Module does not have a proper name, use the nil token instead.
2974 LOG((LOGMD, "WARNING!!! MD ImportHelper::CreatemoduleRefFromScope but scope does not have a proper name!!!!"));
2975
2976 // clear the error
2977 hr = NOERROR;
2978
2979 // It is a bug to create an ModuleRef to an empty name!!!
2980 *ptkModuleRef = mdTokenNil;
2981 }
2982 else
2983 {
2984 // Create ModuleRef record and set the output parameter.
2985 IfFailGo(pMiniMdEmit->AddModuleRefRecord(&pRecordEmit, &iRecordEmit));
2986 *ptkModuleRef = TokenFromRid(iRecordEmit, mdtModuleRef);
2987 IfFailGo(pMiniMdEmit->UpdateENCLog(*ptkModuleRef));
2988
2989 // It is a bug to create an ModuleRef to mscorlib.dll
2990 _ASSERTE(strcmp(szName, COM_RUNTIME_LIBRARY) != 0);
2991
2992 // Set the name of ModuleRef.
2993 IfFailGo(pMiniMdEmit->PutString(TBL_ModuleRef, ModuleRefRec::COL_Name,
2994 pRecordEmit, szName));
2995 }
2996 }
2997 else
2998 IfFailGo(hr);
2999ErrExit:
3000 return hr;
3001} // ImportHelper::CreateModuleRefFromScope
3002
3003
3004//******************************************************************************
3005// Given an import scope and a ModuleRef, create a corresponding ModuleRef in
3006// the given emit scope.
3007//******************************************************************************
3008HRESULT ImportHelper::CreateModuleRefFromModuleRef( // S_OK or error.
3009 CMiniMdRW *pMiniMdEmit, // [IN] Emit scope.
3010 IMetaModelCommon *pCommon, // [IN] Import scope.
3011 mdModuleRef tkModuleRef, // [IN] ModuleRef token.
3012 mdModuleRef *ptkModuleRef) // [OUT] ModuleRef token in the emit scope.
3013{
3014 HRESULT hr = S_OK;
3015 LPCSTR szName;
3016 ModuleRefRec *pRecord;
3017 RID iRecord;
3018
3019 // Set output to Nil.
3020 *ptkModuleRef = mdTokenNil;
3021
3022 // Get name of the ModuleRef being imported.
3023 IfFailGo(pCommon->CommonGetModuleRefProps(tkModuleRef, &szName));
3024
3025 // See if the ModuleRef exist in the Emit scope.
3026 hr = FindModuleRef(pMiniMdEmit, szName, ptkModuleRef);
3027
3028 if (hr == CLDB_E_RECORD_NOTFOUND)
3029 {
3030 // Create ModuleRef record and set the output parameter.
3031 IfFailGo(pMiniMdEmit->AddModuleRefRecord(&pRecord, &iRecord));
3032 *ptkModuleRef = TokenFromRid(iRecord, mdtModuleRef);
3033 IfFailGo(pMiniMdEmit->UpdateENCLog(*ptkModuleRef));
3034
3035 // Set the name of ModuleRef.
3036 IfFailGo(pMiniMdEmit->PutString(TBL_ModuleRef, ModuleRefRec::COL_Name,
3037 pRecord, szName));
3038 }
3039 else
3040 {
3041 IfFailGo(hr);
3042 }
3043ErrExit:
3044 return hr;
3045} // ImportHelper::CreateModuleRefFromModuleRef
3046
3047
3048//******************************************************************************
3049// Given a ExportedType and the Assembly emit scope, create a corresponding ModuleRef
3050// in the give emit scope. The ExportedType being passed in must belong to the
3051// Assembly passed in. Function returns S_FALSE if the ExportedType is implemented
3052// by the emit scope passed in.
3053//******************************************************************************
3054HRESULT ImportHelper::CreateModuleRefFromExportedType( // S_OK or error.
3055 CMiniMdRW *pAssemEmit, // [IN] Import assembly scope.
3056 CMiniMdRW *pMiniMdEmit, // [IN] Emit scope.
3057 mdExportedType tkExportedType, // [IN] ExportedType token in Assembly emit scope.
3058 mdModuleRef *ptkModuleRef) // [OUT] ModuleRef token in the emit scope.
3059{
3060 mdFile tkFile;
3061 LPCUTF8 szFile;
3062 LPCUTF8 szScope;
3063 FileRec *pFileRec;
3064 HRESULT hr = S_OK;
3065
3066 // Set output to nil.
3067 *ptkModuleRef = mdTokenNil;
3068
3069 // Get the implementation token for the ExportedType. It must be a File token
3070 // since the caller should call this function only on ExportedTypes that resolve
3071 // to the same Assembly.
3072 IfFailGo(static_cast<IMetaModelCommon*>(pAssemEmit)->CommonGetExportedTypeProps(
3073 tkExportedType,
3074 NULL,
3075 NULL,
3076 &tkFile));
3077 _ASSERTE(TypeFromToken(tkFile) == mdtFile);
3078
3079 // Get the name of the file.
3080 IfFailGo(pAssemEmit->GetFileRecord(RidFromToken(tkFile), &pFileRec));
3081 IfFailGo(pAssemEmit->getNameOfFile(pFileRec, &szFile));
3082
3083 // Get the name of the emit scope.
3084 IfFailGo(static_cast<IMetaModelCommon*>(pMiniMdEmit)->CommonGetScopeProps(
3085 &szScope,
3086 0));
3087
3088 // If the file corresponds to the emit scope, return S_FALSE;
3089 if (!strcmp(szFile, szScope))
3090 return S_FALSE;
3091
3092 // See if a ModuleRef exists with this name.
3093 hr = FindModuleRef(pMiniMdEmit, szFile, ptkModuleRef);
3094
3095 if (hr == CLDB_E_RECORD_NOTFOUND)
3096 {
3097 // Create ModuleRef record and set the output parameter.
3098
3099 ModuleRefRec *pRecord;
3100 RID iRecord;
3101
3102 IfFailGo(pMiniMdEmit->AddModuleRefRecord(&pRecord, &iRecord));
3103 *ptkModuleRef = TokenFromRid(iRecord, mdtModuleRef);
3104 IfFailGo(pMiniMdEmit->UpdateENCLog(*ptkModuleRef));
3105
3106 // Set the name of ModuleRef.
3107 IfFailGo(pMiniMdEmit->PutString(TBL_ModuleRef, ModuleRefRec::COL_Name,
3108 pRecord, szFile));
3109 }
3110 else
3111 IfFailGo(hr);
3112ErrExit:
3113 return hr;
3114} // ImportHelper::CreateModuleRefFromExportedType
3115
3116//******************************************************************************
3117// Given an AssemblyRef and the corresponding scope, create an AssemblyRef in
3118// the given Module scope and Assembly scope.
3119//******************************************************************************
3120HRESULT ImportHelper::CreateAssemblyRefFromAssemblyRef(
3121 CMiniMdRW *pMiniMdAssemEmit, // [IN] Assembly emit scope.
3122 CMiniMdRW *pMiniMdModuleEmit, // [IN] Module emit scope
3123 IMetaModelCommon *pCommonImport, // [IN] Scope to import the assembly ref from.
3124 mdAssemblyRef tkAssemRef, // [IN] Assembly ref to be imported.
3125 mdAssemblyRef *ptkAssemblyRef) // [OUT] AssemblyRef in the emit scope.
3126{
3127 AssemblyRefRec *pRecordEmit;
3128 CMiniMdRW *rMiniMdRW[2];
3129 CMiniMdRW *pMiniMdEmit;
3130 RID iRecordEmit;
3131 USHORT usMajorVersion;
3132 USHORT usMinorVersion;
3133 USHORT usBuildNumber;
3134 USHORT usRevisionNumber;
3135 DWORD dwFlags;
3136 const void *pbPublicKeyOrToken;
3137 ULONG cbPublicKeyOrToken;
3138 LPCUTF8 szName;
3139 LPCUTF8 szLocale;
3140 const void *pbHashValue;
3141 ULONG cbHashValue;
3142 HRESULT hr = S_OK;
3143
3144 // Set output to Nil.
3145 *ptkAssemblyRef = mdTokenNil;
3146
3147 // Get import AssemblyRef props.
3148 IfFailGo(pCommonImport->CommonGetAssemblyRefProps(
3149 tkAssemRef,
3150 &usMajorVersion, &usMinorVersion, &usBuildNumber, &usRevisionNumber,
3151 &dwFlags, &pbPublicKeyOrToken, &cbPublicKeyOrToken,
3152 &szName, &szLocale,
3153 &pbHashValue, &cbHashValue));
3154
3155 // Create the AssemblyRef in both the Assembly and Module emit scopes.
3156 rMiniMdRW[0] = pMiniMdAssemEmit;
3157 rMiniMdRW[1] = pMiniMdModuleEmit;
3158
3159 for (ULONG i = 0; i < 2; i++)
3160 {
3161 pMiniMdEmit = rMiniMdRW[i];
3162
3163 if (!pMiniMdEmit)
3164 continue;
3165
3166 // See if the AssemblyRef already exists in the emit scope.
3167 hr = FindAssemblyRef(pMiniMdEmit, szName, szLocale, pbPublicKeyOrToken,
3168 cbPublicKeyOrToken, usMajorVersion, usMinorVersion,
3169 usBuildNumber, usRevisionNumber, dwFlags, &tkAssemRef);
3170 if (hr == CLDB_E_RECORD_NOTFOUND)
3171 {
3172 // Create the AssemblyRef record and set the output parameter.
3173 IfFailGo(pMiniMdEmit->AddAssemblyRefRecord(&pRecordEmit, &iRecordEmit));
3174 tkAssemRef = TokenFromRid(iRecordEmit, mdtAssemblyRef);
3175 IfFailGo(pMiniMdEmit->UpdateENCLog(tkAssemRef));
3176
3177 // Set parameters derived from the import Assembly.
3178 pRecordEmit->SetMajorVersion(usMajorVersion);
3179 pRecordEmit->SetMinorVersion(usMinorVersion);
3180 pRecordEmit->SetBuildNumber(usBuildNumber);
3181 pRecordEmit->SetRevisionNumber(usRevisionNumber);
3182 pRecordEmit->SetFlags(dwFlags);
3183
3184 IfFailGo(pMiniMdEmit->PutBlob(TBL_AssemblyRef, AssemblyRefRec::COL_PublicKeyOrToken,
3185 pRecordEmit, pbPublicKeyOrToken, cbPublicKeyOrToken));
3186 IfFailGo(pMiniMdEmit->PutString(TBL_AssemblyRef, AssemblyRefRec::COL_Name,
3187 pRecordEmit, szName));
3188 IfFailGo(pMiniMdEmit->PutString(TBL_AssemblyRef, AssemblyRefRec::COL_Locale,
3189 pRecordEmit, szLocale));
3190
3191 // Set the parameters passed in for the AssemblyRef.
3192 IfFailGo(pMiniMdEmit->PutBlob(TBL_AssemblyRef, AssemblyRefRec::COL_HashValue,
3193 pRecordEmit, pbHashValue, cbHashValue));
3194 }
3195 else
3196 IfFailGo(hr);
3197
3198 // Set the output parameter for the AssemblyRef emitted in Module emit scope.
3199 if (i)
3200 *ptkAssemblyRef = tkAssemRef;
3201 }
3202ErrExit:
3203 return hr;
3204} // ImportHelper::CreateAssemblyRefFromAssemblyRef
3205
3206//******************************************************************************
3207// Given the Assembly Import scope, hash value and execution location, create
3208// a corresponding AssemblyRef in the given assembly and module emit scope.
3209// Set the output parameter to the AssemblyRef token emitted in the module emit
3210// scope.
3211//******************************************************************************
3212HRESULT
3213ImportHelper::CreateAssemblyRefFromAssembly(
3214 CMiniMdRW * pMiniMdAssemEmit, // [IN] Emit assembly scope.
3215 CMiniMdRW * pMiniMdModuleEmit, // [IN] Emit module scope.
3216 IMetaModelCommon * pCommonAssemImport, // [IN] Assembly import scope.
3217 const void * pbHashValue, // [IN] Hash Blob for Assembly.
3218 ULONG cbHashValue, // [IN] Count of bytes.
3219 mdAssemblyRef * ptkAssemblyRef) // [OUT] AssemblyRef token.
3220{
3221#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
3222 return E_NOTIMPL;
3223#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
3224 AssemblyRefRec *pRecordEmit;
3225 CMiniMdRW *rMiniMdRW[2];
3226 CMiniMdRW *pMiniMdEmit;
3227 RID iRecordEmit;
3228 USHORT usMajorVersion;
3229 USHORT usMinorVersion;
3230 USHORT usBuildNumber;
3231 USHORT usRevisionNumber;
3232 DWORD dwFlags;
3233 const void *pbPublicKey;
3234 ULONG cbPublicKey;
3235 LPCUTF8 szName;
3236 LPCUTF8 szLocale;
3237 mdAssemblyRef tkAssemRef;
3238 HRESULT hr = S_OK;
3239 const void *pbToken = NULL;
3240 ULONG cbToken = 0;
3241 ULONG i;
3242
3243 // Set output to Nil.
3244 *ptkAssemblyRef = mdTokenNil;
3245
3246 // Get the Assembly props.
3247 IfFailGo(pCommonAssemImport->CommonGetAssemblyProps(
3248 &usMajorVersion, &usMinorVersion, &usBuildNumber, &usRevisionNumber,
3249 &dwFlags, &pbPublicKey, &cbPublicKey,
3250 &szName, &szLocale));
3251
3252 // Compress the public key into a token.
3253 if ((pbPublicKey != NULL) && (cbPublicKey != 0))
3254 {
3255 _ASSERTE(IsAfPublicKey(dwFlags));
3256 dwFlags &= ~afPublicKey;
3257 if (!StrongNameTokenFromPublicKey((BYTE*)pbPublicKey,
3258 cbPublicKey,
3259 (BYTE**)&pbToken,
3260 &cbToken))
3261 IfFailGo(StrongNameErrorInfo());
3262 }
3263 else
3264 _ASSERTE(!IsAfPublicKey(dwFlags));
3265
3266 // Create the AssemblyRef in both the Assembly and Module emit scopes.
3267 rMiniMdRW[0] = pMiniMdAssemEmit;
3268 rMiniMdRW[1] = pMiniMdModuleEmit;
3269
3270 for (i = 0; i < 2; i++)
3271 {
3272 pMiniMdEmit = rMiniMdRW[i];
3273
3274 if (!pMiniMdEmit)
3275 continue;
3276
3277 // See if the AssemblyRef already exists in the emit scope.
3278 hr = FindAssemblyRef(pMiniMdEmit, szName, szLocale, pbToken,
3279 cbToken, usMajorVersion, usMinorVersion,
3280 usBuildNumber, usRevisionNumber, dwFlags,
3281 &tkAssemRef);
3282 if (hr == CLDB_E_RECORD_NOTFOUND)
3283 {
3284 // Create the AssemblyRef record and set the output parameter.
3285 IfFailGo(pMiniMdEmit->AddAssemblyRefRecord(&pRecordEmit, &iRecordEmit));
3286 tkAssemRef = TokenFromRid(iRecordEmit, mdtAssemblyRef);
3287 IfFailGo(pMiniMdEmit->UpdateENCLog(tkAssemRef));
3288
3289 // Set parameters derived from the import Assembly.
3290 pRecordEmit->SetMajorVersion(usMajorVersion);
3291 pRecordEmit->SetMinorVersion(usMinorVersion);
3292 pRecordEmit->SetBuildNumber(usBuildNumber);
3293 pRecordEmit->SetRevisionNumber(usRevisionNumber);
3294 pRecordEmit->SetFlags(dwFlags);
3295
3296 IfFailGo(pMiniMdEmit->PutBlob(TBL_AssemblyRef, AssemblyRefRec::COL_PublicKeyOrToken,
3297 pRecordEmit, pbToken, cbToken));
3298 IfFailGo(pMiniMdEmit->PutString(TBL_AssemblyRef, AssemblyRefRec::COL_Name,
3299 pRecordEmit, szName));
3300 IfFailGo(pMiniMdEmit->PutString(TBL_AssemblyRef, AssemblyRefRec::COL_Locale,
3301 pRecordEmit, szLocale));
3302
3303 // Set the parameters passed in for the AssemblyRef.
3304 IfFailGo(pMiniMdEmit->PutBlob(TBL_AssemblyRef, AssemblyRefRec::COL_HashValue,
3305 pRecordEmit, pbHashValue, cbHashValue));
3306 }
3307 else
3308 IfFailGo(hr);
3309
3310 // Set the output parameter for the AssemblyRef emitted in Module emit scope.
3311 if (i)
3312 *ptkAssemblyRef = tkAssemRef;
3313 }
3314ErrExit:
3315 if (pbToken)
3316 StrongNameFreeBuffer((BYTE*)pbToken);
3317 return hr;
3318#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
3319} // ImportHelper::CreateAssemblyRefFromAssembly
3320
3321//******************************************************************************
3322// Given an AssemblyRef and the corresponding scope, compare it to see if it
3323// refers to the given Assembly.
3324//******************************************************************************
3325HRESULT ImportHelper::CompareAssemblyRefToAssembly( // S_OK, S_FALSE or error.
3326 IMetaModelCommon *pCommonAssem1, // [IN] Scope that defines the AssemblyRef.
3327 mdAssemblyRef tkAssemRef, // [IN] AssemblyRef.
3328 IMetaModelCommon *pCommonAssem2) // [IN] Assembly against which the Ref is compared.
3329{
3330#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
3331 return E_NOTIMPL;
3332#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
3333 HRESULT hr;
3334
3335 USHORT usMajorVersion1;
3336 USHORT usMinorVersion1;
3337 USHORT usBuildNumber1;
3338 USHORT usRevisionNumber1;
3339 const void *pbPublicKeyOrToken1;
3340 ULONG cbPublicKeyOrToken1;
3341 LPCUTF8 szName1;
3342 LPCUTF8 szLocale1;
3343 DWORD dwFlags1;
3344
3345 USHORT usMajorVersion2;
3346 USHORT usMinorVersion2;
3347 USHORT usBuildNumber2;
3348 USHORT usRevisionNumber2;
3349 const void *pbPublicKey2;
3350 ULONG cbPublicKey2;
3351 LPCUTF8 szName2;
3352 LPCUTF8 szLocale2;
3353 const void *pbToken = NULL;
3354 ULONG cbToken = 0;
3355 bool fMatch;
3356
3357 // Get the AssemblyRef props.
3358 IfFailRet(pCommonAssem1->CommonGetAssemblyRefProps(
3359 tkAssemRef,
3360 &usMajorVersion1, &usMinorVersion1, &usBuildNumber1, &usRevisionNumber1,
3361 &dwFlags1, &pbPublicKeyOrToken1, &cbPublicKeyOrToken1,
3362 &szName1, &szLocale1,
3363 NULL, NULL));
3364 // Get the Assembly props.
3365 IfFailRet(pCommonAssem2->CommonGetAssemblyProps(
3366 &usMajorVersion2, &usMinorVersion2, &usBuildNumber2, &usRevisionNumber2,
3367 0, &pbPublicKey2, &cbPublicKey2,
3368 &szName2, &szLocale2));
3369
3370 // Compare.
3371 if (usMajorVersion1 != usMajorVersion2 ||
3372 usMinorVersion1 != usMinorVersion2 ||
3373 usBuildNumber1 != usBuildNumber2 ||
3374 usRevisionNumber1 != usRevisionNumber2 ||
3375 strcmp(szName1, szName2) ||
3376 strcmp(szLocale1, szLocale2))
3377 {
3378 return S_FALSE;
3379 }
3380
3381 // Defs always contain a full public key (or no key at all). Refs may have
3382 // no key, a full public key or a tokenized key.
3383 if ((cbPublicKeyOrToken1 && !cbPublicKey2) ||
3384 (!cbPublicKeyOrToken1 && cbPublicKey2))
3385 return S_FALSE;
3386
3387 if (cbPublicKeyOrToken1)
3388 {
3389 // If ref contains a full public key we can just directly compare.
3390 if (IsAfPublicKey(dwFlags1) &&
3391 (cbPublicKeyOrToken1 != cbPublicKey2 ||
3392 memcmp(pbPublicKeyOrToken1, pbPublicKey2, cbPublicKeyOrToken1)))
3393 return S_FALSE;
3394
3395 // Otherwise we need to compress the def public key into a token.
3396 if (!StrongNameTokenFromPublicKey((BYTE*)pbPublicKey2,
3397 cbPublicKey2,
3398 (BYTE**)&pbToken,
3399 &cbToken))
3400 return StrongNameErrorInfo();
3401
3402 fMatch = cbPublicKeyOrToken1 == cbToken &&
3403 !memcmp(pbPublicKeyOrToken1, pbToken, cbPublicKeyOrToken1);
3404
3405 StrongNameFreeBuffer((BYTE*)pbToken);
3406
3407 if (!fMatch)
3408 return S_FALSE;
3409 }
3410
3411 return S_OK;
3412#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
3413} // ImportHelper::CompareAssemblyRefToAssembly
3414
3415#endif //FEATURE_METADATA_EMIT
3416