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.

154 lines
5.8 KiB

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