2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Globalization;
7 using System.Runtime.Serialization.Json;
10 using JsonPair = System.Collections.Generic.KeyValuePair<string, System.Json.JsonValue>;
15 public abstract class JsonValue : IEnumerable
17 public static JsonValue Load (Stream stream)
20 throw new ArgumentNullException ("stream");
21 return Load (new StreamReader (stream, true));
24 public static JsonValue Load (TextReader textReader)
26 if (textReader == null)
27 throw new ArgumentNullException ("textReader");
29 var ret = new JavaScriptReader (textReader, true).Read ();
31 return ToJsonValue (ret);
34 static IEnumerable<KeyValuePair<string,JsonValue>> ToJsonPairEnumerable (IEnumerable<KeyValuePair<string,object>> kvpc)
36 foreach (var kvp in kvpc)
37 yield return new KeyValuePair<string,JsonValue> (kvp.Key, ToJsonValue (kvp.Value));
40 static IEnumerable<JsonValue> ToJsonValueEnumerable (IEnumerable<object> arr)
42 foreach (var obj in arr)
43 yield return ToJsonValue (obj);
46 static JsonValue ToJsonValue (object ret)
50 var kvpc = ret as IEnumerable<KeyValuePair<string,object>>;
52 return new JsonObject (ToJsonPairEnumerable (kvpc));
53 var arr = ret as IEnumerable<object>;
55 return new JsonArray (ToJsonValueEnumerable (arr));
58 return new JsonPrimitive ((bool) ret);
60 return new JsonPrimitive ((byte) ret);
62 return new JsonPrimitive ((char) ret);
64 return new JsonPrimitive ((decimal) ret);
66 return new JsonPrimitive ((double) ret);
68 return new JsonPrimitive ((float) ret);
70 return new JsonPrimitive ((int) ret);
72 return new JsonPrimitive ((long) ret);
74 return new JsonPrimitive ((sbyte) ret);
76 return new JsonPrimitive ((short) ret);
78 return new JsonPrimitive ((string) ret);
80 return new JsonPrimitive ((uint) ret);
82 return new JsonPrimitive ((ulong) ret);
84 return new JsonPrimitive ((ushort) ret);
86 return new JsonPrimitive ((DateTime) ret);
87 if (ret is DateTimeOffset)
88 return new JsonPrimitive ((DateTimeOffset) ret);
90 return new JsonPrimitive ((Guid) ret);
92 return new JsonPrimitive ((TimeSpan) ret);
94 return new JsonPrimitive ((Uri) ret);
95 throw new NotSupportedException (String.Format ("Unexpected parser return type: {0}", ret.GetType ()));
98 public static JsonValue Parse (string jsonString)
100 if (jsonString == null)
101 throw new ArgumentNullException ("jsonString");
102 return Load (new StringReader (jsonString));
105 public virtual int Count {
106 get { throw new InvalidOperationException (); }
109 public abstract JsonType JsonType { get; }
111 public virtual JsonValue this [int index] {
112 get { throw new InvalidOperationException (); }
113 set { throw new InvalidOperationException (); }
116 public virtual JsonValue this [string key] {
117 get { throw new InvalidOperationException (); }
118 set { throw new InvalidOperationException (); }
121 public virtual bool ContainsKey (string key)
123 throw new InvalidOperationException ();
126 public virtual void Save (Stream stream)
129 throw new ArgumentNullException ("stream");
130 Save (new StreamWriter (stream));
133 public virtual void Save (TextWriter textWriter)
135 if (textWriter == null)
136 throw new ArgumentNullException ("textWriter");
137 SaveInternal (textWriter);
140 void SaveInternal (TextWriter w)
143 case JsonType.Object:
145 bool following = false;
146 foreach (JsonPair pair in ((JsonObject) this)) {
150 w.Write (EscapeString (pair.Key));
152 if (pair.Value == null)
155 pair.Value.SaveInternal (w);
163 foreach (JsonValue v in ((JsonArray) this)) {
174 case JsonType.Boolean:
175 w.Write ((bool) this ? "true" : "false");
177 case JsonType.String:
179 w.Write (EscapeString (((JsonPrimitive) this).GetFormattedString ()));
183 w.Write (((JsonPrimitive) this).GetFormattedString ());
188 public override string ToString ()
190 StringWriter sw = new StringWriter ();
192 return sw.ToString ();
195 IEnumerator IEnumerable.GetEnumerator ()
197 throw new InvalidOperationException ();
200 // Characters which have to be escaped:
201 // - Required by JSON Spec: Control characters, '"' and '\\'
202 // - Broken surrogates to make sure the JSON string is valid Unicode
203 // (and can be encoded as UTF8)
204 // - JSON does not require U+2028 and U+2029 to be escaped, but
205 // JavaScript does require this:
206 // http://stackoverflow.com/questions/2965293/javascript-parse-error-on-u2028-unicode-character/9168133#9168133
207 // - '/' also does not have to be escaped, but escaping it when
208 // preceeded by a '<' avoids problems with JSON in HTML <script> tags
209 bool NeedEscape (string src, int i) {
211 return c < 32 || c == '"' || c == '\\'
212 // Broken lead surrogate
213 || (c >= '\uD800' && c <= '\uDBFF' &&
214 (i == src.Length - 1 || src [i + 1] < '\uDC00' || src [i + 1] > '\uDFFF'))
215 // Broken tail surrogate
216 || (c >= '\uDC00' && c <= '\uDFFF' &&
217 (i == 0 || src [i - 1] < '\uD800' || src [i - 1] > '\uDBFF'))
218 // To produce valid JavaScript
219 || c == '\u2028' || c == '\u2029'
220 // Escape "</" for <script> tags
221 || (c == '/' && i > 0 && src [i - 1] == '<');
224 internal string EscapeString (string src)
229 for (int i = 0; i < src.Length; i++)
230 if (NeedEscape (src, i)) {
231 var sb = new StringBuilder ();
233 sb.Append (src, 0, i);
234 return DoEscapeString (sb, src, i);
239 string DoEscapeString (StringBuilder sb, string src, int cur)
242 for (int i = cur; i < src.Length; i++)
243 if (NeedEscape (src, i)) {
244 sb.Append (src, start, i - start);
246 case '\b': sb.Append ("\\b"); break;
247 case '\f': sb.Append ("\\f"); break;
248 case '\n': sb.Append ("\\n"); break;
249 case '\r': sb.Append ("\\r"); break;
250 case '\t': sb.Append ("\\t"); break;
251 case '\"': sb.Append ("\\\""); break;
252 case '\\': sb.Append ("\\\\"); break;
253 case '/': sb.Append ("\\/"); break;
256 sb.Append (((int) src [i]).ToString ("x04"));
261 sb.Append (src, start, src.Length - start);
262 return sb.ToString ();
267 public static implicit operator JsonValue (bool value)
269 return new JsonPrimitive (value);
272 public static implicit operator JsonValue (byte value)
274 return new JsonPrimitive (value);
277 public static implicit operator JsonValue (char value)
279 return new JsonPrimitive (value);
282 public static implicit operator JsonValue (decimal value)
284 return new JsonPrimitive (value);
287 public static implicit operator JsonValue (double value)
289 return new JsonPrimitive (value);
292 public static implicit operator JsonValue (float value)
294 return new JsonPrimitive (value);
297 public static implicit operator JsonValue (int value)
299 return new JsonPrimitive (value);
302 public static implicit operator JsonValue (long value)
304 return new JsonPrimitive (value);
307 public static implicit operator JsonValue (sbyte value)
309 return new JsonPrimitive (value);
312 public static implicit operator JsonValue (short value)
314 return new JsonPrimitive (value);
317 public static implicit operator JsonValue (string value)
319 return new JsonPrimitive (value);
322 public static implicit operator JsonValue (uint value)
324 return new JsonPrimitive (value);
327 public static implicit operator JsonValue (ulong value)
329 return new JsonPrimitive (value);
332 public static implicit operator JsonValue (ushort value)
334 return new JsonPrimitive (value);
337 public static implicit operator JsonValue (DateTime value)
339 return new JsonPrimitive (value);
342 public static implicit operator JsonValue (DateTimeOffset value)
344 return new JsonPrimitive (value);
347 public static implicit operator JsonValue (Guid value)
349 return new JsonPrimitive (value);
352 public static implicit operator JsonValue (TimeSpan value)
354 return new JsonPrimitive (value);
357 public static implicit operator JsonValue (Uri value)
359 return new JsonPrimitive (value);
364 public static implicit operator bool (JsonValue value)
367 throw new ArgumentNullException ("value");
368 return Convert.ToBoolean (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
371 public static implicit operator byte (JsonValue value)
374 throw new ArgumentNullException ("value");
375 return Convert.ToByte (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
378 public static implicit operator char (JsonValue value)
381 throw new ArgumentNullException ("value");
382 return Convert.ToChar (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
385 public static implicit operator decimal (JsonValue value)
388 throw new ArgumentNullException ("value");
389 return Convert.ToDecimal (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
392 public static implicit operator double (JsonValue value)
395 throw new ArgumentNullException ("value");
396 return Convert.ToDouble (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
399 public static implicit operator float (JsonValue value)
402 throw new ArgumentNullException ("value");
403 return Convert.ToSingle (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
406 public static implicit operator int (JsonValue value)
409 throw new ArgumentNullException ("value");
410 return Convert.ToInt32 (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
413 public static implicit operator long (JsonValue value)
416 throw new ArgumentNullException ("value");
417 return Convert.ToInt64 (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
420 public static implicit operator sbyte (JsonValue value)
423 throw new ArgumentNullException ("value");
424 return Convert.ToSByte (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
427 public static implicit operator short (JsonValue value)
430 throw new ArgumentNullException ("value");
431 return Convert.ToInt16 (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
434 public static implicit operator string (JsonValue value)
438 return (string) ((JsonPrimitive) value).Value;
441 public static implicit operator uint (JsonValue value)
444 throw new ArgumentNullException ("value");
445 return Convert.ToUInt16 (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
448 public static implicit operator ulong (JsonValue value)
451 throw new ArgumentNullException ("value");
452 return Convert.ToUInt64(((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
455 public static implicit operator ushort (JsonValue value)
458 throw new ArgumentNullException ("value");
459 return Convert.ToUInt16 (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
462 public static implicit operator DateTime (JsonValue value)
465 throw new ArgumentNullException ("value");
466 return (DateTime) ((JsonPrimitive) value).Value;
469 public static implicit operator DateTimeOffset (JsonValue value)
472 throw new ArgumentNullException ("value");
473 return (DateTimeOffset) ((JsonPrimitive) value).Value;
476 public static implicit operator TimeSpan (JsonValue value)
479 throw new ArgumentNullException ("value");
480 return (TimeSpan) ((JsonPrimitive) value).Value;
483 public static implicit operator Guid (JsonValue value)
486 throw new ArgumentNullException ("value");
487 return (Guid) ((JsonPrimitive) value).Value;
490 public static implicit operator Uri (JsonValue value)
493 throw new ArgumentNullException ("value");
494 return (Uri) ((JsonPrimitive) value).Value;