2009-03-23 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mcs / class / corlib / System / String.cs
index 89793f81d3d7e41bec36d801a8e8580f5a361cbc..7533f40da254d2e70bd6fbde1847b28fbe89d84f 100644 (file)
@@ -169,15 +169,16 @@ namespace System
                {
                        if (destination == null)
                                throw new ArgumentNullException ("destination");
-
-                       if (sourceIndex < 0 || destinationIndex < 0 || count < 0)
-                               throw new ArgumentOutOfRangeException (); 
-
+                       if (sourceIndex < 0)
+                               throw new ArgumentOutOfRangeException ("sourceIndex", "Cannot be negative");
+                       if (destinationIndex < 0)
+                               throw new ArgumentOutOfRangeException ("destinationIndex", "Cannot be negative.");
+                       if (count < 0)
+                               throw new ArgumentOutOfRangeException ("count", "Cannot be negative.");
                        if (sourceIndex > Length - count)
-                               throw new ArgumentOutOfRangeException ("sourceIndex + count > Length");
-
+                               throw new ArgumentOutOfRangeException ("sourceIndex", "sourceIndex + count > Length");
                        if (destinationIndex > destination.Length - count)
-                               throw new ArgumentOutOfRangeException ("destinationIndex + count > destination.Length");
+                               throw new ArgumentOutOfRangeException ("destinationIndex", "destinationIndex + count > destination.Length");
 
                        fixed (char* dest = destination, src = this)
                                CharCopy (dest + destinationIndex, src + sourceIndex, count);
@@ -197,13 +198,12 @@ namespace System
                                throw new ArgumentOutOfRangeException ("startIndex", "< 0"); 
                        if (length < 0)
                                throw new ArgumentOutOfRangeException ("length", "< 0"); 
-
                        if (startIndex > this.length - length)
-                               throw new ArgumentOutOfRangeException ("startIndex + length > this.length"); 
+                               throw new ArgumentOutOfRangeException ("startIndex", "Must be greater than the length of the string.");
 
                        char[] tmp = new char [length];
                        fixed (char* dest = tmp, src = this)
-                               CharCopy (dest + startIndex, src, length);
+                               CharCopy (dest, src + startIndex, length);
                        return tmp;
                }
 
@@ -240,7 +240,7 @@ namespace System
                        if (count < 0)
                                throw new ArgumentOutOfRangeException ("count", "Count cannot be less than zero.");
                        if ((options != StringSplitOptions.None) && (options != StringSplitOptions.RemoveEmptyEntries))
-                               throw new ArgumentException ("options must be one of the values in the StringSplitOptions enumeration", "options");
+                               throw new ArgumentException ("Illegal enum value: " + options + ".");
 
                        if (count == 0)
                                return new string [0];
@@ -257,7 +257,7 @@ namespace System
                        if (count < 0)
                                throw new ArgumentOutOfRangeException ("count", "Count cannot be less than zero.");
                        if ((options != StringSplitOptions.None) && (options != StringSplitOptions.RemoveEmptyEntries))
-                               throw new ArgumentException ("Illegal enum value: " + options + ".", "options");
+                               throw new ArgumentException ("Illegal enum value: " + options + ".");
 
                        bool removeEmpty = (options & StringSplitOptions.RemoveEmptyEntries) == StringSplitOptions.RemoveEmptyEntries;
 
@@ -333,11 +333,18 @@ namespace System
 
                public String Substring (int startIndex)
                {
+#if NET_2_0
                        if (startIndex == 0)
                                return this;
-
                        if (startIndex < 0 || startIndex > this.length)
                                throw new ArgumentOutOfRangeException ("startIndex");
+#else
+                       if (startIndex < 0)
+                               throw new ArgumentOutOfRangeException ("startIndex", "Cannot be negative.");
+
+                       if (startIndex > this.length)
+                               throw new ArgumentOutOfRangeException ("length", "Cannot exceed length of string.");
+#endif
 
                        return SubstringUnchecked (startIndex, this.length - startIndex);
                }
@@ -345,15 +352,25 @@ namespace System
                public String Substring (int startIndex, int length)
                {
                        if (length < 0)
-                               throw new ArgumentOutOfRangeException ("length", "< 0");
+                               throw new ArgumentOutOfRangeException ("length", "Cannot be negative.");
                        if (startIndex < 0)
-                               throw new ArgumentOutOfRangeException ("startIndex", "< 0");
+                               throw new ArgumentOutOfRangeException ("startIndex", "Cannot be negative.");
+#if NET_2_0
+                       if (startIndex > this.length)
+                               throw new ArgumentOutOfRangeException ("startIndex", "Cannot exceed length of string.");
+#endif
                        if (startIndex > this.length - length)
-                               throw new ArgumentOutOfRangeException ("startIndex + length > this.length");
+                               throw new ArgumentOutOfRangeException ("length", "startIndex + length > this.length");
+#if NET_2_0
+                       if (startIndex == 0 && length == this.length)
+                               return this;
+#endif
 
                        return SubstringUnchecked (startIndex, length);
-               }       
+               }
 
