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