// Common/MyString.cpp

#include "StdAfx.h"

#include <ctype.h>

#if !defined(_UNICODE) || !defined(USE_UNICODE_FSTRING)
#include "StringConvert.h"
#endif

#include "MyString.h"

#define MY_STRING_NEW(_T_, _size_) new _T_[_size_]


int FindCharPosInString(const char *s, char c) throw()
{
  for (const char *p = s;; p++)
  {
    if (*p == c)
      return (int)(p - s);
    if (*p == 0)
      return -1;
  }
}

int FindCharPosInString(const wchar_t *s, wchar_t c) throw()
{
  for (const wchar_t *p = s;; p++)
  {
    if (*p == c)
      return (int)(p - s);
    if (*p == 0)
      return -1;
  }
}

void MyStringLower_Ascii(char *s) throw()
{
  for (;;)
  {
    char c = *s;
    if (c == 0)
      return;
    *s++ = MyCharLower_Ascii(c);
  }
}

void MyStringLower_Ascii(wchar_t *s) throw()
{
  for (;;)
  {
    wchar_t c = *s;
    if (c == 0)
      return;
    *s++ = MyCharLower_Ascii(c);
  }
}

bool IsString1PrefixedByString2(const char *s1, const char *s2) throw()
{
  for (;;)
  {
    unsigned char c2 = (unsigned char)*s2++; if (c2 == 0) return true;
    unsigned char c1 = (unsigned char)*s1++; if (c1 != c2) return false;
  }
}

bool StringsAreEqualNoCase(const wchar_t *s1, const wchar_t *s2) throw()
{
  for (;;)
  {
    wchar_t c1 = *s1++;
    wchar_t c2 = *s2++;
    if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2)) return false;
    if (c1 == 0) return true;
  }
}

// ---------- ASCII ----------

bool AString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw()
{
  const char *s1 = _chars;
  for (;;)
  {
    char c2 = *s++;
    if (c2 == 0)
      return true;
    char c1 = *s1++;
    if (MyCharLower_Ascii(c1) !=
        MyCharLower_Ascii(c2))
      return false;
  }
}

bool UString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw()
{
  const wchar_t *s1 = _chars;
  for (;;)
  {
    char c2 = *s++;
    if (c2 == 0)
      return true;
    wchar_t c1 = *s1++;
    if (MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2))
      return false;
  }
}

bool StringsAreEqual_Ascii(const wchar_t *u, const char *a) throw()
{
  for (;;)
  {
    unsigned char c = *a;
    if (c != *u)
      return false;
    if (c == 0)
      return true;
    a++;
    u++;
  }
}

bool StringsAreEqualNoCase_Ascii(const char *s1, const char *s2) throw()
{
  for (;;)
  {
    char c1 = *s1++;
    char c2 = *s2++;
    if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2))
      return false;
    if (c1 == 0)
      return true;
  }
}

bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const wchar_t *s2) throw()
{
  for (;;)
  {
    wchar_t c1 = *s1++;
    wchar_t c2 = *s2++;
    if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2))
      return false;
    if (c1 == 0)
      return true;
  }
}

bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const char *s2) throw()
{
  for (;;)
  {
    wchar_t c1 = *s1++;
    char c2 = *s2++;
    if (c1 != (unsigned char)c2 && (c1 > 0x7F || MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2)))
      return false;
    if (c1 == 0)
      return true;
  }
}

bool IsString1PrefixedByString2(const wchar_t *s1, const wchar_t *s2) throw()
{
  for (;;)
  {
    wchar_t c2 = *s2++; if (c2 == 0) return true;
    wchar_t c1 = *s1++; if (c1 != c2) return false;
  }
}

bool IsString1PrefixedByString2_NoCase(const wchar_t *s1, const wchar_t *s2) throw()
{
  for (;;)
  {
    wchar_t c2 = *s2++; if (c2 == 0) return true;
    wchar_t c1 = *s1++;
    if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2))
      return false;
  }
}

