Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  saxeventkeeperimpl.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */



#include <framework/saxeventkeeperimpl.hxx>
#include "buffernode.hxx"
#include "elementmark.hxx"
#include "elementcollector.hxx"
#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
#include <com/sun/star/xml/crypto/sax/ConstOfSecurityId.hpp>
#include <com/sun/star/xml/wrapper/XXMLDocumentWrapper.hpp>
#include <com/sun/star/xml/csax/XCompressedDocumentHandler.hpp>
#include <cppuhelper/supportsservice.hxx>
#include <osl/diagnose.h>
#include <rtl/ustrbuf.hxx>

#include <algorithm>

SAXEventKeeperImpl::SAXEventKeeperImpl( )
    :m_pCurrentBufferNode(nullptr),
     m_nNextElementMarkId(1),
     m_pNewBlocker(nullptr),
     m_pCurrentBlockingBufferNode(nullptr),
     m_bIsReleasing(false),
     m_bIsForwarding(false)
{
    m_vElementMarkBuffers.reserve(2);
    m_vNewElementCollectors.reserve(2);
    m_vReleasedElementMarkBuffers.reserve(2);
}

SAXEventKeeperImpl::~SAXEventKeeperImpl()
{
    /*
     * delete the BufferNode tree
     */

    m_pRootBufferNode.reset();

    m_pCurrentBufferNode = m_pCurrentBlockingBufferNode = nullptr;

    /*
     * delete all unfreed ElementMarks
     */

    m_vNewElementCollectors.clear();
    m_pNewBlocker = nullptr;
}

void SAXEventKeeperImpl::setCurrentBufferNode(BufferNode* pBufferNode)
/****** SAXEventKeeperImpl/setCurrentBufferNode ******************************
 *
 *   NAME
 *  setCurrentBufferNode -- set a new active BufferNode.
 *
 *   SYNOPSIS
 *  setCurrentBufferNode( pBufferNode );
 *
 *   FUNCTION
 *  connects this BufferNode into the BufferNode tree as a child of the
 *  current active BufferNode. Then makes this BufferNode as the current
 *  active BufferNode.
 *  If the previous active BufferNode points to the root
 *  BufferNode, which means that no buffering operation was proceeding,
 *  then notifies the status change listener that buffering  operation
 *  will begin at once.
 *
 *   INPUTS
 *  pBufferNode - a BufferNode which will be the new active BufferNode
 ******************************************************************************/

{
    if (pBufferNode == m_pCurrentBufferNode)
        return;

    if ( m_pCurrentBufferNode == m_pRootBufferNode.get() &&
         m_xSAXEventKeeperStatusChangeListener.is())
    {
        m_xSAXEventKeeperStatusChangeListener->collectionStatusChanged(true);
    }

    if (pBufferNode->getParent() == nullptr)
    {
        m_pCurrentBufferNode->addChild(std::unique_ptr<BufferNode>(pBufferNode));
        pBufferNode->setParent(m_pCurrentBufferNode);
    }

    m_pCurrentBufferNode = pBufferNode;
}

BufferNode* SAXEventKeeperImpl::addNewElementMarkBuffers()
/****** SAXEventKeeperImpl/addNewElementMarkBuffers **************************
 *
 *   NAME
 *  addNewElementMarkBuffers -- add new ElementCollectors and new Blocker.
 *
 *   SYNOPSIS
 *  pBufferNode = addNewElementMarkBuffers( );
 *
 *   FUNCTION
 *  if there are new ElementCollector or new Blocker to be added, then
 *  connect all of them with the current BufferNode. In case of the
 *  current BufferNode doesn't exist, creates one.
 *  Clears up the new ElementCollector list and the new Blocker pointer.
 *
 *   RESULT
 *  pBufferNode - the BufferNode that has been connected with both new
 *                ElementCollectors and new Blocker.
 ******************************************************************************/

{
    BufferNode* pBufferNode = nullptr;

    if (m_pNewBlocker || !m_vNewElementCollectors.empty() )
    {
        /*
         * When the current BufferNode is right pointing to the current
         * working element in the XMLDocumentWrapper component, then
         * no new BufferNode is needed to create.
         * This situation can only happen in the "Forwarding" mode.
         */

        if ( (m_pCurrentBufferNode != nullptr) &&
             (m_xXMLDocument->isCurrent(m_pCurrentBufferNode->getXMLElement())))
        {
            pBufferNode = m_pCurrentBufferNode;
        }
        else
        {
            pBufferNode = new BufferNode(m_xXMLDocument->getCurrentElement());
        }

        if (m_pNewBlocker != nullptr)
        {
            pBufferNode->setBlocker(m_pNewBlocker);

            /*
             * If no blocking before, then notify the status change listener that
             * the SAXEventKeeper has entered "blocking" status, during which, no
             * SAX events will be forwarded to the next document handler.
             */

            if (m_pCurrentBlockingBufferNode == nullptr)
            {
                m_pCurrentBlockingBufferNode = pBufferNode;

                if (m_xSAXEventKeeperStatusChangeListener.is())
                {
                    m_xSAXEventKeeperStatusChangeListener->blockingStatusChanged(true);
                }
            }

            m_pNewBlocker = nullptr;
        }

        forconst auto& i : m_vNewElementCollectors )
        {
            pBufferNode->addElementCollector(i);
        }
        m_vNewElementCollectors.clear();
    }

    return pBufferNode;
}

