/Mono.Cecil/BaseAssemblyResolver.cs
C# | 352 lines | 274 code | 68 blank | 10 comment | 82 complexity | 6c6bf2b763f58ad0c1468bf18efcab64 MD5 | raw file
- //
- // Author:
- // Jb Evain (jbevain@gmail.com)
- //
- // Copyright (c) 2008 - 2015 Jb Evain
- // Copyright (c) 2008 - 2011 Novell, Inc.
- //
- // Licensed under the MIT/X11 license.
- //
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Text;
- using Mono.Collections.Generic;
- namespace Mono.Cecil {
- public delegate AssemblyDefinition AssemblyResolveEventHandler (object sender, AssemblyNameReference reference);
- public sealed class AssemblyResolveEventArgs : EventArgs {
- readonly AssemblyNameReference reference;
- public AssemblyNameReference AssemblyReference {
- get { return reference; }
- }
- public AssemblyResolveEventArgs (AssemblyNameReference reference)
- {
- this.reference = reference;
- }
- }
- #if !SILVERLIGHT && !CF
- [Serializable]
- #endif
- public class AssemblyResolutionException : FileNotFoundException {
- readonly AssemblyNameReference reference;
- public AssemblyNameReference AssemblyReference {
- get { return reference; }
- }
- public AssemblyResolutionException (AssemblyNameReference reference)
- : base (string.Format ("Failed to resolve assembly: '{0}'", reference))
- {
- this.reference = reference;
- }
- #if !SILVERLIGHT && !CF
- protected AssemblyResolutionException (
- System.Runtime.Serialization.SerializationInfo info,
- System.Runtime.Serialization.StreamingContext context)
- : base (info, context)
- {
- }
- #endif
- }
- public abstract class BaseAssemblyResolver : IAssemblyResolver {
- static readonly bool on_mono = Type.GetType ("Mono.Runtime") != null;
- readonly Collection<string> directories;
- #if !SILVERLIGHT && !CF
- Collection<string> gac_paths;
- #endif
- public void AddSearchDirectory (string directory)
- {
- directories.Add (directory);
- }
- public void RemoveSearchDirectory (string directory)
- {
- directories.Remove (directory);
- }
- public string [] GetSearchDirectories ()
- {
- var directories = new string [this.directories.size];
- Array.Copy (this.directories.items, directories, directories.Length);
- return directories;
- }
- public virtual AssemblyDefinition Resolve (string fullName)
- {
- return Resolve (fullName, new ReaderParameters ());
- }
- public virtual AssemblyDefinition Resolve (string fullName, ReaderParameters parameters)
- {
- if (fullName == null)
- throw new ArgumentNullException ("fullName");
- return Resolve (AssemblyNameReference.Parse (fullName), parameters);
- }
- public event AssemblyResolveEventHandler ResolveFailure;
- protected BaseAssemblyResolver ()
- {
- directories = new Collection<string> (2) { ".", "bin" };
- }
- AssemblyDefinition GetAssembly (string file, ReaderParameters parameters)
- {
- if (parameters.AssemblyResolver == null)
- parameters.AssemblyResolver = this;
- return ModuleDefinition.ReadModule (file, parameters).Assembly;
- }
- public virtual AssemblyDefinition Resolve (AssemblyNameReference name)
- {
- return Resolve (name, new ReaderParameters ());
- }
- public virtual AssemblyDefinition Resolve (AssemblyNameReference name, ReaderParameters parameters)
- {
- if (name == null)
- throw new ArgumentNullException ("name");
- if (parameters == null)
- parameters = new ReaderParameters ();
- var assembly = SearchDirectory (name, directories, parameters);
- if (assembly != null)
- return assembly;
- #if !SILVERLIGHT && !CF
- if (name.IsRetargetable) {
- // if the reference is retargetable, zero it
- name = new AssemblyNameReference (name.Name, Mixin.ZeroVersion) {
- PublicKeyToken = Empty<byte>.Array,
- };
- }
- var framework_dir = Path.GetDirectoryName (typeof (object).Module.FullyQualifiedName);
- if (IsZero (name.Version)) {
- assembly = SearchDirectory (name, new [] { framework_dir }, parameters);
- if (assembly != null)
- return assembly;
- }
- if (name.Name == "mscorlib") {
- assembly = GetCorlib (name, parameters);
- if (assembly != null)
- return assembly;
- }
- assembly = GetAssemblyInGac (name, parameters);
- if (assembly != null)
- return assembly;
- assembly = SearchDirectory (name, new [] { framework_dir }, parameters);
- if (assembly != null)
- return assembly;
- #endif
- if (ResolveFailure != null) {
- assembly = ResolveFailure (this, name);
- if (assembly != null)
- return assembly;
- }
- throw new AssemblyResolutionException (name);
- }
- AssemblyDefinition SearchDirectory (AssemblyNameReference name, IEnumerable<string> directories, ReaderParameters parameters)
- {
- var extensions = new [] { ".exe", ".dll" };
- foreach (var directory in directories) {
- foreach (var extension in extensions) {
- string file = Path.Combine (directory, name.Name + extension);
- if (File.Exists (file))
- return GetAssembly (file, parameters);
- }
- }
- return null;
- }
- static bool IsZero (Version version)
- {
- return version.Major == 0 && version.Minor == 0 && version.Build == 0 && version.Revision == 0;
- }
- #if !SILVERLIGHT && !CF
- AssemblyDefinition GetCorlib (AssemblyNameReference reference, ReaderParameters parameters)
- {
- var version = reference.Version;
- var corlib = typeof (object).Assembly.GetName ();
- if (corlib.Version == version || IsZero (version))
- return GetAssembly (typeof (object).Module.FullyQualifiedName, parameters);
- var path = Directory.GetParent (
- Directory.GetParent (
- typeof (object).Module.FullyQualifiedName).FullName
- ).FullName;
- if (on_mono) {
- if (version.Major == 1)
- path = Path.Combine (path, "1.0");
- else if (version.Major == 2) {
- if (version.MajorRevision == 5)
- path = Path.Combine (path, "2.1");
- else
- path = Path.Combine (path, "2.0");
- } else if (version.Major == 4)
- path = Path.Combine (path, "4.0");
- else
- throw new NotSupportedException ("Version not supported: " + version);
- } else {
- switch (version.Major) {
- case 1:
- if (version.MajorRevision == 3300)
- path = Path.Combine (path, "v1.0.3705");
- else
- path = Path.Combine (path, "v1.0.5000.0");
- break;
- case 2:
- path = Path.Combine (path, "v2.0.50727");
- break;
- case 4:
- path = Path.Combine (path, "v4.0.30319");
- break;
- default:
- throw new NotSupportedException ("Version not supported: " + version);
- }
- }
- var file = Path.Combine (path, "mscorlib.dll");
- if (File.Exists (file))
- return GetAssembly (file, parameters);
- return null;
- }
- static Collection<string> GetGacPaths ()
- {
- if (on_mono)
- return GetDefaultMonoGacPaths ();
- var paths = new Collection<string> (2);
- var windir = Environment.GetEnvironmentVariable ("WINDIR");
- if (windir == null)
- return paths;
- paths.Add (Path.Combine (windir, "assembly"));
- paths.Add (Path.Combine (windir, Path.Combine ("Microsoft.NET", "assembly")));
- return paths;
- }
- static Collection<string> GetDefaultMonoGacPaths ()
- {
- var paths = new Collection<string> (1);
- var gac = GetCurrentMonoGac ();
- if (gac != null)
- paths.Add (gac);
- var gac_paths_env = Environment.GetEnvironmentVariable ("MONO_GAC_PREFIX");
- if (string.IsNullOrEmpty (gac_paths_env))
- return paths;
- var prefixes = gac_paths_env.Split (Path.PathSeparator);
- foreach (var prefix in prefixes) {
- if (string.IsNullOrEmpty (prefix))
- continue;
- var gac_path = Path.Combine (Path.Combine (Path.Combine (prefix, "lib"), "mono"), "gac");
- if (Directory.Exists (gac_path) && !paths.Contains (gac))
- paths.Add (gac_path);
- }
- return paths;
- }
- static string GetCurrentMonoGac ()
- {
- return Path.Combine (
- Directory.GetParent (
- Path.GetDirectoryName (typeof (object).Module.FullyQualifiedName)).FullName,
- "gac");
- }
- AssemblyDefinition GetAssemblyInGac (AssemblyNameReference reference, ReaderParameters parameters)
- {
- if (reference.PublicKeyToken == null || reference.PublicKeyToken.Length == 0)
- return null;
- if (gac_paths == null)
- gac_paths = GetGacPaths ();
- if (on_mono)
- return GetAssemblyInMonoGac (reference, parameters);
- return GetAssemblyInNetGac (reference, parameters);
- }
- AssemblyDefinition GetAssemblyInMonoGac (AssemblyNameReference reference, ReaderParameters parameters)
- {
- for (int i = 0; i < gac_paths.Count; i++) {
- var gac_path = gac_paths [i];
- var file = GetAssemblyFile (reference, string.Empty, gac_path);
- if (File.Exists (file))
- return GetAssembly (file, parameters);
- }
- return null;
- }
- AssemblyDefinition GetAssemblyInNetGac (AssemblyNameReference reference, ReaderParameters parameters)
- {
- var gacs = new [] { "GAC_MSIL", "GAC_32", "GAC_64", "GAC" };
- var prefixes = new [] { string.Empty, "v4.0_" };
- for (int i = 0; i < 2; i++) {
- for (int j = 0; j < gacs.Length; j++) {
- var gac = Path.Combine (gac_paths [i], gacs [j]);
- var file = GetAssemblyFile (reference, prefixes [i], gac);
- if (Directory.Exists (gac) && File.Exists (file))
- return GetAssembly (file, parameters);
- }
- }
- return null;
- }
- static string GetAssemblyFile (AssemblyNameReference reference, string prefix, string gac)
- {
- var gac_folder = new StringBuilder ()
- .Append (prefix)
- .Append (reference.Version)
- .Append ("__");
- for (int i = 0; i < reference.PublicKeyToken.Length; i++)
- gac_folder.Append (reference.PublicKeyToken [i].ToString ("x2"));
- return Path.Combine (
- Path.Combine (
- Path.Combine (gac, reference.Name), gac_folder.ToString ()),
- reference.Name + ".dll");
- }
- #endif
- }
- }