aboutsummaryrefslogtreecommitdiffstats
//=============================================================================
//
//   File : KviCString.cpp
//   Creation date : Fri Mar 19 1999 03:20:45 by Szymon Stefanek
//
//   This file is part of the KVIrc IRC client distribution
//   Copyright (C) 1999-2008 Szymon Stefanek (pragma at kvirc dot net)
//
//   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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
//=============================================================================

#include "kvi_debug.h"

#define _KVI_STRING_CPP_

#include "KviCString.h"
#include "KviMemory.h"

#include <QString>

static char hexdigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

kvi_wslen_t kvi_wstrlen(const kvi_wchar_t * str)
{
	const kvi_wchar_t * ptr = str;
	while(*ptr)
		ptr++;
	return (ptr - str);
}

bool kvi_qstringEqualCI(const QString & s1, const QString & s2)
{
	const QChar * p1 = s1.unicode();
	const QChar * p2 = s2.unicode();
	int l = s1.length() < s2.length() ? s1.length() : s2.length();

	while(l-- && (p1->toLower() == p2->toLower()))
		p1++, p2++;

	if(l == -1)
		return true;
	return false;
}

bool kvi_matchStringCI(const char * exp, const char * str)
{
	//               a
	//               .
	// exp = a*x?mem*a
	// str = arexoxmexamemizazv
	//                         .
	//                         n
	const char * afterWild = nullptr;
	const char * nextStrToCheck = nullptr;

	while(*exp)
	{
		if(*exp == '*')
		{
			// exp is a wildcard...
			afterWild = ++exp;
			nextStrToCheck = str + 1;
			if(!(*exp))
				return true; // and it's the last char in the string: matches everything ahead
			continue;
		}

		if(!(*str))
			return false; // str finished but we had something to match :(

		if(tolower(*exp) == tolower(*str))
		{
			// chars matched
			++exp;
			++str;
			if((!(*exp)) && *str)
				goto check_recovery;
			continue;
		}

		if(*exp == '?')
		{
			// any-char wildcard
			++exp;
			++str;
			continue;
		}

	check_recovery:
		// chars unmatched!!!
		if(afterWild)
		{
			// we had a wildcard in exp...
			// let's use this jolly then
			exp = afterWild;
			str = nextStrToCheck;
			nextStrToCheck++;
			// and try to compare now
			continue;
		}

		return false; // no match :(
	}
	return (!(*str));
}

bool kvi_matchStringCS(const char * exp, const char * str)
{
	//               a
	//               .
	// exp = a*x?mem*a
	// str = arexoxmexamemizazv
	//                         .
	//                         n
	const char * afterWild = nullptr;
	const char * nextStrToCheck = nullptr;

	while(*exp)
	{
		if(*exp == '*')
		{
			// exp is a wildcard...
			afterWild = ++exp;
			nextStrToCheck = str + 1;
			if(!(*exp))
				return true; // and it's the last char in the string: matches everything ahead
			continue;
		}

		if(!(*str))
			return false; // str finished but we had something to match :(

		if(*exp == *str)
		{
			// chars matched
			++exp;
			++str;
			if((!(*exp)) && *str)
				goto check_recovery;
			continue;
		}

		if(*exp == '?')
		{
			// any-char wildcard
			++exp;
			++str;
			continue;
		}

	check_recovery:
		// chars unmatched!!!
		if(afterWild)
		{
			// we had a wildcard in exp...
			// let's use this jolly then
			exp = afterWild;
			str = nextStrToCheck;
			nextStrToCheck++;
			// and try to compare now
			continue;
		}

		return false; // no match :(
	}
	return (!(*str));
}

bool kvi_matchStringWithTerminator(const char * exp, const char * str, char terminator, const char ** r1, const char ** r2)
{
#define NOT_AT_END(__str) (*__str && (*__str != terminator))

	//               a
	//               .
	// exp = a*x?mem*a
	// str = arexoxmexamemizazv
	//                         .
	//                         n
	const char * afterWild = nullptr;
	const char * nextStrToCheck = nullptr;

	while(NOT_AT_END(exp))
	{
		if(*exp == '*')
		{
			// exp is a wildcard...
			afterWild = ++exp;
			nextStrToCheck = str + 1;
			if(!(NOT_AT_END(exp)))
			{
				while(NOT_AT_END(str))
					str++;
				*r1 = exp;
				*r2 = str;
				return true; // and it's the last char in the string: matches everything ahead
			}
			continue;
		}

		if(!(*str))
			return false; // str finished but we had something to match :(

		if(tolower(*exp) == tolower(*str))
		{
			// chars matched
			++exp;
			++str;
			if((!(NOT_AT_END(exp))) && NOT_AT_END(str))
				goto check_recovery;
			continue;
		}

		if(*exp == '?')
		{
			// any-char wildcard
			++exp;
			++str;
			continue;
		}

	check_recovery:
		// chars unmatched!!!
		if(afterWild)
		{
			// we had a wildcard in exp...
			// let's use this jolly then
			exp = afterWild;
			str = nextStrToCheck;
			nextStrToCheck++;
			// and try to compare now
			continue;
		}

		return false; // no match :(
	}
	*r1 = exp;
	*r2 = str;
	return (!(NOT_AT_END(str)));

#undef NOT_AT_END
}

bool kvi_matchWildExpr(const char * m1, const char * m2)
{
	//Matches two regular expressions containging wildcards (* and ?)

	//          s1
	//          m1
	// mask1 : *xor
	// mask2 : xorand*xor
	//         m2
	//          s2

	//                        s2
	//                       m2
	//                       |
	// XorT!xor@111.111.111.11
	//
	// *!*@*.net
	//      |
	//      m1
	//      s1
	//

	if(!(m1 && m2 && (*m1)))
		return false;
	const char * savePos1 = nullptr;
	const char * savePos2 = m2;
	while(*m1)
	{
		//loop managed by m1 (initially first mask)
		if(*m1 == '*')
		{
			//Found a wildcard in m1
			savePos1 = ++m1; //move to the next char and save the position...this is our jolly
			if(!*savePos1)
				return true;   //last was a wildcard, matches everything ahead...
			savePos2 = m2 + 1; //next return state for the second string
			continue;          //and return
		}
		if(!(*m2))
			return false; //m2 finished and we had something to match here!
		if(tolower(*m1) == tolower(*m2))
		{
			//chars matched
			m1++; //Go ahead in the two strings
			m2++; //
			if((!(*m1)) && *m2 && savePos1)
			{
				//m1 finished, but m2 not yet and we have a savePosition for m1 (there was a wildcard)...
				//retry matching the string following the * from the savePos2 (one char ahead last time)
				m1 = savePos1; //back to char after wildcard
				m2 = savePos2; //back to last savePos2
				savePos2++;    //next savePos2 will be next char
			}
		}
		else
		{
			if(*m2 == '*')
			{
				//A wlidcard in the second string
				//Invert the game : mask1 <-> mask2
				//mask2 now leads the game...
				savePos1 = m1;     //aux
				m1 = m2;           //...swap
				m2 = savePos1;     //...swap
				savePos1 = m1;     //sync save pos1
				savePos2 = m2 + 1; //sync save pos2
				continue;          //...and again
			}
			// m1 != m2, m1 != *, m2 != *
			if((*m1 == '?') || (*m2 == '?'))
			{
				m1++;
				m2++;
				if((!(*m1)) && *m2 && savePos1)
				{
					//m1 finished, but m2 not yet and we have a savePosition for m1 (there was a wildcard)...
					//retry matching the string following the * from the savePos2 (one char ahead last time)
					m1 = savePos1; //back to char after wildcard
					m2 = savePos2; //back to last savePos2
					savePos2++;    //next savePos2 will be next char
				}
			}
			else
			{
				if(savePos1)
				{
					//Have a jolly man...allow not matching...
					m1 = savePos1; //go back to char after wildcard...need to rematch...
					m2 = savePos2; //back to last savePos2
					savePos2++;    //and set next savePos2
				}
				else
					return false; //No previous wildcards...not matched!
			}
		}
	}
	return (!(*m2)); //m1 surely finished, so for the match, m2 must be finished too
}

/*

	WARNING: Don't remove: working code but actually unused in KVIrc
			Later it might become useful

bool kvi_matchWildExprCS(const char *m1,const char *m2)
{
	if(!(m1 && m2 && (*m1)))return false;
	const char * savePos1 = nullptr;
	const char * savePos2 = m2;
	while(*m1){ //loop managed by m1 (initially first mask)
		if(*m1=='*'){
			//Found a wildcard in m1
			savePos1 = ++m1;            //move to the next char and save the position...this is our jolly
			if(!*savePos1)return true;  //last was a wildcard, matches everything ahead...
			savePos2 = m2+1;            //next return state for the second string
			continue;                   //and return
		}
		if(!(*m2))return false;         //m2 finished and we had something to match here!
		if((*m1)==(*m2)){
			//chars matched
			m1++;                       //Go ahead in the two strings
			m2++;                       //
			if((!(*m1)) && *m2 && savePos1){
				//m1 finished, but m2 not yet and we have a savePosition for m1 (there was a wildcard)...
				//retry matching the string following the * from the savePos2 (one char ahead last time)
				m1 = savePos1;          //back to char after wildcard
				m2 = savePos2;          //back to last savePos2
				savePos2++;             //next savePos2 will be next char
			}
		} else {
			if(*m2 == '*'){
				//A wlidcard in the second string
				//Invert the game : mask1 <-> mask2
				//mask2 now leads the game...
				savePos1 = m1;          //aux
				m1 = m2;                //...swap
				m2 = savePos1;          //...swap
				savePos1 = m1;          //sync save pos1
				savePos2 = m2 + 1;      //sync save pos2
				continue;               //...and again
			}
			if(savePos1){               //Have a jolly man...allow not matching...
				m1 = savePos1;          //go back to char after wildcard...need to rematch...
				m2 = savePos2;          //back to last savePos2
				savePos2++;             //and set next savePos2
			} else return false;        //No previous wildcards...not matched!
		}
	}
	return (!(*m2));                     //m1 surely finished, so for the match, m2 must be finished too

}
*/

