From 549c0f785d4b6d4bc1b39b22827d77d66f48430a Mon Sep 17 00:00:00 2001 From: Michael Stahl Date: Thu, 14 Feb 2013 19:27:28 +0100 Subject: fdo#60732: SwTxtNode: limit to less than STRING_LEN chars It's not a good idea to have STRING_LEN characters in a SwTxtNode because then there is no valid SwPosition at the end of the paragraph. Also it turns out that LO 3.6 and 4.0 do rather stupid things with a full SwTxtNode. So enforce a limit, at first in the usual places that are used during file import, SwTxtNode::InsertText() and SwCntntNode::CanJoinPrev()/CanJoinNext(). Change-Id: Icb0f44acd20aa81635d42b84d4ae0f9b693a661c --- sw/inc/ndtxt.hxx | 5 +++++ sw/source/core/docnode/node.cxx | 36 ++++++++++++++++++++++++------------ sw/source/core/txtnode/ndtxt.cxx | 6 +++++- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx index 5a47fb237883..4b78cd9731fe 100644 --- a/sw/inc/ndtxt.hxx +++ b/sw/inc/ndtxt.hxx @@ -70,6 +70,11 @@ namespace com { namespace sun { namespace star { typedef std::set< xub_StrLen > SwSoftPageBreakList; +// do not fill the String up to the max - need to be able to have a +// SwPosition "behind" the last character, i.e., at index TXTNODE_MAX + 1 +// (also STRING_LEN is often used for "not found") +const xub_StrLen TXTNODE_MAX = STRING_LEN - 2; + /// SwTxtNode is a paragraph in the document model. class SW_DLLPUBLIC SwTxtNode: public SwCntntNode, public ::sfx2::Metadatable { diff --git a/sw/source/core/docnode/node.cxx b/sw/source/core/docnode/node.cxx index a97261150a36..61a720f51691 100644 --- a/sw/source/core/docnode/node.cxx +++ b/sw/source/core/docnode/node.cxx @@ -1624,12 +1624,26 @@ const SfxPoolItem* SwCntntNode::GetNoCondAttr( sal_uInt16 nWhich, return pFnd; } +static bool lcl_CheckMaxLength(SwNode const& rPrev, SwNode const& rNext) +{ + if (rPrev.GetNodeType() != rNext.GetNodeType()) + { + return false; + } + if (!rPrev.IsTxtNode()) + { + return true; + } + size_t const nSum( static_cast(rPrev).GetTxt().Len() + + static_cast(rNext).GetTxt().Len()); + return (nSum <= TXTNODE_MAX); +} + // Can we join two Nodes? // We can return the 2nd position in pIdx. int SwCntntNode::CanJoinNext( SwNodeIndex* pIdx ) const { const SwNodes& rNds = GetNodes(); - sal_uInt8 nNdType = GetNodeType(); SwNodeIndex aIdx( *this, 1 ); const SwNode* pNd = this; @@ -1638,16 +1652,11 @@ int SwCntntNode::CanJoinNext( SwNodeIndex* pIdx ) const ( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsSectionNode() ))) ++aIdx; - if( pNd->GetNodeType() != nNdType || rNds.Count()-1 == aIdx.GetIndex() ) + if (rNds.Count()-1 == aIdx.GetIndex()) return sal_False; - if( IsTxtNode() ) - { // Do not merge strings if the result exceeds the allowed string length - const SwTxtNode* pTxtNd = static_cast(this); - sal_uInt64 nSum = pTxtNd->GetTxt().Len(); - pTxtNd = static_cast(pNd); - nSum += pTxtNd->GetTxt().Len(); - if( nSum > STRING_LEN ) - return sal_False; + if (!lcl_CheckMaxLength(*this, *pNd)) + { + return false; } if( pIdx ) *pIdx = aIdx; @@ -1658,7 +1667,6 @@ int SwCntntNode::CanJoinNext( SwNodeIndex* pIdx ) const // We can return the 2nd position in pIdx. int SwCntntNode::CanJoinPrev( SwNodeIndex* pIdx ) const { - sal_uInt8 nNdType = GetNodeType(); SwNodeIndex aIdx( *this, -1 ); const SwNode* pNd = this; @@ -1667,8 +1675,12 @@ int SwCntntNode::CanJoinPrev( SwNodeIndex* pIdx ) const ( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsSectionNode() ))) aIdx--; - if( pNd->GetNodeType() != nNdType || 0 == aIdx.GetIndex() ) + if (0 == aIdx.GetIndex()) return sal_False; + if (!lcl_CheckMaxLength(*pNd, *this)) + { + return false; + } if( pIdx ) *pIdx = aIdx; return sal_True; diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx index aff275343862..0fa70877715e 100644 --- a/sw/source/core/txtnode/ndtxt.cxx +++ b/sw/source/core/txtnode/ndtxt.cxx @@ -1712,7 +1712,11 @@ void SwTxtNode::InsertText( const XubString & rStr, const SwIndex & rIdx, xub_StrLen aPos = rIdx.GetIndex(); xub_StrLen nLen = m_Text.Len() - aPos; - m_Text.Insert( rStr, aPos ); + ssize_t const nOverflow(static_cast(m_Text.Len()) + + static_cast(rStr.Len()) - TXTNODE_MAX); + m_Text.Insert((nOverflow > 0) ? rStr.Copy(0, rStr.Len() - nOverflow) : rStr, + aPos); + assert(m_Text.Len() <= TXTNODE_MAX); nLen = m_Text.Len() - aPos - nLen; if ( !nLen ) return; -- cgit v1.2.3