Make a copy of the old ZipLib
[mono.git] / mcs / class / corlib / System / String.cs
index 9f67c55c9d727399072e20ff2aefe743c533dc01..cf66fd4336c54bbf83609e49805bdd51e0a2b6bf 100644 (file)
@@ -8,19 +8,47 @@
 //   Sebastien Pouliot  <sebastien@ximian.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
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-using System;
 using System.Text;
 using System.Collections;
 using System.Globalization;
 using System.Runtime.CompilerServices;
 
+#if NET_2_0
+using System.Runtime.ConstrainedExecution;
+using System.Runtime.InteropServices;
+#endif
+
 namespace System
 {
        [Serializable]
-       public sealed class String : IConvertible, IComparable, ICloneable, IEnumerable
+#if NET_2_0
+       [ComVisible (true)]
+       public sealed class String : IConvertible, ICloneable, IEnumerable, IComparable, IComparable<String>, IEquatable <String>
+#else
+       public sealed class String : IConvertible, ICloneable, IEnumerable, IComparable
+#endif
        {
                [NonSerialized] private int length;
                [NonSerialized] private char start_char;
@@ -79,11 +107,17 @@ 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);
@@ -168,18 +202,128 @@ namespace System
                        return InternalSplit (separator, count);
                }
 
-               public String Substring (int startIndex)
+#if NET_2_0
+               [ComVisible (false)]
+               [MonoTODO]
+               public String[] Split (char[] 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 ("options must be one of the values in the StringSplitOptions enumeration", "options");
+
+                       bool removeEmpty = (options & StringSplitOptions.RemoveEmptyEntries) == StringSplitOptions.RemoveEmptyEntries;
+
+                       if (!removeEmpty)
+                               return Split (separator, count);
+                       else
+                               throw new NotImplementedException ();
+               }
+
+               [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 + ".", "options");
+
+                       bool removeEmpty = (options & StringSplitOptions.RemoveEmptyEntries) == StringSplitOptions.RemoveEmptyEntries;
+
+                       if (count == 0 || (this == String.Empty && removeEmpty))
+                               return new String [0];
+
+                       ArrayList arr = new ArrayList ();
+
+                       int pos = 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) {
+                                       pos = matchPos + separator [matchIndex].Length;
+                               }
+                               else {
+                                       arr.Add (this.Substring (pos, matchPos - pos));
+
+                                       pos = matchPos + separator [matchIndex].Length;
+
+                                       if (arr.Count == count - 1) {
+                                               break;
+                                       }
+                               }
+                       }
+
+                       if (arr.Count == 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 unsafe String Substring (int startIndex)
                {
                        if (startIndex < 0 || startIndex > this.length)
                                throw new ArgumentOutOfRangeException ("startIndex");
 
-                       string tmp = InternalAllocateStr (this.length - startIndex);
-                       InternalStrcpy (tmp, 0, this, startIndex, length - startIndex);
-
+                       int newlen = this.length - startIndex;
+                       string tmp = InternalAllocateStr (newlen);
+                       if (newlen != 0) {
+                               fixed (char *dest = tmp, src = this) {
+                                       memcpy ((byte*)dest, (byte*)(src + startIndex), newlen * 2);
+                               }
+                       }
                        return tmp;
                }
 
-               public String Substring (int startIndex, int length)
+               public unsafe String Substring (int startIndex, int length)
                {
                        if (length < 0)
                                throw new ArgumentOutOfRangeException ("length", "< 0");
@@ -193,16 +337,26 @@ namespace System
                                return String.Empty;
 
                        string tmp = InternalAllocateStr (length);
-                       InternalStrcpy (tmp, 0, this, startIndex, length);
+                       fixed (char *dest = tmp, src = this) {
+                               memcpy ((byte*)dest, (byte*)(src + startIndex), length * 2);
+                       }
 
                        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 ()
+               {
+                       return InternalTrim (WhiteChars, 0);
+               }
+
                public String Trim (params char[] trimChars)
                {
                        if (trimChars == null || trimChars.Length == 0)
@@ -395,16 +549,19 @@ namespace System
 
                public bool EndsWith (String value)
                {
-                       if (value == null)
-                               throw new ArgumentNullException ("value");
-
-                       if (value == String.Empty)
-                               return true;
-
-                       if (value.length > this.length)
-                               return false;
+                       return EndsWith (value, false, CultureInfo.CurrentCulture);
+               }
 
-                       return (0 == Compare (this, length - value.length, value, 0, value.length));
+#if NET_2_0
+               public
+#else
+               internal
+#endif
+               bool EndsWith (String value, bool ignoreCase, CultureInfo culture)
+               {
+                       return (culture.CompareInfo.IsSuffix (this, value,
+                               ignoreCase ? CompareOptions.IgnoreCase :
+                               CompareOptions.None));
                }
 
                public int IndexOfAny (char [] anyOf)
@@ -419,8 +576,8 @@ namespace System
                {
                        if (anyOf == null)
                                throw new ArgumentNullException ("anyOf");
-                       if (startIndex < 0 || startIndex >= this.length)
-                               throw new ArgumentOutOfRangeException ("sourceIndex");
+                       if (startIndex < 0 || startIndex > this.length)
+                               throw new ArgumentOutOfRangeException ("startIndex");
 
                        return InternalIndexOfAny (anyOf, startIndex, this.length - startIndex);
                }
@@ -519,7 +676,7 @@ namespace System
                        if (anyOf == null) 
                                throw new ArgumentNullException ("anyOf");
 
-                       if (startIndex < 0 || startIndex > this.length)
+                       if (startIndex < 0 || startIndex >= this.length)
                                throw new ArgumentOutOfRangeException ();
 
                        if (this.length == 0)
@@ -533,7 +690,7 @@ namespace System
                        if (anyOf == null) 
                                throw new ArgumentNullException ("anyOf");
 
-                       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");
@@ -612,7 +769,7 @@ namespace System
                        if (startIndex - count + 1 < 0)
                                throw new ArgumentOutOfRangeException ("startIndex - count + 1 < 0");
 
-                       if (value == String.Empty)
+                       if (value.Length == 0)
                                return 0;
 
                        if (startIndex == 0 && this.length == 0)
@@ -633,6 +790,28 @@ namespace System
                        return CultureInfo.CurrentCulture.CompareInfo.LastIndexOf (this, value, startIndex, count);
                }
 
+#if NET_2_0
+               public bool Contains (String value)
+               {
+                       return IndexOf (value) != -1;
+               }
+
+               public static bool IsNullOrEmpty (String value)
+               {
+                       return (value == null) || (value.Length == 0);
+               }
+
+               public string Remove (int startIndex)
+               {
+                       if (startIndex < 0)
+                               throw new ArgumentOutOfRangeException ("startIndex", "StartIndex can not be less than zero");
+                       if (startIndex >= this.length)
+                               throw new ArgumentOutOfRangeException ("startIndex", "StartIndex must be less than the length of the string");
+
+                       return Remove (startIndex, this.length - startIndex);
+               }
+#endif
+
                public String PadLeft (int totalWidth)
                {
                        return PadLeft (totalWidth, ' ');
@@ -667,16 +846,19 @@ namespace System
 
                public bool StartsWith (String value)
                {
-                       if (value == null)
-                               throw new ArgumentNullException ("value");
-                       
-                       if (value == String.Empty)
-                               return true;
-
-                       if (this.length < value.length)
-                               return false;
+                       return StartsWith (value, false, CultureInfo.CurrentCulture);
+               }
 
-                       return (0 == Compare (this, 0, value, 0 , value.length));
+#if NET_2_0
+               public
+#else
+               internal
+#endif
+               bool StartsWith (String value, bool ignoreCase, CultureInfo culture)
+               {
+                       return (culture.CompareInfo.IsPrefix (this, value,
+                               ignoreCase ? CompareOptions.IgnoreCase :
+                               CompareOptions.None));
                }
 
                /* This method is culture insensitive */
@@ -691,15 +873,11 @@ namespace System
                        if (oldValue == null)
                                throw new ArgumentNullException ("oldValue");
 
-                       if (oldValue == String.Empty)
+                       if (oldValue.Length == 0)
                                throw new ArgumentException ("oldValue is the empty string.");
 
-                       if (this == String.Empty)
+                       if (this.Length == 0)
                                return this;
-
-                       if (oldValue.Length == 0 || oldValue[0] == '\0') {
-                               return(this);
-                       }
                        
                        if (newValue == null)
                                newValue = String.Empty;
@@ -707,7 +885,7 @@ namespace System
                        return InternalReplace (oldValue, newValue, CultureInfo.CurrentCulture.CompareInfo);
                }
 
-               public String Remove (int startIndex, int count)
+               public unsafe String Remove (int startIndex, int count)
                {
                        if (startIndex < 0)
                                throw new ArgumentOutOfRangeException ("startIndex", "< 0");
@@ -717,13 +895,21 @@ namespace System
                        if (startIndex > this.length - count)
                                throw new ArgumentOutOfRangeException ("startIndex + count > this.length");
 
-                       return InternalRemove (startIndex, count);
+                       String tmp = InternalAllocateStr (this.length - count);
+
+                       fixed (char *dest = tmp, src = this) {
+                               char *dst = dest;
+                               memcpy ((byte*)dst, (byte*)src, startIndex * 2);
+                               int skip = startIndex + count;
+                               dst += startIndex;
+                               memcpy ((byte*)dst, (byte*)(src + skip), (length - skip) * 2);
+                       }
+                       return tmp;
                }
 
                public String ToLower ()
                {
-                       // CurrentCulture can never be invariant or null
-                       return InternalToLower (CultureInfo.CurrentCulture);
+                       return ToLower (CultureInfo.CurrentCulture);
                }
 
                public String ToLower (CultureInfo culture)
@@ -734,10 +920,14 @@ namespace System
                        if (culture.LCID == 0x007F) { // Invariant
                                return ToLowerInvariant ();
                        }
-                       return InternalToLower (culture);
+                       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) {
@@ -756,8 +946,7 @@ namespace System
 
                public String ToUpper ()
                {
-                       // CurrentCulture can never be invariant or null
-                       return InternalToUpper (CultureInfo.CurrentCulture);
+                       return ToUpper (CultureInfo.CurrentCulture);
                }
 
                public String ToUpper (CultureInfo culture)
@@ -768,10 +957,14 @@ namespace System
                        if (culture.LCID == 0x007F) { // Invariant
                                return ToUpperInvariant ();
                        }
-                       return InternalToUpper (culture);
+                       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) {
@@ -798,11 +991,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});
@@ -875,14 +1063,15 @@ namespace System
                                        // pad formatted string and append to result
 
                                        if (width > str.length) {
-                                               string pad = new String (' ', width - str.length);
+                                               const char padchar = ' ';
+                                               int padlen = width - str.length;
 
                                                if (left_align) {
                                                        result.Append (str);
-                                                       result.Append (pad);
+                                                       result.Append (padchar, padlen);
                                                }
                                                else {
-                                                       result.Append (pad);
+                                                       result.Append (padchar, padlen);
                                                        result.Append (str);
                                                }
                                        }