bool kvi_matchWildExprWithTerminator(const char * m1, const char * m2, char terminator,
    const char ** r1, const char ** r2)
{
//Matches two regular expressions containging wildcards

#define NOT_AT_END(__str) (*__str && (*__str != terminator))

	bool bSwapped = false;
	if(!(m1 && m2 && (NOT_AT_END(m1))))
		return false;
	const char * savePos1 = nullptr;
	const char * savePos2 = m2;
	while(NOT_AT_END(m1))
	{
		//loop managed by m1 (initially first mask)
		if(*m1 == '*')
		{
			//Found a wildcard in m1
			savePos1 = ++m1; //move to the next char and save the position...this is our jolly
			if(!NOT_AT_END(savePos1))
			{
				//last was a wildcard, matches everything ahead...
				while(NOT_AT_END(m2))
					m2++;
				*r1 = bSwapped ? m2 : m1;
				*r2 = bSwapped ? m1 : m2;
				return true;
			}
			savePos2 = m2 + 1; //next return state for the second string
			continue;          //and return
		}
		if(!NOT_AT_END(m2))
			return false; //m2 finished and we had something to match here!
		if(tolower(*m1) == tolower(*m2))
		{
			//chars matched
			m1++; //Go ahead in the two strings
			m2++; //
			if((!NOT_AT_END(m1)) && NOT_AT_END(m2) && savePos1)
			{
				//m1 finished, but m2 not yet and we have a savePosition for m1 (there was a wildcard)...
				//retry matching the string following the * from the savePos2 (one char ahead last time)
				m1 = savePos1; //back to char after wildcard
				m2 = savePos2; //back to last savePos2
				savePos2++;    //next savePos2 will be next char
			}
		}
		else
		{
			if(*m2 == '*')
			{
				//A wlidcard in the second string
				//Invert the game : mask1 <-> mask2
				//mask2 now leads the game...
				bSwapped = !bSwapped;
				savePos1 = m1;     //aux
				m1 = m2;           //...swap
				m2 = savePos1;     //...swap
				savePos1 = m1;     //sync save pos1
				savePos2 = m2 + 1; //sync save pos2
				continue;          //...and again
			}
			// m1 != m2, m1 != *, m2 != *
			if((*m1 == '?') || (*m2 == '?'))
			{
				m1++;
				m2++;
				if((!NOT_AT_END(m1)) && NOT_AT_END(m2) && savePos1)
				{
					//m1 finished, but m2 not yet and we have a savePosition for m1 (there was a wildcard)...
					//retry matching the string following the * from the savePos2 (one char ahead last time)
					m1 = savePos1; //back to char after wildcard
					m2 = savePos2; //back to last savePos2
					savePos2++;    //next savePos2 will be next char
				}
			}
			else
			{
				if(savePos1)
				{
					//Have a jolly man...allow not matching...
					m1 = savePos1; //go back to char after wildcard...need to rematch...
					m2 = savePos2; //back to last savePos2
					savePos2++;    //and set next savePos2
				}
				else
					return false; //No previous wildcards...not matched!
			}
		}
	}
	*r1 = bSwapped ? m2 : m1;
	*r2 = bSwapped ? m1 : m2;

	return (!NOT_AT_END(m2)); //m1 surely finished, so for the match, m2 must be finished too

#undef NOT_AT_END
}

const char * kvi_extractToken(KviCString & str, const char * aux_ptr, char sep)
{
	KVI_ASSERT(aux_ptr);
	while(*aux_ptr && (*aux_ptr == sep))
		aux_ptr++;
	const char * p = aux_ptr;
	while(*p && (*p != sep))
		p++;
	str.m_len = p - aux_ptr;
	str.m_ptr = (char *)KviMemory::reallocate(str.m_ptr, str.m_len + 1);
	KviMemory::copy(str.m_ptr, aux_ptr, str.m_len);
	*(str.m_ptr + str.m_len) = '\0';
	while(*p && (*p == sep))
		p++;
	return p;
}

const char * kvi_extractUpTo(KviCString & str, const char * aux_ptr, char sep)
{
	KVI_ASSERT(aux_ptr);
	const char * p = aux_ptr;
	while(*p && (*p != sep))
		p++;
	str.m_len = p - aux_ptr;
	str.m_ptr = (char *)KviMemory::reallocate(str.m_ptr, str.m_len + 1);
	KviMemory::copy(str.m_ptr, aux_ptr, str.m_len);
	*(str.m_ptr + str.m_len) = '\0';
	return p;
}

int kvi_vsnprintf(char * buffer, int len, const char * fmt, kvi_va_list list)
{
	KVI_ASSERT(fmt);
	KVI_ASSERT(buffer);
	KVI_ASSERT(len > 0); //printing 0 characters is senseless

	char * p;
	char * argString;
	long argValue;
	unsigned long argUValue;

	//9999999999999999999999999999999\0
	char numberBuffer[32]; //enough ? 10 is enough for 32bit unsigned int...
	char * pNumBuf;
	unsigned int tmp;

	for(p = buffer; *fmt; ++fmt)
	{
		if(len < 1)
			return (-1); //not enough space ... (in fact this could be len < 2 for the terminator)
		//copy up to a '%'
		if(*fmt != '%')
		{
			*p++ = *fmt;
			--len;
			continue;
		}

		++fmt; //skip this '%'
		switch(*fmt)
		{
			case 's': //string
				argString = kvi_va_arg(list, char *);
				if(!argString)
					continue;
				argValue = (long)strlen(argString);
				//check for space...
				if(len <= argValue)
					return (-1); //not enough space for buffer and terminator
				while(*argString)
					*p++ = *argString++;
				len -= argValue;
				continue;
			case 'd': //signed integer
				argValue = kvi_va_arg(list, int);
				if(argValue < 0)
				{ //negative integer
					*p++ = '-';
					if(--len == 0)
						return (-1);
					argValue = -argValue; //need to have it positive
					// most negative integer exception (avoid completely senseless (non digit) responses)
					if(argValue < 0)
						argValue = 0; //we get -0 here
				}
				//write the number in a temporary buffer
				pNumBuf = numberBuffer;
				do
				{
					tmp = argValue / 10;
					*pNumBuf++ = argValue - (tmp * 10) + '0';
				} while((argValue = tmp));
				//copy now....
				argUValue = pNumBuf - numberBuffer; //length of the number string
				if(((uint)len) <= argUValue)
					return (-1); //not enough space for number and terminator
				do
				{
					*p++ = *--pNumBuf;
				} while(pNumBuf != numberBuffer);
				len -= argUValue;
				continue;
			case 'u':                                       //unsigned integer
				argUValue = kvi_va_arg(list, unsigned int); //many implementations place int here
				//write the number in a temporary buffer
				pNumBuf = numberBuffer;
				do
				{
					tmp = argUValue / 10;
					*pNumBuf++ = argUValue - (tmp * 10) + '0';
				} while((argUValue = tmp));
				//copy now....
				argValue = pNumBuf - numberBuffer; //length of the number string
				if(len <= argValue)
					return (-1); //not enough space for number and terminator
				do
				{
					*p++ = *--pNumBuf;
				} while(pNumBuf != numberBuffer);
				len -= argValue;
				continue;
			case 'x':                                       // hexadecimal unsigned integer
				argUValue = kvi_va_arg(list, unsigned int); //many implementations place int here
				//write the number in a temporary buffer
				pNumBuf = numberBuffer;
				do
				{
					tmp = argUValue / 16;
					*pNumBuf++ = hexdigits[argUValue % 16];
				} while((argUValue = tmp));
				//copy now....
				argValue = pNumBuf - numberBuffer; //length of the number string
				if(len <= argValue)
					return (-1); //not enough space for number and terminator
				do
				{
					*p++ = *--pNumBuf;
				} while(pNumBuf != numberBuffer);
				len -= argValue;
				continue;
			case 'c': //char
				//
				// I'm not sure about this...
				// In the linux kernel source the
				// unsigned char is extracted from an integer type.
				// We assume that gcc stacks a char argument
				// as sizeof(int) bytes value.
				// Is this always true ?
				//
				*p++ = (char)kvi_va_arg(list, int);
				--len;
				continue;
			case 'Q': // QString! (this should almost never happen)
			{
				QString * s = kvi_va_arg(list, QString *);
				QByteArray cs = (*s).toUtf8();
				const char * t = cs.data();
				if(!t)
					continue; // nothing to do
				//check for space...
				if(len <= (int)cs.length())
					return (-1); //not enough space for buffer and terminator
				while(*t)
					*p++ = *t++;
				len -= cs.length();
				continue;
			}
			default:        //a normal percent
				*p++ = '%'; //write it
				if(--len == 0)
					return (-1); //not enough space for next char or terminator
				if(*fmt)
				{                //this if is just in case that we have a % at the end of the string.
					*p++ = *fmt; //and write this char
					--len;
				}
				continue;
		}
	}
	if(len < 1)
		return (-1); //missing space for terminator
	*p = '\0';
	return p - buffer;
}

//
// Nearly the same as the above function...
//

