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 0 : CElement::CElement(CDocument const& rDocument, ::osl::Mutex const& rMutex,
45 : xmlNodePtr const pNode)
46 0 : : CElement_Base(rDocument, rMutex, NodeType_ELEMENT_NODE, pNode)
47 : {
48 0 : }
49 :
50 0 : void CElement::saxify(const Reference< XDocumentHandler >& i_xHandler)
51 : {
52 0 : if (!i_xHandler.is()) throw RuntimeException();
53 : comphelper::AttributeList *pAttrs =
54 0 : new comphelper::AttributeList();
55 0 : OUString type = "";
56 : // add namespace definitions to attributes
57 0 : for (xmlNsPtr pNs = m_aNodePtr->nsDef; pNs != 0; pNs = pNs->next) {
58 0 : const xmlChar *pPrefix = pNs->prefix ? pNs->prefix : (const xmlChar*)"";
59 : OUString prefix(reinterpret_cast<const sal_Char*>(pPrefix),
60 0 : strlen(reinterpret_cast<const char*>(pPrefix)),
61 0 : RTL_TEXTENCODING_UTF8);
62 0 : OUString name = (prefix.isEmpty())
63 0 : ? OUString( "xmlns" ) : OUString( "xmlns:" ) + prefix;
64 0 : const xmlChar *pHref = pNs->href;
65 : OUString val(reinterpret_cast<const sal_Char*>(pHref),
66 0 : strlen(reinterpret_cast<const char*>(pHref)),
67 0 : RTL_TEXTENCODING_UTF8);
68 0 : pAttrs->AddAttribute(name, type, val);
69 0 : }
70 : // add attributes
71 0 : for (xmlAttrPtr pAttr = m_aNodePtr->properties;
72 : pAttr != 0; pAttr = pAttr->next) {
73 0 : ::rtl::Reference<CNode> const pNode = GetOwnerDocument().GetCNode(
74 0 : reinterpret_cast<xmlNodePtr>(pAttr));
75 : OSL_ENSURE(pNode != 0, "CNode::get returned 0");
76 0 : OUString prefix = pNode->getPrefix();
77 0 : OUString name = (prefix.isEmpty())
78 0 : ? pNode->getLocalName()
79 0 : : prefix + OUString(':') + pNode->getLocalName();
80 0 : OUString val = pNode->getNodeValue();
81 0 : pAttrs->AddAttribute(name, type, val);
82 0 : }
83 0 : OUString prefix = getPrefix();
84 0 : OUString name = (prefix.isEmpty())
85 0 : ? getLocalName()
86 0 : : prefix + OUString(':') + getLocalName();
87 0 : Reference< XAttributeList > xAttrList(pAttrs);
88 0 : i_xHandler->startElement(name, xAttrList);
89 : // recurse
90 0 : for (xmlNodePtr pChild = m_aNodePtr->children;
91 : pChild != 0; pChild = pChild->next) {
92 : ::rtl::Reference<CNode> const pNode(
93 0 : GetOwnerDocument().GetCNode(pChild));
94 : OSL_ENSURE(pNode != 0, "CNode::get returned 0");
95 0 : pNode->saxify(i_xHandler);
96 0 : }
97 0 : i_xHandler->endElement(name);
98 0 : }
99 :
100 0 : void CElement::fastSaxify( Context& i_rContext )
101 : {
102 0 : if (!i_rContext.mxDocHandler.is()) throw RuntimeException();
103 0 : pushContext(i_rContext);
104 0 : addNamespaces(i_rContext,m_aNodePtr);
105 :
106 : // add attributes
107 0 : i_rContext.mxAttribList->clear();
108 0 : for (xmlAttrPtr pAttr = m_aNodePtr->properties;
109 : pAttr != 0; pAttr = pAttr->next) {
110 0 : ::rtl::Reference<CNode> const pNode = GetOwnerDocument().GetCNode(
111 0 : reinterpret_cast<xmlNodePtr>(pAttr));
112 : OSL_ENSURE(pNode != 0, "CNode::get returned 0");
113 :
114 0 : const xmlChar* xName = pAttr->name;
115 0 : sal_Int32 nAttributeToken=FastToken::DONTKNOW;
116 :
117 0 : 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 0 : nAttributeToken = getToken( i_rContext, (sal_Char*)xName );
123 :
124 0 : if( nAttributeToken != FastToken::DONTKNOW )
125 : i_rContext.mxAttribList->add( nAttributeToken,
126 0 : OUStringToOString(pNode->getNodeValue(),
127 0 : RTL_TEXTENCODING_UTF8));
128 0 : }
129 :
130 0 : const xmlChar* xPrefix = m_aNodePtr->ns ? m_aNodePtr->ns->prefix : (const xmlChar*)"";
131 0 : const xmlChar* xName = m_aNodePtr->name;
132 0 : sal_Int32 nElementToken=FastToken::DONTKNOW;
133 0 : if( strlen((char*)xPrefix) )
134 0 : nElementToken = getTokenWithPrefix( i_rContext, (sal_Char*)xPrefix, (sal_Char*)xName );
135 : else
136 0 : nElementToken = getToken( i_rContext, (sal_Char*)xName );
137 :
138 0 : Reference<XFastContextHandler> xParentHandler(i_rContext.mxCurrentHandler);
139 : try
140 : {
141 0 : Reference< XFastAttributeList > xAttr( i_rContext.mxAttribList.get() );
142 0 : if( nElementToken == FastToken::DONTKNOW )
143 : {
144 0 : const OUString aNamespace;
145 : const OUString aElementName( (sal_Char*)xPrefix,
146 0 : strlen((char*)xPrefix),
147 0 : RTL_TEXTENCODING_UTF8 );
148 :
149 0 : if( xParentHandler.is() )
150 0 : i_rContext.mxCurrentHandler = xParentHandler->createUnknownChildContext( aNamespace, aElementName, xAttr );
151 : else
152 0 : i_rContext.mxCurrentHandler = i_rContext.mxDocHandler->createUnknownChildContext( aNamespace, aElementName, xAttr );
153 :
154 0 : if( i_rContext.mxCurrentHandler.is() )
155 0 : i_rContext.mxCurrentHandler->startUnknownElement( aNamespace, aElementName, xAttr );
156 : }
157 : else
158 : {
159 0 : if( xParentHandler.is() )
160 0 : i_rContext.mxCurrentHandler = xParentHandler->createFastChildContext( nElementToken, xAttr );
161 : else
162 0 : i_rContext.mxCurrentHandler = i_rContext.mxDocHandler->createFastChildContext( nElementToken, xAttr );
163 :
164 0 : if( i_rContext.mxCurrentHandler.is() )
165 0 : i_rContext.mxCurrentHandler->startFastElement( nElementToken, xAttr );
166 0 : }
167 : }
168 0 : catch( Exception& )
169 : {}
170 :
171 : // recurse
172 0 : for (xmlNodePtr pChild = m_aNodePtr->children;
173 : pChild != 0; pChild = pChild->next) {
174 : ::rtl::Reference<CNode> const pNode(
175 0 : GetOwnerDocument().GetCNode(pChild));
176 : OSL_ENSURE(pNode != 0, "CNode::get returned 0");
177 0 : pNode->fastSaxify(i_rContext);
178 0 : }
179 :
180 0 : if( i_rContext.mxCurrentHandler.is() ) try
181 : {
182 0 : if( nElementToken != FastToken::DONTKNOW )
183 0 : 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 0 : i_rContext.mxCurrentHandler = xParentHandler;
199 0 : popContext(i_rContext);
200 0 : }
201 :
202 0 : bool CElement::IsChildTypeAllowed(NodeType const nodeType)
203 : {
204 0 : 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 0 : 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 0 : 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 0 : OUString SAL_CALL CElement::getAttribute(OUString const& name)
229 : throw (RuntimeException, std::exception)
230 : {
231 0 : ::osl::MutexGuard const g(m_rMutex);
232 :
233 0 : if (0 == m_aNodePtr) {
234 0 : return OUString();
235 : }
236 : // search properties
237 0 : OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8);
238 : ::boost::shared_ptr<xmlChar const> const pValue(
239 0 : xmlGetProp(m_aNodePtr, (xmlChar*)o1.getStr()), xmlFree);
240 : OUString const ret( (pValue)
241 0 : ? OUString(reinterpret_cast<sal_Char const*>(pValue.get()),
242 0 : strlen(reinterpret_cast<char const*>(pValue.get())),
243 : RTL_TEXTENCODING_UTF8)
244 0 : : OUString() );
245 0 : return ret;
246 : }
247 :
248 : /**
249 : Retrieves an attribute node by name.
250 : */
251 0 : Reference< XAttr > SAL_CALL CElement::getAttributeNode(OUString const& name)
252 : throw (RuntimeException, std::exception)
253 : {
254 0 : ::osl::MutexGuard const g(m_rMutex);
255 :
256 0 : if (0 == m_aNodePtr) {
257 0 : return 0;
258 : }
259 0 : OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8);
260 : xmlChar const*const pName =
261 0 : reinterpret_cast<xmlChar const*>(o1.getStr());
262 0 : xmlAttrPtr const pAttr = xmlHasProp(m_aNodePtr, pName);
263 0 : if (0 == pAttr) {
264 0 : return 0;
265 : }
266 : Reference< XAttr > const xRet(
267 0 : static_cast< XNode* >(GetOwnerDocument().GetCNode(
268 0 : reinterpret_cast<xmlNodePtr>(pAttr)).get()),
269 0 : UNO_QUERY_THROW);
270 0 : return xRet;
271 : }
272 :
273 : /**
274 : Retrieves an Attr node by local name and namespace URI.
275 : */
276 0 : Reference< XAttr > SAL_CALL CElement::getAttributeNodeNS(
277 : const OUString& namespaceURI, const OUString& localName)
278 : throw (RuntimeException, std::exception)
279 : {
280 0 : ::osl::MutexGuard const g(m_rMutex);
281 :
282 0 : if (0 == m_aNodePtr) {
283 0 : return 0;
284 : }
285 0 : OString o1 = OUStringToOString(localName, RTL_TEXTENCODING_UTF8);
286 : xmlChar const*const pName =
287 0 : reinterpret_cast<xmlChar const*>(o1.getStr());
288 0 : OString o2 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8);
289 : xmlChar const*const pNS =
290 0 : reinterpret_cast<xmlChar const*>(o2.getStr());
291 0 : xmlAttrPtr const pAttr = xmlHasNsProp(m_aNodePtr, pName, pNS);
292 0 : if (0 == pAttr) {
293 0 : return 0;
294 : }
295 : Reference< XAttr > const xRet(
296 0 : static_cast< XNode* >(GetOwnerDocument().GetCNode(
297 0 : reinterpret_cast<xmlNodePtr>(pAttr)).get()),
298 0 : UNO_QUERY_THROW);
299 0 : 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 0 : CElement::getAttributeNS(
308 : OUString const& namespaceURI, OUString const& localName)
309 : throw (RuntimeException, std::exception)
310 : {
311 0 : ::osl::MutexGuard const g(m_rMutex);
312 :
313 0 : if (0 == m_aNodePtr) {
314 0 : return OUString();
315 : }
316 0 : OString o1 = OUStringToOString(localName, RTL_TEXTENCODING_UTF8);
317 : xmlChar const*const pName =
318 0 : reinterpret_cast<xmlChar const*>(o1.getStr());
319 0 : OString o2 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8);
320 : xmlChar const*const pNS =
321 0 : reinterpret_cast<xmlChar const*>(o2.getStr());
322 : ::boost::shared_ptr<xmlChar const> const pValue(
323 0 : xmlGetNsProp(m_aNodePtr, pName, pNS), xmlFree);
324 0 : if (0 == pValue) {
325 0 : return OUString();
326 : }
327 0 : OUString const ret(reinterpret_cast<sal_Char const*>(pValue.get()),
328 0 : strlen(reinterpret_cast<char const*>(pValue.get())),
329 0 : RTL_TEXTENCODING_UTF8);
330 0 : 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 0 : CElement::getElementsByTagName(OUString const& rLocalName)
340 : throw (RuntimeException, std::exception)
341 : {
342 0 : ::osl::MutexGuard const g(m_rMutex);
343 :
344 : Reference< XNodeList > const xList(
345 0 : new CElementList(this, m_rMutex, rLocalName));
346 0 : 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 0 : CElement::getElementsByTagNameNS(
356 : OUString const& rNamespaceURI, OUString const& rLocalName)
357 : throw (RuntimeException, std::exception)
358 : {
359 0 : ::osl::MutexGuard const g(m_rMutex);
360 :
361 : Reference< XNodeList > const xList(
362 0 : new CElementList(this, m_rMutex, rLocalName, &rNamespaceURI));
363 0 : return xList;
364 : }
365 :
366 : /**
367 : The name of the element.
368 : */
369 0 : OUString SAL_CALL CElement::getTagName()
370 : throw (RuntimeException, std::exception)
371 : {
372 0 : ::osl::MutexGuard const g(m_rMutex);
373 :
374 0 : if (0 == m_aNodePtr) {
375 0 : return OUString();
376 : }
377 : OUString const ret((sal_Char*)m_aNodePtr->name,
378 0 : strlen((char*)m_aNodePtr->name), RTL_TEXTENCODING_UTF8);
379 0 : 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 0 : sal_Bool SAL_CALL CElement::hasAttribute(OUString const& name)
388 : throw (RuntimeException, std::exception)
389 : {
390 0 : ::osl::MutexGuard const g(m_rMutex);
391 :
392 0 : OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8);
393 0 : xmlChar *xName = (xmlChar*)o1.getStr();
394 0 : 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 0 : sal_Bool SAL_CALL CElement::hasAttributeNS(
402 : OUString const& namespaceURI, OUString const& localName)
403 : throw (RuntimeException, std::exception)
404 : {
405 0 : ::osl::MutexGuard const g(m_rMutex);
406 :
407 0 : OString o1 = OUStringToOString(localName, RTL_TEXTENCODING_UTF8);
408 0 : xmlChar *xName = (xmlChar*)o1.getStr();
409 0 : OString o2 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8);
410 0 : xmlChar *xNs = (xmlChar*)o2.getStr();
411 0 : return (m_aNodePtr != NULL && xmlHasNsProp(m_aNodePtr, xName, xNs) != NULL);
412 : }
413 :
414 : /**
415 : Removes an attribute by name.
416 : */
417 0 : void SAL_CALL CElement::removeAttribute(OUString const& name)
418 : throw (RuntimeException, DOMException, std::exception)
419 : {
420 0 : ::osl::MutexGuard const g(m_rMutex);
421 :
422 0 : if (0 == m_aNodePtr) {
423 0 : return;
424 : }
425 0 : OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8);
426 : xmlChar const*const pName =
427 0 : reinterpret_cast<xmlChar const*>(o1.getStr());
428 0 : xmlAttrPtr const pAttr = xmlHasProp(m_aNodePtr, pName);
429 0 : if (0 == xmlUnsetProp(m_aNodePtr, pName)) {
430 0 : ::rtl::Reference<CNode> const pCNode(GetOwnerDocument().GetCNode(
431 0 : reinterpret_cast<xmlNodePtr>(pAttr), false));
432 0 : if (pCNode.is()) {
433 0 : pCNode->invalidate(); // freed by xmlUnsetProp
434 0 : }
435 0 : }
436 : }
437 :
438 : /**
439 : Removes an attribute by local name and namespace URI.
440 : */
441 0 : void SAL_CALL CElement::removeAttributeNS(
442 : OUString const& namespaceURI, OUString const& localName)
443 : throw (RuntimeException, DOMException, std::exception)
444 : {
445 0 : ::osl::MutexGuard const g(m_rMutex);
446 :
447 0 : if (0 == m_aNodePtr) {
448 0 : return;
449 : }
450 0 : OString o1 = OUStringToOString(localName, RTL_TEXTENCODING_UTF8);
451 : xmlChar const*const pName =
452 0 : reinterpret_cast<xmlChar const*>(o1.getStr());
453 0 : OString o2 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8);
454 : xmlChar const*const pURI =
455 0 : reinterpret_cast<xmlChar const*>(o2.getStr());
456 : xmlNsPtr const pNs =
457 0 : xmlSearchNsByHref(m_aNodePtr->doc, m_aNodePtr, pURI);
458 0 : xmlAttrPtr const pAttr = xmlHasNsProp(m_aNodePtr, pName, pURI);
459 0 : if (0 == xmlUnsetNsProp(m_aNodePtr, pNs, pName)) {
460 0 : ::rtl::Reference<CNode> const pCNode(GetOwnerDocument().GetCNode(
461 0 : reinterpret_cast<xmlNodePtr>(pAttr), false));
462 0 : if (pCNode.is()) {
463 0 : pCNode->invalidate(); // freed by xmlUnsetNsProp
464 0 : }
465 0 : }
466 : }
467 :
468 : /**
469 : Removes the specified attribute node.
470 : */
471 : Reference< XAttr > SAL_CALL
472 0 : CElement::removeAttributeNode(Reference< XAttr > const& oldAttr)
473 : throw (RuntimeException, DOMException, std::exception)
474 : {
475 0 : ::osl::MutexGuard const g(m_rMutex);
476 :
477 0 : if (0 == m_aNodePtr) {
478 0 : return 0;
479 : }
480 :
481 : ::rtl::Reference<CNode> const pCNode(
482 0 : CNode::GetImplementation(Reference<XNode>(oldAttr.get())));
483 0 : if (!pCNode.is()) { throw RuntimeException(); }
484 :
485 0 : xmlNodePtr const pNode = pCNode->GetNodePtr();
486 0 : xmlAttrPtr const pAttr = (xmlAttrPtr) pNode;
487 0 : if (!pAttr) { throw RuntimeException(); }
488 :
489 0 : if (pAttr->parent != m_aNodePtr)
490 : {
491 0 : DOMException e;
492 0 : e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
493 0 : throw e;
494 : }
495 0 : 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 0 : Reference< XAttr > aAttr;
503 0 : if (!oldAttr->getNamespaceURI().isEmpty()) {
504 0 : OUStringBuffer qname(oldAttr->getPrefix());
505 0 : if (!qname.isEmpty()) {
506 0 : qname.append(':');
507 : }
508 0 : qname.append(oldAttr->getName());
509 0 : aAttr = GetOwnerDocument().createAttributeNS(
510 0 : oldAttr->getNamespaceURI(), qname.makeStringAndClear());
511 : } else {
512 0 : aAttr = GetOwnerDocument().createAttribute(oldAttr->getName());
513 : }
514 0 : aAttr->setValue(oldAttr->getValue());
515 0 : xmlRemoveProp(pAttr);
516 0 : pCNode->invalidate(); // freed by xmlRemoveProp
517 :
518 0 : return aAttr;
519 : }
520 :
521 : /**
522 : Adds a new attribute node.
523 : */
524 : Reference< XAttr >
525 0 : CElement::setAttributeNode_Impl_Lock(
526 : Reference< XAttr > const& xNewAttr, bool const bNS)
527 : {
528 0 : if (xNewAttr->getOwnerDocument() != getOwnerDocument()) {
529 0 : DOMException e;
530 0 : e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR;
531 0 : throw e;
532 : }
533 :
534 0 : ::osl::ClearableMutexGuard guard(m_rMutex);
535 :
536 0 : if (0 == m_aNodePtr) {
537 0 : throw RuntimeException();
538 : }
539 :
540 : // get the implementation
541 : CAttr *const pCAttr = dynamic_cast<CAttr*>(
542 0 : CNode::GetImplementation(xNewAttr));
543 0 : if (!pCAttr) { throw RuntimeException(); }
544 : xmlAttrPtr const pAttr =
545 0 : reinterpret_cast<xmlAttrPtr>(pCAttr->GetNodePtr());
546 0 : if (!pAttr) { throw RuntimeException(); }
547 :
548 : // check whether the attribute is not in use by another element
549 0 : if (pAttr->parent) {
550 0 : DOMException e;
551 0 : e.Code = DOMExceptionType_INUSE_ATTRIBUTE_ERR;
552 0 : throw e;
553 : }
554 :
555 0 : xmlAttrPtr res = NULL;
556 : xmlChar const*const pContent(
557 0 : (pAttr->children) ? pAttr->children->content : 0);
558 :
559 0 : if (bNS) {
560 0 : xmlNsPtr const pNs( pCAttr->GetNamespace(m_aNodePtr) );
561 0 : res = xmlNewNsProp(m_aNodePtr, pNs, pAttr->name, pContent);
562 : } else {
563 0 : res = xmlNewProp(m_aNodePtr, pAttr->name, pContent);
564 : }
565 :
566 : // get the new attr node
567 : Reference< XAttr > const xAttr(
568 0 : static_cast< XNode* >(GetOwnerDocument().GetCNode(
569 0 : reinterpret_cast<xmlNodePtr>(res)).get()),
570 0 : UNO_QUERY_THROW);
571 :
572 : // attribute addition event
573 : // dispatch DOMAttrModified event
574 0 : Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
575 0 : Reference< XMutationEvent > event(docevent->createEvent(
576 0 : "DOMAttrModified"), UNO_QUERY);
577 0 : event->initMutationEvent("DOMAttrModified",
578 : sal_True, sal_False, xAttr,
579 0 : OUString(), xAttr->getValue(), xAttr->getName(),
580 0 : AttrChangeType_ADDITION);
581 :
582 0 : guard.clear(); // release mutex before calling event handlers
583 :
584 0 : dispatchEvent(event);
585 0 : dispatchSubtreeModified();
586 :
587 0 : return xAttr;
588 : }
589 :
590 : Reference< XAttr >
591 0 : CElement::setAttributeNode(const Reference< XAttr >& newAttr)
592 : throw (RuntimeException, DOMException, std::exception)
593 : {
594 0 : return setAttributeNode_Impl_Lock(newAttr, false);
595 : }
596 :
597 : /**
598 : Adds a new attribute.
599 : */
600 : Reference< XAttr >
601 0 : CElement::setAttributeNodeNS(const Reference< XAttr >& newAttr)
602 : throw (RuntimeException, DOMException, std::exception)
603 : {
604 0 : return setAttributeNode_Impl_Lock(newAttr, true);
605 : }
606 :
607 : /**
608 : Adds a new attribute.
609 : */
610 : void SAL_CALL
611 0 : CElement::setAttribute(OUString const& name, OUString const& value)
612 : throw (RuntimeException, DOMException, std::exception)
613 : {
614 0 : ::osl::ClearableMutexGuard guard(m_rMutex);
615 :
616 0 : OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8);
617 0 : xmlChar *xName = (xmlChar*)o1.getStr();
618 0 : OString o2 = OUStringToOString(value, RTL_TEXTENCODING_UTF8);
619 0 : xmlChar *xValue = (xmlChar*)o2.getStr();
620 :
621 0 : if (0 == m_aNodePtr) {
622 0 : throw RuntimeException();
623 : }
624 0 : OUString oldValue;
625 0 : AttrChangeType aChangeType = AttrChangeType_MODIFICATION;
626 : ::boost::shared_ptr<xmlChar const> const pOld(
627 0 : xmlGetProp(m_aNodePtr, xName), xmlFree);
628 0 : if (pOld == 0) {
629 0 : aChangeType = AttrChangeType_ADDITION;
630 0 : 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 0 : Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
640 0 : Reference< XMutationEvent > event(docevent->createEvent(
641 0 : "DOMAttrModified"), UNO_QUERY);
642 0 : event->initMutationEvent("DOMAttrModified",
643 : sal_True, sal_False,
644 0 : Reference< XNode >(getAttributeNode(name), UNO_QUERY),
645 0 : oldValue, value, name, aChangeType);
646 :
647 0 : guard.clear(); // release mutex before calling event handlers
648 0 : dispatchEvent(event);
649 0 : dispatchSubtreeModified();
650 0 : }
651 :
652 : /**
653 : Adds a new attribute.
654 : */
655 : void SAL_CALL
656 0 : CElement::setAttributeNS(OUString const& namespaceURI,
657 : OUString const& qualifiedName, OUString const& value)
658 : throw (RuntimeException, DOMException, std::exception)
659 : {
660 0 : if (namespaceURI.isEmpty()) throw RuntimeException();
661 :
662 0 : ::osl::ClearableMutexGuard guard(m_rMutex);
663 :
664 0 : OString o1, o2, o3, o4, o5;
665 0 : xmlChar *xPrefix = NULL;
666 0 : xmlChar *xLName = NULL;
667 0 : o1 = OUStringToOString(qualifiedName, RTL_TEXTENCODING_UTF8);
668 0 : xmlChar *xQName = (xmlChar*)o1.getStr();
669 0 : sal_Int32 idx = qualifiedName.indexOf(':');
670 0 : if (idx != -1)
671 : {
672 0 : o2 = OUStringToOString(
673 : qualifiedName.copy(0,idx),
674 0 : RTL_TEXTENCODING_UTF8);
675 0 : xPrefix = (xmlChar*)o2.getStr();
676 0 : o3 = OUStringToOString(
677 : qualifiedName.copy(idx+1),
678 0 : RTL_TEXTENCODING_UTF8);
679 0 : xLName = (xmlChar*)o3.getStr();
680 : } else {
681 0 : xPrefix = (xmlChar*)"";
682 0 : xLName = xQName;
683 : }
684 0 : o4 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8);
685 0 : o5 = OUStringToOString(value, RTL_TEXTENCODING_UTF8);
686 0 : xmlChar *xURI= (xmlChar*)o4.getStr();
687 0 : xmlChar *xValue = (xmlChar*)o5.getStr();
688 :
689 0 : if (0 == m_aNodePtr) {
690 0 : throw RuntimeException();
691 : }
692 :
693 : //find the right namespace
694 0 : xmlNsPtr pNs = xmlSearchNs(m_aNodePtr->doc, m_aNodePtr, xPrefix);
695 : // if no namespace found, create a new one
696 0 : if (pNs == NULL) {
697 0 : pNs = xmlNewNs(m_aNodePtr, xURI, xPrefix);
698 : }
699 :
700 0 : if (strcmp((char*)pNs->href, (char*)xURI) != 0) {
701 : // ambiguous ns prefix
702 0 : throw RuntimeException();
703 : }
704 :
705 : // found namespace matches
706 :
707 0 : OUString oldValue;
708 0 : AttrChangeType aChangeType = AttrChangeType_MODIFICATION;
709 : ::boost::shared_ptr<xmlChar const> const pOld(
710 0 : xmlGetNsProp(m_aNodePtr, xLName, pNs->href), xmlFree);
711 0 : if (pOld == 0) {
712 0 : aChangeType = AttrChangeType_ADDITION;
713 0 : 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 0 : Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
722 0 : Reference< XMutationEvent > event(docevent->createEvent(
723 0 : "DOMAttrModified"), UNO_QUERY);
724 0 : event->initMutationEvent(
725 : "DOMAttrModified", sal_True, sal_False,
726 0 : Reference< XNode >(getAttributeNodeNS(namespaceURI, OUString((char*)xLName, strlen((char*)xLName), RTL_TEXTENCODING_UTF8)), UNO_QUERY),
727 0 : oldValue, value, qualifiedName, aChangeType);
728 :
729 0 : guard.clear(); // release mutex before calling event handlers
730 0 : dispatchEvent(event);
731 0 : dispatchSubtreeModified();
732 0 : }
733 :
734 : Reference< XNamedNodeMap > SAL_CALL
735 0 : CElement::getAttributes() throw (RuntimeException, std::exception)
736 : {
737 0 : ::osl::MutexGuard const g(m_rMutex);
738 :
739 : Reference< XNamedNodeMap > const xMap(
740 0 : new CAttributesMap(this, m_rMutex));
741 0 : return xMap;
742 : }
743 :
744 0 : OUString SAL_CALL CElement::getNodeName()throw (RuntimeException, std::exception)
745 : {
746 0 : return getLocalName();
747 : }
748 :
749 0 : OUString SAL_CALL CElement::getLocalName()throw (RuntimeException, std::exception)
750 : {
751 0 : ::osl::MutexGuard const g(m_rMutex);
752 :
753 0 : OUString aName;
754 0 : if (m_aNodePtr != NULL)
755 : {
756 0 : const xmlChar* xName = m_aNodePtr->name;
757 0 : aName = OUString((const sal_Char*)xName, strlen((const char*)xName), RTL_TEXTENCODING_UTF8);
758 : }
759 0 : return aName;
760 : }
761 :
762 0 : OUString SAL_CALL CElement::getNodeValue() throw (RuntimeException, std::exception)
763 : {
764 0 : 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: */
|