1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 // ============================================================
11 // Implements the AssemblyName class
13 // ============================================================
15 #define DISABLE_BINDER_DEBUG_LOGGING
17 #include "assemblyname.hpp"
18 #include "assembly.hpp"
20 #include "variables.hpp"
22 #include "fusionassemblyname.hpp"
24 #include "textualidentityparser.hpp"
30 namespace BINDER_SPACE
32 AssemblyName::AssemblyName()
35 m_dwNameFlags = NAME_FLAG_NONE;
36 // Default values present in every assembly name
37 SetHave(AssemblyIdentity::IDENTITY_FLAG_CULTURE |
38 AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL);
41 AssemblyName::~AssemblyName()
46 HRESULT AssemblyName::Init(IMDInternalImport *pIMetaDataAssemblyImport,
48 mdAssemblyRef mdar /* = 0 */,
49 BOOL fIsDefinition /* = TRUE */)
53 AssemblyMetaDataInternal amd = {0};
54 CONST VOID *pvPublicKeyToken = NULL;
55 DWORD dwPublicKeyToken = 0;
56 LPCSTR pAssemblyName = NULL;
57 DWORD dwRefOrDefFlags = 0;
58 DWORD dwHashAlgId = 0;
60 BINDER_LOG_ENTER(L"AssemblyName::Init(IMetaDataAssemblyImport)");
64 // Get the assembly token
65 IF_FAIL_GO(pIMetaDataAssemblyImport->GetAssemblyFromScope(&mda));
68 BINDER_LOG(L"Have mda scope!");
70 // Get name and metadata
73 IF_FAIL_GO(pIMetaDataAssemblyImport->GetAssemblyProps(
74 mda, // [IN] The Assembly for which to get the properties.
75 &pvPublicKeyToken, // [OUT] Pointer to the PublicKeyToken blob.
76 &dwPublicKeyToken, // [OUT] Count of bytes in the PublicKeyToken Blob.
77 &dwHashAlgId, // [OUT] Hash Algorithm.
78 &pAssemblyName, // [OUT] Name.
79 &amd, // [OUT] Assembly MetaData.
80 &dwRefOrDefFlags // [OUT] Flags.
85 IF_FAIL_GO(pIMetaDataAssemblyImport->GetAssemblyRefProps(
86 mdar, // [IN] The Assembly for which to get the properties.
87 &pvPublicKeyToken, // [OUT] Pointer to the PublicKeyToken blob.
88 &dwPublicKeyToken, // [OUT] Count of bytes in the PublicKeyToken Blob.
89 &pAssemblyName, // [OUT] Name.
90 &amd, // [OUT] Assembly MetaData.
91 NULL, // [OUT] Hash blob.
92 NULL, // [OUT] Count of bytes in hash blob.
93 &dwRefOrDefFlags // [OUT] Flags.
97 BINDER_LOG(L"Have props!");
100 StackSString culture;
101 culture.SetUTF8(amd.szLocale);
104 SString::CIterator itr = culture.Begin();
105 if (culture.Find(itr, L';'))
107 culture = SString(culture, culture.Begin(), itr-1);
114 StackSString assemblyName;
115 assemblyName.SetUTF8(pAssemblyName);
116 assemblyName.Normalize();
118 COUNT_T assemblyNameLength = assemblyName.GetCount();
119 if (assemblyNameLength == 0 || assemblyNameLength >= MAX_PATH_FNAME)
121 IF_FAIL_GO(FUSION_E_INVALID_NAME);
124 SetSimpleName(assemblyName);
127 // See if the assembly[def] is retargetable (ie, for a generic assembly).
128 if (IsAfRetargetable(dwRefOrDefFlags))
130 SetIsRetargetable(TRUE);
134 if (IsAfContentType_Default(dwRefOrDefFlags))
136 SetContentType(AssemblyContentType_Default);
138 else if (IsAfContentType_WindowsRuntime(dwRefOrDefFlags))
140 SetContentType(AssemblyContentType_WindowsRuntime);
144 IF_FAIL_GO(FUSION_E_INVALID_NAME);
147 // Set the assembly version
149 AssemblyVersion *pAssemblyVersion = GetVersion();
151 pAssemblyVersion->SetFeatureVersion(amd.usMajorVersion, amd.usMinorVersion);
152 pAssemblyVersion->SetServiceVersion(amd.usBuildNumber, amd.usRevisionNumber);
153 SetHave(AssemblyIdentity::IDENTITY_FLAG_VERSION);
156 // Set public key and/or public key token (if we have it)
157 if (pvPublicKeyToken && dwPublicKeyToken)
159 SBuffer publicKeyOrTokenBLOB((const BYTE *) pvPublicKeyToken, dwPublicKeyToken);
161 if (IsAfPublicKey(dwRefOrDefFlags))
163 SBuffer publicKeyTokenBLOB;
165 IF_FAIL_GO(GetTokenFromPublicKey(publicKeyOrTokenBLOB, publicKeyTokenBLOB));
166 GetPublicKeyTokenBLOB().Set(publicKeyTokenBLOB);
170 GetPublicKeyTokenBLOB().Set(publicKeyOrTokenBLOB);
173 SetHave(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN);
176 SetArchitecture(PeKind);
179 BINDER_LOG_LEAVE_HR(L"AssemblyName::Init(IMetaDataAssemblyImport)", hr);
183 HRESULT AssemblyName::Init(SString &assemblyDisplayName)
186 BINDER_LOG_ENTER(L"AssemblyName::Init(assemblyDisplayName)");
188 BINDER_LOG_STRING(L"assemblyDisplayName", assemblyDisplayName);
190 IF_FAIL_GO(TextualIdentityParser::Parse(assemblyDisplayName, this));
193 BINDER_LOG_LEAVE_HR(L"AssemblyName::Init(assemblyDisplayName)", hr);
197 HRESULT AssemblyName::Init(IAssemblyName *pIAssemblyName)
201 _ASSERTE(pIAssemblyName != NULL);
206 // Set the simpleName
207 StackSString simpleName;
208 hr = fusion::util::GetSimpleName(pIAssemblyName, simpleName);
210 SetSimpleName(simpleName);
211 SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_SIMPLE_NAME);
215 DWORD dwVersionParts[4] = {0,0,0,0};
216 DWORD cbVersionSize = sizeof(dwVersionParts[0]);
217 hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_MAJOR_VERSION, static_cast<PVOID>(&dwVersionParts[0]), &cbVersionSize);
219 if ((hr == S_OK) && (cbVersionSize != 0))
221 // Property is present - loop to get the individual version details
222 for(DWORD i = 0; i < 4; i++)
224 cbVersionSize = sizeof(dwVersionParts[i]);
225 hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_MAJOR_VERSION+i, static_cast<PVOID>(&dwVersionParts[i]), &cbVersionSize);
229 m_version.SetFeatureVersion(dwVersionParts[0], dwVersionParts[1]);
230 m_version.SetServiceVersion(dwVersionParts[2], dwVersionParts[3]);
231 SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_VERSION);
236 StackSString culture;
237 hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_CULTURE, culture);
242 SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CULTURE);
247 // Display public key token
248 NewArrayHolder<BYTE> pPublicKeyToken;
249 DWORD cbPublicKeyToken = 0;
250 hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_PUBLIC_KEY_TOKEN, static_cast<PBYTE*>(&pPublicKeyToken), &cbPublicKeyToken);
252 if ((hr == S_OK) && (cbPublicKeyToken != 0))
254 m_publicKeyOrTokenBLOB.Set(pPublicKeyToken, cbPublicKeyToken);
255 SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN);
259 SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL);
263 // Display processor architecture
265 DWORD cbPeKind = sizeof(peKind);
266 hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_ARCHITECTURE, static_cast<PVOID>(&peKind), &cbPeKind);
268 if ((hr == S_OK) && (cbPeKind != 0))
270 PEKIND PeKind = (PEKIND)peKind;
271 if (PeKind != peNone)
273 SetArchitecture(PeKind);
274 SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE);
278 // Display retarget flag
279 BOOL fRetarget = FALSE;
280 DWORD cbRetarget = sizeof(fRetarget);
281 hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_RETARGET, static_cast<PVOID>(&fRetarget), &cbRetarget);
283 if ((hr == S_OK) && (cbRetarget != 0))
287 SetIsRetargetable(fRetarget);
288 SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE);
292 // Display content type
293 DWORD dwContentType = AssemblyContentType_Default;
294 DWORD cbContentType = sizeof(dwContentType);
295 hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_CONTENT_TYPE, static_cast<PVOID>(&dwContentType), &cbContentType);
297 if ((hr == S_OK) && (cbContentType != 0))
299 if (dwContentType != AssemblyContentType_Default)
301 SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE);
302 SetContentType((AssemblyContentType)dwContentType);
307 // Display custom flag. Dont set it if it is not present since that will end up adding the "Custom=null" attribute
308 // in the displayname of the assembly that maybe generated using this AssemblyName instance. This could create conflict when
309 // the displayname is generated from the assembly directly as that will not have a "Custom" field set.
310 NewArrayHolder<BYTE> pCustomBLOB;
311 DWORD cbCustomBLOB = 0;
312 hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_CUSTOM, static_cast<PBYTE*>(&pCustomBLOB), &cbCustomBLOB);
314 if ((hr == S_OK) && (cbCustomBLOB != 0))
316 m_customBLOB.Set(pCustomBLOB, cbCustomBLOB);
317 SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CUSTOM);
321 EX_CATCH_HRESULT(hr);
326 HRESULT AssemblyName::CreateFusionName(IAssemblyName **ppIAssemblyName)
329 ReleaseHolder<IAssemblyName> pIAssemblyName;
331 IF_FAIL_GO(CreateAssemblyNameObject(&pIAssemblyName, NULL, 0, NULL));
333 IF_FAIL_GO(LegacyFusion::SetStringProperty(pIAssemblyName, ASM_NAME_NAME, GetSimpleName()));
335 if (Have(AssemblyIdentity::IDENTITY_FLAG_VERSION))
337 AssemblyVersion *pAssemblyVersion = GetVersion();
339 IF_FAIL_GO(LegacyFusion::SetWordProperty(pIAssemblyName,
340 ASM_NAME_MAJOR_VERSION,
341 pAssemblyVersion->GetMajor()));
342 IF_FAIL_GO(LegacyFusion::SetWordProperty(pIAssemblyName,
343 ASM_NAME_MINOR_VERSION,
344 pAssemblyVersion->GetMinor()));
345 IF_FAIL_GO(LegacyFusion::SetWordProperty(pIAssemblyName,
346 ASM_NAME_BUILD_NUMBER,
347 pAssemblyVersion->GetBuild()));
348 IF_FAIL_GO(LegacyFusion::SetWordProperty(pIAssemblyName,
349 ASM_NAME_REVISION_NUMBER,
350 pAssemblyVersion->GetRevision()));
353 if (Have(AssemblyIdentity::IDENTITY_FLAG_CULTURE))
355 IF_FAIL_GO(LegacyFusion::SetStringProperty(pIAssemblyName, ASM_NAME_CULTURE, GetCulture()));
358 if (Have(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY))
360 // GetPublicKeyTokenBLOB contains either PK or PKT.
361 IF_FAIL_GO(LegacyFusion::SetBufferProperty(pIAssemblyName,
363 GetPublicKeyTokenBLOB()));
365 else if (Have(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN))
367 // GetPublicKeyTokenBLOB contains either PK or PKT.
368 IF_FAIL_GO(LegacyFusion::SetBufferProperty(pIAssemblyName,
369 ASM_NAME_PUBLIC_KEY_TOKEN,
370 GetPublicKeyTokenBLOB()));
373 if (Have(AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE))
375 IF_FAIL_GO(LegacyFusion::SetDwordProperty(pIAssemblyName,
376 ASM_NAME_ARCHITECTURE,
377 static_cast<DWORD>(GetArchitecture())));
380 if (Have(AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE))
382 IF_FAIL_GO(LegacyFusion::SetDwordProperty(pIAssemblyName,
383 ASM_NAME_CONTENT_TYPE,
387 *ppIAssemblyName = pIAssemblyName.Extract();
393 ULONG AssemblyName::AddRef()
395 return InterlockedIncrement(&m_cRef);
398 ULONG AssemblyName::Release()
400 ULONG ulRef = InterlockedDecrement(&m_cRef);
408 SString &AssemblyName::GetDeNormalizedCulture()
410 SString &culture = GetCulture();
412 if (EqualsCaseInsensitive(culture, g_BinderVariables->cultureNeutral))
414 culture = g_BinderVariables->emptyString;
420 BOOL AssemblyName::IsStronglyNamed()
422 return Have(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN);
425 BOOL AssemblyName::IsMscorlib()
427 // TODO: Is this simple comparison enough?
428 return EqualsCaseInsensitive(GetSimpleName(), g_BinderVariables->mscorlib);
431 HRESULT AssemblyName::SetArchitecture(SString &architecture)
435 if (architecture.IsEmpty())
437 SetArchitecture(peNone);
439 else if (EqualsCaseInsensitive(architecture, g_BinderVariables->architectureMSIL))
441 SetArchitecture(peMSIL);
443 else if (EqualsCaseInsensitive(architecture, g_BinderVariables->architectureX86))
445 SetArchitecture(peI386);
447 else if (EqualsCaseInsensitive(architecture, g_BinderVariables->architectureAMD64))
449 SetArchitecture(peAMD64);
451 else if (EqualsCaseInsensitive(architecture, g_BinderVariables->architectureARM))
453 SetArchitecture(peARM);
455 else if (EqualsCaseInsensitive(architecture, g_BinderVariables->architectureARM64))
457 SetArchitecture(peARM64);
461 hr = FUSION_E_MANIFEST_PARSE_ERROR;
467 ULONG AssemblyName::Hash(DWORD dwIncludeFlags)
470 DWORD dwUseIdentityFlags = m_dwIdentityFlags;
472 // Prune unwanted name parts
473 if ((dwIncludeFlags & INCLUDE_VERSION) == 0)
475 dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_VERSION;
477 if ((dwIncludeFlags & INCLUDE_ARCHITECTURE) == 0)
479 dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE;
481 if ((dwIncludeFlags & INCLUDE_RETARGETABLE) == 0)
483 dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE;
485 if ((dwIncludeFlags & INCLUDE_CONTENT_TYPE) == 0)
487 dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE;
490 dwHash ^= static_cast<DWORD>(HashCaseInsensitive(GetSimpleName()));
491 dwHash = _rotl(dwHash, 4);
493 if (AssemblyIdentity::Have(dwUseIdentityFlags,
494 AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY) ||
495 AssemblyIdentity::Have(dwUseIdentityFlags,
496 AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN))
498 const BYTE *pbPublicKeyOrToken = GetPublicKeyTokenBLOB();
499 DWORD dwcbPublicKeyOrToken = GetPublicKeyTokenBLOB().GetSize();
501 _ASSERTE(pbPublicKeyOrToken != NULL);
503 dwHash ^= HashBytes(pbPublicKeyOrToken, dwcbPublicKeyOrToken);
504 dwHash = _rotl(dwHash, 4);
507 if (AssemblyIdentity::Have(dwUseIdentityFlags, AssemblyIdentity::IDENTITY_FLAG_VERSION))
509 AssemblyVersion *pAssemblyVersion = GetVersion();
511 dwHash ^= pAssemblyVersion->GetMajor();
512 dwHash = _rotl(dwHash, 8);
513 dwHash ^= pAssemblyVersion->GetMinor();
514 dwHash = _rotl(dwHash, 8);
515 dwHash ^= pAssemblyVersion->GetBuild();
516 dwHash = _rotl(dwHash, 8);
517 dwHash ^= pAssemblyVersion->GetRevision();
518 dwHash = _rotl(dwHash, 8);
521 if (AssemblyIdentity::Have(dwUseIdentityFlags, AssemblyIdentity::IDENTITY_FLAG_CULTURE))
523 dwHash ^= static_cast<DWORD>(HashCaseInsensitive(GetNormalizedCulture()));
524 dwHash = _rotl(dwHash, 4);
527 if (AssemblyIdentity::Have(dwUseIdentityFlags,
528 AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE))
531 dwHash = _rotl(dwHash, 4);
534 if (AssemblyIdentity::Have(dwUseIdentityFlags,
535 AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE))
537 dwHash ^= static_cast<DWORD>(GetArchitecture());
538 dwHash = _rotl(dwHash, 4);
541 if (AssemblyIdentity::Have(dwUseIdentityFlags,
542 AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE))
544 dwHash ^= static_cast<DWORD>(GetContentType());
545 dwHash = _rotl(dwHash, 4);
548 return static_cast<ULONG>(dwHash);
551 BOOL AssemblyName::Equals(AssemblyName *pAssemblyName,
552 DWORD dwIncludeFlags)
554 BOOL fEquals = FALSE;
556 if (GetContentType() == AssemblyContentType_WindowsRuntime)
557 { // Assembly is meaningless for WinRT, all assemblies form one joint type namespace
558 return (GetContentType() == pAssemblyName->GetContentType());
561 if (EqualsCaseInsensitive(GetSimpleName(), pAssemblyName->GetSimpleName()) &&
562 (GetContentType() == pAssemblyName->GetContentType()))
566 if ((dwIncludeFlags & EXCLUDE_CULTURE) == 0)
568 fEquals = EqualsCaseInsensitive(GetNormalizedCulture(), pAssemblyName->GetNormalizedCulture());
571 if (fEquals && (dwIncludeFlags & INCLUDE_PUBLIC_KEY_TOKEN) != 0)
573 fEquals = (GetPublicKeyTokenBLOB().Equals(pAssemblyName->GetPublicKeyTokenBLOB()));
576 if (fEquals && ((dwIncludeFlags & INCLUDE_ARCHITECTURE) != 0))
578 fEquals = (GetArchitecture() == pAssemblyName->GetArchitecture());
581 if (fEquals && ((dwIncludeFlags & INCLUDE_VERSION) != 0))
583 fEquals = GetVersion()->Equals(pAssemblyName->GetVersion());
586 if (fEquals && ((dwIncludeFlags & INCLUDE_RETARGETABLE) != 0))
588 fEquals = (GetIsRetargetable() == pAssemblyName->GetIsRetargetable());
595 BOOL AssemblyName::RefEqualsDef(AssemblyName *pAssemblyNameDef,
596 BOOL fInspectionOnly)
598 BOOL fEquals = FALSE;
600 if (GetContentType() == AssemblyContentType_WindowsRuntime)
601 { // Assembly is meaningless for WinRT, all assemblies form one joint type namespace
602 return (GetContentType() == pAssemblyNameDef->GetContentType());
605 if (EqualsCaseInsensitive(GetSimpleName(), pAssemblyNameDef->GetSimpleName()) &&
606 EqualsCaseInsensitive(GetNormalizedCulture(),
607 pAssemblyNameDef->GetNormalizedCulture()) &&
608 GetPublicKeyTokenBLOB().Equals(pAssemblyNameDef->GetPublicKeyTokenBLOB()) &&
609 (GetContentType() == pAssemblyNameDef->GetContentType()))
611 PEKIND kRefArchitecture = GetArchitecture();
612 PEKIND kDefArchitecture = pAssemblyNameDef->GetArchitecture();
614 if (kRefArchitecture == peNone)
616 fEquals = (fInspectionOnly ||
617 (kDefArchitecture == peNone) ||
618 (kDefArchitecture == peMSIL) ||
619 (kDefArchitecture == Assembly::GetSystemArchitecture()));
623 fEquals = (kRefArchitecture == kDefArchitecture);
630 HRESULT AssemblyName::Clone(AssemblyName **ppAssemblyName)
633 AssemblyName *pClonedAssemblyName = NULL;
635 SAFE_NEW(pClonedAssemblyName, AssemblyName);
636 CloneInto(pClonedAssemblyName);
637 pClonedAssemblyName->m_dwNameFlags = m_dwNameFlags;
639 *ppAssemblyName = pClonedAssemblyName;
645 void AssemblyName::GetDisplayName(PathString &displayName,
646 DWORD dwIncludeFlags)
648 DWORD dwUseIdentityFlags = m_dwIdentityFlags;
650 // Prune unwanted name parts
651 if ((dwIncludeFlags & INCLUDE_VERSION) == 0)
653 dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_VERSION;
655 if ((dwIncludeFlags & INCLUDE_ARCHITECTURE) == 0)
657 dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE;
659 if ((dwIncludeFlags & INCLUDE_RETARGETABLE) == 0)
661 dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE;
663 if ((dwIncludeFlags & INCLUDE_CONTENT_TYPE) == 0)
665 dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE;
668 TextualIdentityParser::ToString(this, dwUseIdentityFlags, displayName);
671 SString &AssemblyName::ArchitectureToString(PEKIND kArchitecture)
673 switch (kArchitecture)
676 return g_BinderVariables->emptyString;
678 return g_BinderVariables->architectureMSIL;
680 return g_BinderVariables->architectureX86;
682 return g_BinderVariables->architectureAMD64;
684 return g_BinderVariables->architectureARM;
686 return g_BinderVariables->architectureARM64;
689 return g_BinderVariables->emptyString;
693 SString &AssemblyName::GetNormalizedCulture()
695 SString &culture = GetCulture();
697 if (culture.IsEmpty())
699 culture = g_BinderVariables->cultureNeutral;
704 }; // namespace BINDER_SPACE