@@ -901,10 +1090,10 @@ namespace System
                        }
 
                        if (start < format.length)
-                               result.Append (format.Substring (start));
+                               result.Append (format, start, format.Length - start);
                }
 
-               public static String Copy (String str)
+               public unsafe static String Copy (String str)
                {
                        if (str == null)
                                throw new ArgumentNullException ("str");
@@ -912,7 +1101,11 @@ namespace System
                        int length = str.length;
 
                        String tmp = InternalAllocateStr (length);
-                       InternalStrcpy (tmp, 0, str);
+                       if (length != 0) {
+                               fixed (char *dest = tmp, src = str) {
+                                       memcpy ((byte*)dest, (byte*)src, length * 2);
+                               }
+                       }
                        return tmp;
                }
 
@@ -924,7 +1117,7 @@ namespace System
                        return obj.ToString ();
                }
 
-               public static String Concat (Object obj1, Object obj2)
+               public unsafe static String Concat (Object obj1, Object obj2)
                {
                        string s1, s2;
 
@@ -940,8 +1133,16 @@ namespace System
                                return s1;
 
                        String tmp = InternalAllocateStr (s1.Length + s2.Length);
-                       InternalStrcpy (tmp, 0, s1);
-                       InternalStrcpy (tmp, s1.length, s2);
+                       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);
+                               }
+                       }
 
                        return tmp;
                }