+               // This method is used by StringBuilder.ToString() and is expected to
+               // always create a new string object (or return String.Empty). 
                internal unsafe String SubstringUnchecked (int startIndex, int length)
                {
                        if (length == 0)
@@ -376,31 +393,117 @@ namespace System
 
                public String Trim ()
                {
-                       return InternalTrim (WhiteChars, 0);
+                       if (length == 0) 
+                               return String.Empty;
+                       int start = FindNotWhiteSpace (0, length, 1);
+
+                       if (start == length)
+                               return String.Empty;
+
+                       int end = FindNotWhiteSpace (length - 1, start, -1);
+
+                       int newLength = end - start + 1;
+                       if (newLength == length)
+                               return this;
+
+                       return SubstringUnchecked (start, newLength);
                }
 
                public String Trim (params char[] trimChars)
                {
                        if (trimChars == null || trimChars.Length == 0)
-                               trimChars = WhiteChars;
+                               return Trim ();
+
+                       if (length == 0) 
+                               return String.Empty;
+                       int start = FindNotInTable (0, length, 1, trimChars);
 
-                       return InternalTrim (trimChars, 0);
+                       if (start == length)
+                               return String.Empty;
+
+                       int end = FindNotInTable (length - 1, start, -1, trimChars);
+
+                       int newLength = end - start + 1;
+                       if (newLength == length)
+                               return this;
+
+                       return SubstringUnchecked (start, newLength);
                }
 
                public String TrimStart (params char[] trimChars)
                {
+                       if (length == 0) 
+                               return String.Empty;
+                       int start;
                        if (trimChars == null || trimChars.Length == 0)
-                               trimChars = WhiteChars;
+                               start = FindNotWhiteSpace (0, length, 1);
+                       else
+                               start = FindNotInTable (0, length, 1, trimChars);
 
-                       return InternalTrim (trimChars, 1);
+                       if (start == 0)
+                               return this;
+
+                       return SubstringUnchecked (start, length - start);
                }
 
                public String TrimEnd (params char[] trimChars)
                {
+                       if (length == 0) 
+                               return String.Empty;
+                       int end;
                        if (trimChars == null || trimChars.Length == 0)
-                               trimChars = WhiteChars;
+                               end = FindNotWhiteSpace (length - 1, -1, -1);
+                       else
+                               end = FindNotInTable (length - 1, -1, -1, trimChars);
+
+                       end++;
+                       if (end == length)
+                               return this;
+
+                       return SubstringUnchecked (0, end);
+               }
+
+               private int FindNotWhiteSpace (int pos, int target, int change)
+               {
+                       while (pos != target) {
+                               char c = this[pos];
+                               if (c < 0x85) {
+                                       if (c != 0x20) {
+                                               if (c < 0x9 || c > 0xD)
+                                                       return pos;
+                                       }
+                               }
+                               else {
+                                       if (c != 0xA0 && c != 0xFEFF && c != 0x3000) {
+#if NET_2_0
+                                               if (c != 0x85 && c != 0x1680 && c != 0x2028 && c != 0x2029)
+#endif
+                                                       if (c < 0x2000 || c > 0x200B)
+                                                               return pos;
+                                       }
+                               }
+                               pos += change;
+                       }
+                       return pos;
+               }
 
-                       return InternalTrim (trimChars, 2);
+               private unsafe int FindNotInTable (int pos, int target, int change, char[] table)
+               {
+                       fixed (char* tablePtr = table, thisPtr = this) {
+                               while (pos != target) {
+                                       char c = thisPtr[pos];
+                                       int x = 0;
+                                       while (x < table.Length) {
+                                               if (c == tablePtr[x])
+                                                       break;
+                                               x++;
+                                       }
+                                       if (x == table.Length)
+                                               return pos;
+                                       pos += change;
+                               }
+                       }
+                       return pos;
                }
 
                public static int Compare (String strA, String strB)
@@ -531,7 +634,33 @@ namespace System
                {
                        return String.Compare (value, this, comparisonType) == 0;
                }
+
+               public static int Compare (string strA, string strB, CultureInfo culture, CompareOptions options)
+               {
+                       if (culture == null)
+                               throw new ArgumentNullException ("culture");
+
+                       return culture.CompareInfo.Compare (strA, strB, options);
+               }
+
+               public static int Compare (string strA, int indexA, string strB, int indexB, int length, CultureInfo culture, CompareOptions options)
+               {
+                       if (culture == null)
+                               throw new ArgumentNullException ("culture");
+
+                       int len1 = length;
+                       int len2 = length;
+                       
+                       if (length > (strA.Length - indexA))
+                               len1 = strA.Length - indexA;
+
+                       if (length > (strB.Length - indexB))
+                               len2 = strB.Length - indexB;
+
+                       return culture.CompareInfo.Compare (strA, indexA, len1, strB, indexB, len2, options);
+               }
 #endif
+
                public int CompareTo (Object value)
                {
                        if (value == null)
@@ -639,6 +768,9 @@ namespace System
 
                public bool EndsWith (String value)
                {
+                       if (value == null)
+                               throw new ArgumentNullException ("value");
+
                        return CultureInfo.CurrentCulture.CompareInfo.IsSuffix (this, value, CompareOptions.None);
                }
 
@@ -649,6 +781,8 @@ namespace System
 #endif
                bool EndsWith (String value, bool ignoreCase, CultureInfo culture)
                {
+                       if (value == null)
+                               throw new ArgumentNullException ("value");
                        if (culture == null)
                                culture = CultureInfo.CurrentCulture;
 
@@ -660,45 +794,42 @@ namespace System
                public int IndexOfAny (char [] anyOf)
                {
                        if (anyOf == null)
-                               throw new ArgumentNullException ("anyOf");
+                               throw new ArgumentNullException ();
                        if (this.length == 0)
                                return -1;
 
-                       return InternalIndexOfAny (anyOf, 0, this.length);
+                       return IndexOfAnyUnchecked (anyOf, 0, this.length);
                }
 
                public int IndexOfAny (char [] anyOf, int startIndex)
                {
                        if (anyOf == null)
-                               throw new ArgumentNullException ("anyOf");
+                               throw new ArgumentNullException ();
                        if (startIndex < 0 || startIndex > this.length)
-                               throw new ArgumentOutOfRangeException ("startIndex");
+                               throw new ArgumentOutOfRangeException ();
 
-                       return InternalIndexOfAny (anyOf, startIndex, this.length - startIndex);
+                       return IndexOfAnyUnchecked (anyOf, startIndex, this.length - startIndex);
                }
 
                public int IndexOfAny (char [] anyOf, int startIndex, int count)
                {
                        if (anyOf == null)
-                               throw new ArgumentNullException ("anyOf");
-                       if (startIndex < 0)
-                               throw new ArgumentOutOfRangeException ("startIndex", "< 0");
-                       if (count < 0)
-                               throw new ArgumentOutOfRangeException ("count", "< 0");
-                       // re-ordered to avoid possible integer overflow
-                       if (startIndex > this.length - count)
-                               throw new ArgumentOutOfRangeException ("startIndex + count > this.length");
+                               throw new ArgumentNullException ();
+                       if (startIndex < 0 || startIndex > this.length)
+                               throw new ArgumentOutOfRangeException ();
+                       if (count < 0 || startIndex > this.length - count)
+                               throw new ArgumentOutOfRangeException ("count", "Count cannot be negative, and startIndex + count must be less than length of the string.");
 
-                       return InternalIndexOfAny (anyOf, startIndex, count);
+                       return IndexOfAnyUnchecked (anyOf, startIndex, count);
                }
 
-               unsafe int InternalIndexOfAny (char[] anyOf, int startIndex, int count)
+               private unsafe int IndexOfAnyUnchecked (char[] anyOf, int startIndex, int count)
                {
                        if (anyOf.Length == 0)
                                return -1;
 
                        if (anyOf.Length == 1)
-                               return IndexOfImpl(anyOf[0], startIndex, count);
+                               return IndexOfUnchecked (anyOf[0], startIndex, count);
 
                        fixed (char* any = anyOf) {
                                int highest = *any;
@@ -744,19 +875,19 @@ namespace System
 
 
 #if NET_2_0
-               public int IndexOf (string value, StringComparison comparison)
+               public int IndexOf (string value, StringComparison comparisonType)
                {
-                       return IndexOf (value, 0, this.Length, comparison);
+                       return IndexOf (value, 0, this.Length, comparisonType);
                }
 
-               public int IndexOf (string value, int startIndex, StringComparison comparison)
+               public int IndexOf (string value, int startIndex, StringComparison comparisonType)
                {
-                       return IndexOf (value, startIndex, this.Length - startIndex, comparison);
+                       return IndexOf (value, startIndex, this.Length - startIndex, comparisonType);
                }
 
-               public int IndexOf (string value, int startIndex, int count, StringComparison comparison)
+               public int IndexOf (string value, int startIndex, int count, StringComparison comparisonType)
                {
-                       switch (comparison) {
+                       switch (comparisonType) {
                        case StringComparison.CurrentCulture:
                                return CultureInfo.CurrentCulture.CompareInfo.IndexOf (this, value, startIndex, count, CompareOptions.None);
                        case StringComparison.CurrentCultureIgnoreCase:
@@ -766,28 +897,103 @@ namespace System
                        case StringComparison.InvariantCultureIgnoreCase:
                                return CultureInfo.InvariantCulture.CompareInfo.IndexOf (this, value, startIndex, count, CompareOptions.IgnoreCase);
                        case StringComparison.Ordinal:
-                               return CultureInfo.InvariantCulture.CompareInfo.IndexOf (this, value, startIndex, count, CompareOptions.Ordinal);
+                               return IndexOfOrdinal (value, startIndex, count, CompareOptions.Ordinal);
                        case StringComparison.OrdinalIgnoreCase:
-                               return CultureInfo.InvariantCulture.CompareInfo.IndexOf (this, value, startIndex, count, CompareOptions.OrdinalIgnoreCase);
+                               return IndexOfOrdinal (value, startIndex, count, CompareOptions.OrdinalIgnoreCase);
+                       default:
+                               string msg = Locale.GetText ("Invalid value '{0}' for StringComparison", comparisonType);
+                               throw new ArgumentException (msg, "comparisonType");
+                       }
+               }
+#endif
+
+               internal int IndexOfOrdinal (string value, int startIndex, int count, CompareOptions options)
+               {
+                       if (value == null)
+                               throw new ArgumentNullException ("value");
+                       if (startIndex < 0)
+                               throw new ArgumentOutOfRangeException ("startIndex");
+                       if (count < 0 || (this.length - startIndex) < count)
+                               throw new ArgumentOutOfRangeException ("count");
+
+                       if (options == CompareOptions.Ordinal)
+                               return IndexOfOrdinalUnchecked (value, startIndex, count);
+                       return IndexOfOrdinalIgnoreCaseUnchecked (value, startIndex, count);
+               }
+
+               internal unsafe int IndexOfOrdinalUnchecked (string value, int startIndex, int count)
+               {
+                       int valueLen = value.Length;
+                       if (count < valueLen)
+                               return -1;
+
+                       if (valueLen <= 1) {
+                               if (valueLen == 1)
+                                       return IndexOfUnchecked (value[0], startIndex, count);
+                               return 0;
+                       }
+
+                       fixed (char* thisptr = this, valueptr = value) {
+                               char* ap = thisptr + startIndex;
+                               char* thisEnd = ap + count - valueLen + 1;
+                               while (ap != thisEnd) {
+                                       if (*ap == *valueptr) {
+                                               for (int i = 1; i < valueLen; i++) {
+                                                       if (ap[i] != valueptr[i])
+                                                               goto NextVal;
+                                               }
+                                               return (int)(ap - thisptr);
+                                       }
+                                       NextVal:
+                                       ap++;
+                               }
                        }
+                       return -1;
+               }
+
+               internal unsafe int IndexOfOrdinalIgnoreCaseUnchecked (string value, int startIndex, int count)
+               {
+                       int valueLen = value.Length;
+                       if (count < valueLen)
+                               return -1;
+
+                       if (valueLen == 0)
+                               return 0;
 
-                       string msg = Locale.GetText ("Invalid value '{0}' for StringComparison", comparison);
-                       throw new ArgumentException  (msg, "comparison");
+                       fixed (char* thisptr = this, valueptr = value) {
+                               char* ap = thisptr + startIndex;
+                               char* thisEnd = ap + count - valueLen + 1;
+                               while (ap != thisEnd) {
+                                       for (int i = 0; i < valueLen; i++) {
+                                               if (Char.ToUpperInvariant (ap[i]) != Char.ToUpperInvariant (valueptr[i]))
+                                                       goto NextVal;
+                                       }
+                                       return (int)(ap - thisptr);
+                                       NextVal:
+                                       ap++;
+                               }
+                       }
+                       return -1;
                }
 
-               public int LastIndexOf (string value, StringComparison comparison)
+#if NET_2_0
+
+               public int LastIndexOf (string value, StringComparison comparisonType)
                {
-                       return LastIndexOf (value, value.Length - 1, value.Length, comparison);
+                       if (this.Length == 0)
+                               return value == String.Empty ? 0 : -1;
+                       else
+                               return LastIndexOf (value, this.Length - 1, this.Length, comparisonType);
                }
 
-               public int LastIndexOf (string value, int startIndex, StringComparison comparison)
+               public int LastIndexOf (string value, int startIndex, StringComparison comparisonType)
                {
-                       return LastIndexOf (value, startIndex, startIndex + 1, comparison);
+                       return LastIndexOf (value, startIndex, startIndex + 1, comparisonType);
                }
 
-               public int LastIndexOf (string value, int startIndex, int count, StringComparison comparison)
+               public int LastIndexOf (string value, int startIndex, int count, StringComparison comparisonType)
                {
-                       switch (comparison) {
+                       switch (comparisonType) {
                        case StringComparison.CurrentCulture:
                                return CultureInfo.CurrentCulture.CompareInfo.LastIndexOf (this, value, startIndex, count, CompareOptions.None);
                        case StringComparison.CurrentCultureIgnoreCase:
@@ -797,57 +1003,123 @@ namespace System
                        case StringComparison.InvariantCultureIgnoreCase:
                                return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf (this, value, startIndex, count, CompareOptions.IgnoreCase);
                        case StringComparison.Ordinal:
-                               return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf (this, value, startIndex, count, CompareOptions.Ordinal);
+                               return LastIndexOfOrdinal (value, startIndex, count, CompareOptions.Ordinal);
                        case StringComparison.OrdinalIgnoreCase:
-                               return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf (this, value, startIndex, count, CompareOptions.OrdinalIgnoreCase);
+                               return LastIndexOfOrdinal (value, startIndex, count, CompareOptions.OrdinalIgnoreCase);
+                       default:
+                               string msg = Locale.GetText ("Invalid value '{0}' for StringComparison", comparisonType);
+                               throw new ArgumentException (msg, "comparisonType");
                        }
-
-                       string msg = Locale.GetText ("Invalid value '{0}' for StringComparison", comparison);
-                       throw new ArgumentException  (msg, "comparison");
                }
 #endif
 
-               public int IndexOf (char value)
+               internal int LastIndexOfOrdinal (string value, int startIndex, int count, CompareOptions options)
                {
-                       if (this.length == 0)
-                               return -1;
+                       if (value == null)
+                               throw new ArgumentNullException ("value");
+                       if (startIndex < 0 || startIndex > length)
+                               throw new ArgumentOutOfRangeException ("startIndex");
+                       if (count < 0 || (startIndex < count - 1))
+                               throw new ArgumentOutOfRangeException ("count");
 
-                       return IndexOfImpl (value, 0, this.length);
+                       if (options == CompareOptions.Ordinal)
+                               return LastIndexOfOrdinalUnchecked (value, startIndex, count);
+                       return LastIndexOfOrdinalIgnoreCaseUnchecked (value, startIndex, count);
                }
 
-               public int IndexOf (String value)
+               internal unsafe int LastIndexOfOrdinalUnchecked (string value, int startIndex, int count)
                {
-                       return IndexOf (value, 0, this.length);
+                       int valueLen = value.Length;
+                       if (count < valueLen)
+                               return -1;
+
+                       if (valueLen <= 1) {
+                               if (valueLen == 1)
+                                       return LastIndexOfUnchecked (value[0], startIndex, count);
+                               return 0;
+                       }
+
+                       fixed (char* thisptr = this, valueptr = value) {
+                               char* ap = thisptr + startIndex - valueLen + 1;
+                               char* thisEnd = ap - count + valueLen - 1;
+                               while (ap != thisEnd) {
+                                       if (*ap == *valueptr) {
+                                               for (int i = 1; i < valueLen; i++) {
+                                                       if (ap[i] != valueptr[i])
+                                                               goto NextVal;
+                                               }
+                                               return (int)(ap - thisptr);
+                                       }
+                                       NextVal:
+                                       ap--;
+                               }
+                       }
+                       return -1;
                }
 
-               public int IndexOf (char value, int startIndex)
+               internal unsafe int LastIndexOfOrdinalIgnoreCaseUnchecked (string value, int startIndex, int count)
                {
-                       return IndexOf (value, startIndex, this.length - startIndex);
+                       int valueLen = value.Length;
+                       if (count < valueLen)
+                               return -1;
+
+                       if (valueLen == 0)
+                               return 0;
+
+                       fixed (char* thisptr = this, valueptr = value) {
+                               char* ap = thisptr + startIndex - valueLen + 1;
+                               char* thisEnd = ap - count + valueLen - 1;
+                               while (ap != thisEnd) {
+                                       for (int i = 0; i < valueLen; i++) {
+                                               if (Char.ToUpperInvariant (ap[i]) != Char.ToUpperInvariant (valueptr[i]))
+                                                       goto NextVal;
+                                       }
+                                       return (int)(ap - thisptr);
+                                       NextVal:
+                                       ap--;
+                               }
+                       }
+                       return -1;
                }
 
-               public int IndexOf (String value, int startIndex)
+               // Following methods are culture-insensitive
+               public int IndexOf (char value)
                {
-                       return IndexOf (value, startIndex, this.length - startIndex);
+                       if (this.length == 0)
+                               return -1;
+
+                       return IndexOfUnchecked (value, 0, this.length);
                }
 
-               /* This method is culture-insensitive */
-               public int IndexOf (char value, int startIndex, int count)
+               public int IndexOf (char value, int startIndex)
                {
                        if (startIndex < 0)
                                throw new ArgumentOutOfRangeException ("startIndex", "< 0");
+                       if (startIndex > this.length)
+                               throw new ArgumentOutOfRangeException ("startIndex", "startIndex > this.length");
+
+                       if ((startIndex == 0 && this.length == 0) || (startIndex == this.length))
+                               return -1;
+
+                       return IndexOfUnchecked (value, startIndex, this.length - startIndex);
+               }
+
+               public int IndexOf (char value, int startIndex, int count)
+               {
+                       if (startIndex < 0 || startIndex > this.length)
+                               throw new ArgumentOutOfRangeException ("startIndex", "Cannot be negative and must be< 0");
                        if (count < 0)
                                throw new ArgumentOutOfRangeException ("count", "< 0");
-                       // re-ordered to avoid possible integer overflow
                        if (startIndex > this.length - count)
-                               throw new ArgumentOutOfRangeException ("startIndex + count > this.length");
+                               throw new ArgumentOutOfRangeException ("count", "startIndex + count > this.length");
 
                        if ((startIndex == 0 && this.length == 0) || (startIndex == this.length) || (count == 0))
                                return -1;
 
-                       return IndexOfImpl (value, startIndex, count);
+                       return IndexOfUnchecked (value, startIndex, count);
                }
 
-               unsafe int IndexOfImpl (char value, int startIndex, int count)
+               internal unsafe int IndexOfUnchecked (char value, int startIndex, int count)
                {
                        // It helps JIT compiler to optimize comparison
                        int value_32 = (int)value;
@@ -888,18 +1160,49 @@ namespace System
                        }
                }
 
-               /* But this one is culture-sensitive */
+               internal unsafe int IndexOfOrdinalIgnoreCase (char value, int startIndex, int count)
+               {
+                       if (length == 0)
+                               return -1;
+                       int end = startIndex + count;
+                       char c = Char.ToUpperInvariant (value);
+                       fixed (char* s = &start_char) {
+                               for (int i = startIndex; i < end; i++)
+                                       if (Char.ToUpperInvariant (s [i]) == c)
+                                               return i;
+                       }
+                       return -1;
+               }
+
+               // Following methods are culture-sensitive
+               public int IndexOf (String value)
+               {
+                       if (value == null)
+                               throw new ArgumentNullException ("value");
+                       if (value.length == 0)
+                               return 0;
+                       if (this.length == 0)
+                               return -1;
+                       return CultureInfo.CurrentCulture.CompareInfo.IndexOf (this, value, 0, length);
+               }
+
+               public int IndexOf (String value, int startIndex)
+               {
+                       return IndexOf (value, startIndex, this.length - startIndex);
+               }
+
                public int IndexOf (String value, int startIndex, int count)
                {
                        if (value == null)
+#if NET_2_0
                                throw new ArgumentNullException ("value");
-                       if (startIndex < 0)
-                               throw new ArgumentOutOfRangeException ("startIndex", "< 0");
-                       if (count < 0)
-                               throw new ArgumentOutOfRangeException ("count", "< 0");
-                       // re-ordered to avoid possible integer overflow
-                       if (startIndex > this.length - count)
-                               throw new ArgumentOutOfRangeException ("startIndex + count > this.length");
+#else
+                               throw new ArgumentNullException ("string2");
+#endif
+                       if (startIndex < 0 || startIndex > this.length)
+                               throw new ArgumentOutOfRangeException ("startIndex", "Cannot be negative, and should not exceed length of string.");
+                       if (count < 0 || startIndex > this.length - count)
+                               throw new ArgumentOutOfRangeException ("count", "Cannot be negative, and should point to location in string.");
 
                        if (value.length == 0)
                                return startIndex;
@@ -913,32 +1216,33 @@ namespace System
                        return CultureInfo.CurrentCulture.CompareInfo.IndexOf (this, value, startIndex, count);
                }
 
+               // Following methods are culture-insensitive
                public int LastIndexOfAny (char [] anyOf)
                {
                        if (anyOf == null)
-                               throw new ArgumentNullException ("anyOf");
+                               throw new ArgumentNullException ();
 
-                       return InternalLastIndexOfAny (anyOf, this.length - 1, this.length);
+                       return LastIndexOfAnyUnchecked (anyOf, this.length - 1, this.length);
                }
 
                public int LastIndexOfAny (char [] anyOf, int startIndex)
                {
-                       if (anyOf == null) 
-                               throw new ArgumentNullException ("anyOf");
+                       if (anyOf == null)
+                               throw new ArgumentNullException ();
 
                        if (startIndex < 0 || startIndex >= this.length)
-                               throw new ArgumentOutOfRangeException ();
+                               throw new ArgumentOutOfRangeException ("startIndex", "Cannot be negative, and should be less than length of string.");
 
                        if (this.length == 0)
                                return -1;
 
-                       return InternalLastIndexOfAny (anyOf, startIndex, startIndex + 1);
+                       return LastIndexOfAnyUnchecked (anyOf, startIndex, startIndex + 1);
                }
 
                public int LastIndexOfAny (char [] anyOf, int startIndex, int count)
                {
                        if (anyOf == null) 
-                               throw new ArgumentNullException ("anyOf");
+                               throw new ArgumentNullException ();
 
                        if ((startIndex < 0) || (startIndex >= this.Length))
                                throw new ArgumentOutOfRangeException ("startIndex", "< 0 || > this.Length");
@@ -950,24 +1254,40 @@ namespace System
                        if (this.length == 0)
                                return -1;
 
-                       return InternalLastIndexOfAny (anyOf, startIndex, count);
+                       return LastIndexOfAnyUnchecked (anyOf, startIndex, count);
                }
 
-               public int LastIndexOf (char value)
+               private unsafe int LastIndexOfAnyUnchecked (char [] anyOf, int startIndex, int count)
                {
-                       if (this.length == 0)
+                       if (anyOf.Length == 1)
+                               return LastIndexOfUnchecked (anyOf[0], startIndex, count);
+
+                       fixed (char* start = this, testStart = anyOf) {
+                               char* ptr = start + startIndex;
+                               char* ptrEnd = ptr - count;
+                               char* test;
+                               char* testEnd = testStart + anyOf.Length;
+
+                               while (ptr != ptrEnd) {
+                                       test = testStart;
+                                       while (test != testEnd) {
+                                               if (*test == *ptr)
+                                                       return (int)(ptr - start);
+                                               test++;
+                                       }
+                                       ptr--;
+                               }
                                return -1;
-                       
-                       return LastIndexOfImpl (value, this.length - 1, this.length);
+                       }
                }
 
-               public int LastIndexOf (String value)
+               // Following methods are culture-insensitive
+               public int LastIndexOf (char value)
                {
                        if (this.length == 0)
-                               /* This overload does additional checking */
-                               return LastIndexOf (value, 0, 0);
-                       else
-                               return LastIndexOf (value, this.length - 1, this.length);
+                               return -1;
+                       
+                       return LastIndexOfUnchecked (value, this.length - 1, this.length);
                }
 
                public int LastIndexOf (char value, int startIndex)
@@ -975,17 +1295,6 @@ namespace System
                        return LastIndexOf (value, startIndex, startIndex + 1);
                }
 
-               public int LastIndexOf (String value, int startIndex)
-               {
-                       if (value == null)
-                               throw new ArgumentNullException ("value");
-                       int max = startIndex;
-                       if (max < this.Length)
-                               max++;
-                       return LastIndexOf (value, startIndex, max);
-               }
-
-               /* This method is culture-insensitive */
                public int LastIndexOf (char value, int startIndex, int count)
                {
                        if (startIndex == 0 && this.length == 0)
@@ -999,11 +1308,10 @@ namespace System
                        if (startIndex - count + 1 < 0)
                                throw new ArgumentOutOfRangeException ("startIndex - count + 1 < 0");
 
-                       return LastIndexOfImpl (value, startIndex, count);
+                       return LastIndexOfUnchecked (value, startIndex, count);
                }
 
-               /* This method is culture-insensitive */
-               unsafe int LastIndexOfImpl (char value, int startIndex, int count)
+               internal unsafe int LastIndexOfUnchecked (char value, int startIndex, int count)
                {
                        // It helps JIT compiler to optimize comparison
                        int value_32 = (int)value;
@@ -1044,11 +1352,47 @@ namespace System
                        }
                }
 
-               /* But this one is culture-sensitive */
+               internal unsafe int LastIndexOfOrdinalIgnoreCase (char value, int startIndex, int count)
+               {
+                       if (length == 0)
+                               return -1;
+                       int end = startIndex - count;
+                       char c = Char.ToUpperInvariant (value);
+                       fixed (char* s = &start_char) {
+                               for (int i = startIndex; i > end; i--)
+                                       if (Char.ToUpperInvariant (s [i]) == c)
+                                               return i;
+                       }
+                       return -1;
+               }
+
+               // Following methods are culture-sensitive
+               public int LastIndexOf (String value)
+               {
+                       if (this.length == 0)
+                               // This overload does additional checking
+                               return LastIndexOf (value, 0, 0);
+                       else
+                               return LastIndexOf (value, this.length - 1, this.length);
+               }
+
+               public int LastIndexOf (String value, int startIndex)
+               {
+                       int max = startIndex;
+                       if (max < this.Length)
+                               max++;
+                       return LastIndexOf (value, startIndex, max);
+               }
+
                public int LastIndexOf (String value, int startIndex, int count)
                {
                        if (value == null)
+#if NET_2_0
                                throw new ArgumentNullException ("value");
+#else
+                               throw new ArgumentNullException ("string2");
+#endif
+
                        // -1 > startIndex > for string (0 > startIndex >= for char)
                        if ((startIndex < -1) || (startIndex > this.Length))
                                throw new ArgumentOutOfRangeException ("startIndex", "< 0 || > this.Length");
@@ -1091,9 +1435,9 @@ namespace System
                        return Normalization.Normalize (this, 0);
                }
 
-               public string Normalize (NormalizationForm form)
+               public string Normalize (NormalizationForm normalizationForm)
                {
-                       switch (form) {
+                       switch (normalizationForm) {
                        default:
                                return Normalization.Normalize (this, 0);
                        case NormalizationForm.FormD:
@@ -1110,9 +1454,9 @@ namespace System
                        return Normalization.IsNormalized (this, 0);
                }
 
-               public bool IsNormalized (NormalizationForm form)
+               public bool IsNormalized (NormalizationForm normalizationForm)
                {
-                       switch (form) {
+                       switch (normalizationForm) {
                        default:
                                return Normalization.IsNormalized (this, 0);
                        case NormalizationForm.FormD:
@@ -1140,15 +1484,27 @@ namespace System
                        return PadLeft (totalWidth, ' ');
                }
 
-               public String PadLeft (int totalWidth, char paddingChar)
+               public unsafe String PadLeft (int totalWidth, char paddingChar)
                {
+                       //LAMESPEC: MSDN Doc says this is reversed for RtL languages, but this seems to be untrue
+
                        if (totalWidth < 0)
                                throw new ArgumentOutOfRangeException ("totalWidth", "< 0");
 
                        if (totalWidth < this.length)
-                               return String.Copy (this);
+                               return this;
+
+                       String tmp = InternalAllocateStr (totalWidth);
 
-                       return InternalPad (totalWidth, paddingChar, false);
+                       fixed (char* dest = tmp, src = this) {
+                               char* padPos = dest;
+                               char* padTo = dest + (totalWidth - length);
+                               while (padPos != padTo)
+                                       *padPos++ = paddingChar;
+
+                               CharCopy (padTo, src, length);
+                       }
+                       return tmp;
                }
 
                public String PadRight (int totalWidth)
@@ -1156,19 +1512,34 @@ namespace System
                        return PadRight (totalWidth, ' ');
                }
 
-               public String PadRight (int totalWidth, char paddingChar)
+               public unsafe String PadRight (int totalWidth, char paddingChar)
                {
+                       //LAMESPEC: MSDN Doc says this is reversed for RtL languages, but this seems to be untrue
+
                        if (totalWidth < 0)
                                throw new ArgumentOutOfRangeException ("totalWidth", "< 0");
 
                        if (totalWidth < this.length)
-                               return String.Copy (this);
+                               return this;
+
+                       String tmp = InternalAllocateStr (totalWidth);
+
+                       fixed (char* dest = tmp, src = this) {
+                               CharCopy (dest, src, length);
 
-                       return InternalPad (totalWidth, paddingChar, true);
+                               char* padPos = dest + length;
+                               char* padTo = dest + totalWidth;
+                               while (padPos != padTo)
+                                       *padPos++ = paddingChar;
+                       }
+                       return tmp;
                }
 
                public bool StartsWith (String value)
                {
+                       if (value == null)
+                               throw new ArgumentNullException ("value");
+
                        return CultureInfo.CurrentCulture.CompareInfo.IsPrefix (this, value, CompareOptions.None);
                }
 
@@ -1176,6 +1547,9 @@ namespace System
                [ComVisible (false)]
                public bool StartsWith (string value, StringComparison comparisonType)
                {
+                       if (value == null)
+                               throw new ArgumentNullException ("value");
+
                        switch (comparisonType) {
                        case StringComparison.CurrentCulture:
                                return CultureInfo.CurrentCulture.CompareInfo.IsPrefix (this, value, CompareOptions.None);
@@ -1198,6 +1572,9 @@ namespace System
                [ComVisible (false)]
                public bool EndsWith (string value, StringComparison comparisonType)
                {
+                       if (value == null)
+                               throw new ArgumentNullException ("value");
+
                        switch (comparisonType) {
                        case StringComparison.CurrentCulture:
                                return CultureInfo.CurrentCulture.CompareInfo.IsSuffix (this, value, CompareOptions.None);
@@ -1216,7 +1593,6 @@ namespace System
                                throw new ArgumentException (msg, "comparisonType");
                        }
                }
-
 #endif
 
 #if NET_2_0
@@ -1232,23 +1608,23 @@ namespace System
                        return culture.CompareInfo.IsPrefix (this, value, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
                }
 
-               /* This method is culture insensitive */
+               // Following method is culture-insensitive
                public unsafe String Replace (char oldChar, char newChar)
                {
                        if (this.length == 0 || oldChar == newChar)
                                return this;
 
-                       int start_pos = IndexOfImpl (oldChar, 0, this.length);
+                       int start_pos = IndexOfUnchecked (oldChar, 0, this.length);
                        if (start_pos == -1)
                                return this;
 
                        if (start_pos < 4)
                                start_pos = 0;
 
-                       string tmp = InternalAllocateStr(length);
+                       string tmp = InternalAllocateStr (length);
                        fixed (char* dest = tmp, src = &start_char) {
                                if (start_pos != 0)
-                                       memcpy((byte*)dest, (byte*)src, start_pos * 2);
+                                       CharCopy (dest, src, start_pos);
 
                                char* end_ptr = dest + length;
                                char* dest_ptr = dest + start_pos;
@@ -1267,9 +1643,12 @@ namespace System
                        return tmp;
                }
 
-               /* This method is culture sensitive */
+               // culture-insensitive using ordinal search (See testcase StringTest.ReplaceStringCultureTests)
                public String Replace (String oldValue, String newValue)
                {
+                       // LAMESPEC: According to MSDN the following method is culture-sensitive but this seems to be incorrect
+                       // LAMESPEC: Result is undefined if result length is longer than maximum string length
+
                        if (oldValue == null)
                                throw new ArgumentNullException ("oldValue");
 
@@ -1282,17 +1661,82 @@ namespace System
                        if (newValue == null)
                                newValue = String.Empty;
 
-                       return InternalReplace (oldValue, newValue, CultureInfo.CurrentCulture.CompareInfo);
+                       return ReplaceUnchecked (oldValue, newValue);
+               }
+
+               private unsafe String ReplaceUnchecked (String oldValue, String newValue)
+               {
+                       if (oldValue.length > length)
+                               return this;
+                       if (oldValue.length == 1 && newValue.length == 1) {
+                               return Replace (oldValue[0], newValue[0]);
+                               // ENHANCE: It would be possible to special case oldValue.length == newValue.length
+                               // because the length of the result would be this.length and length calculation unneccesary
+                       }
+
+                       const int maxValue = 200; // Allocate 800 byte maximum
+                       int* dat = stackalloc int[maxValue];
+                       fixed (char* source = this, replace = newValue) {
+                               int i = 0, count = 0;
+                               while (i < length) {
+                                       int found = IndexOfOrdinalUnchecked (oldValue, i, length - i);
+                                       if (found < 0)
+                                               break;
+                                       else {
+                                               if (count < maxValue)
+                                                       dat[count++] = found;
+                                               else
+                                                       return ReplaceFallback (oldValue, newValue, maxValue);
+                                       }
+                                       i = found + oldValue.length;
+                               }
+                               if (count == 0)
+                                       return this;
+                               int nlen = this.length + ((newValue.length - oldValue.length) * count);
+                               String tmp = InternalAllocateStr (nlen);
+
+                               int curPos = 0, lastReadPos = 0;
+                               fixed (char* dest = tmp) {
+                                       for (int j = 0; j < count; j++) {
+                                               int precopy = dat[j] - lastReadPos;
+                                               CharCopy (dest + curPos, source + lastReadPos, precopy);
+                                               curPos += precopy;
+                                               lastReadPos = dat[j] + oldValue.length;
+                                               CharCopy (dest + curPos, replace, newValue.length);
+                                               curPos += newValue.length;
+                                       }
+                                       CharCopy (dest + curPos, source + lastReadPos, length - lastReadPos);
+                               }
+                               return tmp;
+                       }
+               }
+
+               private String ReplaceFallback (String oldValue, String newValue, int testedCount)
+               {
+                       int lengthEstimate = this.length + ((newValue.length - oldValue.length) * testedCount);
+                       StringBuilder sb = new StringBuilder (lengthEstimate);
+                       for (int i = 0; i < length;) {
+                               int found = IndexOfOrdinalUnchecked (oldValue, i, length - i);
+                               if (found < 0) {
+                                       sb.Append (SubstringUnchecked (i, length - i));
+                                       break;
+                               }
+                               sb.Append (SubstringUnchecked (i, found - i));
+                               sb.Append (newValue);
+                               i = found + oldValue.Length;
+                       }
+                       return sb.ToString ();
+
                }
 
                public unsafe String Remove (int startIndex, int count)
                {
                        if (startIndex < 0)
-                               throw new ArgumentOutOfRangeException ("startIndex", "< 0");
+                               throw new ArgumentOutOfRangeException ("startIndex", "Cannot be negative.");
                        if (count < 0)
-                               throw new ArgumentOutOfRangeException ("count", "< 0");
+                               throw new ArgumentOutOfRangeException ("count", "Cannot be negative.");
                        if (startIndex > this.length - count)
-                               throw new ArgumentOutOfRangeException ("startIndex + count > this.length");
+                               throw new ArgumentOutOfRangeException ("count", "startIndex + count > this.length");
 
                        String tmp = InternalAllocateStr (this.length - count);
 
@@ -1412,15 +1856,34 @@ namespace System
        
                public static string Format (IFormatProvider provider, string format, params object[] args)
                {
-                       StringBuilder b = new StringBuilder ();
-                       FormatHelper (b, provider, format, args);
+                       StringBuilder b = FormatHelper (null, provider, format, args);
                        return b.ToString ();
                }
                
-               internal static void FormatHelper (StringBuilder result, IFormatProvider provider, string format, params object[] args)
+               internal static StringBuilder FormatHelper (StringBuilder result, IFormatProvider provider, string format, params object[] args)
                {
-                       if (format == null || args == null)
-                               throw new ArgumentNullException ();
+                       if (format == null)
+                               throw new ArgumentNullException ("format");
+                       if (args == null)
+                               throw new ArgumentNullException ("args");
+
+                       if (result == null) {
+                               /* Try to approximate the size of result to avoid reallocations */
+                               int i, len;
+
+                               len = 0;
+                               for (i = 0; i < args.Length; ++i) {
+                                       string s = args [i] as string;
+                                       if (s != null)
+                                               len += s.length;
+                                       else
+                                               break;
+                               }
+                               if (i == args.Length)
+                                       result = new StringBuilder (len + format.length);
+                               else
+                                       result = new StringBuilder ();
+                       }
 
                        int ptr = 0;
                        int start = ptr;
@@ -1496,6 +1959,8 @@ namespace System
 
                        if (start < format.length)
                                result.Append (format, start, format.Length - start);
+
+                       return result;
                }
 
                public unsafe static String Copy (String str)
@@ -1514,20 +1979,20 @@ namespace System
                        return tmp;
                }
 
-               public static String Concat (Object obj)
+               public static String Concat (Object arg0)
                {
-                       if (obj == null)
+                       if (arg0 == null)
                                return String.Empty;
 
-                       return obj.ToString ();
+                       return arg0.ToString ();
                }
 
-               public unsafe static String Concat (Object obj1, Object obj2)
+               public unsafe static String Concat (Object arg0, Object arg1)
                {
                        string s1, s2;
 
-                       s1 = (obj1 != null) ? obj1.ToString () : null;
-                       s2 = (obj2 != null) ? obj2.ToString () : null;
+                       s1 = (arg0 != null) ? arg0.ToString () : null;
+                       s2 = (arg1 != null) ? arg1.ToString () : null;
                        
                        if (s1 == null) {
                                if (s2 == null)
@@ -1552,55 +2017,55 @@ namespace System
                        return tmp;
                }
 
-               public static String Concat (Object obj1, Object obj2, Object obj3)
+               public static String Concat (Object arg0, Object arg1, Object arg2)
                {
                        string s1, s2, s3;
-                       if (obj1 == null)
+                       if (arg0 == null)
                                s1 = String.Empty;
                        else
-                               s1 = obj1.ToString ();
+                               s1 = arg0.ToString ();
 
-                       if (obj2 == null)
+                       if (arg1 == null)
                                s2 = String.Empty;
                        else
-                               s2 = obj2.ToString ();
+                               s2 = arg1.ToString ();
 
-                       if (obj3 == null)
+                       if (arg2 == null)
                                s3 = String.Empty;
                        else
-                               s3 = obj3.ToString ();
+                               s3 = arg2.ToString ();
 
                        return Concat (s1, s2, s3);
                }
 
 #if ! BOOTSTRAP_WITH_OLDLIB
                [CLSCompliant(false)]
-               public static String Concat (Object obj1, Object obj2, Object obj3,
-                                            Object obj4, __arglist)
+               public static String Concat (Object arg0, Object arg1, Object arg2,
+                                            Object arg3, __arglist)
                {
                        string s1, s2, s3, s4;
 
-                       if (obj1 == null)
+                       if (arg0 == null)
                                s1 = String.Empty;
                        else
-                               s1 = obj1.ToString ();
+                               s1 = arg0.ToString ();
 
-                       if (obj2 == null)
+                       if (arg1 == null)
                                s2 = String.Empty;
                        else
-                               s2 = obj2.ToString ();
+                               s2 = arg1.ToString ();
 
-                       if (obj3 == null)
+                       if (arg2 == null)
                                s3 = String.Empty;
                        else
-                               s3 = obj3.ToString ();
+                               s3 = arg2.ToString ();
 
                        ArgIterator iter = new ArgIterator (__arglist);
                        int argCount = iter.GetRemainingCount();
 
                        StringBuilder sb = new StringBuilder ();
-                       if (obj4 != null)
-                               sb.Append (obj4.ToString ());
+                       if (arg3 != null)
+                               sb.Append (arg3.ToString ());
 
                        for (int i = 0; i < argCount; i++) {
                                TypedReference typedRef = iter.GetNextArg ();
@@ -1613,106 +2078,106 @@ namespace System
                }
 #endif
 
-               public unsafe static String Concat (String s1, String s2)
+               public unsafe static String Concat (String str0, String str1)
                {
-                       if (s1 == null || s1.Length == 0) {
-                               if (s2 == null || s2.Length == 0)
+                       if (str0 == null || str0.Length == 0) {
+                               if (str1 == null || str1.Length == 0)
                                        return String.Empty;
-                               return s2;
+                               return str1;
                        }
 
-                       if (s2 == null || s2.Length == 0)
-                               return s1
+                       if (str1 == null || str1.Length == 0)
+                               return str0
 
-                       String tmp = InternalAllocateStr (s1.length + s2.length);
+                       String tmp = InternalAllocateStr (str0.length + str1.length);
 
-                       fixed (char *dest = tmp, src = s1)
-                               CharCopy (dest, src, s1.length);
-                       fixed (char *dest = tmp, src = s2)
-                               CharCopy (dest + s1.Length, src, s2.length);
+                       fixed (char *dest = tmp, src = str0)
+                               CharCopy (dest, src, str0.length);
+                       fixed (char *dest = tmp, src = str1)
+                               CharCopy (dest + str0.Length, src, str1.length);
 
                        return tmp;
                }
 
-               public unsafe static String Concat (String s1, String s2, String s3)
+               public unsafe static String Concat (String str0, String str1, String str2)
                {
-                       if (s1 == null || s1.Length == 0){
-                               if (s2 == null || s2.Length == 0){
-                                       if (s3 == null || s3.Length == 0)
+                       if (str0 == null || str0.Length == 0){
+                               if (str1 == null || str1.Length == 0){
+                                       if (str2 == null || str2.Length == 0)
                                                return String.Empty;
-                                       return s3;
+                                       return str2;
                                } else {
-                                       if (s3 == null || s3.Length == 0)
-                                               return s2;
+                                       if (str2 == null || str2.Length == 0)
+                                               return str1;
                                }
-                               s1 = String.Empty;
+                               str0 = String.Empty;
                        } else {
-                               if (s2 == null || s2.Length == 0){
-                                       if (s3 == null || s3.Length == 0)
-                                               return s1;
+                               if (str1 == null || str1.Length == 0){
+                                       if (str2 == null || str2.Length == 0)
+                                               return str0;
                                        else
-                                               s2 = String.Empty;
+                                               str1 = String.Empty;
                                } else {
-                                       if (s3 == null || s3.Length == 0)
-                                               s3 = String.Empty;
+                                       if (str2 == null || str2.Length == 0)
+                                               str2 = String.Empty;
                                }
                        }
 
-                       String tmp = InternalAllocateStr (s1.length + s2.length + s3.length);
+                       String tmp = InternalAllocateStr (str0.length + str1.length + str2.length);
 
-                       if (s1.Length != 0) {
-                               fixed (char *dest = tmp, src = s1) {
-                                       CharCopy (dest, src, s1.length);
+                       if (str0.Length != 0) {
+                               fixed (char *dest = tmp, src = str0) {
+                                       CharCopy (dest, src, str0.length);
                                }
                        }
-                       if (s2.Length != 0) {
-                               fixed (char *dest = tmp, src = s2) {
-                                       CharCopy (dest + s1.Length, src, s2.length);
+                       if (str1.Length != 0) {
+                               fixed (char *dest = tmp, src = str1) {
+                                       CharCopy (dest + str0.Length, src, str1.length);
                                }
                        }
-                       if (s3.Length != 0) {
-                               fixed (char *dest = tmp, src = s3) {
-                                       CharCopy (dest + s1.Length + s2.Length, src, s3.length);
+                       if (str2.Length != 0) {
+                               fixed (char *dest = tmp, src = str2) {
+                                       CharCopy (dest + str0.Length + str1.Length, src, str2.length);
                                }
                        }
 
                        return tmp;
                }
 
-               public unsafe static String Concat (String s1, String s2, String s3, String s4)
+               public unsafe static String Concat (String str0, String str1, String str2, String str3)
                {
-                       if (s1 == null && s2 == null && s3 == null && s4 == null)
+                       if (str0 == null && str1 == null && str2 == null && str3 == null)
                                return String.Empty;
 
-                       if (s1 == null)
-                               s1 = String.Empty;
-                       if (s2 == null)
-                               s2 = String.Empty;
-                       if (s3 == null)
-                               s3 = String.Empty;
-                       if (s4 == null)
-                               s4 = String.Empty;
+                       if (str0 == null)
+                               str0 = String.Empty;
+                       if (str1 == null)
+                               str1 = String.Empty;
+                       if (str2 == null)
+                               str2 = String.Empty;
+                       if (str3 == null)
+                               str3 = String.Empty;
 
-                       String tmp = InternalAllocateStr (s1.length + s2.length + s3.length + s4.length);
+                       String tmp = InternalAllocateStr (str0.length + str1.length + str2.length + str3.length);
 
-                       if (s1.Length != 0) {
-                               fixed (char *dest = tmp, src = s1) {
-                                       CharCopy (dest, src, s1.length);
+                       if (str0.Length != 0) {
+                               fixed (char *dest = tmp, src = str0) {
+                                       CharCopy (dest, src, str0.length);
                                }
                        }
-                       if (s2.Length != 0) {
-                               fixed (char *dest = tmp, src = s2) {
-                                       CharCopy (dest + s1.Length, src, s2.length);
+                       if (str1.Length != 0) {
+                               fixed (char *dest = tmp, src = str1) {
+                                       CharCopy (dest + str0.Length, src, str1.length);
                                }
                        }
-                       if (s3.Length != 0) {
-                               fixed (char *dest = tmp, src = s3) {
-                                       CharCopy (dest + s1.Length + s2.Length, src, s3.length);
+                       if (str2.Length != 0) {
+                               fixed (char *dest = tmp, src = str2) {
+                                       CharCopy (dest + str0.Length + str1.Length, src, str2.length);
                                }
                        }
-                       if (s4.Length != 0) {
-                               fixed (char *dest = tmp, src = s4) {
-                                       CharCopy (dest + s1.Length + s2.Length + s3.Length, src, s4.length);
+                       if (str3.Length != 0) {
+                               fixed (char *dest = tmp, src = str3) {
+                                       CharCopy (dest + str0.Length + str1.Length + str2.Length, src, str3.length);
                                }
                        }
 
@@ -1784,7 +2249,7 @@ namespace System
                                throw new ArgumentNullException ("value");
 
                        if (startIndex < 0 || startIndex > this.length)
-                               throw new ArgumentOutOfRangeException ();
+                               throw new ArgumentOutOfRangeException ("startIndex", "Cannot be negative and must be less than or equal to length of string.");
 
                        if (value.Length == 0)
                                return this;
@@ -1823,8 +2288,10 @@ namespace System
                {
                        if (value == null)
                                throw new ArgumentNullException ("value");
+                       if (separator == null)
+                               separator = String.Empty;
 
-                       return Join (separator, value, 0, value.Length);
+                       return JoinUnchecked (separator, value, 0, value.Length);
                }
 
                public static string Join (string separator, string[] value, int startIndex, int count)
@@ -1835,16 +2302,65 @@ namespace System
                                throw new ArgumentOutOfRangeException ("startIndex", "< 0");
                        if (count < 0)
                                throw new ArgumentOutOfRangeException ("count", "< 0");
-                       // re-ordered to avoid possible integer overflow
                        if (startIndex > value.Length - count)
-                               throw new ArgumentOutOfRangeException ("startIndex + count > value.length");
+                               throw new ArgumentOutOfRangeException ("startIndex", "startIndex + count > value.length");
 
                        if (startIndex == value.Length)
                                return String.Empty;
                        if (separator == null)
                                separator = String.Empty;
 
-                       return InternalJoin (separator, value, startIndex, count);
+                       return JoinUnchecked (separator, value, startIndex, count);
+               }
+
+               private static unsafe string JoinUnchecked (string separator, string[] value, int startIndex, int count)
+               {
+                       // Unchecked parameters
+                       // startIndex, count must be >= 0; startIndex + count must be <= value.length
+                       // separator and value must not be null
+
+                       int length = 0;
+                       int maxIndex = startIndex + count;
+                       // Precount the number of characters that the resulting string will have
+                       for (int i = startIndex; i < maxIndex; i++) {
+                               String s = value[i];
+                               if (s != null)
+                                       length += s.length;
+                       }
+                       length += separator.length * (count - 1);
+                       if (length <= 0)
+                               return String.Empty;
+
+                       String tmp = InternalAllocateStr (length);
+
+                       maxIndex--;
+                       fixed (char* dest = tmp, sepsrc = separator) {
+                               // Copy each string from value except the last one and add a separator for each
+                               int pos = 0;
+                               for (int i = startIndex; i < maxIndex; i++) {
+                                       String source = value[i];
+                                       if (source != null) {
+                                               if (source.Length > 0) {
+                                                       fixed (char* src = source)
+                                                               CharCopy (dest + pos, src, source.Length);
+                                                       pos += source.Length;
+                                               }
+                                       }
+                                       if (separator.Length > 0) {
+                                               CharCopy (dest + pos, sepsrc, separator.Length);
+                                               pos += separator.Length;
+                                       }
+                               }
+                               // Append last string that does not get an additional separator
+                               String sourceLast = value[maxIndex];
+                               if (sourceLast != null) {
+                                       if (sourceLast.Length > 0) {
+                                               fixed (char* src = sourceLast)
+                                                       CharCopy (dest + pos, src, sourceLast.Length);
+                                       }
+                               }
+                       }
+                       return tmp;
                }
 
                bool IConvertible.ToBoolean (IFormatProvider provider)
@@ -1891,36 +2407,64 @@ namespace System
                {
                        return Convert.ToInt64 (this, provider);
                }
-       
+
+#if ONLY_1_1
+#pragma warning disable 3019
+               [CLSCompliant (false)]
+#endif
                sbyte IConvertible.ToSByte (IFormatProvider provider)
                {
                        return Convert.ToSByte (this, provider);
                }
+#if ONLY_1_1
+#pragma warning restore 3019
+#endif
 
                float IConvertible.ToSingle (IFormatProvider provider)
                {
                        return Convert.ToSingle (this, provider);
                }
 
-               object IConvertible.ToType (Type conversionType, IFormatProvider provider)
+               object IConvertible.ToType (Type type, IFormatProvider provider)
                {
-                       return Convert.ToType (this, conversionType,  provider);
+                       return Convert.ToType (this, type, provider, false);
                }
 
+#if ONLY_1_1
+#pragma warning disable 3019
+               [CLSCompliant (false)]
+#endif
                ushort IConvertible.ToUInt16 (IFormatProvider provider)
                {
                        return Convert.ToUInt16 (this, provider);
                }
+#if ONLY_1_1
+#pragma warning restore 3019
+#endif
 
+#if ONLY_1_1
+#pragma warning disable 3019
+               [CLSCompliant (false)]
+#endif
                uint IConvertible.ToUInt32 (IFormatProvider provider)
                {
                        return Convert.ToUInt32 (this, provider);
                }
+#if ONLY_1_1
+#pragma warning restore 3019
+#endif
 
+#if ONLY_1_1
+#pragma warning disable 3019
+               [CLSCompliant (false)]
+#endif
                ulong IConvertible.ToUInt64 (IFormatProvider provider)
                {
                        return Convert.ToUInt64 (this, provider);
                }
+#if ONLY_1_1
+#pragma warning restore 3019
+#endif
 
                public int Length {
                        get {
@@ -1936,7 +2480,7 @@ namespace System
 #if NET_2_0
                IEnumerator<char> IEnumerable<char>.GetEnumerator ()
                {
-                       return GetEnumerator ();
+                       return new CharEnumerator (this);
                }
 #endif
 
@@ -2095,7 +2639,7 @@ namespace System
 
                // Certain constructors are redirected to CreateString methods with
                // matching argument list. The this pointer should not be used.
-
+#pragma warning disable 169
                private unsafe String CreateString (sbyte* value)
                {
                        if (value == null)
@@ -2108,10 +2652,10 @@ namespace System
                                while (bytes++ [0] != 0)
                                        length++;
                        } catch (NullReferenceException) {
-                               throw new ArgumentOutOfRangeException ("value", "Value does not refer to a valid string.");
+                               throw new ArgumentOutOfRangeException ("ptr", "Value does not refer to a valid string.");
 #if NET_2_0
                        } catch (AccessViolationException) {
-                               throw new ArgumentOutOfRangeException ("value", "Value does not refer to a valid string.");
+                               throw new ArgumentOutOfRangeException ("ptr", "Value does not refer to a valid string.");
 #endif
                        }
 
@@ -2159,7 +2703,7 @@ namespace System
                                                        throw;
 #endif
 
-                                               throw new ArgumentOutOfRangeException ("value", "Value, startIndex and length do not refer to a valid string.");
+                                               throw new ArgumentOutOfRangeException ("ptr", "Value, startIndex and length do not refer to a valid string.");
 #if NET_2_0
                                        } catch (AccessViolationException) {
                                                if (!isDefaultEncoding)
@@ -2215,13 +2759,13 @@ namespace System
                unsafe string CreateString (char [] val, int startIndex, int length)
                {
                        if (val == null)
-                               throw new ArgumentNullException ("val");
+                               throw new ArgumentNullException ("value");
                        if (startIndex < 0)
-                               throw new ArgumentOutOfRangeException ("startIndex");
+                               throw new ArgumentOutOfRangeException ("startIndex", "Cannot be negative.");
                        if (length < 0)
-                               throw new ArgumentOutOfRangeException ("length");
+                               throw new ArgumentOutOfRangeException ("length", "Cannot be negative.");
                        if (startIndex > val.Length - length)
-                               throw new ArgumentOutOfRangeException ("Out of range");
+                               throw new ArgumentOutOfRangeException ("startIndex", "Cannot be negative, and should be less than length of string.");
                        if (length == 0)
                                return string.Empty;
 
@@ -2264,6 +2808,7 @@ namespace System
                        }
                        return result;
                }
+#pragma warning restore 169
 
                /* helpers used by the runtime as well as above or eslewhere in corlib */
                internal static unsafe void memset (byte *dest, int val, int len)
@@ -2486,34 +3031,34 @@ namespace System
                unsafe public extern String (sbyte *value, int startIndex, int length, Encoding enc);
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               public extern String (char [] val, int startIndex, int length);
+               public extern String (char [] value, int startIndex, int length);
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               public extern String (char [] val);
+               public extern String (char [] value);
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                public extern String (char c, int count);
 
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               private extern static string InternalJoin (string separator, string[] value, int sIndex, int count);
+//             [MethodImplAttribute (MethodImplOptions.InternalCall)]
+//             private extern static string InternalJoin (string separator, string[] value, int sIndex, int count);
 
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               private extern String InternalReplace (String oldValue, string newValue, CompareInfo comp);
+//             [MethodImplAttribute (MethodImplOptions.InternalCall)]
+//             private extern String InternalReplace (String oldValue, string newValue, CompareInfo comp);
 
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               private extern void InternalCopyTo (int sIndex, char[] dest, int destIndex, int count);
+//             [MethodImplAttribute (MethodImplOptions.InternalCall)]
+//             private extern void InternalCopyTo (int sIndex, char[] dest, int destIndex, int count);
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                private extern String[] InternalSplit (char[] separator, int count, int options);
 
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               private extern String InternalTrim (char[] chars, int typ);
+//             [MethodImplAttribute (MethodImplOptions.InternalCall)]
+//             private extern String InternalTrim (char[] chars, int typ);
 
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               private extern int InternalLastIndexOfAny (char [] anyOf, int sIndex, int count);
+//             [MethodImplAttribute (MethodImplOptions.InternalCall)]
+//             private extern int InternalLastIndexOfAny (char [] anyOf, int sIndex, int count);
 
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               private extern String InternalPad (int width, char chr, bool right);
+//             [MethodImplAttribute (MethodImplOptions.InternalCall)]
+//             private extern String InternalPad (int width, char chr, bool right);
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                internal extern static String InternalAllocateStr (int length);