2009-03-23 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mcs / class / corlib / System / String.cs
index f8188703f0f287b7499fdb3ae78b4e7cd745f006..7533f40da254d2e70bd6fbde1847b28fbe89d84f 100644 (file)
@@ -7,6 +7,7 @@
 //   Dan Lewis (dihlewis@yahoo.co.uk)
 //   Sebastien Pouliot  <sebastien@ximian.com>
 //   Marek Safar (marek.safar@seznam.cz)
+//   Andreas Nahr (Classdevelopment@A-SoftTech.com)
 //
 // (C) 2001 Ximian, Inc.  http://www.ximian.com
 // Copyright (C) 2004-2005 Novell (http://www.novell.com)
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
+//
+//
+// This class contains all implementation for culture-insensitive methods.
+// Culture-sensitive methods are implemented in the System.Globalization or
+// Mono.Globalization namespace.
+//
+// Ensure that argument checks on methods don't overflow
+//
 
 using System.Text;
 using System.Collections;
@@ -56,10 +65,6 @@ namespace System
                [NonSerialized] private int length;
                [NonSerialized] private char start_char;
 
-               private const int COMPARE_CASE = 0;
-               private const int COMPARE_INCASE = 1;
-               private const int COMPARE_ORDINAL = 2;
-
                public static readonly String Empty = "";
 
                public static unsafe bool Equals (string a, string b)
@@ -141,9 +146,13 @@ namespace System
                }
 
                [IndexerName ("Chars")]
-               public extern char this [int index] {
-                       [MethodImplAttribute (MethodImplOptions.InternalCall)]
-                       get;
+               public unsafe char this [int index] {
+                       get {
+                               if (index < 0 || index >= length)
+                                       throw new IndexOutOfRangeException ();
+                               fixed (char* c = &start_char)
+                                       return c[index];
+                       }
                }
 
                public Object Clone ()
@@ -156,44 +165,45 @@ namespace System
                        return TypeCode.String;
                }
 
-               public void CopyTo (int sourceIndex, char[] destination, int destinationIndex, int count)
+               public unsafe void CopyTo (int sourceIndex, char[] destination, int destinationIndex, int count)
                {
-                       // LAMESPEC: should I null-terminate?
                        if (destination == null)
                                throw new ArgumentNullException ("destination");
-
-                       if (sourceIndex < 0 || destinationIndex < 0 || count < 0)
-                               throw new ArgumentOutOfRangeException (); 
-
-                       // re-ordered to avoid possible integer overflow
+                       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");
-                       // re-ordered to avoid possible integer overflow
+                               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");
 
-                       InternalCopyTo (sourceIndex, destination, destinationIndex, count);
+                       fixed (char* dest = destination, src = this)
+                               CharCopy (dest + destinationIndex, src + sourceIndex, count);
                }
 
-               public char[] ToCharArray ()
+               public unsafe char[] ToCharArray ()
                {
-                       return ToCharArray (0, length);
+                       char[] tmp = new char [length];
+                       fixed (char* dest = tmp, src = this)
+                               CharCopy (dest, src, length);
+                       return tmp;
                }
 
-               public char[] ToCharArray (int startIndex, int length)
+               public unsafe char[] ToCharArray (int startIndex, int length)
                {
                        if (startIndex < 0)
                                throw new ArgumentOutOfRangeException ("startIndex", "< 0"); 
                        if (length < 0)
                                throw new ArgumentOutOfRangeException ("length", "< 0"); 
-                       // re-ordered to avoid possible integer overflow
                        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];
-
-                       InternalCopyTo (startIndex, tmp, 0, length);
-
+                       fixed (char* dest = tmp, src = this)
+                               CharCopy (dest, src + startIndex, length);
                        return tmp;
                }
 
@@ -214,14 +224,14 @@ namespace System
                                return new String[0];
 
                        if (count == 1) 
-                               return new String[1] { ToString() };
+                               return new String[1] { this };
 
-                       return InternalSplit (separator, count);
+                       return InternalSplit (separator, count, 0);
                }
 
 #if NET_2_0
                [ComVisible (false)]
-               [MonoTODO]
+               [MonoDocumentationNote ("code should be moved to managed")]
                public String[] Split (char[] separator, int count, StringSplitOptions options)
                {
                        if (separator == null || separator.Length == 0)
@@ -230,30 +240,12 @@ 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 + ".");
 
-                       bool removeEmpty = (options & StringSplitOptions.RemoveEmptyEntries) == StringSplitOptions.RemoveEmptyEntries;
+                       if (count == 0)
+                               return new string [0];
 
-                       if (!removeEmpty)
-                               return Split (separator, count);
-                       else {
-                               /* FIXME: Optimize this */
-                               String[] res = Split (separator, count);
-                               int n = 0;
-                               for (int i = 0; i < res.Length; ++i)
-                                       if (res [i] == String.Empty)
-                                               n ++;
-                               if (n > 0) {
-                                       String[] arr = new String [res.Length - n];
-                                       int pos = 0;
-                                       for (int i = 0; i < res.Length; ++i)
-                                               if (res [i] != String.Empty)
-                                                       arr [pos ++] = res [i];
-                                       return arr;
-                               }
-                               else
-                                       return res;
-                       }
+                       return InternalSplit (separator, count, (int)options);
                }
 
                [ComVisible (false)]
@@ -265,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;
 
@@ -275,6 +267,7 @@ namespace System
                        ArrayList arr = new ArrayList ();
 
                        int pos = 0;
