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");