| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * Copyright (c) 1999 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/>. |
| */ |
| |
| /** |
| * $Log$ |
| * Revision 1.3 1999/12/03 00:11:22 andyh |
| * Added DOMString.clone() to node parameters in and out of the DOM, |
| * where they had been missed. |
| * |
| * DOMString::rawBuffer, removed incorrect assumptions about it |
| * being null terminated. |
| * |
| * Revision 1.2 1999/11/30 21:16:25 roddey |
| * Changes to add the transcode() method to DOMString, which returns a transcoded |
| * version (to local code page) of the DOM string contents. And I changed all of the |
| * exception 'throw by pointer' to 'throw by value' style. |
| * |
| * Revision 1.1.1.1 1999/11/09 01:08:47 twl |
| * Initial checkin |
| * |
| * Revision 1.3 1999/11/08 20:44:12 rahul |
| * Swat for adding in Product name and CVS comment log variable. |
| * |
| */ |
| |
| |
| #include <util/PlatformUtils.hpp> |
| #include <util/RuntimeException.hpp> |
| #include <util/StdOut.hpp> |
| #include <util/TransService.hpp> |
| #include "DOMString.hpp" |
| |
| #include <assert.h> |
| #include <string.h> |
| |
| |
| |
| |
| //---------------------------------------------- |
| // |
| // DOMStringData |
| // |
| //---------------------------------------------- |
| class DOMStringData |
| { |
| public: |
| int fBufferLength; |
| int fRefCount; |
| XMLCh fData[1]; |
| |
| static DOMStringData *allocateBuffer(int length); |
| inline void addRef(); |
| inline void removeRef(); |
| }; |
| |
| void DOMStringData::removeRef() |
| { |
| int result = XMLPlatformUtils::atomicDecrement(fRefCount); |
| if (result==0) |
| { |
| fBufferLength = 0xcccc; |
| fRefCount = 0xcccc; |
| delete this; |
| XMLPlatformUtils::atomicDecrement(DOMString::gLiveStringDataCount); |
| }; |
| }; |
| |
| |
| void DOMStringData::addRef() |
| { |
| XMLPlatformUtils::atomicIncrement(fRefCount); |
| }; |
| |
| |
| DOMStringData *DOMStringData::allocateBuffer(int length) |
| { |
| int sizeToAllocate = sizeof(DOMStringData) // buffer will contain an |
| + length*sizeof(XMLCh); // extra elem because of stub |
| // array in DOMStringData struct. |
| DOMStringData *buf = (DOMStringData *) new char[sizeToAllocate]; |
| XMLPlatformUtils::atomicIncrement(DOMString::gLiveStringDataCount); |
| XMLPlatformUtils::atomicIncrement(DOMString::gTotalStringDataCount); |
| buf->fBufferLength = length; |
| buf->fRefCount = 1; |
| buf->fData[0] = 0; |
| return buf; |
| } |
| |
| |
| |
| |
| //---------------------------------------------------- |
| // |
| // DOMStringHandle |
| // |
| //----------------------------------------------------- |
| |
| class DOMStringHandle |
| { |
| public: |
| int fLength; |
| int fRefCount; |
| DOMStringData *fDSData; |
| |
| void *operator new( size_t sizeToAlloc); |
| void operator delete( void *pvMem ); |
| private: |
| static void *freeListPtr; |
| public: |
| static DOMStringHandle *createNewStringHandle(int bufLength); |
| DOMStringHandle *cloneStringHandle(); |
| inline void addRef(); |
| inline void removeRef(); |
| ~DOMStringHandle() {}; |
| private: |
| inline 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. |
| |
| |
| void *DOMStringHandle::operator new(size_t sizeToAlloc) |
| { |
| assert(sizeToAlloc == sizeof(DOMStringHandle)); |
| void *retPtr; |
| void *oldFreeListPtr; |
| |
| do |
| { |
| retPtr = freeListPtr; // In the common case, freeListPtr points |
| // to an available string handle, and |
| // this will be the block we return. |
| |
| if (retPtr == 0) |
| { |
| // Uncommon case. The free list of string handles is empty |
| // and we must allocate a new batch of them, using |
| // the system's operator new. |
| // |
| // Link all but one of these new StringHandles into our free list by |
| // deleting them with DOMStringHandle::operator delete. |
| // Unconditionally return the one that we didn't put in the free list. |
| // |
| // There is a remote chance that two threads could see the free list |
| // as empty at about the same time and both fall into this code. |
| // No great harm will result - the free list will have twice the |
| // usual number of new free handles added to it. It's not worth |
| // any added code complexity to prevent it from happening. |
| DOMStringHandle *dsg = |
| ::new DOMStringHandle[allocGroupSize]; |
| int i; |
| for (i=1; i<allocGroupSize-1; i++) |
| delete &dsg[i]; |
| |
| return &dsg[0]; |
| } |
| |
| // Thread-safe (atomic) update of freeListPtr. |
| oldFreeListPtr = XMLPlatformUtils::compareAndSwap(&freeListPtr, *(void **)retPtr, retPtr); |
| } |
| // This loop will normally exit the first time through. It will only repeat if, |
| // in a multi-threaded environment, some second thread updated the free list ptr |
| // in the interval between when we looked at it (retPtr = freeListPtr;) and when |
| // we attempted to update it ourselves with the compareAndSwap(). |
| while (oldFreeListPtr != retPtr); |
| |
| return retPtr; |
| }; |
| |
| |
| |
| void DOMStringHandle::operator delete(void *pMem) |
| { |
| void *initialFreeListPtr; |
| void *oldFreeListPtr; |
| do |
| { |
| *(void **)pMem = initialFreeListPtr = freeListPtr; |
| oldFreeListPtr = XMLPlatformUtils::compareAndSwap(&freeListPtr, pMem, initialFreeListPtr); |
| } |
| while (oldFreeListPtr != initialFreeListPtr); |
| }; |
| |
| |
| void DOMStringHandle::addRef() |
| { |
| XMLPlatformUtils::atomicIncrement(fRefCount); |
| }; |
| |
| |
| void DOMStringHandle::removeRef() |
| { |
| int result = XMLPlatformUtils::atomicDecrement(fRefCount); |
| if (result==0) |
| { |
| fDSData->removeRef(); |
| delete this; |
| XMLPlatformUtils::atomicDecrement(DOMString::gLiveStringHandleCount); |
| }; |
| }; |
| |
| |
| DOMStringHandle *DOMStringHandle::createNewStringHandle(int bufLength) |
| { |
| DOMStringHandle *h = new DOMStringHandle; |
| XMLPlatformUtils::atomicIncrement(DOMString::gLiveStringHandleCount); |
| XMLPlatformUtils::atomicIncrement(DOMString::gTotalStringHandleCount); |
| h -> fLength = 0; |
| h -> fRefCount = 1; |
| h -> fDSData = DOMStringData::allocateBuffer(bufLength); |
| return h; |
| }; |
| |
| |
| DOMStringHandle *DOMStringHandle::cloneStringHandle() |
| { |
| DOMStringHandle *h = new DOMStringHandle; |
| XMLPlatformUtils::atomicIncrement(DOMString::gLiveStringHandleCount); |
| 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) |
| { |
| int dataLength = 0; |
| while (data[dataLength] != 0) |
| ++dataLength; |
| |
| if (dataLength != 0) |
| { |
| fHandle = DOMStringHandle::createNewStringHandle(dataLength+1); |
| fHandle->fLength = dataLength; |
| XMLCh *strData = fHandle->fDSData->fData; |
| int i; |
| for (i=0; i<dataLength ; ++i) |
| strData[i] = data[i]; |
| |
| strData[dataLength] = 0; |
| } |
| } |
| } |
| |
| |
| |
| DOMString::DOMString(const XMLCh *data, int dataLength) |
| { |
| fHandle = 0; |
| if (data != 0) |
| { |
| if (dataLength > 0) |
| { |
| fHandle = DOMStringHandle::createNewStringHandle(dataLength+1); |
| fHandle->fLength = dataLength; |
| XMLCh *strData = fHandle->fDSData->fData; |
| int i; |
| for (i=0; i<dataLength ; ++i) |
| strData[i] = data[i]; |
| |
| strData[dataLength] = 0; |
| } |
| } |
| } |
| |
| |
| |
| |
| // getDOMConverter - get the converter from the system default |
| // codepage to Unicode that is to be used when |
| // a DOMString is constructed from a char *. |
| // |
| XMLTranscoder* getDomConverter() |
| { |
| static XMLTranscoder* gDomConverter = 0; |
| if (!gDomConverter) |
| { |
| XMLTranscoder* transcoder = |
| XMLPlatformUtils::fgTransService->makeNewDefTranscoder(); |
| if (!transcoder) |
| XMLPlatformUtils::panic(XMLPlatformUtils::Panic_NoDefTranscoder |
| ); |
| |
| if (XMLPlatformUtils::compareAndSwap((void **)&gDomConverter, |
| transcoder, 0) != 0) |
| delete gDomConverter; |
| } |
| return gDomConverter; |
| }; |
| |
| |
| |
| // |
| // 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) |
| { |
| XMLTranscoder* uniConverter = getDomConverter(); |
| unsigned int len = 0; |
| |
| unsigned int srcLen = strlen(srcString); |
| if (srcLen == 0) |
| return; |
| |
| const unsigned int charsNeeded = |
| uniConverter->calcRequiredSize(srcString); |
| |
| fHandle = DOMStringHandle::createNewStringHandle(charsNeeded + 1); |
| fHandle->fLength = charsNeeded; |
| XMLCh *strData = fHandle->fDSData->fData; |
| if (!uniConverter->transcode(srcString, strData, charsNeeded)) |
| { |
| // <TBD> We should throw something here? |
| } |
| } |
| }; |
| |
| |
| |
| |
| |
| |
| DOMString::DOMString(int initialBufferSize) |
| { |
| fHandle = 0; |
| if (initialBufferSize > 0) |
| fHandle = DOMStringHandle::createNewStringHandle(initialBufferSize); |
| }; |
| |
| |
| 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 + (const DOMString &other) |
| { |
| DOMString retString = this->clone(); |
| retString.appendData(other); |
| return retString; |
| }; |
| |
| |
| 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::appendData(const DOMString &other) |
| { |
| int i; |
| if (other.fHandle == 0 || other.fHandle->fLength == 0) |
| return; |
| |
| if (fHandle == 0 || fHandle->fLength == 0) |
| { |
| if (fHandle) fHandle->removeRef(); |
| this->fHandle = other.fHandle->cloneStringHandle(); |
| return; |
| } |
| |
| 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; |
| for (i=0; i<fHandle->fLength; ++i) |
| newP[i] = oldP[i]; |
| |
| fHandle->fDSData->removeRef(); |
| fHandle->fDSData = newBuf; |
| } |
| |
| XMLCh *srcP = other.fHandle->fDSData->fData; |
| XMLCh *destP = &fHandle->fDSData->fData[fHandle->fLength]; |
| for (i=0; i<=other.fHandle->fLength; i++) |
| destP[i] = srcP[i]; |
| |
| fHandle->fLength += other.fHandle->fLength; |
| } |
| |
| |
| XMLCh DOMString::charAt(int index) const |
| { |
| XMLCh retCh = 0; |
| if (fHandle != 0 && index >= 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(int offset, int delLength) |
| { |
| assert(delLength >= 0); |
| int stringLen = this->length(); |
| assert(offset < stringLen); |
| |
| if (delLength == 0) |
| return; |
| |
| |
| if (offset + delLength >= stringLen) |
| delLength = stringLen - offset; |
| |
| 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; |
| 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. |
| 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; |
| 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; |
| int len = this->fHandle->fLength; |
| |
| 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(int offset, const DOMString &src) |
| { |
| assert(offset>=0); |
| int origStrLength = this->length(); |
| assert(offset<=origStrLength); |
| |
| if (fHandle == 0) |
| { |
| *this = src.clone(); |
| return; |
| } |
| |
| if (src.fHandle == 0 ||src.fHandle->fLength == 0) |
| return; |
| |
| XMLCh *srcP = src.fHandle->fDSData->fData; |
| int srcLength = src.fHandle->fLength; |
| int newLength = fHandle->fLength + srcLength; |
| if (newLength >= fHandle->fDSData->fBufferLength || |
| fHandle->fDSData->fRefCount > 1) |
| { |
| // 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; |
| 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=origStrLength-1; i>=offset; i--) |
| destP[i+srcLength] = destP[i]; |
| |
| for (i=0; i<srcLength; i++) |
| destP[i+offset] = srcP[i]; |
| }; |
| |
| fHandle->fLength += srcLength; |
| } |
| |
| |
| |
| int DOMString::length() const |
| { |
| int len = 0; |
| if (fHandle != 0) |
| len = fHandle->fLength; |
| |
| return len; |
| }; |
| |
| |
| |
| void DOMString::print() const |
| { |
| int len = this->length(); |
| |
| if (len > 0) |
| { |
| |
| XMLCh *p = fHandle->fDSData->fData; |
| |
| XMLStdOut out; |
| XMLCh* buffer = new XMLCh[len+1]; |
| int i; |
| for (i=0; i<len; i++) |
| buffer[i] = p[i]; |
| buffer[len] = 0; |
| out << buffer; |
| delete [] buffer; |
| }; |
| }; |
| |
| |
| void DOMString::println() const |
| { |
| XMLStdOut out; |
| print(); |
| out << EndLn; |
| }; |
| |
| |
| |
| 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 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. |
| // |
| const unsigned int charsNeeded = getDomConverter()->calcRequiredSize(srcP); |
| char* 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; |
| } |
| |
| |
| 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. |
| // |
| int thisLen = length(); |
| 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; |
| 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(int offset, int count) const |
| { |
| DOMString retString; |
| |
| if (count > 0) |
| { |
| int thisLen = length(); |
| assert(offset>=0 && count>=0); |
| if (offset+count > thisLen) |
| { |
| assert (offset < thisLen); |
| count = thisLen - offset; |
| } |
| XMLCh *data = fHandle->fDSData->fData; |
| retString = DOMString(data+offset, count); |
| } |
| return retString; |
| }; |
| |