PageRenderTime 72ms CodeModel.GetById 18ms app.highlight 46ms RepoModel.GetById 1ms app.codeStats 0ms

/Debugger/Debugger.Core/Mono.Cecil/Mono.Cecil.Signatures/SignatureReader.cs

http://github.com/icsharpcode/ILSpy
C# | 991 lines | 454 code | 63 blank | 474 comment | 97 complexity | 42ab2afe5f40cd946f689309eb8cc2ed MD5 | raw file
  1//
  2// SignatureReader.cs
  3//
  4// Author:
  5//   Jb Evain (jbevain@gmail.com)
  6//
  7// (C) 2005 - 2007 Jb Evain
  8//
  9// Permission is hereby granted, free of charge, to any person obtaining
 10// a copy of this software and associated documentation files (the
 11// "Software"), to deal in the Software without restriction, including
 12// without limitation the rights to use, copy, modify, merge, publish,
 13// distribute, sublicense, and/or sell copies of the Software, and to
 14// permit persons to whom the Software is furnished to do so, subject to
 15// the following conditions:
 16//
 17// The above copyright notice and this permission notice shall be
 18// included in all copies or substantial portions of the Software.
 19//
 20// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 21// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 22// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 23// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 24// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 25// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 26// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 27//
 28
 29namespace Mono.Cecil.Signatures {
 30
 31	using System;
 32	using System.Collections;
 33	using System.IO;
 34	using System.Text;
 35
 36	using Mono.Cecil;
 37	using Mono.Cecil.Metadata;
 38
 39	internal sealed class SignatureReader : BaseSignatureVisitor {
 40
 41		byte [] m_blobData;
 42		IDictionary m_signatures;
 43		
 44		public byte[] Blob {
 45			get {
 46				return m_blobData;
 47			}
 48		}
 49		
 50		public SignatureReader (byte [] blobData)
 51		{
 52			m_blobData = blobData;
 53			m_signatures = new Hashtable ();
 54		}
 55		
 56		/*
 57		
 58		MetadataRoot m_root;
 59		ReflectionReader m_reflectReader;
 60		byte [] m_blobData;
 61
 62		IDictionary m_signatures;
 63
 64		IAssemblyResolver AssemblyResolver {
 65			get { return m_reflectReader.Module.Assembly.Resolver; }
 66		}
 67
 68		public SignatureReader (MetadataRoot root, ReflectionReader reflectReader)
 69		{
 70			m_root = root;
 71			m_reflectReader = reflectReader;
 72
 73			m_blobData = m_root.Streams.BlobHeap != null ? m_root.Streams.BlobHeap.Data : new byte [0];
 74
 75			m_signatures = new Hashtable ();
 76		}
 77		
 78		*/
 79
 80		public FieldSig GetFieldSig (uint index)
 81		{
 82			FieldSig f = m_signatures [index] as FieldSig;
 83			if (f == null) {
 84				f = new FieldSig (index);
 85				f.Accept (this);
 86				m_signatures [index] = f;
 87			}
 88			return f;
 89		}
 90
 91		public PropertySig GetPropSig (uint index)
 92		{
 93			PropertySig p = m_signatures [index] as PropertySig;
 94			if (p == null) {
 95				p = new PropertySig (index);
 96				p.Accept (this);
 97				m_signatures [index] = p;
 98			}
 99			return p;
100		}
101
102		public MethodDefSig GetMethodDefSig (uint index)
103		{
104			MethodDefSig m = m_signatures [index] as MethodDefSig;
105			if (m == null) {
106				m = new MethodDefSig (index);
107				m.Accept (this);
108				m_signatures [index] = m;
109			}
110			return m;
111		}
112
113		public MethodRefSig GetMethodRefSig (uint index)
114		{
115			MethodRefSig m = m_signatures [index] as MethodRefSig;
116			if (m == null) {
117				m = new MethodRefSig (index);
118				m.Accept (this);
119				m_signatures [index] = m;
120			}
121			return m;
122		}
123
124		public TypeSpec GetTypeSpec (uint index)
125		{
126			TypeSpec ts = m_signatures [index] as TypeSpec;
127
128			if (ts == null) {
129				ts = ReadTypeSpec (m_blobData, (int) index);
130				m_signatures [index] = ts;
131			}
132
133			return ts;
134		}
135
136		public MethodSpec GetMethodSpec (uint index)
137		{
138			MethodSpec ms = m_signatures [index] as MethodSpec;
139
140			if (ms == null) {
141				ms = ReadMethodSpec (m_blobData, (int) index);
142				m_signatures [index] = ms;
143			}
144
145			return ms;
146		}
147
148		public LocalVarSig GetLocalVarSig (uint index)
149		{
150			LocalVarSig lv = m_signatures [index] as LocalVarSig;
151			if (lv == null) {
152				lv = new LocalVarSig (index);
153				lv.Accept (this);
154				m_signatures [index] = lv;
155			}
156			return lv;
157		}
158		
159		/*
160
161		public CustomAttrib GetCustomAttrib (uint index, MethodReference ctor)
162		{
163			return GetCustomAttrib (index, ctor, false);
164		}
165
166		public CustomAttrib GetCustomAttrib (uint index, MethodReference ctor, bool resolve)
167		{
168			return ReadCustomAttrib ((int) index, ctor, resolve);
169		}
170
171		public CustomAttrib GetCustomAttrib (byte [] data, MethodReference ctor)
172		{
173			return GetCustomAttrib (data, ctor, false);
174		}
175
176		public CustomAttrib GetCustomAttrib (byte [] data, MethodReference ctor, bool resolve)
177		{
178			BinaryReader br = new BinaryReader (new MemoryStream (data));
179			return ReadCustomAttrib (br, data, ctor, resolve);
180		}
181		
182		*/
183
184		public Signature GetMemberRefSig (TokenType tt, uint index)
185		{
186			int start, callconv;
187			Utilities.ReadCompressedInteger (m_blobData, (int) index, out start);
188			callconv = m_blobData [start];
189			if ((callconv & 0x5) == 0x5 || (callconv & 0x10) == 0x10) // vararg || generic?
190				return GetMethodDefSig (index);
191			if ((callconv & 0x6) != 0) // field ?
192				return GetFieldSig (index);
193
194			switch (tt) {
195			case TokenType.TypeDef :
196			case TokenType.TypeRef :
197			case TokenType.TypeSpec :
198				return GetMethodRefSig (index);
199			case TokenType.ModuleRef :
200			case TokenType.Method :
201				return GetMethodDefSig (index);
202			}
203			return null;
204		}
205		
206		/*
207
208		public MarshalSig GetMarshalSig (uint index)
209		{
210			MarshalSig ms = m_signatures [index] as MarshalSig;
211			if (ms == null) {
212				byte [] data = m_root.Streams.BlobHeap.Read (index);
213				ms = ReadMarshalSig (data);
214				m_signatures [index] = ms;
215			}
216			return ms;
217		}
218		
219		*/
220
221		public MethodSig GetStandAloneMethodSig (uint index)
222		{
223			int start;
224			if ((m_blobData [index] & 0x5) > 0) {
225				MethodRefSig mrs = new MethodRefSig (index);
226				ReadMethodRefSig (mrs, m_blobData, (int)index, out start);
227				return mrs;
228			} else {
229				MethodDefSig mds = new MethodDefSig (index);
230				ReadMethodDefSig (mds, m_blobData, (int)index, out start);
231				return mds;
232			}
233		}
234
235		public override void VisitMethodDefSig (MethodDefSig methodDef)
236		{
237			int start;
238			ReadMethodDefSig (methodDef, m_blobData, (int)methodDef.BlobIndex, out start);
239		}
240
241		public override void VisitMethodRefSig (MethodRefSig methodRef)
242		{
243			int start;
244			ReadMethodRefSig (methodRef, m_blobData, (int)methodRef.BlobIndex, out start);
245		}
246
247		public override void VisitFieldSig (FieldSig field)
248		{
249			int start = 0;
250			//Utilities.ReadCompressedInteger (m_blobData, (int) field.BlobIndex, out start);
251			//field.CallingConvention = m_blobData [start];
252			field.Field = (field.CallingConvention & 0x6) != 0;
253			field.CustomMods = ReadCustomMods (m_blobData, start + 1, out start);
254			field.Type = ReadType (m_blobData, start, out start);
255		}
256
257		public override void VisitPropertySig (PropertySig property)
258		{
259			int start;
260			Utilities.ReadCompressedInteger (m_blobData, (int) property.BlobIndex, out start);
261			property.CallingConvention = m_blobData [start];
262			property.Property = (property.CallingConvention & 0x8) != 0;
263			property.ParamCount = Utilities.ReadCompressedInteger (m_blobData, start + 1, out start);
264			property.CustomMods = ReadCustomMods (m_blobData, start, out start);
265			property.Type = ReadType (m_blobData, start, out start);
266			property.Parameters = ReadParameters (property.ParamCount, m_blobData, start);
267		}
268
269		public override void VisitLocalVarSig (LocalVarSig localvar)
270		{
271			int start;
272			Utilities.ReadCompressedInteger (m_blobData, (int) localvar.BlobIndex, out start);
273			localvar.CallingConvention = m_blobData [start];
274			localvar.Local = (localvar.CallingConvention & 0x7) != 0;
275			localvar.Count = Utilities.ReadCompressedInteger (m_blobData, start + 1, out start);
276			localvar.LocalVariables = ReadLocalVariables (localvar.Count, m_blobData, start);
277		}
278
279		void ReadMethodDefSig (MethodDefSig methodDef, byte [] data, int pos, out int start)
280		{
281			methodDef.CallingConvention = data [pos];
282			start = pos + 1;
283			methodDef.HasThis = (methodDef.CallingConvention & 0x20) != 0;
284			methodDef.ExplicitThis = (methodDef.CallingConvention & 0x40) != 0;
285			if ((methodDef.CallingConvention & 0x5) != 0)
286				methodDef.MethCallConv |= MethodCallingConvention.VarArg;
287			else if ((methodDef.CallingConvention & 0x10) != 0) {
288				methodDef.MethCallConv |= MethodCallingConvention.Generic;
289				methodDef.GenericParameterCount = Utilities.ReadCompressedInteger (data, start, out start);
290			} else
291				methodDef.MethCallConv |= MethodCallingConvention.Default;
292
293			methodDef.ParamCount = Utilities.ReadCompressedInteger (data, start, out start);
294			methodDef.RetType = ReadRetType (data, start, out start);
295			int sentpos;
296			methodDef.Parameters = ReadParameters (methodDef.ParamCount, data, start, out sentpos);
297			methodDef.Sentinel = sentpos;
298		}
299
300		void ReadMethodRefSig (MethodRefSig methodRef, byte [] data, int pos, out int start)
301		{
302			methodRef.CallingConvention = data [pos];
303			start = pos + 1;
304			methodRef.HasThis = (methodRef.CallingConvention & 0x20) != 0;
305			methodRef.ExplicitThis = (methodRef.CallingConvention & 0x40) != 0;
306			if ((methodRef.CallingConvention & 0x1) != 0)
307				methodRef.MethCallConv |= MethodCallingConvention.C;
308			else if ((methodRef.CallingConvention & 0x2) != 0)
309				methodRef.MethCallConv |= MethodCallingConvention.StdCall;
310			else if ((methodRef.CallingConvention & 0x3) != 0)
311				methodRef.MethCallConv |= MethodCallingConvention.ThisCall;
312			else if ((methodRef.CallingConvention & 0x4) != 0)
313				methodRef.MethCallConv |= MethodCallingConvention.FastCall;
314			else if ((methodRef.CallingConvention & 0x5) != 0)
315				methodRef.MethCallConv |= MethodCallingConvention.VarArg;
316			else
317				methodRef.MethCallConv |= MethodCallingConvention.Default;
318			methodRef.ParamCount = Utilities.ReadCompressedInteger (data, start, out start);
319			methodRef.RetType = ReadRetType (data, start, out start);
320			int sentpos;
321			methodRef.Parameters = ReadParameters (methodRef.ParamCount, data, start, out sentpos);
322			methodRef.Sentinel = sentpos;
323		}
324
325		LocalVarSig.LocalVariable [] ReadLocalVariables (int length, byte [] data, int pos)
326		{
327			int start = pos;
328			LocalVarSig.LocalVariable [] types = new LocalVarSig.LocalVariable [length];
329			for (int i = 0; i < length; i++)
330				types [i] = ReadLocalVariable (data, start, out start);
331			return types;
332		}
333
334		public LocalVarSig.LocalVariable ReadLocalVariable (byte [] data, int pos, out int start)
335		{
336			start = pos;
337			LocalVarSig.LocalVariable lv = new LocalVarSig.LocalVariable ();
338			lv.ByRef = false;
339			int cursor;
340			while (true) {
341				lv.CustomMods = ReadCustomMods (data, start, out start);
342				cursor = start;
343				int current = Utilities.ReadCompressedInteger (data, start, out start);
344				if (current == (int) ElementType.Pinned) // the only possible constraint
345					lv.Constraint |= Constraint.Pinned;
346				else if (current == (int) ElementType.ByRef) {
347					lv.ByRef = true;
348
349					if (lv.CustomMods == null || lv.CustomMods.Length == 0)
350						lv.CustomMods = ReadCustomMods (data, start, out start);
351				} else {
352					lv.Type = ReadType (data, cursor, out start);
353					break;
354				}
355			}
356			return lv;
357		}
358
359		TypeSpec ReadTypeSpec (byte [] data, int pos)
360		{
361			int start = pos;
362			Utilities.ReadCompressedInteger (data, start, out start);
363			TypeSpec ts = new TypeSpec ();
364			ts.CustomMods = ReadCustomMods (data, start, out start);
365			ts.Type = ReadType (data, start, out start);
366			return ts;
367		}
368
369		MethodSpec ReadMethodSpec (byte [] data, int pos)
370		{
371			int start = pos;
372
373			Utilities.ReadCompressedInteger (data, start, out start);
374			if (Utilities.ReadCompressedInteger (data, start, out start) != 0x0a)
375				throw new ReflectionException ("Invalid MethodSpec signature");
376
377			return new MethodSpec (ReadGenericInstSignature (data, start, out start));
378		}
379
380		RetType ReadRetType (byte [] data, int pos, out int start)
381		{
382			RetType rt = new RetType ();
383			start = pos;
384			rt.CustomMods = ReadCustomMods (data, start, out start);
385			int curs = start;
386			ElementType flag = (ElementType) Utilities.ReadCompressedInteger (data, start, out start);
387			switch (flag) {
388			case ElementType.Void :
389				rt.ByRef = rt.TypedByRef = false;
390				rt.Void = true;
391				break;
392			case ElementType.TypedByRef :
393				rt.ByRef = rt.Void = false;
394				rt.TypedByRef = true;
395				break;
396			case ElementType.ByRef :
397				rt.TypedByRef = rt.Void = false;
398				rt.ByRef = true;
399
400				if (rt.CustomMods == null || rt.CustomMods.Length == 0)
401					rt.CustomMods = ReadCustomMods (data, start, out start);
402
403				rt.Type = ReadType (data, start, out start);
404				break;
405			default :
406				rt.TypedByRef = rt.Void = rt.ByRef = false;
407				rt.Type = ReadType (data, curs, out start);
408				break;
409			}
410			return rt;
411		}
412
413		Param [] ReadParameters (int length, byte [] data, int pos)
414		{
415			Param [] ret = new Param [length];
416			int start = pos;
417			for (int i = 0; i < length; i++)
418				ret [i] = ReadParameter (data, start, out start);
419			return ret;
420		}
421
422		Param [] ReadParameters (int length, byte [] data, int pos, out int sentinelpos)
423		{
424			Param [] ret = new Param [length];
425			int start = pos;
426			sentinelpos = -1;
427
428			for (int i = 0; i < length; i++) {
429				int curs = start;
430				int flag = Utilities.ReadCompressedInteger (data, start, out start);
431
432				if (flag == (int) ElementType.Sentinel) {
433					sentinelpos = i;
434					curs = start;
435				}
436
437				ret [i] = ReadParameter (data, curs, out start);
438			}
439
440			return ret;
441		}
442
443		Param ReadParameter (byte [] data, int pos, out int start)
444		{
445			Param p = new Param ();
446			start = pos;
447
448			p.CustomMods = ReadCustomMods (data, start, out start);
449			int curs = start;
450			ElementType flag = (ElementType) Utilities.ReadCompressedInteger (data, start, out start);
451			switch (flag) {
452			case ElementType.TypedByRef :
453				p.TypedByRef = true;
454				p.ByRef = false;
455				break;
456			case ElementType.ByRef :
457				p.TypedByRef = false;
458				p.ByRef = true;
459
460				if (p.CustomMods == null || p.CustomMods.Length == 0)
461					p.CustomMods = ReadCustomMods (data, start, out start);
462
463				p.Type = ReadType (data, start, out start);
464				break;
465			default :
466				p.TypedByRef = false;
467				p.ByRef = false;
468				p.Type = ReadType (data, curs, out start);
469				break;
470			}
471			return p;
472		}
473
474		public SigType ReadType (byte [] data, int pos, out int start)
475		{
476			start = pos;
477			ElementType element = (ElementType) Utilities.ReadCompressedInteger (data, start, out start);
478			switch (element) {
479			case ElementType.ValueType :
480				VALUETYPE vt = new VALUETYPE ();
481				vt.Type = Utilities.GetMetadataToken(CodedIndex.TypeDefOrRef,
482					(uint) Utilities.ReadCompressedInteger (data, start, out start));
483				return vt;
484			case ElementType.Class :
485				CLASS c = new CLASS ();
486				c.Type = Utilities.GetMetadataToken (CodedIndex.TypeDefOrRef,
487					(uint) Utilities.ReadCompressedInteger (data, start, out start));
488				return c;
489			case ElementType.Ptr :
490				PTR p = new PTR ();
491				int buf = start;
492				int flag = Utilities.ReadCompressedInteger (data, start, out start);
493				p.Void = flag == (int) ElementType.Void;
494				if (p.Void)
495					return p;
496				start = buf;
497				p.CustomMods = ReadCustomMods (data, start, out start);
498				p.PtrType = ReadType (data, start, out start);
499				return p;
500			case ElementType.FnPtr :
501				FNPTR fp = new FNPTR ();
502				if ((data [start] & 0x5) != 0) {
503					MethodRefSig mr = new MethodRefSig ((uint) start);
504					ReadMethodRefSig (mr, data, start, out start);
505					fp.Method = mr;
506				} else {
507					MethodDefSig md = new MethodDefSig ((uint) start);
508					ReadMethodDefSig (md, data, start, out start);
509					fp.Method = md;
510				}
511				return fp;
512			case ElementType.Array :
513				ARRAY ary = new ARRAY ();
514				ary.CustomMods = ReadCustomMods (data, start, out start);
515				ArrayShape shape = new ArrayShape ();
516				ary.Type = ReadType (data, start, out start);
517				shape.Rank = Utilities.ReadCompressedInteger (data, start, out start);
518				shape.NumSizes = Utilities.ReadCompressedInteger (data, start, out start);
519				shape.Sizes = new int [shape.NumSizes];
520				for (int i = 0; i < shape.NumSizes; i++)
521					shape.Sizes [i] = Utilities.ReadCompressedInteger (data, start, out start);
522				shape.NumLoBounds = Utilities.ReadCompressedInteger (data, start, out start);
523				shape.LoBounds = new int [shape.NumLoBounds];
524				for (int i = 0; i < shape.NumLoBounds; i++)
525					shape.LoBounds [i] = Utilities.ReadCompressedInteger (data, start, out start);
526				ary.Shape = shape;
527				return ary;
528			case ElementType.SzArray :
529				SZARRAY sa = new SZARRAY ();
530				sa.CustomMods = ReadCustomMods (data, start, out start);
531				sa.Type = ReadType (data, start, out start);
532				return sa;
533			case ElementType.Var:
534				return new VAR (Utilities.ReadCompressedInteger (data, start, out start));
535			case ElementType.MVar:
536				return new MVAR (Utilities.ReadCompressedInteger (data, start, out start));
537			case ElementType.GenericInst:
538				GENERICINST ginst = new GENERICINST ();
539
540				ginst.ValueType = ((ElementType) Utilities.ReadCompressedInteger (
541					data, start, out start)) == ElementType.ValueType;
542
543				ginst.Type = Utilities.GetMetadataToken (CodedIndex.TypeDefOrRef,
544					(uint) Utilities.ReadCompressedInteger (data, start, out start));
545
546				ginst.Signature = ReadGenericInstSignature (data, start, out start);
547
548				return ginst;
549			default :
550				return new SigType (element);
551			}
552		}
553
554		GenericInstSignature ReadGenericInstSignature (byte [] data, int pos, out int start)
555		{
556			start = pos;
557			GenericInstSignature gis = new GenericInstSignature ();
558			gis.Arity = Utilities.ReadCompressedInteger (data, start, out start);
559			gis.Types = new GenericArg [gis.Arity];
560			for (int i = 0; i < gis.Arity; i++)
561				gis.Types [i] = ReadGenericArg (data, start, out start);
562
563			return gis;
564		}
565
566		GenericArg ReadGenericArg (byte[] data, int pos, out int start)
567		{
568			start = pos;
569			CustomMod [] mods = ReadCustomMods (data, start, out start);
570			GenericArg arg = new GenericArg (ReadType (data, start, out start));
571			arg.CustomMods = mods;
572			return arg;
573		}
574
575		CustomMod [] ReadCustomMods (byte [] data, int pos, out int start)
576		{
577			ArrayList cmods = new ArrayList ();
578			start = pos;
579			while (true) {
580				int buf = start;
581				ElementType flag = (ElementType) Utilities.ReadCompressedInteger (data, start, out start);
582				start = buf;
583				if (!((flag == ElementType.CModOpt) || (flag == ElementType.CModReqD)))
584					break;
585				cmods.Add (ReadCustomMod (data, start, out start));
586			}
587			return cmods.ToArray (typeof (CustomMod)) as CustomMod [];
588		}
589
590		CustomMod ReadCustomMod (byte [] data, int pos, out int start)
591		{
592			CustomMod cm = new CustomMod ();
593			start = pos;
594			ElementType cmod = (ElementType) Utilities.ReadCompressedInteger (data, start, out start);
595			if (cmod == ElementType.CModOpt)
596				cm.CMOD = CustomMod.CMODType.OPT;
597			else if (cmod == ElementType.CModReqD)
598				cm.CMOD = CustomMod.CMODType.REQD;
599			else
600				cm.CMOD = CustomMod.CMODType.None;
601			cm.TypeDefOrRef = Utilities.GetMetadataToken (CodedIndex.TypeDefOrRef,
602				(uint) Utilities.ReadCompressedInteger (data, start, out start));
603			return cm;
604		}
605		
606		/*
607
608		CustomAttrib ReadCustomAttrib (int pos, MethodReference ctor, bool resolve)
609		{
610			int start, length = Utilities.ReadCompressedInteger (m_blobData, pos, out start);
611			byte [] data = new byte [length];
612			Buffer.BlockCopy (m_blobData, start, data, 0, length);
613			try {
614				return ReadCustomAttrib (new BinaryReader (
615					new MemoryStream (data)), data, ctor, resolve);
616			} catch {
617				CustomAttrib ca = new CustomAttrib (ctor);
618				ca.Read = false;
619				return ca;
620			}
621		}
622
623		CustomAttrib ReadCustomAttrib (BinaryReader br, byte [] data, MethodReference ctor, bool resolve)
624		{
625			CustomAttrib ca = new CustomAttrib (ctor);
626			if (data.Length == 0) {
627				ca.FixedArgs = new CustomAttrib.FixedArg [0];
628				ca.NamedArgs = new CustomAttrib.NamedArg [0];
629				return ca;
630			}
631
632			bool read = true;
633
634			ca.Prolog = br.ReadUInt16 ();
635			if (ca.Prolog != CustomAttrib.StdProlog)
636				throw new MetadataFormatException ("Non standard prolog for custom attribute");
637
638			ca.FixedArgs = new CustomAttrib.FixedArg [ctor.Parameters.Count];
639			for (int i = 0; i < ca.FixedArgs.Length && read; i++)
640				ca.FixedArgs [i] = ReadFixedArg (data, br,
641					ctor.Parameters [i].ParameterType, ref read, resolve);
642
643			if (br.BaseStream.Position == br.BaseStream.Length)
644				read = false;
645
646			if (!read) {
647				ca.Read = read;
648				return ca;
649			}
650
651			ca.NumNamed = br.ReadUInt16 ();
652			ca.NamedArgs = new CustomAttrib.NamedArg [ca.NumNamed];
653			for (int i = 0; i < ca.NumNamed && read; i++)
654				ca.NamedArgs [i] = ReadNamedArg (data, br, ref read, resolve);
655
656			ca.Read = read;
657			return ca;
658		}
659
660		CustomAttrib.FixedArg ReadFixedArg (byte [] data, BinaryReader br,
661			TypeReference param, ref bool read, bool resolve)
662		{
663			CustomAttrib.FixedArg fa = new CustomAttrib.FixedArg ();
664			if (param is ArrayType) {
665				param = ((ArrayType) param).ElementType;
666				fa.SzArray = true;
667				fa.NumElem = br.ReadUInt32 ();
668
669				if (fa.NumElem == 0 || fa.NumElem == 0xffffffff) {
670					fa.Elems = new CustomAttrib.Elem [0];
671					fa.NumElem = 0;
672					return fa;
673				}
674
675				fa.Elems = new CustomAttrib.Elem [fa.NumElem];
676				for (int i = 0; i < fa.NumElem; i++)
677					fa.Elems [i] = ReadElem (data, br, param, ref read, resolve);
678			} else
679				fa.Elems = new CustomAttrib.Elem [] { ReadElem (data, br, param, ref read, resolve) };
680
681			return fa;
682		}
683
684		TypeReference CreateEnumTypeReference (string enumName)
685		{
686			string asmName = null;
687			int asmStart = enumName.IndexOf (',');
688			if (asmStart != -1) {
689				asmName = enumName.Substring (asmStart + 1);
690				enumName = enumName.Substring (0, asmStart);
691			}
692			// Inner class style is reflection style.
693			enumName = enumName.Replace ('+', '/');
694			AssemblyNameReference asm;
695			if (asmName == null) {
696				// If no assembly is given then the ECMA standard says the
697				// assembly is either the current one or mscorlib.
698				if (m_reflectReader.Module.Types.Contains (enumName))
699					return m_reflectReader.Module.Types [enumName];
700
701				asm = m_reflectReader.Corlib;
702			} else
703				asm = AssemblyNameReference.Parse (asmName);
704
705			string [] outers = enumName.Split ('/');
706			string outerfullname = outers [0];
707			string ns = null;
708			int nsIndex = outerfullname.LastIndexOf ('.');
709			if (nsIndex != -1)
710				ns = outerfullname.Substring (0, nsIndex);
711			string name = outerfullname.Substring (nsIndex + 1);
712			TypeReference decType = new TypeReference (name, ns, asm);
713			for (int i = 1; i < outers.Length; i++) {
714				TypeReference t = new TypeReference (outers [i], null, asm);
715				t.DeclaringType = decType;
716				decType = t;
717			}
718			decType.IsValueType = true;
719
720			return decType;
721		}
722
723		TypeReference ReadTypeReference (byte [] data, BinaryReader br, out ElementType elemType)
724		{
725			bool array = false;
726			elemType = (ElementType) br.ReadByte ();
727			if (elemType == ElementType.SzArray) {
728				elemType = (ElementType) br.ReadByte ();
729				array = true;
730			}
731
732			TypeReference res;
733			if (elemType == ElementType.Enum)
734				res = CreateEnumTypeReference (ReadUTF8String (data, br));
735			else
736				res = TypeReferenceFromElemType (elemType);
737
738			if (array)
739				res = new ArrayType (res);
740
741			return res;
742		}
743
744		TypeReference TypeReferenceFromElemType (ElementType elemType)
745		{
746			switch (elemType) {
747			case ElementType.Boxed :
748				return m_reflectReader.SearchCoreType (Constants.Object);
749			case ElementType.String :
750				return m_reflectReader.SearchCoreType (Constants.String);
751			case ElementType.Type :
752				return m_reflectReader.SearchCoreType (Constants.Type);
753			case ElementType.Boolean :
754				return m_reflectReader.SearchCoreType (Constants.Boolean);
755			case ElementType.Char :
756				return m_reflectReader.SearchCoreType (Constants.Char);
757			case ElementType.R4 :
758				return m_reflectReader.SearchCoreType (Constants.Single);
759			case ElementType.R8 :
760				return m_reflectReader.SearchCoreType (Constants.Double);
761			case ElementType.I1 :
762				return m_reflectReader.SearchCoreType (Constants.SByte);
763			case ElementType.I2 :
764				return m_reflectReader.SearchCoreType (Constants.Int16);
765			case ElementType.I4 :
766				return m_reflectReader.SearchCoreType (Constants.Int32);
767			case ElementType.I8 :
768				return m_reflectReader.SearchCoreType (Constants.Int64);
769			case ElementType.U1 :
770				return m_reflectReader.SearchCoreType (Constants.Byte);
771			case ElementType.U2 :
772				return m_reflectReader.SearchCoreType (Constants.UInt16);
773			case ElementType.U4 :
774				return m_reflectReader.SearchCoreType (Constants.UInt32);
775			case ElementType.U8 :
776				return m_reflectReader.SearchCoreType (Constants.UInt64);
777			default :
778				throw new MetadataFormatException ("Non valid type in CustomAttrib.Elem: 0x{0}",
779					((byte) elemType).ToString("x2"));
780			}
781		}
782
783		internal CustomAttrib.NamedArg ReadNamedArg (byte [] data, BinaryReader br, ref bool read, bool resolve)
784		{
785			CustomAttrib.NamedArg na = new CustomAttrib.NamedArg ();
786			byte kind = br.ReadByte ();
787			if (kind == 0x53) { // field
788				na.Field = true;
789				na.Property = false;
790			} else if (kind == 0x54) { // property
791				na.Field = false;
792				na.Property = true;
793			} else
794				throw new MetadataFormatException ("Wrong kind of namedarg found: 0x" + kind.ToString("x2"));
795
796			TypeReference elemType = ReadTypeReference (data, br, out na.FieldOrPropType);
797			na.FieldOrPropName = ReadUTF8String (data, br);
798			na.FixedArg = ReadFixedArg (data, br, elemType, ref read, resolve);
799
800			return na;
801		}
802
803		CustomAttrib.Elem ReadElem (byte [] data, BinaryReader br, TypeReference elemType, ref bool read, bool resolve)
804		{
805			CustomAttrib.Elem elem = new CustomAttrib.Elem ();
806
807			string elemName = elemType.FullName;
808
809			if (elemName == Constants.Object) {
810				elemType = ReadTypeReference (data, br, out elem.FieldOrPropType);
811				if (elemType is ArrayType) {
812					read = false; // Don't know how to represent arrays as an object value.
813					return elem;
814				} else if (elemType.FullName == Constants.Object)
815					throw new MetadataFormatException ("Non valid type in CustomAttrib.Elem after boxed prefix: 0x{0}",
816						((byte) elem.FieldOrPropType).ToString("x2"));
817
818				elem = ReadElem (data, br, elemType, ref read, resolve);
819				elem.String = elem.Simple = elem.Type = false;
820				elem.BoxedValueType = true;
821				return elem;
822			}
823
824			elem.ElemType = elemType;
825
826			if (elemName == Constants.Type || elemName == Constants.String) {
827				switch (elemType.FullName) {
828				case Constants.String:
829					elem.String = true;
830					elem.BoxedValueType = elem.Simple = elem.Type = false;
831					break;
832				case Constants.Type:
833					elem.Type = true;
834					elem.BoxedValueType = elem.Simple = elem.String = false;
835					break;
836				}
837
838				if (data [br.BaseStream.Position] == 0xff) { // null
839					elem.Value = null;
840					br.BaseStream.Position++;
841				} else {
842					elem.Value = ReadUTF8String (data, br);
843				}
844				return elem;
845			}
846
847			elem.String = elem.Type = elem.BoxedValueType = false;
848			if (!ReadSimpleValue (br, ref elem, elem.ElemType)) {
849				if (!resolve) { // until enums writing is implemented
850					read = false;
851					return elem;
852				}
853				TypeReference typeRef = GetEnumUnderlyingType (elem.ElemType, resolve);
854				if (typeRef == null || !ReadSimpleValue (br, ref elem, typeRef))
855					read = false;
856			}
857
858			return elem;
859		}
860
861		TypeReference GetEnumUnderlyingType (TypeReference enumType, bool resolve)
862		{
863			TypeDefinition type = enumType as TypeDefinition;
864			if (type == null && resolve && AssemblyResolver != null) {
865				if (enumType.Scope is ModuleDefinition)
866					throw new NotSupportedException ();
867
868				AssemblyDefinition asm = AssemblyResolver.Resolve (
869					((AssemblyNameReference) enumType.Scope).FullName);
870				type = asm.MainModule.Types [enumType.FullName];
871			}
872
873			if (type != null && type.IsEnum)
874				return type.Fields.GetField ("value__").FieldType;
875
876			return null;
877		}
878
879		bool ReadSimpleValue (BinaryReader br, ref CustomAttrib.Elem elem, TypeReference type)
880		{
881			switch (type.FullName) {
882			case Constants.Boolean :
883				elem.Value = br.ReadByte () == 1;
884				break;
885			case Constants.Char :
886				elem.Value = (char) br.ReadUInt16 ();
887				break;
888			case Constants.Single :
889				elem.Value = br.ReadSingle ();
890				break;
891			case Constants.Double :
892				elem.Value = br.ReadDouble ();
893				break;
894			case Constants.Byte :
895				elem.Value = br.ReadByte ();
896				break;
897			case Constants.Int16 :
898				elem.Value = br.ReadInt16 ();
899				break;
900			case Constants.Int32 :
901				elem.Value = br.ReadInt32 ();
902				break;
903			case Constants.Int64 :
904				elem.Value = br.ReadInt64 ();
905				break;
906			case Constants.SByte :
907				elem.Value = br.ReadSByte ();
908				break;
909			case Constants.UInt16 :
910				elem.Value = br.ReadUInt16 ();
911				break;
912			case Constants.UInt32 :
913				elem.Value = br.ReadUInt32 ();
914				break;
915			case Constants.UInt64 :
916				elem.Value = br.ReadUInt64 ();
917				break;
918			default : // enum
919				return false;
920			}
921			elem.Simple = true;
922			return true;
923		}
924
925		MarshalSig ReadMarshalSig (byte [] data)
926		{
927			int start;
928			MarshalSig ms = new MarshalSig ((NativeType) Utilities.ReadCompressedInteger (data, 0, out start));
929			switch (ms.NativeInstrinsic) {
930			case NativeType.ARRAY:
931				MarshalSig.Array ar = new MarshalSig.Array ();
932				ar.ArrayElemType = (NativeType) Utilities.ReadCompressedInteger (data, start, out start);
933				if (start < data.Length)
934					ar.ParamNum = Utilities.ReadCompressedInteger (data, start, out start);
935				if (start < data.Length)
936					ar.NumElem = Utilities.ReadCompressedInteger (data, start, out start);
937				if (start < data.Length)
938					ar.ElemMult = Utilities.ReadCompressedInteger (data, start, out start);
939				ms.Spec = ar;
940				break;
941			case NativeType.CUSTOMMARSHALER:
942				MarshalSig.CustomMarshaler cm = new MarshalSig.CustomMarshaler ();
943				cm.Guid = ReadUTF8String (data, start, out start);
944				cm.UnmanagedType = ReadUTF8String (data, start, out start);
945				cm.ManagedType = ReadUTF8String (data, start, out start);
946				cm.Cookie = ReadUTF8String (data, start, out start);
947				ms.Spec = cm;
948				break;
949			case NativeType.FIXEDARRAY:
950				MarshalSig.FixedArray fa = new MarshalSig.FixedArray ();
951				fa.NumElem = Utilities.ReadCompressedInteger (data, start, out start);
952				if (start < data.Length)
953					fa.ArrayElemType = (NativeType) Utilities.ReadCompressedInteger (data, start, out start);
954				ms.Spec = fa;
955				break;
956			case NativeType.SAFEARRAY:
957				MarshalSig.SafeArray sa = new MarshalSig.SafeArray ();
958				if (start < data.Length)
959					sa.ArrayElemType = (VariantType) Utilities.ReadCompressedInteger (data, start, out start);
960				ms.Spec = sa;
961				break;
962			case NativeType.FIXEDSYSSTRING:
963				MarshalSig.FixedSysString fss = new MarshalSig.FixedSysString ();
964				if (start < data.Length)
965					fss.Size = Utilities.ReadCompressedInteger (data, start, out start);
966				ms.Spec = fss;
967				break;
968			}
969			return ms;
970		}
971
972		static internal string ReadUTF8String (byte [] data, BinaryReader br)
973		{
974			int start = (int)br.BaseStream.Position;
975			string val = ReadUTF8String (data, start, out start);
976			br.BaseStream.Position = start;
977			return val;
978		}
979
980		static internal string ReadUTF8String (byte [] data, int pos, out int start)
981		{
982			int length = Utilities.ReadCompressedInteger (data, pos, out start);
983			pos = start;
984			start += length;
985			// COMPACT FRAMEWORK NOTE: Encoding.GetString (byte[]) is not supported.
986			return Encoding.UTF8.GetString (data, pos, length);
987		}
988		
989		*/
990	}
991}