2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
5 // ---------------------------------------------------------------------------
6 // SString.h (Safe String)
9 // ---------------------------------------------------------------------------
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
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
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.
23 // Note that anywhere you express a "position" in a string, it is in terms of the Unicode representation of the
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.
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().
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
40 // @todo: argument & overflow/underflow checking needs to be added
41 // ------------------------------------------------------------------------------------------
50 // ==========================================================================================
51 // Documentational typedefs: use these to indicate specific representations of 8 bit strings:
52 // ==========================================================================================
54 // Note that LPCSTR means ASCII (7-bit) only!
57 typedef ASCII *LPASCII;
58 typedef const ASCII *LPCASCII;
62 typedef const ANSI *LPCANSI;
66 typedef const UTF8 *LPCUTF8;
68 // ==========================================================================================
69 // SString is the base class for safe strings.
70 // ==========================================================================================
73 typedef DPTR(class SString) PTR_SString;
74 class SString : private SBuffer
76 friend struct _DacGlobals;
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
88 REPRESENTATION_VARIABLE_MASK = 0x02,
89 REPRESENTATION_SINGLE_MASK = 0x01,
90 REPRESENTATION_MASK = 0x07,
93 // Minimum guess for Printf buffer size
94 const static COUNT_T MINIMUM_GUESS = 20;
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 *)
103 _ASSERTE(!"Don't call this.");
116 // UIterator is character-level assignable.
119 // CIterators/Iterator'string must be modified by SString APIs.
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 };
133 static void Startup();
134 static CHECK CheckStartup();
136 static const SString &Empty();
140 explicit SString(const SString &s);
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);
159 SString(WCHAR character);
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);
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);
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);
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);
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);
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);
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);
195 void SetASCII(const ASCII *string, COUNT_T count);
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);
203 // Set this string to the unicode character
204 void Set(WCHAR character);
206 // Set this string to the UTF8 character
207 void SetUTF8(CHAR character);
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);
213 // ------------------------------------------------------------------
215 // ------------------------------------------------------------------
217 // Normalizes the string representation to unicode. This can be used to
218 // make basic read-only operations non-failing.
219 void Normalize() const;
221 // Return the number of characters in the string (excluding the terminating NULL).
222 COUNT_T GetCount() const;
223 BOOL IsEmpty() const;
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
228 BOOL IsASCII() const;
230 // !!!!!!!!!!!!!! WARNING about case insensitive operations !!!!!!!!!!!!!!!
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.
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.
240 // !!!!!!!!!!!!!! WARNING about case insensitive operations !!!!!!!!!!!!!!!
242 // Compute a content-based hash value
244 ULONG HashCaseInsensitive() const;
245 ULONG HashCaseInsensitive(LocaleID locale) const;
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;
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;
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;
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;
271 // Like match, but advances the iterator past the match
273 BOOL Skip(CIterator &i, const SString &s) const;
274 BOOL Skip(CIterator &i, WCHAR c) const;
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;
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;
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;
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;
303 // Sets this string to an empty string "".
306 // Truncate the string to the iterator position
307 void Truncate(const Iterator &i);
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);
315 // Append char c to the end of this string.
316 void Append(const WCHAR c);
317 void AppendUTF8(const CHAR c);
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);
325 // Delete substring position + length
326 void Delete(const Iterator &i, COUNT_T length);
328 // Replace character at i with c
329 void Replace(const Iterator &i, WCHAR c);
331 // Replace substring at (i,i+length) with s
332 void Replace(const Iterator &i, COUNT_T length, const SString &s);
334 // Make sure that string buffer has room to grow
335 void Preallocate(COUNT_T characters) const;
337 // Shrink buffer size as much as possible (reallocate if necessary.)
340 // ------------------------------------------------------------------
342 // ------------------------------------------------------------------
344 // SString splits iterators into two categories.
346 // CIterator and Iterator are cheap to create, but allow only read-only
347 // access to the string.
349 // UIterator forces a unicode conversion, but allows
350 // assignment to individual string characters. They are also a bit more
351 // efficient once created.
353 // ------------------------------------------------------------------
355 // ------------------------------------------------------------------
359 class UIndex : public SBuffer::Index
361 friend class SString;
362 friend class Indexer<WCHAR, UIterator>;
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;
373 WCHAR *GetUnicode() const;
378 class UIterator : public UIndex, public Indexer<WCHAR, UIterator>
380 friend class SString;
387 UIterator(SString *string, int index)
388 : UIndex(string, index)
393 UIterator BeginUnicode();
394 UIterator EndUnicode();
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
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.
408 // Normally the user expects to cast Iterators to CIterators transparently, so
409 // we provide a constructor on CIterator to support this.
413 class Index : public SBuffer::Index
415 friend class SString;
417 friend class Indexer<const WCHAR, CIterator>;
418 friend class Indexer<WCHAR, Iterator>;
421 int m_characterSizeShift;
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;
430 void Resync(const SString *string, BYTE *ptr) const;
432 const WCHAR *GetUnicode() const;
433 const CHAR *GetASCII() const;
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;
445 class CIterator : public Index, public Indexer<const WCHAR, CIterator>
447 friend class SString;
450 const Iterator &ConstCast() const
452 return *(const Iterator *)this;
455 Iterator &ConstCast()
457 return *(Iterator *)this;
460 operator const SBuffer::CIterator &() const
462 return *(const SBuffer::CIterator *)this;
465 operator SBuffer::CIterator &()
467 return *(SBuffer::CIterator *)this;
474 CIterator(const SString *string, int index)
475 : Index(const_cast<SString *>(string), index)
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); }
485 class Iterator : public Index, public Indexer<WCHAR, Iterator>
487 friend class SString;
490 operator const CIterator &() const
492 return *(const CIterator *)this;
495 operator CIterator &()
497 return *(CIterator *)this;
500 operator const SBuffer::Iterator &() const
502 return *(const SBuffer::Iterator *)this;
505 operator SBuffer::Iterator &()
507 return *(SBuffer::Iterator *)this;
514 Iterator(SString *string, int index)
515 : Index(string, index)
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); }
526 CIterator Begin() const;
527 CIterator End() const;
532 // ------------------------------------------------------------------
534 // ------------------------------------------------------------------
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.
540 // You can always get a unicode string. This will force a conversion
542 const WCHAR *GetUnicode() const;
543 const WCHAR *GetUnicode(const CIterator &i) const;
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);
551 // These routines will use the given scratch string if necessary
552 // to perform a conversion to the desired representation
554 // Use a local declaration of InlineScratchBuffer or StackScratchBuffer for parameters of
555 // AbstractScratchBuffer.
556 class AbstractScratchBuffer;
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.
567 // StackScratchBuffer buffer;
568 // const UTF8 *utf8 = s->GetUTF8(buffer);
571 // // No more pointers to returned buffer allowed.
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;
580 // Used when the representation is known, throws if the representation doesn't match
581 const UTF8 *GetUTF8NoConvert() const;
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;
591 //-------------------------------------------------------------------
592 // Accessing the string contents directly
593 //-------------------------------------------------------------------
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.
604 // void GetName(SString & str) {
605 // char * p = str.OpenANSIBuffer(3);
607 // str.CloseBuffer();
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.
616 // You should open the buffer, write the data, and immediately close it.
617 // No sstring operations are valid while the buffer is opened.
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.
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);
629 // Get the max size that can be passed to OpenUnicodeBuffer without causing allocations.
630 COUNT_T GetUnicodeAllocation();
632 // Call after OpenXXXBuffer().
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);
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.
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
650 // Instantiate a copy of the raw buffer in the host and return a pointer to it
651 void * DacGetRawContent() const;
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;
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;
662 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags) const
665 SBuffer::EnumMemoryRegions(flags);
669 //---------------------------------------------------------------------
671 //---------------------------------------------------------------------
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);
679 void Printf(const WCHAR *format, ...);
680 void PPrintf(const WCHAR *format, ...);
681 void VPrintf(const WCHAR *format, va_list args);
683 void PVPrintf(const WCHAR *format, va_list args);
685 void AppendPrintf(const CHAR *format, ...);
686 void AppendVPrintf(const CHAR *format, va_list args);
688 void AppendPrintf(const WCHAR *format, ...);
689 void AppendVPrintf(const WCHAR *format, va_list args);
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());
702 // @todo - get rid of this and move it outside of SString
703 void MakeFullNamespacePath(const SString &nameSpace, const SString &name);
706 //--------------------------------------------------------------------
708 //--------------------------------------------------------------------
710 operator const WCHAR * () const { WRAPPER_NO_CONTRACT; return GetUnicode(); }
712 WCHAR operator[](int index) { WRAPPER_NO_CONTRACT; return Begin()[index]; }
713 WCHAR operator[](int index) const { WRAPPER_NO_CONTRACT; return Begin()[index]; }
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; }
718 // -------------------------------------------------------------------
720 // -------------------------------------------------------------------
722 CHECK CheckIteratorRange(const CIterator &i) const;
723 CHECK CheckIteratorRange(const CIterator &i, COUNT_T length) const;
724 CHECK CheckEmpty() const;
726 static CHECK CheckCount(COUNT_T count);
727 static CHECK CheckRepresentation(int representation);
730 static CHECK CheckASCIIString(const ASCII *string);
731 static CHECK CheckASCIIString(const ASCII *string, COUNT_T count);
734 CHECK Invariant() const;
735 CHECK InternalInvariant() const;
736 #endif // CHECK_INVARIANTS
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);
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);
745 // C++ convenience overloads
746 static int _tstricmp(const CHAR *buffer1, const CHAR *buffer2);
747 static int _tstricmp(const WCHAR *buffer1, const WCHAR *buffer2);
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);
752 // -------------------------------------------------------------------
754 // -------------------------------------------------------------------
758 // Use this via InlineSString<X>
759 SString(void *buffer, COUNT_T size);
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);
767 static const BYTE s_EmptyBuffer[2];
770 SVAL_DECL(BOOL, s_IsANSIMultibyte);
772 #ifdef SSTRING_CONSOLECODEPAGE
773 static UINT s_ConsoleCP;
774 static BOOL s_IsConsoleMultibyte;
777 const static LocaleID s_defaultLCID;
779 SPTR_DECL(SString,s_Empty);
781 COUNT_T GetRawCount() const;
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;
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;
801 int GetCharacterSizeShift() const;
803 COUNT_T SizeToCount(COUNT_T size) const;
804 COUNT_T CountToSize(COUNT_T count) const;
806 COUNT_T GetBufferSizeInCharIncludeNullChar() const;
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;
817 void EnsureWritable() const;
818 void ConvertToFixed() const;
819 void ConvertToIteratable() const;
821 void ConvertASCIIToUnicode(SString &dest) const;
822 void ConvertToUnicode() const;
823 void ConvertToUnicode(const CIterator &i) const;
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();
830 void Resize(COUNT_T count, Representation representation,
831 Preserve preserve = DONT_PRESERVE);
833 void OpenBuffer(Representation representation, COUNT_T countChars);
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 // ===========================================================================
842 template <COUNT_T MEMSIZE>
843 class InlineSString : public SString
846 BYTE m_inline[SBUFFER_PADDED_SIZE(MEMSIZE)];
849 FORCEINLINE InlineSString()
850 : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
855 FORCEINLINE InlineSString(const SString &s)
856 : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
862 FORCEINLINE InlineSString(const SString &s1, const SString &s2)
863 : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
869 FORCEINLINE InlineSString(const SString &s1, const SString &s2, const SString &s3)
870 : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
876 FORCEINLINE InlineSString(const SString &s1, const SString &s2, const SString &s3, const SString &s4)
877 : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
883 FORCEINLINE InlineSString(const SString &s, const CIterator &start, const CIterator &end)
884 : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
890 FORCEINLINE InlineSString(const SString &s, const CIterator &i, COUNT_T length)
891 : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
897 FORCEINLINE InlineSString(const WCHAR *string)
898 : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
904 FORCEINLINE InlineSString(const WCHAR *string, COUNT_T count)
905 : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
911 FORCEINLINE InlineSString(enum tagASCII, const CHAR *string)
912 : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
918 FORCEINLINE InlineSString(enum tagASCII, const CHAR *string, COUNT_T count)
919 : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
922 SetASCII(string, count);
925 FORCEINLINE InlineSString(tagUTF8 dummytag, const UTF8 *string)
926 : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
932 FORCEINLINE InlineSString(tagUTF8 dummytag, const UTF8 *string, COUNT_T count)
933 : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
936 SetUTF8(string, count);
939 FORCEINLINE InlineSString(enum tagANSI dummytag, const ANSI *string)
940 : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
946 FORCEINLINE InlineSString(enum tagANSI dummytag, const ANSI *string, COUNT_T count)
947 : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
950 SetANSI(string, count);
953 #ifdef SSTRING_CONSOLECODEPAGE
954 FORCEINLINE InlineSString(enum tagCONSOLE dummytag, const CONSOLE *string)
955 : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
961 FORCEINLINE InlineSString(enum tagCONSOLE dummytag, const CONSOLE *string, COUNT_T count)
962 : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
965 SetCONSOLE(string, count);
969 FORCEINLINE InlineSString(WCHAR character)
970 : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
976 FORCEINLINE InlineSString(tagUTF8 dummytag, const UTF8 character)
977 : SString(m_inline, SBUFFER_PADDED_SIZE(MEMSIZE))
983 FORCEINLINE InlineSString<MEMSIZE> &operator= (const SString &s)
990 FORCEINLINE InlineSString<MEMSIZE> &operator= (const InlineSString<MEMSIZE> &s)
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 // ================================================================================
1003 typedef InlineSString<512> StackSString;
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;
1009 // ================================================================================
1010 // Quick macro to create an SString around a literal string.
1012 // s = SL("My literal String");
1013 // ================================================================================
1015 #define SL(_literal) SString(SString::Literal, _literal)
1017 // ================================================================================
1018 // ScratchBuffer classes are used by the GetXXX() routines to allocate scratch space in.
1019 // ================================================================================
1021 class SString::AbstractScratchBuffer : private SString
1024 // Do not use this class directly - use
1025 // ScratchBuffer or StackScratchBuffer.
1026 AbstractScratchBuffer(void *buffer, COUNT_T size);
1029 template <COUNT_T MEMSIZE>
1030 class ScratchBuffer : public SString::AbstractScratchBuffer
1033 BYTE m_inline[MEMSIZE];
1037 : AbstractScratchBuffer((void *)m_inline, MEMSIZE)
1039 WRAPPER_NO_CONTRACT;
1043 typedef ScratchBuffer<256> StackScratchBuffer;
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 // ================================================================================
1053 #define THROWS_UNLESS_NORMALIZED \
1054 if (IsNormalized()) NOTHROW; else THROWS
1056 #define THROWS_UNLESS_BOTH_NORMALIZED(s) \
1057 if (IsNormalized() && s.IsNormalized()) NOTHROW; else THROWS
1059 #define FAULTS_UNLESS_NORMALIZED(stmt) \
1060 if (IsNormalized()) FORBID_FAULT; else INJECT_FAULT(stmt)
1062 #define FAULTS_UNLESS_BOTH_NORMALIZED(s, stmt) \
1063 if (IsNormalized() && s.IsNormalized()) FORBID_FAULT; else INJECT_FAULT(stmt)
1065 // ================================================================================
1066 // Inline definitions
1067 // ================================================================================
1069 #include <sstring.inl>
1071 #endif // _SSTRING_H_