using System; using System.Collections.Generic; using System.Globalization; using System.Text; namespace MSCO { /// /// Kleiner eigener JSON-Leser (ohne Newtonsoft.Json - das braucht System.Runtime.Serialization, das ohne MSCLoader im /// Spiel fehlt). Ergebnis: Dictionary<string, object> (Objekt, Schlüssel ohne Groß-/Kleinschreibung), /// List<object>, string, double, bool oder null. /// public static class MiniJson { public static object Parse(string json) { if (json == null) throw new FormatException("No JSON"); int i = 0; object value = ReadValue(json, ref i); SkipWhitespace(json, ref i); if (i < json.Length) throw new FormatException("Unexpected text at " + i); return value; } // ---------------------------------------------------------------- Zugriff public static string Str(Dictionary o, string key, string fallback = null) { object v; if (o == null || !o.TryGetValue(key, out v) || v == null) return fallback; if (v is double) return ((double)v).ToString(CultureInfo.InvariantCulture); return v.ToString(); } public static int Int(Dictionary o, string key, int fallback = 0) { object v; if (o == null || !o.TryGetValue(key, out v)) return fallback; if (v is double) return (int)(double)v; int parsed; return v is string && int.TryParse((string)v, NumberStyles.Integer, CultureInfo.InvariantCulture, out parsed) ? parsed : fallback; } public static bool Bool(Dictionary o, string key, bool fallback = false) { object v; if (o == null || !o.TryGetValue(key, out v)) return fallback; return v is bool ? (bool)v : fallback; } public static List Strings(Dictionary o, string key) { var result = new List(); object v; if (o == null || !o.TryGetValue(key, out v)) return result; var list = v as List; if (list != null) foreach (object item in list) if (item != null) result.Add(item.ToString()); return result; } // ---------------------------------------------------------------- Lesen static object ReadValue(string s, ref int i) { SkipWhitespace(s, ref i); if (i >= s.Length) throw new FormatException("Unexpected end of JSON"); char c = s[i]; if (c == '{') return ReadObject(s, ref i); if (c == '[') return ReadArray(s, ref i); if (c == '"') return ReadString(s, ref i); if (c == '-' || (c >= '0' && c <= '9')) return ReadNumber(s, ref i); if (Word(s, ref i, "true")) return true; if (Word(s, ref i, "false")) return false; if (Word(s, ref i, "null")) return null; throw new FormatException("Unexpected '" + c + "' at " + i); } static Dictionary ReadObject(string s, ref int i) { var o = new Dictionary(StringComparer.OrdinalIgnoreCase); i++; // { SkipWhitespace(s, ref i); if (i < s.Length && s[i] == '}') { i++; return o; } while (true) { SkipWhitespace(s, ref i); if (i >= s.Length || s[i] != '"') throw new FormatException("Expected a name at " + i); string key = ReadString(s, ref i); SkipWhitespace(s, ref i); if (i >= s.Length || s[i] != ':') throw new FormatException("Expected ':' at " + i); i++; o[key] = ReadValue(s, ref i); SkipWhitespace(s, ref i); if (i >= s.Length) throw new FormatException("Unexpected end of JSON"); if (s[i] == ',') { i++; continue; } if (s[i] == '}') { i++; return o; } throw new FormatException("Expected ',' or '}' at " + i); } } static List ReadArray(string s, ref int i) { var list = new List(); i++; // [ SkipWhitespace(s, ref i); if (i < s.Length && s[i] == ']') { i++; return list; } while (true) { list.Add(ReadValue(s, ref i)); SkipWhitespace(s, ref i); if (i >= s.Length) throw new FormatException("Unexpected end of JSON"); if (s[i] == ',') { i++; continue; } if (s[i] == ']') { i++; return list; } throw new FormatException("Expected ',' or ']' at " + i); } } static string ReadString(string s, ref int i) { var sb = new StringBuilder(); i++; // " while (i < s.Length) { char c = s[i++]; if (c == '"') return sb.ToString(); if (c != '\\') { sb.Append(c); continue; } if (i >= s.Length) break; char e = s[i++]; switch (e) { case 'b': sb.Append('\b'); break; case 'f': sb.Append('\f'); break; case 'n': sb.Append('\n'); break; case 'r': sb.Append('\r'); break; case 't': sb.Append('\t'); break; case 'u': if (i + 4 > s.Length) throw new FormatException("Bad \\u escape"); sb.Append((char)int.Parse(s.Substring(i, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture)); i += 4; break; default: sb.Append(e); break; // \" \\ \/ } } throw new FormatException("Unterminated string"); } static double ReadNumber(string s, ref int i) { int start = i; while (i < s.Length && "+-0123456789.eE".IndexOf(s[i]) >= 0) i++; return double.Parse(s.Substring(start, i - start), NumberStyles.Float, CultureInfo.InvariantCulture); } static bool Word(string s, ref int i, string word) { if (string.CompareOrdinal(s, i, word, 0, word.Length) != 0) return false; i += word.Length; return true; } static void SkipWhitespace(string s, ref int i) { while (i < s.Length && char.IsWhiteSpace(s[i])) i++; } } }