GME
13
|
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