xref: /reactos/sdk/lib/atl/cstringt.h (revision 139a3d66)
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 FormatV(
144         _In_opt_z_ LPWSTR pszDest,
145         _In_z_ LPCWSTR pszFormat,
146         _In_ va_list args)
147     {
148         if (pszDest == NULL)
149             return ::_vscwprintf(pszFormat, args);
150         return ::vswprintf(pszDest, pszFormat, args);
151     }
152 
153     static LPWSTR
154     FormatMessageV(_In_z_ LPCWSTR pszFormat, _In_opt_ va_list *pArgList)
155     {
156         LPWSTR psz;
157         ::FormatMessageW(
158             FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING, pszFormat, 0, 0,
159             reinterpret_cast<LPWSTR>(&psz), 0, pArgList);
160         return psz;
161     }
162 
163     static BSTR __cdecl AllocSysString(
164         _In_z_ LPCWSTR pszSource,
165         _In_ int nLength)
166     {
167         return ::SysAllocStringLen(pszSource, nLength);
168     }
169 };
170 
171 
172 // Template specialization
173 
174 template<>
175 class ChTraitsCRT<char> : public ChTraitsBase<char>
176 {
177 public:
178 
179     static int __cdecl GetBaseTypeLength(_In_z_ LPCWSTR pszSource) throw()
180     {
181         return ::WideCharToMultiByte(_AtlGetConversionACP(), 0, pszSource, -1, NULL, 0, NULL, NULL) - 1;
182     }
183 
184     static int __cdecl GetBaseTypeLength(_In_z_ LPCSTR pszSource) throw()
185     {
186         if (pszSource == NULL) return 0;
187         return static_cast<int>(strlen(pszSource));
188     }
189 
190     static int __cdecl GetBaseTypeLength(
191         _In_reads_(nLength) LPCWSTR pszSource,
192         _In_ int nLength) throw()
193     {
194         return ::WideCharToMultiByte(_AtlGetConversionACP(), 0, pszSource, nLength, NULL, 0, NULL, NULL);
195     }
196 
197     static int __cdecl GetBaseTypeLength(
198         _In_reads_(nLength) LPCSTR pszSource,
199         _In_ int nLength) throw()
200     {
201         return nLength;
202     }
203 
204     static void __cdecl ConvertToBaseType(
205         _Out_writes_(nDestLength) LPSTR pszDest,
206         _In_ int nDestLength,
207         _In_ LPCWSTR pszSrc,
208         _In_ int nSrcLength = -1)
209     {
210         if (nSrcLength == -1)
211             nSrcLength = 1 + GetBaseTypeLength(pszSrc);
212 
213         ::WideCharToMultiByte(_AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength, NULL, NULL);
214     }
215 
216     static void __cdecl ConvertToBaseType(
217         _Out_writes_(nDestLength) LPSTR pszDest,
218         _In_ int nDestLength,
219         _In_ LPCSTR pszSrc,
220         _In_ int nSrcLength = -1)
221     {
222         if (nSrcLength == -1)
223             nSrcLength = 1 + GetBaseTypeLength(pszSrc);
224 
225         memcpy(pszDest, pszSrc, nSrcLength);
226     }
227 
228     static void __cdecl MakeLower(
229         _Out_writes_(nSrcLength) LPSTR pszSource,
230         _In_ int nSrcLength)
231     {
232         ::CharLowerBuffA(pszSource, nSrcLength);
233     }
234 
235     static DWORD GetEnvironmentVariable(
236         _In_z_ LPCSTR pszVar,
237         _Out_writes_opt_(nBufLength) LPSTR pszBuf,
238         _In_opt_ int nBufLength)
239     {
240         return ::GetEnvironmentVariableA(pszVar, pszBuf, nBufLength);
241     }
242 
243     static void __cdecl MakeUpper(
244         _Out_writes_(nSrcLength) LPSTR pszSource,
245         _In_ int nSrcLength)
246     {
247         ::CharUpperBuffA(pszSource, nSrcLength);
248     }
249 
250     static LPSTR __cdecl FindString(
251         _In_z_ LPCSTR pszSource,
252         _In_z_ LPCSTR pszSub)
253     {
254         return ::strstr(pszSource, pszSub);
255     }
256 
257     static LPSTR __cdecl FindChar(
258         _In_z_ LPCSTR pszSource,
259         _In_ CHAR ch)
260     {
261         return ::strchr(pszSource, ch);
262     }
263 
264     static LPSTR __cdecl FindCharReverse(
265         _In_z_ LPCSTR pszSource,
266         _In_ CHAR ch)
267     {
268         return ::strrchr(pszSource, ch);
269     }
270 
271     static LPSTR __cdecl FindOneOf(
272         _In_z_ LPCSTR pszSource,
273         _In_z_ LPCSTR pszCharSet)
274     {
275         return ::strpbrk(pszSource, pszCharSet);
276     }
277 
278     static int __cdecl Compare(
279         _In_z_ LPCSTR psz1,
280         _In_z_ LPCSTR psz2)
281     {
282         return ::strcmp(psz1, psz2);
283     }
284 
285     static int __cdecl CompareNoCase(
286         _In_z_ LPCSTR psz1,
287         _In_z_ LPCSTR psz2)
288     {
289         return ::_stricmp(psz1, psz2);
290     }
291 
292     static int __cdecl FormatV(
293         _In_opt_z_ LPSTR pszDest,
294         _In_z_ LPCSTR pszFormat,
295         _In_ va_list args)
296     {
297         if (pszDest == NULL)
298             return ::_vscprintf(pszFormat, args);
299         return ::vsprintf(pszDest, pszFormat, args);
300     }
301 
302     static LPSTR
303     FormatMessageV(_In_z_ LPCSTR pszFormat, _In_opt_ va_list *pArgList)
304     {
305         LPSTR psz;
306         ::FormatMessageA(
307             FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING, pszFormat, 0, 0, reinterpret_cast<LPSTR>(&psz),
308             0, pArgList);
309         return psz;
310     }
311 
312     static BSTR __cdecl AllocSysString(
313         _In_z_ LPCSTR pszSource,
314         _In_ int nLength)
315     {
316         int nLen = ChTraitsCRT<wchar_t>::GetBaseTypeLength(pszSource, nLength);
317         BSTR bstr = ::SysAllocStringLen(NULL, nLen);
318         if (bstr)
319         {
320             ChTraitsCRT<wchar_t>::ConvertToBaseType(bstr, nLen, pszSource, nLength);
321         }
322         return bstr;
323     }
324 
325 };
326 
327 
328 namespace _CSTRING_IMPL_
329 {
330     template <typename _CharType, class StringTraits>
331     struct _MFCDLLTraitsCheck
332     {
333         const static bool c_bIsMFCDLLTraits = false;
334     };
335 }
336 
337 
338 // TODO: disable conversion functions when _CSTRING_DISABLE_NARROW_WIDE_CONVERSION is defined.
339 
340 template <typename BaseType, class StringTraits>
341 class CStringT :
342     public CSimpleStringT <BaseType, _CSTRING_IMPL_::_MFCDLLTraitsCheck<BaseType, StringTraits>::c_bIsMFCDLLTraits>
343 {
344 public:
345     typedef CSimpleStringT<BaseType, _CSTRING_IMPL_::_MFCDLLTraitsCheck<BaseType, StringTraits>::c_bIsMFCDLLTraits> CThisSimpleString;
346     typedef StringTraits StrTraits;
347     typedef typename CThisSimpleString::XCHAR XCHAR;
348     typedef typename CThisSimpleString::PXSTR PXSTR;
349     typedef typename CThisSimpleString::PCXSTR PCXSTR;
350     typedef typename CThisSimpleString::YCHAR YCHAR;
351     typedef typename CThisSimpleString::PYSTR PYSTR;
352     typedef typename CThisSimpleString::PCYSTR PCYSTR;
353 
354 public:
355     CStringT() throw() :
356         CThisSimpleString(StringTraits::GetDefaultManager())
357     {
358     }
359 
360     explicit CStringT( _In_ IAtlStringMgr* pStringMgr) throw() :
361         CThisSimpleString(pStringMgr)
362     {
363     }
364 
365     static void __cdecl Construct(_In_ CStringT* pString)
366     {
367         new(pString) CStringT;
368     }
369 
370     CStringT(_In_ const CStringT& strSrc) :
371         CThisSimpleString(strSrc)
372     {
373     }
374 
375     CStringT(_In_ const CThisSimpleString& strSrc) :
376         CThisSimpleString(strSrc)
377     {
378     }
379 
380     template<class StringTraits_>
381     CStringT(_In_ const CStringT<YCHAR, StringTraits_> & strSrc) :
382         CThisSimpleString(StringTraits::GetDefaultManager())
383     {
384         *this = static_cast<const YCHAR*>(strSrc);
385     }
386 
387 protected:
388     /* helper function */
389     template <typename T_CHAR>
390     void LoadFromPtr_(_In_opt_z_ const T_CHAR* pszSrc)
391     {
392         if (pszSrc == NULL)
393             return;
394         if (IS_INTRESOURCE(pszSrc))
395             LoadString(LOWORD(pszSrc));
396         else
397             *this = pszSrc;
398     }
399 
400 public:
401     CStringT(_In_opt_z_ const XCHAR* pszSrc) :
402         CThisSimpleString(StringTraits::GetDefaultManager())
403     {
404         LoadFromPtr_(pszSrc);
405     }
406 
407     CStringT(_In_opt_z_ const XCHAR* pszSrc,
408              _In_ IAtlStringMgr* pStringMgr) : CThisSimpleString(pStringMgr)
409     {
410         LoadFromPtr_(pszSrc);
411     }
412 
413     CStringT(_In_opt_z_ const YCHAR* pszSrc) :
414         CThisSimpleString(StringTraits::GetDefaultManager())
415     {
416         LoadFromPtr_(pszSrc);
417     }
418 
419     CStringT(_In_opt_z_ const YCHAR* pszSrc,
420              _In_ IAtlStringMgr* pStringMgr) : CThisSimpleString(pStringMgr)
421     {
422         LoadFromPtr_(pszSrc);
423     }
424 
425     CStringT(_In_reads_z_(nLength) const XCHAR* pch,
426              _In_ int nLength) :
427         CThisSimpleString(pch, nLength, StringTraits::GetDefaultManager())
428     {
429     }
430 
431     CStringT(_In_reads_z_(nLength) const YCHAR* pch,
432              _In_ int nLength) :
433         CThisSimpleString(pch, nLength, StringTraits::GetDefaultManager())
434     {
435     }
436 
437     CStringT& operator=(_In_ const CStringT& strSrc)
438     {
439         CThisSimpleString::operator=(strSrc);
440         return *this;
441     }
442 
443     CStringT& operator=(_In_opt_z_ PCXSTR pszSrc)
444     {
445         CThisSimpleString::operator=(pszSrc);
446         return *this;
447     }
448 
449     CStringT& operator=(_In_opt_z_ PCYSTR pszSrc)
450     {
451         int length = pszSrc ? StringTraits::GetBaseTypeLength(pszSrc) : 0;
452         if (length > 0)
453         {
454             PXSTR result = CThisSimpleString::GetBuffer(length);
455             StringTraits::ConvertToBaseType(result, length, pszSrc);
456             CThisSimpleString::ReleaseBufferSetLength(length);
457         }
458         else
459         {
460             CThisSimpleString::Empty();
461         }
462         return *this;
463     }
464 
465     CStringT& operator=(_In_ const CThisSimpleString &strSrc)
466     {
467         CThisSimpleString::operator=(strSrc);
468         return *this;
469     }
470 
471     friend bool operator==(const CStringT& str1, const CStringT& str2) throw()
472     {
473         return str1.Compare(str2) == 0;
474     }
475 
476     friend bool operator==(const CStringT& str1, PCXSTR psz2) throw()
477     {
478         return str1.Compare(psz2) == 0;
479     }
480 
481     friend bool operator==(const CStringT& str1, PCYSTR psz2) throw()
482     {
483         CStringT tmp(psz2, str1.GetManager());
484         return tmp.Compare(str1) == 0;
485     }
486 
487     friend bool operator==(const CStringT& str1, XCHAR ch2) throw()
488     {
489         return str1.GetLength() == 1 && str1[0] == ch2;
490     }
491 
492     friend bool operator==(PCXSTR psz1, const CStringT& str2) throw()
493     {
494         return str2.Compare(psz1) == 0;
495     }
496 
497     friend bool operator==(PCYSTR psz1, const CStringT& str2) throw()
498     {
499         CStringT tmp(psz1, str2.GetManager());
500         return tmp.Compare(str2) == 0;
501     }
502 
503     friend bool operator==(XCHAR ch1, const CStringT& str2) throw()
504     {
505         return str2.GetLength() == 1 && str2[0] == ch1;
506     }
507 
508     CStringT& operator+=(_In_ const CThisSimpleString& str)
509     {
510         CThisSimpleString::operator+=(str);
511         return *this;
512     }
513 
514     CStringT& operator+=(_In_z_ PCXSTR pszSrc)
515     {
516         CThisSimpleString::operator+=(pszSrc);
517         return *this;
518     }
519 
520     CStringT& operator+=(_In_ XCHAR ch)
521     {
522         CThisSimpleString::operator+=(ch);
523         return *this;
524     }
525 
526     BOOL LoadString(_In_ UINT nID)
527     {
528         return LoadString(_AtlBaseModule.GetResourceInstance(), nID);
529     }
530 
531     _Check_return_ BOOL LoadString(_In_ HINSTANCE hInstance,
532                                    _In_ UINT nID)
533     {
534         const ATLSTRINGRESOURCEIMAGE* pImage = AtlGetStringResourceImage(hInstance, nID);
535         if (pImage == NULL) return FALSE;
536 
537         int nLength = StringTraits::GetBaseTypeLength(pImage->achString, pImage->nLength);
538         PXSTR pszBuffer = CThisSimpleString::GetBuffer(nLength);
539         StringTraits::ConvertToBaseType(pszBuffer, nLength, pImage->achString, pImage->nLength);
540         CThisSimpleString::ReleaseBufferSetLength(nLength);
541 
542         return TRUE;
543     }
544 
545     BOOL GetEnvironmentVariable(_In_z_ PCXSTR pszVar)
546     {
547         int nLength = StringTraits::GetEnvironmentVariable(pszVar, NULL, 0);
548 
549         if (nLength > 0)
550         {
551             PXSTR pszBuffer = CThisSimpleString::GetBuffer(nLength);
552             StringTraits::GetEnvironmentVariable(pszVar, pszBuffer, nLength);
553             CThisSimpleString::ReleaseBuffer();
554             return TRUE;
555         }
556 
557         CThisSimpleString::Empty();
558         return FALSE;
559     }
560 
561     CStringT& MakeLower()
562     {
563         int nLength = CThisSimpleString::GetLength();
564         PXSTR pszBuffer = CThisSimpleString::GetBuffer(nLength);
565 
566         StringTraits::MakeLower(pszBuffer, nLength);
567         CThisSimpleString::ReleaseBufferSetLength(nLength);
568 
569         return *this;
570     }
571 
572     CStringT& MakeUpper()
573     {
574         int nLength = CThisSimpleString::GetLength();
575         PXSTR pszBuffer = CThisSimpleString::GetBuffer(nLength);
576 
577         StringTraits::MakeUpper(pszBuffer, nLength);
578         CThisSimpleString::ReleaseBufferSetLength(nLength);
579 
580         return *this;
581     }
582 
583     int Find(_In_ PCXSTR pszSub, _In_opt_ int iStart = 0) const throw()
584     {
585         int nLength = CThisSimpleString::GetLength();
586 
587         if (iStart >= nLength || iStart < 0)
588             return -1;
589 
590         PCXSTR pszString = CThisSimpleString::GetString();
591         PCXSTR pszResult = StringTraits::FindString(pszString + iStart, pszSub);
592 
593         return pszResult ? ((int)(pszResult - pszString)) : -1;
594     }
595 
596     int Find(_In_ XCHAR ch, _In_opt_ int iStart = 0) const throw()
597     {
598         int nLength = CThisSimpleString::GetLength();
599 
600         if (iStart >= nLength || iStart < 0)
601             return -1;
602 
603         PCXSTR pszString = CThisSimpleString::GetString();
604         PCXSTR pszResult = StringTraits::FindChar(pszString + iStart, ch);
605 
606         return pszResult ? ((int)(pszResult - pszString)) : -1;
607     }
608 
609     int FindOneOf(_In_ PCXSTR pszCharSet) const throw()
610     {
611         PCXSTR pszString = CThisSimpleString::GetString();
612         PCXSTR pszResult = StringTraits::FindOneOf(pszString, pszCharSet);
613 
614         return pszResult ? ((int)(pszResult - pszString)) : -1;
615     }
616 
617     int ReverseFind(_In_ XCHAR ch) const throw()
618     {
619         PCXSTR pszString = CThisSimpleString::GetString();
620         PCXSTR pszResult = StringTraits::FindCharReverse(pszString, ch);
621 
622         return pszResult ? ((int)(pszResult - pszString)) : -1;
623     }
624 
625     int Compare(_In_z_ PCXSTR psz) const
626     {
627         return StringTraits::Compare(CThisSimpleString::GetString(), psz);
628     }
629 
630     int CompareNoCase(_In_z_ PCXSTR psz) const
631     {
632         return StringTraits::CompareNoCase(CThisSimpleString::GetString(), psz);
633     }
634 
635     CStringT Mid(int iFirst, int nCount) const
636     {
637         int nLength = CThisSimpleString::GetLength();
638 
639         if (iFirst < 0)
640             iFirst = 0;
641         if (nCount < 0)
642             nCount = 0;
643         if (iFirst > nLength)
644             iFirst = nLength;
645         if (iFirst + nCount > nLength)
646             nCount = nLength - iFirst;
647 
648         return CStringT(CThisSimpleString::GetString() + iFirst, nCount);
649     }
650 
651     CStringT Mid(int iFirst) const
652     {
653         int nLength = CThisSimpleString::GetLength();
654 
655         if (iFirst < 0)
656             iFirst = 0;
657         if (iFirst > nLength)
658             iFirst = nLength;
659 
660         return CStringT(CThisSimpleString::GetString() + iFirst, nLength - iFirst);
661     }
662 
663     CStringT Left(int nCount) const
664     {
665         int nLength = CThisSimpleString::GetLength();
666 
667         if (nCount < 0)
668             nCount = 0;
669         if (nCount > nLength)
670             nCount = nLength;
671 
672         return CStringT(CThisSimpleString::GetString(), nCount);
673     }
674 
675     CStringT Right(int nCount) const
676     {
677         int nLength = CThisSimpleString::GetLength();
678 
679         if (nCount < 0)
680             nCount = 0;
681         if (nCount > nLength)
682             nCount = nLength;
683 
684         return CStringT(CThisSimpleString::GetString() + nLength - nCount, nCount);
685     }
686 
687 
688     void __cdecl Format(UINT nFormatID, ...)
689     {
690         va_list args;
691         va_start(args, nFormatID);
692         CStringT formatString;
693         if (formatString.LoadString(nFormatID))
694             FormatV(formatString, args);
695         va_end(args);
696     }
697 
698     void __cdecl Format(PCXSTR pszFormat, ...)
699     {
700         va_list args;
701         va_start(args, pszFormat);
702         FormatV(pszFormat, args);
703         va_end(args);
704     }
705 
706     void FormatV(PCXSTR pszFormat, va_list args)
707     {
708         int nLength = StringTraits::FormatV(NULL, pszFormat, args);
709 
710         PXSTR pszBuffer = CThisSimpleString::GetBuffer(nLength);
711         StringTraits::FormatV(pszBuffer, pszFormat, args);
712         CThisSimpleString::ReleaseBufferSetLength(nLength);
713     }
714 
715     void __cdecl FormatMessage(UINT nFormatID, ...)
716     {
717         va_list va;
718         va_start(va, nFormatID);
719 
720         CStringT str;
721         if (str.LoadString(nFormatID))
722             FormatMessageV(str, &va);
723 
724         va_end(va);
725     }
726 
727     void __cdecl FormatMessage(PCXSTR pszFormat, ...)
728     {
729         va_list va;
730         va_start(va, pszFormat);
731         FormatMessageV(pszFormat, &va);
732         va_end(va);
733     }
734 
735     void
736     FormatMessageV(PCXSTR pszFormat, va_list *pArgList)
737     {
738         PXSTR psz = StringTraits::FormatMessageV(pszFormat, pArgList);
739         if (!psz)
740             CThisSimpleString::ThrowMemoryException();
741 
742         *this = psz;
743         ::LocalFree(psz);
744     }
745 
746     int Replace(PCXSTR pszOld, PCXSTR pszNew)
747     {
748         PCXSTR pszString = CThisSimpleString::GetString();
749 
750         const int nLength = CThisSimpleString::GetLength();
751         const int nOldLen = StringTraits::GetBaseTypeLength(pszOld);
752         const int nNewLen = StringTraits::GetBaseTypeLength(pszNew);
753         const int nDiff = nNewLen - nOldLen;
754         int nResultLength = nLength;
755 
756         PCXSTR pszFound;
757         while ((pszFound = StringTraits::FindString(pszString, pszOld)))
758         {
759             nResultLength += nDiff;
760             pszString = pszFound + nOldLen;
761         }
762 
763         if (pszString == CThisSimpleString::GetString())
764             return 0;
765 
766         PXSTR pszResult = CThisSimpleString::GetBuffer(nResultLength);
767         PXSTR pszNext;
768         int nCount = 0, nRemaining = nLength;
769         while (nRemaining && (pszNext = StringTraits::FindString(pszResult, pszOld)))
770         {
771             nRemaining -= (pszNext - pszResult);
772             nRemaining -= nOldLen;
773             if (nRemaining > 0)
774                 CThisSimpleString::CopyCharsOverlapped(pszNext + nNewLen, nRemaining + 1, pszNext + nOldLen, nRemaining + 1);
775             CThisSimpleString::CopyCharsOverlapped(pszNext, nNewLen, pszNew, nNewLen);
776             pszResult = pszNext + nNewLen;
777             nCount++;
778         }
779 
780         CThisSimpleString::ReleaseBufferSetLength(nResultLength);
781 
782         return nCount;
783     }
784 
785     int Replace(XCHAR chOld, XCHAR chNew)
786     {
787         PCXSTR pszString = CThisSimpleString::GetString();
788         PXSTR pszFirst = StringTraits::FindChar(pszString, chOld);
789         if (!pszFirst)
790             return 0;
791 
792         int nLength = CThisSimpleString::GetLength();
793         int nCount = 0;
794 
795         PXSTR pszBuffer = CThisSimpleString::GetBuffer(nLength);
796         pszFirst = pszBuffer + (pszFirst - pszString);
797         do {
798             *pszFirst = chNew;
799             ++nCount;
800         } while ((pszFirst = StringTraits::FindChar(pszFirst + 1, chOld)));
801 
802         CThisSimpleString::ReleaseBufferSetLength(nLength);
803         return nCount;
804     }
805 
806 
807     static PCXSTR DefaultTrimChars()
808     {
809         static XCHAR str[] = { ' ', '\t', '\r', '\n', 0 };
810         return str;
811     }
812 
813 
814     CStringT& TrimLeft()
815     {
816         return TrimLeft(DefaultTrimChars());
817     }
818 
819     CStringT& TrimLeft(XCHAR chTarget)
820     {
821         XCHAR str[2] = { chTarget, 0 };
822         return TrimLeft(str);
823     }
824 
825     CStringT& TrimLeft(PCXSTR pszTargets)
826     {
827         int nLength = CThisSimpleString::GetLength();
828         PXSTR pszBuffer = CThisSimpleString::GetBuffer(nLength);
829         int nCount = 0;
830 
831         while (nCount < nLength && StringTraits::FindChar(pszTargets, pszBuffer[nCount]))
832             nCount++;
833 
834         if (nCount > 0)
835         {
836             CThisSimpleString::CopyCharsOverlapped(pszBuffer, nLength - nCount, pszBuffer + nCount, nLength - nCount);
837             nLength -= nCount;
838         }
839         CThisSimpleString::ReleaseBufferSetLength(nLength);
840 
841         return *this;
842     }
843 
844 
845     CStringT& TrimRight()
846     {
847         return TrimRight(DefaultTrimChars());
848     }
849 
850     CStringT& TrimRight(XCHAR chTarget)
851     {
852         XCHAR str[2] = { chTarget, 0 };
853         return TrimRight(str);
854     }
855 
856     CStringT& TrimRight(PCXSTR pszTargets)
857     {
858         int nLength = CThisSimpleString::GetLength();
859         PXSTR pszBuffer = CThisSimpleString::GetBuffer(nLength);
860 
861         while (nLength > 0 && StringTraits::FindChar(pszTargets, pszBuffer[nLength-1]))
862             nLength--;
863 
864         CThisSimpleString::ReleaseBufferSetLength(nLength);
865 
866         return *this;
867     }
868 
869 
870     CStringT& Trim()
871     {
872         return Trim(DefaultTrimChars());
873     }
874 
875     CStringT& Trim(XCHAR chTarget)
876     {
877         XCHAR str[2] = { chTarget, 0 };
878         return Trim(str);
879     }
880 
881     CStringT& Trim(PCXSTR pszTargets)
882     {
883         return TrimRight(pszTargets).TrimLeft(pszTargets);
884     }
885 
886 
887     BSTR AllocSysString() const
888     {
889         return StringTraits::AllocSysString(CThisSimpleString::GetString(), CThisSimpleString::GetLength());
890     }
891 
892 
893 };
894 
895 } //namespace ATL
896 
897 #endif
898