ElementMark* SAXEventKeeperImpl::findElementMarkBuffer(sal_Int32 nId) const
/****** SAXEventKeeperImpl/findElementMarkBuffer *****************************
 *
 *   NAME
 *  findElementMarkBuffer -- finds an ElementMark.
 *
 *   SYNOPSIS
 *  pElementMark = findElementMarkBuffer( nId );
 *
 *   FUNCTION
 *  searches an ElementMark with the particular Id in the ElementMark
 *  list.
 *
 *   INPUTS
 *  nId - the Id of the ElementMark to be searched.
 *
 *   RESULT
 *  pElementMark - the ElementMark with the particular Id, or NULL when
 *                 no such Id exists.
 ******************************************************************************/

{
    ElementMark* pElementMark = nullptr;

    forauto&& ii : m_vElementMarkBuffers )
    {
        if ( nId == ii->getBufferId())
        {
            pElementMark = const_cast<ElementMark*>(ii.get());
            break;
        }
    }

    return pElementMark;
}

void SAXEventKeeperImpl::removeElementMarkBuffer(sal_Int32 nId)
/****** SAXEventKeeperImpl/removeElementMarkBuffer ***************************
 *
 *   NAME
 *  removeElementMarkBuffer -- removes an ElementMark
 *
 *   SYNOPSIS
 *  removeElementMarkBuffer( nId );
 *
 *   FUNCTION
 *  removes an ElementMark with the particular Id in the ElementMark list.
 *
 *   INPUTS
 *  nId - the Id of the ElementMark to be removed.
 ******************************************************************************/

{
    auto ii = std::find_if(m_vElementMarkBuffers.begin(), m_vElementMarkBuffers.end(),
        [nId](std::unique_ptr<const ElementMark>& rElementMark) { return nId == rElementMark->getBufferId(); }
    );
    if (ii == m_vElementMarkBuffers.end())
        return;

    /*
     * checks whether this ElementMark still in the new ElementCollect array
     */

    auto jj = std::find_if(m_vNewElementCollectors.begin(), m_vNewElementCollectors.end(),
        [&ii](const ElementCollector* pElementCollector) { return ii->get() == pElementCollector; }
    );
    if (jj != m_vNewElementCollectors.end())
        m_vNewElementCollectors.erase(jj);

    /*
     * checks whether this ElementMark is the new Blocker
     */

    if (ii->get() == m_pNewBlocker)
    {
        m_pNewBlocker = nullptr;
    }

    m_vElementMarkBuffers.erase( ii );
}

OUString SAXEventKeeperImpl::printBufferNode(
    BufferNode const * pBufferNode, sal_Int32 nIndent) const
/****** SAXEventKeeperImpl/printBufferNode ***********************************
 *
 *   NAME
 *  printBufferNode -- retrieves the information of a BufferNode and its
 *  branch.
 *
 *   SYNOPSIS
 *  info = printBufferNode( pBufferNode, nIndent );
 *
 *   FUNCTION
 *  all retrieved information includes:
 *  1. whether it is the current BufferNode;
 *  2. whether it is the current blocking BufferNode;
 *  3. the name of the parent element;
 *  4. the name of this element;
 *  5. all ElementCollectors working on this BufferNode;
 *  6. the Blocker working on this BufferNode;
 *  7. all child BufferNodes' information.
 *
 *   INPUTS
 *  pBufferNode -   the BufferNode from where information will be retrieved.
 *  nIndent -   how many space characters prefixed before the output
 *              message.
 *
 *   RESULT
 *  info - the information string
 ******************************************************************************/

