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 <node.hxx>
21 :
22 : #include <stdio.h>
23 : #include <string.h>
24 :
25 : #include <libxml/xmlstring.h>
26 :
27 : #include <algorithm>
28 :
29 : #include <boost/bind.hpp>
30 :
31 : #include <rtl/uuid.h>
32 : #include <rtl/instance.hxx>
33 : #include <osl/mutex.hxx>
34 : #include <osl/diagnose.h>
35 :
36 : #include <com/sun/star/xml/sax/FastToken.hpp>
37 :
38 : #include <comphelper/servicehelper.hxx>
39 :
40 : #include <document.hxx>
41 : #include <attr.hxx>
42 : #include <childlist.hxx>
43 :
44 : #include "../events/eventdispatcher.hxx"
45 : #include "../events/mutationevent.hxx"
46 :
47 : using namespace css;
48 : using namespace css::uno;
49 : using namespace css::xml::dom;
50 : using namespace css::xml::dom::events;
51 : using namespace css::xml::sax;
52 :
53 : namespace
54 : {
55 : class theCNodeUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theCNodeUnoTunnelId > {};
56 : }
57 :
58 : namespace DOM
59 : {
60 317841 : void pushContext(Context& io_rContext)
61 : {
62 : // Explicitly use a temp. variable.
63 : // Windows/VC++ seems to mess up if .back() is directly passed as
64 : // parameter. i.e. Don't use push_back( .back() );
65 317841 : Context::NamespaceVectorType::value_type aVal = io_rContext.maNamespaces.back();
66 317841 : io_rContext.maNamespaces.push_back( aVal );
67 317841 : }
68 :
69 317841 : void popContext(Context& io_rContext)
70 : {
71 317841 : io_rContext.maNamespaces.pop_back();
72 317841 : }
73 :
74 317841 : void addNamespaces(Context& io_rContext, xmlNodePtr pNode)
75 : {
76 : // add node's namespaces to current context
77 319767 : for (xmlNsPtr pNs = pNode->nsDef; pNs != 0; pNs = pNs->next) {
78 1926 : const xmlChar *pPrefix = pNs->prefix;
79 : // prefix can be NULL when xmlns attribute is empty (xmlns="")
80 : OString prefix(reinterpret_cast<const sal_Char*>(pPrefix),
81 1926 : pPrefix ? strlen(reinterpret_cast<const char*>(pPrefix)) : 0);
82 1926 : const xmlChar *pHref = pNs->href;
83 : OUString val(reinterpret_cast<const sal_Char*>(pHref),
84 1926 : strlen(reinterpret_cast<const char*>(pHref)),
85 3852 : RTL_TEXTENCODING_UTF8);
86 :
87 : OSL_TRACE("Trying to add namespace %s (prefix %s)",
88 : reinterpret_cast<const char*>(pHref), reinterpret_cast<const char*>(pPrefix));
89 :
90 : Context::NamespaceMapType::iterator aIter=
91 1926 : io_rContext.maNamespaceMap.find(val);
92 1926 : if( aIter != io_rContext.maNamespaceMap.end() )
93 : {
94 1722 : Context::Namespace aNS;
95 1722 : aNS.maPrefix = prefix;
96 1722 : aNS.mnToken = aIter->second;
97 1722 : aNS.maNamespaceURL = val;
98 :
99 1722 : io_rContext.maNamespaces.back().push_back(aNS);
100 :
101 1722 : SAL_INFO("unoxml", "Added with token " << aIter->second);
102 : }
103 1926 : }
104 317841 : }
105 :
106 708045 : sal_Int32 getToken( const Context& rContext, const sal_Char* pToken )
107 : {
108 708045 : const Sequence<sal_Int8> aSeq( reinterpret_cast<sal_Int8 const *>(pToken), strlen( pToken ) );
109 708045 : return rContext.mxTokenHandler->getTokenFromUTF8( aSeq );
110 : }
111 :
112 317960 : sal_Int32 getTokenWithPrefix( const Context& rContext, const sal_Char* pPrefix, const sal_Char* pName )
113 : {
114 317960 : sal_Int32 nNamespaceToken = FastToken::DONTKNOW;
115 : OString prefix(pPrefix,
116 317960 : strlen(reinterpret_cast<const char*>(pPrefix)));
117 :
118 : OSL_TRACE("getTokenWithPrefix(): prefix %s, name %s",
119 : pPrefix, pName);
120 :
121 317960 : Context::NamespaceVectorType::value_type::const_iterator aIter;
122 953880 : if( (aIter=std::find_if(rContext.maNamespaces.back().begin(),
123 317960 : rContext.maNamespaces.back().end(),
124 : boost::bind(std::equal_to<OString>(),
125 : boost::bind(&Context::Namespace::getPrefix,
126 : _1),
127 1271840 : boost::cref(prefix)))) != rContext.maNamespaces.back().end() )
128 : {
129 317821 : nNamespaceToken = aIter->mnToken;
130 317821 : sal_Int32 nNameToken = getToken( rContext, pName );
131 317821 : if( nNameToken != FastToken::DONTKNOW )
132 317821 : nNamespaceToken |= nNameToken;
133 : }
134 :
135 317960 : return nNamespaceToken;
136 : }
137 :
138 :
139 1337767 : CNode::CNode(CDocument const& rDocument, ::osl::Mutex const& rMutex,
140 : NodeType const& reNodeType, xmlNodePtr const& rpNode)
141 : : m_bUnlinked(false)
142 : , m_aNodeType(reNodeType)
143 : , m_aNodePtr(rpNode)
144 : // keep containing document alive
145 : // (but not if this is a document; that would create a leak!)
146 1337767 : , m_xDocument( (m_aNodePtr->type != XML_DOCUMENT_NODE)
147 : ? &const_cast<CDocument&>(rDocument) : 0 )
148 2675534 : , m_rMutex(const_cast< ::osl::Mutex & >(rMutex))
149 : {
150 : OSL_ASSERT(m_aNodePtr);
151 1337767 : }
152 :
153 1337616 : void CNode::invalidate()
154 : {
155 : //remove from list if this wrapper goes away
156 1337616 : if (m_aNodePtr != 0 && m_xDocument.is()) {
157 1319913 : m_xDocument->RemoveCNode(m_aNodePtr, this);
158 : }
159 : // #i113663#: unlinked nodes will not be freed by xmlFreeDoc
160 1337616 : if (m_bUnlinked) {
161 4046 : xmlFreeNode(m_aNodePtr);
162 : }
163 1337616 : m_aNodePtr = 0;
164 1337616 : }
165 :
166 2675004 : CNode::~CNode()
167 : {
168 : // if this is the document itself, the mutex is already freed!
169 1337502 : if (NodeType_DOCUMENT_NODE == m_aNodeType) {
170 17589 : invalidate();
171 : } else {
172 1319913 : ::osl::MutexGuard const g(m_rMutex);
173 1319913 : invalidate(); // other nodes are still alive so must lock mutex
174 : }
175 1337502 : }
176 :
177 : CNode *
178 509407 : CNode::GetImplementation(uno::Reference<uno::XInterface> const& xNode)
179 : {
180 509407 : uno::Reference<lang::XUnoTunnel> const xUnoTunnel(xNode, UNO_QUERY);
181 509407 : if (!xUnoTunnel.is()) { return 0; }
182 : CNode *const pCNode( reinterpret_cast< CNode* >(
183 : ::sal::static_int_cast< sal_IntPtr >(
184 509397 : xUnoTunnel->getSomething(theCNodeUnoTunnelId::get().getSeq()))));
185 509397 : return pCNode;
186 : }
187 :
188 1979214 : CDocument & CNode::GetOwnerDocument()
189 : {
190 : OSL_ASSERT(m_xDocument.is());
191 1979214 : return *m_xDocument; // needs overriding in CDocument!
192 : }
193 :
194 :
195 33233 : static void lcl_nsexchange(
196 : xmlNodePtr const aNode, xmlNsPtr const oldNs, xmlNsPtr const newNs)
197 : {
198 : // recursively exchange any references to oldNs with references to newNs
199 33233 : xmlNodePtr cur = aNode;
200 98259 : while (cur != 0)
201 : {
202 31793 : if (cur->ns == oldNs)
203 11164 : cur->ns = newNs;
204 31793 : if (cur->type == XML_ELEMENT_NODE)
205 : {
206 22050 : xmlAttrPtr curAttr = cur->properties;
207 60255 : while(curAttr != 0)
208 : {
209 16155 : if (curAttr->ns == oldNs)
210 651 : curAttr->ns = newNs;
211 16155 : curAttr = curAttr->next;
212 : }
213 22050 : lcl_nsexchange(cur->children, oldNs, newNs);
214 : }
215 31793 : cur = cur->next;
216 : }
217 33233 : }
218 :
219 649373 : /*static*/ void nscleanup(const xmlNodePtr aNode, const xmlNodePtr aParent)
220 : {
221 649373 : xmlNodePtr cur = aNode;
222 :
223 : //handle attributes
224 649373 : if (cur != NULL && cur->type == XML_ELEMENT_NODE)
225 : {
226 223278 : xmlAttrPtr curAttr = cur->properties;
227 665319 : while(curAttr != 0)
228 : {
229 218763 : if (curAttr->ns != NULL)
230 : {
231 38379 : xmlNsPtr ns = xmlSearchNs(cur->doc, aParent, curAttr->ns->prefix);
232 38379 : if (ns != NULL)
233 1482 : curAttr->ns = ns;
234 : }
235 218763 : curAttr = curAttr->next;
236 : }
237 : }
238 :
239 1858943 : while (cur != NULL)
240 : {
241 560197 : nscleanup(cur->children, cur);
242 560197 : if (cur->ns != NULL)
243 : {
244 496464 : xmlNsPtr ns = xmlSearchNs(cur->doc, aParent, cur->ns->prefix);
245 496464 : if (ns != NULL && ns != cur->ns && strcmp(reinterpret_cast<char const *>(ns->href), reinterpret_cast<char const *>(cur->ns->href))==0)
246 : {
247 11164 : xmlNsPtr curDef = cur->nsDef;
248 11164 : xmlNsPtr *refp = &(cur->nsDef); // insert point
249 33511 : while (curDef != NULL)
250 : {
251 11183 : ns = xmlSearchNs(cur->doc, aParent, curDef->prefix);
252 11183 : if (ns != NULL && ns != curDef && strcmp(reinterpret_cast<char const *>(ns->href), reinterpret_cast<char const *>(curDef->href))==0)
253 : {
254 : // reconnect ns pointers in sub-tree to newly found ns before
255 : // removing redundant nsdecl to prevent dangling pointers.
256 11183 : lcl_nsexchange(cur, curDef, ns);
257 11183 : *refp = curDef->next;
258 11183 : xmlFreeNs(curDef);
259 11183 : curDef = *refp;
260 : } else {
261 0 : refp = &(curDef->next);
262 0 : curDef = curDef->next;
263 : }
264 : }
265 : }
266 : }
267 560197 : cur = cur->next;
268 : }
269 649373 : }
270 :
271 0 : void CNode::saxify(const Reference< XDocumentHandler >& i_xHandler)
272 : {
273 0 : if (!i_xHandler.is()) throw RuntimeException();
274 : // default: do nothing
275 0 : }
276 :
277 1 : void CNode::fastSaxify(Context& io_rContext)
278 : {
279 1 : if (!io_rContext.mxDocHandler.is()) throw RuntimeException();
280 : // default: do nothing
281 1 : }
282 :
283 4 : bool CNode::IsChildTypeAllowed(NodeType const /*nodeType*/)
284 : {
285 : // default: no children allowed
286 4 : return false;
287 : }
288 :
289 : /**
290 : Adds the node newChild to the end of the list of children of this node.
291 : */
292 86077 : Reference< XNode > SAL_CALL CNode::appendChild(
293 : Reference< XNode > const& xNewChild)
294 : throw (RuntimeException, DOMException, std::exception)
295 : {
296 86077 : ::osl::ClearableMutexGuard guard(m_rMutex);
297 :
298 86077 : if (0 == m_aNodePtr) { return 0; }
299 :
300 86077 : CNode *const pNewChild(CNode::GetImplementation(xNewChild));
301 86077 : if (!pNewChild) { throw RuntimeException(); }
302 86068 : xmlNodePtr const cur = pNewChild->GetNodePtr();
303 86068 : if (!cur) { throw RuntimeException(); }
304 :
305 : // error checks:
306 : // from other document
307 86068 : if (cur->doc != m_aNodePtr->doc) {
308 0 : DOMException e;
309 0 : e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR;
310 0 : throw e;
311 : }
312 : // same node
313 86068 : if (cur == m_aNodePtr) {
314 0 : DOMException e;
315 0 : e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
316 0 : throw e;
317 : }
318 86068 : if (cur->parent != NULL) {
319 0 : DOMException e;
320 0 : e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
321 0 : throw e;
322 : }
323 86068 : if (!IsChildTypeAllowed(pNewChild->m_aNodeType)) {
324 4 : DOMException e;
325 4 : e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
326 4 : throw e;
327 : }
328 :
329 : // check whether this is an attribute node; it needs special handling
330 86064 : xmlNodePtr res = NULL;
331 86064 : if (cur->type == XML_ATTRIBUTE_NODE)
332 : {
333 : xmlChar const*const pChildren((cur->children)
334 : ? cur->children->content
335 1 : : reinterpret_cast<xmlChar const*>(""));
336 1 : CAttr *const pCAttr(dynamic_cast<CAttr *>(pNewChild));
337 1 : if (!pCAttr) { throw RuntimeException(); }
338 1 : xmlNsPtr const pNs( pCAttr->GetNamespace(m_aNodePtr) );
339 1 : if (pNs) {
340 : res = reinterpret_cast<xmlNodePtr>(
341 0 : xmlNewNsProp(m_aNodePtr, pNs, cur->name, pChildren));
342 : } else {
343 : res = reinterpret_cast<xmlNodePtr>(
344 1 : xmlNewProp(m_aNodePtr, cur->name, pChildren));
345 : }
346 : }
347 : else
348 : {
349 86063 : res = xmlAddChild(m_aNodePtr, cur);
350 :
351 : // libxml can do optimization when appending nodes.
352 : // if res != cur, something was optimized and the newchild-wrapper
353 : // should be updated
354 86063 : if (res && (cur != res)) {
355 110 : pNewChild->invalidate(); // cur has been freed
356 : }
357 : }
358 :
359 86064 : if (!res) { return 0; }
360 :
361 : // use custom ns cleanup instead of
362 : // xmlReconciliateNs(m_aNodePtr->doc, m_aNodePtr);
363 : // because that will not remove unneeded ns decls
364 86064 : nscleanup(res, m_aNodePtr);
365 :
366 172128 : ::rtl::Reference<CNode> const pNode = GetOwnerDocument().GetCNode(res);
367 :
368 86064 : if (!pNode.is()) { return 0; }
369 :
370 : // dispatch DOMNodeInserted event, target is the new node
371 : // this node is the related node
372 : // does bubble
373 86064 : pNode->m_bUnlinked = false; // will be deleted by xmlFreeDoc
374 172128 : Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
375 86064 : Reference< XMutationEvent > event(docevent->createEvent(
376 172128 : "DOMNodeInserted"), UNO_QUERY);
377 86064 : event->initMutationEvent("DOMNodeInserted", sal_True, sal_False, this,
378 86064 : OUString(), OUString(), OUString(), (AttrChangeType)0 );
379 :
380 : // the following dispatch functions use only UNO interfaces
381 : // and call event listeners, so release mutex to prevent deadlocks.
382 86064 : guard.clear();
383 :
384 86064 : dispatchEvent(event);
385 : // dispatch subtree modified for this node
386 86064 : dispatchSubtreeModified();
387 :
388 172141 : return pNode.get();
389 : }
390 :
391 : /**
392 : Returns a duplicate of this node, i.e., serves as a generic copy
393 : constructor for nodes.
394 : */
395 16 : Reference< XNode > SAL_CALL CNode::cloneNode(sal_Bool bDeep)
396 : throw (RuntimeException, std::exception)
397 : {
398 16 : ::osl::MutexGuard const g(m_rMutex);
399 :
400 16 : if (0 == m_aNodePtr) {
401 0 : return 0;
402 : }
403 16 : ::rtl::Reference<CNode> const pNode = GetOwnerDocument().GetCNode(
404 48 : xmlCopyNode(m_aNodePtr, (bDeep) ? 1 : 0));
405 16 : if (!pNode.is()) { return 0; }
406 16 : pNode->m_bUnlinked = true; // not linked yet
407 32 : return pNode.get();
408 : }
409 :
410 : /**
411 : A NamedNodeMap containing the attributes of this node (if it is an Element)
412 : or null otherwise.
413 : */
414 8 : Reference< XNamedNodeMap > SAL_CALL CNode::getAttributes()
415 : throw (RuntimeException, std::exception)
416 : {
417 : // return empty reference; only element node may override this impl
418 8 : return Reference< XNamedNodeMap>();
419 : }
420 :
421 : /**
422 : A NodeList that contains all children of this node.
423 : */
424 4230 : Reference< XNodeList > SAL_CALL CNode::getChildNodes()
425 : throw (RuntimeException, std::exception)
426 : {
427 4230 : ::osl::MutexGuard const g(m_rMutex);
428 :
429 4230 : if (0 == m_aNodePtr) {
430 0 : return 0;
431 : }
432 8460 : Reference< XNodeList > const xNodeList(new CChildList(this, m_rMutex));
433 8460 : return xNodeList;
434 : }
435 :
436 : /**
437 : The first child of this node.
438 : */
439 41755 : Reference< XNode > SAL_CALL CNode::getFirstChild()
440 : throw (RuntimeException, std::exception)
441 : {
442 41755 : ::osl::MutexGuard const g(m_rMutex);
443 :
444 41755 : if (0 == m_aNodePtr) {
445 0 : return 0;
446 : }
447 : Reference< XNode > const xNode(
448 83510 : GetOwnerDocument().GetCNode(m_aNodePtr->children).get());
449 83510 : return xNode;
450 : }
451 :
452 : /**
453 : The last child of this node.
454 : */
455 20 : Reference< XNode > SAL_CALL CNode::getLastChild()
456 : throw (RuntimeException, std::exception)
457 : {
458 20 : ::osl::MutexGuard const g(m_rMutex);
459 :
460 20 : if (0 == m_aNodePtr) {
461 0 : return 0;
462 : }
463 : Reference< XNode > const xNode(
464 40 : GetOwnerDocument().GetCNode(xmlGetLastChild(m_aNodePtr)).get());
465 40 : return xNode;
466 : }
467 :
468 : /**
469 : Returns the local part of the qualified name of this node.
470 : */
471 7 : OUString SAL_CALL CNode::getLocalName()
472 : throw (RuntimeException, std::exception)
473 : {
474 : // see CElement/CAttr
475 7 : return OUString();
476 : }
477 :
478 :
479 : /**
480 : The namespace URI of this node, or null if it is unspecified.
481 : */
482 19636 : OUString SAL_CALL CNode::getNamespaceURI()
483 : throw (RuntimeException, std::exception)
484 : {
485 19636 : ::osl::MutexGuard const g(m_rMutex);
486 :
487 19636 : OUString aURI;
488 39272 : if (m_aNodePtr != NULL &&
489 49478 : (m_aNodePtr->type == XML_ELEMENT_NODE || m_aNodePtr->type == XML_ATTRIBUTE_NODE) &&
490 19629 : m_aNodePtr->ns != NULL)
491 : {
492 19625 : const xmlChar* xHref = m_aNodePtr->ns->href;
493 19625 : aURI = OUString(reinterpret_cast<char const *>(xHref), strlen(reinterpret_cast<char const *>(xHref)), RTL_TEXTENCODING_UTF8);
494 : }
495 19636 : return aURI;
496 : }
497 :
498 : /**
499 : The node immediately following this node.
500 : */
501 15677 : Reference< XNode > SAL_CALL CNode::getNextSibling()
502 : throw (RuntimeException, std::exception)
503 : {
504 15677 : ::osl::MutexGuard const g(m_rMutex);
505 :
506 15677 : if (0 == m_aNodePtr) {
507 0 : return 0;
508 : }
509 : Reference< XNode > const xNode(
510 31354 : GetOwnerDocument().GetCNode(m_aNodePtr->next).get());
511 31354 : return xNode;
512 : }
513 :
514 : /**
515 : The name of this node, depending on its type; see the table above.
516 : */
517 0 : OUString SAL_CALL CNode::getNodeName()
518 : throw (RuntimeException, std::exception)
519 : {
520 : /*
521 : Interface nodeName nodeValue attributes
522 : --------------------------------------------------------------------------------------
523 : Attr name of attribute value of attribute null
524 : CDATASection "#cdata-section" content of the CDATA Section null
525 : Comment "#comment" content of the comment null
526 : Document "#document" null null
527 : DocumentFragment "#document-fragment" null null
528 : DocumentType document type name null null
529 : Element tag name null NamedNodeMap
530 : Entity entity name null null
531 : EntityReference name of entity null null
532 : referenced
533 : Notation notation name null null
534 : Processing\ target entire content excluding null
535 : Instruction the target
536 : Text "#text" content of the text node null
537 : */
538 0 : OUString aName;
539 0 : return aName;
540 : }
541 :
542 : /**
543 : A code representing the type of the underlying object, as defined above.
544 : */
545 37718 : NodeType SAL_CALL CNode::getNodeType()
546 : throw (RuntimeException, std::exception)
547 : {
548 37718 : ::osl::MutexGuard const g(m_rMutex);
549 :
550 37718 : return m_aNodeType;
551 : }
552 :
553 : /**
554 : The value of this node, depending on its type; see the table above.
555 : */
556 0 : OUString SAL_CALL CNode::getNodeValue()
557 : throw (RuntimeException, std::exception)
558 : {
559 0 : OUString aValue;
560 0 : return aValue;
561 : }
562 :
563 : /**
564 : The Document object associated with this node.
565 : */
566 516045 : Reference< XDocument > SAL_CALL CNode::getOwnerDocument()
567 : throw (RuntimeException, std::exception)
568 : {
569 516045 : ::osl::MutexGuard const g(m_rMutex);
570 :
571 516045 : if (0 == m_aNodePtr) {
572 0 : return 0;
573 : }
574 1032090 : Reference< XDocument > const xDoc(& GetOwnerDocument());
575 1032090 : return xDoc;
576 : }
577 :
578 : /**
579 : The parent of this node.
580 : */
581 4074 : Reference< XNode > SAL_CALL CNode::getParentNode()
582 : throw (RuntimeException, std::exception)
583 : {
584 4074 : ::osl::MutexGuard const g(m_rMutex);
585 :
586 4074 : if (0 == m_aNodePtr) {
587 0 : return 0;
588 : }
589 : Reference< XNode > const xNode(
590 8148 : GetOwnerDocument().GetCNode(m_aNodePtr->parent).get());
591 8148 : return xNode;
592 : }
593 :
594 : /**
595 : The namespace prefix of this node, or null if it is unspecified.
596 : */
597 277600 : OUString SAL_CALL CNode::getPrefix()
598 : throw (RuntimeException, std::exception)
599 : {
600 277600 : ::osl::MutexGuard const g(m_rMutex);
601 :
602 277600 : OUString aPrefix;
603 555200 : if (m_aNodePtr != NULL &&
604 710450 : (m_aNodePtr->type == XML_ELEMENT_NODE || m_aNodePtr->type == XML_ATTRIBUTE_NODE) &&
605 277593 : m_aNodePtr->ns != NULL)
606 : {
607 152404 : const xmlChar* xPrefix = m_aNodePtr->ns->prefix;
608 152404 : if( xPrefix != NULL )
609 151960 : aPrefix = OUString(reinterpret_cast<char const *>(xPrefix), strlen(reinterpret_cast<char const *>(xPrefix)), RTL_TEXTENCODING_UTF8);
610 : }
611 277600 : return aPrefix;
612 :
613 : }
614 :
615 : /**
616 : The node immediately preceding this node.
617 : */
618 9 : Reference< XNode > SAL_CALL CNode::getPreviousSibling()
619 : throw (RuntimeException, std::exception)
620 : {
621 9 : ::osl::MutexGuard const g(m_rMutex);
622 :
623 9 : if (0 == m_aNodePtr) {
624 0 : return 0;
625 : }
626 : Reference< XNode > const xNode(
627 18 : GetOwnerDocument().GetCNode(m_aNodePtr->prev).get());
628 18 : return xNode;
629 : }
630 :
631 : /**
632 : Returns whether this node (if it is an element) has any attributes.
633 : */
634 9367 : sal_Bool SAL_CALL CNode::hasAttributes()
635 : throw (RuntimeException, std::exception)
636 : {
637 9367 : ::osl::MutexGuard const g(m_rMutex);
638 :
639 9367 : return (m_aNodePtr != NULL && m_aNodePtr->properties != NULL);
640 : }
641 :
642 : /**
643 : Returns whether this node has any children.
644 : */
645 36 : sal_Bool SAL_CALL CNode::hasChildNodes()
646 : throw (RuntimeException, std::exception)
647 : {
648 36 : ::osl::MutexGuard const g(m_rMutex);
649 :
650 36 : return (m_aNodePtr != NULL && m_aNodePtr->children != NULL);
651 : }
652 :
653 : /**
654 : Inserts the node newChild before the existing child node refChild.
655 : */
656 24 : Reference< XNode > SAL_CALL CNode::insertBefore(
657 : const Reference< XNode >& newChild, const Reference< XNode >& refChild)
658 : throw (RuntimeException, DOMException, std::exception)
659 : {
660 24 : if (!newChild.is() || !refChild.is()) { throw RuntimeException(); }
661 :
662 14 : if (newChild->getOwnerDocument() != getOwnerDocument()) {
663 0 : DOMException e;
664 0 : e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR;
665 0 : throw e;
666 : }
667 14 : if (refChild->getParentNode() != Reference< XNode >(this)) {
668 9 : DOMException e;
669 9 : e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
670 9 : throw e;
671 : }
672 :
673 5 : ::osl::ClearableMutexGuard guard(m_rMutex);
674 :
675 5 : CNode *const pNewNode(CNode::GetImplementation(newChild));
676 5 : CNode *const pRefNode(CNode::GetImplementation(refChild));
677 5 : if (!pNewNode || !pRefNode) { throw RuntimeException(); }
678 5 : xmlNodePtr const pNewChild(pNewNode->GetNodePtr());
679 5 : xmlNodePtr const pRefChild(pRefNode->GetNodePtr());
680 5 : if (!pNewChild || !pRefChild) { throw RuntimeException(); }
681 :
682 5 : if (pNewChild == m_aNodePtr) {
683 0 : DOMException e;
684 0 : e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
685 0 : throw e;
686 : }
687 : // already has parent
688 5 : if (pNewChild->parent != NULL)
689 : {
690 0 : DOMException e;
691 0 : e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
692 0 : throw e;
693 : }
694 5 : if (!IsChildTypeAllowed(pNewNode->m_aNodeType)) {
695 0 : DOMException e;
696 0 : e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
697 0 : throw e;
698 : }
699 :
700 : // attributes are unordered anyway, so just do appendChild
701 5 : if (XML_ATTRIBUTE_NODE == pNewChild->type) {
702 0 : guard.clear();
703 0 : return appendChild(newChild);
704 : }
705 :
706 5 : xmlNodePtr cur = m_aNodePtr->children;
707 :
708 : //search child before which to insert
709 10 : while (cur != NULL)
710 : {
711 5 : if (cur == pRefChild) {
712 : // insert before
713 5 : pNewChild->next = cur;
714 5 : pNewChild->prev = cur->prev;
715 5 : cur->prev = pNewChild;
716 5 : if (pNewChild->prev != NULL) {
717 0 : pNewChild->prev->next = pNewChild;
718 : }
719 5 : pNewChild->parent = cur->parent;
720 5 : if (pNewChild->parent->children == cur) {
721 5 : pNewChild->parent->children = pNewChild;
722 : }
723 : // do not update parent->last here!
724 5 : pNewNode->m_bUnlinked = false; // will be deleted by xmlFreeDoc
725 5 : break;
726 : }
727 0 : cur = cur->next;
728 : }
729 5 : return refChild;
730 : }
731 :
732 : /**
733 : Tests whether the DOM implementation implements a specific feature and
734 : that feature is supported by this node.
735 : */
736 9 : sal_Bool SAL_CALL CNode::isSupported(const OUString& /*feature*/, const OUString& /*ver*/)
737 : throw (RuntimeException, std::exception)
738 : {
739 : OSL_ENSURE(false, "CNode::isSupported: not implemented (#i113683#)");
740 9 : return sal_False;
741 : }
742 :
743 : /**
744 : Puts all Text nodes in the full depth of the sub-tree underneath this
745 : Node, including attribute nodes, into a "normal" form where only structure
746 : (e.g., elements, comments, processing instructions, CDATA sections, and
747 : entity references) separates Text nodes, i.e., there are neither adjacent
748 : Text nodes nor empty Text nodes.
749 : */
750 9 : void SAL_CALL CNode::normalize()
751 : throw (RuntimeException, std::exception)
752 : {
753 : //XXX combine adjacent text nodes and remove empty ones
754 : OSL_ENSURE(false, "CNode::normalize: not implemented (#i113683#)");
755 9 : }
756 :
757 : /**
758 : Removes the child node indicated by oldChild from the list of children,
759 : and returns it.
760 : */
761 : Reference< XNode > SAL_CALL
762 4033 : CNode::removeChild(const Reference< XNode >& xOldChild)
763 : throw (RuntimeException, DOMException, std::exception)
764 : {
765 4033 : if (!xOldChild.is()) {
766 9 : throw RuntimeException();
767 : }
768 :
769 4024 : if (xOldChild->getOwnerDocument() != getOwnerDocument()) {
770 0 : DOMException e;
771 0 : e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR;
772 0 : throw e;
773 : }
774 4024 : if (xOldChild->getParentNode() != Reference< XNode >(this)) {
775 9 : DOMException e;
776 9 : e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
777 9 : throw e;
778 : }
779 :
780 4015 : ::osl::ClearableMutexGuard guard(m_rMutex);
781 :
782 4015 : if (!m_aNodePtr) { throw RuntimeException(); }
783 :
784 4015 : Reference<XNode> xReturn( xOldChild );
785 :
786 8030 : ::rtl::Reference<CNode> const pOld(CNode::GetImplementation(xOldChild));
787 4015 : if (!pOld.is()) { throw RuntimeException(); }
788 4015 : xmlNodePtr const old = pOld->GetNodePtr();
789 4015 : if (!old) { throw RuntimeException(); }
790 :
791 4015 : if( old->type == XML_ATTRIBUTE_NODE )
792 : {
793 0 : xmlAttrPtr pAttr = reinterpret_cast<xmlAttrPtr>(old);
794 0 : xmlRemoveProp( pAttr );
795 0 : pOld->invalidate(); // freed by xmlRemoveProp
796 0 : xReturn.clear();
797 : }
798 : else
799 : {
800 4015 : xmlUnlinkNode(old);
801 4015 : pOld->m_bUnlinked = true;
802 : }
803 :
804 : /*DOMNodeRemoved
805 : * Fired when a node is being removed from its parent node.
806 : * This event is dispatched before the node is removed from the tree.
807 : * The target of this event is the node being removed.
808 : * Bubbles: Yes
809 : * Cancelable: No
810 : * Context Info: relatedNode holds the parent node
811 : */
812 8030 : Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
813 4015 : Reference< XMutationEvent > event(docevent->createEvent(
814 8030 : "DOMNodeRemoved"), UNO_QUERY);
815 4015 : event->initMutationEvent("DOMNodeRemoved",
816 : sal_True,
817 : sal_False,
818 : this,
819 4015 : OUString(), OUString(), OUString(), (AttrChangeType)0 );
820 :
821 : // the following dispatch functions use only UNO interfaces
822 : // and call event listeners, so release mutex to prevent deadlocks.
823 4015 : guard.clear();
824 :
825 4015 : dispatchEvent(event);
826 : // subtree modified for this node
827 4015 : dispatchSubtreeModified();
828 :
829 8030 : return xReturn;
830 : }
831 :
832 : /**
833 : Replaces the child node oldChild with newChild in the list of children,
834 : and returns the oldChild node.
835 : */
836 29 : Reference< XNode > SAL_CALL CNode::replaceChild(
837 : Reference< XNode > const& xNewChild,
838 : Reference< XNode > const& xOldChild)
839 : throw (RuntimeException, DOMException, std::exception)
840 : {
841 29 : if (!xOldChild.is() || !xNewChild.is()) {
842 10 : throw RuntimeException();
843 : }
844 :
845 19 : if (xNewChild->getOwnerDocument() != getOwnerDocument()) {
846 0 : DOMException e;
847 0 : e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR;
848 0 : throw e;
849 : }
850 19 : if (xOldChild->getParentNode() != Reference< XNode >(this)) {
851 8 : DOMException e;
852 8 : e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
853 8 : throw e;
854 : }
855 :
856 11 : ::osl::ClearableMutexGuard guard(m_rMutex);
857 :
858 : ::rtl::Reference<CNode> const pOldNode(
859 22 : CNode::GetImplementation(xOldChild));
860 : ::rtl::Reference<CNode> const pNewNode(
861 22 : CNode::GetImplementation(xNewChild));
862 11 : if (!pOldNode.is() || !pNewNode.is()) { throw RuntimeException(); }
863 11 : xmlNodePtr const pOld = pOldNode->GetNodePtr();
864 11 : xmlNodePtr const pNew = pNewNode->GetNodePtr();
865 11 : if (!pOld || !pNew) { throw RuntimeException(); }
866 :
867 11 : if (pNew == m_aNodePtr) {
868 0 : DOMException e;
869 0 : e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
870 0 : throw e;
871 : }
872 : // already has parent
873 11 : if (pNew->parent != NULL) {
874 6 : DOMException e;
875 6 : e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
876 6 : throw e;
877 : }
878 5 : if (!IsChildTypeAllowed(pNewNode->m_aNodeType)) {
879 0 : DOMException e;
880 0 : e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
881 0 : throw e;
882 : }
883 :
884 5 : if( pOld->type == XML_ATTRIBUTE_NODE )
885 : {
886 : // can only replace attribute with attribute
887 0 : if ( pOld->type != pNew->type )
888 : {
889 0 : DOMException e;
890 0 : e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
891 0 : throw e;
892 : }
893 :
894 0 : xmlAttrPtr pAttr = reinterpret_cast<xmlAttrPtr>(pOld);
895 0 : xmlRemoveProp( pAttr );
896 0 : pOldNode->invalidate(); // freed by xmlRemoveProp
897 0 : appendChild(xNewChild);
898 : }
899 : else
900 : {
901 :
902 5 : xmlNodePtr cur = m_aNodePtr->children;
903 : //find old node in child list
904 16 : while (cur != NULL)
905 : {
906 6 : if(cur == pOld)
907 : {
908 : // exchange nodes
909 5 : pNew->prev = pOld->prev;
910 5 : if (pNew->prev != NULL)
911 1 : pNew->prev->next = pNew;
912 5 : pNew->next = pOld->next;
913 5 : if (pNew->next != NULL)
914 4 : pNew->next->prev = pNew;
915 5 : pNew->parent = pOld->parent;
916 : // coverity[var_deref_op] pNew->parent cannot be NULL here
917 5 : if(pNew->parent->children == pOld)
918 4 : pNew->parent->children = pNew;
919 5 : if(pNew->parent->last == pOld)
920 1 : pNew->parent->last = pNew;
921 5 : pOld->next = NULL;
922 5 : pOld->prev = NULL;
923 5 : pOld->parent = NULL;
924 5 : pOldNode->m_bUnlinked = true;
925 5 : pNewNode->m_bUnlinked = false; // will be deleted by xmlFreeDoc
926 : }
927 6 : cur = cur->next;
928 : }
929 : }
930 :
931 5 : guard.clear(); // release for calling event handlers
932 5 : dispatchSubtreeModified();
933 :
934 16 : return xOldChild;
935 : }
936 :
937 140966 : void CNode::dispatchSubtreeModified()
938 : {
939 : // only uses UNO interfaces => needs no mutex
940 :
941 : // dispatch DOMSubtreeModified
942 : // target is _this_ node
943 140966 : Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
944 140966 : Reference< XMutationEvent > event(docevent->createEvent(
945 281932 : "DOMSubtreeModified"), UNO_QUERY);
946 140966 : event->initMutationEvent(
947 : "DOMSubtreeModified", sal_True,
948 : sal_False, Reference< XNode >(),
949 140966 : OUString(), OUString(), OUString(), (AttrChangeType)0 );
950 281932 : dispatchEvent(event);
951 140966 : }
952 :
953 : /**
954 : The value of this node, depending on its type; see the table above.
955 : */
956 4 : void SAL_CALL CNode::setNodeValue(const OUString& /*nodeValue*/)
957 : throw (RuntimeException, DOMException, std::exception)
958 : {
959 : // use specific node implememntation
960 : // if we end up down here, something went wrong
961 4 : DOMException e;
962 4 : e.Code = DOMExceptionType_NO_MODIFICATION_ALLOWED_ERR;
963 4 : throw e;
964 : }
965 :
966 : /**
967 : The namespace prefix of this node, or null if it is unspecified.
968 : */
969 8 : void SAL_CALL CNode::setPrefix(const OUString& prefix)
970 : throw (RuntimeException, DOMException, std::exception)
971 : {
972 8 : ::osl::MutexGuard const g(m_rMutex);
973 :
974 16 : if ((0 == m_aNodePtr) ||
975 15 : ((m_aNodePtr->type != XML_ELEMENT_NODE) &&
976 7 : (m_aNodePtr->type != XML_ATTRIBUTE_NODE)))
977 : {
978 7 : DOMException e;
979 7 : e.Code = DOMExceptionType_NO_MODIFICATION_ALLOWED_ERR;
980 7 : throw e;
981 : }
982 2 : OString o1 = OUStringToOString(prefix, RTL_TEXTENCODING_UTF8);
983 1 : xmlChar const *pBuf = reinterpret_cast<xmlChar const *>(o1.getStr());
984 1 : if (m_aNodePtr != NULL && m_aNodePtr->ns != NULL)
985 : {
986 1 : xmlFree(const_cast<xmlChar *>(m_aNodePtr->ns->prefix));
987 1 : m_aNodePtr->ns->prefix = xmlStrdup(pBuf);
988 8 : }
989 :
990 1 : }
991 :
992 : // --- XEventTarget
993 653 : void SAL_CALL CNode::addEventListener(const OUString& eventType,
994 : const Reference< css::xml::dom::events::XEventListener >& listener,
995 : sal_Bool useCapture)
996 : throw (RuntimeException, std::exception)
997 : {
998 653 : ::osl::MutexGuard const g(m_rMutex);
999 :
1000 653 : CDocument & rDocument(GetOwnerDocument());
1001 653 : events::CEventDispatcher & rDispatcher(rDocument.GetEventDispatcher());
1002 653 : rDispatcher.addListener(m_aNodePtr, eventType, listener, useCapture);
1003 653 : }
1004 :
1005 653 : void SAL_CALL CNode::removeEventListener(const OUString& eventType,
1006 : const Reference< css::xml::dom::events::XEventListener >& listener,
1007 : sal_Bool useCapture)
1008 : throw (RuntimeException, std::exception)
1009 : {
1010 653 : ::osl::MutexGuard const g(m_rMutex);
1011 :
1012 653 : CDocument & rDocument(GetOwnerDocument());
1013 653 : events::CEventDispatcher & rDispatcher(rDocument.GetEventDispatcher());
1014 653 : rDispatcher.removeListener(m_aNodePtr, eventType, listener, useCapture);
1015 653 : }
1016 :
1017 298282 : sal_Bool SAL_CALL CNode::dispatchEvent(const Reference< XEvent >& evt)
1018 : throw(RuntimeException, EventException, std::exception)
1019 : {
1020 : CDocument * pDocument;
1021 : events::CEventDispatcher * pDispatcher;
1022 : xmlNodePtr pNode;
1023 : {
1024 298282 : ::osl::MutexGuard const g(m_rMutex);
1025 :
1026 298282 : pDocument = & GetOwnerDocument();
1027 298282 : pDispatcher = & pDocument->GetEventDispatcher();
1028 298282 : pNode = m_aNodePtr;
1029 : }
1030 : // this calls event listeners, do not call with locked mutex
1031 298282 : pDispatcher->dispatchEvent(*pDocument, m_rMutex, pNode, this, evt);
1032 298282 : return sal_True;
1033 : }
1034 :
1035 : ::sal_Int64 SAL_CALL
1036 509397 : CNode::getSomething(Sequence< ::sal_Int8 > const& rId)
1037 : throw (RuntimeException, std::exception)
1038 : {
1039 1018794 : if ((rId.getLength() == 16) &&
1040 509397 : (0 == memcmp(theCNodeUnoTunnelId::get().getSeq().getConstArray(),
1041 1018794 : rId.getConstArray(), 16)))
1042 : {
1043 : return ::sal::static_int_cast< sal_Int64 >(
1044 509397 : reinterpret_cast< sal_IntPtr >(this) );
1045 : }
1046 0 : return 0;
1047 : }
1048 492 : }
1049 :
1050 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|