@@ -967,10 +1168,10 @@ namespace System
                        return Concat (s1, s2, s3);
                }
 
-               //
-               // Do *not* remove `internal' from that method
-               //
-               internal static String Concat (Object obj1, Object obj2, Object obj3, Object obj4)
+#if ! BOOTSTRAP_WITH_OLDLIB
+               [CLSCompliant(false)]
+               public static String Concat (Object obj1, Object obj2, Object obj3,
+                                            Object obj4, __arglist)
                {
                        string s1, s2, s3, s4;
 
@@ -989,16 +1190,25 @@ namespace System
                        else
                                s3 = obj3.ToString ();
 
-                       if (obj4 == null)
-                               s4 = String.Empty;
-                       else
-                               s4 = obj4.ToString ();
+                       ArgIterator iter = new ArgIterator (__arglist);
+                       int argCount = iter.GetRemainingCount();
 
-                       return Concat (s1, s2, s3, s4);
-                       
+                       StringBuilder sb = new StringBuilder ();
+                       if (obj4 != null)
+                               sb.Append (obj4.ToString ());
+
+                       for (int i = 0; i < argCount; i++) {
+                               TypedReference typedRef = iter.GetNextArg ();
+                               sb.Append (TypedReference.ToObject (typedRef));
+                       }
+
+                       s4 = sb.ToString ();
+
+                       return Concat (s1, s2, s3, s4);                 
                }