int kvi_irc_vsnprintf(char * buffer, const char * fmt, kvi_va_list list, bool * bTruncated)
{
	KVI_ASSERT(fmt);
	KVI_ASSERT(buffer);
	if(!(buffer && fmt))
		return false;
	char * p;
	char * argString;
	long argValue;
	unsigned long argUValue;
	char numberBuffer[64]; //enough ? 10 is enough for 32bit unsigned int...
	char * pNumBuf;
	unsigned int tmp;
	*bTruncated = false;
	int len = 512;

	for(p = buffer; *fmt; ++fmt)
	{
		if(len < 3)
			goto truncate;
		//copy up to a '%'
		if(*fmt != '%')
		{
			*p++ = *fmt;
			--len;
			continue;
		}
		++fmt; //skip this '%'
		switch(*fmt)
		{
			case 's': //string
				argString = kvi_va_arg(list, char *);
				if(!argString)
					continue;
				//check for space...
				while(*argString)
				{
					*p++ = *argString++;
					if(--len < 3)
						goto truncate;
				}
				continue;
			case 'Q': // QString! (this should almost never happen)
			{
				QString * s = kvi_va_arg(list, QString *);
				QByteArray cs = (*s).toUtf8();
				const char * t = cs.data();
				if(!t)
					continue; // nothing to do
				while(*t)
				{
					*p++ = *t++;
					if(--len < 3)
						goto truncate;
				}
				continue;
			}
			case 'd': //signed integer
				argValue = kvi_va_arg(list, int);
				if(argValue < 0)
				{ //negative integer
					*p++ = '-';
					if(--len < 3)
						goto truncate;    //place just for CRLF
					argValue = -argValue; //need to have it positive
					if(argValue < 0)
						argValue = 0; // -0 (hack the exception)
				}
				//write the number in a temporary buffer
				pNumBuf = numberBuffer;
				do
				{
					tmp = argValue / 10;
					*pNumBuf++ = argValue - (tmp * 10) + '0';
				} while((argValue = tmp));
				//copy now....
				do
				{
					*p++ = *--pNumBuf;
					if(--len < 3)
						goto truncate;
				} while(pNumBuf != numberBuffer);
				continue;
			case 'u':                                       //unsigned integer
				argUValue = kvi_va_arg(list, unsigned int); //many implementations place int here
				//write the number in a temporary buffer
				pNumBuf = numberBuffer;
				do
				{
					tmp = argUValue / 10;
					*pNumBuf++ = argUValue - (tmp * 10) + '0';
				} while((argUValue = tmp));
				//copy now....
				if(--len < 3)
					goto truncate; //no place for digits
				do
				{
					*p++ = *--pNumBuf;
					if(--len < 3)
						goto truncate;
				} while(pNumBuf != numberBuffer);
				continue;
			case 'c': //char
				*p++ = (char)kvi_va_arg(list, int);
				--len;
				continue;
			default:        //a normal percent
				*p++ = '%'; //write it
				if(--len < 3)
					goto truncate; //not enough space for next char
				if(*fmt)
				{                //this if is just in case that we have a % at the end of the string.
					*p++ = *fmt; //and write this char
					--len;
				}
				continue;
		}
	}
	//successful finish
	KVI_ASSERT(len >= 2);
	*p++ = '\r';
	*p = '\n';
	return ((p - buffer) + 1);
truncate:
	KVI_ASSERT(len >= 2);
	*bTruncated = true;
	*p++ = '\r';
	*p = '\n';
	return ((p - buffer) + 1);
}

#ifndef COMPILE_ix86_ASM

bool kvi_strEqualCS(const char * str1, const char * str2)
{
	KVI_ASSERT(str1);
	KVI_ASSERT(str2);
	if(!(str1 && str2))
		return false;
	unsigned char * s1 = (unsigned char *)str1;
	unsigned char * s2 = (unsigned char *)str2;
	while(*s1)
		if(*s1++ != *s2++)
			return false;
	return (*s1 == *s2);
}

bool kvi_strEqualCSN(const char * str1, const char * str2, int len)
{
	KVI_ASSERT(str1);
	KVI_ASSERT(str2);
	KVI_ASSERT(len >= 0);
	if(!(str1 && str2 && (len >= 0)))
		return false;
	unsigned char * s1 = (unsigned char *)str1;
	unsigned char * s2 = (unsigned char *)str2;
	while(len-- && *s1)
		if(*s1++ != *s2++)
			return false;
	return (len < 0);
}

#endif

bool kvi_strEqualCIN(const char * str1, const char * str2, int len)
{
	KVI_ASSERT(str1);
	KVI_ASSERT(str2);
	KVI_ASSERT(len >= 0);
	if(!(str1 && str2 && (len >= 0)))
		return false;
	unsigned char * s1 = (unsigned char *)str1;
	unsigned char * s2 = (unsigned char *)str2;
	while(len-- && *s1)
		if(tolower(*s1++) != tolower(*s2++))
			return false;
	return (len < 0);
}

bool kvi_strEqualCI(const char * str1, const char * str2)
{
	KVI_ASSERT(str1);
	KVI_ASSERT(str2);
	if(!(str1 && str2))
		return false;
	unsigned char * s1 = (unsigned char *)str1;
	unsigned char * s2 = (unsigned char *)str2;
	while(*s1)
		if(tolower(*s1++) != tolower(*s2++))
			return false;
	return (*s1 == *s2);
}

//
//note that greater here means that come AFTER in the alphabetic order
// return < 0 ---> str1 < str2
// return = 0 ---> str1 = str2
// return > 0 ---> str1 > str2
//

int kvi_strcmpCI(const char * str1, const char * str2)
{
	//abcd abce
	KVI_ASSERT(str1);
	KVI_ASSERT(str2);
	if(!(str1 && str2))
		return false;
	unsigned char * s1 = (unsigned char *)str1;
	unsigned char * s2 = (unsigned char *)str2;
	int diff;
	unsigned char rightchar;
	while(!(diff = (rightchar = tolower(*s1++)) - tolower(*s2++)))
		if(!rightchar)
			break;
	return diff; //diff is nonzero or end of both was reached (it is positive if *s2 > *s1
}

//
//note that greater here means that come AFTER in the alphabetic order
// return < 0 ---> str1 < str2
// return = 0 ---> str1 = str2
// return > 0 ---> str1 > str2
//int kvi_strcmpCIN(const char *str1,const char *str2,int len)
//

int kvi_strcmpCS(const char * str1, const char * str2)
{
	//abcd abce
	KVI_ASSERT(str1);
	KVI_ASSERT(str2);
	if(!(str1 && str2))
		return false;
	unsigned char * s1 = (unsigned char *)str1;
	unsigned char * s2 = (unsigned char *)str2;
	int diff;
	while(!(diff = (*s1) - (*s2++)))
		if(!*s1++)
			break;
	return diff; //diff is nonzero or end of both was reached (it is positive if *s2 > *s1
}

int kvi_strMatchRevCS(const char * str1, const char * str2, int index)
{
	KVI_ASSERT(str1);
	KVI_ASSERT(str2);
	if(!(str1 && str2))
		return false;
	char * s1 = (char *)str1;
	char * s2 = (char *)str2;

	int curlen = (int)strlen(str1);
	int diff;

	if(index < 0 || index >= curlen)
		index = curlen - 1;

	s1 += index;
	while(*s2)
		s2++;
	s2--;

	// now start comparing
	while(true)
	{
		/* in this case, we have str1 = "lo" and str2 = "hello" */
		if(s1 < str1 && !(s2 < str2))
			return 256;
		if(s2 < str2)
			return 0;
		if((diff = (*s1) - (*s2)))
			return diff;
		s1--;
		s2--;
	}
}

KviCString::KviCString()
{
	m_ptr = (char *)KviMemory::allocate(1);
	*m_ptr = '\0';
	m_len = 0;
}

KviCString::KviCString(const char * str)
{
	//Deep copy constructor
	if(str)
	{
		//Deep copy
		m_len = (int)strlen(str);
		m_ptr = (char *)KviMemory::allocate(m_len + 1);
		KviMemory::copy(m_ptr, str, m_len + 1);
	}
	else
	{
		m_ptr = (char *)KviMemory::allocate(1);
		*m_ptr = '\0';
		m_len = 0;
	}
}

KviCString::KviCString(const QByteArray & str)
{
	//Deep copy constructor
	if(str.data())
	{
		//Deep copy
		m_len = str.length();
		m_ptr = (char *)KviMemory::allocate(m_len + 1);
		KviMemory::copy(m_ptr, str, m_len + 1);
	}
	else
	{
		m_ptr = (char *)KviMemory::allocate(1);
		*m_ptr = '\0';
		m_len = 0;
	}
}

KviCString::KviCString(const char * str, int len)
{
	KVI_ASSERT(str);
	//KVI_ASSERT(len <= ((int)strlen(str))); <-- we trust the user here (and a strlen() call may run AFTER len if data is not null terminated)
	KVI_ASSERT(len >= 0);
	m_len = len;
	m_ptr = (char *)KviMemory::allocate(m_len + 1);
	KviMemory::copy(m_ptr, str, m_len);
	*(m_ptr + m_len) = '\0';
}

KviCString::KviCString(const char * bg, const char * end)
{
	KVI_ASSERT(bg);
	KVI_ASSERT(end);
	KVI_ASSERT(bg <= end);
	m_len = end - bg;
	m_ptr = (char *)KviMemory::allocate(m_len + 1);
	KviMemory::copy(m_ptr, bg, m_len);
	*(m_ptr + m_len) = '\0';
}

KviCString::KviCString(KviFormatConstructorTag, const char * fmt, ...)
{
	m_ptr = (char *)KviMemory::allocate(256);
	//First try
	kvi_va_list list;
	kvi_va_start(list, fmt);
	//print...with max 256 chars
	m_len = kvi_vsnprintf(m_ptr, 256, fmt, list);
	kvi_va_end(list);

	//check if we failed
	if(m_len < 0)
	{
		//yes, failed....
		int dummy = 256;
		do
		{ //we failed, so retry with 256 more chars
			dummy += 256;
			//realloc
			m_ptr = (char *)KviMemory::reallocate(m_ptr, dummy);
			//print...
			kvi_va_start(list, fmt);
			m_len = kvi_vsnprintf(m_ptr, dummy, fmt, list);
			kvi_va_end(list);
		} while(m_len < 0);
	}
	//done...
	//now m_len is the length of the written string not including the terminator...
	//perfect! :)
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
}

KviCString::KviCString(const KviCString & str)
{
	KVI_ASSERT(str.m_ptr);
	m_len = str.m_len;
	m_ptr = (char *)KviMemory::allocate(m_len + 1);
	KviMemory::copy(m_ptr, str.m_ptr, m_len + 1);
}

KviCString::KviCString(const QString & str)
{
	QByteArray sz = str.toUtf8();
	if(sz.length() > 0)
	{
		m_len = sz.length();
		m_ptr = (char *)KviMemory::allocate(m_len + 1);
		KviMemory::copy(m_ptr, sz.data(), m_len + 1);
	}
	else
	{
		m_ptr = (char *)KviMemory::allocate(1);
		*m_ptr = '\0';
		m_len = 0;
	}
}

KviCString::KviCString(char c, int fillLen)
{
	KVI_ASSERT(fillLen >= 0);
	m_len = fillLen;
	m_ptr = (char *)KviMemory::allocate(m_len + 1);
	char * p = m_ptr;
	while(fillLen--)
		*p++ = c;
	*p = '\0';
}

