R/Ryujinx.Common/Utilities/MessagePackObjectFormatter.cs

303 lines
7.7 KiB
C#
Raw Normal View History

using MsgPack;
using System;
using System.Text;
namespace Ryujinx.Common.Utilities
{
public static class MessagePackObjectFormatter
{
public static string ToString(this MessagePackObject obj, bool pretty)
{
if (pretty)
{
return Format(obj);
}
else
{
return obj.ToString();
}
}
public static string Format(MessagePackObject obj)
{
var builder = new IndentedStringBuilder();
FormatMsgPackObj(obj, builder);
return builder.ToString();
}
private static void FormatMsgPackObj(MessagePackObject obj, IndentedStringBuilder builder)
{
if (obj.IsMap || obj.IsDictionary)
{
FormatMsgPackMap(obj, builder);
}
else if (obj.IsArray || obj.IsList)
{
FormatMsgPackArray(obj, builder);
}
else if (obj.IsNil)
{
builder.Append("null");
}
else
{
var literal = obj.ToObject();
if (literal is String)
{
builder.AppendQuotedString(obj.AsStringUtf16());
}
else if (literal is byte[] byteArray)
{
FormatByteArray(byteArray, builder);
}
else if (literal is MessagePackExtendedTypeObject extObject)
{
builder.Append('{');
// Indent
builder.IncreaseIndent()
.AppendLine();
// Print TypeCode field
builder.AppendQuotedString("TypeCode")
.Append(": ")
.Append(extObject.TypeCode)
.AppendLine(",");
// Print Value field
builder.AppendQuotedString("Value")
.Append(": ");
FormatByteArrayAsString(extObject.GetBody(), builder, true);
// Unindent
builder.DecreaseIndent()
.AppendLine();
builder.Append('}');
}
else
{
builder.Append(literal);
}
}
}
private static void FormatByteArray(byte[] arr, IndentedStringBuilder builder)
{
builder.Append("[ ");
foreach (var b in arr)
{
builder.Append("0x");
builder.Append(ToHexChar(b >> 4));
builder.Append(ToHexChar(b & 0xF));
builder.Append(", ");
}
// Remove trailing comma
builder.Remove(builder.Length - 2, 2);
builder.Append(" ]");
}
private static void FormatByteArrayAsString(byte[] arr, IndentedStringBuilder builder, bool withPrefix)
{
builder.Append('"');
if (withPrefix)
{
builder.Append("0x");
}
foreach (var b in arr)
{
builder.Append(ToHexChar(b >> 4));
builder.Append(ToHexChar(b & 0xF));
}
builder.Append('"');
}
private static void FormatMsgPackMap(MessagePackObject obj, IndentedStringBuilder builder)
{
var map = obj.AsDictionary();
builder.Append('{');
// Indent
builder.IncreaseIndent()
.AppendLine();
foreach (var item in map)
{
FormatMsgPackObj(item.Key, builder);
builder.Append(": ");
FormatMsgPackObj(item.Value, builder);
builder.AppendLine(",");
}
// Remove the trailing new line and comma
builder.TrimLastLine()
.Remove(builder.Length - 1, 1);
// Unindent
builder.DecreaseIndent()
.AppendLine();
builder.Append('}');
}
private static void FormatMsgPackArray(MessagePackObject obj, IndentedStringBuilder builder)
{
var arr = obj.AsList();
builder.Append("[ ");
foreach (var item in arr)
{
FormatMsgPackObj(item, builder);
builder.Append(", ");
}
// Remove trailing comma
builder.Remove(builder.Length - 2, 2);
builder.Append(" ]");
}
private static char ToHexChar(int b)
{
if (b < 10)
{
return unchecked((char)('0' + b));
}
else
{
return unchecked((char)('A' + (b - 10)));
}
}
internal class IndentedStringBuilder
{
const string DefaultIndent = " ";
private int _indentCount = 0;
private int _newLineIndex = 0;
private StringBuilder _builder;
public string IndentString { get; set; } = DefaultIndent;
public IndentedStringBuilder(StringBuilder builder)
{
_builder = builder;
}
public IndentedStringBuilder()
: this(new StringBuilder())
{ }
public IndentedStringBuilder(string str)
: this(new StringBuilder(str))
{ }
public IndentedStringBuilder(int length)
: this(new StringBuilder(length))
{ }
public int Length { get => _builder.Length; }
public IndentedStringBuilder IncreaseIndent()
{
_indentCount++;
return this;
}
public IndentedStringBuilder DecreaseIndent()
{
_indentCount--;
return this;
}
public IndentedStringBuilder Append(char value)
{
_builder.Append(value);
return this;
}
public IndentedStringBuilder Append(string value)
{
_builder.Append(value);
return this;
}
public IndentedStringBuilder Append(object value)
{
this.Append(value.ToString());
return this;
}
public IndentedStringBuilder AppendQuotedString(string value)
{
_builder.Append('"');
_builder.Append(value);
_builder.Append('"');
return this;
}
public IndentedStringBuilder AppendLine()
{
_newLineIndex = _builder.Length;
_builder.AppendLine();
for (int i = 0; i < _indentCount; i++)
_builder.Append(IndentString);
return this;
}
public IndentedStringBuilder AppendLine(string value)
{
_builder.Append(value);
this.AppendLine();
return this;
}
public IndentedStringBuilder TrimLastLine()
{
_builder.Remove(_newLineIndex, _builder.Length - _newLineIndex);
return this;
}
public IndentedStringBuilder Remove(int startIndex, int length)
{
_builder.Remove(startIndex, length);
return this;
}
public override string ToString()
{
return _builder.ToString();
}
}
}
}