PlatformUtils.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. using System;
  2. using System.IO;
  3. using System.Reflection;
  4. using System.Runtime.InteropServices;
  5. using MonoMod.Utils;
  6. namespace BepInEx.Preloader.Core
  7. {
  8. internal static class PlatformUtils
  9. {
  10. [StructLayout(LayoutKind.Sequential, Pack = 1)]
  11. public struct utsname_osx
  12. {
  13. private const int osx_utslen = 256;
  14. [MarshalAs(UnmanagedType.ByValTStr, SizeConst = osx_utslen)]
  15. public string sysname;
  16. [MarshalAs(UnmanagedType.ByValTStr, SizeConst = osx_utslen)]
  17. public string nodename;
  18. [MarshalAs(UnmanagedType.ByValTStr, SizeConst = osx_utslen)]
  19. public string release;
  20. [MarshalAs(UnmanagedType.ByValTStr, SizeConst = osx_utslen)]
  21. public string version;
  22. [MarshalAs(UnmanagedType.ByValTStr, SizeConst = osx_utslen)]
  23. public string machine;
  24. }
  25. [StructLayout(LayoutKind.Sequential, Pack = 1)]
  26. public struct utsname_linux
  27. {
  28. private const int linux_utslen = 65;
  29. [MarshalAs(UnmanagedType.ByValTStr, SizeConst = linux_utslen)]
  30. public string sysname;
  31. [MarshalAs(UnmanagedType.ByValTStr, SizeConst = linux_utslen)]
  32. public string nodename;
  33. [MarshalAs(UnmanagedType.ByValTStr, SizeConst = linux_utslen)]
  34. public string release;
  35. [MarshalAs(UnmanagedType.ByValTStr, SizeConst = linux_utslen)]
  36. public string version;
  37. [MarshalAs(UnmanagedType.ByValTStr, SizeConst = linux_utslen)]
  38. public string machine;
  39. [MarshalAs(UnmanagedType.ByValTStr, SizeConst = linux_utslen)]
  40. public string domainname;
  41. }
  42. [DllImport("libc.so.6", EntryPoint = "uname", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
  43. private static extern IntPtr uname_linux(ref utsname_linux utsname);
  44. [DllImport("/usr/lib/libSystem.dylib", EntryPoint = "uname", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
  45. private static extern IntPtr uname_osx(ref utsname_osx utsname);
  46. /// <summary>
  47. /// Recreation of MonoMod's PlatformHelper.DeterminePlatform method, but with libc calls instead of creating processes.
  48. /// </summary>
  49. public static void SetPlatform()
  50. {
  51. var current = Platform.Unknown;
  52. // For old Mono, get from a private property to accurately get the platform.
  53. // static extern PlatformID Platform
  54. PropertyInfo p_Platform = typeof(Environment).GetProperty("Platform", BindingFlags.NonPublic | BindingFlags.Static);
  55. string platID;
  56. if (p_Platform != null)
  57. {
  58. platID = p_Platform.GetValue(null, new object[0]).ToString();
  59. }
  60. else
  61. {
  62. // For .NET and newer Mono, use the usual value.
  63. platID = Environment.OSVersion.Platform.ToString();
  64. }
  65. platID = platID.ToLowerInvariant();
  66. if (platID.Contains("win"))
  67. {
  68. current = Platform.Windows;
  69. }
  70. else if (platID.Contains("mac") || platID.Contains("osx"))
  71. {
  72. current = Platform.MacOS;
  73. }
  74. else if (platID.Contains("lin") || platID.Contains("unix"))
  75. {
  76. current = Platform.Linux;
  77. }
  78. if (Is(current, Platform.Linux) && Directory.Exists("/data") && File.Exists("/system/build.prop"))
  79. {
  80. current = Platform.Android;
  81. }
  82. else if (Is(current, Platform.Unix) && Directory.Exists("/System/Library/AccessibilityBundles"))
  83. {
  84. current = Platform.iOS;
  85. }
  86. // Is64BitOperatingSystem has been added in .NET Framework 4.0
  87. MethodInfo m_get_Is64BitOperatingSystem = typeof(Environment).GetProperty("Is64BitOperatingSystem")?.GetGetMethod();
  88. if (m_get_Is64BitOperatingSystem != null)
  89. current |= (((bool)m_get_Is64BitOperatingSystem.Invoke(null, new object[0])) ? Platform.Bits64 : 0);
  90. else
  91. current |= (IntPtr.Size >= 8 ? Platform.Bits64 : 0);
  92. if ((Is(current, Platform.MacOS) || Is(current, Platform.Linux)) && Type.GetType("Mono.Runtime") != null)
  93. {
  94. string arch;
  95. IntPtr result;
  96. if (Is(current, Platform.MacOS))
  97. {
  98. utsname_osx utsname_osx = new utsname_osx();
  99. result = uname_osx(ref utsname_osx);
  100. arch = utsname_osx.machine;
  101. }
  102. else
  103. {
  104. // Linux
  105. utsname_linux utsname_linux = new utsname_linux();
  106. result = uname_linux(ref utsname_linux);
  107. arch = utsname_linux.machine;
  108. }
  109. if (result == IntPtr.Zero && (arch.StartsWith("aarch") || arch.StartsWith("arm")))
  110. current |= Platform.ARM;
  111. }
  112. else
  113. {
  114. // Detect ARM based on PE info or uname.
  115. typeof(object).Module.GetPEKind(out PortableExecutableKinds peKind, out ImageFileMachine machine);
  116. if (machine == (ImageFileMachine)0x01C4 /* ARM, .NET Framework 4.5 */)
  117. current |= Platform.ARM;
  118. }
  119. PlatformHelper.Current = current;
  120. }
  121. private static bool Is(Platform current, Platform expected)
  122. {
  123. return (current & expected) == expected;
  124. }
  125. }
  126. }