aboutsummaryrefslogtreecommitdiff
path: root/src/internal/MessagesToMessages
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-04-22 16:36:39 -0700
committerRob Mensching <rob@firegiant.com>2021-04-22 16:50:15 -0700
commit6a24996a2e831cfe402398af65b31fb1ecd575a9 (patch)
treee377370df4bc7901745c6b5f50268fa665edb3f8 /src/internal/MessagesToMessages
parent2587a8b46b705d53156f5cd1bd866f855049081d (diff)
downloadwix-6a24996a2e831cfe402398af65b31fb1ecd575a9.tar.gz
wix-6a24996a2e831cfe402398af65b31fb1ecd575a9.tar.bz2
wix-6a24996a2e831cfe402398af65b31fb1ecd575a9.zip
Move WixBuildTools into internal
Diffstat (limited to 'src/internal/MessagesToMessages')
-rw-r--r--src/internal/MessagesToMessages/MessagesToMessages.csproj8
-rw-r--r--src/internal/MessagesToMessages/Program.cs261
-rw-r--r--src/internal/MessagesToMessages/Properties/launchSettings.json9
-rw-r--r--src/internal/MessagesToMessages/SimpleJson.cs2127
4 files changed, 2405 insertions, 0 deletions
diff --git a/src/internal/MessagesToMessages/MessagesToMessages.csproj b/src/internal/MessagesToMessages/MessagesToMessages.csproj
new file mode 100644
index 00000000..ce1697ae
--- /dev/null
+++ b/src/internal/MessagesToMessages/MessagesToMessages.csproj
@@ -0,0 +1,8 @@
1<Project Sdk="Microsoft.NET.Sdk">
2
3 <PropertyGroup>
4 <OutputType>Exe</OutputType>
5 <TargetFramework>netcoreapp2.0</TargetFramework>
6 </PropertyGroup>
7
8</Project>
diff --git a/src/internal/MessagesToMessages/Program.cs b/src/internal/MessagesToMessages/Program.cs
new file mode 100644
index 00000000..2d5a3777
--- /dev/null
+++ b/src/internal/MessagesToMessages/Program.cs
@@ -0,0 +1,261 @@
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Linq;
5using System.Text;
6using System.Xml.Linq;
7
8namespace MessagesToMessages
9{
10 class Program
11 {
12 static readonly XNamespace ns = "http://schemas.microsoft.com/genmsgs/2004/07/messages";
13 static readonly XName ClassDefinition = ns + "Class";
14 static readonly XName MessageDefinition = ns + "Message";
15 static readonly XName InstanceDefinition = ns + "Instance";
16 static readonly XName ParameterDefinition = ns + "Parameter";
17 static readonly XName Id = "Id";
18 static readonly XName Level = "Level";
19 static readonly XName Number = "Number";
20 static readonly XName SourceLineNumbers = "SourceLineNumbers";
21 static readonly XName Type = "Type";
22 static readonly XName Name = "Name";
23
24 static void Main(string[] args)
25 {
26 if (args.Length == 0)
27 {
28 return;
29 }
30 else if (args.Length < 2)
31 {
32 Console.WriteLine("Need to specify output folder as well.");
33 }
34 else if (!Directory.Exists(args[1]))
35 {
36 Console.WriteLine("Output folder does not exist: {0}", args[1]);
37 }
38
39 var messages = ReadXml(Path.GetFullPath(args[0]));
40
41 foreach (var m in messages.GroupBy(m => m.Level))
42 {
43 var className = m.First().ClassName;
44 var result = GenerateCs(className, m.Key, m);
45
46 var path = Path.Combine(args[1], className + ".cs");
47 File.WriteAllText(path, result);
48 }
49 }
50
51 private static IEnumerable<Message> ReadXml(string inputPath)
52 {
53 var doc = XDocument.Load(inputPath);
54
55 foreach (var xClass in doc.Root.Descendants(ClassDefinition))
56 {
57 var name = xClass.Attribute(Name)?.Value;
58 var level = xClass.Attribute(Level)?.Value;
59
60 if (String.IsNullOrEmpty(name))
61 {
62 name = level + "Messages";
63 }
64 if (String.IsNullOrEmpty(level))
65 {
66 if (name.EndsWith("Errors", StringComparison.InvariantCultureIgnoreCase))
67 {
68 level = "Error";
69 }
70 else if (name.EndsWith("Verboses", StringComparison.InvariantCultureIgnoreCase))
71 {
72 level = "Verbose";
73 }
74 else if (name.EndsWith("Warnings", StringComparison.InvariantCultureIgnoreCase))
75 {
76 level = "Warning";
77 }
78 }
79
80 var unique = new HashSet<string>();
81 var lastNumber = 0;
82 foreach (var xMessage in xClass.Elements(MessageDefinition))
83 {
84 var id = xMessage.Attribute(Id).Value;
85
86 if (!unique.Add(id))
87 {
88 Console.WriteLine("Duplicated message: {0}", id);
89 }
90
91 if (!Int32.TryParse(xMessage.Attribute(Number)?.Value, out var number))
92 {
93 number = lastNumber;
94 }
95 lastNumber = number + 1;
96
97 var sln = xMessage.Attribute(SourceLineNumbers)?.Value != "no";
98
99 var suffix = 0;
100 foreach (var xInstance in xMessage.Elements(InstanceDefinition))
101 {
102 var value = xInstance.Value.Trim();
103
104 var parameters = xInstance.Elements(ParameterDefinition).Select(ReadParameter).ToList();
105
106 yield return new Message { Id = id, ClassName = name, Level = level, Number = number, Parameters = parameters, SourceLineNumbers = sln, Value = value, Suffix = suffix == 0 ? String.Empty : suffix.ToString() };
107
108 ++suffix;
109 }
110 }
111 }
112 }
113
114 private static Parameter ReadParameter(XElement element)
115 {
116 var name = element.Attribute(Name)?.Value;
117 var type = element.Attribute(Type)?.Value ?? "string";
118
119 if (type.StartsWith("System."))
120 {
121 type = type.Substring(7);
122 }
123
124 switch (type)
125 {
126 case "String":
127 type = "string";
128 break;
129
130 case "Int32":
131 type = "int";
132 break;
133
134 case "Int64":
135 type = "long";
136 break;
137 }
138
139 return new Parameter { Name = name, Type = type };
140 }
141
142 private static string GenerateCs(string className, string level, IEnumerable<Message> messages)
143 {
144 var header = String.Join(Environment.NewLine,
145 "// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.",
146 "",
147 "namespace WixToolset.Data",
148 "{",
149 " using System;",
150 " using System.Resources;",
151 "",
152 " public static class {0}",
153 " {");
154
155 var messageFormat = String.Join(Environment.NewLine,
156 " public static Message {0}({1})",
157 " {{",
158 " return Message({4}, Ids.{0}, \"{3}\"{2});",
159 " }}",
160 "");
161
162
163 var endMessagesFormat = String.Join(Environment.NewLine,
164 " private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args)",
165 " {{",
166 " return new Message(sourceLineNumber, MessageLevel.{0}, (int)id, format, args);",
167 " }}",
168 "",
169 " private static Message Message(SourceLineNumber sourceLineNumber, Ids id, ResourceManager resourceManager, string resourceName, params object[] args)",
170 " {{",
171 " return new Message(sourceLineNumber, MessageLevel.{0}, (int)id, resourceManager, resourceName, args);",
172 " }}",
173 "",
174 " public enum Ids",
175 " {{");
176
177 var idEnumFormat =
178 " {0} = {1},";
179 var footer = String.Join(Environment.NewLine,
180 " }",
181 " }",
182 "}",
183 "");
184
185 var sb = new StringBuilder();
186
187 sb.AppendLine(header.Replace("{0}", className));
188
189 foreach (var message in messages.OrderBy(m => m.Id))
190 {
191 var paramsWithTypes = String.Join(", ", message.Parameters.Select(p => $"{p.Type} {p.Name}"));
192 var paramsWithoutTypes = String.Join(", ", message.Parameters.Select(p => p.Name));
193
194 if (message.SourceLineNumbers)
195 {
196 paramsWithTypes = String.IsNullOrEmpty(paramsWithTypes)
197 ? "SourceLineNumber sourceLineNumbers"
198 : "SourceLineNumber sourceLineNumbers, " + paramsWithTypes;
199 }
200
201 if (!String.IsNullOrEmpty(paramsWithoutTypes))
202 {
203 paramsWithoutTypes = ", " + paramsWithoutTypes;
204 }
205
206 sb.AppendFormat(messageFormat, message.Id, paramsWithTypes, paramsWithoutTypes, ToCSharpString(message.Value), message.SourceLineNumbers ? "sourceLineNumbers" : "null");
207
208 sb.AppendLine();
209 }
210
211 sb.AppendFormat(endMessagesFormat, level);
212 sb.AppendLine();
213
214 var unique = new HashSet<int>();
215 foreach (var message in messages.OrderBy(m => m.Number))
216 {
217 if (unique.Add(message.Number))
218 {
219 sb.AppendFormat(idEnumFormat, message.Id, message.Number);
220 sb.AppendLine();
221 }
222 }
223
224 sb.Append(footer);
225
226 return sb.ToString();
227 }
228
229 private static string ToCSharpString(string value)
230 {
231 return value.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\r", "\\r").Replace("\n", "\\n").Replace("\t", "\\t");
232 }
233
234 private class Message
235 {
236 public string Id { get; set; }
237
238 public string Suffix { get; set; }
239
240 public string ClassName { get; set; }
241
242 public string Level { get; set; }
243
244 public int Number { get; set; }
245
246 public bool SourceLineNumbers { get; set; }
247
248 public string Value { get; set; }
249
250 public IEnumerable<Parameter> Parameters { get; set; }
251 }
252
253
254 private class Parameter
255 {
256 public string Name { get; set; }
257
258 public string Type { get; set; }
259 }
260 }
261}
diff --git a/src/internal/MessagesToMessages/Properties/launchSettings.json b/src/internal/MessagesToMessages/Properties/launchSettings.json
new file mode 100644
index 00000000..dc7570f6
--- /dev/null
+++ b/src/internal/MessagesToMessages/Properties/launchSettings.json
@@ -0,0 +1,9 @@
1{
2 "profiles": {
3 "TablesAndSymbols": {
4 "commandName": "Project",
5 "commandLineArgs": "E:\\src\\wixtoolset\\Core\\src\\WixToolset.Core\\Data\\messages.xml E:\\src\\wixtoolset\\Data\\src\\WixToolset.Data",
6 "workingDirectory": "E:\\src\\wixtoolset\\Core\\src\\WixToolset.Core\\"
7 }
8 }
9} \ No newline at end of file
diff --git a/src/internal/MessagesToMessages/SimpleJson.cs b/src/internal/MessagesToMessages/SimpleJson.cs
new file mode 100644
index 00000000..3d956f6e
--- /dev/null
+++ b/src/internal/MessagesToMessages/SimpleJson.cs
@@ -0,0 +1,2127 @@
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 enable IReadOnlyCollection<T> and IReadOnlyList<T> support.
35//#define SIMPLE_JSON_READONLY_COLLECTIONS
36
37// NOTE: uncomment the following line to disable linq expressions/compiled lambda (better performance) instead of method.invoke().
38// define if you are using .net framework <= 3.0 or < WP7.5
39//#define SIMPLE_JSON_NO_LINQ_EXPRESSION
40
41// NOTE: uncomment the following line if you are compiling under Window Metro style application/library.
42// usually already defined in properties
43//#define NETFX_CORE;
44
45// If you are targetting WinStore, WP8 and NET4.5+ PCL make sure to #define SIMPLE_JSON_TYPEINFO;
46
47// 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
48
49#if NETFX_CORE
50#define SIMPLE_JSON_TYPEINFO
51#endif
52
53using System;
54using System.CodeDom.Compiler;
55using System.Collections;
56using System.Collections.Generic;
57#if !SIMPLE_JSON_NO_LINQ_EXPRESSION
58using System.Linq.Expressions;
59#endif
60using System.ComponentModel;
61using System.Diagnostics.CodeAnalysis;
62#if SIMPLE_JSON_DYNAMIC
63using System.Dynamic;
64#endif
65using System.Globalization;
66using System.Reflection;
67using System.Runtime.Serialization;
68using System.Text;
69using SimpleJson.Reflection;
70
71// ReSharper disable LoopCanBeConvertedToQuery
72// ReSharper disable RedundantExplicitArrayCreation
73// ReSharper disable SuggestUseVarKeywordEvident
74namespace SimpleJson
75{
76 /// <summary>
77 /// Represents the json array.
78 /// </summary>
79 [GeneratedCode("simple-json", "1.0.0")]
80 [EditorBrowsable(EditorBrowsableState.Never)]
81 [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
82#if SIMPLE_JSON_OBJARRAYINTERNAL
83 internal
84#else
85 public
86#endif
87 class JsonArray : List<object>
88 {
89 /// <summary>
90 /// Initializes a new instance of the <see cref="JsonArray"/> class.
91 /// </summary>
92 public JsonArray() { }
93
94 /// <summary>
95 /// Initializes a new instance of the <see cref="JsonArray"/> class.
96 /// </summary>
97 /// <param name="capacity">The capacity of the json array.</param>
98 public JsonArray(int capacity) : base(capacity) { }
99
100 /// <summary>
101 /// The json representation of the array.
102 /// </summary>
103 /// <returns>The json representation of the array.</returns>
104 public override string ToString()
105 {
106 return SimpleJson.SerializeObject(this) ?? string.Empty;
107 }
108 }
109
110 /// <summary>
111 /// Represents the json object.
112 /// </summary>
113 [GeneratedCode("simple-json", "1.0.0")]
114 [EditorBrowsable(EditorBrowsableState.Never)]
115 [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
116#if SIMPLE_JSON_OBJARRAYINTERNAL
117 internal
118#else
119 public
120#endif
121 class JsonObject :
122#if SIMPLE_JSON_DYNAMIC
123 DynamicObject,
124#endif
125 IDictionary<string, object>
126 {
127 /// <summary>
128 /// The internal member dictionary.
129 /// </summary>
130 private readonly Dictionary<string, object> _members;
131
132 /// <summary>
133 /// Initializes a new instance of <see cref="JsonObject"/>.
134 /// </summary>
135 public JsonObject()
136 {
137 _members = new Dictionary<string, object>();
138 }
139
140 /// <summary>
141 /// Initializes a new instance of <see cref="JsonObject"/>.
142 /// </summary>
143 /// <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>
144 public JsonObject(IEqualityComparer<string> comparer)
145 {
146 _members = new Dictionary<string, object>(comparer);
147 }
148
149 /// <summary>
150 /// Gets the <see cref="System.Object"/> at the specified index.
151 /// </summary>
152 /// <value></value>
153 public object this[int index]
154 {
155 get { return GetAtIndex(_members, index); }
156 }
157
158 internal static object GetAtIndex(IDictionary<string, object> obj, int index)
159 {
160 if (obj == null)
161 throw new ArgumentNullException("obj");
162 if (index >= obj.Count)
163 throw new ArgumentOutOfRangeException("index");
164 int i = 0;
165 foreach (KeyValuePair<string, object> o in obj)
166 if (i++ == index) return o.Value;
167 return null;
168 }
169
170 /// <summary>
171 /// Adds the specified key.
172 /// </summary>
173 /// <param name="key">The key.</param>
174 /// <param name="value">The value.</param>
175 public void Add(string key, object value)
176 {
177 _members.Add(key, value);
178 }
179
180 /// <summary>
181 /// Determines whether the specified key contains key.
182 /// </summary>
183 /// <param name="key">The key.</param>
184 /// <returns>
185 /// <c>true</c> if the specified key contains key; otherwise, <c>false</c>.
186 /// </returns>
187 public bool ContainsKey(string key)
188 {
189 return _members.ContainsKey(key);
190 }
191
192 /// <summary>
193 /// Gets the keys.
194 /// </summary>
195 /// <value>The keys.</value>
196 public ICollection<string> Keys
197 {
198 get { return _members.Keys; }
199 }
200
201 /// <summary>
202 /// Removes the specified key.
203 /// </summary>
204 /// <param name="key">The key.</param>
205 /// <returns></returns>
206 public bool Remove(string key)
207 {
208 return _members.Remove(key);
209 }
210
211 /// <summary>
212 /// Tries the get value.
213 /// </summary>
214 /// <param name="key">The key.</param>
215 /// <param name="value">The value.</param>
216 /// <returns></returns>
217 public bool TryGetValue(string key, out object value)
218 {
219 return _members.TryGetValue(key, out value);
220 }
221
222 /// <summary>
223 /// Gets the values.
224 /// </summary>
225 /// <value>The values.</value>
226 public ICollection<object> Values
227 {
228 get { return _members.Values; }
229 }
230
231 /// <summary>
232 /// Gets or sets the <see cref="System.Object"/> with the specified key.
233 /// </summary>
234 /// <value></value>
235 public object this[string key]
236 {
237 get { return _members[key]; }
238 set { _members[key] = value; }
239 }
240
241 /// <summary>
242 /// Adds the specified item.
243 /// </summary>
244 /// <param name="item">The item.</param>
245 public void Add(KeyValuePair<string, object> item)
246 {
247 _members.Add(item.Key, item.Value);
248 }
249
250 /// <summary>
251 /// Clears this instance.
252 /// </summary>
253 public void Clear()
254 {
255 _members.Clear();
256 }
257
258 /// <summary>
259 /// Determines whether [contains] [the specified item].
260 /// </summary>
261 /// <param name="item">The item.</param>
262 /// <returns>
263 /// <c>true</c> if [contains] [the specified item]; otherwise, <c>false</c>.
264 /// </returns>
265 public bool Contains(KeyValuePair<string, object> item)
266 {
267 return _members.ContainsKey(item.Key) && _members[item.Key] == item.Value;
268 }
269
270 /// <summary>
271 /// Copies to.
272 /// </summary>
273 /// <param name="array">The array.</param>
274 /// <param name="arrayIndex">Index of the array.</param>
275 public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
276 {
277 if (array == null) throw new ArgumentNullException("array");
278 int num = Count;
279 foreach (KeyValuePair<string, object> kvp in this)
280 {
281 array[arrayIndex++] = kvp;
282 if (--num <= 0)
283 return;
284 }
285 }
286
287 /// <summary>
288 /// Gets the count.
289 /// </summary>
290 /// <value>The count.</value>
291 public int Count
292 {
293 get { return _members.Count; }
294 }
295
296 /// <summary>
297 /// Gets a value indicating whether this instance is read only.
298 /// </summary>
299 /// <value>
300 /// <c>true</c> if this instance is read only; otherwise, <c>false</c>.
301 /// </value>
302 public bool IsReadOnly
303 {
304 get { return false; }
305 }
306
307 /// <summary>
308 /// Removes the specified item.
309 /// </summary>
310 /// <param name="item">The item.</param>
311 /// <returns></returns>
312 public bool Remove(KeyValuePair<string, object> item)
313 {
314 return _members.Remove(item.Key);
315 }
316
317 /// <summary>
318 /// Gets the enumerator.
319 /// </summary>
320 /// <returns></returns>
321 public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
322 {
323 return _members.GetEnumerator();
324 }
325
326 /// <summary>
327 /// Returns an enumerator that iterates through a collection.
328 /// </summary>
329 /// <returns>
330 /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
331 /// </returns>
332 IEnumerator IEnumerable.GetEnumerator()
333 {
334 return _members.GetEnumerator();
335 }
336
337 /// <summary>
338 /// Returns a json <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
339 /// </summary>
340 /// <returns>
341 /// A json <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
342 /// </returns>
343 public override string ToString()
344 {
345 return SimpleJson.SerializeObject(this);
346 }
347
348#if SIMPLE_JSON_DYNAMIC
349 /// <summary>
350 /// 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.
351 /// </summary>
352 /// <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>
353 /// <param name="result">The result of the type conversion operation.</param>
354 /// <returns>
355 /// Alwasy returns true.
356 /// </returns>
357 public override bool TryConvert(ConvertBinder binder, out object result)
358 {
359 // <pex>
360 if (binder == null)
361 throw new ArgumentNullException("binder");
362 // </pex>
363 Type targetType = binder.Type;
364
365 if ((targetType == typeof(IEnumerable)) ||
366 (targetType == typeof(IEnumerable<KeyValuePair<string, object>>)) ||
367 (targetType == typeof(IDictionary<string, object>)) ||
368 (targetType == typeof(IDictionary)))
369 {
370 result = this;
371 return true;
372 }
373
374 return base.TryConvert(binder, out result);
375 }
376
377 /// <summary>
378 /// Provides the implementation for operations that delete an object member. This method is not intended for use in C# or Visual Basic.
379 /// </summary>
380 /// <param name="binder">Provides information about the deletion.</param>
381 /// <returns>
382 /// Alwasy returns true.
383 /// </returns>
384 public override bool TryDeleteMember(DeleteMemberBinder binder)
385 {
386 // <pex>
387 if (binder == null)
388 throw new ArgumentNullException("binder");
389 // </pex>
390 return _members.Remove(binder.Name);
391 }
392
393 /// <summary>
394 /// 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.
395 /// </summary>
396 /// <param name="binder">Provides information about the operation.</param>
397 /// <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>
398 /// <param name="result">The result of the index operation.</param>
399 /// <returns>
400 /// Alwasy returns true.
401 /// </returns>
402 public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
403 {
404 if (indexes == null) throw new ArgumentNullException("indexes");
405 if (indexes.Length == 1)
406 {
407 result = ((IDictionary<string, object>)this)[(string)indexes[0]];
408 return true;
409 }
410 result = null;
411 return true;
412 }
413
414 /// <summary>
415 /// 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.
416 /// </summary>
417 /// <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>
418 /// <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>
419 /// <returns>
420 /// Alwasy returns true.
421 /// </returns>
422 public override bool TryGetMember(GetMemberBinder binder, out object result)
423 {
424 object value;
425 if (_members.TryGetValue(binder.Name, out value))
426 {
427 result = value;
428 return true;
429 }
430 result = null;
431 return true;
432 }
433
434 /// <summary>
435 /// 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.
436 /// </summary>
437 /// <param name="binder">Provides information about the operation.</param>
438 /// <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>
439 /// <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>
440 /// <returns>
441 /// 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.
442 /// </returns>
443 public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
444 {
445 if (indexes == null) throw new ArgumentNullException("indexes");
446 if (indexes.Length == 1)
447 {
448 ((IDictionary<string, object>)this)[(string)indexes[0]] = value;
449 return true;
450 }
451 return base.TrySetIndex(binder, indexes, value);
452 }
453
454 /// <summary>
455 /// 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.
456 /// </summary>
457 /// <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>
458 /// <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>
459 /// <returns>
460 /// 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.)
461 /// </returns>
462 public override bool TrySetMember(SetMemberBinder binder, object value)
463 {
464 // <pex>
465 if (binder == null)
466 throw new ArgumentNullException("binder");
467 // </pex>
468 _members[binder.Name] = value;
469 return true;
470 }
471
472 /// <summary>
473 /// Returns the enumeration of all dynamic member names.
474 /// </summary>
475 /// <returns>
476 /// A sequence that contains dynamic member names.
477 /// </returns>
478 public override IEnumerable<string> GetDynamicMemberNames()
479 {
480 foreach (var key in Keys)
481 yield return key;
482 }
483#endif
484 }
485}
486
487namespace SimpleJson
488{
489 /// <summary>
490 /// This class encodes and decodes JSON strings.
491 /// Spec. details, see http://www.json.org/
492 ///
493 /// JSON uses Arrays and Objects. These correspond here to the datatypes JsonArray(IList&lt;object>) and JsonObject(IDictionary&lt;string,object>).
494 /// All numbers are parsed to doubles.
495 /// </summary>
496 [GeneratedCode("simple-json", "1.0.0")]
497#if SIMPLE_JSON_INTERNAL
498 internal
499#else
500 public
501#endif
502 static class SimpleJson
503 {
504 private const int TOKEN_NONE = 0;
505 private const int TOKEN_CURLY_OPEN = 1;
506 private const int TOKEN_CURLY_CLOSE = 2;
507 private const int TOKEN_SQUARED_OPEN = 3;
508 private const int TOKEN_SQUARED_CLOSE = 4;
509 private const int TOKEN_COLON = 5;
510 private const int TOKEN_COMMA = 6;
511 private const int TOKEN_STRING = 7;
512 private const int TOKEN_NUMBER = 8;
513 private const int TOKEN_TRUE = 9;
514 private const int TOKEN_FALSE = 10;
515 private const int TOKEN_NULL = 11;
516 private const int BUILDER_CAPACITY = 2000;
517
518 private static readonly char[] EscapeTable;
519 private static readonly char[] EscapeCharacters = new char[] { '"', '\\', '\b', '\f', '\n', '\r', '\t' };
520 private static readonly string EscapeCharactersString = new string(EscapeCharacters);
521
522 static SimpleJson()
523 {
524 EscapeTable = new char[93];
525 EscapeTable['"'] = '"';
526 EscapeTable['\\'] = '\\';
527 EscapeTable['\b'] = 'b';
528 EscapeTable['\f'] = 'f';
529 EscapeTable['\n'] = 'n';
530 EscapeTable['\r'] = 'r';
531 EscapeTable['\t'] = 't';
532 }
533
534 /// <summary>
535 /// Parses the string json into a value
536 /// </summary>
537 /// <param name="json">A JSON string.</param>
538 /// <returns>An IList&lt;object>, a IDictionary&lt;string,object>, a double, a string, null, true, or false</returns>
539 public static object DeserializeObject(string json)
540 {
541 object obj;
542 if (TryDeserializeObject(json, out obj))
543 return obj;
544 throw new SerializationException("Invalid JSON string");
545 }
546
547 /// <summary>
548 /// Try parsing the json string into a value.
549 /// </summary>
550 /// <param name="json">
551 /// A JSON string.
552 /// </param>
553 /// <param name="obj">
554 /// The object.
555 /// </param>
556 /// <returns>
557 /// Returns true if successfull otherwise false.
558 /// </returns>
559 [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification = "Need to support .NET 2")]
560 public static bool TryDeserializeObject(string json, out object obj)
561 {
562 bool success = true;
563 if (json != null)
564 {
565 char[] charArray = json.ToCharArray();
566 int index = 0;
567 obj = ParseValue(charArray, ref index, ref success);
568 }
569 else
570 obj = null;
571
572 return success;
573 }
574
575 public static object DeserializeObject(string json, Type type, IJsonSerializerStrategy jsonSerializerStrategy)
576 {
577 object jsonObject = DeserializeObject(json);
578 return type == null || jsonObject != null && ReflectionUtils.IsAssignableFrom(jsonObject.GetType(), type)
579 ? jsonObject
580 : (jsonSerializerStrategy ?? CurrentJsonSerializerStrategy).DeserializeObject(jsonObject, type);
581 }
582
583 public static object DeserializeObject(string json, Type type)
584 {
585 return DeserializeObject(json, type, null);
586 }
587
588 public static T DeserializeObject<T>(string json, IJsonSerializerStrategy jsonSerializerStrategy)
589 {
590 return (T)DeserializeObject(json, typeof(T), jsonSerializerStrategy);
591 }
592
593 public static T DeserializeObject<T>(string json)
594 {
595 return (T)DeserializeObject(json, typeof(T), null);
596 }
597
598 /// <summary>
599 /// Converts a IDictionary&lt;string,object> / IList&lt;object> object into a JSON string
600 /// </summary>
601 /// <param name="json">A IDictionary&lt;string,object> / IList&lt;object></param>
602 /// <param name="jsonSerializerStrategy">Serializer strategy to use</param>
603 /// <returns>A JSON encoded string, or null if object 'json' is not serializable</returns>
604 public static string SerializeObject(object json, IJsonSerializerStrategy jsonSerializerStrategy)
605 {
606 StringBuilder builder = new StringBuilder(BUILDER_CAPACITY);
607 bool success = SerializeValue(jsonSerializerStrategy, json, builder);
608 return (success ? builder.ToString() : null);
609 }
610
611 public static string SerializeObject(object json)
612 {
613 return SerializeObject(json, CurrentJsonSerializerStrategy);
614 }
615
616 public static string EscapeToJavascriptString(string jsonString)
617 {
618 if (string.IsNullOrEmpty(jsonString))
619 return jsonString;
620
621 StringBuilder sb = new StringBuilder();
622 char c;
623
624 for (int i = 0; i < jsonString.Length;)
625 {
626 c = jsonString[i++];
627
628 if (c == '\\')
629 {
630 int remainingLength = jsonString.Length - i;
631 if (remainingLength >= 2)
632 {
633 char lookahead = jsonString[i];
634 if (lookahead == '\\')
635 {
636 sb.Append('\\');
637 ++i;
638 }
639 else if (lookahead == '"')
640 {
641 sb.Append("\"");
642 ++i;
643 }
644 else if (lookahead == 't')
645 {
646 sb.Append('\t');
647 ++i;
648 }
649 else if (lookahead == 'b')
650 {
651 sb.Append('\b');
652 ++i;
653 }
654 else if (lookahead == 'n')
655 {
656 sb.Append('\n');
657 ++i;
658 }
659 else if (lookahead == 'r')
660 {
661 sb.Append('\r');
662 ++i;
663 }
664 }
665 }
666 else
667 {
668 sb.Append(c);
669 }
670 }
671 return sb.ToString();
672 }
673
674 static IDictionary<string, object> ParseObject(char[] json, ref int index, ref bool success)
675 {
676 IDictionary<string, object> table = new JsonObject();
677 int token;
678
679 // {
680 NextToken(json, ref index);
681
682 bool done = false;
683 while (!done)
684 {
685 token = LookAhead(json, index);
686 if (token == TOKEN_NONE)
687 {
688 success = false;
689 return null;
690 }
691 else if (token == TOKEN_COMMA)
692 NextToken(json, ref index);
693 else if (token == TOKEN_CURLY_CLOSE)
694 {
695 NextToken(json, ref index);
696 return table;
697 }
698 else
699 {
700 // name
701 string name = ParseString(json, ref index, ref success);
702 if (!success)
703 {
704 success = false;
705 return null;
706 }
707 // :
708 token = NextToken(json, ref index);
709 if (token != TOKEN_COLON)
710 {
711 success = false;
712 return null;
713 }
714 // value
715 object value = ParseValue(json, ref index, ref success);
716 if (!success)
717 {
718 success = false;
719 return null;
720 }
721 table[name] = value;
722 }
723 }
724 return table;
725 }
726
727 static JsonArray ParseArray(char[] json, ref int index, ref bool success)
728 {
729 JsonArray array = new JsonArray();
730
731 // [
732 NextToken(json, ref index);
733
734 bool done = false;
735 while (!done)
736 {
737 int token = LookAhead(json, index);
738 if (token == TOKEN_NONE)
739 {
740 success = false;
741 return null;
742 }
743 else if (token == TOKEN_COMMA)
744 NextToken(json, ref index);
745 else if (token == TOKEN_SQUARED_CLOSE)
746 {
747 NextToken(json, ref index);
748 break;
749 }
750 else
751 {
752 object value = ParseValue(json, ref index, ref success);
753 if (!success)
754 return null;
755 array.Add(value);
756 }
757 }
758 return array;
759 }
760
761 static object ParseValue(char[] json, ref int index, ref bool success)
762 {
763 switch (LookAhead(json, index))
764 {
765 case TOKEN_STRING:
766 return ParseString(json, ref index, ref success);
767 case TOKEN_NUMBER:
768 return ParseNumber(json, ref index, ref success);
769 case TOKEN_CURLY_OPEN:
770 return ParseObject(json, ref index, ref success);
771 case TOKEN_SQUARED_OPEN:
772 return ParseArray(json, ref index, ref success);
773 case TOKEN_TRUE:
774 NextToken(json, ref index);
775 return true;
776 case TOKEN_FALSE:
777 NextToken(json, ref index);
778 return false;
779 case TOKEN_NULL:
780 NextToken(json, ref index);
781 return null;
782 case TOKEN_NONE:
783 break;
784 }
785 success = false;
786 return null;
787 }
788
789 static string ParseString(char[] json, ref int index, ref bool success)
790 {
791 StringBuilder s = new StringBuilder(BUILDER_CAPACITY);
792 char c;
793
794 EatWhitespace(json, ref index);
795
796 // "
797 c = json[index++];
798 bool complete = false;
799 while (!complete)
800 {
801 if (index == json.Length)
802 break;
803
804 c = json[index++];
805 if (c == '"')
806 {
807 complete = true;
808 break;
809 }
810 else if (c == '\\')
811 {
812 if (index == json.Length)
813 break;
814 c = json[index++];
815 if (c == '"')
816 s.Append('"');
817 else if (c == '\\')
818 s.Append('\\');
819 else if (c == '/')
820 s.Append('/');
821 else if (c == 'b')
822 s.Append('\b');
823 else if (c == 'f')
824 s.Append('\f');
825 else if (c == 'n')
826 s.Append('\n');
827 else if (c == 'r')
828 s.Append('\r');
829 else if (c == 't')
830 s.Append('\t');
831 else if (c == 'u')
832 {
833 int remainingLength = json.Length - index;
834 if (remainingLength >= 4)
835 {
836 // parse the 32 bit hex into an integer codepoint
837 uint codePoint;
838 if (!(success = UInt32.TryParse(new string(json, index, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out codePoint)))
839 return "";
840
841 // convert the integer codepoint to a unicode char and add to string
842 if (0xD800 <= codePoint && codePoint <= 0xDBFF) // if high surrogate
843 {
844 index += 4; // skip 4 chars
845 remainingLength = json.Length - index;
846 if (remainingLength >= 6)
847 {
848 uint lowCodePoint;
849 if (new string(json, index, 2) == "\\u" && UInt32.TryParse(new string(json, index + 2, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out lowCodePoint))
850 {
851 if (0xDC00 <= lowCodePoint && lowCodePoint <= 0xDFFF) // if low surrogate
852 {
853 s.Append((char)codePoint);
854 s.Append((char)lowCodePoint);
855 index += 6; // skip 6 chars
856 continue;
857 }
858 }
859 }
860 success = false; // invalid surrogate pair
861 return "";
862 }
863 s.Append(ConvertFromUtf32((int)codePoint));
864 // skip 4 chars
865 index += 4;
866 }
867 else
868 break;
869 }
870 }
871 else
872 s.Append(c);
873 }
874 if (!complete)
875 {
876 success = false;
877 return null;
878 }
879 return s.ToString();
880 }
881
882 private static string ConvertFromUtf32(int utf32)
883 {
884 // http://www.java2s.com/Open-Source/CSharp/2.6.4-mono-.net-core/System/System/Char.cs.htm
885 if (utf32 < 0 || utf32 > 0x10FFFF)
886 throw new ArgumentOutOfRangeException("utf32", "The argument must be from 0 to 0x10FFFF.");
887 if (0xD800 <= utf32 && utf32 <= 0xDFFF)
888 throw new ArgumentOutOfRangeException("utf32", "The argument must not be in surrogate pair range.");
889 if (utf32 < 0x10000)
890 return new string((char)utf32, 1);
891 utf32 -= 0x10000;
892 return new string(new char[] { (char)((utf32 >> 10) + 0xD800), (char)(utf32 % 0x0400 + 0xDC00) });
893 }
894
895 static object ParseNumber(char[] json, ref int index, ref bool success)
896 {
897 EatWhitespace(json, ref index);
898 int lastIndex = GetLastIndexOfNumber(json, index);
899 int charLength = (lastIndex - index) + 1;
900 object returnNumber;
901 string str = new string(json, index, charLength);
902 if (str.IndexOf(".", StringComparison.OrdinalIgnoreCase) != -1 || str.IndexOf("e", StringComparison.OrdinalIgnoreCase) != -1)
903 {
904 double number;
905 success = double.TryParse(new string(json, index, charLength), NumberStyles.Any, CultureInfo.InvariantCulture, out number);
906 returnNumber = number;
907 }
908 else
909 {
910 long number;
911 success = long.TryParse(new string(json, index, charLength), NumberStyles.Any, CultureInfo.InvariantCulture, out number);
912 returnNumber = number;
913 }
914 index = lastIndex + 1;
915 return returnNumber;
916 }
917
918 static int GetLastIndexOfNumber(char[] json, int index)
919 {
920 int lastIndex;
921 for (lastIndex = index; lastIndex < json.Length; lastIndex++)
922 if ("0123456789+-.eE".IndexOf(json[lastIndex]) == -1) break;
923 return lastIndex - 1;
924 }
925
926 static void EatWhitespace(char[] json, ref int index)
927 {
928 for (; index < json.Length; index++)
929 if (" \t\n\r\b\f".IndexOf(json[index]) == -1) break;
930 }
931
932 static int LookAhead(char[] json, int index)
933 {
934 int saveIndex = index;
935 return NextToken(json, ref saveIndex);
936 }
937
938 [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
939 static int NextToken(char[] json, ref int index)
940 {
941 EatWhitespace(json, ref index);
942 if (index == json.Length)
943 return TOKEN_NONE;
944 char c = json[index];
945 index++;
946 switch (c)
947 {
948 case '{':
949 return TOKEN_CURLY_OPEN;
950 case '}':
951 return TOKEN_CURLY_CLOSE;
952 case '[':
953 return TOKEN_SQUARED_OPEN;
954 case ']':
955 return TOKEN_SQUARED_CLOSE;
956 case ',':
957 return TOKEN_COMMA;
958 case '"':
959 return TOKEN_STRING;
960 case '0':
961 case '1':
962 case '2':
963 case '3':
964 case '4':
965 case '5':
966 case '6':
967 case '7':
968 case '8':
969 case '9':
970 case '-':
971 return TOKEN_NUMBER;
972 case ':':
973 return TOKEN_COLON;
974 }
975 index--;
976 int remainingLength = json.Length - index;
977 // false
978 if (remainingLength >= 5)
979 {
980 if (json[index] == 'f' && json[index + 1] == 'a' && json[index + 2] == 'l' && json[index + 3] == 's' && json[index + 4] == 'e')
981 {
982 index += 5;
983 return TOKEN_FALSE;
984 }
985 }
986 // true
987 if (remainingLength >= 4)
988 {
989 if (json[index] == 't' && json[index + 1] == 'r' && json[index + 2] == 'u' && json[index + 3] == 'e')
990 {
991 index += 4;
992 return TOKEN_TRUE;
993 }
994 }
995 // null
996 if (remainingLength >= 4)
997 {
998 if (json[index] == 'n' && json[index + 1] == 'u' && json[index + 2] == 'l' && json[index + 3] == 'l')
999 {
1000 index += 4;
1001 return TOKEN_NULL;
1002 }
1003 }
1004 return TOKEN_NONE;
1005 }
1006
1007 static bool SerializeValue(IJsonSerializerStrategy jsonSerializerStrategy, object value, StringBuilder builder)
1008 {
1009 bool success = true;
1010 string stringValue = value as string;
1011 if (stringValue != null)
1012 success = SerializeString(stringValue, builder);
1013 else
1014 {
1015 IDictionary<string, object> dict = value as IDictionary<string, object>;
1016 if (dict != null)
1017 {
1018 success = SerializeObject(jsonSerializerStrategy, dict.Keys, dict.Values, builder);
1019 }
1020 else
1021 {
1022 IDictionary<string, string> stringDictionary = value as IDictionary<string, string>;
1023 if (stringDictionary != null)
1024 {
1025 success = SerializeObject(jsonSerializerStrategy, stringDictionary.Keys, stringDictionary.Values, builder);
1026 }
1027 else
1028 {
1029 IEnumerable enumerableValue = value as IEnumerable;
1030 if (enumerableValue != null)
1031 success = SerializeArray(jsonSerializerStrategy, enumerableValue, builder);
1032 else if (IsNumeric(value))
1033 success = SerializeNumber(value, builder);
1034 else if (value is bool)
1035 builder.Append((bool)value ? "true" : "false");
1036 else if (value == null)
1037 builder.Append("null");
1038 else
1039 {
1040 object serializedObject;
1041 success = jsonSerializerStrategy.TrySerializeNonPrimitiveObject(value, out serializedObject);
1042 if (success)
1043 SerializeValue(jsonSerializerStrategy, serializedObject, builder);
1044 }
1045 }
1046 }
1047 }
1048 return success;
1049 }
1050
1051 static bool SerializeObject(IJsonSerializerStrategy jsonSerializerStrategy, IEnumerable keys, IEnumerable values, StringBuilder builder)
1052 {
1053 builder.Append("{");
1054 IEnumerator ke = keys.GetEnumerator();
1055 IEnumerator ve = values.GetEnumerator();
1056 bool first = true;
1057 while (ke.MoveNext() && ve.MoveNext())
1058 {
1059 object key = ke.Current;
1060 object value = ve.Current;
1061 if (!first)
1062 builder.Append(",");
1063 string stringKey = key as string;
1064 if (stringKey != null)
1065 SerializeString(stringKey, builder);
1066 else
1067 if (!SerializeValue(jsonSerializerStrategy, value, builder)) return false;
1068 builder.Append(":");
1069 if (!SerializeValue(jsonSerializerStrategy, value, builder))
1070 return false;
1071 first = false;
1072 }
1073 builder.Append("}");
1074 return true;
1075 }
1076
1077 static bool SerializeArray(IJsonSerializerStrategy jsonSerializerStrategy, IEnumerable anArray, StringBuilder builder)
1078 {
1079 builder.Append("[");
1080 bool first = true;
1081 foreach (object value in anArray)
1082 {
1083 if (!first)
1084 builder.Append(",");
1085 if (!SerializeValue(jsonSerializerStrategy, value, builder))
1086 return false;
1087 first = false;
1088 }
1089 builder.Append("]");
1090 return true;
1091 }
1092
1093 static bool SerializeString(string aString, StringBuilder builder)
1094 {
1095 // Happy path if there's nothing to be escaped. IndexOfAny is highly optimized (and unmanaged)
1096 if (aString.IndexOfAny(EscapeCharacters) == -1)
1097 {
1098 builder.Append('"');
1099 builder.Append(aString);
1100 builder.Append('"');
1101
1102 return true;
1103 }
1104
1105 builder.Append('"');
1106 int safeCharacterCount = 0;
1107 char[] charArray = aString.ToCharArray();
1108
1109 for (int i = 0; i < charArray.Length; i++)
1110 {
1111 char c = charArray[i];
1112
1113 // Non ascii characters are fine, buffer them up and send them to the builder
1114 // in larger chunks if possible. The escape table is a 1:1 translation table
1115 // with \0 [default(char)] denoting a safe character.
1116 if (c >= EscapeTable.Length || EscapeTable[c] == default(char))
1117 {
1118 safeCharacterCount++;
1119 }
1120 else
1121 {
1122 if (safeCharacterCount > 0)
1123 {
1124 builder.Append(charArray, i - safeCharacterCount, safeCharacterCount);
1125 safeCharacterCount = 0;
1126 }
1127
1128 builder.Append('\\');
1129 builder.Append(EscapeTable[c]);
1130 }
1131 }
1132
1133 if (safeCharacterCount > 0)
1134 {
1135 builder.Append(charArray, charArray.Length - safeCharacterCount, safeCharacterCount);
1136 }
1137
1138 builder.Append('"');
1139 return true;
1140 }
1141
1142 static bool SerializeNumber(object number, StringBuilder builder)
1143 {
1144 if (number is long)
1145 builder.Append(((long)number).ToString(CultureInfo.InvariantCulture));
1146 else if (number is ulong)
1147 builder.Append(((ulong)number).ToString(CultureInfo.InvariantCulture));
1148 else if (number is int)
1149 builder.Append(((int)number).ToString(CultureInfo.InvariantCulture));
1150 else if (number is uint)
1151 builder.Append(((uint)number).ToString(CultureInfo.InvariantCulture));
1152 else if (number is decimal)
1153 builder.Append(((decimal)number).ToString(CultureInfo.InvariantCulture));
1154 else if (number is float)
1155 builder.Append(((float)number).ToString(CultureInfo.InvariantCulture));
1156 else
1157 builder.Append(Convert.ToDouble(number, CultureInfo.InvariantCulture).ToString("r", CultureInfo.InvariantCulture));
1158 return true;
1159 }
1160
1161 /// <summary>
1162 /// Determines if a given object is numeric in any way
1163 /// (can be integer, double, null, etc).
1164 /// </summary>
1165 static bool IsNumeric(object value)
1166 {
1167 if (value is sbyte) return true;
1168 if (value is byte) return true;
1169 if (value is short) return true;
1170 if (value is ushort) return true;
1171 if (value is int) return true;
1172 if (value is uint) return true;
1173 if (value is long) return true;
1174 if (value is ulong) return true;
1175 if (value is float) return true;
1176 if (value is double) return true;
1177 if (value is decimal) return true;
1178 return false;
1179 }
1180
1181 private static IJsonSerializerStrategy _currentJsonSerializerStrategy;
1182 public static IJsonSerializerStrategy CurrentJsonSerializerStrategy
1183 {
1184 get
1185 {
1186 return _currentJsonSerializerStrategy ??
1187 (_currentJsonSerializerStrategy =
1188#if SIMPLE_JSON_DATACONTRACT
1189 DataContractJsonSerializerStrategy
1190#else
1191 PocoJsonSerializerStrategy
1192#endif
1193);
1194 }
1195 set
1196 {
1197 _currentJsonSerializerStrategy = value;
1198 }
1199 }
1200
1201 private static PocoJsonSerializerStrategy _pocoJsonSerializerStrategy;
1202 [EditorBrowsable(EditorBrowsableState.Advanced)]
1203 public static PocoJsonSerializerStrategy PocoJsonSerializerStrategy
1204 {
1205 get
1206 {
1207 return _pocoJsonSerializerStrategy ?? (_pocoJsonSerializerStrategy = new PocoJsonSerializerStrategy());
1208 }
1209 }
1210
1211#if SIMPLE_JSON_DATACONTRACT
1212
1213 private static DataContractJsonSerializerStrategy _dataContractJsonSerializerStrategy;
1214 [System.ComponentModel.EditorBrowsable(EditorBrowsableState.Advanced)]
1215 public static DataContractJsonSerializerStrategy DataContractJsonSerializerStrategy
1216 {
1217 get
1218 {
1219 return _dataContractJsonSerializerStrategy ?? (_dataContractJsonSerializerStrategy = new DataContractJsonSerializerStrategy());
1220 }
1221 }
1222
1223#endif
1224 }
1225
1226 [GeneratedCode("simple-json", "1.0.0")]
1227#if SIMPLE_JSON_INTERNAL
1228 internal
1229#else
1230 public
1231#endif
1232 interface IJsonSerializerStrategy
1233 {
1234 [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification = "Need to support .NET 2")]
1235 bool TrySerializeNonPrimitiveObject(object input, out object output);
1236 object DeserializeObject(object value, Type type);
1237 }
1238
1239 [GeneratedCode("simple-json", "1.0.0")]
1240#if SIMPLE_JSON_INTERNAL
1241 internal
1242#else
1243 public
1244#endif
1245 class PocoJsonSerializerStrategy : IJsonSerializerStrategy
1246 {
1247 internal IDictionary<Type, ReflectionUtils.ConstructorDelegate> ConstructorCache;
1248 internal IDictionary<Type, IDictionary<string, ReflectionUtils.GetDelegate>> GetCache;
1249 internal IDictionary<Type, IDictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>>> SetCache;
1250
1251 internal static readonly Type[] EmptyTypes = new Type[0];
1252 internal static readonly Type[] ArrayConstructorParameterTypes = new Type[] { typeof(int) };
1253
1254 private static readonly string[] Iso8601Format = new string[]
1255 {
1256 @"yyyy-MM-dd\THH:mm:ss.FFFFFFF\Z",
1257 @"yyyy-MM-dd\THH:mm:ss\Z",
1258 @"yyyy-MM-dd\THH:mm:ssK"
1259 };
1260
1261 public PocoJsonSerializerStrategy()
1262 {
1263 ConstructorCache = new ReflectionUtils.ThreadSafeDictionary<Type, ReflectionUtils.ConstructorDelegate>(ContructorDelegateFactory);
1264 GetCache = new ReflectionUtils.ThreadSafeDictionary<Type, IDictionary<string, ReflectionUtils.GetDelegate>>(GetterValueFactory);
1265 SetCache = new ReflectionUtils.ThreadSafeDictionary<Type, IDictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>>>(SetterValueFactory);
1266 }
1267
1268 protected virtual string MapClrMemberNameToJsonFieldName(string clrPropertyName)
1269 {
1270 return clrPropertyName;
1271 }
1272
1273 internal virtual ReflectionUtils.ConstructorDelegate ContructorDelegateFactory(Type key)
1274 {
1275 return ReflectionUtils.GetContructor(key, key.IsArray ? ArrayConstructorParameterTypes : EmptyTypes);
1276 }
1277
1278 internal virtual IDictionary<string, ReflectionUtils.GetDelegate> GetterValueFactory(Type type)
1279 {
1280 IDictionary<string, ReflectionUtils.GetDelegate> result = new Dictionary<string, ReflectionUtils.GetDelegate>();
1281 foreach (PropertyInfo propertyInfo in ReflectionUtils.GetProperties(type))
1282 {
1283 if (propertyInfo.CanRead)
1284 {
1285 MethodInfo getMethod = ReflectionUtils.GetGetterMethodInfo(propertyInfo);
1286 if (getMethod.IsStatic || !getMethod.IsPublic)
1287 continue;
1288 result[MapClrMemberNameToJsonFieldName(propertyInfo.Name)] = ReflectionUtils.GetGetMethod(propertyInfo);
1289 }
1290 }
1291 foreach (FieldInfo fieldInfo in ReflectionUtils.GetFields(type))
1292 {
1293 if (fieldInfo.IsStatic || !fieldInfo.IsPublic)
1294 continue;
1295 result[MapClrMemberNameToJsonFieldName(fieldInfo.Name)] = ReflectionUtils.GetGetMethod(fieldInfo);
1296 }
1297 return result;
1298 }
1299
1300 internal virtual IDictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>> SetterValueFactory(Type type)
1301 {
1302 IDictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>> result = new Dictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>>();
1303 foreach (PropertyInfo propertyInfo in ReflectionUtils.GetProperties(type))
1304 {
1305 if (propertyInfo.CanWrite)
1306 {
1307 MethodInfo setMethod = ReflectionUtils.GetSetterMethodInfo(propertyInfo);
1308 if (setMethod.IsStatic || !setMethod.IsPublic)
1309 continue;
1310 result[MapClrMemberNameToJsonFieldName(propertyInfo.Name)] = new KeyValuePair<Type, ReflectionUtils.SetDelegate>(propertyInfo.PropertyType, ReflectionUtils.GetSetMethod(propertyInfo));
1311 }
1312 }
1313 foreach (FieldInfo fieldInfo in ReflectionUtils.GetFields(type))
1314 {
1315 if (fieldInfo.IsInitOnly || fieldInfo.IsStatic || !fieldInfo.IsPublic)
1316 continue;
1317 result[MapClrMemberNameToJsonFieldName(fieldInfo.Name)] = new KeyValuePair<Type, ReflectionUtils.SetDelegate>(fieldInfo.FieldType, ReflectionUtils.GetSetMethod(fieldInfo));
1318 }
1319 return result;
1320 }
1321
1322 public virtual bool TrySerializeNonPrimitiveObject(object input, out object output)
1323 {
1324 return TrySerializeKnownTypes(input, out output) || TrySerializeUnknownTypes(input, out output);
1325 }
1326
1327 [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
1328 public virtual object DeserializeObject(object value, Type type)
1329 {
1330 if (type == null) throw new ArgumentNullException("type");
1331 string str = value as string;
1332
1333 if (type == typeof(Guid) && string.IsNullOrEmpty(str))
1334 return default(Guid);
1335
1336 if (value == null)
1337 return null;
1338
1339 object obj = null;
1340
1341 if (str != null)
1342 {
1343 if (str.Length != 0) // We know it can't be null now.
1344 {
1345 if (type == typeof(DateTime) || (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(DateTime)))
1346 return DateTime.ParseExact(str, Iso8601Format, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
1347 if (type == typeof(DateTimeOffset) || (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(DateTimeOffset)))
1348 return DateTimeOffset.ParseExact(str, Iso8601Format, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
1349 if (type == typeof(Guid) || (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(Guid)))
1350 return new Guid(str);
1351 if (type == typeof(Uri))
1352 {
1353 bool isValid = Uri.IsWellFormedUriString(str, UriKind.RelativeOrAbsolute);
1354
1355 Uri result;
1356 if (isValid && Uri.TryCreate(str, UriKind.RelativeOrAbsolute, out result))
1357 return result;
1358
1359 return null;
1360 }
1361
1362 if (type == typeof(string))
1363 return str;
1364
1365 return Convert.ChangeType(str, type, CultureInfo.InvariantCulture);
1366 }
1367 else
1368 {
1369 if (type == typeof(Guid))
1370 obj = default(Guid);
1371 else if (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(Guid))
1372 obj = null;
1373 else
1374 obj = str;
1375 }
1376 // Empty string case
1377 if (!ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(Guid))
1378 return str;
1379 }
1380 else if (value is bool)
1381 return value;
1382
1383 bool valueIsLong = value is long;
1384 bool valueIsDouble = value is double;
1385 if ((valueIsLong && type == typeof(long)) || (valueIsDouble && type == typeof(double)))
1386 return value;
1387 if ((valueIsDouble && type != typeof(double)) || (valueIsLong && type != typeof(long)))
1388 {
1389 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)
1390 ? Convert.ChangeType(value, type, CultureInfo.InvariantCulture)
1391 : value;
1392 }
1393 else
1394 {
1395 IDictionary<string, object> objects = value as IDictionary<string, object>;
1396 if (objects != null)
1397 {
1398 IDictionary<string, object> jsonObject = objects;
1399
1400 if (ReflectionUtils.IsTypeDictionary(type))
1401 {
1402 // if dictionary then
1403 Type[] types = ReflectionUtils.GetGenericTypeArguments(type);
1404 Type keyType = types[0];
1405 Type valueType = types[1];
1406
1407 Type genericType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType);
1408
1409 IDictionary dict = (IDictionary)ConstructorCache[genericType]();
1410
1411 foreach (KeyValuePair<string, object> kvp in jsonObject)
1412 dict.Add(kvp.Key, DeserializeObject(kvp.Value, valueType));
1413
1414 obj = dict;
1415 }
1416 else
1417 {
1418 if (type == typeof(object))
1419 obj = value;
1420 else
1421 {
1422 obj = ConstructorCache[type]();
1423 foreach (KeyValuePair<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>> setter in SetCache[type])
1424 {
1425 object jsonValue;
1426 if (jsonObject.TryGetValue(setter.Key, out jsonValue))
1427 {
1428 jsonValue = DeserializeObject(jsonValue, setter.Value.Key);
1429 setter.Value.Value(obj, jsonValue);
1430 }
1431 }
1432 }
1433 }
1434 }
1435 else
1436 {
1437 IList<object> valueAsList = value as IList<object>;
1438 if (valueAsList != null)
1439 {
1440 IList<object> jsonObject = valueAsList;
1441 IList list = null;
1442
1443 if (type.IsArray)
1444 {
1445 list = (IList)ConstructorCache[type](jsonObject.Count);
1446 int i = 0;
1447 foreach (object o in jsonObject)
1448 list[i++] = DeserializeObject(o, type.GetElementType());
1449 }
1450 else if (ReflectionUtils.IsTypeGenericeCollectionInterface(type) || ReflectionUtils.IsAssignableFrom(typeof(IList), type))
1451 {
1452 Type innerType = ReflectionUtils.GetGenericListElementType(type);
1453 list = (IList)(ConstructorCache[type] ?? ConstructorCache[typeof(List<>).MakeGenericType(innerType)])(jsonObject.Count);
1454 foreach (object o in jsonObject)
1455 list.Add(DeserializeObject(o, innerType));
1456 }
1457 obj = list;
1458 }
1459 }
1460 return obj;
1461 }
1462 if (ReflectionUtils.IsNullableType(type))
1463 return ReflectionUtils.ToNullableType(obj, type);
1464 return obj;
1465 }
1466
1467 protected virtual object SerializeEnum(Enum p)
1468 {
1469 return Convert.ToDouble(p, CultureInfo.InvariantCulture);
1470 }
1471
1472 [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification = "Need to support .NET 2")]
1473 protected virtual bool TrySerializeKnownTypes(object input, out object output)
1474 {
1475 bool returnValue = true;
1476 if (input is DateTime)
1477 output = ((DateTime)input).ToUniversalTime().ToString(Iso8601Format[0], CultureInfo.InvariantCulture);
1478 else if (input is DateTimeOffset)
1479 output = ((DateTimeOffset)input).ToUniversalTime().ToString(Iso8601Format[0], CultureInfo.InvariantCulture);
1480 else if (input is Guid)
1481 output = ((Guid)input).ToString("D");
1482 else if (input is Uri)
1483 output = input.ToString();
1484 else
1485 {
1486 Enum inputEnum = input as Enum;
1487 if (inputEnum != null)
1488 output = SerializeEnum(inputEnum);
1489 else
1490 {
1491 returnValue = false;
1492 output = null;
1493 }
1494 }
1495 return returnValue;
1496 }
1497 [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification = "Need to support .NET 2")]
1498 protected virtual bool TrySerializeUnknownTypes(object input, out object output)
1499 {
1500 if (input == null) throw new ArgumentNullException("input");
1501 output = null;
1502 Type type = input.GetType();
1503 if (type.FullName == null)
1504 return false;
1505 IDictionary<string, object> obj = new JsonObject();
1506 IDictionary<string, ReflectionUtils.GetDelegate> getters = GetCache[type];
1507 foreach (KeyValuePair<string, ReflectionUtils.GetDelegate> getter in getters)
1508 {
1509 if (getter.Value != null)
1510 obj.Add(MapClrMemberNameToJsonFieldName(getter.Key), getter.Value(input));
1511 }
1512 output = obj;
1513 return true;
1514 }
1515 }
1516
1517#if SIMPLE_JSON_DATACONTRACT
1518 [GeneratedCode("simple-json", "1.0.0")]
1519#if SIMPLE_JSON_INTERNAL
1520 internal
1521#else
1522 public
1523#endif
1524 class DataContractJsonSerializerStrategy : PocoJsonSerializerStrategy
1525 {
1526 public DataContractJsonSerializerStrategy()
1527 {
1528 GetCache = new ReflectionUtils.ThreadSafeDictionary<Type, IDictionary<string, ReflectionUtils.GetDelegate>>(GetterValueFactory);
1529 SetCache = new ReflectionUtils.ThreadSafeDictionary<Type, IDictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>>>(SetterValueFactory);
1530 }
1531
1532 internal override IDictionary<string, ReflectionUtils.GetDelegate> GetterValueFactory(Type type)
1533 {
1534 bool hasDataContract = ReflectionUtils.GetAttribute(type, typeof(DataContractAttribute)) != null;
1535 if (!hasDataContract)
1536 return base.GetterValueFactory(type);
1537 string jsonKey;
1538 IDictionary<string, ReflectionUtils.GetDelegate> result = new Dictionary<string, ReflectionUtils.GetDelegate>();
1539 foreach (PropertyInfo propertyInfo in ReflectionUtils.GetProperties(type))
1540 {
1541 if (propertyInfo.CanRead)
1542 {
1543 MethodInfo getMethod = ReflectionUtils.GetGetterMethodInfo(propertyInfo);
1544 if (!getMethod.IsStatic && CanAdd(propertyInfo, out jsonKey))
1545 result[jsonKey] = ReflectionUtils.GetGetMethod(propertyInfo);
1546 }
1547 }
1548 foreach (FieldInfo fieldInfo in ReflectionUtils.GetFields(type))
1549 {
1550 if (!fieldInfo.IsStatic && CanAdd(fieldInfo, out jsonKey))
1551 result[jsonKey] = ReflectionUtils.GetGetMethod(fieldInfo);
1552 }
1553 return result;
1554 }
1555
1556 internal override IDictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>> SetterValueFactory(Type type)
1557 {
1558 bool hasDataContract = ReflectionUtils.GetAttribute(type, typeof(DataContractAttribute)) != null;
1559 if (!hasDataContract)
1560 return base.SetterValueFactory(type);
1561 string jsonKey;
1562 IDictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>> result = new Dictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>>();
1563 foreach (PropertyInfo propertyInfo in ReflectionUtils.GetProperties(type))
1564 {
1565 if (propertyInfo.CanWrite)
1566 {
1567 MethodInfo setMethod = ReflectionUtils.GetSetterMethodInfo(propertyInfo);
1568 if (!setMethod.IsStatic && CanAdd(propertyInfo, out jsonKey))
1569 result[jsonKey] = new KeyValuePair<Type, ReflectionUtils.SetDelegate>(propertyInfo.PropertyType, ReflectionUtils.GetSetMethod(propertyInfo));
1570 }
1571 }
1572 foreach (FieldInfo fieldInfo in ReflectionUtils.GetFields(type))
1573 {
1574 if (!fieldInfo.IsInitOnly && !fieldInfo.IsStatic && CanAdd(fieldInfo, out jsonKey))
1575 result[jsonKey] = new KeyValuePair<Type, ReflectionUtils.SetDelegate>(fieldInfo.FieldType, ReflectionUtils.GetSetMethod(fieldInfo));
1576 }
1577 // todo implement sorting for DATACONTRACT.
1578 return result;
1579 }
1580
1581 private static bool CanAdd(MemberInfo info, out string jsonKey)
1582 {
1583 jsonKey = null;
1584 if (ReflectionUtils.GetAttribute(info, typeof(IgnoreDataMemberAttribute)) != null)
1585 return false;
1586 DataMemberAttribute dataMemberAttribute = (DataMemberAttribute)ReflectionUtils.GetAttribute(info, typeof(DataMemberAttribute));
1587 if (dataMemberAttribute == null)
1588 return false;
1589 jsonKey = string.IsNullOrEmpty(dataMemberAttribute.Name) ? info.Name : dataMemberAttribute.Name;
1590 return true;
1591 }
1592 }
1593
1594#endif
1595
1596 namespace Reflection
1597 {
1598 // This class is meant to be copied into other libraries. So we want to exclude it from Code Analysis rules
1599 // that might be in place in the target project.
1600 [GeneratedCode("reflection-utils", "1.0.0")]
1601#if SIMPLE_JSON_REFLECTION_UTILS_PUBLIC
1602 public
1603#else
1604 internal
1605#endif
1606 class ReflectionUtils
1607 {
1608 private static readonly object[] EmptyObjects = new object[] { };
1609
1610 public delegate object GetDelegate(object source);
1611 public delegate void SetDelegate(object source, object value);
1612 public delegate object ConstructorDelegate(params object[] args);
1613
1614 public delegate TValue ThreadSafeDictionaryValueFactory<TKey, TValue>(TKey key);
1615
1616#if SIMPLE_JSON_TYPEINFO
1617 public static TypeInfo GetTypeInfo(Type type)
1618 {
1619 return type.GetTypeInfo();
1620 }
1621#else
1622 public static Type GetTypeInfo(Type type)
1623 {
1624 return type;
1625 }
1626#endif
1627
1628 public static Attribute GetAttribute(MemberInfo info, Type type)
1629 {
1630#if SIMPLE_JSON_TYPEINFO
1631 if (info == null || type == null || !info.IsDefined(type))
1632 return null;
1633 return info.GetCustomAttribute(type);
1634#else
1635 if (info == null || type == null || !Attribute.IsDefined(info, type))
1636 return null;
1637 return Attribute.GetCustomAttribute(info, type);
1638#endif
1639 }
1640
1641 public static Type GetGenericListElementType(Type type)
1642 {
1643 IEnumerable<Type> interfaces;
1644#if SIMPLE_JSON_TYPEINFO
1645 interfaces = type.GetTypeInfo().ImplementedInterfaces;
1646#else
1647 interfaces = type.GetInterfaces();
1648#endif
1649 foreach (Type implementedInterface in interfaces)
1650 {
1651 if (IsTypeGeneric(implementedInterface) &&
1652 implementedInterface.GetGenericTypeDefinition() == typeof(IList<>))
1653 {
1654 return GetGenericTypeArguments(implementedInterface)[0];
1655 }
1656 }
1657 return GetGenericTypeArguments(type)[0];
1658 }
1659
1660 public static Attribute GetAttribute(Type objectType, Type attributeType)
1661 {
1662
1663#if SIMPLE_JSON_TYPEINFO
1664 if (objectType == null || attributeType == null || !objectType.GetTypeInfo().IsDefined(attributeType))
1665 return null;
1666 return objectType.GetTypeInfo().GetCustomAttribute(attributeType);
1667#else
1668 if (objectType == null || attributeType == null || !Attribute.IsDefined(objectType, attributeType))
1669 return null;
1670 return Attribute.GetCustomAttribute(objectType, attributeType);
1671#endif
1672 }
1673
1674 public static Type[] GetGenericTypeArguments(Type type)
1675 {
1676#if SIMPLE_JSON_TYPEINFO
1677 return type.GetTypeInfo().GenericTypeArguments;
1678#else
1679 return type.GetGenericArguments();
1680#endif
1681 }
1682
1683 public static bool IsTypeGeneric(Type type)
1684 {
1685 return GetTypeInfo(type).IsGenericType;
1686 }
1687
1688 public static bool IsTypeGenericeCollectionInterface(Type type)
1689 {
1690 if (!IsTypeGeneric(type))
1691 return false;
1692
1693 Type genericDefinition = type.GetGenericTypeDefinition();
1694
1695 return (genericDefinition == typeof(IList<>)
1696 || genericDefinition == typeof(ICollection<>)
1697 || genericDefinition == typeof(IEnumerable<>)
1698#if SIMPLE_JSON_READONLY_COLLECTIONS
1699 || genericDefinition == typeof(IReadOnlyCollection<>)
1700 || genericDefinition == typeof(IReadOnlyList<>)
1701#endif
1702 );
1703 }
1704
1705 public static bool IsAssignableFrom(Type type1, Type type2)
1706 {
1707 return GetTypeInfo(type1).IsAssignableFrom(GetTypeInfo(type2));
1708 }
1709
1710 public static bool IsTypeDictionary(Type type)
1711 {
1712#if SIMPLE_JSON_TYPEINFO
1713 if (typeof(IDictionary<,>).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()))
1714 return true;
1715#else
1716 if (typeof(System.Collections.IDictionary).IsAssignableFrom(type))
1717 return true;
1718#endif
1719 if (!GetTypeInfo(type).IsGenericType)
1720 return false;
1721
1722 Type genericDefinition = type.GetGenericTypeDefinition();
1723 return genericDefinition == typeof(IDictionary<,>);
1724 }
1725
1726 public static bool IsNullableType(Type type)
1727 {
1728 return GetTypeInfo(type).IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
1729 }
1730
1731 public static object ToNullableType(object obj, Type nullableType)
1732 {
1733 return obj == null ? null : Convert.ChangeType(obj, Nullable.GetUnderlyingType(nullableType), CultureInfo.InvariantCulture);
1734 }
1735
1736 public static bool IsValueType(Type type)
1737 {
1738 return GetTypeInfo(type).IsValueType;
1739 }
1740
1741 public static IEnumerable<ConstructorInfo> GetConstructors(Type type)
1742 {
1743#if SIMPLE_JSON_TYPEINFO
1744 return type.GetTypeInfo().DeclaredConstructors;
1745#else
1746 return type.GetConstructors();
1747#endif
1748 }
1749
1750 public static ConstructorInfo GetConstructorInfo(Type type, params Type[] argsType)
1751 {
1752 IEnumerable<ConstructorInfo> constructorInfos = GetConstructors(type);
1753 int i;
1754 bool matches;
1755 foreach (ConstructorInfo constructorInfo in constructorInfos)
1756 {
1757 ParameterInfo[] parameters = constructorInfo.GetParameters();
1758 if (argsType.Length != parameters.Length)
1759 continue;
1760
1761 i = 0;
1762 matches = true;
1763 foreach (ParameterInfo parameterInfo in constructorInfo.GetParameters())
1764 {
1765 if (parameterInfo.ParameterType != argsType[i])
1766 {
1767 matches = false;
1768 break;
1769 }
1770 }
1771
1772 if (matches)
1773 return constructorInfo;
1774 }
1775
1776 return null;
1777 }
1778
1779 public static IEnumerable<PropertyInfo> GetProperties(Type type)
1780 {
1781#if SIMPLE_JSON_TYPEINFO
1782 return type.GetRuntimeProperties();
1783#else
1784 return type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
1785#endif
1786 }
1787
1788 public static IEnumerable<FieldInfo> GetFields(Type type)
1789 {
1790#if SIMPLE_JSON_TYPEINFO
1791 return type.GetRuntimeFields();
1792#else
1793 return type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
1794#endif
1795 }
1796
1797 public static MethodInfo GetGetterMethodInfo(PropertyInfo propertyInfo)
1798 {
1799#if SIMPLE_JSON_TYPEINFO
1800 return propertyInfo.GetMethod;
1801#else
1802 return propertyInfo.GetGetMethod(true);
1803#endif
1804 }
1805
1806 public static MethodInfo GetSetterMethodInfo(PropertyInfo propertyInfo)
1807 {
1808#if SIMPLE_JSON_TYPEINFO
1809 return propertyInfo.SetMethod;
1810#else
1811 return propertyInfo.GetSetMethod(true);
1812#endif
1813 }
1814
1815 public static ConstructorDelegate GetContructor(ConstructorInfo constructorInfo)
1816 {
1817#if SIMPLE_JSON_NO_LINQ_EXPRESSION
1818 return GetConstructorByReflection(constructorInfo);
1819#else
1820 return GetConstructorByExpression(constructorInfo);
1821#endif
1822 }
1823
1824 public static ConstructorDelegate GetContructor(Type type, params Type[] argsType)
1825 {
1826#if SIMPLE_JSON_NO_LINQ_EXPRESSION
1827 return GetConstructorByReflection(type, argsType);
1828#else
1829 return GetConstructorByExpression(type, argsType);
1830#endif
1831 }
1832
1833 public static ConstructorDelegate GetConstructorByReflection(ConstructorInfo constructorInfo)
1834 {
1835 return delegate (object[] args) { return constructorInfo.Invoke(args); };
1836 }
1837
1838 public static ConstructorDelegate GetConstructorByReflection(Type type, params Type[] argsType)
1839 {
1840 ConstructorInfo constructorInfo = GetConstructorInfo(type, argsType);
1841 return constructorInfo == null ? null : GetConstructorByReflection(constructorInfo);
1842 }
1843
1844#if !SIMPLE_JSON_NO_LINQ_EXPRESSION
1845
1846 public static ConstructorDelegate GetConstructorByExpression(ConstructorInfo constructorInfo)
1847 {
1848 ParameterInfo[] paramsInfo = constructorInfo.GetParameters();
1849 ParameterExpression param = Expression.Parameter(typeof(object[]), "args");
1850 Expression[] argsExp = new Expression[paramsInfo.Length];
1851 for (int i = 0; i < paramsInfo.Length; i++)
1852 {
1853 Expression index = Expression.Constant(i);
1854 Type paramType = paramsInfo[i].ParameterType;
1855 Expression paramAccessorExp = Expression.ArrayIndex(param, index);
1856 Expression paramCastExp = Expression.Convert(paramAccessorExp, paramType);
1857 argsExp[i] = paramCastExp;
1858 }
1859 NewExpression newExp = Expression.New(constructorInfo, argsExp);
1860 Expression<Func<object[], object>> lambda = Expression.Lambda<Func<object[], object>>(newExp, param);
1861 Func<object[], object> compiledLambda = lambda.Compile();
1862 return delegate (object[] args) { return compiledLambda(args); };
1863 }
1864
1865 public static ConstructorDelegate GetConstructorByExpression(Type type, params Type[] argsType)
1866 {
1867 ConstructorInfo constructorInfo = GetConstructorInfo(type, argsType);
1868 return constructorInfo == null ? null : GetConstructorByExpression(constructorInfo);
1869 }
1870
1871#endif
1872
1873 public static GetDelegate GetGetMethod(PropertyInfo propertyInfo)
1874 {
1875#if SIMPLE_JSON_NO_LINQ_EXPRESSION
1876 return GetGetMethodByReflection(propertyInfo);
1877#else
1878 return GetGetMethodByExpression(propertyInfo);
1879#endif
1880 }
1881
1882 public static GetDelegate GetGetMethod(FieldInfo fieldInfo)
1883 {
1884#if SIMPLE_JSON_NO_LINQ_EXPRESSION
1885 return GetGetMethodByReflection(fieldInfo);
1886#else
1887 return GetGetMethodByExpression(fieldInfo);
1888#endif
1889 }
1890
1891 public static GetDelegate GetGetMethodByReflection(PropertyInfo propertyInfo)
1892 {
1893 MethodInfo methodInfo = GetGetterMethodInfo(propertyInfo);
1894 return delegate (object source) { return methodInfo.Invoke(source, EmptyObjects); };
1895 }
1896
1897 public static GetDelegate GetGetMethodByReflection(FieldInfo fieldInfo)
1898 {
1899 return delegate (object source) { return fieldInfo.GetValue(source); };
1900 }
1901
1902#if !SIMPLE_JSON_NO_LINQ_EXPRESSION
1903
1904 public static GetDelegate GetGetMethodByExpression(PropertyInfo propertyInfo)
1905 {
1906 MethodInfo getMethodInfo = GetGetterMethodInfo(propertyInfo);
1907 ParameterExpression instance = Expression.Parameter(typeof(object), "instance");
1908 UnaryExpression instanceCast = (!IsValueType(propertyInfo.DeclaringType)) ? Expression.TypeAs(instance, propertyInfo.DeclaringType) : Expression.Convert(instance, propertyInfo.DeclaringType);
1909 Func<object, object> compiled = Expression.Lambda<Func<object, object>>(Expression.TypeAs(Expression.Call(instanceCast, getMethodInfo), typeof(object)), instance).Compile();
1910 return delegate (object source) { return compiled(source); };
1911 }
1912
1913 public static GetDelegate GetGetMethodByExpression(FieldInfo fieldInfo)
1914 {
1915 ParameterExpression instance = Expression.Parameter(typeof(object), "instance");
1916 MemberExpression member = Expression.Field(Expression.Convert(instance, fieldInfo.DeclaringType), fieldInfo);
1917 GetDelegate compiled = Expression.Lambda<GetDelegate>(Expression.Convert(member, typeof(object)), instance).Compile();
1918 return delegate (object source) { return compiled(source); };
1919 }
1920
1921#endif
1922
1923 public static SetDelegate GetSetMethod(PropertyInfo propertyInfo)
1924 {
1925#if SIMPLE_JSON_NO_LINQ_EXPRESSION
1926 return GetSetMethodByReflection(propertyInfo);
1927#else
1928 return GetSetMethodByExpression(propertyInfo);
1929#endif
1930 }
1931
1932 public static SetDelegate GetSetMethod(FieldInfo fieldInfo)
1933 {
1934#if SIMPLE_JSON_NO_LINQ_EXPRESSION
1935 return GetSetMethodByReflection(fieldInfo);
1936#else
1937 return GetSetMethodByExpression(fieldInfo);
1938#endif
1939 }
1940
1941 public static SetDelegate GetSetMethodByReflection(PropertyInfo propertyInfo)
1942 {
1943 MethodInfo methodInfo = GetSetterMethodInfo(propertyInfo);
1944 return delegate (object source, object value) { methodInfo.Invoke(source, new object[] { value }); };
1945 }
1946
1947 public static SetDelegate GetSetMethodByReflection(FieldInfo fieldInfo)
1948 {
1949 return delegate (object source, object value) { fieldInfo.SetValue(source, value); };
1950 }
1951
1952#if !SIMPLE_JSON_NO_LINQ_EXPRESSION
1953
1954 public static SetDelegate GetSetMethodByExpression(PropertyInfo propertyInfo)
1955 {
1956 MethodInfo setMethodInfo = GetSetterMethodInfo(propertyInfo);
1957 ParameterExpression instance = Expression.Parameter(typeof(object), "instance");
1958 ParameterExpression value = Expression.Parameter(typeof(object), "value");
1959 UnaryExpression instanceCast = (!IsValueType(propertyInfo.DeclaringType)) ? Expression.TypeAs(instance, propertyInfo.DeclaringType) : Expression.Convert(instance, propertyInfo.DeclaringType);
1960 UnaryExpression valueCast = (!IsValueType(propertyInfo.PropertyType)) ? Expression.TypeAs(value, propertyInfo.PropertyType) : Expression.Convert(value, propertyInfo.PropertyType);
1961 Action<object, object> compiled = Expression.Lambda<Action<object, object>>(Expression.Call(instanceCast, setMethodInfo, valueCast), new ParameterExpression[] { instance, value }).Compile();
1962 return delegate (object source, object val) { compiled(source, val); };
1963 }
1964
1965 public static SetDelegate GetSetMethodByExpression(FieldInfo fieldInfo)
1966 {
1967 ParameterExpression instance = Expression.Parameter(typeof(object), "instance");
1968 ParameterExpression value = Expression.Parameter(typeof(object), "value");
1969 Action<object, object> compiled = Expression.Lambda<Action<object, object>>(
1970 Assign(Expression.Field(Expression.Convert(instance, fieldInfo.DeclaringType), fieldInfo), Expression.Convert(value, fieldInfo.FieldType)), instance, value).Compile();
1971 return delegate (object source, object val) { compiled(source, val); };
1972 }
1973
1974 public static BinaryExpression Assign(Expression left, Expression right)
1975 {
1976#if SIMPLE_JSON_TYPEINFO
1977 return Expression.Assign(left, right);
1978#else
1979 MethodInfo assign = typeof(Assigner<>).MakeGenericType(left.Type).GetMethod("Assign");
1980 BinaryExpression assignExpr = Expression.Add(left, right, assign);
1981 return assignExpr;
1982#endif
1983 }
1984
1985 private static class Assigner<T>
1986 {
1987 public static T Assign(ref T left, T right)
1988 {
1989 return (left = right);
1990 }
1991 }
1992
1993#endif
1994
1995 public sealed class ThreadSafeDictionary<TKey, TValue> : IDictionary<TKey, TValue>
1996 {
1997 private readonly object _lock = new object();
1998 private readonly ThreadSafeDictionaryValueFactory<TKey, TValue> _valueFactory;
1999 private Dictionary<TKey, TValue> _dictionary;
2000
2001 public ThreadSafeDictionary(ThreadSafeDictionaryValueFactory<TKey, TValue> valueFactory)
2002 {
2003 _valueFactory = valueFactory;
2004 }
2005
2006 private TValue Get(TKey key)
2007 {
2008 if (_dictionary == null)
2009 return AddValue(key);
2010 TValue value;
2011 if (!_dictionary.TryGetValue(key, out value))
2012 return AddValue(key);
2013 return value;
2014 }
2015
2016 private TValue AddValue(TKey key)
2017 {
2018 TValue value = _valueFactory(key);
2019 lock (_lock)
2020 {
2021 if (_dictionary == null)
2022 {
2023 _dictionary = new Dictionary<TKey, TValue>();
2024 _dictionary[key] = value;
2025 }
2026 else
2027 {
2028 TValue val;
2029 if (_dictionary.TryGetValue(key, out val))
2030 return val;
2031 Dictionary<TKey, TValue> dict = new Dictionary<TKey, TValue>(_dictionary);
2032 dict[key] = value;
2033 _dictionary = dict;
2034 }
2035 }
2036 return value;
2037 }
2038
2039 public void Add(TKey key, TValue value)
2040 {
2041 throw new NotImplementedException();
2042 }
2043
2044 public bool ContainsKey(TKey key)
2045 {
2046 return _dictionary.ContainsKey(key);
2047 }
2048
2049 public ICollection<TKey> Keys
2050 {
2051 get { return _dictionary.Keys; }
2052 }
2053
2054 public bool Remove(TKey key)
2055 {
2056 throw new NotImplementedException();
2057 }
2058
2059 public bool TryGetValue(TKey key, out TValue value)
2060 {
2061 value = this[key];
2062 return true;
2063 }
2064
2065 public ICollection<TValue> Values
2066 {
2067 get { return _dictionary.Values; }
2068 }
2069
2070 public TValue this[TKey key]
2071 {
2072 get { return Get(key); }
2073 set { throw new NotImplementedException(); }
2074 }
2075
2076 public void Add(KeyValuePair<TKey, TValue> item)
2077 {
2078 throw new NotImplementedException();
2079 }
2080
2081 public void Clear()
2082 {
2083 throw new NotImplementedException();
2084 }
2085
2086 public bool Contains(KeyValuePair<TKey, TValue> item)
2087 {
2088 throw new NotImplementedException();
2089 }
2090
2091 public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
2092 {
2093 throw new NotImplementedException();
2094 }
2095
2096 public int Count
2097 {
2098 get { return _dictionary.Count; }
2099 }
2100
2101 public bool IsReadOnly
2102 {
2103 get { throw new NotImplementedException(); }
2104 }
2105
2106 public bool Remove(KeyValuePair<TKey, TValue> item)
2107 {
2108 throw new NotImplementedException();
2109 }
2110
2111 public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
2112 {
2113 return _dictionary.GetEnumerator();
2114 }
2115
2116 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
2117 {
2118 return _dictionary.GetEnumerator();
2119 }
2120 }
2121
2122 }
2123 }
2124}
2125// ReSharper restore LoopCanBeConvertedToQuery
2126// ReSharper restore RedundantExplicitArrayCreation
2127// ReSharper restore SuggestUseVarKeywordEvident \ No newline at end of file