KviCString::KviCString(const kvi_wchar_t * unicode)
{
	if(!unicode)
	{
		m_len = 0;
		m_ptr = (char *)KviMemory::allocate(1);
		*m_ptr = 0;
	}
	else
	{
		m_len = kvi_wstrlen(unicode);
		m_ptr = (char *)KviMemory::allocate(m_len + 1);
		char * p = m_ptr;
		while(*unicode)
			*p++ = *unicode++;
		*p = 0;
	}
}

KviCString::KviCString(const kvi_wchar_t * unicode, int len)
{
	m_len = len;
	m_ptr = (char *)KviMemory::allocate(m_len + 1);
	char * p = m_ptr;
	char * end = p + len;
	while(p != end)
	{
		*p++ = *unicode++;
	}
	*p = 0;
}

KviCString::~KviCString()
{
	KviMemory::free(m_ptr);
}

KviCString & KviCString::operator=(const KviCString & str)
{
	KVI_ASSERT(str.m_ptr);
	KVI_ASSERT(str.m_ptr != m_ptr);
	m_len = str.m_len;
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
	KviMemory::copy(m_ptr, str.m_ptr, m_len + 1);
	return (*this);
}

KviCString & KviCString::operator=(const QByteArray & str)
{
	m_len = str.length();
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
	if(str.data())
		KviMemory::copy(m_ptr, str.data(), m_len + 1);
	else
		*m_ptr = 0;
	return (*this);
}

KviCString & KviCString::operator=(const char * str)
{
	//KVI_ASSERT(str);
	if(str)
	{
		m_len = (int)strlen(str);
		m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
		KviMemory::move(m_ptr, str, m_len + 1);
	}
	else
	{
		m_ptr = (char *)KviMemory::reallocate(m_ptr, 1);
		*m_ptr = '\0';
		m_len = 0;
	}
	return (*this);
}

void KviCString::clear()
{
	m_ptr = (char *)KviMemory::reallocate(m_ptr, 1);
	*m_ptr = '\0';
	m_len = 0;
}

bool KviCString::hasNonWhiteSpaceData() const
{
	const char * aux = m_ptr;
	while(*aux)
	{
		if(((*aux) != ' ') && ((*aux) != '\t'))
			return true;
		aux++;
	}
	return false;
}

void KviCString::bufferToHex(const char * buffer, int len)
{
	KVI_ASSERT(buffer);
	m_len = (len * 2);
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
	char * aux = m_ptr;
	while(len)
	{
		*aux = hexdigits[(unsigned int)(((unsigned char)(*buffer)) / 16)];
		aux++;
		*aux = hexdigits[(unsigned int)(((unsigned char)(*buffer)) % 16)];
		aux++;
		len--;
		buffer++;
	}
	*(m_ptr + m_len) = '\0';
}

static char get_decimal_from_hex_digit_char(char dgt)
{
	if((dgt >= '0') && (dgt <= '9'))
		return (dgt - '0');
	if((dgt >= 'A') && (dgt <= 'F'))
		return (10 + (dgt - 'A'));
	if((dgt >= 'a') && (dgt <= 'f'))
		return (10 + (dgt - 'a'));
	return -1;
}

int KviCString::hexToBuffer(char ** buffer, bool bNullToNewlines)
{
	*buffer = nullptr;
	if((m_len == 0) || (m_len & 1))
		return -1; // this is an error
	int len = (m_len / 2);
	if(len < 1)
		return -1;
	*buffer = (char *)KviMemory::allocate(len);

	char * ptr = *buffer;
	char * aux = m_ptr;

	while(*aux)
	{
		char temp = get_decimal_from_hex_digit_char(*aux);
		if(temp == -1)
		{
			KviMemory::free(*buffer);
			*buffer = nullptr;
			return -1;
		}
		*ptr = temp * 16;
		aux++;
		temp = get_decimal_from_hex_digit_char(*aux);
		if(temp == -1)
		{
			KviMemory::free(*buffer);
			*buffer = nullptr;
			return -1;
		}
		*ptr += temp;
		aux++;
		if(bNullToNewlines)
			if(!(*ptr))
				*ptr = '\n';
		ptr++;
	}
	return len;
}

static const char * base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

void KviCString::bufferToBase64(const char * buffer, int len)
{
	m_len = (len / 3) << 2;
	if(len % 3)
		m_len += 4;

	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);

	unsigned char aux1, aux2, aux3;
	char * aux_ptr = m_ptr;
	while(len > 2)
	{
		aux1 = (unsigned char)*buffer++;
		aux2 = (unsigned char)*buffer++;
		aux3 = (unsigned char)*buffer++;
		*aux_ptr++ = base64_chars[(aux1 & 0xFC) >> 2];
		*aux_ptr++ = base64_chars[((aux1 & 0x03) << 4) | ((aux2 & 0xF0) >> 4)];
		*aux_ptr++ = base64_chars[((aux2 & 0x0F) << 2) | ((aux3 & 0xC0) >> 6)];
		*aux_ptr++ = base64_chars[(aux3 & 0x3F)];
		len -= 3;
	}
	switch(len)
	{
		case 2:
			aux1 = (unsigned char)*buffer++;
			aux2 = (unsigned char)*buffer++;
			*aux_ptr++ = base64_chars[(aux1 & 0xFC) >> 2];
			*aux_ptr++ = base64_chars[((aux1 & 0x03) << 4) | ((aux2 & 0xF0) >> 4)];
			*aux_ptr++ = base64_chars[((aux2 & 0x0F) << 2)];
			*aux_ptr++ = '=';
			break;
		case 1:
			aux1 = (unsigned char)*buffer++;
			aux2 = (unsigned char)*buffer++;
			*aux_ptr++ = base64_chars[(aux1 & 0xFC) >> 2];
			*aux_ptr++ = base64_chars[((aux1 & 0x03) << 4)];
			*aux_ptr++ = '=';
			*aux_ptr++ = '=';
			break;
	}
	*aux_ptr = 0;
}

static unsigned char get_base64_idx(char base64)
{
	if((base64 >= 'A') && (base64 <= 'Z'))
		return (base64 - 'A');
	if((base64 >= 'a') && (base64 <= 'z'))
		return ((base64 - 'a') + 26);
	if((base64 >= '0') && (base64 <= '9'))
		return ((base64 - '0') + 52);
	if(base64 == '+')
		return 62;
	if(base64 == '/')
		return 63;
	if(base64 == '=')
		return 64;
	return 65;
}

int KviCString::base64ToBuffer(char ** buffer, bool)
{
	*buffer = nullptr;
	if((m_len == 0) || (m_len & 3))
		return -1; // this is an error
	int len = (m_len >> 2) * 3;
	*buffer = (char *)KviMemory::allocate(len);

	char * auxBuf = *buffer;

	unsigned char aux1, aux2, aux3, aux4;
	char * aux_ptr = m_ptr;

	int newLen = len;

	while(*aux_ptr)
	{
		if(newLen != len)
		{
			// ops... there was a padding and we still have chars after it
			// this is an error
			KviMemory::free(*buffer);
			*buffer = nullptr;
			return -1;
		}
		aux1 = get_base64_idx(*aux_ptr++);
		aux2 = get_base64_idx(*aux_ptr++);
		aux3 = get_base64_idx(*aux_ptr++);
		aux4 = get_base64_idx(*aux_ptr++);
		if((aux3 > 64) || (aux4 > 64))
		{
			// error
			KviMemory::free(*buffer);
			*buffer = nullptr;
			return -1;
		}
		if((aux1 | aux2) > 63)
		{
			// again error...impossible padding
			KviMemory::free(*buffer);
			*buffer = nullptr;
			return -1;
		}
		if(aux4 == 64)
		{
			if(aux3 == 64)
			{
				// Double padding, only one digit here
				*auxBuf++ = (char)((aux1 << 2) | (aux2 >> 4));
				newLen -= 2;
			}
			else
			{
				// Single padding, two digits here
				*auxBuf++ = (char)((aux1 << 2) | (aux2 >> 4)); // >> 4 is a shr, not a ror! :)
				*auxBuf++ = (char)((aux2 << 4) | (aux3 >> 2));
				newLen -= 1;
			}
		}
		else
		{
			if(aux3 == 64)
			{
				// error... impossible padding
				KviMemory::free(*buffer);
				*buffer = nullptr;
				return -1;
			}
			else
			{
				// Ok, no padding, three digits here
				*auxBuf++ = (char)((aux1 << 2) | (aux2 >> 4));
				*auxBuf++ = (char)((aux2 << 4) | (aux3 >> 2));
				*auxBuf++ = (char)((aux3 << 6) | aux4);
			}
		}
	}

	if(newLen != len)
		*buffer = (char *)KviMemory::reallocate(*buffer, newLen);
	return newLen;
}

KviCString & KviCString::setStr(const char * str, int len)
{
	if(!str)
	{
		clear();
		return *this;
	}
	int alen = (int)strlen(str);
	if((len < 0) || (len > alen))
		m_len = alen;
	else
		m_len = len;
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
	KviMemory::move(m_ptr, str, m_len);
	*(m_ptr + m_len) = '\0';
	return (*this);
}

KviCString & KviCString::operator=(const QString & str)
{
	QByteArray sz = str.toUtf8();
	if(sz.length() > 0)
	{
		m_len = sz.length();
		m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
		KviMemory::copy(m_ptr, sz.data(), m_len + 1);
	}
	else
	{
		m_ptr = (char *)KviMemory::reallocate(m_ptr, 1);
		*m_ptr = '\0';
		m_len = 0;
	}
	return (*this);
}

KviCString & KviCString::operator=(char c)
{
	m_len = 1;
	m_ptr = (char *)KviMemory::reallocate(m_ptr, 2);
	*m_ptr = c;
	*(m_ptr + 1) = '\0';
	return (*this);
}

void KviCString::append(char c)
{
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 2);
	*(m_ptr + m_len) = c;
	m_len++;
	*(m_ptr + m_len) = '\0';
}

void KviCString::append(const KviCString & str)
{
	KVI_ASSERT(str.m_ptr);
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + str.m_len + 1);
	KviMemory::copy((m_ptr + m_len), str.m_ptr, str.m_len + 1);
	m_len += str.m_len;
}

void KviCString::append(const char * str)
{
	if(!str)
		return;
	int len = (int)strlen(str);
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + len + 1);
	KviMemory::copy((m_ptr + m_len), str, len + 1);
	m_len += len;
}

