2009-03-23 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mcs / class / corlib / System / String.cs
index 0111e96d3271edd7364782d031b9f89a92d38f58..7533f40da254d2e70bd6fbde1847b28fbe89d84f 100644 (file)
@@ -6,9 +6,11 @@
 //   Jeffrey Stedfast (fejj@ximian.com)
 //   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 Novell (http://www.novell.com)
+// Copyright (C) 2004-2005 Novell (http://www.novell.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
 // 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;
 using System.Text;
 using System.Collections;
 using System.Globalization;
 using System.Runtime.CompilerServices;
 
+#if NET_2_0
+using System.Collections.Generic;
+using System.Runtime.ConstrainedExecution;
+using System.Runtime.InteropServices;
+using Mono.Globalization.Unicode;
+#endif
+
 namespace System
 {
        [Serializable]
-       public sealed class String : IConvertible, ICloneable, IEnumerable,
 #if NET_2_0
-               IComparable, IComparable<String>
+       [ComVisible (true)]
+       public sealed class String : IConvertible, ICloneable, IEnumerable, IComparable, IComparable<String>, IEquatable <String>, IEnumerable<char>
 #else
-               IComparable
+       public sealed class String : IConvertible, ICloneable, IEnumerable, IComparable
 #endif
        {
                [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)
@@ -68,28 +80,42 @@ namespace System
                        if (len != b.length)
                                return false;
 
-                       if (len == 0)
-                               return true;
+                       fixed (char* s1 = &a.start_char, s2 = &b.start_char) {
+                               char* s1_ptr = s1;
+                               char* s2_ptr = s2;
 
-                       fixed (char * s1 = &a.start_char, s2 = &b.start_char) {
-                               // it must be one char, because 0 len is done above
-                               if (len < 2)
-                                       return *s1 == *s2;
+                               while (len >= 8) {
+                                       if (((int*)s1_ptr)[0] != ((int*)s2_ptr)[0] ||
+                                               ((int*)s1_ptr)[1] != ((int*)s2_ptr)[1] ||
+                                               ((int*)s1_ptr)[2] != ((int*)s2_ptr)[2] ||
+                                               ((int*)s1_ptr)[3] != ((int*)s2_ptr)[3])
+                                               return false;
 
-                               // check by twos
-                               int * sint1 = (int *) s1, sint2 = (int *) s2;
-                               int n2 = len >> 1;
-                               do {
-                                       if (*sint1++ != *sint2++)
+                                       s1_ptr += 8;
+                                       s2_ptr += 8;
+                                       len -= 8;
+                               }
+
+                               if (len >= 4) {
+                                       if (((int*)s1_ptr)[0] != ((int*)s2_ptr)[0] ||
+                                               ((int*)s1_ptr)[1] != ((int*)s2_ptr)[1])
+                                               return false;
+
+                                       s1_ptr += 4;
+                                       s2_ptr += 4;
+                                       len -= 4;
+                               }
+
+                               if (len > 1) {
+                                       if (((int*)s1_ptr)[0] != ((int*)s2_ptr)[0])
                                                return false;
-                               } while (--n2 != 0);
 
-                               // nothing left
-                               if ((len & 1) == 0)
-                                       return true;
+                                       s1_ptr += 2;
+                                       s2_ptr += 2;
+                                       len -= 2;
+                               }
 
-                               // check the last one
-                               return *(char *) sint1 == *(char *) sint2;
+                               return len == 0 || *s1_ptr == *s2_ptr;
                        }
                }
 
@@ -103,20 +129,30 @@ namespace System
                        return !Equals (a, b);
                }
 
+#if NET_2_0
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
+#endif
                public override bool Equals (Object obj)
                {
                        return Equals (this, obj as String);
                }
 
+#if NET_2_0
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
+#endif
                public bool Equals (String value)
                {
                        return Equals (this, value);
                }
 
                [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 ()
@@ -129,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;
                }
 
@@ -187,84 +224,296 @@ 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);
                }
 
-               public unsafe String Substring (int startIndex)
+#if NET_2_0
+               [ComVisible (false)]
+               [MonoDocumentationNote ("code should be moved to managed")]
+               public String[] Split (char[] separator, int count, StringSplitOptions options)
                {
-                       if (startIndex < 0 || startIndex > this.length)
-                               throw new ArgumentOutOfRangeException ("startIndex");
+                       if (separator == null || separator.Length == 0)
+                               return Split (WhiteChars, count, options);
+
+                       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 + ".");
+
+                       if (count == 0)
+                               return new string [0];
+
+                       return InternalSplit (separator, count, (int)options);
+               }
+
+               [ComVisible (false)]
+               public String[] Split (string[] separator, int count, StringSplitOptions options)
+               {
+                       if (separator == null || separator.Length == 0)
+                               return Split (WhiteChars, count, options);
+
+                       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 + ".");
+
+                       bool removeEmpty = (options & StringSplitOptions.RemoveEmptyEntries) == StringSplitOptions.RemoveEmptyEntries;
 
