Files
assimp/code/irrXML/irrString.h
aramis_acg ce6ce098e9 Removed aiProcess_FindDegenerates from the viewer. The step seems to cause some problems that have not yet been solved.
Added irrmesh (Irrlicht Mesh Format) loader to Assimp. Works quite stable, but no lightmapping support yet.
Removed tinyxml, replaced it with irrxml instead. Added an IOStreamToIrrXML wrapper.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@194 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
2008-10-24 20:37:54 +00:00

665 lines
13 KiB
C++

// 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