internal static bool Parse(string s, NumberStyles style, IFormatProvider provider, bool tryParse, out uint result, out Exception exc) { result = 0; exc = null; if (s == null) { if (!tryParse) { exc = new ArgumentNullException("s"); } return(false); } if (s.Length == 0) { if (!tryParse) { exc = Int32.GetFormatException(); } return(false); } NumberFormatInfo nfi = null; if (provider != null) { Type typeNFI = typeof(NumberFormatInfo); nfi = (NumberFormatInfo)provider.GetFormat(typeNFI); } if (nfi == null) { nfi = Thread.CurrentThread.CurrentCulture.NumberFormat; } if (!Int32.CheckStyle(style, tryParse, ref exc)) { return(false); } bool AllowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) != 0; bool AllowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) != 0; bool AllowThousands = (style & NumberStyles.AllowThousands) != 0; bool AllowDecimalPoint = (style & NumberStyles.AllowDecimalPoint) != 0; bool AllowParentheses = (style & NumberStyles.AllowParentheses) != 0; bool AllowTrailingSign = (style & NumberStyles.AllowTrailingSign) != 0; bool AllowLeadingSign = (style & NumberStyles.AllowLeadingSign) != 0; bool AllowTrailingWhite = (style & NumberStyles.AllowTrailingWhite) != 0; bool AllowLeadingWhite = (style & NumberStyles.AllowLeadingWhite) != 0; bool AllowExponent = (style & NumberStyles.AllowExponent) != 0; int pos = 0; if (AllowLeadingWhite && !Int32.JumpOverWhite(ref pos, s, true, tryParse, ref exc)) { return(false); } bool foundOpenParentheses = false; bool negative = false; bool foundSign = false; bool foundCurrency = false; // Pre-number stuff if (AllowParentheses && s [pos] == '(') { foundOpenParentheses = true; foundSign = true; negative = true; // MS always make the number negative when there parentheses // even when NumberFormatInfo.NumberNegativePattern != 0!!! pos++; if (AllowLeadingWhite && !Int32.JumpOverWhite(ref pos, s, true, tryParse, ref exc)) { return(false); } if (s.Substring(pos, nfi.NegativeSign.Length) == nfi.NegativeSign) { if (!tryParse) { exc = Int32.GetFormatException(); } return(false); } if (s.Substring(pos, nfi.PositiveSign.Length) == nfi.PositiveSign) { if (!tryParse) { exc = Int32.GetFormatException(); } return(false); } } if (AllowLeadingSign && !foundSign) { // Sign + Currency Int32.FindSign(ref pos, s, nfi, ref foundSign, ref negative); if (foundSign) { if (AllowLeadingWhite && !Int32.JumpOverWhite(ref pos, s, true, tryParse, ref exc)) { return(false); } if (AllowCurrencySymbol) { Int32.FindCurrency(ref pos, s, nfi, ref foundCurrency); if (foundCurrency && AllowLeadingWhite && !Int32.JumpOverWhite(ref pos, s, true, tryParse, ref exc)) { return(false); } } } } if (AllowCurrencySymbol && !foundCurrency) { // Currency + sign Int32.FindCurrency(ref pos, s, nfi, ref foundCurrency); if (foundCurrency) { if (AllowLeadingWhite && !Int32.JumpOverWhite(ref pos, s, true, tryParse, ref exc)) { return(false); } if (foundCurrency) { if (!foundSign && AllowLeadingSign) { Int32.FindSign(ref pos, s, nfi, ref foundSign, ref negative); if (foundSign && AllowLeadingWhite && !Int32.JumpOverWhite(ref pos, s, true, tryParse, ref exc)) { return(false); } } } } } uint number = 0; int nDigits = 0; int decimalPointPos = -1; uint digitValue; char hexDigit; // Number stuff // Just the same as Int32, but this one adds instead of substract while (pos < s.Length) { if (!Int32.ValidDigit(s [pos], AllowHexSpecifier)) { if (AllowThousands && (Int32.FindOther(ref pos, s, nfi.NumberGroupSeparator) || Int32.FindOther(ref pos, s, nfi.CurrencyGroupSeparator))) { continue; } if (AllowDecimalPoint && decimalPointPos < 0 && (Int32.FindOther(ref pos, s, nfi.NumberDecimalSeparator) || Int32.FindOther(ref pos, s, nfi.CurrencyDecimalSeparator))) { decimalPointPos = nDigits; continue; } break; } nDigits++; if (AllowHexSpecifier) { hexDigit = s [pos++]; if (Char.IsDigit(hexDigit)) { digitValue = (uint)(hexDigit - '0'); } else if (Char.IsLower(hexDigit)) { digitValue = (uint)(hexDigit - 'a' + 10); } else { digitValue = (uint)(hexDigit - 'A' + 10); } if (tryParse) { ulong l = number * 16 + digitValue; if (l > MaxValue) { return(false); } number = (uint)l; } else { number = checked (number * 16 + digitValue); } continue; } try { number = checked (number * 10 + (uint)(s [pos++] - '0')); } catch (OverflowException) { if (!tryParse) { exc = new OverflowException(Locale.GetText("Value too large or too small.")); } return(false); } } // Post number stuff if (nDigits == 0) { if (!tryParse) { exc = Int32.GetFormatException(); } return(false); } int exponent = 0; if (AllowExponent) { if (Int32.FindExponent(ref pos, s, ref exponent, tryParse, ref exc) && exc != null) { return(false); } } if (AllowTrailingSign && !foundSign) { // Sign + Currency Int32.FindSign(ref pos, s, nfi, ref foundSign, ref negative); if (foundSign && pos < s.Length) { if (AllowTrailingWhite && !Int32.JumpOverWhite(ref pos, s, true, tryParse, ref exc)) { return(false); } } } if (AllowCurrencySymbol && !foundCurrency) { if (AllowTrailingWhite && pos < s.Length && !Int32.JumpOverWhite(ref pos, s, false, tryParse, ref exc)) { return(false); } // Currency + sign Int32.FindCurrency(ref pos, s, nfi, ref foundCurrency); if (foundCurrency && pos < s.Length) { if (AllowTrailingWhite && !Int32.JumpOverWhite(ref pos, s, true, tryParse, ref exc)) { return(false); } if (!foundSign && AllowTrailingSign) { Int32.FindSign(ref pos, s, nfi, ref foundSign, ref negative); } } } if (AllowTrailingWhite && pos < s.Length && !Int32.JumpOverWhite(ref pos, s, false, tryParse, ref exc)) { return(false); } if (foundOpenParentheses) { if (pos >= s.Length || s [pos++] != ')') { if (!tryParse) { exc = Int32.GetFormatException(); } return(false); } if (AllowTrailingWhite && pos < s.Length && !Int32.JumpOverWhite(ref pos, s, false, tryParse, ref exc)) { return(false); } } if (pos < s.Length && s [pos] != '\u0000') { if (!tryParse) { exc = Int32.GetFormatException(); } return(false); } // -0 is legal but other negative values are not if (negative && (number > 0)) { if (!tryParse) { exc = new OverflowException( Locale.GetText("Negative number")); } return(false); } if (decimalPointPos >= 0) { exponent = exponent - nDigits + decimalPointPos; } if (exponent < 0) { // // Any non-zero values after decimal point are not allowed // long remainder; number = (uint)Math.DivRem(number, (int)Math.Pow(10, -exponent), out remainder); if (remainder != 0) { if (!tryParse) { exc = new OverflowException("Value too large or too small."); } return(false); } } else if (exponent > 0) { // // result *= 10^exponent // // Reduce the risk of throwing an overflow exc // double res = checked (Math.Pow(10, exponent) * number); if (res < MinValue || res > MaxValue) { if (!tryParse) { exc = new OverflowException("Value too large or too small."); } return(false); } number = (uint)res; } result = number; return(true); }
internal static bool Parse(string s, NumberStyles style, IFormatProvider fp, bool tryParse, out long result, out Exception exc) { result = 0; exc = null; if (s == null) { if (!tryParse) { exc = new ArgumentNullException("s"); } return(false); } if (s.Length == 0) { if (!tryParse) { exc = Int32.GetFormatException(); } return(false); } NumberFormatInfo nfi = null; if (fp != null) { Type typeNFI = typeof(System.Globalization.NumberFormatInfo); nfi = (NumberFormatInfo)fp.GetFormat(typeNFI); } if (nfi == null) { nfi = Thread.CurrentThread.CurrentCulture.NumberFormat; } if (!Int32.CheckStyle(style, tryParse, ref exc)) { return(false); } bool AllowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) != 0; bool AllowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) != 0; bool AllowThousands = (style & NumberStyles.AllowThousands) != 0; bool AllowDecimalPoint = (style & NumberStyles.AllowDecimalPoint) != 0; bool AllowParentheses = (style & NumberStyles.AllowParentheses) != 0; bool AllowTrailingSign = (style & NumberStyles.AllowTrailingSign) != 0; bool AllowLeadingSign = (style & NumberStyles.AllowLeadingSign) != 0; bool AllowTrailingWhite = (style & NumberStyles.AllowTrailingWhite) != 0; bool AllowLeadingWhite = (style & NumberStyles.AllowLeadingWhite) != 0; bool AllowExponent = (style & NumberStyles.AllowExponent) != 0; int pos = 0; if (AllowLeadingWhite && !Int32.JumpOverWhite(ref pos, s, true, tryParse, ref exc)) { return(false); } bool foundOpenParentheses = false; bool negative = false; bool foundSign = false; bool foundCurrency = false; // Pre-number stuff if (AllowParentheses && s [pos] == '(') { foundOpenParentheses = true; foundSign = true; negative = true; // MS always make the number negative when there parentheses // even when NumberFormatInfo.NumberNegativePattern != 0!!! pos++; if (AllowLeadingWhite && !Int32.JumpOverWhite(ref pos, s, true, tryParse, ref exc)) { return(false); } if (s.Substring(pos, nfi.NegativeSign.Length) == nfi.NegativeSign) { if (!tryParse) { exc = Int32.GetFormatException(); } return(false); } if (s.Substring(pos, nfi.PositiveSign.Length) == nfi.PositiveSign) { if (!tryParse) { exc = Int32.GetFormatException(); } return(false); } } if (AllowLeadingSign && !foundSign) { // Sign + Currency Int32.FindSign(ref pos, s, nfi, ref foundSign, ref negative); if (foundSign) { if (AllowLeadingWhite && !Int32.JumpOverWhite(ref pos, s, true, tryParse, ref exc)) { return(false); } if (AllowCurrencySymbol) { Int32.FindCurrency(ref pos, s, nfi, ref foundCurrency); if (foundCurrency && AllowLeadingWhite && !Int32.JumpOverWhite(ref pos, s, true, tryParse, ref exc)) { return(false); } } } } if (AllowCurrencySymbol && !foundCurrency) { // Currency + sign Int32.FindCurrency(ref pos, s, nfi, ref foundCurrency); if (foundCurrency) { if (AllowLeadingWhite && !Int32.JumpOverWhite(ref pos, s, true, tryParse, ref exc)) { return(false); } if (foundCurrency) { if (!foundSign && AllowLeadingSign) { Int32.FindSign(ref pos, s, nfi, ref foundSign, ref negative); if (foundSign && AllowLeadingWhite && !Int32.JumpOverWhite(ref pos, s, true, tryParse, ref exc)) { return(false); } } } } } long number = 0; int nDigits = 0; bool decimalPointFound = false; int digitValue; char hexDigit; int exponent = 0; // Number stuff do { if (!Int32.ValidDigit(s [pos], AllowHexSpecifier)) { if (AllowThousands && (Int32.FindOther(ref pos, s, nfi.NumberGroupSeparator) || Int32.FindOther(ref pos, s, nfi.CurrencyGroupSeparator))) { continue; } else if (!decimalPointFound && AllowDecimalPoint && (Int32.FindOther(ref pos, s, nfi.NumberDecimalSeparator) || Int32.FindOther(ref pos, s, nfi.CurrencyDecimalSeparator))) { decimalPointFound = true; continue; } break; } if (AllowHexSpecifier) { nDigits++; hexDigit = s [pos++]; if (Char.IsDigit(hexDigit)) { digitValue = (int)(hexDigit - '0'); } else if (Char.IsLower(hexDigit)) { digitValue = (int)(hexDigit - 'a' + 10); } else { digitValue = (int)(hexDigit - 'A' + 10); } ulong unumber = (ulong)number; // IMPROVME: We could avoid catching OverflowException try { number = (long)checked (unumber * 16ul + (ulong)digitValue); } catch (OverflowException e) { if (!tryParse) { exc = e; } return(false); } } else if (decimalPointFound) { nDigits++; // Allows decimal point as long as it's only // followed by zeroes. if (s [pos++] != '0') { if (!tryParse) { exc = new OverflowException("Value too large or too " + "small."); } return(false); } } else { nDigits++; try { // Calculations done as negative // (abs (MinValue) > abs (MaxValue)) number = checked ( number * 10 - (long)(s [pos++] - '0') ); } catch (OverflowException) { if (!tryParse) { exc = new OverflowException("Value too large or too " + "small."); } return(false); } } } while (pos < s.Length); // Post number stuff if (nDigits == 0) { if (!tryParse) { exc = Int32.GetFormatException(); } return(false); } if (AllowExponent) { if (Int32.FindExponent(ref pos, s, ref exponent, tryParse, ref exc) && exc != null) { return(false); } } if (AllowTrailingSign && !foundSign) { // Sign + Currency Int32.FindSign(ref pos, s, nfi, ref foundSign, ref negative); if (foundSign && pos < s.Length) { if (AllowTrailingWhite && !Int32.JumpOverWhite(ref pos, s, true, tryParse, ref exc)) { return(false); } } } if (AllowCurrencySymbol && !foundCurrency) { if (AllowTrailingWhite && pos < s.Length && !Int32.JumpOverWhite(ref pos, s, false, tryParse, ref exc)) { return(false); } // Currency + sign Int32.FindCurrency(ref pos, s, nfi, ref foundCurrency); if (foundCurrency && pos < s.Length) { if (AllowTrailingWhite && !Int32.JumpOverWhite(ref pos, s, true, tryParse, ref exc)) { return(false); } if (!foundSign && AllowTrailingSign) { Int32.FindSign(ref pos, s, nfi, ref foundSign, ref negative); } } } if (AllowTrailingWhite && pos < s.Length && !Int32.JumpOverWhite(ref pos, s, false, tryParse, ref exc)) { return(false); } if (foundOpenParentheses) { if (pos >= s.Length || s [pos++] != ')') { if (!tryParse) { exc = Int32.GetFormatException(); } return(false); } if (AllowTrailingWhite && pos < s.Length && !Int32.JumpOverWhite(ref pos, s, false, tryParse, ref exc)) { return(false); } } if (pos < s.Length && s [pos] != '\u0000') { if (!tryParse) { exc = Int32.GetFormatException(); } return(false); } if (!negative && !AllowHexSpecifier) { try { number = checked (-number); } catch (OverflowException e) { if (!tryParse) { exc = e; } return(false); } } // result *= 10^exponent if (exponent > 0) { // Reduce the risk of throwing an overflow exc double res = checked (Math.Pow(10, exponent) * number); if (res < Int32.MinValue || res > Int32.MaxValue) { if (!tryParse) { exc = new OverflowException("Value too large or too small."); } return(false); } number = (long)res; } result = number; return(true); }