// 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
//*******************************************************************************
// @GENERICS: todo: look in hashtable (cf. MetaModelRW.cpp) if necessary
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 cqaNesters; // Array of Nester tokens.
CQuickArray cqaNesterNamespaces; // Array of Nester Namespaces.
CQuickArray 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
// 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)
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
// syntax : MVAR
// 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 [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
// syntax for VALUE_CLASS = ELEMENT_TYPE_VALUECLASS
// 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 &cqaNesters, // Array of Nesters.
CQuickArray &cqaNamespaces, // Names of the nesters.
CQuickArray &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 &cqaTdNesters,// Array of Nesters.
CQuickArray &cqaNamespaces, // Namespaces of the nesters.
CQuickArray &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 &cqaTrNesters,// [OUT] Array of Nesters.
CQuickArray &cqaNamespaces, // [OUT] Namespaces of the nesters.
CQuickArray &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 &cqaNesterNamespaces, // [IN] Array of Nester namespaces.
CQuickArray &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 &cqaNesterNamespaces, // [IN] Array of Names.
CQuickArray &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 &cqaNesterNamespaces, // [IN] Array of Namespaces.
CQuickArray &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 cqaNesters;
CQuickArray cqaNesterNames;
CQuickArray 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(pMiniMdAssemEmit)->CommonGetScopeProps(0, &MvidAssemEmit));
}
IfFailGo(static_cast(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
{
// @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.
// 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.
// @FUTURE: Should we look at visibility flags on ExportedTypes and TypeDefs when
// handling references across Assemblies?
//****************************************************************************
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 cqaNesters;
CQuickArray cqaNesterNames;
CQuickArray 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(pMiniMdAssemEmit)->CommonGetScopeProps(
0,
&MvidAssemEmit));
}
IfFailGo(static_cast(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))
{
// 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!!
// 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(pMiniMdAssemEmit)));
}
else
{
// Check to see if the AssemblyRef resolves to the emit assembly.
IfFailGo(CompareAssemblyRefToAssembly(pCommonImport,
tkOuterImportRes,
static_cast(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);
// cannot assert now!! Due to the IJW workaround!
// _ASSERTE(SUCCEEDED(hr));
}
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(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(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