6 // Jeffrey Stedfast (fejj@ximian.com)
7 // Dan Lewis (dihlewis@yahoo.co.uk)
9 // (C) 2001 Ximian, Inc. http://www.ximian.com
14 using System.Collections;
15 using System.Globalization;
16 using System.Runtime.CompilerServices;
21 public sealed class String : IConvertible, IComparable, ICloneable, IEnumerable
23 [NonSerialized] private int length;
24 [NonSerialized] private char start_char;
26 private const int COMPARE_CASE = 0;
27 private const int COMPARE_INCASE = 1;
28 private const int COMPARE_ORDINAL = 2;
30 public static readonly String Empty = "";
32 public static unsafe bool Equals (string a, string b)
34 if ((a as object) == (b as object))
37 if (a == null || b == null)
48 fixed (char * s1 = &a.start_char, s2 = &b.start_char) {
49 // it must be one char, because 0 len is done above
54 int * sint1 = (int *) s1, sint2 = (int *) s2;
57 if (*sint1++ != *sint2++)
66 return *(char *) sint1 == *(char *) sint2;
70 public static bool operator == (String a, String b)
75 public static bool operator != (String a, String b)
77 return !Equals (a, b);
80 public override bool Equals (Object obj)
82 return Equals (this, obj as String);
85 public bool Equals (String value)
87 return Equals (this, value);
90 [IndexerName ("Chars")]
91 public extern char this [int index] {
92 [MethodImplAttribute (MethodImplOptions.InternalCall)]
96 public Object Clone ()
101 public TypeCode GetTypeCode ()
103 return TypeCode.String;
106 public void CopyTo (int sourceIndex, char[] destination, int destinationIndex, int count)
108 // LAMESPEC: should I null-terminate?
109 if (destination == null)
110 throw new ArgumentNullException ("destination");
112 if (sourceIndex < 0 || destinationIndex < 0 || count < 0)
113 throw new ArgumentOutOfRangeException ();
115 if (sourceIndex + count > Length)
116 throw new ArgumentOutOfRangeException ();
118 if (destinationIndex + count > destination.Length)
119 throw new ArgumentOutOfRangeException ();
121 InternalCopyTo (sourceIndex, destination, destinationIndex, count);
124 public char[] ToCharArray ()
126 return ToCharArray (0, length);
129 public char[] ToCharArray (int startIndex, int length)
131 if (startIndex < 0 || length < 0 || startIndex + length > this.length)
132 throw new ArgumentOutOfRangeException ();
134 char [] tmp = new char[length];
136 InternalCopyTo (startIndex, tmp, 0, length);
141 public String [] Split (params char [] separator)
143 return Split (separator, Int32.MaxValue);
146 public String[] Split (char[] separator, int count)
148 if (separator == null || separator.Length == 0)
149 separator = WhiteChars;
152 throw new ArgumentOutOfRangeException ();
155 return new String[0];
158 return new String[1] { ToString() };
160 return InternalSplit (separator, count);
163 public String Substring (int startIndex)
165 if (startIndex < 0 || startIndex > this.length)
166 throw new ArgumentOutOfRangeException ("startIndex");
168 string tmp = InternalAllocateStr (this.length - startIndex);
169 InternalStrcpy (tmp, 0, this, startIndex, length - startIndex);
174 public String Substring (int startIndex, int length)
176 if (length < 0 || startIndex < 0 || startIndex + length > this.length)
177 throw new ArgumentOutOfRangeException ();
182 string tmp = InternalAllocateStr (length);
183 InternalStrcpy (tmp, 0, this, startIndex, length);
188 private static readonly char[] WhiteChars = { (char) 0x9, (char) 0xA, (char) 0xB, (char) 0xC, (char) 0xD,
189 (char) 0x20, (char) 0xA0, (char) 0x2000, (char) 0x2001, (char) 0x2002, (char) 0x2003, (char) 0x2004,
190 (char) 0x2005, (char) 0x2006, (char) 0x2007, (char) 0x2008, (char) 0x2009, (char) 0x200A, (char) 0x200B,
191 (char) 0x3000, (char) 0xFEFF };
193 public String Trim (params char[] trimChars)
195 if (trimChars == null || trimChars.Length == 0)
196 trimChars = WhiteChars;
198 return InternalTrim (trimChars, 0);
201 public String TrimStart (params char[] trimChars)
203 if (trimChars == null || trimChars.Length == 0)
204 trimChars = WhiteChars;
206 return InternalTrim (trimChars, 1);
209 public String TrimEnd (params char[] trimChars)
211 if (trimChars == null || trimChars.Length == 0)
212 trimChars = WhiteChars;
214 return InternalTrim (trimChars, 2);
217 public static int Compare (String strA, String strB)
219 return Compare (strA, strB, false, CultureInfo.CurrentCulture);
222 public static int Compare (String strA, String strB, bool ignoreCase)
224 return Compare (strA, strB, ignoreCase, CultureInfo.CurrentCulture);
227 public static int Compare (String strA, String strB, bool ignoreCase, CultureInfo culture)
230 throw new ArgumentNullException ("culture");
239 else if (strB == null) {
243 CompareOptions compopts;
246 compopts = CompareOptions.IgnoreCase;
248 compopts = CompareOptions.None;
250 return culture.CompareInfo.Compare (strA, strB, compopts);
253 public static int Compare (String strA, int indexA, String strB, int indexB, int length)
255 return Compare (strA, indexA, strB, indexB, length, false, CultureInfo.CurrentCulture);
258 public static int Compare (String strA, int indexA, String strB, int indexB, int length, bool ignoreCase)
260 return Compare (strA, indexA, strB, indexB, length, ignoreCase, CultureInfo.CurrentCulture);
263 public static int Compare (String strA, int indexA, String strB, int indexB, int length, bool ignoreCase, CultureInfo culture)
266 throw new ArgumentNullException ("culture");
268 if ((indexA > strA.Length) || (indexB > strB.Length) || (indexA < 0) || (indexB < 0) || (length < 0))
269 throw new ArgumentOutOfRangeException ();
281 else if (strB == null) {
285 CompareOptions compopts;
288 compopts = CompareOptions.IgnoreCase;
290 compopts = CompareOptions.None;
292 /* Need to cap the requested length to the
293 * length of the string, because
294 * CompareInfo.Compare will insist that length
295 * <= (string.Length - offset)
300 if (length > (strA.Length - indexA)) {
301 len1 = strA.Length - indexA;
304 if (length > (strB.Length - indexB)) {
305 len2 = strB.Length - indexB;
308 return culture.CompareInfo.Compare (strA, indexA, len1, strB, indexB, len2, compopts);
311 public int CompareTo (Object value)
316 if (!(value is String))
317 throw new ArgumentException ();
319 return String.Compare (this, (String) value, false);
322 public int CompareTo (String strB)
327 return Compare (this, strB, false);
330 public static int CompareOrdinal (String strA, String strB)
338 else if (strB == null) {
342 /* Invariant, because that is cheaper to
343 * instantiate (and chances are it already has
346 return CultureInfo.InvariantCulture.CompareInfo.Compare (strA, strB, CompareOptions.Ordinal);
349 public static int CompareOrdinal (String strA, int indexA, String strB, int indexB, int length)
351 if ((indexA > strA.Length) || (indexB > strB.Length) || (indexA < 0) || (indexB < 0) || (length < 0))
352 throw new ArgumentOutOfRangeException ();
360 else if (strB == null) {
364 /* Need to cap the requested length to the
365 * length of the string, because
366 * CompareInfo.Compare will insist that length
367 * <= (string.Length - offset)
372 if (length > (strA.Length - indexA)) {
373 len1 = strA.Length - indexA;
376 if (length > (strB.Length - indexB)) {
377 len2 = strB.Length - indexB;
380 return CultureInfo.InvariantCulture.CompareInfo.Compare (strA, indexA, len1, strB, indexB, len2, CompareOptions.Ordinal);
383 public bool EndsWith (String value)
386 throw new ArgumentNullException ("value");
388 if (value == String.Empty)
391 if (value.length > this.length)
394 return (0 == Compare (this, length - value.length, value, 0, value.length));
397 public int IndexOfAny (char [] anyOf)
400 throw new ArgumentNullException ("anyOf");
402 return InternalIndexOfAny (anyOf, 0, this.length);
405 public int IndexOfAny (char [] anyOf, int startIndex)
408 throw new ArgumentNullException ("anyOf");
409 if (startIndex < 0 || startIndex >= this.length)
410 throw new ArgumentOutOfRangeException ("sourceIndex");
412 return InternalIndexOfAny (anyOf, startIndex, this.length - startIndex);
415 public int IndexOfAny (char [] anyOf, int startIndex, int count)
418 throw new ArgumentNullException ("anyOf");
419 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
420 throw new ArgumentOutOfRangeException ();
422 return InternalIndexOfAny (anyOf, startIndex, count);
425 public int IndexOf (char value)
427 return IndexOf (value, 0, this.length);
430 public int IndexOf (String value)
432 return IndexOf (value, 0, this.length);
435 public int IndexOf (char value, int startIndex)
437 return IndexOf (value, startIndex, this.length - startIndex);
440 public int IndexOf (String value, int startIndex)
442 return IndexOf (value, startIndex, this.length - startIndex);
445 /* This method is culture-insensitive */
446 public int IndexOf (char value, int startIndex, int count)
448 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
449 throw new ArgumentOutOfRangeException ();
451 if ((startIndex == 0 && this.length == 0) || (startIndex == this.length) || (count == 0))
454 for (int pos = startIndex; pos < startIndex + count; pos++) {
455 if (this[pos] == value)
461 /* But this one is culture-sensitive */
462 public int IndexOf (String value, int startIndex, int count)
465 throw new ArgumentNullException ("value");
467 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
468 throw new ArgumentOutOfRangeException ();
470 if (value.length == 0)
473 if (startIndex == 0 && this.length == 0)
479 return CultureInfo.CurrentCulture.CompareInfo.IndexOf (this, value, startIndex, count);
482 public int LastIndexOfAny (char [] anyOf)
485 throw new ArgumentNullException ("anyOf");
487 return InternalLastIndexOfAny (anyOf, this.length - 1, this.length);
490 public int LastIndexOfAny (char [] anyOf, int startIndex)
493 throw new ArgumentNullException ("anyOf");
495 if (startIndex < 0 || startIndex > this.length)
496 throw new ArgumentOutOfRangeException ();
498 if (this.length == 0)
501 return InternalLastIndexOfAny (anyOf, startIndex, startIndex + 1);
504 public int LastIndexOfAny (char [] anyOf, int startIndex, int count)
507 throw new ArgumentNullException ("anyOf");
509 if (startIndex < 0 || count < 0 || startIndex > this.length || startIndex - count < -1)
510 throw new ArgumentOutOfRangeException ();
512 if (this.length == 0)
515 return InternalLastIndexOfAny (anyOf, startIndex, count);
518 public int LastIndexOf (char value)
520 if (this.length == 0)
523 return LastIndexOf (value, this.length - 1, this.length);
526 public int LastIndexOf (String value)
528 if (this.length == 0)
529 /* This overload does additional checking */
530 return LastIndexOf (value, 0, 0);
532 return LastIndexOf (value, this.length - 1, this.length);
535 public int LastIndexOf (char value, int startIndex)
537 return LastIndexOf (value, startIndex, startIndex + 1);
540 public int LastIndexOf (String value, int startIndex)
542 return LastIndexOf (value, startIndex, startIndex + 1);
545 /* This method is culture-insensitive */
546 public int LastIndexOf (char value, int startIndex, int count)
548 if (startIndex == 0 && this.length == 0)
551 if (startIndex < 0 || count < 0)
552 throw new ArgumentOutOfRangeException ();
554 if (startIndex >= this.length || startIndex - count + 1 < 0)
555 throw new ArgumentOutOfRangeException ();
557 for(int pos = startIndex; pos > startIndex - count; pos--) {
558 if (this [pos] == value)
564 /* But this one is culture-sensitive */
565 public int LastIndexOf (String value, int startIndex, int count)
568 throw new ArgumentNullException ("value");
570 if (value == String.Empty)
573 if (startIndex == 0 && this.length == 0)
576 // This check is needed to match undocumented MS behaviour
577 if (this.length == 0 && value.length > 0)
580 if (value.length > startIndex)
586 if (startIndex < 0 || startIndex > this.length)
587 throw new ArgumentOutOfRangeException ();
589 if (count < 0 || startIndex - count + 1 < 0)
590 throw new ArgumentOutOfRangeException ();
592 return CultureInfo.CurrentCulture.CompareInfo.LastIndexOf (this, value, startIndex, count);
595 public String PadLeft (int totalWidth)
597 return PadLeft (totalWidth, ' ');
600 public String PadLeft (int totalWidth, char paddingChar)
603 throw new ArgumentException ();
605 if (totalWidth < this.length)
606 return String.Copy (this);
608 return InternalPad (totalWidth, paddingChar, false);
611 public String PadRight (int totalWidth)
613 return PadRight (totalWidth, ' ');
616 public String PadRight (int totalWidth, char paddingChar)
619 throw new ArgumentException ();
621 if (totalWidth < this.length)
622 return String.Copy (this);
624 return InternalPad (totalWidth, paddingChar, true);
627 public bool StartsWith (String value)
630 throw new ArgumentNullException ("value");
632 if (value == String.Empty)
635 if (this.length < value.length)
638 return (0 == Compare (this, 0, value, 0 , value.length));
641 /* This method is culture insensitive */
642 public String Replace (char oldChar, char newChar)
644 return InternalReplace (oldChar, newChar);
647 /* This method is culture sensitive */
648 public String Replace (String oldValue, String newValue)
650 if (oldValue == null)
651 throw new ArgumentNullException ("oldValue");
653 if (oldValue == String.Empty)
654 throw new ArgumentException ("oldValue is the empty string.");
656 if (this == String.Empty)
659 if (oldValue.Length == 0 || oldValue[0] == '\0') {
663 if (newValue == null)
664 newValue = String.Empty;
666 return InternalReplace (oldValue, newValue, CultureInfo.CurrentCulture.CompareInfo);
669 public String Remove (int startIndex, int count)
671 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
672 throw new ArgumentOutOfRangeException ();
674 return InternalRemove (startIndex, count);
677 public String ToLower ()
679 // CurrentCulture can never be invariant or null
680 return InternalToLower (CultureInfo.CurrentCulture);
683 public unsafe String ToLower (CultureInfo culture)
686 throw new ArgumentNullException ("culture");
688 if (culture.LCID == 0x007F) { // Invariant
689 string tmp = InternalAllocateStr (length);
690 fixed (char* source = &start_char, dest = tmp) {
692 char* destPtr = (char*)dest;
693 char* sourcePtr = (char*)source;
695 for (int n = 0; n < length; n++) {
696 *destPtr = Char.ToLower (*sourcePtr);
703 return InternalToLower (culture);
706 public String ToUpper ()
708 // CurrentCulture can never be invariant or null
709 return InternalToUpper (CultureInfo.CurrentCulture);
712 public unsafe String ToUpper (CultureInfo culture)
715 throw new ArgumentNullException ("culture");
717 if (culture.LCID == 0x007F) { // Invariant
718 string tmp = InternalAllocateStr (length);
719 fixed (char* source = &start_char, dest = tmp) {
721 char* destPtr = (char*)dest;
722 char* sourcePtr = (char*)source;
724 for (int n = 0; n < length; n++) {
725 *destPtr = Char.ToUpper (*sourcePtr);
732 return InternalToUpper (culture);
735 public override String ToString ()
740 public String ToString (IFormatProvider provider)
745 public String Trim ()
750 public static String Format (String format, Object arg0)
752 return Format (null, format, new Object[] {arg0});
755 public static String Format (String format, Object arg0, Object arg1)
757 return Format (null, format, new Object[] {arg0, arg1});
760 public static String Format (String format, Object arg0, Object arg1, Object arg2)
762 return Format (null, format, new Object[] {arg0, arg1, arg2});
765 public static string Format (string format, params object[] args)
767 return Format (null, format, args);
770 public static string Format (IFormatProvider provider, string format, params object[] args)
772 StringBuilder b = new StringBuilder ();
773 FormatHelper (b, provider, format, args);
774 return b.ToString ();
777 internal static void FormatHelper (StringBuilder result, IFormatProvider provider, string format, params object[] args)
779 if (format == null || args == null)
780 throw new ArgumentNullException ();
784 while (ptr < format.length) {
785 char c = format[ptr ++];
788 result.Append (format, start, ptr - start - 1);
790 // check for escaped open bracket
792 if (format[ptr] == '{') {
803 ParseFormatSpecifier (format, ref ptr, out n, out width, out left_align, out arg_format);
804 if (n >= args.Length)
805 throw new FormatException ("Index (zero based) must be greater than or equal to zero and less than the size of the argument list.");
809 object arg = args[n];
814 else if (arg is IFormattable)
815 str = ((IFormattable)arg).ToString (arg_format, provider);
817 str = arg.ToString ();
819 // pad formatted string and append to result
821 if (width > str.length) {
822 string pad = new String (' ', width - str.length);
838 else if (c == '}' && ptr < format.length && format[ptr] == '}') {
839 result.Append (format, start, ptr - start - 1);
843 throw new FormatException ("Input string was not in a correct format.");
847 if (start < format.length)
848 result.Append (format.Substring (start));
851 public static String Copy (String str)
854 throw new ArgumentNullException ("str");
856 int length = str.length;
858 String tmp = InternalAllocateStr (length);
859 InternalStrcpy (tmp, 0, str);
863 public static String Concat (Object obj)
868 return obj.ToString ();
871 public static String Concat (Object obj1, Object obj2)
875 s1 = (obj1 != null) ? obj1.ToString () : null;
876 s2 = (obj2 != null) ? obj2.ToString () : null;
883 } else if (s2 == null)
886 String tmp = InternalAllocateStr (s1.Length + s2.Length);
887 InternalStrcpy (tmp, 0, s1);
888 InternalStrcpy (tmp, s1.length, s2);
893 public static String Concat (Object obj1, Object obj2, Object obj3)
899 s1 = obj1.ToString ();
904 s2 = obj2.ToString ();
909 s3 = obj3.ToString ();
911 return Concat (s1, s2, s3);
914 public static String Concat (Object obj1, Object obj2, Object obj3, Object obj4)
916 string s1, s2, s3, s4;
921 s1 = obj1.ToString ();
926 s2 = obj2.ToString ();
931 s3 = obj3.ToString ();
936 s4 = obj4.ToString ();
938 return Concat (s1, s2, s3, s4);
942 public static String Concat (String s1, String s2)
953 String tmp = InternalAllocateStr (s1.length + s2.length);
955 InternalStrcpy (tmp, 0, s1);
956 InternalStrcpy (tmp, s1.length, s2);
961 public static String Concat (String s1, String s2, String s3)
985 //return InternalConcat (s1, s2, s3);
986 String tmp = InternalAllocateStr (s1.length + s2.length + s3.length);
988 InternalStrcpy (tmp, 0, s1);
989 InternalStrcpy (tmp, s1.length, s2);
990 InternalStrcpy (tmp, s1.length + s2.length, s3);
995 public static String Concat (String s1, String s2, String s3, String s4)
997 if (s1 == null && s2 == null && s3 == null && s4 == null)
1009 String tmp = InternalAllocateStr (s1.length + s2.length + s3.length + s4.length);
1011 InternalStrcpy (tmp, 0, s1);
1012 InternalStrcpy (tmp, s1.length, s2);
1013 InternalStrcpy (tmp, s1.length + s2.length, s3);
1014 InternalStrcpy (tmp, s1.length + s2.length + s3.length, s4);
1019 public static String Concat (params Object[] args)
1022 int len, i, currentpos;
1025 throw new ArgumentNullException ("args");
1027 strings = new string [args.Length];
1030 foreach (object arg in args) {
1031 /* use Empty for each null argument */
1033 strings[i] = String.Empty;
1035 strings[i] = arg.ToString ();
1036 len += strings[i].length;
1041 return String.Empty;
1045 String tmp = InternalAllocateStr (len);
1046 for (i = 0; i < strings.Length; i++) {
1047 InternalStrcpy (tmp, currentpos, strings[i]);
1048 currentpos += strings[i].length;
1054 public static String Concat (params String[] values)
1056 int len, i, currentpos;
1059 throw new ArgumentNullException ("values");
1062 foreach (string value in values)
1063 len += value != null ? value.length : 0;
1066 return String.Empty;
1070 String tmp = InternalAllocateStr (len);
1071 for (i = 0; i < values.Length; i++) {
1072 if (values[i] == null)
1075 InternalStrcpy (tmp, currentpos, values[i]);
1076 currentpos += values[i].length;
1082 public String Insert (int startIndex, String value)
1085 throw new ArgumentNullException ("value");
1087 if (startIndex < 0 || startIndex > this.length)
1088 throw new ArgumentOutOfRangeException ();
1090 return InternalInsert (startIndex, value);
1094 public static string Intern (string str)
1097 throw new ArgumentNullException ("str");
1099 return InternalIntern (str);
1102 public static string IsInterned (string str)
1105 throw new ArgumentNullException ("str");
1107 return InternalIsInterned (str);
1110 public static string Join (string separator, string [] value)
1113 throw new ArgumentNullException ("value");
1115 return Join (separator, value, 0, value.Length);
1118 public static string Join (string separator, string[] value, int startIndex, int count)
1121 throw new ArgumentNullException ("value");
1123 if (startIndex + count > value.Length)
1124 throw new ArgumentOutOfRangeException ();
1126 if (startIndex == value.Length)
1127 return String.Empty;
1129 return InternalJoin (separator, value, startIndex, count);
1132 bool IConvertible.ToBoolean (IFormatProvider provider)
1134 return Convert.ToBoolean (this, provider);
1137 byte IConvertible.ToByte (IFormatProvider provider)
1139 return Convert.ToByte (this, provider);
1142 char IConvertible.ToChar (IFormatProvider provider)
1144 return Convert.ToChar (this, provider);
1147 DateTime IConvertible.ToDateTime (IFormatProvider provider)
1149 return Convert.ToDateTime (this, provider);
1152 decimal IConvertible.ToDecimal (IFormatProvider provider)
1154 return Convert.ToDecimal (this, provider);
1157 double IConvertible.ToDouble (IFormatProvider provider)
1159 return Convert.ToDouble (this, provider);
1162 short IConvertible.ToInt16 (IFormatProvider provider)
1164 return Convert.ToInt16 (this, provider);
1167 int IConvertible.ToInt32 (IFormatProvider provider)
1169 return Convert.ToInt32 (this, provider);
1172 long IConvertible.ToInt64 (IFormatProvider provider)
1174 return Convert.ToInt64 (this, provider);
1177 [CLSCompliant (false)]
1178 sbyte IConvertible.ToSByte (IFormatProvider provider)
1180 return Convert.ToSByte (this, provider);
1183 float IConvertible.ToSingle (IFormatProvider provider)
1185 return Convert.ToSingle (this, provider);
1188 string IConvertible.ToString (IFormatProvider format)
1193 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
1195 return Convert.ToType (this, conversionType, provider);
1198 [CLSCompliant (false)]
1199 ushort IConvertible.ToUInt16 (IFormatProvider provider)
1201 return Convert.ToUInt16 (this, provider);
1204 [CLSCompliant (false)]
1205 uint IConvertible.ToUInt32 (IFormatProvider provider)
1207 return Convert.ToUInt32 (this, provider);
1210 [CLSCompliant (false)]
1211 ulong IConvertible.ToUInt64 (IFormatProvider provider)
1213 return Convert.ToUInt64 (this, provider);
1216 TypeCode IConvertible.GetTypeCode ()
1218 return TypeCode.String;
1227 public CharEnumerator GetEnumerator ()
1229 return new CharEnumerator (this);
1232 IEnumerator IEnumerable.GetEnumerator ()
1234 return new CharEnumerator (this);
1237 private static void ParseFormatSpecifier (string str, ref int ptr, out int n, out int width,
1238 out bool left_align, out string format)
1240 // parses format specifier of form:
1246 // N = argument number (non-negative integer)
1248 n = ParseDecimal (str, ref ptr);
1250 throw new FormatException ("Input string was not in a correct format.");
1252 // M = width (non-negative integer)
1254 if (str[ptr] == ',') {
1255 // White space between ',' and number or sign.
1257 while (Char.IsWhiteSpace (str [ptr]))
1260 format = str.Substring (start, ptr - start);
1262 left_align = (str [ptr] == '-');
1266 width = ParseDecimal (str, ref ptr);
1268 throw new FormatException ("Input string was not in a correct format.");
1276 // F = argument format (string)
1278 if (str[ptr] == ':') {
1280 while (str[ptr] != '}')
1283 format += str.Substring (start, ptr - start);
1288 if (str[ptr ++] != '}')
1289 throw new FormatException ("Input string was not in a correct format.");
1291 catch (IndexOutOfRangeException) {
1292 throw new FormatException ("Input string was not in a correct format.");
1296 private static int ParseDecimal (string str, ref int ptr)
1302 if (c < '0' || '9' < c)
1305 n = n * 10 + c - '0';
1316 internal unsafe void InternalSetChar (int idx, char val)
1318 if ((uint) idx >= (uint) Length)
1319 throw new ArgumentOutOfRangeException ("idx");
1321 fixed (char * pStr = &start_char)
1327 internal unsafe void InternalSetLength (int newLength)
1329 if (newLength > length)
1330 throw new ArgumentOutOfRangeException ("newLength", "newLength as to be <= length");
1334 // zero terminate, we can pass string objects directly via pinvoke
1335 fixed (char * pStr = &start_char) {
1336 pStr [length] = '\0';
1340 [CLSCompliant (false), MethodImplAttribute (MethodImplOptions.InternalCall)]
1341 unsafe public extern String (char *value);
1343 [CLSCompliant (false), MethodImplAttribute (MethodImplOptions.InternalCall)]
1344 unsafe public extern String (char *value, int startIndex, int length);
1346 [CLSCompliant (false), MethodImplAttribute (MethodImplOptions.InternalCall)]
1347 unsafe public extern String (sbyte *value);
1349 [CLSCompliant (false), MethodImplAttribute (MethodImplOptions.InternalCall)]
1350 unsafe public extern String (sbyte *value, int startIndex, int length);
1352 [CLSCompliant (false), MethodImplAttribute (MethodImplOptions.InternalCall)]
1353 unsafe public extern String (sbyte *value, int startIndex, int length, Encoding enc);
1355 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1356 public extern String (char [] val, int startIndex, int length);
1358 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1359 public extern String (char [] val);
1361 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1362 public extern String (char c, int count);
1364 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1365 public extern override int GetHashCode ();
1367 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1368 private extern static string InternalJoin (string separator, string[] value, int sIndex, int count);
1370 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1371 private extern String InternalInsert (int sourceIndex, String value);
1373 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1374 private extern String InternalReplace (char oldChar, char newChar);
1376 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1377 private extern String InternalReplace (String oldValue, string newValue, CompareInfo comp);
1379 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1380 private extern String InternalRemove (int sIndex, int count);
1382 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1383 private extern void InternalCopyTo (int sIndex, char[] dest, int destIndex, int count);
1385 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1386 private extern String[] InternalSplit (char[] separator, int count);
1388 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1389 private extern String InternalTrim (char[] chars, int typ);
1391 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1392 private extern int InternalIndexOfAny (char [] arr, int sIndex, int count);
1394 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1395 private extern int InternalLastIndexOfAny (char [] anyOf, int sIndex, int count);
1397 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1398 private extern String InternalPad (int width, char chr, bool right);
1400 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1401 private extern String InternalToLower (CultureInfo culture);
1403 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1404 private extern String InternalToUpper (CultureInfo culture);
1406 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1407 internal extern static String InternalAllocateStr (int length);
1409 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1410 internal extern static void InternalStrcpy (String dest, int destPos, String src);
1412 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1413 internal extern static void InternalStrcpy (String dest, int destPos, String src, int sPos, int count);
1415 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1416 private extern static string InternalIntern (string str);
1418 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1419 private extern static string InternalIsInterned (string str);