mirror of https://github.com/icsharpcode/ILSpy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
991 lines
30 KiB
991 lines
30 KiB
// |
|
// SignatureReader.cs |
|
// |
|
// Author: |
|
// Jb Evain (jbevain@gmail.com) |
|
// |
|
// (C) 2005 - 2007 Jb Evain |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining |
|
// a copy of this software and associated documentation files (the |
|
// "Software"), to deal in the Software without restriction, including |
|
// without limitation the rights to use, copy, modify, merge, publish, |
|
// distribute, sublicense, and/or sell copies of the Software, and to |
|
// permit persons to whom the Software is furnished to do so, subject to |
|
// the following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be |
|
// included in all copies or substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
// |
|
|
|
namespace Mono.Cecil.Signatures { |
|
|
|
using System; |
|
using System.Collections; |
|
using System.IO; |
|
using System.Text; |
|
|
|
using Mono.Cecil; |
|
using Mono.Cecil.Metadata; |
|
|
|
internal sealed class SignatureReader : BaseSignatureVisitor { |
|
|
|
byte [] m_blobData; |
|
IDictionary m_signatures; |
|
|
|
public byte[] Blob { |
|
get { |
|
return m_blobData; |
|
} |
|
} |
|
|
|
public SignatureReader (byte [] blobData) |
|
{ |
|
m_blobData = blobData; |
|
m_signatures = new Hashtable (); |
|
} |
|
|
|
/* |
|
|
|
MetadataRoot m_root; |
|
ReflectionReader m_reflectReader; |
|
byte [] m_blobData; |
|
|
|
IDictionary m_signatures; |
|
|
|
IAssemblyResolver AssemblyResolver { |
|
get { return m_reflectReader.Module.Assembly.Resolver; } |
|
} |
|
|
|
public SignatureReader (MetadataRoot root, ReflectionReader reflectReader) |
|
{ |
|
m_root = root; |
|
m_reflectReader = reflectReader; |
|
|
|
m_blobData = m_root.Streams.BlobHeap != null ? m_root.Streams.BlobHeap.Data : new byte [0]; |
|
|
|
m_signatures = new Hashtable (); |
|
} |
|
|
|
*/ |
|
|
|
public FieldSig GetFieldSig (uint index) |
|
{ |
|
FieldSig f = m_signatures [index] as FieldSig; |
|
if (f == null) { |
|
f = new FieldSig (index); |
|
f.Accept (this); |
|
m_signatures [index] = f; |
|
} |
|
return f; |
|
} |
|
|
|
public PropertySig GetPropSig (uint index) |
|
{ |
|
PropertySig p = m_signatures [index] as PropertySig; |
|
if (p == null) { |
|
p = new PropertySig (index); |
|
p.Accept (this); |
|
m_signatures [index] = p; |
|
} |
|
return p; |
|
} |
|
|
|
public MethodDefSig GetMethodDefSig (uint index) |
|
{ |
|
MethodDefSig m = m_signatures [index] as MethodDefSig; |
|
if (m == null) { |
|
m = new MethodDefSig (index); |
|
m.Accept (this); |
|
m_signatures [index] = m; |
|
} |
|
return m; |
|
} |
|
|
|
public MethodRefSig GetMethodRefSig (uint index) |
|
{ |
|
MethodRefSig m = m_signatures [index] as MethodRefSig; |
|
if (m == null) { |
|
m = new MethodRefSig (index); |
|
m.Accept (this); |
|
m_signatures [index] = m; |
|
} |
|
return m; |
|
} |
|
|
|
public TypeSpec GetTypeSpec (uint index) |
|
{ |
|
TypeSpec ts = m_signatures [index] as TypeSpec; |
|
|
|
if (ts == null) { |
|
ts = ReadTypeSpec (m_blobData, (int) index); |
|
m_signatures [index] = ts; |
|
} |
|
|
|
return ts; |
|
} |
|
|
|
public MethodSpec GetMethodSpec (uint index) |
|
{ |
|
MethodSpec ms = m_signatures [index] as MethodSpec; |
|
|
|
if (ms == null) { |
|
ms = ReadMethodSpec (m_blobData, (int) index); |
|
m_signatures [index] = ms; |
|
} |
|
|
|
return ms; |
|
} |
|
|
|
public LocalVarSig GetLocalVarSig (uint index) |
|
{ |
|
LocalVarSig lv = m_signatures [index] as LocalVarSig; |
|
if (lv == null) { |
|
lv = new LocalVarSig (index); |
|
lv.Accept (this); |
|
m_signatures [index] = lv; |
|
} |
|
return lv; |
|
} |
|
|
|
/* |
|
|
|
public CustomAttrib GetCustomAttrib (uint index, MethodReference ctor) |
|
{ |
|
return GetCustomAttrib (index, ctor, false); |
|
} |
|
|
|
public CustomAttrib GetCustomAttrib (uint index, MethodReference ctor, bool resolve) |
|
{ |
|
return ReadCustomAttrib ((int) index, ctor, resolve); |
|
} |
|
|
|
public CustomAttrib GetCustomAttrib (byte [] data, MethodReference ctor) |
|
{ |
|
return GetCustomAttrib (data, ctor, false); |
|
} |
|
|
|
public CustomAttrib GetCustomAttrib (byte [] data, MethodReference ctor, bool resolve) |
|
{ |
|
BinaryReader br = new BinaryReader (new MemoryStream (data)); |
|
return ReadCustomAttrib (br, data, ctor, resolve); |
|
} |
|
|
|
*/ |
|
|
|
public Signature GetMemberRefSig (TokenType tt, uint index) |
|
{ |
|
int start, callconv; |
|
Utilities.ReadCompressedInteger (m_blobData, (int) index, out start); |
|
callconv = m_blobData [start]; |
|
if ((callconv & 0x5) == 0x5 || (callconv & 0x10) == 0x10) // vararg || generic? |
|
return GetMethodDefSig (index); |
|
if ((callconv & 0x6) != 0) // field ? |
|
return GetFieldSig (index); |
|
|
|
switch (tt) { |
|
case TokenType.TypeDef : |
|
case TokenType.TypeRef : |
|
case TokenType.TypeSpec : |
|
return GetMethodRefSig (index); |
|
case TokenType.ModuleRef : |
|
case TokenType.Method : |
|
return GetMethodDefSig (index); |
|
} |
|
return null; |
|
} |
|
|
|
/* |
|
|
|
public MarshalSig GetMarshalSig (uint index) |
|
{ |
|
MarshalSig ms = m_signatures [index] as MarshalSig; |
|
if (ms == null) { |
|
byte [] data = m_root.Streams.BlobHeap.Read (index); |
|
ms = ReadMarshalSig (data); |
|
m_signatures [index] = ms; |
|
} |
|
return ms; |
|
} |
|
|
|
*/ |
|
|
|
public MethodSig GetStandAloneMethodSig (uint index) |
|
{ |
|
int start; |
|
if ((m_blobData [index] & 0x5) > 0) { |
|
MethodRefSig mrs = new MethodRefSig (index); |
|
ReadMethodRefSig (mrs, m_blobData, (int)index, out start); |
|
return mrs; |
|
} else { |
|
MethodDefSig mds = new MethodDefSig (index); |
|
ReadMethodDefSig (mds, m_blobData, (int)index, out start); |
|
return mds; |
|
} |
|
} |
|
|
|
public override void VisitMethodDefSig (MethodDefSig methodDef) |
|
{ |
|
int start; |
|
ReadMethodDefSig (methodDef, m_blobData, (int)methodDef.BlobIndex, out start); |
|
} |
|
|
|
public override void VisitMethodRefSig (MethodRefSig methodRef) |
|
{ |
|
int start; |
|
ReadMethodRefSig (methodRef, m_blobData, (int)methodRef.BlobIndex, out start); |
|
} |
|
|
|
public override void VisitFieldSig (FieldSig field) |
|
{ |
|
int start = 0; |
|
//Utilities.ReadCompressedInteger (m_blobData, (int) field.BlobIndex, out start); |
|
//field.CallingConvention = m_blobData [start]; |
|
field.Field = (field.CallingConvention & 0x6) != 0; |
|
field.CustomMods = ReadCustomMods (m_blobData, start + 1, out start); |
|
field.Type = ReadType (m_blobData, start, out start); |
|
} |
|
|
|
public override void VisitPropertySig (PropertySig property) |
|
{ |
|
int start; |
|
Utilities.ReadCompressedInteger (m_blobData, (int) property.BlobIndex, out start); |
|
property.CallingConvention = m_blobData [start]; |
|
property.Property = (property.CallingConvention & 0x8) != 0; |
|
property.ParamCount = Utilities.ReadCompressedInteger (m_blobData, start + 1, out start); |
|
property.CustomMods = ReadCustomMods (m_blobData, start, out start); |
|
property.Type = ReadType (m_blobData, start, out start); |
|
property.Parameters = ReadParameters (property.ParamCount, m_blobData, start); |
|
} |
|
|
|
public override void VisitLocalVarSig (LocalVarSig localvar) |
|
{ |
|
int start; |
|
Utilities.ReadCompressedInteger (m_blobData, (int) localvar.BlobIndex, out start); |
|
localvar.CallingConvention = m_blobData [start]; |
|
localvar.Local = (localvar.CallingConvention & 0x7) != 0; |
|
localvar.Count = Utilities.ReadCompressedInteger (m_blobData, start + 1, out start); |
|
localvar.LocalVariables = ReadLocalVariables (localvar.Count, m_blobData, start); |
|
} |
|
|
|
void ReadMethodDefSig (MethodDefSig methodDef, byte [] data, int pos, out int start) |
|
{ |
|
methodDef.CallingConvention = data [pos]; |
|
start = pos + 1; |
|
methodDef.HasThis = (methodDef.CallingConvention & 0x20) != 0; |
|
methodDef.ExplicitThis = (methodDef.CallingConvention & 0x40) != 0; |
|
if ((methodDef.CallingConvention & 0x5) != 0) |
|
methodDef.MethCallConv |= MethodCallingConvention.VarArg; |
|
else if ((methodDef.CallingConvention & 0x10) != 0) { |
|
methodDef.MethCallConv |= MethodCallingConvention.Generic; |
|
methodDef.GenericParameterCount = Utilities.ReadCompressedInteger (data, start, out start); |
|
} else |
|
methodDef.MethCallConv |= MethodCallingConvention.Default; |
|
|
|
methodDef.ParamCount = Utilities.ReadCompressedInteger (data, start, out start); |
|
methodDef.RetType = ReadRetType (data, start, out start); |
|
int sentpos; |
|
methodDef.Parameters = ReadParameters (methodDef.ParamCount, data, start, out sentpos); |
|
methodDef.Sentinel = sentpos; |
|
} |
|
|
|
void ReadMethodRefSig (MethodRefSig methodRef, byte [] data, int pos, out int start) |
|
{ |
|
methodRef.CallingConvention = data [pos]; |
|
start = pos + 1; |
|
methodRef.HasThis = (methodRef.CallingConvention & 0x20) != 0; |
|
methodRef.ExplicitThis = (methodRef.CallingConvention & 0x40) != 0; |
|
if ((methodRef.CallingConvention & 0x1) != 0) |
|
methodRef.MethCallConv |= MethodCallingConvention.C; |
|
else if ((methodRef.CallingConvention & 0x2) != 0) |
|
methodRef.MethCallConv |= MethodCallingConvention.StdCall; |
|
else if ((methodRef.CallingConvention & 0x3) != 0) |
|
methodRef.MethCallConv |= MethodCallingConvention.ThisCall; |
|
else if ((methodRef.CallingConvention & 0x4) != 0) |
|
methodRef.MethCallConv |= MethodCallingConvention.FastCall; |
|
else if ((methodRef.CallingConvention & 0x5) != 0) |
|
methodRef.MethCallConv |= MethodCallingConvention.VarArg; |
|
else |
|
methodRef.MethCallConv |= MethodCallingConvention.Default; |
|
methodRef.ParamCount = Utilities.ReadCompressedInteger (data, start, out start); |
|
methodRef.RetType = ReadRetType (data, start, out start); |
|
int sentpos; |
|
methodRef.Parameters = ReadParameters (methodRef.ParamCount, data, start, out sentpos); |
|
methodRef.Sentinel = sentpos; |
|
} |
|
|
|
LocalVarSig.LocalVariable [] ReadLocalVariables (int length, byte [] data, int pos) |
|
{ |
|
int start = pos; |
|
LocalVarSig.LocalVariable [] types = new LocalVarSig.LocalVariable [length]; |
|
for (int i = 0; i < length; i++) |
|
types [i] = ReadLocalVariable (data, start, out start); |
|
return types; |
|
} |
|
|
|
public LocalVarSig.LocalVariable ReadLocalVariable (byte [] data, int pos, out int start) |
|
{ |
|
start = pos; |
|
LocalVarSig.LocalVariable lv = new LocalVarSig.LocalVariable (); |
|
lv.ByRef = false; |
|
int cursor; |
|
while (true) { |
|
lv.CustomMods = ReadCustomMods (data, start, out start); |
|
cursor = start; |
|
int current = Utilities.ReadCompressedInteger (data, start, out start); |
|
if (current == (int) ElementType.Pinned) // the only possible constraint |
|
lv.Constraint |= Constraint.Pinned; |
|
else if (current == (int) ElementType.ByRef) { |
|
lv.ByRef = true; |
|
|
|
if (lv.CustomMods == null || lv.CustomMods.Length == 0) |
|
lv.CustomMods = ReadCustomMods (data, start, out start); |
|
} else { |
|
lv.Type = ReadType (data, cursor, out start); |
|
break; |
|
} |
|
} |
|
return lv; |
|
} |
|
|
|
TypeSpec ReadTypeSpec (byte [] data, int pos) |
|
{ |
|
int start = pos; |
|
Utilities.ReadCompressedInteger (data, start, out start); |
|
TypeSpec ts = new TypeSpec (); |
|
ts.CustomMods = ReadCustomMods (data, start, out start); |
|
ts.Type = ReadType (data, start, out start); |
|
return ts; |
|
} |
|
|
|
MethodSpec ReadMethodSpec (byte [] data, int pos) |
|
{ |
|
int start = pos; |
|
|
|
Utilities.ReadCompressedInteger (data, start, out start); |
|
if (Utilities.ReadCompressedInteger (data, start, out start) != 0x0a) |
|
throw new ReflectionException ("Invalid MethodSpec signature"); |
|
|
|
return new MethodSpec (ReadGenericInstSignature (data, start, out start)); |
|
} |
|
|
|
RetType ReadRetType (byte [] data, int pos, out int start) |
|
{ |
|
RetType rt = new RetType (); |
|
start = pos; |
|
rt.CustomMods = ReadCustomMods (data, start, out start); |
|
int curs = start; |
|
ElementType flag = (ElementType) Utilities.ReadCompressedInteger (data, start, out start); |
|
switch (flag) { |
|
case ElementType.Void : |
|
rt.ByRef = rt.TypedByRef = false; |
|
rt.Void = true; |
|
break; |
|
case ElementType.TypedByRef : |
|
rt.ByRef = rt.Void = false; |
|
rt.TypedByRef = true; |
|
break; |
|
case ElementType.ByRef : |
|
rt.TypedByRef = rt.Void = false; |
|
rt.ByRef = true; |
|
|
|
if (rt.CustomMods == null || rt.CustomMods.Length == 0) |
|
rt.CustomMods = ReadCustomMods (data, start, out start); |
|
|
|
rt.Type = ReadType (data, start, out start); |
|
break; |
|
default : |
|
rt.TypedByRef = rt.Void = rt.ByRef = false; |
|
rt.Type = ReadType (data, curs, out start); |
|
break; |
|
} |
|
return rt; |
|
} |
|
|
|
Param [] ReadParameters (int length, byte [] data, int pos) |
|
{ |
|
Param [] ret = new Param [length]; |
|
int start = pos; |
|
for (int i = 0; i < length; i++) |
|
ret [i] = ReadParameter (data, start, out start); |
|
return ret; |
|
} |
|
|
|
Param [] ReadParameters (int length, byte [] data, int pos, out int sentinelpos) |
|
{ |
|
Param [] ret = new Param [length]; |
|
int start = pos; |
|
sentinelpos = -1; |
|
|
|
for (int i = 0; i < length; i++) { |
|
int curs = start; |
|
int flag = Utilities.ReadCompressedInteger (data, start, out start); |
|
|
|
if (flag == (int) ElementType.Sentinel) { |
|
sentinelpos = i; |
|
curs = start; |
|
} |
|
|
|
ret [i] = ReadParameter (data, curs, out start); |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
Param ReadParameter (byte [] data, int pos, out int start) |
|
{ |
|
Param p = new Param (); |
|
start = pos; |
|
|
|
p.CustomMods = ReadCustomMods (data, start, out start); |
|
int curs = start; |
|
ElementType flag = (ElementType) Utilities.ReadCompressedInteger (data, start, out start); |
|
switch (flag) { |
|
case ElementType.TypedByRef : |
|
p.TypedByRef = true; |
|
p.ByRef = false; |
|
break; |
|
case ElementType.ByRef : |
|
p.TypedByRef = false; |
|
p.ByRef = true; |
|
|
|
if (p.CustomMods == null || p.CustomMods.Length == 0) |
|
p.CustomMods = ReadCustomMods (data, start, out start); |
|
|
|
p.Type = ReadType (data, start, out start); |
|
break; |
|
default : |
|
p.TypedByRef = false; |
|
p.ByRef = false; |
|
p.Type = ReadType (data, curs, out start); |
|
break; |
|
} |
|
return p; |
|
} |
|
|
|
public SigType ReadType (byte [] data, int pos, out int start) |
|
{ |
|
start = pos; |
|
ElementType element = (ElementType) Utilities.ReadCompressedInteger (data, start, out start); |
|
switch (element) { |
|
case ElementType.ValueType : |
|
VALUETYPE vt = new VALUETYPE (); |
|
vt.Type = Utilities.GetMetadataToken(CodedIndex.TypeDefOrRef, |
|
(uint) Utilities.ReadCompressedInteger (data, start, out start)); |
|
return vt; |
|
case ElementType.Class : |
|
CLASS c = new CLASS (); |
|
c.Type = Utilities.GetMetadataToken (CodedIndex.TypeDefOrRef, |
|
(uint) Utilities.ReadCompressedInteger (data, start, out start)); |
|
return c; |
|
case ElementType.Ptr : |
|
PTR p = new PTR (); |
|
int buf = start; |
|
int flag = Utilities.ReadCompressedInteger (data, start, out start); |
|
p.Void = flag == (int) ElementType.Void; |
|
if (p.Void) |
|
return p; |
|
start = buf; |
|
p.CustomMods = ReadCustomMods (data, start, out start); |
|
p.PtrType = ReadType (data, start, out start); |
|
return p; |
|
case ElementType.FnPtr : |
|
FNPTR fp = new FNPTR (); |
|
if ((data [start] & 0x5) != 0) { |
|
MethodRefSig mr = new MethodRefSig ((uint) start); |
|
ReadMethodRefSig (mr, data, start, out start); |
|
fp.Method = mr; |
|
} else { |
|
MethodDefSig md = new MethodDefSig ((uint) start); |
|
ReadMethodDefSig (md, data, start, out start); |
|
fp.Method = md; |
|
} |
|
return fp; |
|
case ElementType.Array : |
|
ARRAY ary = new ARRAY (); |
|
ary.CustomMods = ReadCustomMods (data, start, out start); |
|
ArrayShape shape = new ArrayShape (); |
|
ary.Type = ReadType (data, start, out start); |
|
shape.Rank = Utilities.ReadCompressedInteger (data, start, out start); |
|
shape.NumSizes = Utilities.ReadCompressedInteger (data, start, out start); |
|
shape.Sizes = new int [shape.NumSizes]; |
|
for (int i = 0; i < shape.NumSizes; i++) |
|
shape.Sizes [i] = Utilities.ReadCompressedInteger (data, start, out start); |
|
shape.NumLoBounds = Utilities.ReadCompressedInteger (data, start, out start); |
|
shape.LoBounds = new int [shape.NumLoBounds]; |
|
for (int i = 0; i < shape.NumLoBounds; i++) |
|
shape.LoBounds [i] = Utilities.ReadCompressedInteger (data, start, out start); |
|
ary.Shape = shape; |
|
return ary; |
|
case ElementType.SzArray : |
|
SZARRAY sa = new SZARRAY (); |
|
sa.CustomMods = ReadCustomMods (data, start, out start); |
|
sa.Type = ReadType (data, start, out start); |
|
return sa; |
|
case ElementType.Var: |
|
return new VAR (Utilities.ReadCompressedInteger (data, start, out start)); |
|
case ElementType.MVar: |
|
return new MVAR (Utilities.ReadCompressedInteger (data, start, out start)); |
|
case ElementType.GenericInst: |
|
GENERICINST ginst = new GENERICINST (); |
|
|
|
ginst.ValueType = ((ElementType) Utilities.ReadCompressedInteger ( |
|
data, start, out start)) == ElementType.ValueType; |
|
|
|
ginst.Type = Utilities.GetMetadataToken (CodedIndex.TypeDefOrRef, |
|
(uint) Utilities.ReadCompressedInteger (data, start, out start)); |
|
|
|
ginst.Signature = ReadGenericInstSignature (data, start, out start); |
|
|
|
return ginst; |
|
default : |
|
return new SigType (element); |
|
} |
|
} |
|
|
|
GenericInstSignature ReadGenericInstSignature (byte [] data, int pos, out int start) |
|
{ |
|
start = pos; |
|
GenericInstSignature gis = new GenericInstSignature (); |
|
gis.Arity = Utilities.ReadCompressedInteger (data, start, out start); |
|
gis.Types = new GenericArg [gis.Arity]; |
|
for (int i = 0; i < gis.Arity; i++) |
|
gis.Types [i] = ReadGenericArg (data, start, out start); |
|
|
|
return gis; |
|
} |
|
|
|
GenericArg ReadGenericArg (byte[] data, int pos, out int start) |
|
{ |
|
start = pos; |
|
CustomMod [] mods = ReadCustomMods (data, start, out start); |
|
GenericArg arg = new GenericArg (ReadType (data, start, out start)); |
|
arg.CustomMods = mods; |
|
return arg; |
|
} |
|
|
|
CustomMod [] ReadCustomMods (byte [] data, int pos, out int start) |
|
{ |
|
ArrayList cmods = new ArrayList (); |
|
start = pos; |
|
while (true) { |
|
int buf = start; |
|
ElementType flag = (ElementType) Utilities.ReadCompressedInteger (data, start, out start); |
|
start = buf; |
|
if (!((flag == ElementType.CModOpt) || (flag == ElementType.CModReqD))) |
|
break; |
|
cmods.Add (ReadCustomMod (data, start, out start)); |
|
} |
|
return cmods.ToArray (typeof (CustomMod)) as CustomMod []; |
|
} |
|
|
|
CustomMod ReadCustomMod (byte [] data, int pos, out int start) |
|
{ |
|
CustomMod cm = new CustomMod (); |
|
start = pos; |
|
ElementType cmod = (ElementType) Utilities.ReadCompressedInteger (data, start, out start); |
|
if (cmod == ElementType.CModOpt) |
|
cm.CMOD = CustomMod.CMODType.OPT; |
|
else if (cmod == ElementType.CModReqD) |
|
cm.CMOD = CustomMod.CMODType.REQD; |
|
else |
|
cm.CMOD = CustomMod.CMODType.None; |
|
cm.TypeDefOrRef = Utilities.GetMetadataToken (CodedIndex.TypeDefOrRef, |
|
(uint) Utilities.ReadCompressedInteger (data, start, out start)); |
|
return cm; |
|
} |
|
|
|
/* |
|
|
|
CustomAttrib ReadCustomAttrib (int pos, MethodReference ctor, bool resolve) |
|
{ |
|
int start, length = Utilities.ReadCompressedInteger (m_blobData, pos, out start); |
|
byte [] data = new byte [length]; |
|
Buffer.BlockCopy (m_blobData, start, data, 0, length); |
|
try { |
|
return ReadCustomAttrib (new BinaryReader ( |
|
new MemoryStream (data)), data, ctor, resolve); |
|
} catch { |
|
CustomAttrib ca = new CustomAttrib (ctor); |
|
ca.Read = false; |
|
return ca; |
|
} |
|
} |
|
|
|
CustomAttrib ReadCustomAttrib (BinaryReader br, byte [] data, MethodReference ctor, bool resolve) |
|
{ |
|
CustomAttrib ca = new CustomAttrib (ctor); |
|
if (data.Length == 0) { |
|
ca.FixedArgs = new CustomAttrib.FixedArg [0]; |
|
ca.NamedArgs = new CustomAttrib.NamedArg [0]; |
|
return ca; |
|
} |
|
|
|
bool read = true; |
|
|
|
ca.Prolog = br.ReadUInt16 (); |
|
if (ca.Prolog != CustomAttrib.StdProlog) |
|
throw new MetadataFormatException ("Non standard prolog for custom attribute"); |
|
|
|
ca.FixedArgs = new CustomAttrib.FixedArg [ctor.Parameters.Count]; |
|
for (int i = 0; i < ca.FixedArgs.Length && read; i++) |
|
ca.FixedArgs [i] = ReadFixedArg (data, br, |
|
ctor.Parameters [i].ParameterType, ref read, resolve); |
|
|
|
if (br.BaseStream.Position == br.BaseStream.Length) |
|
read = false; |
|
|
|
if (!read) { |
|
ca.Read = read; |
|
return ca; |
|
} |
|
|
|
ca.NumNamed = br.ReadUInt16 (); |
|
ca.NamedArgs = new CustomAttrib.NamedArg [ca.NumNamed]; |
|
for (int i = 0; i < ca.NumNamed && read; i++) |
|
ca.NamedArgs [i] = ReadNamedArg (data, br, ref read, resolve); |
|
|
|
ca.Read = read; |
|
return ca; |
|
} |
|
|
|
CustomAttrib.FixedArg ReadFixedArg (byte [] data, BinaryReader br, |
|
TypeReference param, ref bool read, bool resolve) |
|
{ |
|
CustomAttrib.FixedArg fa = new CustomAttrib.FixedArg (); |
|
if (param is ArrayType) { |
|
param = ((ArrayType) param).ElementType; |
|
fa.SzArray = true; |
|
fa.NumElem = br.ReadUInt32 (); |
|
|
|
if (fa.NumElem == 0 || fa.NumElem == 0xffffffff) { |
|
fa.Elems = new CustomAttrib.Elem [0]; |
|
fa.NumElem = 0; |
|
return fa; |
|
} |
|
|
|
fa.Elems = new CustomAttrib.Elem [fa.NumElem]; |
|
for (int i = 0; i < fa.NumElem; i++) |
|
fa.Elems [i] = ReadElem (data, br, param, ref read, resolve); |
|
} else |
|
fa.Elems = new CustomAttrib.Elem [] { ReadElem (data, br, param, ref read, resolve) }; |
|
|
|
return fa; |
|
} |
|
|
|
TypeReference CreateEnumTypeReference (string enumName) |
|
{ |
|
string asmName = null; |
|
int asmStart = enumName.IndexOf (','); |
|
if (asmStart != -1) { |
|
asmName = enumName.Substring (asmStart + 1); |
|
enumName = enumName.Substring (0, asmStart); |
|
} |
|
// Inner class style is reflection style. |
|
enumName = enumName.Replace ('+', '/'); |
|
AssemblyNameReference asm; |
|
if (asmName == null) { |
|
// If no assembly is given then the ECMA standard says the |
|
// assembly is either the current one or mscorlib. |
|
if (m_reflectReader.Module.Types.Contains (enumName)) |
|
return m_reflectReader.Module.Types [enumName]; |
|
|
|
asm = m_reflectReader.Corlib; |
|
} else |
|
asm = AssemblyNameReference.Parse (asmName); |
|
|
|
string [] outers = enumName.Split ('/'); |
|
string outerfullname = outers [0]; |
|
string ns = null; |
|
int nsIndex = outerfullname.LastIndexOf ('.'); |
|
if (nsIndex != -1) |
|
ns = outerfullname.Substring (0, nsIndex); |
|
string name = outerfullname.Substring (nsIndex + 1); |
|
TypeReference decType = new TypeReference (name, ns, asm); |
|
for (int i = 1; i < outers.Length; i++) { |
|
TypeReference t = new TypeReference (outers [i], null, asm); |
|
t.DeclaringType = decType; |
|
decType = t; |
|
} |
|
decType.IsValueType = true; |
|
|
|
return decType; |
|
} |
|
|
|
TypeReference ReadTypeReference (byte [] data, BinaryReader br, out ElementType elemType) |
|
{ |
|
bool array = false; |
|
elemType = (ElementType) br.ReadByte (); |
|
if (elemType == ElementType.SzArray) { |
|
elemType = (ElementType) br.ReadByte (); |
|
array = true; |
|
} |
|
|
|
TypeReference res; |
|
if (elemType == ElementType.Enum) |
|
res = CreateEnumTypeReference (ReadUTF8String (data, br)); |
|
else |
|
res = TypeReferenceFromElemType (elemType); |
|
|
|
if (array) |
|
res = new ArrayType (res); |
|
|
|
return res; |
|
} |
|
|
|
TypeReference TypeReferenceFromElemType (ElementType elemType) |
|
{ |
|
switch (elemType) { |
|
case ElementType.Boxed : |
|
return m_reflectReader.SearchCoreType (Constants.Object); |
|
case ElementType.String : |
|
return m_reflectReader.SearchCoreType (Constants.String); |
|
case ElementType.Type : |
|
return m_reflectReader.SearchCoreType (Constants.Type); |
|
case ElementType.Boolean : |
|
return m_reflectReader.SearchCoreType (Constants.Boolean); |
|
case ElementType.Char : |
|
return m_reflectReader.SearchCoreType (Constants.Char); |
|
case ElementType.R4 : |
|
return m_reflectReader.SearchCoreType (Constants.Single); |
|
case ElementType.R8 : |
|
return m_reflectReader.SearchCoreType (Constants.Double); |
|
case ElementType.I1 : |
|
return m_reflectReader.SearchCoreType (Constants.SByte); |
|
case ElementType.I2 : |
|
return m_reflectReader.SearchCoreType (Constants.Int16); |
|
case ElementType.I4 : |
|
return m_reflectReader.SearchCoreType (Constants.Int32); |
|
case ElementType.I8 : |
|
return m_reflectReader.SearchCoreType (Constants.Int64); |
|
case ElementType.U1 : |
|
return m_reflectReader.SearchCoreType (Constants.Byte); |
|
case ElementType.U2 : |
|
return m_reflectReader.SearchCoreType (Constants.UInt16); |
|
case ElementType.U4 : |
|
return m_reflectReader.SearchCoreType (Constants.UInt32); |
|
case ElementType.U8 : |
|
return m_reflectReader.SearchCoreType (Constants.UInt64); |
|
default : |
|
throw new MetadataFormatException ("Non valid type in CustomAttrib.Elem: 0x{0}", |
|
((byte) elemType).ToString("x2")); |
|
} |
|
} |
|
|
|
internal CustomAttrib.NamedArg ReadNamedArg (byte [] data, BinaryReader br, ref bool read, bool resolve) |
|
{ |
|
CustomAttrib.NamedArg na = new CustomAttrib.NamedArg (); |
|
byte kind = br.ReadByte (); |
|
if (kind == 0x53) { // field |
|
na.Field = true; |
|
na.Property = false; |
|
} else if (kind == 0x54) { // property |
|
na.Field = false; |
|
na.Property = true; |
|
} else |
|
throw new MetadataFormatException ("Wrong kind of namedarg found: 0x" + kind.ToString("x2")); |
|
|
|
TypeReference elemType = ReadTypeReference (data, br, out na.FieldOrPropType); |
|
na.FieldOrPropName = ReadUTF8String (data, br); |
|
na.FixedArg = ReadFixedArg (data, br, elemType, ref read, resolve); |
|
|
|
return na; |
|
} |
|
|
|
CustomAttrib.Elem ReadElem (byte [] data, BinaryReader br, TypeReference elemType, ref bool read, bool resolve) |
|
{ |
|
CustomAttrib.Elem elem = new CustomAttrib.Elem (); |
|
|
|
string elemName = elemType.FullName; |
|
|
|
if (elemName == Constants.Object) { |
|
elemType = ReadTypeReference (data, br, out elem.FieldOrPropType); |
|
if (elemType is ArrayType) { |
|
read = false; // Don't know how to represent arrays as an object value. |
|
return elem; |
|
} else if (elemType.FullName == Constants.Object) |
|
throw new MetadataFormatException ("Non valid type in CustomAttrib.Elem after boxed prefix: 0x{0}", |
|
((byte) elem.FieldOrPropType).ToString("x2")); |
|
|
|
elem = ReadElem (data, br, elemType, ref read, resolve); |
|
elem.String = elem.Simple = elem.Type = false; |
|
elem.BoxedValueType = true; |
|
return elem; |
|
} |
|
|
|
elem.ElemType = elemType; |
|
|
|
if (elemName == Constants.Type || elemName == Constants.String) { |
|
switch (elemType.FullName) { |
|
case Constants.String: |
|
elem.String = true; |
|
elem.BoxedValueType = elem.Simple = elem.Type = false; |
|
break; |
|
case Constants.Type: |
|
elem.Type = true; |
|
elem.BoxedValueType = elem.Simple = elem.String = false; |
|
break; |
|
} |
|
|
|
if (data [br.BaseStream.Position] == 0xff) { // null |
|
elem.Value = null; |
|
br.BaseStream.Position++; |
|
} else { |
|
elem.Value = ReadUTF8String (data, br); |
|
} |
|
return elem; |
|
} |
|
|
|
elem.String = elem.Type = elem.BoxedValueType = false; |
|
if (!ReadSimpleValue (br, ref elem, elem.ElemType)) { |
|
if (!resolve) { // until enums writing is implemented |
|
read = false; |
|
return elem; |
|
} |
|
TypeReference typeRef = GetEnumUnderlyingType (elem.ElemType, resolve); |
|
if (typeRef == null || !ReadSimpleValue (br, ref elem, typeRef)) |
|
read = false; |
|
} |
|
|
|
return elem; |
|
} |
|
|
|
TypeReference GetEnumUnderlyingType (TypeReference enumType, bool resolve) |
|
{ |
|
TypeDefinition type = enumType as TypeDefinition; |
|
if (type == null && resolve && AssemblyResolver != null) { |
|
if (enumType.Scope is ModuleDefinition) |
|
throw new NotSupportedException (); |
|
|
|
AssemblyDefinition asm = AssemblyResolver.Resolve ( |
|
((AssemblyNameReference) enumType.Scope).FullName); |
|
type = asm.MainModule.Types [enumType.FullName]; |
|
} |
|
|
|
if (type != null && type.IsEnum) |
|
return type.Fields.GetField ("value__").FieldType; |
|
|
|
return null; |
|
} |
|
|
|
bool ReadSimpleValue (BinaryReader br, ref CustomAttrib.Elem elem, TypeReference type) |
|
{ |
|
switch (type.FullName) { |
|
case Constants.Boolean : |
|
elem.Value = br.ReadByte () == 1; |
|
break; |
|
case Constants.Char : |
|
elem.Value = (char) br.ReadUInt16 (); |
|
break; |
|
case Constants.Single : |
|
elem.Value = br.ReadSingle (); |
|
break; |
|
case Constants.Double : |
|
elem.Value = br.ReadDouble (); |
|
break; |
|
case Constants.Byte : |
|
elem.Value = br.ReadByte (); |
|
break; |
|
case Constants.Int16 : |
|
elem.Value = br.ReadInt16 (); |
|
break; |
|
case Constants.Int32 : |
|
elem.Value = br.ReadInt32 (); |
|
break; |
|
case Constants.Int64 : |
|
elem.Value = br.ReadInt64 (); |
|
break; |
|
case Constants.SByte : |
|
elem.Value = br.ReadSByte (); |
|
break; |
|
case Constants.UInt16 : |
|
elem.Value = br.ReadUInt16 (); |
|
break; |
|
case Constants.UInt32 : |
|
elem.Value = br.ReadUInt32 (); |
|
break; |
|
case Constants.UInt64 : |
|
elem.Value = br.ReadUInt64 (); |
|
break; |
|
default : // enum |
|
return false; |
|
} |
|
elem.Simple = true; |
|
return true; |
|
} |
|
|
|
MarshalSig ReadMarshalSig (byte [] data) |
|
{ |
|
int start; |
|
MarshalSig ms = new MarshalSig ((NativeType) Utilities.ReadCompressedInteger (data, 0, out start)); |
|
switch (ms.NativeInstrinsic) { |
|
case NativeType.ARRAY: |
|
MarshalSig.Array ar = new MarshalSig.Array (); |
|
ar.ArrayElemType = (NativeType) Utilities.ReadCompressedInteger (data, start, out start); |
|
if (start < data.Length) |
|
ar.ParamNum = Utilities.ReadCompressedInteger (data, start, out start); |
|
if (start < data.Length) |
|
ar.NumElem = Utilities.ReadCompressedInteger (data, start, out start); |
|
if (start < data.Length) |
|
ar.ElemMult = Utilities.ReadCompressedInteger (data, start, out start); |
|
ms.Spec = ar; |
|
break; |
|
case NativeType.CUSTOMMARSHALER: |
|
MarshalSig.CustomMarshaler cm = new MarshalSig.CustomMarshaler (); |
|
cm.Guid = ReadUTF8String (data, start, out start); |
|
cm.UnmanagedType = ReadUTF8String (data, start, out start); |
|
cm.ManagedType = ReadUTF8String (data, start, out start); |
|
cm.Cookie = ReadUTF8String (data, start, out start); |
|
ms.Spec = cm; |
|
break; |
|
case NativeType.FIXEDARRAY: |
|
MarshalSig.FixedArray fa = new MarshalSig.FixedArray (); |
|
fa.NumElem = Utilities.ReadCompressedInteger (data, start, out start); |
|
if (start < data.Length) |
|
fa.ArrayElemType = (NativeType) Utilities.ReadCompressedInteger (data, start, out start); |
|
ms.Spec = fa; |
|
break; |
|
case NativeType.SAFEARRAY: |
|
MarshalSig.SafeArray sa = new MarshalSig.SafeArray (); |
|
if (start < data.Length) |
|
sa.ArrayElemType = (VariantType) Utilities.ReadCompressedInteger (data, start, out start); |
|
ms.Spec = sa; |
|
break; |
|
case NativeType.FIXEDSYSSTRING: |
|
MarshalSig.FixedSysString fss = new MarshalSig.FixedSysString (); |
|
if (start < data.Length) |
|
fss.Size = Utilities.ReadCompressedInteger (data, start, out start); |
|
ms.Spec = fss; |
|
break; |
|
} |
|
return ms; |
|
} |
|
|
|
static internal string ReadUTF8String (byte [] data, BinaryReader br) |
|
{ |
|
int start = (int)br.BaseStream.Position; |
|
string val = ReadUTF8String (data, start, out start); |
|
br.BaseStream.Position = start; |
|
return val; |
|
} |
|
|
|
static internal string ReadUTF8String (byte [] data, int pos, out int start) |
|
{ |
|
int length = Utilities.ReadCompressedInteger (data, pos, out start); |
|
pos = start; |
|
start += length; |
|
// COMPACT FRAMEWORK NOTE: Encoding.GetString (byte[]) is not supported. |
|
return Encoding.UTF8.GetString (data, pos, length); |
|
} |
|
|
|
*/ |
|
} |
|
}
|
|
|