System.Drawing: added email to icon and test file headers
[mono.git] / mcs / class / IKVM.Reflection / Reader / ModuleReader.cs
1 /*
2   Copyright (C) 2009-2012 Jeroen Frijters
3
4   This software is provided 'as-is', without any express or implied
5   warranty.  In no event will the authors be held liable for any damages
6   arising from the use of this software.
7
8   Permission is granted to anyone to use this software for any purpose,
9   including commercial applications, and to alter it and redistribute it
10   freely, subject to the following restrictions:
11
12   1. The origin of this software must not be misrepresented; you must not
13      claim that you wrote the original software. If you use this software
14      in a product, an acknowledgment in the product documentation would be
15      appreciated but is not required.
16   2. Altered source versions must be plainly marked as such, and must not be
17      misrepresented as being the original software.
18   3. This notice may not be removed or altered from any source distribution.
19
20   Jeroen Frijters
21   jeroen@frijters.net
22   
23 */
24 using System;
25 using System.IO;
26 using System.Text;
27 using System.Collections.Generic;
28 using IKVM.Reflection.Metadata;
29
30 namespace IKVM.Reflection.Reader
31 {
32         sealed class StreamHeader
33         {
34                 internal uint Offset;
35                 internal uint Size;
36                 internal string Name;
37
38                 internal void Read(BinaryReader br)
39                 {
40                         Offset = br.ReadUInt32();
41                         Size = br.ReadUInt32();
42                         byte[] buf = new byte[32];
43                         byte b;
44                         int len = 0;
45                         while ((b = br.ReadByte()) != 0)
46                         {
47                                 buf[len++] = b;
48                         }
49                         Name = Encoding.UTF8.GetString(buf, 0, len); ;
50                         int padding = -1 + ((len + 4) & ~3) - len;
51                         br.BaseStream.Seek(padding, SeekOrigin.Current);
52                 }
53         }
54
55         sealed class ModuleReader : Module
56         {
57                 internal readonly Stream stream;
58                 private readonly string location;
59                 private Assembly assembly;
60                 private readonly PEReader peFile = new PEReader();
61                 private readonly CliHeader cliHeader = new CliHeader();
62                 private string imageRuntimeVersion;
63                 private int metadataStreamVersion;
64                 private byte[] stringHeap;
65                 private byte[] blobHeap;
66                 private byte[] userStringHeap;
67                 private byte[] guidHeap;
68                 private TypeDefImpl[] typeDefs;
69                 private TypeDefImpl moduleType;
70                 private Assembly[] assemblyRefs;
71                 private Type[] typeRefs;
72                 private Type[] typeSpecs;
73                 private FieldInfo[] fields;
74                 private MethodBase[] methods;
75                 private MemberInfo[] memberRefs;
76                 private Dictionary<int, string> strings = new Dictionary<int, string>();
77                 private Dictionary<TypeName, Type> types = new Dictionary<TypeName, Type>();
78                 private Dictionary<TypeName, LazyForwardedType> forwardedTypes = new Dictionary<TypeName, LazyForwardedType>();
79
80                 private sealed class LazyForwardedType
81                 {
82                         private readonly int assemblyRef;
83                         private Type type;
84
85                         internal LazyForwardedType(int assemblyRef)
86                         {
87                                 this.assemblyRef = assemblyRef;
88                         }
89
90                         internal Type GetType(ModuleReader module, TypeName typeName)
91                         {
92                                 if (type == null)
93                                 {
94                                         Assembly asm = module.ResolveAssemblyRef(assemblyRef);
95                                         type = asm.ResolveType(typeName);
96                                         if (type == null)
97                                         {
98                                                 throw new TypeLoadException(typeName.ToString());
99                                         }
100                                 }
101                                 return type;
102                         }
103                 }
104
105                 internal ModuleReader(AssemblyReader assembly, Universe universe, Stream stream, string location)
106                         : base(universe)
107                 {
108                         this.stream = stream;
109                         this.location = location;
110                         Read();
111                         if (assembly == null && AssemblyTable.records.Length != 0)
112                         {
113                                 assembly = new AssemblyReader(location, this);
114                         }
115                         this.assembly = assembly;
116                 }
117
118                 private void Read()
119                 {
120                         BinaryReader br = new BinaryReader(stream);
121                         peFile.Read(br);
122                         stream.Seek(peFile.RvaToFileOffset(peFile.GetComDescriptorVirtualAddress()), SeekOrigin.Begin);
123                         cliHeader.Read(br);
124                         stream.Seek(peFile.RvaToFileOffset(cliHeader.MetaData.VirtualAddress), SeekOrigin.Begin);
125                         foreach (StreamHeader sh in ReadStreamHeaders(br, out imageRuntimeVersion))
126                         {
127                                 switch (sh.Name)
128                                 {
129                                         case "#Strings":
130                                                 stringHeap = ReadHeap(stream, sh);
131                                                 break;
132                                         case "#Blob":
133                                                 blobHeap = ReadHeap(stream, sh);
134                                                 break;
135                                         case "#US":
136                                                 userStringHeap = ReadHeap(stream, sh);
137                                                 break;
138                                         case "#GUID":
139                                                 guidHeap = ReadHeap(stream, sh);
140                                                 break;
141                                         case "#~":
142                                         case "#-":
143                                                 stream.Seek(peFile.RvaToFileOffset(cliHeader.MetaData.VirtualAddress + sh.Offset), SeekOrigin.Begin);
144                                                 ReadTables(br);
145                                                 break;
146                                         default:
147                                                 throw new BadImageFormatException("Unsupported stream: " + sh.Name);
148                                 }
149                         }
150                 }
151
152                 internal void SetAssembly(Assembly assembly)
153                 {
154                         this.assembly = assembly;
155                 }
156
157                 private static StreamHeader[] ReadStreamHeaders(BinaryReader br, out string Version)
158                 {
159                         uint Signature = br.ReadUInt32();
160                         if (Signature != 0x424A5342)
161                         {
162                                 throw new BadImageFormatException("Invalid metadata signature");
163                         }
164                         /*ushort MajorVersion =*/ br.ReadUInt16();
165                         /*ushort MinorVersion =*/ br.ReadUInt16();
166                         /*uint Reserved =*/ br.ReadUInt32();
167                         uint Length = br.ReadUInt32();
168                         byte[] buf = br.ReadBytes((int)Length);
169                         Version = Encoding.UTF8.GetString(buf).TrimEnd('\u0000');
170                         /*ushort Flags =*/ br.ReadUInt16();
171                         ushort Streams = br.ReadUInt16();
172                         StreamHeader[] streamHeaders = new StreamHeader[Streams];
173                         for (int i = 0; i < streamHeaders.Length; i++)
174                         {
175                                 streamHeaders[i] = new StreamHeader();
176                                 streamHeaders[i].Read(br);
177                         }
178                         return streamHeaders;
179                 }
180
181                 private void ReadTables(BinaryReader br)
182                 {
183                         Table[] tables = GetTables();
184                         /*uint Reserved0 =*/ br.ReadUInt32();
185                         byte MajorVersion = br.ReadByte();
186                         byte MinorVersion = br.ReadByte();
187                         metadataStreamVersion = MajorVersion << 16 | MinorVersion;
188                         byte HeapSizes = br.ReadByte();
189                         /*byte Reserved7 =*/ br.ReadByte();
190                         ulong Valid = br.ReadUInt64();
191                         ulong Sorted = br.ReadUInt64();
192                         for (int i = 0; i < 64; i++)
193                         {
194                                 if ((Valid & (1UL << i)) != 0)
195                                 {
196                                         tables[i].Sorted = (Sorted & (1UL << i)) != 0;
197                                         tables[i].RowCount = br.ReadInt32();
198                                 }
199                                 else if (tables[i] != null)
200                                 {
201                                         tables[i].RowCount = 0;
202                                 }
203                         }
204                         MetadataReader mr = new MetadataReader(this, br.BaseStream, HeapSizes);
205                         for (int i = 0; i < 64; i++)
206                         {
207                                 if ((Valid & (1UL << i)) != 0)
208                                 {
209                                         tables[i].Read(mr);
210                                 }
211                         }
212                         if (ParamPtr.RowCount != 0)
213                         {
214                                 throw new NotImplementedException("ParamPtr table support has not yet been implemented.");
215                         }
216                 }
217
218                 private byte[] ReadHeap(Stream stream, StreamHeader sh)
219                 {
220                         byte[] buf = new byte[sh.Size];
221                         stream.Seek(peFile.RvaToFileOffset(cliHeader.MetaData.VirtualAddress + sh.Offset), SeekOrigin.Begin);
222                         for (int pos = 0; pos < buf.Length; )
223                         {
224                                 int read = stream.Read(buf, pos, buf.Length - pos);
225                                 if (read == 0)
226                                 {
227                                         throw new BadImageFormatException();
228                                 }
229                                 pos += read;
230                         }
231                         return buf;
232                 }
233
234                 internal void SeekRVA(int rva)
235                 {
236                         stream.Seek(peFile.RvaToFileOffset((uint)rva), SeekOrigin.Begin);
237                 }
238
239                 internal override void GetTypesImpl(List<Type> list)
240                 {
241                         PopulateTypeDef();
242                         foreach (TypeDefImpl type in typeDefs)
243                         {
244                                 if (type != moduleType)
245                                 {
246                                         list.Add(type);
247                                 }
248                         }
249                 }
250
251                 private void PopulateTypeDef()
252                 {
253                         if (typeDefs == null)
254                         {
255                                 typeDefs = new TypeDefImpl[TypeDef.records.Length];
256                                 for (int i = 0; i < typeDefs.Length; i++)
257                                 {
258                                         TypeDefImpl type = new TypeDefImpl(this, i);
259                                         typeDefs[i] = type;
260                                         if (type.IsModulePseudoType)
261                                         {
262                                                 moduleType = type;
263                                         }
264                                         else if (!type.IsNestedByFlags)
265                                         {
266                                                 types.Add(new TypeName(type.__Namespace, type.__Name), type);
267                                         }
268                                 }
269                                 // add forwarded types to forwardedTypes dictionary (because Module.GetType(string) should return them)
270                                 for (int i = 0; i < ExportedType.records.Length; i++)
271                                 {
272                                         int implementation = ExportedType.records[i].Implementation;
273                                         if (implementation >> 24 == AssemblyRefTable.Index)
274                                         {
275                                                 TypeName typeName = GetTypeName(ExportedType.records[i].TypeNamespace, ExportedType.records[i].TypeName);
276                                                 forwardedTypes.Add(typeName, new LazyForwardedType((implementation & 0xFFFFFF) - 1));
277                                         }
278                                 }
279                         }
280                 }
281
282                 internal string GetString(int index)
283                 {
284                         if (index == 0)
285                         {
286                                 return null;
287                         }
288                         string str;
289                         if (!strings.TryGetValue(index, out str))
290                         {
291                                 int len = 0;
292                                 while (stringHeap[index + len] != 0)
293                                 {
294                                         len++;
295                                 }
296                                 str = Encoding.UTF8.GetString(stringHeap, index, len);
297                                 strings.Add(index, str);
298                         }
299                         return str;
300                 }
301
302                 private static int ReadCompressedInt(byte[] buffer, ref int offset)
303                 {
304                         byte b1 = buffer[offset++];
305                         if (b1 <= 0x7F)
306                         {
307                                 return b1;
308                         }
309                         else if ((b1 & 0xC0) == 0x80)
310                         {
311                                 byte b2 = buffer[offset++];
312                                 return ((b1 & 0x3F) << 8) | b2;
313                         }
314                         else
315                         {
316                                 byte b2 = buffer[offset++];
317                                 byte b3 = buffer[offset++];
318                                 byte b4 = buffer[offset++];
319                                 return ((b1 & 0x3F) << 24) + (b2 << 16) + (b3 << 8) + b4;
320                         }
321                 }
322
323                 internal byte[] GetBlobCopy(int blobIndex)
324                 {
325                         int len = ReadCompressedInt(blobHeap, ref blobIndex);
326                         byte[] buf = new byte[len];
327                         Buffer.BlockCopy(blobHeap, blobIndex, buf, 0, len);
328                         return buf;
329                 }
330
331                 internal override ByteReader GetBlob(int blobIndex)
332                 {
333                         return ByteReader.FromBlob(blobHeap, blobIndex);
334                 }
335
336                 public override string ResolveString(int metadataToken)
337                 {
338                         string str;
339                         if (!strings.TryGetValue(metadataToken, out str))
340                         {
341                                 if ((metadataToken >> 24) != 0x70)
342                                 {
343                                         throw TokenOutOfRangeException(metadataToken);
344                                 }
345                                 int index = metadataToken & 0xFFFFFF;
346                                 int len = ReadCompressedInt(userStringHeap, ref index) & ~1;
347                                 StringBuilder sb = new StringBuilder(len / 2);
348                                 for (int i = 0; i < len; i += 2)
349                                 {
350                                         char ch = (char)(userStringHeap[index + i] | userStringHeap[index + i + 1] << 8);
351                                         sb.Append(ch);
352                                 }
353                                 str = sb.ToString();
354                                 strings.Add(metadataToken, str);
355                         }
356                         return str;
357                 }
358
359                 internal Type ResolveType(int metadataToken, IGenericContext context)
360                 {
361                         int index = (metadataToken & 0xFFFFFF) - 1;
362                         if (index < 0)
363                         {
364                                 throw TokenOutOfRangeException(metadataToken);
365                         }
366                         else if ((metadataToken >> 24) == TypeDefTable.Index && index < TypeDef.RowCount)
367                         {
368                                 PopulateTypeDef();
369                                 return typeDefs[index];
370                         }
371                         else if ((metadataToken >> 24) == TypeRefTable.Index && index < TypeRef.RowCount)
372                         {
373                                 if (typeRefs == null)
374                                 {
375                                         typeRefs = new Type[TypeRef.records.Length];
376                                 }
377                                 if (typeRefs[index] == null)
378                                 {
379                                         int scope = TypeRef.records[index].ResolutionScope;
380                                         switch (scope >> 24)
381                                         {
382                                                 case AssemblyRefTable.Index:
383                                                         {
384                                                                 Assembly assembly = ResolveAssemblyRef((scope & 0xFFFFFF) - 1);
385                                                                 TypeName typeName = GetTypeName(TypeRef.records[index].TypeNameSpace, TypeRef.records[index].TypeName);
386                                                                 typeRefs[index] = assembly.ResolveType(typeName);
387                                                                 break;
388                                                         }
389                                                 case TypeRefTable.Index:
390                                                         {
391                                                                 Type outer = ResolveType(scope, null);
392                                                                 TypeName typeName = GetTypeName(TypeRef.records[index].TypeNameSpace, TypeRef.records[index].TypeName);
393                                                                 typeRefs[index] = outer.ResolveNestedType(typeName);
394                                                                 break;
395                                                         }
396                                                 case ModuleTable.Index:
397                                                 case ModuleRefTable.Index:
398                                                         {
399                                                                 Module module;
400                                                                 if (scope >> 24 == ModuleTable.Index)
401                                                                 {
402                                                                         if (scope == 0 || scope == 1)
403                                                                         {
404                                                                                 module = this;
405                                                                         }
406                                                                         else
407                                                                         {
408                                                                                 throw new NotImplementedException("self reference scope?");
409                                                                         }
410                                                                 }
411                                                                 else
412                                                                 {
413                                                                         module = ResolveModuleRef(ModuleRef.records[(scope & 0xFFFFFF) - 1]);
414                                                                 }
415                                                                 TypeName typeName = GetTypeName(TypeRef.records[index].TypeNameSpace, TypeRef.records[index].TypeName);
416                                                                 typeRefs[index] = module.FindType(typeName) ?? module.universe.GetMissingTypeOrThrow(module, null, typeName);
417                                                                 break;
418                                                         }
419                                                 default:
420                                                         throw new NotImplementedException("ResolutionScope = " + scope.ToString("X"));
421                                         }
422                                 }
423                                 return typeRefs[index];
424                         }
425                         else if ((metadataToken >> 24) == TypeSpecTable.Index && index < TypeSpec.RowCount)
426                         {
427                                 if (typeSpecs == null)
428                                 {
429                                         typeSpecs = new Type[TypeSpec.records.Length];
430                                 }
431                                 Type type = typeSpecs[index];
432                                 if (type == null)
433                                 {
434                                         TrackingGenericContext tc = context == null ? null : new TrackingGenericContext(context);
435                                         type = Signature.ReadTypeSpec(this, ByteReader.FromBlob(blobHeap, TypeSpec.records[index]), tc);
436                                         if (tc == null || !tc.IsUsed)
437                                         {
438                                                 typeSpecs[index] = type;
439                                         }
440                                 }
441                                 return type;
442                         }
443                         else
444                         {
445                                 throw TokenOutOfRangeException(metadataToken);
446                         }
447                 }
448
449                 private Module ResolveModuleRef(int moduleNameIndex)
450                 {
451                         string moduleName = GetString(moduleNameIndex);
452                         Module module = assembly.GetModule(moduleName);
453                         if (module == null)
454                         {
455                                 throw new FileNotFoundException(moduleName);
456                         }
457                         return module;
458                 }
459
460                 private sealed class TrackingGenericContext : IGenericContext
461                 {
462                         private readonly IGenericContext context;
463                         private bool used;
464
465                         internal TrackingGenericContext(IGenericContext context)
466                         {
467                                 this.context = context;
468                         }
469
470                         internal bool IsUsed
471                         {
472                                 get { return used; }
473                         }
474
475                         public Type GetGenericTypeArgument(int index)
476                         {
477                                 used = true;
478                                 return context.GetGenericTypeArgument(index);
479                         }
480
481                         public Type GetGenericMethodArgument(int index)
482                         {
483                                 used = true;
484                                 return context.GetGenericMethodArgument(index);
485                         }
486                 }
487
488                 public override Type ResolveType(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
489                 {
490                         if ((metadataToken >> 24) == TypeSpecTable.Index)
491                         {
492                                 return ResolveType(metadataToken, new GenericContext(genericTypeArguments, genericMethodArguments));
493                         }
494                         else
495                         {
496                                 return ResolveType(metadataToken, null);
497                         }
498                 }
499
500                 private TypeName GetTypeName(int typeNamespace, int typeName)
501                 {
502                         return new TypeName(GetString(typeNamespace), GetString(typeName));
503                 }
504
505                 private Assembly ResolveAssemblyRef(int index)
506                 {
507                         if (assemblyRefs == null)
508                         {
509                                 assemblyRefs = new Assembly[AssemblyRef.RowCount];
510                         }
511                         if (assemblyRefs[index] == null)
512                         {
513                                 assemblyRefs[index] = ResolveAssemblyRefImpl(ref AssemblyRef.records[index]);
514                         }
515                         return assemblyRefs[index];
516                 }
517
518                 private Assembly ResolveAssemblyRefImpl(ref AssemblyRefTable.Record rec)
519                 {
520                         const int PublicKey = 0x0001;
521                         string name = String.Format("{0}, Version={1}.{2}.{3}.{4}, Culture={5}, {6}={7}",
522                                 GetString(rec.Name),
523                                 rec.MajorVersion,
524                                 rec.MinorVersion,
525                                 rec.BuildNumber,
526                                 rec.RevisionNumber,
527                                 rec.Culture == 0 ? "neutral" : GetString(rec.Culture),
528                                 (rec.Flags & PublicKey) == 0 ? "PublicKeyToken" : "PublicKey",
529                                 PublicKeyOrTokenToString(rec.PublicKeyOrToken));
530                         return universe.Load(name, this.Assembly, true);
531                 }
532
533                 private string PublicKeyOrTokenToString(int publicKeyOrToken)
534                 {
535                         if (publicKeyOrToken == 0)
536                         {
537                                 return "null";
538                         }
539                         ByteReader br = GetBlob(publicKeyOrToken);
540                         if (br.Length == 0)
541                         {
542                                 return "null";
543                         }
544                         StringBuilder sb = new StringBuilder(br.Length * 2);
545                         while (br.Length > 0)
546                         {
547                                 sb.AppendFormat("{0:x2}", br.ReadByte());
548                         }
549                         return sb.ToString();
550                 }
551
552                 public override Guid ModuleVersionId
553                 {
554                         get
555                         {
556                                 byte[] buf = new byte[16];
557                                 Buffer.BlockCopy(guidHeap, 16 * (ModuleTable.records[0].Mvid - 1), buf, 0, 16);
558                                 return new Guid(buf);
559                         }
560                 }
561
562                 public override string FullyQualifiedName
563                 {
564                         get { return location ?? "<Unknown>"; }
565                 }
566
567                 public override string Name
568                 {
569                         get { return location == null ? "<Unknown>" : System.IO.Path.GetFileName(location); }
570                 }
571
572                 public override Assembly Assembly
573                 {
574                         get { return assembly; }
575                 }
576
577                 internal override Type FindType(TypeName typeName)
578                 {
579                         PopulateTypeDef();
580                         Type type;
581                         if (!types.TryGetValue(typeName, out type))
582                         {
583                                 LazyForwardedType fw;
584                                 if (forwardedTypes.TryGetValue(typeName, out fw))
585                                 {
586                                         return fw.GetType(this, typeName);
587                                 }
588                         }
589                         return type;
590                 }
591
592                 internal override Type FindTypeIgnoreCase(TypeName lowerCaseName)
593                 {
594                         PopulateTypeDef();
595                         foreach (Type type in types.Values)
596                         {
597                                 if (new TypeName(type.__Namespace, type.__Name).ToLowerInvariant() == lowerCaseName)
598                                 {
599                                         return type;
600                                 }
601                         }
602                         foreach (TypeName name in forwardedTypes.Keys)
603                         {
604                                 if (name.ToLowerInvariant() == lowerCaseName)
605                                 {
606                                         return forwardedTypes[name].GetType(this, name);
607                                 }
608                         }
609                         return null;
610                 }
611
612                 private Exception TokenOutOfRangeException(int metadataToken)
613                 {
614                         return new ArgumentOutOfRangeException("metadataToken", String.Format("Token 0x{0:x8} is not valid in the scope of module {1}.", metadataToken, this.Name));
615                 }
616
617                 public override MemberInfo ResolveMember(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
618                 {
619                         switch (metadataToken >> 24)
620                         {
621                                 case FieldTable.Index:
622                                         return ResolveField(metadataToken, genericTypeArguments, genericMethodArguments);
623                                 case MemberRefTable.Index:
624                                         int index = (metadataToken & 0xFFFFFF) - 1;
625                                         if (index < 0 || index >= MemberRef.RowCount)
626                                         {
627                                                 goto default;
628                                         }
629                                         return GetMemberRef(index, genericTypeArguments, genericMethodArguments);
630                                 case MethodDefTable.Index:
631                                 case MethodSpecTable.Index:
632                                         return ResolveMethod(metadataToken, genericTypeArguments, genericMethodArguments);
633                                 default:
634                                         throw TokenOutOfRangeException(metadataToken);
635                         }
636                 }
637
638                 internal FieldInfo GetFieldAt(TypeDefImpl owner, int index)
639                 {
640                         if (fields == null)
641                         {
642                                 fields = new FieldInfo[Field.records.Length];
643                         }
644                         if (fields[index] == null)
645                         {
646                                 fields[index] = new FieldDefImpl(this, owner ?? FindFieldOwner(index), index);
647                         }
648                         return fields[index];
649                 }
650
651                 public override FieldInfo ResolveField(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
652                 {
653                         int index = (metadataToken & 0xFFFFFF) - 1;
654                         if (index < 0)
655                         {
656                                 throw TokenOutOfRangeException(metadataToken);
657                         }
658                         else if ((metadataToken >> 24) == FieldTable.Index && index < Field.RowCount)
659                         {
660                                 return GetFieldAt(null, index);
661                         }
662                         else if ((metadataToken >> 24) == MemberRefTable.Index && index < MemberRef.RowCount)
663                         {
664                                 FieldInfo field = GetMemberRef(index, genericTypeArguments, genericMethodArguments) as FieldInfo;
665                                 if (field != null)
666                                 {
667                                         return field;
668                                 }
669                                 throw new ArgumentException(String.Format("Token 0x{0:x8} is not a valid FieldInfo token in the scope of module {1}.", metadataToken, this.Name), "metadataToken");
670                         }
671                         else
672                         {
673                                 throw TokenOutOfRangeException(metadataToken);
674                         }
675                 }
676
677                 private TypeDefImpl FindFieldOwner(int fieldIndex)
678                 {
679                         // TODO use binary search?
680                         for (int i = 0; i < TypeDef.records.Length; i++)
681                         {
682                                 int field = TypeDef.records[i].FieldList - 1;
683                                 int end = TypeDef.records.Length > i + 1 ? TypeDef.records[i + 1].FieldList - 1 : Field.records.Length;
684                                 if (field <= fieldIndex && fieldIndex < end)
685                                 {
686                                         PopulateTypeDef();
687                                         return typeDefs[i];
688                                 }
689                         }
690                         throw new InvalidOperationException();
691                 }
692
693                 internal MethodBase GetMethodAt(TypeDefImpl owner, int index)
694                 {
695                         if (methods == null)
696                         {
697                                 methods = new MethodBase[MethodDef.records.Length];
698                         }
699                         if (methods[index] == null)
700                         {
701                                 MethodDefImpl method = new MethodDefImpl(this, owner ?? FindMethodOwner(index), index);
702                                 methods[index] = method.IsConstructor ? new ConstructorInfoImpl(method) : (MethodBase)method;
703                         }
704                         return methods[index];
705                 }
706
707                 private sealed class GenericContext : IGenericContext
708                 {
709                         private readonly Type[] genericTypeArguments;
710                         private readonly Type[] genericMethodArguments;
711
712                         internal GenericContext(Type[] genericTypeArguments, Type[] genericMethodArguments)
713                         {
714                                 this.genericTypeArguments = genericTypeArguments;
715                                 this.genericMethodArguments = genericMethodArguments;
716                         }
717
718                         public Type GetGenericTypeArgument(int index)
719                         {
720                                 return genericTypeArguments[index];
721                         }
722
723                         public Type GetGenericMethodArgument(int index)
724                         {
725                                 return genericMethodArguments[index];
726                         }
727                 }
728
729                 public override MethodBase ResolveMethod(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
730                 {
731                         int index = (metadataToken & 0xFFFFFF) - 1;
732                         if (index < 0)
733                         {
734                                 throw TokenOutOfRangeException(metadataToken);
735                         }
736                         else if ((metadataToken >> 24) == MethodDefTable.Index && index < MethodDef.RowCount)
737                         {
738                                 return GetMethodAt(null, index);
739                         }
740                         else if ((metadataToken >> 24) == MemberRefTable.Index && index < MemberRef.RowCount)
741                         {
742                                 MethodBase method = GetMemberRef(index, genericTypeArguments, genericMethodArguments) as MethodBase;
743                                 if (method != null)
744                                 {
745                                         return method;
746                                 }
747                                 throw new ArgumentException(String.Format("Token 0x{0:x8} is not a valid MethodBase token in the scope of module {1}.", metadataToken, this.Name), "metadataToken");
748                         }
749                         else if ((metadataToken >> 24) == MethodSpecTable.Index && index < MethodSpec.RowCount)
750                         {
751                                 MethodInfo method = (MethodInfo)ResolveMethod(MethodSpec.records[index].Method, genericTypeArguments, genericMethodArguments);
752                                 ByteReader instantiation = ByteReader.FromBlob(blobHeap, MethodSpec.records[index].Instantiation);
753                                 return method.MakeGenericMethod(Signature.ReadMethodSpec(this, instantiation, new GenericContext(genericTypeArguments, genericMethodArguments)));
754                         }
755                         else
756                         {
757                                 throw TokenOutOfRangeException(metadataToken);
758                         }
759                 }
760
761                 public override Type[] __ResolveOptionalParameterTypes(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments, out CustomModifiers[] customModifiers)
762                 {
763                         int index = (metadataToken & 0xFFFFFF) - 1;
764                         if (index < 0)
765                         {
766                                 throw TokenOutOfRangeException(metadataToken);
767                         }
768                         else if ((metadataToken >> 24) == MemberRefTable.Index && index < MemberRef.RowCount)
769                         {
770                                 int sig = MemberRef.records[index].Signature;
771                                 return Signature.ReadOptionalParameterTypes(this, GetBlob(sig), new GenericContext(genericTypeArguments, genericMethodArguments), out customModifiers);
772                         }
773                         else if ((metadataToken >> 24) == MethodDefTable.Index && index < MethodDef.RowCount)
774                         {
775                                 // for convenience, we support passing a MethodDef token as well, because in some places
776                                 // it makes sense to have a vararg method that is referred to by its methoddef (e.g. ldftn).
777                                 // Note that MethodSpec doesn't make sense, because generic methods cannot be vararg.
778                                 customModifiers = Empty<CustomModifiers>.Array;
779                                 return Type.EmptyTypes;
780                         }
781                         else
782                         {
783                                 throw TokenOutOfRangeException(metadataToken);
784                         }
785                 }
786
787                 public override string ScopeName
788                 {
789                         get { return GetString(ModuleTable.records[0].Name); }
790                 }
791
792                 private TypeDefImpl FindMethodOwner(int methodIndex)
793                 {
794                         // TODO use binary search?
795                         for (int i = 0; i < TypeDef.records.Length; i++)
796                         {
797                                 int method = TypeDef.records[i].MethodList - 1;
798                                 int end = TypeDef.records.Length > i + 1 ? TypeDef.records[i + 1].MethodList - 1 : MethodDef.records.Length;
799                                 if (method <= methodIndex && methodIndex < end)
800                                 {
801                                         PopulateTypeDef();
802                                         return typeDefs[i];
803                                 }
804                         }
805                         throw new InvalidOperationException();
806                 }
807
808                 private MemberInfo GetMemberRef(int index, Type[] genericTypeArguments, Type[] genericMethodArguments)
809                 {
810                         if (memberRefs == null)
811                         {
812                                 memberRefs = new MemberInfo[MemberRef.records.Length];
813                         }
814                         if (memberRefs[index] == null)
815                         {
816                                 int owner = MemberRef.records[index].Class;
817                                 int sig = MemberRef.records[index].Signature;
818                                 string name = GetString(MemberRef.records[index].Name);
819                                 switch (owner >> 24)
820                                 {
821                                         case MethodDefTable.Index:
822                                                 return GetMethodAt(null, (owner & 0xFFFFFF) - 1);
823                                         case ModuleRefTable.Index:
824                                                 memberRefs[index] = ResolveTypeMemberRef(ResolveModuleType(owner), name, ByteReader.FromBlob(blobHeap, sig));
825                                                 break;
826                                         case TypeDefTable.Index:
827                                         case TypeRefTable.Index:
828                                                 memberRefs[index] = ResolveTypeMemberRef(ResolveType(owner), name, ByteReader.FromBlob(blobHeap, sig));
829                                                 break;
830                                         case TypeSpecTable.Index:
831                                         {
832                                                 Type type = ResolveType(owner, genericTypeArguments, genericMethodArguments);
833                                                 if (type.IsArray)
834                                                 {
835                                                         MethodSignature methodSig = MethodSignature.ReadSig(this, ByteReader.FromBlob(blobHeap, sig), new GenericContext(genericTypeArguments, genericMethodArguments));
836                                                         return type.FindMethod(name, methodSig)
837                                                                 ?? universe.GetMissingMethodOrThrow(type, name, methodSig);
838                                                 }
839                                                 else if (type.IsGenericTypeInstance)
840                                                 {
841                                                         MemberInfo member = ResolveTypeMemberRef(type.GetGenericTypeDefinition(), name, ByteReader.FromBlob(blobHeap, sig));
842                                                         MethodBase mb = member as MethodBase;
843                                                         if (mb != null)
844                                                         {
845                                                                 member = mb.BindTypeParameters(type);
846                                                         }
847                                                         FieldInfo fi = member as FieldInfo;
848                                                         if (fi != null)
849                                                         {
850                                                                 member = fi.BindTypeParameters(type);
851                                                         }
852                                                         return member;
853                                                 }
854                                                 else
855                                                 {
856                                                         return ResolveTypeMemberRef(type, name, ByteReader.FromBlob(blobHeap, sig));
857                                                 }
858                                         }
859                                         default:
860                                                 throw new BadImageFormatException();
861                                 }
862                         }
863                         return memberRefs[index];
864                 }
865
866                 private Type ResolveModuleType(int token)
867                 {
868                         int index = (token & 0xFFFFFF) - 1;
869                         string name = GetString(ModuleRef.records[index]);
870                         Module module = assembly.GetModule(name);
871                         if (module == null || module.IsResource())
872                         {
873                                 throw new BadImageFormatException();
874                         }
875                         return module.GetModuleType();
876                 }
877
878                 private MemberInfo ResolveTypeMemberRef(Type type, string name, ByteReader sig)
879                 {
880                         if (sig.PeekByte() == Signature.FIELD)
881                         {
882                                 Type org = type;
883                                 FieldSignature fieldSig = FieldSignature.ReadSig(this, sig, type);
884                                 FieldInfo field = type.FindField(name, fieldSig);
885                                 if (field == null && universe.MissingMemberResolution)
886                                 {
887                                         return universe.GetMissingFieldOrThrow(type, name, fieldSig);
888                                 }
889                                 while (field == null && (type = type.BaseType) != null)
890                                 {
891                                         field = type.FindField(name, fieldSig);
892                                 }
893                                 if (field != null)
894                                 {
895                                         return field;
896                                 }
897                                 throw new MissingFieldException(org.ToString(), name);
898                         }
899                         else
900                         {
901                                 Type org = type;
902                                 MethodSignature methodSig = MethodSignature.ReadSig(this, sig, type);
903                                 MethodBase method = type.FindMethod(name, methodSig);
904                                 if (method == null && universe.MissingMemberResolution)
905                                 {
906                                         return universe.GetMissingMethodOrThrow(type, name, methodSig);
907                                 }
908                                 while (method == null && (type = type.BaseType) != null)
909                                 {
910                                         method = type.FindMethod(name, methodSig);
911                                 }
912                                 if (method != null)
913                                 {
914                                         return method;
915                                 }
916                                 throw new MissingMethodException(org.ToString(), name);
917                         }
918                 }
919
920                 internal ByteReader GetStandAloneSig(int index)
921                 {
922                         return ByteReader.FromBlob(blobHeap, StandAloneSig.records[index]);
923                 }
924
925                 public override byte[] ResolveSignature(int metadataToken)
926                 {
927                         int index = (metadataToken & 0xFFFFFF) - 1;
928                         if ((metadataToken >> 24) == StandAloneSigTable.Index && index >= 0 && index < StandAloneSig.RowCount)
929                         {
930                                 ByteReader br = GetStandAloneSig(index);
931                                 return br.ReadBytes(br.Length);
932                         }
933                         else
934                         {
935                                 throw TokenOutOfRangeException(metadataToken);
936                         }
937                 }
938
939                 public override __StandAloneMethodSig __ResolveStandAloneMethodSig(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
940                 {
941                         int index = (metadataToken & 0xFFFFFF) - 1;
942                         if ((metadataToken >> 24) == StandAloneSigTable.Index && index >= 0 && index < StandAloneSig.RowCount)
943                         {
944                                 return MethodSignature.ReadStandAloneMethodSig(this, GetStandAloneSig(index), new GenericContext(genericTypeArguments, genericMethodArguments));
945                         }
946                         else
947                         {
948                                 throw TokenOutOfRangeException(metadataToken);
949                         }
950                 }
951
952                 internal MethodInfo GetEntryPoint()
953                 {
954                         if (cliHeader.EntryPointToken != 0 && (cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) == 0)
955                         {
956                                 return (MethodInfo)ResolveMethod((int)cliHeader.EntryPointToken);
957                         }
958                         return null;
959                 }
960
961                 internal string[] GetManifestResourceNames()
962                 {
963                         string[] names = new string[ManifestResource.records.Length];
964                         for (int i = 0; i < ManifestResource.records.Length; i++)
965                         {
966                                 names[i] = GetString(ManifestResource.records[i].Name);
967                         }
968                         return names;
969                 }
970
971                 internal ManifestResourceInfo GetManifestResourceInfo(string resourceName)
972                 {
973                         for (int i = 0; i < ManifestResource.records.Length; i++)
974                         {
975                                 if (resourceName == GetString(ManifestResource.records[i].Name))
976                                 {
977                                         return new ManifestResourceInfo(this, i);
978                                 }
979                         }
980                         return null;
981                 }
982
983                 internal Stream GetManifestResourceStream(string resourceName)
984                 {
985                         for (int i = 0; i < ManifestResource.records.Length; i++)
986                         {
987                                 if (resourceName == GetString(ManifestResource.records[i].Name))
988                                 {
989                                         if (ManifestResource.records[i].Implementation != 0x26000000)
990                                         {
991                                                 throw new NotImplementedException();
992                                         }
993                                         SeekRVA((int)cliHeader.Resources.VirtualAddress + ManifestResource.records[i].Offset);
994                                         BinaryReader br = new BinaryReader(stream);
995                                         int length = br.ReadInt32();
996                                         return new MemoryStream(br.ReadBytes(length));
997                                 }
998                         }
999                         throw new FileNotFoundException();
1000                 }
1001
1002                 public override AssemblyName[] __GetReferencedAssemblies()
1003                 {
1004                         List<AssemblyName> list = new List<AssemblyName>();
1005                         for (int i = 0; i < AssemblyRef.records.Length; i++)
1006                         {
1007                                 AssemblyName name = new AssemblyName();
1008                                 name.Name = GetString(AssemblyRef.records[i].Name);
1009                                 name.Version = new Version(
1010                                         AssemblyRef.records[i].MajorVersion,
1011                                         AssemblyRef.records[i].MinorVersion,
1012                                         AssemblyRef.records[i].BuildNumber,
1013                                         AssemblyRef.records[i].RevisionNumber);
1014                                 if (AssemblyRef.records[i].PublicKeyOrToken != 0)
1015                                 {
1016                                         byte[] keyOrToken = GetBlobCopy(AssemblyRef.records[i].PublicKeyOrToken);
1017                                         const int PublicKey = 0x0001;
1018                                         if ((AssemblyRef.records[i].Flags & PublicKey) != 0)
1019                                         {
1020                                                 name.SetPublicKey(keyOrToken);
1021                                         }
1022                                         else
1023                                         {
1024                                                 name.SetPublicKeyToken(keyOrToken);
1025                                         }
1026                                 }
1027                                 else
1028                                 {
1029                                         name.SetPublicKeyToken(Empty<byte>.Array);
1030                                 }
1031                                 if (AssemblyRef.records[i].Culture != 0)
1032                                 {
1033                                         name.Culture = GetString(AssemblyRef.records[i].Culture);
1034                                 }
1035                                 else
1036                                 {
1037                                         name.Culture = "";
1038                                 }
1039                                 if (AssemblyRef.records[i].HashValue != 0)
1040                                 {
1041                                         name.hash = GetBlobCopy(AssemblyRef.records[i].HashValue);
1042                                 }
1043                                 name.Flags = (AssemblyNameFlags)AssemblyRef.records[i].Flags;
1044                                 list.Add(name);
1045                         }
1046                         return list.ToArray();
1047                 }
1048
1049                 public override void __ResolveReferencedAssemblies(Assembly[] assemblies)
1050                 {
1051                         if (assemblyRefs == null)
1052                         {
1053                                 assemblyRefs = new Assembly[AssemblyRef.RowCount];
1054                         }
1055                         for (int i = 0; i < assemblies.Length; i++)
1056                         {
1057                                 if (assemblyRefs[i] == null)
1058                                 {
1059                                         assemblyRefs[i] = assemblies[i];
1060                                 }
1061                         }
1062                 }
1063
1064                 public override string[] __GetReferencedModules()
1065                 {
1066                         string[] arr = new string[this.ModuleRef.RowCount];
1067                         for (int i = 0; i < arr.Length; i++)
1068                         {
1069                                 arr[i] = GetString(this.ModuleRef.records[i]);
1070                         }
1071                         return arr;
1072                 }
1073
1074                 public override Type[] __GetReferencedTypes()
1075                 {
1076                         Type[] arr = new Type[this.TypeRef.RowCount];
1077                         for (int i = 0; i < arr.Length; i++)
1078                         {
1079                                 arr[i] = ResolveType((TypeRefTable.Index << 24) + i + 1);
1080                         }
1081                         return arr;
1082                 }
1083
1084                 public override Type[] __GetExportedTypes()
1085                 {
1086                         Type[] arr = new Type[this.ExportedType.RowCount];
1087                         for (int i = 0; i < arr.Length; i++)
1088                         {
1089                                 arr[i] = ResolveExportedType(i);
1090                         }
1091                         return arr;
1092                 }
1093
1094                 private Type ResolveExportedType(int index)
1095                 {
1096                         TypeName typeName = GetTypeName(ExportedType.records[index].TypeNamespace, ExportedType.records[index].TypeName);
1097                         int implementation = ExportedType.records[index].Implementation;
1098                         int token = ExportedType.records[index].TypeDefId;
1099                         switch (implementation >> 24)
1100                         {
1101                                 case AssemblyRefTable.Index:
1102                                         return ResolveAssemblyRef((implementation & 0xFFFFFF) - 1).ResolveType(typeName).SetMetadataTokenForMissing(token);
1103                                 case ExportedTypeTable.Index:
1104                                         return ResolveExportedType((implementation & 0xFFFFFF) - 1).ResolveNestedType(typeName).SetMetadataTokenForMissing(token);
1105                                 default:
1106                                         throw new NotImplementedException();
1107                         }
1108                 }
1109
1110                 internal override Type GetModuleType()
1111                 {
1112                         PopulateTypeDef();
1113                         return moduleType;
1114                 }
1115
1116                 public override string __ImageRuntimeVersion
1117                 {
1118                         get { return imageRuntimeVersion; }
1119                 }
1120
1121                 public override int MDStreamVersion
1122                 {
1123                         get { return metadataStreamVersion; }
1124                 }
1125
1126                 public override void __GetDataDirectoryEntry(int index, out int rva, out int length)
1127                 {
1128                         peFile.GetDataDirectoryEntry(index, out rva, out length);
1129                 }
1130
1131                 public override long __RelativeVirtualAddressToFileOffset(int rva)
1132                 {
1133                         return peFile.RvaToFileOffset((uint)rva);
1134                 }
1135
1136                 public override bool __GetSectionInfo(int rva, out string name, out int characteristics)
1137                 {
1138                         return peFile.GetSectionInfo(rva, out name, out characteristics);
1139                 }
1140
1141                 public override int __ReadDataFromRVA(int rva, byte[] data, int offset, int length)
1142                 {
1143                         SeekRVA(rva);
1144                         int totalBytesRead = 0;
1145                         while (length > 0)
1146                         {
1147                                 int read = stream.Read(data, offset, length);
1148                                 if (read == 0)
1149                                 {
1150                                         // C++ assemblies can have fields that have an RVA that lies outside of the file
1151                                         break;
1152                                 }
1153                                 offset += read;
1154                                 length -= read;
1155                                 totalBytesRead += read;
1156                         }
1157                         return totalBytesRead;
1158                 }
1159
1160                 public override void GetPEKind(out PortableExecutableKinds peKind, out ImageFileMachine machine)
1161                 {
1162                         peKind = 0;
1163                         if ((cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_ILONLY) != 0)
1164                         {
1165                                 peKind |= PortableExecutableKinds.ILOnly;
1166                         }
1167                         switch (cliHeader.Flags & (CliHeader.COMIMAGE_FLAGS_32BITREQUIRED | CliHeader.COMIMAGE_FLAGS_32BITPREFERRED))
1168                         {
1169                                 case CliHeader.COMIMAGE_FLAGS_32BITREQUIRED:
1170                                         peKind |= PortableExecutableKinds.Required32Bit;
1171                                         break;
1172                                 case CliHeader.COMIMAGE_FLAGS_32BITREQUIRED | CliHeader.COMIMAGE_FLAGS_32BITPREFERRED:
1173                                         peKind |= PortableExecutableKinds.Preferred32Bit;
1174                                         break;
1175                                 default:
1176                                         // COMIMAGE_FLAGS_32BITPREFERRED by itself is illegal, so we ignore it
1177                                         // (not setting any flag is ok)
1178                                         break;
1179                         }
1180                         if (peFile.OptionalHeader.Magic == IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC)
1181                         {
1182                                 peKind |= PortableExecutableKinds.PE32Plus;
1183                         }
1184
1185                         machine = (ImageFileMachine)peFile.FileHeader.Machine;
1186                 }
1187
1188                 public override int __Subsystem
1189                 {
1190                         get { return peFile.OptionalHeader.Subsystem; }
1191                 }
1192
1193                 public override IList<CustomAttributeData> __GetPlaceholderAssemblyCustomAttributes(bool multiple, bool security)
1194                 {
1195                         TypeName typeName;
1196                         switch ((multiple ? 1 : 0) + (security ? 2 : 0))
1197                         {
1198                                 case 0:
1199                                         typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHere");
1200                                         break;
1201                                 case 1:
1202                                         typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHereM");
1203                                         break;
1204                                 case 2:
1205                                         typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHereS");
1206                                         break;
1207                                 case 3:
1208                                 default:
1209                                         typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHereSM");
1210                                         break;
1211                         }
1212                         List<CustomAttributeData> list = new List<CustomAttributeData>();
1213                         for (int i = 0; i < CustomAttribute.records.Length; i++)
1214                         {
1215                                 if ((CustomAttribute.records[i].Parent >> 24) == TypeRefTable.Index)
1216                                 {
1217                                         int index = (CustomAttribute.records[i].Parent & 0xFFFFFF) - 1;
1218                                         if (typeName == GetTypeName(TypeRef.records[index].TypeNameSpace, TypeRef.records[index].TypeName))
1219                                         {
1220                                                 list.Add(new CustomAttributeData(this, i));
1221                                         }
1222                                 }
1223                         }
1224                         return list;
1225                 }
1226
1227                 internal override void Dispose()
1228                 {
1229                         stream.Close();
1230                 }
1231
1232                 internal override void ExportTypes(int fileToken, IKVM.Reflection.Emit.ModuleBuilder manifestModule)
1233                 {
1234                         PopulateTypeDef();
1235                         manifestModule.ExportTypes(typeDefs, fileToken);
1236                 }
1237
1238                 protected override long GetImageBaseImpl()
1239                 {
1240                         return (long)peFile.OptionalHeader.ImageBase;
1241                 }
1242
1243                 protected override long GetStackReserveImpl()
1244                 {
1245                         return (long)peFile.OptionalHeader.SizeOfStackReserve;
1246                 }
1247
1248                 protected override int GetFileAlignmentImpl()
1249                 {
1250                         return (int)peFile.OptionalHeader.FileAlignment;
1251                 }
1252
1253                 protected override DllCharacteristics GetDllCharacteristicsImpl()
1254                 {
1255                         return (DllCharacteristics)peFile.OptionalHeader.DllCharacteristics;
1256                 }
1257
1258                 public override int __EntryPointRVA
1259                 {
1260                         get { return (cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) != 0 ? (int)cliHeader.EntryPointToken : 0; }
1261                 }
1262
1263                 public override int __EntryPointToken
1264                 {
1265                         get { return (cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) == 0 ? (int)cliHeader.EntryPointToken : 0; }
1266                 }
1267         }
1268 }