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.

112 lines
4.1 KiB

  1. #nullable enable
  2. using IPA.Utilities;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Text;
  8. #if NET3
  9. using Net3_Proxy;
  10. using Path = Net3_Proxy.Path;
  11. using File = Net3_Proxy.File;
  12. using Directory = Net3_Proxy.Directory;
  13. #endif
  14. namespace IPA.Injector
  15. {
  16. internal static class GameVersionEarly
  17. {
  18. internal static string ResolveDataPath(string installDir) =>
  19. Directory.EnumerateDirectories(installDir, "*_Data").First();
  20. internal static string GlobalGameManagers(string installDir) =>
  21. Path.Combine(ResolveDataPath(installDir), "globalgamemanagers");
  22. internal static string GetGameVersion()
  23. {
  24. var mgr = GlobalGameManagers(UnityGame.InstallPath);
  25. using (var stream = File.OpenRead(mgr))
  26. using (var reader = new BinaryReader(stream, Encoding.UTF8))
  27. {
  28. const string key = "public.app-category.games";
  29. int pos = 0;
  30. var streamLength = stream.Length;
  31. while (stream.Position < streamLength && pos < key.Length)
  32. {
  33. if (reader.ReadByte() == key[pos]) pos++;
  34. else pos = 0;
  35. }
  36. if (stream.Position == streamLength) // we went through the entire stream without finding the key
  37. throw new KeyNotFoundException("Could not find key '" + key + "' in " + mgr);
  38. var startIndex = 0L;
  39. var endIndex = 0L;
  40. while (stream.Position < streamLength && endIndex == 0L)
  41. {
  42. var current = (char)reader.ReadByte();
  43. if (char.IsDigit(current))
  44. {
  45. startIndex = stream.Position - 1;
  46. var dotCount = 0;
  47. while (stream.Position < streamLength)
  48. {
  49. current = (char)reader.ReadByte();
  50. if (char.IsDigit(current))
  51. {
  52. if (dotCount == 2 && stream.Position < streamLength && !char.IsDigit((char)reader.PeekChar()))
  53. {
  54. endIndex = stream.Position;
  55. break;
  56. }
  57. }
  58. else if (current == '.')
  59. {
  60. dotCount++;
  61. }
  62. else
  63. {
  64. break;
  65. }
  66. }
  67. }
  68. }
  69. var strlen = (int)(endIndex - startIndex);
  70. _ = stream.Seek(-strlen, SeekOrigin.Current);
  71. var strbytes = reader.ReadBytes(strlen);
  72. return Encoding.UTF8.GetString(strbytes);
  73. }
  74. }
  75. internal static AlmostVersion SafeParseVersion() => new(GetGameVersion());
  76. private static void _Load()
  77. {
  78. UnityGame.SetEarlyGameVersion(SafeParseVersion());
  79. UnityGame.CheckGameVersionBoundary();
  80. }
  81. internal static void Load()
  82. {
  83. // This exists for the same reason the wierdness in Injector.Main does
  84. _ = Type.GetType("SemVer.Version, SemVer", false);
  85. _Load();
  86. }
  87. internal static readonly char[] IllegalCharacters = new char[]
  88. {
  89. '<', '>', ':', '/', '\\', '|', '?', '*', '"',
  90. '\u0000', '\u0001', '\u0002', '\u0003', '\u0004', '\u0005', '\u0006', '\u0007',
  91. '\u0008', '\u0009', '\u000a', '\u000b', '\u000c', '\u000d', '\u000e', '\u000d',
  92. '\u000f', '\u0010', '\u0011', '\u0012', '\u0013', '\u0014', '\u0015', '\u0016',
  93. '\u0017', '\u0018', '\u0019', '\u001a', '\u001b', '\u001c', '\u001d', '\u001f',
  94. };
  95. }
  96. }