+#endif
 
-               public static String Concat (String s1, String s2)
+               public unsafe static String Concat (String s1, String s2)
                {
                        if (s1 == null) {
                                if (s2 == null)
@@ -1011,13 +1221,21 @@ namespace System
 
                        String tmp = InternalAllocateStr (s1.length + s2.length);
 
-                       InternalStrcpy (tmp, 0, s1);
-                       InternalStrcpy (tmp, s1.length, s2);
+                       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);
+                               }
+                       }
 
                        return tmp;
                }
 
-               public static String Concat (String s1, String s2, String s3)
+               public unsafe static String Concat (String s1, String s2, String s3)
                {
                        if (s1 == null){
                                if (s2 == null){
@@ -1044,14 +1262,26 @@ namespace System
                        //return InternalConcat (s1, s2, s3);
                        String tmp = InternalAllocateStr (s1.length + s2.length + s3.length);
 
-                       InternalStrcpy (tmp, 0, s1);
-                       InternalStrcpy (tmp, s1.length, s2);
-                       InternalStrcpy (tmp, s1.length + s2.length, s3);
+                       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);
+                               }
+                       }
+                       if (s3.Length != 0) {
+                               fixed (char *dest = tmp, src = s3) {
+                                       memcpy ((byte*)(dest + s1.Length + s2.Length), (byte*)src, s3.length * 2);
+                               }
+                       }
 
                        return tmp;
                }
 
-               public static String Concat (String s1, String s2, String s3, String s4)
+               public unsafe static String Concat (String s1, String s2, String s3, String s4)
                {
                        if (s1 == null && s2 == null && s3 == null && s4 == null)
                                return String.Empty;
@@ -1067,10 +1297,26 @@ namespace System
 
                        String tmp = InternalAllocateStr (s1.length + s2.length + s3.length + s4.length);
 
-                       InternalStrcpy (tmp, 0, s1);
-                       InternalStrcpy (tmp, s1.length, s2);
-                       InternalStrcpy (tmp, s1.length + s2.length, s3);
-                       InternalStrcpy (tmp, s1.length + s2.length + s3.length, s4);
+                       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);
+                               }
+                       }
+                       if (s3.Length != 0) {
+                               fixed (char *dest = tmp, src = s3) {
+                                       memcpy ((byte*)(dest + s1.Length + s2.Length), (byte*)src, s3.length * 2);
+                               }
+                       }
+                       if (s4.Length != 0) {
+                               fixed (char *dest = tmp, src = s4) {
+                                       memcpy ((byte*)(dest + s1.Length + s2.Length + s3.Length), (byte*)src, s4.length * 2);
+                               }
+                       }
 
                        return tmp;
                }