{
    OUStringBuffer rc;

    for ( int i=0; i<nIndent; ++i )
    {
        rc.append(" ");
    }

    if (pBufferNode == m_pCurrentBufferNode)
    {
        rc.append("[%]");
    }

    if (pBufferNode == m_pCurrentBlockingBufferNode)
    {
        rc.append("[B]");
    }

    rc.append(" " + m_xXMLDocument->getNodeName(pBufferNode->getXMLElement()));

    BufferNode* pParent = const_cast<BufferNode*>(pBufferNode->getParent());
    if (pParent != nullptr)
    {
        rc.append("[" + m_xXMLDocument->getNodeName(pParent->getXMLElement()) + "]");
    }

    rc.append(":EC=" + pBufferNode->printChildren() + " BR=");

    ElementMark * pBlocker = pBufferNode->getBlocker();
    if (pBlocker != nullptr)
    {
        rc.append( OUString::number(pBlocker->getBufferId()) +
            "(SecId=" + OUString::number( pBlocker->getSecurityId() ) + ") ");
    }
    rc.append("\n");

    std::vector< std::unique_ptr<BufferNode> > const & vChildren = pBufferNode->getChildren();
    forconst auto& jj : vChildren )
    {
        rc.append(printBufferNode(jj.get(), nIndent+4));
    }

    return rc.makeStringAndClear();
}

css::uno::Sequence< css::uno::Reference< css::xml::wrapper::XXMLElementWrapper > >
    SAXEventKeeperImpl::collectChildWorkingElement(BufferNode const * pBufferNode)
/****** SAXEventKeeperImpl/collectChildWorkingElement ************************
 *
 *   NAME
 *  collectChildWorkingElement -- collects a BufferNode's all child
 *  Elements.
 *
 *   SYNOPSIS
 *  list = collectChildWorkingElement( pBufferNode );
 *
 *   INPUTS
 *  pBufferNode - the BufferNode whose child Elements will be collected.
 *
 *   RESULT
 *  list - the child Elements list.
 ******************************************************************************/

{
    std::vector< std::unique_ptr<BufferNode> > const & vChildren = pBufferNode->getChildren();

    css::uno::Sequence < css::uno::Reference<
        css::xml::wrapper::XXMLElementWrapper > > aChildrenCollection ( vChildren.size());

    std::transform(vChildren.begin(), vChildren.end(), aChildrenCollection.getArray(),
                   [](const auto& i) { return i->getXMLElement(); });

    return aChildrenCollection;
}

void SAXEventKeeperImpl::smashBufferNode(
    BufferNode* pBufferNode, bool bClearRoot) const
/****** SAXEventKeeperImpl/smashBufferNode ***********************************
 *
 *   NAME
 *  smashBufferNode -- removes a BufferNode along with its working
 *  element.
 *
 *   SYNOPSIS
 *  smashBufferNode( pBufferNode, bClearRoot );
 *
 *   FUNCTION
 *  removes the BufferNode's working element from the DOM document, while
 *  reserves all ancestor paths for its child BufferNodes.
 *  when any of the BufferNode's ancestor element is useless, removes it
 *  too.
 *  removes the BufferNode from the BufferNode tree.
 *
 *   INPUTS
 *  pBufferNode -   the BufferNode to be removed
 *  bClearRoot -    whether the root element also needs to be cleared up.
 *
 *   NOTES
 *  when removing a Blocker's BufferNode, the bClearRoot flag should be
 *  true. Because a Blocker can buffer many SAX events which are not used
 *  by any other ElementCollector or Blocker.
 *  When the bClearRoot is set to true, the root BufferNode will be first
 *  cleared, with a stop flag setting at the next Blocking BufferNode. This
 *  operation can delete all useless buffered SAX events which are only
 *  needed by the Blocker to be deleted.
 ******************************************************************************/

