mirror of
https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git
synced 2025-07-14 10:37:41 -04:00
Re-add plString with some cleanup
This commit is contained in:
@ -1,5 +1,16 @@
|
||||
add_definitions(-D_LIB)
|
||||
|
||||
if(NOT WCHAR_BYTES)
|
||||
include(CheckTypeSize)
|
||||
|
||||
check_type_size("wchar_t" WCHAR_BYTES)
|
||||
if(NOT WCHAR_BYTES)
|
||||
message(FATAL_ERROR "Could not determine sizeof(wchar_t)")
|
||||
set(WCHAR_BYTES 0)
|
||||
endif(NOT WCHAR_BYTES)
|
||||
endif(NOT WCHAR_BYTES)
|
||||
add_definitions(-DWCHAR_BYTES=${WCHAR_BYTES})
|
||||
|
||||
set(CoreLib_SOURCES
|
||||
HeadSpin.cpp
|
||||
hsBitVector.cpp
|
||||
@ -26,6 +37,7 @@ set(CoreLib_SOURCES
|
||||
pcSmallRect.cpp
|
||||
plGeneric.cpp
|
||||
plLoadMask.cpp
|
||||
plString.cpp
|
||||
plViewTransform.cpp
|
||||
)
|
||||
|
||||
@ -82,6 +94,7 @@ set(CoreLib_HEADERS
|
||||
plLoadMask.h
|
||||
plQuality.h
|
||||
plRefCnt.h
|
||||
plString.h
|
||||
plTweak.h
|
||||
plViewTransform.h
|
||||
)
|
||||
|
662
Sources/Plasma/CoreLib/plString.cpp
Normal file
662
Sources/Plasma/CoreLib/plString.cpp
Normal file
@ -0,0 +1,662 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#include "plString.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
const plString plString::Null;
|
||||
|
||||
#if !defined(WCHAR_BYTES) || (WCHAR_BYTES != 2) && (WCHAR_BYTES != 4)
|
||||
#error "WCHAR_BYTES must be either 2 (16-bit) or 4 (32-bit)!"
|
||||
#endif
|
||||
|
||||
#if WCHAR_BYTES == 2
|
||||
#define u16slen(str, max) wcsnlen((const wchar_t *)(str), (max))
|
||||
#else
|
||||
static inline size_t u16slen(const UInt16 *ustr, size_t max)
|
||||
{
|
||||
size_t length = 0;
|
||||
for ( ; *ustr++ && max--; ++length)
|
||||
;
|
||||
return length;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define BADCHAR_REPLACEMENT (0xFFFDul)
|
||||
|
||||
void plString::IConvertFromUtf8(const char *utf8, size_t size, bool steal)
|
||||
{
|
||||
if ((long)size < 0)
|
||||
size = strnlen(utf8, -(long)size);
|
||||
|
||||
#ifdef _DEBUG
|
||||
// Check to make sure the string is actually valid UTF-8
|
||||
const char *sp = utf8;
|
||||
while (sp < utf8 + size) {
|
||||
unsigned char unichar = *sp++;
|
||||
if ((unichar & 0xF8) == 0xF0) {
|
||||
// Four bytes
|
||||
hsAssert((*sp++) & 0x80, "Invalid UTF-8 sequence byte (1)");
|
||||
hsAssert((*sp++) & 0x80, "Invalid UTF-8 sequence byte (2)");
|
||||
hsAssert((*sp++) & 0x80, "Invalid UTF-8 sequence byte (3)");
|
||||
} else if ((unichar & 0xF0) == 0xE0) {
|
||||
// Three bytes
|
||||
hsAssert((*sp++) & 0x80, "Invalid UTF-8 sequence byte (1)");
|
||||
hsAssert((*sp++) & 0x80, "Invalid UTF-8 sequence byte (2)");
|
||||
} else if ((unichar & 0xE0) == 0xC0) {
|
||||
// Two bytes
|
||||
hsAssert((*sp++) & 0x80, "Invalid UTF-8 sequence byte (1)");
|
||||
} else if ((unichar & 0xC0) == 0x80) {
|
||||
hsAssert(0, "Invalid UTF-8 marker byte");
|
||||
} else if ((unichar & 0x80) != 0) {
|
||||
hsAssert(0, "UTF-8 character out of range");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
fUtf8Buffer = steal ? plStringBuffer<char>::Steal(utf8, size)
|
||||
: plStringBuffer<char>(utf8, size);
|
||||
}
|
||||
|
||||
void plString::IConvertFromUtf16(const UInt16 *utf16, size_t size)
|
||||
{
|
||||
if ((long)size < 0)
|
||||
size = u16slen(utf16, -(long)size);
|
||||
|
||||
// Calculate the UTF-8 size
|
||||
size_t convlen = 0;
|
||||
const UInt16 *sp = utf16;
|
||||
while (sp < utf16 + size) {
|
||||
if (*sp >= 0xD800 && *sp <= 0xDFFF) {
|
||||
// Surrogate pair
|
||||
convlen += 4;
|
||||
++sp;
|
||||
}
|
||||
else if (*sp > 0x7FF)
|
||||
convlen += 3;
|
||||
else if (*sp > 0x7F)
|
||||
convlen += 2;
|
||||
else
|
||||
convlen += 1;
|
||||
++sp;
|
||||
}
|
||||
|
||||
// And perform the actual conversion
|
||||
char *utf8 = TRACKED_NEW char[convlen + 1];
|
||||
char *dp = utf8;
|
||||
sp = utf16;
|
||||
while (sp < utf16 + size) {
|
||||
if (*sp >= 0xD800 && *sp <= 0xDFFF) {
|
||||
// Surrogate pair
|
||||
unsigned int unichar = 0x10000;
|
||||
|
||||
if (sp + 1 >= utf16 + size) {
|
||||
hsAssert(0, "Incomplete surrogate pair in UTF-16 data");
|
||||
unichar = BADCHAR_REPLACEMENT;
|
||||
} else if (*sp < 0xDC00) {
|
||||
unichar += (*sp++ & 0x3FF) << 10;
|
||||
hsAssert(*sp >= 0xDC00 && *sp <= 0xDFFF,
|
||||
"Invalid surrogate pair in UTF-16 data");
|
||||
unichar += (*sp & 0x3FF);
|
||||
} else {
|
||||
unichar += (*sp++ & 0x3FF);
|
||||
hsAssert(*sp >= 0xD800 && *sp < 0xDC00,
|
||||
"Invalid surrogate pair in UTF-16 data");
|
||||
unichar += (*sp & 0x3FF) << 10;
|
||||
}
|
||||
*dp++ = 0xF0 | ((unichar >> 18) & 0x07);
|
||||
*dp++ = 0x80 | ((unichar >> 12) & 0x3F);
|
||||
*dp++ = 0x80 | ((unichar >> 6) & 0x3F);
|
||||
*dp++ = 0x80 | ((unichar ) & 0x3F);
|
||||
} else if (*sp > 0x7FF) {
|
||||
*dp++ = 0xF0 | ((*sp >> 12) & 0x0F);
|
||||
*dp++ = 0x80 | ((*sp >> 6) & 0x3F);
|
||||
*dp++ = 0x80 | ((*sp ) & 0x3F);
|
||||
} else if (*sp > 0x7F) {
|
||||
*dp++ = 0xF0 | ((*sp >> 6) & 0x1F);
|
||||
*dp++ = 0x80 | ((*sp ) & 0x3F);
|
||||
} else {
|
||||
*dp++ = (char)(*sp);
|
||||
}
|
||||
++sp;
|
||||
}
|
||||
utf8[convlen] = 0;
|
||||
|
||||
fUtf8Buffer = plStringBuffer<char>::Steal(utf8, convlen);
|
||||
}
|
||||
|
||||
void plString::IConvertFromWchar(const wchar_t *wstr, size_t size)
|
||||
{
|
||||
#if WCHAR_BYTES == 2
|
||||
// We assume that if sizeof(wchar_t) == 2, the data is UTF-16 already
|
||||
IConvertFromUtf16((const UInt16 *)wstr, size);
|
||||
#else
|
||||
if ((long)size < 0)
|
||||
size = wcsnlen(wstr, -(long)size);
|
||||
|
||||
// Calculate the UTF-8 size
|
||||
size_t convlen = 0;
|
||||
const wchar_t *sp = wstr;
|
||||
while (sp < wstr + size) {
|
||||
if (*sp > 0x10FFFF) {
|
||||
hsAssert(0, "UCS-4 character out of range");
|
||||
convlen += 3; // Use U+FFFD for release builds
|
||||
}
|
||||
else if (*sp > 0xFFFF)
|
||||
convlen += 4;
|
||||
else if (*sp > 0x7FF)
|
||||
convlen += 3;
|
||||
else if (*sp > 0x7F)
|
||||
convlen += 2;
|
||||
else
|
||||
convlen += 1;
|
||||
++sp;
|
||||
}
|
||||
|
||||
// And perform the actual conversion
|
||||
char *utf8 = TRACKED_NEW char[convlen + 1];
|
||||
char *dp = utf8;
|
||||
sp = wstr;
|
||||
while (sp < wstr + size) {
|
||||
if (*sp > 0x10FFFF) {
|
||||
// Character out of range; Use U+FFFD instead
|
||||
*dp++ = 0xE0 | ((BADCHAR_REPLACEMENT >> 12) & 0x0F);
|
||||
*dp++ = 0x80 | ((BADCHAR_REPLACEMENT >> 6) & 0x3F);
|
||||
*dp++ = 0x80 | ((BADCHAR_REPLACEMENT ) & 0x3F);
|
||||
} else if (*sp > 0xFFFF) {
|
||||
*dp++ = 0xF0 | ((*sp >> 18) & 0x07);
|
||||
*dp++ = 0x80 | ((*sp >> 12) & 0x3F);
|
||||
*dp++ = 0x80 | ((*sp >> 6) & 0x3F);
|
||||
*dp++ = 0x80 | ((*sp ) & 0x3F);
|
||||
} else if (*sp > 0x7FF) {
|
||||
*dp++ = 0xF0 | ((*sp >> 12) & 0x0F);
|
||||
*dp++ = 0x80 | ((*sp >> 6) & 0x3F);
|
||||
*dp++ = 0x80 | ((*sp ) & 0x3F);
|
||||
} else if (*sp > 0x7F) {
|
||||
*dp++ = 0xF0 | ((*sp >> 6) & 0x1F);
|
||||
*dp++ = 0x80 | ((*sp ) & 0x3F);
|
||||
} else {
|
||||
*dp++ = (char)(*sp);
|
||||
}
|
||||
++sp;
|
||||
}
|
||||
utf8[convlen] = 0;
|
||||
|
||||
fUtf8Buffer = plStringBuffer<char>::Steal(utf8, convlen);
|
||||
#endif
|
||||
}
|
||||
|
||||
void plString::IConvertFromIso8859_1(const char *astr, size_t size)
|
||||
{
|
||||
if ((long)size < 0)
|
||||
size = strnlen(astr, -(long)size);
|
||||
|
||||
// Calculate the UTF-8 size
|
||||
size_t convlen = 0;
|
||||
const char *sp = astr;
|
||||
while (sp < astr + size) {
|
||||
if ((*sp++) & 0x80)
|
||||
convlen += 2;
|
||||
else
|
||||
convlen += 1;
|
||||
}
|
||||
|
||||
// And perform the actual conversion
|
||||
char *utf8 = TRACKED_NEW char[convlen + 1];
|
||||
char *dp = utf8;
|
||||
sp = astr;
|
||||
while (sp < astr + size) {
|
||||
if (*astr & 0x80) {
|
||||
*dp++ = 0xC0 | ((*sp >> 6) & 0x1F);
|
||||
*dp++ = 0x80 | ((*sp ) & 0x3F);
|
||||
} else {
|
||||
*dp++ = *sp;
|
||||
}
|
||||
++sp;
|
||||
}
|
||||
utf8[convlen] = 0;
|
||||
|
||||
fUtf8Buffer = plStringBuffer<char>::Steal(utf8, convlen);
|
||||
}
|
||||
|
||||
plStringBuffer<UInt16> plString::ToUtf16() const
|
||||
{
|
||||
if (IsNull())
|
||||
return plStringBuffer<UInt16>();
|
||||
|
||||
// Calculate the UTF-16 size
|
||||
size_t convlen = 0;
|
||||
const char *utf8 = fUtf8Buffer.GetData();
|
||||
const char *sp = utf8;
|
||||
size_t srcSize = fUtf8Buffer.GetSize();
|
||||
while (sp < utf8 + srcSize) {
|
||||
if ((*sp & 0xF8) == 0xF0) {
|
||||
// Will require a surrogate pair
|
||||
++convlen;
|
||||
sp += 4;
|
||||
}
|
||||
else if ((*sp & 0xF0) == 0xE0)
|
||||
sp += 3;
|
||||
else if ((*sp & 0xE0) == 0xC0)
|
||||
sp += 2;
|
||||
else
|
||||
sp += 1;
|
||||
++convlen;
|
||||
}
|
||||
|
||||
// And perform the actual conversion
|
||||
UInt16 *ustr = TRACKED_NEW UInt16[convlen + 1];
|
||||
UInt16 *dp = ustr;
|
||||
sp = utf8;
|
||||
while (sp < utf8 + srcSize) {
|
||||
unsigned int unichar;
|
||||
if ((*sp & 0xF8) == 0xF0) {
|
||||
unichar = (*sp++ & 0x07) << 18;
|
||||
unichar |= (*sp++ & 0x3F) << 12;
|
||||
unichar |= (*sp++ & 0x3F) << 6;
|
||||
unichar |= (*sp++ & 0x3F);
|
||||
|
||||
*dp++ = 0xD800 | ((unichar >> 10) & 0x3FF);
|
||||
*dp++ = 0xDC00 | ((unichar ) & 0x3FF);
|
||||
} else if ((*sp & 0xF0) == 0xE0) {
|
||||
unichar = (*sp++ & 0x0F) << 12;
|
||||
unichar |= (*sp++ & 0x3F) << 6;
|
||||
unichar |= (*sp++ & 0x3F);
|
||||
*dp++ = unichar;
|
||||
} else if ((*sp & 0xE0) == 0xC0) {
|
||||
unichar = (*sp++ & 0x1F) << 6;
|
||||
unichar |= (*sp++ & 0x3F);
|
||||
*dp++ = unichar;
|
||||
} else {
|
||||
*dp++ = *sp++;
|
||||
}
|
||||
}
|
||||
ustr[convlen] = 0;
|
||||
|
||||
return plStringBuffer<UInt16>::Steal(ustr, convlen);
|
||||
}
|
||||
|
||||
plStringBuffer<wchar_t> plString::ToWchar() const
|
||||
{
|
||||
#if WCHAR_BYTES == 2
|
||||
// We assume that if sizeof(wchar_t) == 2, the data is UTF-16 already
|
||||
plStringBuffer<UInt16> utf16 = ToUtf16();
|
||||
return *reinterpret_cast<plStringBuffer<wchar_t>*>(&utf16);
|
||||
#else
|
||||
if (IsNull())
|
||||
return plStringBuffer<wchar_t>();
|
||||
|
||||
// Calculate the UCS-4 size
|
||||
size_t convlen = 0;
|
||||
const char *utf8 = fUtf8Buffer.GetData();
|
||||
const char *sp = utf8;
|
||||
size_t srcSize = fUtf8Buffer.GetSize();
|
||||
while (sp < utf8 + srcSize) {
|
||||
if ((*sp & 0xF8) == 0xF0)
|
||||
sp += 4;
|
||||
else if ((*sp & 0xF0) == 0xE0)
|
||||
sp += 3;
|
||||
else if ((*sp & 0xE0) == 0xC0)
|
||||
sp += 2;
|
||||
else
|
||||
sp += 1;
|
||||
++convlen;
|
||||
}
|
||||
|
||||
// And perform the actual conversion
|
||||
wchar_t *wstr = TRACKED_NEW wchar_t[convlen + 1];
|
||||
wchar_t *dp = wstr;
|
||||
sp = utf8;
|
||||
while (sp < utf8 + srcSize) {
|
||||
unsigned int unichar;
|
||||
if ((*sp & 0xF8) == 0xF0) {
|
||||
unichar = (*sp++ & 0x07) << 18;
|
||||
unichar |= (*sp++ & 0x3F) << 12;
|
||||
unichar |= (*sp++ & 0x3F) << 6;
|
||||
unichar |= (*sp++ & 0x3F);
|
||||
} else if ((*sp & 0xF0) == 0xE0) {
|
||||
unichar = (*sp++ & 0x0F) << 12;
|
||||
unichar |= (*sp++ & 0x3F) << 6;
|
||||
unichar |= (*sp++ & 0x3F);
|
||||
} else if ((*sp & 0xE0) == 0xC0) {
|
||||
unichar = (*sp++ & 0x1F) << 6;
|
||||
unichar |= (*sp++ & 0x3F);
|
||||
} else {
|
||||
unichar = *sp++;
|
||||
}
|
||||
*dp++ = unichar;
|
||||
}
|
||||
wstr[convlen] = 0;
|
||||
|
||||
return plStringBuffer<wchar_t>::Steal(wstr, convlen);
|
||||
#endif
|
||||
}
|
||||
|
||||
plStringBuffer<char> plString::ToIso8859_1() const
|
||||
{
|
||||
if (IsNull())
|
||||
return plStringBuffer<char>();
|
||||
|
||||
// Calculate the ASCII size
|
||||
size_t convlen = 0;
|
||||
const char *utf8 = fUtf8Buffer.GetData();
|
||||
const char *sp = utf8;
|
||||
size_t srcSize = fUtf8Buffer.GetSize();
|
||||
while (sp < utf8 + srcSize) {
|
||||
if ((*sp & 0xF8) == 0xF0)
|
||||
sp += 4;
|
||||
else if ((*sp & 0xF0) == 0xE0)
|
||||
sp += 3;
|
||||
else if ((*sp & 0xE0) == 0xC0)
|
||||
sp += 2;
|
||||
else
|
||||
sp += 1;
|
||||
++convlen;
|
||||
}
|
||||
|
||||
// And perform the actual conversion
|
||||
char *astr = TRACKED_NEW char[convlen + 1];
|
||||
char *dp = astr;
|
||||
sp = utf8;
|
||||
while (sp < utf8 + srcSize) {
|
||||
unsigned int unichar;
|
||||
if ((*sp & 0xF8) == 0xF0) {
|
||||
unichar = (*sp++ & 0x07) << 18;
|
||||
unichar |= (*sp++ & 0x3F) << 12;
|
||||
unichar |= (*sp++ & 0x3F) << 6;
|
||||
unichar |= (*sp++ & 0x3F);
|
||||
} else if ((*sp & 0xF0) == 0xE0) {
|
||||
unichar = (*sp++ & 0x0F) << 12;
|
||||
unichar |= (*sp++ & 0x3F) << 6;
|
||||
unichar |= (*sp++ & 0x3F);
|
||||
} else if ((*sp & 0xE0) == 0xC0) {
|
||||
unichar = (*sp++ & 0x1F) << 6;
|
||||
unichar |= (*sp++ & 0x3F);
|
||||
} else {
|
||||
unichar = *sp++;
|
||||
}
|
||||
*dp++ = (unichar < 0xFF) ? unichar : '?';
|
||||
}
|
||||
astr[convlen] = 0;
|
||||
|
||||
return plStringBuffer<char>::Steal(astr, convlen);
|
||||
}
|
||||
|
||||
plStringBuffer<UniChar> plString::GetUnicodeArray() const
|
||||
{
|
||||
static UniChar empty[1] = {0};
|
||||
|
||||
if (IsNull())
|
||||
return plStringBuffer<UniChar>(empty, 0);
|
||||
|
||||
size_t convlen = GetUniCharCount();
|
||||
UniChar *ustr = new UniChar[convlen + 1];
|
||||
iterator iter = GetIterator();
|
||||
size_t dp = 0;
|
||||
while (!iter.AtEnd())
|
||||
ustr[dp++] = *iter++;
|
||||
ustr[convlen] = 0;
|
||||
return plStringBuffer<UniChar>::Steal(ustr, convlen);
|
||||
}
|
||||
|
||||
int plString::ToInt(int base) const
|
||||
{
|
||||
return static_cast<int>(strtol(s_str(), nil, base));
|
||||
}
|
||||
|
||||
unsigned int plString::ToUInt(int base) const
|
||||
{
|
||||
return static_cast<unsigned int>(strtoul(s_str(), nil, base));
|
||||
}
|
||||
|
||||
float plString::ToFloat() const
|
||||
{
|
||||
// strtof is C99, which MS doesn't support...
|
||||
return (float)strtod(s_str(), nil);
|
||||
}
|
||||
|
||||
double plString::ToDouble() const
|
||||
{
|
||||
return strtod(s_str(), nil);
|
||||
}
|
||||
|
||||
// Microsoft doesn't provide this for us
|
||||
#ifdef _MSC_VER
|
||||
#define va_copy(dest, src) (dest) = (src)
|
||||
#endif
|
||||
|
||||
plString plString::IFormat(const char *fmt, va_list vptr)
|
||||
{
|
||||
char buffer[256];
|
||||
va_list vptr_save;
|
||||
va_copy(vptr_save, vptr);
|
||||
|
||||
int chars = vsnprintf(buffer, 256, fmt, vptr);
|
||||
if (chars < 0) {
|
||||
// We will need to try this multiple times until we get a
|
||||
// large enough buffer :(
|
||||
int size = 4096;
|
||||
for ( ;; ) {
|
||||
va_copy(vptr, vptr_save);
|
||||
char *bigbuffer = TRACKED_NEW char[size];
|
||||
chars = vsnprintf(bigbuffer, size, fmt, vptr);
|
||||
if (chars >= 0)
|
||||
return plString::Steal(bigbuffer);
|
||||
|
||||
delete [] bigbuffer;
|
||||
size *= 2;
|
||||
}
|
||||
} else if (chars >= 256) {
|
||||
va_copy(vptr, vptr_save);
|
||||
char *bigbuffer = TRACKED_NEW char[chars+1];
|
||||
vsnprintf(bigbuffer, chars+1, fmt, vptr);
|
||||
return plString::Steal(bigbuffer);
|
||||
}
|
||||
|
||||
return plString::FromUtf8(buffer);
|
||||
}
|
||||
|
||||
plString plString::Format(const char *fmt, ...)
|
||||
{
|
||||
va_list vptr;
|
||||
va_start(vptr, fmt);
|
||||
plString str = IFormat(fmt, vptr);
|
||||
va_end(vptr);
|
||||
return str;
|
||||
}
|
||||
|
||||
int plString::Find(char ch, CaseSense sense) const
|
||||
{
|
||||
if (sense == kCaseSensitive) {
|
||||
const char *cp = strchr(s_str(), ch);
|
||||
return cp ? (cp - c_str()) : -1;
|
||||
} else {
|
||||
// No need to check for null, since s_str() will return { 0 } if it is null
|
||||
const char *cp = s_str();
|
||||
while (*cp) {
|
||||
if (tolower(*cp) == tolower(ch))
|
||||
return cp - c_str();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int plString::FindReverse(char ch, CaseSense sense) const
|
||||
{
|
||||
if (IsEmpty())
|
||||
return -1;
|
||||
|
||||
if (sense == kCaseSensitive) {
|
||||
const char *cp = strrchr(s_str(), ch);
|
||||
return cp ? (cp - c_str()) : -1;
|
||||
} else {
|
||||
const char *cp = c_str();
|
||||
cp += strlen(cp);
|
||||
|
||||
while (--cp >= c_str()) {
|
||||
if (tolower(*cp) == tolower(ch))
|
||||
return cp - c_str();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static bool in_set(char key, const char *charset)
|
||||
{
|
||||
for (const char *cs = charset; *cs; ++cs) {
|
||||
if (*cs == key)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
plString plString::TrimLeft(const char *charset) const
|
||||
{
|
||||
if (IsEmpty())
|
||||
return Null;
|
||||
|
||||
const char *cp = c_str();
|
||||
while (*cp && in_set(*cp, charset))
|
||||
++cp;
|
||||
|
||||
return Substr(cp - c_str());
|
||||
}
|
||||
|
||||
plString plString::TrimRight(const char *charset) const
|
||||
{
|
||||
if (IsEmpty())
|
||||
return Null;
|
||||
|
||||
const char *cp = c_str();
|
||||
cp += strlen(cp);
|
||||
|
||||
while (--cp >= c_str() && in_set(*cp, charset))
|
||||
;
|
||||
|
||||
return Substr(0, cp - c_str() + 1);
|
||||
}
|
||||
|
||||
plString plString::Trim(const char *charset) const
|
||||
{
|
||||
if (IsEmpty())
|
||||
return Null;
|
||||
|
||||
const char *lp = c_str();
|
||||
const char *rp = lp + strlen(lp);
|
||||
|
||||
while (*lp && in_set(*lp, charset))
|
||||
++lp;
|
||||
while (--rp >= lp && in_set(*rp, charset))
|
||||
;
|
||||
|
||||
return Substr(lp - c_str(), rp - lp + 1);
|
||||
}
|
||||
|
||||
plString plString::Substr(int start, size_t size) const
|
||||
{
|
||||
size_t maxSize = GetSize();
|
||||
|
||||
if (start > maxSize)
|
||||
return Null;
|
||||
if (start < 0)
|
||||
start = 0;
|
||||
if (start + size > maxSize)
|
||||
size = maxSize - start;
|
||||
|
||||
if (start == 0 && size == maxSize)
|
||||
return *this;
|
||||
|
||||
char *substr = TRACKED_NEW char[size + 1];
|
||||
memcpy(substr, c_str() + start, size);
|
||||
substr[size] = 0;
|
||||
|
||||
// Don't re-check UTF-8 on this
|
||||
plString str;
|
||||
str.fUtf8Buffer.Steal(substr, size);
|
||||
return str;
|
||||
}
|
||||
|
||||
plString &plString::operator+=(const plString &str)
|
||||
{
|
||||
size_t catsize = GetSize() + str.GetSize();
|
||||
char *catstr = TRACKED_NEW char[catsize + 1];
|
||||
memcpy(catstr, s_str(), GetSize());
|
||||
memcpy(catstr + GetSize(), str.s_str(), str.GetSize());
|
||||
catstr[catsize] = 0;
|
||||
fUtf8Buffer.Steal(catstr, catsize);
|
||||
return *this;
|
||||
}
|
||||
|
||||
plString operator+(const plString &left, const plString &right)
|
||||
{
|
||||
size_t catsize = left.GetSize() + right.GetSize();
|
||||
char *catstr = TRACKED_NEW char[catsize + 1];
|
||||
memcpy(catstr, left.s_str(), left.GetSize());
|
||||
memcpy(catstr + left.GetSize(), right.s_str(), right.GetSize());
|
||||
catstr[catsize] = 0;
|
||||
|
||||
// Don't re-check UTF-8 on this
|
||||
plString str;
|
||||
str.fUtf8Buffer.Steal(catstr, catsize);
|
||||
return str;
|
||||
}
|
||||
|
||||
plStringStream &plStringStream::operator<<(const char *text)
|
||||
{
|
||||
size_t length = strlen(text);
|
||||
if (fLength + length > fBufSize) {
|
||||
char *bigger = new char[fBufSize * 2];
|
||||
memcpy(bigger, fBuffer, fBufSize);
|
||||
delete [] fBuffer;
|
||||
fBuffer = bigger;
|
||||
fBufSize *= 2;
|
||||
}
|
||||
memcpy(fBuffer + fLength, text, length);
|
||||
fLength += length;
|
||||
return *this;
|
||||
}
|
||||
|
||||
plStringStream &plStringStream::operator<<(int num)
|
||||
{
|
||||
char buffer[12];
|
||||
snprintf(buffer, 12, "%d", num);
|
||||
return operator<<(buffer);
|
||||
}
|
||||
|
||||
plStringStream &plStringStream::operator<<(unsigned int num)
|
||||
{
|
||||
char buffer[12];
|
||||
snprintf(buffer, 12, "%u", num);
|
||||
return operator<<(buffer);
|
||||
}
|
||||
|
||||
plStringStream &plStringStream::operator<<(char ch)
|
||||
{
|
||||
char buffer[2] = { ch, 0 };
|
||||
return operator<<(buffer);
|
||||
}
|
387
Sources/Plasma/CoreLib/plString.h
Normal file
387
Sources/Plasma/CoreLib/plString.h
Normal file
@ -0,0 +1,387 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#ifndef plString_Defined
|
||||
#define plString_Defined
|
||||
|
||||
#include "hsTypes.h"
|
||||
#include "hsUtils.h"
|
||||
#include <stddef.h>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
#define _TEMP_CONVERT_FROM_LITERAL(x) plString::FromUtf8((x))
|
||||
#define _TEMP_CONVERT_FROM_WCHAR_T(x) plString::FromWchar((x))
|
||||
|
||||
typedef unsigned int UniChar;
|
||||
|
||||
template <typename _Ch>
|
||||
class plStringBuffer
|
||||
{
|
||||
private:
|
||||
struct StringRef
|
||||
{
|
||||
unsigned int fRefs;
|
||||
const _Ch *fStringData;
|
||||
const size_t fSize;
|
||||
|
||||
StringRef(const _Ch *data, const size_t size)
|
||||
: fRefs(1), fStringData(data), fSize(size) { }
|
||||
|
||||
inline void AddRef() { ++fRefs; }
|
||||
inline void DecRef()
|
||||
{
|
||||
if (--fRefs == 0) {
|
||||
delete [] fStringData;
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
StringRef *fData;
|
||||
|
||||
public:
|
||||
plStringBuffer() : fData(0) { }
|
||||
|
||||
plStringBuffer(const plStringBuffer<_Ch> ©)
|
||||
{
|
||||
fData = copy.fData;
|
||||
if (fData)
|
||||
fData->AddRef();
|
||||
}
|
||||
|
||||
plStringBuffer(const _Ch *data, size_t size)
|
||||
{
|
||||
_Ch *copyData = new _Ch[size + 1];
|
||||
memcpy(copyData, data, size);
|
||||
copyData[size] = 0;
|
||||
|
||||
fData = new StringRef(copyData, size);
|
||||
}
|
||||
|
||||
~plStringBuffer<_Ch>()
|
||||
{
|
||||
if (fData)
|
||||
fData->DecRef();
|
||||
}
|
||||
|
||||
static plStringBuffer<_Ch> Steal(const _Ch *data, size_t size)
|
||||
{
|
||||
plStringBuffer<_Ch> string;
|
||||
string.fData = new StringRef(data, size);
|
||||
return string;
|
||||
}
|
||||
|
||||
plStringBuffer<_Ch> &operator=(const plStringBuffer<_Ch> ©)
|
||||
{
|
||||
if (copy.fData)
|
||||
copy.fData->AddRef();
|
||||
if (fData)
|
||||
fData->DecRef();
|
||||
fData = copy.fData;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const _Ch *GetData() const { return fData ? fData->fStringData : 0; }
|
||||
const size_t GetSize() const { return fData ? fData->fSize : 0; }
|
||||
};
|
||||
|
||||
|
||||
class plString
|
||||
{
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4146)
|
||||
enum {
|
||||
kSizeAuto = (size_t)(-2147483648L)
|
||||
};
|
||||
#pragma warning(pop)
|
||||
|
||||
enum CaseSense {
|
||||
kCaseSensitive, kCaseInsensitive
|
||||
};
|
||||
|
||||
public:
|
||||
static const plString Null;
|
||||
|
||||
private:
|
||||
plStringBuffer<char> fUtf8Buffer;
|
||||
|
||||
void IConvertFromUtf8(const char *utf8, size_t size, bool steal);
|
||||
void IConvertFromUtf16(const UInt16 *utf16, size_t size);
|
||||
void IConvertFromWchar(const wchar_t *wstr, size_t size);
|
||||
void IConvertFromIso8859_1(const char *astr, size_t size);
|
||||
|
||||
public:
|
||||
plString() { }
|
||||
|
||||
//plString(const char *utf8) { IConvertFromUtf8(utf8, kSizeAuto, false); }
|
||||
//plString(const wchar_t *wstr) { IConvertFromWchar(wstr, kSizeAuto); }
|
||||
plString(const plString ©) : fUtf8Buffer(copy.fUtf8Buffer) { }
|
||||
|
||||
//plString &operator=(const char *utf8) { IConvertFromUtf8(utf8, kSizeAuto, false); return *this; }
|
||||
//plString &operator=(const wchar_t *wstr) { IConvertFromWchar(wstr, kSizeAuto); return *this; }
|
||||
plString &operator=(const plString ©) { fUtf8Buffer = copy.fUtf8Buffer; return *this; }
|
||||
|
||||
plString &operator+=(const plString &str);
|
||||
|
||||
static inline plString FromUtf8(const char *utf8, size_t size = kSizeAuto)
|
||||
{
|
||||
plString str;
|
||||
str.IConvertFromUtf8(utf8, size, false);
|
||||
return str;
|
||||
}
|
||||
|
||||
static inline plString FromUtf16(const UInt16 *utf16, size_t size = kSizeAuto)
|
||||
{
|
||||
plString str;
|
||||
str.IConvertFromUtf16(utf16, size);
|
||||
return str;
|
||||
}
|
||||
|
||||
static inline plString FromWchar(const wchar_t *wstr, size_t size = kSizeAuto)
|
||||
{
|
||||
plString str;
|
||||
str.IConvertFromWchar(wstr, size);
|
||||
return str;
|
||||
}
|
||||
|
||||
static inline plString FromIso8859_1(const char *astr, size_t size = kSizeAuto)
|
||||
{
|
||||
plString str;
|
||||
str.IConvertFromIso8859_1(astr, size);
|
||||
return str;
|
||||
}
|
||||
|
||||
const char *c_str() const { return fUtf8Buffer.GetData(); }
|
||||
const char *s_str() const { return c_str() ? c_str() : ""; }
|
||||
plStringBuffer<char> ToUtf8() const { return fUtf8Buffer; }
|
||||
plStringBuffer<UInt16> ToUtf16() const;
|
||||
plStringBuffer<wchar_t> ToWchar() const;
|
||||
plStringBuffer<char> ToIso8859_1() const;
|
||||
|
||||
// For use in displaying characters in a GUI
|
||||
plStringBuffer<UniChar> GetUnicodeArray() const;
|
||||
|
||||
size_t GetSize() const { return fUtf8Buffer.GetSize(); }
|
||||
bool IsEmpty() const { return fUtf8Buffer.GetSize() == 0; }
|
||||
bool IsNull() const { return fUtf8Buffer.GetData() == 0; }
|
||||
|
||||
int ToInt(int base = 0) const;
|
||||
unsigned int ToUInt(int base = 0) const;
|
||||
float ToFloat() const;
|
||||
double ToDouble() const;
|
||||
|
||||
static plString Format(const char *fmt, ...);
|
||||
static plString IFormat(const char *fmt, va_list vptr);
|
||||
static plString Steal(const char *utf8, size_t size = kSizeAuto)
|
||||
{
|
||||
plString str;
|
||||
str.IConvertFromUtf8(utf8, size, true);
|
||||
return str;
|
||||
}
|
||||
|
||||
int Compare(const plString &str, CaseSense sense = kCaseSensitive) const
|
||||
{
|
||||
return (sense == kCaseSensitive) ? strcmp(s_str(), str.s_str())
|
||||
: stricmp(s_str(), str.s_str());
|
||||
}
|
||||
|
||||
int Compare(const char *str, CaseSense sense = kCaseSensitive) const
|
||||
{
|
||||
return (sense == kCaseSensitive) ? strcmp(s_str(), str)
|
||||
: stricmp(s_str(), str);
|
||||
}
|
||||
|
||||
bool operator==(const plString &other) const { return Compare(other) == 0; }
|
||||
bool operator!=(const plString &other) const { return Compare(other) != 0; }
|
||||
|
||||
int Find(char ch, CaseSense sense = kCaseSensitive) const;
|
||||
int FindReverse(char ch, CaseSense sense = kCaseSensitive) const;
|
||||
|
||||
plString TrimLeft(const char *charset = " \t\n\r") const;
|
||||
plString TrimRight(const char *charset = " \t\n\r") const;
|
||||
plString Trim(const char *charset = " \t\n\r") const;
|
||||
|
||||
plString Substr(int start, size_t size = kSizeAuto) const;
|
||||
plString Left(size_t size) const { return Substr(0, size); }
|
||||
plString Right(size_t size) const { return Substr(GetSize() - size, size); }
|
||||
|
||||
public:
|
||||
struct less : public std::binary_function<plString, plString, bool>
|
||||
{
|
||||
bool operator()(const plString &_L, const plString &_R) const
|
||||
{ return _L.Compare(_R, kCaseSensitive) < 0; }
|
||||
};
|
||||
|
||||
struct less_i : public std::binary_function<plString, plString, bool>
|
||||
{
|
||||
bool operator()(const plString &_L, const plString &_R) const
|
||||
{ return _L.Compare(_R, kCaseInsensitive) < 0; }
|
||||
};
|
||||
|
||||
struct equal : public std::binary_function<plString, plString, bool>
|
||||
{
|
||||
bool operator()(const plString &_L, const plString &_R) const
|
||||
{ return _L.Compare(_R, kCaseSensitive) == 0; }
|
||||
};
|
||||
|
||||
struct equal_i : public std::binary_function<plString, plString, bool>
|
||||
{
|
||||
bool operator()(const plString &_L, const plString &_R) const
|
||||
{ return _L.Compare(_R, kCaseInsensitive) == 0; }
|
||||
};
|
||||
|
||||
public:
|
||||
struct iterator
|
||||
{
|
||||
iterator() : m_ptr(nil), m_end(nil) { }
|
||||
iterator(const iterator ©) : m_ptr(copy.m_ptr), m_end(copy.m_end) { }
|
||||
|
||||
iterator &operator=(const iterator ©)
|
||||
{ m_ptr = copy.m_ptr; m_end = copy.m_end; return *this; }
|
||||
|
||||
iterator &operator++()
|
||||
{
|
||||
if ((*m_ptr & 0xF8) == 0xF0)
|
||||
m_ptr += 4;
|
||||
else if ((*m_ptr & 0xF0) == 0xE0)
|
||||
m_ptr += 3;
|
||||
else if ((*m_ptr & 0xE0) == 0xC0)
|
||||
m_ptr += 2;
|
||||
else
|
||||
m_ptr += 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator &operator+=(size_t delta)
|
||||
{
|
||||
while (delta) {
|
||||
operator++();
|
||||
--delta;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator+(size_t delta) const
|
||||
{
|
||||
iterator copy(*this);
|
||||
copy += delta;
|
||||
return copy;
|
||||
}
|
||||
|
||||
int operator-(const iterator &other) const
|
||||
{
|
||||
return (int)(m_ptr - other.m_ptr);
|
||||
}
|
||||
|
||||
bool operator==(const iterator &other) const { return m_ptr == other.m_ptr; }
|
||||
bool operator!=(const iterator &other) const { return m_ptr != other.m_ptr; }
|
||||
bool operator<(const iterator &other) const { return m_ptr < other.m_ptr; }
|
||||
bool operator>(const iterator &other) const { return m_ptr > other.m_ptr; }
|
||||
bool operator<=(const iterator &other) const { return m_ptr <= other.m_ptr; }
|
||||
bool operator>=(const iterator &other) const { return m_ptr >= other.m_ptr; }
|
||||
|
||||
UniChar operator*() const
|
||||
{
|
||||
UniChar ch;
|
||||
if ((*m_ptr & 0xF8) == 0xF0) {
|
||||
ch = (m_ptr[0] & 0x07) << 18;
|
||||
ch |= (m_ptr[1] & 0x3F) << 12;
|
||||
ch |= (m_ptr[2] & 0x3F) << 6;
|
||||
ch |= (m_ptr[3] & 0x3F);
|
||||
} else if ((*m_ptr & 0xF0) == 0xE0) {
|
||||
ch = (m_ptr[0] & 0x0F) << 12;
|
||||
ch |= (m_ptr[1] & 0x3F) << 6;
|
||||
ch |= (m_ptr[2] & 0x3F);
|
||||
} else if ((*m_ptr & 0xE0) == 0xC0) {
|
||||
ch = (m_ptr[0] & 0x1F) << 6;
|
||||
ch |= (m_ptr[1] & 0x3F);
|
||||
} else {
|
||||
ch = m_ptr[0];
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
bool AtEnd() const { return m_ptr >= m_end; }
|
||||
bool IsValid() const { return m_ptr != 0; }
|
||||
|
||||
private:
|
||||
friend class plString;
|
||||
iterator(const char *ptr, size_t size) : m_ptr(ptr), m_end(ptr + size) { }
|
||||
|
||||
const char *m_ptr;
|
||||
const char *m_end;
|
||||
};
|
||||
|
||||
iterator GetIterator() const { return iterator(s_str(), GetSize()); }
|
||||
|
||||
size_t GetUniCharCount() const
|
||||
{
|
||||
iterator iter = GetIterator();
|
||||
size_t count = 0;
|
||||
while (!iter.AtEnd()) {
|
||||
++iter;
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private:
|
||||
friend plString operator+(const plString &left, const plString &right);
|
||||
};
|
||||
|
||||
plString operator+(const plString &left, const plString &right);
|
||||
|
||||
|
||||
class plStringStream
|
||||
{
|
||||
public:
|
||||
plStringStream() : fBufSize(256), fLength(0)
|
||||
{
|
||||
fBuffer = new char[fBufSize];
|
||||
}
|
||||
~plStringStream() { delete [] fBuffer; }
|
||||
|
||||
plStringStream &operator<<(const char *text);
|
||||
plStringStream &operator<<(int num);
|
||||
plStringStream &operator<<(unsigned int num);
|
||||
plStringStream &operator<<(char ch);
|
||||
|
||||
plStringStream &operator<<(const plString &text)
|
||||
{
|
||||
return operator<<(text.s_str());
|
||||
}
|
||||
|
||||
size_t GetLength() const { return fLength; }
|
||||
plString GetString() { return plString::FromUtf8(fBuffer, fLength); }
|
||||
|
||||
private:
|
||||
char *fBuffer;
|
||||
size_t fBufSize;
|
||||
size_t fLength;
|
||||
};
|
||||
|
||||
#endif //plString_Defined
|
Reference in New Issue
Block a user