X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2Fcorlib%2FSystem%2FInt32.cs;h=b78c0a5b14ec32b54a26167defe075bf8f6734db;hb=60979ce4a41d1be8f9d3d4d38162c0803207b4d5;hp=01923673ee133886025403d23553a4b00067b33b;hpb=c4aef31eeea309e6a795c84c098ac8e1a2490340;p=mono.git diff --git a/mcs/class/corlib/System/Int32.cs b/mcs/class/corlib/System/Int32.cs index 01923673ee1..b78c0a5b14e 100644 --- a/mcs/class/corlib/System/Int32.cs +++ b/mcs/class/corlib/System/Int32.cs @@ -1,11 +1,13 @@ // // System.Int32.cs // -// Author: +// Authors: // Miguel de Icaza (miguel@ximian.com) +// Marek Safar (marek.safar@gmail.com) // // (C) Ximian, Inc. http://www.ximian.com // Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// Copyright (C) 2012 Xamarin Inc (http://www.xamarin.com) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -33,10 +35,8 @@ using System.Threading; namespace System { [Serializable] - public struct Int32 : IFormattable, IConvertible, IComparable -#if NET_2_0 - , IComparable, IEquatable -#endif + [System.Runtime.InteropServices.ComVisible (true)] + public struct Int32 : IFormattable, IConvertible, IComparable, IComparable, IEquatable { public const int MaxValue = 0x7fffffff; @@ -45,15 +45,15 @@ namespace System { // This field is looked up by name in the runtime internal int m_value; - public int CompareTo (object v) + public int CompareTo (object value) { - if (v == null) + if (value == null) return 1; - if (!(v is System.Int32)) + if (!(value is System.Int32)) throw new ArgumentException (Locale.GetText ("Value is not a System.Int32")); - int xv = (int) v; + int xv = (int) value; if (m_value == xv) return 0; if (m_value > xv) @@ -62,12 +62,12 @@ namespace System { return -1; } - public override bool Equals (object o) + public override bool Equals (object obj) { - if (!(o is System.Int32)) + if (!(obj is System.Int32)) return false; - return ((int) o) == m_value; + return ((int) obj) == m_value; } public override int GetHashCode () @@ -75,7 +75,6 @@ namespace System { return m_value; } -#if NET_2_0 public int CompareTo (int value) { if (m_value == value) @@ -86,11 +85,26 @@ namespace System { return -1; } - public bool Equals (int value) + public bool Equals (int obj) { - return value == m_value; + return obj == m_value; + } + + internal static bool ProcessTrailingWhitespace (bool tryParse, string s, int position, ref Exception exc) + { + int len = s.Length; + + for (int i = position; i < len; i++){ + char c = s [i]; + + if (c != 0 && !Char.IsWhiteSpace (c)){ + if (!tryParse) + exc = GetFormatException (); + return false; + } + } + return true; } -#endif internal static bool Parse (string s, bool tryParse, out int result, out Exception exc) { @@ -101,6 +115,7 @@ namespace System { result = 0; exc = null; + NumberFormatInfo nfi = Thread.CurrentThread.CurrentCulture.NumberFormat; if (s == null) { if (!tryParse) @@ -123,12 +138,13 @@ namespace System { return false; } - c = s [i]; - if (c == '+') - i++; - else if (c == '-'){ + var ps_length = nfi.PositiveSign.Length; + var ns_length = nfi.NegativeSign.Length; + if (len > ps_length && string.CompareOrdinalUnchecked (s, i, ns_length, nfi.PositiveSign, 0, ps_length) == 0) + i += ps_length; + else if (len > ns_length && string.CompareOrdinalUnchecked (s, i, ns_length, nfi.NegativeSign, 0, ns_length) == 0) { sign = -1; - i++; + i += ns_length; } for (; i < len; i++){ @@ -140,30 +156,30 @@ namespace System { } if (c >= '0' && c <= '9'){ - try { - val = checked (val * 10 + (c - '0') * sign); - digits_seen = true; - } catch (OverflowException e) { - exc = new OverflowException (); - return false; - } - } else { - if (Char.IsWhiteSpace (c)){ - for (i++; i < len; i++){ - if (!Char.IsWhiteSpace (s [i])) { - if (!tryParse) - exc = GetFormatException (); - return false; - - } + byte d = (byte) (c - '0'); + + if (val > (MaxValue/10)) + goto overflow; + + if (val == (MaxValue/10)){ + if ((d > (MaxValue % 10)) && (sign == 1 || (d > ((MaxValue % 10) + 1)))) + goto overflow; + if (sign == -1) + val = (val * sign * 10) - d; + else + val = (val * 10) + d; + + if (ProcessTrailingWhitespace (tryParse, s, i + 1, ref exc)){ + result = val; + return true; } - break; - } else { - if (!tryParse) - exc = GetFormatException (); - return false; - } - } + goto overflow; + } else + val = val * 10 + d; + + digits_seen = true; + } else if (!ProcessTrailingWhitespace (tryParse, s, i, ref exc)) + return false; } if (!digits_seen) { if (!tryParse) @@ -171,14 +187,22 @@ namespace System { return false; } - result = val; + if (sign == -1) + result = val * sign; + else + result = val; return true; + + overflow: + if (!tryParse) + exc = new OverflowException ("Value is too large"); + return false; } - public static int Parse (string s, IFormatProvider fp) + public static int Parse (string s, IFormatProvider provider) { - return Parse (s, NumberStyles.Integer, fp); + return Parse (s, NumberStyles.Integer, provider); } public static int Parse (string s, NumberStyles style) @@ -202,6 +226,10 @@ namespace System { "are permitted."); return false; } + } else if ((uint) style > (uint) NumberStyles.Any){ + if (!tryParse) + exc = new ArgumentException ("Not a valid number style"); + return false; } return true; @@ -225,13 +253,12 @@ namespace System { ref bool foundSign, ref bool negative) { if ((pos + nfi.NegativeSign.Length) <= s.Length && - s.IndexOf (nfi.NegativeSign, pos, nfi.NegativeSign.Length) == pos) { + s.IndexOfOrdinalUnchecked (nfi.NegativeSign, pos, nfi.NegativeSign.Length) == pos) { negative = true; foundSign = true; pos += nfi.NegativeSign.Length; - } - else if ((pos + nfi.PositiveSign.Length) < s.Length && - s.IndexOf (nfi.PositiveSign, pos, nfi.PositiveSign.Length) == pos) { + } else if ((pos + nfi.PositiveSign.Length) <= s.Length && + s.IndexOfOrdinalUnchecked (nfi.PositiveSign, pos, nfi.PositiveSign.Length) == pos) { negative = false; pos += nfi.PositiveSign.Length; foundSign = true; @@ -250,21 +277,52 @@ namespace System { } } - internal static bool FindExponent (ref int pos, string s) + internal static bool FindExponent (ref int pos, string s, ref int exponent, bool tryParse, ref Exception exc) { - int i = s.IndexOfAny(new char [] {'e', 'E'}, pos); - if (i < 0) - return false; - if (++i == s.Length) - return false; - if (s [i] == '+' || s [i] == '-') - if (++i == s.Length) - return false; - if (!Char.IsDigit (s [i])) - return false; - for (; i < s.Length; ++i) - if (!Char.IsDigit (s [i])) - break; + exponent = 0; + + if (pos >= s.Length || (s [pos] != 'e' && s[pos] != 'E')) { + exc = null; + return false; + } + + var i = pos + 1; + if (i == s.Length) { + exc = tryParse ? null : GetFormatException (); + return true; + } + + // negative exponent not valid for Int32 + if (s [i] == '-') { + exc = tryParse ? null : new OverflowException ("Value too large or too small."); + return true; + } + + if (s [i] == '+' && ++i == s.Length) { + exc = tryParse ? null : GetFormatException (); + return true; + } + + long exp = 0; // temp long value + for (; i < s.Length; i++) { + if (!Char.IsDigit (s [i])) { + exc = tryParse ? null : GetFormatException (); + return true; + } + + // Reduce the risk of throwing an overflow exc + exp = checked (exp * 10 - (int) (s [i] - '0')); + if (exp < Int32.MinValue || exp > Int32.MaxValue) { + exc = tryParse ? null : new OverflowException ("Value too large or too small."); + return true; + } + } + + // exp value saved as negative + exp = -exp; + + exc = null; + exponent = (int)exp; pos = i; return true; } @@ -302,13 +360,7 @@ namespace System { if (s == null) { if (!tryParse) - exc = GetFormatException (); - return false; - } - - if (s == null) { - if (!tryParse) - exc = new ArgumentNullException (); + exc = new ArgumentNullException ("s"); return false; } @@ -318,12 +370,12 @@ namespace System { return false; } - NumberFormatInfo nfi; + NumberFormatInfo nfi = null; if (fp != null) { Type typeNFI = typeof (System.Globalization.NumberFormatInfo); nfi = (NumberFormatInfo) fp.GetFormat (typeNFI); } - else + if (nfi == null) nfi = Thread.CurrentThread.CurrentCulture.NumberFormat; if (!CheckStyle (style, tryParse, ref exc)) @@ -357,7 +409,7 @@ namespace System { negative = true; // MS always make the number negative when there parentheses // even when NumberFormatInfo.NumberNegativePattern != 0!!! pos++; - if (AllowLeadingWhite && !!JumpOverWhite (ref pos, s, true, tryParse, ref exc)) + if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc)) return false; if (s.Substring (pos, nfi.NegativeSign.Length) == nfi.NegativeSign) { @@ -409,7 +461,7 @@ namespace System { int number = 0; int nDigits = 0; - bool decimalPointFound = false; + int decimalPointPos = -1; int digitValue; char hexDigit; @@ -418,19 +470,23 @@ namespace System { if (!ValidDigit (s [pos], AllowHexSpecifier)) { if (AllowThousands && - FindOther (ref pos, s, nfi.NumberGroupSeparator)) + (FindOther (ref pos, s, nfi.NumberGroupSeparator) + || FindOther (ref pos, s, nfi.CurrencyGroupSeparator))) continue; - else - if (!decimalPointFound && AllowDecimalPoint && - FindOther (ref pos, s, nfi.NumberDecimalSeparator)) { - decimalPointFound = true; + + if (AllowDecimalPoint && decimalPointPos < 0 && + (FindOther (ref pos, s, nfi.NumberDecimalSeparator) + || FindOther (ref pos, s, nfi.CurrencyDecimalSeparator))) { + decimalPointPos = nDigits; continue; } break; } - else if (AllowHexSpecifier) { - nDigits++; + + nDigits++; + + if (AllowHexSpecifier) { hexDigit = s [pos++]; if (Char.IsDigit (hexDigit)) digitValue = (int) (hexDigit - '0'); @@ -440,40 +496,26 @@ namespace System { digitValue = (int) (hexDigit - 'A' + 10); uint unumber = (uint)number; - try { + if (tryParse){ + if ((unumber & 0xf0000000) != 0) + return false; + + number = (int) (unumber * 16u + (uint) digitValue); + } else { number = (int)checked (unumber * 16u + (uint)digitValue); - } catch (OverflowException e) { - 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; } + + continue; } - else { - nDigits++; - - try { - // Calculations done as negative - // (abs (MinValue) > abs (MaxValue)) - number = checked ( - number * 10 - - (int) (s [pos++] - '0') - ); - } catch (OverflowException) { - if (!tryParse) - exc = new OverflowException ("Value too large or too " + - "small."); - return false; - } + + try { + // Calculations done as negative + // (abs (MinValue) > abs (MaxValue)) + number = checked (number * 10 - (int) (s [pos++] - '0')); + } catch (OverflowException) { + if (!tryParse) + exc = new OverflowException ("Value too large or too small."); + return false; } } while (pos < s.Length); @@ -484,26 +526,28 @@ namespace System { return false; } - if (AllowExponent) - FindExponent(ref pos, s); + int exponent = 0; + if (AllowExponent) + if (FindExponent (ref pos, s, ref exponent, tryParse, ref exc) && exc != null) + return false; if (AllowTrailingSign && !foundSign) { // Sign + Currency FindSign (ref pos, s, nfi, ref foundSign, ref negative); - if (foundSign) { + if (foundSign && pos < s.Length) { if (AllowTrailingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc)) return false; - if (AllowCurrencySymbol) - FindCurrency (ref pos, s, nfi, - ref foundCurrency); } } if (AllowCurrencySymbol && !foundCurrency) { + if (AllowTrailingWhite && pos < s.Length && !JumpOverWhite (ref pos, s, false, tryParse, ref exc)) + return false; + // Currency + sign FindCurrency (ref pos, s, nfi, ref foundCurrency); - if (foundCurrency) { - if (AllowTrailingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc)) + if (foundCurrency && pos < s.Length) { + if (AllowTrailingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc)) return false; if (!foundSign && AllowTrailingSign) FindSign (ref pos, s, nfi, ref foundSign, @@ -520,8 +564,7 @@ namespace System { exc = GetFormatException (); return false; } - if (AllowTrailingWhite && pos < s.Length && - !JumpOverWhite (ref pos, s, false, tryParse, ref exc)) + if (AllowTrailingWhite && pos < s.Length && !JumpOverWhite (ref pos, s, false, tryParse, ref exc)) return false; } @@ -531,11 +574,48 @@ namespace System { return false; } - if (!negative && !AllowHexSpecifier) - number = checked (-number); + if (!negative && !AllowHexSpecifier){ + if (tryParse){ + long lval = -((long)number); - result = number; + if (lval < MinValue || lval > MaxValue) + return false; + number = (int) lval; + } else + number = checked (-number); + } + + if (decimalPointPos >= 0) + exponent = exponent - nDigits + decimalPointPos; + + if (exponent < 0) { + // + // Any non-zero values after decimal point are not allowed + // + int remainder; + number = 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 = (int)res; + } + + result = number; return true; } @@ -550,22 +630,20 @@ namespace System { return res; } - public static int Parse (string s, NumberStyles style, IFormatProvider fp) + public static int Parse (string s, NumberStyles style, IFormatProvider provider) { Exception exc; int res; - if (!Parse (s, style, fp, false, out res, out exc)) + if (!Parse (s, style, provider, false, out res, out exc)) throw exc; return res; } -#if NET_2_0 public static bool TryParse (string s, out int result) { Exception exc; - if (!Parse (s, true, out result, out exc)) { result = 0; return false; @@ -584,16 +662,15 @@ namespace System { return true; } -#endif public override string ToString () { - return NumberFormatter.FormatGeneral (new NumberFormatter.NumberStore (m_value)); + return NumberFormatter.NumberToString (m_value, null); } - public string ToString (IFormatProvider fp) + public string ToString (IFormatProvider provider) { - return NumberFormatter.FormatGeneral (new NumberFormatter.NumberStore (m_value), fp); + return NumberFormatter.NumberToString (m_value, provider); } public string ToString (string format) @@ -601,10 +678,9 @@ namespace System { return ToString (format, null); } - public string ToString (string format, IFormatProvider fp ) + public string ToString (string format, IFormatProvider provider) { - NumberFormatInfo nfi = NumberFormatInfo.GetInstance( fp ); - return NumberFormatter.NumberToString (format, m_value, nfi); + return NumberFormatter.NumberToString (format, m_value, provider); } // =========== IConvertible Methods =========== // @@ -613,68 +689,80 @@ namespace System { { return TypeCode.Int32; } - - bool IConvertible.ToBoolean (IFormatProvider provider) + + bool IConvertible.ToBoolean (IFormatProvider provider) { return System.Convert.ToBoolean (m_value); } - byte IConvertible.ToByte (IFormatProvider provider) + + byte IConvertible.ToByte (IFormatProvider provider) { return System.Convert.ToByte (m_value); } - char IConvertible.ToChar (IFormatProvider provider) + + char IConvertible.ToChar (IFormatProvider provider) { return System.Convert.ToChar (m_value); } + DateTime IConvertible.ToDateTime (IFormatProvider provider) { return System.Convert.ToDateTime (m_value); } - decimal IConvertible.ToDecimal (IFormatProvider provider) + + decimal IConvertible.ToDecimal (IFormatProvider provider) { return System.Convert.ToDecimal (m_value); } - double IConvertible.ToDouble (IFormatProvider provider) + + double IConvertible.ToDouble (IFormatProvider provider) { return System.Convert.ToDouble (m_value); } - short IConvertible.ToInt16 (IFormatProvider provider) + + short IConvertible.ToInt16 (IFormatProvider provider) { return System.Convert.ToInt16 (m_value); } - int IConvertible.ToInt32 (IFormatProvider provider) + + int IConvertible.ToInt32 (IFormatProvider provider) { return m_value; } - long IConvertible.ToInt64 (IFormatProvider provider) + + long IConvertible.ToInt64 (IFormatProvider provider) { return System.Convert.ToInt64 (m_value); } - sbyte IConvertible.ToSByte (IFormatProvider provider) + sbyte IConvertible.ToSByte (IFormatProvider provider) { return System.Convert.ToSByte (m_value); } - float IConvertible.ToSingle (IFormatProvider provider) + + float IConvertible.ToSingle (IFormatProvider provider) { return System.Convert.ToSingle (m_value); } - object IConvertible.ToType (Type conversionType, IFormatProvider provider) + object IConvertible.ToType (Type targetType, IFormatProvider provider) { - return System.Convert.ToType (m_value, conversionType, provider); + if (targetType == null) + throw new ArgumentNullException ("targetType"); + return System.Convert.ToType (m_value, targetType, provider, false); } - - ushort IConvertible.ToUInt16 (IFormatProvider provider) + + ushort IConvertible.ToUInt16 (IFormatProvider provider) { return System.Convert.ToUInt16 (m_value); } - uint IConvertible.ToUInt32 (IFormatProvider provider) + uint IConvertible.ToUInt32 (IFormatProvider provider) { return System.Convert.ToUInt32 (m_value); } - ulong IConvertible.ToUInt64 (IFormatProvider provider) + + ulong IConvertible.ToUInt64 (IFormatProvider provider) { return System.Convert.ToUInt64 (m_value); }