make these public on monotouch
[mono.git] / mcs / class / corlib / System.Text / StringBuilder.cs
1 // -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2 //
3 // System.Text.StringBuilder
4 //
5 // Authors: 
6 //   Marcin Szczepanski (marcins@zipworld.com.au)
7 //   Paolo Molaro (lupus@ximian.com)
8 //   Patrik Torstensson
9 //
10 // NOTE: In the case the buffer is only filled by 50% a new string
11 //       will be returned by ToString() is cached in the '_cached_str'
12 //               cache_string will also control if a string has been handed out
13 //               to via ToString(). If you are chaning the code make sure that
14 //               if you modify the string data set the cache_string to null.
15 //
16
17 //
18 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
19 //
20 // Permission is hereby granted, free of charge, to any person obtaining
21 // a copy of this software and associated documentation files (the
22 // "Software"), to deal in the Software without restriction, including
23 // without limitation the rights to use, copy, modify, merge, publish,
24 // distribute, sublicense, and/or sell copies of the Software, and to
25 // permit persons to whom the Software is furnished to do so, subject to
26 // the following conditions:
27 // 
28 // The above copyright notice and this permission notice shall be
29 // included in all copies or substantial portions of the Software.
30 // 
31 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 //
39 using System.Runtime.Serialization;
40 using System.Runtime.CompilerServices;
41 using System.Runtime.InteropServices;
42
43 namespace System.Text {
44         
45         [Serializable]
46 #if NET_2_0
47         [ComVisible (true)]
48 #endif
49         [MonoTODO ("Serialization format not compatible with .NET")]
50         public sealed class StringBuilder
51 #if NET_2_0
52                 : ISerializable
53 #endif
54         {
55                 private int _length;
56                 private string _str;
57                 private string _cached_str;
58                 
59                 private int _maxCapacity;
60                 private const int constDefaultCapacity = 16;
61
62                 public StringBuilder(string value, int startIndex, int length, int capacity) 
63                         : this (value, startIndex, length, capacity, Int32.MaxValue)
64                 {
65                 }
66
67                 private StringBuilder(string value, int startIndex, int length, int capacity, int maxCapacity)
68                 {
69                         // first, check the parameters and throw appropriate exceptions if needed
70                         if (null == value)
71                                 value = "";
72
73                         // make sure startIndex is zero or positive
74                         if (startIndex < 0)
75                                 throw new System.ArgumentOutOfRangeException ("startIndex", startIndex, "StartIndex cannot be less than zero.");
76
77                         // make sure length is zero or positive
78                         if(length < 0)
79                                 throw new System.ArgumentOutOfRangeException ("length", length, "Length cannot be less than zero.");
80
81                         if (capacity < 0)
82                                 throw new System.ArgumentOutOfRangeException ("capacity", capacity, "capacity must be greater than zero.");
83
84                         if (maxCapacity < 1)
85                                 throw new System.ArgumentOutOfRangeException ("maxCapacity", "maxCapacity is less than one.");
86                         if (capacity > maxCapacity)
87                                 throw new System.ArgumentOutOfRangeException ("capacity", "Capacity exceeds maximum capacity.");
88
89                         // make sure startIndex and length give a valid substring of value
90                         // re-ordered to avoid possible integer overflow
91                         if (startIndex > value.Length - length)
92                                 throw new System.ArgumentOutOfRangeException ("startIndex", startIndex, "StartIndex and length must refer to a location within the string.");
93
94                         if (capacity == 0) {
95                                 if (maxCapacity > constDefaultCapacity)
96                                         capacity = constDefaultCapacity;
97                                 else
98                                         _str = _cached_str = String.Empty;
99                         }
100                         _maxCapacity = maxCapacity;
101
102                         if (_str == null)
103                                 _str = String.InternalAllocateStr ((length > capacity) ? length : capacity);
104                         if (length > 0)
105                                 String.CharCopy (_str, 0, value, startIndex, length);
106                         
107                         _length = length;
108                 }
109
110                 public StringBuilder () : this (null) {}
111
112                 public StringBuilder(int capacity) : this (String.Empty, 0, 0, capacity) {}
113
114                 public StringBuilder(int capacity, int maxCapacity) : this (String.Empty, 0, 0, capacity, maxCapacity) { }
115
116                 public StringBuilder (string value)
117                 {
118                         /*
119                          * This is an optimization to avoid allocating the internal string
120                          * until the first Append () call.
121                          * The runtime pinvoke marshalling code needs to be aware of this.
122                          */
123                         if (null == value)
124                                 value = "";
125                         
126                         _length = value.Length;
127                         _str = _cached_str = value;
128                         _maxCapacity = Int32.MaxValue;
129                 }
130         
131                 public StringBuilder( string value, int capacity) : this(value == null ? "" : value, 0, value == null ? 0 : value.Length, capacity) {}
132         
133                 public int MaxCapacity {
134                         get {
135                                 return _maxCapacity;
136                         }
137                 }
138
139                 public int Capacity {
140                         get {
141                                 if (_str.Length == 0)
142                                         return Math.Min (_maxCapacity, constDefaultCapacity);
143                                 
144                                 return _str.Length;
145                         }
146
147                         set {
148                                 if (value < _length)
149                                         throw new ArgumentException( "Capacity must be larger than length" );
150
151                                 if (value > _maxCapacity)
152                                         throw new ArgumentOutOfRangeException ("value", "Should be less than or equal to MaxCapacity");
153
154                                 InternalEnsureCapacity(value);
155                         }
156                 }
157
158                 public int Length {
159                         get {
160                                 return _length;
161                         }
162
163                         set {
164                                 if( value < 0 || value > _maxCapacity)
165                                         throw new ArgumentOutOfRangeException();
166
167                                 if (value == _length)
168                                         return;
169
170                                 if (value < _length) {
171                                         // LAMESPEC:  The spec is unclear as to what to do
172                                         // with the capacity when truncating the string.
173
174                                         // Do as MS, keep the capacity
175                                         
176                                         // Make sure that we invalidate any cached string.
177                                         InternalEnsureCapacity (value);
178                                         _length = value;
179                                 } else {
180                                         // Expand the capacity to the new length and
181                                         // pad the string with NULL characters.
182                                         Append('\0', value - _length);
183                                 }
184                         }
185                 }
186
187                 [IndexerName("Chars")]
188                 public char this [int index] {
189                         get {
190                                 if (index >= _length || index < 0)
191                                         throw new IndexOutOfRangeException();
192
193                                 return _str [index];
194                         } 
195
196                         set {
197                                 if (index >= _length || index < 0)
198                                         throw new IndexOutOfRangeException();
199
200                                 if (null != _cached_str)
201                                         InternalEnsureCapacity (_length);
202                                 
203                                 _str.InternalSetChar (index, value);
204                         }
205                 }
206
207                 public override string ToString () 
208                 {
209                         if (_length == 0)
210                                 return String.Empty;
211
212                         if (null != _cached_str)
213                                 return _cached_str;
214
215                         // If we only have a half-full buffer we return a new string.
216                         if (_length < (_str.Length >> 1)) 
217                         {
218                                 // use String.SubstringUnchecked instead of String.Substring
219                                 // as the former is guaranteed to create a new string object
220                                 _cached_str = _str.SubstringUnchecked (0, _length);
221                                 return _cached_str;
222                         }
223
224                         _cached_str = _str;
225                         _str.InternalSetLength(_length);
226
227                         return _str;
228                 }
229
230                 public string ToString (int startIndex, int length) 
231                 {
232                         // re-ordered to avoid possible integer overflow
233                         if (startIndex < 0 || length < 0 || startIndex > _length - length)
234                                 throw new ArgumentOutOfRangeException();
235
236                         // use String.SubstringUnchecked instead of String.Substring
237                         // as the former is guaranteed to create a new string object
238                         if (startIndex == 0 && length == _length)
239                                 return ToString ();
240                         else
241                                 return _str.SubstringUnchecked (startIndex, length);
242                 }
243
244                 public int EnsureCapacity (int capacity) 
245                 {
246                         if (capacity < 0)
247                                 throw new ArgumentOutOfRangeException ("Capacity must be greater than 0." );
248
249                         if( capacity <= _str.Length )
250                                 return _str.Length;
251
252                         InternalEnsureCapacity (capacity);
253
254                         return _str.Length;
255                 }
256
257                 public bool Equals (StringBuilder sb) 
258                 {
259                         if (((object)sb) == null)
260                                 return false;
261                         
262                         if (_length == sb.Length && _str == sb._str )
263                                 return true;
264
265                         return false;
266                 }
267
268                 public StringBuilder Remove (int startIndex, int length)
269                 {
270                         // re-ordered to avoid possible integer overflow
271                         if (startIndex < 0 || length < 0 || startIndex > _length - length)
272                                 throw new ArgumentOutOfRangeException();
273                         
274                         if (null != _cached_str)
275                                 InternalEnsureCapacity (_length);
276                         
277                         // Copy everything after the 'removed' part to the start 
278                         // of the removed part and truncate the sLength
279                         if (_length - (startIndex + length) > 0)
280                                 String.CharCopy (_str, startIndex, _str, startIndex + length, _length - (startIndex + length));
281
282                         _length -= length;
283
284                         return this;
285                 }                              
286
287                 public StringBuilder Replace (char oldChar, char newChar) 
288                 {
289                         return Replace( oldChar, newChar, 0, _length);
290                 }
291
292                 public StringBuilder Replace (char oldChar, char newChar, int startIndex, int count) 
293                 {
294                         // re-ordered to avoid possible integer overflow
295                         if (startIndex > _length - count || startIndex < 0 || count < 0)
296                                 throw new ArgumentOutOfRangeException();
297
298                         if (null != _cached_str)
299                                 InternalEnsureCapacity (_str.Length);
300
301                         for (int replaceIterate = startIndex; replaceIterate < startIndex + count; replaceIterate++ ) {
302                                 if( _str [replaceIterate] == oldChar )
303                                         _str.InternalSetChar (replaceIterate, newChar);
304                         }
305
306                         return this;
307                 }
308
309                 public StringBuilder Replace( string oldValue, string newValue ) {
310                         return Replace (oldValue, newValue, 0, _length);
311                 }
312
313                 public StringBuilder Replace( string oldValue, string newValue, int startIndex, int count ) 
314                 {
315                         if (oldValue == null)
316                                 throw new ArgumentNullException ("The old value cannot be null.");
317
318                         if (startIndex < 0 || count < 0 || startIndex > _length - count)
319                                 throw new ArgumentOutOfRangeException ();
320
321                         if (oldValue.Length == 0)
322                                 throw new ArgumentException ("The old value cannot be zero length.");
323
324                         string substr = _str.Substring(startIndex, count);
325                         string replace = substr.Replace(oldValue, newValue);
326                         // return early if no oldValue was found
327                         if ((object) replace == (object) substr)
328                                 return this;
329
330                         InternalEnsureCapacity (replace.Length + (_length - count));
331
332                         // shift end part
333                         if (replace.Length < count)
334                                 String.CharCopy (_str, startIndex + replace.Length, _str, startIndex + count, _length - startIndex  - count);
335                         else if (replace.Length > count)
336                                 String.CharCopyReverse (_str, startIndex + replace.Length, _str, startIndex + count, _length - startIndex  - count);
337
338                         // copy middle part back into _str
339                         String.CharCopy (_str, startIndex, replace, 0, replace.Length);
340                         
341                         _length = replace.Length + (_length - count);
342
343                         return this;
344                 }
345
346                       
347                 /* The Append Methods */
348                 public StringBuilder Append (char[] value) 
349                 {
350                         if (value == null)
351                                 return this;
352
353                         int needed_cap = _length + value.Length;
354                         if (null != _cached_str || _str.Length < needed_cap)
355                                 InternalEnsureCapacity (needed_cap);
356                         
357                         String.CharCopy (_str, _length, value, 0, value.Length);
358                         _length = needed_cap;
359
360                         return this;
361                 } 
362                 
363                 public StringBuilder Append (string value) 
364                 {
365                         if (value == null)
366                                 return this;
367                         
368                         if (_length == 0 && value.Length < _maxCapacity && value.Length > _str.Length) {
369                                 _length = value.Length;
370                                 _str = _cached_str = value;
371                                 return this;
372                         }
373
374                         int needed_cap = _length + value.Length;
375                         if (null != _cached_str || _str.Length < needed_cap)
376                                 InternalEnsureCapacity (needed_cap);
377
378                         String.CharCopy (_str, _length, value, 0, value.Length);
379                         _length = needed_cap;
380                         return this;
381                 }
382
383                 public StringBuilder Append (bool value) {
384                         return Append (value.ToString());
385                 }
386                 
387                 public StringBuilder Append (byte value) {
388                         return Append (value.ToString());
389                 }
390
391                 public StringBuilder Append (decimal value) {
392                         return Append (value.ToString());
393                 }
394
395                 public StringBuilder Append (double value) {
396                         return Append (value.ToString());
397                 }
398
399                 public StringBuilder Append (short value) {
400                         return Append (value.ToString());
401                 }
402
403                 public StringBuilder Append (int value) {
404                         return Append (value.ToString());
405                 }
406
407                 public StringBuilder Append (long value) {
408                         return Append (value.ToString());
409                 }
410
411                 public StringBuilder Append (object value) {
412                         if (value == null)
413                                 return this;
414
415                         return Append (value.ToString());
416                 }
417
418                 [CLSCompliant(false)]
419                 public StringBuilder Append (sbyte value) {
420                         return Append (value.ToString());
421                 }
422
423                 public StringBuilder Append (float value) {
424                         return Append (value.ToString());
425                 }
426
427                 [CLSCompliant(false)]
428                 public StringBuilder Append (ushort value) {
429                         return Append (value.ToString());
430                 }       
431                 
432                 [CLSCompliant(false)]
433                 public StringBuilder Append (uint value) {
434                         return Append (value.ToString());
435                 }
436
437                 [CLSCompliant(false)]
438                 public StringBuilder Append (ulong value) {
439                         return Append (value.ToString());
440                 }
441
442                 public StringBuilder Append (char value) 
443                 {
444                         int needed_cap = _length + 1;
445                         if (null != _cached_str || _str.Length < needed_cap)
446                                 InternalEnsureCapacity (needed_cap);
447
448                         _str.InternalSetChar(_length, value);
449                         _length = needed_cap;
450
451                         return this;
452                 }
453
454                 public StringBuilder Append (char value, int repeatCount) 
455                 {
456                         if( repeatCount < 0 )
457                                 throw new ArgumentOutOfRangeException();
458
459                         InternalEnsureCapacity (_length + repeatCount);
460                         
461                         for (int i = 0; i < repeatCount; i++)
462                                 _str.InternalSetChar (_length++, value);
463
464                         return this;
465                 }
466
467                 public StringBuilder Append( char[] value, int startIndex, int charCount ) 
468                 {
469                         if (value == null) {
470                                 if (!(startIndex == 0 && charCount == 0))
471                                         throw new ArgumentNullException ("value");
472
473                                 return this;
474                         }
475
476                         if ((charCount < 0 || startIndex < 0) || (startIndex > value.Length - charCount)) 
477                                 throw new ArgumentOutOfRangeException();
478                         
479                         int needed_cap = _length + charCount;
480                         InternalEnsureCapacity (needed_cap);
481
482                         String.CharCopy (_str, _length, value, startIndex, charCount);
483                         _length = needed_cap;
484
485                         return this;
486                 }
487
488                 public StringBuilder Append (string value, int startIndex, int count) 
489                 {
490                         if (value == null) {
491                                 if (startIndex != 0 && count != 0)
492                                         throw new ArgumentNullException ("value");
493                                         
494                                 return this;
495                         }
496
497                         if ((count < 0 || startIndex < 0) || (startIndex > value.Length - count))
498                                 throw new ArgumentOutOfRangeException();
499                         
500                         int needed_cap = _length + count;
501                         if (null != _cached_str || _str.Length < needed_cap)
502                                 InternalEnsureCapacity (needed_cap);
503
504                         String.CharCopy (_str, _length, value, startIndex, count);
505                         
506                         _length = needed_cap;
507
508                         return this;
509                 }
510
511 #if NET_2_0
512                 [ComVisible (false)]
513                 public StringBuilder AppendLine ()
514                 {
515                         return Append (System.Environment.NewLine);
516                 }
517
518                 [ComVisible (false)]
519                 public StringBuilder AppendLine (string value)
520                 {
521                         return Append (value).Append (System.Environment.NewLine);
522                 }
523 #endif
524
525                 public StringBuilder AppendFormat (string format, params object[] args)
526                 {
527                         return AppendFormat (null, format, args);
528                 }
529
530                 public StringBuilder AppendFormat (IFormatProvider provider,
531                                                    string format,
532                                                    params object[] args)
533                 {
534                         String.FormatHelper (this, provider, format, args);
535                         return this;
536                 }
537
538 #if NET_2_1 && !MONOTOUCH
539                 internal
540 #else
541                 public
542 #endif
543                 StringBuilder AppendFormat (string format, object arg0)
544                 {
545                         return AppendFormat (null, format, new object [] { arg0 });
546                 }
547
548 #if NET_2_1 && !MONOTOUCH
549                 internal
550 #else
551                 public
552 #endif
553                 StringBuilder AppendFormat (string format, object arg0, object arg1)
554                 {
555                         return AppendFormat (null, format, new object [] { arg0, arg1 });
556                 }
557
558 #if NET_2_1 && !MONOTOUCH
559                 internal
560 #else
561                 public
562 #endif
563                 StringBuilder AppendFormat (string format, object arg0, object arg1, object arg2)
564                 {
565                         return AppendFormat (null, format, new object [] { arg0, arg1, arg2 });
566                 }
567
568                 /*  The Insert Functions */
569                 
570                 public StringBuilder Insert (int index, char[] value) 
571                 {
572                         return Insert (index, new string (value));
573                 }
574                                 
575                 public StringBuilder Insert (int index, string value) 
576                 {
577                         if( index > _length || index < 0)
578                                 throw new ArgumentOutOfRangeException();
579
580                         if (value == null || value.Length == 0)
581                                 return this;
582
583                         InternalEnsureCapacity (_length + value.Length);
584
585                         // Move everything to the right of the insert point across
586                         String.CharCopyReverse (_str, index + value.Length, _str, index, _length - index);
587                         
588                         // Copy in stuff from the insert buffer
589                         String.CharCopy (_str, index, value, 0, value.Length);
590                         
591                         _length += value.Length;
592
593                         return this;
594                 }
595
596                 public StringBuilder Insert( int index, bool value ) {
597                         return Insert (index, value.ToString());
598                 }
599                 
600                 public StringBuilder Insert( int index, byte value ) {
601                         return Insert (index, value.ToString());
602                 }
603
604                 public StringBuilder Insert( int index, char value) 
605                 {
606                         if (index > _length || index < 0)
607                                 throw new ArgumentOutOfRangeException ("index");
608
609                         InternalEnsureCapacity (_length + 1);
610                         
611                         // Move everything to the right of the insert point across
612                         String.CharCopyReverse (_str, index + 1, _str, index, _length - index);
613                         
614                         _str.InternalSetChar (index, value);
615                         _length++;
616
617                         return this;
618                 }
619
620                 public StringBuilder Insert( int index, decimal value ) {
621                         return Insert (index, value.ToString());
622                 }
623
624                 public StringBuilder Insert( int index, double value ) {
625                         return Insert (index, value.ToString());
626                 }
627                 
628                 public StringBuilder Insert( int index, short value ) {
629                         return Insert (index, value.ToString());
630                 }
631
632                 public StringBuilder Insert( int index, int value ) {
633                         return Insert (index, value.ToString());
634                 }
635
636                 public StringBuilder Insert( int index, long value ) {
637                         return Insert (index, value.ToString());
638                 }
639         
640                 public StringBuilder Insert( int index, object value ) {
641                         return Insert (index, value.ToString());
642                 }
643                 
644                 [CLSCompliant(false)]
645                 public StringBuilder Insert( int index, sbyte value ) {
646                         return Insert (index, value.ToString() );
647                 }
648
649                 public StringBuilder Insert (int index, float value) {
650                         return Insert (index, value.ToString() );
651                 }
652
653                 [CLSCompliant(false)]
654                 public StringBuilder Insert (int index, ushort value) {
655                         return Insert (index, value.ToString() );
656                 }
657
658                 [CLSCompliant(false)]
659                 public StringBuilder Insert (int index, uint value) {
660                         return Insert ( index, value.ToString() );
661                 }
662                 
663                 [CLSCompliant(false)]
664                 public StringBuilder Insert (int index, ulong value) {
665                         return Insert ( index, value.ToString() );
666                 }
667
668                 public StringBuilder Insert (int index, string value, int count) 
669                 {
670                         // LAMESPEC: The spec says to throw an exception if 
671                         // count < 0, while MS throws even for count < 1!
672                         if ( count < 0 )
673                                 throw new ArgumentOutOfRangeException();
674
675                         if (value != null && value != String.Empty)
676                                 for (int insertCount = 0; insertCount < count; insertCount++)
677                                         Insert( index, value );
678
679                         return this;
680                 }
681
682                 public StringBuilder Insert (int index, char [] value, int startIndex, int charCount)
683                 {
684                         if (value == null) {
685                                 if (startIndex == 0 && charCount == 0)
686                                         return this;
687
688                                 throw new ArgumentNullException ("value");
689                         }
690
691                         if (charCount < 0 || startIndex < 0 || startIndex > value.Length - charCount)
692                                 throw new ArgumentOutOfRangeException ();
693
694                         return Insert (index, new String (value, startIndex, charCount));
695                 }
696         
697                 private void InternalEnsureCapacity (int size) 
698                 {
699                         if (size > _str.Length || (object) _cached_str == (object) _str) {
700                                 int capacity = _str.Length;
701
702                                 // Try double buffer, if that doesn't work, set the length as capacity
703                                 if (size > capacity) {
704                                         
705                                         // The first time a string is appended, we just set _cached_str
706                                         // and _str to it. This allows us to do some optimizations.
707                                         // Below, we take this into account.
708                                         if ((object) _cached_str == (object) _str && capacity < constDefaultCapacity)
709                                                 capacity = constDefaultCapacity;
710                                         
711                                         capacity = capacity << 1;
712                                         if (size > capacity)
713                                                 capacity = size;
714
715                                         if (capacity >= Int32.MaxValue || capacity < 0)
716                                                 capacity = Int32.MaxValue;
717
718                                         if (capacity > _maxCapacity && size <= _maxCapacity)
719                                                 capacity = _maxCapacity;
720                                         
721                                         if (capacity > _maxCapacity)
722                                                 throw new ArgumentOutOfRangeException ("size", "capacity was less than the current size.");
723                                 }
724
725                                 string tmp = String.InternalAllocateStr (capacity);
726                                 if (_length > 0)
727                                         String.CharCopy (tmp, 0, _str, 0, _length);
728
729                                 _str = tmp;
730                         }
731
732                         _cached_str = null;
733                 }
734
735 #if NET_2_0
736                 [ComVisible (false)]
737                 public void CopyTo (int sourceIndex, char [] destination, int destinationIndex, int count)
738                 {
739                         if (destination == null)
740                                 throw new ArgumentNullException ("destination");
741                         if ((Length - count < sourceIndex) ||
742                             (destination.Length -count < destinationIndex) ||
743                             (sourceIndex < 0 || destinationIndex < 0 || count < 0))
744                                 throw new ArgumentOutOfRangeException ();
745
746                         for (int i = 0; i < count; i++)
747                                 destination [destinationIndex+i] = _str [sourceIndex+i];
748                 }
749
750                 void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
751                 {
752                         info.AddValue ("m_MaxCapacity", _maxCapacity);
753                         info.AddValue ("Capacity", Capacity);
754                         info.AddValue ("m_StringValue", ToString ());
755                         info.AddValue ("m_currentThread", 0);
756                 }
757
758                 StringBuilder (SerializationInfo info, StreamingContext context)
759                 {
760                         string s = info.GetString ("m_StringValue");
761                         if (s == null)
762                                 s = "";
763                         _length = s.Length;
764                         _str = _cached_str = s;
765                         
766                         _maxCapacity = info.GetInt32 ("m_MaxCapacity");
767                         if (_maxCapacity < 0)
768                                 _maxCapacity = Int32.MaxValue;
769                         Capacity = info.GetInt32 ("Capacity");
770                 }
771 #endif
772         }
773 }