PageRenderTime 23ms CodeModel.GetById 43ms RepoModel.GetById 1ms app.codeStats 0ms

/Mono.Cecil/BaseAssemblyResolver.cs

https://github.com/gluck/cecil
C# | 352 lines | 274 code | 68 blank | 10 comment | 82 complexity | 6c6bf2b763f58ad0c1468bf18efcab64 MD5 | raw file
  1. //
  2. // Author:
  3. // Jb Evain (jbevain@gmail.com)
  4. //
  5. // Copyright (c) 2008 - 2015 Jb Evain
  6. // Copyright (c) 2008 - 2011 Novell, Inc.
  7. //
  8. // Licensed under the MIT/X11 license.
  9. //
  10. using System;
  11. using System.Collections.Generic;
  12. using System.IO;
  13. using System.Text;
  14. using Mono.Collections.Generic;
  15. namespace Mono.Cecil {
  16. public delegate AssemblyDefinition AssemblyResolveEventHandler (object sender, AssemblyNameReference reference);
  17. public sealed class AssemblyResolveEventArgs : EventArgs {
  18. readonly AssemblyNameReference reference;
  19. public AssemblyNameReference AssemblyReference {
  20. get { return reference; }
  21. }
  22. public AssemblyResolveEventArgs (AssemblyNameReference reference)
  23. {
  24. this.reference = reference;
  25. }
  26. }
  27. #if !SILVERLIGHT && !CF
  28. [Serializable]
  29. #endif
  30. public class AssemblyResolutionException : FileNotFoundException {
  31. readonly AssemblyNameReference reference;
  32. public AssemblyNameReference AssemblyReference {
  33. get { return reference; }
  34. }
  35. public AssemblyResolutionException (AssemblyNameReference reference)
  36. : base (string.Format ("Failed to resolve assembly: '{0}'", reference))
  37. {
  38. this.reference = reference;
  39. }
  40. #if !SILVERLIGHT && !CF
  41. protected AssemblyResolutionException (
  42. System.Runtime.Serialization.SerializationInfo info,
  43. System.Runtime.Serialization.StreamingContext context)
  44. : base (info, context)
  45. {
  46. }
  47. #endif
  48. }
  49. public abstract class BaseAssemblyResolver : IAssemblyResolver {
  50. static readonly bool on_mono = Type.GetType ("Mono.Runtime") != null;
  51. readonly Collection<string> directories;
  52. #if !SILVERLIGHT && !CF
  53. Collection<string> gac_paths;
  54. #endif
  55. public void AddSearchDirectory (string directory)
  56. {
  57. directories.Add (directory);
  58. }
  59. public void RemoveSearchDirectory (string directory)
  60. {
  61. directories.Remove (directory);
  62. }
  63. public string [] GetSearchDirectories ()
  64. {
  65. var directories = new string [this.directories.size];
  66. Array.Copy (this.directories.items, directories, directories.Length);
  67. return directories;
  68. }
  69. public virtual AssemblyDefinition Resolve (string fullName)
  70. {
  71. return Resolve (fullName, new ReaderParameters ());
  72. }
  73. public virtual AssemblyDefinition Resolve (string fullName, ReaderParameters parameters)
  74. {
  75. if (fullName == null)
  76. throw new ArgumentNullException ("fullName");
  77. return Resolve (AssemblyNameReference.Parse (fullName), parameters);
  78. }
  79. public event AssemblyResolveEventHandler ResolveFailure;
  80. protected BaseAssemblyResolver ()
  81. {
  82. directories = new Collection<string> (2) { ".", "bin" };
  83. }
  84. AssemblyDefinition GetAssembly (string file, ReaderParameters parameters)
  85. {
  86. if (parameters.AssemblyResolver == null)
  87. parameters.AssemblyResolver = this;
  88. return ModuleDefinition.ReadModule (file, parameters).Assembly;
  89. }
  90. public virtual AssemblyDefinition Resolve (AssemblyNameReference name)
  91. {
  92. return Resolve (name, new ReaderParameters ());
  93. }
  94. public virtual AssemblyDefinition Resolve (AssemblyNameReference name, ReaderParameters parameters)
  95. {
  96. if (name == null)
  97. throw new ArgumentNullException ("name");
  98. if (parameters == null)
  99. parameters = new ReaderParameters ();
  100. var assembly = SearchDirectory (name, directories, parameters);
  101. if (assembly != null)
  102. return assembly;
  103. #if !SILVERLIGHT && !CF
  104. if (name.IsRetargetable) {
  105. // if the reference is retargetable, zero it
  106. name = new AssemblyNameReference (name.Name, Mixin.ZeroVersion) {
  107. PublicKeyToken = Empty<byte>.Array,
  108. };
  109. }
  110. var framework_dir = Path.GetDirectoryName (typeof (object).Module.FullyQualifiedName);
  111. if (IsZero (name.Version)) {
  112. assembly = SearchDirectory (name, new [] { framework_dir }, parameters);
  113. if (assembly != null)
  114. return assembly;
  115. }
  116. if (name.Name == "mscorlib") {
  117. assembly = GetCorlib (name, parameters);
  118. if (assembly != null)
  119. return assembly;
  120. }
  121. assembly = GetAssemblyInGac (name, parameters);
  122. if (assembly != null)
  123. return assembly;
  124. assembly = SearchDirectory (name, new [] { framework_dir }, parameters);
  125. if (assembly != null)
  126. return assembly;
  127. #endif
  128. if (ResolveFailure != null) {
  129. assembly = ResolveFailure (this, name);
  130. if (assembly != null)
  131. return assembly;
  132. }
  133. throw new AssemblyResolutionException (name);
  134. }
  135. AssemblyDefinition SearchDirectory (AssemblyNameReference name, IEnumerable<string> directories, ReaderParameters parameters)
  136. {
  137. var extensions = new [] { ".exe", ".dll" };
  138. foreach (var directory in directories) {
  139. foreach (var extension in extensions) {
  140. string file = Path.Combine (directory, name.Name + extension);
  141. if (File.Exists (file))
  142. return GetAssembly (file, parameters);
  143. }
  144. }
  145. return null;
  146. }
  147. static bool IsZero (Version version)
  148. {
  149. return version.Major == 0 && version.Minor == 0 && version.Build == 0 && version.Revision == 0;
  150. }
  151. #if !SILVERLIGHT && !CF
  152. AssemblyDefinition GetCorlib (AssemblyNameReference reference, ReaderParameters parameters)
  153. {
  154. var version = reference.Version;
  155. var corlib = typeof (object).Assembly.GetName ();
  156. if (corlib.Version == version || IsZero (version))
  157. return GetAssembly (typeof (object).Module.FullyQualifiedName, parameters);
  158. var path = Directory.GetParent (
  159. Directory.GetParent (
  160. typeof (object).Module.FullyQualifiedName).FullName
  161. ).FullName;
  162. if (on_mono) {
  163. if (version.Major == 1)
  164. path = Path.Combine (path, "1.0");
  165. else if (version.Major == 2) {
  166. if (version.MajorRevision == 5)
  167. path = Path.Combine (path, "2.1");
  168. else
  169. path = Path.Combine (path, "2.0");
  170. } else if (version.Major == 4)
  171. path = Path.Combine (path, "4.0");
  172. else
  173. throw new NotSupportedException ("Version not supported: " + version);
  174. } else {
  175. switch (version.Major) {
  176. case 1:
  177. if (version.MajorRevision == 3300)
  178. path = Path.Combine (path, "v1.0.3705");
  179. else
  180. path = Path.Combine (path, "v1.0.5000.0");
  181. break;
  182. case 2:
  183. path = Path.Combine (path, "v2.0.50727");
  184. break;
  185. case 4:
  186. path = Path.Combine (path, "v4.0.30319");
  187. break;
  188. default:
  189. throw new NotSupportedException ("Version not supported: " + version);
  190. }
  191. }
  192. var file = Path.Combine (path, "mscorlib.dll");
  193. if (File.Exists (file))
  194. return GetAssembly (file, parameters);
  195. return null;
  196. }
  197. static Collection<string> GetGacPaths ()
  198. {
  199. if (on_mono)
  200. return GetDefaultMonoGacPaths ();
  201. var paths = new Collection<string> (2);
  202. var windir = Environment.GetEnvironmentVariable ("WINDIR");
  203. if (windir == null)
  204. return paths;
  205. paths.Add (Path.Combine (windir, "assembly"));
  206. paths.Add (Path.Combine (windir, Path.Combine ("Microsoft.NET", "assembly")));
  207. return paths;
  208. }
  209. static Collection<string> GetDefaultMonoGacPaths ()
  210. {
  211. var paths = new Collection<string> (1);
  212. var gac = GetCurrentMonoGac ();
  213. if (gac != null)
  214. paths.Add (gac);
  215. var gac_paths_env = Environment.GetEnvironmentVariable ("MONO_GAC_PREFIX");
  216. if (string.IsNullOrEmpty (gac_paths_env))
  217. return paths;
  218. var prefixes = gac_paths_env.Split (Path.PathSeparator);
  219. foreach (var prefix in prefixes) {
  220. if (string.IsNullOrEmpty (prefix))
  221. continue;
  222. var gac_path = Path.Combine (Path.Combine (Path.Combine (prefix, "lib"), "mono"), "gac");
  223. if (Directory.Exists (gac_path) && !paths.Contains (gac))
  224. paths.Add (gac_path);
  225. }
  226. return paths;
  227. }
  228. static string GetCurrentMonoGac ()
  229. {
  230. return Path.Combine (
  231. Directory.GetParent (
  232. Path.GetDirectoryName (typeof (object).Module.FullyQualifiedName)).FullName,
  233. "gac");
  234. }
  235. AssemblyDefinition GetAssemblyInGac (AssemblyNameReference reference, ReaderParameters parameters)
  236. {
  237. if (reference.PublicKeyToken == null || reference.PublicKeyToken.Length == 0)
  238. return null;
  239. if (gac_paths == null)
  240. gac_paths = GetGacPaths ();
  241. if (on_mono)
  242. return GetAssemblyInMonoGac (reference, parameters);
  243. return GetAssemblyInNetGac (reference, parameters);
  244. }
  245. AssemblyDefinition GetAssemblyInMonoGac (AssemblyNameReference reference, ReaderParameters parameters)
  246. {
  247. for (int i = 0; i < gac_paths.Count; i++) {
  248. var gac_path = gac_paths [i];
  249. var file = GetAssemblyFile (reference, string.Empty, gac_path);
  250. if (File.Exists (file))
  251. return GetAssembly (file, parameters);
  252. }
  253. return null;
  254. }
  255. AssemblyDefinition GetAssemblyInNetGac (AssemblyNameReference reference, ReaderParameters parameters)
  256. {
  257. var gacs = new [] { "GAC_MSIL", "GAC_32", "GAC_64", "GAC" };
  258. var prefixes = new [] { string.Empty, "v4.0_" };
  259. for (int i = 0; i < 2; i++) {
  260. for (int j = 0; j < gacs.Length; j++) {
  261. var gac = Path.Combine (gac_paths [i], gacs [j]);
  262. var file = GetAssemblyFile (reference, prefixes [i], gac);
  263. if (Directory.Exists (gac) && File.Exists (file))
  264. return GetAssembly (file, parameters);
  265. }
  266. }
  267. return null;
  268. }
  269. static string GetAssemblyFile (AssemblyNameReference reference, string prefix, string gac)
  270. {
  271. var gac_folder = new StringBuilder ()
  272. .Append (prefix)
  273. .Append (reference.Version)
  274. .Append ("__");
  275. for (int i = 0; i < reference.PublicKeyToken.Length; i++)
  276. gac_folder.Append (reference.PublicKeyToken [i].ToString ("x2"));
  277. return Path.Combine (
  278. Path.Combine (
  279. Path.Combine (gac, reference.Name), gac_folder.ToString ()),
  280. reference.Name + ".dll");
  281. }
  282. #endif
  283. }
  284. }