// NTFS order: uses upper case
int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2) throw()
{
  for (;;)
  {
    wchar_t c1 = *s1++;
    wchar_t c2 = *s2++;
    if (c1 != c2)
    {
      wchar_t u1 = MyCharUpper(c1);
      wchar_t u2 = MyCharUpper(c2);
      if (u1 < u2) return -1;
      if (u1 > u2) return 1;
    }
    if (c1 == 0) return 0;
  }
}

// ---------- AString ----------

void AString::InsertSpace(unsigned &index, unsigned size)
{
  Grow(size);
  MoveItems(index + size, index);
}

#define k_Alloc_Len_Limit 0x40000000

void AString::ReAlloc(unsigned newLimit)
{
  if (newLimit < _len || newLimit >= k_Alloc_Len_Limit) throw 20130220;
  char *newBuf = MY_STRING_NEW(char, newLimit + 1);
  memcpy(newBuf, _chars, (size_t)(_len + 1)); \
  MY_STRING_DELETE(_chars);
  _chars = newBuf;
  _limit = newLimit;
}

void AString::ReAlloc2(unsigned newLimit)
{
  if (newLimit >= k_Alloc_Len_Limit) throw 20130220;
  char *newBuf = MY_STRING_NEW(char, newLimit + 1);
  newBuf[0] = 0;
  MY_STRING_DELETE(_chars);
  _chars = newBuf;
  _limit = newLimit;
}

void AString::SetStartLen(unsigned len)
{
  _chars = 0;
  _chars = MY_STRING_NEW(char, len + 1);
  _len = len;
  _limit = len;
}

void AString::Grow_1()
{
  unsigned next = _len;
  next += next / 2;
  next += 16;
  next &= ~(unsigned)15;
  ReAlloc(next - 1);
}

void AString::Grow(unsigned n)
{
  unsigned freeSize = _limit - _len;
  if (n <= freeSize)
    return;

  unsigned next = _len + n;
  next += next / 2;
  next += 16;
  next &= ~(unsigned)15;
  ReAlloc(next - 1);
}

AString::AString(unsigned num, const AString &s)
{
  if (num > s._len)
    num = s._len;
  SetStartLen(num);
  memcpy(_chars, s._chars, num);
  _chars[num] = 0;
}

AString::AString(const AString &s, char c)
{
  SetStartLen(s.Len() + 1);
  char *chars = _chars;
  unsigned len = s.Len();
  memcpy(chars, s, len);
  chars[len] = c;
  chars[len + 1] = 0;
}

AString::AString(const char *s1, unsigned num1, const char *s2, unsigned num2)
{
  SetStartLen(num1 + num2);
  char *chars = _chars;
  memcpy(chars, s1, num1);
  memcpy(chars + num1, s2, num2 + 1);
}

AString operator+(const AString &s1, const AString &s2) { return AString(s1, s1.Len(), s2, s2.Len()); }
AString operator+(const AString &s1, const char    *s2) { return AString(s1, s1.Len(), s2, MyStringLen(s2)); }
AString operator+(const char    *s1, const AString &s2) { return AString(s1, MyStringLen(s1), s2, s2.Len()); }

AString::AString()
{
  _chars = 0;
  _chars = MY_STRING_NEW(char, 4);
  _len = 0;
  _limit = 4 - 1;
  _chars[0] = 0;
}

AString::AString(char c)
{
  SetStartLen(1);
  _chars[0] = c;
  _chars[1] = 0;
}

AString::AString(const char *s)
{
  SetStartLen(MyStringLen(s));
  MyStringCopy(_chars, s);
}

AString::AString(const AString &s)
{
  SetStartLen(s._len);
  MyStringCopy(_chars, s._chars);
}

AString &AString::operator=(char c)
{
  if (1 > _limit)
  {
    char *newBuf = MY_STRING_NEW(char, 1 + 1);
    MY_STRING_DELETE(_chars);
    _chars = newBuf;
    _limit = 1;
  }
  _len = 1;
  _chars[0] = c;
  _chars[1] = 0;
  return *this;
}

AString &AString::operator=(const char *s)
{
  unsigned len = MyStringLen(s);
  if (len > _limit)
  {
    char *newBuf = MY_STRING_NEW(char, len + 1);
    MY_STRING_DELETE(_chars);
    _chars = newBuf;
    _limit = len;
  }
  _len = len;
  MyStringCopy(_chars, s);
  return *this;
}

