chore(release): prepare public source release

This commit is contained in:
MercuryToolbox Release
2026-07-18 15:33:01 +08:00
commit 34d6a57f38
510 changed files with 163501 additions and 0 deletions
@@ -0,0 +1,615 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
namespace Mercury.UnityProbe
{
internal static class MercuryUnityProbeProtocol
{
internal const int MaxRequestChars = 64 * 1024;
private const int MaxJsonDepth = 64;
private const int MaxJsonNodes = 4096;
internal static string Serialize(object value)
{
StringBuilder builder = new StringBuilder();
WriteJsonValue(builder, value);
return builder.ToString();
}
internal static Dictionary<string, object> DeserializeRequest(string json)
{
if (json != null && json.Length > MaxRequestChars)
{
throw new FormatException("JSON request exceeds the maximum request length.");
}
JsonParser parser = new JsonParser(json ?? string.Empty);
object value = parser.ParseValue();
parser.SkipWhitespace();
if (!parser.IsComplete)
{
throw new FormatException("Trailing characters after the JSON request.");
}
Dictionary<string, object> request = value as Dictionary<string, object>;
if (request == null)
{
throw new FormatException("JSON request root must be an object.");
}
return request;
}
internal static Dictionary<string, object> Success(string kind, object data)
{
Dictionary<string, object> response = new Dictionary<string, object>(StringComparer.Ordinal);
response["ok"] = true;
response["kind"] = kind ?? "";
response["data"] = data;
response["error"] = null;
return response;
}
internal static Dictionary<string, object> Error(string kind, string error)
{
Dictionary<string, object> response = new Dictionary<string, object>(StringComparer.Ordinal);
response["ok"] = false;
response["kind"] = kind ?? "";
response["data"] = null;
response["error"] = error ?? "Unknown bridge error.";
return response;
}
internal static string ReadString(IDictionary<string, object> request, string key)
{
if (request == null || key == null || !request.ContainsKey(key))
{
return string.Empty;
}
object raw = request[key];
return raw == null ? string.Empty : Convert.ToString(raw, CultureInfo.InvariantCulture) ?? string.Empty;
}
internal static int ReadInt(IDictionary<string, object> request, string key)
{
if (request == null || key == null || !request.ContainsKey(key) || request[key] == null)
{
return 0;
}
try
{
return Convert.ToInt32(request[key], CultureInfo.InvariantCulture);
}
catch
{
return 0;
}
}
internal static int ReadLimit(IDictionary<string, object> request, int fallback)
{
int value = ReadInt(request, "limit");
if (value <= 0)
{
return fallback;
}
if (value > 250)
{
return 250;
}
return value;
}
private static void WriteJsonValue(StringBuilder builder, object value)
{
if (value == null)
{
builder.Append("null");
return;
}
if (value is string)
{
string text = (string)value;
WriteJsonString(builder, text);
return;
}
if (value is char)
{
char character = (char)value;
WriteJsonString(builder, character.ToString());
return;
}
if (value is bool)
{
bool boolean = (bool)value;
builder.Append(boolean ? "true" : "false");
return;
}
if (IsNumericValue(value))
{
builder.Append(Convert.ToString(value, CultureInfo.InvariantCulture));
return;
}
if (value is IDictionary<string, object>)
{
IDictionary<string, object> objectDictionary = (IDictionary<string, object>)value;
WriteJsonObject(builder, objectDictionary);
return;
}
if (value is IDictionary)
{
IDictionary dictionary = (IDictionary)value;
WriteJsonDictionary(builder, dictionary);
return;
}
if (value is IEnumerable)
{
IEnumerable enumerable = (IEnumerable)value;
WriteJsonArray(builder, enumerable);
return;
}
if (value is Enum)
{
Enum enumValue = (Enum)value;
WriteJsonString(builder, enumValue.ToString());
return;
}
WriteJsonString(
builder,
Convert.ToString(value, CultureInfo.InvariantCulture) ?? string.Empty
);
}
private static bool IsNumericValue(object value)
{
switch (Type.GetTypeCode(value.GetType()))
{
case TypeCode.Byte:
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.SByte:
case TypeCode.Single:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
return true;
default:
return false;
}
}
private static void WriteJsonObject(StringBuilder builder, IDictionary<string, object> dictionary)
{
builder.Append('{');
bool wroteAny = false;
foreach (KeyValuePair<string, object> entry in dictionary)
{
if (wroteAny)
{
builder.Append(',');
}
WriteJsonString(builder, entry.Key ?? string.Empty);
builder.Append(':');
WriteJsonValue(builder, entry.Value);
wroteAny = true;
}
builder.Append('}');
}
private static void WriteJsonDictionary(StringBuilder builder, IDictionary dictionary)
{
builder.Append('{');
bool wroteAny = false;
foreach (DictionaryEntry entry in dictionary)
{
if (wroteAny)
{
builder.Append(',');
}
WriteJsonString(
builder,
Convert.ToString(entry.Key, CultureInfo.InvariantCulture) ?? string.Empty
);
builder.Append(':');
WriteJsonValue(builder, entry.Value);
wroteAny = true;
}
builder.Append('}');
}
private static void WriteJsonArray(StringBuilder builder, IEnumerable values)
{
builder.Append('[');
bool wroteAny = false;
foreach (object value in values)
{
if (wroteAny)
{
builder.Append(',');
}
WriteJsonValue(builder, value);
wroteAny = true;
}
builder.Append(']');
}
private static void WriteJsonString(StringBuilder builder, string value)
{
builder.Append('"');
for (int index = 0; index < value.Length; index++)
{
char character = value[index];
switch (character)
{
case '"':
builder.Append("\\\"");
break;
case '\\':
builder.Append("\\\\");
break;
case '\b':
builder.Append("\\b");
break;
case '\f':
builder.Append("\\f");
break;
case '\n':
builder.Append("\\n");
break;
case '\r':
builder.Append("\\r");
break;
case '\t':
builder.Append("\\t");
break;
default:
if (character < 0x20)
{
builder.Append("\\u");
builder.Append(((int)character).ToString("x4", CultureInfo.InvariantCulture));
}
else
{
builder.Append(character);
}
break;
}
}
builder.Append('"');
}
private sealed class JsonParser
{
private readonly string text;
private int index;
private int depth;
private int nodes;
internal JsonParser(string text)
{
this.text = text ?? string.Empty;
index = 0;
}
internal bool IsComplete
{
get { return index >= text.Length; }
}
internal void SkipWhitespace()
{
while (index < text.Length && char.IsWhiteSpace(text[index]))
{
index++;
}
}
internal object ParseValue()
{
CountNode();
SkipWhitespace();
if (index >= text.Length)
{
throw new FormatException("Unexpected end of JSON input.");
}
char current = text[index];
switch (current)
{
case '{':
return ParseObject();
case '[':
return ParseArray();
case '"':
return ParseString();
case 't':
ParseLiteral("true");
return true;
case 'f':
ParseLiteral("false");
return false;
case 'n':
ParseLiteral("null");
return null;
default:
if (current == '-' || char.IsDigit(current))
{
return ParseNumber();
}
throw new FormatException("Unsupported JSON token at position " + index + ".");
}
}
private Dictionary<string, object> ParseObject()
{
Expect('{');
EnterContainer();
try
{
Dictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.Ordinal);
SkipWhitespace();
if (TryConsume('}'))
{
return dictionary;
}
while (true)
{
SkipWhitespace();
string key = ParseString();
SkipWhitespace();
Expect(':');
object value = ParseValue();
dictionary[key] = value;
SkipWhitespace();
if (TryConsume('}'))
{
return dictionary;
}
Expect(',');
}
}
finally
{
LeaveContainer();
}
}
private List<object> ParseArray()
{
Expect('[');
EnterContainer();
try
{
List<object> list = new List<object>();
SkipWhitespace();
if (TryConsume(']'))
{
return list;
}
while (true)
{
list.Add(ParseValue());
SkipWhitespace();
if (TryConsume(']'))
{
return list;
}
Expect(',');
}
}
finally
{
LeaveContainer();
}
}
private void CountNode()
{
nodes++;
if (nodes > MaxJsonNodes)
{
throw new FormatException("JSON request exceeds the maximum node count.");
}
}
private void EnterContainer()
{
depth++;
if (depth > MaxJsonDepth)
{
throw new FormatException("JSON request exceeds the maximum nesting depth.");
}
}
private void LeaveContainer()
{
depth--;
}
private string ParseString()
{
Expect('"');
StringBuilder builder = new StringBuilder();
while (index < text.Length)
{
char current = text[index++];
if (current == '"')
{
return builder.ToString();
}
if (current != '\\')
{
builder.Append(current);
continue;
}
if (index >= text.Length)
{
throw new FormatException("Unterminated escape sequence in JSON string.");
}
char escaped = text[index++];
switch (escaped)
{
case '"':
builder.Append('"');
break;
case '\\':
builder.Append('\\');
break;
case '/':
builder.Append('/');
break;
case 'b':
builder.Append('\b');
break;
case 'f':
builder.Append('\f');
break;
case 'n':
builder.Append('\n');
break;
case 'r':
builder.Append('\r');
break;
case 't':
builder.Append('\t');
break;
case 'u':
builder.Append(ParseUnicodeEscape());
break;
default:
throw new FormatException("Unsupported escape sequence \\" + escaped + " in JSON string.");
}
}
throw new FormatException("Unterminated JSON string.");
}
private char ParseUnicodeEscape()
{
if (index + 4 > text.Length)
{
throw new FormatException("Incomplete unicode escape in JSON string.");
}
string hex = text.Substring(index, 4);
index += 4;
return (char)int.Parse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
}
private object ParseNumber()
{
int start = index;
if (text[index] == '-')
{
index++;
}
while (index < text.Length && char.IsDigit(text[index]))
{
index++;
}
if (index < text.Length && text[index] == '.')
{
index++;
while (index < text.Length && char.IsDigit(text[index]))
{
index++;
}
}
if (index < text.Length && (text[index] == 'e' || text[index] == 'E'))
{
index++;
if (index < text.Length && (text[index] == '+' || text[index] == '-'))
{
index++;
}
while (index < text.Length && char.IsDigit(text[index]))
{
index++;
}
}
string token = text.Substring(start, index - start);
if (token.IndexOfAny(new[] { '.', 'e', 'E' }) >= 0)
{
return double.Parse(token, CultureInfo.InvariantCulture);
}
return long.Parse(token, CultureInfo.InvariantCulture);
}
private void ParseLiteral(string literal)
{
for (int offset = 0; offset < literal.Length; offset++)
{
if (index + offset >= text.Length || text[index + offset] != literal[offset])
{
throw new FormatException("Invalid JSON literal at position " + index + ".");
}
}
index += literal.Length;
}
private void Expect(char expected)
{
SkipWhitespace();
if (index >= text.Length || text[index] != expected)
{
throw new FormatException("Expected '" + expected + "' at position " + index + ".");
}
index++;
}
private bool TryConsume(char value)
{
SkipWhitespace();
if (index < text.Length && text[index] == value)
{
index++;
return true;
}
return false;
}
}
}
}