| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 | 
							- // Sections of this code have been abridged from https://github.com/mono/mono/blob/master/mcs/class/corlib/System/TermInfoReader.cs under the MIT license
 
- using System;
 
- using System.IO;
 
- using System.Linq;
 
- using System.Text;
 
- namespace BepInEx.Unix
 
- {
 
- 	internal class TtyInfo
 
- 	{
 
- 		public string TerminalType { get; set; } = "default";
 
- 		public int MaxColors { get; set; }
 
- 		public string[] ForegroundColorStrings { get; set; }
 
- 		public static TtyInfo Default { get; } = new TtyInfo
 
- 		{
 
- 			MaxColors = 0
 
- 		};
 
- 		public string GetAnsiCode(ConsoleColor color)
 
- 		{
 
- 			if (MaxColors <= 0 || ForegroundColorStrings == null)
 
- 				return string.Empty;
 
- 			int index = (int)color % MaxColors;
 
- 			return ForegroundColorStrings[index];
 
- 		}
 
- 	}
 
- 	internal static class TtyHandler
 
- 	{
 
- 		private static readonly string[] ncursesLocations = new[]
 
- 		{
 
- 			"/usr/share/terminfo",
 
- 			"/etc/terminfo",
 
- 			"/usr/lib/terminfo",
 
- 			"/lib/terminfo"
 
- 		};
 
- 		private static string TryTermInfoDir(string dir, string term)
 
- 		{
 
- 			string infoFilePath = $"{dir}/{(int)term[0]:x}/{term}";
 
- 			if (File.Exists(infoFilePath))
 
- 				return infoFilePath;
 
- 			infoFilePath = Utility.CombinePaths(dir, term.Substring(0, 1), term);
 
- 			if (File.Exists(infoFilePath))
 
- 				return infoFilePath;
 
- 			return null;
 
- 		}
 
- 		private static string FindTermInfoPath(string term)
 
- 		{
 
- 			if (string.IsNullOrEmpty(term))
 
- 				return null;
 
- 			string termInfoVar = Environment.GetEnvironmentVariable("TERMINFO");
 
- 			if (termInfoVar != null && Directory.Exists(termInfoVar))
 
- 			{
 
- 				string text = TryTermInfoDir(termInfoVar, term);
 
- 				if (text != null)
 
- 				{
 
- 					return text;
 
- 				}
 
- 			}
 
- 			foreach (string location in ncursesLocations)
 
- 			{
 
- 				if (Directory.Exists(location))
 
- 				{
 
- 					string text = TryTermInfoDir(location, term);
 
- 					if (text != null)
 
- 						return text;
 
- 				}
 
- 			}
 
- 			return null;
 
- 		}
 
- 		public static TtyInfo GetTtyInfo(string terminal = null)
 
- 		{
 
- 			terminal = terminal ?? Environment.GetEnvironmentVariable("TERM");
 
- 			var path = FindTermInfoPath(terminal);
 
- 			if (path == null)
 
- 				return TtyInfo.Default;
 
- 			byte[] buffer = File.ReadAllBytes(path);
 
- 			var info = TtyInfoParser.Parse(buffer);
 
- 			info.TerminalType = terminal;
 
- 			return info;
 
- 		}
 
- 	}
 
- 	internal static class TtyInfoParser
 
- 	{
 
- 		private static readonly int[] ansiColorMapping =
 
- 		{
 
- 			0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15
 
- 		};
 
- 		public static TtyInfo Parse(byte[] buffer)
 
- 		{
 
- 			int intSize;
 
- 			int magic = GetInt16(buffer, 0);
 
- 			switch (magic)
 
- 			{
 
- 				case 0x11a:
 
- 					intSize = 2;
 
- 					break;
 
- 				case 0x21E:
 
- 					intSize = 4;
 
- 					break;
 
- 				default:
 
- 					// Unknown ttyinfo format
 
- 					return TtyInfo.Default;
 
- 			}
 
- 			int boolFieldLength = GetInt16(buffer, 4);
 
- 			int intFieldLength = GetInt16(buffer, 6);
 
- 			int strOffsetFieldLength = GetInt16(buffer, 8);
 
- 			// Normally i'd put a more complete implementation here, but I only need to parse this info to get the max color count
 
- 			// Feel free to implement the rest of this using these sources:
 
- 			// https://github.com/mono/mono/blob/master/mcs/class/corlib/System/TermInfoReader.cs
 
- 			// https://invisible-island.net/ncurses/man/term.5.html
 
- 			// https://invisible-island.net/ncurses/man/terminfo.5.html
 
- 			int baseOffset = 12 + GetString(buffer, 12).Length + 1; // Skip the terminal name
 
- 			baseOffset += boolFieldLength; // Length of bool field section
 
- 			baseOffset += baseOffset % 2; // Correct for boundary
 
- 			int colorOffset =
 
- 				baseOffset
 
- 				+ (intSize * (int)TermInfoNumbers.MaxColors); // Finally the offset for the max color integer
 
- 			//int stringOffset = baseOffset + (intSize * intFieldLength);
 
- 			//int foregoundColorOffset =
 
- 			//	stringOffset
 
- 			//	+ (2 * (int)TermInfoStrings.SetAForeground);
 
- 			//foregoundColorOffset = stringOffset
 
- 			//					   + (2 * strOffsetFieldLength)
 
- 			//					   + GetInt16(buffer, foregoundColorOffset);
 
- 			var info = new TtyInfo();
 
- 			info.MaxColors = GetInteger(intSize, buffer, colorOffset);
 
- 			//string setForegroundTemplate = GetString(buffer, foregoundColorOffset);
 
- 			//info.ForegroundColorStrings = ansiColorMapping.Select(x => setForegroundTemplate.Replace("%p1%", x.ToString())).ToArray();
 
- 			info.ForegroundColorStrings = ansiColorMapping.Select(x => $"\u001B[{(x > 7 ? 82 + x : 30 + x)}m").ToArray();
 
- 			return info;
 
- 		}
 
- 		private static int GetInt32(byte[] buffer, int offset)
 
- 		{
 
- 			return buffer[offset]
 
- 				   | (buffer[offset + 1] << 8)
 
- 				   | (buffer[offset + 2] << 16)
 
- 				   | (buffer[offset + 3] << 24);
 
- 		}
 
- 		private static short GetInt16(byte[] buffer, int offset)
 
- 		{
 
- 			return (short)(buffer[offset]
 
- 						   | (buffer[offset + 1] << 8));
 
- 		}
 
- 		private static int GetInteger(int intSize, byte[] buffer, int offset)
 
- 		{
 
- 			return intSize == 2
 
- 				? GetInt16(buffer, offset)
 
- 				: GetInt32(buffer, offset);
 
- 		}
 
- 		private static string GetString(byte[] buffer, int offset)
 
- 		{
 
- 			int length = 0;
 
- 			while (buffer[offset + length] != 0x00)
 
- 				length++;
 
- 			return Encoding.ASCII.GetString(buffer, offset, length);
 
- 		}
 
- 		internal enum TermInfoNumbers
 
- 		{
 
- 			MaxColors = 13
 
- 		}
 
- 		internal enum TermInfoStrings
 
- 		{
 
- 			SetAForeground = 359
 
- 		}
 
- 	}
 
- }
 
 
  |