-                       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);
+                       if (count == 0 || (this == String.Empty && removeEmpty))
+                               return new String [0];
+
+                       ArrayList arr = new ArrayList ();
+
+                       int pos = 0;
+                       int matchCount = 0;
+                       while (pos < this.Length) {
+                               int matchIndex = -1;
+                               int matchPos = Int32.MaxValue;
+
+                               // Find the first position where any of the separators matches
+                               for (int i = 0; i < separator.Length; ++i) {
+                                       string sep = separator [i];
+                                       if (sep == null || sep == String.Empty)
+                                               continue;
+
+                                       int match = IndexOf (sep, pos);
+                                       if (match > -1 && match < matchPos) {
+                                               matchIndex = i;
+                                               matchPos = match;
+                                       }
                                }
+
+                               if (matchIndex == -1)
+                                       break;
+
+                               if (!(matchPos == pos && removeEmpty))
+                                       arr.Add (this.Substring (pos, matchPos - pos));
+
+                               pos = matchPos + separator [matchIndex].Length;
+
+                               matchCount ++;
+
+                               if (matchCount == count - 1)
+                                       break;
                        }
-                       return tmp;
+
+                       if (matchCount == 0)
+                               return new String [] { this };
+                       else {
+                               if (removeEmpty && pos == this.Length) {
+                                       String[] res = new String [arr.Count];
+                                       arr.CopyTo (0, res, 0, arr.Count);
+
+                                       return res;
+                               }
+                               else {
+                                       String[] res = new String [arr.Count + 1];
+                                       arr.CopyTo (0, res, 0, arr.Count);
+                                       res [arr.Count] = this.Substring (pos);
+
+                                       return res;
+                               }
+                       }
+               }
+
+               [ComVisible (false)]
+               public String[] Split (char[] separator, StringSplitOptions options)
+               {
+                       return Split (separator, Int32.MaxValue, options);
+               }
+
+               [ComVisible (false)]
+               public String[] Split (String[] separator, StringSplitOptions options)
+               {
+                       return Split (separator, Int32.MaxValue, options);
+               }
+#endif
+
+               public String Substring (int startIndex)
+               {
+#if NET_2_0
+                       if (startIndex == 0)
+                               return this;
+                       if (startIndex < 0 || startIndex > this.length)
+                               throw new ArgumentOutOfRangeException ("startIndex");
+#else
+                       if (startIndex < 0)
+                               throw new ArgumentOutOfRangeException ("startIndex", "Cannot be negative.");
+
+                       if (startIndex > this.length)
+                               throw new ArgumentOutOfRangeException ("length", "Cannot exceed length of string.");
+#endif
+
+                       return SubstringUnchecked (startIndex, this.length - startIndex);
                }
 
-               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
+                       (char) 0x85, (char) 0x1680, (char) 0x2028, (char) 0x2029,
+#endif
                        (char) 0x20, (char) 0xA0, (char) 0x2000, (char) 0x2001, (char) 0x2002, (char) 0x2003, (char) 0x2004,
                        (char) 0x2005, (char) 0x2006, (char) 0x2007, (char) 0x2008, (char) 0x2009, (char) 0x200A, (char) 0x200B,
                        (char) 0x3000, (char) 0xFEFF };
 
+               public String Trim ()
+               {
+                       if (length == 0) 
+                               return String.Empty;
+                       int start = FindNotWhiteSpace (0, length, 1);
+
+                       if (start == length)
+                               return String.Empty;
+
+                       int end = FindNotWhiteSpace (length - 1, start, -1);
+
+                       int newLength = end - start + 1;
+                       if (newLength == length)
+                               return this;
+
+                       return SubstringUnchecked (start, newLength);
+               }
+
                public String Trim (params char[] trimChars)
                {
                        if (trimChars == null || trimChars.Length == 0)
-                               trimChars = WhiteChars;
+                               return Trim ();
+
+                       if (length == 0) 
+                               return String.Empty;
+                       int start = FindNotInTable (0, length, 1, trimChars);
+
+                       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 InternalTrim (trimChars, 0);
+                       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);
+
+                       if (start == 0)
+                               return this;
 
