You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

159 lines
6.0 KiB

  1. using IPA.Logging;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Reflection;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. using static IPA.Logging.Logger;
  10. namespace IPA.Injector
  11. {
  12. internal class LibLoader
  13. {
  14. public static string LibsDir { get; set; } = Path.Combine(Environment.CurrentDirectory, "Libs");
  15. public static string NativeDir { get; set; } = Path.Combine(LibsDir, "Native");
  16. private static Dictionary<string, string> filenameLocations = null;
  17. public static Assembly AssemblyLibLoader(object source, ResolveEventArgs e)
  18. {
  19. var asmName = new AssemblyName(e.Name);
  20. Log(Level.Debug, $"Resolving library {asmName}");
  21. if (filenameLocations == null)
  22. {
  23. filenameLocations = new Dictionary<string, string>();
  24. foreach (var fn in TraverseTree(LibsDir, s => s != NativeDir))
  25. filenameLocations.Add(fn.Name, fn.FullName);
  26. }
  27. var testFilen = $"{asmName.Name}.{asmName.Version}.dll";
  28. Log(Level.Debug, $"Looking for file {testFilen}");
  29. if (filenameLocations.TryGetValue(testFilen, out string path))
  30. {
  31. Log(Level.Debug, $"Found file {testFilen} as {path}");
  32. if (File.Exists(path))
  33. {
  34. return Assembly.LoadFrom(path);
  35. }
  36. else
  37. {
  38. Log(Level.Critical, $"but {path} no longer exists!");
  39. }
  40. }
  41. Log(Level.Critical, $"No library {asmName} found");
  42. return null;
  43. }
  44. private static void Log(Level lvl, string message)
  45. { // multiple proxy methods to delay loading of assemblies until it's done
  46. if (LogCreated)
  47. AssemblyLibLoaderCallLogger(lvl, message);
  48. else
  49. if (((byte)lvl & (byte)StandardLogger.PrintFilter) != 0)
  50. Console.WriteLine($"[{lvl}] {message}");
  51. }
  52. private static void AssemblyLibLoaderCallLogger(Level lvl, string message)
  53. {
  54. libLoader.Log(lvl, message);
  55. }
  56. // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/file-system/how-to-iterate-through-a-directory-tree
  57. private static IEnumerable<FileInfo> TraverseTree(string root, Func<string, bool> dirValidator = null)
  58. {
  59. if (dirValidator == null) dirValidator = (s) => true;
  60. // Data structure to hold names of subfolders to be
  61. // examined for files.
  62. Stack<string> dirs = new Stack<string>(32);
  63. if (!System.IO.Directory.Exists(root))
  64. {
  65. throw new ArgumentException();
  66. }
  67. dirs.Push(root);
  68. while (dirs.Count > 0)
  69. {
  70. string currentDir = dirs.Pop();
  71. string[] subDirs;
  72. try
  73. {
  74. subDirs = System.IO.Directory.GetDirectories(currentDir);
  75. }
  76. // An UnauthorizedAccessException exception will be thrown if we do not have
  77. // discovery permission on a folder or file. It may or may not be acceptable
  78. // to ignore the exception and continue enumerating the remaining files and
  79. // folders. It is also possible (but unlikely) that a DirectoryNotFound exception
  80. // will be raised. This will happen if currentDir has been deleted by
  81. // another application or thread after our call to Directory.Exists. The
  82. // choice of which exceptions to catch depends entirely on the specific task
  83. // you are intending to perform and also on how much you know with certainty
  84. // about the systems on which this code will run.
  85. catch (UnauthorizedAccessException e)
  86. {
  87. //Console.WriteLine(e.Message);
  88. continue;
  89. }
  90. catch (System.IO.DirectoryNotFoundException e)
  91. {
  92. //Console.WriteLine(e.Message);
  93. continue;
  94. }
  95. string[] files = null;
  96. try
  97. {
  98. files = System.IO.Directory.GetFiles(currentDir);
  99. }
  100. catch (UnauthorizedAccessException e)
  101. {
  102. //Console.WriteLine(e.Message);
  103. continue;
  104. }
  105. catch (System.IO.DirectoryNotFoundException e)
  106. {
  107. //Console.WriteLine(e.Message);
  108. continue;
  109. }
  110. // Push the subdirectories onto the stack for traversal.
  111. // This could also be done before handing the files.
  112. foreach (string str in subDirs)
  113. if (dirValidator(str)) dirs.Push(str);
  114. // Perform the required action on each file here.
  115. // Modify this block to perform your required task.
  116. foreach (string file in files)
  117. {
  118. FileInfo nextValue = null;
  119. try
  120. {
  121. // Perform whatever action is required in your scenario.
  122. nextValue = new System.IO.FileInfo(file);
  123. //Console.WriteLine("{0}: {1}, {2}", fi.Name, fi.Length, fi.CreationTime);
  124. }
  125. catch (System.IO.FileNotFoundException e)
  126. {
  127. // If file was deleted by a separate application
  128. // or thread since the call to TraverseTree()
  129. // then just continue.
  130. //Console.WriteLine(e.Message);
  131. continue;
  132. }
  133. yield return nextValue;
  134. }
  135. }
  136. }
  137. }
  138. }