Michael Hansen
13 years ago
3 changed files with 1062 additions and 0 deletions
@ -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); |
||||
} |
@ -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
|
Loading…
Reference in new issue