in src/Elastic.Apm/Libraries/Newtonsoft.Json/JsonTextReader.cs [1810:2067]
private void ParseReadNumber(ReadType readType, char firstChar, int initialPosition)
{
MiscellaneousUtils.Assert(CharBuffer != null);
// set state to PostValue now so that if there is an error parsing the number then the reader can continue
SetPostValueState(true);
_stringReference = new StringReference(CharBuffer, initialPosition, CharPos - initialPosition);
object numberValue;
JsonToken numberType;
var singleDigit = char.IsDigit(firstChar) && _stringReference.Length == 1;
var nonBase10 = firstChar == '0' && _stringReference.Length > 1 && _stringReference.Chars[_stringReference.StartIndex + 1] != '.'
&& _stringReference.Chars[_stringReference.StartIndex + 1] != 'e' && _stringReference.Chars[_stringReference.StartIndex + 1] != 'E';
switch (readType)
{
case ReadType.ReadAsString:
{
var 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 ThrowReaderError("Input string '{0}' is not a valid number.".FormatWith(CultureInfo.InvariantCulture, number), ex);
}
}
else
{
if (!double.TryParse(number, NumberStyles.Float, CultureInfo.InvariantCulture, out _))
throw ThrowReaderError("Input string '{0}' is not a valid number.".FormatWith(CultureInfo.InvariantCulture,
_stringReference.ToString()));
}
numberType = JsonToken.String;
numberValue = number;
}
break;
case ReadType.ReadAsInt32:
{
if (singleDigit)
{
// digit char values start at 48
numberValue = firstChar - 48;
}
else if (nonBase10)
{
var number = _stringReference.ToString();
try
{
var integer = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase)
? Convert.ToInt32(number, 16)
: Convert.ToInt32(number, 8);
numberValue = integer;
}
catch (Exception ex)
{
throw ThrowReaderError("Input string '{0}' is not a valid integer.".FormatWith(CultureInfo.InvariantCulture, number), ex);
}
}
else
{
var parseResult = ConvertUtils.Int32TryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length,
out var value);
if (parseResult == ParseResult.Success)
numberValue = value;
else if (parseResult == ParseResult.Overflow)
throw ThrowReaderError(
"JSON integer {0} is too large or small for an Int32.".FormatWith(CultureInfo.InvariantCulture,
_stringReference.ToString()));
else
throw ThrowReaderError("Input string '{0}' is not a valid integer.".FormatWith(CultureInfo.InvariantCulture,
_stringReference.ToString()));
}
numberType = JsonToken.Integer;
}
break;
case ReadType.ReadAsDecimal:
{
if (singleDigit)
{
// digit char values start at 48
numberValue = (decimal)firstChar - 48;
}
else if (nonBase10)
{
var number = _stringReference.ToString();
try
{
// decimal.Parse doesn't support parsing hexadecimal values
var integer = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase)
? Convert.ToInt64(number, 16)
: Convert.ToInt64(number, 8);
numberValue = Convert.ToDecimal(integer);
}
catch (Exception ex)
{
throw ThrowReaderError("Input string '{0}' is not a valid decimal.".FormatWith(CultureInfo.InvariantCulture, number), ex);
}
}
else
{
var parseResult = ConvertUtils.DecimalTryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length,
out var value);
if (parseResult == ParseResult.Success)
numberValue = value;
else
throw ThrowReaderError("Input string '{0}' is not a valid decimal.".FormatWith(CultureInfo.InvariantCulture,
_stringReference.ToString()));
}
numberType = JsonToken.Float;
}
break;
case ReadType.ReadAsDouble:
{
if (singleDigit)
{
// digit char values start at 48
numberValue = (double)firstChar - 48;
}
else if (nonBase10)
{
var number = _stringReference.ToString();
try
{
// double.Parse doesn't support parsing hexadecimal values
var integer = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase)
? Convert.ToInt64(number, 16)
: Convert.ToInt64(number, 8);
numberValue = Convert.ToDouble(integer);
}
catch (Exception ex)
{
throw ThrowReaderError("Input string '{0}' is not a valid double.".FormatWith(CultureInfo.InvariantCulture, number), ex);
}
}
else
{
var number = _stringReference.ToString();
if (double.TryParse(number, NumberStyles.Float, CultureInfo.InvariantCulture, out var value))
numberValue = value;
else
throw ThrowReaderError("Input string '{0}' is not a valid double.".FormatWith(CultureInfo.InvariantCulture,
_stringReference.ToString()));
}
numberType = JsonToken.Float;
}
break;
case ReadType.Read:
case ReadType.ReadAsInt64:
{
if (singleDigit)
{
// digit char values start at 48
numberValue = (long)firstChar - 48;
numberType = JsonToken.Integer;
}
else if (nonBase10)
{
var number = _stringReference.ToString();
try
{
numberValue = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase)
? Convert.ToInt64(number, 16)
: Convert.ToInt64(number, 8);
}
catch (Exception ex)
{
throw ThrowReaderError("Input string '{0}' is not a valid number.".FormatWith(CultureInfo.InvariantCulture, number), ex);
}
numberType = JsonToken.Integer;
}
else
{
var parseResult = ConvertUtils.Int64TryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length,
out var value);
if (parseResult == ParseResult.Success)
{
numberValue = value;
numberType = JsonToken.Integer;
}
else if (parseResult == ParseResult.Overflow)
{
#if HAVE_BIG_INTEGER
string number = _stringReference.ToString();
if (number.Length > MaximumJavascriptIntegerCharacterLength)
{
throw ThrowReaderError("JSON integer {0} is too large to parse.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()));
}
numberValue = BigIntegerParse(number, CultureInfo.InvariantCulture);
numberType = JsonToken.Integer;
#else
throw ThrowReaderError(
"JSON integer {0} is too large or small for an Int64.".FormatWith(CultureInfo.InvariantCulture,
_stringReference.ToString()));
#endif
}
else
{
if (_floatParseHandling == FloatParseHandling.Decimal)
{
parseResult = ConvertUtils.DecimalTryParse(_stringReference.Chars, _stringReference.StartIndex,
_stringReference.Length, out var d);
if (parseResult == ParseResult.Success)
numberValue = d;
else
throw ThrowReaderError("Input string '{0}' is not a valid decimal.".FormatWith(CultureInfo.InvariantCulture,
_stringReference.ToString()));
}
else
{
var number = _stringReference.ToString();
if (double.TryParse(number, NumberStyles.Float, CultureInfo.InvariantCulture, out var d))
numberValue = d;
else
throw ThrowReaderError("Input string '{0}' is not a valid number.".FormatWith(CultureInfo.InvariantCulture,
_stringReference.ToString()));
}
numberType = JsonToken.Float;
}
}
}
break;
default:
throw JsonReaderException.Create(this, "Cannot read number value as type.");
}
ClearRecentString();
// index has already been updated
SetToken(numberType, numberValue, false);
}