AString &AString::operator=(const AString &s)
{
  if (&s == this)
    return *this;
  unsigned len = s._len;
  if (len > _limit)
  {
    char *newBuf = MY_STRING_NEW(char, len + 1);
    MY_STRING_DELETE(_chars);
    _chars = newBuf;
    _limit = len;
  }
  _len = len;
  MyStringCopy(_chars, s._chars);
  return *this;
}

void AString::SetFromWStr_if_Ascii(const wchar_t *s)
{
  unsigned len = 0;
  {
    for (;; len++)
    {
      wchar_t c = s[len];
      if (c == 0)
        break;
      if (c >= 0x80)
        return;
    }
  }
  if (len > _limit)
  {
    char *newBuf = MY_STRING_NEW(char, len + 1);
    MY_STRING_DELETE(_chars);
    _chars = newBuf;
    _limit = len;
  }
  _len = len;
  char *dest = _chars;
  unsigned i;
  for (i = 0; i < len; i++)
    dest[i] = (char)s[i];
  dest[i] = 0;
}

void AString::Add_Space() { operator+=(' '); }
void AString::Add_Space_if_NotEmpty() { if (!IsEmpty()) Add_Space(); }
void AString::Add_LF() { operator+=('\n'); }

AString &AString::operator+=(const char *s)
{
  unsigned len = MyStringLen(s);
  Grow(len);
  MyStringCopy(_chars + _len, s);
  _len += len;
  return *this;
}

AString &AString::operator+=(const AString &s)
{
  Grow(s._len);
  MyStringCopy(_chars + _len, s._chars);
  _len += s._len;
  return *this;
}

void AString::SetFrom(const char *s, unsigned len) // no check
{
  if (len > _limit)
  {
    char *newBuf = MY_STRING_NEW(char, len + 1);
    MY_STRING_DELETE(_chars);
    _chars = newBuf;
    _limit = len;
  }
  if (len != 0)
    memcpy(_chars, s, len);
  _chars[len] = 0;
  _len = len;
}

void AString::SetFrom_CalcLen(const char *s, unsigned len) // no check
{
  unsigned i;
  for (i = 0; i < len; i++)
    if (s[i] == 0)
      break;
  SetFrom(s, i);
}

int AString::Find(const char *s, unsigned startIndex) const throw()
{
  const char *fs = strstr(_chars + startIndex, s);
  if (!fs)
    return -1;
  return (int)(fs - _chars);
}

int AString::ReverseFind(char c) const throw()
{
  if (_len == 0)
    return -1;
  const char *p = _chars + _len - 1;
  for (;;)
  {
    if (*p == c)
      return (int)(p - _chars);
    if (p == _chars)
      return -1;
    p--; // p = GetPrevCharPointer(_chars, p);
  }
}

int AString::ReverseFind_PathSepar() const throw()
{
  if (_len == 0)
    return -1;
  const char *p = _chars + _len - 1;
  for (;;)
  {
    char c = *p;
    if (IS_PATH_SEPAR(c))
      return (int)(p - _chars);
    if (p == _chars)
      return -1;
    p--;
  }
}

void AString::TrimLeft() throw()
{
  const char *p = _chars;
  for (;; p++)
  {
    char c = *p;
    if (c != ' ' && c != '\n' && c != '\t')
      break;
  }
  unsigned pos = (unsigned)(p - _chars);
  if (pos != 0)
  {
    MoveItems(0, pos);
    _len -= pos;
  }
}

void AString::TrimRight() throw()
{
  const char *p = _chars;
  unsigned i;
  for (i = _len; i != 0; i--)
  {
    char c = p[i - 1];
    if (c != ' ' && c != '\n' && c != '\t')
      break;
  }
  if (i != _len)
  {
    _chars[i] = 0;
    _len = i;
  }
}

void AString::InsertAtFront(char c)
{
  if (_limit == _len)
    Grow_1();
  MoveItems(1, 0);
  _chars[0] = c;
  _len++;
}

void AString::Insert(unsigned index, const char *s)
{
  unsigned num = MyStringLen(s);
  if (num != 0)
  {
    InsertSpace(index, num);
    memcpy(_chars + index, s, num);
    _len += num;
  }
}

