f661075f73e362d50a25d566da1cd04ececee98a
[mono.git] / mcs / tools / cil-strip / 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         internal abstract class BaseAssemblyResolver : IAssemblyResolver {
38
39                 ArrayList m_directories;
40                 string[] m_monoGacPaths;
41
42                 public void AddSearchDirectory (string directory)
43                 {
44                         m_directories.Add (directory);
45                 }
46
47                 public void RemoveSearchDirectory (string directory)
48                 {
49                         m_directories.Remove (directory);
50                 }
51
52                 public string [] GetSearchDirectories ()
53                 {
54                         return (string []) m_directories.ToArray (typeof (string));
55                 }
56
57                 public virtual AssemblyDefinition Resolve (string fullName)
58                 {
59                         return Resolve (AssemblyNameReference.Parse (fullName));
60                 }
61
62                 public BaseAssemblyResolver ()
63                 {
64                         m_directories = new ArrayList ();
65                         m_directories.Add (".");
66                         m_directories.Add ("bin");
67                 }
68
69                 public virtual AssemblyDefinition Resolve (AssemblyNameReference name)
70                 {
71                         AssemblyDefinition assembly;
72                         string frameworkdir = Path.GetDirectoryName (typeof (object).Module.FullyQualifiedName);
73
74                         assembly = SearchDirectory (name, m_directories);
75                         if (assembly != null)
76                                 return assembly;
77
78                         if (IsZero (name.Version)) {
79                                 assembly = SearchDirectory (name, new string [] {frameworkdir});
80                                 if (assembly != null)
81                                         return assembly;
82                         }
83
84 #if !CF_1_0 && !CF_2_0 && !NO_SYSTEM_DLL
85                         if (name.Name == "mscorlib") {
86                                 assembly = GetCorlib (name);
87                                 if (assembly != null)
88                                         return assembly;
89                         }
90
91                         assembly = GetAssemblyInGac (name);
92                         if (assembly != null)
93                                 return assembly;
94 #endif
95
96                         assembly = SearchDirectory (name, new string [] {frameworkdir});
97                         if (assembly != null)
98                                 return assembly;
99
100                         throw new FileNotFoundException ("Could not resolve: " + name);
101                 }
102
103                 static readonly string [] _extentions = new string [] { ".dll", ".exe" };
104
105                 static AssemblyDefinition SearchDirectory (AssemblyNameReference name, IEnumerable directories)
106                 {
107                         foreach (string dir in directories) {
108                                 foreach (string ext in _extentions) {
109                                         string file = Path.Combine (dir, name.Name + ext);
110                                         if (File.Exists (file))
111                                                 return AssemblyFactory.GetAssembly (file);
112                                 }
113                         }
114
115                         return null;
116                 }
117
118                 static bool IsZero (Version version)
119                 {
120                         return version.Major == 0 && version.Minor == 0 && version.Build == 0 && version.Revision == 0;
121                 }
122
123 #if !CF_1_0 && !CF_2_0 && !NO_SYSTEM_DLL
124                 static AssemblyDefinition GetCorlib (AssemblyNameReference reference)
125                 {
126                         SR.AssemblyName corlib = typeof (object).Assembly.GetName ();
127                         if (corlib.Version == reference.Version || IsZero (reference.Version))
128                                 return AssemblyFactory.GetAssembly (typeof (object).Module.FullyQualifiedName);
129
130                         string path = Directory.GetParent (
131                                 Directory.GetParent (
132                                         typeof (object).Module.FullyQualifiedName).FullName
133                                 ).FullName;
134
135                         string runtime_path = null;
136                         if (OnMono ()) {
137                                 if (reference.Version.Major == 1)
138                                         runtime_path = "1.0";
139                                 else if (reference.Version.Major == 2) {
140                                         if (reference.Version.Minor == 1)
141                                                 runtime_path = "2.1";
142                                         else
143                                                 runtime_path = "2.0";
144                                 } else if (reference.Version.Major == 4)
145                                         runtime_path = "4.0";
146                         } else {
147                                 switch (reference.Version.ToString ()) {
148                                 case "1.0.3300.0":
149                                         runtime_path = "v1.0.3705";
150                                         break;
151                                 case "1.0.5000.0":
152                                         runtime_path = "v1.1.4322";
153                                         break;
154                                 case "2.0.0.0":
155                                         runtime_path = "v2.0.50727";
156                                         break;
157                                 case "4.0.0.0":
158                                         runtime_path = "v4.0.30319";
159                                         break;
160                                 }
161                         }
162
163                         if (runtime_path == null)
164                                 throw new NotSupportedException ("Version not supported: " + reference.Version);
165
166                         path = Path.Combine (path, runtime_path);
167
168                         if (File.Exists (Path.Combine (path, "mscorlib.dll")))
169                                 return AssemblyFactory.GetAssembly (Path.Combine (path, "mscorlib.dll"));
170
171                         return null;
172                 }
173
174                 public static bool OnMono ()
175                 {
176                         return typeof (object).Assembly.GetType ("System.MonoType", false) != null;
177                 }
178
179                 string[] MonoGacPaths {
180                         get {
181                                 if (m_monoGacPaths == null)
182                                         m_monoGacPaths = GetDefaultMonoGacPaths ();
183                                 return m_monoGacPaths;
184                         }
185                 }
186
187                 static string[] GetDefaultMonoGacPaths ()
188                 {
189                         ArrayList paths = new ArrayList ();
190                         string s = GetCurrentGacPath ();
191                         if (s != null)
192                                 paths.Add (s);
193                         string gacPathsEnv = Environment.GetEnvironmentVariable ("MONO_GAC_PREFIX");
194                         if (gacPathsEnv != null && gacPathsEnv.Length > 0) {
195                                 string[] gacPrefixes = gacPathsEnv.Split (Path.PathSeparator);
196                                 foreach (string gacPrefix in gacPrefixes) {
197                                         if (gacPrefix != null && gacPrefix.Length > 0) {
198                                                 string gac = Path.Combine (Path.Combine (Path.Combine (gacPrefix, "lib"), "mono"), "gac");
199                                                 if (Directory.Exists (gac) && !paths.Contains (gac))
200                                                         paths.Add (gac);
201                                         }
202                                 }
203                         }
204                         return (string[]) paths.ToArray (typeof (String));
205                 }
206
207                 AssemblyDefinition GetAssemblyInGac (AssemblyNameReference reference)
208                 {
209                         if (reference.PublicKeyToken == null || reference.PublicKeyToken.Length == 0)
210                                 return null;
211
212                         if (OnMono ()) {
213                                 foreach (string gacpath in MonoGacPaths) {
214                                         string s = GetAssemblyFile (reference, gacpath);
215                                         if (File.Exists (s))
216                                                 return AssemblyFactory.GetAssembly (s);
217                                 }
218                         } else {
219                                 string currentGac = GetCurrentGacPath ();
220                                 if (currentGac == null)
221                                         return null;
222
223                                 string [] gacs = new string [] {"GAC_MSIL", "GAC_32", "GAC"};
224                                 for (int i = 0; i < gacs.Length; i++) {
225                                         string gac = Path.Combine (Directory.GetParent (currentGac).FullName, gacs [i]);
226                                         string asm = GetAssemblyFile (reference, gac);
227                                         if (Directory.Exists (gac) && File.Exists (asm))
228                                                 return AssemblyFactory.GetAssembly (asm);
229                                 }
230                         }
231
232                         return null;
233                 }
234
235                 static string GetAssemblyFile (AssemblyNameReference reference, string gac)
236                 {
237                         StringBuilder sb = new StringBuilder ();
238                         sb.Append (reference.Version);
239                         sb.Append ("__");
240                         for (int i = 0; i < reference.PublicKeyToken.Length; i++)
241                                 sb.Append (reference.PublicKeyToken [i].ToString ("x2"));
242
243                         return Path.Combine (
244                                 Path.Combine (
245                                         Path.Combine (gac, reference.Name), sb.ToString ()),
246                                         string.Concat (reference.Name, ".dll"));
247                 }
248
249                 static string GetCurrentGacPath ()
250                 {
251                         string file = typeof (Uri).Module.FullyQualifiedName;
252                         if (!File.Exists (file))
253                                 return null;
254
255                         return Directory.GetParent (
256                                 Directory.GetParent (
257                                         Path.GetDirectoryName (
258                                                 file)
259                                         ).FullName
260                                 ).FullName;
261                 }
262 #endif
263         }
264 }