2002-07-10 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mcs / class / corlib / System / Convert.cs
index fe0f03133ff5ea504ea0392f2aaa840e860ed911..97b7800e9ac89c580fed4f2045261266caffc08a 100644 (file)
@@ -78,7 +78,7 @@ namespace System {
        public sealed class Convert {\r
 \r
                // Fields\r
-               public static readonly object DBNull;\r
+               public static readonly object DBNull = System.DBNull.Value;\r
        \r
                private Convert () {}\r
 \r
@@ -126,9 +126,7 @@ namespace System {
 \r
                public static bool IsDBNull (object value)\r
                {\r
-                       TypeCode tc = Type.GetTypeCode (value.GetType ());\r
-                       \r
-                       if (tc == TypeCode.DBNull)\r
+                       if (value is DBNull)\r
                                return true;\r
                        else\r
                                return false;\r
@@ -395,7 +393,13 @@ namespace System {
 \r
                public static byte ToByte (string value, int fromBase)\r
                {\r
-                       return (byte) ConvertFromBase (value, fromBase);\r
+\r
+                       int retVal = ConvertFromBase (value, fromBase);\r
+\r
+                       if (retVal < (int) Byte.MinValue || retVal > (int) Byte.MaxValue)\r
+                               throw new OverflowException ();\r
+                       else\r
+                               return (byte) retVal;\r
                }\r
 \r
                [CLSCompliant (false)]\r
@@ -701,7 +705,7 @@ namespace System {
 \r
                public static decimal ToDecimal (float value) \r
                {\r
-                       return (decimal) Math.Round (value);                            \r
+                       return (decimal) value;\r
                }\r
 \r
                public static decimal ToDecimal (int value) \r
@@ -775,7 +779,7 @@ namespace System {
        \r
                public static double ToDouble (byte value) \r
                { \r
-                       throw new InvalidCastException ("This conversion is not supported.");\r
+                       return (double) value;\r
                }\r
 \r
                public static double ToDouble (char value)\r
@@ -800,7 +804,7 @@ namespace System {
 \r
                public static double ToDouble (float value) \r
                { \r
-                       return (double) Math.Round (value);       \r
+                       return (double) value;\r
                }\r
 \r
                public static double ToDouble (int value) \r
@@ -962,7 +966,7 @@ namespace System {
                \r
                public static short ToInt16 (string value, int fromBase)\r
                {\r
-                       return (short) ConvertFromBase (value, fromBase);\r
+                       return Convert.ToInt16 (ConvertFromBase (value, fromBase));\r
                }\r
 \r
                [CLSCompliant (false)]\r
@@ -1227,7 +1231,7 @@ namespace System {
                        if (NotValidBase (fromBase))\r
                                throw new ArgumentException ("fromBase is not valid.");\r
                        \r
-                       return (long) ConvertFromBase (value, fromBase);\r
+                       return ConvertFromBase64 (value, fromBase);\r
                }\r
 \r
                [CLSCompliant (false)]\r
@@ -1382,7 +1386,15 @@ namespace System {
                [CLSCompliant (false)]\r
                public static sbyte ToSByte (string value, int fromBase)\r
                {\r
-                       return (sbyte) ConvertFromBase (value, fromBase);\r
+                       int retVal = ConvertFromBase (value, fromBase);\r
+\r
+                       if (retVal == 255)\r
+                               return (sbyte)-1;\r
+\r
+                       if (retVal < (int) SByte.MinValue || retVal > (int) SByte.MaxValue)\r
+                               throw new OverflowException ();\r
+                       else\r
+                               return (sbyte) retVal;\r
                }\r
                \r
                [CLSCompliant (false)]\r
@@ -1640,7 +1652,7 @@ namespace System {
                        if (NotValidBase (toBase))\r
                                throw new ArgumentException ("toBase is not valid.");\r
                        \r
-                       return ConvertToBase ((int) value, toBase);\r
+                       return ConvertToBase (value, toBase);\r
                }\r
 \r
                public static string ToString (long value, IFormatProvider provider) \r
@@ -2240,15 +2252,65 @@ namespace System {
                {\r
                        if (NotValidBase (fromBase))\r
                                throw new ArgumentException ("fromBase is not valid.");\r
-                       \r
+\r
+                       int chars = 0;\r
                        int result = 0;\r
+                       int digitValue;\r
 \r
                        foreach (char c in value) {\r
-                               if (Char.IsLetter (c))\r
-                                       result = (fromBase) * result + c - 'a' + 10;\r
+                               if (Char.IsNumber (c))\r
+                                       digitValue = c - '0';\r
+                               else if (Char.IsLetter (c))\r
+                                       digitValue = Char.ToLower(c) - 'a' + 10;\r
                                else\r
-                                       result = (fromBase) * result + c - '0';\r
+                                       throw new FormatException ("This is an invalid string: " + value);\r
+\r
+                               if (digitValue >= fromBase)\r
+                                       throw new FormatException ("the digits are invalid.");\r
+\r
+                               result = (fromBase) * result + digitValue;\r
+                               chars ++;\r
                        }\r
+\r
+                       if (chars == 0)\r
+                               throw new FormatException ("Could not find any digits.");\r
+\r
+                       if (result > Int32.MaxValue || result < Int32.MinValue)\r
+                               throw new OverflowException ("There is an overflow.");\r
+                       \r
+                       return result;\r
+               }\r
+\r
+               private static long ConvertFromBase64 (string value, int fromBase)\r
+               {\r
+                       if (NotValidBase (fromBase))\r
+                               throw new ArgumentException ("fromBase is not valid.");\r
+\r
+                       int chars = 0;\r
+                       int digitValue;\r
+                       long result = 0;\r
+\r
+                       foreach (char c in value) {\r
+                               if (Char.IsNumber (c))\r
+                                       digitValue = c - '0';\r
+                               else if (Char.IsLetter (c))\r
+                                       digitValue = Char.ToLower(c) - 'a' + 10;\r
+                               else\r
+                                       throw new FormatException ("This is an invalid string: " + value);\r
+\r
+                               if (digitValue >= fromBase)\r
+                                       throw new FormatException ("the digits are invalid.");\r
+\r
+                               result = (fromBase) * result + digitValue;\r
+                               chars ++;\r
+                       }\r
+\r
+                       if (chars == 0)\r
+                               throw new FormatException ("Could not find any digits.");\r
+\r
+                       if (result > Int64.MaxValue || result < Int64.MinValue)\r
+                               throw new OverflowException ("There is an overflow.");\r
+                       \r
                        return result;\r
                }\r
 \r
@@ -2259,6 +2321,14 @@ namespace System {
                        return sb.ToString ();\r
                }\r
 \r
+               private static string ConvertToBase (long value, int toBase)\r
+               {\r
+                       StringBuilder sb = new StringBuilder ();\r
+                       BuildConvertedString64 (sb, value, toBase);\r
+                       return sb.ToString ();\r
+               }\r
+               \r
+\r
                internal static void BuildConvertedString (StringBuilder sb, int value, int toBase)\r
                {\r
                        int divided = value / toBase;\r
@@ -2272,30 +2342,45 @@ namespace System {
                        else\r
                                sb.Append ((char) (reminder + '0'));\r
                }\r
+\r
+               internal static void BuildConvertedString64 (StringBuilder sb, long value, int toBase)\r
+               {\r
+                       long divided = value / toBase;\r
+                       long reminder = value % toBase;         \r
+\r
+                       if (divided > 0)\r
+                               BuildConvertedString64 (sb, divided, toBase);\r
+               \r
+                       if (reminder >= 10)\r
+                               sb.Append ((char) (reminder + 'a' - 10));\r
+                       else\r
+                               sb.Append ((char) (reminder + '0'));\r
+               }\r
                \r
                 // Lookup table for the conversion ToType method. Order\r
                // is important! Used by ToType for comparing the target\r
                // type, and uses hardcoded array indexes.\r
                private static Type[] conversionTable = {\r
                        // Valid ICovnertible Types\r
-                       typeof (Boolean),  //  0 TypeCode.Boolean\r
-                       typeof (Byte),     //  1 TypeCode.Byte\r
-                       typeof (Char),     //  2 TypeCode.Char\r
-                       typeof (DateTime), //  3 TypeCode.DateTime\r
-                       typeof (Decimal),  //  4 TypeCode.Decimal\r
-                       typeof (Double),   //  5 TypeCode.Double\r
-                       typeof (Int16),    //  6 TypeCode.Int16\r
-                       typeof (Int32),    //  7 TypeCode.Int32\r
-                       typeof (Int64),    //  8 TypeCode.Int64\r
-                       typeof (SByte),    //  9 TypeCode.Sbyte\r
-                       typeof (Single),   // 10 TypeCode.Single\r
-                       typeof (String),   // 11 TypeCode.String\r
-                       typeof (UInt16),   // 12 TypeCode.UInt16\r
-                       typeof (UInt32),   // 13 TypeCode.UInt32\r
-                       typeof (UInt64),   // 14 TypeCode.UInt64\r
-         \r
-                       // Invalid IConvertible Interface Types\r
-                       typeof (Object)    // 15 TypeCode.Object\r
+                       null,              //  0 empty\r
+                       typeof (object),   //  1 TypeCode.Object\r
+                       typeof (DBNull),   //  2 TypeCode.DBNull\r
+                       typeof (Boolean),  //  3 TypeCode.Boolean\r
+                       typeof (Char),     //  4 TypeCode.Char\r
+                       typeof (SByte),    //  5 TypeCode.SByte\r
+                       typeof (Byte),     //  6 TypeCode.Byte\r
+                       typeof (Int16),    //  7 TypeCode.Int16\r
+                       typeof (UInt16),   //  8 TypeCode.UInt16\r
+                       typeof (Int32),    //  9 TypeCode.Int32\r
+                       typeof (UInt32),   // 10 TypeCode.UInt32\r
+                       typeof (Int64),    // 11 TypeCode.Int64\r
+                       typeof (UInt64),   // 12 TypeCode.UInt64\r
+                       typeof (Single),   // 13 TypeCode.Single\r
+                       typeof (Double),   // 14 TypeCode.Double\r
+                       typeof (Decimal),  // 15 TypeCode.Decimal\r
+                       typeof (DateTime), // 16 TypeCode.DateTime\r
+                       null,              // 17 null.\r
+                       typeof (String),   // 18 TypeCode.String\r
                };\r
 \r
                // Function to convert an object to another type and return\r
@@ -2305,91 +2390,74 @@ namespace System {
                internal static object ToType (object value, Type conversionType, \r
                                               IFormatProvider provider) \r
                {\r
+                       if (value == null && conversionType == null)\r
+                               return null;\r
+                       \r
                        if (value == null)\r
-                               throw new ArgumentException (Locale.GetText (\r
-                                       "Invalid conversion from null value"));\r
-\r
+                               throw new NullReferenceException ("Value is null.");\r
+                       \r
                        if (value is IConvertible) {\r
-                               IConvertible convertValue = (IConvertible)value;\r
-\r
-                               if (conversionType == conversionTable[0]) {\r
-                                       // 0 TypeCode.Boolean\r
-                                       return (object)(convertValue.ToBoolean (provider));\r
+                               IConvertible convertValue = (IConvertible) value;\r
 \r
-                               } else if (conversionType == conversionTable[1]) {\r
-                                       // 1 TypeCode.Byte\r
-                                       return (object)(convertValue.ToByte (provider));\r
-                 \r
-                               } else if (conversionType == conversionTable[2]) {\r
-                                       // 2 TypeCode.Char\r
-                                       return (object)(convertValue.ToChar (provider));\r
-                 \r
-                               } else if (conversionType == conversionTable[3]) {\r
-                                       // 3 TypeCode.DateTime\r
-                                       return (object)(convertValue.ToDateTime (provider));\r
+                               if (conversionType == conversionTable[0]) // 0 Empty\r
+                                       throw new ArgumentNullException ();\r
+                               \r
+                               else if (conversionType == conversionTable[1]) // 1 TypeCode.Object\r
+                                       return (object) value;\r
+                                       \r
+                               else if (conversionType == conversionTable[2]) // 2 TypeCode.DBNull\r
+                                       throw new InvalidCastException ();     // It's not IConvertible\r
                  \r
-                               } else if (conversionType == conversionTable[4]) {\r
-                                       // 4 TypeCode.Decimal\r
-                                       return (object)(convertValue.ToDecimal (provider));\r
+                               else if (conversionType == conversionTable[3]) // 3 TypeCode.Boolean\r
+                                       return (object) convertValue.ToBoolean (provider);\r
+                                       \r
+                               else if (conversionType == conversionTable[4]) // 4 TypeCode.Char\r
+                                       return (object) convertValue.ToChar (provider);\r
                  \r
-                               } else if (conversionType == conversionTable[5]) {\r
-                                       // 5 TypeCode.Double\r
-                                       return (object)(convertValue.ToDouble (provider));\r
+                               else if (conversionType == conversionTable[5]) // 5 TypeCode.SByte\r
+                                       return (object) convertValue.ToSByte (provider);\r
 \r
-                               } else if (conversionType == conversionTable[6]) {\r
-                                       // 6 TypeCode.Int16\r
-                                       return (object)(convertValue.ToInt16 (provider));\r
-                 \r
-                               } else if (conversionType == conversionTable[7]) {\r
-                                       // 7 TypeCode.Int32\r
-                                       return (object)(convertValue.ToInt32 (provider));\r
-                 \r
-                               } else if (conversionType == conversionTable[8]) {\r
-                                       // 8 TypeCode.Int64\r
-                                       return (object)(convertValue.ToInt64 (provider));\r
-                 \r
-                               } else if (conversionType == conversionTable[9]) {\r
-                                       // 9 TypeCode.Sbyte\r
-                                       return (object)(convertValue.ToSByte (provider));\r
+                               else if (conversionType == conversionTable[6]) // 6 TypeCode.Byte\r
+                                       return (object) convertValue.ToByte (provider);\r
+                               \r
+                               else if (conversionType == conversionTable[7]) // 7 TypeCode.Int16\r
+                                       return (object) convertValue.ToInt16 (provider);\r
+                                       \r
+                               else if (conversionType == conversionTable[8]) // 8 TypeCode.UInt16\r
+                                       return (object) convertValue.ToUInt16 (provider);\r
                  \r
-                               } else if (conversionType == conversionTable[10]) {\r
-                                       // 10 TypeCode.Single\r
-                                       return (object)(convertValue.ToSingle (provider));\r
+                               else if (conversionType == conversionTable[9]) // 9 TypeCode.Int32\r
+                                       return (object) convertValue.ToInt32 (provider);\r
+                       \r
+                               else if (conversionType == conversionTable[10]) // 10 TypeCode.UInt32\r
+                                       return (object) convertValue.ToUInt32 (provider);\r
                  \r
-                               } else if (conversionType == conversionTable[11]) {\r
-                                       // 11 TypeCode.String\r
-                                       return (object)(convertValue.ToString (provider));\r
+                               else if (conversionType == conversionTable[11]) // 11 TypeCode.Int64\r
+                                       return (object) convertValue.ToInt64 (provider);\r
                  \r
-                               } else if (conversionType == conversionTable[12]) {  \r
-                                       // 12 TypeCode.UInt16\r
-                                       return (object)(convertValue.ToUInt16 (provider));\r
+                               else if (conversionType == conversionTable[12]) // 12 TypeCode.UInt64\r
+                                       return (object) convertValue.ToUInt64 (provider);\r
                  \r
-                               } else if (conversionType == conversionTable[13]) {\r
-                                       // 13 TypeCode.UInt32\r
-                                       return (object)(convertValue.ToUInt32 (provider));\r
+                               else if (conversionType == conversionTable[13]) // 13 TypeCode.Single\r
+                                       return (object) convertValue.ToSingle (provider);\r
                  \r
-                               } else if (conversionType == conversionTable[14]) {\r
-                                       // 14 TypeCode.UInt64\r
-                                       return (object)(convertValue.ToUInt64 (provider));\r
-\r
-                               } else if (conversionType == conversionTable[15]) {\r
-                                       // 15 TypeCode.Object\r
-                                       return (object)(value);\r
-\r
-                               } else  {               \r
-                                       // Not in the conversion table\r
-                                       throw new InvalidCastException (Locale.GetText (\r
-                                               "Unknown target conversion type"));\r
-                               }\r
-                       } else {\r
-                               // Value is not IConvertible\r
-                               throw new ArgumentException (Locale.GetText (\r
-                                       "Value is not a convertible object: "+ value.GetType().ToString()+" to "+conversionType.ToString()));\r
-                       }\r
+                               else if (conversionType == conversionTable[14]) // 14 TypeCode.Double\r
+                                       return (object) convertValue.ToDouble (provider);\r
+\r
+                               else if (conversionType == conversionTable[15]) // 15 TypeCode.Decimal\r
+                                       return (object) convertValue.ToDecimal (provider);\r
+\r
+                               else if (conversionType == conversionTable[16]) // 16 TypeCode.DateTime\r
+                                       return (object) convertValue.ToDateTime (provider);\r
+                               \r
+                               else if (conversionType == conversionTable[18]) // 18 TypeCode.String\r
+                                       return (object) convertValue.ToString (provider);\r
+                               else\r
+                                       throw new ArgumentException (Locale.GetText ("Unknown target conversion type"));\r
+                       } else\r
+                               // Not in the conversion table\r
+                               throw new InvalidCastException ((Locale.GetText (\r
+                                       "Value is not a convertible object: " + value.GetType().ToString() + " to " + conversionType.FullName)));\r
                }\r
        }\r
 }\r
-\r
-\r
-\r
-\r