void AString::Insert(unsigned index, const AString &s)
{
  unsigned num = s.Len();
  if (num != 0)
  {
    InsertSpace(index, num);
    memcpy(_chars + index, s, num);
    _len += num;
  }
}

void AString::RemoveChar(char ch) throw()
{
  char *src = _chars;

  for (;;)
  {
    char c = *src++;
    if (c == 0)
      return;
    if (c == ch)
      break;
  }

  char *dest = src - 1;

  for (;;)
  {
    char c = *src++;
    if (c == 0)
      break;
    if (c != ch)
      *dest++ = c;
  }

  *dest = 0;
  _len = (unsigned)(dest - _chars);
}

// !!!!!!!!!!!!!!! test it if newChar = '\0'
void AString::Replace(char oldChar, char newChar) throw()
{
  if (oldChar == newChar)
    return; // 0;
  int pos = 0;
  while ((unsigned)pos < _len)
  {
    pos = Find(oldChar, pos);
    if (pos < 0)
      break;
    _chars[(unsigned)pos] = newChar;
    pos++;
  }
}

void AString::Replace(const AString &oldString, const AString &newString)
{
  if (oldString.IsEmpty())
    return; // 0;
  if (oldString == newString)
    return; // 0;
  unsigned oldLen = oldString.Len();
  unsigned newLen = newString.Len();
  int pos = 0;
  while ((unsigned)pos < _len)
  {
    pos = Find(oldString, pos);
    if (pos < 0)
      break;
    Delete(pos, oldLen);
    Insert(pos, newString);
    pos += newLen;
  }
}

void AString::Delete(unsigned index) throw()
{
  MoveItems(index, index + 1);
  _len--;
}

void AString::Delete(unsigned index, unsigned count) throw()
{
  if (index + count > _len)
    count = _len - index;
  if (count > 0)
  {
    MoveItems(index, index + count);
    _len -= count;
  }
}

void AString::DeleteFrontal(unsigned num) throw()
{
  if (num != 0)
  {
    MoveItems(0, num);
    _len -= num;
  }
}

// ---------- UString ----------

void UString::InsertSpace(unsigned index, unsigned size)
{
  Grow(size);
  MoveItems(index + size, index);
}

void UString::ReAlloc(unsigned newLimit)
{
  if (newLimit < _len || newLimit >= k_Alloc_Len_Limit) throw 20130221;
  wchar_t *newBuf = MY_STRING_NEW(wchar_t, newLimit + 1);
  wmemcpy(newBuf, _chars, _len + 1);
  MY_STRING_DELETE(_chars);
  _chars = newBuf;
  _limit = newLimit;
}

void UString::ReAlloc2(unsigned newLimit)
{
  if (newLimit >= k_Alloc_Len_Limit) throw 20130221;
  wchar_t *newBuf = MY_STRING_NEW(wchar_t, newLimit + 1);
  newBuf[0] = 0;
  MY_STRING_DELETE(_chars);
  _chars = newBuf;
  _limit = newLimit;
}

void UString::SetStartLen(unsigned len)
{
  _chars = 0;
  _chars = MY_STRING_NEW(wchar_t, len + 1);
  _len = len;
  _limit = len;
}

void UString::Grow_1()
{
  unsigned next = _len;
  next += next / 2;
  next += 16;
  next &= ~(unsigned)15;
  ReAlloc(next - 1);
}

void UString::Grow(unsigned n)
{
  unsigned freeSize = _limit - _len;
  if (n <= freeSize)
    return;

  unsigned next = _len + n;
  next += next / 2;
  next += 16;
  next &= ~(unsigned)15;
  ReAlloc(next - 1);
}


UString::UString(unsigned num, const wchar_t *s)
{
  unsigned len = MyStringLen(s);
  if (num > len)
    num = len;
  SetStartLen(num);
  wmemcpy(_chars, s, num);
  _chars[num] = 0;
}


UString::UString(unsigned num, const UString &s)
{
  if (num > s._len)
    num = s._len;
  SetStartLen(num);
  wmemcpy(_chars, s._chars, num);
  _chars[num] = 0;
}

