GME  13
DOMDocumentImpl.cpp
Go to the documentation of this file.
00001 /*
00002  * Licensed to the Apache Software Foundation (ASF) under one or more
00003  * contributor license agreements.  See the NOTICE file distributed with
00004  * this work for additional information regarding copyright ownership.
00005  * The ASF licenses this file to You under the Apache License, Version 2.0
00006  * (the "License"); you may not use this file except in compliance with
00007  * the License.  You may obtain a copy of the License at
00008  *
00009  *      http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 /*
00019  * $Id: DOMDocumentImpl.cpp 932949 2010-04-11 17:40:33Z borisk $
00020  */
00021 #include "DOMDocumentImpl.hpp"
00022 #include "DOMCasts.hpp"
00023 #include "DOMConfigurationImpl.hpp"
00024 #include "DOMDocumentTypeImpl.hpp"
00025 #include "DOMAttrImpl.hpp"
00026 #include "DOMAttrNSImpl.hpp"
00027 #include "DOMCDATASectionImpl.hpp"
00028 #include "DOMCommentImpl.hpp"
00029 #include "DOMDeepNodeListImpl.hpp"
00030 #include "DOMDocumentFragmentImpl.hpp"
00031 #include "DOMElementImpl.hpp"
00032 #include "XSDElementNSImpl.hpp"
00033 #include "DOMEntityImpl.hpp"
00034 #include "DOMEntityReferenceImpl.hpp"
00035 #include "DOMNormalizer.hpp"
00036 #include "DOMNotationImpl.hpp"
00037 #include "DOMProcessingInstructionImpl.hpp"
00038 #include "DOMTextImpl.hpp"
00039 #include "DOMTreeWalkerImpl.hpp"
00040 #include "DOMNodeIteratorImpl.hpp"
00041 #include "DOMNodeIDMap.hpp"
00042 #include "DOMRangeImpl.hpp"
00043 #include "DOMTypeInfoImpl.hpp"
00044 #include "DOMXPathExpressionImpl.hpp"
00045 #include "DOMXPathNSResolverImpl.hpp"
00046 
00047 #include <xercesc/dom/DOMImplementation.hpp>
00048 #include <xercesc/framework/MemoryManager.hpp>
00049 #include <xercesc/util/OutOfMemoryException.hpp>
00050 #include <xercesc/util/XMLInitializer.hpp>
00051 #include <xercesc/util/Janitor.hpp>
00052 
00053 XERCES_CPP_NAMESPACE_BEGIN
00054 
00055 // The chunk size to allocate from the system allocator.
00056 static XMLSize_t kInitialHeapAllocSize =  0x4000;
00057 static XMLSize_t kMaxHeapAllocSize     = 0x80000;
00058 static XMLSize_t kMaxSubAllocationSize =  0x0100;  // Any request for more bytes
00059                                                    // than this will be handled by
00060                                                    // allocating directly with system.
00061 
00062 void XMLInitializer::initializeDOMHeap (XMLSize_t initialHeapAllocSize,
00063                                         XMLSize_t maxHeapAllocSize,
00064                                         XMLSize_t maxSubAllocationSize)
00065 {
00066   kInitialHeapAllocSize = initialHeapAllocSize;
00067   kMaxHeapAllocSize = maxHeapAllocSize;
00068   kMaxSubAllocationSize = maxSubAllocationSize;
00069 }
00070 
00071 //
00072 //   Constructors.   Warning - be very careful with the ordering of initialization
00073 //                             of the heap.  Ordering depends on the order of declaration
00074 //                             in the .hpp file, not on the order of initializers here
00075 //                             in the constructor.  The heap declaration can not be
00076 //                             first - fNode and fParent must be first for the casting
00077 //                             functions in DOMCasts to work correctly.  This means that
00078 //                             fNode and fParent constructors used here can not
00079 //                             allocate.
00080 //
00081 DOMDocumentImpl::DOMDocumentImpl(DOMImplementation* domImpl, MemoryManager* const manager)
00082     : fNode(this),
00083       fParent(this),
00084       fNodeIDMap(0),
00085       fInputEncoding(0),
00086       fXmlEncoding(0),
00087       fXmlStandalone(false),
00088       fXmlVersion(0),
00089       fDocumentURI(0),
00090       fDOMConfiguration(0),
00091       fUserDataTableKeys(17, manager),
00092       fUserDataTable(0),
00093       fCurrentBlock(0),
00094       fFreePtr(0),
00095       fFreeBytesRemaining(0),
00096       fHeapAllocSize(kInitialHeapAllocSize),
00097       fRecycleNodePtr(0),
00098       fRecycleBufferPtr(0),
00099       fNodeListPool(0),
00100       fDocType(0),
00101       fDocElement(0),
00102       fNameTableSize(257),
00103       fNormalizer(0),
00104       fRanges(0),
00105       fNodeIterators(0),
00106       fMemoryManager(manager),
00107       fDOMImplementation(domImpl),
00108       fChanges(0),
00109       errorChecking(true)
00110 {
00111     fNameTable = (DOMStringPoolEntry**)allocate (
00112       sizeof (DOMStringPoolEntry*) * fNameTableSize);
00113     for (XMLSize_t i = 0; i < fNameTableSize; i++)
00114       fNameTable[i] = 0;
00115 }
00116 
00117 
00118 //DOM Level 2
00119 DOMDocumentImpl::DOMDocumentImpl(const XMLCh *fNamespaceURI,
00120                                const XMLCh *qualifiedName,
00121                                DOMDocumentType *doctype,
00122                                DOMImplementation* domImpl,
00123                                MemoryManager* const manager)
00124     : fNode(this),
00125       fParent(this),
00126       fNodeIDMap(0),
00127       fInputEncoding(0),
00128       fXmlEncoding(0),
00129       fXmlStandalone(false),
00130       fXmlVersion(0),
00131       fDocumentURI(0),
00132       fDOMConfiguration(0),
00133       fUserDataTableKeys(17, manager),
00134       fUserDataTable(0),
00135       fCurrentBlock(0),
00136       fFreePtr(0),
00137       fFreeBytesRemaining(0),
00138       fHeapAllocSize(kInitialHeapAllocSize),
00139       fRecycleNodePtr(0),
00140       fRecycleBufferPtr(0),
00141       fNodeListPool(0),
00142       fDocType(0),
00143       fDocElement(0),
00144       fNameTableSize(257),
00145       fNormalizer(0),
00146       fRanges(0),
00147       fNodeIterators(0),
00148       fMemoryManager(manager),
00149       fDOMImplementation(domImpl),
00150       fChanges(0),
00151       errorChecking(true)
00152 {
00153     fNameTable = (DOMStringPoolEntry**)allocate (
00154       sizeof (DOMStringPoolEntry*) * fNameTableSize);
00155     for (XMLSize_t i = 0; i < fNameTableSize; i++)
00156       fNameTable[i] = 0;
00157 
00158     try {
00159         setDocumentType(doctype);
00160 
00161         if (qualifiedName)
00162             appendChild(createElementNS(fNamespaceURI, qualifiedName));  //root element
00163         else if (fNamespaceURI)
00164             throw DOMException(DOMException::NAMESPACE_ERR, 0, getMemoryManager());
00165     }
00166     catch(const OutOfMemoryException&)
00167     {
00168         throw;
00169     }
00170     catch (...) {
00171         this->deleteHeap();
00172         throw;
00173     }
00174 }
00175 
00176 void DOMDocumentImpl::setDocumentType(DOMDocumentType *doctype)
00177 {
00178     if (!doctype)
00179         return;
00180 
00181     // New doctypes can be created either with the factory methods on DOMImplementation, in
00182     //   which case ownerDocument will be 0, or with methods on DocumentImpl, in which case
00183     //   ownerDocument will be set, but the DocType won't yet be a child of the document.
00184     //
00185     DOMDocument* doc = doctype->getOwnerDocument();
00186     if (doc != 0 && doc != this)
00187         throw DOMException(    //one doctype can belong to only one DOMDocumentImpl
00188         DOMException::WRONG_DOCUMENT_ERR, 0, getMemoryManager());
00189 
00190     DOMDocumentTypeImpl* doctypeImpl = (DOMDocumentTypeImpl*) doctype;
00191     doctypeImpl->setOwnerDocument(this);
00192 
00193     // The doctype can not have any Entities or Notations yet, because they can not
00194     //   be created except through factory methods on a document.
00195 
00196     // revisit.  What if this doctype is already a child of the document?
00197     appendChild(doctype);
00198 
00199 }
00200 
00201 DOMDocumentImpl::~DOMDocumentImpl()
00202 {
00203     // While DOMConfiguration is allocated on the Document's heap, itself
00204     // it uses the memory manager directly. This means that while we cannot
00205     // delete with operator delete, we need to call its d-tor.
00206     //
00207     if (fDOMConfiguration)
00208       fDOMConfiguration->~DOMConfiguration ();
00209 
00210     //  Clean up the fNodeListPool
00211     if (fNodeListPool)
00212         fNodeListPool->cleanup();
00213 
00214     if (fRanges)
00215         delete fRanges; //fRanges->cleanup();
00216 
00217     if (fNodeIterators)
00218         delete fNodeIterators;//fNodeIterators->cleanup();
00219 
00220     if (fUserDataTable)
00221         delete fUserDataTable;//fUserDataTable->cleanup();
00222 
00223     if (fRecycleNodePtr) {
00224         fRecycleNodePtr->deleteAllElements();
00225         delete fRecycleNodePtr;
00226     }
00227 
00228     if (fRecycleBufferPtr) {
00229         delete fRecycleBufferPtr;
00230     }
00231 
00232     delete fNormalizer;
00233 
00234     //  Delete the heap for this document.  This uncerimoniously yanks the storage
00235     //      out from under all of the nodes in the document.  Destructors are NOT called.
00236     this->deleteHeap();
00237 }
00238 
00239 
00240 DOMNode *DOMDocumentImpl::cloneNode(bool deep) const {
00241 
00242     // Note:  the cloned document node goes on the same heap we live in.
00243     DOMDocumentImpl *newdoc = new (fMemoryManager) DOMDocumentImpl(fDOMImplementation, fMemoryManager);
00244     if(fXmlEncoding && *fXmlEncoding)
00245         newdoc->setXmlEncoding(fXmlEncoding);
00246     if(fXmlVersion && *fXmlVersion)
00247         newdoc->setXmlVersion(fXmlVersion);
00248     newdoc->setXmlStandalone(fXmlStandalone);
00249 
00250     // then the children by _importing_ them
00251     if (deep)
00252         for (DOMNode *n = this->getFirstChild(); n != 0; n = n->getNextSibling()) {
00253             newdoc->appendChild(newdoc->importNode(n, true, true));
00254     }
00255 
00256     fNode.callUserDataHandlers(DOMUserDataHandler::NODE_CLONED, this, newdoc);
00257     return newdoc;
00258 }
00259 
00260 
00261 const XMLCh * DOMDocumentImpl::getNodeName() const {
00262     static const XMLCh nam[] =  // "#document"
00263         {chPound, chLatin_d, chLatin_o, chLatin_c, chLatin_u, chLatin_m, chLatin_e, chLatin_n, chLatin_t, 0};
00264     return nam;
00265 }
00266 
00267 
00268 DOMNode::NodeType DOMDocumentImpl::getNodeType() const {
00269     return DOMNode::DOCUMENT_NODE;
00270 }
00271 
00272 
00273 // even though ownerDocument refers to this in this implementation
00274 // the DOM Level 2 spec says it must be 0, so make it appear so
00275 DOMDocument * DOMDocumentImpl::getOwnerDocument() const {
00276     return 0;
00277 }
00278 
00279 
00280 DOMAttr *DOMDocumentImpl::createAttribute(const XMLCh *nam)
00281 {
00282     if(!nam || !isXMLName(nam))
00283         throw DOMException(DOMException::INVALID_CHARACTER_ERR,0, getMemoryManager());
00284     return new (this, DOMMemoryManager::ATTR_OBJECT) DOMAttrImpl(this,nam);
00285 }
00286 
00287 
00288 
00289 DOMCDATASection *DOMDocumentImpl::createCDATASection(const XMLCh *data) {
00290     return new (this, DOMMemoryManager::CDATA_SECTION_OBJECT) DOMCDATASectionImpl(this,data);
00291 }
00292 
00293 
00294 
00295 DOMComment *DOMDocumentImpl::createComment(const XMLCh *data)
00296 {
00297     return new (this, DOMMemoryManager::COMMENT_OBJECT) DOMCommentImpl(this, data);
00298 }
00299 
00300 
00301 
00302 DOMDocumentFragment *DOMDocumentImpl::createDocumentFragment()
00303 {
00304     return new (this, DOMMemoryManager::DOCUMENT_FRAGMENT_OBJECT) DOMDocumentFragmentImpl(this);
00305 }
00306 
00307 
00308 
00309 DOMDocumentType *DOMDocumentImpl::createDocumentType(const XMLCh *nam)
00310 {
00311     if (!nam || !isXMLName(nam))
00312         throw DOMException(
00313         DOMException::INVALID_CHARACTER_ERR, 0, getMemoryManager());
00314 
00315     return new (this, DOMMemoryManager::DOCUMENT_TYPE_OBJECT) DOMDocumentTypeImpl(this, nam, false);
00316 }
00317 
00318 
00319 
00320 DOMDocumentType *
00321     DOMDocumentImpl::createDocumentType(const XMLCh *qualifiedName,
00322                                      const XMLCh *publicId,
00323                                      const XMLCh *systemId)
00324 {
00325     if (!qualifiedName || !isXMLName(qualifiedName))
00326         throw DOMException(
00327         DOMException::INVALID_CHARACTER_ERR, 0, getMemoryManager());
00328 
00329     return new (this, DOMMemoryManager::DOCUMENT_TYPE_OBJECT) DOMDocumentTypeImpl(this, qualifiedName, publicId, systemId, false);
00330 }
00331 
00332 
00333 
00334 DOMElement *DOMDocumentImpl::createElement(const XMLCh *tagName)
00335 {
00336     if(!tagName || !isXMLName(tagName))
00337         throw DOMException(DOMException::INVALID_CHARACTER_ERR,0, getMemoryManager());
00338 
00339     return new (this, DOMMemoryManager::ELEMENT_OBJECT) DOMElementImpl(this,tagName);
00340 }
00341 
00342 
00343 DOMElement *DOMDocumentImpl::createElementNoCheck(const XMLCh *tagName)
00344 {
00345     return new (this, DOMMemoryManager::ELEMENT_OBJECT) DOMElementImpl(this, tagName);
00346 }
00347 
00348 
00349 
00350 
00351 DOMEntity *DOMDocumentImpl::createEntity(const XMLCh *nam)
00352 {
00353     if (!nam || !isXMLName(nam))
00354         throw DOMException(
00355         DOMException::INVALID_CHARACTER_ERR, 0, getMemoryManager());
00356 
00357     return new (this, DOMMemoryManager::ENTITY_OBJECT) DOMEntityImpl(this, nam);
00358 }
00359 
00360 
00361 
00362 DOMEntityReference *DOMDocumentImpl::createEntityReference(const XMLCh *nam)
00363 {
00364     if (!nam || !isXMLName(nam))
00365         throw DOMException(
00366         DOMException::INVALID_CHARACTER_ERR, 0, getMemoryManager());
00367 
00368     return new (this, DOMMemoryManager::ENTITY_REFERENCE_OBJECT) DOMEntityReferenceImpl(this, nam);
00369 }
00370 
00371 DOMEntityReference *DOMDocumentImpl::createEntityReferenceByParser(const XMLCh *nam)
00372 {
00373     if (!nam || !isXMLName(nam))
00374         throw DOMException(
00375         DOMException::INVALID_CHARACTER_ERR, 0, getMemoryManager());
00376 
00377     return new (this, DOMMemoryManager::ENTITY_REFERENCE_OBJECT) DOMEntityReferenceImpl(this, nam, false);
00378 }
00379 
00380 DOMNotation *DOMDocumentImpl::createNotation(const XMLCh *nam)
00381 {
00382     if (!nam || !isXMLName(nam))
00383         throw DOMException(
00384         DOMException::INVALID_CHARACTER_ERR, 0, getMemoryManager());
00385 
00386     return new (this, DOMMemoryManager::NOTATION_OBJECT) DOMNotationImpl(this, nam);
00387 }
00388 
00389 
00390 
00391 DOMProcessingInstruction *DOMDocumentImpl::createProcessingInstruction(
00392                                           const XMLCh *target, const XMLCh *data)
00393 {
00394     if(!target || !isXMLName(target))
00395         throw DOMException(DOMException::INVALID_CHARACTER_ERR,0, getMemoryManager());
00396     return new (this, DOMMemoryManager::PROCESSING_INSTRUCTION_OBJECT) DOMProcessingInstructionImpl(this,target,data);
00397 }
00398 
00399 
00400 
00401 
00402 DOMText *DOMDocumentImpl::createTextNode(const XMLCh *data)
00403 {
00404     return new (this, DOMMemoryManager::TEXT_OBJECT) DOMTextImpl(this,data);
00405 }
00406 
00407 
00408 DOMNodeIterator* DOMDocumentImpl::createNodeIterator (
00409   DOMNode *root,
00410   DOMNodeFilter::ShowType whatToShow,
00411   DOMNodeFilter* filter,
00412   bool entityReferenceExpansion)
00413 {
00414     if (!root) {
00415         throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, getMemoryManager());
00416         return 0;
00417     }
00418 
00419     DOMNodeIteratorImpl* nodeIterator = new (this) DOMNodeIteratorImpl(this, root, whatToShow, filter, entityReferenceExpansion);
00420 
00421     if (fNodeIterators == 0L) {
00422         //fNodeIterators = new (this) NodeIterators(1, false);
00423         fNodeIterators = new (fMemoryManager) NodeIterators(1, false, fMemoryManager);
00424     }
00425     fNodeIterators->addElement(nodeIterator);
00426 
00427     return nodeIterator;
00428 }
00429 
00430 
00431 NodeIterators* DOMDocumentImpl::getNodeIterators() const
00432 {
00433     return fNodeIterators;
00434 }
00435 
00436 void DOMDocumentImpl::removeNodeIterator(DOMNodeIteratorImpl* nodeIterator)
00437 {
00438     if (fNodeIterators != 0) {
00439         XMLSize_t sz = fNodeIterators->size();
00440         if (sz !=0) {
00441             for (XMLSize_t i =0; i<sz; i++) {
00442                 if (fNodeIterators->elementAt(i) == nodeIterator) {
00443                     fNodeIterators->removeElementAt(i);
00444                     break;
00445                 }
00446             }
00447         }
00448     }
00449 }
00450 
00451 
00452 DOMXPathExpression* DOMDocumentImpl::createExpression(const XMLCh * expression, const DOMXPathNSResolver *resolver)
00453 {
00454     return new (getMemoryManager()) DOMXPathExpressionImpl(expression, resolver, getMemoryManager());
00455 }
00456 
00457 DOMXPathNSResolver* DOMDocumentImpl::createNSResolver(const DOMNode *nodeResolver)
00458 {
00459     return new (getMemoryManager()) DOMXPathNSResolverImpl(nodeResolver, getMemoryManager());
00460 }
00461 
00462 DOMXPathResult* DOMDocumentImpl::evaluate(const XMLCh *expression,
00463                                           const DOMNode *contextNode,
00464                                           const DOMXPathNSResolver *resolver,
00465                                           DOMXPathResult::ResultType type,
00466                                           DOMXPathResult* result)
00467 {
00468     JanitorMemFunCall<DOMXPathExpression> expr(
00469       createExpression(expression, resolver),
00470       &DOMXPathExpression::release);
00471     return expr->evaluate(contextNode, type, result);
00472 }
00473 
00474 
00475 
00476 DOMTreeWalker* DOMDocumentImpl::createTreeWalker (
00477   DOMNode *root,
00478   DOMNodeFilter::ShowType whatToShow,
00479   DOMNodeFilter* filter,
00480   bool entityReferenceExpansion)
00481 {
00482     if (!root) {
00483         throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, getMemoryManager());
00484         return 0;
00485     }
00486 
00487     return new (this) DOMTreeWalkerImpl(root, whatToShow, filter, entityReferenceExpansion);
00488 }
00489 
00490 
00491 
00492 
00493 DOMDocumentType *DOMDocumentImpl::getDoctype() const
00494 {
00495     return fDocType;
00496 }
00497 
00498 
00499 
00500 DOMElement *DOMDocumentImpl::getDocumentElement() const
00501 {
00502     return fDocElement;
00503 }
00504 
00505 
00506 
00507 DOMNodeList *DOMDocumentImpl::getElementsByTagName(const XMLCh *tagname) const
00508 {
00509     // cast off the const of this because we will update the fNodeListPool
00510     return ((DOMDocumentImpl*)this)->getDeepNodeList(this,tagname);
00511 }
00512 
00513 
00514 DOMImplementation   *DOMDocumentImpl::getImplementation() const {
00515 
00516     return fDOMImplementation;
00517 }
00518 
00519 
00520 DOMNode *DOMDocumentImpl::insertBefore(DOMNode *newChild, DOMNode *refChild)
00521 {
00522     // Only one such child permitted
00523     if(
00524         (newChild->getNodeType() == DOMNode::ELEMENT_NODE  && fDocElement!=0)
00525         ||
00526         (newChild->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE  && fDocType!=0)
00527         )
00528         throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0, getMemoryManager());
00529 
00530     // if the newChild is a documenttype node created from domimplementation, set the ownerDoc first
00531     if ((newChild->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE) && !newChild->getOwnerDocument())
00532         ((DOMDocumentTypeImpl*)newChild)->setOwnerDocument(this);
00533 
00534     fParent.insertBefore(newChild,refChild);
00535 
00536     // If insert succeeded, cache the kid appropriately
00537     if(newChild->getNodeType() == DOMNode::ELEMENT_NODE)
00538         fDocElement=(DOMElement *)newChild;
00539     else if(newChild->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE)
00540         fDocType=(DOMDocumentType *)newChild;
00541 
00542     return newChild;
00543 }
00544 
00545 
00546 DOMNode* DOMDocumentImpl::replaceChild(DOMNode *newChild, DOMNode *oldChild) {
00547     DOMDocumentType* tempDocType = fDocType;
00548     DOMElement* tempDocElement = fDocElement;
00549 
00550     if(oldChild->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE)
00551         fDocType=0;
00552     else if(oldChild->getNodeType() == DOMNode::ELEMENT_NODE)
00553         fDocElement=0;
00554 
00555     try {
00556         insertBefore(newChild, oldChild);
00557         // changed() already done.
00558 
00559         if((oldChild->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE)
00560         || (oldChild->getNodeType() == DOMNode::ELEMENT_NODE))
00561             return fParent.removeChild(oldChild);
00562         else
00563             return removeChild(oldChild);
00564     }
00565     catch(const OutOfMemoryException&)
00566     {
00567         throw;
00568     }
00569     catch(...) {
00570         fDocType = tempDocType;
00571         fDocElement = tempDocElement;
00572         throw;
00573     }
00574 }
00575 
00576 bool DOMDocumentImpl::isXMLName(const XMLCh *s)
00577 {
00578     // fXmlVersion points directly to the static constants
00579     if (fXmlVersion==XMLUni::fgVersion1_1)
00580         return XMLChar1_1::isValidName(s);
00581     else
00582         return XMLChar1_0::isValidName(s);
00583 }
00584 
00585 
00586 
00587 
00588 DOMNode *DOMDocumentImpl::removeChild(DOMNode *oldChild)
00589 {
00590     fParent.removeChild(oldChild);
00591 
00592     // If remove succeeded, un-cache the kid appropriately
00593     if(oldChild->getNodeType() == DOMNode::ELEMENT_NODE)
00594         fDocElement=0;
00595     else if(oldChild->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE)
00596         fDocType=0;
00597 
00598     return oldChild;
00599 }
00600 
00601 
00602 
00603 void DOMDocumentImpl::setNodeValue(const XMLCh *x)
00604 {
00605     fNode.setNodeValue(x);
00606 }
00607 
00608 
00609 //Introduced in DOM Level 2
00610 DOMNode *DOMDocumentImpl::importNode(const DOMNode *source, bool deep)
00611 {
00612     return importNode(source, deep, false);
00613 }
00614 
00615 
00616 DOMElement *DOMDocumentImpl::createElementNS(const XMLCh *fNamespaceURI,
00617                                              const XMLCh *qualifiedName)
00618 {
00619     if(!qualifiedName || !isXMLName(qualifiedName))
00620         throw DOMException(DOMException::INVALID_CHARACTER_ERR,0, getMemoryManager());
00621 
00622     return new (this, DOMMemoryManager::ELEMENT_NS_OBJECT) DOMElementNSImpl(this, fNamespaceURI, qualifiedName);
00623 }
00624 
00625 DOMElement *DOMDocumentImpl::createElementNS(const XMLCh *fNamespaceURI,
00626                                               const XMLCh *qualifiedName,
00627                                               const XMLFileLoc lineNo,
00628                                               const XMLFileLoc columnNo)
00629 {
00630     if(!qualifiedName || !isXMLName(qualifiedName))
00631         throw DOMException(DOMException::INVALID_CHARACTER_ERR,0, getMemoryManager());
00632 
00633     return new (this) XSDElementNSImpl(this, fNamespaceURI, qualifiedName, lineNo, columnNo);
00634 }
00635 
00636 
00637 DOMAttr *DOMDocumentImpl::createAttributeNS(const XMLCh *fNamespaceURI,
00638     const XMLCh *qualifiedName)
00639 {
00640     if(!qualifiedName || !isXMLName(qualifiedName))
00641         throw DOMException(DOMException::INVALID_CHARACTER_ERR,0, getMemoryManager());
00642     return new (this, DOMMemoryManager::ATTR_NS_OBJECT) DOMAttrNSImpl(this, fNamespaceURI, qualifiedName);
00643 }
00644 
00645 
00646 DOMNodeList *DOMDocumentImpl::getElementsByTagNameNS(const XMLCh *fNamespaceURI,
00647     const XMLCh *fLocalName)  const
00648 {
00649     // cast off the const of this because we will update the fNodeListPool
00650     return ((DOMDocumentImpl*)this)->getDeepNodeList(this, fNamespaceURI, fLocalName);
00651 }
00652 
00653 
00654 DOMElement *DOMDocumentImpl::getElementById(const XMLCh *elementId) const
00655 {
00656     if (fNodeIDMap == 0)
00657         return 0;
00658 
00659     DOMAttr *theAttr = fNodeIDMap->find(elementId);
00660     if (theAttr == 0)
00661         return 0;
00662 
00663     return theAttr->getOwnerElement();
00664 }
00665 
00666 const XMLCh* DOMDocumentImpl::getBaseURI() const
00667 {
00668           return fDocumentURI;
00669 }
00670 
00671 DOMRange* DOMDocumentImpl::createRange()
00672 {
00673 
00674     DOMRangeImpl* range = new (this) DOMRangeImpl(this, fMemoryManager);
00675 
00676     if (fRanges == 0L) {
00677         //fRanges = new (this) Ranges(1, false);
00678         fRanges = new (fMemoryManager) Ranges(1, false, fMemoryManager); // XMemory
00679     }
00680     fRanges->addElement(range);
00681     return range;
00682 }
00683 
00684 Ranges* DOMDocumentImpl::getRanges() const
00685 {
00686     return fRanges;
00687 }
00688 
00689 void DOMDocumentImpl::removeRange(DOMRangeImpl* range)
00690 {
00691     if (fRanges != 0) {
00692         XMLSize_t sz = fRanges->size();
00693         if (sz !=0) {
00694             for (XMLSize_t i =0; i<sz; i++) {
00695                 if (fRanges->elementAt(i) == range) {
00696                     fRanges->removeElementAt(i);
00697                     break;
00698                 }
00699             }
00700         }
00701     }
00702 }
00703 
00710 bool DOMDocumentImpl::isKidOK(DOMNode *parent, DOMNode *child)
00711 {
00712       static int kidOK[14];
00713 
00714       if (kidOK[DOMNode::ATTRIBUTE_NODE] == 0)
00715       {
00716           kidOK[DOMNode::DOCUMENT_NODE] =
00717               1 << DOMNode::ELEMENT_NODE |
00718               1 << DOMNode::PROCESSING_INSTRUCTION_NODE |
00719               1 << DOMNode::COMMENT_NODE |
00720               1 << DOMNode::DOCUMENT_TYPE_NODE;
00721 
00722           kidOK[DOMNode::DOCUMENT_FRAGMENT_NODE] =
00723               kidOK[DOMNode::ENTITY_NODE] =
00724               kidOK[DOMNode::ENTITY_REFERENCE_NODE] =
00725               kidOK[DOMNode::ELEMENT_NODE] =
00726               1 << DOMNode::ELEMENT_NODE |
00727               1 << DOMNode::PROCESSING_INSTRUCTION_NODE |
00728               1 << DOMNode::COMMENT_NODE |
00729               1 << DOMNode::TEXT_NODE |
00730               1 << DOMNode::CDATA_SECTION_NODE |
00731               1 << DOMNode::ENTITY_REFERENCE_NODE;
00732 
00733           kidOK[DOMNode::ATTRIBUTE_NODE] =
00734               1 << DOMNode::TEXT_NODE |
00735               1 << DOMNode::ENTITY_REFERENCE_NODE;
00736 
00737           kidOK[DOMNode::PROCESSING_INSTRUCTION_NODE] =
00738               kidOK[DOMNode::COMMENT_NODE] =
00739               kidOK[DOMNode::TEXT_NODE] =
00740               kidOK[DOMNode::CDATA_SECTION_NODE] =
00741               kidOK[DOMNode::NOTATION_NODE] =
00742               0;
00743       }
00744       int p=parent->getNodeType();
00745       int ch = child->getNodeType();
00746       return ((kidOK[p] & 1<<ch) != 0) ||
00747              (p==DOMNode::DOCUMENT_NODE && ch==DOMNode::TEXT_NODE &&
00748               ((XMLString::equals(((DOMDocument*)parent)->getXmlVersion(), XMLUni::fgVersion1_1))?
00749                     XMLChar1_1::isAllSpaces(child->getNodeValue(), XMLString::stringLen(child->getNodeValue())):
00750                     XMLChar1_0::isAllSpaces(child->getNodeValue(), XMLString::stringLen(child->getNodeValue())))
00751              );
00752 }
00753 
00754 void            DOMDocumentImpl::changed()
00755 {
00756     fChanges++;
00757 }
00758 
00759 
00760 int             DOMDocumentImpl::changes() const{
00761     return fChanges;
00762 }
00763 
00764 
00765 
00766 //
00767 //    Delegation for functions inherited from DOMNode
00768 //
00769            DOMNode*         DOMDocumentImpl::appendChild(DOMNode *newChild)          {return insertBefore(newChild, 0); }
00770            DOMNamedNodeMap* DOMDocumentImpl::getAttributes() const                   {return fNode.getAttributes (); }
00771            DOMNodeList*     DOMDocumentImpl::getChildNodes() const                   {return fParent.getChildNodes (); }
00772            DOMNode*         DOMDocumentImpl::getFirstChild() const                   {return fParent.getFirstChild (); }
00773            DOMNode*         DOMDocumentImpl::getLastChild() const                    {return fParent.getLastChild (); }
00774      const XMLCh*           DOMDocumentImpl::getLocalName() const                    {return fNode.getLocalName (); }
00775      const XMLCh*           DOMDocumentImpl::getNamespaceURI() const                 {return fNode.getNamespaceURI (); }
00776            DOMNode*         DOMDocumentImpl::getNextSibling() const                  {return fNode.getNextSibling (); }
00777      const XMLCh*           DOMDocumentImpl::getNodeValue() const                    {return fNode.getNodeValue (); }
00778      const XMLCh*           DOMDocumentImpl::getPrefix() const                       {return fNode.getPrefix (); }
00779            DOMNode*         DOMDocumentImpl::getParentNode() const                   {return fNode.getParentNode (); }
00780            DOMNode*         DOMDocumentImpl::getPreviousSibling() const              {return fNode.getPreviousSibling (); }
00781            bool             DOMDocumentImpl::hasChildNodes() const                   {return fParent.hasChildNodes (); }
00782            void             DOMDocumentImpl::normalize()                             {fParent.normalize (); }
00783            void             DOMDocumentImpl::setPrefix(const XMLCh  *prefix)         {fNode.setPrefix(prefix); }
00784            bool             DOMDocumentImpl::hasAttributes() const                   {return fNode.hasAttributes(); }
00785            bool             DOMDocumentImpl::isSameNode(const DOMNode* other) const  {return fNode.isSameNode(other);}
00786            bool             DOMDocumentImpl::isEqualNode(const DOMNode* arg) const   {return fParent.isEqualNode(arg);}
00787            void*            DOMDocumentImpl::setUserData(const XMLCh* key, void* data, DOMUserDataHandler* handler)
00788                                                                                      {return fNode.setUserData(key, data, handler); }
00789            void*            DOMDocumentImpl::getUserData(const XMLCh* key) const     {return fNode.getUserData(key); }
00790            short            DOMDocumentImpl::compareDocumentPosition(const DOMNode* other) const {return fNode.compareDocumentPosition(other); }
00791            const XMLCh*     DOMDocumentImpl::getTextContent() const                  {return fNode.getTextContent(); }
00792            void             DOMDocumentImpl::setTextContent(const XMLCh* textContent){fNode.setTextContent(textContent); }
00793            const XMLCh*     DOMDocumentImpl::lookupPrefix(const XMLCh* namespaceURI) const  {return fNode.lookupPrefix(namespaceURI); }
00794            bool             DOMDocumentImpl::isDefaultNamespace(const XMLCh* namespaceURI) const {return fNode.isDefaultNamespace(namespaceURI); }
00795            const XMLCh*     DOMDocumentImpl::lookupNamespaceURI(const XMLCh* prefix) const  {return fNode.lookupNamespaceURI(prefix); }
00796 
00797 
00798 
00799 
00800 //-----------------------------------------------------------------------
00801 //
00802 //  Per Document Heap and Heap Helper functions
00803 //
00804 //        revisit - this stuff should be a class of its own, rather than
00805 //                       just lying around naked in DocumentImpl.
00806 //
00807 //-----------------------------------------------------------------------
00808 
00809 XMLCh * DOMDocumentImpl::cloneString(const XMLCh *src)
00810 {
00811     if (!src) return 0;
00812     XMLSize_t len = XMLString::stringLen(src);
00813     len = (len + 1) * sizeof(XMLCh);
00814     len = (len % 4) + len;
00815     XMLCh *newStr = (XMLCh *)this->allocate(len);
00816     XMLString::copyString(newStr, src);
00817     return newStr;
00818 }
00819 
00820 XMLSize_t DOMDocumentImpl::getMemoryAllocationBlockSize() const
00821 {
00822     return fHeapAllocSize;
00823 }
00824 
00825 void DOMDocumentImpl::setMemoryAllocationBlockSize(XMLSize_t size)
00826 {
00827     // the new size must be bigger than the maximum amount of each allocation
00828     if(size>kMaxSubAllocationSize)
00829         fHeapAllocSize=size;
00830 }
00831 
00832 void* DOMDocumentImpl::allocate(XMLSize_t amount)
00833 {
00834   //    Align the request size so that suballocated blocks
00835   //    beyond this one will be maintained at the same alignment.
00836   amount = XMLPlatformUtils::alignPointerForNewBlockAllocation(amount);
00837 
00838   // If the request is for a largish block, hand it off to the system
00839   //   allocator.  The block still must be linked into the list of
00840   //   allocated blocks so that it will be deleted when the time comes.
00841   if (amount > kMaxSubAllocationSize)
00842   {
00843     //  The size of the header we add to our raw blocks
00844     XMLSize_t sizeOfHeader = XMLPlatformUtils::alignPointerForNewBlockAllocation(sizeof(void *));
00845 
00846     //  Try to allocate the block
00847     void* newBlock;
00848     newBlock = fMemoryManager->allocate(sizeOfHeader + amount);
00849 
00850     //  Link it into the list beyond current block, as current block
00851     //  is still being subdivided. If there is no current block
00852     //  then track that we have no bytes to further divide.
00853     if (fCurrentBlock)
00854     {
00855       *(void **)newBlock = *(void **)fCurrentBlock;
00856       *(void **)fCurrentBlock = newBlock;
00857     }
00858     else
00859     {
00860       *(void **)newBlock = 0;
00861       fCurrentBlock = newBlock;
00862       fFreePtr = 0;
00863       fFreeBytesRemaining = 0;
00864     }
00865 
00866     void *retPtr = (char*)newBlock + sizeOfHeader;
00867     return retPtr;
00868   }
00869 
00870   //    It's a normal (sub-allocatable) request.
00871   //    Are we out of room in our current block?
00872   if (amount > fFreeBytesRemaining)
00873   {
00874     // Request doesn't fit in the current block.
00875     // The size of the header we add to our raw blocks
00876     XMLSize_t sizeOfHeader = XMLPlatformUtils::alignPointerForNewBlockAllocation(sizeof(void *));
00877 
00878     // Get a new block from the system allocator.
00879     void* newBlock;
00880     newBlock = fMemoryManager->allocate(fHeapAllocSize);
00881 
00882     *(void **)newBlock = fCurrentBlock;
00883     fCurrentBlock = newBlock;
00884     fFreePtr = (char *)newBlock + sizeOfHeader;
00885     fFreeBytesRemaining = fHeapAllocSize - sizeOfHeader;
00886 
00887     if(fHeapAllocSize<kMaxHeapAllocSize)
00888       fHeapAllocSize*=2;
00889   }
00890 
00891   //    Subdivide the request off current block
00892   void *retPtr = fFreePtr;
00893   fFreePtr += amount;
00894   fFreeBytesRemaining -= amount;
00895 
00896   return retPtr;
00897 }
00898 
00899 
00900 void DOMDocumentImpl::deleteHeap()
00901 {
00902     while (fCurrentBlock != 0)
00903     {
00904         void *nextBlock = *(void **)fCurrentBlock;
00905         fMemoryManager->deallocate(fCurrentBlock);
00906         fCurrentBlock = nextBlock;
00907     }
00908 }
00909 
00910 
00911 DOMNodeList *DOMDocumentImpl::getDeepNodeList(const DOMNode *rootNode, const XMLCh *tagName)
00912 {
00913     if(!fNodeListPool) {
00914         fNodeListPool = new (this) DOMDeepNodeListPool<DOMDeepNodeListImpl>(109, false);
00915     }
00916 
00917     DOMDeepNodeListImpl* retList = fNodeListPool->getByKey(rootNode, tagName, 0);
00918     if (!retList) {
00919         XMLSize_t id = fNodeListPool->put((void*) rootNode, (XMLCh*) tagName, 0, new (this) DOMDeepNodeListImpl(rootNode, tagName));
00920         retList = fNodeListPool->getById(id);
00921     }
00922 
00923     return retList;
00924 }
00925 
00926 
00927 DOMNodeList *DOMDocumentImpl::getDeepNodeList(const DOMNode *rootNode,     //DOM Level 2
00928                                                    const XMLCh *namespaceURI,
00929                                                    const XMLCh *localName)
00930 {
00931     if(!fNodeListPool) {
00932         fNodeListPool = new (this) DOMDeepNodeListPool<DOMDeepNodeListImpl>(109, false);
00933     }
00934 
00935     DOMDeepNodeListImpl* retList = fNodeListPool->getByKey(rootNode, localName, namespaceURI);
00936     if (!retList) {
00937         // the pool will adopt the DOMDeepNodeListImpl
00938         XMLSize_t id = fNodeListPool->put((void*) rootNode, (XMLCh*) localName, (XMLCh*) namespaceURI, new (this) DOMDeepNodeListImpl(rootNode, namespaceURI, localName));
00939         retList = fNodeListPool->getById(id);
00940     }
00941 
00942     return retList;
00943 }
00944 
00945 
00946 //Introduced in DOM Level 3
00947 const XMLCh* DOMDocumentImpl::getInputEncoding() const {
00948     return fInputEncoding;
00949 }
00950 
00951 void DOMDocumentImpl::setInputEncoding(const XMLCh* actualEncoding){
00952     fInputEncoding = cloneString(actualEncoding);
00953 }
00954 
00955 const XMLCh* DOMDocumentImpl::getXmlEncoding() const {
00956     return fXmlEncoding;
00957 }
00958 
00959 void DOMDocumentImpl::setXmlEncoding(const XMLCh* encoding){
00960     fXmlEncoding = cloneString(encoding);
00961 }
00962 
00963 bool DOMDocumentImpl::getXmlStandalone() const{
00964     return fXmlStandalone;
00965 }
00966 
00967 void DOMDocumentImpl::setXmlStandalone(bool standalone){
00968     fXmlStandalone = standalone;
00969 }
00970 
00971 const XMLCh* DOMDocumentImpl::getXmlVersion() const {
00972     return fXmlVersion;
00973 }
00974 
00975 void DOMDocumentImpl::setXmlVersion(const XMLCh* version){
00976 
00977     // store the static strings, so that comparisons will be faster
00978     if(version==0)
00979         fXmlVersion = 0;
00980     else if(*version==0)
00981         fXmlVersion = XMLUni::fgZeroLenString;
00982     else if(XMLString::equals(version, XMLUni::fgVersion1_0))
00983         fXmlVersion = XMLUni::fgVersion1_0;
00984     else if(XMLString::equals(version, XMLUni::fgVersion1_1))
00985         fXmlVersion = XMLUni::fgVersion1_1;
00986     else
00987         throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, getMemoryManager());
00988 }
00989 
00990 const XMLCh* DOMDocumentImpl::getDocumentURI() const
00991 {
00992     return fDocumentURI;
00993 }
00994 
00995 void DOMDocumentImpl::setDocumentURI(const XMLCh* documentURI){
00996     if (documentURI && *documentURI) {
00997         XMLCh* temp = (XMLCh*) this->allocate((XMLString::stringLen(documentURI) + 9)*sizeof(XMLCh));
00998         XMLString::fixURI(documentURI, temp);
00999         fDocumentURI = temp;
01000     }
01001     else
01002         fDocumentURI = 0;
01003 }
01004 
01005 bool DOMDocumentImpl::getStrictErrorChecking() const {
01006     return getErrorChecking();
01007 }
01008 
01009 void DOMDocumentImpl::setStrictErrorChecking(bool strictErrorChecking) {
01010     setErrorChecking(strictErrorChecking);
01011 }
01012 
01013 DOMNode* DOMDocumentImpl::adoptNode(DOMNode* sourceNode) {
01014     if(sourceNode->getOwnerDocument()!=this)
01015     {
01016         // cannot take ownership of a node created by another document, as it comes from its memory pool
01017         // and would be delete when the original document is deleted
01018         return 0;
01019     }
01020     // if the adopted node is already part of this document (i.e. the source and target document are the same),
01021     // this method still has the effect of removing the source node from the child list of its parent, if any
01022     switch(sourceNode->getNodeType())
01023     {
01024     case DOCUMENT_NODE:
01025     case DOCUMENT_TYPE_NODE:
01026         throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, getMemoryManager());
01027     case ATTRIBUTE_NODE:
01028         {
01029             DOMAttr* sourceAttr=(DOMAttr*)sourceNode;
01030             DOMElement* sourceAttrElem=sourceAttr->getOwnerElement();
01031             if(sourceAttrElem)
01032                 sourceAttrElem->removeAttributeNode(sourceAttr);
01033             fNode.callUserDataHandlers(DOMUserDataHandler::NODE_ADOPTED, sourceNode, sourceNode);
01034             break;
01035         }
01036     default:
01037         {
01038             DOMNode* sourceNodeParent=sourceNode->getParentNode();
01039             if(sourceNodeParent)
01040                 sourceNodeParent->removeChild(sourceNode);
01041             fNode.callUserDataHandlers(DOMUserDataHandler::NODE_ADOPTED, sourceNode, sourceNode);
01042         }
01043     }
01044     return 0;
01045 }
01046 
01047 void DOMDocumentImpl::normalizeDocument() {
01048 
01049     if(!fNormalizer)
01050         fNormalizer = new (fMemoryManager) DOMNormalizer(fMemoryManager);
01051 
01052     fNormalizer->normalizeDocument(this);
01053 }
01054 
01055 DOMConfiguration* DOMDocumentImpl::getDOMConfig() const {
01056     if(!fDOMConfiguration)
01057         ((DOMDocumentImpl*)this)->fDOMConfiguration = new ((DOMDocumentImpl*)this) DOMConfigurationImpl(fMemoryManager);
01058 
01059     return fDOMConfiguration;
01060 }
01061 
01062 DOMNode *DOMDocumentImpl::importNode(const DOMNode *source, bool deep, bool cloningDoc)
01063 {
01064     DOMNode *newnode=0;
01065     bool oldErrorCheckingFlag = errorChecking;
01066 
01067     switch (source->getNodeType())
01068     {
01069     case DOMNode::ELEMENT_NODE :
01070         {
01071             DOMElement *newelement;
01072             if (source->getLocalName() == 0)
01073                 newelement = createElement(source->getNodeName());
01074             else
01075             {
01076                 DOMElementNSImpl* nsElem = (DOMElementNSImpl*)createElementNS(source->getNamespaceURI(), source->getNodeName());
01077                 DOMTypeInfoImpl* clonedTypeInfo=NULL;
01078                 // if the source has type informations, copy them
01079                 DOMPSVITypeInfo* sourcePSVI=(DOMPSVITypeInfo*)source->getFeature(XMLUni::fgXercescInterfacePSVITypeInfo, 0);
01080                 if(sourcePSVI && sourcePSVI->getNumericProperty(DOMPSVITypeInfo::PSVI_Schema_Specified))
01081                     clonedTypeInfo=new (this) DOMTypeInfoImpl(this, sourcePSVI);
01082                 else
01083                 {
01084                     const DOMTypeInfo * typeInfo=((DOMElement*)source)->getSchemaTypeInfo();
01085                     // copy it only if it has valid data
01086                     if(typeInfo && typeInfo->getTypeName()!=NULL)
01087                         clonedTypeInfo=new (this) DOMTypeInfoImpl(typeInfo->getTypeNamespace(), typeInfo->getTypeName());
01088                 }
01089                 if(clonedTypeInfo)
01090                     nsElem->setSchemaTypeInfo(clonedTypeInfo);
01091                 newelement=nsElem;
01092             }
01093             DOMNamedNodeMap *srcattr=source->getAttributes();
01094             if(srcattr!=0)
01095                 for(XMLSize_t i=0;i<srcattr->getLength();++i)
01096                 {
01097                     DOMAttr *attr = (DOMAttr *) srcattr->item(i);
01098                     if (attr -> getSpecified() || cloningDoc) { // not a default attribute or we are in the process of cloning the elements from inside a DOMDocumentType
01099                         DOMAttr *nattr = (DOMAttr *) importNode(attr, true, cloningDoc);
01100                         if (attr -> getLocalName() == 0)
01101                             newelement->setAttributeNode(nattr);
01102                         else
01103                             newelement->setAttributeNodeNS(nattr);
01104 
01105                         // if the imported attribute is of ID type, register the new node in fNodeIDMap
01106                         if (attr->isId()) {
01107                             castToNodeImpl(nattr)->isIdAttr(true);
01108                             if (!fNodeIDMap)
01109                                  fNodeIDMap = new (this) DOMNodeIDMap(500, this);
01110                             fNodeIDMap->add((DOMAttr*)nattr);
01111                         }
01112                     }
01113                 }
01114             newnode=newelement;
01115 
01116         }
01117         break;
01118     case DOMNode::ATTRIBUTE_NODE :
01119         {
01120             DOMAttrImpl* newattr=NULL;
01121             if (source->getLocalName() == 0)
01122                 newattr = (DOMAttrImpl*)createAttribute(source->getNodeName());
01123             else {
01124                 newattr = (DOMAttrImpl*)createAttributeNS(source->getNamespaceURI(), source->getNodeName());
01125             }
01126             DOMTypeInfoImpl* clonedTypeInfo=NULL;
01127             // if the source has type informations, copy them
01128             DOMPSVITypeInfo* sourcePSVI=(DOMPSVITypeInfo*)source->getFeature(XMLUni::fgXercescInterfacePSVITypeInfo, 0);
01129             if(sourcePSVI && sourcePSVI->getNumericProperty(DOMPSVITypeInfo::PSVI_Schema_Specified))
01130                 clonedTypeInfo=new (this) DOMTypeInfoImpl(this, sourcePSVI);
01131             else
01132             {
01133                 const DOMTypeInfo * typeInfo=((DOMAttr*)source)->getSchemaTypeInfo();
01134                 // copy it only if it has valid data
01135                 if(typeInfo && typeInfo->getTypeName()!=NULL)
01136                     clonedTypeInfo=new (this) DOMTypeInfoImpl(typeInfo->getTypeNamespace(), typeInfo->getTypeName());
01137             }
01138             if(clonedTypeInfo)
01139                 newattr->setSchemaTypeInfo(clonedTypeInfo);
01140             newnode=newattr;
01141         }
01142         deep = true;
01143         // Kids carry value
01144 
01145         break;
01146     case DOMNode::TEXT_NODE :
01147         newnode = createTextNode(source->getNodeValue());
01148         break;
01149     case DOMNode::CDATA_SECTION_NODE :
01150         newnode = createCDATASection(source->getNodeValue());
01151         break;
01152     case DOMNode::ENTITY_REFERENCE_NODE :
01153         {
01154             DOMEntityReferenceImpl* newentityRef = (DOMEntityReferenceImpl*)createEntityReference(source->getNodeName());
01155             newnode=newentityRef;
01156             // Only the EntityReference itself is copied, even if a deep import is requested, since the source and
01157             // destination documents might have defined the entity differently.
01158             deep = false;
01159         }
01160         break;
01161     case DOMNode::ENTITY_NODE :
01162         {
01163             DOMEntity *srcentity=(DOMEntity *)source;
01164             DOMEntityImpl *newentity = (DOMEntityImpl *)createEntity(source->getNodeName());
01165             newentity->setPublicId(srcentity->getPublicId());
01166             newentity->setSystemId(srcentity->getSystemId());
01167             newentity->setNotationName(srcentity->getNotationName());
01168             newentity->setBaseURI(srcentity->getBaseURI());
01169             // Kids carry additional value
01170             newnode=newentity;
01171             castToNodeImpl(newentity)->setReadOnly(false, true);// allow deep import temporarily
01172         }
01173         break;
01174     case DOMNode::PROCESSING_INSTRUCTION_NODE :
01175         newnode = createProcessingInstruction(source->getNodeName(), source->getNodeValue());
01176         break;
01177     case DOMNode::COMMENT_NODE :
01178         newnode = createComment(source->getNodeValue());
01179         break;
01180     case DOMNode::DOCUMENT_TYPE_NODE :
01181         {
01182             // unless this is used as part of cloning a Document
01183             // forbid it for the sake of being compliant to the DOM spec
01184             if (!cloningDoc)
01185                 throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, getMemoryManager());
01186 
01187             DOMDocumentType *srcdoctype = (DOMDocumentType *)source;
01188             DOMDocumentTypeImpl *newdoctype = (DOMDocumentTypeImpl *)
01189                 createDocumentType(srcdoctype->getNodeName(),
01190                 srcdoctype->getPublicId(),
01191                 srcdoctype->getSystemId());
01192             // Values are on NamedNodeMaps
01193             DOMNamedNodeMap *smap = srcdoctype->getEntities();
01194             DOMNamedNodeMap *tmap = newdoctype->getEntities();
01195             if(smap != 0) {
01196                 for(XMLSize_t i = 0; i < smap->getLength(); i++) {
01197                     tmap->setNamedItem(importNode(smap->item(i), true, cloningDoc));
01198                 }
01199             }
01200             smap = srcdoctype->getNotations();
01201             tmap = newdoctype->getNotations();
01202             if (smap != 0) {
01203                 for(XMLSize_t i = 0; i < smap->getLength(); i++) {
01204                     tmap->setNamedItem(importNode(smap->item(i), true, cloningDoc));
01205                 }
01206             }
01207             const XMLCh* intSubset=srcdoctype->getInternalSubset();
01208             if(intSubset != 0) {
01209                 newdoctype->setInternalSubset(intSubset);
01210             }
01211 
01212             // detect if the DTD being copied is our own implementation, and use the provided methods
01213             try
01214             {
01215                 DOMDocumentTypeImpl* docTypeImpl=(DOMDocumentTypeImpl*)(srcdoctype->getFeature(XMLUni::fgXercescInterfaceDOMDocumentTypeImpl, XMLUni::fgZeroLenString));
01216                 if(docTypeImpl)
01217                 {
01218                     smap = docTypeImpl->getElements();
01219                     tmap = newdoctype->getElements();
01220                     if (smap != 0) {
01221                         for(XMLSize_t i = 0; i < smap->getLength(); i++) {
01222                             tmap->setNamedItem(importNode(smap->item(i), true, cloningDoc));
01223                         }
01224                     }
01225                 }
01226             } catch(DOMException&) {
01227             }
01228 
01229             newnode = newdoctype;
01230         }
01231         break;
01232     case DOMNode::DOCUMENT_FRAGMENT_NODE :
01233         newnode = createDocumentFragment();
01234         // No name, kids carry value
01235         break;
01236     case DOMNode::NOTATION_NODE :
01237         {
01238             DOMNotation *srcnotation=(DOMNotation *)source;
01239             DOMNotationImpl *newnotation = (DOMNotationImpl *)createNotation(source->getNodeName());
01240             newnotation->setPublicId(srcnotation->getPublicId());
01241             newnotation->setSystemId(srcnotation->getSystemId());
01242             newnotation->setBaseURI(srcnotation->getBaseURI());
01243             newnode=newnotation;
01244             // No name, no value
01245             break;
01246         }
01247 
01248     case DOMNode::DOCUMENT_NODE : // Document can't be child of Document
01249     default:                       // Unknown node type
01250         throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, getMemoryManager());
01251     }
01252 
01253     // If deep, replicate and attach the kids.
01254     if (deep)
01255         for (DOMNode *srckid = source->getFirstChild();
01256              srckid != 0;
01257              srckid = srckid->getNextSibling())
01258         {
01259             newnode->appendChild(importNode(srckid, true, cloningDoc));
01260         }
01261 
01262     if (newnode->getNodeType() == DOMNode::ENTITY_NODE) {
01263         castToNodeImpl(newnode)->setReadOnly(true, true);
01264         errorChecking = oldErrorCheckingFlag;
01265     }
01266 
01267     if (cloningDoc)
01268     {
01269         // we know for sure that the source node is a DOMNodeImpl, as cloningDoc is set to true when
01270         // a DOMDocumentImpl is cloned
01271         castToNodeImpl(source)->callUserDataHandlers(DOMUserDataHandler::NODE_CLONED, source, newnode);
01272     }
01273     else
01274         fNode.callUserDataHandlers(DOMUserDataHandler::NODE_IMPORTED, source, newnode);
01275 
01276     return newnode;
01277 }
01278 
01279 // user data utility
01280 void* DOMDocumentImpl::setUserData(DOMNodeImpl* n, const XMLCh* key, void* data, DOMUserDataHandler* handler)
01281 {
01282     void* oldData = 0;
01283     unsigned int keyId=fUserDataTableKeys.addOrFind(key);
01284 
01285     if (!fUserDataTable) {
01286         // create the table on heap so that it can be cleaned in destructor
01287         fUserDataTable = new (fMemoryManager) RefHash2KeysTableOf<DOMUserDataRecord, PtrHasher>
01288         (
01289             109
01290             , true
01291             , fMemoryManager
01292         );
01293     }
01294     else {
01295         DOMUserDataRecord* oldDataRecord = fUserDataTable->get((void*)n, keyId);
01296 
01297         if (oldDataRecord) {
01298             oldData = oldDataRecord->getKey();
01299             fUserDataTable->removeKey((void*)n, keyId);
01300         }
01301     }
01302 
01303     if (data) {
01304 
01305         // clone the key first, and create the DOMUserDataRecord
01306         // create on the heap and adopted by the hashtable which will delete it upon removal.
01307         fUserDataTable->put((void*)n, keyId, new (fMemoryManager) DOMUserDataRecord(data, handler));
01308     }
01309     else {
01310         RefHash2KeysTableOfEnumerator<DOMUserDataRecord, PtrHasher> enumKeys(fUserDataTable, false, fMemoryManager);
01311         enumKeys.setPrimaryKey(n);
01312         if (!enumKeys.hasMoreElements())
01313             n->hasUserData(false);
01314     }
01315 
01316     return oldData;
01317 }
01318 
01319 void* DOMDocumentImpl::getUserData(const DOMNodeImpl* n, const XMLCh* key) const
01320 {
01321     if (fUserDataTable) {
01322         unsigned int keyId=fUserDataTableKeys.getId(key);
01323         if(keyId!=0) {
01324             DOMUserDataRecord* dataRecord = fUserDataTable->get((void*)n, keyId);
01325             if (dataRecord)
01326                 return dataRecord->getKey();
01327         }
01328     }
01329 
01330     return 0;
01331 }
01332 
01333 void DOMDocumentImpl::callUserDataHandlers(const DOMNodeImpl* n, DOMUserDataHandler::DOMOperationType operation, const DOMNode* src, DOMNode* dst) const
01334 {
01335     if (fUserDataTable) {
01336         RefHash2KeysTableOfEnumerator<DOMUserDataRecord, PtrHasher> userDataEnum(fUserDataTable, false, fMemoryManager);
01337         userDataEnum.setPrimaryKey(n);
01338         // Create a snapshot of the handlers to be called, as the "handle" callback could be invalidating the enumerator by calling
01339         // setUserData on the dst node
01340         ValueVectorOf< int > snapshot(3, fMemoryManager);
01341         while (userDataEnum.hasMoreElements()) {
01342             // get the key
01343             void* key;
01344             int key2;
01345             userDataEnum.nextElementKey(key,key2);
01346             snapshot.addElement(key2);
01347         }
01348         ValueVectorEnumerator< int > snapshotEnum(&snapshot);
01349         while(snapshotEnum.hasMoreElements())
01350         {
01351             int key2=snapshotEnum.nextElement();
01352 
01353             // get the DOMUserDataRecord
01354             DOMUserDataRecord* userDataRecord = fUserDataTable->get((void*)n,key2);
01355 
01356             // get the handler
01357             DOMUserDataHandler* handler = userDataRecord->getValue();
01358 
01359             if (handler) {
01360                 // get the data
01361                 void* data = userDataRecord->getKey();
01362                 const XMLCh* userKey = fUserDataTableKeys.getValueForId(key2);
01363                 handler->handle(operation, userKey, data, src, dst);
01364             }
01365         }
01366         // if the operation is NODE_DELETED, we in fact should remove the data from the table
01367         if (operation == DOMUserDataHandler::NODE_DELETED)
01368             fUserDataTable->removeKey((void*)n);
01369     }
01370 }
01371 
01372 
01373 void DOMDocumentImpl::transferUserData(DOMNodeImpl* n1, DOMNodeImpl* n2)
01374 {
01375     if (fUserDataTable) {
01376         fUserDataTable->transferElement((void*)n1, (void*)n2);
01377         n1->hasUserData(false);
01378         n2->hasUserData(true);
01379     }
01380 }
01381 
01382 
01383 DOMNode* DOMDocumentImpl::renameNode(DOMNode* n, const XMLCh* namespaceURI, const XMLCh* name)
01384 {
01385     if (n->getOwnerDocument() != this)
01386         throw DOMException(DOMException::WRONG_DOCUMENT_ERR, 0, getMemoryManager());
01387 
01388     switch (n->getNodeType()) {
01389         case ELEMENT_NODE:
01390             return ((DOMElementImpl*)n)->rename(namespaceURI, name);
01391         case ATTRIBUTE_NODE:
01392             return ((DOMAttrImpl*)n)->rename(namespaceURI, name);
01393         default:
01394             break;
01395     }
01396     throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, getMemoryManager());
01397 
01398     return 0;
01399 }
01400 
01401 void DOMDocumentImpl::release()
01402 {
01403     DOMDocument* doc = (DOMDocument*) this;
01404     fNode.callUserDataHandlers(DOMUserDataHandler::NODE_DELETED, 0, 0);
01405 
01406     // notify userdatahandler first, if we have some
01407     if (fUserDataTable)
01408         releaseDocNotifyUserData(this);
01409 
01410     // release the docType in case it was created from heap
01411     if (fDocType) {
01412         castToNodeImpl(fDocType)->isToBeReleased(true);
01413         fDocType->release();
01414     }
01415 
01416     // delete the document memory pool
01417     delete doc;
01418 }
01419 
01420 void DOMDocumentImpl::releaseDocNotifyUserData(DOMNode* object)
01421 {
01422     DOMNode *child = object->getFirstChild();
01423 
01424     while( child != 0)
01425     {
01426 
01427          DOMNamedNodeMap *attrlist=child->getAttributes();
01428 
01429          if(attrlist!=0)
01430              for(XMLSize_t i=0;i<attrlist->getLength();++i)
01431                  releaseDocNotifyUserData(attrlist->item(i));
01432 
01433         releaseDocNotifyUserData(child);
01434         child = child->getNextSibling();
01435     }
01436 
01437     castToNodeImpl(object)->callUserDataHandlers(DOMUserDataHandler::NODE_DELETED, 0, 0);
01438 }
01439 
01440 void DOMDocumentImpl::release(DOMNode* object, DOMMemoryManager::NodeObjectType type)
01441 {
01442     if (!fRecycleNodePtr)
01443         fRecycleNodePtr = new (fMemoryManager) RefArrayOf<DOMNodePtr> (15, fMemoryManager);
01444 
01445     if (!fRecycleNodePtr->operator[](type))
01446         fRecycleNodePtr->operator[](type) = new (fMemoryManager) RefStackOf<DOMNode> (15, false, fMemoryManager);
01447 
01448     fRecycleNodePtr->operator[](type)->push(object);
01449 }
01450 
01451 void DOMDocumentImpl::releaseBuffer(DOMBuffer* buffer)
01452 {
01453     if (!fRecycleBufferPtr)
01454         fRecycleBufferPtr = new (fMemoryManager) RefStackOf<DOMBuffer> (15, false, fMemoryManager);
01455 
01456     fRecycleBufferPtr->push(buffer);
01457 }
01458 
01459 DOMBuffer* DOMDocumentImpl::popBuffer(XMLSize_t nMinSize)
01460 {
01461     if (!fRecycleBufferPtr || fRecycleBufferPtr->empty())
01462         return 0;
01463 
01464     for(XMLSize_t index=fRecycleBufferPtr->size()-1;index>0;index--)
01465         if(fRecycleBufferPtr->elementAt(index)->getCapacity()>=nMinSize)
01466             return fRecycleBufferPtr->popAt(index);
01467     // if we didn't find a buffer big enough, get the last one
01468     return fRecycleBufferPtr->pop();
01469 }
01470 
01471 
01472 void * DOMDocumentImpl::allocate(XMLSize_t amount, DOMMemoryManager::NodeObjectType type)
01473 {
01474     if (!fRecycleNodePtr)
01475         return allocate(amount);
01476 
01477     DOMNodePtr* ptr = fRecycleNodePtr->operator[](type);
01478     if (!ptr || ptr->empty())
01479         return allocate(amount);
01480 
01481     return (void*) ptr->pop();
01482 
01483 }
01484 
01485 bool DOMDocumentImpl::isSupported(const XMLCh *feature, const XMLCh *version) const
01486 {
01487     // check for '+DOMMemoryManager'
01488     if(feature && *feature=='+' && XMLString::equals(feature+1, XMLUni::fgXercescInterfaceDOMMemoryManager))
01489         return true;
01490     if(feature && *feature)
01491     {
01492         if((*feature==chPlus && XMLString::equals(feature+1, XMLUni::fgXercescInterfaceDOMDocumentImpl)) ||
01493            XMLString::equals(feature, XMLUni::fgXercescInterfaceDOMDocumentImpl))
01494             return true;
01495     }
01496     return fNode.isSupported (feature, version);
01497 }
01498 
01499 void* DOMDocumentImpl::getFeature(const XMLCh* feature, const XMLCh* version) const
01500 {
01501     if(XMLString::equals(feature, XMLUni::fgXercescInterfaceDOMMemoryManager))
01502         return (DOMMemoryManager*)this;
01503     if(XMLString::equals(feature, XMLUni::fgXercescInterfaceDOMDocumentImpl))
01504         return (DOMDocumentImpl*)this;
01505     return fNode.getFeature(feature,version);
01506 }
01507 
01508 
01509 XERCES_CPP_NAMESPACE_END