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$
20 */
21
22 #include "DOMCDATASectionImpl.hpp"
23 #include "DOMNodeImpl.hpp"
24 #include "DOMRangeImpl.hpp"
25 #include "DOMDocumentImpl.hpp"
26 #include "DOMCasts.hpp"
27 #include "DOMStringPool.hpp"
28 #include <xercesc/dom/DOMException.hpp>
29 #include <xercesc/dom/DOMNodeFilter.hpp>
30 #include <xercesc/dom/DOMTreeWalker.hpp>
31 #include <xercesc/util/XMLUniDefs.hpp>
32
33 XERCES_CPP_NAMESPACE_BEGIN
34
DOMCDATASectionImpl(DOMDocument * ownerDoc,const XMLCh * dat)35 DOMCDATASectionImpl::DOMCDATASectionImpl(DOMDocument *ownerDoc, const XMLCh *dat)
36 : fNode(this, ownerDoc), fCharacterData(ownerDoc, dat)
37 {
38 fNode.setIsLeafNode(true);
39 }
40
DOMCDATASectionImpl(DOMDocument * ownerDoc,const XMLCh * data,XMLSize_t n)41 DOMCDATASectionImpl::DOMCDATASectionImpl(DOMDocument *ownerDoc, const XMLCh* data, XMLSize_t n)
42 : fNode(this, ownerDoc), fCharacterData(ownerDoc, data, n)
43 {
44 fNode.setIsLeafNode(true);
45 }
46
DOMCDATASectionImpl(const DOMCDATASectionImpl & other,bool)47 DOMCDATASectionImpl::DOMCDATASectionImpl(const DOMCDATASectionImpl &other, bool /*deep*/)
48 : DOMCDATASection(other),
49 fNode(this, other.fNode),
50 fChild(other.fChild),
51 fCharacterData(other.fCharacterData)
52 {
53 // revisit. Something nees to make "deep" work.
54 }
55
56
~DOMCDATASectionImpl()57 DOMCDATASectionImpl::~DOMCDATASectionImpl()
58 {
59 }
60
61
cloneNode(bool deep) const62 DOMNode *DOMCDATASectionImpl::cloneNode(bool deep) const
63 {
64 DOMNode* newNode = new (this->getOwnerDocument(), DOMMemoryManager::CDATA_SECTION_OBJECT) DOMCDATASectionImpl(*this, deep);
65 fNode.callUserDataHandlers(DOMUserDataHandler::NODE_CLONED, this, newNode);
66 return newNode;
67 }
68
69
getNodeName() const70 const XMLCh * DOMCDATASectionImpl::getNodeName() const {
71 static const XMLCh gcdata_section[] = {chPound, chLatin_c, chLatin_d, chLatin_a, chLatin_t, chLatin_a,
72 chDash, chLatin_s, chLatin_e, chLatin_c, chLatin_t, chLatin_i, chLatin_o, chLatin_n, 0};
73 return gcdata_section;
74 }
75
76
getNodeType() const77 DOMNode::NodeType DOMCDATASectionImpl::getNodeType() const {
78 return DOMNode::CDATA_SECTION_NODE;
79 }
80
81
isIgnorableWhitespace() const82 bool DOMCDATASectionImpl::isIgnorableWhitespace() const
83 {
84 return fNode.ignorableWhitespace();
85 }
86
87
88 //
89 // splitText. revist - factor into a common function for use
90 // here and in DOMTextImpl
91 //
splitText(XMLSize_t offset)92 DOMText *DOMCDATASectionImpl::splitText(XMLSize_t offset)
93 {
94 if (fNode.isReadOnly())
95 {
96 throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNodeMemoryManager);
97 }
98 XMLSize_t len = fCharacterData.fDataBuf->getLen();
99 if (offset > len)
100 throw DOMException(DOMException::INDEX_SIZE_ERR, 0, GetDOMNodeMemoryManager);
101
102 DOMDocumentImpl *doc = (DOMDocumentImpl *)getOwnerDocument();
103 DOMText *newText =
104 doc->createCDATASection(this->substringData(offset, len - offset));
105
106 DOMNode *parent = getParentNode();
107 if (parent != 0)
108 parent->insertBefore(newText, getNextSibling());
109
110 fCharacterData.fDataBuf->chop(offset);
111
112 if (doc != 0) {
113 Ranges* ranges = doc->getRanges();
114 if (ranges != 0) {
115 XMLSize_t sz = ranges->size();
116 if (sz != 0) {
117 for (XMLSize_t i =0; i<sz; i++) {
118 ranges->elementAt(i)->updateSplitInfo( this, newText, offset);
119 }
120 }
121 }
122 }
123
124 return newText;
125 }
126
127
getIsElementContentWhitespace() const128 bool DOMCDATASectionImpl::getIsElementContentWhitespace() const
129 {
130 return isIgnorableWhitespace();
131 }
132
getWholeText() const133 const XMLCh* DOMCDATASectionImpl::getWholeText() const
134 {
135 DOMDocument *doc = getOwnerDocument();
136 if (!doc) {
137 throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, GetDOMNodeMemoryManager);
138 return 0;
139 }
140 DOMNode* root=doc->getDocumentElement();
141 DOMTreeWalker* pWalker=doc->createTreeWalker(root!=NULL?root:(DOMNode*)this, DOMNodeFilter::SHOW_ALL, NULL, true);
142 pWalker->setCurrentNode((DOMNode*)this);
143 // Logically-adjacent text nodes are Text or CDATASection nodes that can be visited sequentially in document order or in
144 // reversed document order without entering, exiting, or passing over Element, Comment, or ProcessingInstruction nodes.
145 DOMNode* prevNode;
146 while((prevNode=pWalker->previousNode())!=NULL)
147 {
148 if(prevNode->getNodeType()==ELEMENT_NODE || prevNode->getNodeType()==COMMENT_NODE || prevNode->getNodeType()==PROCESSING_INSTRUCTION_NODE)
149 break;
150 }
151 XMLBuffer buff(1023, GetDOMNodeMemoryManager);
152 DOMNode* nextNode;
153 while((nextNode=pWalker->nextNode())!=NULL)
154 {
155 if(nextNode->getNodeType()==ELEMENT_NODE || nextNode->getNodeType()==COMMENT_NODE || nextNode->getNodeType()==PROCESSING_INSTRUCTION_NODE)
156 break;
157 if(nextNode->getNodeType()==TEXT_NODE || nextNode->getNodeType()==CDATA_SECTION_NODE)
158 buff.append(nextNode->getNodeValue());
159 }
160 pWalker->release();
161
162 XMLCh* wholeString = (XMLCh*)((DOMDocumentImpl*)doc)->allocate((buff.getLen()+1) * sizeof(XMLCh));
163 XMLString::copyString(wholeString, buff.getRawBuffer());
164 return wholeString;
165 }
166
replaceWholeText(const XMLCh * newText)167 DOMText* DOMCDATASectionImpl::replaceWholeText(const XMLCh* newText)
168 {
169 DOMDocument *doc = getOwnerDocument();
170 DOMTreeWalker* pWalker=doc->createTreeWalker(doc->getDocumentElement(), DOMNodeFilter::SHOW_ALL, NULL, true);
171 pWalker->setCurrentNode((DOMNode*)this);
172 // Logically-adjacent text nodes are Text or CDATASection nodes that can be visited sequentially in document order or in
173 // reversed document order without entering, exiting, or passing over Element, Comment, or ProcessingInstruction nodes.
174 DOMNode* pFirstTextNode=this;
175 DOMNode* prevNode;
176 while((prevNode=pWalker->previousNode())!=NULL)
177 {
178 if(prevNode->getNodeType()==ELEMENT_NODE || prevNode->getNodeType()==COMMENT_NODE || prevNode->getNodeType()==PROCESSING_INSTRUCTION_NODE)
179 break;
180 pFirstTextNode=prevNode;
181 }
182 // before doing any change we need to check if we are going to remove an entity reference that doesn't contain just text
183 DOMNode* pCurrentNode=pWalker->getCurrentNode();
184 DOMNode* nextNode;
185 while((nextNode=pWalker->nextNode())!=NULL)
186 {
187 if(nextNode->getNodeType()==ELEMENT_NODE || nextNode->getNodeType()==COMMENT_NODE || nextNode->getNodeType()==PROCESSING_INSTRUCTION_NODE)
188 break;
189 if(nextNode->getNodeType()==ENTITY_REFERENCE_NODE)
190 {
191 DOMTreeWalker* pInnerWalker=doc->createTreeWalker(nextNode, DOMNodeFilter::SHOW_ALL, NULL, true);
192 while(pInnerWalker->nextNode())
193 {
194 short nodeType=pInnerWalker->getCurrentNode()->getNodeType();
195 if(nodeType!=ENTITY_REFERENCE_NODE && nodeType!=TEXT_NODE && nodeType!=CDATA_SECTION_NODE)
196 throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNodeMemoryManager);
197 }
198 pInnerWalker->release();
199 }
200 }
201 DOMText* retVal=NULL;
202 // if the first node in the chain is a text node, replace its content, otherwise create a new node
203 if(newText && *newText)
204 {
205 if(!castToNodeImpl(pFirstTextNode)->isReadOnly() && (pFirstTextNode->getNodeType()==TEXT_NODE || pFirstTextNode->getNodeType()==CDATA_SECTION_NODE))
206 {
207 pFirstTextNode->setNodeValue(newText);
208 retVal=(DOMText*)pFirstTextNode;
209 }
210 else
211 {
212 if(getNodeType()==TEXT_NODE)
213 retVal=doc->createTextNode(newText);
214 else
215 retVal=doc->createCDATASection(newText);
216 pFirstTextNode->getParentNode()->insertBefore(retVal, pFirstTextNode);
217 }
218 }
219 // now delete all the following text nodes
220 pWalker->setCurrentNode(pCurrentNode);
221 while((nextNode=pWalker->nextNode())!=NULL)
222 {
223 if(nextNode->getNodeType()==ELEMENT_NODE || nextNode->getNodeType()==COMMENT_NODE || nextNode->getNodeType()==PROCESSING_INSTRUCTION_NODE)
224 break;
225 if(nextNode!=retVal)
226 {
227 // keep the tree walker valid
228 pWalker->previousNode();
229 nextNode->getParentNode()->removeChild(nextNode);
230 nextNode->release();
231 }
232 }
233 pWalker->release();
234 return retVal;
235 }
236
237
release()238 void DOMCDATASectionImpl::release()
239 {
240 if (fNode.isOwned() && !fNode.isToBeReleased())
241 throw DOMException(DOMException::INVALID_ACCESS_ERR,0, GetDOMNodeMemoryManager);
242
243 DOMDocumentImpl* doc = (DOMDocumentImpl*) getOwnerDocument();
244
245 if (doc) {
246 fNode.callUserDataHandlers(DOMUserDataHandler::NODE_DELETED, 0, 0);
247 fCharacterData.releaseBuffer();
248 doc->release(this, DOMMemoryManager::CDATA_SECTION_OBJECT);
249 }
250 else {
251 // shouldn't reach here
252 throw DOMException(DOMException::INVALID_ACCESS_ERR,0, GetDOMNodeMemoryManager);
253 }
254 }
255
256
257 //
258 // Delegation stubs for other DOM_Node inherited functions.
259 //
appendChild(DOMNode * newChild)260 DOMNode* DOMCDATASectionImpl::appendChild(DOMNode *newChild) {return fNode.appendChild (newChild); }
getAttributes() const261 DOMNamedNodeMap* DOMCDATASectionImpl::getAttributes() const {return fNode.getAttributes (); }
getChildNodes() const262 DOMNodeList* DOMCDATASectionImpl::getChildNodes() const {return fNode.getChildNodes (); }
getFirstChild() const263 DOMNode* DOMCDATASectionImpl::getFirstChild() const {return fNode.getFirstChild (); }
getLastChild() const264 DOMNode* DOMCDATASectionImpl::getLastChild() const {return fNode.getLastChild (); }
getLocalName() const265 const XMLCh* DOMCDATASectionImpl::getLocalName() const {return fNode.getLocalName (); }
getNamespaceURI() const266 const XMLCh* DOMCDATASectionImpl::getNamespaceURI() const {return fNode.getNamespaceURI (); }
getNextSibling() const267 DOMNode* DOMCDATASectionImpl::getNextSibling() const {return fChild.getNextSibling (); }
getNodeValue() const268 const XMLCh* DOMCDATASectionImpl::getNodeValue() const {return fCharacterData.getNodeValue (); }
getOwnerDocument() const269 DOMDocument* DOMCDATASectionImpl::getOwnerDocument() const {return fNode.getOwnerDocument(); }
getPrefix() const270 const XMLCh* DOMCDATASectionImpl::getPrefix() const {return fNode.getPrefix (); }
getParentNode() const271 DOMNode* DOMCDATASectionImpl::getParentNode() const {return fChild.getParentNode (this); }
getPreviousSibling() const272 DOMNode* DOMCDATASectionImpl::getPreviousSibling() const {return fChild.getPreviousSibling (this); }
hasChildNodes() const273 bool DOMCDATASectionImpl::hasChildNodes() const {return fNode.hasChildNodes (); }
insertBefore(DOMNode * newChild,DOMNode * refChild)274 DOMNode* DOMCDATASectionImpl::insertBefore(DOMNode *newChild, DOMNode *refChild)
275 {return fNode.insertBefore (newChild, refChild); }
normalize()276 void DOMCDATASectionImpl::normalize() {fNode.normalize (); }
removeChild(DOMNode * oldChild)277 DOMNode* DOMCDATASectionImpl::removeChild(DOMNode *oldChild) {return fNode.removeChild (oldChild); }
replaceChild(DOMNode * newChild,DOMNode * oldChild)278 DOMNode* DOMCDATASectionImpl::replaceChild(DOMNode *newChild, DOMNode *oldChild)
279 {return fNode.replaceChild (newChild, oldChild); }
isSupported(const XMLCh * feature,const XMLCh * version) const280 bool DOMCDATASectionImpl::isSupported(const XMLCh *feature, const XMLCh *version) const
281 {return fNode.isSupported (feature, version); }
setPrefix(const XMLCh * prefix)282 void DOMCDATASectionImpl::setPrefix(const XMLCh *prefix) {fNode.setPrefix(prefix); }
hasAttributes() const283 bool DOMCDATASectionImpl::hasAttributes() const {return fNode.hasAttributes(); }
isSameNode(const DOMNode * other) const284 bool DOMCDATASectionImpl::isSameNode(const DOMNode* other) const {return fNode.isSameNode(other); }
isEqualNode(const DOMNode * arg) const285 bool DOMCDATASectionImpl::isEqualNode(const DOMNode* arg) const {return fNode.isEqualNode(arg); }
setUserData(const XMLCh * key,void * data,DOMUserDataHandler * handler)286 void* DOMCDATASectionImpl::setUserData(const XMLCh* key, void* data, DOMUserDataHandler* handler)
287 {return fNode.setUserData(key, data, handler); }
getUserData(const XMLCh * key) const288 void* DOMCDATASectionImpl::getUserData(const XMLCh* key) const {return fNode.getUserData(key); }
getBaseURI() const289 const XMLCh* DOMCDATASectionImpl::getBaseURI() const {return fNode.getBaseURI(); }
compareDocumentPosition(const DOMNode * other) const290 short DOMCDATASectionImpl::compareDocumentPosition(const DOMNode* other) const {return fNode.compareDocumentPosition(other); }
getTextContent() const291 const XMLCh* DOMCDATASectionImpl::getTextContent() const {return fNode.getTextContent(); }
setTextContent(const XMLCh * textContent)292 void DOMCDATASectionImpl::setTextContent(const XMLCh* textContent){fNode.setTextContent(textContent); }
lookupPrefix(const XMLCh * namespaceURI) const293 const XMLCh* DOMCDATASectionImpl::lookupPrefix(const XMLCh* namespaceURI) const {return fNode.lookupPrefix(namespaceURI); }
isDefaultNamespace(const XMLCh * namespaceURI) const294 bool DOMCDATASectionImpl::isDefaultNamespace(const XMLCh* namespaceURI) const {return fNode.isDefaultNamespace(namespaceURI); }
lookupNamespaceURI(const XMLCh * prefix) const295 const XMLCh* DOMCDATASectionImpl::lookupNamespaceURI(const XMLCh* prefix) const {return fNode.lookupNamespaceURI(prefix); }
getFeature(const XMLCh * feature,const XMLCh * version) const296 void* DOMCDATASectionImpl::getFeature(const XMLCh* feature, const XMLCh* version) const {return fNode.getFeature(feature, version); }
297
298
299
300 //
301 // Delegation of CharacerData functions.
302 //
303
304
getData() const305 const XMLCh* DOMCDATASectionImpl::getData() const {return fCharacterData.getData();}
getLength() const306 XMLSize_t DOMCDATASectionImpl::getLength() const {return fCharacterData.getLength();}
substringData(XMLSize_t offset,XMLSize_t count) const307 const XMLCh* DOMCDATASectionImpl::substringData(XMLSize_t offset, XMLSize_t count) const
308 {return fCharacterData.substringData(this, offset, count);}
appendData(const XMLCh * arg)309 void DOMCDATASectionImpl::appendData(const XMLCh *arg) {fCharacterData.appendData(this, arg);}
insertData(XMLSize_t offset,const XMLCh * arg)310 void DOMCDATASectionImpl::insertData(XMLSize_t offset, const XMLCh *arg)
311 {fCharacterData.insertData(this, offset, arg);}
deleteData(XMLSize_t offset,XMLSize_t count)312 void DOMCDATASectionImpl::deleteData(XMLSize_t offset, XMLSize_t count)
313 {fCharacterData.deleteData(this, offset, count);}
replaceData(XMLSize_t offset,XMLSize_t count,const XMLCh * arg)314 void DOMCDATASectionImpl::replaceData(XMLSize_t offset, XMLSize_t count, const XMLCh *arg)
315 {fCharacterData.replaceData(this, offset, count, arg);}
setData(const XMLCh * data)316 void DOMCDATASectionImpl::setData(const XMLCh *data) {fCharacterData.setData(this, data);}
setNodeValue(const XMLCh * nodeValue)317 void DOMCDATASectionImpl::setNodeValue(const XMLCh *nodeValue) {fCharacterData.setNodeValue (this, nodeValue); }
318
319 // Macro-in implementation accessors.
320 DOMNODEIMPL_IMPL(DOMCDATASectionImpl);
321 DOMCHILDIMPL_IMPL(DOMCDATASectionImpl);
322
323 XERCES_CPP_NAMESPACE_END
324