[Tizen] Unify dnetmemoryenumlib terms to match the codebase (#291)
[platform/upstream/coreclr.git] / src / utilcode / sstring.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 // ---------------------------------------------------------------------------
5 // SString.cpp
6 // 
7
8 // ---------------------------------------------------------------------------
9
10 #include "stdafx.h"
11 #include "sstring.h"
12 #include "ex.h"
13 #include "holder.h"
14
15
16 #if defined(_MSC_VER)
17 #pragma inline_depth (25)
18 #endif
19
20 //-----------------------------------------------------------------------------
21 // Static variables
22 //-----------------------------------------------------------------------------
23
24 // Have one internal, well-known, literal for the empty string.
25 const BYTE SString::s_EmptyBuffer[2] = { 0 };
26
27 // @todo: these need to be initialized by calling GetACP()
28
29 UINT SString::s_ACP = 0;
30
31 #ifndef DACCESS_COMPILE
32 static BYTE s_EmptySpace[sizeof(SString)] = { 0 };
33 #endif // DACCESS_COMPILE
34
35 SPTR_IMPL(SString,SString,s_Empty);
36
37 void SString::Startup()
38 {
39     STATIC_CONTRACT_NOTHROW;
40     STATIC_CONTRACT_GC_NOTRIGGER;
41
42     if (s_ACP == 0)
43     {        
44         UINT ACP = GetACP();
45
46 #ifndef DACCESS_COMPILE
47         s_Empty = PTR_SString(new (s_EmptySpace) SString());
48         s_Empty->SetNormalized();
49 #endif // DACCESS_COMPILE
50
51         MemoryBarrier();
52         s_ACP = ACP;
53     }
54 }
55
56 CHECK SString::CheckStartup()
57 {
58     WRAPPER_NO_CONTRACT;
59
60     CHECK(s_Empty != NULL);
61     CHECK_OK;
62 }
63
64 //-----------------------------------------------------------------------------
65 // Case insensitive helpers.
66 //-----------------------------------------------------------------------------
67
68 static WCHAR MapChar(WCHAR wc, DWORD dwFlags)
69 {
70     WRAPPER_NO_CONTRACT;
71
72     WCHAR                     wTmp;
73
74 #ifndef FEATURE_PAL
75     
76     int iRet = ::LCMapStringEx(LOCALE_NAME_INVARIANT, dwFlags, &wc, 1, &wTmp, 1, NULL, NULL, 0);
77     if (!iRet) {
78         // This can fail in non-exceptional cases becauseof unknown unicode characters. 
79         wTmp = wc;
80     }
81
82 #else // !FEATURE_PAL
83     // For PAL, no locale specific processing is done
84
85     if (dwFlags == LCMAP_UPPERCASE)
86     {
87         wTmp =
88 #ifdef SELF_NO_HOST
89             toupper(wc);
90 #else
91             PAL_ToUpperInvariant(wc);
92 #endif
93     }
94     else
95     {
96         _ASSERTE(dwFlags == LCMAP_LOWERCASE);
97         wTmp =
98 #ifdef SELF_NO_HOST
99             tolower(wc);
100 #else
101             PAL_ToLowerInvariant(wc);
102 #endif
103     }
104 #endif // !FEATURE_PAL
105
106     return wTmp;
107 }
108
109 #define IS_UPPER_A_TO_Z(x) (((x) >= W('A')) && ((x) <= W('Z')))
110 #define IS_LOWER_A_TO_Z(x) (((x) >= W('a')) && ((x) <= W('z')))
111 #define CAN_SIMPLE_UPCASE(x) (((x)&~0x7f) == 0)
112 #define CAN_SIMPLE_DOWNCASE(x) (((x)&~0x7f) == 0)
113 #define SIMPLE_UPCASE(x) (IS_LOWER_A_TO_Z(x) ? ((x) - W('a') + W('A')) : (x))
114 #define SIMPLE_DOWNCASE(x) (IS_UPPER_A_TO_Z(x) ? ((x) - W('A') + W('a')) : (x))
115
116 /* static */
117 int SString::CaseCompareHelper(const WCHAR *buffer1, const WCHAR *buffer2, COUNT_T count, BOOL stopOnNull, BOOL stopOnCount)
118 {
119     LIMITED_METHOD_CONTRACT;
120
121     _ASSERTE(stopOnNull || stopOnCount);
122
123     const WCHAR *buffer1End = buffer1 + count;
124     int diff = 0;
125
126     while (!stopOnCount || (buffer1 < buffer1End))
127     {
128         WCHAR ch1 = *buffer1++;
129         WCHAR ch2 = *buffer2++;
130         diff = ch1 - ch2;
131         if ((ch1 == 0) || (ch2 == 0)) 
132         {
133             if  (diff != 0 || stopOnNull) 
134             {
135                 break;
136             }
137         }
138         else 
139         {
140             if (diff != 0)
141             {
142                 diff = ((CAN_SIMPLE_UPCASE(ch1) ? SIMPLE_UPCASE(ch1) : MapChar(ch1, LCMAP_UPPERCASE))
143                         - (CAN_SIMPLE_UPCASE(ch2) ? SIMPLE_UPCASE(ch2) : MapChar(ch2, LCMAP_UPPERCASE)));
144             }
145             if (diff != 0) 
146             {
147                 break;
148             }
149         }
150     }
151
152     return diff;
153 }
154
155 #define IS_LOWER_A_TO_Z_ANSI(x) (((x) >= 'a') && ((x) <= 'z'))
156 #define CAN_SIMPLE_UPCASE_ANSI(x) (((x) >= 0x20) && ((x) <= 0x7f))
157 #define SIMPLE_UPCASE_ANSI(x) (IS_LOWER_A_TO_Z(x) ? ((x) - 'a' + 'A') : (x))
158
159 int GetCaseInsensitiveValueA(const CHAR *buffer, int length) {
160     LIMITED_METHOD_CONTRACT;
161     _ASSERTE(buffer != NULL);
162     _ASSERTE(length == 1 || ((length == 2) && IsDBCSLeadByte(*buffer)));    
163
164     WCHAR wideCh;
165     int sortValue;
166     int conversionReturn = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, buffer, length, &wideCh, 1);            
167     if (conversionReturn == 0) 
168     {
169         // An invalid sequence should only compare equal to itself, so use a negative mapping.
170         if (length == 1) 
171         {
172             sortValue = -((int)((unsigned char)(*buffer)));
173         }
174         else 
175         {
176             sortValue = -(((((int)((unsigned char)(*buffer))) << 8) | ((int)((unsigned char)(*(buffer + 1))))));        
177         }        
178     }
179     else 
180     {
181         _ASSERTE(conversionReturn == 1);
182         sortValue = MapChar(wideCh, LCMAP_UPPERCASE);
183     }
184     return sortValue;
185 }
186
187 /* static */
188 int SString::CaseCompareHelperA(const CHAR *buffer1, const CHAR *buffer2, COUNT_T count, BOOL stopOnNull, BOOL stopOnCount)
189 {
190     LIMITED_METHOD_CONTRACT;
191     
192     _ASSERTE(stopOnNull || stopOnCount);
193
194     const CHAR *buffer1End = buffer1 + count;
195     int diff = 0;
196
197     while (!stopOnCount || (buffer1 < buffer1End))
198     {
199         CHAR ch1 = *buffer1;
200         CHAR ch2 = *buffer2;
201         if ((ch1 == 0) || (ch2 == 0)) 
202         {
203             diff = ch1 - ch2;
204             if  (diff != 0 || stopOnNull) 
205             {
206                 break;
207             }
208             buffer1++;
209             buffer2++;
210         }
211         else if (CAN_SIMPLE_UPCASE_ANSI(ch1) && CAN_SIMPLE_UPCASE_ANSI(ch2)) 
212         {
213             diff = ch1 - ch2;
214             if (diff != 0) 
215             {
216                 diff = (SIMPLE_UPCASE_ANSI(ch1) - SIMPLE_UPCASE_ANSI(ch2));
217                 if (diff != 0)
218                 {
219                     break;
220                 }
221             }
222             buffer1++;
223             buffer2++;
224         }
225         else 
226         {
227             int length = 1;
228             if (IsDBCSLeadByte(ch1) 
229                 && IsDBCSLeadByte(ch2)
230                 && (!stopOnCount || ((buffer1 + 1) < buffer1End))) 
231             {
232                 length = 2;
233             }
234             int sortValue1 = GetCaseInsensitiveValueA(buffer1, length);
235             int sortValue2 = GetCaseInsensitiveValueA(buffer2, length);
236             diff = sortValue1 - sortValue2;
237             if (diff != 0) 
238             {
239                 break;
240             }
241             buffer1 += length;
242             buffer2 += length;
243         }
244     }
245     return diff;
246 }
247
248
249 int CaseHashHelper(const WCHAR *buffer, COUNT_T count)
250 {
251     LIMITED_METHOD_CONTRACT;
252
253     const WCHAR *bufferEnd = buffer + count;
254     ULONG hash = 5381;
255
256     while (buffer < bufferEnd)
257     {
258         WCHAR ch = *buffer++;
259         ch = CAN_SIMPLE_UPCASE(ch) ? SIMPLE_UPCASE(ch) : MapChar(ch, LCMAP_UPPERCASE);
260
261         hash = (((hash << 5) + hash) ^ ch);
262     }
263
264     return hash;
265 }
266
267 static int CaseHashHelperA(const CHAR *buffer, COUNT_T count)
268 {
269     LIMITED_METHOD_CONTRACT;
270
271     const CHAR *bufferEnd = buffer + count;
272     ULONG hash = 5381;
273
274     while (buffer < bufferEnd)
275     {
276         CHAR ch = *buffer++;
277         ch = SIMPLE_UPCASE_ANSI(ch);
278
279         hash = (((hash << 5) + hash) ^ ch);
280     }
281
282     return hash;
283 }
284
285 //-----------------------------------------------------------------------------
286 // Set this string to a copy of the unicode string
287 //-----------------------------------------------------------------------------
288 void SString::Set(const WCHAR *string)
289 {
290     CONTRACT_VOID
291     {
292         INSTANCE_CHECK;
293         PRECONDITION(CheckPointer(string, NULL_OK));
294         THROWS;
295         GC_NOTRIGGER;
296         SUPPORTS_DAC_HOST_ONLY;
297     }
298     CONTRACT_END;
299
300     if (string == NULL || *string == 0)
301         Clear();
302     else
303     {
304         Resize((COUNT_T) wcslen(string), REPRESENTATION_UNICODE);
305         wcscpy_s(GetRawUnicode(), GetBufferSizeInCharIncludeNullChar(), string);
306     }
307
308     RETURN;
309 }
310
311 //-----------------------------------------------------------------------------
312 // Set this string to a copy of the first count characters of the given
313 // unicode string.
314 //-----------------------------------------------------------------------------
315 void SString::Set(const WCHAR *string, COUNT_T count)
316 {
317     SS_CONTRACT_VOID
318     {
319         INSTANCE_CHECK;
320         PRECONDITION(CheckPointer(string, NULL_OK));
321         PRECONDITION(CheckCount(count));
322         THROWS;
323         GC_NOTRIGGER;
324     }
325     SS_CONTRACT_END;
326
327     if (count == 0)
328         Clear();
329     else
330     {
331         Resize(count, REPRESENTATION_UNICODE);
332         wcsncpy_s(GetRawUnicode(), GetBufferSizeInCharIncludeNullChar(), string, count);
333         GetRawUnicode()[count] = 0;
334     }
335
336     SS_RETURN;
337 }
338
339 //-----------------------------------------------------------------------------
340 // Set this string to a point to the first count characters of the given
341 // preallocated unicode string (shallow copy). 
342 //-----------------------------------------------------------------------------
343 void SString::SetPreallocated(const WCHAR *string, COUNT_T count)
344 {
345     SS_CONTRACT_VOID
346     {
347         INSTANCE_CHECK;
348         PRECONDITION(CheckPointer(string, NULL_OK));
349         PRECONDITION(CheckCount(count));
350         SS_POSTCONDITION(IsEmpty());
351         GC_NOTRIGGER;
352         NOTHROW;
353         SUPPORTS_DAC_HOST_ONLY;
354     }
355     SS_CONTRACT_END;
356
357     SetImmutable();
358     SetImmutable((BYTE*) string, count*2);
359     ClearAllocated();
360     SetRepresentation(REPRESENTATION_UNICODE);
361
362     SS_RETURN;
363 }
364
365 //-----------------------------------------------------------------------------
366 // Set this string to a copy of the given ansi string
367 //-----------------------------------------------------------------------------
368 void SString::SetASCII(const ASCII *string)
369 {
370     SS_CONTRACT_VOID
371     {
372         INSTANCE_CHECK;
373         PRECONDITION(CheckPointer(string, NULL_OK));
374         PRECONDITION(CheckASCIIString(string));
375         THROWS;
376         GC_NOTRIGGER;
377     }
378     SS_CONTRACT_END;
379
380     if (string == NULL || *string == 0)
381         Clear();
382     else
383     {
384         Resize((COUNT_T) strlen(string), REPRESENTATION_ASCII);
385         strcpy_s(GetRawUTF8(), GetBufferSizeInCharIncludeNullChar(), string);
386     }
387
388     SS_RETURN;
389 }
390
391 //-----------------------------------------------------------------------------
392 // Set this string to a copy of the first count characters of the given
393 // ascii string
394 //-----------------------------------------------------------------------------
395 void SString::SetASCII(const ASCII *string, COUNT_T count)
396 {
397     SS_CONTRACT_VOID
398     {
399         INSTANCE_CHECK;
400         PRECONDITION(CheckPointer(string, NULL_OK));
401         PRECONDITION(CheckASCIIString(string, count));
402         PRECONDITION(CheckCount(count));
403         THROWS;
404         GC_NOTRIGGER;
405     }
406     SS_CONTRACT_END;
407
408     if (count == 0)
409         Clear();
410     else
411     {
412         Resize(count, REPRESENTATION_ASCII);
413         strncpy_s(GetRawASCII(), GetBufferSizeInCharIncludeNullChar(), string, count);
414         GetRawASCII()[count] = 0;
415     }
416
417     SS_RETURN;
418 }
419
420 //-----------------------------------------------------------------------------
421 // Set this string to a copy of the given UTF8 string
422 //-----------------------------------------------------------------------------
423 void SString::SetUTF8(const UTF8 *string)
424 {
425     SS_CONTRACT_VOID
426     {
427         // !!! Check for illegal UTF8 encoding?
428         INSTANCE_CHECK;
429         PRECONDITION(CheckPointer(string, NULL_OK));
430         THROWS;
431         GC_NOTRIGGER;
432         SUPPORTS_DAC_HOST_ONLY;
433     }
434     SS_CONTRACT_END;
435
436     if (string == NULL || *string == 0)
437         Clear();
438     else
439     {
440         Resize((COUNT_T) strlen(string), REPRESENTATION_UTF8);
441         strcpy_s(GetRawUTF8(), GetBufferSizeInCharIncludeNullChar(), string);
442     }
443
444     SS_RETURN;
445 }
446
447 //-----------------------------------------------------------------------------
448 // Set this string to a copy of the first count characters of the given
449 // UTF8 string.
450 //-----------------------------------------------------------------------------
451 void SString::SetUTF8(const UTF8 *string, COUNT_T count)
452 {
453     SS_CONTRACT_VOID
454     {
455         // !!! Check for illegal UTF8 encoding?
456         INSTANCE_CHECK;
457         PRECONDITION(CheckPointer(string, NULL_OK));
458         PRECONDITION(CheckCount(count));
459         THROWS;
460         GC_NOTRIGGER;
461     }
462     SS_CONTRACT_END;
463
464     if (count == 0)
465         Clear();
466     else
467     {
468         Resize(count, REPRESENTATION_UTF8);
469         strncpy_s(GetRawUTF8(), GetBufferSizeInCharIncludeNullChar(), string, count);
470         GetRawUTF8()[count] = 0;
471     }
472
473     SS_RETURN;
474 }
475
476 //-----------------------------------------------------------------------------
477 // Set this string to a copy of the given ANSI string
478 //-----------------------------------------------------------------------------
479 void SString::SetANSI(const ANSI *string)
480 {
481     SS_CONTRACT_VOID
482     {
483         INSTANCE_CHECK;
484         PRECONDITION(CheckPointer(string, NULL_OK));
485         THROWS;
486         GC_NOTRIGGER;
487     }
488     SS_CONTRACT_END;
489
490     if (string == NULL || *string == 0)
491         Clear();
492     else
493     {
494         Resize((COUNT_T) strlen(string), REPRESENTATION_ANSI);
495         strcpy_s(GetRawANSI(), GetBufferSizeInCharIncludeNullChar(), string);
496     }
497
498     SS_RETURN;
499 }
500
501 //-----------------------------------------------------------------------------
502 // Set this string to a copy of the first count characters of the given
503 // ANSI string.
504 //-----------------------------------------------------------------------------
505 void SString::SetANSI(const ANSI *string, COUNT_T count)
506 {
507     SS_CONTRACT_VOID
508     {
509         INSTANCE_CHECK;
510         PRECONDITION(CheckPointer(string, NULL_OK));
511         PRECONDITION(CheckCount(count));
512         THROWS;
513         GC_NOTRIGGER;
514     }
515     SS_CONTRACT_END;
516
517     if (count == 0)
518         Clear();
519     else
520     {
521         Resize(count, REPRESENTATION_ANSI);
522         strncpy_s(GetRawANSI(), GetBufferSizeInCharIncludeNullChar(), string, count);
523         GetRawANSI()[count] = 0;
524     }
525
526     SS_RETURN;
527 }
528
529 //-----------------------------------------------------------------------------
530 // Set this string to the given unicode character
531 //-----------------------------------------------------------------------------
532 void SString::Set(WCHAR character)
533 {
534     SS_CONTRACT_VOID
535     {
536         INSTANCE_CHECK;
537         THROWS;
538         GC_NOTRIGGER;
539         SUPPORTS_DAC_HOST_ONLY;
540     }
541     SS_CONTRACT_END;
542
543     if (character == 0)
544         Clear();
545     else
546     {
547         Resize(1, REPRESENTATION_UNICODE);
548         GetRawUnicode()[0] = character;
549         GetRawUnicode()[1] = 0;
550     }
551
552     SS_RETURN;
553 }
554
555 //-----------------------------------------------------------------------------
556 // Set this string to the given UTF8 character
557 //-----------------------------------------------------------------------------
558 void SString::SetUTF8(CHAR character)
559 {
560     SS_CONTRACT_VOID
561     {
562         INSTANCE_CHECK;
563         THROWS;
564         GC_NOTRIGGER;
565     }
566     SS_CONTRACT_END;
567
568     if (character == 0)
569         Clear();
570     else
571     {
572         Resize(1, REPRESENTATION_UTF8);
573         GetRawUTF8()[0] = character;
574         GetRawUTF8()[1] = 0;
575     }
576
577     SS_RETURN;
578 }
579
580
581 //-----------------------------------------------------------------------------
582 // Set this string to the given ansi literal.
583 // This will share the memory and not make a copy.
584 //-----------------------------------------------------------------------------
585 void SString::SetLiteral(const ASCII *literal)
586 {
587     SS_CONTRACT_VOID
588     {
589         INSTANCE_CHECK;
590         PRECONDITION(CheckPointer(literal));
591         PRECONDITION(CheckASCIIString(literal));
592         THROWS;
593         GC_NOTRIGGER;
594     }
595     SS_CONTRACT_END;
596
597     SString s(Literal, literal);
598     Set(s);
599
600     SS_RETURN;
601 }
602
603 //-----------------------------------------------------------------------------
604 // Set this string to the given unicode literal.
605 // This will share the memory and not make a copy.
606 //-----------------------------------------------------------------------------
607 void SString::SetLiteral(const WCHAR *literal)
608 {
609     SS_CONTRACT_VOID
610     {
611         INSTANCE_CHECK;
612         PRECONDITION(CheckPointer(literal));
613         THROWS;
614         GC_NOTRIGGER;
615     }
616     SS_CONTRACT_END;
617
618     SString s(Literal, literal);
619     Set(s);
620
621     SS_RETURN;
622 }
623
624 //-----------------------------------------------------------------------------
625 // Hash the string contents
626 //-----------------------------------------------------------------------------
627 ULONG SString::Hash() const
628 {
629     SS_CONTRACT(ULONG)
630     {
631         INSTANCE_CHECK;
632         THROWS_UNLESS_NORMALIZED;
633         GC_NOTRIGGER;
634     }
635     SS_CONTRACT_END;
636
637     ConvertToUnicode();
638
639     SS_RETURN HashString(GetRawUnicode());
640 }
641
642 //-----------------------------------------------------------------------------
643 // Hash the string contents
644 //-----------------------------------------------------------------------------
645 ULONG SString::HashCaseInsensitive() const
646 {
647     SS_CONTRACT(ULONG)
648     {
649         INSTANCE_CHECK;
650         THROWS_UNLESS_NORMALIZED;
651         GC_NOTRIGGER;
652     }
653     SS_CONTRACT_END;
654
655     ConvertToIteratable();
656
657     ULONG result;
658
659     switch (GetRepresentation())
660     {
661     case REPRESENTATION_UNICODE:
662     case REPRESENTATION_EMPTY:
663         result = CaseHashHelper(GetRawUnicode(), GetRawCount());
664         break;
665
666     case REPRESENTATION_ASCII:
667         result = CaseHashHelperA(GetRawASCII(), GetRawCount());
668         break;
669
670     default:
671         UNREACHABLE();
672     }
673
674     SS_RETURN result;
675 }
676
677 //-----------------------------------------------------------------------------
678 // Truncate this string to count characters.
679 //-----------------------------------------------------------------------------
680 void SString::Truncate(const Iterator &i)
681 {
682     SS_CONTRACT_VOID
683     {
684         INSTANCE_CHECK;
685         PRECONDITION(CheckIteratorRange(i));
686         SS_POSTCONDITION(GetRawCount() == i - Begin());
687         THROWS;
688         GC_NOTRIGGER;
689         SUPPORTS_DAC_HOST_ONLY;
690     }
691     SS_CONTRACT_END;
692
693     CONSISTENCY_CHECK(IsFixedSize());
694
695     COUNT_T size = i - Begin();
696
697     Resize(size, GetRepresentation(), PRESERVE);
698
699     i.Resync(this, (BYTE *) (GetRawUnicode() + size));
700
701     SS_RETURN;
702 }
703
704 //-----------------------------------------------------------------------------
705 // Convert the ASCII representation for this String to Unicode. We can do this
706 // quickly and in-place (if this == &dest), which is why it is optimized.
707 //-----------------------------------------------------------------------------
708 void SString::ConvertASCIIToUnicode(SString &dest) const
709 {
710     CONTRACT_VOID
711     {
712         PRECONDITION(IsRepresentation(REPRESENTATION_ASCII));
713         POSTCONDITION(dest.IsRepresentation(REPRESENTATION_UNICODE));
714         THROWS;
715         GC_NOTRIGGER;
716         SUPPORTS_DAC_HOST_ONLY;
717     }
718     CONTRACT_END;
719
720     // Handle the empty case.
721     if (IsEmpty())
722     {
723         dest.Clear();
724         RETURN;
725     }
726
727     CONSISTENCY_CHECK(CheckPointer(GetRawASCII()));
728     CONSISTENCY_CHECK(GetRawCount() > 0);
729
730     // If dest is the same as this, then we need to preserve on resize. 
731     dest.Resize(GetRawCount(), REPRESENTATION_UNICODE,
732                 this == &dest ? PRESERVE : DONT_PRESERVE);
733
734     // Make sure the buffer is big enough.
735     CONSISTENCY_CHECK(dest.GetAllocation() > (GetRawCount() * sizeof(WCHAR)));
736
737     // This is a poor man's widen. Since we know that the representation is ASCII,
738     // we can just pad the string with a bunch of zero-value bytes. Of course,
739     // we move from the end of the string to the start so that we can convert in
740     // place (in the case that &dest == this).
741     WCHAR *outBuf = dest.GetRawUnicode() + dest.GetRawCount();
742     ASCII *inBuf = GetRawASCII() + GetRawCount();
743
744     while (GetRawASCII() <= inBuf)
745     {
746         CONSISTENCY_CHECK(dest.GetRawUnicode() <= outBuf);
747         // The casting zero-extends the value, thus giving us the zero-valued byte.
748         *outBuf = (WCHAR) *inBuf;
749         outBuf--;
750         inBuf--;
751     }
752
753     RETURN;
754 }
755
756 //-----------------------------------------------------------------------------
757 // Convert the internal representation for this String to Unicode.
758 //-----------------------------------------------------------------------------
759 void SString::ConvertToUnicode() const
760 {
761     CONTRACT_VOID
762     {
763         POSTCONDITION(IsRepresentation(REPRESENTATION_UNICODE));
764         if (IsRepresentation(REPRESENTATION_UNICODE)) NOTHROW; else THROWS;
765         GC_NOTRIGGER;
766         SUPPORTS_DAC_HOST_ONLY;
767     }
768     CONTRACT_END;
769
770     if (!IsRepresentation(REPRESENTATION_UNICODE))
771     {
772         if (IsRepresentation(REPRESENTATION_ASCII))
773         {
774             ConvertASCIIToUnicode(*(const_cast<SString *>(this)));
775         }
776         else
777         {
778             StackSString s;
779             ConvertToUnicode(s);
780             PREFIX_ASSUME(!s.IsImmutable());
781             (const_cast<SString*>(this))->Set(s);
782         }
783     }
784
785     RETURN;
786 }
787
788 //-----------------------------------------------------------------------------
789 // Convert the internal representation for this String to Unicode, while
790 // preserving the iterator if the conversion is done.
791 //-----------------------------------------------------------------------------
792 void SString::ConvertToUnicode(const CIterator &i) const
793 {
794     CONTRACT_VOID
795     {
796         PRECONDITION(i.Check());
797         POSTCONDITION(IsRepresentation(REPRESENTATION_UNICODE));
798         if (IsRepresentation(REPRESENTATION_UNICODE)) NOTHROW; else THROWS;
799         GC_NOTRIGGER;
800         SUPPORTS_DAC_HOST_ONLY;
801     }
802     CONTRACT_END;
803
804     if (!IsRepresentation(REPRESENTATION_UNICODE))
805     {
806         CONSISTENCY_CHECK(IsFixedSize());
807
808         COUNT_T index = 0;
809         // Get the current index of the iterator
810         if (i.m_ptr != NULL)
811         {
812             CONSISTENCY_CHECK(GetCharacterSizeShift() == 0);
813             index = (COUNT_T) (i.m_ptr - m_buffer);
814         }
815
816         if (IsRepresentation(REPRESENTATION_ASCII))
817         {
818             ConvertASCIIToUnicode(*(const_cast<SString *>(this)));
819         }
820         else
821         {
822             StackSString s;
823             ConvertToUnicode(s);
824             (const_cast<SString*>(this))->Set(s);
825         }
826
827         // Move the iterator to the new location.
828         if (i.m_ptr != NULL)
829         {
830             i.Resync(this, (BYTE *) (GetRawUnicode() + index));
831         }
832     }
833
834     RETURN;
835 }
836
837 //-----------------------------------------------------------------------------
838 // Set s to be a copy of this string's contents, but in the unicode format.
839 //-----------------------------------------------------------------------------
840 void SString::ConvertToUnicode(SString &s) const
841 {
842     CONTRACT_VOID
843     {
844         PRECONDITION(s.Check());
845         POSTCONDITION(s.IsRepresentation(REPRESENTATION_UNICODE));
846         THROWS;
847         GC_NOTRIGGER;
848         SUPPORTS_DAC_HOST_ONLY;
849     }
850     CONTRACT_END;
851
852     int page = 0;
853
854     switch (GetRepresentation())
855     {
856     case REPRESENTATION_EMPTY:
857         s.Clear();
858         RETURN;
859
860     case REPRESENTATION_UNICODE:
861         s.Set(*this);
862         RETURN;
863
864     case REPRESENTATION_UTF8:
865         page = CP_UTF8;
866         break;
867
868     case REPRESENTATION_ASCII:
869         ConvertASCIIToUnicode(s);
870         RETURN;
871
872     case REPRESENTATION_ANSI:
873         page = CP_ACP;
874         break;
875
876     default:
877         UNREACHABLE();
878     }
879
880     COUNT_T length = WszMultiByteToWideChar(page, 0, GetRawANSI(), GetRawCount()+1, 0, 0);
881     if (length == 0)
882         ThrowLastError();
883
884     s.Resize(length-1, REPRESENTATION_UNICODE);
885
886     length = WszMultiByteToWideChar(page, 0, GetRawANSI(), GetRawCount()+1, s.GetRawUnicode(), length);
887     if (length == 0)
888         ThrowLastError();
889
890     RETURN;
891 }
892
893 //-----------------------------------------------------------------------------
894 // Set s to be a copy of this string's contents, but in the ANSI format.
895 //-----------------------------------------------------------------------------
896 void SString::ConvertToANSI(SString &s) const
897 {
898     CONTRACT_VOID
899     {
900         PRECONDITION(s.Check());
901         POSTCONDITION(s.IsRepresentation(REPRESENTATION_ANSI));
902         THROWS;
903         GC_NOTRIGGER;
904     }
905     CONTRACT_END;
906
907     switch (GetRepresentation())
908     {
909     case REPRESENTATION_EMPTY:
910         s.Clear();
911         RETURN;
912
913     case REPRESENTATION_ASCII:
914     case REPRESENTATION_ANSI:
915         s.Set(*this);
916         RETURN;
917
918     case REPRESENTATION_UTF8:
919         // No direct conversion to ANSI
920         ConvertToUnicode();
921         // fall through
922
923     case REPRESENTATION_UNICODE:
924         break;
925
926     default:
927         UNREACHABLE();
928     }
929
930     // @todo: use WC_NO_BEST_FIT_CHARS
931     COUNT_T length = WszWideCharToMultiByte(CP_ACP, 0, GetRawUnicode(), GetRawCount()+1,
932                                         NULL, 0, NULL, NULL);
933
934     s.Resize(length-1, REPRESENTATION_ANSI);
935
936     // @todo: use WC_NO_BEST_FIT_CHARS
937     length = WszWideCharToMultiByte(CP_ACP, 0, GetRawUnicode(), GetRawCount()+1,
938                                     s.GetRawANSI(), length, NULL, NULL);
939     if (length == 0)
940         ThrowLastError();
941
942     RETURN;
943 }
944
945 //-----------------------------------------------------------------------------
946 // Set s to be a copy of this string's contents, but in the utf8 format.
947 //-----------------------------------------------------------------------------
948 COUNT_T SString::ConvertToUTF8(SString &s) const
949 {
950     CONTRACT(COUNT_T)
951     {
952         PRECONDITION(s.Check());
953         POSTCONDITION(s.IsRepresentation(REPRESENTATION_UTF8));
954         THROWS;
955         GC_NOTRIGGER;
956     }
957     CONTRACT_END;
958
959     switch (GetRepresentation())
960     {
961     case REPRESENTATION_EMPTY:
962         s.Clear();
963         RETURN 1;
964
965     case REPRESENTATION_ASCII:
966     case REPRESENTATION_UTF8:
967         s.Set(*this);
968         RETURN s.GetRawCount()+1;
969
970     case REPRESENTATION_ANSI:
971         // No direct conversion from ANSI to UTF8
972         ConvertToUnicode();
973         // fall through
974
975     case REPRESENTATION_UNICODE:
976         break;
977
978     default:
979         UNREACHABLE();
980     }
981
982     // <TODO> @todo: use WC_NO_BEST_FIT_CHARS </TODO>
983     bool  allAscii;
984     DWORD length;
985
986     HRESULT hr = FString::Unicode_Utf8_Length(GetRawUnicode(), & allAscii, & length);
987
988     if (SUCCEEDED(hr))
989     {
990         s.Resize(length, REPRESENTATION_UTF8);
991
992         //FString::Unicode_Utf8 expects an array all the time
993         //we optimize the empty string by replacing it with null for SString above in Resize
994         if (length > 0)
995         {
996             hr = FString::Unicode_Utf8(GetRawUnicode(), allAscii, (LPSTR) s.GetRawUTF8(), length);
997         }
998     }
999
1000     IfFailThrow(hr);
1001
1002     RETURN length + 1;
1003 }
1004
1005 //-----------------------------------------------------------------------------
1006 // Replace a single character with another character.
1007 //-----------------------------------------------------------------------------
1008 void SString::Replace(const Iterator &i, WCHAR c)
1009 {
1010     CONTRACT_VOID
1011     {
1012         INSTANCE_CHECK;
1013         PRECONDITION(CheckIteratorRange(i, 1));
1014         POSTCONDITION(Match(i, c));
1015         THROWS;
1016         GC_NOTRIGGER;
1017     }
1018     CONTRACT_END;
1019
1020     if (IsRepresentation(REPRESENTATION_ASCII) && ((c&~0x7f) == 0))
1021     {
1022         *(BYTE*)i.m_ptr = (BYTE) c;
1023     }
1024     else
1025     {
1026         ConvertToUnicode(i);
1027
1028         *(USHORT*)i.m_ptr = c;
1029     }
1030
1031     RETURN;
1032 }
1033
1034 //-----------------------------------------------------------------------------
1035 // Replace the substring specified by position, length with the given string s.
1036 //-----------------------------------------------------------------------------
1037 void SString::Replace(const Iterator &i, COUNT_T length, const SString &s)
1038 {
1039     CONTRACT_VOID
1040     {
1041         INSTANCE_CHECK;
1042         PRECONDITION(CheckIteratorRange(i, length));
1043         PRECONDITION(s.Check());
1044         POSTCONDITION(Match(i, s));
1045         THROWS;
1046         GC_NOTRIGGER;
1047         SUPPORTS_DAC_HOST_ONLY;
1048     }
1049     CONTRACT_END;
1050
1051     Representation representation = GetRepresentation();
1052     if (representation == REPRESENTATION_EMPTY)
1053     {
1054         // This special case contains some optimizations (like literal sharing).
1055         Set(s);
1056         ConvertToIteratable();
1057         i.Resync(this, m_buffer);
1058     }
1059     else
1060     {
1061         StackSString temp;
1062         const SString &source = GetCompatibleString(s, temp, i);
1063
1064         COUNT_T deleteSize = length<<GetCharacterSizeShift();
1065         COUNT_T insertSize = source.GetRawCount()<<source.GetCharacterSizeShift();
1066
1067         SBuffer::Replace(i, deleteSize, insertSize);
1068         SBuffer::Copy(i, source.m_buffer, insertSize);
1069     }
1070
1071     RETURN;
1072 }
1073
1074 //-----------------------------------------------------------------------------
1075 // Find s in this string starting at i. Return TRUE & update iterator if found.
1076 //-----------------------------------------------------------------------------
1077 BOOL SString::Find(CIterator &i, const SString &s) const
1078 {
1079     CONTRACT(BOOL)
1080     {
1081         INSTANCE_CHECK;
1082         PRECONDITION(CheckIteratorRange(i));
1083         PRECONDITION(s.Check());
1084         POSTCONDITION(RETVAL == Match(i, s));
1085         THROWS_UNLESS_BOTH_NORMALIZED(s);
1086         GC_NOTRIGGER;
1087     }
1088     CONTRACT_END;
1089
1090     // Get a compatible string from s
1091     StackSString temp;
1092     const SString &source = GetCompatibleString(s, temp, i);
1093
1094     switch (GetRepresentation())
1095     {
1096     case REPRESENTATION_UNICODE:
1097         {
1098             COUNT_T count = source.GetRawCount();
1099             const WCHAR *start = i.GetUnicode();
1100             const WCHAR *end = GetUnicode() + GetRawCount() - count;
1101             while (start <= end)
1102             {
1103                 if (wcsncmp(start, source.GetRawUnicode(), count) == 0)
1104                 {
1105                     i.Resync(this, (BYTE*) start);
1106                     RETURN TRUE;
1107                 }
1108                 start++;
1109             }
1110         }
1111         break;
1112
1113     case REPRESENTATION_ANSI:
1114     case REPRESENTATION_ASCII:
1115         {
1116             COUNT_T count = source.GetRawCount();
1117             const CHAR *start = i.GetASCII();
1118             const CHAR *end = GetRawASCII() + GetRawCount() - count;
1119             while (start <= end)
1120             {
1121                 if (strncmp(start, source.GetRawASCII(), count) == 0)
1122                 {
1123                     i.Resync(this, (BYTE*) start);
1124                     RETURN TRUE;
1125                 }
1126                 start++;
1127             }
1128         }
1129         break;
1130
1131     case REPRESENTATION_EMPTY:
1132         {
1133             if (source.GetRawCount() == 0)
1134                 RETURN TRUE;
1135         }
1136         break;
1137
1138     case REPRESENTATION_UTF8:
1139     default:
1140         UNREACHABLE();
1141     }
1142
1143     RETURN FALSE;
1144 }
1145
1146 //-----------------------------------------------------------------------------
1147 // Find s in this string starting at i. Return TRUE & update iterator if found.
1148 //-----------------------------------------------------------------------------
1149 BOOL SString::Find(CIterator &i, WCHAR c) const
1150 {
1151     CONTRACT(BOOL)
1152     {
1153         INSTANCE_CHECK;
1154         PRECONDITION(CheckIteratorRange(i));
1155         POSTCONDITION(RETVAL == Match(i, c));
1156         THROWS_UNLESS_NORMALIZED;
1157         GC_NOTRIGGER;
1158     }
1159     CONTRACT_END;
1160
1161     // Get a compatible string
1162     if (c & ~0x7f)
1163         ConvertToUnicode(i);
1164
1165     switch (GetRepresentation())
1166     {
1167     case REPRESENTATION_UNICODE:
1168         {
1169             const WCHAR *start = i.GetUnicode();
1170             const WCHAR *end = GetUnicode() + GetRawCount() - 1;
1171             while (start <= end)
1172             {
1173                 if (*start == c)
1174                 {
1175                     i.Resync(this, (BYTE*) start);
1176                     RETURN TRUE;
1177                 }
1178                 start++;
1179             }
1180         }
1181         break;
1182
1183     case REPRESENTATION_ANSI:
1184     case REPRESENTATION_ASCII:
1185         {
1186             const CHAR *start = i.GetASCII();
1187             const CHAR *end = GetRawASCII() + GetRawCount() - 1;
1188             while (start <= end)
1189             {
1190                 if (*start == c)
1191                 {
1192                     i.Resync(this, (BYTE*) start);
1193                     RETURN TRUE;
1194                 }
1195                 start++;
1196             }
1197         }
1198         break;
1199
1200     case REPRESENTATION_EMPTY:
1201         break;
1202
1203     case REPRESENTATION_UTF8:
1204     default:
1205         UNREACHABLE();
1206     }
1207
1208     RETURN FALSE;
1209 }
1210
1211 //-----------------------------------------------------------------------------
1212 // Find s in this string, working backwards staring at i.
1213 // Return TRUE and update iterator if found.
1214 //-----------------------------------------------------------------------------
1215 BOOL SString::FindBack(CIterator &i, const SString &s) const
1216 {
1217     CONTRACT(BOOL)
1218     {
1219         INSTANCE_CHECK;
1220         PRECONDITION(CheckIteratorRange(i));
1221         PRECONDITION(s.Check());
1222         POSTCONDITION(RETVAL == Match(i, s));
1223         THROWS_UNLESS_BOTH_NORMALIZED(s);
1224         GC_NOTRIGGER;
1225     }
1226     CONTRACT_END;
1227
1228     // Get a compatible string from s
1229     StackSString temp;
1230     const SString &source = GetCompatibleString(s, temp, i);
1231
1232     switch (GetRepresentation())
1233     {
1234     case REPRESENTATION_UNICODE:
1235         {
1236             COUNT_T count = source.GetRawCount();
1237             const WCHAR *start = GetRawUnicode() + GetRawCount() - count;
1238             if (start > i.GetUnicode())
1239                 start = i.GetUnicode();
1240             const WCHAR *end = GetRawUnicode();
1241
1242             while (start >= end)
1243             {
1244                 if (wcsncmp(start, source.GetRawUnicode(), count) == 0)
1245                 {
1246                     i.Resync(this, (BYTE*) start);
1247                     RETURN TRUE;
1248                 }
1249                 start--;
1250             }
1251         }
1252         break;
1253
1254     case REPRESENTATION_ANSI:
1255     case REPRESENTATION_ASCII:
1256         {
1257             COUNT_T count = source.GetRawCount();
1258             const CHAR *start = GetRawASCII() + GetRawCount() - count;
1259             if (start > i.GetASCII())
1260                 start = i.GetASCII();
1261             const CHAR *end = GetRawASCII();
1262
1263             while (start >= end)
1264             {
1265                 if (strncmp(start, source.GetRawASCII(), count) == 0)
1266                 {
1267                     i.Resync(this, (BYTE*) start);
1268                     RETURN TRUE;
1269                 }
1270                 start--;
1271             }
1272         }
1273         break;
1274
1275     case REPRESENTATION_EMPTY:
1276         {
1277             if (source.GetRawCount() == 0)
1278                 RETURN TRUE;
1279         }
1280         break;
1281
1282     case REPRESENTATION_UTF8:
1283     default:
1284         UNREACHABLE();
1285     }
1286
1287     RETURN FALSE;
1288 }
1289
1290 //-----------------------------------------------------------------------------
1291 // Find s in this string, working backwards staring at i.
1292 // Return TRUE and update iterator if found.
1293 //-----------------------------------------------------------------------------
1294 BOOL SString::FindBack(CIterator &i, WCHAR c) const
1295 {
1296     CONTRACT(BOOL)
1297     {
1298         INSTANCE_CHECK;
1299         PRECONDITION(CheckIteratorRange(i));
1300         POSTCONDITION(RETVAL == Match(i, c));
1301         THROWS_UNLESS_NORMALIZED;
1302         GC_NOTRIGGER;
1303     }
1304     CONTRACT_END;
1305
1306     // Get a compatible string from s
1307     if (c & ~0x7f)
1308         ConvertToUnicode(i);
1309
1310     switch (GetRepresentation())
1311     {
1312     case REPRESENTATION_UNICODE:
1313         {
1314             const WCHAR *start = GetRawUnicode() + GetRawCount() - 1;
1315             if (start > i.GetUnicode())
1316                 start = i.GetUnicode();
1317             const WCHAR *end = GetRawUnicode();
1318
1319             while (start >= end)
1320             {
1321                 if (*start == c)
1322                 {
1323                     i.Resync(this, (BYTE*) start);
1324                     RETURN TRUE;
1325                 }
1326                 start--;
1327             }
1328         }
1329         break;
1330
1331     case REPRESENTATION_ANSI:
1332     case REPRESENTATION_ASCII:
1333         {
1334             const CHAR *start = GetRawASCII() + GetRawCount() - 1;
1335             if (start > i.GetASCII())
1336                 start = i.GetASCII();
1337             const CHAR *end = GetRawASCII();
1338
1339             while (start >= end)
1340             {
1341                 if (*start == c)
1342                 {
1343                     i.Resync(this, (BYTE*) start);
1344                     RETURN TRUE;
1345                 }
1346                 start--;
1347             }
1348         }
1349         break;
1350
1351     case REPRESENTATION_EMPTY:
1352         break;
1353
1354     case REPRESENTATION_UTF8:
1355     default:
1356         UNREACHABLE();
1357     }
1358
1359     RETURN FALSE;
1360 }
1361
1362 //-----------------------------------------------------------------------------
1363 // Returns TRUE if this string begins with the contents of s
1364 //-----------------------------------------------------------------------------
1365 BOOL SString::BeginsWith(const SString &s) const
1366 {
1367     WRAPPER_NO_CONTRACT;
1368
1369     return Match(Begin(), s);
1370 }
1371
1372 //-----------------------------------------------------------------------------
1373 // Returns TRUE if this string begins with the contents of s
1374 //-----------------------------------------------------------------------------
1375 BOOL SString::BeginsWithCaseInsensitive(const SString &s) const
1376 {
1377     WRAPPER_NO_CONTRACT;
1378
1379     return MatchCaseInsensitive(Begin(), s);
1380 }
1381
1382 //-----------------------------------------------------------------------------
1383 // Returns TRUE if this string ends with the contents of s
1384 //-----------------------------------------------------------------------------
1385 BOOL SString::EndsWith(const SString &s) const
1386 {
1387     WRAPPER_NO_CONTRACT;
1388
1389     // Need this check due to iterator arithmetic below.
1390     if (GetCount() < s.GetCount())
1391     {
1392         return FALSE;
1393     }
1394
1395     return Match(End() - s.GetCount(), s);
1396 }
1397
1398 //-----------------------------------------------------------------------------
1399 // Returns TRUE if this string ends with the contents of s
1400 //-----------------------------------------------------------------------------
1401 BOOL SString::EndsWithCaseInsensitive(const SString &s) const
1402 {
1403     WRAPPER_NO_CONTRACT;
1404
1405     // Need this check due to iterator arithmetic below.
1406     if (GetCount() < s.GetCount())
1407     {
1408         return FALSE;
1409     }
1410
1411     return MatchCaseInsensitive(End() - s.GetCount(), s);
1412 }
1413
1414 //-----------------------------------------------------------------------------
1415 // Compare this string's contents to s's contents.
1416 // The comparison does not take into account localization issues like case folding.
1417 // Return 0 if equal, <0 if this < s, >0 is this > s. (same as strcmp).
1418 //-----------------------------------------------------------------------------
1419 int SString::Compare(const SString &s) const
1420 {
1421     CONTRACT(int)
1422     {
1423         INSTANCE_CHECK;
1424         PRECONDITION(s.Check());
1425         THROWS_UNLESS_BOTH_NORMALIZED(s);
1426         GC_NOTRIGGER;
1427     }
1428     CONTRACT_END;
1429
1430     StackSString temp;
1431     const SString &source = GetCompatibleString(s, temp);
1432
1433     COUNT_T smaller;
1434     int equals = 0;
1435     int result = 0;
1436
1437     if (GetRawCount() < source.GetRawCount())
1438     {
1439         smaller = GetRawCount();
1440         equals = -1;
1441     }
1442     else if (GetRawCount() > source.GetRawCount())
1443     {
1444         smaller = source.GetRawCount();
1445         equals = 1;
1446     }
1447     else
1448     {
1449         smaller = GetRawCount();
1450         equals = 0;
1451     }
1452
1453     switch (GetRepresentation())
1454     {
1455     case REPRESENTATION_UNICODE:
1456         result = wcsncmp(GetRawUnicode(), source.GetRawUnicode(), smaller);
1457         break;
1458
1459     case REPRESENTATION_ASCII:
1460     case REPRESENTATION_ANSI:
1461         result = strncmp(GetRawASCII(), source.GetRawASCII(), smaller);
1462         break;
1463
1464     case REPRESENTATION_EMPTY:
1465         result = 0;
1466         break;
1467
1468     default:
1469     case REPRESENTATION_UTF8:
1470         UNREACHABLE();
1471     }
1472
1473     if (result == 0)
1474         RETURN equals;
1475     else
1476         RETURN result;
1477 }
1478
1479 //-----------------------------------------------------------------------------
1480 // Compare this string's contents to s's contents.
1481 // Return 0 if equal, <0 if this < s, >0 is this > s. (same as strcmp).
1482 //-----------------------------------------------------------------------------
1483
1484 int SString::CompareCaseInsensitive(const SString &s) const
1485 {
1486     CONTRACT(int)
1487     {
1488         INSTANCE_CHECK;
1489         PRECONDITION(s.Check());
1490         THROWS_UNLESS_BOTH_NORMALIZED(s);
1491         GC_NOTRIGGER;
1492     }
1493     CONTRACT_END;
1494
1495     StackSString temp;
1496     const SString &source = GetCompatibleString(s, temp);
1497
1498     COUNT_T smaller;
1499     int equals = 0;
1500     int result = 0;
1501
1502     if (GetRawCount() < source.GetRawCount())
1503     {
1504         smaller = GetRawCount();
1505         equals = -1;
1506     }
1507     else if (GetRawCount() > source.GetRawCount())
1508     {
1509         smaller = source.GetRawCount();
1510         equals = 1;
1511     }
1512     else
1513     {
1514         smaller = GetRawCount();
1515         equals = 0;
1516     }
1517
1518     switch (GetRepresentation())
1519     {
1520     case REPRESENTATION_UNICODE:
1521         result = CaseCompareHelper(GetRawUnicode(), source.GetRawUnicode(), smaller, FALSE, TRUE);
1522         break;
1523
1524     case REPRESENTATION_ASCII:
1525     case REPRESENTATION_ANSI:
1526         result = CaseCompareHelperA(GetRawASCII(), source.GetRawASCII(), smaller, FALSE, TRUE);
1527         break;
1528
1529     case REPRESENTATION_EMPTY:
1530         result = 0;
1531         break;
1532
1533     default:
1534     case REPRESENTATION_UTF8:
1535         UNREACHABLE();
1536     }
1537
1538     if (result == 0)
1539         RETURN equals;
1540     else
1541         RETURN result;
1542 }
1543
1544 //-----------------------------------------------------------------------------
1545 // Compare this string's contents to s's contents.
1546 // The comparison does not take into account localization issues like case folding.
1547 // Return 1 if equal, 0 if not.
1548 //-----------------------------------------------------------------------------
1549 BOOL SString::Equals(const SString &s) const
1550 {
1551     CONTRACT(BOOL)
1552     {
1553         INSTANCE_CHECK;
1554         PRECONDITION(s.Check());
1555         THROWS_UNLESS_BOTH_NORMALIZED(s);
1556         FAULTS_UNLESS_BOTH_NORMALIZED(s, ThrowOutOfMemory());
1557         GC_NOTRIGGER;
1558     }
1559     CONTRACT_END;
1560
1561     StackSString temp;
1562     const SString &source = GetCompatibleString(s, temp);
1563
1564     COUNT_T count = GetRawCount();
1565
1566     if (count != source.GetRawCount())
1567         RETURN FALSE;
1568
1569     switch (GetRepresentation())
1570     {
1571     case REPRESENTATION_UNICODE:
1572         RETURN (wcsncmp(GetRawUnicode(), source.GetRawUnicode(), count) == 0);
1573
1574     case REPRESENTATION_ASCII:
1575     case REPRESENTATION_ANSI:
1576         RETURN (strncmp(GetRawASCII(), source.GetRawASCII(), count) == 0);
1577
1578     case REPRESENTATION_EMPTY:
1579         RETURN TRUE;
1580
1581     default:
1582     case REPRESENTATION_UTF8:
1583         UNREACHABLE();
1584     }
1585
1586     RETURN FALSE;
1587 }
1588
1589 //-----------------------------------------------------------------------------
1590 // Compare this string's contents case insensitively to s's contents.
1591 // Return 1 if equal, 0 if not.
1592 //-----------------------------------------------------------------------------
1593 BOOL SString::EqualsCaseInsensitive(const SString &s) const
1594 {
1595     CONTRACT(BOOL)
1596     {
1597         INSTANCE_CHECK;
1598         PRECONDITION(s.Check());
1599         THROWS_UNLESS_BOTH_NORMALIZED(s);
1600         FAULTS_UNLESS_BOTH_NORMALIZED(s, ThrowOutOfMemory());
1601         GC_NOTRIGGER;
1602     }
1603     CONTRACT_END;
1604
1605     StackSString temp;
1606     const SString &source = GetCompatibleString(s, temp);
1607
1608     COUNT_T count = GetRawCount();
1609
1610     if (count != source.GetRawCount())
1611         RETURN FALSE;
1612
1613     switch (GetRepresentation())
1614     {
1615     case REPRESENTATION_UNICODE:
1616         RETURN (CaseCompareHelper(GetRawUnicode(), source.GetRawUnicode(), count, FALSE, TRUE) == 0);
1617
1618     case REPRESENTATION_ASCII:
1619     case REPRESENTATION_ANSI:
1620         RETURN (CaseCompareHelperA(GetRawASCII(), source.GetRawASCII(), count, FALSE, TRUE) == 0);
1621
1622     case REPRESENTATION_EMPTY:
1623         RETURN TRUE;
1624
1625     default:
1626     case REPRESENTATION_UTF8:
1627         UNREACHABLE();
1628     }
1629
1630     RETURN FALSE;
1631 }
1632
1633 //-----------------------------------------------------------------------------
1634 // Compare s's contents to the substring starting at position
1635 // The comparison does not take into account localization issues like case folding.
1636 // Return TRUE if equal, FALSE if not
1637 //-----------------------------------------------------------------------------
1638 BOOL SString::Match(const CIterator &i, const SString &s) const
1639 {
1640     CONTRACT(BOOL)
1641     {
1642         INSTANCE_CHECK;
1643         PRECONDITION(CheckIteratorRange(i));
1644         PRECONDITION(s.Check());
1645         THROWS_UNLESS_BOTH_NORMALIZED(s);
1646         GC_NOTRIGGER;
1647     }
1648     CONTRACT_END;
1649
1650     StackSString temp;
1651     const SString &source = GetCompatibleString(s, temp, i);
1652
1653     COUNT_T remaining = End() - i;
1654     COUNT_T count = source.GetRawCount();
1655
1656     if (remaining < count)
1657         RETURN FALSE;
1658
1659     switch (GetRepresentation())
1660     {
1661     case REPRESENTATION_UNICODE:
1662         RETURN (wcsncmp(i.GetUnicode(), source.GetRawUnicode(), count) == 0);
1663
1664     case REPRESENTATION_ASCII:
1665     case REPRESENTATION_ANSI:
1666         RETURN (strncmp(i.GetASCII(), source.GetRawASCII(), count) == 0);
1667
1668     case REPRESENTATION_EMPTY:
1669         RETURN TRUE;
1670
1671     default:
1672     case REPRESENTATION_UTF8:
1673         UNREACHABLE();
1674     }
1675
1676     RETURN FALSE;
1677 }
1678
1679 //-----------------------------------------------------------------------------
1680 // Compare s's contents case insensitively to the substring starting at position
1681 // Return TRUE if equal, FALSE if not
1682 //-----------------------------------------------------------------------------
1683 BOOL SString::MatchCaseInsensitive(const CIterator &i, const SString &s) const
1684 {
1685     CONTRACT(BOOL)
1686     {
1687         INSTANCE_CHECK;
1688         PRECONDITION(CheckIteratorRange(i));
1689         PRECONDITION(s.Check());
1690         THROWS_UNLESS_BOTH_NORMALIZED(s);
1691         GC_NOTRIGGER;
1692     }
1693     CONTRACT_END;
1694
1695     StackSString temp;
1696     const SString &source = GetCompatibleString(s, temp, i);
1697
1698     COUNT_T remaining = End() - i;
1699     COUNT_T count = source.GetRawCount();
1700
1701     if (remaining < count)
1702         RETURN FALSE;
1703
1704     switch (GetRepresentation())
1705     {
1706     case REPRESENTATION_UNICODE:
1707     case REPRESENTATION_ANSI:
1708         RETURN (CaseCompareHelper(i.GetUnicode(), source.GetRawUnicode(), count, FALSE, TRUE) == 0);
1709
1710     case REPRESENTATION_ASCII:
1711         RETURN (CaseCompareHelperA(i.GetASCII(), source.GetRawASCII(), count, FALSE, TRUE) == 0);
1712
1713     case REPRESENTATION_EMPTY:
1714         RETURN TRUE;
1715
1716     default:
1717     case REPRESENTATION_UTF8:
1718         UNREACHABLE();
1719     }
1720
1721     RETURN FALSE;
1722 }
1723
1724 //-----------------------------------------------------------------------------
1725 // Compare c case insensitively to the character at position
1726 // Return TRUE if equal, FALSE if not
1727 //-----------------------------------------------------------------------------
1728 BOOL SString::MatchCaseInsensitive(const CIterator &i, WCHAR c) const
1729 {
1730     SS_CONTRACT(BOOL)
1731     {
1732         GC_NOTRIGGER;
1733         INSTANCE_CHECK;
1734         PRECONDITION(CheckIteratorRange(i));
1735         NOTHROW;
1736     }
1737     SS_CONTRACT_END;
1738
1739     // End() will not throw here
1740     CONTRACT_VIOLATION(ThrowsViolation);
1741     if (i >= End())
1742         SS_RETURN FALSE;
1743
1744     WCHAR test = i[0];
1745
1746     SS_RETURN (test == c
1747                || ((CAN_SIMPLE_UPCASE(test) ? SIMPLE_UPCASE(test) : MapChar(test, LCMAP_UPPERCASE))
1748                    == (CAN_SIMPLE_UPCASE(c) ? SIMPLE_UPCASE(c) : MapChar(c, LCMAP_UPPERCASE))));
1749 }
1750
1751 //-----------------------------------------------------------------------------
1752 // Convert string to unicode lowercase using the invariant culture
1753 // Note: Please don't use it in PATH as multiple character can map to the same 
1754 // lower case symbol
1755 //-----------------------------------------------------------------------------
1756 void SString::LowerCase()
1757 {
1758     SS_CONTRACT_VOID
1759     {
1760         GC_NOTRIGGER;
1761         PRECONDITION(CheckPointer(this));
1762         SS_POSTCONDITION(CheckPointer(RETVAL));
1763         if (IsRepresentation(REPRESENTATION_UNICODE)) NOTHROW; else THROWS;
1764         SUPPORTS_DAC;
1765     }
1766     SS_CONTRACT_END;
1767     
1768     ConvertToUnicode();
1769
1770     for (WCHAR *pwch = GetRawUnicode(); pwch < GetRawUnicode() + GetRawCount(); ++pwch)
1771     {
1772         *pwch = (CAN_SIMPLE_DOWNCASE(*pwch) ? SIMPLE_DOWNCASE(*pwch) : MapChar(*pwch, LCMAP_LOWERCASE));
1773     }
1774 }
1775
1776 //-----------------------------------------------------------------------------
1777 // Convert null-terminated string to lowercase using the invariant culture
1778 //-----------------------------------------------------------------------------
1779 //static 
1780 void SString::LowerCase(__inout_z LPWSTR wszString)
1781 {
1782     SS_CONTRACT_VOID
1783     {
1784         GC_NOTRIGGER;
1785         NOTHROW;
1786         SUPPORTS_DAC;
1787     }
1788     SS_CONTRACT_END;
1789     
1790     if (wszString == NULL)
1791     {
1792         return;
1793     }
1794     
1795     for (WCHAR * pwch = wszString; *pwch != '\0'; ++pwch)
1796     {
1797         *pwch = (CAN_SIMPLE_DOWNCASE(*pwch) ? SIMPLE_DOWNCASE(*pwch) : MapChar(*pwch, LCMAP_LOWERCASE));
1798     }
1799 }
1800
1801 //-----------------------------------------------------------------------------
1802 // Convert string to unicode uppercase using the invariant culture
1803 // Note: Please don't use it in PATH as multiple character can map to the same 
1804 // upper case symbol
1805 //-----------------------------------------------------------------------------
1806 void SString::UpperCase()
1807 {
1808     SS_CONTRACT_VOID
1809     {
1810         GC_NOTRIGGER;
1811         PRECONDITION(CheckPointer(this));
1812         SS_POSTCONDITION(CheckPointer(RETVAL));
1813         if (IsRepresentation(REPRESENTATION_UNICODE)) NOTHROW; else THROWS;
1814         GC_NOTRIGGER;
1815         SUPPORTS_DAC;
1816     }
1817     SS_CONTRACT_END;
1818     
1819     ConvertToUnicode();
1820
1821     for (WCHAR *pwch = GetRawUnicode(); pwch < GetRawUnicode() + GetRawCount(); ++pwch)
1822     {
1823         *pwch = (CAN_SIMPLE_UPCASE(*pwch) ? SIMPLE_UPCASE(*pwch) : MapChar(*pwch, LCMAP_UPPERCASE));
1824     }
1825 }
1826
1827 //-----------------------------------------------------------------------------
1828 // Get a const pointer to the internal buffer as an ANSI string.
1829 //-----------------------------------------------------------------------------
1830 const CHAR *SString::GetANSI(AbstractScratchBuffer &scratch) const
1831 {
1832     SS_CONTRACT(const CHAR *)
1833     {
1834         INSTANCE_CHECK_NULL;
1835         THROWS;
1836         GC_NOTRIGGER;
1837     }
1838     SS_CONTRACT_END;
1839
1840     if (this == NULL)
1841         SS_RETURN NULL;
1842
1843     if (IsRepresentation(REPRESENTATION_ANSI))
1844         SS_RETURN GetRawANSI();
1845
1846     ConvertToANSI((SString&)scratch);
1847     SS_RETURN ((SString&)scratch).GetRawANSI();
1848 }
1849
1850 //-----------------------------------------------------------------------------
1851 // Get a const pointer to the internal buffer as a UTF8 string.
1852 //-----------------------------------------------------------------------------
1853 const UTF8 *SString::GetUTF8(AbstractScratchBuffer &scratch) const
1854 {
1855     CONTRACT(const UTF8 *)
1856     {
1857         INSTANCE_CHECK_NULL;
1858         THROWS;
1859         GC_NOTRIGGER;
1860     }
1861     CONTRACT_END;
1862
1863     if (this == NULL)
1864         RETURN NULL;
1865
1866     if (IsRepresentation(REPRESENTATION_UTF8))
1867         RETURN GetRawUTF8();
1868
1869     ConvertToUTF8((SString&)scratch);
1870     RETURN ((SString&)scratch).GetRawUTF8();
1871 }
1872
1873 const UTF8 *SString::GetUTF8(AbstractScratchBuffer &scratch, COUNT_T *pcbUtf8) const
1874 {
1875     CONTRACT(const UTF8 *)
1876     {
1877         INSTANCE_CHECK_NULL;
1878         THROWS;
1879         GC_NOTRIGGER;
1880     }
1881     CONTRACT_END;
1882
1883     if (this == NULL)
1884         RETURN NULL;
1885
1886     if (IsRepresentation(REPRESENTATION_UTF8))
1887     {
1888         *pcbUtf8 = GetRawCount() + 1;
1889         RETURN GetRawUTF8();
1890     }
1891
1892     *pcbUtf8 = ConvertToUTF8((SString&)scratch);
1893     RETURN ((SString&)scratch).GetRawUTF8();
1894 }
1895
1896 //-----------------------------------------------------------------------------
1897 // Get a const pointer to the internal buffer which must already be a UTF8 string.
1898 // This avoids the need to create a scratch buffer we know will never be used.
1899 //-----------------------------------------------------------------------------
1900 const UTF8 *SString::GetUTF8NoConvert() const
1901 {
1902     CONTRACT(const UTF8 *)
1903     {
1904         INSTANCE_CHECK_NULL;
1905         THROWS;
1906         GC_NOTRIGGER;
1907     }
1908     CONTRACT_END;
1909
1910     if (this == NULL)
1911         RETURN NULL;
1912
1913     if (IsRepresentation(REPRESENTATION_UTF8))
1914         RETURN GetRawUTF8();
1915
1916     ThrowHR(E_INVALIDARG);
1917 }
1918
1919 //-----------------------------------------------------------------------------
1920 // Safe version of sprintf.
1921 // Prints formatted ansi text w/ var args to this buffer.
1922 //-----------------------------------------------------------------------------
1923 void SString::Printf(const CHAR *format, ...)
1924 {
1925     WRAPPER_NO_CONTRACT;
1926
1927     va_list args;
1928     va_start(args, format);
1929     VPrintf(format, args);
1930     va_end(args);
1931 }
1932
1933 #ifdef _DEBUG
1934 //
1935 // Check the Printf use for potential globalization bugs. %S formatting
1936 // specifier does Unicode->Ansi or Ansi->Unicode conversion using current
1937 // C-locale. This almost always means globalization bug in the CLR codebase.
1938 //
1939 // Ideally, we would elimitate %S from all format strings. Unfortunately,
1940 // %S is too widespread in non-shipping code that such cleanup is not feasible.
1941 //
1942 static void CheckForFormatStringGlobalizationIssues(const SString &format, const SString &result)
1943 {
1944     CONTRACTL
1945     {
1946         THROWS;
1947         GC_NOTRIGGER;
1948         DEBUG_ONLY;
1949     }
1950     CONTRACTL_END;
1951
1952     BOOL fDangerousFormat = FALSE;
1953
1954     // Check whether the format string contains the %S formatting specifier
1955     SString::CIterator itrFormat = format.Begin();
1956     while (*itrFormat)
1957     {
1958         if (*itrFormat++ == '%')
1959         {
1960             // <TODO>Handle the complex format strings like %blahS</TODO>
1961             if (*itrFormat++ == 'S')
1962             {
1963                 fDangerousFormat = TRUE;
1964                 break;
1965             }
1966         }
1967     }
1968
1969     if (fDangerousFormat)
1970     {
1971         BOOL fNonAsciiUsed = FALSE;
1972
1973         // Now check whether there are any non-ASCII characters in the output.
1974
1975         // Check whether the result contains non-Ascii characters
1976         SString::CIterator itrResult = format.Begin();
1977         while (*itrResult)
1978         {
1979             if (*itrResult++ > 127)
1980             {
1981                 fNonAsciiUsed = TRUE;
1982                 break;
1983             }
1984         }
1985
1986         CONSISTENCY_CHECK_MSGF(!fNonAsciiUsed,
1987             ("Non-ASCII string was produced by %%S format specifier. This is likely globalization bug."
1988             "To fix this, change the format string to %%s and do the correct encoding at the Printf callsite"));
1989     }
1990 }
1991 #endif
1992
1993 #ifndef EBADF
1994 #define EBADF 9
1995 #endif
1996
1997 #ifndef ENOMEM
1998 #define ENOMEM 12
1999 #endif
2000
2001 #ifndef ERANGE
2002 #define ERANGE 34
2003 #endif
2004
2005 #if defined(_MSC_VER)
2006 #undef va_copy
2007 #define va_copy(dest,src) (dest = src)
2008 #endif
2009
2010 void SString::VPrintf(const CHAR *format, va_list args)
2011 {
2012     CONTRACT_VOID
2013     {
2014         INSTANCE_CHECK;
2015         PRECONDITION(CheckPointer(format));
2016         THROWS;
2017         GC_NOTRIGGER;
2018     }
2019     CONTRACT_END;
2020
2021     va_list ap;
2022     // sprintf gives us no means to know how many characters are written
2023     // other than guessing and trying
2024
2025     if (GetRawCount() > 0)
2026     {
2027         // First, try to use the existing buffer
2028         va_copy(ap, args);
2029         int result = _vsnprintf_s(GetRawANSI(), GetRawCount()+1, _TRUNCATE, format, ap);
2030         va_end(ap);
2031
2032         if (result >=0)
2033         {
2034             // Succeeded in writing. Now resize - 
2035             Resize(result, REPRESENTATION_ANSI, PRESERVE);
2036             SString sss(Ansi, format);
2037             INDEBUG(CheckForFormatStringGlobalizationIssues(sss, *this));
2038             RETURN;
2039         }
2040     }
2041
2042     // Make a guess how long the result will be (note this will be doubled)
2043
2044     COUNT_T guess = (COUNT_T) strlen(format)+1;
2045     if (guess < GetRawCount())
2046         guess = GetRawCount();
2047     if (guess < MINIMUM_GUESS)
2048         guess = MINIMUM_GUESS;
2049
2050     while (TRUE)
2051     {
2052         // Double the previous guess - eventually we will get enough space
2053         guess *= 2;
2054         Resize(guess, REPRESENTATION_ANSI);
2055
2056         // Clear errno to avoid false alarms
2057         errno = 0;
2058
2059         va_copy(ap, args);
2060         int result = _vsnprintf_s(GetRawANSI(), GetRawCount()+1, _TRUNCATE, format, ap);
2061         va_end(ap);
2062
2063         if (result >= 0)
2064         {
2065             // Succeed in writing. Shrink the buffer to fit exactly.
2066             Resize(result, REPRESENTATION_ANSI, PRESERVE);
2067             SString sss(Ansi, format);
2068             INDEBUG(CheckForFormatStringGlobalizationIssues(sss, *this));
2069             RETURN;
2070         }
2071
2072         if (errno==ENOMEM)
2073         {
2074             ThrowOutOfMemory();
2075         }
2076         else
2077         if (errno!=0 && errno!=EBADF && errno!=ERANGE)
2078         {
2079             CONSISTENCY_CHECK_MSG(FALSE, "_vsnprintf_s failed. Potential globalization bug.");
2080             ThrowHR(HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION));
2081         }
2082     }
2083     RETURN;
2084 }
2085
2086 void SString::Printf(const WCHAR *format, ...)
2087 {
2088     WRAPPER_NO_CONTRACT;
2089
2090     va_list args;
2091     va_start(args, format);
2092     VPrintf(format, args);
2093     va_end(args);
2094 }
2095
2096 void SString::PPrintf(const WCHAR *format, ...)
2097 {
2098     CONTRACT_VOID
2099     {
2100         INSTANCE_CHECK;
2101         PRECONDITION(CheckPointer(format));
2102         THROWS;
2103         GC_NOTRIGGER;
2104     }
2105     CONTRACT_END;
2106
2107     va_list argItr;
2108     va_start(argItr, format);
2109     PVPrintf(format, argItr);
2110     va_end(argItr);    
2111
2112     RETURN;
2113 }
2114
2115 void SString::VPrintf(const WCHAR *format, va_list args)
2116 {
2117     CONTRACT_VOID
2118     {
2119         INSTANCE_CHECK;
2120         PRECONDITION(CheckPointer(format));
2121         THROWS;
2122         GC_NOTRIGGER;
2123     }
2124     CONTRACT_END;
2125
2126     va_list ap;
2127     // sprintf gives us no means to know how many characters are written
2128     // other than guessing and trying
2129
2130     if (GetRawCount() > 0)
2131     {
2132         // First, try to use the existing buffer
2133         va_copy(ap, args);
2134         int result = _vsnwprintf_s(GetRawUnicode(), GetRawCount()+1, _TRUNCATE, format, ap);
2135         va_end(ap);
2136
2137         if (result >= 0)
2138         {
2139             // succeeded
2140             Resize(result, REPRESENTATION_UNICODE, PRESERVE);
2141             SString sss(format);
2142             INDEBUG(CheckForFormatStringGlobalizationIssues(sss, *this));
2143             RETURN;
2144         }
2145     }
2146
2147     // Make a guess how long the result will be (note this will be doubled)
2148
2149     COUNT_T guess = (COUNT_T) wcslen(format)+1;
2150     if (guess < GetRawCount())
2151         guess = GetRawCount();
2152     if (guess < MINIMUM_GUESS)
2153         guess = MINIMUM_GUESS;
2154
2155     while (TRUE)
2156     {
2157         // Double the previous guess - eventually we will get enough space
2158         guess *= 2;
2159         Resize(guess, REPRESENTATION_UNICODE);
2160
2161         // Clear errno to avoid false alarms
2162         errno = 0;
2163
2164         va_copy(ap, args);
2165         int result = _vsnwprintf_s(GetRawUnicode(), GetRawCount()+1, _TRUNCATE, format, ap);
2166         va_end(ap);
2167
2168         if (result >= 0)
2169         {
2170             Resize(result, REPRESENTATION_UNICODE, PRESERVE);
2171             SString sss(format);
2172             INDEBUG(CheckForFormatStringGlobalizationIssues(sss, *this));
2173             RETURN;
2174         }
2175
2176         if (errno==ENOMEM)
2177         {
2178             ThrowOutOfMemory();
2179         }
2180         else
2181         if (errno!=0 && errno!=EBADF && errno!=ERANGE)
2182         {
2183             CONSISTENCY_CHECK_MSG(FALSE, "_vsnwprintf_s failed. Potential globalization bug.");
2184             ThrowHR(HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION));
2185         }
2186     }
2187     RETURN;
2188 }
2189
2190 void SString::PVPrintf(const WCHAR *format, va_list args)
2191 {
2192     CONTRACT_VOID
2193     {
2194         INSTANCE_CHECK;
2195         PRECONDITION(CheckPointer(format));
2196         THROWS;
2197         GC_NOTRIGGER;
2198     }
2199     CONTRACT_END;
2200
2201     va_list ap;
2202     // sprintf gives us no means to know how many characters are written
2203     // other than guessing and trying
2204
2205     if (GetRawCount() > 0)
2206     {
2207         // First, try to use the existing buffer
2208         va_copy(ap, args);
2209 #if defined(FEATURE_CORESYSTEM)
2210         int result = _vsnwprintf_s(GetRawUnicode(), GetRawCount()+1, _TRUNCATE, format, ap);
2211 #else
2212         int result = _vswprintf_p(GetRawUnicode(), GetRawCount()+1, format, ap);
2213 #endif
2214         va_end(ap);
2215         if (result >= 0)
2216         {
2217             // succeeded
2218             Resize(result, REPRESENTATION_UNICODE, PRESERVE);
2219             SString sss(format);
2220             INDEBUG(CheckForFormatStringGlobalizationIssues(sss, *this));
2221             RETURN;
2222         }
2223     }
2224
2225     // Make a guess how long the result will be (note this will be doubled)
2226
2227     COUNT_T guess = (COUNT_T) wcslen(format)+1;
2228     if (guess < GetRawCount())
2229         guess = GetRawCount();
2230     if (guess < MINIMUM_GUESS)
2231         guess = MINIMUM_GUESS;
2232
2233     while (TRUE)
2234     {
2235         // Double the previous guess - eventually we will get enough space
2236         guess *= 2;
2237         Resize(guess, REPRESENTATION_UNICODE, DONT_PRESERVE);
2238
2239         // Clear errno to avoid false alarms
2240         errno = 0;
2241
2242         va_copy(ap, args);
2243 #if defined(FEATURE_CORESYSTEM)
2244         int result = _vsnwprintf_s(GetRawUnicode(), GetRawCount()+1, _TRUNCATE, format, ap);
2245 #else
2246         int result = _vswprintf_p(GetRawUnicode(), GetRawCount()+1, format, ap);
2247 #endif
2248         va_end(ap);
2249
2250         if (result >= 0)
2251         {
2252             Resize(result, REPRESENTATION_UNICODE, PRESERVE);
2253             SString sss(format);
2254             INDEBUG(CheckForFormatStringGlobalizationIssues(sss, *this));
2255             RETURN;
2256         }
2257
2258         if (errno==ENOMEM)
2259         {
2260             ThrowOutOfMemory();
2261         }
2262         else
2263         if (errno!=0 && errno!=EBADF && errno!=ERANGE)
2264         {
2265             CONSISTENCY_CHECK_MSG(FALSE, "_vsnwprintf_s failed. Potential globalization bug.");
2266             ThrowHR(HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION));
2267         }
2268     }
2269     RETURN;
2270 }
2271
2272 void SString::AppendPrintf(const CHAR *format, ...)
2273 {
2274     WRAPPER_NO_CONTRACT;
2275
2276     va_list args;
2277     va_start(args, format);
2278     AppendVPrintf(format, args);
2279     va_end(args);
2280 }
2281
2282 void SString::AppendVPrintf(const CHAR *format, va_list args)
2283 {
2284     WRAPPER_NO_CONTRACT;
2285
2286     StackSString s;
2287     s.VPrintf(format, args);
2288     Append(s);
2289 }
2290
2291 void SString::AppendPrintf(const WCHAR *format, ...)
2292 {
2293     WRAPPER_NO_CONTRACT;
2294
2295     va_list args;
2296     va_start(args, format);
2297     AppendVPrintf(format, args);
2298     va_end(args);
2299 }
2300
2301 void SString::AppendVPrintf(const WCHAR *format, va_list args)
2302 {
2303     WRAPPER_NO_CONTRACT;
2304
2305     StackSString s;
2306     s.VPrintf(format, args);
2307     Append(s);
2308 }
2309
2310 //----------------------------------------------------------------------------
2311 // LoadResource - moved to sstring_com.cpp
2312 //----------------------------------------------------------------------------
2313
2314 //----------------------------------------------------------------------------
2315 // Format the message and put the contents in this string
2316 //----------------------------------------------------------------------------
2317
2318 BOOL SString::FormatMessage(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId,
2319                             const SString &arg1, const SString &arg2,
2320                             const SString &arg3, const SString &arg4,
2321                             const SString &arg5, const SString &arg6,
2322                             const SString &arg7, const SString &arg8,
2323                             const SString &arg9, const SString &arg10)
2324 {
2325     CONTRACT(BOOL)
2326     {
2327         INSTANCE_CHECK;
2328         THROWS;
2329         GC_NOTRIGGER;
2330     }
2331     CONTRACT_END;
2332
2333     const WCHAR *args[] = {arg1.GetUnicode(), arg2.GetUnicode(), arg3.GetUnicode(), arg4.GetUnicode(),
2334                            arg5.GetUnicode(), arg6.GetUnicode(), arg7.GetUnicode(), arg8.GetUnicode(),
2335                            arg9.GetUnicode(), arg10.GetUnicode()};
2336
2337     if (GetRawCount() > 0)
2338     {
2339         // First, try to use our existing buffer to hold the result.
2340         Resize(GetRawCount(), REPRESENTATION_UNICODE);
2341
2342         DWORD result = ::WszFormatMessage(dwFlags | FORMAT_MESSAGE_ARGUMENT_ARRAY,
2343                                           lpSource, dwMessageId, dwLanguageId,
2344                                           GetRawUnicode(), GetRawCount()+1, (va_list*)args);
2345
2346         // Although we cannot directly detect truncation, we can tell if we
2347         // used up all the space (in which case we will assume truncation.)
2348
2349         if (result != 0 && result < GetRawCount())
2350         {
2351             if (GetRawUnicode()[result-1] == W(' '))
2352             {
2353                 GetRawUnicode()[result-1] = W('\0');
2354                 result -= 1;
2355             }
2356             Resize(result, REPRESENTATION_UNICODE, PRESERVE);
2357             RETURN TRUE;
2358         }
2359     }
2360
2361     // We don't have enough space in our buffer, do dynamic allocation.
2362     LocalAllocHolder<WCHAR> string;
2363
2364     DWORD result = ::WszFormatMessage(dwFlags | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY,
2365                                       lpSource, dwMessageId, dwLanguageId,
2366                                       (LPWSTR)(LPWSTR*)&string, 0, (va_list*)args);
2367
2368     if (result == 0)
2369         RETURN FALSE;
2370     else
2371     {
2372         if (string[result-1] == W(' '))
2373             string[result-1] = W('\0');
2374
2375         Set(string);
2376         RETURN TRUE;
2377     }
2378 }
2379
2380 #if 1
2381 //----------------------------------------------------------------------------
2382 // Helper
2383 //----------------------------------------------------------------------------
2384
2385 // @todo -this should be removed and placed outside of SString
2386 void SString::MakeFullNamespacePath(const SString &nameSpace, const SString &name)
2387 {
2388     CONTRACT_VOID
2389     {
2390         INSTANCE_CHECK;
2391         THROWS;
2392         GC_NOTRIGGER;
2393     }
2394     CONTRACT_END;
2395
2396     if (nameSpace.GetRepresentation() == REPRESENTATION_UTF8
2397         && name.GetRepresentation() == REPRESENTATION_UTF8)
2398     {
2399         const UTF8 *ns = nameSpace.GetRawUTF8();
2400         const UTF8 *n = name.GetRawUTF8();
2401         COUNT_T count = ns::GetFullLength(ns, n)-1;
2402         Resize(count, REPRESENTATION_UTF8);
2403         if (count > 0)
2404             ns::MakePath(GetRawUTF8(), count+1, ns, n);
2405     }
2406     else
2407     {
2408         const WCHAR *ns = nameSpace;
2409         const WCHAR *n = name;
2410         COUNT_T count = ns::GetFullLength(ns, n)-1;
2411         Resize(count, REPRESENTATION_UNICODE);
2412         if (count > 0)
2413             ns::MakePath(GetRawUnicode(), count+1, ns, n);
2414     }
2415
2416     RETURN;
2417 }
2418 #endif
2419
2420
2421
2422 //----------------------------------------------------------------------------
2423 // Private helper.
2424 // Check to see if the string fits the suggested representation
2425 //----------------------------------------------------------------------------
2426 BOOL SString::IsRepresentation(Representation representation) const
2427 {
2428     CONTRACT(BOOL)
2429     {
2430         PRECONDITION(CheckRepresentation(representation));
2431         NOTHROW;
2432         GC_NOTRIGGER;
2433         SUPPORTS_DAC;
2434     }
2435     CONTRACT_END;
2436
2437     Representation currentRepresentation = GetRepresentation();
2438
2439     // If representations are the same, cool.
2440     if (currentRepresentation == representation)
2441         RETURN TRUE;
2442
2443     // If we have an empty representation, we match everything
2444     if (currentRepresentation == REPRESENTATION_EMPTY)
2445         RETURN TRUE;
2446
2447     // If we're a 1 byte charset, there are some more chances to match
2448     if (currentRepresentation != REPRESENTATION_UNICODE
2449         && representation != REPRESENTATION_UNICODE)
2450     {
2451         // If we're ASCII, we can be any 1 byte rep
2452         if (currentRepresentation == REPRESENTATION_ASCII)
2453             RETURN TRUE;
2454
2455         // We really want to be ASCII - scan to see if we qualify
2456         if (ScanASCII())
2457             RETURN TRUE;
2458     }
2459
2460     // Sorry, must convert.
2461     RETURN FALSE;
2462 }
2463
2464 //----------------------------------------------------------------------------
2465 // Private helper.
2466 // Get the contents of the given string in a form which is compatible with our
2467 // string (and is in a fixed character set.)  Updates the given iterator
2468 // if necessary to keep it in sync.
2469 //----------------------------------------------------------------------------
2470 const SString &SString::GetCompatibleString(const SString &s, SString &scratch, const CIterator &i) const
2471 {
2472     CONTRACTL
2473     {
2474         PRECONDITION(s.Check());
2475         PRECONDITION(scratch.Check());
2476         PRECONDITION(scratch.CheckEmpty());
2477         THROWS_UNLESS_BOTH_NORMALIZED(s);
2478         GC_NOTRIGGER;
2479         SUPPORTS_DAC;
2480     }
2481     CONTRACTL_END;
2482
2483     // Since we have an iterator, we should be fixed size already
2484     CONSISTENCY_CHECK(IsFixedSize());
2485
2486     switch (GetRepresentation())
2487     {
2488     case REPRESENTATION_EMPTY:
2489         return s;
2490
2491     case REPRESENTATION_ASCII:
2492         if (s.IsRepresentation(REPRESENTATION_ASCII))
2493             return s;
2494
2495         // We can't in general convert to ASCII, so try unicode.
2496         ConvertToUnicode(i);
2497         // fall through
2498
2499     case REPRESENTATION_UNICODE:
2500         if (s.IsRepresentation(REPRESENTATION_UNICODE))
2501             return s;
2502
2503         // @todo: we could convert s to unicode - is that a good policy????
2504         s.ConvertToUnicode(scratch);
2505         return scratch;
2506
2507     case REPRESENTATION_UTF8:
2508     case REPRESENTATION_ANSI:
2509         // These should all be impossible since we have an CIterator on us.
2510     default:
2511         UNREACHABLE_MSG("Unexpected string representation");
2512     }
2513
2514     return s;
2515 }
2516
2517 //----------------------------------------------------------------------------
2518 // Private helper.
2519 // Get the contents of the given string in a form which is compatible with our
2520 // string (and is in a fixed character set.)
2521 // May convert our string to unicode.
2522 //----------------------------------------------------------------------------
2523 const SString &SString::GetCompatibleString(const SString &s, SString &scratch) const
2524 {
2525     CONTRACTL
2526     {
2527         PRECONDITION(s.Check());
2528         PRECONDITION(scratch.Check());
2529         PRECONDITION(scratch.CheckEmpty());
2530         THROWS_UNLESS_BOTH_NORMALIZED(s);
2531         GC_NOTRIGGER;
2532     }
2533     CONTRACTL_END;
2534
2535     // First, make sure we have a fixed size.
2536     ConvertToFixed();
2537
2538     switch (GetRepresentation())
2539     {
2540     case REPRESENTATION_EMPTY:
2541         return s;
2542
2543     case REPRESENTATION_ANSI:
2544         if (s.IsRepresentation(REPRESENTATION_ANSI))
2545             return s;
2546
2547         s.ConvertToANSI(scratch);
2548         return scratch;
2549
2550     case REPRESENTATION_ASCII:
2551         if (s.IsRepresentation(REPRESENTATION_ASCII))
2552             return s;
2553
2554         // We can't in general convert to ASCII, so try unicode.
2555         ConvertToUnicode();
2556         // fall through
2557
2558     case REPRESENTATION_UNICODE:
2559         if (s.IsRepresentation(REPRESENTATION_UNICODE))
2560             return s;
2561
2562         // @todo: we could convert s to unicode in place - is that a good policy????
2563         s.ConvertToUnicode(scratch);
2564         return scratch;
2565
2566     case REPRESENTATION_UTF8:
2567     default:
2568         UNREACHABLE();
2569     }
2570
2571     return s;
2572 }
2573
2574 //----------------------------------------------------------------------------
2575 // Private helper.
2576 // If we have a 1 byte representation, scan the buffer to see if we can gain
2577 // some conversion flexibility by labelling it ASCII
2578 //----------------------------------------------------------------------------
2579 BOOL SString::ScanASCII() const
2580 {
2581     CONTRACT(BOOL)
2582     {
2583         POSTCONDITION(IsRepresentation(REPRESENTATION_ASCII) || IsASCIIScanned());
2584         NOTHROW;
2585         GC_NOTRIGGER;
2586         SUPPORTS_DAC;
2587     }
2588     CONTRACT_END;
2589
2590     if (!IsASCIIScanned())
2591     {
2592         const CHAR *c = GetRawANSI();
2593         const CHAR *cEnd = c + GetRawCount();
2594         while (c < cEnd)
2595         {
2596             if (*c & 0x80)
2597                 break;
2598             c++;
2599         }
2600         if (c == cEnd)
2601         {
2602             const_cast<SString *>(this)->SetRepresentation(REPRESENTATION_ASCII);
2603             RETURN TRUE;
2604         }
2605         else
2606             const_cast<SString *>(this)->SetASCIIScanned();
2607     }
2608     RETURN FALSE;
2609 }
2610
2611 //----------------------------------------------------------------------------
2612 // Private helper.
2613 // Resize updates the geometry of the string and ensures that
2614 // the space can be written to.
2615 // count - number of characters (not including null) to hold
2616 // preserve - if we realloc, do we copy data from old to new?
2617 //----------------------------------------------------------------------------
2618
2619 void SString::Resize(COUNT_T count, SString::Representation representation, Preserve preserve)
2620 {
2621     CONTRACT_VOID
2622     {
2623         PRECONDITION(CountToSize(count) >= count);
2624         POSTCONDITION(IsRepresentation(representation));
2625         POSTCONDITION(GetRawCount() == count);
2626         if (count == 0) NOTHROW; else THROWS;
2627         GC_NOTRIGGER;
2628         SUPPORTS_DAC_HOST_ONLY;
2629     }
2630     CONTRACT_END;
2631
2632     // If we are resizing to zero, Clear is more efficient
2633     if (count == 0)
2634     {
2635         Clear();
2636     }
2637     else
2638     {
2639         SetRepresentation(representation);
2640
2641         COUNT_T size = CountToSize(count);
2642
2643         // detect overflow
2644         if (size < count)
2645             ThrowOutOfMemory();
2646
2647         ClearNormalized();
2648
2649         SBuffer::Resize(size, preserve);
2650
2651         if (IsImmutable())
2652             EnsureMutable();
2653
2654         NullTerminate();
2655     }
2656
2657     RETURN;
2658 }
2659
2660 //-----------------------------------------------------------------------------
2661 // This is essentially a specialized version of the above for size 0
2662 //-----------------------------------------------------------------------------
2663 void SString::Clear()
2664 {
2665     CONTRACT_VOID
2666     {
2667         INSTANCE_CHECK;
2668         POSTCONDITION(IsEmpty());
2669         NOTHROW;
2670         GC_NOTRIGGER;
2671         SUPPORTS_DAC_HOST_ONLY;
2672     }
2673     CONTRACT_END;
2674
2675     SetRepresentation(REPRESENTATION_EMPTY);
2676
2677     if (IsImmutable())
2678     {
2679         // Use shared empty string rather than allocating a new buffer
2680         SBuffer::SetImmutable(s_EmptyBuffer, sizeof(s_EmptyBuffer));
2681     }
2682     else
2683     {
2684         // Leave allocated buffer for future growth
2685         SBuffer::TweakSize(sizeof(WCHAR));
2686         GetRawUnicode()[0] = 0;
2687     }
2688
2689     RETURN;
2690 }
2691
2692
2693 #ifdef DACCESS_COMPILE
2694
2695 //---------------------------------------------------------------------------------------
2696 //
2697 // Return a pointer to the raw buffer
2698 //
2699 // Returns:
2700 //    A pointer to the raw string buffer.
2701 //
2702 void * SString::DacGetRawContent() const
2703 {
2704     if (IsEmpty())
2705     {
2706         return NULL;
2707     }
2708
2709     switch (GetRepresentation())
2710     {
2711         case REPRESENTATION_EMPTY:
2712             return NULL;
2713
2714         case REPRESENTATION_UNICODE:
2715         case REPRESENTATION_UTF8:
2716         case REPRESENTATION_ASCII:
2717         case REPRESENTATION_ANSI:
2718             // Note: no need to call DacInstantiateString because we know the exact length already.
2719             return SBuffer::DacGetRawContent();
2720
2721         default:
2722             DacNotImpl();
2723             return NULL;
2724     }
2725 }
2726
2727 //---------------------------------------------------------------------------------------
2728 //
2729 // Return a pointer to the raw buffer as a pointer to a unicode string.  Does not
2730 // do conversion, and thus requires that the representation already be in unicode.
2731 //
2732 // Returns:
2733 //    A pointer to the raw string buffer as a unicode string.
2734 //
2735 const WCHAR * SString::DacGetRawUnicode() const
2736 {
2737     if (IsEmpty() || (GetRepresentation() == REPRESENTATION_EMPTY))
2738     {
2739         return W("");
2740     }
2741
2742     if (GetRepresentation() != REPRESENTATION_UNICODE)
2743     {
2744         DacError(E_UNEXPECTED);
2745     }
2746
2747     HRESULT status = S_OK;
2748     WCHAR* wszBuf = NULL;
2749     EX_TRY
2750     {
2751         wszBuf = static_cast<WCHAR*>(SBuffer::DacGetRawContent());
2752     }
2753     EX_CATCH_HRESULT(status);
2754
2755     if (SUCCEEDED(status))
2756     {
2757         return wszBuf;
2758     }
2759     else
2760     {
2761         return NULL;
2762     }
2763 }
2764
2765 //---------------------------------------------------------------------------------------
2766 //
2767 // Copy the string from the target into the provided buffer, converting to unicode if necessary
2768 //
2769 // Arguments:
2770 //    cBufChars - size of pBuffer in count of unicode characters.
2771 //    pBuffer - a buffer of cBufChars unicode chars.
2772 //    pcNeedChars - space to store the number of unicode chars in the SString.
2773 //
2774 // Returns:
2775 //    true if successful - and buffer is filled with the unicode representation of
2776 //       the string.
2777 //    false if unsuccessful.
2778 //
2779 bool SString::DacGetUnicode(COUNT_T                                   cBufChars,
2780                             __out_z __inout_ecount(cBufChars) WCHAR * pBuffer,
2781                             COUNT_T *                                 pcNeedChars) const
2782 {
2783     SUPPORTS_DAC;
2784
2785     PVOID pContent = NULL;
2786     int iPage = CP_ACP;
2787
2788     if (IsEmpty() || (GetRepresentation() == REPRESENTATION_EMPTY))
2789     {
2790         if (pcNeedChars)
2791         {
2792             *pcNeedChars = 1;
2793         }
2794         if (pBuffer && cBufChars)
2795         {
2796             pBuffer[0] = 0;
2797         }
2798         return true;
2799     }
2800
2801     HRESULT status = S_OK;
2802     EX_TRY
2803     {
2804         pContent = SBuffer::DacGetRawContent();
2805     }
2806     EX_CATCH_HRESULT(status);
2807
2808     if (SUCCEEDED(status) && pContent != NULL)
2809     {
2810         switch (GetRepresentation())
2811         {
2812
2813         case REPRESENTATION_UNICODE:
2814
2815             if (pcNeedChars)
2816             {
2817                 *pcNeedChars = GetCount() + 1;
2818             }
2819
2820             if (pBuffer && cBufChars)
2821             {
2822                 if (cBufChars > GetCount() + 1)
2823                 {
2824                     cBufChars = GetCount() + 1;
2825                 }
2826                 memcpy(pBuffer, pContent, cBufChars * sizeof(*pBuffer));
2827                 pBuffer[cBufChars - 1] = 0;
2828             }
2829
2830             return true;
2831
2832         case REPRESENTATION_UTF8:
2833             iPage = CP_UTF8;
2834         case REPRESENTATION_ASCII:
2835         case REPRESENTATION_ANSI:
2836             // iPage defaults to CP_ACP.
2837             if (pcNeedChars)
2838             {
2839                 *pcNeedChars = WszMultiByteToWideChar(iPage, 0, reinterpret_cast<PSTR>(pContent), -1, NULL, 0);
2840             }
2841             if (pBuffer && cBufChars)
2842             {
2843                 if (!WszMultiByteToWideChar(iPage, 0, reinterpret_cast<PSTR>(pContent), -1, pBuffer, cBufChars))
2844                 {
2845                     return false;
2846                 }
2847             }
2848             return true;
2849
2850         default:
2851             DacNotImpl();
2852             return false;
2853         }
2854     }
2855     return false;
2856 }
2857
2858 #endif //DACCESS_COMPILE