+                       int matchCount = 0;
                        while (pos < this.Length) {
                                int matchIndex = -1;
                                int matchPos = Int32.MaxValue;
@@ -295,21 +288,18 @@ namespace System
                                if (matchIndex == -1)
                                        break;
 
-                               if (matchPos == pos && removeEmpty) {
-                                       pos = matchPos + separator [matchIndex].Length;
-                               }
-                               else {
+                               if (!(matchPos == pos && removeEmpty))
                                        arr.Add (this.Substring (pos, matchPos - pos));
 
-                                       pos = matchPos + separator [matchIndex].Length;
+                               pos = matchPos + separator [matchIndex].Length;
 
-                                       if (arr.Count == count - 1) {
-                                               break;
-                                       }
-                               }
+                               matchCount ++;
+
+                               if (matchCount == count - 1)
+                                       break;
                        }
 
-                       if (arr.Count == 0)
+                       if (matchCount == 0)
                                return new String [] { this };
                        else {
                                if (removeEmpty && pos == this.Length) {
@@ -341,41 +331,57 @@ namespace System
                }
 #endif
 
-               public unsafe String Substring (int startIndex)
+               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.");
 
-                       int newlen = this.length - startIndex;
-                       string tmp = InternalAllocateStr (newlen);
-                       if (newlen != 0) {
-                               fixed (char *dest = tmp, src = this) {
-                                       memcpy ((byte*)dest, (byte*)(src + startIndex), newlen * 2);
-                               }
-                       }
-                       return tmp;
+                       if (startIndex > this.length)
+                               throw new ArgumentOutOfRangeException ("length", "Cannot exceed length of string.");
+#endif
+
+                       return SubstringUnchecked (startIndex, this.length - startIndex);
                }
 
-               public unsafe String Substring (int startIndex, int length)
+               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");
-                       // re-ordered to avoid possible integer overflow
+                               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)
                                return String.Empty;
 
                        string tmp = InternalAllocateStr (length);
-                       fixed (char *dest = tmp, src = this) {
-                               memcpy ((byte*)dest, (byte*)(src + startIndex), length * 2);
+                       fixed (chardest = tmp, src = this) {
+                               CharCopy (dest, src + startIndex, length);
                        }
-
                        return tmp;
-               }       
+               }
 
                private static readonly char[] WhiteChars = { (char) 0x9, (char) 0xA, (char) 0xB, (char) 0xC, (char) 0xD,
 #if NET_2_0
@@ -387,41 +393,127 @@ 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 ();
 
-                       return InternalTrim (trimChars, 0);
+                       if (length == 0) 
+                               return String.Empty;
+                       int start = FindNotInTable (0, length, 1, trimChars);
+
+                       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 InternalTrim (trimChars, 2);
+                       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;
+               }
+
+               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)
                {
-                       return Compare (strA, strB, false, CultureInfo.CurrentCulture);
+                       return CultureInfo.CurrentCulture.CompareInfo.Compare (strA, strB, CompareOptions.None);
                }
 
                public static int Compare (String strA, String strB, bool ignoreCase)
                {
-                       return Compare (strA, strB, ignoreCase, CultureInfo.CurrentCulture);
+                       return CultureInfo.CurrentCulture.CompareInfo.Compare (strA, strB, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
                }
 
                public static int Compare (String strA, String strB, bool ignoreCase, CultureInfo culture)
@@ -429,25 +521,7 @@ namespace System
                        if (culture == null)
                                throw new ArgumentNullException ("culture");
 
-                       if (strA == null) {
-                               if (strB == null)
-                                       return 0;
-                               else
-                                       return -1;
-
-                       }
-                       else if (strB == null) {
-                               return 1;
-                       }
-
-                       CompareOptions compopts;
-
-                       if (ignoreCase)
-                               compopts = CompareOptions.IgnoreCase;
-                       else
-                               compopts = CompareOptions.None;
-
-                       return culture.CompareInfo.Compare (strA, strB, compopts);
+                       return culture.CompareInfo.Compare (strA, strB, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
                }
 
                public static int Compare (String strA, int indexA, String strB, int indexB, int length)
@@ -489,11 +563,11 @@ namespace System
                        else
                                compopts = CompareOptions.None;
 
-                       /* Need to cap the requested length to the
-                        * length of the string, because
-                        * CompareInfo.Compare will insist that length
-                        * <= (string.Length - offset)
-                        */
+                       // Need to cap the requested length to the
+                       // length of the string, because
+                       // CompareInfo.Compare will insist that length
+                       // <= (string.Length - offset)
+
                        int len1 = length;
                        int len2 = length;
                        
@@ -505,6 +579,7 @@ namespace System
                                len2 = strB.Length - indexB;
                        }
 
+                       // ENHANCE: Might call internal_compare_switch directly instead of doing all checks twice
                        return culture.CompareInfo.Compare (strA, indexA, len1, strB, indexB, len2, compopts);
                }
 #if NET_2_0
@@ -520,12 +595,12 @@ namespace System
                        case StringComparison.InvariantCultureIgnoreCase:
                                return Compare (strA, strB, true, CultureInfo.InvariantCulture);
                        case StringComparison.Ordinal:
-                               return CompareOrdinal (strA, strB, CompareOptions.Ordinal);
+                               return CompareOrdinalUnchecked (strA, 0, Int32.MaxValue, strB, 0, Int32.MaxValue);
                        case StringComparison.OrdinalIgnoreCase:
-                               return CompareOrdinal (strA, strB, CompareOptions.Ordinal | CompareOptions.IgnoreCase);
+                               return CompareOrdinalCaseInsensitiveUnchecked (strA, 0, Int32.MaxValue, strB, 0, Int32.MaxValue);
                        default:
                                string msg = Locale.GetText ("Invalid value '{0}' for StringComparison", comparisonType);
-                               throw new ArgumentException ("comparisonType", msg);
+                               throw new ArgumentException (msg, "comparisonType");
                        }
                }
 