-                       return InternalTrim (trimChars, 1);
+                       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)
@@ -272,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)
@@ -332,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;
                        
@@ -348,8 +579,87 @@ 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
+               public static int Compare (string strA, string strB, StringComparison comparisonType)
+               {
+                       switch (comparisonType) {
+                       case StringComparison.CurrentCulture:
+                               return Compare (strA, strB, false, CultureInfo.CurrentCulture);
+                       case StringComparison.CurrentCultureIgnoreCase:
+                               return Compare (strA, strB, true, CultureInfo.CurrentCulture);
+                       case StringComparison.InvariantCulture:
+                               return Compare (strA, strB, false, CultureInfo.InvariantCulture);
+                       case StringComparison.InvariantCultureIgnoreCase:
+                               return Compare (strA, strB, true, CultureInfo.InvariantCulture);
+                       case StringComparison.Ordinal:
+                               return CompareOrdinalUnchecked (strA, 0, Int32.MaxValue, strB, 0, Int32.MaxValue);
+                       case StringComparison.OrdinalIgnoreCase:
+                               return CompareOrdinalCaseInsensitiveUnchecked (strA, 0, Int32.MaxValue, strB, 0, Int32.MaxValue);
+                       default:
+                               string msg = Locale.GetText ("Invalid value '{0}' for StringComparison", comparisonType);
+                               throw new ArgumentException (msg, "comparisonType");
+                       }
+               }
+
+               public static int Compare (string strA, int indexA, string strB, int indexB, int length, StringComparison comparisonType)
+               {
+                       switch (comparisonType) {
+                       case StringComparison.CurrentCulture:
+                               return Compare (strA, indexA, strB, indexB, length, false, CultureInfo.CurrentCulture);
+                       case StringComparison.CurrentCultureIgnoreCase:
+                               return Compare (strA, indexA, strB, indexB, length, true, CultureInfo.CurrentCulture);
+                       case StringComparison.InvariantCulture:
+                               return Compare (strA, indexA, strB, indexB, length, false, CultureInfo.InvariantCulture);
+                       case StringComparison.InvariantCultureIgnoreCase:
+                               return Compare (strA, indexA, strB, indexB, length, true, CultureInfo.InvariantCulture);
+                       case StringComparison.Ordinal:
+                               return CompareOrdinal (strA, indexA, strB, indexB, length);
+                       case StringComparison.OrdinalIgnoreCase:
+                               return CompareOrdinalCaseInsensitive (strA, indexA, strB, indexB, length);
+                       default:
+                               string msg = Locale.GetText ("Invalid value '{0}' for StringComparison", comparisonType);
+                               throw new ArgumentException (msg, "comparisonType");
+                       }
+               }
+
+               public static bool Equals (string a, string b, StringComparison comparisonType)
+               {
+                       return String.Compare (a, b, comparisonType) == 0;
+               }
+
+               public bool Equals (string value, StringComparison 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)
                {
@@ -359,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)
@@ -367,60 +677,93 @@ 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 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 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);
+
+                       if (lengthA == lengthB && Object.ReferenceEquals (strA, strB))
+                               return 0;
 
-                       /* Invariant, because that is cheaper to
-                        * instantiate (and chances are it already has
-                        * been.)
-                        */
-                       return CultureInfo.InvariantCulture.CompareInfo.Compare (strA, strB, 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;
+                       }
                }
 
-               public static int CompareOrdinal (String strA, int indexA, String strB, int indexB, int length)
+               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, CompareOptions.Ordinal);
                }
 
                public bool EndsWith (String value)
@@ -428,101 +771,438 @@ namespace System
                        if (value == null)
                                throw new ArgumentNullException ("value");
 
-                       if (value.Length == 0)
-                               return true;
+                       return CultureInfo.CurrentCulture.CompareInfo.IsSuffix (this, value, CompareOptions.None);
+               }
 
-                       if (value.length > this.length)
-                               return false;
+#if NET_2_0
+               public
+#else
+               internal
+#endif
+               bool EndsWith (String value, bool ignoreCase, CultureInfo culture)
+               {
+                       if (value == null)
+                               throw new ArgumentNullException ("value");
+                       if (culture == null)
+                               culture = CultureInfo.CurrentCulture;
 
-                       return (0 == Compare (this, length - value.length, value, 0, value.length));
+                       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");
-                       if (startIndex < 0 || startIndex >= this.length)
-                               throw new ArgumentOutOfRangeException ("sourceIndex");
+                               throw new ArgumentNullException ();
+                       if (startIndex < 0 || startIndex > this.length)
+                               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);
                }
 
