2008-10-27 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mcs / class / Mono.Cecil / Mono.Cecil / BaseAssemblyResolver.cs
1 //
2 // BaseAssemblyResolver.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@gmail.com)
6 //
7 // (C) 2005 Jb Evain
8 //
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:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
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.
27 //
28
29 namespace Mono.Cecil {
30
31         using System;
32         using System.Collections;
33         using System.IO;
34         using SR = System.Reflection;
35         using System.Text;
36
37         public abstract class BaseAssemblyResolver : IAssemblyResolver {
38
39                 ArrayList m_directories;
40
41                 public void AddSearchDirectory (string directory)
42                 {
43                         m_directories.Add (directory);
44                 }
45
46                 public void RemoveSearchDirectory (string directory)
47                 {
48                         m_directories.Remove (directory);
49                 }
50
51                 public string [] GetSearchDirectories ()
52                 {
53                         return (string []) m_directories.ToArray (typeof (string));
54                 }
55
56                 public virtual AssemblyDefinition Resolve (string fullName)
57                 {
58                         return Resolve (AssemblyNameReference.Parse (fullName));
59                 }
60
61                 public BaseAssemblyResolver ()
62                 {
63                         m_directories = new ArrayList ();
64                         m_directories.Add (".");
65                         m_directories.Add ("bin");
66                 }
67
68                 public virtual AssemblyDefinition Resolve (AssemblyNameReference name)
69                 {
70                         AssemblyDefinition assembly;
71                         string frameworkdir = Path.GetDirectoryName (typeof (object).Module.FullyQualifiedName);
72
73                         assembly = SearchDirectory (name, m_directories);
74                         if (assembly != null)
75                                 return assembly;
76
77                         if (IsZero (name.Version)) {
78                                 assembly = SearchDirectory (name, new string [] {frameworkdir});
79                                 if (assembly != null)
80                                         return assembly;
81                         }
82
83 #if !CF_1_0 && !CF_2_0
84                         if (name.Name == "mscorlib") {
85                                 assembly = GetCorlib (name);
86                                 if (assembly != null)
87                                         return assembly;
88                         }
89
90                         assembly = GetAssemblyInGac (name);
91                         if (assembly != null)
92                                 return assembly;
93 #endif
94
95                         assembly = SearchDirectory (name, new string [] {frameworkdir});
96                         if (assembly != null)
97                                 return assembly;
98
99                         throw new FileNotFoundException ("Could not resolve: " + name);
100                 }
101
102                 static readonly string [] _extentions = new string [] { ".dll", ".exe" };
103
104                 static AssemblyDefinition SearchDirectory (AssemblyNameReference name, IEnumerable directories)
105                 {
106                         foreach (string dir in directories) {
107                                 foreach (string ext in _extentions) {
108                                         string file = Path.Combine (dir, name.Name + ext);
109                                         if (File.Exists (file))
110                                                 return AssemblyFactory.GetAssembly (file);
111                                 }
112                         }
113
114                         return null;
115                 }
116
117                 static bool IsZero (Version version)
118                 {
119                         return version.Major == 0 && version.Minor == 0 && version.Build == 0 && version.Revision == 0;
120                 }
121
122 #if !CF_1_0 && !CF_2_0
123                 static AssemblyDefinition GetCorlib (AssemblyNameReference reference)
124                 {
125                         SR.AssemblyName corlib = typeof (object).Assembly.GetName ();
126                         if (corlib.Version == reference.Version || IsZero (reference.Version))
127                                 return AssemblyFactory.GetAssembly (typeof (object).Module.FullyQualifiedName);
128
129                         string path = Directory.GetParent (
130                                 Directory.GetParent (
131                                         typeof (object).Module.FullyQualifiedName).FullName
132                                 ).FullName;
133
134                         if (OnMono ()) {
135                                 if (reference.Version.Major == 1)
136                                         path = Path.Combine (path, "1.0");
137                                 else if (reference.Version.Major == 2) {
138                                         if (reference.Version.Minor == 1)
139                                                 path = Path.Combine (path, "2.1");
140                                         else
141                                                 path = Path.Combine (path, "2.0");
142                                 } else
143                                         throw new NotSupportedException ("Version not supported: " + reference.Version);
144                         } else {
145                                 if (reference.Version.ToString () == "1.0.3300.0")
146                                         path = Path.Combine (path, "v1.0.3705");
147                                 else if (reference.Version.ToString () == "1.0.5000.0")
148                                         path = Path.Combine (path, "v1.1.4322");
149                                 else if (reference.Version.ToString () == "2.0.0.0")
150                                         path = Path.Combine (path, "v2.0.50727");
151                                 else
152                                         throw new NotSupportedException ("Version not supported: " + reference.Version);
153                         }
154
155                         if (File.Exists (Path.Combine (path, "mscorlib.dll")))
156                                 return AssemblyFactory.GetAssembly (Path.Combine (path, "mscorlib.dll"));
157
158                         return null;
159                 }
160
161                 public static bool OnMono ()
162                 {
163                         return typeof (object).Assembly.GetType ("System.MonoType", false) != null;
164                 }
165
166                 static AssemblyDefinition GetAssemblyInGac (AssemblyNameReference reference)
167                 {
168                         if (reference.PublicKeyToken == null || reference.PublicKeyToken.Length == 0)
169                                 return null;
170
171                         string currentGac = GetCurrentGacPath ();
172                         if (OnMono ()) {
173                                 string s = GetAssemblyFile (reference, currentGac);
174                                 if (File.Exists (s))
175                                         return AssemblyFactory.GetAssembly (s);
176                         } else {
177                                 string [] gacs = new string [] {"GAC_MSIL", "GAC_32", "GAC"};
178                                 for (int i = 0; i < gacs.Length; i++) {
179                                         string gac = Path.Combine (Directory.GetParent (currentGac).FullName, gacs [i]);
180                                         string asm = GetAssemblyFile (reference, gac);
181                                         if (Directory.Exists (gac) && File.Exists (asm))
182                                                 return AssemblyFactory.GetAssembly (asm);
183                                 }
184                         }
185
186                         return null;
187                 }
188
189                 static string GetAssemblyFile (AssemblyNameReference reference, string gac)
190                 {
191                         StringBuilder sb = new StringBuilder ();
192                         sb.Append (reference.Version);
193                         sb.Append ("__");
194                         for (int i = 0; i < reference.PublicKeyToken.Length; i++)
195                                 sb.Append (reference.PublicKeyToken [i].ToString ("x2"));
196
197                         return Path.Combine (
198                                 Path.Combine (
199                                         Path.Combine (gac, reference.Name), sb.ToString ()),
200                                         string.Concat (reference.Name, ".dll"));
201                 }
202
203                 static string GetCurrentGacPath ()
204                 {
205                         return Directory.GetParent (
206                                 Directory.GetParent (
207                                         Path.GetDirectoryName (
208                                                 typeof (Uri).Module.FullyQualifiedName)
209                                         ).FullName
210                                 ).FullName;
211                 }
212 #endif
213         }
214 }