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