// Common/MyString.cpp | |
#include "StdAfx.h" | |
#ifdef _WIN32 | |
#include <windows.h> | |
#include <wchar.h> | |
#else | |
#include <ctype.h> | |
#endif | |
#if !defined(_UNICODE) || !defined(USE_UNICODE_FSTRING) | |
#include "StringConvert.h" | |
#endif | |
#include "MyString.h" | |
#define MY_STRING_NEW(_T_, _size_) new _T_[_size_] | |
// #define MY_STRING_NEW(_T_, _size_) ((_T_ *)my_new((size_t)(_size_) * sizeof(_T_))) | |
/* | |
inline const char* MyStringGetNextCharPointer(const char *p) throw() | |
{ | |
#if defined(_WIN32) && !defined(UNDER_CE) | |
return CharNextA(p); | |
#else | |
return p + 1; | |
#endif | |
} | |
*/ | |
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; | |
// MyStringGetNextCharPointer(p); | |
} | |
} | |
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 MyStringUpper_Ascii(wchar_t *s) | |
{ | |
for (;;) | |
{ | |
wchar_t c = *s; | |
if (c == 0) | |
return; | |
*s++ = MyCharUpper_Ascii(c); | |
} | |
} | |
*/ | |
void MyStringLower_Ascii(wchar_t *s) throw() | |
{ | |
for (;;) | |
{ | |
wchar_t c = *s; | |
if (c == 0) | |
return; | |
*s++ = MyCharLower_Ascii(c); | |
} | |
} | |
#ifdef _WIN32 | |
#ifdef _UNICODE | |
// wchar_t * MyStringUpper(wchar_t *s) { return CharUpperW(s); } | |
// wchar_t * MyStringLower(wchar_t *s) { return CharLowerW(s); } | |
// for WinCE - FString - char | |
// const char *MyStringGetPrevCharPointer(const char * /* base */, const char *p) { return p - 1; } | |
#else | |
// const char * MyStringGetPrevCharPointer(const char *base, const char *p) throw() { return CharPrevA(base, p); } | |
// char * MyStringUpper(char *s) { return CharUpperA(s); } | |
// char * MyStringLower(char *s) { return CharLowerA(s); } | |
wchar_t MyCharUpper_WIN(wchar_t c) throw() | |
{ | |
wchar_t *res = CharUpperW((LPWSTR)(UINT_PTR)(unsigned)c); | |
if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) | |
return (wchar_t)(unsigned)(UINT_PTR)res; | |
const int kBufSize = 4; | |
char s[kBufSize + 1]; | |
int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufSize, 0, 0); | |
if (numChars == 0 || numChars > kBufSize) | |
return c; | |
s[numChars] = 0; | |
::CharUpperA(s); | |
::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1); | |
return c; | |
} | |
/* | |
wchar_t MyCharLower_WIN(wchar_t c) | |
{ | |
wchar_t *res = CharLowerW((LPWSTR)(UINT_PTR)(unsigned)c); | |
if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) | |
return (wchar_t)(unsigned)(UINT_PTR)res; | |
const int kBufSize = 4; | |
char s[kBufSize + 1]; | |
int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufSize, 0, 0); | |
if (numChars == 0 || numChars > kBufSize) | |
return c; | |
s[numChars] = 0; | |
::CharLowerA(s); | |
::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1); | |
return c; | |
} | |
*/ | |
/* | |
wchar_t * MyStringUpper(wchar_t *s) | |
{ | |
if (s == 0) | |
return 0; | |
wchar_t *res = CharUpperW(s); | |
if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) | |
return res; | |
AString a = UnicodeStringToMultiByte(s); | |
a.MakeUpper(); | |
MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a)); | |
return s; | |
} | |
*/ | |
/* | |
wchar_t * MyStringLower(wchar_t *s) | |
{ | |
if (s == 0) | |
return 0; | |
wchar_t *res = CharLowerW(s); | |
if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) | |
return res; | |
AString a = UnicodeStringToMultiByte(s); | |
a.MakeLower(); | |
MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a)); | |
return s; | |
} | |
*/ | |
#endif | |
#endif | |
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; | |
} | |
} | |
// 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; | |
} | |
} | |
int MyStringCompareNoCase_N(const wchar_t *s1, const wchar_t *s2, unsigned num) throw() | |
{ | |
for (; num != 0; num--) | |
{ | |
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; | |
} | |
return 0; | |
} | |
// ---------- AString ---------- | |
void AString::InsertSpace(unsigned &index, unsigned size) | |
{ | |
Grow(size); | |
MoveItems(index + size, index); | |
} | |
void AString::ReAlloc(unsigned newLimit) | |
{ | |
if (newLimit < _len || newLimit >= 0x20000000) throw 20130220; | |
// MY_STRING_REALLOC(_chars, char, newLimit + 1, _len + 1); | |
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::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 char *s) | |
{ | |
unsigned len = MyStringLen(s); | |
if (num > len) | |
num = len; | |
SetStartLen(num); | |
memcpy(_chars, s, num); | |
_chars[num] = 0; | |
} | |
*/ | |
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; | |
} | |
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; | |
} | |
memcpy(_chars, s, len); | |
_chars[len] = 0; | |
_len = len; | |
} | |
int AString::Find(const AString &s, unsigned startIndex) const throw() | |
{ | |
if (s.IsEmpty()) | |
return startIndex; | |
for (; startIndex < _len; startIndex++) | |
{ | |
unsigned j; | |
for (j = 0; j < s._len && startIndex + j < _len; j++) | |
if (_chars[startIndex + j] != s._chars[j]) | |
break; | |
if (j == s._len) | |
return (int)startIndex; | |
} | |
return -1; | |
} | |
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); | |
} | |
} | |
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; | |
int i; | |
for (i = _len - 1; i >= 0; i--) | |
{ | |
char c = p[i]; | |
if (c != ' ' && c != '\n' && c != '\t') | |
break; | |
} | |
i++; | |
if ((unsigned)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, char c) | |
{ | |
InsertSpace(index, 1); | |
_chars[index] = 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() | |
{ | |
int pos = Find(ch); | |
if (pos < 0) | |
return; | |
const char *src = _chars; | |
char *dest = _chars + pos; | |
pos++; | |
unsigned len = _len; | |
for (; (unsigned)pos < len; pos++) | |
{ | |
char c = src[(unsigned)pos]; | |
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; | |
// unsigned number = 0; | |
int pos = 0; | |
while ((unsigned)pos < _len) | |
{ | |
pos = Find(oldChar, pos); | |
if (pos < 0) | |
break; | |
_chars[pos] = newChar; | |
pos++; | |
// number++; | |
} | |
return; // number; | |
} | |
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(); | |
// unsigned number = 0; | |
int pos = 0; | |
while ((unsigned)pos < _len) | |
{ | |
pos = Find(oldString, pos); | |
if (pos < 0) | |
break; | |
Delete(pos, oldLen); | |
Insert(pos, newString); | |
pos += newLen; | |
// number++; | |
} | |
// return number; | |
} | |
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; | |
} | |
} | |
/* | |
AString operator+(const AString &s1, const AString &s2) | |
{ | |
AString result(s1); | |
result += s2; | |
return result; | |
} | |
AString operator+(const AString &s, const char *chars) | |
{ | |
AString result(s); | |
result += chars; | |
return result; | |
} | |
AString operator+(const char *chars, const AString &s) | |
{ | |
AString result(chars); | |
result += s; | |
return result; | |
} | |
AString operator+(const AString &s, char c) | |
{ | |
AString result(s); | |
result += c; | |
return result; | |
} | |
*/ | |
/* | |
AString operator+(char c, const AString &s) | |
{ | |
AString result(c); | |
result += s; | |
return result; | |
} | |
*/ | |
// ---------- UString ---------- | |
void UString::InsertSpace(unsigned index, unsigned size) | |
{ | |
Grow(size); | |
MoveItems(index + size, index); | |
} | |
void UString::ReAlloc(unsigned newLimit) | |
{ | |
if (newLimit < _len || newLimit >= 0x20000000) throw 20130221; | |
// MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, _len + 1); | |
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::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) | |
{ | |
SetStartLen(MyStringLen(s)); | |
MyStringCopy(_chars, s); | |
} | |
UString::UString(const UString &s) | |
{ | |
SetStartLen(s._len); | |
MyStringCopy(_chars, s._chars); | |
} | |
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; | |
MyStringCopy(_chars, s); | |
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; | |
MyStringCopy(_chars, s._chars); | |
return *this; | |
} | |
UString &UString::operator+=(const wchar_t *s) | |
{ | |
unsigned len = MyStringLen(s); | |
Grow(len); | |
MyStringCopy(_chars + _len, s); | |
_len += len; | |
return *this; | |
} | |
UString &UString::operator+=(const UString &s) | |
{ | |
Grow(s._len); | |
MyStringCopy(_chars + _len, s._chars); | |
_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; | |
} | |
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] = s[i]; | |
chars[len] = 0; | |
_len = len; | |
} | |
void UString::AddAsciiStr(const char *s) | |
{ | |
unsigned len = MyStringLen(s); | |
Grow(len); | |
wchar_t *chars = _chars + _len; | |
for (unsigned i = 0; i < len; i++) | |
chars[i] = s[i]; | |
chars[len] = 0; | |
_len += len; | |
} | |
int UString::Find(const UString &s, unsigned startIndex) const throw() | |
{ | |
if (s.IsEmpty()) | |
return startIndex; | |
for (; startIndex < _len; startIndex++) | |
{ | |
unsigned j; | |
for (j = 0; j < s._len && startIndex + j < _len; j++) | |
if (_chars[startIndex + j] != s._chars[j]) | |
break; | |
if (j == s._len) | |
return (int)startIndex; | |
} | |
return -1; | |
} | |
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--; | |
} | |
} | |
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; | |
int i; | |
for (i = _len - 1; i >= 0; i--) | |
{ | |
wchar_t c = p[i]; | |
if (c != ' ' && c != '\n' && c != '\t') | |
break; | |
} | |
i++; | |
if ((unsigned)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, wchar_t c) | |
{ | |
InsertSpace(index, 1); | |
_chars[index] = 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() | |
{ | |
int pos = Find(ch); | |
if (pos < 0) | |
return; | |
const wchar_t *src = _chars; | |
wchar_t *dest = _chars + pos; | |
pos++; | |
unsigned len = _len; | |
for (; (unsigned)pos < len; pos++) | |
{ | |
wchar_t c = src[(unsigned)pos]; | |
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; | |
// unsigned number = 0; | |
int pos = 0; | |
while ((unsigned)pos < _len) | |
{ | |
pos = Find(oldChar, pos); | |
if (pos < 0) | |
break; | |
_chars[pos] = newChar; | |
pos++; | |
// number++; | |
} | |
return; // number; | |
} | |
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(); | |
// unsigned number = 0; | |
int pos = 0; | |
while ((unsigned)pos < _len) | |
{ | |
pos = Find(oldString, pos); | |
if (pos < 0) | |
break; | |
Delete(pos, oldLen); | |
Insert(pos, newString); | |
pos += newLen; | |
// number++; | |
} | |
// return number; | |
} | |
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; | |
} | |
} | |
// ---------------------------------------- | |
/* | |
int MyStringCompareNoCase(const char *s1, const char *s2) | |
{ | |
return MyStringCompareNoCase(MultiByteToUnicodeString(s1), MultiByteToUnicodeString(s2)); | |
} | |
*/ | |
static inline UINT GetCurrentCodePage() | |
{ | |
#if defined(UNDER_CE) || !defined(_WIN32) | |
return CP_ACP; | |
#else | |
return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; | |
#endif | |
} | |
#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 |