Coverage Report

Created: 2025-07-23 06:41

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