nuclear@0: // Copyright (C) 2002-2005 Nikolaus Gebhardt nuclear@0: // This file is part of the "Irrlicht Engine" and the "irrXML" project. nuclear@0: // For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h nuclear@0: nuclear@0: #ifndef __IRR_STRING_H_INCLUDED__ nuclear@0: #define __IRR_STRING_H_INCLUDED__ nuclear@0: nuclear@0: #include "irrTypes.h" nuclear@0: nuclear@0: namespace irr nuclear@0: { nuclear@0: namespace core nuclear@0: { nuclear@0: nuclear@0: //! Very simple string class with some useful features. nuclear@0: /** string and string work both with unicode AND ascii, nuclear@0: so you can assign unicode to string and ascii to string nuclear@0: (and the other way round) if your ever would want to. nuclear@0: Note that the conversation between both is not done using an encoding. nuclear@0: nuclear@0: Known bugs: nuclear@0: Special characters like 'Ä', 'Ü' and 'Ö' are ignored in the nuclear@0: methods make_upper, make_lower and equals_ignore_case. nuclear@0: */ nuclear@0: template nuclear@0: class string nuclear@0: { nuclear@0: public: nuclear@0: nuclear@0: //! Default constructor nuclear@0: string() nuclear@0: : array(0), allocated(1), used(1) nuclear@0: { nuclear@0: array = new T[1]; nuclear@0: array[0] = 0x0; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: nuclear@0: //! Constructor nuclear@0: string(const string& other) nuclear@0: : array(0), allocated(0), used(0) nuclear@0: { nuclear@0: *this = other; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //! Constructs a string from an int nuclear@0: string(int number) nuclear@0: : array(0), allocated(0), used(0) nuclear@0: { nuclear@0: // store if negative and make positive nuclear@0: nuclear@0: bool negative = false; nuclear@0: if (number < 0) nuclear@0: { nuclear@0: number *= -1; nuclear@0: negative = true; nuclear@0: } nuclear@0: nuclear@0: // temporary buffer for 16 numbers nuclear@0: nuclear@0: c8 tmpbuf[16]; nuclear@0: tmpbuf[15] = 0; nuclear@0: s32 idx = 15; nuclear@0: nuclear@0: // special case '0' nuclear@0: nuclear@0: if (!number) nuclear@0: { nuclear@0: tmpbuf[14] = '0'; nuclear@0: *this = &tmpbuf[14]; nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: // add numbers nuclear@0: nuclear@0: while(number && idx) nuclear@0: { nuclear@0: idx--; nuclear@0: tmpbuf[idx] = (c8)('0' + (number % 10)); nuclear@0: number = number / 10; nuclear@0: } nuclear@0: nuclear@0: // add sign nuclear@0: nuclear@0: if (negative) nuclear@0: { nuclear@0: idx--; nuclear@0: tmpbuf[idx] = '-'; nuclear@0: } nuclear@0: nuclear@0: *this = &tmpbuf[idx]; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: nuclear@0: //! Constructor for copying a string from a pointer with a given lenght nuclear@0: template nuclear@0: string(const B* c, s32 lenght) nuclear@0: : array(0), allocated(0), used(0) nuclear@0: { nuclear@0: if (!c) nuclear@0: return; nuclear@0: nuclear@0: allocated = used = lenght+1; nuclear@0: array = new T[used]; nuclear@0: nuclear@0: for (s32 l = 0; l nuclear@0: string(const B* c) nuclear@0: : array(0),allocated(0), used(0) nuclear@0: { nuclear@0: *this = c; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: nuclear@0: //! destructor nuclear@0: ~string() nuclear@0: { nuclear@0: delete [] array; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: nuclear@0: //! Assignment operator nuclear@0: string& operator=(const string& other) nuclear@0: { nuclear@0: if (this == &other) nuclear@0: return *this; nuclear@0: nuclear@0: delete [] array; nuclear@0: allocated = used = other.size()+1; nuclear@0: array = new T[used]; nuclear@0: nuclear@0: const T* p = other.c_str(); nuclear@0: for (s32 i=0; i nuclear@0: string& operator=(const B* c) nuclear@0: { nuclear@0: if (!c) nuclear@0: { nuclear@0: if (!array) nuclear@0: { nuclear@0: array = new T[1]; nuclear@0: allocated = 1; nuclear@0: used = 1; nuclear@0: } nuclear@0: array[0] = 0x0; nuclear@0: return *this; nuclear@0: } nuclear@0: nuclear@0: if ((void*)c == (void*)array) nuclear@0: return *this; nuclear@0: nuclear@0: s32 len = 0; nuclear@0: const B* p = c; nuclear@0: while(*p) nuclear@0: { nuclear@0: ++len; nuclear@0: ++p; nuclear@0: } nuclear@0: nuclear@0: // we'll take the old string for a while, because the new string could be nuclear@0: // a part of the current string. nuclear@0: T* oldArray = array; nuclear@0: nuclear@0: allocated = used = len+1; nuclear@0: array = new T[used]; nuclear@0: nuclear@0: for (s32 l = 0; l operator+(const string& other) nuclear@0: { nuclear@0: string str(*this); nuclear@0: str.append(other); nuclear@0: nuclear@0: return str; nuclear@0: } nuclear@0: nuclear@0: //! Add operator for strings, ascii and unicode nuclear@0: template nuclear@0: string operator+(const B* c) nuclear@0: { nuclear@0: string str(*this); nuclear@0: str.append(c); nuclear@0: nuclear@0: return str; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: nuclear@0: //! Direct access operator nuclear@0: T& operator [](const s32 index) const nuclear@0: { nuclear@0: _IRR_DEBUG_BREAK_IF(index>=used) // bad index nuclear@0: nuclear@0: return array[index]; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //! Comparison operator nuclear@0: bool operator ==(const T* str) const nuclear@0: { nuclear@0: int i; nuclear@0: for(i=0; array[i] && str[i]; ++i) nuclear@0: if (array[i] != str[i]) nuclear@0: return false; nuclear@0: nuclear@0: return !array[i] && !str[i]; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: nuclear@0: //! Comparison operator nuclear@0: bool operator ==(const string& other) const nuclear@0: { nuclear@0: for(s32 i=0; array[i] && other.array[i]; ++i) nuclear@0: if (array[i] != other.array[i]) nuclear@0: return false; nuclear@0: nuclear@0: return used == other.used; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: nuclear@0: //! Is smaller operator nuclear@0: bool operator <(const string& other) const nuclear@0: { nuclear@0: for(s32 i=0; array[i] && other.array[i]; ++i) nuclear@0: if (array[i] != other.array[i]) nuclear@0: return (array[i] < other.array[i]); nuclear@0: nuclear@0: return used < other.used; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: nuclear@0: //! Equals not operator nuclear@0: bool operator !=(const string& other) const nuclear@0: { nuclear@0: return !(*this == other); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: nuclear@0: //! Returns length of string nuclear@0: /** \return Returns length of the string in characters. */ nuclear@0: s32 size() const nuclear@0: { nuclear@0: return used-1; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: nuclear@0: //! Returns character string nuclear@0: /** \return Returns pointer to C-style zero terminated string. */ nuclear@0: const T* c_str() const nuclear@0: { nuclear@0: return array; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: nuclear@0: //! Makes the string lower case. nuclear@0: void make_lower() nuclear@0: { nuclear@0: const T A = (T)'A'; nuclear@0: const T Z = (T)'Z'; nuclear@0: const T diff = (T)'a' - A; nuclear@0: nuclear@0: for (s32 i=0; i=A && array[i]<=Z) nuclear@0: array[i] += diff; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: nuclear@0: nuclear@0: //! Makes the string upper case. nuclear@0: void make_upper() nuclear@0: { nuclear@0: const T a = (T)'a'; nuclear@0: const T z = (T)'z'; nuclear@0: const T diff = (T)'A' - a; nuclear@0: nuclear@0: for (s32 i=0; i=a && array[i]<=z) nuclear@0: array[i] += diff; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: nuclear@0: nuclear@0: //! Compares the string ignoring case. nuclear@0: /** \param other: Other string to compare. nuclear@0: \return Returns true if the string are equal ignoring case. */ nuclear@0: bool equals_ignore_case(const string& other) const nuclear@0: { nuclear@0: for(s32 i=0; array[i] && other[i]; ++i) nuclear@0: if (toLower(array[i]) != toLower(other[i])) nuclear@0: return false; nuclear@0: nuclear@0: return used == other.used; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //! compares the first n characters of the strings nuclear@0: bool equalsn(const string& other, int len) nuclear@0: { nuclear@0: int i; nuclear@0: for(i=0; array[i] && other[i] && i < len; ++i) nuclear@0: if (array[i] != other[i]) nuclear@0: return false; nuclear@0: nuclear@0: // if one (or both) of the strings was smaller then they nuclear@0: // are only equal if they have the same lenght nuclear@0: return (i == len) || (used == other.used); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //! compares the first n characters of the strings nuclear@0: bool equalsn(const T* str, int len) nuclear@0: { nuclear@0: int i; nuclear@0: for(i=0; array[i] && str[i] && i < len; ++i) nuclear@0: if (array[i] != str[i]) nuclear@0: return false; nuclear@0: nuclear@0: // if one (or both) of the strings was smaller then they nuclear@0: // are only equal if they have the same lenght nuclear@0: return (i == len) || (array[i] == 0 && str[i] == 0); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //! Appends a character to this string nuclear@0: /** \param character: Character to append. */ nuclear@0: void append(T character) nuclear@0: { nuclear@0: if (used + 1 > allocated) nuclear@0: reallocate((s32)used + 1); nuclear@0: nuclear@0: used += 1; nuclear@0: nuclear@0: array[used-2] = character; nuclear@0: array[used-1] = 0; nuclear@0: } nuclear@0: nuclear@0: //! Appends a string to this string nuclear@0: /** \param other: String to append. */ nuclear@0: void append(const string& other) nuclear@0: { nuclear@0: --used; nuclear@0: nuclear@0: s32 len = other.size(); nuclear@0: nuclear@0: if (used + len + 1 > allocated) nuclear@0: reallocate((s32)used + (s32)len + 1); nuclear@0: nuclear@0: for (s32 l=0; l& other, s32 length) nuclear@0: { nuclear@0: s32 len = other.size(); nuclear@0: nuclear@0: if (len < length) nuclear@0: { nuclear@0: append(other); nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: len = length; nuclear@0: --used; nuclear@0: nuclear@0: if (used + len > allocated) nuclear@0: reallocate((s32)used + (s32)len); nuclear@0: nuclear@0: for (s32 l=0; l nuclear@0: s32 findFirstCharNotInList(B* c, int count) const nuclear@0: { nuclear@0: for (int i=0; i nuclear@0: s32 findLastCharNotInList(B* c, int count) const nuclear@0: { nuclear@0: for (int i=used-2; i>=0; --i) nuclear@0: { nuclear@0: int j; nuclear@0: for (j=0; j=0; --i) nuclear@0: if (array[i] == c) nuclear@0: return i; nuclear@0: nuclear@0: return -1; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //! Returns a substring nuclear@0: //! \param begin: Start of substring. nuclear@0: //! \param length: Length of substring. nuclear@0: string subString(s32 begin, s32 length) nuclear@0: { nuclear@0: if (length <= 0) nuclear@0: return string(""); nuclear@0: nuclear@0: string o; nuclear@0: o.reserve(length+1); nuclear@0: nuclear@0: for (s32 i=0; i& other) nuclear@0: { nuclear@0: append(other); nuclear@0: } nuclear@0: nuclear@0: void operator += (int i) nuclear@0: { nuclear@0: append(string(i)); nuclear@0: } nuclear@0: nuclear@0: //! replaces all characters of a special type with another one nuclear@0: void replace(T toReplace, T replaceWith) nuclear@0: { nuclear@0: for (s32 i=0; i=used || index<0) // access violation nuclear@0: nuclear@0: for (int i=index+1; i=(T)'A' && t<=(T)'Z') nuclear@0: return t + ((T)'a' - (T)'A'); nuclear@0: else nuclear@0: return t; nuclear@0: } nuclear@0: nuclear@0: //! Reallocate the array, make it bigger or smaler nuclear@0: void reallocate(s32 new_size) nuclear@0: { nuclear@0: T* old_array = array; nuclear@0: nuclear@0: array = new T[new_size]; nuclear@0: allocated = new_size; nuclear@0: nuclear@0: s32 amount = used < new_size ? used : new_size; nuclear@0: for (s32 i=0; i stringc; nuclear@0: nuclear@0: //! Typedef for wide character strings nuclear@0: typedef string stringw; nuclear@0: nuclear@0: } // end namespace core nuclear@0: } // end namespace irr nuclear@0: nuclear@0: #endif nuclear@0: