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