/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 |