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 // we ignore unknown streams, because the CLR does so too
148 // (and some obfuscators add bogus streams)
154 internal void SetAssembly(Assembly assembly)
156 this.assembly = assembly;
159 private static StreamHeader[] ReadStreamHeaders(BinaryReader br, out string Version)
161 uint Signature = br.ReadUInt32();
162 if (Signature != 0x424A5342)
164 throw new BadImageFormatException("Invalid metadata signature");
166 /*ushort MajorVersion =*/ br.ReadUInt16();
167 /*ushort MinorVersion =*/ br.ReadUInt16();
168 /*uint Reserved =*/ br.ReadUInt32();
169 uint Length = br.ReadUInt32();
170 byte[] buf = br.ReadBytes((int)Length);
171 Version = Encoding.UTF8.GetString(buf).TrimEnd('\u0000');
172 /*ushort Flags =*/ br.ReadUInt16();
173 ushort Streams = br.ReadUInt16();
174 StreamHeader[] streamHeaders = new StreamHeader[Streams];
175 for (int i = 0; i < streamHeaders.Length; i++)
177 streamHeaders[i] = new StreamHeader();
178 streamHeaders[i].Read(br);
180 return streamHeaders;
183 private void ReadTables(BinaryReader br)
185 Table[] tables = GetTables();
186 /*uint Reserved0 =*/ br.ReadUInt32();
187 byte MajorVersion = br.ReadByte();
188 byte MinorVersion = br.ReadByte();
189 metadataStreamVersion = MajorVersion << 16 | MinorVersion;
190 byte HeapSizes = br.ReadByte();
191 /*byte Reserved7 =*/ br.ReadByte();
192 ulong Valid = br.ReadUInt64();
193 ulong Sorted = br.ReadUInt64();
194 for (int i = 0; i < 64; i++)
196 if ((Valid & (1UL << i)) != 0)
198 tables[i].Sorted = (Sorted & (1UL << i)) != 0;
199 tables[i].RowCount = br.ReadInt32();
201 else if (tables[i] != null)
203 tables[i].RowCount = 0;
206 MetadataReader mr = new MetadataReader(this, br.BaseStream, HeapSizes);
207 for (int i = 0; i < 64; i++)
209 if ((Valid & (1UL << i)) != 0)
214 if (ParamPtr.RowCount != 0)
216 throw new NotImplementedException("ParamPtr table support has not yet been implemented.");
220 private byte[] ReadHeap(Stream stream, StreamHeader sh)
222 byte[] buf = new byte[sh.Size];
223 stream.Seek(peFile.RvaToFileOffset(cliHeader.MetaData.VirtualAddress + sh.Offset), SeekOrigin.Begin);
224 for (int pos = 0; pos < buf.Length; )
226 int read = stream.Read(buf, pos, buf.Length - pos);
229 throw new BadImageFormatException();
236 internal void SeekRVA(int rva)
238 stream.Seek(peFile.RvaToFileOffset((uint)rva), SeekOrigin.Begin);
241 internal override void GetTypesImpl(List<Type> list)
244 foreach (TypeDefImpl type in typeDefs)
246 if (type != moduleType)
253 private void PopulateTypeDef()
255 if (typeDefs == null)
257 typeDefs = new TypeDefImpl[TypeDef.records.Length];
258 for (int i = 0; i < typeDefs.Length; i++)
260 TypeDefImpl type = new TypeDefImpl(this, i);
262 if (type.IsModulePseudoType)
266 else if (!type.IsNestedByFlags)
268 types.Add(new TypeName(type.__Namespace, type.__Name), type);
271 // add forwarded types to forwardedTypes dictionary (because Module.GetType(string) should return them)
272 for (int i = 0; i < ExportedType.records.Length; i++)
274 int implementation = ExportedType.records[i].Implementation;
275 if (implementation >> 24 == AssemblyRefTable.Index)
277 TypeName typeName = GetTypeName(ExportedType.records[i].TypeNamespace, ExportedType.records[i].TypeName);
278 forwardedTypes.Add(typeName, new LazyForwardedType((implementation & 0xFFFFFF) - 1));
284 internal override string GetString(int index)
291 if (!strings.TryGetValue(index, out str))
294 while (stringHeap[index + len] != 0)
298 str = Encoding.UTF8.GetString(stringHeap, index, len);
299 strings.Add(index, str);
304 private static int ReadCompressedInt(byte[] buffer, ref int offset)
306 byte b1 = buffer[offset++];
311 else if ((b1 & 0xC0) == 0x80)
313 byte b2 = buffer[offset++];
314 return ((b1 & 0x3F) << 8) | b2;
318 byte b2 = buffer[offset++];
319 byte b3 = buffer[offset++];
320 byte b4 = buffer[offset++];
321 return ((b1 & 0x3F) << 24) + (b2 << 16) + (b3 << 8) + b4;
325 internal byte[] GetBlobCopy(int blobIndex)
327 int len = ReadCompressedInt(blobHeap, ref blobIndex);
328 byte[] buf = new byte[len];
329 Buffer.BlockCopy(blobHeap, blobIndex, buf, 0, len);
333 internal override ByteReader GetBlob(int blobIndex)
335 return ByteReader.FromBlob(blobHeap, blobIndex);
338 public override string ResolveString(int metadataToken)
341 if (!strings.TryGetValue(metadataToken, out str))
343 if ((metadataToken >> 24) != 0x70)
345 throw TokenOutOfRangeException(metadataToken);
347 int index = metadataToken & 0xFFFFFF;
348 int len = ReadCompressedInt(userStringHeap, ref index) & ~1;
349 StringBuilder sb = new StringBuilder(len / 2);
350 for (int i = 0; i < len; i += 2)
352 char ch = (char)(userStringHeap[index + i] | userStringHeap[index + i + 1] << 8);
356 strings.Add(metadataToken, str);
361 internal override Type ResolveType(int metadataToken, IGenericContext context)
363 int index = (metadataToken & 0xFFFFFF) - 1;
366 throw TokenOutOfRangeException(metadataToken);
368 else if ((metadataToken >> 24) == TypeDefTable.Index && index < TypeDef.RowCount)
371 return typeDefs[index];
373 else if ((metadataToken >> 24) == TypeRefTable.Index && index < TypeRef.RowCount)
375 if (typeRefs == null)
377 typeRefs = new Type[TypeRef.records.Length];
379 if (typeRefs[index] == null)
381 int scope = TypeRef.records[index].ResolutionScope;
384 case AssemblyRefTable.Index:
386 Assembly assembly = ResolveAssemblyRef((scope & 0xFFFFFF) - 1);
387 TypeName typeName = GetTypeName(TypeRef.records[index].TypeNameSpace, TypeRef.records[index].TypeName);
388 typeRefs[index] = assembly.ResolveType(typeName);
391 case TypeRefTable.Index:
393 Type outer = ResolveType(scope, null);
394 TypeName typeName = GetTypeName(TypeRef.records[index].TypeNameSpace, TypeRef.records[index].TypeName);
395 typeRefs[index] = outer.ResolveNestedType(typeName);
398 case ModuleTable.Index:
399 case ModuleRefTable.Index:
402 if (scope >> 24 == ModuleTable.Index)
404 if (scope == 0 || scope == 1)
410 throw new NotImplementedException("self reference scope?");
415 module = ResolveModuleRef(ModuleRef.records[(scope & 0xFFFFFF) - 1]);
417 TypeName typeName = GetTypeName(TypeRef.records[index].TypeNameSpace, TypeRef.records[index].TypeName);
418 typeRefs[index] = module.FindType(typeName) ?? module.universe.GetMissingTypeOrThrow(module, null, typeName);
422 throw new NotImplementedException("ResolutionScope = " + scope.ToString("X"));
425 return typeRefs[index];
427 else if ((metadataToken >> 24) == TypeSpecTable.Index && index < TypeSpec.RowCount)
429 if (typeSpecs == null)
431 typeSpecs = new Type[TypeSpec.records.Length];
433 Type type = typeSpecs[index];
436 TrackingGenericContext tc = context == null ? null : new TrackingGenericContext(context);
437 type = Signature.ReadTypeSpec(this, ByteReader.FromBlob(blobHeap, TypeSpec.records[index]), tc);
438 if (tc == null || !tc.IsUsed)
440 typeSpecs[index] = type;
447 throw TokenOutOfRangeException(metadataToken);
451 private Module ResolveModuleRef(int moduleNameIndex)
453 string moduleName = GetString(moduleNameIndex);
454 Module module = assembly.GetModule(moduleName);
457 throw new FileNotFoundException(moduleName);
462 private sealed class TrackingGenericContext : IGenericContext
464 private readonly IGenericContext context;
467 internal TrackingGenericContext(IGenericContext context)
469 this.context = context;
477 public Type GetGenericTypeArgument(int index)
480 return context.GetGenericTypeArgument(index);
483 public Type GetGenericMethodArgument(int index)
486 return context.GetGenericMethodArgument(index);
490 private TypeName GetTypeName(int typeNamespace, int typeName)
492 return new TypeName(GetString(typeNamespace), GetString(typeName));
495 internal Assembly ResolveAssemblyRef(int index)
497 if (assemblyRefs == null)
499 assemblyRefs = new Assembly[AssemblyRef.RowCount];
501 if (assemblyRefs[index] == null)
503 assemblyRefs[index] = ResolveAssemblyRefImpl(ref AssemblyRef.records[index]);
505 return assemblyRefs[index];
508 private Assembly ResolveAssemblyRefImpl(ref AssemblyRefTable.Record rec)
510 const int PublicKey = 0x0001;
511 string name = String.Format("{0}, Version={1}.{2}.{3}.{4}, Culture={5}, {6}={7}",
517 rec.Culture == 0 ? "neutral" : GetString(rec.Culture),
518 (rec.Flags & PublicKey) == 0 ? "PublicKeyToken" : "PublicKey",
519 PublicKeyOrTokenToString(rec.PublicKeyOrToken));
520 return universe.Load(name, this.Assembly, true);
523 private string PublicKeyOrTokenToString(int publicKeyOrToken)
525 if (publicKeyOrToken == 0)
529 ByteReader br = GetBlob(publicKeyOrToken);
534 StringBuilder sb = new StringBuilder(br.Length * 2);
535 while (br.Length > 0)
537 sb.AppendFormat("{0:x2}", br.ReadByte());
539 return sb.ToString();
542 public override Guid ModuleVersionId
546 byte[] buf = new byte[16];
547 Buffer.BlockCopy(guidHeap, 16 * (ModuleTable.records[0].Mvid - 1), buf, 0, 16);
548 return new Guid(buf);
552 public override string FullyQualifiedName
554 get { return location ?? "<Unknown>"; }
557 public override string Name
559 get { return location == null ? "<Unknown>" : System.IO.Path.GetFileName(location); }
562 public override Assembly Assembly
564 get { return assembly; }
567 internal override Type FindType(TypeName typeName)
571 if (!types.TryGetValue(typeName, out type))
573 LazyForwardedType fw;
574 if (forwardedTypes.TryGetValue(typeName, out fw))
576 return fw.GetType(this, typeName);
582 internal override Type FindTypeIgnoreCase(TypeName lowerCaseName)
585 foreach (Type type in types.Values)
587 if (new TypeName(type.__Namespace, type.__Name).ToLowerInvariant() == lowerCaseName)
592 foreach (TypeName name in forwardedTypes.Keys)
594 if (name.ToLowerInvariant() == lowerCaseName)
596 return forwardedTypes[name].GetType(this, name);
602 private Exception TokenOutOfRangeException(int metadataToken)
604 return new ArgumentOutOfRangeException("metadataToken", String.Format("Token 0x{0:x8} is not valid in the scope of module {1}.", metadataToken, this.Name));
607 public override MemberInfo ResolveMember(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
609 switch (metadataToken >> 24)
611 case FieldTable.Index:
612 return ResolveField(metadataToken, genericTypeArguments, genericMethodArguments);
613 case MemberRefTable.Index:
614 int index = (metadataToken & 0xFFFFFF) - 1;
615 if (index < 0 || index >= MemberRef.RowCount)
619 return GetMemberRef(index, genericTypeArguments, genericMethodArguments);
620 case MethodDefTable.Index:
621 case MethodSpecTable.Index:
622 return ResolveMethod(metadataToken, genericTypeArguments, genericMethodArguments);
624 throw TokenOutOfRangeException(metadataToken);
628 internal FieldInfo GetFieldAt(TypeDefImpl owner, int index)
632 fields = new FieldInfo[Field.records.Length];
634 if (fields[index] == null)
636 fields[index] = new FieldDefImpl(this, owner ?? FindFieldOwner(index), index);
638 return fields[index];
641 public override FieldInfo ResolveField(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
643 int index = (metadataToken & 0xFFFFFF) - 1;
646 throw TokenOutOfRangeException(metadataToken);
648 else if ((metadataToken >> 24) == FieldTable.Index && index < Field.RowCount)
650 return GetFieldAt(null, index);
652 else if ((metadataToken >> 24) == MemberRefTable.Index && index < MemberRef.RowCount)
654 FieldInfo field = GetMemberRef(index, genericTypeArguments, genericMethodArguments) as FieldInfo;
659 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");
663 throw TokenOutOfRangeException(metadataToken);
667 private TypeDefImpl FindFieldOwner(int fieldIndex)
669 // TODO use binary search?
670 for (int i = 0; i < TypeDef.records.Length; i++)
672 int field = TypeDef.records[i].FieldList - 1;
673 int end = TypeDef.records.Length > i + 1 ? TypeDef.records[i + 1].FieldList - 1 : Field.records.Length;
674 if (field <= fieldIndex && fieldIndex < end)
680 throw new InvalidOperationException();
683 internal MethodBase GetMethodAt(TypeDefImpl owner, int index)
687 methods = new MethodBase[MethodDef.records.Length];
689 if (methods[index] == null)
691 MethodDefImpl method = new MethodDefImpl(this, owner ?? FindMethodOwner(index), index);
692 methods[index] = method.IsConstructor ? new ConstructorInfoImpl(method) : (MethodBase)method;
694 return methods[index];
697 public override MethodBase ResolveMethod(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
699 int index = (metadataToken & 0xFFFFFF) - 1;
702 throw TokenOutOfRangeException(metadataToken);
704 else if ((metadataToken >> 24) == MethodDefTable.Index && index < MethodDef.RowCount)
706 return GetMethodAt(null, index);
708 else if ((metadataToken >> 24) == MemberRefTable.Index && index < MemberRef.RowCount)
710 MethodBase method = GetMemberRef(index, genericTypeArguments, genericMethodArguments) as MethodBase;
715 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");
717 else if ((metadataToken >> 24) == MethodSpecTable.Index && index < MethodSpec.RowCount)
719 MethodInfo method = (MethodInfo)ResolveMethod(MethodSpec.records[index].Method, genericTypeArguments, genericMethodArguments);
720 ByteReader instantiation = ByteReader.FromBlob(blobHeap, MethodSpec.records[index].Instantiation);
721 return method.MakeGenericMethod(Signature.ReadMethodSpec(this, instantiation, new GenericContext(genericTypeArguments, genericMethodArguments)));
725 throw TokenOutOfRangeException(metadataToken);
729 public override Type[] __ResolveOptionalParameterTypes(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments, out CustomModifiers[] customModifiers)
731 int index = (metadataToken & 0xFFFFFF) - 1;
734 throw TokenOutOfRangeException(metadataToken);
736 else if ((metadataToken >> 24) == MemberRefTable.Index && index < MemberRef.RowCount)
738 int sig = MemberRef.records[index].Signature;
739 return Signature.ReadOptionalParameterTypes(this, GetBlob(sig), new GenericContext(genericTypeArguments, genericMethodArguments), out customModifiers);
741 else if ((metadataToken >> 24) == MethodDefTable.Index && index < MethodDef.RowCount)
743 // for convenience, we support passing a MethodDef token as well, because in some places
744 // it makes sense to have a vararg method that is referred to by its methoddef (e.g. ldftn).
745 // Note that MethodSpec doesn't make sense, because generic methods cannot be vararg.
746 customModifiers = Empty<CustomModifiers>.Array;
747 return Type.EmptyTypes;
751 throw TokenOutOfRangeException(metadataToken);
755 public override string ScopeName
757 get { return GetString(ModuleTable.records[0].Name); }
760 private TypeDefImpl FindMethodOwner(int methodIndex)
762 // TODO use binary search?
763 for (int i = 0; i < TypeDef.records.Length; i++)
765 int method = TypeDef.records[i].MethodList - 1;
766 int end = TypeDef.records.Length > i + 1 ? TypeDef.records[i + 1].MethodList - 1 : MethodDef.records.Length;
767 if (method <= methodIndex && methodIndex < end)
773 throw new InvalidOperationException();
776 private MemberInfo GetMemberRef(int index, Type[] genericTypeArguments, Type[] genericMethodArguments)
778 if (memberRefs == null)
780 memberRefs = new MemberInfo[MemberRef.records.Length];
782 if (memberRefs[index] == null)
784 int owner = MemberRef.records[index].Class;
785 int sig = MemberRef.records[index].Signature;
786 string name = GetString(MemberRef.records[index].Name);
789 case MethodDefTable.Index:
790 return GetMethodAt(null, (owner & 0xFFFFFF) - 1);
791 case ModuleRefTable.Index:
792 memberRefs[index] = ResolveTypeMemberRef(ResolveModuleType(owner), name, ByteReader.FromBlob(blobHeap, sig));
794 case TypeDefTable.Index:
795 case TypeRefTable.Index:
796 memberRefs[index] = ResolveTypeMemberRef(ResolveType(owner), name, ByteReader.FromBlob(blobHeap, sig));
798 case TypeSpecTable.Index:
800 Type type = ResolveType(owner, genericTypeArguments, genericMethodArguments);
803 MethodSignature methodSig = MethodSignature.ReadSig(this, ByteReader.FromBlob(blobHeap, sig), new GenericContext(genericTypeArguments, genericMethodArguments));
804 return type.FindMethod(name, methodSig)
805 ?? universe.GetMissingMethodOrThrow(type, name, methodSig);
807 else if (type.IsConstructedGenericType)
809 MemberInfo member = ResolveTypeMemberRef(type.GetGenericTypeDefinition(), name, ByteReader.FromBlob(blobHeap, sig));
810 MethodBase mb = member as MethodBase;
813 member = mb.BindTypeParameters(type);
815 FieldInfo fi = member as FieldInfo;
818 member = fi.BindTypeParameters(type);
824 return ResolveTypeMemberRef(type, name, ByteReader.FromBlob(blobHeap, sig));
828 throw new BadImageFormatException();
831 return memberRefs[index];
834 private Type ResolveModuleType(int token)
836 int index = (token & 0xFFFFFF) - 1;
837 string name = GetString(ModuleRef.records[index]);
838 Module module = assembly.GetModule(name);
839 if (module == null || module.IsResource())
841 throw new BadImageFormatException();
843 return module.GetModuleType();
846 private MemberInfo ResolveTypeMemberRef(Type type, string name, ByteReader sig)
848 if (sig.PeekByte() == Signature.FIELD)
851 FieldSignature fieldSig = FieldSignature.ReadSig(this, sig, type);
852 FieldInfo field = type.FindField(name, fieldSig);
853 if (field == null && universe.MissingMemberResolution)
855 return universe.GetMissingFieldOrThrow(type, name, fieldSig);
857 while (field == null && (type = type.BaseType) != null)
859 field = type.FindField(name, fieldSig);
865 throw new MissingFieldException(org.ToString(), name);
870 MethodSignature methodSig = MethodSignature.ReadSig(this, sig, type);
871 MethodBase method = type.FindMethod(name, methodSig);
872 if (method == null && universe.MissingMemberResolution)
874 return universe.GetMissingMethodOrThrow(type, name, methodSig);
876 while (method == null && (type = type.BaseType) != null)
878 method = type.FindMethod(name, methodSig);
884 throw new MissingMethodException(org.ToString(), name);
888 internal ByteReader GetStandAloneSig(int index)
890 return ByteReader.FromBlob(blobHeap, StandAloneSig.records[index]);
893 public override byte[] ResolveSignature(int metadataToken)
895 int index = (metadataToken & 0xFFFFFF) - 1;
896 if ((metadataToken >> 24) == StandAloneSigTable.Index && index >= 0 && index < StandAloneSig.RowCount)
898 ByteReader br = GetStandAloneSig(index);
899 return br.ReadBytes(br.Length);
903 throw TokenOutOfRangeException(metadataToken);
907 public override __StandAloneMethodSig __ResolveStandAloneMethodSig(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
909 int index = (metadataToken & 0xFFFFFF) - 1;
910 if ((metadataToken >> 24) == StandAloneSigTable.Index && index >= 0 && index < StandAloneSig.RowCount)
912 return MethodSignature.ReadStandAloneMethodSig(this, GetStandAloneSig(index), new GenericContext(genericTypeArguments, genericMethodArguments));
916 throw TokenOutOfRangeException(metadataToken);
920 internal MethodInfo GetEntryPoint()
922 if (cliHeader.EntryPointToken != 0 && (cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) == 0)
924 return (MethodInfo)ResolveMethod((int)cliHeader.EntryPointToken);
929 internal string[] GetManifestResourceNames()
931 string[] names = new string[ManifestResource.records.Length];
932 for (int i = 0; i < ManifestResource.records.Length; i++)
934 names[i] = GetString(ManifestResource.records[i].Name);
939 internal ManifestResourceInfo GetManifestResourceInfo(string resourceName)
941 for (int i = 0; i < ManifestResource.records.Length; i++)
943 if (resourceName == GetString(ManifestResource.records[i].Name))
945 ManifestResourceInfo info = new ManifestResourceInfo(this, i);
946 Assembly asm = info.ReferencedAssembly;
947 if (asm != null && !asm.__IsMissing && asm.GetManifestResourceInfo(resourceName) == null)
957 internal Stream GetManifestResourceStream(string resourceName)
959 for (int i = 0; i < ManifestResource.records.Length; i++)
961 if (resourceName == GetString(ManifestResource.records[i].Name))
963 if (ManifestResource.records[i].Implementation != 0x26000000)
965 ManifestResourceInfo info = new ManifestResourceInfo(this, i);
966 switch (ManifestResource.records[i].Implementation >> 24)
968 case FileTable.Index:
969 string fileName = Path.Combine(Path.GetDirectoryName(location), info.FileName);
970 if (System.IO.File.Exists(fileName))
972 // note that, like System.Reflection, we return null for zero length files and
973 // ManifestResource.Offset is ignored
974 FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete);
983 case AssemblyRefTable.Index:
984 Assembly asm = info.ReferencedAssembly;
989 return asm.GetManifestResourceStream(resourceName);
991 throw new BadImageFormatException();
994 SeekRVA((int)cliHeader.Resources.VirtualAddress + ManifestResource.records[i].Offset);
995 BinaryReader br = new BinaryReader(stream);
996 int length = br.ReadInt32();
997 return new MemoryStream(br.ReadBytes(length));
1003 public override AssemblyName[] __GetReferencedAssemblies()
1005 List<AssemblyName> list = new List<AssemblyName>();
1006 for (int i = 0; i < AssemblyRef.records.Length; i++)
1008 AssemblyName name = new AssemblyName();
1009 name.Name = GetString(AssemblyRef.records[i].Name);
1010 name.Version = new Version(
1011 AssemblyRef.records[i].MajorVersion,
1012 AssemblyRef.records[i].MinorVersion,
1013 AssemblyRef.records[i].BuildNumber,
1014 AssemblyRef.records[i].RevisionNumber);
1015 if (AssemblyRef.records[i].PublicKeyOrToken != 0)
1017 byte[] keyOrToken = GetBlobCopy(AssemblyRef.records[i].PublicKeyOrToken);
1018 const int PublicKey = 0x0001;
1019 if ((AssemblyRef.records[i].Flags & PublicKey) != 0)
1021 name.SetPublicKey(keyOrToken);
1025 name.SetPublicKeyToken(keyOrToken);
1030 name.SetPublicKeyToken(Empty<byte>.Array);
1032 if (AssemblyRef.records[i].Culture != 0)
1034 name.Culture = GetString(AssemblyRef.records[i].Culture);
1040 if (AssemblyRef.records[i].HashValue != 0)
1042 name.hash = GetBlobCopy(AssemblyRef.records[i].HashValue);
1044 name.Flags = (AssemblyNameFlags)AssemblyRef.records[i].Flags;
1047 return list.ToArray();
1050 public override void __ResolveReferencedAssemblies(Assembly[] assemblies)
1052 if (assemblyRefs == null)
1054 assemblyRefs = new Assembly[AssemblyRef.RowCount];
1056 for (int i = 0; i < assemblies.Length; i++)
1058 if (assemblyRefs[i] == null)
1060 assemblyRefs[i] = assemblies[i];
1065 public override string[] __GetReferencedModules()
1067 string[] arr = new string[this.ModuleRef.RowCount];
1068 for (int i = 0; i < arr.Length; i++)
1070 arr[i] = GetString(this.ModuleRef.records[i]);
1075 public override Type[] __GetReferencedTypes()
1077 Type[] arr = new Type[this.TypeRef.RowCount];
1078 for (int i = 0; i < arr.Length; i++)
1080 arr[i] = ResolveType((TypeRefTable.Index << 24) + i + 1);
1085 public override Type[] __GetExportedTypes()
1087 Type[] arr = new Type[this.ExportedType.RowCount];
1088 for (int i = 0; i < arr.Length; i++)
1090 arr[i] = ResolveExportedType(i);
1095 private Type ResolveExportedType(int index)
1097 TypeName typeName = GetTypeName(ExportedType.records[index].TypeNamespace, ExportedType.records[index].TypeName);
1098 int implementation = ExportedType.records[index].Implementation;
1099 int token = ExportedType.records[index].TypeDefId;
1100 switch (implementation >> 24)
1102 case AssemblyRefTable.Index:
1103 return ResolveAssemblyRef((implementation & 0xFFFFFF) - 1).ResolveType(typeName).SetMetadataTokenForMissing(token);
1104 case ExportedTypeTable.Index:
1105 return ResolveExportedType((implementation & 0xFFFFFF) - 1).ResolveNestedType(typeName).SetMetadataTokenForMissing(token);
1107 throw new NotImplementedException();
1111 internal override Type GetModuleType()
1117 public override string __ImageRuntimeVersion
1119 get { return imageRuntimeVersion; }
1122 public override int MDStreamVersion
1124 get { return metadataStreamVersion; }
1127 public override void __GetDataDirectoryEntry(int index, out int rva, out int length)
1129 peFile.GetDataDirectoryEntry(index, out rva, out length);
1132 public override long __RelativeVirtualAddressToFileOffset(int rva)
1134 return peFile.RvaToFileOffset((uint)rva);
1137 public override bool __GetSectionInfo(int rva, out string name, out int characteristics)
1139 return peFile.GetSectionInfo(rva, out name, out characteristics);
1142 public override int __ReadDataFromRVA(int rva, byte[] data, int offset, int length)
1145 int totalBytesRead = 0;
1148 int read = stream.Read(data, offset, length);
1151 // C++ assemblies can have fields that have an RVA that lies outside of the file
1156 totalBytesRead += read;
1158 return totalBytesRead;
1161 public override void GetPEKind(out PortableExecutableKinds peKind, out ImageFileMachine machine)
1164 if ((cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_ILONLY) != 0)
1166 peKind |= PortableExecutableKinds.ILOnly;
1168 switch (cliHeader.Flags & (CliHeader.COMIMAGE_FLAGS_32BITREQUIRED | CliHeader.COMIMAGE_FLAGS_32BITPREFERRED))
1170 case CliHeader.COMIMAGE_FLAGS_32BITREQUIRED:
1171 peKind |= PortableExecutableKinds.Required32Bit;
1173 case CliHeader.COMIMAGE_FLAGS_32BITREQUIRED | CliHeader.COMIMAGE_FLAGS_32BITPREFERRED:
1174 peKind |= PortableExecutableKinds.Preferred32Bit;
1177 // COMIMAGE_FLAGS_32BITPREFERRED by itself is illegal, so we ignore it
1178 // (not setting any flag is ok)
1181 if (peFile.OptionalHeader.Magic == IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC)
1183 peKind |= PortableExecutableKinds.PE32Plus;
1186 machine = (ImageFileMachine)peFile.FileHeader.Machine;
1189 public override int __Subsystem
1191 get { return peFile.OptionalHeader.Subsystem; }
1194 public override IList<CustomAttributeData> __GetPlaceholderAssemblyCustomAttributes(bool multiple, bool security)
1197 switch ((multiple ? 1 : 0) + (security ? 2 : 0))
1200 typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHere");
1203 typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHereM");
1206 typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHereS");
1210 typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHereSM");
1213 List<CustomAttributeData> list = new List<CustomAttributeData>();
1214 for (int i = 0; i < CustomAttribute.records.Length; i++)
1216 if ((CustomAttribute.records[i].Parent >> 24) == TypeRefTable.Index)
1218 int index = (CustomAttribute.records[i].Parent & 0xFFFFFF) - 1;
1219 if (typeName == GetTypeName(TypeRef.records[index].TypeNameSpace, TypeRef.records[index].TypeName))
1221 list.Add(new CustomAttributeData(this, i));
1228 internal override void Dispose()
1233 internal override void ExportTypes(int fileToken, IKVM.Reflection.Emit.ModuleBuilder manifestModule)
1236 manifestModule.ExportTypes(typeDefs, fileToken);
1239 protected override long GetImageBaseImpl()
1241 return (long)peFile.OptionalHeader.ImageBase;
1244 protected override long GetStackReserveImpl()
1246 return (long)peFile.OptionalHeader.SizeOfStackReserve;
1249 protected override int GetFileAlignmentImpl()
1251 return (int)peFile.OptionalHeader.FileAlignment;
1254 protected override DllCharacteristics GetDllCharacteristicsImpl()
1256 return (DllCharacteristics)peFile.OptionalHeader.DllCharacteristics;
1259 public override int __EntryPointRVA
1261 get { return (cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) != 0 ? (int)cliHeader.EntryPointToken : 0; }
1264 public override int __EntryPointToken
1266 get { return (cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) == 0 ? (int)cliHeader.EntryPointToken : 0; }