1 // Common/String.h
2
3 #ifndef __COMMON_STRING_H
4 #define __COMMON_STRING_H
5
6 #include <string.h>
7
8 #include "MyVector.h"
9
10 template <class T>
MyStringLen(const T * s)11 inline int MyStringLen(const T *s)
12 {
13 int i;
14 for (i = 0; s[i] != '\0'; i++);
15 return i;
16 }
17
18 template <class T>
MyStringCopy(T * dest,const T * src)19 inline T * MyStringCopy(T *dest, const T *src)
20 {
21 T *destStart = dest;
22 while ((*dest++ = *src++) != 0);
23 return destStart;
24 }
25
MyStringGetNextCharPointer(wchar_t * p)26 inline wchar_t* MyStringGetNextCharPointer(wchar_t *p)
27 { return (p + 1); }
MyStringGetNextCharPointer(const wchar_t * p)28 inline const wchar_t* MyStringGetNextCharPointer(const wchar_t *p)
29 { return (p + 1); }
MyStringGetPrevCharPointer(const wchar_t *,wchar_t * p)30 inline wchar_t* MyStringGetPrevCharPointer(const wchar_t *, wchar_t *p)
31 { return (p - 1); }
MyStringGetPrevCharPointer(const wchar_t *,const wchar_t * p)32 inline const wchar_t* MyStringGetPrevCharPointer(const wchar_t *, const wchar_t *p)
33 { return (p - 1); }
34
35 #ifdef _WIN32
36
MyStringGetNextCharPointer(const char * p)37 inline const char* MyStringGetNextCharPointer(const char *p)
38 {
39 #ifdef UNDER_CE
40 return p + 1;
41 #else
42 return CharNextA(p);
43 #endif
44 }
45
MyStringGetPrevCharPointer(const char * base,const char * p)46 inline const char* MyStringGetPrevCharPointer(const char *base, const char *p)
47 { return CharPrevA(base, p); }
48
MyCharUpper(char c)49 inline char MyCharUpper(char c)
50 { return (char)(unsigned int)(UINT_PTR)CharUpperA((LPSTR)(UINT_PTR)(unsigned int)(unsigned char)c); }
51 #ifdef _UNICODE
MyCharUpper(wchar_t c)52 inline wchar_t MyCharUpper(wchar_t c)
53 { return (wchar_t)(unsigned int)(UINT_PTR)CharUpperW((LPWSTR)(UINT_PTR)(unsigned int)c); }
54 #else
55 wchar_t MyCharUpper(wchar_t c);
56 #endif
57
58 #ifdef _UNICODE
MyCharLower(wchar_t c)59 inline wchar_t MyCharLower(wchar_t c)
60 { return (wchar_t)(unsigned int)(UINT_PTR)CharLowerW((LPWSTR)(UINT_PTR)(unsigned int)c); }
61 #else
62 wchar_t MyCharLower(wchar_t c);
63 #endif
64
MyCharLower(char c)65 inline char MyCharLower(char c)
66 #ifdef UNDER_CE
67 { return (char)MyCharLower((wchar_t)c); }
68 #else
69 { return (char)(unsigned int)(UINT_PTR)CharLowerA((LPSTR)(UINT_PTR)(unsigned int)(unsigned char)c); }
70 #endif
71
MyStringUpper(char * s)72 inline char * MyStringUpper(char *s) { return CharUpperA(s); }
73 #ifdef _UNICODE
MyStringUpper(wchar_t * s)74 inline wchar_t * MyStringUpper(wchar_t *s) { return CharUpperW(s); }
75 #else
76 wchar_t * MyStringUpper(wchar_t *s);
77 #endif
78
MyStringLower(char * s)79 inline char * MyStringLower(char *s) { return CharLowerA(s); }
80 #ifdef _UNICODE
MyStringLower(wchar_t * s)81 inline wchar_t * MyStringLower(wchar_t *s) { return CharLowerW(s); }
82 #else
83 wchar_t * MyStringLower(wchar_t *s);
84 #endif
85
86 #else // Standard-C
87 wchar_t MyCharUpper(wchar_t c);
88 #endif
89
90 //////////////////////////////////////
91 // Compare
92
93 /*
94 #ifndef UNDER_CE
95 int MyStringCollate(const char *s1, const char *s2);
96 int MyStringCollateNoCase(const char *s1, const char *s2);
97 #endif
98 int MyStringCollate(const wchar_t *s1, const wchar_t *s2);
99 int MyStringCollateNoCase(const wchar_t *s1, const wchar_t *s2);
100 */
101
102 int MyStringCompare(const char *s1, const char *s2);
103 int MyStringCompare(const wchar_t *s1, const wchar_t *s2);
104
105 // int MyStringCompareNoCase(const char *s1, const char *s2);
106 int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2);
107
108 template <class T>
109 class CStringBase
110 {
TrimLeftWithCharSet(const CStringBase & charSet)111 void TrimLeftWithCharSet(const CStringBase &charSet)
112 {
113 const T *p = _chars;
114 while (charSet.Find(*p) >= 0 && (*p != 0))
115 p = GetNextCharPointer(p);
116 Delete(0, (int)(p - _chars));
117 }
TrimRightWithCharSet(const CStringBase & charSet)118 void TrimRightWithCharSet(const CStringBase &charSet)
119 {
120 const T *p = _chars;
121 const T *pLast = NULL;
122 while (*p != 0)
123 {
124 if (charSet.Find(*p) >= 0)
125 {
126 if (pLast == NULL)
127 pLast = p;
128 }
129 else
130 pLast = NULL;
131 p = GetNextCharPointer(p);
132 }
133 if (pLast != NULL)
134 {
135 int i = (int)(pLast - _chars);
136 Delete(i, _length - i);
137 }
138
139 }
MoveItems(int destIndex,int srcIndex)140 void MoveItems(int destIndex, int srcIndex)
141 {
142 memmove(_chars + destIndex, _chars + srcIndex,
143 sizeof(T) * (_length - srcIndex + 1));
144 }
145
InsertSpace(int & index,int size)146 void InsertSpace(int &index, int size)
147 {
148 CorrectIndex(index);
149 GrowLength(size);
150 MoveItems(index + size, index);
151 }
152
GetNextCharPointer(const T * p)153 static const T *GetNextCharPointer(const T *p)
154 { return MyStringGetNextCharPointer(p); }
GetPrevCharPointer(const T * base,const T * p)155 static const T *GetPrevCharPointer(const T *base, const T *p)
156 { return MyStringGetPrevCharPointer(base, p); }
157 protected:
158 T *_chars;
159 int _length;
160 int _capacity;
161
SetCapacity(int newCapacity)162 void SetCapacity(int newCapacity)
163 {
164 int realCapacity = newCapacity + 1;
165 if (realCapacity == _capacity)
166 return;
167 /*
168 const int kMaxStringSize = 0x20000000;
169 if (newCapacity > kMaxStringSize || newCapacity < _length)
170 throw 1052337;
171 */
172 T *newBuffer = new T[realCapacity];
173 if (_capacity > 0)
174 {
175 for (int i = 0; i < _length; i++)
176 newBuffer[i] = _chars[i];
177 delete []_chars;
178 }
179 _chars = newBuffer;
180 _chars[_length] = 0;
181 _capacity = realCapacity;
182 }
183
GrowLength(int n)184 void GrowLength(int n)
185 {
186 int freeSize = _capacity - _length - 1;
187 if (n <= freeSize)
188 return;
189 int delta;
190 if (_capacity > 64)
191 delta = _capacity / 2;
192 else if (_capacity > 8)
193 delta = 16;
194 else
195 delta = 4;
196 if (freeSize + delta < n)
197 delta = n - freeSize;
198 SetCapacity(_capacity + delta);
199 }
200
CorrectIndex(int & index)201 void CorrectIndex(int &index) const
202 {
203 if (index > _length)
204 index = _length;
205 }
206
207 public:
CStringBase()208 CStringBase(): _chars(0), _length(0), _capacity(0) { SetCapacity(3); }
CStringBase(T c)209 CStringBase(T c): _chars(0), _length(0), _capacity(0)
210 {
211 SetCapacity(1);
212 _chars[0] = c;
213 _chars[1] = 0;
214 _length = 1;
215 }
CStringBase(const T * chars)216 CStringBase(const T *chars): _chars(0), _length(0), _capacity(0)
217 {
218 int length = MyStringLen(chars);
219 SetCapacity(length);
220 MyStringCopy(_chars, chars); // can be optimized by memove()
221 _length = length;
222 }
CStringBase(const CStringBase & s)223 CStringBase(const CStringBase &s): _chars(0), _length(0), _capacity(0)
224 {
225 SetCapacity(s._length);
226 MyStringCopy(_chars, s._chars);
227 _length = s._length;
228 }
~CStringBase()229 ~CStringBase() { delete []_chars; }
230
231 operator const T*() const { return _chars;}
232
Back()233 T Back() const { return _chars[_length - 1]; }
234
235 // The minimum size of the character buffer in characters.
236 // This value does not include space for a null terminator.
GetBuffer(int minBufLength)237 T* GetBuffer(int minBufLength)
238 {
239 if (minBufLength >= _capacity)
240 SetCapacity(minBufLength);
241 return _chars;
242 }
ReleaseBuffer()243 void ReleaseBuffer() { ReleaseBuffer(MyStringLen(_chars)); }
ReleaseBuffer(int newLength)244 void ReleaseBuffer(int newLength)
245 {
246 /*
247 if (newLength >= _capacity)
248 throw 282217;
249 */
250 _chars[newLength] = 0;
251 _length = newLength;
252 }
253
254 CStringBase& operator=(T c)
255 {
256 Empty();
257 SetCapacity(1);
258 _chars[0] = c;
259 _chars[1] = 0;
260 _length = 1;
261 return *this;
262 }
263 CStringBase& operator=(const T *chars)
264 {
265 Empty();
266 int length = MyStringLen(chars);
267 SetCapacity(length);
268 MyStringCopy(_chars, chars);
269 _length = length;
270 return *this;
271 }
272 CStringBase& operator=(const CStringBase& s)
273 {
274 if (&s == this)
275 return *this;
276 Empty();
277 SetCapacity(s._length);
278 MyStringCopy(_chars, s._chars);
279 _length = s._length;
280 return *this;
281 }
282
283 CStringBase& operator+=(T c)
284 {
285 GrowLength(1);
286 _chars[_length] = c;
287 _chars[++_length] = 0;
288 return *this;
289 }
290 CStringBase& operator+=(const T *s)
291 {
292 int len = MyStringLen(s);
293 GrowLength(len);
294 MyStringCopy(_chars + _length, s);
295 _length += len;
296 return *this;
297 }
298 CStringBase& operator+=(const CStringBase &s)
299 {
300 GrowLength(s._length);
301 MyStringCopy(_chars + _length, s._chars);
302 _length += s._length;
303 return *this;
304 }
Empty()305 void Empty()
306 {
307 _length = 0;
308 _chars[0] = 0;
309 }
Length()310 int Length() const { return _length; }
IsEmpty()311 bool IsEmpty() const { return (_length == 0); }
312
Mid(int startIndex)313 CStringBase Mid(int startIndex) const
314 { return Mid(startIndex, _length - startIndex); }
Mid(int startIndex,int count)315 CStringBase Mid(int startIndex, int count) const
316 {
317 if (startIndex + count > _length)
318 count = _length - startIndex;
319
320 if (startIndex == 0 && startIndex + count == _length)
321 return *this;
322
323 CStringBase<T> result;
324 result.SetCapacity(count);
325 // MyStringNCopy(result._chars, _chars + startIndex, count);
326 for (int i = 0; i < count; i++)
327 result._chars[i] = _chars[startIndex + i];
328 result._chars[count] = 0;
329 result._length = count;
330 return result;
331 }
Left(int count)332 CStringBase Left(int count) const
333 { return Mid(0, count); }
Right(int count)334 CStringBase Right(int count) const
335 {
336 if (count > _length)
337 count = _length;
338 return Mid(_length - count, count);
339 }
340
MakeUpper()341 void MakeUpper()
342 { MyStringUpper(_chars); }
MakeLower()343 void MakeLower()
344 { MyStringLower(_chars); }
345
Compare(const CStringBase & s)346 int Compare(const CStringBase& s) const
347 { return MyStringCompare(_chars, s._chars); }
348
Compare(const T * s)349 int Compare(const T *s) const
350 { return MyStringCompare(_chars, s); }
351
CompareNoCase(const CStringBase & s)352 int CompareNoCase(const CStringBase& s) const
353 { return MyStringCompareNoCase(_chars, s._chars); }
354
CompareNoCase(const T * s)355 int CompareNoCase(const T *s) const
356 { return MyStringCompareNoCase(_chars, s); }
357
358 /*
359 int Collate(const CStringBase& s) const
360 { return MyStringCollate(_chars, s._chars); }
361 int CollateNoCase(const CStringBase& s) const
362 { return MyStringCollateNoCase(_chars, s._chars); }
363 */
364
Find(T c)365 int Find(T c) const { return Find(c, 0); }
Find(T c,int startIndex)366 int Find(T c, int startIndex) const
367 {
368 const T *p = _chars + startIndex;
369 for (;;)
370 {
371 if (*p == c)
372 return (int)(p - _chars);
373 if (*p == 0)
374 return -1;
375 p = GetNextCharPointer(p);
376 }
377 }
Find(const CStringBase & s)378 int Find(const CStringBase &s) const { return Find(s, 0); }
Find(const CStringBase & s,int startIndex)379 int Find(const CStringBase &s, int startIndex) const
380 {
381 if (s.IsEmpty())
382 return startIndex;
383 for (; startIndex < _length; startIndex++)
384 {
385 int j;
386 for (j = 0; j < s._length && startIndex + j < _length; j++)
387 if (_chars[startIndex+j] != s._chars[j])
388 break;
389 if (j == s._length)
390 return startIndex;
391 }
392 return -1;
393 }
ReverseFind(T c)394 int ReverseFind(T c) const
395 {
396 if (_length == 0)
397 return -1;
398 const T *p = _chars + _length - 1;
399 for (;;)
400 {
401 if (*p == c)
402 return (int)(p - _chars);
403 if (p == _chars)
404 return -1;
405 p = GetPrevCharPointer(_chars, p);
406 }
407 }
FindOneOf(const CStringBase & s)408 int FindOneOf(const CStringBase &s) const
409 {
410 for (int i = 0; i < _length; i++)
411 if (s.Find(_chars[i]) >= 0)
412 return i;
413 return -1;
414 }
415
TrimLeft(T c)416 void TrimLeft(T c)
417 {
418 const T *p = _chars;
419 while (c == *p)
420 p = GetNextCharPointer(p);
421 Delete(0, p - _chars);
422 }
423 private:
GetTrimDefaultCharSet()424 CStringBase GetTrimDefaultCharSet()
425 {
426 CStringBase<T> charSet;
427 charSet += (T)' ';
428 charSet += (T)'\n';
429 charSet += (T)'\t';
430 return charSet;
431 }
432 public:
433
TrimLeft()434 void TrimLeft()
435 {
436 TrimLeftWithCharSet(GetTrimDefaultCharSet());
437 }
TrimRight()438 void TrimRight()
439 {
440 TrimRightWithCharSet(GetTrimDefaultCharSet());
441 }
TrimRight(T c)442 void TrimRight(T c)
443 {
444 const T *p = _chars;
445 const T *pLast = NULL;
446 while (*p != 0)
447 {
448 if (*p == c)
449 {
450 if (pLast == NULL)
451 pLast = p;
452 }
453 else
454 pLast = NULL;
455 p = GetNextCharPointer(p);
456 }
457 if (pLast != NULL)
458 {
459 int i = pLast - _chars;
460 Delete(i, _length - i);
461 }
462 }
Trim()463 void Trim()
464 {
465 TrimRight();
466 TrimLeft();
467 }
468
Insert(int index,T c)469 int Insert(int index, T c)
470 {
471 InsertSpace(index, 1);
472 _chars[index] = c;
473 _length++;
474 return _length;
475 }
Insert(int index,const CStringBase & s)476 int Insert(int index, const CStringBase &s)
477 {
478 CorrectIndex(index);
479 if (s.IsEmpty())
480 return _length;
481 int numInsertChars = s.Length();
482 InsertSpace(index, numInsertChars);
483 for (int i = 0; i < numInsertChars; i++)
484 _chars[index + i] = s[i];
485 _length += numInsertChars;
486 return _length;
487 }
488
489 // !!!!!!!!!!!!!!! test it if newChar = '\0'
Replace(T oldChar,T newChar)490 int Replace(T oldChar, T newChar)
491 {
492 if (oldChar == newChar)
493 return 0;
494 int number = 0;
495 int pos = 0;
496 while (pos < Length())
497 {
498 pos = Find(oldChar, pos);
499 if (pos < 0)
500 break;
501 _chars[pos] = newChar;
502 pos++;
503 number++;
504 }
505 return number;
506 }
Replace(const CStringBase & oldString,const CStringBase & newString)507 int Replace(const CStringBase &oldString, const CStringBase &newString)
508 {
509 if (oldString.IsEmpty())
510 return 0;
511 if (oldString == newString)
512 return 0;
513 int oldStringLength = oldString.Length();
514 int newStringLength = newString.Length();
515 int number = 0;
516 int pos = 0;
517 while (pos < _length)
518 {
519 pos = Find(oldString, pos);
520 if (pos < 0)
521 break;
522 Delete(pos, oldStringLength);
523 Insert(pos, newString);
524 pos += newStringLength;
525 number++;
526 }
527 return number;
528 }
529 int Delete(int index, int count = 1)
530 {
531 if (index + count > _length)
532 count = _length - index;
533 if (count > 0)
534 {
535 MoveItems(index, index + count);
536 _length -= count;
537 }
538 return _length;
539 }
DeleteBack()540 void DeleteBack() { Delete(_length - 1); }
541 };
542
543 template <class T>
544 CStringBase<T> operator+(const CStringBase<T>& s1, const CStringBase<T>& s2)
545 {
546 CStringBase<T> result(s1);
547 result += s2;
548 return result;
549 }
550
551 template <class T>
552 CStringBase<T> operator+(const CStringBase<T>& s, T c)
553 {
554 CStringBase<T> result(s);
555 result += c;
556 return result;
557 }
558
559 template <class T>
560 CStringBase<T> operator+(T c, const CStringBase<T>& s)
561 {
562 CStringBase<T> result(c);
563 result += s;
564 return result;
565 }
566
567 template <class T>
568 CStringBase<T> operator+(const CStringBase<T>& s, const T * chars)
569 {
570 CStringBase<T> result(s);
571 result += chars;
572 return result;
573 }
574
575 template <class T>
576 CStringBase<T> operator+(const T * chars, const CStringBase<T>& s)
577 {
578 CStringBase<T> result(chars);
579 result += s;
580 return result;
581 }
582
583 template <class T>
584 bool operator==(const CStringBase<T>& s1, const CStringBase<T>& s2)
585 { return (s1.Compare(s2) == 0); }
586
587 template <class T>
588 bool operator<(const CStringBase<T>& s1, const CStringBase<T>& s2)
589 { return (s1.Compare(s2) < 0); }
590
591 template <class T>
592 bool operator==(const T *s1, const CStringBase<T>& s2)
593 { return (s2.Compare(s1) == 0); }
594
595 template <class T>
596 bool operator==(const CStringBase<T>& s1, const T *s2)
597 { return (s1.Compare(s2) == 0); }
598
599 template <class T>
600 bool operator!=(const CStringBase<T>& s1, const CStringBase<T>& s2)
601 { return (s1.Compare(s2) != 0); }
602
603 template <class T>
604 bool operator!=(const T *s1, const CStringBase<T>& s2)
605 { return (s2.Compare(s1) != 0); }
606
607 template <class T>
608 bool operator!=(const CStringBase<T>& s1, const T *s2)
609 { return (s1.Compare(s2) != 0); }
610
611 typedef CStringBase<char> AString;
612 typedef CStringBase<wchar_t> UString;
613
614 typedef CObjectVector<AString> AStringVector;
615 typedef CObjectVector<UString> UStringVector;
616
617 #ifdef _UNICODE
618 typedef UString CSysString;
619 #else
620 typedef AString CSysString;
621 #endif
622
623 typedef CObjectVector<CSysString> CSysStringVector;
624
625 #endif
626