{
    if (pBufferNode->hasAnything())
        return;

    BufferNode* pParent = const_cast<BufferNode*>(pBufferNode->getParent());

    /*
     * delete the XML data
     */

    if (pParent == m_pRootBufferNode.get())
    {
        bool bIsNotBlocking = (m_pCurrentBlockingBufferNode == nullptr);
        bool bIsBlockInside = false;
        bool bIsBlockingAfterward = false;

        /*
         * If this is a blocker, then remove any out-element data
         * which caused by blocking. The removal process will stop
         * at the next blocker to avoid removing any useful data.
         */

        if (bClearRoot)
        {
            css::uno::Sequence< css::uno::Reference< css::xml::wrapper::XXMLElementWrapper > >
                aChildElements = collectChildWorkingElement(m_pRootBufferNode.get());

            /*
             * the clearUselessData only clearup the content in the
             * node, not the node itself.
             */

            m_xXMLDocument->clearUselessData(m_pRootBufferNode->getXMLElement(),
                aChildElements,
                bIsNotBlocking?nullptr:
                               (m_pCurrentBlockingBufferNode->getXMLElement()));

            /*
             * remove the node if it is empty, then if its parent is also
             * empty, remove it, then if the next parent is also empty,
             * remove it,..., until parent become null.
             */

            m_xXMLDocument->collapse( m_pRootBufferNode->getXMLElement() );
        }

        /*
         * if blocking, check the relationship between this BufferNode and
         * the current blocking BufferNode.
         */

        if ( !bIsNotBlocking )
        {
            /*
             * the current blocking BufferNode is a descendant of this BufferNode.
             */

            bIsBlockInside = (nullptr != pBufferNode->isAncestor(m_pCurrentBlockingBufferNode));

            /*
             * the current blocking BufferNode locates behind this BufferNode in tree
             * order.
             */

            bIsBlockingAfterward = pBufferNode->isPrevious(m_pCurrentBlockingBufferNode);
        }

        /*
         * this BufferNode's working element needs to be deleted only when
         * 1. there is no blocking, or
         * 2. the current blocking BufferNode is a descendant of this BufferNode,
         *    (then in the BufferNode's working element, the useless data before the blocking
         *     element should be deleted.) or
         * 3. the current blocking BufferNode is locates behind this BufferNode in tree,
         *    (then the useless data between the blocking element and the working element
         *     should be deleted.).
         * Otherwise, this working element should not be deleted.
         */

        if ( bIsNotBlocking || bIsBlockInside || bIsBlockingAfterward )
        {
            css::uno::Sequence< css::uno::Reference< css::xml::wrapper::XXMLElementWrapper > >
                aChildElements = collectChildWorkingElement(pBufferNode);

            /*
             * the clearUselessData only clearup the content in the
             * node, not the node itself.
             */

            m_xXMLDocument->clearUselessData(pBufferNode->getXMLElement(),
                aChildElements,
                bIsBlockInside?(m_pCurrentBlockingBufferNode->getXMLElement()):
                           nullptr);

            /*
             * remove the node if it is empty, then if its parent is also
             * empty, remove it, then if the next parent is also empty,
             * remove it,..., until parent become null.
             */

            m_xXMLDocument->collapse( pBufferNode->getXMLElement() );
        }
    }

    sal_Int32 nIndex = pParent->indexOfChild(pBufferNode);

    std::vector< std::unique_ptr<BufferNode> > vChildren = pBufferNode->releaseChildren();
    pParent->removeChild(pBufferNode); // delete buffernode

    forauto& i : vChildren )
    {
        i->setParent(pParent);
        pParent->addChild(std::move(i), nIndex);
        nIndex++;
    }
}

BufferNode* SAXEventKeeperImpl::findNextBlockingBufferNode(
    BufferNode* pStartBufferNode)
/****** SAXEventKeeperImpl/findNextBlockingBufferNode ************************
 *
 *   NAME
 *  findNextBlockingBufferNode -- finds the next blocking BufferNode
 *  behind the particular BufferNode.
 *
 *   SYNOPSIS
 *  pBufferNode = findNextBlockingBufferNode( pStartBufferNode );
 *
 *   INPUTS
 *  pStartBufferNode - the BufferNode from where to search the next
 *                     blocking BufferNode.
 *
 *   RESULT
 *  pBufferNode - the next blocking BufferNode, or NULL if no such
 *                BufferNode exists.
 ******************************************************************************/

{
    BufferNode* pNext = nullptr;

    if (pStartBufferNode != nullptr)
    {
        pNext = pStartBufferNode;

        while (nullptr != (pNext = const_cast<BufferNode*>(pNext->getNextNodeByTreeOrder())))
        {
            if (pNext->getBlocker() != nullptr)
            {
                break;
            }
        }
    }

    return pNext;
}

void SAXEventKeeperImpl::diffuse(BufferNode* pBufferNode)
/****** SAXEventKeeperImpl/diffuse *******************************************
 *
 *   NAME
 *  diffuse -- diffuse the notification.
 *
 *   SYNOPSIS
 *  diffuse( pBufferNode );
 *
 *   FUNCTION
 *  diffuse the collecting completion notification from the specific
 *  BufferNode along its parent link, until an ancestor which is not
 *  completely received is met.
 *
 *   INPUTS
 *  pBufferNode - the BufferNode from which the notification will be
 *                diffused.
 ******************************************************************************/

{
    BufferNode* pParent = pBufferNode;

    while(pParent->isAllReceived())
    {
        pParent->elementCollectorNotify();
        pParent = const_cast<BufferNode*>(pParent->getParent());
    }
}

void SAXEventKeeperImpl::releaseElementMarkBuffer()
/****** SAXEventKeeperImpl/releaseElementMarkBuffer **************************
 *
 *   NAME
 *  releaseElementMarkBuffer -- releases useless ElementMarks
 *
 *   SYNOPSIS
 *  releaseElementMarkBuffer( );
 *
 *   FUNCTION
 *  releases each ElementMark in the releasing list
 *  m_vReleasedElementMarkBuffers.
 *  The operation differs between an ElementCollector and a Blocker.
 ******************************************************************************/

