Polygon Crucher SDK - Documentation
Documentation
Loading...
Searching...
No Matches
XString.h
Go to the documentation of this file.
1//! @file XString.h
2//! @brief CXStringT is a template class for handling unicode, utf8 or ansi strings
3//!
4//! Created by Mootools initially based on David Nash code
5///////////////////////////////////////////////////////////////////////////////////
6#ifndef CXTSTRING_CLASS_H
7#define CXTSTRING_CLASS_H
8
9#ifdef _MSC_VER
10#pragma once
11#endif // _MSC_VER
12
13#ifdef __WINDOWS__
14#pragma warning(push)
15#pragma warning(disable: 4996)
16#endif
17
18// CXTString code based on:
19//
20// Win32++ Version 7.3
21// Released: 30th November 2011
22//
23// David Nash
24// email: dnash@bigpond.net.au
25// url: https://sourceforge.net/projects/win32-framework
26//
27//
28// Copyright (c) 2005-2011 David Nash
29//
30// Permission is hereby granted, free of charge, to
31// any person obtaining a copy of this software and
32// associated documentation files (the "Software"),
33// to deal in the Software without restriction, including
34// without limitation the rights to use, copy, modify,
35// merge, publish, distribute, sublicense, and/or sell
36// copies of the Software, and to permit persons to whom
37// the Software is furnished to do so, subject to the
38// following conditions:
39//
40// The above copyright notice and this permission notice
41// shall be included in all copies or substantial portions
42// of the Software.
43//
44// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
45// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
46// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
47// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
48// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
49// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
50// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
51// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
52// OR OTHER DEALINGS IN THE SOFTWARE.
53//
54////////////////////////////////////////////////////////
55//
56// Acknowledgements:
57// Thanks to Adam Szulc for his initial CXTString code.
58//
59////////////////////////////////////////////////////////
60// xstring.h
61// Declaration of the xstring.h
62//
63// This class is intended to provide a simple alternative to the MFC/ATL
64// CXTString class that ships with Microsoft compilers. The CXTString class
65// specified here is compatible with other compilers such as Borland 5.5
66// and MinGW.
67//
68// Differences between this class and the MFC/ATL CXTString class
69// ------------------------------------------------------------
70// 1) The constructors for this class accepts both ANSI and Unicode characters and
71// automatically converts these to TCHAR as required.
72//
73// 2) This class is not reference counted, so these CStrings should be passed as
74// references or const references when used as function arguments. As a result there
75// is no need for functions like LockBuffer and UnLockBuffer.
76//
77// 3) The Format functions only accepts POD (Plain Old Data) arguments. It does not
78// accept arguments which are class or struct objects. In particular it does not
79// accept CXTString objects, unless these are cast to LPCTSTR.
80// This is demonstrates valid and invalid usage:
81// CXTString string1(_T("Hello World"));
82// CXTString string2;
83//
84// // This is invalid, and produces undefined behaviour.
85// string2.Format(_T("String1 is: %s"), string1); // No! you can't do this
86//
87// // This is ok
88// string2.Format(_T("String1 is: %s"), (LPCTSTR)string1); // Yes, this is correct
89//
90// Note: The MFC/ATL CXTString class uses a non portable hack to make its CXTString class
91// behave like a POD. Other compilers (such as the MinGW compiler) specifically
92// prohibit the use of non POD types for functions with variable argument lists.
93//
94// 4) This class provides a few additional functions:
95// data Returns a const TCHAR string. This is an alternative for casting to LPCTSTR.
96// GetErrorString Assigns CXTString to the error string for the specified System Error Code
97// (from ::GetLastErrror() for example).
98// GetString Returns a reference to the underlying std::basic_string<TCHAR>. This
99// reference can be used to modify the string directly.
100
101// MacOS: cf. note at the end of the file
102#if defined(__WINDOWS__) && defined(MOOTOOLS_DLL_IMPORTS_ALL)
103// When using the class through a dll under windows, template instantiation are exported
104// we use only exported version and removing inline prevents to use inline expansion as it could generate dependency missing functions
105// CXTString<char> and CXTString<wchart_t> are exported at the end of the file
106#define MOOTOOLS_XSTRINGS_NO_INLINE
107#endif
108
109BEGIN_MOOTOOLS_NAMESPACE
110
111 template<class XCHAR> class CXTString;
112 template<class XCHAR> class CXTCharArray;
113
114 typedef CXTCharArray<TCHAR> CXCharArray;
115 typedef CXTCharArray<char> CXCharArrayA;
116 typedef CXTCharArray<wchar_t> CXCharArrayW;
117
118 typedef CXTString<TCHAR> CXString; //!< CXString depend on the target OS. Could be CXStringW (Windows) or CXStringA (Linux / Macos)
119 typedef CXTString<char> CXStringA; //!< CXStringA is an ansi / utf8 char string. Cf. CXTString
120 typedef CXTString<wchar_t> CXStringW; //!< CXStringA is an unicode wchar_t string. Cf. CXTString
121
122#if defined(_DEBUG) && !defined(MOOTOOLS_NO_TRACE)
123 extern DLL_TOOLSFUNCTION void XTRACE(LPCTSTR lpszFormat, ...);
124#else
125 #define XTRACE(...) __noop
126#endif
127
128 #define ISXCHARUNICODE(TYPE) ((sizeof(TYPE) == sizeof(wchar_t)))
129
130 template<class XCHAR> class CXTCharArray
131 {
132 friend class CXTString<XCHAR>;
133
134 protected:
135 XCHAR *buffer; // Set it first, so &CXString() points directly to the buffer
136 varint bufCharCount, maxBufCount; // bufCharCount is the number of characters (excluding null), maxBufCount is the max number of char of the buffer
137 public:
138 typedef enum { firstCharCount = 16, secondCharCount = 64 } XCharDefaults;
139
140 ///////////////////////////////////////////////////////////////
141 // CXTCharArray
142 CXTCharArray();
143 CXTCharArray(const XCHAR *string, size_t charCount);
144 CXTCharArray(XCHAR value, size_t charCount);
145 ~CXTCharArray();
146
147 void setlength(SIZET newSize);
148 varint length() const; // Not signed to enable substraction
149 void init();
150 bool belongto(varint index, const XCHAR *string, size_t charCount = -1) const;
151 void remove(varint pos, size_t charCount = -1);
152 void assign(const CXTCharArray<XCHAR>& chars, varint first = 0, size_t charCount = -1);
153 void assign(const XCHAR *string, size_t charCount = -1);
154 size_t insert(varint index, const XCHAR *string, size_t charCount = -1); // Return the number of inserted char
155 void append(const XCHAR *string, size_t charCount = -1);
156 const XCHAR *data() const;
157 XCHAR *data();
158 XCHAR *detach(); // Detach buffer. Caller must free buffer with xfree
159 void empty();
160
161 // these methods using same name for char and wchar_t allows resolving linking based on the XCHAR type
162 static void xchar_memset(XCHAR *str, XCHAR value, SIZET count);
163 static SIZET xchar_strlen(const XCHAR *str);
164 static int xchar_strcmp(const XCHAR *char1, const XCHAR *char2);
165 static int xchar_strcoll(const XCHAR *char1, const XCHAR *char2);
166 static int xchar_stricoll(const XCHAR *char1, const XCHAR *char2);
167 static int xchar_stricmp(const XCHAR *char1, const XCHAR *char2);
168 static int xchar_isspace(const XCHAR char1);
169 static int xchar_toupper(XCHAR char1);
170 static int xchar_tolower(XCHAR char1);
171 static int xchar_vnprintf(XCHAR *buffer, SIZET count, const XCHAR *format, va_list argptr);
172 static int xchar_vscanf_s(const XCHAR *buffer, const XCHAR *format, va_list argptr);
173 };
174
175#ifndef MOOTOOLS_XSTRINGS_NO_INLINE
176 // Specialization char
177 template <> inline void CXTCharArray<char>::xchar_memset(char *str, char value, SIZET count)
178 {
179 return xmemset(str, value, count);
180 }
181
182 template <> inline SIZET CXTCharArray<char>::xchar_strlen(const char *str)
183 {
184 return xstrlen(str);
185 }
186
187 template <> inline int CXTCharArray<char>::xchar_strcmp(const char *char1, const char *char2)
188 {
189 return xstrcmp(char1, char2);
190 }
191
192 template <> inline int CXTCharArray<char>::xchar_strcoll(const char *char1, const char *char2)
193 {
194 return xstrcoll(char1, char2);
195 }
196
197 template <> inline int CXTCharArray<char>::xchar_stricoll(const char *char1, const char *char2)
198 {
199 return xstricoll(char1, char2);
200 }
201
202 template <> inline int CXTCharArray<char>::xchar_stricmp(const char *char1, const char *char2)
203 {
204 return xstricmp(char1, char2);
205 }
206
207 template <> inline int CXTCharArray<char>::xchar_isspace(char char1)
208 {
209 return xisspace(char1);
210 }
211
212 template <> inline int CXTCharArray<char>::xchar_toupper(char char1)
213 {
214 return xtoupper(char1);
215 }
216
217 template <> inline int CXTCharArray<char>::xchar_tolower(char char1)
218 {
219 return xtolower(char1);
220 }
221
222 template <> inline int CXTCharArray<char>::xchar_vnprintf(char *buffer, SIZET count, const char *format, va_list argptr)
223 {
224 return xvnprintf(buffer, count, format, argptr);
225 }
226
227 template <> inline int CXTCharArray<char>::xchar_vscanf_s(const char *buffer, const char *format, va_list argptr)
228 {
229 return xvscanf_s(buffer, format, argptr);
230 }
231
232 // Specialization wchar_t
233 template <> inline void CXTCharArray<wchar_t>::xchar_memset(wchar_t *str, wchar_t value, SIZET count)
234 {
235 return xwmemset(str, value, count);
236 }
237
238 template <> inline SIZET CXTCharArray<wchar_t>::xchar_strlen(const wchar_t *str)
239 {
240 return xwstrlen(str);
241 }
242
243 template <> inline int CXTCharArray<wchar_t>::xchar_strcmp(const wchar_t *char1, const wchar_t *char2)
244 {
245 return xwstrcmp(char1, char2);
246 }
247
248 template <> inline int CXTCharArray<wchar_t>::xchar_strcoll(const wchar_t *char1, const wchar_t *char2)
249 {
250 return xwstrcoll(char1, char2);
251 }
252
253 template <> inline int CXTCharArray<wchar_t>::xchar_stricoll(const wchar_t *char1, const wchar_t *char2)
254 {
255 return xwstricoll(char1, char2);
256 }
257
258 template <> inline int CXTCharArray<wchar_t>::xchar_stricmp(const wchar_t *char1, const wchar_t *char2)
259 {
260 return xwstricmp(char1, char2);
261 }
262
263 template <> inline int CXTCharArray<wchar_t>::xchar_isspace(wchar_t char1)
264 {
265 return xwisspace(char1);
266 }
267
268 template <> inline int CXTCharArray<wchar_t>::xchar_toupper(wchar_t char1)
269 {
270 return xwtoupper(char1);
271 }
272
273 template <> inline int CXTCharArray<wchar_t>::xchar_tolower(wchar_t char1)
274 {
275 return xwtolower(char1);
276 }
277
278 template <> inline int CXTCharArray<wchar_t>::xchar_vnprintf(wchar_t *buffer, SIZET count, const wchar_t *format, va_list argptr)
279 {
280 return xwvnprintf(buffer, count, format, argptr);
281 }
282
283 template <> inline int CXTCharArray<wchar_t>::xchar_vscanf_s(const wchar_t *buffer, const wchar_t *format, va_list argptr)
284 {
285 return xwvscanf_s(buffer, format, argptr);
286 }
287
288 // Implementation
289 template <class XCHAR> inline CXTCharArray<XCHAR>::CXTCharArray()
290 {
291 buffer = NULL;
292 init();
293 }
294
295 template <class XCHAR> inline CXTCharArray<XCHAR>::CXTCharArray(const XCHAR *string, size_t charCount)
296 {
297 buffer = NULL;
298 bufCharCount = 0;
299 maxBufCount = 0;
300 assign(string, charCount);
301 }
302
303 template <class XCHAR> inline CXTCharArray<XCHAR>::CXTCharArray(XCHAR value, size_t charCount)
304 {
305 buffer = NULL;
306 bufCharCount = 0;
307 maxBufCount = 0;
308
309 setlength(charCount);
310 if (charCount > 0)
311 xchar_memset(buffer, value, charCount);
312 }
313
314 template <class XCHAR> inline CXTCharArray<XCHAR>::~CXTCharArray()
315 {
316 xfree(buffer);
317 }
318
319 template <class XCHAR> inline void CXTCharArray<XCHAR>::setlength(SIZET newCharCount)
320 {
321 size_t newSize = (newCharCount+1)*sizeof(XCHAR); // don't forget null
322 if (newSize <= maxBufCount*sizeof(XCHAR))
323 {
324 bufCharCount = (varint)newCharCount;
325 buffer[bufCharCount] = '\0';
326 return;
327 }
328
329 maxBufCount = (varint)((newCharCount * 2)+1);
330 if (maxBufCount < firstCharCount)
331 maxBufCount = firstCharCount;
332 else if (maxBufCount < secondCharCount)
333 maxBufCount = secondCharCount;
334
335 buffer = (XCHAR *)xrealloc(buffer, maxBufCount*sizeof(XCHAR));
336 bufCharCount = (varint)newCharCount;
337 buffer[bufCharCount] = '\0';
338 }
339
340 template<class XCHAR> inline void CXTCharArray<XCHAR>::init()
341 {
342 if (buffer)
343 xfree(buffer);
344
345 buffer = NULL;
346 bufCharCount = 0;
347 maxBufCount = 0;
348
349 setlength(0);
350 }
351
352 template <class XCHAR> inline varint CXTCharArray<XCHAR>::length() const
353 {
354 return bufCharCount;
355 }
356
357 template<class XCHAR> inline bool CXTCharArray<XCHAR>::belongto(varint index, const XCHAR *string, size_t charSetCount) const
358 {
359 if (index < 0 || index >= bufCharCount)
360 return false;
361
362 if (string == NULL)
363 return false;
364
365 XASSERT(charSetCount <= xchar_strlen(string));
366 if (charSetCount == -1)
367 charSetCount = xchar_strlen(string);
368
369 if (charSetCount == 0)
370 return false;
371
372 size_t pos = 0;
373 const XCHAR *chars = &buffer[index];
374 while (pos < charSetCount)
375 {
376 if (*chars == *string)
377 return true;
378
379 string++;
380 pos++;
381 }
382
383 return false;
384 }
385
386 template <class XCHAR> inline void CXTCharArray<XCHAR>::remove(varint first, size_t charCount)
387 {
388 if (first < 0 || first >= length() || charCount == 0)
389 return;
390
391 if (charCount == (size_t)(-1) || first + (varint)charCount >= length())
392 bufCharCount = first;
393 else
394 {
395 size_t copyCount = size_t(length()-(first + charCount));
396 xmemmove_s(buffer + first, (bufCharCount-first)*sizeof(XCHAR), buffer + first + charCount, copyCount*sizeof(XCHAR));
397 bufCharCount -= (varint)charCount;
398 }
399
400 setlength(bufCharCount);
401 }
402
403 template <class XCHAR> inline void CXTCharArray<XCHAR>::assign(const CXTCharArray<XCHAR>& chars, varint first, size_t charCount)
404 {
405 if (first > chars.length() || charCount == 0)
406 {
407 setlength(0);
408 return;
409 }
410
411 if (charCount == (size_t)(-1) || first + (varint)charCount > chars.length())
412 charCount = size_t(chars.length() - first);
413
414 setlength(charCount);
415 xmemcpy_s(buffer, bufCharCount*sizeof(XCHAR), chars.buffer+first, charCount*sizeof(XCHAR));
416 }
417
418 template <class XCHAR> inline void CXTCharArray<XCHAR>::assign(const XCHAR *string, size_t charCount)
419 {
420 if (string == NULL)
421 charCount = 0;
422 else if (charCount == (size_t)(-1))
423 charCount = xchar_strlen(string);
424
425 setlength(charCount);
426
427 if (charCount > 0)
428 xmemcpy_s(buffer, bufCharCount*sizeof(XCHAR), string, charCount*sizeof(XCHAR));
429 }
430
431 template <class XCHAR> inline size_t CXTCharArray<XCHAR>::insert(varint index, const XCHAR *string, size_t charCount)
432 {
433 if (charCount == 0 || string == NULL)
434 return 0;
435
436 if (index < 0 || index > bufCharCount)
437 return 0;
438
439 XASSERT(charCount == -1 || charCount <= xchar_strlen(string));
440 if (charCount == -1)
441 charCount = xchar_strlen(string);
442
443 varint prevSize = bufCharCount;
444 setlength(bufCharCount + charCount);
445
446 if (prevSize-index > 0)
447 xmemmove_s(buffer + index + charCount, (bufCharCount-(index+charCount))*sizeof(XCHAR), buffer+index, (prevSize - index)*sizeof(XCHAR));
448
449 xmemcpy_s(buffer + index, (bufCharCount-index)*sizeof(XCHAR), string, charCount*sizeof(XCHAR));
450
451 return charCount;
452 }
453
454 template <class XCHAR> inline void CXTCharArray<XCHAR>::append(const XCHAR *string, size_t charCount)
455 {
456 size_t prevSize = bufCharCount;
457
458 XASSERT(charCount == (size_t)(-1) || charCount <= xchar_strlen(string));
459 if (string == NULL)
460 charCount = 0;
461 else if (charCount == (size_t)-1)
462 charCount = xchar_strlen(string);
463
464 setlength(prevSize + charCount);
465
466 if (charCount > 0)
467 xmemcpy_s(buffer + prevSize, (bufCharCount-prevSize)*sizeof(XCHAR), string, charCount*sizeof(XCHAR));
468 }
469
470 template <class XCHAR> inline const XCHAR *CXTCharArray<XCHAR>::data() const
471 {
472 return buffer;
473 }
474
475 template <class XCHAR> inline XCHAR *CXTCharArray<XCHAR>::data()
476 {
477 return buffer;
478 }
479
480 template <class XCHAR> inline XCHAR *CXTCharArray<XCHAR>::detach()
481 {
482 XCHAR *buf = buffer;
483 buffer = NULL;
484 return buf;
485 }
486
487 template <class XCHAR> inline void CXTCharArray<XCHAR>::empty()
488 {
489 setlength(0);
490 }
491#endif // inline
492
493END_MOOTOOLS_NAMESPACE
494
495#include "xstringoperation.h"
496
497#ifdef __LINUX__
498#define XSTRING_FRIEND template<XCHAR> // Avoid warning: friend declaration declares a non-template function [-Wnon-template-friend]
499#else
500#define XSTRING_FRIEND // defining template<XCHAR> makes VS having trouble to deduces template args
501#endif
502
503BEGIN_MOOTOOLS_NAMESPACE
504//! @class CXTString
505//! @brief CXStringT is the template class for handling strings.
506//! @details CXStringT is declined and CXStringW (unicode strings) and CXStringA (ansi or utf8 strings).
507//!
508//! CXString is the default string class. It depends on the OS:
509//! * CXString = CXStringW under Windows.
510//! * CXString = CXStringA under Linux or Macos. In that case, the string are encoded in UTF8.
511//!
512//! There are also convenient defines such:
513//! * LPCWSTR / LPWSTR for a pointer to const wchar_t or wchar_t
514//! * LPCSTR / LPSTR for a pointer to const char / char
515//!
516//! A generic defines is declared and depends on the OS:
517//! * LPCTSTR / LPTSTR which is a const pointer / pointer on wchar_t * under Windows
518//! * LPCTSTR / LPTSTR which is a const pointer / pointer on char * under Linux and Macos
519//!
520//! CXString contains all needed methods to add, substract, extract, convert, format, scan strings.\n
521//! XCW2A, XCA2W are convenients class to convert unicode to ansi / utf8 and vice versa.
522//!
523//! @template XCHAR is char or wchar_t
524//!
525 template<class XCHAR> class DLL_TOOLSFUNCTION CXTString
526 {
527 typedef XCHAR* LPXSTR;
528 typedef const XCHAR* LPCXSTR;
530
531 // friend functions of CXTString
532 XSTRING_FRIEND friend DLL_TOOLSFUNCTION CXTString<XCHAR> operator + (const CXTString<XCHAR>& string1, const CXTString<XCHAR>& string2);
533 XSTRING_FRIEND friend DLL_TOOLSFUNCTION CXTString<XCHAR> operator + (const CXTString<XCHAR>& string, LPCXSTR pszText);
534 XSTRING_FRIEND friend DLL_TOOLSFUNCTION CXTString<XCHAR> operator + (const CXTString<XCHAR>& string, XCHAR ch);
535 XSTRING_FRIEND friend DLL_TOOLSFUNCTION CXTString<XCHAR> operator + (LPCXSTR pszText, const CXTString<XCHAR>& string);
536 XSTRING_FRIEND friend DLL_TOOLSFUNCTION CXTString<XCHAR> operator + (char ch, const CXTString<XCHAR>& string);
537 XSTRING_FRIEND friend DLL_TOOLSFUNCTION bool operator < (const CXTString<XCHAR>& string1, const CXTString<XCHAR>& string2);
538 XSTRING_FRIEND friend DLL_TOOLSFUNCTION bool operator > (const CXTString<XCHAR>& string1, const CXTString<XCHAR>& string2);
539 XSTRING_FRIEND friend DLL_TOOLSFUNCTION bool operator <= (const CXTString<XCHAR>& string1, const CXTString<XCHAR>& string2);
540 XSTRING_FRIEND friend DLL_TOOLSFUNCTION bool operator >= (const CXTString<XCHAR>& string1, const CXTString<XCHAR>& string2);
541 XSTRING_FRIEND friend DLL_TOOLSFUNCTION bool operator < (const CXTString<XCHAR>& string1, LPCXSTR pszText);
542 XSTRING_FRIEND friend DLL_TOOLSFUNCTION bool operator > (const CXTString<XCHAR>& string1, LPCXSTR pszText);
543 XSTRING_FRIEND friend DLL_TOOLSFUNCTION bool operator <= (const CXTString<XCHAR>& string1, LPCXSTR pszText);
544 XSTRING_FRIEND friend DLL_TOOLSFUNCTION bool operator >= (const CXTString<XCHAR>& string1, LPCXSTR pszText);
545
546#ifndef MOOTOOLS_XSTRINGS_NO_INLINE
547 // friend functions of CXTString
548 friend DLL_TOOLSFUNCTION inline CXTString<XCHAR> operator + (const CXTString<XCHAR>& string1, const CXTString<XCHAR>& string2)
549 {
551 str.m_str.append(string2.m_str.data());
552 return str;
553 }
554
555 friend DLL_TOOLSFUNCTION inline CXTString<XCHAR> operator + (const CXTString<XCHAR>& string, typename CXTString<XCHAR>::LPCXSTR pszText)
556 {
557 CXTString str(string);
558 if (pszText)
559 str.m_str.append(pszText);
560 return str;
561 }
562
563 friend DLL_TOOLSFUNCTION inline CXTString<XCHAR> operator + (const CXTString<XCHAR>& string, XCHAR ch)
564 {
565 CXTString str(string);
566 str.m_str.append(&ch, 1);
567 return str;
568 }
569
570 friend DLL_TOOLSFUNCTION inline CXTString<XCHAR> operator + (typename CXTString<XCHAR>::LPCXSTR pszText, const CXTString<XCHAR>& string)
571 {
573 str.m_str.append(string);
574 return str;
575 }
576
577 friend DLL_TOOLSFUNCTION inline CXTString<XCHAR> operator + (char ch, const CXTString<XCHAR>& string)
578 {
580 str.m_str.append(string);
581 return str;
582 }
583
584 friend DLL_TOOLSFUNCTION inline bool operator < (const CXTString<XCHAR>& string1, const CXTString<XCHAR>& string2)
585 {
586 return string1.Compare(string2) < 0;
587 }
588
589 friend DLL_TOOLSFUNCTION inline bool operator > (const CXTString<XCHAR>& string1, const CXTString<XCHAR>& string2)
590 {
591 return string1.Compare(string2) > 0;
592 }
593
594 friend DLL_TOOLSFUNCTION inline bool operator <= (const CXTString<XCHAR>& string1, const CXTString<XCHAR>& string2)
595 {
596 return string1.Compare(string2) <= 0;
597 }
598
599 friend DLL_TOOLSFUNCTION inline bool operator >= (const CXTString<XCHAR>& string1, const CXTString<XCHAR>& string2)
600 {
601 return string1.Compare(string2) >= 0;
602 }
603
604 friend DLL_TOOLSFUNCTION inline bool operator < (const CXTString<XCHAR>& string1, typename CXTString<XCHAR>::LPCXSTR pszText)
605 {
606 return string1.Compare(pszText) < 0;
607 }
608
609 friend DLL_TOOLSFUNCTION inline bool operator > (const CXTString<XCHAR>& string1, typename CXTString<XCHAR>::LPCXSTR pszText)
610 {
611 return string1.Compare(pszText) > 0;
612 }
613
614 friend DLL_TOOLSFUNCTION inline bool operator <= (const CXTString<XCHAR>& string1, typename CXTString<XCHAR>::LPCXSTR pszText)
615 {
616 return string1.Compare(pszText) <= 0;
617 }
618
619 friend DLL_TOOLSFUNCTION inline bool operator >= (const CXTString<XCHAR>& string1, typename CXTString<XCHAR>::LPCXSTR pszText)
620 {
621 return string1.Compare(pszText) >= 0;
622 }
623#endif // inline
624
625 int FindInternal(LPCXSTR pszText, int nStart, bool endpos) const;
626 int FindInternalNoCase(LPCXSTR pszText, int nStart, bool endpos) const;
627
628 public:
629 CXTString();
630 ~CXTString();
634 CXTString(XCHAR ch, int nLength = 1);
635 CXTString(LPCXSTR pszText, int nLength);
636
639 CXTString<XCHAR>& operator = (const unsigned char *pszText);
642
643 void Copy(LPCXSTR szText, int nCount); // Faster than operator = if we know the number of bytes to copy
644
645 bool operator == (LPCXSTR pszText) const;
646 bool operator != (LPCXSTR pszText) const;
647 operator LPCXSTR() const;
648 operator CXTCharArray<XCHAR>&();
654
655 // Attributes
656 static xStringEncoding GetDefaultEncoding();
657 int GetLength() const; //!< returns the length of the buffer in characters (can be greater than strlen, if set by GetBufferSetLength)
658
659 // Operations
660 void AppendFormat(LPCXSTR pszFormat,...);
661 void AppendFormat(unsigned int nFormatID, ...);
662 int Compare(LPCXSTR pszText) const;
663 int CompareNoCase(LPCXSTR pszText) const;
664 int Delete(int nIndex, int nCount = 1);
665 int Find(XCHAR ch, int nIndex = 0) const;
666 int FindNoCase(XCHAR ch, int nIndex = 0) const;
667 int Find(LPCXSTR pszText, int nStart = 0, bool caseInsensitive = false) const;
668 int FindEndPos(LPCXSTR pszText, int nStart = 0, bool caseInsensitive = false) const;
669 int FindOneOf(LPCXSTR pszText) const;
670 int ScanS(LPCXSTR pszFormat, ...) const;
671 int ScanVS(LPCXSTR pszFormat, va_list args) const;
672 int ScanVS(int offsetCount, LPCXSTR pszFormat, va_list args) const;
673 void Format(unsigned int nID, ...);
674 void Format(LPCXSTR pszFormat,...);
675 void FormatV(LPCXSTR pszFormat, va_list args);
676 XCHAR GetAt(int nIndex) const;
677 LPCXSTR GetAtPtr(int nIndex) const;
678 LPCXSTR GetConstBuffer(int nMinBufLength = -1);
679 LPXSTR GetBuffer(int nMinBufLength = -1);
680 LPXSTR GetBufferSetLength(int nBufferLength);
681 void ReleaseBuffer(int nNewLength = -1);
682 LPXSTR DetachBuffer(); //!< Detach buffer. Caller must free buffer with xfree
683 void Empty();
684 int Insert(int nIndex, XCHAR ch);
685 int Insert(int nIndex, const CXTString<XCHAR>& str);
686 bool IsEmpty() const;
687 CXTString Left(int nCount) const;
688 bool LoadString(unsigned int nID);
689 void MakeLower(int count = -1);
690 void MakeReverse();
691 void MakeUpper(int count = -1);
692 CXTString Mid(int nFirst, int nCount = -1) const;
693 int Remove(XCHAR ch);
694 int Remove(LPCXSTR pszText, bool caseInsensitive = false);
695 int Replace(XCHAR chOld, XCHAR chNew);
696 int Replace(LPCXSTR pszOld, LPCXSTR pszNew);
697 int ReverseFind(XCHAR pszText, int nStart = -1) const;
698 int ReverseFind(LPCXSTR pszText, int nStart = -1) const;
699 CXTString Right(int nCount) const;
700 void SetAt(int nIndex, XCHAR ch);
701 CXTString SpanExcluding(LPCXSTR pszText) const;
702 CXTString SpanIncluding(LPCXSTR pszText) const;
703 CXTString Tokenize(LPCXSTR pszTokens, int& iStart) const;
704 void Trim(); //!< Remove left and right space char
705 void TrimLeft();
706 void TrimLeft(XCHAR chTarget); //!< Remove left specified character
707 void TrimLeft(LPCXSTR pszTargets); //!< Remove any character from pszTargets string on the left side of the string
708 void TrimRight();
709 void TrimRight(XCHAR chTarget);
710 void TrimRight(LPCXSTR pszTargets);
711 int Collate(LPCXSTR pszText) const;
712 int CollateNoCase(LPCXSTR pszText) const;
713
714#ifdef MOOTOOLS_MFC_PRODUCT_BUILD
715 CXTString(const CStringA& txt);
717 CXTString(const CStringW& txt);
719#endif
720
721 private:
722 XARRAYSTR m_str; // Set it first, so &CXString() points directly to the buffer
723 };
724
725#ifndef MOOTOOLS_XSTRINGS_NO_INLINE
726 ///////////////////////////////////////////////////////////
727 // CXTString implementation
728
729 template <class XCHAR> inline CXTString<XCHAR>::CXTString()
730 {
731 }
732
733 template <class XCHAR> inline CXTString<XCHAR>::~CXTString()
734 {
735 }
736
737 template <class XCHAR> inline CXTString<XCHAR>::CXTString(const CXTString<XCHAR>& str) : m_str(str, str.GetLength())
738 {
739 }
740
741 template <class XCHAR> inline CXTString<XCHAR>::CXTString(XCHAR ch, int nLength) : m_str(ch, nLength)
742 {
743 }
744
745 template <class XCHAR> inline CXTString<XCHAR>::CXTString(LPCXSTR pszText, int nLength) : m_str(pszText, nLength)
746 {
747 }
748
749 template <class XCHAR> inline int CXTString<XCHAR>::GetLength() const
750 {
751 return static_cast<int>(m_str.length());
752 }
753
754 template <class XCHAR> inline CXTString<XCHAR>& CXTString<XCHAR>::operator = (const CXTString<XCHAR>& str)
755 {
756 // use str.GetLength(), otherwise assign use something similar to strlen, which is not correct, as GetBufferSetLength() / ReleaseBuffer(count) leads
757 // to have a buffer size which value elements (potentially containing multiple null characters). Copy must keep that size value, which is not the case using assign(str)
758 m_str.assign(str, str.GetLength());
759 return *this;
760 }
761
762 template <class XCHAR> inline CXTString<XCHAR>& CXTString<XCHAR>::operator = (const unsigned char *pszText)
763 {
764 *this = reinterpret_cast<LPCSTR>(pszText);
765 return *this;
766 }
767
768 template <class XCHAR> inline CXTString<XCHAR>& CXTString<XCHAR>::operator = (const XCHAR ch)
769 {
770 m_str.assign(&ch, 1);
771 return *this;
772 }
773
774 template <class XCHAR> inline bool CXTString<XCHAR>::operator == (LPCXSTR pszText) const
775 // Returns TRUE if the strings have the same content
776 {
777 return (Compare(pszText) == 0);
778 }
779
780 template <class XCHAR> inline bool CXTString<XCHAR>::operator != (LPCXSTR pszText) const
781 // Returns TRUE if the strings have a different content
782 {
783 return (Compare(pszText) != 0);
784 }
785
786 template <class XCHAR> inline CXTString<XCHAR>::operator LPCXSTR() const
787 {
788 return m_str.data();
789 }
790
791 template<class XCHAR>
793 {
794 return m_str;
795 }
796
797 template <class XCHAR> inline XCHAR CXTString<XCHAR>::operator [] (int nIndex)
798 {
799 XASSERT(nIndex >= 0);
800 XASSERT(nIndex < GetLength());
801 return m_str.data()[nIndex];
802 }
803
804 template <class XCHAR> inline CXTString<XCHAR>& CXTString<XCHAR>::operator += (XCHAR ch)
805 {
806 m_str.append(&ch, 1);
807 return *this;
808 }
809
810 template <class XCHAR> inline CXTString<XCHAR>& CXTString<XCHAR>::operator += (const CXTString<XCHAR>& str)
811 {
812 m_str.append(str);
813 return *this;
814 }
815
816 template <class XCHAR> inline void CXTString<XCHAR>::AppendFormat(LPCXSTR pszFormat,...)
817 // Appends formatted data to an the CXTString content.
818 {
819 if (!pszFormat)
820 return;
821
823
826 str.FormatV(pszFormat, args);
827 va_end(args);
828
829 m_str.append(str);
830 }
831
832 template <class XCHAR> inline void CXTString<XCHAR>::AppendFormat(unsigned int nFormatID, ...)
833 // Appends formatted data to an the CXTString content.
834 {
837
838 if (str1.LoadString(nFormatID))
839 {
842 str2.FormatV(str1.m_str.data(), args);
843 va_end(args);
844
845 m_str.append(str2);
846 }
847 }
848
849 template <class XCHAR> inline int CXTString<XCHAR>::Collate(LPCXSTR pszText) const
850 // Performs a case sensitive comparison of the two strings using locale-specific information.
851 {
852 if (pszText == NULL && GetLength() == 0)
853 return 0;
854
855 if (pszText == NULL) // GetLength() != 0
856 return 1;
857
858 return CXTCharArray<XCHAR>::xchar_strcoll(m_str.data(), pszText);
859 }
860
861 template <class XCHAR> inline int CXTString<XCHAR>::CollateNoCase(LPCXSTR pszText) const
862 // Performs a case insensitive comparison of the two strings using locale-specific information.
863 {
864 if (pszText == NULL && GetLength() == 0)
865 return 0;
866
867 if (pszText == NULL) // GetLength() != 0
868 return 1;
869
870 return CXTCharArray<XCHAR>::xchar_stricoll(m_str.data(), pszText);
871 }
872
873 template <class XCHAR> inline int CXTString<XCHAR>::Compare(LPCXSTR pszText) const
874 // Performs a case sensitive comparison of the two strings.
875 {
876 if (pszText == NULL && GetLength() == 0)
877 return 0;
878
879 if (pszText == NULL) // GetLength() != 0
880 return 1;
881
882 return CXTCharArray<XCHAR>::xchar_strcmp(m_str.data(), pszText);
883 }
884
885 template <class XCHAR> inline int CXTString<XCHAR>::CompareNoCase(LPCXSTR pszText) const
886 // Performs a case insensitive comparison of the two strings.
887 {
888 if (pszText == NULL && GetLength() == 0)
889 return 0;
890
891 if (pszText == NULL) // GetLength() != 0
892 return 1;
893
894 return CXTCharArray<XCHAR>::xchar_stricmp(m_str.data(), pszText);
895 }
896
897 template <class XCHAR> inline int CXTString<XCHAR>::Delete(int nIndex, int nCount /* = 1 */)
898 // Deletes a character or characters from the string.
899 {
900 XASSERT(nIndex >= 0 && nIndex < GetLength());
901 XASSERT(nCount >= 0);
902 if (nIndex < 0 || nIndex >= GetLength())
903 return GetLength();
904
905 if (nCount <= 0)
906 return GetLength();
907
908 m_str.remove(nIndex, nCount);
909 return (int)GetLength();
910 }
911
912 template <class XCHAR> inline void CXTString<XCHAR>::Empty()
913 // Erases the contents of the string.
914 {
915 m_str.empty();
916 }
917
918 template <class XCHAR> inline void CXTString<XCHAR>::SetAt(int nIndex, XCHAR ch)
919 // Sets the character at the specificed position to the specified value.
920 {
921 XASSERT(nIndex >= 0);
922 XASSERT(nIndex < m_str.length());
923 if (nIndex >= m_str.length())
924 return;
925
926 *(m_str.data() + nIndex) = ch;
927 }
928
929 template <class XCHAR> inline XCHAR CXTString<XCHAR>::GetAt(int nIndex) const
930 // Returns the character at the specified location within the string.
931 {
932 XASSERT(nIndex >= 0);
933 XASSERT(nIndex < GetLength());
934 if (nIndex >= GetLength())
935 return 0;
936
937 return m_str.data()[nIndex];
938 }
939
940 template <class XCHAR> inline const XCHAR* CXTString<XCHAR>::GetAtPtr(int nIndex) const
941 // Returns the character at the specified location within the string.
942 {
943 XASSERT(nIndex >= 0);
944 XASSERT(nIndex < GetLength());
945 if (nIndex >= GetLength())
946 return NULL;
947
948 return &m_str.data()[nIndex];
949 }
950
951 template <class XCHAR> inline void CXTString<XCHAR>::ReleaseBuffer(int refLength /*= -1*/)
952 // This copies the contents of the buffer (acquired by GetBuffer) to this CXTString,
953 // and releases the contents of the buffer. The default length of -1 copies from the
954 // buffer until a null terminator is reached. If the buffer doesn't contain a null
955 // terminator, you must specify the buffer's length.
956 {
957 XASSERT(refLength >= 0 || refLength == -1);
958 SIZET newLength = refLength;
959 if (newLength == -1)
960 newLength = CXTCharArray<XCHAR>::xchar_strlen(m_str.data()); // string must be null terminated
961
962 XASSERT((varint)newLength <= m_str.length());
963 if ((varint)newLength > m_str.length())
964 newLength = m_str.length() - 1;
965
966 m_str.setlength(newLength);
967 }
968
969 template <class XCHAR> inline XCHAR *CXTString<XCHAR>::GetBufferSetLength(int nLength)
970 // Creates a buffer of nLength charaters and return a pointer to this buffer.
971 // This buffer can be used by any function which accepts a LPCXSTR.
972 // Care must be taken not to exceed the length of the buffer. Use ReleaseBuffer to safely
973 // copy this buffer back to the CXTString object.
974 {
975 m_str.setlength(nLength); // The string must have the required length size, in case ReleaseBuffer not called (MFC compliant)
976 return m_str.data();
977 }
978
979 template <class XCHAR> inline const XCHAR *CXTString<XCHAR>::GetConstBuffer(int nMinBufLength)
980 // Get the string in a buffer which size is at least nMinBufLength.
981 // if nMinBufLength lower than the string size+1 (null char), then nMinBufLength is set to the string size+1
982 {
983 if (nMinBufLength < static_cast<int>(m_str.length())) // Include trailing null char
984 nMinBufLength = static_cast<int>(m_str.length());
985
986 return GetBufferSetLength(nMinBufLength);
987 }
988
989 template <class XCHAR> inline XCHAR *CXTString<XCHAR>::GetBuffer(int nMinBufLength)
990 // Get the string in a buffer which size is at least nMinBufLength.
991 // if nMinBufLength lower than the string size+1 (null char), then nMinBufLength is set to the string size+1
992 {
993 if (nMinBufLength < static_cast<int>(m_str.length())) // Include trailing null char
994 nMinBufLength = static_cast<int>(m_str.length());
995
996 return GetBufferSetLength(nMinBufLength);
997 }
998
999 template <class XCHAR> inline XCHAR *CXTString<XCHAR>::DetachBuffer()
1000 {
1001 return m_str.detach();
1002 }
1003
1004 template <class XCHAR> inline int CXTString<XCHAR>::Insert(int nIndex, XCHAR ch)
1005 // Inserts a single character or a substring at the given index within the string.
1006 {
1007 XASSERT(nIndex >= 0);
1008 XASSERT(ch);
1009
1010 m_str.insert(nIndex, &ch, 1);
1011 return (int)m_str.length();
1012 }
1013
1014 template <class XCHAR> inline int CXTString<XCHAR>::Insert(int nIndex, const CXTString<XCHAR>& str)
1015 // Inserts a single character or a substring at the given index within the string.
1016 {
1017 XASSERT(nIndex >= 0 && nIndex <= GetLength());
1018
1019 m_str.insert(nIndex, str);
1020 return (int)m_str.length();
1021 }
1022
1023 template <class XCHAR> inline bool CXTString<XCHAR>::IsEmpty() const
1024 // Returns TRUE if the string is empty
1025 {
1026 return (m_str.length() == 0);
1027 }
1028
1029 template <class XCHAR> inline void CXTString<XCHAR>::MakeLower(int count)
1030 // Converts all the characters in this string to lowercase characters.
1031 {
1032 varint length = m_str.length();
1033 if (count != -1 && count < length)
1034 length = count;
1035
1036 XCHAR *chars = m_str.data();
1037 varint pos = 0;
1038 while (pos < length)
1039 {
1040 *chars = (XCHAR)m_str.xchar_tolower(*chars);
1041 chars++;
1042 pos++;
1043 }
1044 }
1045
1046 template <class XCHAR> inline void CXTString<XCHAR>::MakeReverse()
1047 // Reverses the string.
1048 {
1049 XCHAR tmp;
1050 varint length = m_str.length();
1051 XCHAR *beginchars = m_str.data();
1052 XCHAR *endchars = beginchars + length;
1053 while (beginchars < endchars)
1054 {
1055 tmp = *endchars;
1056 *endchars = *beginchars;
1057 *beginchars = tmp;
1058
1059 beginchars++;
1060 endchars--;
1061 }
1062 }
1063
1064 template <class XCHAR> inline void CXTString<XCHAR>::MakeUpper(int count)
1065 // Converts all the characters in this string to uppercase characters.
1066 {
1067 varint length = m_str.length();
1068 if (count != -1 && count < length)
1069 length = count;
1070
1071 XCHAR *chars = m_str.data();
1072 varint pos = 0;
1073 while (pos < length)
1074 {
1075 *chars = (XCHAR)m_str.xchar_toupper(*chars);
1076 chars++;
1077 pos++;
1078 }
1079 }
1080
1081 template <class XCHAR> inline CXTString<XCHAR> CXTString<XCHAR>::Mid(int nFirst, int nCount) const
1082 // Extracts the middle part of a string.
1083 {
1084 XASSERT(nCount == -1 || nCount >= 0);
1085 if (nFirst < 0)
1086 nFirst = 0;
1087
1088 if (nCount >= 0 && (nFirst + nCount > m_str.length()))
1089 nCount = LInt2Int(m_str.length()- nFirst);
1090
1091 CXTString str;
1092 str.m_str.assign(m_str, nFirst, nCount);
1093 return str;
1094 }
1095
1096 template <class XCHAR> inline CXTString<XCHAR> CXTString<XCHAR>::Left(int nCount) const
1097 // Extracts the left part of a string.
1098 {
1099 if (nCount < 0)
1100 return CXTString();
1101
1102 if (nCount > m_str.length())
1103 nCount = LInt2Int(m_str.length());
1104
1105 return CXTString(m_str.data(), nCount);
1106 }
1107
1108 template <class XCHAR> inline CXTString<XCHAR> CXTString<XCHAR>::Right(int nCount) const
1109 // Extracts the right part of a string.
1110 {
1111 if (nCount < 0)
1112 return CXTString();
1113
1114 if (nCount > m_str.length())
1115 nCount = LInt2Int(m_str.length());
1116
1117 return CXTString(m_str.data() + m_str.length() - nCount, nCount);
1118 }
1119
1120 template <class XCHAR> inline int CXTString<XCHAR>::FindOneOf(LPCXSTR pszText) const
1121 // Finds the first matching character from a set.
1122 {
1123 if (!pszText)
1124 return (int)-1;
1125
1126 size_t searchLength = CXTCharArray<XCHAR>::xchar_strlen(pszText);
1127 if (searchLength == 0)
1128 return -1;
1129
1130 int nIndex = 0;
1131 size_t i = 0;
1132 while (i < searchLength)
1133 {
1134 if ((nIndex = Find(pszText[i])) != -1)
1135 return nIndex;
1136 i++;
1137 }
1138
1139 return -1;
1140 }
1141
1142 template <class XCHAR> inline int CXTString<XCHAR>::Find(XCHAR ch, int nIndex /* = 0 */) const
1143 // Finds a character in the string.
1144 {
1145 XASSERT(nIndex >= 0);
1146 if (nIndex >= GetLength())
1147 return -1;
1148
1149 varint length = m_str.length();
1150 const XCHAR *chars = m_str.data();
1151 varint pos = nIndex;
1152 while (pos < length)
1153 {
1154 if (chars[pos] == ch)
1155 return LInt2Int(pos);
1156
1157 pos++;
1158 }
1159
1160 return -1;
1161 }
1162
1163 template <class XCHAR> inline int CXTString<XCHAR>::FindNoCase(XCHAR ch, int nIndex /* = 0 */) const
1164 // Finds a character in the string.
1165 {
1166 XASSERT(nIndex >= 0);
1167 if (nIndex >= GetLength())
1168 return -1;
1169
1170 ch = xttolower(ch);
1171
1172 varint length = m_str.length();
1173 const XCHAR* chars = m_str.data();
1174 varint pos = nIndex;
1175 while (pos < length)
1176 {
1177 if (xttolower(chars[pos]) == ch)
1178 return LInt2Int(pos);
1179
1180 pos++;
1181 }
1182
1183 return -1;
1184 }
1185
1186 template <class XCHAR> inline int CXTString<XCHAR>::FindEndPos(LPCXSTR pszText, int nIndex /* = 0 */, bool caseInsensitive) const
1187 // Finds a substring within the string and return the first character position after that string
1188 {
1189 return caseInsensitive ? FindInternalNoCase(pszText, nIndex, false) : FindInternal(pszText, nIndex, true);
1190 }
1191
1192 template <class XCHAR> inline int CXTString<XCHAR>::Find(LPCXSTR pszText, int nIndex /* = 0 */, bool caseInsensitive) const
1193 // Finds a substring within the string.
1194 {
1195 return caseInsensitive ? FindInternalNoCase(pszText, nIndex, false) : FindInternal(pszText, nIndex, false);
1196 }
1197
1198 template <class XCHAR> inline int CXTString<XCHAR>::FindInternal(LPCXSTR pszText, int nIndex, bool endpos) const
1199 // Finds a substring within the string.
1200 // If string found, it always returns a position, which can be the last null character.
1201 {
1202 XASSERT(nIndex >= 0);
1203 if (!pszText)
1204 return -1;
1205
1206 if (nIndex >= GetLength())
1207 return -1;
1208
1209 size_t searchLength = CXTCharArray<XCHAR>::xchar_strlen(pszText);
1210 if (searchLength == 0)
1211 return -1;
1212
1213 const XCHAR *chars = m_str.data();
1214 while ((nIndex = Find(pszText[0], nIndex)) != -1)
1215 {
1216 size_t firstpos = nIndex, i = 0;
1217 while (++i < searchLength) // First char already found
1218 {
1219 nIndex++;
1220 if (nIndex >= GetLength())
1221 return -1;
1222
1223 if (chars[nIndex] != pszText[i])
1224 break;
1225 }
1226
1227 if (i == searchLength)
1228 {
1229 if (endpos)
1231
1232 return LInt2Int(firstpos); // This might return null termination character pos.
1233 }
1234 }
1235
1236 return -1;
1237 }
1238
1239 template <class XCHAR> inline int CXTString<XCHAR>::FindInternalNoCase(LPCXSTR pszText, int nIndex, bool endpos) const
1240 // Finds a substring within the string.
1241 // If string found, it always returns a position, which can be the last null character.
1242 {
1243 XASSERT(nIndex >= 0);
1244 if (!pszText)
1245 return -1;
1246
1247 if (nIndex >= GetLength())
1248 return -1;
1249
1250 size_t searchLength = CXTCharArray<XCHAR>::xchar_strlen(pszText);
1251 if (searchLength == 0)
1252 return -1;
1253
1254 const XCHAR* chars = m_str.data();
1255 while ((nIndex = FindNoCase(pszText[0], nIndex)) != -1)
1256 {
1257 size_t firstpos = nIndex, i = 0;
1258 while (++i < searchLength) // First char already found
1259 {
1260 nIndex++;
1261 if (nIndex >= GetLength())
1262 return -1;
1263
1264 if (xttolower(chars[nIndex]) != xttolower(pszText[i]))
1265 break;
1266 }
1267
1268 if (i == searchLength)
1269 {
1270 if (endpos)
1272
1273 return LInt2Int(firstpos); // This might return null termination character pos.
1274 }
1275 }
1276
1277 return -1;
1278 }
1279
1280 template <class XCHAR> inline int CXTString<XCHAR>::ReverseFind(XCHAR ch, int nIndex /* = -1 */) const
1281 // Search for a substring within the string, starting from the end.
1282 {
1283 XASSERT(nIndex == -1 || nIndex >= 0 );
1284 if (m_str.length() == 0)
1285 return -1;
1286
1287 if (nIndex == -1 || nIndex >= m_str.length())
1288 nIndex = LInt2Int(m_str.length() - 1);
1289
1290 XASSERT(nIndex >= 0);
1291 const XCHAR *chars = m_str.data();
1292 while (nIndex >= 0) // nIndex should be signed
1293 {
1294 if (chars[nIndex] == ch)
1295 return nIndex;
1296
1297 nIndex--;
1298 }
1299
1300 return -1;
1301 }
1302
1303 template <class XCHAR> inline int CXTString<XCHAR>::ReverseFind(LPCXSTR pszText, int nIndex /* = -1 */) const
1304 // Search for a substring within the string, starting from the end.
1305 {
1306 XASSERT(nIndex == -1 || nIndex >= 0);
1307 if (!pszText || m_str.length() == 0)
1308 return -1;
1309
1310 if (nIndex == -1 || nIndex >= m_str.length())
1311 nIndex = LInt2Int(m_str.length() - 1);
1312
1313 XASSERT(nIndex >= 0);
1314
1315 size_t searchLength = CXTCharArray<XCHAR>::xchar_strlen(pszText);
1316 if (searchLength == 0)
1317 return -1;
1318
1319 const XCHAR *chars = m_str.data();
1320 while ((nIndex = ReverseFind(pszText[searchLength-1], nIndex)) != -1)
1321 {
1322 varint i = searchLength-1;
1323 while (--i >= 0) // last char already found
1324 {
1325 nIndex--;
1326 if (nIndex < 0)
1327 return -1;
1328
1329 if (chars[nIndex] != pszText[i])
1330 break;
1331 }
1332
1333 if (i < 0)
1334 return nIndex;
1335 }
1336
1337 return -1;
1338 }
1339
1340 template <class XCHAR> inline int CXTString<XCHAR>::Remove(XCHAR ch)
1341 // Removes each occurrence of the specified substring from the string.
1342 {
1343 varint removed = 0, length = m_str.length();
1344 varint pos = 0;
1345 const XCHAR *chars = m_str.data();
1346 while (pos < length)
1347 {
1348 if (chars[pos] == ch)
1349 {
1350 m_str.remove(pos, 1);
1351 removed++;
1352 length--;
1353 }
1354 else
1355 pos++;
1356 }
1357
1358 return LInt2Int(removed);
1359 }
1360
1361 template <class XCHAR> inline int CXTString<XCHAR>::Remove(LPCXSTR pszText, bool noCase)
1362 // Removes each occurrence of the specified substring from the string.
1363 {
1364 if (pszText == NULL)
1365 return 0;
1366
1367 size_t length = CXTCharArray<XCHAR>::xchar_strlen(pszText);
1368 if (length == 0)
1369 return 0;
1370
1371 int nCount = 0;
1372 int pos = 0;
1373 while ((pos = Find(pszText, pos, noCase)) != -1)
1374 {
1375 m_str.remove(pos, length);
1376 ++nCount;
1377 }
1378
1379 return nCount;
1380 }
1381
1382 template <class XCHAR> inline int CXTString<XCHAR>::Replace(XCHAR chOld, XCHAR chNew)
1383 // Replaces each occurance of the old character with the new character.
1384 {
1385 varint length = m_str.length();
1386 XCHAR *chars = m_str.data();
1387
1388 int nCount = 0;
1389 varint pos = 0;
1390 while (pos < length)
1391 {
1392 if (*chars == chOld)
1393 {
1394 *chars = chNew;
1395 nCount++;
1396 }
1397 chars++;
1398 pos++;
1399 }
1400
1401 return nCount;
1402 }
1403
1404 template <class XCHAR> inline int CXTString<XCHAR>::Replace(LPCXSTR pszOld, LPCXSTR pszNew)
1405 // Replaces each occurance of the old substring with the new substring.
1406 {
1407 if (pszOld == NULL || pszNew == NULL)
1408 return 0;
1409
1410 size_t oldlength = CXTCharArray<XCHAR>::xchar_strlen(pszOld);
1411 size_t newlength = CXTCharArray<XCHAR>::xchar_strlen(pszNew);
1412
1413 int nCount = 0;
1414 varint pos = 0;
1415 while ((pos = Find(pszOld, (int)pos)) != -1)
1416 {
1417 m_str.remove(pos, oldlength);
1418 pos += (varint)m_str.insert(pos, pszNew, newlength);
1419 ++nCount;
1420 }
1421
1422 return nCount;
1423 }
1424
1425 template <class XCHAR> inline CXTString<XCHAR> CXTString<XCHAR>::SpanExcluding(LPCXSTR pszText) const
1426 // Extracts characters from the string, starting with the first character,
1427 // that are not in the set of characters identified by pszCharSet.
1428 {
1429 if (pszText == NULL)
1430 return CXTString<XCHAR>();
1431
1432 size_t spanLength = CXTCharArray<XCHAR>::xchar_strlen(pszText);
1433 if (spanLength == 0)
1434 return *this;
1435
1436 varint pos = 0;
1437 varint length = m_str.length();
1438
1439 CXTString str;
1440 const XCHAR *chars = m_str.data();
1441 while (pos < length)
1442 {
1443 if (!m_str.belongto(pos, pszText, spanLength))
1444 str.m_str.append(chars + pos, 1);
1445
1446 pos++;
1447 }
1448
1449 return str;
1450 }
1451
1452 template <class XCHAR> inline CXTString<XCHAR> CXTString<XCHAR>::SpanIncluding(LPCXSTR pszText) const
1453 // Extracts a substring that contains only the characters in a set.
1454 {
1455 if (pszText == NULL)
1456 return CXTString<XCHAR>();
1457
1458 size_t spanLength = CXTCharArray<XCHAR>::xchar_strlen(pszText);
1459 if (spanLength == 0)
1460 return CXTString<XCHAR>();
1461
1462 varint pos = 0;
1463 varint length = m_str.length();
1464
1465 CXTString str;
1466 const XCHAR *chars = m_str.data();
1467 while (pos < length)
1468 {
1469 if (m_str.belongto(pos, pszText, spanLength))
1470 str.m_str.append(chars + pos, 1);
1471
1472 pos++;
1473 }
1474
1475 return str;
1476 }
1477
1478 template <class XCHAR> inline CXTString<XCHAR> CXTString<XCHAR>::Tokenize(LPCXSTR pszTokens, int& index) const
1479 // Extracts specified tokens in a target string.
1480 {
1481 varint length = m_str.length();
1482
1483 if (index < 0 || index >= (varint)length)
1484 {
1485 index = -1;
1486 return CXTString();
1487 }
1488
1489 if (!pszTokens)
1490 {
1491 index = -1;
1492 return CXTString();
1493 }
1494
1495 size_t tokenLength = CXTCharArray<XCHAR>::xchar_strlen(pszTokens);
1496 if (tokenLength == 0)
1497 {
1498 index = -1;
1499 return CXTString();
1500 }
1501
1502 varint pos = index;
1503 varint otherpos = -1;
1504 while (pos < length)
1505 {
1506 if (!m_str.belongto(pos, pszTokens, tokenLength))
1507 {
1508 otherpos = pos++;
1509 break;
1510 }
1511
1512 pos++;
1513 }
1514
1515 varint tokenpos = -1;
1516 while (pos < length)
1517 {
1518 if (m_str.belongto(pos, pszTokens, tokenLength))
1519 {
1520 tokenpos = pos;
1521 break;
1522 }
1523
1524 pos++;
1525 }
1526
1527 if (tokenpos == -1)
1528 {
1529 index = -1; // no more token
1530 tokenpos = length;
1531 }
1532 else
1533 index = (int)tokenpos + 1;
1534
1535 if (otherpos != -1)
1536 return Mid(LInt2Int(otherpos), LInt2Int(tokenpos-otherpos));
1537
1538 return CXTString();
1539 }
1540
1541 template <class XCHAR> inline void CXTString<XCHAR>::Trim()
1542 // Trims all leading and trailing whitespace characters from the string.
1543 {
1544 TrimLeft();
1545 TrimRight();
1546 }
1547
1548 template <class XCHAR> inline void CXTString<XCHAR>::TrimLeft()
1549 // Trims leading whitespace characters from the string.
1550 {
1551 varint length = m_str.length();
1552 varint count = 0;
1553 const XCHAR *chars = m_str.data();
1554 while (count < length)
1555 {
1556 if (!CXTCharArray<XCHAR>::xchar_isspace(*chars))
1557 break;
1558
1559 chars++;
1560 count++;
1561 }
1562
1563 m_str.remove(0, count);
1564 }
1565
1566 template <class XCHAR> inline void CXTString<XCHAR>::TrimLeft(XCHAR chTarget)
1567 // Trims the specified character from the beginning of the string.
1568 {
1569 varint length = m_str.length();
1570 if (length == 0)
1571 return;
1572
1573 varint count = 0;
1574 const XCHAR *chars = m_str.data();
1575 while (count < length)
1576 {
1577 if (*chars != chTarget)
1578 break;
1579
1580 chars++;
1581 count++;
1582 }
1583
1584 m_str.remove(0, count);
1585 }
1586
1587 template <class XCHAR> inline void CXTString<XCHAR>::TrimLeft(LPCXSTR pszTargets)
1588 // Trims the specified set of characters from the beginning of the string.
1589 {
1590 if (pszTargets == NULL)
1591 return;
1592
1593 size_t targetLength = CXTCharArray<XCHAR>::xchar_strlen(pszTargets);
1594 if (targetLength <= 0)
1595 return;
1596
1597 varint length = m_str.length();
1598 if (length == 0)
1599 return;
1600
1601 varint count = 0;
1602 while (count < length)
1603 {
1604 if (!m_str.belongto(count, pszTargets, targetLength))
1605 break;
1606
1607 count++;
1608 }
1609
1610 m_str.remove(0, count);
1611 }
1612
1613 template <class XCHAR> inline void CXTString<XCHAR>::TrimRight()
1614 // Trims trailing whitespace characters from the string.
1615 {
1616 varint length = m_str.length();
1617 varint count = 0;
1618 const XCHAR *chars = m_str.data();
1619 chars += (length-1);
1620 while (count < length)
1621 {
1622 if (!CXTCharArray<XCHAR>::xchar_isspace(*chars))
1623 break;
1624
1625 chars--;
1626 count++;
1627 }
1628
1629 m_str.remove(size_t(length - count), count);
1630 }
1631
1632 template <class XCHAR> inline void CXTString<XCHAR>::TrimRight(XCHAR chTarget)
1633 // Trims the specified character from the end of the string.
1634 {
1635 varint length = m_str.length();
1636 if (length == 0)
1637 return;
1638
1639 varint count = 0;
1640 const XCHAR *chars = m_str.data();
1641 chars += (length-1);
1642 while (count < length)
1643 {
1644 if (*chars != chTarget)
1645 break;
1646
1647 chars--;
1648 count++;
1649 }
1650
1651 m_str.remove(size_t(length - count), count);
1652 }
1653
1654 template <class XCHAR> inline void CXTString<XCHAR>::TrimRight(LPCXSTR pszTargets)
1655 // Trims the specified set of characters from the end of the string.
1656 {
1657 if (pszTargets == NULL)
1658 return;
1659
1660 size_t targetLength = CXTCharArray<XCHAR>::xchar_strlen(pszTargets);
1661 if (targetLength <= 0)
1662 return;
1663
1664 varint length = m_str.length();
1665 if (length == 0)
1666 return;
1667
1668 varint count = 0;
1669 while (count < length)
1670 {
1671 if (!m_str.belongto(size_t(length-count-1), pszTargets, targetLength))
1672 break;
1673
1674 count++;
1675 }
1676
1677 m_str.remove(size_t(length - count), count);
1678 }
1679
1680 // Scan
1681 template <class XCHAR> inline int CXTString<XCHAR>::ScanS(LPCXSTR pszFormat, ...) const
1682 // Formats the string as sprintf does.
1683 {
1684 if (pszFormat == NULL)
1685 return 0;
1686
1687 va_list args;
1689 int result = ScanVS(pszFormat, args);
1690 va_end(args);
1691
1692 return result;
1693 }
1694
1695 template <class XCHAR> inline int CXTString<XCHAR>::ScanVS(LPCXSTR pszFormat, va_list args) const
1696 {
1697 if (pszFormat && GetLength() > 0)
1698 return CXTCharArray<XCHAR>::xchar_vscanf_s(m_str.data(), pszFormat, args);
1699
1700 return 0;
1701 }
1702
1703 template <class XCHAR> inline int CXTString<XCHAR>::ScanVS(int offsetCount, LPCXSTR pszFormat, va_list args) const
1704 {
1705 if (pszFormat && GetLength() > offsetCount)
1706 return CXTCharArray<XCHAR>::xchar_vscanf_s(m_str.data()+offsetCount, pszFormat, args);
1707
1708 return 0;
1709 }
1710
1711 // Format
1712 template <class XCHAR> inline void CXTString<XCHAR>::Format(LPCXSTR pszFormat, ...)
1713 // Formats the string as sprintf does.
1714 {
1715 if (pszFormat == NULL)
1716 return;
1717
1718 va_list args;
1720 FormatV(pszFormat, args);
1721 va_end(args);
1722 }
1723
1724 template <class XCHAR> inline void CXTString<XCHAR>::Format(unsigned int nID, ...)
1725 // Formats the string as sprintf does.
1726 {
1727 CXTString str;
1728 if (str.LoadString(nID))
1729 {
1730 va_list args;
1731 va_start(args, nID);
1732 FormatV(str.m_str.data(), args);
1733 va_end(args);
1734 }
1735 }
1736
1737 template <class XCHAR> inline void CXTString<XCHAR>::FormatV(LPCXSTR pszFormat, va_list args)
1738 // Formats the string using a variable list of arguments.
1739 {
1740 if (pszFormat == NULL)
1741 return;
1742
1743 va_list argscpy; // Needed as a single access is allowed for args on some OS
1745 int length = CXTCharArray<XCHAR>::xchar_vnprintf(0, 0, pszFormat, argscpy);
1746 va_end(argscpy);
1747
1748 if (length == -1)
1749 {
1750 Empty();
1751#ifdef _DEBUG
1752 XTRACE(_T("CXTString<XCHAR>::Format: an error occurs when formatting the string\n"));
1753#endif
1754 return;
1755 }
1756
1757 m_str.setlength(length); // this add space for null char
1758
1759#ifdef _DEBUG
1760 int result = CXTCharArray<XCHAR>::xchar_vnprintf(m_str.data(), length+1, pszFormat, args); // null char must be counted
1761 if (result != length)
1762 XTRACE(_T("CXTString<XCHAR>::Format: computed buffer is too short (%d != %d)\n"), result, length);
1763#else
1764 CXTCharArray<XCHAR>::xchar_vnprintf(m_str.data(), length+1, pszFormat, args);
1765#endif
1766 }
1767
1768 template <class XCHAR> bool CXTString<XCHAR>::LoadString(unsigned int resourceID)
1769 {
1770 *this = xLoadString(resourceID);
1771 return !IsEmpty();
1772 }
1773
1774 ///////////////////////////////////////////////////////////////////////////////////////////
1775 // Specialization
1776
1777 template<> inline DLL_TOOLSFUNCTION
1779 {
1780 if (pszText)
1781 m_str.assign(pszText);
1782 }
1783
1784 template<> inline DLL_TOOLSFUNCTION
1786 {
1787 if (pszText)
1788 m_str.assign(pszText);
1789 }
1790
1791 template<> inline DLL_TOOLSFUNCTION
1792 xStringEncoding CXTString<char>::GetDefaultEncoding()
1793 {
1794 #ifdef __WINDOWS__
1795 return xStringAnsi;
1796 #elif defined(__APPLE__) || defined(__LINUX__)
1797 return xStringUtf8;
1798 #endif
1799 }
1800
1801 template<> inline DLL_TOOLSFUNCTION
1803 {
1804 #ifdef __WINDOWS__
1805 return xStringUtf16;
1806 #elif defined(__APPLE__) || defined(__LINUX__)
1807 return xStringUtf16;
1808 #endif
1809 }
1810
1811 // Assignements
1812 template<> inline DLL_TOOLSFUNCTION
1814 {
1815 if (pszText)
1816 m_str.assign(pszText);
1817 else
1818 m_str.empty();
1819
1820 return *this;
1821 }
1822
1823 template<> inline DLL_TOOLSFUNCTION
1825 {
1826 if (pszText)
1827 m_str.assign(pszText);
1828 else
1829 m_str.empty();
1830
1831 return *this;
1832 }
1833
1834 template<> inline DLL_TOOLSFUNCTION
1836 {
1837 if (szText)
1838 m_str.append(szText);
1839
1840 return *this;
1841 }
1842
1843 template<> inline DLL_TOOLSFUNCTION
1845 {
1846 if (szText)
1847 m_str.append(szText);
1848
1849 return *this;
1850 }
1851
1852 template<> inline DLL_TOOLSFUNCTION
1854 {
1855 XFASTCW2A(m_str, pszText);
1856 }
1857
1858 template<> inline DLL_TOOLSFUNCTION
1860 {
1861 XFASTCA2W(m_str, pszText);
1862 }
1863
1864 template<> inline DLL_TOOLSFUNCTION
1866 {
1867 XFASTCW2A(m_str, pszText);
1868 return *this;
1869 }
1870
1871 template<class XCHAR>
1872 inline void CXTString<XCHAR>::Copy(LPCXSTR pszText, int nCount)
1873 {
1874 if (pszText && nCount > 0)
1875 m_str.assign(pszText, nCount);
1876 else
1877 m_str.empty();
1878 }
1879
1880 template<> inline DLL_TOOLSFUNCTION
1882 {
1883 XFASTCA2W(m_str, pszText);
1884 return *this;
1885 }
1886
1887 template<> inline DLL_TOOLSFUNCTION
1889 {
1890 if (szText)
1891 m_str.append(XCW2A(szText));
1892
1893 return *this;
1894 }
1895
1896 template<> inline DLL_TOOLSFUNCTION
1898 {
1899 if (szText)
1900 m_str.append(XCA2W(szText));
1901
1902 return *this;
1903 }
1904
1905#ifdef MOOTOOLS_MFC_PRODUCT_BUILD
1906 template <> inline DLL_TOOLSFUNCTION
1908 {
1909 }
1910
1911 template <> inline DLL_TOOLSFUNCTION
1913 {
1914 }
1915
1916 template <> inline DLL_TOOLSFUNCTION
1918 {
1919 }
1920
1921 template <> inline DLL_TOOLSFUNCTION
1923 {
1924 }
1925
1926 template <> inline DLL_TOOLSFUNCTION
1928 {
1929 this->operator=((LPCSTR)string);
1930 return *this;
1931 }
1932
1933 template <> inline DLL_TOOLSFUNCTION
1935 {
1936 this->operator=((LPCWSTR)string);
1937 return *this;
1938 }
1939
1940 template <> inline DLL_TOOLSFUNCTION
1942 {
1943 this->operator=((LPCSTR)string);
1944 return *this;
1945 }
1946
1947 template <> inline DLL_TOOLSFUNCTION
1949 {
1950 this->operator=((LPCWSTR)string);
1951 return *this;
1952 }
1953#endif
1954#endif // inline
1955
1956// If the template is used through DLL, this is better to have the class only once in a dll.
1957// Windows: In this case DLL_TOOLSFUNCTION is __declspec(dllexport) for one project and __declspec(dllimport) for the others
1958// MacOS: template are not exported and are used as inline function
1959// From Apple doc: "Note: Although template declarations can be marked with the visibility attribute, template instantiations cannot. This is a known limitation and may be fixed in a future version of GCC."
1960#if defined(__WINDOWS__)
1961template class DLL_TOOLSFUNCTION CXTString<char>;
1962template class DLL_TOOLSFUNCTION CXTString<wchar_t>;
1963#endif
1964
1965END_MOOTOOLS_NAMESPACE
1966
1967#ifdef __WINDOWS__
1968#pragma warning(pop)
1969#endif
1970#endif//CXTSTRING_CLASS_H
CXTString< wchar_t > CXStringW
CXStringA is an unicode wchar_t string. Cf. CXTString.
Definition XString.h:120
CXTString< char > CXStringA
CXStringA is an ansi / utf8 char string. Cf. CXTString.
Definition XString.h:119
CXTString< TCHAR > CXString
CXString depend on the target OS. Could be CXStringW (Windows) or CXStringA (Linux / Macos)
Definition XString.h:118
The class defines an x, y, z 3D point which can use int, float or double.
Definition 3DPoint.h:27
CXStringT is the template class for handling strings.
Definition XString.h:526
void TrimLeft(XCHAR chTarget)
Remove left specified character.
Definition XString.h:1566
void Trim()
Remove left and right space char.
Definition XString.h:1541
int GetLength() const
returns the length of the buffer in characters (can be greater than strlen, if set by GetBufferSetLen...
Definition XString.h:749
LPXSTR DetachBuffer()
Detach buffer. Caller must free buffer with xfree.
Definition XString.h:999
void TrimLeft(LPCXSTR pszTargets)
Remove any character from pszTargets string on the left side of the string.
Definition XString.h:1587
Conversion from ansi / utf8 (char) to unicode (wchar_t)
Definition xstringoperation.h:66
Conversion from unicode (wchar_t) to ansi / utf8 (char)
Definition xstringoperation.h:92
strings low level functions and conversion. Some are declared in macos_stringoperation,...