Home | History | Annotate | Download | only in Common
      1 // Common/MyString.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #ifdef _WIN32
      6 #include <windows.h>
      7 #include <wchar.h>
      8 #else
      9 #include <ctype.h>
     10 #endif
     11 
     12 #if !defined(_UNICODE) || !defined(USE_UNICODE_FSTRING)
     13 #include "StringConvert.h"
     14 #endif
     15 
     16 #include "MyString.h"
     17 
     18 #define MY_STRING_NEW(_T_, _size_) new _T_[_size_]
     19 // #define MY_STRING_NEW(_T_, _size_) ((_T_ *)my_new((size_t)(_size_) * sizeof(_T_)))
     20 
     21 /*
     22 inline const char* MyStringGetNextCharPointer(const char *p) throw()
     23 {
     24   #if defined(_WIN32) && !defined(UNDER_CE)
     25   return CharNextA(p);
     26   #else
     27   return p + 1;
     28   #endif
     29 }
     30 */
     31 
     32 int FindCharPosInString(const char *s, char c) throw()
     33 {
     34   for (const char *p = s;; p++)
     35   {
     36     if (*p == c)
     37       return (int)(p - s);
     38     if (*p == 0)
     39       return -1;
     40     // MyStringGetNextCharPointer(p);
     41   }
     42 }
     43 
     44 int FindCharPosInString(const wchar_t *s, wchar_t c) throw()
     45 {
     46   for (const wchar_t *p = s;; p++)
     47   {
     48     if (*p == c)
     49       return (int)(p - s);
     50     if (*p == 0)
     51       return -1;
     52   }
     53 }
     54 
     55 /*
     56 void MyStringUpper_Ascii(wchar_t *s)
     57 {
     58   for (;;)
     59   {
     60     wchar_t c = *s;
     61     if (c == 0)
     62       return;
     63     *s++ = MyCharUpper_Ascii(c);
     64   }
     65 }
     66 */
     67 
     68 void MyStringLower_Ascii(wchar_t *s) throw()
     69 {
     70   for (;;)
     71   {
     72     wchar_t c = *s;
     73     if (c == 0)
     74       return;
     75     *s++ = MyCharLower_Ascii(c);
     76   }
     77 }
     78 
     79 #ifdef _WIN32
     80 
     81 #ifdef _UNICODE
     82 
     83 // wchar_t * MyStringUpper(wchar_t *s) { return CharUpperW(s); }
     84 // wchar_t * MyStringLower(wchar_t *s) { return CharLowerW(s); }
     85 // for WinCE - FString - char
     86 // const char *MyStringGetPrevCharPointer(const char * /* base */, const char *p) { return p - 1; }
     87 
     88 #else
     89 
     90 // const char * MyStringGetPrevCharPointer(const char *base, const char *p) throw() { return CharPrevA(base, p); }
     91 // char * MyStringUpper(char *s) { return CharUpperA(s); }
     92 // char * MyStringLower(char *s) { return CharLowerA(s); }
     93 
     94 wchar_t MyCharUpper_WIN(wchar_t c) throw()
     95 {
     96   wchar_t *res = CharUpperW((LPWSTR)(UINT_PTR)(unsigned)c);
     97   if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
     98     return (wchar_t)(unsigned)(UINT_PTR)res;
     99   const int kBufSize = 4;
    100   char s[kBufSize + 1];
    101   int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufSize, 0, 0);
    102   if (numChars == 0 || numChars > kBufSize)
    103     return c;
    104   s[numChars] = 0;
    105   ::CharUpperA(s);
    106   ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1);
    107   return c;
    108 }
    109 
    110 /*
    111 wchar_t MyCharLower_WIN(wchar_t c)
    112 {
    113   wchar_t *res = CharLowerW((LPWSTR)(UINT_PTR)(unsigned)c);
    114   if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
    115     return (wchar_t)(unsigned)(UINT_PTR)res;
    116   const int kBufSize = 4;
    117   char s[kBufSize + 1];
    118   int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufSize, 0, 0);
    119   if (numChars == 0 || numChars > kBufSize)
    120     return c;
    121   s[numChars] = 0;
    122   ::CharLowerA(s);
    123   ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1);
    124   return c;
    125 }
    126 */
    127 
    128 /*
    129 wchar_t * MyStringUpper(wchar_t *s)
    130 {
    131   if (s == 0)
    132     return 0;
    133   wchar_t *res = CharUpperW(s);
    134   if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
    135     return res;
    136   AString a = UnicodeStringToMultiByte(s);
    137   a.MakeUpper();
    138   MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a));
    139   return s;
    140 }
    141 */
    142 
    143 /*
    144 wchar_t * MyStringLower(wchar_t *s)
    145 {
    146   if (s == 0)
    147     return 0;
    148   wchar_t *res = CharLowerW(s);
    149   if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
    150     return res;
    151   AString a = UnicodeStringToMultiByte(s);
    152   a.MakeLower();
    153   MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a));
    154   return s;
    155 }
    156 */
    157 
    158 #endif
    159 
    160 #endif
    161 
    162 bool IsString1PrefixedByString2(const char *s1, const char *s2) throw()
    163 {
    164   for (;;)
    165   {
    166     unsigned char c2 = (unsigned char)*s2++; if (c2 == 0) return true;
    167     unsigned char c1 = (unsigned char)*s1++; if (c1 != c2) return false;
    168   }
    169 }
    170 
    171 bool StringsAreEqualNoCase(const wchar_t *s1, const wchar_t *s2) throw()
    172 {
    173   for (;;)
    174   {
    175     wchar_t c1 = *s1++;
    176     wchar_t c2 = *s2++;
    177     if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2)) return false;
    178     if (c1 == 0) return true;
    179   }
    180 }
    181 
    182 // ---------- ASCII ----------
    183 
    184 bool AString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw()
    185 {
    186   const char *s1 = _chars;
    187   for (;;)
    188   {
    189     char c2 = *s++;
    190     if (c2 == 0)
    191       return true;
    192     char c1 = *s1++;
    193     if (MyCharLower_Ascii(c1) !=
    194         MyCharLower_Ascii(c2))
    195       return false;
    196   }
    197 }
    198 
    199 bool UString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw()
    200 {
    201   const wchar_t *s1 = _chars;
    202   for (;;)
    203   {
    204     char c2 = *s++;
    205     if (c2 == 0)
    206       return true;
    207     wchar_t c1 = *s1++;
    208     if (MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2))
    209       return false;
    210   }
    211 }
    212 
    213 bool StringsAreEqual_Ascii(const wchar_t *u, const char *a) throw()
    214 {
    215   for (;;)
    216   {
    217     unsigned char c = *a;
    218     if (c != *u)
    219       return false;
    220     if (c == 0)
    221       return true;
    222     a++;
    223     u++;
    224   }
    225 }
    226 
    227 bool StringsAreEqualNoCase_Ascii(const char *s1, const char *s2) throw()
    228 {
    229   for (;;)
    230   {
    231     char c1 = *s1++;
    232     char c2 = *s2++;
    233     if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2))
    234       return false;
    235     if (c1 == 0)
    236       return true;
    237   }
    238 }
    239 
    240 bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const wchar_t *s2) throw()
    241 {
    242   for (;;)
    243   {
    244     wchar_t c1 = *s1++;
    245     wchar_t c2 = *s2++;
    246     if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2))
    247       return false;
    248     if (c1 == 0)
    249       return true;
    250   }
    251 }
    252 
    253 bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const char *s2) throw()
    254 {
    255   for (;;)
    256   {
    257     wchar_t c1 = *s1++;
    258     char c2 = *s2++;
    259     if (c1 != (unsigned char)c2 && (c1 > 0x7F || MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2)))
    260       return false;
    261     if (c1 == 0)
    262       return true;
    263   }
    264 }
    265 
    266 bool IsString1PrefixedByString2(const wchar_t *s1, const wchar_t *s2) throw()
    267 {
    268   for (;;)
    269   {
    270     wchar_t c2 = *s2++; if (c2 == 0) return true;
    271     wchar_t c1 = *s1++; if (c1 != c2) return false;
    272   }
    273 }
    274 
    275 // NTFS order: uses upper case
    276 int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2) throw()
    277 {
    278   for (;;)
    279   {
    280     wchar_t c1 = *s1++;
    281     wchar_t c2 = *s2++;
    282     if (c1 != c2)
    283     {
    284       wchar_t u1 = MyCharUpper(c1);
    285       wchar_t u2 = MyCharUpper(c2);
    286       if (u1 < u2) return -1;
    287       if (u1 > u2) return 1;
    288     }
    289     if (c1 == 0) return 0;
    290   }
    291 }
    292 
    293 int MyStringCompareNoCase_N(const wchar_t *s1, const wchar_t *s2, unsigned num) throw()
    294 {
    295   for (; num != 0; num--)
    296   {
    297     wchar_t c1 = *s1++;
    298     wchar_t c2 = *s2++;
    299     if (c1 != c2)
    300     {
    301       wchar_t u1 = MyCharUpper(c1);
    302       wchar_t u2 = MyCharUpper(c2);
    303       if (u1 < u2) return -1;
    304       if (u1 > u2) return 1;
    305     }
    306     if (c1 == 0) return 0;
    307   }
    308   return 0;
    309 }
    310 
    311 
    312 // ---------- AString ----------
    313 
    314 void AString::InsertSpace(unsigned &index, unsigned size)
    315 {
    316   Grow(size);
    317   MoveItems(index + size, index);
    318 }
    319 
    320 void AString::ReAlloc(unsigned newLimit)
    321 {
    322   if (newLimit < _len || newLimit >= 0x20000000) throw 20130220;
    323   // MY_STRING_REALLOC(_chars, char, newLimit + 1, _len + 1);
    324   char *newBuf = MY_STRING_NEW(char, newLimit + 1);
    325   memcpy(newBuf, _chars, (size_t)(_len + 1)); \
    326   MY_STRING_DELETE(_chars);
    327   _chars = newBuf;
    328 
    329   _limit = newLimit;
    330 }
    331 
    332 void AString::SetStartLen(unsigned len)
    333 {
    334   _chars = 0;
    335   _chars = MY_STRING_NEW(char, len + 1);
    336   _len = len;
    337   _limit = len;
    338 }
    339 
    340 void AString::Grow_1()
    341 {
    342   unsigned next = _len;
    343   next += next / 2;
    344   next += 16;
    345   next &= ~(unsigned)15;
    346   ReAlloc(next - 1);
    347 }
    348 
    349 void AString::Grow(unsigned n)
    350 {
    351   unsigned freeSize = _limit - _len;
    352   if (n <= freeSize)
    353     return;
    354 
    355   unsigned next = _len + n;
    356   next += next / 2;
    357   next += 16;
    358   next &= ~(unsigned)15;
    359   ReAlloc(next - 1);
    360 }
    361 
    362 /*
    363 AString::AString(unsigned num, const char *s)
    364 {
    365   unsigned len = MyStringLen(s);
    366   if (num > len)
    367     num = len;
    368   SetStartLen(num);
    369   memcpy(_chars, s, num);
    370   _chars[num] = 0;
    371 }
    372 */
    373 
    374 AString::AString(unsigned num, const AString &s)
    375 {
    376   if (num > s._len)
    377     num = s._len;
    378   SetStartLen(num);
    379   memcpy(_chars, s._chars, num);
    380   _chars[num] = 0;
    381 }
    382 
    383 AString::AString(const AString &s, char c)
    384 {
    385   SetStartLen(s.Len() + 1);
    386   char *chars = _chars;
    387   unsigned len = s.Len();
    388   memcpy(chars, s, len);
    389   chars[len] = c;
    390   chars[len + 1] = 0;
    391 }
    392 
    393 AString::AString(const char *s1, unsigned num1, const char *s2, unsigned num2)
    394 {
    395   SetStartLen(num1 + num2);
    396   char *chars = _chars;
    397   memcpy(chars, s1, num1);
    398   memcpy(chars + num1, s2, num2 + 1);
    399 }
    400 
    401 AString operator+(const AString &s1, const AString &s2) { return AString(s1, s1.Len(), s2, s2.Len()); }
    402 AString operator+(const AString &s1, const char    *s2) { return AString(s1, s1.Len(), s2, MyStringLen(s2)); }
    403 AString operator+(const char    *s1, const AString &s2) { return AString(s1, MyStringLen(s1), s2, s2.Len()); }
    404 
    405 AString::AString()
    406 {
    407   _chars = 0;
    408   _chars = MY_STRING_NEW(char, 4);
    409   _len = 0;
    410   _limit = 4 - 1;
    411   _chars[0] = 0;
    412 }
    413 
    414 AString::AString(char c)
    415 {
    416   SetStartLen(1);
    417   _chars[0] = c;
    418   _chars[1] = 0;
    419 }
    420 
    421 AString::AString(const char *s)
    422 {
    423   SetStartLen(MyStringLen(s));
    424   MyStringCopy(_chars, s);
    425 }
    426 
    427 AString::AString(const AString &s)
    428 {
    429   SetStartLen(s._len);
    430   MyStringCopy(_chars, s._chars);
    431 }
    432 
    433 AString &AString::operator=(char c)
    434 {
    435   if (1 > _limit)
    436   {
    437     char *newBuf = MY_STRING_NEW(char, 1 + 1);
    438     MY_STRING_DELETE(_chars);
    439     _chars = newBuf;
    440     _limit = 1;
    441   }
    442   _len = 1;
    443   _chars[0] = c;
    444   _chars[1] = 0;
    445   return *this;
    446 }
    447 
    448 AString &AString::operator=(const char *s)
    449 {
    450   unsigned len = MyStringLen(s);
    451   if (len > _limit)
    452   {
    453     char *newBuf = MY_STRING_NEW(char, len + 1);
    454     MY_STRING_DELETE(_chars);
    455     _chars = newBuf;
    456     _limit = len;
    457   }
    458   _len = len;
    459   MyStringCopy(_chars, s);
    460   return *this;
    461 }
    462 
    463 AString &AString::operator=(const AString &s)
    464 {
    465   if (&s == this)
    466     return *this;
    467   unsigned len = s._len;
    468   if (len > _limit)
    469   {
    470     char *newBuf = MY_STRING_NEW(char, len + 1);
    471     MY_STRING_DELETE(_chars);
    472     _chars = newBuf;
    473     _limit = len;
    474   }
    475   _len = len;
    476   MyStringCopy(_chars, s._chars);
    477   return *this;
    478 }
    479 
    480 AString &AString::operator+=(const char *s)
    481 {
    482   unsigned len = MyStringLen(s);
    483   Grow(len);
    484   MyStringCopy(_chars + _len, s);
    485   _len += len;
    486   return *this;
    487 }
    488 
    489 AString &AString::operator+=(const AString &s)
    490 {
    491   Grow(s._len);
    492   MyStringCopy(_chars + _len, s._chars);
    493   _len += s._len;
    494   return *this;
    495 }
    496 
    497 void AString::SetFrom(const char *s, unsigned len) // no check
    498 {
    499   if (len > _limit)
    500   {
    501     char *newBuf = MY_STRING_NEW(char, len + 1);
    502     MY_STRING_DELETE(_chars);
    503     _chars = newBuf;
    504     _limit = len;
    505   }
    506   memcpy(_chars, s, len);
    507   _chars[len] = 0;
    508   _len = len;
    509 }
    510 
    511 int AString::Find(const AString &s, unsigned startIndex) const throw()
    512 {
    513   if (s.IsEmpty())
    514     return startIndex;
    515   for (; startIndex < _len; startIndex++)
    516   {
    517     unsigned j;
    518     for (j = 0; j < s._len && startIndex + j < _len; j++)
    519       if (_chars[startIndex + j] != s._chars[j])
    520         break;
    521     if (j == s._len)
    522       return (int)startIndex;
    523   }
    524   return -1;
    525 }
    526 
    527 int AString::ReverseFind(char c) const throw()
    528 {
    529   if (_len == 0)
    530     return -1;
    531   const char *p = _chars + _len - 1;
    532   for (;;)
    533   {
    534     if (*p == c)
    535       return (int)(p - _chars);
    536     if (p == _chars)
    537       return -1;
    538     p--; // p = GetPrevCharPointer(_chars, p);
    539   }
    540 }
    541 
    542 void AString::TrimLeft() throw()
    543 {
    544   const char *p = _chars;
    545   for (;; p++)
    546   {
    547     char c = *p;
    548     if (c != ' ' && c != '\n' && c != '\t')
    549       break;
    550   }
    551   unsigned pos = (unsigned)(p - _chars);
    552   if (pos != 0)
    553   {
    554     MoveItems(0, pos);
    555     _len -= pos;
    556   }
    557 }
    558 
    559 void AString::TrimRight() throw()
    560 {
    561   const char *p = _chars;
    562   int i;
    563   for (i = _len - 1; i >= 0; i--)
    564   {
    565     char c = p[i];
    566     if (c != ' ' && c != '\n' && c != '\t')
    567       break;
    568   }
    569   i++;
    570   if ((unsigned)i != _len)
    571   {
    572     _chars[i] = 0;
    573     _len = i;
    574   }
    575 }
    576 
    577 void AString::InsertAtFront(char c)
    578 {
    579   if (_limit == _len)
    580     Grow_1();
    581   MoveItems(1, 0);
    582   _chars[0] = c;
    583   _len++;
    584 }
    585 
    586 /*
    587 void AString::Insert(unsigned index, char c)
    588 {
    589   InsertSpace(index, 1);
    590   _chars[index] = c;
    591   _len++;
    592 }
    593 */
    594 
    595 void AString::Insert(unsigned index, const char *s)
    596 {
    597   unsigned num = MyStringLen(s);
    598   if (num != 0)
    599   {
    600     InsertSpace(index, num);
    601     memcpy(_chars + index, s, num);
    602     _len += num;
    603   }
    604 }
    605 
    606 void AString::Insert(unsigned index, const AString &s)
    607 {
    608   unsigned num = s.Len();
    609   if (num != 0)
    610   {
    611     InsertSpace(index, num);
    612     memcpy(_chars + index, s, num);
    613     _len += num;
    614   }
    615 }
    616 
    617 void AString::RemoveChar(char ch) throw()
    618 {
    619   int pos = Find(ch);
    620   if (pos < 0)
    621     return;
    622   const char *src = _chars;
    623   char *dest = _chars + pos;
    624   pos++;
    625   unsigned len = _len;
    626   for (; (unsigned)pos < len; pos++)
    627   {
    628     char c = src[(unsigned)pos];
    629     if (c != ch)
    630       *dest++ = c;
    631   }
    632   *dest = 0;
    633   _len = (unsigned)(dest - _chars);
    634 }
    635 
    636 // !!!!!!!!!!!!!!! test it if newChar = '\0'
    637 void AString::Replace(char oldChar, char newChar) throw()
    638 {
    639   if (oldChar == newChar)
    640     return; // 0;
    641   // unsigned number = 0;
    642   int pos = 0;
    643   while ((unsigned)pos < _len)
    644   {
    645     pos = Find(oldChar, pos);
    646     if (pos < 0)
    647       break;
    648     _chars[pos] = newChar;
    649     pos++;
    650     // number++;
    651   }
    652   return; //  number;
    653 }
    654 
    655 void AString::Replace(const AString &oldString, const AString &newString)
    656 {
    657   if (oldString.IsEmpty())
    658     return; // 0;
    659   if (oldString == newString)
    660     return; // 0;
    661   unsigned oldLen = oldString.Len();
    662   unsigned newLen = newString.Len();
    663   // unsigned number = 0;
    664   int pos = 0;
    665   while ((unsigned)pos < _len)
    666   {
    667     pos = Find(oldString, pos);
    668     if (pos < 0)
    669       break;
    670     Delete(pos, oldLen);
    671     Insert(pos, newString);
    672     pos += newLen;
    673     // number++;
    674   }
    675   // return number;
    676 }
    677 
    678 void AString::Delete(unsigned index) throw()
    679 {
    680   MoveItems(index, index + 1);
    681   _len--;
    682 }
    683 
    684 void AString::Delete(unsigned index, unsigned count) throw()
    685 {
    686   if (index + count > _len)
    687     count = _len - index;
    688   if (count > 0)
    689   {
    690     MoveItems(index, index + count);
    691     _len -= count;
    692   }
    693 }
    694 
    695 void AString::DeleteFrontal(unsigned num) throw()
    696 {
    697   if (num != 0)
    698   {
    699     MoveItems(0, num);
    700     _len -= num;
    701   }
    702 }
    703 
    704 /*
    705 AString operator+(const AString &s1, const AString &s2)
    706 {
    707   AString result(s1);
    708   result += s2;
    709   return result;
    710 }
    711 
    712 AString operator+(const AString &s, const char *chars)
    713 {
    714   AString result(s);
    715   result += chars;
    716   return result;
    717 }
    718 
    719 AString operator+(const char *chars, const AString &s)
    720 {
    721   AString result(chars);
    722   result += s;
    723   return result;
    724 }
    725 
    726 AString operator+(const AString &s, char c)
    727 {
    728   AString result(s);
    729   result += c;
    730   return result;
    731 }
    732 */
    733 
    734 /*
    735 AString operator+(char c, const AString &s)
    736 {
    737   AString result(c);
    738   result += s;
    739   return result;
    740 }
    741 */
    742 
    743 
    744 
    745 
    746 // ---------- UString ----------
    747 
    748 void UString::InsertSpace(unsigned index, unsigned size)
    749 {
    750   Grow(size);
    751   MoveItems(index + size, index);
    752 }
    753 
    754 void UString::ReAlloc(unsigned newLimit)
    755 {
    756   if (newLimit < _len || newLimit >= 0x20000000) throw 20130221;
    757   // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, _len + 1);
    758   wchar_t *newBuf = MY_STRING_NEW(wchar_t, newLimit + 1);
    759   wmemcpy(newBuf, _chars, _len + 1);
    760   MY_STRING_DELETE(_chars);
    761   _chars = newBuf;
    762 
    763   _limit = newLimit;
    764 }
    765 
    766 void UString::SetStartLen(unsigned len)
    767 {
    768   _chars = 0;
    769   _chars = MY_STRING_NEW(wchar_t, len + 1);
    770   _len = len;
    771   _limit = len;
    772 }
    773 
    774 void UString::Grow_1()
    775 {
    776   unsigned next = _len;
    777   next += next / 2;
    778   next += 16;
    779   next &= ~(unsigned)15;
    780   ReAlloc(next - 1);
    781 }
    782 
    783 void UString::Grow(unsigned n)
    784 {
    785   unsigned freeSize = _limit - _len;
    786   if (n <= freeSize)
    787     return;
    788 
    789   unsigned next = _len + n;
    790   next += next / 2;
    791   next += 16;
    792   next &= ~(unsigned)15;
    793   ReAlloc(next - 1);
    794 }
    795 
    796 
    797 UString::UString(unsigned num, const wchar_t *s)
    798 {
    799   unsigned len = MyStringLen(s);
    800   if (num > len)
    801     num = len;
    802   SetStartLen(num);
    803   wmemcpy(_chars, s, num);
    804   _chars[num] = 0;
    805 }
    806 
    807 
    808 UString::UString(unsigned num, const UString &s)
    809 {
    810   if (num > s._len)
    811     num = s._len;
    812   SetStartLen(num);
    813   wmemcpy(_chars, s._chars, num);
    814   _chars[num] = 0;
    815 }
    816 
    817 UString::UString(const UString &s, wchar_t c)
    818 {
    819   SetStartLen(s.Len() + 1);
    820   wchar_t *chars = _chars;
    821   unsigned len = s.Len();
    822   wmemcpy(chars, s, len);
    823   chars[len] = c;
    824   chars[len + 1] = 0;
    825 }
    826 
    827 UString::UString(const wchar_t *s1, unsigned num1, const wchar_t *s2, unsigned num2)
    828 {
    829   SetStartLen(num1 + num2);
    830   wchar_t *chars = _chars;
    831   wmemcpy(chars, s1, num1);
    832   wmemcpy(chars + num1, s2, num2 + 1);
    833 }
    834 
    835 UString operator+(const UString &s1, const UString &s2) { return UString(s1, s1.Len(), s2, s2.Len()); }
    836 UString operator+(const UString &s1, const wchar_t *s2) { return UString(s1, s1.Len(), s2, MyStringLen(s2)); }
    837 UString operator+(const wchar_t *s1, const UString &s2) { return UString(s1, MyStringLen(s1), s2, s2.Len()); }
    838 
    839 UString::UString()
    840 {
    841   _chars = 0;
    842   _chars = MY_STRING_NEW(wchar_t, 4);
    843   _len = 0;
    844   _limit = 4 - 1;
    845   _chars[0] = 0;
    846 }
    847 
    848 UString::UString(wchar_t c)
    849 {
    850   SetStartLen(1);
    851   _chars[0] = c;
    852   _chars[1] = 0;
    853 }
    854 
    855 UString::UString(const wchar_t *s)
    856 {
    857   SetStartLen(MyStringLen(s));
    858   MyStringCopy(_chars, s);
    859 }
    860 
    861 UString::UString(const UString &s)
    862 {
    863   SetStartLen(s._len);
    864   MyStringCopy(_chars, s._chars);
    865 }
    866 
    867 UString &UString::operator=(wchar_t c)
    868 {
    869   if (1 > _limit)
    870   {
    871     wchar_t *newBuf = MY_STRING_NEW(wchar_t, 1 + 1);
    872     MY_STRING_DELETE(_chars);
    873     _chars = newBuf;
    874     _limit = 1;
    875   }
    876   _len = 1;
    877   _chars[0] = c;
    878   _chars[1] = 0;
    879   return *this;
    880 }
    881 
    882 UString &UString::operator=(const wchar_t *s)
    883 {
    884   unsigned len = MyStringLen(s);
    885   if (len > _limit)
    886   {
    887     wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
    888     MY_STRING_DELETE(_chars);
    889     _chars = newBuf;
    890     _limit = len;
    891   }
    892   _len = len;
    893   MyStringCopy(_chars, s);
    894   return *this;
    895 }
    896 
    897 UString &UString::operator=(const UString &s)
    898 {
    899   if (&s == this)
    900     return *this;
    901   unsigned len = s._len;
    902   if (len > _limit)
    903   {
    904     wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
    905     MY_STRING_DELETE(_chars);
    906     _chars = newBuf;
    907     _limit = len;
    908   }
    909   _len = len;
    910   MyStringCopy(_chars, s._chars);
    911   return *this;
    912 }
    913 
    914 UString &UString::operator+=(const wchar_t *s)
    915 {
    916   unsigned len = MyStringLen(s);
    917   Grow(len);
    918   MyStringCopy(_chars + _len, s);
    919   _len += len;
    920   return *this;
    921 }
    922 
    923 UString &UString::operator+=(const UString &s)
    924 {
    925   Grow(s._len);
    926   MyStringCopy(_chars + _len, s._chars);
    927   _len += s._len;
    928   return *this;
    929 }
    930 
    931 void UString::SetFrom(const wchar_t *s, unsigned len) // no check
    932 {
    933   if (len > _limit)
    934   {
    935     wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
    936     MY_STRING_DELETE(_chars);
    937     _chars = newBuf;
    938     _limit = len;
    939   }
    940   wmemcpy(_chars, s, len);
    941   _chars[len] = 0;
    942   _len = len;
    943 }
    944 
    945 void UString::SetFromAscii(const char *s)
    946 {
    947   unsigned len = MyStringLen(s);
    948   if (len > _limit)
    949   {
    950     wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
    951     MY_STRING_DELETE(_chars);
    952     _chars = newBuf;
    953     _limit = len;
    954   }
    955   wchar_t *chars = _chars;
    956   for (unsigned i = 0; i < len; i++)
    957     chars[i] = s[i];
    958   chars[len] = 0;
    959   _len = len;
    960 }
    961 
    962 void UString::AddAsciiStr(const char *s)
    963 {
    964   unsigned len = MyStringLen(s);
    965   Grow(len);
    966   wchar_t *chars = _chars + _len;
    967   for (unsigned i = 0; i < len; i++)
    968     chars[i] = s[i];
    969   chars[len] = 0;
    970   _len += len;
    971 }
    972 
    973 
    974 
    975 int UString::Find(const UString &s, unsigned startIndex) const throw()
    976 {
    977   if (s.IsEmpty())
    978     return startIndex;
    979   for (; startIndex < _len; startIndex++)
    980   {
    981     unsigned j;
    982     for (j = 0; j < s._len && startIndex + j < _len; j++)
    983       if (_chars[startIndex + j] != s._chars[j])
    984         break;
    985     if (j == s._len)
    986       return (int)startIndex;
    987   }
    988   return -1;
    989 }
    990 
    991 int UString::ReverseFind(wchar_t c) const throw()
    992 {
    993   if (_len == 0)
    994     return -1;
    995   const wchar_t *p = _chars + _len - 1;
    996   for (;;)
    997   {
    998     if (*p == c)
    999       return (int)(p - _chars);
   1000     if (p == _chars)
   1001       return -1;
   1002     p--;
   1003   }
   1004 }
   1005 
   1006 void UString::TrimLeft() throw()
   1007 {
   1008   const wchar_t *p = _chars;
   1009   for (;; p++)
   1010   {
   1011     wchar_t c = *p;
   1012     if (c != ' ' && c != '\n' && c != '\t')
   1013       break;
   1014   }
   1015   unsigned pos = (unsigned)(p - _chars);
   1016   if (pos != 0)
   1017   {
   1018     MoveItems(0, pos);
   1019     _len -= pos;
   1020   }
   1021 }
   1022 
   1023 void UString::TrimRight() throw()
   1024 {
   1025   const wchar_t *p = _chars;
   1026   int i;
   1027   for (i = _len - 1; i >= 0; i--)
   1028   {
   1029     wchar_t c = p[i];
   1030     if (c != ' ' && c != '\n' && c != '\t')
   1031       break;
   1032   }
   1033   i++;
   1034   if ((unsigned)i != _len)
   1035   {
   1036     _chars[i] = 0;
   1037     _len = i;
   1038   }
   1039 }
   1040 
   1041 void UString::InsertAtFront(wchar_t c)
   1042 {
   1043   if (_limit == _len)
   1044     Grow_1();
   1045   MoveItems(1, 0);
   1046   _chars[0] = c;
   1047   _len++;
   1048 }
   1049 
   1050 /*
   1051 void UString::Insert(unsigned index, wchar_t c)
   1052 {
   1053   InsertSpace(index, 1);
   1054   _chars[index] = c;
   1055   _len++;
   1056 }
   1057 */
   1058 
   1059 void UString::Insert(unsigned index, const wchar_t *s)
   1060 {
   1061   unsigned num = MyStringLen(s);
   1062   if (num != 0)
   1063   {
   1064     InsertSpace(index, num);
   1065     wmemcpy(_chars + index, s, num);
   1066     _len += num;
   1067   }
   1068 }
   1069 
   1070 void UString::Insert(unsigned index, const UString &s)
   1071 {
   1072   unsigned num = s.Len();
   1073   if (num != 0)
   1074   {
   1075     InsertSpace(index, num);
   1076     wmemcpy(_chars + index, s, num);
   1077     _len += num;
   1078   }
   1079 }
   1080 
   1081 void UString::RemoveChar(wchar_t ch) throw()
   1082 {
   1083   int pos = Find(ch);
   1084   if (pos < 0)
   1085     return;
   1086   const wchar_t *src = _chars;
   1087   wchar_t *dest = _chars + pos;
   1088   pos++;
   1089   unsigned len = _len;
   1090   for (; (unsigned)pos < len; pos++)
   1091   {
   1092     wchar_t c = src[(unsigned)pos];
   1093     if (c != ch)
   1094       *dest++ = c;
   1095   }
   1096   *dest = 0;
   1097   _len = (unsigned)(dest - _chars);
   1098 }
   1099 
   1100 // !!!!!!!!!!!!!!! test it if newChar = '\0'
   1101 void UString::Replace(wchar_t oldChar, wchar_t newChar) throw()
   1102 {
   1103   if (oldChar == newChar)
   1104     return; // 0;
   1105   // unsigned number = 0;
   1106   int pos = 0;
   1107   while ((unsigned)pos < _len)
   1108   {
   1109     pos = Find(oldChar, pos);
   1110     if (pos < 0)
   1111       break;
   1112     _chars[pos] = newChar;
   1113     pos++;
   1114     // number++;
   1115   }
   1116   return; //  number;
   1117 }
   1118 
   1119 void UString::Replace(const UString &oldString, const UString &newString)
   1120 {
   1121   if (oldString.IsEmpty())
   1122     return; // 0;
   1123   if (oldString == newString)
   1124     return; // 0;
   1125   unsigned oldLen = oldString.Len();
   1126   unsigned newLen = newString.Len();
   1127   // unsigned number = 0;
   1128   int pos = 0;
   1129   while ((unsigned)pos < _len)
   1130   {
   1131     pos = Find(oldString, pos);
   1132     if (pos < 0)
   1133       break;
   1134     Delete(pos, oldLen);
   1135     Insert(pos, newString);
   1136     pos += newLen;
   1137     // number++;
   1138   }
   1139   // return number;
   1140 }
   1141 
   1142 void UString::Delete(unsigned index) throw()
   1143 {
   1144   MoveItems(index, index + 1);
   1145   _len--;
   1146 }
   1147 
   1148 void UString::Delete(unsigned index, unsigned count) throw()
   1149 {
   1150   if (index + count > _len)
   1151     count = _len - index;
   1152   if (count > 0)
   1153   {
   1154     MoveItems(index, index + count);
   1155     _len -= count;
   1156   }
   1157 }
   1158 
   1159 void UString::DeleteFrontal(unsigned num) throw()
   1160 {
   1161   if (num != 0)
   1162   {
   1163     MoveItems(0, num);
   1164     _len -= num;
   1165   }
   1166 }
   1167 
   1168 
   1169 // ----------------------------------------
   1170 
   1171 /*
   1172 int MyStringCompareNoCase(const char *s1, const char *s2)
   1173 {
   1174   return MyStringCompareNoCase(MultiByteToUnicodeString(s1), MultiByteToUnicodeString(s2));
   1175 }
   1176 */
   1177 
   1178 static inline UINT GetCurrentCodePage()
   1179 {
   1180   #if defined(UNDER_CE) || !defined(_WIN32)
   1181   return CP_ACP;
   1182   #else
   1183   return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP;
   1184   #endif
   1185 }
   1186 
   1187 #ifdef USE_UNICODE_FSTRING
   1188 
   1189 #ifndef _UNICODE
   1190 
   1191 AString fs2fas(CFSTR s)
   1192 {
   1193   return UnicodeStringToMultiByte(s, GetCurrentCodePage());
   1194 }
   1195 
   1196 FString fas2fs(const AString &s)
   1197 {
   1198   return MultiByteToUnicodeString(s, GetCurrentCodePage());
   1199 }
   1200 
   1201 #endif
   1202 
   1203 #else
   1204 
   1205 UString fs2us(const FString &s)
   1206 {
   1207   return MultiByteToUnicodeString((AString)s, GetCurrentCodePage());
   1208 }
   1209 
   1210 FString us2fs(const wchar_t *s)
   1211 {
   1212   return UnicodeStringToMultiByte(s, GetCurrentCodePage());
   1213 }
   1214 
   1215 #endif
   1216