String

来源:互联网 发布:哪里购买淘宝店铺 编辑:程序博客网 时间:2024/06/11 23:42
  1. // ==++==
  2. // 
  3. //   
  4. //    Copyright (c) 2002 Microsoft Corporation.  All rights reserved.
  5. //   
  6. //    The use and distribution terms for this software are contained in the file
  7. //    named license.txt, which can be found in the root of this distribution.
  8. //    By using this software in any fashion, you are agreeing to be bound by the
  9. //    terms of this license.
  10. //   
  11. //    You must not remove this notice, or any other, from this software.
  12. //   
  13. // 
  14. // ==--==
  15. /*============================================================
  16. **
  17. ** Class:  String
  18. **
  19. **                                        
  20. **
  21. ** Purpose: Contains headers for the String class.  Actual implementations
  22. ** are in String.cpp
  23. **
  24. ** Date:  March 15, 1998
  25. **
  26. ===========================================================*/
  27. namespace System {
  28.     using System.Text;
  29.     using System;
  30.     using System.Globalization;
  31.     using System.Threading;
  32.     using System.Collections;
  33.     using System.Runtime.CompilerServices;
  34.     using va_list = System.ArgIterator;
  35.     using __UnmanagedMemoryStream = System.IO.__UnmanagedMemoryStream;
  36.     //
  37.     // For Information on these methods, please see COMString.cpp
  38.     //
  39.     // The String class represents a static string of characters.  Many of
  40.     // the String methods perform some type of transformation on the current
  41.     // instance and return the result as a new String. All comparison methods are
  42.     // implemented as a part of String.  As with arrays, character positions
  43.     // (indices) are zero-based.
  44.     //
  45.     // When passing a null string into a constructor in VJ and VC, the null should be
  46.     // explicitly type cast to a String.
  47.     // For Example:
  48.     // String s = new String((String)null);
  49.     // Text.Out.WriteLine(s);
  50.     //
  51.     /// <include file='doc/String.uex' path='docs/doc[@for="String"]/*' />
  52.     [Serializable] public sealed class String : IComparable, ICloneable, IConvertible, IEnumerable {
  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_arrayLength;
  59.         [NonSerialized]private int  m_stringLength;
  60.         [NonSerialized]private char m_firstChar;
  61.         //private static readonly char FmtMsgMarkerChar='%';
  62.         //private static readonly char FmtMsgFmtCodeChar='!';
  63.         //These are defined in Com99/src/vm/COMStringCommon.h and must be kept in sync.
  64.         private const int TrimHead = 0;
  65.         private const int TrimTail = 1;
  66.         private const int TrimBoth = 2;
  67.     
  68.         // The Empty constant holds the empty string value.
  69.         //We need to call the String constructor so that the compiler doesn't mark this as a literal.
  70.         //Marking this as a literal would mean that it doesn't show up as a field which we can access 
  71.         //from native.
  72.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Empty"]/*' />
  73.         public static readonly String Empty = "";
  74.     
  75.         //
  76.         //Native Static Methods
  77.         //
  78.     
  79.         // Joins an array of strings together as one string with a separator between each original string.
  80.         //
  81.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Join"]/*' />
  82.         public static String Join (String separator, String[] value) {
  83.             if (value==null) {
  84.                 throw new ArgumentNullException("value");
  85.             }
  86.             return Join(separator, value, 0, value.Length);
  87.         }
  88.     
  89.         // Joins an array of strings together as one string with a separator between each original string.
  90.         //
  91.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Join1"]/*' />
  92.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  93.         public static extern String Join (String separator, String[] value, int startIndex, int count);
  94.     
  95.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  96.         internal static extern int nativeCompareOrdinal(String strA, String strB, bool bIgnoreCase);
  97.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  98.         internal static extern int nativeCompareOrdinalEx(String strA, int indexA, String strB, int indexB, int count);
  99.         //This will not work in case-insensitive mode for any character greater than 0x80.  
  100.         //We'll throw an ArgumentException.
  101.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  102.         unsafe internal static extern int nativeCompareOrdinalWC(String strA, char *strBChars, bool bIgnoreCase, out bool success);
  103.         //
  104.         // This is a helper method for the security team.  They need to uppercase some strings (guaranteed to be less 
  105.         // than 0x80) before security is fully initialized.  Without security initialized, we can't grab resources (the nlp's)
  106.         // from the assembly.  This provides a workaround for that problem and should NOT be used anywhere else.
  107.         //
  108.         internal static String SmallCharToUpper(String strA) {
  109.             String newString = FastAllocateString(strA.Length);
  110.             nativeSmallCharToUpper(strA, newString);
  111.             return newString;
  112.         }
  113.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  114.         private static extern void nativeSmallCharToUpper(String strIn, String strOut);
  115.         // This is a helper method for the security team.  They need to construct strings from a char[]
  116.         // within their homebrew XML parser.  They guarantee that the char[] they pass in isn't null and
  117.         // that the provided indices are valid so we just stuff real fast.
  118.         internal static String CreateFromCharArray( char[] array, int start, int count )
  119.         {
  120.             String newString = FastAllocateString( count );
  121.             FillStringArray( newString, 0, array, start, count );
  122.             return newString;
  123.         }
  124.         //
  125.         //
  126.         // NATIVE INSTANCE METHODS
  127.         //
  128.         //
  129.     
  130.         //
  131.         // Search/Query methods
  132.         //
  133.     
  134.         // Determines whether two strings match.
  135.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Equals"]/*' />
  136.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  137.         public extern override bool Equals(Object obj);
  138.     
  139.         // Determines whether two strings match.
  140.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Equals1"]/*' />
  141.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  142.         public extern bool Equals(String value);
  143.     
  144.         // Determines whether two Strings match.
  145.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Equals2"]/*' />
  146.         public static bool Equals(String a, String b) {
  147.             if ((Object)a==(Object)b) {
  148.                 return true;
  149.             }
  150.     
  151.             if ((Object)a==null || (Object)b==null) {
  152.                 return false;
  153.             }
  154.     
  155.             return a.Equals(b);
  156.         }
  157.         /// <include file='doc/String.uex' path='docs/doc[@for="String.operatorEQ"]/*' />
  158.         public static bool operator == (String a, String b) {
  159.            return String.Equals(a, b);
  160.         }
  161.         /// <include file='doc/String.uex' path='docs/doc[@for="String.operatorNE"]/*' />
  162.         public static bool operator != (String a, String b) {
  163.            return !String.Equals(a, b);
  164.         }
  165.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  166.         internal extern char InternalGetChar(int index);
  167.     
  168.         // Gets the character at a specified position.
  169.         //
  170.         /// <include file='doc/String.uex' path='docs/doc[@for="String.this"]/*' />
  171.         [System.Runtime.CompilerServices.IndexerName("Chars")]
  172.         public char this[int index] {
  173.             get { return InternalGetChar(index); }
  174.         }
  175.         // Converts a substring of this string to an array of characters.  Copies the
  176.         // characters of this string beginning at position startIndex and ending at
  177.         // startIndex + length - 1 to the character array buffer, beginning
  178.         // at bufferStartIndex.
  179.         //
  180.         /// <include file='doc/String.uex' path='docs/doc[@for="String.CopyTo"]/*' />
  181.         public void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count)
  182.         {
  183.             if (destination == null
  184.                 throw new ArgumentNullException("destination");
  185.             if (count < 0)
  186.                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
  187.             if (sourceIndex < 0)
  188.                 throw new ArgumentOutOfRangeException("sourceIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
  189.             if (count > Length - sourceIndex)
  190.                 throw new ArgumentOutOfRangeException("sourceIndex", Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
  191.             if (destinationIndex > destination.Length-count || destinationIndex < 0)
  192.                 throw new ArgumentOutOfRangeException("destinationIndex", Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
  193.             InternalCopyTo(sourceIndex, destination, destinationIndex, count);
  194.         }
  195.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  196.         internal extern void InternalCopyTo(int sourceIndex, char[] destination, int destinationIndex, int count);
  197.     
  198.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  199.         internal extern void CopyToByteArray(int sourceIndex, byte[] destination, int destinationIndex, int charCount);
  200.     
  201.         // Returns the entire string as an array of characters.
  202.         /// <include file='doc/String.uex' path='docs/doc[@for="String.ToCharArray"]/*' />
  203.         public char[] ToCharArray() {
  204.             return ToCharArray(0,Length);
  205.         }
  206.     
  207.         // Returns a substring of this string as an array of characters.
  208.         //
  209.         /// <include file='doc/String.uex' path='docs/doc[@for="String.ToCharArray1"]/*' />
  210.         public char[] ToCharArray(int startIndex, int length)
  211.         {
  212.             // Range check everything.
  213.             if (startIndex < 0 || startIndex > Length || startIndex > Length - length)
  214.                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
  215.             if (length < 0)
  216.                 throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_Index"));
  217.             char[] chars = new char[length];
  218.             InternalCopyTo(startIndex, chars, 0, length);
  219.             return chars;
  220.         }
  221.     
  222.         // Gets a hash code for this string.  If strings A and B are such that A.Equals(B), then
  223.         // they will return the same hash code.
  224.         /// <include file='doc/String.uex' path='docs/doc[@for="String.GetHashCode"]/*' />
  225.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  226.         public extern override int GetHashCode();
  227.     
  228.         // Gets the length of this string
  229.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Length"]/*' />
  230.         public int Length {
  231.             get { return InternalLength(); }
  232.         }
  233.     
  234.         /// This is a EE implemented function so that the JIT can recognise is specially
  235.         /// and eliminate checks on character fetchs.
  236.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  237.         private extern int InternalLength();
  238.     
  239.         ///<internalonly/>
  240.         internal int ArrayLength {
  241.             get { return (m_arrayLength); }
  242.         }
  243.         // Used by StringBuilder
  244.         internal int Capacity {
  245.             get { return (m_arrayLength - 1); }
  246.         }
  247.         // Creates an array of strings by splitting this string at each
  248.         // occurence of a separator.  The separator is searched for, and if found,
  249.         // the substring preceding the occurence is stored as the first element in
  250.         // the array of strings.  We then continue in this manner by searching
  251.         // the substring that follows the occurence.  On the other hand, if the separator
  252.         // is not found, the array of strings will contain this instance as its only element.
  253.         // If the separator is null
  254.         // whitespace (i.e., Character.IsWhitespace) is used as the separator.
  255.         //
  256.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Split"]/*' />
  257.         public String [] Split(params char [] separator) {
  258.             return Split(separator, Int32.MaxValue);
  259.         }
  260.     
  261.         // Creates an array of strings by splitting this string at each
  262.         // occurence of a separator.  The separator is searched for, and if found,
  263.         // the substring preceding the occurence is stored as the first element in
  264.         // the array of strings.  We then continue in this manner by searching
  265.         // the substring that follows the occurence.  On the other hand, if the separator
  266.         // is not found, the array of strings will contain this instance as its only element.
  267.         // If the spearator is the empty string (i.e., String.Empty), then
  268.         // whitespace (i.e., Character.IsWhitespace) is used as the separator.
  269.         // If there are more than count different strings, the last n-(count-1)
  270.         // elements are concatenated and added as the last String.
  271.         //
  272.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Split1"]/*' />
  273.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  274.         public extern String[] Split(char[] separator, int count);
  275.     
  276.     
  277.         // Returns a substring of this string.
  278.         //
  279.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Substring"]/*' />
  280.         public String Substring (int startIndex) {
  281.             return this.Substring (startIndex, Length-startIndex);
  282.         }
  283.     
  284.         // Returns a substring of this string.
  285.         //
  286.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Substring1"]/*' />
  287.         public String Substring (int startIndex, int length) {
  288.             
  289.             int thisLength = Length;
  290.             
  291.             //Bounds Checking.
  292.             if (startIndex<0) {
  293.                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
  294.             }
  295.             if (length<0) {
  296.                 throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
  297.             } 
  298.             if (startIndex > thisLength-length) {
  299.                 throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_IndexLength"));
  300.             }
  301.             String s = FastAllocateString(length);
  302.             FillSubstring(s, 0, this, startIndex, length);
  303.             return s;
  304.         }
  305.     
  306.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  307.         internal extern String TrimHelper(char[] trimChars, int trimType);
  308.     
  309.         //This should really live on System.Globalization.CharacterInfo.  However,
  310.         //Trim gets called by security while resgen is running, so we can't run
  311.         //CharacterInfo's class initializer (which goes to native and looks for a 
  312.         //resource table that hasn't yet been attached to the assembly when resgen
  313.         //runs.  
  314.         internal static readonly char[] WhitespaceChars =   
  315.             { (char) 0x9, (char) 0xA, (char) 0xB, (char) 0xC, (char) 0xD, (char) 0x20, (char) 0xA0,
  316.               (char) 0x2000, (char) 0x2001, (char) 0x2002, (char) 0x2003, (char) 0x2004, (char) 0x2005,
  317.               (char) 0x2006, (char) 0x2007, (char) 0x2008, (char) 0x2009, (char) 0x200A, (char) 0x200B,
  318.               (char) 0x3000, (char) 0xFEFF };
  319.     
  320.         // Removes a string of characters from the ends of this string.
  321.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Trim"]/*' />
  322.         public String Trim(params char[] trimChars) {
  323.             if (null==trimChars || trimChars.Length == 0) {
  324.                 trimChars=WhitespaceChars;
  325.             }
  326.             return TrimHelper(trimChars,TrimBoth);
  327.         }
  328.     
  329.         // Removes a string of characters from the beginning of this string.
  330.         /// <include file='doc/String.uex' path='docs/doc[@for="String.TrimStart"]/*' />
  331.         public String TrimStart(params char[] trimChars) {
  332.             if (null==trimChars || trimChars.Length == 0) {
  333.                 trimChars=WhitespaceChars;
  334.             }
  335.             return TrimHelper(trimChars,TrimHead);
  336.         }
  337.     
  338.     
  339.         // Removes a string of characters from the end of this string.
  340.         /// <include file='doc/String.uex' path='docs/doc[@for="String.TrimEnd"]/*' />
  341.         public String TrimEnd(params char[] trimChars) {
  342.             if (null==trimChars || trimChars.Length == 0) {
  343.                 trimChars=WhitespaceChars;
  344.             }
  345.             return TrimHelper(trimChars,TrimTail);
  346.         }
  347.     
  348.     
  349.         // Creates a new string with the characters copied in from ptr. If
  350.         // ptr is null, a string initialized to ";<;No Object>;"; (i.e.,
  351.         // String.NullString) is created.
  352.         //
  353.         // Issue: This method is only accessible from VC.
  354.         /// <include file='doc/String.uex' path='docs/doc[@for="String.String"]/*' />
  355.         [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
  356.         unsafe public extern String(char *value);
  357.         /// <include file='doc/String.uex' path='docs/doc[@for="String.String1"]/*' />
  358.         [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
  359.         unsafe public extern String(char *value, int startIndex, int length);
  360.     
  361.        /// <include file='doc/String.uex' path='docs/doc[@for="String.String2"]/*' />
  362.         [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
  363.        unsafe public extern String(sbyte *value);
  364.         /// <include file='doc/String.uex' path='docs/doc[@for="String.String3"]/*' />
  365.         [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
  366.         unsafe public extern String(sbyte *value, int startIndex, int length);
  367.         /// <include file='doc/String.uex' path='docs/doc[@for="String.String4"]/*' />
  368.         [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
  369.         unsafe public extern String(sbyte *value, int startIndex, int length, Encoding enc);
  370.                 
  371.         unsafe static private String CreateString(sbyte *value, int startIndex, int length, Encoding enc) {
  372.             if (enc == null)
  373.                 return new String(value, startIndex, length); // default to ANSI
  374.             if (length < 0)
  375.                 throw new ArgumentOutOfRangeException("length",Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  376.             byte [] b = new byte[length];
  377.             __UnmanagedMemoryStream.memcpy((byte*)value, startIndex, b, 0, length);
  378.             return enc.GetString(b);
  379.         }
  380.         // For ASCIIEncoding::GetString()
  381.         unsafe static internal String CreateStringFromASCII(byte[] bytes, int startIndex, int length) {
  382.             BCLDebug.Assert(bytes != null"need a byte[].");
  383.             BCLDebug.Assert(startIndex >= 0 && (startIndex < bytes.Length || bytes.Length == 0), "startIndex >= 0 && startIndex < bytes.Length");
  384.             BCLDebug.Assert(length >= 0 && length <= bytes.Length - startIndex, "length >= 0 && length <= bytes.Length - startIndex");
  385.             if (length == 0)
  386.                 return String.Empty;
  387.             String s = FastAllocateString(length);
  388.             fixed(char* pChars = &s.m_firstChar) {
  389.                 for(int i=0; i<length; i++) 
  390.                     pChars[i] = (char) (bytes[i+startIndex] & 0x7f);
  391.             }
  392.             return s;
  393.         }
  394.     
  395.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  396.         private extern static String FastAllocateString(int length);
  397.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  398.         private extern static void FillString(String dest, int destPos, String src);
  399.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  400.         private extern static void FillStringChecked(String dest, int destPos, String src);
  401.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  402.         private extern static void FillStringEx(String dest, int destPos, String src,int srcLength);
  403.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  404.         private extern static void FillStringArray(String dest, int stringStart, char[] array, int charStart, int count);
  405.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  406.         private extern static void FillSubstring(String dest, int destPos, String src, int startPos, int count);
  407.     
  408.         // Creates a new string from the characters in a subarray.  The new string will
  409.         // be created from the characters in value between startIndex and
  410.         // startIndex + length - 1.
  411.         //
  412.         /// <include file='doc/String.uex' path='docs/doc[@for="String.String7"]/*' />
  413.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  414.         public extern String(char [] value, int startIndex, int length);
  415.     
  416.         // Creates a new string from the characters in a subarray.  The new string will be
  417.         // created from the characters in value.
  418.         //
  419.         /// <include file='doc/String.uex' path='docs/doc[@for="String.String5"]/*' />
  420.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  421.         public extern String(char [] value);
  422.     
  423.         /// <include file='doc/String.uex' path='docs/doc[@for="String.String6"]/*' />
  424.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  425.         public extern String(char c, int count);
  426.     
  427.         //
  428.         //
  429.         // INSTANCE METHODS
  430.         //
  431.         //
  432.     
  433.         // Provides a culture-correct string comparison. StrA is compared to StrB
  434.         // to determine whether it is lexicographically less, equal, or greater, and then returns
  435.         // either a negative integer, 0, or a positive integer; respectively.
  436.         //
  437.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Compare"]/*' />
  438.         public static int Compare(String strA, String strB) {
  439.             return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.None);
  440.         }
  441.     
  442.         // Provides a culture-correct string comparison. strA is compared to strB
  443.         // to determine whether it is lexicographically less, equal, or greater, and then a
  444.         // negative integer, 0, or a positive integer is returned; respectively.
  445.         // The case-sensitive option is set by ignoreCase
  446.         //
  447.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Compare1"]/*' />
  448.         public static int Compare(String strA, String strB, bool ignoreCase) {
  449.             if (ignoreCase) {
  450.                 return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase);
  451.             }
  452.             return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.None);
  453.         }
  454.     
  455.         // Provides a culture-correct string comparison. strA is compared to strB
  456.         // to determine whether it is lexicographically less, equal, or greater, and then a
  457.         // negative integer, 0, or a positive integer is returned; respectively.
  458.         // The case-sensitive option is set by ignoreCase, and the culture is set
  459.         // by culture
  460.         //
  461.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Compare2"]/*' />
  462.         public static int Compare(String strA, String strB, bool ignoreCase, CultureInfo culture) {
  463.             if (culture==null) {
  464.                 throw new ArgumentNullException("culture");
  465.             }
  466.     
  467.             if (ignoreCase) {
  468.                 return culture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase);
  469.             }
  470.             return culture.CompareInfo.Compare(strA, strB, CompareOptions.None);
  471.         }
  472.     
  473.         // Determines whether two string regions match.  The substring of strA beginning
  474.         // at indexA of length count is compared with the substring of strB
  475.         // beginning at indexB of the same length.
  476.         //
  477.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Compare3"]/*' />
  478.         public static int Compare(String strA, int indexA, String strB, int indexB, int length) {
  479.             int lengthA = length;
  480.             int lengthB = length;
  481.             if (strA!=null) {
  482.                 if (strA.Length - indexA < lengthA) {
  483.                   lengthA = (strA.Length - indexA);
  484.                 }
  485.             }
  486.             if (strB!=null) {
  487.                 if (strB.Length - indexB < lengthB) {
  488.                     lengthB = (strB.Length - indexB);
  489.                 }
  490.             }
  491.             return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None);
  492.         }
  493.     
  494.     
  495.         // Determines whether two string regions match.  The substring of strA beginning
  496.         // at indexA of length count is compared with the substring of strB
  497.         // beginning at indexB of the same length.  Case sensitivity is determined by the ignoreCase boolean.
  498.         //
  499.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Compare4"]/*' />
  500.         public static int Compare(String strA, int indexA, String strB, int indexB, int length, bool ignoreCase) {
  501.             int lengthA = length;
  502.             int lengthB = length;
  503.             if (strA!=null) {
  504.                 if (strA.Length - indexA < lengthA) {
  505.                   lengthA = (strA.Length - indexA);
  506.                 }
  507.             }
  508.             if (strB!=null) {
  509.                 if (strB.Length - indexB < lengthB) {
  510.                     lengthB = (strB.Length - indexB);
  511.                 }
  512.             }
  513.             if (ignoreCase) {
  514.                 return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.IgnoreCase);
  515.             }
  516.             return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None);
  517.         }
  518.     
  519.         // Determines whether two string regions match.  The substring of strA beginning
  520.         // at indexA of length length is compared with the substring of strB
  521.         // beginning at indexB of the same length.  Case sensitivity is determined by the ignoreCase boolean,
  522.         // and the culture is set by culture.
  523.         //
  524.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Compare5"]/*' />
  525.         public static int Compare(String strA, int indexA, String strB, int indexB, int length, bool ignoreCase, CultureInfo culture) {
  526.             if (culture==null) {
  527.                 throw new ArgumentNullException("culture");
  528.             }
  529.             int lengthA = length;
  530.             int lengthB = length;
  531.             if (strA!=null) {
  532.                 if (strA.Length - indexA < lengthA) {
  533.                   lengthA = (strA.Length - indexA);
  534.                 }
  535.             }
  536.             if (strB!=null) {
  537.                 if (strB.Length - indexB < lengthB) {
  538.                     lengthB = (strB.Length - indexB);
  539.                 }
  540.             }
  541.     
  542.             if (ignoreCase) {
  543.                 return culture.CompareInfo.Compare(strA,indexA,lengthA, strB, indexB, lengthB,CompareOptions.IgnoreCase);
  544.             } else {
  545.                 return culture.CompareInfo.Compare(strA,indexA,lengthA, strB, indexB, lengthB,CompareOptions.None);
  546.             }
  547.         }
  548.     
  549.         // Compares this object to another object, returning an integer that
  550.         // indicates the relationship. This method returns a value less than 0 if this is less than value, 0
  551.         // if this is equal to value, or a value greater than 0
  552.         // if this is greater than value.  Strings are considered to be
  553.         // greater than all non-String objects.  Note that this means sorted 
  554.         // arrays would contain nulls, other objects, then Strings in that order.
  555.         //
  556.         /// <include file='doc/String.uex' path='docs/doc[@for="String.CompareTo"]/*' />
  557.         public int CompareTo(Object value) {
  558.             if (value == null) {
  559.                 return 1;
  560.             }
  561.             
  562.             if (!(value is String)) {
  563.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeString"));
  564.             }
  565.             return String.Compare(this,(String)value);
  566.         }
  567.     
  568.         // Determines the sorting relation of StrB to the current instance.
  569.         //
  570.         /// <include file='doc/String.uex' path='docs/doc[@for="String.CompareTo1"]/*' />
  571.         public int CompareTo(String strB) {
  572.             if (strB==null) {
  573.                 return 1;
  574.             }
  575.             return CultureInfo.CurrentCulture.CompareInfo.Compare(this, strB, 0);
  576.         }
  577.     
  578.         // Compares strA and strB using an ordinal (code-point) comparison.
  579.         //
  580.         /// <include file='doc/String.uex' path='docs/doc[@for="String.CompareOrdinal"]/*' />
  581.         public static int CompareOrdinal(String strA, String strB) {
  582.             if (strA == null || strB == null) {
  583.                 if ((Object)strA==(Object)strB) { //they're both null;
  584.                     return 0;
  585.                 }
  586.                 return (strA==null)? -1 : 1; //-1 if A is null, 1 if B is null.
  587.             }
  588.             
  589.             return nativeCompareOrdinal(strA, strB, false);
  590.         }
  591.     
  592.         // Compares strA and strB using an ordinal (code-point) comparison.
  593.         //
  594.         /// <include file='doc/String.uex' path='docs/doc[@for="String.CompareOrdinal1"]/*' />
  595.         public static int CompareOrdinal(String strA, int indexA, String strB, int indexB, int length) {
  596.             if (strA == null || strB == null) {
  597.                 if ((Object)strA==(Object)strB) { //they're both null;
  598.                     return 0;
  599.                 }
  600.     
  601.                 return (strA==null)? -1 : 1; //-1 if A is null, 1 if B is null.
  602.             }
  603.     
  604.             return nativeCompareOrdinalEx(strA, indexA, strB, indexB, length);
  605.         }
  606.     
  607.     
  608.         // Determines whether a specified string is a suffix of the the current instance.
  609.         //
  610.         // The case-sensitive and culture-sensitive option is set by options,
  611.         // and the default culture is used.
  612.         //
  613.         /// <include file='doc/String.uex' path='docs/doc[@for="String.EndsWith"]/*' />
  614.         public bool EndsWith(String value) {
  615.             if (null==value) {
  616.                 throw new ArgumentNullException("value");
  617.             }
  618.             int valueLen = value.Length;
  619.             int thisLen = this.Length;
  620.             if (valueLen>thisLen) {
  621.                 return false;
  622.             }
  623.             return (0==Compare(this, thisLen-valueLen, value, 0, valueLen));
  624.         }
  625.         internal bool EndsWith(char value) {
  626.             int thisLen = this.Length;
  627.             if (thisLen != 0) {
  628.                 if (this[thisLen - 1] == value)
  629.                     return true;
  630.             }
  631.             return false;
  632.         }
  633.     
  634.     
  635.         // Returns the index of the first occurance of value in the current instance.
  636.         // The search starts at startIndex and runs thorough the next count characters.
  637.         //
  638.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IndexOf"]/*' />
  639.         public int IndexOf(char value) {
  640.             return IndexOf(value, 0, this.Length);
  641.         }
  642.     
  643.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IndexOf1"]/*' />
  644.         public int IndexOf(char value, int startIndex) {
  645.             return IndexOf(value, startIndex, this.Length - startIndex);
  646.         }
  647.     
  648.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IndexOf2"]/*' />
  649.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  650.         public extern int IndexOf(char value, int startIndex, int count);
  651.     
  652.         // Returns the index of the first occurance of any character in value in the current instance.
  653.         // The search starts at startIndex and runs to endIndex-1. [startIndex,endIndex).
  654.         //
  655.         
  656.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IndexOfAny1"]/*' />
  657.         public int IndexOfAny(char [] anyOf) {
  658.             return IndexOfAny(anyOf,0, this.Length);
  659.         }
  660.     
  661.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IndexOfAny2"]/*' />
  662.         public int IndexOfAny(char [] anyOf, int startIndex) {
  663.             return IndexOfAny(anyOf, startIndex, this.Length - startIndex);
  664.         }
  665.     
  666.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IndexOfAny3"]/*' />
  667.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  668.         public extern int IndexOfAny(char [] anyOf, int startIndex, int count);
  669.     
  670.     
  671.         // Determines the position within this string of the first occurence of the specified
  672.         // string, according to the specified search criteria.  The search begins at
  673.         // the first character of this string, it is case-sensitive and culture-sensitive,
  674.         // and the default culture is used.
  675.         //
  676.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IndexOf6"]/*' />
  677.         public int IndexOf(String value) {
  678.             return CultureInfo.CurrentCulture.CompareInfo.IndexOf(this,value);
  679.         }
  680.     
  681.         // Determines the position within this string of the first occurence of the specified
  682.         // string, according to the specified search criteria.  The search begins at
  683.         // startIndex, it is case-sensitive and culture-sensitve, and the default culture is used.
  684.         //
  685.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IndexOf7"]/*' />
  686.         public int IndexOf(String value, int startIndex){
  687.             return CultureInfo.CurrentCulture.CompareInfo.IndexOf(this,value,startIndex);
  688.         }
  689.     
  690.         // Determines the position within this string of the first occurence of the specified
  691.         // string, according to the specified search criteria.  The search begins at
  692.         // startIndex, ends at endIndex and the default culture is used.
  693.         //
  694.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IndexOf8"]/*' />
  695.         public int IndexOf(String value, int startIndex, int count){
  696.             if (startIndex + count > this.Length) {
  697.                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Index"));
  698.             }
  699.             return CultureInfo.CurrentCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.None);
  700.         }
  701.     
  702.     
  703.         // Returns the index of the last occurance of value in the current instance.
  704.         // The search starts at startIndex and runs to endIndex. [startIndex,endIndex].
  705.         // The character at position startIndex is included in the search.  startIndex is the larger
  706.         // index within the string.
  707.         //
  708.         /// <include file='doc/String.uex' path='docs/doc[@for="String.LastIndexOf"]/*' />
  709.         public int LastIndexOf(char value) {
  710.             return LastIndexOf(value, this.Length-1, this.Length);
  711.         }
  712.     
  713.         /// <include file='doc/String.uex' path='docs/doc[@for="String.LastIndexOf1"]/*' />
  714.         public int LastIndexOf(char value, int startIndex){
  715.             return LastIndexOf(value,startIndex,startIndex + 1);
  716.         }
  717.     
  718.         /// <include file='doc/String.uex' path='docs/doc[@for="String.LastIndexOf2"]/*' />
  719.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  720.         public extern int LastIndexOf(char value, int startIndex, int count);
  721.     
  722.         // Returns the index of the last occurance of any character in value in the current instance.
  723.         // The search starts at startIndex and runs to endIndex. [startIndex,endIndex].
  724.         // The character at position startIndex is included in the search.  startIndex is the larger
  725.         // index within the string.
  726.         //
  727.         
  728.         /// <include file='doc/String.uex' path='docs/doc[@for="String.LastIndexOfAny1"]/*' />
  729.         public int LastIndexOfAny(char [] anyOf) {
  730.             return LastIndexOfAny(anyOf,this.Length-1,this.Length);
  731.         }
  732.     
  733.         /// <include file='doc/String.uex' path='docs/doc[@for="String.LastIndexOfAny2"]/*' />
  734.         public int LastIndexOfAny(char [] anyOf, int startIndex) {
  735.             return LastIndexOfAny(anyOf,startIndex,startIndex + 1);
  736.         }
  737.     
  738.         /// <include file='doc/String.uex' path='docs/doc[@for="String.LastIndexOfAny3"]/*' />
  739.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  740.         public extern int LastIndexOfAny(char [] anyOf, int startIndex, int count);
  741.     
  742.     
  743.         // Returns the index of the last occurance of any character in value in the current instance.
  744.         // The search starts at startIndex and runs to endIndex. [startIndex,endIndex].
  745.         // The character at position startIndex is included in the search.  startIndex is the larger
  746.         // index within the string.
  747.         //
  748.         /// <include file='doc/String.uex' path='docs/doc[@for="String.LastIndexOf6"]/*' />
  749.         public int LastIndexOf(String value) {
  750.             return LastIndexOf(value, this.Length-1,this.Length);
  751.         }
  752.     
  753.         /// <include file='doc/String.uex' path='docs/doc[@for="String.LastIndexOf7"]/*' />
  754.         public int LastIndexOf(String value, int startIndex) {
  755.             return LastIndexOf(value, startIndex, startIndex + 1);
  756.         }
  757.     
  758.         /// <include file='doc/String.uex' path='docs/doc[@for="String.LastIndexOf8"]/*' />
  759.         public int LastIndexOf(String value, int startIndex, int count) {
  760.             if (count<0) {
  761.                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
  762.             }
  763.             return CultureInfo.CurrentCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.None);
  764.         }
  765.     
  766.     
  767.         //
  768.         //
  769.         /// <include file='doc/String.uex' path='docs/doc[@for="String.PadLeft"]/*' />
  770.         public String PadLeft(int totalWidth) {
  771.             return PadHelper(totalWidth, ' 'false);
  772.         }
  773.     
  774.         /// <include file='doc/String.uex' path='docs/doc[@for="String.PadLeft1"]/*' />
  775.         public String PadLeft(int totalWidth, char paddingChar) {
  776.             return PadHelper(totalWidth, paddingChar, false);
  777.         }
  778.         
  779.         /// <include file='doc/String.uex' path='docs/doc[@for="String.PadRight"]/*' />
  780.         public String PadRight(int totalWidth) {
  781.             return PadHelper(totalWidth, ' 'true);
  782.         }
  783.     
  784.         /// <include file='doc/String.uex' path='docs/doc[@for="String.PadRight1"]/*' />
  785.         public String PadRight(int totalWidth, char paddingChar) {
  786.             return PadHelper(totalWidth, paddingChar, true);
  787.         }
  788.     
  789.     
  790.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  791.         private extern String PadHelper(int totalWidth, char paddingChar, bool isRightPadded);
  792.     
  793.         // Determines whether a specified string is a prefix of the current instance
  794.         //
  795.         /// <include file='doc/String.uex' path='docs/doc[@for="String.StartsWith"]/*' />
  796.         public bool StartsWith(String value) {
  797.             if (null==value) {
  798.                 throw new ArgumentNullException("value");
  799.             }
  800.             if (this.Length<value.Length) {
  801.                 return false;
  802.             }
  803.             return (0==Compare(this,0, value,0, value.Length));
  804.         }
  805.     
  806.         // Creates a copy of this string in lower case.
  807.         /// <include file='doc/String.uex' path='docs/doc[@for="String.ToLower"]/*' />
  808.         public String ToLower() {
  809.             return this.ToLower(CultureInfo.CurrentCulture);
  810.         }
  811.     
  812.         // Creates a copy of this string in lower case.  The culture is set by culture.
  813.         /// <include file='doc/String.uex' path='docs/doc[@for="String.ToLower1"]/*' />
  814.         public String ToLower(CultureInfo culture) {
  815.             if (culture==null) {
  816.                 throw new ArgumentNullException("culture");
  817.             }
  818.             return culture.TextInfo.ToLower(this);
  819.         }
  820.     
  821.         // Creates a copy of this string in upper case.
  822.         /// <include file='doc/String.uex' path='docs/doc[@for="String.ToUpper"]/*' />
  823.         public String ToUpper() {
  824.             return this.ToUpper(CultureInfo.CurrentCulture);
  825.         }
  826.     
  827.         // Creates a copy of this string in upper case.  The culture is set by culture.
  828.         /// <include file='doc/String.uex' path='docs/doc[@for="String.ToUpper1"]/*' />
  829.         public String ToUpper(CultureInfo culture) {
  830.             if (culture==null) {
  831.                 throw new ArgumentNullException("culture");
  832.             }
  833.             return culture.TextInfo.ToUpper(this);
  834.         }
  835.     
  836.         // Returns this string.
  837.         /// <include file='doc/String.uex' path='docs/doc[@for="String.ToString"]/*' />
  838.         public override String ToString() {
  839.             return this;
  840.         }
  841.         /// <include file='doc/String.uex' path='docs/doc[@for="String.ToString1"]/*' />
  842.         public String ToString(IFormatProvider provider) {
  843.             return this;
  844.         }
  845.     
  846.         // Method required for the ICloneable interface.
  847.         // There's no point in cloning a string since they're immutable, so we simply return this.
  848.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Clone"]/*' />
  849.         public Object Clone() {
  850.             return this;
  851.         }
  852.     
  853.     
  854.         // Trims the whitespace from both ends of the string.  Whitespace is defined by
  855.         // CharacterInfo.WhitespaceChars.
  856.         //
  857.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Trim1"]/*' />
  858.         public String Trim() {
  859.             return this.Trim(WhitespaceChars);
  860.         }
  861.     
  862.         //
  863.         //
  864.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Insert"]/*' />
  865.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  866.         public extern String Insert(int startIndex, String value);
  867.     
  868.         // Replaces all instances of oldChar with newChar.
  869.         //
  870.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Replace"]/*' />
  871.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  872.         public extern String Replace (char oldChar, char newChar);
  873.     // This method contains the same functionality as StringBuilder Replace. The only difference is that
  874.     // a new String has to be allocated since Strings are immutable
  875.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Replace1"]/*' />
  876.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  877.         public extern String Replace (String oldValue, String newValue);
  878.     
  879.         //
  880.         //
  881.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Remove"]/*' />
  882.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  883.         public extern String Remove(int startIndex, int count);
  884.     
  885.     
  886.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Format"]/*' />
  887.         public static String Format(String format, Object arg0) {
  888.             return Format(null, format, new Object[] {arg0});
  889.         }
  890.     
  891.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Format1"]/*' />
  892.         public static String Format(String format, Object arg0, Object arg1) {
  893.             return Format(null, format, new Object[] {arg0, arg1});
  894.         }
  895.     
  896.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Format2"]/*' />
  897.         public static String Format(String format, Object arg0, Object arg1, Object arg2) {
  898.             return Format(null, format, new Object[] {arg0, arg1, arg2});
  899.         }
  900.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Format3"]/*' />
  901.         public static String Format(String format, params Object[] args) {
  902.             return Format(null, format, args);
  903.         }
  904.     
  905.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Format4"]/*' />
  906.         public static String Format( IFormatProvider provider, String format, params Object[] args) {
  907.             if (format == null || args == null
  908.                 throw new ArgumentNullException((format==null)?"format":"args");
  909.             StringBuilder sb = new StringBuilder(format.Length + args.Length * 8);
  910.             sb.AppendFormat(provider,format,args);
  911.             return sb.ToString();
  912.         }
  913.     
  914.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Copy"]/*' />
  915.         public static String Copy (String str) {
  916.             if (str==null) {
  917.                 throw new ArgumentNullException("str");
  918.             }
  919.             int length = str.Length;
  920.             String result = FastAllocateString(length);
  921.             FillString(result, 0, str);
  922.             return result;
  923.         }
  924.         // Used by StringBuilder to avoid data corruption
  925.         internal static String InternalCopy (String str) {
  926.             int length = str.Length;
  927.             String result = FastAllocateString(length);
  928.             FillStringEx(result, 0, str, length); // The underlying's String can changed length is StringBuilder
  929.             return result;
  930.         }
  931.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Concat"]/*' />
  932.         public static String Concat(Object arg0) {
  933.             if (arg0==null) {
  934.                 return String.Empty;
  935.             }
  936.             return arg0.ToString();
  937.         }
  938.     
  939.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Concat1"]/*' />
  940.         public static String Concat(Object arg0, Object arg1) {
  941.             if (arg0==null) {
  942.                 arg0 = String.Empty;
  943.             }
  944.     
  945.             if (arg1==null) {
  946.                 arg1 = String.Empty;
  947.             }
  948.             return Concat(arg0.ToString(), arg1.ToString());
  949.         }
  950.     
  951.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Concat2"]/*' />
  952.         public static String Concat(Object arg0, Object arg1, Object arg2) {
  953.             if (arg0==null) {
  954.                 arg0 = String.Empty;
  955.             }
  956.     
  957.             if (arg1==null) {
  958.                 arg1 = String.Empty;
  959.             }
  960.     
  961.             if (arg2==null) {
  962.                 arg2 = String.Empty;
  963.             }
  964.     
  965.             return Concat(arg0.ToString(), arg1.ToString(), arg2.ToString());
  966.         }
  967.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Concat3"]/*' />
  968.         [CLSCompliant(false)] 
  969.         public static String Concat(Object arg0, Object arg1, Object arg2, Object arg3, __arglist) 
  970.         {
  971.             Object[]   objArgs;
  972.             int        argCount;
  973.             
  974.             ArgIterator args = new ArgIterator(__arglist);
  975.             //+4 to account for the 4 hard-coded arguments at the beginning of the list.
  976.             argCount = args.GetRemainingCount() + 4;
  977.     
  978.             objArgs = new Object[argCount];
  979.             
  980.             //Handle the hard-coded arguments
  981.             objArgs[0] = arg0;
  982.             objArgs[1] = arg1;
  983.             objArgs[2] = arg2;
  984.             objArgs[3] = arg3;
  985.             
  986.             //Walk all of the args in the variable part of the argument list.
  987.             for (int i=4; i<argCount; i++) {
  988.                 objArgs[i] = TypedReference.ToObject(args.GetNextArg());
  989.             }
  990.             return Concat(objArgs);
  991.         }
  992.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Concat4"]/*' />
  993.         public static String Concat(params Object[] args) {
  994.             if (args==null) {
  995.                 throw new ArgumentNullException("args");
  996.             }
  997.     
  998.             String[] sArgs = new String[args.Length];
  999.             int totalLength=0;
  1000.             
  1001.             for (int i=0; i<args.Length; i++) {
  1002.                 sArgs[i] = ((args[i]==null)?(String.Empty):(args[i].ToString()));
  1003.                 totalLength += sArgs[i].Length;
  1004.             }
  1005.             return ConcatArray(sArgs, totalLength);
  1006.         }
  1007.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Concat5"]/*' />
  1008.         public static String Concat(String str0, String str1) {
  1009.             if (str0 == null) {
  1010.                 if (str1==null) {
  1011.                     return String.Empty;
  1012.                 }
  1013.                 return str1;
  1014.             }
  1015.             if (str1==null) {
  1016.                 return str0;
  1017.             }
  1018.             int str0Length = str0.Length;
  1019.             
  1020.             String result = FastAllocateString(str0Length + str1.Length);
  1021.             
  1022.             FillStringChecked(result, 0,        str0);
  1023.             FillStringChecked(result, str0Length, str1);
  1024.             
  1025.             return result;
  1026.         }
  1027.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Concat6"]/*' />
  1028.         public static String Concat(String str0, String str1, String str2) {
  1029.             if (str0==null && str1==null && str2==null) {
  1030.                 return String.Empty;
  1031.             }
  1032.             if (str0==null) {
  1033.                 str0 = String.Empty;
  1034.             }
  1035.             if (str1==null) {
  1036.                 str1 = String.Empty;
  1037.             }
  1038.             if (str2 == null) {
  1039.                 str2 = String.Empty;
  1040.             }
  1041.             int totalLength = str0.Length + str1.Length + str2.Length;
  1042.             String result = FastAllocateString(totalLength);
  1043.             FillStringChecked(result, 0, str0);
  1044.             FillStringChecked(result, str0.Length, str1);
  1045.             FillStringChecked(result, str0.Length + str1.Length, str2);
  1046.             return result;
  1047.         }
  1048.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Concat7"]/*' />
  1049.         public static String Concat(String str0, String str1, String str2, String str3) {
  1050.             if (str0==null && str1==null && str2==null && str3==null) {
  1051.                 return String.Empty;
  1052.             }
  1053.             if (str0==null) {
  1054.                 str0 = String.Empty;
  1055.             }
  1056.             if (str1==null) {
  1057.                 str1 = String.Empty;
  1058.             }
  1059.             if (str2 == null) {
  1060.                 str2 = String.Empty;
  1061.             }
  1062.             
  1063.             if (str3 == null) {
  1064.                 str3 = String.Empty;
  1065.             }
  1066.             int totalLength = str0.Length + str1.Length + str2.Length + str3.Length;
  1067.             String result = FastAllocateString(totalLength);
  1068.             FillStringChecked(result, 0, str0);
  1069.             FillStringChecked(result, str0.Length, str1);
  1070.             FillStringChecked(result, str0.Length + str1.Length, str2);
  1071.             FillStringChecked(result, str0.Length + str1.Length + str2.Length, str3);
  1072.             return result;
  1073.         }
  1074.         private static String ConcatArray(String[] values, int totalLength) {
  1075.             String result =  FastAllocateString(totalLength);
  1076.             int currPos=0;
  1077.             for (int i=0; i<values.Length; i++) {
  1078.                 BCLDebug.Assert((currPos + values[i].Length <= totalLength), 
  1079.                                 "[String.ConcatArray](currPos + values[i].Length <= totalLength)");
  1080.                 FillStringChecked(result, currPos, values[i]);
  1081.                 currPos+=values[i].Length;
  1082.             }
  1083.             return result;
  1084.         }
  1085.         private static String[] CopyArrayOnNull(String[] values, out int totalLength) {
  1086.             totalLength = 0;
  1087.             
  1088.             String[] outValues = new String[values.Length];
  1089.             
  1090.             for (int i=0; i<values.Length; i++) {
  1091.                 outValues[i] = ((values[i]==null)?String.Empty:values[i]);
  1092.                 totalLength += outValues[i].Length;
  1093.             }
  1094.             return outValues;
  1095.         }
  1096.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Concat8"]/*' />
  1097.         public static String Concat(params String[] values) {
  1098.             int totalLength=0;
  1099.             if (values==null) {
  1100.                 throw new ArgumentNullException("values");
  1101.             }
  1102.             for (int i=0; i<values.Length; i++) {
  1103.                 if (values[i]==null) {
  1104.                     values = CopyArrayOnNull(values, out totalLength);
  1105.                     break;
  1106.                 } else {
  1107.                     totalLength += values[i].Length;
  1108.                 }
  1109.             }
  1110.             
  1111.             return ConcatArray(values, totalLength);
  1112.         }
  1113.         /// <include file='doc/String.uex' path='docs/doc[@for="String.Intern"]/*' />
  1114.         public static String Intern(String str) {
  1115.             if (str==null) {
  1116.                 throw new ArgumentNullException("str");
  1117.             }
  1118.             return Thread.GetDomain().GetOrInternString(str);
  1119.         }
  1120.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IsInterned"]/*' />
  1121.         public static String IsInterned(String str) {
  1122.             if (str==null) {
  1123.                 throw new ArgumentNullException("str");
  1124.             }
  1125.             return Thread.GetDomain().IsStringInterned(str);
  1126.         }
  1127.         //
  1128.         // IValue implementation
  1129.         // 
  1130.         
  1131.         /// <include file='doc/String.uex' path='docs/doc[@for="String.GetTypeCode"]/*' />
  1132.         public TypeCode GetTypeCode() {
  1133.             return TypeCode.String;
  1134.         }
  1135.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IConvertible.ToBoolean"]/*' />
  1136.         /// <internalonly/>
  1137.         bool IConvertible.ToBoolean(IFormatProvider provider) {
  1138.             return Convert.ToBoolean(this, provider);
  1139.         }
  1140.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IConvertible.ToChar"]/*' />
  1141.         /// <internalonly/>
  1142.         char IConvertible.ToChar(IFormatProvider provider) {
  1143.             return Convert.ToChar(this, provider);
  1144.         }
  1145.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IConvertible.ToSByte"]/*' />
  1146.         /// <internalonly/>
  1147.         [CLSCompliant(false)]
  1148.         sbyte IConvertible.ToSByte(IFormatProvider provider) {
  1149.             return Convert.ToSByte(this, provider);
  1150.         }
  1151.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IConvertible.ToByte"]/*' />
  1152.         /// <internalonly/>
  1153.         byte IConvertible.ToByte(IFormatProvider provider) {
  1154.             return Convert.ToByte(this, provider);
  1155.         }
  1156.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IConvertible.ToInt16"]/*' />
  1157.         /// <internalonly/>
  1158.         short IConvertible.ToInt16(IFormatProvider provider) {
  1159.             return Convert.ToInt16(this, provider);
  1160.         }
  1161.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IConvertible.ToUInt16"]/*' />
  1162.         /// <internalonly/>
  1163.         [CLSCompliant(false)]
  1164.         ushort IConvertible.ToUInt16(IFormatProvider provider) {
  1165.             return Convert.ToUInt16(this, provider);
  1166.         }
  1167.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IConvertible.ToInt32"]/*' />
  1168.         /// <internalonly/>
  1169.         int IConvertible.ToInt32(IFormatProvider provider) {
  1170.             return Convert.ToInt32(this, provider);
  1171.         }
  1172.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IConvertible.ToUInt32"]/*' />
  1173.         /// <internalonly/>
  1174.         [CLSCompliant(false)]
  1175.         uint IConvertible.ToUInt32(IFormatProvider provider) {
  1176.             return Convert.ToUInt32(this, provider);
  1177.         }
  1178.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IConvertible.ToInt64"]/*' />
  1179.         /// <internalonly/>
  1180.         long IConvertible.ToInt64(IFormatProvider provider) {
  1181.             return Convert.ToInt64(this, provider);
  1182.         }
  1183.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IConvertible.ToUInt64"]/*' />
  1184.         /// <internalonly/>
  1185.         [CLSCompliant(false)]
  1186.         ulong IConvertible.ToUInt64(IFormatProvider provider) {
  1187.             return Convert.ToUInt64(this, provider);
  1188.         }
  1189.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IConvertible.ToSingle"]/*' />
  1190.         /// <internalonly/>
  1191.         float IConvertible.ToSingle(IFormatProvider provider) {
  1192.             return Convert.ToSingle(this, provider);
  1193.         }
  1194.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IConvertible.ToDouble"]/*' />
  1195.         /// <internalonly/>
  1196.         double IConvertible.ToDouble(IFormatProvider provider) {
  1197.             return Convert.ToDouble(this, provider);
  1198.         }
  1199.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IConvertible.ToDecimal"]/*' />
  1200.         /// <internalonly/>
  1201.         Decimal IConvertible.ToDecimal(IFormatProvider provider) {
  1202.             return Convert.ToDecimal(this, provider);
  1203.         }
  1204.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IConvertible.ToDateTime"]/*' />
  1205.         /// <internalonly/>
  1206.         DateTime IConvertible.ToDateTime(IFormatProvider provider) {
  1207.             return Convert.ToDateTime(this, provider);
  1208.         }
  1209.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IConvertible.ToType"]/*' />
  1210.         /// <internalonly/>
  1211.         Object IConvertible.ToType(Type type, IFormatProvider provider) {
  1212.             return Convert.DefaultToType((IConvertible)this, type, provider);
  1213.         }
  1214.         // Is this a string that can be compared quickly (that is it has only characters > 0x80 
  1215.         // and not a - or '
  1216.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1217.         internal extern bool IsFastSort();
  1218.         
  1219.         ///<internalonly/>
  1220.         unsafe internal void SetChar(int index, char value)
  1221.         {
  1222. #if _DEBUG
  1223.             BCLDebug.Assert(ValidModifiableString(), "Modifiable string must not have highChars flags set");
  1224. #endif
  1225.             //Bounds check and then set the actual bit.
  1226.             if ((UInt32)index >= (UInt32)Length)
  1227.                 throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
  1228.             fixed (char *p = this.m_firstChar) {
  1229.                 // Set the character.
  1230.                 p[index] = value;
  1231.             }
  1232.         }
  1233. #if _DEBUG
  1234.         // Only used in debug build. Insure that the HighChar state information for a string is not set as known
  1235.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1236.         private extern bool ValidModifiableString();
  1237. #endif
  1238.         ///<internalonly/>
  1239.         unsafe internal void AppendInPlace(char value,int currentLength)
  1240.         {
  1241.             BCLDebug.Assert(currentLength < m_arrayLength, "[String.AppendInPlace(char)currentLength < m_arrayLength");
  1242. #if _DEBUG
  1243.             BCLDebug.Assert(ValidModifiableString(), "Modifiable string must not have highChars flags set");
  1244. #endif
  1245.             fixed (char *p = this.m_firstChar)
  1246.             {
  1247.                 // Append the character.
  1248.                 p[currentLength] = value;
  1249.                 p[++currentLength] = '/0';
  1250.                 m_stringLength = currentLength;
  1251.             }
  1252.         }
  1253.         ///<internalonly/>
  1254.         unsafe internal void AppendInPlace(char value, int repeatCount, int currentLength)
  1255.         {
  1256.             BCLDebug.Assert(currentLength+repeatCount < m_arrayLength, "[String.AppendInPlace]currentLength+repeatCount < m_arrayLength");
  1257. #if _DEBUG
  1258.             BCLDebug.Assert(ValidModifiableString(), "Modifiable string must not have highChars flags set");
  1259. #endif
  1260.             
  1261.             int newLength = currentLength + repeatCount;
  1262.             fixed (char *p = this.m_firstChar)
  1263.             {
  1264.                 int i;
  1265.                 for (i=currentLength; i<newLength; i++) {
  1266.                     p[i] = value;
  1267.                 }
  1268.                 p[i] = '/0';
  1269.             }
  1270.             this.m_stringLength = newLength; 
  1271.         }
  1272.         ///<internalonly/>
  1273.        internal unsafe void AppendInPlace(String value, int currentLength) {
  1274.             BCLDebug.Assert(value!=null"[String.AppendInPlace]value!=null");
  1275.             BCLDebug.Assert(value.Length + currentLength < this.m_arrayLength, "[String.AppendInPlace]Length is wrong.");
  1276. #if _DEBUG
  1277.             BCLDebug.Assert(ValidModifiableString(), "Modifiable string must not have highChars flags set");
  1278. #endif
  1279.             
  1280.             FillString(this, currentLength, value);
  1281.             SetLength(currentLength + value.Length);
  1282.             NullTerminate();    
  1283.         }
  1284.         
  1285.         internal void AppendInPlace(String value, int startIndex, int count, int currentLength) {
  1286.             BCLDebug.Assert(value!=null"[String.AppendInPlace]value!=null");
  1287.             BCLDebug.Assert(count + currentLength < this.m_arrayLength, "[String.AppendInPlace]count + currentLength < this.m_arrayLength");
  1288.             BCLDebug.Assert(count>=0, "[String.AppendInPlace]count>=0");
  1289.             BCLDebug.Assert(startIndex>=0, "[String.AppendInPlace]startIndex>=0");
  1290.             BCLDebug.Assert(startIndex <= (value.Length - count), "[String.AppendInPlace]startIndex <= (value.Length - count)");
  1291. #if _DEBUG
  1292.             BCLDebug.Assert(ValidModifiableString(), "Modifiable string must not have highChars flags set");
  1293. #endif
  1294.             
  1295.             FillSubstring(this, currentLength, value, startIndex, count);
  1296.             SetLength(currentLength + count);
  1297.             NullTerminate();
  1298.         }
  1299.         internal unsafe void AppendInPlace(char *value, int count,int currentLength) {
  1300.             BCLDebug.Assert(value!=null"[String.AppendInPlace]value!=null");
  1301.             BCLDebug.Assert(count + currentLength < this.m_arrayLength, "[String.AppendInPlace]count + currentLength < this.m_arrayLength");
  1302.             BCLDebug.Assert(count>=0, "[String.AppendInPlace]count>=0");
  1303. #if _DEBUG
  1304.             BCLDebug.Assert(ValidModifiableString(), "Modifiable string must not have highChars flags set");
  1305. #endif
  1306.             fixed(char *p = this.m_firstChar) {
  1307.                 int i;
  1308.                 for (i=0; i<count; i++) {
  1309.                     p[currentLength+i] = value[i];
  1310.                 }
  1311.             }
  1312.             SetLength(currentLength + count);
  1313.             NullTerminate();
  1314.         }
  1315.         ///<internalonly/>
  1316.         internal unsafe void AppendInPlace(char[] value, int start, int count, int currentLength) {
  1317.             BCLDebug.Assert(value!=null"[String.AppendInPlace]value!=null");
  1318.             BCLDebug.Assert(count + currentLength < this.m_arrayLength, "[String.AppendInPlace]Length is wrong.");
  1319.             BCLDebug.Assert(value.Length-count>=start, "[String.AppendInPlace]value.Length-count>=start");
  1320. #if _DEBUG
  1321.             BCLDebug.Assert(ValidModifiableString(), "Modifiable string must not have highChars flags set");
  1322. #endif
  1323.             FillStringArray(this, currentLength, value, start, count);
  1324.             this.m_stringLength = (currentLength + count); 
  1325.             this.NullTerminate();
  1326.         }
  1327.         ///<internalonly/>
  1328.         unsafe internal void ReplaceCharInPlace(char oldChar, char newChar, int startIndex, int count,int currentLength) {
  1329.             BCLDebug.Assert(startIndex>=0, "[String.ReplaceCharInPlace]startIndex>0");
  1330.             BCLDebug.Assert(startIndex<=currentLength, "[String.ReplaceCharInPlace]startIndex>=Length");
  1331.             BCLDebug.Assert((startIndex<=currentLength-count), "[String.ReplaceCharInPlace]count>0 && startIndex<=currentLength-count");
  1332. #if _DEBUG
  1333.             BCLDebug.Assert(ValidModifiableString(), "Modifiable string must not have highChars flags set");
  1334. #endif
  1335.             int endIndex = startIndex+count;
  1336.             fixed (char *p = this.m_firstChar) {
  1337.                 for (int i=startIndex;i<endIndex; i++) {
  1338.                     if (p[i]==oldChar) {
  1339.                         p[i]=newChar;
  1340.                     }
  1341.                 }
  1342.             }
  1343.         }
  1344.         ///<internalonly/>
  1345.         internal static String GetStringForStringBuilder(String value, int capacity) {
  1346.             BCLDebug.Assert(value!=null"[String.GetStringForStringBuilder]value!=null");
  1347.             BCLDebug.Assert(capacity>=value.Length,  "[String.GetStringForStringBuilder]capacity>=value.Length");
  1348.             
  1349.             String newStr = FastAllocateString(capacity);
  1350.             if (value.Length==0) {
  1351.                 newStr.m_stringLength=0;
  1352.                 newStr.m_firstChar='/0';
  1353.                 return newStr;
  1354.             }
  1355.             FillString(newStr, 0, value);
  1356.             newStr.m_stringLength = value.m_stringLength;
  1357.             return newStr;
  1358.         }
  1359.         ///<internalonly/>
  1360.         private unsafe void NullTerminate() {
  1361.             fixed(char *p = this.m_firstChar) {
  1362.                 p[m_stringLength] = '/0';
  1363.             }
  1364.         }
  1365.         ///<internalonly/>
  1366.         unsafe internal void ClearPostNullChar() {
  1367.             int newLength = Length+1;
  1368.             if (newLength<m_arrayLength) {
  1369.                 fixed(char *p = this.m_firstChar) {
  1370.                     p[newLength] = '/0';
  1371.                 }
  1372.             }
  1373.         }
  1374.         ///<internalonly/>
  1375.         internal void SetLength(int newLength) {
  1376.             BCLDebug.Assert(newLength <= m_arrayLength, "newLength<=m_arrayLength");
  1377.             m_stringLength = newLength;
  1378.         }
  1379.         
  1380.         /// <include file='doc/String.uex' path='docs/doc[@for="String.GetEnumerator"]/*' />
  1381.         public CharEnumerator GetEnumerator() {
  1382.             BCLDebug.Perf(false"Avoid using String's CharEnumerator until C# special cases foreach on String - use the indexed property on String instead.");
  1383.             return new CharEnumerator(this);
  1384.         }
  1385.         /// <include file='doc/String.uex' path='docs/doc[@for="String.IEnumerable.GetEnumerator"]/*' />
  1386.         /// <internalonly/>
  1387.         IEnumerator IEnumerable.GetEnumerator() {
  1388.             BCLDebug.Perf(false"Avoid using String's CharEnumerator until C# special cases foreach on String - use the indexed property on String instead.");
  1389.             return new CharEnumerator(this);
  1390.         }
  1391.         //
  1392.         // This is just designed to prevent compiler warnings.
  1393.         // This field is used from native, but we need to prevent the compiler warnings.
  1394.         //
  1395. #if _DEBUG
  1396.         private void DontTouchThis() {
  1397.             m_arrayLength = 0;
  1398.             m_stringLength = 0;
  1399.             m_firstChar = m_firstChar;
  1400.         }
  1401. #endif
  1402.         internal unsafe void InternalSetCharNoBoundsCheck(int index, char value) {
  1403.             fixed (char *p = this.m_firstChar) {
  1404.                 p[index] = value;
  1405.             }
  1406.         }
  1407.          // Copies the source String (byte buffer) to the destination IntPtr memory allocated with len bytes.
  1408.         internal unsafe static void InternalCopy(String src, IntPtr dest,int len)
  1409.         {
  1410.             if (len == 0)
  1411.                 return;
  1412.             fixed(char* charPtr = &src.m_firstChar) {
  1413.                 byte* srcPtr = (byte*) charPtr;
  1414.                 byte* dstPtr = (byte*) dest.ToPointer();
  1415.                 System.IO.__UnmanagedMemoryStream.memcpyimpl(srcPtr, dstPtr, len);
  1416.             }
  1417.         }
  1418.         // memcopies characters inside a String. 
  1419.         internal unsafe static void InternalMemCpy(String src, int srcOffset, String dst, int destOffset, int len)
  1420.         { 
  1421.             if (len == 0)
  1422.                 return;
  1423.             fixed(char* srcPtr = &src.m_firstChar) {
  1424.                 fixed(char* dstPtr = &dst.m_firstChar) {
  1425.                     System.IO.__UnmanagedMemoryStream.memcpyimpl((byte*)(srcPtr + srcOffset), (byte*)(dstPtr + destOffset), len);
  1426.                 }
  1427.             }
  1428.         }
  1429.       
  1430.         internal unsafe static void revmemcpyimpl(byte* src, byte* dest, int len) {
  1431.             if (len == 0)
  1432.                 return;
  1433.             dest += len;
  1434.             src += len;
  1435.             
  1436.             if (((long)src & 3) != 0)
  1437.             {
  1438.                 do{
  1439.                     dest--;
  1440.                     src--;
  1441.                     len--;
  1442.                     *dest = *src;
  1443.                 } while (len > 0 && ((long)src & 3) != 0);
  1444.             }
  1445.             
  1446.             if (len >= 16){
  1447.                 len -= 16;
  1448.                 do{
  1449.                     dest -= (byte*)16;
  1450.                     src -= (byte*)16;
  1451.                     ((int*)dest)[3] = ((int*)src)[3];
  1452.                     ((int*)dest)[2] = ((int*)src)[2];
  1453.                     ((int*)dest)[1] = ((int*)src)[1];
  1454.                     ((int*)dest)[0] = ((int*)src)[0];
  1455.                     
  1456.                 } while ((len -= 16) >= 0);
  1457.             }
  1458.             if ((len & 8) > 0) {
  1459.                 dest -= (byte*)8;
  1460.                 src -= (byte*)8;
  1461.                 ((int*)dest)[1] = ((int*)src)[1];
  1462.                 ((int*)dest)[0] = ((int*)src)[0];
  1463.             }
  1464.             if ((len & 4) > 0) {
  1465.                 dest -= (byte*)4;
  1466.                 src -= (byte*)4;
  1467.                 ((int*)dest)[0] = ((int*)src)[0];
  1468.             }
  1469.             if ((len & 2) != 0) {
  1470.                 dest -= (byte*)2;
  1471.                 src -= (byte*)2;
  1472.                 ((short*)dest)[0] = ((short*)src)[0];
  1473.             }
  1474.             if ((len & 1) != 0) {
  1475.                 dest--;
  1476.                 src--;
  1477.                 *dest = *src;
  1478.             }
  1479.         }        
  1480.         // Copies the source String (byte buffer) to the destination IntPtr memory allocated with len bytes.
  1481.         internal unsafe static void InternalCopy(String src, byte[] dest,int len)
  1482.         {
  1483.             if (len == 0)
  1484.                 return;
  1485.             fixed(char* charPtr = &src.m_firstChar) {
  1486.                 fixed(byte* destPtr = dest) {
  1487.                     byte* srcPtr = (byte*) charPtr;
  1488.                     System.IO.__UnmanagedMemoryStream.memcpyimpl(srcPtr, destPtr, len);
  1489.                 }
  1490.             }
  1491.         }
  1492.         internal unsafe void InsertInPlace(int index, String value, int repeatCount, int currentLength, int requiredLength) {
  1493.             BCLDebug.Assert(requiredLength  < m_arrayLength, "[String.InsertString] requiredLength  < m_arrayLength");
  1494.             BCLDebug.Assert(index + value.Length * repeatCount < m_arrayLength, "[String.InsertString] index + value.Length * repeatCount < m_arrayLength");
  1495. #if _DEBUG
  1496.             BCLDebug.Assert(ValidModifiableString(), "Modifiable string must not have highChars flags set");
  1497. #endif
  1498.               //Copy the old characters over to make room and then insert the new characters.
  1499.             fixed(char* srcPtr = this.m_firstChar) {
  1500.                 fixed(char* valuePtr = &value.m_firstChar) {
  1501.                    revmemcpyimpl((byte*)(srcPtr + index),(byte*)(srcPtr + index + value.Length * repeatCount), (currentLength - index) * sizeof(char));
  1502.                    for (int i=0; i<repeatCount; i++) {
  1503.                         System.IO.__UnmanagedMemoryStream.memcpyimpl((byte*)valuePtr, (byte*)(srcPtr + index + i * value.Length), value.Length * sizeof(char));
  1504.                    }
  1505.                 }
  1506.                 srcPtr[requiredLength] = '/0';
  1507.             }
  1508.             this.m_stringLength = requiredLength; 
  1509.         }
  1510.     }
  1511. }
 
原创粉丝点击