// Author:
// Jb Evain (jbevain@gmail.com)
//
-// (C) 2005 Jb Evain
+// Copyright (c) 2008 - 2011 Jb Evain
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+using Mono.Collections.Generic;
+
namespace Mono.Cecil {
- using System;
- using System.Collections;
- using System.IO;
- using SR = System.Reflection;
- using System.Text;
+ 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 {
- ArrayList m_directories;
+ 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)
{
- m_directories.Add (directory);
+ directories.Add (directory);
}
public void RemoveSearchDirectory (string directory)
{
- m_directories.Remove (directory);
+ directories.Remove (directory);
}
public string [] GetSearchDirectories ()
{
- return (string []) m_directories.ToArray (typeof (string));
+ 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 (AssemblyNameReference.Parse (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" };
}
- public BaseAssemblyResolver ()
+ AssemblyDefinition GetAssembly (string file, ReaderParameters parameters)
{
- m_directories = new ArrayList ();
- m_directories.Add (".");
- m_directories.Add ("bin");
+ if (parameters.AssemblyResolver == null)
+ parameters.AssemblyResolver = this;
+
+ return ModuleDefinition.ReadModule (file, parameters).Assembly;
}
public virtual AssemblyDefinition Resolve (AssemblyNameReference name)
{
- AssemblyDefinition assembly;
- string frameworkdir = Path.GetDirectoryName (typeof (object).Module.FullyQualifiedName);
+ 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 ();
- assembly = SearchDirectory (name, m_directories);
+ var assembly = SearchDirectory (name, directories, parameters);
if (assembly != null)
return assembly;
+#if !SILVERLIGHT && !CF
+ var framework_dir = Path.GetDirectoryName (typeof (object).Module.FullyQualifiedName);
+
if (IsZero (name.Version)) {
- assembly = SearchDirectory (name, new string [] {frameworkdir});
+ assembly = SearchDirectory (name, new [] { framework_dir }, parameters);
if (assembly != null)
return assembly;
}
-#if !CF_1_0 && !CF_2_0
if (name.Name == "mscorlib") {
- assembly = GetCorlib (name);
+ assembly = GetCorlib (name, parameters);
if (assembly != null)
return assembly;
}
- assembly = GetAssemblyInGac (name);
+ assembly = GetAssemblyInGac (name, parameters);
if (assembly != null)
return assembly;
-#endif
- assembly = SearchDirectory (name, new string [] {frameworkdir});
+ assembly = SearchDirectory (name, new [] { framework_dir }, parameters);
if (assembly != null)
return assembly;
+#endif
- throw new FileNotFoundException ("Could not resolve: " + name);
- }
+ if (ResolveFailure != null) {
+ assembly = ResolveFailure (this, name);
+ if (assembly != null)
+ return assembly;
+ }
- static readonly string [] _extentions = new string [] { ".dll", ".exe" };
+ throw new AssemblyResolutionException (name);
+ }
- static AssemblyDefinition SearchDirectory (AssemblyNameReference name, IEnumerable directories)
+ AssemblyDefinition SearchDirectory (AssemblyNameReference name, IEnumerable<string> directories, ReaderParameters parameters)
{
- foreach (string dir in directories) {
- foreach (string ext in _extentions) {
- string file = Path.Combine (dir, name.Name + ext);
+ 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 AssemblyFactory.GetAssembly (file);
+ return GetAssembly (file, parameters);
}
}
static bool IsZero (Version version)
{
- return version.Major == 0 && version.Minor == 0 && version.Build == 0 && version.Revision == 0;
+ return version == null || (version.Major == 0 && version.Minor == 0 && version.Build == 0 && version.Revision == 0);
}
-#if !CF_1_0 && !CF_2_0
- static AssemblyDefinition GetCorlib (AssemblyNameReference reference)
+#if !SILVERLIGHT && !CF
+ AssemblyDefinition GetCorlib (AssemblyNameReference reference, ReaderParameters parameters)
{
- SR.AssemblyName corlib = typeof (object).Assembly.GetName ();
- if (corlib.Version == reference.Version || IsZero (reference.Version))
- return AssemblyFactory.GetAssembly (typeof (object).Module.FullyQualifiedName);
+ var version = reference.Version;
+ var corlib = typeof (object).Assembly.GetName ();
- string path = Directory.GetParent (
+ 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 (OnMono ()) {
- if (reference.Version.Major == 1)
+ if (on_mono) {
+ if (version.Major == 1)
path = Path.Combine (path, "1.0");
- else if (reference.Version.Major == 2) {
- if (reference.Version.Minor == 1)
+ else if (version.Major == 2) {
+ if (version.MajorRevision == 5)
path = Path.Combine (path, "2.1");
else
path = Path.Combine (path, "2.0");
- } else
- throw new NotSupportedException ("Version not supported: " + reference.Version);
+ } else if (version.Major == 4)
+ path = Path.Combine (path, "4.0");
+ else
+ throw new NotSupportedException ("Version not supported: " + 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")
+ 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");
- else if (reference.Version.ToString () == "4.0.0.0")
- path = Path.Combine (path, "v4.0.20506");
- else
- throw new NotSupportedException ("Version not supported: " + reference.Version);
+ break;
+ case 4:
+ path = Path.Combine (path, "v4.0.30319");
+ break;
+ default:
+ throw new NotSupportedException ("Version not supported: " + version);
+ }
}
- if (File.Exists (Path.Combine (path, "mscorlib.dll")))
- return AssemblyFactory.GetAssembly (Path.Combine (path, "mscorlib.dll"));
+ var file = Path.Combine (path, "mscorlib.dll");
+ if (File.Exists (file))
+ return GetAssembly (file, parameters);
return null;
}
- public static bool OnMono ()
+ 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 typeof (object).Assembly.GetType ("System.MonoType", false) != null;
+ return Path.Combine (
+ Directory.GetParent (
+ Path.GetDirectoryName (typeof (object).Module.FullyQualifiedName)).FullName,
+ "gac");
}
- static AssemblyDefinition GetAssemblyInGac (AssemblyNameReference reference)
+ AssemblyDefinition GetAssemblyInGac (AssemblyNameReference reference, ReaderParameters parameters)
{
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 AssemblyFactory.GetAssembly (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 AssemblyFactory.GetAssembly (asm);
+ 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" };
+ 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 gac)
+ static string GetAssemblyFile (AssemblyNameReference reference, string prefix, string gac)
{
- StringBuilder sb = new StringBuilder ();
- sb.Append (reference.Version);
- sb.Append ("__");
+ var gac_folder = new StringBuilder ()
+ .Append (prefix)
+ .Append (reference.Version)
+ .Append ("__");
+
for (int i = 0; i < reference.PublicKeyToken.Length; i++)
- sb.Append (reference.PublicKeyToken [i].ToString ("x2"));
+ gac_folder.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;
+ Path.Combine (gac, reference.Name), gac_folder.ToString ()),
+ reference.Name + ".dll");
}
#endif
}