You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1353 lines
44 KiB

  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. * If you want to use compression when saving to file / stream / B64 you have to include
  9. * SharpZipLib ( http://www.icsharpcode.net/opensource/sharpziplib/ ) in your project and
  10. * define "USE_SharpZipLib" at the top of the file
  11. *
  12. * Written by Bunny83
  13. * 2012-06-09
  14. *
  15. * [2012-06-09 First Version]
  16. * - provides strongly typed node classes and lists / dictionaries
  17. * - provides easy access to class members / array items / data values
  18. * - the parser now properly identifies types. So generating JSON with this framework should work.
  19. * - only double quotes (") are used for quoting strings.
  20. * - provides "casting" properties to easily convert to / from those types:
  21. * int / float / double / bool
  22. * - provides a common interface for each node so no explicit casting is required.
  23. * - the parser tries to avoid errors, but if malformed JSON is parsed the result is more or less undefined
  24. * - It can serialize/deserialize a node tree into/from an experimental compact binary format. It might
  25. * be handy if you want to store things in a file and don't want it to be easily modifiable
  26. *
  27. * [2012-12-17 Update]
  28. * - Added internal JSONLazyCreator class which simplifies the construction of a JSON tree
  29. * Now you can simple reference any item that doesn't exist yet and it will return a JSONLazyCreator
  30. * The class determines the required type by it's further use, creates the type and removes itself.
  31. * - Added binary serialization / deserialization.
  32. * - Added support for BZip2 zipped binary format. Requires the SharpZipLib ( http://www.icsharpcode.net/opensource/sharpziplib/ )
  33. * The usage of the SharpZipLib library can be disabled by removing or commenting out the USE_SharpZipLib define at the top
  34. * - The serializer uses different types when it comes to store the values. Since my data values
  35. * are all of type string, the serializer will "try" which format fits best. The order is: int, float, double, bool, string.
  36. * It's not the most efficient way but for a moderate amount of data it should work on all platforms.
  37. *
  38. * [2017-03-08 Update]
  39. * - Optimised parsing by using a StringBuilder for token. This prevents performance issues when large
  40. * string data fields are contained in the json data.
  41. * - Finally refactored the badly named JSONClass into JSONObject.
  42. * - Replaced the old JSONData class by distict typed classes ( JSONString, JSONNumber, JSONBool, JSONNull ) this
  43. * allows to propertly convert the node tree back to json without type information loss. The actual value
  44. * parsing now happens at parsing time and not when you actually access one of the casting properties.
  45. *
  46. * [2017-04-11 Update]
  47. * - Fixed parsing bug where empty string values have been ignored.
  48. * - Optimised "ToString" by using a StringBuilder internally. This should heavily improve performance for large files
  49. * - Changed the overload of "ToString(string aIndent)" to "ToString(int aIndent)"
  50. *
  51. * [2017-11-29 Update]
  52. * - Removed the IEnumerator implementations on JSONArray & JSONObject and replaced it with a common
  53. * struct Enumerator in JSONNode that should avoid garbage generation. The enumerator always works
  54. * on KeyValuePair<string, JSONNode>, even for JSONArray.
  55. * - Added two wrapper Enumerators that allows for easy key or value enumeration. A JSONNode now has
  56. * a "Keys" and a "Values" enumerable property. Those are also struct enumerators / enumerables
  57. * - A KeyValuePair<string, JSONNode> can now be implicitly converted into a JSONNode. This allows
  58. * a foreach loop over a JSONNode to directly access the values only. Since KeyValuePair as well as
  59. * all the Enumerators are structs, no garbage is allocated.
  60. * - To add Linq support another "LinqEnumerator" is available through the "Linq" property. This
  61. * enumerator does implement the generic IEnumerable interface so most Linq extensions can be used
  62. * on this enumerable object. This one does allocate memory as it's a wrapper class.
  63. * - The Escape method now escapes all control characters (# < 32) in strings as uncode characters
  64. * (\uXXXX) and if the static bool JSONNode.forceASCII is set to true it will also escape all
  65. * characters # > 127. This might be useful if you require an ASCII output. Though keep in mind
  66. * when your strings contain many non-ascii characters the strings become much longer (x6) and are
  67. * no longer human readable.
  68. * - The node types JSONObject and JSONArray now have an "Inline" boolean switch which will default to
  69. * false. It can be used to serialize this element inline even you serialize with an indented format
  70. * This is useful for arrays containing numbers so it doesn't place every number on a new line
  71. * - Extracted the binary serialization code into a seperate extension file. All classes are now declared
  72. * as "partial" so an extension file can even add a new virtual or abstract method / interface to
  73. * JSONNode and override it in the concrete type classes. It's of course a hacky approach which is
  74. * generally not recommended, but i wanted to keep everything tightly packed.
  75. * - Added a static CreateOrGet method to the JSONNull class. Since this class is immutable it could
  76. * be reused without major problems. If you have a lot null fields in your data it will help reduce
  77. * the memory / garbage overhead. I also added a static setting (reuseSameInstance) to JSONNull
  78. * (default is true) which will change the behaviour of "CreateOrGet". If you set this to false
  79. * CreateOrGet will not reuse the cached instance but instead create a new JSONNull instance each time.
  80. * I made the JSONNull constructor private so if you need to create an instance manually use
  81. * JSONNull.CreateOrGet()
  82. *
  83. * [2018-01-09 Update]
  84. * - Changed all double.TryParse and double.ToString uses to use the invariant culture to avoid problems
  85. * on systems with a culture that uses a comma as decimal point.
  86. *
  87. * [2018-01-26 Update]
  88. * - Added AsLong. Note that a JSONNumber is stored as double and can't represent all long values. However
  89. * storing it as string would work.
  90. * - Added static setting "JSONNode.longAsString" which controls the default type that is used by the
  91. * LazyCreator when using AsLong
  92. *
  93. * [2018-04-25 Update]
  94. * - Added support for parsing single values (JSONBool, JSONString, JSONNumber, JSONNull) as top level value.
  95. *
  96. * The MIT License (MIT)
  97. *
  98. * Copyright (c) 2012-2017 Markus Göbel (Bunny83)
  99. *
  100. * Permission is hereby granted, free of charge, to any person obtaining a copy
  101. * of this software and associated documentation files (the "Software"), to deal
  102. * in the Software without restriction, including without limitation the rights
  103. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  104. * copies of the Software, and to permit persons to whom the Software is
  105. * furnished to do so, subject to the following conditions:
  106. *
  107. * The above copyright notice and this permission notice shall be included in all
  108. * copies or substantial portions of the Software.
  109. *
  110. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  111. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  112. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  113. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  114. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  115. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  116. * SOFTWARE.
  117. *
  118. * * * * */
  119. using System;
  120. using System.Collections;
  121. using System.Collections.Generic;
  122. using System.Globalization;
  123. using System.Linq;
  124. using System.Text;
  125. namespace SimpleJSON
  126. {
  127. public enum JSONNodeType
  128. {
  129. Array = 1,
  130. Object = 2,
  131. String = 3,
  132. Number = 4,
  133. NullValue = 5,
  134. Boolean = 6,
  135. None = 7,
  136. Custom = 0xFF,
  137. }
  138. public enum JSONTextMode
  139. {
  140. Compact,
  141. Indent
  142. }
  143. public abstract partial class JSONNode
  144. {
  145. #region Enumerators
  146. public struct Enumerator
  147. {
  148. private enum Type { None, Array, Object }
  149. private Type type;
  150. private Dictionary<string, JSONNode>.Enumerator m_Object;
  151. private List<JSONNode>.Enumerator m_Array;
  152. public bool IsValid { get { return type != Type.None; } }
  153. public Enumerator(List<JSONNode>.Enumerator aArrayEnum)
  154. {
  155. type = Type.Array;
  156. m_Object = default(Dictionary<string, JSONNode>.Enumerator);
  157. m_Array = aArrayEnum;
  158. }
  159. public Enumerator(Dictionary<string, JSONNode>.Enumerator aDictEnum)
  160. {
  161. type = Type.Object;
  162. m_Object = aDictEnum;
  163. m_Array = default(List<JSONNode>.Enumerator);
  164. }
  165. public KeyValuePair<string, JSONNode> Current
  166. {
  167. get
  168. {
  169. if (type == Type.Array)
  170. return new KeyValuePair<string, JSONNode>(string.Empty, m_Array.Current);
  171. else if (type == Type.Object)
  172. return m_Object.Current;
  173. return new KeyValuePair<string, JSONNode>(string.Empty, null);
  174. }
  175. }
  176. public bool MoveNext()
  177. {
  178. if (type == Type.Array)
  179. return m_Array.MoveNext();
  180. else if (type == Type.Object)
  181. return m_Object.MoveNext();
  182. return false;
  183. }
  184. }
  185. public struct ValueEnumerator
  186. {
  187. private Enumerator m_Enumerator;
  188. public ValueEnumerator(List<JSONNode>.Enumerator aArrayEnum) : this(new Enumerator(aArrayEnum)) { }
  189. public ValueEnumerator(Dictionary<string, JSONNode>.Enumerator aDictEnum) : this(new Enumerator(aDictEnum)) { }
  190. public ValueEnumerator(Enumerator aEnumerator) { m_Enumerator = aEnumerator; }
  191. public JSONNode Current { get { return m_Enumerator.Current.Value; } }
  192. public bool MoveNext() { return m_Enumerator.MoveNext(); }
  193. public ValueEnumerator GetEnumerator() { return this; }
  194. }
  195. public struct KeyEnumerator
  196. {
  197. private Enumerator m_Enumerator;
  198. public KeyEnumerator(List<JSONNode>.Enumerator aArrayEnum) : this(new Enumerator(aArrayEnum)) { }
  199. public KeyEnumerator(Dictionary<string, JSONNode>.Enumerator aDictEnum) : this(new Enumerator(aDictEnum)) { }
  200. public KeyEnumerator(Enumerator aEnumerator) { m_Enumerator = aEnumerator; }
  201. public JSONNode Current { get { return m_Enumerator.Current.Key; } }
  202. public bool MoveNext() { return m_Enumerator.MoveNext(); }
  203. public KeyEnumerator GetEnumerator() { return this; }
  204. }
  205. public class LinqEnumerator : IEnumerator<KeyValuePair<string, JSONNode>>, IEnumerable<KeyValuePair<string, JSONNode>>
  206. {
  207. private JSONNode m_Node;
  208. private Enumerator m_Enumerator;
  209. internal LinqEnumerator(JSONNode aNode)
  210. {
  211. m_Node = aNode;
  212. if (m_Node != null)
  213. m_Enumerator = m_Node.GetEnumerator();
  214. }
  215. public KeyValuePair<string, JSONNode> Current { get { return m_Enumerator.Current; } }
  216. object IEnumerator.Current { get { return m_Enumerator.Current; } }
  217. public bool MoveNext() { return m_Enumerator.MoveNext(); }
  218. public void Dispose()
  219. {
  220. m_Node = null;
  221. m_Enumerator = new Enumerator();
  222. }
  223. public IEnumerator<KeyValuePair<string, JSONNode>> GetEnumerator()
  224. {
  225. return new LinqEnumerator(m_Node);
  226. }
  227. public void Reset()
  228. {
  229. if (m_Node != null)
  230. m_Enumerator = m_Node.GetEnumerator();
  231. }
  232. IEnumerator IEnumerable.GetEnumerator()
  233. {
  234. return new LinqEnumerator(m_Node);
  235. }
  236. }
  237. #endregion Enumerators
  238. #region common interface
  239. public static bool forceASCII = false; // Use Unicode by default
  240. public static bool longAsString = false; // lazy creator creates a JSONString instead of JSONNumber
  241. public abstract JSONNodeType Tag { get; }
  242. public virtual JSONNode this[int aIndex] { get { return null; } set { } }
  243. public virtual JSONNode this[string aKey] { get { return null; } set { } }
  244. public virtual string Value { get { return ""; } set { } }
  245. public virtual int Count { get { return 0; } }
  246. public virtual bool IsNumber { get { return false; } }
  247. public virtual bool IsString { get { return false; } }
  248. public virtual bool IsBoolean { get { return false; } }
  249. public virtual bool IsNull { get { return false; } }
  250. public virtual bool IsArray { get { return false; } }
  251. public virtual bool IsObject { get { return false; } }
  252. public virtual bool Inline { get { return false; } set { } }
  253. public virtual void Add(string aKey, JSONNode aItem)
  254. {
  255. }
  256. public virtual void Add(JSONNode aItem)
  257. {
  258. Add("", aItem);
  259. }
  260. public virtual JSONNode Remove(string aKey)
  261. {
  262. return null;
  263. }
  264. public virtual JSONNode Remove(int aIndex)
  265. {
  266. return null;
  267. }
  268. public virtual JSONNode Remove(JSONNode aNode)
  269. {
  270. return aNode;
  271. }
  272. public virtual IEnumerable<JSONNode> Children
  273. {
  274. get
  275. {
  276. yield break;
  277. }
  278. }
  279. public IEnumerable<JSONNode> DeepChildren
  280. {
  281. get
  282. {
  283. foreach (var C in Children)
  284. foreach (var D in C.DeepChildren)
  285. yield return D;
  286. }
  287. }
  288. public override string ToString()
  289. {
  290. StringBuilder sb = new StringBuilder();
  291. WriteToStringBuilder(sb, 0, 0, JSONTextMode.Compact);
  292. return sb.ToString();
  293. }
  294. public virtual string ToString(int aIndent)
  295. {
  296. StringBuilder sb = new StringBuilder();
  297. WriteToStringBuilder(sb, 0, aIndent, JSONTextMode.Indent);
  298. return sb.ToString();
  299. }
  300. internal abstract void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode);
  301. public abstract Enumerator GetEnumerator();
  302. public IEnumerable<KeyValuePair<string, JSONNode>> Linq { get { return new LinqEnumerator(this); } }
  303. public KeyEnumerator Keys { get { return new KeyEnumerator(GetEnumerator()); } }
  304. public ValueEnumerator Values { get { return new ValueEnumerator(GetEnumerator()); } }
  305. #endregion common interface
  306. #region typecasting properties
  307. public virtual double AsDouble
  308. {
  309. get
  310. {
  311. double v = 0.0;
  312. if (double.TryParse(Value, NumberStyles.Float, CultureInfo.InvariantCulture, out v))
  313. return v;
  314. return 0.0;
  315. }
  316. set
  317. {
  318. Value = value.ToString(CultureInfo.InvariantCulture);
  319. }
  320. }
  321. public virtual int AsInt
  322. {
  323. get { return (int)AsDouble; }
  324. set { AsDouble = value; }
  325. }
  326. public virtual float AsFloat
  327. {
  328. get { return (float)AsDouble; }
  329. set { AsDouble = value; }
  330. }
  331. public virtual bool AsBool
  332. {
  333. get
  334. {
  335. bool v = false;
  336. if (bool.TryParse(Value, out v))
  337. return v;
  338. return !string.IsNullOrEmpty(Value);
  339. }
  340. set
  341. {
  342. Value = (value) ? "true" : "false";
  343. }
  344. }
  345. public virtual long AsLong
  346. {
  347. get
  348. {
  349. long val = 0;
  350. if (long.TryParse(Value, out val))
  351. return val;
  352. return 0L;
  353. }
  354. set
  355. {
  356. Value = value.ToString();
  357. }
  358. }
  359. public virtual JSONArray AsArray
  360. {
  361. get
  362. {
  363. return this as JSONArray;
  364. }
  365. }
  366. public virtual JSONObject AsObject
  367. {
  368. get
  369. {
  370. return this as JSONObject;
  371. }
  372. }
  373. #endregion typecasting properties
  374. #region operators
  375. public static implicit operator JSONNode(string s)
  376. {
  377. return new JSONString(s);
  378. }
  379. public static implicit operator string(JSONNode d)
  380. {
  381. return (d == null) ? null : d.Value;
  382. }
  383. public static implicit operator JSONNode(double n)
  384. {
  385. return new JSONNumber(n);
  386. }
  387. public static implicit operator double(JSONNode d)
  388. {
  389. return (d == null) ? 0 : d.AsDouble;
  390. }
  391. public static implicit operator JSONNode(float n)
  392. {
  393. return new JSONNumber(n);
  394. }
  395. public static implicit operator float(JSONNode d)
  396. {
  397. return (d == null) ? 0 : d.AsFloat;
  398. }
  399. public static implicit operator JSONNode(int n)
  400. {
  401. return new JSONNumber(n);
  402. }
  403. public static implicit operator int(JSONNode d)
  404. {
  405. return (d == null) ? 0 : d.AsInt;
  406. }
  407. public static implicit operator JSONNode(long n)
  408. {
  409. if (longAsString)
  410. return new JSONString(n.ToString());
  411. return new JSONNumber(n);
  412. }
  413. public static implicit operator long(JSONNode d)
  414. {
  415. return (d == null) ? 0L : d.AsLong;
  416. }
  417. public static implicit operator JSONNode(bool b)
  418. {
  419. return new JSONBool(b);
  420. }
  421. public static implicit operator bool(JSONNode d)
  422. {
  423. return (d == null) ? false : d.AsBool;
  424. }
  425. public static implicit operator JSONNode(KeyValuePair<string, JSONNode> aKeyValue)
  426. {
  427. return aKeyValue.Value;
  428. }
  429. public static bool operator ==(JSONNode a, object b)
  430. {
  431. if (ReferenceEquals(a, b))
  432. return true;
  433. bool aIsNull = a is JSONNull || ReferenceEquals(a, null) || a is JSONLazyCreator;
  434. bool bIsNull = b is JSONNull || ReferenceEquals(b, null) || b is JSONLazyCreator;
  435. if (aIsNull && bIsNull)
  436. return true;
  437. return !aIsNull && a.Equals(b);
  438. }
  439. public static bool operator !=(JSONNode a, object b)
  440. {
  441. return !(a == b);
  442. }
  443. public override bool Equals(object obj)
  444. {
  445. return ReferenceEquals(this, obj);
  446. }
  447. public override int GetHashCode()
  448. {
  449. return base.GetHashCode();
  450. }
  451. #endregion operators
  452. [ThreadStatic]
  453. private static StringBuilder m_EscapeBuilder;
  454. internal static StringBuilder EscapeBuilder
  455. {
  456. get
  457. {
  458. if (m_EscapeBuilder == null)
  459. m_EscapeBuilder = new StringBuilder();
  460. return m_EscapeBuilder;
  461. }
  462. }
  463. internal static string Escape(string aText)
  464. {
  465. var sb = EscapeBuilder;
  466. sb.Length = 0;
  467. if (sb.Capacity < aText.Length + aText.Length / 10)
  468. sb.Capacity = aText.Length + aText.Length / 10;
  469. foreach (char c in aText)
  470. {
  471. switch (c)
  472. {
  473. case '\\':
  474. sb.Append("\\\\");
  475. break;
  476. case '\"':
  477. sb.Append("\\\"");
  478. break;
  479. case '\n':
  480. sb.Append("\\n");
  481. break;
  482. case '\r':
  483. sb.Append("\\r");
  484. break;
  485. case '\t':
  486. sb.Append("\\t");
  487. break;
  488. case '\b':
  489. sb.Append("\\b");
  490. break;
  491. case '\f':
  492. sb.Append("\\f");
  493. break;
  494. default:
  495. if (c < ' ' || (forceASCII && c > 127))
  496. {
  497. ushort val = c;
  498. sb.Append("\\u").Append(val.ToString("X4"));
  499. }
  500. else
  501. sb.Append(c);
  502. break;
  503. }
  504. }
  505. string result = sb.ToString();
  506. sb.Length = 0;
  507. return result;
  508. }
  509. private static JSONNode ParseElement(string token, bool quoted)
  510. {
  511. if (quoted)
  512. return token;
  513. string tmp = token.ToLower();
  514. if (tmp == "false" || tmp == "true")
  515. return tmp == "true";
  516. if (tmp == "null")
  517. return JSONNull.CreateOrGet();
  518. double val;
  519. if (double.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out val))
  520. return val;
  521. else
  522. return token;
  523. }
  524. public static JSONNode Parse(string aJSON)
  525. {
  526. Stack<JSONNode> stack = new Stack<JSONNode>();
  527. JSONNode ctx = null;
  528. int i = 0;
  529. StringBuilder Token = new StringBuilder();
  530. string TokenName = "";
  531. bool QuoteMode = false;
  532. bool TokenIsQuoted = false;
  533. while (i < aJSON.Length)
  534. {
  535. switch (aJSON[i])
  536. {
  537. case '{':
  538. if (QuoteMode)
  539. {
  540. Token.Append(aJSON[i]);
  541. break;
  542. }
  543. stack.Push(new JSONObject());
  544. if (ctx != null)
  545. {
  546. ctx.Add(TokenName, stack.Peek());
  547. }
  548. TokenName = "";
  549. Token.Length = 0;
  550. ctx = stack.Peek();
  551. break;
  552. case '[':
  553. if (QuoteMode)
  554. {
  555. Token.Append(aJSON[i]);
  556. break;
  557. }
  558. stack.Push(new JSONArray());
  559. if (ctx != null)
  560. {
  561. ctx.Add(TokenName, stack.Peek());
  562. }
  563. TokenName = "";
  564. Token.Length = 0;
  565. ctx = stack.Peek();
  566. break;
  567. case '}':
  568. case ']':
  569. if (QuoteMode)
  570. {
  571. Token.Append(aJSON[i]);
  572. break;
  573. }
  574. if (stack.Count == 0)
  575. throw new Exception("JSON Parse: Too many closing brackets");
  576. stack.Pop();
  577. if (Token.Length > 0 || TokenIsQuoted)
  578. ctx.Add(TokenName, ParseElement(Token.ToString(), TokenIsQuoted));
  579. TokenIsQuoted = false;
  580. TokenName = "";
  581. Token.Length = 0;
  582. if (stack.Count > 0)
  583. ctx = stack.Peek();
  584. break;
  585. case ':':
  586. if (QuoteMode)
  587. {
  588. Token.Append(aJSON[i]);
  589. break;
  590. }
  591. TokenName = Token.ToString();
  592. Token.Length = 0;
  593. TokenIsQuoted = false;
  594. break;
  595. case '"':
  596. QuoteMode ^= true;
  597. TokenIsQuoted |= QuoteMode;
  598. break;
  599. case ',':
  600. if (QuoteMode)
  601. {
  602. Token.Append(aJSON[i]);
  603. break;
  604. }
  605. if (Token.Length > 0 || TokenIsQuoted)
  606. ctx.Add(TokenName, ParseElement(Token.ToString(), TokenIsQuoted));
  607. TokenIsQuoted = false;
  608. TokenName = "";
  609. Token.Length = 0;
  610. TokenIsQuoted = false;
  611. break;
  612. case '\r':
  613. case '\n':
  614. break;
  615. case ' ':
  616. case '\t':
  617. if (QuoteMode)
  618. Token.Append(aJSON[i]);
  619. break;
  620. case '\\':
  621. ++i;
  622. if (QuoteMode)
  623. {
  624. char C = aJSON[i];
  625. switch (C)
  626. {
  627. case 't':
  628. Token.Append('\t');
  629. break;
  630. case 'r':
  631. Token.Append('\r');
  632. break;
  633. case 'n':
  634. Token.Append('\n');
  635. break;
  636. case 'b':
  637. Token.Append('\b');
  638. break;
  639. case 'f':
  640. Token.Append('\f');
  641. break;
  642. case 'u':
  643. {
  644. string s = aJSON.Substring(i + 1, 4);
  645. Token.Append((char)int.Parse(
  646. s,
  647. System.Globalization.NumberStyles.AllowHexSpecifier));
  648. i += 4;
  649. break;
  650. }
  651. default:
  652. Token.Append(C);
  653. break;
  654. }
  655. }
  656. break;
  657. default:
  658. Token.Append(aJSON[i]);
  659. break;
  660. }
  661. ++i;
  662. }
  663. if (QuoteMode)
  664. {
  665. throw new Exception("JSON Parse: Quotation marks seems to be messed up.");
  666. }
  667. if (ctx == null)
  668. return ParseElement(Token.ToString(), TokenIsQuoted);
  669. return ctx;
  670. }
  671. }
  672. // End of JSONNode
  673. public partial class JSONArray : JSONNode
  674. {
  675. private List<JSONNode> m_List = new List<JSONNode>();
  676. private bool inline = false;
  677. public override bool Inline
  678. {
  679. get { return inline; }
  680. set { inline = value; }
  681. }
  682. public override JSONNodeType Tag { get { return JSONNodeType.Array; } }
  683. public override bool IsArray { get { return true; } }
  684. public override Enumerator GetEnumerator() { return new Enumerator(m_List.GetEnumerator()); }
  685. public override JSONNode this[int aIndex]
  686. {
  687. get
  688. {
  689. if (aIndex < 0 || aIndex >= m_List.Count)
  690. return new JSONLazyCreator(this);
  691. return m_List[aIndex];
  692. }
  693. set
  694. {
  695. if (value == null)
  696. value = JSONNull.CreateOrGet();
  697. if (aIndex < 0 || aIndex >= m_List.Count)
  698. m_List.Add(value);
  699. else
  700. m_List[aIndex] = value;
  701. }
  702. }
  703. public override JSONNode this[string aKey]
  704. {
  705. get { return new JSONLazyCreator(this); }
  706. set
  707. {
  708. if (value == null)
  709. value = JSONNull.CreateOrGet();
  710. m_List.Add(value);
  711. }
  712. }
  713. public override int Count
  714. {
  715. get { return m_List.Count; }
  716. }
  717. public override void Add(string aKey, JSONNode aItem)
  718. {
  719. if (aItem == null)
  720. aItem = JSONNull.CreateOrGet();
  721. m_List.Add(aItem);
  722. }
  723. public override JSONNode Remove(int aIndex)
  724. {
  725. if (aIndex < 0 || aIndex >= m_List.Count)
  726. return null;
  727. JSONNode tmp = m_List[aIndex];
  728. m_List.RemoveAt(aIndex);
  729. return tmp;
  730. }
  731. public override JSONNode Remove(JSONNode aNode)
  732. {
  733. m_List.Remove(aNode);
  734. return aNode;
  735. }
  736. public override IEnumerable<JSONNode> Children
  737. {
  738. get
  739. {
  740. foreach (JSONNode N in m_List)
  741. yield return N;
  742. }
  743. }
  744. internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
  745. {
  746. aSB.Append('[');
  747. int count = m_List.Count;
  748. if (inline)
  749. aMode = JSONTextMode.Compact;
  750. for (int i = 0; i < count; i++)
  751. {
  752. if (i > 0)
  753. aSB.Append(',');
  754. if (aMode == JSONTextMode.Indent)
  755. aSB.AppendLine();
  756. if (aMode == JSONTextMode.Indent)
  757. aSB.Append(' ', aIndent + aIndentInc);
  758. m_List[i].WriteToStringBuilder(aSB, aIndent + aIndentInc, aIndentInc, aMode);
  759. }
  760. if (aMode == JSONTextMode.Indent)
  761. aSB.AppendLine().Append(' ', aIndent);
  762. aSB.Append(']');
  763. }
  764. }
  765. // End of JSONArray
  766. public partial class JSONObject : JSONNode
  767. {
  768. private Dictionary<string, JSONNode> m_Dict = new Dictionary<string, JSONNode>();
  769. private bool inline = false;
  770. public override bool Inline
  771. {
  772. get { return inline; }
  773. set { inline = value; }
  774. }
  775. public override JSONNodeType Tag { get { return JSONNodeType.Object; } }
  776. public override bool IsObject { get { return true; } }
  777. public override Enumerator GetEnumerator() { return new Enumerator(m_Dict.GetEnumerator()); }
  778. public override JSONNode this[string aKey]
  779. {
  780. get
  781. {
  782. if (m_Dict.ContainsKey(aKey))
  783. return m_Dict[aKey];
  784. else
  785. return new JSONLazyCreator(this, aKey);
  786. }
  787. set
  788. {
  789. if (value == null)
  790. value = JSONNull.CreateOrGet();
  791. if (m_Dict.ContainsKey(aKey))
  792. m_Dict[aKey] = value;
  793. else
  794. m_Dict.Add(aKey, value);
  795. }
  796. }
  797. public override JSONNode this[int aIndex]
  798. {
  799. get
  800. {
  801. if (aIndex < 0 || aIndex >= m_Dict.Count)
  802. return null;
  803. return m_Dict.ElementAt(aIndex).Value;
  804. }
  805. set
  806. {
  807. if (value == null)
  808. value = JSONNull.CreateOrGet();
  809. if (aIndex < 0 || aIndex >= m_Dict.Count)
  810. return;
  811. string key = m_Dict.ElementAt(aIndex).Key;
  812. m_Dict[key] = value;
  813. }
  814. }
  815. public override int Count
  816. {
  817. get { return m_Dict.Count; }
  818. }
  819. public override void Add(string aKey, JSONNode aItem)
  820. {
  821. if (aItem == null)
  822. aItem = JSONNull.CreateOrGet();
  823. if (!string.IsNullOrEmpty(aKey))
  824. {
  825. if (m_Dict.ContainsKey(aKey))
  826. m_Dict[aKey] = aItem;
  827. else
  828. m_Dict.Add(aKey, aItem);
  829. }
  830. else
  831. m_Dict.Add(Guid.NewGuid().ToString(), aItem);
  832. }
  833. public override JSONNode Remove(string aKey)
  834. {
  835. if (!m_Dict.ContainsKey(aKey))
  836. return null;
  837. JSONNode tmp = m_Dict[aKey];
  838. m_Dict.Remove(aKey);
  839. return tmp;
  840. }
  841. public override JSONNode Remove(int aIndex)
  842. {
  843. if (aIndex < 0 || aIndex >= m_Dict.Count)
  844. return null;
  845. var item = m_Dict.ElementAt(aIndex);
  846. m_Dict.Remove(item.Key);
  847. return item.Value;
  848. }
  849. public override JSONNode Remove(JSONNode aNode)
  850. {
  851. try
  852. {
  853. var item = m_Dict.Where(k => k.Value == aNode).First();
  854. m_Dict.Remove(item.Key);
  855. return aNode;
  856. }
  857. catch
  858. {
  859. return null;
  860. }
  861. }
  862. public override IEnumerable<JSONNode> Children
  863. {
  864. get
  865. {
  866. foreach (KeyValuePair<string, JSONNode> N in m_Dict)
  867. yield return N.Value;
  868. }
  869. }
  870. internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
  871. {
  872. aSB.Append('{');
  873. bool first = true;
  874. if (inline)
  875. aMode = JSONTextMode.Compact;
  876. foreach (var k in m_Dict)
  877. {
  878. if (!first)
  879. aSB.Append(',');
  880. first = false;
  881. if (aMode == JSONTextMode.Indent)
  882. aSB.AppendLine();
  883. if (aMode == JSONTextMode.Indent)
  884. aSB.Append(' ', aIndent + aIndentInc);
  885. aSB.Append('\"').Append(Escape(k.Key)).Append('\"');
  886. if (aMode == JSONTextMode.Compact)
  887. aSB.Append(':');
  888. else
  889. aSB.Append(" : ");
  890. k.Value.WriteToStringBuilder(aSB, aIndent + aIndentInc, aIndentInc, aMode);
  891. }
  892. if (aMode == JSONTextMode.Indent)
  893. aSB.AppendLine().Append(' ', aIndent);
  894. aSB.Append('}');
  895. }
  896. }
  897. // End of JSONObject
  898. public partial class JSONString : JSONNode
  899. {
  900. private string m_Data;
  901. public override JSONNodeType Tag { get { return JSONNodeType.String; } }
  902. public override bool IsString { get { return true; } }
  903. public override Enumerator GetEnumerator() { return new Enumerator(); }
  904. public override string Value
  905. {
  906. get { return m_Data; }
  907. set
  908. {
  909. m_Data = value;
  910. }
  911. }
  912. public JSONString(string aData)
  913. {
  914. m_Data = aData;
  915. }
  916. internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
  917. {
  918. aSB.Append('\"').Append(Escape(m_Data)).Append('\"');
  919. }
  920. public override bool Equals(object obj)
  921. {
  922. if (base.Equals(obj))
  923. return true;
  924. string s = obj as string;
  925. if (s != null)
  926. return m_Data == s;
  927. JSONString s2 = obj as JSONString;
  928. if (s2 != null)
  929. return m_Data == s2.m_Data;
  930. return false;
  931. }
  932. public override int GetHashCode()
  933. {
  934. return m_Data.GetHashCode();
  935. }
  936. }
  937. // End of JSONString
  938. public partial class JSONNumber : JSONNode
  939. {
  940. private double m_Data;
  941. public override JSONNodeType Tag { get { return JSONNodeType.Number; } }
  942. public override bool IsNumber { get { return true; } }
  943. public override Enumerator GetEnumerator() { return new Enumerator(); }
  944. public override string Value
  945. {
  946. get { return m_Data.ToString(CultureInfo.InvariantCulture); }
  947. set
  948. {
  949. double v;
  950. if (double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out v))
  951. m_Data = v;
  952. }
  953. }
  954. public override double AsDouble
  955. {
  956. get { return m_Data; }
  957. set { m_Data = value; }
  958. }
  959. public override long AsLong
  960. {
  961. get { return (long)m_Data; }
  962. set { m_Data = value; }
  963. }
  964. public JSONNumber(double aData)
  965. {
  966. m_Data = aData;
  967. }
  968. public JSONNumber(string aData)
  969. {
  970. Value = aData;
  971. }
  972. internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
  973. {
  974. aSB.Append(Value);
  975. }
  976. private static bool IsNumeric(object value)
  977. {
  978. return value is int || value is uint
  979. || value is float || value is double
  980. || value is decimal
  981. || value is long || value is ulong
  982. || value is short || value is ushort
  983. || value is sbyte || value is byte;
  984. }
  985. public override bool Equals(object obj)
  986. {
  987. if (obj == null)
  988. return false;
  989. if (base.Equals(obj))
  990. return true;
  991. JSONNumber s2 = obj as JSONNumber;
  992. if (s2 != null)
  993. return m_Data == s2.m_Data;
  994. if (IsNumeric(obj))
  995. return Convert.ToDouble(obj) == m_Data;
  996. return false;
  997. }
  998. public override int GetHashCode()
  999. {
  1000. return m_Data.GetHashCode();
  1001. }
  1002. }
  1003. // End of JSONNumber
  1004. public partial class JSONBool : JSONNode
  1005. {
  1006. private bool m_Data;
  1007. public override JSONNodeType Tag { get { return JSONNodeType.Boolean; } }
  1008. public override bool IsBoolean { get { return true; } }
  1009. public override Enumerator GetEnumerator() { return new Enumerator(); }
  1010. public override string Value
  1011. {
  1012. get { return m_Data.ToString(); }
  1013. set
  1014. {
  1015. bool v;
  1016. if (bool.TryParse(value, out v))
  1017. m_Data = v;
  1018. }
  1019. }
  1020. public override bool AsBool
  1021. {
  1022. get { return m_Data; }
  1023. set { m_Data = value; }
  1024. }
  1025. public JSONBool(bool aData)
  1026. {
  1027. m_Data = aData;
  1028. }
  1029. public JSONBool(string aData)
  1030. {
  1031. Value = aData;
  1032. }
  1033. internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
  1034. {
  1035. aSB.Append((m_Data) ? "true" : "false");
  1036. }
  1037. public override bool Equals(object obj)
  1038. {
  1039. if (obj == null)
  1040. return false;
  1041. if (obj is bool)
  1042. return m_Data == (bool)obj;
  1043. return false;
  1044. }
  1045. public override int GetHashCode()
  1046. {
  1047. return m_Data.GetHashCode();
  1048. }
  1049. }
  1050. // End of JSONBool
  1051. public partial class JSONNull : JSONNode
  1052. {
  1053. static JSONNull m_StaticInstance = new JSONNull();
  1054. public static bool reuseSameInstance = true;
  1055. public static JSONNull CreateOrGet()
  1056. {
  1057. if (reuseSameInstance)
  1058. return m_StaticInstance;
  1059. return new JSONNull();
  1060. }
  1061. private JSONNull() { }
  1062. public override JSONNodeType Tag { get { return JSONNodeType.NullValue; } }
  1063. public override bool IsNull { get { return true; } }
  1064. public override Enumerator GetEnumerator() { return new Enumerator(); }
  1065. public override string Value
  1066. {
  1067. get { return "null"; }
  1068. set { }
  1069. }
  1070. public override bool AsBool
  1071. {
  1072. get { return false; }
  1073. set { }
  1074. }
  1075. public override bool Equals(object obj)
  1076. {
  1077. if (object.ReferenceEquals(this, obj))
  1078. return true;
  1079. return (obj is JSONNull);
  1080. }
  1081. public override int GetHashCode()
  1082. {
  1083. return 0;
  1084. }
  1085. internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
  1086. {
  1087. aSB.Append("null");
  1088. }
  1089. }
  1090. // End of JSONNull
  1091. internal partial class JSONLazyCreator : JSONNode
  1092. {
  1093. private JSONNode m_Node = null;
  1094. private string m_Key = null;
  1095. public override JSONNodeType Tag { get { return JSONNodeType.None; } }
  1096. public override Enumerator GetEnumerator() { return new Enumerator(); }
  1097. public JSONLazyCreator(JSONNode aNode)
  1098. {
  1099. m_Node = aNode;
  1100. m_Key = null;
  1101. }
  1102. public JSONLazyCreator(JSONNode aNode, string aKey)
  1103. {
  1104. m_Node = aNode;
  1105. m_Key = aKey;
  1106. }
  1107. private T Set<T>(T aVal) where T : JSONNode
  1108. {
  1109. if (m_Key == null)
  1110. m_Node.Add(aVal);
  1111. else
  1112. m_Node.Add(m_Key, aVal);
  1113. m_Node = null; // Be GC friendly.
  1114. return aVal;
  1115. }
  1116. public override JSONNode this[int aIndex]
  1117. {
  1118. get { return new JSONLazyCreator(this); }
  1119. set { Set(new JSONArray()).Add(value); }
  1120. }
  1121. public override JSONNode this[string aKey]
  1122. {
  1123. get { return new JSONLazyCreator(this, aKey); }
  1124. set { Set(new JSONObject()).Add(aKey, value); }
  1125. }
  1126. public override void Add(JSONNode aItem)
  1127. {
  1128. Set(new JSONArray()).Add(aItem);
  1129. }
  1130. public override void Add(string aKey, JSONNode aItem)
  1131. {
  1132. Set(new JSONObject()).Add(aKey, aItem);
  1133. }
  1134. public static bool operator ==(JSONLazyCreator a, object b)
  1135. {
  1136. if (b == null)
  1137. return true;
  1138. return System.Object.ReferenceEquals(a, b);
  1139. }
  1140. public static bool operator !=(JSONLazyCreator a, object b)
  1141. {
  1142. return !(a == b);
  1143. }
  1144. public override bool Equals(object obj)
  1145. {
  1146. if (obj == null)
  1147. return true;
  1148. return System.Object.ReferenceEquals(this, obj);
  1149. }
  1150. public override int GetHashCode()
  1151. {
  1152. return 0;
  1153. }
  1154. public override int AsInt
  1155. {
  1156. get { Set(new JSONNumber(0)); return 0; }
  1157. set { Set(new JSONNumber(value)); }
  1158. }
  1159. public override float AsFloat
  1160. {
  1161. get { Set(new JSONNumber(0.0f)); return 0.0f; }
  1162. set { Set(new JSONNumber(value)); }
  1163. }
  1164. public override double AsDouble
  1165. {
  1166. get { Set(new JSONNumber(0.0)); return 0.0; }
  1167. set { Set(new JSONNumber(value)); }
  1168. }
  1169. public override long AsLong
  1170. {
  1171. get
  1172. {
  1173. if (longAsString)
  1174. Set(new JSONString("0"));
  1175. else
  1176. Set(new JSONNumber(0.0));
  1177. return 0L;
  1178. }
  1179. set
  1180. {
  1181. if (longAsString)
  1182. Set(new JSONString(value.ToString()));
  1183. else
  1184. Set(new JSONNumber(value));
  1185. }
  1186. }
  1187. public override bool AsBool
  1188. {
  1189. get { Set(new JSONBool(false)); return false; }
  1190. set { Set(new JSONBool(value)); }
  1191. }
  1192. public override JSONArray AsArray
  1193. {
  1194. get { return Set(new JSONArray()); }
  1195. }
  1196. public override JSONObject AsObject
  1197. {
  1198. get { return Set(new JSONObject()); }
  1199. }
  1200. internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
  1201. {
  1202. aSB.Append("null");
  1203. }
  1204. }
  1205. // End of JSONLazyCreator
  1206. public static class JSON
  1207. {
  1208. public static JSONNode Parse(string aJSON)
  1209. {
  1210. return JSONNode.Parse(aJSON);
  1211. }
  1212. }
  1213. }