using System.Drawing; using System.Text; using static System.Drawing.Color; namespace InnovEnergy.Lib.Protocols.DBus.Utils; public static class HexView { public static String ToHexView2(this ArraySegment segment, Boolean upToSegment = true, Int32 lineWith = 16) { var sbHex = new StringBuilder(); var sbAsc = new StringBuilder(); var sbLines = new StringBuilder(); var data = segment.Array!; var end = upToSegment ? segment.Offset + segment.Count : data.Length; for (var lineStart = 0; lineStart < end; lineStart += lineWith) { sbHex.Clear(); sbAsc.Clear(); for (var pos = lineStart; pos < lineStart + lineWith; pos++) { if (pos >= data.Length) { sbHex.Append("".PadRight((lineWith - (pos % lineWith)) * 3)); break; } var color = IsInsideSegment(pos) ? Red : Black; var octet = data[pos]; sbHex.Append(octet.ToString("X2").Color(color)); sbHex.Append(" "); sbAsc.Append(Printable(octet).Color(color)); } sbLines.Append(lineStart.ToString().PadLeft(4) + ": "); sbLines.Append(sbHex.ToString()); sbLines.Append(" "); sbLines.AppendLine(sbAsc.ToString()); } return sbLines.ToString(); Boolean IsInsideSegment(Int32 pos) => pos >= segment.Offset && pos < segment.Offset + segment.Count; } public static String ToHexView(this ArraySegment data, Int32 lineWith = 16, params (ArraySegment segment, Color color)[] colored) { var sbHex = new StringBuilder(); var sbAsc = new StringBuilder(); var sbLines = new StringBuilder(); for (var i = 0; i < data.Count; i += lineWith) { sbHex.Clear(); sbAsc.Clear(); for (var pos = i; pos < i + lineWith; pos++) { if (pos >= data.Count) { sbHex.Append("".PadRight((lineWith - (pos % lineWith)) * 3)); break; } var color = colored .Where(c => Inside(pos, c.segment)) .Select(c => c.color) .FirstOrDefault(); sbHex.Append(data[pos].ToString("X2").Color(color)); sbHex.Append(" "); sbAsc.Append(Printable(data[pos]).Color(color)); } sbLines.Append(i.ToString().PadLeft(4) + ": "); sbLines.Append(sbHex.ToString()); sbLines.Append(" "); sbLines.AppendLine(sbAsc.ToString()); } return sbLines.ToString(); Boolean Inside(Int32 pos, ArraySegment segment) { pos += data.Offset ; return pos >= segment.Offset && pos < segment.Offset + segment.Count; } } public static String ToHexView(this IEnumerable data, Int32 lineWith = 16) { var sbHex = new StringBuilder(); var sbAsc = new StringBuilder(); var sbLine = new StringBuilder(); using var e = data.GetEnumerator(); var more = true; var address = 0; do { var l = lineWith; while (l-- > 0) { more = e.MoveNext(); if (!more) break; sbHex.Append(e.Current.ToString("X2") + " "); sbAsc.Append(Printable(e.Current)); } sbLine.Append(address.ToString().PadLeft(4) + ": "); sbLine.Append(sbHex.ToString().PadRight(lineWith * 3 + 2)); sbLine.AppendLine(sbAsc.ToString()); sbHex.Clear(); sbAsc.Clear(); address += lineWith; } while (more); return sbLine.ToString(); } private static String Printable(Byte b) { var ch = (Char) b; if (Char.IsLetterOrDigit(ch) || Char.IsPunctuation(ch) || Char.IsSymbol(ch) || ch == ' ') return ch.ToString(); return "."; } private static String Color(this String txt, Color fg = default, Color bg = default) { const String startFg = "\u001b[38;2;"; const String startBg = "\u001b[48;2;"; const String end = "\u001b[0m"; if (fg == default && bg == default) return txt; var sb = new StringBuilder(); if (fg != default) { sb.Append(startFg); sb.Append($"{fg.R};{fg.G};{fg.B}m"); } if (bg != default) { sb.Append(startBg); sb.Append($"{fg.R};{fg.G};{fg.B}m"); } sb.Append(txt); sb.Append(end); return sb.ToString(); } }