Add support on Windows to install atexit handler(s) early in application’s startup.
[mono.git] / mcs / class / referencesource / mscorlib / system / string.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 /*============================================================
7 **
8 ** Class:  String
9 **
10 **
11 ** Purpose: Your favorite String class.  Native methods 
12 ** are implemented in StringNative.cpp
13 **
14 **
15 ===========================================================*/
16 namespace System {
17     using System.Text;
18     using System;
19     using System.Runtime;
20     using System.Runtime.ConstrainedExecution;
21     using System.Globalization;
22     using System.Threading;
23     using System.Collections;
24     using System.Collections.Generic;    
25     using System.Runtime.CompilerServices;
26     using System.Runtime.InteropServices;    
27     using System.Runtime.Versioning;
28     using Microsoft.Win32;
29     using System.Diagnostics.Contracts;
30
31     //
32     // For Information on these methods, please see COMString.cpp
33     //
34     // The String class represents a static string of characters.  Many of
35     // the String methods perform some type of transformation on the current
36     // instance and return the result as a new String. All comparison methods are
37     // implemented as a part of String.  As with arrays, character positions
38     // (indices) are zero-based.
39     //
40     // When passing a null string into a constructor in VJ and VC, the null should be
41     // explicitly type cast to a String.
42     // For Example:
43     // String s = new String((String)null);
44     // Console.WriteLine(s);
45     //
46     [ComVisible(true)]
47     [Serializable] 
48     public sealed partial class String : IComparable, ICloneable, IConvertible, IEnumerable
49 #if GENERICS_WORK
50         , IComparable<String>, IEnumerable<char>, IEquatable<String>
51 #endif
52     {
53         
54         //
55         //NOTE NOTE NOTE NOTE
56         //These fields map directly onto the fields in an EE StringObject.  See object.h for the layout.
57         //
58         [NonSerialized]private int  m_stringLength;
59
60         [NonSerialized]private char m_firstChar;
61
62         //private static readonly char FmtMsgMarkerChar='%';
63         //private static readonly char FmtMsgFmtCodeChar='!';
64         //These are defined in Com99/src/vm/COMStringCommon.h and must be kept in [....].
65         private const int TrimHead = 0;
66         private const int TrimTail = 1;
67         private const int TrimBoth = 2;
68
69         // The Empty constant holds the empty string value. It is initialized by the EE during startup.
70         // It is treated as intrinsic by the JIT as so the static constructor would never run.
71         // Leaving it uninitialized would confuse debuggers.
72         //
73         //We need to call the String constructor so that the compiler doesn't mark this as a literal.
74         //Marking this as a literal would mean that it doesn't show up as a field which we can access 
75         //from native.
76         public static readonly String Empty;
77
78         //
79         //Native Static Methods
80         //
81     
82         // Joins an array of strings together as one string with a separator between each original string.
83         //
84         public static String Join(String separator, params String[] value) {
85             if (value==null)
86                 throw new ArgumentNullException("value");
87             Contract.EndContractBlock();
88             return Join(separator, value, 0, value.Length);
89         }
90
91         [ComVisible(false)]
92         public static String Join(String separator, params Object[] values) {
93             if (values==null)
94                 throw new ArgumentNullException("values");
95             Contract.EndContractBlock();
96
97             if (values.Length == 0 || values[0] == null)
98                 return String.Empty;
99
100             if (separator == null)
101                 separator = String.Empty;
102
103             StringBuilder result = StringBuilderCache.Acquire();
104
105             String value = values[0].ToString();           
106             if (value != null)
107                 result.Append(value);
108
109             for (int i = 1; i < values.Length; i++) {
110                 result.Append(separator);
111                 if (values[i] != null) {
112                     // handle the case where their ToString() override is broken
113                     value = values[i].ToString();
114                     if (value != null)
115                         result.Append(value);
116                 }
117             }
118             return StringBuilderCache.GetStringAndRelease(result);
119         }
120
121         [ComVisible(false)]
122         public static String Join<T>(String separator, IEnumerable<T> values) {
123             if (values == null)
124                 throw new ArgumentNullException("values");
125             Contract.Ensures(Contract.Result<String>() != null);
126             Contract.EndContractBlock();
127
128             if (separator == null)
129                 separator = String.Empty;
130
131             using(IEnumerator<T> en = values.GetEnumerator()) {
132                 if (!en.MoveNext())
133                     return String.Empty;
134
135                 StringBuilder result = StringBuilderCache.Acquire();
136                 if (en.Current != null) {
137                     // handle the case that the enumeration has null entries
138                     // and the case where their ToString() override is broken
139                     string value = en.Current.ToString();
140                     if (value != null)
141                         result.Append(value);
142                 }
143
144                 while (en.MoveNext()) {
145                     result.Append(separator);
146                     if (en.Current != null) {
147                         // handle the case that the enumeration has null entries
148                         // and the case where their ToString() override is broken
149                         string value = en.Current.ToString();
150                         if (value != null)
151                             result.Append(value);
152                     }
153                 }            
154                 return StringBuilderCache.GetStringAndRelease(result);
155             }
156         }
157
158
159
160         [ComVisible(false)]
161         public static String Join(String separator, IEnumerable<String> values) {
162             if (values == null)
163                 throw new ArgumentNullException("values");
164             Contract.Ensures(Contract.Result<String>() != null);
165             Contract.EndContractBlock();
166
167             if (separator == null)
168                 separator = String.Empty;
169
170
171             using(IEnumerator<String> en = values.GetEnumerator()) {
172                 if (!en.MoveNext())
173                     return String.Empty;
174
175                 StringBuilder result = StringBuilderCache.Acquire();
176                 if (en.Current != null) {
177                     result.Append(en.Current);
178                 }
179
180                 while (en.MoveNext()) {
181                     result.Append(separator);
182                     if (en.Current != null) {
183                         result.Append(en.Current);
184                     }
185                 }            
186                 return StringBuilderCache.GetStringAndRelease(result);
187             }           
188         }
189
190
191 #if WIN64
192         private const int charPtrAlignConst = 3;
193         private const int alignConst        = 7;
194 #else
195         private const int charPtrAlignConst = 1;
196         private const int alignConst        = 3;
197 #endif
198
199         internal char FirstChar { get { return m_firstChar; } }
200
201         // Joins an array of strings together as one string with a separator between each original string.
202         //
203         [System.Security.SecuritySafeCritical]  // auto-generated
204         public unsafe static String Join(String separator, String[] value, int startIndex, int count) {
205             //Range check the array
206             if (value == null)
207                 throw new ArgumentNullException("value");
208
209             if (startIndex < 0)
210                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
211             if (count < 0)
212                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
213
214             if (startIndex > value.Length - count)
215                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
216             Contract.EndContractBlock();
217
218             //Treat null as empty string.
219             if (separator == null) {
220                 separator = String.Empty;
221             }
222
223             //If count is 0, that skews a whole bunch of the calculations below, so just special case that.
224             if (count == 0) {
225                 return String.Empty;
226             }
227             
228             int jointLength = 0;
229             //Figure out the total length of the strings in value
230             int endIndex = startIndex + count - 1;
231             for (int stringToJoinIndex = startIndex; stringToJoinIndex <= endIndex; stringToJoinIndex++) {
232                 if (value[stringToJoinIndex] != null) {
233                     jointLength += value[stringToJoinIndex].Length;
234                 }
235             }
236             
237             //Add enough room for the separator.
238             jointLength += (count - 1) * separator.Length;
239
240             // Note that we may not catch all overflows with this check (since we could have wrapped around the 4gb range any number of times
241             // and landed back in the positive range.) The input array might be modifed from other threads, 
242             // so we have to do an overflow check before each append below anyway. Those overflows will get caught down there.
243             if ((jointLength < 0) || ((jointLength + 1) < 0) ) {
244                 throw new OutOfMemoryException();
245             }
246
247             //If this is an empty string, just return.
248             if (jointLength == 0) {
249                 return String.Empty;
250             }
251
252             string jointString = FastAllocateString( jointLength );
253             fixed (char * pointerToJointString = &jointString.m_firstChar) {
254                 UnSafeCharBuffer charBuffer = new UnSafeCharBuffer( pointerToJointString, jointLength);                
255                 
256                 // Append the first string first and then append each following string prefixed by the separator.
257                 charBuffer.AppendString( value[startIndex] );
258                 for (int stringToJoinIndex = startIndex + 1; stringToJoinIndex <= endIndex; stringToJoinIndex++) {
259                     charBuffer.AppendString( separator );
260                     charBuffer.AppendString( value[stringToJoinIndex] );
261                 }
262                 Contract.Assert(*(pointerToJointString + charBuffer.Length) == '\0', "String must be null-terminated!");
263             }
264
265             return jointString;
266         }
267
268         [System.Security.SecuritySafeCritical]  // auto-generated
269         private unsafe static int CompareOrdinalIgnoreCaseHelper(String strA, String strB)
270         {
271             Contract.Requires(strA != null);
272             Contract.Requires(strB != null);
273             Contract.EndContractBlock();
274             int length = Math.Min(strA.Length, strB.Length);
275     
276             fixed (char* ap = &strA.m_firstChar) fixed (char* bp = &strB.m_firstChar)
277             {
278                 char* a = ap;
279                 char* b = bp;
280
281                 while (length != 0) 
282                 {
283                     int charA = *a;
284                     int charB = *b;
285
286                     Contract.Assert((charA | charB) <= 0x7F, "strings have to be ASCII");
287
288                     // uppercase both chars - notice that we need just one compare per char
289                     if ((uint)(charA - 'a') <= (uint)('z' - 'a')) charA -= 0x20;
290                     if ((uint)(charB - 'a') <= (uint)('z' - 'a')) charB -= 0x20;
291
292                     //Return the (case-insensitive) difference between them.
293                     if (charA != charB)
294                         return charA - charB;
295
296                     // Next char
297                     a++; b++;
298                     length--;
299                 }
300
301                 return strA.Length - strB.Length;
302             }
303         }
304 #if !MONO
305         // native call to COMString::CompareOrdinalEx
306         [System.Security.SecurityCritical]  // auto-generated
307         [ResourceExposure(ResourceScope.None)]
308         [MethodImplAttribute(MethodImplOptions.InternalCall)]
309         internal static extern int nativeCompareOrdinalEx(String strA, int indexA, String strB, int indexB, int count);
310
311         //This will not work in case-insensitive mode for any character greater than 0x80.  
312         //We'll throw an ArgumentException.
313         // 
314         [System.Security.SecurityCritical]  // auto-generated
315         [ResourceExposure(ResourceScope.None)]
316         [MethodImplAttribute(MethodImplOptions.InternalCall)]
317         unsafe internal static extern int nativeCompareOrdinalIgnoreCaseWC(String strA, sbyte *strBBytes);
318 #endif
319         //
320         // This is a helper method for the security team.  They need to uppercase some strings (guaranteed to be less 
321         // than 0x80) before security is fully initialized.  Without security initialized, we can't grab resources (the nlp's)
322         // from the assembly.  This provides a workaround for that problem and should NOT be used anywhere else.
323         //
324         [System.Security.SecuritySafeCritical]  // auto-generated
325         internal unsafe static string SmallCharToUpper(string strIn) {
326             Contract.Requires(strIn != null);
327             Contract.EndContractBlock();
328             //
329             // Get the length and pointers to each of the buffers.  Walk the length
330             // of the string and copy the characters from the inBuffer to the outBuffer,
331             // capitalizing it if necessary.  We assert that all of our characters are
332             // less than 0x80.
333             //
334             int length = strIn.Length;
335             String strOut = FastAllocateString(length);
336             fixed (char * inBuff = &strIn.m_firstChar, outBuff = &strOut.m_firstChar) {
337
338                 for(int i = 0; i < length; i++) {
339                     int c = inBuff[i];
340                     Contract.Assert(c <= 0x7F, "string has to be ASCII");
341
342                     // uppercase - notice that we need just one compare
343                     if ((uint)(c - 'a') <= (uint)('z' - 'a')) c -= 0x20;
344
345                     outBuff[i] = (char)c;
346                 }
347
348                 Contract.Assert(outBuff[length]=='\0', "outBuff[length]=='\0'");
349             }
350             return strOut;
351         }
352
353         //
354         //
355         // NATIVE INSTANCE METHODS
356         //
357         //
358     
359         //
360         // Search/Query methods
361         //
362
363         [System.Security.SecuritySafeCritical]  // auto-generated
364         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
365         private unsafe static bool EqualsHelper(String strA, String strB)
366         {
367             Contract.Requires(strA != null);
368             Contract.Requires(strB != null);
369             Contract.Requires(strA.Length == strB.Length);
370
371             int length = strA.Length;
372
373             fixed (char* ap = &strA.m_firstChar) fixed (char* bp = &strB.m_firstChar)
374             {
375                 char* a = ap;
376                 char* b = bp;
377
378                 // unroll the loop
379                 // the mono jit will inline the 64-bit check and eliminate the irrelevant path
380                 if (Environment.Is64BitProcess) {
381                     // for AMD64 bit platform we unroll by 12 and
382                     // check 3 qword at a time. This is less code
383                     // than the 32 bit case and is shorter
384                     // pathlength
385
386                     while (length >= 12)
387                     {
388                         if (*(long*)a     != *(long*)b) return false;
389                         if (*(long*)(a+4) != *(long*)(b+4)) return false;
390                         if (*(long*)(a+8) != *(long*)(b+8)) return false;
391                         a += 12; b += 12; length -= 12;
392                     }
393                 } else {
394                     while (length >= 10)
395                     {
396                         if (*(int*)a != *(int*)b) return false;
397                         if (*(int*)(a+2) != *(int*)(b+2)) return false;
398                         if (*(int*)(a+4) != *(int*)(b+4)) return false;
399                         if (*(int*)(a+6) != *(int*)(b+6)) return false;
400                         if (*(int*)(a+8) != *(int*)(b+8)) return false;
401                         a += 10; b += 10; length -= 10;
402                     }
403                 }
404
405                 // This depends on the fact that the String objects are
406                 // always zero terminated and that the terminating zero is not included
407                 // in the length. For odd string sizes, the last compare will include
408                 // the zero terminator.
409                 while (length > 0) 
410                 {
411                     if (*(int*)a != *(int*)b) break;
412                     a += 2; b += 2; length -= 2;
413                 }
414
415                 return (length <= 0);
416             }
417         }
418         
419         [System.Security.SecuritySafeCritical]  // auto-generated
420         private unsafe static int CompareOrdinalHelper(String strA, String strB)
421         {
422             Contract.Requires(strA != null);
423             Contract.Requires(strB != null);
424
425             int length = Math.Min(strA.Length, strB.Length);
426             int diffOffset = -1;
427
428             fixed (char* ap = &strA.m_firstChar) fixed (char* bp = &strB.m_firstChar)
429             {
430                 char* a = ap;
431                 char* b = bp;
432
433                 // unroll the loop
434                 while (length >= 10)
435                 {
436                     if (*(int*)a != *(int*)b) { 
437                         diffOffset = 0; 
438                         break;
439                     }
440                     
441                     if (*(int*)(a+2) != *(int*)(b+2)) {
442                         diffOffset = 2;
443                         break;
444                     }
445                     
446                     if (*(int*)(a+4) != *(int*)(b+4)) {
447                         diffOffset = 4;
448                         break;
449                     }
450                     
451                     if (*(int*)(a+6) != *(int*)(b+6)) {
452                         diffOffset = 6;
453                         break;
454                     }
455                     
456                     if (*(int*)(a+8) != *(int*)(b+8)) {
457                         diffOffset = 8;
458                         break;
459                     }
460                     a += 10; 
461                     b += 10; 
462                     length -= 10;
463                 }
464
465                 if( diffOffset != -1) {
466                     // we already see a difference in the unrolled loop above
467                     a += diffOffset;
468                     b += diffOffset;
469                     int order;
470                     if ( (order = (int)*a - (int)*b) != 0) {
471                         return order;
472                     }
473                     Contract.Assert( *(a+1) != *(b+1), "This byte must be different if we reach here!");
474                     return ((int)*(a+1) - (int)*(b+1));                    
475                 }
476
477                 // now go back to slower code path and do comparison on 4 bytes one time.
478                 // Following code also take advantage of the fact strings will 
479                 // use even numbers of characters (runtime will have a extra zero at the end.)
480                 // so even if length is 1 here, we can still do the comparsion.  
481                 while (length > 0) {
482                     if (*(int*)a != *(int*)b) {
483                         break;
484                     }
485                     a += 2; 
486                     b += 2; 
487                     length -= 2;
488                 }
489
490                 if( length > 0) { 
491                     int c;
492                     // found a different int on above loop
493                     if ( (c = (int)*a - (int)*b) != 0) {
494                         return c;
495                     }
496                     Contract.Assert( *(a+1) != *(b+1), "This byte must be different if we reach here!");
497                     return ((int)*(a+1) - (int)*(b+1));                                        
498                 }
499
500                 // At this point, we have compared all the characters in at least one string.
501                 // The longer string will be larger.
502                 return strA.Length - strB.Length;
503             }
504         }
505
506         // Determines whether two strings match.
507         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
508         public override bool Equals(Object obj) {
509             if (this == null)                        //this is necessary to guard against reverse-pinvokes and
510                 throw new NullReferenceException();  //other callers who do not use the callvirt instruction
511
512             String str = obj as String;
513             if (str == null)
514                 return false;
515
516             if (Object.ReferenceEquals(this, obj))
517                 return true;
518
519             if (this.Length != str.Length)
520                 return false;
521
522             return EqualsHelper(this, str);
523         }
524
525         // Determines whether two strings match.
526         [Pure]
527         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
528         public bool Equals(String value) {
529             if (this == null)                        //this is necessary to guard against reverse-pinvokes and
530                 throw new NullReferenceException();  //other callers who do not use the callvirt instruction
531
532             if (value == null)
533                 return false;
534
535             if (Object.ReferenceEquals(this, value))
536                 return true;
537             
538             if (this.Length != value.Length)
539                 return false;
540
541             return EqualsHelper(this, value);
542         }
543
544         [Pure]
545         [System.Security.SecuritySafeCritical]  // auto-generated
546         public bool Equals(String value, StringComparison comparisonType) {
547             if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase)
548                 throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
549             Contract.EndContractBlock();
550
551             if ((Object)this == (Object)value) {
552                 return true;
553             }
554
555             if ((Object)value == null) {
556                 return false;
557             }
558
559             switch (comparisonType) {
560                 case StringComparison.CurrentCulture:
561                     return (CultureInfo.CurrentCulture.CompareInfo.Compare(this, value, CompareOptions.None) == 0);
562
563                 case StringComparison.CurrentCultureIgnoreCase:
564                     return (CultureInfo.CurrentCulture.CompareInfo.Compare(this, value, CompareOptions.IgnoreCase) == 0);
565
566                 case StringComparison.InvariantCulture:
567                     return (CultureInfo.InvariantCulture.CompareInfo.Compare(this, value, CompareOptions.None) == 0);
568
569                 case StringComparison.InvariantCultureIgnoreCase:
570                     return (CultureInfo.InvariantCulture.CompareInfo.Compare(this, value, CompareOptions.IgnoreCase) == 0);
571
572                 case StringComparison.Ordinal:
573                     if (this.Length != value.Length)
574                         return false;
575                     return EqualsHelper(this, value);
576
577                 case StringComparison.OrdinalIgnoreCase:
578                     if (this.Length != value.Length)
579                         return false;
580
581                     // If both strings are ASCII strings, we can take the fast path.
582                     if (this.IsAscii() && value.IsAscii()) {
583                         return (CompareOrdinalIgnoreCaseHelper(this, value) == 0);
584                     }
585                     // Take the slow path.                                    
586                     return (TextInfo.CompareOrdinalIgnoreCase(this, value) == 0);
587
588                 default:
589                     throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
590             }
591         }
592
593
594         // Determines whether two Strings match.
595         [Pure]
596         public static bool Equals(String a, String b) {
597             if ((Object)a==(Object)b) {
598                 return true;
599             }
600
601             if ((Object)a==null || (Object)b==null) {
602                 return false;
603             }
604
605             if (a.Length != b.Length)
606                 return false;
607
608             return EqualsHelper(a, b);
609         }
610
611         [Pure]
612         [System.Security.SecuritySafeCritical]  // auto-generated
613         public static bool Equals(String a, String b, StringComparison comparisonType) {
614             if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase)
615                 throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
616             Contract.EndContractBlock();
617
618             if ((Object)a==(Object)b) {
619                 return true;
620             }
621     
622             if ((Object)a==null || (Object)b==null) {
623                 return false;
624             }
625
626             switch (comparisonType) {
627                 case StringComparison.CurrentCulture:
628                     return (CultureInfo.CurrentCulture.CompareInfo.Compare(a, b, CompareOptions.None) == 0);
629
630                 case StringComparison.CurrentCultureIgnoreCase:
631                     return (CultureInfo.CurrentCulture.CompareInfo.Compare(a, b, CompareOptions.IgnoreCase) == 0);
632
633                 case StringComparison.InvariantCulture:
634                     return (CultureInfo.InvariantCulture.CompareInfo.Compare(a, b, CompareOptions.None) == 0);
635
636                 case StringComparison.InvariantCultureIgnoreCase:
637                     return (CultureInfo.InvariantCulture.CompareInfo.Compare(a, b, CompareOptions.IgnoreCase) == 0);
638
639                 case StringComparison.Ordinal:
640                     if (a.Length != b.Length)
641                         return false;
642
643                     return EqualsHelper(a, b);
644
645                 case StringComparison.OrdinalIgnoreCase:
646                     if (a.Length != b.Length)
647                         return false;
648                     else {
649                         // If both strings are ASCII strings, we can take the fast path.
650                         if (a.IsAscii() && b.IsAscii()) {
651                             return (CompareOrdinalIgnoreCaseHelper(a, b) == 0);
652                         }
653                         // Take the slow path.
654
655                         return (TextInfo.CompareOrdinalIgnoreCase(a, b) == 0);
656                     }
657
658                 default:
659                     throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
660             }
661         }
662
663         public static bool operator == (String a, String b) {
664            return String.Equals(a, b);
665         }
666
667         public static bool operator != (String a, String b) {
668            return !String.Equals(a, b);
669         }
670
671         // Gets the character at a specified position.
672         //
673         // Spec#: Apply the precondition here using a contract assembly.  Potential perf issue.
674         [System.Runtime.CompilerServices.IndexerName("Chars")]
675 #if MONO
676         public unsafe char this[int index] {
677             get {
678                 if (index < 0 || index >= m_stringLength)
679                     throw new IndexOutOfRangeException ();
680                 fixed (char* c = &m_firstChar)
681                     return c[index];
682             }
683         }
684 #else
685         public extern char this[int index] {
686             [ResourceExposure(ResourceScope.None)]
687             [MethodImpl(MethodImplOptions.InternalCall)]
688             [System.Security.SecuritySafeCritical] // public member
689             get;
690         }
691 #endif
692         // Converts a substring of this string to an array of characters.  Copies the
693         // characters of this string beginning at position startIndex and ending at
694         // startIndex + length - 1 to the character array buffer, beginning
695         // at bufferStartIndex.
696         //
697         [System.Security.SecuritySafeCritical]  // auto-generated
698         unsafe public void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count)
699         {
700             if (destination == null)
701                 throw new ArgumentNullException("destination");
702             if (count < 0)
703                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
704             if (sourceIndex < 0)
705                 throw new ArgumentOutOfRangeException("sourceIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
706             if (count > Length - sourceIndex)
707                 throw new ArgumentOutOfRangeException("sourceIndex", Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
708             if (destinationIndex > destination.Length - count || destinationIndex < 0)
709                 throw new ArgumentOutOfRangeException("destinationIndex", Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
710             Contract.EndContractBlock();
711
712             // Note: fixed does not like empty arrays
713             if (count > 0)
714             {
715                 fixed (char* src = &this.m_firstChar)
716                     fixed (char* dest = destination)
717                         wstrcpy(dest + destinationIndex, src + sourceIndex, count);
718             }
719         }
720         
721         // Returns the entire string as an array of characters.
722         [System.Security.SecuritySafeCritical]  // auto-generated
723         unsafe public char[] ToCharArray() {
724             // <
725             int length = Length;
726             char[] chars = new char[length];
727             if (length > 0)
728             {
729                 fixed (char* src = &this.m_firstChar)
730                     fixed (char* dest = chars) {
731                         wstrcpy(dest, src, length);
732                     }
733             }
734             return chars;
735         }
736     
737         // Returns a substring of this string as an array of characters.
738         //
739         [System.Security.SecuritySafeCritical]  // auto-generated
740         unsafe public char[] ToCharArray(int startIndex, int length)
741         {
742             // Range check everything.
743             if (startIndex < 0 || startIndex > Length || startIndex > Length - length)
744                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
745             if (length < 0)
746                 throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_Index"));
747             Contract.EndContractBlock();
748
749             char[] chars = new char[length];
750             if(length > 0)
751             {
752                 fixed (char* src = &this.m_firstChar)
753                     fixed (char* dest = chars) {
754                         wstrcpy(dest, src + startIndex, length);
755                     }
756             }
757             return chars;
758         }
759
760         [Pure]
761         public static bool IsNullOrEmpty(String value) {
762             return (value == null || value.Length == 0);
763         }
764
765         [Pure]
766         public static bool IsNullOrWhiteSpace(String value) {
767             if (value == null) return true;
768
769             for(int i = 0; i < value.Length; i++) {
770                 if(!Char.IsWhiteSpace(value[i])) return false;
771             }
772
773             return true;
774         }
775
776 #if FEATURE_RANDOMIZED_STRING_HASHING
777         // Do not remove!
778         // This method is called by reflection in System.Xml
779         [System.Security.SecurityCritical]
780         [ResourceExposure(ResourceScope.None)]
781         [MethodImplAttribute(MethodImplOptions.InternalCall)]
782         internal static extern int InternalMarvin32HashString(string s, int strLen, long additionalEntropy);
783
784         [System.Security.SecuritySafeCritical]
785         [ResourceExposure(ResourceScope.None)]
786         internal static bool UseRandomizedHashing() {
787             return InternalUseRandomizedHashing();
788         }
789
790         [System.Security.SecurityCritical]
791         [System.Security.SuppressUnmanagedCodeSecurity]
792         [ResourceExposure(ResourceScope.None)]
793         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
794         private static extern bool InternalUseRandomizedHashing();
795 #endif
796
797         // Gets a hash code for this string.  If strings A and B are such that A.Equals(B), then
798         // they will return the same hash code.
799         [System.Security.SecuritySafeCritical]  // auto-generated
800         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
801         public override int GetHashCode() {
802
803 #if FEATURE_RANDOMIZED_STRING_HASHING
804             if(HashHelpers.s_UseRandomizedStringHashing)
805             {
806                 return InternalMarvin32HashString(this, this.Length, 0);
807             }
808 #endif // FEATURE_RANDOMIZED_STRING_HASHING
809
810             unsafe {
811                 fixed (char *src = this) {
812                     Contract.Assert(src[this.Length] == '\0', "src[this.Length] == '\\0'");
813                     Contract.Assert( ((int)src)%4 == 0, "Managed string should start at 4 bytes boundary");
814
815 #if WIN32
816                     int hash1 = (5381<<16) + 5381;
817 #else
818                     int hash1 = 5381;
819 #endif
820                     int hash2 = hash1;
821
822 #if WIN32
823                     // 32 bit machines.
824                     int* pint = (int *)src;
825                     int len = this.Length;
826                     while (len > 2)
827                     {
828                         hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
829                         hash2 = ((hash2 << 5) + hash2 + (hash2 >> 27)) ^ pint[1];
830                         pint += 2;
831                         len  -= 4;
832                     }
833
834                     if (len > 0)
835                     {
836                         hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
837                     }
838 #else
839                     int     c;
840                     char *s = src;
841                     while ((c = s[0]) != 0) {
842                         hash1 = ((hash1 << 5) + hash1) ^ c;
843                         c = s[1];
844                         if (c == 0)
845                             break;
846                         hash2 = ((hash2 << 5) + hash2) ^ c;
847                         s += 2;
848                     }
849 #endif
850 #if !MONO && DEBUG
851                     // We want to ensure we can change our hash function daily.
852                     // This is perfectly fine as long as you don't persist the
853                     // value from GetHashCode to disk or count on String A 
854                     // hashing before string B.  Those are bugs in your code.
855                     hash1 ^= ThisAssembly.DailyBuildNumber;
856 #endif
857                     return hash1 + (hash2 * 1566083941);
858                 }
859             }
860         }
861
862         // Use this if and only if you need the hashcode to not change across app domains (e.g. you have an app domain agile
863         // hash table).
864         [System.Security.SecuritySafeCritical]  // auto-generated
865         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
866         internal int GetLegacyNonRandomizedHashCode() {
867             unsafe {
868                 fixed (char *src = this) {
869                     Contract.Assert(src[this.Length] == '\0', "src[this.Length] == '\\0'");
870                     Contract.Assert( ((int)src)%4 == 0, "Managed string should start at 4 bytes boundary");
871
872 #if WIN32
873                     int hash1 = (5381<<16) + 5381;
874 #else
875                     int hash1 = 5381;
876 #endif
877                     int hash2 = hash1;
878
879 #if WIN32
880                     // 32 bit machines.
881                     int* pint = (int *)src;
882                     int len = this.Length;
883                     while (len > 2)
884                     {
885                         hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
886                         hash2 = ((hash2 << 5) + hash2 + (hash2 >> 27)) ^ pint[1];
887                         pint += 2;
888                         len  -= 4;
889                     }
890
891                     if (len > 0)
892                     {
893                         hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
894                     }
895 #else
896                     int     c;
897                     char *s = src;
898                     while ((c = s[0]) != 0) {
899                         hash1 = ((hash1 << 5) + hash1) ^ c;
900                         c = s[1];
901                         if (c == 0)
902                             break;
903                         hash2 = ((hash2 << 5) + hash2) ^ c;
904                         s += 2;
905                     }
906 #endif
907 #if !MONO && DEBUG
908                     // We want to ensure we can change our hash function daily.
909                     // This is perfectly fine as long as you don't persist the
910                     // value from GetHashCode to disk or count on String A 
911                     // hashing before string B.  Those are bugs in your code.
912                     hash1 ^= ThisAssembly.DailyBuildNumber;
913 #endif
914                     return hash1 + (hash2 * 1566083941);
915                 }
916             }
917         }
918 #if !MONO
919         // Gets the length of this string
920         //
921         /// This is a EE implemented function so that the JIT can recognise is specially
922         /// and eliminate checks on character fetchs in a loop like:
923         ///        for(int I = 0; I < str.Length; i++) str[i]
924         /// The actually code generated for this will be one instruction and will be inlined.
925         //
926         // Spec#: Add postcondition in a contract assembly.  Potential perf problem.
927         public extern int Length {
928             [System.Security.SecuritySafeCritical]  // auto-generated
929             [ResourceExposure(ResourceScope.None)]
930             [MethodImplAttribute(MethodImplOptions.InternalCall)]
931             get;
932         }
933 #endif
934         // Creates an array of strings by splitting this string at each
935         // occurence of a separator.  The separator is searched for, and if found,
936         // the substring preceding the occurence is stored as the first element in
937         // the array of strings.  We then continue in this manner by searching
938         // the substring that follows the occurence.  On the other hand, if the separator
939         // is not found, the array of strings will contain this instance as its only element.
940         // If the separator is null
941         // whitespace (i.e., Character.IsWhitespace) is used as the separator.
942         //
943         public String [] Split(params char [] separator) {
944             Contract.Ensures(Contract.Result<String[]>() != null);
945             return SplitInternal(separator, Int32.MaxValue, StringSplitOptions.None);
946         }
947
948         // Creates an array of strings by splitting this string at each
949         // occurence of a separator.  The separator is searched for, and if found,
950         // the substring preceding the occurence is stored as the first element in
951         // the array of strings.  We then continue in this manner by searching
952         // the substring that follows the occurence.  On the other hand, if the separator
953         // is not found, the array of strings will contain this instance as its only element.
954         // If the spearator is the empty string (i.e., String.Empty), then
955         // whitespace (i.e., Character.IsWhitespace) is used as the separator.
956         // If there are more than count different strings, the last n-(count-1)
957         // elements are concatenated and added as the last String.
958         //
959         public string[] Split(char[] separator, int count) {
960             Contract.Ensures(Contract.Result<String[]>() != null);
961             return SplitInternal(separator, count, StringSplitOptions.None);
962         }
963
964         [ComVisible(false)]
965         public String[] Split(char[] separator, StringSplitOptions options) {
966             Contract.Ensures(Contract.Result<String[]>() != null);
967             return SplitInternal(separator, Int32.MaxValue, options);
968         }
969
970         [ComVisible(false)]
971         public String[] Split(char[] separator, int count, StringSplitOptions options)
972         {
973             Contract.Ensures(Contract.Result<String[]>() != null);
974             return SplitInternal(separator, count, options);
975         }
976
977         [ComVisible(false)]
978         internal String[] SplitInternal(char[] separator, int count, StringSplitOptions options)
979         {
980             if (count < 0)
981                 throw new ArgumentOutOfRangeException("count",
982                     Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
983
984             if (options < StringSplitOptions.None || options > StringSplitOptions.RemoveEmptyEntries)
985                 throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", options));
986             Contract.Ensures(Contract.Result<String[]>() != null);
987             Contract.EndContractBlock();
988
989             bool omitEmptyEntries = (options == StringSplitOptions.RemoveEmptyEntries);
990
991             if ((count == 0) || (omitEmptyEntries && this.Length == 0)) 
992             {           
993                 return new String[0];
994             }
995             
996             int[] sepList = new int[Length];            
997             int numReplaces = MakeSeparatorList(separator, ref sepList);            
998             
999             //Handle the special case of no replaces and special count.
1000             if (0 == numReplaces || count == 1) {
1001                 String[] stringArray = new String[1];
1002                 stringArray[0] = this;
1003                 return stringArray;
1004             }            
1005
1006             if(omitEmptyEntries) 
1007             {
1008                 return InternalSplitOmitEmptyEntries(sepList, null, numReplaces, count);
1009             }
1010             else 
1011             {
1012                 return InternalSplitKeepEmptyEntries(sepList, null, numReplaces, count);
1013             }            
1014         }
1015
1016         [ComVisible(false)]
1017         public String [] Split(String[] separator, StringSplitOptions options) {
1018             Contract.Ensures(Contract.Result<String[]>() != null);
1019             return Split(separator, Int32.MaxValue, options);
1020         }
1021
1022         [ComVisible(false)]
1023         public String[] Split(String[] separator, Int32 count, StringSplitOptions options) {
1024             if (count < 0) {
1025                 throw new ArgumentOutOfRangeException("count",
1026                     Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
1027             }
1028
1029             if (options < StringSplitOptions.None || options > StringSplitOptions.RemoveEmptyEntries) {
1030                 throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)options));
1031             }
1032             Contract.EndContractBlock();
1033
1034             bool omitEmptyEntries = (options == StringSplitOptions.RemoveEmptyEntries);
1035
1036             if (separator == null || separator.Length ==0) {
1037                 return SplitInternal((char[]) null, count, options);
1038             }
1039             
1040             if ((count == 0) || (omitEmptyEntries && this.Length ==0)) {
1041                 return new String[0];
1042             }
1043
1044             int[] sepList = new int[Length];
1045             int[] lengthList = new int[Length];                        
1046             int numReplaces = MakeSeparatorList(separator, ref sepList, ref lengthList);
1047
1048             //Handle the special case of no replaces and special count.
1049             if (0 == numReplaces || count == 1) {
1050                 String[] stringArray = new String[1];
1051                 stringArray[0] = this;
1052                 return stringArray;
1053             }
1054             
1055             if (omitEmptyEntries) {
1056                 return InternalSplitOmitEmptyEntries(sepList, lengthList, numReplaces, count);
1057             }
1058             else {
1059                 return InternalSplitKeepEmptyEntries(sepList, lengthList, numReplaces, count);
1060             }
1061         }                        
1062         
1063         // Note a few special case in this function:
1064         //     If there is no separator in the string, a string array which only contains 
1065         //     the original string will be returned regardless of the count. 
1066         //
1067
1068         private String[] InternalSplitKeepEmptyEntries(Int32 [] sepList, Int32 [] lengthList, Int32 numReplaces, int count) {
1069             Contract.Requires(numReplaces >= 0);
1070             Contract.Requires(count >= 2);
1071             Contract.Ensures(Contract.Result<String[]>() != null);
1072         
1073             int currIndex = 0;
1074             int arrIndex = 0;
1075
1076             count--;
1077             int numActualReplaces = (numReplaces < count) ? numReplaces : count;
1078
1079             //Allocate space for the new array.
1080             //+1 for the string from the end of the last replace to the end of the String.
1081             String[] splitStrings = new String[numActualReplaces+1];
1082
1083             for (int i = 0; i < numActualReplaces && currIndex < Length; i++) {
1084                 splitStrings[arrIndex++] = Substring(currIndex, sepList[i]-currIndex );                            
1085                 currIndex=sepList[i] + ((lengthList == null) ? 1 : lengthList[i]);
1086             }
1087
1088             //Handle the last string at the end of the array if there is one.
1089             if (currIndex < Length && numActualReplaces >= 0) {
1090                 splitStrings[arrIndex] = Substring(currIndex);
1091             } 
1092             else if (arrIndex==numActualReplaces) {
1093                 //We had a separator character at the end of a string.  Rather than just allowing
1094                 //a null character, we'll replace the last element in the array with an empty string.
1095                 splitStrings[arrIndex] = String.Empty;
1096
1097             }
1098
1099             return splitStrings;
1100         }
1101
1102         
1103         // This function will not keep the Empty String 
1104         private String[] InternalSplitOmitEmptyEntries(Int32[] sepList, Int32[] lengthList, Int32 numReplaces, int count) {
1105             Contract.Requires(numReplaces >= 0);
1106             Contract.Requires(count >= 2);
1107             Contract.Ensures(Contract.Result<String[]>() != null);
1108
1109             // Allocate array to hold items. This array may not be 
1110             // filled completely in this function, we will create a 
1111             // new array and copy string references to that new array.
1112
1113             int maxItems = (numReplaces < count) ? (numReplaces+1): count ;
1114             String[] splitStrings = new String[maxItems];
1115
1116             int currIndex = 0;
1117             int arrIndex = 0;
1118
1119             for(int i=0; i< numReplaces && currIndex < Length; i++) {
1120                 if( sepList[i]-currIndex > 0) { 
1121                     splitStrings[arrIndex++] = Substring(currIndex, sepList[i]-currIndex );                            
1122                 }
1123                 currIndex=sepList[i] + ((lengthList == null) ? 1 : lengthList[i]);
1124                 if( arrIndex == count -1 )  {
1125                     // If all the remaining entries at the end are empty, skip them
1126                     while( i < numReplaces - 1 && currIndex == sepList[++i]) { 
1127                         currIndex += ((lengthList == null) ? 1 : lengthList[i]);
1128                     }
1129                     break;
1130                 }
1131             }
1132
1133             // we must have at least one slot left to fill in the last string.
1134             Contract.Assert(arrIndex < maxItems);
1135
1136             //Handle the last string at the end of the array if there is one.
1137             if (currIndex< Length) {                
1138                 splitStrings[arrIndex++] = Substring(currIndex);
1139             }
1140
1141             String[] stringArray = splitStrings;
1142             if( arrIndex!= maxItems) { 
1143                 stringArray = new String[arrIndex];
1144                 for( int j = 0; j < arrIndex; j++) {
1145                     stringArray[j] = splitStrings[j];
1146                 }   
1147             }
1148             return stringArray;
1149         }       
1150
1151         //--------------------------------------------------------------------    
1152         // This function returns number of the places within baseString where 
1153         // instances of characters in Separator occur.         
1154         // Args: separator  -- A string containing all of the split characters.
1155         //       sepList    -- an array of ints for split char indicies.
1156         //--------------------------------------------------------------------    
1157         [System.Security.SecuritySafeCritical]  // auto-generated
1158         private unsafe int MakeSeparatorList(char[] separator, ref int[] sepList) {
1159             int foundCount=0;
1160
1161             if (separator == null || separator.Length ==0) {
1162                 fixed (char* pwzChars = &this.m_firstChar) {
1163                     //If they passed null or an empty string, look for whitespace.
1164                     for (int i=0; i < Length && foundCount < sepList.Length; i++) {
1165                         if (Char.IsWhiteSpace(pwzChars[i])) {
1166                             sepList[foundCount++]=i;
1167                         }
1168                     }
1169                 }
1170             } 
1171             else {
1172                 int sepListCount = sepList.Length;
1173                 int sepCount = separator.Length;
1174                 //If they passed in a string of chars, actually look for those chars.
1175                 fixed (char* pwzChars = &this.m_firstChar, pSepChars = separator) {
1176                     for (int i=0; i< Length && foundCount < sepListCount; i++) {                        
1177                         char * pSep = pSepChars;
1178                         for( int j =0; j < sepCount; j++, pSep++) {
1179                            if ( pwzChars[i] == *pSep) {
1180                                sepList[foundCount++]=i;
1181                                break;
1182                            }
1183                         }
1184                     }
1185                 }
1186             }
1187             return foundCount;
1188         }        
1189         
1190         //--------------------------------------------------------------------    
1191         // This function returns number of the places within baseString where 
1192         // instances of separator strings occur.         
1193         // Args: separators -- An array containing all of the split strings.
1194         //       sepList    -- an array of ints for split string indicies.
1195         //       lengthList -- an array of ints for split string lengths.
1196         //--------------------------------------------------------------------    
1197         [System.Security.SecuritySafeCritical]  // auto-generated
1198         private unsafe int MakeSeparatorList(String[] separators, ref int[] sepList, ref int[] lengthList) {
1199             Contract.Assert(separators != null && separators.Length > 0, "separators != null && separators.Length > 0");
1200             
1201             int foundCount = 0;
1202             int sepListCount = sepList.Length;
1203             int sepCount = separators.Length;
1204
1205             fixed (char* pwzChars = &this.m_firstChar) {
1206                 for (int i=0; i< Length && foundCount < sepListCount; i++) {                        
1207                     for( int j =0; j < separators.Length; j++) {
1208                         String separator = separators[j];
1209                         if (String.IsNullOrEmpty(separator)) {
1210                             continue;
1211                         }
1212                         Int32 currentSepLength = separator.Length;
1213                         if ( pwzChars[i] == separator[0] && currentSepLength <= Length - i) {
1214                             if (currentSepLength == 1 
1215                                 || String.CompareOrdinal(this, i, separator, 0, currentSepLength) == 0) {
1216                                 sepList[foundCount] = i;
1217                                 lengthList[foundCount] = currentSepLength;
1218                                 foundCount++;
1219                                 i += currentSepLength - 1;
1220                                 break;
1221                             }
1222                         }
1223                     }
1224                 }
1225             }
1226             return foundCount;
1227         }
1228        
1229         // Returns a substring of this string.
1230         //
1231         public String Substring (int startIndex) {
1232             return this.Substring (startIndex, Length-startIndex);
1233         }
1234     
1235         // Returns a substring of this string.
1236         //
1237         [System.Security.SecuritySafeCritical]  // auto-generated
1238         public String Substring(int startIndex, int length) {
1239                     
1240             //Bounds Checking.
1241             if (startIndex < 0) {
1242                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
1243             }
1244
1245             if (startIndex > Length) {
1246                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndexLargerThanLength"));
1247             }
1248
1249             if (length < 0) {
1250                 throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
1251             }
1252
1253             if (startIndex > Length - length) {
1254                 throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_IndexLength"));
1255             }
1256             Contract.EndContractBlock();
1257
1258             if( length == 0) {
1259                 return String.Empty;
1260             }
1261
1262             if( startIndex == 0 && length == this.Length) {
1263                 return this;
1264             }
1265
1266             return InternalSubString(startIndex, length);
1267         }
1268
1269         [System.Security.SecurityCritical]  // auto-generated
1270         unsafe string InternalSubString(int startIndex, int length) {
1271             Contract.Assert( startIndex >= 0 && startIndex <= this.Length, "StartIndex is out of range!");
1272             Contract.Assert( length >= 0 && startIndex <= this.Length - length, "length is out of range!");            
1273             
1274             String result = FastAllocateString(length);
1275
1276             fixed(char* dest = &result.m_firstChar)
1277                 fixed(char* src = &this.m_firstChar) {
1278                     wstrcpy(dest, src + startIndex, length);
1279                 }
1280
1281             return result;
1282         }
1283     
1284     
1285         // Removes a string of characters from the ends of this string.
1286         [Pure]
1287         public String Trim(params char[] trimChars) {
1288             if (null==trimChars || trimChars.Length == 0) {
1289                 return TrimHelper(TrimBoth);
1290             }
1291             return TrimHelper(trimChars,TrimBoth);
1292         }
1293     
1294         // Removes a string of characters from the beginning of this string.
1295         public String TrimStart(params char[] trimChars) {
1296             if (null==trimChars || trimChars.Length == 0) {
1297                 return TrimHelper(TrimHead);
1298             }
1299             return TrimHelper(trimChars,TrimHead);
1300         }
1301     
1302     
1303         // Removes a string of characters from the end of this string.
1304         public String TrimEnd(params char[] trimChars) {
1305             if (null==trimChars || trimChars.Length == 0) {
1306                 return TrimHelper(TrimTail);
1307             }
1308             return TrimHelper(trimChars,TrimTail);
1309         }
1310     
1311     
1312         // Creates a new string with the characters copied in from ptr. If
1313         // ptr is null, a 0-length string (like String.Empty) is returned.
1314         //
1315         [System.Security.SecurityCritical]  // auto-generated
1316         [ResourceExposure(ResourceScope.None)]
1317         [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
1318         unsafe public extern String(char *value);
1319         [System.Security.SecurityCritical]  // auto-generated
1320         [ResourceExposure(ResourceScope.None)]
1321         [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
1322         unsafe public extern String(char *value, int startIndex, int length);
1323     
1324         [System.Security.SecurityCritical]  // auto-generated
1325         [ResourceExposure(ResourceScope.None)]
1326         [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
1327         unsafe public extern String(sbyte *value);
1328         [System.Security.SecurityCritical]  // auto-generated
1329         [ResourceExposure(ResourceScope.None)]
1330         [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
1331         unsafe public extern String(sbyte *value, int startIndex, int length);
1332
1333         [System.Security.SecurityCritical]  // auto-generated
1334         [ResourceExposure(ResourceScope.None)]
1335         [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
1336         unsafe public extern String(sbyte *value, int startIndex, int length, Encoding enc);
1337 #if !MONO
1338         [System.Security.SecurityCritical]  // auto-generated
1339         unsafe static private String CreateString(sbyte *value, int startIndex, int length, Encoding enc) {            
1340             if (enc == null)
1341                 return new String(value, startIndex, length); // default to ANSI
1342
1343             if (length < 0)
1344                 throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
1345             if (startIndex < 0)
1346                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
1347             if ((value + startIndex) < value) {
1348                 // overflow check
1349                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));
1350             }
1351
1352             byte [] b = new byte[length];
1353
1354             try {
1355                 Buffer.Memcpy(b, 0, (byte*)value, startIndex, length);
1356             }
1357             catch(NullReferenceException) {
1358                 // If we got a NullReferencException. It means the pointer or 
1359                 // the index is out of range
1360                 throw new ArgumentOutOfRangeException("value", 
1361                         Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));                
1362             }
1363
1364             return enc.GetString(b);
1365         }
1366 #endif
1367         // Helper for encodings so they can talk to our buffer directly
1368         // stringLength must be the exact size we'll expect
1369         [System.Security.SecurityCritical]  // auto-generated
1370         unsafe static internal String CreateStringFromEncoding(
1371             byte* bytes, int byteLength, Encoding encoding)
1372         {
1373             Contract.Requires(bytes != null);
1374             Contract.Requires(byteLength >= 0);
1375
1376             // Get our string length
1377             int stringLength = encoding.GetCharCount(bytes, byteLength, null);
1378             Contract.Assert(stringLength >= 0, "stringLength >= 0");
1379             
1380             // They gave us an empty string if they needed one
1381             // 0 bytelength might be possible if there's something in an encoder
1382             if (stringLength == 0)
1383                 return String.Empty;
1384             
1385             String s = FastAllocateString(stringLength);
1386             fixed(char* pTempChars = &s.m_firstChar)
1387             {
1388                 int doubleCheck = encoding.GetChars(bytes, byteLength, pTempChars, stringLength, null);
1389                 Contract.Assert(stringLength == doubleCheck, 
1390                     "Expected encoding.GetChars to return same length as encoding.GetCharCount");
1391             }
1392
1393             return s;
1394         }
1395 #if !MONO
1396         [System.Security.SecuritySafeCritical]  // auto-generated
1397         unsafe internal int ConvertToAnsi(byte *pbNativeBuffer, int cbNativeBuffer, bool fBestFit, bool fThrowOnUnmappableChar)
1398         {
1399             Contract.Assert(cbNativeBuffer >= (Length + 1) * Marshal.SystemMaxDBCSCharSize, "Insufficient buffer length passed to ConvertToAnsi");
1400
1401             const uint CP_ACP = 0;
1402             int nb;
1403
1404             const uint WC_NO_BEST_FIT_CHARS = 0x00000400;
1405
1406             uint flgs = (fBestFit ? 0 : WC_NO_BEST_FIT_CHARS);
1407             uint DefaultCharUsed = 0;
1408
1409             fixed (char* pwzChar = &this.m_firstChar)
1410             {
1411                 nb = Win32Native.WideCharToMultiByte(
1412                     CP_ACP,
1413                     flgs,
1414                     pwzChar,
1415                     this.Length,
1416                     pbNativeBuffer,
1417                     cbNativeBuffer,
1418                     IntPtr.Zero,
1419                     (fThrowOnUnmappableChar ? new IntPtr(&DefaultCharUsed) : IntPtr.Zero));
1420             }
1421
1422             if (0 != DefaultCharUsed)
1423             {
1424                 throw new ArgumentException(Environment.GetResourceString("Interop_Marshal_Unmappable_Char"));
1425             }
1426
1427             pbNativeBuffer[nb] = 0;
1428             return nb;
1429         }
1430 #endif
1431         // Normalization Methods
1432         // These just wrap calls to Normalization class
1433         public bool IsNormalized()
1434         {
1435 #if !FEATURE_NORM_IDNA_ONLY
1436             // Default to Form C
1437             return IsNormalized(NormalizationForm.FormC);
1438 #else
1439             // Default to Form IDNA
1440             return IsNormalized((NormalizationForm)ExtendedNormalizationForms.FormIdna);
1441 #endif
1442         }
1443
1444         [System.Security.SecuritySafeCritical]  // auto-generated
1445         public bool IsNormalized(NormalizationForm normalizationForm)
1446         {
1447 #if !FEATURE_NORM_IDNA_ONLY
1448             if (this.IsFastSort())
1449             {
1450                 // If its FastSort && one of the 4 main forms, then its already normalized
1451                 if( normalizationForm == NormalizationForm.FormC ||
1452                     normalizationForm == NormalizationForm.FormKC ||
1453                     normalizationForm == NormalizationForm.FormD ||
1454                     normalizationForm == NormalizationForm.FormKD )
1455                     return true;
1456             }            
1457 #endif // !FEATURE_NORM_IDNA_ONLY            
1458             return Normalization.IsNormalized(this, normalizationForm);
1459         }
1460
1461         public String Normalize()
1462         {
1463 #if !FEATURE_NORM_IDNA_ONLY
1464             // Default to Form C
1465             return Normalize(NormalizationForm.FormC);
1466 #else
1467             // Default to Form IDNA
1468             return Normalize((NormalizationForm)ExtendedNormalizationForms.FormIdna);
1469 #endif
1470         }
1471
1472         [System.Security.SecuritySafeCritical]  // auto-generated
1473         public String Normalize(NormalizationForm normalizationForm)
1474         {
1475 #if !FEATURE_NORM_IDNA_ONLY        
1476             if (this.IsAscii())
1477             {
1478                 // If its FastSort && one of the 4 main forms, then its already normalized
1479                 if( normalizationForm == NormalizationForm.FormC ||
1480                     normalizationForm == NormalizationForm.FormKC ||
1481                     normalizationForm == NormalizationForm.FormD ||
1482                     normalizationForm == NormalizationForm.FormKD )
1483                     return this;
1484             }
1485 #endif // !FEATURE_NORM_IDNA_ONLY            
1486             return Normalization.Normalize(this, normalizationForm);
1487         }
1488
1489         [System.Security.SecurityCritical]  // auto-generated
1490         [ResourceExposure(ResourceScope.None)]
1491         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1492         internal extern static String FastAllocateString(int length);
1493
1494         [System.Security.SecuritySafeCritical]  // auto-generated
1495         unsafe private static void FillStringChecked(String dest, int destPos, String src)
1496         {
1497             Contract.Requires(dest != null);
1498             Contract.Requires(src != null);
1499             if (src.Length > dest.Length - destPos) {
1500                 throw new IndexOutOfRangeException();
1501             }
1502             Contract.EndContractBlock();
1503
1504             fixed(char *pDest = &dest.m_firstChar)
1505                 fixed (char *pSrc = &src.m_firstChar) {
1506                     wstrcpy(pDest + destPos, pSrc, src.Length);
1507                 }
1508         }
1509
1510         // Creates a new string from the characters in a subarray.  The new string will
1511         // be created from the characters in value between startIndex and
1512         // startIndex + length - 1.
1513         //
1514         [System.Security.SecuritySafeCritical]  // auto-generated
1515         [ResourceExposure(ResourceScope.None)]
1516         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1517         public extern String(char [] value, int startIndex, int length);
1518     
1519         // Creates a new string from the characters in a subarray.  The new string will be
1520         // created from the characters in value.
1521         //
1522         
1523         [System.Security.SecuritySafeCritical]  // auto-generated
1524         [ResourceExposure(ResourceScope.None)]
1525         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1526         public extern String(char [] value);
1527
1528         [System.Security.SecurityCritical]  // auto-generated
1529         internal static unsafe void wstrcpy(char *dmem, char *smem, int charCount)
1530         {
1531             Buffer.Memcpy((byte*)dmem, (byte*)smem, charCount * 2); // 2 used everywhere instead of sizeof(char)
1532         }
1533
1534         [System.Security.SecuritySafeCritical]  // auto-generated
1535         private String CtorCharArray(char [] value)
1536         {
1537             if (value != null && value.Length != 0) {
1538                 String result = FastAllocateString(value.Length);
1539
1540                 unsafe {
1541                     fixed (char * dest = result, source = value) {
1542                         wstrcpy(dest, source, value.Length);
1543                     }
1544                 }
1545                 return result;
1546             }
1547             else
1548                 return String.Empty;
1549         }
1550
1551         [System.Security.SecuritySafeCritical]  // auto-generated
1552         private String CtorCharArrayStartLength(char [] value, int startIndex, int length)
1553         {
1554             if (value == null)
1555                 throw new ArgumentNullException("value");
1556
1557             if (startIndex < 0)
1558                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
1559
1560             if (length < 0)
1561                 throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
1562
1563             if (startIndex > value.Length - length)
1564                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
1565             Contract.EndContractBlock();
1566
1567             if (length > 0) {
1568                 String result = FastAllocateString(length);
1569
1570                 unsafe {
1571                     fixed (char * dest = result, source = value) {
1572                         wstrcpy(dest, source + startIndex, length);
1573                     }
1574                 }
1575                 return result;
1576             }
1577             else
1578                 return String.Empty;
1579         }
1580
1581         [System.Security.SecuritySafeCritical]  // auto-generated
1582         private String CtorCharCount(char c, int count)
1583         {
1584             if (count > 0) {
1585                 String result = FastAllocateString(count);
1586                 if (c != 0)
1587                 {
1588                     unsafe {
1589                         fixed (char *dest = result) {
1590                             char *dmem = dest;
1591                             while (((uint)dmem & 3) != 0 && count > 0) {
1592                                 *dmem++ = c;
1593                                 count--;
1594                             }
1595                             uint cc = (uint)((c << 16) | c);
1596                             if (count >= 4) {
1597                                 count -= 4;
1598                                 do{
1599                                     ((uint *)dmem)[0] = cc;
1600                                     ((uint *)dmem)[1] = cc;
1601                                     dmem += 4;
1602                                     count -= 4;
1603                                 } while (count >= 0);
1604                             }
1605                             if ((count & 2) != 0) {
1606                                 ((uint *)dmem)[0] = cc;
1607                                 dmem += 2;
1608                             }
1609                             if ((count & 1) != 0)
1610                                 dmem[0] = c;
1611                         }
1612                     }
1613                 }
1614                 return result;
1615             }
1616             else if (count == 0)
1617                 return String.Empty;
1618             else
1619                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_MustBeNonNegNum", "count"));
1620         }
1621
1622         [System.Security.SecurityCritical]  // auto-generated
1623         private static unsafe int wcslen(char *ptr)
1624         {
1625             char *end = ptr;
1626
1627             // The following code is (somewhat surprisingly!) significantly faster than a naive loop,
1628             // at least on x86 and the current jit.
1629
1630             // First make sure our pointer is aligned on a dword boundary
1631             while (((uint)end & 3) != 0 && *end != 0)
1632                 end++;
1633             if (*end != 0) {
1634                 // The loop condition below works because if "end[0] & end[1]" is non-zero, that means
1635                 // neither operand can have been zero. If is zero, we have to look at the operands individually,
1636                 // but we hope this going to fairly rare.
1637
1638                 // In general, it would be incorrect to access end[1] if we haven't made sure
1639                 // end[0] is non-zero. However, we know the ptr has been aligned by the loop above
1640                 // so end[0] and end[1] must be in the same page, so they're either both accessible, or both not.
1641
1642                 while ((end[0] & end[1]) != 0 || (end[0] != 0 && end[1] != 0)) {
1643                     end += 2;
1644                 }
1645             }
1646             // finish up with the naive loop
1647             for ( ; *end != 0; end++)
1648                 ;
1649
1650             int count = (int)(end - ptr);
1651
1652             return count;
1653         }
1654
1655         [System.Security.SecurityCritical]  // auto-generated
1656         private unsafe String CtorCharPtr(char *ptr)
1657         {
1658             if (ptr == null)
1659                 return String.Empty;
1660
1661 #if !FEATURE_PAL
1662             if (ptr < (char*)64000)
1663                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeStringPtrNotAtom"));
1664 #endif // FEATURE_PAL
1665
1666             Contract.Assert(this == null, "this == null");        // this is the string constructor, we allocate it
1667
1668             try {
1669                 int count = wcslen(ptr);
1670                 if (count == 0)
1671                     return String.Empty;
1672
1673                 String result = FastAllocateString(count);
1674                 fixed (char *dest = result)
1675                     wstrcpy(dest, ptr, count);
1676                 return result;
1677             }
1678             catch (NullReferenceException) {
1679                 throw new ArgumentOutOfRangeException("ptr", Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));
1680             }
1681         }
1682
1683         [System.Security.SecurityCritical]  // auto-generated
1684         private unsafe String CtorCharPtrStartLength(char *ptr, int startIndex, int length)
1685         {
1686             if (length < 0) {
1687                 throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
1688             }
1689
1690             if (startIndex < 0) {
1691                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
1692             }
1693             Contract.EndContractBlock();
1694             Contract.Assert(this == null, "this == null");        // this is the string constructor, we allocate it
1695
1696             char *pFrom = ptr + startIndex;
1697             if (pFrom < ptr) {
1698                 // This means that the pointer operation has had an overflow
1699                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));
1700             }
1701
1702             if (length == 0)
1703                 return String.Empty;
1704
1705             String result = FastAllocateString(length);
1706
1707             try {
1708                 fixed(char *dest = result)
1709                     wstrcpy(dest, pFrom, length);
1710                 return result;
1711             }
1712             catch (NullReferenceException) {
1713                 throw new ArgumentOutOfRangeException("ptr", Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));
1714             }
1715         }
1716
1717         [System.Security.SecuritySafeCritical]  // auto-generated
1718         [ResourceExposure(ResourceScope.None)]
1719         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1720         public extern String(char c, int count);
1721     
1722         //
1723         //
1724         // INSTANCE METHODS
1725         //
1726         //
1727     
1728         // Provides a culture-correct string comparison. StrA is compared to StrB
1729         // to determine whether it is lexicographically less, equal, or greater, and then returns
1730         // either a negative integer, 0, or a positive integer; respectively.
1731         //
1732         [Pure]
1733         public static int Compare(String strA, String strB) {
1734             return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.None);
1735         }
1736     
1737
1738         // Provides a culture-correct string comparison. strA is compared to strB
1739         // to determine whether it is lexicographically less, equal, or greater, and then a
1740         // negative integer, 0, or a positive integer is returned; respectively.
1741         // The case-sensitive option is set by ignoreCase
1742         //
1743         [Pure]
1744         public static int Compare(String strA, String strB, bool ignoreCase)
1745         {
1746             if (ignoreCase) {
1747                 return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase);
1748             }
1749             return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.None);
1750         }
1751
1752   
1753         // Provides a more flexible function for string comparision. See StringComparison 
1754         // for meaning of different comparisonType.
1755         [Pure]
1756         [System.Security.SecuritySafeCritical]  // auto-generated
1757         public static int Compare(String strA, String strB, StringComparison comparisonType) 
1758         {
1759             // Single comparison to check if comparisonType is within [CurrentCulture .. OrdinalIgnoreCase]
1760             if ((uint) (comparisonType                     - StringComparison.CurrentCulture) > 
1761                 (uint) (StringComparison.OrdinalIgnoreCase - StringComparison.CurrentCulture)) {
1762                 throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
1763             }
1764             Contract.EndContractBlock();
1765
1766             if ((Object)strA == (Object)strB) {
1767                 return 0;
1768             }
1769
1770             //they can't both be null;
1771             if (strA == null) {
1772                 return -1;
1773             }
1774             
1775             if (strB == null) {
1776                 return 1;
1777             }
1778
1779             switch (comparisonType) {
1780                 case StringComparison.CurrentCulture:
1781                     return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.None);
1782
1783                 case StringComparison.CurrentCultureIgnoreCase:
1784                     return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase);
1785
1786                 case StringComparison.InvariantCulture:
1787                     return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, strB, CompareOptions.None);
1788
1789                 case StringComparison.InvariantCultureIgnoreCase:
1790                     return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase);
1791
1792                 case StringComparison.Ordinal:
1793                     // Most common case: first character is different.
1794                     if ((strA.m_firstChar - strB.m_firstChar) != 0)
1795                     {
1796                         return strA.m_firstChar - strB.m_firstChar;
1797                     }
1798
1799                     return CompareOrdinalHelper(strA, strB);
1800
1801                 case StringComparison.OrdinalIgnoreCase:
1802                     // If both strings are ASCII strings, we can take the fast path.
1803                     if (strA.IsAscii() && strB.IsAscii()) {
1804                         return (CompareOrdinalIgnoreCaseHelper(strA, strB));
1805                     }
1806                     // Take the slow path.                
1807                     return TextInfo.CompareOrdinalIgnoreCase(strA, strB);
1808
1809                 default:
1810                     throw new NotSupportedException(Environment.GetResourceString("NotSupported_StringComparison"));
1811             }
1812         }
1813
1814
1815         // Provides a culture-correct string comparison. strA is compared to strB
1816         // to determine whether it is lexicographically less, equal, or greater, and then a
1817         // negative integer, 0, or a positive integer is returned; respectively.
1818         //
1819         [Pure]
1820         public static int Compare(String strA, String strB, CultureInfo culture, CompareOptions options) {
1821             if (culture==null) {
1822                 throw new ArgumentNullException("culture");
1823             }
1824             Contract.EndContractBlock();
1825
1826             return culture.CompareInfo.Compare(strA, strB, options);
1827         }
1828
1829
1830
1831         // Provides a culture-correct string comparison. strA is compared to strB
1832         // to determine whether it is lexicographically less, equal, or greater, and then a
1833         // negative integer, 0, or a positive integer is returned; respectively.
1834         // The case-sensitive option is set by ignoreCase, and the culture is set
1835         // by culture
1836         //
1837         [Pure]
1838         public static int Compare(String strA, String strB, bool ignoreCase, CultureInfo culture) {
1839             if (culture == null) {
1840                 throw new ArgumentNullException("culture");
1841             }
1842             Contract.EndContractBlock();
1843     
1844             if (ignoreCase) {
1845                 return culture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase);
1846             }
1847             return culture.CompareInfo.Compare(strA, strB, CompareOptions.None);
1848         }
1849
1850         // Determines whether two string regions match.  The substring of strA beginning
1851         // at indexA of length count is compared with the substring of strB
1852         // beginning at indexB of the same length.
1853         //
1854         [Pure]
1855         public static int Compare(String strA, int indexA, String strB, int indexB, int length) {
1856             int lengthA = length;
1857             int lengthB = length;
1858
1859             if (strA!=null) {
1860                 if (strA.Length - indexA < lengthA) {
1861                   lengthA = (strA.Length - indexA);
1862                 }
1863             }
1864
1865             if (strB!=null) {
1866                 if (strB.Length - indexB < lengthB) {
1867                     lengthB = (strB.Length - indexB);
1868                 }
1869             }
1870             return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None);
1871         }
1872
1873
1874         // Determines whether two string regions match.  The substring of strA beginning
1875         // at indexA of length count is compared with the substring of strB
1876         // beginning at indexB of the same length.  Case sensitivity is determined by the ignoreCase boolean.
1877         //
1878         [Pure]
1879         public static int Compare(String strA, int indexA, String strB, int indexB, int length, bool ignoreCase) {
1880             int lengthA = length;
1881             int lengthB = length;
1882
1883             if (strA!=null) {
1884                 if (strA.Length - indexA < lengthA) {
1885                   lengthA = (strA.Length - indexA);
1886                 }
1887             }
1888
1889             if (strB!=null) {
1890                 if (strB.Length - indexB < lengthB) {
1891                     lengthB = (strB.Length - indexB);
1892                 }
1893             }
1894
1895             if (ignoreCase) {
1896                 return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.IgnoreCase);
1897             }
1898             return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None);
1899         }
1900     
1901         // Determines whether two string regions match.  The substring of strA beginning
1902         // at indexA of length length is compared with the substring of strB
1903         // beginning at indexB of the same length.  Case sensitivity is determined by the ignoreCase boolean,
1904         // and the culture is set by culture.
1905         //
1906         [Pure]
1907         public static int Compare(String strA, int indexA, String strB, int indexB, int length, bool ignoreCase, CultureInfo culture) {
1908             if (culture == null) {
1909                 throw new ArgumentNullException("culture");
1910             }
1911             Contract.EndContractBlock();
1912
1913             int lengthA = length;
1914             int lengthB = length;
1915
1916             if (strA!=null) {
1917                 if (strA.Length - indexA < lengthA) {
1918                   lengthA = (strA.Length - indexA);
1919                 }
1920             }
1921
1922             if (strB!=null) {
1923                 if (strB.Length - indexB < lengthB) {
1924                     lengthB = (strB.Length - indexB);
1925                 }
1926             }
1927     
1928             if (ignoreCase) {
1929                 return culture.CompareInfo.Compare(strA,indexA,lengthA, strB, indexB, lengthB,CompareOptions.IgnoreCase);
1930             } else {
1931                 return culture.CompareInfo.Compare(strA,indexA,lengthA, strB, indexB, lengthB,CompareOptions.None);
1932             }
1933         }
1934
1935
1936         // Determines whether two string regions match.  The substring of strA beginning
1937         // at indexA of length length is compared with the substring of strB
1938         // beginning at indexB of the same length.
1939         //
1940         [Pure]
1941         public static int Compare(String strA, int indexA, String strB, int indexB, int length, CultureInfo culture, CompareOptions options) {
1942             if (culture==null) {
1943                 throw new ArgumentNullException("culture");
1944             }
1945             Contract.EndContractBlock();
1946
1947             int lengthA = length;
1948             int lengthB = length;
1949
1950             if (strA!=null) {
1951                 if (strA.Length - indexA < lengthA) {
1952                   lengthA = (strA.Length - indexA);
1953                 }
1954             }
1955
1956             if (strB!=null) {
1957                 if (strB.Length - indexB < lengthB) {
1958                     lengthB = (strB.Length - indexB);
1959                 }
1960             }
1961     
1962             return culture.CompareInfo.Compare(strA,indexA,lengthA, strB, indexB, lengthB, options);
1963         }
1964
1965         [Pure]
1966         [System.Security.SecuritySafeCritical]  // auto-generated
1967         public static int Compare(String strA, int indexA, String strB, int indexB, int length, StringComparison comparisonType) {
1968             if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase) {
1969                 throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
1970             }
1971             Contract.EndContractBlock();
1972             
1973             if (strA == null || strB == null) {
1974                  if ((Object)strA==(Object)strB) { //they're both null;
1975                      return 0;
1976                  }
1977
1978                  return (strA==null)? -1 : 1; //-1 if A is null, 1 if B is null.
1979             }    
1980             
1981             // @
1982             if (length < 0) {
1983                 throw new ArgumentOutOfRangeException("length",
1984                                                       Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
1985             }
1986
1987             if (indexA < 0) {
1988                 throw new ArgumentOutOfRangeException("indexA",
1989                                                      Environment.GetResourceString("ArgumentOutOfRange_Index"));
1990             }
1991
1992             if (indexB < 0) {
1993                 throw new ArgumentOutOfRangeException("indexB",
1994                                                      Environment.GetResourceString("ArgumentOutOfRange_Index"));
1995             }
1996
1997             if (strA.Length - indexA < 0) {
1998                 throw new ArgumentOutOfRangeException("indexA",
1999                                                       Environment.GetResourceString("ArgumentOutOfRange_Index"));
2000             }
2001
2002             if (strB.Length - indexB < 0) {
2003                 throw new ArgumentOutOfRangeException("indexB",
2004                                                       Environment.GetResourceString("ArgumentOutOfRange_Index"));
2005             }
2006             
2007             if( ( length == 0 )  ||
2008                 ((strA == strB) && (indexA == indexB)) ){
2009                 return 0;
2010             }
2011
2012             int lengthA = length;
2013             int lengthB = length;
2014
2015             if (strA!=null) {
2016                 if (strA.Length - indexA < lengthA) {
2017                   lengthA = (strA.Length - indexA);
2018                 }
2019             }
2020
2021             if (strB!=null) {
2022                 if (strB.Length - indexB < lengthB) {
2023                     lengthB = (strB.Length - indexB);
2024                 }
2025             }
2026     
2027             switch (comparisonType) {
2028                 case StringComparison.CurrentCulture:
2029                     return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None);
2030
2031                 case StringComparison.CurrentCultureIgnoreCase:
2032                     return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.IgnoreCase);
2033
2034                 case StringComparison.InvariantCulture:
2035                     return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None);
2036
2037                 case StringComparison.InvariantCultureIgnoreCase:
2038                     return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.IgnoreCase);
2039
2040                 case StringComparison.Ordinal:
2041                     // 
2042                     return nativeCompareOrdinalEx(strA, indexA, strB, indexB, length);
2043
2044                 case StringComparison.OrdinalIgnoreCase:
2045                     return (TextInfo.CompareOrdinalIgnoreCaseEx(strA, indexA, strB, indexB, lengthA, lengthB));
2046
2047                 default:
2048                     throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"));
2049             }
2050
2051         }
2052
2053         // Compares this object to another object, returning an integer that
2054         // indicates the relationship. This method returns a value less than 0 if this is less than value, 0
2055         // if this is equal to value, or a value greater than 0
2056         // if this is greater than value.  Strings are considered to be
2057         // greater than all non-String objects.  Note that this means sorted 
2058         // arrays would contain nulls, other objects, then Strings in that order.
2059         //
2060         [Pure]
2061         public int CompareTo(Object value) {
2062             if (value == null) {
2063                 return 1;
2064             }
2065
2066             if (!(value is String)) {
2067                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeString"));
2068             }
2069
2070             return String.Compare(this,(String)value, StringComparison.CurrentCulture);
2071         }
2072     
2073         // Determines the sorting relation of StrB to the current instance.
2074         //
2075         [Pure]
2076         public int CompareTo(String strB) {
2077             if (strB==null) {
2078                 return 1;
2079             }
2080
2081             return CultureInfo.CurrentCulture.CompareInfo.Compare(this, strB, 0);
2082         }
2083
2084         // Compares strA and strB using an ordinal (code-point) comparison.
2085         //
2086         [Pure]
2087         public static int CompareOrdinal(String strA, String strB) {
2088             if ((Object)strA == (Object)strB) {
2089                 return 0;
2090             }
2091
2092             //they can't both be null;
2093             if( strA == null) {
2094                 return -1;
2095             }
2096             
2097             if( strB == null) {
2098                 return 1;
2099             }
2100
2101             // Most common case, first character is different.
2102             if ((strA.m_firstChar - strB.m_firstChar) != 0)
2103             {
2104                 return strA.m_firstChar - strB.m_firstChar;
2105             }
2106
2107             // 
2108             return CompareOrdinalHelper(strA, strB);
2109         }
2110         
2111
2112         // Compares strA and strB using an ordinal (code-point) comparison.
2113         //
2114         [Pure]
2115         [System.Security.SecuritySafeCritical]  // auto-generated
2116         public static int CompareOrdinal(String strA, int indexA, String strB, int indexB, int length) {
2117            if (strA == null || strB == null) {
2118                 if ((Object)strA==(Object)strB) { //they're both null;
2119                     return 0;
2120                 }
2121
2122                 return (strA==null)? -1 : 1; //-1 if A is null, 1 if B is null.
2123             }
2124
2125             return nativeCompareOrdinalEx(strA, indexA, strB, indexB, length);
2126         }
2127
2128
2129         [Pure]
2130         public bool Contains( string value ) {
2131             return ( IndexOf(value, StringComparison.Ordinal) >=0 );
2132         }
2133
2134         // Determines whether a specified string is a suffix of the the current instance.
2135         //
2136         // The case-sensitive and culture-sensitive option is set by options,
2137         // and the default culture is used.
2138         //        
2139         [Pure]
2140         public Boolean EndsWith(String value) {
2141             return EndsWith(value, StringComparison.CurrentCulture);
2142         }
2143
2144         [Pure]
2145         [System.Security.SecuritySafeCritical]  // auto-generated
2146         [ComVisible(false)]
2147         public Boolean EndsWith(String value, StringComparison comparisonType) {
2148             if( (Object)value == null) {
2149                 throw new ArgumentNullException("value");                                
2150             }
2151
2152             if( comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase) {
2153                 throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
2154             }
2155             Contract.EndContractBlock();
2156
2157             if( (Object)this == (Object)value) {
2158                 return true;
2159             }
2160
2161             if( value.Length == 0) {
2162                 return true;
2163             }
2164             
2165             switch (comparisonType) {
2166                 case StringComparison.CurrentCulture:
2167                     return CultureInfo.CurrentCulture.CompareInfo.IsSuffix(this, value, CompareOptions.None);
2168
2169                 case StringComparison.CurrentCultureIgnoreCase:
2170                     return CultureInfo.CurrentCulture.CompareInfo.IsSuffix(this, value, CompareOptions.IgnoreCase);
2171
2172                 case StringComparison.InvariantCulture:
2173                     return CultureInfo.InvariantCulture.CompareInfo.IsSuffix(this, value, CompareOptions.None);
2174
2175                 case StringComparison.InvariantCultureIgnoreCase:
2176                     return CultureInfo.InvariantCulture.CompareInfo.IsSuffix(this, value, CompareOptions.IgnoreCase);                    
2177
2178                 case StringComparison.Ordinal:
2179                     return this.Length < value.Length ? false : (nativeCompareOrdinalEx(this, this.Length -value.Length, value, 0, value.Length) == 0);
2180
2181                 case StringComparison.OrdinalIgnoreCase:                    
2182                     return this.Length < value.Length ? false : (TextInfo.CompareOrdinalIgnoreCaseEx(this, this.Length - value.Length, value, 0, value.Length, value.Length) == 0);
2183
2184                 default:
2185                     throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
2186             }                        
2187         }
2188
2189         [Pure]
2190         public Boolean EndsWith(String value, Boolean ignoreCase, CultureInfo culture) {
2191             if (null==value) {
2192                 throw new ArgumentNullException("value");
2193             }
2194             Contract.EndContractBlock();
2195             
2196             if((object)this == (object)value) {
2197                 return true;
2198             }
2199
2200             CultureInfo referenceCulture;
2201             if (culture == null)
2202                 referenceCulture = CultureInfo.CurrentCulture;
2203             else
2204                 referenceCulture = culture;
2205
2206             return referenceCulture.CompareInfo.IsSuffix(this, value, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
2207         }
2208
2209         [Pure]
2210         internal bool EndsWith(char value) {
2211             int thisLen = this.Length;
2212             if (thisLen != 0) {
2213                 if (this[thisLen - 1] == value)
2214                     return true;
2215             }
2216             return false;
2217         }
2218     
2219     
2220         // Returns the index of the first occurance of value in the current instance.
2221         // The search starts at startIndex and runs thorough the next count characters.
2222         //
2223         [Pure]
2224         public int IndexOf(char value) {
2225             return IndexOf(value, 0, this.Length);
2226         }
2227
2228         [Pure]
2229         public int IndexOf(char value, int startIndex) {
2230             return IndexOf(value, startIndex, this.Length - startIndex);
2231         }
2232 #if !MONO
2233         [Pure]
2234         [System.Security.SecuritySafeCritical]  // auto-generated
2235         [ResourceExposure(ResourceScope.None)]
2236         [MethodImplAttribute(MethodImplOptions.InternalCall)]
2237         public extern int IndexOf(char value, int startIndex, int count);
2238 #endif
2239         // Returns the index of the first occurance of any character in value in the current instance.
2240         // The search starts at startIndex and runs to endIndex-1. [startIndex,endIndex).
2241         //
2242         [Pure]        
2243         public int IndexOfAny(char [] anyOf) {
2244             return IndexOfAny(anyOf,0, this.Length);
2245         }
2246     
2247         [Pure]
2248         public int IndexOfAny(char [] anyOf, int startIndex) {
2249             return IndexOfAny(anyOf, startIndex, this.Length - startIndex);
2250         }
2251 #if !MONO
2252         [Pure]
2253         [System.Security.SecuritySafeCritical]  // auto-generated
2254         [ResourceExposure(ResourceScope.None)]
2255         [MethodImplAttribute(MethodImplOptions.InternalCall)]
2256         public extern int IndexOfAny(char [] anyOf, int startIndex, int count);
2257 #endif
2258         
2259         // Determines the position within this string of the first occurence of the specified
2260         // string, according to the specified search criteria.  The search begins at
2261         // the first character of this string, it is case-sensitive and ordinal (code-point)
2262         // comparison is used.
2263         //
2264         [Pure]
2265         public int IndexOf(String value) {
2266             return IndexOf(value, StringComparison.CurrentCulture);
2267         }
2268
2269         // Determines the position within this string of the first occurence of the specified
2270         // string, according to the specified search criteria.  The search begins at
2271         // startIndex, it is case-sensitive and ordinal (code-point) comparison is used.
2272         //
2273         [Pure]
2274         public int IndexOf(String value, int startIndex) {
2275             return IndexOf(value, startIndex, StringComparison.CurrentCulture);
2276         }
2277
2278         // Determines the position within this string of the first occurence of the specified
2279         // string, according to the specified search criteria.  The search begins at
2280         // startIndex, ends at endIndex and ordinal (code-point) comparison is used.
2281         //
2282         [Pure]
2283         public int IndexOf(String value, int startIndex, int count) {
2284             if (startIndex < 0 || startIndex > this.Length) {
2285                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
2286             }
2287
2288             if (count < 0 || count > this.Length - startIndex) {
2289                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
2290             }
2291             Contract.EndContractBlock();
2292             
2293             return IndexOf(value, startIndex, count, StringComparison.CurrentCulture);
2294         }
2295
2296         [Pure]
2297         public int IndexOf(String value, StringComparison comparisonType) {
2298             return IndexOf(value, 0, this.Length, comparisonType);
2299         }
2300
2301         [Pure]
2302         public int IndexOf(String value, int startIndex, StringComparison comparisonType) {
2303             return IndexOf(value, startIndex, this.Length - startIndex, comparisonType);
2304         }
2305
2306         [Pure]
2307         [System.Security.SecuritySafeCritical]
2308         public int IndexOf(String value, int startIndex, int count, StringComparison comparisonType) {
2309             // Validate inputs
2310             if (value == null)
2311                 throw new ArgumentNullException("value");
2312
2313             if (startIndex < 0 || startIndex > this.Length)
2314                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
2315
2316             if (count < 0 || startIndex > this.Length - count)
2317                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
2318             Contract.EndContractBlock();
2319
2320             switch (comparisonType) {
2321                 case StringComparison.CurrentCulture:
2322                     return CultureInfo.CurrentCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.None);
2323
2324                 case StringComparison.CurrentCultureIgnoreCase:
2325                     return CultureInfo.CurrentCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
2326
2327                 case StringComparison.InvariantCulture:
2328                     return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.None);
2329
2330                 case StringComparison.InvariantCultureIgnoreCase:
2331                     return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
2332
2333                 case StringComparison.Ordinal:
2334                     return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.Ordinal);
2335
2336                 case StringComparison.OrdinalIgnoreCase:
2337                     if (value.IsAscii() && this.IsAscii())
2338                         return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
2339                     else
2340                         return TextInfo.IndexOfStringOrdinalIgnoreCase(this, value, startIndex, count);
2341
2342                 default:
2343                     throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
2344             }  
2345         }
2346
2347         // Returns the index of the last occurance of value in the current instance.
2348         // The search starts at startIndex and runs to endIndex. [startIndex,endIndex].
2349         // The character at position startIndex is included in the search.  startIndex is the larger
2350         // index within the string.
2351         //
2352         [Pure]
2353         public int LastIndexOf(char value) {
2354             return LastIndexOf(value, this.Length-1, this.Length);
2355         }
2356
2357         [Pure]
2358         public int LastIndexOf(char value, int startIndex){
2359             return LastIndexOf(value,startIndex,startIndex + 1);
2360         }
2361 #if !MONO
2362         [Pure]
2363         [System.Security.SecuritySafeCritical]  // auto-generated
2364         [ResourceExposure(ResourceScope.None)]
2365         [MethodImplAttribute(MethodImplOptions.InternalCall)]
2366         public extern int LastIndexOf(char value, int startIndex, int count);
2367 #endif
2368         // Returns the index of the last occurance of any character in value in the current instance.
2369         // The search starts at startIndex and runs to endIndex. [startIndex,endIndex].
2370         // The character at position startIndex is included in the search.  startIndex is the larger
2371         // index within the string.
2372         //
2373         
2374         //ForceInline ... Jit can't recognize String.get_Length to determine that this is "fluff"
2375         [Pure]
2376         public int LastIndexOfAny(char [] anyOf) {
2377             return LastIndexOfAny(anyOf,this.Length-1,this.Length);
2378         }
2379     
2380         //ForceInline ... Jit can't recognize String.get_Length to determine that this is "fluff"
2381         [Pure]
2382         public int LastIndexOfAny(char [] anyOf, int startIndex) {
2383             return LastIndexOfAny(anyOf,startIndex,startIndex + 1);
2384         }
2385 #if !MONO
2386         [Pure]
2387         [System.Security.SecuritySafeCritical]  // auto-generated
2388         [ResourceExposure(ResourceScope.None)]
2389         [MethodImplAttribute(MethodImplOptions.InternalCall)]
2390         public extern int LastIndexOfAny(char [] anyOf, int startIndex, int count);
2391 #endif
2392     
2393         // Returns the index of the last occurance of any character in value in the current instance.
2394         // The search starts at startIndex and runs to endIndex. [startIndex,endIndex].
2395         // The character at position startIndex is included in the search.  startIndex is the larger
2396         // index within the string.
2397         //
2398         [Pure]
2399         public int LastIndexOf(String value) {
2400             return LastIndexOf(value, this.Length-1,this.Length, StringComparison.CurrentCulture);
2401         }
2402
2403         [Pure]
2404         public int LastIndexOf(String value, int startIndex) {
2405             return LastIndexOf(value, startIndex, startIndex + 1, StringComparison.CurrentCulture);
2406         }
2407
2408         [Pure]
2409         public int LastIndexOf(String value, int startIndex, int count) {
2410             if (count<0) {
2411                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
2412             }
2413             Contract.EndContractBlock();
2414
2415             return LastIndexOf(value, startIndex, count, StringComparison.CurrentCulture);
2416         }
2417
2418         [Pure]
2419         public int LastIndexOf(String value, StringComparison comparisonType) {
2420             return LastIndexOf(value, this.Length-1, this.Length, comparisonType);
2421         }
2422
2423         [Pure]
2424         public int LastIndexOf(String value, int startIndex, StringComparison comparisonType) {
2425             return LastIndexOf(value, startIndex, startIndex + 1, comparisonType);
2426         }
2427
2428         [Pure]
2429         [System.Security.SecuritySafeCritical]
2430         public int LastIndexOf(String value, int startIndex, int count, StringComparison comparisonType) {
2431             if (value == null)
2432                 throw new ArgumentNullException("value");
2433             Contract.EndContractBlock();
2434
2435             // Special case for 0 length input strings
2436             if (this.Length == 0 && (startIndex == -1 || startIndex == 0))
2437                 return (value.Length == 0) ? 0 : -1;
2438
2439             // Now after handling empty strings, make sure we're not out of range
2440             if (startIndex < 0 || startIndex > this.Length)
2441                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
2442             
2443             // Make sure that we allow startIndex == this.Length
2444             if (startIndex == this.Length)
2445             {
2446                 startIndex--;
2447                 if (count > 0)
2448                     count--;
2449
2450                 // If we are looking for nothing, just return 0
2451                 if (value.Length == 0 && count >= 0 && startIndex - count + 1 >= 0)
2452                     return startIndex;
2453             }
2454
2455             // 2nd half of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0.
2456             if (count < 0 || startIndex - count + 1 < 0)
2457                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
2458
2459
2460             switch (comparisonType) {
2461                 case StringComparison.CurrentCulture:
2462                     return CultureInfo.CurrentCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.None);
2463
2464                 case StringComparison.CurrentCultureIgnoreCase:
2465                     return CultureInfo.CurrentCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
2466
2467                 case StringComparison.InvariantCulture:
2468                     return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.None);
2469
2470                 case StringComparison.InvariantCultureIgnoreCase:
2471                     return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
2472                 case StringComparison.Ordinal:
2473                     return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.Ordinal);
2474                      
2475                 case StringComparison.OrdinalIgnoreCase:
2476                     if (value.IsAscii() && this.IsAscii())
2477                         return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
2478                     else
2479                         return TextInfo.LastIndexOfStringOrdinalIgnoreCase(this, value, startIndex, count);
2480                 default:
2481                     throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
2482             }  
2483         }
2484         
2485         //
2486         //
2487         [Pure]
2488         public String PadLeft(int totalWidth) {
2489             return PadHelper(totalWidth, ' ', false);
2490         }
2491
2492         [Pure]
2493         public String PadLeft(int totalWidth, char paddingChar) {
2494             return PadHelper(totalWidth, paddingChar, false);
2495         }
2496
2497         [Pure]
2498         public String PadRight(int totalWidth) {
2499             return PadHelper(totalWidth, ' ', true);
2500         }
2501
2502         [Pure]
2503         public String PadRight(int totalWidth, char paddingChar) {
2504             return PadHelper(totalWidth, paddingChar, true);
2505         }
2506     
2507 #if !MONO
2508         [System.Security.SecuritySafeCritical]  // auto-generated
2509         [ResourceExposure(ResourceScope.None)]
2510         [MethodImplAttribute(MethodImplOptions.InternalCall)]
2511         private extern String PadHelper(int totalWidth, char paddingChar, bool isRightPadded);
2512 #endif
2513         // Determines whether a specified string is a prefix of the current instance
2514         //
2515         [Pure]
2516         public Boolean StartsWith(String value) {
2517             if ((Object)value == null) {
2518                 throw new ArgumentNullException("value");
2519             }
2520             Contract.EndContractBlock();
2521             return StartsWith(value, StringComparison.CurrentCulture);
2522         }
2523
2524         [Pure]
2525         [System.Security.SecuritySafeCritical]  // auto-generated
2526         [ComVisible(false)]
2527         public Boolean StartsWith(String value, StringComparison comparisonType) {
2528             if( (Object)value == null) {
2529                 throw new ArgumentNullException("value");                                
2530             }
2531
2532             if( comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase) {
2533                 throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
2534             }
2535             Contract.EndContractBlock();
2536
2537             if( (Object)this == (Object)value) {
2538                 return true;
2539             }
2540
2541             if( value.Length == 0) {
2542                 return true;
2543             }
2544
2545             switch (comparisonType) {
2546                 case StringComparison.CurrentCulture:
2547                     return CultureInfo.CurrentCulture.CompareInfo.IsPrefix(this, value, CompareOptions.None);
2548
2549                 case StringComparison.CurrentCultureIgnoreCase:
2550                     return CultureInfo.CurrentCulture.CompareInfo.IsPrefix(this, value, CompareOptions.IgnoreCase);
2551
2552                 case StringComparison.InvariantCulture:
2553                     return CultureInfo.InvariantCulture.CompareInfo.IsPrefix(this, value, CompareOptions.None);
2554
2555                 case StringComparison.InvariantCultureIgnoreCase:
2556                     return CultureInfo.InvariantCulture.CompareInfo.IsPrefix(this, value, CompareOptions.IgnoreCase);                    
2557
2558                 case StringComparison.Ordinal:
2559                     if( this.Length < value.Length) {
2560                         return false;
2561                     }
2562                     return (nativeCompareOrdinalEx(this, 0, value, 0, value.Length) == 0);
2563
2564                 case StringComparison.OrdinalIgnoreCase:
2565                     if( this.Length < value.Length) {
2566                         return false;
2567                     }
2568                     
2569                     return (TextInfo.CompareOrdinalIgnoreCaseEx(this, 0, value, 0, value.Length, value.Length) == 0);
2570
2571                 default:
2572                     throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
2573             }                        
2574         }
2575
2576         [Pure]
2577         public Boolean StartsWith(String value, Boolean ignoreCase, CultureInfo culture) {
2578             if (null==value) {
2579                 throw new ArgumentNullException("value");
2580             }
2581             Contract.EndContractBlock();
2582
2583             if((object)this == (object)value) {
2584                 return true;
2585             }
2586
2587             CultureInfo referenceCulture;
2588             if (culture == null)
2589                 referenceCulture = CultureInfo.CurrentCulture;
2590             else
2591                 referenceCulture = culture;
2592
2593             return referenceCulture.CompareInfo.IsPrefix(this, value, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
2594         }
2595   
2596         // Creates a copy of this string in lower case.
2597         [Pure]
2598         public String ToLower() {
2599             Contract.Ensures(Contract.Result<String>() != null);
2600             Contract.EndContractBlock();
2601             return this.ToLower(CultureInfo.CurrentCulture);
2602         }
2603     
2604         // Creates a copy of this string in lower case.  The culture is set by culture.
2605         [Pure]
2606         public String ToLower(CultureInfo culture) {
2607             if (culture==null) {
2608                 throw new ArgumentNullException("culture");
2609             }
2610             Contract.Ensures(Contract.Result<String>() != null);
2611             Contract.EndContractBlock();
2612             return culture.TextInfo.ToLower(this);
2613         }
2614
2615         // Creates a copy of this string in lower case based on invariant culture.
2616         [Pure]
2617         public String ToLowerInvariant() {
2618             Contract.Ensures(Contract.Result<String>() != null);
2619             Contract.EndContractBlock();
2620             return this.ToLower(CultureInfo.InvariantCulture);
2621         }
2622     
2623         // Creates a copy of this string in upper case.
2624         [Pure]
2625         public String ToUpper() {
2626             Contract.Ensures(Contract.Result<String>() != null);
2627             Contract.EndContractBlock();
2628             return this.ToUpper(CultureInfo.CurrentCulture);
2629         }
2630    
2631
2632         // Creates a copy of this string in upper case.  The culture is set by culture.
2633         [Pure]
2634         public String ToUpper(CultureInfo culture) {
2635             if (culture==null) {
2636                 throw new ArgumentNullException("culture");
2637             }
2638             Contract.Ensures(Contract.Result<String>() != null);
2639             Contract.EndContractBlock();
2640             return culture.TextInfo.ToUpper(this);
2641         }
2642
2643
2644         //Creates a copy of this string in upper case based on invariant culture.
2645         [Pure]
2646         public String ToUpperInvariant() {
2647             Contract.Ensures(Contract.Result<String>() != null);
2648             Contract.EndContractBlock();
2649             return this.ToUpper(CultureInfo.InvariantCulture);
2650         }
2651
2652    
2653         // Returns this string.
2654         public override String ToString() {
2655             Contract.Ensures(Contract.Result<String>() != null);
2656             Contract.EndContractBlock();
2657             return this;
2658         }
2659
2660         public String ToString(IFormatProvider provider) {
2661             Contract.Ensures(Contract.Result<String>() != null);
2662             Contract.EndContractBlock();
2663             return this;
2664         }
2665     
2666         // Method required for the ICloneable interface.
2667         // There's no point in cloning a string since they're immutable, so we simply return this.
2668         public Object Clone() {
2669             Contract.Ensures(Contract.Result<Object>() != null);
2670             Contract.EndContractBlock();
2671             return this;
2672         }
2673     
2674         private static bool IsBOMWhitespace(char c)
2675         {
2676 #if FEATURE_LEGACYNETCF
2677             if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8 && c == '\xFEFF')
2678             {
2679                 // Dev11 450846 quirk:
2680                 // NetCF treats the BOM as a whitespace character when performing trim operations.
2681                 return true;
2682             }
2683             else
2684 #endif
2685             {
2686                 return false;
2687             }
2688         }
2689
2690         // Trims the whitespace from both ends of the string.  Whitespace is defined by
2691         // Char.IsWhiteSpace.
2692         //
2693         [Pure]
2694         public String Trim() {
2695             Contract.Ensures(Contract.Result<String>() != null);
2696             Contract.EndContractBlock();
2697
2698             return TrimHelper(TrimBoth);        
2699         }
2700
2701        
2702         [System.Security.SecuritySafeCritical]  // auto-generated
2703         private String TrimHelper(int trimType) {
2704             //end will point to the first non-trimmed character on the right
2705             //start will point to the first non-trimmed character on the Left
2706             int end = this.Length-1;
2707             int start=0;
2708
2709             //Trim specified characters.
2710             if (trimType !=TrimTail)  {
2711                 for (start=0; start < this.Length; start++) {
2712                     if (!Char.IsWhiteSpace(this[start]) && !IsBOMWhitespace(this[start])) break;
2713                 }
2714             }
2715             
2716             if (trimType !=TrimHead) {
2717                 for (end= Length -1; end >= start;  end--) {
2718                     if (!Char.IsWhiteSpace(this[end])  && !IsBOMWhitespace(this[start])) break;
2719                 }
2720             }
2721
2722             return CreateTrimmedString(start, end);
2723         }
2724     
2725     
2726         [System.Security.SecuritySafeCritical]  // auto-generated
2727         private String TrimHelper(char[] trimChars, int trimType) {
2728             //end will point to the first non-trimmed character on the right
2729             //start will point to the first non-trimmed character on the Left
2730             int end = this.Length-1;
2731             int start=0;
2732
2733             //Trim specified characters.
2734             if (trimType !=TrimTail)  {
2735                 for (start=0; start < this.Length; start++) {
2736                     int i = 0;
2737                     char ch = this[start];
2738                     for( i = 0; i < trimChars.Length; i++) {
2739                         if( trimChars[i] == ch) break;
2740                     }
2741                     if( i == trimChars.Length) { // the character is not white space
2742                         break;  
2743                     }
2744                 }
2745             }
2746             
2747             if (trimType !=TrimHead) {
2748                 for (end= Length -1; end >= start;  end--) {
2749                     int i = 0;    
2750                     char ch = this[end];                    
2751                     for(i = 0; i < trimChars.Length; i++) {
2752                         if( trimChars[i] == ch) break;
2753                     }
2754                     if( i == trimChars.Length) { // the character is not white space
2755                         break;  
2756                     }                    
2757                 }
2758             }
2759
2760             return CreateTrimmedString(start, end);
2761         }
2762
2763
2764         [System.Security.SecurityCritical]  // auto-generated
2765         private String CreateTrimmedString(int start, int end) {
2766             //Create a new STRINGREF and initialize it from the range determined above.
2767             int len = end -start + 1;
2768             if (len == this.Length) {
2769                 // Don't allocate a new string as the trimmed string has not changed.
2770                 return this;
2771             }
2772
2773             if( len == 0) {
2774                 return String.Empty;
2775             }
2776             return InternalSubString(start, len);
2777         }
2778     
2779         [System.Security.SecuritySafeCritical]  // auto-generated
2780         public String Insert(int startIndex, String value)
2781         {
2782             if (value == null)
2783                 throw new ArgumentNullException("value");
2784             if (startIndex < 0 || startIndex > this.Length)
2785                 throw new ArgumentOutOfRangeException("startIndex");
2786             Contract.Ensures(Contract.Result<String>() != null);
2787             Contract.Ensures(Contract.Result<String>().Length == this.Length + value.Length);
2788             Contract.EndContractBlock();
2789             int oldLength = Length;
2790             int insertLength = value.Length;
2791             // In case this computation overflows, newLength will be negative and FastAllocateString throws OutOfMemoryException
2792             int newLength = oldLength + insertLength;
2793             if (newLength == 0)
2794                 return String.Empty;
2795             String result = FastAllocateString(newLength);
2796             unsafe
2797             {
2798                 fixed (char* srcThis = &m_firstChar)
2799                 {
2800                     fixed (char* srcInsert = &value.m_firstChar)
2801                     {
2802                         fixed (char* dst = &result.m_firstChar)
2803                         {
2804                             wstrcpy(dst, srcThis, startIndex);
2805                             wstrcpy(dst + startIndex, srcInsert, insertLength);
2806                             wstrcpy(dst + startIndex + insertLength, srcThis + startIndex, oldLength - startIndex);
2807                         }
2808                     }
2809                 }
2810             }
2811             return result;
2812         }
2813 #if !MONO
2814         // Replaces all instances of oldChar with newChar.
2815         //
2816         [System.Security.SecuritySafeCritical]  // auto-generated
2817         [ResourceExposure(ResourceScope.None)]
2818         [MethodImplAttribute(MethodImplOptions.InternalCall)]
2819         private extern String ReplaceInternal(char oldChar, char newChar);
2820 #endif
2821         public String Replace(char oldChar, char newChar)
2822         {
2823             Contract.Ensures(Contract.Result<String>() != null);
2824             Contract.Ensures(Contract.Result<String>().Length == this.Length);
2825             Contract.EndContractBlock();
2826
2827             return ReplaceInternal(oldChar, newChar);
2828         }
2829 #if !MONO
2830         // This method contains the same functionality as StringBuilder Replace. The only difference is that
2831         // a new String has to be allocated since Strings are immutable
2832         [System.Security.SecuritySafeCritical]  // auto-generated
2833         [ResourceExposure(ResourceScope.None)]
2834         [MethodImplAttribute(MethodImplOptions.InternalCall)]
2835         private extern String ReplaceInternal(String oldValue, String newValue);
2836 #endif
2837         public String Replace(String oldValue, String newValue)
2838         {
2839             if (oldValue == null)
2840                 throw new ArgumentNullException("oldValue");
2841             // Note that if newValue is null, we treat it like String.Empty.
2842             Contract.Ensures(Contract.Result<String>() != null);
2843             Contract.EndContractBlock();
2844
2845             string s = ReplaceInternal(oldValue, newValue);
2846 #if FEATURE_LEGACYNETCF
2847             if (CompatibilitySwitches.IsAppEarlierThanWindowsPhoneMango)
2848             {
2849                 // Dev11 453753 quirk
2850                 // for pre-Mango this function had a bug that would cause it to
2851                 // drop all characters to the right of the first embedded NULL.
2852                 // this was quirked on Mango for pre-Mango apps however for apps
2853                 // targeting Mango the bug was fixed.
2854                 int i = s.IndexOf('\0');
2855                 if (i > 0)
2856                     return s.Substring(0, i);
2857                 else
2858                     return s;
2859             }
2860             else
2861 #endif
2862             {
2863                 return s;
2864             }
2865         }
2866
2867         [System.Security.SecuritySafeCritical]  // auto-generated
2868         public String Remove(int startIndex, int count)
2869         {
2870             if (startIndex < 0)
2871                 throw new ArgumentOutOfRangeException("startIndex", 
2872                     Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
2873             if (count < 0)
2874                 throw new ArgumentOutOfRangeException("count", 
2875                     Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
2876             if (count > Length - startIndex)
2877                 throw new ArgumentOutOfRangeException("count", 
2878                     Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
2879             Contract.Ensures(Contract.Result<String>() != null);
2880             Contract.Ensures(Contract.Result<String>().Length == this.Length - count);
2881             Contract.EndContractBlock();
2882             int newLength = Length - count;
2883             if (newLength == 0)
2884                 return String.Empty;
2885             String result = FastAllocateString(newLength);
2886             unsafe
2887             {
2888                 fixed (char* src = &m_firstChar)
2889                 {
2890                     fixed (char* dst = &result.m_firstChar)
2891                     {
2892                         wstrcpy(dst, src, startIndex);
2893                         wstrcpy(dst + startIndex, src + startIndex + count, newLength - startIndex);
2894                     }
2895                 }
2896             }
2897             return result;
2898         }
2899
2900         // a remove that just takes a startindex. 
2901         public string Remove( int startIndex ) {
2902             if (startIndex < 0) {
2903                 throw new ArgumentOutOfRangeException("startIndex", 
2904                         Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
2905             }
2906             
2907             if (startIndex >= Length) {
2908                 throw new ArgumentOutOfRangeException("startIndex", 
2909                         Environment.GetResourceString("ArgumentOutOfRange_StartIndexLessThanLength"));                
2910             }
2911             
2912             Contract.Ensures(Contract.Result<String>() != null);
2913             Contract.EndContractBlock();
2914
2915             return Substring(0, startIndex);
2916         }   
2917     
2918         public static String Format(String format, Object arg0) {
2919             Contract.Ensures(Contract.Result<String>() != null);
2920             return FormatHelper(null, format, new ParamsArray(arg0));
2921         }
2922     
2923         public static String Format(String format, Object arg0, Object arg1) {
2924             Contract.Ensures(Contract.Result<String>() != null);
2925             return FormatHelper(null, format, new ParamsArray(arg0, arg1));
2926         }
2927     
2928         public static String Format(String format, Object arg0, Object arg1, Object arg2) {
2929             Contract.Ensures(Contract.Result<String>() != null);
2930             return FormatHelper(null, format, new ParamsArray(arg0, arg1, arg2));
2931         }
2932
2933         public static String Format(String format, params Object[] args) {
2934             if (args == null)
2935             {
2936                 // To preserve the original exception behavior, throw an exception about format if both
2937                 // args and format are null. The actual null check for format is in FormatHelper.
2938                 throw new ArgumentNullException((format == null) ? "format" : "args");
2939             }
2940             Contract.Ensures(Contract.Result<String>() != null);
2941             Contract.EndContractBlock();
2942             
2943             return FormatHelper(null, format, new ParamsArray(args));
2944         }
2945         
2946         public static String Format(IFormatProvider provider, String format, Object arg0) {
2947             Contract.Ensures(Contract.Result<String>() != null);
2948             return FormatHelper(provider, format, new ParamsArray(arg0));
2949         }
2950     
2951         public static String Format(IFormatProvider provider, String format, Object arg0, Object arg1) {
2952             Contract.Ensures(Contract.Result<String>() != null);
2953             return FormatHelper(provider, format, new ParamsArray(arg0, arg1));
2954         }
2955     
2956         public static String Format(IFormatProvider provider, String format, Object arg0, Object arg1, Object arg2) {
2957             Contract.Ensures(Contract.Result<String>() != null);
2958             return FormatHelper(provider, format, new ParamsArray(arg0, arg1, arg2));
2959         }
2960
2961         public static String Format(IFormatProvider provider, String format, params Object[] args) {
2962             if (args == null)
2963             {
2964                 // To preserve the original exception behavior, throw an exception about format if both
2965                 // args and format are null. The actual null check for format is in FormatHelper.
2966                 throw new ArgumentNullException((format == null) ? "format" : "args");
2967             }
2968             Contract.Ensures(Contract.Result<String>() != null);
2969             Contract.EndContractBlock();
2970             
2971             return FormatHelper(provider, format, new ParamsArray(args));
2972         }
2973         
2974         private static String FormatHelper(IFormatProvider provider, String format, ParamsArray args) {
2975             if (format == null)
2976                 throw new ArgumentNullException("format");
2977             
2978             return StringBuilderCache.GetStringAndRelease(
2979                 StringBuilderCache
2980                     .Acquire(format.Length + args.Length * 8)
2981                     .AppendFormatHelper(provider, format, args));
2982         }
2983     
2984         [System.Security.SecuritySafeCritical]  // auto-generated
2985         unsafe public static String Copy (String str) {
2986             if (str==null) {
2987                 throw new ArgumentNullException("str");
2988             }
2989             Contract.Ensures(Contract.Result<String>() != null);
2990             Contract.EndContractBlock();
2991
2992             int length = str.Length;
2993
2994             String result = FastAllocateString(length);
2995
2996             fixed(char* dest = &result.m_firstChar)
2997                 fixed(char* src = &str.m_firstChar) {
2998                      wstrcpy(dest, src, length);
2999                 }
3000              return result;
3001         }
3002
3003         public static String Concat(Object arg0) {
3004             Contract.Ensures(Contract.Result<String>() != null);
3005             Contract.EndContractBlock();
3006
3007             if (arg0 == null)
3008             {
3009                 return String.Empty;
3010             }
3011             return arg0.ToString();
3012         }
3013     
3014         public static String Concat(Object arg0, Object arg1) {
3015             Contract.Ensures(Contract.Result<String>() != null);
3016             Contract.EndContractBlock();
3017
3018             if (arg0 == null)
3019             {
3020                 arg0 = String.Empty;
3021             }
3022     
3023             if (arg1==null) {
3024                 arg1 = String.Empty;
3025             }
3026             return Concat(arg0.ToString(), arg1.ToString());
3027         }
3028     
3029         public static String Concat(Object arg0, Object arg1, Object arg2) {
3030             Contract.Ensures(Contract.Result<String>() != null);
3031             Contract.EndContractBlock();
3032
3033             if (arg0 == null)
3034             {
3035                 arg0 = String.Empty;
3036             }
3037     
3038             if (arg1==null) {
3039                 arg1 = String.Empty;
3040             }
3041     
3042             if (arg2==null) {
3043                 arg2 = String.Empty;
3044             }
3045     
3046             return Concat(arg0.ToString(), arg1.ToString(), arg2.ToString());
3047         }
3048
3049         [CLSCompliant(false)] 
3050         public static String Concat(Object arg0, Object arg1, Object arg2, Object arg3, __arglist) 
3051         {
3052             Contract.Ensures(Contract.Result<String>() != null);
3053             Contract.EndContractBlock();
3054
3055             Object[]   objArgs;
3056             int        argCount;
3057             
3058             ArgIterator args = new ArgIterator(__arglist);
3059
3060             //+4 to account for the 4 hard-coded arguments at the beginning of the list.
3061             argCount = args.GetRemainingCount() + 4;
3062     
3063             objArgs = new Object[argCount];
3064             
3065             //Handle the hard-coded arguments
3066             objArgs[0] = arg0;
3067             objArgs[1] = arg1;
3068             objArgs[2] = arg2;
3069             objArgs[3] = arg3;
3070             
3071             //Walk all of the args in the variable part of the argument list.
3072             for (int i=4; i<argCount; i++) {
3073                 objArgs[i] = TypedReference.ToObject(args.GetNextArg());
3074             }
3075
3076             return Concat(objArgs);
3077         }
3078
3079         public static String Concat(params Object[] args) {
3080             if (args==null) {
3081                 throw new ArgumentNullException("args");
3082             }
3083             Contract.Ensures(Contract.Result<String>() != null);
3084             Contract.EndContractBlock();
3085     
3086             String[] sArgs = new String[args.Length];
3087             int totalLength=0;
3088             
3089             for (int i=0; i<args.Length; i++) {
3090                 object value = args[i];
3091                 sArgs[i] = ((value==null)?(String.Empty):(value.ToString()));
3092                 if (sArgs[i] == null) sArgs[i] = String.Empty; // value.ToString() above could have returned null
3093                 totalLength += sArgs[i].Length;
3094                 // check for overflow
3095                 if (totalLength < 0) {
3096                     throw new OutOfMemoryException();
3097                 }
3098             }
3099             return ConcatArray(sArgs, totalLength);
3100         }
3101
3102         [ComVisible(false)]
3103         public static String Concat<T>(IEnumerable<T> values) {
3104             if (values == null)
3105                 throw new ArgumentNullException("values");
3106             Contract.Ensures(Contract.Result<String>() != null);
3107             Contract.EndContractBlock();
3108
3109             StringBuilder result = StringBuilderCache.Acquire();
3110             using(IEnumerator<T> en = values.GetEnumerator()) {
3111                 while (en.MoveNext()) {
3112                     if (en.Current != null) {
3113                         // handle the case that the enumeration has null entries
3114                         // and the case where their ToString() override is broken
3115                         string value = en.Current.ToString();
3116                         if (value != null)
3117                             result.Append(value);
3118                     }
3119                 }            
3120             }
3121             return StringBuilderCache.GetStringAndRelease(result);
3122         }
3123
3124
3125         [ComVisible(false)]
3126         public static String Concat(IEnumerable<String> values) {
3127             if (values == null)
3128                 throw new ArgumentNullException("values");
3129             Contract.Ensures(Contract.Result<String>() != null);
3130             Contract.EndContractBlock();
3131
3132             StringBuilder result = StringBuilderCache.Acquire();
3133             using(IEnumerator<String> en = values.GetEnumerator()) {
3134                 while (en.MoveNext()) {
3135                     if (en.Current != null) {
3136                         result.Append(en.Current);
3137                     }
3138                 }            
3139             }
3140             return StringBuilderCache.GetStringAndRelease(result);            
3141         }
3142
3143
3144         [System.Security.SecuritySafeCritical]  // auto-generated
3145         public static String Concat(String str0, String str1) {
3146             Contract.Ensures(Contract.Result<String>() != null);
3147             Contract.Ensures(Contract.Result<String>().Length ==
3148                 (str0 == null ? 0 : str0.Length) +
3149                 (str1 == null ? 0 : str1.Length));
3150             Contract.EndContractBlock();
3151
3152             if (IsNullOrEmpty(str0)) {
3153                 if (IsNullOrEmpty(str1)) {
3154                     return String.Empty;
3155                 }
3156                 return str1;
3157             }
3158
3159             if (IsNullOrEmpty(str1)) {
3160                 return str0;
3161             }
3162
3163             int str0Length = str0.Length;
3164             
3165             String result = FastAllocateString(str0Length + str1.Length);
3166             
3167             FillStringChecked(result, 0,        str0);
3168             FillStringChecked(result, str0Length, str1);
3169             
3170             return result;
3171         }
3172
3173         [System.Security.SecuritySafeCritical]  // auto-generated
3174         public static String Concat(String str0, String str1, String str2) {
3175             Contract.Ensures(Contract.Result<String>() != null);
3176             Contract.Ensures(Contract.Result<String>().Length ==
3177                 (str0 == null ? 0 : str0.Length) +
3178                 (str1 == null ? 0 : str1.Length) +
3179                 (str2 == null ? 0 : str2.Length));
3180             Contract.EndContractBlock();
3181
3182             if (str0==null && str1==null && str2==null) {
3183                 return String.Empty;
3184             }
3185
3186             if (str0==null) {
3187                 str0 = String.Empty;
3188             }
3189
3190             if (str1==null) {
3191                 str1 = String.Empty;
3192             }
3193
3194             if (str2 == null) {
3195                 str2 = String.Empty;
3196             }
3197
3198             int totalLength = str0.Length + str1.Length + str2.Length;
3199
3200             String result = FastAllocateString(totalLength);
3201             FillStringChecked(result, 0, str0);
3202             FillStringChecked(result, str0.Length, str1);
3203             FillStringChecked(result, str0.Length + str1.Length, str2);
3204
3205             return result;
3206         }
3207
3208         [System.Security.SecuritySafeCritical]  // auto-generated
3209         public static String Concat(String str0, String str1, String str2, String str3) {
3210             Contract.Ensures(Contract.Result<String>() != null);
3211             Contract.Ensures(Contract.Result<String>().Length == 
3212                 (str0 == null ? 0 : str0.Length) +
3213                 (str1 == null ? 0 : str1.Length) +
3214                 (str2 == null ? 0 : str2.Length) +
3215                 (str3 == null ? 0 : str3.Length));
3216             Contract.EndContractBlock();
3217
3218             if (str0==null && str1==null && str2==null && str3==null) {
3219                 return String.Empty;
3220             }
3221
3222             if (str0==null) {
3223                 str0 = String.Empty;
3224             }
3225
3226             if (str1==null) {
3227                 str1 = String.Empty;
3228             }
3229
3230             if (str2 == null) {
3231                 str2 = String.Empty;
3232             }
3233             
3234             if (str3 == null) {
3235                 str3 = String.Empty;
3236             }
3237
3238             int totalLength = str0.Length + str1.Length + str2.Length + str3.Length;
3239
3240             String result = FastAllocateString(totalLength);
3241             FillStringChecked(result, 0, str0);
3242             FillStringChecked(result, str0.Length, str1);
3243             FillStringChecked(result, str0.Length + str1.Length, str2);
3244             FillStringChecked(result, str0.Length + str1.Length + str2.Length, str3);
3245
3246             return result;
3247         }
3248
3249         [System.Security.SecuritySafeCritical]  // auto-generated
3250         private static String ConcatArray(String[] values, int totalLength) {
3251             String result =  FastAllocateString(totalLength);
3252             int currPos=0;
3253
3254             for (int i=0; i<values.Length; i++) {
3255                 Contract.Assert((currPos <= totalLength - values[i].Length), 
3256                                 "[String.ConcatArray](currPos <= totalLength - values[i].Length)");
3257
3258                 FillStringChecked(result, currPos, values[i]);
3259                 currPos+=values[i].Length;
3260             }
3261
3262             return result;
3263         }
3264
3265         public static String Concat(params String[] values) {
3266             if (values == null)
3267                 throw new ArgumentNullException("values");
3268             Contract.Ensures(Contract.Result<String>() != null);
3269             // Spec#: Consider a postcondition saying the length of this string == the sum of each string in array
3270             Contract.EndContractBlock();
3271             int totalLength=0;
3272
3273             // Always make a copy to prevent changing the array on another thread.
3274             String[] internalValues = new String[values.Length];
3275             
3276             for (int i=0; i<values.Length; i++) {
3277                 string value = values[i];
3278                 internalValues[i] = ((value==null)?(String.Empty):(value));
3279                 totalLength += internalValues[i].Length;
3280                 // check for overflow
3281                 if (totalLength < 0) {
3282                     throw new OutOfMemoryException();
3283                 }
3284             }
3285             
3286             return ConcatArray(internalValues, totalLength);
3287         }
3288         
3289         [System.Security.SecuritySafeCritical]  // auto-generated
3290         public static String Intern(String str) {
3291             if (str==null) {
3292                 throw new ArgumentNullException("str");
3293             }
3294             Contract.Ensures(Contract.Result<String>().Length == str.Length);
3295             Contract.Ensures(str.Equals(Contract.Result<String>()));
3296             Contract.EndContractBlock();
3297
3298 #if MONO
3299             return InternalIntern (str);
3300 #else
3301             return Thread.GetDomain().GetOrInternString(str);
3302 #endif
3303         }
3304
3305         [Pure]
3306         [System.Security.SecuritySafeCritical]  // auto-generated
3307         public static String IsInterned(String str) {
3308             if (str==null) {
3309                 throw new ArgumentNullException("str");
3310             }
3311             Contract.Ensures(Contract.Result<String>() == null || Contract.Result<String>().Length == str.Length);
3312             Contract.EndContractBlock();
3313
3314 #if MONO
3315             return InternalIsInterned (str);
3316 #else
3317             return Thread.GetDomain().IsStringInterned(str);
3318 #endif
3319         }
3320
3321
3322         //
3323         // IConvertible implementation
3324         // 
3325       
3326         public TypeCode GetTypeCode() {
3327             return TypeCode.String;
3328         }
3329
3330         /// <internalonly/>
3331         bool IConvertible.ToBoolean(IFormatProvider provider) {
3332             return Convert.ToBoolean(this, provider);
3333         }
3334
3335         /// <internalonly/>
3336         char IConvertible.ToChar(IFormatProvider provider) {
3337             return Convert.ToChar(this, provider);
3338         }
3339
3340         /// <internalonly/>
3341         sbyte IConvertible.ToSByte(IFormatProvider provider) {
3342             return Convert.ToSByte(this, provider);
3343         }
3344
3345         /// <internalonly/>
3346         byte IConvertible.ToByte(IFormatProvider provider) {
3347             return Convert.ToByte(this, provider);
3348         }
3349
3350         /// <internalonly/>
3351         short IConvertible.ToInt16(IFormatProvider provider) {
3352             return Convert.ToInt16(this, provider);
3353         }
3354
3355         /// <internalonly/>
3356         ushort IConvertible.ToUInt16(IFormatProvider provider) {
3357             return Convert.ToUInt16(this, provider);
3358         }
3359
3360         /// <internalonly/>
3361         int IConvertible.ToInt32(IFormatProvider provider) {
3362             return Convert.ToInt32(this, provider);
3363         }
3364
3365         /// <internalonly/>
3366         uint IConvertible.ToUInt32(IFormatProvider provider) {
3367             return Convert.ToUInt32(this, provider);
3368         }
3369
3370         /// <internalonly/>
3371         long IConvertible.ToInt64(IFormatProvider provider) {
3372             return Convert.ToInt64(this, provider);
3373         }
3374
3375         /// <internalonly/>
3376         ulong IConvertible.ToUInt64(IFormatProvider provider) {
3377             return Convert.ToUInt64(this, provider);
3378         }
3379
3380         /// <internalonly/>
3381         float IConvertible.ToSingle(IFormatProvider provider) {
3382             return Convert.ToSingle(this, provider);
3383         }
3384
3385         /// <internalonly/>
3386         double IConvertible.ToDouble(IFormatProvider provider) {
3387             return Convert.ToDouble(this, provider);
3388         }
3389
3390         /// <internalonly/>
3391         Decimal IConvertible.ToDecimal(IFormatProvider provider) {
3392             return Convert.ToDecimal(this, provider);
3393         }
3394
3395         /// <internalonly/>
3396         DateTime IConvertible.ToDateTime(IFormatProvider provider) {
3397             return Convert.ToDateTime(this, provider);
3398         }
3399
3400         /// <internalonly/>
3401         Object IConvertible.ToType(Type type, IFormatProvider provider) {
3402             return Convert.DefaultToType((IConvertible)this, type, provider);
3403         }
3404
3405 #if !MONO
3406         // Is this a string that can be compared quickly (that is it has only characters > 0x80 
3407         // and not a - or '
3408         [System.Security.SecurityCritical]  // auto-generated
3409         [ResourceExposure(ResourceScope.None)]
3410         [MethodImplAttribute(MethodImplOptions.InternalCall)]
3411         internal extern bool IsFastSort();
3412         // Is this a string that only contains characters < 0x80.
3413         [System.Security.SecurityCritical]  // auto-generated
3414         [ResourceExposure(ResourceScope.None)]
3415         [MethodImplAttribute(MethodImplOptions.InternalCall)]
3416         internal extern bool IsAscii();
3417
3418         // Set extra byte for odd-sized strings that came from interop as BSTR.
3419         [System.Security.SecurityCritical]
3420         [ResourceExposure(ResourceScope.None)]
3421         [MethodImplAttribute(MethodImplOptions.InternalCall)]
3422         internal extern void SetTrailByte(byte data);
3423         // Try to retrieve the extra byte - returns false if not present.
3424         [System.Security.SecurityCritical]
3425         [ResourceExposure(ResourceScope.None)]
3426         [MethodImplAttribute(MethodImplOptions.InternalCall)]
3427         internal extern bool TryGetTrailByte(out byte data);
3428 #endif
3429 #if !FEATURE_CORECLR
3430         public CharEnumerator GetEnumerator() {
3431             Contract.Ensures(Contract.Result<CharEnumerator>() != null);
3432             Contract.EndContractBlock();
3433             BCLDebug.Perf(false, "Avoid using String's CharEnumerator until C# special cases foreach on String - use the indexed property on String instead.");
3434             return new CharEnumerator(this);
3435         }
3436 #endif // !FEATURE_CORECLR
3437
3438         IEnumerator<char> IEnumerable<char>.GetEnumerator() {
3439             Contract.Ensures(Contract.Result<IEnumerator<char>>() != null);
3440             Contract.EndContractBlock();
3441             BCLDebug.Perf(false, "Avoid using String's CharEnumerator until C# special cases foreach on String - use the indexed property on String instead.");
3442             return new CharEnumerator(this);
3443         }
3444
3445         /// <internalonly/>
3446         IEnumerator IEnumerable.GetEnumerator() {
3447             Contract.Ensures(Contract.Result<IEnumerator>() != null);
3448             Contract.EndContractBlock();
3449             BCLDebug.Perf(false, "Avoid using String's CharEnumerator until C# special cases foreach on String - use the indexed property on String instead.");
3450             return new CharEnumerator(this);
3451         }
3452
3453          // Copies the source String (byte buffer) to the destination IntPtr memory allocated with len bytes.
3454         [System.Security.SecurityCritical]  // auto-generated
3455         internal unsafe static void InternalCopy(String src, IntPtr dest,int len)
3456         {
3457             if (len == 0)
3458                 return;
3459             fixed(char* charPtr = &src.m_firstChar) {
3460                 byte* srcPtr = (byte*) charPtr;
3461                 byte* dstPtr = (byte*) dest;
3462                 Buffer.Memcpy(dstPtr, srcPtr, len);
3463             }
3464         }      
3465     }
3466
3467     [ComVisible(false)]
3468     [Flags]
3469     public enum StringSplitOptions {
3470         None = 0,
3471         RemoveEmptyEntries = 1
3472     }
3473 }