@@ -1111,7 +1357,7 @@ namespace System
                        return InternalJoin (String.Empty, values, 0, values.Length);
                }
 
-               public String Insert (int startIndex, String value)
+               public unsafe String Insert (int startIndex, String value)
                {
                        if (value == null)
                                throw new ArgumentNullException ("value");
@@ -1119,7 +1365,21 @@ namespace System
                        if (startIndex < 0 || startIndex > this.length)
                                throw new ArgumentOutOfRangeException ();
 
-                       return InternalInsert (startIndex, value);
+                       if (value.Length == 0)
+                               return this;
+                       if (this.Length == 0)
+                               return value;
+                       String tmp = InternalAllocateStr (this.length + value.length);
+
+                       fixed (char *dest = tmp, src = this, val = value) {
+                               char *dst = dest;
+                               memcpy ((byte*)dst, (byte*)src, startIndex * 2);
+                               dst += startIndex;
+                               memcpy ((byte*)dst, (byte*)val, value.length * 2);
+                               dst += value.length;
+                               memcpy ((byte*)dst, (byte*)(src + startIndex), (length - startIndex) * 2);
+                       }
+                       return tmp;
                }
 
 
@@ -1287,9 +1547,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);
 
@@ -1371,6 +1632,181 @@ namespace System
                        }
                }
 
