301 lines
7.3 KiB
C#
301 lines
7.3 KiB
C#
// dnlib: See LICENSE.txt for more info
|
|
|
|
using System;
|
|
using System.Diagnostics;
|
|
using dnlib.IO;
|
|
|
|
namespace dnlib.DotNet.Pdb.Portable {
|
|
struct LocalConstantSigBlobReader {
|
|
readonly ModuleDef module;
|
|
DataReader reader;
|
|
readonly GenericParamContext gpContext;
|
|
RecursionCounter recursionCounter;
|
|
|
|
public LocalConstantSigBlobReader(ModuleDef module, ref DataReader reader, GenericParamContext gpContext) {
|
|
this.module = module;
|
|
this.reader = reader;
|
|
this.gpContext = gpContext;
|
|
recursionCounter = default;
|
|
}
|
|
|
|
public bool Read(out TypeSig type, out object value) {
|
|
bool b = ReadCatch(out type, out value);
|
|
Debug.Assert(!b || reader.Position == reader.Length);
|
|
return b;
|
|
}
|
|
|
|
bool ReadCatch(out TypeSig type, out object value) {
|
|
try {
|
|
return ReadCore(out type, out value);
|
|
}
|
|
catch {
|
|
}
|
|
type = null;
|
|
value = null;
|
|
return false;
|
|
}
|
|
|
|
bool ReadCore(out TypeSig type, out object value) {
|
|
if (!recursionCounter.Increment()) {
|
|
type = null;
|
|
value = null;
|
|
return false;
|
|
}
|
|
|
|
bool res;
|
|
ITypeDefOrRef tdr;
|
|
UTF8String ns, name;
|
|
var et = (ElementType)reader.ReadByte();
|
|
switch (et) {
|
|
case ElementType.Boolean:
|
|
type = module.CorLibTypes.Boolean;
|
|
value = reader.ReadBoolean();
|
|
if (reader.Position < reader.Length)
|
|
type = ReadTypeDefOrRefSig();
|
|
res = true;
|
|
break;
|
|
|
|
case ElementType.Char:
|
|
type = module.CorLibTypes.Char;
|
|
value = reader.ReadChar();
|
|
if (reader.Position < reader.Length)
|
|
type = ReadTypeDefOrRefSig();
|
|
res = true;
|
|
break;
|
|
|
|
case ElementType.I1:
|
|
type = module.CorLibTypes.SByte;
|
|
value = reader.ReadSByte();
|
|
if (reader.Position < reader.Length)
|
|
type = ReadTypeDefOrRefSig();
|
|
res = true;
|
|
break;
|
|
|
|
case ElementType.U1:
|
|
type = module.CorLibTypes.Byte;
|
|
value = reader.ReadByte();
|
|
if (reader.Position < reader.Length)
|
|
type = ReadTypeDefOrRefSig();
|
|
res = true;
|
|
break;
|
|
|
|
case ElementType.I2:
|
|
type = module.CorLibTypes.Int16;
|
|
value = reader.ReadInt16();
|
|
if (reader.Position < reader.Length)
|
|
type = ReadTypeDefOrRefSig();
|
|
res = true;
|
|
break;
|
|
|
|
case ElementType.U2:
|
|
type = module.CorLibTypes.UInt16;
|
|
value = reader.ReadUInt16();
|
|
if (reader.Position < reader.Length)
|
|
type = ReadTypeDefOrRefSig();
|
|
res = true;
|
|
break;
|
|
|
|
case ElementType.I4:
|
|
type = module.CorLibTypes.Int32;
|
|
value = reader.ReadInt32();
|
|
if (reader.Position < reader.Length)
|
|
type = ReadTypeDefOrRefSig();
|
|
res = true;
|
|
break;
|
|
|
|
case ElementType.U4:
|
|
type = module.CorLibTypes.UInt32;
|
|
value = reader.ReadUInt32();
|
|
if (reader.Position < reader.Length)
|
|
type = ReadTypeDefOrRefSig();
|
|
res = true;
|
|
break;
|
|
|
|
case ElementType.I8:
|
|
type = module.CorLibTypes.Int64;
|
|
value = reader.ReadInt64();
|
|
if (reader.Position < reader.Length)
|
|
type = ReadTypeDefOrRefSig();
|
|
res = true;
|
|
break;
|
|
|
|
case ElementType.U8:
|
|
type = module.CorLibTypes.UInt64;
|
|
value = reader.ReadUInt64();
|
|
if (reader.Position < reader.Length)
|
|
type = ReadTypeDefOrRefSig();
|
|
res = true;
|
|
break;
|
|
|
|
case ElementType.R4:
|
|
type = module.CorLibTypes.Single;
|
|
value = reader.ReadSingle();
|
|
res = true;
|
|
break;
|
|
|
|
case ElementType.R8:
|
|
type = module.CorLibTypes.Double;
|
|
value = reader.ReadDouble();
|
|
res = true;
|
|
break;
|
|
|
|
case ElementType.String:
|
|
type = module.CorLibTypes.String;
|
|
value = ReadString();
|
|
res = true;
|
|
break;
|
|
|
|
case ElementType.Ptr:
|
|
res = ReadCatch(out type, out value);
|
|
if (res)
|
|
type = new PtrSig(type);
|
|
break;
|
|
|
|
case ElementType.ByRef:
|
|
res = ReadCatch(out type, out value);
|
|
if (res)
|
|
type = new ByRefSig(type);
|
|
break;
|
|
|
|
case ElementType.Object:
|
|
type = module.CorLibTypes.Object;
|
|
value = null;
|
|
res = true;
|
|
break;
|
|
|
|
case ElementType.ValueType:
|
|
tdr = ReadTypeDefOrRef();
|
|
type = tdr.ToTypeSig();
|
|
value = null;
|
|
if (GetName(tdr, out ns, out name) && ns == stringSystem && tdr.DefinitionAssembly.IsCorLib()) {
|
|
if (name == stringDecimal) {
|
|
if (reader.Length - reader.Position != 13)
|
|
goto default;
|
|
try {
|
|
byte b = reader.ReadByte();
|
|
value = new Decimal(reader.ReadInt32(), reader.ReadInt32(), reader.ReadInt32(), (b & 0x80) != 0, (byte)(b & 0x7F));
|
|
}
|
|
catch {
|
|
goto default;
|
|
}
|
|
}
|
|
else if (name == stringDateTime) {
|
|
if (reader.Length - reader.Position != 8)
|
|
goto default;
|
|
try {
|
|
value = new DateTime(reader.ReadInt64());
|
|
}
|
|
catch {
|
|
goto default;
|
|
}
|
|
}
|
|
}
|
|
if (value is null && reader.Position != reader.Length)
|
|
value = reader.ReadRemainingBytes();
|
|
res = true;
|
|
break;
|
|
|
|
case ElementType.Class:
|
|
type = new ClassSig(ReadTypeDefOrRef());
|
|
value = reader.Position == reader.Length ? null : reader.ReadRemainingBytes();
|
|
res = true;
|
|
break;
|
|
|
|
case ElementType.CModReqd:
|
|
tdr = ReadTypeDefOrRef();
|
|
res = ReadCatch(out type, out value);
|
|
if (res)
|
|
type = new CModReqdSig(tdr, type);
|
|
break;
|
|
|
|
case ElementType.CModOpt:
|
|
tdr = ReadTypeDefOrRef();
|
|
res = ReadCatch(out type, out value);
|
|
if (res)
|
|
type = new CModOptSig(tdr, type);
|
|
break;
|
|
|
|
case ElementType.Var:
|
|
case ElementType.Array:
|
|
case ElementType.GenericInst:
|
|
case ElementType.TypedByRef:
|
|
case ElementType.I:
|
|
case ElementType.U:
|
|
case ElementType.FnPtr:
|
|
case ElementType.SZArray:
|
|
case ElementType.MVar:
|
|
case ElementType.End:
|
|
case ElementType.Void:
|
|
case ElementType.ValueArray:
|
|
case ElementType.R:
|
|
case ElementType.Internal:
|
|
case ElementType.Module:
|
|
case ElementType.Sentinel:
|
|
case ElementType.Pinned:
|
|
default:
|
|
Debug.Fail($"Unsupported element type in LocalConstant sig blob: {et}");
|
|
res = false;
|
|
type = null;
|
|
value = null;
|
|
break;
|
|
}
|
|
|
|
recursionCounter.Decrement();
|
|
return res;
|
|
}
|
|
static readonly UTF8String stringSystem = new UTF8String("System");
|
|
static readonly UTF8String stringDecimal = new UTF8String("Decimal");
|
|
static readonly UTF8String stringDateTime = new UTF8String("DateTime");
|
|
|
|
static bool GetName(ITypeDefOrRef tdr, out UTF8String @namespace, out UTF8String name) {
|
|
if (tdr is TypeRef tr) {
|
|
@namespace = tr.Namespace;
|
|
name = tr.Name;
|
|
return true;
|
|
}
|
|
|
|
if (tdr is TypeDef td) {
|
|
@namespace = td.Namespace;
|
|
name = td.Name;
|
|
return true;
|
|
}
|
|
|
|
@namespace = null;
|
|
name = null;
|
|
return false;
|
|
}
|
|
|
|
TypeSig ReadTypeDefOrRefSig() {
|
|
uint codedToken;
|
|
if (!reader.TryReadCompressedUInt32(out codedToken))
|
|
return null;
|
|
ISignatureReaderHelper helper = module;
|
|
var tdr = helper.ResolveTypeDefOrRef(codedToken, gpContext);
|
|
return tdr.ToTypeSig();
|
|
}
|
|
|
|
ITypeDefOrRef ReadTypeDefOrRef() {
|
|
uint codedToken;
|
|
if (!reader.TryReadCompressedUInt32(out codedToken))
|
|
return null;
|
|
ISignatureReaderHelper helper = module;
|
|
var tdr = helper.ResolveTypeDefOrRef(codedToken, gpContext);
|
|
var corType = module.CorLibTypes.GetCorLibTypeSig(tdr);
|
|
if (corType is not null)
|
|
return corType.TypeDefOrRef;
|
|
return tdr;
|
|
}
|
|
|
|
string ReadString() {
|
|
if (reader.Position == reader.Length)
|
|
return string.Empty;
|
|
byte b = reader.ReadByte();
|
|
if (b == 0xFF && reader.Position == reader.Length)
|
|
return null;
|
|
reader.Position--;
|
|
Debug.Assert((reader.BytesLeft & 1) == 0);
|
|
return reader.ReadUtf16String((int)(reader.BytesLeft / 2));
|
|
}
|
|
}
|
|
}
|