{
    m_bIsReleasing = true;
    while (!m_vReleasedElementMarkBuffers.empty())
    {
        auto pId = m_vReleasedElementMarkBuffers.begin();
        sal_Int32 nId = *pId;
        m_vReleasedElementMarkBuffers.erase( pId );

        ElementMark* pElementMark = findElementMarkBuffer(nId);

        if (pElementMark != nullptr)
        {
            if (css::xml::crypto::sax::ElementMarkType_ELEMENTCOLLECTOR
                == pElementMark->getType())
            /*
             * it is a EC
             */

            {
                ElementCollector* pElementCollector = static_cast<ElementCollector*>(pElementMark);

                css::xml::crypto::sax::ElementMarkPriority nPriority = pElementCollector->getPriority();
                /*
                 * Delete the EC from the buffer node.
                 */

                BufferNode* pBufferNode = pElementCollector->getBufferNode();
                pBufferNode->removeElementCollector(pElementCollector);

                if ( nPriority == css::xml::crypto::sax::ElementMarkPriority_BEFOREMODIFY)
                {
                    pBufferNode->notifyBranch();
                }

                /*
                 * delete the ElementMark
                 */

                pElementCollector = nullptr;
                pElementMark = nullptr;
                removeElementMarkBuffer(nId);

                /*
                 * delete the BufferNode
                 */

                diffuse(pBufferNode);
                smashBufferNode(pBufferNode, false);
            }
            else
            /*
             * it is a Blocker
             */

            {
                /*
                 * Delete the TH from the buffer node.
                 */

                BufferNode *pBufferNode = pElementMark->getBufferNode();
                assert(pBufferNode);
                pBufferNode->setBlocker(nullptr);

                /*
                 * If there is a following handler and no blocking now, then
                 * forward this event
                 */

                if (m_pCurrentBlockingBufferNode == pBufferNode)
                {
                    /*
                     * Before forwarding, the next blocking point needs to be
                     * found.
                     */

                    m_pCurrentBlockingBufferNode = findNextBlockingBufferNode(pBufferNode);

                    /*
                     * Forward the blocked events between these two STHs.
                     */

                    if (m_xNextHandler.is())
                    {
                        BufferNode* pTempCurrentBufferNode = m_pCurrentBufferNode;
                        BufferNode* pTempCurrentBlockingBufferNode = m_pCurrentBlockingBufferNode;

                        m_pCurrentBufferNode = pBufferNode;
                        assert(pBufferNode);
                        m_pCurrentBlockingBufferNode = nullptr;

                        m_bIsForwarding = true;

                        m_xXMLDocument->generateSAXEvents(
                            m_xNextHandler,
                            this,
                            pBufferNode->getXMLElement(),
                            (pTempCurrentBlockingBufferNode == nullptr)?nullptr:(pTempCurrentBlockingBufferNode->getXMLElement()));

                        m_bIsForwarding = false;

                        m_pCurrentBufferNode = pTempCurrentBufferNode;
                        if (m_pCurrentBlockingBufferNode == nullptr)
                        {
                            m_pCurrentBlockingBufferNode = pTempCurrentBlockingBufferNode;
                        }
                    }

                    if (m_pCurrentBlockingBufferNode == nullptr &&
                        m_xSAXEventKeeperStatusChangeListener.is())
                    {
                        m_xSAXEventKeeperStatusChangeListener->blockingStatusChanged(false);
                    }
                }

                /*
                 * delete the ElementMark
                 */

                pElementMark = nullptr;
                removeElementMarkBuffer(nId);

                /*
                 * delete the BufferNode
                 */

                diffuse(pBufferNode);
                smashBufferNode(pBufferNode, true);
            }
        }
    }

    m_bIsReleasing = false;

    if (!m_pRootBufferNode->hasAnything() &&
        !m_pRootBufferNode->hasChildren() &&
        m_xSAXEventKeeperStatusChangeListener.is())
    {
        m_xSAXEventKeeperStatusChangeListener->bufferStatusChanged(true);
    }
}

void SAXEventKeeperImpl::markElementMarkBuffer(sal_Int32 nId)
/****** SAXEventKeeperImpl/markElementMarkBuffer *****************************
 *
 *   NAME
 *  markElementMarkBuffer -- marks an ElementMark to be released
 *
 *   SYNOPSIS
 *  markElementMarkBuffer( nId );
 *
 *   FUNCTION
 *  puts the ElementMark with the particular Id into the releasing list,
 *  checks whether the releasing process is running, if not then launch
 *  this process.
 *
 *   INPUTS
 *  nId - the Id of the ElementMark which will be released
 ******************************************************************************/

{
    m_vReleasedElementMarkBuffers.push_back( nId );
    if ( !m_bIsReleasing )
    {
        releaseElementMarkBuffer();
    }
}

sal_Int32 SAXEventKeeperImpl::createElementCollector(
    css::xml::crypto::sax::ElementMarkPriority nPriority,
    bool bModifyElement,
    const css::uno::Reference< css::xml::crypto::sax::XReferenceResolvedListener >& xReferenceResolvedListener)
