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