/* Copyright (C) 2011-2012 de4dot@gmail.com This file is part of de4dot. de4dot is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. de4dot is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with de4dot. If not, see . */ using System; using System.Collections.Generic; using System.Reflection; using dot10.DotNet; using de4dot.blocks; namespace AssemblyData.methodsrewriter { static class Resolver { static Dictionary assemblyResolvers = new Dictionary(StringComparer.Ordinal); static Dictionary modules = new Dictionary(); public static MModule loadAssembly(Module module) { MModule info; if (modules.TryGetValue(module, out info)) return info; info = new MModule(module, ModuleDefMD.Load(module.FullyQualifiedName)); modules[module] = info; return info; } static MModule getModule(ModuleDef moduleDef) { foreach (var mm in modules.Values) { if (mm.moduleDef == moduleDef) return mm; } return null; } static MModule getModule(AssemblyRef asmRef) { foreach (var mm in modules.Values) { var asm = mm.moduleDef.Assembly; if (asm != null && asm.FullName == asmRef.FullName) return mm; } return null; } public static MModule getModule(IScope scope) { if (scope.ScopeType == ScopeType.ModuleDef) return getModule((ModuleDef)scope); else if (scope.ScopeType == ScopeType.AssemblyRef) return getModule((AssemblyRef)scope); return null; } public static MType getType(ITypeDefOrRef typeRef) { if (typeRef == null) return null; var module = getModule(typeRef.Scope); if (module != null) return module.getType(typeRef); return null; } public static MMethod getMethod(IMethod methodReference) { if (methodReference == null) return null; var module = getModule(methodReference.DeclaringType.Scope); if (module != null) return module.getMethod(methodReference); return null; } public static MField getField(IField fieldReference) { if (fieldReference == null) return null; var module = getModule(fieldReference.DeclaringType.Scope); if (module != null) return module.getField(fieldReference); return null; } public static object getRtObject(ITokenOperand memberRef) { if (memberRef == null) return null; else if (memberRef is ITypeDefOrRef) return getRtType((ITypeDefOrRef)memberRef); else if (memberRef is IField) return getRtField((IField)memberRef); else if (memberRef is IMethod) return getRtMethod((IMethod)memberRef); throw new ApplicationException(string.Format("Unknown MemberReference: {0}", memberRef)); } public static Type getRtType(ITypeDefOrRef typeRef) { var mtype = getType(typeRef); if (mtype != null) return mtype.type; return Resolver.resolve(typeRef); } public static FieldInfo getRtField(IField fieldRef) { var mfield = getField(fieldRef); if (mfield != null) return mfield.fieldInfo; return Resolver.resolve(fieldRef); } public static MethodBase getRtMethod(IMethod methodRef) { var mmethod = getMethod(methodRef); if (mmethod != null) return mmethod.methodBase; return Resolver.resolve(methodRef); } static AssemblyResolver getAssemblyResolver(ITypeDefOrRef type) { var asmName = type.DefinitionAssembly.FullName; AssemblyResolver resolver; if (!assemblyResolvers.TryGetValue(asmName, out resolver)) assemblyResolvers[asmName] = resolver = new AssemblyResolver(asmName); return resolver; } static Type resolve(IType typeRef) { if (typeRef == null) return null; var elemType = typeRef.GetElementType(); var resolver = getAssemblyResolver(elemType); var resolvedType = resolver.resolve(elemType); if (resolvedType != null) return fixType(typeRef, resolvedType); throw new ApplicationException(string.Format("Could not resolve type {0} ({1:X8}) in assembly {2}", typeRef, typeRef.MDToken.Raw, resolver)); } static FieldInfo resolve(IField fieldRef) { if (fieldRef == null) return null; var resolver = getAssemblyResolver(fieldRef.DeclaringType); var fieldInfo = resolver.resolve(fieldRef); if (fieldInfo != null) return fieldInfo; throw new ApplicationException(string.Format("Could not resolve field {0} ({1:X8}) in assembly {2}", fieldRef, fieldRef.MDToken.Raw, resolver)); } static MethodBase resolve(IMethod methodRef) { if (methodRef == null) return null; var resolver = getAssemblyResolver(methodRef.DeclaringType); var methodBase = resolver.resolve(methodRef); if (methodBase != null) return methodBase; throw new ApplicationException(string.Format("Could not resolve method {0} ({1:X8}) in assembly {2}", methodRef, methodRef.MDToken.Raw, resolver)); } static Type fixType(ITypeDefOrRef typeRef, Type type) { var ts = typeRef as TypeSpec; if (ts == null) return type; var sig = ts.TypeSig; while (sig != null) { switch (sig.ElementType) { case ElementType.SZArray: type = type.MakeArrayType(); break; case ElementType.Array: type = type.MakeArrayType((int)((ArraySig)sig).Rank); break; case ElementType.ByRef: type = type.MakeByRefType(); break; case ElementType.Ptr: type = type.MakePointerType(); break; case ElementType.GenericInst: var git = (GenericInstSig)sig; var args = new Type[git.GenericArguments.Count]; bool isGenericTypeDef = true; for (int i = 0; i < args.Length; i++) { var arg = git.GenericArguments[i]; if (!(arg is GenericSig)) isGenericTypeDef = false; args[i] = Resolver.resolve(arg); } if (!isGenericTypeDef) type = type.MakeGenericType(args); break; default: break; } sig = sig.Next; } return type; } } }