diff options
Diffstat (limited to 'src/md/compiler/importhelper.cpp')
-rw-r--r-- | src/md/compiler/importhelper.cpp | 3415 |
1 files changed, 3415 insertions, 0 deletions
diff --git a/src/md/compiler/importhelper.cpp b/src/md/compiler/importhelper.cpp new file mode 100644 index 0000000000..abebe1e805 --- /dev/null +++ b/src/md/compiler/importhelper.cpp @@ -0,0 +1,3415 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +//***************************************************************************** +// ImportHelper.cpp +// + +// +// contains utility code to MD directory +// +//***************************************************************************** +#include "stdafx.h" +#include "importhelper.h" +#include "mdutil.h" +#include "rwutil.h" +#include "mdlog.h" +#include "strongname.h" +#include "sstring.h" + +#define COM_RUNTIME_LIBRARY "ComRuntimeLibrary" + + +//******************************************************************************* +// Find the MethodSpec by Method and Instantiation +//******************************************************************************* +//@GENERICS: todo: look in hashtable (cf. MetaModelRW.cpp) if necessary +HRESULT ImportHelper::FindMethodSpecByMethodAndInstantiation( + CMiniMdRW *pMiniMd, // [IN] the minimd to lookup + /*mdMethodDefOrRef*/ mdToken tkMethod, // [IN] MethodSpec method field + PCCOR_SIGNATURE pInstantiation, // [IN] MethodSpec instantiation (a signature) + ULONG cbInstantiation, // [IN] Size of instantiation. + mdMethodSpec *pMethodSpec, // [OUT] Put the MethodSpec token here. + RID rid /* = 0*/) // [IN] Optional rid to be ignored. +{ + HRESULT hr; + MethodSpecRec *pRecord; + /*mdMethodDefOrRef*/ mdToken tkMethodTmp; + PCCOR_SIGNATURE pInstantiationTmp; + ULONG cbInstantiationTmp; + ULONG cMethodSpecs; + ULONG i; + + _ASSERTE(pMethodSpec); + + cMethodSpecs = pMiniMd->getCountMethodSpecs(); + + // linear scan through the MethodSpec table + for (i=1; i <= cMethodSpecs; ++i) + { + // For the call from Validator ignore the rid passed in. + if (i == rid) + continue; + + IfFailRet(pMiniMd->GetMethodSpecRecord(i, &pRecord)); + + tkMethodTmp = pMiniMd->getMethodOfMethodSpec(pRecord); + if ((tkMethodTmp != tkMethod)) + continue; + + //@GENERICS: not sure what is meant by duplicate here: identical sig pointers or sig pointer contents? + IfFailRet(pMiniMd->getInstantiationOfMethodSpec(pRecord, &pInstantiationTmp, &cbInstantiationTmp)); + if (cbInstantiationTmp != cbInstantiation || memcmp(pInstantiation, pInstantiationTmp, cbInstantiation)) + continue; + + // Matching record found. + *pMethodSpec = TokenFromRid(i, mdtMethodSpec); + return S_OK; + } + return CLDB_E_RECORD_NOTFOUND; +} // HRESULT ImportHelper::FindMethodSpecByMethodAndInstantiation() + + +//******************************************************************************* +// Find the GenericParam by owner and constraint +//******************************************************************************* +//@GENERICS: todo: look in hashtable (cf. MetaModelRW.cpp) if necessary +HRESULT ImportHelper::FindGenericParamConstraintByOwnerAndConstraint( + CMiniMdRW *pMiniMd, // [IN] the minimd to lookup + mdGenericParam tkOwner, // [IN] GenericParamConstraint Owner + mdToken tkConstraint, // [IN] GenericParamConstraint Constraint + mdGenericParamConstraint *pGenericParamConstraint,// [OUT] Put the GenericParam token here. + RID rid /* = 0*/) // [IN] Optional rid to be ignored. +{ + HRESULT hr; + GenericParamConstraintRec *pRecord; + mdGenericParam tkOwnerTmp; + mdToken tkConstraintTmp; + ULONG cGenericParamConstraints; + + ULONG i; + + _ASSERTE(pGenericParamConstraint); + + cGenericParamConstraints = pMiniMd->getCountGenericParamConstraints(); + + // linear scan through the GenericParam table + for (i=1; i <= cGenericParamConstraints; ++i) + { + // For the call from Validator ignore the rid passed in. + if (i == rid) + continue; + + IfFailRet(pMiniMd->GetGenericParamConstraintRecord(i, &pRecord)); + + tkOwnerTmp = pMiniMd->getOwnerOfGenericParamConstraint(pRecord); + tkConstraintTmp = pMiniMd->getConstraintOfGenericParamConstraint(pRecord); + + if ((tkOwnerTmp != tkOwner) || (tkConstraintTmp != tkConstraint)) + continue; + + // Matching record found. + *pGenericParamConstraint = TokenFromRid(i, mdtGenericParamConstraint); + return S_OK; + } + return CLDB_E_RECORD_NOTFOUND; +} // HRESULT ImportHelper::FindGenericParamConstraintByOwnerAndConstraint() + +//******************************************************************************* +// Find the GenericParam by owner and name or number +//******************************************************************************* +//<REVISIT_TODO> @GENERICS: todo: look in hashtable (cf. MetaModelRW.cpp) if necessary </REVISIT_TODO> +HRESULT ImportHelper::FindGenericParamByOwner( + CMiniMdRW *pMiniMd, // [IN] the minimd to lookup + mdToken tkOwner, // [IN] GenericParam Owner + LPCUTF8 szUTF8Name, // [IN] GeneriParam Name, may be NULL if not used for search + ULONG *pNumber, // [IN] GeneriParam Number, may be NULL if not used for search + mdGenericParam *pGenericParam, // [OUT] Put the GenericParam token here. + RID rid /* = 0*/) // [IN] Optional rid to be ignored. +{ + HRESULT hr; + GenericParamRec *pRecord; + mdToken tkOwnerTmp; + ULONG cGenericParams; + LPCUTF8 szCurName; + ULONG curNumber; + ULONG i; + + _ASSERTE(pGenericParam); + + cGenericParams = pMiniMd->getCountGenericParams(); + + // linear scan through the GenericParam table + for (i=1; i <= cGenericParams; ++i) + { + // For the call from Validator ignore the rid passed in. + if (i == rid) + continue; + + IfFailRet(pMiniMd->GetGenericParamRecord(i, &pRecord)); + + tkOwnerTmp = pMiniMd->getOwnerOfGenericParam(pRecord); + if ( tkOwnerTmp != tkOwner) + continue; + + // if the name is significant, try to match it + if (szUTF8Name) + { + IfFailRet(pMiniMd->getNameOfGenericParam(pRecord, &szCurName)); + if (strcmp(szCurName, szUTF8Name)) + continue; + } + + // if the number is significant, try to match it + if (pNumber) + { curNumber = pMiniMd->getNumberOfGenericParam(pRecord); + if (*pNumber != curNumber) + continue; + } + + // Matching record found. + *pGenericParam = TokenFromRid(i, mdtGenericParam); + return S_OK; + } + return CLDB_E_RECORD_NOTFOUND; +} // HRESULT ImportHelper::FindGenericParamByOwner() + +//******************************************************************************* +// Find a Method given a parent, name and signature. +//******************************************************************************* +HRESULT ImportHelper::FindMethod( + CMiniMdRW * pMiniMd, // [IN] the minimd to lookup + mdTypeDef td, // [IN] parent. + LPCUTF8 szName, // [IN] MethodDef name. + PCCOR_SIGNATURE pSig, // [IN] Signature. + ULONG cbSig, // [IN] Size of signature. + mdMethodDef * pmb, // [OUT] Put the MethodDef token here. + RID rid, // = 0 // [IN] Optional rid to be ignored. + PSIGCOMPARE pSignatureCompare, // = NULL // [IN] Optional Routine to compare signatures + void * pCompareContext) // = NULL // [IN] Optional context for the compare function +{ + HRESULT hr = S_OK; + ULONG ridStart; // Start of td's methods. + ULONG ridEnd; // End of td's methods. + ULONG index; // Loop control. + TypeDefRec *pRec; // A TypeDef Record. + MethodRec *pMethod; // A MethodDef Record. + LPCUTF8 szNameUtf8Tmp; // A found MethodDef's name. + PCCOR_SIGNATURE pSigTmp; // A found MethodDef's signature. + ULONG cbSigTmp; // Size of a found MethodDef's signature. + PCCOR_SIGNATURE pvSigTemp = pSig; // For use in parsing a signature. + CQuickBytes qbSig; // Struct to build a non-varargs signature. + CMiniMdRW::HashSearchResult rtn; + + if (cbSig) + { // check to see if this is a vararg signature + if (isCallConv(CorSigUncompressCallingConv(pvSigTemp), IMAGE_CEE_CS_CALLCONV_VARARG)) + { // Get the fix part of VARARG signature + IfFailGo(_GetFixedSigOfVarArg(pSig, cbSig, &qbSig, &cbSig)); + pSig = (PCCOR_SIGNATURE) qbSig.Ptr(); + } + } + + *pmb = TokenFromRid(rid, mdtMethodDef); // to know what to ignore + rtn = pMiniMd->FindMemberDefFromHash(td, szName, pSig, cbSig, pmb); + if (rtn == CMiniMdRW::Found) + { + goto ErrExit; + } + else if (rtn == CMiniMdRW::NotFound) + { + IfFailGo(CLDB_E_RECORD_NOTFOUND); + } + _ASSERTE(rtn == CMiniMdRW::NoTable); + + *pmb = mdMethodDefNil; + + // get the range of method rids given a typedef + IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(td), &pRec)); + ridStart = pMiniMd->getMethodListOfTypeDef(pRec); + IfFailGo(pMiniMd->getEndMethodListOfTypeDef(RidFromToken(td), &ridEnd)); + // Iterate over the methods. + for (index = ridStart; index < ridEnd; index ++ ) + { + RID methodRID; + IfFailGo(pMiniMd->GetMethodRid(index, &methodRID)); + // For the call from Validator ignore the rid passed in. + if (methodRID != rid) + { + // Get the method and its name. + IfFailGo(pMiniMd->GetMethodRecord(methodRID, &pMethod)); + IfFailGo(pMiniMd->getNameOfMethod(pMethod, &szNameUtf8Tmp)); + + // If name matches what was requested... + if ( strcmp(szNameUtf8Tmp, szName) == 0 ) + { + if (cbSig && pSig) + { + IfFailGo(pMiniMd->getSignatureOfMethod(pMethod, &pSigTmp, &cbSigTmp)); + + // If the caller did not provide a custom compare routine + // then we use memcmp to match the signatures + // + if (pSignatureCompare == NULL) + { + if (cbSigTmp != cbSig || memcmp(pSig, pSigTmp, cbSig)) + continue; + } + else + { + // Call the custom compare routine + // + if (!pSignatureCompare(pSigTmp, cbSigTmp, pSig, cbSig, pCompareContext)) + continue; + } + } + // Ignore PrivateScope methods. + if (IsMdPrivateScope(pMiniMd->getFlagsOfMethod(pMethod))) + continue; + + // Found method. + *pmb = TokenFromRid(methodRID, mdtMethodDef); + goto ErrExit; + } + } + } + + // record not found + *pmb = mdMethodDefNil; + hr = CLDB_E_RECORD_NOTFOUND; + +ErrExit: + return hr; +} // ImportHelper::FindMethod + +//******************************************************************************* +// Find a Field given a parent, name and signature. +//******************************************************************************* +HRESULT ImportHelper::FindField( + CMiniMdRW * pMiniMd, // [IN] the minimd to lookup + mdTypeDef td, // [IN] parent. + LPCUTF8 szName, // [IN] FieldDef name. + PCCOR_SIGNATURE pSig, // [IN] Signature. + ULONG cbSig, // [IN] Size of signature. + mdFieldDef * pfd, // [OUT] Put the FieldDef token here. + RID rid) // = 0 // [IN] Optional rid to be ignored. +{ + HRESULT hr = S_OK; // A result. + ULONG ridStart; // Start of td's methods. + ULONG ridEnd; // End of td's methods. + ULONG index; // Loop control. + TypeDefRec *pRec; // A TypeDef Record. + FieldRec *pField; // A FieldDef Record. + LPCUTF8 szNameUtf8Tmp; // A found FieldDef's name. + PCCOR_SIGNATURE pSigTmp; // A found FieldDef's signature. + ULONG cbSigTmp; // Size of a found FieldDef's signature. + CMiniMdRW::HashSearchResult rtn; + + *pfd = TokenFromRid(rid,mdtFieldDef); // to know what to ignore + rtn = pMiniMd->FindMemberDefFromHash(td, szName, pSig, cbSig, pfd); + if (rtn == CMiniMdRW::Found) + { + goto ErrExit; + } + else if (rtn == CMiniMdRW::NotFound) + { + IfFailGo(CLDB_E_RECORD_NOTFOUND); + } + _ASSERTE(rtn == CMiniMdRW::NoTable); + + *pfd = mdFieldDefNil; + + // get the range of method rids given a typedef + IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(td), &pRec)); + ridStart = pMiniMd->getFieldListOfTypeDef(pRec); + IfFailGo(pMiniMd->getEndFieldListOfTypeDef(RidFromToken(td), &ridEnd)); + + // Iterate over the methods. + for (index = ridStart; index < ridEnd; index ++ ) + { + RID fieldRID; + IfFailGo(pMiniMd->GetFieldRid(index, &fieldRID)); + // For the call from Validator ignore the rid passed in. + if (fieldRID != rid) + { + // Get the field and its name. + IfFailGo(pMiniMd->GetFieldRecord(fieldRID, &pField)); + IfFailGo(pMiniMd->getNameOfField(pField, &szNameUtf8Tmp)); + + // If name matches what was requested... + if ( strcmp(szNameUtf8Tmp, szName) == 0 ) + { + // Check signature if specified. + if (cbSig && pSig) + { + IfFailGo(pMiniMd->getSignatureOfField(pField, &pSigTmp, &cbSigTmp)); + if (cbSigTmp != cbSig || memcmp(pSig, pSigTmp, cbSig)) + continue; + } + // Ignore PrivateScope fields. + if (IsFdPrivateScope(pMiniMd->getFlagsOfField(pField))) + continue; + // Field found. + *pfd = TokenFromRid(fieldRID, mdtFieldDef); + goto ErrExit; + } + } + } + + // record not found + *pfd = mdFieldDefNil; + hr = CLDB_E_RECORD_NOTFOUND; + +ErrExit: + return hr; +} // ImportHelper::FindField + +//******************************************************************************* +// Find a Member given a parent, name and signature. +//******************************************************************************* +HRESULT ImportHelper::FindMember( + CMiniMdRW * pMiniMd, // [IN] the minimd to lookup + mdTypeDef td, // [IN] parent. + LPCUTF8 szName, // [IN] Member name. + PCCOR_SIGNATURE pSig, // [IN] Signature. + ULONG cbSig, // [IN] Size of signature. + mdToken * ptk) // [OUT] Put the token here. +{ + HRESULT hr; + + if (cbSig == 0) + { + Debug_ReportError("Invalid signature size 0."); + return CLDB_E_INDEX_NOTFOUND; + } + + // determine if it is ref to MethodDef or FieldDef + if ((pSig[0] & IMAGE_CEE_CS_CALLCONV_MASK) != IMAGE_CEE_CS_CALLCONV_FIELD) + { + hr = FindMethod(pMiniMd, td, szName, pSig, cbSig, ptk); + } + else + { + hr = FindField(pMiniMd, td, szName, pSig, cbSig, ptk); + } + + if (hr == CLDB_E_RECORD_NOTFOUND) + *ptk = mdTokenNil; + + return hr; +} // ImportHelper::FindMember + + +//******************************************************************************* +// Find the memberref given name, sig, and parent +//******************************************************************************* +HRESULT ImportHelper::FindMemberRef( + CMiniMdRW * pMiniMd, // [IN] the minimd to lookup + mdToken tkParent, // [IN] the parent token + LPCUTF8 szName, // [IN] memberref name + const COR_SIGNATURE * pbSig, // [IN] Signature. + ULONG cbSig, // [IN] Size of signature. + mdMemberRef * pmr, // [OUT] Put the MemberRef token found + RID rid, // = 0 // [IN] Optional rid to be ignored. + HashSearchOption fCreateHash) // = DoNotCreateHash // [IN] Should we create hash first? (Optimize for multiple calls vs. single isolated call) +{ + ULONG cMemberRefRecs; + MemberRefRec * pMemberRefRec; + LPCUTF8 szNameTmp = 0; + const COR_SIGNATURE * pbSigTmp; // Signature. + ULONG cbSigTmp; // Size of signature. + mdToken tkParentTmp; // the parent token + HRESULT hr = NOERROR; + CMiniMdRW::HashSearchResult rtn; + + if ((szName == NULL) || (pmr == NULL)) + { + IfFailGo(CLDB_E_RECORD_NOTFOUND); + } + + if (fCreateHash == CreateHash) + { // Caller asked for creating hash to optimize for multiple calls + IfFailGo(pMiniMd->CreateMemberRefHash()); + } + + *pmr = TokenFromRid(rid, mdtMemberRef); // to know what to ignore + rtn = pMiniMd->FindMemberRefFromHash(tkParent, szName, pbSig, cbSig, pmr); + if (rtn == CMiniMdRW::Found) + { + goto ErrExit; + } + else if (rtn == CMiniMdRW::NotFound) + { + IfFailGo(CLDB_E_RECORD_NOTFOUND); + } + _ASSERTE(rtn == CMiniMdRW::NoTable); + + *pmr = mdMemberRefNil; + + cMemberRefRecs = pMiniMd->getCountMemberRefs(); + + // Search for the MemberRef + for (ULONG i = 1; i <= cMemberRefRecs; i++) + { + // For the call from Validator ignore the rid passed in. + if (i == rid) + continue; + + IfFailGo(pMiniMd->GetMemberRefRecord(i, &pMemberRefRec)); + if (!IsNilToken(tkParent)) + { + // given a valid parent + tkParentTmp = pMiniMd->getClassOfMemberRef(pMemberRefRec); + if (tkParentTmp != tkParent) + { + // if parent is specified and not equal to the current row, + // try the next row. + continue; + } + } + if ((szName != NULL) && (*szName != 0)) + { + // name is specified + IfFailGo(pMiniMd->getNameOfMemberRef(pMemberRefRec, &szNameTmp)); + if (strcmp(szName, szNameTmp) != 0) + { + // Name is not equal. Try next row. + continue; + } + } + if ((cbSig != 0) && (pbSig != NULL)) + { + // signature is specifed + IfFailGo(pMiniMd->getSignatureOfMemberRef(pMemberRefRec, &pbSigTmp, &cbSigTmp)); + if (cbSigTmp != cbSig) + continue; + if (memcmp( pbSig, pbSigTmp, cbSig ) != 0) + continue; + } + + // we found a match + *pmr = TokenFromRid(i, mdtMemberRef); + return S_OK; + } + hr = CLDB_E_RECORD_NOTFOUND; +ErrExit: + return hr; +} // ImportHelper::FindMemberRef + + + +//******************************************************************************* +// Find duplicate StandAloneSig +//******************************************************************************* +HRESULT ImportHelper::FindStandAloneSig( + CMiniMdRW *pMiniMd, // [IN] the minimd to lookup + const COR_SIGNATURE *pbSig, // [IN] Signature. + ULONG cbSig, // [IN] Size of signature. + mdSignature *psa) // [OUT] Put the StandAloneSig token found +{ + HRESULT hr; + ULONG cRecs; + StandAloneSigRec *pRec; + const COR_SIGNATURE *pbSigTmp; // Signature. + ULONG cbSigTmp; // Size of signature. + + + _ASSERTE(cbSig && psa); + *psa = mdSignatureNil; + + cRecs = pMiniMd->getCountStandAloneSigs(); + + // Search for the StandAloneSignature + for (ULONG i = 1; i <= cRecs; i++) + { + IfFailRet(pMiniMd->GetStandAloneSigRecord(i, &pRec)); + IfFailRet(pMiniMd->getSignatureOfStandAloneSig(pRec, &pbSigTmp, &cbSigTmp)); + if (cbSigTmp != cbSig) + continue; + if (memcmp( pbSig, pbSigTmp, cbSig ) != 0) + continue; + + // we found a match + *psa = TokenFromRid(i, mdtSignature); + return S_OK; + } + return CLDB_E_RECORD_NOTFOUND; +} // HRESULT ImportHelper::FindStandAloneSig() + +//******************************************************************************* +// Find duplicate TypeSpec +//******************************************************************************* +HRESULT +ImportHelper::FindTypeSpec( + CMiniMdRW * pMiniMd, // [IN] the minimd to lookup + const COR_SIGNATURE * pbSig, // [IN] Signature. + ULONG cbSig, // [IN] Size of signature. + mdTypeSpec * pTypeSpec) // [OUT] Put the TypeSpec token found +{ + HRESULT hr; + ULONG cRecs; + TypeSpecRec * pRec; + const COR_SIGNATURE * pbSigTmp; // Signature. + ULONG cbSigTmp; // Size of signature. + + // cbSig can be 0 + _ASSERTE(pTypeSpec != NULL); + *pTypeSpec = mdSignatureNil; + + cRecs = pMiniMd->getCountTypeSpecs(); + + // Search for the TypeSpec + for (ULONG i = 1; i <= cRecs; i++) + { + IfFailRet(pMiniMd->GetTypeSpecRecord(i, &pRec)); + IfFailRet(pMiniMd->getSignatureOfTypeSpec(pRec, &pbSigTmp, &cbSigTmp)); + if (cbSigTmp != cbSig) + continue; + if (memcmp(pbSig, pbSigTmp, cbSig) != 0) + continue; + + // we found a match + *pTypeSpec = TokenFromRid(i, mdtTypeSpec); + return S_OK; + } + return CLDB_E_RECORD_NOTFOUND; +} // ImportHelper::FindTypeSpec + + +//******************************************************************************* +// Find the MethodImpl +//******************************************************************************* +HRESULT ImportHelper::FindMethodImpl( + CMiniMdRW *pMiniMd, // [IN] The MiniMd to lookup. + mdTypeDef tkClass, // [IN] The parent TypeDef token. + mdMethodDef tkBody, // [IN] Method body token. + mdMethodDef tkDecl, // [IN] Method declaration token. + RID *pRid) // [OUT] Put the MethodImpl rid here +{ + HRESULT hr; + MethodImplRec *pMethodImplRec; // MethodImpl record. + ULONG cMethodImplRecs; // Count of MethodImpl records. + mdTypeDef tkClassTmp; // Parent TypeDef token. + mdToken tkBodyTmp; // Method body token. + mdToken tkDeclTmp; // Method declaration token. + + _ASSERTE(TypeFromToken(tkClass) == mdtTypeDef); + _ASSERTE(TypeFromToken(tkBody) == mdtMemberRef || TypeFromToken(tkBody) == mdtMethodDef); + _ASSERTE(TypeFromToken(tkDecl) == mdtMemberRef || TypeFromToken(tkDecl) == mdtMethodDef); + _ASSERTE(!IsNilToken(tkClass) && !IsNilToken(tkBody) && !IsNilToken(tkDecl)); + + if (pRid) + *pRid = 0; + + cMethodImplRecs = pMiniMd->getCountMethodImpls(); + + // Search for the MethodImpl. + for (ULONG i = 1; i <= cMethodImplRecs; i++) + { + IfFailRet(pMiniMd->GetMethodImplRecord(i, &pMethodImplRec)); + + // match the parent column + tkClassTmp = pMiniMd->getClassOfMethodImpl(pMethodImplRec); + if (tkClassTmp != tkClass) + continue; + + // match the method body column + tkBodyTmp = pMiniMd->getMethodBodyOfMethodImpl(pMethodImplRec); + if (tkBodyTmp != tkBody) + continue; + + // match the method declaration column + tkDeclTmp = pMiniMd->getMethodDeclarationOfMethodImpl(pMethodImplRec); + if (tkDeclTmp != tkDecl) + continue; + + // we found a match + if (pRid) + *pRid = i; + return S_OK; + } + return CLDB_E_RECORD_NOTFOUND; +} // HRESULT ImportHelper::FindMethodImpl() + +//******************************************************************************* +// Find the TypeRef given the fully qualified name and the assembly name +//******************************************************************************* +HRESULT ImportHelper::FindCustomAttributeCtorByName( + CMiniMdRW *pMiniMd, // [IN] the minimd to lookup + LPCUTF8 szAssemblyName, // [IN] Assembly Name. + LPCUTF8 szNamespace, // [IN] TypeRef Namespace. + LPCUTF8 szName, // [IN] TypeRef Name. + mdTypeDef *ptk, // [OUT] Put the TypeRef token here. + RID rid /* = 0*/) // [IN] Optional rid to be ignored. +{ + HRESULT hr; + ULONG cRecs; // Count of records. + AssemblyRefRec *pRec; // Current record being looked at. + LPCUTF8 szTmp; // Temp string. + mdTypeRef tkCAType; + + cRecs = pMiniMd->getCountAssemblyRefs(); + // Search for the AssemblyRef record. + for (ULONG i = 1; i <= cRecs; i++) + { + IfFailRet(pMiniMd->GetAssemblyRefRecord(i, &pRec)); + + IfFailRet(pMiniMd->getNameOfAssemblyRef(pRec, &szTmp)); + if (!strcmp(szTmp, szAssemblyName) && + (SUCCEEDED(FindTypeRefByName(pMiniMd, TokenFromRid(i, mdtAssemblyRef), szNamespace, szName, &tkCAType, rid))) && + (SUCCEEDED(FindMemberRef(pMiniMd, tkCAType, COR_CTOR_METHOD_NAME, NULL, 0 ,ptk)))) + { + return S_OK; + } + } + + return CLDB_E_RECORD_NOTFOUND; +} + +//******************************************************************************* +// Find the TypeRef given the fully qualified name. +//******************************************************************************* +HRESULT ImportHelper::FindTypeRefByName( + CMiniMdRW *pMiniMd, // [IN] the minimd to lookup + mdToken tkResolutionScope, // [IN] Resolution scope for the TypeRef. + LPCUTF8 szNamespace, // [IN] TypeRef Namespace. + LPCUTF8 szName, // [IN] TypeRef Name. + mdTypeRef *ptk, // [OUT] Put the TypeRef token here. + RID rid /* = 0*/) // [IN] Optional rid to be ignored. +{ + HRESULT hr=S_OK; // A result. + ULONG cTypeRefRecs; // Count of TypeRefs to scan. + TypeRefRec *pTypeRefRec; // A TypeRef record. + LPCUTF8 szNameTmp; // A TypeRef's Name. + LPCUTF8 szNamespaceTmp; // A TypeRef's Namespace. + mdToken tkResTmp; // TypeRef's resolution scope. + ULONG i; // Loop control. + + _ASSERTE(szName && ptk); + *ptk = mdTypeRefNil; + + // Treat no namespace as empty string. + if (!szNamespace) + szNamespace = ""; + + if (pMiniMd->m_pNamedItemHash) + { + // If hash is build, go through the hash table + TOKENHASHENTRY *p; // Hash entry from chain. + ULONG iHash; // Item's hash value. + int pos; // Position in hash chain. + + // Hash the data. + iHash = pMiniMd->HashNamedItem(0, szName); + + // Go through every entry in the hash chain looking for ours. + for (p = pMiniMd->m_pNamedItemHash->FindFirst(iHash, pos); + p; + p = pMiniMd->m_pNamedItemHash->FindNext(pos)) + { + + // name hash can hold more than one kind of token + if (TypeFromToken(p->tok) != (ULONG)mdtTypeRef) + { + continue; + } + + // skip this one if asked + if (RidFromToken(p->tok) == rid) + continue; + + IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(p->tok), &pTypeRefRec)); + IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szNamespaceTmp)); + IfFailGo(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szNameTmp)); + if (strcmp(szName, szNameTmp) || strcmp(szNamespace, szNamespaceTmp)) + { + // if the name space is not equal, then check the next one. + continue; + } + tkResTmp = pMiniMd->getResolutionScopeOfTypeRef(pTypeRefRec); + + if (tkResTmp == tkResolutionScope || + (IsNilToken(tkResTmp) && IsNilToken(tkResolutionScope))) + { + // we found a match + *ptk = p->tok; + return S_OK; + } + } + hr = CLDB_E_RECORD_NOTFOUND; + } + else + { + cTypeRefRecs = pMiniMd->getCountTypeRefs(); + + // Search for the TypeRef. + for (i = 1; i <= cTypeRefRecs; i++) + { + // For the call from Validator ignore the rid passed in. + if (i == rid) + continue; + + IfFailGo(pMiniMd->GetTypeRefRecord(i, &pTypeRefRec)); + + // See if the Resolution scopes match. + tkResTmp = pMiniMd->getResolutionScopeOfTypeRef(pTypeRefRec); + if (IsNilToken(tkResTmp)) + { + if (!IsNilToken(tkResolutionScope)) + continue; + } + else if (tkResTmp != tkResolutionScope) + continue; + + IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szNamespaceTmp)); + if (strcmp(szNamespace, szNamespaceTmp)) + continue; + + IfFailGo(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szNameTmp)); + if (! strcmp(szName, szNameTmp)) + { + *ptk = TokenFromRid(i, mdtTypeRef); + return S_OK; + } + } + hr = CLDB_E_RECORD_NOTFOUND; + } +ErrExit: + return hr; +} // HRESULT ImportHelper::FindTypeRefByName() + + +//******************************************************************************* +// Find the ModuleRef given the name, guid and mvid. +//******************************************************************************* +HRESULT ImportHelper::FindModuleRef( + CMiniMdRW *pMiniMd, // [IN] the minimd to lookup + LPCUTF8 szUTF8Name, // [IN] ModuleRef name. + mdModuleRef *pmur, // [OUT] Put the ModuleRef token here. + RID rid /* = 0*/) // [IN] Optional rid to be ignored. +{ + HRESULT hr; + ModuleRefRec *pModuleRef; + ULONG cModuleRefs; + LPCUTF8 szCurName; + ULONG i; + + _ASSERTE(pmur); + _ASSERTE(szUTF8Name); + + cModuleRefs = pMiniMd->getCountModuleRefs(); + + // linear scan through the ModuleRef table + for (i=1; i <= cModuleRefs; ++i) + { + // For the call from Validator ignore the rid passed in. + if (i == rid) + continue; + + IfFailRet(pMiniMd->GetModuleRefRecord(i, &pModuleRef)); + + if (szUTF8Name != NULL) + { + IfFailRet(pMiniMd->getNameOfModuleRef(pModuleRef, &szCurName)); + if (strcmp(szCurName, szUTF8Name)) + continue; + } + // Matching record found. + *pmur = TokenFromRid(i, mdtModuleRef); + return S_OK; + } + return CLDB_E_RECORD_NOTFOUND; +} // HRESULT ImportHelper::FindModuleRef() + + + +//******************************************************************************* +// Find the TypeDef given the type and namespace name +//******************************************************************************* +HRESULT +ImportHelper::FindTypeDefByName( + CMiniMdRW * pMiniMd, // [IN] the minimd to lookup + LPCUTF8 szTypeDefNamespace, // [IN] Full qualified TypeRef name. + LPCUTF8 szTypeDefName, // [IN] Full qualified TypeRef name. + mdToken tkEnclosingClass, // [IN] TypeDef/TypeRef/Module for Enclosing class. + mdTypeDef * ptkTypeDef, // [OUT] Put the TypeRef token here. + RID ridIgnore) // =0 // [IN] Optional rid to be ignored. +{ + ULONG cTypeDefRecs; + TypeDefRec * pTypeDefRec; + LPCUTF8 szName; + LPCUTF8 szNamespace; + DWORD dwFlags; + HRESULT hr = S_OK; + + _ASSERTE((szTypeDefName != NULL) && (ptkTypeDef != NULL)); + _ASSERTE((TypeFromToken(tkEnclosingClass) == mdtTypeDef) || + (TypeFromToken(tkEnclosingClass) == mdtTypeRef) || + (tkEnclosingClass == TokenFromRid(1, mdtModule)) || + IsNilToken(tkEnclosingClass)); + + *ptkTypeDef = mdTypeDefNil; + + cTypeDefRecs = pMiniMd->getCountTypeDefs(); + + // Treat no namespace as empty string. + if (szTypeDefNamespace == NULL) + szTypeDefNamespace = ""; + + if (tkEnclosingClass == TokenFromRid(1, mdtModule)) + { // Module scope is the same as no scope (used in .winmd files as TypeRef scope for self-references) + tkEnclosingClass = mdTokenNil; + } + + // Get TypeDef of the tkEnclosingClass passed in + if (TypeFromToken(tkEnclosingClass) == mdtTypeRef) + { + // Resolve the TypeRef to a TypeDef + TypeRefRec * pTypeRefRec; + mdToken tkResolutionScope; + LPCUTF8 szTypeRefName; + LPCUTF8 szTypeRefNamespace; + + IfFailRet(pMiniMd->GetTypeRefRecord(RidFromToken(tkEnclosingClass), &pTypeRefRec)); + tkResolutionScope = pMiniMd->getResolutionScopeOfTypeRef(pTypeRefRec); + IfFailRet(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szTypeRefName)); + IfFailRet(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szTypeRefNamespace)); + + if (tkEnclosingClass == tkResolutionScope && !strcmp(szTypeDefName, szTypeRefName) && + ((szTypeDefNamespace == nullptr && szTypeRefNamespace == nullptr) || + (szTypeDefNamespace != nullptr && szTypeRefNamespace != nullptr && !strcmp(szTypeDefNamespace, szTypeRefNamespace)))) + { + // + // This defensive workaround works around a feature of DotFuscator that adds a bad type-ref + // which causes tools like ILDASM to crash. The type-ref's parent is set to itself + // which causes this function to recurse infinitely. A side-effect is that during Ngen we + // parse all the type-refs in an assembly and Ngen also hangs infinitely. + // This workaround is necessary because several popular gaming libraries experience hangs + // and we need binary compatibility in Apollo. + // + return CLDB_E_FILE_CORRUPT; + } + + // Update tkEnclosingClass to TypeDef + IfFailRet(FindTypeDefByName( + pMiniMd, + szTypeRefNamespace, + szTypeRefName, + (TypeFromToken(tkResolutionScope) == mdtTypeRef) ? tkResolutionScope : mdTokenNil, + &tkEnclosingClass)); + _ASSERTE(TypeFromToken(tkEnclosingClass) == mdtTypeDef); + } + + // Search for the TypeDef + for (ULONG i = 1; i <= cTypeDefRecs; i++) + { + // For the call from Validator ignore the rid passed in. + if (i == ridIgnore) + continue; + + IfFailRet(pMiniMd->GetTypeDefRecord(i, &pTypeDefRec)); + + dwFlags = pMiniMd->getFlagsOfTypeDef(pTypeDefRec); + + if (!IsTdNested(dwFlags) && !IsNilToken(tkEnclosingClass)) + { + // If the class is not Nested and EnclosingClass passed in is not nil + continue; + } + else if (IsTdNested(dwFlags) && IsNilToken(tkEnclosingClass)) + { + // If the class is nested and EnclosingClass passed is nil + continue; + } + else if (!IsNilToken(tkEnclosingClass)) + { + _ASSERTE(TypeFromToken(tkEnclosingClass) == mdtTypeDef); + + RID iNestedClassRec; + NestedClassRec * pNestedClassRec; + mdTypeDef tkEnclosingClassTmp; + + IfFailRet(pMiniMd->FindNestedClassHelper(TokenFromRid(i, mdtTypeDef), &iNestedClassRec)); + if (InvalidRid(iNestedClassRec)) + continue; + IfFailRet(pMiniMd->GetNestedClassRecord(iNestedClassRec, &pNestedClassRec)); + tkEnclosingClassTmp = pMiniMd->getEnclosingClassOfNestedClass(pNestedClassRec); + if (tkEnclosingClass != tkEnclosingClassTmp) + continue; + } + + IfFailRet(pMiniMd->getNameOfTypeDef(pTypeDefRec, &szName)); + if (strcmp(szTypeDefName, szName) == 0) + { + IfFailRet(pMiniMd->getNamespaceOfTypeDef(pTypeDefRec, &szNamespace)); + if (strcmp(szTypeDefNamespace, szNamespace) == 0) + { + *ptkTypeDef = TokenFromRid(i, mdtTypeDef); + return S_OK; + } + } + } + return CLDB_E_RECORD_NOTFOUND; +} // ImportHelper::FindTypeDefByName + +//******************************************************************************* +// Find the InterfaceImpl given the typedef and implemented interface +//******************************************************************************* +HRESULT ImportHelper::FindInterfaceImpl( + CMiniMdRW *pMiniMd, // [IN] the minimd to lookup + mdToken tkClass, // [IN] TypeDef of the type + mdToken tkInterface, // [IN] could be typedef/typeref + mdInterfaceImpl *ptk, // [OUT] Put the interface token here. + RID rid /* = 0*/) // [IN] Optional rid to be ignored. +{ + HRESULT hr; + ULONG ridStart, ridEnd; + ULONG i; + InterfaceImplRec *pInterfaceImplRec; + + _ASSERTE(ptk); + *ptk = mdInterfaceImplNil; + if ( pMiniMd->IsSorted(TBL_InterfaceImpl) ) + { + IfFailRet(pMiniMd->getInterfaceImplsForTypeDef(RidFromToken(tkClass), &ridEnd, &ridStart)); + } + else + { + ridStart = 1; + ridEnd = pMiniMd->getCountInterfaceImpls() + 1; + } + + // Search for the interfaceimpl + for (i = ridStart; i < ridEnd; i++) + { + // For the call from Validator ignore the rid passed in. + if (i == rid) + continue; + + IfFailRet(pMiniMd->GetInterfaceImplRecord(i, &pInterfaceImplRec)); + if ( tkClass != pMiniMd->getClassOfInterfaceImpl(pInterfaceImplRec) ) + continue; + if ( tkInterface == pMiniMd->getInterfaceOfInterfaceImpl(pInterfaceImplRec) ) + { + *ptk = TokenFromRid(i, mdtInterfaceImpl); + return S_OK; + } + } + return CLDB_E_RECORD_NOTFOUND; +} // HRESULT ImportHelper::FindInterfaceImpl() + + + +//******************************************************************************* +// Find the Permission by parent and action +//******************************************************************************* +HRESULT ImportHelper::FindPermission( + CMiniMdRW *pMiniMd, // [IN] the minimd to lookup + mdToken tkParent, // [IN] Token with the Permission + USHORT usAction, // [IN] The action of the permission + mdPermission *ppm) // [OUT] Put permission token here +{ + HRESULT hr; + DeclSecurityRec *pRec; + ULONG ridStart, ridEnd; + ULONG i; + mdToken tkParentTmp; + + _ASSERTE(ppm); + + if ( pMiniMd->IsSorted(TBL_DeclSecurity) ) + { + + IfFailRet(pMiniMd->getDeclSecurityForToken(tkParent, &ridEnd, &ridStart)); + } + else + { + ridStart = 1; + ridEnd = pMiniMd->getCountDeclSecuritys() + 1; + } + // loop through all permission + for (i = ridStart; i < ridEnd; i++) + { + IfFailRet(pMiniMd->GetDeclSecurityRecord(i, &pRec)); + tkParentTmp = pMiniMd->getParentOfDeclSecurity(pRec); + if ( tkParentTmp != tkParent ) + continue; + if (pRec->GetAction() == usAction) + { + *ppm = TokenFromRid(i, mdtPermission); + return S_OK; + } + } + return CLDB_E_RECORD_NOTFOUND; +} // HRESULT ImportHelper::FindPermission() + + +//***************************************************************************** +// find a property record +//***************************************************************************** +HRESULT ImportHelper::FindProperty( + CMiniMdRW *pMiniMd, // [IN] the minimd to lookup + mdToken tkTypeDef, // [IN] typedef token + LPCUTF8 szName, // [IN] name of the property + const COR_SIGNATURE *pbSig, // [IN] Signature. + ULONG cbSig, // [IN] Size of signature. + mdProperty *ppr) // [OUT] Property token +{ + HRESULT hr; + RID ridPropertyMap; + PropertyMapRec *pPropertyMapRec; + PropertyRec *pRec; + ULONG ridStart; + ULONG ridEnd; + ULONG i; + LPCUTF8 szNameTmp; + PCCOR_SIGNATURE pbSigTmp; + ULONG cbSigTmp; + ULONG pr; + + IfFailRet(pMiniMd->FindPropertyMapFor(RidFromToken(tkTypeDef), &ridPropertyMap)); + if ( !InvalidRid(ridPropertyMap) ) + { + IfFailRet(pMiniMd->GetPropertyMapRecord(ridPropertyMap, &pPropertyMapRec)); + ridStart = pMiniMd->getPropertyListOfPropertyMap(pPropertyMapRec); + IfFailRet(pMiniMd->getEndPropertyListOfPropertyMap(ridPropertyMap, &ridEnd)); + + for (i = ridStart; i < ridEnd; i++) + { + // get the property rid + IfFailRet(pMiniMd->GetPropertyRid(i, &pr)); + IfFailRet(pMiniMd->GetPropertyRecord(pr, &pRec)); + IfFailRet(pMiniMd->getNameOfProperty(pRec, &szNameTmp)); + IfFailRet(pMiniMd->getTypeOfProperty(pRec, &pbSigTmp, &cbSigTmp)); + if ( strcmp (szName, szNameTmp) != 0 ) + continue; + if ( cbSig != 0 && (cbSigTmp != cbSig || memcmp(pbSig, pbSigTmp, cbSig) != 0 ) ) + continue; + *ppr = TokenFromRid( i, mdtProperty ); + return S_OK; + } + return CLDB_E_RECORD_NOTFOUND; + } + else + { + return CLDB_E_RECORD_NOTFOUND; + } +} // HRESULT ImportHelper::FindProperty() + + + + +//***************************************************************************** +// find an Event record +//***************************************************************************** +HRESULT ImportHelper::FindEvent( + CMiniMdRW *pMiniMd, // [IN] the minimd to lookup + mdToken tkTypeDef, // [IN] typedef token + LPCUTF8 szName, // [IN] name of the event + mdProperty *pev) // [OUT] Event token +{ + HRESULT hr; + RID ridEventMap; + EventMapRec *pEventMapRec; + EventRec *pRec; + ULONG ridStart; + ULONG ridEnd; + ULONG i; + LPCUTF8 szNameTmp; + ULONG ev; + + IfFailRet(pMiniMd->FindEventMapFor(RidFromToken(tkTypeDef), &ridEventMap)); + if ( !InvalidRid(ridEventMap) ) + { + IfFailRet(pMiniMd->GetEventMapRecord(ridEventMap, &pEventMapRec)); + ridStart = pMiniMd->getEventListOfEventMap(pEventMapRec); + IfFailRet(pMiniMd->getEndEventListOfEventMap(ridEventMap, &ridEnd)); + + for (i = ridStart; i < ridEnd; i++) + { + // get the Event rid + IfFailRet(pMiniMd->GetEventRid(i, &ev)); + + // get the event row + IfFailRet(pMiniMd->GetEventRecord(ev, &pRec)); + IfFailRet(pMiniMd->getNameOfEvent(pRec, &szNameTmp)); + if ( strcmp (szName, szNameTmp) == 0) + { + *pev = TokenFromRid( ev, mdtEvent ); + return S_OK; + } + } + return CLDB_E_RECORD_NOTFOUND; + } + else + { + return CLDB_E_RECORD_NOTFOUND; + } +} // HRESULT ImportHelper::FindEvent() + + + +//***************************************************************************** +// find an custom value record given by parent and type token. This will always return +// the first one that is found regardless duplicated. +//***************************************************************************** +HRESULT ImportHelper::FindCustomAttributeByToken( + CMiniMdRW *pMiniMd, // [IN] the minimd to lookup + mdToken tkParent, // [IN] the parent that custom value is associated with + mdToken tkType, // [IN] type of the CustomAttribute + const void *pCustBlob, // [IN] custom attribute blob + ULONG cbCustBlob, // [IN] size of the blob. + mdCustomAttribute *pcv) // [OUT] CustomAttribute token +{ + HRESULT hr; + CustomAttributeRec *pRec; + ULONG ridStart, ridEnd; + ULONG i; + mdToken tkParentTmp; + mdToken tkTypeTmp; + const void *pCustBlobTmp; + ULONG cbCustBlobTmp; + + _ASSERTE(pcv); + *pcv = mdCustomAttributeNil; + if ( pMiniMd->IsSorted(TBL_CustomAttribute) ) + { + IfFailRet(pMiniMd->FindCustomAttributeFor( + RidFromToken(tkParent), + TypeFromToken(tkParent), + tkType, + (RID *)pcv)); + if (InvalidRid(*pcv)) + { + return S_FALSE; + } + else if (pCustBlob) + { + IfFailRet(pMiniMd->GetCustomAttributeRecord(RidFromToken(*pcv), &pRec)); + IfFailRet(pMiniMd->getValueOfCustomAttribute(pRec, (const BYTE **)&pCustBlobTmp, &cbCustBlobTmp)); + if (cbCustBlob == cbCustBlobTmp && + !memcmp(pCustBlob, pCustBlobTmp, cbCustBlob)) + { + return S_OK; + } + } + else + { + return S_OK; + } + } + else + { + CLookUpHash *pHashTable = pMiniMd->m_pLookUpHashs[TBL_CustomAttribute]; + + if (pHashTable) + { + // table is not sorted but hash is built + // We want to create dynmaic array to hold the dynamic enumerator. + TOKENHASHENTRY *p; + ULONG iHash; + int pos; + + // Hash the data. + iHash = pMiniMd->HashCustomAttribute(tkParent); + + // Go through every entry in the hash chain looking for ours. + for (p = pHashTable->FindFirst(iHash, pos); + p; + p = pHashTable->FindNext(pos)) + { + IfFailRet(pMiniMd->GetCustomAttributeRecord(RidFromToken(p->tok), &pRec)); + + tkParentTmp = pMiniMd->getParentOfCustomAttribute(pRec); + if (tkParentTmp != tkParent) + continue; + + tkTypeTmp = pMiniMd->getTypeOfCustomAttribute(pRec); + if (tkType != tkTypeTmp) + continue; + if (pCustBlob != NULL) + { + IfFailRet(pMiniMd->getValueOfCustomAttribute(pRec, (const BYTE **)&pCustBlobTmp, &cbCustBlobTmp)); + if (cbCustBlob == cbCustBlobTmp && + !memcmp(pCustBlob, pCustBlobTmp, cbCustBlob)) + { + *pcv = TokenFromRid(p->tok, mdtCustomAttribute); + return S_OK; + } + } + else + return S_OK; + } + } + else + { + // linear scan + ridStart = 1; + ridEnd = pMiniMd->getCountCustomAttributes() + 1; + + // loop through all custom values + for (i = ridStart; i < ridEnd; i++) + { + IfFailRet(pMiniMd->GetCustomAttributeRecord(i, &pRec)); + + tkParentTmp = pMiniMd->getParentOfCustomAttribute(pRec); + if ( tkParentTmp != tkParent ) + continue; + + tkTypeTmp = pMiniMd->getTypeOfCustomAttribute(pRec); + if (tkType != tkTypeTmp) + continue; + + if (pCustBlob != NULL) + { + IfFailRet(pMiniMd->getValueOfCustomAttribute(pRec, (const BYTE **)&pCustBlobTmp, &cbCustBlobTmp)); + if (cbCustBlob == cbCustBlobTmp && + !memcmp(pCustBlob, pCustBlobTmp, cbCustBlob)) + { + *pcv = TokenFromRid(i, mdtCustomAttribute); + return S_OK; + } + } + else + return S_OK; + } + } + // fall through + } + return S_FALSE; +} // ImportHelper::FindCustomAttributeByToken + +//***************************************************************************** +// Helper function to lookup and retrieve a CustomAttribute. +//***************************************************************************** +HRESULT ImportHelper::GetCustomAttributeByName( // S_OK or error. + CMiniMdRW *pMiniMd, // [IN] the minimd to lookup + mdToken tkObj, // [IN] Object with Custom Attribute. + LPCUTF8 szName, // [IN] Name of desired Custom Attribute. + const void **ppData, // [OUT] Put pointer to data here. + ULONG *pcbData) // [OUT] Put size of data here. +{ + return pMiniMd->CommonGetCustomAttributeByName(tkObj, szName, ppData, pcbData); +} // ImportHelper::GetCustomAttributeByName + +#ifdef FEATURE_METADATA_EMIT + +//******************************************************************************* +// Find an AssemblyRef record given the name. +//******************************************************************************* +HRESULT ImportHelper::FindAssemblyRef( + CMiniMdRW *pMiniMd, // [IN] the minimd to lookup. + LPCUTF8 szName, // [IN] Name. + LPCUTF8 szLocale, // [IN] Locale. + const void *pbPublicKeyOrToken, // [IN] Public key or token (based on flags). + ULONG cbPublicKeyOrToken, // [IN] Byte count of public key or token. + USHORT usMajorVersion, // [IN] Major version. + USHORT usMinorVersion, // [IN] Minor version. + USHORT usBuildNumber, // [IN] Build number. + USHORT usRevisionNumber, // [IN] Revision number. + DWORD dwFlags, // [IN] Flags. + mdAssemblyRef *pmar) // [OUT] returned AssemblyRef token. +{ + HRESULT hr; + ULONG cRecs; // Count of records. + AssemblyRefRec *pRec; // Current record being looked at. + LPCUTF8 szTmp; // Temp string. + const void *pbTmp; // Temp blob. + ULONG cbTmp; // Temp byte count. + DWORD dwTmp; // Temp flags. + const void *pbToken = NULL; // Token version of public key. + ULONG cbToken = 0; // Count of bytes in token. +#if !defined(FEATURE_METADATA_EMIT_IN_DEBUGGER) || defined(DACCESS_COMPILE) + const void *pbTmpToken; // Token version of public key. + ULONG cbTmpToken; // Count of bytes in token. + bool fMatch; // Did public key or tokens match? +#endif // !FEATURE_METADATA_EMIT_IN_DEBUGGER || DACCESS_COMPILE + + // Handle special cases upfront. + if (!szLocale) + szLocale = ""; + if (!pbPublicKeyOrToken) + cbPublicKeyOrToken = 0; + + if (!IsAfPublicKey(dwFlags)) + { + pbToken = pbPublicKeyOrToken; + cbToken = cbPublicKeyOrToken; + } + + _ASSERTE(pMiniMd && szName && pmar); + *pmar = 0; + + cRecs = pMiniMd->getCountAssemblyRefs(); + + // Search for the AssemblyRef record. + for (ULONG i = 1; i <= cRecs; i++) + { + IfFailRet(pMiniMd->GetAssemblyRefRecord(i, &pRec)); + + IfFailRet(pMiniMd->getNameOfAssemblyRef(pRec, &szTmp)); + if (strcmp(szTmp, szName)) + continue; + + IfFailRet(pMiniMd->getLocaleOfAssemblyRef(pRec, &szTmp)); + if (strcmp(szTmp, szLocale)) + continue; + + if (pRec->GetMajorVersion() != usMajorVersion) + continue; + if (pRec->GetMinorVersion() != usMinorVersion) + continue; + + // We'll "unify" all versions of mscorlib and Microsoft.VisualC... so if this + // is one of those, we won't do the version check beyond the major/minor + + LPCUTF8 szAssemblyRefName; + IfFailRet(pMiniMd->getNameOfAssemblyRef(pRec, &szAssemblyRefName)); + if (SString::_stricmp(szAssemblyRefName, "mscorlib") && + SString::_stricmp(szAssemblyRefName, "microsoft.visualc")) + { + if (pRec->GetBuildNumber() != usBuildNumber) + continue; + if (pRec->GetRevisionNumber() != usRevisionNumber) + continue; + } + + IfFailRet(pMiniMd->getPublicKeyOrTokenOfAssemblyRef(pRec, (const BYTE **)&pbTmp, &cbTmp)); + + if ((cbPublicKeyOrToken && !cbTmp) || + (!cbPublicKeyOrToken && cbTmp)) + continue; + + if (cbTmp) + { + // Either ref may be using either a full public key or a token + // (determined by the ref flags). Must cope with all variations. + dwTmp = pMiniMd->getFlagsOfAssemblyRef(pRec); + if (IsAfPublicKey(dwTmp) == IsAfPublicKey(dwFlags)) + { + // Easy case, they're both in the same form. + if (cbTmp != cbPublicKeyOrToken || memcmp(pbTmp, pbPublicKeyOrToken, cbTmp)) + continue; + } + else if (IsAfPublicKey(dwTmp)) + { +#if defined(FEATURE_METADATA_EMIT_IN_DEBUGGER) && !defined(DACCESS_COMPILE) + return E_FAIL; +#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER || DACCESS_COMPILE + // Need to compress target public key to see if it matches. + if (!StrongNameTokenFromPublicKey((BYTE*)pbTmp, + cbTmp, + (BYTE**)&pbTmpToken, + &cbTmpToken)) + { + return StrongNameErrorInfo(); + } + fMatch = cbTmpToken == cbPublicKeyOrToken && !memcmp(pbTmpToken, pbPublicKeyOrToken, cbTmpToken); + StrongNameFreeBuffer((BYTE*)pbTmpToken); + if (!fMatch) + continue; +#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER || DACCESS_COMPILE + } + else + { + // Need to compress out public key to see if it matches. We + // cache the result of this for further iterations. + if (!pbToken) + { +#if defined(FEATURE_METADATA_EMIT_IN_DEBUGGER) && !defined(DACCESS_COMPILE) + return E_FAIL; +#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER || DACCESS_COMPILE + if (!StrongNameTokenFromPublicKey((BYTE*)pbPublicKeyOrToken, + cbPublicKeyOrToken, + (BYTE**)&pbToken, + &cbToken)) + { + return StrongNameErrorInfo(); + } +#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER || DACCESS_COMPILE + } + if (cbTmp != cbToken || memcmp(pbTmp, pbToken, cbToken)) + continue; + } + } + + if (pbToken && IsAfPublicKey(dwFlags)) + { +#if !defined(FEATURE_METADATA_EMIT_IN_DEBUGGER) || defined(DACCESS_COMPILE) + StrongNameFreeBuffer((BYTE*)pbToken); +#endif + } + *pmar = TokenFromRid(i, mdtAssemblyRef); + return S_OK; + } + if (pbToken && IsAfPublicKey(dwFlags)) + { +#if !defined(FEATURE_METADATA_EMIT_IN_DEBUGGER) || defined(DACCESS_COMPILE) + StrongNameFreeBuffer((BYTE*)pbToken); +#endif + } + return CLDB_E_RECORD_NOTFOUND; +} // ImportHelper::FindAssemblyRef + +//******************************************************************************* +// Find a File record given the name. +//******************************************************************************* +HRESULT ImportHelper::FindFile( + CMiniMdRW *pMiniMd, // [IN] the minimd to lookup. + LPCUTF8 szName, // [IN] name for the File. + mdFile *pmf, // [OUT] returned File token. + RID rid /* = 0 */) // [IN] Optional rid to be ignored. +{ + HRESULT hr; + ULONG cRecs; // Count of records. + FileRec *pRec; // Current record being looked at. + + LPCUTF8 szNameTmp; + + _ASSERTE(pMiniMd && szName && pmf); + *pmf = 0; + + cRecs = pMiniMd->getCountFiles(); + + // Search for the File record. + for (ULONG i = 1; i <= cRecs; i++) + { + // For the call from Validator ignore the rid passed in. + if (i == rid) + continue; + + IfFailRet(pMiniMd->GetFileRecord(i, &pRec)); + + IfFailRet(pMiniMd->getNameOfFile(pRec, &szNameTmp)); + if (!strcmp(szNameTmp, szName)) + { + *pmf = TokenFromRid(i, mdtFile); + return S_OK; + } + } + return CLDB_E_RECORD_NOTFOUND; +} // ImportHelper::FindFile + +#endif //FEATURE_METADATA_EMIT + +//******************************************************************************* +// Find a ExportedType record given the name. +//******************************************************************************* +HRESULT ImportHelper::FindExportedType( + CMiniMdRW *pMiniMd, // [IN] the minimd to lookup. + LPCUTF8 szNamespace, // [IN] namespace for the ExportedType. + LPCUTF8 szName, // [IN] name for the ExportedType. + mdExportedType tkEnclosingType, // [IN] token for the enclosing type. + mdExportedType *pmct, // [OUT] returned ExportedType token. + RID rid /* = 0 */) // [IN] Optional rid to be ignored. +{ + HRESULT hr; + ULONG cRecs; // Count of records. + ExportedTypeRec *pRec; // Current record being looked at. + mdToken tkImpl; + LPCUTF8 szNamespaceTmp; + LPCUTF8 szNameTmp; + + _ASSERTE(pMiniMd && szName && pmct); + *pmct = 0; + + // Treat no namespace as empty string. + if (!szNamespace) + szNamespace = ""; + + cRecs = pMiniMd->getCountExportedTypes(); + + // Search for the ExportedType record. + for (ULONG i = 1; i <= cRecs; i++) + { + // For the call from Validator ignore the rid passed in. + if (i == rid) + continue; + + IfFailRet(pMiniMd->GetExportedTypeRecord(i, &pRec)); + + // Handle the case of nested vs. non-nested classes. + tkImpl = pMiniMd->getImplementationOfExportedType(pRec); + if (TypeFromToken(tkImpl) == mdtExportedType && !IsNilToken(tkImpl)) + { + // Current ExportedType being looked at is a nested type, so + // comparing the implementation token. + if (tkImpl != tkEnclosingType) + continue; + } + else if (TypeFromToken(tkEnclosingType) == mdtExportedType && + !IsNilToken(tkEnclosingType)) + { + // ExportedType passed in is nested but the current ExportedType is not. + continue; + } + + IfFailRet(pMiniMd->getTypeNamespaceOfExportedType(pRec, &szNamespaceTmp)); + if (strcmp(szNamespaceTmp, szNamespace)) + continue; + + IfFailRet(pMiniMd->getTypeNameOfExportedType(pRec, &szNameTmp)); + if (!strcmp(szNameTmp, szName)) + { + *pmct = TokenFromRid(i, mdtExportedType); + return S_OK; + } + } + return CLDB_E_RECORD_NOTFOUND; +} // HRESULT ImportHelper::FindExportedType() + +//******************************************************************************* +// Find a ManifestResource record given the name. +//******************************************************************************* +HRESULT ImportHelper::FindManifestResource( + CMiniMdRW *pMiniMd, // [IN] the minimd to lookup. + LPCUTF8 szName, // [IN] name for the ManifestResource. + mdManifestResource *pmmr, // [OUT] returned ManifestResource token. + RID rid /* = 0 */) // [IN] Optional rid to be ignored. +{ + HRESULT hr; + ULONG cRecs; // Count of records. + ManifestResourceRec *pRec; // Current record being looked at. + + LPCUTF8 szNameTmp; + + _ASSERTE(pMiniMd && szName && pmmr); + *pmmr = 0; + + cRecs = pMiniMd->getCountManifestResources(); + + // Search for the ManifestResource record. + for (ULONG i = 1; i <= cRecs; i++) + { + // For the call from Validator ignore the rid passed in. + if (i == rid) + continue; + + IfFailRet(pMiniMd->GetManifestResourceRecord(i, &pRec)); + + IfFailRet(pMiniMd->getNameOfManifestResource(pRec, &szNameTmp)); + if (!strcmp(szNameTmp, szName)) + { + *pmmr = TokenFromRid(i, mdtManifestResource); + return S_OK; + } + } + return CLDB_E_RECORD_NOTFOUND; +} // HRESULT ImportHelper::FindManifestResource() + +#ifdef FEATURE_METADATA_EMIT + +//**************************************************************************** +// Convert tokens contained in an element type +//**************************************************************************** +HRESULT +ImportHelper::MergeUpdateTokenInFieldSig( + CMiniMdRW *pMiniMdAssemEmit, // [IN] The assembly emit scope. + CMiniMdRW *pMiniMdEmit, // [IN] The emit scope. + IMetaModelCommon *pCommonAssemImport,// [IN] Assembly scope where the signature is from. + const void *pbHashValue, // [IN] Hash value for the import assembly. + ULONG cbHashValue, // [IN] Size in bytes for the hash value. + IMetaModelCommon *pCommonImport, // [IN] The scope to merge into the emit scope. + PCCOR_SIGNATURE pbSigImp, // signature from the imported scope + MDTOKENMAP *ptkMap, // Internal OID mapping structure. + CQuickBytes *pqkSigEmit, // [OUT] buffer for translated signature + ULONG cbStartEmit, // [IN] start point of buffer to write to + ULONG *pcbImp, // [OUT] total number of bytes consumed from pbSigImp + ULONG *pcbEmit) // [OUT] total number of bytes write to pqkSigEmit +{ + + HRESULT hr; // A result. + ULONG cb; // count of bytes + ULONG cb1; // count of bytes + ULONG cb2; // count of bytes + ULONG cbSubTotal; + ULONG cbImp; + ULONG cbEmit; + ULONG cbSrcTotal = 0; // count of bytes consumed in the imported signature + ULONG cbDestTotal = 0; // count of bytes for the new signature + ULONG ulElementType = 0; // place holder for expanded data + ULONG ulData; + ULONG ulTemp; + mdToken tkRidFrom; // Original rid + mdToken tkRidTo; // new rid + int iData; + CQuickArray<mdToken> cqaNesters; // Array of Nester tokens. + CQuickArray<LPCUTF8> cqaNesterNamespaces; // Array of Nester Namespaces. + CQuickArray<LPCUTF8> cqaNesterNames; // Array of Nester names. + + _ASSERTE(pcbEmit); + + cb = CorSigUncompressData(&pbSigImp[cbSrcTotal], &ulElementType); + cbSrcTotal += cb; + + // count numbers of modifiers + while (CorIsModifierElementType((CorElementType) ulElementType)) + { + cb = CorSigUncompressData(&pbSigImp[cbSrcTotal], &ulElementType); + cbSrcTotal += cb; + } + + // copy ELEMENT_TYPE_* over + cbDestTotal = cbSrcTotal; + IfFailGo(pqkSigEmit->ReSizeNoThrow(cbStartEmit + cbDestTotal)); + memcpy(((BYTE *)pqkSigEmit->Ptr()) + cbStartEmit, pbSigImp, cbDestTotal); + switch (ulElementType) + { + case ELEMENT_TYPE_SZARRAY: + // syntax : SZARRAY <BaseType> + + // conver the base type for the SZARRAY or GENERICARRAY + IfFailGo(MergeUpdateTokenInFieldSig( + pMiniMdAssemEmit, // The assembly emit scope. + pMiniMdEmit, // The emit scope. + pCommonAssemImport, // The assembly scope where the signature is from. + pbHashValue, // Hash value for the import assembly. + cbHashValue, // Size in bytes for the hash value. + pCommonImport, // scope to merge into the emit scope. + &pbSigImp[cbSrcTotal], // from the imported scope + ptkMap, // OID mapping structure. + pqkSigEmit, // [OUT] buffer for translated signature + cbStartEmit + cbDestTotal, // [IN] start point of buffer to write to + &cbImp, // [OUT] total number of bytes consumed from pbSigImp + &cbEmit)); // [OUT] total number of bytes write to pqkSigEmit + cbSrcTotal += cbImp; + cbDestTotal += cbEmit; + break; + + case ELEMENT_TYPE_GENERICINST: + { + // syntax : WITH (ELEMENT_TYPE_CLASS | ELEMENT_TYPE_VALUECLASS) <BaseType> + + IfFailGo(MergeUpdateTokenInFieldSig( + pMiniMdAssemEmit, // The assembly emit scope. + pMiniMdEmit, // The emit scope. + pCommonAssemImport, // The assembly scope where the signature is from. + pbHashValue, // Hash value for the import assembly. + cbHashValue, // Size in bytes for the hash value. + pCommonImport, // scope to merge into the emit scope. + &pbSigImp[cbSrcTotal], // from the imported scope + ptkMap, // OID mapping structure. + pqkSigEmit, // [OUT] buffer for translated signature + cbStartEmit + cbDestTotal, // [IN] start point of buffer to write to + &cbImp, // [OUT] total number of bytes consumed from pbSigImp + &cbEmit)); // [OUT] total number of bytes write to pqkSigEmit + cbSrcTotal += cbImp; + cbDestTotal += cbEmit; + + // copy over the number of arguments + ULONG nargs; + cb = CorSigUncompressData(&pbSigImp[cbSrcTotal], &nargs); + + IfFailGo(pqkSigEmit->ReSizeNoThrow(cbStartEmit + cbDestTotal + cb)); + cb1 = CorSigCompressData(nargs, ((BYTE *)pqkSigEmit->Ptr()) + cbStartEmit + cbDestTotal); + _ASSERTE(cb == cb1); + + cbSrcTotal += cb; + cbDestTotal += cb1; + + for (ULONG narg = 0; narg < nargs; narg++) { + IfFailGo(MergeUpdateTokenInFieldSig( + pMiniMdAssemEmit, // The assembly emit scope. + pMiniMdEmit, // The emit scope. + pCommonAssemImport, // The assembly scope where the signature is from. + pbHashValue, // Hash value for the import assembly. + cbHashValue, // Size in bytes for the hash value. + pCommonImport, // The scope to merge into the emit scope. + &pbSigImp[cbSrcTotal], // signature from the imported scope + ptkMap, // Internal OID mapping structure. + pqkSigEmit, // [OUT] buffer for translated signature + cbStartEmit + cbDestTotal, // [IN] start point of buffer to write to + &cbImp, // [OUT] total number of bytes consumed from pbSigImp + &cbEmit)); // [OUT] total number of bytes write to pqkSigEmit + cbSrcTotal += cbImp; + cbDestTotal += cbEmit; + } + } + + break; + + case ELEMENT_TYPE_MVAR: + case ELEMENT_TYPE_VAR: + // syntax : VAR <n> + // syntax : MVAR <n> + + // after the VAR or MVAR there is an integer indicating which type variable + // + cb = CorSigUncompressData(&pbSigImp[cbSrcTotal], &ulData); + + IfFailGo(pqkSigEmit->ReSizeNoThrow(cbStartEmit + cbDestTotal + cb)); + cb1 = CorSigCompressData(ulData, ((BYTE *)pqkSigEmit->Ptr()) + cbStartEmit + cbDestTotal); + _ASSERTE(cb == cb1); + + cbSrcTotal += cb; + cbDestTotal += cb1; + + break; + + case ELEMENT_TYPE_ARRAY: + // syntax : ARRAY BaseType <rank> [i size_1... size_i] [j lowerbound_1 ... lowerbound_j] + + // conver the base type for the MDARRAY + IfFailGo(MergeUpdateTokenInFieldSig( + pMiniMdAssemEmit, // The assembly emit scope. + pMiniMdEmit, // The emit scope. + pCommonAssemImport, // The assembly scope where the signature is from. + pbHashValue, // Hash value for the import assembly. + cbHashValue, // Size in bytes for the hash value. + pCommonImport, // The scope to merge into the emit scope. + &pbSigImp[cbSrcTotal], // signature from the imported scope + ptkMap, // Internal OID mapping structure. + pqkSigEmit, // [OUT] buffer for translated signature + cbStartEmit + cbSrcTotal, // [IN] start point of buffer to write to + &cbImp, // [OUT] total number of bytes consumed from pbSigImp + &cbEmit)); // [OUT] total number of bytes write to pqkSigEmit + cbSrcTotal += cbImp; + cbDestTotal += cbEmit; + + // Parse for the rank + cbSubTotal = CorSigUncompressData(&pbSigImp[cbSrcTotal], &ulData); + + // if rank == 0, we are done + if (ulData != 0) + { + // any size of dimension specified? + cb = CorSigUncompressData(&pbSigImp[cbSrcTotal + cbSubTotal], &ulData); + cbSubTotal += cb; + + while (ulData--) + { + cb = CorSigUncompressData(&pbSigImp[cbSrcTotal + cbSubTotal], &ulTemp); + cbSubTotal += cb; + } + + // any lower bound specified? + cb = CorSigUncompressData(&pbSigImp[cbSrcTotal + cbSubTotal], &ulData); + cbSubTotal += cb; + + while (ulData--) + { + cb = CorSigUncompressSignedInt(&pbSigImp[cbSrcTotal + cbSubTotal], &iData); + cbSubTotal += cb; + } + } + + // cbSubTotal is now the number of bytes still left to move over + // cbSrcTotal is where bytes start on the pbSigImp to be copied over + // cbStartEmit + cbDestTotal is where the destination of copy + + IfFailGo(pqkSigEmit->ReSizeNoThrow(cbStartEmit + cbDestTotal + cbSubTotal)); + memcpy(((BYTE *)pqkSigEmit->Ptr())+cbStartEmit + cbDestTotal, &pbSigImp[cbSrcTotal], cbSubTotal); + + cbSrcTotal = cbSrcTotal + cbSubTotal; + cbDestTotal = cbDestTotal + cbSubTotal; + + break; + case ELEMENT_TYPE_FNPTR: + // function pointer is followed by another complete signature + IfFailGo(MergeUpdateTokenInSig( + pMiniMdAssemEmit, // The assembly emit scope. + pMiniMdEmit, // The emit scope. + pCommonAssemImport, // The assembly scope where the signature is from. + pbHashValue, // Hash value for the import assembly. + cbHashValue, // Size in bytes for the hash value. + pCommonImport, // The scope to merge into the emit scope. + &pbSigImp[cbSrcTotal], // signature from the imported scope + ptkMap, // Internal OID mapping structure. + pqkSigEmit, // [OUT] buffer for translated signature + cbStartEmit + cbDestTotal, // [IN] start point of buffer to write to + &cbImp, // [OUT] total number of bytes consumed from pbSigImp + &cbEmit)); // [OUT] total number of bytes write to pqkSigEmit + cbSrcTotal += cbImp; + cbDestTotal += cbEmit; + break; + case ELEMENT_TYPE_VALUETYPE: + case ELEMENT_TYPE_CLASS: + case ELEMENT_TYPE_CMOD_REQD: + case ELEMENT_TYPE_CMOD_OPT: + + // syntax for CLASS = ELEMENT_TYPE_CLASS <rid> + // syntax for VALUE_CLASS = ELEMENT_TYPE_VALUECLASS <rid> + + // now get the embedded typeref token + cb = CorSigUncompressToken(&pbSigImp[cbSrcTotal], &tkRidFrom); + + // Map the ulRidFrom to ulRidTo + if (ptkMap) + { + // mdtBaseType does not record in the map. It is unique across modules + if ( TypeFromToken(tkRidFrom) == mdtBaseType ) + { + tkRidTo = tkRidFrom; + } + else + { + IfFailGo( ptkMap->Remap(tkRidFrom, &tkRidTo) ); + } + } + else + { + // If the token is a TypeDef or a TypeRef, get/create the + // ResolutionScope for the outermost TypeRef. + if (TypeFromToken(tkRidFrom) == mdtTypeDef) + { + IfFailGo(ImportTypeDef(pMiniMdAssemEmit, + pMiniMdEmit, + pCommonAssemImport, + pbHashValue, + cbHashValue, + pCommonImport, + tkRidFrom, + true, // Optimize to TypeDef if emit and import scopes are identical. + &tkRidTo)); + } + else if (TypeFromToken(tkRidFrom) == mdtTypeRef) + { + IfFailGo(ImportTypeRef(pMiniMdAssemEmit, + pMiniMdEmit, + pCommonAssemImport, + pbHashValue, + cbHashValue, + pCommonImport, + tkRidFrom, + &tkRidTo)); + } + else if ( TypeFromToken(tkRidFrom) == mdtTypeSpec ) + { + // copy over the TypeSpec + PCCOR_SIGNATURE pvTypeSpecSig; + ULONG cbTypeSpecSig; + CQuickBytes qkTypeSpecSigEmit; + ULONG cbTypeSpecEmit; + + IfFailGo(pCommonImport->CommonGetTypeSpecProps( + tkRidFrom, + &pvTypeSpecSig, + &cbTypeSpecSig)); + + // Translate the typespec signature before look up + IfFailGo(MergeUpdateTokenInFieldSig( + pMiniMdAssemEmit, // The assembly emit scope. + pMiniMdEmit, // The emit scope. + pCommonAssemImport, // The assembly scope where the signature is from. + pbHashValue, // Hash value for the import assembly. + cbHashValue, // Size in bytes for the hash value. + pCommonImport, // The scope to merge into the emit scope. + pvTypeSpecSig, // signature from the imported scope + ptkMap, // Internal OID mapping structure. + &qkTypeSpecSigEmit, // [OUT] buffer for translated signature + 0, // start from first byte of TypeSpec signature + 0, // don't care how many bytes are consumed + &cbTypeSpecEmit) ); // [OUT] total number of bytes write to pqkSigEmit + + hr = FindTypeSpec(pMiniMdEmit, + (PCCOR_SIGNATURE) (qkTypeSpecSigEmit.Ptr()), + cbTypeSpecEmit, + &tkRidTo); + + if ( hr == CLDB_E_RECORD_NOTFOUND ) + { + // Create TypeSpec record. + TypeSpecRec *pRecEmit; + + IfFailGo(pMiniMdEmit->AddTypeSpecRecord(&pRecEmit, (RID *)&tkRidTo)); + + IfFailGo(pMiniMdEmit->PutBlob( + TBL_TypeSpec, + TypeSpecRec::COL_Signature, + pRecEmit, + (PCCOR_SIGNATURE) (qkTypeSpecSigEmit.Ptr()), + cbTypeSpecEmit)); + tkRidTo = TokenFromRid( tkRidTo, mdtTypeSpec ); + IfFailGo(pMiniMdEmit->UpdateENCLog(tkRidTo)); + } + IfFailGo( hr ); + } + else + { + _ASSERTE( TypeFromToken(tkRidFrom) == mdtBaseType ); + + // base type is unique across module + tkRidTo = tkRidFrom; + } + } + + // How many bytes the new rid will consume? + cb1 = CorSigCompressToken(tkRidTo, &ulData); + + // ensure buffer is big enough + IfFailGo(pqkSigEmit->ReSizeNoThrow(cbStartEmit + cbDestTotal + cb1)); + + // store the new token + cb2 = CorSigCompressToken( + tkRidTo, + (ULONG *)( ((BYTE *)pqkSigEmit->Ptr()) + cbStartEmit + cbDestTotal) ); + + // inconsistency on CorSigCompressToken and CorSigUncompressToken + _ASSERTE(cb1 == cb2); + + cbSrcTotal = cbSrcTotal + cb; + cbDestTotal = cbDestTotal + cb1; + + if ( ulElementType == ELEMENT_TYPE_CMOD_REQD || + ulElementType == ELEMENT_TYPE_CMOD_OPT) + { + // need to skip over the base type + IfFailGo(MergeUpdateTokenInFieldSig( + pMiniMdAssemEmit, // The assembly emit scope. + pMiniMdEmit, // The emit scope. + pCommonAssemImport, // The assembly scope where the signature is from. + pbHashValue, // Hash value for the import assembly. + cbHashValue, // Size in bytes for the hash value. + pCommonImport, // The scope to merge into the emit scope. + &pbSigImp[cbSrcTotal], // signature from the imported scope + ptkMap, // Internal OID mapping structure. + pqkSigEmit, // [OUT] buffer for translated signature + cbStartEmit + cbDestTotal, // [IN] start point of buffer to write to + &cbImp, // [OUT] total number of bytes consumed from pbSigImp + &cbEmit)); // [OUT] total number of bytes write to pqkSigEmit + cbSrcTotal += cbImp; + cbDestTotal += cbEmit; + } + + break; + default: + _ASSERTE(cbSrcTotal == cbDestTotal); + + if ((ulElementType >= ELEMENT_TYPE_MAX) || + (ulElementType == ELEMENT_TYPE_PTR) || + (ulElementType == ELEMENT_TYPE_BYREF) || + (ulElementType == ELEMENT_TYPE_VALUEARRAY_UNSUPPORTED)) + { + IfFailGo(META_E_BAD_SIGNATURE); + } + break; + } + if (pcbImp) + *pcbImp = cbSrcTotal; + *pcbEmit = cbDestTotal; + +ErrExit: + return hr; +} // ImportHelper::MergeUpdateTokenInFieldSig + +#endif //FEATURE_METADATA_EMIT + +//**************************************************************************** +// convert tokens contained in a COM+ signature +//**************************************************************************** +HRESULT ImportHelper::MergeUpdateTokenInSig(// S_OK or error. + CMiniMdRW *pMiniMdAssemEmit, // [IN] The assembly emit scope. + CMiniMdRW *pMiniMdEmit, // [IN] The emit scope. + IMetaModelCommon *pCommonAssemImport,// [IN] Assembly scope where the signature is from. + const void *pbHashValue, // [IN] Hash value for the import assembly. + ULONG cbHashValue, // [IN] Size in bytes for the hash value. + IMetaModelCommon *pCommonImport, // [IN] The scope to merge into the emit scope. + PCCOR_SIGNATURE pbSigImp, // signature from the imported scope + MDTOKENMAP *ptkMap, // Internal OID mapping structure. + CQuickBytes *pqkSigEmit, // [OUT] translated signature + ULONG cbStartEmit, // [IN] start point of buffer to write to + ULONG *pcbImp, // [OUT] total number of bytes consumed from pbSigImp + ULONG *pcbEmit) // [OUT] total number of bytes write to pqkSigEmit +{ +#ifdef FEATURE_METADATA_EMIT + HRESULT hr = NOERROR; // A result. + ULONG cb; // count of bytes + ULONG cb1; + ULONG cbSrcTotal = 0; // count of bytes consumed in the imported signature + ULONG cbDestTotal = 0; // count of bytes for the new signature + ULONG cbEmit; // count of bytes consumed in the imported signature + ULONG cbImp; // count of bytes for the new signature + ULONG cArg = 0; // count of arguments in the signature + ULONG cTyArg = 0; + ULONG callingconv = 0; // calling convention from signature + + _ASSERTE(pcbEmit && pqkSigEmit && pbSigImp); + + // calling convention + cb = CorSigUncompressData(&pbSigImp[cbSrcTotal], &callingconv); + _ASSERTE((callingconv & IMAGE_CEE_CS_CALLCONV_MASK) < IMAGE_CEE_CS_CALLCONV_MAX); + + // skip over calling convention + cbSrcTotal += cb; + + if (isCallConv(callingconv, IMAGE_CEE_CS_CALLCONV_FIELD)) + { + // It is a FieldRef + cb1 = CorSigCompressData(callingconv, ((BYTE *)pqkSigEmit->Ptr()) + cbStartEmit); + + // compression and uncompression better match + _ASSERTE(cb == cb1); + + cbDestTotal = cbSrcTotal = cb; + IfFailGo(MergeUpdateTokenInFieldSig( + pMiniMdAssemEmit, + pMiniMdEmit, + pCommonAssemImport, + pbHashValue, + cbHashValue, + pCommonImport, + &pbSigImp[cbSrcTotal], + ptkMap, + pqkSigEmit, // output buffer to hold the new sig for the field + cbStartEmit + cbDestTotal, // number of bytes already in pqkSigDest + &cbImp, // number of bytes consumed from imported signature + &cbEmit)); // number of bytes write to the new signature + *pcbEmit = cbDestTotal + cbEmit; + } + else + { + + // It is a MethodRef + // count of type arguments + if (callingconv & IMAGE_CEE_CS_CALLCONV_GENERIC) + { + cb = CorSigUncompressData(&pbSigImp[cbSrcTotal], &cTyArg); + cbSrcTotal += cb; + } + + // count of argument + cb = CorSigUncompressData(&pbSigImp[cbSrcTotal], &cArg); + cbSrcTotal += cb; + + // move over the calling convention and the count of arguments + IfFailGo(pqkSigEmit->ReSizeNoThrow(cbStartEmit + cbSrcTotal)); + memcpy(((BYTE *)pqkSigEmit->Ptr()) + cbStartEmit, pbSigImp, cbSrcTotal); + cbDestTotal = cbSrcTotal; + + if ( !( isCallConv(callingconv, IMAGE_CEE_CS_CALLCONV_LOCAL_SIG) || isCallConv(callingconv, IMAGE_CEE_CS_CALLCONV_GENERICINST)) ) + { + // LocalVar sig does not have return type + // process the return type + IfFailGo(MergeUpdateTokenInFieldSig( + pMiniMdAssemEmit, + pMiniMdEmit, + pCommonAssemImport, + pbHashValue, + cbHashValue, + pCommonImport, + &pbSigImp[cbSrcTotal], + ptkMap, + pqkSigEmit, // output buffer to hold the new sig for the field + cbStartEmit + cbDestTotal, // number of bytes already in pqkSigDest + &cbImp, // number of bytes consumed from imported signature + &cbEmit)); // number of bytes write to the new signature + + // advance the count + cbSrcTotal += cbImp; + cbDestTotal += cbEmit; + } + + + while (cArg) + { + // process every argument + IfFailGo(MergeUpdateTokenInFieldSig( + pMiniMdAssemEmit, + pMiniMdEmit, + pCommonAssemImport, + pbHashValue, + cbHashValue, + pCommonImport, + &pbSigImp[cbSrcTotal], + ptkMap, + pqkSigEmit, // output buffer to hold the new sig for the field + cbStartEmit + cbDestTotal, + &cbImp, // number of bytes consumed from imported signature + &cbEmit)); // number of bytes write to the new signature + cbSrcTotal += cbImp; + cbDestTotal += cbEmit; + cArg--; + } + + // total of number of bytes consumed from imported signature + if (pcbImp) + *pcbImp = cbSrcTotal; + + // total number of bytes emitted by this function call to the emitting signature + *pcbEmit = cbDestTotal; + } + +ErrExit: + return hr; +#else //!FEATURE_METADATA_EMIT + // This code should be called only with public emit APIs + _ASSERTE_MSG(FALSE, "This method should not be reachable"); + return E_NOTIMPL; +#endif //!FEATURE_METADATA_EMIT +} // ImportHelper::MergeUpdateTokenInSig + +//**************************************************************************** +// Given a TypeDef or a TypeRef, return the Nesting hierarchy. The first +// element in the returned array always refers to the class token passed and +// the nesting hierarchy expands outwards from there. +//**************************************************************************** +HRESULT ImportHelper::GetNesterHierarchy( + IMetaModelCommon *pCommon, // Scope in which to find the hierarchy. + mdToken tk, // TypeDef/TypeRef whose hierarchy is needed. + CQuickArray<mdToken> &cqaNesters, // Array of Nesters. + CQuickArray<LPCUTF8> &cqaNamespaces, // Names of the nesters. + CQuickArray<LPCUTF8> &cqaNames) // Namespaces of the nesters. +{ + _ASSERTE(pCommon && + (TypeFromToken(tk) == mdtTypeDef || + TypeFromToken(tk) == mdtTypeRef) && + !IsNilToken(tk)); + + if (TypeFromToken(tk) == mdtTypeDef) + { + return GetTDNesterHierarchy(pCommon, + tk, + cqaNesters, + cqaNamespaces, + cqaNames); + } + else + { + return GetTRNesterHierarchy(pCommon, + tk, + cqaNesters, + cqaNamespaces, + cqaNames); + } +} // HRESULT ImportHelper::GetNesterHierarchy() + +//**************************************************************************** +// Get Nesting hierarchy given a TypeDef. +//**************************************************************************** +HRESULT ImportHelper::GetTDNesterHierarchy( + IMetaModelCommon *pCommon, // Scope in which to find the hierarchy. + mdTypeDef td, // TypeDef whose hierarchy is needed. + CQuickArray<mdTypeDef> &cqaTdNesters,// Array of Nesters. + CQuickArray<LPCUTF8> &cqaNamespaces, // Namespaces of the nesters. + CQuickArray<LPCUTF8> &cqaNames) // Names of the nesters. +{ + LPCUTF8 szName, szNamespace; + DWORD dwFlags; + mdTypeDef tdNester; + ULONG ulNesters; + HRESULT hr = NOERROR; + + _ASSERTE(pCommon && + TypeFromToken(td) == mdtTypeDef && + !IsNilToken(td)); + + // Set current Nester index to 0. + ulNesters = 0; + // The first element in the hierarchy is the TypeDef itself. + tdNester = td; + // Bogus initialization to kick off the while loop. + dwFlags = tdNestedPublic; + // Loop as long as the TypeDef is a Nested TypeDef. + while (IsTdNested(dwFlags)) + { + if (InvalidRid(tdNester)) + IfFailGo(CLDB_E_RECORD_NOTFOUND); + // Get the name and namespace for the TypeDef. + IfFailGo(pCommon->CommonGetTypeDefProps( + tdNester, + &szNamespace, + &szName, + &dwFlags, + NULL, + NULL)); + + // Update the dynamic arrays. + ulNesters++; + + IfFailGo(cqaTdNesters.ReSizeNoThrow(ulNesters)); + cqaTdNesters[ulNesters-1] = tdNester; + + IfFailGo(cqaNamespaces.ReSizeNoThrow(ulNesters)); + cqaNamespaces[ulNesters-1] = szNamespace; + + IfFailGo(cqaNames.ReSizeNoThrow(ulNesters)); + cqaNames[ulNesters-1] = szName; + + IfFailGo(pCommon->CommonGetEnclosingClassOfTypeDef(tdNester, &tdNester)); + } + // Outermost class must have enclosing of Nil. + _ASSERTE(IsNilToken(tdNester)); +ErrExit: + return hr; +} // HRESULT ImportHelper::GetTDNesterHierarchy() + + +//**************************************************************************** +// Get Nesting hierarchy given a TypeRef. +//**************************************************************************** +HRESULT ImportHelper::GetTRNesterHierarchy( + IMetaModelCommon *pCommon, // [IN] Scope in which to find the hierarchy. + mdTypeRef tr, // [IN] TypeRef whose hierarchy is needed. + CQuickArray<mdTypeRef> &cqaTrNesters,// [OUT] Array of Nesters. + CQuickArray<LPCUTF8> &cqaNamespaces, // [OUT] Namespaces of the nesters. + CQuickArray<LPCUTF8> &cqaNames) // [OUT] Names of the nesters. +{ + LPCUTF8 szNamespace; + LPCUTF8 szName; + mdTypeRef trNester; + mdToken tkResolutionScope; + ULONG ulNesters; + HRESULT hr = S_OK; + + _ASSERTE(pCommon && + TypeFromToken(tr) == mdtTypeRef && + !IsNilToken(tr)); + + // Set current Nester index to 0. + ulNesters = 0; + // The first element in the hierarchy is the TypeRef itself. + trNester = tr; + // Loop as long as the TypeRef is a Nested TypeRef. + while (TypeFromToken(trNester) == mdtTypeRef && !IsNilToken(trNester)) + { + // Get the name and namespace for the TypeDef. + IfFailGo(pCommon->CommonGetTypeRefProps( + trNester, + &szNamespace, + &szName, + &tkResolutionScope)); + + // Update the dynamic arrays. + ulNesters++; + + IfFailGo(cqaTrNesters.ReSizeNoThrow(ulNesters)); + cqaTrNesters[ulNesters-1] = trNester; + + IfFailGo(cqaNamespaces.ReSizeNoThrow(ulNesters)); + cqaNamespaces[ulNesters-1] = szNamespace; + + IfFailGo(cqaNames.ReSizeNoThrow(ulNesters)); + cqaNames[ulNesters-1] = szName; + + trNester = tkResolutionScope; + } +ErrExit: + return hr; +} // HRESULT ImportHelper::GetTRNesterHierarchy() + +//**************************************************************************** +// Create the Nesting hierarchy given the array of TypeRef names. The first +// TypeRef in the array is the innermost TypeRef. +//**************************************************************************** +HRESULT ImportHelper::CreateNesterHierarchy( + CMiniMdRW *pMiniMdEmit, // [IN] Emit scope to create the Nesters in. + CQuickArray<LPCUTF8> &cqaNesterNamespaces, // [IN] Array of Nester namespaces. + CQuickArray<LPCUTF8> &cqaNesterNames, // [IN] Array of Nester names. + mdToken tkResolutionScope, // [IN] ResolutionScope for the innermost TypeRef. + mdTypeRef *ptr) // [OUT] Token for the innermost TypeRef. +{ + TypeRefRec *pRecEmit; + ULONG iRecord; + LPCUTF8 szName; + LPCUTF8 szNamespace; + mdTypeRef trNester; + mdTypeRef trCur; + ULONG ulNesters; + HRESULT hr = S_OK; + + _ASSERTE(cqaNesterNames.Size() == cqaNesterNamespaces.Size() && + cqaNesterNames.Size()); + + // Initialize the output parameter. + *ptr = mdTypeRefNil; + + // Get count of Nesters in the hierarchy. + ulNesters = (ULONG)cqaNesterNames.Size(); + + // For each nester try to find the corresponding TypeRef in the emit scope. + // For the outermost TypeRef, ResolutionScope is what's passed in. + if (tkResolutionScope == mdTokenNil) + trNester = mdTypeRefNil; + else + trNester = tkResolutionScope; + ULONG ulCurNester; + for (ulCurNester = ulNesters-1; ulCurNester != (ULONG) -1; ulCurNester--) + { + hr = FindTypeRefByName(pMiniMdEmit, + trNester, + cqaNesterNamespaces[ulCurNester], + cqaNesterNames[ulCurNester], + &trCur); + if (hr == CLDB_E_RECORD_NOTFOUND) + break; + else + IfFailGo(hr); + trNester = trCur; + } + if (SUCCEEDED(hr)) + *ptr = trNester; + else if ( hr == CLDB_E_RECORD_NOTFOUND ) + { + // Create TypeRef records for the part of the hierarchy for which + // TypeRefs are not already present. + for (;ulCurNester != (ULONG) -1; ulCurNester--) + { + szName = cqaNesterNames[ulCurNester]; + szNamespace = cqaNesterNamespaces[ulCurNester]; + + IfFailGo(pMiniMdEmit->AddTypeRefRecord(&pRecEmit, &iRecord)); + if (szNamespace && szNamespace[0] != '\0') + { + // only put the namespace if it is not an empty string and not NULL + IfFailGo(pMiniMdEmit->PutString(TBL_TypeRef, TypeRefRec::COL_Namespace, + pRecEmit, szNamespace)); + } + IfFailGo(pMiniMdEmit->PutString(TBL_TypeRef, TypeRefRec::COL_Name, + pRecEmit, szName)); + IfFailGo(pMiniMdEmit->PutToken(TBL_TypeRef, + TypeRefRec::COL_ResolutionScope, pRecEmit, trNester)); + + trNester = TokenFromRid(iRecord, mdtTypeRef); + IfFailGo(pMiniMdEmit->UpdateENCLog(trNester)); + + // Hash the name. + IfFailGo(pMiniMdEmit->AddNamedItemToHash(TBL_TypeRef, trNester, szName, 0)); + } + *ptr = trNester; + } + else + IfFailGo(hr); +ErrExit: + return hr; +} // ImportHelper::CreateNesterHierarchy + +//**************************************************************************** +// Given the arrays of names and namespaces for the Nested Type hierarchy, +// find the innermost TypeRef token. The arrays start with the innermost +// TypeRefs and go outwards. +//**************************************************************************** +HRESULT ImportHelper::FindNestedTypeRef( + CMiniMdRW *pMiniMd, // [IN] Scope in which to find the TypeRef. + CQuickArray<LPCUTF8> &cqaNesterNamespaces, // [IN] Array of Names. + CQuickArray<LPCUTF8> &cqaNesterNames, // [IN] Array of Namespaces. + mdToken tkResolutionScope, // [IN] Resolution scope for the outermost TypeRef. + mdTypeRef *ptr) // [OUT] Inner most TypeRef token. +{ + ULONG ulNesters; + ULONG ulCurNester; + HRESULT hr = S_OK; + + _ASSERTE(cqaNesterNames.Size() == cqaNesterNamespaces.Size() && + cqaNesterNames.Size()); + + // Set the output parameter to Nil token. + *ptr = mdTokenNil; + + // Get count in the hierarchy, the give TypeDef included. + ulNesters = (ULONG)cqaNesterNames.Size(); + + // For each nester try to find the corresponding TypeRef in + // the emit scope. For the outermost TypeDef enclosing class is Nil. + for (ulCurNester = ulNesters-1; ulCurNester != (ULONG) -1; ulCurNester--) + { + IfFailGo(FindTypeRefByName(pMiniMd, + tkResolutionScope, + cqaNesterNamespaces[ulCurNester], + cqaNesterNames[ulCurNester], + &tkResolutionScope)); + } + *ptr = tkResolutionScope; +ErrExit: + return hr; +} // HRESULT ImportHelper::FindNestedTypeRef() + + +//**************************************************************************** +// Given the arrays of names and namespaces for the Nested Type hierarchy, +// find the innermost TypeDef token. The arrays start with the innermost +// TypeDef and go outwards. +//**************************************************************************** +HRESULT ImportHelper::FindNestedTypeDef( + CMiniMdRW *pMiniMd, // [IN] Scope in which to find the TypeRef. + CQuickArray<LPCUTF8> &cqaNesterNamespaces, // [IN] Array of Namespaces. + CQuickArray<LPCUTF8> &cqaNesterNames, // [IN] Array of Names. + mdTypeDef tdNester, // [IN] Enclosing class for the Outermost TypeDef. + mdTypeDef *ptd) // [OUT] Inner most TypeRef token. +{ + ULONG ulNesters; + ULONG ulCurNester; + HRESULT hr = S_OK; + + _ASSERTE(cqaNesterNames.Size() == cqaNesterNamespaces.Size() && + cqaNesterNames.Size()); + + // Set the output parameter to Nil token. + *ptd = mdTokenNil; + + // Get count in the hierarchy, the give TypeDef included. + ulNesters = (ULONG)cqaNesterNames.Size(); + + // For each nester try to find the corresponding TypeRef in + // the emit scope. For the outermost TypeDef enclosing class is Nil. + for (ulCurNester = ulNesters-1; ulCurNester != (ULONG) -1; ulCurNester--) + { + IfFailGo(FindTypeDefByName(pMiniMd, + cqaNesterNamespaces[ulCurNester], + cqaNesterNames[ulCurNester], + tdNester, + &tdNester)); + } + *ptd = tdNester; +ErrExit: + return hr; +} // ImportHelper::FindNestedTypeDef + +#ifdef FEATURE_METADATA_EMIT + +//**************************************************************************** +// Given the TypeDef and the corresponding assembly and module import scopes, +// create a corresponding TypeRef in the given emit scope. +//**************************************************************************** +HRESULT +ImportHelper::ImportTypeDef( + CMiniMdRW * pMiniMdAssemEmit, // [IN] Assembly emit scope. + CMiniMdRW * pMiniMdEmit, // [IN] Module emit scope. + IMetaModelCommon * pCommonAssemImport, // [IN] Assembly import scope. + const void * pbHashValue, // [IN] Hash value for import assembly. + ULONG cbHashValue, // [IN] Size in bytes of hash value. + IMetaModelCommon * pCommonImport, // [IN] Module import scope. + mdTypeDef tdImport, // [IN] Imported TypeDef. + bool bReturnTd, // [IN] If the import and emit scopes are identical, return the TypeDef. + mdToken * ptkType) // [OUT] Output token for the imported type in the emit scope. +{ + CQuickArray<mdTypeDef> cqaNesters; + CQuickArray<LPCUTF8> cqaNesterNames; + CQuickArray<LPCUTF8> cqaNesterNamespaces; + GUID nullguid = GUID_NULL; + GUID MvidAssemImport = nullguid; + GUID MvidAssemEmit = nullguid; + GUID MvidImport = nullguid; + GUID MvidEmit = nullguid; + GUID GuidImport = GUID_NULL; + LPCUTF8 szModuleImport; + mdToken tkOuterRes = mdTokenNil; + HRESULT hr = S_OK; + BOOL bBCL = false; + + _ASSERTE(pMiniMdEmit && pCommonImport && ptkType); + _ASSERTE(TypeFromToken(tdImport) == mdtTypeDef && tdImport != mdTypeDefNil); + + // Get MVIDs for import and emit, assembly and module scopes. + if (pCommonAssemImport != NULL) + { + IfFailGo(pCommonAssemImport->CommonGetScopeProps(0, &MvidAssemImport)); + } + IfFailGo(pCommonImport->CommonGetScopeProps(&szModuleImport, &MvidImport)); + if (pMiniMdAssemEmit != NULL) + { + IfFailGo(static_cast<IMetaModelCommon*>(pMiniMdAssemEmit)->CommonGetScopeProps(0, &MvidAssemEmit)); + } + IfFailGo(static_cast<IMetaModelCommon*>(pMiniMdEmit)->CommonGetScopeProps(0, &MvidEmit)); + + if (pCommonAssemImport == NULL && strcmp(szModuleImport, COM_RUNTIME_LIBRARY) == 0) + { + const BYTE *pBlob; // Blob with dispid. + ULONG cbBlob; // Length of blob. + WCHAR wzBlob[40]; // Wide char format of guid. + int ix; // Loop control. + + hr = pCommonImport->CommonGetCustomAttributeByName(1, INTEROP_GUID_TYPE, (const void **)&pBlob, &cbBlob); + if (hr != S_FALSE) + { + // Should be in format. Total length == 41 + // <0x0001><0x24>01234567-0123-0123-0123-001122334455<0x0000> + if ((cbBlob == 41) || (GET_UNALIGNED_VAL16(pBlob) == 1)) + { + for (ix=1; ix<=36; ++ix) + wzBlob[ix] = pBlob[ix+2]; + wzBlob[0] = '{'; + wzBlob[37] = '}'; + wzBlob[38] = 0; + // It's ok that we ignore the hr here. It's not needed, but I + // don't want to remove it in case a code analysis tool will complain + // about not capturing return codes. + hr = IIDFromString(wzBlob, &GuidImport); + } + } + bBCL = (GuidImport == LIBID_ComPlusRuntime); + } + + // Compute the ResolutionScope for the imported type. + if (bBCL) + { + // This is the case that we are referring to mscorlib.dll but client does not provide the manifest for + // mscorlib.dll!! Do not generate ModuleRef to the mscorlib.dll. But instead we should just leave the + // ResolutionScope empty + tkOuterRes = mdTokenNil; + } + else if (MvidAssemImport == MvidAssemEmit && MvidImport == MvidEmit) + { + // The TypeDef is in the same Assembly and the Same scope. + if (bReturnTd) + { + *ptkType = tdImport; + goto ErrExit; + } + else + tkOuterRes = TokenFromRid(1, mdtModule); + } + else if (MvidAssemImport == MvidAssemEmit && MvidImport != MvidEmit) + { + // The TypeDef is in the same Assembly but a different module. + + // Create a ModuleRef corresponding to the import scope. + IfFailGo(CreateModuleRefFromScope(pMiniMdEmit, pCommonImport, &tkOuterRes)); + } + else if (MvidAssemImport != MvidAssemEmit) + { + if (pCommonAssemImport) + { + // The TypeDef is from a different Assembly. + + // Import and Emit scopes can't be identical and be from different + // Assemblies at the same time. + _ASSERTE(MvidImport != MvidEmit && + "Import scope can't be identical to the Emit scope and be from a different Assembly at the same time."); + + _ASSERTE(pCommonAssemImport); + + // Create an AssemblyRef corresponding to the import scope. + IfFailGo(CreateAssemblyRefFromAssembly(pMiniMdAssemEmit, + pMiniMdEmit, + pCommonAssemImport, + pbHashValue, + cbHashValue, + &tkOuterRes)); + } + else + { + // <REVISIT_TODO>@FUTURE: review this fix! We may want to return error in the future. + // This is to enable smc to reference mscorlib.dll while it does not have the manifest for mscorlib.dll opened.</REVISIT_TODO> + // Create a Nil ResolutionScope to the TypeRef. + tkOuterRes = mdTokenNil; + } + } + + // Get the nesting hierarchy for the Type from the import scope and create + // the corresponding Type hierarchy in the emit scope. Note that the non- + // nested class case simply folds into this scheme. + + IfFailGo(GetNesterHierarchy(pCommonImport, + tdImport, + cqaNesters, + cqaNesterNamespaces, + cqaNesterNames)); + + IfFailGo(CreateNesterHierarchy(pMiniMdEmit, + cqaNesterNamespaces, + cqaNesterNames, + tkOuterRes, + ptkType)); +ErrExit: + return hr; +} // ImportHelper::ImportTypeDef + +//**************************************************************************** +// Given the TypeRef and the corresponding assembly and module import scopes, +// return the corresponding token in the given emit scope. +// <REVISIT_TODO>@FUTURE: Should we look at visibility flags on ExportedTypes and TypeDefs when +// handling references across Assemblies?</REVISIT_TODO> +//**************************************************************************** +HRESULT ImportHelper::ImportTypeRef( + CMiniMdRW *pMiniMdAssemEmit, // [IN] Assembly emit scope. + CMiniMdRW *pMiniMdEmit, // [IN] Module emit scope. + IMetaModelCommon *pCommonAssemImport, // [IN] Assembly import scope. + const void *pbHashValue, // [IN] Hash value for import assembly. + ULONG cbHashValue, // [IN] Size in bytes of hash value. + IMetaModelCommon *pCommonImport, // [IN] Module import scope. + mdTypeRef trImport, // [IN] Imported TypeRef. + mdToken *ptkType) // [OUT] Output token for the imported type in the emit scope. +{ + CQuickArray<mdTypeDef> cqaNesters; + CQuickArray<LPCUTF8> cqaNesterNames; + CQuickArray<LPCUTF8> cqaNesterNamespaces; + LPCUTF8 szScopeNameEmit; + GUID nullguid = GUID_NULL; + GUID MvidAssemImport = nullguid; + GUID MvidAssemEmit = nullguid; + GUID MvidImport = nullguid; + GUID MvidEmit = nullguid; + mdToken tkOuterImportRes; // ResolutionScope for the outermost TypeRef in import scope. + mdToken tkOuterEmitRes = mdTokenNil; // ResolutionScope for outermost TypeRef in emit scope. + HRESULT hr = S_OK; + bool bAssemblyRefFromAssemScope = false; + + _ASSERTE(pMiniMdEmit && pCommonImport && ptkType); + _ASSERTE(TypeFromToken(trImport) == mdtTypeRef); + + // Get MVIDs for import and emit, assembly and module scopes. + if (pCommonAssemImport != NULL) + { + IfFailGo(pCommonAssemImport->CommonGetScopeProps(0, &MvidAssemImport)); + } + IfFailGo(pCommonImport->CommonGetScopeProps(0, &MvidImport)); + if (pMiniMdAssemEmit != NULL) + { + IfFailGo(static_cast<IMetaModelCommon*>(pMiniMdAssemEmit)->CommonGetScopeProps( + 0, + &MvidAssemEmit)); + } + IfFailGo(static_cast<IMetaModelCommon*>(pMiniMdEmit)->CommonGetScopeProps( + &szScopeNameEmit, + &MvidEmit)); + + // Get the outermost resolution scope for the TypeRef being imported. + IfFailGo(GetNesterHierarchy(pCommonImport, + trImport, + cqaNesters, + cqaNesterNamespaces, + cqaNesterNames)); + IfFailGo(pCommonImport->CommonGetTypeRefProps( + cqaNesters[cqaNesters.Size() - 1], + 0, + 0, + &tkOuterImportRes)); + + // Compute the ResolutionScope for the imported type. + if (MvidAssemImport == MvidAssemEmit && MvidImport == MvidEmit) + { + *ptkType = trImport; + goto ErrExit; + } + else if (MvidAssemImport == MvidAssemEmit && MvidImport != MvidEmit) + { + // The TypeRef is in the same Assembly but a different module. + + if (IsNilToken(tkOuterImportRes)) + { + tkOuterEmitRes = tkOuterImportRes; + } + else if (TypeFromToken(tkOuterImportRes) == mdtModule) + { + // TypeRef resolved to the import module in which its defined. + + // + if (pMiniMdAssemEmit == NULL && pCommonAssemImport == NULL) + { + tkOuterEmitRes = TokenFromRid(1, mdtModule); + } + else + { + // Create a ModuleRef corresponding to the import scope. + IfFailGo(CreateModuleRefFromScope(pMiniMdEmit, + pCommonImport, + &tkOuterEmitRes)); + } + } + else if (TypeFromToken(tkOuterImportRes) == mdtAssemblyRef) + { + // TypeRef is from a different Assembly. + + // Create a corresponding AssemblyRef in the emit scope. + IfFailGo(CreateAssemblyRefFromAssemblyRef(pMiniMdAssemEmit, + pMiniMdEmit, + pCommonImport, + tkOuterImportRes, + &tkOuterEmitRes)); + } + else if (TypeFromToken(tkOuterImportRes) == mdtModuleRef) + { + // Get Name of the ModuleRef. + LPCUTF8 szMRName; + IfFailGo(pCommonImport->CommonGetModuleRefProps(tkOuterImportRes, &szMRName)); + + if (!strcmp(szMRName, szScopeNameEmit)) + { + // ModuleRef from import scope resolves to the emit scope. + tkOuterEmitRes = TokenFromRid(1, mdtModule); + } + else + { + // ModuleRef does not correspond to the emit scope. + // Create a corresponding ModuleRef. + IfFailGo(CreateModuleRefFromModuleRef(pMiniMdEmit, + pCommonImport, + tkOuterImportRes, + &tkOuterEmitRes)); + } + } + } + else if (MvidAssemImport != MvidAssemEmit) + { + // The TypeDef is from a different Assembly. + + // Import and Emit scopes can't be identical and be from different + // Assemblies at the same time. + _ASSERTE(MvidImport != MvidEmit && + "Import scope can't be identical to the Emit scope and be from a different Assembly at the same time."); + + mdToken tkImplementation; // Implementation token for ExportedType. + if (IsNilToken(tkOuterImportRes)) + { + // <REVISIT_TODO>BUG FIX:: URT 13626 + // Well, before all of the clients generate AR for mscorlib.dll reference, it is not true + // that tkOuterImportRes == nil will imply that we have to find such an entry in the import manifest!!</REVISIT_TODO> + + // Look for a ExportedType entry in the import Assembly. Its an error + // if we don't find a ExportedType entry. + mdExportedType tkExportedType; + hr = pCommonAssemImport->CommonFindExportedType( + cqaNesterNamespaces[cqaNesters.Size() - 1], + cqaNesterNames[cqaNesters.Size() - 1], + mdTokenNil, + &tkExportedType); + if (SUCCEEDED(hr)) + { + IfFailGo(pCommonAssemImport->CommonGetExportedTypeProps( + tkExportedType, + NULL, + NULL, + &tkImplementation)); + if (TypeFromToken(tkImplementation) == mdtFile) + { + // Type is from a different Assembly. + IfFailGo(CreateAssemblyRefFromAssembly(pMiniMdAssemEmit, + pMiniMdEmit, + pCommonAssemImport, + pbHashValue, + cbHashValue, + &tkOuterEmitRes)); + } + else if (TypeFromToken(tkImplementation) == mdtAssemblyRef) + { + // This folds into the case where the Type is AssemblyRef. So + // let it fall through to that case. + + // Remember that this AssemblyRef token is actually from the Manifest scope not + // the module scope!!! + bAssemblyRefFromAssemScope = true; + tkOuterImportRes = tkImplementation; + } + else + _ASSERTE(!"Unexpected ExportedType implementation token."); + } + else + { + // In this case, we will just move over the TypeRef with Nil ResolutionScope. + hr = NOERROR; + tkOuterEmitRes = mdTokenNil; + } + } + else if (TypeFromToken(tkOuterImportRes) == mdtModule) + { + // Type is from a different Assembly. + IfFailGo(CreateAssemblyRefFromAssembly(pMiniMdAssemEmit, + pMiniMdEmit, + pCommonAssemImport, + pbHashValue, + cbHashValue, + &tkOuterEmitRes)); + } + // Not else if, because mdtModule case above could change + // tkOuterImportRes to an AssemblyRef. + if (TypeFromToken(tkOuterImportRes) == mdtAssemblyRef) + { + // If there is an emit assembly, see if the import assembly ref points to + // it. If there is no emit assembly, the import assembly, by definition, + // does not point to this one. + if (pMiniMdAssemEmit == NULL || !pMiniMdAssemEmit->getCountAssemblys()) + hr = S_FALSE; + else + { + if (bAssemblyRefFromAssemScope) + { + // Check to see if the AssemblyRef resolves to the emit assembly. + IfFailGo(CompareAssemblyRefToAssembly(pCommonAssemImport, + tkOuterImportRes, + static_cast<IMetaModelCommon*>(pMiniMdAssemEmit))); + + } + else + { + // Check to see if the AssemblyRef resolves to the emit assembly. + IfFailGo(CompareAssemblyRefToAssembly(pCommonImport, + tkOuterImportRes, + static_cast<IMetaModelCommon*>(pMiniMdAssemEmit))); + } + } + if (hr == S_OK) + { + // The TypeRef being imported is defined in the current Assembly. + + // Find the ExportedType for the outermost TypeRef in the Emit assembly. + mdExportedType tkExportedType; + + hr = FindExportedType(pMiniMdAssemEmit, + cqaNesterNamespaces[cqaNesters.Size() - 1], + cqaNesterNames[cqaNesters.Size() - 1], + mdTokenNil, // Enclosing ExportedType. + &tkExportedType); + if (hr == S_OK) + { + // Create a ModuleRef based on the File name for the ExportedType. + // If the ModuleRef corresponds to pMiniMdEmit, the function + // will return S_FALSE, in which case set tkOuterEmitRes to + // the Module token. + hr = CreateModuleRefFromExportedType(pMiniMdAssemEmit, + pMiniMdEmit, + tkExportedType, + &tkOuterEmitRes); + if (hr == S_FALSE) + tkOuterEmitRes = TokenFromRid(1, mdtModule); + else + IfFailGo(hr); + } + else if (hr == CLDB_E_RECORD_NOTFOUND) + { + // Find the Type in the Assembly emit scope to cover the + // case where ExportedTypes may be implicitly defined. Its an + // error if we can't find the Type at this point. + IfFailGo(FindTypeDefByName(pMiniMdAssemEmit, + cqaNesterNamespaces[cqaNesters.Size() - 1], + cqaNesterNames[cqaNesters.Size() - 1], + mdTokenNil, // Enclosing Type. + &tkOuterEmitRes)); + tkOuterEmitRes = TokenFromRid(1, mdtModule); + } + else + { + _ASSERTE(FAILED(hr)); + IfFailGo(hr); + } + } + else if (hr == S_FALSE) + { + // The TypeRef being imported is from a different Assembly. + + if (bAssemblyRefFromAssemScope) + { + // Create a corresponding AssemblyRef. + IfFailGo(CreateAssemblyRefFromAssemblyRef(pMiniMdAssemEmit, + pMiniMdEmit, + pCommonAssemImport, + tkOuterImportRes, + &tkOuterEmitRes)); + } + else + { + // Create a corresponding AssemblyRef. + IfFailGo(CreateAssemblyRefFromAssemblyRef(pMiniMdAssemEmit, + pMiniMdEmit, + pCommonImport, + tkOuterImportRes, + &tkOuterEmitRes)); + } + } + else + { + _ASSERTE(FAILED(hr)); + IfFailGo(hr); + } + } + else if (TypeFromToken(tkOuterImportRes) == mdtModuleRef) + { + // Type is from a different Assembly. + IfFailGo(CreateAssemblyRefFromAssembly(pMiniMdAssemEmit, + pMiniMdEmit, + pCommonAssemImport, + pbHashValue, + cbHashValue, + &tkOuterEmitRes)); + } + } + + // Try to find the TypeDef in the emit scope. If we cannot find the + // typedef, we need to introduce a typeref. + + // See if the Nested TypeDef is present in the Emit scope. + hr = CLDB_E_RECORD_NOTFOUND; + if (TypeFromToken(tkOuterEmitRes) == mdtModule && !IsNilToken(tkOuterEmitRes)) + { + hr = FindNestedTypeDef(pMiniMdEmit, + cqaNesterNamespaces, + cqaNesterNames, + mdTokenNil, + ptkType); + + // <REVISIT_TODO>cannot assert now!! Due to the IJW workaround! + // _ASSERTE(SUCCEEDED(hr));</REVISIT_TODO> + } + + if (hr == CLDB_E_RECORD_NOTFOUND) + { + IfFailGo(CreateNesterHierarchy(pMiniMdEmit, + cqaNesterNamespaces, + cqaNesterNames, + tkOuterEmitRes, + ptkType)); + } + else + IfFailGo(hr); +ErrExit: + return hr; +} // ImportHelper::ImportTypeRef + +//****************************************************************************** +// Given import scope, create a corresponding ModuleRef. +//****************************************************************************** +HRESULT ImportHelper::CreateModuleRefFromScope( // S_OK or error. + CMiniMdRW *pMiniMdEmit, // [IN] Emit scope in which the ModuleRef is to be created. + IMetaModelCommon *pCommonImport, // [IN] Import scope. + mdModuleRef *ptkModuleRef) // [OUT] Output token for ModuleRef. +{ + HRESULT hr = S_OK; + LPCSTR szName; + ModuleRefRec *pRecordEmit; + RID iRecordEmit; + + // Set output to nil. + *ptkModuleRef = mdTokenNil; + + // Get name of import scope. + IfFailGo(pCommonImport->CommonGetScopeProps(&szName, 0)); + + // See if the ModuleRef exists in the Emit scope. + hr = FindModuleRef(pMiniMdEmit, szName, ptkModuleRef); + + if (hr == CLDB_E_RECORD_NOTFOUND) + { + if (szName[0] == '\0') + { + // It the referenced Module does not have a proper name, use the nil token instead. + LOG((LOGMD, "WARNING!!! MD ImportHelper::CreatemoduleRefFromScope but scope does not have a proper name!!!!")); + + // clear the error + hr = NOERROR; + + // It is a bug to create an ModuleRef to an empty name!!! + *ptkModuleRef = mdTokenNil; + } + else + { + // Create ModuleRef record and set the output parameter. + IfFailGo(pMiniMdEmit->AddModuleRefRecord(&pRecordEmit, &iRecordEmit)); + *ptkModuleRef = TokenFromRid(iRecordEmit, mdtModuleRef); + IfFailGo(pMiniMdEmit->UpdateENCLog(*ptkModuleRef)); + + // It is a bug to create an ModuleRef to mscorlib.dll + _ASSERTE(strcmp(szName, COM_RUNTIME_LIBRARY) != 0); + + // Set the name of ModuleRef. + IfFailGo(pMiniMdEmit->PutString(TBL_ModuleRef, ModuleRefRec::COL_Name, + pRecordEmit, szName)); + } + } + else + IfFailGo(hr); +ErrExit: + return hr; +} // ImportHelper::CreateModuleRefFromScope + + +//****************************************************************************** +// Given an import scope and a ModuleRef, create a corresponding ModuleRef in +// the given emit scope. +//****************************************************************************** +HRESULT ImportHelper::CreateModuleRefFromModuleRef( // S_OK or error. + CMiniMdRW *pMiniMdEmit, // [IN] Emit scope. + IMetaModelCommon *pCommon, // [IN] Import scope. + mdModuleRef tkModuleRef, // [IN] ModuleRef token. + mdModuleRef *ptkModuleRef) // [OUT] ModuleRef token in the emit scope. +{ + HRESULT hr = S_OK; + LPCSTR szName; + ModuleRefRec *pRecord; + RID iRecord; + + // Set output to Nil. + *ptkModuleRef = mdTokenNil; + + // Get name of the ModuleRef being imported. + IfFailGo(pCommon->CommonGetModuleRefProps(tkModuleRef, &szName)); + + // See if the ModuleRef exist in the Emit scope. + hr = FindModuleRef(pMiniMdEmit, szName, ptkModuleRef); + + if (hr == CLDB_E_RECORD_NOTFOUND) + { + // Create ModuleRef record and set the output parameter. + IfFailGo(pMiniMdEmit->AddModuleRefRecord(&pRecord, &iRecord)); + *ptkModuleRef = TokenFromRid(iRecord, mdtModuleRef); + IfFailGo(pMiniMdEmit->UpdateENCLog(*ptkModuleRef)); + + // Set the name of ModuleRef. + IfFailGo(pMiniMdEmit->PutString(TBL_ModuleRef, ModuleRefRec::COL_Name, + pRecord, szName)); + } + else + { + IfFailGo(hr); + } +ErrExit: + return hr; +} // ImportHelper::CreateModuleRefFromModuleRef + + +//****************************************************************************** +// Given a ExportedType and the Assembly emit scope, create a corresponding ModuleRef +// in the give emit scope. The ExportedType being passed in must belong to the +// Assembly passed in. Function returns S_FALSE if the ExportedType is implemented +// by the emit scope passed in. +//****************************************************************************** +HRESULT ImportHelper::CreateModuleRefFromExportedType( // S_OK or error. + CMiniMdRW *pAssemEmit, // [IN] Import assembly scope. + CMiniMdRW *pMiniMdEmit, // [IN] Emit scope. + mdExportedType tkExportedType, // [IN] ExportedType token in Assembly emit scope. + mdModuleRef *ptkModuleRef) // [OUT] ModuleRef token in the emit scope. +{ + mdFile tkFile; + LPCUTF8 szFile; + LPCUTF8 szScope; + FileRec *pFileRec; + HRESULT hr = S_OK; + + // Set output to nil. + *ptkModuleRef = mdTokenNil; + + // Get the implementation token for the ExportedType. It must be a File token + // since the caller should call this function only on ExportedTypes that resolve + // to the same Assembly. + IfFailGo(static_cast<IMetaModelCommon*>(pAssemEmit)->CommonGetExportedTypeProps( + tkExportedType, + NULL, + NULL, + &tkFile)); + _ASSERTE(TypeFromToken(tkFile) == mdtFile); + + // Get the name of the file. + IfFailGo(pAssemEmit->GetFileRecord(RidFromToken(tkFile), &pFileRec)); + IfFailGo(pAssemEmit->getNameOfFile(pFileRec, &szFile)); + + // Get the name of the emit scope. + IfFailGo(static_cast<IMetaModelCommon*>(pMiniMdEmit)->CommonGetScopeProps( + &szScope, + 0)); + + // If the file corresponds to the emit scope, return S_FALSE; + if (!strcmp(szFile, szScope)) + return S_FALSE; + + // See if a ModuleRef exists with this name. + hr = FindModuleRef(pMiniMdEmit, szFile, ptkModuleRef); + + if (hr == CLDB_E_RECORD_NOTFOUND) + { + // Create ModuleRef record and set the output parameter. + + ModuleRefRec *pRecord; + RID iRecord; + + IfFailGo(pMiniMdEmit->AddModuleRefRecord(&pRecord, &iRecord)); + *ptkModuleRef = TokenFromRid(iRecord, mdtModuleRef); + IfFailGo(pMiniMdEmit->UpdateENCLog(*ptkModuleRef)); + + // Set the name of ModuleRef. + IfFailGo(pMiniMdEmit->PutString(TBL_ModuleRef, ModuleRefRec::COL_Name, + pRecord, szFile)); + } + else + IfFailGo(hr); +ErrExit: + return hr; +} // ImportHelper::CreateModuleRefFromExportedType + +//****************************************************************************** +// Given an AssemblyRef and the corresponding scope, create an AssemblyRef in +// the given Module scope and Assembly scope. +//****************************************************************************** +HRESULT ImportHelper::CreateAssemblyRefFromAssemblyRef( + CMiniMdRW *pMiniMdAssemEmit, // [IN] Assembly emit scope. + CMiniMdRW *pMiniMdModuleEmit, // [IN] Module emit scope + IMetaModelCommon *pCommonImport, // [IN] Scope to import the assembly ref from. + mdAssemblyRef tkAssemRef, // [IN] Assembly ref to be imported. + mdAssemblyRef *ptkAssemblyRef) // [OUT] AssemblyRef in the emit scope. +{ + AssemblyRefRec *pRecordEmit; + CMiniMdRW *rMiniMdRW[2]; + CMiniMdRW *pMiniMdEmit; + RID iRecordEmit; + USHORT usMajorVersion; + USHORT usMinorVersion; + USHORT usBuildNumber; + USHORT usRevisionNumber; + DWORD dwFlags; + const void *pbPublicKeyOrToken; + ULONG cbPublicKeyOrToken; + LPCUTF8 szName; + LPCUTF8 szLocale; + const void *pbHashValue; + ULONG cbHashValue; + HRESULT hr = S_OK; + + // Set output to Nil. + *ptkAssemblyRef = mdTokenNil; + + // Get import AssemblyRef props. + IfFailGo(pCommonImport->CommonGetAssemblyRefProps( + tkAssemRef, + &usMajorVersion, &usMinorVersion, &usBuildNumber, &usRevisionNumber, + &dwFlags, &pbPublicKeyOrToken, &cbPublicKeyOrToken, + &szName, &szLocale, + &pbHashValue, &cbHashValue)); + + // Create the AssemblyRef in both the Assembly and Module emit scopes. + rMiniMdRW[0] = pMiniMdAssemEmit; + rMiniMdRW[1] = pMiniMdModuleEmit; + + for (ULONG i = 0; i < 2; i++) + { + pMiniMdEmit = rMiniMdRW[i]; + + if (!pMiniMdEmit) + continue; + + // See if the AssemblyRef already exists in the emit scope. + hr = FindAssemblyRef(pMiniMdEmit, szName, szLocale, pbPublicKeyOrToken, + cbPublicKeyOrToken, usMajorVersion, usMinorVersion, + usBuildNumber, usRevisionNumber, dwFlags, &tkAssemRef); + if (hr == CLDB_E_RECORD_NOTFOUND) + { + // Create the AssemblyRef record and set the output parameter. + IfFailGo(pMiniMdEmit->AddAssemblyRefRecord(&pRecordEmit, &iRecordEmit)); + tkAssemRef = TokenFromRid(iRecordEmit, mdtAssemblyRef); + IfFailGo(pMiniMdEmit->UpdateENCLog(tkAssemRef)); + + // Set parameters derived from the import Assembly. + pRecordEmit->SetMajorVersion(usMajorVersion); + pRecordEmit->SetMinorVersion(usMinorVersion); + pRecordEmit->SetBuildNumber(usBuildNumber); + pRecordEmit->SetRevisionNumber(usRevisionNumber); + pRecordEmit->SetFlags(dwFlags); + + IfFailGo(pMiniMdEmit->PutBlob(TBL_AssemblyRef, AssemblyRefRec::COL_PublicKeyOrToken, + pRecordEmit, pbPublicKeyOrToken, cbPublicKeyOrToken)); + IfFailGo(pMiniMdEmit->PutString(TBL_AssemblyRef, AssemblyRefRec::COL_Name, + pRecordEmit, szName)); + IfFailGo(pMiniMdEmit->PutString(TBL_AssemblyRef, AssemblyRefRec::COL_Locale, + pRecordEmit, szLocale)); + + // Set the parameters passed in for the AssemblyRef. + IfFailGo(pMiniMdEmit->PutBlob(TBL_AssemblyRef, AssemblyRefRec::COL_HashValue, + pRecordEmit, pbHashValue, cbHashValue)); + } + else + IfFailGo(hr); + + // Set the output parameter for the AssemblyRef emitted in Module emit scope. + if (i) + *ptkAssemblyRef = tkAssemRef; + } +ErrExit: + return hr; +} // ImportHelper::CreateAssemblyRefFromAssemblyRef + +//****************************************************************************** +// Given the Assembly Import scope, hash value and execution location, create +// a corresponding AssemblyRef in the given assembly and module emit scope. +// Set the output parameter to the AssemblyRef token emitted in the module emit +// scope. +//****************************************************************************** +HRESULT +ImportHelper::CreateAssemblyRefFromAssembly( + CMiniMdRW * pMiniMdAssemEmit, // [IN] Emit assembly scope. + CMiniMdRW * pMiniMdModuleEmit, // [IN] Emit module scope. + IMetaModelCommon * pCommonAssemImport, // [IN] Assembly import scope. + const void * pbHashValue, // [IN] Hash Blob for Assembly. + ULONG cbHashValue, // [IN] Count of bytes. + mdAssemblyRef * ptkAssemblyRef) // [OUT] AssemblyRef token. +{ +#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER + return E_NOTIMPL; +#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER + AssemblyRefRec *pRecordEmit; + CMiniMdRW *rMiniMdRW[2]; + CMiniMdRW *pMiniMdEmit; + RID iRecordEmit; + USHORT usMajorVersion; + USHORT usMinorVersion; + USHORT usBuildNumber; + USHORT usRevisionNumber; + DWORD dwFlags; + const void *pbPublicKey; + ULONG cbPublicKey; + LPCUTF8 szName; + LPCUTF8 szLocale; + mdAssemblyRef tkAssemRef; + HRESULT hr = S_OK; + const void *pbToken = NULL; + ULONG cbToken = 0; + ULONG i; + + // Set output to Nil. + *ptkAssemblyRef = mdTokenNil; + + // Get the Assembly props. + IfFailGo(pCommonAssemImport->CommonGetAssemblyProps( + &usMajorVersion, &usMinorVersion, &usBuildNumber, &usRevisionNumber, + &dwFlags, &pbPublicKey, &cbPublicKey, + &szName, &szLocale)); + + // Compress the public key into a token. + if ((pbPublicKey != NULL) && (cbPublicKey != 0)) + { + _ASSERTE(IsAfPublicKey(dwFlags)); + dwFlags &= ~afPublicKey; + if (!StrongNameTokenFromPublicKey((BYTE*)pbPublicKey, + cbPublicKey, + (BYTE**)&pbToken, + &cbToken)) + IfFailGo(StrongNameErrorInfo()); + } + else + _ASSERTE(!IsAfPublicKey(dwFlags)); + + // Create the AssemblyRef in both the Assembly and Module emit scopes. + rMiniMdRW[0] = pMiniMdAssemEmit; + rMiniMdRW[1] = pMiniMdModuleEmit; + + for (i = 0; i < 2; i++) + { + pMiniMdEmit = rMiniMdRW[i]; + + if (!pMiniMdEmit) + continue; + + // See if the AssemblyRef already exists in the emit scope. + hr = FindAssemblyRef(pMiniMdEmit, szName, szLocale, pbToken, + cbToken, usMajorVersion, usMinorVersion, + usBuildNumber, usRevisionNumber, dwFlags, + &tkAssemRef); + if (hr == CLDB_E_RECORD_NOTFOUND) + { + // Create the AssemblyRef record and set the output parameter. + IfFailGo(pMiniMdEmit->AddAssemblyRefRecord(&pRecordEmit, &iRecordEmit)); + tkAssemRef = TokenFromRid(iRecordEmit, mdtAssemblyRef); + IfFailGo(pMiniMdEmit->UpdateENCLog(tkAssemRef)); + + // Set parameters derived from the import Assembly. + pRecordEmit->SetMajorVersion(usMajorVersion); + pRecordEmit->SetMinorVersion(usMinorVersion); + pRecordEmit->SetBuildNumber(usBuildNumber); + pRecordEmit->SetRevisionNumber(usRevisionNumber); + pRecordEmit->SetFlags(dwFlags); + + IfFailGo(pMiniMdEmit->PutBlob(TBL_AssemblyRef, AssemblyRefRec::COL_PublicKeyOrToken, + pRecordEmit, pbToken, cbToken)); + IfFailGo(pMiniMdEmit->PutString(TBL_AssemblyRef, AssemblyRefRec::COL_Name, + pRecordEmit, szName)); + IfFailGo(pMiniMdEmit->PutString(TBL_AssemblyRef, AssemblyRefRec::COL_Locale, + pRecordEmit, szLocale)); + + // Set the parameters passed in for the AssemblyRef. + IfFailGo(pMiniMdEmit->PutBlob(TBL_AssemblyRef, AssemblyRefRec::COL_HashValue, + pRecordEmit, pbHashValue, cbHashValue)); + } + else + IfFailGo(hr); + + // Set the output parameter for the AssemblyRef emitted in Module emit scope. + if (i) + *ptkAssemblyRef = tkAssemRef; + } +ErrExit: + if (pbToken) + StrongNameFreeBuffer((BYTE*)pbToken); + return hr; +#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER +} // ImportHelper::CreateAssemblyRefFromAssembly + +//****************************************************************************** +// Given an AssemblyRef and the corresponding scope, compare it to see if it +// refers to the given Assembly. +//****************************************************************************** +HRESULT ImportHelper::CompareAssemblyRefToAssembly( // S_OK, S_FALSE or error. + IMetaModelCommon *pCommonAssem1, // [IN] Scope that defines the AssemblyRef. + mdAssemblyRef tkAssemRef, // [IN] AssemblyRef. + IMetaModelCommon *pCommonAssem2) // [IN] Assembly against which the Ref is compared. +{ +#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER + return E_NOTIMPL; +#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER + HRESULT hr; + + USHORT usMajorVersion1; + USHORT usMinorVersion1; + USHORT usBuildNumber1; + USHORT usRevisionNumber1; + const void *pbPublicKeyOrToken1; + ULONG cbPublicKeyOrToken1; + LPCUTF8 szName1; + LPCUTF8 szLocale1; + DWORD dwFlags1; + + USHORT usMajorVersion2; + USHORT usMinorVersion2; + USHORT usBuildNumber2; + USHORT usRevisionNumber2; + const void *pbPublicKey2; + ULONG cbPublicKey2; + LPCUTF8 szName2; + LPCUTF8 szLocale2; + const void *pbToken = NULL; + ULONG cbToken = 0; + bool fMatch; + + // Get the AssemblyRef props. + IfFailRet(pCommonAssem1->CommonGetAssemblyRefProps( + tkAssemRef, + &usMajorVersion1, &usMinorVersion1, &usBuildNumber1, &usRevisionNumber1, + &dwFlags1, &pbPublicKeyOrToken1, &cbPublicKeyOrToken1, + &szName1, &szLocale1, + NULL, NULL)); + // Get the Assembly props. + IfFailRet(pCommonAssem2->CommonGetAssemblyProps( + &usMajorVersion2, &usMinorVersion2, &usBuildNumber2, &usRevisionNumber2, + 0, &pbPublicKey2, &cbPublicKey2, + &szName2, &szLocale2)); + + // Compare. + if (usMajorVersion1 != usMajorVersion2 || + usMinorVersion1 != usMinorVersion2 || + usBuildNumber1 != usBuildNumber2 || + usRevisionNumber1 != usRevisionNumber2 || + strcmp(szName1, szName2) || + strcmp(szLocale1, szLocale2)) + { + return S_FALSE; + } + + // Defs always contain a full public key (or no key at all). Refs may have + // no key, a full public key or a tokenized key. + if ((cbPublicKeyOrToken1 && !cbPublicKey2) || + (!cbPublicKeyOrToken1 && cbPublicKey2)) + return S_FALSE; + + if (cbPublicKeyOrToken1) + { + // If ref contains a full public key we can just directly compare. + if (IsAfPublicKey(dwFlags1) && + (cbPublicKeyOrToken1 != cbPublicKey2 || + memcmp(pbPublicKeyOrToken1, pbPublicKey2, cbPublicKeyOrToken1))) + return S_FALSE; + + // Otherwise we need to compress the def public key into a token. + if (!StrongNameTokenFromPublicKey((BYTE*)pbPublicKey2, + cbPublicKey2, + (BYTE**)&pbToken, + &cbToken)) + return StrongNameErrorInfo(); + + fMatch = cbPublicKeyOrToken1 == cbToken && + !memcmp(pbPublicKeyOrToken1, pbToken, cbPublicKeyOrToken1); + + StrongNameFreeBuffer((BYTE*)pbToken); + + if (!fMatch) + return S_FALSE; + } + + return S_OK; +#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER +} // ImportHelper::CompareAssemblyRefToAssembly + +#endif //FEATURE_METADATA_EMIT |