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