2 // BaseAssemblyResolver.cs
5 // Jb Evain (jbevain@gmail.com)
7 // Copyright (c) 2008 - 2010 Jb Evain
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System.Collections.Generic;
34 using Mono.Collections.Generic;
36 namespace Mono.Cecil {
38 public delegate AssemblyDefinition AssemblyResolveEventHandler (object sender, AssemblyNameReference reference);
40 public sealed class AssemblyResolveEventArgs : EventArgs {
42 readonly AssemblyNameReference reference;
44 public AssemblyNameReference AssemblyReference {
45 get { return reference; }
48 public AssemblyResolveEventArgs (AssemblyNameReference reference)
50 this.reference = reference;
54 public abstract class BaseAssemblyResolver : IAssemblyResolver {
56 static readonly bool on_mono = Type.GetType ("Mono.Runtime") != null;
58 readonly Collection<string> directories;
60 #if !SILVERLIGHT && !CF
61 Collection<string> gac_paths;
64 public void AddSearchDirectory (string directory)
66 directories.Add (directory);
69 public void RemoveSearchDirectory (string directory)
71 directories.Remove (directory);
74 public string [] GetSearchDirectories ()
76 var directories = new string [this.directories.size];
77 Array.Copy (this.directories.items, directories, directories.Length);
81 public virtual AssemblyDefinition Resolve (string fullName)
83 return Resolve (fullName, new ReaderParameters ());
86 public virtual AssemblyDefinition Resolve (string fullName, ReaderParameters parameters)
89 throw new ArgumentNullException ("fullName");
91 return Resolve (AssemblyNameReference.Parse (fullName), parameters);
94 public event AssemblyResolveEventHandler ResolveFailure;
96 protected BaseAssemblyResolver ()
98 directories = new Collection<string> (2) { ".", "bin" };
101 AssemblyDefinition GetAssembly (string file, ReaderParameters parameters)
103 if (parameters.AssemblyResolver == null)
104 parameters.AssemblyResolver = this;
106 return ModuleDefinition.ReadModule (file, parameters).Assembly;
109 public virtual AssemblyDefinition Resolve (AssemblyNameReference name)
111 return Resolve (name, new ReaderParameters ());
114 public virtual AssemblyDefinition Resolve (AssemblyNameReference name, ReaderParameters parameters)
117 throw new ArgumentNullException ("name");
118 if (parameters == null)
119 parameters = new ReaderParameters ();
121 var assembly = SearchDirectory (name, directories, parameters);
122 if (assembly != null)
125 #if !SILVERLIGHT && !CF
126 var framework_dir = Path.GetDirectoryName (typeof (object).Module.FullyQualifiedName);
128 if (IsZero (name.Version)) {
129 assembly = SearchDirectory (name, new [] { framework_dir }, parameters);
130 if (assembly != null)
134 if (name.Name == "mscorlib") {
135 assembly = GetCorlib (name, parameters);
136 if (assembly != null)
140 assembly = GetAssemblyInGac (name, parameters);
141 if (assembly != null)
144 assembly = SearchDirectory (name, new [] { framework_dir }, parameters);
145 if (assembly != null)
149 if (ResolveFailure != null) {
150 assembly = ResolveFailure (this, name);
151 if (assembly != null)
155 throw new FileNotFoundException ("Could not resolve: " + name);
158 AssemblyDefinition SearchDirectory (AssemblyNameReference name, IEnumerable<string> directories, ReaderParameters parameters)
160 var extensions = new [] { ".exe", ".dll" };
161 foreach (var directory in directories) {
162 foreach (var extension in extensions) {
163 string file = Path.Combine (directory, name.Name + extension);
164 if (File.Exists (file))
165 return GetAssembly (file, parameters);
172 static bool IsZero (Version version)
174 return version == null || (version.Major == 0 && version.Minor == 0 && version.Build == 0 && version.Revision == 0);
177 #if !SILVERLIGHT && !CF
178 AssemblyDefinition GetCorlib (AssemblyNameReference reference, ReaderParameters parameters)
180 var version = reference.Version;
181 var corlib = typeof (object).Assembly.GetName ();
183 if (corlib.Version == version || IsZero (version))
184 return GetAssembly (typeof (object).Module.FullyQualifiedName, parameters);
186 var path = Directory.GetParent (
187 Directory.GetParent (
188 typeof (object).Module.FullyQualifiedName).FullName
192 if (version.Major == 1)
193 path = Path.Combine (path, "1.0");
194 else if (version.Major == 2) {
195 if (version.MajorRevision == 5)
196 path = Path.Combine (path, "2.1");
198 path = Path.Combine (path, "2.0");
199 } else if (version.Major == 4)
200 path = Path.Combine (path, "4.0");
202 throw new NotSupportedException ("Version not supported: " + version);
204 switch (version.Major) {
206 if (version.MajorRevision == 3300)
207 path = Path.Combine (path, "v1.0.3705");
209 path = Path.Combine (path, "v1.0.5000.0");
212 path = Path.Combine (path, "v2.0.50727");
215 path = Path.Combine (path, "v4.0.30319");
218 throw new NotSupportedException ("Version not supported: " + version);
222 var file = Path.Combine (path, "mscorlib.dll");
223 if (File.Exists (file))
224 return GetAssembly (file, parameters);
229 static Collection<string> GetGacPaths ()
232 return GetDefaultMonoGacPaths ();
234 var paths = new Collection<string> (2);
235 var windir = Environment.GetEnvironmentVariable ("WINDIR");
239 paths.Add (Path.Combine (windir, "assembly"));
240 paths.Add (Path.Combine (windir, Path.Combine ("Microsoft.NET", "assembly")));
244 static Collection<string> GetDefaultMonoGacPaths ()
246 var paths = new Collection<string> (1);
247 var gac = GetCurrentMonoGac ();
251 var gac_paths_env = Environment.GetEnvironmentVariable ("MONO_GAC_PREFIX");
252 if (string.IsNullOrEmpty (gac_paths_env))
255 var prefixes = gac_paths_env.Split (Path.PathSeparator);
256 foreach (var prefix in prefixes) {
257 if (string.IsNullOrEmpty (prefix))
260 var gac_path = Path.Combine (Path.Combine (Path.Combine (prefix, "lib"), "mono"), "gac");
261 if (Directory.Exists (gac_path) && !paths.Contains (gac))
262 paths.Add (gac_path);
268 static string GetCurrentMonoGac ()
270 return Path.Combine (
271 Directory.GetParent (
272 Path.GetDirectoryName (typeof (object).Module.FullyQualifiedName)).FullName,
276 AssemblyDefinition GetAssemblyInGac (AssemblyNameReference reference, ReaderParameters parameters)
278 if (reference.PublicKeyToken == null || reference.PublicKeyToken.Length == 0)
281 if (gac_paths == null)
282 gac_paths = GetGacPaths ();
285 return GetAssemblyInMonoGac (reference, parameters);
287 return GetAssemblyInNetGac (reference, parameters);
290 AssemblyDefinition GetAssemblyInMonoGac (AssemblyNameReference reference, ReaderParameters parameters)
292 for (int i = 0; i < gac_paths.Count; i++) {
293 var gac_path = gac_paths [i];
294 var file = GetAssemblyFile (reference, string.Empty, gac_path);
295 if (File.Exists (file))
296 return GetAssembly (file, parameters);
302 AssemblyDefinition GetAssemblyInNetGac (AssemblyNameReference reference, ReaderParameters parameters)
304 var gacs = new [] { "GAC_MSIL", "GAC_32", "GAC" };
305 var prefixes = new [] { string.Empty, "v4.0_" };
307 for (int i = 0; i < 2; i++) {
308 for (int j = 0; j < gacs.Length; j++) {
309 var gac = Path.Combine (gac_paths [i], gacs [j]);
310 var file = GetAssemblyFile (reference, prefixes [i], gac);
311 if (Directory.Exists (gac) && File.Exists (file))
312 return GetAssembly (file, parameters);
319 static string GetAssemblyFile (AssemblyNameReference reference, string prefix, string gac)
321 var gac_folder = new StringBuilder ();
322 gac_folder.Append (prefix);
323 gac_folder.Append (reference.Version);
324 gac_folder.Append ("__");
325 for (int i = 0; i < reference.PublicKeyToken.Length; i++)
326 gac_folder.Append (reference.PublicKeyToken [i].ToString ("x2"));
328 return Path.Combine (
330 Path.Combine (gac, reference.Name), gac_folder.ToString ()),
331 reference.Name + ".dll");