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