/****** SAXEventKeeperImpl/createElementCollector ****************************
 *
 *   NAME
 *  createElementCollector -- creates a new ElementCollector on the
 *  incoming element.
 *
 *   SYNOPSIS
 *  nId = createElementCollector( nSecurityId, nPriority,
 *                               bModifyElement,
 *                               xReferenceResolvedListener );
 *
 *   FUNCTION
 *  allocs a new Id, then create an ElementCollector with this Id value.
 *  Add the new created ElementCollector to the new ElementCollecotor list.
 *
 *   INPUTS
 *  nPriority -     the priority of the new ElementCollector
 *  bModifyElement -whether this BufferNode will modify the content of
 *                  the corresponding element it works on
 *  xReferenceResolvedListener - the listener for the new ElementCollector.
 *
 *   RESULT
 *  nId - the Id of the new ElementCollector
 ******************************************************************************/

{
    sal_Int32 nId = m_nNextElementMarkId;
    m_nNextElementMarkId ++;

    ElementCollector* pElementCollector
        = new ElementCollector(
            nId,
            nPriority,
            bModifyElement,
            xReferenceResolvedListener);

    m_vElementMarkBuffers.push_back(
        std::unique_ptr<const ElementMark>(pElementCollector));

    /*
     * All the new EC to initial EC array.
     */

    m_vNewElementCollectors.push_back( pElementCollector );

    return nId;
}


sal_Int32 SAXEventKeeperImpl::createBlocker()
/****** SAXEventKeeperImpl/createBlocker *************************************
 *
 *   NAME
 *  createBlocker -- creates a new Blocker on the incoming element.
 *
 *   SYNOPSIS
 *  nId = createBlocker( nSecurityId );
 *
 *   RESULT
 *  nId - the Id of the new Blocker
 ******************************************************************************/

{
    sal_Int32 nId = m_nNextElementMarkId;
    m_nNextElementMarkId ++;

    OSL_ASSERT(m_pNewBlocker == nullptr);

    m_pNewBlocker = new ElementMark(css::xml::crypto::sax::ConstOfSecurityId::UNDEFINEDSECURITYID, nId);
    m_vElementMarkBuffers.push_back(
        std::unique_ptr<const ElementMark>(m_pNewBlocker));

    return nId;
}

/* XSAXEventKeeper */
sal_Int32 SAL_CALL SAXEventKeeperImpl::addElementCollector(  )
{
    return createElementCollector(
        css::xml::crypto::sax::ElementMarkPriority_AFTERMODIFY,
        false,
        nullptr);
}

void SAL_CALL SAXEventKeeperImpl::removeElementCollector( sal_Int32 id )
{
    markElementMarkBuffer(id);
}

sal_Int32 SAL_CALL SAXEventKeeperImpl::addBlocker(  )
{
    return createBlocker();
}

void SAL_CALL SAXEventKeeperImpl::removeBlocker( sal_Int32 id )
{
    markElementMarkBuffer(id);
}

sal_Bool SAL_CALL SAXEventKeeperImpl::isBlocking(  )
{
    return (m_pCurrentBlockingBufferNode != nullptr);
}

css::uno::Reference< css::xml::wrapper::XXMLElementWrapper > SAL_CALL
    SAXEventKeeperImpl::getElement( sal_Int32 id )
{
    css::uno::Reference< css::xml::wrapper::XXMLElementWrapper > rc;

    ElementMark* pElementMark = findElementMarkBuffer(id);
    if (pElementMark != nullptr)
    {
        rc = pElementMark->getBufferNode()->getXMLElement();
    }

    return rc;
}

void SAL_CALL SAXEventKeeperImpl::setElement(
    sal_Int32 id,
    const css::uno::Reference< css::xml::wrapper::XXMLElementWrapper >& aElement )
{
    if (aElement.is())
    {
        m_xXMLDocument->rebuildIDLink(aElement);

        ElementMark* pElementMark = findElementMarkBuffer(id);

        if (pElementMark != nullptr)
        {
            BufferNode* pBufferNode = pElementMark->getBufferNode();
            if (pBufferNode != nullptr)
            {
                const bool bIsCurrent = m_xXMLDocument->isCurrent(pBufferNode->getXMLElement());
                pBufferNode->setXMLElement(aElement);

                if (bIsCurrent)
                {
                    m_xXMLDocument->setCurrentElement(aElement);
                }
            }
        }
    }
    else
    {
        removeElementCollector( id );
    }
}

css::uno::Reference< css::xml::sax::XDocumentHandler > SAL_CALL SAXEventKeeperImpl::setNextHandler(
    const css::uno::Reference< css::xml::sax::XDocumentHandler >& xNewHandler )
{
    css::uno::Reference< css::xml::sax::XDocumentHandler > xOldHandler = m_xNextHandler;

    m_xNextHandler = xNewHandler;
    return xOldHandler;
}