@@ -541,12 +616,12 @@ namespace System
                        case StringComparison.InvariantCultureIgnoreCase:
                                return Compare (strA, indexA, strB, indexB, length, true, CultureInfo.InvariantCulture);
                        case StringComparison.Ordinal:
-                               return CompareOrdinal (strA, indexA, strB, indexB, length, CompareOptions.Ordinal);
+                               return CompareOrdinal (strA, indexA, strB, indexB, length);
                        case StringComparison.OrdinalIgnoreCase:
-                               return CompareOrdinal (strA, indexA, strB, indexB, length, CompareOptions.Ordinal | CompareOptions.IgnoreCase);
+                               return CompareOrdinalCaseInsensitive (strA, indexA, strB, indexB, length);
                        default:
                                string msg = Locale.GetText ("Invalid value '{0}' for StringComparison", comparisonType);
-                               throw new ArgumentException ("comparisonType", msg);
+                               throw new ArgumentException (msg, "comparisonType");
                        }
                }
 
@@ -557,9 +632,35 @@ namespace System
 
                public bool Equals (string value, StringComparison comparisonType)
                {
-                       return String.Equals (this, value, comparisonType);
+                       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)
@@ -568,7 +669,7 @@ namespace System
                        if (!(value is String))
                                throw new ArgumentException ();
 
-                       return String.Compare (this, (String) value, false);
+                       return String.Compare (this, (String) value);
                }
 
                public int CompareTo (String strB)
@@ -576,75 +677,101 @@ namespace System
                        if (strB == null)
                                return 1;
 
-                       return Compare (this, strB, false);
+                       return Compare (this, strB);
                }
 
                public static int CompareOrdinal (String strA, String strB)
                {
-                       return CompareOrdinal (strA, strB, CompareOptions.Ordinal);
+                       return CompareOrdinalUnchecked (strA, 0, Int32.MaxValue, strB, 0, Int32.MaxValue);
+               }
+
+               public static int CompareOrdinal (String strA, int indexA, String strB, int indexB, int length)
+               {
+                       if ((indexA > strA.Length) || (indexB > strB.Length) || (indexA < 0) || (indexB < 0) || (length < 0))
+                               throw new ArgumentOutOfRangeException ();
+
+                       return CompareOrdinalUnchecked (strA, indexA, length, strB, indexB, length);
+               }
+
+               internal static int CompareOrdinalCaseInsensitive (String strA, int indexA, String strB, int indexB, int length)
+               {
+                       if ((indexA > strA.Length) || (indexB > strB.Length) || (indexA < 0) || (indexB < 0) || (length < 0))
+                               throw new ArgumentOutOfRangeException ();
+
+                       return CompareOrdinalCaseInsensitiveUnchecked (strA, indexA, length, strB, indexB, length);
                }
 
-               internal static int CompareOrdinal (String strA, String strB, CompareOptions options)
+               internal static unsafe int CompareOrdinalUnchecked (String strA, int indexA, int lenA, String strB, int indexB, int lenB)
                {
                        if (strA == null) {
                                if (strB == null)
                                        return 0;
                                else
                                        return -1;
-                       }
-                       else if (strB == null) {
+                       } else if (strB == null) {
                                return 1;
                        }
+                       int lengthA = Math.Min (lenA, strA.Length - indexA);
+                       int lengthB = Math.Min (lenB, strB.Length - indexB);
 
-                       /* Invariant, because that is cheaper to
-                        * instantiate (and chances are it already has
-                        * been.)
-                        */
-                       return CultureInfo.InvariantCulture.CompareInfo.Compare (strA, strB, options);
-               }
+                       if (lengthA == lengthB && Object.ReferenceEquals (strA, strB))
+                               return 0;
 
-               public static int CompareOrdinal (String strA, int indexA, String strB, int indexB, int length)
-               {
-                       return CompareOrdinal (strA, indexA, strB, indexB, length, CompareOptions.Ordinal);
+                       fixed (char* aptr = strA, bptr = strB) {
+                               char* ap = aptr + indexA;
+                               char* end = ap + Math.Min (lengthA, lengthB);
+                               char* bp = bptr + indexB;
+                               while (ap < end) {
+                                       if (*ap != *bp)
+                                               return *ap - *bp;
+                                       ap++;
+                                       bp++;
+                               }
+                               return lengthA - lengthB;
+                       }
                }
 
