DOMString.cpp
上传用户:huihehuasu
上传日期:2007-01-10
资源大小:6948k
文件大小:34k
源码类别:

xml/soap/webservice

开发平台:

C/C++

  1. /*
  2.  * The Apache Software License, Version 1.1
  3.  *
  4.  * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights
  5.  * reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  *
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  *
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in
  16.  *    the documentation and/or other materials provided with the
  17.  *    distribution.
  18.  *
  19.  * 3. The end-user documentation included with the redistribution,
  20.  *    if any, must include the following acknowledgment:
  21.  *       "This product includes software developed by the
  22.  *        Apache Software Foundation (http://www.apache.org/)."
  23.  *    Alternately, this acknowledgment may appear in the software itself,
  24.  *    if and wherever such third-party acknowledgments normally appear.
  25.  *
  26.  * 4. The names "Xerces" and "Apache Software Foundation" must
  27.  *    not be used to endorse or promote products derived from this
  28.  *    software without prior written permission. For written
  29.  *    permission, please contact apache@apache.org.
  30.  *
  31.  * 5. Products derived from this software may not be called "Apache",
  32.  *    nor may "Apache" appear in their name, without prior written
  33.  *    permission of the Apache Software Foundation.
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38.  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42.  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44.  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45.  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46.  * SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Software Foundation, and was
  51.  * originally based on software copyright (c) 1999, International
  52.  * Business Machines, Inc., http://www.ibm.com .  For more information
  53.  * on the Apache Software Foundation, please see
  54.  * <http://www.apache.org/>.
  55.  */
  56. /*
  57.  * $Log: DOMString.cpp,v $
  58.  * Revision 1.23  2001/10/22 17:53:05  tng
  59.  * [Bug 3660] Off-by-one error in DOMString.cpp.  And check that memory has been acquired successfully after memory acquistion requests in DOMString.
  60.  *
  61.  * Revision 1.22  2001/10/18 18:01:29  tng
  62.  * [Bug 1699] Redirect "delete this" to a temp ptr to bypass AIX xlC v5 optimization memory leak problem.
  63.  *
  64.  * Revision 1.21  2001/06/26 19:28:25  tng
  65.  * [Bug 2119] DOMString::print() should use DOMString::transcode() for transcoding.
  66.  *
  67.  * Revision 1.20  2001/05/11 13:25:19  tng
  68.  * Copyright update.
  69.  *
  70.  * Revision 1.19  2001/01/25 19:22:50  tng
  71.  * Some bug fixes + Cleanup.  Fixed by Khaled Noaman.
  72.  *
  73.  * Revision 1.18  2000/08/03 20:39:53  jberry
  74.  * Add prototype for getDomConverter(), eliminating compiler warning
  75.  *
  76.  * Revision 1.17  2000/06/02 00:45:42  andyh
  77.  * DOM Fixes:  DOMString::rawBuffer() now returns a const XMLCh * pointer.
  78.  * Two plain deletes changed to array deletes.
  79.  *
  80.  * Revision 1.16  2000/05/09 00:22:29  andyh
  81.  * Memory Cleanup.  XMLPlatformUtils::Terminate() deletes all lazily
  82.  * allocated memory; memory leak checking tools will no longer report
  83.  * that leaks exist.  (DOM GetElementsByTagID temporarily removed
  84.  * as part of this.)
  85.  *
  86.  * Revision 1.15  2000/03/28 19:43:13  roddey
  87.  * Fixes for signed/unsigned warnings. New work for two way transcoding
  88.  * stuff.
  89.  *
  90.  * Revision 1.14  2000/03/02 19:53:52  roddey
  91.  * This checkin includes many changes done while waiting for the
  92.  * 1.1.0 code to be finished. I can't list them all here, but a list is
  93.  * available elsewhere.
  94.  *
  95.  * Revision 1.13  2000/02/06 07:47:27  rahulj
  96.  * Year 2K copyright swat.
  97.  *
  98.  * Revision 1.12  2000/02/05 01:19:19  andyh
  99.  * Add more DOMString tests.  Fix limit test error in DOMString::insertData()
  100.  * Andy Heninger  heninger@us.ibm.com
  101.  *
  102.  * Revision 1.11  2000/02/04 05:06:29  andyh
  103.  * Change all DOMString offsets and lengths form signed to unsigned
  104.  * Other misc. cleanups.
  105.  *
  106.  * Revision 1.10  2000/02/04 00:52:57  rahulj
  107.  * Changed size_t to int.
  108.  *
  109.  * Revision 1.9  2000/02/03 23:07:27  andyh
  110.  * Add several new functions from Robert Weir to DOMString.
  111.  *
  112.  * Revision 1.8  2000/01/29 00:39:08  andyh
  113.  * Redo synchronization in DOMStringHandle allocator.  There
  114.  * was a bug in the use of Compare and Swap.  Switched to mutexes.
  115.  *
  116.  * Changed a few plain deletes to delete [].
  117.  *
  118.  * Revision 1.7  2000/01/18 19:55:37  andyh
  119.  * Remove dependencies on XMLStdout and err, as these are about
  120.  * to stop working.
  121.  *
  122.  * Revision 1.6  2000/01/05 22:16:26  robweir
  123.  * Move DOMString implementation class declarations into a new
  124.  * file: DOMStringImpl.hpp.  Include this header in DOMString.hpp
  125.  * for XML_DEBUG builds so the underlying character array will be
  126.  * visible in the debugger.  <robert_weir@lotus.com>
  127.  *
  128.  * Revision 1.5  1999/12/17 02:09:41  andyh
  129.  * Fix bug in DOMString::insertData() that occured if the source
  130.  * and destination strings were the same and the orginal buffer had
  131.  * enough space to hold the result.
  132.  *
  133.  * Revision 1.4  1999/12/15 19:44:46  roddey
  134.  * Changed to use new LCP transcoder scheme.
  135.  *
  136.  * Revision 1.3  1999/12/03 00:11:22  andyh
  137.  * Added DOMString.clone() to node parameters in and out of the DOM,
  138.  * where they had been missed.
  139.  *
  140.  * DOMString::rawBuffer, removed incorrect assumptions about it
  141.  * being null terminated.
  142.  *
  143.  * Revision 1.2  1999/11/30 21:16:25  roddey
  144.  * Changes to add the transcode() method to DOMString, which returns a transcoded
  145.  * version (to local code page) of the DOM string contents. And I changed all of the
  146.  * exception 'throw by pointer' to 'throw by value' style.
  147.  *
  148.  * Revision 1.1.1.1  1999/11/09 01:08:47  twl
  149.  * Initial checkin
  150.  *
  151.  * Revision 1.3  1999/11/08 20:44:12  rahul
  152.  * Swat for adding in Product name and CVS comment log variable.
  153.  *
  154.  */
  155. #include <stdio.h>
  156. #include <util/PlatformUtils.hpp>
  157. #include <util/RuntimeException.hpp>
  158. #include <util/TransService.hpp>
  159. #include <util/XMLString.hpp>
  160. #include "DOM_DOMException.hpp"
  161. #include "DOMString.hpp"
  162. #ifndef XML_DEBUG
  163. #include "DOMStringImpl.hpp"
  164. #endif
  165. #include <assert.h>
  166. #include <string.h>
  167. //----------------------------------------------
  168. //
  169. //  Forward decls
  170. //
  171. //----------------------------------------------
  172. static void DOMStringTerminate();
  173. XMLLCPTranscoder*  getDomConverter();
  174. //----------------------------------------------
  175. //
  176. //      DOMStringData
  177. //
  178. //----------------------------------------------
  179. void DOMStringData::removeRef()
  180. {
  181.     int result = XMLPlatformUtils::atomicDecrement(fRefCount);
  182.     if (result==0)
  183.     {
  184.         fBufferLength = 0xcccc;
  185.         fRefCount     = 0xcccc;
  186.         delete [] this;  //  was allocated with new char[size] !
  187.         XMLPlatformUtils::atomicDecrement(DOMString::gLiveStringDataCount);
  188.     };
  189. };
  190. void DOMStringData::addRef()
  191. {
  192.     XMLPlatformUtils::atomicIncrement(fRefCount);
  193. };
  194. DOMStringData *DOMStringData::allocateBuffer(unsigned int length)
  195. {
  196.     unsigned int sizeToAllocate = sizeof(DOMStringData) //  buffer will contain an
  197.         + length*sizeof(XMLCh);                //  extra elem because of stub
  198.                                                //  array in DOMStringData struct.
  199.     DOMStringData *buf = 0;
  200.     try {
  201.         buf = (DOMStringData *) new char[sizeToAllocate];
  202.     }
  203.     catch (...) {
  204.         ThrowXML(RuntimeException, XMLExcepts::Out_Of_Memory);
  205.     }
  206.     if (!buf)
  207.        ThrowXML(RuntimeException, XMLExcepts::Out_Of_Memory);
  208.     XMLPlatformUtils::atomicIncrement(DOMString::gLiveStringDataCount);
  209.     XMLPlatformUtils::atomicIncrement(DOMString::gTotalStringDataCount);
  210.     buf->fBufferLength = length;
  211.     buf->fRefCount = 1;
  212.     buf->fData[0] = 0;
  213.     return buf;
  214. }
  215. //----------------------------------------------------
  216. //
  217. //      DOMStringHandle
  218. //
  219. //-----------------------------------------------------
  220. //
  221. //  Specialized new and delete operators for DOMStringHandles.
  222. //      These are used, rather than the standard system operator new,
  223. //      for improved performance.
  224. //
  225. //      We allocate largish blocks of memory using the standard system
  226. //      new function, and sub-allocate string handles from that block.
  227. //      Un-allocated string handles within the allocated blocks are kept
  228. //      in a singly linked list, making allocation and deallocation
  229. //      very quick in the common case.
  230. //
  231. //      String handle allocation is thread safe.  A multi-threaded
  232. //      application may have threads concurrently accessing multiple
  233. //      DOM documents; since all string handles come from the same pool,
  234. //      this allocator must be safe.  The compare and exchange function,
  235. //      which is available as a single instruction in most processor
  236. //      architectures, and typically surfaced as an OS function,
  237. //      is used to safely update the string handle free list.
  238. //
  239. void *DOMStringHandle::freeListPtr = 0;   // Point to the head of the
  240.                                           //  free list of un-allocated
  241.                                           //  string handles, or 0 if there
  242.                                           //  are no free string handles.
  243. static const int allocGroupSize = 1024;   // Number of string handles to allocate
  244.                                           //  as a chunk from the system's
  245.                                           //  memory allocator.
  246. DOMStringHandle *DOMStringHandle::blockListPtr = 0;  // Point to the head of the list
  247.                                           //  of larger blocks in which DOMStringHandles
  248.                                           //  are allocated.
  249. //
  250. //  There is one global mutex that is used to synchronize access to the
  251. //     allocator free list for DOMStringHandles.  This function gets that
  252. //     mutex, and will create it on the first attempt to get it.
  253. //
  254. static XMLMutex* DOMStringHandleMutex = 0;   // Mutex will be deleted by ~DOMStringHandle.
  255. XMLMutex& DOMStringHandle::getMutex()
  256. {
  257.     if (!DOMStringHandleMutex)
  258.     {
  259.         XMLMutex* tmpMutex = new XMLMutex;
  260.         if (XMLPlatformUtils::compareAndSwap((void**)&DOMStringHandleMutex, tmpMutex, 0))
  261.         {
  262.             // Someone beat us to it, so let's clean up ours
  263.             delete tmpMutex;
  264.         }
  265.     }
  266.     return *DOMStringHandleMutex;
  267. }
  268. //
  269. //  Operator new for DOMStringHandles.  Called implicitly from the
  270. //          DOMStringHandle constructor.
  271. //
  272. void *DOMStringHandle::operator new(size_t sizeToAlloc)
  273. {
  274.     assert(sizeToAlloc == sizeof(DOMStringHandle));
  275.     void    *retPtr;
  276.     XMLMutexLock lock(&getMutex());    // Lock the DOMStringHandle mutex for
  277.                                        //  the duration of this function.
  278.     if (freeListPtr == 0)
  279.     {
  280.         // Uncommon case.  The free list of string handles is empty
  281.         // Allocate a new batch of them, using the system's
  282.         // operator new to get a chunk of memory.
  283.         //
  284.        DOMStringHandle *dsg =
  285.             ::new DOMStringHandle[allocGroupSize];
  286.         // Link the block itself into the list of blocks.  The purpose of this is to
  287.         //   let us locate and delete the blocks when shutting down.
  288.         //
  289.         *(DOMStringHandle **)dsg = blockListPtr;
  290.         blockListPtr = dsg;
  291.         // Link all of the new storage for StringHandles into the StringHandle free list
  292.         int   i;    //   Start with index 1;  index 0 is reserved for linking the
  293.                     //   larger allocation blocks together.
  294.         for (i=1; i<allocGroupSize-1; i++) {
  295.             *(void **)&dsg[i] = freeListPtr;
  296.             freeListPtr = &dsg[i];
  297.         }
  298.     }
  299.     retPtr = freeListPtr;
  300.     freeListPtr = *(void **)freeListPtr;
  301.     return retPtr;
  302. };
  303. //
  304. //  Operator delete for DOMStringHandles.  Called implicitly from the
  305. //              Destructor for DOMStringHandle.
  306. //
  307. void DOMStringHandle::operator delete(void *pMem)
  308. {
  309.     {
  310.         XMLMutexLock   lock(&getMutex());    // Lock the DOMStringHandle mutex for the
  311.         //    duration of this function.
  312.         *(void **)pMem = freeListPtr;
  313.         freeListPtr = pMem;
  314.     }
  315.     // If ALL of the string handles are gone, delete the storage blocks used for the
  316.     //   handles as well.  This will generally only happen on PlatFormUtils::Terminate(),
  317.     //   since any use of the DOM will cache some commonly used DOMStrings
  318.     //   forever (until Terminate).
  319.     if (DOMString::gLiveStringHandleCount == 0)
  320.     {
  321.         DOMStringHandle *pThisBlock, *pNextBlock;
  322.         for (pThisBlock = blockListPtr; pThisBlock != 0; pThisBlock = pNextBlock)
  323.         {
  324.             pNextBlock = *(DOMStringHandle **)pThisBlock;
  325.             delete [] pThisBlock;
  326.         }
  327.         blockListPtr = 0;
  328.         freeListPtr  = 0;
  329.         DOMStringTerminate();            //  Clean up everything else related to DOMString.
  330.     }
  331. };
  332. void DOMStringHandle::addRef()
  333. {
  334.     XMLPlatformUtils::atomicIncrement(fRefCount);
  335. };
  336. void DOMStringHandle::removeRef()
  337. {
  338.     int result = XMLPlatformUtils::atomicDecrement(fRefCount);
  339.     if (result==0)
  340.     {
  341.         fDSData->removeRef();
  342.         XMLPlatformUtils::atomicDecrement(DOMString::gLiveStringHandleCount);
  343. //        delete this;
  344.         DOMStringHandle* ptr = this;
  345.         delete ptr;
  346.     };
  347. };
  348. DOMStringHandle *DOMStringHandle::createNewStringHandle(unsigned int bufLength)
  349. {
  350.     DOMStringHandle  *h = new DOMStringHandle;
  351.     XMLPlatformUtils::atomicIncrement(DOMString::gLiveStringHandleCount);
  352.     XMLPlatformUtils::atomicIncrement(DOMString::gTotalStringHandleCount);
  353.     h -> fLength = 0;
  354.     h -> fRefCount = 1;
  355.     h -> fDSData = DOMStringData::allocateBuffer(bufLength);
  356.     return h;
  357. };
  358. DOMStringHandle *DOMStringHandle::cloneStringHandle()
  359. {
  360.     DOMStringHandle *h = new DOMStringHandle;
  361.     XMLPlatformUtils::atomicIncrement(DOMString::gLiveStringHandleCount);
  362.     h->fLength   = fLength;
  363.     h->fRefCount = 1;
  364.     h->fDSData   = fDSData;
  365.     h->fDSData->addRef();
  366.     return h;
  367. }
  368. //------------------------------------------------------------
  369. //
  370. //      DOMString
  371. //
  372. //------------------------------------------------------------
  373. int DOMString::gLiveStringDataCount    = 0;
  374. int DOMString::gTotalStringDataCount   = 0;
  375. int DOMString::gLiveStringHandleCount  = 0;
  376. int DOMString::gTotalStringHandleCount = 0;
  377. DOMString::DOMString()
  378. {
  379.     fHandle = 0;
  380. };
  381. DOMString::DOMString(const DOMString &other)
  382. {
  383.     fHandle = other.fHandle;
  384.     if (fHandle)
  385.         fHandle->addRef();
  386. };
  387. DOMString::DOMString(const XMLCh *data)
  388. {
  389.     fHandle = 0;
  390.     if (data != 0)
  391.     {
  392.         unsigned int dataLength = 0;
  393.         while (data[dataLength] != 0)
  394.             ++dataLength;
  395.         if (dataLength != 0)
  396.         {
  397.             fHandle = DOMStringHandle::createNewStringHandle(dataLength+1);
  398.             fHandle->fLength = dataLength;
  399.             XMLCh *strData = fHandle->fDSData->fData;
  400.             unsigned int i;
  401.             for (i=0; i<dataLength ; ++i)
  402.                 strData[i] = data[i];
  403.             strData[dataLength] = 0;
  404.         }
  405.     }
  406. }
  407. DOMString::DOMString(const XMLCh *data, unsigned int dataLength)
  408. {
  409.     fHandle = 0;
  410.     if (data != 0)
  411.     {
  412.         if (dataLength > 0)
  413.         {
  414.             fHandle = DOMStringHandle::createNewStringHandle(dataLength+1);
  415.             fHandle->fLength = dataLength;
  416.             XMLCh *strData = fHandle->fDSData->fData;
  417.             unsigned int i;
  418.             for (i=0; i<dataLength ; ++i)
  419.                 strData[i] = data[i];
  420.             strData[dataLength] = 0;
  421.         }
  422.     }
  423. }
  424. //  getDOMConverter - get the converter from the system default
  425. //          codepage to Unicode that is to be used when
  426. //          a DOMString is constructed from a char *.
  427. //
  428. static XMLLCPTranscoder* gDomConverter = 0;
  429. XMLLCPTranscoder*  getDomConverter()
  430. {
  431.     if (!gDomConverter)
  432.     {
  433.         XMLLCPTranscoder* transcoder =
  434.         XMLPlatformUtils::fgTransService->makeNewLCPTranscoder();
  435.         if (!transcoder)
  436.             XMLPlatformUtils::panic(XMLPlatformUtils::Panic_NoDefTranscoder
  437.             );
  438.         if (XMLPlatformUtils::compareAndSwap((void **)&gDomConverter,
  439.         transcoder, 0) != 0)
  440.             delete transcoder;
  441.     }
  442.     return gDomConverter;
  443. };
  444. //
  445. //  Create a DOMString from a char * string in the default code page
  446. //                     of the system on which we are executing.
  447. //
  448. //
  449. DOMString::DOMString(const char *srcString)
  450. {
  451.     fHandle = 0;
  452.     if (srcString != 0)
  453.     {
  454.         XMLLCPTranscoder*  uniConverter = getDomConverter();
  455.         unsigned int srcLen = strlen(srcString);
  456.         if (srcLen == 0)
  457.             return;
  458.         const unsigned int charsNeeded =
  459.             uniConverter->calcRequiredSize(srcString);
  460.         fHandle = DOMStringHandle::createNewStringHandle(charsNeeded + 1);
  461.         fHandle->fLength = charsNeeded;
  462.         XMLCh *strData = fHandle->fDSData->fData;
  463.         if (!uniConverter->transcode(srcString, strData, charsNeeded))
  464.         {
  465.             // <TBD> We should throw something here?
  466.         }
  467.     }
  468. };
  469. DOMString::DOMString(int nullValue)
  470. {
  471.    assert(nullValue == 0);
  472.    fHandle = 0;
  473. };
  474. DOMString::~DOMString()
  475. {
  476.     if (fHandle)
  477.         fHandle->removeRef();
  478.     fHandle = 0;
  479. };
  480. DOMString & DOMString::operator =(const DOMString &other)
  481. {
  482.     if (this == &other)
  483.         return *this;
  484.     if (fHandle)
  485.         fHandle->removeRef();
  486.     fHandle = other.fHandle;
  487.     if (fHandle)
  488.         fHandle->addRef();
  489.     return *this;
  490. };
  491. DOMString & DOMString::operator = (DOM_NullPtr *arg)
  492. {
  493.     assert(arg == 0);
  494.     if (fHandle)
  495.         fHandle->removeRef();
  496.     fHandle = 0;
  497.     return *this;
  498. };
  499. bool DOMString::operator ==(const DOMString &other) const
  500. {
  501.     return this->fHandle == other.fHandle;
  502. };
  503. bool DOMString::operator !=(const DOMString &other) const
  504. {
  505.     return this->fHandle != other.fHandle;
  506. };
  507. bool DOMString::operator == (const DOM_NullPtr *p) const
  508. {
  509.     return (fHandle == 0);
  510. };
  511. bool DOMString::operator != (const DOM_NullPtr *p) const
  512. {
  513.     return (fHandle != 0);
  514. };
  515. void DOMString::reserve(unsigned int size)
  516. {
  517. if (fHandle == 0)
  518. {
  519.     if (size > 0)
  520.         fHandle = DOMStringHandle::createNewStringHandle(size);
  521. }
  522. }
  523. void DOMString::appendData(const DOMString &other)
  524. {
  525.     if (other.fHandle == 0 || other.fHandle->fLength == 0)
  526.         return;
  527.     // If this string is empty and this string does not have an
  528.     //   already allocated buffer sufficient to hold the string being
  529.     //   appended, return a clone of the other string.
  530.     //
  531.     if (fHandle == 0 || (fHandle->fLength == 0 &&
  532.         fHandle->fDSData->fBufferLength < other.fHandle->fLength))
  533.     {
  534.         if (fHandle) fHandle->removeRef();
  535.         this->fHandle = other.fHandle->cloneStringHandle();
  536.         return;
  537.     }
  538.     unsigned int newLength = fHandle->fLength + other.fHandle->fLength;
  539.     if (newLength >= fHandle->fDSData->fBufferLength ||
  540.         fHandle->fDSData->fRefCount > 1)
  541.     {
  542.         // We can't stick the data to be added onto the end of the
  543.         //  existing string, either because there is not space in
  544.         //  the buffer, or because the buffer is being shared with
  545.         //  some other string.  So, make a new buffer.
  546.         DOMStringData *newBuf = DOMStringData::allocateBuffer(newLength);
  547.         XMLCh *newP = newBuf->fData;
  548.         XMLCh *oldP = fHandle->fDSData->fData;
  549.         unsigned int i;
  550.         for (i=0; i<fHandle->fLength; ++i)
  551.             newP[i] = oldP[i];
  552.         fHandle->fDSData->removeRef();
  553.         fHandle->fDSData = newBuf;
  554.     }
  555.     //
  556.     // This string now had enough buffer room to hold the data to
  557.     //  be appended.  Go ahead and copy it in.
  558.     XMLCh *srcP = other.fHandle->fDSData->fData;
  559.     XMLCh *destP = &fHandle->fDSData->fData[fHandle->fLength];
  560.     unsigned int i;
  561.     for (i=0; i<other.fHandle->fLength; i++)
  562.         destP[i] = srcP[i];
  563.     fHandle->fLength += other.fHandle->fLength;
  564. }
  565. void DOMString::appendData(XMLCh ch)
  566. {
  567. unsigned int newLength = 0;
  568. if (fHandle == 0)
  569. {
  570. fHandle = DOMStringHandle::createNewStringHandle(1);
  571. newLength = 1;
  572. }
  573. else
  574. newLength = fHandle->fLength + 1;
  575.     if (newLength >= fHandle->fDSData->fBufferLength ||
  576.         fHandle->fDSData->fRefCount > 1)
  577.     {
  578.         // We can't stick the data to be added onto the end of the
  579.         //  existing string, either because there is not space in
  580.         //  the buffer, or because the buffer is being shared with
  581.         //  some other string.  So, make a new buffer.
  582.         DOMStringData *newBuf = DOMStringData::allocateBuffer(newLength);
  583.         XMLCh *newP = newBuf->fData;
  584.         XMLCh *oldP = fHandle->fDSData->fData;
  585.         unsigned int i;
  586.         for (i=0; i<fHandle->fLength; ++i)
  587.             newP[i] = oldP[i];
  588.         fHandle->fDSData->removeRef();
  589.         fHandle->fDSData = newBuf;
  590.     }
  591.     XMLCh *destP = &fHandle->fDSData->fData[fHandle->fLength];
  592. destP[0] = ch;
  593.     fHandle->fLength ++;
  594. }
  595. // TODO: A custom version could be written more efficiently, avoiding
  596. // the creation of the temporary DOMString
  597. void DOMString::appendData(const XMLCh* other)
  598. {
  599. appendData(DOMString(other));
  600. }
  601. DOMString& DOMString::operator +=(const DOMString &other)
  602. {
  603. appendData(other);
  604. return *this;
  605. }
  606. DOMString& DOMString::operator +=(const XMLCh *str)
  607. {
  608. appendData(str);
  609. return *this;
  610. }
  611. DOMString& DOMString::operator +=(XMLCh ch)
  612. {
  613. appendData(ch);
  614. return *this;
  615. }
  616. XMLCh     DOMString::charAt(unsigned int index) const
  617. {
  618.     XMLCh retCh = 0;
  619.     if ((fHandle != 0) && (index < fHandle->fLength))
  620.         retCh = fHandle->fDSData->fData[index];
  621.     return retCh;
  622. };
  623. DOMString DOMString::clone() const
  624. {
  625.     DOMString retString;
  626.     if (fHandle != 0)
  627.         retString.fHandle = this->fHandle->cloneStringHandle();
  628.     return retString;
  629. };
  630. void DOMString::deleteData(unsigned int offset, unsigned int delLength)
  631. {
  632.     unsigned int stringLen = this->length();
  633.     if (offset >= stringLen)
  634.         throw DOM_DOMException(DOM_DOMException::INDEX_SIZE_ERR, 0);
  635.     if (delLength == 0)
  636.         return;
  637.     // Cap the value of delLength to avoid trouble with overflows
  638.     //  in the following length computations.
  639.     if (delLength > stringLen)
  640.         delLength = stringLen;
  641.     // If the length of data to be deleted would extend off the end
  642.     //   of the string, cut it back to stop at the end of string.
  643.     if (offset + delLength >= stringLen)
  644.         delLength = stringLen - offset;
  645.     unsigned int newStringLength = stringLen - delLength;
  646.     if (fHandle->fDSData->fRefCount > 1 && offset+delLength < stringLen)
  647.     {
  648.         // The deletion is of a range in the middle of the string
  649.         //  and there's another string handle using the buffer so
  650.         //  we need to make a new buffer before moving characters
  651.         //  around.
  652.         DOMStringData *newBuf = DOMStringData::allocateBuffer(newStringLength);
  653.         XMLCh *newP = newBuf->fData;
  654.         XMLCh *oldP = fHandle->fDSData->fData;
  655.         unsigned int i;
  656.         for (i=0; i<offset; i++)
  657.             newP[i] = oldP[i];
  658.         for (i=offset; i<newStringLength; i++)
  659.             newP[i] = oldP[i+delLength];
  660.         fHandle->fLength = newStringLength;
  661.         fHandle->fDSData->removeRef();
  662.         fHandle->fDSData = newBuf;
  663.     }
  664.     else if (offset+delLength < stringLen)
  665.     {
  666.         // The deletion is of a range in the middle of the string,
  667.         // but no other string is sharing the buffer, so we can
  668.         // just delete in place.
  669.         unsigned int i;
  670.         XMLCh *bufP =  fHandle->fDSData->fData;
  671.         for (i=offset; i<newStringLength; i++)
  672.             bufP[i] = bufP[i+delLength];
  673.         fHandle->fLength = newStringLength;
  674.     }
  675.     else
  676.     {
  677.         // The deletion continues to the end of the string.
  678.         // Simply reset the length.  We don't need to worry
  679.         // about other strings sharing the buffer because
  680.         // no characters are moved.
  681.         fHandle->fLength = newStringLength;
  682.     }
  683. };
  684. bool DOMString::equals(const DOMString &other) const
  685. {
  686.     bool retVal = true;
  687.     if (this->fHandle != 0  && other.fHandle != 0)
  688.     {
  689.         if (this->fHandle->fLength != other.fHandle->fLength)
  690.         {
  691.             retVal =  false;
  692.         }
  693.         else
  694.         {
  695.             XMLCh *thisP  = this->fHandle->fDSData->fData;
  696.             XMLCh *otherP = other.fHandle->fDSData->fData;
  697.             unsigned int i;
  698.             for (i=0; i<this->fHandle->fLength; i++)
  699.             {
  700.                 if (thisP[i] != otherP[i])
  701.                 {
  702.                     retVal = false;
  703.                     break;
  704.                 }
  705.             }
  706.         }
  707.     }
  708.     else
  709.     {
  710.         // At this point, one or more of the fHandle
  711.         //  pointers is known to be zero.
  712.         if (fHandle       && fHandle->fLength != 0  ||
  713.             other.fHandle && other.fHandle->fLength != 0)
  714.             retVal = false;
  715.     }
  716.     return retVal;
  717. };
  718. bool DOMString::equals(const XMLCh *other) const
  719. {
  720.     if (this->fHandle != 0  && other != 0)
  721.     {
  722.         // Both strings have non-null data pointers, so
  723.         //  we can go ahead and actually compare them.
  724.         XMLCh *thisP  = this->fHandle->fDSData->fData;
  725.         unsigned int len    = this->fHandle->fLength;
  726.         unsigned int i;
  727.         for (i=0; i<len; i++)
  728.         {
  729.             if (other[i] == 0)   // "other" is null terminated.
  730.                 return false;    //   (If there were no chance of a DOM
  731.                                  //   string having a 0 char in the middle of
  732.                                  //   it, this test could be omitted.)
  733.             if (thisP[i] != other[i])
  734.                 return false;
  735.         }
  736.         if (other[len] != 0)     // This test for the end of the other
  737.             return false;        //  string can't be done without first
  738.                                  //  checking that we haven't walked off the
  739.                                  //  end.  (It has actually happened - off end
  740.                                  //  of string, page, and valid memory.)
  741.         return true;
  742.     }
  743.     // At this point, we know that at least one of the strings had a null
  744.     //  data pointer.
  745.     if (fHandle  && fHandle->fLength != 0)
  746.         return false;
  747.     if (other && *other != 0)
  748.         return false;
  749.     return true;  // Both strings are empty.  DOMString treats zero-length
  750.                   //   and a null data pointer as equivalent.
  751. };
  752. void DOMString::insertData(unsigned int offset, const DOMString &src)
  753. {
  754.     unsigned int origStrLength = this->length();
  755.     if (offset > origStrLength)
  756.         throw DOM_DOMException(DOM_DOMException::INDEX_SIZE_ERR, 0);
  757.     if (fHandle == 0)
  758.     {
  759.         *this = src.clone();
  760.         return;
  761.     }
  762.     if (src.fHandle == 0 || src.fHandle->fLength == 0)
  763.         return;
  764.     XMLCh *srcP = src.fHandle->fDSData->fData;
  765.     unsigned int srcLength = src.fHandle->fLength;
  766.     unsigned int newLength = fHandle->fLength + srcLength;
  767.     if (newLength >= fHandle->fDSData->fBufferLength ||
  768.         fHandle->fDSData->fRefCount > 1  || fHandle == src.fHandle )
  769.     {
  770.         // We can't stick the data to be added into the
  771.         //  existing string, either because there is not space in
  772.         //  the buffer, or because the buffer is being shared with
  773.         //  some other string.
  774.         //  So, make a new buffer.
  775.         DOMStringData *newBuf = DOMStringData::allocateBuffer(newLength);
  776.         XMLCh *newP  = newBuf->fData;
  777.         XMLCh *oldP   = fHandle->fDSData->fData;
  778.         unsigned int i;
  779.         for (i=0; i<offset; ++i)
  780.             newP[i] = oldP[i];
  781.         for (i=0; i<srcLength; i++)
  782.             newP[i+offset] = srcP[i];
  783.         for (i=offset; i<origStrLength; i++)
  784.             newP[i+srcLength] = oldP[i];
  785.         fHandle->fDSData->removeRef();
  786.         fHandle->fDSData = newBuf;
  787.     }
  788.     else
  789.     {
  790.         // There is room in the already-existing buffer to hold
  791.         //  the data to be inserted.  Insert it.
  792.         //
  793.         XMLCh *destP = fHandle->fDSData->fData;
  794.         int i;
  795.         for (i=(int)origStrLength-1; i>=(int)offset; i--)
  796.             destP[i+srcLength] = destP[i];
  797.         unsigned int j;
  798.         for (j=0; j<srcLength; j++)
  799.             destP[j+offset] = srcP[j];
  800.     };
  801.     fHandle->fLength += srcLength;
  802. }
  803. unsigned int DOMString::length() const
  804. {
  805.     unsigned int len = 0;
  806.     if (fHandle != 0)
  807.         len = fHandle->fLength;
  808.     return len;
  809. };
  810. void DOMString::print() const
  811. {
  812.     unsigned int len = this->length();
  813.     if (len > 0)
  814.     {
  815.         // Transcode from Unicode to char * in whatever the system local code page is.
  816.         char *pc = transcode();
  817.         fputs(pc, stdout);
  818.         delete [] pc;
  819.     }
  820. };
  821. void DOMString::println() const
  822. {
  823. print();
  824.     putchar('n');
  825. };
  826. const XMLCh *DOMString::rawBuffer() const
  827. {
  828.     XMLCh  *retP = 0;
  829.     if (fHandle)
  830.     {
  831.         retP = fHandle->fDSData->fData;
  832.     }
  833.     return retP;
  834. };
  835. char *DOMString::transcode() const
  836. {
  837.     if (!fHandle || fHandle->fLength == 0)
  838.     {
  839.         char* retP = new char[1];
  840.         *retP = 0;
  841.         return retP;
  842.     }
  843.     // We've got some data
  844.     // DOMStrings are not always null terminated, so we may need to
  845.     // copy to another buffer first in order to null terminate it for
  846.     // use as input to the transcoding routines..
  847.     //
  848.     XMLCh* DOMStrData = fHandle->fDSData->fData;
  849.     const unsigned int localBufLen = 1000;
  850.     XMLCh localBuf[localBufLen];
  851.     XMLCh *allocatedBuf = 0;
  852.     XMLCh *srcP;
  853.     if (DOMStrData[fHandle->fLength] == 0)
  854.     {
  855.         // The data in the DOMString itself happens to be null terminated.
  856.         //  Just use it in place.
  857.         srcP = DOMStrData;
  858.     }
  859.     else if (fHandle->fLength < localBufLen-1)
  860.     {
  861.         // The data is not null terminated, but does fit in the
  862.         //  local buffer (fast allocation).  Copy it over, and add
  863.         //  the null termination,
  864.         memcpy(localBuf, DOMStrData, fHandle->fLength * sizeof(XMLCh));
  865.         srcP = localBuf;
  866.         srcP[fHandle->fLength] = 0;
  867.     }
  868.     else
  869.     {
  870.         // The data is too big for the local buffer.  Heap allocate one.
  871.         allocatedBuf = srcP = new XMLCh[fHandle->fLength + 1];
  872.         memcpy(allocatedBuf, DOMStrData, fHandle->fLength * sizeof(XMLCh));
  873.         srcP[fHandle->fLength] = 0;
  874.     }
  875.     //
  876.     //  Find out how many output chars we need and allocate a buffer big enough
  877.     //  for that plus a null.
  878.     //
  879.     const unsigned int charsNeeded = getDomConverter()->calcRequiredSize(srcP);
  880.     char* retP = new char[charsNeeded + 1];
  881.     if (!getDomConverter()->transcode(srcP, retP, charsNeeded))
  882.     {
  883.         // <TBD> We should throw something here?
  884.     }
  885.     delete [] allocatedBuf;   // which will be null if we didn't allocate one.
  886.     // Cap it off and return it
  887.     retP[charsNeeded] = 0;
  888.     return retP;
  889. }
  890. DOMString DOMString::transcode(const char* str)
  891. {
  892.     return DOMString(str);
  893. }
  894. int DOMString::compareString(const DOMString &other) const
  895. {
  896.     // Note: this strcmp does not match the semantics
  897.     //       of the standard C strcmp.  All it needs to do is
  898.     //       define some less than - equals - greater than ordering
  899.     //       of strings.  How doesn't matter.
  900.     //
  901.     unsigned int thisLen = length();
  902.     unsigned int otherLen = other.length();
  903.     if (thisLen < otherLen)
  904.         return -1;
  905.     if (thisLen > otherLen)
  906.         return 1;
  907.     if (thisLen == 0)
  908.         return 0;
  909.     XMLCh *thisP =  this->fHandle->fDSData->fData;
  910.     XMLCh *otherP = other.fHandle->fDSData->fData;
  911.     unsigned int i;
  912.     for (i=0; i<thisLen; i++)
  913.     {
  914.         if (thisP[i] < otherP[i])
  915.             return -1;
  916.         else if (thisP[i] > otherP[i])
  917.             return 1;
  918.     };
  919.     return 0;
  920. };
  921. DOMString DOMString::substringData(unsigned int offset, unsigned int count) const
  922. {
  923.     if (count == 0)
  924.         return DOMString();
  925.     unsigned int thisLen = length();
  926.     if (offset >= thisLen)
  927.         throw DOM_DOMException(DOM_DOMException::INDEX_SIZE_ERR, 0);
  928.     // Cap count to the string length to eliminate overflow
  929.     //  problems when we get passed bogus values, like -1.
  930.     if (count > thisLen)
  931.         count = thisLen;
  932.     // If the count extends past the end of the string, cut it
  933.     //   back so that the returned string will stop at the end
  934.     //   of the source string.
  935.     if (offset + count >= thisLen)
  936.         count = thisLen - offset;
  937.     // If the substring starts at the beginning of the original string
  938.     //   we do not need to copy the data, but can set up a new
  939.     //   string handle with the shorter length.
  940.     if (offset == 0)
  941.     {
  942.         DOMString retString = this->clone();
  943.         retString.fHandle->fLength = count;
  944.         return retString;
  945.     };
  946.     // The substring starts somewhere in the interior of the orignal string.
  947.     // Create a completely new DOMString.  No buffer sharing is possible.
  948.     XMLCh *data = fHandle->fDSData->fData;
  949.     return DOMString(data+offset, count);
  950. };
  951. DOMString operator + (const DOMString &lhs, const DOMString &rhs)
  952. {
  953.     DOMString retString = lhs.clone();
  954.     retString.appendData(rhs);
  955.     return retString;
  956. }
  957. DOMString operator + (const DOMString &lhs, const XMLCh* rhs)
  958. {
  959.     DOMString retString = lhs.clone();
  960.     retString.appendData(rhs);
  961.     return retString;
  962. }
  963. DOMString operator + (const XMLCh* lhs, const DOMString& rhs)
  964. {
  965.     DOMString retString = DOMString(lhs);
  966.     retString.appendData(rhs);
  967.     return retString;
  968. }
  969. DOMString operator + (const DOMString &lhs, XMLCh rhs)
  970. {
  971.     DOMString retString = lhs.clone();
  972.     retString.appendData(rhs);
  973.     return retString;
  974. }
  975. DOMString operator + (XMLCh lhs, const DOMString& rhs)
  976. {
  977.     DOMString retString;
  978. retString.appendData(lhs);
  979.     retString.appendData(rhs);
  980.     return retString;
  981. }
  982. static void DOMStringTerminate()        // Termination function cleans up all lazily created
  983. {                                       //   resources used by the DOMString implementation.
  984.                                         //   Called when no DOMStrings remain in the app.  (We
  985.                                         //   know this from reference counting.)
  986.         delete DOMStringHandleMutex;    //  Delete the synchronization mutex,
  987.         DOMStringHandleMutex = 0;
  988.         delete gDomConverter;           //  Delete the local code page converter.
  989.         gDomConverter = 0;
  990. };