296 lines
5.5 KiB
C++
296 lines
5.5 KiB
C++
#include "stdafx.h"
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include "SimplStr.h"
|
|
|
|
// A simple string class
|
|
// This one is designed for minimal footprint, lack of virtual functions
|
|
// and UTF8/Unicode support
|
|
|
|
|
|
short strcasecmp(const char *a, const char *b)
|
|
{
|
|
for( ; ((*a > 96 ? *a - 32 : *a) == (*b > 96 ? *b - 32 : *b)) && *a; a++, b++)
|
|
{}
|
|
|
|
return (*a > 96 ? *a - 32 : *a) - (*b > 96 ? *b - 32 : *b);
|
|
}
|
|
|
|
CSimpleString::CSimpleString()
|
|
{
|
|
myData = 0;
|
|
myLength = 0;
|
|
myActualLength = 16; // Not true when myData == 0, but an optimization
|
|
myUTFPos = 0;
|
|
}
|
|
|
|
CSimpleUTFString::CSimpleUTFString()
|
|
{
|
|
myData = 0;
|
|
myLength = 0;
|
|
myActualLength = 16; // Not true when myData == 0, but an optimization
|
|
}
|
|
|
|
CSimpleString::~CSimpleString()
|
|
{
|
|
if(myData)
|
|
delete [] myData;
|
|
}
|
|
|
|
CSimpleUTFString::~CSimpleUTFString()
|
|
{
|
|
if(myData)
|
|
delete [] myData;
|
|
}
|
|
|
|
HRESULT CSimpleString::Grow(unsigned newSize)
|
|
{
|
|
HRESULT rc = S_OK;
|
|
|
|
if(!myData || newSize > myActualLength)
|
|
{
|
|
while(myActualLength < newSize)
|
|
myActualLength *= 2;
|
|
|
|
char *newData = new char[myActualLength];
|
|
if ( newData )
|
|
{
|
|
assert(newData != 0);
|
|
if(myData != 0 && myLength > 0)
|
|
{
|
|
assert(newData != 0);
|
|
assert(myData != 0);
|
|
assert(myLength > 0);
|
|
assert(myLength < 0x01000000); // Sanity checking
|
|
|
|
memmove(newData, myData, myLength);
|
|
delete [] myData;
|
|
}
|
|
myData = newData;
|
|
}
|
|
else
|
|
{
|
|
rc = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
HRESULT CSimpleUTFString::Grow(unsigned newSize)
|
|
{
|
|
HRESULT rc = S_OK;
|
|
if(!myData || newSize > myActualLength)
|
|
{
|
|
while(myActualLength < newSize)
|
|
myActualLength *= 2;
|
|
|
|
unsigned short *newData = new unsigned short[myActualLength];
|
|
if ( newData )
|
|
{
|
|
assert(newData != 0);
|
|
if(myData != 0 && myLength > 0)
|
|
{
|
|
assert(newData != 0);
|
|
assert(myData != 0);
|
|
assert(myLength > 0);
|
|
assert(myLength < 0x01000000); // Sanity checking
|
|
|
|
memmove(newData, myData, myLength * 2);
|
|
delete [] myData;
|
|
}
|
|
myData = newData;
|
|
}
|
|
else
|
|
{
|
|
rc = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
HRESULT CSimpleString::Copy(CSimpleString *val)
|
|
{
|
|
HRESULT rc = Grow(val->myLength);
|
|
if ( !FAILED( rc ) )
|
|
{
|
|
myLength = val->myLength;
|
|
memmove(myData, val->myData, myLength);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
HRESULT CSimpleUTFString::Copy(unsigned short *unicodeChars, unsigned long length)
|
|
{
|
|
HRESULT rc = Grow(length);
|
|
if ( !FAILED( rc ) )
|
|
{
|
|
myLength = length;
|
|
memmove(myData, unicodeChars, length * sizeof(unsigned short));
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
HRESULT CSimpleUTFString::Copy(CSimpleUTFString *val)
|
|
{
|
|
HRESULT rc = Grow(val->myLength);
|
|
if ( !FAILED(rc) )
|
|
{
|
|
myLength = val->myLength;
|
|
memmove(myData, val->myData, myLength * 2);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
HRESULT CSimpleString::Cat(unsigned char theChar)
|
|
{
|
|
HRESULT rc = Grow(myLength + 1);
|
|
if ( !FAILED(rc) )
|
|
{
|
|
myData[myLength++] = theChar;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
HRESULT CSimpleUTFString::Cat(unsigned short theChar)
|
|
{
|
|
HRESULT rc = Grow(myLength + 1);
|
|
if ( !FAILED(rc) )
|
|
{
|
|
myData[myLength++] = theChar;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
HRESULT CSimpleUTFString::Cat(char * theChars)
|
|
{
|
|
HRESULT rc = S_OK;
|
|
while(*theChars)
|
|
{
|
|
rc = Grow(myLength + 1);
|
|
if ( FAILED(rc) )
|
|
{
|
|
return rc;
|
|
}
|
|
myData[myLength++] = *theChars;
|
|
theChars++;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
HRESULT CSimpleUTFString::Cat(unsigned char theChar)
|
|
{
|
|
HRESULT rc = S_OK;
|
|
// So that it will inline better
|
|
if(!(theChar & 0x80) || myUTFPos == 0)
|
|
{
|
|
rc = Grow(myLength + 1);
|
|
if ( FAILED(rc) )
|
|
{
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
if(theChar & 0x80)
|
|
{
|
|
if(myUTFPos == 0)
|
|
{
|
|
if(theChar & 0x20) // 1st byte of three byte sequence
|
|
{
|
|
myData[myLength] = (theChar & 0x0f) << 12;
|
|
myUTFPos = 2;
|
|
}
|
|
else // 1st byte of a two byte sequence
|
|
{
|
|
myData[myLength] = (theChar & 0x1f) << 6;
|
|
myUTFPos = 1;
|
|
}
|
|
}
|
|
else if(myUTFPos == 1) // 2nd byte of a two byte sequence
|
|
{
|
|
myData[myLength++] |= (theChar & 0x3f);
|
|
myUTFPos = 0;
|
|
}
|
|
else if(myUTFPos == 2)
|
|
{
|
|
myData[myLength] |= (theChar & 0x3f) << 6;
|
|
myUTFPos = 3;
|
|
}
|
|
else
|
|
{
|
|
myData[myLength++] |= (theChar & 0x3f);
|
|
myUTFPos = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
myData[myLength++] = theChar;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
// The caller must call delete [] on the return value
|
|
char * CSimpleString::toString(void)
|
|
{
|
|
char *newData = new char[myLength + 1];
|
|
if ( newData )
|
|
{
|
|
memmove(newData, myData, myLength);
|
|
newData[myLength] = 0;
|
|
}
|
|
return newData;
|
|
}
|
|
|
|
char * CSimpleUTFString::toString(void)
|
|
{
|
|
char *newData = new char[myLength + 2];
|
|
if ( newData )
|
|
{
|
|
unsigned long i;
|
|
for(i = 0; i < myLength; i++)
|
|
newData[i] = (char) myData[i];
|
|
newData[myLength] = 0;
|
|
newData[myLength + 1] = 0;
|
|
}
|
|
return newData;
|
|
}
|
|
|
|
HRESULT CSimpleUTFString::Extract(char *into)
|
|
{
|
|
unsigned long i;
|
|
for(i = 0; i < myLength; i++)
|
|
into[i] = (char) myData[i];
|
|
into[myLength] = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
long CSimpleString::Cmp(char *compareString, BOOL caseSensitive)
|
|
{
|
|
if ( FAILED( Grow(myLength + 1) ) )
|
|
{
|
|
return -1;
|
|
}
|
|
myData[myLength] = 0;
|
|
if(caseSensitive)
|
|
return strcmp(compareString, myData);
|
|
else
|
|
return strcasecmp(compareString, myData);
|
|
}
|
|
|
|
long CSimpleUTFString::Cmp(char *compareString, BOOL caseSensitive)
|
|
{
|
|
char *val = toString();
|
|
short result = -1;
|
|
|
|
if ( val )
|
|
{
|
|
if(caseSensitive)
|
|
result = strcmp(compareString, val);
|
|
else
|
|
result = strcasecmp(compareString, val);
|
|
|
|
delete [] val;
|
|
}
|
|
return result;
|
|
}
|
|
|