Don't ignore drives with type "aufs" or "overlay" (Xamarin-31021)
[mono.git] / mcs / class / System.Json / System.Json / JsonValue.cs
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Globalization;
5 using System.IO;
6 using System.Linq;
7 using System.Runtime.Serialization.Json;
8 using System.Text;
9
10 using JsonPair = System.Collections.Generic.KeyValuePair<string, System.Json.JsonValue>;
11
12
13 namespace System.Json
14 {
15         public abstract class JsonValue : IEnumerable
16         {
17                 public static JsonValue Load (Stream stream)
18                 {
19                         if (stream == null)
20                                 throw new ArgumentNullException ("stream");
21                         return Load (new StreamReader (stream, true));
22                 }
23
24                 public static JsonValue Load (TextReader textReader)
25                 {
26                         if (textReader == null)
27                                 throw new ArgumentNullException ("textReader");
28
29                         var ret = new JavaScriptReader (textReader, true).Read ();
30
31                         return ToJsonValue (ret);
32                 }
33
34                 static IEnumerable<KeyValuePair<string,JsonValue>> ToJsonPairEnumerable (IEnumerable<KeyValuePair<string,object>> kvpc)
35                 {
36                         foreach (var kvp in kvpc)
37                                 yield return new KeyValuePair<string,JsonValue> (kvp.Key, ToJsonValue (kvp.Value));
38                 }
39
40                 static IEnumerable<JsonValue> ToJsonValueEnumerable (IEnumerable<object> arr)
41                 {
42                         foreach (var obj in arr)
43                                 yield return ToJsonValue (obj);
44                 }
45
46                 static JsonValue ToJsonValue (object ret)
47                 {
48                         if (ret == null)
49                                 return null;
50                         var kvpc = ret as IEnumerable<KeyValuePair<string,object>>;
51                         if (kvpc != null)
52                                 return new JsonObject (ToJsonPairEnumerable (kvpc));
53                         var arr = ret as IEnumerable<object>;
54                         if (arr != null)
55                                 return new JsonArray (ToJsonValueEnumerable (arr));
56
57                         if (ret is bool)
58                                 return new JsonPrimitive ((bool) ret);
59                         if (ret is byte)
60                                 return new JsonPrimitive ((byte) ret);
61                         if (ret is char)
62                                 return new JsonPrimitive ((char) ret);
63                         if (ret is decimal)
64                                 return new JsonPrimitive ((decimal) ret);
65                         if (ret is double)
66                                 return new JsonPrimitive ((double) ret);
67                         if (ret is float)
68                                 return new JsonPrimitive ((float) ret);
69                         if (ret is int)
70                                 return new JsonPrimitive ((int) ret);
71                         if (ret is long)
72                                 return new JsonPrimitive ((long) ret);
73                         if (ret is sbyte)
74                                 return new JsonPrimitive ((sbyte) ret);
75                         if (ret is short)
76                                 return new JsonPrimitive ((short) ret);
77                         if (ret is string)
78                                 return new JsonPrimitive ((string) ret);
79                         if (ret is uint)
80                                 return new JsonPrimitive ((uint) ret);
81                         if (ret is ulong)
82                                 return new JsonPrimitive ((ulong) ret);
83                         if (ret is ushort)
84                                 return new JsonPrimitive ((ushort) ret);
85                         if (ret is DateTime)
86                                 return new JsonPrimitive ((DateTime) ret);
87                         if (ret is DateTimeOffset)
88                                 return new JsonPrimitive ((DateTimeOffset) ret);
89                         if (ret is Guid)
90                                 return new JsonPrimitive ((Guid) ret);
91                         if (ret is TimeSpan)
92                                 return new JsonPrimitive ((TimeSpan) ret);
93                         if (ret is Uri)
94                                 return new JsonPrimitive ((Uri) ret);
95                         throw new NotSupportedException (String.Format ("Unexpected parser return type: {0}", ret.GetType ()));
96                 }
97
98                 public static JsonValue Parse (string jsonString)
99                 {
100                         if (jsonString == null)
101                                 throw new ArgumentNullException ("jsonString");
102                         return Load (new StringReader (jsonString));
103                 }
104
105                 public virtual int Count {
106                         get { throw new InvalidOperationException (); }
107                 }
108
109                 public abstract JsonType JsonType { get; }
110
111                 public virtual JsonValue this [int index] {
112                         get { throw new InvalidOperationException (); }
113                         set { throw new InvalidOperationException (); }
114                 }
115
116                 public virtual JsonValue this [string key] {
117                         get { throw new InvalidOperationException (); }
118                         set { throw new InvalidOperationException (); }
119                 }
120
121                 public virtual bool ContainsKey (string key)
122                 {
123                         throw new InvalidOperationException ();
124                 }
125
126                 public virtual void Save (Stream stream)
127                 {
128                         if (stream == null)
129                                 throw new ArgumentNullException ("stream");
130                         Save (new StreamWriter (stream));
131                 }
132
133                 public virtual void Save (TextWriter textWriter)
134                 {
135                         if (textWriter == null)
136                                 throw new ArgumentNullException ("textWriter");
137                         SaveInternal (textWriter);
138                 }
139                 
140                 void SaveInternal (TextWriter w)
141                 {
142                         switch (JsonType) {
143                         case JsonType.Object:
144                                 w.Write ('{');
145                                 bool following = false;
146                                 foreach (JsonPair pair in ((JsonObject) this)) {
147                                         if (following)
148                                                 w.Write (", ");
149                                         w.Write ('\"');
150                                         w.Write (EscapeString (pair.Key));
151                                         w.Write ("\": ");
152                                         if (pair.Value == null)
153                                                 w.Write ("null");
154                                         else
155                                                 pair.Value.SaveInternal (w);
156                                         following = true;
157                                 }
158                                 w.Write ('}');
159                                 break;
160                         case JsonType.Array:
161                                 w.Write ('[');
162                                 following = false;
163                                 foreach (JsonValue v in ((JsonArray) this)) {
164                                         if (following)
165                                                 w.Write (", ");
166                                         if (v != null) 
167                                                 v.SaveInternal (w);
168                                         else
169                                                 w.Write ("null");
170                                         following = true;
171                                 }
172                                 w.Write (']');
173                                 break;
174                         case JsonType.Boolean:
175                                 w.Write ((bool) this ? "true" : "false");
176                                 break;
177                         case JsonType.String:
178                                 w.Write ('"');
179                                 w.Write (EscapeString (((JsonPrimitive) this).GetFormattedString ()));
180                                 w.Write ('"');
181                                 break;
182                         default:
183                                 w.Write (((JsonPrimitive) this).GetFormattedString ());
184                                 break;
185                         }
186                 }
187
188                 public override string ToString ()
189                 {
190                         StringWriter sw = new StringWriter ();
191                         Save (sw);
192                         return sw.ToString ();
193                 }
194
195                 IEnumerator IEnumerable.GetEnumerator ()
196                 {
197                         throw new InvalidOperationException ();
198                 }
199
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) {
210                         char c = src [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] == '<');
222                 }
223                 
224                 internal string EscapeString (string src)
225                 {
226                         if (src == null)
227                                 return null;
228
229                         for (int i = 0; i < src.Length; i++)
230                                 if (NeedEscape (src, i)) {
231                                         var sb = new StringBuilder ();
232                                         if (i > 0)
233                                                 sb.Append (src, 0, i);
234                                         return DoEscapeString (sb, src, i);
235                                 }
236                         return src;
237                 }
238
239                 string DoEscapeString (StringBuilder sb, string src, int cur)
240                 {
241                         int start = cur;
242                         for (int i = cur; i < src.Length; i++)
243                                 if (NeedEscape (src, i)) {
244                                         sb.Append (src, start, i - start);
245                                         switch (src [i]) {
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;
254                                         default:
255                                                 sb.Append ("\\u");
256                                                 sb.Append (((int) src [i]).ToString ("x04"));
257                                                 break;
258                                         }
259                                         start = i + 1;
260                                 }
261                         sb.Append (src, start, src.Length - start);
262                         return sb.ToString ();
263                 }
264
265                 // CLI -> JsonValue
266
267                 public static implicit operator JsonValue (bool value)
268                 {
269                         return new JsonPrimitive (value);
270                 }
271
272                 public static implicit operator JsonValue (byte value)
273                 {
274                         return new JsonPrimitive (value);
275                 }
276
277                 public static implicit operator JsonValue (char value)
278                 {
279                         return new JsonPrimitive (value);
280                 }
281
282                 public static implicit operator JsonValue (decimal value)
283                 {
284                         return new JsonPrimitive (value);
285                 }
286
287                 public static implicit operator JsonValue (double value)
288                 {
289                         return new JsonPrimitive (value);
290                 }
291
292                 public static implicit operator JsonValue (float value)
293                 {
294                         return new JsonPrimitive (value);
295                 }
296
297                 public static implicit operator JsonValue (int value)
298                 {
299                         return new JsonPrimitive (value);
300                 }
301
302                 public static implicit operator JsonValue (long value)
303                 {
304                         return new JsonPrimitive (value);
305                 }
306
307                 public static implicit operator JsonValue (sbyte value)
308                 {
309                         return new JsonPrimitive (value);
310                 }
311
312                 public static implicit operator JsonValue (short value)
313                 {
314                         return new JsonPrimitive (value);
315                 }
316
317                 public static implicit operator JsonValue (string value)
318                 {
319                         return new JsonPrimitive (value);
320                 }
321
322                 public static implicit operator JsonValue (uint value)
323                 {
324                         return new JsonPrimitive (value);
325                 }
326
327                 public static implicit operator JsonValue (ulong value)
328                 {
329                         return new JsonPrimitive (value);
330                 }
331
332                 public static implicit operator JsonValue (ushort value)
333                 {
334                         return new JsonPrimitive (value);
335                 }
336
337                 public static implicit operator JsonValue (DateTime value)
338                 {
339                         return new JsonPrimitive (value);
340                 }
341
342                 public static implicit operator JsonValue (DateTimeOffset value)
343                 {
344                         return new JsonPrimitive (value);
345                 }
346
347                 public static implicit operator JsonValue (Guid value)
348                 {
349                         return new JsonPrimitive (value);
350                 }
351
352                 public static implicit operator JsonValue (TimeSpan value)
353                 {
354                         return new JsonPrimitive (value);
355                 }
356
357                 public static implicit operator JsonValue (Uri value)
358                 {
359                         return new JsonPrimitive (value);
360                 }
361
362                 // JsonValue -> CLI
363
364                 public static implicit operator bool (JsonValue value)
365                 {
366                         if (value == null)
367                                 throw new ArgumentNullException ("value");
368                         return Convert.ToBoolean (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
369                 }
370
371                 public static implicit operator byte (JsonValue value)
372                 {
373                         if (value == null)
374                                 throw new ArgumentNullException ("value");
375                         return Convert.ToByte (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
376                 }
377
378                 public static implicit operator char (JsonValue value)
379                 {
380                         if (value == null)
381                                 throw new ArgumentNullException ("value");
382                         return Convert.ToChar (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
383                 }
384
385                 public static implicit operator decimal (JsonValue value)
386                 {
387                         if (value == null)
388                                 throw new ArgumentNullException ("value");
389                         return Convert.ToDecimal (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
390                 }
391
392                 public static implicit operator double (JsonValue value)
393                 {
394                         if (value == null)
395                                 throw new ArgumentNullException ("value");
396                         return Convert.ToDouble (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
397                 }
398
399                 public static implicit operator float (JsonValue value)
400                 {
401                         if (value == null)
402                                 throw new ArgumentNullException ("value");
403                         return Convert.ToSingle (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
404                 }
405
406                 public static implicit operator int (JsonValue value)
407                 {
408                         if (value == null)
409                                 throw new ArgumentNullException ("value");
410                         return Convert.ToInt32 (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
411                 }
412
413                 public static implicit operator long (JsonValue value)
414                 {
415                         if (value == null)
416                                 throw new ArgumentNullException ("value");
417                         return Convert.ToInt64 (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
418                 }
419
420                 public static implicit operator sbyte (JsonValue value)
421                 {
422                         if (value == null)
423                                 throw new ArgumentNullException ("value");
424                         return Convert.ToSByte (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
425                 }
426
427                 public static implicit operator short (JsonValue value)
428                 {
429                         if (value == null)
430                                 throw new ArgumentNullException ("value");
431                         return Convert.ToInt16 (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
432                 }
433
434                 public static implicit operator string (JsonValue value)
435                 {
436                         if (value == null)
437                                 return null;
438                         return (string) ((JsonPrimitive) value).Value;
439                 }
440
441                 public static implicit operator uint (JsonValue value)
442                 {
443                         if (value == null)
444                                 throw new ArgumentNullException ("value");
445                         return Convert.ToUInt16 (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
446                 }
447
448                 public static implicit operator ulong (JsonValue value)
449                 {
450                         if (value == null)
451                                 throw new ArgumentNullException ("value");
452                         return Convert.ToUInt64(((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
453                 }
454
455                 public static implicit operator ushort (JsonValue value)
456                 {
457                         if (value == null)
458                                 throw new ArgumentNullException ("value");
459                         return Convert.ToUInt16 (((JsonPrimitive) value).Value, NumberFormatInfo.InvariantInfo);
460                 }
461
462                 public static implicit operator DateTime (JsonValue value)
463                 {
464                         if (value == null)
465                                 throw new ArgumentNullException ("value");
466                         return (DateTime) ((JsonPrimitive) value).Value;
467                 }
468
469                 public static implicit operator DateTimeOffset (JsonValue value)
470                 {
471                         if (value == null)
472                                 throw new ArgumentNullException ("value");
473                         return (DateTimeOffset) ((JsonPrimitive) value).Value;
474                 }
475
476                 public static implicit operator TimeSpan (JsonValue value)
477                 {
478                         if (value == null)
479                                 throw new ArgumentNullException ("value");
480                         return (TimeSpan) ((JsonPrimitive) value).Value;
481                 }
482
483                 public static implicit operator Guid (JsonValue value)
484                 {
485                         if (value == null)
486                                 throw new ArgumentNullException ("value");
487                         return (Guid) ((JsonPrimitive) value).Value;
488                 }
489
490                 public static implicit operator Uri (JsonValue value)
491                 {
492                         if (value == null)
493                                 throw new ArgumentNullException ("value");
494                         return (Uri) ((JsonPrimitive) value).Value;
495                 }
496         }
497 }