void KviCString::append(const QString & str)
{
	QByteArray sz = str.toUtf8();
	if(sz.length() < 1)
		return;
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + sz.length() + 1);
	KviMemory::copy((m_ptr + m_len), sz.data(), sz.length() + 1);
	m_len += sz.length();
}

void KviCString::append(const char * str, int len)
{
	KVI_ASSERT(str);
	//	KVI_ASSERT(len <= ((int)strlen(str)));
	KVI_ASSERT(len >= 0);
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + len + 1);
	KviMemory::copy((m_ptr + m_len), str, len);
	m_len += len;
	*(m_ptr + m_len) = '\0';
}

void KviCString::append(KviFormatConstructorTag, const char * fmt, ...)
{
	int auxLen;
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 256);
	//First try
	kvi_va_list list;
	kvi_va_start(list, fmt);
	//print...with max 256 chars
	auxLen = kvi_vsnprintf(m_ptr + m_len, 256, fmt, list);
	kvi_va_end(list);

	//check if we failed
	if(auxLen < 0)
	{
		//yes, failed....
		int dummy = 256;
		do
		{ //we failed, so retry with 256 more chars
			dummy += 256;
			//realloc
			m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + dummy);
			//print...
			kvi_va_start(list, fmt);
			auxLen = kvi_vsnprintf(m_ptr + m_len, dummy, fmt, list);
			kvi_va_end(list);
		} while(auxLen < 0);
	}
	m_len += auxLen;
	//done...
	//now m_len is the length of the written string not including the terminator...
	//perfect! :)
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
}

void KviCString::extractFromString(const char * begin, const char * end)
{
	KVI_ASSERT(begin);
	KVI_ASSERT(end);
	KVI_ASSERT(end >= begin);
	m_len = end - begin;
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
	KviMemory::copy(m_ptr, begin, m_len);
	*(m_ptr + m_len) = '\0';
}

void KviCString::prepend(const KviCString & str)
{
	KVI_ASSERT(str.m_ptr);
	KVI_ASSERT(str.m_ptr != m_ptr);
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + str.m_len + 1);
	KviMemory::move((m_ptr + str.m_len), m_ptr, m_len + 1); //move self
	KviMemory::copy(m_ptr, str.m_ptr, str.m_len);
	m_len += str.m_len;
}

void KviCString::prepend(const char * str)
{
	if(!str)
		return;
	int len = (int)strlen(str);
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + len + 1);
	KviMemory::move((m_ptr + len), m_ptr, m_len + 1); //move self
	KviMemory::copy(m_ptr, str, len);
	m_len += len;
}

void KviCString::prepend(const char * str, int len)
{
	KVI_ASSERT(str);
	KVI_ASSERT(len <= ((int)strlen(str)));
	KVI_ASSERT(len >= 0);
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + len + 1);
	KviMemory::move((m_ptr + len), m_ptr, m_len + 1); //move self
	KviMemory::copy(m_ptr, str, len);
	m_len += len;
}

unsigned char iso88591_toUpper_map[256] = {
	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
	0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
	0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
};

void KviCString::toUpperISO88591()
{
	char * p = m_ptr;
	while(*p)
	{
		*p = (char)iso88591_toUpper_map[(unsigned char)*p];
		p++;
	}
}

void KviCString::toUpper()
{
	char * p = m_ptr;
	while(*p)
	{
		*p = toupper(*p);
		p++;
	}
}

unsigned char iso88591_toLower_map[256] = {
	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
	0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
	0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
};

void KviCString::toLowerISO88591()
{
	char * p = m_ptr;
	while(*p)
	{
		*p = (char)iso88591_toLower_map[(unsigned char)*p];
		p++;
	}
}

void KviCString::toLower()
{
	char * p = m_ptr;
	while(*p)
	{
		*p = tolower(*p);
		p++;
	}
}

KviCString KviCString::upper() const
{
	KviCString tmp(*this);
	tmp.toUpper();
	return tmp;
}

KviCString KviCString::upperISO88591() const
{
	KviCString tmp(*this);
	tmp.toUpperISO88591();
	return tmp;
}

KviCString KviCString::lower() const
{
	KviCString tmp(*this);
	tmp.toLower();
	return tmp;
}

KviCString KviCString::lowerISO88591() const
{
	KviCString tmp(*this);
	tmp.toLowerISO88591();
	return tmp;
}

KviCString KviCString::left(int maxLen) const
{
	if(maxLen <= 0)
	{
		KviCString empty;
		return empty;
	}
	if(maxLen > m_len)
		maxLen = m_len;
	KviCString str(m_ptr, maxLen);
	return str;
}

KviCString KviCString::right(int maxLen) const
{
	if(maxLen <= 0)
	{
		KviCString empty;
		return empty;
	}
	if(maxLen > m_len)
		maxLen = m_len;
	KviCString str((m_ptr + (m_len - maxLen)), maxLen);
	return str;
}

KviCString KviCString::middle(int idx, int maxLen) const
{
	KVI_ASSERT(maxLen >= 0);
	KVI_ASSERT(idx >= 0);
	if((maxLen <= 0) || (idx < 0))
	{ //max len negative...invalid params
		KviCString ret;
		return ret;
	}
	if((maxLen + idx) <= m_len)
	{ //valid params
		KviCString str(m_ptr + idx, maxLen);
		return str;
	}
	if(idx < m_len)
	{ //string shorter than requested
		KviCString str(m_ptr + idx);
		return str;
	}
	// idx out of bounds
	KviCString ret;
	return ret;
}

KviCString ** KviCString::splitToArray(char sep, int max, int * realCount) const
{
	KviCString ** strings = (KviCString **)KviMemory::allocate(sizeof(KviCString *));
	int number = 0;
	char * ptr = m_ptr;
	char * last = ptr;
	while((max > 0) && *ptr)
	{
		strings = (KviCString **)KviMemory::reallocate((void *)strings, sizeof(KviCString *) * (number + 2));
		if(max > 1)
		{
			while(*ptr && (*ptr != sep))
				ptr++;
			strings[number] = new KviCString(last, ptr - last);
		}
		else
		{
			strings[number] = new KviCString(ptr);
		}
		number++;
		max--;
		if(*ptr)
		{
			ptr++;
			last = ptr;
		}
	}
	if(realCount)
		*realCount = number;
	strings[number] = nullptr;
	return strings;
}

void KviCString::freeArray(KviCString ** strings)
{
	if(!strings)
		return;
	KviCString ** aux = strings;
	while(*aux)
	{
		delete(*aux); // delete (KviCString *)
		aux++;
	}
	KviMemory::free(strings);
}

void KviCString::freeBuffer(char * buffer)
{
	if(!buffer)
		return;
	KviMemory::free(buffer);
}

void KviCString::joinFromArray(KviCString ** strings, const char * sep, bool bLastSep)
{
	setLen(0);
	if(!strings)
		return;

	while(*strings)
	{
		append(*(*strings));
		strings++;
		if(*strings)
		{
			if(sep)
				append(sep);
		}
		else
		{
			if(sep && bLastSep)
				append(sep);
		}
	}
}

KviCString & KviCString::insert(int idx, const char * data)
{
	KVI_ASSERT(data);
	if(idx <= m_len)
	{
		int len = (int)strlen(data);
		m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + len + 1);
		KviMemory::move(m_ptr + idx + len, m_ptr + idx, (m_len - idx) + 1);
		KviMemory::copy(m_ptr + idx, data, len);
		m_len += len;
	}
	return (*this);
}

KviCString & KviCString::insert(int idx, char c)
{
	if(idx <= m_len)
	{
		m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 2);
		KviMemory::move(m_ptr + idx + 1, m_ptr + idx, (m_len - idx) + 1);
		m_len++;
		*(m_ptr + idx) = c;
	}
	return (*this);
}

// FIXME: #warning "Double check the following two functions !!!"

KviCString & KviCString::hexEncodeWithTable(const unsigned char table[256])
{
	char * aux = m_ptr;
	char * begin = m_ptr;

	char * n = nullptr;
	int curSize = 0;

	while(*aux)
	{
		if(table[*((unsigned char *)aux)] || (*aux == '%'))
		{
			int len = aux - begin;
			n = (char *)KviMemory::reallocate(n, curSize + len + 3);
			KviMemory::move(n + curSize, begin, len);
			curSize += len;

			n[curSize] = '%';
			curSize++;
			n[curSize] = hexdigits[(unsigned int)(((unsigned char)(*aux)) / 16)];
			curSize++;
			n[curSize] = hexdigits[(unsigned int)(((unsigned char)(*aux)) % 16)];
			curSize++;

			aux++;
			begin = aux;
		}
		else
			aux++;
	}

	int len = aux - begin;
	n = (char *)KviMemory::reallocate(n, curSize + len + 1);
	KviMemory::move(n + curSize, begin, len);
	curSize += len;

	n[curSize] = '\0';

	KviMemory::free((void *)m_ptr);
	m_ptr = n;
	m_len = curSize;

	return (*this);
}

