#include <algorithm>
#include <ctype.h>
#include <math.h>
#include "Data2.hxx"
#include "DataException.hxx"
#include "cpLog.h"
#if defined(WIN32) || defined(__QNX__)
#define strcasecmp(a,b) stricmp(a,b)
#define strncasecmp(a,b,c) strnicmp(a,b,c)
#endif
using namespace std;
const int Data::npos = INT_MAX;
Data::Data()
: mLength(0),
mBuf(0),
mCapacity(127)
{
mBuf = new char[mCapacity+1];
mBuf[0] = 0;
}
Data::Data(int capacity, bool)
: mLength(0),
mBuf(0),
mCapacity(capacity)
{
mBuf = new char[capacity+1];
mBuf[0] = 0;
}
Data::Data(const char* str, int length)
: mLength(length),
mBuf(new char[mLength+1]),
mCapacity(length)
{
assert(str);
memcpy(mBuf, str, length);
mBuf[length] = 0;
}
Data::Data(const char* str)
: mLength(0),
mBuf(0),
mCapacity(0)
{
assert(str);
mLength = strlen(str);
mCapacity = mLength;
mBuf = new char[mLength+1];
memcpy(mBuf, str, mLength+1);
}
Data::Data(const string& str) :
mLength(str.size()),
mBuf(new char[mLength+1]),
mCapacity(mLength)
{
memcpy(mBuf, str.c_str(), mLength+1);
}
Data::Data(int val)
: mLength(0),
mBuf(0),
mCapacity(0)
{
if (val == 0)
{
mBuf = new char[2];
mBuf[0] = '0';
mBuf[1] = 0;
mLength = 1;
return;
}
bool neg = false;
int value = val;
if (value < 0)
{
value = -value;
neg = true;
}
int c = 0;
int v = value;
while (v /= 10)
{
c++;
}
if (neg)
{
c++;
}
mLength = c+1;
mCapacity = c+1;
mBuf = new char[c+2];
mBuf[c+1] = 0;
v = value;
while (v)
{
mBuf[c--] = '0' + v%10;
v /= 10;
}
if (neg)
{
mBuf[0] = '-';
}
}
Data::Data(double value, int precision)
: mLength(0),
mBuf(0),
mCapacity(0)
{
assert(precision < 10);
double v = value;
bool neg = (value < 0.0);
if (neg)
{
v = -v;
}
Data m((unsigned long)v);
// remainder
v = v - floor(v);
int p = precision;
while (p--)
{
v *= 10;
}
int dec = (int)floor(v+0.5);
Data d;
if (dec == 0)
{
d = "0";
}
else
{
d.resize(precision);
d.mBuf[precision] = 0;
p = precision;
// neglect trailing zeros
bool significant = false;
while (p--)
{
if (dec % 10 || significant)
{
significant = true;
d.mLength++;
d.mBuf[p] = '0' + (dec % 10);
}
else
{
d.mBuf[p] = 0;
}
dec /= 10;
}
}
if (neg)
{
resize(m.length() + d.length() + 2);
mBuf[0] = '-';
memcpy(mBuf+1, m.mBuf, m.length());
mBuf[1+m.length()] = '.';
memcpy(mBuf+1+m.length()+1, d.mBuf, d.length()+1);
mLength = m.length() + d.length() + 2;
}
else
{
resize(m.length() + d.length() + 1);
memcpy(mBuf, m.mBuf, m.length());
mBuf[m.length()] = '.';
memcpy(mBuf+m.length()+1, d.mBuf, d.length()+1);
mLength = m.length() + d.length() + 1;
}
}
Data::Data(unsigned long value)
: mLength(0),
mBuf(0),
mCapacity(0)
{
if (value == 0)
{
mBuf = new char[2];
mBuf[0] = '0';
mBuf[1] = 0;
mLength = 1;
return;
}
int c = 0;
unsigned long v = value;
while (v /= 10)
{
c++;
}
mLength = c+1;
mCapacity = c+1;
mBuf = new char[c+2];
mBuf[c+1] = 0;
v = value;
while (v)
{
mBuf[c--] = '0' + v%10;
v /= 10;
}
}
Data::Data(char c)
: mLength(1),
mBuf(0),
mCapacity(mLength)
{
mBuf = new char[2];
mBuf[0] = c;
mBuf[1] = 0;
}
Data::Data(bool value)
: mLength(0),
mBuf(0),
mCapacity(0)
{
static char* truec = "true";
static char* falsec = "false";
if (value)
{
mBuf = new char[5];
mLength = 4;
mCapacity = 4;
memcpy(mBuf, truec, 5);
}
else
{
mBuf = new char[6];
mLength = 5;
mCapacity = 5;
memcpy(mBuf, falsec, 6);
}
}
Data::Data(const Data& rhs)
: mLength(rhs.mLength),
mBuf(new char[mLength+1]),
mCapacity(mLength)
{
memcpy(mBuf, rhs.mBuf, mLength+1);
}
Data::~Data()
{
delete[] mBuf;
}
Data&
Data::operator=(const char* str)
{
assert(str);
const int len = strlen(str);
if (len > mCapacity)
{
resize(len);
}
mLength = len;
memcpy(mBuf, str, mLength+1);
return *this;
}
Data&
Data::operator=( const Data& data )
{
if (&data != this)
{
if (data.length() > mCapacity)
{
resize(data.length());
}
mLength = data.length();
memcpy(mBuf, data.mBuf, data.mLength+1);
}
return *this;
}
const char*
Data::logData() const
{
return mBuf;
}
const char*
Data::c_str() const
{
return mBuf;
}
const char*
Data::getData(char* buf, int len) const
{
assert(len);
strncpy(buf, mBuf, len-1);
buf[len-1] = 0;
return buf;
}
const char*
Data::getData(LocalScopeAllocator& lo) const
{
lo.allocate(mLength+1);
memcpy(lo, mBuf, mLength+1);
return lo;
}
char
Data::getChar(int i) const
{
assert(i<mLength);
return mBuf[i];
}
void
Data::setchar(int i, char c)
{
if (i >= mLength)
{
resize(i+1);
mLength = i+1;
memset(mBuf + mLength, 0, mCapacity-mLength+1);
}
assert(i<mLength);
mBuf[i] = c;
}
char
Data::operator[](int i) const
{
assert(i<mLength);
return mBuf[i];
}
int
Data::length() const
{
return mLength;
}
void
Data::setBufferSize(int newCapacity)
{
resize(newCapacity);
}
void
Data::resize(int newCapacity)
{
if (newCapacity < mCapacity)
{
return;
}
char* oldBuf = mBuf;
mBuf = new char[newCapacity+1];
for (int i = 0; i < mLength; i++)
{
mBuf[i] = oldBuf[i];
}
mBuf[mLength] = 0;
mCapacity = newCapacity;
delete[] oldBuf;
}
bool
Data::operator==(const char* str) const
{
assert(str);
return strcmp(mBuf, str) == 0;
}
bool
Data::operator==( const Data& data) const
{
return strcmp(mBuf, data.mBuf) == 0;
}
bool
Data::operator!=(const char* str) const
{
assert(str);
return strcmp(mBuf, str) != 0;
}
bool
Data::operator!=(const Data& data) const
{
return strcmp(mBuf, data.mBuf) != 0;
}
bool
operator==(const char* str, const Data& data)
{
assert(str);
return strcmp(str, data.mBuf) == 0;
}
bool
operator!=(const char* str, const Data& data)
{
assert(str);
return strcmp(str, data.mBuf) != 0;
}
bool
Data::operator>(const Data& data) const
{
return strcmp(mBuf, data.mBuf) > 0;
}
bool
Data::operator<(const Data& data) const
{
return strcmp(mBuf, data.mBuf) < 0;
}
bool
Data::operator>(const char* data) const
{
return strcmp(mBuf, data) > 0;
}
bool
Data::operator<(const char* data) const
{
return strcmp(mBuf, data) < 0;
}
int
Data::compare(const char* str, int length) const
{
return strncmp(mBuf, str, length);
}
int
Data::compare(const Data& data) const
{
return strncmp(mBuf, data.mBuf, data.length());
}
int
Data::compareNoCase(const char* str, int length) const
{
return strncasecmp(mBuf, str, length);
}
int
Data::compareNoCase(const Data& data) const
{
return strncasecmp(mBuf, data.mBuf, data.length());
}
Data
Data::operator+(const Data& data) const
{
// reserve
Data ret(mLength + data.mLength, true);
memcpy(ret.mBuf, mBuf, mLength);
memcpy(ret.mBuf+mLength, data.mBuf, data.mLength+1);
ret.mLength = mLength + data.mLength;
return ret;
}
Data
Data::operator+(const char* str) const
{
assert(str);
// reserve
int l = strlen(str);
Data ret(length() + l, true);
memcpy(ret.mBuf, mBuf, mLength);
memcpy(ret.mBuf+mLength, str, l+1);
ret.mLength = mLength + l;
return ret;
}
Data
Data::operator+(const char c) const
{
// reserve
Data ret(length() + 1, true);
memcpy(ret.mBuf, mBuf, mLength);
ret.mBuf[mLength] = c;
ret.mBuf[mLength+1] = 0;
ret.mLength = mLength + 1;
return ret;
}
Data&
Data::operator+=(const Data& data)
{
if (mCapacity < mLength + data.mLength)
{
resize(mLength + data.mLength);
}
memcpy(mBuf+mLength, data.mBuf, data.mLength+1);
mLength += data.mLength;
return *this;
}
Data&
Data::operator+=(const char* str)
{
assert(str);
int l = strlen(str);
if (mCapacity < mLength + l)
{
resize(mLength + l);
}
memcpy(mBuf+mLength, str, l+1);
mLength += l;
return *this;
}
Data&
Data::operator+=(const char c)
{
if (mCapacity < mLength + 1)
{
resize(mLength + 1);
}
mBuf[mLength] = c;
mBuf[mLength+1] = 0;
mLength += 1;
return *this;
}
Data&
Data::lowercase()
{
char* p = mBuf;
while ((*p = tolower(*p)) != 0)
{
p++;
}
return *this;
}
Data&
Data::uppercase()
{
char* p = mBuf;
while ((*p = toupper(*p)) != 0)
{
p++;
}
return *this;
}
void
Data::erase()
{
mLength = 0;
mBuf[0] = 0;
}
int Data::convertInt() const
{
int val = 0;
char* p = mBuf;
int l = mLength;
int s = 1;
while (isspace(*p++))
{
l--;
}
p--;
if (*p == '-')
{
s = -1;
p++;
l--;
}
while (l--)
{
char c = *p++;
if ((c >= '0') && (c <= '9'))
{
val *= 10;
val += c - '0';
}
else
{
return s*val;
}
}
return s*val;
}
long Data::convertLong() const
{
long val = 0;
char* p = mBuf;
int l = mLength;
int s = 1;
while (isspace(*p++))
{
l--;
}
p--;
if (*p == '-')
{
s = -1;
p++;
l--;
}
while (l--)
{
char c = *p++;
if ((c >= '0') && (c <= '9'))
{
val *= 10;
val += c - '0';
}
else
{
return s*val;
}
}
return s*val;
}
string Data::convertString() const
{
return string(mBuf);
}
double Data::convertDouble() const
{
long val = 0;
char* p = mBuf;
int s = 1;
while (isspace(*p++));
p--;
if (*p == '-')
{
s = -1;
p++;
}
while (isdigit(*p))
{
val *= 10;
val += *p - '0';
p++;
}
if (*p == '.')
{
p++;
long d = 0;
double div = 1.0;
while (isdigit(*p))
{
d *= 10;
d += *p - '0';
div *= 10;
p++;
}
return s*(val + d/div);
}
return s*val;
}
int
Data::match(const char* match,
Data* retModifiedData,
bool replace,
Data replaceWith)
{
assert(match);
int retVal = FIRST;
int matchLength = strlen(match);
int replacePos = find(match);
if (replacePos == Data::npos)
{
return NOT_FOUND;
}
if (retModifiedData != 0)
{
*retModifiedData = Data(mBuf, replacePos);
if (retModifiedData->length() != 0)
{
retVal = FOUND;
}
}
if (replace)
{
if (mLength - replacePos - matchLength + replaceWith.length() <= mCapacity)
{
memcpy(mBuf + replaceWith.length(),
mBuf + replacePos + matchLength,
mLength - replacePos - matchLength + 1);
memcpy(mBuf, replaceWith.mBuf, replaceWith.length());
mLength = mLength - replacePos - matchLength + replaceWith.length();
}
else
{
// apparently we never need to grow on replace
assert(0);
}
}
return retVal;
}
bool isIn(char c, const char* match)
{
char p;
while((p = *match++))
{
if (p == c)
{
return true;
}
}
return false;
}
Data
Data::parse(const char* match, bool* matchFail )
{
assert(match);
int start = 0;
bool foundAny = false;
// find start
while (!foundAny && (start < mLength))
{
foundAny = isIn(mBuf[start++], match);
}
// find end
if (foundAny)
{
int end = --start;
while (end < mLength &&
isIn(mBuf[end], match))
{
end++;
}
// end--;
Data result(mBuf, start);
memcpy(mBuf, mBuf + end, mLength - end + 1);
mLength = mLength - end;
mBuf[mLength] = '\0';
assert(mLength >= 0);
if (matchFail)
{
*matchFail = false;
}
return result;
}
else
{
if (matchFail)
{
*matchFail = true;
}
Data result;//(0, true);
return result;
}
}
Data
Data::parseOutsideQuotes(const char* match,
bool useQuote,
bool useAngle,
bool* matchFail )
{
int pos = 0;
bool inDoubleQuotes = false;
bool inAngleBrackets = false;
bool foundAny = false;
while (!foundAny && (pos < mLength))
{
char p = mBuf[pos];
switch (p)
{
case '"':
if (!inAngleBrackets && useQuote)
{
inDoubleQuotes = !inDoubleQuotes;
}
break;
case '<':
if (!inDoubleQuotes && useAngle)
{
inAngleBrackets = true;
}
break;
case '>':
if (!inDoubleQuotes && useAngle)
{
inAngleBrackets = false;
}
break;
default:
break;
}
if (!inDoubleQuotes && !inAngleBrackets && isIn(p, match))
{
foundAny = true;
}
pos++;
}
int pos2 = pos;
while (foundAny &&
(pos2 < mLength) &&
isIn(mBuf[pos2], match))
{
pos2++;
}
if (foundAny)
{
Data result(mBuf, pos-1);
memcpy(mBuf, mBuf + pos2, mLength - pos2 + 1);
mLength -= pos2;
if (matchFail)
{
*matchFail = false;
}
return result;
}
else
{
if (matchFail)
{
*matchFail = true;
}
Data result;
return result;
}
}
Data
Data::matchChar(const char* match, char* matchedChar )
{
int pos = 0;
bool foundAny = false;
while (!foundAny && (pos < mLength))
{
char p = mBuf[pos];
if( isIn(p, match))
{
foundAny = true;
if (matchedChar)
{
*matchedChar = p;
}
}
pos++;
}
if (foundAny)
{
Data result(mBuf, pos-1);
memcpy(mBuf, mBuf+pos, mLength-pos+1);
mLength -= pos;
return result;
}
else
{
Data result;
if (matchedChar)
{
*matchedChar = '\0';
}
return result;
}
}
Data
Data::getLine(bool* matchFail )
{
const int STARTING = 0;
const int HAS_CR = 1;
const int HAS_LF = 2;
const int HAS_CRLF = 3;
int state = STARTING;
int pos = 0;
bool foundAny = false;
while (!foundAny && (pos < mLength))
{
char p = mBuf[pos];
switch(p)
{
case '\r':
state = HAS_CR;
break;
case '\n':
if (state == HAS_CR)
{
state = HAS_CRLF;
}
else
{
state = HAS_LF;
}
foundAny = true;
break;
default:
state = STARTING;
}
pos++;
}
int pos2 = pos;
if(state == HAS_CRLF)
{
pos--;
}
if (foundAny)
{
Data result(mBuf, pos-1);
memcpy(mBuf, mBuf+pos2, mLength-pos2+1);
mLength -= pos2;
if (matchFail)
{
*matchFail = false;
}
return result;
}
else
{
if (matchFail)
{
*matchFail = true;
}
Data result;
return result;
}
}
Data
Data::substring(int first, int last) const
{
if (last == -1 ||
last == Data::npos)
{
last = mLength;
}
assert(first <= last);
assert(first >= 0);
assert(last <= mLength);
return Data(mBuf+first, last-first);
}
bool
isEqualNoCase(const Data& left, const Data& right )
{
if (left.mLength != right.mLength)
{
return false;
}
return strncasecmp(left.mBuf, right.mBuf, left.mLength) == 0;
}
bool
isEqualNoCase(const char* left, const Data& right )
{
return strcasecmp(left, right.mBuf) == 0;
}
int
Data::find(const Data& match, int start) const
{
assert(start >= 0);
assert(start <= mLength);
char* pos = std::search(mBuf+start, mBuf+mLength,
match.mBuf, match.mBuf + match.mLength);
if (pos == mBuf+mLength)
{
if (match.mLength == 0)
{
if (mLength == 0)
{
return Data::npos;
}
return 0;
}
return Data::npos;
}
return pos - mBuf;
}
int
Data::find_first_of(Data find, int start) const
{
string f = find.convertString();
string me = this->convertString();
string::size_type p = me.find_first_of(f, start);
if (p == string::npos)
{
return Data::npos;
}
else
{
return p;
}
}
int
Data::find_first_not_of(Data find, int start) const
{
string f = find.convertString();
string me = this->convertString();
string::size_type p = me.find_first_not_of(f, start);
if (p == string::npos)
{
return Data::npos;
}
else
{
return p;
}
}
int
Data::find_last_of(Data find, int start) const
{
string f = find.convertString();
string me = this->convertString();
string::size_type p = me.find_last_of(f, start);
if (p == string::npos)
{
return Data::npos;
}
else
{
return p;
}
}
int
Data::find_last_not_of(Data find, int start) const
{
string f = find.convertString();
string me = this->convertString();
string::size_type p = me.find_last_not_of(f, start);
if (p == string::npos)
{
return Data::npos;
}
else
{
return p;
}
}
int
Data::find(const char* match, int start) const
{
assert(start >= 0);
assert(start <= mLength);
const int matchLength = strlen(match);
char* m = const_cast<char*>(match);
char* b = const_cast<char*>(mBuf);
char* pos = std::search(b+start, b+mLength,
m, m+matchLength);
assert(pos <= b+mLength);
assert(pos >= mBuf);
if (pos == b+mLength)
{
if (matchLength == 0)
{
if (mLength == 0)
{
return Data::npos;
}
return 0;
}
return Data::npos;
}
return pos - mBuf;
}
Data&
Data::removeSpaces()
{
int firstChar = 0;
while ((firstChar < mLength) &&
mBuf[firstChar] == ' ')
{
firstChar++;
}
int lastChar = mLength-1;
while ((lastChar > 0) && (mBuf[lastChar] == ' '))
{
lastChar--;
}
if (firstChar > lastChar)
{
erase();
}
else
{
memcpy(mBuf, mBuf+firstChar, lastChar-firstChar+1);
mLength = lastChar-firstChar+1;
mBuf[mLength] = 0;
}
return *this;
}
// the functionality of this method has changed from the implementation in
// CopyOnWrite. It now looks for folded lines which mean a CRLF followed by
// whitespace and replaces the CRLF with two spaces (' '). This should allow the
// parser to continue since lines will no longer be folded
Data&
Data::removeLWS()
{
char* p = mBuf;
char* end = mBuf + mLength - 2;
while (p != 0 && p < end)
{
// look for CRLF + ' ' or '\t' since this indicates line folding
// will not go past end, since && will short circuit when == 0
if (*p == '\r' && *(p+1) == '\n' && (*(p+2) == ' ' || (*(p+2) == '\t')))
{
*p++ = ' '; // replace \r with ' '
*p++ = ' ';// replace \n with ' '
}
else
{
p++;
}
}
return *this;
}
void
Data::expand(const Data& startFrom,
const Data& findstr,
const Data& replstr,
const Data& delimiter)
{
assert(0);
int startPos = find(startFrom);
if (startPos < Data::npos)
{
int delimPos = find(delimiter, startPos);
int findPos = find(findstr, startPos);
while (findPos < delimPos)
{
//found replstr, replace
replace(findPos, findstr.mLength, replstr.mBuf, replstr.mLength);
//find next.
delimPos = find(delimiter, findPos + replstr.mLength);
findPos = find(findstr, findPos);
}
}
}
Data&
Data::replace(int startPos, int numElements, const Data& replacement)
{
assert((startPos + numElements) <= mLength);
return replace(startPos, startPos + numElements, replacement.c_str(), replacement.size());
}
Data&
Data::replace(int startPos, int endPos, const char* replaceStr, int replaceLength)
{
assert(replaceStr);
assert(startPos < endPos);
assert(endPos <= mLength);
resize(startPos + replaceLength + (mLength - endPos));
memcpy(mBuf + startPos + replaceLength,
mBuf + endPos, mLength-endPos + 1);
memcpy(mBuf + startPos, replaceStr, replaceLength);
mLength = startPos + replaceLength + (mLength - endPos);
return *this;
}
ostream&
operator<<(ostream& s, const Data& data)
{
s << data.mBuf;
return s;
}
syntax highlighted by Code2HTML, v. 0.9.1