/* * Copyright (c) 2012-2016 Daniele Bartolini and individual contributors. * License: https://github.com/taylor001/crown/blob/master/LICENSE */ /* * Public Domain Niklas Frykholm */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; namespace Crown { /// /// Provides functions for encoding and decoding files in the simplified JSON format. /// public class SJSON { /// /// Encodes the Hashtable t in the simplified JSON format. The Hashtable can /// contain, numbers, bools, strings, ArrayLists and Hashtables. /// public static string Encode(Hashtable t) { StringBuilder builder = new StringBuilder(); WriteRootObject(t, builder); return builder.ToString(); } /// /// Encodes the object o in the simplified JSON format (not as a root object). /// /// public static string EncodeObject(object o) { StringBuilder builder = new StringBuilder(); Write(o, builder, 0); return builder.ToString(); } /// /// Decodes a SJSON bytestream into a Hashtable with numbers, bools, strings, /// ArrayLists and Hashtables. /// public static Hashtable Decode(byte[] sjson) { int index = 0; return ParseRootObject(sjson, ref index); } /// /// Convenience function for loading a file. /// public static Hashtable Load(string path) { System.IO.FileStream fs = System.IO.File.Open(path, System.IO.FileMode.Open, System.IO.FileAccess.Read); byte[] bytes = new byte[fs.Length]; fs.Read(bytes, 0, bytes.Length); fs.Close(); return Decode(bytes); } /// /// Convenience function for saving a file. /// public static void Save(Hashtable h, string path) { string s = Encode(h); System.IO.FileStream fs = System.IO.File.Open(path, System.IO.FileMode.Create); byte[] bytes = System.Text.Encoding.UTF8.GetBytes(s); fs.Write(bytes, 0, bytes.Count()); fs.Close(); } static void WriteRootObject(Hashtable t, StringBuilder builder) { WriteObjectFields(t, builder, 0); } static void WriteObjectFields(Hashtable t, StringBuilder builder, int indentation) { List keys = t.Keys.Cast().ToList(); keys.Sort(); foreach (string key in keys) { WriteNewLine(builder, indentation); builder.Append(key); builder.Append(" = "); Write(t[key], builder, indentation); } } static void WriteNewLine(StringBuilder builder, int indentation) { builder.Append('\n'); for (int i = 0; i < indentation; ++i) builder.Append('\t'); } static void Write(object o, StringBuilder builder, int indentation) { if (o == null) builder.Append("null"); else if (o is Boolean && (bool)o == false) builder.Append("false"); else if (o is Boolean) builder.Append("true"); else if (o is byte) builder.Append((byte)o); else if (o is int) builder.Append((int)o); else if (o is float) builder.Append((float)o); else if (o is double) builder.Append((double)o); else if (o is string) WriteString((String)o, builder); else if (o is ArrayList) WriteArray((ArrayList)o, builder, indentation); else if (o is Hashtable) WriteObject((Hashtable)o, builder, indentation); else throw new ArgumentException("Unknown object"); } static void WriteString(String s, StringBuilder builder) { builder.Append('"'); for (int i=0; i s = new List(); while (true) { byte c = json[index]; if (c == ' ' || c == '\t' || c == '\n' || c == '=') break; s.Add(c); ++index; } return new UTF8Encoding().GetString(s.ToArray()); } static void Consume(byte [] json, ref int index, String consume) { SkipWhitespace(json, ref index); for (int i=0; i= '0' && c <= '9') return ParseNumber(json, ref index); else if (c == 't') { Consume(json, ref index, "true"); return true; } else if (c == 'f') { Consume(json, ref index, "false"); return false; } else if (c == 'n') { Consume(json, ref index, "null"); return null; } else throw new FormatException(); } static byte Next(byte [] json, ref int index) { SkipWhitespace(json, ref index); return json[index]; } static Hashtable ParseObject(byte [] json, ref int index) { Hashtable ht = new Hashtable(); Consume(json, ref index, "{"); SkipWhitespace(json, ref index); while (Next(json, ref index) != '}') { String key = ParseIdentifier(json, ref index); Consume(json, ref index, "="); object value = ParseValue(json, ref index); ht[key] = value; } Consume(json, ref index, "}"); return ht; } static ArrayList ParseArray(byte [] json, ref int index) { ArrayList a = new ArrayList(); Consume(json, ref index, "["); while (Next(json, ref index) != ']') { object value = ParseValue(json, ref index); a.Add(value); } Consume(json, ref index, "]"); return a; } static String ParseString(byte[] json, ref int index) { List s = new List(); Consume(json, ref index, "\""); while (true) { byte c = json[index]; ++index; if (c == '"') break; else if (c != '\\') s.Add(c); else { byte q = json[index]; ++index; if (q == '"' || q == '\\' || q == '/') s.Add(q); else if (q == 'b') s.Add((byte)'\b'); else if (q == 'f') s.Add((byte)'\f'); else if (q == 'n') s.Add((byte)'\n'); else if (q == 'r') s.Add((byte)'\r'); else if (q == 't') s.Add((byte)'\t'); else if (q == 'u') { throw new FormatException(); } else { throw new FormatException(); } } } return new UTF8Encoding().GetString(s.ToArray()); } static Double ParseNumber(byte[] json, ref int index) { int end = index; while (end < json.Length && "0123456789+-.eE".IndexOf((char)json[end]) != -1) ++end; byte[] num = new byte[end - index]; Array.Copy(json, index, num, 0, num.Length); index = end; String numstr = new UTF8Encoding().GetString(num); return Double.Parse(numstr); } } }