update Mono.Cecil
[mono.git] / mcs / class / Mono.Cecil / Mono.Cecil / AssemblyReader.cs
1 //
2 // AssemblyReader.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@gmail.com)
6 //
7 // Copyright (c) 2008 - 2011 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
29 using System;
30 using System.Collections.Generic;
31 using System.IO;
32 using System.Text;
33
34 using Mono.Collections.Generic;
35 using Mono.Cecil.Cil;
36 using Mono.Cecil.Metadata;
37 using Mono.Cecil.PE;
38
39 using RVA = System.UInt32;
40
41 namespace Mono.Cecil {
42
43         abstract class ModuleReader {
44
45                 readonly protected Image image;
46                 readonly protected ModuleDefinition module;
47
48                 protected ModuleReader (Image image, ReadingMode mode)
49                 {
50                         this.image = image;
51                         this.module = new ModuleDefinition (image);
52                         this.module.ReadingMode = mode;
53                 }
54
55                 protected abstract void ReadModule ();
56
57                 protected void ReadModuleManifest (MetadataReader reader)
58                 {
59                         reader.Populate (module);
60
61                         ReadAssembly (reader);
62                 }
63
64                 void ReadAssembly (MetadataReader reader)
65                 {
66                         var name = reader.ReadAssemblyNameDefinition ();
67                         if (name == null) {
68                                 module.kind = ModuleKind.NetModule;
69                                 return;
70                         }
71
72                         var assembly = new AssemblyDefinition ();
73                         assembly.Name = name;
74
75                         module.assembly = assembly;
76                         assembly.main_module = module;
77                 }
78
79                 public static ModuleDefinition CreateModuleFrom (Image image, ReaderParameters parameters)
80                 {
81                         var module = ReadModule (image, parameters);
82
83                         ReadSymbols (module, parameters);
84
85                         if (parameters.AssemblyResolver != null)
86                                 module.assembly_resolver = parameters.AssemblyResolver;
87
88                         return module;
89                 }
90
91                 static void ReadSymbols (ModuleDefinition module, ReaderParameters parameters)
92                 {
93                         var symbol_reader_provider = parameters.SymbolReaderProvider;
94
95                         if (symbol_reader_provider == null && parameters.ReadSymbols)
96                                 symbol_reader_provider = SymbolProvider.GetPlatformReaderProvider ();
97
98                         if (symbol_reader_provider != null) {
99                                 module.SymbolReaderProvider = symbol_reader_provider;
100
101                                 var reader = parameters.SymbolStream != null
102                                         ? symbol_reader_provider.GetSymbolReader (module, parameters.SymbolStream)
103                                         : symbol_reader_provider.GetSymbolReader (module, module.FullyQualifiedName);
104
105                                 module.ReadSymbols (reader);
106                         }
107                 }
108
109                 static ModuleDefinition ReadModule (Image image, ReaderParameters parameters)
110                 {
111                         var reader = CreateModuleReader (image, parameters.ReadingMode);
112                         reader.ReadModule ();
113                         return reader.module;
114                 }
115
116                 static ModuleReader CreateModuleReader (Image image, ReadingMode mode)
117                 {
118                         switch (mode) {
119                         case ReadingMode.Immediate:
120                                 return new ImmediateModuleReader (image);
121                         case ReadingMode.Deferred:
122                                 return new DeferredModuleReader (image);
123                         default:
124                                 throw new ArgumentException ();
125                         }
126                 }
127         }
128
129         sealed class ImmediateModuleReader : ModuleReader {
130
131                 public ImmediateModuleReader (Image image)
132                         : base (image, ReadingMode.Immediate)
133                 {
134                 }
135
136                 protected override void ReadModule ()
137                 {
138                         this.module.Read (this.module, (module, reader) => {
139                                 ReadModuleManifest (reader);
140                                 ReadModule (module);
141                                 return module;
142                         });
143                 }
144
145                 public static void ReadModule (ModuleDefinition module)
146                 {
147                         if (module.HasAssemblyReferences)
148                                 Read (module.AssemblyReferences);
149                         if (module.HasResources)
150                                 Read (module.Resources);
151                         if (module.HasModuleReferences)
152                                 Read (module.ModuleReferences);
153                         if (module.HasTypes)
154                                 ReadTypes (module.Types);
155                         if (module.HasExportedTypes)
156                                 Read (module.ExportedTypes);
157                         if (module.HasCustomAttributes)
158                                 Read (module.CustomAttributes);
159
160                         var assembly = module.Assembly;
161                         if (assembly == null)
162                                 return;
163
164                         if (assembly.HasCustomAttributes)
165                                 Read (assembly.CustomAttributes);
166                         if (assembly.HasSecurityDeclarations)
167                                 Read (assembly.SecurityDeclarations);
168                 }
169
170                 static void ReadTypes (Collection<TypeDefinition> types)
171                 {
172                         for (int i = 0; i < types.Count; i++)
173                                 ReadType (types [i]);
174                 }
175
176                 static void ReadType (TypeDefinition type)
177                 {
178                         ReadGenericParameters (type);
179
180                         if (type.HasInterfaces)
181                                 Read (type.Interfaces);
182
183                         if (type.HasNestedTypes)
184                                 ReadTypes (type.NestedTypes);
185
186                         if (type.HasLayoutInfo)
187                                 Read (type.ClassSize);
188
189                         if (type.HasFields)
190                                 ReadFields (type);
191
192                         if (type.HasMethods)
193                                 ReadMethods (type);
194
195                         if (type.HasProperties)
196                                 ReadProperties (type);
197
198                         if (type.HasEvents)
199                                 ReadEvents (type);
200
201                         ReadSecurityDeclarations (type);
202                         ReadCustomAttributes (type);
203                 }
204
205                 static void ReadGenericParameters (IGenericParameterProvider provider)
206                 {
207                         if (!provider.HasGenericParameters)
208                                 return;
209
210                         var parameters = provider.GenericParameters;
211
212                         for (int i = 0; i < parameters.Count; i++) {
213                                 var parameter = parameters [i];
214
215                                 if (parameter.HasConstraints)
216                                         Read (parameter.Constraints);
217
218                                 if (parameter.HasCustomAttributes)
219                                         Read (parameter.CustomAttributes);
220                         }
221                 }
222
223                 static void ReadSecurityDeclarations (ISecurityDeclarationProvider provider)
224                 {
225                         if (provider.HasSecurityDeclarations)
226                                 Read (provider.SecurityDeclarations);
227                 }
228
229                 static void ReadCustomAttributes (ICustomAttributeProvider provider)
230                 {
231                         if (provider.HasCustomAttributes)
232                                 Read (provider.CustomAttributes);
233                 }
234
235                 static void ReadFields (TypeDefinition type)
236                 {
237                         var fields = type.Fields;
238
239                         for (int i = 0; i < fields.Count; i++) {
240                                 var field = fields [i];
241
242                                 if (field.HasConstant)
243                                         Read (field.Constant);
244
245                                 if (field.HasLayoutInfo)
246                                         Read (field.Offset);
247
248                                 if (field.RVA > 0)
249                                         Read (field.InitialValue);
250
251                                 if (field.HasMarshalInfo)
252                                         Read (field.MarshalInfo);
253
254                                 ReadCustomAttributes (field);
255                         }
256                 }
257
258                 static void ReadMethods (TypeDefinition type)
259                 {
260                         var methods = type.Methods;
261
262                         for (int i = 0; i < methods.Count; i++) {
263                                 var method = methods [i];
264
265                                 ReadGenericParameters (method);
266
267                                 if (method.HasParameters)
268                                         ReadParameters (method);
269
270                                 if (method.HasOverrides)
271                                         Read (method.Overrides);
272
273                                 if (method.IsPInvokeImpl)
274                                         Read (method.PInvokeInfo);
275
276                                 ReadSecurityDeclarations (method);
277                                 ReadCustomAttributes (method);
278
279                                 var return_type = method.MethodReturnType;
280                                 if (return_type.HasConstant)
281                                         Read (return_type.Constant);
282
283                                 if (return_type.HasMarshalInfo)
284                                         Read (return_type.MarshalInfo);
285
286                                 ReadCustomAttributes (return_type);
287                         }
288                 }
289
290                 static void ReadParameters (MethodDefinition method)
291                 {
292                         var parameters = method.Parameters;
293
294                         for (int i = 0; i < parameters.Count; i++) {
295                                 var parameter = parameters [i];
296
297                                 if (parameter.HasConstant)
298                                         Read (parameter.Constant);
299
300                                 if (parameter.HasMarshalInfo)
301                                         Read (parameter.MarshalInfo);
302
303                                 ReadCustomAttributes (parameter);
304                         }
305                 }
306
307                 static void ReadProperties (TypeDefinition type)
308                 {
309                         var properties = type.Properties;
310
311                         for (int i = 0; i < properties.Count; i++) {
312                                 var property = properties [i];
313
314                                 Read (property.GetMethod);
315
316                                 if (property.HasConstant)
317                                         Read (property.Constant);
318
319                                 ReadCustomAttributes (property);
320                         }
321                 }
322
323                 static void ReadEvents (TypeDefinition type)
324                 {
325                         var events = type.Events;
326
327                         for (int i = 0; i < events.Count; i++) {
328                                 var @event = events [i];
329
330                                 Read (@event.AddMethod);
331
332                                 ReadCustomAttributes (@event);
333                         }
334                 }
335
336                 static void Read (object collection)
337                 {
338                 }
339         }
340
341         sealed class DeferredModuleReader : ModuleReader {
342
343                 public DeferredModuleReader (Image image)
344                         : base (image, ReadingMode.Deferred)
345                 {
346                 }
347
348                 protected override void ReadModule ()
349                 {
350                         this.module.Read (this.module, (module, reader) => {
351                                 ReadModuleManifest (reader);
352                                 return module;
353                         });
354                 }
355         }
356
357         sealed class MetadataReader : ByteBuffer {
358
359                 readonly internal Image image;
360                 readonly internal ModuleDefinition module;
361                 readonly internal MetadataSystem metadata;
362
363                 internal IGenericContext context;
364                 internal CodeReader code;
365
366                 uint Position {
367                         get { return (uint) base.position; }
368                         set { base.position = (int) value; }
369                 }
370
371                 public MetadataReader (ModuleDefinition module)
372                         : base (module.Image.MetadataSection.Data)
373                 {
374                         this.image = module.Image;
375                         this.module = module;
376                         this.metadata = module.MetadataSystem;
377                         this.code = new CodeReader (image.MetadataSection, this);
378                 }
379
380                 int GetCodedIndexSize (CodedIndex index)
381                 {
382                         return image.GetCodedIndexSize (index);
383                 }
384
385                 uint ReadByIndexSize (int size)
386                 {
387                         if (size == 4)
388                                 return ReadUInt32 ();
389                         else
390                                 return ReadUInt16 ();
391                 }
392
393                 byte [] ReadBlob ()
394                 {
395                         var blob_heap = image.BlobHeap;
396                         if (blob_heap == null) {
397                                 position += 2;
398                                 return Empty<byte>.Array;
399                         }
400
401                         return blob_heap.Read (ReadBlobIndex ());
402                 }
403
404                 byte [] ReadBlob (uint signature)
405                 {
406                         var blob_heap = image.BlobHeap;
407                         if (blob_heap == null)
408                                 return Empty<byte>.Array;
409
410                         return blob_heap.Read (signature);
411                 }
412
413                 uint ReadBlobIndex ()
414                 {
415                         var blob_heap = image.BlobHeap;
416                         return ReadByIndexSize (blob_heap != null ? blob_heap.IndexSize : 2);
417                 }
418
419                 string ReadString ()
420                 {
421                         return image.StringHeap.Read (ReadByIndexSize (image.StringHeap.IndexSize));
422                 }
423
424                 uint ReadStringIndex ()
425                 {
426                         return ReadByIndexSize (image.StringHeap.IndexSize);
427                 }
428
429                 uint ReadTableIndex (Table table)
430                 {
431                         return ReadByIndexSize (image.GetTableIndexSize (table));
432                 }
433
434                 MetadataToken ReadMetadataToken (CodedIndex index)
435                 {
436                         return index.GetMetadataToken (ReadByIndexSize (GetCodedIndexSize (index)));
437                 }
438
439                 int MoveTo (Table table)
440                 {
441                         var info = image.TableHeap [table];
442                         if (info.Length != 0)
443                                 Position = info.Offset;
444
445                         return (int) info.Length;
446                 }
447
448                 bool MoveTo (Table table, uint row)
449                 {
450                         var info = image.TableHeap [table];
451                         var length = info.Length;
452                         if (length == 0 || row > length)
453                                 return false;
454
455                         Position = info.Offset + (info.RowSize * (row - 1));
456                         return true;
457                 }
458
459                 public AssemblyNameDefinition ReadAssemblyNameDefinition ()
460                 {
461                         if (MoveTo (Table.Assembly) == 0)
462                                 return null;
463
464                         var name = new AssemblyNameDefinition ();
465
466                         name.HashAlgorithm = (AssemblyHashAlgorithm) ReadUInt32 ();
467
468                         PopulateVersionAndFlags (name);
469
470                         name.PublicKey = ReadBlob ();
471
472                         PopulateNameAndCulture (name);
473
474                         return name;
475                 }
476
477                 public ModuleDefinition Populate (ModuleDefinition module)
478                 {
479                         if (MoveTo (Table.Module) == 0)
480                                 return module;
481
482                         Advance (2); // Generation
483
484                         module.Name = ReadString ();
485                         module.Mvid = image.GuidHeap.Read (ReadByIndexSize (image.GuidHeap.IndexSize));
486
487                         return module;
488                 }
489
490                 void InitializeAssemblyReferences ()
491                 {
492                         if (metadata.AssemblyReferences != null)
493                                 return;
494
495                         int length = MoveTo (Table.AssemblyRef);
496                         var references = metadata.AssemblyReferences = new AssemblyNameReference [length];
497
498                         for (uint i = 0; i < length; i++) {
499                                 var reference = new AssemblyNameReference ();
500                                 reference.token = new MetadataToken (TokenType.AssemblyRef, i + 1);
501
502                                 PopulateVersionAndFlags (reference);
503
504                                 var key_or_token = ReadBlob ();
505
506                                 if (reference.HasPublicKey)
507                                         reference.PublicKey = key_or_token;
508                                 else
509                                         reference.PublicKeyToken = key_or_token;
510
511                                 PopulateNameAndCulture (reference);
512
513                                 reference.Hash = ReadBlob ();
514
515                                 references [i] = reference;
516                         }
517                 }
518
519                 public Collection<AssemblyNameReference> ReadAssemblyReferences ()
520                 {
521                         InitializeAssemblyReferences ();
522
523                         return new Collection<AssemblyNameReference> (metadata.AssemblyReferences);
524                 }
525
526                 public MethodDefinition ReadEntryPoint ()
527                 {
528                         if (module.Kind != ModuleKind.Console && module.Kind != ModuleKind.Windows)
529                                 return null;
530
531                         var token = new MetadataToken (module.Image.EntryPointToken);
532
533                         return GetMethodDefinition (token.RID);
534                 }
535
536                 public Collection<ModuleDefinition> ReadModules ()
537                 {
538                         var modules = new Collection<ModuleDefinition> (1);
539                         modules.Add (this.module);
540
541                         int length = MoveTo (Table.File);
542                         for (uint i = 1; i <= length; i++) {
543                                 var attributes = (FileAttributes) ReadUInt32 ();
544                                 var name = ReadString ();
545                                 ReadBlobIndex ();
546
547                                 if (attributes != FileAttributes.ContainsMetaData)
548                                         continue;
549
550                                 var parameters = new ReaderParameters {
551                                         ReadingMode = module.ReadingMode,
552                                         SymbolReaderProvider = module.SymbolReaderProvider,
553                                 };
554
555                                 modules.Add (ModuleDefinition.ReadModule (
556                                         GetModuleFileName (name), parameters));
557                         }
558
559                         return modules;
560                 }
561
562                 string GetModuleFileName (string name)
563                 {
564                         if (module.FullyQualifiedName == null)
565                                 throw new NotSupportedException ();
566
567                         var path = Path.GetDirectoryName (module.FullyQualifiedName);
568                         return Path.Combine (path, name);
569                 }
570
571                 void InitializeModuleReferences ()
572                 {
573                         if (metadata.ModuleReferences != null)
574                                 return;
575
576                         int length = MoveTo (Table.ModuleRef);
577                         var references = metadata.ModuleReferences = new ModuleReference [length];
578
579                         for (uint i = 0; i < length; i++) {
580                                 var reference = new ModuleReference (ReadString ());
581                                 reference.token = new MetadataToken (TokenType.ModuleRef, i + 1);
582
583                                 references [i] = reference;
584                         }
585                 }
586
587                 public Collection<ModuleReference> ReadModuleReferences ()
588                 {
589                         InitializeModuleReferences ();
590
591                         return new Collection<ModuleReference> (metadata.ModuleReferences);
592                 }
593
594                 public bool HasFileResource ()
595                 {
596                         int length = MoveTo (Table.File);
597                         if (length == 0)
598                                 return false;
599
600                         for (uint i = 1; i <= length; i++)
601                                 if (ReadFileRecord (i).Col1 == FileAttributes.ContainsNoMetaData)
602                                         return true;
603
604                         return false;
605                 }
606
607                 public Collection<Resource> ReadResources ()
608                 {
609                         int length = MoveTo (Table.ManifestResource);
610                         var resources = new Collection<Resource> (length);
611
612                         for (int i = 1; i <= length; i++) {
613                                 var offset = ReadUInt32 ();
614                                 var flags = (ManifestResourceAttributes) ReadUInt32 ();
615                                 var name = ReadString ();
616                                 var implementation = ReadMetadataToken (CodedIndex.Implementation);
617
618                                 Resource resource;
619
620                                 if (implementation.RID == 0) {
621                                         resource = new EmbeddedResource (name, flags, offset, this);
622                                 } else if (implementation.TokenType == TokenType.AssemblyRef) {
623                                         resource = new AssemblyLinkedResource (name, flags) {
624                                                 Assembly = (AssemblyNameReference) GetTypeReferenceScope (implementation),
625                                         };
626                                 } else if (implementation.TokenType == TokenType.File) {
627                                         var file_record = ReadFileRecord (implementation.RID);
628
629                                         resource = new LinkedResource (name, flags) {
630                                                 File = file_record.Col2,
631                                                 hash = ReadBlob (file_record.Col3)
632                                         };
633                                 } else
634                                         throw new NotSupportedException ();
635
636                                 resources.Add (resource);
637                         }
638
639                         return resources;
640                 }
641
642                 Row<FileAttributes, string, uint> ReadFileRecord (uint rid)
643                 {
644                         var position = this.position;
645
646                         if (!MoveTo (Table.File, rid))
647                                 throw new ArgumentException ();
648
649                         var record = new Row<FileAttributes, string, uint> (
650                                 (FileAttributes) ReadUInt32 (),
651                                 ReadString (),
652                                 ReadBlobIndex ());
653
654                         this.position = position;
655
656                         return record;
657                 }
658
659                 public MemoryStream GetManagedResourceStream (uint offset)
660                 {
661                         var rva = image.Resources.VirtualAddress;
662                         var section = image.GetSectionAtVirtualAddress (rva);
663                         var position = (rva - section.VirtualAddress) + offset;
664                         var buffer = section.Data;
665
666                         var length = buffer [position]
667                                 | (buffer [position + 1] << 8)
668                                 | (buffer [position + 2] << 16)
669                                 | (buffer [position + 3] << 24);
670
671                         return new MemoryStream (buffer, (int) position + 4, length);
672                 }
673
674                 void PopulateVersionAndFlags (AssemblyNameReference name)
675                 {
676                         name.Version = new Version (
677                                 ReadUInt16 (),
678                                 ReadUInt16 (),
679                                 ReadUInt16 (),
680                                 ReadUInt16 ());
681
682                         name.Attributes = (AssemblyAttributes) ReadUInt32 ();
683                 }
684
685                 void PopulateNameAndCulture (AssemblyNameReference name)
686                 {
687                         name.Name = ReadString ();
688                         name.Culture = ReadString ();
689                 }
690
691                 public TypeDefinitionCollection ReadTypes ()
692                 {
693                         InitializeTypeDefinitions ();
694                         var mtypes = metadata.Types;
695                         var type_count = mtypes.Length - metadata.NestedTypes.Count;
696                         var types = new TypeDefinitionCollection (module, type_count);
697
698                         for (int i = 0; i < mtypes.Length; i++) {
699                                 var type = mtypes [i];
700                                 if (IsNested (type.Attributes))
701                                         continue;
702
703                                 types.Add (type);
704                         }
705
706                         if (image.HasTable (Table.MethodPtr) || image.HasTable (Table.FieldPtr))
707                                 CompleteTypes ();
708
709                         return types;
710                 }
711
712                 void CompleteTypes ()
713                 {
714                         var types = metadata.Types;
715
716                         for (int i = 0; i < types.Length; i++) {
717                                 var type = types [i];
718
719                                 InitializeCollection (type.Fields);
720                                 InitializeCollection (type.Methods);
721                         }
722                 }
723
724                 void InitializeTypeDefinitions ()
725                 {
726                         if (metadata.Types != null)
727                                 return;
728
729                         InitializeNestedTypes ();
730                         InitializeFields ();
731                         InitializeMethods ();
732
733                         int length = MoveTo (Table.TypeDef);
734                         var types = metadata.Types = new TypeDefinition [length];
735
736                         for (uint i = 0; i < length; i++) {
737                                 if (types [i] != null)
738                                         continue;
739
740                                 types [i] = ReadType (i + 1);
741                         }
742                 }
743
744                 static bool IsNested (TypeAttributes attributes)
745                 {
746                         switch (attributes & TypeAttributes.VisibilityMask) {
747                         case TypeAttributes.NestedAssembly:
748                         case TypeAttributes.NestedFamANDAssem:
749                         case TypeAttributes.NestedFamily:
750                         case TypeAttributes.NestedFamORAssem:
751                         case TypeAttributes.NestedPrivate:
752                         case TypeAttributes.NestedPublic:
753                                 return true;
754                         default:
755                                 return false;
756                         }
757                 }
758
759                 public bool HasNestedTypes (TypeDefinition type)
760                 {
761                         uint [] mapping;
762                         InitializeNestedTypes ();
763
764                         if (!metadata.TryGetNestedTypeMapping (type, out mapping))
765                                 return false;
766
767                         return mapping.Length > 0;
768                 }
769
770                 public Collection<TypeDefinition> ReadNestedTypes (TypeDefinition type)
771                 {
772                         InitializeNestedTypes ();
773                         uint [] mapping;
774                         if (!metadata.TryGetNestedTypeMapping (type, out mapping))
775                                 return new MemberDefinitionCollection<TypeDefinition> (type);
776
777                         var nested_types = new MemberDefinitionCollection<TypeDefinition> (type, mapping.Length);
778
779                         for (int i = 0; i < mapping.Length; i++)
780                                 nested_types.Add (GetTypeDefinition (mapping [i]));
781
782                         metadata.RemoveNestedTypeMapping (type);
783
784                         return nested_types;
785                 }
786
787                 void InitializeNestedTypes ()
788                 {
789                         if (metadata.NestedTypes != null)
790                                 return;
791
792                         var length = MoveTo (Table.NestedClass);
793
794                         metadata.NestedTypes = new Dictionary<uint, uint []> (length);
795                         metadata.ReverseNestedTypes = new Dictionary<uint, uint> (length);
796
797                         if (length == 0)
798                                 return;
799
800                         for (int i = 1; i <= length; i++) {
801                                 var nested = ReadTableIndex (Table.TypeDef);
802                                 var declaring = ReadTableIndex (Table.TypeDef);
803
804                                 AddNestedMapping (declaring, nested);
805                         }
806                 }
807
808                 void AddNestedMapping (uint declaring, uint nested)
809                 {
810                         metadata.SetNestedTypeMapping (declaring, AddMapping (metadata.NestedTypes, declaring, nested));
811                         metadata.SetReverseNestedTypeMapping (nested, declaring);
812                 }
813
814                 static TValue [] AddMapping<TKey, TValue> (Dictionary<TKey, TValue []> cache, TKey key, TValue value)
815                 {
816                         TValue [] mapped;
817                         if (!cache.TryGetValue (key, out mapped)) {
818                                 mapped = new [] { value };
819                                 return mapped;
820                         }
821
822                         var new_mapped = new TValue [mapped.Length + 1];
823                         Array.Copy (mapped, new_mapped, mapped.Length);
824                         new_mapped [mapped.Length] = value;
825                         return new_mapped;
826                 }
827
828                 TypeDefinition ReadType (uint rid)
829                 {
830                         if (!MoveTo (Table.TypeDef, rid))
831                                 return null;
832
833                         var attributes = (TypeAttributes) ReadUInt32 ();
834                         var name = ReadString ();
835                         var @namespace = ReadString ();
836                         var type = new TypeDefinition (@namespace, name, attributes);
837                         type.token = new MetadataToken (TokenType.TypeDef, rid);
838                         type.scope = module;
839                         type.module = module;
840
841                         metadata.AddTypeDefinition (type);
842
843                         this.context = type;
844
845                         type.BaseType = GetTypeDefOrRef (ReadMetadataToken (CodedIndex.TypeDefOrRef));
846
847                         type.fields_range = ReadFieldsRange (rid);
848                         type.methods_range = ReadMethodsRange (rid);
849
850                         if (IsNested (attributes))
851                                 type.DeclaringType = GetNestedTypeDeclaringType (type);
852
853                         return type;
854                 }
855
856                 TypeDefinition GetNestedTypeDeclaringType (TypeDefinition type)
857                 {
858                         uint declaring_rid;
859                         if (!metadata.TryGetReverseNestedTypeMapping (type, out declaring_rid))
860                                 return null;
861
862                         metadata.RemoveReverseNestedTypeMapping (type);
863                         return GetTypeDefinition (declaring_rid);
864                 }
865
866                 Range ReadFieldsRange (uint type_index)
867                 {
868                         return ReadListRange (type_index, Table.TypeDef, Table.Field);
869                 }
870
871                 Range ReadMethodsRange (uint type_index)
872                 {
873                         return ReadListRange (type_index, Table.TypeDef, Table.Method);
874                 }
875
876                 Range ReadListRange (uint current_index, Table current, Table target)
877                 {
878                         var list = new Range ();
879
880                         list.Start = ReadTableIndex (target);
881
882                         uint next_index;
883                         var current_table = image.TableHeap [current];
884
885                         if (current_index == current_table.Length)
886                                 next_index = image.TableHeap [target].Length + 1;
887                         else {
888                                 var position = Position;
889                                 Position += (uint) (current_table.RowSize - image.GetTableIndexSize (target));
890                                 next_index = ReadTableIndex (target);
891                                 Position = position;
892                         }
893
894                         list.Length = next_index - list.Start;
895
896                         return list;
897                 }
898
899                 public Row<short, int> ReadTypeLayout (TypeDefinition type)
900                 {
901                         InitializeTypeLayouts ();
902                         Row<ushort, uint> class_layout;
903                         var rid = type.token.RID;
904                         if (!metadata.ClassLayouts.TryGetValue (rid, out class_layout))
905                                 return new Row<short, int> (Mixin.NoDataMarker, Mixin.NoDataMarker);
906
907                         type.PackingSize = (short) class_layout.Col1;
908                         type.ClassSize = (int) class_layout.Col2;
909
910                         metadata.ClassLayouts.Remove (rid);
911
912                         return new Row<short, int> ((short) class_layout.Col1, (int) class_layout.Col2);
913                 }
914
915                 void InitializeTypeLayouts ()
916                 {
917                         if (metadata.ClassLayouts != null)
918                                 return;
919
920                         int length = MoveTo (Table.ClassLayout);
921
922                         var class_layouts = metadata.ClassLayouts = new Dictionary<uint, Row<ushort, uint>> (length);
923
924                         for (uint i = 0; i < length; i++) {
925                                 var packing_size = ReadUInt16 ();
926                                 var class_size = ReadUInt32 ();
927
928                                 var parent = ReadTableIndex (Table.TypeDef);
929
930                                 class_layouts.Add (parent, new Row<ushort, uint> (packing_size, class_size));
931                         }
932                 }
933
934                 public TypeReference GetTypeDefOrRef (MetadataToken token)
935                 {
936                         return (TypeReference) LookupToken (token);
937                 }
938
939                 public TypeDefinition GetTypeDefinition (uint rid)
940                 {
941                         InitializeTypeDefinitions ();
942
943                         var type = metadata.GetTypeDefinition (rid);
944                         if (type != null)
945                                 return type;
946
947                         return ReadTypeDefinition (rid);
948                 }
949
950                 TypeDefinition ReadTypeDefinition (uint rid)
951                 {
952                         if (!MoveTo (Table.TypeDef, rid))
953                                 return null;
954
955                         return ReadType (rid);
956                 }
957
958                 void InitializeTypeReferences ()
959                 {
960                         if (metadata.TypeReferences != null)
961                                 return;
962
963                         metadata.TypeReferences = new TypeReference [image.GetTableLength (Table.TypeRef)];
964                 }
965
966                 public TypeReference GetTypeReference (string scope, string full_name)
967                 {
968                         InitializeTypeReferences ();
969
970                         var length = metadata.TypeReferences.Length;
971
972                         for (uint i = 1; i <= length; i++) {
973                                 var type = GetTypeReference (i);
974
975                                 if (type.FullName != full_name)
976                                         continue;
977
978                                 if (string.IsNullOrEmpty (scope))
979                                         return type;
980
981                                 if (type.Scope.Name == scope)
982                                         return type;
983                         }
984
985                         return null;
986                 }
987
988                 TypeReference GetTypeReference (uint rid)
989                 {
990                         InitializeTypeReferences ();
991
992                         var type = metadata.GetTypeReference (rid);
993                         if (type != null)
994                                 return type;
995
996                         return ReadTypeReference (rid);
997                 }
998
999                 TypeReference ReadTypeReference (uint rid)
1000                 {
1001                         if (!MoveTo (Table.TypeRef, rid))
1002                                 return null;
1003
1004                         TypeReference declaring_type = null;
1005                         IMetadataScope scope;
1006
1007                         var scope_token = ReadMetadataToken (CodedIndex.ResolutionScope);
1008
1009                         var name = ReadString ();
1010                         var @namespace = ReadString ();
1011
1012                         var type = new TypeReference (
1013                                 @namespace,
1014                                 name,
1015                                 module,
1016                                 null);
1017
1018                         type.token = new MetadataToken (TokenType.TypeRef, rid);
1019
1020                         metadata.AddTypeReference (type);
1021
1022                         if (scope_token.TokenType == TokenType.TypeRef) {
1023                                 declaring_type = GetTypeDefOrRef (scope_token);
1024
1025                                 scope = declaring_type != null
1026                                         ? declaring_type.Scope
1027                                         : module;
1028                         } else
1029                                 scope = GetTypeReferenceScope (scope_token);
1030
1031                         type.scope = scope;
1032                         type.DeclaringType = declaring_type;
1033
1034                         MetadataSystem.TryProcessPrimitiveType (type);
1035
1036                         return type;
1037                 }
1038
1039                 IMetadataScope GetTypeReferenceScope (MetadataToken scope)
1040                 {
1041                         switch (scope.TokenType) {
1042                         case TokenType.AssemblyRef:
1043                                 InitializeAssemblyReferences ();
1044                                 return metadata.AssemblyReferences [(int) scope.RID - 1];
1045                         case TokenType.ModuleRef:
1046                                 InitializeModuleReferences ();
1047                                 return metadata.ModuleReferences [(int) scope.RID - 1];
1048                         case TokenType.Module:
1049                                 return module;
1050                         default:
1051                                 throw new NotSupportedException ();
1052                         }
1053                 }
1054
1055                 public IEnumerable<TypeReference> GetTypeReferences ()
1056                 {
1057                         InitializeTypeReferences ();
1058
1059                         var length = image.GetTableLength (Table.TypeRef);
1060
1061                         var type_references = new TypeReference [length];
1062
1063                         for (uint i = 1; i <= length; i++)
1064                                 type_references [i - 1] = GetTypeReference (i);
1065
1066                         return type_references;
1067                 }
1068
1069                 TypeReference GetTypeSpecification (uint rid)
1070                 {
1071                         if (!MoveTo (Table.TypeSpec, rid))
1072                                 return null;
1073
1074                         var reader = ReadSignature (ReadBlobIndex ());
1075                         var type = reader.ReadTypeSignature ();
1076                         if (type.token.RID == 0)
1077                                 type.token = new MetadataToken (TokenType.TypeSpec, rid);
1078
1079                         return type;
1080                 }
1081
1082                 SignatureReader ReadSignature (uint signature)
1083                 {
1084                         return new SignatureReader (signature, this);
1085                 }
1086
1087                 public bool HasInterfaces (TypeDefinition type)
1088                 {
1089                         InitializeInterfaces ();
1090                         MetadataToken [] mapping;
1091
1092                         return metadata.TryGetInterfaceMapping (type, out mapping);
1093                 }
1094
1095                 public Collection<TypeReference> ReadInterfaces (TypeDefinition type)
1096                 {
1097                         InitializeInterfaces ();
1098                         MetadataToken [] mapping;
1099
1100                         if (!metadata.TryGetInterfaceMapping (type, out mapping))
1101                                 return new Collection<TypeReference> ();
1102
1103                         var interfaces = new Collection<TypeReference> (mapping.Length);
1104
1105                         this.context = type;
1106
1107                         for (int i = 0; i < mapping.Length; i++)
1108                                 interfaces.Add (GetTypeDefOrRef (mapping [i]));
1109
1110                         metadata.RemoveInterfaceMapping (type);
1111
1112                         return interfaces;
1113                 }
1114
1115                 void InitializeInterfaces ()
1116                 {
1117                         if (metadata.Interfaces != null)
1118                                 return;
1119
1120                         int length = MoveTo (Table.InterfaceImpl);
1121
1122                         metadata.Interfaces = new Dictionary<uint, MetadataToken []> (length);
1123
1124                         for (int i = 0; i < length; i++) {
1125                                 var type = ReadTableIndex (Table.TypeDef);
1126                                 var @interface = ReadMetadataToken (CodedIndex.TypeDefOrRef);
1127
1128                                 AddInterfaceMapping (type, @interface);
1129                         }
1130                 }
1131
1132                 void AddInterfaceMapping (uint type, MetadataToken @interface)
1133                 {
1134                         metadata.SetInterfaceMapping (type, AddMapping (metadata.Interfaces, type, @interface));
1135                 }
1136
1137                 public Collection<FieldDefinition> ReadFields (TypeDefinition type)
1138                 {
1139                         var fields_range = type.fields_range;
1140                         if (fields_range.Length == 0)
1141                                 return new MemberDefinitionCollection<FieldDefinition> (type);
1142
1143                         var fields = new MemberDefinitionCollection<FieldDefinition> (type, (int) fields_range.Length);
1144                         this.context = type;
1145
1146                         if (!MoveTo (Table.FieldPtr, fields_range.Start)) {
1147                                 if (!MoveTo (Table.Field, fields_range.Start))
1148                                         return fields;
1149
1150                                 for (uint i = 0; i < fields_range.Length; i++)
1151                                         ReadField (fields_range.Start + i, fields);
1152                         } else
1153                                 ReadPointers (Table.FieldPtr, Table.Field, fields_range, fields, ReadField);
1154
1155                         return fields;
1156                 }
1157
1158                 void ReadField (uint field_rid, Collection<FieldDefinition> fields)
1159                 {
1160                         var attributes = (FieldAttributes) ReadUInt16 ();
1161                         var name = ReadString ();
1162                         var signature = ReadBlobIndex ();
1163
1164                         var field = new FieldDefinition (name, attributes, ReadFieldType (signature));
1165                         field.token = new MetadataToken (TokenType.Field, field_rid);
1166                         metadata.AddFieldDefinition (field);
1167
1168                         if (IsDeleted (field))
1169                                 return;
1170
1171                         fields.Add (field);
1172                 }
1173
1174                 void InitializeFields ()
1175                 {
1176                         if (metadata.Fields != null)
1177                                 return;
1178
1179                         metadata.Fields = new FieldDefinition [image.GetTableLength (Table.Field)];
1180                 }
1181
1182                 TypeReference ReadFieldType (uint signature)
1183                 {
1184                         var reader = ReadSignature (signature);
1185
1186                         const byte field_sig = 0x6;
1187
1188                         if (reader.ReadByte () != field_sig)
1189                                 throw new NotSupportedException ();
1190
1191                         return reader.ReadTypeSignature ();
1192                 }
1193
1194                 public int ReadFieldRVA (FieldDefinition field)
1195                 {
1196                         InitializeFieldRVAs ();
1197                         var rid = field.token.RID;
1198
1199                         RVA rva;
1200                         if (!metadata.FieldRVAs.TryGetValue (rid, out rva))
1201                                 return 0;
1202
1203                         var size = GetFieldTypeSize (field.FieldType);
1204
1205                         if (size == 0 || rva == 0)
1206                                 return 0;
1207
1208                         metadata.FieldRVAs.Remove (rid);
1209
1210                         field.InitialValue = GetFieldInitializeValue (size, rva);
1211
1212                         return (int) rva;
1213                 }
1214
1215                 byte [] GetFieldInitializeValue (int size, RVA rva)
1216                 {
1217                         var section = image.GetSectionAtVirtualAddress (rva);
1218                         if (section == null)
1219                                 return Empty<byte>.Array;
1220
1221                         var value = new byte [size];
1222                         Buffer.BlockCopy (section.Data, (int) (rva - section.VirtualAddress), value, 0, size);
1223                         return value;
1224                 }
1225
1226                 static int GetFieldTypeSize (TypeReference type)
1227                 {
1228                         int size = 0;
1229
1230                         switch (type.etype) {
1231                         case ElementType.Boolean:
1232                         case ElementType.U1:
1233                         case ElementType.I1:
1234                                 size = 1;
1235                                 break;
1236                         case ElementType.U2:
1237                         case ElementType.I2:
1238                         case ElementType.Char:
1239                                 size = 2;
1240                                 break;
1241                         case ElementType.U4:
1242                         case ElementType.I4:
1243                         case ElementType.R4:
1244                                 size = 4;
1245                                 break;
1246                         case ElementType.U8:
1247                         case ElementType.I8:
1248                         case ElementType.R8:
1249                                 size = 8;
1250                                 break;
1251                         case ElementType.Ptr:
1252                         case ElementType.FnPtr:
1253                                 size = IntPtr.Size;
1254                                 break;
1255                         case ElementType.CModOpt:
1256                         case ElementType.CModReqD:
1257                                 return GetFieldTypeSize (((IModifierType) type).ElementType);
1258                         default:
1259                                 var field_type = type.CheckedResolve ();
1260                                 if (field_type.HasLayoutInfo)
1261                                         size = field_type.ClassSize;
1262
1263                                 break;
1264                         }
1265
1266                         return size;
1267                 }
1268
1269                 void InitializeFieldRVAs ()
1270                 {
1271                         if (metadata.FieldRVAs != null)
1272                                 return;
1273
1274                         int length = MoveTo (Table.FieldRVA);
1275
1276                         var field_rvas = metadata.FieldRVAs = new Dictionary<uint, uint> (length);
1277
1278                         for (int i = 0; i < length; i++) {
1279                                 var rva = ReadUInt32 ();
1280                                 var field = ReadTableIndex (Table.Field);
1281
1282                                 field_rvas.Add (field, rva);
1283                         }
1284                 }
1285
1286                 public int ReadFieldLayout (FieldDefinition field)
1287                 {
1288                         InitializeFieldLayouts ();
1289                         var rid = field.token.RID;
1290                         uint offset;
1291                         if (!metadata.FieldLayouts.TryGetValue (rid, out offset))
1292                                 return Mixin.NoDataMarker;
1293
1294                         metadata.FieldLayouts.Remove (rid);
1295
1296                         return (int) offset;
1297                 }
1298
1299                 void InitializeFieldLayouts ()
1300                 {
1301                         if (metadata.FieldLayouts != null)
1302                                 return;
1303
1304                         int length = MoveTo (Table.FieldLayout);
1305
1306                         var field_layouts = metadata.FieldLayouts = new Dictionary<uint, uint> (length);
1307
1308                         for (int i = 0; i < length; i++) {
1309                                 var offset = ReadUInt32 ();
1310                                 var field = ReadTableIndex (Table.Field);
1311
1312                                 field_layouts.Add (field, offset);
1313                         }
1314                 }
1315
1316                 public bool HasEvents (TypeDefinition type)
1317                 {
1318                         InitializeEvents ();
1319
1320                         Range range;
1321                         if (!metadata.TryGetEventsRange (type, out range))
1322                                 return false;
1323
1324                         return range.Length > 0;
1325                 }
1326
1327                 public Collection<EventDefinition> ReadEvents (TypeDefinition type)
1328                 {
1329                         InitializeEvents ();
1330                         Range range;
1331
1332                         if (!metadata.TryGetEventsRange (type, out range))
1333                                 return new MemberDefinitionCollection<EventDefinition> (type);
1334
1335                         var events = new MemberDefinitionCollection<EventDefinition> (type, (int) range.Length);
1336
1337                         metadata.RemoveEventsRange (type);
1338
1339                         if (range.Length == 0)
1340                                 return events;
1341
1342                         this.context = type;
1343
1344                         if (!MoveTo (Table.EventPtr, range.Start)) {
1345                                 if (!MoveTo (Table.Event, range.Start))
1346                                         return events;
1347
1348                                 for (uint i = 0; i < range.Length; i++)
1349                                         ReadEvent (range.Start + i, events);
1350                         } else
1351                                 ReadPointers (Table.EventPtr, Table.Event, range, events, ReadEvent);
1352
1353                         return events;
1354                 }
1355
1356                 void ReadEvent (uint event_rid, Collection<EventDefinition> events)
1357                 {
1358                         var attributes = (EventAttributes) ReadUInt16 ();
1359                         var name = ReadString ();
1360                         var event_type = GetTypeDefOrRef (ReadMetadataToken (CodedIndex.TypeDefOrRef));
1361
1362                         var @event = new EventDefinition (name, attributes, event_type);
1363                         @event.token = new MetadataToken (TokenType.Event, event_rid);
1364
1365                         if (IsDeleted (@event))
1366                                 return;
1367
1368                         events.Add (@event);
1369                 }
1370
1371                 void InitializeEvents ()
1372                 {
1373                         if (metadata.Events != null)
1374                                 return;
1375
1376                         int length = MoveTo (Table.EventMap);
1377
1378                         metadata.Events = new Dictionary<uint, Range> (length);
1379
1380                         for (uint i = 1; i <= length; i++) {
1381                                 var type_rid = ReadTableIndex (Table.TypeDef);
1382                                 Range events_range = ReadEventsRange (i);
1383                                 metadata.AddEventsRange (type_rid, events_range);
1384                         }
1385                 }
1386
1387                 Range ReadEventsRange (uint rid)
1388                 {
1389                         return ReadListRange (rid, Table.EventMap, Table.Event);
1390                 }
1391
1392                 public bool HasProperties (TypeDefinition type)
1393                 {
1394                         InitializeProperties ();
1395
1396                         Range range;
1397                         if (!metadata.TryGetPropertiesRange (type, out range))
1398                                 return false;
1399
1400                         return range.Length > 0;
1401                 }
1402
1403                 public Collection<PropertyDefinition> ReadProperties (TypeDefinition type)
1404                 {
1405                         InitializeProperties ();
1406
1407                         Range range;
1408
1409                         if (!metadata.TryGetPropertiesRange (type, out range))
1410                                 return new MemberDefinitionCollection<PropertyDefinition> (type);
1411
1412                         metadata.RemovePropertiesRange (type);
1413
1414                         var properties = new MemberDefinitionCollection<PropertyDefinition> (type, (int) range.Length);
1415
1416                         if (range.Length == 0)
1417                                 return properties;
1418
1419                         this.context = type;
1420
1421                         if (!MoveTo (Table.PropertyPtr, range.Start)) {
1422                                 if (!MoveTo (Table.Property, range.Start))
1423                                         return properties;
1424                                 for (uint i = 0; i < range.Length; i++)
1425                                         ReadProperty (range.Start + i, properties);
1426                         } else
1427                                 ReadPointers (Table.PropertyPtr, Table.Property, range, properties, ReadProperty);
1428
1429                         return properties;
1430                 }
1431
1432                 void ReadProperty (uint property_rid, Collection<PropertyDefinition> properties)
1433                 {
1434                         var attributes = (PropertyAttributes) ReadUInt16 ();
1435                         var name = ReadString ();
1436                         var signature = ReadBlobIndex ();
1437
1438                         var reader = ReadSignature (signature);
1439                         const byte property_signature = 0x8;
1440
1441                         var calling_convention = reader.ReadByte ();
1442
1443                         if ((calling_convention & property_signature) == 0)
1444                                 throw new NotSupportedException ();
1445
1446                         var has_this = (calling_convention & 0x20) != 0;
1447
1448                         reader.ReadCompressedUInt32 (); // count
1449
1450                         var property = new PropertyDefinition (name, attributes, reader.ReadTypeSignature ());
1451                         property.HasThis = has_this;
1452                         property.token = new MetadataToken (TokenType.Property, property_rid);
1453
1454                         if (IsDeleted (property))
1455                                 return;
1456
1457                         properties.Add (property);
1458                 }
1459
1460                 void InitializeProperties ()
1461                 {
1462                         if (metadata.Properties != null)
1463                                 return;
1464
1465                         int length = MoveTo (Table.PropertyMap);
1466
1467                         metadata.Properties = new Dictionary<uint, Range> (length);
1468
1469                         for (uint i = 1; i <= length; i++) {
1470                                 var type_rid = ReadTableIndex (Table.TypeDef);
1471                                 var properties_range = ReadPropertiesRange (i);
1472                                 metadata.AddPropertiesRange (type_rid, properties_range);
1473                         }
1474                 }
1475
1476                 Range ReadPropertiesRange (uint rid)
1477                 {
1478                         return ReadListRange (rid, Table.PropertyMap, Table.Property);
1479                 }
1480
1481                 MethodSemanticsAttributes ReadMethodSemantics (MethodDefinition method)
1482                 {
1483                         InitializeMethodSemantics ();
1484                         Row<MethodSemanticsAttributes, MetadataToken> row;
1485                         if (!metadata.Semantics.TryGetValue (method.token.RID, out row))
1486                                 return MethodSemanticsAttributes.None;
1487
1488                         var type = method.DeclaringType;
1489
1490                         switch (row.Col1) {
1491                         case MethodSemanticsAttributes.AddOn:
1492                                 GetEvent (type, row.Col2).add_method = method;
1493                                 break;
1494                         case MethodSemanticsAttributes.Fire:
1495                                 GetEvent (type, row.Col2).invoke_method = method;
1496                                 break;
1497                         case MethodSemanticsAttributes.RemoveOn:
1498                                 GetEvent (type, row.Col2).remove_method = method;
1499                                 break;
1500                         case MethodSemanticsAttributes.Getter:
1501                                 GetProperty (type, row.Col2).get_method = method;
1502                                 break;
1503                         case MethodSemanticsAttributes.Setter:
1504                                 GetProperty (type, row.Col2).set_method = method;
1505                                 break;
1506                         case MethodSemanticsAttributes.Other:
1507                                 switch (row.Col2.TokenType) {
1508                                 case TokenType.Event: {
1509                                         var @event = GetEvent (type, row.Col2);
1510                                         if (@event.other_methods == null)
1511                                                 @event.other_methods = new Collection<MethodDefinition> ();
1512
1513                                         @event.other_methods.Add (method);
1514                                         break;
1515                                 }
1516                                 case TokenType.Property: {
1517                                         var property = GetProperty (type, row.Col2);
1518                                         if (property.other_methods == null)
1519                                                 property.other_methods = new Collection<MethodDefinition> ();
1520
1521                                         property.other_methods.Add (method);
1522
1523                                         break;
1524                                 }
1525                                 default:
1526                                         throw new NotSupportedException ();
1527                                 }
1528                                 break;
1529                         default:
1530                                 throw new NotSupportedException ();
1531                         }
1532
1533                         metadata.Semantics.Remove (method.token.RID);
1534
1535                         return row.Col1;
1536                 }
1537
1538                 static EventDefinition GetEvent (TypeDefinition type, MetadataToken token)
1539                 {
1540                         if (token.TokenType != TokenType.Event)
1541                                 throw new ArgumentException ();
1542
1543                         return GetMember (type.Events, token);
1544                 }
1545
1546                 static PropertyDefinition GetProperty (TypeDefinition type, MetadataToken token)
1547                 {
1548                         if (token.TokenType != TokenType.Property)
1549                                 throw new ArgumentException ();
1550
1551                         return GetMember (type.Properties, token);
1552                 }
1553
1554                 static TMember GetMember<TMember> (Collection<TMember> members, MetadataToken token) where TMember : IMemberDefinition
1555                 {
1556                         for (int i = 0; i < members.Count; i++) {
1557                                 var member = members [i];
1558                                 if (member.MetadataToken == token)
1559                                         return member;
1560                         }
1561
1562                         throw new ArgumentException ();
1563                 }
1564
1565                 void InitializeMethodSemantics ()
1566                 {
1567                         if (metadata.Semantics != null)
1568                                 return;
1569
1570                         int length = MoveTo (Table.MethodSemantics);
1571
1572                         var semantics = metadata.Semantics = new Dictionary<uint, Row<MethodSemanticsAttributes, MetadataToken>> (0);
1573
1574                         for (uint i = 0; i < length; i++) {
1575                                 var attributes = (MethodSemanticsAttributes) ReadUInt16 ();
1576                                 var method_rid = ReadTableIndex (Table.Method);
1577                                 var association = ReadMetadataToken (CodedIndex.HasSemantics);
1578
1579                                 semantics [method_rid] = new Row<MethodSemanticsAttributes, MetadataToken> (attributes, association);
1580                         }
1581                 }
1582
1583                 public PropertyDefinition ReadMethods (PropertyDefinition property)
1584                 {
1585                         ReadAllSemantics (property.DeclaringType);
1586                         return property;
1587                 }
1588
1589                 public EventDefinition ReadMethods (EventDefinition @event)
1590                 {
1591                         ReadAllSemantics (@event.DeclaringType);
1592                         return @event;
1593                 }
1594
1595                 public MethodSemanticsAttributes ReadAllSemantics (MethodDefinition method)
1596                 {
1597                         ReadAllSemantics (method.DeclaringType);
1598
1599                         return method.SemanticsAttributes;
1600                 }
1601
1602                 void ReadAllSemantics (TypeDefinition type)
1603                 {
1604                         var methods = type.Methods;
1605                         for (int i = 0; i < methods.Count; i++) {
1606                                 var method = methods [i];
1607                                 if (method.sem_attrs.HasValue)
1608                                         continue;
1609
1610                                 method.sem_attrs = ReadMethodSemantics (method);
1611                         }
1612                 }
1613
1614                 Range ReadParametersRange (uint method_rid)
1615                 {
1616                         return ReadListRange (method_rid, Table.Method, Table.Param);
1617                 }
1618
1619                 public Collection<MethodDefinition> ReadMethods (TypeDefinition type)
1620                 {
1621                         var methods_range = type.methods_range;
1622                         if (methods_range.Length == 0)
1623                                 return new MemberDefinitionCollection<MethodDefinition> (type);
1624
1625                         var methods = new MemberDefinitionCollection<MethodDefinition> (type, (int) methods_range.Length);
1626                         if (!MoveTo (Table.MethodPtr, methods_range.Start)) {
1627                                 if (!MoveTo (Table.Method, methods_range.Start))
1628                                         return methods;
1629
1630                                 for (uint i = 0; i < methods_range.Length; i++)
1631                                         ReadMethod (methods_range.Start + i, methods);
1632                         } else
1633                                 ReadPointers (Table.MethodPtr, Table.Method, methods_range, methods, ReadMethod);
1634
1635                         return methods;
1636                 }
1637
1638                 void ReadPointers<TMember> (Table ptr, Table table, Range range, Collection<TMember> members, Action<uint, Collection<TMember>> reader)
1639                         where TMember : IMemberDefinition
1640                 {
1641                         for (uint i = 0; i < range.Length; i++) {
1642                                 MoveTo (ptr, range.Start + i);
1643
1644                                 var rid = ReadTableIndex (table);
1645                                 MoveTo (table, rid);
1646
1647                                 reader (rid, members);
1648                         }
1649                 }
1650
1651                 static bool IsDeleted (IMemberDefinition member)
1652                 {
1653                         return member.IsSpecialName && member.Name == "_Deleted";
1654                 }
1655
1656                 void InitializeMethods ()
1657                 {
1658                         if (metadata.Methods != null)
1659                                 return;
1660
1661                         metadata.Methods = new MethodDefinition [image.GetTableLength (Table.Method)];
1662                 }
1663
1664                 void ReadMethod (uint method_rid, Collection<MethodDefinition> methods)
1665                 {
1666                         var method = new MethodDefinition ();
1667                         method.rva = ReadUInt32 ();
1668                         method.ImplAttributes = (MethodImplAttributes) ReadUInt16 ();
1669                         method.Attributes = (MethodAttributes) ReadUInt16 ();
1670                         method.Name = ReadString ();
1671                         method.token = new MetadataToken (TokenType.Method, method_rid);
1672
1673                         if (IsDeleted (method))
1674                                 return;
1675
1676                         methods.Add (method); // attach method
1677
1678                         var signature = ReadBlobIndex ();
1679                         var param_range = ReadParametersRange (method_rid);
1680
1681                         this.context = method;
1682
1683                         ReadMethodSignature (signature, method);
1684                         metadata.AddMethodDefinition (method);
1685
1686                         if (param_range.Length == 0)
1687                                 return;
1688
1689                         var position = base.position;
1690                         ReadParameters (method, param_range);
1691                         base.position = position;
1692                 }
1693
1694                 void ReadParameters (MethodDefinition method, Range param_range)
1695                 {
1696                         if (!MoveTo (Table.ParamPtr, param_range.Start)) {
1697                                 if (!MoveTo (Table.Param, param_range.Start))
1698                                         return;
1699
1700                                 for (uint i = 0; i < param_range.Length; i++)
1701                                         ReadParameter (param_range.Start + i, method);
1702                         } else
1703                                 ReadParameterPointers (method, param_range);
1704                 }
1705
1706                 void ReadParameterPointers (MethodDefinition method, Range range)
1707                 {
1708                         for (uint i = 0; i < range.Length; i++) {
1709                                 MoveTo (Table.ParamPtr, range.Start + i);
1710
1711                                 var rid = ReadTableIndex (Table.Param);
1712
1713                                 MoveTo (Table.Param, rid);
1714
1715                                 ReadParameter (rid, method);
1716                         }
1717                 }
1718
1719                 void ReadParameter (uint param_rid, MethodDefinition method)
1720                 {
1721                         var attributes = (ParameterAttributes) ReadUInt16 ();
1722                         var sequence = ReadUInt16 ();
1723                         var name = ReadString ();
1724
1725                         var parameter = sequence == 0
1726                                 ? method.MethodReturnType.Parameter
1727                                 : method.Parameters [sequence - 1];
1728
1729                         parameter.token = new MetadataToken (TokenType.Param, param_rid);
1730                         parameter.Name = name;
1731                         parameter.Attributes = attributes;
1732                 }
1733
1734                 void ReadMethodSignature (uint signature, IMethodSignature method)
1735                 {
1736                         var reader = ReadSignature (signature);
1737                         reader.ReadMethodSignature (method);
1738                 }
1739
1740                 public PInvokeInfo ReadPInvokeInfo (MethodDefinition method)
1741                 {
1742                         InitializePInvokes ();
1743                         Row<PInvokeAttributes, uint, uint> row;
1744
1745                         var rid = method.token.RID;
1746
1747                         if (!metadata.PInvokes.TryGetValue (rid, out row))
1748                                 return null;
1749
1750                         metadata.PInvokes.Remove (rid);
1751
1752                         return new PInvokeInfo (
1753                                 row.Col1,
1754                                 image.StringHeap.Read (row.Col2),
1755                                 module.ModuleReferences [(int) row.Col3 - 1]);
1756                 }
1757
1758                 void InitializePInvokes ()
1759                 {
1760                         if (metadata.PInvokes != null)
1761                                 return;
1762
1763                         int length = MoveTo (Table.ImplMap);
1764
1765                         var pinvokes = metadata.PInvokes = new Dictionary<uint, Row<PInvokeAttributes, uint, uint>> (length);
1766
1767                         for (int i = 1; i <= length; i++) {
1768                                 var attributes = (PInvokeAttributes) ReadUInt16 ();
1769                                 var method = ReadMetadataToken (CodedIndex.MemberForwarded);
1770                                 var name = ReadStringIndex ();
1771                                 var scope = ReadTableIndex (Table.File);
1772
1773                                 if (method.TokenType != TokenType.Method)
1774                                         continue;
1775
1776                                 pinvokes.Add (method.RID, new Row<PInvokeAttributes, uint, uint> (attributes, name, scope));
1777                         }
1778                 }
1779
1780                 public bool HasGenericParameters (IGenericParameterProvider provider)
1781                 {
1782                         InitializeGenericParameters ();
1783
1784                         Range range;
1785                         if (!metadata.TryGetGenericParameterRange (provider, out range))
1786                                 return false;
1787
1788                         return range.Length > 0;
1789                 }
1790
1791                 public Collection<GenericParameter> ReadGenericParameters (IGenericParameterProvider provider)
1792                 {
1793                         InitializeGenericParameters ();
1794
1795                         Range range;
1796                         if (!metadata.TryGetGenericParameterRange (provider, out range)
1797                                 || !MoveTo (Table.GenericParam, range.Start))
1798                                 return new Collection<GenericParameter> ();
1799
1800                         metadata.RemoveGenericParameterRange (provider);
1801
1802                         var generic_parameters = new Collection<GenericParameter> ((int) range.Length);
1803
1804                         for (uint i = 0; i < range.Length; i++) {
1805                                 ReadUInt16 (); // index
1806                                 var flags = (GenericParameterAttributes) ReadUInt16 ();
1807                                 ReadMetadataToken (CodedIndex.TypeOrMethodDef);
1808                                 var name = ReadString ();
1809
1810                                 var parameter = new GenericParameter (name, provider);
1811                                 parameter.token = new MetadataToken (TokenType.GenericParam, range.Start + i);
1812                                 parameter.Attributes = flags;
1813
1814                                 generic_parameters.Add (parameter);
1815                         }
1816
1817                         return generic_parameters;
1818                 }
1819
1820                 void InitializeGenericParameters ()
1821                 {
1822                         if (metadata.GenericParameters != null)
1823                                 return;
1824
1825                         metadata.GenericParameters = InitializeRanges (
1826                                 Table.GenericParam, () => {
1827                                         Advance (4);
1828                                         var next = ReadMetadataToken (CodedIndex.TypeOrMethodDef);
1829                                         ReadStringIndex ();
1830                                         return next;
1831                         });
1832                 }
1833
1834                 Dictionary<MetadataToken, Range> InitializeRanges (Table table, Func<MetadataToken> get_next)
1835                 {
1836                         int length = MoveTo (table);
1837                         var ranges = new Dictionary<MetadataToken, Range> (length);
1838
1839                         if (length == 0)
1840                                 return ranges;
1841
1842                         MetadataToken owner = MetadataToken.Zero;
1843                         Range range = new Range (1, 0);
1844
1845                         for (uint i = 1; i <= length; i++) {
1846                                 var next = get_next ();
1847
1848                                 if (i == 1) {
1849                                         owner = next;
1850                                         range.Length++;
1851                                 } else if (next != owner) {
1852                                         if (owner.RID != 0)
1853                                                 ranges.Add (owner, range);
1854                                         range = new Range (i, 1);
1855                                         owner = next;
1856                                 } else
1857                                         range.Length++;
1858                         }
1859
1860                         if (owner != MetadataToken.Zero && !ranges.ContainsKey (owner))
1861                                 ranges.Add (owner, range);
1862
1863                         return ranges;
1864                 }
1865
1866                 public bool HasGenericConstraints (GenericParameter generic_parameter)
1867                 {
1868                         InitializeGenericConstraints ();
1869
1870                         MetadataToken [] mapping;
1871                         if (!metadata.TryGetGenericConstraintMapping (generic_parameter, out mapping))
1872                                 return false;
1873
1874                         return mapping.Length > 0;
1875                 }
1876
1877                 public Collection<TypeReference> ReadGenericConstraints (GenericParameter generic_parameter)
1878                 {
1879                         InitializeGenericConstraints ();
1880
1881                         MetadataToken [] mapping;
1882                         if (!metadata.TryGetGenericConstraintMapping (generic_parameter, out mapping))
1883                                 return new Collection<TypeReference> ();
1884
1885                         var constraints = new Collection<TypeReference> (mapping.Length);
1886
1887                         this.context = (IGenericContext) generic_parameter.Owner;
1888
1889                         for (int i = 0; i < mapping.Length; i++)
1890                                 constraints.Add (GetTypeDefOrRef (mapping [i]));
1891
1892                         metadata.RemoveGenericConstraintMapping (generic_parameter);
1893
1894                         return constraints;
1895                 }
1896
1897                 void InitializeGenericConstraints ()
1898                 {
1899                         if (metadata.GenericConstraints != null)
1900                                 return;
1901
1902                         var length = MoveTo (Table.GenericParamConstraint);
1903
1904                         metadata.GenericConstraints = new Dictionary<uint, MetadataToken []> (length);
1905
1906                         for (int i = 1; i <= length; i++)
1907                                 AddGenericConstraintMapping (
1908                                         ReadTableIndex (Table.GenericParam),
1909                                         ReadMetadataToken (CodedIndex.TypeDefOrRef));
1910                 }
1911
1912                 void AddGenericConstraintMapping (uint generic_parameter, MetadataToken constraint)
1913                 {
1914                         metadata.SetGenericConstraintMapping (
1915                                 generic_parameter,
1916                                 AddMapping (metadata.GenericConstraints, generic_parameter, constraint));
1917                 }
1918
1919                 public bool HasOverrides (MethodDefinition method)
1920                 {
1921                         InitializeOverrides ();
1922                         MetadataToken [] mapping;
1923
1924                         if (!metadata.TryGetOverrideMapping (method, out mapping))
1925                                 return false;
1926
1927                         return mapping.Length > 0;
1928                 }
1929
1930                 public Collection<MethodReference> ReadOverrides (MethodDefinition method)
1931                 {
1932                         InitializeOverrides ();
1933
1934                         MetadataToken [] mapping;
1935                         if (!metadata.TryGetOverrideMapping (method, out mapping))
1936                                 return new Collection<MethodReference> ();
1937
1938                         var overrides = new Collection<MethodReference> (mapping.Length);
1939
1940                         this.context = method;
1941
1942                         for (int i = 0; i < mapping.Length; i++)
1943                                 overrides.Add ((MethodReference) LookupToken (mapping [i]));
1944
1945                         metadata.RemoveOverrideMapping (method);
1946
1947                         return overrides;
1948                 }
1949
1950                 void InitializeOverrides ()
1951                 {
1952                         if (metadata.Overrides != null)
1953                                 return;
1954
1955                         var length = MoveTo (Table.MethodImpl);
1956
1957                         metadata.Overrides = new Dictionary<uint, MetadataToken []> (length);
1958
1959                         for (int i = 1; i <= length; i++) {
1960                                 ReadTableIndex (Table.TypeDef);
1961
1962                                 var method = ReadMetadataToken (CodedIndex.MethodDefOrRef);
1963                                 if (method.TokenType != TokenType.Method)
1964                                         throw new NotSupportedException ();
1965
1966                                 var @override = ReadMetadataToken (CodedIndex.MethodDefOrRef);
1967
1968                                 AddOverrideMapping (method.RID, @override);
1969                         }
1970                 }
1971
1972                 void AddOverrideMapping (uint method_rid, MetadataToken @override)
1973                 {
1974                         metadata.SetOverrideMapping (
1975                                 method_rid,
1976                                 AddMapping (metadata.Overrides, method_rid, @override));
1977                 }
1978
1979                 public MethodBody ReadMethodBody (MethodDefinition method)
1980                 {
1981                         return code.ReadMethodBody (method);
1982                 }
1983
1984                 public CallSite ReadCallSite (MetadataToken token)
1985                 {
1986                         if (!MoveTo (Table.StandAloneSig, token.RID))
1987                                 return null;
1988
1989                         var signature = ReadBlobIndex ();
1990
1991                         var call_site = new CallSite ();
1992
1993                         ReadMethodSignature (signature, call_site);
1994
1995                         call_site.MetadataToken = token;
1996
1997                         return call_site;
1998                 }
1999
2000                 public VariableDefinitionCollection ReadVariables (MetadataToken local_var_token)
2001                 {
2002                         if (!MoveTo (Table.StandAloneSig, local_var_token.RID))
2003                                 return null;
2004
2005                         var reader = ReadSignature (ReadBlobIndex ());
2006                         const byte local_sig = 0x7;
2007
2008                         if (reader.ReadByte () != local_sig)
2009                                 throw new NotSupportedException ();
2010
2011                         var count = reader.ReadCompressedUInt32 ();
2012                         if (count == 0)
2013                                 return null;
2014
2015                         var variables = new VariableDefinitionCollection ((int) count);
2016
2017                         for (int i = 0; i < count; i++)
2018                                 variables.Add (new VariableDefinition (reader.ReadTypeSignature ()));
2019
2020                         return variables;
2021                 }
2022
2023                 public IMetadataTokenProvider LookupToken (MetadataToken token)
2024                 {
2025                         var rid = token.RID;
2026
2027                         if (rid == 0)
2028                                 return null;
2029
2030                         IMetadataTokenProvider element;
2031                         var position = this.position;
2032                         var context = this.context;
2033
2034                         switch (token.TokenType) {
2035                         case TokenType.TypeDef:
2036                                 element = GetTypeDefinition (rid);
2037                                 break;
2038                         case TokenType.TypeRef:
2039                                 element = GetTypeReference (rid);
2040                                 break;
2041                         case TokenType.TypeSpec:
2042                                 element = GetTypeSpecification (rid);
2043                                 break;
2044                         case TokenType.Field:
2045                                 element = GetFieldDefinition (rid);
2046                                 break;
2047                         case TokenType.Method:
2048                                 element = GetMethodDefinition (rid);
2049                                 break;
2050                         case TokenType.MemberRef:
2051                                 element = GetMemberReference (rid);
2052                                 break;
2053                         case TokenType.MethodSpec:
2054                                 element = GetMethodSpecification (rid);
2055                                 break;
2056                         default:
2057                                 return null;
2058                         }
2059
2060                         this.position = position;
2061                         this.context = context;
2062
2063                         return element;
2064                 }
2065
2066                 public FieldDefinition GetFieldDefinition (uint rid)
2067                 {
2068                         InitializeTypeDefinitions ();
2069
2070                         var field = metadata.GetFieldDefinition (rid);
2071                         if (field != null)
2072                                 return field;
2073
2074                         return LookupField (rid);
2075                 }
2076
2077                 FieldDefinition LookupField (uint rid)
2078                 {
2079                         var type = metadata.GetFieldDeclaringType (rid);
2080                         if (type == null)
2081                                 return null;
2082
2083                         InitializeCollection (type.Fields);
2084
2085                         return metadata.GetFieldDefinition (rid);
2086                 }
2087
2088                 public MethodDefinition GetMethodDefinition (uint rid)
2089                 {
2090                         InitializeTypeDefinitions ();
2091
2092                         var method = metadata.GetMethodDefinition (rid);
2093                         if (method != null)
2094                                 return method;
2095
2096                         return LookupMethod (rid);
2097                 }
2098
2099                 MethodDefinition LookupMethod (uint rid)
2100                 {
2101                         var type = metadata.GetMethodDeclaringType (rid);
2102                         if (type == null)
2103                                 return null;
2104
2105                         InitializeCollection (type.Methods);
2106
2107                         return metadata.GetMethodDefinition (rid);
2108                 }
2109
2110                 MethodSpecification GetMethodSpecification (uint rid)
2111                 {
2112                         if (!MoveTo (Table.MethodSpec, rid))
2113                                 return null;
2114
2115                         var element_method = (MethodReference) LookupToken (
2116                                 ReadMetadataToken (CodedIndex.MethodDefOrRef));
2117                         var signature = ReadBlobIndex ();
2118
2119                         var method_spec = ReadMethodSpecSignature (signature, element_method);
2120                         method_spec.token = new MetadataToken (TokenType.MethodSpec, rid);
2121                         return method_spec;
2122                 }
2123
2124                 MethodSpecification ReadMethodSpecSignature (uint signature, MethodReference method)
2125                 {
2126                         var reader = ReadSignature (signature);
2127                         const byte methodspec_sig = 0x0a;
2128
2129                         var call_conv = reader.ReadByte ();
2130
2131                         if (call_conv != methodspec_sig)
2132                                 throw new NotSupportedException ();
2133
2134                         var instance = new GenericInstanceMethod (method);
2135
2136                         reader.ReadGenericInstanceSignature (method, instance);
2137
2138                         return instance;
2139                 }
2140
2141                 MemberReference GetMemberReference (uint rid)
2142                 {
2143                         InitializeMemberReferences ();
2144
2145                         var member = metadata.GetMemberReference (rid);
2146                         if (member != null)
2147                                 return member;
2148
2149                         member = ReadMemberReference (rid);
2150                         if (member != null && !member.ContainsGenericParameter)
2151                                 metadata.AddMemberReference (member);
2152                         return member;
2153                 }
2154
2155                 MemberReference ReadMemberReference (uint rid)
2156                 {
2157                         if (!MoveTo (Table.MemberRef, rid))
2158                                 return null;
2159
2160                         var token = ReadMetadataToken (CodedIndex.MemberRefParent);
2161                         var name = ReadString ();
2162                         var signature = ReadBlobIndex ();
2163
2164                         MemberReference member;
2165
2166                         switch (token.TokenType) {
2167                         case TokenType.TypeDef:
2168                         case TokenType.TypeRef:
2169                         case TokenType.TypeSpec:
2170                                 member = ReadTypeMemberReference (token, name, signature);
2171                                 break;
2172                         case TokenType.Method:
2173                                 member = ReadMethodMemberReference (token, name, signature);
2174                                 break;
2175                         default:
2176                                 throw new NotSupportedException ();
2177                         }
2178
2179                         member.token = new MetadataToken (TokenType.MemberRef, rid);
2180
2181                         return member;
2182                 }
2183
2184                 MemberReference ReadTypeMemberReference (MetadataToken type, string name, uint signature)
2185                 {
2186                         var declaring_type = GetTypeDefOrRef (type);
2187
2188                         this.context = declaring_type;
2189
2190                         var member = ReadMemberReferenceSignature (signature, declaring_type);
2191                         member.Name = name;
2192
2193                         return member;
2194                 }
2195
2196                 MemberReference ReadMemberReferenceSignature (uint signature, TypeReference declaring_type)
2197                 {
2198                         var reader = ReadSignature (signature);
2199                         const byte field_sig = 0x6;
2200
2201                         if (reader.buffer [reader.position] == field_sig) {
2202                                 reader.position++;
2203                                 var field = new FieldReference ();
2204                                 field.DeclaringType = declaring_type;
2205                                 field.FieldType = reader.ReadTypeSignature ();
2206                                 return field;
2207                         } else {
2208                                 var method = new MethodReference ();
2209                                 method.DeclaringType = declaring_type;
2210                                 reader.ReadMethodSignature (method);
2211                                 return method;
2212                         }
2213                 }
2214
2215                 MemberReference ReadMethodMemberReference (MetadataToken token, string name, uint signature)
2216                 {
2217                         var method = GetMethodDefinition (token.RID);
2218
2219                         this.context = method;
2220
2221                         var member = ReadMemberReferenceSignature (signature, method.DeclaringType);
2222                         member.Name = name;
2223
2224                         return member;
2225                 }
2226
2227                 void InitializeMemberReferences ()
2228                 {
2229                         if (metadata.MemberReferences != null)
2230                                 return;
2231
2232                         metadata.MemberReferences = new MemberReference [image.GetTableLength (Table.MemberRef)];
2233                 }
2234
2235                 public IEnumerable<MemberReference> GetMemberReferences ()
2236                 {
2237                         InitializeMemberReferences ();
2238
2239                         var length = image.GetTableLength (Table.MemberRef);
2240
2241                         var type_system = module.TypeSystem;
2242
2243                         var context = new MethodReference (string.Empty, type_system.Void);
2244                         context.DeclaringType = new TypeReference (string.Empty, string.Empty, module, type_system.Corlib);
2245
2246                         var member_references = new MemberReference [length];
2247
2248                         for (uint i = 1; i <= length; i++) {
2249                                 this.context = context;
2250                                 member_references [i - 1] = GetMemberReference (i);
2251                         }
2252
2253                         return member_references;
2254                 }
2255
2256                 void InitializeConstants ()
2257                 {
2258                         if (metadata.Constants != null)
2259                                 return;
2260
2261                         var length = MoveTo (Table.Constant);
2262
2263                         var constants = metadata.Constants = new Dictionary<MetadataToken, Row<ElementType, uint>> (length);
2264
2265                         for (uint i = 1; i <= length; i++) {
2266                                 var type = (ElementType) ReadUInt16 ();
2267                                 var owner = ReadMetadataToken (CodedIndex.HasConstant);
2268                                 var signature = ReadBlobIndex ();
2269
2270                                 constants.Add (owner, new Row<ElementType, uint> (type, signature));
2271                         }
2272                 }
2273
2274                 public object ReadConstant (IConstantProvider owner)
2275                 {
2276                         InitializeConstants ();
2277
2278                         Row<ElementType, uint> row;
2279                         if (!metadata.Constants.TryGetValue (owner.MetadataToken, out row))
2280                                 return Mixin.NoValue;
2281
2282                         metadata.Constants.Remove (owner.MetadataToken);
2283
2284                         switch (row.Col1) {
2285                         case ElementType.Class:
2286                         case ElementType.Object:
2287                                 return null;
2288                         case ElementType.String:
2289                                 return ReadConstantString (ReadBlob (row.Col2));
2290                         default:
2291                                 return ReadConstantPrimitive (row.Col1, row.Col2);
2292                         }
2293                 }
2294
2295                 static string ReadConstantString (byte [] blob)
2296                 {
2297                         var length = blob.Length;
2298                         if ((length & 1) == 1)
2299                                 length--;
2300
2301                         return Encoding.Unicode.GetString (blob, 0, length);
2302                 }
2303
2304                 object ReadConstantPrimitive (ElementType type, uint signature)
2305                 {
2306                         var reader = ReadSignature (signature);
2307                         return reader.ReadConstantSignature (type);
2308                 }
2309
2310                 void InitializeCustomAttributes ()
2311                 {
2312                         if (metadata.CustomAttributes != null)
2313                                 return;
2314
2315                         metadata.CustomAttributes = InitializeRanges (
2316                                 Table.CustomAttribute, () => {
2317                                         var next = ReadMetadataToken (CodedIndex.HasCustomAttribute);
2318                                         ReadMetadataToken (CodedIndex.CustomAttributeType);
2319                                         ReadBlobIndex ();
2320                                         return next;
2321                         });
2322                 }
2323
2324                 public bool HasCustomAttributes (ICustomAttributeProvider owner)
2325                 {
2326                         InitializeCustomAttributes ();
2327
2328                         Range range;
2329                         if (!metadata.TryGetCustomAttributeRange (owner, out range))
2330                                 return false;
2331
2332                         return range.Length > 0;
2333                 }
2334
2335                 public Collection<CustomAttribute> ReadCustomAttributes (ICustomAttributeProvider owner)
2336                 {
2337                         InitializeCustomAttributes ();
2338
2339                         Range range;
2340                         if (!metadata.TryGetCustomAttributeRange (owner, out range)
2341                                 || !MoveTo (Table.CustomAttribute, range.Start))
2342                                 return new Collection<CustomAttribute> ();
2343
2344                         var custom_attributes = new Collection<CustomAttribute> ((int) range.Length);
2345
2346                         for (int i = 0; i < range.Length; i++) {
2347                                 ReadMetadataToken (CodedIndex.HasCustomAttribute);
2348
2349                                 var constructor = (MethodReference) LookupToken (
2350                                         ReadMetadataToken (CodedIndex.CustomAttributeType));
2351
2352                                 var signature = ReadBlobIndex ();
2353
2354                                 custom_attributes.Add (new CustomAttribute (signature, constructor));
2355                         }
2356
2357                         metadata.RemoveCustomAttributeRange (owner);
2358
2359                         return custom_attributes;
2360                 }
2361
2362                 public byte [] ReadCustomAttributeBlob (uint signature)
2363                 {
2364                         return ReadBlob (signature);
2365                 }
2366
2367                 public void ReadCustomAttributeSignature (CustomAttribute attribute)
2368                 {
2369                         var reader = ReadSignature (attribute.signature);
2370                         if (reader.ReadUInt16 () != 0x0001)
2371                             throw new InvalidOperationException ();
2372
2373                         var constructor = attribute.Constructor;
2374                         if (constructor.HasParameters)
2375                                 reader.ReadCustomAttributeConstructorArguments (attribute, constructor.Parameters);
2376
2377                         if (!reader.CanReadMore ())
2378                                 return;
2379
2380                         var named = reader.ReadUInt16 ();
2381
2382                         if (named == 0)
2383                                 return;
2384
2385                         reader.ReadCustomAttributeNamedArguments (named, ref attribute.fields, ref attribute.properties);
2386                 }
2387
2388                 void InitializeMarshalInfos ()
2389                 {
2390                         if (metadata.FieldMarshals != null)
2391                                 return;
2392
2393                         var length = MoveTo (Table.FieldMarshal);
2394
2395                         var marshals = metadata.FieldMarshals = new Dictionary<MetadataToken, uint> (length);
2396
2397                         for (int i = 0; i < length; i++) {
2398                                 var token = ReadMetadataToken (CodedIndex.HasFieldMarshal);
2399                                 var signature = ReadBlobIndex ();
2400                                 if (token.RID == 0)
2401                                         continue;
2402
2403                                 marshals.Add (token, signature);
2404                         }
2405                 }
2406
2407                 public bool HasMarshalInfo (IMarshalInfoProvider owner)
2408                 {
2409                         InitializeMarshalInfos ();
2410
2411                         return metadata.FieldMarshals.ContainsKey (owner.MetadataToken);
2412                 }
2413
2414                 public MarshalInfo ReadMarshalInfo (IMarshalInfoProvider owner)
2415                 {
2416                         InitializeMarshalInfos ();
2417
2418                         uint signature;
2419                         if (!metadata.FieldMarshals.TryGetValue (owner.MetadataToken, out signature))
2420                                 return null;
2421
2422                         var reader = ReadSignature (signature);
2423
2424                         metadata.FieldMarshals.Remove (owner.MetadataToken);
2425
2426                         return reader.ReadMarshalInfo ();
2427                 }
2428
2429                 void InitializeSecurityDeclarations ()
2430                 {
2431                         if (metadata.SecurityDeclarations != null)
2432                                 return;
2433
2434                         metadata.SecurityDeclarations = InitializeRanges (
2435                                 Table.DeclSecurity, () => {
2436                                         ReadUInt16 ();
2437                                         var next = ReadMetadataToken (CodedIndex.HasDeclSecurity);
2438                                         ReadBlobIndex ();
2439                                         return next;
2440                         });
2441                 }
2442
2443                 public bool HasSecurityDeclarations (ISecurityDeclarationProvider owner)
2444                 {
2445                         InitializeSecurityDeclarations ();
2446
2447                         Range range;
2448                         if (!metadata.TryGetSecurityDeclarationRange (owner, out range))
2449                                 return false;
2450
2451                         return range.Length > 0;
2452                 }
2453
2454                 public Collection<SecurityDeclaration> ReadSecurityDeclarations (ISecurityDeclarationProvider owner)
2455                 {
2456                         InitializeSecurityDeclarations ();
2457
2458                         Range range;
2459                         if (!metadata.TryGetSecurityDeclarationRange (owner, out range)
2460                                 || !MoveTo (Table.DeclSecurity, range.Start))
2461                                 return new Collection<SecurityDeclaration> ();
2462
2463                         var security_declarations = new Collection<SecurityDeclaration> ((int) range.Length);
2464
2465                         for (int i = 0; i < range.Length; i++) {
2466                                 var action = (SecurityAction) ReadUInt16 ();
2467                                 ReadMetadataToken (CodedIndex.HasDeclSecurity);
2468                                 var signature = ReadBlobIndex ();
2469
2470                                 security_declarations.Add (new SecurityDeclaration (action, signature, module));
2471                         }
2472
2473                         metadata.RemoveSecurityDeclarationRange (owner);
2474
2475                         return security_declarations;
2476                 }
2477
2478                 public byte [] ReadSecurityDeclarationBlob (uint signature)
2479                 {
2480                         return ReadBlob (signature);
2481                 }
2482
2483                 public void ReadSecurityDeclarationSignature (SecurityDeclaration declaration)
2484                 {
2485                         var signature = declaration.signature;
2486                         var reader = ReadSignature (signature);
2487
2488                         if (reader.buffer [reader.position] != '.') {
2489                                 ReadXmlSecurityDeclaration (signature, declaration);
2490                                 return;
2491                         }
2492
2493                         reader.position++;
2494                         var count = reader.ReadCompressedUInt32 ();
2495                         var attributes = new Collection<SecurityAttribute> ((int) count);
2496
2497                         for (int i = 0; i < count; i++)
2498                                 attributes.Add (reader.ReadSecurityAttribute ());
2499
2500                         declaration.security_attributes = attributes;
2501                 }
2502
2503                 void ReadXmlSecurityDeclaration (uint signature, SecurityDeclaration declaration)
2504                 {
2505                         var blob = ReadBlob (signature);
2506                         var attributes = new Collection<SecurityAttribute> (1);
2507
2508                         var attribute = new SecurityAttribute (
2509                                 module.TypeSystem.LookupType ("System.Security.Permissions", "PermissionSetAttribute"));
2510
2511                         attribute.properties = new Collection<CustomAttributeNamedArgument> (1);
2512                         attribute.properties.Add (
2513                                 new CustomAttributeNamedArgument (
2514                                         "XML",
2515                                         new CustomAttributeArgument (
2516                                                 module.TypeSystem.String,
2517                                                 Encoding.Unicode.GetString (blob, 0, blob.Length))));
2518
2519                         attributes.Add (attribute);
2520
2521                         declaration.security_attributes = attributes;
2522                 }
2523
2524                 public Collection<ExportedType> ReadExportedTypes ()
2525                 {
2526                         var length = MoveTo (Table.ExportedType);
2527                         if (length == 0)
2528                                 return new Collection<ExportedType> ();
2529
2530                         var exported_types = new Collection<ExportedType> (length);
2531
2532                         for (int i = 1; i <= length; i++) {
2533                                 var attributes = (TypeAttributes) ReadUInt32 ();
2534                                 var identifier = ReadUInt32 ();
2535                                 var name = ReadString ();
2536                                 var @namespace = ReadString ();
2537                                 var implementation = ReadMetadataToken (CodedIndex.Implementation);
2538
2539                                 ExportedType declaring_type = null;
2540                                 IMetadataScope scope = null;
2541
2542                                 switch (implementation.TokenType) {
2543                                 case TokenType.AssemblyRef:
2544                                 case TokenType.File:
2545                                         scope = GetExportedTypeScope (implementation);
2546                                         break;
2547                                 case TokenType.ExportedType:
2548                                         // FIXME: if the table is not properly sorted
2549                                         declaring_type = exported_types [(int) implementation.RID - 1];
2550                                         break;
2551                                 }
2552
2553                                 var exported_type = new ExportedType (@namespace, name, module, scope) {
2554                                         Attributes = attributes,
2555                                         Identifier = (int) identifier,
2556                                         DeclaringType = declaring_type,
2557                                 };
2558                                 exported_type.token = new MetadataToken (TokenType.ExportedType, i);
2559
2560                                 exported_types.Add (exported_type);
2561                         }
2562
2563                         return exported_types;
2564                 }
2565
2566                 IMetadataScope GetExportedTypeScope (MetadataToken token)
2567                 {
2568                         var position = this.position;
2569                         IMetadataScope scope;
2570
2571                         switch (token.TokenType) {
2572                         case TokenType.AssemblyRef:
2573                                 InitializeAssemblyReferences ();
2574                                 scope = metadata.AssemblyReferences [(int) token.RID - 1];
2575                                 break;
2576                         case TokenType.File:
2577                                 InitializeModuleReferences ();
2578                                 scope = GetModuleReferenceFromFile (token);
2579                                 break;
2580                         default:
2581                                 throw new NotSupportedException ();
2582                         }
2583
2584                         this.position = position;
2585                         return scope;
2586                 }
2587
2588                 ModuleReference GetModuleReferenceFromFile (MetadataToken token)
2589                 {
2590                         if (!MoveTo (Table.File, token.RID))
2591                                 return null;
2592
2593                         ReadUInt32 ();
2594                         var file_name = ReadString ();
2595                         var modules = module.ModuleReferences;
2596
2597                         ModuleReference reference;
2598                         for (int i = 0; i < modules.Count; i++) {
2599                                 reference = modules [i];
2600                                 if (reference.Name == file_name)
2601                                         return reference;
2602                         }
2603
2604                         reference = new ModuleReference (file_name);
2605                         modules.Add (reference);
2606                         return reference;
2607                 }
2608
2609                 static void InitializeCollection (object o)
2610                 {
2611                 }
2612         }
2613
2614         sealed class SignatureReader : ByteBuffer {
2615
2616                 readonly MetadataReader reader;
2617                 readonly uint start, sig_length;
2618
2619                 TypeSystem TypeSystem {
2620                         get { return reader.module.TypeSystem; }
2621                 }
2622
2623                 public SignatureReader (uint blob, MetadataReader reader)
2624                         : base (reader.buffer)
2625                 {
2626                         this.reader = reader;
2627
2628                         MoveToBlob (blob);
2629
2630                         this.sig_length = ReadCompressedUInt32 ();
2631                         this.start = (uint) position;
2632                 }
2633
2634                 void MoveToBlob (uint blob)
2635                 {
2636                         position = (int) (reader.image.BlobHeap.Offset + blob);
2637                 }
2638
2639                 MetadataToken ReadTypeTokenSignature ()
2640                 {
2641                         return CodedIndex.TypeDefOrRef.GetMetadataToken (ReadCompressedUInt32 ());
2642                 }
2643
2644                 GenericParameter GetGenericParameter (GenericParameterType type, uint var)
2645                 {
2646                         var context = reader.context;
2647
2648                         if (context == null)
2649                                 throw new NotSupportedException ();
2650
2651                         IGenericParameterProvider provider;
2652
2653                         switch (type) {
2654                         case GenericParameterType.Type:
2655                                 provider = context.Type;
2656                                 break;
2657                         case GenericParameterType.Method:
2658                                 provider = context.Method;
2659                                 break;
2660                         default:
2661                                 throw new NotSupportedException ();
2662                         }
2663
2664                         int index = (int) var;
2665
2666                         if (!context.IsDefinition)
2667                                 CheckGenericContext (provider, index);
2668
2669                         return provider.GenericParameters [index];
2670                 }
2671
2672                 static void CheckGenericContext (IGenericParameterProvider owner, int index)
2673                 {
2674                         var owner_parameters = owner.GenericParameters;
2675
2676                         for (int i = owner_parameters.Count; i <= index; i++)
2677                                 owner_parameters.Add (new GenericParameter (owner));
2678                 }
2679
2680                 public void ReadGenericInstanceSignature (IGenericParameterProvider provider, IGenericInstance instance)
2681                 {
2682                         var arity = ReadCompressedUInt32 ();
2683
2684                         if (!provider.IsDefinition)
2685                                 CheckGenericContext (provider, (int) arity - 1);
2686
2687                         var instance_arguments = instance.GenericArguments;
2688
2689                         for (int i = 0; i < arity; i++)
2690                                 instance_arguments.Add (ReadTypeSignature ());
2691                 }
2692
2693                 ArrayType ReadArrayTypeSignature ()
2694                 {
2695                         var array = new ArrayType (ReadTypeSignature ());
2696
2697                         var rank = ReadCompressedUInt32 ();
2698
2699                         var sizes = new uint [ReadCompressedUInt32 ()];
2700                         for (int i = 0; i < sizes.Length; i++)
2701                                 sizes [i] = ReadCompressedUInt32 ();
2702
2703                         var low_bounds = new int [ReadCompressedUInt32 ()];
2704                         for (int i = 0; i < low_bounds.Length; i++)
2705                                 low_bounds [i] = ReadCompressedInt32 ();
2706
2707                         array.Dimensions.Clear ();
2708
2709                         for (int i = 0; i < rank; i++) {
2710                                 int? lower = null, upper = null;
2711
2712                                 if (i < low_bounds.Length)
2713                                         lower = low_bounds [i];
2714
2715                                 if (i < sizes.Length)
2716                                         upper = lower + (int) sizes [i] - 1;
2717
2718                                 array.Dimensions.Add (new ArrayDimension (lower, upper));
2719                         }
2720
2721                         return array;
2722                 }
2723
2724                 TypeReference GetTypeDefOrRef (MetadataToken token)
2725                 {
2726                         return reader.GetTypeDefOrRef (token);
2727                 }
2728
2729                 public TypeReference ReadTypeSignature ()
2730                 {
2731                         return ReadTypeSignature ((ElementType) ReadByte ());
2732                 }
2733
2734                 TypeReference ReadTypeSignature (ElementType etype)
2735                 {
2736                         switch (etype) {
2737                         case ElementType.ValueType: {
2738                                 var value_type = GetTypeDefOrRef (ReadTypeTokenSignature ());
2739                                 value_type.IsValueType = true;
2740                                 return value_type;
2741                         }
2742                         case ElementType.Class:
2743                                 return GetTypeDefOrRef (ReadTypeTokenSignature ());
2744                         case ElementType.Ptr:
2745                                 return new PointerType (ReadTypeSignature ());
2746                         case ElementType.FnPtr: {
2747                                 var fptr = new FunctionPointerType ();
2748                                 ReadMethodSignature (fptr);
2749                                 return fptr;
2750                         }
2751                         case ElementType.ByRef:
2752                                 return new ByReferenceType (ReadTypeSignature ());
2753                         case ElementType.Pinned:
2754                                 return new PinnedType (ReadTypeSignature ());
2755                         case ElementType.SzArray:
2756                                 return new ArrayType (ReadTypeSignature ());
2757                         case ElementType.Array:
2758                                 return ReadArrayTypeSignature ();
2759                         case ElementType.CModOpt:
2760                                 return new OptionalModifierType (
2761                                         GetTypeDefOrRef (ReadTypeTokenSignature ()), ReadTypeSignature ());
2762                         case ElementType.CModReqD:
2763                                 return new RequiredModifierType (
2764                                         GetTypeDefOrRef (ReadTypeTokenSignature ()), ReadTypeSignature ());
2765                         case ElementType.Sentinel:
2766                                 return new SentinelType (ReadTypeSignature ());
2767                         case ElementType.Var:
2768                                 return GetGenericParameter (GenericParameterType.Type, ReadCompressedUInt32 ());
2769                         case ElementType.MVar:
2770                                 return GetGenericParameter (GenericParameterType.Method, ReadCompressedUInt32 ());
2771                         case ElementType.GenericInst: {
2772                                 var is_value_type = ReadByte () == (byte) ElementType.ValueType;
2773                                 var element_type = GetTypeDefOrRef (ReadTypeTokenSignature ());
2774                                 var generic_instance = new GenericInstanceType (element_type);
2775
2776                                 ReadGenericInstanceSignature (element_type, generic_instance);
2777
2778                                 if (is_value_type) {
2779                                         generic_instance.IsValueType = true;
2780                                         element_type.GetElementType ().IsValueType = true;
2781                                 }
2782
2783                                 return generic_instance;
2784                         }
2785                         case ElementType.Object: return TypeSystem.Object;
2786                         case ElementType.Void: return TypeSystem.Void;
2787                         case ElementType.TypedByRef: return TypeSystem.TypedReference;
2788                         case ElementType.I: return TypeSystem.IntPtr;
2789                         case ElementType.U: return TypeSystem.UIntPtr;
2790                         default: return GetPrimitiveType (etype);
2791                         }
2792                 }
2793
2794                 public void ReadMethodSignature (IMethodSignature method)
2795                 {
2796                         var calling_convention = ReadByte ();
2797
2798                         const byte has_this = 0x20;
2799                         const byte explicit_this = 0x40;
2800
2801                         if ((calling_convention & has_this) != 0) {
2802                                 method.HasThis = true;
2803                                 calling_convention = (byte) (calling_convention & ~has_this);
2804                         }
2805
2806                         if ((calling_convention & explicit_this) != 0) {
2807                                 method.ExplicitThis = true;
2808                                 calling_convention = (byte) (calling_convention & ~explicit_this);
2809                         }
2810
2811                         method.CallingConvention = (MethodCallingConvention) calling_convention;
2812
2813                         var generic_context = method as MethodReference;
2814                         if (generic_context != null)
2815                                 reader.context = generic_context;
2816
2817                         if ((calling_convention & 0x10) != 0) {
2818                                 var arity = ReadCompressedUInt32 ();
2819
2820                                 if (generic_context != null && !generic_context.IsDefinition)
2821                                         CheckGenericContext (generic_context, (int) arity -1 );
2822                         }
2823
2824                         var param_count = ReadCompressedUInt32 ();
2825
2826                         method.MethodReturnType.ReturnType = ReadTypeSignature ();
2827
2828                         if (param_count == 0)
2829                                 return;
2830
2831                         Collection<ParameterDefinition> parameters;
2832
2833                         var method_ref = method as MethodReference;
2834                         if (method_ref != null)
2835                                 parameters = method_ref.parameters = new ParameterDefinitionCollection (method, (int) param_count);
2836                         else
2837                                 parameters = method.Parameters;
2838
2839                         for (int i = 0; i < param_count; i++)
2840                                 parameters.Add (new ParameterDefinition (ReadTypeSignature ()));
2841                 }
2842
2843                 public object ReadConstantSignature (ElementType type)
2844                 {
2845                         return ReadPrimitiveValue (type);
2846                 }
2847
2848                 public void ReadCustomAttributeConstructorArguments (CustomAttribute attribute, Collection<ParameterDefinition> parameters)
2849                 {
2850                         var count = parameters.Count;
2851                         if (count == 0)
2852                                 return;
2853
2854                         attribute.arguments = new Collection<CustomAttributeArgument> (count);
2855
2856                         for (int i = 0; i < count; i++)
2857                                 attribute.arguments.Add (
2858                                         ReadCustomAttributeFixedArgument (parameters [i].ParameterType));
2859                 }
2860
2861                 CustomAttributeArgument ReadCustomAttributeFixedArgument (TypeReference type)
2862                 {
2863                         if (type.IsArray)
2864                                 return ReadCustomAttributeFixedArrayArgument ((ArrayType) type);
2865
2866                         return ReadCustomAttributeElement (type);
2867                 }
2868
2869                 public void ReadCustomAttributeNamedArguments (ushort count, ref Collection<CustomAttributeNamedArgument> fields, ref Collection<CustomAttributeNamedArgument> properties)
2870                 {
2871                         for (int i = 0; i < count; i++)
2872                                 ReadCustomAttributeNamedArgument (ref fields, ref properties);
2873                 }
2874
2875                 void ReadCustomAttributeNamedArgument (ref Collection<CustomAttributeNamedArgument> fields, ref Collection<CustomAttributeNamedArgument> properties)
2876                 {
2877                         var kind = ReadByte ();
2878                         var type = ReadCustomAttributeFieldOrPropType ();
2879                         var name = ReadUTF8String ();
2880
2881                         Collection<CustomAttributeNamedArgument> container;
2882                         switch (kind) {
2883                         case 0x53:
2884                                 container = GetCustomAttributeNamedArgumentCollection (ref fields);
2885                                 break;
2886                         case 0x54:
2887                                 container = GetCustomAttributeNamedArgumentCollection (ref properties);
2888                                 break;
2889                         default:
2890                                 throw new NotSupportedException ();
2891                         }
2892
2893                         container.Add (new CustomAttributeNamedArgument (name, ReadCustomAttributeFixedArgument (type)));
2894                 }
2895
2896                 static Collection<CustomAttributeNamedArgument> GetCustomAttributeNamedArgumentCollection (ref Collection<CustomAttributeNamedArgument> collection)
2897                 {
2898                         if (collection != null)
2899                                 return collection;
2900
2901                         return collection = new Collection<CustomAttributeNamedArgument> ();
2902                 }
2903
2904                 CustomAttributeArgument ReadCustomAttributeFixedArrayArgument (ArrayType type)
2905                 {
2906                         var length = ReadUInt32 ();
2907
2908                         if (length == 0xffffffff)
2909                                 return new CustomAttributeArgument (type, null);
2910
2911                         if (length == 0)
2912                                 return new CustomAttributeArgument (type, Empty<CustomAttributeArgument>.Array);
2913
2914                         var arguments = new CustomAttributeArgument [length];
2915                         var element_type = type.ElementType;
2916
2917                         for (int i = 0; i < length; i++)
2918                                 arguments [i] = ReadCustomAttributeElement (element_type);
2919
2920                         return new CustomAttributeArgument (type, arguments);
2921                 }
2922
2923                 CustomAttributeArgument ReadCustomAttributeElement (TypeReference type)
2924                 {
2925                         if (type.IsArray)
2926                                 return ReadCustomAttributeFixedArrayArgument ((ArrayType) type);
2927
2928                         return new CustomAttributeArgument (
2929                                 type,
2930                                 type.etype == ElementType.Object
2931                                         ? ReadCustomAttributeElement (ReadCustomAttributeFieldOrPropType ())
2932                                         : ReadCustomAttributeElementValue (type));
2933                 }
2934
2935                 object ReadCustomAttributeElementValue (TypeReference type)
2936                 {
2937                         var etype = type.etype;
2938
2939                         switch (etype) {
2940                         case ElementType.String:
2941                                 return ReadUTF8String ();
2942                         case ElementType.None:
2943                                 if (type.IsTypeOf ("System", "Type"))
2944                                         return ReadTypeReference ();
2945
2946                                 return ReadCustomAttributeEnum (type);
2947                         default:
2948                                 return ReadPrimitiveValue (etype);
2949                         }
2950                 }
2951
2952                 object ReadPrimitiveValue (ElementType type)
2953                 {
2954                         switch (type) {
2955                         case ElementType.Boolean:
2956                                 return ReadByte () == 1;
2957                         case ElementType.I1:
2958                                 return (sbyte) ReadByte ();
2959                         case ElementType.U1:
2960                                 return ReadByte ();
2961                         case ElementType.Char:
2962                                 return (char) ReadUInt16 ();
2963                         case ElementType.I2:
2964                                 return ReadInt16 ();
2965                         case ElementType.U2:
2966                                 return ReadUInt16 ();
2967                         case ElementType.I4:
2968                                 return ReadInt32 ();
2969                         case ElementType.U4:
2970                                 return ReadUInt32 ();
2971                         case ElementType.I8:
2972                                 return ReadInt64 ();
2973                         case ElementType.U8:
2974                                 return ReadUInt64 ();
2975                         case ElementType.R4:
2976                                 return ReadSingle ();
2977                         case ElementType.R8:
2978                                 return ReadDouble ();
2979                         default:
2980                                 throw new NotImplementedException (type.ToString ());
2981                         }
2982                 }
2983
2984                 TypeReference GetPrimitiveType (ElementType etype)
2985                 {
2986                         switch (etype) {
2987                         case ElementType.Boolean:
2988                                 return TypeSystem.Boolean;
2989                         case ElementType.Char:
2990                                 return TypeSystem.Char;
2991                         case ElementType.I1:
2992                                 return TypeSystem.SByte;
2993                         case ElementType.U1:
2994                                 return TypeSystem.Byte;
2995                         case ElementType.I2:
2996                                 return TypeSystem.Int16;
2997                         case ElementType.U2:
2998                                 return TypeSystem.UInt16;
2999                         case ElementType.I4:
3000                                 return TypeSystem.Int32;
3001                         case ElementType.U4:
3002                                 return TypeSystem.UInt32;
3003                         case ElementType.I8:
3004                                 return TypeSystem.Int64;
3005                         case ElementType.U8:
3006                                 return TypeSystem.UInt64;
3007                         case ElementType.R4:
3008                                 return TypeSystem.Single;
3009                         case ElementType.R8:
3010                                 return TypeSystem.Double;
3011                         case ElementType.String:
3012                                 return TypeSystem.String;
3013                         default:
3014                                 throw new NotImplementedException (etype.ToString ());
3015                         }
3016                 }
3017
3018                 TypeReference ReadCustomAttributeFieldOrPropType ()
3019                 {
3020                         var etype = (ElementType) ReadByte ();
3021
3022                         switch (etype) {
3023                         case ElementType.Boxed:
3024                                 return TypeSystem.Object;
3025                         case ElementType.SzArray:
3026                                 return new ArrayType (ReadCustomAttributeFieldOrPropType ());
3027                         case ElementType.Enum:
3028                                 return ReadTypeReference ();
3029                         case ElementType.Type:
3030                                 return TypeSystem.LookupType ("System", "Type");
3031                         default:
3032                                 return GetPrimitiveType (etype);
3033                         }
3034                 }
3035
3036                 public TypeReference ReadTypeReference ()
3037                 {
3038                         return TypeParser.ParseType (reader.module, ReadUTF8String ());
3039                 }
3040
3041                 object ReadCustomAttributeEnum (TypeReference enum_type)
3042                 {
3043                         var type = enum_type.CheckedResolve ();
3044                         if (!type.IsEnum)
3045                                 throw new ArgumentException ();
3046
3047                         return ReadCustomAttributeElementValue (type.GetEnumUnderlyingType ());
3048                 }
3049
3050                 public SecurityAttribute ReadSecurityAttribute ()
3051                 {
3052                         var attribute = new SecurityAttribute (ReadTypeReference ());
3053
3054                         ReadCompressedUInt32 ();
3055
3056                         ReadCustomAttributeNamedArguments (
3057                                 (ushort) ReadCompressedUInt32 (),
3058                                 ref attribute.fields,
3059                                 ref attribute.properties);
3060
3061                         return attribute;
3062                 }
3063
3064                 public MarshalInfo ReadMarshalInfo ()
3065                 {
3066                         var native = ReadNativeType ();
3067                         switch (native) {
3068                         case NativeType.Array: {
3069                                 var array = new ArrayMarshalInfo ();
3070                                 if (CanReadMore ())
3071                                         array.element_type = ReadNativeType ();
3072                                 if (CanReadMore ())
3073                                         array.size_parameter_index = (int) ReadCompressedUInt32 ();
3074                                 if (CanReadMore ())
3075                                         array.size = (int) ReadCompressedUInt32 ();
3076                                 if (CanReadMore ())
3077                                         array.size_parameter_multiplier = (int) ReadCompressedUInt32 ();
3078                                 return array;
3079                         }
3080                         case NativeType.SafeArray: {
3081                                 var array = new SafeArrayMarshalInfo ();
3082                                 if (CanReadMore ())
3083                                         array.element_type = ReadVariantType ();
3084                                 return array;
3085                         }
3086                         case NativeType.FixedArray: {
3087                                 var array = new FixedArrayMarshalInfo ();
3088                                 if (CanReadMore ())
3089                                         array.size = (int) ReadCompressedUInt32 ();
3090                                 if (CanReadMore ())
3091                                         array.element_type = ReadNativeType ();
3092                                 return array;
3093                         }
3094                         case NativeType.FixedSysString: {
3095                                 var sys_string = new FixedSysStringMarshalInfo ();
3096                                 if (CanReadMore ())
3097                                         sys_string.size = (int) ReadCompressedUInt32 ();
3098                                 return sys_string;
3099                         }
3100                         case NativeType.CustomMarshaler: {
3101                                 var marshaler = new CustomMarshalInfo ();
3102                                 var guid_value = ReadUTF8String ();
3103                                 marshaler.guid = !string.IsNullOrEmpty (guid_value) ? new Guid (guid_value) : Guid.Empty;
3104                                 marshaler.unmanaged_type = ReadUTF8String ();
3105                                 marshaler.managed_type = ReadTypeReference ();
3106                                 marshaler.cookie = ReadUTF8String ();
3107                                 return marshaler;
3108                         }
3109                         default:
3110                                 return new MarshalInfo (native);
3111                         }
3112                 }
3113
3114                 NativeType ReadNativeType ()
3115                 {
3116                         return (NativeType) ReadByte ();
3117                 }
3118
3119                 VariantType ReadVariantType ()
3120                 {
3121                         return (VariantType) ReadByte ();
3122                 }
3123
3124                 string ReadUTF8String ()
3125                 {
3126                         if (buffer [position] == 0xff) {
3127                                 position++;
3128                                 return null;
3129                         }
3130
3131                         var length = (int) ReadCompressedUInt32 ();
3132                         if (length == 0)
3133                                 return string.Empty;
3134
3135                         var @string = Encoding.UTF8.GetString (buffer, position,
3136                                 buffer [position + length - 1] == 0 ? length - 1 : length);
3137
3138                         position += length;
3139                         return @string;
3140                 }
3141
3142                 public bool CanReadMore ()
3143                 {
3144                         return position - start < sig_length;
3145                 }
3146         }
3147 }