-               public int IndexOf (char value)
+               private unsafe int IndexOfAnyUnchecked (char[] anyOf, int startIndex, int count)
                {
-                       return IndexOf (value, 0, this.length);
+                       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;
                }
 
-               public int IndexOf (String value)
+
+#if NET_2_0
+               public int IndexOf (string value, StringComparison comparisonType)
                {
-                       return IndexOf (value, 0, this.length);
+                       return IndexOf (value, 0, this.Length, comparisonType);
                }
 
-               public int IndexOf (char value, int startIndex)
+               public int IndexOf (string value, int startIndex, StringComparison comparisonType)
                {
-                       return IndexOf (value, startIndex, this.length - startIndex);
+                       return IndexOf (value, startIndex, this.Length - startIndex, comparisonType);
                }
 
-               public int IndexOf (String value, int startIndex)
+               public int IndexOf (string value, int startIndex, int count, StringComparison comparisonType)
                {
-                       return IndexOf (value, startIndex, this.length - startIndex);
+                       switch (comparisonType) {
+                       case StringComparison.CurrentCulture:
+                               return CultureInfo.CurrentCulture.CompareInfo.IndexOf (this, value, startIndex, count, CompareOptions.None);
+                       case StringComparison.CurrentCultureIgnoreCase:
+                               return CultureInfo.CurrentCulture.CompareInfo.IndexOf (this, value, startIndex, count, CompareOptions.IgnoreCase);
+                       case StringComparison.InvariantCulture:
+                               return CultureInfo.InvariantCulture.CompareInfo.IndexOf (this, value, startIndex, count, CompareOptions.None);
+                       case StringComparison.InvariantCultureIgnoreCase:
+                               return CultureInfo.InvariantCulture.CompareInfo.IndexOf (this, value, startIndex, count, CompareOptions.IgnoreCase);
+                       case StringComparison.Ordinal:
+                               return IndexOfOrdinal (value, startIndex, count, CompareOptions.Ordinal);
+                       case StringComparison.OrdinalIgnoreCase:
+                               return IndexOfOrdinal (value, startIndex, count, CompareOptions.OrdinalIgnoreCase);
+                       default:
+                               string msg = Locale.GetText ("Invalid value '{0}' for StringComparison", comparisonType);
+                               throw new ArgumentException (msg, "comparisonType");
+                       }
                }
+#endif
 
-               /* This method is culture-insensitive */
-               public int IndexOf (char value, int startIndex, int count)
+               internal int IndexOfOrdinal (string value, int startIndex, int count, CompareOptions options)
+               {
+                       if (value == null)
+                               throw new ArgumentNullException ("value");
+                       if (startIndex < 0)
+                               throw new ArgumentOutOfRangeException ("startIndex");
+                       if (count < 0 || (this.length - startIndex) < count)
+                               throw new ArgumentOutOfRangeException ("count");
+
+                       if (options == CompareOptions.Ordinal)
+                               return IndexOfOrdinalUnchecked (value, startIndex, count);
+                       return IndexOfOrdinalIgnoreCaseUnchecked (value, startIndex, count);
+               }
+
+               internal unsafe int IndexOfOrdinalUnchecked (string value, int startIndex, int count)
+               {
+                       int valueLen = value.Length;
+                       if (count < valueLen)
+                               return -1;
+
+                       if (valueLen <= 1) {
+                               if (valueLen == 1)
+                                       return IndexOfUnchecked (value[0], startIndex, count);
+                               return 0;
+                       }
+
+                       fixed (char* thisptr = this, valueptr = value) {
+                               char* ap = thisptr + startIndex;
+                               char* thisEnd = ap + count - valueLen + 1;
+                               while (ap != thisEnd) {
+                                       if (*ap == *valueptr) {
+                                               for (int i = 1; i < valueLen; i++) {
+                                                       if (ap[i] != valueptr[i])
+                                                               goto NextVal;
+                                               }
+                                               return (int)(ap - thisptr);
+                                       }
+                                       NextVal:
+                                       ap++;
+                               }
+                       }
+                       return -1;
+               }
+
+               internal unsafe int IndexOfOrdinalIgnoreCaseUnchecked (string value, int startIndex, int count)
+               {
+                       int valueLen = value.Length;
+                       if (count < valueLen)
+                               return -1;
+
+                       if (valueLen == 0)
+                               return 0;
+
+                       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;
+               }
+
+#if NET_2_0
+
+               public int LastIndexOf (string value, StringComparison comparisonType)
+               {
+                       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:
+                               return CultureInfo.CurrentCulture.CompareInfo.LastIndexOf (this, value, startIndex, count, CompareOptions.IgnoreCase);
+                       case StringComparison.InvariantCulture:
+                               return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf (this, value, startIndex, count, CompareOptions.None);
+                       case StringComparison.InvariantCultureIgnoreCase:
+                               return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf (this, value, startIndex, count, CompareOptions.IgnoreCase);
+                       case StringComparison.Ordinal:
+                               return LastIndexOfOrdinal (value, startIndex, count, CompareOptions.Ordinal);
+                       case StringComparison.OrdinalIgnoreCase:
+                               return LastIndexOfOrdinal (value, startIndex, count, CompareOptions.OrdinalIgnoreCase);
+                       default:
+                               string msg = Locale.GetText ("Invalid value '{0}' for StringComparison", comparisonType);
+                               throw new ArgumentException (msg, "comparisonType");
+                       }
+               }
+#endif
+
+               internal int LastIndexOfOrdinal (string value, int startIndex, int count, CompareOptions options)
+               {
+                       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);
+               }
+
+               internal unsafe int LastIndexOfOrdinalUnchecked (string value, int startIndex, int count)
+               {
+                       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;
+               }
+
+               internal unsafe int LastIndexOfOrdinalIgnoreCaseUnchecked (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 - 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;
+               }
+
+               // Following methods are culture-insensitive
+               public int IndexOf (char value)
+               {
+                       if (this.length == 0)
+                               return -1;
+
+                       return IndexOfUnchecked (value, 0, this.length);
+               }
+
+               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;
@@ -536,34 +1216,35 @@ 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 ();
+                       if (startIndex < 0 || startIndex >= this.length)
+                               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))
+                       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");
@@ -573,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)
@@ -598,17 +1295,6 @@ namespace System
                        return LastIndexOf (value, startIndex, startIndex + 1);
                }
 
