A port of the irrlicht XML parser library.
Diff: irrString.h
- Revision:
- 0:41a49a73580c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irrString.h Wed Nov 17 20:19:41 2010 +0000 @@ -0,0 +1,663 @@ +// Copyright (C) 2002-2005 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine" and the "irrXML" project. +// For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h + +#ifndef __IRR_STRING_H_INCLUDED__ +#define __IRR_STRING_H_INCLUDED__ + +#include "irrTypes.h" + +namespace irr +{ +namespace core +{ + +//! Very simple string class with some useful features. +/** string<c8> and string<wchar_t> work both with unicode AND ascii, +so you can assign unicode to string<c8> and ascii to string<wchar_t> +(and the other way round) if your ever would want to. +Note that the conversation between both is not done using an encoding. + +Known bugs: +Special characters like 'Ä', 'Ü' and 'Ö' are ignored in the +methods make_upper, make_lower and equals_ignore_case. +*/ +template <class T> +class string +{ +public: + + //! Default constructor + string() + : allocated(1), used(1), array(0) + { + array = new T[1]; + array[0] = 0x0; + } + + + + //! Constructor + string(const string<T>& other) + : allocated(0), used(0), array(0) + { + *this = other; + } + + + //! Constructs a string from an int + string(int number) + : allocated(0), used(0), array(0) + { + // store if negative and make positive + + bool negative = false; + if (number < 0) + { + number *= -1; + negative = true; + } + + // temporary buffer for 16 numbers + + c8 tmpbuf[16]; + tmpbuf[15] = 0; + s32 idx = 15; + + // special case '0' + + if (!number) + { + tmpbuf[14] = '0'; + *this = &tmpbuf[14]; + return; + } + + // add numbers + + while(number && idx) + { + idx--; + tmpbuf[idx] = (c8)('0' + (number % 10)); + number = number / 10; + } + + // add sign + + if (negative) + { + idx--; + tmpbuf[idx] = '-'; + } + + *this = &tmpbuf[idx]; + } + + + + //! Constructor for copying a string from a pointer with a given lenght + template <class B> + string(const B* c, s32 lenght) + : allocated(0), used(0), array(0) + { + if (!c) + return; + + allocated = used = lenght+1; + array = new T[used]; + + for (s32 l = 0; l<lenght; ++l) + array[l] = (T)c[l]; + + array[lenght] = 0; + } + + + + //! Constructor for unicode and ascii strings + template <class B> + string(const B* c) + : allocated(0), used(0), array(0) + { + *this = c; + } + + + + //! destructor + ~string() + { + delete [] array; + } + + + + //! Assignment operator + string<T>& operator=(const string<T>& other) + { + if (this == &other) + return *this; + + delete [] array; + allocated = used = other.size()+1; + array = new T[used]; + + const T* p = other.c_str(); + for (s32 i=0; i<used; ++i, ++p) + array[i] = *p; + + return *this; + } + + + + //! Assignment operator for strings, ascii and unicode + template <class B> + string<T>& operator=(const B* c) + { + if (!c) + { + if (!array) + { + array = new T[1]; + allocated = 1; + used = 1; + } + array[0] = 0x0; + return *this; + } + + if ((void*)c == (void*)array) + return *this; + + s32 len = 0; + const B* p = c; + while(*p) + { + ++len; + ++p; + } + + // we'll take the old string for a while, because the new string could be + // a part of the current string. + T* oldArray = array; + + allocated = used = len+1; + array = new T[used]; + + for (s32 l = 0; l<len+1; ++l) + array[l] = (T)c[l]; + + delete [] oldArray; + return *this; + } + + //! Add operator for other strings + string<T> operator+(const string<T>& other) + { + string<T> str(*this); + str.append(other); + + return str; + } + + //! Add operator for strings, ascii and unicode + template <class B> + string<T> operator+(const B* c) + { + string<T> str(*this); + str.append(c); + + return str; + } + + + + //! Direct access operator + T& operator [](const s32 index) const + { + _IRR_DEBUG_BREAK_IF(index>=used) // bad index + + return array[index]; + } + + + //! Comparison operator + bool operator ==(const T* str) const + { + int i; + for(i=0; array[i] && str[i]; ++i) + if (array[i] != str[i]) + return false; + + return !array[i] && !str[i]; + } + + + + //! Comparison operator + bool operator ==(const string<T>& other) const + { + for(s32 i=0; array[i] && other.array[i]; ++i) + if (array[i] != other.array[i]) + return false; + + return used == other.used; + } + + + + //! Is smaller operator + bool operator <(const string<T>& other) const + { + for(s32 i=0; array[i] && other.array[i]; ++i) + if (array[i] != other.array[i]) + return (array[i] < other.array[i]); + + return used < other.used; + } + + + + //! Equals not operator + bool operator !=(const string<T>& other) const + { + return !(*this == other); + } + + + + //! Returns length of string + /** \return Returns length of the string in characters. */ + s32 size() const + { + return used-1; + } + + + + //! Returns character string + /** \return Returns pointer to C-style zero terminated string. */ + const T* c_str() const + { + return array; + } + + + + //! Makes the string lower case. + void make_lower() + { + const T A = (T)'A'; + const T Z = (T)'Z'; + const T diff = (T)'a' - A; + + for (s32 i=0; i<used; ++i) + { + if (array[i]>=A && array[i]<=Z) + array[i] += diff; + } + } + + + + //! Makes the string upper case. + void make_upper() + { + const T a = (T)'a'; + const T z = (T)'z'; + const T diff = (T)'A' - a; + + for (s32 i=0; i<used; ++i) + { + if (array[i]>=a && array[i]<=z) + array[i] += diff; + } + } + + + + //! Compares the string ignoring case. + /** \param other: Other string to compare. + \return Returns true if the string are equal ignoring case. */ + bool equals_ignore_case(const string<T>& other) const + { + for(s32 i=0; array[i] && other[i]; ++i) + if (toLower(array[i]) != toLower(other[i])) + return false; + + return used == other.used; + } + + + //! compares the first n characters of the strings + bool equalsn(const string<T>& other, int len) + { + int i; + for(i=0; array[i] && other[i] && i < len; ++i) + if (array[i] != other[i]) + return false; + + // if one (or both) of the strings was smaller then they + // are only equal if they have the same lenght + return (i == len) || (used == other.used); + } + + + //! compares the first n characters of the strings + bool equalsn(const T* str, int len) + { + int i; + for(i=0; array[i] && str[i] && i < len; ++i) + if (array[i] != str[i]) + return false; + + // if one (or both) of the strings was smaller then they + // are only equal if they have the same lenght + return (i == len) || (array[i] == 0 && str[i] == 0); + } + + + //! Appends a character to this string + /** \param character: Character to append. */ + void append(T character) + { + if (used + 1 > allocated) + reallocate((s32)used + 1); + + used += 1; + + array[used-2] = character; + array[used-1] = 0; + } + + //! Appends a string to this string + /** \param other: String to append. */ + void append(const string<T>& other) + { + --used; + + s32 len = other.size(); + + if (used + len + 1 > allocated) + reallocate((s32)used + (s32)len + 1); + + for (s32 l=0; l<len+1; ++l) + array[l+used] = other[l]; + + used = used + len + 1; + } + + + //! Appends a string of the length l to this string. + /** \param other: other String to append to this string. + \param length: How much characters of the other string to add to this one. */ + void append(const string<T>& other, s32 length) + { + s32 len = other.size(); + + if (len < length) + { + append(other); + return; + } + + len = length; + --used; + + if (used + len > allocated) + reallocate((s32)used + (s32)len); + + for (s32 l=0; l<len; ++l) + array[l+used] = other[l]; + + used = used + len; + } + + + //! Reserves some memory. + /** \param count: Amount of characters to reserve. */ + void reserve(s32 count) + { + if (count < allocated) + return; + + reallocate(count); + } + + + //! finds first occurrence of character in string + /** \param c: Character to search for. + \return Returns position where the character has been found, + or -1 if not found. */ + s32 findFirst(T c) const + { + for (s32 i=0; i<used; ++i) + if (array[i] == c) + return i; + + return -1; + } + + //! finds first occurrence of a character of a list in string + /** \param c: List of strings to find. For example if the method + should find the first occurance of 'a' or 'b', this parameter should be "ab". + \param count: Amount of characters in the list. Ususally, + this should be strlen(ofParameter1) + \return Returns position where one of the character has been found, + or -1 if not found. */ + s32 findFirstChar(T* c, int count) const + { + for (s32 i=0; i<used; ++i) + for (int j=0; j<count; ++j) + if (array[i] == c[j]) + return i; + + return -1; + } + + + //! Finds first position of a character not in a given list. + /** \param c: List of characters not to find. For example if the method + should find the first occurance of a character not 'a' or 'b', this parameter should be "ab". + \param count: Amount of characters in the list. Ususally, + this should be strlen(ofParameter1) + \return Returns position where the character has been found, + or -1 if not found. */ + template <class B> + s32 findFirstCharNotInList(B* c, int count) const + { + for (int i=0; i<used; ++i) + { + int j; + for (j=0; j<count; ++j) + if (array[i] == c[j]) + break; + + if (j==count) + return i; + } + + return -1; + } + + //! Finds last position of a character not in a given list. + /** \param c: List of characters not to find. For example if the method + should find the first occurance of a character not 'a' or 'b', this parameter should be "ab". + \param count: Amount of characters in the list. Ususally, + this should be strlen(ofParameter1) + \return Returns position where the character has been found, + or -1 if not found. */ + template <class B> + s32 findLastCharNotInList(B* c, int count) const + { + for (int i=used-2; i>=0; --i) + { + int j; + for (j=0; j<count; ++j) + if (array[i] == c[j]) + break; + + if (j==count) + return i; + } + + return -1; + } + + //! finds next occurrence of character in string + /** \param c: Character to search for. + \param startPos: Position in string to start searching. + \return Returns position where the character has been found, + or -1 if not found. */ + s32 findNext(T c, s32 startPos) const + { + for (s32 i=startPos; i<used; ++i) + if (array[i] == c) + return i; + + return -1; + } + + + //! finds last occurrence of character in string + //! \param c: Character to search for. + //! \return Returns position where the character has been found, + //! or -1 if not found. + s32 findLast(T c) const + { + for (s32 i=used-1; i>=0; --i) + if (array[i] == c) + return i; + + return -1; + } + + + //! Returns a substring + //! \param begin: Start of substring. + //! \param length: Length of substring. + string<T> subString(s32 begin, s32 length) + { + if (length <= 0) + return string<T>(""); + + string<T> o; + o.reserve(length+1); + + for (s32 i=0; i<length; ++i) + o.array[i] = array[i+begin]; + + o.array[length] = 0; + o.used = o.allocated; + + return o; + } + + + void operator += (T c) + { + append(c); + } + + void operator += (const string<T>& other) + { + append(other); + } + + void operator += (int i) + { + append(string<T>(i)); + } + + //! replaces all characters of a special type with another one + void replace(T toReplace, T replaceWith) + { + for (s32 i=0; i<used; ++i) + if (array[i] == toReplace) + array[i] = replaceWith; + } + + //! trims the string. + /** Removes whitespace from begin and end of the string. */ + void trim() + { + const char whitespace[] = " \t\n"; + const int whitespacecount = 3; + + // find start and end of real string without whitespace + int begin = findFirstCharNotInList(whitespace, whitespacecount); + if (begin == -1) + return; + + int end = findLastCharNotInList(whitespace, whitespacecount); + if (end == -1) + return; + + *this = subString(begin, (end +1) - begin); + } + + + //! Erases a character from the string. May be slow, because all elements + //! following after the erased element have to be copied. + //! \param index: Index of element to be erased. + void erase(int index) + { + _IRR_DEBUG_BREAK_IF(index>=used || index<0) // access violation + + for (int i=index+1; i<used; ++i) + array[i-1] = array[i]; + + --used; + } + + + +private: + + //! Returns a character converted to lower case + T toLower(const T& t) const + { + if (t>=(T)'A' && t<=(T)'Z') + return t + ((T)'a' - (T)'A'); + else + return t; + } + + //! Reallocate the array, make it bigger or smaler + void reallocate(s32 new_size) + { + T* old_array = array; + + array = new T[new_size]; + allocated = new_size; + + s32 amount = used < new_size ? used : new_size; + for (s32 i=0; i<amount; ++i) + array[i] = old_array[i]; + + if (allocated < used) + used = allocated; + + delete [] old_array; + } + + + //--- member variables + + T* array; + s32 allocated; + s32 used; +}; + + +//! Typedef for character strings +typedef string<irr::c8> stringc; + +//! Typedef for wide character strings +typedef string<wchar_t> stringw; + +} // end namespace core +} // end namespace irr + +#endif