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 <sal/config.h>
21 
22 #include <osl/diagnose.h>
23 #include <com/sun/star/uno/XComponentContext.hpp>
24 #include <com/sun/star/xml/crypto/sax/XSAXEventKeeper.hpp>
25 #include <cppuhelper/supportsservice.hxx>
26 #include <xmlsec/xmldocumentwrapper_xmlsecimpl.hxx>
27 #include "xmlelementwrapper_xmlsecimpl.hxx"
28 
29 #include <xmloff/attrlist.hxx>
30 
31 #ifdef UNX
32 #define stricmp strcasecmp
33 #endif
34 
35 using namespace com::sun::star;
36 namespace cssl = com::sun::star::lang;
37 namespace cssxc = com::sun::star::xml::crypto;
38 namespace cssxcsax = com::sun::star::xml::csax;
39 namespace cssxs = com::sun::star::xml::sax;
40 namespace cssxw = com::sun::star::xml::wrapper;
41 
42 #define STRXMLNS "xmlns"
43 
44 /* used by the recursiveDelete method */
45 #define NODE_REMOVED    0
46 #define NODE_NOTREMOVED 1
47 #define NODE_STOPPED     2
48 
XMLDocumentWrapper_XmlSecImpl()49 XMLDocumentWrapper_XmlSecImpl::XMLDocumentWrapper_XmlSecImpl()
50     : m_nCurrentPosition(0)
51     , m_pStopAtNode(nullptr)
52     , m_pCurrentReservedNode(nullptr)
53     , m_nReservedNodeIndex(0)
54 {
55     saxHelper.startDocument();
56     m_pDocument = saxHelper.getDocument();
57 
58     /*
59      * creates the virtual root element
60      */
61     saxHelper.startElement("root", uno::Sequence<cssxcsax::XMLAttribute>());
62 
63     m_pRootElement = saxHelper.getCurrentNode();
64     m_pCurrentElement = m_pRootElement;
65 }
66 
~XMLDocumentWrapper_XmlSecImpl()67 XMLDocumentWrapper_XmlSecImpl::~XMLDocumentWrapper_XmlSecImpl()
68 {
69     saxHelper.endDocument();
70     xmlFreeDoc(m_pDocument);
71 }
72 
getNextSAXEvent()73 void XMLDocumentWrapper_XmlSecImpl::getNextSAXEvent()
74 /****** XMLDocumentWrapper_XmlSecImpl/getNextSAXEvent *************************
75  *
76  *   NAME
77  *  getNextSAXEvent -- Prepares the next SAX event to be manipulate
78  *
79  *   FUNCTION
80  *  When converting the document into SAX events, this method is used to
81  *  decide the next SAX event to be generated.
82  *  Two member variables are checked to make the decision, the
83  *  m_pCurrentElement and the m_nCurrentPosition.
84  *  The m_pCurrentElement represents the node which have been covered, and
85  *  the m_nCurrentPosition represents the event which have been sent.
86  *  For example, suppose that the m_pCurrentElement
87  *  points to element A, and the m_nCurrentPosition equals to
88  *  NODEPOSITION_STARTELEMENT, then the next SAX event should be the
89  *  endElement for element A if A has no child, or startElement for the
90  *  first child element of element A otherwise.
91  *  The m_nCurrentPosition can be one of following values:
92  *  NODEPOSITION_STARTELEMENT for startElement;
93  *  NODEPOSITION_ENDELEMENT for endElement;
94  *  NODEPOSITION_NORMAL for other SAX events;
95  ******************************************************************************/
96 {
97     OSL_ASSERT( m_pCurrentElement != nullptr );
98 
99         /*
100          * Get the next event through tree order.
101          *
102          * if the current event is a startElement, then the next
103          * event depends on whether or not the current node has
104          * children.
105          */
106     if (m_nCurrentPosition == NODEPOSITION_STARTELEMENT)
107     {
108             /*
109              * If the current node has children, then its first child
110              * should be next current node, and the next event will be
111              * startElement or characters(PI) based on that child's node
112              * type. Otherwise, the endElement of current node is the
113              * next event.
114              */
115         if (m_pCurrentElement->children != nullptr)
116         {
117             m_pCurrentElement = m_pCurrentElement->children;
118             m_nCurrentPosition
119                 = (m_pCurrentElement->type == XML_ELEMENT_NODE)?
120                     NODEPOSITION_STARTELEMENT:NODEPOSITION_NORMAL;
121         }
122         else
123         {
124             m_nCurrentPosition = NODEPOSITION_ENDELEMENT;
125         }
126     }
127         /*
128          * if the current event is a not startElement, then the next
129          * event depends on whether or not the current node has
130          * following sibling.
131          */
132     else if (m_nCurrentPosition == NODEPOSITION_ENDELEMENT || m_nCurrentPosition == NODEPOSITION_NORMAL)
133     {
134         xmlNodePtr pNextSibling = m_pCurrentElement->next;
135 
136             /*
137              * If the current node has following sibling, that sibling
138              * should be next current node, and the next event will be
139              * startElement or characters(PI) based on that sibling's node
140              * type. Otherwise, the endElement of current node's parent
141              * becomes the next event.
142              */
143         if (pNextSibling != nullptr)
144         {
145             m_pCurrentElement = pNextSibling;
146             m_nCurrentPosition
147                 = (m_pCurrentElement->type == XML_ELEMENT_NODE)?
148                     NODEPOSITION_STARTELEMENT:NODEPOSITION_NORMAL;
149         }
150         else
151         {
152             m_pCurrentElement = m_pCurrentElement->parent;
153             m_nCurrentPosition = NODEPOSITION_ENDELEMENT;
154         }
155     }
156 }
157 
sendStartElement(const uno::Reference<cssxs::XDocumentHandler> & xHandler,const uno::Reference<cssxs::XDocumentHandler> & xHandler2,const xmlNodePtr pNode)158 void XMLDocumentWrapper_XmlSecImpl::sendStartElement(
159     const uno::Reference< cssxs::XDocumentHandler >& xHandler,
160     const uno::Reference< cssxs::XDocumentHandler >& xHandler2,
161     const xmlNodePtr pNode)
162 /****** XMLDocumentWrapper_XmlSecImpl/sendStartElement ************************
163  *
164  *   NAME
165  *  sendStartElement -- Constructs a startElement SAX event
166  *
167  *   FUNCTION
168  *  Used when converting the document into SAX event stream.
169  *  This method constructs a startElement SAX event for a particular
170  *  element, then calls the startElement methods of the XDocumentHandlers.
171  *
172  *   INPUTS
173  *  xHandler -  the first XDocumentHandler interface to receive the
174  *          startElement SAX event. It can be NULL.
175  *  xHandler2 - the second XDocumentHandler interface to receive the
176  *          startElement SAX event. It can't be NULL.
177  *  pNode -     the node on which the startElement should be generated.
178  *          This node must be an element type.
179  ******************************************************************************/
180 {
181     SvXMLAttributeList* pAttributeList = new SvXMLAttributeList();
182     uno::Reference < cssxs::XAttributeList > xAttrList(pAttributeList);
183 
184     xmlNsPtr pNsDef = pNode->nsDef;
185 
186     while (pNsDef != nullptr)
187     {
188         const xmlChar* pNsPrefix = pNsDef->prefix;
189         const xmlChar* pNsHref = pNsDef->href;
190 
191         if (pNsDef->prefix == nullptr)
192         {
193             pAttributeList->AddAttribute(
194                 STRXMLNS,
195                 OUString::fromUtf8(reinterpret_cast<char const *>(pNsHref)));
196         }
197         else
198         {
199             pAttributeList->AddAttribute(
200                 STRXMLNS ":"
201                 +OUString::fromUtf8(reinterpret_cast<char const *>(pNsPrefix)),
202                 OUString::fromUtf8(reinterpret_cast<char const *>(pNsHref)));
203         }
204 
205         pNsDef = pNsDef->next;
206     }
207 
208     xmlAttrPtr pAttr = pNode->properties;
209 
210     while (pAttr != nullptr)
211     {
212         const xmlChar* pAttrName = pAttr->name;
213         xmlNsPtr pAttrNs = pAttr->ns;
214 
215         OUString ouAttrName;
216         if (pAttrNs == nullptr)
217         {
218             ouAttrName = OUString::fromUtf8(reinterpret_cast<char const *>(pAttrName));
219         }
220         else
221         {
222             ouAttrName = OUString::fromUtf8(reinterpret_cast<char const *>(pAttrNs->prefix))
223                 + ":" + OUString::fromUtf8(reinterpret_cast<char const *>(pAttrName));
224         }
225 
226         pAttributeList->AddAttribute(
227             ouAttrName,
228             OUString::fromUtf8(reinterpret_cast<char*>(pAttr->children->content)));
229         pAttr = pAttr->next;
230     }
231 
232     OString sNodeName = getNodeQName(pNode);
233 
234     if (xHandler.is())
235     {
236         xHandler->startElement(
237             OUString::fromUtf8(sNodeName),
238             xAttrList);
239     }
240 
241     xHandler2->startElement(
242         OUString::fromUtf8(sNodeName),
243         xAttrList);
244 }
245 
sendEndElement(const uno::Reference<cssxs::XDocumentHandler> & xHandler,const uno::Reference<cssxs::XDocumentHandler> & xHandler2,const xmlNodePtr pNode)246 void XMLDocumentWrapper_XmlSecImpl::sendEndElement(
247     const uno::Reference< cssxs::XDocumentHandler >& xHandler,
248     const uno::Reference< cssxs::XDocumentHandler >& xHandler2,
249     const xmlNodePtr pNode)
250 /****** XMLDocumentWrapper_XmlSecImpl/sendEndElement **************************
251  *
252  *   NAME
253  *  sendEndElement -- Constructs an endElement SAX event
254  *
255  *   FUNCTION
256  *  Used when converting the document into SAX event stream.
257  *  This method constructs an endElement SAX event for a particular
258  *  element, then calls the endElement methods of the XDocumentHandlers.
259  *
260  *   INPUTS
261  *  xHandler -  the first XDocumentHandler interface to receive the
262  *          endElement SAX event. It can be NULL.
263  *  xHandler2 - the second XDocumentHandler interface to receive the
264  *          endElement SAX event. It can't be NULL.
265  *  pNode -     the node on which the endElement should be generated.
266  *          This node must be an element type.
267  ******************************************************************************/
268 {
269     OString sNodeName = getNodeQName(pNode);
270 
271     if (xHandler.is())
272     {
273         xHandler->endElement(OUString::fromUtf8(sNodeName));
274     }
275 
276     xHandler2->endElement(OUString::fromUtf8(sNodeName));
277 }
278 
sendNode(const uno::Reference<cssxs::XDocumentHandler> & xHandler,const uno::Reference<cssxs::XDocumentHandler> & xHandler2,const xmlNodePtr pNode)279 void XMLDocumentWrapper_XmlSecImpl::sendNode(
280     const uno::Reference< cssxs::XDocumentHandler >& xHandler,
281     const uno::Reference< cssxs::XDocumentHandler >& xHandler2,
282     const xmlNodePtr pNode)
283 /****** XMLDocumentWrapper_XmlSecImpl/sendNode ********************************
284  *
285  *   NAME
286  *  sendNode -- Constructs a characters SAX event or a
287  *  processingInstruction SAX event
288  *
289  *   FUNCTION
290  *  Used when converting the document into SAX event stream.
291  *  This method constructs a characters SAX event or a
292  *  processingInstructionfor SAX event based on the type of a particular
293  *  element, then calls the corresponding methods of the XDocumentHandlers.
294  *
295  *   INPUTS
296  *  xHandler -  the first XDocumentHandler interface to receive the
297  *          SAX event. It can be NULL.
298  *  xHandler2 - the second XDocumentHandler interface to receive the
299  *          SAX event. It can't be NULL.
300  *  pNode -     the node on which the endElement should be generated.
301  *          If it is a text node, then a characters SAX event is
302  *          generated; if it is a PI node, then a
303  *          processingInstructionfor SAX event is generated.
304  ******************************************************************************/
305 {
306     xmlElementType type = pNode->type;
307 
308     if (type == XML_TEXT_NODE)
309     {
310         if (xHandler.is())
311         {
312             xHandler->characters(OUString::fromUtf8(reinterpret_cast<char*>(pNode->content)));
313         }
314 
315         xHandler2->characters(OUString::fromUtf8(reinterpret_cast<char*>(pNode->content)));
316     }
317     else if (type == XML_PI_NODE)
318     {
319         if (xHandler.is())
320         {
321             xHandler->processingInstruction(
322                 OUString::fromUtf8(reinterpret_cast<char const *>(pNode->name)),
323                 OUString::fromUtf8(reinterpret_cast<char const *>(pNode->content)));
324         }
325 
326         xHandler2->processingInstruction(
327             OUString::fromUtf8(reinterpret_cast<char const *>(pNode->name)),
328             OUString::fromUtf8(reinterpret_cast<char*>(pNode->content)));
329     }
330 }
331 
getNodeQName(const xmlNodePtr pNode)332 OString XMLDocumentWrapper_XmlSecImpl::getNodeQName(const xmlNodePtr pNode)
333 /****** XMLDocumentWrapper_XmlSecImpl/getNodeQName ****************************
334  *
335  *   NAME
336  *  getNodeQName -- Retrieves the qualified name of a node
337  *
338  *   INPUTS
339  *  pNode - the node whose name will be retrieved
340  *
341  *   RESULT
342  *  name - the node's qualified name
343  ******************************************************************************/
344 {
345     OString sNodeName(reinterpret_cast<const char*>(pNode->name));
346     if (pNode->ns != nullptr)
347     {
348         xmlNsPtr pNs = pNode->ns;
349 
350         if (pNs->prefix != nullptr)
351         {
352             OString sPrefix(reinterpret_cast<const char*>(pNs->prefix));
353             sNodeName = sPrefix + ":" + sNodeName;
354         }
355     }
356 
357     return sNodeName;
358 }
359 
checkElement(const uno::Reference<cssxw::XXMLElementWrapper> & xXMLElement)360 xmlNodePtr XMLDocumentWrapper_XmlSecImpl::checkElement( const uno::Reference< cssxw::XXMLElementWrapper >& xXMLElement)
361 /****** XMLDocumentWrapper_XmlSecImpl/checkElement ****************************
362  *
363  *   NAME
364  *  checkElement -- Retrieves the node wrapped by an XXMLElementWrapper
365  *  interface
366  *
367  *   INPUTS
368  *  xXMLElement -   the XXMLElementWrapper interface wrapping a node
369  *
370  *   RESULT
371  *  node - the node wrapped in the XXMLElementWrapper interface
372  ******************************************************************************/
373 {
374     xmlNodePtr rc = nullptr;
375 
376     if (xXMLElement.is())
377     {
378         uno::Reference< cssl::XUnoTunnel > xNodTunnel( xXMLElement, uno::UNO_QUERY_THROW ) ;
379         XMLElementWrapper_XmlSecImpl* pElement
380             = reinterpret_cast<XMLElementWrapper_XmlSecImpl*>(
381                 sal::static_int_cast<sal_uIntPtr>(
382                     xNodTunnel->getSomething(
383                         XMLElementWrapper_XmlSecImpl::getUnoTunnelId() ))) ;
384 
385         if( pElement == nullptr ) {
386             throw uno::RuntimeException() ;
387         }
388 
389         rc = pElement->getNativeElement();
390     }
391 
392     return rc;
393 }
394 
recursiveDelete(const xmlNodePtr pNode)395 sal_Int32 XMLDocumentWrapper_XmlSecImpl::recursiveDelete(
396     const xmlNodePtr pNode)
397 /****** XMLDocumentWrapper_XmlSecImpl/recursiveDelete *************************
398  *
399  *   NAME
400  *  recursiveDelete -- Deletes a particular node with its branch.
401  *
402  *   FUNCTION
403  *  Deletes a particular node with its branch, while reserving the nodes
404  *  (and their branches) listed in the m_aReservedNodes.
405  *  The deletion process is performed in the tree order, that is, a node
406  *  is deleted after its previous sibling node is deleted, a parent node
407  *  is deleted after its branch is deleted.
408  *  During the deletion process when the m_pStopAtNode is reached, the
409  *  progress is interrupted at once.
410  *
411  *   INPUTS
412  *  pNode - the node to be deleted
413  *
414  *   RESULT
415  *  result -    the result of the deletion process, can be one of following
416  *          values:
417  *          NODE_STOPPED - the process is interrupted by meeting the
418  *              m_pStopAtNode
419  *          NODE_NOTREMOVED - the pNode is not completely removed
420  *              because there is its descendant in the
421  *              m_aReservedNodes list
422  *          NODE_REMOVED - the pNode and its branch are completely
423  *              removed
424  *
425  *   NOTES
426  *  The node in the m_aReservedNodes list must be in the tree order, otherwise
427  *  the result is unpredictable.
428  ******************************************************************************/
429 {
430     if (pNode == m_pStopAtNode)
431     {
432         return NODE_STOPPED;
433     }
434 
435     if (pNode != m_pCurrentReservedNode)
436     {
437         xmlNodePtr pChild = pNode->children;
438 
439         xmlNodePtr pNextSibling;
440         bool bIsRemoved = true;
441         sal_Int32 nResult;
442 
443         while( pChild != nullptr )
444         {
445             pNextSibling = pChild->next;
446             nResult = recursiveDelete(pChild);
447 
448             switch (nResult)
449             {
450             case NODE_STOPPED:
451                 return NODE_STOPPED;
452             case NODE_NOTREMOVED:
453                 bIsRemoved = false;
454                 break;
455             case NODE_REMOVED:
456                 removeNode(pChild);
457                 break;
458             default:
459                 throw uno::RuntimeException();
460             }
461 
462             pChild = pNextSibling;
463         }
464 
465         if (pNode == m_pCurrentElement)
466         {
467             bIsRemoved = false;
468         }
469 
470         return bIsRemoved?NODE_REMOVED:NODE_NOTREMOVED;
471     }
472     else
473     {
474         getNextReservedNode();
475         return NODE_NOTREMOVED;
476     }
477 }
478 
getNextReservedNode()479 void XMLDocumentWrapper_XmlSecImpl::getNextReservedNode()
480 /****** XMLDocumentWrapper_XmlSecImpl/getNextReservedNode *********************
481  *
482  *   NAME
483  *  getNextReservedNode -- Highlights the next reserved node in the
484  *  reserved node list
485  *
486  *   FUNCTION
487  *  The m_aReservedNodes array holds a node list, while the
488  *  m_pCurrentReservedNode points to the one currently highlighted.
489  *  This method is used to highlight the next node in the node list.
490  *  This method is called at the time when the current highlighted node
491  *  has been already processed, and the next node should be ready.
492  ******************************************************************************/
493 {
494     if (m_nReservedNodeIndex < m_aReservedNodes.getLength())
495     {
496         m_pCurrentReservedNode = checkElement( m_aReservedNodes[m_nReservedNodeIndex] );
497         m_nReservedNodeIndex ++;
498     }
499     else
500     {
501         m_pCurrentReservedNode = nullptr;
502     }
503 }
504 
removeNode(const xmlNodePtr pNode) const505 void XMLDocumentWrapper_XmlSecImpl::removeNode(const xmlNodePtr pNode) const
506 /****** XMLDocumentWrapper_XmlSecImpl/removeNode ******************************
507  *
508  *   NAME
509  *  removeNode -- Deletes a node with its branch unconditionally
510  *
511  *   FUNCTION
512  *  Delete the node along with its branch from the document.
513  *
514  *   INPUTS
515  *  pNode - the node to be deleted
516  ******************************************************************************/
517 {
518     /* you can't remove the current node */
519     OSL_ASSERT( m_pCurrentElement != pNode );
520 
521     xmlAttrPtr pAttr = pNode->properties;
522 
523     while (pAttr != nullptr)
524     {
525         if (!stricmp(reinterpret_cast<char const *>(pAttr->name), "id"))
526         {
527             xmlRemoveID(m_pDocument, pAttr);
528         }
529 
530         pAttr = pAttr->next;
531     }
532 
533     xmlUnlinkNode(pNode);
534     xmlFreeNode(pNode);
535 }
536 
buildIDAttr(xmlNodePtr pNode) const537 void XMLDocumentWrapper_XmlSecImpl::buildIDAttr(xmlNodePtr pNode) const
538 /****** XMLDocumentWrapper_XmlSecImpl/buildIDAttr *****************************
539  *
540  *   NAME
541  *  buildIDAttr -- build the ID attribute of a node
542  *
543  *   INPUTS
544  *  pNode - the node whose id attribute will be built
545  ******************************************************************************/
546 {
547     xmlAttrPtr idAttr = xmlHasProp( pNode, reinterpret_cast<const unsigned char *>("id") );
548     if (idAttr == nullptr)
549     {
550         idAttr = xmlHasProp( pNode, reinterpret_cast<const unsigned char *>("Id") );
551     }
552 
553     if (idAttr != nullptr)
554     {
555         xmlChar* idValue = xmlNodeListGetString( m_pDocument, idAttr->children, 1 ) ;
556         xmlAddID( nullptr, m_pDocument, idValue, idAttr );
557     }
558 }
559 
rebuildIDLink(xmlNodePtr pNode) const560 void XMLDocumentWrapper_XmlSecImpl::rebuildIDLink(xmlNodePtr pNode) const
561 /****** XMLDocumentWrapper_XmlSecImpl/rebuildIDLink ***************************
562  *
563  *   NAME
564  *  rebuildIDLink -- rebuild the ID link for the branch
565  *
566  *   INPUTS
567  *  pNode - the node, from which the branch will be rebuilt
568  ******************************************************************************/
569 {
570     if (pNode != nullptr && pNode->type == XML_ELEMENT_NODE)
571     {
572         buildIDAttr( pNode );
573 
574         xmlNodePtr child = pNode->children;
575         while (child != nullptr)
576         {
577             rebuildIDLink(child);
578             child = child->next;
579         }
580     }
581 }
582 
583 /* XXMLDocumentWrapper */
getCurrentElement()584 uno::Reference< cssxw::XXMLElementWrapper > SAL_CALL XMLDocumentWrapper_XmlSecImpl::getCurrentElement(  )
585 {
586     XMLElementWrapper_XmlSecImpl* pElement = new XMLElementWrapper_XmlSecImpl(m_pCurrentElement);
587     return uno::Reference< cssxw::XXMLElementWrapper >(pElement);
588 }
589 
setCurrentElement(const uno::Reference<cssxw::XXMLElementWrapper> & element)590 void SAL_CALL XMLDocumentWrapper_XmlSecImpl::setCurrentElement( const uno::Reference< cssxw::XXMLElementWrapper >& element )
591 {
592     m_pCurrentElement = checkElement( element );
593     saxHelper.setCurrentNode( m_pCurrentElement );
594 }
595 
removeCurrentElement()596 void SAL_CALL XMLDocumentWrapper_XmlSecImpl::removeCurrentElement(  )
597 {
598     OSL_ASSERT( m_pCurrentElement != nullptr );
599 
600     xmlNodePtr pOldCurrentElement = m_pCurrentElement;
601 
602     /*
603      * pop the top node in the parser context's
604      * nodeTab stack, then the parent of that node will
605      * automatically become the new stack top, and
606      * the current node as well.
607      */
608     saxHelper.endElement(OUString::fromUtf8(reinterpret_cast<char const *>(pOldCurrentElement->name)));
609     m_pCurrentElement = saxHelper.getCurrentNode();
610 
611     /*
612      * remove the node
613      */
614     removeNode(pOldCurrentElement);
615 }
616 
isCurrent(const uno::Reference<cssxw::XXMLElementWrapper> & node)617 sal_Bool SAL_CALL XMLDocumentWrapper_XmlSecImpl::isCurrent( const uno::Reference< cssxw::XXMLElementWrapper >& node )
618 {
619     xmlNodePtr pNode = checkElement(node);
620     return (pNode == m_pCurrentElement);
621 }
622 
isCurrentElementEmpty()623 sal_Bool SAL_CALL XMLDocumentWrapper_XmlSecImpl::isCurrentElementEmpty(  )
624 {
625     bool rc = false;
626 
627     if (m_pCurrentElement->children == nullptr)
628     {
629         rc = true;
630     }
631 
632     return rc;
633 }
634 
getNodeName(const uno::Reference<cssxw::XXMLElementWrapper> & node)635 OUString SAL_CALL XMLDocumentWrapper_XmlSecImpl::getNodeName( const uno::Reference< cssxw::XXMLElementWrapper >& node )
636 {
637     xmlNodePtr pNode = checkElement(node);
638     return OUString::fromUtf8(reinterpret_cast<char const *>(pNode->name));
639 }
640 
clearUselessData(const uno::Reference<cssxw::XXMLElementWrapper> & node,const uno::Sequence<uno::Reference<cssxw::XXMLElementWrapper>> & reservedDescendants,const uno::Reference<cssxw::XXMLElementWrapper> & stopAtNode)641 void SAL_CALL XMLDocumentWrapper_XmlSecImpl::clearUselessData(
642     const uno::Reference< cssxw::XXMLElementWrapper >& node,
643     const uno::Sequence< uno::Reference< cssxw::XXMLElementWrapper > >& reservedDescendants,
644     const uno::Reference< cssxw::XXMLElementWrapper >& stopAtNode )
645 {
646     xmlNodePtr pTargetNode = checkElement(node);
647 
648     m_pStopAtNode = checkElement(stopAtNode);
649     m_aReservedNodes = reservedDescendants;
650     m_nReservedNodeIndex = 0;
651 
652     getNextReservedNode();
653 
654     recursiveDelete(pTargetNode);
655 }
656 
collapse(const uno::Reference<cssxw::XXMLElementWrapper> & node)657 void SAL_CALL XMLDocumentWrapper_XmlSecImpl::collapse( const uno::Reference< cssxw::XXMLElementWrapper >& node )
658 {
659     xmlNodePtr pTargetNode = checkElement(node);
660     xmlNodePtr pParent;
661 
662     while (pTargetNode != nullptr)
663     {
664         if (pTargetNode->children != nullptr || pTargetNode == m_pCurrentElement)
665         {
666             break;
667         }
668 
669         pParent = pTargetNode->parent;
670         removeNode(pTargetNode);
671         pTargetNode = pParent;
672     }
673 }
674 
getTree(const uno::Reference<cssxs::XDocumentHandler> & handler)675 void SAL_CALL XMLDocumentWrapper_XmlSecImpl::getTree( const uno::Reference< cssxs::XDocumentHandler >& handler )
676 {
677     if (m_pRootElement != nullptr)
678     {
679         xmlNodePtr pTempCurrentElement = m_pCurrentElement;
680         sal_Int32 nTempCurrentPosition = m_nCurrentPosition;
681 
682         m_pCurrentElement = m_pRootElement;
683 
684         m_nCurrentPosition = NODEPOSITION_STARTELEMENT;
685 
686         while(true)
687         {
688             switch (m_nCurrentPosition)
689             {
690             case NODEPOSITION_STARTELEMENT:
691                 sendStartElement(nullptr, handler, m_pCurrentElement);
692                 break;
693             case NODEPOSITION_ENDELEMENT:
694                 sendEndElement(nullptr, handler, m_pCurrentElement);
695                 break;
696             case NODEPOSITION_NORMAL:
697                 sendNode(nullptr, handler, m_pCurrentElement);
698                 break;
699             }
700 
701             if ( (m_pCurrentElement == m_pRootElement) && (m_nCurrentPosition == NODEPOSITION_ENDELEMENT ))
702             {
703                 break;
704             }
705 
706             getNextSAXEvent();
707         }
708 
709         m_pCurrentElement = pTempCurrentElement;
710         m_nCurrentPosition = nTempCurrentPosition;
711     }
712 }
713 
generateSAXEvents(const uno::Reference<cssxs::XDocumentHandler> & handler,const uno::Reference<cssxs::XDocumentHandler> & xEventKeeperHandler,const uno::Reference<cssxw::XXMLElementWrapper> & startNode,const uno::Reference<cssxw::XXMLElementWrapper> & endNode)714 void SAL_CALL XMLDocumentWrapper_XmlSecImpl::generateSAXEvents(
715     const uno::Reference< cssxs::XDocumentHandler >& handler,
716     const uno::Reference< cssxs::XDocumentHandler >& xEventKeeperHandler,
717     const uno::Reference< cssxw::XXMLElementWrapper >& startNode,
718     const uno::Reference< cssxw::XXMLElementWrapper >& endNode )
719 {
720         /*
721          * The first SAX event is the startElement of the startNode
722          * element.
723          */
724     bool bHasCurrentElementChild = (m_pCurrentElement->children != nullptr);
725 
726     xmlNodePtr pTempCurrentElement = m_pCurrentElement;
727 
728     m_pCurrentElement = checkElement(startNode);
729 
730     if (m_pCurrentElement->type == XML_ELEMENT_NODE)
731     {
732         m_nCurrentPosition = NODEPOSITION_STARTELEMENT;
733     }
734     else
735     {
736         m_nCurrentPosition = NODEPOSITION_NORMAL;
737     }
738 
739     xmlNodePtr pEndNode = checkElement(endNode);
740 
741     uno::Reference < cssxc::sax::XSAXEventKeeper > xSAXEventKeeper( xEventKeeperHandler, uno::UNO_QUERY );
742 
743     uno::Reference< cssxs::XDocumentHandler > xHandler = handler;
744 
745     while(true)
746     {
747         switch (m_nCurrentPosition)
748         {
749         case NODEPOSITION_STARTELEMENT:
750             sendStartElement(xHandler, xEventKeeperHandler, m_pCurrentElement);
751             break;
752         case NODEPOSITION_ENDELEMENT:
753             sendEndElement(xHandler, xEventKeeperHandler, m_pCurrentElement);
754             break;
755         case NODEPOSITION_NORMAL:
756             sendNode(xHandler, xEventKeeperHandler, m_pCurrentElement);
757             break;
758         default:
759             throw uno::RuntimeException();
760         }
761 
762         if (xSAXEventKeeper->isBlocking())
763         {
764             xHandler = nullptr;
765         }
766 
767         if (pEndNode == nullptr &&
768             ((bHasCurrentElementChild && m_pCurrentElement == xmlGetLastChild(pTempCurrentElement) && m_nCurrentPosition != NODEPOSITION_STARTELEMENT) ||
769              (!bHasCurrentElementChild && m_pCurrentElement == pTempCurrentElement && m_nCurrentPosition == NODEPOSITION_STARTELEMENT)))
770         {
771             break;
772         }
773 
774         getNextSAXEvent();
775 
776             /*
777              * If there is an end point specified, then check whether
778              * the current node equals to the end point. If so, stop
779              * generating.
780              */
781         if (pEndNode != nullptr && m_pCurrentElement == pEndNode)
782         {
783             break;
784         }
785     }
786 
787     m_pCurrentElement = pTempCurrentElement;
788 }
789 
rebuildIDLink(const css::uno::Reference<css::xml::wrapper::XXMLElementWrapper> & node)790 void SAL_CALL XMLDocumentWrapper_XmlSecImpl::rebuildIDLink(
791     const css::uno::Reference< css::xml::wrapper::XXMLElementWrapper >& node )
792 {
793     xmlNodePtr pNode = checkElement( node );
794     rebuildIDLink(pNode);
795 }
796 
797 
798 /* cssxs::XDocumentHandler */
startDocument()799 void SAL_CALL XMLDocumentWrapper_XmlSecImpl::startDocument(  )
800 {
801 }
802 
endDocument()803 void SAL_CALL XMLDocumentWrapper_XmlSecImpl::endDocument(  )
804 {
805 }
806 
startElement(const OUString & aName,const uno::Reference<cssxs::XAttributeList> & xAttribs)807 void SAL_CALL XMLDocumentWrapper_XmlSecImpl::startElement( const OUString& aName, const uno::Reference< cssxs::XAttributeList >& xAttribs )
808 {
809     sal_Int32 nLength = xAttribs->getLength();
810     uno::Sequence< cssxcsax::XMLAttribute > aAttributes (nLength);
811 
812     for (int i = 0; i < nLength; ++i)
813     {
814         aAttributes[i].sName = xAttribs->getNameByIndex(static_cast<short>(i));
815         aAttributes[i].sValue =xAttribs->getValueByIndex(static_cast<short>(i));
816     }
817 
818     compressedStartElement(aName, aAttributes);
819 }
820 
endElement(const OUString & aName)821 void SAL_CALL XMLDocumentWrapper_XmlSecImpl::endElement( const OUString& aName )
822 {
823     saxHelper.endElement(aName);
824     m_pCurrentElement = saxHelper.getCurrentNode();
825 }
826 
characters(const OUString & aChars)827 void SAL_CALL XMLDocumentWrapper_XmlSecImpl::characters( const OUString& aChars )
828 {
829     saxHelper.characters(aChars);
830 }
831 
ignorableWhitespace(const OUString & aWhitespaces)832 void SAL_CALL XMLDocumentWrapper_XmlSecImpl::ignorableWhitespace( const OUString& aWhitespaces )
833 {
834     saxHelper.ignorableWhitespace(aWhitespaces);
835 }
836 
processingInstruction(const OUString & aTarget,const OUString & aData)837 void SAL_CALL XMLDocumentWrapper_XmlSecImpl::processingInstruction( const OUString& aTarget, const OUString& aData )
838 {
839     saxHelper.processingInstruction(aTarget, aData);
840 }
841 
setDocumentLocator(const uno::Reference<cssxs::XLocator> &)842 void SAL_CALL XMLDocumentWrapper_XmlSecImpl::setDocumentLocator( const uno::Reference< cssxs::XLocator >& )
843 {
844 }
845 
846 /* XCompressedDocumentHandler */
compressedStartDocument()847 void SAL_CALL XMLDocumentWrapper_XmlSecImpl::compressedStartDocument(  )
848 {
849 }
850 
compressedEndDocument()851 void SAL_CALL XMLDocumentWrapper_XmlSecImpl::compressedEndDocument(  )
852 {
853 }
854 
compressedStartElement(const OUString & aName,const uno::Sequence<cssxcsax::XMLAttribute> & aAttributes)855 void SAL_CALL XMLDocumentWrapper_XmlSecImpl::compressedStartElement( const OUString& aName, const uno::Sequence< cssxcsax::XMLAttribute >& aAttributes )
856 {
857     saxHelper.startElement(aName, aAttributes);
858     m_pCurrentElement = saxHelper.getCurrentNode();
859 
860     buildIDAttr( m_pCurrentElement );
861 }
862 
compressedEndElement(const OUString & aName)863 void SAL_CALL XMLDocumentWrapper_XmlSecImpl::compressedEndElement( const OUString& aName )
864 {
865     endElement( aName );
866 }
867 
compressedCharacters(const OUString & aChars)868 void SAL_CALL XMLDocumentWrapper_XmlSecImpl::compressedCharacters( const OUString& aChars )
869 {
870     characters( aChars );
871 }
872 
compressedIgnorableWhitespace(const OUString & aWhitespaces)873 void SAL_CALL XMLDocumentWrapper_XmlSecImpl::compressedIgnorableWhitespace( const OUString& aWhitespaces )
874 {
875     ignorableWhitespace( aWhitespaces );
876 }
877 
compressedProcessingInstruction(const OUString & aTarget,const OUString & aData)878 void SAL_CALL XMLDocumentWrapper_XmlSecImpl::compressedProcessingInstruction( const OUString& aTarget, const OUString& aData )
879 {
880     processingInstruction( aTarget, aData );
881 }
882 
compressedSetDocumentLocator(sal_Int32,sal_Int32,const OUString &,const OUString &)883 void SAL_CALL XMLDocumentWrapper_XmlSecImpl::compressedSetDocumentLocator( sal_Int32 /*columnNumber*/, sal_Int32 /*lineNumber*/, const OUString& /*publicId*/, const OUString& /*systemId*/ )
884 {
885 }
886 
887 /* XServiceInfo */
getImplementationName()888 OUString SAL_CALL XMLDocumentWrapper_XmlSecImpl::getImplementationName(  )
889 {
890     return "com.sun.star.xml.wrapper.XMLDocumentWrapper";
891 }
892 
supportsService(const OUString & rServiceName)893 sal_Bool SAL_CALL XMLDocumentWrapper_XmlSecImpl::supportsService( const OUString& rServiceName )
894 {
895     return cppu::supportsService( this, rServiceName );
896 }
897 
getSupportedServiceNames()898 uno::Sequence< OUString > SAL_CALL XMLDocumentWrapper_XmlSecImpl::getSupportedServiceNames(  )
899 {
900     uno::Sequence<OUString> aRet{ "com.sun.star.xml.wrapper.XMLDocumentWrapper" };
901     return aRet;
902 }
903 
904 extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
com_sun_star_xml_wrapper_XMLDocumentWrapper_get_implementation(uno::XComponentContext *,uno::Sequence<uno::Any> const &)905 com_sun_star_xml_wrapper_XMLDocumentWrapper_get_implementation(
906     uno::XComponentContext* /*pCtx*/, uno::Sequence<uno::Any> const& /*rSeq*/)
907 {
908     return cppu::acquire(new XMLDocumentWrapper_XmlSecImpl());
909 }
910 
911 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
912