[SHELL32] SHChangeNotify: Use tree for CDirectoryList (#6784)
[reactos.git] / sdk / lib / atl / cstringt.h
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