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