From 81098652b37266bf7ed29d8c1e86c270ae18b79d Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Tue, 19 Apr 2016 21:55:58 +1200 Subject: [PATCH] -Fixed JsonTextReader.ReadAsString incorrectly erroring when reading some numbers --- .../JsonTextReaderTest.cs | 31 +++++++++++++ Src/Newtonsoft.Json/JsonTextReader.cs | 43 ++++++++++++++++--- 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs index d043d7e0..5ed72bb9 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs @@ -61,6 +61,37 @@ namespace Newtonsoft.Json.Tests [TestFixture] public class JsonTextReaderTest : TestFixtureBase { + [Test] + public void FloatParseHandling_ReadAsString() + { + string json = "[9223372036854775807, 1.7976931348623157E+308, 792281625142643375935439503.35, 792281625142643375935555555555555555555555555555555555555555555555555439503.35]"; + + JsonTextReader reader = new JsonTextReader(new StringReader(json)); + reader.FloatParseHandling = Json.FloatParseHandling.Decimal; + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartArray, reader.TokenType); + + Assert.AreEqual("9223372036854775807", reader.ReadAsString()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("9223372036854775807", reader.Value); + + Assert.AreEqual("1.7976931348623157E+308", reader.ReadAsString()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("1.7976931348623157E+308", reader.Value); + + Assert.AreEqual("792281625142643375935439503.35", reader.ReadAsString()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("792281625142643375935439503.35", reader.Value); + + Assert.AreEqual("792281625142643375935555555555555555555555555555555555555555555555555439503.35", reader.ReadAsString()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("792281625142643375935555555555555555555555555555555555555555555555555439503.35", reader.Value); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndArray, reader.TokenType); + } + [Test] public void LineInfoAndNewLines() { diff --git a/Src/Newtonsoft.Json/JsonTextReader.cs b/Src/Newtonsoft.Json/JsonTextReader.cs index 96a3ee83..b49efcd5 100644 --- a/Src/Newtonsoft.Json/JsonTextReader.cs +++ b/Src/Newtonsoft.Json/JsonTextReader.cs @@ -614,10 +614,8 @@ namespace Newtonsoft.Json _charPos++; throw CreateUnexpectedCharacterException(currentChar); } - ParseNumber(ReadType.Read); - string s = ((IFormattable)Value).ToString(null, CultureInfo.InvariantCulture); - SetToken(JsonToken.String, s); - return s; + ParseNumber(ReadType.ReadAsString); + return Value; case 't': case 'f': if (readType != ReadType.ReadAsString) @@ -1807,7 +1805,42 @@ namespace Newtonsoft.Json bool singleDigit = (char.IsDigit(firstChar) && _stringReference.Length == 1); bool nonBase10 = (firstChar == '0' && _stringReference.Length > 1 && _stringReference.Chars[_stringReference.StartIndex + 1] != '.' && _stringReference.Chars[_stringReference.StartIndex + 1] != 'e' && _stringReference.Chars[_stringReference.StartIndex + 1] != 'E'); - if (readType == ReadType.ReadAsInt32) + if (readType == ReadType.ReadAsString) + { + string number = _stringReference.ToString(); + + // validate that the string is a valid number + if (nonBase10) + { + try + { + if (number.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) + { + Convert.ToInt64(number, 16); + } + else + { + Convert.ToInt64(number, 8); + } + } + catch (Exception ex) + { + throw JsonReaderException.Create(this, "Input string '{0}' is not a valid number.".FormatWith(CultureInfo.InvariantCulture, number), ex); + } + } + else + { + double value; + if (!double.TryParse(number, NumberStyles.Float, CultureInfo.InvariantCulture, out value)) + { + throw JsonReaderException.Create(this, "Input string '{0}' is not a valid number.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString())); + } + } + + numberType = JsonToken.String; + numberValue = number; + } + else if (readType == ReadType.ReadAsInt32) { if (singleDigit) {