|
8 | 8 | * Written by Bunny83 |
9 | 9 | * 2012-06-09 |
10 | 10 | * |
11 | | - * [2012-06-09 First Version] |
12 | | - * - provides strongly typed node classes and lists / dictionaries |
13 | | - * - provides easy access to class members / array items / data values |
14 | | - * - the parser now properly identifies types. So generating JSON with this framework should work. |
15 | | - * - only double quotes (") are used for quoting strings. |
16 | | - * - provides "casting" properties to easily convert to / from those types: |
17 | | - * int / float / double / bool |
18 | | - * - provides a common interface for each node so no explicit casting is required. |
19 | | - * - the parser tries to avoid errors, but if malformed JSON is parsed the result is more or less undefined |
20 | | - * - It can serialize/deserialize a node tree into/from an experimental compact binary format. It might |
21 | | - * be handy if you want to store things in a file and don't want it to be easily modifiable |
22 | | - * |
23 | | - * [2012-12-17 Update] |
24 | | - * - Added internal JSONLazyCreator class which simplifies the construction of a JSON tree |
25 | | - * Now you can simple reference any item that doesn't exist yet and it will return a JSONLazyCreator |
26 | | - * The class determines the required type by it's further use, creates the type and removes itself. |
27 | | - * - Added binary serialization / deserialization. |
28 | | - * - Added support for BZip2 zipped binary format. Requires the SharpZipLib ( http://www.icsharpcode.net/opensource/sharpziplib/ ) |
29 | | - * The usage of the SharpZipLib library can be disabled by removing or commenting out the USE_SharpZipLib define at the top |
30 | | - * - The serializer uses different types when it comes to store the values. Since my data values |
31 | | - * are all of type string, the serializer will "try" which format fits best. The order is: int, float, double, bool, string. |
32 | | - * It's not the most efficient way but for a moderate amount of data it should work on all platforms. |
33 | | - * |
34 | | - * [2017-03-08 Update] |
35 | | - * - Optimised parsing by using a StringBuilder for token. This prevents performance issues when large |
36 | | - * string data fields are contained in the json data. |
37 | | - * - Finally refactored the badly named JSONClass into JSONObject. |
38 | | - * - Replaced the old JSONData class by distict typed classes ( JSONString, JSONNumber, JSONBool, JSONNull ) this |
39 | | - * allows to propertly convert the node tree back to json without type information loss. The actual value |
40 | | - * parsing now happens at parsing time and not when you actually access one of the casting properties. |
41 | | - * |
42 | | - * [2017-04-11 Update] |
43 | | - * - Fixed parsing bug where empty string values have been ignored. |
44 | | - * - Optimised "ToString" by using a StringBuilder internally. This should heavily improve performance for large files |
45 | | - * - Changed the overload of "ToString(string aIndent)" to "ToString(int aIndent)" |
46 | | - * |
47 | | - * [2017-11-29 Update] |
48 | | - * - Removed the IEnumerator implementations on JSONArray & JSONObject and replaced it with a common |
49 | | - * struct Enumerator in JSONNode that should avoid garbage generation. The enumerator always works |
50 | | - * on KeyValuePair<string, JSONNode>, even for JSONArray. |
51 | | - * - Added two wrapper Enumerators that allows for easy key or value enumeration. A JSONNode now has |
52 | | - * a "Keys" and a "Values" enumerable property. Those are also struct enumerators / enumerables |
53 | | - * - A KeyValuePair<string, JSONNode> can now be implicitly converted into a JSONNode. This allows |
54 | | - * a foreach loop over a JSONNode to directly access the values only. Since KeyValuePair as well as |
55 | | - * all the Enumerators are structs, no garbage is allocated. |
56 | | - * - To add Linq support another "LinqEnumerator" is available through the "Linq" property. This |
57 | | - * enumerator does implement the generic IEnumerable interface so most Linq extensions can be used |
58 | | - * on this enumerable object. This one does allocate memory as it's a wrapper class. |
59 | | - * - The Escape method now escapes all control characters (# < 32) in strings as uncode characters |
60 | | - * (\uXXXX) and if the static bool JSONNode.forceASCII is set to true it will also escape all |
61 | | - * characters # > 127. This might be useful if you require an ASCII output. Though keep in mind |
62 | | - * when your strings contain many non-ascii characters the strings become much longer (x6) and are |
63 | | - * no longer human readable. |
64 | | - * - The node types JSONObject and JSONArray now have an "Inline" boolean switch which will default to |
65 | | - * false. It can be used to serialize this element inline even you serialize with an indented format |
66 | | - * This is useful for arrays containing numbers so it doesn't place every number on a new line |
67 | | - * - Extracted the binary serialization code into a seperate extension file. All classes are now declared |
68 | | - * as "partial" so an extension file can even add a new virtual or abstract method / interface to |
69 | | - * JSONNode and override it in the concrete type classes. It's of course a hacky approach which is |
70 | | - * generally not recommended, but i wanted to keep everything tightly packed. |
71 | | - * - Added a static CreateOrGet method to the JSONNull class. Since this class is immutable it could |
72 | | - * be reused without major problems. If you have a lot null fields in your data it will help reduce |
73 | | - * the memory / garbage overhead. I also added a static setting (reuseSameInstance) to JSONNull |
74 | | - * (default is true) which will change the behaviour of "CreateOrGet". If you set this to false |
75 | | - * CreateOrGet will not reuse the cached instance but instead create a new JSONNull instance each time. |
76 | | - * I made the JSONNull constructor private so if you need to create an instance manually use |
77 | | - * JSONNull.CreateOrGet() |
78 | | - * |
79 | | - * [2018-01-09 Update] |
80 | | - * - Changed all double.TryParse and double.ToString uses to use the invariant culture to avoid problems |
81 | | - * on systems with a culture that uses a comma as decimal point. |
82 | | - * |
83 | | - * [2018-01-26 Update] |
84 | | - * - Added AsLong. Note that a JSONNumber is stored as double and can't represent all long values. However |
85 | | - * storing it as string would work. |
86 | | - * - Added static setting "JSONNode.longAsString" which controls the default type that is used by the |
87 | | - * LazyCreator when using AsLong |
88 | | - * |
89 | | - * [2018-04-25 Update] |
90 | | - * - Added support for parsing single values (JSONBool, JSONString, JSONNumber, JSONNull) as top level value. |
91 | | - * |
92 | | - * [2019-02-18 Update] |
93 | | - * - Added HasKey(key) and GetValueOrDefault(key, default) to the JSONNode class to provide way to read |
94 | | - * values conditionally without creating a LazyCreator |
95 | | - * |
96 | | - * [2019-03-25 Update] |
97 | | - * - Added static setting "allowLineComments" to the JSONNode class which is true by default. This allows |
98 | | - * "//" line comments when parsing json text as long as it's not within quoted text. All text after // up |
99 | | - * to the end of the line is completely ignored / skipped. This makes it easier to create human readable |
100 | | - * and editable files. Note that stripped comments are not read, processed or preserved in any way. So |
101 | | - * this feature is only relevant for human created files. |
102 | | - * - Explicitly strip BOM (Byte Order Mark) when parsing to avoid getting it leaked into a single primitive |
103 | | - * value. That's a rare case but better safe than sorry. |
104 | | - * - Allowing adding the empty string as key |
| 11 | + * Changelog now external. See Changelog.txt |
105 | 12 | * |
106 | 13 | * The MIT License (MIT) |
107 | 14 | * |
108 | | - * Copyright (c) 2012-2017 Markus Göbel (Bunny83) |
| 15 | + * Copyright (c) 2012-2019 Markus Göbel (Bunny83) |
109 | 16 | * |
110 | 17 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
111 | 18 | * of this software and associated documentation files (the "Software"), to deal |
@@ -176,7 +83,8 @@ public Enumerator(Dictionary<string, JSONNode>.Enumerator aDictEnum) |
176 | 83 | } |
177 | 84 | public KeyValuePair<string, JSONNode> Current |
178 | 85 | { |
179 | | - get { |
| 86 | + get |
| 87 | + { |
180 | 88 | if (type == Type.Array) |
181 | 89 | return new KeyValuePair<string, JSONNode>(string.Empty, m_Array.Current); |
182 | 90 | else if (type == Type.Object) |
@@ -301,6 +209,11 @@ public virtual JSONNode Remove(JSONNode aNode) |
301 | 209 | return aNode; |
302 | 210 | } |
303 | 211 |
|
| 212 | + public virtual JSONNode Clone() |
| 213 | + { |
| 214 | + return null; |
| 215 | + } |
| 216 | + |
304 | 217 | public virtual IEnumerable<JSONNode> Children |
305 | 218 | { |
306 | 219 | get |
@@ -359,7 +272,7 @@ public virtual double AsDouble |
359 | 272 | get |
360 | 273 | { |
361 | 274 | double v = 0.0; |
362 | | - if (double.TryParse(Value,NumberStyles.Float, CultureInfo.InvariantCulture, out v)) |
| 275 | + if (double.TryParse(Value, NumberStyles.Float, CultureInfo.InvariantCulture, out v)) |
363 | 276 | return v; |
364 | 277 | return 0.0; |
365 | 278 | } |
@@ -525,7 +438,8 @@ public override int GetHashCode() |
525 | 438 | private static StringBuilder m_EscapeBuilder; |
526 | 439 | internal static StringBuilder EscapeBuilder |
527 | 440 | { |
528 | | - get { |
| 441 | + get |
| 442 | + { |
529 | 443 | if (m_EscapeBuilder == null) |
530 | 444 | m_EscapeBuilder = new StringBuilder(); |
531 | 445 | return m_EscapeBuilder; |
@@ -739,7 +653,7 @@ public static JSONNode Parse(string aJSON) |
739 | 653 | } |
740 | 654 | break; |
741 | 655 | case '/': |
742 | | - if (allowLineComments && !QuoteMode && i + 1 < aJSON.Length && aJSON[i+1] == '/') |
| 656 | + if (allowLineComments && !QuoteMode && i + 1 < aJSON.Length && aJSON[i + 1] == '/') |
743 | 657 | { |
744 | 658 | while (++i < aJSON.Length && aJSON[i] != '\n' && aJSON[i] != '\r') ; |
745 | 659 | break; |
@@ -838,6 +752,20 @@ public override JSONNode Remove(JSONNode aNode) |
838 | 752 | return aNode; |
839 | 753 | } |
840 | 754 |
|
| 755 | + public override JSONNode Clone() |
| 756 | + { |
| 757 | + var node = new JSONArray(); |
| 758 | + node.m_List.Capacity = m_List.Capacity; |
| 759 | + foreach(var n in m_List) |
| 760 | + { |
| 761 | + if (n != null) |
| 762 | + node.Add(n.Clone()); |
| 763 | + else |
| 764 | + node.Add(null); |
| 765 | + } |
| 766 | + return node; |
| 767 | + } |
| 768 | + |
841 | 769 | public override IEnumerable<JSONNode> Children |
842 | 770 | { |
843 | 771 | get |
@@ -981,6 +909,16 @@ public override JSONNode Remove(JSONNode aNode) |
981 | 909 | } |
982 | 910 | } |
983 | 911 |
|
| 912 | + public override JSONNode Clone() |
| 913 | + { |
| 914 | + var node = new JSONObject(); |
| 915 | + foreach (var n in m_Dict) |
| 916 | + { |
| 917 | + node.Add(n.Key, n.Value.Clone()); |
| 918 | + } |
| 919 | + return node; |
| 920 | + } |
| 921 | + |
984 | 922 | public override bool HasKey(string aKey) |
985 | 923 | { |
986 | 924 | return m_Dict.ContainsKey(aKey); |
@@ -1056,6 +994,10 @@ public JSONString(string aData) |
1056 | 994 | { |
1057 | 995 | m_Data = aData; |
1058 | 996 | } |
| 997 | + public override JSONNode Clone() |
| 998 | + { |
| 999 | + return new JSONString(m_Data); |
| 1000 | + } |
1059 | 1001 |
|
1060 | 1002 | internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) |
1061 | 1003 | { |
@@ -1120,6 +1062,11 @@ public JSONNumber(string aData) |
1120 | 1062 | Value = aData; |
1121 | 1063 | } |
1122 | 1064 |
|
| 1065 | + public override JSONNode Clone() |
| 1066 | + { |
| 1067 | + return new JSONNumber(m_Data); |
| 1068 | + } |
| 1069 | + |
1123 | 1070 | internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) |
1124 | 1071 | { |
1125 | 1072 | aSB.Append(Value); |
@@ -1187,6 +1134,11 @@ public JSONBool(string aData) |
1187 | 1134 | Value = aData; |
1188 | 1135 | } |
1189 | 1136 |
|
| 1137 | + public override JSONNode Clone() |
| 1138 | + { |
| 1139 | + return new JSONBool(m_Data); |
| 1140 | + } |
| 1141 | + |
1190 | 1142 | internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) |
1191 | 1143 | { |
1192 | 1144 | aSB.Append((m_Data) ? "true" : "false"); |
@@ -1233,6 +1185,11 @@ public override bool AsBool |
1233 | 1185 | set { } |
1234 | 1186 | } |
1235 | 1187 |
|
| 1188 | + public override JSONNode Clone() |
| 1189 | + { |
| 1190 | + return CreateOrGet(); |
| 1191 | + } |
| 1192 | + |
1236 | 1193 | public override bool Equals(object obj) |
1237 | 1194 | { |
1238 | 1195 | if (object.ReferenceEquals(this, obj)) |
|
0 commit comments