-               internal static int CompareOrdinal (String strA, int indexA, String strB, int indexB, int length, CompareOptions options)
+               internal static unsafe int CompareOrdinalCaseInsensitiveUnchecked (String strA, int indexA, int lenA, String strB, int indexB, int lenB)
                {
-                       if ((indexA > strA.Length) || (indexB > strB.Length) || (indexA < 0) || (indexB < 0) || (length < 0))
-                               throw new ArgumentOutOfRangeException ();
-
+                       // Same as above, but checks versus uppercase characters
                        if (strA == null) {
                                if (strB == null)
                                        return 0;
                                else
                                        return -1;
-                       }
-                       else if (strB == null) {
+                       } else if (strB == null) {
                                return 1;
                        }
+                       int lengthA = Math.Min (lenA, strA.Length - indexA);
+                       int lengthB = Math.Min (lenB, strB.Length - indexB);
 
-                       /* Need to cap the requested length to the
-                        * length of the string, because
-                        * CompareInfo.Compare will insist that length
-                        * <= (string.Length - offset)
-                        */
-                       int len1 = length;
-                       int len2 = length;
-
-                       if (length > (strA.Length - indexA)) {
-                               len1 = strA.Length - indexA;
-                       }
+                       if (lengthA == lengthB && Object.ReferenceEquals (strA, strB))
+                               return 0;
 
-                       if (length > (strB.Length - indexB)) {
-                               len2 = strB.Length - indexB;
+                       fixed (char* aptr = strA, bptr = strB) {
+                               char* ap = aptr + indexA;
+                               char* end = ap + Math.Min (lengthA, lengthB);
+                               char* bp = bptr + indexB;
+                               while (ap < end) {
+                                       if (*ap != *bp) {
+                                               char c1 = Char.ToUpperInvariant (*ap);
+                                               char c2 = Char.ToUpperInvariant (*bp);
+                                               if (c1 != c2)
+                                                       return c1 - c2;
+                                       }
+                                       ap++;
+                                       bp++;
+                               }
+                               return lengthA - lengthB;
                        }
-
-                       return CultureInfo.InvariantCulture.CompareInfo.Compare (strA, indexA, len1, strB, indexB, len2, options);
                }
 
                public bool EndsWith (String value)
                {
-                       return EndsWith (value, false, CultureInfo.CurrentCulture);
+                       if (value == null)
+                               throw new ArgumentNullException ("value");
+
+                       return CultureInfo.CurrentCulture.CompareInfo.IsSuffix (this, value, CompareOptions.None);
                }
 
 #if NET_2_0
@@ -654,58 +781,113 @@ namespace System
 #endif
                bool EndsWith (String value, bool ignoreCase, CultureInfo culture)
                {
-                       return (culture.CompareInfo.IsSuffix (this, value,
-                               ignoreCase ? CompareOptions.IgnoreCase :
-                               CompareOptions.None));
+                       if (value == null)
+                               throw new ArgumentNullException ("value");
+                       if (culture == null)
+                               culture = CultureInfo.CurrentCulture;
+
+                       return culture.CompareInfo.IsSuffix (this, value,
+                               ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
                }
 
+               // Following methods are culture-insensitive
                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);
                }
 
+               private unsafe int IndexOfAnyUnchecked (char[] anyOf, int startIndex, int count)
+               {
+                       if (anyOf.Length == 0)
+                               return -1;
+
+                       if (anyOf.Length == 1)
+                               return IndexOfUnchecked (anyOf[0], startIndex, count);
+
+                       fixed (char* any = anyOf) {
+                               int highest = *any;
+                               int lowest = *any;
+
+                               char* end_any_ptr = any + anyOf.Length;
+                               char* any_ptr = any;
+                               while (++any_ptr != end_any_ptr) {
+                                       if (*any_ptr > highest) {
+                                               highest = *any_ptr;
+                                               continue;
+                                       }
+
+                                       if (*any_ptr < lowest)
+                                               lowest = *any_ptr;
+                               }
+
+                               fixed (char* start = &start_char) {
+                                       char* ptr = start + startIndex;
+                                       char* end_ptr = ptr + count;
+
+                                       while (ptr != end_ptr) {
+                                               if (*ptr > highest || *ptr < lowest) {
+                                                       ptr++;
+                                                       continue;
+                                               }
+
+                                               if (*ptr == *any)
+                                                       return (int)(ptr - start);
+
+                                               any_ptr = any;
+                                               while (++any_ptr != end_any_ptr) {
+                                                       if (*ptr == *any_ptr)
+                                                               return (int)(ptr - start);
+                                               }
+
+                                               ptr++;
+                                       }
+                               }
+                       }
+                       return -1;
+               }
+
+
 #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:
@@ -715,26 +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");
                        }
-                       throw new SystemException ("INTERNAL ERROR: should not reach here ...");
                }
+#endif
 
-               public int LastIndexOf (string value, StringComparison comparison)
+               internal int IndexOfOrdinal (string value, int startIndex, int count, CompareOptions options)
                {
-                       return LastIndexOf (value, value.Length - 1, value.Length, comparison);
+                       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);
                }
 
-               public int LastIndexOf (string value, int startIndex, StringComparison comparison)
+               internal unsafe int IndexOfOrdinalUnchecked (string value, int startIndex, int count)
                {
-                       return LastIndexOf (value, startIndex, startIndex + 1, comparison);
+                       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;
+
+                       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, int startIndex, int count, StringComparison comparison)
+#if NET_2_0
+
+               public int LastIndexOf (string value, StringComparison comparisonType)
                {
-                       switch (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 comparisonType)
+               {
+                       return LastIndexOf (value, startIndex, startIndex + 1, comparisonType);
+               }
+
+               public int LastIndexOf (string value, int startIndex, int count, StringComparison comparisonType)
+               {
+                       switch (comparisonType) {
                        case StringComparison.CurrentCulture:
                                return CultureInfo.CurrentCulture.CompareInfo.LastIndexOf (this, value, startIndex, count, CompareOptions.None);
                        case StringComparison.CurrentCultureIgnoreCase:
@@ -744,67 +1003,206 @@ 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");
                        }
-                       throw new SystemException ("INTERNAL ERROR: should not reach here ...");
                }
 #endif
 
-               public int IndexOf (char value)
+               internal int LastIndexOfOrdinal (string value, int startIndex, int count, CompareOptions options)
                {
-                       return IndexOf (value, 0, this.length);
+                       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");
+
+                       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;
 
-                       for (int pos = startIndex; pos < startIndex + count; pos++) {
-                               if (this[pos] == value)
-                                       return(pos);
+                       return IndexOfUnchecked (value, startIndex, count);
+               }
+
+               internal unsafe int IndexOfUnchecked (char value, int startIndex, int count)
+               {
+                       // It helps JIT compiler to optimize comparison
+                       int value_32 = (int)value;
+
+                       fixed (char* start = &start_char) {
+                               char* ptr = start + startIndex;
+                               char* end_ptr = ptr + (count >> 3 << 3);
+
+                               while (ptr != end_ptr) {
+                                       if (*ptr == value_32)
+                                               return (int)(ptr - start);
+                                       if (ptr[1] == value_32)
+                                               return (int)(ptr - start + 1);
+                                       if (ptr[2] == value_32)
+                                               return (int)(ptr - start + 2);
+                                       if (ptr[3] == value_32)
+                                               return (int)(ptr - start + 3);
+                                       if (ptr[4] == value_32)
+                                               return (int)(ptr - start + 4);
+                                       if (ptr[5] == value_32)
+                                               return (int)(ptr - start + 5);
+                                       if (ptr[6] == value_32)
+                                               return (int)(ptr - start + 6);
+                                       if (ptr[7] == value_32)
+                                               return (int)(ptr - start + 7);
+
+                                       ptr += 8;
+                               }
+
+                               end_ptr += count & 0x07;
+                               while (ptr != end_ptr) {
+                                       if (*ptr == value_32)
+                                               return (int)(ptr - start);
+
+                                       ptr++;
+                               }
+                               return -1;
+                       }
+               }
+
+               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;
                }
 
-               /* But this one is culture-sensitive */
+               // 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;
@@ -818,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");
@@ -855,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;
-                       else
-                               return LastIndexOf (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)
@@ -880,42 +1295,104 @@ namespace System
                        return LastIndexOf (value, startIndex, startIndex + 1);
                }
 
