You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
429 lines
13 KiB
429 lines
13 KiB
/*==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 "HeadSpin.h" |
|
#include <stddef.h> |
|
#include <vector> |
|
#include <functional> |
|
|
|
/* NOTE & TODO: |
|
* These macros are intentionally annoyingly named, to mark what code |
|
* needs to be cleaned up after a larger portion of Plasma is converted |
|
* to plString. |
|
*/ |
|
#define _TEMP_CONVERT_FROM_LITERAL(x) plString::FromUtf8((x)) |
|
#define _TEMP_CONVERT_FROM_WCHAR_T(x) plString::FromWchar((x)) |
|
#define _TEMP_CONVERT_TO_CONST_CHAR(x) ((x).c_str()) |
|
#define _TEMP_CONVERT_TO_WCHAR_T(x) ((x).ToWchar().GetData()) |
|
|
|
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(nil) { } |
|
|
|
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; } |
|
size_t GetSize() const { return fData ? fData->fSize : 0; } |
|
}; |
|
|
|
|
|
class plString |
|
{ |
|
enum { |
|
kSizeAuto = (size_t)(0x80000000) |
|
}; |
|
|
|
public: |
|
static const plString Null; |
|
|
|
private: |
|
plStringBuffer<char> fUtf8Buffer; |
|
|
|
void IConvertFromUtf8(const char *utf8, size_t size, bool steal); |
|
void IConvertFromUtf16(const uint16_t *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_t *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 char *safe = "") const { return c_str() ? c_str() : safe; } |
|
char CharAt(size_t position) const { return c_str()[position]; } |
|
|
|
plStringBuffer<char> ToUtf8() const { return fUtf8Buffer; } |
|
plStringBuffer<uint16_t> 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; |
|
} |
|
|
|
enum CaseSensitivity { |
|
kCaseSensitive, kCaseInsensitive |
|
}; |
|
|
|
int Compare(const plString &str, CaseSensitivity sense = kCaseSensitive) const |
|
{ |
|
if (c_str() == str.c_str()) |
|
return 0; |
|
|
|
return (sense == kCaseSensitive) ? strcmp(s_str(), str.s_str()) |
|
: stricmp(s_str(), str.s_str()); |
|
} |
|
|
|
int Compare(const char *str, CaseSensitivity sense = kCaseSensitive) const |
|
{ |
|
return (sense == kCaseSensitive) ? strcmp(s_str(), str) |
|
: stricmp(s_str(), str); |
|
} |
|
|
|
int CompareN(const plString &str, size_t count, CaseSensitivity sense = kCaseSensitive) const |
|
{ |
|
if (c_str() == str.c_str()) |
|
return 0; |
|
|
|
return (sense == kCaseSensitive) ? strncmp(s_str(), str.s_str(), count) |
|
: strnicmp(s_str(), str.s_str(), count); |
|
} |
|
|
|
int CompareN(const char *str, size_t count, CaseSensitivity sense = kCaseSensitive) const |
|
{ |
|
return (sense == kCaseSensitive) ? strncmp(s_str(), str, count) |
|
: strnicmp(s_str(), str, count); |
|
} |
|
|
|
bool operator<(const plString &other) const { return Compare(other) < 0; } |
|
bool operator==(const plString &other) const { return Compare(other) == 0; } |
|
bool operator!=(const plString &other) const { return Compare(other) != 0; } |
|
|
|
int Find(char ch, CaseSensitivity sense = kCaseSensitive) const; |
|
int FindLast(char ch, CaseSensitivity sense = kCaseSensitive) const; |
|
|
|
int Find(const char *str, CaseSensitivity sense = kCaseSensitive) const; |
|
int Find(const plString &str, CaseSensitivity sense = kCaseSensitive) const |
|
{ return Find(str.c_str(), sense); } |
|
|
|
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); } |
|
|
|
// NOTE: Does ::Compare(blah, kCaseInsensitive) make more sense? If |
|
// so, use that instead -- it's faster and more efficient! |
|
plString ToUpper() const; |
|
plString ToLower() const; |
|
|
|
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++(int) |
|
{ |
|
iterator iter_save = *this; |
|
(void) operator++(); |
|
return iter_save; |
|
} |
|
|
|
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 &append(const char *data, size_t length); |
|
|
|
plStringStream &operator<<(const char *text); |
|
plStringStream &operator<<(int num); |
|
plStringStream &operator<<(unsigned int num); |
|
plStringStream &operator<<(char ch) { return append(&ch, 1); } |
|
|
|
plStringStream &operator<<(const plString &text) |
|
{ |
|
return append(text.s_str(), text.GetSize()); |
|
} |
|
|
|
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
|
|
|