-               public int LastIndexOf (String value, int startIndex)
-               {
-                       if (value == null)
-                               throw new ArgumentNullException ("value");
-                       int max = startIndex;
-                       if (max < this.Length)
-                               max++;
-                       return LastIndexOf (value, startIndex, max);
-               }
-
-               /* This method is culture-insensitive */
                public int LastIndexOf (char value, int startIndex, int count)
                {
                        if (startIndex == 0 && this.length == 0)
@@ -622,18 +1308,91 @@ namespace System
                        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 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;
                }
 
-               /* But this one is culture-sensitive */
+               // Following methods are culture-sensitive
+               public int LastIndexOf (String value)
+               {
+                       if (this.length == 0)
+                               // This overload does additional checking
+                               return LastIndexOf (value, 0, 0);
+                       else
+                               return LastIndexOf (value, this.length - 1, this.length);
+               }
+
+               public int LastIndexOf (String value, int startIndex)
+               {
+                       int max = startIndex;
+                       if (max < this.Length)
+                               max++;
+                       return LastIndexOf (value, startIndex, max);
+               }
+
                public int LastIndexOf (String value, int startIndex, int count)
                {
                        if (value == null)
+#if NET_2_0
                                throw new ArgumentNullException ("value");
+#else
+                               throw new ArgumentNullException ("string2");
+#endif
+
                        // -1 > startIndex > for string (0 > startIndex >= for char)
                        if ((startIndex < -1) || (startIndex > this.Length))
                                throw new ArgumentOutOfRangeException ("startIndex", "< 0 || > this.Length");
@@ -643,7 +1402,7 @@ namespace System
                                throw new ArgumentOutOfRangeException ("startIndex - count + 1 < 0");
 
                        if (value.Length == 0)
-                               return 0;
+                               return startIndex;
 
                        if (startIndex == 0 && this.length == 0)
                                return -1;
@@ -652,9 +1411,6 @@ namespace System
                        if (this.length == 0 && value.length > 0)
                                return -1;
 
-                       if (value.length > startIndex)
-                               return -1;
-
                        if (count == 0)
                                return -1;
 
@@ -674,6 +1430,44 @@ namespace System
                        return (value == null) || (value.Length == 0);
                }
 