OUString SAL_CALL SAXEventKeeperImpl::printBufferNodeTree()
{
    OUString rc = "ElementMarkBuffers: size = "
        + OUString::number(m_vElementMarkBuffers.size())
        + "\nCurrentBufferNode: "
        + m_xXMLDocument->getNodeName(m_pCurrentBufferNode->getXMLElement())
        + "\n" + printBufferNode(m_pRootBufferNode.get(), 0);

    return rc;
}

css::uno::Reference< css::xml::wrapper::XXMLElementWrapper > SAL_CALL SAXEventKeeperImpl::getCurrentBlockingNode()
{
    css::uno::Reference< css::xml::wrapper::XXMLElementWrapper > rc;

    if (m_pCurrentBlockingBufferNode != nullptr)
    {
        rc = m_pCurrentBlockingBufferNode->getXMLElement();
    }

    return rc;
}

/* XSecuritySAXEventKeeper */
sal_Int32 SAL_CALL SAXEventKeeperImpl::addSecurityElementCollector(
    css::xml::crypto::sax::ElementMarkPriority priority,
    sal_Bool modifyElement )
{
    return createElementCollector(
        priority,
        modifyElement,
        nullptr);
}

void SAL_CALL SAXEventKeeperImpl::setSecurityId( sal_Int32 id, sal_Int32 securityId )
{
    ElementMark* pElementMark = findElementMarkBuffer(id);
    if (pElementMark != nullptr)
    {
        pElementMark->setSecurityId(securityId);
    }
}


/* XReferenceResolvedBroadcaster */
void SAL_CALL SAXEventKeeperImpl::addReferenceResolvedListener(
    sal_Int32 referenceId,
    const css::uno::Reference< css::xml::crypto::sax::XReferenceResolvedListener >& listener )
{
    ElementCollector* pElementCollector = static_cast<ElementCollector*>(findElementMarkBuffer(referenceId));
    if (pElementCollector != nullptr)
    {
        pElementCollector->setReferenceResolvedListener(listener);
    }
}

void SAL_CALL SAXEventKeeperImpl::removeReferenceResolvedListener(
    sal_Int32 /*referenceId*/,
    const css::uno::Reference< css::xml::crypto::sax::XReferenceResolvedListener >&)
{
}

/* XSAXEventKeeperStatusChangeBroadcaster */
void SAL_CALL SAXEventKeeperImpl::addSAXEventKeeperStatusChangeListener(
    const css::uno::Reference< css::xml::crypto::sax::XSAXEventKeeperStatusChangeListener >& listener )
{
    m_xSAXEventKeeperStatusChangeListener = listener;
}

void SAL_CALL SAXEventKeeperImpl::removeSAXEventKeeperStatusChangeListener(
    const css::uno::Reference< css::xml::crypto::sax::XSAXEventKeeperStatusChangeListener >&)
{
}

/* XDocumentHandler */
void SAL_CALL SAXEventKeeperImpl::startDocument(  )
{
    if ( m_xNextHandler.is())
    {
        m_xNextHandler->startDocument();
    }
}

void SAL_CALL SAXEventKeeperImpl::endDocument(  )
{
    if ( m_xNextHandler.is())
    {
        m_xNextHandler->endDocument();
    }
}

void SAL_CALL SAXEventKeeperImpl::startElement(
    const OUString& aName,
    const css::uno::Reference< css::xml::sax::XAttributeList >& xAttribs )
{
    /*
     * If there is a following handler and no blocking now, then
     * forward this event
     */

    if ((m_pCurrentBlockingBufferNode == nullptr) &&
        (m_xNextHandler.is()) &&
        (!m_bIsForwarding) &&
        (m_pNewBlocker == nullptr))
    {
        m_xNextHandler->startElement(aName, xAttribs);
    }
    /*
     * If not forwarding, buffer this startElement.
     */

    if (!m_bIsForwarding)
    {
        sal_Int32 nLength = xAttribs->getLength();
        css::uno::Sequence< css::xml::csax::XMLAttribute > aAttributes (nLength);
        auto aAttributesRange = asNonConstRange(aAttributes);

        for ( int i = 0; i<nLength; ++i )
        {
            aAttributesRange[i].sName = xAttribs->getNameByIndex(static_cast<short>(i));
            aAttributesRange[i].sValue =xAttribs->getValueByIndex(static_cast<short>(i));
        }

        m_xCompressedDocumentHandler->compressedStartElement(aName, aAttributes);
    }

    BufferNode* pBufferNode = addNewElementMarkBuffers();
    if (pBufferNode != nullptr)
    {
        setCurrentBufferNode(pBufferNode);
    }
}

