XTermFix.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection.Emit;
  5. using HarmonyLib;
  6. namespace BepInEx.Preloader.RuntimeFixes
  7. {
  8. internal static class XTermFix
  9. {
  10. public static void Apply()
  11. {
  12. if (Environment.OSVersion.Platform != PlatformID.Unix)
  13. return;
  14. if (AccessTools.Method("System.TermInfoReader:DetermineVersion") != null)
  15. {
  16. // Fix has been applied officially
  17. return;
  18. }
  19. var harmony = new HarmonyLib.Harmony("com.bepinex.xtermfix");
  20. harmony.Patch(AccessTools.Method("System.TermInfoReader:ReadHeader"),
  21. prefix: new HarmonyMethod(typeof(XTermFix), nameof(ReadHeaderPrefix)));
  22. harmony.Patch(AccessTools.Method("System.TermInfoReader:Get", new []{ AccessTools.TypeByName("System.TermInfoNumbers") }),
  23. transpiler: new HarmonyMethod(typeof(XTermFix), nameof(GetTermInfoNumbersTranspiler)));
  24. harmony.Patch(AccessTools.Method("System.TermInfoReader:Get", new []{ AccessTools.TypeByName("System.TermInfoStrings") }),
  25. transpiler: new HarmonyMethod(typeof(XTermFix), nameof(GetTermInfoStringsTranspiler)));
  26. harmony.Patch(AccessTools.Method("System.TermInfoReader:GetStringBytes", new []{ AccessTools.TypeByName("System.TermInfoStrings") }),
  27. transpiler: new HarmonyMethod(typeof(XTermFix), nameof(GetTermInfoStringsTranspiler)));
  28. }
  29. public static int intOffset;
  30. public static int GetInt32(byte[] buffer, int offset)
  31. {
  32. int b1 = buffer[offset];
  33. int b2 = buffer[offset + 1];
  34. int b3 = buffer[offset + 2];
  35. int b4 = buffer[offset + 3];
  36. if (b1 == 255 && b2 == 255 && b3 == 255 && b4 == 255)
  37. return -1;
  38. return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
  39. }
  40. public static short GetInt16(byte[] buffer, int offset)
  41. {
  42. int b1 = buffer[offset];
  43. int b2 = buffer[offset + 1];
  44. if (b1 == 255 && b2 == 255)
  45. return -1;
  46. return (short)(b1 | (b2 << 8));
  47. }
  48. public static int GetInteger(byte[] buffer, int offset)
  49. {
  50. return intOffset == 2
  51. ? GetInt16(buffer, offset)
  52. : GetInt32(buffer, offset);
  53. }
  54. public static void DetermineVersion(short magic)
  55. {
  56. if (magic == 0x11a)
  57. intOffset = 2;
  58. else if (magic == 0x21e)
  59. intOffset = 4;
  60. else
  61. throw new Exception($"Unknown xterm header format: {magic}");
  62. }
  63. public static bool ReadHeaderPrefix(object __instance, byte[] buffer, ref int position, ref short ___boolSize, ref short ___numSize, ref short ___strOffsets)
  64. {
  65. short magic = GetInt16(buffer, position);
  66. position += 2;
  67. DetermineVersion(magic);
  68. // nameSize = GetInt16(buffer, position);
  69. position += 2;
  70. ___boolSize = GetInt16(buffer, position);
  71. position += 2;
  72. ___numSize = GetInt16(buffer, position);
  73. position += 2;
  74. ___strOffsets = GetInt16(buffer, position);
  75. position += 2;
  76. // strSize = GetInt16(buffer, position);
  77. position += 2;
  78. return false;
  79. }
  80. public static IEnumerable<CodeInstruction> GetTermInfoNumbersTranspiler(IEnumerable<CodeInstruction> instructions)
  81. {
  82. // This implementation does not seem to have changed so I will be using indexes like the lazy fuck I am
  83. var list = instructions.ToList();
  84. list[31] = new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(XTermFix), nameof(intOffset)));
  85. list[36] = new CodeInstruction(OpCodes.Nop);
  86. list[39] = new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(XTermFix), nameof(GetInteger)));
  87. return list;
  88. }
  89. public static IEnumerable<CodeInstruction> GetTermInfoStringsTranspiler(IEnumerable<CodeInstruction> instructions)
  90. {
  91. // This implementation does not seem to have changed so I will be using indexes like the lazy fuck I am
  92. var list = instructions.ToList();
  93. list[32] = new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(XTermFix), nameof(intOffset)));
  94. return list;
  95. }
  96. }
  97. }