/*
Copyright (C) 2014-2019 de4dot@gmail.com
This file is part of dnSpy
dnSpy is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
dnSpy is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with dnSpy. If not, see .
*/
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace dnSpy.Debugger.DotNet.Metadata.Impl {
sealed class AssemblyNameEqualityComparer : IEqualityComparer {
readonly bool ignorePublicKeyToken;
public AssemblyNameEqualityComparer(bool ignorePublicKeyToken) =>
this.ignorePublicKeyToken = ignorePublicKeyToken;
static readonly byte[][] systemPublicKeyTokens;
static AssemblyNameEqualityComparer() {
systemPublicKeyTokens = new byte[][] {
new byte[8] { 0x1C, 0x9E, 0x25, 0x96, 0x86, 0xF9, 0x21, 0xE0 },
new byte[8] { 0x5F, 0xD5, 0x7C, 0x54, 0x3A, 0x9C, 0x02, 0x47 },
new byte[8] { 0x96, 0x9D, 0xB8, 0x05, 0x3D, 0x33, 0x22, 0xAC },
new byte[8] { 0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89 },
new byte[8] { 0x31, 0xBF, 0x38, 0x56, 0xAD, 0x36, 0x4E, 0x35 },
new byte[8] { 0xB0, 0x3F, 0x5F, 0x7F, 0x11, 0xD5, 0x0A, 0x3A },
new byte[8] { 0x7C, 0xEC, 0x85, 0xD7, 0xBE, 0xA7, 0x79, 0x8E },
new byte[8] { 0x07, 0x38, 0xEB, 0x9F, 0x13, 0x2E, 0xD7, 0x56 },
};
}
public bool Equals([AllowNull] IDmdAssemblyName x, [AllowNull] IDmdAssemblyName y) {
if ((object?)x == y)
return true;
if (x is null || y is null)
return false;
if (!StringComparer.OrdinalIgnoreCase.Equals(x.Name, y.Name))
return false;
// Version number is ignored since an assembly reference can be redirected to any other version at runtime
if (!StringComparer.OrdinalIgnoreCase.Equals(x.CultureName ?? string.Empty, y.CultureName ?? string.Empty))
return false;
if (x.ContentType != y.ContentType)
return false;
return ignorePublicKeyToken || PublicKeyTokenEquals(x.GetPublicKeyToken(), y.GetPublicKeyToken());
}
static bool PublicKeyTokenEquals(byte[]? a, byte[]? b) {
if (a is null)
a = Array.Empty();
if (b is null)
b = Array.Empty();
if (Equals(a, b))
return true;
return IsSystemPublicKeyToken(a) && IsSystemPublicKeyToken(b);
}
static bool IsSystemPublicKeyToken(byte[] a) {
if (a is null)
return false;
foreach (var sys in systemPublicKeyTokens) {
if (Equals(sys, a))
return true;
}
return false;
}
static bool Equals(byte[] a, byte[] b) {
if (a == b)
return true;
if (a is null || b is null)
return false;
if (a.Length != b.Length)
return false;
for (int i = 0; i < a.Length; i++) {
if (a[i] != b[i])
return false;
}
return true;
}
public int GetHashCode([DisallowNull] IDmdAssemblyName obj) {
int hc = StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Name ?? string.Empty);
// Version number is ignored, see Equals()
hc ^= (obj.CultureName ?? string.Empty).GetHashCode();
// PublicKeyToken is ignored
return hc;
}
}
}