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