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