// dnlib: See LICENSE.txt for more info
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using dnlib.DotNet.MD;
namespace dnlib.DotNet {
///
/// A high-level representation of a row in the ImplMap table
///
[DebuggerDisplay("{Module} {Name}")]
public abstract class ImplMap : IMDTokenProvider {
///
/// The row id in its table
///
protected uint rid;
///
public MDToken MDToken => new MDToken(Table.ImplMap, rid);
///
public uint Rid {
get => rid;
set => rid = value;
}
///
/// From column ImplMap.MappingFlags
///
public PInvokeAttributes Attributes {
get => (PInvokeAttributes)attributes;
set => attributes = (int)value;
}
/// Attributes
protected int attributes;
///
/// From column ImplMap.ImportName
///
public UTF8String Name {
get => name;
set => name = value;
}
/// Name
protected UTF8String name;
///
/// From column ImplMap.ImportScope
///
public ModuleRef Module {
get => module;
set => module = value;
}
///
protected ModuleRef module;
///
/// Modify property: =
/// ( & ) | .
///
/// Value to AND
/// Value to OR
void ModifyAttributes(PInvokeAttributes andMask, PInvokeAttributes 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, PInvokeAttributes flags) {
if (set)
attributes |= (int)flags;
else
attributes &= ~(int)flags;
}
///
/// Gets/sets the bit
///
public bool IsNoMangle {
get => ((PInvokeAttributes)attributes & PInvokeAttributes.NoMangle) != 0;
set => ModifyAttributes(value, PInvokeAttributes.NoMangle);
}
///
/// Gets/sets the char set
///
public PInvokeAttributes CharSet {
get => (PInvokeAttributes)attributes & PInvokeAttributes.CharSetMask;
set => ModifyAttributes(~PInvokeAttributes.CharSetMask, value & PInvokeAttributes.CharSetMask);
}
///
/// true if is set
///
public bool IsCharSetNotSpec => ((PInvokeAttributes)attributes & PInvokeAttributes.CharSetMask) == PInvokeAttributes.CharSetNotSpec;
///
/// true if is set
///
public bool IsCharSetAnsi => ((PInvokeAttributes)attributes & PInvokeAttributes.CharSetMask) == PInvokeAttributes.CharSetAnsi;
///
/// true if is set
///
public bool IsCharSetUnicode => ((PInvokeAttributes)attributes & PInvokeAttributes.CharSetMask) == PInvokeAttributes.CharSetUnicode;
///
/// true if is set
///
public bool IsCharSetAuto => ((PInvokeAttributes)attributes & PInvokeAttributes.CharSetMask) == PInvokeAttributes.CharSetAuto;
///
/// Gets/sets best fit
///
public PInvokeAttributes BestFit {
get => (PInvokeAttributes)attributes & PInvokeAttributes.BestFitMask;
set => ModifyAttributes(~PInvokeAttributes.BestFitMask, value & PInvokeAttributes.BestFitMask);
}
///
/// true if is set
///
public bool IsBestFitUseAssem => ((PInvokeAttributes)attributes & PInvokeAttributes.BestFitMask) == PInvokeAttributes.BestFitUseAssem;
///
/// true if is set
///
public bool IsBestFitEnabled => ((PInvokeAttributes)attributes & PInvokeAttributes.BestFitMask) == PInvokeAttributes.BestFitEnabled;
///
/// true if is set
///
public bool IsBestFitDisabled => ((PInvokeAttributes)attributes & PInvokeAttributes.BestFitMask) == PInvokeAttributes.BestFitDisabled;
///
/// Gets/sets throw on unmappable char
///
public PInvokeAttributes ThrowOnUnmappableChar {
get => (PInvokeAttributes)attributes & PInvokeAttributes.ThrowOnUnmappableCharMask;
set => ModifyAttributes(~PInvokeAttributes.ThrowOnUnmappableCharMask, value & PInvokeAttributes.ThrowOnUnmappableCharMask);
}
///
/// true if is set
///
public bool IsThrowOnUnmappableCharUseAssem => ((PInvokeAttributes)attributes & PInvokeAttributes.ThrowOnUnmappableCharMask) == PInvokeAttributes.ThrowOnUnmappableCharUseAssem;
///
/// true if is set
///
public bool IsThrowOnUnmappableCharEnabled => ((PInvokeAttributes)attributes & PInvokeAttributes.ThrowOnUnmappableCharMask) == PInvokeAttributes.ThrowOnUnmappableCharEnabled;
///
/// true if is set
///
public bool IsThrowOnUnmappableCharDisabled => ((PInvokeAttributes)attributes & PInvokeAttributes.ThrowOnUnmappableCharMask) == PInvokeAttributes.ThrowOnUnmappableCharDisabled;
///
/// Gets/sets the bit
///
public bool SupportsLastError {
get => ((PInvokeAttributes)attributes & PInvokeAttributes.SupportsLastError) != 0;
set => ModifyAttributes(value, PInvokeAttributes.SupportsLastError);
}
///
/// Gets/sets calling convention
///
public PInvokeAttributes CallConv {
get => (PInvokeAttributes)attributes & PInvokeAttributes.CallConvMask;
set => ModifyAttributes(~PInvokeAttributes.CallConvMask, value & PInvokeAttributes.CallConvMask);
}
///
/// true if is set
///
public bool IsCallConvWinapi => ((PInvokeAttributes)attributes & PInvokeAttributes.CallConvMask) == PInvokeAttributes.CallConvWinapi;
///
/// true if is set
///
public bool IsCallConvCdecl => ((PInvokeAttributes)attributes & PInvokeAttributes.CallConvMask) == PInvokeAttributes.CallConvCdecl;
///
/// true if is set
///
public bool IsCallConvStdcall => ((PInvokeAttributes)attributes & PInvokeAttributes.CallConvMask) == PInvokeAttributes.CallConvStdcall;
///
/// true if is set
///
public bool IsCallConvThiscall => ((PInvokeAttributes)attributes & PInvokeAttributes.CallConvMask) == PInvokeAttributes.CallConvThiscall;
///
/// true if is set
///
public bool IsCallConvFastcall => ((PInvokeAttributes)attributes & PInvokeAttributes.CallConvMask) == PInvokeAttributes.CallConvFastcall;
///
/// Checks whether this is a certain P/Invoke method
///
/// Name of the DLL
/// Name of the function within the DLL
/// true if it's the specified P/Invoke method, else false
public bool IsPinvokeMethod(string dllName, string funcName) => IsPinvokeMethod(dllName, funcName, IsWindows());
///
/// Checks whether this is a certain P/Invoke method
///
/// Name of the DLL
/// Name of the function within the DLL
/// Treat as Windows
/// true if it's the specified P/Invoke method, else false
public bool IsPinvokeMethod(string dllName, string funcName, bool treatAsWindows) {
if (name != funcName)
return false;
var mod = module;
if (mod is null)
return false;
return GetDllName(dllName, treatAsWindows).Equals(GetDllName(mod.Name, treatAsWindows), StringComparison.OrdinalIgnoreCase);
}
static string GetDllName(string dllName, bool treatAsWindows) {
if (treatAsWindows)
dllName = dllName.TrimEnd(trimChars);
if (dllName.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
return dllName.Substring(0, dllName.Length - 4);
return dllName;
}
static bool IsWindows() =>
#if NETSTANDARD || NETCOREAPP
RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
#else
Path.DirectorySeparatorChar == '\\' || Path.AltDirectorySeparatorChar == '\\';
#endif
static readonly char[] trimChars = { ' ' };
}
///
/// An ImplMap row created by the user and not present in the original .NET file
///
public class ImplMapUser : ImplMap {
///
/// Default constructor
///
public ImplMapUser() {
}
///
/// Constructor
///
/// Scope
/// Name
/// Flags
public ImplMapUser(ModuleRef scope, UTF8String name, PInvokeAttributes flags) {
module = scope;
this.name = name;
attributes = (int)flags;
}
}
///
/// Created from a row in the ImplMap table
///
sealed class ImplMapMD : ImplMap, IMDTokenProviderMD {
readonly uint origRid;
///
public uint OrigRid => origRid;
///
/// Constructor
///
/// The module which contains this ImplMap row
/// Row ID
/// If is null
/// If is invalid
public ImplMapMD(ModuleDefMD readerModule, uint rid) {
#if DEBUG
if (readerModule is null)
throw new ArgumentNullException("readerModule");
if (readerModule.TablesStream.ImplMapTable.IsInvalidRID(rid))
throw new BadImageFormatException($"ImplMap rid {rid} does not exist");
#endif
origRid = rid;
this.rid = rid;
bool b = readerModule.TablesStream.TryReadImplMapRow(origRid, out var row);
Debug.Assert(b);
attributes = row.MappingFlags;
name = readerModule.StringsStream.ReadNoNull(row.ImportName);
module = readerModule.ResolveModuleRef(row.ImportScope);
}
}
}