+               public int LastIndexOf (char value, int startIndex, int count)
+               {
+                       if (startIndex == 0 && this.length == 0)
+                               return -1;
+
+                       // >= for char (> for string)
+                       if ((startIndex < 0) || (startIndex >= this.Length))
+                               throw new ArgumentOutOfRangeException ("startIndex", "< 0 || >= this.Length");
+                       if ((count < 0) || (count > this.Length))
+                               throw new ArgumentOutOfRangeException ("count", "< 0 || > this.Length");
+                       if (startIndex - count + 1 < 0)
+                               throw new ArgumentOutOfRangeException ("startIndex - count + 1 < 0");
+
+                       return LastIndexOfUnchecked (value, startIndex, count);
+               }
+
+               internal unsafe int LastIndexOfUnchecked (char value, int startIndex, int count)
+               {
+                       // It helps JIT compiler to optimize comparison
+                       int value_32 = (int)value;
+
+                       fixed (char* start = &start_char) {
+                               char* ptr = start + startIndex;
+                               char* end_ptr = ptr - (count >> 3 << 3);
+
+                               while (ptr != end_ptr) {
+                                       if (*ptr == value_32)
+                                               return (int)(ptr - start);
+                                       if (ptr[-1] == value_32)
+                                               return (int)(ptr - start) - 1;
+                                       if (ptr[-2] == value_32)
+                                               return (int)(ptr - start) - 2;
+                                       if (ptr[-3] == value_32)
+                                               return (int)(ptr - start) - 3;
+                                       if (ptr[-4] == value_32)
+                                               return (int)(ptr - start) - 4;
+                                       if (ptr[-5] == value_32)
+                                               return (int)(ptr - start) - 5;
+                                       if (ptr[-6] == value_32)
+                                               return (int)(ptr - start) - 6;
+                                       if (ptr[-7] == value_32)
+                                               return (int)(ptr - start) - 7;
+
+                                       ptr -= 8;
+                               }
+
+                               end_ptr -= count & 0x07;
+                               while (ptr != end_ptr) {
+                                       if (*ptr == value_32)
+                                               return (int)(ptr - start);
+
+                                       ptr--;
+                               }
+                               return -1;
+                       }
+               }
+
+               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)
                {
-                       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)
-                               return -1;
-
-                       // >= for char (> for string)
-                       if ((startIndex < 0) || (startIndex >= this.Length))
-                               throw new ArgumentOutOfRangeException ("startIndex", "< 0 || >= this.Length");
-                       if ((count < 0) || (count > this.Length))
-                               throw new ArgumentOutOfRangeException ("count", "< 0 || > this.Length");
-                       if (startIndex - count + 1 < 0)
-                               throw new ArgumentOutOfRangeException ("startIndex - count + 1 < 0");
-
-                       for(int pos = startIndex; pos > startIndex - count; pos--) {
-                               if (this [pos] == value)
-                                       return pos;
-                       }
-                       return -1;
-               }
-
-               /* But this one is culture-sensitive */
                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");
@@ -955,12 +1432,12 @@ namespace System
 
                public string Normalize ()
                {
-                       return Normalize (NormalizationForm.FormC);
+                       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:
@@ -974,12 +1451,12 @@ namespace System
 
                public bool IsNormalized ()
                {
-                       return IsNormalized (NormalizationForm.FormC);
+                       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:
@@ -1007,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);
+
+                       fixed (char* dest = tmp, src = this) {
+                               char* padPos = dest;
+                               char* padTo = dest + (totalWidth - length);
+                               while (padPos != padTo)
+                                       *padPos++ = paddingChar;
 
-                       return InternalPad (totalWidth, paddingChar, false);
+                               CharCopy (padTo, src, length);
+                       }
+                       return tmp;
                }
 
                public String PadRight (int totalWidth)
@@ -1023,25 +1512,44 @@ 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;
 
-                       return InternalPad (totalWidth, paddingChar, true);
+                       String tmp = InternalAllocateStr (totalWidth);
+
+                       fixed (char* dest = tmp, src = this) {
+                               CharCopy (dest, src, length);
+
+                               char* padPos = dest + length;
+                               char* padTo = dest + totalWidth;
+                               while (padPos != padTo)
+                                       *padPos++ = paddingChar;
+                       }
+                       return tmp;
                }
 
                public bool StartsWith (String value)
                {
-                       return StartsWith (value, false, CultureInfo.CurrentCulture);
+                       if (value == null)
+                               throw new ArgumentNullException ("value");
+
+                       return CultureInfo.CurrentCulture.CompareInfo.IsPrefix (this, value, CompareOptions.None);
                }
 
 #if NET_2_0