UString::UString(const UString &s, wchar_t c)
{
  SetStartLen(s.Len() + 1);
  wchar_t *chars = _chars;
  unsigned len = s.Len();
  wmemcpy(chars, s, len);
  chars[len] = c;
  chars[len + 1] = 0;
}

UString::UString(const wchar_t *s1, unsigned num1, const wchar_t *s2, unsigned num2)
{
  SetStartLen(num1 + num2);
  wchar_t *chars = _chars;
  wmemcpy(chars, s1, num1);
  wmemcpy(chars + num1, s2, num2 + 1);
}

UString operator+(const UString &s1, const UString &s2) { return UString(s1, s1.Len(), s2, s2.Len()); }
UString operator+(const UString &s1, const wchar_t *s2) { return UString(s1, s1.Len(), s2, MyStringLen(s2)); }
UString operator+(const wchar_t *s1, const UString &s2) { return UString(s1, MyStringLen(s1), s2, s2.Len()); }

UString::UString()
{
  _chars = 0;
  _chars = MY_STRING_NEW(wchar_t, 4);
  _len = 0;
  _limit = 4 - 1;
  _chars[0] = 0;
}

UString::UString(wchar_t c)
{
  SetStartLen(1);
  _chars[0] = c;
  _chars[1] = 0;
}

UString::UString(const wchar_t *s)
{
  unsigned len = MyStringLen(s);
  SetStartLen(len);
  wmemcpy(_chars, s, len + 1);
}

UString::UString(const UString &s)
{
  SetStartLen(s._len);
  wmemcpy(_chars, s._chars, s._len + 1);
}

UString &UString::operator=(wchar_t c)
{
  if (1 > _limit)
  {
    wchar_t *newBuf = MY_STRING_NEW(wchar_t, 1 + 1);
    MY_STRING_DELETE(_chars);
    _chars = newBuf;
    _limit = 1;
  }
  _len = 1;
  _chars[0] = c;
  _chars[1] = 0;
  return *this;
}

UString &UString::operator=(const wchar_t *s)
{
  unsigned len = MyStringLen(s);
  if (len > _limit)
  {
    wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
    MY_STRING_DELETE(_chars);
    _chars = newBuf;
    _limit = len;
  }
  _len = len;
  wmemcpy(_chars, s, len + 1);
  return *this;
}

UString &UString::operator=(const UString &s)
{
  if (&s == this)
    return *this;
  unsigned len = s._len;
  if (len > _limit)
  {
    wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
    MY_STRING_DELETE(_chars);
    _chars = newBuf;
    _limit = len;
  }
  _len = len;
  wmemcpy(_chars, s._chars, len + 1);
  return *this;
}

void UString::SetFromBstr(BSTR s)
{
  unsigned len = ::SysStringLen(s);
  if (len > _limit)
  {
    wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
    MY_STRING_DELETE(_chars);
    _chars = newBuf;
    _limit = len;
  }
  _len = len;
  wmemcpy(_chars, s, len + 1);
}

void UString::Add_Space() { operator+=(L' '); }
void UString::Add_Space_if_NotEmpty() { if (!IsEmpty()) Add_Space(); }

void UString::Add_LF()
{
  if (_limit == _len)
    Grow_1();
  unsigned len = _len;
  wchar_t *chars = _chars;
  chars[len++] = L'\n';
  chars[len] = 0;
  _len = len;
}

UString &UString::operator+=(const wchar_t *s)
{
  unsigned len = MyStringLen(s);
  Grow(len);
  wmemcpy(_chars + _len, s, len + 1);
  _len += len;
  return *this;
}

UString &UString::operator+=(const UString &s)
{
  Grow(s._len);
  wmemcpy(_chars + _len, s._chars, s._len + 1);
  _len += s._len;
  return *this;
}

void UString::SetFrom(const wchar_t *s, unsigned len) // no check
{
  if (len > _limit)
  {
    wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
    MY_STRING_DELETE(_chars);
    _chars = newBuf;
    _limit = len;
  }
  if (len != 0)
    wmemcpy(_chars, s, len);
  _chars[len] = 0;
  _len = len;
}

