initial commit for custom double parsing

This commit is contained in:
Markus Cozowicz
2016-07-06 09:44:30 -04:00
parent 1c1a602d0e
commit 24fdb1c9e4
2 changed files with 112 additions and 3 deletions
+6 -3
View File
@@ -1973,13 +1973,16 @@ namespace Newtonsoft.Json
}
else
{
string number = _stringReference.ToString();
double value;
if (double.TryParse(number, NumberStyles.Float, CultureInfo.InvariantCulture, out value))
ParseResult parseResult = ConvertUtils.DoubleTryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length, out value);
if (parseResult == ParseResult.Success)
{
numberValue = value;
}
else if (parseResult == ParseResult.Overflow)
{
throw JsonReaderException.Create(this, "JSON integer {0} is too large or small for an Double.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()));
}
else
{
throw JsonReaderException.Create(this, "Input string '{0}' is not a valid double.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()));
@@ -930,6 +930,112 @@ namespace Newtonsoft.Json.Utilities
return ParseResult.Success;
}
public static ParseResult DoubleTryParse(char[] chars, int start, int length, out double value)
{
value = 0;
if (length == 0)
{
return ParseResult.Invalid;
}
bool isNegative = (chars[start] == '-');
if (isNegative)
{
// text just a negative sign
if (length == 1)
{
return ParseResult.Invalid;
}
start++;
length--;
}
var i = start;
int end = start + length;
int numDecimals = 0;
int exponent = 0;
for (; i < end; i++)
{
char c = chars[i];
switch (chars[i])
{
case '.':
numDecimals = i;
break;
case 'e':
case 'E':
{
i++;
if (i == end)
return ParseResult.Success;
c = chars[i];
bool exponentNegative = false;
switch (c)
{
case '-':
exponentNegative = true;
i++;
break;
case '+':
i++;
break;
}
// parse 3 digit up to 308 max.
for (;i < end;i++)
{
c = chars[i];
if (c < '0' || c > '9')
return ParseResult.Invalid;
exponent = (10 * exponent) + (c - '0');
}
if (exponent > 308)
return ParseResult.Invalid;
if (exponentNegative)
exponent = -exponent;
}
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
value = (10 * value) + (c - '0');
break;
default:
return ParseResult.Invalid;
}
}
value *= Math.Pow(10, exponent - numDecimals);
// go from negative to positive to avoids overflow
// negative can be slightly bigger than positive
if (!isNegative)
{
// negative integer can be one bigger than positive
if (value == double.MinValue)
{
return ParseResult.Overflow;
}
value = -value;
}
return ParseResult.Success;
}
public static bool TryConvertGuid(string s, out Guid g)
{
// GUID has to have format 00000000-0000-0000-0000-000000000000