blob: d169c257e24a438dfdfdc4244e07d24053b768c1 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* $Id: DOMString.cpp 568078 2007-08-21 11:43:25Z amassari $
*/
#include <stdio.h>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/RuntimeException.hpp>
#include <xercesc/util/TransService.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/XMLRegisterCleanup.hpp>
#include "DOM_DOMException.hpp"
#include "DOMString.hpp"
#ifndef XML_DEBUG
#include "DOMStringImpl.hpp"
#endif
#include <assert.h>
#include <string.h>
XERCES_CPP_NAMESPACE_BEGIN
//----------------------------------------------
//
// Forward decls
//
//----------------------------------------------
static void reinitDomConverter();
static void reinitDomMutex();
XMLLCPTranscoder* getDomConverter();
// ---------------------------------------------------------------------------
// Local static functions
// ---------------------------------------------------------------------------
// getDOMConverter - get the converter from the system default
// codepage to Unicode that is to be used when
// a DOMString is constructed from a char *.
//
static XMLLCPTranscoder* gDomConverter = 0;
static XMLRegisterCleanup cleanupDomConverter;
int DOMString::gLiveStringDataCount = 0;
int DOMString::gTotalStringDataCount = 0;
int DOMString::gLiveStringHandleCount = 0;
int DOMString::gTotalStringHandleCount = 0;
XMLLCPTranscoder* getDomConverter()
{
if (!gDomConverter)
{
XMLLCPTranscoder* transcoder = XMLPlatformUtils::fgTransService->makeNewLCPTranscoder();
if (!transcoder)
XMLPlatformUtils::panic(PanicHandler::Panic_NoDefTranscoder
);
if (XMLPlatformUtils::compareAndSwap((void **)&gDomConverter, transcoder, 0) != 0)
delete transcoder;
else
cleanupDomConverter.registerCleanup(reinitDomConverter);
}
return gDomConverter;
}
//
// There is one global mutex that is used to synchronize access to the
// allocator free list for DOMStringHandles. This function gets that
// mutex, and will create it on the first attempt to get it.
//
static XMLMutex* DOMStringHandleMutex = 0; // Mutex will be deleted by ~DOMStringHandle.
static XMLRegisterCleanup cleanupDomMutex;
XMLMutex& DOMStringHandle::getMutex()
{
if (!DOMStringHandleMutex)
{
XMLMutex* tmpMutex = new XMLMutex(XMLPlatformUtils::fgMemoryManager);
if (XMLPlatformUtils::compareAndSwap((void**)&DOMStringHandleMutex, tmpMutex, 0))
{
// Someone beat us to it, so let's clean up ours
delete tmpMutex;
}
else
cleanupDomMutex.registerCleanup(reinitDomMutex);
}
return *DOMStringHandleMutex;
}
//----------------------------------------------
//
// DOMStringData
//
//----------------------------------------------
void DOMStringData::removeRef()
{
int result = XMLPlatformUtils::atomicDecrement(fRefCount);
if (result==0)
{
fBufferLength = 0xcccc;
fRefCount = 0xcccc;
XMLPlatformUtils::fgMemoryManager->deallocate(this);//delete [] this; // was allocated with new char[size] !
XMLPlatformUtils::atomicDecrement(DOMString::gLiveStringDataCount);
}
}
void DOMStringData::addRef()
{
XMLPlatformUtils::atomicIncrement(fRefCount);
}
DOMStringData *DOMStringData::allocateBuffer(unsigned int length)
{
unsigned int sizeToAllocate = sizeof(DOMStringData) // buffer will contain an
+ length*sizeof(XMLCh); // extra elem because of stub
// array in DOMStringData struct.
DOMStringData *buf = 0;
buf = (DOMStringData *) XMLPlatformUtils::fgMemoryManager->allocate
(
sizeToAllocate * sizeof(char)
);//new char[sizeToAllocate];
XMLPlatformUtils::atomicIncrement(DOMString::gLiveStringDataCount);
XMLPlatformUtils::atomicIncrement(DOMString::gTotalStringDataCount);
buf->fBufferLength = length;
buf->fRefCount = 1;
buf->fData[0] = 0;
return buf;
}
//----------------------------------------------------
//
// DOMStringHandle
//
//-----------------------------------------------------
//
// Specialized new and delete operators for DOMStringHandles.
// These are used, rather than the standard system operator new,
// for improved performance.
//
// We allocate largish blocks of memory using the standard system
// new function, and sub-allocate string handles from that block.
// Un-allocated string handles within the allocated blocks are kept
// in a singly linked list, making allocation and deallocation
// very quick in the common case.
//
// String handle allocation is thread safe. A multi-threaded
// application may have threads concurrently accessing multiple
// DOM documents; since all string handles come from the same pool,
// this allocator must be safe. The compare and exchange function,
// which is available as a single instruction in most processor
// architectures, and typically surfaced as an OS function,
// is used to safely update the string handle free list.
//
void *DOMStringHandle::freeListPtr = 0; // Point to the head of the
// free list of un-allocated
// string handles, or 0 if there
// are no free string handles.
static const int allocGroupSize = 1024; // Number of string handles to allocate
// as a chunk from the system's
// memory allocator.
DOMStringHandle *DOMStringHandle::blockListPtr = 0; // Point to the head of the list
// of larger blocks in which DOMStringHandles
// are allocated.
//
// Operator new for DOMStringHandles. Called implicitly from the
// DOMStringHandle constructor.
//
void *DOMStringHandle::operator new(size_t sizeToAlloc)
{
assert(sizeToAlloc == sizeof(DOMStringHandle));
void *retPtr;
XMLMutexLock lock(&getMutex()); // Lock the DOMStringHandle mutex for
// the duration of this function.
if (freeListPtr == 0)
{
// Uncommon case. The free list of string handles is empty
// Allocate a new batch of them, using the system's
// operator new to get a chunk of memory.
//
DOMStringHandle *dsg = (DOMStringHandle*)
XMLPlatformUtils::fgMemoryManager->allocate
(
allocGroupSize * sizeof(DOMStringHandle)
);//::new DOMStringHandle[allocGroupSize];
// Link the block itself into the list of blocks. The purpose of this is to
// let us locate and delete the blocks when shutting down.
//
*(DOMStringHandle **)dsg = blockListPtr;
blockListPtr = dsg;
// Link all of the new storage for StringHandles into the StringHandle free list
int i; // Start with index 1; index 0 is reserved for linking the
// larger allocation blocks together.
for (i=1; i<allocGroupSize-1; i++) {
*(void **)&dsg[i] = freeListPtr;
freeListPtr = &dsg[i];
}
}
retPtr = freeListPtr;
freeListPtr = *(void **)freeListPtr;
XMLPlatformUtils::atomicIncrement(DOMString::gLiveStringHandleCount);
return retPtr;
}
//
// Operator delete for DOMStringHandles. Called implicitly from the
// Destructor for DOMStringHandle.
//
void DOMStringHandle::operator delete(void *pMem)
{
XMLMutexLock lock(&getMutex()); // Lock the DOMStringHandle mutex for the
// duration of this function.
XMLPlatformUtils::atomicDecrement(DOMString::gLiveStringHandleCount);
*(void **)pMem = freeListPtr;
freeListPtr = pMem;
// If ALL of the string handles are gone, delete the storage blocks used for the
// handles as well.
if (DOMString::gLiveStringHandleCount == 0)
{
DOMStringHandle *pThisBlock, *pNextBlock;
for (pThisBlock = blockListPtr; pThisBlock != 0; pThisBlock = pNextBlock)
{
pNextBlock = *(DOMStringHandle **)pThisBlock;
XMLPlatformUtils::fgMemoryManager->deallocate(pThisBlock);//delete [] pThisBlock;
}
blockListPtr = 0;
freeListPtr = 0;
}
}
void DOMStringHandle::addRef()
{
XMLPlatformUtils::atomicIncrement(fRefCount);
}
void DOMStringHandle::removeRef()
{
int result = XMLPlatformUtils::atomicDecrement(fRefCount);
if (result==0)
{
fDSData->removeRef();
// delete this;
DOMStringHandle* ptr = this;
delete ptr;
}
}
DOMStringHandle *DOMStringHandle::createNewStringHandle(unsigned int bufLength)
{
DOMStringHandle *h = new DOMStringHandle;
XMLPlatformUtils::atomicIncrement(DOMString::gTotalStringHandleCount);
h -> fLength = 0;
h -> fRefCount = 1;
h -> fDSData = DOMStringData::allocateBuffer(bufLength);
return h;
}
DOMStringHandle *DOMStringHandle::cloneStringHandle()
{
DOMStringHandle *h = new DOMStringHandle;
h->fLength = fLength;
h->fRefCount = 1;
h->fDSData = fDSData;
h->fDSData->addRef();
return h;
}
//------------------------------------------------------------
//
// DOMString
//
//------------------------------------------------------------
DOMString::DOMString()
{
fHandle = 0;
}
DOMString::DOMString(const DOMString &other) :
XMemory(other)
{
fHandle = other.fHandle;
if (fHandle)
fHandle->addRef();
}
DOMString::DOMString(const XMLCh *data)
{
fHandle = 0;
if (data != 0)
{
unsigned int dataLength = 0;
while (data[dataLength] != 0)
++dataLength;
if (dataLength != 0)
{
fHandle = DOMStringHandle::createNewStringHandle(dataLength+1);
fHandle->fLength = dataLength;
XMLCh *strData = fHandle->fDSData->fData;
unsigned int i;
for (i=0; i<dataLength ; ++i)
strData[i] = data[i];
strData[dataLength] = 0;
}
}
}
DOMString::DOMString(const XMLCh *data, unsigned int dataLength)
{
fHandle = 0;
if (data != 0)
{
if (dataLength > 0)
{
fHandle = DOMStringHandle::createNewStringHandle(dataLength+1);
fHandle->fLength = dataLength;
XMLCh *strData = fHandle->fDSData->fData;
unsigned int i;
for (i=0; i<dataLength ; ++i)
strData[i] = data[i];
strData[dataLength] = 0;
}
}
}
//
// Create a DOMString from a char * string in the default code page
// of the system on which we are executing.
//
//
DOMString::DOMString(const char *srcString)
{
fHandle = 0;
if (srcString != 0)
{
XMLLCPTranscoder* uniConverter = getDomConverter();
unsigned int srcLen = strlen(srcString);
if (srcLen == 0)
return;
// The charsNeeded normally is same as srcLen. To enhance performance,
// we start with this estimate, and if overflow, then call calcRequiredSize for actual size
fHandle = DOMStringHandle::createNewStringHandle(srcLen + 1);
XMLCh *strData = fHandle->fDSData->fData;
if (!uniConverter->transcode(srcString, strData, srcLen) || (XMLString::stringLen(strData) != srcLen))
{
// conversion failed, so try again
if (fHandle)
fHandle->removeRef();
fHandle = 0;
srcLen = uniConverter->calcRequiredSize(srcString);
fHandle = DOMStringHandle::createNewStringHandle(srcLen + 1);
XMLCh *strData2 = fHandle->fDSData->fData;
if (!uniConverter->transcode(srcString, strData2, srcLen))
{
// <TBD> We should throw something here?
}
}
fHandle->fLength = srcLen;
}
}
DOMString::DOMString(int nullValue)
{
assert(nullValue == 0);
fHandle = 0;
}
DOMString::~DOMString()
{
if (fHandle)
fHandle->removeRef();
fHandle = 0;
}
DOMString & DOMString::operator =(const DOMString &other)
{
if (this == &other)
return *this;
if (fHandle)
fHandle->removeRef();
fHandle = other.fHandle;
if (fHandle)
fHandle->addRef();
return *this;
}
DOMString & DOMString::operator = (DOM_NullPtr *arg)
{
assert(arg == 0);
if (fHandle)
fHandle->removeRef();
fHandle = 0;
return *this;
}
bool DOMString::operator ==(const DOMString &other) const
{
return this->fHandle == other.fHandle;
}
bool DOMString::operator !=(const DOMString &other) const
{
return this->fHandle != other.fHandle;
}
bool DOMString::operator == (const DOM_NullPtr * /*p*/) const
{
return (fHandle == 0);
}
bool DOMString::operator != (const DOM_NullPtr * /*p*/) const
{
return (fHandle != 0);
}
void DOMString::reserve(unsigned int size)
{
if (fHandle == 0)
{
if (size > 0)
fHandle = DOMStringHandle::createNewStringHandle(size);
}
}
void DOMString::appendData(const DOMString &other)
{
if (other.fHandle == 0 || other.fHandle->fLength == 0)
return;
// If this string is empty and this string does not have an
// already allocated buffer sufficient to hold the string being
// appended, return a clone of the other string.
//
if (fHandle == 0 || (fHandle->fLength == 0 &&
fHandle->fDSData->fBufferLength < other.fHandle->fLength))
{
if (fHandle) fHandle->removeRef();
this->fHandle = other.fHandle->cloneStringHandle();
return;
}
unsigned int newLength = fHandle->fLength + other.fHandle->fLength;
if (newLength >= fHandle->fDSData->fBufferLength ||
fHandle->fDSData->fRefCount > 1)
{
// We can't stick the data to be added onto the end of the
// existing string, either because there is not space in
// the buffer, or because the buffer is being shared with
// some other string. So, make a new buffer.
DOMStringData *newBuf = DOMStringData::allocateBuffer(newLength+1);
XMLCh *newP = newBuf->fData;
XMLCh *oldP = fHandle->fDSData->fData;
unsigned int i;
for (i=0; i<fHandle->fLength; ++i)
newP[i] = oldP[i];
fHandle->fDSData->removeRef();
fHandle->fDSData = newBuf;
}
//
// This string now had enough buffer room to hold the data to
// be appended. Go ahead and copy it in.
XMLCh *srcP = other.fHandle->fDSData->fData;
XMLCh *destP = &fHandle->fDSData->fData[fHandle->fLength];
unsigned int i;
for (i=0; i<other.fHandle->fLength; i++)
destP[i] = srcP[i];
fHandle->fLength += other.fHandle->fLength;
}
void DOMString::appendData(XMLCh ch)
{
unsigned int newLength = 0;
if (fHandle == 0)
{
fHandle = DOMStringHandle::createNewStringHandle(2);
newLength = 1;
}
else
newLength = fHandle->fLength + 1;
if (newLength >= fHandle->fDSData->fBufferLength ||
fHandle->fDSData->fRefCount > 1)
{
// We can't stick the data to be added onto the end of the
// existing string, either because there is not space in
// the buffer, or because the buffer is being shared with
// some other string. So, make a new buffer.
DOMStringData *newBuf = DOMStringData::allocateBuffer(newLength+1);
XMLCh *newP = newBuf->fData;
XMLCh *oldP = fHandle->fDSData->fData;
unsigned int i;
for (i=0; i<fHandle->fLength; ++i)
newP[i] = oldP[i];
fHandle->fDSData->removeRef();
fHandle->fDSData = newBuf;
}
XMLCh *destP = &fHandle->fDSData->fData[fHandle->fLength];
destP[0] = ch;
fHandle->fLength ++;
}
// TODO: A custom version could be written more efficiently, avoiding
// the creation of the temporary DOMString
void DOMString::appendData(const XMLCh* other)
{
appendData(DOMString(other));
}
DOMString& DOMString::operator +=(const DOMString &other)
{
appendData(other);
return *this;
}
DOMString& DOMString::operator +=(const XMLCh *str)
{
appendData(str);
return *this;
}
DOMString& DOMString::operator +=(XMLCh ch)
{
appendData(ch);
return *this;
}
XMLCh DOMString::charAt(unsigned int index) const
{
XMLCh retCh = 0;
if ((fHandle != 0) && (index < fHandle->fLength))
retCh = fHandle->fDSData->fData[index];
return retCh;
}
DOMString DOMString::clone() const
{
DOMString retString;
if (fHandle != 0)
retString.fHandle = this->fHandle->cloneStringHandle();
return retString;
}
void DOMString::deleteData(unsigned int offset, unsigned int delLength)
{
unsigned int stringLen = this->length();
if (offset > stringLen)
throw DOM_DOMException(DOM_DOMException::INDEX_SIZE_ERR, 0);
// Cap the value of delLength to avoid trouble with overflows
// in the following length computations.
if (delLength > stringLen)
delLength = stringLen;
// If the length of data to be deleted would extend off the end
// of the string, cut it back to stop at the end of string.
if (offset + delLength >= stringLen)
delLength = stringLen - offset;
if (delLength == 0)
return;
unsigned int newStringLength = stringLen - delLength;
if (fHandle->fDSData->fRefCount > 1 && offset+delLength < stringLen)
{
// The deletion is of a range in the middle of the string
// and there's another string handle using the buffer so
// we need to make a new buffer before moving characters
// around.
DOMStringData *newBuf = DOMStringData::allocateBuffer(newStringLength+1);
XMLCh *newP = newBuf->fData;
XMLCh *oldP = fHandle->fDSData->fData;
unsigned int i;
for (i=0; i<offset; i++)
newP[i] = oldP[i];
for (i=offset; i<newStringLength; i++)
newP[i] = oldP[i+delLength];
fHandle->fLength = newStringLength;
fHandle->fDSData->removeRef();
fHandle->fDSData = newBuf;
}
else if (offset+delLength < stringLen)
{
// The deletion is of a range in the middle of the string,
// but no other string is sharing the buffer, so we can
// just delete in place.
unsigned int i;
XMLCh *bufP = fHandle->fDSData->fData;
for (i=offset; i<newStringLength; i++)
bufP[i] = bufP[i+delLength];
fHandle->fLength = newStringLength;
}
else
{
// The deletion continues to the end of the string.
// Simply reset the length. We don't need to worry
// about other strings sharing the buffer because
// no characters are moved.
fHandle->fLength = newStringLength;
}
}
bool DOMString::equals(const DOMString &other) const
{
bool retVal = true;
if (this->fHandle != 0 && other.fHandle != 0)
{
if (this->fHandle->fLength != other.fHandle->fLength)
{
retVal = false;
}
else
{
XMLCh *thisP = this->fHandle->fDSData->fData;
XMLCh *otherP = other.fHandle->fDSData->fData;
unsigned int i;
for (i=0; i<this->fHandle->fLength; i++)
{
if (thisP[i] != otherP[i])
{
retVal = false;
break;
}
}
}
}
else
{
// At this point, one or more of the fHandle
// pointers is known to be zero.
if (fHandle && fHandle->fLength != 0 ||
other.fHandle && other.fHandle->fLength != 0)
retVal = false;
}
return retVal;
}
bool DOMString::equals(const XMLCh *other) const
{
if (this->fHandle != 0 && other != 0)
{
// Both strings have non-null data pointers, so
// we can go ahead and actually compare them.
XMLCh *thisP = this->fHandle->fDSData->fData;
unsigned int len = this->fHandle->fLength;
unsigned int i;
for (i=0; i<len; i++)
{
if (other[i] == 0) // "other" is null terminated.
return false; // (If there were no chance of a DOM
// string having a 0 char in the middle of
// it, this test could be omitted.)
if (thisP[i] != other[i])
return false;
}
if (other[len] != 0) // This test for the end of the other
return false; // string can't be done without first
// checking that we haven't walked off the
// end. (It has actually happened - off end
// of string, page, and valid memory.)
return true;
}
// At this point, we know that at least one of the strings had a null
// data pointer.
if (fHandle && fHandle->fLength != 0)
return false;
if (other && *other != 0)
return false;
return true; // Both strings are empty. DOMString treats zero-length
// and a null data pointer as equivalent.
}
void DOMString::insertData(unsigned int offset, const DOMString &src)
{
unsigned int origStrLength = this->length();
if (offset > origStrLength)
throw DOM_DOMException(DOM_DOMException::INDEX_SIZE_ERR, 0);
if (fHandle == 0)
{
*this = src.clone();
return;
}
if (src.fHandle == 0 || src.fHandle->fLength == 0)
return;
XMLCh *srcP = src.fHandle->fDSData->fData;
unsigned int srcLength = src.fHandle->fLength;
unsigned int newLength = fHandle->fLength + srcLength;
if (newLength >= fHandle->fDSData->fBufferLength ||
fHandle->fDSData->fRefCount > 1 || fHandle == src.fHandle )
{
// We can't stick the data to be added into the
// existing string, either because there is not space in
// the buffer, or because the buffer is being shared with
// some other string.
// So, make a new buffer.
DOMStringData *newBuf = DOMStringData::allocateBuffer(newLength+1);
XMLCh *newP = newBuf->fData;
XMLCh *oldP = fHandle->fDSData->fData;
unsigned int i;
for (i=0; i<offset; ++i)
newP[i] = oldP[i];
for (i=0; i<srcLength; i++)
newP[i+offset] = srcP[i];
for (i=offset; i<origStrLength; i++)
newP[i+srcLength] = oldP[i];
fHandle->fDSData->removeRef();
fHandle->fDSData = newBuf;
}
else
{
// There is room in the already-existing buffer to hold
// the data to be inserted. Insert it.
//
XMLCh *destP = fHandle->fDSData->fData;
int i;
for (i=(int)origStrLength-1; i>=(int)offset; i--)
destP[i+srcLength] = destP[i];
unsigned int j;
for (j=0; j<srcLength; j++)
destP[j+offset] = srcP[j];
}
fHandle->fLength += srcLength;
}
unsigned int DOMString::length() const
{
unsigned int len = 0;
if (fHandle != 0)
len = fHandle->fLength;
return len;
}
void DOMString::print() const
{
unsigned int len = this->length();
if (len > 0)
{
// Transcode from Unicode to char * in whatever the system local code page is.
char *pc = transcode(XMLPlatformUtils::fgMemoryManager);
fputs(pc, stdout);
XMLPlatformUtils::fgMemoryManager->deallocate(pc);//delete [] pc;
}
}
void DOMString::println() const
{
print();
putchar('\n');
}
const XMLCh *DOMString::rawBuffer() const
{
XMLCh *retP = 0;
if (fHandle)
{
retP = fHandle->fDSData->fData;
retP[fHandle->fLength]=0;
}
return retP;
}
char *DOMString::transcode() const
{
if (!fHandle || fHandle->fLength == 0)
{
char* retP = new char[1];
*retP = 0;
return retP;
}
// We've got some data
const XMLCh* srcP = rawBuffer();
//
// Find out how many output chars we need and allocate a buffer big enough
// for that plus a null.
//
// The charsNeeded normally is same as fHandle->fLength. To enhance performance,
// we start with this estimate, and if overflow, then call calcRequiredSize for actual size
unsigned int charsNeeded = fHandle->fLength;
char* retP = new char[charsNeeded + 1];
if (!getDomConverter()->transcode(srcP, retP, charsNeeded) || (XMLString::stringLen(retP) != charsNeeded))
{
delete [] retP;
charsNeeded = getDomConverter()->calcRequiredSize(srcP);
retP = new char[charsNeeded + 1];
if (!getDomConverter()->transcode(srcP, retP, charsNeeded))
{
// <TBD> We should throw something here?
}
}
// Cap it off and return it
retP[charsNeeded] = 0;
return retP;
}
char *DOMString::transcode(MemoryManager* const manager) const
{
if (!fHandle || fHandle->fLength == 0)
{
char* retP = (char*) manager->allocate(sizeof(char));//new char[1];
*retP = 0;
return retP;
}
// We've got some data
const XMLCh* srcP = rawBuffer();
//
// Find out how many output chars we need and allocate a buffer big enough
// for that plus a null.
//
// The charsNeeded normally is same as fHandle->fLength. To enhance performance,
// we start with this estimate, and if overflow, then call calcRequiredSize for actual size
unsigned int charsNeeded = fHandle->fLength;
char* retP = (char*) manager->allocate((charsNeeded + 1) * sizeof(char));//new char[charsNeeded + 1];
if (!getDomConverter()->transcode(srcP, retP, charsNeeded) || (XMLString::stringLen(retP) != charsNeeded))
{
manager->deallocate(retP);//delete [] retP;
charsNeeded = getDomConverter()->calcRequiredSize(srcP);
retP = (char*) manager->allocate((charsNeeded + 1) * sizeof(char));//new char[charsNeeded + 1];
if (!getDomConverter()->transcode(srcP, retP, charsNeeded))
{
// <TBD> We should throw something here?
}
}
// Cap it off and return it
retP[charsNeeded] = 0;
return retP;
}
DOMString DOMString::transcode(const char* str)
{
return DOMString(str);
}
bool DOMString::operator < (const DOMString &other) const
{
return (compareString(other) < 0);
}
int DOMString::compareString(const DOMString &other) const
{
// Note: this strcmp does not match the semantics
// of the standard C strcmp. All it needs to do is
// define some less than - equals - greater than ordering
// of strings. How doesn't matter.
//
unsigned int thisLen = length();
unsigned int otherLen = other.length();
if (thisLen < otherLen)
return -1;
if (thisLen > otherLen)
return 1;
if (thisLen == 0)
return 0;
XMLCh *thisP = this->fHandle->fDSData->fData;
XMLCh *otherP = other.fHandle->fDSData->fData;
unsigned int i;
for (i=0; i<thisLen; i++)
{
if (thisP[i] < otherP[i])
return -1;
else if (thisP[i] > otherP[i])
return 1;
}
return 0;
}
DOMString DOMString::substringData(unsigned int offset, unsigned int count) const
{
unsigned int thisLen = length();
if (offset > thisLen)
throw DOM_DOMException(DOM_DOMException::INDEX_SIZE_ERR, 0);
// Cap count to the string length to eliminate overflow
// problems when we get passed bogus values, like -1.
if (count > thisLen)
count = thisLen;
// If the count extends past the end of the string, cut it
// back so that the returned string will stop at the end
// of the source string.
if (offset + count >= thisLen)
count = thisLen - offset;
if (count == 0)
return DOMString();
// If the substring starts at the beginning of the original string
// we do not need to copy the data, but can set up a new
// string handle with the shorter length.
if (offset == 0)
{
DOMString retString = this->clone();
retString.fHandle->fLength = count;
return retString;
}
// The substring starts somewhere in the interior of the orignal string.
// Create a completely new DOMString. No buffer sharing is possible.
XMLCh *data = fHandle->fDSData->fData;
return DOMString(data+offset, count);
}
DOMString operator + (const DOMString &lhs, const DOMString &rhs)
{
DOMString retString = lhs.clone();
retString.appendData(rhs);
return retString;
}
DOMString operator + (const DOMString &lhs, const XMLCh* rhs)
{
DOMString retString = lhs.clone();
retString.appendData(rhs);
return retString;
}
DOMString operator + (const XMLCh* lhs, const DOMString& rhs)
{
DOMString retString = DOMString(lhs);
retString.appendData(rhs);
return retString;
}
DOMString operator + (const DOMString &lhs, XMLCh rhs)
{
DOMString retString = lhs.clone();
retString.appendData(rhs);
return retString;
}
DOMString operator + (XMLCh lhs, const DOMString& rhs)
{
DOMString retString;
retString.appendData(lhs);
retString.appendData(rhs);
return retString;
}
// -----------------------------------------------------------------------
// Notification that lazy data has been deleted
// -----------------------------------------------------------------------
static void reinitDomConverter()
{
delete gDomConverter; // Delete the local code page converter.
gDomConverter = 0;
}
static void reinitDomMutex()
{
delete DOMStringHandleMutex; // Delete the synchronization mutex,
DOMStringHandleMutex = 0;
}
XERCES_CPP_NAMESPACE_END