obfuz/Plugins/dnlib/DotNet/Writer/SignatureWriter.cs

350 lines
9.4 KiB
C#

// dnlib: See LICENSE.txt for more info
using System;
using System.IO;
namespace dnlib.DotNet.Writer {
/// <summary>
/// Helps <see cref="SignatureWriter"/> map <see cref="ITypeDefOrRef"/>s to tokens
/// </summary>
public interface ISignatureWriterHelper : IWriterError {
/// <summary>
/// Returns a <c>TypeDefOrRef</c> encoded token
/// </summary>
/// <param name="typeDefOrRef">A <c>TypeDefOrRef</c> type</param>
uint ToEncodedToken(ITypeDefOrRef typeDefOrRef);
}
/// <summary>
/// Writes signatures
/// </summary>
public struct SignatureWriter : IDisposable {
readonly ISignatureWriterHelper helper;
RecursionCounter recursionCounter;
readonly MemoryStream outStream;
readonly DataWriter writer;
readonly bool disposeStream;
/// <summary>
/// Write a <see cref="TypeSig"/> signature
/// </summary>
/// <param name="helper">Helper</param>
/// <param name="typeSig">The type</param>
/// <returns>The signature as a byte array</returns>
public static byte[] Write(ISignatureWriterHelper helper, TypeSig typeSig) {
using (var writer = new SignatureWriter(helper)) {
writer.Write(typeSig);
return writer.GetResult();
}
}
internal static byte[] Write(ISignatureWriterHelper helper, TypeSig typeSig, DataWriterContext context) {
using (var writer = new SignatureWriter(helper, context)) {
writer.Write(typeSig);
return writer.GetResult();
}
}
/// <summary>
/// Write a <see cref="CallingConventionSig"/> signature
/// </summary>
/// <param name="helper">Helper</param>
/// <param name="sig">The signature</param>
/// <returns>The signature as a byte array</returns>
public static byte[] Write(ISignatureWriterHelper helper, CallingConventionSig sig) {
using (var writer = new SignatureWriter(helper)) {
writer.Write(sig);
return writer.GetResult();
}
}
internal static byte[] Write(ISignatureWriterHelper helper, CallingConventionSig sig, DataWriterContext context) {
using (var writer = new SignatureWriter(helper, context)) {
writer.Write(sig);
return writer.GetResult();
}
}
SignatureWriter(ISignatureWriterHelper helper) {
this.helper = helper;
recursionCounter = new RecursionCounter();
outStream = new MemoryStream();
writer = new DataWriter(outStream);
disposeStream = true;
}
SignatureWriter(ISignatureWriterHelper helper, DataWriterContext context) {
this.helper = helper;
recursionCounter = new RecursionCounter();
outStream = context.OutStream;
writer = context.Writer;
disposeStream = false;
outStream.SetLength(0);
outStream.Position = 0;
}
byte[] GetResult() => outStream.ToArray();
uint WriteCompressedUInt32(uint value) => writer.WriteCompressedUInt32(helper, value);
int WriteCompressedInt32(int value) => writer.WriteCompressedInt32(helper, value);
void Write(TypeSig typeSig) {
const ElementType DEFAULT_ELEMENT_TYPE = ElementType.Boolean;
if (typeSig is null) {
helper.Error("TypeSig is null");
writer.WriteByte((byte)DEFAULT_ELEMENT_TYPE);
return;
}
if (!recursionCounter.Increment()) {
helper.Error("Infinite recursion");
writer.WriteByte((byte)DEFAULT_ELEMENT_TYPE);
return;
}
uint count;
switch (typeSig.ElementType) {
case ElementType.Void:
case ElementType.Boolean:
case ElementType.Char:
case ElementType.I1:
case ElementType.U1:
case ElementType.I2:
case ElementType.U2:
case ElementType.I4:
case ElementType.U4:
case ElementType.I8:
case ElementType.U8:
case ElementType.R4:
case ElementType.R8:
case ElementType.String:
case ElementType.TypedByRef:
case ElementType.I:
case ElementType.U:
case ElementType.Object:
case ElementType.Sentinel:
writer.WriteByte((byte)typeSig.ElementType);
break;
case ElementType.Ptr:
case ElementType.ByRef:
case ElementType.SZArray:
case ElementType.Pinned:
writer.WriteByte((byte)typeSig.ElementType);
Write(typeSig.Next);
break;
case ElementType.ValueType:
case ElementType.Class:
writer.WriteByte((byte)typeSig.ElementType);
Write(((TypeDefOrRefSig)typeSig).TypeDefOrRef);
break;
case ElementType.Var:
case ElementType.MVar:
writer.WriteByte((byte)typeSig.ElementType);
WriteCompressedUInt32(((GenericSig)typeSig).Number);
break;
case ElementType.Array:
writer.WriteByte((byte)typeSig.ElementType);
var ary = (ArraySig)typeSig;
Write(ary.Next);
WriteCompressedUInt32(ary.Rank);
if (ary.Rank == 0)
break;
count = WriteCompressedUInt32((uint)ary.Sizes.Count);
for (uint i = 0; i < count; i++)
WriteCompressedUInt32(ary.Sizes[(int)i]);
count = WriteCompressedUInt32((uint)ary.LowerBounds.Count);
for (uint i = 0; i < count; i++)
WriteCompressedInt32(ary.LowerBounds[(int)i]);
break;
case ElementType.GenericInst:
writer.WriteByte((byte)typeSig.ElementType);
var gis = (GenericInstSig)typeSig;
Write(gis.GenericType);
count = WriteCompressedUInt32((uint)gis.GenericArguments.Count);
for (uint i = 0; i < count; i++)
Write(gis.GenericArguments[(int)i]);
break;
case ElementType.ValueArray:
writer.WriteByte((byte)typeSig.ElementType);
Write(typeSig.Next);
WriteCompressedUInt32((typeSig as ValueArraySig).Size);
break;
case ElementType.FnPtr:
writer.WriteByte((byte)typeSig.ElementType);
Write((typeSig as FnPtrSig).Signature);
break;
case ElementType.CModReqd:
case ElementType.CModOpt:
writer.WriteByte((byte)typeSig.ElementType);
Write((typeSig as ModifierSig).Modifier);
Write(typeSig.Next);
break;
case ElementType.Module:
writer.WriteByte((byte)typeSig.ElementType);
WriteCompressedUInt32((typeSig as ModuleSig).Index);
Write(typeSig.Next);
break;
case ElementType.End:
case ElementType.R:
case ElementType.Internal:
default:
helper.Error("Unknown or unsupported element type");
writer.WriteByte((byte)DEFAULT_ELEMENT_TYPE);
break;
}
recursionCounter.Decrement();
}
void Write(ITypeDefOrRef tdr) {
if (tdr is null) {
helper.Error("TypeDefOrRef is null");
WriteCompressedUInt32(0);
return;
}
uint encodedToken = helper.ToEncodedToken(tdr);
if (encodedToken > 0x1FFFFFFF) {
helper.Error("Encoded token doesn't fit in 29 bits");
encodedToken = 0;
}
WriteCompressedUInt32(encodedToken);
}
void Write(CallingConventionSig sig) {
if (sig is null) {
helper.Error("sig is null");
return;
}
if (!recursionCounter.Increment()) {
helper.Error("Infinite recursion");
return;
}
MethodBaseSig mbs;
FieldSig fs;
LocalSig ls;
GenericInstMethodSig gim;
if ((mbs = sig as MethodBaseSig) is not null)
Write(mbs);
else if ((fs = sig as FieldSig) is not null)
Write(fs);
else if ((ls = sig as LocalSig) is not null)
Write(ls);
else if ((gim = sig as GenericInstMethodSig) is not null)
Write(gim);
else {
helper.Error("Unknown calling convention sig");
writer.WriteByte((byte)sig.GetCallingConvention());
}
recursionCounter.Decrement();
}
void Write(MethodBaseSig sig) {
if (sig is null) {
helper.Error("sig is null");
return;
}
if (!recursionCounter.Increment()) {
helper.Error("Infinite recursion");
return;
}
writer.WriteByte((byte)sig.GetCallingConvention());
if (sig.Generic)
WriteCompressedUInt32(sig.GenParamCount);
uint numParams = (uint)sig.Params.Count;
if (sig.ParamsAfterSentinel is not null)
numParams += (uint)sig.ParamsAfterSentinel.Count;
uint count = WriteCompressedUInt32(numParams);
Write(sig.RetType);
for (uint i = 0; i < count && i < (uint)sig.Params.Count; i++)
Write(sig.Params[(int)i]);
if (sig.ParamsAfterSentinel is not null && sig.ParamsAfterSentinel.Count > 0) {
writer.WriteByte((byte)ElementType.Sentinel);
for (uint i = 0, j = (uint)sig.Params.Count; i < (uint)sig.ParamsAfterSentinel.Count && j < count; i++, j++)
Write(sig.ParamsAfterSentinel[(int)i]);
}
recursionCounter.Decrement();
}
void Write(FieldSig sig) {
if (sig is null) {
helper.Error("sig is null");
return;
}
if (!recursionCounter.Increment()) {
helper.Error("Infinite recursion");
return;
}
writer.WriteByte((byte)sig.GetCallingConvention());
Write(sig.Type);
recursionCounter.Decrement();
}
void Write(LocalSig sig) {
if (sig is null) {
helper.Error("sig is null");
return;
}
if (!recursionCounter.Increment()) {
helper.Error("Infinite recursion");
return;
}
writer.WriteByte((byte)sig.GetCallingConvention());
uint count = WriteCompressedUInt32((uint)sig.Locals.Count);
if (count >= 0x10000) {
// ldloc 0xFFFF is invalid, see the ldloc documentation
helper.Error("Too many locals, max number of locals is 65535 (0xFFFF)");
}
for (uint i = 0; i < count; i++)
Write(sig.Locals[(int)i]);
recursionCounter.Decrement();
}
void Write(GenericInstMethodSig sig) {
if (sig is null) {
helper.Error("sig is null");
return;
}
if (!recursionCounter.Increment()) {
helper.Error("Infinite recursion");
return;
}
writer.WriteByte((byte)sig.GetCallingConvention());
uint count = WriteCompressedUInt32((uint)sig.GenericArguments.Count);
for (uint i = 0; i < count; i++)
Write(sig.GenericArguments[(int)i]);
recursionCounter.Decrement();
}
/// <inheritdoc/>
public void Dispose() {
if (!disposeStream)
return;
if (outStream is not null)
outStream.Dispose();
}
}
}