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 0 : 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 0 : Context::NamespaceVectorType::value_type aVal = io_rContext.maNamespaces.back();
63 0 : io_rContext.maNamespaces.push_back( aVal );
64 0 : }
65 :
66 0 : void popContext(Context& io_rContext)
67 : {
68 0 : io_rContext.maNamespaces.pop_back();
69 0 : }
70 :
71 0 : void addNamespaces(Context& io_rContext, xmlNodePtr pNode)
72 : {
73 : // add node's namespaces to current context
74 0 : for (xmlNsPtr pNs = pNode->nsDef; pNs != 0; pNs = pNs->next) {
75 0 : 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 0 : pPrefix ? strlen(reinterpret_cast<const char*>(pPrefix)) : 0);
79 0 : const xmlChar *pHref = pNs->href;
80 : OUString val(reinterpret_cast<const sal_Char*>(pHref),
81 0 : strlen(reinterpret_cast<const char*>(pHref)),
82 0 : 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 0 : io_rContext.maNamespaceMap.find(val);
89 0 : if( aIter != io_rContext.maNamespaceMap.end() )
90 : {
91 0 : Context::Namespace aNS;
92 0 : aNS.maPrefix = prefix;
93 0 : aNS.mnToken = aIter->second;
94 0 : aNS.maNamespaceURL = val;
95 :
96 0 : io_rContext.maNamespaces.back().push_back(aNS);
97 :
98 0 : OSL_TRACE("Added with token 0x%x", aIter->second);
99 : }
100 0 : }
101 0 : }
102 :
103 0 : sal_Int32 getToken( const Context& rContext, const sal_Char* pToken )
104 : {
105 0 : const Sequence<sal_Int8> aSeq( (sal_Int8*)pToken, strlen( pToken ) );
106 0 : return rContext.mxTokenHandler->getTokenFromUTF8( aSeq );
107 : }
108 :
109 0 : sal_Int32 getTokenWithPrefix( const Context& rContext, const sal_Char* pPrefix, const sal_Char* pName )
110 : {
111 0 : sal_Int32 nNamespaceToken = FastToken::DONTKNOW;
112 : OString prefix(pPrefix,
113 0 : strlen(reinterpret_cast<const char*>(pPrefix)));
114 :
115 : OSL_TRACE("getTokenWithPrefix(): prefix %s, name %s",
116 : (const char*)pPrefix, (const char*)pName);
117 :
118 0 : Context::NamespaceVectorType::value_type::const_iterator aIter;
119 0 : if( (aIter=std::find_if(rContext.maNamespaces.back().begin(),
120 0 : rContext.maNamespaces.back().end(),
121 : boost::bind(std::equal_to<OString>(),
122 : boost::bind(&Context::Namespace::getPrefix,
123 : _1),
124 0 : boost::cref(prefix)))) != rContext.maNamespaces.back().end() )
125 : {
126 0 : nNamespaceToken = aIter->mnToken;
127 0 : sal_Int32 nNameToken = getToken( rContext, pName );
128 0 : if( nNameToken != FastToken::DONTKNOW )
129 0 : nNamespaceToken |= nNameToken;
130 : }
131 :
132 0 : return nNamespaceToken;
133 : }
134 :
135 :
136 0 : 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 0 : , m_xDocument( (m_aNodePtr->type != XML_DOCUMENT_NODE)
144 : ? &const_cast<CDocument&>(rDocument) : 0 )
145 0 : , m_rMutex(const_cast< ::osl::Mutex & >(rMutex))
146 : {
147 : OSL_ASSERT(m_aNodePtr);
148 0 : }
149 :
150 0 : void CNode::invalidate()
151 : {
152 : //remove from list if this wrapper goes away
153 0 : if (m_aNodePtr != 0 && m_xDocument.is()) {
154 0 : m_xDocument->RemoveCNode(m_aNodePtr, this);
155 : }
156 : // #i113663#: unlinked nodes will not be freed by xmlFreeDoc
157 0 : if (m_bUnlinked) {
158 0 : xmlFreeNode(m_aNodePtr);
159 : }
160 0 : m_aNodePtr = 0;
161 0 : }
162 :
163 0 : CNode::~CNode()
164 : {
165 : // if this is the document itself, the mutex is already freed!
166 0 : if (NodeType_DOCUMENT_NODE == m_aNodeType) {
167 0 : invalidate();
168 : } else {
169 0 : ::osl::MutexGuard const g(m_rMutex);
170 0 : invalidate(); // other nodes are still alive so must lock mutex
171 : }
172 0 : }
173 :
174 : CNode *
175 0 : CNode::GetImplementation(uno::Reference<uno::XInterface> const& xNode)
176 : {
177 0 : uno::Reference<lang::XUnoTunnel> const xUnoTunnel(xNode, UNO_QUERY);
178 0 : if (!xUnoTunnel.is()) { return 0; }
179 : CNode *const pCNode( reinterpret_cast< CNode* >(
180 : ::sal::static_int_cast< sal_IntPtr >(
181 0 : xUnoTunnel->getSomething(theCNodeUnoTunnelId::get().getSeq()))));
182 0 : return pCNode;
183 : }
184 :
185 0 : CDocument & CNode::GetOwnerDocument()
186 : {
187 : OSL_ASSERT(m_xDocument.is());
188 0 : return *m_xDocument; // needs overriding in CDocument!
189 : }
190 :
191 :
192 0 : 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 0 : xmlNodePtr cur = aNode;
197 0 : while (cur != 0)
198 : {
199 0 : if (cur->ns == oldNs)
200 0 : cur->ns = newNs;
201 0 : if (cur->type == XML_ELEMENT_NODE)
202 : {
203 0 : xmlAttrPtr curAttr = cur->properties;
204 0 : while(curAttr != 0)
205 : {
206 0 : if (curAttr->ns == oldNs)
207 0 : curAttr->ns = newNs;
208 0 : curAttr = curAttr->next;
209 : }
210 0 : lcl_nsexchange(cur->children, oldNs, newNs);
211 : }
212 0 : cur = cur->next;
213 : }
214 0 : }
215 :
216 0 : /*static*/ void nscleanup(const xmlNodePtr aNode, const xmlNodePtr aParent)
217 : {
218 0 : xmlNodePtr cur = aNode;
219 :
220 : //handle attributes
221 0 : if (cur != NULL && cur->type == XML_ELEMENT_NODE)
222 : {
223 0 : xmlAttrPtr curAttr = cur->properties;
224 0 : while(curAttr != 0)
225 : {
226 0 : if (curAttr->ns != NULL)
227 : {
228 0 : xmlNsPtr ns = xmlSearchNs(cur->doc, aParent, curAttr->ns->prefix);
229 0 : if (ns != NULL)
230 0 : curAttr->ns = ns;
231 : }
232 0 : curAttr = curAttr->next;
233 : }
234 : }
235 :
236 0 : while (cur != NULL)
237 : {
238 0 : nscleanup(cur->children, cur);
239 0 : if (cur->ns != NULL)
240 : {
241 0 : xmlNsPtr ns = xmlSearchNs(cur->doc, aParent, cur->ns->prefix);
242 0 : if (ns != NULL && ns != cur->ns && strcmp((char*)ns->href, (char*)cur->ns->href)==0)
243 : {
244 0 : xmlNsPtr curDef = cur->nsDef;
245 0 : xmlNsPtr *refp = &(cur->nsDef); // insert point
246 0 : while (curDef != NULL)
247 : {
248 0 : ns = xmlSearchNs(cur->doc, aParent, curDef->prefix);
249 0 : 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 0 : lcl_nsexchange(cur, curDef, ns);
254 0 : *refp = curDef->next;
255 0 : xmlFreeNs(curDef);
256 0 : curDef = *refp;
257 : } else {
258 0 : refp = &(curDef->next);
259 0 : curDef = curDef->next;
260 : }
261 : }
262 : }
263 : }
264 0 : cur = cur->next;
265 : }
266 0 : }
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 0 : Reference< XNode > SAL_CALL CNode::appendChild(
290 : Reference< XNode > const& xNewChild)
291 : throw (RuntimeException, DOMException, std::exception)
292 : {
293 0 : ::osl::ClearableMutexGuard guard(m_rMutex);
294 :
295 0 : if (0 == m_aNodePtr) { return 0; }
296 :
297 0 : CNode *const pNewChild(CNode::GetImplementation(xNewChild));
298 0 : if (!pNewChild) { throw RuntimeException(); }
299 0 : xmlNodePtr const cur = pNewChild->GetNodePtr();
300 0 : if (!cur) { throw RuntimeException(); }
301 :
302 : // error checks:
303 : // from other document
304 0 : 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 0 : if (cur == m_aNodePtr) {
311 0 : DOMException e;
312 0 : e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
313 0 : throw e;
314 : }
315 0 : if (cur->parent != NULL) {
316 0 : DOMException e;
317 0 : e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
318 0 : throw e;
319 : }
320 0 : 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 0 : xmlNodePtr res = NULL;
328 0 : 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 0 : 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 0 : if (res && (cur != res)) {
352 0 : pNewChild->invalidate(); // cur has been freed
353 : }
354 : }
355 :
356 0 : 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 0 : nscleanup(res, m_aNodePtr);
362 :
363 0 : ::rtl::Reference<CNode> const pNode = GetOwnerDocument().GetCNode(res);
364 :
365 0 : 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 0 : pNode->m_bUnlinked = false; // will be deleted by xmlFreeDoc
371 0 : Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
372 0 : Reference< XMutationEvent > event(docevent->createEvent(
373 0 : "DOMNodeInserted"), UNO_QUERY);
374 0 : event->initMutationEvent("DOMNodeInserted", sal_True, sal_False, this,
375 0 : 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 0 : guard.clear();
380 :
381 0 : dispatchEvent(event);
382 : // dispatch subtree modified for this node
383 0 : dispatchSubtreeModified();
384 :
385 0 : 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, std::exception)
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, std::exception)
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, std::exception)
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 0 : Reference< XNode > SAL_CALL CNode::getFirstChild()
437 : throw (RuntimeException, std::exception)
438 : {
439 0 : ::osl::MutexGuard const g(m_rMutex);
440 :
441 0 : if (0 == m_aNodePtr) {
442 0 : return 0;
443 : }
444 : Reference< XNode > const xNode(
445 0 : GetOwnerDocument().GetCNode(m_aNodePtr->children).get());
446 0 : return xNode;
447 : }
448 :
449 : /**
450 : The last child of this node.
451 : */
452 0 : Reference< XNode > SAL_CALL CNode::getLastChild()
453 : throw (RuntimeException, std::exception)
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, std::exception)
470 : {
471 : // see CElement/CAttr
472 0 : return OUString();
473 : }
474 :
475 :
476 : /**
477 : The namespace URI of this node, or null if it is unspecified.
478 : */
479 0 : OUString SAL_CALL CNode::getNamespaceURI()
480 : throw (RuntimeException, std::exception)
481 : {
482 0 : ::osl::MutexGuard const g(m_rMutex);
483 :
484 0 : OUString aURI;
485 0 : if (m_aNodePtr != NULL &&
486 0 : (m_aNodePtr->type == XML_ELEMENT_NODE || m_aNodePtr->type == XML_ATTRIBUTE_NODE) &&
487 0 : m_aNodePtr->ns != NULL)
488 : {
489 0 : const xmlChar* xHref = m_aNodePtr->ns->href;
490 0 : aURI = OUString((sal_Char*)xHref, strlen((char*)xHref), RTL_TEXTENCODING_UTF8);
491 : }
492 0 : return aURI;
493 : }
494 :
495 : /**
496 : The node immediately following this node.
497 : */
498 0 : Reference< XNode > SAL_CALL CNode::getNextSibling()
499 : throw (RuntimeException, std::exception)
500 : {
501 0 : ::osl::MutexGuard const g(m_rMutex);
502 :
503 0 : if (0 == m_aNodePtr) {
504 0 : return 0;
505 : }
506 : Reference< XNode > const xNode(
507 0 : GetOwnerDocument().GetCNode(m_aNodePtr->next).get());
508 0 : 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, std::exception)
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 0 : NodeType SAL_CALL CNode::getNodeType()
543 : throw (RuntimeException, std::exception)
544 : {
545 0 : ::osl::MutexGuard const g(m_rMutex);
546 :
547 0 : 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, std::exception)
555 : {
556 0 : OUString aValue;
557 0 : return aValue;
558 : }
559 :
560 : /**
561 : The Document object associated with this node.
562 : */
563 0 : Reference< XDocument > SAL_CALL CNode::getOwnerDocument()
564 : throw (RuntimeException, std::exception)
565 : {
566 0 : ::osl::MutexGuard const g(m_rMutex);
567 :
568 0 : if (0 == m_aNodePtr) {
569 0 : return 0;
570 : }
571 0 : Reference< XDocument > const xDoc(& GetOwnerDocument());
572 0 : return xDoc;
573 : }
574 :
575 : /**
576 : The parent of this node.
577 : */
578 0 : Reference< XNode > SAL_CALL CNode::getParentNode()
579 : throw (RuntimeException, std::exception)
580 : {
581 0 : ::osl::MutexGuard const g(m_rMutex);
582 :
583 0 : if (0 == m_aNodePtr) {
584 0 : return 0;
585 : }
586 : Reference< XNode > const xNode(
587 0 : GetOwnerDocument().GetCNode(m_aNodePtr->parent).get());
588 0 : return xNode;
589 : }
590 :
591 : /**
592 : The namespace prefix of this node, or null if it is unspecified.
593 : */
594 0 : OUString SAL_CALL CNode::getPrefix()
595 : throw (RuntimeException, std::exception)
596 : {
597 0 : ::osl::MutexGuard const g(m_rMutex);
598 :
599 0 : OUString aPrefix;
600 0 : if (m_aNodePtr != NULL &&
601 0 : (m_aNodePtr->type == XML_ELEMENT_NODE || m_aNodePtr->type == XML_ATTRIBUTE_NODE) &&
602 0 : m_aNodePtr->ns != NULL)
603 : {
604 0 : const xmlChar* xPrefix = m_aNodePtr->ns->prefix;
605 0 : if( xPrefix != NULL )
606 0 : aPrefix = OUString((sal_Char*)xPrefix, strlen((char*)xPrefix), RTL_TEXTENCODING_UTF8);
607 : }
608 0 : 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, std::exception)
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 0 : sal_Bool SAL_CALL CNode::hasAttributes()
632 : throw (RuntimeException, std::exception)
633 : {
634 0 : ::osl::MutexGuard const g(m_rMutex);
635 :
636 0 : 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, std::exception)
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, std::exception)
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, std::exception)
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, std::exception)
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 0 : CNode::removeChild(const Reference< XNode >& xOldChild)
760 : throw (RuntimeException, DOMException, std::exception)
761 : {
762 0 : if (!xOldChild.is()) {
763 0 : throw RuntimeException();
764 : }
765 :
766 0 : if (xOldChild->getOwnerDocument() != getOwnerDocument()) {
767 0 : DOMException e;
768 0 : e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR;
769 0 : throw e;
770 : }
771 0 : 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 0 : ::osl::ClearableMutexGuard guard(m_rMutex);
778 :
779 0 : if (!m_aNodePtr) { throw RuntimeException(); }
780 :
781 0 : Reference<XNode> xReturn( xOldChild );
782 :
783 0 : ::rtl::Reference<CNode> const pOld(CNode::GetImplementation(xOldChild));
784 0 : if (!pOld.is()) { throw RuntimeException(); }
785 0 : xmlNodePtr const old = pOld->GetNodePtr();
786 0 : if (!old) { throw RuntimeException(); }
787 :
788 0 : 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 0 : xmlUnlinkNode(old);
798 0 : 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 0 : Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
810 0 : Reference< XMutationEvent > event(docevent->createEvent(
811 0 : "DOMNodeRemoved"), UNO_QUERY);
812 0 : event->initMutationEvent("DOMNodeRemoved",
813 : sal_True,
814 : sal_False,
815 : this,
816 0 : 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 0 : guard.clear();
821 :
822 0 : dispatchEvent(event);
823 : // subtree modified for this node
824 0 : dispatchSubtreeModified();
825 :
826 0 : 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, std::exception)
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 0 : void CNode::dispatchSubtreeModified()
934 : {
935 : // only uses UNO interfaces => needs no mutex
936 :
937 : // dispatch DOMSubtreeModified
938 : // target is _this_ node
939 0 : Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
940 0 : Reference< XMutationEvent > event(docevent->createEvent(
941 0 : "DOMSubtreeModified"), UNO_QUERY);
942 0 : event->initMutationEvent(
943 : "DOMSubtreeModified", sal_True,
944 : sal_False, Reference< XNode >(),
945 0 : OUString(), OUString(), OUString(), (AttrChangeType)0 );
946 0 : dispatchEvent(event);
947 0 : }
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, std::exception)
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, std::exception)
967 : {
968 0 : ::osl::MutexGuard const g(m_rMutex);
969 :
970 0 : if ((0 == m_aNodePtr) ||
971 0 : ((m_aNodePtr->type != XML_ELEMENT_NODE) &&
972 0 : (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, std::exception)
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, std::exception)
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 0 : sal_Bool SAL_CALL CNode::dispatchEvent(const Reference< XEvent >& evt)
1014 : throw(RuntimeException, EventException, std::exception)
1015 : {
1016 : CDocument * pDocument;
1017 : events::CEventDispatcher * pDispatcher;
1018 : xmlNodePtr pNode;
1019 : {
1020 0 : ::osl::MutexGuard const g(m_rMutex);
1021 :
1022 0 : pDocument = & GetOwnerDocument();
1023 0 : pDispatcher = & pDocument->GetEventDispatcher();
1024 0 : pNode = m_aNodePtr;
1025 : }
1026 : // this calls event listeners, do not call with locked mutex
1027 0 : pDispatcher->dispatchEvent(*pDocument, m_rMutex, pNode, this, evt);
1028 0 : return sal_True;
1029 : }
1030 :
1031 : ::sal_Int64 SAL_CALL
1032 0 : CNode::getSomething(Sequence< ::sal_Int8 > const& rId)
1033 : throw (RuntimeException, std::exception)
1034 : {
1035 0 : if ((rId.getLength() == 16) &&
1036 0 : (0 == memcmp(theCNodeUnoTunnelId::get().getSeq().getConstArray(),
1037 0 : rId.getConstArray(), 16)))
1038 : {
1039 : return ::sal::static_int_cast< sal_Int64 >(
1040 0 : reinterpret_cast< sal_IntPtr >(this) );
1041 : }
1042 0 : return 0;
1043 : }
1044 0 : }
1045 :
1046 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|