DOMString.cpp
上传用户:zhuqijet
上传日期:2013-06-25
资源大小:10074k
文件大小:36k
- /*
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 1999-2002 The Apache Software Foundation. All rights
- * reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The end-user documentation included with the redistribution,
- * if any, must include the following acknowledgment:
- * "This product includes software developed by the
- * Apache Software Foundation (http://www.apache.org/)."
- * Alternately, this acknowledgment may appear in the software itself,
- * if and wherever such third-party acknowledgments normally appear.
- *
- * 4. The names "Xerces" and "Apache Software Foundation" must
- * not be used to endorse or promote products derived from this
- * software without prior written permission. For written
- * permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache",
- * nor may "Apache" appear in their name, without prior written
- * permission of the Apache Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation, and was
- * originally based on software copyright (c) 1999, International
- * Business Machines, Inc., http://www.ibm.com . For more information
- * on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- */
- /*
- * $Id: DOMString.cpp,v 1.7 2003/05/22 02:26:50 knoaman Exp $
- */
- #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;
- 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;
- 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;
- try {
- buf = (DOMStringData *) XMLPlatformUtils::fgMemoryManager->allocate
- (
- sizeToAllocate * sizeof(char)
- );//new char[sizeToAllocate];
- }
- catch (...) {
- ThrowXML(RuntimeException, XMLExcepts::Out_Of_Memory);
- }
- if (!buf)
- ThrowXML(RuntimeException, XMLExcepts::Out_Of_Memory);
- 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
- //
- //------------------------------------------------------------
- int DOMString::gLiveStringDataCount = 0;
- int DOMString::gTotalStringDataCount = 0;
- int DOMString::gLiveStringHandleCount = 0;
- int DOMString::gTotalStringHandleCount = 0;
- DOMString::DOMString()
- {
- fHandle = 0;
- };
- DOMString::DOMString(const DOMString &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);
- 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(1);
- 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);
- 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 || offset < 0 || delLength < 0)
- 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);
- 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);
- 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;
- }
- 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
- // DOMStrings are not always null terminated, so we may need to
- // copy to another buffer first in order to null terminate it for
- // use as input to the transcoding routines..
- //
- XMLCh* DOMStrData = fHandle->fDSData->fData;
- const unsigned int localBufLen = 1000;
- XMLCh localBuf[localBufLen];
- XMLCh *allocatedBuf = 0;
- XMLCh *srcP;
- if (DOMStrData[fHandle->fLength] == 0)
- {
- // The data in the DOMString itself happens to be null terminated.
- // Just use it in place.
- srcP = DOMStrData;
- }
- else if (fHandle->fLength < localBufLen-1)
- {
- // The data is not null terminated, but does fit in the
- // local buffer (fast allocation). Copy it over, and add
- // the null termination,
- memcpy(localBuf, DOMStrData, fHandle->fLength * sizeof(XMLCh));
- srcP = localBuf;
- srcP[fHandle->fLength] = 0;
- }
- else
- {
- // The data is too big for the local buffer. Heap allocate one.
- allocatedBuf = srcP = new XMLCh[fHandle->fLength + 1];
- memcpy(allocatedBuf, DOMStrData, fHandle->fLength * sizeof(XMLCh));
- srcP[fHandle->fLength] = 0;
- }
- //
- // 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?
- }
- }
- delete [] allocatedBuf; // which will be null if we didn't allocate one.
- // 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
- // DOMStrings are not always null terminated, so we may need to
- // copy to another buffer first in order to null terminate it for
- // use as input to the transcoding routines..
- //
- XMLCh* DOMStrData = fHandle->fDSData->fData;
- const unsigned int localBufLen = 1000;
- XMLCh localBuf[localBufLen];
- XMLCh *allocatedBuf = 0;
- XMLCh *srcP;
- if (DOMStrData[fHandle->fLength] == 0)
- {
- // The data in the DOMString itself happens to be null terminated.
- // Just use it in place.
- srcP = DOMStrData;
- }
- else if (fHandle->fLength < localBufLen-1)
- {
- // The data is not null terminated, but does fit in the
- // local buffer (fast allocation). Copy it over, and add
- // the null termination,
- memcpy(localBuf, DOMStrData, fHandle->fLength * sizeof(XMLCh));
- srcP = localBuf;
- srcP[fHandle->fLength] = 0;
- }
- else
- {
- // The data is too big for the local buffer. Heap allocate one.
- allocatedBuf = srcP = (XMLCh*) manager->allocate
- (
- (fHandle->fLength + 1) * sizeof(XMLCh)
- );//new XMLCh[fHandle->fLength + 1];
- memcpy(allocatedBuf, DOMStrData, fHandle->fLength * sizeof(XMLCh));
- srcP[fHandle->fLength] = 0;
- }
- //
- // 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?
- }
- }
- if (allocatedBuf)
- manager->deallocate(allocatedBuf);//delete [] allocatedBuf; // which will be null if we didn't allocate one.
- // Cap it off and return it
- retP[charsNeeded] = 0;
- return retP;
- }
- DOMString DOMString::transcode(const char* str)
- {
- return DOMString(str);
- }
- 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 || offset < 0 || count < 0)
- 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