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