//Original or reader part: https://github.com/MarcosLopezC/LightJson/ using KKdBaseLib; using BaseExtensions = KKdBaseLib.Extensions; namespace KKdMainLib.IO { public struct JSON : System.IDisposable { public JSON(Stream _IO) => this._IO = _IO; private Stream _IO; public void Close() => _IO.C(); public byte[] ToArray(bool Close = false) => _IO.ToArray(Close); public MsgPack Read() => ReadValue(); private MsgPack ReadValue(string Key = null) { char c = _IO.SW().PCUTF8(); object obj = null; if (char.IsDigit(c)) obj = RF(); else obj = c switch { '"' => RS (), '{' => RO (), '[' => RA (), '-' => RF (), 't' => RBo(), 'f' => RBo(), 'n' => RN (), _ => null , }; return new MsgPack(Key, obj); } private string RS() { if (!Extensions.As(_IO, '"')) return null; char c; string s = ""; while (true) { c = _IO.RCUTF8(); if (c == '\\') { c = _IO.RCUTF8(); switch (char.ToLower(c)) { case '"' : case '\\': case '/' : s += c; break; case 'b' : s += '\b'; break; case 'f' : s += '\f'; break; case 'n' : s += '\n'; break; case 'r' : s += '\r'; break; case 't' : s += '\t'; break; case 'u' : s += RUL(); break; default: return null; } } else if (c == '"') break; else if (char.IsControl(c)) return null; else s += c; } return s; } private char RUL() => (char)((((((RHD() << 4) | RHD()) << 4) | RHD()) << 4) | RHD()); private int RHD() => byte.Parse(_IO.RCUTF8().ToString(), System.Globalization.NumberStyles.HexNumber); private KKdList RO() { KKdList obj = KKdList.New; if (!Extensions.As(_IO, '{')) return KKdList.Null; if (_IO.SW().PCUTF8() == '}') { _IO.RCUTF8(); return KKdList.Null; } string key; char c; while (true) { _IO.SW(); key = RS(); if (!Extensions.As(_IO.SW(), ':')) return KKdList.Null; obj.Add(ReadValue(key)); c = _IO.SW().PCUTF8(); if (c == '}') { _IO.RCUTF8(); break; } else if (c == ',') { _IO.RCUTF8(); continue; } else return KKdList.Null; } obj.Capacity = obj.Count; return obj; } private MsgPack[] RA() { KKdList obj = KKdList.New; if (!Extensions.As(_IO, '[')) return null; if (_IO.SW().PCUTF8() == ']') { _IO.RCUTF8(); return obj.ToArray(); } char c; while (true) { obj.Add(ReadValue(null)); c = _IO.SW().PCUTF8(); if (c == ']') { _IO.RCUTF8(); break; } else if (c == ',') { _IO.RCUTF8(); continue; } else return null; } obj.Capacity = obj.Count; return obj.ToArray(); } private object RF() { string s = ""; _IO.SW(); bool negative = false; if (_IO.PCUTF8() == '-') { _IO.RCUTF8(); negative = true; } if (_IO.PCUTF8() == '0') s += _IO.RCUTF8(); else s += RD (); char c = _IO.PCUTF8(); if (c == '.') s += _IO.RCUTF8() + RD(); else if (negative && s == "0") return (float)-0.0f; else if (c != 'e' && c != 'E') { if (negative) s = "-" + s; long val; try { val = long.Parse(s); } catch { return ulong.Parse(s); } if (val >= 0x00000000 && val < 0x000000100) return ( byte)val; else if (val >= -0x00000080 && val < 0x000000080) return ( sbyte)val; else if (val >= -0x00008000 && val < 0x000008000) return ( short)val; else if (val >= 0x00000000 && val < 0x000010000) return (ushort)val; else if (val >= -0x80000000 && val < 0x000800000) return ( int)val; else if (val >= 0x00000000 && val < 0x100000000) return ( uint)val; else return val; } c = _IO.PCUTF8(); if (c == 'e' || c == 'E') { s += _IO.RCUTF8(); c = _IO.PCUTF8(); if (c == '+' || c == '-') s += _IO.RCUTF8(); s += RD(); } double d = s.ToF64(); if ((float)d == d) return negative ? (((float)d).ToU32() | 0x80000000).ToF32() : (float)d; else return negative ? (d.ToU64() | 0x8000000000000000).ToF64() : d; } private bool RBo() { char c = _IO.PCUTF8(); if (c == 't' && _IO.As( "true")) return true; else if (c == 'f' && _IO.As("false")) return false; return false; } private object RN() { _IO.As("null"); return null; } private string RD() { string s = ""; while (char.IsDigit(_IO.SW(). PCUTF8())) s += _IO.RCUTF8(); return s; } public JSON W(MsgPack msgPack, bool ignoreNull, string end = "\n", string tabChar = " ") => W(msgPack, ignoreNull, end, tabChar, "", true); public JSON W(MsgPack msgPack, bool ignoreNull, bool style = false) => W(msgPack, ignoreNull, "\n", " ", "", style); private JSON W(MsgPack msgPack, bool ignoreNull, string end, string tabChar, string tab, bool style, bool isArray = false) { string oldTab = tab; tab += tabChar; if (msgPack.Name != null && !isArray ) _IO.W("\"" + msgPack.Name + "\":" + (style ? " " : "")); if (msgPack.Object == null) { if (!ignoreNull) WN(); return this; } if (msgPack.List.NotNull) { WM(); if (style) _IO.W(end); if (msgPack.List.Count > 1) for (int i = 0; i < msgPack.List.Count; i++) { if (style) _IO.W(tab); W(msgPack.List[i], ignoreNull, end, tabChar, tab, style); if (i + 1 < msgPack.List.Count) _IO.W(','); if (style) _IO.W(end); } else if (msgPack.List.Count == 1) { if (style) _IO.W(tab); W(msgPack.List[0], ignoreNull, end, tabChar, tab, style); if (style) _IO.W(end); } if (style) _IO.W(oldTab); WM(true); } else if (msgPack.Array != null) { WA(); if (style) _IO.W(end); if (msgPack.Array.Length > 1) for (int i = 0; i < msgPack.Array.Length; i++) { if (style) _IO.W(tab); W(msgPack.Array[i], ignoreNull, end, tabChar, tab, style, true); if (i + 1 < msgPack.Array.Length) _IO.W(','); if (style) _IO.W(end); } else if (msgPack.Array.Length == 1) { if (style) _IO.W(tab); W(msgPack.Array[0], ignoreNull, end, tabChar, tab, style, true); if (style) _IO.W(end); } if (style) _IO.W(oldTab); WA(true); } else if (msgPack.Object is MsgPack msg) W(msg, ignoreNull, end, tabChar, tab, style); else if (msgPack.Object is string str) W(str); else _IO.W(BaseExtensions.ToS(msgPack.Object)); return this; } public void Dispose() => _IO.C(); private void W(string val) => _IO.W("\"" + val .Replace("\\", "\\\\").Replace("/" , "\\/").Replace("\"", "\\\"") .Replace("\0", "\\0" ).Replace("\b", "\\b").Replace("\f", "\\f" ) .Replace("\n", "\\n" ).Replace("\r", "\\r").Replace("\t", "\\t" ) + "\""); private void WN() => _IO.W("null"); private void WA(bool End = false) => _IO.W(End ? "]" : "["); private void WM(bool End = false) => _IO.W(End ? "}" : "{"); } }