+               [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);
@@ -1056,12 +1564,17 @@ namespace System
                        case StringComparison.OrdinalIgnoreCase:
                                return CultureInfo.CurrentCulture.CompareInfo.IsPrefix (this, value, CompareOptions.OrdinalIgnoreCase);
                        default:
-                               return false;
+                               string msg = Locale.GetText ("Invalid value '{0}' for StringComparison", comparisonType);
+                               throw new ArgumentException (msg, "comparisonType");
                        }
                }
 
+               [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);
@@ -1076,10 +1589,10 @@ namespace System
                        case StringComparison.OrdinalIgnoreCase:
                                return CultureInfo.CurrentCulture.CompareInfo.IsSuffix (this, value, CompareOptions.OrdinalIgnoreCase);
                        default:
-                               return false;
+                               string msg = Locale.GetText ("Invalid value '{0}' for StringComparison", comparisonType);
+                               throw new ArgumentException (msg, "comparisonType");
                        }
                }
-
 #endif
 
 #if NET_2_0
@@ -1092,20 +1605,50 @@ namespace System
                        if (culture == null)
                                culture = CultureInfo.CurrentCulture;
                        
-                       return (culture.CompareInfo.IsPrefix (this, value,
-                               ignoreCase ? CompareOptions.IgnoreCase :
-                               CompareOptions.None));
+                       return culture.CompareInfo.IsPrefix (this, value, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
                }
 
-               /* This method is culture insensitive */
-               public String Replace (char oldChar, char newChar)
+               // Following method is culture-insensitive
+               public unsafe String Replace (char oldChar, char newChar)
                {
-                       return InternalReplace (oldChar, newChar);
+                       if (this.length == 0 || oldChar == newChar)
+                               return this;
+
+                       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);
+                       fixed (char* dest = tmp, src = &start_char) {
+                               if (start_pos != 0)
+                                       CharCopy (dest, src, start_pos);
+
+                               char* end_ptr = dest + length;
+                               char* dest_ptr = dest + start_pos;
+                               char* src_ptr = src + start_pos;
+
+                               while (dest_ptr != end_ptr) {
+                                       if (*src_ptr == oldChar)
+                                               *dest_ptr = newChar;
+                                       else
+                                               *dest_ptr = *src_ptr;
+
+                                       ++src_ptr;
+                                       ++dest_ptr;
+                               }
+                       }
+                       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");
 
@@ -1118,27 +1661,91 @@ 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");
-                       // re-ordered to avoid possible integer overflow
+                               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);
 
                        fixed (char *dest = tmp, src = this) {
                                char *dst = dest;
-                               memcpy ((byte*)dst, (byte*)src, startIndex * 2);
+                               CharCopy (dst, src, startIndex);
                                int skip = startIndex + count;
                                dst += startIndex;
-                               memcpy ((byte*)dst, (byte*)(src + skip), (length - skip) * 2);
+                               CharCopy (dst, src + skip, length - skip);
                        }
                        return tmp;
                }
@@ -1153,9 +1760,9 @@ namespace System
                        if (culture == null)
                                throw new ArgumentNullException ("culture");
 
-                       if (culture.LCID == 0x007F) // Invariant
+                       if (culture.LCID == 0x007F) // Invariant
                                return ToLowerInvariant ();
-                       }
+
                        return culture.TextInfo.ToLower (this);
                }
 
@@ -1190,9 +1797,9 @@ namespace System
                        if (culture == null)
                                throw new ArgumentNullException ("culture");
 
-                       if (culture.LCID == 0x007F) // Invariant
+                       if (culture.LCID == 0x007F) // Invariant
                                return ToUpperInvariant ();
-                       }
+
                        return culture.TextInfo.ToUpper (this);
                }
 
@@ -1249,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;
@@ -1333,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)
@@ -1345,26 +1973,26 @@ namespace System
                        String tmp = InternalAllocateStr (length);
                        if (length != 0) {
                                fixed (char *dest = tmp, src = str) {
-                                       memcpy ((byte*)dest, (byte*)src, length * 2);
+                                       CharCopy (dest, src, length);
                                }
                        }
                        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)
@@ -1377,67 +2005,67 @@ namespace System
                        String tmp = InternalAllocateStr (s1.Length + s2.Length);
                        if (s1.Length != 0) {
                                fixed (char *dest = tmp, src = s1) {
-                                       memcpy ((byte*)dest, (byte*)src, s1.length * 2);
+                                       CharCopy (dest, src, s1.length);
                                }
                        }
                        if (s2.Length != 0) {
                                fixed (char *dest = tmp, src = s2) {
-                                       memcpy ((byte*)(dest + s1.Length), (byte*)src, s2.length * 2);
+                                       CharCopy (dest + s1.Length, src, s2.length);
                                }
                        }
 
                        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 ();
@@ -1450,113 +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);
 
-                       if (s1.Length != 0) {
-                               fixed (char *dest = tmp, src = s1) {
-                                       memcpy ((byte*)dest, (byte*)src, s1.length * 2);
-                               }
-                       }
-                       if (s2.Length != 0) {
-                               fixed (char *dest = tmp, src = s2) {
-                                       memcpy ((byte*)(dest + s1.Length), (byte*)src, s2.length * 2);
-                               }
-                       }
+                       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;
                                }
                        }
 
