/src/libreoffice/unoxml/source/dom/element.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #include "element.hxx" |
21 | | |
22 | | #include <string.h> |
23 | | |
24 | | #include <memory> |
25 | | |
26 | | #include <osl/diagnose.h> |
27 | | #include <rtl/ustrbuf.hxx> |
28 | | |
29 | | #include <com/sun/star/xml/dom/DOMException.hpp> |
30 | | #include <com/sun/star/xml/dom/events/XMutationEvent.hpp> |
31 | | #include <com/sun/star/xml/sax/FastToken.hpp> |
32 | | |
33 | | #include <comphelper/attributelist.hxx> |
34 | | #include <comphelper/servicehelper.hxx> |
35 | | |
36 | | #include <eventdispatcher.hxx> |
37 | | #include <node.hxx> |
38 | | #include "attr.hxx" |
39 | | #include "elementlist.hxx" |
40 | | #include "attributesmap.hxx" |
41 | | #include "document.hxx" |
42 | | |
43 | | using namespace css::uno; |
44 | | using namespace css::xml::dom; |
45 | | using namespace css::xml::dom::events; |
46 | | using namespace css::xml::sax; |
47 | | |
48 | | namespace DOM |
49 | | { |
50 | | |
51 | | CElement::CElement(CDocument const& rDocument, ::osl::Mutex const& rMutex, |
52 | | xmlNodePtr const pNode) |
53 | 2.00M | : CElement_Base(rDocument, rMutex, NodeType_ELEMENT_NODE, pNode) |
54 | 2.00M | { |
55 | 2.00M | } |
56 | | |
57 | | void CElement::saxify(const Reference< XDocumentHandler >& i_xHandler) |
58 | 276 | { |
59 | 276 | if (!i_xHandler.is()) throw RuntimeException(); |
60 | 276 | rtl::Reference<comphelper::AttributeList> pAttrs = |
61 | 276 | new comphelper::AttributeList(); |
62 | | // add namespace definitions to attributes |
63 | 2.96k | for (xmlNsPtr pNs = m_aNodePtr->nsDef; pNs != nullptr; pNs = pNs->next) { |
64 | 2.69k | const xmlChar *pPrefix = pNs->prefix ? pNs->prefix : reinterpret_cast<const xmlChar*>(""); |
65 | 2.69k | OUString prefix(reinterpret_cast<const char*>(pPrefix), |
66 | 2.69k | strlen(reinterpret_cast<const char*>(pPrefix)), |
67 | 2.69k | RTL_TEXTENCODING_UTF8); |
68 | 2.69k | OUString name = (prefix.isEmpty()) |
69 | 2.69k | ? u"xmlns"_ustr : "xmlns:" + prefix; |
70 | 2.69k | const xmlChar *pHref = pNs->href; |
71 | 2.69k | OUString val(reinterpret_cast<const char*>(pHref), |
72 | 2.69k | strlen(reinterpret_cast<const char*>(pHref)), |
73 | 2.69k | RTL_TEXTENCODING_UTF8); |
74 | 2.69k | pAttrs->AddAttribute(name, val); |
75 | 2.69k | } |
76 | | // add attributes |
77 | 276 | for (xmlAttrPtr pAttr = m_aNodePtr->properties; |
78 | 414 | pAttr != nullptr; pAttr = pAttr->next) { |
79 | 138 | ::rtl::Reference<CNode> const pNode = GetOwnerDocument().GetCNode( |
80 | 138 | reinterpret_cast<xmlNodePtr>(pAttr)); |
81 | 138 | OSL_ENSURE(pNode != nullptr, "CNode::get returned 0"); |
82 | 138 | OUString prefix = pNode->getPrefix(); |
83 | 138 | OUString name = (prefix.isEmpty()) |
84 | 138 | ? pNode->getLocalName() |
85 | 138 | : prefix + ":" + pNode->getLocalName(); |
86 | 138 | OUString val = pNode->getNodeValue(); |
87 | 138 | pAttrs->AddAttribute(name, val); |
88 | 138 | } |
89 | 276 | OUString prefix = getPrefix(); |
90 | 276 | OUString name = (prefix.isEmpty()) |
91 | 276 | ? getLocalName() |
92 | 276 | : prefix + ":" + getLocalName(); |
93 | 276 | i_xHandler->startElement(name, pAttrs); |
94 | | // recurse |
95 | 276 | for (xmlNodePtr pChild = m_aNodePtr->children; |
96 | 552 | pChild != nullptr; pChild = pChild->next) { |
97 | 276 | ::rtl::Reference<CNode> const pNode( |
98 | 276 | GetOwnerDocument().GetCNode(pChild)); |
99 | 276 | OSL_ENSURE(pNode != nullptr, "CNode::get returned 0"); |
100 | 276 | pNode->saxify(i_xHandler); |
101 | 276 | } |
102 | 276 | i_xHandler->endElement(name); |
103 | 276 | } |
104 | | |
105 | | void CElement::fastSaxify( Context& i_rContext ) |
106 | 556k | { |
107 | 556k | if (!i_rContext.mxDocHandler.is()) throw RuntimeException(); |
108 | 556k | pushContext(i_rContext); |
109 | 556k | addNamespaces(i_rContext,m_aNodePtr); |
110 | | |
111 | | // add attributes |
112 | 556k | i_rContext.mxAttribList->clear(); |
113 | 556k | for (xmlAttrPtr pAttr = m_aNodePtr->properties; |
114 | 1.22M | pAttr != nullptr; pAttr = pAttr->next) { |
115 | 666k | ::rtl::Reference<CNode> const pNode = GetOwnerDocument().GetCNode( |
116 | 666k | reinterpret_cast<xmlNodePtr>(pAttr)); |
117 | 666k | OSL_ENSURE(pNode != nullptr, "CNode::get returned 0"); |
118 | | |
119 | 666k | const xmlChar* pName = pAttr->name; |
120 | 666k | sal_Int32 nAttributeToken=FastToken::DONTKNOW; |
121 | | |
122 | 666k | if( pAttr->ns && strlen(reinterpret_cast<char const *>(pAttr->ns->prefix)) ) |
123 | 2.02k | nAttributeToken = getTokenWithPrefix( i_rContext, |
124 | 2.02k | reinterpret_cast<char const *>(pAttr->ns->prefix), |
125 | 2.02k | reinterpret_cast<char const *>(pName) ); |
126 | 664k | else |
127 | 664k | nAttributeToken = getToken( i_rContext, reinterpret_cast<char const *>(pName) ); |
128 | | |
129 | 666k | if( nAttributeToken != FastToken::DONTKNOW ) |
130 | 665k | i_rContext.mxAttribList->add( nAttributeToken, |
131 | 665k | OUStringToOString(pNode->getNodeValue(), |
132 | 665k | RTL_TEXTENCODING_UTF8)); |
133 | 666k | } |
134 | | |
135 | 556k | const xmlChar* pPrefix = (m_aNodePtr->ns && m_aNodePtr->ns->prefix) ? m_aNodePtr->ns->prefix : reinterpret_cast<const xmlChar*>(""); |
136 | 556k | const xmlChar* pName = m_aNodePtr->name; |
137 | 556k | sal_Int32 nElementToken=FastToken::DONTKNOW; |
138 | 556k | if( strlen(reinterpret_cast<char const *>(pPrefix)) ) |
139 | 556k | nElementToken = getTokenWithPrefix( i_rContext, reinterpret_cast<char const *>(pPrefix), reinterpret_cast<char const *>(pName) ); |
140 | 0 | else |
141 | 0 | nElementToken = getToken( i_rContext, reinterpret_cast<char const *>(pName) ); |
142 | | |
143 | 556k | Reference<XFastContextHandler> xParentHandler(i_rContext.mxCurrentHandler); |
144 | 556k | try |
145 | 556k | { |
146 | 556k | Reference< XFastAttributeList > xAttr( i_rContext.mxAttribList ); |
147 | 556k | if( nElementToken == FastToken::DONTKNOW ) |
148 | 493 | { |
149 | 493 | const OUString aNamespace; |
150 | 493 | const OUString aElementName( reinterpret_cast<char const *>(pPrefix), |
151 | 493 | strlen(reinterpret_cast<char const *>(pPrefix)), |
152 | 493 | RTL_TEXTENCODING_UTF8 ); |
153 | | |
154 | 493 | if( xParentHandler.is() ) |
155 | 0 | i_rContext.mxCurrentHandler = xParentHandler->createUnknownChildContext( aNamespace, aElementName, xAttr ); |
156 | 493 | else |
157 | 493 | i_rContext.mxCurrentHandler = i_rContext.mxDocHandler->createUnknownChildContext( aNamespace, aElementName, xAttr ); |
158 | | |
159 | 493 | if( i_rContext.mxCurrentHandler.is() ) |
160 | 0 | i_rContext.mxCurrentHandler->startUnknownElement( aNamespace, aElementName, xAttr ); |
161 | 493 | } |
162 | 556k | else |
163 | 556k | { |
164 | 556k | if( xParentHandler.is() ) |
165 | 529k | i_rContext.mxCurrentHandler = xParentHandler->createFastChildContext( nElementToken, xAttr ); |
166 | 26.6k | else |
167 | 26.6k | i_rContext.mxCurrentHandler = i_rContext.mxDocHandler->createFastChildContext( nElementToken, xAttr ); |
168 | | |
169 | 556k | if( i_rContext.mxCurrentHandler.is() ) |
170 | 367k | i_rContext.mxCurrentHandler->startFastElement( nElementToken, xAttr ); |
171 | 556k | } |
172 | 556k | } |
173 | 556k | catch( Exception& ) |
174 | 556k | {} |
175 | | |
176 | | // recurse |
177 | 556k | for (xmlNodePtr pChild = m_aNodePtr->children; |
178 | 1.38M | pChild != nullptr; pChild = pChild->next) { |
179 | 830k | ::rtl::Reference<CNode> const pNode( |
180 | 830k | GetOwnerDocument().GetCNode(pChild)); |
181 | 830k | OSL_ENSURE(pNode != nullptr, "CNode::get returned 0"); |
182 | 830k | pNode->fastSaxify(i_rContext); |
183 | 830k | } |
184 | | |
185 | 556k | if( i_rContext.mxCurrentHandler.is() ) try |
186 | 367k | { |
187 | 367k | if( nElementToken != FastToken::DONTKNOW ) |
188 | 367k | i_rContext.mxCurrentHandler->endFastElement( nElementToken ); |
189 | 0 | else |
190 | 0 | { |
191 | 0 | const OUString aElementName( reinterpret_cast<char const *>(pPrefix), |
192 | 0 | strlen(reinterpret_cast<char const *>(pPrefix)), |
193 | 0 | RTL_TEXTENCODING_UTF8 ); |
194 | |
|
195 | 0 | i_rContext.mxCurrentHandler->endUnknownElement( u""_ustr, aElementName ); |
196 | 0 | } |
197 | 367k | } |
198 | 367k | catch( Exception& ) |
199 | 367k | {} |
200 | | |
201 | | // restore after children have been processed |
202 | 556k | i_rContext.mxCurrentHandler = std::move(xParentHandler); |
203 | 556k | popContext(i_rContext); |
204 | 556k | } |
205 | | |
206 | | bool CElement::IsChildTypeAllowed(NodeType const nodeType, NodeType const*const) |
207 | 792k | { |
208 | 792k | switch (nodeType) { |
209 | 572k | case NodeType_ELEMENT_NODE: |
210 | 792k | case NodeType_TEXT_NODE: |
211 | 792k | case NodeType_COMMENT_NODE: |
212 | 792k | case NodeType_PROCESSING_INSTRUCTION_NODE: |
213 | 792k | case NodeType_CDATA_SECTION_NODE: |
214 | 792k | case NodeType_ENTITY_REFERENCE_NODE: |
215 | 792k | return true; |
216 | 0 | case NodeType_ATTRIBUTE_NODE: |
217 | | /* this is not really allowed by the DOM spec, but this |
218 | | implementation has evidently supported it (by special case |
219 | | handling, so the attribute does not actually become a child) |
220 | | so allow it for backward compatibility */ |
221 | 0 | return true; |
222 | 0 | default: |
223 | 0 | return false; |
224 | 792k | } |
225 | 792k | } |
226 | | |
227 | | |
228 | | /** |
229 | | Retrieves an attribute value by name. |
230 | | return empty string if attribute is not set |
231 | | */ |
232 | | OUString SAL_CALL CElement::getAttribute(OUString const& name) |
233 | 0 | { |
234 | 0 | ::osl::MutexGuard const g(m_rMutex); |
235 | |
|
236 | 0 | if (nullptr == m_aNodePtr) { |
237 | 0 | return OUString(); |
238 | 0 | } |
239 | | // search properties |
240 | 0 | OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8); |
241 | 0 | std::shared_ptr<xmlChar const> const pValue( |
242 | 0 | xmlGetProp(m_aNodePtr, reinterpret_cast<xmlChar const *>(o1.getStr())), xmlFree); |
243 | 0 | OUString const ret( pValue |
244 | 0 | ? OUString(reinterpret_cast<char const*>(pValue.get()), |
245 | 0 | strlen(reinterpret_cast<char const*>(pValue.get())), |
246 | 0 | RTL_TEXTENCODING_UTF8) |
247 | 0 | : OUString() ); |
248 | 0 | return ret; |
249 | 0 | } |
250 | | |
251 | | /** |
252 | | Retrieves an attribute node by name. |
253 | | */ |
254 | | Reference< XAttr > SAL_CALL CElement::getAttributeNode(OUString const& name) |
255 | 0 | { |
256 | 0 | ::osl::MutexGuard const g(m_rMutex); |
257 | |
|
258 | 0 | if (nullptr == m_aNodePtr) { |
259 | 0 | return nullptr; |
260 | 0 | } |
261 | 0 | OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8); |
262 | 0 | xmlChar const*const pName = |
263 | 0 | reinterpret_cast<xmlChar const*>(o1.getStr()); |
264 | 0 | xmlAttrPtr const pAttr = xmlHasProp(m_aNodePtr, pName); |
265 | 0 | if (nullptr == pAttr) { |
266 | 0 | return nullptr; |
267 | 0 | } |
268 | 0 | Reference< XAttr > const xRet( |
269 | 0 | static_cast< XNode* >(GetOwnerDocument().GetCNode( |
270 | 0 | reinterpret_cast<xmlNodePtr>(pAttr)).get()), |
271 | 0 | UNO_QUERY_THROW); |
272 | 0 | return xRet; |
273 | 0 | } |
274 | | |
275 | | /** |
276 | | Retrieves an Attr node by local name and namespace URI. |
277 | | */ |
278 | | Reference< XAttr > SAL_CALL CElement::getAttributeNodeNS( |
279 | | const OUString& namespaceURI, const OUString& localName) |
280 | 0 | { |
281 | 0 | ::osl::MutexGuard const g(m_rMutex); |
282 | |
|
283 | 0 | if (nullptr == m_aNodePtr) { |
284 | 0 | return nullptr; |
285 | 0 | } |
286 | 0 | OString o1 = OUStringToOString(localName, RTL_TEXTENCODING_UTF8); |
287 | 0 | xmlChar const*const pName = |
288 | 0 | reinterpret_cast<xmlChar const*>(o1.getStr()); |
289 | 0 | OString o2 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8); |
290 | 0 | xmlChar const*const pNS = |
291 | 0 | reinterpret_cast<xmlChar const*>(o2.getStr()); |
292 | 0 | xmlAttrPtr const pAttr = xmlHasNsProp(m_aNodePtr, pName, pNS); |
293 | 0 | if (nullptr == pAttr) { |
294 | 0 | return nullptr; |
295 | 0 | } |
296 | 0 | Reference< XAttr > const xRet( |
297 | 0 | static_cast< XNode* >(GetOwnerDocument().GetCNode( |
298 | 0 | reinterpret_cast<xmlNodePtr>(pAttr)).get()), |
299 | 0 | UNO_QUERY_THROW); |
300 | 0 | return xRet; |
301 | 0 | } |
302 | | |
303 | | /** |
304 | | Retrieves an attribute value by local name and namespace URI. |
305 | | return empty string if attribute is not set |
306 | | */ |
307 | | OUString SAL_CALL |
308 | | CElement::getAttributeNS( |
309 | | OUString const& namespaceURI, OUString const& localName) |
310 | 111k | { |
311 | 111k | ::osl::MutexGuard const g(m_rMutex); |
312 | | |
313 | 111k | if (nullptr == m_aNodePtr) { |
314 | 0 | return OUString(); |
315 | 0 | } |
316 | 111k | OString o1 = OUStringToOString(localName, RTL_TEXTENCODING_UTF8); |
317 | 111k | xmlChar const*const pName = |
318 | 111k | reinterpret_cast<xmlChar const*>(o1.getStr()); |
319 | 111k | OString o2 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8); |
320 | 111k | xmlChar const*const pNS = |
321 | 111k | reinterpret_cast<xmlChar const*>(o2.getStr()); |
322 | 111k | std::shared_ptr<xmlChar const> const pValue( |
323 | 111k | xmlGetNsProp(m_aNodePtr, pName, pNS), xmlFree); |
324 | 111k | if (nullptr == pValue) { |
325 | 80.4k | return OUString(); |
326 | 80.4k | } |
327 | 30.9k | OUString const ret(reinterpret_cast<char const*>(pValue.get()), |
328 | 30.9k | strlen(reinterpret_cast<char const*>(pValue.get())), |
329 | 30.9k | RTL_TEXTENCODING_UTF8); |
330 | 30.9k | return ret; |
331 | 111k | } |
332 | | |
333 | | /** |
334 | | Returns a NodeList of all descendant Elements with a given tag name, |
335 | | in the order in which they are |
336 | | encountered in a preorder traversal of this Element tree. |
337 | | */ |
338 | | Reference< XNodeList > SAL_CALL |
339 | | CElement::getElementsByTagName(OUString const& rLocalName) |
340 | 0 | { |
341 | 0 | ::osl::MutexGuard const g(m_rMutex); |
342 | |
|
343 | 0 | Reference< XNodeList > const xList( |
344 | 0 | new CElementList(this, m_rMutex, rLocalName)); |
345 | 0 | return xList; |
346 | 0 | } |
347 | | |
348 | | /** |
349 | | Returns a NodeList of all the descendant Elements with a given local |
350 | | name and namespace URI in the order in which they are encountered in |
351 | | a preorder traversal of this Element tree. |
352 | | */ |
353 | | Reference< XNodeList > SAL_CALL |
354 | | CElement::getElementsByTagNameNS( |
355 | | OUString const& rNamespaceURI, OUString const& rLocalName) |
356 | 0 | { |
357 | 0 | ::osl::MutexGuard const g(m_rMutex); |
358 | |
|
359 | 0 | Reference< XNodeList > const xList( |
360 | 0 | new CElementList(this, m_rMutex, rLocalName, &rNamespaceURI)); |
361 | 0 | return xList; |
362 | 0 | } |
363 | | |
364 | | /** |
365 | | The name of the element. |
366 | | */ |
367 | | OUString SAL_CALL CElement::getTagName() |
368 | 97.0k | { |
369 | 97.0k | ::osl::MutexGuard const g(m_rMutex); |
370 | | |
371 | 97.0k | if (nullptr == m_aNodePtr) { |
372 | 0 | return OUString(); |
373 | 0 | } |
374 | 97.0k | OUString const ret(reinterpret_cast<char const *>(m_aNodePtr->name), |
375 | 97.0k | strlen(reinterpret_cast<char const *>(m_aNodePtr->name)), RTL_TEXTENCODING_UTF8); |
376 | 97.0k | return ret; |
377 | 97.0k | } |
378 | | |
379 | | |
380 | | /** |
381 | | Returns true when an attribute with a given name is specified on this |
382 | | element or has a default value, false otherwise. |
383 | | */ |
384 | | sal_Bool SAL_CALL CElement::hasAttribute(OUString const& name) |
385 | 0 | { |
386 | 0 | ::osl::MutexGuard const g(m_rMutex); |
387 | |
|
388 | 0 | OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8); |
389 | 0 | xmlChar const *pName = reinterpret_cast<xmlChar const *>(o1.getStr()); |
390 | 0 | return (m_aNodePtr != nullptr && xmlHasProp(m_aNodePtr, pName) != nullptr); |
391 | 0 | } |
392 | | |
393 | | /** |
394 | | Returns true when an attribute with a given local name and namespace |
395 | | URI is specified on this element or has a default value, false otherwise. |
396 | | */ |
397 | | sal_Bool SAL_CALL CElement::hasAttributeNS( |
398 | | OUString const& namespaceURI, OUString const& localName) |
399 | 0 | { |
400 | 0 | ::osl::MutexGuard const g(m_rMutex); |
401 | |
|
402 | 0 | OString o1 = OUStringToOString(localName, RTL_TEXTENCODING_UTF8); |
403 | 0 | xmlChar const *pName = reinterpret_cast<xmlChar const *>(o1.getStr()); |
404 | 0 | OString o2 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8); |
405 | 0 | xmlChar const *pNs = reinterpret_cast<xmlChar const *>(o2.getStr()); |
406 | 0 | return (m_aNodePtr != nullptr && xmlHasNsProp(m_aNodePtr, pName, pNs) != nullptr); |
407 | 0 | } |
408 | | |
409 | | /** |
410 | | Removes an attribute by name. |
411 | | */ |
412 | | void SAL_CALL CElement::removeAttribute(OUString const& name) |
413 | 0 | { |
414 | 0 | ::osl::MutexGuard const g(m_rMutex); |
415 | |
|
416 | 0 | if (nullptr == m_aNodePtr) { |
417 | 0 | return; |
418 | 0 | } |
419 | 0 | OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8); |
420 | 0 | xmlChar const*const pName = |
421 | 0 | reinterpret_cast<xmlChar const*>(o1.getStr()); |
422 | 0 | xmlAttrPtr const pAttr = xmlHasProp(m_aNodePtr, pName); |
423 | 0 | if (0 == xmlUnsetProp(m_aNodePtr, pName)) { |
424 | 0 | ::rtl::Reference<CNode> const pCNode(GetOwnerDocument().GetCNode( |
425 | 0 | reinterpret_cast<xmlNodePtr>(pAttr), false)); |
426 | 0 | if (pCNode.is()) { |
427 | 0 | pCNode->invalidate(); // freed by xmlUnsetProp |
428 | 0 | } |
429 | 0 | } |
430 | 0 | } |
431 | | |
432 | | /** |
433 | | Removes an attribute by local name and namespace URI. |
434 | | */ |
435 | | void SAL_CALL CElement::removeAttributeNS( |
436 | | OUString const& namespaceURI, OUString const& localName) |
437 | 0 | { |
438 | 0 | ::osl::MutexGuard const g(m_rMutex); |
439 | |
|
440 | 0 | if (nullptr == m_aNodePtr) { |
441 | 0 | return; |
442 | 0 | } |
443 | 0 | OString o1 = OUStringToOString(localName, RTL_TEXTENCODING_UTF8); |
444 | 0 | xmlChar const*const pName = |
445 | 0 | reinterpret_cast<xmlChar const*>(o1.getStr()); |
446 | 0 | OString o2 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8); |
447 | 0 | xmlChar const*const pURI = |
448 | 0 | reinterpret_cast<xmlChar const*>(o2.getStr()); |
449 | 0 | xmlNsPtr const pNs = |
450 | 0 | xmlSearchNsByHref(m_aNodePtr->doc, m_aNodePtr, pURI); |
451 | 0 | xmlAttrPtr const pAttr = xmlHasNsProp(m_aNodePtr, pName, pURI); |
452 | 0 | if (0 == xmlUnsetNsProp(m_aNodePtr, pNs, pName)) { |
453 | 0 | ::rtl::Reference<CNode> const pCNode(GetOwnerDocument().GetCNode( |
454 | 0 | reinterpret_cast<xmlNodePtr>(pAttr), false)); |
455 | 0 | if (pCNode.is()) { |
456 | 0 | pCNode->invalidate(); // freed by xmlUnsetNsProp |
457 | 0 | } |
458 | 0 | } |
459 | 0 | } |
460 | | |
461 | | /** |
462 | | Removes the specified attribute node. |
463 | | */ |
464 | | Reference< XAttr > SAL_CALL |
465 | | CElement::removeAttributeNode(Reference< XAttr > const& oldAttr) |
466 | 0 | { |
467 | 0 | ::osl::MutexGuard const g(m_rMutex); |
468 | |
|
469 | 0 | if (nullptr == m_aNodePtr) { |
470 | 0 | return nullptr; |
471 | 0 | } |
472 | | |
473 | 0 | ::rtl::Reference<CNode> const pCNode( |
474 | 0 | dynamic_cast<CNode*>(oldAttr.get())); |
475 | 0 | if (!pCNode.is()) { throw RuntimeException(); } |
476 | | |
477 | 0 | xmlNodePtr const pNode = pCNode->GetNodePtr(); |
478 | 0 | xmlAttrPtr const pAttr = reinterpret_cast<xmlAttrPtr>(pNode); |
479 | 0 | if (!pAttr) { throw RuntimeException(); } |
480 | | |
481 | 0 | if (pAttr->parent != m_aNodePtr) |
482 | 0 | { |
483 | 0 | DOMException e; |
484 | 0 | e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; |
485 | 0 | throw e; |
486 | 0 | } |
487 | 0 | if (pAttr->doc != m_aNodePtr->doc) |
488 | 0 | { |
489 | 0 | DOMException e; |
490 | 0 | e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR; |
491 | 0 | throw e; |
492 | 0 | } |
493 | | |
494 | 0 | Reference< XAttr > aAttr; |
495 | 0 | if (!oldAttr->getNamespaceURI().isEmpty()) { |
496 | 0 | OUStringBuffer qname(oldAttr->getPrefix()); |
497 | 0 | if (!qname.isEmpty()) { |
498 | 0 | qname.append(':'); |
499 | 0 | } |
500 | 0 | qname.append(oldAttr->getName()); |
501 | 0 | aAttr = GetOwnerDocument().createAttributeNS( |
502 | 0 | oldAttr->getNamespaceURI(), qname.makeStringAndClear()); |
503 | 0 | } else { |
504 | 0 | aAttr = GetOwnerDocument().createAttribute(oldAttr->getName()); |
505 | 0 | } |
506 | 0 | aAttr->setValue(oldAttr->getValue()); |
507 | 0 | xmlRemoveProp(pAttr); |
508 | 0 | pCNode->invalidate(); // freed by xmlRemoveProp |
509 | |
|
510 | 0 | return aAttr; |
511 | 0 | } |
512 | | |
513 | | /** |
514 | | Adds a new attribute node. |
515 | | */ |
516 | | Reference< XAttr > |
517 | | CElement::setAttributeNode_Impl_Lock( |
518 | | Reference< XAttr > const& xNewAttr, bool const bNS) |
519 | 0 | { |
520 | 0 | if (xNewAttr->getOwnerDocument() != getOwnerDocument()) { |
521 | 0 | DOMException e; |
522 | 0 | e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR; |
523 | 0 | throw e; |
524 | 0 | } |
525 | | |
526 | 0 | ::osl::ClearableMutexGuard guard(m_rMutex); |
527 | |
|
528 | 0 | if (nullptr == m_aNodePtr) { |
529 | 0 | throw RuntimeException(); |
530 | 0 | } |
531 | | |
532 | | // get the implementation |
533 | 0 | CAttr *const pCAttr = dynamic_cast<CAttr*>(xNewAttr.get()); |
534 | 0 | if (!pCAttr) { throw RuntimeException(); } |
535 | 0 | xmlAttrPtr const pAttr = |
536 | 0 | reinterpret_cast<xmlAttrPtr>(pCAttr->GetNodePtr()); |
537 | 0 | if (!pAttr) { throw RuntimeException(); } |
538 | | |
539 | | // check whether the attribute is not in use by another element |
540 | 0 | if (pAttr->parent) { |
541 | 0 | DOMException e; |
542 | 0 | e.Code = DOMExceptionType_INUSE_ATTRIBUTE_ERR; |
543 | 0 | throw e; |
544 | 0 | } |
545 | | |
546 | 0 | xmlAttrPtr res = nullptr; |
547 | 0 | xmlChar const*const pContent( |
548 | 0 | (pAttr->children) ? pAttr->children->content : nullptr); |
549 | |
|
550 | 0 | if (bNS) { |
551 | 0 | xmlNsPtr const pNs( pCAttr->GetNamespace(m_aNodePtr) ); |
552 | 0 | res = xmlNewNsProp(m_aNodePtr, pNs, pAttr->name, pContent); |
553 | 0 | } else { |
554 | 0 | res = xmlNewProp(m_aNodePtr, pAttr->name, pContent); |
555 | 0 | } |
556 | | |
557 | | // get the new attr node |
558 | 0 | Reference< XAttr > const xAttr( |
559 | 0 | static_cast< XNode* >(GetOwnerDocument().GetCNode( |
560 | 0 | reinterpret_cast<xmlNodePtr>(res)).get()), |
561 | 0 | UNO_QUERY_THROW); |
562 | | |
563 | | // attribute addition event |
564 | | // dispatch DOMAttrModified event |
565 | 0 | Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY); |
566 | 0 | Reference< XMutationEvent > event(docevent->createEvent( |
567 | 0 | u"DOMAttrModified"_ustr), UNO_QUERY); |
568 | 0 | event->initMutationEvent(u"DOMAttrModified"_ustr, |
569 | 0 | true, false, xAttr, |
570 | 0 | OUString(), xAttr->getValue(), xAttr->getName(), |
571 | 0 | AttrChangeType_ADDITION); |
572 | |
|
573 | 0 | guard.clear(); // release mutex before calling event handlers |
574 | |
|
575 | 0 | dispatchEvent(event); |
576 | 0 | dispatchSubtreeModified(); |
577 | |
|
578 | 0 | return xAttr; |
579 | 0 | } |
580 | | |
581 | | Reference< XAttr > |
582 | | CElement::setAttributeNode(const Reference< XAttr >& newAttr) |
583 | 0 | { |
584 | 0 | return setAttributeNode_Impl_Lock(newAttr, false); |
585 | 0 | } |
586 | | |
587 | | /** |
588 | | Adds a new attribute. |
589 | | */ |
590 | | Reference< XAttr > |
591 | | CElement::setAttributeNodeNS(const Reference< XAttr >& newAttr) |
592 | 0 | { |
593 | 0 | return setAttributeNode_Impl_Lock(newAttr, true); |
594 | 0 | } |
595 | | |
596 | | /** |
597 | | Adds a new attribute. |
598 | | */ |
599 | | void SAL_CALL |
600 | | CElement::setAttribute(OUString const& name, OUString const& value) |
601 | 11.1k | { |
602 | 11.1k | ::osl::ClearableMutexGuard guard(m_rMutex); |
603 | | |
604 | 11.1k | OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8); |
605 | 11.1k | xmlChar const *pName = reinterpret_cast<xmlChar const *>(o1.getStr()); |
606 | 11.1k | OString o2 = OUStringToOString(value, RTL_TEXTENCODING_UTF8); |
607 | 11.1k | xmlChar const *pValue = reinterpret_cast<xmlChar const *>(o2.getStr()); |
608 | | |
609 | 11.1k | if (nullptr == m_aNodePtr) { |
610 | 0 | throw RuntimeException(); |
611 | 0 | } |
612 | 11.1k | OUString oldValue; |
613 | 11.1k | AttrChangeType aChangeType = AttrChangeType_MODIFICATION; |
614 | 11.1k | std::shared_ptr<xmlChar const> const pOld( |
615 | 11.1k | xmlGetProp(m_aNodePtr, pName), xmlFree); |
616 | 11.1k | if (pOld == nullptr) { |
617 | 11.1k | aChangeType = AttrChangeType_ADDITION; |
618 | 11.1k | xmlNewProp(m_aNodePtr, pName, pValue); |
619 | 11.1k | } else { |
620 | 52 | oldValue = OUString(reinterpret_cast<char const*>(pOld.get()), |
621 | 52 | strlen(reinterpret_cast<char const*>(pOld.get())), |
622 | 52 | RTL_TEXTENCODING_UTF8); |
623 | 52 | xmlSetProp(m_aNodePtr, pName, pValue); |
624 | 52 | } |
625 | | |
626 | 11.1k | CDocument& rDocument(GetOwnerDocument()); |
627 | 11.1k | if (rDocument.GetEventDispatcher().hasListeners()) |
628 | 0 | { |
629 | | // dispatch DOMAttrModified event |
630 | 0 | Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY); |
631 | 0 | Reference< XMutationEvent > event(docevent->createEvent( |
632 | 0 | u"DOMAttrModified"_ustr), UNO_QUERY); |
633 | 0 | event->initMutationEvent(u"DOMAttrModified"_ustr, |
634 | 0 | true, false, |
635 | 0 | getAttributeNode(name), |
636 | 0 | oldValue, value, name, aChangeType); |
637 | |
|
638 | 0 | guard.clear(); // release mutex before calling event handlers |
639 | 0 | dispatchEvent(event); |
640 | 0 | dispatchSubtreeModified(); |
641 | 0 | } |
642 | 11.1k | } |
643 | | |
644 | | /** |
645 | | Adds a new attribute. |
646 | | */ |
647 | | void SAL_CALL |
648 | | CElement::setAttributeNS(OUString const& namespaceURI, |
649 | | OUString const& qualifiedName, OUString const& value) |
650 | 216k | { |
651 | 216k | if (namespaceURI.isEmpty()) throw RuntimeException(); |
652 | | |
653 | 216k | ::osl::ClearableMutexGuard guard(m_rMutex); |
654 | | |
655 | 216k | OString o1, o2, o3, o4, o5; |
656 | 216k | xmlChar const *pPrefix = nullptr; |
657 | 216k | xmlChar const *pLName = nullptr; |
658 | 216k | o1 = OUStringToOString(qualifiedName, RTL_TEXTENCODING_UTF8); |
659 | 216k | xmlChar const *pQName = reinterpret_cast<xmlChar const *>(o1.getStr()); |
660 | 216k | sal_Int32 idx = qualifiedName.indexOf(':'); |
661 | 216k | if (idx != -1) |
662 | 216k | { |
663 | 216k | o2 = OUStringToOString( |
664 | 216k | qualifiedName.subView(0,idx), |
665 | 216k | RTL_TEXTENCODING_UTF8); |
666 | 216k | pPrefix = reinterpret_cast<xmlChar const *>(o2.getStr()); |
667 | 216k | o3 = OUStringToOString( |
668 | 216k | qualifiedName.subView(idx+1), |
669 | 216k | RTL_TEXTENCODING_UTF8); |
670 | 216k | pLName = reinterpret_cast<xmlChar const *>(o3.getStr()); |
671 | 216k | } else { |
672 | 0 | pPrefix = reinterpret_cast<xmlChar const *>(""); |
673 | 0 | pLName = pQName; |
674 | 0 | } |
675 | 216k | o4 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8); |
676 | 216k | o5 = OUStringToOString(value, RTL_TEXTENCODING_UTF8); |
677 | 216k | xmlChar const *pURI= reinterpret_cast<xmlChar const *>(o4.getStr()); |
678 | 216k | xmlChar const *pValue = reinterpret_cast<xmlChar const *>(o5.getStr()); |
679 | | |
680 | 216k | if (nullptr == m_aNodePtr) { |
681 | 0 | throw RuntimeException(); |
682 | 0 | } |
683 | | |
684 | | //find the right namespace |
685 | 216k | xmlNsPtr pNs = xmlSearchNs(m_aNodePtr->doc, m_aNodePtr, pPrefix); |
686 | | // if no namespace found, create a new one |
687 | 216k | if (pNs == nullptr) { |
688 | 3.04k | pNs = xmlNewNs(m_aNodePtr, pURI, pPrefix); |
689 | 3.04k | } |
690 | | |
691 | 216k | if (strcmp(reinterpret_cast<char const *>(pNs->href), reinterpret_cast<char const *>(pURI)) != 0) { |
692 | | // ambiguous ns prefix |
693 | 95 | throw RuntimeException(); |
694 | 95 | } |
695 | | |
696 | | // found namespace matches |
697 | | |
698 | 215k | OUString oldValue; |
699 | 215k | AttrChangeType aChangeType = AttrChangeType_MODIFICATION; |
700 | 215k | std::shared_ptr<xmlChar const> const pOld( |
701 | 215k | xmlGetNsProp(m_aNodePtr, pLName, pNs->href), xmlFree); |
702 | 215k | if (pOld == nullptr) { |
703 | 215k | aChangeType = AttrChangeType_ADDITION; |
704 | 215k | xmlNewNsProp(m_aNodePtr, pNs, pLName, pValue); |
705 | 215k | } else { |
706 | 0 | oldValue = OUString(reinterpret_cast<char const*>(pOld.get()), |
707 | 0 | strlen(reinterpret_cast<char const*>(pOld.get())), |
708 | 0 | RTL_TEXTENCODING_UTF8); |
709 | 0 | xmlSetNsProp(m_aNodePtr, pNs, pLName, pValue); |
710 | 0 | } |
711 | | |
712 | 215k | CDocument& rDocument(GetOwnerDocument()); |
713 | 215k | if (rDocument.GetEventDispatcher().hasListeners()) |
714 | 0 | { |
715 | | // dispatch DOMAttrModified event |
716 | 0 | Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY); |
717 | 0 | Reference< XMutationEvent > event(docevent->createEvent( |
718 | 0 | u"DOMAttrModified"_ustr), UNO_QUERY); |
719 | 0 | event->initMutationEvent( |
720 | 0 | u"DOMAttrModified"_ustr, true, false, |
721 | 0 | getAttributeNodeNS(namespaceURI, OUString(reinterpret_cast<char const *>(pLName), strlen(reinterpret_cast<char const *>(pLName)), RTL_TEXTENCODING_UTF8)), |
722 | 0 | oldValue, value, qualifiedName, aChangeType); |
723 | |
|
724 | 0 | guard.clear(); // release mutex before calling event handlers |
725 | 0 | dispatchEvent(event); |
726 | 0 | dispatchSubtreeModified(); |
727 | 0 | } |
728 | 215k | } |
729 | | |
730 | | Reference< XNamedNodeMap > SAL_CALL |
731 | | CElement::getAttributes() |
732 | 0 | { |
733 | 0 | ::osl::MutexGuard const g(m_rMutex); |
734 | |
|
735 | 0 | Reference< XNamedNodeMap > const xMap( |
736 | 0 | new CAttributesMap(this, m_rMutex)); |
737 | 0 | return xMap; |
738 | 0 | } |
739 | | |
740 | | OUString SAL_CALL CElement::getNodeName() |
741 | 1.14M | { |
742 | 1.14M | return getLocalName(); |
743 | 1.14M | } |
744 | | |
745 | | OUString SAL_CALL CElement::getLocalName() |
746 | 1.14M | { |
747 | 1.14M | ::osl::MutexGuard const g(m_rMutex); |
748 | | |
749 | 1.14M | OUString aName; |
750 | 1.14M | if (m_aNodePtr != nullptr) |
751 | 1.14M | { |
752 | 1.14M | const xmlChar* pName = m_aNodePtr->name; |
753 | 1.14M | aName = OUString(reinterpret_cast<const char*>(pName), strlen(reinterpret_cast<const char*>(pName)), RTL_TEXTENCODING_UTF8); |
754 | 1.14M | } |
755 | 1.14M | return aName; |
756 | 1.14M | } |
757 | | |
758 | | OUString SAL_CALL CElement::getNodeValue() |
759 | 0 | { |
760 | 0 | return OUString(); |
761 | 0 | } |
762 | | } |
763 | | |
764 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |