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
10template <class T>
11inline int MyStringLen(const T *s)
12{
13  int i;
14  for (i = 0; s[i] != '\0'; i++);
15  return i;
16}
17
18template <class T>
19inline T * MyStringCopy(T *dest, const T *src)
20{
21  T *destStart = dest;
22  while ((*dest++ = *src++) != 0);
23  return destStart;
24}
25
26inline wchar_t* MyStringGetNextCharPointer(wchar_t *p)
27  { return (p + 1); }
28inline const wchar_t* MyStringGetNextCharPointer(const wchar_t *p)
29  { return (p + 1); }
30inline wchar_t* MyStringGetPrevCharPointer(const wchar_t *, wchar_t *p)
31  { return (p - 1); }
32inline const wchar_t* MyStringGetPrevCharPointer(const wchar_t *, const wchar_t *p)
33  { return (p - 1); }
34
35#ifdef _WIN32
36
37inline 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
46inline const char* MyStringGetPrevCharPointer(const char *base, const char *p)
47  { return CharPrevA(base, p); }
48
49inline char MyCharUpper(char c)
50  { return (char)(unsigned int)(UINT_PTR)CharUpperA((LPSTR)(UINT_PTR)(unsigned int)(unsigned char)c); }
51#ifdef _UNICODE
52inline wchar_t MyCharUpper(wchar_t c)
53  { return (wchar_t)(unsigned int)(UINT_PTR)CharUpperW((LPWSTR)(UINT_PTR)(unsigned int)c); }
54#else
55wchar_t MyCharUpper(wchar_t c);
56#endif
57
58#ifdef _UNICODE
59inline wchar_t MyCharLower(wchar_t c)
60  { return (wchar_t)(unsigned int)(UINT_PTR)CharLowerW((LPWSTR)(UINT_PTR)(unsigned int)c); }
61#else
62wchar_t MyCharLower(wchar_t c);
63#endif
64
65inline 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
72inline char * MyStringUpper(char *s) { return CharUpperA(s); }
73#ifdef _UNICODE
74inline wchar_t * MyStringUpper(wchar_t *s) { return CharUpperW(s); }
75#else
76wchar_t * MyStringUpper(wchar_t *s);
77#endif
78
79inline char * MyStringLower(char *s) { return CharLowerA(s); }
80#ifdef _UNICODE
81inline wchar_t * MyStringLower(wchar_t *s) { return CharLowerW(s); }
82#else
83wchar_t * MyStringLower(wchar_t *s);
84#endif
85
86#else // Standard-C
87wchar_t MyCharUpper(wchar_t c);
88#endif
89
90//////////////////////////////////////
91// Compare
92
93/*
94#ifndef UNDER_CE
95int MyStringCollate(const char *s1, const char *s2);
96int MyStringCollateNoCase(const char *s1, const char *s2);
97#endif
98int MyStringCollate(const wchar_t *s1, const wchar_t *s2);
99int MyStringCollateNoCase(const wchar_t *s1, const wchar_t *s2);
100*/
101
102int MyStringCompare(const char *s1, const char  *s2);
103int MyStringCompare(const wchar_t *s1, const wchar_t *s2);
104
105// int MyStringCompareNoCase(const char *s1, const char  *s2);
106int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2);
107
108template <class T>
109class CStringBase
110{
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  }
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  }
140  void MoveItems(int destIndex, int srcIndex)
141  {
142    memmove(_chars + destIndex, _chars + srcIndex,
143        sizeof(T) * (_length - srcIndex + 1));
144  }
145
146  void InsertSpace(int &index, int size)
147  {
148    CorrectIndex(index);
149    GrowLength(size);
150    MoveItems(index + size, index);
151  }
152
153  static const T *GetNextCharPointer(const T *p)
154    { return MyStringGetNextCharPointer(p); }
155  static const T *GetPrevCharPointer(const T *base, const T *p)
156    { return MyStringGetPrevCharPointer(base, p); }
157protected:
158  T *_chars;
159  int _length;
160  int _capacity;
161
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
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
201  void CorrectIndex(int &index) const
202  {
203    if (index > _length)
204      index = _length;
205  }
206
207public:
208  CStringBase(): _chars(0), _length(0), _capacity(0) { SetCapacity(3); }
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  }
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  }
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  }
229  ~CStringBase() {  delete []_chars; }
230
231  operator const T*() const { return _chars;}
232
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.
237  T* GetBuffer(int minBufLength)
238  {
239    if (minBufLength >= _capacity)
240      SetCapacity(minBufLength);
241    return _chars;
242  }
243  void ReleaseBuffer() { ReleaseBuffer(MyStringLen(_chars)); }
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  }
305  void Empty()
306  {
307    _length = 0;
308    _chars[0] = 0;
309  }
310  int Length() const { return _length; }
311  bool IsEmpty() const { return (_length == 0); }
312
313  CStringBase Mid(int startIndex) const
314    { return Mid(startIndex, _length - startIndex); }
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  }
332  CStringBase Left(int count) const
333    { return Mid(0, count); }
334  CStringBase Right(int count) const
335  {
336    if (count > _length)
337      count = _length;
338    return Mid(_length - count, count);
339  }
340
341  void MakeUpper()
342    { MyStringUpper(_chars); }
343  void MakeLower()
344    { MyStringLower(_chars); }
345
346  int Compare(const CStringBase& s) const
347    { return MyStringCompare(_chars, s._chars); }
348
349  int Compare(const T *s) const
350    { return MyStringCompare(_chars, s); }
351
352  int CompareNoCase(const CStringBase& s) const
353    { return MyStringCompareNoCase(_chars, s._chars); }
354
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
365  int Find(T c) const { return Find(c, 0); }
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  }
378  int Find(const CStringBase &s) const { return Find(s, 0); }
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  }
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  }
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
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:
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
434  void TrimLeft()
435  {
436    TrimLeftWithCharSet(GetTrimDefaultCharSet());
437  }
438  void TrimRight()
439  {
440    TrimRightWithCharSet(GetTrimDefaultCharSet());
441  }
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  }
463  void Trim()
464  {
465    TrimRight();
466    TrimLeft();
467  }
468
469  int Insert(int index, T c)
470  {
471    InsertSpace(index, 1);
472    _chars[index] = c;
473    _length++;
474    return _length;
475  }
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'
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  }
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  }
540  void DeleteBack() { Delete(_length - 1); }
541};
542
543template <class T>
544CStringBase<T> operator+(const CStringBase<T>& s1, const CStringBase<T>& s2)
545{
546  CStringBase<T> result(s1);
547  result += s2;
548  return result;
549}
550
551template <class T>
552CStringBase<T> operator+(const CStringBase<T>& s, T c)
553{
554  CStringBase<T> result(s);
555  result += c;
556  return result;
557}
558
559template <class T>
560CStringBase<T> operator+(T c, const CStringBase<T>& s)
561{
562  CStringBase<T> result(c);
563  result += s;
564  return result;
565}
566
567template <class T>
568CStringBase<T> operator+(const CStringBase<T>& s, const T * chars)
569{
570  CStringBase<T> result(s);
571  result += chars;
572  return result;
573}
574
575template <class T>
576CStringBase<T> operator+(const T * chars, const CStringBase<T>& s)
577{
578  CStringBase<T> result(chars);
579  result += s;
580  return result;
581}
582
583template <class T>
584bool operator==(const CStringBase<T>& s1, const CStringBase<T>& s2)
585  { return (s1.Compare(s2) == 0); }
586
587template <class T>
588bool operator<(const CStringBase<T>& s1, const CStringBase<T>& s2)
589  { return (s1.Compare(s2) < 0); }
590
591template <class T>
592bool operator==(const T *s1, const CStringBase<T>& s2)
593  { return (s2.Compare(s1) == 0); }
594
595template <class T>
596bool operator==(const CStringBase<T>& s1, const T *s2)
597  { return (s1.Compare(s2) == 0); }
598
599template <class T>
600bool operator!=(const CStringBase<T>& s1, const CStringBase<T>& s2)
601  { return (s1.Compare(s2) != 0); }
602
603template <class T>
604bool operator!=(const T *s1, const CStringBase<T>& s2)
605  { return (s2.Compare(s1) != 0); }
606
607template <class T>
608bool operator!=(const CStringBase<T>& s1, const T *s2)
609  { return (s1.Compare(s2) != 0); }
610
611typedef CStringBase<char> AString;
612typedef CStringBase<wchar_t> UString;
613
614typedef CObjectVector<AString> AStringVector;
615typedef CObjectVector<UString> UStringVector;
616
617#ifdef _UNICODE
618  typedef UString CSysString;
619#else
620  typedef AString CSysString;
621#endif
622
623typedef CObjectVector<CSysString> CSysStringVector;
624
625#endif
626