xref: /reactos/sdk/lib/atl/cstringt.h (revision d0ed4fdb)
1 #ifndef __CSTRINGT_H__
2 #define __CSTRINGT_H__
3 
4 #pragma once
5 #include <atlsimpstr.h>
6 #include <stddef.h>
7 #include <stdio.h>
8 #include <wchar.h>
9 #include <atlmem.h>
10 
11 namespace ATL
12 {
13 
14 inline UINT WINAPI _AtlGetConversionACP() throw()
15 {
16 #ifdef _CONVERSION_DONT_USE_THREAD_LOCALE
17     return CP_ACP;
18 #else
19     return CP_THREAD_ACP;
20 #endif
21 }
22 
23 
24 template<typename _CharType = wchar_t>
25 class ChTraitsCRT : public ChTraitsBase<_CharType>
26 {
27 public:
28 
29     static int __cdecl GetBaseTypeLength(_In_z_ LPCWSTR pszSource) throw()
30     {
31         if (pszSource == NULL) return -1;
32         return static_cast<int>(wcslen(pszSource));
33     }
34 
35     static int __cdecl GetBaseTypeLength(_In_z_ LPCSTR pszSource) throw()
36     {
37         if (pszSource == NULL) return 0;
38         return ::MultiByteToWideChar(_AtlGetConversionACP(), 0, pszSource, -1, NULL, 0) - 1;
39     }
40 
41     static int __cdecl GetBaseTypeLength(
42         _In_reads_(nLength) LPCWSTR pszSource,
43         _In_ int nLength) throw()
44     {
45         return nLength;
46     }
47 
48     static int __cdecl GetBaseTypeLength(
49         _In_reads_(nLength) LPCSTR pszSource,
50         _In_ int nLength) throw()
51     {
52         return ::MultiByteToWideChar(_AtlGetConversionACP(), 0, pszSource, nLength, NULL, 0);
53     }
54 
55     static void __cdecl ConvertToBaseType(
56         _Out_writes_(nDestLength) LPWSTR pszDest,
57         _In_ int nDestLength,
58         _In_ LPCWSTR pszSrc,
59         _In_ int nSrcLength = -1)
60     {
61         if (nSrcLength == -1)
62             nSrcLength = 1 + GetBaseTypeLength(pszSrc);
63 
64         wmemcpy(pszDest, pszSrc, nSrcLength);
65     }
66 
67     static void __cdecl ConvertToBaseType(
68         _Out_writes_(nDestLength) LPWSTR pszDest,
69         _In_ int nDestLength,
70         _In_ LPCSTR pszSrc,
71         _In_ int nSrcLength = -1)
72     {
73         if (nSrcLength == -1)
74             nSrcLength = 1 + GetBaseTypeLength(pszSrc);
75 
76         ::MultiByteToWideChar(_AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength);
77     }
78 
79     static void __cdecl MakeLower(
80         _Out_writes_(nSrcLength) LPWSTR pszSource,
81         _In_ int nSrcLength)
82     {
83         ::CharLowerBuffW(pszSource, nSrcLength);
84     }
85 
86     static DWORD GetEnvironmentVariable(
87         _In_z_ LPCWSTR pszVar,
88         _Out_writes_opt_(nBufLength) LPWSTR pszBuf,
89         _In_opt_ int nBufLength)
90     {
91         return ::GetEnvironmentVariableW(pszVar, pszBuf, nBufLength);
92     }
93 
94     static void __cdecl MakeUpper(
95         _Out_writes_(nSrcLength) LPWSTR pszSource,
96         _In_ int nSrcLength)
97     {
98         ::CharUpperBuffW(pszSource, nSrcLength);
99     }
100 
101     static LPWSTR __cdecl FindString(
102         _In_z_ LPCWSTR pszSource,
103         _In_z_ LPCWSTR pszSub)
104     {
105         return ::wcsstr(pszSource, pszSub);
106     }
107 
108     static LPWSTR __cdecl FindChar(
109         _In_z_ LPCWSTR pszSource,
110         _In_ WCHAR ch)
111     {
112         return ::wcschr(pszSource, ch);
113     }
114 
115     static LPWSTR __cdecl FindCharReverse(
116         _In_z_ LPCWSTR pszSource,
117         _In_ WCHAR ch)
118     {
119         return ::wcsrchr(pszSource, ch);
120     }
121 
122     static LPWSTR __cdecl FindOneOf(
123         _In_z_ LPCWSTR pszSource,
124         _In_z_ LPCWSTR pszCharSet)
125     {
126         return ::wcspbrk(pszSource, pszCharSet);
127     }
128 
129     static int __cdecl Compare(
130         _In_z_ LPCWSTR psz1,
131         _In_z_ LPCWSTR psz2)
132     {
133         return ::wcscmp(psz1, psz2);
134     }
135 
136     static int __cdecl CompareNoCase(
137         _In_z_ LPCWSTR psz1,
138         _In_z_ LPCWSTR psz2)
139     {
140         return ::_wcsicmp(psz1, psz2);
141     }
142 
143     static int __cdecl StringSpanIncluding(
144         _In_z_ LPCWSTR pszBlock,
145         _In_z_ LPCWSTR pszSet)
146     {
147         return (int)::wcsspn(pszBlock, pszSet);
148     }
149 
150     static int __cdecl StringSpanExcluding(
151         _In_z_ LPCWSTR pszBlock,
152         _In_z_ LPCWSTR pszSet)
153     {
154         return (int)::wcscspn(pszBlock, pszSet);
155     }
156 
157     static int __cdecl FormatV(
158         _In_opt_z_ LPWSTR pszDest,
159         _In_z_ LPCWSTR pszFormat,
160         _In_ va_list args)
161     {
162         if (pszDest == NULL)
163             return ::_vscwprintf(pszFormat, args);
164         return ::vswprintf(pszDest, pszFormat, args);
165     }
166 
167     static LPWSTR
168     FormatMessageV(_In_z_ LPCWSTR pszFormat, _In_opt_ va_list *pArgList)
169     {
170         LPWSTR psz;
171         ::FormatMessageW(
172             FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING, pszFormat, 0, 0,
173             reinterpret_cast<LPWSTR>(&psz), 0, pArgList);
174         return psz;
175     }
176 
177     static BSTR __cdecl AllocSysString(
178         _In_z_ LPCWSTR pszSource,
179         _In_ int nLength)
180     {
181         return ::SysAllocStringLen(pszSource, nLength);
182     }
183 };
184 
185 
186 // Template specialization
187 
188 template<>
189 class ChTraitsCRT<char> : public ChTraitsBase<char>
190 {
191 public:
192 
193     static int __cdecl GetBaseTypeLength(_In_z_ LPCWSTR pszSource) throw()
194     {
195         return ::WideCharToMultiByte(_AtlGetConversionACP(), 0, pszSource, -1, NULL, 0, NULL, NULL) - 1;
196     }
197 
198     static int __cdecl GetBaseTypeLength(_In_z_ LPCSTR pszSource) throw()
199     {
200         if (pszSource == NULL) return 0;
201         return static_cast<int>(strlen(pszSource));
202     }
203 
204     static int __cdecl GetBaseTypeLength(
205         _In_reads_(nLength) LPCWSTR pszSource,
206         _In_ int nLength) throw()
207     {
208         return ::WideCharToMultiByte(_AtlGetConversionACP(), 0, pszSource, nLength, NULL, 0, NULL, NULL);
209     }
210 
211     static int __cdecl GetBaseTypeLength(
212         _In_reads_(nLength) LPCSTR pszSource,
213         _In_ int nLength) throw()
214     {
215         return nLength;
216     }
217 
218     static void __cdecl ConvertToBaseType(
219         _Out_writes_(nDestLength) LPSTR pszDest,
220         _In_ int nDestLength,
221         _In_ LPCWSTR pszSrc,
222         _In_ int nSrcLength = -1)
223     {
224         if (nSrcLength == -1)
225             nSrcLength = 1 + GetBaseTypeLength(pszSrc);
226 
227         ::WideCharToMultiByte(_AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength, NULL, NULL);
228     }
229 
230     static void __cdecl ConvertToBaseType(
231         _Out_writes_(nDestLength) LPSTR pszDest,
232         _In_ int nDestLength,
233         _In_ LPCSTR pszSrc,
234         _In_ int nSrcLength = -1)
235     {
236         if (nSrcLength == -1)
237             nSrcLength = 1 + GetBaseTypeLength(pszSrc);
238 
239         memcpy(pszDest, pszSrc, nSrcLength);
240     }
241 
242     static void __cdecl MakeLower(
243         _Out_writes_(nSrcLength) LPSTR pszSource,
244         _In_ int nSrcLength)
245     {
246         ::CharLowerBuffA(pszSource, nSrcLength);
247     }
248 
249     static DWORD GetEnvironmentVariable(
250         _In_z_ LPCSTR pszVar,
251         _Out_writes_opt_(nBufLength) LPSTR pszBuf,
252         _In_opt_ int nBufLength)
253     {
254         return ::GetEnvironmentVariableA(pszVar, pszBuf, nBufLength);
255     }
256 
257     static void __cdecl MakeUpper(
258         _Out_writes_(nSrcLength) LPSTR pszSource,
259         _In_ int nSrcLength)
260     {
261         ::CharUpperBuffA(pszSource, nSrcLength);
262     }
263 
264     static LPSTR __cdecl FindString(
265         _In_z_ LPCSTR pszSource,
266         _In_z_ LPCSTR pszSub)
267     {
268         return ::strstr(pszSource, pszSub);
269     }
270 
271     static LPSTR __cdecl FindChar(
272         _In_z_ LPCSTR pszSource,
273         _In_ CHAR ch)
274     {
275         return ::strchr(pszSource, ch);
276     }
277 
278     static LPSTR __cdecl FindCharReverse(
279         _In_z_ LPCSTR pszSource,
280         _In_ CHAR ch)
281     {
282         return ::strrchr(pszSource, ch);
283     }
284 
285     static LPSTR __cdecl FindOneOf(
286         _In_z_ LPCSTR pszSource,
287         _In_z_ LPCSTR pszCharSet)
288     {
289         return ::strpbrk(pszSource, pszCharSet);
290     }
291 
292     static int __cdecl Compare(
293         _In_z_ LPCSTR psz1,
294         _In_z_ LPCSTR psz2)
295     {
296         return ::strcmp(psz1, psz2);
297     }
298 
299     static int __cdecl CompareNoCase(
300         _In_z_ LPCSTR psz1,
301         _In_z_ LPCSTR psz2)
302     {
303         return ::_stricmp(psz1, psz2);
304     }
305 
306     static int __cdecl StringSpanIncluding(
307         _In_z_ LPCSTR pszBlock,
308         _In_z_ LPCSTR pszSet)
309     {
310         return (int)::strspn(pszBlock, pszSet);
311     }
312 
313     static int __cdecl StringSpanExcluding(
314         _In_z_ LPCSTR pszBlock,
315         _In_z_ LPCSTR pszSet)
316     {
317         return (int)::strcspn(pszBlock, pszSet);
318     }
319 
320     static int __cdecl FormatV(
321         _In_opt_z_ LPSTR pszDest,
322         _In_z_ LPCSTR pszFormat,
323         _In_ va_list args)
324     {
325         if (pszDest == NULL)
326             return ::_vscprintf(pszFormat, args);
327         return ::vsprintf(pszDest, pszFormat, args);
328     }
329 
330     static LPSTR
331     FormatMessageV(_In_z_ LPCSTR pszFormat, _In_opt_ va_list *pArgList)
332     {
333         LPSTR psz;
334         ::FormatMessageA(
335             FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING, pszFormat, 0, 0, reinterpret_cast<LPSTR>(&psz),
336             0, pArgList);
337         return psz;
338     }
339 
340     static BSTR __cdecl AllocSysString(
341         _In_z_ LPCSTR pszSource,
342         _In_ int nLength)
343     {
344         int nLen = ChTraitsCRT<wchar_t>::GetBaseTypeLength(pszSource, nLength);
345         BSTR bstr = ::SysAllocStringLen(NULL, nLen);
346         if (bstr)
347         {
348             ChTraitsCRT<wchar_t>::ConvertToBaseType(bstr, nLen, pszSource, nLength);
349         }
350         return bstr;
351     }
352 
353 };
354 
355 
356 namespace _CSTRING_IMPL_
357 {
358     template <typename _CharType, class StringTraits>
359     struct _MFCDLLTraitsCheck
360     {
361         const static bool c_bIsMFCDLLTraits = false;
362     };
363 }
364 
365 
366 // TODO: disable conversion functions when _CSTRING_DISABLE_NARROW_WIDE_CONVERSION is defined.
367 
368 template <typename BaseType, class StringTraits>
369 class CStringT :
370     public CSimpleStringT <BaseType, _CSTRING_IMPL_::_MFCDLLTraitsCheck<BaseType, StringTraits>::c_bIsMFCDLLTraits>
371 {
372 public:
373     typedef CSimpleStringT<BaseType, _CSTRING_IMPL_::_MFCDLLTraitsCheck<BaseType, StringTraits>::c_bIsMFCDLLTraits> CThisSimpleString;
374     typedef StringTraits StrTraits;
375     typedef typename CThisSimpleString::XCHAR XCHAR;
376     typedef typename CThisSimpleString::PXSTR PXSTR;
377     typedef typename CThisSimpleString::PCXSTR PCXSTR;
378     typedef typename CThisSimpleString::YCHAR YCHAR;
379     typedef typename CThisSimpleString::PYSTR PYSTR;
380     typedef typename CThisSimpleString::PCYSTR PCYSTR;
381 
382 public:
383     CStringT() throw() :
384         CThisSimpleString(StringTraits::GetDefaultManager())
385     {
386     }
387 
388     explicit CStringT( _In_ IAtlStringMgr* pStringMgr) throw() :
389         CThisSimpleString(pStringMgr)
390     {
391     }
392 
393     static void __cdecl Construct(_In_ CStringT* pString)
394     {
395         new(pString) CStringT;
396     }
397 
398     CStringT(_In_ const CStringT& strSrc) :
399         CThisSimpleString(strSrc)
400     {
401     }
402 
403     CStringT(_In_ const CThisSimpleString& strSrc) :
404         CThisSimpleString(strSrc)
405     {
406     }
407 
408     template<class StringTraits_>
409     CStringT(_In_ const CStringT<YCHAR, StringTraits_> & strSrc) :
410         CThisSimpleString(StringTraits::GetDefaultManager())
411     {
412         *this = static_cast<const YCHAR*>(strSrc);
413     }
414 
415 protected:
416     /* helper function */
417     template <typename T_CHAR>
418     void LoadFromPtr_(_In_opt_z_ const T_CHAR* pszSrc)
419     {
420         if (pszSrc == NULL)
421             return;
422         if (IS_INTRESOURCE(pszSrc))
423             LoadString(LOWORD(pszSrc));
424         else
425             *this = pszSrc;
426     }
427 
428 public:
429     CStringT(_In_opt_z_ const XCHAR* pszSrc) :
430         CThisSimpleString(StringTraits::GetDefaultManager())
431     {
432         LoadFromPtr_(pszSrc);
433     }
434 
435     CStringT(_In_opt_z_ const XCHAR* pszSrc,
436              _In_ IAtlStringMgr* pStringMgr) : CThisSimpleString(pStringMgr)
437     {
438         LoadFromPtr_(pszSrc);
439     }
440 
441     CStringT(_In_opt_z_ const YCHAR* pszSrc) :
442         CThisSimpleString(StringTraits::GetDefaultManager())
443     {
444         LoadFromPtr_(pszSrc);
445     }
446 
447     CStringT(_In_opt_z_ const YCHAR* pszSrc,
448              _In_ IAtlStringMgr* pStringMgr) : CThisSimpleString(pStringMgr)
449     {
450         LoadFromPtr_(pszSrc);
451     }
452 
453     CStringT(_In_reads_z_(nLength) const XCHAR* pch,
454              _In_ int nLength) :
455         CThisSimpleString(pch, nLength, StringTraits::GetDefaultManager())
456     {
457     }
458 
459     CStringT(_In_reads_z_(nLength) const YCHAR* pch,
460              _In_ int nLength) :
461         CThisSimpleString(pch, nLength, StringTraits::GetDefaultManager())
462     {
463     }
464 
465     CStringT& operator=(_In_ const CStringT& strSrc)
466     {
467         CThisSimpleString::operator=(strSrc);
468         return *this;
469     }
470 
471     CStringT& operator=(_In_opt_z_ PCXSTR pszSrc)
472     {
473         CThisSimpleString::operator=(pszSrc);
474         return *this;
475     }
476 
477     CStringT& operator=(_In_opt_z_ PCYSTR pszSrc)
478     {
479         int length = pszSrc ? StringTraits::GetBaseTypeLength(pszSrc) : 0;
480         if (length > 0)
481         {
482             PXSTR result = CThisSimpleString::GetBuffer(length);
483             StringTraits::ConvertToBaseType(result, length, pszSrc);
484             CThisSimpleString::ReleaseBufferSetLength(length);
485         }
486         else
487         {
488             CThisSimpleString::Empty();
489         }
490         return *this;
491     }
492 
493     CStringT& operator=(_In_ const CThisSimpleString &strSrc)
494     {
495         CThisSimpleString::operator=(strSrc);
496         return *this;
497     }
498 
499     friend bool operator==(const CStringT& str1, const CStringT& str2) throw()
500     {
501         return str1.Compare(str2) == 0;
502     }
503 
504     friend bool operator==(const CStringT& str1, PCXSTR psz2) throw()
505     {
506         return str1.Compare(psz2) == 0;
507     }
508 
509     friend bool operator==(const CStringT& str1, PCYSTR psz2) throw()
510     {
511         CStringT tmp(psz2, str1.GetManager());
512         return tmp.Compare(str1) == 0;
513     }
514 
515     friend bool operator==(const CStringT& str1, XCHAR ch2) throw()
516     {
517         return str1.GetLength() == 1 && str1[0] == ch2;
518     }
519 
520     friend bool operator==(PCXSTR psz1, const CStringT& str2) throw()
521     {
522         return str2.Compare(psz1) == 0;
523     }
524 
525     friend bool operator==(PCYSTR psz1, const CStringT& str2) throw()
526     {
527         CStringT tmp(psz1, str2.GetManager());
528         return tmp.Compare(str2) == 0;
529     }
530 
531     friend bool operator==(XCHAR ch1, const CStringT& str2) throw()
532     {
533         return str2.GetLength() == 1 && str2[0] == ch1;
534     }
535 
536     CStringT& operator+=(_In_ const CThisSimpleString& str)
537     {
538         CThisSimpleString::operator+=(str);
539         return *this;
540     }
541 
542     CStringT& operator+=(_In_z_ PCXSTR pszSrc)
543     {
544         CThisSimpleString::operator+=(pszSrc);
545         return *this;
546     }
547 
548     CStringT& operator+=(_In_ XCHAR ch)
549     {
550         CThisSimpleString::operator+=(ch);
551         return *this;
552     }
553 
554     BOOL LoadString(_In_ UINT nID)
555     {
556         return LoadString(_AtlBaseModule.GetResourceInstance(), nID);
557     }
558 
559     _Check_return_ BOOL LoadString(_In_ HINSTANCE hInstance,
560                                    _In_ UINT nID)
561     {
562         const ATLSTRINGRESOURCEIMAGE* pImage = AtlGetStringResourceImage(hInstance, nID);
563         if (pImage == NULL) return FALSE;
564 
565         int nLength = StringTraits::GetBaseTypeLength(pImage->achString, pImage->nLength);
566         PXSTR pszBuffer = CThisSimpleString::GetBuffer(nLength);
567         StringTraits::ConvertToBaseType(pszBuffer, nLength, pImage->achString, pImage->nLength);
568         CThisSimpleString::ReleaseBufferSetLength(nLength);
569 
570         return TRUE;
571     }
572 
573     BOOL GetEnvironmentVariable(_In_z_ PCXSTR pszVar)
574     {
575         int nLength = StringTraits::GetEnvironmentVariable(pszVar, NULL, 0);
576 
577         if (nLength > 0)
578         {
579             PXSTR pszBuffer = CThisSimpleString::GetBuffer(nLength);
580             StringTraits::GetEnvironmentVariable(pszVar, pszBuffer, nLength);
581             CThisSimpleString::ReleaseBuffer();
582             return TRUE;
583         }
584 
585         CThisSimpleString::Empty();
586         return FALSE;
587     }
588 
589     CStringT& MakeLower()
590     {
591         int nLength = CThisSimpleString::GetLength();
592         PXSTR pszBuffer = CThisSimpleString::GetBuffer(nLength);
593 
594         StringTraits::MakeLower(pszBuffer, nLength);
595         CThisSimpleString::ReleaseBufferSetLength(nLength);
596 
597         return *this;
598     }
599 
600     CStringT& MakeUpper()
601     {
602         int nLength = CThisSimpleString::GetLength();
603         PXSTR pszBuffer = CThisSimpleString::GetBuffer(nLength);
604 
605         StringTraits::MakeUpper(pszBuffer, nLength);
606         CThisSimpleString::ReleaseBufferSetLength(nLength);
607 
608         return *this;
609     }
610 
611     int Find(_In_ PCXSTR pszSub, _In_opt_ int iStart = 0) const throw()
612     {
613         int nLength = CThisSimpleString::GetLength();
614 
615         if (iStart >= nLength || iStart < 0)
616             return -1;
617 
618         PCXSTR pszString = CThisSimpleString::GetString();
619         PCXSTR pszResult = StringTraits::FindString(pszString + iStart, pszSub);
620 
621         return pszResult ? ((int)(pszResult - pszString)) : -1;
622     }
623 
624     int Find(_In_ XCHAR ch, _In_opt_ int iStart = 0) const throw()
625     {
626         int nLength = CThisSimpleString::GetLength();
627 
628         if (iStart >= nLength || iStart < 0)
629             return -1;
630 
631         PCXSTR pszString = CThisSimpleString::GetString();
632         PCXSTR pszResult = StringTraits::FindChar(pszString + iStart, ch);
633 
634         return pszResult ? ((int)(pszResult - pszString)) : -1;
635     }
636 
637     int FindOneOf(_In_ PCXSTR pszCharSet) const throw()
638     {
639         PCXSTR pszString = CThisSimpleString::GetString();
640         PCXSTR pszResult = StringTraits::FindOneOf(pszString, pszCharSet);
641 
642         return pszResult ? ((int)(pszResult - pszString)) : -1;
643     }
644 
645     int ReverseFind(_In_ XCHAR ch) const throw()
646     {
647         PCXSTR pszString = CThisSimpleString::GetString();
648         PCXSTR pszResult = StringTraits::FindCharReverse(pszString, ch);
649 
650         return pszResult ? ((int)(pszResult - pszString)) : -1;
651     }
652 
653     int Compare(_In_z_ PCXSTR psz) const
654     {
655         return StringTraits::Compare(CThisSimpleString::GetString(), psz);
656     }
657 
658     int CompareNoCase(_In_z_ PCXSTR psz) const
659     {
660         return StringTraits::CompareNoCase(CThisSimpleString::GetString(), psz);
661     }
662 
663     CStringT Mid(int iFirst, int nCount) const
664     {
665         int nLength = CThisSimpleString::GetLength();
666 
667         if (iFirst < 0)
668             iFirst = 0;
669         if (nCount < 0)
670             nCount = 0;
671         if (iFirst > nLength)
672             iFirst = nLength;
673         if (iFirst + nCount > nLength)
674             nCount = nLength - iFirst;
675 
676         return CStringT(CThisSimpleString::GetString() + iFirst, nCount);
677     }
678 
679     CStringT Mid(int iFirst) const
680     {
681         int nLength = CThisSimpleString::GetLength();
682 
683         if (iFirst < 0)
684             iFirst = 0;
685         if (iFirst > nLength)
686             iFirst = nLength;
687 
688         return CStringT(CThisSimpleString::GetString() + iFirst, nLength - iFirst);
689     }
690 
691     CStringT Left(int nCount) const
692     {
693         int nLength = CThisSimpleString::GetLength();
694 
695         if (nCount < 0)
696             nCount = 0;
697         if (nCount > nLength)
698             nCount = nLength;
699 
700         return CStringT(CThisSimpleString::GetString(), nCount);
701     }
702 
703     CStringT Right(int nCount) const
704     {
705         int nLength = CThisSimpleString::GetLength();
706 
707         if (nCount < 0)
708             nCount = 0;
709         if (nCount > nLength)
710             nCount = nLength;
711 
712         return CStringT(CThisSimpleString::GetString() + nLength - nCount, nCount);
713     }
714 
715 
716     void __cdecl Format(UINT nFormatID, ...)
717     {
718         va_list args;
719         va_start(args, nFormatID);
720         CStringT formatString;
721         if (formatString.LoadString(nFormatID))
722             FormatV(formatString, args);
723         va_end(args);
724     }
725 
726     void __cdecl Format(PCXSTR pszFormat, ...)
727     {
728         va_list args;
729         va_start(args, pszFormat);
730         FormatV(pszFormat, args);
731         va_end(args);
732     }
733 
734     void FormatV(PCXSTR pszFormat, va_list args)
735     {
736         int nLength = StringTraits::FormatV(NULL, pszFormat, args);
737 
738         PXSTR pszBuffer = CThisSimpleString::GetBuffer(nLength);
739         StringTraits::FormatV(pszBuffer, pszFormat, args);
740         CThisSimpleString::ReleaseBufferSetLength(nLength);
741     }
742 
743     void __cdecl FormatMessage(UINT nFormatID, ...)
744     {
745         va_list va;
746         va_start(va, nFormatID);
747 
748         CStringT str;
749         if (str.LoadString(nFormatID))
750             FormatMessageV(str, &va);
751 
752         va_end(va);
753     }
754 
755     void __cdecl FormatMessage(PCXSTR pszFormat, ...)
756     {
757         va_list va;
758         va_start(va, pszFormat);
759         FormatMessageV(pszFormat, &va);
760         va_end(va);
761     }
762 
763     void
764     FormatMessageV(PCXSTR pszFormat, va_list *pArgList)
765     {
766         PXSTR psz = StringTraits::FormatMessageV(pszFormat, pArgList);
767         if (!psz)
768             CThisSimpleString::ThrowMemoryException();
769 
770         *this = psz;
771         ::LocalFree(psz);
772     }
773 
774     int Replace(PCXSTR pszOld, PCXSTR pszNew)
775     {
776         PCXSTR pszString = CThisSimpleString::GetString();
777 
778         const int nLength = CThisSimpleString::GetLength();
779         const int nOldLen = StringTraits::GetBaseTypeLength(pszOld);
780         const int nNewLen = StringTraits::GetBaseTypeLength(pszNew);
781         const int nDiff = nNewLen - nOldLen;
782         int nResultLength = nLength;
783 
784         PCXSTR pszFound;
785         while ((pszFound = StringTraits::FindString(pszString, pszOld)))
786         {
787             nResultLength += nDiff;
788             pszString = pszFound + nOldLen;
789         }
790 
791         if (pszString == CThisSimpleString::GetString())
792             return 0;
793 
794         PXSTR pszResult = CThisSimpleString::GetBuffer(nResultLength);
795         PXSTR pszNext;
796         int nCount = 0, nRemaining = nLength;
797         while (nRemaining && (pszNext = StringTraits::FindString(pszResult, pszOld)))
798         {
799             nRemaining -= (pszNext - pszResult);
800             nRemaining -= nOldLen;
801             if (nRemaining > 0)
802                 CThisSimpleString::CopyCharsOverlapped(pszNext + nNewLen, nRemaining + 1, pszNext + nOldLen, nRemaining + 1);
803             CThisSimpleString::CopyCharsOverlapped(pszNext, nNewLen, pszNew, nNewLen);
804             pszResult = pszNext + nNewLen;
805             nCount++;
806         }
807 
808         CThisSimpleString::ReleaseBufferSetLength(nResultLength);
809 
810         return nCount;
811     }
812 
813     int Replace(XCHAR chOld, XCHAR chNew)
814     {
815         PCXSTR pszString = CThisSimpleString::GetString();
816         PXSTR pszFirst = StringTraits::FindChar(pszString, chOld);
817         if (!pszFirst)
818             return 0;
819 
820         int nLength = CThisSimpleString::GetLength();
821         int nCount = 0;
822 
823         PXSTR pszBuffer = CThisSimpleString::GetBuffer(nLength);
824         pszFirst = pszBuffer + (pszFirst - pszString);
825         do {
826             *pszFirst = chNew;
827             ++nCount;
828         } while ((pszFirst = StringTraits::FindChar(pszFirst + 1, chOld)));
829 
830         CThisSimpleString::ReleaseBufferSetLength(nLength);
831         return nCount;
832     }
833 
834 
835     CStringT Tokenize(_In_z_ PCXSTR pszTokens, _Inout_ int& iStart) const
836     {
837         ATLASSERT(iStart >= 0);
838 
839         if (iStart < 0)
840             AtlThrow(E_INVALIDARG);
841 
842         if (!pszTokens || !pszTokens[0])
843         {
844             if (iStart < CThisSimpleString::GetLength())
845             {
846                 return Mid(iStart);
847             }
848             iStart = -1;
849             return CStringT();
850         }
851 
852         if (iStart < CThisSimpleString::GetLength())
853         {
854             int iRangeOffset = StringTraits::StringSpanIncluding(CThisSimpleString::GetString() + iStart, pszTokens);
855 
856             if (iRangeOffset + iStart < CThisSimpleString::GetLength())
857             {
858                 int iNewStart = iStart + iRangeOffset;
859                 int nCount = StringTraits::StringSpanExcluding(CThisSimpleString::GetString() + iNewStart, pszTokens);
860 
861                 iStart = iNewStart + nCount + 1;
862 
863                 return Mid(iNewStart, nCount);
864             }
865         }
866 
867         iStart = -1;
868         return CStringT();
869     }
870 
871     static PCXSTR DefaultTrimChars()
872     {
873         static XCHAR str[] = { ' ', '\t', '\r', '\n', 0 };
874         return str;
875     }
876 
877 
878     CStringT& TrimLeft()
879     {
880         return TrimLeft(DefaultTrimChars());
881     }
882 
883     CStringT& TrimLeft(XCHAR chTarget)
884     {
885         XCHAR str[2] = { chTarget, 0 };
886         return TrimLeft(str);
887     }
888 
889     CStringT& TrimLeft(PCXSTR pszTargets)
890     {
891         int nLength = CThisSimpleString::GetLength();
892         PXSTR pszBuffer = CThisSimpleString::GetBuffer(nLength);
893         int nCount = 0;
894 
895         while (nCount < nLength && StringTraits::FindChar(pszTargets, pszBuffer[nCount]))
896             nCount++;
897 
898         if (nCount > 0)
899         {
900             CThisSimpleString::CopyCharsOverlapped(pszBuffer, nLength - nCount, pszBuffer + nCount, nLength - nCount);
901             nLength -= nCount;
902         }
903         CThisSimpleString::ReleaseBufferSetLength(nLength);
904 
905         return *this;
906     }
907 
908 
909     CStringT& TrimRight()
910     {
911         return TrimRight(DefaultTrimChars());
912     }
913 
914     CStringT& TrimRight(XCHAR chTarget)
915     {
916         XCHAR str[2] = { chTarget, 0 };
917         return TrimRight(str);
918     }
919 
920     CStringT& TrimRight(PCXSTR pszTargets)
921     {
922         int nLength = CThisSimpleString::GetLength();
923         PXSTR pszBuffer = CThisSimpleString::GetBuffer(nLength);
924 
925         while (nLength > 0 && StringTraits::FindChar(pszTargets, pszBuffer[nLength-1]))
926             nLength--;
927 
928         CThisSimpleString::ReleaseBufferSetLength(nLength);
929 
930         return *this;
931     }
932 
933 
934     CStringT& Trim()
935     {
936         return Trim(DefaultTrimChars());
937     }
938 
939     CStringT& Trim(XCHAR chTarget)
940     {
941         XCHAR str[2] = { chTarget, 0 };
942         return Trim(str);
943     }
944 
945     CStringT& Trim(PCXSTR pszTargets)
946     {
947         return TrimRight(pszTargets).TrimLeft(pszTargets);
948     }
949 
950 
951     BSTR AllocSysString() const
952     {
953         return StringTraits::AllocSysString(CThisSimpleString::GetString(), CThisSimpleString::GetLength());
954     }
955 
956 
957 };
958 
959 } //namespace ATL
960 
961 #endif
962