+               public string Normalize ()
+               {
+                       return Normalization.Normalize (this, 0);
+               }
+
+               public string Normalize (NormalizationForm normalizationForm)
+               {
+                       switch (normalizationForm) {
+                       default:
+                               return Normalization.Normalize (this, 0);
+                       case NormalizationForm.FormD:
+                               return Normalization.Normalize (this, 1);
+                       case NormalizationForm.FormKC:
+                               return Normalization.Normalize (this, 2);
+                       case NormalizationForm.FormKD:
+                               return Normalization.Normalize (this, 3);
+                       }
+               }
+
+               public bool IsNormalized ()
+               {
+                       return Normalization.IsNormalized (this, 0);
+               }
+
+               public bool IsNormalized (NormalizationForm normalizationForm)
+               {
+                       switch (normalizationForm) {
+                       default:
+                               return Normalization.IsNormalized (this, 0);
+                       case NormalizationForm.FormD:
+                               return Normalization.IsNormalized (this, 1);
+                       case NormalizationForm.FormKC:
+                               return Normalization.IsNormalized (this, 2);
+                       case NormalizationForm.FormKD:
+                               return Normalization.IsNormalized (this, 3);
+                       }
+               }
+
                public string Remove (int startIndex)
                {
                        if (startIndex < 0)
@@ -690,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)
@@ -706,73 +1512,240 @@ namespace System
                        return PadRight (totalWidth, ' ');
                }
 
-               public String PadRight (int totalWidth, char paddingChar)
+               public unsafe String PadRight (int totalWidth, char paddingChar)
                {
+                       //LAMESPEC: MSDN Doc says this is reversed for RtL languages, but this seems to be untrue
+
                        if (totalWidth < 0)
                                throw new ArgumentOutOfRangeException ("totalWidth", "< 0");
 
                        if (totalWidth < this.length)
-                               return String.Copy (this);
+                               return this;
+
+                       String tmp = InternalAllocateStr (totalWidth);
 
-                       return InternalPad (totalWidth, paddingChar, true);
+                       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)
                {
                        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);
+                       case StringComparison.CurrentCultureIgnoreCase:
+                               return CultureInfo.CurrentCulture.CompareInfo.IsPrefix (this, value, CompareOptions.IgnoreCase);
+                       case StringComparison.InvariantCulture:
+                               return CultureInfo.InvariantCulture.CompareInfo.IsPrefix (this, value, CompareOptions.None);
+                       case StringComparison.InvariantCultureIgnoreCase:
+                               return CultureInfo.InvariantCulture.CompareInfo.IsPrefix (this, value, CompareOptions.IgnoreCase);
+                       case StringComparison.Ordinal:
+                               return CultureInfo.CurrentCulture.CompareInfo.IsPrefix (this, value, CompareOptions.Ordinal);
+                       case StringComparison.OrdinalIgnoreCase:
+                               return CultureInfo.CurrentCulture.CompareInfo.IsPrefix (this, value, CompareOptions.OrdinalIgnoreCase);
+                       default:
+                               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);
+                       case StringComparison.CurrentCultureIgnoreCase:
+                               return CultureInfo.CurrentCulture.CompareInfo.IsSuffix (this, value, CompareOptions.IgnoreCase);
+                       case StringComparison.InvariantCulture:
+                               return CultureInfo.InvariantCulture.CompareInfo.IsSuffix (this, value, CompareOptions.None);
+                       case StringComparison.InvariantCultureIgnoreCase:
+                               return CultureInfo.InvariantCulture.CompareInfo.IsSuffix (this, value, CompareOptions.IgnoreCase);
+                       case StringComparison.Ordinal:
+                               return CultureInfo.CurrentCulture.CompareInfo.IsSuffix (this, value, CompareOptions.Ordinal);
+                       case StringComparison.OrdinalIgnoreCase:
+                               return CultureInfo.CurrentCulture.CompareInfo.IsSuffix (this, value, CompareOptions.OrdinalIgnoreCase);
+                       default:
+                               string msg = Locale.GetText ("Invalid value '{0}' for StringComparison", comparisonType);
+                               throw new ArgumentException (msg, "comparisonType");
+                       }
+               }
+#endif
+
+#if NET_2_0
+               public
+#else
+               internal
+#endif
+               bool StartsWith (String value, bool ignoreCase, CultureInfo culture)
+               {
+                       if (culture == null)
+                               culture = CultureInfo.CurrentCulture;
                        
-                       if (value.Length == 0)
-                               return true;
+                       return culture.CompareInfo.IsPrefix (this, value, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
+               }
 
-                       if (this.length < value.length)
-                               return false;
+               // Following method is culture-insensitive
+               public unsafe String Replace (char oldChar, char 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;
+               }
+
+               // 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");
+
+                       if (oldValue.Length == 0)
+                               throw new ArgumentException ("oldValue is the empty string.");
+
+                       if (this.Length == 0)
+                               return this;
+                       
+                       if (newValue == null)
+                               newValue = String.Empty;
 
-                       return (0 == Compare (this, 0, value, 0 , value.length));
+                       return ReplaceUnchecked (oldValue, newValue);
                }
 
