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.

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