// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Threading;
using dnlib.DotNet.MD;
using dnlib.DotNet.Pdb;
namespace dnlib.DotNet {
///
/// A high-level representation of a row in the AssemblyRef table
///
public abstract class AssemblyRef : IHasCustomAttribute, IImplementation, IResolutionScope, IHasCustomDebugInformation, IAssembly, IScope {
///
/// An assembly ref that can be used to indicate that it references the current assembly
/// when the current assembly is not known (eg. a type string without any assembly info
/// when it references a type in the current assembly).
///
public static readonly AssemblyRef CurrentAssembly = new AssemblyRefUser("<<>>");
///
/// The row id in its table
///
protected uint rid;
///
public MDToken MDToken => new MDToken(Table.AssemblyRef, rid);
///
public uint Rid {
get => rid;
set => rid = value;
}
///
public int HasCustomAttributeTag => 15;
///
public int ImplementationTag => 1;
///
public int ResolutionScopeTag => 2;
///
public ScopeType ScopeType => ScopeType.AssemblyRef;
///
public string ScopeName => FullName;
///
/// From columns AssemblyRef.MajorVersion, AssemblyRef.MinorVersion,
/// AssemblyRef.BuildNumber, AssemblyRef.RevisionNumber
///
/// If is null
public Version Version {
get => version;
set => version = value ?? throw new ArgumentNullException(nameof(value));
}
///
protected Version version;
///
/// From column AssemblyRef.Flags
///
public AssemblyAttributes Attributes {
get => (AssemblyAttributes)attributes;
set => attributes = (int)value;
}
/// Attributes
protected int attributes;
///
/// From column AssemblyRef.PublicKeyOrToken
///
/// If is null
public PublicKeyBase PublicKeyOrToken {
get => publicKeyOrToken;
set => publicKeyOrToken = value ?? throw new ArgumentNullException(nameof(value));
}
///
protected PublicKeyBase publicKeyOrToken;
///
/// From column AssemblyRef.Name
///
public UTF8String Name {
get => name;
set => name = value;
}
/// Name
protected UTF8String name;
///
/// From column AssemblyRef.Locale
///
public UTF8String Culture {
get => culture;
set => culture = value;
}
/// Culture
protected UTF8String culture;
///
/// From column AssemblyRef.HashValue
///
public byte[] Hash {
get => hashValue;
set => hashValue = value;
}
///
protected byte[] hashValue;
///
/// Gets all custom attributes
///
public CustomAttributeCollection CustomAttributes {
get {
if (customAttributes is null)
InitializeCustomAttributes();
return customAttributes;
}
}
///
protected CustomAttributeCollection customAttributes;
/// Initializes
protected virtual void InitializeCustomAttributes() =>
Interlocked.CompareExchange(ref customAttributes, new CustomAttributeCollection(), null);
///
public bool HasCustomAttributes => CustomAttributes.Count > 0;
///
public int HasCustomDebugInformationTag => 15;
///
public bool HasCustomDebugInfos => CustomDebugInfos.Count > 0;
///
/// Gets all custom debug infos
///
public IList CustomDebugInfos {
get {
if (customDebugInfos is null)
InitializeCustomDebugInfos();
return customDebugInfos;
}
}
///
protected IList customDebugInfos;
/// Initializes
protected virtual void InitializeCustomDebugInfos() =>
Interlocked.CompareExchange(ref customDebugInfos, new List(), null);
///
public string FullName => FullNameToken;
///
/// Same as , except that it uses the PublicKey if available.
///
public string RealFullName => FullNameFactory.AssemblyFullName(this, false);
///
/// Gets the full name of the assembly but use a public key token
///
public string FullNameToken => FullNameFactory.AssemblyFullName(this, true);
///
/// Modify property: =
/// ( & ) | .
///
/// Value to AND
/// Value to OR
void ModifyAttributes(AssemblyAttributes andMask, AssemblyAttributes orMask) =>
attributes = (attributes & (int)andMask) | (int)orMask;
///
/// Set or clear flags in
///
/// true if flags should be set, false if flags should
/// be cleared
/// Flags to set or clear
void ModifyAttributes(bool set, AssemblyAttributes flags) {
if (set)
attributes |= (int)flags;
else
attributes &= ~(int)flags;
}
///
/// Gets/sets the bit
///
public bool HasPublicKey {
get => ((AssemblyAttributes)attributes & AssemblyAttributes.PublicKey) != 0;
set => ModifyAttributes(value, AssemblyAttributes.PublicKey);
}
///
/// Gets/sets the processor architecture
///
public AssemblyAttributes ProcessorArchitecture {
get => (AssemblyAttributes)attributes & AssemblyAttributes.PA_Mask;
set => ModifyAttributes(~AssemblyAttributes.PA_Mask, value & AssemblyAttributes.PA_Mask);
}
///
/// Gets/sets the processor architecture
///
public AssemblyAttributes ProcessorArchitectureFull {
get => (AssemblyAttributes)attributes & AssemblyAttributes.PA_FullMask;
set => ModifyAttributes(~AssemblyAttributes.PA_FullMask, value & AssemblyAttributes.PA_FullMask);
}
///
/// true if unspecified processor architecture
///
public bool IsProcessorArchitectureNone => ((AssemblyAttributes)attributes & AssemblyAttributes.PA_Mask) == AssemblyAttributes.PA_None;
///
/// true if neutral (PE32) architecture
///
public bool IsProcessorArchitectureMSIL => ((AssemblyAttributes)attributes & AssemblyAttributes.PA_Mask) == AssemblyAttributes.PA_MSIL;
///
/// true if x86 (PE32) architecture
///
public bool IsProcessorArchitectureX86 => ((AssemblyAttributes)attributes & AssemblyAttributes.PA_Mask) == AssemblyAttributes.PA_x86;
///
/// true if IA-64 (PE32+) architecture
///
public bool IsProcessorArchitectureIA64 => ((AssemblyAttributes)attributes & AssemblyAttributes.PA_Mask) == AssemblyAttributes.PA_IA64;
///
/// true if x64 (PE32+) architecture
///
public bool IsProcessorArchitectureX64 => ((AssemblyAttributes)attributes & AssemblyAttributes.PA_Mask) == AssemblyAttributes.PA_AMD64;
///
/// true if ARM (PE32) architecture
///
public bool IsProcessorArchitectureARM => ((AssemblyAttributes)attributes & AssemblyAttributes.PA_Mask) == AssemblyAttributes.PA_ARM;
///
/// true if eg. reference assembly (not runnable)
///
public bool IsProcessorArchitectureNoPlatform => ((AssemblyAttributes)attributes & AssemblyAttributes.PA_Mask) == AssemblyAttributes.PA_NoPlatform;
///
/// Gets/sets the bit
///
public bool IsProcessorArchitectureSpecified {
get => ((AssemblyAttributes)attributes & AssemblyAttributes.PA_Specified) != 0;
set => ModifyAttributes(value, AssemblyAttributes.PA_Specified);
}
///
/// Gets/sets the bit
///
public bool EnableJITcompileTracking {
get => ((AssemblyAttributes)attributes & AssemblyAttributes.EnableJITcompileTracking) != 0;
set => ModifyAttributes(value, AssemblyAttributes.EnableJITcompileTracking);
}
///
/// Gets/sets the bit
///
public bool DisableJITcompileOptimizer {
get => ((AssemblyAttributes)attributes & AssemblyAttributes.DisableJITcompileOptimizer) != 0;
set => ModifyAttributes(value, AssemblyAttributes.DisableJITcompileOptimizer);
}
///
/// Gets/sets the bit
///
public bool IsRetargetable {
get => ((AssemblyAttributes)attributes & AssemblyAttributes.Retargetable) != 0;
set => ModifyAttributes(value, AssemblyAttributes.Retargetable);
}
///
/// Gets/sets the content type
///
public AssemblyAttributes ContentType {
get => (AssemblyAttributes)attributes & AssemblyAttributes.ContentType_Mask;
set => ModifyAttributes(~AssemblyAttributes.ContentType_Mask, value & AssemblyAttributes.ContentType_Mask);
}
///
/// true if content type is Default
///
public bool IsContentTypeDefault => ((AssemblyAttributes)attributes & AssemblyAttributes.ContentType_Mask) == AssemblyAttributes.ContentType_Default;
///
/// true if content type is WindowsRuntime
///
public bool IsContentTypeWindowsRuntime => ((AssemblyAttributes)attributes & AssemblyAttributes.ContentType_Mask) == AssemblyAttributes.ContentType_WindowsRuntime;
///
public override string ToString() => FullName;
}
///
/// An AssemblyRef row created by the user and not present in the original .NET file
///
public class AssemblyRefUser : AssemblyRef {
///
/// Creates a reference to CLR 1.0's mscorlib
///
public static AssemblyRefUser CreateMscorlibReferenceCLR10() => new AssemblyRefUser("mscorlib", new Version(1, 0, 3300, 0), new PublicKeyToken("b77a5c561934e089"));
///
/// Creates a reference to CLR 1.1's mscorlib
///
public static AssemblyRefUser CreateMscorlibReferenceCLR11() => new AssemblyRefUser("mscorlib", new Version(1, 0, 5000, 0), new PublicKeyToken("b77a5c561934e089"));
///
/// Creates a reference to CLR 2.0's mscorlib
///
public static AssemblyRefUser CreateMscorlibReferenceCLR20() => new AssemblyRefUser("mscorlib", new Version(2, 0, 0, 0), new PublicKeyToken("b77a5c561934e089"));
///
/// Creates a reference to CLR 4.0's mscorlib
///
public static AssemblyRefUser CreateMscorlibReferenceCLR40() => new AssemblyRefUser("mscorlib", new Version(4, 0, 0, 0), new PublicKeyToken("b77a5c561934e089"));
///
/// Default constructor
///
public AssemblyRefUser()
: this(UTF8String.Empty) {
}
///
/// Constructor
///
/// Simple name
/// If any of the args is invalid
public AssemblyRefUser(UTF8String name)
: this(name, new Version(0, 0, 0, 0)) {
}
///
/// Constructor
///
/// Simple name
/// Version
/// If any of the args is invalid
public AssemblyRefUser(UTF8String name, Version version)
: this(name, version, new PublicKey()) {
}
///
/// Constructor
///
/// Simple name
/// Version
/// Public key or public key token
/// If any of the args is invalid
public AssemblyRefUser(UTF8String name, Version version, PublicKeyBase publicKey)
: this(name, version, publicKey, UTF8String.Empty) {
}
///
/// Constructor
///
/// Simple name
/// Version
/// Public key or public key token
/// Locale
/// If any of the args is invalid
public AssemblyRefUser(UTF8String name, Version version, PublicKeyBase publicKey, UTF8String locale) {
if (name is null)
throw new ArgumentNullException(nameof(name));
if (locale is null)
throw new ArgumentNullException(nameof(locale));
this.name = name;
this.version = version ?? throw new ArgumentNullException(nameof(version));
publicKeyOrToken = publicKey;
culture = locale;
attributes = (int)(publicKey is PublicKey ? AssemblyAttributes.PublicKey : AssemblyAttributes.None);
}
///
/// Constructor
///
/// Assembly name info
/// If is null
public AssemblyRefUser(AssemblyName asmName)
: this(new AssemblyNameInfo(asmName)) => attributes = (int)asmName.Flags;
///
/// Constructor
///
/// Assembly
public AssemblyRefUser(IAssembly assembly) {
if (assembly is null)
throw new ArgumentNullException("asmName");
version = assembly.Version ?? new Version(0, 0, 0, 0);
publicKeyOrToken = assembly.PublicKeyOrToken;
name = UTF8String.IsNullOrEmpty(assembly.Name) ? UTF8String.Empty : assembly.Name;
culture = assembly.Culture;
attributes = (int)((publicKeyOrToken is PublicKey ? AssemblyAttributes.PublicKey : AssemblyAttributes.None) | assembly.ContentType);
}
}
///
/// Created from a row in the AssemblyRef table
///
sealed class AssemblyRefMD : AssemblyRef, IMDTokenProviderMD {
/// The module where this instance is located
readonly ModuleDefMD readerModule;
readonly uint origRid;
///
public uint OrigRid => origRid;
///
protected override void InitializeCustomAttributes() {
var list = readerModule.Metadata.GetCustomAttributeRidList(Table.AssemblyRef, origRid);
var tmp = new CustomAttributeCollection(list.Count, list, (list2, index) => readerModule.ReadCustomAttribute(list[index]));
Interlocked.CompareExchange(ref customAttributes, tmp, null);
}
///
protected override void InitializeCustomDebugInfos() {
var list = new List();
readerModule.InitializeCustomDebugInfos(new MDToken(MDToken.Table, origRid), new GenericParamContext(), list);
Interlocked.CompareExchange(ref customDebugInfos, list, null);
}
///
/// Constructor
///
/// The module which contains this AssemblyRef row
/// Row ID
/// If is null
/// If is invalid
public AssemblyRefMD(ModuleDefMD readerModule, uint rid) {
#if DEBUG
if (readerModule is null)
throw new ArgumentNullException("readerModule");
if (readerModule.TablesStream.AssemblyRefTable.IsInvalidRID(rid))
throw new BadImageFormatException($"AssemblyRef rid {rid} does not exist");
#endif
origRid = rid;
this.rid = rid;
this.readerModule = readerModule;
bool b = readerModule.TablesStream.TryReadAssemblyRefRow(origRid, out var row);
Debug.Assert(b);
version = new Version(row.MajorVersion, row.MinorVersion, row.BuildNumber, row.RevisionNumber);
attributes = (int)row.Flags;
var pkData = readerModule.BlobStream.Read(row.PublicKeyOrToken);
if ((attributes & (uint)AssemblyAttributes.PublicKey) != 0)
publicKeyOrToken = new PublicKey(pkData);
else
publicKeyOrToken = new PublicKeyToken(pkData);
name = readerModule.StringsStream.ReadNoNull(row.Name);
culture = readerModule.StringsStream.ReadNoNull(row.Locale);
hashValue = readerModule.BlobStream.Read(row.HashValue);
}
}
}