2025-12-03 01:52:33 +09:00

90 lines
2.3 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using JetBrains.Annotations;
namespace F10.StreamDeckIntegration.Json {
/// <summary>
/// Simplified JSON parser to exclusively deal with StreamDeck JSON websocket communication messages.
/// </summary>
internal static class JsonParser {
[CanBeNull]
internal static Dictionary<string, JsonData> Parse(string json) {
if (!json.StartsWith("{") || !json.EndsWith("}")) return null;
var dict = new Dictionary<string, JsonData>();
// Remove start and end {}
json = json.Substring(1);
json = json.Remove(json.Length - 1);
// Encode all characters between quotes
json = EncodeInQuotes(json);
// Separate by , (taking care of nested {})
var lastIndex = 0;
var nestedLevel = 0;
for (var i = 0; i < json.Length; i++) {
if (i >= json.Length - 1 || json[i] == ',' && nestedLevel <= 0) {
// Separate key-value :
var section = json.Substring(lastIndex, (i + 1) - lastIndex);
// Remove start and end ,
if (section.StartsWith(",")) {
section = section.Substring(1);
}
if (section.EndsWith(",")) {
section = section.Remove(section.Length - 1);
}
// Split by :
var keyValue = section.Split(new[] {':'}, 2).Select(x => x.Trim()).ToArray();
// Has nested json?
var jsonData = keyValue[1].Contains("{")
? new JsonData(Parse(Uri.UnescapeDataString(keyValue[1])))
: new JsonData(RemoveQuotesAndDecode(keyValue[1]));
dict.Add(RemoveQuotesAndDecode(keyValue[0]), jsonData);
lastIndex = i;
continue;
}
switch (json[i]) {
case '{':
nestedLevel++;
continue;
case '}':
nestedLevel--;
continue;
}
}
return dict;
}
private static string EncodeInQuotes(string data) {
const string pattern = "\"([^\"]*)\"";
return Regex.Replace(data, pattern, Encode, RegexOptions.IgnoreCase);
}
private static string Encode(Match m) {
return "\"" + Uri.EscapeDataString(m.Groups[1].Value) + "\"";
}
// Remove start and end quotes, decode
private static string RemoveQuotesAndDecode(string data) {
if (data.StartsWith("\"")) {
data = data.Substring(1);
}
if (data.EndsWith("\"")) {
data = data.Remove(data.Length - 1);
}
return Uri.UnescapeDataString(data);
}
}
}