use insert function instead of for loop
[LibreOffice.git] / xmlsecurity / source / framework / saxeventkeeperimpl.cxx
blob8a0da7185dccfce874ccbe47b7e2d3ee8de7c206
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <framework/saxeventkeeperimpl.hxx>
22 #include "buffernode.hxx"
23 #include "elementmark.hxx"
24 #include "elementcollector.hxx"
25 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
26 #include <com/sun/star/xml/crypto/sax/ConstOfSecurityId.hpp>
27 #include <com/sun/star/xml/wrapper/XXMLDocumentWrapper.hpp>
28 #include <com/sun/star/xml/csax/XCompressedDocumentHandler.hpp>
29 #include <cppuhelper/supportsservice.hxx>
30 #include <osl/diagnose.h>
31 #include <rtl/ustrbuf.hxx>
33 #include <algorithm>
35 SAXEventKeeperImpl::SAXEventKeeperImpl( )
36 :m_pCurrentBufferNode(nullptr),
37 m_nNextElementMarkId(1),
38 m_pNewBlocker(nullptr),
39 m_pCurrentBlockingBufferNode(nullptr),
40 m_bIsReleasing(false),
41 m_bIsForwarding(false)
43 m_vElementMarkBuffers.reserve(2);
44 m_vNewElementCollectors.reserve(2);
45 m_vReleasedElementMarkBuffers.reserve(2);
48 SAXEventKeeperImpl::~SAXEventKeeperImpl()
51 * delete the BufferNode tree
53 m_pRootBufferNode.reset();
55 m_pCurrentBufferNode = m_pCurrentBlockingBufferNode = nullptr;
58 * delete all unfreed ElementMarks
60 m_vNewElementCollectors.clear();
61 m_pNewBlocker = nullptr;
64 void SAXEventKeeperImpl::setCurrentBufferNode(BufferNode* pBufferNode)
65 /****** SAXEventKeeperImpl/setCurrentBufferNode ******************************
67 * NAME
68 * setCurrentBufferNode -- set a new active BufferNode.
70 * SYNOPSIS
71 * setCurrentBufferNode( pBufferNode );
73 * FUNCTION
74 * connects this BufferNode into the BufferNode tree as a child of the
75 * current active BufferNode. Then makes this BufferNode as the current
76 * active BufferNode.
77 * If the previous active BufferNode points to the root
78 * BufferNode, which means that no buffering operation was proceeding,
79 * then notifies the status change listener that buffering operation
80 * will begin at once.
82 * INPUTS
83 * pBufferNode - a BufferNode which will be the new active BufferNode
84 ******************************************************************************/
86 if (pBufferNode == m_pCurrentBufferNode)
87 return;
89 if ( m_pCurrentBufferNode == m_pRootBufferNode.get() &&
90 m_xSAXEventKeeperStatusChangeListener.is())
92 m_xSAXEventKeeperStatusChangeListener->collectionStatusChanged(true);
95 if (pBufferNode->getParent() == nullptr)
97 m_pCurrentBufferNode->addChild(std::unique_ptr<BufferNode>(pBufferNode));
98 pBufferNode->setParent(m_pCurrentBufferNode);
101 m_pCurrentBufferNode = pBufferNode;
104 BufferNode* SAXEventKeeperImpl::addNewElementMarkBuffers()
105 /****** SAXEventKeeperImpl/addNewElementMarkBuffers **************************
107 * NAME
108 * addNewElementMarkBuffers -- add new ElementCollectors and new Blocker.
110 * SYNOPSIS
111 * pBufferNode = addNewElementMarkBuffers( );
113 * FUNCTION
114 * if there are new ElementCollector or new Blocker to be added, then
115 * connect all of them with the current BufferNode. In case of the
116 * current BufferNode doesn't exist, creates one.
117 * Clears up the new ElementCollector list and the new Blocker pointer.
119 * RESULT
120 * pBufferNode - the BufferNode that has been connected with both new
121 * ElementCollectors and new Blocker.
122 ******************************************************************************/
124 BufferNode* pBufferNode = nullptr;
126 if (m_pNewBlocker || !m_vNewElementCollectors.empty() )
129 * When the current BufferNode is right pointing to the current
130 * working element in the XMLDocumentWrapper component, then
131 * no new BufferNode is needed to create.
132 * This situation can only happen in the "Forwarding" mode.
134 if ( (m_pCurrentBufferNode != nullptr) &&
135 (m_xXMLDocument->isCurrent(m_pCurrentBufferNode->getXMLElement())))
137 pBufferNode = m_pCurrentBufferNode;
139 else
141 pBufferNode = new BufferNode(m_xXMLDocument->getCurrentElement());
144 if (m_pNewBlocker != nullptr)
146 pBufferNode->setBlocker(m_pNewBlocker);
149 * If no blocking before, then notify the status change listener that
150 * the SAXEventKeeper has entered "blocking" status, during which, no
151 * SAX events will be forwarded to the next document handler.
153 if (m_pCurrentBlockingBufferNode == nullptr)
155 m_pCurrentBlockingBufferNode = pBufferNode;
157 if (m_xSAXEventKeeperStatusChangeListener.is())
159 m_xSAXEventKeeperStatusChangeListener->blockingStatusChanged(true);
163 m_pNewBlocker = nullptr;
166 for( const auto& i : m_vNewElementCollectors )
168 pBufferNode->addElementCollector(i);
170 m_vNewElementCollectors.clear();
173 return pBufferNode;
176 ElementMark* SAXEventKeeperImpl::findElementMarkBuffer(sal_Int32 nId) const
177 /****** SAXEventKeeperImpl/findElementMarkBuffer *****************************
179 * NAME
180 * findElementMarkBuffer -- finds an ElementMark.
182 * SYNOPSIS
183 * pElementMark = findElementMarkBuffer( nId );
185 * FUNCTION
186 * searches an ElementMark with the particular Id in the ElementMark
187 * list.
189 * INPUTS
190 * nId - the Id of the ElementMark to be searched.
192 * RESULT
193 * pElementMark - the ElementMark with the particular Id, or NULL when
194 * no such Id exists.
195 ******************************************************************************/
197 ElementMark* pElementMark = nullptr;
199 for( auto&& ii : m_vElementMarkBuffers )
201 if ( nId == ii->getBufferId())
203 pElementMark = const_cast<ElementMark*>(ii.get());
204 break;
208 return pElementMark;
211 void SAXEventKeeperImpl::removeElementMarkBuffer(sal_Int32 nId)
212 /****** SAXEventKeeperImpl/removeElementMarkBuffer ***************************
214 * NAME
215 * removeElementMarkBuffer -- removes an ElementMark
217 * SYNOPSIS
218 * removeElementMarkBuffer( nId );
220 * FUNCTION
221 * removes an ElementMark with the particular Id in the ElementMark list.
223 * INPUTS
224 * nId - the Id of the ElementMark to be removed.
225 ******************************************************************************/
227 auto ii = std::find_if(m_vElementMarkBuffers.begin(), m_vElementMarkBuffers.end(),
228 [nId](std::unique_ptr<const ElementMark>& rElementMark) { return nId == rElementMark->getBufferId(); }
230 if (ii == m_vElementMarkBuffers.end())
231 return;
234 * checks whether this ElementMark still in the new ElementCollect array
236 auto jj = std::find_if(m_vNewElementCollectors.begin(), m_vNewElementCollectors.end(),
237 [&ii](const ElementCollector* pElementCollector) { return ii->get() == pElementCollector; }
239 if (jj != m_vNewElementCollectors.end())
240 m_vNewElementCollectors.erase(jj);
243 * checks whether this ElementMark is the new Blocker
245 if (ii->get() == m_pNewBlocker)
247 m_pNewBlocker = nullptr;
250 m_vElementMarkBuffers.erase( ii );
253 OUString SAXEventKeeperImpl::printBufferNode(
254 BufferNode const * pBufferNode, sal_Int32 nIndent) const
255 /****** SAXEventKeeperImpl/printBufferNode ***********************************
257 * NAME
258 * printBufferNode -- retrieves the information of a BufferNode and its
259 * branch.
261 * SYNOPSIS
262 * info = printBufferNode( pBufferNode, nIndent );
264 * FUNCTION
265 * all retrieved information includes:
266 * 1. whether it is the current BufferNode;
267 * 2. whether it is the current blocking BufferNode;
268 * 3. the name of the parent element;
269 * 4. the name of this element;
270 * 5. all ElementCollectors working on this BufferNode;
271 * 6. the Blocker working on this BufferNode;
272 * 7. all child BufferNodes' information.
274 * INPUTS
275 * pBufferNode - the BufferNode from where information will be retrieved.
276 * nIndent - how many space characters prefixed before the output
277 * message.
279 * RESULT
280 * info - the information string
281 ******************************************************************************/
283 OUStringBuffer rc;
285 for ( int i=0; i<nIndent; ++i )
287 rc.append(" ");
290 if (pBufferNode == m_pCurrentBufferNode)
292 rc.append("[%]");
295 if (pBufferNode == m_pCurrentBlockingBufferNode)
297 rc.append("[B]");
300 rc.append(" " + m_xXMLDocument->getNodeName(pBufferNode->getXMLElement()));
302 BufferNode* pParent = const_cast<BufferNode*>(pBufferNode->getParent());
303 if (pParent != nullptr)
305 rc.append("[" + m_xXMLDocument->getNodeName(pParent->getXMLElement()) + "]");
308 rc.append(":EC=" + pBufferNode->printChildren() + " BR=");
310 ElementMark * pBlocker = pBufferNode->getBlocker();
311 if (pBlocker != nullptr)
313 rc.append( OUString::number(pBlocker->getBufferId()) +
314 "(SecId=" + OUString::number( pBlocker->getSecurityId() ) + ") ");
316 rc.append("\n");
318 std::vector< std::unique_ptr<BufferNode> > const & vChildren = pBufferNode->getChildren();
319 for( const auto& jj : vChildren )
321 rc.append(printBufferNode(jj.get(), nIndent+4));
324 return rc.makeStringAndClear();
327 css::uno::Sequence< css::uno::Reference< css::xml::wrapper::XXMLElementWrapper > >
328 SAXEventKeeperImpl::collectChildWorkingElement(BufferNode const * pBufferNode)
329 /****** SAXEventKeeperImpl/collectChildWorkingElement ************************
331 * NAME
332 * collectChildWorkingElement -- collects a BufferNode's all child
333 * Elements.
335 * SYNOPSIS
336 * list = collectChildWorkingElement( pBufferNode );
338 * INPUTS
339 * pBufferNode - the BufferNode whose child Elements will be collected.
341 * RESULT
342 * list - the child Elements list.
343 ******************************************************************************/
345 std::vector< std::unique_ptr<BufferNode> > const & vChildren = pBufferNode->getChildren();
347 css::uno::Sequence < css::uno::Reference<
348 css::xml::wrapper::XXMLElementWrapper > > aChildrenCollection ( vChildren.size());
350 std::transform(vChildren.begin(), vChildren.end(), aChildrenCollection.getArray(),
351 [](const auto& i) { return i->getXMLElement(); });
353 return aChildrenCollection;
356 void SAXEventKeeperImpl::smashBufferNode(
357 BufferNode* pBufferNode, bool bClearRoot) const
358 /****** SAXEventKeeperImpl/smashBufferNode ***********************************
360 * NAME
361 * smashBufferNode -- removes a BufferNode along with its working
362 * element.
364 * SYNOPSIS
365 * smashBufferNode( pBufferNode, bClearRoot );
367 * FUNCTION
368 * removes the BufferNode's working element from the DOM document, while
369 * reserves all ancestor paths for its child BufferNodes.
370 * when any of the BufferNode's ancestor element is useless, removes it
371 * too.
372 * removes the BufferNode from the BufferNode tree.
374 * INPUTS
375 * pBufferNode - the BufferNode to be removed
376 * bClearRoot - whether the root element also needs to be cleared up.
378 * NOTES
379 * when removing a Blocker's BufferNode, the bClearRoot flag should be
380 * true. Because a Blocker can buffer many SAX events which are not used
381 * by any other ElementCollector or Blocker.
382 * When the bClearRoot is set to true, the root BufferNode will be first
383 * cleared, with a stop flag setting at the next Blocking BufferNode. This
384 * operation can delete all useless buffered SAX events which are only
385 * needed by the Blocker to be deleted.
386 ******************************************************************************/
388 if (pBufferNode->hasAnything())
389 return;
391 BufferNode* pParent = const_cast<BufferNode*>(pBufferNode->getParent());
394 * delete the XML data
396 if (pParent == m_pRootBufferNode.get())
398 bool bIsNotBlocking = (m_pCurrentBlockingBufferNode == nullptr);
399 bool bIsBlockInside = false;
400 bool bIsBlockingAfterward = false;
403 * If this is a blocker, then remove any out-element data
404 * which caused by blocking. The removal process will stop
405 * at the next blocker to avoid removing any useful data.
407 if (bClearRoot)
409 css::uno::Sequence< css::uno::Reference< css::xml::wrapper::XXMLElementWrapper > >
410 aChildElements = collectChildWorkingElement(m_pRootBufferNode.get());
413 * the clearUselessData only clearup the content in the
414 * node, not the node itself.
416 m_xXMLDocument->clearUselessData(m_pRootBufferNode->getXMLElement(),
417 aChildElements,
418 bIsNotBlocking?nullptr:
419 (m_pCurrentBlockingBufferNode->getXMLElement()));
422 * remove the node if it is empty, then if its parent is also
423 * empty, remove it, then if the next parent is also empty,
424 * remove it,..., until parent become null.
426 m_xXMLDocument->collapse( m_pRootBufferNode->getXMLElement() );
430 * if blocking, check the relationship between this BufferNode and
431 * the current blocking BufferNode.
433 if ( !bIsNotBlocking )
436 * the current blocking BufferNode is a descendant of this BufferNode.
438 bIsBlockInside = (nullptr != pBufferNode->isAncestor(m_pCurrentBlockingBufferNode));
441 * the current blocking BufferNode locates behind this BufferNode in tree
442 * order.
444 bIsBlockingAfterward = pBufferNode->isPrevious(m_pCurrentBlockingBufferNode);
448 * this BufferNode's working element needs to be deleted only when
449 * 1. there is no blocking, or
450 * 2. the current blocking BufferNode is a descendant of this BufferNode,
451 * (then in the BufferNode's working element, the useless data before the blocking
452 * element should be deleted.) or
453 * 3. the current blocking BufferNode is locates behind this BufferNode in tree,
454 * (then the useless data between the blocking element and the working element
455 * should be deleted.).
456 * Otherwise, this working element should not be deleted.
458 if ( bIsNotBlocking || bIsBlockInside || bIsBlockingAfterward )
460 css::uno::Sequence< css::uno::Reference< css::xml::wrapper::XXMLElementWrapper > >
461 aChildElements = collectChildWorkingElement(pBufferNode);
464 * the clearUselessData only clearup the content in the
465 * node, not the node itself.
467 m_xXMLDocument->clearUselessData(pBufferNode->getXMLElement(),
468 aChildElements,
469 bIsBlockInside?(m_pCurrentBlockingBufferNode->getXMLElement()):
470 nullptr);
473 * remove the node if it is empty, then if its parent is also
474 * empty, remove it, then if the next parent is also empty,
475 * remove it,..., until parent become null.
477 m_xXMLDocument->collapse( pBufferNode->getXMLElement() );
481 sal_Int32 nIndex = pParent->indexOfChild(pBufferNode);
483 std::vector< std::unique_ptr<BufferNode> > vChildren = pBufferNode->releaseChildren();
484 pParent->removeChild(pBufferNode); // delete buffernode
486 for( auto& i : vChildren )
488 i->setParent(pParent);
489 pParent->addChild(std::move(i), nIndex);
490 nIndex++;
494 BufferNode* SAXEventKeeperImpl::findNextBlockingBufferNode(
495 BufferNode* pStartBufferNode)
496 /****** SAXEventKeeperImpl/findNextBlockingBufferNode ************************
498 * NAME
499 * findNextBlockingBufferNode -- finds the next blocking BufferNode
500 * behind the particular BufferNode.
502 * SYNOPSIS
503 * pBufferNode = findNextBlockingBufferNode( pStartBufferNode );
505 * INPUTS
506 * pStartBufferNode - the BufferNode from where to search the next
507 * blocking BufferNode.
509 * RESULT
510 * pBufferNode - the next blocking BufferNode, or NULL if no such
511 * BufferNode exists.
512 ******************************************************************************/
514 BufferNode* pNext = nullptr;
516 if (pStartBufferNode != nullptr)
518 pNext = pStartBufferNode;
520 while (nullptr != (pNext = const_cast<BufferNode*>(pNext->getNextNodeByTreeOrder())))
522 if (pNext->getBlocker() != nullptr)
524 break;
529 return pNext;
532 void SAXEventKeeperImpl::diffuse(BufferNode* pBufferNode)
533 /****** SAXEventKeeperImpl/diffuse *******************************************
535 * NAME
536 * diffuse -- diffuse the notification.
538 * SYNOPSIS
539 * diffuse( pBufferNode );
541 * FUNCTION
542 * diffuse the collecting completion notification from the specific
543 * BufferNode along its parent link, until an ancestor which is not
544 * completely received is met.
546 * INPUTS
547 * pBufferNode - the BufferNode from which the notification will be
548 * diffused.
549 ******************************************************************************/
551 BufferNode* pParent = pBufferNode;
553 while(pParent->isAllReceived())
555 pParent->elementCollectorNotify();
556 pParent = const_cast<BufferNode*>(pParent->getParent());
560 void SAXEventKeeperImpl::releaseElementMarkBuffer()
561 /****** SAXEventKeeperImpl/releaseElementMarkBuffer **************************
563 * NAME
564 * releaseElementMarkBuffer -- releases useless ElementMarks
566 * SYNOPSIS
567 * releaseElementMarkBuffer( );
569 * FUNCTION
570 * releases each ElementMark in the releasing list
571 * m_vReleasedElementMarkBuffers.
572 * The operation differs between an ElementCollector and a Blocker.
573 ******************************************************************************/
575 m_bIsReleasing = true;
576 while (!m_vReleasedElementMarkBuffers.empty())
578 auto pId = m_vReleasedElementMarkBuffers.begin();
579 sal_Int32 nId = *pId;
580 m_vReleasedElementMarkBuffers.erase( pId );
582 ElementMark* pElementMark = findElementMarkBuffer(nId);
584 if (pElementMark != nullptr)
586 if (css::xml::crypto::sax::ElementMarkType_ELEMENTCOLLECTOR
587 == pElementMark->getType())
589 * it is a EC
592 ElementCollector* pElementCollector = static_cast<ElementCollector*>(pElementMark);
594 css::xml::crypto::sax::ElementMarkPriority nPriority = pElementCollector->getPriority();
596 * Delete the EC from the buffer node.
598 BufferNode* pBufferNode = pElementCollector->getBufferNode();
599 pBufferNode->removeElementCollector(pElementCollector);
601 if ( nPriority == css::xml::crypto::sax::ElementMarkPriority_BEFOREMODIFY)
603 pBufferNode->notifyBranch();
607 * delete the ElementMark
609 pElementCollector = nullptr;
610 pElementMark = nullptr;
611 removeElementMarkBuffer(nId);
614 * delete the BufferNode
616 diffuse(pBufferNode);
617 smashBufferNode(pBufferNode, false);
619 else
621 * it is a Blocker
625 * Delete the TH from the buffer node.
627 BufferNode *pBufferNode = pElementMark->getBufferNode();
628 assert(pBufferNode);
629 pBufferNode->setBlocker(nullptr);
632 * If there is a following handler and no blocking now, then
633 * forward this event
635 if (m_pCurrentBlockingBufferNode == pBufferNode)
638 * Before forwarding, the next blocking point needs to be
639 * found.
641 m_pCurrentBlockingBufferNode = findNextBlockingBufferNode(pBufferNode);
644 * Forward the blocked events between these two STHs.
646 if (m_xNextHandler.is())
648 BufferNode* pTempCurrentBufferNode = m_pCurrentBufferNode;
649 BufferNode* pTempCurrentBlockingBufferNode = m_pCurrentBlockingBufferNode;
651 m_pCurrentBufferNode = pBufferNode;
652 assert(pBufferNode);
653 m_pCurrentBlockingBufferNode = nullptr;
655 m_bIsForwarding = true;
657 m_xXMLDocument->generateSAXEvents(
658 m_xNextHandler,
659 this,
660 pBufferNode->getXMLElement(),
661 (pTempCurrentBlockingBufferNode == nullptr)?nullptr:(pTempCurrentBlockingBufferNode->getXMLElement()));
663 m_bIsForwarding = false;
665 m_pCurrentBufferNode = pTempCurrentBufferNode;
666 if (m_pCurrentBlockingBufferNode == nullptr)
668 m_pCurrentBlockingBufferNode = pTempCurrentBlockingBufferNode;
672 if (m_pCurrentBlockingBufferNode == nullptr &&
673 m_xSAXEventKeeperStatusChangeListener.is())
675 m_xSAXEventKeeperStatusChangeListener->blockingStatusChanged(false);
680 * delete the ElementMark
682 pElementMark = nullptr;
683 removeElementMarkBuffer(nId);
686 * delete the BufferNode
688 diffuse(pBufferNode);
689 smashBufferNode(pBufferNode, true);
694 m_bIsReleasing = false;
696 if (!m_pRootBufferNode->hasAnything() &&
697 !m_pRootBufferNode->hasChildren() &&
698 m_xSAXEventKeeperStatusChangeListener.is())
700 m_xSAXEventKeeperStatusChangeListener->bufferStatusChanged(true);
704 void SAXEventKeeperImpl::markElementMarkBuffer(sal_Int32 nId)
705 /****** SAXEventKeeperImpl/markElementMarkBuffer *****************************
707 * NAME
708 * markElementMarkBuffer -- marks an ElementMark to be released
710 * SYNOPSIS
711 * markElementMarkBuffer( nId );
713 * FUNCTION
714 * puts the ElementMark with the particular Id into the releasing list,
715 * checks whether the releasing process is running, if not then launch
716 * this process.
718 * INPUTS
719 * nId - the Id of the ElementMark which will be released
720 ******************************************************************************/
722 m_vReleasedElementMarkBuffers.push_back( nId );
723 if ( !m_bIsReleasing )
725 releaseElementMarkBuffer();
729 sal_Int32 SAXEventKeeperImpl::createElementCollector(
730 css::xml::crypto::sax::ElementMarkPriority nPriority,
731 bool bModifyElement,
732 const css::uno::Reference< css::xml::crypto::sax::XReferenceResolvedListener >& xReferenceResolvedListener)
733 /****** SAXEventKeeperImpl/createElementCollector ****************************
735 * NAME
736 * createElementCollector -- creates a new ElementCollector on the
737 * incoming element.
739 * SYNOPSIS
740 * nId = createElementCollector( nSecurityId, nPriority,
741 * bModifyElement,
742 * xReferenceResolvedListener );
744 * FUNCTION
745 * allocs a new Id, then create an ElementCollector with this Id value.
746 * Add the new created ElementCollector to the new ElementCollecotor list.
748 * INPUTS
749 * nPriority - the priority of the new ElementCollector
750 * bModifyElement -whether this BufferNode will modify the content of
751 * the corresponding element it works on
752 * xReferenceResolvedListener - the listener for the new ElementCollector.
754 * RESULT
755 * nId - the Id of the new ElementCollector
756 ******************************************************************************/
758 sal_Int32 nId = m_nNextElementMarkId;
759 m_nNextElementMarkId ++;
761 ElementCollector* pElementCollector
762 = new ElementCollector(
763 nId,
764 nPriority,
765 bModifyElement,
766 xReferenceResolvedListener);
768 m_vElementMarkBuffers.push_back(
769 std::unique_ptr<const ElementMark>(pElementCollector));
772 * All the new EC to initial EC array.
774 m_vNewElementCollectors.push_back( pElementCollector );
776 return nId;
780 sal_Int32 SAXEventKeeperImpl::createBlocker()
781 /****** SAXEventKeeperImpl/createBlocker *************************************
783 * NAME
784 * createBlocker -- creates a new Blocker on the incoming element.
786 * SYNOPSIS
787 * nId = createBlocker( nSecurityId );
789 * RESULT
790 * nId - the Id of the new Blocker
791 ******************************************************************************/
793 sal_Int32 nId = m_nNextElementMarkId;
794 m_nNextElementMarkId ++;
796 OSL_ASSERT(m_pNewBlocker == nullptr);
798 m_pNewBlocker = new ElementMark(css::xml::crypto::sax::ConstOfSecurityId::UNDEFINEDSECURITYID, nId);
799 m_vElementMarkBuffers.push_back(
800 std::unique_ptr<const ElementMark>(m_pNewBlocker));
802 return nId;
805 /* XSAXEventKeeper */
806 sal_Int32 SAL_CALL SAXEventKeeperImpl::addElementCollector( )
808 return createElementCollector(
809 css::xml::crypto::sax::ElementMarkPriority_AFTERMODIFY,
810 false,
811 nullptr);
814 void SAL_CALL SAXEventKeeperImpl::removeElementCollector( sal_Int32 id )
816 markElementMarkBuffer(id);
819 sal_Int32 SAL_CALL SAXEventKeeperImpl::addBlocker( )
821 return createBlocker();
824 void SAL_CALL SAXEventKeeperImpl::removeBlocker( sal_Int32 id )
826 markElementMarkBuffer(id);
829 sal_Bool SAL_CALL SAXEventKeeperImpl::isBlocking( )
831 return (m_pCurrentBlockingBufferNode != nullptr);
834 css::uno::Reference< css::xml::wrapper::XXMLElementWrapper > SAL_CALL
835 SAXEventKeeperImpl::getElement( sal_Int32 id )
837 css::uno::Reference< css::xml::wrapper::XXMLElementWrapper > rc;
839 ElementMark* pElementMark = findElementMarkBuffer(id);
840 if (pElementMark != nullptr)
842 rc = pElementMark->getBufferNode()->getXMLElement();
845 return rc;
848 void SAL_CALL SAXEventKeeperImpl::setElement(
849 sal_Int32 id,
850 const css::uno::Reference< css::xml::wrapper::XXMLElementWrapper >& aElement )
852 if (aElement.is())
854 m_xXMLDocument->rebuildIDLink(aElement);
856 ElementMark* pElementMark = findElementMarkBuffer(id);
858 if (pElementMark != nullptr)
860 BufferNode* pBufferNode = pElementMark->getBufferNode();
861 if (pBufferNode != nullptr)
863 const bool bIsCurrent = m_xXMLDocument->isCurrent(pBufferNode->getXMLElement());
864 pBufferNode->setXMLElement(aElement);
866 if (bIsCurrent)
868 m_xXMLDocument->setCurrentElement(aElement);
873 else
875 removeElementCollector( id );
879 css::uno::Reference< css::xml::sax::XDocumentHandler > SAL_CALL SAXEventKeeperImpl::setNextHandler(
880 const css::uno::Reference< css::xml::sax::XDocumentHandler >& xNewHandler )
882 css::uno::Reference< css::xml::sax::XDocumentHandler > xOldHandler = m_xNextHandler;
884 m_xNextHandler = xNewHandler;
885 return xOldHandler;
888 OUString SAL_CALL SAXEventKeeperImpl::printBufferNodeTree()
890 OUString rc = "ElementMarkBuffers: size = "
891 + OUString::number(m_vElementMarkBuffers.size())
892 + "\nCurrentBufferNode: "
893 + m_xXMLDocument->getNodeName(m_pCurrentBufferNode->getXMLElement())
894 + "\n" + printBufferNode(m_pRootBufferNode.get(), 0);
896 return rc;
899 css::uno::Reference< css::xml::wrapper::XXMLElementWrapper > SAL_CALL SAXEventKeeperImpl::getCurrentBlockingNode()
901 css::uno::Reference< css::xml::wrapper::XXMLElementWrapper > rc;
903 if (m_pCurrentBlockingBufferNode != nullptr)
905 rc = m_pCurrentBlockingBufferNode->getXMLElement();
908 return rc;
911 /* XSecuritySAXEventKeeper */
912 sal_Int32 SAL_CALL SAXEventKeeperImpl::addSecurityElementCollector(
913 css::xml::crypto::sax::ElementMarkPriority priority,
914 sal_Bool modifyElement )
916 return createElementCollector(
917 priority,
918 modifyElement,
919 nullptr);
922 void SAL_CALL SAXEventKeeperImpl::setSecurityId( sal_Int32 id, sal_Int32 securityId )
924 ElementMark* pElementMark = findElementMarkBuffer(id);
925 if (pElementMark != nullptr)
927 pElementMark->setSecurityId(securityId);
932 /* XReferenceResolvedBroadcaster */
933 void SAL_CALL SAXEventKeeperImpl::addReferenceResolvedListener(
934 sal_Int32 referenceId,
935 const css::uno::Reference< css::xml::crypto::sax::XReferenceResolvedListener >& listener )
937 ElementCollector* pElementCollector = static_cast<ElementCollector*>(findElementMarkBuffer(referenceId));
938 if (pElementCollector != nullptr)
940 pElementCollector->setReferenceResolvedListener(listener);
944 void SAL_CALL SAXEventKeeperImpl::removeReferenceResolvedListener(
945 sal_Int32 /*referenceId*/,
946 const css::uno::Reference< css::xml::crypto::sax::XReferenceResolvedListener >&)
950 /* XSAXEventKeeperStatusChangeBroadcaster */
951 void SAL_CALL SAXEventKeeperImpl::addSAXEventKeeperStatusChangeListener(
952 const css::uno::Reference< css::xml::crypto::sax::XSAXEventKeeperStatusChangeListener >& listener )
954 m_xSAXEventKeeperStatusChangeListener = listener;
957 void SAL_CALL SAXEventKeeperImpl::removeSAXEventKeeperStatusChangeListener(
958 const css::uno::Reference< css::xml::crypto::sax::XSAXEventKeeperStatusChangeListener >&)
962 /* XDocumentHandler */
963 void SAL_CALL SAXEventKeeperImpl::startDocument( )
965 if ( m_xNextHandler.is())
967 m_xNextHandler->startDocument();
971 void SAL_CALL SAXEventKeeperImpl::endDocument( )
973 if ( m_xNextHandler.is())
975 m_xNextHandler->endDocument();
979 void SAL_CALL SAXEventKeeperImpl::startElement(
980 const OUString& aName,
981 const css::uno::Reference< css::xml::sax::XAttributeList >& xAttribs )
984 * If there is a following handler and no blocking now, then
985 * forward this event
987 if ((m_pCurrentBlockingBufferNode == nullptr) &&
988 (m_xNextHandler.is()) &&
989 (!m_bIsForwarding) &&
990 (m_pNewBlocker == nullptr))
992 m_xNextHandler->startElement(aName, xAttribs);
995 * If not forwarding, buffer this startElement.
997 if (!m_bIsForwarding)
999 sal_Int32 nLength = xAttribs->getLength();
1000 css::uno::Sequence< css::xml::csax::XMLAttribute > aAttributes (nLength);
1001 auto aAttributesRange = asNonConstRange(aAttributes);
1003 for ( int i = 0; i<nLength; ++i )
1005 aAttributesRange[i].sName = xAttribs->getNameByIndex(static_cast<short>(i));
1006 aAttributesRange[i].sValue =xAttribs->getValueByIndex(static_cast<short>(i));
1009 m_xCompressedDocumentHandler->compressedStartElement(aName, aAttributes);
1012 BufferNode* pBufferNode = addNewElementMarkBuffers();
1013 if (pBufferNode != nullptr)
1015 setCurrentBufferNode(pBufferNode);
1019 void SAL_CALL SAXEventKeeperImpl::endElement( const OUString& aName )
1021 const bool bIsCurrent = m_xXMLDocument->isCurrent(m_pCurrentBufferNode->getXMLElement());
1024 * If there is a following handler and no blocking now, then
1025 * forward this event
1027 if ((m_pCurrentBlockingBufferNode == nullptr) &&
1028 (m_xNextHandler.is()) &&
1029 (!m_bIsForwarding))
1031 m_xNextHandler->endElement(aName);
1034 if ((m_pCurrentBlockingBufferNode != nullptr) ||
1035 (m_pCurrentBufferNode != m_pRootBufferNode.get()) ||
1036 (!m_xXMLDocument->isCurrentElementEmpty()))
1038 if (!m_bIsForwarding)
1040 m_xCompressedDocumentHandler->compressedEndElement(aName);
1044 * If the current buffer node has not notified yet, and
1045 * the current buffer node is waiting for the current element,
1046 * then let it notify.
1048 if (bIsCurrent && (m_pCurrentBufferNode != m_pRootBufferNode.get()))
1050 BufferNode* pOldCurrentBufferNode = m_pCurrentBufferNode;
1051 m_pCurrentBufferNode = const_cast<BufferNode*>(m_pCurrentBufferNode->getParent());
1053 pOldCurrentBufferNode->setReceivedAll();
1055 if ((m_pCurrentBufferNode == m_pRootBufferNode.get()) &&
1056 m_xSAXEventKeeperStatusChangeListener.is())
1058 m_xSAXEventKeeperStatusChangeListener->collectionStatusChanged(false);
1062 else
1064 if (!m_bIsForwarding)
1066 m_xXMLDocument->removeCurrentElement();
1071 void SAL_CALL SAXEventKeeperImpl::characters( const OUString& aChars )
1073 if (m_bIsForwarding)
1074 return;
1076 if ((m_pCurrentBlockingBufferNode == nullptr) && m_xNextHandler.is())
1078 m_xNextHandler->characters(aChars);
1081 if ((m_pCurrentBlockingBufferNode != nullptr) ||
1082 (m_pCurrentBufferNode != m_pRootBufferNode.get()))
1084 m_xCompressedDocumentHandler->compressedCharacters(aChars);
1088 void SAL_CALL SAXEventKeeperImpl::ignorableWhitespace( const OUString& aWhitespaces )
1090 characters( aWhitespaces );
1093 void SAL_CALL SAXEventKeeperImpl::processingInstruction(
1094 const OUString& aTarget, const OUString& aData )
1096 if (m_bIsForwarding)
1097 return;
1099 if ((m_pCurrentBlockingBufferNode == nullptr) && m_xNextHandler.is())
1101 m_xNextHandler->processingInstruction(aTarget, aData);
1104 if ((m_pCurrentBlockingBufferNode != nullptr) ||
1105 (m_pCurrentBufferNode != m_pRootBufferNode.get()))
1107 m_xCompressedDocumentHandler->compressedProcessingInstruction(aTarget, aData);
1111 void SAL_CALL SAXEventKeeperImpl::setDocumentLocator( const css::uno::Reference< css::xml::sax::XLocator >&)
1115 /* XInitialization */
1116 void SAL_CALL SAXEventKeeperImpl::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
1118 OSL_ASSERT(aArguments.getLength() == 1);
1120 aArguments[0] >>= m_xXMLDocument;
1121 m_xDocumentHandler.set( m_xXMLDocument, css::uno::UNO_QUERY );
1122 m_xCompressedDocumentHandler.set( m_xXMLDocument, css::uno::UNO_QUERY );
1124 m_pRootBufferNode.reset( new BufferNode(m_xXMLDocument->getCurrentElement()) );
1125 m_pCurrentBufferNode = m_pRootBufferNode.get();
1128 OUString SAXEventKeeperImpl_getImplementationName ()
1130 return u"com.sun.star.xml.security.framework.SAXEventKeeperImpl"_ustr;
1133 css::uno::Sequence< OUString > SAXEventKeeperImpl_getSupportedServiceNames( )
1135 return { u"com.sun.star.xml.crypto.sax.SAXEventKeeper"_ustr };
1138 /* XServiceInfo */
1139 OUString SAL_CALL SAXEventKeeperImpl::getImplementationName( )
1141 return SAXEventKeeperImpl_getImplementationName();
1144 sal_Bool SAL_CALL SAXEventKeeperImpl::supportsService( const OUString& rServiceName )
1146 return cppu::supportsService(this, rServiceName);
1149 css::uno::Sequence< OUString > SAL_CALL SAXEventKeeperImpl::getSupportedServiceNames( )
1151 return SAXEventKeeperImpl_getSupportedServiceNames();
1154 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */