From a06716c6a6ee55c966494f54d6dd67bf425802f3 Mon Sep 17 00:00:00 2001 From: Jon Hanna Date: Sat, 19 Dec 2015 23:40:56 +0000 Subject: [PATCH] Refactor some cases of repeated code into separate methods. Make the MoveToContent() and ReadToContent() produced from this public. --- .../DiscriminatedUnionConverterTests.cs | 2 +- .../Converters/JsonValueConverterTests.cs | 6 +- .../Converters/KeyValuePairConverterTests.cs | 2 +- .../PreserveReferencesHandlingTests.cs | 2 +- .../Converters/DataSetConverter.cs | 12 +- .../Converters/DataTableConverter.cs | 30 +- .../Converters/DiscriminatedUnionConverter.cs | 16 +- .../Converters/EntityKeyMemberConverter.cs | 18 +- .../Converters/ExpandoObjectConverter.cs | 7 +- .../Converters/KeyValuePairConverter.cs | 16 +- Src/Newtonsoft.Json/JsonReader.cs | 554 ++++++++---------- Src/Newtonsoft.Json/JsonTextReader.cs | 2 +- Src/Newtonsoft.Json/Linq/JArray.cs | 5 +- Src/Newtonsoft.Json/Linq/JConstructor.cs | 5 +- Src/Newtonsoft.Json/Linq/JObject.cs | 5 +- Src/Newtonsoft.Json/Linq/JProperty.cs | 5 +- Src/Newtonsoft.Json/Linq/JToken.cs | 83 ++- .../JsonSerializerInternalReader.cs | 84 +-- 18 files changed, 351 insertions(+), 503 deletions(-) diff --git a/Src/Newtonsoft.Json.Tests/Converters/DiscriminatedUnionConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/DiscriminatedUnionConverterTests.cs index a34249e7..fb0c7051 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/DiscriminatedUnionConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/DiscriminatedUnionConverterTests.cs @@ -264,7 +264,7 @@ namespace Newtonsoft.Json.Tests.Converters [Test] public void DeserializeBasicUnion_UnexpectedEnd() { - ExceptionAssert.Throws(() => JsonConvert.DeserializeObject(@"{""Case"":"), "Unexpected end when reading union. Path 'Case', line 1, position 8."); + ExceptionAssert.Throws(() => JsonConvert.DeserializeObject(@"{""Case"":"), "Unexpected end when reading JSON. Path 'Case', line 1, position 8."); } [Test] diff --git a/Src/Newtonsoft.Json.Tests/Converters/JsonValueConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/JsonValueConverterTests.cs index 718ae61f..b6b28b17 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/JsonValueConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/JsonValueConverterTests.cs @@ -158,7 +158,7 @@ namespace Newtonsoft.Json.Tests.Converters ExceptionAssert.Throws(() => { converter.ReadJson(writer, typeof (JsonValue), null, null); - }, "Unexpected end. Path '', line 1, position 1."); + }, "Unexpected end when reading JSON. Path '', line 1, position 1."); } [Test] @@ -173,7 +173,7 @@ namespace Newtonsoft.Json.Tests.Converters ExceptionAssert.Throws(() => { converter.ReadJson(writer, typeof (JsonValue), null, null); - }, "Unexpected end. Path '', line 1, position 13."); + }, "Unexpected end when reading JSON. Path '', line 1, position 13."); } [Test] @@ -188,7 +188,7 @@ namespace Newtonsoft.Json.Tests.Converters ExceptionAssert.Throws(() => { converter.ReadJson(writer, typeof (JsonValue), null, null); - }, "Unexpected end. Path 'hi', line 1, position 6."); + }, "Unexpected end when reading JSON. Path 'hi', line 1, position 6."); } [Test] diff --git a/Src/Newtonsoft.Json.Tests/Converters/KeyValuePairConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/KeyValuePairConverterTests.cs index 47e6f203..83a10171 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/KeyValuePairConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/KeyValuePairConverterTests.cs @@ -60,7 +60,7 @@ namespace Newtonsoft.Json.Tests.Converters [Test] public void DeserializeUnexpectedEnd() { - ExceptionAssert.Throws(() => JsonConvert.DeserializeObject>(@"{""Key"": ""123"","), "Unexpected end when reading KeyValuePair. Path 'Key', line 1, position 14."); + ExceptionAssert.Throws(() => JsonConvert.DeserializeObject>(@"{""Key"": ""123"","), "Unexpected end when reading JSON. Path 'Key', line 1, position 14."); } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Serialization/PreserveReferencesHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/PreserveReferencesHandlingTests.cs index ffe6609d..05e60f04 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/PreserveReferencesHandlingTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/PreserveReferencesHandlingTests.cs @@ -479,7 +479,7 @@ namespace Newtonsoft.Json.Tests.Serialization PreserveReferencesHandling = PreserveReferencesHandling.All, MetadataPropertyHandling = MetadataPropertyHandling.Default }); - }, @"Unexpected end when deserializing object. Path '$id', line 2, position 8."); + }, @"Unexpected end when reading JSON. Path '$id', line 2, position 8."); } public class CircularReferenceClassConverter : JsonConverter diff --git a/Src/Newtonsoft.Json/Converters/DataSetConverter.cs b/Src/Newtonsoft.Json/Converters/DataSetConverter.cs index 9f9b823d..5c86e827 100644 --- a/Src/Newtonsoft.Json/Converters/DataSetConverter.cs +++ b/Src/Newtonsoft.Json/Converters/DataSetConverter.cs @@ -82,7 +82,7 @@ namespace Newtonsoft.Json.Converters DataTableConverter converter = new DataTableConverter(); - CheckedRead(reader); + reader.ReadAndAssert(); while (reader.TokenType == JsonToken.PropertyName) { @@ -96,7 +96,7 @@ namespace Newtonsoft.Json.Converters ds.Tables.Add(dt); } - CheckedRead(reader); + reader.ReadAndAssert(); } return ds; @@ -113,14 +113,6 @@ namespace Newtonsoft.Json.Converters { return typeof(DataSet).IsAssignableFrom(valueType); } - - private void CheckedRead(JsonReader reader) - { - if (!reader.Read()) - { - throw JsonSerializationException.Create(reader, "Unexpected end when reading DataSet."); - } - } } } diff --git a/Src/Newtonsoft.Json/Converters/DataTableConverter.cs b/Src/Newtonsoft.Json/Converters/DataTableConverter.cs index 6749c131..b2f775a8 100644 --- a/Src/Newtonsoft.Json/Converters/DataTableConverter.cs +++ b/Src/Newtonsoft.Json/Converters/DataTableConverter.cs @@ -103,7 +103,7 @@ namespace Newtonsoft.Json.Converters { dt.TableName = (string)reader.Value; - CheckedRead(reader); + reader.ReadAndAssert(); if (reader.TokenType == JsonToken.Null) { @@ -116,13 +116,13 @@ namespace Newtonsoft.Json.Converters throw JsonSerializationException.Create(reader, "Unexpected JSON token when reading DataTable. Expected StartArray, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); } - CheckedRead(reader); + reader.ReadAndAssert(); while (reader.TokenType != JsonToken.EndArray) { CreateRow(reader, dt, serializer); - CheckedRead(reader); + reader.ReadAndAssert(); } return dt; @@ -131,13 +131,13 @@ namespace Newtonsoft.Json.Converters private static void CreateRow(JsonReader reader, DataTable dt, JsonSerializer serializer) { DataRow dr = dt.NewRow(); - CheckedRead(reader); + reader.ReadAndAssert(); while (reader.TokenType == JsonToken.PropertyName) { string columnName = (string)reader.Value; - CheckedRead(reader); + reader.ReadAndAssert(); DataColumn column = dt.Columns[columnName]; if (column == null) @@ -151,7 +151,7 @@ namespace Newtonsoft.Json.Converters { if (reader.TokenType == JsonToken.StartArray) { - CheckedRead(reader); + reader.ReadAndAssert(); } DataTable nestedDt = new DataTable(); @@ -160,7 +160,7 @@ namespace Newtonsoft.Json.Converters { CreateRow(reader, nestedDt, serializer); - CheckedRead(reader); + reader.ReadAndAssert(); } dr[columnName] = nestedDt; @@ -169,7 +169,7 @@ namespace Newtonsoft.Json.Converters { if (reader.TokenType == JsonToken.StartArray) { - CheckedRead(reader); + reader.ReadAndAssert(); } List o = new List(); @@ -177,7 +177,7 @@ namespace Newtonsoft.Json.Converters while (reader.TokenType != JsonToken.EndArray) { o.Add(reader.Value); - CheckedRead(reader); + reader.ReadAndAssert(); } Array destinationArray = Array.CreateInstance(column.DataType.GetElementType(), o.Count); @@ -190,7 +190,7 @@ namespace Newtonsoft.Json.Converters dr[columnName] = (reader.Value != null) ? serializer.Deserialize(reader, column.DataType) : DBNull.Value; } - CheckedRead(reader); + reader.ReadAndAssert(); } dr.EndEdit(); @@ -214,7 +214,7 @@ namespace Newtonsoft.Json.Converters case JsonToken.Undefined: return typeof(string); case JsonToken.StartArray: - CheckedRead(reader); + reader.ReadAndAssert(); if (reader.TokenType == JsonToken.StartObject) { return typeof(DataTable); // nested datatable @@ -227,14 +227,6 @@ namespace Newtonsoft.Json.Converters } } - private static void CheckedRead(JsonReader reader) - { - if (!reader.Read()) - { - throw JsonSerializationException.Create(reader, "Unexpected end when reading DataTable."); - } - } - /// /// Determines whether this instance can convert the specified value type. /// diff --git a/Src/Newtonsoft.Json/Converters/DiscriminatedUnionConverter.cs b/Src/Newtonsoft.Json/Converters/DiscriminatedUnionConverter.cs index 8876243b..bffaba88 100644 --- a/Src/Newtonsoft.Json/Converters/DiscriminatedUnionConverter.cs +++ b/Src/Newtonsoft.Json/Converters/DiscriminatedUnionConverter.cs @@ -160,14 +160,14 @@ namespace Newtonsoft.Json.Converters JArray fields = null; // start object - ReadAndAssert(reader); + reader.ReadAndAssert(); while (reader.TokenType == JsonToken.PropertyName) { string propertyName = reader.Value.ToString(); if (string.Equals(propertyName, CasePropertyName, StringComparison.OrdinalIgnoreCase)) { - ReadAndAssert(reader); + reader.ReadAndAssert(); Union union = UnionCache.Get(objectType); @@ -182,7 +182,7 @@ namespace Newtonsoft.Json.Converters } else if (string.Equals(propertyName, FieldsPropertyName, StringComparison.OrdinalIgnoreCase)) { - ReadAndAssert(reader); + reader.ReadAndAssert(); if (reader.TokenType != JsonToken.StartArray) { throw JsonSerializationException.Create(reader, "Union fields must been an array."); @@ -195,7 +195,7 @@ namespace Newtonsoft.Json.Converters throw JsonSerializationException.Create(reader, "Unexpected property '{0}' found when reading union.".FormatWith(CultureInfo.InvariantCulture, propertyName)); } - ReadAndAssert(reader); + reader.ReadAndAssert(); } if (caseInfo == null) @@ -274,14 +274,6 @@ namespace Newtonsoft.Json.Converters return (bool)FSharpUtils.IsUnion(null, objectType, null); } - - private static void ReadAndAssert(JsonReader reader) - { - if (!reader.Read()) - { - throw JsonSerializationException.Create(reader, "Unexpected end when reading union."); - } - } } } diff --git a/Src/Newtonsoft.Json/Converters/EntityKeyMemberConverter.cs b/Src/Newtonsoft.Json/Converters/EntityKeyMemberConverter.cs index 964f727f..87250d84 100644 --- a/Src/Newtonsoft.Json/Converters/EntityKeyMemberConverter.cs +++ b/Src/Newtonsoft.Json/Converters/EntityKeyMemberConverter.cs @@ -91,7 +91,7 @@ namespace Newtonsoft.Json.Converters private static void ReadAndAssertProperty(JsonReader reader, string propertyName) { - ReadAndAssert(reader); + reader.ReadAndAssert(); if (reader.TokenType != JsonToken.PropertyName || !string.Equals(reader.Value.ToString(), propertyName, StringComparison.OrdinalIgnoreCase)) { @@ -99,14 +99,6 @@ namespace Newtonsoft.Json.Converters } } - private static void ReadAndAssert(JsonReader reader) - { - if (!reader.Read()) - { - throw new JsonSerializationException("Unexpected end."); - } - } - /// /// Reads the JSON representation of the object. /// @@ -122,20 +114,20 @@ namespace Newtonsoft.Json.Converters object entityKeyMember = _reflectionObject.Creator(); ReadAndAssertProperty(reader, KeyPropertyName); - ReadAndAssert(reader); + reader.ReadAndAssert(); _reflectionObject.SetValue(entityKeyMember, KeyPropertyName, reader.Value.ToString()); ReadAndAssertProperty(reader, TypePropertyName); - ReadAndAssert(reader); + reader.ReadAndAssert(); string type = reader.Value.ToString(); Type t = Type.GetType(type); ReadAndAssertProperty(reader, ValuePropertyName); - ReadAndAssert(reader); + reader.ReadAndAssert(); _reflectionObject.SetValue(entityKeyMember, ValuePropertyName, serializer.Deserialize(reader, t)); - ReadAndAssert(reader); + reader.ReadAndAssert(); return entityKeyMember; } diff --git a/Src/Newtonsoft.Json/Converters/ExpandoObjectConverter.cs b/Src/Newtonsoft.Json/Converters/ExpandoObjectConverter.cs index 70477752..45d522e1 100644 --- a/Src/Newtonsoft.Json/Converters/ExpandoObjectConverter.cs +++ b/Src/Newtonsoft.Json/Converters/ExpandoObjectConverter.cs @@ -66,12 +66,9 @@ namespace Newtonsoft.Json.Converters private object ReadValue(JsonReader reader) { - while (reader.TokenType == JsonToken.Comment) + if (!reader.MoveToContentUnsafe()) { - if (!reader.Read()) - { - throw JsonSerializationException.Create(reader, "Unexpected end when reading ExpandoObject."); - } + throw JsonSerializationException.Create(reader, "Unexpected end when reading ExpandoObject."); } switch (reader.TokenType) diff --git a/Src/Newtonsoft.Json/Converters/KeyValuePairConverter.cs b/Src/Newtonsoft.Json/Converters/KeyValuePairConverter.cs index 7528ef86..71f5fbb0 100644 --- a/Src/Newtonsoft.Json/Converters/KeyValuePairConverter.cs +++ b/Src/Newtonsoft.Json/Converters/KeyValuePairConverter.cs @@ -93,7 +93,7 @@ namespace Newtonsoft.Json.Converters object key = null; object value = null; - ReadAndAssert(reader); + reader.ReadAndAssert(); Type t = ReflectionUtils.IsNullableType(objectType) ? Nullable.GetUnderlyingType(objectType) @@ -106,12 +106,12 @@ namespace Newtonsoft.Json.Converters string propertyName = reader.Value.ToString(); if (string.Equals(propertyName, KeyName, StringComparison.OrdinalIgnoreCase)) { - ReadAndAssert(reader); + reader.ReadAndAssert(); key = serializer.Deserialize(reader, reflectionObject.GetType(KeyName)); } else if (string.Equals(propertyName, ValueName, StringComparison.OrdinalIgnoreCase)) { - ReadAndAssert(reader); + reader.ReadAndAssert(); value = serializer.Deserialize(reader, reflectionObject.GetType(ValueName)); } else @@ -119,7 +119,7 @@ namespace Newtonsoft.Json.Converters reader.Skip(); } - ReadAndAssert(reader); + reader.ReadAndAssert(); } return reflectionObject.Creator(key, value); @@ -145,13 +145,5 @@ namespace Newtonsoft.Json.Converters return false; } - - private static void ReadAndAssert(JsonReader reader) - { - if (!reader.Read()) - { - throw JsonSerializationException.Create(reader, "Unexpected end when reading KeyValuePair."); - } - } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonReader.cs b/Src/Newtonsoft.Json/JsonReader.cs index 961dbb8d..6fd4f827 100644 --- a/Src/Newtonsoft.Json/JsonReader.cs +++ b/Src/Newtonsoft.Json/JsonReader.cs @@ -457,67 +457,46 @@ namespace Newtonsoft.Json { _readType = ReadType.ReadAsDateTimeOffset; - JsonToken t; + JsonToken t = ReadToContentInternal(); - do + switch (t) { - if (!ReadInternal()) - { - SetToken(JsonToken.None); + case JsonToken.None: + case JsonToken.Null: + case JsonToken.EndArray: return null; - } - else - { - t = TokenType; - } - } while (t == JsonToken.Comment); + case JsonToken.Date: + if (Value is DateTime) + { + SetToken(JsonToken.Date, new DateTimeOffset((DateTime)Value), false); + } - if (t == JsonToken.Date) - { - if (Value is DateTime) - { - SetToken(JsonToken.Date, new DateTimeOffset((DateTime)Value), false); - } + return (DateTimeOffset)Value; + case JsonToken.String: + string s = (string)Value; + if (string.IsNullOrEmpty(s)) + { + SetToken(JsonToken.Null); + return null; + } - return (DateTimeOffset)Value; + DateTimeOffset dt; + if (DateTimeUtils.TryParseDateTimeOffset(s, _dateFormatString, Culture, out dt)) + { + SetToken(JsonToken.Date, dt, false); + return dt; + } + + if (DateTimeOffset.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt)) + { + SetToken(JsonToken.Date, dt, false); + return dt; + } + + throw JsonReaderException.Create(this, "Could not convert string to DateTimeOffset: {0}.".FormatWith(CultureInfo.InvariantCulture, Value)); + default: + throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t)); } - - if (t == JsonToken.Null) - { - return null; - } - - if (t == JsonToken.String) - { - string s = (string)Value; - if (string.IsNullOrEmpty(s)) - { - SetToken(JsonToken.Null); - return null; - } - - DateTimeOffset dt; - if (DateTimeUtils.TryParseDateTimeOffset(s, _dateFormatString, Culture, out dt)) - { - SetToken(JsonToken.Date, dt, false); - return dt; - } - - if (DateTimeOffset.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt)) - { - SetToken(JsonToken.Date, dt, false); - return dt; - } - - throw JsonReaderException.Create(this, "Could not convert string to DateTimeOffset: {0}.".FormatWith(CultureInfo.InvariantCulture, Value)); - } - - if (t == JsonToken.EndArray) - { - return null; - } - - throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t)); } #endif @@ -525,20 +504,12 @@ namespace Newtonsoft.Json { _readType = ReadType.ReadAsBytes; - JsonToken t; + JsonToken t = ReadToContentInternal(); - do + if (t == JsonToken.None) { - if (!ReadInternal()) - { - SetToken(JsonToken.None); - return null; - } - else - { - t = TokenType; - } - } while (t == JsonToken.Comment); + return null; + } if (IsWrappedInTypeObject()) { @@ -548,81 +519,66 @@ namespace Newtonsoft.Json return data; } - // attempt to convert possible base 64 or GUID string to bytes - // GUID has to have format 00000000-0000-0000-0000-000000000000 - if (t == JsonToken.String) + switch (t) { - string s = (string)Value; - - byte[] data; - - Guid g; - if (s.Length == 0) - { - data = new byte[0]; - } - else if (ConvertUtils.TryConvertGuid(s, out g)) - { - data = g.ToByteArray(); - } - else - { - data = Convert.FromBase64String(s); - } - - SetToken(JsonToken.Bytes, data, false); - return data; - } - - if (t == JsonToken.Null) - { - return null; - } - - if (t == JsonToken.Bytes) - { - if (ValueType == typeof(Guid)) - { - byte[] data = ((Guid)Value).ToByteArray(); - SetToken(JsonToken.Bytes, data, false); - return data; - } - - return (byte[])Value; - } - - if (t == JsonToken.StartArray) - { - List data = new List(); - - while (ReadInternal()) - { - t = TokenType; - switch (t) + case JsonToken.String: { - case JsonToken.Integer: - data.Add(Convert.ToByte(Value, CultureInfo.InvariantCulture)); - break; - case JsonToken.EndArray: - byte[] d = data.ToArray(); - SetToken(JsonToken.Bytes, d, false); - return d; - case JsonToken.Comment: - // skip - break; - default: - throw JsonReaderException.Create(this, "Unexpected token when reading bytes: {0}.".FormatWith(CultureInfo.InvariantCulture, t)); + // attempt to convert possible base 64 or GUID string to bytes + // GUID has to have format 00000000-0000-0000-0000-000000000000 + string s = (string)Value; + + byte[] data; + + Guid g; + if (s.Length == 0) + { + data = new byte[0]; + } + else if (ConvertUtils.TryConvertGuid(s, out g)) + { + data = g.ToByteArray(); + } + else + { + data = Convert.FromBase64String(s); + } + + SetToken(JsonToken.Bytes, data, false); + return data; + } + case JsonToken.Null: + case JsonToken.EndArray: + return null; + case JsonToken.Bytes: + if (ValueType == typeof(Guid)) + { + byte[] data = ((Guid)Value).ToByteArray(); + SetToken(JsonToken.Bytes, data, false); + return data; } - } - throw JsonReaderException.Create(this, "Unexpected end when reading bytes."); + return (byte[])Value; + case JsonToken.StartArray: + List buffer = new List(); + + while (true) + { + switch (t = ReadToContentInternal()) + { + case JsonToken.None: + throw JsonReaderException.Create(this, "Unexpected end when reading bytes."); + case JsonToken.Integer: + buffer.Add(Convert.ToByte(Value, CultureInfo.InvariantCulture)); + break; + case JsonToken.EndArray: + byte[] d = buffer.ToArray(); + SetToken(JsonToken.Bytes, d, false); + return d; + default: + throw JsonReaderException.Create(this, "Unexpected token when reading bytes: {0}.".FormatWith(CultureInfo.InvariantCulture, t)); + } + } } - - if (t == JsonToken.EndArray) - { - return null; - } - throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t)); } @@ -630,62 +586,41 @@ namespace Newtonsoft.Json { _readType = ReadType.ReadAsDecimal; - JsonToken t; + JsonToken t = ReadToContentInternal(); - do + switch (t) { - if (!ReadInternal()) - { - SetToken(JsonToken.None); + case JsonToken.None: + case JsonToken.Null: + case JsonToken.EndArray: return null; - } - else - { - t = TokenType; - } - } while (t == JsonToken.Comment); + case JsonToken.Integer: + case JsonToken.Float: + if (!(Value is decimal)) + { + SetToken(JsonToken.Float, Convert.ToDecimal(Value, CultureInfo.InvariantCulture), false); + } - if (t == JsonToken.Integer || t == JsonToken.Float) - { - if (!(Value is decimal)) - { - SetToken(JsonToken.Float, Convert.ToDecimal(Value, CultureInfo.InvariantCulture), false); - } + return (decimal)Value; + case JsonToken.String: + string s = (string)Value; + if (string.IsNullOrEmpty(s)) + { + SetToken(JsonToken.Null); + return null; + } - return (decimal)Value; + decimal d; + if (decimal.TryParse(s, NumberStyles.Number, Culture, out d)) + { + SetToken(JsonToken.Float, d, false); + return d; + } + else + { + throw JsonReaderException.Create(this, "Could not convert string to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, Value)); + } } - - if (t == JsonToken.Null) - { - return null; - } - - if (t == JsonToken.String) - { - string s = (string)Value; - if (string.IsNullOrEmpty(s)) - { - SetToken(JsonToken.Null); - return null; - } - - decimal d; - if (decimal.TryParse(s, NumberStyles.Number, Culture, out d)) - { - SetToken(JsonToken.Float, d, false); - return d; - } - else - { - throw JsonReaderException.Create(this, "Could not convert string to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, Value)); - } - } - - if (t == JsonToken.EndArray) - { - return null; - } - throw JsonReaderException.Create(this, "Error reading decimal. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t)); } @@ -693,62 +628,39 @@ namespace Newtonsoft.Json { _readType = ReadType.ReadAsInt32; - JsonToken t; - - do + switch (ReadToContentInternal()) { - if (!ReadInternal()) - { - SetToken(JsonToken.None); + case JsonToken.None: + case JsonToken.Null: + case JsonToken.EndArray: return null; - } - else - { - t = TokenType; - } - } while (t == JsonToken.Comment); + case JsonToken.Integer: + case JsonToken.Float: + if (!(Value is int)) + { + SetToken(JsonToken.Integer, Convert.ToInt32(Value, CultureInfo.InvariantCulture), false); + } - if (t == JsonToken.Integer || t == JsonToken.Float) - { - if (!(Value is int)) - { - SetToken(JsonToken.Integer, Convert.ToInt32(Value, CultureInfo.InvariantCulture), false); - } + return (int)Value; + case JsonToken.String: + string s = (string)Value; + if (string.IsNullOrEmpty(s)) + { + SetToken(JsonToken.Null); + return null; + } - return (int)Value; + int i; + if (int.TryParse(s, NumberStyles.Integer, Culture, out i)) + { + SetToken(JsonToken.Integer, i, false); + return i; + } + else + { + throw JsonReaderException.Create(this, "Could not convert string to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, Value)); + } } - - if (t == JsonToken.Null) - { - return null; - } - - int i; - if (t == JsonToken.String) - { - string s = (string)Value; - if (string.IsNullOrEmpty(s)) - { - SetToken(JsonToken.Null); - return null; - } - - if (int.TryParse(s, NumberStyles.Integer, Culture, out i)) - { - SetToken(JsonToken.Integer, i, false); - return i; - } - else - { - throw JsonReaderException.Create(this, "Could not convert string to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, Value)); - } - } - - if (t == JsonToken.EndArray) - { - return null; - } - throw JsonReaderException.Create(this, "Error reading integer. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); } @@ -756,29 +668,16 @@ namespace Newtonsoft.Json { _readType = ReadType.ReadAsString; - JsonToken t; + JsonToken t = ReadToContentInternal(); - do + switch (t) { - if (!ReadInternal()) - { - SetToken(JsonToken.None); + case JsonToken.None: + case JsonToken.Null: + case JsonToken.EndArray: return null; - } - else - { - t = TokenType; - } - } while (t == JsonToken.Comment); - - if (t == JsonToken.String) - { - return (string)Value; - } - - if (t == JsonToken.Null) - { - return null; + case JsonToken.String: + return (string)Value; } if (JsonTokenUtils.IsPrimitiveToken(t)) @@ -800,11 +699,6 @@ namespace Newtonsoft.Json } } - if (t == JsonToken.EndArray) - { - return null; - } - throw JsonReaderException.Create(this, "Error reading string. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t)); } @@ -812,55 +706,39 @@ namespace Newtonsoft.Json { _readType = ReadType.ReadAsDateTime; - do + switch (ReadToContentInternal()) { - if (!ReadInternal()) - { - SetToken(JsonToken.None); + case JsonToken.None: + case JsonToken.Null: + case JsonToken.EndArray: return null; - } - } while (TokenType == JsonToken.Comment); + case JsonToken.Date: + return (DateTime)Value; + case JsonToken.String: + string s = (string)Value; + if (string.IsNullOrEmpty(s)) + { + SetToken(JsonToken.Null); + return null; + } - if (TokenType == JsonToken.Date) - { - return (DateTime)Value; - } + DateTime dt; + if (DateTimeUtils.TryParseDateTime(s, DateTimeZoneHandling, _dateFormatString, Culture, out dt)) + { + dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling); + SetToken(JsonToken.Date, dt, false); + return dt; + } - if (TokenType == JsonToken.Null) - { - return null; - } + if (DateTime.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt)) + { + dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling); + SetToken(JsonToken.Date, dt, false); + return dt; + } - if (TokenType == JsonToken.String) - { - string s = (string)Value; - if (string.IsNullOrEmpty(s)) - { - SetToken(JsonToken.Null); - return null; - } + throw JsonReaderException.Create(this, "Could not convert string to DateTime: {0}.".FormatWith(CultureInfo.InvariantCulture, Value)); - DateTime dt; - if (DateTimeUtils.TryParseDateTime(s, DateTimeZoneHandling, _dateFormatString, Culture, out dt)) - { - dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling); - SetToken(JsonToken.Date, dt, false); - return dt; - } - - if (DateTime.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt)) - { - dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling); - SetToken(JsonToken.Date, dt, false); - return dt; - } - - throw JsonReaderException.Create(this, "Could not convert string to DateTime: {0}.".FormatWith(CultureInfo.InvariantCulture, Value)); - } - - if (TokenType == JsonToken.EndArray) - { - return null; } throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); @@ -1109,5 +987,69 @@ namespace Newtonsoft.Json _tokenType = JsonToken.None; _value = null; } + + internal void ReadAndAssert() + { + if (!Read()) + { + throw JsonSerializationException.Create(this, "Unexpected end when reading JSON."); + } + } + + /// + /// Reads the next non-comment JSON token from the stream. + /// + /// true if the next non-comment token was read successfully; false if there are no more tokens to read. + public bool ReadToContent() + { + return Read() && MoveToContentUnsafe(); + } + + /// + /// Checks whether the current JSON token is a content (non-comment) token, reading past comments if necessary. + /// + /// true if the current token was not a comment, or the reader successfully read to a non-comment token; false if there are no more tokens to read. + public bool MoveToContent() + { + if (TokenType == JsonToken.None && !Read()) + { + return false; + } + + return MoveToContentUnsafe(); + } + + // MoveToContent() but assumes stream was already read into. + internal bool MoveToContentUnsafe() + { + while (TokenType == JsonToken.Comment) + { + if (!Read()) + { + return false; + } + } + + return true; + } + + private JsonToken ReadToContentInternal() + { + JsonToken t; + do + { + if (!ReadInternal()) + { + SetToken(JsonToken.None); + return JsonToken.None; + } + else + { + t = TokenType; + } + } while (t == JsonToken.Comment); + + return t; + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonTextReader.cs b/Src/Newtonsoft.Json/JsonTextReader.cs index e6d377b1..be0446f6 100644 --- a/Src/Newtonsoft.Json/JsonTextReader.cs +++ b/Src/Newtonsoft.Json/JsonTextReader.cs @@ -1039,7 +1039,7 @@ namespace Newtonsoft.Json } else { - throw JsonReaderException.Create(this, "Unexpected end."); + throw JsonReaderException.Create(this, "Unexpected end when reading JSON."); } return true; case 'N': diff --git a/Src/Newtonsoft.Json/Linq/JArray.cs b/Src/Newtonsoft.Json/Linq/JArray.cs index e73100d2..ad924eae 100644 --- a/Src/Newtonsoft.Json/Linq/JArray.cs +++ b/Src/Newtonsoft.Json/Linq/JArray.cs @@ -132,10 +132,7 @@ namespace Newtonsoft.Json.Linq } } - while (reader.TokenType == JsonToken.Comment) - { - reader.Read(); - } + reader.MoveToContentUnsafe(); if (reader.TokenType != JsonToken.StartArray) { diff --git a/Src/Newtonsoft.Json/Linq/JConstructor.cs b/Src/Newtonsoft.Json/Linq/JConstructor.cs index 74e35ff3..3a44a20c 100644 --- a/Src/Newtonsoft.Json/Linq/JConstructor.cs +++ b/Src/Newtonsoft.Json/Linq/JConstructor.cs @@ -221,10 +221,7 @@ namespace Newtonsoft.Json.Linq } } - while (reader.TokenType == JsonToken.Comment) - { - reader.Read(); - } + reader.MoveToContentUnsafe(); if (reader.TokenType != JsonToken.StartConstructor) { diff --git a/Src/Newtonsoft.Json/Linq/JObject.cs b/Src/Newtonsoft.Json/Linq/JObject.cs index f8d8e86c..c5c1a9d2 100644 --- a/Src/Newtonsoft.Json/Linq/JObject.cs +++ b/Src/Newtonsoft.Json/Linq/JObject.cs @@ -370,10 +370,7 @@ namespace Newtonsoft.Json.Linq } } - while (reader.TokenType == JsonToken.Comment) - { - reader.Read(); - } + reader.MoveToContentUnsafe(); if (reader.TokenType != JsonToken.StartObject) { diff --git a/Src/Newtonsoft.Json/Linq/JProperty.cs b/Src/Newtonsoft.Json/Linq/JProperty.cs index e6f42a87..6501681e 100644 --- a/Src/Newtonsoft.Json/Linq/JProperty.cs +++ b/Src/Newtonsoft.Json/Linq/JProperty.cs @@ -382,10 +382,7 @@ namespace Newtonsoft.Json.Linq } } - while (reader.TokenType == JsonToken.Comment) - { - reader.Read(); - } + reader.MoveToContentUnsafe(); if (reader.TokenType != JsonToken.PropertyName) { diff --git a/Src/Newtonsoft.Json/Linq/JToken.cs b/Src/Newtonsoft.Json/Linq/JToken.cs index 90d06676..6918b2bd 100644 --- a/Src/Newtonsoft.Json/Linq/JToken.cs +++ b/Src/Newtonsoft.Json/Linq/JToken.cs @@ -2113,60 +2113,47 @@ namespace Newtonsoft.Json.Linq if (reader.TokenType == JsonToken.None) { - if (!reader.Read()) + if (!(settings != null && settings.CommentHandling == CommentHandling.Ignore ? reader.ReadToContent() : reader.Read())) { throw JsonReaderException.Create(reader, "Error reading JToken from JsonReader."); } } - while (true) + IJsonLineInfo lineInfo = reader as IJsonLineInfo; + + switch (reader.TokenType) { - IJsonLineInfo lineInfo = reader as IJsonLineInfo; - - switch (reader.TokenType) - { - case JsonToken.StartObject: - return JObject.Load(reader, settings); - case JsonToken.StartArray: - return JArray.Load(reader, settings); - case JsonToken.StartConstructor: - return JConstructor.Load(reader, settings); - case JsonToken.PropertyName: - return JProperty.Load(reader, settings); - case JsonToken.String: - case JsonToken.Integer: - case JsonToken.Float: - case JsonToken.Date: - case JsonToken.Boolean: - case JsonToken.Bytes: - JValue v = new JValue(reader.Value); - v.SetLineInfo(lineInfo, settings); - return v; - case JsonToken.Comment: - if (settings != null && settings.CommentHandling == CommentHandling.Ignore) - { - if (!reader.Read()) - { - throw JsonReaderException.Create(reader, "Error reading JToken from JsonReader."); - } - - continue; - } - - v = JValue.CreateComment(reader.Value.ToString()); - v.SetLineInfo(lineInfo, settings); - return v; - case JsonToken.Null: - v = JValue.CreateNull(); - v.SetLineInfo(lineInfo, settings); - return v; - case JsonToken.Undefined: - v = JValue.CreateUndefined(); - v.SetLineInfo(lineInfo, settings); - return v; - default: - throw JsonReaderException.Create(reader, "Error reading JToken from JsonReader. Unexpected token: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); - } + case JsonToken.StartObject: + return JObject.Load(reader, settings); + case JsonToken.StartArray: + return JArray.Load(reader, settings); + case JsonToken.StartConstructor: + return JConstructor.Load(reader, settings); + case JsonToken.PropertyName: + return JProperty.Load(reader, settings); + case JsonToken.String: + case JsonToken.Integer: + case JsonToken.Float: + case JsonToken.Date: + case JsonToken.Boolean: + case JsonToken.Bytes: + JValue v = new JValue(reader.Value); + v.SetLineInfo(lineInfo, settings); + return v; + case JsonToken.Comment: + v = JValue.CreateComment(reader.Value.ToString()); + v.SetLineInfo(lineInfo, settings); + return v; + case JsonToken.Null: + v = JValue.CreateNull(); + v.SetLineInfo(lineInfo, settings); + return v; + case JsonToken.Undefined: + v = JValue.CreateUndefined(); + v.SetLineInfo(lineInfo, settings); + return v; + default: + throw JsonReaderException.Create(reader, "Error reading JToken from JsonReader. Unexpected token: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); } } diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs index 6370cbc2..1b21efbb 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs @@ -71,12 +71,9 @@ namespace Newtonsoft.Json.Serialization JsonContract contract = Serializer._contractResolver.ResolveContract(objectType); - while (reader.TokenType == JsonToken.None || reader.TokenType == JsonToken.Comment) + if (!reader.MoveToContent()) { - if (!reader.Read()) - { - throw JsonSerializationException.Create(reader, "No JSON content found."); - } + throw JsonSerializationException.Create(reader, "No JSON content found."); } if (reader.TokenType == JsonToken.StartArray) @@ -94,16 +91,16 @@ namespace Newtonsoft.Json.Serialization } else if (reader.TokenType == JsonToken.StartObject) { - CheckedRead(reader); + reader.ReadAndAssert(); string id = null; if (Serializer.MetadataPropertyHandling != MetadataPropertyHandling.Ignore && reader.TokenType == JsonToken.PropertyName && string.Equals(reader.Value.ToString(), JsonTypeReflector.IdPropertyName, StringComparison.Ordinal)) { - CheckedRead(reader); + reader.ReadAndAssert(); id = (reader.Value != null) ? reader.Value.ToString() : null; - CheckedRead(reader); + reader.ReadAndAssert(); } if (contract.ContractType == JsonContractType.Dictionary) @@ -249,13 +246,10 @@ namespace Newtonsoft.Json.Serialization if (reader.TokenType == JsonToken.PropertyName) { string propertyName = (string)reader.Value; - do + if (!reader.ReadToContent()) { - if (!reader.Read()) - { - break; - } - } while (reader.TokenType == JsonToken.Comment); + break; + } if (CheckPropertyName(reader, propertyName)) { @@ -421,7 +415,7 @@ namespace Newtonsoft.Json.Serialization if (Serializer.MetadataPropertyHandling == MetadataPropertyHandling.Ignore) { // don't look for metadata properties - CheckedRead(reader); + reader.ReadAndAssert(); id = null; } else if (Serializer.MetadataPropertyHandling == MetadataPropertyHandling.ReadAhead) @@ -439,7 +433,7 @@ namespace Newtonsoft.Json.Serialization tokenReader.SupportMultipleContent = reader.SupportMultipleContent; // start - CheckedRead(tokenReader); + tokenReader.ReadAndAssert(); reader = tokenReader; } @@ -452,7 +446,7 @@ namespace Newtonsoft.Json.Serialization } else { - CheckedRead(reader); + reader.ReadAndAssert(); object newValue; if (ReadMetadataProperties(reader, ref resolvedObjectType, ref contract, member, containerContract, containerMember, existingValue, out newValue, out id)) { @@ -498,7 +492,7 @@ namespace Newtonsoft.Json.Serialization && reader.TokenType == JsonToken.PropertyName && string.Equals(reader.Value.ToString(), JsonTypeReflector.ValuePropertyName, StringComparison.Ordinal)) { - CheckedRead(reader); + reader.ReadAndAssert(); // the token should not be an object because the $type value could have been included in the object // without needing the $value property @@ -509,7 +503,7 @@ namespace Newtonsoft.Json.Serialization object value = CreateValueInternal(reader, resolvedObjectType, primitiveContract, member, null, null, existingValue); - CheckedRead(reader); + reader.ReadAndAssert(); return value; } break; @@ -641,7 +635,7 @@ namespace Newtonsoft.Json.Serialization { string qualifiedTypeName = (string)typeToken; JsonReader typeTokenReader = typeToken.CreateReader(); - CheckedRead(typeTokenReader); + typeTokenReader.ReadAndAssert(); ResolveTypeName(typeTokenReader, ref objectType, ref contract, member, containerContract, containerMember, qualifiedTypeName); JToken valueToken = current[JsonTypeReflector.ValuePropertyName]; @@ -649,7 +643,7 @@ namespace Newtonsoft.Json.Serialization { while (true) { - CheckedRead(reader); + reader.ReadAndAssert(); if (reader.TokenType == JsonToken.PropertyName) { if ((string)reader.Value == JsonTypeReflector.ValuePropertyName) @@ -658,7 +652,7 @@ namespace Newtonsoft.Json.Serialization } } - CheckedRead(reader); + reader.ReadAndAssert(); reader.Skip(); } } @@ -672,7 +666,7 @@ namespace Newtonsoft.Json.Serialization if (valuesToken != null) { JsonReader listReader = valuesToken.CreateReader(); - CheckedRead(listReader); + listReader.ReadAndAssert(); newValue = CreateList(listReader, objectType, contract, member, existingValue, id); reader.Skip(); @@ -680,7 +674,7 @@ namespace Newtonsoft.Json.Serialization } } - CheckedRead(reader); + reader.ReadAndAssert(); return false; } @@ -705,7 +699,7 @@ namespace Newtonsoft.Json.Serialization if (string.Equals(propertyName, JsonTypeReflector.RefPropertyName, StringComparison.Ordinal)) { - CheckedRead(reader); + reader.ReadAndAssert(); if (reader.TokenType != JsonToken.String && reader.TokenType != JsonToken.Null) { throw JsonSerializationException.Create(reader, "JSON reference {0} property must have a string or null value.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName)); @@ -713,7 +707,7 @@ namespace Newtonsoft.Json.Serialization string reference = (reader.Value != null) ? reader.Value.ToString() : null; - CheckedRead(reader); + reader.ReadAndAssert(); if (reference != null) { @@ -738,29 +732,29 @@ namespace Newtonsoft.Json.Serialization } else if (string.Equals(propertyName, JsonTypeReflector.TypePropertyName, StringComparison.Ordinal)) { - CheckedRead(reader); + reader.ReadAndAssert(); string qualifiedTypeName = reader.Value.ToString(); ResolveTypeName(reader, ref objectType, ref contract, member, containerContract, containerMember, qualifiedTypeName); - CheckedRead(reader); + reader.ReadAndAssert(); metadataProperty = true; } else if (string.Equals(propertyName, JsonTypeReflector.IdPropertyName, StringComparison.Ordinal)) { - CheckedRead(reader); + reader.ReadAndAssert(); id = (reader.Value != null) ? reader.Value.ToString() : null; - CheckedRead(reader); + reader.ReadAndAssert(); metadataProperty = true; } else if (string.Equals(propertyName, JsonTypeReflector.ArrayValuesPropertyName, StringComparison.Ordinal)) { - CheckedRead(reader); + reader.ReadAndAssert(); object list = CreateList(reader, objectType, contract, member, existingValue, id); - CheckedRead(reader); + reader.ReadAndAssert(); newValue = list; return true; } @@ -842,14 +836,6 @@ namespace Newtonsoft.Json.Serialization return arrayContract; } - private void CheckedRead(JsonReader reader) - { - if (!reader.Read()) - { - throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object."); - } - } - private object CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, object existingValue, string id) { object value; @@ -1475,8 +1461,6 @@ namespace Newtonsoft.Json.Serialization currentList = listStack.Peek(); previousErrorIndex = null; break; - case JsonToken.Comment: - break; default: object value; @@ -1630,8 +1614,6 @@ namespace Newtonsoft.Json.Serialization case JsonToken.EndArray: finished = true; break; - case JsonToken.Comment: - break; default: object value; @@ -1762,7 +1744,7 @@ namespace Newtonsoft.Json.Serialization JsonConverter itemConverter = GetConverter(itemContract, null, contract, member); JsonReader tokenReader = token.CreateReader(); - CheckedRead(tokenReader); // Move to first token + tokenReader.ReadAndAssert(); // Move to first token object result; if (itemConverter != null && itemConverter.CanRead) @@ -2213,7 +2195,7 @@ namespace Newtonsoft.Json.Serialization // the value might be a string which will then get converted which will error if read as date for example if (hasConverter) { - return reader.Read(); + return reader.ReadToContent(); } ReadType t = (contract != null) ? contract.InternalReadType : ReadType.Read; @@ -2221,15 +2203,7 @@ namespace Newtonsoft.Json.Serialization switch (t) { case ReadType.Read: - do - { - if (!reader.Read()) - { - return false; - } - } while (reader.TokenType == JsonToken.Comment); - - return true; + return reader.ReadToContent(); case ReadType.ReadAsInt32: reader.ReadAsInt32(); break;