From 17c9cfef1a1bf48489fc856d59c6776a47ef0f77 Mon Sep 17 00:00:00 2001 From: Eike Rathke Date: Mon, 8 Jun 2015 15:33:51 +0200 Subject: check bounds in RPN tokens, tdf#90694 related and others MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Listeners are set up from references in RPN, so check those for bounds to catch also references resulting from named expressions, database ranges, tables, ... and references in the token code array that are not referenced in RPN. (cherry picked from commit 4baf76ddb39580678cf14019900be78bb9071d7b) Windows MSVC: cannot specify explicit initializer for arrays (cherry picked from commit 883ebe0283dc6bdf62f08191dede2a249f777f63) c42897ba6bb520c931f63e56d0f453ed14cfaa3d Change-Id: I54770b45818f4c0541a39815278d3271a77b345d Reviewed-on: https://gerrit.libreoffice.org/16155 Reviewed-by: Caolán McNamara Reviewed-by: Christian Lohmaier Tested-by: Christian Lohmaier --- sc/source/core/tool/token.cxx | 277 +++++++++++++++++++++++++----------------- 1 file changed, 163 insertions(+), 114 deletions(-) diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx index 9500a2841149..1462a8be309f 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -113,6 +113,34 @@ namespace rRef.SetAbsTab(0); } + struct TokenPointerRange + { + FormulaToken** mpStart; + FormulaToken** mpStop; + + TokenPointerRange() : mpStart(NULL), mpStop(NULL) {} + TokenPointerRange( FormulaToken** p, sal_uInt16 n ) : + mpStart(p), mpStop( p + static_cast(n)) {} + }; + struct TokenPointers + { + TokenPointerRange maPointerRange[2]; + + TokenPointers( FormulaToken** pCode, sal_uInt16 nLen, FormulaToken** pRPN, sal_uInt16 nRPN ) + { + maPointerRange[0] = TokenPointerRange( pCode, nLen); + maPointerRange[1] = TokenPointerRange( pRPN, nRPN); + } + + static bool skipToken( size_t i, const FormulaToken* const * pp ) + { + // Handle all tokens in RPN, and code tokens only if they have a + // reference count of 1, which means they are not referenced in + // RPN. + return i == 0 && (*pp)->GetRef() > 1; + } + }; + } // namespace // Align MemPools on 4k boundaries - 64 bytes (4k is a MUST for OS/2) @@ -3670,28 +3698,35 @@ void checkBounds( void ScTokenArray::CheckRelativeReferenceBounds( const sc::RefUpdateContext& rCxt, const ScAddress& rPos, SCROW nGroupLen, std::vector& rBounds ) const { - FormulaToken** p = pCode; - FormulaToken** pEnd = p + static_cast(nLen); - for (; p != pEnd; ++p) + TokenPointers aPtrs( pCode, nLen, pRPN, nRPN); + for (size_t j=0; j<2; ++j) { - switch ((*p)->GetType()) + FormulaToken** p = aPtrs.maPointerRange[j].mpStart; + FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop; + for (; p != pEnd; ++p) { - case svSingleRef: - { - formula::FormulaToken* pToken = *p; - checkBounds(rCxt, rPos, nGroupLen, *pToken->GetSingleRef(), rBounds); - } - break; - case svDoubleRef: + if (TokenPointers::skipToken(j,p)) + continue; + + switch ((*p)->GetType()) { - formula::FormulaToken* pToken = *p; - const ScComplexRefData& rRef = *pToken->GetDoubleRef(); - checkBounds(rCxt, rPos, nGroupLen, rRef.Ref1, rBounds); - checkBounds(rCxt, rPos, nGroupLen, rRef.Ref2, rBounds); + case svSingleRef: + { + formula::FormulaToken* pToken = *p; + checkBounds(rCxt, rPos, nGroupLen, *pToken->GetSingleRef(), rBounds); + } + break; + case svDoubleRef: + { + formula::FormulaToken* pToken = *p; + const ScComplexRefData& rRef = *pToken->GetDoubleRef(); + checkBounds(rCxt, rPos, nGroupLen, rRef.Ref1, rBounds); + checkBounds(rCxt, rPos, nGroupLen, rRef.Ref2, rBounds); + } + break; + default: + ; } - break; - default: - ; } } } @@ -3699,29 +3734,36 @@ void ScTokenArray::CheckRelativeReferenceBounds( void ScTokenArray::CheckRelativeReferenceBounds( const ScAddress& rPos, SCROW nGroupLen, const ScRange& rRange, std::vector& rBounds ) const { - FormulaToken** p = pCode; - FormulaToken** pEnd = p + static_cast(nLen); - for (; p != pEnd; ++p) + TokenPointers aPtrs( pCode, nLen, pRPN, nRPN); + for (size_t j=0; j<2; ++j) { - switch ((*p)->GetType()) + FormulaToken** p = aPtrs.maPointerRange[j].mpStart; + FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop; + for (; p != pEnd; ++p) { - case svSingleRef: - { - formula::FormulaToken* pToken = *p; - const ScSingleRefData& rRef = *pToken->GetSingleRef(); - checkBounds(rPos, nGroupLen, rRange, rRef, rBounds); - } - break; - case svDoubleRef: + if (TokenPointers::skipToken(j,p)) + continue; + + switch ((*p)->GetType()) { - formula::FormulaToken* pToken = *p; - const ScComplexRefData& rRef = *pToken->GetDoubleRef(); - checkBounds(rPos, nGroupLen, rRange, rRef.Ref1, rBounds); - checkBounds(rPos, nGroupLen, rRange, rRef.Ref2, rBounds); + case svSingleRef: + { + formula::FormulaToken* pToken = *p; + const ScSingleRefData& rRef = *pToken->GetSingleRef(); + checkBounds(rPos, nGroupLen, rRange, rRef, rBounds); + } + break; + case svDoubleRef: + { + formula::FormulaToken* pToken = *p; + const ScComplexRefData& rRef = *pToken->GetDoubleRef(); + checkBounds(rPos, nGroupLen, rRange, rRef.Ref1, rBounds); + checkBounds(rPos, nGroupLen, rRange, rRef.Ref2, rBounds); + } + break; + default: + ; } - break; - default: - ; } } } @@ -3730,91 +3772,98 @@ void ScTokenArray::CheckExpandReferenceBounds( const sc::RefUpdateContext& rCxt, const ScAddress& rPos, SCROW nGroupLen, std::vector& rBounds ) const { const SCROW nInsRow = rCxt.maRange.aStart.Row(); - const FormulaToken* const * p = pCode; - const FormulaToken* const * pEnd = p + static_cast(nLen); - for (; p != pEnd; ++p) + TokenPointers aPtrs( pCode, nLen, pRPN, nRPN); + for (size_t j=0; j<2; ++j) { - switch ((*p)->GetType()) + const FormulaToken* const * p = aPtrs.maPointerRange[j].mpStart; + const FormulaToken* const * pEnd = aPtrs.maPointerRange[j].mpStop; + for (; p != pEnd; ++p) { - case svDoubleRef: - { - const formula::FormulaToken* pToken = *p; - const ScComplexRefData& rRef = *pToken->GetDoubleRef(); - bool bStartRowRelative = rRef.Ref1.IsRowRel(); - bool bEndRowRelative = rRef.Ref2.IsRowRel(); - - // For absolute references nothing needs to be done, they stay - // the same for all and if to be expanded the group will be - // adjusted later. - if (!bStartRowRelative && !bEndRowRelative) - break; // switch - - ScRange aAbsStart(rRef.toAbs(rPos)); - ScAddress aPos(rPos); - aPos.IncRow(nGroupLen); - ScRange aAbsEnd(rRef.toAbs(aPos)); - // References must be at least two rows to be expandable. - if ((aAbsStart.aEnd.Row() - aAbsStart.aStart.Row() < 1) && - (aAbsEnd.aEnd.Row() - aAbsEnd.aStart.Row() < 1)) - break; // switch - - // Only need to process if an edge may be touching the - // insertion row anywhere within the run of the group. - if (!((aAbsStart.aStart.Row() <= nInsRow && nInsRow <= aAbsEnd.aStart.Row()) || - (aAbsStart.aEnd.Row() <= nInsRow && nInsRow <= aAbsEnd.aEnd.Row()))) - break; // switch - - SCROW nStartRow = aAbsStart.aStart.Row(); - SCROW nEndRow = aAbsStart.aEnd.Row(); - // Position on first relevant range. - SCROW nOffset = 0; - if (nEndRow + 1 < nInsRow) - { - if (bEndRowRelative) - { - nOffset = nInsRow - nEndRow - 1; - nEndRow += nOffset; - if (bStartRowRelative) - nStartRow += nOffset; - } - else // bStartRowRelative==true - { - nOffset = nInsRow - nStartRow; - nStartRow += nOffset; - // Start is overtaking End, swap. - bStartRowRelative = false; - bEndRowRelative = true; - } - } - for (SCROW i = nOffset; i < nGroupLen; ++i) - { - bool bSplit = (nStartRow == nInsRow || nEndRow + 1 == nInsRow); - if (bSplit) - rBounds.push_back( rPos.Row() + i); + if (TokenPointers::skipToken(j,p)) + continue; - if (bEndRowRelative) - ++nEndRow; - if (bStartRowRelative) + switch ((*p)->GetType()) + { + case svDoubleRef: { - ++nStartRow; - if (!bEndRowRelative && nStartRow == nEndRow) + const formula::FormulaToken* pToken = *p; + const ScComplexRefData& rRef = *pToken->GetDoubleRef(); + bool bStartRowRelative = rRef.Ref1.IsRowRel(); + bool bEndRowRelative = rRef.Ref2.IsRowRel(); + + // For absolute references nothing needs to be done, they stay + // the same for all and if to be expanded the group will be + // adjusted later. + if (!bStartRowRelative && !bEndRowRelative) + break; // switch + + ScRange aAbsStart(rRef.toAbs(rPos)); + ScAddress aPos(rPos); + aPos.IncRow(nGroupLen); + ScRange aAbsEnd(rRef.toAbs(aPos)); + // References must be at least two rows to be expandable. + if ((aAbsStart.aEnd.Row() - aAbsStart.aStart.Row() < 1) && + (aAbsEnd.aEnd.Row() - aAbsEnd.aStart.Row() < 1)) + break; // switch + + // Only need to process if an edge may be touching the + // insertion row anywhere within the run of the group. + if (!((aAbsStart.aStart.Row() <= nInsRow && nInsRow <= aAbsEnd.aStart.Row()) || + (aAbsStart.aEnd.Row() <= nInsRow && nInsRow <= aAbsEnd.aEnd.Row()))) + break; // switch + + SCROW nStartRow = aAbsStart.aStart.Row(); + SCROW nEndRow = aAbsStart.aEnd.Row(); + // Position on first relevant range. + SCROW nOffset = 0; + if (nEndRow + 1 < nInsRow) { - // Start is overtaking End, swap. - bStartRowRelative = false; - bEndRowRelative = true; + if (bEndRowRelative) + { + nOffset = nInsRow - nEndRow - 1; + nEndRow += nOffset; + if (bStartRowRelative) + nStartRow += nOffset; + } + else // bStartRowRelative==true + { + nOffset = nInsRow - nStartRow; + nStartRow += nOffset; + // Start is overtaking End, swap. + bStartRowRelative = false; + bEndRowRelative = true; + } + } + for (SCROW i = nOffset; i < nGroupLen; ++i) + { + bool bSplit = (nStartRow == nInsRow || nEndRow + 1 == nInsRow); + if (bSplit) + rBounds.push_back( rPos.Row() + i); + + if (bEndRowRelative) + ++nEndRow; + if (bStartRowRelative) + { + ++nStartRow; + if (!bEndRowRelative && nStartRow == nEndRow) + { + // Start is overtaking End, swap. + bStartRowRelative = false; + bEndRowRelative = true; + } + } + if (nInsRow < nStartRow || (!bStartRowRelative && nInsRow <= nEndRow)) + { + if (bSplit && (++i < nGroupLen)) + rBounds.push_back( rPos.Row() + i); + break; // for, out of range now + } } } - if (nInsRow < nStartRow || (!bStartRowRelative && nInsRow <= nEndRow)) - { - if (bSplit && (++i < nGroupLen)) - rBounds.push_back( rPos.Row() + i); - break; // for, out of range now - } - } + break; + default: + ; } - break; - default: - ; } } } -- cgit v1.2.3