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}