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