From f1a9993723e8bcb3ec61456a17ff4c47ed2326b2 Mon Sep 17 00:00:00 2001 From: JamesNK Date: Sun, 6 Dec 2009 23:10:14 +0000 Subject: [PATCH] -Added reading and writing binary JSON (BSON) support - work in progress -Added BsonReader, BsonWriter -Added support for reading and writing byte arrays to JsonReader, JsonWriter and LINQ to JSON classes -Added ReadAsBytes to JsonReader -Changed Silverlight build serializer to look for a TypeConverter -Changed .NET build to not rely on System.ComponentModel.DataAnnotations assembly to support .NET 4.0 client profile -Remove DateTimeOffset stand-in from Compact Framework build -Fixed .NET 2.0 build to run on environments without .NET 2.0 SP1 -Fixed deserialization to always use a new value created from a JsonConverter -Fixed XmlNodeConverter to support converting comments in JSON --- .../Bson/BsonReaderTests.cs | 180 ++++++ .../Bson/BsonWriterTests.cs | 112 ++++ .../Converters/IsoDateTimeConverterTests.cs | 2 + .../JavaScriptDateTimeConverterTests.cs | 20 +- .../Converters/XmlNodeConverterTest.cs | 29 + Src/Newtonsoft.Json.Tests/JsonConvertTest.cs | 4 +- .../JsonTextReaderTest.cs | 13 + .../JsonTextWriterTest.cs | 70 ++- .../Linq/JObjectTests.cs | 4 +- .../Linq/JTokenReaderTest.cs | 53 ++ Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs | 14 +- .../Linq/JTokenWriterTest.cs | 10 +- Src/Newtonsoft.Json.Tests/Linq/JValueTests.cs | 6 + .../Linq/LinqToJsonTest.cs | 7 +- .../Newtonsoft.Json.Tests.csproj | 2 + .../Serialization/JsonSerializerTest.cs | 84 ++- .../Serialization/NullValueHandlingTests.cs | 29 +- .../TestObjects/DateTimeTestClass.cs | 4 +- .../TestObjects/NullableDateTimeTestClass.cs | 4 +- .../TestObjects/Store.cs | 4 +- Src/Newtonsoft.Json/Bson/BsonBinaryType.cs | 41 ++ Src/Newtonsoft.Json/Bson/BsonReader.cs | 312 ++++++++++ Src/Newtonsoft.Json/Bson/BsonType.cs | 55 ++ Src/Newtonsoft.Json/Bson/BsonWriter.cs | 291 ++++++++++ .../Converters/BinaryConverter.cs | 20 +- .../Converters/DataSetConverter.cs | 29 +- .../Converters/DataTableConverter.cs | 29 +- .../Converters/HtmlColorConverter.cs | 2 +- .../Converters/IsoDateTimeConverter.cs | 10 +- .../Converters/JavaScriptDateTimeConverter.cs | 16 +- .../Converters/XmlNodeConverter.cs | 3 + Src/Newtonsoft.Json/DateTimeOffset.cs | 544 ------------------ Src/Newtonsoft.Json/JsonConvert.cs | 11 +- Src/Newtonsoft.Json/JsonReader.cs | 6 +- Src/Newtonsoft.Json/JsonSerializer.cs | 2 +- Src/Newtonsoft.Json/JsonTextReader.cs | 87 ++- Src/Newtonsoft.Json/JsonTextWriter.cs | 29 +- Src/Newtonsoft.Json/JsonToken.cs | 14 +- Src/Newtonsoft.Json/JsonValidatingReader.cs | 26 +- Src/Newtonsoft.Json/JsonWriter.cs | 21 + Src/Newtonsoft.Json/Linq/JContainer.cs | 2 +- Src/Newtonsoft.Json/Linq/JObject.cs | 10 +- Src/Newtonsoft.Json/Linq/JToken.cs | 27 + Src/Newtonsoft.Json/Linq/JTokenReader.cs | 15 +- Src/Newtonsoft.Json/Linq/JTokenType.cs | 3 +- Src/Newtonsoft.Json/Linq/JTokenWriter.cs | 8 + Src/Newtonsoft.Json/Linq/JValue.cs | 20 +- .../Newtonsoft.Json.Compact.csproj | 2 +- .../Newtonsoft.Json.Net20.csproj | 3 +- .../Newtonsoft.Json.Silverlight.csproj | 2 +- Src/Newtonsoft.Json/Newtonsoft.Json.csproj | 8 +- .../Serialization/DefaultContractResolver.cs | 6 +- .../JsonSerializerInternalReader.cs | 56 +- .../JsonSerializerInternalWriter.cs | 18 +- .../Serialization/JsonTypeReflector.cs | 91 ++- .../Utilities/Base64Encoder.cs | 95 +++ Src/Newtonsoft.Json/Utilities/ConvertUtils.cs | 21 +- .../Utilities/MiscellaneousUtils.cs | 58 +- Src/Newtonsoft.Json/Utilities/StringBuffer.cs | 5 + 59 files changed, 1952 insertions(+), 697 deletions(-) create mode 100644 Src/Newtonsoft.Json.Tests/Bson/BsonReaderTests.cs create mode 100644 Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs create mode 100644 Src/Newtonsoft.Json/Bson/BsonBinaryType.cs create mode 100644 Src/Newtonsoft.Json/Bson/BsonReader.cs create mode 100644 Src/Newtonsoft.Json/Bson/BsonType.cs create mode 100644 Src/Newtonsoft.Json/Bson/BsonWriter.cs delete mode 100644 Src/Newtonsoft.Json/DateTimeOffset.cs create mode 100644 Src/Newtonsoft.Json/Utilities/Base64Encoder.cs diff --git a/Src/Newtonsoft.Json.Tests/Bson/BsonReaderTests.cs b/Src/Newtonsoft.Json.Tests/Bson/BsonReaderTests.cs new file mode 100644 index 00000000..95880fdd --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Bson/BsonReaderTests.cs @@ -0,0 +1,180 @@ +#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.Linq; +using System.Text; +using NUnit.Framework; +using Newtonsoft.Json.Bson; +using System.IO; +using Newtonsoft.Json.Utilities; + +namespace Newtonsoft.Json.Tests.Bson +{ + public class BsonReaderTests : TestFixtureBase + { + [Test] + public void ReadSingleObject() + { + byte[] data = MiscellaneousUtils.HexToBytes("0F-00-00-00-10-42-6C-61-68-00-01-00-00-00-00"); + MemoryStream ms = new MemoryStream(data); + BsonReader reader = new BsonReader(ms); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("Blah", reader.Value); + Assert.AreEqual(typeof(string), reader.ValueType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Integer, reader.TokenType); + Assert.AreEqual(1, reader.Value); + Assert.AreEqual(typeof(long), reader.ValueType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndObject, reader.TokenType); + + Assert.IsFalse(reader.Read()); + } + + [Test] + public void ReadObjectBsonFromSite() + { + byte[] data = MiscellaneousUtils.HexToBytes("20-00-00-00-02-30-00-02-00-00-00-61-00-02-31-00-02-00-00-00-62-00-02-32-00-02-00-00-00-63-00-00"); + + MemoryStream ms = new MemoryStream(data); + BsonReader reader = new BsonReader(ms); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("0", reader.Value); + Assert.AreEqual(typeof(string), reader.ValueType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("a", reader.Value); + Assert.AreEqual(typeof(string), reader.ValueType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("1", reader.Value); + Assert.AreEqual(typeof(string), reader.ValueType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("b", reader.Value); + Assert.AreEqual(typeof(string), reader.ValueType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("2", reader.Value); + Assert.AreEqual(typeof(string), reader.ValueType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("c", reader.Value); + Assert.AreEqual(typeof(string), reader.ValueType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndObject, reader.TokenType); + + Assert.IsFalse(reader.Read()); + } + + [Test] + public void ReadArrayBsonFromSite() + { + byte[] data = MiscellaneousUtils.HexToBytes("20-00-00-00-02-30-00-02-00-00-00-61-00-02-31-00-02-00-00-00-62-00-02-32-00-02-00-00-00-63-00-00"); + + MemoryStream ms = new MemoryStream(data); + BsonReader reader = new BsonReader(ms, true); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartArray, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("a", reader.Value); + Assert.AreEqual(typeof(string), reader.ValueType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("b", reader.Value); + Assert.AreEqual(typeof(string), reader.ValueType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("c", reader.Value); + Assert.AreEqual(typeof(string), reader.ValueType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndArray, reader.TokenType); + + Assert.IsFalse(reader.Read()); + } + + [Test] + public void ReadBytes() + { + byte[] data = MiscellaneousUtils.HexToBytes("2B-00-00-00-02-30-00-02-00-00-00-61-00-02-31-00-02-00-00-00-62-00-05-32-00-0C-00-00-00-02-48-65-6C-6C-6F-20-77-6F-72-6C-64-21-00"); + + MemoryStream ms = new MemoryStream(data); + BsonReader reader = new BsonReader(ms, true); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartArray, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("a", reader.Value); + Assert.AreEqual(typeof(string), reader.ValueType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("b", reader.Value); + Assert.AreEqual(typeof(string), reader.ValueType); + + byte[] encodedStringData = reader.ReadAsBytes(); + Assert.IsNotNull(encodedStringData); + Assert.AreEqual(JsonToken.Bytes, reader.TokenType); + Assert.AreEqual(encodedStringData, reader.Value); + Assert.AreEqual(typeof(byte[]), reader.ValueType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndArray, reader.TokenType); + + Assert.IsFalse(reader.Read()); + + string decodedString = Encoding.UTF8.GetString(encodedStringData); + Assert.AreEqual("Hello world!", decodedString); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs b/Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs new file mode 100644 index 00000000..f3ce880b --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs @@ -0,0 +1,112 @@ +#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.Linq; +using System.Text; +using NUnit.Framework; +using Newtonsoft.Json.Bson; +using System.IO; +using Newtonsoft.Json.Utilities; + +namespace Newtonsoft.Json.Tests.Bson +{ + public class BsonWriterTests : TestFixtureBase + { + [Test] + public void WriteSingleObject() + { + MemoryStream ms = new MemoryStream(); + BsonWriter writer = new BsonWriter(ms); + + writer.WriteStartObject(); + writer.WritePropertyName("Blah"); + writer.WriteValue(1); + writer.WriteEndObject(); + writer.Flush(); + + string bson = MiscellaneousUtils.BytesToHex(ms.ToArray()); + Assert.AreEqual("0F-00-00-00-10-42-6C-61-68-00-01-00-00-00-00", bson); + } + + [Test] + [ExpectedException(typeof(JsonWriterException), ExpectedMessage = "Cannot flush BsonWriter until JSON is complete.")] + public void FlushInsideObject() + { + MemoryStream ms = new MemoryStream(); + BsonWriter writer = new BsonWriter(ms); + + writer.WriteStartObject(); + writer.WritePropertyName("Blah"); + writer.WriteValue(1); + writer.Flush(); + } + + [Test] + public void WriteArrayBsonFromSite() + { + MemoryStream ms = new MemoryStream(); + BsonWriter writer = new BsonWriter(ms); + writer.WriteStartArray(); + writer.WriteValue("a"); + writer.WriteValue("b"); + writer.WriteValue("c"); + writer.WriteEndArray(); + + writer.Flush(); + + ms.Seek(0, SeekOrigin.Begin); + + string expected = "20-00-00-00-02-30-00-02-00-00-00-61-00-02-31-00-02-00-00-00-62-00-02-32-00-02-00-00-00-63-00-00"; + string bson = MiscellaneousUtils.BytesToHex(ms.ToArray()); + + Assert.AreEqual(expected, bson); + } + + [Test] + public void WriteBytes() + { + byte[] data = Encoding.UTF8.GetBytes("Hello world!"); + + MemoryStream ms = new MemoryStream(); + BsonWriter writer = new BsonWriter(ms); + writer.WriteStartArray(); + writer.WriteValue("a"); + writer.WriteValue("b"); + writer.WriteValue(data); + writer.WriteEndArray(); + + writer.Flush(); + + ms.Seek(0, SeekOrigin.Begin); + + string expected = "2B-00-00-00-02-30-00-02-00-00-00-61-00-02-31-00-02-00-00-00-62-00-05-32-00-0C-00-00-00-02-48-65-6C-6C-6F-20-77-6F-72-6C-64-21-00"; + string bson = MiscellaneousUtils.BytesToHex(ms.ToArray()); + + Assert.AreEqual(expected, bson); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs index 351f0cae..3b2558a7 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs @@ -142,6 +142,7 @@ namespace Newtonsoft.Json.Tests.Converters } #endif +#if !PocketPC && !NET20 [Test] public void SerializeDateTimeOffset() { @@ -266,6 +267,7 @@ namespace Newtonsoft.Json.Tests.Converters string json2 = JsonConvert.SerializeObject(c, new IsoDateTimeConverter() { DateTimeStyles = DateTimeStyles.AssumeUniversal }); Assert.AreNotEqual(json, json2); } +#endif [Test] public void BlogCodeSample() diff --git a/Src/Newtonsoft.Json.Tests/Converters/JavaScriptDateTimeConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/JavaScriptDateTimeConverterTests.cs index 31a947ea..0111607f 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/JavaScriptDateTimeConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/JavaScriptDateTimeConverterTests.cs @@ -47,6 +47,7 @@ namespace Newtonsoft.Json.Tests.Converters Assert.AreEqual("new Date(976918263055)", result); } +#if !PocketPC && !NET20 [Test] public void SerializeDateTimeOffset() { @@ -85,15 +86,6 @@ namespace Newtonsoft.Json.Tests.Converters Assert.AreEqual(@"{""PreField"":null,""DateTimeField"":new Date(976918263055),""DateTimeOffsetField"":new Date(976918263055),""PostField"":null}", result); } - [Test] - public void DeserializeDateTime() - { - JavaScriptDateTimeConverter converter = new JavaScriptDateTimeConverter(); - - DateTime result = JsonConvert.DeserializeObject("new Date(976918263055)", converter); - Assert.AreEqual(new DateTime(2000, 12, 15, 22, 11, 3, 55, DateTimeKind.Utc), result); - } - [Test] [ExpectedException(typeof(Exception), ExpectedMessage = "Cannot convert null value to System.DateTime.")] public void DeserializeNullToNonNullable() @@ -113,5 +105,15 @@ namespace Newtonsoft.Json.Tests.Converters DateTimeOffset result = JsonConvert.DeserializeObject(json, converter); Assert.AreEqual(new DateTimeOffset(2000, 12, 15, 22, 11, 3, 55, TimeSpan.Zero), result); } +#endif + + [Test] + public void DeserializeDateTime() + { + JavaScriptDateTimeConverter converter = new JavaScriptDateTimeConverter(); + + DateTime result = JsonConvert.DeserializeObject("new Date(976918263055)", converter); + Assert.AreEqual(new DateTime(2000, 12, 15, 22, 11, 3, 55, DateTimeKind.Utc), result); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs b/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs index e6cd9619..a3dc965f 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs @@ -523,6 +523,35 @@ namespace Newtonsoft.Json.Tests.Converters string json = JsonConvert.SerializeXmlNode(doc); Assert.AreEqual(@"{""name"":""O\""Connor""}", json); } + + [Test] + public void SerializeComment() + { + string xml = @" + Text +"; + XmlDocument doc = new XmlDocument(); + doc.LoadXml(xml); + + string jsonText = JsonConvert.SerializeObject(doc, Formatting.Indented, new XmlNodeConverter()); + + string expected = @"{ + ""span"": { + ""@class"": ""vevent"", + ""a"": { + ""@class"": ""url"", + ""@href"": ""http://www.web2con.com/"", + ""#text"": ""Text"" + }/* Hi! */ + } +}"; + + Assert.AreEqual(expected, jsonText); + + XmlDocument newDoc = JsonConvert.DeserializeObject(jsonText, new XmlNodeConverter()); + Assert.AreEqual(@"Text", newDoc.InnerXml); + } + } } #endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs b/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs index a9e49cbc..3e0982f4 100644 --- a/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs @@ -232,8 +232,10 @@ now brown cow?", '"', true); value = new DateTime(JsonConvert.InitialJavaScriptDateTicks, DateTimeKind.Utc); Assert.AreEqual(@"""\/Date(0)\/""", JsonConvert.ToString(value)); +#if !PocketPC && !NET20 value = new DateTimeOffset(JsonConvert.InitialJavaScriptDateTicks, TimeSpan.Zero); Assert.AreEqual(@"""\/Date(0+0000)\/""", JsonConvert.ToString(value)); +#endif value = null; Assert.AreEqual("null", JsonConvert.ToString(value)); @@ -271,7 +273,7 @@ now brown cow?", '"', true); int i = JsonConvert.DeserializeObject("1"); Assert.AreEqual(1, i); -#if !PocketPC +#if !PocketPC && !NET20 DateTimeOffset d = JsonConvert.DeserializeObject(@"""\/Date(-59011455539000+0000)\/"""); Assert.AreEqual(new DateTimeOffset(new DateTime(100, 1, 1, 1, 1, 1, DateTimeKind.Utc)), d); #endif diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs index 6735c6fe..62cf12af 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs @@ -469,5 +469,18 @@ namespace Newtonsoft.Json.Tests reader.Read(); } + + [Test] + public void ReadSingleBytes() + { + StringReader s = new StringReader(@"""SGVsbG8gd29ybGQu"""); + JsonTextReader reader = new JsonTextReader(s); + + byte[] data = reader.ReadAsBytes(); + Assert.IsNotNull(data); + + string text = Encoding.UTF8.GetString(data, 0, data.Length); + Assert.AreEqual("Hello world.", text); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs index 66c1c9e8..e94ef7a9 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs @@ -103,13 +103,21 @@ namespace Newtonsoft.Json.Tests jsonWriter.WriteValue((decimal?)1.1m); jsonWriter.WriteValue((DateTime?)null); jsonWriter.WriteValue((DateTime?)new DateTime(JsonConvert.InitialJavaScriptDateTicks, DateTimeKind.Utc)); +#if !PocketPC && !NET20 jsonWriter.WriteValue((DateTimeOffset?)null); jsonWriter.WriteValue((DateTimeOffset?)new DateTimeOffset(JsonConvert.InitialJavaScriptDateTicks, TimeSpan.Zero)); +#endif jsonWriter.WriteEndArray(); } string json = sw.ToString(); - string expected = @"[null,""c"",null,true,null,1,null,1,null,1,null,1,null,1,null,1,null,1,null,1,null,1.1,null,1.1,null,1.1,null,""\/Date(0)\/"",null,""\/Date(0+0000)\/""]"; + string expected; + +#if !PocketPC && !NET20 + expected = @"[null,""c"",null,true,null,1,null,1,null,1,null,1,null,1,null,1,null,1,null,1,null,1.1,null,1.1,null,1.1,null,""\/Date(0)\/"",null,""\/Date(0+0000)\/""]"; +#else + expected = @"[null,""c"",null,true,null,1,null,1,null,1,null,1,null,1,null,1,null,1,null,1,null,1.1,null,1.1,null,1.1,null,""\/Date(0)\/""]"; +#endif Assert.AreEqual(expected, json); } @@ -532,5 +540,65 @@ _____'propertyName': NaN Assert.AreEqual(expected, result); } + + [Test] + public void WriteSingleBytes() + { + StringBuilder sb = new StringBuilder(); + StringWriter sw = new StringWriter(sb); + + string text = "Hello world."; + byte[] data = Encoding.UTF8.GetBytes(text); + + using (JsonTextWriter jsonWriter = new JsonTextWriter(sw)) + { + jsonWriter.Formatting = Formatting.Indented; + Assert.AreEqual(Formatting.Indented, jsonWriter.Formatting); + + jsonWriter.WriteValue(data); + } + + string expected = @"""SGVsbG8gd29ybGQu"""; + string result = sb.ToString(); + + Assert.AreEqual(expected, result); + + byte[] d2 = Convert.FromBase64String(result.Trim('"')); + + Assert.AreEqual(text, Encoding.UTF8.GetString(d2, 0, d2.Length)); + } + + [Test] + public void WriteBytesInArray() + { + StringBuilder sb = new StringBuilder(); + StringWriter sw = new StringWriter(sb); + + string text = "Hello world."; + byte[] data = Encoding.UTF8.GetBytes(text); + + using (JsonTextWriter jsonWriter = new JsonTextWriter(sw)) + { + jsonWriter.Formatting = Formatting.Indented; + Assert.AreEqual(Formatting.Indented, jsonWriter.Formatting); + + jsonWriter.WriteStartArray(); + jsonWriter.WriteValue(data); + jsonWriter.WriteValue(data); + jsonWriter.WriteValue((object)data); + jsonWriter.WriteValue((byte[])null); + jsonWriter.WriteEndArray(); + } + + string expected = @"[ + ""SGVsbG8gd29ybGQu"", + ""SGVsbG8gd29ybGQu"", + ""SGVsbG8gd29ybGQu"", + null +]"; + string result = sb.ToString(); + + Assert.AreEqual(expected, result); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs index 4a541d41..df01bbdd 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs @@ -11,8 +11,6 @@ using System.IO; using System.Collections; #if !PocketPC && !SILVERLIGHT using System.Web.UI; -using System.Collections; -using System.ComponentModel; #endif namespace Newtonsoft.Json.Tests.Linq @@ -596,7 +594,7 @@ Parameter name: arrayIndex")] Assert.AreEqual(p4, l[1]); } -#if !PocketPC && !SILVERLIGHT +#if !PocketPC && !SILVERLIGHT && !NET20 [Test] public void PropertyChanging() { diff --git a/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs b/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs index d988bab0..51e44595 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs @@ -35,6 +35,7 @@ namespace Newtonsoft.Json.Tests.Linq { public class JTokenReaderTest : TestFixtureBase { +#if !PocketPC && !NET20 [Test] public void YahooFinance() { @@ -109,6 +110,7 @@ namespace Newtonsoft.Json.Tests.Linq Assert.IsFalse(jsonReader.Read()); } } +#endif [Test] public void ReadLineInfo() @@ -194,5 +196,56 @@ namespace Newtonsoft.Json.Tests.Linq Assert.AreEqual(false, lineInfo.HasLineInfo()); } } + + [Test] + public void ReadBytes() + { + byte[] data = Encoding.UTF8.GetBytes("Hello world!"); + + JObject o = + new JObject( + new JProperty("Test1", data) + ); + + using (JTokenReader jsonReader = new JTokenReader(o)) + { + jsonReader.Read(); + Assert.AreEqual(JsonToken.StartObject, jsonReader.TokenType); + + jsonReader.Read(); + Assert.AreEqual(JsonToken.PropertyName, jsonReader.TokenType); + Assert.AreEqual("Test1", jsonReader.Value); + + byte[] readBytes = jsonReader.ReadAsBytes(); + Assert.AreEqual(data, readBytes); + + Assert.IsTrue(jsonReader.Read()); + Assert.AreEqual(JsonToken.EndObject, jsonReader.TokenType); + + Assert.IsFalse(jsonReader.Read()); + } + } + + [Test] + [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error reading bytes. Expected bytes but got Integer.")] + public void ReadBytesFailure() + { + JObject o = + new JObject( + new JProperty("Test1", 1) + ); + + using (JTokenReader jsonReader = new JTokenReader(o)) + { + jsonReader.Read(); + Assert.AreEqual(JsonToken.StartObject, jsonReader.TokenType); + + jsonReader.Read(); + Assert.AreEqual(JsonToken.PropertyName, jsonReader.TokenType); + Assert.AreEqual("Test1", jsonReader.Value); + + jsonReader.ReadAsBytes(); + } + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs index 973053ed..f98ad14d 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs @@ -196,7 +196,7 @@ namespace Newtonsoft.Json.Tests.Linq public void Casting() { Assert.AreEqual(new DateTime(2000, 12, 20), (DateTime)new JValue(new DateTime(2000, 12, 20))); -#if !PocketPC +#if !PocketPC && !NET20 Assert.AreEqual(new DateTimeOffset(2000, 12, 20, 23, 50, 10, TimeSpan.Zero), (DateTimeOffset)new JValue(new DateTimeOffset(2000, 12, 20, 23, 50, 10, TimeSpan.Zero))); Assert.AreEqual(null, (DateTimeOffset?)new JValue((DateTimeOffset?)null)); Assert.AreEqual(null, (DateTimeOffset?)(JValue)null); @@ -240,13 +240,16 @@ namespace Newtonsoft.Json.Tests.Linq Assert.AreEqual(5f, (float)(new JValue(5L))); Assert.AreEqual(5f, (float)(new JValue(5m))); Assert.AreEqual(5f, (float?)(new JValue(5m))); + + byte[] data = new byte[0]; + Assert.AreEqual(data, (byte[])(new JValue(data))); } [Test] public void ImplicitCastingTo() { Assert.IsTrue(JToken.DeepEquals(new JValue(new DateTime(2000, 12, 20)), (JValue)new DateTime(2000, 12, 20))); -#if !PocketPC +#if !PocketPC && !NET20 Assert.IsTrue(JToken.DeepEquals(new JValue(new DateTimeOffset(2000, 12, 20, 23, 50, 10, TimeSpan.Zero)), (JValue)new DateTimeOffset(2000, 12, 20, 23, 50, 10, TimeSpan.Zero))); Assert.IsTrue(JToken.DeepEquals(new JValue((DateTimeOffset?)null), (JValue)(DateTimeOffset?)null)); #endif @@ -269,6 +272,7 @@ namespace Newtonsoft.Json.Tests.Linq Assert.IsTrue(JToken.DeepEquals(new JValue(ushort.MaxValue), (JValue)ushort.MaxValue)); Assert.IsTrue(JToken.DeepEquals(new JValue(11.1f), (JValue)11.1f)); Assert.IsTrue(JToken.DeepEquals(new JValue(float.MinValue), (JValue)float.MinValue)); + Assert.IsTrue(JToken.DeepEquals(new JValue(double.MinValue), (JValue)double.MinValue)); Assert.IsTrue(JToken.DeepEquals(new JValue(uint.MaxValue), (JValue)uint.MaxValue)); Assert.IsTrue(JToken.DeepEquals(new JValue(ulong.MaxValue), (JValue)ulong.MaxValue)); Assert.IsTrue(JToken.DeepEquals(new JValue(ulong.MinValue), (JValue)ulong.MinValue)); @@ -281,7 +285,13 @@ namespace Newtonsoft.Json.Tests.Linq Assert.IsTrue(JToken.DeepEquals(new JValue(double.MaxValue), (JValue)(double?)double.MaxValue)); Assert.IsTrue(JToken.DeepEquals(new JValue((object)null), (JValue)(double?)null)); + Assert.IsFalse(JToken.DeepEquals(new JValue(true), (JValue)(bool?)null)); Assert.IsFalse(JToken.DeepEquals(new JValue((object)null), (JValue)(object)null)); + + byte[] emptyData = new byte[0]; + Assert.IsTrue(JToken.DeepEquals(new JValue(emptyData), (JValue)emptyData)); + Assert.IsFalse(JToken.DeepEquals(new JValue(emptyData), (JValue)new byte[1])); + Assert.IsTrue(JToken.DeepEquals(new JValue(Encoding.UTF8.GetBytes("Hi")), (JValue)Encoding.UTF8.GetBytes("Hi"))); } [Test] diff --git a/Src/Newtonsoft.Json.Tests/Linq/JTokenWriterTest.cs b/Src/Newtonsoft.Json.Tests/Linq/JTokenWriterTest.cs index 94bb8d9c..e8d55ff6 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JTokenWriterTest.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JTokenWriterTest.cs @@ -39,6 +39,8 @@ namespace Newtonsoft.Json.Tests.Linq [Test] public void ValueFormatting() { + byte[] data = Encoding.UTF8.GetBytes("Hello world."); + JToken root; using (JTokenWriter jsonWriter = new JTokenWriter()) { @@ -55,13 +57,14 @@ namespace Newtonsoft.Json.Tests.Linq jsonWriter.WriteValue("This is a string."); jsonWriter.WriteNull(); jsonWriter.WriteUndefined(); + jsonWriter.WriteValue(data); jsonWriter.WriteEndArray(); root = jsonWriter.Token; } Assert.IsInstanceOfType(typeof(JArray), root); - Assert.AreEqual(12, root.Children().Count()); + Assert.AreEqual(13, root.Children().Count()); Assert.AreEqual("@", (string)root[0]); Assert.AreEqual("\r\n\t\f\b?{\\r\\n\"\'", (string)root[1]); Assert.AreEqual(true, (bool)root[2]); @@ -73,6 +76,8 @@ namespace Newtonsoft.Json.Tests.Linq Assert.AreEqual(string.Empty, (string)root[8]); Assert.AreEqual("This is a string.", (string)root[9]); Assert.AreEqual(null, ((JValue)root[10]).Value); + Assert.AreEqual(null, ((JValue)root[11]).Value); + Assert.AreEqual(data, (byte[])root[12]); } [Test] @@ -100,6 +105,9 @@ namespace Newtonsoft.Json.Tests.Linq jsonWriter.WriteValue("DVD read/writer"); Assert.AreEqual(WriteState.Array, jsonWriter.WriteState); + jsonWriter.WriteValue(new byte[0]); + Assert.AreEqual(WriteState.Array, jsonWriter.WriteState); + jsonWriter.WriteEnd(); Assert.AreEqual(WriteState.Object, jsonWriter.WriteState); diff --git a/Src/Newtonsoft.Json.Tests/Linq/JValueTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JValueTests.cs index 8cacf95e..a7c5f58d 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JValueTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JValueTests.cs @@ -60,6 +60,12 @@ namespace Newtonsoft.Json.Tests.Linq v.Value = DBNull.Value; Assert.AreEqual(DBNull.Value, v.Value); Assert.AreEqual(JTokenType.Null, v.Type); + + byte[] data = new byte[0]; + v.Value = data; + + Assert.AreEqual(data, v.Value); + Assert.AreEqual(JTokenType.Bytes, v.Type); } [Test] diff --git a/Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs b/Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs index ac9d4792..749d8b30 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs @@ -545,6 +545,7 @@ keyword such as type of business."" Assert.AreEqual(null, c["purple"]); } +#if !PocketPC && !NET20 [Test] public void ToStringJsonConverter() { @@ -597,6 +598,7 @@ keyword such as type of business."" Assert.AreEqual(4, jsonWriter.Token.Children().Count()); } +#endif [Test] public void FromObject() @@ -683,9 +685,8 @@ keyword such as type of business."" o = new JObject( new JProperty("Test1", new DateTime(2000, 10, 15, 5, 5, 5, DateTimeKind.Utc)), - new JProperty("Test2", new DateTimeOffset(2000, 10, 15, 5, 5, 5, new TimeSpan(11, 11, 0))), - new JProperty("Test3", "Test3Value"), - new JProperty("Test4", null) + new JProperty("Test2", "Test2Value"), + new JProperty("Test3", null) ); enumerable = o.AsJEnumerable(); diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj index 9208f68b..89fe8467 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj @@ -83,6 +83,8 @@ + + diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs index bfba81c6..fdd81b1e 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs @@ -428,7 +428,6 @@ keyword such as type of business."" result = JsonConvert.SerializeObject(testDates); Assert.AreEqual(expected, result); } -#endif [Test] public void DateTimeOffset() @@ -443,6 +442,7 @@ keyword such as type of business."" string result = JsonConvert.SerializeObject(testDates); Assert.AreEqual(@"[""\/Date(-59011455539000+0000)\/"",""\/Date(946688461000+0000)\/"",""\/Date(946641661000+1300)\/"",""\/Date(946701061000-0330)\/""]", result); } +#endif [Test] public void NonStringKeyDictionary() @@ -1715,6 +1715,7 @@ keyword such as type of business."" Assert.AreEqual("Product 1", products[0].Name); } +#if !PocketPC && !NET20 [Test] public void DeserializeEmptyStringToNullableDateTime() { @@ -1723,6 +1724,7 @@ keyword such as type of business."" NullableDateTimeTestClass c = JsonConvert.DeserializeObject(json); Assert.AreEqual(null, c.DateTimeField); } +#endif [Test] [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Unable to find a constructor to use for type Newtonsoft.Json.Tests.TestObjects.Event. A class should either have a default constructor or only one constructor with arguments.")] @@ -1911,5 +1913,85 @@ keyword such as type of business."" Assert.AreEqual(structTest.IntProperty, deserialized.IntProperty); Assert.AreEqual(structTest.IntField, deserialized.IntField); } + + public class ListOfIds : JsonConverter where T : Bar, new() + { + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + IList list = (IList) value; + + writer.WriteStartArray(); + foreach (T item in list) + { + writer.WriteValue(item.Id); + } + writer.WriteEndArray(); + } + + public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer) + { + IList list = new List(); + + reader.Read(); + while (reader.TokenType != JsonToken.EndArray) + { + long id = (long)reader.Value; + + list.Add(new T + { + Id = Convert.ToInt32(id) + }); + + reader.Read(); + } + + return list; + } + + public override bool CanConvert(Type objectType) + { + return typeof (IList).IsAssignableFrom(objectType); + } + } + + public class Foo + { + public Foo() + { + Bars = new List(); + } + + [JsonConverter(typeof(ListOfIds))] + public List Bars { get; set; } + } + + public class Bar + { + public int Id { get; set; } + } + + [Test] + public void SerializeListWithJsonConverter() + { + Foo f = new Foo(); + f.Bars.Add(new Bar { Id = 0 }); + f.Bars.Add(new Bar { Id = 1 }); + f.Bars.Add(new Bar { Id = 2 }); + + string json = JsonConvert.SerializeObject(f, Formatting.Indented); + Assert.AreEqual(@"{ + ""Bars"": [ + 0, + 1, + 2 + ] +}", json); + + Foo newFoo = JsonConvert.DeserializeObject(json); + Assert.AreEqual(3, newFoo.Bars.Count); + Assert.AreEqual(0, newFoo.Bars[0].Id); + Assert.AreEqual(1, newFoo.Bars[1].Id); + Assert.AreEqual(2, newFoo.Bars[2].Id); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Serialization/NullValueHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/NullValueHandlingTests.cs index f7abe806..cf55e795 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/NullValueHandlingTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/NullValueHandlingTests.cs @@ -1,4 +1,29 @@ -using System; +#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.IO; using System.Linq; @@ -23,7 +48,7 @@ namespace Newtonsoft.Json.Tests.Serialization //JsonConvert.ConvertDateTimeToJavaScriptTicks(s1.Establised.DateTime) - Assert.AreEqual(@"{""Color"":4,""Establised"":""\/Date(1264122061000+0000)\/"",""Width"":1.1,""Employees"":999,""RoomsPerFloor"":[1,2,3,4,5,6,7,8,9],""Open"":false,""Symbol"":""@"",""Mottos"":[""Hello World"",""öäüÖÄÜ\\'{new Date(12345);}[222]_µ@²³~"",null,"" ""],""Cost"":100980.1,""Escape"":""\r\n\t\f\b?{\\r\\n\""'"",""product"":[{""Name"":""Rocket"",""ExpiryDate"":""\/Date(949532490000)\/"",""Price"":0.0},{""Name"":""Alien"",""ExpiryDate"":""\/Date(946684800000)\/"",""Price"":0.0}]}", sw.GetStringBuilder().ToString()); + Assert.AreEqual(@"{""Color"":4,""Establised"":""\/Date(1264122061000)\/"",""Width"":1.1,""Employees"":999,""RoomsPerFloor"":[1,2,3,4,5,6,7,8,9],""Open"":false,""Symbol"":""@"",""Mottos"":[""Hello World"",""öäüÖÄÜ\\'{new Date(12345);}[222]_µ@²³~"",null,"" ""],""Cost"":100980.1,""Escape"":""\r\n\t\f\b?{\\r\\n\""'"",""product"":[{""Name"":""Rocket"",""ExpiryDate"":""\/Date(949532490000)\/"",""Price"":0.0},{""Name"":""Alien"",""ExpiryDate"":""\/Date(946684800000)\/"",""Price"":0.0}]}", sw.GetStringBuilder().ToString()); Store s2 = (Store)jsonSerializer.Deserialize(new JsonTextReader(new StringReader("{}")), typeof(Store)); Assert.AreEqual("\r\n\t\f\b?{\\r\\n\"\'", s2.Escape); diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/DateTimeTestClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/DateTimeTestClass.cs index fe49cd32..c51d55ad 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/DateTimeTestClass.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/DateTimeTestClass.cs @@ -23,6 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion +#if !PocketPC && !NET20 using System; using System.Collections.Generic; using System.Linq; @@ -37,4 +38,5 @@ namespace Newtonsoft.Json.Tests.TestObjects public DateTimeOffset DateTimeOffsetField { get; set; } public string PostField { get; set; } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/NullableDateTimeTestClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/NullableDateTimeTestClass.cs index 118b4f5c..71af0afa 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/NullableDateTimeTestClass.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/NullableDateTimeTestClass.cs @@ -23,6 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion +#if !PocketPC && !NET20 using System; using System.Collections.Generic; using System.Linq; @@ -37,4 +38,5 @@ namespace Newtonsoft.Json.Tests.TestObjects public DateTimeOffset? DateTimeOffsetField { get; set; } public string PostField { get; set; } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/Store.cs b/Src/Newtonsoft.Json.Tests/TestObjects/Store.cs index a64aa2e2..1c0df19b 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/Store.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/Store.cs @@ -31,7 +31,7 @@ namespace Newtonsoft.Json.Tests.TestObjects public class Store { public StoreColor Color = StoreColor.Yellow; - public DateTimeOffset Establised = new DateTimeOffset(2010, 1, 22, 1, 1, 1, TimeSpan.Zero); + public DateTime Establised = new DateTime(2010, 1, 22, 1, 1, 1, DateTimeKind.Utc); public double Width = 1.1; public int Employees = 999; public int[] RoomsPerFloor = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; @@ -61,4 +61,4 @@ namespace Newtonsoft.Json.Tests.TestObjects product.Add(alien); } } -} \ No newline at end of file +} diff --git a/Src/Newtonsoft.Json/Bson/BsonBinaryType.cs b/Src/Newtonsoft.Json/Bson/BsonBinaryType.cs new file mode 100644 index 00000000..5a967db5 --- /dev/null +++ b/Src/Newtonsoft.Json/Bson/BsonBinaryType.cs @@ -0,0 +1,41 @@ +#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.Linq; +using System.Text; + +namespace Newtonsoft.Json.Bson +{ + internal enum BsonBinaryType : byte + { + Function = 0x01, + Data = 0x02, + Uuid = 0x03, + Md5 = 0x05, + UserDefined = 0x80 + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Bson/BsonReader.cs b/Src/Newtonsoft.Json/Bson/BsonReader.cs new file mode 100644 index 00000000..f0e421de --- /dev/null +++ b/Src/Newtonsoft.Json/Bson/BsonReader.cs @@ -0,0 +1,312 @@ +#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.Globalization; +using System.Linq; +using System.Text; +using System.IO; +using Newtonsoft.Json.Utilities; +using Newtonsoft.Json.Linq; + +namespace Newtonsoft.Json.Bson +{ + public class BsonReader : JsonReader + { + private readonly BinaryReader _reader; + private readonly bool _rootTypeIsArray; + private readonly List _stack; + + private BsonType _currentElementType; + + + private class ContainerContext + { + public JTokenType Type { get; private set; } + public int Length { get; set; } + public int Position { get; set; } + + public ContainerContext(JTokenType type) + { + Type = type; + } + } + + public BsonReader(Stream stream) : this(stream, false) + { + } + + public BsonReader(Stream stream, bool rootTypeIsArray) + { + ValidationUtils.ArgumentNotNull(stream, "stream"); + _reader = new BinaryReader(stream); + _stack = new List(); + _rootTypeIsArray = rootTypeIsArray; + } + + private string ReadElement() + { + _currentElementType = ReadType(); + string elementName = ReadString(); + return elementName; + } + + public override byte[] ReadAsBytes() + { + Read(); + if (TokenType != JsonToken.Bytes) + throw new JsonReaderException("Error reading bytes. Expected bytes but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); + + return (byte[])Value; + } + + public override bool Read() + { + try + { + switch (CurrentState) + { + case State.Start: + { + JsonToken token = (!_rootTypeIsArray) ? JsonToken.StartObject : JsonToken.StartArray; + JTokenType type = (!_rootTypeIsArray) ? JTokenType.Object : JTokenType.Array; + + SetToken(token); + ContainerContext newContext = new ContainerContext(type); + _stack.Add(newContext); + newContext.Length = ReadInt32(); + return true; + } + case State.ObjectStart: + { + SetToken(JsonToken.PropertyName, ReadElement()); + return true; + } + case State.Complete: + break; + case State.Property: + { + ReadType(_currentElementType); + return true; + } + case State.Object: + break; + case State.ArrayStart: + ReadElement(); + ReadType(_currentElementType); + return true; + case State.Array: + break; + case State.Closed: + break; + case State.PostValue: + ContainerContext context = GetCurrentContext(); + if (context == null) + return false; + + int lengthMinusEnd = context.Length - 1; + + if (context.Position < lengthMinusEnd) + { + if (context.Type == JTokenType.Array) + { + ReadElement(); + ReadType(_currentElementType); + return true; + } + else + { + SetToken(JsonToken.PropertyName, ReadElement()); + return true; + } + } + else if (context.Position == lengthMinusEnd) + { + if (ReadByte() != 0) + throw new JsonReaderException("Unexpected end of object byte value."); + + _stack.RemoveAt(_stack.Count - 1); + if (_stack.Count != 0) + MovePosition(context.Length); + + JsonToken endToken = (context.Type == JTokenType.Object) ? JsonToken.EndObject : JsonToken.EndArray; + SetToken(endToken); + return true; + } + break; + case State.ConstructorStart: + break; + case State.Constructor: + break; + case State.Error: + break; + case State.Finished: + break; + default: + throw new ArgumentOutOfRangeException(); + } + + return false; + } + catch (EndOfStreamException) + { + return false; + } + } + + private byte ReadByte() + { + MovePosition(1); + return _reader.ReadByte(); + } + + private void ReadType(BsonType type) + { + switch (type) + { + case BsonType.Number: + SetToken(JsonToken.Float, ReadDouble()); + break; + case BsonType.String: + SetToken(JsonToken.String, ReadLengthString()); + break; + case BsonType.Object: + break; + case BsonType.Array: + break; + case BsonType.Binary: + SetToken(JsonToken.Bytes, ReadBinary()); + break; + case BsonType.Undefined: + break; + case BsonType.Oid: + break; + case BsonType.Boolean: + break; + case BsonType.Date: + break; + case BsonType.Null: + break; + case BsonType.Regex: + break; + case BsonType.Reference: + break; + case BsonType.Code: + break; + case BsonType.Symbol: + break; + case BsonType.CodeWScope: + break; + case BsonType.Integer: + SetToken(JsonToken.Integer, (long)ReadInt32()); + break; + case BsonType.TimeStamp: + break; + case BsonType.MinKey: + break; + case BsonType.MaxKey: + break; + default: + throw new ArgumentOutOfRangeException("type"); + } + } + + private byte[] ReadBinary() + { + int dataLength = ReadInt32(); + + // BsonBinaryType not used + ReadByte(); + + return ReadBytes(dataLength); + } + + private string ReadString() + { + List buff = new List(); + byte b = _reader.ReadByte(); + while (b != 0) + { + buff.Add(b); + b = _reader.ReadByte(); + } + + MovePosition(buff.Count + 1); + string ret = Encoding.UTF8.GetString(buff.ToArray()); + return ret; + } + + private string ReadLengthString() + { + int length = ReadInt32(); + + MovePosition(length); + byte[] buffer = _reader.ReadBytes(length - 1); + _reader.ReadByte(); + + return Encoding.UTF8.GetString(buffer); + } + + private double ReadDouble() + { + MovePosition(8); + return _reader.ReadDouble(); + } + + private int ReadInt32() + { + MovePosition(4); + return _reader.ReadInt32(); + } + + private BsonType ReadType() + { + MovePosition(1); + return (BsonType)_reader.ReadSByte(); + } + + private ContainerContext GetCurrentContext() + { + int count = _stack.Count; + if (count == 0) + return null; + + return _stack[count - 1]; + } + + private void MovePosition(int count) + { + ContainerContext context = GetCurrentContext(); + context.Position += count; + } + + private byte[] ReadBytes(int count) + { + MovePosition(count); + return _reader.ReadBytes(count); + } + } +} diff --git a/Src/Newtonsoft.Json/Bson/BsonType.cs b/Src/Newtonsoft.Json/Bson/BsonType.cs new file mode 100644 index 00000000..5a65c5f4 --- /dev/null +++ b/Src/Newtonsoft.Json/Bson/BsonType.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.Linq; +using System.Text; + +namespace Newtonsoft.Json.Bson +{ + internal enum BsonType : sbyte + { + Number = 1, + String = 2, + Object = 3, + Array = 4, + Binary = 5, + Undefined = 6, + Oid = 7, + Boolean = 8, + Date = 9, + Null = 10, + Regex = 11, + Reference = 12, + Code = 13, + Symbol = 14, + CodeWScope = 15, + Integer = 16, + TimeStamp = 17, + MinKey = -1, + MaxKey = 127 + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Bson/BsonWriter.cs b/Src/Newtonsoft.Json/Bson/BsonWriter.cs new file mode 100644 index 00000000..2b007fb0 --- /dev/null +++ b/Src/Newtonsoft.Json/Bson/BsonWriter.cs @@ -0,0 +1,291 @@ +#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.IO; +using System.Linq; +using System.Text; +using Newtonsoft.Json.Utilities; +using Newtonsoft.Json.Linq; + +namespace Newtonsoft.Json.Bson +{ + public class BsonWriter : JTokenWriter + { + private readonly Stream _stream; + private readonly BinaryWriter _writer; + + + public BsonWriter(Stream stream) + { + ValidationUtils.ArgumentNotNull(stream, "stream"); + _stream = stream; + _writer = new BinaryWriter(stream); + } + + public override void Flush() + { + if (Top != 0) + throw new JsonWriterException("Cannot flush BsonWriter until JSON is complete."); + + WriteToken(Token); + _writer.Flush(); + } + + private void WriteToken(JToken t) + { + switch (t.Type) + { + case JTokenType.Object: + { + int size = CalculateSize(t); + _writer.Write(size); + foreach (JProperty property in t) + { + _writer.Write((sbyte)GetTypeNumber(property.Value)); + WriteString(property.Name); + WriteToken(property.Value); + } + _writer.Write((byte)0); + } + break; + case JTokenType.Array: + { + int size = CalculateSize(t); + _writer.Write(size); + int index = 0; + foreach (JToken c in t) + { + _writer.Write((sbyte)GetTypeNumber(c)); + WriteString(index.ToString()); + WriteToken(c); + index++; + } + _writer.Write((byte)0); + } + break; + case JTokenType.Integer: + _writer.Write((int)t); + break; + case JTokenType.Float: + _writer.Write((double)t); + break; + case JTokenType.String: + WriteStringWithLength((string)t); + break; + case JTokenType.Boolean: + _writer.Write((bool)t); + break; + case JTokenType.Null: + case JTokenType.Undefined: + break; + case JTokenType.Date: + DateTime dateTime = (DateTime) t; + dateTime = dateTime.ToUniversalTime(); + long ticks = JsonConvert.ConvertDateTimeToJavaScriptTicks(dateTime); + _writer.Write(ticks); + break; + case JTokenType.Bytes: + byte[] data = (byte[])t; + _writer.Write(data.Length); + _writer.Write((byte)BsonBinaryType.Data); + _writer.Write(data); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + private void WriteString(string s) + { + byte[] bytes = Encoding.UTF8.GetBytes(s); + _writer.Write(bytes); + _writer.Write((byte)0); + } + + private void WriteStringWithLength(string s) + { + _writer.Write(CalculateSizeWithLength(s, false)); + WriteString(s); + } + + private BsonType GetTypeNumber(JToken t) + { + switch (t.Type) + { + case JTokenType.Object: + return BsonType.Object; + case JTokenType.Array: + return BsonType.Array; + case JTokenType.Integer: + return BsonType.Integer; + case JTokenType.Float: + return BsonType.Number; + case JTokenType.String: + return BsonType.String; + case JTokenType.Boolean: + return BsonType.Boolean; + case JTokenType.Null: + case JTokenType.Undefined: + return BsonType.Null; + case JTokenType.Date: + return BsonType.Date; + case JTokenType.Bytes: + return BsonType.Binary; + default: + throw new ArgumentOutOfRangeException(); + } + } + + private int CalculateSize(string s) + { + int ret; + if (s != null) + ret = Encoding.UTF8.GetByteCount(s); + else + ret = 0; + return ret + 1; + } + + private int CalculateSizeWithLength(string s, bool includeSize) + { + int baseSize = (includeSize) + ? 5 // size bytes + terminator + : 1; // terminator + + int ret; + if (s != null) + ret = Encoding.UTF8.GetByteCount(s); + else + ret = 0; + return baseSize + ret; + } + + private int CalculateSize(JToken t) + { + switch (t.Type) + { + case JTokenType.Object: + { + int bases = 4; + foreach (JProperty p in t) + { + bases += CalculateSize(p); + } + bases += 1; + return bases; + } + case JTokenType.Array: + { + int bases = 4; + int index = 0; + foreach (JToken c in t) + { + bases += 1; + bases += CalculateSize(index.ToString()); + bases += CalculateSize(c); + index++; + } + bases += 1; + return bases; + } + case JTokenType.Constructor: + throw new JsonWriterException("Cannot write JSON constructor as BSON."); + case JTokenType.Property: + JProperty property = (JProperty) t; + int ss = 1; + ss += CalculateSize(property.Name); + ss += CalculateSize(property.Value); + return ss; + case JTokenType.Comment: + throw new JsonWriterException("Cannot write JSON comment as BSON."); + case JTokenType.Integer: + return 4; + case JTokenType.Float: + return 8; + case JTokenType.String: + string s = (string)t; + + return CalculateSizeWithLength(s, true); + case JTokenType.Boolean: + return 1; + case JTokenType.Null: + case JTokenType.Undefined: + return 0; + case JTokenType.Date: + return 8; + case JTokenType.Raw: + throw new JsonWriterException("Cannot write raw JSON as BSON."); + case JTokenType.Bytes: + byte[] data = (byte[]) t; + return 4 + 1 + data.Length; + default: + throw new ArgumentOutOfRangeException(); + } + } + + public void Write(string str) + { + Byte[] buf = new byte[Encoding.UTF8.GetByteCount(str) + 1]; + buf[buf.Length - 1] = 0; + Encoding.UTF8.GetBytes(str, 0, str.Length, buf, 0); + _writer.Write(buf); + } + + public void Write(bool val) + { + if (val) + _writer.Write((byte)1); + else + _writer.Write((byte)0); + } + + public void Write(byte val) + { + _writer.Write(val); + } + + public void Write(byte[] val) + { + _writer.Write(val); + } + + public void Write(int val) + { + _writer.Write(val); + } + + public void Write(long val) + { + _writer.Write(val); + } + + public void Write(double val) + { + _writer.Write(val); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Converters/BinaryConverter.cs b/Src/Newtonsoft.Json/Converters/BinaryConverter.cs index 01ac5afd..2a344239 100644 --- a/Src/Newtonsoft.Json/Converters/BinaryConverter.cs +++ b/Src/Newtonsoft.Json/Converters/BinaryConverter.cs @@ -65,12 +65,9 @@ namespace Newtonsoft.Json.Converters return; } - byte[] data = value as byte[]; + byte[] data = GetByteArray(value); - if (data == null) - data = GetByteArray(value); - - writer.WriteValue(Convert.ToBase64String(data)); + writer.WriteValue(data); } private byte[] GetByteArray(object value) @@ -113,19 +110,17 @@ namespace Newtonsoft.Json.Converters if (reader.TokenType != JsonToken.String) throw new Exception("Unexpected token parsing binary. Expected String, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); + // current token is already at base64 string + // unable to call ReadAsBytes so do it the old fashion way string encodedData = reader.Value.ToString(); - byte[] data = Convert.FromBase64String(encodedData); - if (t == typeof(byte[])) - return data; - #if !SILVERLIGHT && !PocketPC && !NET20 if (t.AssignableToTypeName(BinaryTypeName)) return Activator.CreateInstance(t, data); #endif #if !SILVERLIGHT - if (typeof(SqlBinary).IsAssignableFrom(t)) + if (t == typeof(SqlBinary)) return new SqlBinary(data); #endif throw new Exception("Unexpected object type when writing binary: {0}".FormatWith(CultureInfo.InvariantCulture, objectType)); @@ -144,15 +139,12 @@ namespace Newtonsoft.Json.Converters ? Nullable.GetUnderlyingType(objectType) : objectType; - if (t == typeof(byte[])) - return true; - #if !SILVERLIGHT && !PocketPC && !NET20 if (t.AssignableToTypeName(BinaryTypeName)) return true; #endif #if !SILVERLIGHT - if (typeof(SqlBinary).IsAssignableFrom(t)) + if (t == typeof(SqlBinary)) return true; #endif return false; diff --git a/Src/Newtonsoft.Json/Converters/DataSetConverter.cs b/Src/Newtonsoft.Json/Converters/DataSetConverter.cs index 692de6bd..6fe951a1 100644 --- a/Src/Newtonsoft.Json/Converters/DataSetConverter.cs +++ b/Src/Newtonsoft.Json/Converters/DataSetConverter.cs @@ -1,4 +1,29 @@ -#if !SILVERLIGHT +#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 + +#if !SILVERLIGHT using System; using System.Collections.Generic; using System.Data; @@ -48,7 +73,7 @@ namespace Newtonsoft.Json.Converters public override bool CanConvert(Type valueType) { - return typeof(DataSet).IsAssignableFrom(valueType); + return (valueType == typeof(DataSet)); } } } diff --git a/Src/Newtonsoft.Json/Converters/DataTableConverter.cs b/Src/Newtonsoft.Json/Converters/DataTableConverter.cs index 675d7330..e207f8a4 100644 --- a/Src/Newtonsoft.Json/Converters/DataTableConverter.cs +++ b/Src/Newtonsoft.Json/Converters/DataTableConverter.cs @@ -1,4 +1,29 @@ -#if !SILVERLIGHT +#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 + +#if !SILVERLIGHT using System; using System.Collections.Generic; using System.Linq; @@ -100,7 +125,7 @@ namespace Newtonsoft.Json.Converters public override bool CanConvert(Type valueType) { - return typeof(DataTable).IsAssignableFrom(valueType); + return (valueType == typeof(DataTable)); } } } diff --git a/Src/Newtonsoft.Json/Converters/HtmlColorConverter.cs b/Src/Newtonsoft.Json/Converters/HtmlColorConverter.cs index b4a29b7c..c82875eb 100644 --- a/Src/Newtonsoft.Json/Converters/HtmlColorConverter.cs +++ b/Src/Newtonsoft.Json/Converters/HtmlColorConverter.cs @@ -56,7 +56,7 @@ namespace Newtonsoft.Json.Converters /// public override bool CanConvert(Type valueType) { - return typeof(Color).IsAssignableFrom(valueType); + return (valueType == typeof(Color)); } /// diff --git a/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs b/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs index b03e7d87..0e37a87e 100644 --- a/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs @@ -68,6 +68,7 @@ namespace Newtonsoft.Json.Converters text = dateTime.ToString(_dateTimeFormat ?? DefaultDateTimeFormat, Culture); } +#if !PocketPC && !NET20 else if (value is DateTimeOffset) { DateTimeOffset dateTimeOffset = (DateTimeOffset)value; @@ -77,6 +78,7 @@ namespace Newtonsoft.Json.Converters text = dateTimeOffset.ToString(_dateTimeFormat ?? DefaultDateTimeFormat, Culture); } +#endif else { throw new Exception("Unexpected value when converting date. Expected DateTime or DateTimeOffset, got {0}.".FormatWith(CultureInfo.InvariantCulture, ReflectionUtils.GetObjectType(value))); @@ -115,6 +117,7 @@ namespace Newtonsoft.Json.Converters if (string.IsNullOrEmpty(dateText) && nullable) return null; +#if !PocketPC && !NET20 if (t == typeof(DateTimeOffset)) { if (!string.IsNullOrEmpty(_dateTimeFormat)) @@ -122,6 +125,7 @@ namespace Newtonsoft.Json.Converters else return DateTimeOffset.Parse(dateText, Culture, _dateTimeStyles); } +#endif if (!string.IsNullOrEmpty(_dateTimeFormat)) return DateTime.ParseExact(dateText, _dateTimeFormat, Culture, _dateTimeStyles); @@ -142,10 +146,12 @@ namespace Newtonsoft.Json.Converters ? Nullable.GetUnderlyingType(objectType) : objectType; - if (typeof(DateTime).IsAssignableFrom(t)) + if (t == typeof(DateTime)) return true; - if (typeof(DateTimeOffset).IsAssignableFrom(t)) +#if !PocketPC && !NET20 + if (t == typeof(DateTimeOffset)) return true; +#endif return false; } diff --git a/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs b/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs index 74b40284..be043dde 100644 --- a/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs @@ -25,12 +25,18 @@ namespace Newtonsoft.Json.Converters DateTime utcDateTime = dateTime.ToUniversalTime(); ticks = JsonConvert.ConvertDateTimeToJavaScriptTicks(utcDateTime); } - else +#if !PocketPC && !NET20 + else if (value is DateTimeOffset) { DateTimeOffset dateTimeOffset = (DateTimeOffset)value; DateTimeOffset utcDateTimeOffset = dateTimeOffset.ToUniversalTime(); ticks = JsonConvert.ConvertDateTimeToJavaScriptTicks(utcDateTimeOffset.UtcDateTime); } +#endif + else + { + throw new Exception("Expected date object value."); + } writer.WriteStartConstructor("Date"); writer.WriteValue(ticks); @@ -75,8 +81,10 @@ namespace Newtonsoft.Json.Converters if (reader.TokenType != JsonToken.EndConstructor) throw new Exception("Unexpected token parsing date. Expected EndConstructor, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); +#if !PocketPC && !NET20 if (t == typeof(DateTimeOffset)) return new DateTimeOffset(d); +#endif return d; } @@ -94,10 +102,12 @@ namespace Newtonsoft.Json.Converters ? Nullable.GetUnderlyingType(objectType) : objectType; - if (typeof(DateTime).IsAssignableFrom(t)) + if (t == typeof(DateTime)) return true; - if (typeof(DateTimeOffset).IsAssignableFrom(t)) +#if !PocketPC && !NET20 + if (t == typeof(DateTimeOffset)) return true; +#endif return false; } diff --git a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs index ed2e06b6..13361658 100644 --- a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs @@ -522,6 +522,9 @@ namespace Newtonsoft.Json.Converters DeserializeValue(reader, document, manager, "-" + constructorName, currentNode); } break; + case JsonToken.Comment: + currentNode.AppendChild(document.CreateComment((string)reader.Value)); + break; case JsonToken.EndObject: case JsonToken.EndArray: return; diff --git a/Src/Newtonsoft.Json/DateTimeOffset.cs b/Src/Newtonsoft.Json/DateTimeOffset.cs deleted file mode 100644 index 601ea534..00000000 --- a/Src/Newtonsoft.Json/DateTimeOffset.cs +++ /dev/null @@ -1,544 +0,0 @@ -#if PocketPC -#pragma warning disable 1591 - -// This class is... borrowed from .NET and Microsoft for a short time. -// Hopefully Microsoft will add DateTimeOffset to the compact framework -// or I will rewrite a striped down version of this file myself - -using System.Globalization; -using System.Runtime.InteropServices; -using System.Runtime.Serialization; -using System.Security.Permissions; -using System; - -namespace System -{ - public struct DateTimeOffset : IComparable, IFormattable, IComparable, IEquatable - { - private DateTime _dateTime; - private short _offsetMinutes; - internal const long MaxOffset = 0x7558bdb000L; - public static readonly DateTimeOffset MaxValue; - internal const long MinOffset = -504000000000L; - public static readonly DateTimeOffset MinValue; - - static DateTimeOffset() - { - MinValue = new DateTimeOffset(0L, TimeSpan.Zero); - MaxValue = new DateTimeOffset(0x2bca2875f4373fffL, TimeSpan.Zero); - } - - public DateTimeOffset(System.DateTime dateTime) - { - TimeSpan utcOffset; - if (dateTime.Kind != DateTimeKind.Utc) - { - utcOffset = TimeZone.CurrentTimeZone.GetUtcOffset(dateTime); - } - else - { - utcOffset = new TimeSpan(0L); - } - this._offsetMinutes = ValidateOffset(utcOffset); - this._dateTime = ValidateDate(dateTime, utcOffset); - } - - public DateTimeOffset(System.DateTime dateTime, TimeSpan offset) - { - if (dateTime.Kind == DateTimeKind.Local) - { - if (offset != TimeZone.CurrentTimeZone.GetUtcOffset(dateTime)) - { - throw new ArgumentException("The UTC Offset of the local dateTime parameter does not match the offset argument.", "offset"); - } - } - else if ((dateTime.Kind == DateTimeKind.Utc) && (offset != TimeSpan.Zero)) - { - throw new ArgumentException("The UTC Offset for Utc DateTime instances must be 0.", "offset"); - } - this._offsetMinutes = ValidateOffset(offset); - this._dateTime = ValidateDate(dateTime, offset); - } - - public DateTimeOffset(long ticks, TimeSpan offset) - { - this._offsetMinutes = ValidateOffset(offset); - System.DateTime dateTime = new System.DateTime(ticks); - this._dateTime = ValidateDate(dateTime, offset); - } - - public DateTimeOffset(int year, int month, int day, int hour, int minute, int second, TimeSpan offset) - { - this._offsetMinutes = ValidateOffset(offset); - this._dateTime = ValidateDate(new System.DateTime(year, month, day, hour, minute, second), offset); - } - - public DateTimeOffset(int year, int month, int day, int hour, int minute, int second, int millisecond, TimeSpan offset) - { - this._offsetMinutes = ValidateOffset(offset); - this._dateTime = ValidateDate(new System.DateTime(year, month, day, hour, minute, second, millisecond), offset); - } - - public DateTimeOffset(int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar, TimeSpan offset) - { - this._offsetMinutes = ValidateOffset(offset); - this._dateTime = ValidateDate(new System.DateTime(year, month, day, hour, minute, second, millisecond, calendar), offset); - } - - public DateTimeOffset Add(TimeSpan timeSpan) - { - return new DateTimeOffset(this.ClockDateTime.Add(timeSpan), this.Offset); - } - - public DateTimeOffset AddDays(double days) - { - return new DateTimeOffset(this.ClockDateTime.AddDays(days), this.Offset); - } - - public DateTimeOffset AddHours(double hours) - { - return new DateTimeOffset(this.ClockDateTime.AddHours(hours), this.Offset); - } - - public DateTimeOffset AddMilliseconds(double milliseconds) - { - return new DateTimeOffset(this.ClockDateTime.AddMilliseconds(milliseconds), this.Offset); - } - - public DateTimeOffset AddMinutes(double minutes) - { - return new DateTimeOffset(this.ClockDateTime.AddMinutes(minutes), this.Offset); - } - - public DateTimeOffset AddMonths(int months) - { - return new DateTimeOffset(this.ClockDateTime.AddMonths(months), this.Offset); - } - - public DateTimeOffset AddSeconds(double seconds) - { - return new DateTimeOffset(this.ClockDateTime.AddSeconds(seconds), this.Offset); - } - - public DateTimeOffset AddTicks(long ticks) - { - return new DateTimeOffset(this.ClockDateTime.AddTicks(ticks), this.Offset); - } - - public DateTimeOffset AddYears(int years) - { - return new DateTimeOffset(this.ClockDateTime.AddYears(years), this.Offset); - } - - public static int Compare(DateTimeOffset first, DateTimeOffset second) - { - return System.DateTime.Compare(first.UtcDateTime, second.UtcDateTime); - } - - public int CompareTo(DateTimeOffset other) - { - System.DateTime utcDateTime = other.UtcDateTime; - System.DateTime time2 = this.UtcDateTime; - if (time2 > utcDateTime) - { - return 1; - } - if (time2 < utcDateTime) - { - return -1; - } - return 0; - } - - public bool Equals(DateTimeOffset other) - { - return this.UtcDateTime.Equals(other.UtcDateTime); - } - - public override bool Equals(object obj) - { - if (obj is DateTimeOffset) - { - DateTimeOffset offset = (DateTimeOffset)obj; - return this.UtcDateTime.Equals(offset.UtcDateTime); - } - return false; - } - - public static bool Equals(DateTimeOffset first, DateTimeOffset second) - { - return System.DateTime.Equals(first.UtcDateTime, second.UtcDateTime); - } - - public bool EqualsExact(DateTimeOffset other) - { - return (((this.ClockDateTime == other.ClockDateTime) && (this.Offset == other.Offset)) && (this.ClockDateTime.Kind == other.ClockDateTime.Kind)); - } - - public static DateTimeOffset FromFileTime(long fileTime) - { - return new DateTimeOffset(System.DateTime.FromFileTime(fileTime)); - } - - public override int GetHashCode() - { - return this.UtcDateTime.GetHashCode(); - } - - public static DateTimeOffset operator +(DateTimeOffset dateTimeTz, TimeSpan timeSpan) - { - return new DateTimeOffset(dateTimeTz.ClockDateTime + timeSpan, dateTimeTz.Offset); - } - - public static bool operator ==(DateTimeOffset left, DateTimeOffset right) - { - return (left.UtcDateTime == right.UtcDateTime); - } - - public static bool operator >(DateTimeOffset left, DateTimeOffset right) - { - return (left.UtcDateTime > right.UtcDateTime); - } - - public static bool operator >=(DateTimeOffset left, DateTimeOffset right) - { - return (left.UtcDateTime >= right.UtcDateTime); - } - - public static implicit operator DateTimeOffset(System.DateTime dateTime) - { - return new DateTimeOffset(dateTime); - } - - public static bool operator !=(DateTimeOffset left, DateTimeOffset right) - { - return (left.UtcDateTime != right.UtcDateTime); - } - - public static bool operator <(DateTimeOffset left, DateTimeOffset right) - { - return (left.UtcDateTime < right.UtcDateTime); - } - - public static bool operator <=(DateTimeOffset left, DateTimeOffset right) - { - return (left.UtcDateTime <= right.UtcDateTime); - } - - public static TimeSpan operator -(DateTimeOffset left, DateTimeOffset right) - { - return (TimeSpan)(left.UtcDateTime - right.UtcDateTime); - } - - public static DateTimeOffset operator -(DateTimeOffset dateTimeTz, TimeSpan timeSpan) - { - return new DateTimeOffset(dateTimeTz.ClockDateTime - timeSpan, dateTimeTz.Offset); - } - - public static DateTimeOffset Parse(string input) - { - return new DateTimeOffset(DateTime.Parse(input, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None)); - } - - public static DateTimeOffset Parse(string input, IFormatProvider formatProvider) - { - return Parse(input, formatProvider, DateTimeStyles.None); - } - - public static DateTimeOffset Parse(string input, IFormatProvider formatProvider, DateTimeStyles styles) - { - styles = ValidateStyles(styles, "styles"); - return new DateTimeOffset(DateTime.Parse(input, DateTimeFormatInfo.GetInstance(formatProvider), styles)); - } - - public static DateTimeOffset ParseExact(string input, string format, IFormatProvider formatProvider) - { - return ParseExact(input, format, formatProvider, DateTimeStyles.None); - } - - public static DateTimeOffset ParseExact(string input, string format, IFormatProvider formatProvider, DateTimeStyles styles) - { - styles = ValidateStyles(styles, "styles"); - return new DateTimeOffset(DateTime.ParseExact(input, format, DateTimeFormatInfo.GetInstance(formatProvider), styles)); - } - - public static DateTimeOffset ParseExact(string input, string[] formats, IFormatProvider formatProvider, DateTimeStyles styles) - { - styles = ValidateStyles(styles, "styles"); - return new DateTimeOffset(DateTime.ParseExact(input, formats, DateTimeFormatInfo.GetInstance(formatProvider), styles)); - } - - public TimeSpan Subtract(DateTimeOffset value) - { - return this.UtcDateTime.Subtract(value.UtcDateTime); - } - - public DateTimeOffset Subtract(TimeSpan value) - { - return new DateTimeOffset(this.ClockDateTime.Subtract(value), this.Offset); - } - - int IComparable.CompareTo(object obj) - { - if (obj == null) - { - return 1; - } - if (!(obj is DateTimeOffset)) - { - throw new ArgumentException("Object must be of type DateTimeOffset."); - } - DateTimeOffset offset = (DateTimeOffset)obj; - System.DateTime utcDateTime = offset.UtcDateTime; - System.DateTime time2 = this.UtcDateTime; - if (time2 > utcDateTime) - { - return 1; - } - if (time2 < utcDateTime) - { - return -1; - } - return 0; - } - - public long ToFileTime() - { - return this.UtcDateTime.ToFileTime(); - } - - public DateTimeOffset ToLocalTime() - { - return new DateTimeOffset(this.UtcDateTime.ToLocalTime()); - } - - public DateTimeOffset ToOffset(TimeSpan offset) - { - System.DateTime time = this._dateTime + offset; - return new DateTimeOffset(time.Ticks, offset); - } - - public string ToString(string format, IFormatProvider formatProvider) - { - if (!string.IsNullOrEmpty(format)) - { - format = format.Replace("K", "zzz"); - format = format.Replace("zzz", Offset.Hours.ToString("+00;-00", CultureInfo.InvariantCulture) + ":" + Offset.Minutes.ToString("00;00", CultureInfo.InvariantCulture)); - format = format.Replace("zz", Offset.Hours.ToString("+00;-00", CultureInfo.InvariantCulture)); - format = format.Replace("z", Offset.Hours.ToString("+0;-0", CultureInfo.InvariantCulture)); - } - - return ClockDateTime.ToString(format, formatProvider); - } - - public DateTimeOffset ToUniversalTime() - { - return new DateTimeOffset(this.UtcDateTime); - } - - private static System.DateTime ValidateDate(System.DateTime dateTime, TimeSpan offset) - { - long ticks = dateTime.Ticks - offset.Ticks; - if ((ticks < 0L) || (ticks > 0x2bca2875f4373fffL)) - { - throw new ArgumentOutOfRangeException("offset", "The UTC time represented when the offset is applied must be between year 0 and 10,000."); - } - return new System.DateTime(ticks, DateTimeKind.Unspecified); - } - - private static short ValidateOffset(TimeSpan offset) - { - long ticks = offset.Ticks; - if ((ticks % 0x23c34600L) != 0L) - { - throw new ArgumentException("Offset must be specified in whole minutes.", "offset"); - } - if ((ticks < -504000000000L) || (ticks > 0x7558bdb000L)) - { - throw new ArgumentOutOfRangeException("offset", "Offset must be within plus or minus 14 hours."); - } - return (short)(offset.Ticks / 0x23c34600L); - } - - private static DateTimeStyles ValidateStyles(DateTimeStyles style, string parameterName) - { - if ((style & ~(DateTimeStyles.RoundtripKind | DateTimeStyles.AssumeUniversal | DateTimeStyles.AssumeLocal | DateTimeStyles.AdjustToUniversal | DateTimeStyles.NoCurrentDateDefault | DateTimeStyles.AllowWhiteSpaces)) != DateTimeStyles.None) - { - throw new ArgumentException("An undefined DateTimeStyles value is being used.", parameterName); - } - if (((style & DateTimeStyles.AssumeLocal) != DateTimeStyles.None) && ((style & DateTimeStyles.AssumeUniversal) != DateTimeStyles.None)) - { - throw new ArgumentException("The DateTimeStyles values AssumeLocal and AssumeUniversal cannot be used together.", parameterName); - } - if ((style & DateTimeStyles.NoCurrentDateDefault) != DateTimeStyles.None) - { - throw new ArgumentException("The DateTimeStyles value 'NoCurrentDateDefault' is not allowed when parsing DateTimeOffset.", parameterName); - } - style &= ~DateTimeStyles.RoundtripKind; - style &= ~DateTimeStyles.AssumeLocal; - return style; - } - - private System.DateTime ClockDateTime - { - get - { - System.DateTime time = this._dateTime + this.Offset; - return new System.DateTime(time.Ticks, DateTimeKind.Unspecified); - } - } - - public System.DateTime Date - { - get - { - return this.ClockDateTime.Date; - } - } - - public System.DateTime DateTime - { - get - { - return this.ClockDateTime; - } - } - - public int Day - { - get - { - return this.ClockDateTime.Day; - } - } - - public System.DayOfWeek DayOfWeek - { - get - { - return this.ClockDateTime.DayOfWeek; - } - } - - public int DayOfYear - { - get - { - return this.ClockDateTime.DayOfYear; - } - } - - public int Hour - { - get - { - return this.ClockDateTime.Hour; - } - } - - public System.DateTime LocalDateTime - { - get - { - return this.UtcDateTime.ToLocalTime(); - } - } - - public int Millisecond - { - get - { - return this.ClockDateTime.Millisecond; - } - } - - public int Minute - { - get - { - return this.ClockDateTime.Minute; - } - } - - public int Month - { - get - { - return this.ClockDateTime.Month; - } - } - - public static DateTimeOffset Now - { - get - { - return new DateTimeOffset(System.DateTime.Now); - } - } - - public TimeSpan Offset - { - get - { - return new TimeSpan(0, this._offsetMinutes, 0); - } - } - - public int Second - { - get - { - return this.ClockDateTime.Second; - } - } - - public long Ticks - { - get - { - return this.ClockDateTime.Ticks; - } - } - - public TimeSpan TimeOfDay - { - get - { - return this.ClockDateTime.TimeOfDay; - } - } - - public System.DateTime UtcDateTime - { - get - { - return System.DateTime.SpecifyKind(this._dateTime, DateTimeKind.Utc); - } - } - - public static DateTimeOffset UtcNow - { - get - { - return new DateTimeOffset(System.DateTime.UtcNow); - } - } - - public long UtcTicks - { - get - { - return this.UtcDateTime.Ticks; - } - } - - public int Year - { - get - { - return this.ClockDateTime.Year; - } - } - } -} -#endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonConvert.cs b/Src/Newtonsoft.Json/JsonConvert.cs index 9c6d4436..db5d1c7b 100644 --- a/Src/Newtonsoft.Json/JsonConvert.cs +++ b/Src/Newtonsoft.Json/JsonConvert.cs @@ -106,6 +106,7 @@ namespace Newtonsoft.Json return ToStringInternal(value, utcOffset, value.Kind); } +#if !PocketPC && !NET20 /// /// Converts the to its JSON string representation. /// @@ -115,6 +116,7 @@ namespace Newtonsoft.Json { return ToStringInternal(value.UtcDateTime, value.Offset, DateTimeKind.Local); } +#endif internal static string ToStringInternal(DateTime value, TimeSpan offset, DateTimeKind kind) { @@ -387,10 +389,12 @@ namespace Newtonsoft.Json return Null; } } +#if !PocketPC && !NET20 else if (value is DateTimeOffset) { return ToString((DateTimeOffset)value); } +#endif throw new ArgumentException("Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.".FormatWith(CultureInfo.InvariantCulture, value.GetType())); } @@ -427,9 +431,14 @@ namespace Newtonsoft.Json return false; } } - + +#if !PocketPC && !NET20 if (value is DateTimeOffset) return true; +#endif + + if (value is byte[]) + return true; return false; } diff --git a/Src/Newtonsoft.Json/JsonReader.cs b/Src/Newtonsoft.Json/JsonReader.cs index 86a38e2c..875a5ac9 100644 --- a/Src/Newtonsoft.Json/JsonReader.cs +++ b/Src/Newtonsoft.Json/JsonReader.cs @@ -169,7 +169,7 @@ namespace Newtonsoft.Json /// /// Initializes a new instance of the class with the specified . /// - public JsonReader() + protected JsonReader() { //_testBuffer = new StringBuilder(); _currentState = State.Start; @@ -204,6 +204,8 @@ namespace Newtonsoft.Json /// true if the next token was read successfully; false if there are no more tokens to read. public abstract bool Read(); + public abstract byte[] ReadAsBytes(); + /// /// Skips the children of the current token. /// @@ -275,6 +277,7 @@ namespace Newtonsoft.Json case JsonToken.Date: case JsonToken.String: case JsonToken.Raw: + case JsonToken.Bytes: _currentState = State.PostValue; break; } @@ -351,6 +354,7 @@ namespace Newtonsoft.Json case JsonToken.EndConstructor: case JsonToken.Date: case JsonToken.Raw: + case JsonToken.Bytes: return false; default: throw MiscellaneousUtils.CreateArgumentOutOfRangeException("token", token, "Unexpected JsonToken value."); diff --git a/Src/Newtonsoft.Json/JsonSerializer.cs b/Src/Newtonsoft.Json/JsonSerializer.cs index 2d65567b..e8cc5994 100644 --- a/Src/Newtonsoft.Json/JsonSerializer.cs +++ b/Src/Newtonsoft.Json/JsonSerializer.cs @@ -423,7 +423,7 @@ namespace Newtonsoft.Json if (objectType == null) throw new ArgumentNullException("objectType"); - converter = JsonTypeReflector.GetConverter(objectType, objectType); + converter = JsonTypeReflector.GetJsonConverter(objectType, objectType); return (converter != null); } diff --git a/Src/Newtonsoft.Json/JsonTextReader.cs b/Src/Newtonsoft.Json/JsonTextReader.cs index 83d4e981..00ce3f6d 100644 --- a/Src/Newtonsoft.Json/JsonTextReader.cs +++ b/Src/Newtonsoft.Json/JsonTextReader.cs @@ -60,12 +60,30 @@ namespace Newtonsoft.Json } private void ParseString(char quote) + { + ReadStringIntoBuffer(quote, null); + + string text = _buffer.ToString(); + _buffer.Position = 0; + + if (text.StartsWith("/Date(", StringComparison.Ordinal) && text.EndsWith(")/", StringComparison.Ordinal)) + { + ParseDate(text); + } + else + { + SetToken(JsonToken.String, text); + QuoteChar = quote; + } + } + + private void ReadStringIntoBuffer(char quote, int? untilPosition) { bool stringTerminated = false; bool hexNumber = false; int hexCount = 0; - while (!stringTerminated && MoveNext()) + while (!stringTerminated && (untilPosition == null || _buffer.Position < untilPosition) && MoveNext()) { if (hexNumber) hexCount++; @@ -136,18 +154,6 @@ namespace Newtonsoft.Json throw CreateJsonReaderException("Unterminated string. Expected delimiter: {0}. Line {1}, position {2}.", quote, _currentLineNumber, _currentLinePosition); ClearCurrentChar(); - string text = _buffer.ToString(); - _buffer.Position = 0; - - if (text.StartsWith("/Date(", StringComparison.Ordinal) && text.EndsWith(")/", StringComparison.Ordinal)) - { - ParseDate(text); - } - else - { - SetToken(JsonToken.String, text); - QuoteChar = quote; - } } private JsonReaderException CreateJsonReaderException(string format, params object[] args) @@ -321,6 +327,61 @@ namespace Newtonsoft.Json } } + public override byte[] ReadAsBytes() + { + while (true) + { + if (_currentChar == '\0') + { + if (!MoveNext()) + throw CreateJsonReaderException("Unexpected end: Line {0}, position {1}.", _currentLineNumber, _currentLinePosition); + } + + switch (CurrentState) + { + case State.Start: + case State.Property: + case State.Array: + case State.ArrayStart: + case State.Constructor: + case State.ConstructorStart: + do + { + switch (_currentChar) + { + case '"': + case '\'': + ReadStringIntoBuffer(_currentChar, null); + + byte[] data = Convert.FromBase64CharArray(_buffer.GetInternalBuffer(), 0, _buffer.Position); + _buffer.Position = 0; + + SetToken(JsonToken.Bytes, data); + + return data; + case 'n': + ParseNull(); + return null; + default: + if (char.IsWhiteSpace(_currentChar)) + { + // eat + } + else + { + throw CreateJsonReaderException("Unexpected character encountered while parsing value: {0}. Line {1}, position {2}.", _currentChar, _currentLineNumber, _currentLinePosition); + } + break; + } + } while (MoveNext()); + ParseValue(); + break; + default: + throw CreateJsonReaderException("Unexpected state: {0}. Line {1}, position {2}.", CurrentState, _currentLineNumber, _currentLinePosition); + } + } + } + private bool ParsePostValue() { do diff --git a/Src/Newtonsoft.Json/JsonTextWriter.cs b/Src/Newtonsoft.Json/JsonTextWriter.cs index 0746b1eb..ce2ee004 100644 --- a/Src/Newtonsoft.Json/JsonTextWriter.cs +++ b/Src/Newtonsoft.Json/JsonTextWriter.cs @@ -37,12 +37,24 @@ namespace Newtonsoft.Json /// public class JsonTextWriter : JsonWriter { - private TextWriter _writer; + private readonly TextWriter _writer; + private Base64Encoder _base64Encoder; private char _indentChar; private int _indentation; private char _quoteChar; private bool _quoteName; + private Base64Encoder Base64Encoder + { + get + { + if (_base64Encoder == null) + _base64Encoder = new Base64Encoder(_writer); + + return _base64Encoder; + } + } + /// /// Gets or sets how many IndentChars to write for each level in the hierarchy when is set to Formatting.Indented. /// @@ -419,6 +431,20 @@ namespace Newtonsoft.Json WriteValueInternal(JsonConvert.ToString(value), JsonToken.Date); } + public override void WriteValue(byte[] value) + { + base.WriteValue(value); + + if (value != null) + { + _writer.Write(_quoteChar); + Base64Encoder.Encode(value, 0, value.Length); + Base64Encoder.Flush(); + _writer.Write(_quoteChar); + } + } + +#if !PocketPC && !NET20 /// /// Writes a value. /// @@ -428,6 +454,7 @@ namespace Newtonsoft.Json base.WriteValue(value); WriteValueInternal(JsonConvert.ToString(value), JsonToken.Date); } +#endif #endregion /// diff --git a/Src/Newtonsoft.Json/JsonToken.cs b/Src/Newtonsoft.Json/JsonToken.cs index 1e5fae1f..5870c420 100644 --- a/Src/Newtonsoft.Json/JsonToken.cs +++ b/Src/Newtonsoft.Json/JsonToken.cs @@ -47,11 +47,11 @@ namespace Newtonsoft.Json /// StartArray, /// - /// An object property name. + /// A constructor start token. /// StartConstructor, /// - /// A constructor end token. + /// An object property name. /// PropertyName, /// @@ -95,12 +95,16 @@ namespace Newtonsoft.Json /// EndArray, /// - /// A constructor start token. + /// A constructor end token. /// EndConstructor, /// /// A Date. /// - Date + Date, + /// + /// Byte data. + /// + Bytes } -} +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonValidatingReader.cs b/Src/Newtonsoft.Json/JsonValidatingReader.cs index 0899c2d2..2b958aa0 100644 --- a/Src/Newtonsoft.Json/JsonValidatingReader.cs +++ b/Src/Newtonsoft.Json/JsonValidatingReader.cs @@ -304,6 +304,14 @@ namespace Newtonsoft.Json } } + public override byte[] ReadAsBytes() + { + byte[] data = _reader.ReadAsBytes(); + + ValidateCurrentToken(); + return data; + } + /// /// Reads the next JSON token from the stream. /// @@ -318,7 +326,13 @@ namespace Newtonsoft.Json if (_reader.TokenType == JsonToken.Comment) return true; - // first time Read has been called. build model + ValidateCurrentToken(); + return true; + } + + private void ValidateCurrentToken() + { + // first time validate has been called. build model if (_model == null) { JsonSchemaModelBuilder builder = new JsonSchemaModelBuilder(); @@ -330,15 +344,15 @@ namespace Newtonsoft.Json case JsonToken.StartObject: ProcessValue(); JsonSchemaModel objectSchema = (ValidateObject(CurrentMemberSchema)) - ? CurrentMemberSchema - : null; + ? CurrentMemberSchema + : null; Push(new SchemaScope(JTokenType.Object, objectSchema)); break; case JsonToken.StartArray: ProcessValue(); JsonSchemaModel arraySchema = (ValidateArray(CurrentMemberSchema)) - ? CurrentMemberSchema - : null; + ? CurrentMemberSchema + : null; Push(new SchemaScope(JTokenType.Array, arraySchema)); break; case JsonToken.StartConstructor: @@ -387,8 +401,6 @@ namespace Newtonsoft.Json default: throw new ArgumentOutOfRangeException(); } - - return true; } private void ValidateEndObject(JsonSchemaModel schema) diff --git a/Src/Newtonsoft.Json/JsonWriter.cs b/Src/Newtonsoft.Json/JsonWriter.cs index e7738d7d..eeabf6fe 100644 --- a/Src/Newtonsoft.Json/JsonWriter.cs +++ b/Src/Newtonsoft.Json/JsonWriter.cs @@ -101,6 +101,7 @@ namespace Newtonsoft.Json Array, ConstructorStart, Constructor, + Bytes, Closed, Error } @@ -578,6 +579,7 @@ namespace Newtonsoft.Json case JsonToken.Null: case JsonToken.Undefined: case JsonToken.Date: + case JsonToken.Bytes: // a value is being written token = 7; break; @@ -780,6 +782,7 @@ namespace Newtonsoft.Json AutoComplete(JsonToken.Date); } +#if !PocketPC && !NET20 /// /// Writes a value. /// @@ -788,6 +791,7 @@ namespace Newtonsoft.Json { AutoComplete(JsonToken.Date); } +#endif /// /// Writes a value. @@ -957,6 +961,7 @@ namespace Newtonsoft.Json WriteValue(value.Value); } +#if !PocketPC && !NET20 /// /// Writes a value. /// @@ -968,6 +973,15 @@ namespace Newtonsoft.Json else WriteValue(value.Value); } +#endif + + public virtual void WriteValue(byte[] value) + { + if (value == null) + WriteNull(); + else + AutoComplete(JsonToken.Bytes); + } /// /// Writes a value. @@ -1037,11 +1051,18 @@ namespace Newtonsoft.Json return; } } +#if !PocketPC && !NET20 else if (value is DateTimeOffset) { WriteValue((DateTimeOffset)value); return; } +#endif + else if (value is byte[]) + { + WriteValue((byte[])value); + return; + } throw new ArgumentException("Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.".FormatWith(CultureInfo.InvariantCulture, value.GetType())); } diff --git a/Src/Newtonsoft.Json/Linq/JContainer.cs b/Src/Newtonsoft.Json/Linq/JContainer.cs index fc813665..23365779 100644 --- a/Src/Newtonsoft.Json/Linq/JContainer.cs +++ b/Src/Newtonsoft.Json/Linq/JContainer.cs @@ -257,7 +257,7 @@ namespace Newtonsoft.Json.Linq internal bool IsMultiContent(object content) { - return (content is IEnumerable && !(content is string) && !(content is JToken)); + return (content is IEnumerable && !(content is string) && !(content is JToken) && !(content is byte[])); } internal virtual void AddItem(bool isLast, JToken previous, JToken item) diff --git a/Src/Newtonsoft.Json/Linq/JObject.cs b/Src/Newtonsoft.Json/Linq/JObject.cs index f6a01d16..5fb4260f 100644 --- a/Src/Newtonsoft.Json/Linq/JObject.cs +++ b/Src/Newtonsoft.Json/Linq/JObject.cs @@ -43,7 +43,7 @@ namespace Newtonsoft.Json.Linq [TypeDescriptionProvider(typeof(JTypeDescriptionProvider))] #endif public class JObject : JContainer, IDictionary, INotifyPropertyChanged -#if !PocketPC && !SILVERLIGHT +#if !PocketPC && !SILVERLIGHT && !NET20 , INotifyPropertyChanging #endif { @@ -51,7 +51,7 @@ namespace Newtonsoft.Json.Linq /// Occurs when a property value changes. /// public event PropertyChangedEventHandler PropertyChanged; -#if !PocketPC && !SILVERLIGHT +#if !PocketPC && !SILVERLIGHT && !NET20 /// /// Occurs when a property value is changing. /// @@ -121,7 +121,7 @@ namespace Newtonsoft.Json.Linq internal void InternalPropertyChanging(JProperty childProperty) { -#if !PocketPC && !SILVERLIGHT +#if !PocketPC && !SILVERLIGHT && !NET20 OnPropertyChanging(childProperty.Name); #endif } @@ -221,7 +221,7 @@ namespace Newtonsoft.Json.Linq } else { -#if !PocketPC && !SILVERLIGHT +#if !PocketPC && !SILVERLIGHT && !NET20 OnPropertyChanging(propertyName); #endif Add(new JProperty(propertyName, value)); @@ -472,7 +472,7 @@ namespace Newtonsoft.Json.Linq PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } -#if !PocketPC && !SILVERLIGHT +#if !PocketPC && !SILVERLIGHT && !NET20 /// /// Raises the event with the provided arguments. /// diff --git a/Src/Newtonsoft.Json/Linq/JToken.cs b/Src/Newtonsoft.Json/Linq/JToken.cs index 3cde6282..8587e5ed 100644 --- a/Src/Newtonsoft.Json/Linq/JToken.cs +++ b/Src/Newtonsoft.Json/Linq/JToken.cs @@ -400,6 +400,11 @@ namespace Newtonsoft.Json.Linq return (o.Type == JTokenType.String || o.Type == JTokenType.Comment || o.Type == JTokenType.Raw || IsNullable(o)); } + private static bool ValidateBytes(JToken o) + { + return (o.Type == JTokenType.Bytes || IsNullable(o)); + } + private static string GetType(JToken t) { return (t != null) ? t.Type.ToString() : "{null}"; @@ -420,6 +425,7 @@ namespace Newtonsoft.Json.Linq return (bool)v.Value; } +#if !PocketPC && !NET20 /// /// Performs an explicit conversion from to . /// @@ -433,6 +439,7 @@ namespace Newtonsoft.Json.Linq return (DateTimeOffset)v.Value; } +#endif /// /// Performs an explicit conversion from to . @@ -482,6 +489,7 @@ namespace Newtonsoft.Json.Linq return (DateTime?)v.Value; } +#if !PocketPC && !NET20 /// /// Performs an explicit conversion from to . /// @@ -498,6 +506,7 @@ namespace Newtonsoft.Json.Linq return (DateTimeOffset?)v.Value; } +#endif /// /// Performs an explicit conversion from to . @@ -732,6 +741,15 @@ namespace Newtonsoft.Json.Linq return Convert.ToUInt64(v.Value, CultureInfo.InvariantCulture); } + + public static explicit operator byte[](JToken value) + { + JValue v = EnsureValue(value); + if (v == null || !ValidateBytes(v)) + throw new ArgumentException("Can not convert {0} to byte array.".FormatWith(CultureInfo.InvariantCulture, GetType(v))); + + return (byte[])v.Value; + } #endregion #region Cast to operators @@ -745,6 +763,7 @@ namespace Newtonsoft.Json.Linq return new JValue(value); } +#if !PocketPC && !NET20 /// /// Performs an implicit conversion from to . /// @@ -754,6 +773,7 @@ namespace Newtonsoft.Json.Linq { return new JValue(value); } +#endif /// /// Performs an implicit conversion from to . @@ -785,6 +805,7 @@ namespace Newtonsoft.Json.Linq return new JValue(value); } +#if !PocketPC && !NET20 /// /// Performs an implicit conversion from to . /// @@ -794,6 +815,7 @@ namespace Newtonsoft.Json.Linq { return new JValue(value); } +#endif /// /// Performs an implicit conversion from to . @@ -964,6 +986,11 @@ namespace Newtonsoft.Json.Linq { return new JValue(value); } + + public static implicit operator JToken(byte[] value) + { + return new JValue(value); + } #endregion IEnumerator IEnumerable.GetEnumerator() diff --git a/Src/Newtonsoft.Json/Linq/JTokenReader.cs b/Src/Newtonsoft.Json/Linq/JTokenReader.cs index 28d99825..dc220420 100644 --- a/Src/Newtonsoft.Json/Linq/JTokenReader.cs +++ b/Src/Newtonsoft.Json/Linq/JTokenReader.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using Newtonsoft.Json.Utilities; +using System.Globalization; namespace Newtonsoft.Json.Linq { @@ -27,6 +28,15 @@ namespace Newtonsoft.Json.Linq _current = token; } + public override byte[] ReadAsBytes() + { + Read(); + if (TokenType != JsonToken.Bytes) + throw new JsonReaderException("Error reading bytes. Expected bytes but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); + + return (byte[])Value; + } + /// /// Reads the next JSON token from the stream. /// @@ -172,6 +182,9 @@ namespace Newtonsoft.Json.Linq case JTokenType.Raw: SetToken(JsonToken.Raw, ((JValue)token).Value); break; + case JTokenType.Bytes: + SetToken(JsonToken.Bytes, ((JValue)token).Value); + break; default: throw MiscellaneousUtils.CreateArgumentOutOfRangeException("Type", token.Type, "Unexpected JTokenType."); } @@ -216,4 +229,4 @@ namespace Newtonsoft.Json.Linq } } } -} +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Linq/JTokenType.cs b/Src/Newtonsoft.Json/Linq/JTokenType.cs index d0106da3..e20ce277 100644 --- a/Src/Newtonsoft.Json/Linq/JTokenType.cs +++ b/Src/Newtonsoft.Json/Linq/JTokenType.cs @@ -90,6 +90,7 @@ namespace Newtonsoft.Json.Linq /// /// A raw JSON value. /// - Raw + Raw, + Bytes } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Linq/JTokenWriter.cs b/Src/Newtonsoft.Json/Linq/JTokenWriter.cs index 273dea37..baae1ed1 100644 --- a/Src/Newtonsoft.Json/Linq/JTokenWriter.cs +++ b/Src/Newtonsoft.Json/Linq/JTokenWriter.cs @@ -334,6 +334,7 @@ namespace Newtonsoft.Json.Linq AddValue(value, JsonToken.Date); } +#if !PocketPC && !NET20 /// /// Writes a value. /// @@ -343,6 +344,13 @@ namespace Newtonsoft.Json.Linq base.WriteValue(value); AddValue(value, JsonToken.Date); } +#endif + + public override void WriteValue(byte[] value) + { + base.WriteValue(value); + AddValue(value, JsonToken.Bytes); + } #endregion } } diff --git a/Src/Newtonsoft.Json/Linq/JValue.cs b/Src/Newtonsoft.Json/Linq/JValue.cs index e7312077..57255110 100644 --- a/Src/Newtonsoft.Json/Linq/JValue.cs +++ b/Src/Newtonsoft.Json/Linq/JValue.cs @@ -142,6 +142,8 @@ namespace Newtonsoft.Json.Linq { if (objA == null && objB == null) return true; + if (objA == null || objB == null) + return false; switch (_valueType) { @@ -158,6 +160,13 @@ namespace Newtonsoft.Json.Linq return objA.Equals(objB); case JTokenType.Date: return objA.Equals(objB); + case JTokenType.Bytes: + byte[] b1 = objA as byte[]; + byte[] b2 = objB as byte[]; + if (b1 == null || b2 == null) + return false; + + return MiscellaneousUtils.ByteArrayCompare(b1, b2); default: throw MiscellaneousUtils.CreateArgumentOutOfRangeException("valueType", _valueType, "Unexpected value type: {0}".FormatWith(CultureInfo.InvariantCulture, _valueType)); } @@ -214,8 +223,12 @@ namespace Newtonsoft.Json.Linq return JTokenType.Float; else if (value is DateTime) return JTokenType.Date; +#if !PocketPC && !NET20 else if (value is DateTimeOffset) return JTokenType.Date; +#endif + else if (value is byte[]) + return JTokenType.Bytes; else if (value is bool) return JTokenType.Boolean; @@ -303,12 +316,17 @@ namespace Newtonsoft.Json.Linq case JTokenType.Date: WriteConvertableValue(writer, converters, v => { +#if !PocketPC && !NET20 if (v is DateTimeOffset) writer.WriteValue((DateTimeOffset)v); else - writer.WriteValue(Convert.ToDateTime(v, CultureInfo.InvariantCulture)); +#endif + writer.WriteValue(Convert.ToDateTime(v, CultureInfo.InvariantCulture)); }, _value); break; + case JTokenType.Bytes: + WriteConvertableValue(writer, converters, v => writer.WriteValue((byte[])v), _value); + break; case JTokenType.Raw: writer.WriteRawValue(_value.ToString()); break; diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj index 4e07914a..3fedf28c 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj @@ -64,7 +64,6 @@ - @@ -159,6 +158,7 @@ + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj index b8f3ec9d..325ddaca 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj @@ -54,7 +54,7 @@ 4 bin\Debug\Newtonsoft.Json.Net20.xml true - -Microsoft.Design#CA1012;-Microsoft.Design#CA2210;-Microsoft.Design#CA1040;-Microsoft.Design#CA1005;-Microsoft.Design#CA1020;-Microsoft.Design#CA1021;-Microsoft.Design#CA1010;-Microsoft.Design#CA1011;-Microsoft.Design#CA1009;-Microsoft.Design#CA1050;-Microsoft.Design#CA1026;-Microsoft.Design#CA1019;-Microsoft.Design#CA1031;-Microsoft.Design#CA1047;-Microsoft.Design#CA1000;-Microsoft.Design#CA1048;-Microsoft.Design#CA1051;-Microsoft.Design#CA1002;-Microsoft.Design#CA1061;-Microsoft.Design#CA1006;-Microsoft.Design#CA1046;-Microsoft.Design#CA1045;-Microsoft.Design#CA1065;-Microsoft.Design#CA1038;-Microsoft.Design#CA1008;-Microsoft.Design#CA1028;-Microsoft.Design#CA1064;-Microsoft.Design#CA1004;-Microsoft.Design#CA1035;-Microsoft.Design#CA1063;-Microsoft.Design#CA1032;-Microsoft.Design#CA1023;-Microsoft.Design#CA1033;-Microsoft.Design#CA1039;-Microsoft.Design#CA1016;-Microsoft.Design#CA1014;-Microsoft.Design#CA1017;-Microsoft.Design#CA1018;-Microsoft.Design#CA1027;-Microsoft.Design#CA1059;-Microsoft.Design#CA1060;-Microsoft.Design#CA1034;-Microsoft.Design#CA1013;-Microsoft.Design#CA1036;-Microsoft.Design#CA1044;-Microsoft.Design#CA1041;-Microsoft.Design#CA1025;-Microsoft.Design#CA1052;-Microsoft.Design#CA1053;-Microsoft.Design#CA1057;-Microsoft.Design#CA1058;-Microsoft.Design#CA1001;-Microsoft.Design#CA1049;-Microsoft.Design#CA1054;-Microsoft.Design#CA1056;-Microsoft.Design#CA1055;-Microsoft.Design#CA1030;-Microsoft.Design#CA1003;-Microsoft.Design#CA1007;-Microsoft.Design#CA1043;-Microsoft.Design#CA1024;-Microsoft.Globalization#CA1301;-Microsoft.Globalization#CA1302;-Microsoft.Globalization#CA1308;-Microsoft.Globalization#CA1306;-Microsoft.Globalization#CA2101;-Microsoft.Globalization#CA1300;-Microsoft.Globalization#CA1307;-Microsoft.Globalization#CA1309;-Microsoft.Interoperability#CA1403;-Microsoft.Interoperability#CA1406;-Microsoft.Interoperability#CA1413;-Microsoft.Interoperability#CA1402;-Microsoft.Interoperability#CA1407;-Microsoft.Interoperability#CA1404;-Microsoft.Interoperability#CA1410;-Microsoft.Interoperability#CA1411;-Microsoft.Interoperability#CA1405;-Microsoft.Interoperability#CA1409;-Microsoft.Interoperability#CA1415;-Microsoft.Interoperability#CA1408;-Microsoft.Interoperability#CA1414;-Microsoft.Interoperability#CA1412;-Microsoft.Interoperability#CA1400;-Microsoft.Interoperability#CA1401;-Microsoft.Maintainability#CA1506;-Microsoft.Maintainability#CA1502;-Microsoft.Maintainability#CA1501;-Microsoft.Maintainability#CA1505;-Microsoft.Maintainability#CA1504;-Microsoft.Maintainability#CA1500;-Microsoft.Mobility#CA1600;-Microsoft.Mobility#CA1601;-Microsoft.Naming#CA1702;-Microsoft.Naming#CA1700;-Microsoft.Naming#CA1712;-Microsoft.Naming#CA1713;-Microsoft.Naming#CA1714;-Microsoft.Naming#CA1709;-Microsoft.Naming#CA1704;-Microsoft.Naming#CA1708;-Microsoft.Naming#CA1715;-Microsoft.Naming#CA1710;-Microsoft.Naming#CA1720;-Microsoft.Naming#CA1707;-Microsoft.Naming#CA1722;-Microsoft.Naming#CA1711;-Microsoft.Naming#CA1716;-Microsoft.Naming#CA1717;-Microsoft.Naming#CA1725;-Microsoft.Naming#CA1719;-Microsoft.Naming#CA1721;-Microsoft.Naming#CA1701;-Microsoft.Naming#CA1703;-Microsoft.Naming#CA1724;-Microsoft.Naming#CA1726;-Microsoft.Performance#CA1809;-Microsoft.Performance#CA1811;-Microsoft.Performance#CA1812;-Microsoft.Performance#CA1813;-Microsoft.Performance#CA1823;-Microsoft.Performance#CA1800;-Microsoft.Performance#CA1805;-Microsoft.Performance#CA1810;-Microsoft.Performance#CA1824;-Microsoft.Performance#CA1822;-Microsoft.Performance#CA1815;-Microsoft.Performance#CA1814;-Microsoft.Performance#CA1819;-Microsoft.Performance#CA1821;-Microsoft.Performance#CA1804;-Microsoft.Performance#CA1820;-Microsoft.Performance#CA1802;-Microsoft.Portability#CA1901;-Microsoft.Portability#CA1900;-Microsoft.Reliability#CA2001;-Microsoft.Reliability#CA2002;-Microsoft.Reliability#CA2003;-Microsoft.Reliability#CA2004;-Microsoft.Reliability#CA2006;-Microsoft.Security#CA2116;-Microsoft.Security#CA2117;-Microsoft.Security#CA2105;-Microsoft.Security#CA2115;-Microsoft.Security#CA2102;-Microsoft.Security#CA2104;-Microsoft.Security#CA2122;-Microsoft.Security#CA2114;-Microsoft.Security#CA2123;-Microsoft.Security#CA2111;-Microsoft.Security#CA2108;-Microsoft.Security#CA2107;-Microsoft.Security#CA2103;-Microsoft.Security#CA2118;-Microsoft.Security#CA2109;-Microsoft.Security#CA2119;-Microsoft.Security#CA2106;-Microsoft.Security#CA2112;-Microsoft.Security#CA2120;-Microsoft.Security#CA2121;-Microsoft.Security#CA2126;-Microsoft.Security#CA2124;-Microsoft.Security#CA2127;-Microsoft.Security#CA2128;-Microsoft.Security#CA2129;-Microsoft.Usage#CA2243;-Microsoft.Usage#CA2236;-Microsoft.Usage#CA1816;-Microsoft.Usage#CA2227;-Microsoft.Usage#CA2213;-Microsoft.Usage#CA2216;-Microsoft.Usage#CA2214;-Microsoft.Usage#CA2222;-Microsoft.Usage#CA1806;-Microsoft.Usage#CA2217;-Microsoft.Usage#CA2212;-Microsoft.Usage#CA2219;-Microsoft.Usage#CA2201;-Microsoft.Usage#CA2228;-Microsoft.Usage#CA2221;-Microsoft.Usage#CA2220;-Microsoft.Usage#CA2240;-Microsoft.Usage#CA2229;-Microsoft.Usage#CA2238;-Microsoft.Usage#CA2207;-Microsoft.Usage#CA2208;-Microsoft.Usage#CA2235;-Microsoft.Usage#CA2237;-Microsoft.Usage#CA2232;-Microsoft.Usage#CA2223;-Microsoft.Usage#CA2211;-Microsoft.Usage#CA2233;-Microsoft.Usage#CA2225;-Microsoft.Usage#CA2226;-Microsoft.Usage#CA2231;-Microsoft.Usage#CA2224;-Microsoft.Usage#CA2218;-Microsoft.Usage#CA2234;-Microsoft.Usage#CA2239;-Microsoft.Usage#CA2200;-Microsoft.Usage#CA1801;-Microsoft.Usage#CA2242;-Microsoft.Usage#CA2205;-Microsoft.Usage#CA2230 + -Microsoft.Design#CA1012;-Microsoft.Design#CA2210;-Microsoft.Design#CA1040;-Microsoft.Design#CA1005;-Microsoft.Design#CA1020;-Microsoft.Design#CA1021;-Microsoft.Design#CA1010;-Microsoft.Design#CA1011;-Microsoft.Design#CA1009;-Microsoft.Design#CA1050;-Microsoft.Design#CA1026;-Microsoft.Design#CA1019;-Microsoft.Design#CA1031;-Microsoft.Design#CA1047;-Microsoft.Design#CA1000;-Microsoft.Design#CA1048;-Microsoft.Design#CA1051;-Microsoft.Design#CA1002;-Microsoft.Design#CA1061;-Microsoft.Design#CA1006;-Microsoft.Design#CA1046;-Microsoft.Design#CA1045;-Microsoft.Design#CA1065;-Microsoft.Design#CA1038;-Microsoft.Design#CA1008;-Microsoft.Design#CA1028;-Microsoft.Design#CA1064;-Microsoft.Design#CA1004;-Microsoft.Design#CA1035;-Microsoft.Design#CA1063;-Microsoft.Design#CA1032;-Microsoft.Design#CA1023;-Microsoft.Design#CA1033;-Microsoft.Design#CA1039;-Microsoft.Design#CA1016;-Microsoft.Design#CA1014;-Microsoft.Design#CA1017;-Microsoft.Design#CA1018;-Microsoft.Design#CA1027;-Microsoft.Design#CA1059;-Microsoft.Design#CA1060;-Microsoft.Design#CA1034;-Microsoft.Design#CA1013;-Microsoft.Design#CA1036;-Microsoft.Design#CA1044;-Microsoft.Design#CA1041;-Microsoft.Design#CA1025;-Microsoft.Design#CA1052;-Microsoft.Design#CA1053;-Microsoft.Design#CA1057;-Microsoft.Design#CA1058;-Microsoft.Design#CA1001;-Microsoft.Design#CA1049;-Microsoft.Design#CA1054;-Microsoft.Design#CA1056;-Microsoft.Design#CA1055;-Microsoft.Design#CA1030;-Microsoft.Design#CA1003;-Microsoft.Design#CA1007;-Microsoft.Design#CA1043;-Microsoft.Design#CA1024;-Microsoft.Globalization#CA1301;-Microsoft.Globalization#CA1302;-Microsoft.Globalization#CA1308;-Microsoft.Globalization#CA1306;-Microsoft.Globalization#CA2101;-Microsoft.Globalization#CA1300;-Microsoft.Globalization#CA1307;-Microsoft.Globalization#CA1309;-Microsoft.Interoperability#CA1403;-Microsoft.Interoperability#CA1406;-Microsoft.Interoperability#CA1413;-Microsoft.Interoperability#CA1402;-Microsoft.Interoperability#CA1407;-Microsoft.Interoperability#CA1404;-Microsoft.Interoperability#CA1410;-Microsoft.Interoperability#CA1411;-Microsoft.Interoperability#CA1405;-Microsoft.Interoperability#CA1409;-Microsoft.Interoperability#CA1415;-Microsoft.Interoperability#CA1408;-Microsoft.Interoperability#CA1414;-Microsoft.Interoperability#CA1412;-Microsoft.Interoperability#CA1400;-Microsoft.Interoperability#CA1401;-Microsoft.Maintainability#CA1506;-Microsoft.Maintainability#CA1502;-Microsoft.Maintainability#CA1501;-Microsoft.Maintainability#CA1505;-Microsoft.Maintainability#CA1504;-Microsoft.Maintainability#CA1500;-Microsoft.Mobility#CA1600;-Microsoft.Mobility#CA1601;-Microsoft.Naming#CA1702;-Microsoft.Naming#CA1700;-Microsoft.Naming#CA1712;-Microsoft.Naming#CA1713;-Microsoft.Naming#CA1714;-Microsoft.Naming#CA1709;-Microsoft.Naming#CA1704;-Microsoft.Naming#CA1708;-Microsoft.Naming#CA1715;-Microsoft.Naming#CA1710;-Microsoft.Naming#CA1720;-Microsoft.Naming#CA1707;-Microsoft.Naming#CA1722;-Microsoft.Naming#CA1711;-Microsoft.Naming#CA1716;-Microsoft.Naming#CA1717;-Microsoft.Naming#CA1725;-Microsoft.Naming#CA1719;-Microsoft.Naming#CA1721;-Microsoft.Naming#CA1701;-Microsoft.Naming#CA1703;-Microsoft.Naming#CA1724;-Microsoft.Naming#CA1726;-Microsoft.Performance#CA1809;-Microsoft.Performance#CA1811;-Microsoft.Performance#CA1812;-Microsoft.Performance#CA1813;-Microsoft.Performance#CA1823;-Microsoft.Performance#CA1800;-Microsoft.Performance#CA1805;-Microsoft.Performance#CA1810;-Microsoft.Performance#CA1824;-Microsoft.Performance#CA1822;-Microsoft.Performance#CA1815;-Microsoft.Performance#CA1814;-Microsoft.Performance#CA1819;-Microsoft.Performance#CA1821;-Microsoft.Performance#CA1804;-Microsoft.Performance#CA1820;-Microsoft.Performance#CA1802;+!Microsoft.Portability#CA1903;-Microsoft.Portability#CA1901;-Microsoft.Portability#CA1900;-Microsoft.Reliability#CA2001;-Microsoft.Reliability#CA2002;-Microsoft.Reliability#CA2003;-Microsoft.Reliability#CA2004;-Microsoft.Reliability#CA2006;-Microsoft.Security#CA2116;-Microsoft.Security#CA2117;-Microsoft.Security#CA2105;-Microsoft.Security#CA2115;-Microsoft.Security#CA2102;-Microsoft.Security#CA2104;-Microsoft.Security#CA2122;-Microsoft.Security#CA2114;-Microsoft.Security#CA2123;-Microsoft.Security#CA2111;-Microsoft.Security#CA2108;-Microsoft.Security#CA2107;-Microsoft.Security#CA2103;-Microsoft.Security#CA2118;-Microsoft.Security#CA2109;-Microsoft.Security#CA2119;-Microsoft.Security#CA2106;-Microsoft.Security#CA2112;-Microsoft.Security#CA2120;-Microsoft.Security#CA2121;-Microsoft.Security#CA2126;-Microsoft.Security#CA2124;-Microsoft.Security#CA2127;-Microsoft.Security#CA2128;-Microsoft.Security#CA2129;-Microsoft.Usage#CA2243;-Microsoft.Usage#CA2236;-Microsoft.Usage#CA1816;-Microsoft.Usage#CA2227;-Microsoft.Usage#CA2213;-Microsoft.Usage#CA2216;-Microsoft.Usage#CA2214;-Microsoft.Usage#CA2222;-Microsoft.Usage#CA1806;-Microsoft.Usage#CA2217;-Microsoft.Usage#CA2212;-Microsoft.Usage#CA2219;-Microsoft.Usage#CA2201;-Microsoft.Usage#CA2228;-Microsoft.Usage#CA2221;-Microsoft.Usage#CA2220;-Microsoft.Usage#CA2240;-Microsoft.Usage#CA2229;-Microsoft.Usage#CA2238;-Microsoft.Usage#CA2207;-Microsoft.Usage#CA2208;-Microsoft.Usage#CA2235;-Microsoft.Usage#CA2237;-Microsoft.Usage#CA2232;-Microsoft.Usage#CA2223;-Microsoft.Usage#CA2211;-Microsoft.Usage#CA2233;-Microsoft.Usage#CA2225;-Microsoft.Usage#CA2226;-Microsoft.Usage#CA2231;-Microsoft.Usage#CA2224;-Microsoft.Usage#CA2218;-Microsoft.Usage#CA2234;-Microsoft.Usage#CA2239;-Microsoft.Usage#CA2200;-Microsoft.Usage#CA1801;-Microsoft.Usage#CA2242;-Microsoft.Usage#CA2205;-Microsoft.Usage#CA2230 pdbonly @@ -175,6 +175,7 @@ + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj index f5c4a81b..0de29b41 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj @@ -66,7 +66,6 @@ - @@ -142,6 +141,7 @@ + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj index 21868f08..f81607fa 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj @@ -65,9 +65,6 @@ - - 3.5 - 3.5 @@ -80,6 +77,10 @@ + + + + @@ -178,6 +179,7 @@ + diff --git a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs index a1eda08c..18473197 100644 --- a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs +++ b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs @@ -193,6 +193,8 @@ namespace Newtonsoft.Json.Serialization foreach (MethodInfo method in contract.UnderlyingType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)) { + // compact framework errors when getting parameters for a generic method + // lame, but generic methods should not be callbacks anyway if (method.ContainsGenericParameters) continue; @@ -348,7 +350,7 @@ namespace Newtonsoft.Json.Serialization #else property.ValueProvider = new ReflectionValueProvider(member); #endif - property.Converter = JsonTypeReflector.GetConverter(member, property.PropertyType); + property.Converter = JsonTypeReflector.GetJsonConverter(member, property.PropertyType); #if !PocketPC && !NET20 DataContractAttribute dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(member.DeclaringType); @@ -395,7 +397,7 @@ namespace Newtonsoft.Json.Serialization property.Readable = ReflectionUtils.CanReadMemberValue(member); property.Writable = ReflectionUtils.CanSetMemberValue(member); - property.MemberConverter = JsonTypeReflector.GetConverter(member, ReflectionUtils.GetMemberUnderlyingType(member)); + property.MemberConverter = JsonTypeReflector.GetJsonConverter(member, ReflectionUtils.GetMemberUnderlyingType(member)); DefaultValueAttribute defaultValueAttribute = JsonTypeReflector.GetAttribute(member); property.DefaultValue = (defaultValueAttribute != null) ? defaultValueAttribute.Value : null; diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs index 5b14a2de..cf7eddc3 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs @@ -168,6 +168,7 @@ namespace Newtonsoft.Json.Serialization case JsonToken.Float: case JsonToken.Boolean: case JsonToken.Date: + case JsonToken.Bytes: return EnsureType(reader.Value, objectType); case JsonToken.String: // convert empty string to null automatically for nullable types @@ -382,24 +383,6 @@ namespace Newtonsoft.Json.Serialization return value.ToString(); } - private void SetObjectMember(JsonReader reader, object target, JsonObjectContract contract, string memberName) - { - JsonProperty property; - // attempt exact case match first - // then try match ignoring case - if (contract.Properties.TryGetClosestMatchProperty(memberName, out property)) - { - SetPropertyValue(property, reader, target); - } - else - { - if (Serializer.MissingMemberHandling == MissingMemberHandling.Error) - throw new JsonSerializationException("Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, contract.UnderlyingType.Name)); - - reader.Skip(); - } - } - private void SetPropertyValue(JsonProperty property, JsonReader reader, object target) { if (property.Ignored) @@ -431,7 +414,11 @@ namespace Newtonsoft.Json.Serialization object value = CreateValue(reader, property.PropertyType, (useExistingValue) ? currentValue : null, property.Converter); - if (!useExistingValue && ShouldSetPropertyValue(property, value)) + // always set the value if useExistingValue is false, + // otherwise also set it if CreateValue returns a new value compared to the currentValue + // this could happen because of a JsonConverter against the type + if ((!useExistingValue || value != currentValue) + && ShouldSetPropertyValue(property, value)) property.ValueProvider.SetValue(target, value); } @@ -679,14 +666,34 @@ namespace Newtonsoft.Json.Serialization case JsonToken.PropertyName: string memberName = reader.Value.ToString(); - if (!reader.Read()) - throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); + JsonProperty property; + // attempt exact case match first + // then try match ignoring case + if (!contract.Properties.TryGetClosestMatchProperty(memberName, out property)) + { + if (Serializer.MissingMemberHandling == MissingMemberHandling.Error) + throw new JsonSerializationException("Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, contract.UnderlyingType.Name)); - SetRequiredProperty(reader, memberName, contract, requiredProperties); + reader.Skip(); + continue; + } + + if (property.PropertyType == typeof(byte[])) + { + reader.ReadAsBytes(); + } + else + { + if (!reader.Read()) + throw new JsonSerializationException( + "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); + } + + SetRequiredProperty(reader, property, requiredProperties); try { - SetObjectMember(reader, newObject, contract, memberName); + SetPropertyValue(property, reader, newObject); } catch (Exception ex) { @@ -718,9 +725,8 @@ namespace Newtonsoft.Json.Serialization throw new JsonSerializationException("Unexpected end when deserializing object."); } - private void SetRequiredProperty(JsonReader reader, string memberName, JsonObjectContract contract, Dictionary requiredProperties) + private void SetRequiredProperty(JsonReader reader, JsonProperty property, Dictionary requiredProperties) { - JsonProperty property = requiredProperties.Keys.ForgivingCaseSensitiveFind(p => p.PropertyName, memberName); if (property != null) { requiredProperties[property] = (reader.TokenType == JsonToken.Null || reader.TokenType == JsonToken.Undefined) diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs index fc07969c..e47d6517 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs @@ -226,19 +226,29 @@ namespace Newtonsoft.Json.Serialization internal static bool TryConvertToString(object value, Type type, out string s) { -#if !SILVERLIGHT && !PocketPC - TypeConverter converter = TypeDescriptor.GetConverter(type); +#if !PocketPC + TypeConverter converter = ConvertUtils.GetConverter(type); // 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) || value is Type)) + if (converter != null +#if !SILVERLIGHT + && !(converter is ComponentConverter) +#endif + && (converter.GetType() != typeof(TypeConverter) || value is Type)) { if (converter.CanConvertTo(typeof(string))) { +#if !SILVERLIGHT s = converter.ConvertToInvariantString(value); +#else + s = converter.ConvertToString(value); +#endif return true; } } -#else +#endif + +#if SILVERLIGHT || PocketPC if (value is Guid || value is Type || value is Uri || value is TimeSpan) { s = value.ToString(); diff --git a/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs b/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs index 6694d52d..04882bd7 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs @@ -24,9 +24,7 @@ #endregion using System; -#if !SILVERLIGHT && !PocketPC && !NET20 -using System.ComponentModel.DataAnnotations; -#endif +using System.ComponentModel; using System.Globalization; using System.Linq; using System.Reflection; @@ -35,6 +33,13 @@ using Newtonsoft.Json.Utilities; namespace Newtonsoft.Json.Serialization { +#if !SILVERLIGHT && !PocketPC && !NET20 + internal interface IMetadataTypeAttribute + { + Type MetadataClassType { get; } + } +#endif + internal static class JsonTypeReflector { public const string IdPropertyName = "$id"; @@ -42,9 +47,30 @@ namespace Newtonsoft.Json.Serialization public const string TypePropertyName = "$type"; public const string ArrayValuesPropertyName = "$values"; - private static readonly ThreadSafeStore ConverterTypeCache = new ThreadSafeStore(GetConverterTypeFromAttribute); + private static readonly ThreadSafeStore JsonConverterTypeCache = new ThreadSafeStore(GetJsonConverterTypeFromAttribute); #if !SILVERLIGHT && !PocketPC && !NET20 private static readonly ThreadSafeStore AssociatedMetadataTypesCache = new ThreadSafeStore(GetAssociateMetadataTypeFromAttribute); + + private const string MetadataTypeAttributeTypeName = + "System.ComponentModel.DataAnnotations.MetadataTypeAttribute, System.ComponentModel.DataAnnotations, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; + private static Type _cachedMetadataTypeAttributeType; +#endif +#if SILVERLIGHT + private static readonly ThreadSafeStore TypeConverterTypeCache = new ThreadSafeStore(GetTypeConverterTypeFromAttribute); + + private static Type GetTypeConverterTypeFromAttribute(ICustomAttributeProvider attributeProvider) + { + TypeConverterAttribute converterAttribute = GetAttribute(attributeProvider); + if (converterAttribute == null) + return null; + + return Type.GetType(converterAttribute.ConverterTypeName); + } + + private static Type GetTypeConverterType(ICustomAttributeProvider attributeProvider) + { + return TypeConverterTypeCache.Get(attributeProvider); + } #endif public static JsonContainerAttribute GetJsonContainerAttribute(Type type) @@ -83,12 +109,12 @@ namespace Newtonsoft.Json.Serialization return objectAttribute.MemberSerialization; } - private static Type GetConverterType(ICustomAttributeProvider attributeProvider) + private static Type GetJsonConverterType(ICustomAttributeProvider attributeProvider) { - return ConverterTypeCache.Get(attributeProvider); + return JsonConverterTypeCache.Get(attributeProvider); } - private static Type GetConverterTypeFromAttribute(ICustomAttributeProvider attributeProvider) + private static Type GetJsonConverterTypeFromAttribute(ICustomAttributeProvider attributeProvider) { JsonConverterAttribute converterAttribute = GetAttribute(attributeProvider); return (converterAttribute != null) @@ -96,9 +122,9 @@ namespace Newtonsoft.Json.Serialization : null; } - public static JsonConverter GetConverter(ICustomAttributeProvider attributeProvider, Type targetConvertedType) + public static JsonConverter GetJsonConverter(ICustomAttributeProvider attributeProvider, Type targetConvertedType) { - Type converterType = GetConverterType(attributeProvider); + Type converterType = GetJsonConverterType(attributeProvider); if (converterType != null) { @@ -113,6 +139,22 @@ namespace Newtonsoft.Json.Serialization return null; } +#if !PocketPC + public static TypeConverter GetTypeConverter(Type type) + { +#if !SILVERLIGHT + return TypeDescriptor.GetConverter(type); +#else + Type converterType = GetTypeConverterType(type); + + if (converterType != null) + return (TypeConverter)ReflectionUtils.CreateInstance(converterType); + + return null; +#endif + } +#endif + #if !SILVERLIGHT && !PocketPC && !NET20 private static Type GetAssociatedMetadataType(Type type) { @@ -121,9 +163,34 @@ namespace Newtonsoft.Json.Serialization private static Type GetAssociateMetadataTypeFromAttribute(Type type) { - MetadataTypeAttribute metadataTypeAttribute = ReflectionUtils.GetAttribute(type, true); + Type metadataTypeAttributeType = GetMetadataTypeAttributeType(); + if (metadataTypeAttributeType == null) + return null; - return (metadataTypeAttribute != null) ? metadataTypeAttribute.MetadataClassType : null; + object attribute = type.GetCustomAttributes(metadataTypeAttributeType, true).SingleOrDefault(); + if (attribute == null) + return null; + + IMetadataTypeAttribute metadataTypeAttribute = DynamicWrapper.CreateWrapper(attribute); + + return metadataTypeAttribute.MetadataClassType; + } + + private static Type GetMetadataTypeAttributeType() + { + // always attempt to get the metadata type attribute type + // the assembly may have been loaded since last time + if (_cachedMetadataTypeAttributeType == null) + { + Type metadataTypeAttributeType = Type.GetType(MetadataTypeAttributeTypeName); + + if (metadataTypeAttributeType != null) + _cachedMetadataTypeAttributeType = metadataTypeAttributeType; + else + return null; + } + + return _cachedMetadataTypeAttributeType; } private static T GetAttribute(Type type) where T : Attribute @@ -169,7 +236,5 @@ namespace Newtonsoft.Json.Serialization return ReflectionUtils.GetAttribute(attributeProvider, true); } #endif - - } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/Base64Encoder.cs b/Src/Newtonsoft.Json/Utilities/Base64Encoder.cs new file mode 100644 index 00000000..2a1d86a1 --- /dev/null +++ b/Src/Newtonsoft.Json/Utilities/Base64Encoder.cs @@ -0,0 +1,95 @@ +using System; +using System.IO; + +namespace Newtonsoft.Json.Utilities +{ + internal class Base64Encoder + { + private const int Base64LineSize = 76; + private const int LineSizeInBytes = 57; + + private readonly char[] _charsLine = new char[Base64LineSize]; + private readonly TextWriter _writer; + + private byte[] _leftOverBytes; + private int _leftOverBytesCount; + + public Base64Encoder(TextWriter writer) + { + ValidationUtils.ArgumentNotNull(writer, "writer"); + _writer = writer; + } + + public void Encode(byte[] buffer, int index, int count) + { + if (buffer == null) + throw new ArgumentNullException("buffer"); + + if (index < 0) + throw new ArgumentOutOfRangeException("index"); + + if (count < 0) + throw new ArgumentOutOfRangeException("count"); + + if (count > (buffer.Length - index)) + throw new ArgumentOutOfRangeException("count"); + + if (_leftOverBytesCount > 0) + { + int leftOverBytesCount = _leftOverBytesCount; + while (leftOverBytesCount < 3 && count > 0) + { + _leftOverBytes[leftOverBytesCount++] = buffer[index++]; + count--; + } + if (count == 0 && leftOverBytesCount < 3) + { + _leftOverBytesCount = leftOverBytesCount; + return; + } + int num2 = Convert.ToBase64CharArray(_leftOverBytes, 0, 3, _charsLine, 0); + WriteChars(_charsLine, 0, num2); + } + _leftOverBytesCount = count % 3; + if (_leftOverBytesCount > 0) + { + count -= _leftOverBytesCount; + if (_leftOverBytes == null) + { + _leftOverBytes = new byte[3]; + } + for (int i = 0; i < _leftOverBytesCount; i++) + { + _leftOverBytes[i] = buffer[(index + count) + i]; + } + } + int num4 = index + count; + int length = LineSizeInBytes; + while (index < num4) + { + if ((index + length) > num4) + { + length = num4 - index; + } + int num6 = Convert.ToBase64CharArray(buffer, index, length, _charsLine, 0); + WriteChars(_charsLine, 0, num6); + index += length; + } + } + + public void Flush() + { + if (_leftOverBytesCount > 0) + { + int count = Convert.ToBase64CharArray(_leftOverBytes, 0, _leftOverBytesCount, _charsLine, 0); + WriteChars(_charsLine, 0, count); + _leftOverBytesCount = 0; + } + } + + private void WriteChars(char[] chars, int index, int count) + { + _writer.Write(chars, index, count); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs b/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs index 2486328e..9bb213a1 100644 --- a/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs @@ -29,6 +29,8 @@ using System.Linq; using System.Text; using System.Globalization; using System.ComponentModel; +using Newtonsoft.Json.Serialization; + #if !SILVERLIGHT using System.Data.SqlTypes; #endif @@ -53,8 +55,10 @@ namespace Newtonsoft.Json.Utilities return true; } +#if !PocketPC && !NET20 if (initialType == typeof(DateTime) && targetType == typeof(DateTimeOffset)) return true; +#endif if (initialType == typeof(Guid) && (targetType == typeof(Guid) || targetType == typeof(string))) return true; @@ -161,8 +165,10 @@ namespace Newtonsoft.Json.Utilities return System.Convert.ChangeType(initialValue, targetType, culture); } +#if !PocketPC && !NET20 if (initialValue is DateTime && targetType == typeof(DateTimeOffset)) return new DateTimeOffset((DateTime)initialValue); +#endif if (initialValue is string) { @@ -403,20 +409,9 @@ namespace Newtonsoft.Json.Utilities #endif #if !PocketPC - private static TypeConverter GetConverter(Type t) + internal static TypeConverter GetConverter(Type t) { - ValidationUtils.ArgumentNotNull(t, "t"); - -#if !SILVERLIGHT - return TypeDescriptor.GetConverter(t); -#else - object[] customAttributes = t.GetCustomAttributes(typeof(TypeConverterAttribute), true); - if (customAttributes.Length != 1) - return null; - - TypeConverterAttribute typeConverterAttribute = (TypeConverterAttribute)customAttributes[0]; - return (Activator.CreateInstance(Type.GetType(typeConverterAttribute.ConverterTypeName)) as TypeConverter); -#endif + return JsonTypeReflector.GetTypeConverter(t); } #endif diff --git a/Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs b/Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs index 71ae1706..108cecd1 100644 --- a/Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs @@ -42,5 +42,61 @@ namespace Newtonsoft.Json.Utilities return (value is string) ? @"""" + value.ToString() + @"""" : value.ToString(); } + + public static byte[] HexToBytes(string hex) + { + // array to put the result in + byte[] bytes = new byte[hex.Length / 2]; + // variable to determine shift of high/low nibble + int shift = 4; + // offset of the current byte in the array + int offset = 0; + // loop the characters in the string + foreach (char c in hex) + { + if (c == '-' && shift == 4) + continue; + + // get character code in range 0-9, 17-22 + // the % 32 handles lower case characters + int b = (c - '0') % 32; + // correction for a-f + if (b > 9) b -= 7; + // store nibble (4 bits) in byte array + bytes[offset] |= (byte)(b << shift); + // toggle the shift variable between 0 and 4 + shift ^= 4; + // move to next byte + if (shift != 0) offset++; + } + return bytes; + } + + public static string BytesToHex(byte[] bytes) + { + return BytesToHex(bytes, false); + } + + public static string BytesToHex(byte[] bytes, bool removeDashes) + { + string hex = BitConverter.ToString(bytes); + if (removeDashes) + hex = hex.Replace("-", ""); + + return hex; + } + + public static bool ByteArrayCompare(byte[] a1, byte[] a2) + { + if (a1.Length != a2.Length) + return false; + + for (int i = 0; i < a1.Length; i++) + if (a1[i] != a2[i]) + return false; + + return true; + } + } -} +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/StringBuffer.cs b/Src/Newtonsoft.Json/Utilities/StringBuffer.cs index b458f397..22897f40 100644 --- a/Src/Newtonsoft.Json/Utilities/StringBuffer.cs +++ b/Src/Newtonsoft.Json/Utilities/StringBuffer.cs @@ -90,5 +90,10 @@ namespace Newtonsoft.Json.Utilities // TODO: validation return new string(_buffer, start, length); } + + public char[] GetInternalBuffer() + { + return _buffer; + } } } \ No newline at end of file