// // BaseAssemblyResolver.cs // // Author: // Jb Evain (jbevain@gmail.com) // // (C) 2007 Novell, Inc. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // // This code is a modified version of the assembly resolver implemented in Cecil. // Keep in synch as much as possible. using System; using System.Collections; using System.Collections.Specialized; using System.IO; using System.Text; using Mono.Cecil; namespace Stetic { internal class AssemblyResolver : BaseAssemblyResolver { Hashtable _assemblies; ApplicationBackend app; public IDictionary AssemblyCache { get { return _assemblies; } } public AssemblyResolver (ApplicationBackend app) { this.app = app; _assemblies = new Hashtable (); } public StringCollection Directories = new StringCollection (); public override AssemblyDefinition Resolve (AssemblyNameReference name) { return Resolve (name, (string)null); } public AssemblyDefinition Resolve (AssemblyNameReference name, string basePath) { AssemblyDefinition asm = (AssemblyDefinition) _assemblies [name.FullName]; if (asm == null) { if (app != null) { string ares = app.ResolveAssembly (name.Name); if (ares != null) { asm = AssemblyDefinition.ReadAssembly (ares, new ReaderParameters { AssemblyResolver = this }); _assemblies [name.FullName] = asm; return asm; } } string file = Resolve (name.FullName, basePath); if (file != null) asm = AssemblyDefinition.ReadAssembly (file, new ReaderParameters { AssemblyResolver = this }); else asm = base.Resolve (name); _assemblies [name.FullName] = asm; } return asm; } public void ClearCache () { _assemblies.Clear (); } public TypeDefinition Resolve (TypeReference type) { if (type is TypeDefinition) return (TypeDefinition) type; AssemblyNameReference reference = type.Scope as AssemblyNameReference; if (reference != null) { AssemblyDefinition assembly = Resolve (reference); return assembly.MainModule.GetType (type.FullName); } ModuleDefinition module = type.Scope as ModuleDefinition; if (module != null) return module.GetType (type.FullName); throw new NotImplementedException (); } public string Resolve (string assemblyName, string basePath) { if (Path.IsPathRooted (assemblyName) && (assemblyName.EndsWith (".dll") || assemblyName.EndsWith (".exe"))) return Path.GetFullPath (assemblyName); if (app != null) { string ares = app.ResolveAssembly (assemblyName); if (ares != null) return Path.GetFullPath (ares); } StringCollection col = new StringCollection (); col.Add (basePath); foreach (string s in Directories) col.Add (s); try { return Resolve (AssemblyNameReference.Parse (assemblyName), col); } catch { } return null; } public string Resolve (AssemblyNameReference name, StringCollection basePaths) { string [] exts = new string [] { ".dll", ".exe" }; if (basePaths != null) { foreach (string dir in basePaths) { foreach (string ext in exts) { string file = Path.Combine (dir, name.Name + ext); if (File.Exists (file)) return file; } } } if (name.Name == "mscorlib") return GetCorlib (name); string asm = GetAssemblyInGac (name); if (asm != null) return Path.GetFullPath (asm); throw new FileNotFoundException ("Could not resolve: " + name); } string GetCorlib (AssemblyNameReference reference) { if (typeof (object).Assembly.GetName ().Version == reference.Version) return typeof (object).Assembly.Location; string path = Directory.GetParent ( Directory.GetParent ( typeof (object).Module.FullyQualifiedName).FullName ).FullName; if (OnMono ()) { if (reference.Version.Major == 1) path = Path.Combine (path, "1.0"); else if (reference.Version.Major == 2) path = Path.Combine (path, "2.0"); else throw new NotSupportedException ("Version not supported: " + reference.Version); } else { if (reference.Version.ToString () == "1.0.3300.0") path = Path.Combine (path, "v1.0.3705"); else if (reference.Version.ToString () == "1.0.5000.0") path = Path.Combine (path, "v1.1.4322"); else if (reference.Version.ToString () == "2.0.0.0") path = Path.Combine (path, "v2.0.50727"); else throw new NotSupportedException ("Version not supported: " + reference.Version); } return Path.GetFullPath (Path.Combine (path, "mscorlib.dll")); } static string GetAssemblyInGac (AssemblyNameReference reference) { if (reference.PublicKeyToken == null || reference.PublicKeyToken.Length == 0) return null; string currentGac = GetCurrentGacPath (); if (OnMono ()) { string s = GetAssemblyFile (reference, currentGac); if (File.Exists (s)) return s; } else { string [] gacs = new string [] {"GAC_MSIL", "GAC_32", "GAC"}; for (int i = 0; i < gacs.Length; i++) { string gac = Path.Combine (Directory.GetParent (currentGac).FullName, gacs [i]); string asm = GetAssemblyFile (reference, gac); if (Directory.Exists (gac) && File.Exists (asm)) return asm; } } return null; } static string GetAssemblyFile (AssemblyNameReference reference, string gac) { StringBuilder sb = new StringBuilder (); sb.Append (reference.Version); sb.Append ("__"); for (int i = 0; i < reference.PublicKeyToken.Length; i++) sb.Append (reference.PublicKeyToken [i].ToString ("x2")); return Path.Combine ( Path.Combine ( Path.Combine (gac, reference.Name), sb.ToString ()), string.Concat (reference.Name, ".dll")); } static string GetCurrentGacPath () { return Directory.GetParent ( Directory.GetParent ( Path.GetDirectoryName ( typeof (Uri).Module.FullyQualifiedName) ).FullName ).FullName; } static bool OnMono () { return Type.GetType ("Mono.Runtime") != null; } } }