// // 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 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; 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; } 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); } */ } }