// dnlib: See LICENSE.txt for more info using System; using System.Collections.Generic; using System.Diagnostics; using System.Threading; using dnlib.DotNet.MD; using dnlib.DotNet.Pdb; namespace dnlib.DotNet { /// /// A high-level representation of a row in the ManifestResource table /// [DebuggerDisplay("{Offset} {Name.String} {Implementation}")] public abstract class ManifestResource : IHasCustomAttribute, IHasCustomDebugInformation { /// /// The row id in its table /// protected uint rid; /// public MDToken MDToken => new MDToken(Table.ManifestResource, rid); /// public uint Rid { get => rid; set => rid = value; } /// public int HasCustomAttributeTag => 18; /// /// From column ManifestResource.Offset /// public uint Offset { get => offset; set => offset = value; } /// protected uint offset; /// /// From column ManifestResource.Flags /// public ManifestResourceAttributes Flags { get => (ManifestResourceAttributes)attributes; set => attributes = (int)value; } /// Attributes protected int attributes; /// /// From column ManifestResource.Name /// public UTF8String Name { get => name; set => name = value; } /// Name protected UTF8String name; /// /// From column ManifestResource.Implementation /// public IImplementation Implementation { get => implementation; set => implementation = value; } /// protected IImplementation implementation; /// /// 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 => 18; /// 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); /// /// Modify property: = /// ( & ) | . /// /// Value to AND /// Value to OR void ModifyAttributes(ManifestResourceAttributes andMask, ManifestResourceAttributes orMask) => attributes = (attributes & (int)andMask) | (int)orMask; /// /// Gets/sets the visibility /// public ManifestResourceAttributes Visibility { get => (ManifestResourceAttributes)attributes & ManifestResourceAttributes.VisibilityMask; set => ModifyAttributes(~ManifestResourceAttributes.VisibilityMask, value & ManifestResourceAttributes.VisibilityMask); } /// /// true if is set /// public bool IsPublic => ((ManifestResourceAttributes)attributes & ManifestResourceAttributes.VisibilityMask) == ManifestResourceAttributes.Public; /// /// true if is set /// public bool IsPrivate => ((ManifestResourceAttributes)attributes & ManifestResourceAttributes.VisibilityMask) == ManifestResourceAttributes.Private; } /// /// A ManifestResource row created by the user and not present in the original .NET file /// public class ManifestResourceUser : ManifestResource { /// /// Default constructor /// public ManifestResourceUser() { } /// /// Constructor /// /// Name /// Implementation public ManifestResourceUser(UTF8String name, IImplementation implementation) : this(name, implementation, 0) { } /// /// Constructor /// /// Name /// Implementation /// Flags public ManifestResourceUser(UTF8String name, IImplementation implementation, ManifestResourceAttributes flags) : this(name, implementation, flags, 0) { } /// /// Constructor /// /// Name /// Implementation /// Flags /// Offset public ManifestResourceUser(UTF8String name, IImplementation implementation, ManifestResourceAttributes flags, uint offset) { this.name = name; this.implementation = implementation; attributes = (int)flags; this.offset = offset; } } /// /// Created from a row in the ManifestResource table /// sealed class ManifestResourceMD : ManifestResource, 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.ManifestResource, 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 ManifestResource row /// Row ID /// If is null /// If is invalid public ManifestResourceMD(ModuleDefMD readerModule, uint rid) { #if DEBUG if (readerModule is null) throw new ArgumentNullException("readerModule"); if (readerModule.TablesStream.ManifestResourceTable.IsInvalidRID(rid)) throw new BadImageFormatException($"ManifestResource rid {rid} does not exist"); #endif origRid = rid; this.rid = rid; this.readerModule = readerModule; bool b = readerModule.TablesStream.TryReadManifestResourceRow(origRid, out var row); Debug.Assert(b); offset = row.Offset; attributes = (int)row.Flags; name = readerModule.StringsStream.ReadNoNull(row.Name); implementation = readerModule.ResolveImplementation(row.Implementation); } } }