/* TA3D, a remake of Total Annihilation Copyright (C) 2005 Roland BROCHARD 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA*/ #ifndef _SHARED_UTIL_W_STRING_H__ #define _SHARED_UTIL_W_STRING_H__ # include # include # include # include # include #include "data_types.h" #ifdef __MINGW32__ typedef unsigned char byte; #endif //! \name Macros for Shared::Util::String //@{ //! Macro to append some data to the string # define TA3D_WSTR_APPEND std::stringstream out; \ out << v; \ append(out.str());\ return *this //! Macro to convert the string into a given type # define TA3D_WSTR_CAST_OP(X) X v; \ fromString(v, *this); \ return v; //! Macro to append the value of a boolean (true -> "true", false -> "false") # define TA3D_WSTR_APPEND_BOOL(X) append(X ? "true" : "false") //@} // Macros for Shared::Util::String # define TA3D_WSTR_SEPARATORS " \t\r\n" #ifndef WIN32 using Shared::Platform::byte; #endif using namespace Shared::Platform; namespace Shared { namespace Util { /*! \class String ** \brief A String implementation for `TA3D` ** ** \code ** Shared::Util::String a("abcd"); ** std::cout << a << std::endl; // display: `abcd` ** Shared::Util::String b(10 + 2); ** std::cout << b << std::endl; // display: `12` ** Shared::Util::String c(10.3); ** std::cout << c << std::endl; // display: `10.3` ** ** // The same with the operator `<<` ** Shared::Util::String d; ** d << "Value : " << 42; ** std::cout << d << std::endl; // display: `Value : 42` ** \endcode ** ** Here is an example to show when to use static methods : ** \code ** Shared::Util::String s = "HelLo wOrLd"; ** std::cout << Shared::Util::String::ToLower(s) << std::endl; // `hello world` ** std::cout << s << std::endl; // `HelLo wOrLd` ** std::cout << s.toLower() << std::endl; // `hello world` ** std::cout << s << std::endl; // `hello world` ** \endcode */ class String : public std::string { public: //! A String list typedef std::list List; //! A String vector typedef std::vector Vector; //! Char Case enum CharCase { //! The string should remain untouched soCaseSensitive, //! The string should be converted to lowercase soIgnoreCase }; public: /*! ** \brief Copy then Convert the case (lower case) of characters in the string using the UTF8 charset ** \param s The string to convert ** \return A new string */ static String ToLower(const char* s) {return String(s).toLower();} /*! ** \brief Copy then Convert the case (lower case) of characters in the string using the UTF8 charset ** \param s The string to convert ** \return A new string */ static String ToLower(const wchar_t* s) {return String(s).toLower();} /*! ** \brief Copy then Convert the case (lower case) of characters in the string using the UTF8 charset ** \param s The string to convert ** \return A new string */ static String ToLower(const String& s) {return String(s).toLower();} /*! ** \brief Copy then Convert the case (upper case) of characters in the string using the UTF8 charset ** \param s The string to convert ** \return A new string */ static String ToUpper(const char* s) {return String(s).toUpper();} /*! ** \brief Copy then Convert the case (upper case) of characters in the string using the UTF8 charset ** \param s The string to convert ** \return A new string */ static String ToUpper(const wchar_t* s) {return String(s).toUpper();} /*! ** \brief Copy then Convert the case (upper case) of characters in the string using the UTF8 charset ** \param s The string to convert ** \return A new string */ static String ToUpper(const String& s) {return String(s).toUpper();} /*! ** \brief Remove trailing and leading spaces ** \param s The string to convert ** \param trimChars The chars to remove ** \return A new string */ static String Trim(const char* s, const String& trimChars = TA3D_WSTR_SEPARATORS) {return String(s).trim(trimChars);} /*! ** \brief Remove trailing and leading spaces ** \param s The string to convert ** \param trimChars The chars to remove ** \return A new string */ static String Trim(const wchar_t* s, const String& trimChars = TA3D_WSTR_SEPARATORS) {return String(s).trim(trimChars);} /*! ** \brief Remove trailing and leading spaces ** \param s The string to convert ** \param trimChars The chars to remove ** \return A new string */ static String Trim(const String& s, const String& trimChars = TA3D_WSTR_SEPARATORS) {return String(s).trim(trimChars);} /*! ** \brief Convert all antislashes into slashes ** \param s The string to convert ** \return A new string */ static String ConvertAntiSlashesIntoSlashes(const String& s) {return String(s).convertAntiSlashesIntoSlashes();} /*! ** \brief Convert all slashes into antislashes ** \param s The string to convert ** \return A new string */ static String ConvertSlashesIntoAntiSlashes(const String& s) {return String(s).convertSlashesIntoAntiSlashes();} /*! ** \brief Extract the key and its value from a string (mainly provided by TDF files) ** ** \param s A line (ex: ` category=core vtol ctrl_v level1 weapon notsub ;`) ** \param[out] key The key that has been found ** \param[out] value The associated value ** \param chcase The key will be converted to lowercase if equals to `soIgnoreCase` ** ** \code ** String k, v; ** ** // -> k='category' ** // -> v='core vtol ctrl_v level1 weapon notsub' ** String::ToKeyValue(" category=core vtol ctrl_v level1 weapon notsub ;", k, v) ** ** // -> k='foo' ** // -> v='bar' ** String::ToKeyValue(" foo = bar ; "); ** ** // -> k='}' v='' ** String::ToKeyValue(" } ", k, v); ** ** // -> k='[' v='Example of Section' ** String::ToKeyValue(" [Example of Section] ", k, v); ** ** // -> k='foo' v='bar' ** String::ToKeyValue(" foo=bar; // comment", k, v); ** ** // -> k='foo' v='bar' ** String::ToKeyValue(" foo=bar; // comments here; ", k, v); ** \endcode */ static void ToKeyValue(const String& s, String& key, String& value, const enum CharCase chcase = soCaseSensitive); /*! ** \brief Find the index of a string in a vector ** \param l The vector ** \param s The string to look for ** \return The index of the string found, -1 otherwise */ static int FindInList(const String::Vector& l, const char* s); static int FindInList(const String::Vector& l, const String& s); /*! ** \brief Convert a string from ASCII to UTF8 ** \param s The string to convert ** \return A new Null-terminated String (must be deleted with the keyword `delete[]`), even if s is NULL */ static char* ConvertToUTF8(const char* s); /*! ** \brief Convert a string from ASCII to UTF8 ** \param s The string to convert ** \param len The length of the string ** \param[out] The new size ** \return A new Null-terminated String (must be deleted with the keyword `delete[]`), even if s is NULL */ static char* ConvertToUTF8(const char* s, const Shared::Platform::uint32 len); static char* ConvertToUTF8(const char* s, const Shared::Platform::uint32 len, Shared::Platform::uint32& newSize); /*! ** \brief Convert a string from ASCII to UTF8 ** \param s The string to convert ** \return A new String */ static String ConvertToUTF8(const String& s); static char* ConvertFromUTF8(const char* str); /*! ** \brief Formatted string ** \param format The format of the new string ** \return A new string */ static String Format(const String& f, ...); static String Format(const char* f, ...); public: //! \name Constructors and Destructor //@{ //! Default constructor String() :std::string() {} //! Constructor by copy String(const String& v, size_type pos = 0, size_type n = npos) :std::string(v, pos, n) {} //! Constructor with a default value from a std::string String(const std::string& v) :std::string(v) {} //! Constructor with a default value from a wide string (wchar_t*) String(const wchar_t* v) :std::string() {if (v) *this << v;} //! Constructor with a default value from a string (char*) String(const char* v) :std::string() { if (v) append(v); } //! Constructor with a default value from a string (char*) and a length String(const char* v, String::size_type n) :std::string(v, n) {} //! Constructor with a default value from a single char String(const char v) :std::string() {*this += v;} //! Constructor with a default value from an int (8 bits) String(const int8_t v) :std::string() {*this << v;} //! Constructor with a default value from an int (16 bits) String(const int16_t v) :std::string() {*this << v;} //! Constructor with a default value from an int (32 bits) String(const int32_t v) :std::string() {*this << v;} //! Constructor with a default value from an int (64 bits) String(const int64_t v) :std::string() {*this << v;} //! Constructor with a default value from an unsigned int (8 bits) String(const uint8_t v) :std::string() {*this << v;} //! Constructor with a default value from an unsigned int (16 bits) String(const uint16_t v) :std::string() {*this << v;} //! Constructor with a default value from an unsigned int (32 bits) String(const uint32_t v) :std::string() {*this << v;} //! Constructor with a default value from an unsigned int (64 bits) String(const uint64_t v) :std::string() {*this << v;} //! Constructor with a default value from a float String(const float v) :std::string() {*this << v;} //! Constructor with a default value from a double String(const double v) :std::string() {*this << v;} //! Destructor ~String() {} //@} //! \name The operator `<<` //@{ //! Append a string (char*) String& operator << (const char* v) {append(v);return *this;} //! Append a string (stl) String& operator << (const std::string& v) {append(v);return *this;} //! Append a string (Shared::Util::String) String& operator << (const String& v) {append(v);return *this;} //! Append a single char String& operator << (const char v) {*(static_cast(this)) += v; return *this;} //! Append a wide string (wchar_t*) String& operator << (const wchar_t* v); //! Append an int (8 bits) String& operator << (const int8_t v) {TA3D_WSTR_APPEND;} //! Append an unsigned int (8 bits) String& operator << (const uint8_t v) {TA3D_WSTR_APPEND;} //! Append an int (16 bits) String& operator << (const int16_t v) {TA3D_WSTR_APPEND;} //! Append an unsigned int (16 bits) String& operator << (const uint16_t v) {TA3D_WSTR_APPEND;} //! Append an int (32 bits) String& operator << (const int32_t v) {TA3D_WSTR_APPEND;} //! Append an unsigned int (32 bits) String& operator << (const uint32_t v) {TA3D_WSTR_APPEND;} //! Append an int (64 bits) String& operator << (const int64_t v) {TA3D_WSTR_APPEND;} //! Append an unsigned int (64 bits) String& operator << (const uint64_t v) {TA3D_WSTR_APPEND;} //! Convert then Append a float String& operator << (const float v) {TA3D_WSTR_APPEND;} //! Convert then Append a double String& operator << (const double v) {TA3D_WSTR_APPEND;} //! Convert then Append a boolean (will be converted into "true" or "false") String& operator << (const bool v) {TA3D_WSTR_APPEND_BOOL(v);return *this;} //@} //! \name Convertions //@{ //! Convert this string into an int (8 bits) int8_t toInt8() const {TA3D_WSTR_CAST_OP(int8_t);} //! Convert this string into an int (16 bits) int16_t toInt16() const {TA3D_WSTR_CAST_OP(int16_t);} //! Convert this string into an int (32 bits) int32_t toInt32() const {TA3D_WSTR_CAST_OP(int32_t);} //! Convert this string into an int (64 bits) int64_t toInt64() const {TA3D_WSTR_CAST_OP(int64_t);} //! Convert this string into an unsigned int (8 bits) uint8_t toUInt8() const {TA3D_WSTR_CAST_OP(uint8_t);} //! Convert this string into an unsigned int (16 bits) uint16_t toUInt16() const {TA3D_WSTR_CAST_OP(uint16_t);} //! Convert this string into an unsigned int (32 bits) uint32_t toUInt32() const {TA3D_WSTR_CAST_OP(uint32_t);} //! Convert this string into an unsigned int (64 bits) uint64_t toUInt64() const {TA3D_WSTR_CAST_OP(uint64_t);} //! Convert this string into a float float toFloat() const {TA3D_WSTR_CAST_OP(float);} //! Convert this string into a float with a default value if empty float toFloat(const float def) const {if (empty()) return def;TA3D_WSTR_CAST_OP(float);} //! Convert this string into a double double toDouble() const {TA3D_WSTR_CAST_OP(double);} //! Convert this string into a bool (true if the lower case value is equals to "true", "1" or "on") bool toBool() const; //! \name The operator `+=` (with the same abilities than the operator `<<`) //@{ //! Append a string (char*) String& operator += (const char* v) {append(v); return *this;} //! Append a string (stl) String& operator += (const std::string& v) {append(v); return *this;} //! Append a string (Shared::Util::String) String& operator += (const Shared::Util::String& v) {append(v); return *this; } //! Append a single char String& operator += (const char v) {*(static_cast(this)) += (char)v; return *this;} //! Append a wide string (wchar_t*) String& operator += (const wchar_t* v) {*this << v; return *this;} //! Append an int (8 bits) String& operator += (const int8_t v) {*this << v; return *this;} //! Append an unsigned int (8 bits) String& operator += (const uint8_t v) {*this << v; return *this;} //! Append an int (16 bits) String& operator += (const int16_t v) {*this << v; return *this; } //! Append an unsigned int (16 bits) String& operator += (const uint16_t v) {*this << v; return *this; } //! Append an int (32 bits) String& operator += (const int32_t v) {*this << v; return *this; } //! Append an unsigned int (32 bits) String& operator += (const uint32_t v) {*this << v; return *this; } //! Append an int (64 bits) String& operator += (const int64_t v) {*this << v; return *this; } //! Append an unsigned int (64 bits) String& operator += (const uint64_t v) {*this << v; return *this; } //! Convert then Append a float String& operator += (const float v) {*this << v; return *this; } //! Convert then Append a double String& operator += (const double v) {*this << v; return *this; } //! Convert then Append a boolean (will be converted into "true" or "false") String& operator += (const bool v) {TA3D_WSTR_APPEND_BOOL(v); return *this; } //@} //! \name The operator `+` //@{ //! Create a new String from the concatenation of *this and a string const String operator + (const String& rhs) { return String(*this) += rhs; } //! Create a new String from the concatenation of *this and a char const String operator + (const char rhs) { return String(*this) += rhs; } //! Create a new String from the concatenation of *this and a widechar const String operator + (const wchar_t rhs) { return String(*this) += rhs; } //! Create a new String from the concatenation of *this and a const char* const String operator + (const char* rhs) { return String(*this) += rhs; } //! Create a new String from the concatenation of *this and a wide string const String operator + (const wchar_t* rhs) { return String(*this) += rhs; } //! Create a new String from the concatenation of *this and a signed int (8 bits) const String operator + (const int8_t rhs) { return String(*this) += rhs; } //! Create a new String from the concatenation of *this and a signed int (16 bits) const String operator + (const int16_t rhs) { return String(*this) += rhs; } //! Create a new String from the concatenation of *this and a signed int (32 bits) const String operator + (const int32_t rhs) { return String(*this) += rhs; } //! Create a new String from the concatenation of *this and a signed int (64 bits) const String operator + (const int64_t rhs) { return String(*this) += rhs; } //! Create a new String from the concatenation of *this and an unsigned int (8 bits) const String operator + (const uint8_t rhs) { return String(*this) += rhs; } //! Create a new String from the concatenation of *this and an unsigned int (16 bits) const String operator + (const uint16_t rhs) { return String(*this) += rhs; } //! Create a new String from the concatenation of *this and an unsigned int (32 bits) const String operator + (const uint32_t rhs) { return String(*this) += rhs; } //! Create a new String from the concatenation of *this and an unsigned int (64 bits) const String operator + (const uint64_t rhs) { return String(*this) += rhs; } //! Create a new String from the concatenation of *this and a float const String operator + (const float rhs) { return String(*this) += rhs; } //! Create a new String from the concatenation of *this and a double const String operator + (const double rhs) { return String(*this) += rhs; } //@} //! \name Case convertion //@{ /*! ** \brief Convert the case (lower case) of characters in the string using the UTF8 charset ** \return Returns *this */ String& toLower(); /*! ** \brief Convert the case (upper case) of characters in the string using the UTF8 charset ** \return Returns *this */ String& toUpper(); //@} Case convertion /*! ** \brief Remove trailing and leading spaces ** \param trimChars The chars to remove ** \return Returns *this */ String& trim(const String& trimChars = TA3D_WSTR_SEPARATORS); //! \name Split //@{ /*! ** \brief Divide a string into several parts ** \param[out] All found parts ** \param sepearators Sequence of chars considered as a separator ** \param emptyBefore True to clear the vector before fulfill it ** \warning Do not take care of string representation (with `'` or `"`) */ void split(String::Vector& out, const String& separators = TA3D_WSTR_SEPARATORS, const bool emptyBefore = true) const; /*! ** \brief Divide a string into several parts ** \param[out] All found parts ** \param sepearators Sequence of chars considered as a separator ** \param emptyBefore True to clear the list before fulfill it ** \warning Do not take care of string representation (with `'` or `"`) */ void split(String::List& out, const String& separators = TA3D_WSTR_SEPARATORS, const bool emptyBefore = true) const; //@} Split /*! ** \brief Extract the key and its value from a string (mainly provided by TDF files) ** ** \param[out] key The key that has been found ** \param[out] value The associated value ** ** \see String::ToKeyValue() */ void toKeyValue(String& key, String& value, const enum CharCase chcase = soCaseSensitive) const {ToKeyValue(*this, key, value, chcase);} /*! ** \brief Convert all antislashes into slashes ** \return Returns *this */ String& convertAntiSlashesIntoSlashes(); /*! ** \brief Convert all slashes into antislashes ** \return Returns *this */ String& convertSlashesIntoAntiSlashes(); /*! ** \brief Get the hash value of this string */ Shared::Platform::uint32 hashValue() const; /*! ** \brief Convert the string from ASCII to UTF8 ** \return Always *this */ String& convertToUTF8() {*this = ConvertToUTF8(*this); return *this;} /*! ** \brief Replace a substr by another one ** \param toSearch The string to look for ** \param replaceWith The string replacement ** \param option Option when looking for the string `toSearch` ** \return Always *this */ String& findAndReplace(const String& toSearch, const String& replaceWith, const enum String::CharCase option = soCaseSensitive); String& findAndReplace(char toSearch, const char replaceWith, const enum String::CharCase option = soCaseSensitive); /*! ** \brief Reset the current value with a formatted string ** \param f The format of the new string ** \return Always *this */ String& format(const String& f, ...); String& format(const char* f, ...); /*! ** \brief Append a formatted string ** \param f The format of the new string ** \return Always *this */ String& appendFormat(const String& f, ...); String& appendFormat(const char* f, ...); String& vappendFormat(const char* f, va_list parg); /*! ** \brief Detect if the string matches the given pattern ** \param pattern ** \return true if match */ bool match(const String &pattern); /*! ** \brief returns a substring assuming current string is an UTF8 String ** \param pos ** \param len ** \return the substring */ String substrUTF8(int pos = 0, int len = -1) const; /*! ** \brief returns the String size assuming it's in UTF8 ** \return the number of UTF8 symbols */ int sizeUTF8() const; private: /*! ** \brief Convert a string into another type, given by the template parameter `T` ** \param[out] t The destination variable ** \param s The string to convert ** \param f The base to use for the convertion (std::hex, std::dec, ...) ** \return True if the operation succeeded, False otherwise */ template bool fromString(T& t, const String& s) const { std::istringstream iss(s); if (s.size() > 2) { if(s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) iss >> std::hex; else if (s[0] == '0' && s[1] != 'x' && s[1] != 'X') iss >> std::oct; else iss >> std::dec; } else iss >> std::dec; return !(iss >> t).fail(); } #ifndef WIN32 static int ASCIItoUTF8(const Shared::Platform::byte c, Shared::Platform::byte *out); #else static int ASCIItoUTF8(const byte c, byte *out); #endif }; // class String //int ASCIItoUTF8(const byte c, byte *out); /*! ** \brief Convert an UTF-8 String into a WideChar String ** \todo This class must be removed as soon as possible and is only here to prevent against ** stange bugs with the previous implementation */ struct WString { public: WString(const char* s); WString(const String& str); void fromUtf8(const char* s, size_t length); const wchar_t* cw_str() const {return pBuffer;} private: wchar_t pBuffer[5120]; }; void strrev(char *p); void strrev_utf8(char *p); void strrev_utf8(std::string &p); bool is_string_all_ascii(std::string str); }} // namespace TA3D #endif // _SHARED_UTIL_W_STRING_H__