// 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); } } }