void UString::SetFromAscii(const char *s)
{
  unsigned len = MyStringLen(s);
  if (len > _limit)
  {
    wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
    MY_STRING_DELETE(_chars);
    _chars = newBuf;
    _limit = len;
  }
  wchar_t *chars = _chars;
  for (unsigned i = 0; i < len; i++)
    chars[i] = (unsigned char)s[i];
  chars[len] = 0;
  _len = len;
}

void UString::AddAscii(const char *s)
{
  unsigned len = MyStringLen(s);
  Grow(len);
  wchar_t *chars = _chars + _len;
  for (unsigned i = 0; i < len; i++)
    chars[i] = (unsigned char)s[i];
  chars[len] = 0;
  _len += len;
}



int UString::Find(const wchar_t *s, unsigned startIndex) const throw()
{
  const wchar_t *fs = wcsstr(_chars + startIndex, s);
  if (!fs)
    return -1;
  return (int)(fs - _chars);
}

int UString::ReverseFind(wchar_t c) const throw()
{
  if (_len == 0)
    return -1;
  const wchar_t *p = _chars + _len - 1;
  for (;;)
  {
    if (*p == c)
      return (int)(p - _chars);
    if (p == _chars)
      return -1;
    p--;
  }
}

int UString::ReverseFind_PathSepar() const throw()
{
  if (_len == 0)
    return -1;
  const wchar_t *p = _chars + _len - 1;
  for (;;)
  {
    wchar_t c = *p;
    if (IS_PATH_SEPAR(c))
      return (int)(p - _chars);
    if (p == _chars)
      return -1;
    p--;
  }
}

void UString::TrimLeft() throw()
{
  const wchar_t *p = _chars;
  for (;; p++)
  {
    wchar_t c = *p;
    if (c != ' ' && c != '\n' && c != '\t')
      break;
  }
  unsigned pos = (unsigned)(p - _chars);
  if (pos != 0)
  {
    MoveItems(0, pos);
    _len -= pos;
  }
}

void UString::TrimRight() throw()
{
  const wchar_t *p = _chars;
  unsigned i;
  for (i = _len; i != 0; i--)
  {
    wchar_t c = p[i - 1];
    if (c != ' ' && c != '\n' && c != '\t')
      break;
  }
  if (i != _len)
  {
    _chars[i] = 0;
    _len = i;
  }
}

void UString::InsertAtFront(wchar_t c)
{
  if (_limit == _len)
    Grow_1();
  MoveItems(1, 0);
  _chars[0] = c;
  _len++;
}

void UString::Insert(unsigned index, const wchar_t *s)
{
  unsigned num = MyStringLen(s);
  if (num != 0)
  {
    InsertSpace(index, num);
    wmemcpy(_chars + index, s, num);
    _len += num;
  }
}

void UString::Insert(unsigned index, const UString &s)
{
  unsigned num = s.Len();
  if (num != 0)
  {
    InsertSpace(index, num);
    wmemcpy(_chars + index, s, num);
    _len += num;
  }
}

void UString::RemoveChar(wchar_t ch) throw()
{
  wchar_t *src = _chars;

  for (;;)
  {
    wchar_t c = *src++;
    if (c == 0)
      return;
    if (c == ch)
      break;
  }

  wchar_t *dest = src - 1;

  for (;;)
  {
    wchar_t c = *src++;
    if (c == 0)
      break;
    if (c != ch)
      *dest++ = c;
  }

  *dest = 0;
  _len = (unsigned)(dest - _chars);
}

// !!!!!!!!!!!!!!! test it if newChar = '\0'
void UString::Replace(wchar_t oldChar, wchar_t newChar) throw()
{
  if (oldChar == newChar)
    return; // 0;
  int pos = 0;
  while ((unsigned)pos < _len)
  {
    pos = Find(oldChar, pos);
    if (pos < 0)
      break;
    _chars[(unsigned)pos] = newChar;
    pos++;
  }
}

void UString::Replace(const UString &oldString, const UString &newString)
{
  if (oldString.IsEmpty())
    return; // 0;
  if (oldString == newString)
    return; // 0;
  unsigned oldLen = oldString.Len();
  unsigned newLen = newString.Len();
  int pos = 0;
  while ((unsigned)pos < _len)
  {
    pos = Find(oldString, pos);
    if (pos < 0)
      break;
    Delete(pos, oldLen);
    Insert(pos, newString);
    pos += newLen;
  }
}

