obfuz/Plugins/dnlib/DotNet/Constant.cs

205 lines
4.9 KiB
C#
Raw Normal View History

2025-04-08 20:31:44 +08:00
// dnlib: See LICENSE.txt for more info
using System;
using System.Diagnostics;
using dnlib.DotNet.MD;
using dnlib.IO;
namespace dnlib.DotNet {
/// <summary>
/// A high-level representation of a row in the Constant table
/// </summary>
public abstract class Constant : IMDTokenProvider {
/// <summary>
/// The row id in its table
/// </summary>
protected uint rid;
/// <inheritdoc/>
public MDToken MDToken => new MDToken(Table.Constant, rid);
/// <inheritdoc/>
public uint Rid {
get => rid;
set => rid = value;
}
/// <summary>
/// From column Constant.Type
/// </summary>
public ElementType Type {
get => type;
set => type = value;
}
/// <summary/>
protected ElementType type;
/// <summary>
/// From column Constant.Value
/// </summary>
public object Value {
get => value;
set => this.value = value;
}
/// <summary/>
protected object value;
}
/// <summary>
/// A Constant row created by the user and not present in the original .NET file
/// </summary>
public class ConstantUser : Constant {
/// <summary>
/// Default constructor
/// </summary>
public ConstantUser() {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="value">Value</param>
public ConstantUser(object value) {
type = GetElementType(value);
this.value = value;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="value">Value</param>
/// <param name="type">Type</param>
public ConstantUser(object value, ElementType type) {
this.type = type;
this.value = value;
}
static ElementType GetElementType(object value) {
if (value is null)
return ElementType.Class;
return System.Type.GetTypeCode(value.GetType()) switch {
TypeCode.Boolean => ElementType.Boolean,
TypeCode.Char => ElementType.Char,
TypeCode.SByte => ElementType.I1,
TypeCode.Byte => ElementType.U1,
TypeCode.Int16 => ElementType.I2,
TypeCode.UInt16 => ElementType.U2,
TypeCode.Int32 => ElementType.I4,
TypeCode.UInt32 => ElementType.U4,
TypeCode.Int64 => ElementType.I8,
TypeCode.UInt64 => ElementType.U8,
TypeCode.Single => ElementType.R4,
TypeCode.Double => ElementType.R8,
TypeCode.String => ElementType.String,
_ => ElementType.Void,
};
}
}
/// <summary>
/// Created from a row in the Constant table
/// </summary>
sealed class ConstantMD : Constant, IMDTokenProviderMD {
readonly uint origRid;
/// <inheritdoc/>
public uint OrigRid => origRid;
/// <summary>
/// Constructor
/// </summary>
/// <param name="readerModule">The module which contains this <c>Constant</c> row</param>
/// <param name="rid">Row ID</param>
/// <exception cref="ArgumentNullException">If <paramref name="readerModule"/> is <c>null</c></exception>
/// <exception cref="ArgumentException">If <paramref name="rid"/> is invalid</exception>
public ConstantMD(ModuleDefMD readerModule, uint rid) {
#if DEBUG
if (readerModule is null)
throw new ArgumentNullException("readerModule");
if (readerModule.TablesStream.ConstantTable.IsInvalidRID(rid))
throw new BadImageFormatException($"Constant rid {rid} does not exist");
#endif
origRid = rid;
this.rid = rid;
bool b = readerModule.TablesStream.TryReadConstantRow(origRid, out var row);
Debug.Assert(b);
type = (ElementType)row.Type;
var reader = readerModule.BlobStream.CreateReader(row.Value);
value = GetValue(type, ref reader);
}
static object GetValue(ElementType etype, ref DataReader reader) {
switch (etype) {
case ElementType.Boolean:
if (reader.Length < 1)
return false;
return reader.ReadBoolean();
case ElementType.Char:
if (reader.Length < 2)
return (char)0;
return reader.ReadChar();
case ElementType.I1:
if (reader.Length < 1)
return (sbyte)0;
return reader.ReadSByte();
case ElementType.U1:
if (reader.Length < 1)
return (byte)0;
return reader.ReadByte();
case ElementType.I2:
if (reader.Length < 2)
return (short)0;
return reader.ReadInt16();
case ElementType.U2:
if (reader.Length < 2)
return (ushort)0;
return reader.ReadUInt16();
case ElementType.I4:
if (reader.Length < 4)
return (int)0;
return reader.ReadInt32();
case ElementType.U4:
if (reader.Length < 4)
return (uint)0;
return reader.ReadUInt32();
case ElementType.I8:
if (reader.Length < 8)
return (long)0;
return reader.ReadInt64();
case ElementType.U8:
if (reader.Length < 8)
return (ulong)0;
return reader.ReadUInt64();
case ElementType.R4:
if (reader.Length < 4)
return (float)0;
return reader.ReadSingle();
case ElementType.R8:
if (reader.Length < 8)
return (double)0;
return reader.ReadDouble();
case ElementType.String:
return reader.ReadUtf16String((int)(reader.BytesLeft / 2));
case ElementType.Class:
return null;
default:
return null;
}
}
}
}