void SAL_CALL SAXEventKeeperImpl::endElement( const OUString& aName )
{
    const bool bIsCurrent = m_xXMLDocument->isCurrent(m_pCurrentBufferNode->getXMLElement());

    /*
     * If there is a following handler and no blocking now, then
     * forward this event
     */

    if ((m_pCurrentBlockingBufferNode == nullptr) &&
        (m_xNextHandler.is()) &&
        (!m_bIsForwarding))
    {
        m_xNextHandler->endElement(aName);
    }

    if ((m_pCurrentBlockingBufferNode != nullptr) ||
        (m_pCurrentBufferNode != m_pRootBufferNode.get()) ||
        (!m_xXMLDocument->isCurrentElementEmpty()))
    {
        if (!m_bIsForwarding)
        {
            m_xCompressedDocumentHandler->compressedEndElement(aName);
        }

        /*
        * If the current buffer node has not notified yet, and
        * the current buffer node is waiting for the current element,
        * then let it notify.
        */

        if (bIsCurrent && (m_pCurrentBufferNode != m_pRootBufferNode.get()))
        {
            BufferNode* pOldCurrentBufferNode = m_pCurrentBufferNode;
            m_pCurrentBufferNode = const_cast<BufferNode*>(m_pCurrentBufferNode->getParent());

            pOldCurrentBufferNode->setReceivedAll();

            if ((m_pCurrentBufferNode == m_pRootBufferNode.get()) &&
                m_xSAXEventKeeperStatusChangeListener.is())
            {
                m_xSAXEventKeeperStatusChangeListener->collectionStatusChanged(false);
            }
        }
    }
    else
    {
        if (!m_bIsForwarding)
        {
            m_xXMLDocument->removeCurrentElement();
        }
    }
}

void SAL_CALL SAXEventKeeperImpl::characters( const OUString& aChars )
{
    if (m_bIsForwarding)
        return;

    if ((m_pCurrentBlockingBufferNode == nullptr) && m_xNextHandler.is())
    {
        m_xNextHandler->characters(aChars);
    }

    if ((m_pCurrentBlockingBufferNode != nullptr) ||
        (m_pCurrentBufferNode != m_pRootBufferNode.get()))
    {
        m_xCompressedDocumentHandler->compressedCharacters(aChars);
    }
}

void SAL_CALL SAXEventKeeperImpl::ignorableWhitespace( const OUString& aWhitespaces )
{
    characters( aWhitespaces );
}

void SAL_CALL SAXEventKeeperImpl::processingInstruction(
    const OUString& aTarget, const OUString& aData )
{
    if (m_bIsForwarding)
        return;

    if ((m_pCurrentBlockingBufferNode == nullptr) && m_xNextHandler.is())
    {
        m_xNextHandler->processingInstruction(aTarget, aData);
    }

    if ((m_pCurrentBlockingBufferNode != nullptr) ||
        (m_pCurrentBufferNode != m_pRootBufferNode.get()))
    {
        m_xCompressedDocumentHandler->compressedProcessingInstruction(aTarget, aData);
    }
}

void SAL_CALL SAXEventKeeperImpl::setDocumentLocator( const css::uno::Reference< css::xml::sax::XLocator >&)
{
}

/* XInitialization */
void SAL_CALL SAXEventKeeperImpl::initialize( const css::uno::Sequence< css::uno::Any >&&nbsp;aArguments )
{
    OSL_ASSERT(aArguments.getLength() == 1);

    aArguments[0] >>= m_xXMLDocument;
    m_xDocumentHandler.set( m_xXMLDocument, css::uno::UNO_QUERY );
    m_xCompressedDocumentHandler.set( m_xXMLDocument, css::uno::UNO_QUERY );

    m_pRootBufferNode.reset( new BufferNode(m_xXMLDocument->getCurrentElement()) );
    m_pCurrentBufferNode = m_pRootBufferNode.get();
}

OUString SAXEventKeeperImpl_getImplementationName ()
{
    return u"com.sun.star.xml.security.framework.SAXEventKeeperImpl"_ustr;
}

css::uno::Sequence< OUString > SAXEventKeeperImpl_getSupportedServiceNames(  )
{
    return { u"com.sun.star.xml.crypto.sax.SAXEventKeeper"_ustr };
}

/* XServiceInfo */
OUString SAL_CALL SAXEventKeeperImpl::getImplementationName(  )
{
    return SAXEventKeeperImpl_getImplementationName();
}

sal_Bool SAL_CALL SAXEventKeeperImpl::supportsService( const OUString& rServiceName )
{
    return cppu::supportsService(this, rServiceName);
}

css::uno::Sequence< OUString > SAL_CALL SAXEventKeeperImpl::getSupportedServiceNames(  )
{
    return SAXEventKeeperImpl_getSupportedServiceNames();
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=95 H=99 G=96

¤ Dauer der Verarbeitung: 0.20 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge