2 Copyright (C) 2009-2012 Jeroen Frijters
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.
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:
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.
27 using System.Collections.Generic;
28 using IKVM.Reflection.Metadata;
30 namespace IKVM.Reflection.Reader
32 sealed class StreamHeader
38 internal void Read(BinaryReader br)
40 Offset = br.ReadUInt32();
41 Size = br.ReadUInt32();
42 byte[] buf = new byte[32];
45 while ((b = br.ReadByte()) != 0)
49 Name = Encoding.UTF8.GetString(buf, 0, len); ;
50 int padding = -1 + ((len + 4) & ~3) - len;
51 br.BaseStream.Seek(padding, SeekOrigin.Current);
55 sealed class ModuleReader : Module
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>();
80 private sealed class LazyForwardedType
82 private readonly int assemblyRef;
85 internal LazyForwardedType(int assemblyRef)
87 this.assemblyRef = assemblyRef;
90 internal Type GetType(ModuleReader module, TypeName typeName)
94 Assembly asm = module.ResolveAssemblyRef(assemblyRef);
95 type = asm.ResolveType(typeName);
98 throw new TypeLoadException(typeName.ToString());
105 internal ModuleReader(AssemblyReader assembly, Universe universe, Stream stream, string location)
108 this.stream = stream;
109 this.location = location;
111 if (assembly == null && AssemblyTable.records.Length != 0)
113 assembly = new AssemblyReader(location, this);
115 this.assembly = assembly;
120 BinaryReader br = new BinaryReader(stream);
122 stream.Seek(peFile.RvaToFileOffset(peFile.GetComDescriptorVirtualAddress()), SeekOrigin.Begin);
124 stream.Seek(peFile.RvaToFileOffset(cliHeader.MetaData.VirtualAddress), SeekOrigin.Begin);
125 foreach (StreamHeader sh in ReadStreamHeaders(br, out imageRuntimeVersion))
130 stringHeap = ReadHeap(stream, sh);
133 blobHeap = ReadHeap(stream, sh);
136 userStringHeap = ReadHeap(stream, sh);
139 guidHeap = ReadHeap(stream, sh);
143 stream.Seek(peFile.RvaToFileOffset(cliHeader.MetaData.VirtualAddress + sh.Offset), SeekOrigin.Begin);
147 throw new BadImageFormatException("Unsupported stream: " + sh.Name);
152 internal void SetAssembly(Assembly assembly)
154 this.assembly = assembly;
157 private static StreamHeader[] ReadStreamHeaders(BinaryReader br, out string Version)
159 uint Signature = br.ReadUInt32();
160 if (Signature != 0x424A5342)
162 throw new BadImageFormatException("Invalid metadata signature");
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++)
175 streamHeaders[i] = new StreamHeader();
176 streamHeaders[i].Read(br);
178 return streamHeaders;
181 private void ReadTables(BinaryReader br)
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++)
194 if ((Valid & (1UL << i)) != 0)
196 tables[i].Sorted = (Sorted & (1UL << i)) != 0;
197 tables[i].RowCount = br.ReadInt32();
199 else if (tables[i] != null)
201 tables[i].RowCount = 0;
204 MetadataReader mr = new MetadataReader(this, br.BaseStream, HeapSizes);
205 for (int i = 0; i < 64; i++)
207 if ((Valid & (1UL << i)) != 0)
212 if (ParamPtr.RowCount != 0)
214 throw new NotImplementedException("ParamPtr table support has not yet been implemented.");
218 private byte[] ReadHeap(Stream stream, StreamHeader sh)
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; )
224 int read = stream.Read(buf, pos, buf.Length - pos);
227 throw new BadImageFormatException();
234 internal void SeekRVA(int rva)
236 stream.Seek(peFile.RvaToFileOffset((uint)rva), SeekOrigin.Begin);
239 internal override void GetTypesImpl(List<Type> list)
242 foreach (TypeDefImpl type in typeDefs)
244 if (type != moduleType)
251 private void PopulateTypeDef()
253 if (typeDefs == null)
255 typeDefs = new TypeDefImpl[TypeDef.records.Length];
256 for (int i = 0; i < typeDefs.Length; i++)
258 TypeDefImpl type = new TypeDefImpl(this, i);
260 if (type.IsModulePseudoType)
264 else if (!type.IsNestedByFlags)
266 types.Add(new TypeName(type.__Namespace, type.__Name), type);
269 // add forwarded types to forwardedTypes dictionary (because Module.GetType(string) should return them)
270 for (int i = 0; i < ExportedType.records.Length; i++)
272 int implementation = ExportedType.records[i].Implementation;
273 if (implementation >> 24 == AssemblyRefTable.Index)
275 TypeName typeName = GetTypeName(ExportedType.records[i].TypeNamespace, ExportedType.records[i].TypeName);
276 forwardedTypes.Add(typeName, new LazyForwardedType((implementation & 0xFFFFFF) - 1));
282 internal override string GetString(int index)
289 if (!strings.TryGetValue(index, out str))
292 while (stringHeap[index + len] != 0)
296 str = Encoding.UTF8.GetString(stringHeap, index, len);
297 strings.Add(index, str);
302 private static int ReadCompressedInt(byte[] buffer, ref int offset)
304 byte b1 = buffer[offset++];
309 else if ((b1 & 0xC0) == 0x80)
311 byte b2 = buffer[offset++];
312 return ((b1 & 0x3F) << 8) | b2;
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;
323 internal byte[] GetBlobCopy(int blobIndex)
325 int len = ReadCompressedInt(blobHeap, ref blobIndex);
326 byte[] buf = new byte[len];
327 Buffer.BlockCopy(blobHeap, blobIndex, buf, 0, len);
331 internal override ByteReader GetBlob(int blobIndex)
333 return ByteReader.FromBlob(blobHeap, blobIndex);
336 public override string ResolveString(int metadataToken)
339 if (!strings.TryGetValue(metadataToken, out str))
341 if ((metadataToken >> 24) != 0x70)
343 throw TokenOutOfRangeException(metadataToken);
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)
350 char ch = (char)(userStringHeap[index + i] | userStringHeap[index + i + 1] << 8);
354 strings.Add(metadataToken, str);
359 internal override Type ResolveType(int metadataToken, IGenericContext context)
361 int index = (metadataToken & 0xFFFFFF) - 1;
364 throw TokenOutOfRangeException(metadataToken);
366 else if ((metadataToken >> 24) == TypeDefTable.Index && index < TypeDef.RowCount)
369 return typeDefs[index];
371 else if ((metadataToken >> 24) == TypeRefTable.Index && index < TypeRef.RowCount)
373 if (typeRefs == null)
375 typeRefs = new Type[TypeRef.records.Length];
377 if (typeRefs[index] == null)
379 int scope = TypeRef.records[index].ResolutionScope;
382 case AssemblyRefTable.Index:
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);
389 case TypeRefTable.Index:
391 Type outer = ResolveType(scope, null);
392 TypeName typeName = GetTypeName(TypeRef.records[index].TypeNameSpace, TypeRef.records[index].TypeName);
393 typeRefs[index] = outer.ResolveNestedType(typeName);
396 case ModuleTable.Index:
397 case ModuleRefTable.Index:
400 if (scope >> 24 == ModuleTable.Index)
402 if (scope == 0 || scope == 1)
408 throw new NotImplementedException("self reference scope?");
413 module = ResolveModuleRef(ModuleRef.records[(scope & 0xFFFFFF) - 1]);
415 TypeName typeName = GetTypeName(TypeRef.records[index].TypeNameSpace, TypeRef.records[index].TypeName);
416 typeRefs[index] = module.FindType(typeName) ?? module.universe.GetMissingTypeOrThrow(module, null, typeName);
420 throw new NotImplementedException("ResolutionScope = " + scope.ToString("X"));
423 return typeRefs[index];
425 else if ((metadataToken >> 24) == TypeSpecTable.Index && index < TypeSpec.RowCount)
427 if (typeSpecs == null)
429 typeSpecs = new Type[TypeSpec.records.Length];
431 Type type = typeSpecs[index];
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)
438 typeSpecs[index] = type;
445 throw TokenOutOfRangeException(metadataToken);
449 private Module ResolveModuleRef(int moduleNameIndex)
451 string moduleName = GetString(moduleNameIndex);
452 Module module = assembly.GetModule(moduleName);
455 throw new FileNotFoundException(moduleName);
460 private sealed class TrackingGenericContext : IGenericContext
462 private readonly IGenericContext context;
465 internal TrackingGenericContext(IGenericContext context)
467 this.context = context;
475 public Type GetGenericTypeArgument(int index)
478 return context.GetGenericTypeArgument(index);
481 public Type GetGenericMethodArgument(int index)
484 return context.GetGenericMethodArgument(index);
488 private TypeName GetTypeName(int typeNamespace, int typeName)
490 return new TypeName(GetString(typeNamespace), GetString(typeName));
493 internal Assembly ResolveAssemblyRef(int index)
495 if (assemblyRefs == null)
497 assemblyRefs = new Assembly[AssemblyRef.RowCount];
499 if (assemblyRefs[index] == null)
501 assemblyRefs[index] = ResolveAssemblyRefImpl(ref AssemblyRef.records[index]);
503 return assemblyRefs[index];
506 private Assembly ResolveAssemblyRefImpl(ref AssemblyRefTable.Record rec)
508 const int PublicKey = 0x0001;
509 string name = String.Format("{0}, Version={1}.{2}.{3}.{4}, Culture={5}, {6}={7}",
515 rec.Culture == 0 ? "neutral" : GetString(rec.Culture),
516 (rec.Flags & PublicKey) == 0 ? "PublicKeyToken" : "PublicKey",
517 PublicKeyOrTokenToString(rec.PublicKeyOrToken));
518 return universe.Load(name, this.Assembly, true);
521 private string PublicKeyOrTokenToString(int publicKeyOrToken)
523 if (publicKeyOrToken == 0)
527 ByteReader br = GetBlob(publicKeyOrToken);
532 StringBuilder sb = new StringBuilder(br.Length * 2);
533 while (br.Length > 0)
535 sb.AppendFormat("{0:x2}", br.ReadByte());
537 return sb.ToString();
540 public override Guid ModuleVersionId
544 byte[] buf = new byte[16];
545 Buffer.BlockCopy(guidHeap, 16 * (ModuleTable.records[0].Mvid - 1), buf, 0, 16);
546 return new Guid(buf);
550 public override string FullyQualifiedName
552 get { return location ?? "<Unknown>"; }
555 public override string Name
557 get { return location == null ? "<Unknown>" : System.IO.Path.GetFileName(location); }
560 public override Assembly Assembly
562 get { return assembly; }
565 internal override Type FindType(TypeName typeName)
569 if (!types.TryGetValue(typeName, out type))
571 LazyForwardedType fw;
572 if (forwardedTypes.TryGetValue(typeName, out fw))
574 return fw.GetType(this, typeName);
580 internal override Type FindTypeIgnoreCase(TypeName lowerCaseName)
583 foreach (Type type in types.Values)
585 if (new TypeName(type.__Namespace, type.__Name).ToLowerInvariant() == lowerCaseName)
590 foreach (TypeName name in forwardedTypes.Keys)
592 if (name.ToLowerInvariant() == lowerCaseName)
594 return forwardedTypes[name].GetType(this, name);
600 private Exception TokenOutOfRangeException(int metadataToken)
602 return new ArgumentOutOfRangeException("metadataToken", String.Format("Token 0x{0:x8} is not valid in the scope of module {1}.", metadataToken, this.Name));
605 public override MemberInfo ResolveMember(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
607 switch (metadataToken >> 24)
609 case FieldTable.Index:
610 return ResolveField(metadataToken, genericTypeArguments, genericMethodArguments);
611 case MemberRefTable.Index:
612 int index = (metadataToken & 0xFFFFFF) - 1;
613 if (index < 0 || index >= MemberRef.RowCount)
617 return GetMemberRef(index, genericTypeArguments, genericMethodArguments);
618 case MethodDefTable.Index:
619 case MethodSpecTable.Index:
620 return ResolveMethod(metadataToken, genericTypeArguments, genericMethodArguments);
622 throw TokenOutOfRangeException(metadataToken);
626 internal FieldInfo GetFieldAt(TypeDefImpl owner, int index)
630 fields = new FieldInfo[Field.records.Length];
632 if (fields[index] == null)
634 fields[index] = new FieldDefImpl(this, owner ?? FindFieldOwner(index), index);
636 return fields[index];
639 public override FieldInfo ResolveField(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
641 int index = (metadataToken & 0xFFFFFF) - 1;
644 throw TokenOutOfRangeException(metadataToken);
646 else if ((metadataToken >> 24) == FieldTable.Index && index < Field.RowCount)
648 return GetFieldAt(null, index);
650 else if ((metadataToken >> 24) == MemberRefTable.Index && index < MemberRef.RowCount)
652 FieldInfo field = GetMemberRef(index, genericTypeArguments, genericMethodArguments) as FieldInfo;
657 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");
661 throw TokenOutOfRangeException(metadataToken);
665 private TypeDefImpl FindFieldOwner(int fieldIndex)
667 // TODO use binary search?
668 for (int i = 0; i < TypeDef.records.Length; i++)
670 int field = TypeDef.records[i].FieldList - 1;
671 int end = TypeDef.records.Length > i + 1 ? TypeDef.records[i + 1].FieldList - 1 : Field.records.Length;
672 if (field <= fieldIndex && fieldIndex < end)
678 throw new InvalidOperationException();
681 internal MethodBase GetMethodAt(TypeDefImpl owner, int index)
685 methods = new MethodBase[MethodDef.records.Length];
687 if (methods[index] == null)
689 MethodDefImpl method = new MethodDefImpl(this, owner ?? FindMethodOwner(index), index);
690 methods[index] = method.IsConstructor ? new ConstructorInfoImpl(method) : (MethodBase)method;
692 return methods[index];
695 public override MethodBase ResolveMethod(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
697 int index = (metadataToken & 0xFFFFFF) - 1;
700 throw TokenOutOfRangeException(metadataToken);
702 else if ((metadataToken >> 24) == MethodDefTable.Index && index < MethodDef.RowCount)
704 return GetMethodAt(null, index);
706 else if ((metadataToken >> 24) == MemberRefTable.Index && index < MemberRef.RowCount)
708 MethodBase method = GetMemberRef(index, genericTypeArguments, genericMethodArguments) as MethodBase;
713 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");
715 else if ((metadataToken >> 24) == MethodSpecTable.Index && index < MethodSpec.RowCount)
717 MethodInfo method = (MethodInfo)ResolveMethod(MethodSpec.records[index].Method, genericTypeArguments, genericMethodArguments);
718 ByteReader instantiation = ByteReader.FromBlob(blobHeap, MethodSpec.records[index].Instantiation);
719 return method.MakeGenericMethod(Signature.ReadMethodSpec(this, instantiation, new GenericContext(genericTypeArguments, genericMethodArguments)));
723 throw TokenOutOfRangeException(metadataToken);
727 public override Type[] __ResolveOptionalParameterTypes(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments, out CustomModifiers[] customModifiers)
729 int index = (metadataToken & 0xFFFFFF) - 1;
732 throw TokenOutOfRangeException(metadataToken);
734 else if ((metadataToken >> 24) == MemberRefTable.Index && index < MemberRef.RowCount)
736 int sig = MemberRef.records[index].Signature;
737 return Signature.ReadOptionalParameterTypes(this, GetBlob(sig), new GenericContext(genericTypeArguments, genericMethodArguments), out customModifiers);
739 else if ((metadataToken >> 24) == MethodDefTable.Index && index < MethodDef.RowCount)
741 // for convenience, we support passing a MethodDef token as well, because in some places
742 // it makes sense to have a vararg method that is referred to by its methoddef (e.g. ldftn).
743 // Note that MethodSpec doesn't make sense, because generic methods cannot be vararg.
744 customModifiers = Empty<CustomModifiers>.Array;
745 return Type.EmptyTypes;
749 throw TokenOutOfRangeException(metadataToken);
753 public override string ScopeName
755 get { return GetString(ModuleTable.records[0].Name); }
758 private TypeDefImpl FindMethodOwner(int methodIndex)
760 // TODO use binary search?
761 for (int i = 0; i < TypeDef.records.Length; i++)
763 int method = TypeDef.records[i].MethodList - 1;
764 int end = TypeDef.records.Length > i + 1 ? TypeDef.records[i + 1].MethodList - 1 : MethodDef.records.Length;
765 if (method <= methodIndex && methodIndex < end)
771 throw new InvalidOperationException();
774 private MemberInfo GetMemberRef(int index, Type[] genericTypeArguments, Type[] genericMethodArguments)
776 if (memberRefs == null)
778 memberRefs = new MemberInfo[MemberRef.records.Length];
780 if (memberRefs[index] == null)
782 int owner = MemberRef.records[index].Class;
783 int sig = MemberRef.records[index].Signature;
784 string name = GetString(MemberRef.records[index].Name);
787 case MethodDefTable.Index:
788 return GetMethodAt(null, (owner & 0xFFFFFF) - 1);
789 case ModuleRefTable.Index:
790 memberRefs[index] = ResolveTypeMemberRef(ResolveModuleType(owner), name, ByteReader.FromBlob(blobHeap, sig));
792 case TypeDefTable.Index:
793 case TypeRefTable.Index:
794 memberRefs[index] = ResolveTypeMemberRef(ResolveType(owner), name, ByteReader.FromBlob(blobHeap, sig));
796 case TypeSpecTable.Index:
798 Type type = ResolveType(owner, genericTypeArguments, genericMethodArguments);
801 MethodSignature methodSig = MethodSignature.ReadSig(this, ByteReader.FromBlob(blobHeap, sig), new GenericContext(genericTypeArguments, genericMethodArguments));
802 return type.FindMethod(name, methodSig)
803 ?? universe.GetMissingMethodOrThrow(type, name, methodSig);
805 else if (type.IsConstructedGenericType)
807 MemberInfo member = ResolveTypeMemberRef(type.GetGenericTypeDefinition(), name, ByteReader.FromBlob(blobHeap, sig));
808 MethodBase mb = member as MethodBase;
811 member = mb.BindTypeParameters(type);
813 FieldInfo fi = member as FieldInfo;
816 member = fi.BindTypeParameters(type);
822 return ResolveTypeMemberRef(type, name, ByteReader.FromBlob(blobHeap, sig));
826 throw new BadImageFormatException();
829 return memberRefs[index];
832 private Type ResolveModuleType(int token)
834 int index = (token & 0xFFFFFF) - 1;
835 string name = GetString(ModuleRef.records[index]);
836 Module module = assembly.GetModule(name);
837 if (module == null || module.IsResource())
839 throw new BadImageFormatException();
841 return module.GetModuleType();
844 private MemberInfo ResolveTypeMemberRef(Type type, string name, ByteReader sig)
846 if (sig.PeekByte() == Signature.FIELD)
849 FieldSignature fieldSig = FieldSignature.ReadSig(this, sig, type);
850 FieldInfo field = type.FindField(name, fieldSig);
851 if (field == null && universe.MissingMemberResolution)
853 return universe.GetMissingFieldOrThrow(type, name, fieldSig);
855 while (field == null && (type = type.BaseType) != null)
857 field = type.FindField(name, fieldSig);
863 throw new MissingFieldException(org.ToString(), name);
868 MethodSignature methodSig = MethodSignature.ReadSig(this, sig, type);
869 MethodBase method = type.FindMethod(name, methodSig);
870 if (method == null && universe.MissingMemberResolution)
872 return universe.GetMissingMethodOrThrow(type, name, methodSig);
874 while (method == null && (type = type.BaseType) != null)
876 method = type.FindMethod(name, methodSig);
882 throw new MissingMethodException(org.ToString(), name);
886 internal ByteReader GetStandAloneSig(int index)
888 return ByteReader.FromBlob(blobHeap, StandAloneSig.records[index]);
891 public override byte[] ResolveSignature(int metadataToken)
893 int index = (metadataToken & 0xFFFFFF) - 1;
894 if ((metadataToken >> 24) == StandAloneSigTable.Index && index >= 0 && index < StandAloneSig.RowCount)
896 ByteReader br = GetStandAloneSig(index);
897 return br.ReadBytes(br.Length);
901 throw TokenOutOfRangeException(metadataToken);
905 public override __StandAloneMethodSig __ResolveStandAloneMethodSig(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
907 int index = (metadataToken & 0xFFFFFF) - 1;
908 if ((metadataToken >> 24) == StandAloneSigTable.Index && index >= 0 && index < StandAloneSig.RowCount)
910 return MethodSignature.ReadStandAloneMethodSig(this, GetStandAloneSig(index), new GenericContext(genericTypeArguments, genericMethodArguments));
914 throw TokenOutOfRangeException(metadataToken);
918 internal MethodInfo GetEntryPoint()
920 if (cliHeader.EntryPointToken != 0 && (cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) == 0)
922 return (MethodInfo)ResolveMethod((int)cliHeader.EntryPointToken);
927 internal string[] GetManifestResourceNames()
929 string[] names = new string[ManifestResource.records.Length];
930 for (int i = 0; i < ManifestResource.records.Length; i++)
932 names[i] = GetString(ManifestResource.records[i].Name);
937 internal ManifestResourceInfo GetManifestResourceInfo(string resourceName)
939 for (int i = 0; i < ManifestResource.records.Length; i++)
941 if (resourceName == GetString(ManifestResource.records[i].Name))
943 ManifestResourceInfo info = new ManifestResourceInfo(this, i);
944 Assembly asm = info.ReferencedAssembly;
945 if (asm != null && !asm.__IsMissing && asm.GetManifestResourceInfo(resourceName) == null)
955 internal Stream GetManifestResourceStream(string resourceName)
957 for (int i = 0; i < ManifestResource.records.Length; i++)
959 if (resourceName == GetString(ManifestResource.records[i].Name))
961 if (ManifestResource.records[i].Implementation != 0x26000000)
963 ManifestResourceInfo info = new ManifestResourceInfo(this, i);
964 switch (ManifestResource.records[i].Implementation >> 24)
966 case FileTable.Index:
967 string fileName = Path.Combine(Path.GetDirectoryName(location), info.FileName);
968 if (System.IO.File.Exists(fileName))
970 // note that, like System.Reflection, we return null for zero length files and
971 // ManifestResource.Offset is ignored
972 FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete);
981 case AssemblyRefTable.Index:
982 Assembly asm = info.ReferencedAssembly;
987 return asm.GetManifestResourceStream(resourceName);
989 throw new BadImageFormatException();
992 SeekRVA((int)cliHeader.Resources.VirtualAddress + ManifestResource.records[i].Offset);
993 BinaryReader br = new BinaryReader(stream);
994 int length = br.ReadInt32();
995 return new MemoryStream(br.ReadBytes(length));
1001 public override AssemblyName[] __GetReferencedAssemblies()
1003 List<AssemblyName> list = new List<AssemblyName>();
1004 for (int i = 0; i < AssemblyRef.records.Length; i++)
1006 AssemblyName name = new AssemblyName();
1007 name.Name = GetString(AssemblyRef.records[i].Name);
1008 name.Version = new Version(
1009 AssemblyRef.records[i].MajorVersion,
1010 AssemblyRef.records[i].MinorVersion,
1011 AssemblyRef.records[i].BuildNumber,
1012 AssemblyRef.records[i].RevisionNumber);
1013 if (AssemblyRef.records[i].PublicKeyOrToken != 0)
1015 byte[] keyOrToken = GetBlobCopy(AssemblyRef.records[i].PublicKeyOrToken);
1016 const int PublicKey = 0x0001;
1017 if ((AssemblyRef.records[i].Flags & PublicKey) != 0)
1019 name.SetPublicKey(keyOrToken);
1023 name.SetPublicKeyToken(keyOrToken);
1028 name.SetPublicKeyToken(Empty<byte>.Array);
1030 if (AssemblyRef.records[i].Culture != 0)
1032 name.Culture = GetString(AssemblyRef.records[i].Culture);
1038 if (AssemblyRef.records[i].HashValue != 0)
1040 name.hash = GetBlobCopy(AssemblyRef.records[i].HashValue);
1042 name.Flags = (AssemblyNameFlags)AssemblyRef.records[i].Flags;
1045 return list.ToArray();
1048 public override void __ResolveReferencedAssemblies(Assembly[] assemblies)
1050 if (assemblyRefs == null)
1052 assemblyRefs = new Assembly[AssemblyRef.RowCount];
1054 for (int i = 0; i < assemblies.Length; i++)
1056 if (assemblyRefs[i] == null)
1058 assemblyRefs[i] = assemblies[i];
1063 public override string[] __GetReferencedModules()
1065 string[] arr = new string[this.ModuleRef.RowCount];
1066 for (int i = 0; i < arr.Length; i++)
1068 arr[i] = GetString(this.ModuleRef.records[i]);
1073 public override Type[] __GetReferencedTypes()
1075 Type[] arr = new Type[this.TypeRef.RowCount];
1076 for (int i = 0; i < arr.Length; i++)
1078 arr[i] = ResolveType((TypeRefTable.Index << 24) + i + 1);
1083 public override Type[] __GetExportedTypes()
1085 Type[] arr = new Type[this.ExportedType.RowCount];
1086 for (int i = 0; i < arr.Length; i++)
1088 arr[i] = ResolveExportedType(i);
1093 private Type ResolveExportedType(int index)
1095 TypeName typeName = GetTypeName(ExportedType.records[index].TypeNamespace, ExportedType.records[index].TypeName);
1096 int implementation = ExportedType.records[index].Implementation;
1097 int token = ExportedType.records[index].TypeDefId;
1098 switch (implementation >> 24)
1100 case AssemblyRefTable.Index:
1101 return ResolveAssemblyRef((implementation & 0xFFFFFF) - 1).ResolveType(typeName).SetMetadataTokenForMissing(token);
1102 case ExportedTypeTable.Index:
1103 return ResolveExportedType((implementation & 0xFFFFFF) - 1).ResolveNestedType(typeName).SetMetadataTokenForMissing(token);
1105 throw new NotImplementedException();
1109 internal override Type GetModuleType()
1115 public override string __ImageRuntimeVersion
1117 get { return imageRuntimeVersion; }
1120 public override int MDStreamVersion
1122 get { return metadataStreamVersion; }
1125 public override void __GetDataDirectoryEntry(int index, out int rva, out int length)
1127 peFile.GetDataDirectoryEntry(index, out rva, out length);
1130 public override long __RelativeVirtualAddressToFileOffset(int rva)
1132 return peFile.RvaToFileOffset((uint)rva);
1135 public override bool __GetSectionInfo(int rva, out string name, out int characteristics)
1137 return peFile.GetSectionInfo(rva, out name, out characteristics);
1140 public override int __ReadDataFromRVA(int rva, byte[] data, int offset, int length)
1143 int totalBytesRead = 0;
1146 int read = stream.Read(data, offset, length);
1149 // C++ assemblies can have fields that have an RVA that lies outside of the file
1154 totalBytesRead += read;
1156 return totalBytesRead;
1159 public override void GetPEKind(out PortableExecutableKinds peKind, out ImageFileMachine machine)
1162 if ((cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_ILONLY) != 0)
1164 peKind |= PortableExecutableKinds.ILOnly;
1166 switch (cliHeader.Flags & (CliHeader.COMIMAGE_FLAGS_32BITREQUIRED | CliHeader.COMIMAGE_FLAGS_32BITPREFERRED))
1168 case CliHeader.COMIMAGE_FLAGS_32BITREQUIRED:
1169 peKind |= PortableExecutableKinds.Required32Bit;
1171 case CliHeader.COMIMAGE_FLAGS_32BITREQUIRED | CliHeader.COMIMAGE_FLAGS_32BITPREFERRED:
1172 peKind |= PortableExecutableKinds.Preferred32Bit;
1175 // COMIMAGE_FLAGS_32BITPREFERRED by itself is illegal, so we ignore it
1176 // (not setting any flag is ok)
1179 if (peFile.OptionalHeader.Magic == IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC)
1181 peKind |= PortableExecutableKinds.PE32Plus;
1184 machine = (ImageFileMachine)peFile.FileHeader.Machine;
1187 public override int __Subsystem
1189 get { return peFile.OptionalHeader.Subsystem; }
1192 public override IList<CustomAttributeData> __GetPlaceholderAssemblyCustomAttributes(bool multiple, bool security)
1195 switch ((multiple ? 1 : 0) + (security ? 2 : 0))
1198 typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHere");
1201 typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHereM");
1204 typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHereS");
1208 typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHereSM");
1211 List<CustomAttributeData> list = new List<CustomAttributeData>();
1212 for (int i = 0; i < CustomAttribute.records.Length; i++)
1214 if ((CustomAttribute.records[i].Parent >> 24) == TypeRefTable.Index)
1216 int index = (CustomAttribute.records[i].Parent & 0xFFFFFF) - 1;
1217 if (typeName == GetTypeName(TypeRef.records[index].TypeNameSpace, TypeRef.records[index].TypeName))
1219 list.Add(new CustomAttributeData(this, i));
1226 internal override void Dispose()
1231 internal override void ExportTypes(int fileToken, IKVM.Reflection.Emit.ModuleBuilder manifestModule)
1234 manifestModule.ExportTypes(typeDefs, fileToken);
1237 protected override long GetImageBaseImpl()
1239 return (long)peFile.OptionalHeader.ImageBase;
1242 protected override long GetStackReserveImpl()
1244 return (long)peFile.OptionalHeader.SizeOfStackReserve;
1247 protected override int GetFileAlignmentImpl()
1249 return (int)peFile.OptionalHeader.FileAlignment;
1252 protected override DllCharacteristics GetDllCharacteristicsImpl()
1254 return (DllCharacteristics)peFile.OptionalHeader.DllCharacteristics;
1257 public override int __EntryPointRVA
1259 get { return (cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) != 0 ? (int)cliHeader.EntryPointToken : 0; }
1262 public override int __EntryPointToken
1264 get { return (cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) == 0 ? (int)cliHeader.EntryPointToken : 0; }