void UString::Delete(unsigned index) throw()
{
  MoveItems(index, index + 1);
  _len--;
}

void UString::Delete(unsigned index, unsigned count) throw()
{
  if (index + count > _len)
    count = _len - index;
  if (count > 0)
  {
    MoveItems(index, index + count);
    _len -= count;
  }
}

void UString::DeleteFrontal(unsigned num) throw()
{
  if (num != 0)
  {
    MoveItems(0, num);
    _len -= num;
  }
}


// ---------- UString2 ----------

void UString2::ReAlloc2(unsigned newLimit)
{
  if (newLimit >= k_Alloc_Len_Limit) throw 20130221;
  _chars = MY_STRING_NEW(wchar_t, newLimit + 1);
}

void UString2::SetStartLen(unsigned len)
{
  _chars = 0;
  _chars = MY_STRING_NEW(wchar_t, len + 1);
  _len = len;
}

UString2::UString2(const wchar_t *s)
{
  unsigned len = MyStringLen(s);
  SetStartLen(len);
  wmemcpy(_chars, s, len + 1);
}

UString2::UString2(const UString2 &s): _chars(NULL), _len(0)
{
  if (s._chars)
  {
    SetStartLen(s._len);
    wmemcpy(_chars, s._chars, s._len + 1);
  }
}

UString2 &UString2::operator=(const wchar_t *s)
{
  unsigned len = MyStringLen(s);
  if (len > _len)
  {
    wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
    if (_chars)
      MY_STRING_DELETE(_chars);
    _chars = newBuf;
  }
  _len = len;
  MyStringCopy(_chars, s);
  return *this;
}

void UString2::SetFromAscii(const char *s)
{
  unsigned len = MyStringLen(s);
  if (len > _len)
  {
    wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
    if (_chars)
      MY_STRING_DELETE(_chars);
    _chars = newBuf;
  }
  wchar_t *chars = _chars;
  for (unsigned i = 0; i < len; i++)
    chars[i] = (unsigned char)s[i];
  chars[len] = 0;
  _len = len;
}

UString2 &UString2::operator=(const UString2 &s)
{
  if (&s == this)
    return *this;
  unsigned len = s._len;
  if (len > _len)
  {
    wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
    if (_chars)
      MY_STRING_DELETE(_chars);
    _chars = newBuf;
  }
  _len = len;
  MyStringCopy(_chars, s._chars);
  return *this;
}

bool operator==(const UString2 &s1, const UString2 &s2)
{
  return s1.Len() == s2.Len() && (s1.IsEmpty() || wcscmp(s1.GetRawPtr(), s2.GetRawPtr()) == 0);
}

bool operator==(const UString2 &s1, const wchar_t *s2)
{
  if (s1.IsEmpty())
    return (*s2 == 0);
  return wcscmp(s1.GetRawPtr(), s2) == 0;
}

bool operator==(const wchar_t *s1, const UString2 &s2)
{
  if (s2.IsEmpty())
    return (*s1 == 0);
  return wcscmp(s1, s2.GetRawPtr()) == 0;
}



// ----------------------------------------

static inline UINT GetCurrentCodePage()
{
  return CP_ACP;
}

#ifdef USE_UNICODE_FSTRING

#ifndef _UNICODE

AString fs2fas(CFSTR s)
{
  return UnicodeStringToMultiByte(s, GetCurrentCodePage());
}

FString fas2fs(const AString &s)
{
  return MultiByteToUnicodeString(s, GetCurrentCodePage());
}

#endif

#else

UString fs2us(const FString &s)
{
  return MultiByteToUnicodeString((AString)s, GetCurrentCodePage());
}

FString us2fs(const wchar_t *s)
{
  return UnicodeStringToMultiByte(s, GetCurrentCodePage());
}

#endif



#ifndef ENV_HAVE_WCTYPE_H
// FIXME

wchar_t *wmemcpy(wchar_t * d, const wchar_t * s, size_t n)
{
  wchar_t *a = d;
  while (n--) *d++ = *s++;
  return a;
}

