source: icXML/icXML-devel/src/xercesc/dom/impl/DOMDocumentImpl.cpp @ 2722

Last change on this file since 2722 was 2722, checked in by cameron, 6 years ago

Original Xerces files with import mods for icxercesc

File size: 51.3 KB
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/*
19 * $Id: DOMDocumentImpl.cpp 932949 2010-04-11 17:40:33Z borisk $
20 */
21#include "DOMDocumentImpl.hpp"
22#include "DOMCasts.hpp"
23#include "DOMConfigurationImpl.hpp"
24#include "DOMDocumentTypeImpl.hpp"
25#include "DOMAttrImpl.hpp"
26#include "DOMAttrNSImpl.hpp"
27#include "DOMCDATASectionImpl.hpp"
28#include "DOMCommentImpl.hpp"
29#include "DOMDeepNodeListImpl.hpp"
30#include "DOMDocumentFragmentImpl.hpp"
31#include "DOMElementImpl.hpp"
32#include "XSDElementNSImpl.hpp"
33#include "DOMEntityImpl.hpp"
34#include "DOMEntityReferenceImpl.hpp"
35#include "DOMNormalizer.hpp"
36#include "DOMNotationImpl.hpp"
37#include "DOMProcessingInstructionImpl.hpp"
38#include "DOMTextImpl.hpp"
39#include "DOMTreeWalkerImpl.hpp"
40#include "DOMNodeIteratorImpl.hpp"
41#include "DOMNodeIDMap.hpp"
42#include "DOMRangeImpl.hpp"
43#include "DOMTypeInfoImpl.hpp"
44#include "DOMXPathExpressionImpl.hpp"
45#include "DOMXPathNSResolverImpl.hpp"
46
47#include <xercesc/dom/DOMImplementation.hpp>
48#include <xercesc/framework/MemoryManager.hpp>
49#include <xercesc/util/OutOfMemoryException.hpp>
50#include <xercesc/util/XMLInitializer.hpp>
51#include <xercesc/util/Janitor.hpp>
52
53XERCES_CPP_NAMESPACE_BEGIN
54
55// The chunk size to allocate from the system allocator.
56static XMLSize_t kInitialHeapAllocSize =  0x4000;
57static XMLSize_t kMaxHeapAllocSize     = 0x80000;
58static XMLSize_t kMaxSubAllocationSize =  0x0100;  // Any request for more bytes
59                                                   // than this will be handled by
60                                                   // allocating directly with system.
61
62void XMLInitializer::initializeDOMHeap (XMLSize_t initialHeapAllocSize,
63                                        XMLSize_t maxHeapAllocSize,
64                                        XMLSize_t maxSubAllocationSize)
65{
66  kInitialHeapAllocSize = initialHeapAllocSize;
67  kMaxHeapAllocSize = maxHeapAllocSize;
68  kMaxSubAllocationSize = maxSubAllocationSize;
69}
70
71//
72//   Constructors.   Warning - be very careful with the ordering of initialization
73//                             of the heap.  Ordering depends on the order of declaration
74//                             in the .hpp file, not on the order of initializers here
75//                             in the constructor.  The heap declaration can not be
76//                             first - fNode and fParent must be first for the casting
77//                             functions in DOMCasts to work correctly.  This means that
78//                             fNode and fParent constructors used here can not
79//                             allocate.
80//
81DOMDocumentImpl::DOMDocumentImpl(DOMImplementation* domImpl, MemoryManager* const manager)
82    : fNode(this),
83      fParent(this),
84      fNodeIDMap(0),
85      fInputEncoding(0),
86      fXmlEncoding(0),
87      fXmlStandalone(false),
88      fXmlVersion(0),
89      fDocumentURI(0),
90      fDOMConfiguration(0),
91      fUserDataTableKeys(17, manager),
92      fUserDataTable(0),
93      fCurrentBlock(0),
94      fFreePtr(0),
95      fFreeBytesRemaining(0),
96      fHeapAllocSize(kInitialHeapAllocSize),
97      fRecycleNodePtr(0),
98      fRecycleBufferPtr(0),
99      fNodeListPool(0),
100      fDocType(0),
101      fDocElement(0),
102      fNameTableSize(257),
103      fNormalizer(0),
104      fRanges(0),
105      fNodeIterators(0),
106      fMemoryManager(manager),
107      fDOMImplementation(domImpl),
108      fChanges(0),
109      errorChecking(true)
110{
111    fNameTable = (DOMStringPoolEntry**)allocate (
112      sizeof (DOMStringPoolEntry*) * fNameTableSize);
113    for (XMLSize_t i = 0; i < fNameTableSize; i++)
114      fNameTable[i] = 0;
115}
116
117
118//DOM Level 2
119DOMDocumentImpl::DOMDocumentImpl(const XMLCh *fNamespaceURI,
120                               const XMLCh *qualifiedName,
121                               DOMDocumentType *doctype,
122                               DOMImplementation* domImpl,
123                               MemoryManager* const manager)
124    : fNode(this),
125      fParent(this),
126      fNodeIDMap(0),
127      fInputEncoding(0),
128      fXmlEncoding(0),
129      fXmlStandalone(false),
130      fXmlVersion(0),
131      fDocumentURI(0),
132      fDOMConfiguration(0),
133      fUserDataTableKeys(17, manager),
134      fUserDataTable(0),
135      fCurrentBlock(0),
136      fFreePtr(0),
137      fFreeBytesRemaining(0),
138      fHeapAllocSize(kInitialHeapAllocSize),
139      fRecycleNodePtr(0),
140      fRecycleBufferPtr(0),
141      fNodeListPool(0),
142      fDocType(0),
143      fDocElement(0),
144      fNameTableSize(257),
145      fNormalizer(0),
146      fRanges(0),
147      fNodeIterators(0),
148      fMemoryManager(manager),
149      fDOMImplementation(domImpl),
150      fChanges(0),
151      errorChecking(true)
152{
153    fNameTable = (DOMStringPoolEntry**)allocate (
154      sizeof (DOMStringPoolEntry*) * fNameTableSize);
155    for (XMLSize_t i = 0; i < fNameTableSize; i++)
156      fNameTable[i] = 0;
157
158    try {
159        setDocumentType(doctype);
160
161        if (qualifiedName)
162            appendChild(createElementNS(fNamespaceURI, qualifiedName));  //root element
163        else if (fNamespaceURI)
164            throw DOMException(DOMException::NAMESPACE_ERR, 0, getMemoryManager());
165    }
166    catch(const OutOfMemoryException&)
167    {
168        throw;
169    }
170    catch (...) {
171        this->deleteHeap();
172        throw;
173    }
174}
175
176void DOMDocumentImpl::setDocumentType(DOMDocumentType *doctype)
177{
178    if (!doctype)
179        return;
180
181    // New doctypes can be created either with the factory methods on DOMImplementation, in
182    //   which case ownerDocument will be 0, or with methods on DocumentImpl, in which case
183    //   ownerDocument will be set, but the DocType won't yet be a child of the document.
184    //
185    DOMDocument* doc = doctype->getOwnerDocument();
186    if (doc != 0 && doc != this)
187        throw DOMException(    //one doctype can belong to only one DOMDocumentImpl
188        DOMException::WRONG_DOCUMENT_ERR, 0, getMemoryManager());
189
190    DOMDocumentTypeImpl* doctypeImpl = (DOMDocumentTypeImpl*) doctype;
191    doctypeImpl->setOwnerDocument(this);
192
193    // The doctype can not have any Entities or Notations yet, because they can not
194    //   be created except through factory methods on a document.
195
196    // revisit.  What if this doctype is already a child of the document?
197    appendChild(doctype);
198
199}
200
201DOMDocumentImpl::~DOMDocumentImpl()
202{
203    // While DOMConfiguration is allocated on the Document's heap, itself
204    // it uses the memory manager directly. This means that while we cannot
205    // delete with operator delete, we need to call its d-tor.
206    //
207    if (fDOMConfiguration)
208      fDOMConfiguration->~DOMConfiguration ();
209
210    //  Clean up the fNodeListPool
211    if (fNodeListPool)
212        fNodeListPool->cleanup();
213
214    if (fRanges)
215        delete fRanges; //fRanges->cleanup();
216
217    if (fNodeIterators)
218        delete fNodeIterators;//fNodeIterators->cleanup();
219
220    if (fUserDataTable)
221        delete fUserDataTable;//fUserDataTable->cleanup();
222
223    if (fRecycleNodePtr) {
224        fRecycleNodePtr->deleteAllElements();
225        delete fRecycleNodePtr;
226    }
227
228    if (fRecycleBufferPtr) {
229        delete fRecycleBufferPtr;
230    }
231
232    delete fNormalizer;
233
234    //  Delete the heap for this document.  This uncerimoniously yanks the storage
235    //      out from under all of the nodes in the document.  Destructors are NOT called.
236    this->deleteHeap();
237}
238
239
240DOMNode *DOMDocumentImpl::cloneNode(bool deep) const {
241
242    // Note:  the cloned document node goes on the same heap we live in.
243    DOMDocumentImpl *newdoc = new (fMemoryManager) DOMDocumentImpl(fDOMImplementation, fMemoryManager);
244    if(fXmlEncoding && *fXmlEncoding)
245        newdoc->setXmlEncoding(fXmlEncoding);
246    if(fXmlVersion && *fXmlVersion)
247        newdoc->setXmlVersion(fXmlVersion);
248    newdoc->setXmlStandalone(fXmlStandalone);
249
250    // then the children by _importing_ them
251    if (deep)
252        for (DOMNode *n = this->getFirstChild(); n != 0; n = n->getNextSibling()) {
253            newdoc->appendChild(newdoc->importNode(n, true, true));
254    }
255
256    fNode.callUserDataHandlers(DOMUserDataHandler::NODE_CLONED, this, newdoc);
257    return newdoc;
258}
259
260
261const XMLCh * DOMDocumentImpl::getNodeName() const {
262    static const XMLCh nam[] =  // "#document"
263        {chPound, chLatin_d, chLatin_o, chLatin_c, chLatin_u, chLatin_m, chLatin_e, chLatin_n, chLatin_t, 0};
264    return nam;
265}
266
267
268DOMNode::NodeType DOMDocumentImpl::getNodeType() const {
269    return DOMNode::DOCUMENT_NODE;
270}
271
272
273// even though ownerDocument refers to this in this implementation
274// the DOM Level 2 spec says it must be 0, so make it appear so
275DOMDocument * DOMDocumentImpl::getOwnerDocument() const {
276    return 0;
277}
278
279
280DOMAttr *DOMDocumentImpl::createAttribute(const XMLCh *nam)
281{
282    if(!nam || !isXMLName(nam))
283        throw DOMException(DOMException::INVALID_CHARACTER_ERR,0, getMemoryManager());
284    return new (this, DOMMemoryManager::ATTR_OBJECT) DOMAttrImpl(this,nam);
285}
286
287
288
289DOMCDATASection *DOMDocumentImpl::createCDATASection(const XMLCh *data) {
290    return new (this, DOMMemoryManager::CDATA_SECTION_OBJECT) DOMCDATASectionImpl(this,data);
291}
292
293
294
295DOMComment *DOMDocumentImpl::createComment(const XMLCh *data)
296{
297    return new (this, DOMMemoryManager::COMMENT_OBJECT) DOMCommentImpl(this, data);
298}
299
300
301
302DOMDocumentFragment *DOMDocumentImpl::createDocumentFragment()
303{
304    return new (this, DOMMemoryManager::DOCUMENT_FRAGMENT_OBJECT) DOMDocumentFragmentImpl(this);
305}
306
307
308
309DOMDocumentType *DOMDocumentImpl::createDocumentType(const XMLCh *nam)
310{
311    if (!nam || !isXMLName(nam))
312        throw DOMException(
313        DOMException::INVALID_CHARACTER_ERR, 0, getMemoryManager());
314
315    return new (this, DOMMemoryManager::DOCUMENT_TYPE_OBJECT) DOMDocumentTypeImpl(this, nam, false);
316}
317
318
319
320DOMDocumentType *
321    DOMDocumentImpl::createDocumentType(const XMLCh *qualifiedName,
322                                     const XMLCh *publicId,
323                                     const XMLCh *systemId)
324{
325    if (!qualifiedName || !isXMLName(qualifiedName))
326        throw DOMException(
327        DOMException::INVALID_CHARACTER_ERR, 0, getMemoryManager());
328
329    return new (this, DOMMemoryManager::DOCUMENT_TYPE_OBJECT) DOMDocumentTypeImpl(this, qualifiedName, publicId, systemId, false);
330}
331
332
333
334DOMElement *DOMDocumentImpl::createElement(const XMLCh *tagName)
335{
336    if(!tagName || !isXMLName(tagName))
337        throw DOMException(DOMException::INVALID_CHARACTER_ERR,0, getMemoryManager());
338
339    return new (this, DOMMemoryManager::ELEMENT_OBJECT) DOMElementImpl(this,tagName);
340}
341
342
343DOMElement *DOMDocumentImpl::createElementNoCheck(const XMLCh *tagName)
344{
345    return new (this, DOMMemoryManager::ELEMENT_OBJECT) DOMElementImpl(this, tagName);
346}
347
348
349
350
351DOMEntity *DOMDocumentImpl::createEntity(const XMLCh *nam)
352{
353    if (!nam || !isXMLName(nam))
354        throw DOMException(
355        DOMException::INVALID_CHARACTER_ERR, 0, getMemoryManager());
356
357    return new (this, DOMMemoryManager::ENTITY_OBJECT) DOMEntityImpl(this, nam);
358}
359
360
361
362DOMEntityReference *DOMDocumentImpl::createEntityReference(const XMLCh *nam)
363{
364    if (!nam || !isXMLName(nam))
365        throw DOMException(
366        DOMException::INVALID_CHARACTER_ERR, 0, getMemoryManager());
367
368    return new (this, DOMMemoryManager::ENTITY_REFERENCE_OBJECT) DOMEntityReferenceImpl(this, nam);
369}
370
371DOMEntityReference *DOMDocumentImpl::createEntityReferenceByParser(const XMLCh *nam)
372{
373    if (!nam || !isXMLName(nam))
374        throw DOMException(
375        DOMException::INVALID_CHARACTER_ERR, 0, getMemoryManager());
376
377    return new (this, DOMMemoryManager::ENTITY_REFERENCE_OBJECT) DOMEntityReferenceImpl(this, nam, false);
378}
379
380DOMNotation *DOMDocumentImpl::createNotation(const XMLCh *nam)
381{
382    if (!nam || !isXMLName(nam))
383        throw DOMException(
384        DOMException::INVALID_CHARACTER_ERR, 0, getMemoryManager());
385
386    return new (this, DOMMemoryManager::NOTATION_OBJECT) DOMNotationImpl(this, nam);
387}
388
389
390
391DOMProcessingInstruction *DOMDocumentImpl::createProcessingInstruction(
392                                          const XMLCh *target, const XMLCh *data)
393{
394    if(!target || !isXMLName(target))
395        throw DOMException(DOMException::INVALID_CHARACTER_ERR,0, getMemoryManager());
396    return new (this, DOMMemoryManager::PROCESSING_INSTRUCTION_OBJECT) DOMProcessingInstructionImpl(this,target,data);
397}
398
399
400
401
402DOMText *DOMDocumentImpl::createTextNode(const XMLCh *data)
403{
404    return new (this, DOMMemoryManager::TEXT_OBJECT) DOMTextImpl(this,data);
405}
406
407
408DOMNodeIterator* DOMDocumentImpl::createNodeIterator (
409  DOMNode *root,
410  DOMNodeFilter::ShowType whatToShow,
411  DOMNodeFilter* filter,
412  bool entityReferenceExpansion)
413{
414    if (!root) {
415        throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, getMemoryManager());
416        return 0;
417    }
418
419    DOMNodeIteratorImpl* nodeIterator = new (this) DOMNodeIteratorImpl(this, root, whatToShow, filter, entityReferenceExpansion);
420
421    if (fNodeIterators == 0L) {
422        //fNodeIterators = new (this) NodeIterators(1, false);
423        fNodeIterators = new (fMemoryManager) NodeIterators(1, false, fMemoryManager);
424    }
425    fNodeIterators->addElement(nodeIterator);
426
427    return nodeIterator;
428}
429
430
431NodeIterators* DOMDocumentImpl::getNodeIterators() const
432{
433    return fNodeIterators;
434}
435
436void DOMDocumentImpl::removeNodeIterator(DOMNodeIteratorImpl* nodeIterator)
437{
438    if (fNodeIterators != 0) {
439        XMLSize_t sz = fNodeIterators->size();
440        if (sz !=0) {
441            for (XMLSize_t i =0; i<sz; i++) {
442                if (fNodeIterators->elementAt(i) == nodeIterator) {
443                    fNodeIterators->removeElementAt(i);
444                    break;
445                }
446            }
447        }
448    }
449}
450
451
452DOMXPathExpression* DOMDocumentImpl::createExpression(const XMLCh * expression, const DOMXPathNSResolver *resolver)
453{
454    return new (getMemoryManager()) DOMXPathExpressionImpl(expression, resolver, getMemoryManager());
455}
456
457DOMXPathNSResolver* DOMDocumentImpl::createNSResolver(const DOMNode *nodeResolver)
458{
459    return new (getMemoryManager()) DOMXPathNSResolverImpl(nodeResolver, getMemoryManager());
460}
461
462DOMXPathResult* DOMDocumentImpl::evaluate(const XMLCh *expression,
463                                          const DOMNode *contextNode,
464                                          const DOMXPathNSResolver *resolver,
465                                          DOMXPathResult::ResultType type,
466                                          DOMXPathResult* result)
467{
468    JanitorMemFunCall<DOMXPathExpression> expr(
469      createExpression(expression, resolver),
470      &DOMXPathExpression::release);
471    return expr->evaluate(contextNode, type, result);
472}
473
474
475
476DOMTreeWalker* DOMDocumentImpl::createTreeWalker (
477  DOMNode *root,
478  DOMNodeFilter::ShowType whatToShow,
479  DOMNodeFilter* filter,
480  bool entityReferenceExpansion)
481{
482    if (!root) {
483        throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, getMemoryManager());
484        return 0;
485    }
486
487    return new (this) DOMTreeWalkerImpl(root, whatToShow, filter, entityReferenceExpansion);
488}
489
490
491
492
493DOMDocumentType *DOMDocumentImpl::getDoctype() const
494{
495    return fDocType;
496}
497
498
499
500DOMElement *DOMDocumentImpl::getDocumentElement() const
501{
502    return fDocElement;
503}
504
505
506
507DOMNodeList *DOMDocumentImpl::getElementsByTagName(const XMLCh *tagname) const
508{
509    // cast off the const of this because we will update the fNodeListPool
510    return ((DOMDocumentImpl*)this)->getDeepNodeList(this,tagname);
511}
512
513
514DOMImplementation   *DOMDocumentImpl::getImplementation() const {
515
516    return fDOMImplementation;
517}
518
519
520DOMNode *DOMDocumentImpl::insertBefore(DOMNode *newChild, DOMNode *refChild)
521{
522    // Only one such child permitted
523    if(
524        (newChild->getNodeType() == DOMNode::ELEMENT_NODE  && fDocElement!=0)
525        ||
526        (newChild->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE  && fDocType!=0)
527        )
528        throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0, getMemoryManager());
529
530    // if the newChild is a documenttype node created from domimplementation, set the ownerDoc first
531    if ((newChild->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE) && !newChild->getOwnerDocument())
532        ((DOMDocumentTypeImpl*)newChild)->setOwnerDocument(this);
533
534    fParent.insertBefore(newChild,refChild);
535
536    // If insert succeeded, cache the kid appropriately
537    if(newChild->getNodeType() == DOMNode::ELEMENT_NODE)
538        fDocElement=(DOMElement *)newChild;
539    else if(newChild->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE)
540        fDocType=(DOMDocumentType *)newChild;
541
542    return newChild;
543}
544
545
546DOMNode* DOMDocumentImpl::replaceChild(DOMNode *newChild, DOMNode *oldChild) {
547    DOMDocumentType* tempDocType = fDocType;
548    DOMElement* tempDocElement = fDocElement;
549
550    if(oldChild->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE)
551        fDocType=0;
552    else if(oldChild->getNodeType() == DOMNode::ELEMENT_NODE)
553        fDocElement=0;
554
555    try {
556        insertBefore(newChild, oldChild);
557        // changed() already done.
558
559        if((oldChild->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE)
560        || (oldChild->getNodeType() == DOMNode::ELEMENT_NODE))
561            return fParent.removeChild(oldChild);
562        else
563            return removeChild(oldChild);
564    }
565    catch(const OutOfMemoryException&)
566    {
567        throw;
568    }
569    catch(...) {
570        fDocType = tempDocType;
571        fDocElement = tempDocElement;
572        throw;
573    }
574}
575
576bool DOMDocumentImpl::isXMLName(const XMLCh *s)
577{
578    // fXmlVersion points directly to the static constants
579    if (fXmlVersion==XMLUni::fgVersion1_1)
580        return XMLChar1_1::isValidName(s);
581    else
582        return XMLChar1_0::isValidName(s);
583}
584
585
586
587
588DOMNode *DOMDocumentImpl::removeChild(DOMNode *oldChild)
589{
590    fParent.removeChild(oldChild);
591
592    // If remove succeeded, un-cache the kid appropriately
593    if(oldChild->getNodeType() == DOMNode::ELEMENT_NODE)
594        fDocElement=0;
595    else if(oldChild->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE)
596        fDocType=0;
597
598    return oldChild;
599}
600
601
602
603void DOMDocumentImpl::setNodeValue(const XMLCh *x)
604{
605    fNode.setNodeValue(x);
606}
607
608
609//Introduced in DOM Level 2
610DOMNode *DOMDocumentImpl::importNode(const DOMNode *source, bool deep)
611{
612    return importNode(source, deep, false);
613}
614
615
616DOMElement *DOMDocumentImpl::createElementNS(const XMLCh *fNamespaceURI,
617                                             const XMLCh *qualifiedName)
618{
619    if(!qualifiedName || !isXMLName(qualifiedName))
620        throw DOMException(DOMException::INVALID_CHARACTER_ERR,0, getMemoryManager());
621
622    return new (this, DOMMemoryManager::ELEMENT_NS_OBJECT) DOMElementNSImpl(this, fNamespaceURI, qualifiedName);
623}
624
625DOMElement *DOMDocumentImpl::createElementNS(const XMLCh *fNamespaceURI,
626                                              const XMLCh *qualifiedName,
627                                              const XMLFileLoc lineNo,
628                                              const XMLFileLoc columnNo)
629{
630    if(!qualifiedName || !isXMLName(qualifiedName))
631        throw DOMException(DOMException::INVALID_CHARACTER_ERR,0, getMemoryManager());
632
633    return new (this) XSDElementNSImpl(this, fNamespaceURI, qualifiedName, lineNo, columnNo);
634}
635
636
637DOMAttr *DOMDocumentImpl::createAttributeNS(const XMLCh *fNamespaceURI,
638    const XMLCh *qualifiedName)
639{
640    if(!qualifiedName || !isXMLName(qualifiedName))
641        throw DOMException(DOMException::INVALID_CHARACTER_ERR,0, getMemoryManager());
642    return new (this, DOMMemoryManager::ATTR_NS_OBJECT) DOMAttrNSImpl(this, fNamespaceURI, qualifiedName);
643}
644
645
646DOMNodeList *DOMDocumentImpl::getElementsByTagNameNS(const XMLCh *fNamespaceURI,
647    const XMLCh *fLocalName)  const
648{
649    // cast off the const of this because we will update the fNodeListPool
650    return ((DOMDocumentImpl*)this)->getDeepNodeList(this, fNamespaceURI, fLocalName);
651}
652
653
654DOMElement *DOMDocumentImpl::getElementById(const XMLCh *elementId) const
655{
656    if (fNodeIDMap == 0)
657        return 0;
658
659    DOMAttr *theAttr = fNodeIDMap->find(elementId);
660    if (theAttr == 0)
661        return 0;
662
663    return theAttr->getOwnerElement();
664}
665
666const XMLCh* DOMDocumentImpl::getBaseURI() const
667{
668          return fDocumentURI;
669}
670
671DOMRange* DOMDocumentImpl::createRange()
672{
673
674    DOMRangeImpl* range = new (this) DOMRangeImpl(this, fMemoryManager);
675
676    if (fRanges == 0L) {
677        //fRanges = new (this) Ranges(1, false);
678        fRanges = new (fMemoryManager) Ranges(1, false, fMemoryManager); // XMemory
679    }
680    fRanges->addElement(range);
681    return range;
682}
683
684Ranges* DOMDocumentImpl::getRanges() const
685{
686    return fRanges;
687}
688
689void DOMDocumentImpl::removeRange(DOMRangeImpl* range)
690{
691    if (fRanges != 0) {
692        XMLSize_t sz = fRanges->size();
693        if (sz !=0) {
694            for (XMLSize_t i =0; i<sz; i++) {
695                if (fRanges->elementAt(i) == range) {
696                    fRanges->removeElementAt(i);
697                    break;
698                }
699            }
700        }
701    }
702}
703
704/** Uses the kidOK lookup table to check whether the proposed
705    tree structure is legal.
706
707    ????? It feels like there must be a more efficient solution,
708    but for the life of me I can't think what it would be.
709*/
710bool DOMDocumentImpl::isKidOK(DOMNode *parent, DOMNode *child)
711{
712      static int kidOK[14];
713
714      if (kidOK[DOMNode::ATTRIBUTE_NODE] == 0)
715      {
716          kidOK[DOMNode::DOCUMENT_NODE] =
717              1 << DOMNode::ELEMENT_NODE |
718              1 << DOMNode::PROCESSING_INSTRUCTION_NODE |
719              1 << DOMNode::COMMENT_NODE |
720              1 << DOMNode::DOCUMENT_TYPE_NODE;
721
722          kidOK[DOMNode::DOCUMENT_FRAGMENT_NODE] =
723              kidOK[DOMNode::ENTITY_NODE] =
724              kidOK[DOMNode::ENTITY_REFERENCE_NODE] =
725              kidOK[DOMNode::ELEMENT_NODE] =
726              1 << DOMNode::ELEMENT_NODE |
727              1 << DOMNode::PROCESSING_INSTRUCTION_NODE |
728              1 << DOMNode::COMMENT_NODE |
729              1 << DOMNode::TEXT_NODE |
730              1 << DOMNode::CDATA_SECTION_NODE |
731              1 << DOMNode::ENTITY_REFERENCE_NODE;
732
733          kidOK[DOMNode::ATTRIBUTE_NODE] =
734              1 << DOMNode::TEXT_NODE |
735              1 << DOMNode::ENTITY_REFERENCE_NODE;
736
737          kidOK[DOMNode::PROCESSING_INSTRUCTION_NODE] =
738              kidOK[DOMNode::COMMENT_NODE] =
739              kidOK[DOMNode::TEXT_NODE] =
740              kidOK[DOMNode::CDATA_SECTION_NODE] =
741              kidOK[DOMNode::NOTATION_NODE] =
742              0;
743      }
744      int p=parent->getNodeType();
745      int ch = child->getNodeType();
746      return ((kidOK[p] & 1<<ch) != 0) ||
747             (p==DOMNode::DOCUMENT_NODE && ch==DOMNode::TEXT_NODE &&
748              ((XMLString::equals(((DOMDocument*)parent)->getXmlVersion(), XMLUni::fgVersion1_1))?
749                    XMLChar1_1::isAllSpaces(child->getNodeValue(), XMLString::stringLen(child->getNodeValue())):
750                    XMLChar1_0::isAllSpaces(child->getNodeValue(), XMLString::stringLen(child->getNodeValue())))
751             );
752}
753
754void            DOMDocumentImpl::changed()
755{
756    fChanges++;
757}
758
759
760int             DOMDocumentImpl::changes() const{
761    return fChanges;
762}
763
764
765
766//
767//    Delegation for functions inherited from DOMNode
768//
769           DOMNode*         DOMDocumentImpl::appendChild(DOMNode *newChild)          {return insertBefore(newChild, 0); }
770           DOMNamedNodeMap* DOMDocumentImpl::getAttributes() const                   {return fNode.getAttributes (); }
771           DOMNodeList*     DOMDocumentImpl::getChildNodes() const                   {return fParent.getChildNodes (); }
772           DOMNode*         DOMDocumentImpl::getFirstChild() const                   {return fParent.getFirstChild (); }
773           DOMNode*         DOMDocumentImpl::getLastChild() const                    {return fParent.getLastChild (); }
774     const XMLCh*           DOMDocumentImpl::getLocalName() const                    {return fNode.getLocalName (); }
775     const XMLCh*           DOMDocumentImpl::getNamespaceURI() const                 {return fNode.getNamespaceURI (); }
776           DOMNode*         DOMDocumentImpl::getNextSibling() const                  {return fNode.getNextSibling (); }
777     const XMLCh*           DOMDocumentImpl::getNodeValue() const                    {return fNode.getNodeValue (); }
778     const XMLCh*           DOMDocumentImpl::getPrefix() const                       {return fNode.getPrefix (); }
779           DOMNode*         DOMDocumentImpl::getParentNode() const                   {return fNode.getParentNode (); }
780           DOMNode*         DOMDocumentImpl::getPreviousSibling() const              {return fNode.getPreviousSibling (); }
781           bool             DOMDocumentImpl::hasChildNodes() const                   {return fParent.hasChildNodes (); }
782           void             DOMDocumentImpl::normalize()                             {fParent.normalize (); }
783           void             DOMDocumentImpl::setPrefix(const XMLCh  *prefix)         {fNode.setPrefix(prefix); }
784           bool             DOMDocumentImpl::hasAttributes() const                   {return fNode.hasAttributes(); }
785           bool             DOMDocumentImpl::isSameNode(const DOMNode* other) const  {return fNode.isSameNode(other);}
786           bool             DOMDocumentImpl::isEqualNode(const DOMNode* arg) const   {return fParent.isEqualNode(arg);}
787           void*            DOMDocumentImpl::setUserData(const XMLCh* key, void* data, DOMUserDataHandler* handler)
788                                                                                     {return fNode.setUserData(key, data, handler); }
789           void*            DOMDocumentImpl::getUserData(const XMLCh* key) const     {return fNode.getUserData(key); }
790           short            DOMDocumentImpl::compareDocumentPosition(const DOMNode* other) const {return fNode.compareDocumentPosition(other); }
791           const XMLCh*     DOMDocumentImpl::getTextContent() const                  {return fNode.getTextContent(); }
792           void             DOMDocumentImpl::setTextContent(const XMLCh* textContent){fNode.setTextContent(textContent); }
793           const XMLCh*     DOMDocumentImpl::lookupPrefix(const XMLCh* namespaceURI) const  {return fNode.lookupPrefix(namespaceURI); }
794           bool             DOMDocumentImpl::isDefaultNamespace(const XMLCh* namespaceURI) const {return fNode.isDefaultNamespace(namespaceURI); }
795           const XMLCh*     DOMDocumentImpl::lookupNamespaceURI(const XMLCh* prefix) const  {return fNode.lookupNamespaceURI(prefix); }
796
797
798
799
800//-----------------------------------------------------------------------
801//
802//  Per Document Heap and Heap Helper functions
803//
804//        revisit - this stuff should be a class of its own, rather than
805//                       just lying around naked in DocumentImpl.
806//
807//-----------------------------------------------------------------------
808
809XMLCh * DOMDocumentImpl::cloneString(const XMLCh *src)
810{
811    if (!src) return 0;
812    XMLSize_t len = XMLString::stringLen(src);
813    len = (len + 1) * sizeof(XMLCh);
814    len = (len % 4) + len;
815    XMLCh *newStr = (XMLCh *)this->allocate(len);
816    XMLString::copyString(newStr, src);
817    return newStr;
818}
819
820XMLSize_t DOMDocumentImpl::getMemoryAllocationBlockSize() const
821{
822    return fHeapAllocSize;
823}
824
825void DOMDocumentImpl::setMemoryAllocationBlockSize(XMLSize_t size)
826{
827    // the new size must be bigger than the maximum amount of each allocation
828    if(size>kMaxSubAllocationSize)
829        fHeapAllocSize=size;
830}
831
832void* DOMDocumentImpl::allocate(XMLSize_t amount)
833{
834  //    Align the request size so that suballocated blocks
835  //    beyond this one will be maintained at the same alignment.
836  amount = XMLPlatformUtils::alignPointerForNewBlockAllocation(amount);
837
838  // If the request is for a largish block, hand it off to the system
839  //   allocator.  The block still must be linked into the list of
840  //   allocated blocks so that it will be deleted when the time comes.
841  if (amount > kMaxSubAllocationSize)
842  {
843    //  The size of the header we add to our raw blocks
844    XMLSize_t sizeOfHeader = XMLPlatformUtils::alignPointerForNewBlockAllocation(sizeof(void *));
845
846    //  Try to allocate the block
847    void* newBlock;
848    newBlock = fMemoryManager->allocate(sizeOfHeader + amount);
849
850    //  Link it into the list beyond current block, as current block
851    //  is still being subdivided. If there is no current block
852    //  then track that we have no bytes to further divide.
853    if (fCurrentBlock)
854    {
855      *(void **)newBlock = *(void **)fCurrentBlock;
856      *(void **)fCurrentBlock = newBlock;
857    }
858    else
859    {
860      *(void **)newBlock = 0;
861      fCurrentBlock = newBlock;
862      fFreePtr = 0;
863      fFreeBytesRemaining = 0;
864    }
865
866    void *retPtr = (char*)newBlock + sizeOfHeader;
867    return retPtr;
868  }
869
870  //    It's a normal (sub-allocatable) request.
871  //    Are we out of room in our current block?
872  if (amount > fFreeBytesRemaining)
873  {
874    // Request doesn't fit in the current block.
875    // The size of the header we add to our raw blocks
876    XMLSize_t sizeOfHeader = XMLPlatformUtils::alignPointerForNewBlockAllocation(sizeof(void *));
877
878    // Get a new block from the system allocator.
879    void* newBlock;
880    newBlock = fMemoryManager->allocate(fHeapAllocSize);
881
882    *(void **)newBlock = fCurrentBlock;
883    fCurrentBlock = newBlock;
884    fFreePtr = (char *)newBlock + sizeOfHeader;
885    fFreeBytesRemaining = fHeapAllocSize - sizeOfHeader;
886
887    if(fHeapAllocSize<kMaxHeapAllocSize)
888      fHeapAllocSize*=2;
889  }
890
891  //    Subdivide the request off current block
892  void *retPtr = fFreePtr;
893  fFreePtr += amount;
894  fFreeBytesRemaining -= amount;
895
896  return retPtr;
897}
898
899
900void DOMDocumentImpl::deleteHeap()
901{
902    while (fCurrentBlock != 0)
903    {
904        void *nextBlock = *(void **)fCurrentBlock;
905        fMemoryManager->deallocate(fCurrentBlock);
906        fCurrentBlock = nextBlock;
907    }
908}
909
910
911DOMNodeList *DOMDocumentImpl::getDeepNodeList(const DOMNode *rootNode, const XMLCh *tagName)
912{
913    if(!fNodeListPool) {
914        fNodeListPool = new (this) DOMDeepNodeListPool<DOMDeepNodeListImpl>(109, false);
915    }
916
917    DOMDeepNodeListImpl* retList = fNodeListPool->getByKey(rootNode, tagName, 0);
918    if (!retList) {
919        XMLSize_t id = fNodeListPool->put((void*) rootNode, (XMLCh*) tagName, 0, new (this) DOMDeepNodeListImpl(rootNode, tagName));
920        retList = fNodeListPool->getById(id);
921    }
922
923    return retList;
924}
925
926
927DOMNodeList *DOMDocumentImpl::getDeepNodeList(const DOMNode *rootNode,     //DOM Level 2
928                                                   const XMLCh *namespaceURI,
929                                                   const XMLCh *localName)
930{
931    if(!fNodeListPool) {
932        fNodeListPool = new (this) DOMDeepNodeListPool<DOMDeepNodeListImpl>(109, false);
933    }
934
935    DOMDeepNodeListImpl* retList = fNodeListPool->getByKey(rootNode, localName, namespaceURI);
936    if (!retList) {
937        // the pool will adopt the DOMDeepNodeListImpl
938        XMLSize_t id = fNodeListPool->put((void*) rootNode, (XMLCh*) localName, (XMLCh*) namespaceURI, new (this) DOMDeepNodeListImpl(rootNode, namespaceURI, localName));
939        retList = fNodeListPool->getById(id);
940    }
941
942    return retList;
943}
944
945
946//Introduced in DOM Level 3
947const XMLCh* DOMDocumentImpl::getInputEncoding() const {
948    return fInputEncoding;
949}
950
951void DOMDocumentImpl::setInputEncoding(const XMLCh* actualEncoding){
952    fInputEncoding = cloneString(actualEncoding);
953}
954
955const XMLCh* DOMDocumentImpl::getXmlEncoding() const {
956    return fXmlEncoding;
957}
958
959void DOMDocumentImpl::setXmlEncoding(const XMLCh* encoding){
960    fXmlEncoding = cloneString(encoding);
961}
962
963bool DOMDocumentImpl::getXmlStandalone() const{
964    return fXmlStandalone;
965}
966
967void DOMDocumentImpl::setXmlStandalone(bool standalone){
968    fXmlStandalone = standalone;
969}
970
971const XMLCh* DOMDocumentImpl::getXmlVersion() const {
972    return fXmlVersion;
973}
974
975void DOMDocumentImpl::setXmlVersion(const XMLCh* version){
976
977    // store the static strings, so that comparisons will be faster
978    if(version==0)
979        fXmlVersion = 0;
980    else if(*version==0)
981        fXmlVersion = XMLUni::fgZeroLenString;
982    else if(XMLString::equals(version, XMLUni::fgVersion1_0))
983        fXmlVersion = XMLUni::fgVersion1_0;
984    else if(XMLString::equals(version, XMLUni::fgVersion1_1))
985        fXmlVersion = XMLUni::fgVersion1_1;
986    else
987        throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, getMemoryManager());
988}
989
990const XMLCh* DOMDocumentImpl::getDocumentURI() const
991{
992    return fDocumentURI;
993}
994
995void DOMDocumentImpl::setDocumentURI(const XMLCh* documentURI){
996    if (documentURI && *documentURI) {
997        XMLCh* temp = (XMLCh*) this->allocate((XMLString::stringLen(documentURI) + 9)*sizeof(XMLCh));
998        XMLString::fixURI(documentURI, temp);
999        fDocumentURI = temp;
1000    }
1001    else
1002        fDocumentURI = 0;
1003}
1004
1005bool DOMDocumentImpl::getStrictErrorChecking() const {
1006    return getErrorChecking();
1007}
1008
1009void DOMDocumentImpl::setStrictErrorChecking(bool strictErrorChecking) {
1010    setErrorChecking(strictErrorChecking);
1011}
1012
1013DOMNode* DOMDocumentImpl::adoptNode(DOMNode* sourceNode) {
1014    if(sourceNode->getOwnerDocument()!=this)
1015    {
1016        // cannot take ownership of a node created by another document, as it comes from its memory pool
1017        // and would be delete when the original document is deleted
1018        return 0;
1019    }
1020    // if the adopted node is already part of this document (i.e. the source and target document are the same),
1021    // this method still has the effect of removing the source node from the child list of its parent, if any
1022    switch(sourceNode->getNodeType())
1023    {
1024    case DOCUMENT_NODE:
1025    case DOCUMENT_TYPE_NODE:
1026        throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, getMemoryManager());
1027    case ATTRIBUTE_NODE:
1028        {
1029            DOMAttr* sourceAttr=(DOMAttr*)sourceNode;
1030            DOMElement* sourceAttrElem=sourceAttr->getOwnerElement();
1031            if(sourceAttrElem)
1032                sourceAttrElem->removeAttributeNode(sourceAttr);
1033            fNode.callUserDataHandlers(DOMUserDataHandler::NODE_ADOPTED, sourceNode, sourceNode);
1034            break;
1035        }
1036    default:
1037        {
1038            DOMNode* sourceNodeParent=sourceNode->getParentNode();
1039            if(sourceNodeParent)
1040                sourceNodeParent->removeChild(sourceNode);
1041            fNode.callUserDataHandlers(DOMUserDataHandler::NODE_ADOPTED, sourceNode, sourceNode);
1042        }
1043    }
1044    return 0;
1045}
1046
1047void DOMDocumentImpl::normalizeDocument() {
1048
1049    if(!fNormalizer)
1050        fNormalizer = new (fMemoryManager) DOMNormalizer(fMemoryManager);
1051
1052    fNormalizer->normalizeDocument(this);
1053}
1054
1055DOMConfiguration* DOMDocumentImpl::getDOMConfig() const {
1056    if(!fDOMConfiguration)
1057        ((DOMDocumentImpl*)this)->fDOMConfiguration = new ((DOMDocumentImpl*)this) DOMConfigurationImpl(fMemoryManager);
1058
1059    return fDOMConfiguration;
1060}
1061
1062DOMNode *DOMDocumentImpl::importNode(const DOMNode *source, bool deep, bool cloningDoc)
1063{
1064    DOMNode *newnode=0;
1065    bool oldErrorCheckingFlag = errorChecking;
1066
1067    switch (source->getNodeType())
1068    {
1069    case DOMNode::ELEMENT_NODE :
1070        {
1071            DOMElement *newelement;
1072            if (source->getLocalName() == 0)
1073                newelement = createElement(source->getNodeName());
1074            else
1075            {
1076                DOMElementNSImpl* nsElem = (DOMElementNSImpl*)createElementNS(source->getNamespaceURI(), source->getNodeName());
1077                DOMTypeInfoImpl* clonedTypeInfo=NULL;
1078                // if the source has type informations, copy them
1079                DOMPSVITypeInfo* sourcePSVI=(DOMPSVITypeInfo*)source->getFeature(XMLUni::fgXercescInterfacePSVITypeInfo, 0);
1080                if(sourcePSVI && sourcePSVI->getNumericProperty(DOMPSVITypeInfo::PSVI_Schema_Specified))
1081                    clonedTypeInfo=new (this) DOMTypeInfoImpl(this, sourcePSVI);
1082                else
1083                {
1084                    const DOMTypeInfo * typeInfo=((DOMElement*)source)->getSchemaTypeInfo();
1085                    // copy it only if it has valid data
1086                    if(typeInfo && typeInfo->getTypeName()!=NULL)
1087                        clonedTypeInfo=new (this) DOMTypeInfoImpl(typeInfo->getTypeNamespace(), typeInfo->getTypeName());
1088                }
1089                if(clonedTypeInfo)
1090                    nsElem->setSchemaTypeInfo(clonedTypeInfo);
1091                newelement=nsElem;
1092            }
1093            DOMNamedNodeMap *srcattr=source->getAttributes();
1094            if(srcattr!=0)
1095                for(XMLSize_t i=0;i<srcattr->getLength();++i)
1096                {
1097                    DOMAttr *attr = (DOMAttr *) srcattr->item(i);
1098                    if (attr -> getSpecified() || cloningDoc) { // not a default attribute or we are in the process of cloning the elements from inside a DOMDocumentType
1099                        DOMAttr *nattr = (DOMAttr *) importNode(attr, true, cloningDoc);
1100                        if (attr -> getLocalName() == 0)
1101                            newelement->setAttributeNode(nattr);
1102                        else
1103                            newelement->setAttributeNodeNS(nattr);
1104
1105                        // if the imported attribute is of ID type, register the new node in fNodeIDMap
1106                        if (attr->isId()) {
1107                            castToNodeImpl(nattr)->isIdAttr(true);
1108                            if (!fNodeIDMap)
1109                                 fNodeIDMap = new (this) DOMNodeIDMap(500, this);
1110                            fNodeIDMap->add((DOMAttr*)nattr);
1111                        }
1112                    }
1113                }
1114            newnode=newelement;
1115
1116        }
1117        break;
1118    case DOMNode::ATTRIBUTE_NODE :
1119        {
1120            DOMAttrImpl* newattr=NULL;
1121            if (source->getLocalName() == 0)
1122                newattr = (DOMAttrImpl*)createAttribute(source->getNodeName());
1123            else {
1124                newattr = (DOMAttrImpl*)createAttributeNS(source->getNamespaceURI(), source->getNodeName());
1125            }
1126            DOMTypeInfoImpl* clonedTypeInfo=NULL;
1127            // if the source has type informations, copy them
1128            DOMPSVITypeInfo* sourcePSVI=(DOMPSVITypeInfo*)source->getFeature(XMLUni::fgXercescInterfacePSVITypeInfo, 0);
1129            if(sourcePSVI && sourcePSVI->getNumericProperty(DOMPSVITypeInfo::PSVI_Schema_Specified))
1130                clonedTypeInfo=new (this) DOMTypeInfoImpl(this, sourcePSVI);
1131            else
1132            {
1133                const DOMTypeInfo * typeInfo=((DOMAttr*)source)->getSchemaTypeInfo();
1134                // copy it only if it has valid data
1135                if(typeInfo && typeInfo->getTypeName()!=NULL)
1136                    clonedTypeInfo=new (this) DOMTypeInfoImpl(typeInfo->getTypeNamespace(), typeInfo->getTypeName());
1137            }
1138            if(clonedTypeInfo)
1139                newattr->setSchemaTypeInfo(clonedTypeInfo);
1140            newnode=newattr;
1141        }
1142        deep = true;
1143        // Kids carry value
1144
1145        break;
1146    case DOMNode::TEXT_NODE :
1147        newnode = createTextNode(source->getNodeValue());
1148        break;
1149    case DOMNode::CDATA_SECTION_NODE :
1150        newnode = createCDATASection(source->getNodeValue());
1151        break;
1152    case DOMNode::ENTITY_REFERENCE_NODE :
1153        {
1154            DOMEntityReferenceImpl* newentityRef = (DOMEntityReferenceImpl*)createEntityReference(source->getNodeName());
1155            newnode=newentityRef;
1156            // Only the EntityReference itself is copied, even if a deep import is requested, since the source and
1157            // destination documents might have defined the entity differently.
1158            deep = false;
1159        }
1160        break;
1161    case DOMNode::ENTITY_NODE :
1162        {
1163            DOMEntity *srcentity=(DOMEntity *)source;
1164            DOMEntityImpl *newentity = (DOMEntityImpl *)createEntity(source->getNodeName());
1165            newentity->setPublicId(srcentity->getPublicId());
1166            newentity->setSystemId(srcentity->getSystemId());
1167            newentity->setNotationName(srcentity->getNotationName());
1168            newentity->setBaseURI(srcentity->getBaseURI());
1169            // Kids carry additional value
1170            newnode=newentity;
1171            castToNodeImpl(newentity)->setReadOnly(false, true);// allow deep import temporarily
1172        }
1173        break;
1174    case DOMNode::PROCESSING_INSTRUCTION_NODE :
1175        newnode = createProcessingInstruction(source->getNodeName(), source->getNodeValue());
1176        break;
1177    case DOMNode::COMMENT_NODE :
1178        newnode = createComment(source->getNodeValue());
1179        break;
1180    case DOMNode::DOCUMENT_TYPE_NODE :
1181        {
1182            // unless this is used as part of cloning a Document
1183            // forbid it for the sake of being compliant to the DOM spec
1184            if (!cloningDoc)
1185                throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, getMemoryManager());
1186
1187            DOMDocumentType *srcdoctype = (DOMDocumentType *)source;
1188            DOMDocumentTypeImpl *newdoctype = (DOMDocumentTypeImpl *)
1189                createDocumentType(srcdoctype->getNodeName(),
1190                srcdoctype->getPublicId(),
1191                srcdoctype->getSystemId());
1192            // Values are on NamedNodeMaps
1193            DOMNamedNodeMap *smap = srcdoctype->getEntities();
1194            DOMNamedNodeMap *tmap = newdoctype->getEntities();
1195            if(smap != 0) {
1196                for(XMLSize_t i = 0; i < smap->getLength(); i++) {
1197                    tmap->setNamedItem(importNode(smap->item(i), true, cloningDoc));
1198                }
1199            }
1200            smap = srcdoctype->getNotations();
1201            tmap = newdoctype->getNotations();
1202            if (smap != 0) {
1203                for(XMLSize_t i = 0; i < smap->getLength(); i++) {
1204                    tmap->setNamedItem(importNode(smap->item(i), true, cloningDoc));
1205                }
1206            }
1207            const XMLCh* intSubset=srcdoctype->getInternalSubset();
1208            if(intSubset != 0) {
1209                newdoctype->setInternalSubset(intSubset);
1210            }
1211
1212            // detect if the DTD being copied is our own implementation, and use the provided methods
1213            try
1214            {
1215                DOMDocumentTypeImpl* docTypeImpl=(DOMDocumentTypeImpl*)(srcdoctype->getFeature(XMLUni::fgXercescInterfaceDOMDocumentTypeImpl, XMLUni::fgZeroLenString));
1216                if(docTypeImpl)
1217                {
1218                    smap = docTypeImpl->getElements();
1219                    tmap = newdoctype->getElements();
1220                    if (smap != 0) {
1221                        for(XMLSize_t i = 0; i < smap->getLength(); i++) {
1222                            tmap->setNamedItem(importNode(smap->item(i), true, cloningDoc));
1223                        }
1224                    }
1225                }
1226            } catch(DOMException&) {
1227            }
1228
1229            newnode = newdoctype;
1230        }
1231        break;
1232    case DOMNode::DOCUMENT_FRAGMENT_NODE :
1233        newnode = createDocumentFragment();
1234        // No name, kids carry value
1235        break;
1236    case DOMNode::NOTATION_NODE :
1237        {
1238            DOMNotation *srcnotation=(DOMNotation *)source;
1239            DOMNotationImpl *newnotation = (DOMNotationImpl *)createNotation(source->getNodeName());
1240            newnotation->setPublicId(srcnotation->getPublicId());
1241            newnotation->setSystemId(srcnotation->getSystemId());
1242            newnotation->setBaseURI(srcnotation->getBaseURI());
1243            newnode=newnotation;
1244            // No name, no value
1245            break;
1246        }
1247
1248    case DOMNode::DOCUMENT_NODE : // Document can't be child of Document
1249    default:                       // Unknown node type
1250        throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, getMemoryManager());
1251    }
1252
1253    // If deep, replicate and attach the kids.
1254    if (deep)
1255        for (DOMNode *srckid = source->getFirstChild();
1256             srckid != 0;
1257             srckid = srckid->getNextSibling())
1258        {
1259            newnode->appendChild(importNode(srckid, true, cloningDoc));
1260        }
1261
1262    if (newnode->getNodeType() == DOMNode::ENTITY_NODE) {
1263        castToNodeImpl(newnode)->setReadOnly(true, true);
1264        errorChecking = oldErrorCheckingFlag;
1265    }
1266
1267    if (cloningDoc)
1268    {
1269        // we know for sure that the source node is a DOMNodeImpl, as cloningDoc is set to true when
1270        // a DOMDocumentImpl is cloned
1271        castToNodeImpl(source)->callUserDataHandlers(DOMUserDataHandler::NODE_CLONED, source, newnode);
1272    }
1273    else
1274        fNode.callUserDataHandlers(DOMUserDataHandler::NODE_IMPORTED, source, newnode);
1275
1276    return newnode;
1277}
1278
1279// user data utility
1280void* DOMDocumentImpl::setUserData(DOMNodeImpl* n, const XMLCh* key, void* data, DOMUserDataHandler* handler)
1281{
1282    void* oldData = 0;
1283    unsigned int keyId=fUserDataTableKeys.addOrFind(key);
1284
1285    if (!fUserDataTable) {
1286        // create the table on heap so that it can be cleaned in destructor
1287        fUserDataTable = new (fMemoryManager) RefHash2KeysTableOf<DOMUserDataRecord, PtrHasher>
1288        (
1289            109
1290            , true
1291            , fMemoryManager
1292        );
1293    }
1294    else {
1295        DOMUserDataRecord* oldDataRecord = fUserDataTable->get((void*)n, keyId);
1296
1297        if (oldDataRecord) {
1298            oldData = oldDataRecord->getKey();
1299            fUserDataTable->removeKey((void*)n, keyId);
1300        }
1301    }
1302
1303    if (data) {
1304
1305        // clone the key first, and create the DOMUserDataRecord
1306        // create on the heap and adopted by the hashtable which will delete it upon removal.
1307        fUserDataTable->put((void*)n, keyId, new (fMemoryManager) DOMUserDataRecord(data, handler));
1308    }
1309    else {
1310        RefHash2KeysTableOfEnumerator<DOMUserDataRecord, PtrHasher> enumKeys(fUserDataTable, false, fMemoryManager);
1311        enumKeys.setPrimaryKey(n);
1312        if (!enumKeys.hasMoreElements())
1313            n->hasUserData(false);
1314    }
1315
1316    return oldData;
1317}
1318
1319void* DOMDocumentImpl::getUserData(const DOMNodeImpl* n, const XMLCh* key) const
1320{
1321    if (fUserDataTable) {
1322        unsigned int keyId=fUserDataTableKeys.getId(key);
1323        if(keyId!=0) {
1324            DOMUserDataRecord* dataRecord = fUserDataTable->get((void*)n, keyId);
1325            if (dataRecord)
1326                return dataRecord->getKey();
1327        }
1328    }
1329
1330    return 0;
1331}
1332
1333void DOMDocumentImpl::callUserDataHandlers(const DOMNodeImpl* n, DOMUserDataHandler::DOMOperationType operation, const DOMNode* src, DOMNode* dst) const
1334{
1335    if (fUserDataTable) {
1336        RefHash2KeysTableOfEnumerator<DOMUserDataRecord, PtrHasher> userDataEnum(fUserDataTable, false, fMemoryManager);
1337        userDataEnum.setPrimaryKey(n);
1338        // Create a snapshot of the handlers to be called, as the "handle" callback could be invalidating the enumerator by calling
1339        // setUserData on the dst node
1340        ValueVectorOf< int > snapshot(3, fMemoryManager);
1341        while (userDataEnum.hasMoreElements()) {
1342            // get the key
1343            void* key;
1344            int key2;
1345            userDataEnum.nextElementKey(key,key2);
1346            snapshot.addElement(key2);
1347        }
1348        ValueVectorEnumerator< int > snapshotEnum(&snapshot);
1349        while(snapshotEnum.hasMoreElements())
1350        {
1351            int key2=snapshotEnum.nextElement();
1352
1353            // get the DOMUserDataRecord
1354            DOMUserDataRecord* userDataRecord = fUserDataTable->get((void*)n,key2);
1355
1356            // get the handler
1357            DOMUserDataHandler* handler = userDataRecord->getValue();
1358
1359            if (handler) {
1360                // get the data
1361                void* data = userDataRecord->getKey();
1362                const XMLCh* userKey = fUserDataTableKeys.getValueForId(key2);
1363                handler->handle(operation, userKey, data, src, dst);
1364            }
1365        }
1366        // if the operation is NODE_DELETED, we in fact should remove the data from the table
1367        if (operation == DOMUserDataHandler::NODE_DELETED)
1368            fUserDataTable->removeKey((void*)n);
1369    }
1370}
1371
1372
1373void DOMDocumentImpl::transferUserData(DOMNodeImpl* n1, DOMNodeImpl* n2)
1374{
1375    if (fUserDataTable) {
1376        fUserDataTable->transferElement((void*)n1, (void*)n2);
1377        n1->hasUserData(false);
1378        n2->hasUserData(true);
1379    }
1380}
1381
1382
1383DOMNode* DOMDocumentImpl::renameNode(DOMNode* n, const XMLCh* namespaceURI, const XMLCh* name)
1384{
1385    if (n->getOwnerDocument() != this)
1386        throw DOMException(DOMException::WRONG_DOCUMENT_ERR, 0, getMemoryManager());
1387
1388    switch (n->getNodeType()) {
1389        case ELEMENT_NODE:
1390            return ((DOMElementImpl*)n)->rename(namespaceURI, name);
1391        case ATTRIBUTE_NODE:
1392            return ((DOMAttrImpl*)n)->rename(namespaceURI, name);
1393        default:
1394            break;
1395    }
1396    throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, getMemoryManager());
1397
1398    return 0;
1399}
1400
1401void DOMDocumentImpl::release()
1402{
1403    DOMDocument* doc = (DOMDocument*) this;
1404    fNode.callUserDataHandlers(DOMUserDataHandler::NODE_DELETED, 0, 0);
1405
1406    // notify userdatahandler first, if we have some
1407    if (fUserDataTable)
1408        releaseDocNotifyUserData(this);
1409
1410    // release the docType in case it was created from heap
1411    if (fDocType) {
1412        castToNodeImpl(fDocType)->isToBeReleased(true);
1413        fDocType->release();
1414    }
1415
1416    // delete the document memory pool
1417    delete doc;
1418}
1419
1420void DOMDocumentImpl::releaseDocNotifyUserData(DOMNode* object)
1421{
1422    DOMNode *child = object->getFirstChild();
1423
1424    while( child != 0)
1425    {
1426
1427         DOMNamedNodeMap *attrlist=child->getAttributes();
1428
1429         if(attrlist!=0)
1430             for(XMLSize_t i=0;i<attrlist->getLength();++i)
1431                 releaseDocNotifyUserData(attrlist->item(i));
1432
1433        releaseDocNotifyUserData(child);
1434        child = child->getNextSibling();
1435    }
1436
1437    castToNodeImpl(object)->callUserDataHandlers(DOMUserDataHandler::NODE_DELETED, 0, 0);
1438}
1439
1440void DOMDocumentImpl::release(DOMNode* object, DOMMemoryManager::NodeObjectType type)
1441{
1442    if (!fRecycleNodePtr)
1443        fRecycleNodePtr = new (fMemoryManager) RefArrayOf<DOMNodePtr> (15, fMemoryManager);
1444
1445    if (!fRecycleNodePtr->operator[](type))
1446        fRecycleNodePtr->operator[](type) = new (fMemoryManager) RefStackOf<DOMNode> (15, false, fMemoryManager);
1447
1448    fRecycleNodePtr->operator[](type)->push(object);
1449}
1450
1451void DOMDocumentImpl::releaseBuffer(DOMBuffer* buffer)
1452{
1453    if (!fRecycleBufferPtr)
1454        fRecycleBufferPtr = new (fMemoryManager) RefStackOf<DOMBuffer> (15, false, fMemoryManager);
1455
1456    fRecycleBufferPtr->push(buffer);
1457}
1458
1459DOMBuffer* DOMDocumentImpl::popBuffer(XMLSize_t nMinSize)
1460{
1461    if (!fRecycleBufferPtr || fRecycleBufferPtr->empty())
1462        return 0;
1463
1464    for(XMLSize_t index=fRecycleBufferPtr->size()-1;index>0;index--)
1465        if(fRecycleBufferPtr->elementAt(index)->getCapacity()>=nMinSize)
1466            return fRecycleBufferPtr->popAt(index);
1467    // if we didn't find a buffer big enough, get the last one
1468    return fRecycleBufferPtr->pop();
1469}
1470
1471
1472void * DOMDocumentImpl::allocate(XMLSize_t amount, DOMMemoryManager::NodeObjectType type)
1473{
1474    if (!fRecycleNodePtr)
1475        return allocate(amount);
1476
1477    DOMNodePtr* ptr = fRecycleNodePtr->operator[](type);
1478    if (!ptr || ptr->empty())
1479        return allocate(amount);
1480
1481    return (void*) ptr->pop();
1482
1483}
1484
1485bool DOMDocumentImpl::isSupported(const XMLCh *feature, const XMLCh *version) const
1486{
1487    // check for '+DOMMemoryManager'
1488    if(feature && *feature=='+' && XMLString::equals(feature+1, XMLUni::fgXercescInterfaceDOMMemoryManager))
1489        return true;
1490    if(feature && *feature)
1491    {
1492        if((*feature==chPlus && XMLString::equals(feature+1, XMLUni::fgXercescInterfaceDOMDocumentImpl)) ||
1493           XMLString::equals(feature, XMLUni::fgXercescInterfaceDOMDocumentImpl))
1494            return true;
1495    }
1496    return fNode.isSupported (feature, version);
1497}
1498
1499void* DOMDocumentImpl::getFeature(const XMLCh* feature, const XMLCh* version) const
1500{
1501    if(XMLString::equals(feature, XMLUni::fgXercescInterfaceDOMMemoryManager))
1502        return (DOMMemoryManager*)this;
1503    if(XMLString::equals(feature, XMLUni::fgXercescInterfaceDOMDocumentImpl))
1504        return (DOMDocumentImpl*)this;
1505    return fNode.getFeature(feature,version);
1506}
1507
1508
1509XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.