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