-                       //return InternalConcat (s1, s2, s3);
-                       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) {
-                                       memcpy ((byte*)dest, (byte*)src, s1.length * 2);
+                       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) {
-                                       memcpy ((byte*)(dest + s1.Length), (byte*)src, s2.length * 2);
+                       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) {
-                                       memcpy ((byte*)(dest + s1.Length + s2.Length), (byte*)src, s3.length * 2);
+                       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) {
-                                       memcpy ((byte*)dest, (byte*)src, s1.length * 2);
+                       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) {
-                                       memcpy ((byte*)(dest + s1.Length), (byte*)src, s2.length * 2);
+                       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) {
-                                       memcpy ((byte*)(dest + s1.Length + s2.Length), (byte*)src, s3.length * 2);
+                       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) {
-                                       memcpy ((byte*)(dest + s1.Length + s2.Length + s3.Length), (byte*)src, s4.length * 2);
+                       if (str3.Length != 0) {
+                               fixed (char *dest = tmp, src = str3) {
+                                       CharCopy (dest + str0.Length + str1.Length + str2.Length, src, str3.length);
                                }
                        }
 
@@ -1568,27 +2189,22 @@ namespace System
                        if (args == null)
                                throw new ArgumentNullException ("args");
 
-                       int i = args.Length;
-                       if (i == 0)
+                       int argLen = args.Length;
+                       if (argLen == 0)
                                return String.Empty;
 
-                       string [] strings = new string [i];
-                       i = 0;
+                       string [] strings = new string [argLen];
                        int len = 0;
-                       foreach (object arg in args) {
-                               if (arg == null) {
-                                       strings[i] = String.Empty;
-                               } else {
-                                       strings[i] = arg.ToString ();
+                       for (int i = 0; i < argLen; i++) {
+                               if (args[i] != null) {
+                                       strings[i] = args[i].ToString ();
                                        len += strings[i].length;
                                }
-                               i++;
                        }
-
                        if (len == 0)
                                return String.Empty;
 
-                       return InternalJoin (String.Empty, strings, 0, strings.Length);
+                       return ConcatInternal (strings, len);
                }
 
                public static String Concat (params String[] values)
@@ -1596,7 +2212,35 @@ namespace System
                        if (values == null)
                                throw new ArgumentNullException ("values");
 
-                       return InternalJoin (String.Empty, values, 0, values.Length);
+                       int len = 0;
+                       for (int i = 0; i < values.Length; i++) {
+                               String s = values[i];
+                               if (s != null)
+                                       len += s.length;
+                       }
+                       if (len == 0)
+                               return String.Empty;
+
+                       return ConcatInternal (values, len);
+               }
+
+               private static unsafe String ConcatInternal (String[] values, int length)
+               {
+                       String tmp = InternalAllocateStr (length);
+
+                       fixed (char* dest = tmp) {
+                               int pos = 0;
+                               for (int i = 0; i < values.Length; i++) {
+                                       String source = values[i];
+                                       if (source != null) {
+                                               fixed (char* src = source) {
+                                                       CharCopy (dest + pos, src, source.length);
+                                               }
+                                               pos += source.Length;
+                                       }
+                               }
+                       }
+                       return tmp;
                }
 
                public unsafe String Insert (int startIndex, String value)
@@ -1605,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;
@@ -1615,16 +2259,15 @@ namespace System
 
                        fixed (char *dest = tmp, src = this, val = value) {
                                char *dst = dest;
-                               memcpy ((byte*)dst, (byte*)src, startIndex * 2);
+                               CharCopy (dst, src, startIndex);
                                dst += startIndex;
-                               memcpy ((byte*)dst, (byte*)val, value.length * 2);
+                               CharCopy (dst, val, value.length);
                                dst += value.length;
-                               memcpy ((byte*)dst, (byte*)(src + startIndex), (length - startIndex) * 2);
+                               CharCopy (dst, src + startIndex, length - startIndex);
                        }
                        return tmp;
                }
 
-
                public static string Intern (string str)
                {
                        if (str == null)
@@ -1645,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)
@@ -1657,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)
@@ -1713,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 {
@@ -1758,7 +2480,7 @@ namespace System
 #if NET_2_0
                IEnumerator<char> IEnumerable<char>.GetEnumerator ()
                {
-                       return GetEnumerator ();
+                       return new CharEnumerator (this);
                }
 #endif
 
@@ -1880,6 +2602,7 @@ namespace System
 #if NET_2_0
                [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
 #endif
+               // When modifying it, GetCaseInsensitiveHashCode() should be modified as well.
                public unsafe override int GetHashCode ()
                {
                        fixed (char * c = this) {
@@ -1897,9 +2620,26 @@ namespace System
                        }
                }
 
+               internal unsafe int GetCaseInsensitiveHashCode ()
+               {
+                       fixed (char * c = this) {
+                               char * cc = c;
+                               char * end = cc + length - 1;
+                               int h = 0;
+                               for (;cc < end; cc += 2) {
+                                       h = (h << 5) - h + Char.ToUpperInvariant (*cc);
+                                       h = (h << 5) - h + Char.ToUpperInvariant (cc [1]);
+                               }
+                               ++end;
+                               if (cc < end)
+                                       h = (h << 5) - h + Char.ToUpperInvariant (*cc);
+                               return h;
+                       }
+               }
+
                // 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)
@@ -1912,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
                        }
 
@@ -1963,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)
@@ -1977,6 +2717,99 @@ namespace System
                        return enc.GetString (bytes);
                }
 
