diff options
author | JamesNK <james@newtonking.com> | 2007-09-08 12:59:38 +0400 |
---|---|---|
committer | JamesNK <james@newtonking.com> | 2007-09-08 12:59:38 +0400 |
commit | e65bc2becd3ded759b5d5ca42c7d28a631cfc06d (patch) | |
tree | f9588f5735df2b74843e7baa9a8d2baa855601bc /Src/Newtonsoft.Json |
Diffstat (limited to 'Src/Newtonsoft.Json')
33 files changed, 6234 insertions, 0 deletions
diff --git a/Src/Newtonsoft.Json/Converters/AspNetAjaxDateTimeConverter.cs b/Src/Newtonsoft.Json/Converters/AspNetAjaxDateTimeConverter.cs new file mode 100644 index 0000000..eaaf83f --- /dev/null +++ b/Src/Newtonsoft.Json/Converters/AspNetAjaxDateTimeConverter.cs @@ -0,0 +1,59 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Globalization;
+
+namespace Newtonsoft.Json.Converters
+{
+ public class AspNetAjaxDateTimeConverter : JsonConverter
+ {
+ public override void WriteJson(JsonWriter writer, object value)
+ {
+ DateTime dateTime = (DateTime)value;
+ long javaScriptTicks = JavaScriptConvert.ConvertDateTimeToJavaScriptTicks(dateTime);
+
+ writer.WriteValue("@" + javaScriptTicks.ToString(null, CultureInfo.InvariantCulture) + "@");
+ }
+
+ public override object ReadJson(JsonReader reader, Type objectType)
+ {
+ string dateTimeText = (string)reader.Value;
+ dateTimeText = dateTimeText.Substring(1, dateTimeText.Length - 2);
+
+ long javaScriptTicks = Convert.ToInt64(dateTimeText);
+
+ return JavaScriptConvert.ConvertJavaScriptTicksToDateTime(javaScriptTicks);
+ }
+
+ public override bool CanConvert(Type valueType)
+ {
+ return typeof(DateTime).IsAssignableFrom(valueType);
+ }
+ }
+}
diff --git a/Src/Newtonsoft.Json/Converters/HtmlColorConverter.cs b/Src/Newtonsoft.Json/Converters/HtmlColorConverter.cs new file mode 100644 index 0000000..434146e --- /dev/null +++ b/Src/Newtonsoft.Json/Converters/HtmlColorConverter.cs @@ -0,0 +1,45 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Drawing;
+
+namespace Newtonsoft.Json.Converters
+{
+ public class HtmlColorConverter : JsonConverter
+ {
+ public override void WriteJson(JsonWriter writer, object value)
+ {
+ writer.WriteValue(ColorTranslator.ToHtml((Color)value));
+ }
+
+ public override bool CanConvert(Type valueType)
+ {
+ return typeof(Color).IsAssignableFrom(valueType);
+ }
+ }
+}
diff --git a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs new file mode 100644 index 0000000..2775821 --- /dev/null +++ b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs @@ -0,0 +1,472 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Drawing;
+using System.Xml;
+using Newtonsoft.Json.Utilities;
+
+namespace Newtonsoft.Json.Converters
+{
+ public class XmlNodeConverter : JsonConverter
+ {
+ private const string TextName = "#text";
+ private const string CommentName = "#comment";
+ private const string CDataName = "#cdata-section";
+ private const string WhitespaceName = "#whitespace";
+ private const string SignificantWhitespaceName = "#significant-whitespace";
+ private const string DeclarationName = "?xml";
+
+ #region Writing
+ public override void WriteJson(JsonWriter writer, object value)
+ {
+ XmlNode node = value as XmlNode;
+
+ if (node == null)
+ throw new ArgumentException("Value must be an XmlNode", "value");
+
+ writer.WriteStartObject();
+ SerializeNode(writer, node, true);
+ writer.WriteEndObject();
+ }
+
+ private string GetPropertyName(XmlNode node)
+ {
+ switch (node.NodeType)
+ {
+ case XmlNodeType.Attribute:
+ return "@" + node.Name;
+ case XmlNodeType.CDATA:
+ return CDataName;
+ case XmlNodeType.Comment:
+ return CommentName;
+ case XmlNodeType.Element:
+ return node.Name;
+ case XmlNodeType.ProcessingInstruction:
+ return "?" + node.Name;
+ case XmlNodeType.XmlDeclaration:
+ return DeclarationName;
+ case XmlNodeType.SignificantWhitespace:
+ return SignificantWhitespaceName;
+ case XmlNodeType.Text:
+ return TextName;
+ case XmlNodeType.Whitespace:
+ return WhitespaceName;
+ default:
+ throw new JsonSerializationException("Unexpected XmlNodeType when getting node name: " + node.NodeType);
+ }
+ }
+
+ private void SerializeGroupedNodes(JsonWriter writer, XmlNode node)
+ {
+ // group nodes together by name
+ Dictionary<string, List<XmlNode>> nodesGroupedByName = new Dictionary<string, List<XmlNode>>();
+
+ for (int i = 0; i < node.ChildNodes.Count; i++)
+ {
+ XmlNode childNode = node.ChildNodes[i];
+ string nodeName = GetPropertyName(childNode);
+
+ List<XmlNode> nodes;
+ if (!nodesGroupedByName.TryGetValue(nodeName, out nodes))
+ {
+ nodes = new List<XmlNode>();
+ nodesGroupedByName.Add(nodeName, nodes);
+ }
+
+ nodes.Add(childNode);
+ }
+
+ // loop through grouped nodes. write single name instances as normal,
+ // write multiple names together in an array
+ foreach (KeyValuePair<string, List<XmlNode>> nodeNameGroup in nodesGroupedByName)
+ {
+ List<XmlNode> groupedNodes = nodeNameGroup.Value;
+
+ if (groupedNodes.Count == 1)
+ {
+ SerializeNode(writer, groupedNodes[0], true);
+ }
+ else
+ {
+ writer.WritePropertyName(nodeNameGroup.Key);
+ writer.WriteStartArray();
+
+ for (int i = 0; i < groupedNodes.Count; i++)
+ {
+ SerializeNode(writer, groupedNodes[i], false);
+ }
+
+ writer.WriteEndArray();
+ }
+ }
+ }
+
+ private void SerializeNode(JsonWriter writer, XmlNode node, bool writePropertyName)
+ {
+ switch (node.NodeType)
+ {
+ case XmlNodeType.Document:
+ case XmlNodeType.DocumentFragment:
+ SerializeGroupedNodes(writer, node);
+ break;
+ case XmlNodeType.Element:
+ if (writePropertyName)
+ writer.WritePropertyName(node.Name);
+
+ if (CollectionUtils.IsNullOrEmpty(node.Attributes) && node.ChildNodes.Count == 1
+ && node.ChildNodes[0].NodeType == XmlNodeType.Text)
+ {
+ // write elements with a single text child as a name value pair
+ writer.WriteValue(node.ChildNodes[0].Value);
+ }
+ else if (node.ChildNodes.Count == 0 && CollectionUtils.IsNullOrEmpty(node.Attributes))
+ {
+ // empty element
+ writer.WriteNull();
+ }
+ else
+ {
+ writer.WriteStartObject();
+
+ for (int i = 0; i < node.Attributes.Count; i++)
+ {
+ SerializeNode(writer, node.Attributes[i], true);
+ }
+
+ SerializeGroupedNodes(writer, node);
+
+ writer.WriteEndObject();
+ }
+
+ break;
+ case XmlNodeType.Comment:
+ if (writePropertyName)
+ writer.WriteComment(node.Value);
+ break;
+ case XmlNodeType.Attribute:
+ case XmlNodeType.Text:
+ case XmlNodeType.CDATA:
+ case XmlNodeType.ProcessingInstruction:
+ case XmlNodeType.Whitespace:
+ case XmlNodeType.SignificantWhitespace:
+ if (writePropertyName)
+ writer.WritePropertyName(GetPropertyName(node));
+ writer.WriteValue(node.Value);
+ break;
+ case XmlNodeType.XmlDeclaration:
+ XmlDeclaration declaration = (XmlDeclaration)node;
+ writer.WritePropertyName(GetPropertyName(node));
+ writer.WriteStartObject();
+
+ if (!string.IsNullOrEmpty(declaration.Version))
+ {
+ writer.WritePropertyName("@version");
+ writer.WriteValue(declaration.Version);
+ }
+ if (!string.IsNullOrEmpty(declaration.Encoding))
+ {
+ writer.WritePropertyName("@encoding");
+ writer.WriteValue(declaration.Encoding);
+ }
+ if (!string.IsNullOrEmpty(declaration.Standalone))
+ {
+ writer.WritePropertyName("@standalone");
+ writer.WriteValue(declaration.Standalone);
+ }
+
+ writer.WriteEndObject();
+ break;
+ default:
+ throw new JsonSerializationException("Unexpected XmlNodeType when serializing nodes: " + node.NodeType);
+ }
+ }
+ #endregion
+
+ #region Reading
+ public override object ReadJson(JsonReader reader, Type objectType)
+ {
+ // maybe have CanReader and a CanWrite methods so this sort of test wouldn't be necessary
+ if (objectType != typeof(XmlDocument))
+ throw new JsonSerializationException("XmlNodeConverter only supports deserializing XmlDocuments");
+
+ XmlDocument document = new XmlDocument();
+ XmlNamespaceManager manager = new XmlNamespaceManager(document.NameTable);
+ reader.Read();
+
+ DeserializeNode(reader, document, manager, document);
+
+ return document;
+ }
+
+ private void DeserializeValue(JsonReader reader, XmlDocument document, XmlNamespaceManager manager, string propertyName, XmlNode currentNode)
+ {
+ switch (propertyName)
+ {
+ case TextName:
+ currentNode.AppendChild(document.CreateTextNode(reader.Value.ToString()));
+ break;
+ case CDataName:
+ currentNode.AppendChild(document.CreateCDataSection(reader.Value.ToString()));
+ break;
+ case WhitespaceName:
+ currentNode.AppendChild(document.CreateWhitespace(reader.Value.ToString()));
+ break;
+ case SignificantWhitespaceName:
+ currentNode.AppendChild(document.CreateSignificantWhitespace(reader.Value.ToString()));
+ break;
+ default:
+ // processing instructions and the xml declaration start with ?
+ if (propertyName[0] == '?')
+ {
+ if (propertyName == DeclarationName)
+ {
+ string version = null;
+ string encoding = null;
+ string standalone = null;
+ while (reader.Read() && reader.TokenType != JsonToken.EndObject)
+ {
+ switch (reader.Value.ToString())
+ {
+ case "@version":
+ reader.Read();
+ version = reader.Value.ToString();
+ break;
+ case "@encoding":
+ reader.Read();
+ encoding = reader.Value.ToString();
+ break;
+ case "@standalone":
+ reader.Read();
+ standalone = reader.Value.ToString();
+ break;
+ default:
+ throw new JsonSerializationException("Unexpected property name encountered while deserializing XmlDeclaration: " + reader.Value);
+ }
+ }
+
+ XmlDeclaration declaration = document.CreateXmlDeclaration(version, encoding, standalone);
+ currentNode.AppendChild(declaration);
+ }
+ else
+ {
+ XmlProcessingInstruction instruction = document.CreateProcessingInstruction(propertyName.Substring(1), reader.Value.ToString());
+ currentNode.AppendChild(instruction);
+ }
+ }
+ else
+ {
+ // deserialize xml element
+ bool finishedAttributes = false;
+ bool finishedElement = false;
+ string elementPrefix = GetPrefix(propertyName);
+ Dictionary<string, string> attributeNameValues = new Dictionary<string, string>();
+
+ // a string token means the element only has a single text child
+ if (reader.TokenType != JsonToken.String
+ && reader.TokenType != JsonToken.Null
+ && reader.TokenType != JsonToken.Boolean
+ && reader.TokenType != JsonToken.Integer
+ && reader.TokenType != JsonToken.Float
+ && reader.TokenType != JsonToken.Date)
+ {
+ // read properties until first non-attribute is encountered
+ while (!finishedAttributes && !finishedElement && reader.Read())
+ {
+ switch (reader.TokenType)
+ {
+ case JsonToken.PropertyName:
+ string attributeName = reader.Value.ToString();
+
+ if (attributeName[0] == '@')
+ {
+ attributeName = attributeName.Substring(1);
+ reader.Read();
+ string attributeValue = reader.Value.ToString();
+ attributeNameValues.Add(attributeName, attributeValue);
+
+ string namespacePrefix;
+
+ if (IsNamespaceAttribute(attributeName, out namespacePrefix))
+ {
+ manager.AddNamespace(namespacePrefix, attributeValue);
+ }
+ }
+ else
+ {
+ finishedAttributes = true;
+ }
+ break;
+ case JsonToken.EndObject:
+ finishedElement = true;
+ break;
+ default:
+ throw new JsonSerializationException("Unexpected JsonToken: " + reader.TokenType);
+ }
+ }
+ }
+
+ // have to wait until attributes have been parsed before creating element
+ // attributes may contain namespace info used by the element
+ XmlElement element = (!string.IsNullOrEmpty(elementPrefix))
+ ? document.CreateElement(propertyName, manager.LookupNamespace(elementPrefix))
+ : document.CreateElement(propertyName);
+
+ currentNode.AppendChild(element);
+
+ // add attributes to newly created element
+ foreach (KeyValuePair<string, string> nameValue in attributeNameValues)
+ {
+ string attributePrefix = GetPrefix(nameValue.Key);
+
+ XmlAttribute attribute = (!string.IsNullOrEmpty(attributePrefix))
+ ? document.CreateAttribute(nameValue.Key, manager.LookupNamespace(attributePrefix))
+ : document.CreateAttribute(nameValue.Key);
+
+ attribute.Value = nameValue.Value;
+
+ element.SetAttributeNode(attribute);
+ }
+
+ if (reader.TokenType == JsonToken.String)
+ {
+ element.AppendChild(document.CreateTextNode(reader.Value.ToString()));
+ }
+ else if (reader.TokenType == JsonToken.Integer)
+ {
+ element.AppendChild(document.CreateTextNode(XmlConvert.ToString((long)reader.Value)));
+ }
+ else if (reader.TokenType == JsonToken.Float)
+ {
+ element.AppendChild(document.CreateTextNode(XmlConvert.ToString((double)reader.Value)));
+ }
+ else if (reader.TokenType == JsonToken.Boolean)
+ {
+ element.AppendChild(document.CreateTextNode(XmlConvert.ToString((bool)reader.Value)));
+ }
+ else if (reader.TokenType == JsonToken.Date)
+ {
+ element.AppendChild(document.CreateTextNode(XmlConvert.ToString((DateTime)reader.Value)));
+ }
+ else if (reader.TokenType == JsonToken.Null)
+ {
+ // empty element. do nothing
+ }
+ else
+ {
+ // finished element will have no children to deserialize
+ if (!finishedElement)
+ {
+ manager.PushScope();
+
+ DeserializeNode(reader, document, manager, element);
+
+ manager.PopScope();
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ private void DeserializeNode(JsonReader reader, XmlDocument document, XmlNamespaceManager manager, XmlNode currentNode)
+ {
+ do
+ {
+ switch (reader.TokenType)
+ {
+ case JsonToken.PropertyName:
+ string propertyName = reader.Value.ToString();
+ reader.Read();
+
+ if (reader.TokenType == JsonToken.StartArray)
+ {
+ while (reader.Read() && reader.TokenType != JsonToken.EndArray)
+ {
+ DeserializeValue(reader, document, manager, propertyName, currentNode);
+ }
+ }
+ else
+ {
+ DeserializeValue(reader, document, manager, propertyName, currentNode);
+ }
+ break;
+ //case JsonToken.String:
+ // DeserializeValue(reader, document, manager, TextName, currentNode);
+ // break;
+ case JsonToken.EndObject:
+ case JsonToken.EndArray:
+ return;
+ default:
+ throw new JsonSerializationException("Unexpected JsonToken when deserializing node: " + reader.TokenType);
+ }
+ } while (reader.TokenType == JsonToken.PropertyName || reader.Read());
+ // don't read if current token is a property. token was already read when parsing element attributes
+ }
+
+ /// <summary>
+ /// Checks if the attributeName is a namespace attribute.
+ /// </summary>
+ /// <param name="attributeName">Attribute name to test.</param>
+ /// <param name="prefix">The attribute name prefix if it has one, otherwise an empty string.</param>
+ /// <returns>True if attribute name is for a namespace attribute, otherwise false.</returns>
+ private bool IsNamespaceAttribute(string attributeName, out string prefix)
+ {
+ if (attributeName.StartsWith("xmlns", StringComparison.Ordinal))
+ {
+ if (attributeName.Length == 5)
+ {
+ prefix = string.Empty;
+ return true;
+ }
+ else if (attributeName[5] == ':')
+ {
+ prefix = attributeName.Substring(6, attributeName.Length - 6);
+ return true;
+ }
+ }
+ prefix = null;
+ return false;
+ }
+
+ private string GetPrefix(string qualifiedName)
+ {
+ int colonPosition = qualifiedName.IndexOf(':');
+
+ if ((colonPosition == -1 || colonPosition == 0) || (qualifiedName.Length - 1) == colonPosition)
+ return string.Empty;
+ else
+ return qualifiedName.Substring(0, colonPosition);
+ }
+ #endregion
+
+ public override bool CanConvert(Type valueType)
+ {
+ return typeof(XmlNode).IsAssignableFrom(valueType);
+ }
+ }
+}
diff --git a/Src/Newtonsoft.Json/Identifier.cs b/Src/Newtonsoft.Json/Identifier.cs new file mode 100644 index 0000000..b74df37 --- /dev/null +++ b/Src/Newtonsoft.Json/Identifier.cs @@ -0,0 +1,102 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Web;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Web.UI.WebControls;
+using System.ComponentModel;
+
+namespace Newtonsoft.Json
+{
+ public class Identifier
+ {
+ private string _name;
+
+ public string Name
+ {
+ get { return _name; }
+ }
+
+ public Identifier(string name)
+ {
+ _name = name;
+ }
+
+ private static bool IsAsciiLetter(char c)
+ {
+ return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
+ }
+
+ public override bool Equals(object obj)
+ {
+ Identifier function = obj as Identifier;
+
+ return Equals(function);
+ }
+
+ public bool Equals(Identifier function)
+ {
+ return (_name == function.Name);
+ }
+
+ public static bool Equals(Identifier a, Identifier b)
+ {
+ if (a == b)
+ return true;
+
+ if (a != null && b != null)
+ return a.Equals(b);
+
+ return false;
+ }
+
+ public override int GetHashCode()
+ {
+ return _name.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return _name;
+ }
+
+ public static bool operator ==(Identifier a, Identifier b)
+ {
+ return Identifier.Equals(a, b);
+ }
+
+ public static bool operator !=(Identifier a, Identifier b)
+ {
+ return !Identifier.Equals(a, b);
+ }
+ }
+}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json/JavaScriptArray.cs b/Src/Newtonsoft.Json/JavaScriptArray.cs new file mode 100644 index 0000000..6456cdd --- /dev/null +++ b/Src/Newtonsoft.Json/JavaScriptArray.cs @@ -0,0 +1,64 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Newtonsoft.Json
+{
+ /// <summary>
+ /// Represents a JavaScript array.
+ /// </summary>
+ public class JavaScriptArray : List<object>
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="JavaScriptObject"/> class.
+ /// </summary>
+ public JavaScriptArray()
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="JavaScriptArray"/> class that
+ /// contains elements copied from the specified collection.
+ /// </summary>
+ /// <param name="collection">The collection whose elements are copied to the new array.</param>
+ public JavaScriptArray(IEnumerable<object> collection)
+ : base(collection)
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="JavaScriptArray"/> class that
+ /// is empty and has the specified initial capacity.
+ /// </summary>
+ /// <param name="capacity">The number of elements that the new array can initially store.</param>
+ public JavaScriptArray(int capacity)
+ : base(capacity)
+ {
+ }
+ }
+}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json/JavaScriptConstructor.cs b/Src/Newtonsoft.Json/JavaScriptConstructor.cs new file mode 100644 index 0000000..dd5b2b4 --- /dev/null +++ b/Src/Newtonsoft.Json/JavaScriptConstructor.cs @@ -0,0 +1,81 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Newtonsoft.Json
+{
+ /// <summary>
+ /// Represents a JavaScript constructor.
+ /// </summary>
+ public class JavaScriptConstructor
+ {
+ private string _name;
+ private JavaScriptParameters _parameters;
+
+ public JavaScriptParameters Parameters
+ {
+ get { return _parameters; }
+ }
+
+ public string Name
+ {
+ get { return _name; }
+ }
+
+ public JavaScriptConstructor(string name, JavaScriptParameters parameters)
+ {
+ if (name == null)
+ throw new ArgumentNullException("name");
+
+ if (name.Length == 0)
+ throw new ArgumentException("Constructor name cannot be empty.", "name");
+
+ _name = name;
+ _parameters = parameters ?? JavaScriptParameters.Empty;
+ }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+
+ sb.Append("new ");
+ sb.Append(_name);
+ sb.Append("(");
+ if (_parameters != null)
+ {
+ for (int i = 0; i < _parameters.Count; i++)
+ {
+ sb.Append(_parameters[i]);
+ }
+ }
+ sb.Append(")");
+
+ return sb.ToString();
+ }
+ }
+}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json/JavaScriptConvert.cs b/Src/Newtonsoft.Json/JavaScriptConvert.cs new file mode 100644 index 0000000..ea1f7df --- /dev/null +++ b/Src/Newtonsoft.Json/JavaScriptConvert.cs @@ -0,0 +1,448 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Drawing;
+using System.Web.UI.WebControls;
+using System.Collections;
+using System.IO;
+using System.Globalization;
+using System.Runtime.Serialization;
+using System.Reflection;
+using System.Data.SqlTypes;
+using Newtonsoft.Json.Utilities;
+using System.Xml;
+using Newtonsoft.Json.Converters;
+
+namespace Newtonsoft.Json
+{
+ /// <summary>
+ /// Provides methods for converting between common language runtime types and JavaScript types.
+ /// </summary>
+ public static class JavaScriptConvert
+ {
+ /// <summary>
+ /// Represents JavaScript's boolean value true as a string. This field is read-only.
+ /// </summary>
+ public static readonly string True;
+
+ /// <summary>
+ /// Represents JavaScript's boolean value false as a string. This field is read-only.
+ /// </summary>
+ public static readonly string False;
+
+ /// <summary>
+ /// Represents JavaScript's null as a string. This field is read-only.
+ /// </summary>
+ public static readonly string Null;
+
+ /// <summary>
+ /// Represents JavaScript's undefined as a string. This field is read-only.
+ /// </summary>
+ public static readonly string Undefined;
+
+ internal static long InitialJavaScriptDateTicks;
+ internal static DateTime MinimumJavaScriptDate;
+
+ static JavaScriptConvert()
+ {
+ True = "true";
+ False = "false";
+ Null = "null";
+ Undefined = "undefined";
+
+ InitialJavaScriptDateTicks = (new DateTime(1970, 1, 1)).Ticks;
+ MinimumJavaScriptDate = new DateTime(100, 1, 1);
+ }
+
+ /// <summary>
+ /// Converts the <see cref="DateTime"/> to it's JavaScript string representation.
+ /// </summary>
+ /// <param name="value">The value to convert.</param>
+ /// <returns>A Json string representation of the <see cref="DateTime"/>.</returns>
+ public static string ToString(DateTime value)
+ {
+ long javaScriptTicks = ConvertDateTimeToJavaScriptTicks(value);
+
+ return "new Date(" + javaScriptTicks + ")";
+ }
+
+ internal static long ConvertDateTimeToJavaScriptTicks(DateTime dateTime)
+ {
+ if (dateTime < MinimumJavaScriptDate)
+ dateTime = MinimumJavaScriptDate;
+
+ long javaScriptTicks = (dateTime.Ticks - InitialJavaScriptDateTicks) / (long)10000;
+
+ return javaScriptTicks;
+ }
+
+ internal static DateTime ConvertJavaScriptTicksToDateTime(long javaScriptTicks)
+ {
+ DateTime dateTime = new DateTime((javaScriptTicks * 10000) + InitialJavaScriptDateTicks);
+
+ return dateTime;
+ }
+
+ /// <summary>
+ /// Converts the <see cref="Boolean"/> to it's JavaScript string representation.
+ /// </summary>
+ /// <param name="value">The value to convert.</param>
+ /// <returns>A Json string representation of the <see cref="Boolean"/>.</returns>
+ public static string ToString(bool value)
+ {
+ return (value) ? True : False;
+ }
+
+ /// <summary>
+ /// Converts the <see cref="Char"/> to it's JavaScript string representation.
+ /// </summary>
+ /// <param name="value">The value to convert.</param>
+ /// <returns>A Json string representation of the <see cref="Char"/>.</returns>
+ public static string ToString(char value)
+ {
+ return ToString(char.ToString(value));
+ }
+
+ /// <summary>
+ /// Converts the <see cref="Enum"/> to it's JavaScript string representation.
+ /// </summary>
+ /// <param name="value">The value to convert.</param>
+ /// <returns>A Json string representation of the <see cref="Enum"/>.</returns>
+ public static string ToString(Enum value)
+ {
+ return value.ToString();
+ }
+
+ /// <summary>
+ /// Converts the <see cref="Int32"/> to it's JavaScript string representation.
+ /// </summary>
+ /// <param name="value">The value to convert.</param>
+ /// <returns>A Json string representation of the <see cref="Int32"/>.</returns>
+ public static string ToString(int value)
+ {
+ return value.ToString(null, CultureInfo.InvariantCulture);
+ }
+
+ /// <summary>
+ /// Converts the <see cref="Int16"/> to it's JavaScript string representation.
+ /// </summary>
+ /// <param name="value">The value to convert.</param>
+ /// <returns>A Json string representation of the <see cref="Int16"/>.</returns>
+ public static string ToString(short value)
+ {
+ return value.ToString(null, CultureInfo.InvariantCulture);
+ }
+
+ /// <summary>
+ /// Converts the <see cref="UInt16"/> to it's JavaScript string representation.
+ /// </summary>
+ /// <param name="value">The value to convert.</param>
+ /// <returns>A Json string representation of the <see cref="UInt16"/>.</returns>
+ public static string ToString(ushort value)
+ {
+ return value.ToString(null, CultureInfo.InvariantCulture);
+ }
+
+ /// <summary>
+ /// Converts the <see cref="UInt32"/> to it's JavaScript string representation.
+ /// </summary>
+ /// <param name="value">The value to convert.</param>
+ /// <returns>A Json string representation of the <see cref="UInt32"/>.</returns>
+ public static string ToString(uint value)
+ {
+ return value.ToString(null, CultureInfo.InvariantCulture);
+ }
+
+ /// <summary>
+ /// Converts the <see cref="Int64"/> to it's JavaScript string representation.
+ /// </summary>
+ /// <param name="value">The value to convert.</param>
+ /// <returns>A Json string representation of the <see cref="Int64"/>.</returns>
+ public static string ToString(long value)
+ {
+ return value.ToString(null, CultureInfo.InvariantCulture);
+ }
+
+ /// <summary>
+ /// Converts the <see cref="UInt64"/> to it's JavaScript string representation.
+ /// </summary>
+ /// <param name="value">The value to convert.</param>
+ /// <returns>A Json string representation of the <see cref="UInt64"/>.</returns>
+ public static string ToString(ulong value)
+ {
+ return value.ToString(null, CultureInfo.InvariantCulture);
+ }
+
+ /// <summary>
+ /// Converts the <see cref="Single"/> to it's JavaScript string representation.
+ /// </summary>
+ /// <param name="value">The value to convert.</param>
+ /// <returns>A Json string representation of the <see cref="Single"/>.</returns>
+ public static string ToString(float value)
+ {
+ return value.ToString(null, CultureInfo.InvariantCulture);
+ }
+
+ /// <summary>
+ /// Converts the <see cref="Double"/> to it's JavaScript string representation.
+ /// </summary>
+ /// <param name="value">The value to convert.</param>
+ /// <returns>A Json string representation of the <see cref="Double"/>.</returns>
+ public static string ToString(double value)
+ {
+ return value.ToString(null, CultureInfo.InvariantCulture);
+ }
+
+ /// <summary>
+ /// Converts the <see cref="Byte"/> to it's JavaScript string representation.
+ /// </summary>
+ /// <param name="value">The value to convert.</param>
+ /// <returns>A Json string representation of the <see cref="Byte"/>.</returns>
+ public static string ToString(byte value)
+ {
+ return value.ToString(null, CultureInfo.InvariantCulture);
+ }
+
+ /// <summary>
+ /// Converts the <see cref="SByte"/> to it's JavaScript string representation.
+ /// </summary>
+ /// <param name="value">The value to convert.</param>
+ /// <returns>A Json string representation of the <see cref="SByte"/>.</returns>
+ public static string ToString(sbyte value)
+ {
+ return value.ToString(null, CultureInfo.InvariantCulture);
+ }
+
+ /// <summary>
+ /// Converts the <see cref="Decimal"/> to it's JavaScript string representation.
+ /// </summary>
+ /// <param name="value">The value to convert.</param>
+ /// <returns>A Json string representation of the <see cref="SByte"/>.</returns>
+ public static string ToString(decimal value)
+ {
+ return value.ToString(null, CultureInfo.InvariantCulture);
+ }
+
+ /// <summary>
+ /// Converts the <see cref="Guid"/> to it's JavaScript string representation.
+ /// </summary>
+ /// <param name="value">The value to convert.</param>
+ /// <returns>A Json string representation of the <see cref="Guid"/>.</returns>
+ public static string ToString(Guid value)
+ {
+ return '"' + value.ToString("D", CultureInfo.InvariantCulture) + '"';
+ }
+
+ /// <summary>
+ /// Converts the <see cref="String"/> to it's JavaScript string representation.
+ /// </summary>
+ /// <param name="value">The value to convert.</param>
+ /// <returns>A Json string representation of the <see cref="String"/>.</returns>
+ public static string ToString(string value)
+ {
+ return ToString(value, '"');
+ }
+
+ /// <summary>
+ /// Converts the <see cref="String"/> to it's JavaScript string representation.
+ /// </summary>
+ /// <param name="value">The value to convert.</param>
+ /// <param name="delimter">The string delimiter character.</param>
+ /// <returns>A Json string representation of the <see cref="String"/>.</returns>
+ public static string ToString(string value, char delimter)
+ {
+ return JavaScriptUtils.ToEscapedJavaScriptString(value, delimter, true);
+ }
+
+ /// <summary>
+ /// Converts the <see cref="Object"/> to it's JavaScript string representation.
+ /// </summary>
+ /// <param name="value">The value to convert.</param>
+ /// <returns>A Json string representation of the <see cref="Object"/>.</returns>
+ public static string ToString(object value)
+ {
+ if (value == null)
+ {
+ return Null;
+ }
+ else if (value is IConvertible)
+ {
+ IConvertible convertible = value as IConvertible;
+
+ switch (convertible.GetTypeCode())
+ {
+ case TypeCode.String:
+ return ToString((string)convertible);
+ case TypeCode.Char:
+ return ToString((char)convertible);
+ case TypeCode.Boolean:
+ return ToString((bool)convertible);
+ case TypeCode.SByte:
+ return ToString((sbyte)convertible);
+ case TypeCode.Int16:
+ return ToString((short)convertible);
+ case TypeCode.UInt16:
+ return ToString((ushort)convertible);
+ case TypeCode.Int32:
+ return ToString((int)convertible);
+ case TypeCode.Byte:
+ return ToString((byte)convertible);
+ case TypeCode.UInt32:
+ return ToString((uint)convertible);
+ case TypeCode.Int64:
+ return ToString((long)convertible);
+ case TypeCode.UInt64:
+ return ToString((ulong)convertible);
+ case TypeCode.Single:
+ return ToString((float)convertible);
+ case TypeCode.Double:
+ return ToString((double)convertible);
+ case TypeCode.DateTime:
+ return ToString((DateTime)convertible);
+ case TypeCode.Decimal:
+ return ToString((decimal)convertible);
+ }
+ }
+
+ throw new ArgumentException(string.Format("Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.", value.GetType()));
+ }
+
+ /// <summary>
+ /// Serializes the specified object to a Json object.
+ /// </summary>
+ /// <param name="value">The object to serialize.</param>
+ /// <returns>A Json string representation of the object.</returns>
+ public static string SerializeObject(object value)
+ {
+ return SerializeObject(value, null);
+ }
+
+ public static string SerializeObject(object value, params JsonConverter[] converters)
+ {
+ StringWriter sw = new StringWriter(CultureInfo.InvariantCulture);
+ JsonSerializer jsonSerializer = new JsonSerializer();
+
+ if (!CollectionUtils.IsNullOrEmpty<JsonConverter>(converters))
+ {
+ for (int i = 0; i < converters.Length; i++)
+ {
+ jsonSerializer.Converters.Add(converters[i]);
+ }
+ }
+
+ using (JsonWriter jsonWriter = new JsonWriter(sw))
+ {
+ //jsonWriter.Formatting = Formatting.Indented;
+ jsonSerializer.Serialize(jsonWriter, value);
+ }
+
+ return sw.ToString();
+ }
+
+ /// <summary>
+ /// Deserializes the specified object to a Json object.
+ /// </summary>
+ /// <param name="value">The object to deserialize.</param>
+ /// <returns>The deserialized object from the Json string.</returns>
+ public static object DeserializeObject(string value)
+ {
+ return DeserializeObject(value, null, null);
+ }
+
+ /// <summary>
+ /// Deserializes the specified object to a Json object.
+ /// </summary>
+ /// <param name="value">The object to deserialize.</param>
+ /// <param name="type">The <see cref="Type"/> of object being deserialized.</param>
+ /// <returns>The deserialized object from the Json string.</returns>
+ public static object DeserializeObject(string value, Type type)
+ {
+ return DeserializeObject(value, type, null);
+ }
+
+ /// <summary>
+ /// Deserializes the specified object to a Json object.
+ /// </summary>
+ /// <typeparam name="T">The type of the object to deserialize.</typeparam>
+ /// <param name="value">The object to deserialize.</param>
+ /// <returns>The deserialized object from the Json string.</returns>
+ public static T DeserializeObject<T>(string value)
+ {
+ return DeserializeObject<T>(value, null);
+ }
+
+ /// <summary>
+ /// Deserializes the specified object to a Json object.
+ /// </summary>
+ /// <typeparam name="T">The type of the object to deserialize.</typeparam>
+ /// <param name="value">The object to deserialize.</param>
+ /// <param name="converters">Converters to use while deserializing.</param>
+ /// <returns>The deserialized object from the Json string.</returns>
+ public static T DeserializeObject<T>(string value, params JsonConverter[] converters)
+ {
+ return (T)DeserializeObject(value, typeof(T), converters);
+ }
+
+ public static object DeserializeObject(string value, Type type, params JsonConverter[] converters)
+ {
+ StringReader sr = new StringReader(value);
+ JsonSerializer jsonSerializer = new JsonSerializer();
+
+ if (!CollectionUtils.IsNullOrEmpty<JsonConverter>(converters))
+ {
+ for (int i = 0; i < converters.Length; i++)
+ {
+ jsonSerializer.Converters.Add(converters[i]);
+ }
+ }
+
+ object deserializedValue;
+
+ using (JsonReader jsonReader = new JsonReader(sr))
+ {
+ deserializedValue = jsonSerializer.Deserialize(jsonReader, type);
+ }
+
+ return deserializedValue;
+ }
+
+ public static string SerializeXmlNode(XmlNode node)
+ {
+ XmlNodeConverter converter = new XmlNodeConverter();
+
+ return SerializeObject(node, converter);
+ }
+
+ public static XmlNode DeerializeXmlNode(string value)
+ {
+ XmlNodeConverter converter = new XmlNodeConverter();
+
+ return (XmlDocument)DeserializeObject(value, typeof(XmlDocument), converter);
+ }
+ }
+}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json/JavaScriptObject.cs b/Src/Newtonsoft.Json/JavaScriptObject.cs new file mode 100644 index 0000000..b1625ba --- /dev/null +++ b/Src/Newtonsoft.Json/JavaScriptObject.cs @@ -0,0 +1,55 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Newtonsoft.Json
+{
+ /// <summary>
+ /// Represents a JavaScript object.
+ /// </summary>
+ public class JavaScriptObject : Dictionary<string, object>
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="JavaScriptObject"/> class.
+ /// </summary>
+ public JavaScriptObject()
+ : base(EqualityComparer<string>.Default)
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="JavaScriptObject"/> class that
+ /// contains values copied from the specified <see cref="JavaScriptObject"/>.
+ /// </summary>
+ /// <param name="javaScriptObject">The <see cref="JavaScriptObject"/> whose elements are copied to the new object.</param>
+ public JavaScriptObject(JavaScriptObject javaScriptObject)
+ : base(javaScriptObject, EqualityComparer<string>.Default)
+ {
+ }
+ }
+}
diff --git a/Src/Newtonsoft.Json/JavaScriptParameters.cs b/Src/Newtonsoft.Json/JavaScriptParameters.cs new file mode 100644 index 0000000..ba0a2cd --- /dev/null +++ b/Src/Newtonsoft.Json/JavaScriptParameters.cs @@ -0,0 +1,42 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Collections.ObjectModel;
+
+namespace Newtonsoft.Json
+{
+ public class JavaScriptParameters : ReadOnlyCollection<object>
+ {
+ public static readonly JavaScriptParameters Empty = new JavaScriptParameters(new List<object>());
+
+ public JavaScriptParameters(IList<object> list)
+ : base(list)
+ {
+ }
+ }
+}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonConverter.cs b/Src/Newtonsoft.Json/JsonConverter.cs new file mode 100644 index 0000000..bff625b --- /dev/null +++ b/Src/Newtonsoft.Json/JsonConverter.cs @@ -0,0 +1,48 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Newtonsoft.Json
+{
+ public abstract class JsonConverter
+ {
+ public virtual void WriteJson(JsonWriter writer, object value)
+ {
+ JsonSerializer serializer = new JsonSerializer();
+
+ serializer.Serialize(writer, value);
+ }
+
+ public virtual object ReadJson(JsonReader reader, Type objectType)
+ {
+ throw new NotImplementedException(string.Format("{0} has not overriden FromJson method.", GetType().Name));
+ }
+
+ public abstract bool CanConvert(Type objectType);
+ }
+}
diff --git a/Src/Newtonsoft.Json/JsonConverterCollection.cs b/Src/Newtonsoft.Json/JsonConverterCollection.cs new file mode 100644 index 0000000..b19ab76 --- /dev/null +++ b/Src/Newtonsoft.Json/JsonConverterCollection.cs @@ -0,0 +1,36 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Collections.ObjectModel;
+
+namespace Newtonsoft.Json
+{
+ public class JsonConverterCollection : Collection<JsonConverter>
+ {
+ }
+}
diff --git a/Src/Newtonsoft.Json/JsonHandler.cs b/Src/Newtonsoft.Json/JsonHandler.cs new file mode 100644 index 0000000..ca2a93f --- /dev/null +++ b/Src/Newtonsoft.Json/JsonHandler.cs @@ -0,0 +1,63 @@ +using System;
+using System.Web;
+using System.Web.Caching;
+using System.Xml;
+using System.Text;
+using System.Security.Principal;
+
+namespace Newtonsoft.Json
+{
+ public abstract class JsonHandler : HandlerBase, IHttpHandler
+ {
+ public event EventHandler Error;
+
+ protected abstract void WriteResult(JsonWriter writer);
+
+ public static void JsonResponse(HttpResponse response, Action<JsonWriter> writeAction)
+ {
+ response.ClearHeaders();
+ response.ClearContent();
+
+ JsonWriter writer = new JsonWriter(response.Output);
+
+ writeAction(writer);
+
+ writer.Flush();
+ }
+
+ protected virtual void OnError(EventArgs e)
+ {
+ if (Error != null)
+ {
+ Error(this, e);
+ }
+ }
+
+ void IHttpHandler.ProcessRequest(HttpContext context)
+ {
+ if (context == null)
+ throw new ArgumentNullException("context");
+
+ Context = context;
+
+ try
+ {
+ JsonHandler.JsonResponse(context.Response, new Action<JsonWriter>(WriteResult));
+ }
+ catch (Exception exception)
+ {
+ context.AddError(exception);
+ OnError(EventArgs.Empty);
+ if (context.Error != null)
+ {
+ throw new HttpUnhandledException("blah", exception);
+ }
+ }
+ }
+
+ bool IHttpHandler.IsReusable
+ {
+ get { return false; }
+ }
+ }
+}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonIgnoreAttribute.cs b/Src/Newtonsoft.Json/JsonIgnoreAttribute.cs new file mode 100644 index 0000000..8262998 --- /dev/null +++ b/Src/Newtonsoft.Json/JsonIgnoreAttribute.cs @@ -0,0 +1,36 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Newtonsoft.Json
+{
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
+ public sealed class JsonIgnoreAttribute : Attribute
+ {
+ }
+}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonPropertyAttribute.cs b/Src/Newtonsoft.Json/JsonPropertyAttribute.cs new file mode 100644 index 0000000..08f8094 --- /dev/null +++ b/Src/Newtonsoft.Json/JsonPropertyAttribute.cs @@ -0,0 +1,21 @@ +using System;
+
+namespace Newtonsoft.Json
+{
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
+ public sealed class JsonPropertyAttribute : Attribute
+ {
+ private string _propertyName;
+
+ public string PropertyName
+ {
+ get { return _propertyName; }
+ set { _propertyName = value; }
+ }
+
+ public JsonPropertyAttribute(string propertyName)
+ {
+ _propertyName = propertyName;
+ }
+ }
+}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonReader.cs b/Src/Newtonsoft.Json/JsonReader.cs new file mode 100644 index 0000000..197da20 --- /dev/null +++ b/Src/Newtonsoft.Json/JsonReader.cs @@ -0,0 +1,897 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+using System.Xml;
+using System.Globalization;
+
+namespace Newtonsoft.Json
+{
+ /// <summary>
+ /// Represents a reader that provides fast, non-cached, forward-only access to serialized Json data.
+ /// </summary>
+ public class JsonReader : IDisposable
+ {
+ private enum State
+ {
+ Start,
+ Complete,
+ Property,
+ ObjectStart,
+ Object,
+ ArrayStart,
+ Array,
+ Closed,
+ PostValue,
+ Constructor,
+ ConstructorEnd,
+ Error,
+ Finished
+ }
+
+ private TextReader _reader;
+ private char _currentChar;
+
+ // current Token data
+ private JsonToken _token;
+ private object _value;
+ private Type _valueType;
+ private char _quoteChar;
+ private StringBuffer _buffer;
+ //private StringBuilder _testBuffer;
+ private State _currentState;
+
+ private int _top;
+ private List<JsonType> _stack;
+
+ /// <summary>
+ /// Gets the quotation mark character used to enclose the value of a string.
+ /// </summary>
+ public char QuoteChar
+ {
+ get { return _quoteChar; }
+ }
+
+ /// <summary>
+ /// Gets the type of the current Json token.
+ /// </summary>
+ public JsonToken TokenType
+ {
+ get { return _token; }
+ }
+
+ /// <summary>
+ /// Gets the text value of the current Json token.
+ /// </summary>
+ public object Value
+ {
+ get { return _value; }
+ }
+
+ /// <summary>
+ /// Gets The Common Language Runtime (CLR) type for the current Json token.
+ /// </summary>
+ public Type ValueType
+ {
+ get { return _valueType; }
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="JsonReader"/> class with the specified <see cref="TextReader"/>.
+ /// </summary>
+ /// <param name="reader">The <c>TextReader</c> containing the XML data to read.</param>
+ public JsonReader(TextReader reader)
+ {
+ if (reader == null)
+ throw new ArgumentNullException("reader");
+
+ _reader = reader;
+ _buffer = new StringBuffer(4096);
+ //_testBuffer = new StringBuilder();
+ _currentState = State.Start;
+ _stack = new List<JsonType>();
+ _top = 0;
+ Push(JsonType.None);
+ }
+
+ private void Push(JsonType value)
+ {
+ _stack.Add(value);
+ _top++;
+ }
+
+ private JsonType Pop()
+ {
+ JsonType value = Peek();
+ _stack.RemoveAt(_stack.Count - 1);
+ _top--;
+
+ return value;
+ }
+
+ private JsonType Peek()
+ {
+ return _stack[_top - 1];
+ }
+
+ private void ParseString(char quote)
+ {
+ bool stringTerminated = false;
+
+ while (!stringTerminated && MoveNext())
+ {
+ switch (_currentChar)
+ {
+ //case 0:
+ //case 0x0A:
+ //case 0x0D:
+ // throw new JsonReaderException("Unterminated string");
+ case '\\':
+ if (MoveNext())
+ {
+ switch (_currentChar)
+ {
+ case 'b':
+ _buffer.Append('\b');
+ break;
+ case 't':
+ _buffer.Append('\t');
+ break;
+ case 'n':
+ _buffer.Append('\n');
+ break;
+ case 'f':
+ _buffer.Append('\f');
+ break;
+ case 'r':
+ _buffer.Append('\r');
+ break;
+ case 'u':
+ //_buffer.Append((char) Integer.parseInt(next(4), 16));
+ break;
+ case 'x':
+ //_buffer.Append((char) Integer.parseInt(next(2), 16));
+ break;
+ default:
+ _buffer.Append(_currentChar);
+ break;
+ }
+ }
+ else
+ {
+ throw new JsonReaderException("Unterminated string. Expected delimiter: " + quote);
+ }
+ break;
+ case '"':
+ case '\'':
+ if (_currentChar == quote)
+ stringTerminated = true;
+ else
+ goto default;
+ break;
+ default:
+ _buffer.Append(_currentChar);
+ break;
+ }
+ }
+
+ if (!stringTerminated)
+ throw new JsonReaderException("Unterminated string. Expected delimiter: " + quote);
+
+ ClearCurrentChar();
+ _currentState = State.PostValue;
+ _token = JsonToken.String;
+ _value = _buffer.ToString();
+ _buffer.Position = 0;
+ _valueType = typeof(string);
+ _quoteChar = quote;
+ }
+
+ private bool MoveNext()
+ {
+ int value = _reader.Read();
+
+ if (value != -1)
+ {
+ _currentChar = (char)value;
+ //_testBuffer.Append(_currentChar);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ private bool HasNext()
+ {
+ return (_reader.Peek() != -1);
+ }
+
+ private char PeekNext()
+ {
+ return (char)_reader.Peek();
+ }
+
+ private void ClearCurrentChar()
+ {
+ _currentChar = '\0';
+ }
+
+ private bool MoveTo(char value)
+ {
+ while (MoveNext())
+ {
+ if (_currentChar == value)
+ return true;
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Reads the next Json token from the stream.
+ /// </summary>
+ /// <returns></returns>
+ public bool Read()
+ {
+ while (true)
+ {
+ if (_currentChar == '\0')
+ {
+ if (!MoveNext())
+ return false;
+ }
+
+ switch (_currentState)
+ {
+ case State.Start:
+ case State.Property:
+ case State.Array:
+ case State.ArrayStart:
+ return ParseValue();
+ case State.Complete:
+ break;
+ case State.Object:
+ case State.ObjectStart:
+ return ParseObject();
+ case State.PostValue:
+ // returns true if it hits
+ // end of object or array
+ if (ParsePostValue())
+ return true;
+ break;
+ case State.Closed:
+ break;
+ case State.Error:
+ break;
+ default:
+ throw new JsonReaderException("Unexpected state: " + _currentState);
+ }
+ }
+ }
+
+ private bool ParsePostValue()
+ {
+ do
+ {
+ switch (_currentChar)
+ {
+ case '}':
+ SetToken(JsonToken.EndObject);
+ ClearCurrentChar();
+ return true;
+ case ']':
+ SetToken(JsonToken.EndArray);
+ ClearCurrentChar();
+ return true;
+ case '/':
+ ParseComment();
+ return true;
+ case ',':
+ // finished paring
+ SetStateBasedOnCurrent();
+ ClearCurrentChar();
+ return false;
+ default:
+ if (char.IsWhiteSpace(_currentChar))
+ {
+ // eat whitespace
+ ClearCurrentChar();
+ }
+ else
+ {
+ throw new JsonReaderException("After parsing a value an unexpected character was encoutered: " + _currentChar);
+ }
+ break;
+ }
+ } while (MoveNext());
+
+ return false;
+ }
+
+ private bool ParseObject()
+ {
+ do
+ {
+ switch (_currentChar)
+ {
+ case '}':
+ SetToken(JsonToken.EndObject);
+ return true;
+ case '/':
+ ParseComment();
+ return true;
+ case ',':
+ SetToken(JsonToken.Undefined);
+ return true;
+ default:
+ if (char.IsWhiteSpace(_currentChar))
+ {
+ // eat
+ }
+ else
+ {
+ return ParseProperty();
+ }
+ break;
+ }
+ } while (MoveNext());
+
+ return false;
+ }
+
+ private bool ParseProperty()
+ {
+ if (ValidIdentifierChar(_currentChar))
+ {
+ ParseUnquotedProperty();
+ }
+ else if (_currentChar == '"' || _currentChar == '\'')
+ {
+ ParseQuotedProperty(_currentChar);
+ }
+ else
+ {
+ throw new JsonReaderException("Invalid property identifier character: " + _currentChar);
+ }
+
+ // finished property. move to colon
+ if (_currentChar != ':')
+ {
+ MoveTo(':');
+ }
+
+ SetToken(JsonToken.PropertyName, _buffer.ToString());
+ _buffer.Position = 0;
+
+ return true;
+ }
+
+ private void ParseQuotedProperty(char quoteChar)
+ {
+ // parse property name until quoted char is hit
+ while (MoveNext())
+ {
+ if (_currentChar == quoteChar)
+ {
+ return;
+ }
+ else
+ {
+ _buffer.Append(_currentChar);
+ }
+ }
+
+ throw new JsonReaderException("Unclosed quoted property. Expected: " + quoteChar);
+ }
+
+ private bool ValidIdentifierChar(char value)
+ {
+ return (char.IsLetterOrDigit(_currentChar) || _currentChar == '_' || _currentChar == '$');
+ }
+
+ private void ParseUnquotedProperty()
+ {
+ // parse unquoted property name until whitespace or colon
+ _buffer.Append(_currentChar);
+
+ while (MoveNext())
+ {
+ if (char.IsWhiteSpace(_currentChar) || _currentChar == ':')
+ {
+ break;
+ }
+ else if (ValidIdentifierChar(_currentChar))
+ {
+ _buffer.Append(_currentChar);
+ }
+ else
+ {
+ throw new JsonReaderException("Invalid JavaScript property identifier character: " + _currentChar);
+ }
+ }
+ }
+
+ private void SetToken(JsonToken newToken)
+ {
+ SetToken(newToken, null);
+ }
+
+ private void SetToken(JsonToken newToken, object value)
+ {
+ _token = newToken;
+
+ switch (newToken)
+ {
+ case JsonToken.StartObject:
+ _currentState = State.ObjectStart;
+ Push(JsonType.Object);
+ ClearCurrentChar();
+ break;
+ case JsonToken.StartArray:
+ _currentState = State.ArrayStart;
+ Push(JsonType.Array);
+ ClearCurrentChar();
+ break;
+ case JsonToken.EndObject:
+ ValidateEnd(JsonToken.EndObject);
+ ClearCurrentChar();
+ _currentState = State.PostValue;
+ break;
+ case JsonToken.EndArray:
+ ValidateEnd(JsonToken.EndArray);
+ ClearCurrentChar();
+ _currentState = State.PostValue;
+ break;
+ case JsonToken.PropertyName:
+ _currentState = State.Property;
+ ClearCurrentChar();
+ break;
+ case JsonToken.Undefined:
+ case JsonToken.Integer:
+ case JsonToken.Float:
+ case JsonToken.Boolean:
+ case JsonToken.Null:
+ case JsonToken.Constructor:
+ case JsonToken.Date:
+ _currentState = State.PostValue;
+ break;
+ }
+
+ if (value != null)
+ {
+ _value = value;
+ _valueType = value.GetType();
+ }
+ else
+ {
+ _value = null;
+ _valueType = null;
+ }
+ }
+
+ private bool ParseValue()
+ {
+ do
+ {
+ switch (_currentChar)
+ {
+ case '"':
+ case '\'':
+ ParseString(_currentChar);
+ return true;
+ case 't':
+ ParseTrue();
+ return true;
+ case 'f':
+ ParseFalse();
+ return true;
+ case 'n':
+ if (HasNext())
+ {
+ char next = PeekNext();
+
+ if (next == 'u')
+ ParseNull();
+ else if (next == 'e')
+ ParseConstructor();
+ else
+ throw new JsonReaderException("Unexpected character encountered while parsing value: " + _currentChar);
+ }
+ else
+ {
+ throw new JsonReaderException("Unexpected end");
+ }
+ return true;
+ case '/':
+ ParseComment();
+ return true;
+ case 'u':
+ ParseUndefined();
+ return true;
+ case '{':
+ SetToken(JsonToken.StartObject);
+ return true;
+ case '[':
+ SetToken(JsonToken.StartArray);
+ return true;
+ case '}':
+ SetToken(JsonToken.EndObject);
+ return true;
+ case ']':
+ SetToken(JsonToken.EndArray);
+ return true;
+ case ',':
+ SetToken(JsonToken.Undefined);
+ //ClearCurrentChar();
+ return true;
+ case ')':
+ if (_currentState == State.Constructor)
+ {
+ _currentState = State.ConstructorEnd;
+ return false;
+ }
+ else
+ {
+ throw new JsonReaderException("Unexpected character encountered while parsing value: " + _currentChar);
+ }
+ default:
+ if (char.IsWhiteSpace(_currentChar))
+ {
+ // eat
+ }
+ else if (char.IsNumber(_currentChar) || _currentChar == '-' || _currentChar == '.')
+ {
+ ParseNumber();
+ return true;
+ }
+ else
+ {
+ throw new JsonReaderException("Unexpected character encountered while parsing value: " + _currentChar);
+ }
+ break;
+ }
+ } while (MoveNext());
+
+ return false;
+ }
+
+ private bool EatWhitespace(bool oneOrMore)
+ {
+ bool whitespace = false;
+ while (char.IsWhiteSpace(_currentChar))
+ {
+ whitespace = true;
+ MoveNext();
+ }
+
+ return (!oneOrMore || whitespace);
+ }
+
+ private void ParseConstructor()
+ {
+ if (MatchValue("new", true))
+ {
+ if (EatWhitespace(true))
+ {
+ while (char.IsLetter(_currentChar))
+ {
+ _buffer.Append(_currentChar);
+ MoveNext();
+ }
+
+ string constructorName = _buffer.ToString();
+ _buffer.Position = 0;
+
+ List<object> parameters = new List<object>();
+
+ EatWhitespace(false);
+
+ if (_currentChar == '(' && MoveNext())
+ {
+ _currentState = State.Constructor;
+
+ while (ParseValue())
+ {
+ parameters.Add(_value);
+ _currentState = State.Constructor;
+ }
+
+ if (string.CompareOrdinal(constructorName, "Date") == 0)
+ {
+ long javaScriptTicks = Convert.ToInt64(parameters[0]);
+
+ DateTime date = JavaScriptConvert.ConvertJavaScriptTicksToDateTime(javaScriptTicks);
+
+ SetToken(JsonToken.Date, date);
+ }
+ else
+ {
+ JavaScriptConstructor constructor = new JavaScriptConstructor(constructorName, new JavaScriptParameters(parameters));
+
+ if (_currentState == State.ConstructorEnd)
+ {
+ SetToken(JsonToken.Constructor, constructor);
+ }
+ }
+
+ // move past ')'
+ MoveNext();
+ }
+ }
+ }
+ }
+
+ private void ParseNumber()
+ {
+ // parse until seperator character or end
+ bool end = false;
+ do
+ {
+ if (CurrentIsSeperator())
+ end = true;
+ else
+ _buffer.Append(_currentChar);
+
+ } while (!end && MoveNext());
+
+ string number = _buffer.ToString();
+ object numberValue;
+ JsonToken numberType;
+
+ if (number.IndexOf('.') == -1)
+ {
+ numberValue = Convert.ToInt64(_buffer.ToString(), CultureInfo.InvariantCulture);
+ numberType = JsonToken.Integer;
+ }
+ else
+ {
+ numberValue = Convert.ToDouble(_buffer.ToString(), CultureInfo.InvariantCulture);
+ numberType = JsonToken.Float;
+ }
+
+ _buffer.Position = 0;
+
+ SetToken(numberType, numberValue);
+ }
+
+ private void ValidateEnd(JsonToken endToken)
+ {
+ JsonType currentObject = Pop();
+
+ if (GetTypeForCloseToken(endToken) != currentObject)
+ throw new JsonReaderException(string.Format("JsonToken {0} is not valid for closing JsonType {1}.", endToken, currentObject));
+ }
+
+ private void SetStateBasedOnCurrent()
+ {
+ JsonType currentObject = Peek();
+
+ switch (currentObject)
+ {
+ case JsonType.Object:
+ _currentState = State.Object;
+ break;
+ case JsonType.Array:
+ _currentState = State.Array;
+ break;
+ case JsonType.None:
+ _currentState = State.Finished;
+ break;
+ default:
+ throw new JsonReaderException("While setting the reader state back to current object an unexpected JsonType was encountered: " + currentObject);
+ }
+ }
+
+ private JsonType GetTypeForCloseToken(JsonToken token)
+ {
+ switch (token)
+ {
+ case JsonToken.EndObject:
+ return JsonType.Object;
+ case JsonToken.EndArray:
+ return JsonType.Array;
+ default:
+ throw new JsonReaderException("Not a valid close JsonToken: " + token);
+ }
+ }
+
+ private void ParseComment()
+ {
+ // should have already parsed / character before reaching this method
+
+ MoveNext();
+
+ if (_currentChar == '*')
+ {
+ while (MoveNext())
+ {
+ if (_currentChar == '*')
+ {
+ if (MoveNext())
+ {
+ if (_currentChar == '/')
+ {
+ break;
+ }
+ else
+ {
+ _buffer.Append('*');
+ _buffer.Append(_currentChar);
+ }
+ }
+ }
+ else
+ {
+ _buffer.Append(_currentChar);
+ }
+ }
+ }
+ else
+ {
+ throw new JsonReaderException("Error parsing comment. Expected: *");
+ }
+
+ SetToken(JsonToken.Comment, _buffer.ToString());
+
+ _buffer.Position = 0;
+
+ ClearCurrentChar();
+ }
+
+ private bool MatchValue(string value)
+ {
+ int i = 0;
+ do
+ {
+ if (_currentChar != value[i])
+ {
+ break;
+ }
+ i++;
+ }
+ while (i < value.Length && MoveNext());
+
+ return (i == value.Length);
+ }
+
+ private bool MatchValue(string value, bool noTrailingNonSeperatorCharacters)
+ {
+ // will match value and then move to the next character, checking that it is a seperator character
+ bool match = MatchValue(value);
+
+ if (!noTrailingNonSeperatorCharacters)
+ return match;
+ else
+ return (match && (!MoveNext() || CurrentIsSeperator()));
+ }
+
+ private bool CurrentIsSeperator()
+ {
+ switch (_currentChar)
+ {
+ case '}':
+ case ']':
+ case ',':
+ return true;
+ case '/':
+ // check next character to see if start of a comment
+ return (HasNext() && PeekNext() == '*');
+ case ')':
+ if (_currentState == State.Constructor)
+ return true;
+ break;
+ default:
+ if (char.IsWhiteSpace(_currentChar))
+ return true;
+ break;
+ }
+
+ return false;
+ }
+
+ private void ParseTrue()
+ {
+ // check characters equal 'true'
+ // and that it is followed by either a seperator character
+ // or the text ends
+ if (MatchValue(JavaScriptConvert.True, true))
+ {
+ SetToken(JsonToken.Boolean, true);
+ }
+ else
+ {
+ throw new JsonReaderException("Error parsing boolean value.");
+ }
+ }
+
+ private void ParseNull()
+ {
+ if (MatchValue(JavaScriptConvert.Null, true))
+ {
+ SetToken(JsonToken.Null);
+ }
+ else
+ {
+ throw new JsonReaderException("Error parsing null value.");
+ }
+ }
+
+ private void ParseUndefined()
+ {
+ if (MatchValue(JavaScriptConvert.Undefined, true))
+ {
+ SetToken(JsonToken.Undefined);
+ }
+ else
+ {
+ throw new JsonReaderException("Error parsing undefined value.");
+ }
+ }
+
+ private void ParseFalse()
+ {
+ if (MatchValue(JavaScriptConvert.False, true))
+ {
+ SetToken(JsonToken.Boolean, false);
+ }
+ else
+ {
+ throw new JsonReaderException("Error parsing boolean value.");
+ }
+ }
+
+ void IDisposable.Dispose()
+ {
+ Dispose(true);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (_currentState != State.Closed && disposing)
+ Close();
+ }
+
+ /// <summary>
+ /// Changes the <see cref="State"/> to Closed.
+ /// </summary>
+ public void Close()
+ {
+ _currentState = State.Closed;
+ _token = JsonToken.None;
+ _value = null;
+ _valueType = null;
+
+ if (_reader != null)
+ _reader.Close();
+
+ if (_buffer != null)
+ _buffer.Clear();
+ }
+ }
+}
diff --git a/Src/Newtonsoft.Json/JsonReaderException.cs b/Src/Newtonsoft.Json/JsonReaderException.cs new file mode 100644 index 0000000..9940c67 --- /dev/null +++ b/Src/Newtonsoft.Json/JsonReaderException.cs @@ -0,0 +1,65 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Newtonsoft.Json
+{
+ /// <summary>
+ /// The exception thrown when an error occurs while reading Json text.
+ /// </summary>
+ public class JsonReaderException : Exception
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="JsonReaderException"/> class.
+ /// </summary>
+ public JsonReaderException()
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="JsonReaderException"/> class
+ /// with a specified error message.
+ /// </summary>
+ /// <param name="message">The error message that explains the reason for the exception.</param>
+ public JsonReaderException(string message)
+ : base(message)
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="JsonReaderException"/> class
+ /// with a specified error message and a reference to the inner exception that is the cause of this exception.
+ /// </summary>
+ /// <param name="message">The error message that explains the reason for the exception.</param>
+ /// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param>
+ public JsonReaderException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+ }
+}
diff --git a/Src/Newtonsoft.Json/JsonSerializationException.cs b/Src/Newtonsoft.Json/JsonSerializationException.cs new file mode 100644 index 0000000..bec2635 --- /dev/null +++ b/Src/Newtonsoft.Json/JsonSerializationException.cs @@ -0,0 +1,65 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Newtonsoft.Json
+{
+ /// <summary>
+ /// The exception thrown when an error occurs during Json serialization or deserialization.
+ /// </summary>
+ public class JsonSerializationException : Exception
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="JsonSerializationException"/> class.
+ /// </summary>
+ public JsonSerializationException()
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="JsonSerializationException"/> class
+ /// with a specified error message.
+ /// </summary>
+ /// <param name="message">The error message that explains the reason for the exception.</param>
+ public JsonSerializationException(string message)
+ : base(message)
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="JsonSerializationException"/> class
+ /// with a specified error message and a reference to the inner exception that is the cause of this exception.
+ /// </summary>
+ /// <param name="message">The error message that explains the reason for the exception.</param>
+ /// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param>
+ public JsonSerializationException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+ }
+}
diff --git a/Src/Newtonsoft.Json/JsonSerializer.cs b/Src/Newtonsoft.Json/JsonSerializer.cs new file mode 100644 index 0000000..43dabb3 --- /dev/null +++ b/Src/Newtonsoft.Json/JsonSerializer.cs @@ -0,0 +1,649 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+using System.Collections;
+using System.Reflection;
+using System.ComponentModel;
+using Newtonsoft.Json.Utilities;
+using System.Globalization;
+
+namespace Newtonsoft.Json
+{
+ /// <summary>
+ /// Specifies reference loop handling options for the <see cref="JsonWriter"/>.
+ /// </summary>
+ public enum ReferenceLoopHandling
+ {
+ /// <summary>
+ /// Throw a <see cref="JsonSerializationException"/> when a loop is encountered.
+ /// </summary>
+ Error = 0,
+ /// <summary>
+ /// Ignore loop references and do not serialize.
+ /// </summary>
+ Ignore = 1,
+ /// <summary>
+ /// Serialize loop references.
+ /// </summary>
+ Serialize = 2
+ }
+
+ /// <summary>
+ /// Serializes and deserializes objects into and from the Json format.
+ /// The <see cref="JsonSerializer"/> enables you to control how objects are encoded into Json.
+ /// </summary>
+ public class JsonSerializer
+ {
+ private ReferenceLoopHandling _referenceLoopHandling;
+ private int _level;
+ private JsonConverterCollection _converters;
+ private Dictionary<Type, MemberMappingCollection> _typeMemberMappings;
+
+ /// <summary>
+ /// Get or set how reference loops (e.g. a class referencing itself) is handled.
+ /// </summary>
+ public ReferenceLoopHandling ReferenceLoopHandling
+ {
+ get { return _referenceLoopHandling; }
+ set
+ {
+ if (value < ReferenceLoopHandling.Error || value > ReferenceLoopHandling.Serialize)
+ {
+ throw new ArgumentOutOfRangeException("value");
+ }
+ _referenceLoopHandling = value;
+ }
+ }
+
+ public JsonConverterCollection Converters
+ {
+ get
+ {
+ if (_converters == null)
+ _converters = new JsonConverterCollection();
+
+ return _converters;
+ }
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="JsonSerializer"/> class.
+ /// </summary>
+ public JsonSerializer()
+ {
+ _referenceLoopHandling = ReferenceLoopHandling.Error;
+ }
+
+ #region Deserialize
+ /// <summary>
+ /// Deserializes the Json structure contained by the specified <see cref="JsonReader"/>.
+ /// </summary>
+ /// <param name="reader">The <see cref="JsonReader"/> that contains the Json structure to deserialize.</param>
+ /// <returns>The <see cref="Object"/> being deserialized.</returns>
+ public object Deserialize(JsonReader reader)
+ {
+ return Deserialize(reader, null);
+ }
+
+ /// <summary>
+ /// Deserializes the Json structure contained by the specified <see cref="JsonReader"/>
+ /// into an instance of the specified type.
+ /// </summary>
+ /// <param name="reader">The type of object to create.</param>
+ /// <param name="objectType">The <see cref="Type"/> of object being deserialized.</param>
+ /// <returns>The instance of <paramref name="objectType"/> being deserialized.</returns>
+ public object Deserialize(JsonReader reader, Type objectType)
+ {
+ if (reader == null)
+ throw new ArgumentNullException("reader");
+
+ if (!reader.Read())
+ return null;
+
+ return GetObject(reader, objectType);
+ }
+
+ private JavaScriptArray PopulateJavaScriptArray(JsonReader reader)
+ {
+ JavaScriptArray jsArray = new JavaScriptArray();
+
+ while (reader.Read())
+ {
+ switch (reader.TokenType)
+ {
+ case JsonToken.EndArray:
+ return jsArray;
+ case JsonToken.Comment:
+ break;
+ default:
+ object value = GetObject(reader, null);
+
+ jsArray.Add(value);
+ break;
+ }
+ }
+
+ throw new JsonSerializationException("Unexpected end while deserializing array.");
+ }
+
+ private JavaScriptObject PopulateJavaScriptObject(JsonReader reader)
+ {
+ JavaScriptObject jsObject = new JavaScriptObject();
+
+ while (reader.Read())
+ {
+ switch (reader.TokenType)
+ {
+ case JsonToken.PropertyName:
+ string memberName = reader.Value.ToString();
+
+ // move to the value token. skip comments
+ do
+ {
+ if (!reader.Read())
+ throw new JsonSerializationException("Unexpected end while deserializing object.");
+ } while (reader.TokenType == JsonToken.Comment);
+
+ object value = GetObject(reader, null);
+
+ jsObject[memberName] = value;
+ break;
+ case JsonToken.EndObject:
+ return jsObject;
+ case JsonToken.Comment:
+ break;
+ default:
+ throw new JsonSerializationException("Unexpected token while deserializing object: " + reader.TokenType);
+ }
+ }
+
+ throw new JsonSerializationException("Unexpected end while deserializing object.");
+ }
+
+ private object GetObject(JsonReader reader, Type objectType)
+ {
+ _level++;
+
+ object value;
+ JsonConverter converter;
+
+ if (HasMatchingConverter(objectType, out converter))
+ {
+ return converter.ReadJson(reader, objectType);
+ }
+ else
+ {
+ switch (reader.TokenType)
+ {
+ // populate a typed object or generic dictionary/array
+ // depending upon whether an objectType was supplied
+ case JsonToken.StartObject:
+ value = (objectType != null) ? PopulateObject(reader, objectType) : PopulateJavaScriptObject(reader);
+ break;
+ case JsonToken.StartArray:
+ value = (objectType != null) ? PopulateList(reader, objectType) : PopulateJavaScriptArray(reader);
+ break;
+ case JsonToken.Integer:
+ case JsonToken.Float:
+ case JsonToken.String:
+ case JsonToken.Boolean:
+ case JsonToken.Date:
+ value = EnsureType(reader.Value, objectType);
+ break;
+ case JsonToken.Constructor:
+ value = reader.Value.ToString();
+ break;
+ case JsonToken.Null:
+ case JsonToken.Undefined:
+ value = null;
+ break;
+ default:
+ throw new JsonSerializationException("Unexpected token whil deserializing object: " + reader.TokenType);
+ }
+ }
+
+ _level--;
+
+ return value;
+ }
+
+ private object EnsureType(object value, Type targetType)
+ {
+ // do something about null value when the targetType is a valuetype?
+ if (value == null)
+ return null;
+
+ if (targetType == null)
+ return value;
+
+ Type valueType = value.GetType();
+
+ // type of value and type of target don't match
+ // attempt to convert value's type to target's type
+ if (valueType != targetType)
+ {
+ TypeConverter targetConverter = TypeDescriptor.GetConverter(targetType);
+
+ if (!targetConverter.CanConvertFrom(valueType))
+ {
+ if (targetConverter.CanConvertFrom(typeof(string)))
+ {
+ string valueString = TypeDescriptor.GetConverter(value).ConvertToInvariantString(value);
+
+ return targetConverter.ConvertFromInvariantString(valueString);
+ }
+
+ if (!targetType.IsAssignableFrom(valueType))
+ throw new InvalidOperationException(string.Format("Cannot convert object of type '{0}' to type '{1}'", value.GetType(), targetType));
+
+ return value;
+ }
+
+ return targetConverter.ConvertFrom(null, CultureInfo.InvariantCulture, value);
+ }
+ else
+ {
+ return value;
+ }
+ }
+
+ private MemberMappingCollection GetMemberMappings(Type objectType)
+ {
+ if (_typeMemberMappings == null)
+ _typeMemberMappings = new Dictionary<Type, MemberMappingCollection>();
+
+ MemberMappingCollection memberMappings;
+
+ if (_typeMemberMappings.TryGetValue(objectType, out memberMappings))
+ return memberMappings;
+
+ memberMappings = CreateMemberMappings(objectType);
+ _typeMemberMappings[objectType] = memberMappings;
+
+ return memberMappings;
+ }
+
+ private MemberMappingCollection CreateMemberMappings(Type objectType)
+ {
+ List<MemberInfo> members = ReflectionUtils.GetFieldsAndProperties(objectType, BindingFlags.Public | BindingFlags.Instance);
+ MemberMappingCollection memberMappings = new MemberMappingCollection();
+
+ foreach (MemberInfo member in members)
+ {
+ string mappedName;
+
+ JsonPropertyAttribute propertyAttribute = ReflectionUtils.GetAttribute<JsonPropertyAttribute>(member, true);
+ if (propertyAttribute != null)
+ mappedName = propertyAttribute.PropertyName;
+ else
+ mappedName = member.Name;
+
+ bool ignored = member.IsDefined(typeof (JsonIgnoreAttribute), true);
+ bool readable = ReflectionUtils.CanReadMemberValue(member);
+ bool writable = ReflectionUtils.CanSetMemberValue(member);
+ MemberMapping memberMapping = new MemberMapping(mappedName, member, ignored, readable, writable);
+
+ memberMappings.AddMapping(memberMapping);
+ }
+
+ return memberMappings;
+ }
+
+ private void SetObjectMember(JsonReader reader, object target, Type targetType, string memberName)
+ {
+ if (!reader.Read())
+ throw new JsonSerializationException(string.Format("Unexpected end when setting {0}'s value.", memberName));
+
+ MemberMappingCollection memberMappings = GetMemberMappings(targetType);
+ Type memberType;
+ object value;
+
+ // test if a member with memberName exists on the type
+ // otherwise test if target is a dictionary and assign value with the key if it is
+ if (memberMappings.Contains(memberName))
+ {
+ MemberMapping memberMapping = memberMappings[memberName];
+
+ if (memberMapping.Ignored)
+ return;
+
+ // ignore member if it is readonly
+ if (!memberMapping.Writable)
+ return;
+
+ // get the member's underlying type
+ memberType = ReflectionUtils.GetMemberUnderlyingType(memberMapping.Member);
+
+ value = GetObject(reader, memberType);
+
+ ReflectionUtils.SetMemberValue(memberMapping.Member, target, value);
+ }
+ else if (typeof(IDictionary).IsAssignableFrom(targetType))
+ {
+ // attempt to get the IDictionary's type
+ memberType = ReflectionUtils.GetDictionaryValueType(target.GetType());
+
+ value = GetObject(reader, memberType);
+
+ ((IDictionary)target).Add(memberName, value);
+ }
+ else
+ {
+ throw new JsonSerializationException(string.Format("Could not find member '{0}' on object of type '{1}'", memberName, targetType.GetType().Name));
+ }
+ }
+
+ private object PopulateList(JsonReader reader, Type objectType)
+ {
+ Type elementType = ReflectionUtils.GetListItemType(objectType);
+
+ IList populatedList = CollectionUtils.CreateAndPopulateList(objectType, delegate(IList list)
+ {
+ while (reader.Read())
+ {
+ switch (reader.TokenType)
+ {
+ case JsonToken.EndArray:
+ return;
+ case JsonToken.Comment:
+ break;
+ default:
+ object value = GetObject(reader, elementType);
+
+ list.Add(value);
+ break;
+ }
+ }
+
+ throw new JsonSerializationException("Unexpected end when deserializing array.");
+ });
+
+ return populatedList;
+ }
+
+ private object PopulateObject(JsonReader reader, Type objectType)
+ {
+ object newObject = Activator.CreateInstance(objectType);
+
+ while (reader.Read())
+ {
+ switch (reader.TokenType)
+ {
+ case JsonToken.PropertyName:
+ string memberName = reader.Value.ToString();
+
+ SetObjectMember(reader, newObject, objectType, memberName);
+ break;
+ case JsonToken.EndObject:
+ return newObject;
+ default:
+ throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
+ }
+ }
+
+ throw new JsonSerializationException("Unexpected end when deserializing object.");
+ }
+ #endregion
+
+ #region Serialize
+ /// <summary>
+ /// Serializes the specified <see cref="Object"/> and writes the Json structure
+ /// to a <c>Stream</c> using the specified <see cref="TextWriter"/>.
+ /// </summary>
+ /// <param name="textWriter">The <see cref="TextWriter"/> used to write the Json structure.</param>
+ /// <param name="value">The <see cref="Object"/> to serialize.</param>
+ public void Serialize(TextWriter textWriter, object value)
+ {
+ Serialize(new JsonWriter(textWriter), value);
+ }
+
+ /// <summary>
+ /// Serializes the specified <see cref="Object"/> and writes the Json structure
+ /// to a <c>Stream</c> using the specified <see cref="JsonWriter"/>.
+ /// </summary>
+ /// <param name="jsonWriter">The <see cref="JsonWriter"/> used to write the Json structure.</param>
+ /// <param name="value">The <see cref="Object"/> to serialize.</param>
+ public void Serialize(JsonWriter jsonWriter, object value)
+ {
+ if (jsonWriter == null)
+ throw new ArgumentNullException("jsonWriter");
+
+ if (value == null)
+ throw new ArgumentNullException("value");
+
+ SerializeValue(jsonWriter, value);
+ }
+
+
+ private void SerializeValue(JsonWriter writer, object value)
+ {
+ JsonConverter converter;
+
+ if (value == null)
+ {
+ writer.WriteNull();
+ }
+ else if (HasMatchingConverter(value.GetType(), out converter))
+ {
+ converter.WriteJson(writer, value);
+ }
+ else if (value is IConvertible)
+ {
+ IConvertible convertible = value as IConvertible;
+
+ switch (convertible.GetTypeCode())
+ {
+ case TypeCode.String:
+ writer.WriteValue((string)convertible);
+ break;
+ case TypeCode.Char:
+ writer.WriteValue((char)convertible);
+ break;
+ case TypeCode.Boolean:
+ writer.WriteValue((bool)convertible);
+ break;
+ case TypeCode.SByte:
+ writer.WriteValue((sbyte)convertible);
+ break;
+ case TypeCode.Int16:
+ writer.WriteValue((short)convertible);
+ break;
+ case TypeCode.UInt16:
+ writer.WriteValue((ushort)convertible);
+ break;
+ case TypeCode.Int32:
+ writer.WriteValue((int)convertible);
+ break;
+ case TypeCode.Byte:
+ writer.WriteValue((byte)convertible);
+ break;
+ case TypeCode.UInt32:
+ writer.WriteValue((uint)convertible);
+ break;
+ case TypeCode.Int64:
+ writer.WriteValue((long)convertible);
+ break;
+ case TypeCode.UInt64:
+ writer.WriteValue((ulong)convertible);
+ break;
+ case TypeCode.Single:
+ writer.WriteValue((float)convertible);
+ break;
+ case TypeCode.Double:
+ writer.WriteValue((double)convertible);
+ break;
+ case TypeCode.DateTime:
+ writer.WriteValue((DateTime)convertible);
+ break;
+ case TypeCode.Decimal:
+ writer.WriteValue((decimal)convertible);
+ break;
+ default:
+ SerializeObject(writer, value);
+ break;
+ }
+ }
+ else if (value is IList)
+ {
+ SerializeList(writer, (IList)value);
+ }
+ else if (value is IDictionary)
+ {
+ SerializeDictionary(writer, (IDictionary)value);
+ }
+ else if (value is ICollection)
+ {
+ SerializeCollection(writer, (ICollection)value);
+ }
+ else if (value is Identifier)
+ {
+ writer.WriteRaw(value.ToString());
+ }
+ else
+ {
+ SerializeObject(writer, value);
+ }
+ }
+
+ private bool HasMatchingConverter(Type type, out JsonConverter matchingConverter)
+ {
+ if (_converters != null)
+ {
+ for (int i = 0; i < _converters.Count; i++)
+ {
+ JsonConverter converter = _converters[i];
+
+ if (converter.CanConvert(type))
+ {
+ matchingConverter = converter;
+ return true;
+ }
+ }
+ }
+
+ matchingConverter = null;
+ return false;
+ }
+
+ private void WriteMemberInfoProperty(JsonWriter writer, object value, MemberInfo member, string propertyName)
+ {
+ if (!ReflectionUtils.IsIndexedProperty(member))
+ {
+ object memberValue = ReflectionUtils.GetMemberValue(member, value);
+
+ if (writer.SerializeStack.IndexOf(memberValue) != -1)
+ {
+ switch (_referenceLoopHandling)
+ {
+ case ReferenceLoopHandling.Error:
+ throw new JsonSerializationException("Self referencing loop");
+ case ReferenceLoopHandling.Ignore:
+ // return from method
+ return;
+ case ReferenceLoopHandling.Serialize:
+ // continue
+ break;
+ default:
+ throw new InvalidOperationException(string.Format("Unexpected ReferenceLoopHandling value: '{0}'", _referenceLoopHandling));
+ }
+ }
+
+ writer.WritePropertyName(propertyName ?? member.Name);
+ SerializeValue(writer, memberValue);
+ }
+ }
+
+ private void SerializeObject(JsonWriter writer, object value)
+ {
+ Type objectType = value.GetType();
+
+ TypeConverter converter = TypeDescriptor.GetConverter(objectType);
+
+ // use the objectType's TypeConverter if it has one and can convert to a string
+ if (converter != null && !(converter is ComponentConverter) && converter.GetType() != typeof(TypeConverter))
+ {
+ if (converter.CanConvertTo(typeof(string)))
+ {
+ writer.WriteValue(converter.ConvertToInvariantString(value));
+ return;
+ }
+ }
+
+ writer.SerializeStack.Add(value);
+
+ writer.WriteStartObject();
+
+ MemberMappingCollection memberMappings = GetMemberMappings(objectType);
+
+ foreach (MemberMapping memberMapping in memberMappings)
+ {
+ if (!memberMapping.Ignored && memberMapping.Readable)
+ WriteMemberInfoProperty(writer, value, memberMapping.Member, memberMapping.MappingName);
+ }
+
+ writer.WriteEndObject();
+
+ writer.SerializeStack.Remove(value);
+ }
+
+ private void SerializeCollection(JsonWriter writer, ICollection values)
+ {
+ object[] collectionValues = new object[values.Count];
+ values.CopyTo(collectionValues, 0);
+
+ SerializeList(writer, collectionValues);
+ }
+
+ private void SerializeList(JsonWriter writer, IList values)
+ {
+ writer.WriteStartArray();
+
+ for (int i = 0; i < values.Count; i++)
+ {
+ SerializeValue(writer, values[i]);
+ }
+
+ writer.WriteEndArray();
+ }
+
+ private void SerializeDictionary(JsonWriter writer, IDictionary values)
+ {
+ writer.WriteStartObject();
+
+ foreach (DictionaryEntry entry in values)
+ {
+ writer.WritePropertyName(entry.Key.ToString());
+ SerializeValue(writer, entry.Value);
+ }
+
+ writer.WriteEndObject();
+ }
+ #endregion
+ }
+}
diff --git a/Src/Newtonsoft.Json/JsonToken.cs b/Src/Newtonsoft.Json/JsonToken.cs new file mode 100644 index 0000000..e64d875 --- /dev/null +++ b/Src/Newtonsoft.Json/JsonToken.cs @@ -0,0 +1,98 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Newtonsoft.Json
+{
+ /// <summary>
+ /// Specifies the type of Json token.
+ /// </summary>
+ public enum JsonToken
+ {
+ /// <summary>
+ /// This is returned by the <see cref="JsonReader"/> if a <see cref="JsonReader.Read"/> method has not been called.
+ /// </summary>
+ None,
+ /// <summary>
+ /// An object start token.
+ /// </summary>
+ StartObject,
+ /// <summary>
+ /// An array start token.
+ /// </summary>
+ StartArray,
+ /// <summary>
+ /// An object property name.
+ /// </summary>
+ PropertyName,
+ /// <summary>
+ /// A comment.
+ /// </summary>
+ Comment,
+ /// <summary>
+ /// An interger.
+ /// </summary>
+ Integer,
+ /// <summary>
+ /// A float.
+ /// </summary>
+ Float,
+ /// <summary>
+ /// A string.
+ /// </summary>
+ String,
+ /// <summary>
+ /// A boolean.
+ /// </summary>
+ Boolean,
+ /// <summary>
+ /// A null token.
+ /// </summary>
+ Null,
+ /// <summary>
+ /// An undefined token.
+ /// </summary>
+ Undefined,
+ /// <summary>
+ /// An object end token.
+ /// </summary>
+ EndObject,
+ /// <summary>
+ /// An array end token.
+ /// </summary>
+ EndArray,
+ /// <summary>
+ /// A JavaScript object constructor.
+ /// </summary>
+ Constructor,
+ /// <summary>
+ /// A Date.
+ /// </summary>
+ Date
+ }
+}
diff --git a/Src/Newtonsoft.Json/JsonWriter.cs b/Src/Newtonsoft.Json/JsonWriter.cs new file mode 100644 index 0000000..499aa72 --- /dev/null +++ b/Src/Newtonsoft.Json/JsonWriter.cs @@ -0,0 +1,732 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+using System.Xml;
+using Newtonsoft.Json.Utilities;
+
+namespace Newtonsoft.Json
+{
+ internal enum JsonType
+ {
+ Object,
+ Array,
+ None
+ }
+
+ /// <summary>
+ /// Specifies the state of the <see cref="JsonWriter"/>.
+ /// </summary>
+ public enum WriteState
+ {
+ /// <summary>
+ /// An exception has been thrown, which has left the <see cref="JsonWriter"/> in an invalid state.
+ /// You may call the <see cref="JsonWriter.Close"/> method to put the <see cref="JsonWriter"/> in the <c>Closed</c> state.
+ /// Any other <see cref="JsonWriter"/> method calls results in an <see cref="InvalidOperationException"/> being thrown.
+ /// </summary>
+ Error,
+ /// <summary>
+ /// The <see cref="JsonWriter.Close"/> method has been called.
+ /// </summary>
+ Closed,
+ /// <summary>
+ /// An object is being written.
+ /// </summary>
+ Object,
+ /// <summary>
+ /// A array is being written.
+ /// </summary>
+ Array,
+ /// <summary>
+ /// A property is being written.
+ /// </summary>
+ Property,
+ /// <summary>
+ /// A write method has not been called.
+ /// </summary>
+ Start
+ }
+
+ /// <summary>
+ /// Specifies formatting options for the <see cref="JsonWriter"/>.
+ /// </summary>
+ public enum Formatting
+ {
+ /// <summary>
+ /// No special formatting is applied. This is the default.
+ /// </summary>
+ None,
+ /// <summary>
+ /// Causes child objects to be indented according to the <see cref="JsonWriter.Indentation"/> and <see cref="JsonWriter.IndentChar"/> settings.
+ /// </summary>
+ Indented
+ }
+
+ /// <summary>
+ /// Represents a writer that provides a fast, non-cached, forward-only way of generating Json data.
+ /// </summary>
+ public class JsonWriter : IDisposable
+ {
+ private enum State
+ {
+ Start,
+ Property,
+ ObjectStart,
+ Object,
+ ArrayStart,
+ Array,
+ Closed,
+ Error
+ }
+
+ // array that gives a new state based on the current state an the token being written
+ private static readonly State[,] stateArray = {
+ // Start PropertyName ObjectStart Object ArrayStart Array Closed Error
+ //
+ /* None */{ State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error },
+ /* StartObject */{ State.ObjectStart, State.ObjectStart, State.Error, State.Error, State.ObjectStart, State.ObjectStart, State.Error, State.Error },
+ /* StartArray */{ State.ArrayStart, State.ArrayStart, State.Error, State.Error, State.ArrayStart, State.ArrayStart, State.Error, State.Error },
+ /* StartProperty */{ State.Error, State.Error, State.Property, State.Property, State.Error, State.Error, State.Error, State.Error },
+ /* Comment */{ State.Error, State.Property, State.ObjectStart, State.Object, State.ArrayStart, State.Array, State.Error, State.Error },
+ /* Value */{ State.Error, State.Object, State.Error, State.Error, State.Array, State.Array, State.Error, State.Error },
+ };
+
+ private int _top;
+ private List<JsonType> _stack;
+ private List<object> _serializeStack;
+ private TextWriter _writer;
+ private Formatting _formatting;
+ private char _indentChar;
+ private int _indentation;
+ private char _quoteChar;
+ private bool _quoteName;
+ private State _currentState;
+
+ internal List<object> SerializeStack
+ {
+ get
+ {
+ if (_serializeStack == null)
+ _serializeStack = new List<object>();
+
+ return _serializeStack;
+ }
+ }
+
+ /// <summary>
+ /// Gets the state of the writer.
+ /// </summary>
+ public WriteState WriteState
+ {
+ get
+ {
+ switch (_currentState)
+ {
+ case State.Error:
+ return WriteState.Error;
+ case State.Closed:
+ return WriteState.Closed;
+ case State.Object:
+ case State.ObjectStart:
+ return WriteState.Object;
+ case State.Array:
+ case State.ArrayStart:
+ return WriteState.Array;
+ case State.Property:
+ return WriteState.Property;
+ case State.Start:
+ return WriteState.Start;
+ default:
+ throw new JsonWriterException("Invalid state: " + _currentState);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Indicates how the output is formatted.
+ /// </summary>
+ public Formatting Formatting
+ {
+ get { return _formatting; }
+ set { _formatting = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets how many IndentChars to write for each level in the hierarchy when <paramref name="Formatting"/> is set to <c>Formatting.Indented</c>.
+ /// </summary>
+ public int Indentation
+ {
+ get { return _indentation; }
+ set
+ {
+ if (value < 0)
+ throw new ArgumentException("Indentation value must be greater than 0.");
+
+ _indentation = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets which character to use to quote attribute values.
+ /// </summary>
+ public char QuoteChar
+ {
+ get { return _quoteChar; }
+ set
+ {
+ if (value != '"' && value != '\'')
+ throw new ArgumentException(@"Invalid JavaScript string quote character. Valid quote characters are ' and "".");
+
+ _quoteChar = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets which character to use for indenting when <paramref name="Formatting"/> is set to <c>Formatting.Indented</c>.
+ /// </summary>
+ public char IndentChar
+ {
+ get { return _indentChar; }
+ set { _indentChar = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether object names will be surrounded with quotes.
+ /// </summary>
+ public bool QuoteName
+ {
+ get { return _quoteName; }
+ set { _quoteName = value; }
+ }
+
+ /// <summary>
+ /// Creates an instance of the <c>JsonWriter</c> class using the specified <see cref="TextWriter"/>.
+ /// </summary>
+ /// <param name="textWriter">The <c>TextWriter</c> to write to.</param>
+ public JsonWriter(TextWriter textWriter)
+ {
+ if (textWriter == null)
+ throw new ArgumentNullException("textWriter");
+
+ _writer = textWriter;
+ _quoteChar = '"';
+ _quoteName = true;
+ _indentChar = ' ';
+ _indentation = 2;
+ _formatting = Formatting.None;
+ _stack = new List<JsonType>(1);
+ _stack.Add(JsonType.None);
+ _currentState = State.Start;
+ }
+
+ private void Push(JsonType value)
+ {
+ _top++;
+ if (_stack.Count <= _top)
+ _stack.Add(value);
+ else
+ _stack[_top] = value;
+ }
+
+ private JsonType Pop()
+ {
+ JsonType value = Peek();
+ _top--;
+
+ return value;
+ }
+
+ private JsonType Peek()
+ {
+ return _stack[_top];
+ }
+
+ /// <summary>
+ /// Flushes whatever is in the buffer to the underlying streams and also flushes the underlying stream.
+ /// </summary>
+ public void Flush()
+ {
+ _writer.Flush();
+ }
+
+ /// <summary>
+ /// Closes this stream and the underlying stream.
+ /// </summary>
+ public void Close()
+ {
+ AutoCompleteAll();
+
+ _writer.Close();
+ }
+
+ /// <summary>
+ /// Writes the beginning of a Json object.
+ /// </summary>
+ public void WriteStartObject()
+ {
+ AutoComplete(JsonToken.StartObject);
+
+ Push(JsonType.Object);
+
+ _writer.Write("{");
+ }
+
+ /// <summary>
+ /// Writes the end of a Json object.
+ /// </summary>
+ public void WriteEndObject()
+ {
+ AutoCompleteClose(JsonToken.EndObject);
+ }
+
+ /// <summary>
+ /// Writes the beginning of a Json array.
+ /// </summary>
+ public void WriteStartArray()
+ {
+ AutoComplete(JsonToken.StartArray);
+ Push(JsonType.Array);
+ _writer.Write("[");
+ }
+
+ /// <summary>
+ /// Writes the end of an array.
+ /// </summary>
+ public void WriteEndArray()
+ {
+ AutoCompleteClose(JsonToken.EndArray);
+ }
+
+ /// <summary>
+ /// Writes the property name of a name/value pair on a Json object.
+ /// </summary>
+ /// <param name="name"></param>
+ public void WritePropertyName(string name)
+ {
+ //_objectStack.Push(new JsonObjectInfo(JsonType.Property));
+ AutoComplete(JsonToken.PropertyName);
+
+ if (_quoteName)
+ _writer.Write(_quoteChar);
+
+ _writer.Write(name);
+
+ if (_quoteName)
+ _writer.Write(_quoteChar);
+
+ _writer.Write(':');
+ }
+
+ /// <summary>
+ /// Writes the end of the current Json object or array.
+ /// </summary>
+ public void WriteEnd()
+ {
+ WriteEnd(Peek());
+ }
+
+ private void WriteEnd(JsonType type)
+ {
+ switch (type)
+ {
+ case JsonType.Object:
+ WriteEndObject();
+ break;
+ case JsonType.Array:
+ WriteEndArray();
+ break;
+ default:
+ throw new JsonWriterException("Unexpected type when writing end: " + type);
+ }
+ }
+
+ private void AutoCompleteAll()
+ {
+ while (_top > 0)
+ {
+ WriteEnd();
+ }
+ }
+
+ private JsonType GetTypeForCloseToken(JsonToken token)
+ {
+ switch (token)
+ {
+ case JsonToken.EndObject:
+ return JsonType.Object;
+ case JsonToken.EndArray:
+ return JsonType.Array;
+ default:
+ throw new JsonWriterException("No type for token: " + token);
+ }
+ }
+
+ private JsonToken GetCloseTokenForType(JsonType type)
+ {
+ switch (type)
+ {
+ case JsonType.Object:
+ return JsonToken.EndObject;
+ case JsonType.Array:
+ return JsonToken.EndArray;
+ default:
+ throw new JsonWriterException("No close token for type: " + type);
+ }
+ }
+
+ private void AutoCompleteClose(JsonToken tokenBeingClosed)
+ {
+ // write closing symbol and calculate new state
+
+ int levelsToComplete = 0;
+
+ for (int i = 0; i < _top; i++)
+ {
+ int currentLevel = _top - i;
+
+ if (_stack[currentLevel] == GetTypeForCloseToken(tokenBeingClosed))
+ {
+ levelsToComplete = i + 1;
+ break;
+ }
+ }
+
+ if (levelsToComplete == 0)
+ throw new JsonWriterException("No token to close.");
+
+ for (int i = 0; i < levelsToComplete; i++)
+ {
+ JsonToken token = GetCloseTokenForType(Pop());
+
+ if (_currentState != State.ObjectStart && _currentState != State.ArrayStart)
+ WriteIndent();
+
+ switch (token)
+ {
+ case JsonToken.EndObject:
+ _writer.Write("}");
+ break;
+ case JsonToken.EndArray:
+ _writer.Write("]");
+ break;
+ default:
+ throw new JsonWriterException("Invalid JsonToken: " + token);
+ }
+ }
+
+ JsonType currentLevelType = Peek();
+
+ switch (currentLevelType)
+ {
+ case JsonType.Object:
+ _currentState = State.Object;
+ break;
+ case JsonType.Array:
+ _currentState = State.Array;
+ break;
+ case JsonType.None:
+ _currentState = State.Start;
+ break;
+ default:
+ throw new JsonWriterException("Unknown JsonType: " + currentLevelType);
+ }
+ }
+
+ private void WriteIndent()
+ {
+ if (_formatting == Formatting.Indented)
+ {
+ _writer.Write(Environment.NewLine);
+ // for each level of object...
+ for (int i = 0; i < _top; i++)
+ {
+ // ...write the indent char the specified number of times
+ for (int j = 0; j < _indentation; j++)
+ {
+ _writer.Write(_indentChar);
+ }
+ }
+ }
+ }
+
+ private void AutoComplete(JsonToken tokenBeingWritten)
+ {
+ int token;
+
+ switch (tokenBeingWritten)
+ {
+ default:
+ token = (int)tokenBeingWritten;
+ break;
+ case JsonToken.Integer:
+ case JsonToken.Float:
+ case JsonToken.String:
+ case JsonToken.Boolean:
+ case JsonToken.Null:
+ case JsonToken.Undefined:
+ case JsonToken.Date:
+ // a value is being written
+ token = 5;
+ break;
+ }
+
+ // gets new state based on the current state and what is being written
+ State newState = stateArray[token, (int)_currentState];
+
+ if (newState == State.Error)
+ throw new JsonWriterException(string.Format("Token {0} in state {1} would result in an invalid JavaScript object.", tokenBeingWritten.ToString(), _currentState.ToString()));
+
+ if ((_currentState == State.Object || _currentState == State.Array) && tokenBeingWritten != JsonToken.Comment)
+ {
+ _writer.Write(',');
+ }
+ else if (_currentState == State.Property)
+ {
+ if (_formatting == Formatting.Indented)
+ _writer.Write(' ');
+ }
+
+ if (tokenBeingWritten == JsonToken.PropertyName ||
+ (WriteState == WriteState.Array))
+ {
+ WriteIndent();
+ }
+
+ _currentState = newState;
+ }
+
+ private void WriteValueInternal(string value, JsonToken token)
+ {
+ AutoComplete(token);
+
+ _writer.Write(value);
+ }
+
+ #region WriteValue methods
+ /// <summary>
+ /// Writes a null value.
+ /// </summary>
+ public void WriteNull()
+ {
+ WriteValueInternal(JavaScriptConvert.Null, JsonToken.Null);
+ }
+
+ /// <summary>
+ /// Writes an undefined value.
+ /// </summary>
+ public void WriteUndefined()
+ {
+ WriteValueInternal(JavaScriptConvert.Undefined, JsonToken.Undefined);
+ }
+
+ /// <summary>
+ /// Writes raw JavaScript manually.
+ /// </summary>
+ /// <param name="javaScript">The raw JavaScript to write.</param>
+ public void WriteRaw(string javaScript)
+ {
+ // hack. some 'raw' or 'other' token perhaps?
+ WriteValueInternal(javaScript, JsonToken.Undefined);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="String"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="String"/> value to write.</param>
+ public void WriteValue(string value)
+ {
+ WriteValueInternal(JavaScriptConvert.ToString(value, _quoteChar), JsonToken.String);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="Int32"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="Int32"/> value to write.</param>
+ public void WriteValue(int value)
+ {
+ WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Integer);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="UInt32"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="UInt32"/> value to write.</param>
+ public void WriteValue(uint value)
+ {
+ WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Integer);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="Int64"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="Int64"/> value to write.</param>
+ public void WriteValue(long value)
+ {
+ WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Integer);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="UInt64"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="UInt64"/> value to write.</param>
+ public void WriteValue(ulong value)
+ {
+ WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Integer);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="Single"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="Single"/> value to write.</param>
+ public void WriteValue(float value)
+ {
+ WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Float);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="Double"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="Double"/> value to write.</param>
+ public void WriteValue(double value)
+ {
+ WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Float);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="Boolean"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="Boolean"/> value to write.</param>
+ public void WriteValue(bool value)
+ {
+ WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Boolean);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="Int16"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="Int16"/> value to write.</param>
+ public void WriteValue(short value)
+ {
+ WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Integer);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="UInt16"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="UInt16"/> value to write.</param>
+ public void WriteValue(ushort value)
+ {
+ WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Integer);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="Char"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="Char"/> value to write.</param>
+ public void WriteValue(char value)
+ {
+ WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Integer);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="Byte"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="Byte"/> value to write.</param>
+ public void WriteValue(byte value)
+ {
+ WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Integer);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="SByte"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="SByte"/> value to write.</param>
+ public void WriteValue(sbyte value)
+ {
+ WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Integer);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="Decimal"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="Decimal"/> value to write.</param>
+ public void WriteValue(decimal value)
+ {
+ WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Float);
+ }
+
+ /// <summary>
+ /// Writes a <see cref="DateTime"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="DateTime"/> value to write.</param>
+ public void WriteValue(DateTime value)
+ {
+ WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Date);
+ }
+ #endregion
+
+ /// <summary>
+ /// Writes out a comment <code>/*...*/</code> containing the specified text.
+ /// </summary>
+ /// <param name="text">Text to place inside the comment.</param>
+ public void WriteComment(string text)
+ {
+ AutoComplete(JsonToken.Comment);
+
+ _writer.Write("/*");
+ _writer.Write(text);
+ _writer.Write("*/");
+ }
+
+ /// <summary>
+ /// Writes out the given white space.
+ /// </summary>
+ /// <param name="ws">The string of white space characters.</param>
+ public void WriteWhitespace(string ws)
+ {
+ if (ws != null)
+ {
+ if (!StringUtils.IsWhiteSpace(ws))
+ throw new JsonWriterException("Only white space characters should be used.");
+
+ _writer.Write(ws);
+ }
+ }
+
+ void IDisposable.Dispose()
+ {
+ Dispose(true);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (WriteState != WriteState.Closed)
+ Close();
+ }
+ }
+}
diff --git a/Src/Newtonsoft.Json/JsonWriterException.cs b/Src/Newtonsoft.Json/JsonWriterException.cs new file mode 100644 index 0000000..bc43cd3 --- /dev/null +++ b/Src/Newtonsoft.Json/JsonWriterException.cs @@ -0,0 +1,65 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Newtonsoft.Json
+{
+ /// <summary>
+ /// The exception thrown when an error occurs while reading Json text.
+ /// </summary>
+ public class JsonWriterException : Exception
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="JsonWriterException"/> class.
+ /// </summary>
+ public JsonWriterException()
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="JsonWriterException"/> class
+ /// with a specified error message.
+ /// </summary>
+ /// <param name="message">The error message that explains the reason for the exception.</param>
+ public JsonWriterException(string message)
+ : base(message)
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="JsonWriterException"/> class
+ /// with a specified error message and a reference to the inner exception that is the cause of this exception.
+ /// </summary>
+ /// <param name="message">The error message that explains the reason for the exception.</param>
+ /// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param>
+ public JsonWriterException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+ }
+}
diff --git a/Src/Newtonsoft.Json/MemberMapping.cs b/Src/Newtonsoft.Json/MemberMapping.cs new file mode 100644 index 0000000..910f429 --- /dev/null +++ b/Src/Newtonsoft.Json/MemberMapping.cs @@ -0,0 +1,50 @@ +using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection;
+
+namespace Newtonsoft.Json
+{
+ internal struct MemberMapping
+ {
+ private readonly string _mappingName;
+ private readonly MemberInfo _member;
+ private readonly bool _ignored;
+ private readonly bool _readable;
+ private readonly bool _writable;
+
+ public MemberMapping(string mappingName, MemberInfo member, bool ignored, bool readable, bool writable)
+ {
+ _mappingName = mappingName;
+ _member = member;
+ _ignored = ignored;
+ _readable = readable;
+ _writable = writable;
+ }
+
+ public string MappingName
+ {
+ get { return _mappingName; }
+ }
+
+ public MemberInfo Member
+ {
+ get { return _member; }
+ }
+
+ public bool Ignored
+ {
+ get { return _ignored; }
+ }
+
+ public bool Readable
+ {
+ get { return _readable; }
+ }
+
+ public bool Writable
+ {
+ get { return _writable; }
+ }
+ }
+}
diff --git a/Src/Newtonsoft.Json/MemberMappingCollection.cs b/Src/Newtonsoft.Json/MemberMappingCollection.cs new file mode 100644 index 0000000..bb00286 --- /dev/null +++ b/Src/Newtonsoft.Json/MemberMappingCollection.cs @@ -0,0 +1,42 @@ +using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Collections.ObjectModel;
+
+namespace Newtonsoft.Json
+{
+ internal class MemberMappingCollection : KeyedCollection<string, MemberMapping>
+ {
+ protected override string GetKeyForItem(MemberMapping item)
+ {
+ return item.MappingName;
+ }
+
+ public void AddMapping(MemberMapping memberMapping)
+ {
+ if (Contains(memberMapping.MappingName))
+ {
+ // don't overwrite existing mapping with ignored mapping
+ if (memberMapping.Ignored)
+ return;
+
+ MemberMapping existingMemberMapping = this[memberMapping.MappingName];
+
+ if (!existingMemberMapping.Ignored)
+ {
+ throw new JsonSerializationException(
+ string.Format(
+ "A member with the name '{0}' already exists on {1}. Use the JsonPropertyAttribute to specify another name.",
+ memberMapping.MappingName, memberMapping.Member.DeclaringType));
+ }
+ else
+ {
+ // remove ignored mapping so it can be replaced in collection
+ Remove(existingMemberMapping);
+ }
+ }
+
+ Add(memberMapping);
+ }
+ }
+}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj new file mode 100644 index 0000000..f5335ba --- /dev/null +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj @@ -0,0 +1,84 @@ +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.50727</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{A9AE40FF-1A21-414A-9FE7-3BE13644CC6D}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Newtonsoft.Json</RootNamespace>
+ <AssemblyName>Newtonsoft.Json</AssemblyName>
+ <SignAssembly>false</SignAssembly>
+ <AssemblyOriginatorKeyFile>
+ </AssemblyOriginatorKeyFile>
+ <SccProjectName>
+ </SccProjectName>
+ <SccLocalPath>
+ </SccLocalPath>
+ <SccAuxPath>
+ </SccAuxPath>
+ <SccProvider>
+ </SccProvider>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <DocumentationFile>bin\Debug\Newtonsoft.Json.XML</DocumentationFile>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <DocumentationFile>bin\Release\Newtonsoft.Json.XML</DocumentationFile>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Drawing" />
+ <Reference Include="System.Web" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Converters\AspNetAjaxDateTimeConverter.cs" />
+ <Compile Include="Converters\XmlNodeConverter.cs" />
+ <Compile Include="Converters\HtmlColorConverter.cs" />
+ <Compile Include="JavaScriptParameters.cs" />
+ <Compile Include="JavaScriptConstructor.cs" />
+ <Compile Include="JsonPropertyAttribute.cs" />
+ <Compile Include="JsonIgnoreAttribute.cs" />
+ <Compile Include="JsonWriterException.cs" />
+ <Compile Include="JsonReaderException.cs" />
+ <Compile Include="Identifier.cs" />
+ <Compile Include="JavaScriptArray.cs" />
+ <Compile Include="JavaScriptObject.cs" />
+ <Compile Include="JsonConverter.cs" />
+ <Compile Include="JsonConverterCollection.cs" />
+ <Compile Include="JsonReader.cs" />
+ <Compile Include="JavaScriptConvert.cs" />
+ <Compile Include="JsonSerializationException.cs" />
+ <Compile Include="JsonSerializer.cs" />
+ <Compile Include="MemberMapping.cs" />
+ <Compile Include="MemberMappingCollection.cs" />
+ <Compile Include="Utilities\JavaScriptUtils.cs" />
+ <Compile Include="JsonToken.cs" />
+ <Compile Include="JsonWriter.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="StringBuffer.cs" />
+ <Compile Include="Utilities\CollectionUtils.cs" />
+ <Compile Include="Utilities\MathUtils.cs" />
+ <Compile Include="Utilities\MiscellaneousUtils.cs" />
+ <Compile Include="Utilities\ReflectionUtils.cs" />
+ <Compile Include="Utilities\StringUtils.cs" />
+ <Compile Include="Utilities\ValidationUtils.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+</Project>
\ No newline at end of file diff --git a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..e17ba8f --- /dev/null +++ b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs @@ -0,0 +1,57 @@ +#region License
+// Copyright 2006 James Newton-King
+// http://www.newtonsoft.com
+//
+// This work is licensed under the Creative Commons Attribution 2.5 License
+// http://creativecommons.org/licenses/by/2.5/
+//
+// You are free:
+// * to copy, distribute, display, and perform the work
+// * to make derivative works
+// * to make commercial use of the work
+//
+// Under the following conditions:
+// * You must attribute the work in the manner specified by the author or licensor:
+// - If you find this component useful a link to http://www.newtonsoft.com would be appreciated.
+// * For any reuse or distribution, you must make clear to others the license terms of this work.
+// * Any of these conditions can be waived if you get permission from the copyright holder.
+#endregion
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Newtonsoft Json.NET")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Newtonsoft")]
+[assembly: AssemblyProduct("Newtonsoft Json.NET")]
+[assembly: AssemblyCopyright("Copyright © Newtonsoft 2006")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+[assembly: AllowPartiallyTrustedCallers]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM componenets. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("9ca358aa-317b-4925-8ada-4a29e943a363")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("1.3.0.0")]
+[assembly: AssemblyFileVersion("1.3.0.0")]
\ No newline at end of file diff --git a/Src/Newtonsoft.Json/StringBuffer.cs b/Src/Newtonsoft.Json/StringBuffer.cs new file mode 100644 index 0000000..0365799 --- /dev/null +++ b/Src/Newtonsoft.Json/StringBuffer.cs @@ -0,0 +1,90 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Newtonsoft.Json
+{
+ /// <summary>
+ /// Builds a string. Unlike StringBuilder this class lets you reuse it's internal buffer.
+ /// </summary>
+ internal class StringBuffer
+ {
+ private char[] _buffer;
+ private int _position;
+
+ private static char[] _emptyBuffer = new char[0];
+
+ public int Position
+ {
+ get { return _position; }
+ set { _position = value; }
+ }
+
+ public StringBuffer()
+ {
+ _buffer = _emptyBuffer;
+ }
+
+ public StringBuffer(int initalSize)
+ {
+ _buffer = new char[initalSize];
+ }
+
+ public void Append(char value)
+ {
+ // test if the buffer array is large enough to take the value
+ if (_position + 1 > _buffer.Length)
+ {
+ EnsureSize(1);
+ }
+
+ // set value and increment poisition
+ _buffer[_position++] = value;
+ }
+
+ public void Clear()
+ {
+ _buffer = _emptyBuffer;
+ _position = 0;
+ }
+
+ private void EnsureSize(int appendLength)
+ {
+ char[] newBuffer = new char[_position + appendLength * 2];
+
+ Array.Copy(_buffer, newBuffer, _position);
+
+ _buffer = newBuffer;
+ }
+
+ public override string ToString()
+ {
+ return new string(_buffer, 0, _position);
+ }
+ }
+}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs b/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs new file mode 100644 index 0000000..6616a3d --- /dev/null +++ b/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs @@ -0,0 +1,419 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Reflection;
+using System.Text;
+using System.Collections;
+
+namespace Newtonsoft.Json.Utilities
+{
+ internal static class CollectionUtils
+ {
+ public static List<T> CreateList<T>(params T[] values)
+ {
+ return new List<T>(values);
+ }
+
+ /// <summary>
+ /// Determines whether the collection is null or empty.
+ /// </summary>
+ /// <param name="collection">The collection.</param>
+ /// <returns>
+ /// <c>true</c> if the collection is null or empty; otherwise, <c>false</c>.
+ /// </returns>
+ public static bool IsNullOrEmpty(ICollection collection)
+ {
+ if (collection != null)
+ {
+ return (collection.Count == 0);
+ }
+ return true;
+ }
+
+ /// <summary>
+ /// Determines whether the collection is null or empty.
+ /// </summary>
+ /// <param name="collection">The collection.</param>
+ /// <returns>
+ /// <c>true</c> if the collection is null or empty; otherwise, <c>false</c>.
+ /// </returns>
+ public static bool IsNullOrEmpty<T>(ICollection<T> collection)
+ {
+ if (collection != null)
+ {
+ return (collection.Count == 0);
+ }
+ return true;
+ }
+
+ /// <summary>
+ /// Determines whether the collection is null, empty or its contents are uninitialized values.
+ /// </summary>
+ /// <param name="list">The list.</param>
+ /// <returns>
+ /// <c>true</c> if the collection is null or empty or its contents are uninitialized values; otherwise, <c>false</c>.
+ /// </returns>
+ public static bool IsNullOrEmptyOrDefault<T>(IList<T> list)
+ {
+ if (IsNullOrEmpty<T>(list))
+ return true;
+
+ return ReflectionUtils.ItemsUnitializedValue<T>(list);
+ }
+
+ /// <summary>
+ /// Makes a slice of the specified list in between the start and end indexes.
+ /// </summary>
+ /// <param name="list">The list.</param>
+ /// <param name="start">The start index.</param>
+ /// <param name="end">The end index.</param>
+ /// <returns>A slice of the list.</returns>
+ public static IList<T> Slice<T>(IList<T> list, int? start, int? end)
+ {
+ return Slice<T>(list, start, end, null);
+ }
+
+ /// <summary>
+ /// Makes a slice of the specified list in between the start and end indexes,
+ /// getting every so many items based upon the step.
+ /// </summary>
+ /// <param name="list">The list.</param>
+ /// <param name="start">The start index.</param>
+ /// <param name="end">The end index.</param>
+ /// <param name="step">The step.</param>
+ /// <returns>A slice of the list.</returns>
+ public static IList<T> Slice<T>(IList<T> list, int? start, int? end, int? step)
+ {
+ if (list == null)
+ throw new ArgumentNullException("list");
+
+ if (step == 0)
+ throw new ArgumentException("Step cannot be zero.", "step");
+
+ List<T> slicedList = new List<T>();
+
+ // nothing to slice
+ if (list.Count == 0)
+ return slicedList;
+
+ // set defaults for null arguments
+ int s = step ?? 1;
+ int startIndex = start ?? 0;
+ int endIndex = end ?? list.Count;
+
+ // start from the end of the list if start is negitive
+ startIndex = (startIndex < 0) ? list.Count + startIndex : startIndex;
+
+ // end from the start of the list if end is negitive
+ endIndex = (endIndex < 0) ? list.Count + endIndex : endIndex;
+
+ // ensure indexes keep within collection bounds
+ startIndex = Math.Max(startIndex, 0);
+ endIndex = Math.Min(endIndex, list.Count - 1);
+
+ // loop between start and end indexes, incrementing by the step
+ for (int i = startIndex; i < endIndex; i += s)
+ {
+ slicedList.Add(list[i]);
+ }
+
+ return slicedList;
+ }
+
+
+ /// <summary>
+ /// Group the collection using a function which returns the key.
+ /// </summary>
+ /// <param name="source">The source collection to group.</param>
+ /// <param name="keySelector">The key selector.</param>
+ /// <returns>A Dictionary with each key relating to a list of objects in a list grouped under it.</returns>
+ public static Dictionary<K, List<V>> GroupBy<K, V>(ICollection<V> source, Func<V, K> keySelector)
+ {
+ if (keySelector == null)
+ throw new ArgumentNullException("keySelector");
+
+ Dictionary<K, List<V>> groupedValues = new Dictionary<K, List<V>>();
+
+ foreach (V value in source)
+ {
+ // using delegate to get the value's key
+ K key = keySelector(value);
+ List<V> groupedValueList;
+
+ // add a list for grouped values if the key is not already in Dictionary
+ if (!groupedValues.TryGetValue(key, out groupedValueList))
+ {
+ groupedValueList = new List<V>();
+ groupedValues.Add(key, groupedValueList);
+ }
+
+ groupedValueList.Add(value);
+ }
+
+ return groupedValues;
+ }
+
+ /// <summary>
+ /// Adds the elements of the specified collection to the specified generic IList.
+ /// </summary>
+ /// <param name="initial">The list to add to.</param>
+ /// <param name="collection">The collection of elements to add.</param>
+ public static void AddRange<T>(IList<T> initial, IEnumerable<T> collection)
+ {
+ if (initial == null)
+ throw new ArgumentNullException("initial");
+
+ if (collection == null)
+ return;
+
+ foreach (T value in collection)
+ {
+ initial.Add(value);
+ }
+ }
+
+ public static List<T> Distinct<T>(List<T> collection)
+ {
+ List<T> distinctList = new List<T>();
+
+ foreach (T value in collection)
+ {
+ if (!distinctList.Contains(value))
+ distinctList.Add(value);
+ }
+
+ return distinctList;
+ }
+
+ public static List<List<T>> Flatten<T>(params IList<T>[] lists)
+ {
+ List<List<T>> flattened = new List<List<T>>();
+ Dictionary<int, T> currentList = new Dictionary<int, T>();
+
+ Recurse<T>(new List<IList<T>>(lists), 0, currentList, flattened);
+
+ return flattened;
+ }
+
+ private static void Recurse<T>(IList<IList<T>> global, int current, Dictionary<int, T> currentSet, List<List<T>> flattenedResult)
+ {
+ IList<T> currentArray = global[current];
+
+ for (int i = 0; i < currentArray.Count; i++)
+ {
+ currentSet[current] = currentArray[i];
+
+ if (current == global.Count - 1)
+ {
+ List<T> items = new List<T>();
+
+ for (int k = 0; k < currentSet.Count; k++)
+ {
+ items.Add(currentSet[k]);
+ }
+
+ flattenedResult.Add(items);
+ }
+ else
+ {
+ Recurse(global, current + 1, currentSet, flattenedResult);
+ }
+ }
+ }
+
+ public static List<T> CreateList<T>(ICollection collection)
+ {
+ if (collection == null)
+ throw new ArgumentNullException("collection");
+
+ T[] array = new T[collection.Count];
+ collection.CopyTo(array, 0);
+
+ return new List<T>(array);
+ }
+
+ public static bool ListEquals<T>(IList<T> a, IList<T> b)
+ {
+ if (a == null || b == null)
+ return (a == null && b == null);
+
+ if (a.Count != b.Count)
+ return false;
+
+ EqualityComparer<T> comparer = EqualityComparer<T>.Default;
+
+ for (int i = 0; i < a.Count; i++)
+ {
+ if (!comparer.Equals(a[i], b[i]))
+ return false;
+ }
+
+ return true;
+ }
+
+ #region GetSingleItem
+ public static bool TryGetSingleItem<T>(IList<T> list, out T value)
+ {
+ return TryGetSingleItem<T>(list, false, out value);
+ }
+
+ public static bool TryGetSingleItem<T>(IList<T> list, bool returnDefaultIfEmpty, out T value)
+ {
+ return MiscellaneousUtils.TryAction<T>(delegate { return GetSingleItem(list, returnDefaultIfEmpty); }, out value);
+ }
+
+ public static T GetSingleItem<T>(IList<T> list)
+ {
+ return GetSingleItem<T>(list, false);
+ }
+
+ public static T GetSingleItem<T>(IList<T> list, bool returnDefaultIfEmpty)
+ {
+ if (list.Count == 1)
+ return list[0];
+ else if (returnDefaultIfEmpty && list.Count == 0)
+ return default(T);
+ else
+ throw new Exception(string.Format("Expected single {0} in list but got {1}.", typeof(T), list.Count));
+ }
+ #endregion
+
+ public static IList<T> Minus<T>(IList<T> list, IList<T> minus)
+ {
+ ValidationUtils.ArgumentNotNull(list, "list");
+
+ List<T> result = new List<T>(list.Count);
+ foreach (T t in list)
+ {
+ if (minus == null || !minus.Contains(t))
+ result.Add(t);
+ }
+
+ return result;
+ }
+
+ public static T[] CreateArray<T>(IEnumerable<T> enumerable)
+ {
+ ValidationUtils.ArgumentNotNull(enumerable, "enumerable");
+
+ if (enumerable is T[])
+ return (T[])enumerable;
+
+ List<T> tempList = new List<T>(enumerable);
+ return tempList.ToArray();
+ }
+
+ public static object CreateGenericList(Type listType)
+ {
+ ValidationUtils.ArgumentNotNull(listType, "listType");
+
+ return ReflectionUtils.CreateGeneric(typeof(List<>), listType);
+ }
+
+ public static bool IsListType(Type type)
+ {
+ ValidationUtils.ArgumentNotNull(type, "listType");
+
+ if (type.IsArray)
+ return true;
+ else if (typeof(IList).IsAssignableFrom(type))
+ return true;
+ else if (ReflectionUtils.IsSubClass(type, typeof(IList<>)))
+ return true;
+ else
+ return false;
+ }
+
+ public static IList CreateAndPopulateList(Type listType, Action<IList> populateList)
+ {
+ ValidationUtils.ArgumentNotNull(listType, "listType");
+ ValidationUtils.ArgumentNotNull(populateList, "populateList");
+
+ IList list;
+ Type readOnlyCollectionType;
+ bool isReadOnlyOrFixedSize = false;
+
+ if (listType.IsArray)
+ {
+ // have to use an arraylist when creating array
+ // there is no way to know the size until it is finised
+ list = new ArrayList();
+ isReadOnlyOrFixedSize = true;
+ }
+ else if (ReflectionUtils.IsSubClass(listType, typeof(ReadOnlyCollection<>), out readOnlyCollectionType))
+ {
+ Type readOnlyCollectionContentsType = readOnlyCollectionType.GetGenericArguments()[0];
+ Type genericEnumerable = ReflectionUtils.MakeGenericType(typeof(IEnumerable<>), readOnlyCollectionContentsType);
+ bool suitableConstructor = false;
+
+ foreach (ConstructorInfo constructor in listType.GetConstructors())
+ {
+ IList<ParameterInfo> parameters = constructor.GetParameters();
+
+ if (parameters.Count == 1)
+ {
+ if (genericEnumerable.IsAssignableFrom(parameters[0].ParameterType))
+ {
+ suitableConstructor = true;
+ break;
+ }
+ }
+ }
+
+ if (!suitableConstructor)
+ throw new Exception(string.Format("Readonly type {0} does not have a public constructor that takes a type that implements {1}.", listType, genericEnumerable));
+
+ // can't add or modify a readonly list
+ // use List<T> and convert once populated
+ list = (IList)CreateGenericList(readOnlyCollectionContentsType);
+ isReadOnlyOrFixedSize = true;
+ }
+ else if (typeof(IList).IsAssignableFrom(listType) && ReflectionUtils.IsInstantiatableType(listType))
+ {
+ list = (IList)Activator.CreateInstance(listType);
+ }
+ else
+ {
+ throw new Exception(string.Format("Cannot create and populate list type {0}.", listType));
+ }
+
+ populateList(list);
+
+ // create readonly and fixed sized collections using the temporary list
+ if (isReadOnlyOrFixedSize)
+ {
+ if (listType.IsArray)
+ list = ((ArrayList)list).ToArray(ReflectionUtils.GetListItemType(listType));
+ else if (ReflectionUtils.IsSubClass(listType, typeof(ReadOnlyCollection<>)))
+ list = (IList)Activator.CreateInstance(listType, list);
+ }
+
+ return list;
+ }
+ }
+}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs b/Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs new file mode 100644 index 0000000..7bedfbb --- /dev/null +++ b/Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs @@ -0,0 +1,137 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Web;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Web.UI;
+using System.Web.UI.WebControls;
+
+namespace Newtonsoft.Json.Utilities
+{
+ internal static class JavaScriptUtils
+ {
+ public static string GetCallbackEventFunction(Page page, Control control)
+ {
+ string script = page.ClientScript.GetCallbackEventReference(control, "eventArgument", "eventCallback", "context", "errorCallback", true);
+
+ script = "function(eventArgument,eventCallback,context,errorCallback){" + script + "}";
+
+ return script;
+ }
+
+ public static string GetCallbackEventFunction(Page page, Control control, string argument)
+ {
+ string script = page.ClientScript.GetCallbackEventReference(control, "'" + argument + "'", "eventCallback", "context", "errorCallback", true);
+
+ script = "function(eventCallback,context,errorCallback){" + script + "}";
+
+ return script;
+ }
+
+ public static void WriteEscapedJavaScriptChar(TextWriter writer, char c, char delimiter)
+ {
+ switch (c)
+ {
+ case '\t':
+ writer.Write(@"\t");
+ break;
+ case '\n':
+ writer.Write(@"\n");
+ break;
+ case '\r':
+ writer.Write(@"\r");
+ break;
+ case '\f':
+ writer.Write(@"\f");
+ break;
+ case '\b':
+ writer.Write(@"\b");
+ break;
+ case '\\':
+ writer.Write(@"\\");
+ break;
+ //case '<':
+ //case '>':
+ //case '\'':
+ // StringUtils.WriteCharAsUnicode(writer, c);
+ // break;
+ case '"':
+ // only escape if this charater is being used as the delimiter
+ writer.Write((delimiter == '"') ? "\\\"" : null);
+ break;
+ default:
+ if (c > '\u001f')
+ writer.Write(c);
+ else
+ StringUtils.WriteCharAsUnicode(writer, c);
+ break;
+ }
+ }
+
+ public static void WriteEscapedJavaScriptString(TextWriter writer, string value, char delimiter, bool appendDelimiters)
+ {
+ // leading delimiter
+ if (appendDelimiters)
+ writer.Write(delimiter);
+
+ if (value != null)
+ {
+ for (int i = 0; i < value.Length; i++)
+ {
+ WriteEscapedJavaScriptChar(writer, value[i], delimiter);
+ }
+ }
+
+ // trailing delimiter
+ if (appendDelimiters)
+ writer.Write(delimiter);
+ }
+
+ public static string ToEscapedJavaScriptString(string value)
+ {
+ return ToEscapedJavaScriptString(value, '"', true);
+ }
+
+ public static string ToEscapedJavaScriptString(string value, char delimiter, bool appendDelimiters)
+ {
+ using (StringWriter w = StringUtils.CreateStringWriter(StringUtils.GetLength(value) ?? 16))
+ {
+ WriteEscapedJavaScriptString(w, value, delimiter, appendDelimiters);
+ return w.ToString();
+ }
+ }
+ }
+}
+
+
+
+
diff --git a/Src/Newtonsoft.Json/Utilities/MathUtils.cs b/Src/Newtonsoft.Json/Utilities/MathUtils.cs new file mode 100644 index 0000000..26a6b88 --- /dev/null +++ b/Src/Newtonsoft.Json/Utilities/MathUtils.cs @@ -0,0 +1,60 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Newtonsoft.Json.Utilities
+{
+ internal class MathUtils
+ {
+ public static int HexToInt(char h)
+ {
+ if ((h >= '0') && (h <= '9'))
+ {
+ return (h - '0');
+ }
+ if ((h >= 'a') && (h <= 'f'))
+ {
+ return ((h - 'a') + 10);
+ }
+ if ((h >= 'A') && (h <= 'F'))
+ {
+ return ((h - 'A') + 10);
+ }
+ return -1;
+ }
+
+ public static char IntToHex(int n)
+ {
+ if (n <= 9)
+ {
+ return (char)(n + 48);
+ }
+ return (char)((n - 10) + 97);
+ }
+ }
+}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs b/Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs new file mode 100644 index 0000000..00d8135 --- /dev/null +++ b/Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs @@ -0,0 +1,84 @@ +using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Reflection;
+using System.Text;
+
+namespace Newtonsoft.Json.Utilities
+{
+ internal delegate void Action();
+ internal delegate T Creator<T>();
+ internal delegate T Func<A0, T>(A0 arg0);
+ internal delegate T Func<A0, A1, T>(A0 arg0, A1 arg1);
+ internal delegate T Func<A0, A1, A2, T>(A0 arg0, A1 arg1, A2 arg2);
+
+ internal static class MiscellaneousUtils
+ {
+ public static bool TryAction<T>(Creator<T> creator, out T output)
+ {
+ ValidationUtils.ArgumentNotNull(creator, "creator");
+
+ try
+ {
+ output = creator();
+ return true;
+ }
+ catch
+ {
+ output = default(T);
+ return false;
+ }
+ }
+
+ public static bool TryGetDescription(object value, out string description)
+ {
+ return TryAction<string>(delegate { return GetDescription(value); }, out description);
+ }
+
+ public static string GetDescription(object o)
+ {
+ ValidationUtils.ArgumentNotNull(o, "o");
+
+ ICustomAttributeProvider attributeProvider = o as ICustomAttributeProvider;
+
+ // object passed in isn't an attribute provider
+ // if value is an enum value, get value field member, otherwise get values type
+ if (attributeProvider == null)
+ {
+ Type valueType = o.GetType();
+
+ if (valueType.IsEnum)
+ attributeProvider = valueType.GetField(o.ToString());
+ else
+ attributeProvider = valueType;
+ }
+
+ DescriptionAttribute descriptionAttribute = ReflectionUtils.GetAttribute<DescriptionAttribute>(attributeProvider);
+
+ if (descriptionAttribute != null)
+ return descriptionAttribute.Description;
+ else
+ throw new Exception(string.Format("No DescriptionAttribute on '{0}'.", o.GetType()));
+ }
+
+ public static IList<string> GetDescriptions(IList values)
+ {
+ ValidationUtils.ArgumentNotNull(values, "values");
+
+ string[] descriptions = new string[values.Count];
+
+ for (int i = 0; i < values.Count; i++)
+ {
+ descriptions[i] = GetDescription(values[i]);
+ }
+
+ return descriptions;
+ }
+
+ public static string ToString(object value)
+ {
+ return (value != null) ? value.ToString() : "{null}";
+ }
+ }
+}
diff --git a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs new file mode 100644 index 0000000..75561e5 --- /dev/null +++ b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs @@ -0,0 +1,524 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection;
+using System.Collections;
+using System.ComponentModel;
+
+namespace Newtonsoft.Json.Utilities
+{
+ internal static class ReflectionUtils
+ {
+ public static Type GetObjectType(object v)
+ {
+ return (v != null) ? v.GetType() : null;
+ }
+
+ public static bool IsInstantiatableType(Type t)
+ {
+ ValidationUtils.ArgumentNotNull(t, "t");
+
+ if (t.IsAbstract || t.IsInterface || t.IsArray || t.IsGenericTypeDefinition || t == typeof(void))
+ return false;
+
+ if (!HasDefaultConstructor(t))
+ return false;
+
+ return true;
+ }
+
+ public static bool HasDefaultConstructor(Type t)
+ {
+ ValidationUtils.ArgumentNotNull(t, "t");
+
+ if (t.IsValueType)
+ return true;
+
+ return (t.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new Type[0], null) != null);
+ }
+
+ public static bool IsNullable(Type t)
+ {
+ ValidationUtils.ArgumentNotNull(t, "t");
+
+ if (t.IsValueType)
+ return IsNullableType(t);
+
+ return true;
+ }
+
+ public static bool IsNullableType(Type t)
+ {
+ ValidationUtils.ArgumentNotNull(t, "t");
+
+ return (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>));
+ }
+
+ //public static bool IsValueTypeUnitializedValue(ValueType value)
+ //{
+ // if (value == null)
+ // return true;
+
+ // return value.Equals(CreateUnitializedValue(value.GetType()));
+ //}
+
+ public static bool IsUnitializedValue(object value)
+ {
+ if (value == null)
+ {
+ return true;
+ }
+ else
+ {
+ object unitializedValue = CreateUnitializedValue(value.GetType());
+ return value.Equals(unitializedValue);
+ }
+ }
+
+ public static object CreateUnitializedValue(Type type)
+ {
+ ValidationUtils.ArgumentNotNull(type, "type");
+
+ if (type.IsGenericTypeDefinition)
+ throw new ArgumentException(string.Format("Type {0} is a generic type definition and cannot be instantiated.", type), "type");
+
+ if (type.IsClass || type.IsInterface || type == typeof(void))
+ return null;
+ else if (type.IsValueType)
+ return Activator.CreateInstance(type);
+ else
+ throw new ArgumentException(string.Format("Type {0} cannot be instantiated.", type), "type");
+ }
+
+ public static bool IsPropertyIndexed(PropertyInfo property)
+ {
+ ValidationUtils.ArgumentNotNull(property, "property");
+
+ return !CollectionUtils.IsNullOrEmpty<ParameterInfo>(property.GetIndexParameters());
+ }
+
+ public static bool IsSubClass(Type type, Type check)
+ {
+ Type implementingType;
+ return IsSubClass(type, check, out implementingType);
+ }
+
+ public static bool IsSubClass(Type type, Type check, out Type implementingType)
+ {
+ ValidationUtils.ArgumentNotNull(type, "type");
+ ValidationUtils.ArgumentNotNull(check, "check");
+
+ return IsSubClassInternal(type, type, check, out implementingType);
+ }
+
+ private static bool IsSubClassInternal(Type initialType, Type currentType, Type check, out Type implementingType)
+ {
+ if (currentType == check)
+ {
+ implementingType = currentType;
+ return true;
+ }
+
+ // don't get interfaces for an interface unless the initial type is an interface
+ if (check.IsInterface && (initialType.IsInterface || currentType == initialType))
+ {
+ foreach (Type t in currentType.GetInterfaces())
+ {
+ if (IsSubClassInternal(initialType, t, check, out implementingType))
+ {
+ // don't return the interface itself, return it's implementor
+ if (check == implementingType)
+ implementingType = currentType;
+
+ return true;
+ }
+ }
+ }
+
+ if (currentType.IsGenericType && !currentType.IsGenericTypeDefinition)
+ {
+ if (IsSubClassInternal(initialType, currentType.GetGenericTypeDefinition(), check, out implementingType))
+ {
+ implementingType = currentType;
+ return true;
+ }
+ }
+
+ if (currentType.BaseType == null)
+ {
+ implementingType = null;
+ return false;
+ }
+
+ return IsSubClassInternal(initialType, currentType.BaseType, check, out implementingType);
+ }
+
+ /// <summary>
+ /// Gets the type of the typed list's items.
+ /// </summary>
+ /// <param name="type">The type.</param>
+ /// <returns>The type of the typed list's items.</returns>
+ public static Type GetListItemType(Type type)
+ {
+ ValidationUtils.ArgumentNotNull(type, "type");
+ Type genericListType;
+
+ if (type.IsArray)
+ {
+ return type.GetElementType();
+ }
+ else if (IsSubClass(type, typeof(IList<>), out genericListType))
+ {
+ if (genericListType.IsGenericTypeDefinition)
+ throw new Exception(string.Format("Type {0} is not a list.", type));
+
+ return genericListType.GetGenericArguments()[0];
+ }
+ else if (typeof(IList).IsAssignableFrom(type))
+ {
+ return null;
+ }
+ else
+ {
+ throw new Exception(string.Format("Type {0} is not a list.", type));
+ }
+ }
+
+ public static Type GetDictionaryValueType(Type type)
+ {
+ ValidationUtils.ArgumentNotNull(type, "type");
+
+ Type genericDictionaryType;
+ if (IsSubClass(type, typeof(IDictionary<,>), out genericDictionaryType))
+ {
+ if (genericDictionaryType.IsGenericTypeDefinition)
+ throw new Exception(string.Format("Type {0} is not a dictionary.", type));
+
+ return genericDictionaryType.GetGenericArguments()[1];
+ }
+ else if (typeof(IDictionary).IsAssignableFrom(type))
+ {
+ return null;
+ }
+ else
+ {
+ throw new Exception(string.Format("Type {0} is not a dictionary.", type));
+ }
+ }
+
+ /// <summary>
+ /// Tests whether the list's items are their unitialized value.
+ /// </summary>
+ /// <param name="list">The list.</param>
+ /// <returns>Whether the list's items are their unitialized value</returns>
+ public static bool ItemsUnitializedValue<T>(IList<T> list)
+ {
+ ValidationUtils.ArgumentNotNull(list, "list");
+
+ Type elementType = GetListItemType(list.GetType());
+
+ if (elementType.IsValueType)
+ {
+ object unitializedValue = CreateUnitializedValue(elementType);
+
+ for (int i = 0; i < list.Count; i++)
+ {
+ if (!list[i].Equals(unitializedValue))
+ return false;
+ }
+ }
+ else if (elementType.IsClass)
+ {
+ for (int i = 0; i < list.Count; i++)
+ {
+ object value = list[i];
+
+ if (value != null)
+ return false;
+ }
+ }
+ else
+ {
+ throw new Exception(string.Format("Type {0} is neither a ValueType or a Class.", elementType));
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Gets the member's underlying type.
+ /// </summary>
+ /// <param name="member">The member.</param>
+ /// <returns>The underlying type of the member.</returns>
+ public static Type GetMemberUnderlyingType(MemberInfo member)
+ {
+ ValidationUtils.ArgumentNotNull(member, "member");
+
+ switch (member.MemberType)
+ {
+ case MemberTypes.Field:
+ return ((FieldInfo)member).FieldType;
+ case MemberTypes.Property:
+ return ((PropertyInfo)member).PropertyType;
+ case MemberTypes.Event:
+ return ((EventInfo)member).EventHandlerType;
+ default:
+ throw new ArgumentException("MemberInfo must be if type FieldInfo, PropertyInfo or EventInfo", "member");
+ }
+ }
+
+ /// <summary>
+ /// Determines whether the member is an indexed property.
+ /// </summary>
+ /// <param name="member">The member.</param>
+ /// <returns>
+ /// <c>true</c> if the member is an indexed property; otherwise, <c>false</c>.
+ /// </returns>
+ public static bool IsIndexedProperty(MemberInfo member)
+ {
+ ValidationUtils.ArgumentNotNull(member, "member");
+
+ PropertyInfo propertyInfo = member as PropertyInfo;
+
+ if (propertyInfo != null)
+ return IsIndexedProperty(propertyInfo);
+ else
+ return false;
+ }
+
+ /// <summary>
+ /// Determines whether the property is an indexed property.
+ /// </summary>
+ /// <param name="property">The property.</param>
+ /// <returns>
+ /// <c>true</c> if the property is an indexed property; otherwise, <c>false</c>.
+ /// </returns>
+ public static bool IsIndexedProperty(PropertyInfo property)
+ {
+ ValidationUtils.ArgumentNotNull(property, "property");
+
+ return (property.GetIndexParameters().Length > 0);
+ }
+
+ public static MemberInfo GetMember(Type type, string name, MemberTypes memberTypes)
+ {
+ return GetMember(type, name, memberTypes, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
+ }
+
+ public static MemberInfo GetMember(Type type, string name, MemberTypes memberTypes, BindingFlags bindingAttr)
+ {
+ ValidationUtils.ArgumentNotNull(type, "type");
+ ValidationUtils.ArgumentNotNull(name, "name");
+
+ MemberInfo[] result = type.GetMember(name, memberTypes, bindingAttr);
+
+ return CollectionUtils.GetSingleItem<MemberInfo>(result);
+ }
+
+ /// <summary>
+ /// Gets the member's value on the object.
+ /// </summary>
+ /// <param name="member">The member.</param>
+ /// <param name="target">The target object.</param>
+ /// <returns>The member's value on the object.</returns>
+ public static object GetMemberValue(MemberInfo member, object target)
+ {
+ ValidationUtils.ArgumentNotNull(member, "member");
+ ValidationUtils.ArgumentNotNull(target, "target");
+
+ switch (member.MemberType)
+ {
+ case MemberTypes.Field:
+ return ((FieldInfo)member).GetValue(target);
+ case MemberTypes.Property:
+ try
+ {
+ return ((PropertyInfo)member).GetValue(target, null);
+ }
+ catch (TargetParameterCountException e)
+ {
+ throw new ArgumentException(string.Format("MemberInfo '{0}' has index parameters", member.Name), "member", e);
+ }
+ default:
+ throw new ArgumentException(string.Format("MemberInfo '{0}' is not of type FieldInfo or PropertyInfo", member.Name), "member");
+ }
+ }
+
+ /// <summary>
+ /// Sets the member's value on the target object.
+ /// </summary>
+ /// <param name="member">The member.</param>
+ /// <param name="target">The target.</param>
+ /// <param name="value">The value.</param>
+ public static void SetMemberValue(MemberInfo member, object target, object value)
+ {
+ ValidationUtils.ArgumentNotNull(member, "member");
+ ValidationUtils.ArgumentNotNull(target, "target");
+
+ switch (member.MemberType)
+ {
+ case MemberTypes.Field:
+ ((FieldInfo)member).SetValue(target, value);
+ break;
+ case MemberTypes.Property:
+ ((PropertyInfo)member).SetValue(target, value, null);
+ break;
+ default:
+ throw new ArgumentException(string.Format("MemberInfo '{0}' must be of type FieldInfo or PropertyInfo", member.Name), "member");
+ }
+ }
+
+ /// <summary>
+ /// Determines whether the specified MemberInfo can be read.
+ /// </summary>
+ /// <param name="member">The MemberInfo to determine whether can be read.</param>
+ /// <returns>
+ /// <c>true</c> if the specified MemberInfo can be read; otherwise, <c>false</c>.
+ /// </returns>
+ public static bool CanReadMemberValue(MemberInfo member)
+ {
+ switch (member.MemberType)
+ {
+ case MemberTypes.Field:
+ return true;
+ case MemberTypes.Property:
+ return ((PropertyInfo)member).CanRead;
+ default:
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Determines whether the specified MemberInfo can be set.
+ /// </summary>
+ /// <param name="member">The MemberInfo to determine whether can be set.</param>
+ /// <returns>
+ /// <c>true</c> if the specified MemberInfo can be set; otherwise, <c>false</c>.
+ /// </returns>
+ public static bool CanSetMemberValue(MemberInfo member)
+ {
+ switch (member.MemberType)
+ {
+ case MemberTypes.Field:
+ return true;
+ case MemberTypes.Property:
+ return ((PropertyInfo)member).CanWrite;
+ default:
+ return false;
+ }
+ }
+
+ public static List<MemberInfo> GetFieldsAndProperties<T>(BindingFlags bindingAttr)
+ {
+ return GetFieldsAndProperties(typeof(T), bindingAttr);
+ }
+
+ public static List<MemberInfo> GetFieldsAndProperties(Type type, BindingFlags bindingAttr)
+ {
+ List<MemberInfo> targetMembers = new List<MemberInfo>();
+
+ targetMembers.AddRange(type.GetFields(bindingAttr));
+ targetMembers.AddRange(type.GetProperties(bindingAttr));
+
+ return targetMembers;
+ }
+
+ public static T GetAttribute<T>(ICustomAttributeProvider attributeProvider) where T : Attribute
+ {
+ return GetAttribute<T>(attributeProvider, true);
+ }
+
+ public static T GetAttribute<T>(ICustomAttributeProvider attributeProvider, bool inherit) where T : Attribute
+ {
+ T[] attributes = GetAttributes<T>(attributeProvider, inherit);
+
+ return CollectionUtils.GetSingleItem(attributes, true);
+ }
+
+ public static T[] GetAttributes<T>(ICustomAttributeProvider attributeProvider, bool inherit) where T : Attribute
+ {
+ ValidationUtils.ArgumentNotNull(attributeProvider, "attributeProvider");
+
+ return (T[])attributeProvider.GetCustomAttributes(typeof(T), inherit);
+ }
+
+ public static string GetNameAndAssessmblyName(Type t)
+ {
+ ValidationUtils.ArgumentNotNull(t, "t");
+
+ return t.FullName + ", " + t.Assembly.GetName().Name;
+ }
+
+ public static List<MemberInfo> FindMembers(Type targetType, MemberTypes memberType, BindingFlags bindingAttr, MemberFilter filter, object filterCriteria)
+ {
+ ValidationUtils.ArgumentNotNull(targetType, "targetType");
+
+ List<MemberInfo> memberInfos = new List<MemberInfo>(targetType.FindMembers(memberType, bindingAttr, filter, filterCriteria));
+
+ // fix weirdness with FieldInfos only being returned for the current Type
+ // find base type fields and add them to result
+ if ((memberType & MemberTypes.Field) != 0
+ && (bindingAttr & BindingFlags.NonPublic) != 0)
+ {
+ // modify flags to not search for public fields
+ BindingFlags nonPublicBindingAttr = bindingAttr ^ BindingFlags.Public;
+
+ while ((targetType = targetType.BaseType) != null)
+ {
+ memberInfos.AddRange(targetType.FindMembers(MemberTypes.Field, nonPublicBindingAttr, filter, filterCriteria));
+ }
+ }
+
+ return memberInfos;
+ }
+
+ public static Type MakeGenericType(Type genericTypeDefinition, params Type[] innerTypes)
+ {
+ ValidationUtils.ArgumentNotNull(genericTypeDefinition, "genericTypeDefinition");
+ ValidationUtils.ArgumentNotNullOrEmpty<Type>(innerTypes, "innerTypes");
+ ValidationUtils.ArgumentConditionTrue(genericTypeDefinition.IsGenericTypeDefinition, "genericTypeDefinition", string.Format("Type {0} is not a generic type definition.", genericTypeDefinition));
+
+ return genericTypeDefinition.MakeGenericType(innerTypes);
+ }
+
+ public static object CreateGeneric(Type genericTypeDefinition, Type innerType, params object[] args)
+ {
+ return CreateGeneric(genericTypeDefinition, new Type[] { innerType }, args);
+ }
+
+ public static object CreateGeneric(Type genericTypeDefinition, IList<Type> innerTypes, params object[] args)
+ {
+ ValidationUtils.ArgumentNotNull(genericTypeDefinition, "genericTypeDefinition");
+ ValidationUtils.ArgumentNotNullOrEmpty(innerTypes, "innerTypes");
+
+ Type specificType = MakeGenericType(genericTypeDefinition, CollectionUtils.CreateArray(innerTypes));
+
+ return Activator.CreateInstance(specificType, args);
+ }
+ }
+}
diff --git a/Src/Newtonsoft.Json/Utilities/StringUtils.cs b/Src/Newtonsoft.Json/Utilities/StringUtils.cs new file mode 100644 index 0000000..8861c15 --- /dev/null +++ b/Src/Newtonsoft.Json/Utilities/StringUtils.cs @@ -0,0 +1,396 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Data.SqlTypes;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Newtonsoft.Json.Utilities
+{
+ internal static class StringUtils
+ {
+ public const string CarriageReturnLineFeed = "\r\n";
+ public const string Empty = "";
+ public const char CarriageReturn = '\r';
+ public const char LineFeed = '\n';
+ public const char Tab = '\t';
+
+ /// <summary>
+ /// Determines whether the string contains white space.
+ /// </summary>
+ /// <param name="s">The string to test for white space.</param>
+ /// <returns>
+ /// <c>true</c> if the string contains white space; otherwise, <c>false</c>.
+ /// </returns>
+ public static bool ContainsWhiteSpace(string s)
+ {
+ if (s == null)
+ throw new ArgumentNullException("s");
+
+ for (int i = 0; i < s.Length; i++)
+ {
+ if (char.IsWhiteSpace(s[i]))
+ return true;
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Determines whether the string is all white space. Empty string will return false.
+ /// </summary>
+ /// <param name="s">The string to test whether it is all white space.</param>
+ /// <returns>
+ /// <c>true</c> if the string is all white space; otherwise, <c>false</c>.
+ /// </returns>
+ public static bool IsWhiteSpace(string s)
+ {
+ if (s == null)
+ throw new ArgumentNullException("s");
+
+ if (s.Length == 0)
+ return false;
+
+ for (int i = 0; i < s.Length; i++)
+ {
+ if (!char.IsWhiteSpace(s[i]))
+ return false;
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Ensures the target string ends with the specified string.
+ /// </summary>
+ /// <param name="target">The target.</param>
+ /// <param name="value">The value.</param>
+ /// <returns>The target string with the value string at the end.</returns>
+ public static string EnsureEndsWith(string target, string value)
+ {
+ if (target == null)
+ throw new ArgumentNullException("target");
+
+ if (value == null)
+ throw new ArgumentNullException("value");
+
+ if (target.Length >= value.Length)
+ {
+ if (string.Compare(target, target.Length - value.Length, value, 0, value.Length, StringComparison.OrdinalIgnoreCase) ==
+ 0)
+ return target;
+
+ string trimmedString = target.TrimEnd(null);
+
+ if (string.Compare(trimmedString, trimmedString.Length - value.Length, value, 0, value.Length,
+ StringComparison.OrdinalIgnoreCase) == 0)
+ return target;
+ }
+
+ return target + value;
+ }
+
+ /// <summary>
+ /// Determines whether the SqlString is null or empty.
+ /// </summary>
+ /// <param name="s">The string.</param>
+ /// <returns>
+ /// <c>true</c> if the SqlString is null or empty; otherwise, <c>false</c>.
+ /// </returns>
+ public static bool IsNullOrEmpty(SqlString s)
+ {
+ if (s.IsNull)
+ return true;
+ else
+ return string.IsNullOrEmpty(s.Value);
+ }
+
+ public static bool IsNullOrEmptyOrWhiteSpace(string s)
+ {
+ if (string.IsNullOrEmpty(s))
+ return true;
+ else if (IsWhiteSpace(s))
+ return true;
+ else
+ return false;
+ }
+
+ /// <summary>
+ /// Perform an action if the string is not null or empty.
+ /// </summary>
+ /// <param name="value">The value.</param>
+ /// <param name="action">The action to perform.</param>
+ public static void IfNotNullOrEmpty(string value, Action<string> action)
+ {
+ IfNotNullOrEmpty(value, action, null);
+ }
+
+ private static void IfNotNullOrEmpty(string value, Action<string> trueAction, Action<string> falseAction)
+ {
+ if (!string.IsNullOrEmpty(value))
+ {
+ if (trueAction != null)
+ trueAction(value);
+ }
+ else
+ {
+ if (falseAction != null)
+ falseAction(value);
+ }
+ }
+
+ /// <summary>
+ /// Indents the specified string.
+ /// </summary>
+ /// <param name="s">The string to indent.</param>
+ /// <param name="indentation">The number of characters to indent by.</param>
+ /// <returns></returns>
+ public static string Indent(string s, int indentation)
+ {
+ return Indent(s, indentation, ' ');
+ }
+
+ /// <summary>
+ /// Indents the specified string.
+ /// </summary>
+ /// <param name="s">The string to indent.</param>
+ /// <param name="indentation">The number of characters to indent by.</param>
+ /// <param name="indentChar">The indent character.</param>
+ /// <returns></returns>
+ public static string Indent(string s, int indentation, char indentChar)
+ {
+ if (s == null)
+ throw new ArgumentNullException("s");
+
+ if (indentation <= 0)
+ throw new ArgumentException("Must be greater than zero.", "indentation");
+
+ StringReader sr = new StringReader(s);
+ StringWriter sw = new StringWriter();
+
+ ActionTextReaderLine(sr, sw, delegate(TextWriter tw, string line)
+ {
+ tw.Write(new string(indentChar, indentation));
+ tw.Write(line);
+ });
+
+ return sw.ToString();
+ }
+
+ private delegate void ActionLine(TextWriter textWriter, string line);
+
+ private static void ActionTextReaderLine(TextReader textReader, TextWriter textWriter, ActionLine lineAction)
+ {
+ string line;
+ bool firstLine = true;
+ while ((line = textReader.ReadLine()) != null)
+ {
+ if (!firstLine)
+ textWriter.WriteLine();
+ else
+ firstLine = false;
+
+ lineAction(textWriter, line);
+ }
+ }
+
+ /// <summary>
+ /// Numbers the lines.
+ /// </summary>
+ /// <param name="s">The string to number.</param>
+ /// <returns></returns>
+ public static string NumberLines(string s)
+ {
+ if (s == null)
+ throw new ArgumentNullException("s");
+
+ StringReader sr = new StringReader(s);
+ StringWriter sw = new StringWriter();
+
+ int lineNumber = 1;
+
+ ActionTextReaderLine(sr, sw, delegate(TextWriter tw, string line)
+ {
+ tw.Write(lineNumber.ToString().PadLeft(4));
+ tw.Write(". ");
+ tw.Write(line);
+
+ lineNumber++;
+ });
+
+ return sw.ToString();
+ }
+
+ /// <summary>
+ /// Nulls an empty string.
+ /// </summary>
+ /// <param name="s">The string.</param>
+ /// <returns>Null if the string was null, otherwise the string unchanged.</returns>
+ public static string NullEmptyString(string s)
+ {
+ return (string.IsNullOrEmpty(s)) ? null : s;
+ }
+
+ public static string ReplaceNewLines(string s, string replacement)
+ {
+ StringReader sr = new StringReader(s);
+ StringBuilder sb = new StringBuilder();
+
+ bool first = true;
+
+ string line;
+ while ((line = sr.ReadLine()) != null)
+ {
+ if (first)
+ first = false;
+ else
+ sb.Append(replacement);
+
+ sb.Append(line);
+ }
+
+ return sb.ToString();
+ }
+
+ public static string RemoveHtml(string s)
+ {
+ return RemoveHtmlInternal(s, null);
+ }
+
+ public static string RemoveHtml(string s, IList<string> removeTags)
+ {
+ if (removeTags == null)
+ throw new ArgumentNullException("removeTags");
+
+ return RemoveHtmlInternal(s, removeTags);
+ }
+
+ private static string RemoveHtmlInternal(string s, IList<string> removeTags)
+ {
+ List<string> removeTagsUpper = null;
+
+ if (removeTags != null)
+ {
+ removeTagsUpper = new List<string>(removeTags.Count);
+
+ foreach (string tag in removeTags)
+ {
+ removeTagsUpper.Add(tag.ToUpperInvariant());
+ }
+ }
+
+ Regex anyTag = new Regex(@"<[/]{0,1}\s*(?<tag>\w*)\s*(?<attr>.*?=['""].*?[""'])*?\s*[/]{0,1}>", RegexOptions.Compiled);
+
+ return anyTag.Replace(s, delegate(Match match)
+ {
+ string tag = match.Groups["tag"].Value.ToUpperInvariant();
+
+ if (removeTagsUpper == null)
+ return string.Empty;
+ else if (removeTagsUpper.Contains(tag))
+ return string.Empty;
+ else
+ return match.Value;
+ });
+ }
+
+ public static string Truncate(string s, int maximumLength)
+ {
+ return Truncate(s, maximumLength, "...");
+ }
+
+ public static string Truncate(string s, int maximumLength, string suffix)
+ {
+ if (suffix == null)
+ throw new ArgumentNullException("suffix");
+
+ if (maximumLength <= 0)
+ throw new ArgumentException("Maximum length must be greater than zero.", "maximumLength");
+
+ int subStringLength = maximumLength - suffix.Length;
+
+ if (subStringLength <= 0)
+ throw new ArgumentException("Length of suffix string is greater or equal to maximumLength");
+
+ if (s != null && s.Length > maximumLength)
+ {
+ string truncatedString = s.Substring(0, subStringLength);
+ // incase the last character is a space
+ truncatedString = truncatedString.Trim();
+ truncatedString += suffix;
+
+ return truncatedString;
+ }
+ else
+ {
+ return s;
+ }
+ }
+
+ public static StringWriter CreateStringWriter(int capacity)
+ {
+ StringBuilder sb = new StringBuilder(capacity);
+ StringWriter sw = new StringWriter(sb);
+
+ return sw;
+ }
+
+ public static int? GetLength(string value)
+ {
+ if (value == null)
+ return null;
+ else
+ return value.Length;
+ }
+
+ public static string ToCharAsUnicode(char c)
+ {
+ using (StringWriter w = new StringWriter())
+ {
+ WriteCharAsUnicode(w, c);
+ return w.ToString();
+ }
+ }
+
+ public static void WriteCharAsUnicode(TextWriter writer, char c)
+ {
+ ValidationUtils.ArgumentNotNull(writer, "writer");
+
+ char h1 = MathUtils.IntToHex((c >> 12) & '\x000f');
+ char h2 = MathUtils.IntToHex((c >> 8) & '\x000f');
+ char h3 = MathUtils.IntToHex((c >> 4) & '\x000f');
+ char h4 = MathUtils.IntToHex(c & '\x000f');
+
+ writer.Write('\\');
+ writer.Write('u');
+ writer.Write(h1);
+ writer.Write(h2);
+ writer.Write(h3);
+ writer.Write(h4);
+ }
+ }
+}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/ValidationUtils.cs b/Src/Newtonsoft.Json/Utilities/ValidationUtils.cs new file mode 100644 index 0000000..aae4e05 --- /dev/null +++ b/Src/Newtonsoft.Json/Utilities/ValidationUtils.cs @@ -0,0 +1,148 @@ +#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Newtonsoft.Json.Utilities
+{
+ internal static class ValidationUtils
+ {
+ public const string EmailAddressRegex = @"^([a-zA-Z0-9_'+*$%\^&!\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9:]{2,4})+$";
+ public const string CurrencyRegex = @"(^\$?(?!0,?\d)\d{1,3}(,?\d{3})*(\.\d\d)?)$";
+ public const string DateRegex =
+ @"^(((0?[1-9]|[12]\d|3[01])[\.\-\/](0?[13578]|1[02])[\.\-\/]((1[6-9]|[2-9]\d)?\d{2}|\d))|((0?[1-9]|[12]\d|30)[\.\-\/](0?[13456789]|1[012])[\.\-\/]((1[6-9]|[2-9]\d)?\d{2}|\d))|((0?[1-9]|1\d|2[0-8])[\.\-\/]0?2[\.\-\/]((1[6-9]|[2-9]\d)?\d{2}|\d))|(29[\.\-\/]0?2[\.\-\/]((1[6-9]|[2-9]\d)?(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00)|00|[048])))$";
+ public const string NumericRegex = @"\d*";
+
+ public static void ArgumentNotNullOrEmpty(string value, string parameterName)
+ {
+ if (value == null)
+ throw new ArgumentNullException(parameterName);
+
+ if (value.Length == 0)
+ throw new ArgumentException(string.Format("'{0}' cannot be empty.", parameterName), parameterName);
+ }
+
+ public static void ArgumentNotNullOrEmptyOrWhitespace(string value, string parameterName)
+ {
+ ArgumentNotNullOrEmpty(value, parameterName);
+
+ if (StringUtils.IsWhiteSpace(value))
+ throw new ArgumentException(string.Format("'{0}' cannot only be whitespace.", parameterName), parameterName);
+ }
+
+ public static void ArgumentTypeIsEnum(Type enumType, string parameterName)
+ {
+ ArgumentNotNull(enumType, "enumType");
+
+ if (!enumType.IsEnum)
+ throw new ArgumentException(string.Format("Type {0} is not an Enum.", enumType), parameterName);
+ }
+
+ public static void ArgumentNotNullOrEmpty<T>(ICollection<T> collection, string parameterName)
+ {
+ ArgumentNotNullOrEmpty<T>(collection, parameterName, string.Format("Collection '{0}' cannot be empty.", parameterName));
+ }
+
+ public static void ArgumentNotNullOrEmpty<T>(ICollection<T> collection, string parameterName, string message)
+ {
+ if (collection == null)
+ throw new ArgumentNullException(parameterName);
+
+ if (collection.Count == 0)
+ throw new ArgumentException(message, parameterName);
+ }
+
+ public static void ArgumentNotNullOrEmpty(ICollection collection, string parameterName)
+ {
+ ArgumentNotNullOrEmpty(collection, parameterName, string.Format("Collection '{0}' cannot be empty.", parameterName));
+ }
+
+ public static void ArgumentNotNullOrEmpty(ICollection collection, string parameterName, string message)
+ {
+ if (collection == null)
+ throw new ArgumentNullException(parameterName);
+
+ if (collection.Count == 0)
+ throw new ArgumentException(message, parameterName);
+ }
+
+ public static void ArgumentNotNull(object value, string parameterName)
+ {
+ if (value == null)
+ throw new ArgumentNullException(parameterName);
+ }
+
+ public static void ArgumentNotNegative(int value, string parameterName)
+ {
+ if (value <= 0)
+ throw new ArgumentOutOfRangeException(parameterName, value, "Argument cannot be negative.");
+ }
+
+ public static void ArgumentNotNegative(int value, string parameterName, string message)
+ {
+ if (value <= 0)
+ throw new ArgumentOutOfRangeException(parameterName, value, message);
+ }
+
+ public static void ArgumentNotZero(int value, string parameterName)
+ {
+ if (value == 0)
+ throw new ArgumentOutOfRangeException(parameterName, value, "Argument cannot be zero.");
+ }
+
+ public static void ArgumentNotZero(int value, string parameterName, string message)
+ {
+ if (value == 0)
+ throw new ArgumentOutOfRangeException(parameterName, value, message);
+ }
+
+ public static void ArgumentIsPositive<T>(T value, string parameterName) where T : struct, IComparable<T>
+ {
+ if (value.CompareTo(default(T)) != 1)
+ throw new ArgumentOutOfRangeException(parameterName, value, "Positive number required.");
+ }
+
+ public static void ArgumentIsPositive(int value, string parameterName, string message)
+ {
+ if (value > 0)
+ throw new ArgumentOutOfRangeException(parameterName, value, message);
+ }
+
+ public static void ObjectNotDisposed(bool disposed, Type objectType)
+ {
+ if (disposed)
+ throw new ObjectDisposedException(objectType.Name);
+ }
+
+ public static void ArgumentConditionTrue(bool condition, string parameterName, string message)
+ {
+ if (!condition)
+ throw new ArgumentException(message, parameterName);
+ }
+ }
+}
\ No newline at end of file |