+#if NET_2_0
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
+#endif
+               public unsafe override int GetHashCode ()
+               {
+                       fixed (char * c = this) {
+                               char * cc = c;
+                               char * end = cc + length - 1;
+                               int h = 0;
+                               for (;cc < end; cc += 2) {
+                                       h = (h << 5) - h + *cc;
+                                       h = (h << 5) - h + cc [1];
+                               }
+                               ++end;
+                               if (cc < end)
+                                       h = (h << 5) - h + *cc;
+                               return h;
+                       }
+               }
+
+               /* helpers used by the runtime as well as above or eslewhere in corlib */
+               internal static unsafe void memset (byte *dest, int val, int len)
+               {
+                       if (len < 8) {
+                               while (len != 0) {
+                                       *dest = (byte)val;
+                                       ++dest;
+                                       --len;
+                               }
+                               return;
+                       }
+                       if (val != 0) {
+                               val = val | (val << 8);
+                               val = val | (val << 16);
+                       }
+                       // align to 4
+                       int rest = (int)dest & 3;
+                       if (rest != 0) {
+                               rest = 4 - rest;
+                               len -= rest;
+                               do {
+                                       *dest = (byte)val;
+                                       ++dest;
+                                       --rest;
+                               } while (rest != 0);
+                       }
+                       while (len >= 16) {
+                               ((int*)dest) [0] = val;
+                               ((int*)dest) [1] = val;
+                               ((int*)dest) [2] = val;
+                               ((int*)dest) [3] = val;
+                               dest += 16;
+                               len -= 16;
+                       }
+                       while (len >= 4) {
+                               ((int*)dest) [0] = val;
+                               dest += 4;
+                               len -= 4;
+                       }
+                       // tail bytes
+                       while (len > 0) {
+                               *dest = (byte)val;
+                               dest++;
+                               len--;
+                       }
+               }
+
+               internal 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
+                               // that can tolerate unaligned reads/writes of doubles
+                               ((double*)dest) [0] = ((double*)src) [0];
+                               ((double*)dest) [1] = ((double*)src) [1];
+                               ((double*)dest) [2] = ((double*)src) [2];
+                               ((double*)dest) [3] = ((double*)src) [3];
+                               dest += 32;
+                               src += 32;
+                               size -= 32;
+                       }*/
+                       while (size >= 16) {
+                               ((int*)dest) [0] = ((int*)src) [0];
+                               ((int*)dest) [1] = ((int*)src) [1];
+                               ((int*)dest) [2] = ((int*)src) [2];
+                               ((int*)dest) [3] = ((int*)src) [3];
+                               dest += 16;
+                               src += 16;
+                               size -= 16;
+                       }
+                       while (size >= 4) {
+                               ((int*)dest) [0] = ((int*)src) [0];
+                               dest += 4;
+                               src += 4;
+                               size -= 4;
+                       }
+                       while (size > 0) {
+                               ((byte*)dest) [0] = ((byte*)src) [0];
+                               dest += 1;
+                               src += 1;
+                               --size;
+                       }
+               }
+               static unsafe void memcpy2 (byte *dest, byte *src, int size) {
+                       while (size >= 8) {
+                               ((short*)dest) [0] = ((short*)src) [0];
+                               ((short*)dest) [1] = ((short*)src) [1];
+                               ((short*)dest) [2] = ((short*)src) [2];
+                               ((short*)dest) [3] = ((short*)src) [3];
+                               dest += 8;
+                               src += 8;
+                               size -= 8;
+                       }
+                       while (size >= 2) {
+                               ((short*)dest) [0] = ((short*)src) [0];
+                               dest += 2;
+                               src += 2;
+                               size -= 2;
+                       }
+                       if (size > 0)
+                               ((byte*)dest) [0] = ((byte*)src) [0];
+               }
+               static unsafe void memcpy1 (byte *dest, byte *src, int size) {
+                       while (size >= 8) {
+                               ((byte*)dest) [0] = ((byte*)src) [0];
+                               ((byte*)dest) [1] = ((byte*)src) [1];
+                               ((byte*)dest) [2] = ((byte*)src) [2];
+                               ((byte*)dest) [3] = ((byte*)src) [3];
+                               ((byte*)dest) [4] = ((byte*)src) [4];
+                               ((byte*)dest) [5] = ((byte*)src) [5];
+                               ((byte*)dest) [6] = ((byte*)src) [6];
+                               ((byte*)dest) [7] = ((byte*)src) [7];
+                               dest += 8;
+                               src += 8;
+                               size -= 8;
+                       }
+                       while (size >= 2) {
+                               ((byte*)dest) [0] = ((byte*)src) [0];
+                               ((byte*)dest) [1] = ((byte*)src) [1];
+                               dest += 2;
+                               src += 2;
+                               size -= 2;
+                       }
+                       if (size > 0)
+                               ((byte*)dest) [0] = ((byte*)src) [0];
+               }
+               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
+                       // (just ignore the issue on x86?)
+                       if ((((int)dest | (int)src) & 3) != 0) {
+                               if (((int)dest & 1) != 0 && ((int)src & 1) != 0 && size >= 1) {
+                                       dest [0] = src [0];
+                                       ++dest;
+                                       ++src;
+                                       --size;
+                               }
+                               if (((int)dest & 2) != 0 && ((int)src & 2) != 0 && size >= 2) {
+                                       ((short*)dest) [0] = ((short*)src) [0];
+                                       dest += 2;
+                                       src += 2;
+                                       size -= 2;
+                               }
+                               if ((((int)dest | (int)src) & 1) != 0) {
+                                       memcpy1 (dest, src, size);
+                                       return;
+                               }
+                               if ((((int)dest | (int)src) & 2) != 0) {
+                                       memcpy2 (dest, src, size);
+                                       return;
+                               }
+                       }
+                       memcpy4 (dest, src, size);
+               }
+
                [CLSCompliant (false), MethodImplAttribute (MethodImplOptions.InternalCall)]
                unsafe public extern String (char *value);
 
@@ -1395,24 +1831,15 @@ namespace System
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                public extern String (char c, int count);
 
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               public extern override int GetHashCode ();
-
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                private extern static string InternalJoin (string separator, string[] value, int sIndex, int count);
 
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               private extern String InternalInsert (int sourceIndex, String value);
-
                [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 String InternalRemove (int sIndex, int count);
-
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                private extern void InternalCopyTo (int sIndex, char[] dest, int destIndex, int count);
 
@@ -1431,12 +1858,6 @@ namespace System
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                private extern String InternalPad (int width, char chr, bool right);
 
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               private extern String InternalToLower (CultureInfo culture);
-
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               private extern String InternalToUpper (CultureInfo culture);
-
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                internal extern static String InternalAllocateStr (int length);