+               unsafe string CreateString (char *value)
+               {
+                       if (value == null)
+                               return string.Empty;
+                       char *p = value;
+                       int i = 0;
+                       while (*p != 0) {
+                               ++i;
+                               ++p;
+                       }
+                       string result = InternalAllocateStr (i);
+
+                       if (i != 0) {
+                               fixed (char *dest = result) {
+                                       CharCopy (dest, value, i);
+                               }
+                       }
+                       return result;
+               }
+
+               unsafe string CreateString (char *value, int startIndex, int length)
+               {
+                       if (length == 0)
+                               return string.Empty;
+                       if (value == null)
+                               throw new ArgumentNullException ("value");
+                       if (startIndex < 0)
+                               throw new ArgumentOutOfRangeException ("startIndex");
+                       if (length < 0)
+                               throw new ArgumentOutOfRangeException ("length");
+
+                       string result = InternalAllocateStr (length);
+
+                       fixed (char *dest = result) {
+                               CharCopy (dest, value + startIndex, length);
+                       }
+                       return result;
+               }
+
+               unsafe string CreateString (char [] val, int startIndex, int length)
+               {
+                       if (val == null)
+                               throw new ArgumentNullException ("value");
+                       if (startIndex < 0)
+                               throw new ArgumentOutOfRangeException ("startIndex", "Cannot be negative.");
+                       if (length < 0)
+                               throw new ArgumentOutOfRangeException ("length", "Cannot be negative.");
+                       if (startIndex > val.Length - length)
+                               throw new ArgumentOutOfRangeException ("startIndex", "Cannot be negative, and should be less than length of string.");
+                       if (length == 0)
+                               return string.Empty;
+
+                       string result = InternalAllocateStr (length);
+
+                       fixed (char *dest = result, src = val) {
+                               CharCopy (dest, src + startIndex, length);
+                       }
+                       return result;
+               }
+
+               unsafe string CreateString (char [] val)
+               {
+                       if (val == null)
+                               return string.Empty;
+                       if (val.Length == 0)
+                               return string.Empty;
+                       string result = InternalAllocateStr (val.Length);
+
+                       fixed (char *dest = result, src = val) {
+                               CharCopy (dest, src, val.Length);
+                       }
+                       return result;
+               }
+
+               unsafe string CreateString (char c, int count)
+               {
+                       if (count < 0)
+                               throw new ArgumentOutOfRangeException ("count");
+                       if (count == 0)
+                               return string.Empty;
+                       string result = InternalAllocateStr (count);
+                       fixed (char *dest = result) {
+                               char *p = dest;
+                               char *end = p + count;
+                               while (p < end) {
+                                       *p = c;
+                                       p++;
+                               }
+                       }
+                       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)
                {
@@ -2133,6 +2966,55 @@ namespace System
                        memcpy4 (dest, src, size);
                }
 
+               internal static unsafe void CharCopy (char *dest, char *src, int count) {
+                       // Same rules as for memcpy, but with the premise that 
+                       // chars can only be aligned to even addresses if their
+                       // enclosing types are correctly aligned
+                       if ((((int)(byte*)dest | (int)(byte*)src) & 3) != 0) {
+                               if (((int)(byte*)dest & 2) != 0 && ((int)(byte*)src & 2) != 0 && count > 0) {
+                                       ((short*)dest) [0] = ((short*)src) [0];
+                                       dest++;
+                                       src++;
+                                       count--;
+                               }
+                               if ((((int)(byte*)dest | (int)(byte*)src) & 2) != 0) {
+                                       memcpy2 ((byte*)dest, (byte*)src, count * 2);
+                                       return;
+                               }
+                       }
+                       memcpy4 ((byte*)dest, (byte*)src, count * 2);
+               }
+
+               internal static unsafe void CharCopyReverse (char *dest, char *src, int count)
+               {
+                       dest += count;
+                       src += count;
+                       for (int i = count; i > 0; i--) {
+                               dest--;
+                               src--;
+                               *dest = *src;
+                       }       
+               }
+
+               internal static unsafe void CharCopy (String target, int targetIndex, String source, int sourceIndex, int count)
+               {
+                       fixed (char* dest = target, src = source)
+                               CharCopy (dest + targetIndex, src + sourceIndex, count);
+               }
+
+               internal static unsafe void CharCopy (String target, int targetIndex, Char[] source, int sourceIndex, int count)
+               {
+                       fixed (char* dest = target, src = source)
+                               CharCopy (dest + targetIndex, src + sourceIndex, count);
+               }
+
+               // Use this method if you cannot block copy from left to right (e.g. because you are coping within the same string)
+               internal static unsafe void CharCopyReverse (String target, int targetIndex, String source, int sourceIndex, int count)
+               {
+                       fixed (char* dest = target, src = source)
+                               CharCopyReverse (dest + targetIndex, src + sourceIndex, count);
+               }
+
                [CLSCompliant (false), MethodImplAttribute (MethodImplOptions.InternalCall)]
                unsafe public extern String (char *value);
 
@@ -2149,40 +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 String InternalReplace (char oldChar, char newChar);
-
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               private extern String InternalReplace (String oldValue, string newValue, CompareInfo comp);
+//             [MethodImplAttribute (MethodImplOptions.InternalCall)]
+//             private extern static string InternalJoin (string separator, string[] value, int sIndex, int count);
 
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               private extern void InternalCopyTo (int sIndex, char[] dest, int destIndex, int count);
+//             [MethodImplAttribute (MethodImplOptions.InternalCall)]
+//             private extern String InternalReplace (String oldValue, string newValue, CompareInfo comp);
 
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               private extern String[] InternalSplit (char[] separator, int count);
+//             [MethodImplAttribute (MethodImplOptions.InternalCall)]
+//             private extern void InternalCopyTo (int sIndex, char[] dest, int destIndex, int count);
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               private extern String InternalTrim (char[] chars, int typ);
+               private extern String[] InternalSplit (char[] separator, int count, int options);
 
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               private extern int InternalIndexOfAny (char [] arr, int sIndex, int count);
+//             [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);