/*==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 { #pragma warning(push) #pragma warning(disable : 4146) enum { kSizeAuto = (size_t)(-2147483648L) }; #pragma warning(pop) 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); } 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 &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