KviCString & KviCString::hexEncodeWhiteSpace()
{
	static unsigned char ascii_jump_table[256] = {
		// clang-format off
		//	000 001 002 003 004 005 006 007   008 009 010 011 012 013 014 015
		//	NUL SOH STX ETX EOT ENQ ACK BEL   BS  HT  LF  VT  FF  CR  SO  SI
			1  ,1  ,1  ,1  ,1  ,1  ,1  ,1    ,1  ,1  ,1  ,1  ,1  ,1  ,1  ,1  ,
		//	016 017 018 019 020 021 022 023   024 025 026 027 028 029 030 031
		//	DLE DC1 DC2 DC3 DC4 NAK SYN ETB   CAN EM  SUB ESC FS  GS  RS  US
			1  ,1  ,1  ,1  ,1  ,1  ,1  ,1    ,1  ,1  ,1  ,1  ,1  ,1  ,1  ,1  ,
		//	032 033 034 035 036 037 038 039   040 041 042 043 044 045 046 047
		//	    !   "   #   $   %   &   '     (   )   *   +   ,   -   .   /
			1  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
		//	048 049 050 051 052 053 054 055   056 057 058 059 060 061 062 063
		//	0   1   2   3   4   5   6   7     8   9   :   ;   <   =   >   ?
			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
		//	064 065 066 067 068 069 070 071   072 073 074 075 076 077 078 079
		//	@   A   B   C   D   E   F   G     H   I   J   K   L   M   N   O
			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
		//	080 081 082 083 084 085 086 087   088 089 090 091 092 093 094 095
		//	P   Q   R   S   T   U   V   W     X   Y   Z   [   \   ]   ^   _
			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
		//	096 097 098 099 100 101 102 103   104 105 106 107 108 109 110 111
		//	`   a   b   c   d   e   f   g     h   i   j   k   l   m   n   o
			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
		//	112 113 114 115 116 117 118 119   120 121 122 123 124 125 126 127
		//	p   q   r   s   t   u   v   w     x   y   z   {   |   }   ~   
			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
		//	128 129 130 131 132 133 134 135   136 137 138 139 140 141 142 143
		//
			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
		//	144 145 146 147 148 149 150 151   152 153 154 155 156 157 158 159
		//
			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
		//	160 161 162 163 164 165 166 167   168 169 170 171 172 173 174 175
		//
			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
		//	176 177 178 179 180 181 182 183   184 185 186 187 188 189 190 191
		//
			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
		//	192 193 194 195 196 197 198 199   200 201 202 203 204 205 206 207
		//	�  �  �  �  �  �  �  �    �  �  �  �  �  �  �  �
			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
		//	208 209 210 211 212 213 214 215   216 217 218 219 220 221 222 223
		//	�  �  �  �  �  �  �  �    �  �  �  �  �  �  �  �
			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
		//	224 225 226 227 228 229 230 231   232 233 234 235 236 237 238 239
		//	�  �  �  �  �  �  �  �    �  �  �  �  �  �  �  �
			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
		//	240 241 242 243 244 245 246 247   248 249 250 251 252 253 254 255
		//	�  �  �  �  �  �  �  �
			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0
		// clang-format on
	};

	return hexEncodeWithTable(ascii_jump_table);
}

KviCString & KviCString::hexDecode(const char * pFrom)
{
	// WARNING: pFrom can be also m_ptr here!
	const char * aux = pFrom;
	const char * begin = pFrom;

	char * n = nullptr;
	int curSize = 0;

	while(*aux)
	{
		if(*aux == '%')
		{
			// move last block
			int len = aux - begin;
			n = (char *)KviMemory::reallocate(n, curSize + len + 1);
			KviMemory::move(n + curSize, begin, len);
			curSize += len;

			// get the hex code
			aux++;

			char theChar = get_decimal_from_hex_digit_char(*aux);
			if(theChar < 0)
			{
				n[curSize] = '%'; // wrong code...just a '%'
				curSize++;
			}
			else
			{
				aux++;
				char theChar2 = get_decimal_from_hex_digit_char(*aux);
				if(theChar2 < 0)
				{
					// wrong code...just a '%' and step back
					n[curSize] = '%';
					curSize++;
					aux--;
				}
				else
				{
					n[curSize] = (theChar * 16) + theChar2;
					curSize++;
					aux++;
				}
			}

			begin = aux;
		}
		else
			aux++;
	}

	int len = aux - begin;
	n = (char *)KviMemory::reallocate(n, curSize + len + 2);
	KviMemory::move(n + curSize, begin, len);
	curSize += len;
	n[curSize] = '\0';

	KviMemory::free((void *)m_ptr);
	m_ptr = n;
	m_len = curSize;

	return (*this);
}

KviCString & KviCString::replaceAll(const char c, const char * str)
{
	int idx = findFirstIdx(c);
	KviCString tmp;
	while(idx >= 0)
	{
		if(idx > 0)
			tmp += left(idx);
		cutLeft(idx + 1);
		tmp.append(str);
		idx = findFirstIdx(c);
	}
	tmp.append(*this);
	// Now copy
	m_len = tmp.m_len;
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
	KviMemory::copy(m_ptr, tmp.m_ptr, m_len + 1);
	return (*this);
}

KviCString & KviCString::replaceAll(const char * toFind, const char * str, bool bCaseS)
{
	int len = (int)strlen(toFind);
	int idx = findFirstIdx(toFind, bCaseS);
	KviCString tmp;
	while(idx >= 0)
	{
		if(idx > 0)
			tmp += left(idx);
		cutLeft(idx + len);
		tmp.append(str);
		idx = findFirstIdx(toFind, bCaseS);
	}
	tmp.append(*this);
	// Now copy
	m_len = tmp.m_len;
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
	KviMemory::copy(m_ptr, tmp.m_ptr, m_len + 1);
	return (*this);
}

KviCString & KviCString::transliterate(const char * szToFind, const char * szReplacement)
{
	while(*szToFind && *szReplacement)
	{
		char * p = m_ptr;
		while(*p)
		{
			if(*p == *szToFind)
				*p = *szReplacement;
			++p;
		}
		++szToFind;
		++szReplacement;
	}
	return (*this);
}

int KviCString::occurrences(char c, bool caseS) const
{
	char * p = m_ptr;
	int cnt = 0;
	if(caseS)
	{
		while(*p)
		{
			if(*p == c)
				cnt++;
			p++;
		}
	}
	else
	{
		char b = tolower(c);
		while(*p)
		{
			if(tolower(*p) == b)
				cnt++;
			p++;
		}
	}
	return cnt;
}

int KviCString::occurrences(const char * str, bool caseS) const
{
	KVI_ASSERT(str);
	char * p = m_ptr;
	int cnt = 0;
	int len = (int)strlen(str);
	if(caseS)
	{
		while(*p)
		{
			if(*p == *str)
			{
				if(kvi_strEqualCSN(p, str, len))
					cnt++;
			}
			p++;
		}
	}
	else
	{
		while(*p)
		{
			char c = tolower(*str);
			if(tolower(*p) == c)
			{
				if(kvi_strEqualCIN(p, str, len))
					cnt++;
			}
			p++;
		}
	}
	return cnt;
}

bool KviCString::contains(char c, bool caseS) const
{
	char * p = m_ptr;
	if(caseS)
	{
		while(*p)
		{
			if(*p == c)
				return true;
			p++;
		}
	}
	else
	{
		char b = tolower(c);
		while(*p)
		{
			if(tolower(*p) == b)
				return true;
			p++;
		}
	}
	return false;
}

bool KviCString::contains(const char * str, bool caseS) const
{
	KVI_ASSERT(str);
	char * p = m_ptr;
	int len = (int)strlen(str);
	if(caseS)
	{
		while(*p)
		{
			if(*p == *str)
			{
				if(kvi_strEqualCSN(p, str, len))
					return true;
			}
			p++;
		}
	}
	else
	{
		while(*p)
		{
			char c = tolower(*str);
			if(tolower(*p) == c)
			{
				if(kvi_strEqualCIN(p, str, len))
					return true;
			}
			p++;
		}
	}
	return false;
}

KviCString & KviCString::setNum(long num)
{
	char numberBuffer[30];
	bool bNegative = false;
	long tmp;
	char * p;
	char * pNumBuf = numberBuffer;

	// somebody can explain to me why 	-(-2147483648) = -2147483648 ? (2^31)
	// it is like signed char x = 128 ---> 10000000 that is signed -0 (!?)
	// mmmmh...or it is assumed to be -128 (a number representation exception)
	// at least on my machine it happens...

	// found the solution by myself today...
	//
	// ABS(3)              Linux Programmer's Manual              ABS(3)
	// NAME
	//        abs - computes the absolute value of an integer.
	// ...
	// DESCRIPTION
	//        The abs() function computes the absolute value of the integer argument j.
	// RETURN VALUE
	//        Returns the absolute value of the integer argument.
	// CONFORMING TO
	//        SVID 3, POSIX, BSD 4.3, ISO 9899
	// NOTE ##################################################################################
	//        Trying to take the absolute value of the most negative integer is not defined.
	// #######################################################################################

	// so should i use temporaneous doubles to make calculations ?

	if(num < 0)
	{ //negative integer
		bNegative = true;
		num = -num; //need to have it positive
		if(num < 0)
		{	// 2^31 exception
			// We need to avoid absurd responses like ".(./),." :)
			num = 0; // we get a negative zero here...it is still an exception
		}
	}

	//write the number in a temporary buffer (at least '0')
	do
	{
		tmp = num / 10;
		*pNumBuf++ = num - (tmp * 10) + '0';
	} while((num = tmp));

	//copy now....
	m_len = pNumBuf - numberBuffer; //length of the number string
	if(bNegative)
	{
		m_len++;
		m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
		p = m_ptr;
		*p++ = '-';
	}
	else
	{
		m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
		p = m_ptr;
	}
	do
	{
		*p++ = *--pNumBuf;
	} while(pNumBuf != numberBuffer);
	*(m_ptr + m_len) = '\0';
	return (*this);
}

KviCString & KviCString::setNum(unsigned long num)
{
	char numberBuffer[30];
	unsigned long tmp;
	char * p;
	char * pNumBuf = numberBuffer;

	//write the number in a temporary buffer (at least '0')
	do
	{
		tmp = num / 10;
		*pNumBuf++ = num - (tmp * 10) + '0';
	} while((num = tmp));

	//copy now....
	m_len = pNumBuf - numberBuffer; //length of the number string
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
	p = m_ptr;
	do
	{
		*p++ = *--pNumBuf;
	} while(pNumBuf != numberBuffer);
	*(m_ptr + m_len) = '\0';
	return (*this);
}

long long KviCString::toLongLong(bool * bOk) const
{
	long long result = 0;
	if(bOk)
		*bOk = false;
	char * p = m_ptr;
	bool bNeg = false;
	while(isspace(*p))
		p++; //skip spaces
	if(*p == '-')
	{
		bNeg = true;
		p++;
	}
	else
	{
		if(*p == '+')
			p++;
	}
	if(isdigit(*p))
	{ //point to something interesting ?
		do
		{
			result = (result * 10) + (*p - '0');
			p++;
		} while(isdigit(*p));
		if(bNeg)
			result = -result;
		while(isspace(*p))
			p++; //skip trailing spaces
		if(*p)
			return 0; //if this is not the end...die.
		if(bOk)
			*bOk = true;
		return result;
	}
	return 0;
}

