/*==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 .
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
#include
#include
/* 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
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 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 ToUtf8() const { return fUtf8Buffer; }
plStringBuffer ToUtf16() const;
plStringBuffer ToWchar() const;
plStringBuffer ToIso8859_1() const;
// For use in displaying characters in a GUI
plStringBuffer 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
{
bool operator()(const plString &_L, const plString &_R) const
{ return _L.Compare(_R, kCaseSensitive) < 0; }
};
struct less_i : public std::binary_function
{
bool operator()(const plString &_L, const plString &_R) const
{ return _L.Compare(_R, kCaseInsensitive) < 0; }
};
struct equal : public std::binary_function
{
bool operator()(const plString &_L, const plString &_R) const
{ return _L.Compare(_R, kCaseSensitive) == 0; }
};
struct equal_i : public std::binary_function
{
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