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