Add a fourth parameter to the DEFINE_DACVAR macro that is the actual fully qualified...
[platform/upstream/coreclr.git] / src / inc / sstring.h
1 //
2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
4 //
5 // ---------------------------------------------------------------------------
6 // SString.h  (Safe String)
7 // 
8
9 // ---------------------------------------------------------------------------
10
11 // ------------------------------------------------------------------------------------------
12 // SString is the "standard" string representation for the EE.  Its has two purposes.
13 // (1) it provides an easy-to-use, relatively efficient, string class for APIs to standardize
14 //      on.
15 // (2) it completely encapsulates all "unsafe" string operations - that is, string operations
16 //      which yield possible buffer overrun bugs.  Typesafe use of this API should help guarantee
17 //      safety.
18 //
19 // A SString is conceptually unicode, although the internal conversion might be delayed as long as possible
20 // Basically it's up to the implementation whether conversion takes place immediately or is delayed, and if
21 // delayed, what operations trigger the conversion.
22 //
23 // Note that anywhere you express a "position" in a string, it is in terms of the Unicode representation of the
24 // string.
25 //
26 // If you need a direct non-unicode representation, you will have to provide a fresh SString which can
27 // recieve a conversion operation if necessary.
28 //
29 // The alternate encodings available are:
30 // 1. ASCII - string consisting entirely of ASCII (7 bit) characters.  This is the only 1 byte encoding
31 //    guaranteed to be fixed width. Such a string is also a valid instance of all the other 1 byte string
32 //    representations, and we take advantage of this fact.
33 // 2. UTF-8 - standard multibyte unicode encoding.
34 // 3. ANSI - Potentially multibyte encoding using the ANSI page determined by GetACP().
35 //
36 // @todo: Note that we could also provide support for several other cases (but currently do not.)
37 //  - Page specified by GetOEMCP() (OEM page)
38 //  - Arbitrary page support
39 //
40 // @todo: argument & overflow/underflow checking needs to be added
41 // ------------------------------------------------------------------------------------------
42
43
44 #ifndef _SSTRING_H_
45 #define _SSTRING_H_
46
47 #include "utilcode.h"
48 #include "sbuffer.h"
49
50 // ==========================================================================================
51 // Documentational typedefs: use these to indicate specific representations of 8 bit strings:
52 // ==========================================================================================
53
54 // Note that LPCSTR means ASCII (7-bit) only!
55
56 typedef CHAR ASCII;
57 typedef ASCII *LPASCII;
58 typedef const ASCII *LPCASCII;
59
60 typedef CHAR ANSI;
61 typedef ANSI *LPANSI;
62 typedef const ANSI *LPCANSI;
63
64 typedef CHAR UTF8;
65 typedef UTF8 *LPUTF8;
66 typedef const UTF8 *LPCUTF8;
67
68 // ==========================================================================================
69 // SString is the base class for safe strings.
70 // ==========================================================================================
71
72
73 typedef DPTR(class SString) PTR_SString;
74 class SString : private SBuffer
75 {
76     friend struct _DacGlobals;
77
78 private:
79     enum Representation
80     {
81         // Note: bits are meaningful:      xVS  V == Variable?  S == Single byte width?
82         REPRESENTATION_EMPTY    = 0x00, // 000
83         REPRESENTATION_UNICODE  = 0x04, // 100
84         REPRESENTATION_ASCII    = 0x01, // 001
85         REPRESENTATION_UTF8     = 0x03, // 011
86         REPRESENTATION_ANSI     = 0x07, // 111
87
88         REPRESENTATION_VARIABLE_MASK    = 0x02,
89         REPRESENTATION_SINGLE_MASK      = 0x01,
90         REPRESENTATION_MASK             = 0x07,
91     };
92
93     // Minimum guess for Printf buffer size
94     const static COUNT_T MINIMUM_GUESS = 20;
95
96
97 #ifdef _DEBUG
98     // Used to have a public ctor of this form - made it too easy to lose
99     // utf8 info by accident. Now you have to specify the representation type
100     // explicitly - this privator ctor prevents reinsertion of this ctor.
101     explicit SString(const ASCII *)
102     {
103         _ASSERTE(!"Don't call this.");
104     }
105 #endif
106
107   protected:
108     class Index;
109     class UIndex;
110
111     friend class Index;
112     friend class UIndex;
113
114   public:
115
116     // UIterator is character-level assignable.
117     class UIterator;
118
119     // CIterators/Iterator'string must be modified by SString APIs.
120     class CIterator;
121     class Iterator;
122
123     // Tokens for constructor overloads
124     enum tagUTF8Literal { Utf8Literal };
125     enum tagLiteral { Literal };
126     enum tagUTF8 { Utf8 };
127     enum tagANSI { Ansi };
128     enum tagASCII {Ascii };
129 #ifdef SSTRING_CONSOLECODEPAGE
130     enum tagCONSOLE { Console };
131 #endif
132
133     static void Startup();
134     static CHECK CheckStartup();
135
136     static const SString &Empty();
137
138     SString();
139
140     explicit SString(const SString &s);
141
142     SString(const SString &s1, const SString &s2);
143     SString(const SString &s1, const SString &s2, const SString &s3);
144     SString(const SString &s1, const SString &s2, const SString &s3, const SString &s4);
145     SString(const SString &s, const CIterator &i, COUNT_T length);
146     SString(const SString &s, const CIterator &start, const CIterator &end);
147     SString(const WCHAR *string);
148     SString(const WCHAR *string, COUNT_T count);
149     SString(enum tagASCII dummyTag, const ASCII *string);
150     SString(enum tagASCII dummyTag, const ASCII *string, COUNT_T count);
151     SString(enum tagUTF8 dummytag, const UTF8 *string);
152     SString(enum tagUTF8 dummytag, const UTF8 *string, COUNT_T count);
153     SString(enum tagANSI dummytag, const ANSI *string);
154     SString(enum tagANSI dummytag, const ANSI *string, COUNT_T count);
155 #ifdef SSTRING_CONSOLECODEPAGE
156     SString(enum tagCONSOLE dummytag, const CONSOLE *string);
157     SString(enum tagCONSOLE dummytag, const CONSOLE *string, COUNT_T count);
158 #endif
159     SString(WCHAR character);
160
161     // NOTE: Literals MUST be read-only never-freed strings.
162     SString(enum tagLiteral dummytag, const CHAR *literal);
163     SString(enum tagUTF8Literal dummytag, const UTF8 *literal);
164     SString(enum tagLiteral dummytag, const WCHAR *literal);
165     SString(enum tagLiteral dummytag, const WCHAR *literal, COUNT_T count);
166
167     // Set this string to the concatenation of s1,s2,s3,s4
168     void Set(const SString &s);
169     void Set(const SString &s1, const SString &s2);
170     void Set(const SString &s1, const SString &s2, const SString &s3);
171     void Set(const SString &s1, const SString &s2, const SString &s3, const SString &s4);
172
173     // Set this string to the substring of s, starting at i, of length characters.
174     void Set(const SString &s, const CIterator &i, COUNT_T length);
175
176     // Set this string to the substring of s, starting at start and ending at end (exclusive)
177     void Set(const SString &s, const CIterator &start, const CIterator &end);
178
179     // Set this string to a copy of the given string
180     void Set(const WCHAR *string);
181     void SetASCII(const ASCII *string);
182     void SetUTF8(const UTF8 *string);
183     void SetANSI(const ANSI *string);
184 #ifdef SSTRING_CONSOLECODEPAGE
185     void SetConsole(const CONSOLE *string);
186 #endif
187
188     // Set this string to a copy of the first count chars of the given string
189     void Set(const WCHAR *string, COUNT_T count);
190
191     // Set this string to a prellocated copy of a given string.
192     // The caller is the owner of the bufffer and has to coordinate its lifetime.
193     void SetPreallocated(const WCHAR *string, COUNT_T count);
194
195     void SetASCII(const ASCII *string, COUNT_T count);
196
197     void SetUTF8(const UTF8 *string, COUNT_T count);
198     void SetANSI(const ANSI *string, COUNT_T count);
199 #ifdef SSTRING_CONSOLECODEPAGE
200     void SetConsole(const CONSOLE *string, COUNT_T count);
201 #endif
202
203     // Set this string to the unicode character
204     void Set(WCHAR character);
205
206     // Set this string to the UTF8 character
207     void SetUTF8(CHAR character);
208
209     // This this string to the given literal. We share the mem and don't make a copy.
210     void SetLiteral(const CHAR *literal);
211     void SetLiteral(const WCHAR *literal);
212
213     // ------------------------------------------------------------------
214     // Public operations
215     // ------------------------------------------------------------------
216
217     // Normalizes the string representation to unicode.  This can be used to
218     // make basic read-only operations non-failing.
219     void Normalize() const;
220
221     // Return the number of characters in the string (excluding the terminating NULL).
222     COUNT_T GetCount() const;
223     BOOL IsEmpty() const;
224
225     // Return whether a single byte string has all characters which fit in the ASCII set.  
226     // (Note that this will return FALSE if the string has been converted to unicode for any 
227     // reason.)
228     BOOL IsASCII() const;
229
230     // !!!!!!!!!!!!!! WARNING about case insensitive operations !!!!!!!!!!!!!!! 
231     //
232     //                 THIS IS NOT SUPPORTED FULLY ON WIN9x  
233     //      SString case-insensitive comparison is based off LCMapString, 
234     //      which does not work on characters outside the current OS code page.
235     //
236     //      Case insensitive code in SString is primarily targeted at 
237     //      supporting path comparisons, which is supported correctly on 9x, 
238     //      since file system names are limited to the OS code page.
239     // 
240     // !!!!!!!!!!!!!! WARNING about case insensitive operations !!!!!!!!!!!!!!! 
241
242     // Compute a content-based hash value
243     ULONG Hash() const;
244     ULONG HashCaseInsensitive() const;
245     ULONG HashCaseInsensitive(LocaleID locale) const;
246
247     // Do a string comparison. Return 0 if the strings
248     // have the same value,  -1 if this is "less than" s, or 1 if
249     // this is "greater than" s.
250     int Compare(const SString &s) const;
251     int CompareCaseInsensitive(const SString &s) const; // invariant locale
252     int CompareCaseInsensitive(const SString &s, LocaleID locale) const;
253
254     // Do a case sensitive string comparison. Return TRUE if the strings
255     // have the same value FALSE if not.
256     BOOL Equals(const SString &s) const;
257     BOOL EqualsCaseInsensitive(const SString &s) const; // invariant locale
258     BOOL EqualsCaseInsensitive(const SString &s, LocaleID locale) const;
259
260     // Match s to a portion of the string starting at the position.
261     // Return TRUE if the strings have the same value
262     // (regardless of representation), FALSE if not.
263     BOOL Match(const CIterator &i, const SString &s) const;
264     BOOL MatchCaseInsensitive(const CIterator &i, const SString &s) const; // invariant locale
265     BOOL MatchCaseInsensitive(const CIterator &i, const SString &s, LocaleID locale) const;
266
267     BOOL Match(const CIterator &i, WCHAR c) const;
268     BOOL MatchCaseInsensitive(const CIterator &i, WCHAR c) const; // invariant locale
269     BOOL MatchCaseInsensitive(const CIterator &i, WCHAR c, LocaleID locale) const;
270
271     // Like match, but advances the iterator past the match
272     // if successful
273     BOOL Skip(CIterator &i, const SString &s) const;
274     BOOL Skip(CIterator &i, WCHAR c) const;
275
276     // Start searching for a match of the given string, starting at
277     // the given iterator point.
278     // If a match exists, move the iterator to point to the nearest
279     // occurence of s in the string and return TRUE.
280     // If no match exists, return FALSE and leave the iterator unchanged.
281     BOOL Find(CIterator &i, const SString &s) const;
282     BOOL Find(CIterator &i, const WCHAR *s) const;
283     BOOL FindASCII(CIterator &i, const ASCII *s) const;
284     BOOL FindUTF8(CIterator &i, const UTF8 *s) const;
285     BOOL Find(CIterator &i, WCHAR c) const;
286
287     BOOL FindBack(CIterator &i, const SString &s) const;
288     BOOL FindBack(CIterator &i, const WCHAR *s) const;
289     BOOL FindBackASCII(CIterator &i, const ASCII *s) const;
290     BOOL FindBackUTF8(CIterator &i, const UTF8 *s) const;
291     BOOL FindBack(CIterator &i, WCHAR c) const;
292
293     // Returns TRUE if this string begins with the contents of s
294     BOOL BeginsWith(const SString &s) const;
295     BOOL BeginsWithCaseInsensitive(const SString &s) const; // invariant locale
296     BOOL BeginsWithCaseInsensitive(const SString &s, LocaleID locale) const;
297
298     // Returns TRUE if this string ends with the contents of s
299     BOOL EndsWith(const SString &s) const;
300     BOOL EndsWithCaseInsensitive(const SString &s) const; // invariant locale
301     BOOL EndsWithCaseInsensitive(const SString &s, LocaleID locale) const;
302
303     // Sets this string to an empty string "".
304     void Clear();
305
306     // Truncate the string to the iterator position
307     void Truncate(const Iterator &i);
308
309     // Append s to the end of this string.
310     void Append(const SString &s);
311     void Append(const WCHAR *s);
312     void AppendASCII(const CHAR *s);
313     void AppendUTF8(const CHAR *s);
314
315     // Append char c to the end of this string.
316     void Append(const WCHAR c);
317     void AppendUTF8(const CHAR c);
318
319     // Insert s into this string at the 'position'th character.
320     void Insert(const Iterator &i, const SString &s);
321     void Insert(const Iterator &i, const WCHAR *s);
322     void InsertASCII(const Iterator &i, const CHAR *s);
323     void InsertUTF8(const Iterator &i, const CHAR *s);
324
325     // Delete substring position + length
326     void Delete(const Iterator &i, COUNT_T length);
327
328     // Replace character at i with c
329     void Replace(const Iterator &i, WCHAR c);
330
331     // Replace substring at (i,i+length) with s
332     void Replace(const Iterator &i, COUNT_T length, const SString &s);
333
334     // Make sure that string buffer has room to grow
335     void Preallocate(COUNT_T characters) const;
336
337     // Shrink buffer size as much as possible (reallocate if necessary.)
338     void Trim() const;
339
340     // ------------------------------------------------------------------
341     // Iterators:
342     // ------------------------------------------------------------------
343
344     // SString splits iterators into two categories.  
345     //
346     // CIterator and Iterator are cheap to create, but allow only read-only
347     // access to the string.  
348     //
349     // UIterator forces a unicode conversion, but allows
350     // assignment to individual string characters.  They are also a bit more 
351     // efficient once created.
352
353     // ------------------------------------------------------------------
354     // UIterator:
355     // ------------------------------------------------------------------
356
357  protected:
358
359     class UIndex : public SBuffer::Index
360     {
361         friend class SString;
362         friend class Indexer<WCHAR, UIterator>;
363
364       protected:
365
366         UIndex();
367         UIndex(SString *string, SCOUNT_T index);
368         WCHAR &GetAt(SCOUNT_T delta) const;
369         void Skip(SCOUNT_T delta);
370         SCOUNT_T Subtract(const UIndex &i) const;
371         CHECK DoCheck(SCOUNT_T delta) const;
372
373         WCHAR *GetUnicode() const;
374     };
375
376  public:
377
378     class UIterator : public UIndex, public Indexer<WCHAR, UIterator>
379     {
380         friend class SString;
381
382     public:
383         UIterator()
384         {
385         }
386
387         UIterator(SString *string, int index)
388           : UIndex(string, index)
389         {
390         }
391     };
392
393     UIterator BeginUnicode();
394     UIterator EndUnicode();
395
396     // For CIterator & Iterator, we try our best to iterate the string without
397     // modifying it. (Currently, we do require an ASCII or Unicode string
398     // for simple WCHAR retrival, but you could imagine being more flexible
399     // going forward - perhaps even supporting iterating multibyte encodings
400     // directly.)
401     //
402     // Because of the runtime-changable nature of the string, CIterators
403     // require an extra member to record the character size. They also
404     // are unable to properly implement GetAt as required by the template
405     // (since there may not be a direct WCHAR pointer), so they provide
406     // further customization in a subclass.
407     //
408     // Normally the user expects to cast Iterators to CIterators transparently, so
409     // we provide a constructor on CIterator to support this.
410
411  protected:
412
413     class Index : public SBuffer::Index
414     {
415         friend class SString;
416
417         friend class Indexer<const WCHAR, CIterator>;
418         friend class Indexer<WCHAR, Iterator>;
419
420       protected:
421         int               m_characterSizeShift;
422
423         Index();
424         Index(SString *string, SCOUNT_T index);
425         BYTE &GetAt(SCOUNT_T delta) const;
426         void Skip(SCOUNT_T delta);
427         SCOUNT_T Subtract(const Index &i) const;
428         CHECK DoCheck(SCOUNT_T delta) const;
429
430         void Resync(const SString *string, BYTE *ptr) const;
431
432         const WCHAR *GetUnicode() const;
433         const CHAR *GetASCII() const;
434
435       public:
436         // Note these should supercede the Indexer versions
437         // since this class comes first in the inheritence list
438         WCHAR operator*() const;
439         void operator->() const;
440         WCHAR operator[](int index) const;
441     };
442
443  public:
444
445     class CIterator : public Index, public Indexer<const WCHAR, CIterator>
446     {
447         friend class SString;
448
449       public:
450         const Iterator &ConstCast() const
451         {
452             return *(const Iterator *)this;
453         }
454
455         Iterator &ConstCast()
456         {
457             return *(Iterator *)this;
458         }
459
460         operator const SBuffer::CIterator &() const
461         {
462             return *(const SBuffer::CIterator *)this;
463         }
464
465         operator SBuffer::CIterator &()
466         {
467             return *(SBuffer::CIterator *)this;
468         }
469
470         CIterator()
471         {
472         }
473
474         CIterator(const SString *string, int index)
475           : Index(const_cast<SString *>(string), index)
476         {
477         }
478
479         // explicitly resolve these for gcc
480         WCHAR operator*() const { return Index::operator*(); }
481         void operator->() const { Index::operator->(); }
482         WCHAR operator[](int index) const { return Index::operator[](index); }
483     };
484
485     class Iterator : public Index, public Indexer<WCHAR, Iterator>
486     {
487         friend class SString;
488
489       public:
490         operator const CIterator &() const
491         {
492             return *(const CIterator *)this;
493         }
494
495         operator CIterator &()
496         {
497             return *(CIterator *)this;
498         }
499
500         operator const SBuffer::Iterator &() const
501         {
502             return *(const SBuffer::Iterator *)this;
503         }
504
505         operator SBuffer::Iterator &()
506         {
507             return *(SBuffer::Iterator *)this;
508         }
509
510         Iterator()
511         {
512         }
513
514         Iterator(SString *string, int index)
515           : Index(string, index)
516         {
517             SUPPORTS_DAC;
518         }
519
520         // explicitly resolve these for gcc
521         WCHAR operator*() const { return Index::operator*(); }
522         void operator->() const { Index::operator->(); }
523         WCHAR operator[](int index) const { return Index::operator[](index); }
524     };
525
526     CIterator Begin() const;
527     CIterator End() const;
528
529     Iterator Begin();
530     Iterator End();
531
532     // ------------------------------------------------------------------
533     // Conversion:
534     // ------------------------------------------------------------------
535
536     // Get a const pointer to the string in the current representation.
537     // This pointer can not be cached because it will become invalid if
538     // the SString changes representation or reallocates its buffer.
539
540     // You can always get a unicode string.  This will force a conversion
541     // if necessary.
542     const WCHAR *GetUnicode() const;
543     const WCHAR *GetUnicode(const CIterator &i) const;
544
545     void LowerCase();
546     void UpperCase();
547     
548     // Helper function to convert string in-place to lower-case (no allocation overhead for SString instance)
549     static void LowerCase(__inout_z LPWSTR wszString);
550     
551     // These routines will use the given scratch string if necessary
552     // to perform a conversion to the desired representation
553
554     // Use a local declaration of InlineScratchBuffer or StackScratchBuffer for parameters of
555     // AbstractScratchBuffer.
556     class AbstractScratchBuffer;
557
558     // These routines will use the given scratch buffer if necessary
559     // to perform a conversion to the desired representation.  Note that
560     // the lifetime of the pointer return is limited by BOTH the
561     // scratch string and the source (this) string.
562     //
563     // Typical usage:
564     //
565     // SString *s = ...;
566     // {
567     //   StackScratchBuffer buffer;
568     //   const UTF8 *utf8 = s->GetUTF8(buffer);
569     //   CallFoo(utf8);
570     // }
571     // // No more pointers to returned buffer allowed.
572
573     const UTF8 *GetUTF8(AbstractScratchBuffer &scratch) const;
574     const UTF8 *GetUTF8(AbstractScratchBuffer &scratch, COUNT_T *pcbUtf8) const;
575     const ANSI *GetANSI(AbstractScratchBuffer &scratch) const;
576 #ifdef SSTRING_CONSOLECODEPAGE
577     const CONSOLE *GetConsole(AbstractScratchBuffer &scratch) const;
578 #endif
579
580     // Used when the representation is known, throws if the representation doesn't match
581     const UTF8 *GetUTF8NoConvert() const;
582
583     // Converts/copies into the given output string
584     void ConvertToUnicode(SString &dest) const;
585     void ConvertToANSI(SString &dest) const;
586     COUNT_T ConvertToUTF8(SString &dest) const;
587 #ifdef SSTRING_CONSOLECODEPAGE
588     void ConvertToConsole(SString &dest) const;
589 #endif
590
591     //-------------------------------------------------------------------
592     // Accessing the string contents directly
593     //-------------------------------------------------------------------
594
595     // To write directly to the SString's underlying buffer:
596     // 1) Call OpenXXXBuffer() and pass it the count of characters
597     // you need. (Not including the null-terminator).
598     // 2) That returns a pointer to the raw buffer which you can write to.
599     // 3) When you are done writing to the pointer, call CloseBuffer()
600     // and pass it the count of characters you actually wrote (not including
601     // the null). The pointer from step 1 is now invalid.
602
603     // example usage:
604     // void GetName(SString & str) {
605     //      char * p = str.OpenANSIBuffer(3);
606     //      strcpy(p, "Cat");
607     //      str.CloseBuffer();
608     // }
609
610     // Regarding the null-terminator:
611     // 1) Note that we wrote 4 characters (3 + a null). That's ok. OpenBuffer
612     // allocates 1 extra byte for the null.
613     // 2) If we only wrote 3 characters and no null, that's ok too. CloseBuffer()
614     // will add a null-terminator.
615
616     // You should open the buffer, write the data, and immediately close it.
617     // No sstring operations are valid while the buffer is opened.
618     //
619     // In a debug build, Open/Close will do lots of little checks to make sure
620     // you don't buffer overflow while it's opened. In a retail build, this
621     // is a very streamlined action.
622
623
624     // Open the raw buffer for writing countChars characters (not including the null).
625     WCHAR *OpenUnicodeBuffer(COUNT_T maxCharCount);
626     UTF8 *OpenUTF8Buffer(COUNT_T maxSingleCharCount);
627     ANSI *OpenANSIBuffer(COUNT_T maxSingleCharCount);
628
629     // Get the max size that can be passed to OpenUnicodeBuffer without causing allocations.
630     COUNT_T GetUnicodeAllocation();
631
632     // Call after OpenXXXBuffer().
633
634     // Provide the count of characters actually used (not including the
635     // null terminator). This will make sure the SString's size is correct
636     // and that we have a null-terminator.
637     void CloseBuffer(COUNT_T finalCount);
638
639     // Close the buffer. Assumes that we completely filled the buffer
640     // that OpenBuffer() gave back. If we didn't write all the characters,
641     // call CloseBuffer(int) instead.
642     void CloseBuffer();
643
644 #ifdef DACCESS_COMPILE
645     // DAC access to string functions.
646     // Note that other accessors above are not DAC-safe and will return TARGET pointers into
647     // the string instead of copying the string over to the host.
648     // @dbgtodo  dac support: Prevent usage of such DAC-unsafe SString APIs in DAC code
649
650     // Instantiate a copy of the raw buffer in the host and return a pointer to it
651     void * DacGetRawContent() const;
652
653     // Instantiate a copy of the raw buffer in the host.  Requires that the underlying 
654     // representation is already unicode.
655     const WCHAR * DacGetRawUnicode() const;
656
657     // Copy the string from the target into the provided buffer, converting to unicode if necessary
658     bool DacGetUnicode(COUNT_T                                  bufChars,
659                        __out_z __inout_ecount(bufChars) WCHAR * buffer,
660                        COUNT_T *                                needChars) const;
661
662     void EnumMemoryRegions(CLRDataEnumMemoryFlags flags) const
663     {
664         SUPPORTS_DAC;
665         SBuffer::EnumMemoryRegions(flags);
666     }
667 #endif
668
669     //---------------------------------------------------------------------
670     // Utilities
671     //---------------------------------------------------------------------
672
673     // WARNING: The MBCS version of printf function are factory for globalization
674     // issues when used to format Unicode strings (%S). The Unicode versions are
675     // preffered in this case.
676     void Printf(const CHAR *format, ...);
677     void VPrintf(const CHAR *format, va_list args);
678
679     void Printf(const WCHAR *format, ...);
680     void PPrintf(const WCHAR *format, ...);
681     void VPrintf(const WCHAR *format, va_list args);
682
683     void PVPrintf(const WCHAR *format, va_list args);
684
685     void AppendPrintf(const CHAR *format, ...);
686     void AppendVPrintf(const CHAR *format, va_list args);
687
688     void AppendPrintf(const WCHAR *format, ...);
689     void AppendVPrintf(const WCHAR *format, va_list args);
690
691     BOOL LoadResource(CCompRC::ResourceCategory eCategory, int resourceID);
692     HRESULT LoadResourceAndReturnHR(CCompRC::ResourceCategory eCategory, int resourceID);
693     HRESULT LoadResourceAndReturnHR(CCompRC* pResourceDLL, CCompRC::ResourceCategory eCategory, int resourceID);
694     BOOL FormatMessage(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId,
695                        const SString &arg1 = Empty(), const SString &arg2 = Empty(),
696                        const SString &arg3 = Empty(), const SString &arg4 = Empty(),
697                        const SString &arg5 = Empty(), const SString &arg6 = Empty(),
698                        const SString &arg7 = Empty(), const SString &arg8 = Empty(),
699                        const SString &arg9 = Empty(), const SString &arg10 = Empty());
700
701 #if 1
702     // @todo - get rid of this and move it outside of SString
703     void MakeFullNamespacePath(const SString &nameSpace, const SString &name);
704 #endif
705
706     //--------------------------------------------------------------------
707     // Operators
708     //--------------------------------------------------------------------
709
710     operator const WCHAR * () const { WRAPPER_NO_CONTRACT; return GetUnicode(); }
711
712     WCHAR operator[](int index) { WRAPPER_NO_CONTRACT; return Begin()[index]; }
713     WCHAR operator[](int index) const { WRAPPER_NO_CONTRACT; return Begin()[index]; }
714
715     SString &operator= (const SString &s) { WRAPPER_NO_CONTRACT; Set(s); return *this; }
716     SString &operator+= (const SString &s) { WRAPPER_NO_CONTRACT; Append(s); return *this; }
717
718     // -------------------------------------------------------------------
719     // Check functions
720     // -------------------------------------------------------------------
721
722     CHECK CheckIteratorRange(const CIterator &i) const;
723     CHECK CheckIteratorRange(const CIterator &i, COUNT_T length) const;
724     CHECK CheckEmpty() const;
725
726     static CHECK CheckCount(COUNT_T count);
727     static CHECK CheckRepresentation(int representation);
728
729 #if CHECK_INVARIANTS
730     static CHECK CheckASCIIString(const ASCII *string);
731     static CHECK CheckASCIIString(const ASCII *string, COUNT_T count);
732
733     CHECK Check() const;
734     CHECK Invariant() const;
735     CHECK InternalInvariant() const;
736 #endif  // CHECK_INVARIANTS
737
738     // Helpers for CRT function equivalance.
739     static int __cdecl _stricmp(const CHAR *buffer1, const CHAR *buffer2);
740     static int __cdecl _strnicmp(const CHAR *buffer1, const CHAR *buffer2, COUNT_T count);
741
742     static int __cdecl _wcsicmp(const WCHAR *buffer1, const WCHAR *buffer2);
743     static int __cdecl _wcsnicmp(const WCHAR *buffer1, const WCHAR *buffer2, COUNT_T count);
744
745     // C++ convenience overloads
746     static int _tstricmp(const CHAR *buffer1, const CHAR *buffer2);
747     static int _tstricmp(const WCHAR *buffer1, const WCHAR *buffer2);
748
749     static int _tstrnicmp(const CHAR *buffer1, const CHAR *buffer2, COUNT_T count);
750     static int _tstrnicmp(const WCHAR *buffer1, const WCHAR *buffer2, COUNT_T count);
751
752     // -------------------------------------------------------------------
753     // Internal routines
754     // -------------------------------------------------------------------
755
756
757  protected:
758     // Use this via InlineSString<X>
759     SString(void *buffer, COUNT_T size);
760
761  private:
762     static int CaseCompareHelperA(const CHAR *buffer1, const CHAR *buffer2, COUNT_T count, LocaleID lcid, BOOL stopOnNull, BOOL stopOnCount);
763     static int CaseCompareHelper(const WCHAR *buffer1, const WCHAR *buffer2, COUNT_T count, LocaleID lcid, BOOL stopOnNull, BOOL stopOnCount);
764     
765     // Internal helpers:
766
767     static const BYTE s_EmptyBuffer[2];
768
769     static UINT s_ACP;
770     SVAL_DECL(BOOL, s_IsANSIMultibyte);
771
772 #ifdef SSTRING_CONSOLECODEPAGE
773     static UINT s_ConsoleCP;
774     static BOOL s_IsConsoleMultibyte;
775 #endif
776
777     const static LocaleID s_defaultLCID;
778
779     SPTR_DECL(SString,s_Empty);
780
781     COUNT_T GetRawCount() const;
782
783     // Get buffer as appropriate string rep
784     ASCII *GetRawASCII() const;
785     UTF8 *GetRawUTF8() const;
786     ANSI *GetRawANSI() const;
787     WCHAR *GetRawUnicode() const;
788 #ifdef SSTRING_CONSOLECODEPAGE
789     CONSOLE *GetRawConsole() const;
790 #endif
791
792     void InitEmpty();
793
794     Representation GetRepresentation() const;
795     void SetRepresentation(Representation representation);
796     BOOL IsRepresentation(Representation representation) const;
797     BOOL IsFixedSize() const;
798     BOOL IsIteratable() const;
799     BOOL IsSingleByte() const;
800
801     int GetCharacterSizeShift() const;
802
803     COUNT_T SizeToCount(COUNT_T size) const;
804     COUNT_T CountToSize(COUNT_T count) const;
805
806     COUNT_T GetBufferSizeInCharIncludeNullChar() const;
807
808     BOOL IsLiteral() const;
809     BOOL IsAllocated() const;
810     BOOL IsBufferOpen() const;
811     BOOL IsASCIIScanned() const;
812     void SetASCIIScanned() const;
813     void SetNormalized() const;
814     BOOL IsNormalized() const;
815     void ClearNormalized() const;
816
817     void EnsureWritable() const;
818     void ConvertToFixed() const;
819     void ConvertToIteratable() const;
820
821     void ConvertASCIIToUnicode(SString &dest) const;
822     void ConvertToUnicode() const;
823     void ConvertToUnicode(const CIterator &i) const;
824   
825     const SString &GetCompatibleString(const SString &s, SString &scratch) const;
826     const SString &GetCompatibleString(const SString &s, SString &scratch, const CIterator &i) const;
827     BOOL ScanASCII() const;
828     void NullTerminate();
829
830     void Resize(COUNT_T count, Representation representation, 
831                 Preserve preserve = DONT_PRESERVE);
832
833     void OpenBuffer(Representation representation, COUNT_T countChars);
834 };
835
836 // ===========================================================================
837 // InlineSString is used for stack allocation of strings, or when the string contents
838 // are expected or known to be small.  Note that it still supports expandability via
839 // heap allocation if necessary.
840 // ===========================================================================
841
842 template <COUNT_T MEMSIZE>
843 class InlineSString : public SString
844 {
845 private:
846     BYTE m_inline[SBUFFER_PADDED_SIZE(MEMSIZE)];
847
848 public:
849     FORCEINLINE InlineSString()
850       : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
851     {
852         WRAPPER_NO_CONTRACT;
853     }
854
855     FORCEINLINE InlineSString(const SString &s)
856       : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
857     {
858         WRAPPER_NO_CONTRACT;
859         Set(s);
860     }
861
862     FORCEINLINE InlineSString(const SString &s1, const SString &s2)
863       : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
864     {
865         WRAPPER_NO_CONTRACT;
866         Set(s1, s2);
867     }
868
869     FORCEINLINE InlineSString(const SString &s1, const SString &s2, const SString &s3)
870       : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
871     {
872         WRAPPER_NO_CONTRACT;
873         Set(s1, s2, s3);
874     }
875
876     FORCEINLINE InlineSString(const SString &s1, const SString &s2, const SString &s3, const SString &s4)
877       : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
878     {
879         WRAPPER_NO_CONTRACT;
880         Set(s1, s2, s3, s4);
881     }
882
883     FORCEINLINE InlineSString(const SString &s, const CIterator &start, const CIterator &end)
884       : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
885     {
886         WRAPPER_NO_CONTRACT;
887         Set(s, start, end);
888     }
889
890     FORCEINLINE InlineSString(const SString &s, const CIterator &i, COUNT_T length)
891       : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
892     {
893         WRAPPER_NO_CONTRACT;
894         Set(s, i, length);
895     }
896
897     FORCEINLINE InlineSString(const WCHAR *string)
898       : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
899     {
900         WRAPPER_NO_CONTRACT;
901         Set(string);
902     }
903
904     FORCEINLINE InlineSString(const WCHAR *string, COUNT_T count)
905       : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
906     {
907         WRAPPER_NO_CONTRACT;
908         Set(string, count);
909     }
910
911     FORCEINLINE InlineSString(enum tagASCII, const CHAR *string)
912       : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
913     {
914         WRAPPER_NO_CONTRACT;
915         SetASCII(string);
916     }
917
918     FORCEINLINE InlineSString(enum tagASCII, const CHAR *string, COUNT_T count)
919       : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
920     {
921         WRAPPER_NO_CONTRACT;
922         SetASCII(string, count);
923     }
924
925     FORCEINLINE InlineSString(tagUTF8 dummytag, const UTF8 *string)
926       : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
927     {
928         WRAPPER_NO_CONTRACT;
929         SetUTF8(string);
930     }
931
932     FORCEINLINE InlineSString(tagUTF8 dummytag, const UTF8 *string, COUNT_T count)
933       : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
934     {
935         WRAPPER_NO_CONTRACT;
936         SetUTF8(string, count);
937     }
938
939     FORCEINLINE InlineSString(enum tagANSI dummytag, const ANSI *string)
940       : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
941     {
942         WRAPPER_NO_CONTRACT;
943         SetANSI(string);
944     }
945
946     FORCEINLINE InlineSString(enum tagANSI dummytag, const ANSI *string, COUNT_T count)
947       : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
948     {
949         WRAPPER_NO_CONTRACT;
950         SetANSI(string, count);
951     }
952
953 #ifdef SSTRING_CONSOLECODEPAGE
954     FORCEINLINE InlineSString(enum tagCONSOLE dummytag, const CONSOLE *string)
955       : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
956     {
957         WRAPPER_NO_CONTRACT;
958         SetCONSOLE(string);
959     }
960
961     FORCEINLINE InlineSString(enum tagCONSOLE dummytag, const CONSOLE *string, COUNT_T count)
962       : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
963     {
964         WRAPPER_NO_CONTRACT;
965         SetCONSOLE(string, count);
966     }
967 #endif
968
969     FORCEINLINE InlineSString(WCHAR character)
970       : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
971     {
972         WRAPPER_NO_CONTRACT;
973         Set(character);
974     }
975
976     FORCEINLINE InlineSString(tagUTF8 dummytag, const UTF8 character)
977       : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
978     {
979         WRAPPER_NO_CONTRACT;
980         SetUTF8(character);
981     }
982
983     FORCEINLINE InlineSString<MEMSIZE> &operator= (const SString &s)
984     {
985         WRAPPER_NO_CONTRACT;
986         Set(s);
987         return *this;
988     }
989
990     FORCEINLINE InlineSString<MEMSIZE> &operator= (const InlineSString<MEMSIZE> &s)
991     {
992         WRAPPER_NO_CONTRACT;
993         Set(s);
994         return *this;
995     }
996 };
997
998 // ================================================================================
999 // StackSString is a lot like CQuickBytes.  Use it to create an SString object
1000 // using some stack space as a preallocated buffer.
1001 // ================================================================================
1002
1003 typedef InlineSString<512> StackSString;
1004
1005 // This is a smaller version for when it is known that the string that's going to
1006 // be needed is small and it's preferable not to take up the stack space.
1007 typedef InlineSString<32>  SmallStackSString;
1008
1009 // ================================================================================
1010 // Quick macro to create an SString around a literal string.
1011 // usage:
1012 //        s = SL("My literal String");
1013 // ================================================================================
1014
1015 #define SL(_literal) SString(SString::Literal, _literal)
1016
1017 // ================================================================================
1018 // ScratchBuffer classes are used by the GetXXX() routines to allocate scratch space in.
1019 // ================================================================================
1020
1021 class SString::AbstractScratchBuffer : private SString
1022 {
1023   protected:
1024     // Do not use this class directly - use
1025     // ScratchBuffer or StackScratchBuffer.
1026     AbstractScratchBuffer(void *buffer, COUNT_T size);
1027 };
1028
1029 template <COUNT_T MEMSIZE>
1030 class ScratchBuffer : public SString::AbstractScratchBuffer
1031 {
1032   private:
1033     BYTE m_inline[MEMSIZE];
1034
1035   public:
1036     ScratchBuffer()
1037     : AbstractScratchBuffer((void *)m_inline, MEMSIZE)
1038     {
1039         WRAPPER_NO_CONTRACT;
1040     }
1041 };
1042
1043 typedef ScratchBuffer<256> StackScratchBuffer;
1044
1045 // ================================================================================
1046 // Special contract definition - THROWS_UNLESS_NORMALIZED
1047 // this is used for operations which might fail for generalized strings but
1048 // not if the string has already been converted to unicode.  Rather than just
1049 // setting this on all conversions to unicode, we only set it when explicitly
1050 // asked.  This should expose more potential problems.
1051 // ================================================================================
1052
1053 #define THROWS_UNLESS_NORMALIZED \
1054     if (IsNormalized()) NOTHROW; else THROWS
1055
1056 #define THROWS_UNLESS_BOTH_NORMALIZED(s) \
1057     if (IsNormalized() && s.IsNormalized()) NOTHROW; else THROWS
1058
1059 #define FAULTS_UNLESS_NORMALIZED(stmt) \
1060     if (IsNormalized()) FORBID_FAULT; else INJECT_FAULT(stmt)
1061
1062 #define FAULTS_UNLESS_BOTH_NORMALIZED(s, stmt) \
1063     if (IsNormalized() && s.IsNormalized()) FORBID_FAULT; else INJECT_FAULT(stmt)
1064
1065 // ================================================================================
1066 // Inline definitions
1067 // ================================================================================
1068
1069 #include <sstring.inl>
1070
1071 #endif  // _SSTRING_H_