// 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;
using dnlib.Threading;
namespace dnlib.DotNet {
///
/// A high-level representation of a row in the Event table
///
public abstract class EventDef : IHasCustomAttribute, IHasSemantic, IHasCustomDebugInformation, IFullName, IMemberDef {
///
/// The row id in its table
///
protected uint rid;
#if THREAD_SAFE
readonly Lock theLock = Lock.Create();
#endif
///
public MDToken MDToken => new MDToken(Table.Event, rid);
///
public uint Rid {
get => rid;
set => rid = value;
}
///
public int HasCustomAttributeTag => 10;
///
public int HasSemanticTag => 0;
///
/// From column Event.EventFlags
///
public EventAttributes Attributes {
get => (EventAttributes)attributes;
set => attributes = (int)value;
}
///
protected int attributes;
///
/// From column Event.Name
///
public UTF8String Name {
get => name;
set => name = value;
}
/// Name
protected UTF8String name;
///
/// From column Event.EventType
///
public ITypeDefOrRef EventType {
get => eventType;
set => eventType = value;
}
///
protected ITypeDefOrRef eventType;
///
/// 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 int HasCustomDebugInformationTag => 10;
///
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);
///
/// Gets/sets the adder method
///
public MethodDef AddMethod {
get {
if (otherMethods is null)
InitializeEventMethods();
return addMethod;
}
set {
if (otherMethods is null)
InitializeEventMethods();
addMethod = value;
}
}
///
/// Gets/sets the invoker method
///
public MethodDef InvokeMethod {
get {
if (otherMethods is null)
InitializeEventMethods();
return invokeMethod;
}
set {
if (otherMethods is null)
InitializeEventMethods();
invokeMethod = value;
}
}
///
/// Gets/sets the remover method
///
public MethodDef RemoveMethod {
get {
if (otherMethods is null)
InitializeEventMethods();
return removeMethod;
}
set {
if (otherMethods is null)
InitializeEventMethods();
removeMethod = value;
}
}
///
/// Gets the other methods
///
public IList OtherMethods {
get {
if (otherMethods is null)
InitializeEventMethods();
return otherMethods;
}
}
void InitializeEventMethods() {
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
if (otherMethods is null)
InitializeEventMethods_NoLock();
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
}
///
/// Initializes , ,
/// and .
///
protected virtual void InitializeEventMethods_NoLock() =>
otherMethods = new List();
///
protected MethodDef addMethod;
///
protected MethodDef invokeMethod;
///
protected MethodDef removeMethod;
///
protected IList otherMethods;
/// Reset , , ,
protected void ResetMethods() => otherMethods = null;
///
/// true if there are no methods attached to this event
///
public bool IsEmpty =>
// The first property access initializes the other fields we access here
AddMethod is null &&
removeMethod is null &&
invokeMethod is null &&
otherMethods.Count == 0;
///
public bool HasCustomAttributes => CustomAttributes.Count > 0;
///
/// true if is not empty
///
public bool HasOtherMethods => OtherMethods.Count > 0;
///
/// Gets/sets the declaring type (owner type)
///
public TypeDef DeclaringType {
get => declaringType2;
set {
var currentDeclaringType = DeclaringType2;
if (currentDeclaringType == value)
return;
if (currentDeclaringType is not null)
currentDeclaringType.Events.Remove(this); // Will set DeclaringType2 = null
if (value is not null)
value.Events.Add(this); // Will set DeclaringType2 = value
}
}
///
ITypeDefOrRef IMemberRef.DeclaringType => declaringType2;
///
/// Called by and should normally not be called by any user
/// code. Use instead. Only call this if you must set the
/// declaring type without inserting it in the declaring type's method list.
///
public TypeDef DeclaringType2 {
get => declaringType2;
set => declaringType2 = value;
}
///
protected TypeDef declaringType2;
///
public ModuleDef Module => declaringType2?.Module;
///
/// Gets the full name of the event
///
public string FullName => FullNameFactory.EventFullName(declaringType2?.FullName, name, eventType, null, null);
bool IIsTypeOrMethod.IsType => false;
bool IIsTypeOrMethod.IsMethod => false;
bool IMemberRef.IsField => false;
bool IMemberRef.IsTypeSpec => false;
bool IMemberRef.IsTypeRef => false;
bool IMemberRef.IsTypeDef => false;
bool IMemberRef.IsMethodSpec => false;
bool IMemberRef.IsMethodDef => false;
bool IMemberRef.IsMemberRef => false;
bool IMemberRef.IsFieldDef => false;
bool IMemberRef.IsPropertyDef => false;
bool IMemberRef.IsEventDef => true;
bool IMemberRef.IsGenericParam => false;
///
/// 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, EventAttributes flags) {
if (set)
attributes |= (int)flags;
else
attributes &= ~(int)flags;
}
///
/// Gets/sets the bit
///
public bool IsSpecialName {
get => ((EventAttributes)attributes & EventAttributes.SpecialName) != 0;
set => ModifyAttributes(value, EventAttributes.SpecialName);
}
///
/// Gets/sets the bit
///
public bool IsRuntimeSpecialName {
get => ((EventAttributes)attributes & EventAttributes.RTSpecialName) != 0;
set => ModifyAttributes(value, EventAttributes.RTSpecialName);
}
///
public override string ToString() => FullName;
}
///
/// An Event row created by the user and not present in the original .NET file
///
public class EventDefUser : EventDef {
///
/// Default constructor
///
public EventDefUser() {
}
///
/// Constructor
///
/// Name
public EventDefUser(UTF8String name)
: this(name, null, 0) {
}
///
/// Constructor
///
/// Name
/// Type
public EventDefUser(UTF8String name, ITypeDefOrRef type)
: this(name, type, 0) {
}
///
/// Constructor
///
/// Name
/// Type
/// Flags
public EventDefUser(UTF8String name, ITypeDefOrRef type, EventAttributes flags) {
this.name = name;
eventType = type;
attributes = (int)flags;
}
}
///
/// Created from a row in the Event table
///
sealed class EventDefMD : EventDef, 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.Event, 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(declaringType2), list);
Interlocked.CompareExchange(ref customDebugInfos, list, null);
}
///
/// Constructor
///
/// The module which contains this Event row
/// Row ID
/// If is null
/// If is invalid
public EventDefMD(ModuleDefMD readerModule, uint rid) {
#if DEBUG
if (readerModule is null)
throw new ArgumentNullException("readerModule");
if (readerModule.TablesStream.EventTable.IsInvalidRID(rid))
throw new BadImageFormatException($"Event rid {rid} does not exist");
#endif
origRid = rid;
this.rid = rid;
this.readerModule = readerModule;
bool b = readerModule.TablesStream.TryReadEventRow(origRid, out var row);
Debug.Assert(b);
attributes = row.EventFlags;
name = readerModule.StringsStream.ReadNoNull(row.Name);
declaringType2 = readerModule.GetOwnerType(this);
eventType = readerModule.ResolveTypeDefOrRef(row.EventType, new GenericParamContext(declaringType2));
}
internal EventDefMD InitializeAll() {
MemberMDInitializer.Initialize(Attributes);
MemberMDInitializer.Initialize(Name);
MemberMDInitializer.Initialize(EventType);
MemberMDInitializer.Initialize(CustomAttributes);
MemberMDInitializer.Initialize(AddMethod);
MemberMDInitializer.Initialize(InvokeMethod);
MemberMDInitializer.Initialize(RemoveMethod);
MemberMDInitializer.Initialize(OtherMethods);
MemberMDInitializer.Initialize(DeclaringType);
return this;
}
///
protected override void InitializeEventMethods_NoLock() {
IList newOtherMethods;
var dt = declaringType2 as TypeDefMD;
if (dt is null)
newOtherMethods = new List();
else
dt.InitializeEvent(this, out addMethod, out invokeMethod, out removeMethod, out newOtherMethods);
otherMethods = newOtherMethods;
}
}
}