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 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 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 public override Type ResolveType(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
490 if ((metadataToken >> 24) == TypeSpecTable.Index)
492 return ResolveType(metadataToken, new GenericContext(genericTypeArguments, genericMethodArguments));
496 return ResolveType(metadataToken, null);
500 private TypeName GetTypeName(int typeNamespace, int typeName)
502 return new TypeName(GetString(typeNamespace), GetString(typeName));
505 internal Assembly ResolveAssemblyRef(int index)
507 if (assemblyRefs == null)
509 assemblyRefs = new Assembly[AssemblyRef.RowCount];
511 if (assemblyRefs[index] == null)
513 assemblyRefs[index] = ResolveAssemblyRefImpl(ref AssemblyRef.records[index]);
515 return assemblyRefs[index];
518 private Assembly ResolveAssemblyRefImpl(ref AssemblyRefTable.Record rec)
520 const int PublicKey = 0x0001;
521 string name = String.Format("{0}, Version={1}.{2}.{3}.{4}, Culture={5}, {6}={7}",
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);
533 private string PublicKeyOrTokenToString(int publicKeyOrToken)
535 if (publicKeyOrToken == 0)
539 ByteReader br = GetBlob(publicKeyOrToken);
544 StringBuilder sb = new StringBuilder(br.Length * 2);
545 while (br.Length > 0)
547 sb.AppendFormat("{0:x2}", br.ReadByte());
549 return sb.ToString();
552 public override Guid ModuleVersionId
556 byte[] buf = new byte[16];
557 Buffer.BlockCopy(guidHeap, 16 * (ModuleTable.records[0].Mvid - 1), buf, 0, 16);
558 return new Guid(buf);
562 public override string FullyQualifiedName
564 get { return location ?? "<Unknown>"; }
567 public override string Name
569 get { return location == null ? "<Unknown>" : System.IO.Path.GetFileName(location); }
572 public override Assembly Assembly
574 get { return assembly; }
577 internal override Type FindType(TypeName typeName)
581 if (!types.TryGetValue(typeName, out type))
583 LazyForwardedType fw;
584 if (forwardedTypes.TryGetValue(typeName, out fw))
586 return fw.GetType(this, typeName);
592 internal override Type FindTypeIgnoreCase(TypeName lowerCaseName)
595 foreach (Type type in types.Values)
597 if (new TypeName(type.__Namespace, type.__Name).ToLowerInvariant() == lowerCaseName)
602 foreach (TypeName name in forwardedTypes.Keys)
604 if (name.ToLowerInvariant() == lowerCaseName)
606 return forwardedTypes[name].GetType(this, name);
612 private Exception TokenOutOfRangeException(int metadataToken)
614 return new ArgumentOutOfRangeException("metadataToken", String.Format("Token 0x{0:x8} is not valid in the scope of module {1}.", metadataToken, this.Name));
617 public override MemberInfo ResolveMember(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
619 switch (metadataToken >> 24)
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)
629 return GetMemberRef(index, genericTypeArguments, genericMethodArguments);
630 case MethodDefTable.Index:
631 case MethodSpecTable.Index:
632 return ResolveMethod(metadataToken, genericTypeArguments, genericMethodArguments);
634 throw TokenOutOfRangeException(metadataToken);
638 internal FieldInfo GetFieldAt(TypeDefImpl owner, int index)
642 fields = new FieldInfo[Field.records.Length];
644 if (fields[index] == null)
646 fields[index] = new FieldDefImpl(this, owner ?? FindFieldOwner(index), index);
648 return fields[index];
651 public override FieldInfo ResolveField(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
653 int index = (metadataToken & 0xFFFFFF) - 1;
656 throw TokenOutOfRangeException(metadataToken);
658 else if ((metadataToken >> 24) == FieldTable.Index && index < Field.RowCount)
660 return GetFieldAt(null, index);
662 else if ((metadataToken >> 24) == MemberRefTable.Index && index < MemberRef.RowCount)
664 FieldInfo field = GetMemberRef(index, genericTypeArguments, genericMethodArguments) as FieldInfo;
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");
673 throw TokenOutOfRangeException(metadataToken);
677 private TypeDefImpl FindFieldOwner(int fieldIndex)
679 // TODO use binary search?
680 for (int i = 0; i < TypeDef.records.Length; i++)
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)
690 throw new InvalidOperationException();
693 internal MethodBase GetMethodAt(TypeDefImpl owner, int index)
697 methods = new MethodBase[MethodDef.records.Length];
699 if (methods[index] == null)
701 MethodDefImpl method = new MethodDefImpl(this, owner ?? FindMethodOwner(index), index);
702 methods[index] = method.IsConstructor ? new ConstructorInfoImpl(method) : (MethodBase)method;
704 return methods[index];
707 private sealed class GenericContext : IGenericContext
709 private readonly Type[] genericTypeArguments;
710 private readonly Type[] genericMethodArguments;
712 internal GenericContext(Type[] genericTypeArguments, Type[] genericMethodArguments)
714 this.genericTypeArguments = genericTypeArguments;
715 this.genericMethodArguments = genericMethodArguments;
718 public Type GetGenericTypeArgument(int index)
720 return genericTypeArguments[index];
723 public Type GetGenericMethodArgument(int index)
725 return genericMethodArguments[index];
729 public override MethodBase ResolveMethod(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
731 int index = (metadataToken & 0xFFFFFF) - 1;
734 throw TokenOutOfRangeException(metadataToken);
736 else if ((metadataToken >> 24) == MethodDefTable.Index && index < MethodDef.RowCount)
738 return GetMethodAt(null, index);
740 else if ((metadataToken >> 24) == MemberRefTable.Index && index < MemberRef.RowCount)
742 MethodBase method = GetMemberRef(index, genericTypeArguments, genericMethodArguments) as MethodBase;
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");
749 else if ((metadataToken >> 24) == MethodSpecTable.Index && index < MethodSpec.RowCount)
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)));
757 throw TokenOutOfRangeException(metadataToken);
761 public override Type[] __ResolveOptionalParameterTypes(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments, out CustomModifiers[] customModifiers)
763 int index = (metadataToken & 0xFFFFFF) - 1;
766 throw TokenOutOfRangeException(metadataToken);
768 else if ((metadataToken >> 24) == MemberRefTable.Index && index < MemberRef.RowCount)
770 int sig = MemberRef.records[index].Signature;
771 return Signature.ReadOptionalParameterTypes(this, GetBlob(sig), new GenericContext(genericTypeArguments, genericMethodArguments), out customModifiers);
773 else if ((metadataToken >> 24) == MethodDefTable.Index && index < MethodDef.RowCount)
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;
783 throw TokenOutOfRangeException(metadataToken);
787 public override string ScopeName
789 get { return GetString(ModuleTable.records[0].Name); }
792 private TypeDefImpl FindMethodOwner(int methodIndex)
794 // TODO use binary search?
795 for (int i = 0; i < TypeDef.records.Length; i++)
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)
805 throw new InvalidOperationException();
808 private MemberInfo GetMemberRef(int index, Type[] genericTypeArguments, Type[] genericMethodArguments)
810 if (memberRefs == null)
812 memberRefs = new MemberInfo[MemberRef.records.Length];
814 if (memberRefs[index] == null)
816 int owner = MemberRef.records[index].Class;
817 int sig = MemberRef.records[index].Signature;
818 string name = GetString(MemberRef.records[index].Name);
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));
826 case TypeDefTable.Index:
827 case TypeRefTable.Index:
828 memberRefs[index] = ResolveTypeMemberRef(ResolveType(owner), name, ByteReader.FromBlob(blobHeap, sig));
830 case TypeSpecTable.Index:
832 Type type = ResolveType(owner, genericTypeArguments, genericMethodArguments);
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);
839 else if (type.IsGenericTypeInstance)
841 MemberInfo member = ResolveTypeMemberRef(type.GetGenericTypeDefinition(), name, ByteReader.FromBlob(blobHeap, sig));
842 MethodBase mb = member as MethodBase;
845 member = mb.BindTypeParameters(type);
847 FieldInfo fi = member as FieldInfo;
850 member = fi.BindTypeParameters(type);
856 return ResolveTypeMemberRef(type, name, ByteReader.FromBlob(blobHeap, sig));
860 throw new BadImageFormatException();
863 return memberRefs[index];
866 private Type ResolveModuleType(int token)
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())
873 throw new BadImageFormatException();
875 return module.GetModuleType();
878 private MemberInfo ResolveTypeMemberRef(Type type, string name, ByteReader sig)
880 if (sig.PeekByte() == Signature.FIELD)
883 FieldSignature fieldSig = FieldSignature.ReadSig(this, sig, type);
884 FieldInfo field = type.FindField(name, fieldSig);
885 if (field == null && universe.MissingMemberResolution)
887 return universe.GetMissingFieldOrThrow(type, name, fieldSig);
889 while (field == null && (type = type.BaseType) != null)
891 field = type.FindField(name, fieldSig);
897 throw new MissingFieldException(org.ToString(), name);
902 MethodSignature methodSig = MethodSignature.ReadSig(this, sig, type);
903 MethodBase method = type.FindMethod(name, methodSig);
904 if (method == null && universe.MissingMemberResolution)
906 return universe.GetMissingMethodOrThrow(type, name, methodSig);
908 while (method == null && (type = type.BaseType) != null)
910 method = type.FindMethod(name, methodSig);
916 throw new MissingMethodException(org.ToString(), name);
920 internal ByteReader GetStandAloneSig(int index)
922 return ByteReader.FromBlob(blobHeap, StandAloneSig.records[index]);
925 public override byte[] ResolveSignature(int metadataToken)
927 int index = (metadataToken & 0xFFFFFF) - 1;
928 if ((metadataToken >> 24) == StandAloneSigTable.Index && index >= 0 && index < StandAloneSig.RowCount)
930 ByteReader br = GetStandAloneSig(index);
931 return br.ReadBytes(br.Length);
935 throw TokenOutOfRangeException(metadataToken);
939 public override __StandAloneMethodSig __ResolveStandAloneMethodSig(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
941 int index = (metadataToken & 0xFFFFFF) - 1;
942 if ((metadataToken >> 24) == StandAloneSigTable.Index && index >= 0 && index < StandAloneSig.RowCount)
944 return MethodSignature.ReadStandAloneMethodSig(this, GetStandAloneSig(index), new GenericContext(genericTypeArguments, genericMethodArguments));
948 throw TokenOutOfRangeException(metadataToken);
952 internal MethodInfo GetEntryPoint()
954 if (cliHeader.EntryPointToken != 0 && (cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) == 0)
956 return (MethodInfo)ResolveMethod((int)cliHeader.EntryPointToken);
961 internal string[] GetManifestResourceNames()
963 string[] names = new string[ManifestResource.records.Length];
964 for (int i = 0; i < ManifestResource.records.Length; i++)
966 names[i] = GetString(ManifestResource.records[i].Name);
971 internal ManifestResourceInfo GetManifestResourceInfo(string resourceName)
973 for (int i = 0; i < ManifestResource.records.Length; i++)
975 if (resourceName == GetString(ManifestResource.records[i].Name))
977 ManifestResourceInfo info = new ManifestResourceInfo(this, i);
978 Assembly asm = info.ReferencedAssembly;
979 if (asm != null && !asm.__IsMissing && asm.GetManifestResourceInfo(resourceName) == null)
989 internal Stream GetManifestResourceStream(string resourceName)
991 for (int i = 0; i < ManifestResource.records.Length; i++)
993 if (resourceName == GetString(ManifestResource.records[i].Name))
995 if (ManifestResource.records[i].Implementation != 0x26000000)
997 ManifestResourceInfo info = new ManifestResourceInfo(this, i);
998 switch (ManifestResource.records[i].Implementation >> 24)
1000 case FileTable.Index:
1001 string fileName = Path.Combine(Path.GetDirectoryName(location), info.FileName);
1002 if (System.IO.File.Exists(fileName))
1004 // note that, like System.Reflection, we return null for zero length files and
1005 // ManifestResource.Offset is ignored
1006 FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete);
1015 case AssemblyRefTable.Index:
1016 Assembly asm = info.ReferencedAssembly;
1017 if (asm.__IsMissing)
1021 return asm.GetManifestResourceStream(resourceName);
1023 throw new BadImageFormatException();
1026 SeekRVA((int)cliHeader.Resources.VirtualAddress + ManifestResource.records[i].Offset);
1027 BinaryReader br = new BinaryReader(stream);
1028 int length = br.ReadInt32();
1029 return new MemoryStream(br.ReadBytes(length));
1035 public override AssemblyName[] __GetReferencedAssemblies()
1037 List<AssemblyName> list = new List<AssemblyName>();
1038 for (int i = 0; i < AssemblyRef.records.Length; i++)
1040 AssemblyName name = new AssemblyName();
1041 name.Name = GetString(AssemblyRef.records[i].Name);
1042 name.Version = new Version(
1043 AssemblyRef.records[i].MajorVersion,
1044 AssemblyRef.records[i].MinorVersion,
1045 AssemblyRef.records[i].BuildNumber,
1046 AssemblyRef.records[i].RevisionNumber);
1047 if (AssemblyRef.records[i].PublicKeyOrToken != 0)
1049 byte[] keyOrToken = GetBlobCopy(AssemblyRef.records[i].PublicKeyOrToken);
1050 const int PublicKey = 0x0001;
1051 if ((AssemblyRef.records[i].Flags & PublicKey) != 0)
1053 name.SetPublicKey(keyOrToken);
1057 name.SetPublicKeyToken(keyOrToken);
1062 name.SetPublicKeyToken(Empty<byte>.Array);
1064 if (AssemblyRef.records[i].Culture != 0)
1066 name.Culture = GetString(AssemblyRef.records[i].Culture);
1072 if (AssemblyRef.records[i].HashValue != 0)
1074 name.hash = GetBlobCopy(AssemblyRef.records[i].HashValue);
1076 name.Flags = (AssemblyNameFlags)AssemblyRef.records[i].Flags;
1079 return list.ToArray();
1082 public override void __ResolveReferencedAssemblies(Assembly[] assemblies)
1084 if (assemblyRefs == null)
1086 assemblyRefs = new Assembly[AssemblyRef.RowCount];
1088 for (int i = 0; i < assemblies.Length; i++)
1090 if (assemblyRefs[i] == null)
1092 assemblyRefs[i] = assemblies[i];
1097 public override string[] __GetReferencedModules()
1099 string[] arr = new string[this.ModuleRef.RowCount];
1100 for (int i = 0; i < arr.Length; i++)
1102 arr[i] = GetString(this.ModuleRef.records[i]);
1107 public override Type[] __GetReferencedTypes()
1109 Type[] arr = new Type[this.TypeRef.RowCount];
1110 for (int i = 0; i < arr.Length; i++)
1112 arr[i] = ResolveType((TypeRefTable.Index << 24) + i + 1);
1117 public override Type[] __GetExportedTypes()
1119 Type[] arr = new Type[this.ExportedType.RowCount];
1120 for (int i = 0; i < arr.Length; i++)
1122 arr[i] = ResolveExportedType(i);
1127 private Type ResolveExportedType(int index)
1129 TypeName typeName = GetTypeName(ExportedType.records[index].TypeNamespace, ExportedType.records[index].TypeName);
1130 int implementation = ExportedType.records[index].Implementation;
1131 int token = ExportedType.records[index].TypeDefId;
1132 switch (implementation >> 24)
1134 case AssemblyRefTable.Index:
1135 return ResolveAssemblyRef((implementation & 0xFFFFFF) - 1).ResolveType(typeName).SetMetadataTokenForMissing(token);
1136 case ExportedTypeTable.Index:
1137 return ResolveExportedType((implementation & 0xFFFFFF) - 1).ResolveNestedType(typeName).SetMetadataTokenForMissing(token);
1139 throw new NotImplementedException();
1143 internal override Type GetModuleType()
1149 public override string __ImageRuntimeVersion
1151 get { return imageRuntimeVersion; }
1154 public override int MDStreamVersion
1156 get { return metadataStreamVersion; }
1159 public override void __GetDataDirectoryEntry(int index, out int rva, out int length)
1161 peFile.GetDataDirectoryEntry(index, out rva, out length);
1164 public override long __RelativeVirtualAddressToFileOffset(int rva)
1166 return peFile.RvaToFileOffset((uint)rva);
1169 public override bool __GetSectionInfo(int rva, out string name, out int characteristics)
1171 return peFile.GetSectionInfo(rva, out name, out characteristics);
1174 public override int __ReadDataFromRVA(int rva, byte[] data, int offset, int length)
1177 int totalBytesRead = 0;
1180 int read = stream.Read(data, offset, length);
1183 // C++ assemblies can have fields that have an RVA that lies outside of the file
1188 totalBytesRead += read;
1190 return totalBytesRead;
1193 public override void GetPEKind(out PortableExecutableKinds peKind, out ImageFileMachine machine)
1196 if ((cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_ILONLY) != 0)
1198 peKind |= PortableExecutableKinds.ILOnly;
1200 switch (cliHeader.Flags & (CliHeader.COMIMAGE_FLAGS_32BITREQUIRED | CliHeader.COMIMAGE_FLAGS_32BITPREFERRED))
1202 case CliHeader.COMIMAGE_FLAGS_32BITREQUIRED:
1203 peKind |= PortableExecutableKinds.Required32Bit;
1205 case CliHeader.COMIMAGE_FLAGS_32BITREQUIRED | CliHeader.COMIMAGE_FLAGS_32BITPREFERRED:
1206 peKind |= PortableExecutableKinds.Preferred32Bit;
1209 // COMIMAGE_FLAGS_32BITPREFERRED by itself is illegal, so we ignore it
1210 // (not setting any flag is ok)
1213 if (peFile.OptionalHeader.Magic == IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC)
1215 peKind |= PortableExecutableKinds.PE32Plus;
1218 machine = (ImageFileMachine)peFile.FileHeader.Machine;
1221 public override int __Subsystem
1223 get { return peFile.OptionalHeader.Subsystem; }
1226 public override IList<CustomAttributeData> __GetPlaceholderAssemblyCustomAttributes(bool multiple, bool security)
1229 switch ((multiple ? 1 : 0) + (security ? 2 : 0))
1232 typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHere");
1235 typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHereM");
1238 typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHereS");
1242 typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHereSM");
1245 List<CustomAttributeData> list = new List<CustomAttributeData>();
1246 for (int i = 0; i < CustomAttribute.records.Length; i++)
1248 if ((CustomAttribute.records[i].Parent >> 24) == TypeRefTable.Index)
1250 int index = (CustomAttribute.records[i].Parent & 0xFFFFFF) - 1;
1251 if (typeName == GetTypeName(TypeRef.records[index].TypeNameSpace, TypeRef.records[index].TypeName))
1253 list.Add(new CustomAttributeData(this, i));
1260 internal override void Dispose()
1265 internal override void ExportTypes(int fileToken, IKVM.Reflection.Emit.ModuleBuilder manifestModule)
1268 manifestModule.ExportTypes(typeDefs, fileToken);
1271 protected override long GetImageBaseImpl()
1273 return (long)peFile.OptionalHeader.ImageBase;
1276 protected override long GetStackReserveImpl()
1278 return (long)peFile.OptionalHeader.SizeOfStackReserve;
1281 protected override int GetFileAlignmentImpl()
1283 return (int)peFile.OptionalHeader.FileAlignment;
1286 protected override DllCharacteristics GetDllCharacteristicsImpl()
1288 return (DllCharacteristics)peFile.OptionalHeader.DllCharacteristics;
1291 public override int __EntryPointRVA
1293 get { return (cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) != 0 ? (int)cliHeader.EntryPointToken : 0; }
1296 public override int __EntryPointToken
1298 get { return (cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) == 0 ? (int)cliHeader.EntryPointToken : 0; }