// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using System.Threading;
using dnlib.IO;
using dnlib.DotNet.MD;
using dnlib.DotNet.Pdb;
namespace dnlib.DotNet {
///
/// Type of resource
///
public enum ResourceType {
///
/// It's a
///
Embedded,
///
/// It's a
///
AssemblyLinked,
///
/// It's a
///
Linked,
}
///
/// Resource base class
///
public abstract class Resource : IMDTokenProvider, IHasCustomAttribute, IHasCustomDebugInformation {
private protected uint rid;
private protected uint? offset;
UTF8String name;
ManifestResourceAttributes flags;
///
public MDToken MDToken => new MDToken(Table.ManifestResource, rid);
///
public uint Rid {
get => rid;
set => rid = value;
}
///
/// Gets/sets the offset of the resource
///
public uint? Offset {
get => offset;
set => offset = value;
}
///
/// Gets/sets the name
///
public UTF8String Name {
get => name;
set => name = value;
}
///
/// Gets/sets the flags
///
public ManifestResourceAttributes Attributes {
get => flags;
set => flags = value;
}
///
/// Gets the type of resource
///
public abstract ResourceType ResourceType { get; }
///
/// Gets/sets the visibility
///
public ManifestResourceAttributes Visibility {
get => flags & ManifestResourceAttributes.VisibilityMask;
set => flags = (flags & ~ManifestResourceAttributes.VisibilityMask) | (value & ManifestResourceAttributes.VisibilityMask);
}
///
/// true if is set
///
public bool IsPublic => (flags & ManifestResourceAttributes.VisibilityMask) == ManifestResourceAttributes.Public;
///
/// true if is set
///
public bool IsPrivate => (flags & ManifestResourceAttributes.VisibilityMask) == ManifestResourceAttributes.Private;
///
public int HasCustomAttributeTag => 18;
///
/// 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;
///
/// 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 bool HasCustomDebugInfos => CustomDebugInfos.Count > 0;
///
/// Constructor
///
/// Name
/// flags
protected Resource(UTF8String name, ManifestResourceAttributes flags) {
this.name = name;
this.flags = flags;
}
}
///
/// A resource that is embedded in a .NET module. This is the most common type of resource.
///
public class EmbeddedResource : Resource {
readonly DataReaderFactory dataReaderFactory;
readonly uint resourceStartOffset;
readonly uint resourceLength;
///
/// Gets the length of the data
///
public uint Length => resourceLength;
///
public override ResourceType ResourceType => ResourceType.Embedded;
///
/// Constructor
///
/// Name of resource
/// Resource data
/// Resource flags
public EmbeddedResource(UTF8String name, byte[] data, ManifestResourceAttributes flags = ManifestResourceAttributes.Private)
: this(name, ByteArrayDataReaderFactory.Create(data, filename: null), 0, (uint)data.Length, flags) {
}
///
/// Constructor
///
/// Name of resource
/// Data reader factory
/// Offset of resource data
/// Length of resource data
/// Resource flags
public EmbeddedResource(UTF8String name, DataReaderFactory dataReaderFactory, uint offset, uint length, ManifestResourceAttributes flags = ManifestResourceAttributes.Private)
: base(name, flags) {
this.dataReaderFactory = dataReaderFactory ?? throw new ArgumentNullException(nameof(dataReaderFactory));
resourceStartOffset = offset;
resourceLength = length;
}
///
/// Gets a data reader that can access the resource
///
///
public DataReader CreateReader() => dataReaderFactory.CreateReader(resourceStartOffset, resourceLength);
///
public override string ToString() => $"{UTF8String.ToSystemStringOrEmpty(Name)} - size: {(resourceLength)}";
}
sealed class EmbeddedResourceMD : EmbeddedResource, 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);
}
public EmbeddedResourceMD(ModuleDefMD readerModule, ManifestResource mr, byte[] data)
: this(readerModule, mr, ByteArrayDataReaderFactory.Create(data, filename: null), 0, (uint)data.Length) {
}
public EmbeddedResourceMD(ModuleDefMD readerModule, ManifestResource mr, DataReaderFactory dataReaderFactory, uint offset, uint length)
: base(mr.Name, dataReaderFactory, offset, length, mr.Flags) {
this.readerModule = readerModule;
origRid = rid = mr.Rid;
this.offset = mr.Offset;
}
}
///
/// A reference to a resource in another assembly
///
public class AssemblyLinkedResource : Resource {
AssemblyRef asmRef;
///
public override ResourceType ResourceType => ResourceType.AssemblyLinked;
///
/// Gets/sets the assembly reference
///
public AssemblyRef Assembly {
get => asmRef;
set => asmRef = value ?? throw new ArgumentNullException(nameof(value));
}
///
/// Constructor
///
/// Name of resource
/// Assembly reference
/// Resource flags
public AssemblyLinkedResource(UTF8String name, AssemblyRef asmRef, ManifestResourceAttributes flags)
: base(name, flags) => this.asmRef = asmRef ?? throw new ArgumentNullException(nameof(asmRef));
///
public override string ToString() => $"{UTF8String.ToSystemStringOrEmpty(Name)} - assembly: {asmRef.FullName}";
}
sealed class AssemblyLinkedResourceMD : AssemblyLinkedResource, 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);
}
public AssemblyLinkedResourceMD(ModuleDefMD readerModule, ManifestResource mr, AssemblyRef asmRef) : base(mr.Name, asmRef, mr.Flags) {
this.readerModule = readerModule;
origRid = rid = mr.Rid;
offset = mr.Offset;
}
}
///
/// A resource that is stored in a file on disk
///
public class LinkedResource : Resource {
FileDef file;
///
public override ResourceType ResourceType => ResourceType.Linked;
///
/// Gets/sets the file
///
public FileDef File {
get => file;
set => file = value ?? throw new ArgumentNullException(nameof(value));
}
///
/// Gets/sets the hash
///
public byte[] Hash {
get => file.HashValue;
set => file.HashValue = value;
}
///
/// Gets/sets the file name
///
public UTF8String FileName => file is null ? UTF8String.Empty : file.Name;
///
/// Constructor
///
/// Name of resource
/// The file
/// Resource flags
public LinkedResource(UTF8String name, FileDef file, ManifestResourceAttributes flags)
: base(name, flags) => this.file = file;
///
public override string ToString() => $"{UTF8String.ToSystemStringOrEmpty(Name)} - file: {UTF8String.ToSystemStringOrEmpty(FileName)}";
}
sealed class LinkedResourceMD : LinkedResource, 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);
}
public LinkedResourceMD(ModuleDefMD readerModule, ManifestResource mr, FileDef file) : base(mr.Name, file, mr.Flags) {
this.readerModule = readerModule;
origRid = rid = mr.Rid;
offset = mr.Offset;
}
}
}