Able
Askowl Base Library Enabler
Json.cs
1 // Copyright 2018 (C) paul@marrington.net http://www.askowl.net/unity-packages
2 
3 namespace Askowl {
4  using System;
5  using System.Text;
6 
7  /// <a href="http://bit.ly/2NX3NjD">Deserialisation from JSON format</a>
8  public class Json : IDisposable {
9  #region PublicInterface
10  /// <a href="http://bit.ly/2NX3NjD">Retrieve a Json instance used to load data into</a>
11  public static Json Instance => new Json();
12 
13  private Json() { }
14 
15  /// <a href="http://bit.ly/2Oo6eer">Parse text containing valid but unknown format JSON</a>
16  public Json Parse(string jsonText) {
17  tree = Trees.Instance;
18  json = jsonText;
19  idx = 0;
20 
21  if (!SkipWhiteSpace()) return this;
22 
23  if (json[idx] == '{') { ParseToNode(); } else { ParseOneEntryToNode(); }
24 
25  return this;
26  }
27 
28  /// <a href="http://bit.ly/2NX3NjD">Clear deserialized JSON tree</a> <inheritdoc />
29  public void Dispose() => tree.Dispose();
30 
31  /// <a href="http://bit.ly/2NX3NjD">Retrieve the current node in the parsed JSON tree</a>
32  public Trees Node => tree;
33  #endregion
34 
35  #region SupportData
36  private Trees tree;
37 
38  private string json = "";
39  private int idx;
40 
41  private readonly StringBuilder builder = new StringBuilder();
42  #endregion
43 
44  #region Parsing
45  private void ParseToNode() {
46  while (ParseOneEntryToNode()) {
47  if (!SkipWhiteSpace() || (json[idx] == '}')) {
48  idx++;
49  break;
50  }
51  }
52  }
53 
54  private bool ParseOneEntryToNode() {
55  if (!SkipWhiteSpace()) return false;
56 
57  string key = json[idx++] == '"' ? ParseString() : NextWord(-1);
58  if (json[idx] == ':') idx++;
59 
60  using (tree.Anchor()) {
61  tree.Add(key);
62  ParseObject();
63  }
64 
65  return idx < json.Length;
66  }
67 
68  private void ParseObject() {
69  if (!SkipWhiteSpace()) return;
70 
71  char token = json[idx++];
72 
73  switch (token) {
74  case '{':
75  ParseToNode();
76  return;
77  case '[':
78  ParseArray();
79  return;
80  case '"':
81  tree.Leaf = ParseString();
82  return;
83  default:
84  tree.Leaf = NextWord(-1);
85  break;
86  }
87 
88  SkipWhiteSpace();
89  }
90 
91  private void ParseArray() {
92  var index = 0;
93 
94  while (SkipWhiteSpace() && (json[idx] != ']')) {
95  using (tree.Anchor()) {
96  tree.Add(index++.ToString());
97  ParseObject();
98  }
99  }
100 
101  idx++; // skip ']'
102  }
103 
104  private string ParseString() {
105  builder.Clear();
106 
107  while ((idx < json.Length) && (json[idx] != '"')) builder.Append(json[idx] == '\\' ? Escape() : json[idx++]);
108 
109  idx++; // drop closing quote
110  SkipWhiteSpace();
111  return builder.ToString();
112  }
113 
114  private char Escape() {
115  switch (json[++idx]) {
116  case 'b': return '\b';
117  case 'f': return '\f';
118  case 'n': return '\n';
119  case 'r': return '\t';
120  case 't': return '\t';
121  default: return json[idx];
122  }
123  }
124 
125  private string NextWord(int offset = 0) {
126  int first = idx += offset;
127  while ((idx < json.Length) && ("{}[]\",:".IndexOf(json[idx]) == -1)) idx++;
128  string word = json.Substring(startIndex: first, length: idx - first);
129  SkipWhiteSpace();
130  return word.Trim();
131  }
132 
133  private static bool IsWhiteSpace(char chr) => char.IsWhiteSpace(chr) || (chr == ',');
134 
135  private bool SkipWhiteSpace() {
136  while ((idx < json.Length) && IsWhiteSpace(json[idx])) idx++;
137  return idx < json.Length;
138  }
139  #endregion
140  }
141 }
Definition: Clock.cs:3
static Json Instance
Retrieve a Json instance used to load data into
Definition: Json.cs:11
Deserialisation from JSON format
Definition: Json.cs:8
Trees Node
Retrieve the current node in the parsed JSON tree
Definition: Json.cs:32
Tree Container
Definition: Trees.cs:9
object Leaf
Definition: Trees.cs:141
Json Parse(string jsonText)
Parse text containing valid but unknown format JSON
Definition: Json.cs:16
static Trees Instance
Fetch a cached Trees instance
Definition: Trees.cs:109
IDisposable Anchor(string path="")
Mark here so wec an return to it
Definition: Trees.cs:206
void Dispose()
Clear deserialized JSON tree
Trees Add(string path)
Walk the path creating new segments as needed