internal static bool TryParseBigInteger(string value, NumberStyles style, NumberFormatInfo info, out BigInteger result) { result = Zero; ArgumentException e; if (!TryValidateParseStyleInteger(style, out e)) { throw e; // TryParse still throws ArgumentException on invalid NumberStyles } if (value == null) { return(false); } var number = BigNumberBuffer.Create(); if (!ParseNumber(new StringProcessor(value), style, number, info)) { return(false); } if ((style & NumberStyles.AllowHexSpecifier) != 0) { if (!HexNumberToBigInteger(number, ref result)) { return(false); } } else { if (!NumberToBigInteger(number, out result)) { return(false); } } return(true); }
private static bool HexNumberToBigInteger(BigNumberBuffer number, ref BigInteger value) { if (number.Digits == null || number.Digits.Length == 0) { return(false); } var len = number.Digits.Length; // there is no trailing '\0' var bits = new byte[(len / 2) + (len % 2)]; var shift = false; var isNegative = false; var bitIndex = 0; // parse the string into a little-endian two's complement byte array // string value : O F E B 7 \0 // string index (i) : 0 1 2 3 4 5 <-- // byte[] (bitIndex): 2 1 1 0 0 <-- // for (var i = len - 1; i > -1; i--) { var c = number.Digits[i]; byte b; if (c >= '0' && c <= '9') { b = (byte)(c - '0'); } else if (c >= 'A' && c <= 'F') { b = (byte)((c - 'A') + 10); } else { Contract.Assert(c >= 'a' && c <= 'f'); b = (byte)((c - 'a') + 10); } isNegative |= (i == 0 && (b & 0x08) == 0x08); if (shift) { bits[bitIndex] = (byte)(bits[bitIndex] | (b << 4)); bitIndex++; } else { bits[bitIndex] = isNegative ? (byte)(b | 0xF0) : (b); } shift = !shift; } value = new BigInteger(bits); return(true); }
private static bool NumberToBigInteger(BigNumberBuffer number, out BigInteger value) { var cur = 0; if (number.Scale > number.Digits.Length) { var i = number.Digits.Length; value = 0; while (--i >= 0) { value *= 10; value += (number.Digits[cur++] - '0'); } var adjust = number.Scale - number.Digits.Length; while (adjust > 9) { value *= 1000000000; adjust -= 9; } while (adjust > 0) { value *= 10; adjust--; } } else { var i = number.Scale; value = 0; while (--i >= 0) { value *= 10; value += (number.Digits[cur++] - '0'); } for (; cur < number.Digits.Length - 1; cur++) { if (number.Digits[cur++] != '0') { return(false); } } } if (number.Negative) { value = -value; } return(true); }
internal static bool ParseNumber(StringProcessor reader, NumberStyles options, BigNumberBuffer number, NumberFormatInfo info) { // Percent intentionally not supported // After testig with .NET the patterns are ignored... all patterns are welcome var currencySymbol = info.CurrencySymbol; var numberGroupSeparator = info.NumberGroupSeparator; var currencyGroupSeparator = info.CurrencyGroupSeparator; var positiveSign = info.PositiveSign; var negativeSign = info.NegativeSign; if ((options & NumberStyles.AllowHexSpecifier) != NumberStyles.None) { var allowLeadingWhite = (options & NumberStyles.AllowLeadingWhite) != NumberStyles.None; var allowTrailingWhite = (options & NumberStyles.AllowTrailingWhite) != NumberStyles.None; /* * // Assume validated * if ( * (options & NumberStyles.AllowCurrencySymbol) != NumberStyles.None || (options & NumberStyles.AllowLeadingSign) != NumberStyles.None || (options & NumberStyles.AllowParentheses) != NumberStyles.None || (options & NumberStyles.AllowThousands) != NumberStyles.None || (options & NumberStyles.AllowExponent) != NumberStyles.None || (options & NumberStyles.AllowTrailingSign) != NumberStyles.None || ) ||{ || return false; ||}*/ number.Negative = false; if (allowLeadingWhite) { reader.SkipWhile(CharHelper.IsClassicWhitespace); } while (true) { var input = reader.ReadWhile(new[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F' }); if (input == string.Empty) { break; } number.Scale += input.Length; number.Digits.Append(input.ToUpperInvariant()); } if (allowTrailingWhite) { reader.SkipWhile(CharHelper.IsClassicWhitespace); } return(reader.EndOfString); } else { var allowCurrencySymbol = (options & NumberStyles.AllowCurrencySymbol) != NumberStyles.None; var allowLeadingWhite = (options & NumberStyles.AllowLeadingWhite) != NumberStyles.None; var allowLeadingSign = (options & NumberStyles.AllowLeadingSign) != NumberStyles.None; var allowParentheses = (options & NumberStyles.AllowParentheses) != NumberStyles.None; var allowThousands = (options & NumberStyles.AllowThousands) != NumberStyles.None; var allowExponent = (options & NumberStyles.AllowExponent) != NumberStyles.None; var allowTrailingWhite = (options & NumberStyles.AllowTrailingWhite) != NumberStyles.None; var allowTrailingSign = (options & NumberStyles.AllowTrailingSign) != NumberStyles.None; var allowDecimalPoint = (options & NumberStyles.AllowDecimalPoint) != NumberStyles.None; var isCurrency = false; number.Negative = false; var waitingParentheses = false; var positive = false; // [ws][$][sign][digits,]digits[E[sign]exponential_digits][ws] if (allowLeadingWhite) { reader.SkipWhile(CharHelper.IsClassicWhitespace); } // [$][sign][digits,]digits[E[sign]exponential_digits][ws] if (allowCurrencySymbol && reader.Read(currencySymbol)) { isCurrency = true; reader.SkipWhile(CharHelper.IsClassicWhitespace); } // [sign][digits,]digits[E[sign]exponential_digits][ws if (allowLeadingSign) { number.Negative |= reader.Read(negativeSign); positive |= reader.Read(positiveSign); } if (!number.Negative && allowParentheses && reader.Read('(')) { // Testing on .NET show that $(n) is allowed, even tho there is no CurrencyNegativePattern for it number.Negative = true; waitingParentheses = true; } // --- if (!isCurrency && allowCurrencySymbol && reader.Read(currencySymbol)) // If the currency symbol is after the negative sign { isCurrency = true; reader.SkipWhile(CharHelper.IsClassicWhitespace); } // [digits,]digits[E[sign]exponential_digits][ws] var failure = true; var digits = new[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; var decimalFound = false; while (true) { var input = reader.ReadWhile(digits); if (input == string.Empty) { if (allowDecimalPoint && !decimalFound) { if (reader.Read(info.CurrencyDecimalSeparator)) { decimalFound = true; continue; } if (reader.Read(info.NumberDecimalSeparator)) { if (isCurrency) { return(false); } decimalFound = true; continue; } } break; } failure = false; if (!decimalFound) { number.Scale += input.Length; } number.Digits.Append(input); if (allowThousands) { // Testing on .NET show that combining currency and number group separators is allowed // But not if the currency symbol has already appeared reader.SkipWhile(currencyGroupSeparator); if (!isCurrency) { reader.SkipWhile(numberGroupSeparator); } } } if (failure) { return(false); } // [E[sign]exponential_digits][ws] if (allowExponent && (reader.Read('E') || reader.Read('e'))) { // [sign]exponential_digits // Testing on .NET show that no pattern is used here, also no parentheses nor group separators supported // The exponent can be big - but anything beyond 9999 is ignored var exponentNegative = reader.Read(negativeSign); if (!exponentNegative) { reader.Read(positiveSign); } var input = reader.ReadWhile(digits); var exponentMagnitude = int.Parse(input, CultureInfo.InvariantCulture); number.Scale += (exponentNegative ? -1 : 1) * (input.Length > 4 ? 9999 : exponentMagnitude); if (number.Scale < 0) { return(false); } } // --- if (allowTrailingWhite) { reader.SkipWhile(CharHelper.IsClassicWhitespace); } if (!isCurrency && allowCurrencySymbol && reader.Read(currencySymbol)) { isCurrency = true; } // --- if (!number.Negative && !positive && allowTrailingSign) { number.Negative |= reader.Read(negativeSign); positive |= reader.Read(positiveSign); } if (waitingParentheses && !reader.Read(')')) { return(false); } // --- if (!isCurrency && allowCurrencySymbol && reader.Read(currencySymbol)) // If the currency symbol is after the negative sign { isCurrency = true; // For completeness sake } // [ws] if (allowTrailingWhite) { reader.SkipWhile(CharHelper.IsClassicWhitespace); } return(reader.EndOfString); } }