unsigned long long KviCString::toULongLong(bool * bOk) const
{
	unsigned long long result = 0;
	if(bOk)
		*bOk = false;
	char * p = m_ptr;
	while(isspace(*p))
		p++; //skip spaces
	if(isdigit(*p))
	{ //point to something interesting ?
		do
		{
			result = (result * 10) + (*p - '0');
			p++;
		} while(isdigit(*p));
		while(isspace(*p))
			p++; //skip trailing spaces
		if(*p)
			return 0; //if this is not the end...die.
		if(bOk)
			*bOk = true;
		return result;
	}
	return 0;
}

long KviCString::toLong(bool * bOk) const
{
	long result = 0;
	if(bOk)
		*bOk = false;
	char * p = m_ptr;
	bool bNeg = false;
	while(isspace(*p))
		p++; //skip spaces
	if(*p == '-')
	{
		bNeg = true;
		p++;
	}
	else
	{
		if(*p == '+')
			p++;
	}
	if(isdigit(*p))
	{ //point to something interesting ?
		do
		{
			result = (result * 10) + (*p - '0');
			p++;
		} while(isdigit(*p));
		if(bNeg)
			result = -result;
		while(isspace(*p))
			p++; //skip trailing spaces
		if(*p)
			return 0; //if this is not the end...die.
		if(bOk)
			*bOk = true;
		return result;
	}
	return 0;
}

unsigned long KviCString::toULong(bool * bOk) const
{
	unsigned long result = 0;
	if(bOk)
		*bOk = false;
	char * p = m_ptr;
	while(isspace(*p))
		p++; //skip spaces
	if(isdigit(*p))
	{ //point to something interesting ?
		do
		{
			result = (result * 10) + (*p - '0');
			p++;
		} while(isdigit(*p));
		while(isspace(*p))
			p++; //skip trailing spaces
		if(*p)
			return 0; //if this is not the end...die.
		if(bOk)
			*bOk = true;
		return result;
	}
	return 0;
}

long KviCString::toLongExt(bool * bOk, int base)
{
	if(m_len == 0)
	{
		if(bOk)
			*bOk = false;
		return 0;
	}
	char * endptr;
	long result = strtol(m_ptr, &endptr, base);
	if(*endptr)
	{
		// must be whitespaces, otherwise there is trailing garbage inside
		while(isspace(*endptr) && (*endptr))
			endptr++;
		if(*endptr)
		{
			// still not at the end
			// trailing garbage not allowed
			if(bOk)
				*bOk = false;
			return result;
		}
	}
	if(bOk)
		*bOk = true;
	return result;
}

KviCString & KviCString::cutLeft(int len)
{
	KVI_ASSERT(len >= 0);
	if(len <= m_len)
	{
		m_len -= len;
		KviMemory::move(m_ptr, m_ptr + len, m_len + 1);
		m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
	}
	else
	{
		m_ptr = (char *)KviMemory::reallocate(m_ptr, 1);
		*m_ptr = '\0';
		m_len = 0;
	}
	return (*this);
}

KviCString & KviCString::cutRight(int len)
{
	KVI_ASSERT(len >= 0);
	if(len <= m_len)
	{
		m_len -= len;
		m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
		*(m_ptr + m_len) = '\0';
	}
	else
	{
		m_ptr = (char *)KviMemory::reallocate(m_ptr, 1);
		*m_ptr = '\0';
		m_len = 0;
	}
	return (*this);
}

KviCString & KviCString::cut(int idx, int len)
{
	KVI_ASSERT(idx >= 0);
	KVI_ASSERT(len >= 0);
	if(idx < m_len)
	{
		// idx = 3 len = 3 m_len = 10
		// 0123456789
		// abcdefghij
		//    ^  ^
		//   p1  p2
		char * p1 = m_ptr + idx;
		if(len + idx > m_len)
			len = m_len - idx;
		char * p2 = p1 + len;
		KviMemory::move(p1, p2, (m_len - (len + idx)) + 1);
		m_len -= len;
		m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
	}
	return (*this);
}

KviCString & KviCString::cutToFirst(char c, bool bIncluded)
{
	int idx = findFirstIdx(c);
	if(idx != -1)
		cutLeft(bIncluded ? idx + 1 : idx);
	return (*this);
}

KviCString KviCString::leftToFirst(char c, bool bIncluded) const
{
	int idx = findFirstIdx(c);
	if(idx == -1)
		return KviCString(*this);
	return KviCString(m_ptr, bIncluded ? idx + 1 : idx);
}

KviCString KviCString::leftToLast(char c, bool bIncluded) const
{
	int idx = findLastIdx(c);
	return KviCString(m_ptr, bIncluded ? idx + 1 : idx);
}

KviCString & KviCString::cutFromFirst(char c, bool bIncluded)
{
	int idx = findFirstIdx(c);
	if(idx != -1)
		cutRight(bIncluded ? (m_len - idx) : (m_len - (idx + 1)));
	return (*this);
}

KviCString & KviCString::cutToLast(char c, bool bIncluded)
{
	int idx = findLastIdx(c);
	if(idx != -1)
		cutLeft(bIncluded ? idx + 1 : idx);
	return (*this);
}

KviCString & KviCString::cutFromLast(char c, bool bIncluded)
{
	int idx = findLastIdx(c);
	if(idx != -1)
		cutRight(bIncluded ? (m_len - idx) : (m_len - (idx + 1)));
	return (*this);
}

KviCString & KviCString::cutToFirst(const char * c, bool bIncluded)
{
	int len = (int)strlen(c);
	int idx = findFirstIdx(c);
	if(idx != -1)
		cutLeft(bIncluded ? idx + len : idx);
	return (*this);
}

KviCString & KviCString::cutFromFirst(const char * c, bool bIncluded)
{
	int len = (int)strlen(c);
	int idx = findFirstIdx(c);
	if(idx != -1)
		cutRight(bIncluded ? (m_len - idx) : (m_len - (idx + len)));
	return (*this);
}

KviCString & KviCString::cutToLast(const char * c, bool bIncluded)
{
	int len = (int)strlen(c);
	int idx = findLastIdx(c);
	if(idx != -1)
		cutLeft(bIncluded ? idx + len : idx);
	return (*this);
}

KviCString & KviCString::cutFromLast(const char * c, bool bIncluded)
{
	int len = (int)strlen(c);
	int idx = findLastIdx(c);
	if(idx != -1)
		cutRight(bIncluded ? (m_len - idx) : (m_len - (idx + len)));
	return (*this);
}

KviCString & KviCString::setLen(int iLen)
{
	KVI_ASSERT(iLen >= 0);
	m_len = iLen;
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
	*(m_ptr + m_len) = '\0';
	return (*this);
}

KviCString & KviCString::padRight(int iLen, const char c)
{
	KVI_ASSERT(iLen >= 0);
	m_ptr = (char *)KviMemory::reallocate(m_ptr, iLen + 1);
	*(m_ptr + iLen) = '\0';
	if(iLen > m_len)
		KviMemory::set(m_ptr + m_len, c, iLen - m_len);
	m_len = iLen;
	return (*this);
}

KviCString & KviCString::stripLeftWhiteSpace()
{
	char * p = m_ptr;
	while(isspace(*p))
		p++;
	m_len -= (p - m_ptr);
	KviMemory::move(m_ptr, p, m_len + 1);
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
	return (*this);
}

KviCString & KviCString::stripLeft(char c)
{
	KVI_ASSERT(c != '\0');
	char * p = m_ptr;
	while(*p == c)
		p++;
	m_len -= (p - m_ptr);
	KviMemory::move(m_ptr, p, m_len + 1);
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
	return (*this);
}

bool KviCString::getToken(KviCString & str, char sep, bool skipEmpty)
{
	KVI_ASSERT(str.m_ptr);
	KVI_ASSERT(str.m_ptr != m_ptr);
	char * p = m_ptr;
	//skip to the end
	while(*p && (*p != sep))
		p++;
	//0123456789
	//abcd xyz
	//^   ^
	str.m_len = p - m_ptr;
	str.m_ptr = (char *)KviMemory::reallocate(str.m_ptr, str.m_len + 1);
	KviMemory::copy(str.m_ptr, m_ptr, str.m_len);
	*(str.m_ptr + str.m_len) = '\0';
	while(*p && (*p == sep))
	{
		p++;
		if(!skipEmpty)
			break;
	}
	cutLeft(p - m_ptr);
	return (m_len != 0);
}

bool KviCString::getLine(KviCString & str)
{
	KVI_ASSERT(str.m_ptr);
	KVI_ASSERT(str.m_ptr != m_ptr);
	if(m_len == 0)
		return false;
	char * p = m_ptr;
	//skip to the end
	while(*p && (*p != '\n'))
		p++;
	//0123456789
	//abcd xyz
	//^   ^
	str.m_len = p - m_ptr;
	str.m_ptr = (char *)KviMemory::reallocate(str.m_ptr, str.m_len + 1);
	KviMemory::copy(str.m_ptr, m_ptr, str.m_len);
	*(str.m_ptr + str.m_len) = '\0';
	p++;
	cutLeft(p - m_ptr);
	return true;
}

KviCString KviCString::getToken(char sep, bool skipEmpty)
{
	char * p = m_ptr;
	while(*p && (*p != sep))
		p++;
	KviCString ret(m_ptr, p);
	while(*p && (*p == sep))
	{
		p++;
		if(!skipEmpty)
			break;
	}
	cutLeft(p - m_ptr);
	return ret;
}

KviCString & KviCString::vsprintf(const char * fmt, kvi_va_list list)
{
	kvi_va_list save;
	kvi_va_copy(save, list);

	m_ptr = (char *)KviMemory::reallocate(m_ptr, 256);
	//First try
	//print...with max 256 chars
	m_len = kvi_vsnprintf(m_ptr, 256, fmt, list);

	//check if we failed
	if(m_len < 0)
	{
		//yes, failed....
		int dummy = 256;
		do
		{ //we failed, so retry with 256 more chars
			dummy += 256;
			//realloc
			m_ptr = (char *)KviMemory::reallocate(m_ptr, dummy);
			//print...
			kvi_va_copy(list, save);
			m_len = kvi_vsnprintf(m_ptr, dummy, fmt, list);
		} while(m_len < 0);
	}
	//done...
	//now m_len is the length of the written string not including the terminator...
	//perfect! :)
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
	kvi_va_end(save);
	return (*this);
}