-               /* This method is culture insensitive */
-               public String Replace (char oldChar, char newChar)
+               private unsafe String ReplaceUnchecked (String oldValue, String newValue)
                {
-                       return InternalReplace (oldChar, newChar);
+                       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;
+                       }
                }
 
-               /* This method is culture sensitive */
-               public String Replace (String oldValue, String newValue)
+               private String ReplaceFallback (String oldValue, String newValue, int testedCount)
                {
-                       if (oldValue == null)
-                               throw new ArgumentNullException ("oldValue");
-
-                       if (oldValue.Length == 0)
-                               throw new ArgumentException ("oldValue is the empty string.");
-
-                       if (this.Length == 0)
-                               return this;
-                       
-                       if (newValue == null)
-                               newValue = String.Empty;
+                       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 ();
 
-                       return InternalReplace (oldValue, newValue, CultureInfo.CurrentCulture.CompareInfo);
                }
 
                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;
                }
@@ -787,13 +1760,17 @@ 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);
                }
 
+#if NET_2_0
+               public unsafe String ToLowerInvariant ()
+#else
                internal unsafe String ToLowerInvariant ()
+#endif
                {
                        string tmp = InternalAllocateStr (length);
                        fixed (char* source = &start_char, dest = tmp) {
@@ -820,13 +1797,17 @@ 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);
                }
 
+#if NET_2_0
+               public unsafe String ToUpperInvariant ()
+#else
                internal unsafe String ToUpperInvariant ()
+#endif
                {
                        string tmp = InternalAllocateStr (length);
                        fixed (char* source = &start_char, dest = tmp) {
@@ -853,11 +1834,6 @@ namespace System
                        return this;
                }
 
-               public String Trim ()
-               {
-                       return Trim (null);
-               }
-
                public static String Format (String format, Object arg0)
                {
                        return Format (null, format, new Object[] {arg0});
@@ -880,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;
@@ -920,8 +1915,14 @@ namespace System
                                        object arg = args[n];
 
                                        string str;
+                                       ICustomFormatter formatter = null;
+                                       if (provider != null)
+                                               formatter = provider.GetFormat (typeof (ICustomFormatter))
+                                                       as ICustomFormatter;
                                        if (arg == null)
-                                               str = "";
+                                               str = String.Empty;
+                                       else if (formatter != null)
+                                               str = formatter.Format (arg_format, arg, provider);
                                        else if (arg is IFormattable)
                                                str = ((IFormattable)arg).ToString (arg_format, provider);
                                        else
@@ -958,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)
@@ -970,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)
@@ -1002,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 ();
@@ -1075,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) {
-                               if (s2 == null)
+                       if (str0 == null || str0.Length == 0) {
+                               if (str1 == null || str1.Length == 0)
                                        return String.Empty;
-                               return s2;
+                               return str1;
                        }
 
-                       if (s2 == null)
-                               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){
-                               if (s2 == null){
-                                       if (s3 == null)
+                       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)
-                                               return s2;
+                                       if (str2 == null || str2.Length == 0)
+                                               return str1;
                                }
-                               s1 = String.Empty;
+                               str0 = String.Empty;
                        } else {
-                               if (s2 == null){
-                                       if (s3 == null)
-                                               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 = 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);
                                }
                        }
 
@@ -1193,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)
@@ -1221,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)
@@ -1230,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;
@@ -1240,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)
@@ -1270,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)
@@ -1282,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)
@@ -1338,46 +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);
                }
 
-               string IConvertible.ToString (IFormatProvider format)
-               {
-                       return this;
-               }
-
-               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);
                }
