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