KviCString & KviCString::sprintf(const char * fmt, ...)
{
	m_ptr = (char *)KviMemory::reallocate(m_ptr, 256);
	//First try
	kvi_va_list list;
	kvi_va_start(list, fmt);
	//print...with max 256 chars
	m_len = kvi_vsnprintf(m_ptr, 256, fmt, list);
	kvi_va_end(list);

	//check if we failed
	if(m_len < 0)
	{
		//yes, failed....
		int dummy = 256;
		do
		{ //we failed, so retry with 256 more chars
			dummy += 256;
			//realloc
			m_ptr = (char *)KviMemory::reallocate(m_ptr, dummy);
			//print...
			kvi_va_start(list, fmt);
			m_len = kvi_vsnprintf(m_ptr, dummy, fmt, list);
			kvi_va_end(list);
		} while(m_len < 0);
	}
	//done...
	//now m_len is the length of the written string not including the terminator...
	//perfect! :)
	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
	return (*this);
}

int KviCString::find(const char * str, int idx, bool caseS) const
{
	if(idx >= m_len)
		return -1;
	char * p = m_ptr + idx;
	int len = (int)strlen(str);
	if(caseS)
	{
		for(;;)
		{
			while(*p && (*p != *str))
				p++;
			if(*p)
			{
				if(kvi_strEqualCSN(str, p, len))
					return (p - m_ptr);
				else
					p++;
			}
			else
				return -1;
		}
	}
	else
	{
		for(;;)
		{
			char tmp = toupper(*str);
			while(*p && (toupper(*p) != tmp))
				p++;
			if(*p)
			{
				if(kvi_strEqualCIN(str, p, len))
					return (p - m_ptr);
				else
					p++;
			}
			else
				return -1;
		}
	}
}

int KviCString::find(char c, int idx) const
{
	if(idx >= m_len)
		return -1;
	char * p = m_ptr + idx;
	while(*p && (*p != c))
		p++;
	return (*p ? p - m_ptr : -1);
}

int KviCString::findRev(const char * str, int idx, bool caseS) const
{
	if((m_len + idx) < 0)
		return -1;
	char * p = m_ptr + m_len + idx;
	int len = (int)strlen(str);
	if(caseS)
	{
		for(;;)
		{
			while((p >= m_ptr) && (*p != *str))
				p--;
			if(p >= m_ptr)
			{
				if(kvi_strEqualCSN(str, p, len))
					return (p - m_ptr);
				else
					p--;
			}
			else
				return -1;
		}
	}
	else
	{
		for(;;)
		{
			char tmp = toupper(*str);
			while((p >= m_ptr) && (toupper(*p) != tmp))
				p--;
			if(p >= m_ptr)
			{
				if(kvi_strEqualCIN(str, p, len))
					return (p - m_ptr);
				else
					p--;
			}
			else
				return -1;
		}
	}
}

int KviCString::findFirstIdx(char c) const
{
	char * p = m_ptr;
	while(*p && (*p != c))
		p++;
	return (*p ? p - m_ptr : -1);
}

int KviCString::findFirstIdx(const char * str, bool caseS) const
{
	// This function can't be used to search inside
	// multibyte encoded strings... convert your
	// code to QString and use QString::findRev().
	// We must throw away KviCString at all in this case...

	// return QString(m_ptr).find(QString(str),0,caseS);

	// Both this KviCString and the const char * str are assumed
	// to be in the proper (and same) encoding.
	// If KviCString is in encoding A then QString(m_ptr) might
	// or not be decoded correctly.
	// Also if KviCString is in UTF-8 (for example), then
	// a position in QString() does not map to the position in the char array
	// since a single UNICODE char may use one or more bytes...

	KVI_ASSERT(str);
	char * p = m_ptr;
	int len = (int)strlen(str);
	if(caseS)
	{
		for(;;)
		{
			while(*p && (*p != *str))
				p++;
			if(*p)
			{
				if(kvi_strEqualCSN(str, p, len))
					return (p - m_ptr);
				else
					p++;
			}
			else
				return -1;
		}
	}
	else
	{
		// this will NOT work for strings that aren't in the current system encoding :(
		for(;;)
		{
			char tmp = toupper(*str);
			while(*p && (toupper(*p) != tmp))
				p++;
			if(*p)
			{
				if(kvi_strEqualCIN(str, p, len))
					return (p - m_ptr);
				else
					p++;
			}
			else
				return -1;
		}
	}
}

int KviCString::findLastIdx(char c) const
{
	//Empty string ?
	if(m_len < 1)
		return -1;
	//p points to the last character in the string
	char * p = ((m_ptr + m_len) - 1);
	//go back until we find a match or we run to the first char in the string.
	while((*p != c) && (p > m_ptr))
		p--;
	//if *p == c --> matched, else we are at the beginning of the string.
	return ((*p == c) ? p - m_ptr : -1);
}

int KviCString::findLastIdx(const char * str, bool caseS) const
{
	// This function can't be used to search inside
	// multibyte encoded strings... convert your
	// code to QString and use QString::findRev().
	// We must throw away KviCString at all in this case...

	// return QString(m_ptr).findRev(QString(str),-1,caseS);

	KVI_ASSERT(str);
	//Calc the len of the searched string
	int len = (int)strlen(str);
	//Too long ?
	if(m_len < len)
		return -1;
	//p points to the last character in the string
	char * p = ((m_ptr + m_len) - 1);
	if(caseS)
	{
		for(;;)
		{
			//go back until we find a character that mathes or we run to the first char.
			while((*p != *str) && (p > m_ptr))
				p--;
			if(*p == *str)
			{
				//maybe occurrence....
				if(kvi_strEqualCSN(str, p, len))
					return (p - m_ptr);
				else
				{
					//Nope...continue if there is more data to check...
					if(p == m_ptr)
						return -1;
					p--;
				}
			}
			else
				return -1; //Beginning of the string
		}
	}
	else
	{
		// case insensitive
		for(;;)
		{
			//go back until we find a character that mathes or we run to the first char.
			char tmp = toupper(*str);
			while((toupper(*p) != tmp) && (p > m_ptr))
				p--;
			if(toupper(*p) == tmp)
			{
				//maybe occurrence....
				if(kvi_strEqualCIN(str, p, len))
					return (p - m_ptr);
				else
				{
					//Nope...continue if there is more data to check...
					if(p == m_ptr)
						return -1;
					p--;
				}
			}
			else
				return -1; //Beginning of the string
		}
	}
}

KviCString & KviCString::trim()
{
	// 0123456789
	//    abcd   0
	// ^        ^
	// left   right
	char * left = m_ptr;
	char * right = m_ptr + m_len - 1;
	// skip initial spaces
	while(isspace(*left))
		left++;
	if(*left)
	{
		// valid string, left points to first non-space
		while((right >= left) && isspace(*right))
			right--;
		// 0123456789
		//    abcd   0
		//    ^  ^
		// left   right
		m_len = (right - left) + 1;
		KviMemory::move(m_ptr, left, m_len);
		m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
		*(m_ptr + m_len) = '\0';
	}
	else
	{
		m_ptr = (char *)KviMemory::reallocate(m_ptr, 1);
		*m_ptr = '\0';
		m_len = 0;
	}
	return (*this);
}

KviCString & KviCString::stripRightWhiteSpace()
{
	if(*m_ptr)
	{
		char * right = m_ptr + m_len - 1;
		const char * start = right;
		//isspace accepts 0..255 values in MSVC
		while((right >= m_ptr) && ((unsigned)(*right + 1) <= 256) && isspace(*right))
			right--;
		if(right != start)
		{
			m_len = (right - m_ptr) + 1;
			m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
			*(m_ptr + m_len) = '\0';
		}
	}
	return (*this);
}

KviCString & KviCString::stripRight(char c)
{
	if(*m_ptr)
	{
		char * right = m_ptr + m_len - 1;
		const char * start = right;
		while((right >= m_ptr) && (*right == c))
			right--;
		if(right != start)
		{
			m_len = (right - m_ptr) + 1;
			m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
			*(m_ptr + m_len) = '\0';
		}
	}
	return (*this);
}

KviCString & KviCString::stripSpace()
{
	// 0123456789
	//    abcd   0
	// ^        ^
	// left   right
	char * left = m_ptr;
	char * right = m_ptr + m_len - 1;
	// skip initial spaces
	while((*left == ' ') || (*left == '\t'))
		left++;
	if(*left)
	{
		// valid string, left points to first non-space
		while((right >= left) && ((*right == ' ') || (*right == '\t')))
			right--;
		// 0123456789
		//    abcd   0
		//    ^  ^
		// left   right
		m_len = (right - left) + 1;
		KviMemory::move(m_ptr, left, m_len);
		m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
		*(m_ptr + m_len) = '\0';
	}
	else
	{
		m_ptr = (char *)KviMemory::reallocate(m_ptr, 1);
		*m_ptr = '\0';
		m_len = 0;
	}
	return (*this);
}

bool KviCString::isNum() const
{
	char * p = m_ptr;
	while(isspace(*p))
		p++;
	if(*p == '-')
		p++;
	if(!isdigit(*p))
		return false;
	while(isdigit(*p))
		p++;
	while(isspace(*p))
		p++;
	return (*p == '\0');
}

bool KviCString::isUnsignedNum() const
{
	char * p = m_ptr;
	while(isspace(*p))
		p++;
	if(!isdigit(*p))
		return false;
	while(isdigit(*p))
		p++;
	while(isspace(*p))
		p++;
	return (*p == '\0');
}

static KviCString g_szApplicationWideEmptyString;

KviCString & KviCString::emptyString()
{
	return g_szApplicationWideEmptyString;
}

bool KviCString::ext_contains(const char * data, const char * item, bool caseS)
{
	if(item && data)
	{
		int len = (int)strlen(item);
		char c = tolower(*item);
		if(caseS)
		{
			while(*data)
			{
				while(*data && (tolower(*data) != c))
					data++;
				if(*data)
				{
					if(kvi_strEqualCSN(item, data, len))
						return true;
					else
						data++;
				}
			}
		}
		else
		{
			while(*data)
			{
				while(*data && (tolower(*data) != c))
					data++;
				if(*data)
				{
					if(kvi_strEqualCIN(item, data, len))
						return true;
					else
						data++;
				}
			}
		}
	}
	return false;
}