int wmemcmp(const wchar_t *l, const wchar_t *r, size_t n)
{
  for (; n && *l==*r; n--, l++, r++);
  return n ? (*l-*r) : 0;
}

wchar_t *wmemchr(const wchar_t *s, wchar_t c, size_t n)
{
  for (; n && *s != c; n--, s++);
  return n ? (wchar_t *)s : 0;
}

int wcscmp(const wchar_t *l, const wchar_t *r)
{
  for (; *l==*r && *l && *r; l++, r++);
  return *l - *r;
}

size_t wcslen(const wchar_t *s)
{
  const wchar_t *a;
  for (a=s; *s; s++);
  return s-a;
}

wchar_t *wcschr(const wchar_t *s, wchar_t c)
{
  if (!c) return (wchar_t *)s + wcslen(s);
  for (; *s && *s != c; s++);
  return *s ? (wchar_t *)s : 0;
}

#undef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#undef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))

static wchar_t *twoway_wcsstr(const wchar_t *h, const wchar_t *n)
{
  const wchar_t *z;
  size_t l, ip, jp, k, p, ms, p0, mem, mem0;

  /* Computing length of needle */
  for (l=0; n[l] && h[l]; l++);
  if (n[l]) return 0; /* hit the end of h */

  /* Compute maximal suffix */
  ip = -1; jp = 0; k = p = 1;
  while (jp+k<l) {
    if (n[ip+k] == n[jp+k]) {
      if (k == p) {
        jp += p;
        k = 1;
      } else k++;
    } else if (n[ip+k] > n[jp+k]) {
      jp += k;
      k = 1;
      p = jp - ip;
    } else {
      ip = jp++;
      k = p = 1;
    }
  }
  ms = ip;
  p0 = p;

  /* And with the opposite comparison */
  ip = -1; jp = 0; k = p = 1;
  while (jp+k<l) {
    if (n[ip+k] == n[jp+k]) {
      if (k == p) {
        jp += p;
        k = 1;
      } else k++;
    } else if (n[ip+k] < n[jp+k]) {
      jp += k;
      k = 1;
      p = jp - ip;
    } else {
      ip = jp++;
      k = p = 1;
    }
  }
  if (ip+1 > ms+1) ms = ip;
  else p = p0;

  /* Periodic needle? */
  if (wmemcmp(n, n+p, ms+1)) {
    mem0 = 0;
    p = MAX(ms, l-ms-1) + 1;
  } else mem0 = l-p;
  mem = 0;

  /* Initialize incremental end-of-haystack pointer */
  z = h;

  /* Search loop */
  for (;;) {
    /* Update incremental end-of-haystack pointer */
    if (z-h < l) {
      /* Fast estimate for MIN(l,63) */
      size_t grow = l | 63;
      const wchar_t *z2 = wmemchr(z, 0, grow);
      if (z2) {
        z = z2;
        if (z-h < l) return 0;
      } else z += grow;
    }

    /* Compare right half */
    for (k=MAX(ms+1,mem); n[k] && n[k] == h[k]; k++);
    if (n[k]) {
      h += k-ms;
      mem = 0;
      continue;
    }
    /* Compare left half */
    for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--);
    if (k <= mem) return (wchar_t *)h;
    h += p;
    mem = mem0;
  }
}

wchar_t *wcsstr(const wchar_t * h, const wchar_t * n)
{
  /* Return immediately on empty needle or haystack */
  if (!n[0]) return (wchar_t *)h;
  if (!h[0]) return 0;

  /* Use faster algorithms for short needles */
  h = wcschr(h, *n);
  if (!h || !n[1]) return (wchar_t *)h;
  if (!h[1]) return 0;

  return twoway_wcsstr(h, n);
}

#if defined(__DJGPP__)
wchar_t *wcscpy(wchar_t * d, const wchar_t * s)
{
  wchar_t *a = d;
  while ((*d++ = *s++));
  return a;
}

wchar_t *wcscat(wchar_t *dest, const wchar_t * src)
{
  wcscpy(dest + wcslen(dest), src);
  return dest;
}

#endif

#endif
