A game about forced loneliness, made by TACStudios
1/* * * * *
2 * A simple JSON Parser / builder
3 * ------------------------------
4 *
5 * It mainly has been written as a simple JSON parser. It can build a JSON string
6 * from the node-tree, or generate a node tree from any valid JSON string.
7 *
8 * Written by Bunny83
9 * 2012-06-09
10 *
11 * Changelog now external. See Changelog.txt
12 *
13 * The MIT License (MIT)
14 *
15 * Copyright (c) 2012-2022 Markus Göbel (Bunny83)
16 *
17 * Permission is hereby granted, free of charge, to any person obtaining a copy
18 * of this software and associated documentation files (the "Software"), to deal
19 * in the Software without restriction, including without limitation the rights
20 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21 * copies of the Software, and to permit persons to whom the Software is
22 * furnished to do so, subject to the following conditions:
23 *
24 * The above copyright notice and this permission notice shall be included in all
25 * copies or substantial portions of the Software.
26 *
27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 * SOFTWARE.
34 *
35 * * * * */
36using System;
37using System.Collections;
38using System.Collections.Generic;
39using System.Globalization;
40using System.Linq;
41using System.Text;
42
43namespace SimpleJSON
44{
45 internal enum JSONNodeType
46 {
47 Array = 1,
48 Object = 2,
49 String = 3,
50 Number = 4,
51 NullValue = 5,
52 Boolean = 6,
53 None = 7,
54 Custom = 0xFF,
55 }
56 internal enum JSONTextMode
57 {
58 Compact,
59 Indent
60 }
61
62 internal abstract partial class JSONNode
63 {
64 #region Enumerators
65 internal struct Enumerator
66 {
67 private enum Type { None, Array, Object }
68 private Type type;
69 private Dictionary<string, JSONNode>.Enumerator m_Object;
70 private List<JSONNode>.Enumerator m_Array;
71 public bool IsValid { get { return type != Type.None; } }
72 public Enumerator(List<JSONNode>.Enumerator aArrayEnum)
73 {
74 type = Type.Array;
75 m_Object = default(Dictionary<string, JSONNode>.Enumerator);
76 m_Array = aArrayEnum;
77 }
78 public Enumerator(Dictionary<string, JSONNode>.Enumerator aDictEnum)
79 {
80 type = Type.Object;
81 m_Object = aDictEnum;
82 m_Array = default(List<JSONNode>.Enumerator);
83 }
84 public KeyValuePair<string, JSONNode> Current
85 {
86 get
87 {
88 if (type == Type.Array)
89 return new KeyValuePair<string, JSONNode>(string.Empty, m_Array.Current);
90 else if (type == Type.Object)
91 return m_Object.Current;
92 return new KeyValuePair<string, JSONNode>(string.Empty, null);
93 }
94 }
95 public bool MoveNext()
96 {
97 if (type == Type.Array)
98 return m_Array.MoveNext();
99 else if (type == Type.Object)
100 return m_Object.MoveNext();
101 return false;
102 }
103 }
104 internal struct ValueEnumerator
105 {
106 private Enumerator m_Enumerator;
107 public ValueEnumerator(List<JSONNode>.Enumerator aArrayEnum) : this(new Enumerator(aArrayEnum)) { }
108 public ValueEnumerator(Dictionary<string, JSONNode>.Enumerator aDictEnum) : this(new Enumerator(aDictEnum)) { }
109 public ValueEnumerator(Enumerator aEnumerator) { m_Enumerator = aEnumerator; }
110 public JSONNode Current { get { return m_Enumerator.Current.Value; } }
111 public bool MoveNext() { return m_Enumerator.MoveNext(); }
112 public ValueEnumerator GetEnumerator() { return this; }
113 }
114 internal struct KeyEnumerator
115 {
116 private Enumerator m_Enumerator;
117 public KeyEnumerator(List<JSONNode>.Enumerator aArrayEnum) : this(new Enumerator(aArrayEnum)) { }
118 public KeyEnumerator(Dictionary<string, JSONNode>.Enumerator aDictEnum) : this(new Enumerator(aDictEnum)) { }
119 public KeyEnumerator(Enumerator aEnumerator) { m_Enumerator = aEnumerator; }
120 public string Current { get { return m_Enumerator.Current.Key; } }
121 public bool MoveNext() { return m_Enumerator.MoveNext(); }
122 public KeyEnumerator GetEnumerator() { return this; }
123 }
124
125 internal class LinqEnumerator : IEnumerator<KeyValuePair<string, JSONNode>>, IEnumerable<KeyValuePair<string, JSONNode>>
126 {
127 private JSONNode m_Node;
128 private Enumerator m_Enumerator;
129 internal LinqEnumerator(JSONNode aNode)
130 {
131 m_Node = aNode;
132 if (m_Node != null)
133 m_Enumerator = m_Node.GetEnumerator();
134 }
135 public KeyValuePair<string, JSONNode> Current { get { return m_Enumerator.Current; } }
136 object IEnumerator.Current { get { return m_Enumerator.Current; } }
137 public bool MoveNext() { return m_Enumerator.MoveNext(); }
138
139 public void Dispose()
140 {
141 m_Node = null;
142 m_Enumerator = new Enumerator();
143 }
144
145 public IEnumerator<KeyValuePair<string, JSONNode>> GetEnumerator()
146 {
147 return new LinqEnumerator(m_Node);
148 }
149
150 public void Reset()
151 {
152 if (m_Node != null)
153 m_Enumerator = m_Node.GetEnumerator();
154 }
155
156 IEnumerator IEnumerable.GetEnumerator()
157 {
158 return new LinqEnumerator(m_Node);
159 }
160 }
161
162 #endregion Enumerators
163
164 #region common interface
165
166 public static bool forceASCII = false; // Use Unicode by default
167 public static bool longAsString = false; // lazy creator creates a JSONString instead of JSONNumber
168 public static bool allowLineComments = true; // allow "//"-style comments at the end of a line
169
170 public abstract JSONNodeType Tag { get; }
171
172 public virtual JSONNode this[int aIndex] { get { return null; } set { } }
173
174 public virtual JSONNode this[string aKey] { get { return null; } set { } }
175
176 public virtual string Value { get { return ""; } set { } }
177
178 public virtual int Count { get { return 0; } }
179
180 public virtual bool IsNumber { get { return false; } }
181 public virtual bool IsString { get { return false; } }
182 public virtual bool IsBoolean { get { return false; } }
183 public virtual bool IsNull { get { return false; } }
184 public virtual bool IsArray { get { return false; } }
185 public virtual bool IsObject { get { return false; } }
186
187 public virtual bool Inline { get { return false; } set { } }
188
189 public virtual void Add(string aKey, JSONNode aItem)
190 {
191 }
192 public virtual void Add(JSONNode aItem)
193 {
194 Add("", aItem);
195 }
196
197 public virtual JSONNode Remove(string aKey)
198 {
199 return null;
200 }
201
202 public virtual JSONNode Remove(int aIndex)
203 {
204 return null;
205 }
206
207 public virtual JSONNode Remove(JSONNode aNode)
208 {
209 return aNode;
210 }
211 public virtual void Clear() { }
212
213 public virtual JSONNode Clone()
214 {
215 return null;
216 }
217
218 public virtual IEnumerable<JSONNode> Children
219 {
220 get
221 {
222 yield break;
223 }
224 }
225
226 public IEnumerable<JSONNode> DeepChildren
227 {
228 get
229 {
230 foreach (var C in Children)
231 foreach (var D in C.DeepChildren)
232 yield return D;
233 }
234 }
235
236 public virtual bool HasKey(string aKey)
237 {
238 return false;
239 }
240
241 public virtual JSONNode GetValueOrDefault(string aKey, JSONNode aDefault)
242 {
243 return aDefault;
244 }
245
246 public override string ToString()
247 {
248 StringBuilder sb = new StringBuilder();
249 WriteToStringBuilder(sb, 0, 0, JSONTextMode.Compact);
250 return sb.ToString();
251 }
252
253 public virtual string ToString(int aIndent)
254 {
255 StringBuilder sb = new StringBuilder();
256 WriteToStringBuilder(sb, 0, aIndent, JSONTextMode.Indent);
257 return sb.ToString();
258 }
259 internal abstract void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode);
260
261 public abstract Enumerator GetEnumerator();
262 public IEnumerable<KeyValuePair<string, JSONNode>> Linq { get { return new LinqEnumerator(this); } }
263 public KeyEnumerator Keys { get { return new KeyEnumerator(GetEnumerator()); } }
264 public ValueEnumerator Values { get { return new ValueEnumerator(GetEnumerator()); } }
265
266 #endregion common interface
267
268 #region typecasting properties
269
270
271 public virtual double AsDouble
272 {
273 get
274 {
275 double v = 0.0;
276 if (double.TryParse(Value, NumberStyles.Float, CultureInfo.InvariantCulture, out v))
277 return v;
278 return 0.0;
279 }
280 set
281 {
282 Value = value.ToString(CultureInfo.InvariantCulture);
283 }
284 }
285
286 public virtual int AsInt
287 {
288 get { return (int)AsDouble; }
289 set { AsDouble = value; }
290 }
291
292 public virtual float AsFloat
293 {
294 get { return (float)AsDouble; }
295 set { AsDouble = value; }
296 }
297
298 public virtual bool AsBool
299 {
300 get
301 {
302 bool v = false;
303 if (bool.TryParse(Value, out v))
304 return v;
305 return !string.IsNullOrEmpty(Value);
306 }
307 set
308 {
309 Value = (value) ? "true" : "false";
310 }
311 }
312
313 public virtual long AsLong
314 {
315 get
316 {
317 long val = 0;
318 if (long.TryParse(Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out val))
319 return val;
320 return 0L;
321 }
322 set
323 {
324 Value = value.ToString(CultureInfo.InvariantCulture);
325 }
326 }
327
328 public virtual ulong AsULong
329 {
330 get
331 {
332 ulong val = 0;
333 if (ulong.TryParse(Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out val))
334 return val;
335 return 0;
336 }
337 set
338 {
339 Value = value.ToString(CultureInfo.InvariantCulture);
340 }
341 }
342
343 public virtual JSONArray AsArray
344 {
345 get
346 {
347 return this as JSONArray;
348 }
349 }
350
351 public virtual JSONObject AsObject
352 {
353 get
354 {
355 return this as JSONObject;
356 }
357 }
358
359
360 #endregion typecasting properties
361
362 #region operators
363
364 public static implicit operator JSONNode(string s)
365 {
366 return (s == null) ? (JSONNode)JSONNull.CreateOrGet() : new JSONString(s);
367 }
368 public static implicit operator string(JSONNode d)
369 {
370 return (d == null) ? null : d.Value;
371 }
372
373 public static implicit operator JSONNode(double n)
374 {
375 return new JSONNumber(n);
376 }
377 public static implicit operator double(JSONNode d)
378 {
379 return (d == null) ? 0 : d.AsDouble;
380 }
381
382 public static implicit operator JSONNode(float n)
383 {
384 return new JSONNumber(n);
385 }
386 public static implicit operator float(JSONNode d)
387 {
388 return (d == null) ? 0 : d.AsFloat;
389 }
390
391 public static implicit operator JSONNode(int n)
392 {
393 return new JSONNumber(n);
394 }
395 public static implicit operator int(JSONNode d)
396 {
397 return (d == null) ? 0 : d.AsInt;
398 }
399
400 public static implicit operator JSONNode(long n)
401 {
402 if (longAsString)
403 return new JSONString(n.ToString(CultureInfo.InvariantCulture));
404 return new JSONNumber(n);
405 }
406 public static implicit operator long(JSONNode d)
407 {
408 return (d == null) ? 0L : d.AsLong;
409 }
410
411 public static implicit operator JSONNode(ulong n)
412 {
413 if (longAsString)
414 return new JSONString(n.ToString(CultureInfo.InvariantCulture));
415 return new JSONNumber(n);
416 }
417 public static implicit operator ulong(JSONNode d)
418 {
419 return (d == null) ? 0 : d.AsULong;
420 }
421
422 public static implicit operator JSONNode(bool b)
423 {
424 return new JSONBool(b);
425 }
426 public static implicit operator bool(JSONNode d)
427 {
428 return (d == null) ? false : d.AsBool;
429 }
430
431 public static implicit operator JSONNode(KeyValuePair<string, JSONNode> aKeyValue)
432 {
433 return aKeyValue.Value;
434 }
435
436 public static bool operator ==(JSONNode a, object b)
437 {
438 if (ReferenceEquals(a, b))
439 return true;
440 bool aIsNull = a is JSONNull || ReferenceEquals(a, null) || a is JSONLazyCreator;
441 bool bIsNull = b is JSONNull || ReferenceEquals(b, null) || b is JSONLazyCreator;
442 if (aIsNull && bIsNull)
443 return true;
444 return !aIsNull && a.Equals(b);
445 }
446
447 public static bool operator !=(JSONNode a, object b)
448 {
449 return !(a == b);
450 }
451
452 public override bool Equals(object obj)
453 {
454 return ReferenceEquals(this, obj);
455 }
456
457 public override int GetHashCode()
458 {
459 return base.GetHashCode();
460 }
461
462 #endregion operators
463
464 [ThreadStatic]
465 private static StringBuilder m_EscapeBuilder;
466 internal static StringBuilder EscapeBuilder
467 {
468 get
469 {
470 if (m_EscapeBuilder == null)
471 m_EscapeBuilder = new StringBuilder();
472 return m_EscapeBuilder;
473 }
474 }
475 internal static string Escape(string aText)
476 {
477 var sb = EscapeBuilder;
478 sb.Length = 0;
479 if (sb.Capacity < aText.Length + aText.Length / 10)
480 sb.Capacity = aText.Length + aText.Length / 10;
481 foreach (char c in aText)
482 {
483 switch (c)
484 {
485 case '\\':
486 sb.Append("\\\\");
487 break;
488 case '\"':
489 sb.Append("\\\"");
490 break;
491 case '\n':
492 sb.Append("\\n");
493 break;
494 case '\r':
495 sb.Append("\\r");
496 break;
497 case '\t':
498 sb.Append("\\t");
499 break;
500 case '\b':
501 sb.Append("\\b");
502 break;
503 case '\f':
504 sb.Append("\\f");
505 break;
506 default:
507 if (c < ' ' || (forceASCII && c > 127))
508 {
509 ushort val = c;
510 sb.Append("\\u").Append(val.ToString("X4"));
511 }
512 else
513 sb.Append(c);
514 break;
515 }
516 }
517 string result = sb.ToString();
518 sb.Length = 0;
519 return result;
520 }
521
522 private static JSONNode ParseElement(string token, bool quoted)
523 {
524 if (quoted)
525 return token;
526 if (token.Length <= 5)
527 {
528 string tmp = token.ToLower();
529 if (tmp == "false" || tmp == "true")
530 return tmp == "true";
531 if (tmp == "null")
532 return JSONNull.CreateOrGet();
533 }
534 double val;
535 if (double.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out val))
536 return val;
537 else
538 return token;
539 }
540
541 public static JSONNode Parse(string aJSON)
542 {
543 Stack<JSONNode> stack = new Stack<JSONNode>();
544 JSONNode ctx = null;
545 int i = 0;
546 StringBuilder Token = new StringBuilder();
547 string TokenName = "";
548 bool QuoteMode = false;
549 bool TokenIsQuoted = false;
550 bool HasNewlineChar = false;
551 while (i < aJSON.Length)
552 {
553 switch (aJSON[i])
554 {
555 case '{':
556 if (QuoteMode)
557 {
558 Token.Append(aJSON[i]);
559 break;
560 }
561 stack.Push(new JSONObject());
562 if (ctx != null)
563 {
564 ctx.Add(TokenName, stack.Peek());
565 }
566 TokenName = "";
567 Token.Length = 0;
568 ctx = stack.Peek();
569 HasNewlineChar = false;
570 break;
571
572 case '[':
573 if (QuoteMode)
574 {
575 Token.Append(aJSON[i]);
576 break;
577 }
578
579 stack.Push(new JSONArray());
580 if (ctx != null)
581 {
582 ctx.Add(TokenName, stack.Peek());
583 }
584 TokenName = "";
585 Token.Length = 0;
586 ctx = stack.Peek();
587 HasNewlineChar = false;
588 break;
589
590 case '}':
591 case ']':
592 if (QuoteMode)
593 {
594
595 Token.Append(aJSON[i]);
596 break;
597 }
598 if (stack.Count == 0)
599 throw new Exception("JSON Parse: Too many closing brackets");
600
601 stack.Pop();
602 if (Token.Length > 0 || TokenIsQuoted)
603 ctx.Add(TokenName, ParseElement(Token.ToString(), TokenIsQuoted));
604 if (ctx != null)
605 ctx.Inline = !HasNewlineChar;
606 TokenIsQuoted = false;
607 TokenName = "";
608 Token.Length = 0;
609 if (stack.Count > 0)
610 ctx = stack.Peek();
611 break;
612
613 case ':':
614 if (QuoteMode)
615 {
616 Token.Append(aJSON[i]);
617 break;
618 }
619 TokenName = Token.ToString();
620 Token.Length = 0;
621 TokenIsQuoted = false;
622 break;
623
624 case '"':
625 QuoteMode ^= true;
626 TokenIsQuoted |= QuoteMode;
627 break;
628
629 case ',':
630 if (QuoteMode)
631 {
632 Token.Append(aJSON[i]);
633 break;
634 }
635 if (Token.Length > 0 || TokenIsQuoted)
636 ctx.Add(TokenName, ParseElement(Token.ToString(), TokenIsQuoted));
637 TokenIsQuoted = false;
638 TokenName = "";
639 Token.Length = 0;
640 TokenIsQuoted = false;
641 break;
642
643 case '\r':
644 case '\n':
645 HasNewlineChar = true;
646 break;
647
648 case ' ':
649 case '\t':
650 if (QuoteMode)
651 Token.Append(aJSON[i]);
652 break;
653
654 case '\\':
655 ++i;
656 if (QuoteMode)
657 {
658 char C = aJSON[i];
659 switch (C)
660 {
661 case 't':
662 Token.Append('\t');
663 break;
664 case 'r':
665 Token.Append('\r');
666 break;
667 case 'n':
668 Token.Append('\n');
669 break;
670 case 'b':
671 Token.Append('\b');
672 break;
673 case 'f':
674 Token.Append('\f');
675 break;
676 case 'u':
677 {
678 string s = aJSON.Substring(i + 1, 4);
679 Token.Append((char)int.Parse(
680 s,
681 System.Globalization.NumberStyles.AllowHexSpecifier));
682 i += 4;
683 break;
684 }
685 default:
686 Token.Append(C);
687 break;
688 }
689 }
690 break;
691 case '/':
692 if (allowLineComments && !QuoteMode && i + 1 < aJSON.Length && aJSON[i + 1] == '/')
693 {
694 while (++i < aJSON.Length && aJSON[i] != '\n' && aJSON[i] != '\r') ;
695 break;
696 }
697 Token.Append(aJSON[i]);
698 break;
699 case '\uFEFF': // remove / ignore BOM (Byte Order Mark)
700 break;
701
702 default:
703 Token.Append(aJSON[i]);
704 break;
705 }
706 ++i;
707 }
708 if (QuoteMode)
709 {
710 throw new Exception("JSON Parse: Quotation marks seems to be messed up.");
711 }
712 if (ctx == null)
713 return ParseElement(Token.ToString(), TokenIsQuoted);
714 return ctx;
715 }
716
717 }
718 // End of JSONNode
719
720 internal partial class JSONArray : JSONNode
721 {
722 private List<JSONNode> m_List = new List<JSONNode>();
723 private bool inline = false;
724 public override bool Inline
725 {
726 get { return inline; }
727 set { inline = value; }
728 }
729
730 public override JSONNodeType Tag { get { return JSONNodeType.Array; } }
731 public override bool IsArray { get { return true; } }
732 public override Enumerator GetEnumerator() { return new Enumerator(m_List.GetEnumerator()); }
733
734 public override JSONNode this[int aIndex]
735 {
736 get
737 {
738 if (aIndex < 0 || aIndex >= m_List.Count)
739 return new JSONLazyCreator(this);
740 return m_List[aIndex];
741 }
742 set
743 {
744 if (value == null)
745 value = JSONNull.CreateOrGet();
746 if (aIndex < 0 || aIndex >= m_List.Count)
747 m_List.Add(value);
748 else
749 m_List[aIndex] = value;
750 }
751 }
752
753 public override JSONNode this[string aKey]
754 {
755 get { return new JSONLazyCreator(this); }
756 set
757 {
758 if (value == null)
759 value = JSONNull.CreateOrGet();
760 m_List.Add(value);
761 }
762 }
763
764 public override int Count
765 {
766 get { return m_List.Count; }
767 }
768
769 public override void Add(string aKey, JSONNode aItem)
770 {
771 if (aItem == null)
772 aItem = JSONNull.CreateOrGet();
773 m_List.Add(aItem);
774 }
775
776 public override JSONNode Remove(int aIndex)
777 {
778 if (aIndex < 0 || aIndex >= m_List.Count)
779 return null;
780 JSONNode tmp = m_List[aIndex];
781 m_List.RemoveAt(aIndex);
782 return tmp;
783 }
784
785 public override JSONNode Remove(JSONNode aNode)
786 {
787 m_List.Remove(aNode);
788 return aNode;
789 }
790
791 public override void Clear()
792 {
793 m_List.Clear();
794 }
795
796 public override JSONNode Clone()
797 {
798 var node = new JSONArray();
799 node.m_List.Capacity = m_List.Capacity;
800 foreach (var n in m_List)
801 {
802 if (n != null)
803 node.Add(n.Clone());
804 else
805 node.Add(null);
806 }
807 return node;
808 }
809
810 public override IEnumerable<JSONNode> Children
811 {
812 get
813 {
814 foreach (JSONNode N in m_List)
815 yield return N;
816 }
817 }
818
819
820 internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
821 {
822 aSB.Append('[');
823 int count = m_List.Count;
824 if (inline)
825 aMode = JSONTextMode.Compact;
826 for (int i = 0; i < count; i++)
827 {
828 if (i > 0)
829 aSB.Append(',');
830 if (aMode == JSONTextMode.Indent)
831 aSB.AppendLine();
832
833 if (aMode == JSONTextMode.Indent)
834 aSB.Append(' ', aIndent + aIndentInc);
835 m_List[i].WriteToStringBuilder(aSB, aIndent + aIndentInc, aIndentInc, aMode);
836 }
837 if (aMode == JSONTextMode.Indent)
838 aSB.AppendLine().Append(' ', aIndent);
839 aSB.Append(']');
840 }
841 }
842 // End of JSONArray
843
844 internal partial class JSONObject : JSONNode
845 {
846 private Dictionary<string, JSONNode> m_Dict = new Dictionary<string, JSONNode>();
847
848 private bool inline = false;
849 public override bool Inline
850 {
851 get { return inline; }
852 set { inline = value; }
853 }
854
855 public override JSONNodeType Tag { get { return JSONNodeType.Object; } }
856 public override bool IsObject { get { return true; } }
857
858 public override Enumerator GetEnumerator() { return new Enumerator(m_Dict.GetEnumerator()); }
859
860
861 public override JSONNode this[string aKey]
862 {
863 get
864 {
865 if (m_Dict.ContainsKey(aKey))
866 return m_Dict[aKey];
867 else
868 return new JSONLazyCreator(this, aKey);
869 }
870 set
871 {
872 if (value == null)
873 value = JSONNull.CreateOrGet();
874 if (m_Dict.ContainsKey(aKey))
875 m_Dict[aKey] = value;
876 else
877 m_Dict.Add(aKey, value);
878 }
879 }
880
881 public override JSONNode this[int aIndex]
882 {
883 get
884 {
885 if (aIndex < 0 || aIndex >= m_Dict.Count)
886 return null;
887 return m_Dict.ElementAt(aIndex).Value;
888 }
889 set
890 {
891 if (value == null)
892 value = JSONNull.CreateOrGet();
893 if (aIndex < 0 || aIndex >= m_Dict.Count)
894 return;
895 string key = m_Dict.ElementAt(aIndex).Key;
896 m_Dict[key] = value;
897 }
898 }
899
900 public override int Count
901 {
902 get { return m_Dict.Count; }
903 }
904
905 public override void Add(string aKey, JSONNode aItem)
906 {
907 if (aItem == null)
908 aItem = JSONNull.CreateOrGet();
909
910 if (aKey != null)
911 {
912 if (m_Dict.ContainsKey(aKey))
913 m_Dict[aKey] = aItem;
914 else
915 m_Dict.Add(aKey, aItem);
916 }
917 else
918 m_Dict.Add(Guid.NewGuid().ToString(), aItem);
919 }
920
921 public override JSONNode Remove(string aKey)
922 {
923 if (!m_Dict.ContainsKey(aKey))
924 return null;
925 JSONNode tmp = m_Dict[aKey];
926 m_Dict.Remove(aKey);
927 return tmp;
928 }
929
930 public override JSONNode Remove(int aIndex)
931 {
932 if (aIndex < 0 || aIndex >= m_Dict.Count)
933 return null;
934 var item = m_Dict.ElementAt(aIndex);
935 m_Dict.Remove(item.Key);
936 return item.Value;
937 }
938
939 public override JSONNode Remove(JSONNode aNode)
940 {
941 try
942 {
943 var item = m_Dict.Where(k => k.Value == aNode).First();
944 m_Dict.Remove(item.Key);
945 return aNode;
946 }
947 catch
948 {
949 return null;
950 }
951 }
952
953 public override void Clear()
954 {
955 m_Dict.Clear();
956 }
957
958 public override JSONNode Clone()
959 {
960 var node = new JSONObject();
961 foreach (var n in m_Dict)
962 {
963 node.Add(n.Key, n.Value.Clone());
964 }
965 return node;
966 }
967
968 public override bool HasKey(string aKey)
969 {
970 return m_Dict.ContainsKey(aKey);
971 }
972
973 public override JSONNode GetValueOrDefault(string aKey, JSONNode aDefault)
974 {
975 JSONNode res;
976 if (m_Dict.TryGetValue(aKey, out res))
977 return res;
978 return aDefault;
979 }
980
981 public override IEnumerable<JSONNode> Children
982 {
983 get
984 {
985 foreach (KeyValuePair<string, JSONNode> N in m_Dict)
986 yield return N.Value;
987 }
988 }
989
990 internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
991 {
992 aSB.Append('{');
993 bool first = true;
994 if (inline)
995 aMode = JSONTextMode.Compact;
996 foreach (var k in m_Dict)
997 {
998 if (!first)
999 aSB.Append(',');
1000 first = false;
1001 if (aMode == JSONTextMode.Indent)
1002 aSB.AppendLine();
1003 if (aMode == JSONTextMode.Indent)
1004 aSB.Append(' ', aIndent + aIndentInc);
1005 aSB.Append('\"').Append(Escape(k.Key)).Append('\"');
1006 if (aMode == JSONTextMode.Compact)
1007 aSB.Append(':');
1008 else
1009 aSB.Append(": ");
1010 k.Value.WriteToStringBuilder(aSB, aIndent + aIndentInc, aIndentInc, aMode);
1011 }
1012 if (aMode == JSONTextMode.Indent)
1013 aSB.AppendLine().Append(' ', aIndent);
1014 aSB.Append('}');
1015 }
1016
1017 }
1018 // End of JSONObject
1019
1020 internal partial class JSONString : JSONNode
1021 {
1022 private string m_Data;
1023
1024 public override JSONNodeType Tag { get { return JSONNodeType.String; } }
1025 public override bool IsString { get { return true; } }
1026
1027 public override Enumerator GetEnumerator() { return new Enumerator(); }
1028
1029
1030 public override string Value
1031 {
1032 get { return m_Data; }
1033 set
1034 {
1035 m_Data = value;
1036 }
1037 }
1038
1039 public JSONString(string aData)
1040 {
1041 m_Data = aData;
1042 }
1043 public override JSONNode Clone()
1044 {
1045 return new JSONString(m_Data);
1046 }
1047
1048 internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
1049 {
1050 aSB.Append('\"').Append(Escape(m_Data)).Append('\"');
1051 }
1052 public override bool Equals(object obj)
1053 {
1054 if (base.Equals(obj))
1055 return true;
1056 string s = obj as string;
1057 if (s != null)
1058 return m_Data == s;
1059 JSONString s2 = obj as JSONString;
1060 if (s2 != null)
1061 return m_Data == s2.m_Data;
1062 return false;
1063 }
1064 public override int GetHashCode()
1065 {
1066 return m_Data.GetHashCode();
1067 }
1068 public override void Clear()
1069 {
1070 m_Data = "";
1071 }
1072 }
1073 // End of JSONString
1074
1075 internal partial class JSONNumber : JSONNode
1076 {
1077 private double m_Data;
1078
1079 public override JSONNodeType Tag { get { return JSONNodeType.Number; } }
1080 public override bool IsNumber { get { return true; } }
1081 public override Enumerator GetEnumerator() { return new Enumerator(); }
1082
1083 public override string Value
1084 {
1085 get { return m_Data.ToString(CultureInfo.InvariantCulture); }
1086 set
1087 {
1088 double v;
1089 if (double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out v))
1090 m_Data = v;
1091 }
1092 }
1093
1094 public override double AsDouble
1095 {
1096 get { return m_Data; }
1097 set { m_Data = value; }
1098 }
1099 public override long AsLong
1100 {
1101 get { return (long)m_Data; }
1102 set { m_Data = value; }
1103 }
1104 public override ulong AsULong
1105 {
1106 get { return (ulong)m_Data; }
1107 set { m_Data = value; }
1108 }
1109
1110 public JSONNumber(double aData)
1111 {
1112 m_Data = aData;
1113 }
1114
1115 public JSONNumber(string aData)
1116 {
1117 Value = aData;
1118 }
1119
1120 public override JSONNode Clone()
1121 {
1122 return new JSONNumber(m_Data);
1123 }
1124
1125 internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
1126 {
1127 aSB.Append(Value.ToString(CultureInfo.InvariantCulture));
1128 }
1129 private static bool IsNumeric(object value)
1130 {
1131 return value is int || value is uint
1132 || value is float || value is double
1133 || value is decimal
1134 || value is long || value is ulong
1135 || value is short || value is ushort
1136 || value is sbyte || value is byte;
1137 }
1138 public override bool Equals(object obj)
1139 {
1140 if (obj == null)
1141 return false;
1142 if (base.Equals(obj))
1143 return true;
1144 JSONNumber s2 = obj as JSONNumber;
1145 if (s2 != null)
1146 return m_Data == s2.m_Data;
1147 if (IsNumeric(obj))
1148 return Convert.ToDouble(obj) == m_Data;
1149 return false;
1150 }
1151 public override int GetHashCode()
1152 {
1153 return m_Data.GetHashCode();
1154 }
1155 public override void Clear()
1156 {
1157 m_Data = 0;
1158 }
1159 }
1160 // End of JSONNumber
1161
1162 internal partial class JSONBool : JSONNode
1163 {
1164 private bool m_Data;
1165
1166 public override JSONNodeType Tag { get { return JSONNodeType.Boolean; } }
1167 public override bool IsBoolean { get { return true; } }
1168 public override Enumerator GetEnumerator() { return new Enumerator(); }
1169
1170 public override string Value
1171 {
1172 get { return m_Data.ToString(); }
1173 set
1174 {
1175 bool v;
1176 if (bool.TryParse(value, out v))
1177 m_Data = v;
1178 }
1179 }
1180 public override bool AsBool
1181 {
1182 get { return m_Data; }
1183 set { m_Data = value; }
1184 }
1185
1186 public JSONBool(bool aData)
1187 {
1188 m_Data = aData;
1189 }
1190
1191 public JSONBool(string aData)
1192 {
1193 Value = aData;
1194 }
1195
1196 public override JSONNode Clone()
1197 {
1198 return new JSONBool(m_Data);
1199 }
1200
1201 internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
1202 {
1203 aSB.Append((m_Data) ? "true" : "false");
1204 }
1205 public override bool Equals(object obj)
1206 {
1207 if (obj == null)
1208 return false;
1209 if (obj is bool)
1210 return m_Data == (bool)obj;
1211 return false;
1212 }
1213 public override int GetHashCode()
1214 {
1215 return m_Data.GetHashCode();
1216 }
1217 public override void Clear()
1218 {
1219 m_Data = false;
1220 }
1221 }
1222 // End of JSONBool
1223
1224 internal partial class JSONNull : JSONNode
1225 {
1226 static JSONNull m_StaticInstance = new JSONNull();
1227 public static bool reuseSameInstance = true;
1228 public static JSONNull CreateOrGet()
1229 {
1230 if (reuseSameInstance)
1231 return m_StaticInstance;
1232 return new JSONNull();
1233 }
1234 private JSONNull() { }
1235
1236 public override JSONNodeType Tag { get { return JSONNodeType.NullValue; } }
1237 public override bool IsNull { get { return true; } }
1238 public override Enumerator GetEnumerator() { return new Enumerator(); }
1239
1240 public override string Value
1241 {
1242 get { return "null"; }
1243 set { }
1244 }
1245 public override bool AsBool
1246 {
1247 get { return false; }
1248 set { }
1249 }
1250
1251 public override JSONNode Clone()
1252 {
1253 return CreateOrGet();
1254 }
1255
1256 public override bool Equals(object obj)
1257 {
1258 if (object.ReferenceEquals(this, obj))
1259 return true;
1260 return (obj is JSONNull);
1261 }
1262 public override int GetHashCode()
1263 {
1264 return 0;
1265 }
1266
1267 internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
1268 {
1269 aSB.Append("null");
1270 }
1271 }
1272 // End of JSONNull
1273
1274 internal partial class JSONLazyCreator : JSONNode
1275 {
1276 private JSONNode m_Node = null;
1277 private string m_Key = null;
1278 public override JSONNodeType Tag { get { return JSONNodeType.None; } }
1279 public override Enumerator GetEnumerator() { return new Enumerator(); }
1280
1281 public JSONLazyCreator(JSONNode aNode)
1282 {
1283 m_Node = aNode;
1284 m_Key = null;
1285 }
1286
1287 public JSONLazyCreator(JSONNode aNode, string aKey)
1288 {
1289 m_Node = aNode;
1290 m_Key = aKey;
1291 }
1292
1293 private T Set<T>(T aVal) where T : JSONNode
1294 {
1295 if (m_Key == null)
1296 m_Node.Add(aVal);
1297 else
1298 m_Node.Add(m_Key, aVal);
1299 m_Node = null; // Be GC friendly.
1300 return aVal;
1301 }
1302
1303 public override JSONNode this[int aIndex]
1304 {
1305 get { return new JSONLazyCreator(this); }
1306 set { Set(new JSONArray()).Add(value); }
1307 }
1308
1309 public override JSONNode this[string aKey]
1310 {
1311 get { return new JSONLazyCreator(this, aKey); }
1312 set { Set(new JSONObject()).Add(aKey, value); }
1313 }
1314
1315 public override void Add(JSONNode aItem)
1316 {
1317 Set(new JSONArray()).Add(aItem);
1318 }
1319
1320 public override void Add(string aKey, JSONNode aItem)
1321 {
1322 Set(new JSONObject()).Add(aKey, aItem);
1323 }
1324
1325 public static bool operator ==(JSONLazyCreator a, object b)
1326 {
1327 if (b == null)
1328 return true;
1329 return System.Object.ReferenceEquals(a, b);
1330 }
1331
1332 public static bool operator !=(JSONLazyCreator a, object b)
1333 {
1334 return !(a == b);
1335 }
1336
1337 public override bool Equals(object obj)
1338 {
1339 if (obj == null)
1340 return true;
1341 return System.Object.ReferenceEquals(this, obj);
1342 }
1343
1344 public override int GetHashCode()
1345 {
1346 return 0;
1347 }
1348
1349 public override int AsInt
1350 {
1351 get { Set(new JSONNumber(0)); return 0; }
1352 set { Set(new JSONNumber(value)); }
1353 }
1354
1355 public override float AsFloat
1356 {
1357 get { Set(new JSONNumber(0.0f)); return 0.0f; }
1358 set { Set(new JSONNumber(value)); }
1359 }
1360
1361 public override double AsDouble
1362 {
1363 get { Set(new JSONNumber(0.0)); return 0.0; }
1364 set { Set(new JSONNumber(value)); }
1365 }
1366
1367 public override long AsLong
1368 {
1369 get
1370 {
1371 if (longAsString)
1372 Set(new JSONString("0"));
1373 else
1374 Set(new JSONNumber(0.0));
1375 return 0L;
1376 }
1377 set
1378 {
1379 if (longAsString)
1380 Set(new JSONString(value.ToString(CultureInfo.InvariantCulture)));
1381 else
1382 Set(new JSONNumber(value));
1383 }
1384 }
1385
1386 public override ulong AsULong
1387 {
1388 get
1389 {
1390 if (longAsString)
1391 Set(new JSONString("0"));
1392 else
1393 Set(new JSONNumber(0.0));
1394 return 0L;
1395 }
1396 set
1397 {
1398 if (longAsString)
1399 Set(new JSONString(value.ToString(CultureInfo.InvariantCulture)));
1400 else
1401 Set(new JSONNumber(value));
1402 }
1403 }
1404
1405 public override bool AsBool
1406 {
1407 get { Set(new JSONBool(false)); return false; }
1408 set { Set(new JSONBool(value)); }
1409 }
1410
1411 public override JSONArray AsArray
1412 {
1413 get { return Set(new JSONArray()); }
1414 }
1415
1416 public override JSONObject AsObject
1417 {
1418 get { return Set(new JSONObject()); }
1419 }
1420 internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
1421 {
1422 aSB.Append("null");
1423 }
1424 }
1425 // End of JSONLazyCreator
1426
1427 internal static class JSON
1428 {
1429 public static JSONNode Parse(string aJSON)
1430 {
1431 return JSONNode.Parse(aJSON);
1432 }
1433 }
1434}