-
-               TypeCode IConvertible.GetTypeCode ()
-               {
-                       return TypeCode.String;
-               }
+#if ONLY_1_1
+#pragma warning restore 3019
+#endif
 
                public int Length {
                        get {
@@ -1390,6 +2477,13 @@ namespace System
                        return new CharEnumerator (this);
                }
 
+#if NET_2_0
+               IEnumerator<char> IEnumerable<char>.GetEnumerator ()
+               {
+                       return new CharEnumerator (this);
+               }
+#endif
+
                IEnumerator IEnumerable.GetEnumerator ()
                {
                        return new CharEnumerator (this);
@@ -1414,9 +2508,10 @@ namespace System
 
                                if (str[ptr] == ',') {
                                        // White space between ',' and number or sign.
-                                       int start = ++ptr;
+                                       ++ptr;
                                        while (Char.IsWhiteSpace (str [ptr]))
                                                ++ptr;
+                                       int start = ptr;
 
                                        format = str.Substring (start, ptr - start);
 
@@ -1431,7 +2526,7 @@ namespace System
                                else {
                                        width = 0;
                                        left_align = false;
-                                       format = "";
+                                       format = String.Empty;
                                }
 
                                // F = argument format (string)
@@ -1490,14 +2585,24 @@ namespace System
                        if (newLength > length)
                                throw new ArgumentOutOfRangeException ("newLength", "newLength as to be <= length");
 
-                       length = newLength;
-
                        // zero terminate, we can pass string objects directly via pinvoke
+                       // we also zero the rest of the string, since the new GC needs to be
+                       // able to handle the changing size (it will skip the 0 bytes).
                        fixed (char * pStr = &start_char) {
-                               pStr [length] = '\0';
+                               char *p = pStr + newLength;
+                               char *end = pStr + length;
+                               while (p < end) {
+                                       p [0] = '\0';
+                                       p++;
+                               }
                        }
+                       length = newLength;
                }
 
+#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) {
@@ -1515,6 +2620,196 @@ 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)
+                               return String.Empty;
+
+                       byte* bytes = (byte*) value;
+                       int length = 0;
+
+                       try {
+                               while (bytes++ [0] != 0)
+                                       length++;
+                       } catch (NullReferenceException) {
+                               throw new ArgumentOutOfRangeException ("ptr", "Value does not refer to a valid string.");
+#if NET_2_0
+                       } catch (AccessViolationException) {
+                               throw new ArgumentOutOfRangeException ("ptr", "Value does not refer to a valid string.");
+#endif
+                       }
+
+                       return CreateString (value, 0, length, null);
+               }
+
+               private unsafe String CreateString (sbyte* value, int startIndex, int length)
+               {
+                       return CreateString (value, startIndex, length, null);
+               }
+
+               private unsafe String CreateString (sbyte* value, int startIndex, int length, Encoding enc)
+               {
+                       if (length < 0)
+                               throw new ArgumentOutOfRangeException ("length", "Non-negative number required.");
+                       if (startIndex < 0)
+                               throw new ArgumentOutOfRangeException ("startIndex", "Non-negative number required.");
+                       if (value + startIndex < value)
+                               throw new ArgumentOutOfRangeException ("startIndex", "Value, startIndex and length do not refer to a valid string.");
+
+                       bool isDefaultEncoding;
+
+                       if (isDefaultEncoding = (enc == null)) {
+#if NET_2_0
+                               if (value == null)
+                                       throw new ArgumentNullException ("value");
+                               if (length == 0)
+#else
+                               if (value == null || length == 0)
+#endif
+                                       return String.Empty;
+
+                               enc = Encoding.Default;
+                       }
+
+                       byte [] bytes = new byte [length];
+
+                       if (length != 0)
+                               fixed (byte* bytePtr = bytes)
+                                       try {
+                                               memcpy (bytePtr, (byte*) (value + startIndex), length);
+                                       } catch (NullReferenceException) {
+#if !NET_2_0
+                                               if (!isDefaultEncoding)
+                                                       throw;
+#endif
+
+                                               throw new ArgumentOutOfRangeException ("ptr", "Value, startIndex and length do not refer to a valid string.");
+#if NET_2_0
+                                       } catch (AccessViolationException) {
+                                               if (!isDefaultEncoding)
+                                                       throw;
+
+                                               throw new ArgumentOutOfRangeException ("value", "Value, startIndex and length do not refer to a valid string.");
+#endif
+                                       }
+
+                       // GetString () is called even when length == 0
+                       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)
                {
@@ -1562,7 +2857,7 @@ namespace System
                        }
                }
 
-               internal static unsafe void memcpy4 (byte *dest, byte *src, int size) {
+               static unsafe void memcpy4 (byte *dest, byte *src, int size) {
                        /*while (size >= 32) {
                                // using long is better than int and slower than double
                                // FIXME: enable this only on correct alignment or on platforms
@@ -1640,7 +2935,8 @@ namespace System
                        if (size > 0)
                                ((byte*)dest) [0] = ((byte*)src) [0];
                }
-               static unsafe void memcpy (byte *dest, byte *src, int size) {
+
+               internal static unsafe void memcpy (byte *dest, byte *src, int size) {
                        // FIXME: if pointers are not aligned, try to align them
                        // so a faster routine can be used. Handle the case where
                        // the pointers can't be reduced to have the same alignment
@@ -1670,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);
 
@@ -1686,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);