Xamarin Public Jenkins (auto-signing) 64ac736ec5 Imported Upstream version 6.0.0.172
Former-commit-id: f3cc9b82f3e5bd8f0fd3ebc098f789556b44e9cd
2019-04-12 14:10:50 +00:00

992 lines
31 KiB
C#

//
// 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 {
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)
{
byte [] data = m_root.Streams.BlobHeap.Read (index);
int start;
if ((data [0] & 0x5) > 0) {
MethodRefSig mrs = new MethodRefSig (index);
ReadMethodRefSig (mrs, data, 0, out start);
return mrs;
} else {
MethodDefSig mds = new MethodDefSig (index);
ReadMethodDefSig (mds, data, 0, out start);
return mds;
}
}
public override void VisitMethodDefSig (MethodDefSig methodDef)
{
int start;
ReadMethodDefSig (methodDef, m_root.Streams.BlobHeap.Read (methodDef.BlobIndex), 0, out start);
}
public override void VisitMethodRefSig (MethodRefSig methodRef)
{
int start;
ReadMethodRefSig (methodRef, m_root.Streams.BlobHeap.Read (methodRef.BlobIndex), 0, out start);
}
public override void VisitFieldSig (FieldSig field)
{
int start;
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, out 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 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 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;
}
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;
rt.CustomMods = CombineCustomMods(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;
}
static CustomMod [] CombineCustomMods (CustomMod [] original, CustomMod [] next)
{
if (next == null || next.Length == 0)
return original;
CustomMod [] mods = new CustomMod [original.Length + next.Length];
Array.Copy (original, mods, original.Length);
Array.Copy (next, 0, mods, original.Length, next.Length);
return mods;
}
Param [] ReadParameters (int length, byte [] data, int pos, out int start)
{
Param [] ret = new Param [length];
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 start, out int sentinelpos)
{
Param [] ret = new Param [length];
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;
}
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 = null;
start = pos;
while (true) {
int buf = start;
if (buf >= data.Length - 1)
break;
ElementType flag = (ElementType) Utilities.ReadCompressedInteger (data, start, out start);
start = buf;
if (!((flag == ElementType.CModOpt) || (flag == ElementType.CModReqD)))
break;
if (cmods == null)
cmods = new ArrayList (2);
cmods.Add (ReadCustomMod (data, start, out start));
}
return cmods == null ? CustomMod.EmptyCustomMod : 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 = CustomAttrib.FixedArg.Empty;
ca.NamedArgs = CustomAttrib.NamedArg.Empty;
return ca;
}
bool read = true;
ca.Prolog = br.ReadUInt16 ();
if (ca.Prolog != CustomAttrib.StdProlog)
throw new MetadataFormatException ("Non standard prolog for custom attribute");
if (ctor.HasParameters) {
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);
} else {
ca.FixedArgs = CustomAttrib.FixedArg.Empty;
}
if (br.BaseStream.Position == br.BaseStream.Length)
read = false;
if (!read) {
ca.Read = read;
return ca;
}
ca.NumNamed = br.ReadUInt16 ();
if (ca.NumNamed > 0) {
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);
} else {
ca.NamedArgs = CustomAttrib.NamedArg.Empty;
}
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.Module = m_reflectReader.Module;
t.DeclaringType = decType;
decType = t;
}
decType.Module = m_reflectReader.Module;
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 :
case ElementType.Object:
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);
if (asm != null)
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)
{
MarshalSig ms = new MarshalSig ((NativeType) data[0]);
int start = 1;
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);
}
}
}