Revision 2:ae2e128a3d94

b/Assets/Plugins.meta
1
fileFormatVersion: 2
2
guid: 9e3d28cb51eb31b4591de67e58a1db04
3
folderAsset: yes
4
DefaultImporter:
5
  userData: 
b/Assets/Plugins/SimpleJson.cs
1
//-----------------------------------------------------------------------
2
// <copyright file="SimpleJson.cs" company="The Outercurve Foundation">
3
//    Copyright (c) 2011, The Outercurve Foundation.
4
//
5
//    Licensed under the MIT License (the "License");
6
//    you may not use this file except in compliance with the License.
7
//    You may obtain a copy of the License at
8
//      http://www.opensource.org/licenses/mit-license.php
9
//
10
//    Unless required by applicable law or agreed to in writing, software
11
//    distributed under the License is distributed on an "AS IS" BASIS,
12
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
//    See the License for the specific language governing permissions and
14
//    limitations under the License.
15
// </copyright>
16
// <author>Nathan Totten (ntotten.com), Jim Zimmerman (jimzimmerman.com) and Prabir Shrestha (prabir.me)</author>
17
// <website>https://github.com/facebook-csharp-sdk/simple-json</website>
18
//-----------------------------------------------------------------------
19

  
20
// VERSION:
21

  
22
// NOTE: uncomment the following line to make SimpleJson class internal.
23
//#define SIMPLE_JSON_INTERNAL
24

  
25
// NOTE: uncomment the following line to make JsonArray and JsonObject class internal.
26
//#define SIMPLE_JSON_OBJARRAYINTERNAL
27

  
28
// NOTE: uncomment the following line to enable dynamic support.
29
//#define SIMPLE_JSON_DYNAMIC
30

  
31
// NOTE: uncomment the following line to enable DataContract support.
32
//#define SIMPLE_JSON_DATACONTRACT
33

  
34
// NOTE: uncomment the following line to disable linq expressions/compiled lambda (better performance) instead of method.invoke().
35
// define if you are using .net framework <= 3.0 or < WP7.5
36
#define SIMPLE_JSON_NO_LINQ_EXPRESSION
37

  
38
// NOTE: uncomment the following line if you are compiling under Window Metro style application/library.
39
// usually already defined in properties
40
//#define NETFX_CORE;
41

  
42
// If you are targetting WinStore, WP8 and NET4.5+ PCL make sure to #define SIMPLE_JSON_TYPEINFO;
43

  
44
// original json parsing code from http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html
45

  
46
#if NETFX_CORE
47
#define SIMPLE_JSON_TYPEINFO
48
#endif
49

  
50
using System;
51
using System.CodeDom.Compiler;
52
using System.Collections;
53
using System.Collections.Generic;
54
#if !SIMPLE_JSON_NO_LINQ_EXPRESSION
55
using System.Linq.Expressions;
56
#endif
57
using System.ComponentModel;
58
using System.Diagnostics.CodeAnalysis;
59
#if SIMPLE_JSON_DYNAMIC
60
using System.Dynamic;
61
#endif
62
using System.Globalization;
63
using System.Reflection;
64
using System.Runtime.Serialization;
65
using System.Text;
66
using SimpleJson.Reflection;
67

  
68
// ReSharper disable LoopCanBeConvertedToQuery
69
// ReSharper disable RedundantExplicitArrayCreation
70
// ReSharper disable SuggestUseVarKeywordEvident
71
namespace SimpleJson
72
{
73
    /// <summary>
74
    /// Represents the json array.
75
    /// </summary>
76
    [GeneratedCode("simple-json", "1.0.0")]
77
    [EditorBrowsable(EditorBrowsableState.Never)]
78
    [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
79
#if SIMPLE_JSON_OBJARRAYINTERNAL
80
    internal
81
#else
82
    public
83
#endif
84
 class JsonArray : List<object>
85
    {
86
        /// <summary>
87
        /// Initializes a new instance of the <see cref="JsonArray"/> class. 
88
        /// </summary>
89
        public JsonArray() { }
90

  
91
        /// <summary>
92
        /// Initializes a new instance of the <see cref="JsonArray"/> class. 
93
        /// </summary>
94
        /// <param name="capacity">The capacity of the json array.</param>
95
        public JsonArray(int capacity) : base(capacity) { }
96

  
97
        /// <summary>
98
        /// The json representation of the array.
99
        /// </summary>
100
        /// <returns>The json representation of the array.</returns>
101
        public override string ToString()
102
        {
103
            return SimpleJson.SerializeObject(this) ?? string.Empty;
104
        }
105
    }
106

  
107
    /// <summary>
108
    /// Represents the json object.
109
    /// </summary>
110
    [GeneratedCode("simple-json", "1.0.0")]
111
    [EditorBrowsable(EditorBrowsableState.Never)]
112
    [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
113
#if SIMPLE_JSON_OBJARRAYINTERNAL
114
    internal
115
#else
116
    public
117
#endif
118
 class JsonObject :
119
#if SIMPLE_JSON_DYNAMIC
120
 DynamicObject,
121
#endif
122
 IDictionary<string, object>
123
    {
124
        /// <summary>
125
        /// The internal member dictionary.
126
        /// </summary>
127
        private readonly Dictionary<string, object> _members;
128

  
129
        /// <summary>
130
        /// Initializes a new instance of <see cref="JsonObject"/>.
131
        /// </summary>
132
        public JsonObject()
133
        {
134
            _members = new Dictionary<string, object>();
135
        }
136

  
137
        /// <summary>
138
        /// Initializes a new instance of <see cref="JsonObject"/>.
139
        /// </summary>
140
        /// <param name="comparer">The <see cref="T:System.Collections.Generic.IEqualityComparer`1"/> implementation to use when comparing keys, or null to use the default <see cref="T:System.Collections.Generic.EqualityComparer`1"/> for the type of the key.</param>
141
        public JsonObject(IEqualityComparer<string> comparer)
142
        {
143
            _members = new Dictionary<string, object>(comparer);
144
        }
145

  
146
        /// <summary>
147
        /// Gets the <see cref="System.Object"/> at the specified index.
148
        /// </summary>
149
        /// <value></value>
150
        public object this[int index]
151
        {
152
            get { return GetAtIndex(_members, index); }
153
        }
154

  
155
        internal static object GetAtIndex(IDictionary<string, object> obj, int index)
156
        {
157
            if (obj == null)
158
                throw new ArgumentNullException("obj");
159
            if (index >= obj.Count)
160
                throw new ArgumentOutOfRangeException("index");
161
            int i = 0;
162
            foreach (KeyValuePair<string, object> o in obj)
163
                if (i++ == index) return o.Value;
164
            return null;
165
        }
166

  
167
        /// <summary>
168
        /// Adds the specified key.
169
        /// </summary>
170
        /// <param name="key">The key.</param>
171
        /// <param name="value">The value.</param>
172
        public void Add(string key, object value)
173
        {
174
            _members.Add(key, value);
175
        }
176

  
177
        /// <summary>
178
        /// Determines whether the specified key contains key.
179
        /// </summary>
180
        /// <param name="key">The key.</param>
181
        /// <returns>
182
        ///     <c>true</c> if the specified key contains key; otherwise, <c>false</c>.
183
        /// </returns>
184
        public bool ContainsKey(string key)
185
        {
186
            return _members.ContainsKey(key);
187
        }
188

  
189
        /// <summary>
190
        /// Gets the keys.
191
        /// </summary>
192
        /// <value>The keys.</value>
193
        public ICollection<string> Keys
194
        {
195
            get { return _members.Keys; }
196
        }
197

  
198
        /// <summary>
199
        /// Removes the specified key.
200
        /// </summary>
201
        /// <param name="key">The key.</param>
202
        /// <returns></returns>
203
        public bool Remove(string key)
204
        {
205
            return _members.Remove(key);
206
        }
207

  
208
        /// <summary>
209
        /// Tries the get value.
210
        /// </summary>
211
        /// <param name="key">The key.</param>
212
        /// <param name="value">The value.</param>
213
        /// <returns></returns>
214
        public bool TryGetValue(string key, out object value)
215
        {
216
            return _members.TryGetValue(key, out value);
217
        }
218

  
219
        /// <summary>
220
        /// Gets the values.
221
        /// </summary>
222
        /// <value>The values.</value>
223
        public ICollection<object> Values
224
        {
225
            get { return _members.Values; }
226
        }
227

  
228
        /// <summary>
229
        /// Gets or sets the <see cref="System.Object"/> with the specified key.
230
        /// </summary>
231
        /// <value></value>
232
        public object this[string key]
233
        {
234
            get { return _members[key]; }
235
            set { _members[key] = value; }
236
        }
237

  
238
        /// <summary>
239
        /// Adds the specified item.
240
        /// </summary>
241
        /// <param name="item">The item.</param>
242
        public void Add(KeyValuePair<string, object> item)
243
        {
244
            _members.Add(item.Key, item.Value);
245
        }
246

  
247
        /// <summary>
248
        /// Clears this instance.
249
        /// </summary>
250
        public void Clear()
251
        {
252
            _members.Clear();
253
        }
254

  
255
        /// <summary>
256
        /// Determines whether [contains] [the specified item].
257
        /// </summary>
258
        /// <param name="item">The item.</param>
259
        /// <returns>
260
        /// 	<c>true</c> if [contains] [the specified item]; otherwise, <c>false</c>.
261
        /// </returns>
262
        public bool Contains(KeyValuePair<string, object> item)
263
        {
264
            return _members.ContainsKey(item.Key) && _members[item.Key] == item.Value;
265
        }
266

  
267
        /// <summary>
268
        /// Copies to.
269
        /// </summary>
270
        /// <param name="array">The array.</param>
271
        /// <param name="arrayIndex">Index of the array.</param>
272
        public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
273
        {
274
            if (array == null) throw new ArgumentNullException("array");
275
            int num = Count;
276
            foreach (KeyValuePair<string, object> kvp in this)
277
            {
278
                array[arrayIndex++] = kvp;
279
                if (--num <= 0)
280
                    return;
281
            }
282
        }
283

  
284
        /// <summary>
285
        /// Gets the count.
286
        /// </summary>
287
        /// <value>The count.</value>
288
        public int Count
289
        {
290
            get { return _members.Count; }
291
        }
292

  
293
        /// <summary>
294
        /// Gets a value indicating whether this instance is read only.
295
        /// </summary>
296
        /// <value>
297
        /// 	<c>true</c> if this instance is read only; otherwise, <c>false</c>.
298
        /// </value>
299
        public bool IsReadOnly
300
        {
301
            get { return false; }
302
        }
303

  
304
        /// <summary>
305
        /// Removes the specified item.
306
        /// </summary>
307
        /// <param name="item">The item.</param>
308
        /// <returns></returns>
309
        public bool Remove(KeyValuePair<string, object> item)
310
        {
311
            return _members.Remove(item.Key);
312
        }
313

  
314
        /// <summary>
315
        /// Gets the enumerator.
316
        /// </summary>
317
        /// <returns></returns>
318
        public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
319
        {
320
            return _members.GetEnumerator();
321
        }
322

  
323
        /// <summary>
324
        /// Returns an enumerator that iterates through a collection.
325
        /// </summary>
326
        /// <returns>
327
        /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
328
        /// </returns>
329
        IEnumerator IEnumerable.GetEnumerator()
330
        {
331
            return _members.GetEnumerator();
332
        }
333

  
334
        /// <summary>
335
        /// Returns a json <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
336
        /// </summary>
337
        /// <returns>
338
        /// A json <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
339
        /// </returns>
340
        public override string ToString()
341
        {
342
            return SimpleJson.SerializeObject(this);
343
        }
344

  
345
#if SIMPLE_JSON_DYNAMIC
346
        /// <summary>
347
        /// Provides implementation for type conversion operations. Classes derived from the <see cref="T:System.Dynamic.DynamicObject"/> class can override this method to specify dynamic behavior for operations that convert an object from one type to another.
348
        /// </summary>
349
        /// <param name="binder">Provides information about the conversion operation. The binder.Type property provides the type to which the object must be converted. For example, for the statement (String)sampleObject in C# (CType(sampleObject, Type) in Visual Basic), where sampleObject is an instance of the class derived from the <see cref="T:System.Dynamic.DynamicObject"/> class, binder.Type returns the <see cref="T:System.String"/> type. The binder.Explicit property provides information about the kind of conversion that occurs. It returns true for explicit conversion and false for implicit conversion.</param>
350
        /// <param name="result">The result of the type conversion operation.</param>
351
        /// <returns>
352
        /// Alwasy returns true.
353
        /// </returns>
354
        public override bool TryConvert(ConvertBinder binder, out object result)
355
        {
356
            // <pex>
357
            if (binder == null)
358
                throw new ArgumentNullException("binder");
359
            // </pex>
360
            Type targetType = binder.Type;
361

  
362
            if ((targetType == typeof(IEnumerable)) ||
363
                (targetType == typeof(IEnumerable<KeyValuePair<string, object>>)) ||
364
                (targetType == typeof(IDictionary<string, object>)) ||
365
                (targetType == typeof(IDictionary)))
366
            {
367
                result = this;
368
                return true;
369
            }
370

  
371
            return base.TryConvert(binder, out result);
372
        }
373

  
374
        /// <summary>
375
        /// Provides the implementation for operations that delete an object member. This method is not intended for use in C# or Visual Basic.
376
        /// </summary>
377
        /// <param name="binder">Provides information about the deletion.</param>
378
        /// <returns>
379
        /// Alwasy returns true.
380
        /// </returns>
381
        public override bool TryDeleteMember(DeleteMemberBinder binder)
382
        {
383
            // <pex>
384
            if (binder == null)
385
                throw new ArgumentNullException("binder");
386
            // </pex>
387
            return _members.Remove(binder.Name);
388
        }
389

  
390
        /// <summary>
391
        /// Provides the implementation for operations that get a value by index. Classes derived from the <see cref="T:System.Dynamic.DynamicObject"/> class can override this method to specify dynamic behavior for indexing operations.
392
        /// </summary>
393
        /// <param name="binder">Provides information about the operation.</param>
394
        /// <param name="indexes">The indexes that are used in the operation. For example, for the sampleObject[3] operation in C# (sampleObject(3) in Visual Basic), where sampleObject is derived from the DynamicObject class, <paramref name="indexes"/> is equal to 3.</param>
395
        /// <param name="result">The result of the index operation.</param>
396
        /// <returns>
397
        /// Alwasy returns true.
398
        /// </returns>
399
        public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
400
        {
401
            if (indexes == null) throw new ArgumentNullException("indexes");
402
            if (indexes.Length == 1)
403
            {
404
                result = ((IDictionary<string, object>)this)[(string)indexes[0]];
405
                return true;
406
            }
407
            result = null;
408
            return true;
409
        }
410

  
411
        /// <summary>
412
        /// Provides the implementation for operations that get member values. Classes derived from the <see cref="T:System.Dynamic.DynamicObject"/> class can override this method to specify dynamic behavior for operations such as getting a value for a property.
413
        /// </summary>
414
        /// <param name="binder">Provides information about the object that called the dynamic operation. The binder.Name property provides the name of the member on which the dynamic operation is performed. For example, for the Console.WriteLine(sampleObject.SampleProperty) statement, where sampleObject is an instance of the class derived from the <see cref="T:System.Dynamic.DynamicObject"/> class, binder.Name returns "SampleProperty". The binder.IgnoreCase property specifies whether the member name is case-sensitive.</param>
415
        /// <param name="result">The result of the get operation. For example, if the method is called for a property, you can assign the property value to <paramref name="result"/>.</param>
416
        /// <returns>
417
        /// Alwasy returns true.
418
        /// </returns>
419
        public override bool TryGetMember(GetMemberBinder binder, out object result)
420
        {
421
            object value;
422
            if (_members.TryGetValue(binder.Name, out value))
423
            {
424
                result = value;
425
                return true;
426
            }
427
            result = null;
428
            return true;
429
        }
430

  
431
        /// <summary>
432
        /// Provides the implementation for operations that set a value by index. Classes derived from the <see cref="T:System.Dynamic.DynamicObject"/> class can override this method to specify dynamic behavior for operations that access objects by a specified index.
433
        /// </summary>
434
        /// <param name="binder">Provides information about the operation.</param>
435
        /// <param name="indexes">The indexes that are used in the operation. For example, for the sampleObject[3] = 10 operation in C# (sampleObject(3) = 10 in Visual Basic), where sampleObject is derived from the <see cref="T:System.Dynamic.DynamicObject"/> class, <paramref name="indexes"/> is equal to 3.</param>
436
        /// <param name="value">The value to set to the object that has the specified index. For example, for the sampleObject[3] = 10 operation in C# (sampleObject(3) = 10 in Visual Basic), where sampleObject is derived from the <see cref="T:System.Dynamic.DynamicObject"/> class, <paramref name="value"/> is equal to 10.</param>
437
        /// <returns>
438
        /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.
439
        /// </returns>
440
        public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
441
        {
442
            if (indexes == null) throw new ArgumentNullException("indexes");
443
            if (indexes.Length == 1)
444
            {
445
                ((IDictionary<string, object>)this)[(string)indexes[0]] = value;
446
                return true;
447
            }
448
            return base.TrySetIndex(binder, indexes, value);
449
        }
450

  
451
        /// <summary>
452
        /// Provides the implementation for operations that set member values. Classes derived from the <see cref="T:System.Dynamic.DynamicObject"/> class can override this method to specify dynamic behavior for operations such as setting a value for a property.
453
        /// </summary>
454
        /// <param name="binder">Provides information about the object that called the dynamic operation. The binder.Name property provides the name of the member to which the value is being assigned. For example, for the statement sampleObject.SampleProperty = "Test", where sampleObject is an instance of the class derived from the <see cref="T:System.Dynamic.DynamicObject"/> class, binder.Name returns "SampleProperty". The binder.IgnoreCase property specifies whether the member name is case-sensitive.</param>
455
        /// <param name="value">The value to set to the member. For example, for sampleObject.SampleProperty = "Test", where sampleObject is an instance of the class derived from the <see cref="T:System.Dynamic.DynamicObject"/> class, the <paramref name="value"/> is "Test".</param>
456
        /// <returns>
457
        /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.)
458
        /// </returns>
459
        public override bool TrySetMember(SetMemberBinder binder, object value)
460
        {
461
            // <pex>
462
            if (binder == null)
463
                throw new ArgumentNullException("binder");
464
            // </pex>
465
            _members[binder.Name] = value;
466
            return true;
467
        }
468

  
469
        /// <summary>
470
        /// Returns the enumeration of all dynamic member names.
471
        /// </summary>
472
        /// <returns>
473
        /// A sequence that contains dynamic member names.
474
        /// </returns>
475
        public override IEnumerable<string> GetDynamicMemberNames()
476
        {
477
            foreach (var key in Keys)
478
                yield return key;
479
        }
480
#endif
481
    }
482
}
483

  
484
namespace SimpleJson
485
{
486
    /// <summary>
487
    /// This class encodes and decodes JSON strings.
488
    /// Spec. details, see http://www.json.org/
489
    /// 
490
    /// JSON uses Arrays and Objects. These correspond here to the datatypes JsonArray(IList&lt;object>) and JsonObject(IDictionary&lt;string,object>).
491
    /// All numbers are parsed to doubles.
492
    /// </summary>
493
    [GeneratedCode("simple-json", "1.0.0")]
494
#if SIMPLE_JSON_INTERNAL
495
    internal
496
#else
497
    public
498
#endif
499
 static class SimpleJson
500
    {
501
        private const int TOKEN_NONE = 0;
502
        private const int TOKEN_CURLY_OPEN = 1;
503
        private const int TOKEN_CURLY_CLOSE = 2;
504
        private const int TOKEN_SQUARED_OPEN = 3;
505
        private const int TOKEN_SQUARED_CLOSE = 4;
506
        private const int TOKEN_COLON = 5;
507
        private const int TOKEN_COMMA = 6;
508
        private const int TOKEN_STRING = 7;
509
        private const int TOKEN_NUMBER = 8;
510
        private const int TOKEN_TRUE = 9;
511
        private const int TOKEN_FALSE = 10;
512
        private const int TOKEN_NULL = 11;
513
        private const int BUILDER_CAPACITY = 2000;
514

  
515
        /// <summary>
516
        /// Parses the string json into a value
517
        /// </summary>
518
        /// <param name="json">A JSON string.</param>
519
        /// <returns>An IList&lt;object>, a IDictionary&lt;string,object>, a double, a string, null, true, or false</returns>
520
        public static object DeserializeObject(string json)
521
        {
522
            object obj;
523
            if (TryDeserializeObject(json, out obj))
524
                return obj;
525
            throw new SerializationException("Invalid JSON string");
526
        }
527

  
528
        /// <summary>
529
        /// Try parsing the json string into a value.
530
        /// </summary>
531
        /// <param name="json">
532
        /// A JSON string.
533
        /// </param>
534
        /// <param name="obj">
535
        /// The object.
536
        /// </param>
537
        /// <returns>
538
        /// Returns true if successfull otherwise false.
539
        /// </returns>
540
        [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification="Need to support .NET 2")]
541
        public static bool TryDeserializeObject(string json, out object obj)
542
        {
543
            bool success = true;
544
            if (json != null)
545
            {
546
                char[] charArray = json.ToCharArray();
547
                int index = 0;
548
                obj = ParseValue(charArray, ref index, ref success);
549
            }
550
            else
551
                obj = null;
552

  
553
            return success;
554
        }
555

  
556
        public static object DeserializeObject(string json, Type type, IJsonSerializerStrategy jsonSerializerStrategy)
557
        {
558
            object jsonObject = DeserializeObject(json);
559
            return type == null || jsonObject != null && ReflectionUtils.IsAssignableFrom(jsonObject.GetType(), type)
560
                       ? jsonObject
561
                       : (jsonSerializerStrategy ?? CurrentJsonSerializerStrategy).DeserializeObject(jsonObject, type);
562
        }
563

  
564
        public static object DeserializeObject(string json, Type type)
565
        {
566
            return DeserializeObject(json, type, null);
567
        }
568

  
569
        public static T DeserializeObject<T>(string json, IJsonSerializerStrategy jsonSerializerStrategy)
570
        {
571
            return (T)DeserializeObject(json, typeof(T), jsonSerializerStrategy);
572
        }
573

  
574
        public static T DeserializeObject<T>(string json)
575
        {
576
            return (T)DeserializeObject(json, typeof(T), null);
577
        }
578

  
579
        /// <summary>
580
        /// Converts a IDictionary&lt;string,object> / IList&lt;object> object into a JSON string
581
        /// </summary>
582
        /// <param name="json">A IDictionary&lt;string,object> / IList&lt;object></param>
583
        /// <param name="jsonSerializerStrategy">Serializer strategy to use</param>
584
        /// <returns>A JSON encoded string, or null if object 'json' is not serializable</returns>
585
        public static string SerializeObject(object json, IJsonSerializerStrategy jsonSerializerStrategy)
586
        {
587
            StringBuilder builder = new StringBuilder(BUILDER_CAPACITY);
588
            bool success = SerializeValue(jsonSerializerStrategy, json, builder);
589
            return (success ? builder.ToString() : null);
590
        }
591

  
592
        public static string SerializeObject(object json)
593
        {
594
            return SerializeObject(json, CurrentJsonSerializerStrategy);
595
        }
596

  
597
        public static string EscapeToJavascriptString(string jsonString)
598
        {
599
            if (string.IsNullOrEmpty(jsonString))
600
                return jsonString;
601

  
602
            StringBuilder sb = new StringBuilder();
603
            char c;
604

  
605
            for (int i = 0; i < jsonString.Length; )
606
            {
607
                c = jsonString[i++];
608

  
609
                if (c == '\\')
610
                {
611
                    int remainingLength = jsonString.Length - i;
612
                    if (remainingLength >= 2)
613
                    {
614
                        char lookahead = jsonString[i];
615
                        if (lookahead == '\\')
616
                        {
617
                            sb.Append('\\');
618
                            ++i;
619
                        }
620
                        else if (lookahead == '"')
621
                        {
622
                            sb.Append("\"");
623
                            ++i;
624
                        }
625
                        else if (lookahead == 't')
626
                        {
627
                            sb.Append('\t');
628
                            ++i;
629
                        }
630
                        else if (lookahead == 'b')
631
                        {
632
                            sb.Append('\b');
633
                            ++i;
634
                        }
635
                        else if (lookahead == 'n')
636
                        {
637
                            sb.Append('\n');
638
                            ++i;
639
                        }
640
                        else if (lookahead == 'r')
641
                        {
642
                            sb.Append('\r');
643
                            ++i;
644
                        }
645
                    }
646
                }
647
                else
648
                {
649
                    sb.Append(c);
650
                }
651
            }
652
            return sb.ToString();
653
        }
654

  
655
        static IDictionary<string, object> ParseObject(char[] json, ref int index, ref bool success)
656
        {
657
            IDictionary<string, object> table = new JsonObject();
658
            int token;
659

  
660
            // {
661
            NextToken(json, ref index);
662

  
663
            bool done = false;
664
            while (!done)
665
            {
666
                token = LookAhead(json, index);
667
                if (token == TOKEN_NONE)
668
                {
669
                    success = false;
670
                    return null;
671
                }
672
                else if (token == TOKEN_COMMA)
673
                    NextToken(json, ref index);
674
                else if (token == TOKEN_CURLY_CLOSE)
675
                {
676
                    NextToken(json, ref index);
677
                    return table;
678
                }
679
                else
680
                {
681
                    // name
682
                    string name = ParseString(json, ref index, ref success);
683
                    if (!success)
684
                    {
685
                        success = false;
686
                        return null;
687
                    }
688
                    // :
689
                    token = NextToken(json, ref index);
690
                    if (token != TOKEN_COLON)
691
                    {
692
                        success = false;
693
                        return null;
694
                    }
695
                    // value
696
                    object value = ParseValue(json, ref index, ref success);
697
                    if (!success)
698
                    {
699
                        success = false;
700
                        return null;
701
                    }
702
                    table[name] = value;
703
                }
704
            }
705
            return table;
706
        }
707

  
708
        static JsonArray ParseArray(char[] json, ref int index, ref bool success)
709
        {
710
            JsonArray array = new JsonArray();
711

  
712
            // [
713
            NextToken(json, ref index);
714

  
715
            bool done = false;
716
            while (!done)
717
            {
718
                int token = LookAhead(json, index);
719
                if (token == TOKEN_NONE)
720
                {
721
                    success = false;
722
                    return null;
723
                }
724
                else if (token == TOKEN_COMMA)
725
                    NextToken(json, ref index);
726
                else if (token == TOKEN_SQUARED_CLOSE)
727
                {
728
                    NextToken(json, ref index);
729
                    break;
730
                }
731
                else
732
                {
733
                    object value = ParseValue(json, ref index, ref success);
734
                    if (!success)
735
                        return null;
736
                    array.Add(value);
737
                }
738
            }
739
            return array;
740
        }
741

  
742
        static object ParseValue(char[] json, ref int index, ref bool success)
743
        {
744
            switch (LookAhead(json, index))
745
            {
746
                case TOKEN_STRING:
747
                    return ParseString(json, ref index, ref success);
748
                case TOKEN_NUMBER:
749
                    return ParseNumber(json, ref index, ref success);
750
                case TOKEN_CURLY_OPEN:
751
                    return ParseObject(json, ref index, ref success);
752
                case TOKEN_SQUARED_OPEN:
753
                    return ParseArray(json, ref index, ref success);
754
                case TOKEN_TRUE:
755
                    NextToken(json, ref index);
756
                    return true;
757
                case TOKEN_FALSE:
758
                    NextToken(json, ref index);
759
                    return false;
760
                case TOKEN_NULL:
761
                    NextToken(json, ref index);
762
                    return null;
763
                case TOKEN_NONE:
764
                    break;
765
            }
766
            success = false;
767
            return null;
768
        }
769

  
770
        static string ParseString(char[] json, ref int index, ref bool success)
771
        {
772
            StringBuilder s = new StringBuilder(BUILDER_CAPACITY);
773
            char c;
774

  
775
            EatWhitespace(json, ref index);
776

  
777
            // "
778
            c = json[index++];
779
            bool complete = false;
780
            while (!complete)
781
            {
782
                if (index == json.Length)
783
                    break;
784

  
785
                c = json[index++];
786
                if (c == '"')
787
                {
788
                    complete = true;
789
                    break;
790
                }
791
                else if (c == '\\')
792
                {
793
                    if (index == json.Length)
794
                        break;
795
                    c = json[index++];
796
                    if (c == '"')
797
                        s.Append('"');
798
                    else if (c == '\\')
799
                        s.Append('\\');
800
                    else if (c == '/')
801
                        s.Append('/');
802
                    else if (c == 'b')
803
                        s.Append('\b');
804
                    else if (c == 'f')
805
                        s.Append('\f');
806
                    else if (c == 'n')
807
                        s.Append('\n');
808
                    else if (c == 'r')
809
                        s.Append('\r');
810
                    else if (c == 't')
811
                        s.Append('\t');
812
                    else if (c == 'u')
813
                    {
814
                        int remainingLength = json.Length - index;
815
                        if (remainingLength >= 4)
816
                        {
817
                            // parse the 32 bit hex into an integer codepoint
818
                            uint codePoint;
819
                            if (!(success = UInt32.TryParse(new string(json, index, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out codePoint)))
820
                                return "";
821

  
822
                            // convert the integer codepoint to a unicode char and add to string
823
                            if (0xD800 <= codePoint && codePoint <= 0xDBFF)  // if high surrogate
824
                            {
825
                                index += 4; // skip 4 chars
826
                                remainingLength = json.Length - index;
827
                                if (remainingLength >= 6)
828
                                {
829
                                    uint lowCodePoint;
830
                                    if (new string(json, index, 2) == "\\u" && UInt32.TryParse(new string(json, index + 2, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out lowCodePoint))
831
                                    {
832
                                        if (0xDC00 <= lowCodePoint && lowCodePoint <= 0xDFFF)    // if low surrogate
833
                                        {
834
                                            s.Append((char)codePoint);
835
                                            s.Append((char)lowCodePoint);
836
                                            index += 6; // skip 6 chars
837
                                            continue;
838
                                        }
839
                                    }
840
                                }
841
                                success = false;    // invalid surrogate pair
842
                                return "";
843
                            }
844
                            s.Append(ConvertFromUtf32((int)codePoint));
845
                            // skip 4 chars
846
                            index += 4;
847
                        }
848
                        else
849
                            break;
850
                    }
851
                }
852
                else
853
                    s.Append(c);
854
            }
855
            if (!complete)
856
            {
857
                success = false;
858
                return null;
859
            }
860
            return s.ToString();
861
        }
862

  
863
        private static string ConvertFromUtf32(int utf32)
864
        {
865
            // http://www.java2s.com/Open-Source/CSharp/2.6.4-mono-.net-core/System/System/Char.cs.htm
866
            if (utf32 < 0 || utf32 > 0x10FFFF)
867
                throw new ArgumentOutOfRangeException("utf32", "The argument must be from 0 to 0x10FFFF.");
868
            if (0xD800 <= utf32 && utf32 <= 0xDFFF)
869
                throw new ArgumentOutOfRangeException("utf32", "The argument must not be in surrogate pair range.");
870
            if (utf32 < 0x10000)
871
                return new string((char)utf32, 1);
872
            utf32 -= 0x10000;
873
            return new string(new char[] { (char)((utf32 >> 10) + 0xD800), (char)(utf32 % 0x0400 + 0xDC00) });
874
        }
875

  
876
        static object ParseNumber(char[] json, ref int index, ref bool success)
877
        {
878
            EatWhitespace(json, ref index);
879
            int lastIndex = GetLastIndexOfNumber(json, index);
880
            int charLength = (lastIndex - index) + 1;
881
            object returnNumber;
882
            string str = new string(json, index, charLength);
883
            if (str.IndexOf(".", StringComparison.OrdinalIgnoreCase) != -1 || str.IndexOf("e", StringComparison.OrdinalIgnoreCase) != -1)
884
            {
885
                double number;
886
                success = double.TryParse(new string(json, index, charLength), NumberStyles.Any, CultureInfo.InvariantCulture, out number);
887
                returnNumber = number;
888
            }
889
            else
890
            {
891
                long number;
892
                success = long.TryParse(new string(json, index, charLength), NumberStyles.Any, CultureInfo.InvariantCulture, out number);
893
                returnNumber = number;
894
            }
895
            index = lastIndex + 1;
896
            return returnNumber;
897
        }
898

  
899
        static int GetLastIndexOfNumber(char[] json, int index)
900
        {
901
            int lastIndex;
902
            for (lastIndex = index; lastIndex < json.Length; lastIndex++)
903
                if ("0123456789+-.eE".IndexOf(json[lastIndex]) == -1) break;
904
            return lastIndex - 1;
905
        }
906

  
907
        static void EatWhitespace(char[] json, ref int index)
908
        {
909
            for (; index < json.Length; index++)
910
                if (" \t\n\r\b\f".IndexOf(json[index]) == -1) break;
911
        }
912

  
913
        static int LookAhead(char[] json, int index)
914
        {
915
            int saveIndex = index;
916
            return NextToken(json, ref saveIndex);
917
        }
918

  
919
        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
920
        static int NextToken(char[] json, ref int index)
921
        {
922
            EatWhitespace(json, ref index);
923
            if (index == json.Length)
924
                return TOKEN_NONE;
925
            char c = json[index];
926
            index++;
927
            switch (c)
928
            {
929
                case '{':
930
                    return TOKEN_CURLY_OPEN;
931
                case '}':
932
                    return TOKEN_CURLY_CLOSE;
933
                case '[':
934
                    return TOKEN_SQUARED_OPEN;
935
                case ']':
936
                    return TOKEN_SQUARED_CLOSE;
937
                case ',':
938
                    return TOKEN_COMMA;
939
                case '"':
940
                    return TOKEN_STRING;
941
                case '0':
942
                case '1':
943
                case '2':
944
                case '3':
945
                case '4':
946
                case '5':
947
                case '6':
948
                case '7':
949
                case '8':
950
                case '9':
951
                case '-':
952
                    return TOKEN_NUMBER;
953
                case ':':
954
                    return TOKEN_COLON;
955
            }
956
            index--;
957
            int remainingLength = json.Length - index;
958
            // false
959
            if (remainingLength >= 5)
960
            {
961
                if (json[index] == 'f' && json[index + 1] == 'a' && json[index + 2] == 'l' && json[index + 3] == 's' && json[index + 4] == 'e')
962
                {
963
                    index += 5;
964
                    return TOKEN_FALSE;
965
                }
966
            }
967
            // true
968
            if (remainingLength >= 4)
969
            {
970
                if (json[index] == 't' && json[index + 1] == 'r' && json[index + 2] == 'u' && json[index + 3] == 'e')
971
                {
972
                    index += 4;
973
                    return TOKEN_TRUE;
974
                }
975
            }
976
            // null
977
            if (remainingLength >= 4)
978
            {
979
                if (json[index] == 'n' && json[index + 1] == 'u' && json[index + 2] == 'l' && json[index + 3] == 'l')
980
                {
981
                    index += 4;
982
                    return TOKEN_NULL;
983
                }
984
            }
985
            return TOKEN_NONE;
986
        }
987

  
988
        static bool SerializeValue(IJsonSerializerStrategy jsonSerializerStrategy, object value, StringBuilder builder)
989
        {
990
            bool success = true;
991
            string stringValue = value as string;
992
            if (stringValue != null)
993
                success = SerializeString(stringValue, builder);
994
            else
995
            {
996
                IDictionary<string, object> dict = value as IDictionary<string, object>;
997
                if (dict != null)
998
                {
999
                    success = SerializeObject(jsonSerializerStrategy, dict.Keys, dict.Values, builder);
1000
                }
1001
                else
1002
                {
1003
                    IDictionary<string, string> stringDictionary = value as IDictionary<string, string>;
1004
                    if (stringDictionary != null)
1005
                    {
1006
                        success = SerializeObject(jsonSerializerStrategy, stringDictionary.Keys, stringDictionary.Values, builder);
1007
                    }
1008
                    else
1009
                    {
1010
                        IEnumerable enumerableValue = value as IEnumerable;
1011
                        if (enumerableValue != null)
1012
                            success = SerializeArray(jsonSerializerStrategy, enumerableValue, builder);
1013
                        else if (IsNumeric(value))
1014
                            success = SerializeNumber(value, builder);
1015
                        else if (value is bool)
1016
                            builder.Append((bool)value ? "true" : "false");
1017
                        else if (value == null)
1018
                            builder.Append("null");
1019
                        else
1020
                        {
1021
                            object serializedObject;
1022
                            success = jsonSerializerStrategy.TrySerializeNonPrimitiveObject(value, out serializedObject);
1023
                            if (success)
1024
                                SerializeValue(jsonSerializerStrategy, serializedObject, builder);
1025
                        }
1026
                    }
1027
                }
1028
            }
1029
            return success;
1030
        }
1031

  
1032
        static bool SerializeObject(IJsonSerializerStrategy jsonSerializerStrategy, IEnumerable keys, IEnumerable values, StringBuilder builder)
1033
        {
1034
            builder.Append("{");
1035
            IEnumerator ke = keys.GetEnumerator();
1036
            IEnumerator ve = values.GetEnumerator();
1037
            bool first = true;
1038
            while (ke.MoveNext() && ve.MoveNext())
1039
            {
1040
                object key = ke.Current;
1041
                object value = ve.Current;
1042
                if (!first)
1043
                    builder.Append(",");
1044
                string stringKey = key as string;
1045
                if (stringKey != null)
1046
                    SerializeString(stringKey, builder);
1047
                else
1048
                    if (!SerializeValue(jsonSerializerStrategy, value, builder)) return false;
1049
                builder.Append(":");
1050
                if (!SerializeValue(jsonSerializerStrategy, value, builder))
1051
                    return false;
1052
                first = false;
1053
            }
1054
            builder.Append("}");
1055
            return true;
1056
        }
1057

  
1058
        static bool SerializeArray(IJsonSerializerStrategy jsonSerializerStrategy, IEnumerable anArray, StringBuilder builder)
1059
        {
1060
            builder.Append("[");
1061
            bool first = true;
1062
            foreach (object value in anArray)
1063
            {
1064
                if (!first)
1065
                    builder.Append(",");
1066
                if (!SerializeValue(jsonSerializerStrategy, value, builder))
1067
                    return false;
1068
                first = false;
1069
            }
1070
            builder.Append("]");
1071
            return true;
1072
        }
1073

  
1074
        static bool SerializeString(string aString, StringBuilder builder)
1075
        {
1076
            builder.Append("\"");
1077
            char[] charArray = aString.ToCharArray();
1078
            for (int i = 0; i < charArray.Length; i++)
1079
            {
1080
                char c = charArray[i];
1081
                if (c == '"')
1082
                    builder.Append("\\\"");
1083
                else if (c == '\\')
1084
                    builder.Append("\\\\");
1085
                else if (c == '\b')
1086
                    builder.Append("\\b");
1087
                else if (c == '\f')
1088
                    builder.Append("\\f");
1089
                else if (c == '\n')
1090
                    builder.Append("\\n");
1091
                else if (c == '\r')
1092
                    builder.Append("\\r");
1093
                else if (c == '\t')
1094
                    builder.Append("\\t");
1095
                else
1096
                    builder.Append(c);
1097
            }
1098
            builder.Append("\"");
1099
            return true;
1100
        }
1101

  
1102
        static bool SerializeNumber(object number, StringBuilder builder)
1103
        {
1104
            if (number is long)
1105
                builder.Append(((long)number).ToString(CultureInfo.InvariantCulture));
1106
            else if (number is ulong)
1107
                builder.Append(((ulong)number).ToString(CultureInfo.InvariantCulture));
1108
            else if (number is int)
1109
                builder.Append(((int)number).ToString(CultureInfo.InvariantCulture));
1110
            else if (number is uint)
1111
                builder.Append(((uint)number).ToString(CultureInfo.InvariantCulture));
1112
            else if (number is decimal)
1113
                builder.Append(((decimal)number).ToString(CultureInfo.InvariantCulture));
1114
            else if (number is float)
1115
                builder.Append(((float)number).ToString(CultureInfo.InvariantCulture));
1116
            else
1117
                builder.Append(Convert.ToDouble(number, CultureInfo.InvariantCulture).ToString("r", CultureInfo.InvariantCulture));
1118
            return true;
1119
        }
1120

  
1121
        /// <summary>
1122
        /// Determines if a given object is numeric in any way
1123
        /// (can be integer, double, null, etc).
1124
        /// </summary>
1125
        static bool IsNumeric(object value)
1126
        {
1127
            if (value is sbyte) return true;
1128
            if (value is byte) return true;
1129
            if (value is short) return true;
1130
            if (value is ushort) return true;
1131
            if (value is int) return true;
1132
            if (value is uint) return true;
1133
            if (value is long) return true;
1134
            if (value is ulong) return true;
1135
            if (value is float) return true;
1136
            if (value is double) return true;
1137
            if (value is decimal) return true;
1138
            return false;
1139
        }
1140

  
1141
        private static IJsonSerializerStrategy _currentJsonSerializerStrategy;
1142
        public static IJsonSerializerStrategy CurrentJsonSerializerStrategy
1143
        {
1144
            get
1145
            {
1146
                return _currentJsonSerializerStrategy ??
1147
                    (_currentJsonSerializerStrategy =
1148
#if SIMPLE_JSON_DATACONTRACT
1149
 DataContractJsonSerializerStrategy
1150
#else
1151
 PocoJsonSerializerStrategy
1152
#endif
1153
);
1154
            }
1155
            set
1156
            {
1157
                _currentJsonSerializerStrategy = value;
1158
            }
1159
        }
1160

  
1161
        private static PocoJsonSerializerStrategy _pocoJsonSerializerStrategy;
1162
        [EditorBrowsable(EditorBrowsableState.Advanced)]
1163
        public static PocoJsonSerializerStrategy PocoJsonSerializerStrategy
1164
        {
1165
            get
1166
            {
1167
                return _pocoJsonSerializerStrategy ?? (_pocoJsonSerializerStrategy = new PocoJsonSerializerStrategy());
1168
            }
1169
        }
1170

  
1171
#if SIMPLE_JSON_DATACONTRACT
1172

  
1173
        private static DataContractJsonSerializerStrategy _dataContractJsonSerializerStrategy;
1174
        [System.ComponentModel.EditorBrowsable(EditorBrowsableState.Advanced)]
1175
        public static DataContractJsonSerializerStrategy DataContractJsonSerializerStrategy
1176
        {
1177
            get
1178
            {
1179
                return _dataContractJsonSerializerStrategy ?? (_dataContractJsonSerializerStrategy = new DataContractJsonSerializerStrategy());
1180
            }
1181
        }
1182

  
1183
#endif
1184
    }
1185
    
1186
    [GeneratedCode("simple-json", "1.0.0")]
1187
#if SIMPLE_JSON_INTERNAL
1188
    internal
1189
#else
1190
    public
1191
#endif
1192
 interface IJsonSerializerStrategy
1193
    {
1194
        [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification="Need to support .NET 2")]
1195
        bool TrySerializeNonPrimitiveObject(object input, out object output);
1196
        object DeserializeObject(object value, Type type);
1197
    }
1198

  
1199
    [GeneratedCode("simple-json", "1.0.0")]
1200
#if SIMPLE_JSON_INTERNAL
1201
    internal
1202
#else
1203
    public
1204
#endif
1205
 class PocoJsonSerializerStrategy : IJsonSerializerStrategy
1206
    {
1207
        internal IDictionary<Type, ReflectionUtils.ConstructorDelegate> ConstructorCache;
1208
        internal IDictionary<Type, IDictionary<string, ReflectionUtils.GetDelegate>> GetCache;
1209
        internal IDictionary<Type, IDictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>>> SetCache;
1210

  
1211
        internal static readonly Type[] EmptyTypes = new Type[0];
1212
        internal static readonly Type[] ArrayConstructorParameterTypes = new Type[] { typeof(int) };
1213

  
1214
        private static readonly string[] Iso8601Format = new string[]
1215
                                                             {
1216
                                                                 @"yyyy-MM-dd\THH:mm:ss.FFFFFFF\Z",
1217
                                                                 @"yyyy-MM-dd\THH:mm:ss\Z",
1218
                                                                 @"yyyy-MM-dd\THH:mm:ssK"
1219
                                                             };
1220

  
1221
        public PocoJsonSerializerStrategy()
1222
        {
1223
            ConstructorCache = new ReflectionUtils.ThreadSafeDictionary<Type, ReflectionUtils.ConstructorDelegate>(ContructorDelegateFactory);
1224
            GetCache = new ReflectionUtils.ThreadSafeDictionary<Type, IDictionary<string, ReflectionUtils.GetDelegate>>(GetterValueFactory);
1225
            SetCache = new ReflectionUtils.ThreadSafeDictionary<Type, IDictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>>>(SetterValueFactory);
1226
        }
1227

  
1228
        protected virtual string MapClrMemberNameToJsonFieldName(string clrPropertyName)
1229
        {
1230
            return clrPropertyName;
1231
        }
1232

  
1233
        internal virtual ReflectionUtils.ConstructorDelegate ContructorDelegateFactory(Type key)
1234
        {
1235
            return ReflectionUtils.GetContructor(key, key.IsArray ? ArrayConstructorParameterTypes : EmptyTypes);
1236
        }
1237

  
1238
        internal virtual IDictionary<string, ReflectionUtils.GetDelegate> GetterValueFactory(Type type)
1239
        {
1240
            IDictionary<string, ReflectionUtils.GetDelegate> result = new Dictionary<string, ReflectionUtils.GetDelegate>();
1241
            foreach (PropertyInfo propertyInfo in ReflectionUtils.GetProperties(type))
1242
            {
1243
                if (propertyInfo.CanRead)
1244
                {
1245
                    MethodInfo getMethod = ReflectionUtils.GetGetterMethodInfo(propertyInfo);
1246
                    if (getMethod.IsStatic || !getMethod.IsPublic)
1247
                        continue;
1248
                    result[MapClrMemberNameToJsonFieldName(propertyInfo.Name)] = ReflectionUtils.GetGetMethod(propertyInfo);
1249
                }
1250
            }
1251
            foreach (FieldInfo fieldInfo in ReflectionUtils.GetFields(type))
1252
            {
1253
                if (fieldInfo.IsStatic || !fieldInfo.IsPublic)
1254
                    continue;
1255
                result[MapClrMemberNameToJsonFieldName(fieldInfo.Name)] = ReflectionUtils.GetGetMethod(fieldInfo);
1256
            }
1257
            return result;
1258
        }
1259

  
1260
        internal virtual IDictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>> SetterValueFactory(Type type)
1261
        {
1262
            IDictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>> result = new Dictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>>();
1263
            foreach (PropertyInfo propertyInfo in ReflectionUtils.GetProperties(type))
1264
            {
1265
                if (propertyInfo.CanWrite)
1266
                {
1267
                    MethodInfo setMethod = ReflectionUtils.GetSetterMethodInfo(propertyInfo);
1268
                    if (setMethod.IsStatic || !setMethod.IsPublic)
1269
                        continue;
1270
                    result[MapClrMemberNameToJsonFieldName(propertyInfo.Name)] = new KeyValuePair<Type, ReflectionUtils.SetDelegate>(propertyInfo.PropertyType, ReflectionUtils.GetSetMethod(propertyInfo));
1271
                }
1272
            }
1273
            foreach (FieldInfo fieldInfo in ReflectionUtils.GetFields(type))
1274
            {
1275
                if (fieldInfo.IsInitOnly || fieldInfo.IsStatic || !fieldInfo.IsPublic)
1276
                    continue;
1277
                result[MapClrMemberNameToJsonFieldName(fieldInfo.Name)] = new KeyValuePair<Type, ReflectionUtils.SetDelegate>(fieldInfo.FieldType, ReflectionUtils.GetSetMethod(fieldInfo));
1278
            }
1279
            return result;
1280
        }
1281

  
1282
        public virtual bool TrySerializeNonPrimitiveObject(object input, out object output)
1283
        {
1284
            return TrySerializeKnownTypes(input, out output) || TrySerializeUnknownTypes(input, out output);
1285
        }
1286

  
1287
        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
1288
        public virtual object DeserializeObject(object value, Type type)
1289
        {
1290
            if (type == null) throw new ArgumentNullException("type");
1291
            string str = value as string;
1292

  
1293
            if (type == typeof (Guid) && string.IsNullOrEmpty(str))
1294
                return default(Guid);
1295

  
1296
            if (value == null)
1297
                return null;
1298
            
1299
            object obj = null;
1300

  
1301
            if (str != null)
1302
            {
1303
                if (str.Length != 0) // We know it can't be null now.
1304
                {
1305
                    if (type == typeof(DateTime) || (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(DateTime)))
1306
                        return DateTime.ParseExact(str, Iso8601Format, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
1307
                    if (type == typeof(DateTimeOffset) || (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(DateTimeOffset)))
1308
                        return DateTimeOffset.ParseExact(str, Iso8601Format, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
1309
                    if (type == typeof(Guid) || (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(Guid)))
1310
                        return new Guid(str);
1311
                    if (type == typeof(Uri))
1312
                    {
1313
                        bool isValid =  Uri.IsWellFormedUriString(str, UriKind.RelativeOrAbsolute);
1314

  
1315
                        Uri result;
1316
                        if (isValid && Uri.TryCreate(str, UriKind.RelativeOrAbsolute, out result))
1317
                            return result;
1318
                    }
1319
                    return str;
1320
                }
1321
                else
1322
                {
1323
                    if (type == typeof(Guid))
1324
                        obj = default(Guid);
1325
                    else if (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(Guid))
1326
                        obj = null;
1327
                    else
1328
                        obj = str;
1329
                }
1330
                // Empty string case
1331
                if (!ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(Guid))
1332
                    return str;
1333
            }
1334
            else if (value is bool)
1335
                return value;
1336
            
1337
            bool valueIsLong = value is long;
1338
            bool valueIsDouble = value is double;
1339
            if ((valueIsLong && type == typeof(long)) || (valueIsDouble && type == typeof(double)))
1340
                return value;
1341
            if ((valueIsDouble && type != typeof(double)) || (valueIsLong && type != typeof(long)))
1342
            {
1343
                obj = type == typeof(int) || type == typeof(long) || type == typeof(double) || type == typeof(float) || type == typeof(bool) || type == typeof(decimal) || type == typeof(byte) || type == typeof(short)
1344
                            ? Convert.ChangeType(value, type, CultureInfo.InvariantCulture)
1345
                            : value;
1346
            }
1347
            else
1348
            {
1349
                IDictionary<string, object> objects = value as IDictionary<string, object>;
1350
                if (objects != null)
1351
                {
1352
                    IDictionary<string, object> jsonObject = objects;
1353

  
1354
                    if (ReflectionUtils.IsTypeDictionary(type))
1355
                    {
1356
                        // if dictionary then
1357
                        Type[] types = ReflectionUtils.GetGenericTypeArguments(type);
1358
                        Type keyType = types[0];
1359
                        Type valueType = types[1];
1360

  
1361
                        Type genericType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType);
1362

  
1363
                        IDictionary dict = (IDictionary)ConstructorCache[genericType]();
1364

  
1365
                        foreach (KeyValuePair<string, object> kvp in jsonObject)
1366
                            dict.Add(kvp.Key, DeserializeObject(kvp.Value, valueType));
1367

  
1368
                        obj = dict;
1369
                    }
1370
                    else
1371
                    {
1372
                        if (type == typeof(object))
1373
                            obj = value;
1374
                        else
1375
                        {
1376
                            obj = ConstructorCache[type]();
1377
                            foreach (KeyValuePair<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>> setter in SetCache[type])
1378
                            {
1379
                                object jsonValue;
1380
                                if (jsonObject.TryGetValue(setter.Key, out jsonValue))
1381
                                {
1382
                                    jsonValue = DeserializeObject(jsonValue, setter.Value.Key);
1383
                                    setter.Value.Value(obj, jsonValue);
1384
                                }
1385
                            }
1386
                        }
1387
                    }
1388
                }
1389
                else
1390
                {
1391
                    IList<object> valueAsList = value as IList<object>;
1392
                    if (valueAsList != null)
1393
                    {
1394
                        IList<object> jsonObject = valueAsList;
1395
                        IList list = null;
1396

  
1397
                        if (type.IsArray)
1398
                        {
1399
                            list = (IList)ConstructorCache[type](jsonObject.Count);
1400
                            int i = 0;
1401
                            foreach (object o in jsonObject)
1402
                                list[i++] = DeserializeObject(o, type.GetElementType());
1403
                        }
1404
                        else if (ReflectionUtils.IsTypeGenericeCollectionInterface(type) || ReflectionUtils.IsAssignableFrom(typeof(IList), type))
1405
                        {
1406
                            Type innerType = ReflectionUtils.GetGenericListElementType(type);
1407
                            list = (IList)(ConstructorCache[type] ?? ConstructorCache[typeof(List<>).MakeGenericType(innerType)])(jsonObject.Count);
1408
                            foreach (object o in jsonObject)
1409
                                list.Add(DeserializeObject(o, innerType));
1410
                        }
1411
                        obj = list;
1412
                    }
1413
                }
1414
                return obj;
1415
            }
1416
            if (ReflectionUtils.IsNullableType(type))
1417
                return ReflectionUtils.ToNullableType(obj, type);
1418
            return obj;
1419
        }
1420

  
1421
        protected virtual object SerializeEnum(Enum p)
1422
        {
1423
            return Convert.ToDouble(p, CultureInfo.InvariantCulture);
1424
        }
1425

  
1426
        [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification="Need to support .NET 2")]
1427
        protected virtual bool TrySerializeKnownTypes(object input, out object output)
1428
        {
1429
            bool returnValue = true;
1430
            if (input is DateTime)
1431
                output = ((DateTime)input).ToUniversalTime().ToString(Iso8601Format[0], CultureInfo.InvariantCulture);
1432
            else if (input is DateTimeOffset)
1433
                output = ((DateTimeOffset)input).ToUniversalTime().ToString(Iso8601Format[0], CultureInfo.InvariantCulture);
1434
            else if (input is Guid)
1435
                output = ((Guid)input).ToString("D");
1436
            else if (input is Uri)
1437
                output = input.ToString();
1438
            else
1439
            {
1440
                Enum inputEnum = input as Enum;
1441
                if (inputEnum != null)
1442
                    output = SerializeEnum(inputEnum);
1443
                else
1444
                {
1445
                    returnValue = false;
1446
                    output = null;
1447
                }
1448
            }
1449
            return returnValue;
1450
        }
1451
        [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification="Need to support .NET 2")]
1452
        protected virtual bool TrySerializeUnknownTypes(object input, out object output)
1453
        {
1454
            if (input == null) throw new ArgumentNullException("input");
1455
            output = null;
1456
            Type type = input.GetType();
1457
            if (type.FullName == null)
1458
                return false;
1459
            IDictionary<string, object> obj = new JsonObject();
1460
            IDictionary<string, ReflectionUtils.GetDelegate> getters = GetCache[type];
1461
            foreach (KeyValuePair<string, ReflectionUtils.GetDelegate> getter in getters)
1462
            {
1463
                if (getter.Value != null)
1464
                    obj.Add(MapClrMemberNameToJsonFieldName(getter.Key), getter.Value(input));
1465
            }
1466
            output = obj;
1467
            return true;
1468
        }
1469
    }
1470

  
1471
#if SIMPLE_JSON_DATACONTRACT
1472
    [GeneratedCode("simple-json", "1.0.0")]
1473
#if SIMPLE_JSON_INTERNAL
1474
    internal
1475
#else
1476
    public
1477
#endif
1478
 class DataContractJsonSerializerStrategy : PocoJsonSerializerStrategy
1479
    {
1480
        public DataContractJsonSerializerStrategy()
1481
        {
1482
            GetCache = new ReflectionUtils.ThreadSafeDictionary<Type, IDictionary<string, ReflectionUtils.GetDelegate>>(GetterValueFactory);
1483
            SetCache = new ReflectionUtils.ThreadSafeDictionary<Type, IDictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>>>(SetterValueFactory);
1484
        }
1485

  
1486
        internal override IDictionary<string, ReflectionUtils.GetDelegate> GetterValueFactory(Type type)
1487
        {
1488
            bool hasDataContract = ReflectionUtils.GetAttribute(type, typeof(DataContractAttribute)) != null;
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff