android: Update app icon to new startcenter icon
[LibreOffice.git] / xmlsecurity / source / framework / buffernode.cxx
blob4dfa9fbfe20b46d721216b1050eff8c95846d3f6
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 "elementmark.hxx"
22 #include "elementcollector.hxx"
23 #include "buffernode.hxx"
24 #include <com/sun/star/xml/crypto/sax/ConstOfSecurityId.hpp>
25 #include <osl/diagnose.h>
26 #include <rtl/ustrbuf.hxx>
27 #include <utility>
29 BufferNode::BufferNode( css::uno::Reference< css::xml::wrapper::XXMLElementWrapper > xXMLElement )
30 :m_pParent(nullptr),
31 m_pBlocker(nullptr),
32 m_bAllReceived(false),
33 m_xXMLElement(std::move(xXMLElement))
37 bool BufferNode::isECOfBeforeModifyIncluded(sal_Int32 nIgnoredSecurityId) const
38 /****** BufferNode/isECOfBeforeModifyIncluded ********************************
40 * NAME
41 * isECOfBeforeModifyIncluded -- checks whether there is some
42 * ElementCollector on this BufferNode, that has BEFORE-MODIFY priority.
44 * SYNOPSIS
45 * bExist = isECOfBeforeModifyIncluded(nIgnoredSecurityId);
47 * FUNCTION
48 * checks each ElementCollector on this BufferNode, if all following
49 * conditions are satisfied, then returns true:
50 * 1. the ElementCollector's priority is BEFOREMODIFY;
51 * 2. the ElementCollector's securityId can't be ignored.
52 * otherwise, returns false.
54 * INPUTS
55 * nIgnoredSecurityId - the security Id to be ignored. If it equals
56 * to UNDEFINEDSECURITYID, then no security Id
57 * will be ignored.
59 * RESULT
60 * bExist - true if a match found, false otherwise
61 ******************************************************************************/
63 return std::any_of(m_vElementCollectors.cbegin(), m_vElementCollectors.cend(),
64 [nIgnoredSecurityId](const ElementCollector* pElementCollector) {
65 return (nIgnoredSecurityId == css::xml::crypto::sax::ConstOfSecurityId::UNDEFINEDSECURITYID ||
66 pElementCollector->getSecurityId() != nIgnoredSecurityId) &&
67 (pElementCollector->getPriority() == css::xml::crypto::sax::ElementMarkPriority_BEFOREMODIFY);
68 });
71 void BufferNode::setReceivedAll()
72 /****** BufferNode/setReceiveAll *********************************************
74 * NAME
75 * setReceivedAll -- indicates that the element in this BufferNode has
76 * been completely buffered.
78 * SYNOPSIS
79 * setReceivedAll();
81 * FUNCTION
82 * sets the all-received flag and launches ElementCollector's notify
83 * process.
85 * INPUTS
86 * empty
88 * RESULT
89 * empty
90 ******************************************************************************/
92 m_bAllReceived = true;
93 elementCollectorNotify();
97 void BufferNode::addElementCollector(const ElementCollector* pElementCollector)
98 /****** BufferNode/addElementCollector ***************************************
100 * NAME
101 * addElementCollector -- adds a new ElementCollector to this BufferNode.
103 * SYNOPSIS
104 * addElementCollector(pElementCollector);
106 * FUNCTION
107 * see NAME
109 * INPUTS
110 * pElementCollector - the ElementCollector to be added
112 * RESULT
113 * empty
114 ******************************************************************************/
116 m_vElementCollectors.push_back( pElementCollector );
117 const_cast<ElementCollector*>(pElementCollector)->setBufferNode(this);
120 void BufferNode::removeElementCollector(const ElementCollector* pElementCollector)
121 /****** BufferNode/removeElementCollector ************************************
123 * NAME
124 * removeElementCollector -- removes an ElementCollector from this
125 * BufferNode.
127 * SYNOPSIS
128 * removeElementCollector(pElementCollector);
130 * FUNCTION
131 * see NAME
133 * INPUTS
134 * pElementCollector - the ElementCollector to be removed
136 * RESULT
137 * empty
138 ******************************************************************************/
140 auto ii = std::find(m_vElementCollectors.begin(), m_vElementCollectors.end(), pElementCollector);
141 if (ii != m_vElementCollectors.end())
143 m_vElementCollectors.erase( ii );
144 const_cast<ElementCollector*>(pElementCollector)->setBufferNode(nullptr);
149 void BufferNode::setBlocker(const ElementMark* pBlocker)
150 /****** BufferNode/setBlocker ************************************************
152 * NAME
153 * setBlocker -- adds a blocker to this BufferNode.
155 * SYNOPSIS
156 * setBlocker(pBlocker);
158 * FUNCTION
159 * see NAME
161 * INPUTS
162 * pBlocker - the new blocker to be attached
164 * RESULT
165 * empty
167 * NOTES
168 * Because there is only one blocker permitted for a BufferNode, so the
169 * old blocker on this BufferNode, if there is one, will be overcasted.
170 ******************************************************************************/
172 OSL_ASSERT(!(m_pBlocker != nullptr && pBlocker != nullptr));
174 m_pBlocker = const_cast<ElementMark*>(pBlocker);
175 if (m_pBlocker != nullptr)
177 m_pBlocker->setBufferNode(this);
181 OUString BufferNode::printChildren() const
182 /****** BufferNode/printChildren *********************************************
184 * NAME
185 * printChildren -- prints children information into a string.
187 * SYNOPSIS
188 * result = printChildren();
190 * FUNCTION
191 * see NAME
193 * INPUTS
194 * empty
196 * RESULT
197 * result - the information string
198 ******************************************************************************/
200 OUStringBuffer rc;
202 for( const ElementCollector* ii : m_vElementCollectors )
204 rc.append("BufID=" + OUString::number(ii->getBufferId()));
206 if (ii->getModify())
208 rc.append("[M]");
211 rc.append(",Pri=");
213 switch (ii->getPriority())
215 case css::xml::crypto::sax::ElementMarkPriority_BEFOREMODIFY:
216 rc.append("BEFOREMODIFY");
217 break;
218 case css::xml::crypto::sax::ElementMarkPriority_AFTERMODIFY:
219 rc.append("AFTERMODIFY");
220 break;
221 default:
222 rc.append("UNKNOWN");
223 break;
226 rc.append("(SecID=" + OUString::number(ii->getSecurityId()) + ") ");
229 return rc.makeStringAndClear();
232 bool BufferNode::hasAnything() const
233 /****** BufferNode/hasAnything ***********************************************
235 * NAME
236 * hasAnything -- checks whether there is any ElementCollector or blocker
237 * on this BufferNode.
239 * SYNOPSIS
240 * bExist = hasAnything();
242 * FUNCTION
243 * see NAME
245 * INPUTS
246 * empty
248 * RESULT
249 * bExist - true if there is, false otherwise.
250 ******************************************************************************/
252 return (m_pBlocker || !m_vElementCollectors.empty());
255 bool BufferNode::hasChildren() const
256 /****** BufferNode/hasChildren ***********************************************
258 * NAME
259 * hasChildren -- checks whether this BufferNode has any child
260 * BufferNode.
262 * SYNOPSIS
263 * bExist = hasChildren();
265 * FUNCTION
266 * see NAME
268 * INPUTS
269 * empty
271 * RESULT
272 * bExist - true if there is, false otherwise.
273 ******************************************************************************/
275 return (!m_vChildren.empty());
278 std::vector< std::unique_ptr<BufferNode> > const & BufferNode::getChildren() const
280 return m_vChildren;
283 std::vector< std::unique_ptr<BufferNode> > BufferNode::releaseChildren()
285 return std::move(m_vChildren);
288 const BufferNode* BufferNode::getFirstChild() const
289 /****** BufferNode/getFirstChild *********************************************
291 * NAME
292 * getFirstChild -- retrieves the first child BufferNode.
294 * SYNOPSIS
295 * child = getFirstChild();
297 * FUNCTION
298 * see NAME
300 * INPUTS
301 * empty
303 * RESULT
304 * child - the first child BufferNode, or NULL if there is no child
305 * BufferNode.
306 ******************************************************************************/
308 BufferNode* rc = nullptr;
310 if (!m_vChildren.empty())
312 rc = m_vChildren.front().get();
315 return rc;
318 void BufferNode::addChild(std::unique_ptr<BufferNode> pChild, sal_Int32 nPosition)
319 /****** BufferNode/addChild(pChild,nPosition) ********************************
321 * NAME
322 * addChild -- inserts a child BufferNode at specific position.
324 * SYNOPSIS
325 * addChild(pChild, nPosition);
327 * FUNCTION
328 * see NAME
330 * INPUTS
331 * pChild - the child BufferNode to be added.
332 * nPosition - the position where the new child locates.
334 * RESULT
335 * empty
337 * NOTES
338 * If the nPosition is -1, then the new child BufferNode is appended
339 * at the end.
340 ******************************************************************************/
342 if (nPosition == -1)
344 m_vChildren.push_back( std::move(pChild) );
346 else
348 m_vChildren.insert(m_vChildren.begin() + nPosition, std::move(pChild));
352 void BufferNode::addChild(std::unique_ptr<BufferNode> pChild)
353 /****** BufferNode/addChild() ************************************************
355 * NAME
356 * addChild -- add a new child BufferNode.
358 * SYNOPSIS
359 * addChild(pChild);
361 * FUNCTION
362 * see NAME
364 * INPUTS
365 * pChild - the child BufferNode to be added.
367 * RESULT
368 * empty
370 * NOTES
371 * The new child BufferNode is appended at the end.
372 ******************************************************************************/
374 addChild(std::move(pChild), -1);
377 void BufferNode::removeChild(const BufferNode* pChild)
378 /****** BufferNode/removeChild ***********************************************
380 * NAME
381 * removeChild -- removes and deletes a child BufferNode from the children list.
383 * SYNOPSIS
384 * removeChild(pChild);
386 * FUNCTION
387 * see NAME
389 * INPUTS
390 * pChild - the child BufferNode to be removed
392 * RESULT
393 * empty
394 ******************************************************************************/
396 auto ii = std::find_if(m_vChildren.begin(), m_vChildren.end(),
397 [pChild] (const std::unique_ptr<BufferNode>& i)
398 { return i.get() == pChild; });
399 if (ii != m_vChildren.end())
400 m_vChildren.erase( ii );
403 sal_Int32 BufferNode::indexOfChild(const BufferNode* pChild) const
404 /****** BufferNode/indexOfChild **********************************************
406 * NAME
407 * indexOfChild -- gets the index of a child BufferNode.
409 * SYNOPSIS
410 * index = indexOfChild(pChild);
412 * FUNCTION
413 * see NAME
415 * INPUTS
416 * pChild - the child BufferNode whose index to be gotten
418 * RESULT
419 * index - the index of that child BufferNode. If that child BufferNode
420 * is not found, -1 is returned.
421 ******************************************************************************/
423 auto ii = std::find_if(m_vChildren.begin(), m_vChildren.end(),
424 [pChild] (const std::unique_ptr<BufferNode>& i)
425 { return i.get() == pChild; });
426 if (ii == m_vChildren.end())
427 return -1;
429 return std::distance(m_vChildren.begin(), ii);
433 void BufferNode::setParent(const BufferNode* pParent)
435 m_pParent = const_cast<BufferNode*>(pParent);
438 const BufferNode* BufferNode::getNextSibling() const
439 /****** BufferNode/getNextSibling ********************************************
441 * NAME
442 * getNextSibling -- retrieves the next sibling BufferNode.
444 * SYNOPSIS
445 * sibling = getNextSibling();
447 * FUNCTION
448 * see NAME
450 * INPUTS
451 * empty
453 * RESULT
454 * sibling - the next sibling BufferNode, or NULL if there is none.
455 ******************************************************************************/
457 BufferNode* rc = nullptr;
459 if (m_pParent != nullptr)
461 rc = const_cast<BufferNode*>(m_pParent->getNextChild(this));
464 return rc;
467 const BufferNode* BufferNode::isAncestor(const BufferNode* pDescendant) const
468 /****** BufferNode/isAncestor ************************************************
470 * NAME
471 * isAncestor -- checks whether this BufferNode is an ancestor of another
472 * BufferNode.
474 * SYNOPSIS
475 * bIs = isAncestor(pDescendant);
477 * FUNCTION
478 * see NAME
480 * INPUTS
481 * pDescendant - the BufferNode to be checked as a descendant
483 * RESULT
484 * bIs - true if this BufferNode is an ancestor of the pDescendant,
485 * false otherwise.
486 ******************************************************************************/
488 BufferNode* rc = nullptr;
490 if (pDescendant != nullptr)
492 auto ii = std::find_if(m_vChildren.cbegin(), m_vChildren.cend(),
493 [&pDescendant](const std::unique_ptr<BufferNode>& pChild) {
494 return (pChild.get() == pDescendant) || (pChild->isAncestor(pDescendant) != nullptr);
497 if (ii != m_vChildren.end())
498 rc = ii->get();
501 return rc;
504 bool BufferNode::isPrevious(const BufferNode* pFollowing) const
505 /****** BufferNode/isPrevious ************************************************
507 * NAME
508 * isPrevious -- checks whether this BufferNode is ahead of another
509 * BufferNode in the tree order.
511 * SYNOPSIS
512 * bIs = isPrevious(pFollowing);
514 * FUNCTION
515 * see NAME
517 * INPUTS
518 * pFollowing - the BufferNode to be checked as a following
520 * RESULT
521 * bIs - true if this BufferNode is ahead in the tree order, false
522 * otherwise.
523 ******************************************************************************/
525 bool rc = false;
527 BufferNode* pNextBufferNode = const_cast<BufferNode*>(getNextNodeByTreeOrder());
528 while (pNextBufferNode != nullptr)
530 if (pNextBufferNode == pFollowing)
532 rc = true;
533 break;
536 pNextBufferNode = const_cast<BufferNode*>(pNextBufferNode->getNextNodeByTreeOrder());
539 return rc;
542 const BufferNode* BufferNode::getNextNodeByTreeOrder() const
543 /****** BufferNode/getNextNodeByTreeOrder ************************************
545 * NAME
546 * getNextNodeByTreeOrder -- retrieves the next BufferNode in the tree
547 * order.
549 * SYNOPSIS
550 * next = getNextNodeByTreeOrder();
552 * FUNCTION
553 * see NAME
555 * INPUTS
556 * empty
558 * RESULT
559 * next - the BufferNode following this BufferNode in the tree order,
560 * or NULL if there is none.
562 * NOTES
563 * The "next" node in tree order is defined as:
564 * 1. If a node has children, then the first child is;
565 * 2. otherwise, if it has a following sibling, then this sibling node is;
566 * 3. otherwise, if it has a parent node, the parent's next sibling
567 * node is;
568 * 4. otherwise, no "next" node exists.
569 ******************************************************************************/
572 * If this buffer node has m_vChildren, then return the first
573 * child.
575 if (hasChildren())
577 return getFirstChild();
581 * Otherwise, it this buffer node has a following sibling,
582 * then return that sibling.
584 BufferNode* pNextSibling = const_cast<BufferNode*>(getNextSibling());
585 if (pNextSibling != nullptr)
587 return pNextSibling;
591 * Otherwise, it this buffer node has parent, then return
592 * its parent's following sibling.
594 BufferNode* pNode = const_cast<BufferNode*>(this);
595 BufferNode* pParent;
596 BufferNode* pNextSiblingParent = nullptr;
600 if (pNode == nullptr)
602 break;
605 pParent = const_cast<BufferNode*>(pNode->getParent());
606 if (pParent != nullptr)
608 pNextSiblingParent = const_cast<BufferNode*>(pParent->getNextSibling());
610 pNode = pParent;
612 } while (pNextSiblingParent == nullptr);
614 return pNextSiblingParent;
618 void BufferNode::setXMLElement( const css::uno::Reference< css::xml::wrapper::XXMLElementWrapper >& xXMLElement )
620 m_xXMLElement = xXMLElement;
623 void BufferNode::notifyBranch()
624 /****** BufferNode/notifyBranch **********************************************
626 * NAME
627 * notifyBranch -- notifies each BufferNode in the branch of this
628 * BufferNode in the tree order.
630 * SYNOPSIS
631 * notifyBranch();
633 * FUNCTION
634 * see NAME
636 * INPUTS
637 * empty
639 * RESULT
640 * empty
641 ******************************************************************************/
643 for( std::unique_ptr<BufferNode>& pBufferNode : m_vChildren )
645 pBufferNode->elementCollectorNotify();
646 pBufferNode->notifyBranch();
650 void BufferNode::elementCollectorNotify()
651 /****** BufferNode/elementCollectorNotify ************************************
653 * NAME
654 * elementCollectorNotify -- notifies this BufferNode.
656 * SYNOPSIS
657 * elementCollectorNotify();
659 * FUNCTION
660 * Notifies this BufferNode if the notification is not suppressed.
662 * INPUTS
663 * empty
665 * RESULT
666 * child - the first child BufferNode, or NULL if there is no child
667 * BufferNode.
668 ******************************************************************************/
670 if (m_vElementCollectors.empty())
671 return;
673 css::xml::crypto::sax::ElementMarkPriority nMaxPriority = css::xml::crypto::sax::ElementMarkPriority_MINIMUM;
674 css::xml::crypto::sax::ElementMarkPriority nPriority;
677 * get the max priority among ElementCollectors on this BufferNode
679 for( const ElementCollector* pElementCollector : m_vElementCollectors )
681 nPriority = pElementCollector->getPriority();
682 if (nPriority > nMaxPriority)
684 nMaxPriority = nPriority;
688 std::vector< const ElementCollector* > vElementCollectors( m_vElementCollectors );
690 for( const ElementCollector* ii : vElementCollectors )
692 ElementCollector* pElementCollector = const_cast<ElementCollector*>(ii);
693 nPriority = pElementCollector->getPriority();
694 bool bToModify = pElementCollector->getModify();
697 * Only ElementCollector with the max priority can
698 * perform notify operation.
699 * Moreover, if any blocker exists in the subtree of
700 * this BufferNode, this ElementCollector can't do notify
701 * unless its priority is BEFOREMODIFY.
703 if (nPriority == nMaxPriority &&
704 (nPriority == css::xml::crypto::sax::ElementMarkPriority_BEFOREMODIFY ||
705 !isBlockerInSubTreeIncluded(pElementCollector->getSecurityId())))
708 * If this ElementCollector will modify the buffered element, then
709 * special attention must be paid.
711 * If there is any ElementCollector in the subtree or any ancestor
712 * ElementCollector with PRI_BEFPREMODIFY priority, this
713 * ElementCollector can't perform notify operation, otherwise, it
714 * will destroy the buffered element, in turn, ElementCollectors
715 * mentioned above can't perform their mission.
717 //if (!(nMaxPriority == css::xml::crypto::sax::ElementMarkPriority_PRI_MODIFY &&
718 if (!(bToModify &&
719 (isECInSubTreeIncluded(pElementCollector->getSecurityId()) ||
720 isECOfBeforeModifyInAncestorIncluded(pElementCollector->getSecurityId()))
723 pElementCollector->notifyListener();
729 bool BufferNode::isECInSubTreeIncluded(sal_Int32 nIgnoredSecurityId) const
730 /****** BufferNode/isECInSubTreeIncluded *************************************
732 * NAME
733 * isECInSubTreeIncluded -- checks whether there is any ElementCollector
734 * in the branch of this BufferNode.
736 * SYNOPSIS
737 * bExist = isECInSubTreeIncluded(nIgnoredSecurityId);
739 * FUNCTION
740 * checks each BufferNode in the branch of this BufferNode, if there is
741 * an ElementCollector whose signatureId is not ignored, then return
742 * true, otherwise, false returned.
744 * INPUTS
745 * nIgnoredSecurityId - the security Id to be ignored. If it equals
746 * to UNDEFINEDSECURITYID, then no security Id
747 * will be ignored.
749 * RESULT
750 * bExist - true if a match found, false otherwise.
751 ******************************************************************************/
753 bool rc = std::any_of(m_vElementCollectors.begin(), m_vElementCollectors.end(),
754 [nIgnoredSecurityId](const ElementCollector* pElementCollector) {
755 return nIgnoredSecurityId == css::xml::crypto::sax::ConstOfSecurityId::UNDEFINEDSECURITYID ||
756 pElementCollector->getSecurityId() != nIgnoredSecurityId;
759 if ( !rc )
761 rc = std::any_of(m_vChildren.begin(), m_vChildren.end(),
762 [nIgnoredSecurityId](const std::unique_ptr<BufferNode>& pBufferNode) {
763 return pBufferNode->isECInSubTreeIncluded(nIgnoredSecurityId);
767 return rc;
770 bool BufferNode::isECOfBeforeModifyInAncestorIncluded(sal_Int32 nIgnoredSecurityId) const
771 /****** BufferNode/isECOfBeforeModifyInAncestorIncluded **********************
773 * NAME
774 * isECOfBeforeModifyInAncestorIncluded -- checks whether there is some
775 * ancestor BufferNode which has ElementCollector with PRI_BEFPREMODIFY
776 * priority.
778 * SYNOPSIS
779 * bExist = isECOfBeforeModifyInAncestorIncluded(nIgnoredSecurityId);
781 * FUNCTION
782 * checks each ancestor BufferNode through the parent link, if there is
783 * an ElementCollector with PRI_BEFPREMODIFY priority and its
784 * signatureId is not ignored, then return true, otherwise, false
785 * returned.
787 * INPUTS
788 * nIgnoredSecurityId - the security Id to be ignored. If it equals
789 * to UNDEFINEDSECURITYID, then no security Id
790 * will be ignored.
792 * RESULT
793 * bExist - true if a match found, false otherwise.
794 ******************************************************************************/
796 bool rc = false;
798 BufferNode* pParentNode = m_pParent;
799 while (pParentNode != nullptr)
801 if (pParentNode->isECOfBeforeModifyIncluded(nIgnoredSecurityId))
803 rc = true;
804 break;
807 pParentNode = const_cast<BufferNode*>(pParentNode->getParent());
810 return rc;
813 bool BufferNode::isBlockerInSubTreeIncluded(sal_Int32 nIgnoredSecurityId) const
814 /****** BufferNode/isBlockerInSubTreeIncluded ********************************
816 * NAME
817 * isBlockerInSubTreeIncluded -- checks whether there is some BufferNode
818 * which has blocker on it
820 * SYNOPSIS
821 * bExist = isBlockerInSubTreeIncluded(nIgnoredSecurityId);
823 * FUNCTION
824 * checks each BufferNode in the branch of this BufferNode, if one has
825 * a blocker on it, and the blocker's securityId is not ignored, then
826 * returns true; otherwise, false returns.
828 * INPUTS
829 * nIgnoredSecurityId - the security Id to be ignored. If it equals
830 * to UNDEFINEDSECURITYID, then no security Id
831 * will be ignored.
833 * RESULT
834 * bExist - true if a match found, false otherwise.
835 ******************************************************************************/
837 return std::any_of(m_vChildren.begin(), m_vChildren.end(),
838 [nIgnoredSecurityId](const std::unique_ptr<BufferNode>& pBufferNode) {
839 ElementMark* pBlocker = pBufferNode->getBlocker();
840 return (pBlocker != nullptr &&
841 (nIgnoredSecurityId == css::xml::crypto::sax::ConstOfSecurityId::UNDEFINEDSECURITYID ||
842 pBlocker->getSecurityId() != nIgnoredSecurityId )) ||
843 pBufferNode->isBlockerInSubTreeIncluded(nIgnoredSecurityId);
847 const BufferNode* BufferNode::getNextChild(const BufferNode* pChild) const
848 /****** BufferNode/getNextChild **********************************************
850 * NAME
851 * getNextChild -- get the next child BufferNode.
853 * SYNOPSIS
854 * nextChild = getNextChild();
856 * FUNCTION
857 * see NAME
859 * INPUTS
860 * pChild - the child BufferNode whose next node is retrieved.
862 * RESULT
863 * nextChild - the next child BufferNode after the pChild, or NULL if
864 * there is none.
865 ******************************************************************************/
867 BufferNode* rc = nullptr;
868 bool bChildFound = false;
870 for( std::unique_ptr<BufferNode> const & i : m_vChildren )
872 if (bChildFound)
874 rc = i.get();
875 break;
878 if( i.get() == pChild )
880 bChildFound = true;
884 return rc;
887 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */